neptune/kern/start.c
2026-01-03 20:12:44 +01:00

131 lines
3.9 KiB
C

#include <assert.h>
#include <badrand.h>
#include <banner.h>
#include <buddy.h>
#include <config.h>
#include <endian.h>
#include <freelist.h>
#include <hexdump.h>
#include <memory.h>
#include <panic.h>
#include <proc.h>
#include <riscv.h>
#include <rtc.h>
#include <spinlock.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <uart.h>
#include <util.h>
/**
* Allocate one stack per CPU (hart).
* Each stack is 4096 bytes, aligned to 16 bytes for safety and performance.
* The entry assembly code will calculate the proper stack address for the
* current hart. For more info, read up on stack pointers and see: entry.S
*/
char stack0[4096 * NCPU] __attribute__((aligned(16)));
/* Keep this here and sync on it until we have synchronized printf */
spinlock_t sl = {0};
volatile int hold = 1;
volatile int max_hart = 0;
/* This is where entry.S drops us of. All cores land here */
void start() {
// Do this first
__atomic_fetch_add(&max_hart, 1, __ATOMIC_SEQ_CST);
u64 id = read_mhartid();
// Keep each CPU's hartid in its tp (thread pointer) register, for cpuid().
// This can then be retrieved with r_wp or cpuid(). It is used to index the
// cpus[] array in mycpu(), which in turn holds state for each individual
// cpu (struct Cpu).
write_tp(id);
if (unlikely(id == 0)) {
/* Here we will do a bunch of initialization steps */
sbadrand(rtc_time_read() ^ swap64(rtc_time_read()));
memory_sweep(heap_start, heap_end);
buddy_init(heap_start, heap_end);
spinlock_init(&sl);
/* Set previous privilege to S-mode, this causes mret to enter S-mode trap handler */
unsigned long x = r_mstatus();
x &= ~MSTATUS_MPP_MASK;
x |= MSTATUS_MPP_S;
w_mstatus(x);
/* Delegate all interrupts and exceptions to S-mode */
w_medeleg(~(uint64_t)0x0);
w_mideleg(~(uint64_t)0x0);
w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE);
for (int i = 0; i < banner_len; i++) uart_putc(banner[i]);
__sync_synchronize();
hold = 0;
} else {
while (hold);
}
if (id == 0) {
spin_lock(&sl);
kprintf("Core count: %d\n", max_hart);
if (max_hart == NCPU)
kprintf("All cores up!\n");
else
PANIC("Some cores seem to have been enumerated incorrectly!\n");
{
FreeList fl;
void *mem = buddy_alloc(4096);
fl_init(&fl, (uintptr_t)mem, 4096, sizeof(int));
uint32_t *hello = fl_alloc(&fl);
*hello = UINT32_MAX;
fl_free(&fl, hello);
int a = fl_available(&fl);
assert_msg(fl_check(&fl) > 0, "FreeList checking failed, might be corrupt.");
kprintf("Freelist available: %d\n", a);
kprintf("Freelist item size: %d\n", fl.size);
buddy_free(mem);
}
{
const uint64_t time = rtc_time_read();
/* Set alarm and check that its correct */
rtc_alarm_set(time + MS_TO_NS(1000));
const uint64_t alrm = rtc_alarm_read();
assert(alrm == time + MS_TO_NS(1000));
/* Should be one provided alarm is not elapsed */
assert(rtc_alarm_status() == 1);
rtc_alarm_clear();
assert(rtc_alarm_status() == 0);
/* Time should have passed */
assert(time != rtc_time_read());
}
{
uint64_t rn = badrand();
assert(rn != badrand());
}
{
char buffer[128];
memset(buffer, 0, 128);
assert(!looks_random(buffer, 128));
badrand_buf(buffer, 128);
assert(looks_random(buffer, 128));
}
kprintf("To exit qemu, press CTRL+a followed by x\n");
spin_unlock(&sl);
}
// We should not arrive here, but if we do, hang in a while on wfi.
while (1) __asm__ volatile("wfi"); // (Wait For Interrupt)
}