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");
|
STATIC_YOINK("EfiMain");
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
int i;
|
||||||
volatile int x = 1;
|
volatile int x = 1;
|
||||||
volatile int y = 2;
|
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));
|
printf("\e[92;44mHello World!\e[0m %d\n", 1 / (x + y - 3));
|
||||||
for (;;);
|
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_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), b, n, &wrote, 0);
|
||||||
__imp_SetLastError(e);
|
__imp_SetLastError(e);
|
||||||
} else if (IsMetal()) {
|
} else if (IsMetal()) {
|
||||||
|
if (_weaken(_klog_vga)) _weaken(_klog_vga)(b, n);
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
dx = 0x3F8 + UART_LSR;
|
dx = 0x3F8 + UART_LSR;
|
||||||
|
@ -189,7 +190,6 @@ privileged static void klog(const char *b, size_t n) {
|
||||||
: /* no inputs */
|
: /* no inputs */
|
||||||
: "a"(b[i]), "dN"(dx));
|
: "a"(b[i]), "dN"(dx));
|
||||||
}
|
}
|
||||||
if (_weaken(_klog_vga)) _weaken(_klog_vga)(b, n);
|
|
||||||
} else {
|
} else {
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
|
: "=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,
|
noasan textreal void __reclaim_boot_pages(struct mman *mm, uint64_t skip_start,
|
||||||
uint64_t skip_end) {
|
uint64_t skip_end) {
|
||||||
uint64_t p = mm->frp, q = IMAGE_BASE_REAL, e;
|
uint64_t p = mm->frp, q = IMAGE_BASE_REAL, i, n = mm->e820n, b, e;
|
||||||
e = mm->e820[0].addr + mm->e820[0].size;
|
for (i = 0; i < n; ++i) {
|
||||||
while (q != e) {
|
b = mm->e820[i].addr;
|
||||||
struct ReclaimedPage *rp = (struct ReclaimedPage *)(BANE + q);
|
if (b >= IMAGE_BASE_PHYSICAL) break;
|
||||||
rp->next = p;
|
e = MIN(IMAGE_BASE_PHYSICAL, b + mm->e820[i].size);
|
||||||
p = q;
|
q = MAX(IMAGE_BASE_REAL, b);
|
||||||
q += 4096;
|
while (q < e) {
|
||||||
if (q == skip_start) q = skip_end;
|
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;
|
mm->frp = p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,12 @@
|
||||||
0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B \
|
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)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
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_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
|
||||||
typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_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 {
|
typedef enum {
|
||||||
EfiReservedMemoryType,
|
EfiReservedMemoryType,
|
||||||
|
@ -214,6 +221,54 @@ typedef struct {
|
||||||
bool CursorVisible;
|
bool CursorVisible;
|
||||||
} EFI_SIMPLE_TEXT_OUTPUT_MODE;
|
} 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 {
|
typedef struct {
|
||||||
uint64_t Signature;
|
uint64_t Signature;
|
||||||
uint32_t Revision;
|
uint32_t Revision;
|
||||||
|
@ -300,6 +355,9 @@ typedef EFI_STATUS(EFIAPI *EFI_SET_WATCHDOG_TIMER)(uintptr_t Timeout,
|
||||||
uint64_t WatchdogCode,
|
uint64_t WatchdogCode,
|
||||||
uintptr_t DataSize,
|
uintptr_t DataSize,
|
||||||
char16_t *opt_WatchdogData);
|
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_SET_TIME)(EFI_TIME *Time);
|
||||||
typedef EFI_STATUS(EFIAPI *EFI_GET_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)(
|
typedef EFI_STATUS(EFIAPI *EFI_TEXT_ENABLE_CURSOR)(
|
||||||
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, bool Visible);
|
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,
|
typedef EFI_STATUS(EFIAPI *EFI_HANDLE_PROTOCOL)(EFI_HANDLE Handle,
|
||||||
EFI_GUID *Protocol,
|
EFI_GUID *Protocol,
|
||||||
void *out_Interface);
|
void *out_Interface);
|
||||||
|
@ -414,7 +485,7 @@ typedef struct {
|
||||||
void *OpenProtocolInformation;
|
void *OpenProtocolInformation;
|
||||||
void *ProtocolsPerHandle;
|
void *ProtocolsPerHandle;
|
||||||
void *LocateHandleBuffer;
|
void *LocateHandleBuffer;
|
||||||
void *LocateProtocol;
|
EFI_LOCATE_PROTOCOL LocateProtocol;
|
||||||
void *InstallMultipleProtocolInterfaces;
|
void *InstallMultipleProtocolInterfaces;
|
||||||
void *UninstallMultipleProtocolInterfaces;
|
void *UninstallMultipleProtocolInterfaces;
|
||||||
void *CalculateCrc32;
|
void *CalculateCrc32;
|
||||||
|
@ -458,6 +529,13 @@ struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
|
||||||
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
|
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 {
|
typedef struct {
|
||||||
uint32_t Revision;
|
uint32_t Revision;
|
||||||
EFI_HANDLE ParentHandle;
|
EFI_HANDLE ParentHandle;
|
||||||
|
|
|
@ -16,9 +16,12 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "ape/relocations.h"
|
||||||
#include "ape/sections.internal.h"
|
#include "ape/sections.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/bits.h"
|
#include "libc/intrin/bits.h"
|
||||||
|
#include "libc/intrin/newbie.h"
|
||||||
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/efi.h"
|
#include "libc/nt/efi.h"
|
||||||
#include "libc/nt/thunk/msabi.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 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.
|
* EFI Application Entrypoint.
|
||||||
|
@ -62,19 +139,8 @@ static const EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
|
||||||
*
|
*
|
||||||
* @see libc/dce.h
|
* @see libc/dce.h
|
||||||
*/
|
*/
|
||||||
__msabi noasan __attribute__((__naked__))
|
__msabi noasan EFI_STATUS EfiMain(EFI_HANDLE ImageHandle,
|
||||||
EFI_STATUS EfiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
|
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) {
|
|
||||||
int type, x87cw = 0x037f;
|
int type, x87cw = 0x037f;
|
||||||
struct mman *mm;
|
struct mman *mm;
|
||||||
uint32_t DescVersion;
|
uint32_t DescVersion;
|
||||||
|
@ -82,18 +148,37 @@ __msabi noasan EFI_STATUS _DoEfiMain(EFI_HANDLE ImageHandle,
|
||||||
struct EfiArgs *ArgBlock;
|
struct EfiArgs *ArgBlock;
|
||||||
EFI_LOADED_IMAGE *ImgInfo;
|
EFI_LOADED_IMAGE *ImgInfo;
|
||||||
EFI_MEMORY_DESCRIPTOR *Map, *Desc;
|
EFI_MEMORY_DESCRIPTOR *Map, *Desc;
|
||||||
uint64_t NewBase = 1024 * 1024;
|
uint64_t Address;
|
||||||
uintptr_t Args, MapKey, DescSize;
|
uintptr_t Args, MapKey, DescSize;
|
||||||
uint64_t p, pe, cr4, *m, *pd, *sp, *pml4t, *pdt1, *pdt2, *pdpt1, *pdpt2;
|
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(
|
SystemTable->BootServices->AllocatePages(
|
||||||
AllocateAddress, EfiConventionalMemory,
|
AllocateAddress, EfiRuntimeServicesData, 4096 / 4096, &Address);
|
||||||
MAX(2 * 1024 * 1024, 1024 * 1024 + (_end - _base)) / 4096, &NewBase);
|
Address = 4096;
|
||||||
SystemTable->BootServices->SetMem(0, 0x80000, 0);
|
SystemTable->BootServices->AllocatePages(
|
||||||
SystemTable->BootServices->CopyMem((void *)(1024 * 1024), _base,
|
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);
|
_end - _base);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -106,6 +191,13 @@ __msabi noasan EFI_STATUS _DoEfiMain(EFI_HANDLE ImageHandle,
|
||||||
sizeof(ArgBlock->ArgBlock), ArgBlock->Args,
|
sizeof(ArgBlock->ArgBlock), ArgBlock->Args,
|
||||||
ARRAYLEN(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.
|
* 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;
|
MapSize *= 2;
|
||||||
SystemTable->BootServices->GetMemoryMap(&MapSize, Map, &MapKey, &DescSize,
|
SystemTable->BootServices->GetMemoryMap(&MapSize, Map, &MapKey, &DescSize,
|
||||||
&DescVersion);
|
&DescVersion);
|
||||||
mm = (struct mman *)0x0500;
|
|
||||||
for (j = i = 0, Desc = Map; i < MapSize / DescSize; ++i) {
|
for (j = i = 0, Desc = Map; i < MapSize / DescSize; ++i) {
|
||||||
if (Desc->Type == EfiConventionalMemory) {
|
switch (Desc->Type) {
|
||||||
mm->e820[j].addr = Desc->PhysicalStart;
|
case EfiLoaderCode:
|
||||||
mm->e820[j].size = Desc->NumberOfPages * 4096;
|
case EfiLoaderData:
|
||||||
mm->e820[j].type = kMemoryUsable;
|
case EfiBootServicesCode:
|
||||||
++j;
|
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);
|
Desc = (EFI_MEMORY_DESCRIPTOR *)((char *)Desc + DescSize);
|
||||||
}
|
}
|
||||||
|
@ -154,77 +253,8 @@ __msabi noasan EFI_STATUS _DoEfiMain(EFI_HANDLE ImageHandle,
|
||||||
SystemTable->BootServices->ExitBootServices(ImageHandle, MapKey);
|
SystemTable->BootServices->ExitBootServices(ImageHandle, MapKey);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Switches to copied image.
|
* Switches to copied image and launches program.
|
||||||
*/
|
*/
|
||||||
asm volatile("cli\n\t"
|
_EfiPostboot(mm, pml4t, Args, ArgBlock->Args);
|
||||||
"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");
|
|
||||||
|
|
||||||
unreachable;
|
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