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

@@ -1,3 +1,4 @@
#include "socks/queue.h"
#include <socks/types.h>
#include <socks/vm.h>
#include <string.h>
@@ -126,3 +127,80 @@ void vm_zone_init(vm_zone_t *z, const vm_zone_descriptor_t *zone_info)
convert_region_to_blocks(z, block_start, block_end + VM_PAGE_SIZE - 1, this_page_reserved);
}
}
static int replenish_free_page_list(vm_zone_t *z, vm_page_order_t order)
{
if (queue_length(&z->z_free_pages[order]) != 0) {
/* we already have pages available. */
return 0;
}
if (order == VM_PAGE_MAX_ORDER) {
/* there are no larger pages to split, so just give up. */
return -1;
}
/* the lowest page order that is >= `order` and still has pages available */
vm_page_order_t first_order_with_free = VM_MAX_PAGE_ORDERS;
for (vm_page_order_t i = order; i <= VM_PAGE_MAX_ORDER; i++) {
if (queue_length(&z->z_free_pages[i]) > 0) {
first_order_with_free = i;
break;
}
}
if (first_order_with_free == VM_MAX_PAGE_ORDERS) {
/* there are no pages available to split */
return -1;
}
if (first_order_with_free == order) {
/* there are free pages of the requested order, so nothing needs to be done */
return 0;
}
/* starting from the first page list with free pages,
take a page, split it in half, and add the sub-pages
to the next order's free list. */
for (vm_page_order_t i = first_order_with_free; i > order; i--) {
queue_entry_t *pg_entry = queue_pop_front(&z->z_free_pages[order]);
vm_page_t *pg = QUEUE_CONTAINER(vm_page_t, p_free_list, pg_entry);
vm_page_t *a, *b;
vm_page_split(pg, &a, &b);
queue_push_back(&z->z_free_pages[order - 1], &a->p_free_list);
queue_push_back(&z->z_free_pages[order - 1], &b->p_free_list);
}
/* handle the last order separately. if the requested order is 0 (4K)
handling it within the for-loop would cause an underflow */
queue_entry_t *pg_entry = queue_pop_front(&z->z_free_pages[order + 1]);
vm_page_t *pg = QUEUE_CONTAINER(vm_page_t, p_free_list, pg_entry);
vm_page_t *a, *b;
vm_page_split(pg, &a, &b);
queue_push_back(&z->z_free_pages[order - 1], &a->p_free_list);
queue_push_back(&z->z_free_pages[order - 1], &b->p_free_list);
return 0;
}
vm_page_t *vm_zone_alloc_page(vm_zone_t *z, vm_page_order_t order, vm_flags_t flags)
{
int result = replenish_free_page_list(z, order);
if (result != 0) {
return NULL;
}
queue_entry_t *pg_entry = queue_pop_front(&z->z_free_pages[order]);
return QUEUE_CONTAINER(vm_page_t, p_free_list, pg_entry);
}
void vm_zone_free_page(vm_zone_t *z, vm_page_t *pg)
{
}