Skip to content

Commit

Permalink
Scheduler and interrupts 2.0, shutdown/reboot (#79)
Browse files Browse the repository at this point in the history
This adds:
- A new scheduler soon capable of running on multiple CPUs
- An interrupts framework update designed to better abstract from specific platforms
- An implementation of shutdown and reboot
    - On ESP32, reboot resets the CPU(s)
    - On ESP32, shutdown enters deep sleep
- Support for asynchronous signals (i.e. sent by other processes)
  • Loading branch information
robotman2412 authored Aug 22, 2024
1 parent efc6012 commit fa3b27f
Show file tree
Hide file tree
Showing 93 changed files with 3,258 additions and 803 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ image:
$(MAKE) -C files build
$(MAKE) -C kernel image

.PHONY: burn
burn:
$(MAKE) -C files build
$(MAKE) -C kernel burn

.PHONY: monitor
monitor:
$(MAKE) -C kernel monitor
Expand Down
14 changes: 14 additions & 0 deletions common/include/attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@
// this file provides convenience macros for the attributes provided by gcc:
// https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html

#ifdef BADGEROS_KERNEL
#include <config.h>
#ifdef CONFIG_TARGET_generic
// Function that must be in RAM for XIP targets.
#define RAMFUNC
#else
// Function that must be in RAM for XIP targets.
#define RAMFUNC __attribute__((section(".ramtext")))
#endif
#endif

// Disable address sanitization for a function.
#define NOASAN __attribute__((no_sanitize("address")))

Expand Down Expand Up @@ -38,3 +49,6 @@

// Function written in assembly.
#define NAKED __attribute__((naked))

// Volatile variables.
#define VOLATILE volatile
4 changes: 2 additions & 2 deletions common/include/sys/wait.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
// Create status for child exited normally.
#define W_EXITED(ret) ((ret) << 8)
// Create status for child exited by signal.
#define W_SIGNALLED(sig) ((sig) | 0x40)
#define W_SIGNALLED(sig) (((sig) << 8) | 0x40)
// Create status for child that was suspended by a signal.
#define W_STOPCODE(sig) ((sig) << 8 | 0x20)
#define W_STOPCODE(sig) (((sig) << 8) | 0x20)
// Child was continued.
#define W_CONTINUED 0x10
// Child dumped core.
Expand Down
76 changes: 5 additions & 71 deletions files/sbin/init/main.c
Original file line number Diff line number Diff line change
@@ -1,34 +1,10 @@

// SPDX-License-Identifier: MIT

#include "hal/i2c.h"
#include "signal.h"
#include "syscall.h"

#define SDA_PIN 6
#define SCL_PIN 7
#define CH32_ADDR 0x42

#define I2C_REG_FW_VERSION_0 0 // LSB
#define I2C_REG_FW_VERSION_1 1 // MSB
#define I2C_REG_RESERVED_0 2
#define I2C_REG_RESERVED_1 3
#define I2C_REG_LED_0 4 // LSB
#define I2C_REG_LED_1 5
#define I2C_REG_LED_2 6
#define I2C_REG_LED_3 7 // MSB
#define I2C_REG_BTN_0 8 // Button 0
#define I2C_REG_BTN_1 9 // Button 1
#define I2C_REG_BTN_2 10 // Button 2
#define I2C_REG_BTN_3 11 // Button 3
#define I2C_REG_BTN_4 12 // Button 4

uint8_t read_reg(uint8_t regno) {
badge_err_t ec = {0};
i2c_master_write_to(&ec, 0, CH32_ADDR, &regno, 1);
uint8_t ret = 0;
i2c_master_read_from(&ec, 0, CH32_ADDR, &ret, 1);
return ret;
}

size_t strlen(char const *cstr) {
char const *pre = cstr;
Expand All @@ -43,53 +19,11 @@ void print(char const *cstr) {
char const hextab[] = "0123456789ABCDEF";

int main() {
badge_err_t ec = {0};
print("Hi, Ther.");
// syscall_sys_shutdown(false);
// return 420;
syscall_proc_sighandler(SIGHUP, SIG_IGN);

// Set up I2C to the CH32V003.
i2c_master_init(&ec, 0, SDA_PIN, SCL_PIN, 100000);
i2c_master_write_to(&ec, 0, CH32_ADDR, "\x00", 1);
i2c_master_write_to(&ec, 0, CH32_ADDR, "\x00", 1);
// uint8_t tmp;
// i2c_master_read_from(&ec, 0, CH32_ADDR, &tmp, 1);
// i2c_master_read_from(&ec, 0, CH32_ADDR, &tmp, 1);
// i2c_master_read_from(&ec, 0, CH32_ADDR, &tmp, 1);
// i2c_master_write_to(&ec, 0, CH32_ADDR, "\x04\xff\xff", 3);
// syscall_sys_shutdown(false);
// return 69;

// Read coproc FW ver.
uint16_t fwv = read_reg(I2C_REG_FW_VERSION_0) | (read_reg(I2C_REG_FW_VERSION_1) << 8);
char buf[4];
buf[0] = hextab[(fwv >> 12) & 15];
buf[1] = hextab[(fwv >> 8) & 15];
buf[2] = hextab[(fwv >> 4) & 15];
buf[3] = hextab[(fwv >> 0) & 15];
print("CH32 version: 0x");
syscall_temp_write(buf, 4);
print("\n");

// Poll inputs until one of the buttons is pressed, then exit.
// while (true) {
if (read_reg(I2C_REG_BTN_0)) {
print("BTN0 triggered\n");
}
if (read_reg(I2C_REG_BTN_1)) {
print("BTN1 triggered\n");
}
if (read_reg(I2C_REG_BTN_2)) {
print("BTN2 triggered\n");
}
if (read_reg(I2C_REG_BTN_3)) {
print("BTN3 triggered\n");
}
if (read_reg(I2C_REG_BTN_4)) {
print("BTN4 triggered\n");
}
// }
badge_err_t ec = {0};
print("Hi, Ther.\n");

syscall_sys_shutdown(false);
syscall_sys_shutdown(true);
return 0;
}
18 changes: 12 additions & 6 deletions kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ set(common_compiler_flags
-march=${target_arch} # Selects the target CPU.
-mabi=${target_abi} # Selects target ABI
-nodefaultlibs # Do not link any default libraries like libgcc or libc.
-O2 # Optimize the code.
-O0 # Optimize the code.
-ggdb # Generate debug information in default extended format.
-Werror=return-type # Error when a function doesn't return a value, but declares to do so.
-Werror=implicit-fallthrough
-Werror=int-conversion
-Wall -Wextra # Ramp up warning level.
-Wno-missing-braces
-std=gnu11 # We use the C11 standard
-DBADGEROS_KERNEL # Tell the code we're building for the kernel
-DBADGEROS_MALLOC_DEBUG_LEVEL=3 # Malloc debug level set to WARN
-DBADGEROS_MALLOC_DEBUG_LEVEL=2 # Malloc debug level set to WARN
-DSOFTBIT # Turn on our emulated bit operations
-fno-omit-frame-pointer # Always use frame pointer
-ffunction-sections
Expand All @@ -45,10 +47,6 @@ if("${CMAKE_BUILD_TYPE}" MATCHES "Release")
message("Building in release mode")
else()
message("Building in debug mode")
set(common_compiler_flags ${common_compiler_flags}
-fsanitize=undefined # Adds sanitizer for undefined behaviour.
-fsanitize-undefined-trap-on-error
)
endif()

# we must pass the same options to GCC and LD when using LTO, as the linker will actually do the codegen
Expand All @@ -70,8 +68,10 @@ add_executable(${target}
${CMAKE_CURRENT_LIST_DIR}/src/badgelib/mutex.c
${CMAKE_CURRENT_LIST_DIR}/src/badgelib/num_to_str.c
${CMAKE_CURRENT_LIST_DIR}/src/badgelib/rawprint.c

${CMAKE_CURRENT_LIST_DIR}/src/blockdevice/blkdev_ram.c
${CMAKE_CURRENT_LIST_DIR}/src/blockdevice/blockdevice.c

${CMAKE_CURRENT_LIST_DIR}/src/filesystem/filesystem.c
${CMAKE_CURRENT_LIST_DIR}/src/filesystem/syscall_impl.c
# ${CMAKE_CURRENT_LIST_DIR}/src/filesystem/vfs_fat.c
Expand All @@ -80,21 +80,26 @@ add_executable(${target}
${CMAKE_CURRENT_LIST_DIR}/src/freestanding/int_routines.c
${CMAKE_CURRENT_LIST_DIR}/src/freestanding/string.c
${CMAKE_CURRENT_LIST_DIR}/src/hal/syscall_impl.c

${CMAKE_CURRENT_LIST_DIR}/src/malloc/malloc.c
${CMAKE_CURRENT_LIST_DIR}/src/malloc/static-buddy.c
${CMAKE_CURRENT_LIST_DIR}/src/malloc/slab-alloc.c

${CMAKE_CURRENT_LIST_DIR}/src/process/kbelfx.c
${CMAKE_CURRENT_LIST_DIR}/src/process/proc_memmap.c
${CMAKE_CURRENT_LIST_DIR}/src/process/process.c
${CMAKE_CURRENT_LIST_DIR}/src/process/sighandler.c
${CMAKE_CURRENT_LIST_DIR}/src/process/syscall_impl.c
${CMAKE_CURRENT_LIST_DIR}/src/process/syscall_util.c

${CMAKE_CURRENT_LIST_DIR}/src/scheduler/scheduler.c
${CMAKE_CURRENT_LIST_DIR}/src/scheduler/syscall_impl.c

${CMAKE_CURRENT_LIST_DIR}/src/housekeeping.c
${CMAKE_CURRENT_LIST_DIR}/src/main.c
${CMAKE_CURRENT_LIST_DIR}/src/page_alloc.c
${CMAKE_CURRENT_LIST_DIR}/src/syscall.c

${cpu_src}
${port_src}
)
Expand All @@ -108,6 +113,7 @@ include_directories(
${cpu_include}
${port_include}
)
include_directories(SYSTEM ${port_system_include})

# Add libraries.
add_subdirectory(../common/badgelib badgelib)
Expand Down
7 changes: 5 additions & 2 deletions kernel/cpu/riscv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ set(cpu_src
${CMAKE_CURRENT_LIST_DIR}/src/scheduler.c
${CMAKE_CURRENT_LIST_DIR}/src/usercopy.c
)
if(DEFINED cpu_multicore)
set(cpu_src ${cpu_src} ${CMAKE_CURRENT_LIST_DIR}/src/cpu1_entrypoint.S)
endif()
if(DEFINED cpu_riscv_enable_riscv_intc)
set(cpu_src ${cpu_src} ${CMAKE_CURRENT_LIST_DIR}/src/interrupt/riscv_intc.c)
endif()
if(DEFINED cpu_riscv_enable_sifive_plic)
set(cpu_src ${cpu_src} ${CMAKE_CURRENT_LIST_DIR}/src/interrupt/sifive_plic.c)
if(DEFINED cpu_riscv_enable_riscv_plic)
set(cpu_src ${cpu_src} ${CMAKE_CURRENT_LIST_DIR}/src/interrupt/riscv_plic.c)
endif()
if(DEFINED cpu_riscv_enable_pmp)
set(cpu_src ${cpu_src} ${CMAKE_CURRENT_LIST_DIR}/src/memprotect/riscv_pmp.c)
Expand Down
34 changes: 24 additions & 10 deletions kernel/cpu/riscv/include/cpu/interrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,34 @@

#include <stdbool.h>

// Globally enable/disable interrupts in this CPU.
// Enable interrupts if a condition is met.
static inline void irq_enable_if(bool enable) {
long mask = enable << CSR_STATUS_IE_BIT;
asm volatile("csrs " CSR_STATUS_STR ", %0" ::"ri"(mask));
}

// Disable interrupts if a condition is met.
static inline void irq_disable_if(bool disable) {
long mask = disable << CSR_STATUS_IE_BIT;
asm volatile("csrc " CSR_STATUS_STR ", %0" ::"ri"(mask));
}

// Enable interrupts.
static inline void irq_enable() {
long mask = 1 << CSR_STATUS_IE_BIT;
asm volatile("csrs " CSR_STATUS_STR ", %0" ::"ri"(mask));
}

// Disable interrupts.
// Returns whether interrupts were enabled.
static inline bool irq_enable(bool enable) {
long mask = CSR_STATUS_PP_MASK << CSR_STATUS_PP_BASE_BIT;
if (enable) {
asm volatile("csrrs %0, " CSR_STATUS_STR ", %0" : "+r"(mask));
} else {
asm volatile("csrrc %0, " CSR_STATUS_STR ", %0" : "+r"(mask));
}
return (mask >> CSR_STATUS_PP_BASE_BIT) & 1;
static inline bool irq_disable() {
long mask = 1 << CSR_STATUS_IE_BIT;
asm volatile("csrrc %0, " CSR_STATUS_STR ", %0" : "+r"(mask));
return (mask >> CSR_STATUS_IE_BIT) & 1;
}

// Query whether interrupts are enabled in this CPU.
static inline bool irq_enabled() {
static inline bool irq_is_enabled() {
long mask;
asm("csrr %0, " CSR_STATUS_STR : "=r"(mask));
return (mask >> CSR_STATUS_PP_BASE_BIT) & 1;
Expand Down
11 changes: 0 additions & 11 deletions kernel/cpu/riscv/include/cpu/isr.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,6 @@ extern void riscv_trap_handler();
// Return a value from the syscall handler.
extern void syscall_return(long long value) __attribute__((noreturn));

// Disable interrupts and return whether they were enabled.
static inline bool isr_global_disable() {
uint32_t status;
asm volatile("csrr %0, " CSR_STATUS_STR : "=r"(status));
asm volatile("csrc " CSR_STATUS_STR ", %0" ::"r"((1U << CSR_STATUS_IE_BIT)));
return status & (1U << CSR_STATUS_IE_BIT);
}
// Enable interrupts.
static inline void isr_global_enable() {
asm volatile("csrs " CSR_STATUS_STR ", %0" ::"r"((1U << CSR_STATUS_IE_BIT)));
}
// Explicit context switch from kernel.
// Interrupts must be disabled on entry and will be re-enabled on exit.
// If the context switch target is not set, this is a NOP.
Expand Down
11 changes: 8 additions & 3 deletions kernel/cpu/riscv/include/cpu/isr_ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,17 @@ static inline isr_ctx_t *isr_ctx_switch_get() {
static inline void isr_ctx_switch_set(isr_ctx_t *switch_to) {
isr_ctx_t *kctx;
asm("csrr %0, " CSR_SCRATCH_STR : "=r"(kctx));
kctx->ctxswitch = switch_to;
switch_to->cpulocal = kctx->cpulocal;
kctx->ctxswitch = switch_to;
}
// Immediately swap the ISR context handle.
static inline isr_ctx_t *isr_ctx_swap(isr_ctx_t *kctx) {
asm("csrrw %0, " CSR_SCRATCH_STR ", %0" : "+r"(kctx));
return kctx;
isr_ctx_t *old;
asm("csrrw %0, " CSR_SCRATCH_STR ", %1" : "=r"(old) : "r"(kctx) : "memory");
kctx->cpulocal = old->cpulocal;
kctx->ctxswitch = old->ctxswitch;
asm("" ::: "memory");
return old;
}
// Print a register dump given isr_ctx_t.
void isr_ctx_dump(isr_ctx_t const *ctx);
Expand Down
17 changes: 15 additions & 2 deletions kernel/cpu/riscv/include/cpu/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ extern size_t mmu_half_size;
extern size_t mmu_hhdm_size;
// Number of page table levels.
extern int mmu_levels;
// Whether RISC-V Svpbmt is supported.
extern bool mmu_svpbmt;
// Virtual page number offset used for HHDM.
#define mmu_hhdm_vpn (mmu_hhdm_vaddr / MMU_PAGE_SIZE)
// Virtual page number of the higher half.
Expand All @@ -123,6 +125,11 @@ extern int mmu_levels;



// Whether a certain DTB MMU type is supported.
bool mmu_dtb_supported(char const *type);

// MMU-specific init code.
void mmu_early_init();
// MMU-specific init code.
void mmu_init();

Expand All @@ -145,7 +152,12 @@ static inline mmu_pte_t mmu_pte_new_leaf(size_t ppn, uint32_t flags) {
pte.g = !!(flags & MEMPROTECT_FLAG_GLOBAL);
pte.a = 1;
pte.d = 1;
pte.ppn = ppn;
if (mmu_svpbmt && flags & MEMPROTECT_FLAG_IO) {
pte.pbmt = RISCV_PBMT_IO;
} else if (mmu_svpbmt && flags & MEMPROTECT_FLAG_NC) {
pte.pbmt = RISCV_PBMT_NC;
}
pte.ppn = ppn;
return pte;
}
// Create a new internal PTE.
Expand Down Expand Up @@ -188,5 +200,6 @@ static inline void mmu_disable_sum() {

// Notify the MMU of global mapping changes.
static inline void mmu_vmem_fence() {
asm("sfence.vma" ::: "memory");
asm volatile("fence rw,rw" ::: "memory");
asm volatile("sfence.vma" ::: "memory");
}
22 changes: 22 additions & 0 deletions kernel/cpu/riscv/include/cpu/riscv_plic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

// SPDX-License-Identifier: MIT

#pragma once

#include <stdint.h>



// Maximum number of PLIC contexts.
#define PLIC_MAX_CTX_COUNT 15872

// Offset for interrupt priorities.
#define PLIC_PRIO_OFF 0x000000
// Offset for interrupt pending bits.
#define PLIC_PENDING_OFF 0x001000
// Offset for interrupt enable bits.
#define PLIC_ENABLE_OFF(ctx) (0x002000 + (ctx) * 0x80)
// Offset for priority threshold.
#define PLIC_THRESH_OFF(ctx) (0x200000 + (ctx) * 0x1000)
// Offset for claim/complete.
#define PLIC_CLAIM_OFF(ctx) (0x200004 + (ctx) * 0x1000)
Loading

0 comments on commit fa3b27f

Please sign in to comment.