diff --git a/sandbox/vm/include/socks/vm.h b/sandbox/vm/include/socks/vm.h index 15ee0c6..1d71236 100644 --- a/sandbox/vm/include/socks/vm.h +++ b/sandbox/vm/include/socks/vm.h @@ -6,7 +6,11 @@ #include #include -#define VM_PAGE_SIZE 0x1000 +#define VM_CHECK_ALIGN(p, mask) ((((p) & (mask)) == (p)) ? 1 : 0) +#define VM_PAGE_SIZE 0x1000 +#define VM_PAGE_SHIFT 12 + +typedef phys_addr_t vm_alignment_t; typedef struct vm_object { unsigned int reserved; @@ -39,6 +43,7 @@ typedef enum vm_page_order { VM_PAGE_256M, VM_PAGE_512M, VM_PAGE_1G, + VM_PAGE_MIN_ORDER = VM_PAGE_4K, VM_PAGE_MAX_ORDER = VM_PAGE_1G, } vm_page_order_t; @@ -96,6 +101,10 @@ extern kern_status_t vm_bootstrap(const vm_zone_descriptor_t *zones, size_t nr_z extern void vm_page_init_array(); extern vm_page_t *vm_page_get(phys_addr_t addr); extern size_t vm_page_order_to_bytes(vm_page_order_t order); +extern size_t vm_page_order_to_pages(vm_page_order_t order); +extern vm_alignment_t vm_page_order_to_alignment(vm_page_order_t order); + +extern size_t vm_bytes_to_pages(size_t bytes); extern void vm_zone_init(vm_zone_t *z, const char *name, uintptr_t base, uintptr_t limit); diff --git a/sandbox/vm/vm_page.c b/sandbox/vm/vm_page.c index c78fba4..36f9151 100644 --- a/sandbox/vm/vm_page.c +++ b/sandbox/vm/vm_page.c @@ -85,3 +85,33 @@ size_t vm_page_order_to_bytes(vm_page_order_t order) return page_order_bytes[order]; } + +phys_addr_t vm_page_order_to_pages(vm_page_order_t order) +{ + if (order < 0 || order > VM_PAGE_MAX_ORDER) { + return 0; + } + + return page_order_bytes[order] >> VM_PAGE_SHIFT; +} + +vm_alignment_t vm_page_order_to_alignment(vm_page_order_t order) +{ + if (order < 0 || order > VM_PAGE_MAX_ORDER) { + return 0; + } + + return ~(page_order_bytes[order] - 1); +} + + +size_t vm_bytes_to_pages(size_t bytes) +{ + if (bytes & (VM_PAGE_SIZE-1)) { + bytes &= ~(VM_PAGE_SIZE-1); + bytes += VM_PAGE_SIZE; + } + + bytes >>= VM_PAGE_SHIFT; + return bytes; +} diff --git a/sandbox/vm/vm_zone.c b/sandbox/vm/vm_zone.c index e0c4c42..a116a83 100644 --- a/sandbox/vm/vm_zone.c +++ b/sandbox/vm/vm_zone.c @@ -3,38 +3,88 @@ #include #include #include +#include + +static void convert_region_to_blocks(vm_zone_t *zone, phys_addr_t base, phys_addr_t limit, int reserved) +{ + size_t block_frames = vm_bytes_to_pages(limit - base); + printf("adding region %08zx-%08zx (%zu frames) to zone %s\n", base, limit, block_frames, zone->z_name); + int reset_order = 0; + + for (int order = VM_PAGE_MAX_ORDER; order >= VM_PAGE_MIN_ORDER; ) { + size_t order_frames = vm_page_order_to_pages(order); + vm_alignment_t order_alignment = vm_page_order_to_alignment(order); + + if (order_frames > block_frames) { + order--; + continue; + } + + if (!VM_CHECK_ALIGN(base, order_alignment)) { + reset_order = 1; + order--; + continue; + } + + printf("%s: %zu %s pages at %08" PRIxPTR "\n", + zone->z_name, + order_frames, + reserved == 1 ? "reserved" : "free", + base); + + base += order_frames * VM_PAGE_SIZE; + block_frames -= order_frames; + + if (reset_order) { + order = VM_PAGE_MAX_ORDER; + reset_order = 0; + } else { + order--; + } + + if (base > limit) { + printf("too many pages created!\n"); + abort(); + } + + if (base == limit) { + break; + } + } +} void vm_zone_init(vm_zone_t *z, const char *name, uintptr_t base, uintptr_t limit) { + printf("initialising zone %s (%08zx-%08zx)\n", name, base, limit); memset(z, 0x0, sizeof *z); z->z_name = name; - phys_addr_t block_start = 0; - int last_page_reserved = -1; + phys_addr_t block_start = base, block_end = base; + int this_page_reserved = 0, last_page_reserved = -1; for (uintptr_t i = base; i < limit; i += VM_PAGE_SIZE) { vm_page_t *pg = vm_page_get(i); if (!pg) { break; } - int this_page_reserved = (pg->p_flags & VM_PAGE_RESERVED) ? 1 : 0; + this_page_reserved = (pg->p_flags & VM_PAGE_RESERVED) ? 1 : 0; if (last_page_reserved == -1) { last_page_reserved = this_page_reserved; } if (this_page_reserved == last_page_reserved) { + block_end = i; continue; } - printf("%s: %zu %s pages at %" PRIxPTR "\n", - name, - (i - block_start) / VM_PAGE_SIZE, - this_page_reserved == 1 ? "reserved" : "free", - block_start); - + convert_region_to_blocks(z, block_start, i, this_page_reserved); + block_start = i; - vm_page_order_t order = VM_PAGE_MAX_ORDER; last_page_reserved = this_page_reserved; } + + if (block_start != block_end) { + convert_region_to_blocks(z, block_start, block_end, this_page_reserved); + } }