diff --git a/build/iso/boot/grub/menu.lst b/build/iso/boot/grub/menu.lst index 89a0671..2ccb451 100644 --- a/build/iso/boot/grub/menu.lst +++ b/build/iso/boot/grub/menu.lst @@ -126,4 +126,4 @@ hiddenmenu title XOmB kernel /boot/xomb #module /your/module -### END PITTGEEKS AUTOMAGIC KERNELS LIST +module /boot/testapp diff --git a/build/iso/boot/test b/build/iso/boot/test new file mode 100755 index 0000000..d2955fb Binary files /dev/null and b/build/iso/boot/test differ diff --git a/build/iso/boot/testapp b/build/iso/boot/testapp new file mode 100755 index 0000000..4c1126a Binary files /dev/null and b/build/iso/boot/testapp differ diff --git a/kernel/arch/x86_64/core/lapic.d b/kernel/arch/x86_64/core/lapic.d index 45564db..f662624 100644 --- a/kernel/arch/x86_64/core/lapic.d +++ b/kernel/arch/x86_64/core/lapic.d @@ -28,7 +28,7 @@ public: install(); - startAPs(); + // startAPs(); return ErrorVal.Success; } @@ -79,19 +79,24 @@ private: // Map in the register space apicRegisters = cast(ApicRegisterSpace*)Paging.mapRegion(localAPICAddr, ApicRegisterSpace.sizeof); - // Map in the first megabyte of space - ubyte* bootRange; - - bootRange = cast(ubyte*)Paging.mapRegion(cast(void*)0x0, 0x100000); - // Write the trampoline code where it needs to be uint trampolineLength = cast(ulong)LinkerScript.etrampoline - cast(ulong)LinkerScript.trampoline; ubyte* trampolineCode = cast(ubyte*)LinkerScript.trampoline + cast(ulong)System.kernel.virtualStart; - kprintfln!("trampolineLength: {} trampolineCode: {x} trampoline: {x} Kernel: {x}")(trampolineLength, trampolineCode, LinkerScript.trampoline, System.kernel.start); + // Map in the first megabyte of space + ubyte* bootRange; + bootRange = cast(ubyte*)Paging.mapRegion(cast(void*)0x0, trampolineLength); - bootRange[0..trampolineLength] = trampolineCode[0..trampolineLength]; + kprintfln!("bootRange: {} trampolineLength: {} trampolineCode: {x} trampoline: {x} Kernel: {x}")(bootRange, trampolineLength, trampolineCode, LinkerScript.trampoline, System.kernel.start); + + for(uint i; i < trampolineLength; i++) { + *bootRange = *trampolineCode; + bootRange++; + trampolineCode++; + } + // bootRange[0..trampolineLength] = trampolineCode[0..trampolineLength]; + kprintfln!("Trampoline copied")(); } void EOI() { diff --git a/kernel/arch/x86_64/core/paging.d b/kernel/arch/x86_64/core/paging.d index 0980160..24b11c9 100644 --- a/kernel/arch/x86_64/core/paging.d +++ b/kernel/arch/x86_64/core/paging.d @@ -34,8 +34,7 @@ import kernel.dev.console; // - devices // - misc -struct Paging -{ +struct Paging { static: public: @@ -83,30 +82,13 @@ public: // We need to map the kernel kernelAddress = heapAddress; - ulong curPhysAddr = cast(ulong)System.kernel.start; - ulong regionLength = System.kernel.length + Heap.length + (curPhysAddr % PAGESIZE); - curPhysAddr -= (curPhysAddr % PAGESIZE); - - // Set the new starting address - void* physAddr = cast(void*)curPhysAddr; - - // Get the end address - curPhysAddr += regionLength; - - // Align the end address - if ((curPhysAddr % PAGESIZE) > 0) - { - curPhysAddr += PAGESIZE - (curPhysAddr % PAGESIZE); - } - - // Define the end address - void* endAddr = cast(void*)curPhysAddr; - - // This region will be located at the current heapAddress - void* location = heapAddress; + mapRegion(System.kernel.start, System.kernel.length); - // Do the actual mapping - heapMap!(true)(physAddr, endAddr); + void* bitmapLocation = heapAddress; + + // Map Heap bitmap + kprintfln!("Heap: {x}")(*(cast(ulong*)Heap.start)); + mapRegion(Heap.start, Heap.length); // We now have the kernel mapped kernelMapped = true; @@ -119,21 +101,29 @@ public: // Restart the console driver to look at the right place Console.initialize(); + kprintfln!("bitmapLocation: {x}")(bitmapLocation); + Heap.virtualStart = bitmapLocation; // This is the virtual address for the page table root = cast(PageLevel4*)0xFFFFFFFF_FFFFF000; - kprintfln!("root: {x}")(root); + kprintfln!("root: {x} : {x}")(root, rootPhysical); + kprintfln!("heap: {x}")(Heap.virtualStart); // All is well. return ErrorVal.Success; } void install() { + kprintfln!("Installing...")(); ulong rootAddr = cast(ulong)rootPhysical; + kprintfln!("Installing........")(); asm { mov RAX, rootAddr; mov CR3, RAX; } + kprintfln!("Installed")(); + kprintfln!("Heap: {x}")(*(cast(ulong*)Heap.virtualStart)); + } // This function will get the physical address that is mapped from the @@ -161,7 +151,6 @@ public: out ulong indexLevel4) { ulong vAddr = cast(ulong)virtAddress; - kprintfln!("addr {x}")(virtAddress); vAddr >>= 12; indexLevel1 = vAddr & 0x1ff; @@ -203,12 +192,55 @@ public: // This region will be located at the current heapAddress void* location = heapAddress; - doHeapMap(physAddr, endAddr); + if (kernelMapped) { + doHeapMap(physAddr, endAddr); + } + else { + heapMap!(true)(physAddr, endAddr); + } // Return the position of this region return location; } + void* mapRegion(PageLevel4* rootTable, void* physAddr, ulong regionLength, void* virtAddr = null) { + if (virtAddr is null) { + virtAddr = physAddr; + } + // Sanitize inputs + + // physAddr should be floored to the page boundary + // regionLength should be ceilinged to the page boundary + ulong curPhysAddr = cast(ulong)physAddr; + regionLength += (curPhysAddr % PAGESIZE); + curPhysAddr -= (curPhysAddr % PAGESIZE); + + // Set the new starting address + physAddr = cast(void*)curPhysAddr; + + // Get the end address + curPhysAddr += regionLength; + + // Align the end address + if ((curPhysAddr % PAGESIZE) > 0) + { + curPhysAddr += PAGESIZE - (curPhysAddr % PAGESIZE); + } + + // Define the end address + void* endAddr = cast(void*)curPhysAddr; + + kprintfln!("virtaddr: {x}")(virtAddr); + + heapMap!(false, false)(physAddr, endAddr, virtAddr); + + return virtAddr; + } + + PageLevel4* kernelPageTable() { + return cast(PageLevel4*)0xfffffffffffff000; + } + private: @@ -236,10 +268,9 @@ private: // -- Mapping Functions -- // + template heapMap(bool initialMapping = false, bool kernelLevel = true) { + void heapMap(void* physAddr, void* endAddr, void* virtAddr = heapAddress) { - template heapMap(bool initialMapping = false) { - void heapMap(void* physAddr, void* endAddr) - { // Do the mapping PageLevel3* pl3; PageLevel2* pl2; @@ -249,7 +280,7 @@ private: void* startAddr = physAddr; // Find the initial page - translateAddress(heapAddress, indexL1, indexL2, indexL3, indexL4); + translateAddress(virtAddr, indexL1, indexL2, indexL3, indexL4); // From there, map the region ulong done = 0; @@ -257,52 +288,84 @@ private: { // get the L3 table static if (initialMapping) { - pl3 = cast(PageLevel3*)Heap.allocPageNoMap(); - *pl3 = PageLevel3.init; - root.entries[indexL4].pml = cast(ulong)pl3; - root.entries[indexL4].present = 1; - root.entries[indexL4].rw = 1; + if (root.entries[indexL4].present) { + pl3 = cast(PageLevel3*)(root.entries[indexL4].address << 12); + } + else { + pl3 = cast(PageLevel3*)Heap.allocPageNoMap(); + *pl3 = PageLevel3.init; + root.entries[indexL4].pml = cast(ulong)pl3; + root.entries[indexL4].present = 1; + root.entries[indexL4].rw = 1; + static if (!kernelLevel) { + root.entries[indexL4].us = 1; + } + } } else { - pl3 = root.getOrCreateTable(indexL4); + pl3 = root.getOrCreateTable(indexL4, !kernelLevel); } for ( ; indexL3 < 512 ; indexL3++ ) { // get the L2 table static if (initialMapping) { - pl2 = cast(PageLevel2*)Heap.allocPageNoMap(); - *pl2 = PageLevel2.init; - pl3.entries[indexL3].pml = cast(ulong)pl2; - pl3.entries[indexL3].present = 1; - pl3.entries[indexL3].rw = 1; + if (pl3.entries[indexL3].present) { + pl2 = cast(PageLevel2*)(pl3.entries[indexL3].address << 12); + } + else { + pl2 = cast(PageLevel2*)Heap.allocPageNoMap(); + *pl2 = PageLevel2.init; + pl3.entries[indexL3].pml = cast(ulong)pl2; + pl3.entries[indexL3].present = 1; + pl3.entries[indexL3].rw = 1; + static if (!kernelLevel) { + pl3.entries[indexL3].us = 1; + } + } } else { - pl2 = pl3.getOrCreateTable(indexL3); + pl2 = pl3.getOrCreateTable(indexL3, !kernelLevel); } for ( ; indexL2 < 512 ; indexL2++ ) { // get the L1 table static if (initialMapping) { - pl1 = cast(PageLevel1*)Heap.allocPageNoMap(); - *pl1 = PageLevel1.init; - pl2.entries[indexL2].pml = cast(ulong)pl1; - pl2.entries[indexL2].present = 1; - pl2.entries[indexL2].rw = 1; + if (pl2.entries[indexL2].present) { + pl1 = cast(PageLevel1*)(pl2.entries[indexL2].address << 12); + } + else { + pl1 = cast(PageLevel1*)Heap.allocPageNoMap(); + *pl1 = PageLevel1.init; + pl2.entries[indexL2].pml = cast(ulong)pl1; + pl2.entries[indexL2].present = 1; + pl2.entries[indexL2].rw = 1; + static if (!kernelLevel) { + pl2.entries[indexL2].us = 1; + } + } } else { - pl1 = pl2.getOrCreateTable(indexL2); + pl1 = pl2.getOrCreateTable(indexL2, !kernelLevel); } for ( ; indexL1 < 512 ; indexL1++ ) { // set the address + if (pl1.entries[indexL1].present) { + // Page already allocated + // XXX: Fail + } + pl1.entries[indexL1].pml = cast(ulong)physAddr; pl1.entries[indexL1].present = 1; pl1.entries[indexL1].rw = 1; pl1.entries[indexL1].pat = 1; + static if (!kernelLevel) { + pl1.entries[indexL1].us = 1; + } physAddr += PAGESIZE; done += PAGESIZE; @@ -334,14 +397,17 @@ private: ulong regionLength = cast(ulong)endAddr - cast(ulong)startAddr; // Relocate heap address - heapAddress += regionLength; + static if (kernelLevel) { + heapAddress += regionLength; + } } } alias heapMap!(false) doHeapMap; -// -- Structures -- // +} +// -- Structures -- // // The x86 implements a four level page table. // We use the 4KB page size hierarchy @@ -401,7 +467,7 @@ private: return cast(PageLevel3*)(0xFFFFFF7F_BFE00000 + (idx << 12)); } - PageLevel3* getOrCreateTable(uint idx) { + PageLevel3* getOrCreateTable(uint idx, bool usermode = false) { PageLevel3* ret = getTable(idx); if (ret is null) { @@ -412,6 +478,7 @@ private: entries[idx].pml = cast(ulong)ret; entries[idx].present = 1; entries[idx].rw = 1; + entries[idx].us = usermode; // Calculate virtual address ret = cast(PageLevel3*)(0xFFFFFF7F_BFE00000 + (idx << 12)); @@ -437,7 +504,7 @@ private: return cast(PageLevel2*)(0xFFFFFF7F_C0000000 + ((baseAddr + idx) << 12)); } - PageLevel2* getOrCreateTable(uint idx) { + PageLevel2* getOrCreateTable(uint idx, bool usermode = false) { PageLevel2* ret = getTable(idx); if (ret is null) { @@ -448,6 +515,7 @@ private: entries[idx].pml = cast(ulong)ret; entries[idx].present = 1; entries[idx].rw = 1; + entries[idx].us = usermode; // Calculate virtual address ulong baseAddr = cast(ulong)this; @@ -476,7 +544,7 @@ private: return cast(PageLevel1*)(0xFFFFFF80_00000000 + ((baseAddr + idx) << 12)); } - PageLevel1* getOrCreateTable(uint idx) { + PageLevel1* getOrCreateTable(uint idx, bool usermode = false) { PageLevel1* ret = getTable(idx); if (ret is null) { @@ -487,6 +555,7 @@ private: entries[idx].pml = cast(ulong)ret; entries[idx].present = 1; entries[idx].rw = 1; + entries[idx].us = usermode; // Calculate virtual address ulong baseAddr = cast(ulong)this; @@ -508,4 +577,4 @@ private: return cast(void*)(entries[idx].address << 12); } } -} + diff --git a/kernel/arch/x86_64/cpu.d b/kernel/arch/x86_64/cpu.d index 271992c..ca6e467 100644 --- a/kernel/arch/x86_64/cpu.d +++ b/kernel/arch/x86_64/cpu.d @@ -34,6 +34,7 @@ public: // This module will conform to the interface ErrorVal initialize() { + kprintfln!("Paging?")(); Paging.install(); printToLog("Enabling Paging", ErrorVal.Success); diff --git a/kernel/arch/x86_64/imports/architecture.d b/kernel/arch/x86_64/imports/architecture.d index f2fe9d0..cf1e162 100644 --- a/kernel/arch/x86_64/imports/architecture.d +++ b/kernel/arch/x86_64/imports/architecture.d @@ -13,3 +13,4 @@ public import kernel.arch.x86_64.cpu; public import kernel.arch.x86_64.multiprocessor; public import kernel.arch.x86_64.vm; public import kernel.arch.x86_64.mutex; +public import kernel.arch.x86_64.pagetable; diff --git a/kernel/arch/x86_64/main.d b/kernel/arch/x86_64/main.d index 713402b..d9f0c0a 100644 --- a/kernel/arch/x86_64/main.d +++ b/kernel/arch/x86_64/main.d @@ -52,15 +52,6 @@ public: // Interrupt Descriptor Table printToLog("Initializing IDT", IDT.initialize()); - - // Initialize the system heap, because we will need it - Heap.initialize(cast(ubyte*)LinkerScript.kernelVMA - + cast(ulong)System.kernel.start - + System.kernel.length); - - // Install Virtual Memory and Paging - printToLog("Initializing Paging", Paging.initialize()); - // Everything must have succeeded return ErrorVal.Success; } diff --git a/kernel/arch/x86_64/pagetable.d b/kernel/arch/x86_64/pagetable.d index 087f6d6..0413a47 100644 --- a/kernel/arch/x86_64/pagetable.d +++ b/kernel/arch/x86_64/pagetable.d @@ -7,10 +7,131 @@ module kernel.arch.x86_64.pagetable; -struct PageTable -{ -static: +import kernel.arch.x86_64.core.paging; + +import kernel.core.error; +import kernel.core.kprintf; + +import kernel.mem.heap; + +struct PageTable { public: + ErrorVal initialize() { + // Make a new root pagetable + rootPhysAddr = Heap.allocPageNoMap(); + root = cast(PageLevel3*)(Paging.mapRegion(rootPhysAddr, 4096)); + *root = PageLevel3.init; + + kprintfln!("New Page Table: {x} {x}")(rootPhysAddr, root); + + // Map to kernel page table + Paging.kernelPageTable.entries[0].pml = cast(ulong)rootPhysAddr; + Paging.kernelPageTable.entries[0].present = 1; + Paging.kernelPageTable.entries[0].rw = 1; + Paging.kernelPageTable.entries[0].us = 1; + + // Allocate Stack + stack = Heap.allocPageNoMap(); + Paging.mapRegion(null, stack, 4096, cast(void*)0x80000000); + stack = cast(void*)0x80000000; + + contextStack = Heap.allocPageNoMap(); + contextStack = cast(void*)Paging.mapRegion(contextStack, 4096); + + return ErrorVal.Success; + } + + ErrorVal preamble(void* entry) { + ulong* stackSpace = cast(ulong*)(contextStack + 4096); + + // Push Things to Stack + + // SS (USER_DS with RPL of 3) + stackSpace--; + *stackSpace = ((8 << 3) | 3); + + // RSP (user stack) + stackSpace--; + *stackSpace = (cast(ulong)stack) + 4096; + + // FLAGS + stackSpace--; + *stackSpace = ((1 << 9) | (3 << 12)); + + // CS (USER_CS with RPL of 3) + stackSpace--; + *stackSpace = ((9 << 3) | 3); + + // RIP (entry) + stackSpace--; + *stackSpace = cast(ulong)entry; + + // ERROR CODE and VECTOR NUMBER + stackSpace--; + *stackSpace = 0; + stackSpace--; + *stackSpace = 0; + + contextStackPtr = stackSpace; + + return ErrorVal.Success; + } + + ErrorVal map(void* physAddr, ulong length) { + Paging.mapRegion(null, physAddr, length, cast(void*)0x100000); + kprintfln!("success...")(); + + return ErrorVal.Success; + } + + ErrorVal alloc(void* virtAddr, ulong length) { + void* physAddr = Heap.allocPageNoMap(); + Paging.mapRegion(null, physAddr, 4096, virtAddr); + virtAddr += 4096; + + while (length > 4096) { + physAddr = Heap.allocPageNoMap(); + kprintfln!("mapping: {x} -> {x}")(physAddr, virtAddr); + Paging.mapRegion(null, physAddr, 4096, virtAddr); + virtAddr += 4096; + length -= 4096; + } + + return ErrorVal.Success; + } + + void* install() { + + // Install Page Table + Paging.kernelPageTable.entries[0].address = (cast(ulong)rootPhysAddr) >> 12; + + return contextStackPtr; + } + + void execute() { + install(); + asm { + // Get return from install() and set as stack pointer + mov RSP, RAX; + + // Context Restore + + add RSP, 16; + + // Go to userspace + iretq; + } + } + +protected: + + void* stack; + void* heap; + + void* contextStack; + void* contextStackPtr; + void* rootPhysAddr; + PageLevel3* root; } diff --git a/kernel/arch/x86_64/vm.d b/kernel/arch/x86_64/vm.d index a107ebc..711cbde 100644 --- a/kernel/arch/x86_64/vm.d +++ b/kernel/arch/x86_64/vm.d @@ -22,6 +22,11 @@ struct VirtualMemory static: public: + ErrorVal initialize() { + // Install Virtual Memory and Paging + return Paging.initialize(); + } + // The page size we are using uint getPageSize() { return Paging.PAGESIZE; diff --git a/kernel/core/kmain.d b/kernel/core/kmain.d index c1db38c..77dfcae 100644 --- a/kernel/core/kmain.d +++ b/kernel/core/kmain.d @@ -15,9 +15,18 @@ import kernel.core.kprintf; //handle everything that the boot loader gives us import kernel.system.bootinfo; +// handle loading executables from modules +import kernel.system.loader; + +// Scheduler +import kernel.environ.scheduler; + //we need to print log stuff to the screen import kernel.core.log; +// kernel heap +import kernel.mem.heap; + // The main function for the kernel. // This will receive data from the boot loader. @@ -39,6 +48,12 @@ extern(C) void kmain(int bootLoaderID, void *data) // 2. Architecture Initialization printToLog("Initializing Architecture", Architecture.initialize()); + // Initialize the kernel Heap + Heap.initialize(); + + // 2b. Paging Initialization + printToLog("Initializing Virtual Memory", VirtualMemory.initialize()); + // 3. Processor Initialization printToLog("Initializing Processor", Cpu.initialize()); @@ -52,6 +67,15 @@ extern(C) void kmain(int bootLoaderID, void *data) printToLog("Initializing Multiprocessor", Multiprocessor.initialize()); // 7. Schedule + + Loader.loadModules(); + + Scheduler.initialize(); + Scheduler.schedule(); + + Scheduler.execute(); + + // Run task for(;;) { } diff --git a/kernel/environ/info.d b/kernel/environ/info.d new file mode 100644 index 0000000..3ed0323 --- /dev/null +++ b/kernel/environ/info.d @@ -0,0 +1,46 @@ +/* + * info.d + * + * This module describes an environment. + * + */ + +module kernel.environ.info; + +import kernel.core.error; + +import architecture; + +struct Environment { + void* start; + void* virtualStart; + + void* entry; + + ulong length; + + PageTable pageTable; + + ErrorVal initialize() { + // Create a page table for this environment + pageTable.initialize(); + pageTable.alloc(virtualStart, length); + + pageTable.preamble(entry); + + return ErrorVal.Success; + } + + ErrorVal preamble() { + return ErrorVal.Success; + } + + ErrorVal postamble() { + return ErrorVal.Success; + } + + void execute() { + pageTable.execute(); + } +} + diff --git a/kernel/environ/scheduler.d b/kernel/environ/scheduler.d new file mode 100644 index 0000000..1dc6dd1 --- /dev/null +++ b/kernel/environ/scheduler.d @@ -0,0 +1,52 @@ +/* + * scheduler.d + * + * Common interface to a scheduler. + * + */ + +module environ.scheduler; + +import kernel.core.error; + +import kernel.environ.info; + +import kernel.sched.uniprocess; + +import kernel.core.kprintf; + +struct Scheduler { +static: +public: + + ErrorVal initialize() { + return ErrorVal.Success; + } + + Environment* schedule() { + kprintfln!("Scheduler.schedule()")(); + return (current = UniprocessScheduler.schedule()); + } + + Environment* newEnvironment() { + kprintfln!("Scheduler.newEnvironment()")(); + return UniprocessScheduler.newEnvironment(); + } + + ErrorVal add(Environment* environ) { + kprintfln!("Scheduler.add()")(); + return UniprocessScheduler.add(environ); + } + + ErrorVal execute() { + current.execute(); + + // The previous function should NOT return + // So if it does, fail + return ErrorVal.Fail; + } + +private: + + Environment* current; +} diff --git a/kernel/mem/heap.d b/kernel/mem/heap.d index f9dbe82..e701aef 100644 --- a/kernel/mem/heap.d +++ b/kernel/mem/heap.d @@ -18,18 +18,31 @@ import kernel.core.kprintf; import kernel.core.log; import kernel.core.error; -struct Heap -{ +/* + + The Heap will be placed in virtual space directly after the virtual space + taken up by the kernel (kernel.virtualStart + kernel.length). + + The Architecture initialization will be responsible for reporting the + length and virtual address of the kernel. The architecture will need to + allot space for the bitmap and have a direct mapping to RAM for the Heap + to initialize. + + The Heap can be asked its location via the 'start' and 'virtualStart' + functions. When VirtualMemory is initialized, it will need to make + sure a mapping exists for Heap.start .. Heap.start + Heap.length to + map to Heap.virtualStart. + + */ + +struct Heap { static: public: // Needs to be called by the architecture - ErrorVal initialize(void* location) - { - kprintfln!("location: {x}")(location); + ErrorVal initialize() { // We do not want to reinitialize this module. - if (initialized) - { + if (initialized) { return ErrorVal.Fail; } @@ -40,7 +53,9 @@ public: totalPages = System.memory.length / VirtualMemory.getPageSize(); // Find the first free page, and set up the bitmap. - bitmap = cast(ulong*)location; + + // First, start out with the address at the end of the kernel + bitmap = cast(ulong*)(System.kernel.start + System.kernel.length); // Align the bitmap address to the page size (ceiling) ulong padding = cast(ulong)bitmap % VirtualMemory.getPageSize(); @@ -54,30 +69,92 @@ public: bitmapPages = totalPages / 64; if ((totalPages % 64) > 0) { bitmapPages++; } + ulong bitmapSize = bitmapPages * VirtualMemory.getPageSize(); + ulong* bitmapEdge = bitmap + (bitmapSize >> 3); + kprintfln!("bitmap: {x} for {x} pages : totalpages {x}")(bitmap, bitmapPages, totalPages); + // Now, check to see if the bitmap can fit here + bool bitmapOk = false; + while(!bitmapOk) { + uint i; + for (i = 0; i < System.numRegions; i++) { + ulong* regionAddr = cast(ulong*)System.regionInfo[i].start; + ulong* regionEdge = cast(ulong*)(System.regionInfo[i].start + System.regionInfo[i].length); + if ((bitmap < regionEdge) && (bitmapEdge > regionAddr)) { + // overlap... + // move bitmap + kprintfln!("Region Overlaps! Moving Heap")(); + bitmap = regionEdge; + // align to page size + bitmap = cast(ulong*)(cast(ubyte*)bitmap + VirtualMemory.getPageSize() - (cast(ulong)bitmap % VirtualMemory.getPageSize())); + bitmapEdge = bitmap + (bitmapSize >> 3); + break; + } + } + if (i < System.numRegions) { + continue; + } + + for (i = 0; i < System.numModules; i++) { + ulong* regionAddr = cast(ulong*)System.moduleInfo[i].start; + ulong* regionEdge = cast(ulong*)(System.moduleInfo[i].start + System.moduleInfo[i].length); + if ((bitmap < regionEdge) && (bitmapEdge > regionAddr)) { + // overlap... + // move bitmap + kprintfln!("Module Overlaps! Moving Heap")(); + bitmap = regionEdge; + // align to page size + bitmap = cast(ulong*)(cast(ubyte*)bitmap + VirtualMemory.getPageSize() - (cast(ulong)bitmap % VirtualMemory.getPageSize())); + bitmapEdge = bitmap + (bitmapSize >> 3); + kprintfln!("(NEW) Bitmap location: {x}")(bitmap); + break; + } + } + if (i == System.numModules) { + bitmapOk = true; + } + } + kprintfln!("Bitmap location: {x}")(bitmap); + // Set up the bitmap for the regions used by the system. // The kernel... markOffRegion(System.kernel.start, System.kernel.length); + // The bitmap... + markOffRegion(cast(void*)bitmap, bitmapSize); + // Each other region - for(uint i=0; i VirtualMemory.getPageSize) { + allocPage(); + regionLength -= VirtualMemory.getPageSize(); + } + + return ret; + } + // This will free an allocated page, if it is allowed. - ErrorVal freePage(void* address) - { + ErrorVal freePage(void* address) { // Find the page index ulong pageIndex = cast(ulong)address; // Is this address a valid result of allocPage? - if ((pageIndex % VirtualMemory.getPageSize()) > 0) - { + if ((pageIndex % VirtualMemory.getPageSize()) > 0) { // Should be aligned, otherwise, what to do here is ambiguious. return ErrorVal.Fail; } @@ -136,6 +221,14 @@ public: return bitmapPages * VirtualMemory.getPageSize(); } + ubyte* start() { + return cast(ubyte*)bitmapPhys; + } + + ubyte* virtualStart() { + return cast(ubyte*)bitmap; + } + private: // Whether or not this module has been initialized @@ -148,10 +241,10 @@ private: ulong bitmapPages; ulong* bitmap; + ulong* bitmapPhys; // A helper function to mark off a range of memory - void markOffRegion(void* start, ulong length) - { + void markOffRegion(void* start, ulong length) { // When aligning to a page, floor the start, ceiling the end // Get the first pageIndex @@ -161,8 +254,7 @@ private: startAddr = cast(ulong)start; endAddr = startAddr + length; startAddr -= startAddr % VirtualMemory.getPageSize(); - if ((endAddr % VirtualMemory.getPageSize())>0) - { + if ((endAddr % VirtualMemory.getPageSize())>0) { endAddr += VirtualMemory.getPageSize() - (endAddr % VirtualMemory.getPageSize()); } @@ -174,19 +266,16 @@ private: ulong maxIndex = (endAddr - startAddr) / VirtualMemory.getPageSize(); maxIndex += pageIndex; - for(; pageIndex= totalPages) - { + if (pageIndex >= totalPages) { return; } @@ -197,48 +286,42 @@ private: } // Returns the page index of a free page - ulong findPage() - { + ulong findPage() { ulong* curPtr = bitmap; ulong curIndex = 0; - ulong subIndex = 0; - while(true) - { + while(true) { // this would mean that there is a 0 in there somewhere - if (*curPtr < 0xffffffffffffffffUL) - { + if (*curPtr < 0xffffffffffffffffUL) { // look for the 0 - subIndex = 0; - ulong tmpVal = *curPtr; - - if((tmpVal & 0x1) == 0) - { - if (curIndex < totalPages) - { - // mark it off as used - *curPtr |= (1 << subIndex); - - // return the page index - return curIndex; + ulong subIndex = curIndex; + + for (uint b; b < 64; b++) { + if((tmpVal & 0x1) == 0) { + if (subIndex < totalPages) { + // mark it off as used + *curPtr |= cast(ulong)(1UL << b); + + // return the page index + return subIndex; + } + else { + return 0xffffffffffffffffUL; + } } - else - { - return 0xffffffffffffffffUL; + else { + tmpVal >>= 1; + subIndex++; } } - else - { - tmpVal >>= 1; - curIndex++; - subIndex++; - } + + // Shouldn't get here... the world will end + return 0xffffffffffffffffUL; } curIndex += 64; - if (curIndex >= totalPages) - { + if (curIndex >= totalPages) { return 0xffffffffffffffffUL; } curPtr++; diff --git a/kernel/sched/uniprocess.d b/kernel/sched/uniprocess.d new file mode 100644 index 0000000..c2b75bc --- /dev/null +++ b/kernel/sched/uniprocess.d @@ -0,0 +1,40 @@ +/* + * uniprocess.d + * + * This scheduler will only run one user app. + * + */ + +module sched.uniprocess; + +import kernel.environ.info; + +import kernel.core.error; + +struct UniprocessScheduler { +static: + + // Do not do anything + Environment* schedule() { + return &environment; + } + + // Set up the only environment + Environment* newEnvironment() { + if (numEnvironments == MAX_ENVIRONMENTS) { + return null; + } + numEnvironments++; + return &environment; + } + + ErrorVal add(Environment* environ) { + return ErrorVal.Success; + } + +protected: + const uint MAX_ENVIRONMENTS = 1; + + Environment environment; + uint numEnvironments; +} diff --git a/kernel/system/definitions.d b/kernel/system/definitions.d index 509efbd..784e6e5 100644 --- a/kernel/system/definitions.d +++ b/kernel/system/definitions.d @@ -5,8 +5,7 @@ module kernel.system.definitions; // This structure keeps track of information pertaining to onboard memory. -struct Memory -{ +struct Memory { // The size of the RAM. ulong length; @@ -15,20 +14,20 @@ struct Memory } // This structure keeps track of modules loaded alongside the kernel. -struct Module -{ +struct Module { // The location and length of the module. ubyte* start; ulong length; + ubyte* virtualStart; + // The name of the module, if given. char[64] name; } // This enum is for the Region structure // It contains human-read information about the type of region. -enum RegionType: ubyte -{ +enum RegionType: ubyte { // The region is special reserved data from the BIOS Reserved, @@ -37,8 +36,7 @@ enum RegionType: ubyte } // This structure keeps track of special memory regions. -struct Region -{ +struct Region { // The location and length of the region ubyte* start; ulong length; @@ -51,8 +49,7 @@ struct Region } // This structure keeps information about the disks found in the system. -struct Disk -{ +struct Disk { // Some identifing number for the drive, as reported by the system. ulong number; @@ -68,8 +65,7 @@ struct Disk // This structure stores information about the processors available // in the system. -struct Processor -{ +struct Processor { } diff --git a/kernel/system/elf.d b/kernel/system/elf.d index efad7be..0f76991 100644 --- a/kernel/system/elf.d +++ b/kernel/system/elf.d @@ -7,11 +7,11 @@ module kernel.core.elf; -import kernel.core.multiboot; +import kernel.system.multiboot; -import kernel.arch.vmem; +import kernel.core.kprintf; -struct ELF { +struct Elf { static: alias void* elf64_addr; // size 8 @@ -74,9 +74,9 @@ static: const elfosabi_standalone = 255; const elfmag0 = 0x7f; - const elfmag1 = 'e'; - const elfmag2 = 'l'; - const elfmag3 = 'f'; + const elfmag1 = 0x45; + const elfmag2 = 0x4c; + const elfmag3 = 0x46; /** these constant variables declare possible values for the ei_class member of the e_ident[] array. they identify the object file as @@ -211,8 +211,8 @@ static: template elf32_st_type(int i) { const elf32_st_type = i & 0xf; } template elf32_st_info(int b, int t) { const elf32_st_info = (b << 4) + (t & 0xf); } template elf64_r_sym(int i) { const elf64_r_sym = i >> 32; } - template elf64_r_type(int i) { const elf64_r_type = i & 0xffffffffl; } - template elf64_r_info(int s, int t) { const elf64_r_info = (s << 32) + (t & 0xffffffffl); } + template elf64_r_type(int i) { const elf64_r_type = i & 0xffffffffL; } + template elf64_r_info(int s, int t) { const elf64_r_info = (s << 32) + (t & 0xffffffffL); } const elf_entryaddy_offset = (ei_nident * ubyte.sizeof) + 2 * elf64_half.sizeof + elf64_word.sizeof + 4; @@ -478,21 +478,21 @@ static: elf_start = a pointer to the beginning of the elf header. returns: int (0 or 1), depending on whether the magic number matches or not. */ - int elf64_check_magic(char *elf_start) { - if (elf_start[0] == elfmag0 && - elf_start[1] == elfmag1 && - elf_start[2] == elfmag2 && - elf_start[3] == elfmag3) { - return 1; - } - else { - return 0; + bool isValid(ubyte* address) { + kprintfln!("ELF header: {x} {x} {x} {x}...")(address[0], address[1], address[2], address[3]); + if (address[0] == elfmag0 && + address[1] == elfmag1 && + address[2] == elfmag2 && + address[3] == elfmag3) { + kprintfln!("true")(); + return true; } + return false; } // will return the offset to the bss section or null. it will fill the variables. it will return true on success. bool fillbssinfo(void* address, out void* bssaddress, out uint length) { - bssaddress = null; + /* bssaddress = null; length = 0; elf64_ehdr* header = cast(elf64_ehdr*)address; @@ -524,7 +524,7 @@ static: length = section.sh_size; return true; } - } + }*/ return false; } @@ -544,7 +544,7 @@ static: // gets the entry point at the elf header located at address void* getentry(void* address) { - elf64_ehdr* header = cast(elf64_ehdr*)address; +/* elf64_ehdr* header = cast(elf64_ehdr*)address; // find all the sections in the module's elf section header. elf64_shdr[] sections = (cast(elf64_shdr*)(address + header.e_shoff))[0 .. header.e_shnum]; @@ -555,6 +555,35 @@ static: // declare a void function which can be called to jump to the memory position of // __start(). - return cast(void*)text.sh_offset; + return cast(void*)text.sh_offset;*/ + return (cast(void*)(cast(elf64_ehdr*)address).e_entry); + } + + void* getphysaddr(void* address) { + elf64_ehdr* header = cast(elf64_ehdr*)address; + elf64_phdr* load = cast(elf64_phdr*)(address + header.e_phoff); + return cast(void*)load.p_paddr; + } + + void* getvirtaddr(void* address) { + elf64_ehdr* header = cast(elf64_ehdr*)address; + elf64_phdr* load = cast(elf64_phdr*)(address + header.e_phoff); + return cast(void*)load.p_vaddr; + } + + ulong getoffset(void* address) { + elf64_ehdr* header = cast(elf64_ehdr*)address; + + // find all the sections in the module's elf section header. + //elf64_shdr[] sections = (cast(elf64_shdr*)(address + header.e_shoff))[0 .. header.e_shnum]; + //elf64_shdr* strtable = §ions[header.e_shstrndx]; + + // go to the first section in the section header. + elf64_phdr* load = cast(elf64_phdr*)(address + header.e_phoff); + + kprintfln!("text phoff: {x} ptr: {x}")(header.e_phoff, load); + // declare a void function which can be called to jump to the memory position of + // __start();; + return cast(ulong)load.p_offset; } } diff --git a/kernel/system/loader.d b/kernel/system/loader.d new file mode 100644 index 0000000..06725be --- /dev/null +++ b/kernel/system/loader.d @@ -0,0 +1,100 @@ +/* + * loader.d + * + * This module can load an executable. + * + */ + +module kernel.system.loader; + +import kernel.system.elf; +import kernel.system.info; + +import kernel.environ.info; +import kernel.environ.scheduler; + +import kernel.core.error; +import kernel.core.kprintf; + +import kernel.mem.heap; + +import kernel.core.util; + +import architecture; + +extern(C) void* memcpy(void*, void*, size_t); + +struct Loader { +static: + + // This function will load all modules. + ErrorVal loadModules() { + for(uint i = 0; i < System.numModules; i++) { + // Map in module + + System.moduleInfo[i].virtualStart = cast(ubyte*)VirtualMemory.mapRegion(System.moduleInfo[i].start, System.moduleInfo[i].length); + loadFromModule(i); + } + return ErrorVal.Success; + } + + // This function will load an executable from a module, if it can. + ErrorVal loadFromModule(uint index) { + + // check bounds + if (index >= System.moduleInfo.length) { + return ErrorVal.Fail; + } + + if (index >= System.numModules) { + return ErrorVal.Fail; + } + + // Check the module for being a compatible executable + ubyte* moduleAddr = System.moduleInfo[index].virtualStart; + kprintfln!("Module Found: {x} : {x}")(System.moduleInfo[index].start, moduleAddr); + if (Elf.isValid(moduleAddr)) { + void* entryAddress = Elf.getentry(moduleAddr); + void* physAddress = Elf.getphysaddr(moduleAddr); + void* virtAddress = Elf.getvirtaddr(moduleAddr); + kprintfln!("ELF Module : {}\n Entry: {x} p: {x} v: {x}")(index, entryAddress, physAddress, virtAddress); + + // Create an environment through the scheduler + Environment* environ = Scheduler.newEnvironment(); + + if (environ is null) { + kprintfln!("No more environments!")(); + } + else { + // Load executable + environ.virtualStart = virtAddress; + environ.length = System.moduleInfo[index].length - Elf.getoffset(moduleAddr); + + kprintfln!("Initializing this environment")(); + //environ.start = System.moduleInfo[index].start; + environ.start = physAddress; + //environ.virtualStart = moduleAddr; + + environ.entry = entryAddress; + + environ.initialize(); + kprintfln!("Loading this environment {}")(Elf.getoffset(moduleAddr)); + ulong length = environ.length; + ubyte* d = cast(ubyte*)environ.virtualStart; + ubyte* s = cast(ubyte*)moduleAddr; + s += Elf.getoffset(moduleAddr); + for(ulong i; i < length; i++) { + *d = *s; + d++; + s++; + } + kprintfln!("Environment Loaded")(); + + Scheduler.add(environ); + kprintfln!("Success (Environment Loaded)")(); + } + } + + return ErrorVal.Success; + } +} diff --git a/kernel/system/multiboot.d b/kernel/system/multiboot.d index 0bae102..f07fa33 100644 --- a/kernel/system/multiboot.d +++ b/kernel/system/multiboot.d @@ -151,12 +151,15 @@ ErrorVal verifyBootInformation(int id, void *data) { multi_module *mod = cast(multi_module *)(info.mods_addr); int mod_count = info.mods_count; - for(int i = 0; i < mod_count; i++, mod++) { + for(int i = 0; i < mod_count && i < 10; i++, mod++) { System.moduleInfo[i].start = cast(ubyte *)(mod.mod_start); - System.moduleInfo[i].length = cast(uint)(mod.mod_end); + System.moduleInfo[i].length = cast(uint)(mod.mod_end - mod.mod_start); + int len = strlen(cast(char *)mod.string); System.moduleInfo[i].name[0 .. len] = (cast(char *)(mod.string))[0 .. len]; - kprintfln!("module {}: start:{} length:{} name:{}")(i, cast(uint)(mod.mod_start), cast(uint)(mod.mod_end), cast(char *)(mod.string)); + + kprintfln!("module {}: start:{} length:{} name:{}")(i, System.moduleInfo[i].start, System.moduleInfo[i].length, System.moduleInfo[i].name[0..len]); + System.numModules++; } } @@ -222,23 +225,23 @@ ErrorVal verifyBootInformation(int id, void *data) { number = dinfo.drive_number; // Configuration - heads = dinfo.drive_heads; - cylinders = dinfo.drive_cylinders; - sectors = dinfo.drive_sectors; - - // Ports (determined by the size of the structure) - numPorts = dinfo.size - 10; - numPorts /= 2; - - // Allow no more than the amount we can statically store - if (numPorts > ports.length) - { - numPorts = ports.length; - } + heads = dinfo.drive_heads; + cylinders = dinfo.drive_cylinders; + sectors = dinfo.drive_sectors; + + // Ports (determined by the size of the structure) + numPorts = dinfo.size - 10; + numPorts /= 2; + + // Allow no more than the amount we can statically store + if (numPorts > ports.length) + { + numPorts = ports.length; + } - // Copy the information - ports[0..numPorts] = dinfo.ports[0..numPorts]; - } + // Copy the information + ports[0..numPorts] = dinfo.ports[0..numPorts]; + } // Go to the next disk entry. System.numDisks++;