mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-08 19:00:27 +00:00
[metal] Allow munmap() to reclaim dynamically allocated pages
This commit is contained in:
parent
dfd7f9aa1b
commit
de295966b1
5 changed files with 92 additions and 22 deletions
|
@ -21,13 +21,18 @@
|
||||||
|
|
||||||
noasan int sys_munmap_metal(void *addr, size_t size) {
|
noasan int sys_munmap_metal(void *addr, size_t size) {
|
||||||
size_t i;
|
size_t i;
|
||||||
uint64_t *e;
|
uint64_t *e, paddr;
|
||||||
struct mman *mm;
|
struct mman *mm;
|
||||||
|
uint64_t *pml4t = __get_pml4t();
|
||||||
mm = (struct mman *)(BANE + 0x0500);
|
mm = (struct mman *)(BANE + 0x0500);
|
||||||
for (i = 0; i < size; i += 4096) {
|
for (i = 0; i < size; i += 4096) {
|
||||||
e = __get_virtual(mm, __get_pml4t(), (uint64_t)addr + i, false);
|
e = __get_virtual(mm, pml4t, (uint64_t)addr + i, false);
|
||||||
if (e) *e = ~(PAGE_V | PAGE_RSRV);
|
if (e) {
|
||||||
invlpg((uint64_t)addr + i);
|
paddr = *e & PAGE_TA;
|
||||||
|
*e &= ~(PAGE_V | PAGE_RSRV);
|
||||||
|
invlpg((uint64_t)addr + i);
|
||||||
|
__unref_page(mm, pml4t, paddr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ noasan struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot,
|
||||||
size_t i;
|
size_t i;
|
||||||
struct mman *mm;
|
struct mman *mm;
|
||||||
struct DirectMap res;
|
struct DirectMap res;
|
||||||
uint64_t addr, faddr = 0, page, *pte, *fdpte, *pml4t;
|
uint64_t addr, faddr = 0, page, e, *pte, *fdpte, *pml4t;
|
||||||
mm = (struct mman *)(BANE + 0x0500);
|
mm = (struct mman *)(BANE + 0x0500);
|
||||||
pml4t = __get_pml4t();
|
pml4t = __get_pml4t();
|
||||||
size = ROUNDUP(size, 4096);
|
size = ROUNDUP(size, 4096);
|
||||||
|
@ -78,27 +78,27 @@ noasan struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot,
|
||||||
sys_mmap_metal_break = MAX(addr + size, sys_mmap_metal_break);
|
sys_mmap_metal_break = MAX(addr + size, sys_mmap_metal_break);
|
||||||
}
|
}
|
||||||
for (i = 0; i < size; i += 4096) {
|
for (i = 0; i < size; i += 4096) {
|
||||||
page = __new_page(mm);
|
|
||||||
pte = __get_virtual(mm, pml4t, addr + i, true);
|
pte = __get_virtual(mm, pml4t, addr + i, true);
|
||||||
if (pte) {
|
if (pte) {
|
||||||
if ((flags & MAP_ANONYMOUS_linux)) {
|
if ((flags & MAP_ANONYMOUS_linux)) {
|
||||||
page = __new_page(mm);
|
page = __new_page(mm);
|
||||||
if (!page) return bad_mmap();
|
if (!page) return bad_mmap();
|
||||||
__clear_page(BANE + page);
|
__clear_page(BANE + page);
|
||||||
page |= PAGE_RSRV | PAGE_U;
|
e = page | PAGE_RSRV | PAGE_U;
|
||||||
if ((prot & PROT_WRITE))
|
if ((prot & PROT_WRITE))
|
||||||
page |= PAGE_V | PAGE_RW;
|
e |= PAGE_V | PAGE_RW;
|
||||||
else if ((prot & (PROT_READ | PROT_EXEC)))
|
else if ((prot & (PROT_READ | PROT_EXEC)))
|
||||||
page |= PAGE_V;
|
e |= PAGE_V;
|
||||||
if (!(prot & PROT_EXEC)) page |= PAGE_XD;
|
if (!(prot & PROT_EXEC)) e |= PAGE_XD;
|
||||||
} else {
|
} else {
|
||||||
fdpte = __get_virtual(mm, pml4t, faddr + i, false);
|
fdpte = __get_virtual(mm, pml4t, faddr + i, false);
|
||||||
page = *fdpte;
|
e = *fdpte | PAGE_RSRV | PAGE_U;
|
||||||
page |= PAGE_RSRV | PAGE_U;
|
page = e & PAGE_TA;
|
||||||
if (!(prot & PROT_WRITE)) page &= ~PAGE_RW;
|
if (!(prot & PROT_WRITE)) e &= ~PAGE_RW;
|
||||||
if (!(prot & PROT_EXEC)) page |= PAGE_XD;
|
if (!(prot & PROT_EXEC)) e |= PAGE_XD;
|
||||||
}
|
}
|
||||||
*pte = page;
|
__ref_page(mm, pml4t, page);
|
||||||
|
*pte = e;
|
||||||
invlpg(addr + i);
|
invlpg(addr + i);
|
||||||
} else {
|
} else {
|
||||||
addr = -1;
|
addr = -1;
|
||||||
|
|
|
@ -133,10 +133,11 @@ static noasan textreal void __normalize_e820(struct mman *mm, uint64_t top) {
|
||||||
/**
|
/**
|
||||||
* Identity maps an area of physical memory to its negative address.
|
* Identity maps an area of physical memory to its negative address.
|
||||||
*/
|
*/
|
||||||
noasan textreal void __invert_memory_area(struct mman *mm, uint64_t *pml4t,
|
noasan textreal uint64_t *__invert_memory_area(struct mman *mm,
|
||||||
uint64_t ps, uint64_t size,
|
uint64_t *pml4t,
|
||||||
uint64_t pte_flags) {
|
uint64_t ps, uint64_t size,
|
||||||
uint64_t pe = ps + size, p, *m;
|
uint64_t pte_flags) {
|
||||||
|
uint64_t pe = ps + size, p, *m = NULL;
|
||||||
ps = ROUNDDOWN(ps, 4096);
|
ps = ROUNDDOWN(ps, 4096);
|
||||||
pe = ROUNDUP(pe, 4096);
|
pe = ROUNDUP(pe, 4096);
|
||||||
for (p = ps; p != pe; p += 4096) {
|
for (p = ps; p != pe; p += 4096) {
|
||||||
|
@ -145,6 +146,62 @@ noasan textreal void __invert_memory_area(struct mman *mm, uint64_t *pml4t,
|
||||||
*m = p | PAGE_V | PAGE_RSRV | pte_flags;
|
*m = p | PAGE_V | PAGE_RSRV | pte_flags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the reference count for a page of physical memory.
|
||||||
|
*/
|
||||||
|
noasan void __ref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
|
||||||
|
uint64_t *m, e;
|
||||||
|
m = __invert_memory_area(mm, pml4t, p, 4096, PAGE_RW | PAGE_XD);
|
||||||
|
if (m) {
|
||||||
|
e = *m;
|
||||||
|
if ((e & PAGE_REFC) != PAGE_REFC) {
|
||||||
|
e += PAGE_1REF;
|
||||||
|
*m = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the reference counts for an area of physical memory.
|
||||||
|
*/
|
||||||
|
noasan void __ref_pages(struct mman *mm, uint64_t *pml4t, uint64_t ps,
|
||||||
|
uint64_t size) {
|
||||||
|
uint64_t p = ROUNDDOWN(ps, 4096), e = ROUNDUP(ps + size, 4096);
|
||||||
|
while (p != e) {
|
||||||
|
__ref_page(mm, pml4t, p);
|
||||||
|
p += 4096;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reclaims a page of physical memory for later use.
|
||||||
|
*/
|
||||||
|
static noasan void __reclaim_page(struct mman *mm, uint64_t p) {
|
||||||
|
struct ReclaimedPage *rp = (struct ReclaimedPage *)(BANE + p);
|
||||||
|
_unassert(p == (p & PAGE_TA));
|
||||||
|
rp->next = mm->frp;
|
||||||
|
mm->frp = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements the reference count for a page of physical memory. Frees the
|
||||||
|
* page if there are no virtual addresses (excluding the negative space)
|
||||||
|
* referring to it.
|
||||||
|
*/
|
||||||
|
noasan void __unref_page(struct mman *mm, uint64_t *pml4t, uint64_t p) {
|
||||||
|
uint64_t *m, e;
|
||||||
|
m = __invert_memory_area(mm, pml4t, p, 4096, PAGE_RW | PAGE_XD);
|
||||||
|
if (m) {
|
||||||
|
e = *m;
|
||||||
|
if ((e & PAGE_REFC) != PAGE_REFC) {
|
||||||
|
e -= PAGE_1REF;
|
||||||
|
*m = e;
|
||||||
|
if ((e & PAGE_REFC) == 0) __reclaim_page(mm, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -224,6 +281,7 @@ noasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b,
|
||||||
v = __clear_page(BANE + __new_page(mm));
|
v = __clear_page(BANE + __new_page(mm));
|
||||||
}
|
}
|
||||||
*__get_virtual(mm, pml4t, p->p_vaddr + i, true) = (v & PAGE_TA) | f;
|
*__get_virtual(mm, pml4t, p->p_vaddr + i, true) = (v & PAGE_TA) | f;
|
||||||
|
__ref_page(mm, pml4t, v & PAGE_TA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,7 +289,7 @@ noasan textreal void __map_phdrs(struct mman *mm, uint64_t *pml4t, uint64_t b,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reclaim memory pages which were used at boot time but which can now be
|
* Reclaims memory pages which were used at boot time but which can now be
|
||||||
* made available for the application.
|
* made available for the application.
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
|
|
|
@ -167,6 +167,9 @@
|
||||||
#define PAGE_GROD /* blinkenlights MAP_GROWSDOWN */ 0b010000000000
|
#define PAGE_GROD /* blinkenlights MAP_GROWSDOWN */ 0b010000000000
|
||||||
#define PAGE_TA 0x00007ffffffff000
|
#define PAGE_TA 0x00007ffffffff000
|
||||||
#define PAGE_PA2 0x00007fffffe00000
|
#define PAGE_PA2 0x00007fffffe00000
|
||||||
|
#define PAGE_IGN2 0x07f0000000000000
|
||||||
|
#define PAGE_REFC PAGE_IGN2 /* libc reference counting */
|
||||||
|
#define PAGE_1REF 0x0010000000000000 /* libc reference counting */
|
||||||
#define PAGE_XD 0x8000000000000000
|
#define PAGE_XD 0x8000000000000000
|
||||||
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
@ -186,10 +189,13 @@ struct IdtDescriptor {
|
||||||
uint64_t *__get_virtual(struct mman *, uint64_t *, int64_t, bool);
|
uint64_t *__get_virtual(struct mman *, uint64_t *, int64_t, bool);
|
||||||
uint64_t __clear_page(uint64_t);
|
uint64_t __clear_page(uint64_t);
|
||||||
uint64_t __new_page(struct mman *);
|
uint64_t __new_page(struct mman *);
|
||||||
void __invert_memory_area(struct mman *, uint64_t *, uint64_t, uint64_t,
|
uint64_t * __invert_memory_area(struct mman *, uint64_t *, uint64_t, uint64_t,
|
||||||
uint64_t);
|
uint64_t);
|
||||||
void __map_phdrs(struct mman *, 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);
|
void __reclaim_boot_pages(struct mman *, uint64_t, uint64_t);
|
||||||
|
void __ref_page(struct mman *, uint64_t *, uint64_t);
|
||||||
|
void __ref_pages(struct mman *, uint64_t *, uint64_t, uint64_t);
|
||||||
|
void __unref_page(struct mman *, uint64_t *, uint64_t);
|
||||||
|
|
||||||
forceinline unsigned char inb(unsigned short port) {
|
forceinline unsigned char inb(unsigned short port) {
|
||||||
unsigned char al;
|
unsigned char al;
|
||||||
|
|
|
@ -53,6 +53,7 @@ void _vga_reinit(struct Tty *tty, unsigned short starty, unsigned short startx,
|
||||||
/* Make sure the video buffer is mapped into virtual memory. */
|
/* Make sure the video buffer is mapped into virtual memory. */
|
||||||
__invert_memory_area(mm, __get_pml4t(), vid_buf_phy, vid_buf_sz,
|
__invert_memory_area(mm, __get_pml4t(), vid_buf_phy, vid_buf_sz,
|
||||||
PAGE_RW | PAGE_XD);
|
PAGE_RW | PAGE_XD);
|
||||||
|
__ref_pages(mm, __get_pml4t(), vid_buf_phy, vid_buf_sz);
|
||||||
/*
|
/*
|
||||||
* Initialize our tty structure from the current screen geometry, screen
|
* Initialize our tty structure from the current screen geometry, screen
|
||||||
* contents, cursor position, & character dimensions.
|
* contents, cursor position, & character dimensions.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue