AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1#include "hv/allocator.h"
2#include "hv/config.h"
3#include "hv/panic.h"
4#include "hv/string.h"
5#include "hv/uart.h"
6
7#define MAX_ALLOC_PAGES 1024u
8
9static paddr_t g_base;
10static uint64_t g_size;
11static uint8_t g_used[MAX_ALLOC_PAGES];
12static uint64_t g_pages;
13
14void allocator_init(paddr_t base, uint64_t size)
15{
16 BUG_ON(!hv_is_aligned_u64(base, CONFIG_PAGE_SIZE));
17 BUG_ON(!hv_is_aligned_u64(size, CONFIG_PAGE_SIZE));
18 g_base = base;
19 g_size = size;
20 g_pages = size / CONFIG_PAGE_SIZE;
21 BUG_ON(g_pages > MAX_ALLOC_PAGES);
22 hv_memset(g_used, 0, sizeof(g_used));
23}
24
25void *alloc_page(void)
26{
27 for (uint64_t i = 0; i < g_pages; i++) {
28 if (g_used[i] == 0u) {
29 g_used[i] = 1u;
30 return (void *)(uintptr_t)(g_base + (i * CONFIG_PAGE_SIZE));
31 }
32 }
33 return (void *)0;
34}
35
36bool allocator_owns(paddr_t addr, uint64_t size)
37{
38 uint64_t end;
39 uint64_t alloc_end;
40 if (hv_add_overflow_u64(addr, size, &end) ||
41 hv_add_overflow_u64(g_base, g_size, &alloc_end)) {
42 return false;
43 }
44 return addr >= g_base && end <= alloc_end;
45}
46
47bool allocator_selftest(void)
48{
49 if (!hv_is_aligned_u64(g_base, CONFIG_PAGE_SIZE) || g_pages == 0u) {
50 return false;
51 }
52 uint64_t free_count = 0;
53 for (uint64_t i = 0; i < g_pages; i++) {
54 if (g_used[i] == 0u) {
55 free_count++;
56 }
57 }
58 return free_count != 0u && allocator_owns(g_base, CONFIG_PAGE_SIZE);
59}
60
61void allocator_dump(void)
62{
63 uint64_t used = 0;
64 for (uint64_t i = 0; i < g_pages; i++) {
65 if (g_used[i] != 0u) {
66 used++;
67 }
68 }
69 uart_puts("allocator base=");
70 uart_put_hex64(g_base);
71 uart_puts(" size=");
72 uart_put_hex64(g_size);
73 uart_puts(" pages=");
74 uart_put_dec64(g_pages);
75 uart_puts(" used=");
76 uart_put_dec64(used);
77 uart_puts("\n");
78}