|
| 1 | +#include <kernel.h> |
| 2 | + |
| 3 | +typedef struct vmem_heap { |
| 4 | + struct heap h; |
| 5 | + heap physical; |
| 6 | + heap virtual; |
| 7 | +} *vmem_heap; |
| 8 | + |
| 9 | +static void vmem_dealloc(heap h, u64 a, bytes len) |
| 10 | +{ |
| 11 | + bytes pagesize = h->pagesize; |
| 12 | + len = pad(len, pagesize); |
| 13 | + for (u64 v = a; v < a + len; v += pagesize) { |
| 14 | + unmap(v, pagesize); |
| 15 | + } |
| 16 | + vmem_heap vmh = (vmem_heap)h; |
| 17 | + deallocate(vmh->virtual, a, len); |
| 18 | +} |
| 19 | + |
| 20 | +static u64 vmem_alloc(heap h, bytes len) |
| 21 | +{ |
| 22 | + vmem_heap vmh = (vmem_heap)h; |
| 23 | + bytes pagesize = h->pagesize; |
| 24 | + len = pad(len, pagesize); |
| 25 | + u64 v = allocate_u64(vmh->virtual, len); |
| 26 | + if (v != INVALID_PHYSICAL) { |
| 27 | + heap physical = vmh->physical; |
| 28 | + pageflags flags = pageflags_writable(pageflags_memory()); |
| 29 | + u64 virt_offset = 0; |
| 30 | + do { |
| 31 | + u64 phys_len = len - virt_offset; |
| 32 | + u64 p; |
| 33 | + while (true) { |
| 34 | + p = allocate_u64(physical, phys_len); |
| 35 | + if ((p != INVALID_PHYSICAL) || (phys_len == pagesize)) |
| 36 | + break; |
| 37 | + phys_len = pad(phys_len >> 1, pagesize); |
| 38 | + } |
| 39 | + if (p != INVALID_PHYSICAL) { |
| 40 | + map(v + virt_offset, p, phys_len, flags); |
| 41 | + virt_offset += phys_len; |
| 42 | + } else if (phys_len == pagesize) { |
| 43 | + break; |
| 44 | + } |
| 45 | + } while (virt_offset < len); |
| 46 | + if (virt_offset < len) { /* physical memory allocation failed */ |
| 47 | + vmem_dealloc(h, v, virt_offset); |
| 48 | + v = INVALID_PHYSICAL; |
| 49 | + } |
| 50 | + } |
| 51 | + return v; |
| 52 | +} |
| 53 | + |
| 54 | +heap create_vmem_heap(void) |
| 55 | +{ |
| 56 | + kernel_heaps kh = get_kernel_heaps(); |
| 57 | + vmem_heap vmh = allocate(kh->locked, sizeof(*vmh)); |
| 58 | + if (vmh != INVALID_ADDRESS) { |
| 59 | + vmh->h.alloc = vmem_alloc; |
| 60 | + vmh->h.dealloc = vmem_dealloc; |
| 61 | + vmh->h.allocated = 0; |
| 62 | + vmh->h.total = 0; |
| 63 | + vmh->h.management = 0; |
| 64 | + vmh->physical = heap_physical(kh); |
| 65 | + vmh->virtual = &heap_virtual_page(kh)->h; |
| 66 | + vmh->h.pagesize = vmh->physical->pagesize; |
| 67 | + } |
| 68 | + return &vmh->h; |
| 69 | +} |
0 commit comments