From 3d85d14c564e245c00d31b1adf9c4ee7c2d9754a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 18 Jul 2012 18:50:26 +0800 Subject: [PATCH] Kernel/x86 - Cleaned up PMM init (and removed mboot from pmm code) --- KernelLand/Kernel/Makefile | 9 +- KernelLand/Kernel/arch/x86/main.c | 81 ++++++++++-- KernelLand/Kernel/arch/x86/mm_phys.c | 98 +++++++-------- KernelLand/Kernel/arch/x86/start.asm | 9 +- KernelLand/Kernel/include/pmemmap.h | 37 ++++++ KernelLand/Kernel/pmemmap.c | 177 +++++++++++++++++++++++++++ 6 files changed, 338 insertions(+), 73 deletions(-) create mode 100644 KernelLand/Kernel/include/pmemmap.h create mode 100644 KernelLand/Kernel/pmemmap.c diff --git a/KernelLand/Kernel/Makefile b/KernelLand/Kernel/Makefile index e391f03c..7562079c 100644 --- a/KernelLand/Kernel/Makefile +++ b/KernelLand/Kernel/Makefile @@ -25,7 +25,7 @@ ASFLAGS += -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1 CPPFLAGS += -I./include -I./arch/$(ARCHDIR)/include -D_MODULE_NAME_=\"Kernel\" CPPFLAGS += -D ARCH=$(ARCH) -D ARCHDIR=$(ARCHDIR) -D PLATFORM=\"$(PLATFORM)\" -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1 CPPFLAGS += -D KERNEL_VERSION=$(KERNEL_VERSION) -ffreestanding -CFLAGS += -Wall -fno-stack-protector -Wstrict-prototypes -g +CFLAGS += -Wall -fno-stack-protector -Wstrict-prototypes -std=gnu99 -g CFLAGS += -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wuninitialized CFLAGS += -O3 LDFLAGS += -T arch/$(ARCHDIR)/link.ld -g @@ -51,6 +51,7 @@ BUILDINFO_OBJ := $(OBJDIR)buildinfo.o$(OBJSUFFIX) BUILDINFO_SRC := $(OBJDIR)buildinfo.c$(OBJSUFFIX) OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ)) +OBJ += pmemmap.o OBJ += heap.o logging.o debug.o lib.o libc.o adt.o time.o OBJ += drvutil_video.o drvutil_disk.o OBJ += messages.o modules.o syscalls.o system.o @@ -116,7 +117,7 @@ $(OBJDIR)%.ao$(OBJSUFFIX): %.$(AS_SUFFIX) Makefile @mkdir -p $(dir $@) @$(AS) $(ASFLAGS) $< -o $@ ifeq ($(AS_SUFFIX),S) - @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.ao.dep$(OBJSUFFIX) $< + @$(MAKEDEP) $(CPPFLAGS) -MT $@ -MP -o $(OBJDIR)$*.ao.dep$(OBJSUFFIX) $< endif # C Sources @@ -124,7 +125,7 @@ $(OBJDIR)%.o$(OBJSUFFIX): %.c Makefile @echo --- CC -o $@ @mkdir -p $(dir $@) @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< - @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.o.dep$(OBJSUFFIX) $< + @$(MAKEDEP) $(CPPFLAGS) -MT $@ -MP -o $(OBJDIR)$*.o.dep$(OBJSUFFIX) $< # Build-time linked modules %.xo.$(ARCH): @@ -149,3 +150,5 @@ $(BUILDINFO_OBJ): $(BUILDINFO_SRC) # Dependency Files -include $(DEPFILES) + +%.h: diff --git a/KernelLand/Kernel/arch/x86/main.c b/KernelLand/Kernel/arch/x86/main.c index 92fef22c..466b61e4 100644 --- a/KernelLand/Kernel/arch/x86/main.c +++ b/KernelLand/Kernel/arch/x86/main.c @@ -9,16 +9,20 @@ #include #include #include +#include #define VGA_ERRORS 0 +#define KERNEL_LOAD 0x100000 // 1MiB #define MAX_ARGSTR_POS (0x400000-0x2000) +#define MAX_PMEMMAP_ENTS 16 // === IMPORTS === +extern char gKernelEnd[]; extern void Heap_Install(void); extern void Desctab_Install(void); extern void MM_PreinitVirtual(void); -extern void MM_Install(tMBoot_Info *MBoot); +extern void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges); extern void MM_InstallVirtual(void); extern void Threads_Init(void); extern int Time_Setup(void); @@ -41,27 +45,80 @@ struct { // === CODE === int kmain(Uint MbMagic, void *MbInfoPtr) { - int i; tMBoot_Module *mods; tMBoot_Info *mbInfo; + tPMemMapEnt pmemmap[MAX_PMEMMAP_ENTS]; + int nPMemMapEnts; LogF("Acess2 x86-"PLATFORM" v"EXPAND_STR(KERNEL_VERSION)"\r\n"); LogF(" Build %i, Git Hash %s\r\n", BUILD_NUM, gsGitHash); - // Set up non-boot info dependent stuff - Desctab_Install(); // Set up GDT and IDT MM_PreinitVirtual(); // Initialise virtual mappings - + + mbInfo = MbInfoPtr; + switch(MbMagic) { // Multiboot 1 - case MULTIBOOT_MAGIC: + case MULTIBOOT_MAGIC: { + // TODO: Handle when this isn't in the mapped area + gsBootCmdLine = (char*)(mbInfo->CommandLine + KERNEL_BASE); + + tMBoot_MMapEnt *ent = (void*)mbInfo->MMapAddr; + tMBoot_MMapEnt *last = (void*)(mbInfo->MMapAddr + mbInfo->MMapLength); + + // Build up memory map + nPMemMapEnts = 0; + while( ent < last && nPMemMapEnts < MAX_PMEMMAP_ENTS ) + { + tPMemMapEnt *nent = &pmemmap[nPMemMapEnts]; + nent->Start = ent->Base; + nent->Length = ent->Length; + switch(ent->Type) + { + case 1: + nent->Type = PMEMTYPE_FREE; + break; + default: + nent->Type = PMEMTYPE_RESERVED; + break; + } + nent->NUMADomain = 0; + + nPMemMapEnts ++; + ent = (void*)( (tVAddr)ent + ent->Size + 4 ); + } + + // Ensure it's valid + nPMemMapEnts = PMemMap_ValidateMap(pmemmap, nPMemMapEnts, MAX_PMEMMAP_ENTS); + // TODO: Error handling + + // Replace kernel with PMEMTYPE_USED + nPMemMapEnts = PMemMap_MarkRangeUsed( + pmemmap, nPMemMapEnts, MAX_PMEMMAP_ENTS, + KERNEL_LOAD, (tVAddr)&gKernelEnd - KERNEL_LOAD - KERNEL_BASE + ); + + // Replace modules with PMEMTYPE_USED + nPMemMapEnts = PMemMap_MarkRangeUsed(pmemmap, nPMemMapEnts, MAX_PMEMMAP_ENTS, + mbInfo->Modules, mbInfo->ModuleCount*sizeof(*mods) + ); + mods = (void*)mbInfo->Modules; + for( int i = 0; i < mbInfo->ModuleCount; i ++ ) + { + nPMemMapEnts = PMemMap_MarkRangeUsed( + pmemmap, nPMemMapEnts, MAX_PMEMMAP_ENTS, + mods->Start, mods->End - mods->Start + ); + } + + // Debug - Output map + PMemMap_DumpBlocks(pmemmap, nPMemMapEnts); + // Adjust Multiboot structure address mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE ); - gsBootCmdLine = (char*)(mbInfo->CommandLine + KERNEL_BASE); - MM_Install( mbInfo ); // Set up physical memory manager - break; + break; } // Multiboot 2 case MULTIBOOT2_MAGIC: @@ -76,6 +133,9 @@ int kmain(Uint MbMagic, void *MbInfoPtr) return 0; } + // Set up physical memory manager + MM_Install(nPMemMapEnts, pmemmap); + MM_InstallVirtual(); // Clean up virtual address space Heap_Install(); // Create initial heap @@ -93,7 +153,7 @@ int kmain(Uint MbMagic, void *MbInfoPtr) mods = (void*)( mbInfo->Modules + KERNEL_BASE ); giArch_NumBootModules = mbInfo->ModuleCount; gaArch_BootModules = malloc( giArch_NumBootModules * sizeof(*gaArch_BootModules) ); - for( i = 0; i < mbInfo->ModuleCount; i ++ ) + for( int i = 0; i < mbInfo->ModuleCount; i ++ ) { int ofs; @@ -119,7 +179,6 @@ int kmain(Uint MbMagic, void *MbInfoPtr) } else gaArch_BootModules[i].ArgString = (char *)mods[i].String + KERNEL_BASE; - Log_Log("Arch", " - %s", gaArch_BootModules[i].ArgString); } // Pass on to Independent Loader diff --git a/KernelLand/Kernel/arch/x86/mm_phys.c b/KernelLand/Kernel/arch/x86/mm_phys.c index bd1cafcd..a3318176 100644 --- a/KernelLand/Kernel/arch/x86/mm_phys.c +++ b/KernelLand/Kernel/arch/x86/mm_phys.c @@ -4,8 +4,9 @@ */ #define DEBUG 0 #include -#include #include +#include +#include //#define USE_STACK 1 #define TRACE_ALLOCS 0 // Print trace messages on AllocPhys/DerefPhys @@ -14,11 +15,10 @@ static const int addrClasses[] = {0,16,20,24,32,64}; static const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]); // === IMPORTS === -extern char gKernelEnd[]; extern void Proc_PrintBacktrace(void); // === PROTOTYPES === -void MM_Install(tMBoot_Info *MBoot); +void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges); //tPAddr MM_AllocPhys(void); //tPAddr MM_AllocPhysRange(int Pages, int MaxBits); //void MM_RefPhys(tPAddr PAddr); @@ -39,82 +39,66 @@ void **gaPageNodes = (void*)MM_PAGENODE_BASE; #define REFENT_PER_PAGE (0x1000/sizeof(gaPageReferences[0])) // === CODE === -void MM_Install(tMBoot_Info *MBoot) +void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges) { - Uint kernelPages, num; Uint i; Uint64 maxAddr = 0; - tMBoot_Module *mods; - tMBoot_MMapEnt *ent; // --- Find largest address - MBoot->MMapAddr |= KERNEL_BASE; - ent = (void *)( MBoot->MMapAddr ); - while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength ) + for( i = 0; i < NPMemRanges; i ++ ) { - // Adjust for size - ent->Size += 4; - + tPMemMapEnt *ent = &PMemRanges[i]; // If entry is RAM and is above `maxAddr`, change `maxAddr` - if(ent->Type == 1) + if(ent->Type == PMEMTYPE_FREE || ent->Type == PMEMTYPE_USED) { - if(ent->Base + ent->Length > maxAddr) - maxAddr = ent->Base + ent->Length; + if(ent->Start + ent->Length > maxAddr) + maxAddr = ent->Start + ent->Length; giTotalMemorySize += ent->Length >> 12; } - // Go to next entry - ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size ); } - if(maxAddr == 0) { - giPageCount = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value - } - else { - giPageCount = maxAddr >> 12; - } + giPageCount = maxAddr >> 12; giLastPossibleFree = giPageCount - 1; memsetd(gaPageBitmap, 0xFFFFFFFF, giPageCount/32); // Set up allocateable space - ent = (void *)( MBoot->MMapAddr ); - while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength ) - { - memsetd( &gaPageBitmap[ent->Base/(4096*32)], 0, ent->Length/(4096*32) ); - ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size ); + for( i = 0; i < NPMemRanges; i ++ ) + { + tPMemMapEnt *ent = &PMemRanges[i]; + if( ent->Type == PMEMTYPE_FREE ) + { + Uint64 startpg = ent->Start / PAGE_SIZE; + Uint64 pgcount = ent->Length / PAGE_SIZE; + while( startpg % 32 && pgcount ) { + gaPageBitmap[startpg/32] &= ~(1U << (startpg%32)); + startpg ++; + pgcount --; + } + memsetd( &gaPageBitmap[startpg/32], 0, pgcount/32 ); + startpg += pgcount - pgcount%32; + pgcount -= pgcount - pgcount%32; + while(pgcount) { + gaPageBitmap[startpg/32] &= ~(1U << (startpg%32)); + startpg ++; + pgcount --; + } + } + else if( ent->Type == PMEMTYPE_USED ) + { + giPhysAlloc += ent->Length / PAGE_SIZE; + } } - - // Get used page count (Kernel) - kernelPages = (Uint)&gKernelEnd - KERNEL_BASE - 0x100000; - kernelPages += 0xFFF; // Page Align - kernelPages >>= 12; - giPhysAlloc += kernelPages; // Add to used count - // Fill page bitmap - num = kernelPages/32; - memsetd( &gaPageBitmap[0x100000/(4096*32)], -1, num ); - gaPageBitmap[ 0x100000/(4096*32) + num ] = (1 << (kernelPages & 31)) - 1; - // Fill Superpage bitmap - num = kernelPages/(32*32); - memsetd( &gaSuperBitmap[0x100000/(4096*32*32)], -1, num ); - gaSuperBitmap[ 0x100000/(4096*32*32) + num ] = (1 << ((kernelPages / 32) & 31)) - 1; - - // Mark Multiboot's pages as taken - // - Structure - MM_RefPhys( (Uint)MBoot - KERNEL_BASE ); - // - Module List - for(i = (MBoot->ModuleCount*sizeof(tMBoot_Module)+0xFFF)>12; i--; ) - MM_RefPhys( MBoot->Modules + (i << 12) ); - // - Modules - mods = (void*)(MBoot->Modules + KERNEL_BASE); - for(i = 0; i < MBoot->ModuleCount; i++) + // - A set bit means that there are no free pages in this block of 32 + for( i = 0; i < (giPageCount+31)/32; i ++ ) { - num = (mods[i].End - mods[i].Start + 0xFFF) >> 12; - while(num--) - MM_RefPhys( (mods[i].Start & ~0xFFF) + (num<<12) ); + if( gaPageBitmap[i] + 1 == 0 ) { + gaSuperBitmap[i/32] |= (1 << i%32); + } } - + gaPageReferences = (void*)MM_REFCOUNT_BASE; Log_Log("PMem", "Physical memory set up (%lli pages of ~%lli MiB used)", diff --git a/KernelLand/Kernel/arch/x86/start.asm b/KernelLand/Kernel/arch/x86/start.asm index b6026de6..1d4a35d8 100644 --- a/KernelLand/Kernel/arch/x86/start.asm +++ b/KernelLand/Kernel/arch/x86/start.asm @@ -57,6 +57,7 @@ mboot: [section .text] [extern kmain] +[extern Desctab_Install] [global start] start: ; Just show we're here @@ -87,11 +88,15 @@ start: .higher_half: mov WORD [0xB8006], 0x0773 ; 's' + + push ebx ; Multiboot Info + push eax ; Multiboot Magic Value + ; NOTE: These are actually for kmain + + call Desctab_Install mov WORD [0xB8008], 0x0773 ; 's' ; Call the kernel - push ebx ; Multiboot Info - push eax ; Multiboot Magic Value mov WORD [0xB800A], 0x0732 ; '2' call kmain diff --git a/KernelLand/Kernel/include/pmemmap.h b/KernelLand/Kernel/include/pmemmap.h new file mode 100644 index 00000000..4b89e457 --- /dev/null +++ b/KernelLand/Kernel/include/pmemmap.h @@ -0,0 +1,37 @@ +/* + * Acess2 Kernel + * - By John Hodge (thePowersGang) + * + * pmemmap.h + * - Physical Memory Map definitions + */ +#ifndef _PMEMMAP_H_ +#define _PMEMMAP_H_ + +typedef struct sPMemMapEnt tPMemMapEnt; + +enum ePMemMapEntType +{ + PMEMTYPE_FREE, // Free RAM + PMEMTYPE_USED, // Used by Kernel / Modules + PMEMTYPE_RESERVED, // Unavaliable + PMEMTYPE_NVRAM, // Non-volatile + PMEMTYPE_UNMAPPED // Nothing on these lines +}; + +struct sPMemMapEnt +{ + Uint64 Start; + Uint64 Length; + enum ePMemMapEntType Type; + Uint16 NUMADomain; +}; + +extern void PMemMap_DumpBlocks(tPMemMapEnt *map, int NEnts); +extern int PMemMap_SplitBlock(tPMemMapEnt *map, int NEnts, int MaxEnts, int Block, Uint64 Offset); +extern int PMemMap_CompactMap(tPMemMapEnt *map, int NEnts, int MaxEnts); +extern int PMemMap_ValidateMap(tPMemMapEnt *map, int NEnts, int MaxEnts); +extern int PMemMap_MarkRangeUsed(tPMemMapEnt *map, int NEnts, int MaxEnts, Uint64 Base, Uint64 Size); + +#endif + diff --git a/KernelLand/Kernel/pmemmap.c b/KernelLand/Kernel/pmemmap.c new file mode 100644 index 00000000..50f8de19 --- /dev/null +++ b/KernelLand/Kernel/pmemmap.c @@ -0,0 +1,177 @@ +/* + * Acess2 Kernel + * - By John Hodge (thePowersGang) + * + * pmemmap.c + * - Physical memory map manipulation + */ +#include +#include + +// === CODE === +void PMemMap_DumpBlocks(tPMemMapEnt *map, int NEnts) +{ + for( int i = 0; i < NEnts; i ++ ) + { + Log_Debug("Arch", "%i: %i 0x%02x %08llx+%llx", + i, map[i].Type, map[i].NUMADomain, + map[i].Start, map[i].Length + ); + } +} + +int PMemMap_SplitBlock(tPMemMapEnt *map, int NEnts, int MaxEnts, int Block, Uint64 Offset) +{ + LOG("Splitting %i (%llx+%llx) at %llx", Block, map[Block].Start, map[Block].Length, Offset); + + Uint64 _len = map[Block].Length; + map[Block].Length = Offset; + if( NEnts == MaxEnts ) { + // out of space + return NEnts; + } + Block ++; + if( Block < NEnts ) { + // Can't be anything after + memmove(&map[Block+1], &map[Block], (NEnts - Block)*sizeof(map[0])); + } + NEnts ++; + + // New (free) block + map[Block].Start = map[Block-1].Start + Offset; + map[Block].Length = _len - Offset; + map[Block].Type = map[Block-1].Type; + map[Block].NUMADomain = map[Block-1].NUMADomain; + LOG("- New %i %02x %llx+%llx", map[Block].Type, map[Block].NUMADomain, map[Block].Start, map[Block].Length); + + return NEnts; +} + +int PMemMap_CompactMap(tPMemMapEnt *map, int NEnts, int MaxEnts) +{ + for( int i = 1; i < NEnts; i ++ ) + { + // Check if the ranges are contiguous + if( map[i-1].Start + map[i-1].Length < map[i].Start ) + continue ; + // Check if the type is the same + if( map[i-1].Type != map[i].Type ) + continue ; + // Check if the NUMA Domains are the same + if( map[i-1].NUMADomain != map[i].NUMADomain ) + continue ; + + // Ok, they should be together + map[i-1].Length += map[i].Length; + memmove(&map[i], &map[i+1], (NEnts - (i+1))*sizeof(map[0])); + + // Counteract the i++ in the loop iterator + i --; + NEnts --; + } + return NEnts; +} + +int PMemMap_ValidateMap(tPMemMapEnt *map, int NEnts, int MaxEnts) +{ + // Sort the pmem map + int bNeedsSort = 0; + for( int i = 1; i < NEnts; i ++ ) + { + if( map[i-1].Start > map[i].Start ) { + bNeedsSort = 1; + break; + } + } + if( bNeedsSort ) + { + Log_Warning("Arch", "TODO: Impliment memory map sorting"); + // TODO: Sort memory map + } + + // Ensure that the map has no overlaps + for( int i = 1; i < NEnts; i ++ ) + { + if( map[i-1].Start + map[i-1].Length <= map[i].Start ) + continue ; + // Oops, overlap! + Log_Notice("Arch", "Map ranges %llx+%llx and %llx+%llx overlap", + map[i-1].Start, map[i-1].Length, + map[i].Start, map[i].Length + ); + } + + return PMemMap_CompactMap(map, NEnts, MaxEnts); +} + + +int PMemMap_MarkRangeUsed(tPMemMapEnt *map, int NEnts, int MaxEnts, Uint64 Base, Uint64 Size) +{ + int first; + + Size = (Size + 0xFFF) & ~0xFFF; + Base = Base & ~0xFFF; + + first = -1; + for( int i = 0; i < NEnts; i ++ ) + { + if( map[i].Start + map[i].Length > Base ) { + first = i; + break; + } + } + if( first == -1 ) { + // Not in map + LOG("%llx+%llx not in map (past end)", Base, Size); + return NEnts; + } + + if( map[first].Start > Base ) { + // Not in map + LOG("%llx+%llx not in map (in hole)", Base, Size); + return NEnts; + } + + // Detect single + if( map[first].Start <= Base && Base + Size <= map[first].Start + map[first].Length ) + { + // Split before + if( map[first].Start < Base ) + { + if( NEnts == MaxEnts ) { + // out of space... oops + return NEnts; + } + NEnts = PMemMap_SplitBlock(map, NEnts, MaxEnts, first, Base - map[first].Start); + first ++; + } + + // map[first].Start == Base + // Split after + if( map[first].Length > Size ) + { + if( NEnts == MaxEnts ) { + // out of space + return NEnts; + } + NEnts = PMemMap_SplitBlock(map, NEnts, MaxEnts, first, Size); + } + + // map[first] is now exactly the block + map[first].Type = PMEMTYPE_USED; + + return PMemMap_CompactMap(map, NEnts, MaxEnts); + } + else + { + // Wait... this should never happen, right? + Log_Notice("Arch", "Module %llx+%llx overlaps two or more ranges", + Base, Size); + PMemMap_DumpBlocks(map, NEnts); + // TODO: Error? + return NEnts; + } +} + + + -- 2.20.1