aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv/supervisor/hsm/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv/supervisor/hsm/README.md')
-rw-r--r--arch/riscv/supervisor/hsm/README.md126
1 files changed, 126 insertions, 0 deletions
diff --git a/arch/riscv/supervisor/hsm/README.md b/arch/riscv/supervisor/hsm/README.md
new file mode 100644
index 0000000..a950152
--- /dev/null
+++ b/arch/riscv/supervisor/hsm/README.md
@@ -0,0 +1,126 @@
+# Messing with the Hart State Management Extension ("HSM") from the SBI
+
+This is a simple kernel that messes with the HSM Extension from the SBI v2.0. In
+general, and according to the RISC-V specification, harts can enter Supervisor
+mode at any time. This makes thing simple both for the RISC-V specification and
+machines implementing the architecture. For the kernel this means that you never
+know which hart is going to start first, and in cases like the Linux kernel, you
+actually want to ensure that only one hart is running for initialization
+purposes before waking up the rest. In order to guarantee this, the Linux kernel
+runs a lottery.
+
+To run a lottery on this context means that the first hart to appear will
+actually take a lock in the kernel, which will block any other "secondary" hart
+that appears later. This lock is going to be released once the "main" hart
+guarantees that the kernel has been initialized up to a point where other harts
+can come in. This lock is implemented with an atomic variable that holds how
+many harts have been seen (hence, the first hart will read a zero value from
+this variable, and the rest will read a non-zero one).
+
+All of that being said, the SBI specification v2.0 comes with a cleaner
+approach: the HSM extension. With this extension a Supervisor will be able to
+manage the state of any hart of the system, which is either `started`, `stopped`
+or `suspended` (plus transition states). Moreover, there is the guarantee that
+only one hart will be initialized with the `started` state, whereas the rest
+will be on `stopped`. This means that a kernel can drop the whole idea of a
+lottery and have the guarantee that only one hart will run on start. Whenever
+the kernel has been initialized to a specific stage, it will be able to change
+the state of the rest of harts to `started`.
+
+## This example
+
+This example uses the HSM extension but it also keeps the idea of a lottery.
+That is, the first hart will "acquire" the lock ("win" the lottery), and will be
+responsible for bringing the rest up. At first this hart will simply print
+information on the system. For example, on a system with four harts you will get
+something like:
+
+```
+Hello, world!
+Hart that won the lottery: 1
+Harts still asleep: 0, 2, 3
+
+How many harts have _participated_ in the lottery? 1
+How many harts have _failed_ in the lottery? 0
+```
+
+In this example, only one hart is available: one that "won" the lottery, and the
+rest have not even appeared. The hart with ID '1' will be responsible for waking
+up '0', '2' and '3'. After making some initial checks, it will wake up the first
+secondary hart (no reason to just wake up one, just doing it this way for the
+show):
+
+```
+Waking up first secondary hart
+How many harts have _participated_ in the lottery? 2
+How many harts have _failed_ in the lottery? 1
+```
+
+Now two harts are available, but the one that woke up is a "secondary" one, so
+it lost the lottery and is stuck in `head.S` on an infinite loop doing nothing.
+After doing that, the main hart will wake up the rest:
+
+```
+Waking up the rest
+How many harts have _participated_ in the lottery? 4
+How many harts have _failed_ in the lottery? 3
+```
+
+Now all four harts are up, but three of them (the "secondary" ones) are simply
+stuck in an infinite loop since they have "lost" the lottery. At this point this
+example does something weird for a kernel: it will return from the main
+function. Doing so allows `head.S` to count the main hart as a "failed" one, and
+it will print some final messages for it:
+
+```
+Goodbye, cruel world!
+How many harts have _participated_ in the lottery? 4
+How many harts have _failed_ in the lottery? 4
+
+THE END
+```
+
+At the point where "THE END" is printed, we will then perform an SBI call to the
+System Reset Extension ("SRST") to gracefully shutdown the system.
+
+## Test
+
+To test this yourself you need a recent enough QEMU which is able to run as a
+RISC-V system, and you need to set the `CROSS_COMPILE` environment variable as
+you would on the Linux Kernel if you are doing this on a non-RISC-V machine.
+After that, you can simply run `make` to build the binary, or simply run `make
+qemu` to both build it and run QEMU.
+
+Notice also that the Makefile accepts the `CPUS` variable, which by default is
+set to 4. Change this variable to something else to get a different number of
+harts on the example (but lesser than 10, since I haven't bothered to account
+for that when printing numerical values). For example, `make qemu CPUS=8`:
+
+``` shell
+Hello, world!
+Hart that won the lottery: 5
+Harts still asleep: 0, 1, 2, 3, 4, 6, 7
+How many harts have _participated_ in the lottery? 1
+How many harts have _failed_ in the lottery? 0
+
+Waking up first secondary hart
+How many harts have _participated_ in the lottery? 2
+How many harts have _failed_ in the lottery? 1
+
+Waking up the rest
+How many harts have _participated_ in the lottery? 8
+How many harts have _failed_ in the lottery? 7
+
+Goodbye, cruel world!
+How many harts have _participated_ in the lottery? 8
+How many harts have _failed_ in the lottery? 8
+
+THE END
+```
+
+## Rationale
+
+This example came after exploring the topic of SMP on
+[fbos](https://github.com/mssola/fbos). Even if in there I did not explore this
+extension further (because of the needs of the project), I decided that I wanted
+a fresh simple kernel to mess with this extension. And hence this project.