sandbox: vm: add page splitting, merging, and allocation

This commit is contained in:
2023-02-01 15:03:42 +00:00
parent 4cb30737fb
commit af49d47ba8
4 changed files with 218 additions and 0 deletions

View File

@@ -145,3 +145,118 @@ vm_zone_t *vm_page_get_zone(vm_page_t *pg)
return &node->pg_zones[pg->p_zone];
}
vm_page_t *vm_page_alloc(vm_page_order_t order, vm_flags_t flags)
{
/* TODO prefer nodes closer to us */
vm_pg_data_t *node = vm_pg_data_get(0);
vm_zone_id_t zone_id = VM_ZONE_HIGHMEM;
if (flags & VM_GET_DMA) {
zone_id = VM_ZONE_DMA;
}
while (1) {
vm_zone_t *z = &node->pg_zones[zone_id];
vm_page_t *pg = vm_zone_alloc_page(z, order, flags);
if (pg) {
return pg;
}
if (zone_id == VM_ZONE_MIN) {
break;
}
zone_id--;
}
return NULL;
}
void vm_page_free(vm_page_t *pg)
{
vm_zone_t *z = vm_page_get_zone(pg);
if (!z) {
return;
}
vm_zone_free_page(z, pg);
}
int vm_page_split(vm_page_t *pg, vm_page_t **a, vm_page_t **b)
{
if (pg->p_order == VM_PAGE_MIN_ORDER) {
return -1;
}
size_t nr_frames = vm_page_order_to_pages(pg->p_order);
for (size_t i = 0; i < nr_frames; i++) {
pg[i].p_order = pg->p_order - 1;
}
vm_page_t *buddy = vm_page_get_buddy(pg);
if (pg->p_order == VM_PAGE_MIN_ORDER) {
pg->p_flags &= ~(VM_PAGE_HUGE | VM_PAGE_HEAD);
buddy->p_flags &= ~(VM_PAGE_HUGE | VM_PAGE_HEAD);
} else {
pg->p_flags |= VM_PAGE_HEAD | VM_PAGE_HUGE;
buddy->p_flags |= VM_PAGE_HEAD | VM_PAGE_HUGE;
}
*a = pg;
*b = buddy;
return 0;
}
vm_page_t *vm_page_merge(vm_page_t *a, vm_page_t *b)
{
if (a->p_order != b->p_order) {
return NULL;
}
if (a->p_order == VM_PAGE_MAX_ORDER) {
return NULL;
}
if (vm_page_get_buddy(a) != b) {
return NULL;
}
if (VM_PAGE_IS_RESERVED(a) && !VM_PAGE_IS_RESERVED(b)) {
return NULL;
}
if (!VM_PAGE_IS_RESERVED(a) && VM_PAGE_IS_RESERVED(b)) {
return NULL;
}
/* make sure that a comes before b */
if (a > b) {
vm_page_t *tmp = a;
a = b;
b = tmp;
}
a->p_order++;
size_t nr_frames = vm_page_order_to_pages(a->p_order);
for (size_t i = 0; i < nr_frames; i++) {
a[i].p_flags &= ~VM_PAGE_HEAD;
a[i].p_flags |= VM_PAGE_HUGE;
a[i].p_order = a->p_order;
}
a->p_flags |= VM_PAGE_HEAD;
return 0;
}
vm_page_t *vm_page_get_buddy(vm_page_t *pg)
{
phys_addr_t paddr = vm_page_get_paddr(pg);
paddr = paddr ^ vm_page_order_to_bytes(pg->p_order);
return vm_page_get(paddr);
}