Compare commits
6 commits
5948d6c8e8
...
5dbcb33726
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5dbcb33726 | ||
![]() |
58bface3c9 | ||
![]() |
93295eaeb8 | ||
![]() |
74fdd26759 | ||
![]() |
f48e74bebe | ||
![]() |
f1f480251c |
9 changed files with 70 additions and 19 deletions
2
Makefile
2
Makefile
|
@ -27,7 +27,7 @@ CFLAGS += -fno-omit-frame-pointer # More reliable backtraces in GDB
|
||||||
|
|
||||||
all: kernel.elf
|
all: kernel.elf
|
||||||
|
|
||||||
kernel.elf: entry.o start.o lib/string.o lib/proc.o lib/spinlock.o lib/proc.o
|
kernel.elf: entry.o start.o lib/string.o lib/proc.o lib/spinlock.o lib/proc.o lib/uart.o lib/panic.o
|
||||||
@echo LD $@
|
@echo LD $@
|
||||||
@$(LD) $(LDFLAGS) -o $@ $^
|
@$(LD) $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
|
20
README.md
20
README.md
|
@ -6,3 +6,23 @@ For a quick reference on RISC-V assembly:
|
||||||
Toolchains:
|
Toolchains:
|
||||||
- https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
|
- https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
|
||||||
- https://github.com/xpack-dev-tools/qemu-riscv-xpack/
|
- https://github.com/xpack-dev-tools/qemu-riscv-xpack/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
| Register | Name | Privilege Level | Description |
|
||||||
|
|-------------|----------------------------|------------------|-----------------------------------------------------------------------------|
|
||||||
|
| `mstatus` | Machine Status Register | Machine | Holds global interrupt enable, previous privilege mode, etc. |
|
||||||
|
| `mtvec` | Machine Trap-Vector Base | Machine | Holds the base address of the trap handler (exception/interrupt entry). |
|
||||||
|
| `mepc` | Machine Exception PC | Machine | Stores the program counter at the time of the last trap. |
|
||||||
|
| `mcause` | Machine Cause Register | Machine | Indicates the cause of the last trap (interrupt or exception). |
|
||||||
|
| `satp` | Supervisor Address Translation and Protection | Supervisor | Controls page table base address and mode (e.g., Sv39, Sv48). |
|
||||||
|
| `sstatus` | Supervisor Status Register | Supervisor | Like `mstatus`, but accessible from supervisor mode. |
|
||||||
|
| `stvec` | Supervisor Trap-Vector Base| Supervisor | Like `mtvec`, but for supervisor mode traps. |
|
||||||
|
| `sepc` | Supervisor Exception PC | Supervisor | Like `mepc`, but for supervisor mode. |
|
||||||
|
| `scause` | Supervisor Cause Register | Supervisor | Like `mcause`, but for supervisor mode traps. |
|
||||||
|
| `sscratch` | Supervisor Scratch | Supervisor | Can be used to store temporary state across traps in supervisor mode. |
|
||||||
|
| `mscratch` | Machine Scratch | Machine | Like `sscratch`, but in machine mode. |
|
||||||
|
| `mcycle` | Machine Cycle Counter | Machine | Counts the number of cycles executed. |
|
||||||
|
| `mtime` | Machine Timer Register | Machine (via memory-mapped) | Used for timing and scheduling (not a CSR, but a memory-mapped register). |
|
||||||
|
| `mip` | Machine Interrupt Pending | Machine | Indicates pending interrupts. |
|
||||||
|
| `mie` | Machine Interrupt Enable | Machine | Controls which interrupts are enabled. |
|
||||||
|
|
8
lib/panic.c
Normal file
8
lib/panic.c
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include <uart.h>
|
||||||
|
volatile int panicked;
|
||||||
|
|
||||||
|
void panic(char *s) {
|
||||||
|
panicked = 1;
|
||||||
|
uart_puts(s);
|
||||||
|
while (1);
|
||||||
|
}
|
6
lib/panic.h
Normal file
6
lib/panic.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef KERNEL_PANIC_H
|
||||||
|
#define KERNEL_PANIC_H
|
||||||
|
|
||||||
|
void panic(char *s);
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,13 +4,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// #include <lib/stdio.h>
|
// #include <lib/stdio.h>
|
||||||
|
#include <panic.h>
|
||||||
#include <proc.h>
|
#include <proc.h>
|
||||||
#include <riscv.h>
|
#include <riscv.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
|
|
||||||
// void panic(char *s) { for (;;); }
|
|
||||||
void panic(char *s) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The aquire() and release() functions control ownership of the lock.
|
* The aquire() and release() functions control ownership of the lock.
|
||||||
* To perform these operations, modern CPU's provide atomic instructions
|
* To perform these operations, modern CPU's provide atomic instructions
|
||||||
|
@ -60,8 +58,8 @@ void acquire(struct spinlock *lk) {
|
||||||
panic("acquire");
|
panic("acquire");
|
||||||
|
|
||||||
// Spin until aquired. See file header for details
|
// Spin until aquired. See file header for details
|
||||||
while (__sync_lock_test_and_set(&lk->locked, 1) != 0) {
|
while (__sync_lock_test_and_set(&lk->locked, 1) != 0);
|
||||||
}
|
|
||||||
__sync_synchronize(); // No loads/stores after this point
|
__sync_synchronize(); // No loads/stores after this point
|
||||||
|
|
||||||
// Record info about lock acquisition for holding() and debugging.
|
// Record info about lock acquisition for holding() and debugging.
|
||||||
|
|
9
lib/uart.c
Normal file
9
lib/uart.c
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/* QEMU memory maps a UART device here. */
|
||||||
|
#define UART_BASE ((volatile char *)0x10000000)
|
||||||
|
|
||||||
|
void uart_putc(char c) { *UART_BASE = c; }
|
||||||
|
|
||||||
|
void uart_puts(const char *s) {
|
||||||
|
while (*s) uart_putc(*s++);
|
||||||
|
}
|
||||||
|
|
10
lib/uart.h
Normal file
10
lib/uart.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef UART_KERNEL_H
|
||||||
|
#define UART_KERNEL_H
|
||||||
|
|
||||||
|
/** Send a single character to the UART device */
|
||||||
|
void uart_putc(char c);
|
||||||
|
|
||||||
|
/** Send a **NULL TERMINATED** string to the UART device */
|
||||||
|
void uart_puts(const char *s);
|
||||||
|
|
||||||
|
#endif
|
3
riscv.h
3
riscv.h
|
@ -40,6 +40,9 @@ static inline u64 r_tp() {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Write thread pointer */
|
||||||
|
static inline void w_tp(u64 x) { asm volatile("mv tp, %0" : : "r"(x)); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the value of the sstatus register.
|
* Read the value of the sstatus register.
|
||||||
* (Supervisor Status Register)
|
* (Supervisor Status Register)
|
||||||
|
|
23
start.c
23
start.c
|
@ -1,18 +1,10 @@
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <proc.h>
|
||||||
#include <riscv.h>
|
#include <riscv.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
|
#include <string.h>
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
#include <uart.h>
|
||||||
/* QEMU memory maps a UART device here. */
|
|
||||||
#define UART_BASE ((volatile char *)0x10000000)
|
|
||||||
|
|
||||||
/** Send a single character to the UART device */
|
|
||||||
void uart_putc(char c) { *UART_BASE = c; }
|
|
||||||
|
|
||||||
/** Send a **NULL TERMINATED** string to the UART device */
|
|
||||||
void uart_puts(const char *s) {
|
|
||||||
while (*s) uart_putc(*s++);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate one stack per CPU (hart).
|
* Allocate one stack per CPU (hart).
|
||||||
|
@ -28,8 +20,13 @@ volatile int greeted = 0;
|
||||||
|
|
||||||
/* This is where entry.S drops us of. All cores land here */
|
/* This is where entry.S drops us of. All cores land here */
|
||||||
void start() {
|
void start() {
|
||||||
|
u64 id = r_mhartid();
|
||||||
|
|
||||||
u64 a = r_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).
|
||||||
|
w_tp(id);
|
||||||
|
|
||||||
acquire(&sl);
|
acquire(&sl);
|
||||||
|
|
||||||
|
@ -39,7 +36,7 @@ void start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_puts("Hart number: ");
|
uart_puts("Hart number: ");
|
||||||
uart_putc(a + '0');
|
uart_putc(id + '0');
|
||||||
uart_putc('\n');
|
uart_putc('\n');
|
||||||
|
|
||||||
release(&sl);
|
release(&sl);
|
||||||
|
|
Loading…
Add table
Reference in a new issue