[NSWI004] [Teachers at NSWI004] Bug report
Lubomír Bulej
bulej at d3s.mff.cuni.cz
Wed Dec 16 13:55:47 CET 2020
Hello,
I see that Vojtech has already replied, so I'll just add a few more bits.
There are more things at play.
TLDR:
you need to set ASID explicitly before you call `cpu_switch_context()`,
because ASID can (depending on your implementation) change between context
switches.
The `cp0.h` header file contains the `cp0_set_asid()` function which should be
used in an appropriate context to set the active ASID. We forgot to explicitly
mention this function in the assignment text, even though I would assume that
the section on TLB management would have you look in the `cpu0.h` header file.
My apologies for that omission.
Long answer:
Switching CPU context (i.e., switching between threads) does not require
switching address spaces, which is why `cpu_switch_context()` does not do it.
Our goal was to have a relatively straightforward implementation of
`cpu_switch_context()` so that it's clear what it is doing (even though there
are a few extra hoops to go through to be able to use the k0 and k1 registers).
ASID is a property of an address space and an address space is a property of a
process. Even though you do not have an explicit process context in your
kernel, you should treat an address space as one, i.e., deal with it
explicitly in your thread switch code.
I can imagine having a function `as_switch_to()` which would pick the right
ASID (depending on your ASID allocation strategy) and use the cp0_set_asid()
function to set it.
This function would be called by the `thread_switch_to()` function so that
thread code would not have to worry about implementation details of switching
address space (or having to work with ASIDs), as opposed to having
`thread_switch_to()` store the value in the thread's `context_t` before
switching and expecting `cpu_switch_context()` to load CP0 EntryHi.
I can understand how you arrived at the conclusion that the code in
`context.S` is buggy, even though we consider it correct. One misleading bit
is the content of `context_t`, which indeed contains an `entryhi` member which
is not used by the assembly code in `context.S`.
Note, however, that it also does not work with `badvaddr`, `epc`, and `cause`.
The exception handler code works with `status`, `epc`, `badvaddr`, and
`cause`. As mentioned in `exc.h`, we keep those values in `context_t` so that
we can reuse the structure type (and the manually defined offsets) also in
exception handlers. The trade-off we were making was in favor of simplicity.
Done "properly", we would have different structure types for `context_t` and
`eh_context_t` and we would generate offsets using a tool to ensure that the
two things remain consistent. However, this proved to be confusing to students
in previous years.
Anyway, we are left with an `entryhi` which is not used anywhere. This is the
result of `cpu_switch_context()` simplification we were doing for the earlier
assignments, in which we did not think of removing the `entryhi` field.
In later assignments, we generally avoid changing files from earlier
assignments unless necessary (i.e., if the change is required by the new
assignment, or if we discover a bug).
However, the unused `entryhi` may have led you to the conclusion that it
should be used by `cpu_switch_context()`. Technically, your modification
works, but is not what we intended design-wise.
Rest assured that we spend non-trivial time on preparing the assignments, but
sometimes trivial things combine in an unexpected fashion and become
misleading. My apologies for the confusion.
Lubomir Bulej
On 16/12/2020 00:50, Jura Pelc wrote:
>
> Hello,
>
> after nontrivial time spent scanning your assembly code, I figured out that
> during a context switch the entryHi register is not loaded nor stored in contexts.
> With your implementation of context.S, tests were failing, caused by
> thread_kill call in global_exception_handler because memory was access with an
> ASID unset.
>
> I coincide it as a bug since context switch should preserve the entire
> context_t structure but entryHi nor CONTEXT_CP0_ENTRYHI_OFFSET was not used
> anywhere in SAVE_REGISTERS nor LOAD_REGISTERS.
>
> I made the following changes, I want someone to concur with my findings.
> ```
> diff --git a/kernel/src/proc/context.S b/kernel/src/proc/context.S
> index 3da3a0c..a43ddef 100644
> --- a/kernel/src/proc/context.S
> +++ b/kernel/src/proc/context.S
> @@ -42,6 +42,8 @@ cpu_switch_context:
> mflo $t1
> sw $t0, CONTEXT_HI_OFFSET($a0)
> sw $t1, CONTEXT_LO_OFFSET($a0)
> + mfc0 $t0, $10
> + sw $t0, CONTEXT_CP0_ENTRYHI_OFFSET($a0)
>
> /*
> * Save the CP0 Status register and disable interrupts (by
> @@ -71,6 +73,8 @@ cpu_switch_context:
> lw $t1, CONTEXT_LO_OFFSET($a1)
> mthi $t0
> mtlo $t1
> + lw $t0, CONTEXT_CP0_ENTRYHI_OFFSET($a1)
> + mtc0 $t0, $10
>
> move $k0, $a1
> LOAD_REGISTERS $k0
> ```
>
More information about the NSWI004
mailing list