mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 02:38:31 +00:00
Support malloc() on bare metal
Your Actually Portable Executables now contains a simple virtual memory that works similarly to the Linux Kernel in the sense that it maps your physical memory to negative addresses. This is needed to support mmap() and malloc(). This functionality has zero code size impact. For example the MODE=tiny LIFE.COM executable is still only 12KB in size. The APE bootloader code has also been simplified to improve readibility and further elevate the elegance by which we're able to support so many platforms thereby enhancing verifiability so that we may engender trust in this bootloading process.
This commit is contained in:
parent
ac3b1dfb21
commit
edd9297eba
89 changed files with 900 additions and 1417 deletions
|
@ -16,17 +16,23 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/efi.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/efi.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/e820.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/* TOOD: Why can't we change CR3? Could it really need PML5T? */
|
||||
/* TOOD: Why does QEMU in UEFI mode take ten seconds to boot? */
|
||||
|
||||
struct EfiArgs {
|
||||
char *args[4096];
|
||||
char argblock[ARG_MAX];
|
||||
char *Args[0x400 / sizeof(char *)];
|
||||
char ArgBlock[0xC00];
|
||||
};
|
||||
|
||||
static const EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
|
||||
|
@ -36,15 +42,14 @@ static const EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
|
|||
*
|
||||
* This entrypoint is mutually exclusive from WinMain since
|
||||
* Windows apps and EFI apps use the same PE binary format.
|
||||
* By default, we build binaries to support Windows. If you
|
||||
* want to your APE executable to boot on UEFI instead then
|
||||
* you need to run the following build command:
|
||||
* So if you want to trade away Windows so that you can use
|
||||
* UEFI instead of the normal BIOS boot process, do this:
|
||||
*
|
||||
* make -j8 CPPFLAGS=-DSUPPORT_VECTOR=251
|
||||
* STATIC_YOINK("EfiMain");
|
||||
* int main() { ... }
|
||||
*
|
||||
* That'll remove all the Windows code and turn EFI on. You
|
||||
* can also remove by BIOS code too, by changing 251 to 249
|
||||
* but it shouldn't matter. Here's how to emulate EFI apps:
|
||||
* You can use QEMU to test this, but please note that UEFI
|
||||
* goes thousands of times slower than the normal BIOS boot
|
||||
*
|
||||
* qemu-system-x86_64 \
|
||||
* -bios OVMF.fd \
|
||||
|
@ -54,41 +59,129 @@ static const EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
|
|||
* FS0:
|
||||
* deathstar.com
|
||||
*
|
||||
* If you're using the amalgamated release binaries then it
|
||||
* should be possible to enable UEFI mode by having this at
|
||||
* the top of your main source file to hint the APE linker:
|
||||
*
|
||||
* STATIC_YOINK("EfiMain");
|
||||
* int main() { ... }
|
||||
*
|
||||
* @see libc/dce.h
|
||||
*/
|
||||
__msabi noasan EFI_STATUS EfiMain(EFI_HANDLE ImageHandle,
|
||||
EFI_SYSTEM_TABLE *SystemTable) {
|
||||
intptr_t argc;
|
||||
struct EfiArgs *ea;
|
||||
EFI_LOADED_IMAGE *img;
|
||||
extern char os asm("__hostos");
|
||||
os = UEFI;
|
||||
__efi_image_handle = ImageHandle;
|
||||
__efi_system_table = SystemTable;
|
||||
SystemTable->BootServices->AllocatePool(EfiConventionalMemory, sizeof(*ea),
|
||||
&ea);
|
||||
bool ispml5t;
|
||||
int type, x87cw;
|
||||
struct mman *mm;
|
||||
uint32_t DescVersion;
|
||||
uintptr_t i, j, MapSize;
|
||||
struct EfiArgs *ArgBlock;
|
||||
EFI_LOADED_IMAGE *ImgInfo;
|
||||
EFI_MEMORY_DESCRIPTOR *Map;
|
||||
uintptr_t Args, MapKey, DescSize;
|
||||
uint64_t p, pe, cr4, *m, *pd, *sp, *pml4t, *pdt1, *pdt2, *pdpt1, *pdpt2;
|
||||
extern char __os asm("__hostos");
|
||||
|
||||
__os = METAL;
|
||||
|
||||
/*
|
||||
* Allocates and clears PC-compatible memory and copies image.
|
||||
*/
|
||||
SystemTable->BootServices->AllocatePages(
|
||||
EfiConventionalMemory, AllocateAddress,
|
||||
MAX(2 * 1024 * 1024, 1024 * 1024 + (_end - _base)) / 4096, 0);
|
||||
SystemTable->BootServices->SetMem(0, 0x80000, 0);
|
||||
SystemTable->BootServices->CopyMem((void *)(1024 * 1024), _base,
|
||||
_end - _base);
|
||||
|
||||
/*
|
||||
* Converts UEFI shell arguments to argv.
|
||||
*/
|
||||
ArgBlock = (struct EfiArgs *)0x7e000;
|
||||
SystemTable->BootServices->HandleProtocol(ImageHandle,
|
||||
&kEfiLoadedImageProtocol, &img);
|
||||
argc = GetDosArgv(img->LoadOptions, ea->argblock, ARG_MAX, ea->args,
|
||||
ARRAYLEN(ea->args));
|
||||
asm("push\t$0\n\t" /* auxv[0][1] */
|
||||
"push\t$0\n\t" /* auxv[0][0] */
|
||||
"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"
|
||||
".weak\t_start\n\t"
|
||||
"jmp\t_start"
|
||||
: /* no outputs */
|
||||
: "a"(argc), "S"(ea->args), "c"((argc + 1) * 8));
|
||||
&kEfiLoadedImageProtocol, &ImgInfo);
|
||||
Args = GetDosArgv(ImgInfo->LoadOptions, ArgBlock->ArgBlock,
|
||||
sizeof(ArgBlock->ArgBlock), ArgBlock->Args,
|
||||
ARRAYLEN(ArgBlock->Args));
|
||||
|
||||
/*
|
||||
* Asks UEFI which parts of our RAM we're allowed to use.
|
||||
*/
|
||||
Map = NULL;
|
||||
MapSize = 0;
|
||||
SystemTable->BootServices->GetMemoryMap(&MapSize, Map, &MapKey, &DescSize,
|
||||
&DescVersion);
|
||||
SystemTable->BootServices->AllocatePool(EfiLoaderData, MapSize, Map);
|
||||
SystemTable->BootServices->GetMemoryMap(&MapSize, Map, &MapKey, &DescSize,
|
||||
&DescVersion);
|
||||
asm("xor\t%0,%0" : "=r"(mm)); /* gcc assumes null isn't mapped */
|
||||
for (j = i = 0; i < MapSize / sizeof(EFI_MEMORY_DESCRIPTOR); ++i) {
|
||||
if (Map[i].Type != EfiConventionalMemory) continue;
|
||||
mm->e820[j].addr = Map[i].PhysicalStart;
|
||||
mm->e820[j].size = Map[i].NumberOfPages * 4096;
|
||||
mm->e820[j].type = kMemoryUsable;
|
||||
++j;
|
||||
}
|
||||
SystemTable->BootServices->FreePool(Map);
|
||||
|
||||
/*
|
||||
* Sets up page tables.
|
||||
*/
|
||||
pd = (uint64_t *)0x79000;
|
||||
pdt1 = (uint64_t *)0x7b000;
|
||||
pdt2 = (uint64_t *)0x7a000;
|
||||
pdpt1 = (uint64_t *)0x7d000;
|
||||
pdpt2 = (uint64_t *)0x7c000;
|
||||
pml4t = (uint64_t *)0x7e000;
|
||||
for (i = 0; i < 512; ++i) {
|
||||
pd[i] = 0x1000 * i + PAGE_V + PAGE_RW;
|
||||
}
|
||||
pdt1[0] = (intptr_t)pd + PAGE_V + PAGE_RW;
|
||||
pdt2[0] = (intptr_t)pd + PAGE_V + PAGE_RW;
|
||||
pdpt1[0] = (intptr_t)pdt1 + PAGE_V + PAGE_RW;
|
||||
pdpt2[0] = (intptr_t)pdt2 + PAGE_V + PAGE_RW;
|
||||
pml4t[0] = (intptr_t)pdpt1 + PAGE_V + PAGE_RW;
|
||||
pml4t[256] = (intptr_t)pdpt2 + PAGE_V + PAGE_RW;
|
||||
__map_phdrs(mm, pml4t, 1024 * 1024);
|
||||
|
||||
/*
|
||||
* Asks UEFI to handover control?
|
||||
*/
|
||||
SystemTable->BootServices->ExitBootServices(ImageHandle, MapKey);
|
||||
|
||||
/*
|
||||
* Launches program.
|
||||
*/
|
||||
asm volatile("fldcw\t%3\n\t"
|
||||
"mov\t%4,%%cr3\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"
|
||||
"xor\t%%ecx,%%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"
|
||||
"jmp\t_start"
|
||||
: /* no outputs */
|
||||
: "a"(Args), "S"(ArgBlock->Args), "c"((Args + 1) * 8),
|
||||
"m"(x87cw), "r"(pml4t)
|
||||
: "memory");
|
||||
|
||||
unreachable;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue