aboutsummaryrefslogtreecommitdiffstats
path: root/bootloader/main.c
diff options
context:
space:
mode:
authorGravatar ornitorrincos 2026-08-18 12:15:05 +0200
committerGravatar ornitorrincos 2026-08-18 12:15:05 +0200
commit132d3236bb884433bf94e961f6d32264e0334aec (patch)
tree06638976b06f019ea4037175ff228f8271057c44 /bootloader/main.c
Diffstat (limited to '')
-rw-r--r--bootloader/main.c396
1 files changed, 396 insertions, 0 deletions
diff --git a/bootloader/main.c b/bootloader/main.c
new file mode 100644
index 0000000..e196777
--- /dev/null
+++ b/bootloader/main.c
@@ -0,0 +1,396 @@
+#include <efi.h>
+#include <efilib.h>
+#include <efidef.h>
+#include <string.h>
+
+#include "disk.h"
+#include "vga.h"
+#include "vmmem.h"
+#include "ELF.h"
+#include "memorytypes.h"
+#include "paging_struct.h"
+#include "paging.h"
+#include "other.h"
+
+// pixel struct information(hardcoded to what qemu exposes)
+typedef struct _Pixel
+{
+ UINT8 B;
+ UINT8 G;
+ UINT8 R;
+ UINT8 Z;
+} Pixel;
+
+// struct that is going to be passed to the kernel about general system information
+typedef struct _OSDATA
+{
+ UINT32 Magic; // magic number to check
+
+ UINT32 FBWidth; // with of the framebuffer
+ UINT32 FBHeight; // height
+ UINT32 PixelSize; // size of each pixel(an rgb pixel might have a bigger size)
+ void * FBAddr; // address of the linear framebuffer
+
+ void * MEMMap; // pointer to the system memory map
+
+ void * RAMDisk; // pointer to a ramdisk loaded from the hdd
+
+ void* RSDP;
+} OSDATA;
+
+extern void BootDisableInterrupts(void); // asm code is not correct(callee doesn't set the stack correctly)
+typedef void (*kfn)(OSDATA *); // typedef to setup the entry point of the kernel and do a "jump" into it
+
+
+
+void
+EFIAPI
+efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
+{
+ __asm__("hlt");
+
+ // Memory Map
+ UINTN mapsize = 0;
+ UINTN allocsize = 0;
+ EFI_MEMORY_DESCRIPTOR * map = NULL;
+ UINTN mapkey = 0;
+ UINTN descriptorsize = 0;
+ UINT32 version = 0;
+
+
+ InitializeLib(ImageHandle, SystemTable);
+ uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); // clear the screen
+ //Pixel * fb = SetVideoMode(1024, 768, 32);
+ Pixel * fb = SetVideoMode(800, 600, 24);
+
+ PrintImageAddr(ImageHandle);
+
+ // Print(L"Number of tables: %d\n", SystemTable->NumberOfTableEntries);
+
+ EFI_GUID acpi_10 = ACPI_TABLE_GUID;
+ EFI_GUID acpi_20 = ACPI_20_TABLE_GUID;
+ void* acpi20table = NULL;
+
+
+ for(int i = 0; i < SystemTable->NumberOfTableEntries; i++)
+ {
+ if(AreEqual(&(SystemTable->ConfigurationTable[i].VendorGuid), &acpi_10, sizeof(EFI_GUID)))
+ {
+ // Print(L"ACPI 1.0 Found\n");
+ }
+ if(AreEqual(&(SystemTable->ConfigurationTable[i].VendorGuid), &acpi_20, sizeof(EFI_GUID)))
+ {
+ // Print(L"ACPI 2.0 Found\n");
+ acpi20table = SystemTable->ConfigurationTable[i].VendorTable; // <- this should be the RSDP
+ }
+ }
+
+ // some uefi implementations time out with their default setting, disable the timer
+ BS->SetWatchdogTimer(0, 0, 0, NULL);
+
+
+ //Print(L"Firmware Vendor: %s Rev: 0x%08x\n", ST->FirmwareVendor, ST->FirmwareRevision);
+
+ //while(1){};
+
+ // allocate the datat for the kernel(need to specify memory time not to be a generic loader data type)
+ OSDATA * osdata = AllocatePool(sizeof(OSDATA));
+
+ if(osdata == NULL)
+ {
+ Print(L"Os Data allocation failed\n");
+ }
+
+ int32_t kernel_size;
+
+ ELF * kernel = LoadFile(L"kernel.bin", MEM_KERNEL, &kernel_size); // we set the memory type to the one from the kernel
+
+ {
+ PH* ph = (PH*)(((uint64_t)kernel) + kernel->e_phoff); // use this to know how much and what pages to map
+ uint64_t phcount = (((uint64_t)kernel) + kernel->e_phnum);
+
+ //kernel_size = ph->p_filesz;
+ uint64_t size = (uint64_t)(kernel_size = ph->p_memsz);
+ uint64_t entry = (uint64_t)(kernel + ph->p_offset);
+
+ /*
+ Print(L"Kernel Size: 0x%llX\n", size);
+ Print(L"Kernel Entry: 0x%llX\n", entry);
+ Print(L"Program Header Count: 0x%llX\n", phcount);
+ */
+ }
+
+ // print general information about the kernel elf header
+ //PrintELFInfo(kernel);
+ Loaded_ELF* loaded_kernel = LoadELF(kernel);
+
+
+ // attempt to allocate the memory map, first try is going to be too small
+ // as such the firmware will return the correct size
+ EFI_STATUS memret = EFI_SUCCESS;
+ EFI_STATUS bootstatus = EFI_SUCCESS;
+
+ uefi_call_wrapper(BS->GetMemoryMap, 5, &mapsize, map, &mapkey, &descriptorsize, &version);
+
+
+ // as the allocation will probably modify the memory map allocate 4kb more(one page)
+ // so that the new memory map probably fits
+ allocsize = mapsize + 10*4098;
+
+ mapsize = allocsize;
+
+ uefi_call_wrapper(BS->AllocatePool, 3, EfiLoaderData, allocsize, (void**)&map);
+
+ uefi_call_wrapper(BS->GetMemoryMap, 5, &mapsize, map, &mapkey, &descriptorsize, &version);
+
+ // set virtual addresses in here
+ // try some paging
+ initCR3();
+
+ //uint64_t address = 0;
+ //uint64_t max = 0x400000000ull;//0x20000000;
+ // EFI_MEMORY_DESCRIPTOR * mapiterator = map;
+
+ uint64_t elements = mapsize/descriptorsize;
+
+ printCR3();
+
+ //Print(L"elements: %d\n", elements);
+
+
+
+ for(int entry = 0; entry < elements; ++entry)
+ {
+ // mapiterator = (EFI_MEMORY_DESCRIPTOR*)(((EFI_PHYSICAL_ADDRESS)mapiterator + descriptorsize));
+
+ EFI_MEMORY_DESCRIPTOR* mapiterator = (EFI_MEMORY_DESCRIPTOR*)(((uint8_t*)map) + entry*descriptorsize);
+
+ // EFI_MEMORY_DESCRIPTOR* mapiterator = &(map[entry]);
+ uint64_t page = mapiterator->PhysicalStart;
+
+ uint64_t Pstart = mapiterator->PhysicalStart;
+ uint64_t Vstart = mapiterator->VirtualStart;
+ uint64_t Npages = mapiterator->NumberOfPages;
+ uint64_t Tpage = mapiterator->Type;
+ uint64_t Att = mapiterator->Attribute;
+
+ //if(Pstart != Vstart)
+ /*
+ if(Vstart != 0)
+ {
+ Print(L"\n");
+ Print(L"---------------------------------------\n");
+ Print(L"NON MATCHING PHYSICAL AND VIRTUAL PAGES\n");
+ Print(L"Physical Start: 0x%llX\n", Pstart);
+ Print(L"Virtual Start: 0x%llX\n", Vstart);
+ Print(L"Number of Pages: 0x%llX\n", Npages);
+ Print(L"Type of Page: 0x%llX\n", Tpage);
+ Print(L"---------------------------------------\n");
+ Print(L"\n");
+ }
+ */
+
+ // if((Npages > 0) && (Vstart != 0))
+ // if(Vstart != 0)
+ // if((Pstart == 0) && (Vstart == 0))
+ // if(Pstart == Vstart)
+ if(Tpage == EfiConventionalMemory) // free pages
+ {
+ Print(L"\n");
+ Print(L"---------------------------------------\n");
+ Print(L"MAPPED MEMORY\n");
+ Print(L"Physical Start: 0x%llX\n", Pstart);
+ Print(L"Virtual Start: 0x%llX\n", Vstart);
+ Print(L"Number of Pages: 0x%llX\n", Npages);
+ Print(L"Type of Page: 0x%llX\n", Tpage);
+ Print(L"Attribute of Page: 0x%llX\n", Att);
+ Print(L"---------------------------------------\n");
+ Print(L"\n");
+ }
+
+ //Print(L"page: 0x%llX\n", page);
+ /* for(int pageentry = 0; pageentry < mapiterator->NumberOfPages; pageentry++)
+ {
+ //Print(L"SetAddr\n");
+ SetVirtualAddress(page, page);
+ page += 0x1000;
+ } */
+ }
+
+ while(1) {};
+
+ uint64_t maxaddr = 0x0000001000000000ull;
+ for(uint64_t page = 0x0; page < maxaddr; page += 0x1000)
+ {
+ SetVirtualAddress(page, page); // <- This is chanigng the memorymap 100%
+ }
+
+ // need to map the physical address the kernel is in to -2GB virtual
+ //uint64_t startvm = 0xffffffff7fffffffull;
+ //uint64_t startvm = kernel->e_entry;
+ //uint64_t currentvm = 0;
+
+ //PH* ph = (PH*)(((uint64_t)kernel) + kernel->e_phoff); // use this to know how much and what pages to map
+
+ //kernel_size = ph->p_filesz;
+ //kernel_size = ph->p_memsz;
+
+ /*
+ while(currentvm < kernel_size)
+ {
+ SetVirtualAddress((uint64_t)kernel + ph->p_offset + currentvm, startvm + currentvm);
+
+ currentvm += 0x1000;
+ }
+ */
+
+ Print(L"BEFORE MAPPING KERNEL ENTRY: 0x%llX\n", loaded_kernel->entry);
+
+ for(int i = 0; i < loaded_kernel->ph_num; i++)
+ {
+ Loaded_PH* ph = &(loaded_kernel->ph[i]);
+ Print(L"MAPPING PH: 0x%llX\n", (uint64_t)ph->vaddr);
+ uint64_t mapsize = ph->mem_size;
+ uint64_t mapped = 0;
+ while(mapped < mapsize)
+ {
+ SetVirtualAddress((uint64_t)ph->data + mapped, (uint64_t)ph->vaddr + mapped);
+ mapped += 0x1000;
+ }
+ }
+
+ // now map already allocated 8KB for the Kernel Stack
+
+
+ //printCR3();
+
+ //Print(L"kernel: 0x%llx\n", kernel);
+
+ // the call to exit boot services tells the firmware we are ready to take control of the system
+
+ // never ever call Print after the next line
+ // after the first call boot services can be partially disabled
+ // loop until the firmware reports a successful exit, the specification allows for partial shutdowns
+ // so more than one call might be necessary(on qemu with OVMF it is)
+ while((bootstatus = uefi_call_wrapper(BS->ExitBootServices, 2, ImageHandle, mapkey)) != EFI_SUCCESS) // <- actually we need an up to date mapkey, so maybe we could actually get a memorymap before, create a OS liked memory map and exit services?
+ {
+
+ mapsize = allocsize;
+
+ while((memret = uefi_call_wrapper(BS->GetMemoryMap, 5, &mapsize, map, &mapkey, &descriptorsize, &version)) == EFI_BUFFER_TOO_SMALL)
+ {
+
+ allocsize = allocsize + 2*4096; // add 8kb(2 pages)
+
+ uefi_call_wrapper(BS->FreePool, 1, map);
+
+ uefi_call_wrapper(BS->AllocatePool, 3, EfiLoaderData, allocsize, (void**)&map);
+
+ mapsize = allocsize;
+ }
+ }
+
+ SetCrc(&(SystemTable->Hdr)); // As we exited boot services we need to set the CRC32 again
+
+ // as we can't print to the screen the way of showing the return status of this function
+ // is to write a red or green square on the top left corner of the screen
+ if(SetVM(mapsize, descriptorsize, version, map, kernel) != EFI_SUCCESS)
+ {
+ int i = 0;
+ int j = 0;
+
+ for(i = 0; i < 256; ++i)
+ {
+ for(j = 0; j < 256; ++j)
+ {
+ Pixel p;
+ p.R = 255;
+ p.G = 0;
+ p.B = 0;
+ //p.Z = 255;
+ fb[j + 800*i] = p;
+ }
+ }
+ } else
+ {
+ int i = 0;
+ int j = 0;
+
+ for(i = 0; i < 64; ++i)
+ {
+ for(j = 0; j < 64; ++j)
+ {
+ Pixel p;
+ p.R = 0;
+ p.G = 255;
+ p.B = 0;
+ //p.Z = 255;
+ fb[j + 800*i] = p;
+ }
+ }
+ }
+
+ // we should now set s Print(L"Calling ExitBootServices\n");oe virtual mapping
+ //BootDisableInterrupts();
+
+
+ //OSDATA * osdata = (OSDATA*)(640*1024);
+
+
+
+ osdata->Magic = 0xDDEE;
+ osdata->FBWidth = 1024;
+ osdata->FBHeight = 768;
+ osdata->FBAddr = fb;
+ osdata->PixelSize = 24;
+ osdata->MEMMap = map;
+ osdata->RAMDisk = NULL;
+ osdata->RSDP = acpi20table;
+
+ // this while only serves not to call the kernel for now
+ // after calling exit boot services we can't return to the uefi environment because it's been destroyed
+ //
+
+ //kernel = (ELF*)0x280000000; // correct virtual pointer to 10GB (Sign: 0 PML4: 0 PDP:10 PD:0 Page:0)
+
+ // kfn kernel_jump = (void*)kernel->e_entry;//(void*)((EFI_PHYSICAL_ADDRESS)kernel + kernel->EntryPoint);
+ kfn kernel_jump = (void*)loaded_kernel->entry;//(void*)((EFI_PHYSICAL_ADDRESS)kernel + kernel->EntryPoint);
+
+
+ writeCR3();
+ //while(1){}
+ {
+ int i = 0;
+ int j = 0;
+
+ for(i = 0; i < 256; ++i)
+ {
+ for(j = 0; j < 256; ++j)
+ {
+ Pixel p;
+ p.R = 255;
+ p.G = 255;
+ p.B = 255;
+ p.Z = 255;
+ fb[j + 800*i] = p;
+ }
+ }
+ }
+
+ // disable interrupts
+ __asm__("cli");
+
+ //writeCR3();
+
+
+ //__asm__("hlt");
+
+ kernel_jump(osdata);
+
+ while(1){}
+
+ __asm__("hlt"); // sanity in case the kernel exists, should throw an error somehow
+ // not as if the kernel shouldn't have this same code at the end of the main though
+
+ // we should never ever reach this point(if kernel exists, it should shutdown the computer)
+}