Squash commits for public release

This commit is contained in:
2025-02-12 09:54:05 -05:00
commit 7118adc514
1108 changed files with 80873 additions and 0 deletions

View 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;
}

View 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

View 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

View 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
View 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));
}

View 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