diff --git a/ape/ape.S b/ape/ape.S index 81bcff31e..dad97b2e7 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -1504,7 +1504,6 @@ long: movabs $BANE+PHYSICAL(0f),%rax xor %r15d,%r15d xor %ebx,%ebx xor %ebp,%ebp - push %rbp mov $mm,%rdi mov %cr3,%rsi mov $IMAGE_BASE_PHYSICAL,%edx @@ -1594,6 +1593,10 @@ kernel: movabs $ape_stack_vaddr,%rsp .byte 0x0f,0x1f,0207 # nop rdi binbase .long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512 #endif + movabs $BANE+mm,%rdi + mov $0x79000,%esi + mov $0x7f000,%edx + call __reclaim_boot_pages push $_HOSTMETAL # sets __hostos in crt.S pop %rcx pushq .Lenv0(%rip) # envp[0][0] diff --git a/libc/intrin/mman.greg.c b/libc/intrin/mman.greg.c index 642418409..6191d5f6e 100644 --- a/libc/intrin/mman.greg.c +++ b/libc/intrin/mman.greg.c @@ -33,6 +33,7 @@ │ αcτµαlly pδrταblε εxεcµταblε § no-frills virtual memory management │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "ape/relocations.h" +#include "libc/assert.h" #include "libc/elf/def.h" #include "libc/elf/struct/phdr.h" #include "libc/macros.internal.h" @@ -44,13 +45,25 @@ #define INVERT(x) (BANE + PHYSICAL(x)) +struct ReclaimedPage { + uint64_t next; +}; + /** * Allocates new page of physical memory. */ noasan texthead uint64_t __new_page(struct mman *mm) { - uint64_t p; + uint64_t p = mm->frp; + if (p) { + uint64_t q; + struct ReclaimedPage *rp = (struct ReclaimedPage *)(BANE + p); + _unassert(p == (p & PAGE_TA)); + q = rp->next; + _unassert(q == (q & PAGE_TA)); + mm->frp = q; + return p; + } if (mm->pdpi == mm->e820n) { - /* TODO: reclaim free pages */ return 0; } while (mm->pdp >= mm->e820[mm->pdpi].addr + mm->e820[mm->pdpi].size) { @@ -113,6 +126,7 @@ static noasan textreal void __normalize_e820(struct mman *mm, uint64_t top) { mm->pdp = MAX(top, mm->e820[0].addr); mm->pdpi = 0; mm->e820n = n; + mm->frp = 0; } /** @@ -210,3 +224,21 @@ noasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b, } mm->pdp = MAX(mm->pdp, m); } + +/** + * Reclaim memory pages which were used at boot time but which can now be + * made available for the application. + */ +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; + } + mm->frp = p; +} diff --git a/libc/runtime/efimain.greg.c b/libc/runtime/efimain.greg.c index 5601c896e..926deaa52 100644 --- a/libc/runtime/efimain.greg.c +++ b/libc/runtime/efimain.greg.c @@ -136,6 +136,7 @@ __msabi noasan EFI_STATUS EfiMain(EFI_HANDLE ImageHandle, pml4t[0] = (intptr_t)pdpt1 + PAGE_V + PAGE_RW; pml4t[256] = (intptr_t)pdpt2 + PAGE_V + PAGE_RW; __map_phdrs(mm, pml4t, 1024 * 1024, 1024 * 1024 + (_end - _base)); + __reclaim_boot_pages(mm, 0x79000, 0x7f000); /* * Asks UEFI to handover control? diff --git a/libc/runtime/mman.internal.h b/libc/runtime/mman.internal.h index 64c0fcb95..8d3ba21b9 100644 --- a/libc/runtime/mman.internal.h +++ b/libc/runtime/mman.internal.h @@ -8,31 +8,33 @@ struct mman { int64_t pdp; /* 0x0500 */ int32_t pdpi; /* 0x0508 */ int32_t e820n; /* 0x050c */ - struct SmapEntry e820[256]; /* 0x0510 */ - struct SmapEntry e820_end[0]; /* 0x1d10 */ - char pc_drive_base_table[11]; /* 0x1d10 */ - unsigned char pc_drive_type; /* 0x1d1b */ - unsigned char pc_drive_last_sector; /* 0x1d1c */ - unsigned short pc_drive_last_cylinder; /* 0x1d1e */ - unsigned char pc_drives_attached; /* 0x1d20 */ - unsigned char pc_drive_last_head; /* 0x1d21 */ - unsigned char pc_drive; /* 0x1d22 */ - char bad_idt[6]; /* 0x1d23 */ - unsigned char pc_video_type; /* 0x1d29 */ - unsigned short pc_video_stride; /* 0x1d2a — line width, including any + uint64_t frp; /* 0x0510 — free list of reclaimed, + previously used pages */ + struct SmapEntry e820[256]; /* 0x0518 */ + struct SmapEntry e820_end[0]; /* 0x1d18 */ + char pc_drive_base_table[11]; /* 0x1d18 */ + unsigned char pc_drive_type; /* 0x1d23 */ + unsigned char pc_drive_last_sector; /* 0x1d24 */ + unsigned short pc_drive_last_cylinder; /* 0x1d26 */ + unsigned char pc_drives_attached; /* 0x1d28 */ + unsigned char pc_drive_last_head; /* 0x1d29 */ + unsigned char pc_drive; /* 0x1d2a */ + char bad_idt[6]; /* 0x1d2b */ + unsigned char pc_video_type; /* 0x1d31 */ + unsigned short pc_video_stride; /* 0x1d32 — line width, including any invisible "pixels" — in bytes (NOTE) */ - unsigned short pc_video_width; /* 0x1d2c — width in chars. (text) + unsigned short pc_video_width; /* 0x1d34 — width in chars. (text) or pixels (graphics) */ - unsigned short pc_video_height; /* 0x1d2e — height in chars. (text) + unsigned short pc_video_height; /* 0x1d36 — height in chars. (text) or pixels (graphics) */ - uint64_t pc_video_framebuffer; /* 0x1d30 — physical address of + uint64_t pc_video_framebuffer; /* 0x1d38 — physical address of video frame buffer */ - uint64_t pc_video_framebuffer_size; /* 0x1d38 */ - struct { /* 0x1d40 — starting cursor pos. */ + uint64_t pc_video_framebuffer_size; /* 0x1d40 */ + struct { /* 0x1d48 — starting cursor pos. */ unsigned short y, x; } pc_video_curs_info; - unsigned short pc_video_char_height; /* 0x1d44 — character height (useful + unsigned short pc_video_char_height; /* 0x1d4c — character height (useful for setting cursor shape in text mode) */ }; diff --git a/libc/runtime/pc.internal.h b/libc/runtime/pc.internal.h index 64904dcba..1144fed8c 100644 --- a/libc/runtime/pc.internal.h +++ b/libc/runtime/pc.internal.h @@ -189,6 +189,7 @@ uint64_t __new_page(struct mman *); void __invert_memory_area(struct mman *, uint64_t *, uint64_t, uint64_t, uint64_t); void __map_phdrs(struct mman *, uint64_t *, uint64_t, uint64_t); +void __reclaim_boot_pages(struct mman *, uint64_t, uint64_t); forceinline unsigned char inb(unsigned short port) { unsigned char al;