initiall commit
This commit is contained in:
commit
d838adddd5
5
riscv32-os/.gitignore
vendored
Normal file
5
riscv32-os/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
*.o
|
||||
*.elf
|
||||
*.map
|
||||
*.bin
|
||||
qemu.log
|
||||
19
riscv32-os/Makefile
Normal file
19
riscv32-os/Makefile
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
CC ?= clang
|
||||
QEMU ?= qemu-system-riscv32
|
||||
FW ?= /usr/share/qemu/opensbi-riscv32-generic-fw_dynamic.bin
|
||||
|
||||
CFLAGS = -fuse-ld=lld -std=c11 -O2 -g3 -Wall -Wextra \
|
||||
--target=riscv32 -march=rv32imac -mabi=ilp32 \
|
||||
-ffreestanding -nostdlib
|
||||
|
||||
all: kernel.elf
|
||||
|
||||
kernel.elf: kernel.c common.c common.h kernel.h kernel.ld
|
||||
$(CC) $(CFLAGS) -Wl,-T,kernel.ld -Wl,-Map,kernel.map -o $@ kernel.c common.c
|
||||
|
||||
run: kernel.elf
|
||||
$(QEMU) -machine virt -nographic -serial mon:stdio --no-reboot \
|
||||
-bios $(FW) -kernel kernel.elf
|
||||
|
||||
clean:
|
||||
rm -f *.o *.elf *.map qemu.log
|
||||
82
riscv32-os/common.c
Normal file
82
riscv32-os/common.c
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#include "common.h"
|
||||
|
||||
void putchar(char ch);
|
||||
|
||||
void *memset(void *buf, int c, size_t n) {
|
||||
uint8_t *p = (uint8_t*)buf;
|
||||
while (n--) *p++ = (uint8_t)c;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void print_uint_hex(uint32_t v) {
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
uint32_t nib = (v >> (i * 4)) & 0xF;
|
||||
putchar("0123456789abcdef"[nib]);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_int_dec(int v) {
|
||||
if (v == 0) { putchar('0'); return; }
|
||||
if (v < 0) { putchar('-'); v = -v; }
|
||||
|
||||
int div = 1;
|
||||
while (v / div > 9) div *= 10;
|
||||
|
||||
while (div > 0) {
|
||||
putchar('0' + (v / div));
|
||||
v %= div;
|
||||
div /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
void printf(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt != '%') {
|
||||
putchar(*fmt++);
|
||||
continue;
|
||||
}
|
||||
|
||||
fmt++;
|
||||
char spec = *fmt ? *fmt : '\0';
|
||||
|
||||
if (spec == '\0') { putchar('%'); break; }
|
||||
|
||||
switch (spec) {
|
||||
case '%':
|
||||
putchar('%');
|
||||
break;
|
||||
case 'c': {
|
||||
int ch = va_arg(ap, int);
|
||||
putchar((char)ch);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
const char *s = va_arg(ap, const char*);
|
||||
if (!s) s = "(null)";
|
||||
while (*s) putchar(*s++);
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
int v = va_arg(ap, int);
|
||||
print_int_dec(v);
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
uint32_t v = va_arg(ap, uint32_t);
|
||||
print_uint_hex(v);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
putchar('%');
|
||||
putchar(spec);
|
||||
break;
|
||||
}
|
||||
|
||||
fmt++;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
16
riscv32-os/common.h
Normal file
16
riscv32-os/common.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long size_t;
|
||||
|
||||
#define NULL ((void*)0)
|
||||
|
||||
/* Use compiler builtins instead of libc stdarg */
|
||||
#define va_list __builtin_va_list
|
||||
#define va_start __builtin_va_start
|
||||
#define va_end __builtin_va_end
|
||||
#define va_arg __builtin_va_arg
|
||||
|
||||
void *memset(void *buf, int c, size_t n);
|
||||
void printf(const char *fmt, ...);
|
||||
171
riscv32-os/kernel.c
Normal file
171
riscv32-os/kernel.c
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
#include "kernel.h"
|
||||
|
||||
extern char __bss[], __bss_end[], __stack_top[];
|
||||
|
||||
static inline struct sbiret sbi_call(long a0, long a1, long a2, long a3,
|
||||
long a4, long a5, long fid, long eid) {
|
||||
register long x0 __asm__("a0") = a0;
|
||||
register long x1 __asm__("a1") = a1;
|
||||
register long x2 __asm__("a2") = a2;
|
||||
register long x3 __asm__("a3") = a3;
|
||||
register long x4 __asm__("a4") = a4;
|
||||
register long x5 __asm__("a5") = a5;
|
||||
register long x6 __asm__("a6") = fid;
|
||||
register long x7 __asm__("a7") = eid;
|
||||
|
||||
__asm__ __volatile__("ecall"
|
||||
: "+r"(x0), "+r"(x1)
|
||||
: "r"(x2), "r"(x3), "r"(x4), "r"(x5), "r"(x6), "r"(x7)
|
||||
: "memory");
|
||||
return (struct sbiret){ .error = x0, .value = x1 };
|
||||
}
|
||||
|
||||
void putchar(char ch) {
|
||||
sbi_call((long)ch, 0, 0, 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
int getchar(void) {
|
||||
int ch;
|
||||
do {
|
||||
struct sbiret ret = sbi_call(0, 0, 0, 0, 0, 0, 0, 2);
|
||||
ch = (int)ret.error;
|
||||
} while (ch == -1);
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void get_sbi_spec_version(void) {
|
||||
struct sbiret ret = sbi_call(0, 0, 0, 0, 0, 0, 0, SBI_EXT_BASE);
|
||||
|
||||
if (ret.error != SBI_SUCCESS) {
|
||||
printf("Error: %d\n", (int)ret.error);
|
||||
return;
|
||||
}
|
||||
|
||||
long version = ret.value;
|
||||
int major = (version >> 24) & 0x7F;
|
||||
int minor = version & 0xFFFFFF;
|
||||
|
||||
printf("SBI Specification Version: %d.%d\n", major, minor);
|
||||
}
|
||||
|
||||
static void get_num_counters(void) {
|
||||
struct sbiret ret = sbi_call(0, 0, 0, 0, 0, 0, 0, SBI_EXT_PMU);
|
||||
|
||||
if (ret.error != SBI_SUCCESS) {
|
||||
printf("Error: %d\n", (int)ret.error);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Number of counters: %d\n", (int)ret.value);
|
||||
}
|
||||
|
||||
static int read_number(void) {
|
||||
int num = 0;
|
||||
int ch;
|
||||
|
||||
while (1) {
|
||||
ch = getchar();
|
||||
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
putchar('\n');
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
putchar(ch);
|
||||
num = num * 10 + (ch - '0');
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static void get_counter_info(void) {
|
||||
printf("Enter counter index: ");
|
||||
int idx = read_number();
|
||||
|
||||
struct sbiret ret = sbi_call(idx, 0, 0, 0, 0, 0, 1, SBI_EXT_PMU);
|
||||
|
||||
if (ret.error == SBI_ERR_NOT_SUPPORTED) {
|
||||
printf("PMU extension not supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret.error != SBI_SUCCESS) {
|
||||
printf("Error: %d (invalid counter index?)\n", (int)ret.error);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t info = (uint32_t)ret.value;
|
||||
|
||||
uint32_t csr = info & 0xFFF;
|
||||
uint32_t width_minus_one = (info >> 12) & 0x3F;
|
||||
uint32_t type = (info >> 31) & 0x1;
|
||||
|
||||
printf("Counter %d details:\n", idx);
|
||||
printf(" Type: %s\n", type ? "Firmware" : "Hardware");
|
||||
|
||||
if (type == 0) {
|
||||
printf(" CSR: 0x%x\n", csr);
|
||||
printf(" Width: %d bits\n", width_minus_one + 1);
|
||||
} else {
|
||||
printf(" (CSR and Width fields ignored for firmware counters)\n");
|
||||
}
|
||||
|
||||
printf(" Raw info: 0x%x\n", info);
|
||||
}
|
||||
|
||||
static void system_shutdown(void) {
|
||||
printf("Goodbye!\n");
|
||||
sbi_call(0, 0, 0, 0, 0, 0, 0, SBI_EXT_SRST);
|
||||
}
|
||||
|
||||
static void print_menu(void) {
|
||||
printf("1. Get SBI specification version\n");
|
||||
printf("2. Get number of counters\n");
|
||||
printf("3. Get details of a counter\n");
|
||||
printf("4. System Shutdown\n");
|
||||
}
|
||||
|
||||
static void kernel_main(void) {
|
||||
memset(__bss, 0, (size_t)(__bss_end - __bss));
|
||||
|
||||
print_menu();
|
||||
|
||||
while (1) {
|
||||
printf("Choose option (1-4): ");
|
||||
int ch = getchar();
|
||||
putchar(ch);
|
||||
putchar('\n');
|
||||
|
||||
switch (ch) {
|
||||
case '1':
|
||||
get_sbi_spec_version();
|
||||
break;
|
||||
case '2':
|
||||
get_num_counters();
|
||||
break;
|
||||
case '3':
|
||||
get_counter_info();
|
||||
break;
|
||||
case '4':
|
||||
system_shutdown();
|
||||
return;
|
||||
default:
|
||||
printf("Invalid option\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((section(".text.boot")))
|
||||
__attribute__((naked))
|
||||
void boot(void) {
|
||||
__asm__ __volatile__(
|
||||
"mv sp, %[stack_top]\n"
|
||||
"j %[kmain]\n"
|
||||
:
|
||||
: [stack_top] "r" (__stack_top),
|
||||
[kmain] "i" (kernel_main)
|
||||
);
|
||||
}
|
||||
24
riscv32-os/kernel.h
Normal file
24
riscv32-os/kernel.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct sbiret {
|
||||
long error;
|
||||
long value;
|
||||
};
|
||||
|
||||
#define SBI_SUCCESS 0
|
||||
#define SBI_ERR_FAILED -1
|
||||
#define SBI_ERR_NOT_SUPPORTED -2
|
||||
#define SBI_ERR_INVALID_PARAM -3
|
||||
|
||||
#define SBI_EXT_BASE 0x10
|
||||
#define SBI_EXT_PMU 0x504D55
|
||||
#define SBI_EXT_SRST 0x53525354
|
||||
|
||||
#define PANIC(fmt, ...) do { \
|
||||
printf("PANIC: %s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
|
||||
for (;;) { __asm__ __volatile__("wfi"); } \
|
||||
} while (0)
|
||||
|
||||
int getchar(void);
|
||||
24
riscv32-os/kernel.ld
Normal file
24
riscv32-os/kernel.ld
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
ENTRY(boot)
|
||||
|
||||
SECTIONS {
|
||||
/* QEMU virt loads the kernel at 0x80200000 */
|
||||
. = 0x80200000;
|
||||
|
||||
.text : {
|
||||
KEEP(*(.text.boot));
|
||||
*(.text .text.*);
|
||||
}
|
||||
|
||||
.rodata : ALIGN(4) { *(.rodata .rodata.*); }
|
||||
.data : ALIGN(4) { *(.data .data.*); }
|
||||
|
||||
.bss : ALIGN(4) {
|
||||
__bss = .;
|
||||
*(.bss .bss.* .sbss .sbss.*);
|
||||
__bss_end = .;
|
||||
}
|
||||
|
||||
. = ALIGN(4);
|
||||
. += 128 * 1024; /* 128KB stack */
|
||||
__stack_top = .;
|
||||
}
|
||||
29
riscv32-os/run.sh
Executable file
29
riscv32-os/run.sh
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
QEMU="${QEMU:-qemu-system-riscv32}"
|
||||
CC="${CC:-clang}"
|
||||
|
||||
FW="${FW:-/usr/share/qemu/opensbi-riscv32-generic-fw_dynamic.bin}"
|
||||
if [[ ! -f "$FW" ]]; then
|
||||
echo "ERROR: OpenSBI firmware not found at: $FW"
|
||||
echo "Try: ls -1 /usr/share/qemu/*opensbi*riscv32*fw_dynamic*.bin"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CFLAGS=(
|
||||
-fuse-ld=lld
|
||||
-std=c11 -O2 -g3 -Wall -Wextra
|
||||
--target=riscv32
|
||||
-march=rv32imac -mabi=ilp32
|
||||
-ffreestanding -nostdlib
|
||||
)
|
||||
|
||||
"$CC" "${CFLAGS[@]}" \
|
||||
-Wl,-T,kernel.ld -Wl,-Map,kernel.map \
|
||||
-o kernel.elf \
|
||||
kernel.c common.c
|
||||
|
||||
"$QEMU" -machine virt -nographic -serial mon:stdio --no-reboot \
|
||||
-bios "$FW" \
|
||||
-kernel kernel.elf
|
||||
20
setup.sh
Executable file
20
setup.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo
|
||||
echo "== Checks =="
|
||||
clang --version | head -n1
|
||||
qemu-system-riscv32 --version | head -n1
|
||||
|
||||
echo
|
||||
echo "clang riscv32 target:"
|
||||
clang -print-targets | grep -E 'riscv32' || {
|
||||
echo "ERROR: clang does not list riscv32 target."
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo
|
||||
echo "OpenSBI firmware candidates:"
|
||||
ls -1 /usr/share/qemu/*opensbi*riscv32*fw_dynamic*.bin 2>/dev/null || true
|
||||
echo
|
||||
echo "Done."
|
||||
Loading…
Reference in New Issue
Block a user