Skip to content
This repository has been archived by the owner on Oct 22, 2022. It is now read-only.

Commit

Permalink
Implement byte-grained allocator and enable Sv39 paging in S-mode
Browse files Browse the repository at this point in the history
  • Loading branch information
DonaldKellett committed Oct 1, 2022
1 parent 36f271a commit 6f8d62b
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 53 deletions.
Binary file added misc/gallery/03-mm/06.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added misc/gallery/03-mm/07.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added misc/gallery/03-mm/08.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 43 additions & 3 deletions src/asm/crt0.s
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,48 @@
.global HEAP_START
HEAP_START: .dword __heap_start

.global HEAP_END
HEAP_END: .dword __heap_end
.global HEAP_SIZE
HEAP_SIZE: .dword __heap_size

.global INIT_START
INIT_START: .dword __init_start

.global INIT_END
INIT_END: .dword __init_end

.global TEXT_START
TEXT_START: .dword __text_start

.global TEXT_END
TEXT_END: .dword __text_end

.global RODATA_START
RODATA_START: .dword __rodata_start

.global RODATA_END
RODATA_END: .dword __rodata_end

.global DATA_START
DATA_START: .dword __data_start

.global DATA_END
DATA_END: .dword __data_end

.global BSS_START
BSS_START: .dword __bss_start

.global BSS_END
BSS_END: .dword __bss_end

.global KERNEL_STACK_START
KERNEL_STACK_START: .dword __kernel_stack_start

.global KERNEL_STACK_END
KERNEL_STACK_END: .dword __kernel_stack_end

.section .data
.global KERNEL_TABLE
KERNEL_TABLE: .dword 0

.section .init, "ax"
.global _start
Expand Down Expand Up @@ -54,7 +94,7 @@ __bss_zero_loop_end:
.option pop

# Initialize stack and frame pointer registers
la sp, __stack_top
la sp, __kernel_stack_end
mv fp, sp

# prepare_s_mode is where we'll continue after kinit
Expand Down
9 changes: 9 additions & 0 deletions src/common/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,12 @@
int toupper(int c) {
return 'a' <= c && c <= 'z' ? c + 'A' - 'a' : c;
}

char *strcpy(char *destination, const char *source) {
if (!destination || !source)
return NULL;
char *tmp = destination;
while (*source)
*tmp++ = *source++;
return destination;
}
3 changes: 3 additions & 0 deletions src/common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
__VA_OPT__(,) __VA_ARGS__);\
})

#define SATP_FROM(mode, asid, ppn) (((size_t)(mode) << 60) | ((size_t)(asid) << 44) | ppn)

int toupper(int);
char *strcpy(char *, const char *);

#endif
152 changes: 111 additions & 41 deletions src/kmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,142 @@
#include "syscon/syscon.h"
#include "common/common.h"
#include "mm/page.h"
#include "mm/sv39.h"
#include "mm/kmem.h"

// Define PLIC and CLINT here for now
// We'll move them into separate header files when we get there
#define PLIC_ADDR 0xc000000
#define CLINT_ADDR 0x2000000

extern const size_t INIT_START;
extern const size_t INIT_END;
extern const size_t TEXT_START;
extern const size_t TEXT_END;
extern const size_t RODATA_START;
extern const size_t RODATA_END;
extern const size_t DATA_START;
extern const size_t DATA_END;
extern const size_t BSS_START;
extern const size_t BSS_END;
extern const size_t KERNEL_STACK_START;
extern const size_t KERNEL_STACK_END;
extern const size_t HEAP_START;
extern const size_t HEAP_SIZE;
extern size_t KERNEL_TABLE;

const char HELLO[] =
"Hello World! This is a dynamically allocated string using the byte-grained allocator.\n";

// Identity map range
// Takes a contiguous allocation of memory and maps it using PAGE_SIZE
// `start` must not exceed `end`
void id_map_range(struct page_table *root, size_t start, size_t end,
uint64_t bits) {
ASSERT(root != NULL, "id_map_range(): root page table cannot be NULL");
ASSERT(start <= end, "id_map_range(): start must not exceed end");
ASSERT(PTE_IS_LEAF(bits),
"id_map_range(): Provided bits must correspond to leaf entry");
size_t memaddr = start & ~(PAGE_SIZE - 1);
size_t num_kb_pages = (align_val(end, PAGE_ORDER) - memaddr) / PAGE_SIZE;
for (size_t i = 0; i < num_kb_pages; ++i) {
map(root, memaddr, memaddr, bits, 0);
memaddr += PAGE_SIZE;
}
}

uint64_t kinit(void) {
// Initialize core subsystems
uart_init(UART_ADDR);
kputs("UART initialized");
kputs("We are in M-mode!");

page_init();
kputs("Page-grained allocator initialized");
kmem_init();
kputs("Byte-grained allocator initialized");

kputs("Exiting M-mode\n");
return 0;
}
// Map heap allocations
struct page_table *root = kmem_get_page_table();
size_t kheap_head = (size_t)kmem_get_head();
size_t total_pages = kmem_get_num_allocations();
kprintf("\n\n");
kprintf("INIT: [%p, %p)\n", INIT_START, INIT_END);
kprintf("TEXT: [%p, %p)\n", TEXT_START, TEXT_END);
kprintf("RODATA: [%p, %p)\n", RODATA_START, RODATA_END);
kprintf("DATA: [%p, %p)\n", DATA_START, DATA_END);
kprintf("BSS: [%p, %p)\n", BSS_START, BSS_END);
kprintf("HEAP: [%p, %p)\n", kheap_head, kheap_head + total_pages * PAGE_SIZE);
kprintf("STACK: [%p, %p)\n", KERNEL_STACK_START, KERNEL_STACK_END);
id_map_range(root, kheap_head, kheap_head + total_pages * PAGE_SIZE, PTE_RW);

void kmain(void) {
kputs("We are in S-mode!");
// Map heap descriptors
size_t num_pages = get_num_pages();
id_map_range(root, HEAP_START, HEAP_START + num_pages, PTE_RW);

print_page_allocations();
// Map init section
id_map_range(root, INIT_START, INIT_END, PTE_RX);

void *p1 = alloc_pages(7);
kputs("Allocated 7 pages to p1");
void *p2 = alloc_page();
kputs("Allocated 1 page to p2");
void *p3 = alloc_pages(2);
kputs("Allocated 2 pages to p3");
void *p4 = alloc_pages(9);
kputs("Allocated 9 pages to p4");
void *p5 = alloc_page();
kputs("Allocated 1 page to p5");
// Map executable section
id_map_range(root, TEXT_START, TEXT_END, PTE_RX);

print_page_allocations();
// Map rodata section
id_map_range(root, RODATA_START, RODATA_END, PTE_READ);

dealloc_pages(p3);
kputs("Deallocated p3");
// Map data section
id_map_range(root, DATA_START, DATA_END, PTE_RW);

print_page_allocations();
// Map bss section
id_map_range(root, BSS_START, BSS_END, PTE_RW);

p3 = alloc_page();
kputs("Allocated 1 page to p3");
void *p6 = alloc_page();
kputs("Allocated 1 page to p6");
// Map kernel stack
id_map_range(root, KERNEL_STACK_START, KERNEL_STACK_END, PTE_RW);

print_page_allocations();
// Map UART
map(root, UART_ADDR, UART_ADDR, PTE_RW, 0);

dealloc_pages(p4);
kputs("Deallocated p4");
// Map syscon registers
map(root, SYSCON_ADDR, SYSCON_ADDR, PTE_RW, 0);

print_page_allocations();
// Map PLIC
id_map_range(root, PLIC_ADDR, PLIC_ADDR + 0x2000, PTE_RW);
id_map_range(root, PLIC_ADDR + 0x200000, PLIC_ADDR + 0x208000, PTE_RW);

dealloc_pages(p5);
kputs("Deallocated p5");
// Map CLINT
map(root, CLINT_ADDR, CLINT_ADDR, PTE_RW, 0);

print_page_allocations();

dealloc_pages(p1);
kputs("Deallocated p1");
// Let's see Sv39 address translation in action
size_t vaddr = INIT_START;
size_t paddr = virt_to_phys(root, vaddr);
ASSERT(paddr != 0x0,
"kinit(): Failed to map INIT_START physical address to INIT_START physical address");
kprintf("vaddr = %p maps to paddr = %p\n", vaddr, paddr);

print_page_allocations();
// Store the kernel table
KERNEL_TABLE = (size_t)root;

dealloc_pages(p2);
kputs("Deallocated p2");
dealloc_pages(p3);
kputs("Deallocated p3");
dealloc_pages(p6);
kputs("Deallocated p6");
kputs("Exiting M-mode\n");
return SATP_FROM(MODE_SV39, 0, ((size_t)root) >> PAGE_ORDER);
}

print_page_allocations();
void kmain(void) {
kputs("We are in S-mode!");
kputchar('\n');

char *hello = kcalloc(1 + sizeof(HELLO), sizeof(char));
strcpy(hello, HELLO);
kprintf("%s\n", hello);
kfree(hello);

int *one_to_five = kmalloc(5 * sizeof(int));
for (int i = 0; i < 5; ++i)
one_to_five[i] = i + 1;
for (int i = 0; i < 5; ++i)
kprintf("%d\n", one_to_five[i]);
kfree(one_to_five);

kprintf("Goodbye!\n");

poweroff();
}
21 changes: 16 additions & 5 deletions src/lds/riscv64-virt.ld
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,35 @@ SECTIONS {
* This mean there's a chance stack and heap collide, but we'll assume
* it never happens
*/
.text : ALIGN(4K) {
.init : ALIGN(4K) {
PROVIDE(__init_start = .);
*(.init);
PROVIDE(__init_end = .);
}
.text : ALIGN(4K) {
PROVIDE(__text_start = .);
*(.text);
PROVIDE(__text_end = .);
}
.rodata : ALIGN(4K) {
PROVIDE(__rodata_start = .);
*(.rodata);
PROVIDE(__rodata_end = .);
}
.data : ALIGN(4K) {
PROVIDE(__data_start = .);
*(.data);
PROVIDE(__data_end = .);
}
.bss : ALIGN(4K) {
PROVIDE(__bss_start = .);
*(.bss);
PROVIDE(__bss_end = .);
PROVIDE(__global_pointer = .);
PROVIDE(__heap_start = .);
}
PROVIDE(__global_pointer = .);
PROVIDE(__heap_start = .);
. = 0x88000000;
PROVIDE(__heap_end = .);
PROVIDE(__stack_top = .);
PROVIDE(__kernel_stack_start = . - 0x80000);
PROVIDE(__kernel_stack_end = .);
PROVIDE(__heap_size = __kernel_stack_start - __heap_start);
}
11 changes: 7 additions & 4 deletions src/mm/page.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
#include "../common/common.h"
#include "../uart/uart.h"

extern size_t HEAP_START;
extern size_t HEAP_END;
extern const size_t HEAP_START;
extern const size_t HEAP_SIZE;
extern const size_t HEAP_END;

static size_t HEAP_BOTTOM = 0;
static size_t HEAP_SIZE = 0;
static size_t NUM_PAGES = 0;
static size_t ALLOC_START = 0;
static size_t ALLOC_END = 0;

size_t get_num_pages(void) {
return NUM_PAGES;
}

// Align pointer to nearest 2^order bytes, rounded up
size_t align_val(size_t val, size_t order) {
size_t o = (1ull << order) - 1;
Expand All @@ -26,7 +30,6 @@ static size_t page_address_from_id(size_t id) {
// Initialize the heap for page allocation
void page_init(void) {
HEAP_BOTTOM = HEAP_START;
HEAP_SIZE = HEAP_END - HEAP_START;
NUM_PAGES = HEAP_SIZE / PAGE_SIZE;
struct page *ptr = (struct page *)HEAP_BOTTOM;
// Explicitly mark all pages as free
Expand Down
2 changes: 2 additions & 0 deletions src/mm/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ struct page {
uint8_t flags;
};

size_t get_num_pages(void);

size_t align_val(size_t, size_t);

void page_init(void);
Expand Down
3 changes: 3 additions & 0 deletions src/mm/sv39.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#include <stdint.h>

// MODE=8 encodes Sv39 paging in SATP register
#define MODE_SV39 8

// Page table entry (PTE) bits
#define PTE_NONE 0
#define PTE_VALID (1 << 0)
Expand Down

0 comments on commit 6f8d62b

Please sign in to comment.