From 4577c2d10c436056c2f81293dd72e6a2fcb3c33b Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 1 Apr 2018 22:48:46 -0700 Subject: [PATCH] Add the beginning of support for kernel graphics to bootloader. * Load a font file off disk to pass to kernel * Expose a framebuffer to the kernel * Currently the kernel just paints the screen red --- Makefile | 7 +- assets/fonts/tamsyn10x20r.psf | Bin 0 -> 10823 bytes src/boot/console.c | 100 +++++++++++++++---- src/boot/console.h | 11 +++ src/boot/loader.c | 178 ++++++++++++++++++++++------------ src/boot/loader.h | 29 ++++-- src/boot/main.c | 61 ++++++++++-- src/boot/utility.c | 11 ++- src/boot/utility.h | 4 +- src/modules/main/main.c | 41 +++++++- 10 files changed, 338 insertions(+), 104 deletions(-) create mode 100644 assets/fonts/tamsyn10x20r.psf diff --git a/Makefile b/Makefile index 5d704cc..13c723b 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ VERSION ?= $(shell git describe --dirty --always) GITSHA ?= $(shell git rev-parse --short HEAD) KERNEL_FILENAME:= popcorn.bin +KERNEL_FONT := assets/fonts/tamsyn10x20r.psf MODULES := main @@ -183,7 +184,10 @@ $(BUILD_D)/arch/%.c.o: $(ARCH_D)/%.c $(INIT_DEP) $(BUILD_D)/flash.img: $(OVMF) cp $^ $@ -$(BUILD_D)/fs.img: $(BUILD_D)/boot.efi $(BUILD_D)/kernel.bin +$(BUILD_D)/screenfont.psf: $(KERNEL_FONT) + cp $^ $@ + +$(BUILD_D)/fs.img: $(BUILD_D)/boot.efi $(BUILD_D)/kernel.bin $(BUILD_D)/screenfont.psf $(eval TEMPFILE := $(shell mktemp --suffix=.img)) dd if=/dev/zero of=$@.tmp bs=512 count=93750 $(PARTED) $@.tmp -s -a minimal mklabel gpt @@ -195,6 +199,7 @@ $(BUILD_D)/fs.img: $(BUILD_D)/boot.efi $(BUILD_D)/kernel.bin mmd -i $(TEMPFILE) ::/EFI/BOOT mcopy -i $(TEMPFILE) $(BUILD_D)/boot.efi ::/EFI/BOOT/BOOTX64.efi mcopy -i $(TEMPFILE) $(BUILD_D)/kernel.bin ::$(KERNEL_FILENAME) + mcopy -i $(TEMPFILE) $(BUILD_D)/screenfont.psf ::screenfont.psf mlabel -i $(TEMPFILE) ::Popcorn_OS dd if=$(TEMPFILE) of=$@.tmp bs=512 count=91669 seek=2048 conv=notrunc rm $(TEMPFILE) diff --git a/assets/fonts/tamsyn10x20r.psf b/assets/fonts/tamsyn10x20r.psf new file mode 100644 index 0000000000000000000000000000000000000000..e9222b77d336baf4eeeedde32764cf5352cc7b62 GIT binary patch literal 10823 zcmeHM>2nlC6z>GeS}n^Y$_L9r*es}k3h_q8WH$sz6pyHQ;sJQzeVeG59q$Vj5fSf$ z!vnlgQBkPv|AfDSZ$IDb-k0v_>D^h2Q1~I;HPhFxU%#u5>3Q_mOJ7zLiuAN`hF)_h znMThsT=v44>i6Q9*V20S+hj$#m8W%zM;19@H?d>H=u*{0@K6ILrh#_MUR6g zKEu*jrFzt0GNjH{Q>py~H9Hwdri2hG6UxLM$_=R{wCXQW3zHBi(uVcfa=RI?P`3r! zrPJ^?Rkf$UTsxIwyBE34J;P8S&gQA<^bApZ<6yb0n(><9(iBcqCz>8T>FV)Pbv)Nv zhUtZYEya>r39WXDv=f&phJo$7n5;0QhSe&{vxQ@!K;z6I+lg%oD$Xg>v*TOs78~HI zhQETEVbIpIV&k@}qv*VFJne=3M9JDOhN~Ls$}}%|^v3k2*Yz-FWNj>Om1u-IjE&3k zS}Hbeq(8w`RG;Cmojj~j@NMenL%iR{dA3dHS9XSUlGJt%q~}GNqF7YYbgL~nI%3}# z%6fqv+qN@rVVI%1RXItLw~~$Z_@+w8jzu*ygp#&Obxl{tEtdgNh1gZn3f08I%(@?x z>wXg(ll!eBzZ1)H+D|pH;QUW0#c1I0RL%gp%Q5uI>H;mv8K5~U~WRNnlx zvq#=cJ-!~WCI)Cdc$nfK{~H^=~cxB(U+R-$vAf^ zuqOca?sVuSOU9#5k5AiH#&qxhQu0sJvX-{m-=4wx>bB|2bYporIv->!j%9FC!E;3V z#OArI0y3iYiR`#Oy$bEpmSz^$VJy)}2zyeKxAYIwa9qoevxxAXmbVg;F}}o=qb6s4 zFLr+6^Ad+e=H$dBKaQFOwl-EGF0>=H6eI)HK9U+82Cvu@sLtCz_Csl!cy6?K!Y5vcJmNm``nGl0FPm66co%+JEi0 zjjfxK_-OIDZ0e(!g2btcsY{8e`=KWpOa_w0e$`}tQUjA3nAE_e1`fLhcvZH+tSw6A=8lbT+UC;zitFVw*y=rIxjaAVQpJR0mztlH%RUvC=N*;50_^>ueY;l4IlgU8 zSQcDsDevK}2R;q0Pd1piK8c-oTc;(+0_mhgr@s>2rxp^aJ(M)N+aC(G{J#I!|4htz zvm2&-$&MVtp2V{EvJ=mdc%JpbiKl;P6y3_h-|~Exb+gWX``Z6kd=J5MS-w~NQRNPi zX*I*yFY|nQXVF=n|JdZwQ--5faF(xpdRD5A3mV5 zyIB5z#D9>6skDe@x(lM0^tUgc7SjJeL@#+b(Mujq{2&kK#`SLmtnWA}T#jd>yDzb` z&b7K6|J&d@@}>0V*sqqmMw1iGDDpVI*^=9pz5pj2=HWy$c{uTyJe+7S568D2eEX4y zb7GCqS*egzlUEhTk;Jv6bG#qe)z9u6{`#lL%lMBL2fJ^`iWKUP|Kr(vz2-Pye{8Wv z^nATE!#V!a_kihjO&RX29L;f#zvei{Umosg`nP%#dEUutmhn-RCY+Z_Ie&3}&&W#J zSQ&d*jN9=A?)$S~I1TS7oxIj=f(>zwzveinmpmME$}0c|Yb`06s^Ha5ock*v|C{iG z^8=BFdN$Fs*VHEF{V|od(X*SLUGzN9T~ON!6w!?mW??o?!KpY6b1)b4 za5~PwnV63S=)qYy8|UC$oQLyq0T$vyT!f3U2$!H2eJG=Xek{fSmS8ECVGu*O6qjK+ zF2@zP5?5guSK}I7ixs#I*W(7P;11l0yKpzw;vU?K`*1%V zz=L=Q591L$ipTIcp1_kB!6=@>(|88!@GQoR6ir{X&r$mVwJ%xL+BVd-qqc(t{~EP# zDA`HRcdQ7b!rE>oRola_zf5)?bOQYx^z+a!K)(q667BootServices; - con_out = system_table->ConOut; - EFI_GRAPHICS_OUTPUT_PROTOCOL *gfx_out_proto; status = bootsvc->LocateProtocol(&guid_gfx_out, NULL, (void **)&gfx_out_proto); CHECK_EFI_STATUS_OR_RETURN(status, "LocateProtocol gfx"); const uint32_t modes = gfx_out_proto->Mode->MaxMode; - uint32_t res = gfx_out_proto->Mode->Info->HorizontalResolution * - gfx_out_proto->Mode->Info->VerticalResolution; uint32_t best = gfx_out_proto->Mode->Mode; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info = + (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *)gfx_out_proto->Mode; + + uint32_t res = info->HorizontalResolution * info->VerticalResolution; + int is_fb = info->PixelFormat != PixelBltOnly; + for (uint32_t i = 0; i < modes; ++i) { - UINTN size = 0; - EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info = NULL; + size_t size = 0; status = gfx_out_proto->QueryMode(gfx_out_proto, i, &size, &info); CHECK_EFI_STATUS_OR_RETURN(status, "QueryMode"); @@ -42,8 +41,9 @@ con_initialize(EFI_SYSTEM_TABLE *system_table, const CHAR16 *version) #endif const uint32_t new_res = info->HorizontalResolution * info->VerticalResolution; + const int new_is_fb = info->PixelFormat == PixelBltOnly; - if (new_res > res) { + if (new_is_fb > is_fb && new_res >= res) { best = i; res = new_res; } @@ -51,6 +51,21 @@ con_initialize(EFI_SYSTEM_TABLE *system_table, const CHAR16 *version) status = gfx_out_proto->SetMode(gfx_out_proto, best); CHECK_EFI_STATUS_OR_RETURN(status, "SetMode %d/%d", best, modes); + return EFI_SUCCESS; +} + +EFI_STATUS +con_initialize(EFI_SYSTEM_TABLE *system_table, const CHAR16 *version) +{ + EFI_STATUS status; + + EFI_BOOT_SERVICES *bootsvc = system_table->BootServices; + con_out = system_table->ConOut; + + // Might not find a video device at all, so ignore not found errors + status = con_pick_mode(bootsvc); + if (status != EFI_NOT_FOUND) + CHECK_EFI_STATUS_OR_RETURN(status, "con_pick_mode"); status = con_out->QueryMode(con_out, con_out->Mode->Mode, &COLS, &ROWS); CHECK_EFI_STATUS_OR_RETURN(status, "QueryMode"); @@ -70,14 +85,6 @@ con_initialize(EFI_SYSTEM_TABLE *system_table, const CHAR16 *version) return status; } -size_t -con_wstrlen(const CHAR16 *s) -{ - size_t count = 0; - while (s && *s++) count++; - return count; -} - size_t con_print_hex(uint32_t n) { @@ -178,7 +185,7 @@ con_printf(const CHAR16 *fmt, ...) case L's': { CHAR16 *s = va_arg(args, CHAR16*); - count += con_wstrlen(s); + count += wstrlen(s); con_out->OutputString(con_out, s); } break; @@ -244,3 +251,58 @@ con_status_fail(const CHAR16 *error) con_out->SetAttribute(con_out, EFI_LIGHTGRAY); con_out->OutputString(con_out, (CHAR16 *)L"\r\n"); } + +EFI_STATUS +con_get_framebuffer( + EFI_BOOT_SERVICES *bootsvc, + void **buffer, + size_t *buffer_size, + uint32_t *hres, + uint32_t *vres, + uint32_t *rmask, + uint32_t *gmask, + uint32_t *bmask) +{ + EFI_STATUS status; + + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; + status = bootsvc->LocateProtocol(&guid_gfx_out, NULL, (void **)&gop); + if (status != EFI_NOT_FOUND) { + CHECK_EFI_STATUS_OR_RETURN(status, "LocateProtocol gfx"); + + *buffer = (void *)gop->Mode->FrameBufferBase; + *buffer_size = gop->Mode->FrameBufferSize; + *hres = gop->Mode->Info->HorizontalResolution; + *vres = gop->Mode->Info->VerticalResolution; + + switch (gop->Mode->Info->PixelFormat) { + case PixelRedGreenBlueReserved8BitPerColor: + *rmask = 0x0000ff; + *gmask = 0x00ff00; + *bmask = 0xff0000; + return EFI_SUCCESS; + + case PixelBlueGreenRedReserved8BitPerColor: + *bmask = 0x0000ff; + *gmask = 0x00ff00; + *rmask = 0xff0000; + return EFI_SUCCESS; + + case PixelBitMask: + *rmask = gop->Mode->Info->PixelInformation.RedMask; + *gmask = gop->Mode->Info->PixelInformation.GreenMask; + *bmask = gop->Mode->Info->PixelInformation.BlueMask; + return EFI_SUCCESS; + + default: + // Not a framebuffer, fall through to zeroing out + // values below. + break; + } + } + + *buffer = NULL; + *buffer_size = *hres = *vres = 0; + *rmask = *gmask = *bmask = 0; + return EFI_SUCCESS; +} diff --git a/src/boot/console.h b/src/boot/console.h index fdb3f05..1e28b04 100644 --- a/src/boot/console.h +++ b/src/boot/console.h @@ -7,3 +7,14 @@ void con_status_begin(const CHAR16 *message); void con_status_ok(); void con_status_fail(const CHAR16 *error); size_t con_printf(const CHAR16 *fmt, ...); + +EFI_STATUS +con_get_framebuffer( + EFI_BOOT_SERVICES *bootsvc, + void **buffer, + size_t *buffer_size, + uint32_t *hres, + uint32_t *vres, + uint32_t *rmask, + uint32_t *gmask, + uint32_t *bmask); diff --git a/src/boot/loader.c b/src/boot/loader.c index c8eed99..579df69 100644 --- a/src/boot/loader.c +++ b/src/boot/loader.c @@ -1,97 +1,147 @@ #include "guids.h" #include "loader.h" +#include "memory.h" #include "utility.h" +#define PAGE_SIZE 0x1000 + static CHAR16 kernel_name[] = KERNEL_FILENAME; +static CHAR16 font_name[] = KERNEL_FONT; + +EFI_STATUS +loader_alloc_pages( + EFI_BOOT_SERVICES *bootsvc, + EFI_MEMORY_TYPE mem_type, + size_t *length, + void **pages, + void **next) +{ + EFI_STATUS status; + + size_t page_count = ((*length - 1) / PAGE_SIZE) + 1; + EFI_PHYSICAL_ADDRESS addr = (EFI_PHYSICAL_ADDRESS)*pages; + + status = bootsvc->AllocatePages(AllocateAddress, mem_type, page_count, &addr); + if (status == EFI_NOT_FOUND || status == EFI_OUT_OF_RESOURCES) { + // couldn't get the address we wanted, try loading the kernel anywhere + status = + bootsvc->AllocatePages(AllocateAnyPages, mem_type, page_count, &addr); + } + CHECK_EFI_STATUS_OR_RETURN(status, L"Allocating kernel pages type %x", mem_type); + + *length = page_count * PAGE_SIZE; + *pages = (void *)addr; + *next = (void*)(addr + *length); + + return EFI_SUCCESS; +} + +EFI_STATUS +loader_load_file( + EFI_BOOT_SERVICES *bootsvc, + EFI_FILE_PROTOCOL *root, + const CHAR16 *filename, + EFI_MEMORY_TYPE mem_type, + void **data, + size_t *length, + void **next) +{ + EFI_STATUS status; + + EFI_FILE_PROTOCOL *file = NULL; + status = root->Open(root, &file, (CHAR16 *)filename, EFI_FILE_MODE_READ, + EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM); + + if (status == EFI_NOT_FOUND) + return status; + + CHECK_EFI_STATUS_OR_RETURN(status, L"Opening file %s", filename); + + char info[sizeof(EFI_FILE_INFO) + 100]; + size_t info_length = sizeof(info); + + status = file->GetInfo(file, &guid_file_info, &info_length, info); + CHECK_EFI_STATUS_OR_RETURN(status, L"Getting file info"); + + *length = ((EFI_FILE_INFO *)info)->FileSize; + + status = loader_alloc_pages(bootsvc, mem_type, length, data, next); + CHECK_EFI_STATUS_OR_RETURN(status, L"Allocating pages"); + + status = file->Read(file, length, *data); + CHECK_EFI_STATUS_OR_RETURN(status, L"Reading file"); + + status = file->Close(file); + CHECK_EFI_STATUS_OR_RETURN(status, L"Closing file handle"); + + return EFI_SUCCESS; +} + EFI_STATUS loader_load_kernel( EFI_BOOT_SERVICES *bootsvc, - void **kernel_image, - uint64_t *kernel_length, - void **kernel_data, - uint64_t *data_length) + struct loader_data *data) { - if (kernel_image == 0 || kernel_length == 0) - CHECK_EFI_STATUS_OR_RETURN(EFI_INVALID_PARAMETER, "NULL kernel_image or length pointer"); - - if (kernel_data == 0 || data_length == 0) - CHECK_EFI_STATUS_OR_RETURN(EFI_INVALID_PARAMETER, "NULL kernel_data or length pointer"); + if (data == NULL) + CHECK_EFI_STATUS_OR_RETURN(EFI_INVALID_PARAMETER, L"NULL loader_data"); EFI_STATUS status; EFI_HANDLE *handles = NULL; - UINTN handleCount = 0; + size_t handleCount = 0; status = bootsvc->LocateHandleBuffer(ByProtocol, &guid_simple_filesystem, NULL, &handleCount, &handles); - CHECK_EFI_STATUS_OR_RETURN(status, "LocateHandleBuffer"); + CHECK_EFI_STATUS_OR_RETURN(status, L"LocateHandleBuffer"); for (unsigned i = 0; i < handleCount; ++i) { EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fileSystem = NULL; status = bootsvc->HandleProtocol(handles[i], &guid_simple_filesystem, (void **)&fileSystem); - CHECK_EFI_STATUS_OR_RETURN(status, "HandleProtocol"); + CHECK_EFI_STATUS_OR_RETURN(status, L"HandleProtocol"); EFI_FILE_PROTOCOL *root = NULL; status = fileSystem->OpenVolume(fileSystem, &root); - CHECK_EFI_STATUS_OR_RETURN(status, "OpenVolume"); + CHECK_EFI_STATUS_OR_RETURN(status, L"OpenVolume"); - EFI_FILE_PROTOCOL *file = NULL; - status = root->Open(root, &file, kernel_name, EFI_FILE_MODE_READ, - EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM); + void *next = NULL; - if (!EFI_ERROR(status)) { - void *buffer = NULL; - UINTN buffer_size = sizeof(EFI_FILE_INFO) + sizeof(kernel_name); + data->kernel_image = (void *)KERNEL_PHYS_ADDRESS; + status = loader_load_file( + bootsvc, + root, + kernel_name, + KERNEL_MEMTYPE, + &data->kernel_image, + &data->kernel_image_length, + &next); + if (status == EFI_NOT_FOUND) + continue; - status = bootsvc->AllocatePool(EfiLoaderCode, buffer_size, &buffer); - CHECK_EFI_STATUS_OR_RETURN(status, "Allocating kernel file info memory"); + CHECK_EFI_STATUS_OR_RETURN(status, L"loader_load_file: %s", kernel_name); - status = file->GetInfo(file, &guid_file_info, &buffer_size, buffer); - CHECK_EFI_STATUS_OR_RETURN(status, "Getting kernel file info"); + data->screen_font = next; + status = loader_load_file( + bootsvc, + root, + font_name, + KERNEL_FONT_MEMTYPE, + &data->screen_font, + &data->screen_font_length, + &next); - buffer_size = ((EFI_FILE_INFO *)buffer)->FileSize; + CHECK_EFI_STATUS_OR_RETURN(status, L"loader_load_file: %s", font_name); - status = bootsvc->FreePool(buffer); - CHECK_EFI_STATUS_OR_RETURN(status, "Freeing kernel file info memory"); + data->kernel_data = next; + data->kernel_data_length += PAGE_SIZE; // extra page for map growth + status = loader_alloc_pages( + bootsvc, + KERNEL_DATA_MEMTYPE, + &data->kernel_data_length, + &data->kernel_data, + &next); + CHECK_EFI_STATUS_OR_RETURN(status, L"loader_alloc_pages: kernel data"); - UINTN page_count = ((buffer_size - 1) / 0x1000) + 1; - EFI_PHYSICAL_ADDRESS addr = KERNEL_PHYS_ADDRESS; - EFI_MEMORY_TYPE mem_type = KERNEL_MEMTYPE; // Special value to tell the kernel it's here - status = bootsvc->AllocatePages(AllocateAddress, mem_type, page_count, &addr); - if (status == EFI_NOT_FOUND) { - // couldn't get the address we wanted, try loading the kernel anywhere - status = - bootsvc->AllocatePages(AllocateAnyPages, mem_type, page_count, &addr); - } - CHECK_EFI_STATUS_OR_RETURN(status, "Allocating kernel pages"); - - buffer = (void *)addr; - status = file->Read(file, &buffer_size, buffer); - CHECK_EFI_STATUS_OR_RETURN(status, "Reading kernel file"); - - status = file->Close(file); - CHECK_EFI_STATUS_OR_RETURN(status, "Closing kernel file handle"); - - *kernel_length = buffer_size; - *kernel_image = buffer; - - addr += page_count * 0x1000; // Get the next page after the kernel pages - mem_type = KERNEL_DATA_MEMTYPE; // Special value for kernel data - page_count = ((*data_length - 1) / 0x1000) + 1; - status = bootsvc->AllocatePages(AllocateAddress, mem_type, page_count, &addr); - if (status == EFI_NOT_FOUND) { - // couldn't get the address we wanted, try loading anywhere - status = - bootsvc->AllocatePages(AllocateAnyPages, mem_type, page_count, &addr); - } - CHECK_EFI_STATUS_OR_RETURN(status, "Allocating kernel data pages"); - - *data_length = page_count * 0x1000; - *kernel_data = (void *)addr; - bootsvc->SetMem(*kernel_data, *data_length, 0); - - return EFI_SUCCESS; - } + return EFI_SUCCESS; } return EFI_NOT_FOUND; diff --git a/src/boot/loader.h b/src/boot/loader.h index 79fa161..572c964 100644 --- a/src/boot/loader.h +++ b/src/boot/loader.h @@ -1,5 +1,6 @@ #pragma once #include +#include #ifndef KERNEL_PHYS_ADDRESS #define KERNEL_PHYS_ADDRESS 0x100000 @@ -13,8 +14,12 @@ #define KERNEL_MEMTYPE 0x80000000 #endif +#ifndef KERNEL_FONT_MEMTYPE +#define KERNEL_FONT_MEMTYPE 0x80000001 +#endif + #ifndef KERNEL_DATA_MEMTYPE -#define KERNEL_DATA_MEMTYPE 0x80000001 +#define KERNEL_DATA_MEMTYPE 0x80000002 #endif #ifndef KERNEL_DATA_PAGES @@ -25,9 +30,19 @@ #define KERNEL_FILENAME L"kernel.bin" #endif -EFI_STATUS loader_load_kernel( - EFI_BOOT_SERVICES *bootsvc, - void **kernel_image, - uint64_t *kernel_length, - void **kernel_data, - uint64_t *data_length); +#ifndef KERNEL_FONT +#define KERNEL_FONT L"screenfont.psf" +#endif + +struct loader_data { + void *kernel_image; + size_t kernel_image_length; + + void *kernel_data; + size_t kernel_data_length; + + void *screen_font; + size_t screen_font_length; +}; + +EFI_STATUS loader_load_kernel(EFI_BOOT_SERVICES *bootsvc, struct loader_data *data); diff --git a/src/boot/main.c b/src/boot/main.c index 587190c..0760566 100644 --- a/src/boot/main.c +++ b/src/boot/main.c @@ -39,13 +39,28 @@ struct popcorn_data { uint16_t version; uint16_t length; - uint16_t data_pages; - uint16_t _reserverd; + uint32_t _reserved0; uint32_t flags; + void *font; + size_t font_length; + + void *data; + size_t data_length; + EFI_MEMORY_DESCRIPTOR *memory_map; EFI_RUNTIME_SERVICES *runtime; + void *acpi_table; + + void *frame_buffer; + size_t frame_buffer_size; + uint32_t hres; + uint32_t vres; + uint32_t rmask; + uint32_t gmask; + uint32_t bmask; + uint32_t _reserved1; } __attribute__((aligned(_Alignof(EFI_MEMORY_DESCRIPTOR)))); #pragma pack(pop) @@ -95,13 +110,16 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) uint64_t kernel_length = 0; con_printf(L"Loading kernel into memory...\r\n"); - status = loader_load_kernel(bootsvc, &kernel_image, &kernel_length, &kernel_data, &data_length); + struct loader_data load; + load.kernel_data_length = data_length; + status = loader_load_kernel(bootsvc, &load); CHECK_EFI_STATUS_OR_FAIL(status); - con_printf(L" %u bytes at 0x%x\r\n", kernel_length, kernel_image); - con_printf(L" %u data bytes at 0x%x\r\n", data_length, kernel_data); + con_printf(L" %u image bytes at 0x%x\r\n", load.kernel_image_length, load.kernel_image); + con_printf(L" %u font bytes at 0x%x\r\n", load.screen_font_length, load.screen_font); + con_printf(L" %u data bytes at 0x%x\r\n", load.kernel_data_length, load.kernel_data); - struct kernel_header *version = (struct kernel_header *)kernel_image; + struct kernel_header *version = (struct kernel_header *)load.kernel_image; if (version->magic != KERNEL_HEADER_MAGIC) { con_printf(L" bad magic %x\r\n", version->magic); CHECK_EFI_STATUS_OR_FAIL(EFI_CRC_ERROR); @@ -115,22 +133,45 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) // Set up the kernel data pages to pass to the kernel // - struct popcorn_data *data_header = (struct popcorn_data *)kernel_data; + struct popcorn_data *data_header = (struct popcorn_data *)load.kernel_data; + data_header->magic = DATA_HEADER_MAGIC; data_header->version = DATA_HEADER_VERSION; data_header->length = sizeof(struct popcorn_data); - data_header->data_pages = data_length / 0x1000; - data_header->_reserverd = 0; + data_header->flags = 0; + + data_header->font = load.screen_font; + data_header->font_length = load.screen_font_length; + + data_header->data = load.screen_font; + data_header->data_length = load.screen_font_length; + data_header->memory_map = (EFI_MEMORY_DESCRIPTOR *)(data_header + 1); data_header->runtime = system_table->RuntimeServices; data_header->acpi_table = acpi_table; + data_header->_reserved0 = 0; + data_header->_reserved1 = 0; + + // Figure out the framebuffer (if any) and add that to the data header + // + status = con_get_framebuffer( + bootsvc, + &data_header->frame_buffer, + &data_header->frame_buffer_size, + &data_header->hres, + &data_header->vres, + &data_header->rmask, + &data_header->gmask, + &data_header->bmask); + CHECK_EFI_STATUS_OR_FAIL(status); + // Save the memory map and tell the firmware we're taking control. // struct memory_map map; map.entries = data_header->memory_map; - map.length = (data_length - header_size); + map.length = (load.kernel_data_length - header_size); status = memory_get_map(bootsvc, &map); CHECK_EFI_STATUS_OR_FAIL(status); diff --git a/src/boot/utility.c b/src/boot/utility.c index cadd973..0757ef8 100644 --- a/src/boot/utility.c +++ b/src/boot/utility.c @@ -1,4 +1,4 @@ -#include +#include "utility.h" struct error_code_desc { EFI_STATUS code; @@ -60,3 +60,12 @@ util_error_message(EFI_STATUS status) else return L"Unknown Warning"; } + +size_t +wstrlen(const CHAR16 *s) +{ + size_t count = 0; + while (s && *s++) count++; + return count; +} + diff --git a/src/boot/utility.h b/src/boot/utility.h index 5df0a09..99395d1 100644 --- a/src/boot/utility.h +++ b/src/boot/utility.h @@ -1,14 +1,16 @@ #include "console.h" #include #include +#include #define UNUSED __attribute__((unused)) +size_t wstrlen(const CHAR16 *s); const CHAR16 *util_error_message(EFI_STATUS status); #define CHECK_EFI_STATUS_OR_RETURN(s, msg, ...) \ if (EFI_ERROR((s))) { \ - con_printf(L"EFI_ERROR: " msg L": %s\n", ##__VA_ARGS__, util_error_message(s)); \ + con_printf(L"ERROR: " msg L": %s\r\n", ##__VA_ARGS__, util_error_message(s)); \ return (s); \ } diff --git a/src/modules/main/main.c b/src/modules/main/main.c index 33c7182..cfdb333 100644 --- a/src/modules/main/main.c +++ b/src/modules/main/main.c @@ -1,7 +1,46 @@ +#include +#include + void do_the_set_registers(); +#pragma pack(push, 1) +struct popcorn_data { + uint32_t magic; + uint16_t version; + uint16_t length; + + uint32_t _reserverd0; + uint32_t flags; + + void *font; + size_t font_length; + + void *data; + size_t data_length; + + void *memory_map; + void *runtime; + + void *acpi_table; + + void *frame_buffer; + size_t frame_buffer_size; + uint32_t hres; + uint32_t vres; + uint32_t rmask; + uint32_t gmask; + uint32_t bmask; + uint32_t _reserved1; +} +__attribute__((aligned(8))); +#pragma pack(pop) + void -kernel_main(void *header) +kernel_main(struct popcorn_data *header) { + uint32_t *p = header->frame_buffer; + uint32_t *end = p + (header->frame_buffer_size / sizeof(uint32_t)); + while (p < end) *p++ = header->rmask; + do_the_set_registers(header); }