io1/riscv32-os/kernel.c
2026-02-06 15:52:53 +03:00

171 lines
3.9 KiB
C

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