From 1ce7df083a8b1b6d3ed63e529d128e399f5ee032 Mon Sep 17 00:00:00 2001 From: nakst <> Date: Fri, 29 Oct 2021 14:42:47 +0100 Subject: [PATCH] booting into 32 bit kernels --- arch/x86_64/kernel.cpp | 1 + boot/x86/loader.s | 179 ++++++++++++++++++++++++++++++++++++++++- util/build.c | 10 ++- 3 files changed, 186 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/kernel.cpp b/arch/x86_64/kernel.cpp index 98eabeb..73448e5 100644 --- a/arch/x86_64/kernel.cpp +++ b/arch/x86_64/kernel.cpp @@ -303,6 +303,7 @@ bool MMArchMapPage(MMSpace *space, uintptr_t physicalAddress, uintptr_t virtualA // That said, a CPU won't overwrite and clear a dirty bit when writing out its accessed flag (tested on Qemu); // see here https://stackoverflow.com/questions/69024372/. // Tl;dr: if a CPU ever sees an entry without these bits set, it can overwrite the entry with junk whenever it feels like it. + // TODO Should we be marking page tables as dirty/accessed? (Including those made by the 32-bit AND 64-bit bootloader and MMArchInitialise). value |= (1 << 5) | (1 << 6); if ((oldValue & 1) && !(flags & MM_MAP_PAGE_OVERWRITE)) { diff --git a/boot/x86/loader.s b/boot/x86/loader.s index bf4314d..b5c95f2 100644 --- a/boot/x86/loader.s +++ b/boot/x86/loader.s @@ -1,7 +1,7 @@ [bits 16] [org 0x1000] -; This is missing any fileSystem specific macros. +; This is missing any file system specific macros. %define vesa_info 0x7000 %define os_installation_identifier 0x7FF0 %define temporary_load_buffer 0x9000 @@ -363,7 +363,184 @@ setup_elf: jne error_32 cmp byte [ebx + 4],2 je setup_elf_64 + cmp byte [ebx + 4],1 jne error_32 + jmp setup_elf_32 + +setup_elf_32: + mov dword [page_table_allocation_location],0x2000 + + ; Check the ELF data is correct + mov ebx,[kernel_buffer] + mov esi,error_bad_kernel + cmp byte [ebx + 5],1 + jne error_32 + cmp byte [ebx + 7],0 + jne error_32 + cmp byte [ebx + 16],2 + jne error_32 + cmp byte [ebx + 18],0x03 + jne error_32 + + ; Find the program headers + ; EAX = ELF header, EBX = program headers + mov eax,ebx + mov ebx,[eax + 28] + add ebx,eax + + ; ECX = entries, EDX = size of entry + movzx ecx,word [eax + 44] + movzx edx,word [eax + 42] + + ; Loop through each program header + .loop_program_headers: + push eax + push ecx + push edx + push ebx + + ; Only deal with load segments + mov eax,[ebx] + cmp eax,1 + jne .next_entry + + ; Work out how many physical pages we need to allocate + mov ecx,[ebx + 20] + shr ecx,12 + inc ecx + + ; Get the starting virtual address + mov eax,[ebx + 8] + mov [.target_page],eax + + ; For every frame in the segment + .frame_loop: + xor ebx,ebx + + ; For every memory region + .memory_region_loop: + + ; Check the region has enough pages remaining + mov eax,[ebx + memory_map + 8] + or eax,eax + jz .try_next_memory_region + + ; Remove one page from the region + mov eax,[ebx + memory_map + 4] + or eax,eax + jnz .try_next_memory_region ; Reject 64-bit pages. + mov eax,[ebx + memory_map + 0] + mov [.physical_page],eax + add eax,0x1000 + mov [ebx + memory_map + 0],eax + sub dword [ebx + memory_map + 8],1 + + jmp .found_physical_page + + ; Go to the next memory region + .try_next_memory_region: + add ebx,16 + mov eax,[load_memory_map.pointer] + cmp ebx,eax + jne .memory_region_loop + mov esi,error_no_memory + jmp error_32 + + ; Map the page into virtual memory + .found_physical_page: + + ; Make sure we have a page table + mov eax,[.target_page] + shr eax,22 + shl eax,2 + add eax,0xFFFFF000 + mov ebx,[eax] + cmp ebx,0 + jne .has_pt + mov ebx,[page_table_allocation_location] + add ebx,page_directory + or ebx,7 + mov [eax],ebx + add dword [page_table_allocation_location],0x1000 + mov eax,cr3 + mov cr3,eax + .has_pt: + + ; Map the page! + mov eax,[.target_page] + shr eax,12 + mov ebx,[.physical_page] + or ebx,0x103 + shl eax,2 + add eax,0xFFC00000 + mov [eax],ebx + mov ebx,[.target_page] + invlpg [ebx] + + ; Go to the next frame + add dword [.target_page],0x1000 + dec ecx + or ecx,ecx + jnz .frame_loop + + ; Restore the pointer to the segment + pop ebx + push ebx + + ; Clear the memory + mov ecx,[ebx + 20] + xor eax,eax + mov edi,[ebx + 8] + rep stosb + + ; Copy the memory + mov ecx,[ebx + 16] + mov esi,[ebx + 4] + add esi,[kernel_buffer] + mov edi,[ebx + 8] + rep movsb + + ; Go to the next entry + .next_entry: + pop ebx + pop edx + pop ecx + pop eax + + add ebx,edx + dec ecx + or ecx,ecx + jnz .loop_program_headers + + jmp run_kernel32 + + .target_page: dd 0 + .physical_page: dd 0 + +run_kernel32: + ; Let the kernel use the memory that was used to store the executable + xor eax,eax + mov ebx,[load_memory_map.pointer] + mov [memory_map + ebx + 4],eax + mov [memory_map + ebx + 12],eax + mov [memory_map + ebx + 16],eax + mov [memory_map + ebx + 20],eax + mov eax,[memory_map + ebx + 8] + mov [memory_map + ebx + 24],eax + mov eax,[memory_map + ebx + 12] + mov [memory_map + ebx + 28],eax + mov eax,[kernel_buffer] + mov [memory_map + ebx],eax + mov eax,[kernel_size] + shr eax,12 + mov [memory_map + ebx + 8],eax + + ; Execute the kernel's _start function + mov ebx,[kernel_buffer] + mov ecx,[ebx + 24] + xor edi,edi + mov esi,1 + jmp ecx setup_elf_64: ; Check that the processor is 64-bit diff --git a/util/build.c b/util/build.c index 7a486d1..791106a 100644 --- a/util/build.c +++ b/util/build.c @@ -2,14 +2,16 @@ #define _GNU_SOURCE #endif -#if 1 +#if 0 #define TOOLCHAIN_PREFIX "x86_64-essence" #define TARGET_NAME "x86_64" #define TOOLCHAIN_HAS_RED_ZONE #define TOOLCHAIN_HAS_CSTDLIB +#define QEMU_EXECUTABLE "qemu-system-x86_64" #else #define TOOLCHAIN_PREFIX "i686-elf" #define TARGET_NAME "x86_32" +#define QEMU_EXECUTABLE "qemu-system-i386" #endif #define WARNING_FLAGS \ @@ -519,7 +521,7 @@ void Run(int emulator, int log, int debug) { serialFlags[0] = 0; } - CallSystemF("%s %s qemu-system-x86_64 %s%s %s -m %d %s -smp cores=%d -cpu Haswell " + CallSystemF("%s %s " QEMU_EXECUTABLE " %s%s %s -m %d %s -smp cores=%d -cpu Haswell " " -device qemu-xhci,id=xhci -device usb-kbd,bus=xhci.0,id=mykeyboard -device usb-mouse,bus=xhci.0,id=mymouse " " -netdev user,id=u1 -device e1000,netdev=u1 -object filter-dump,id=f1,netdev=u1,file=bin/net.dat " " %s %s %s %s %s %s %s ", @@ -1397,7 +1399,9 @@ void DoCommand(const char *l) { LineCountFile("", "start.sh"); const char *folders[] = { - "desktop/", "boot/x86/", "drivers/", "kernel/", "apps/", "apps/file_manager/", "shared/", "util/" + "desktop/", "boot/x86/", "drivers/", "kernel/", + "apps/", "apps/file_manager/", "shared/", "util/", + "arch/", "arch/x86_32/", "arch/x86_64/", }; for (uintptr_t i = 0; i < sizeof(folders) / sizeof(folders[0]); i++) {