From 8089876c5121986e50f389bdb6d326a521e907cd Mon Sep 17 00:00:00 2001 From: tkchia Date: Thu, 22 Sep 2022 18:28:44 +0000 Subject: [PATCH] Bare metal: tweaks pertaining to physical memory handling - Factor __invert_memory() into two routines, to make it easier for other libc routines to create their own negative address mappings - Tweak __invert_memory() to map only the usable memory as given in the 0xe820 memory map, and no more - Arrange for VGA console initialization to map video memory separately into virtual memory (in case needed) - Rename libc/vga/vga-init.S to libc/vga/rlinit-vga.S, to reduce confusion as to the module's purpose --- libc/intrin/mman.greg.c | 29 ++++++++++++++++++++------- libc/runtime/pc.internal.h | 2 ++ libc/vga/{vga-init.S => rlinit-vga.S} | 0 libc/vga/writev-vga.c | 4 ++++ 4 files changed, 28 insertions(+), 7 deletions(-) rename libc/vga/{vga-init.S => rlinit-vga.S} (100%) diff --git a/libc/intrin/mman.greg.c b/libc/intrin/mman.greg.c index e85eb9784..c9f54e3e7 100644 --- a/libc/intrin/mman.greg.c +++ b/libc/intrin/mman.greg.c @@ -112,19 +112,34 @@ static noasan textreal void __normalize_e820(struct mman *mm) { mm->e820n = n; } +/** + * Identity maps an area of physical memory to its negative address. + */ +noasan textreal void __invert_memory_area(struct mman *mm, uint64_t *pml4t, + uint64_t ps, uint64_t size, + uint64_t pte_flags) { + uint64_t pe = ps + size, p, *m; + ps = ROUNDDOWN(ps, 4096); + pe = ROUNDUP(pe, 4096); + for (p = ps; p != pe; p += 4096) { + m = __get_virtual(mm, pml4t, BANE + p, true); + if (m && !(*m & PAGE_V)) { + *m = p | PAGE_V | pte_flags; + } + } +} + /** * Identity maps all usable physical memory to its negative address. */ static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) { uint64_t i, j, *m, p, pe; for (i = 0; i < mm->e820n; ++i) { - for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size; - p != pe + 0x200000; p += 4096) { - m = __get_virtual(mm, pml4t, BANE + p, true); - if (m && !(*m & PAGE_V)) { - *m = p | PAGE_V | PAGE_RW; - } - } + uint64_t ps = mm->e820[i].addr, size = mm->e820[i].size; + /* ape/ape.S has already mapped the first 2 MiB of physical memory. */ + if (ps < 0x200000 && ps + size <= 0x200000) + continue; + __invert_memory_area(mm, pml4t, ps, size, PAGE_RW); } } diff --git a/libc/runtime/pc.internal.h b/libc/runtime/pc.internal.h index 45ca8d919..a2dc3b84a 100644 --- a/libc/runtime/pc.internal.h +++ b/libc/runtime/pc.internal.h @@ -185,6 +185,8 @@ struct IdtDescriptor { uint64_t *__get_virtual(struct mman *, uint64_t *, int64_t, bool); uint64_t __clear_page(uint64_t); 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); forceinline unsigned char inb(unsigned short port) { diff --git a/libc/vga/vga-init.S b/libc/vga/rlinit-vga.S similarity index 100% rename from libc/vga/vga-init.S rename to libc/vga/rlinit-vga.S diff --git a/libc/vga/writev-vga.c b/libc/vga/writev-vga.c index d71cd445b..0bb14c9fc 100644 --- a/libc/vga/writev-vga.c +++ b/libc/vga/writev-vga.c @@ -60,6 +60,7 @@ ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) { __attribute__((__constructor__)) static textstartup void _vga_init(void) { if (IsMetal()) { + struct mman *mm = (struct mman *)(BANE + 0x0500); void * const vid_buf = (void *)(BANE + 0xb8000ull); /* * Get the initial cursor position from the BIOS data area. Also get @@ -74,6 +75,9 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) { chr_ht_hi = *(uint8_t *)(BANE + 0x0486ull); if (chr_ht_hi != 0 || chr_ht > 32) chr_ht = 32; + /* Make sure the video buffer is mapped into virtual memory. */ + __invert_memory_area(mm, __get_pml4t(), (uint64_t)vid_buf, + 2 * VGA_TTY_HEIGHT * VGA_TTY_WIDTH, PAGE_RW); /* * Initialize our tty structure from the current screen contents, * current cursor position, & character height.