aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2024-12-03 14:34:43 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2024-12-03 14:34:43 +0100
commit2eead36f97faf5bdad1abd60a220c0af72a5526c (patch)
treeb3a058db55deaffc9555d4f2955a89ae7da40bea /kernel
parent95c4b00e90e24d3bcb5d3b6e56f0e29b725ba9ce (diff)
downloadfbos-2eead36f97faf5bdad1abd60a220c0af72a5526c.tar.gz
fbos-2eead36f97faf5bdad1abd60a220c0af72a5526c.zip
Run a hart lottery on SMP
On systems with SMP multiple harts will try to run the kernel, and they will appear at random. But in this kernel, in order to keep things simple, we want to make sure that *only one* hart is running the show, as it greatly simplifies things on these kinds of systems. The solution is similar to what Linux does, which is to allow the first hart to initialize things, but then (and different to what Linux does), it will infinitely stall all the other harts that arrive at a random later point in time. In order to make this more apparent, I have also added a print message showing which hart is being used to run the whole thing. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fbos.ld.S5
-rw-r--r--kernel/head.S17
-rw-r--r--kernel/main.c11
-rw-r--r--kernel/printk.c15
4 files changed, 46 insertions, 2 deletions
diff --git a/kernel/fbos.ld.S b/kernel/fbos.ld.S
index 160a5cb..3bda55b 100644
--- a/kernel/fbos.ld.S
+++ b/kernel/fbos.ld.S
@@ -41,13 +41,16 @@ SECTIONS {
.data : {
*(.data)
}
-
. = ALIGN(8);
.rodata : {
*(.rodata)
}
+ . = ALIGN(8);
+ .sdata : {
+ *(.sdata*)
+ }
. = ALIGN(8);
.bss : {
diff --git a/kernel/head.S b/kernel/head.S
index 74f83d8..b175b89 100644
--- a/kernel/head.S
+++ b/kernel/head.S
@@ -63,6 +63,23 @@ _start_kernel:
// Flush the instruction cache
fence.i
+ // Run the hart lottery. If this is not the first time that it happens, then
+ // stall this hart forever: on this simple kernel we only want one hart
+ // available to avoid SMP shenanigans. See explanation on fbos/init.h.
+ la a3, hart_lottery
+ li a2, 1
+ amoadd.w a3, a2, (a3)
+ beqz a3, .Lhart_proceed
+.Lhart_wait:
+ wfi
+ j .Lhart_wait
+
+.Lhart_proceed:
+ // Store the hart id as we will tamper with the 'a0' register later when
+ // performing the call to `start_kernel`.
+ la a3, hart_id
+ sw a0, 0(a3)
+
// Reset all registers except ra, a0, a1.
li sp, 0
li gp, 0
diff --git a/kernel/main.c b/kernel/main.c
index a2e4d13..822d638 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -5,6 +5,12 @@
#include <fbos/string.h>
#include <fbos/dt.h>
+/*
+ * Data related to harts and set by kernel/head.S. Defined in fbos/init.h.
+ */
+atomic32_t hart_lottery __section(".sdata");
+uint32_t hart_id;
+
// Stack to be used by our processes, which is initialized in head.S.
// "Blasphemy!" I hear you say. "How dare you use the same stack for kernel and
// user space?" It's not like this is some sort of utopian system in which
@@ -52,6 +58,11 @@ __noreturn __kernel void start_kernel(void *dtb)
write("\n", 1);
}
+ // And print the hart ID where this is being run.
+ printk("Running on Hart ID: ");
+ print_digit(hart_id);
+ write("\n", 1);
+
// At this point everything has already been handled: setup the interrupt
// vector and enable the timer to start ticking and scheduling the three
// tasks at hand.
diff --git a/kernel/printk.c b/kernel/printk.c
index bd2bcab..1cc68db 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -3,7 +3,7 @@
#include <fbos/string.h>
#include <fbos/sbi.h>
-void __noreturn __kernel die(const char *const message)
+__kernel __noreturn void die(const char *const message)
{
if (message) {
printk(message);
@@ -13,6 +13,19 @@ void __noreturn __kernel die(const char *const message)
;
}
+__kernel void print_digit(uint32_t digit)
+{
+ char buffer[2];
+
+ if (digit > 9) {
+ die("We cannot print numbers with two or more digits :D\n");
+ }
+
+ buffer[0] = '0' + digit;
+ buffer[1] = '\0';
+ write(buffer, 2);
+}
+
__kernel void write(const char *const message, size_t n)
{
struct sbi_ret ret = sbi_ecall2(DBCN_EXT, DBCN_WRITE, n, (unsigned long)message);