This otherwise caused a race condition between the signal dispatcher
(which sets sepc to the signal trampoline) and sepc being updated in the
trap handler.
We obviously have to keep the sepc set by the signal dispatcher and not
increment it afterwards.
Sticking this to the function source has multiple benefits:
- We instrument more code, by not excluding entire files.
- NO_SANITIZE_COVERAGE can be used in Header files.
- Keeping the info with the source code, means if a function or
file is moved around, the NO_SANITIZE_COVERAGE moves with it.
This simple delay loop uses the time CSR to wait for the given amount
of time. The tick frequency of the CSR is read from the
/cpus/timebase-frequency devicetree property.
Instead, rewrite the region page fault handling code to not use
PageFault::type() on RISC-V.
I split Region::handle_fault into having a RISC-V-specific
implementation, as I am not sure if I cover all page fault handling edge
cases by solely relying on MM's own region metadata.
We should probably also take the processor-provided page fault reason
into account, if we decide to merge these two implementations in the
future.
This commit also removes the unnecessary user_sp RegisterState member.
We never use the kernel stack pointer on entry, so we can simply always
store the stack pointer of the previous privilege mode in sp.
Also remove the sp member from mcontext, as RISC-V doesn't have a
dedicated stack pointer register.
sp is defined to be x2 (x[1] in our case) by the ABI.
I probably accidentally included sp while copying the struct from
aarch64.
sepc has to be incremented before the call to syscall_handler,
as we otherwise would return to the ecall instruction, resulting in an
infinite trap loop.
We can't increment it after syscall_handler, as sepc might get changed
while handling the syscall.
thread_context_first_enter reuses the context restoring code in the
trap handler, just like other arches already do.
The `ld x2, 1*8(sp)` is unnecessary in the trap handler, as the stack
pointer should be equal to the stack pointer slot in the RegisterState
if the trap is from supervisor mode (and we currently don't support
user traps).
This load will however make us unable to reuse that code for
thread_context_first_enter.
This commit adds two functions which save/restore the entire FPU state.
On RISC-V, you only need to save the floating pointer registers
themselves and the fcsr CSR, which contains the entire state of the F/D
extensions.
The former automatically adapts the prefix to binary and octal
output, and is what we already use in the majority of cases.
Patch generated by:
rg -l '0x\{' | xargs sed -i '' -e 's/0x{:/{:#/'
I ran it 4 times (until it stopped changing things) since each
invocation only converted one instance per line.
No behavior change.
According to the Intel Software Developer's Manual Volume 3A section
6.12.1.3, the interrupt gate type means the IF flag is cleared to
prevent nested interruption. The trap gate type does not modify the
IF flag. Thus the gate type argument is important when constructing
an IDTEntry.
On x86_64 and x86, storage_segment (bit 12 counting from 0)
is always 0 according to the Intel Software Developer's Manual,
volume 3A, section 6.11 and section 6.14.1. It has therefore
been removed as a parameter from IDTEntry's constructor and
hardwired to 0.
This makes it possible to use MakeIndexSequqnce in functions like:
template<typename T, size_t N>
constexpr auto foo(T (&a)[N])
This means AK/StdLibExtraDetails.h must now include AK/Types.h
for size_t, which means AK/Types.h can no longer include
AK/StdLibExtras.h (which arguably it shouldn't do anyways),
which requires rejiggering some things.
(IMHO Types.h shouldn't use AK::Details metaprogramming at all.
FlatPtr doesn't necessarily have to use Conditional<> and ssize_t could
maybe be in its own header or something. But since it's tangential to
this PR, going with the tried and true "lift things that cause the
cycle up to the top" approach.)
Multiple fields in sstatus are defined as WPRI "Reserved Writes Preserve
Values, Reads Ignore Values", which means we have to preserve their
values when writing to other fields in the same CSR.
We don't really need to touch any fields except SIE.
Interrupts are probably already disabled, but just to be safe,
disable them explicitly.
I just copy-pasted microseconds_since_boot and
set_interrupt_interval_usec from aarch64.
However, on RISC-V, they are not in microseconds.
The TimerRegisters struct is also unused.
current_time and set_compare can also be private and static.
IRQHandler is not the correct class to inherit from, as the timer
is not connected to an IRQController.
Each hart has one of these Timers directly connected to it.
I originally added this header because I misunderstood how
IRQControllers are supposed to be used.
I thought that I would need a IRQController class for the hart-local
interrupt controller, but apparently, this class is supposed to be used
for non-local interrupt controllers like the IOAPIC or RISC-V PLIC.
x86 LAPICs don't use this class either.
I am not sure why 096cecb95e disabled the stack protector and sanitizers
for all files, but this is not necessary.
Only the pre_init code needs to run without them, as that code runs
identity mapped.
We initialize the MMU by first setting up the page tables for the
kernel image and the initial kernel stack.
Then we jump to a identity mapped page which makes the newly created
kernel root page table active by setting `satp` and then jumps to
`init`.
This trap handler uses the SBI to print an error message via a newly
introduced panic function, which is necessary as `pre_init` is running
identity mapped.
Also add a header file for `pre_init.cpp` as we wan't to use the panic
and `dbgln` function in the MMU init code as well.
We first try to use the newer "SRST" extension for rebooting and
shutting down and if that fails, we try to shutdown using the legacy
"System Shutdown" extension (which can't reboot, so we always shutdown).
The kernel will halt, if we return from here due to all attempts at
rebooting / shutting down failing.