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
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
@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
@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):
# Dependency Files
-include $(DEPFILES)
+
+%.h:
#include <init.h>
#include <mm_virt.h>
#include <mp.h>
+#include <pmemmap.h>
#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);
// === 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:
return 0;
}
+ // Set up physical memory manager
+ MM_Install(nPMemMapEnts, pmemmap);
+
MM_InstallVirtual(); // Clean up virtual address space
Heap_Install(); // Create initial heap
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;
}
else
gaArch_BootModules[i].ArgString = (char *)mods[i].String + KERNEL_BASE;
- Log_Log("Arch", " - %s", gaArch_BootModules[i].ArgString);
}
// Pass on to Independent Loader
*/
#define DEBUG 0
#include <acess.h>
-#include <mboot.h>
#include <mm_virt.h>
+#include <pmemmap.h>
+#include <hal_proc.h>
//#define USE_STACK 1
#define TRACE_ALLOCS 0 // Print trace messages on AllocPhys/DerefPhys
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);
#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)",
[section .text]
[extern kmain]
+[extern Desctab_Install]
[global start]
start:
; Just show we're here
.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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * pmemmap.c
+ * - Physical memory map manipulation
+ */
+#include <acess.h>
+#include <pmemmap.h>
+
+// === 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;
+ }
+}
+
+
+