diff --git a/examples/vga2.c b/examples/vga2.c index c5e1de2b6..ab846106d 100644 --- a/examples/vga2.c +++ b/examples/vga2.c @@ -27,8 +27,13 @@ STATIC_YOINK("_idt"); STATIC_YOINK("EfiMain"); int main(int argc, char *argv[]) { + int i; volatile int x = 1; volatile int y = 2; + printf("argc = %d\n", argc); + for (i = 0; i < argc; ++i) { + printf("argv[%d] = \"%s\"\n", i, argv[i]); + } printf("\e[92;44mHello World!\e[0m %d\n", 1 / (x + y - 3)); for (;;); } diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index 8335fb468..7d16482af 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -177,6 +177,7 @@ privileged static void klog(const char *b, size_t n) { __imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), b, n, &wrote, 0); __imp_SetLastError(e); } else if (IsMetal()) { + if (_weaken(_klog_vga)) _weaken(_klog_vga)(b, n); for (i = 0; i < n; ++i) { for (;;) { dx = 0x3F8 + UART_LSR; @@ -189,7 +190,6 @@ privileged static void klog(const char *b, size_t n) { : /* no inputs */ : "a"(b[i]), "dN"(dx)); } - if (_weaken(_klog_vga)) _weaken(_klog_vga)(b, n); } else { asm volatile("syscall" : "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx) diff --git a/libc/intrin/mman.greg.c b/libc/intrin/mman.greg.c index 286a1c2d9..d403b7022 100644 --- a/libc/intrin/mman.greg.c +++ b/libc/intrin/mman.greg.c @@ -236,14 +236,23 @@ noasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b, */ noasan textreal void __reclaim_boot_pages(struct mman *mm, uint64_t skip_start, uint64_t skip_end) { - uint64_t p = mm->frp, q = IMAGE_BASE_REAL, e; - e = mm->e820[0].addr + mm->e820[0].size; - while (q != e) { - struct ReclaimedPage *rp = (struct ReclaimedPage *)(BANE + q); - rp->next = p; - p = q; - q += 4096; - if (q == skip_start) q = skip_end; + uint64_t p = mm->frp, q = IMAGE_BASE_REAL, i, n = mm->e820n, b, e; + for (i = 0; i < n; ++i) { + b = mm->e820[i].addr; + if (b >= IMAGE_BASE_PHYSICAL) break; + e = MIN(IMAGE_BASE_PHYSICAL, b + mm->e820[i].size); + q = MAX(IMAGE_BASE_REAL, b); + while (q < e) { + struct ReclaimedPage *rp; + if (q == skip_start) { + q = skip_end; + if (q >= e) break; + } + rp = (struct ReclaimedPage *)(BANE + q); + rp->next = p; + p = q; + q += 4096; + } } mm->frp = p; } diff --git a/libc/nt/efi.h b/libc/nt/efi.h index 6ac501950..3178a3e86 100644 --- a/libc/nt/efi.h +++ b/libc/nt/efi.h @@ -97,6 +97,12 @@ 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B \ } \ } +#define GRAPHICS_OUTPUT_PROTOCOL \ + { \ + 0x9042A9DE, 0x23DC, 0x4A38, { \ + 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A \ + } \ + } #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -113,6 +119,7 @@ COSMOPOLITAN_C_START_ typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL; typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL; +typedef struct _EFI_GRAPHICS_OUTPUT_PROTOCOL EFI_GRAPHICS_OUTPUT_PROTOCOL; typedef enum { EfiReservedMemoryType, @@ -214,6 +221,54 @@ typedef struct { bool CursorVisible; } EFI_SIMPLE_TEXT_OUTPUT_MODE; +typedef enum { + PixelRedGreenBlueReserved8BitPerColor, + PixelBlueGreenRedReserved8BitPerColor, + PixelBitMask, + PixelBltOnly, + PixelFormatMax +} EFI_GRAPHICS_PIXEL_FORMAT; + +typedef struct { + uint32_t RedMask; + uint32_t GreenMask; + uint32_t BlueMask; + uint32_t ReservedMask; +} EFI_PIXEL_BITMASK; + +typedef struct { + uint32_t Version; + uint32_t HorizontalResolution; + uint32_t VerticalResolution; + EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; + EFI_PIXEL_BITMASK PixelInformation; + uint32_t PixelsPerScanLine; +} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION; + +typedef struct { + uint8_t Blue; + uint8_t Green; + uint8_t Red; + uint8_t Reserved; +} EFI_GRAPHICS_OUTPUT_BLT_PIXEL; + +typedef enum { + EfiBltVideoFill, + EfiBltVideoToBltBuffer, + EfiBltBufferToVideo, + EfiBltVideoToVideo, + EfiGraphicsOutputBltOperationMax +} EFI_GRAPHICS_OUTPUT_BLT_OPERATION; + +typedef struct { + uint32_t MaxMode; + uint32_t Mode; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + uint32_t SizeOfInfo; + uint64_t FrameBufferBase; + uint32_t FrameBufferSize; +} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE; + typedef struct { uint64_t Signature; uint32_t Revision; @@ -300,6 +355,9 @@ typedef EFI_STATUS(EFIAPI *EFI_SET_WATCHDOG_TIMER)(uintptr_t Timeout, uint64_t WatchdogCode, uintptr_t DataSize, char16_t *opt_WatchdogData); +typedef EFI_STATUS(EFIAPI *EFI_LOCATE_PROTOCOL)(EFI_GUID *Protocol, + void *Registration, + void *Interface); typedef EFI_STATUS(EFIAPI *EFI_SET_TIME)(EFI_TIME *Time); typedef EFI_STATUS(EFIAPI *EFI_GET_TIME)( @@ -343,6 +401,19 @@ typedef EFI_STATUS(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION)( typedef EFI_STATUS(EFIAPI *EFI_TEXT_ENABLE_CURSOR)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, bool Visible); +typedef EFI_STATUS(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE)( + EFI_GRAPHICS_OUTPUT_PROTOCOL *This, uint32_t ModeNumber, + uint32_t *SizeOfInfo, EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info); +typedef EFI_STATUS(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE)( + EFI_GRAPHICS_OUTPUT_PROTOCOL *This, uint32_t ModeNumber); +typedef EFI_STATUS(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT)( + EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, + EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + uint32_t SourceX, uint32_t SourceY, + uint32_t DestinationX, uint32_t DestinationY, + uint32_t Width, uint32_t Height, uint32_t Delta); + typedef EFI_STATUS(EFIAPI *EFI_HANDLE_PROTOCOL)(EFI_HANDLE Handle, EFI_GUID *Protocol, void *out_Interface); @@ -414,7 +485,7 @@ typedef struct { void *OpenProtocolInformation; void *ProtocolsPerHandle; void *LocateHandleBuffer; - void *LocateProtocol; + EFI_LOCATE_PROTOCOL LocateProtocol; void *InstallMultipleProtocolInterfaces; void *UninstallMultipleProtocolInterfaces; void *CalculateCrc32; @@ -458,6 +529,13 @@ struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL { EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; }; +struct _EFI_GRAPHICS_OUTPUT_PROTOCOL { + EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE QueryMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE SetMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt; + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode; +}; + typedef struct { uint32_t Revision; EFI_HANDLE ParentHandle; diff --git a/libc/runtime/efimain.greg.c b/libc/runtime/efimain.greg.c index e3b12798e..dcbbe0dab 100644 --- a/libc/runtime/efimain.greg.c +++ b/libc/runtime/efimain.greg.c @@ -16,9 +16,12 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/relocations.h" #include "ape/sections.internal.h" #include "libc/dce.h" #include "libc/intrin/bits.h" +#include "libc/intrin/newbie.h" +#include "libc/intrin/weaken.h" #include "libc/macros.internal.h" #include "libc/nt/efi.h" #include "libc/nt/thunk/msabi.h" @@ -37,6 +40,80 @@ struct EfiArgs { }; static const EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL; +static const EFI_GUID kEfiGraphicsOutputProtocol = GRAPHICS_OUTPUT_PROTOCOL; + +extern const char vga_console[]; +extern void _EfiPostboot(struct mman *, uint64_t *, uintptr_t, char **); + +static void EfiInitVga(struct mman *mm, EFI_SYSTEM_TABLE *SystemTable) { + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphInfo; + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *GraphMode; + EFI_PIXEL_BITMASK *PixelInfo; + unsigned vid_typ = PC_VIDEO_TEXT; + size_t bytes_per_pix = 0; + + SystemTable->BootServices->LocateProtocol(&kEfiGraphicsOutputProtocol, NULL, + &GraphInfo); + GraphMode = GraphInfo->Mode; + switch (GraphMode->Info->PixelFormat) { + case PixelRedGreenBlueReserved8BitPerColor: + vid_typ = PC_VIDEO_RGBX8888; + bytes_per_pix = 4; + break; + case PixelBlueGreenRedReserved8BitPerColor: + vid_typ = PC_VIDEO_BGRX8888; + bytes_per_pix = 4; + break; + case PixelBitMask: + PixelInfo = &GraphMode->Info->PixelInformation; + switch (le32toh(PixelInfo->RedMask)) { + case 0x00FF0000U: + if (le32toh(PixelInfo->ReservedMask) >= 0x01000000U && + le32toh(PixelInfo->GreenMask) == 0x0000FF00U && + le32toh(PixelInfo->BlueMask) == 0x000000FFU) { + vid_typ = PC_VIDEO_BGRX8888; + bytes_per_pix = 4; + } + break; + case 0x000000FFU: + if (le32toh(PixelInfo->ReservedMask) >= 0x01000000U && + le32toh(PixelInfo->GreenMask) == 0x0000FF00U && + le32toh(PixelInfo->BlueMask) == 0x00FF0000U) { + vid_typ = PC_VIDEO_RGBX8888; + bytes_per_pix = 4; + } + break; + case 0x0000F800U: + if (le32toh(PixelInfo->ReservedMask) <= 0x0000FFFFU && + le32toh(PixelInfo->GreenMask) == 0x000007E0U && + le32toh(PixelInfo->BlueMask) == 0x0000001FU) { + vid_typ = PC_VIDEO_BGR565; + bytes_per_pix = 2; + } + break; + case 0x00007C00U: + if (le32toh(PixelInfo->ReservedMask) <= 0x0000FFFFU && + le32toh(PixelInfo->GreenMask) == 0x000003E0U && + le32toh(PixelInfo->BlueMask) == 0x0000001FU) { + vid_typ = PC_VIDEO_BGR555; + bytes_per_pix = 2; + } + break; + } + default: + notpossible; + } + if (!bytes_per_pix) notpossible; + mm->pc_video_type = vid_typ; + mm->pc_video_stride = GraphMode->Info->PixelsPerScanLine * bytes_per_pix; + mm->pc_video_width = GraphMode->Info->HorizontalResolution; + mm->pc_video_height = GraphMode->Info->VerticalResolution; + mm->pc_video_framebuffer = GraphMode->FrameBufferBase; + mm->pc_video_framebuffer_size = GraphMode->FrameBufferSize; + mm->pc_video_curs_info.y = mm->pc_video_curs_info.x = 0; + SystemTable->BootServices->SetMem((void *)GraphMode->FrameBufferBase, + GraphMode->FrameBufferSize, 0); +} /** * EFI Application Entrypoint. @@ -62,19 +139,8 @@ static const EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL; * * @see libc/dce.h */ -__msabi noasan __attribute__((__naked__)) -EFI_STATUS EfiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { - asm volatile("mov\t$0f,%esp\n\t" - "and\t$-16,%esp\n\t" - "jmp\t_DoEfiMain\n\t" - ".bss\n\t" - ".space\t8192\n" - "0:\n\t" - ".previous"); -} - -__msabi noasan EFI_STATUS _DoEfiMain(EFI_HANDLE ImageHandle, - EFI_SYSTEM_TABLE *SystemTable) { +__msabi noasan EFI_STATUS EfiMain(EFI_HANDLE ImageHandle, + EFI_SYSTEM_TABLE *SystemTable) { int type, x87cw = 0x037f; struct mman *mm; uint32_t DescVersion; @@ -82,18 +148,37 @@ __msabi noasan EFI_STATUS _DoEfiMain(EFI_HANDLE ImageHandle, struct EfiArgs *ArgBlock; EFI_LOADED_IMAGE *ImgInfo; EFI_MEMORY_DESCRIPTOR *Map, *Desc; - uint64_t NewBase = 1024 * 1024; + uint64_t Address; uintptr_t Args, MapKey, DescSize; uint64_t p, pe, cr4, *m, *pd, *sp, *pml4t, *pdt1, *pdt2, *pdpt1, *pdpt2; /* - * Allocates and clears PC-compatible memory and copies image. + * Allocates and clears PC-compatible memory and copies image. Marks the + * pages as EfiRuntimeServicesData, so that we can simply free up all + * EfiLoader... and EfiBootServices... pages later. The first page at + * address 0 is normally already allocated as EfiBootServicesData, so + * handle it separately. */ + Address = 0; SystemTable->BootServices->AllocatePages( - AllocateAddress, EfiConventionalMemory, - MAX(2 * 1024 * 1024, 1024 * 1024 + (_end - _base)) / 4096, &NewBase); - SystemTable->BootServices->SetMem(0, 0x80000, 0); - SystemTable->BootServices->CopyMem((void *)(1024 * 1024), _base, + AllocateAddress, EfiRuntimeServicesData, 4096 / 4096, &Address); + Address = 4096; + SystemTable->BootServices->AllocatePages( + AllocateAddress, EfiRuntimeServicesData, (IMAGE_BASE_REAL - 4096) / 4096, + &Address); + Address = 0x79000; + SystemTable->BootServices->AllocatePages( + AllocateAddress, EfiRuntimeServicesData, + (0x7e000 - 0x79000 + sizeof(struct EfiArgs) + 4095) / 4096, &Address); + Address = IMAGE_BASE_PHYSICAL; + SystemTable->BootServices->AllocatePages( + AllocateAddress, EfiRuntimeServicesData, + ((_end - _base) + 4095) / 4096, &Address); + mm = (struct mman *)0x0500; + SystemTable->BootServices->SetMem(mm, sizeof(*mm), 0); + SystemTable->BootServices->SetMem((void *)0x79000, + 0x7e000 - 0x79000 + sizeof(struct EfiArgs), 0); + SystemTable->BootServices->CopyMem((void *)IMAGE_BASE_PHYSICAL, _base, _end - _base); /* @@ -106,6 +191,13 @@ __msabi noasan EFI_STATUS _DoEfiMain(EFI_HANDLE ImageHandle, sizeof(ArgBlock->ArgBlock), ArgBlock->Args, ARRAYLEN(ArgBlock->Args)); + /* + * Gets information about our current video mode. Clears the screen. + * TODO: if needed, switch to a video mode that has a linear frame buffer + * type we support. + */ + if (_weaken(vga_console)) EfiInitVga(mm, SystemTable); + /* * Asks UEFI which parts of our RAM we're allowed to use. */ @@ -117,13 +209,20 @@ __msabi noasan EFI_STATUS _DoEfiMain(EFI_HANDLE ImageHandle, MapSize *= 2; SystemTable->BootServices->GetMemoryMap(&MapSize, Map, &MapKey, &DescSize, &DescVersion); - mm = (struct mman *)0x0500; for (j = i = 0, Desc = Map; i < MapSize / DescSize; ++i) { - if (Desc->Type == EfiConventionalMemory) { - mm->e820[j].addr = Desc->PhysicalStart; - mm->e820[j].size = Desc->NumberOfPages * 4096; - mm->e820[j].type = kMemoryUsable; - ++j; + switch (Desc->Type) { + case EfiLoaderCode: + case EfiLoaderData: + case EfiBootServicesCode: + case EfiBootServicesData: + if (Desc->PhysicalStart != 0) + break; + /* fallthrough */ + case EfiConventionalMemory: + mm->e820[j].addr = Desc->PhysicalStart; + mm->e820[j].size = Desc->NumberOfPages * 4096; + mm->e820[j].type = kMemoryUsable; + ++j; } Desc = (EFI_MEMORY_DESCRIPTOR *)((char *)Desc + DescSize); } @@ -154,77 +253,8 @@ __msabi noasan EFI_STATUS _DoEfiMain(EFI_HANDLE ImageHandle, SystemTable->BootServices->ExitBootServices(ImageHandle, MapKey); /* - * Switches to copied image. + * Switches to copied image and launches program. */ - asm volatile("cli\n\t" - "add\t%1,%%rsp\n\t" - "lea\t0f(%1),%0\n\t" - "jmp\t*%0\n" - "0:\n\t" - "mov\t%2,%%cr3\n\t" - "add\t%3,%%rsp\n\t" - "lea\t1f(%1),%0\n\t" - "add\t%3,%0\n\t" - "jmp\t*%0\n" - "1:" - : "=&r"(p) - : "r"(1024 * 1024 - (uint64_t)_base), "r"(pml4t), "r"(BANE)); - - /* - * Sets up virtual memory mapping. - */ - __map_phdrs(mm, pml4t, 1024 * 1024, 1024 * 1024 + (_end - _base)); - __reclaim_boot_pages(mm, 0x79000, 0x7f000); - - /* - * Launches program. - */ - asm volatile("fldcw\t%3\n\t" - ".weak\t_gdtr\n\t" - "lgdt\t_gdtr\n\t" - "mov\t%w6,%%ds\n\t" - "mov\t%w6,%%ss\n\t" - "mov\t%w6,%%es\n\t" - "mov\t%w6,%%fs\n\t" - "mov\t%w6,%%gs\n\t" - ".weak\tape_stack_vaddr\n\t" - ".weak\tape_stack_memsz\n\t" - "movabs\t$ape_stack_vaddr,%%rsp\n\t" - "add\t$ape_stack_memsz,%%rsp\n\t" - "push\t$0\n\t" /* auxv[1][1] */ - "push\t$0\n\t" /* auxv[1][0] */ - "push\t(%1)\n\t" /* auxv[0][1] */ - "push\t$31\n\t" /* auxv[0][0] AT_EXECFN */ - "push\t$0\n\t" /* envp[0] */ - "sub\t%2,%%rsp\n\t" - "mov\t%%rsp,%%rdi\n\t" - "rep movsb\n\t" /* argv */ - "push\t%0\n\t" /* argc */ - "xor\t%%edi,%%edi\n\t" - "xor\t%%eax,%%eax\n\t" - "xor\t%%ebx,%%ebx\n\t" - "mov\t%4,%%ecx\n\t" - "xor\t%%edx,%%edx\n\t" - "xor\t%%edi,%%edi\n\t" - "xor\t%%esi,%%esi\n\t" - "xor\t%%ebp,%%ebp\n\t" - "xor\t%%r8d,%%r8d\n\t" - "xor\t%%r9d,%%r9d\n\t" - "xor\t%%r10d,%%r10d\n\t" - "xor\t%%r11d,%%r11d\n\t" - "xor\t%%r12d,%%r12d\n\t" - "xor\t%%r13d,%%r13d\n\t" - "xor\t%%r14d,%%r14d\n\t" - "xor\t%%r15d,%%r15d\n\t" - ".weak\t_start\n\t" - "push\t%5\n\t" - "push\t$_start\n\t" - "lretq" - : /* no outputs */ - : "a"(Args), "S"(ArgBlock->Args), "c"((Args + 1) * 8), - "m"(x87cw), "i"(_HOSTMETAL), "i"(GDT_LONG_CODE), - "r"(GDT_LONG_DATA) - : "memory"); - + _EfiPostboot(mm, pml4t, Args, ArgBlock->Args); unreachable; } diff --git a/libc/runtime/efipostboot.S b/libc/runtime/efipostboot.S new file mode 100644 index 000000000..1ef27085d --- /dev/null +++ b/libc/runtime/efipostboot.S @@ -0,0 +1,126 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/relocations.h" +#include "libc/dce.h" +#include "libc/macros.internal.h" +#include "libc/runtime/pc.internal.h" +.real + +// Start the Cosmopolitan runtime after exiting UEFI Boot Services. +// +// @param rdi is mm +// @param rsi is new pml4t +// @param rdx is argc +// @param rcx is argv +// @see libc/runtime/efimain.greg.c +_EfiPostboot: + cli +// Define handy mnemonics for parameters & constants stored in +// call-saved registers. +#define rMm %r12 +#define rArgc %r13 +#define rArgv %r14 +#define rBane %r15 + movabs $BANE,rBane + mov %rdi,rMm + mov %rdx,rArgc + lea (rBane,%rcx),rArgv + mov $PHYSICAL(.Ltmpstk),%rax # switch to temporary stack + and $-16,%al # in physical space + xchg %rax,%rsp + mov $PHYSICAL(0f),%eax # resume execution in copied + jmp *%rax # image +0: mov $EFER,%ecx # enable syscall/sysret & nx + rdmsr + or $EFER_SCE|EFER_NXE,%eax + wrmsr + mov %rsi,%cr3 # load new page table + add rBane,%rsp # we can now switch stack to + add rBane,rMm # negative address space + mov $1024*1024,%edx # set up virtual memory + mov $1024*1024+_end,%ecx # mapping + sub $_base,%ecx + call __map_phdrs + mov $1f,%eax # switch rip to virtual + jmp *%rax # address space +1: push $0x037f + fldcw (%rsp) + .weak _gdtr + lgdt _gdtr # switch to our own GDT + mov $GDT_LONG_DATA,%ax + mov %ax,%ds + mov %ax,%ss + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + .weak ape_stack_vaddr + .weak ape_stack_memsz + movabs $ape_stack_vaddr,%rsp # switch to final stack in + add $ape_stack_memsz,%rsp # virtual address space + movl $0,0x7b000 # unmap null 2mb + mov rMm,%rdi + xor %esi,%esi # free up now-unused pages + xor %edx,%edx + call __reclaim_boot_pages + push .Lenv0(%rip) # envp[0][0] + mov %rsp,%rbp + push $0 # auxv[1][1] + push $0 # auxv[1][0] + mov (rArgv),%rax + add rBane,%rax + push %rax # auxv[0][1] + push $31 # auxv[0][0] AT_EXECFN + push $0 # envp[1] + push %rbp # envp[0] + push $0 # argv[argc] NULL + lea -8(rArgv,rArgc,8),%rsi # push rest of argv, & + mov rArgc,%rcx # adjust pointers to point to + std # negative space +2: lodsq + add rBane,%rax + push %rax + loop 2b + cld + push rArgc # argc + pushpop _HOSTMETAL,%rcx # sets __hostos in crt.S + xor %ebp,%ebp + xor %eax,%eax + xor %ebx,%ebx + xor %edx,%edx + xor %edi,%edi + xor %esi,%esi + xor %r8d,%r8d + xor %r9d,%r9d + xor %r10d,%r10d + xor %r11d,%r11d + xor %r12d,%r12d + xor %r13d,%r13d + xor %r14d,%r14d + xor %r15d,%r15d + push $GDT_LONG_CODE + .weak _start + push $_start + lretq + .endfn _EfiPostboot,globl,hidden + .rodata +.Lenv0: .asciz "METAL=1" + .bss + .space 0x1000 +.Ltmpstk: + .previous