Squash commits for public release
This commit is contained in:
24
boot/riscv64/prekernel/drivers/uart.c
Normal file
24
boot/riscv64/prekernel/drivers/uart.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "uart.h"
|
||||
|
||||
volatile uint32_t* output = NULL;
|
||||
|
||||
#define UART 0x10000000
|
||||
#define UART_THR (char*)(UART + 0x00) // THR:transmitter holding register
|
||||
#define UART_LSR (char*)(UART + 0x05) // LSR:line status register
|
||||
#define UART_LSR_EMPTY_MASK 0x40 // LSR Bit 6: Transmitter empty; both the THR and LSR are empty
|
||||
|
||||
void uart_init()
|
||||
{
|
||||
output = (uint32_t*)UART;
|
||||
}
|
||||
|
||||
int uart_write(uint8_t data)
|
||||
{
|
||||
if (!output) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while ((*UART_LSR & UART_LSR_EMPTY_MASK) == 0) { }
|
||||
*output = data;
|
||||
return 0;
|
||||
}
|
||||
9
boot/riscv64/prekernel/drivers/uart.h
Normal file
9
boot/riscv64/prekernel/drivers/uart.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef _BOOT_DRIVERS_UART_H
|
||||
#define _BOOT_DRIVERS_UART_H
|
||||
|
||||
#include <libboot/types.h>
|
||||
|
||||
void uart_init();
|
||||
int uart_write(uint8_t data);
|
||||
|
||||
#endif // _BOOT_DRIVERS_UART_H
|
||||
100
boot/riscv64/prekernel/entry.S
Normal file
100
boot/riscv64/prekernel/entry.S
Normal file
@@ -0,0 +1,100 @@
|
||||
.extern main
|
||||
.extern main_s_mode
|
||||
|
||||
.section ".xos_boot_text", "xa"
|
||||
prekernel_header:
|
||||
auipc a0, 0
|
||||
la a1, PREKERNEL_STACK_TOP_OFFSET
|
||||
mv sp, a1
|
||||
j main
|
||||
|
||||
.global enable_mmu
|
||||
enable_mmu:
|
||||
fence rw, rw
|
||||
csrw satp, a0
|
||||
csrs sstatus, a1
|
||||
sfence.vma
|
||||
ret
|
||||
|
||||
.global jump_to_kernel
|
||||
jump_to_kernel:
|
||||
fence rw, rw
|
||||
sfence.vma
|
||||
jr a1
|
||||
loop:
|
||||
j loop
|
||||
|
||||
.align 4
|
||||
timervec:
|
||||
csrrw a0, mscratch, a0
|
||||
sd a1, 0(a0)
|
||||
sd a2, 8(a0)
|
||||
sd a3, 16(a0)
|
||||
|
||||
ld a1, 24(a0)
|
||||
ld a2, 32(a0)
|
||||
ld a3, 0(a1)
|
||||
add a3, a3, a2
|
||||
sd a3, 0(a1)
|
||||
|
||||
li a1, 2
|
||||
csrw sip, a1
|
||||
|
||||
ld a3, 16(a0)
|
||||
ld a2, 8(a0)
|
||||
ld a1, 0(a0)
|
||||
csrrw a0, mscratch, a0
|
||||
|
||||
mret
|
||||
|
||||
.global setup_timer_m_mode
|
||||
setup_timer_m_mode:
|
||||
csrw mscratch, a0
|
||||
la t0, timervec
|
||||
csrw mtvec, t0
|
||||
|
||||
csrr t0, mstatus // Add flag MSTATUS_MIE | MSTATUS_SUM
|
||||
li t1, (1 << 3) | (1 << 18)
|
||||
or t0, t0, t1
|
||||
csrw mstatus, t0
|
||||
|
||||
csrr t0, mie // Add flag MIE_MTIE
|
||||
li t1, (1 << 7)
|
||||
or t0, t0, t1
|
||||
csrw mie, t0
|
||||
|
||||
ret
|
||||
|
||||
.global jump_to_s_mode
|
||||
jump_to_s_mode:
|
||||
csrr t0, mstatus
|
||||
li t1, 3 << 11
|
||||
and t0, t0, t1
|
||||
li t1, 1 << 11
|
||||
or t0, t0, t1
|
||||
csrw mstatus, t0
|
||||
|
||||
la t1, sv_main
|
||||
csrw mepc, t1
|
||||
|
||||
csrw satp, zero
|
||||
|
||||
li t1, 0xffff
|
||||
csrw medeleg, t1
|
||||
csrw mideleg, t1
|
||||
|
||||
li t1, (1 << 1) | (1 << 5) | (1 << 9)
|
||||
csrr t0, sie
|
||||
or t0, t0, t1
|
||||
csrw sie, t0
|
||||
|
||||
li t1, 0x3fffffffffffff
|
||||
csrw pmpaddr0, t1
|
||||
|
||||
li t1, 0xf
|
||||
csrw pmpcfg0, t1
|
||||
|
||||
mret
|
||||
|
||||
sv_main:
|
||||
j main_s_mode
|
||||
185
boot/riscv64/prekernel/main.c
Normal file
185
boot/riscv64/prekernel/main.c
Normal file
@@ -0,0 +1,185 @@
|
||||
#include "drivers/uart.h"
|
||||
#include "vm.h"
|
||||
#include <libboot/abi/memory.h>
|
||||
#include <libboot/devtree/devtree.h>
|
||||
#include <libboot/elf/elf_lite.h>
|
||||
#include <libboot/log/log.h>
|
||||
#include <libboot/mem/alloc.h>
|
||||
#include <libboot/mem/mem.h>
|
||||
|
||||
#define DEBUG_BOOT
|
||||
#define EARLY_FB
|
||||
|
||||
extern uint32_t EMBED_DEVTREE_START[];
|
||||
extern uint32_t EMBED_DEVTREE_END[];
|
||||
|
||||
extern void jump_to_s_mode(uintptr_t);
|
||||
extern void jump_to_kernel(void*, uintptr_t);
|
||||
static void* bootdesc_paddr;
|
||||
static void* bootdesc_vaddr;
|
||||
static size_t kernel_vaddr = 0;
|
||||
static size_t kernel_paddr = 0;
|
||||
static size_t kernel_size = 0;
|
||||
|
||||
#define LAUNCH_SERVER_PATH "/System/launch_server"
|
||||
|
||||
static int alloc_init()
|
||||
{
|
||||
devtree_entry_t* dev = devtree_find_device("ram");
|
||||
if (!dev) {
|
||||
log("Can't find RAM in devtree");
|
||||
while (1) { };
|
||||
}
|
||||
|
||||
extern uint32_t RAWIMAGE_END[];
|
||||
uintptr_t start_addr = ROUND_CEIL((uint64_t)RAWIMAGE_END, page_size());
|
||||
size_t free_space = dev->region_size - (start_addr - dev->region_base);
|
||||
malloc_init((void*)start_addr, free_space);
|
||||
|
||||
#ifdef DEBUG_BOOT
|
||||
log("malloc inited %llx %llx", start_addr, free_space);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t memory_layout_size()
|
||||
{
|
||||
return 0 + 1; // Including the trailing element.
|
||||
}
|
||||
|
||||
static int preserve_alloc_init(size_t kernsize)
|
||||
{
|
||||
const size_t devtreesize = ROUND_CEIL(devtree_size(), page_size());
|
||||
const size_t memmap = ROUND_CEIL(memory_layout_size() * sizeof(memory_layout_t), page_size());
|
||||
const size_t bootargsstruct = ROUND_CEIL(sizeof(boot_args_t), page_size());
|
||||
const size_t bootargssize = devtreesize + memmap + bootargsstruct;
|
||||
|
||||
// 32 tables should be enough for initial mappings.
|
||||
const size_t prekernelvmsize = 32 * page_size();
|
||||
const size_t total = ROUND_CEIL(kernsize + bootargssize + prekernelvmsize, page_size());
|
||||
|
||||
return palloc_init(total, 2 << 20);
|
||||
}
|
||||
|
||||
static memory_boot_desc_t memory_boot_desc_init()
|
||||
{
|
||||
devtree_entry_t* dev = devtree_find_device("ram");
|
||||
if (!dev) {
|
||||
#ifdef EARLY_FB
|
||||
log("Can't find RAM in devtree");
|
||||
#endif
|
||||
while (1) { };
|
||||
}
|
||||
|
||||
memory_boot_desc_t res;
|
||||
const size_t memlayout_size = memory_layout_size();
|
||||
memory_layout_t* mem_layout_paddr = palloc_aligned(memlayout_size * sizeof(memory_layout_t), page_size());
|
||||
|
||||
// Init of trailing element.
|
||||
mem_layout_paddr[memlayout_size - 1].flags = MEMORY_LAYOUT_FLAG_TERMINATE;
|
||||
memory_layout_t* mem_layout_vaddr = paddr_to_vaddr(mem_layout_paddr, kernel_paddr, kernel_vaddr);
|
||||
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
|
||||
log("initing MEMLAYOUT %lx of %d elems", mem_layout_vaddr, memlayout_size);
|
||||
#endif
|
||||
|
||||
res.ram_base = dev->region_base;
|
||||
res.ram_size = dev->region_size;
|
||||
res.reserved_areas = mem_layout_vaddr;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void load_kernel(void* kenrelstart)
|
||||
{
|
||||
kernel_size = elf_get_kernel_size(kenrelstart);
|
||||
kernel_size = ROUND_CEIL(kernel_size, page_size());
|
||||
|
||||
int err = preserve_alloc_init(kernel_size);
|
||||
if (err) {
|
||||
#ifdef EARLY_FB
|
||||
log("add assert");
|
||||
#endif
|
||||
while (1) { }
|
||||
}
|
||||
|
||||
int res = elf_load_kernel(kenrelstart, kernel_size, &kernel_vaddr, &kernel_paddr);
|
||||
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
|
||||
log("kernel %lx %lx %lx", kernel_vaddr, kernel_paddr, kernel_size);
|
||||
#endif
|
||||
|
||||
void* odt_paddr = palloc_aligned(devtree_size(), page_size());
|
||||
memcpy(odt_paddr, devtree_start(), devtree_size());
|
||||
void* odt_vaddr = paddr_to_vaddr(odt_paddr, kernel_paddr, kernel_vaddr);
|
||||
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
|
||||
log("copying ODT %lx -> %lx of %d", devtree_start(), odt_vaddr, devtree_size());
|
||||
#endif
|
||||
|
||||
boot_args_t boot_args;
|
||||
boot_args.vaddr = kernel_vaddr;
|
||||
boot_args.paddr = kernel_paddr;
|
||||
boot_args.kernel_data_size = 0x0; // Sets up later
|
||||
boot_args.mem_boot_desc = memory_boot_desc_init();
|
||||
boot_args.devtree = odt_vaddr;
|
||||
boot_args.fb_boot_desc.vaddr = 0; // Marking fb as invalid.
|
||||
memcpy(boot_args.init_process, LAUNCH_SERVER_PATH, sizeof(LAUNCH_SERVER_PATH));
|
||||
|
||||
bootdesc_paddr = palloc_aligned(sizeof(boot_args), page_size());
|
||||
memcpy(bootdesc_paddr, &boot_args, sizeof(boot_args));
|
||||
bootdesc_vaddr = paddr_to_vaddr(bootdesc_paddr, kernel_paddr, kernel_vaddr);
|
||||
#if defined(DEBUG_BOOT) && defined(EARLY_FB)
|
||||
log("copying BOOTDESC %lx -> %lx of %d", &boot_args, bootdesc_vaddr, sizeof(boot_args));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int enable_timer()
|
||||
{
|
||||
devtree_entry_t* dev = devtree_find_device("rv64timer");
|
||||
if (!dev) {
|
||||
log("Can't find timer in devtree");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct timer_scratch_mem {
|
||||
uint64_t entries[5];
|
||||
};
|
||||
struct timer_scratch_mem* scratch = palloc_aligned(sizeof(struct timer_scratch_mem), page_size());
|
||||
|
||||
size_t hartid = 0;
|
||||
volatile uint64_t* mtime = (uint64_t*)(dev->region_base + 0xBFF8);
|
||||
volatile uint64_t* mtimecmp = (uint64_t*)(dev->region_base + 0x4000 + 8 * hartid);
|
||||
|
||||
size_t interval = 10000000 / 125;
|
||||
*mtimecmp = *mtime + interval;
|
||||
scratch->entries[3] = (uint64_t)mtimecmp;
|
||||
scratch->entries[4] = interval;
|
||||
|
||||
extern void setup_timer_m_mode(void*);
|
||||
setup_timer_m_mode(scratch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void main(uintptr_t base)
|
||||
{
|
||||
devtree_init((void*)EMBED_DEVTREE_START, (uint64_t)EMBED_DEVTREE_END - (uint64_t)EMBED_DEVTREE_START);
|
||||
uart_init();
|
||||
log_init(uart_write);
|
||||
alloc_init();
|
||||
|
||||
extern uint32_t EMBED_KERNEL_START[];
|
||||
load_kernel((void*)(EMBED_KERNEL_START));
|
||||
|
||||
enable_timer();
|
||||
jump_to_s_mode(base);
|
||||
}
|
||||
|
||||
int main_s_mode(uintptr_t base)
|
||||
{
|
||||
vm_setup(base, bootdesc_paddr);
|
||||
|
||||
#ifdef DEBUG_BOOT
|
||||
log("Preboot done: booting to OS@%llx", ((boot_args_t*)bootdesc_vaddr)->vaddr);
|
||||
#endif
|
||||
|
||||
((boot_args_t*)bootdesc_vaddr)->kernel_data_size = ROUND_CEIL(palloc_used_size(), page_size());
|
||||
jump_to_kernel((void*)bootdesc_vaddr, ((boot_args_t*)bootdesc_vaddr)->vaddr);
|
||||
return 0;
|
||||
}
|
||||
141
boot/riscv64/prekernel/vm.c
Normal file
141
boot/riscv64/prekernel/vm.c
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "vm.h"
|
||||
#include <libboot/abi/kernel.h>
|
||||
#include <libboot/abi/rawimage.h>
|
||||
#include <libboot/devtree/devtree.h>
|
||||
#include <libboot/log/log.h>
|
||||
#include <libboot/mem/alloc.h>
|
||||
#include <libboot/mem/mem.h>
|
||||
|
||||
#define DEBUG_VM
|
||||
|
||||
static uint64_t* global_page_table;
|
||||
static const uint64_t kernel_base = 0xffff800000000000;
|
||||
|
||||
static uint64_t* new_ptable(boot_args_t* args)
|
||||
{
|
||||
uint64_t* res = (uint64_t*)palloc_aligned(page_size(), page_size());
|
||||
memset(res, 0, page_size());
|
||||
#ifdef DEBUG_VM
|
||||
log(" alloc ptable %llx %llx", (uint64_t)res, page_size());
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
static void map4kb_2mb(boot_args_t* args, size_t phyz, size_t virt)
|
||||
{
|
||||
const size_t page_covers = (1ull << PTABLE_LV1_VADDR_OFFSET);
|
||||
const size_t page_mask = page_covers - 1;
|
||||
|
||||
if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Mapping from level3.
|
||||
uint64_t* page_table = global_page_table;
|
||||
uint64_t ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)];
|
||||
if (ptable_desc == 0) {
|
||||
uint64_t* nptbl = new_ptable(args);
|
||||
uint64_t pdesc = 0x00000000000001; // v bit is set
|
||||
pdesc |= ((uintptr_t)nptbl >> 2);
|
||||
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)] = pdesc;
|
||||
ptable_desc = pdesc;
|
||||
}
|
||||
|
||||
// Level2
|
||||
page_table = (uint64_t*)(((ptable_desc >> 10) << 12) & 0xffffffffffff);
|
||||
ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)];
|
||||
if (ptable_desc == 0) {
|
||||
uint64_t* nptbl = new_ptable(args);
|
||||
uint64_t pdesc = 0x00000000000001; // v bit is set
|
||||
pdesc |= ((uintptr_t)nptbl >> 2);
|
||||
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc;
|
||||
ptable_desc = pdesc;
|
||||
}
|
||||
|
||||
page_table = (uint64_t*)(((ptable_desc >> 10) << 12) & 0xffffffffffff);
|
||||
uint64_t pdesc = 0x0000000000000f; // w + v + x + r bits are set.
|
||||
pdesc |= ((uintptr_t)phyz >> 2);
|
||||
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV1_VADDR_OFFSET, VMM_LV1_ENTITY_COUNT)] = pdesc;
|
||||
}
|
||||
|
||||
static void map4kb_1gb(boot_args_t* args, size_t phyz, size_t virt)
|
||||
{
|
||||
const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET);
|
||||
const size_t page_mask = page_covers - 1;
|
||||
|
||||
if ((phyz & page_mask) != 0 || (virt & page_mask) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Mapping from level3.
|
||||
uint64_t* page_table = global_page_table;
|
||||
uint64_t ptable_desc = page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)];
|
||||
if (ptable_desc == 0) {
|
||||
uint64_t* nptbl = new_ptable(args);
|
||||
uint64_t pdesc = 0x00000000000001; // v bit is set
|
||||
pdesc |= ((uintptr_t)nptbl >> 2);
|
||||
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV3_VADDR_OFFSET, VMM_LV3_ENTITY_COUNT)] = pdesc;
|
||||
ptable_desc = pdesc;
|
||||
}
|
||||
|
||||
page_table = (uint64_t*)(((ptable_desc >> 10) << 12) & 0xffffffffffff);
|
||||
uint64_t pdesc = 0x0000000000000f; // w + v + x + r bits are set.
|
||||
pdesc |= ((uintptr_t)phyz >> 2);
|
||||
page_table[VM_VADDR_OFFSET_AT_LEVEL(virt, PTABLE_LV2_VADDR_OFFSET, VMM_LV2_ENTITY_COUNT)] = pdesc;
|
||||
}
|
||||
|
||||
static void map_uart(boot_args_t* args)
|
||||
{
|
||||
devtree_entry_t* dev = devtree_find_device("uart");
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t paddr = dev->region_base;
|
||||
const size_t page_covers = (1ull << PTABLE_LV2_VADDR_OFFSET);
|
||||
paddr &= ~(page_covers - 1);
|
||||
|
||||
#ifdef DEBUG_VM
|
||||
log("mapping %lx %lx", paddr, paddr);
|
||||
#endif
|
||||
map4kb_1gb(args, paddr, paddr);
|
||||
}
|
||||
|
||||
void vm_setup(uintptr_t base, boot_args_t* args)
|
||||
{
|
||||
global_page_table = (uint64_t*)palloc_aligned(page_size(), page_size());
|
||||
memset(global_page_table, 0, page_size());
|
||||
|
||||
const size_t map_range_2mb = (2 << 20);
|
||||
const size_t map_range_1gb = (1 << 30);
|
||||
|
||||
// Mapping kernel vaddr to paddr
|
||||
size_t kernel_size_to_map = palloc_total_size() + shadow_area_size();
|
||||
size_t kernel_range_count_to_map = (kernel_size_to_map + (map_range_2mb - 1)) / map_range_2mb;
|
||||
for (size_t i = 0; i < kernel_range_count_to_map; i++) {
|
||||
#ifdef DEBUG_VM
|
||||
log("mapping %lx %lx", args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb);
|
||||
#endif
|
||||
map4kb_2mb(args, args->paddr + i * map_range_2mb, args->vaddr + i * map_range_2mb);
|
||||
}
|
||||
|
||||
// Mapping RAM
|
||||
size_t ram_base = ROUND_FLOOR(args->mem_boot_desc.ram_base, map_range_1gb);
|
||||
size_t ram_size = args->mem_boot_desc.ram_size;
|
||||
size_t ram_range_count_to_map = (ram_size + (map_range_1gb - 1)) / map_range_1gb;
|
||||
for (size_t i = 0; i < ram_range_count_to_map; i++) {
|
||||
#ifdef DEBUG_VM
|
||||
log("mapping %lx %lx", ram_base + i * map_range_1gb, ram_base + i * map_range_1gb);
|
||||
#endif
|
||||
map4kb_1gb(args, ram_base + i * map_range_1gb, ram_base + i * map_range_1gb);
|
||||
}
|
||||
|
||||
map_uart(args);
|
||||
|
||||
#ifdef DEBUG_VM
|
||||
log("Complete tables setup");
|
||||
#endif
|
||||
|
||||
extern void enable_mmu(uintptr_t, uintptr_t);
|
||||
enable_mmu((uintptr_t)(9ull << 60) | (((uintptr_t)global_page_table >> 12) & 0xffffffffff), (1 << 18));
|
||||
}
|
||||
24
boot/riscv64/prekernel/vm.h
Normal file
24
boot/riscv64/prekernel/vm.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef _BOOT_VM_H
|
||||
#define _BOOT_VM_H
|
||||
|
||||
#include <libboot/abi/memory.h>
|
||||
#include <libboot/types.h>
|
||||
|
||||
#define VMM_LV0_ENTITY_COUNT (512)
|
||||
#define VMM_LV1_ENTITY_COUNT (512)
|
||||
#define VMM_LV2_ENTITY_COUNT (512)
|
||||
#define VMM_LV3_ENTITY_COUNT (512)
|
||||
|
||||
#define PTABLE_LV_TOP (3)
|
||||
#define PTABLE_LV0_VADDR_OFFSET (12)
|
||||
#define PTABLE_LV1_VADDR_OFFSET (21)
|
||||
#define PTABLE_LV2_VADDR_OFFSET (30)
|
||||
#define PTABLE_LV3_VADDR_OFFSET (39)
|
||||
|
||||
#define VM_VADDR_OFFSET_AT_LEVEL(vaddr, off, ent) ((vaddr >> off) % ent)
|
||||
|
||||
static size_t page_size() { return 0x1000; }
|
||||
|
||||
void vm_setup(uintptr_t base, boot_args_t* args);
|
||||
|
||||
#endif // _BOOT_VM_H
|
||||
Reference in New Issue
Block a user