mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-08 19:00:27 +00:00
[metal] Get examples/vga2.c VGA output working for UEFI boot
This commit is contained in:
parent
9fe2f55113
commit
dfd7f9aa1b
6 changed files with 354 additions and 106 deletions
|
@ -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 (;;);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
126
libc/runtime/efipostboot.S
Normal file
126
libc/runtime/efipostboot.S
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue