-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update specs to use semi-lazy FPU switching #819
base: explicit_fpu
Are you sure you want to change the base?
Conversation
de54aec
to
1dbb4fc
Compare
od" | ||
|
||
definition enableFpu :: "unit machine_monad" where | ||
"enableFpu \<equiv> modify (\<lambda>s. s\<lparr>fpu_enabled := True \<rparr>)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left over from internal review:
the (lack of) link between
enableFpu
andenableFpuEL01
confuses me... there's no machine op for disabling the FPU? AreenableFpu
andenableFpuEL01
called separately by the C, or is this only the abstract spec model?
I was confused also. In the C,
enableFpu
calls eitherdisableTrapFpu
orenableFpuEL01
, depending on whether it is a configuration with hypervisor support (see https://github.com/seL4/seL4/blob/85aa104eb4d527bc9f0aac28f3e9c3a84eed1d7a/include/arch/arm/arch/64/mode/machine/fpu.h#L127). I was originally going to just haveenableFpu
in the spec before realising thatenableFpuEL01
is called directly fromvcpu_disable
(https://github.com/seL4/seL4/blob/85aa104eb4d527bc9f0aac28f3e9c3a84eed1d7a/include/arch/arm/armv/armv8-a/64/armv/vcpu.h#L702)
That seems odd, because it is unconditionally enabling FPU for native threads with no VCPU on hyp configurations. Doesn't that effectively ignore the native thread's configured flags?
|
||
postSetFlags :: PPtr TCB -> TcbFlags -> Kernel () | ||
postSetFlags t flags = | ||
when (tcbFlagToWord (ArchFlag FpuDisabled) .&. flags /= 0) (fpuRelease t) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interesting, with one flag I guess this is the shortest way to do it, but with more flags it'll be a bunch of tcbFlagToWord
s .|.
'ed together?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, good question, I hadn't thought about what this will look like if/when there are more flags. Maybe it's worth adding some sort of flagSet
helper function that does the tcbFlagToWord
and .&.
. That would make this something like
when (flagSet (ArchFlag FpuDisabled) flags) (fpuRelease t)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like that sounds good, but I'd prefer isFlagSet
or something, otherwise it sounds like a flag-setter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe inFlagSet
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like isFlagSet
, to me it's more of an abstraction where we don't care how it's implemented while inFlagSet
implies that it's a set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hasFlag
? I keep reading isFlagSet
as "is this a flag set", not "is this flag set/unset".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhh, I really think that isFlagSet
is pretty standard for "is the flag set", I'm not sure many people would think of isFlagASet
when reading it, and I'm not even sure that's possible in Isabelle's type system, and isSetOfFlags
is an even more creative interpretation... but then Englishes
> type TcbFlags = Word | ||
|
||
> data TcbFlag | ||
> = NoFlag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still not sure I understand the purpose of NoFlag
, could you enlighten me?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't speak about the original intentions in the C, but in my mind here it provides a way to abstract away the details of how the flags are implemented. For instance, we could say flags = NoFlag
to say that no flags are set.
Having now said that, this is another argument for adding something like the flagSet
helper function I mentioned in a different comment, since that would extend this abstraction and hide the details of the flags being implemented as a Word
.
data ArchTcbFlag = FpuDisabled | ||
|
||
archTcbFlagToWord :: ArchTcbFlag -> Word | ||
archTcbFlagToWord (FpuDisabled) = 0x1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No desire for bit
-equivalent here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I missed that. Thinking about it now though, the equivalent in C produces values with the final mask, so at some point we'll need to do the conversion between that and the bit
form. Do we think that that's simple enough that it can be done wherever, or would it be better do it in Refine
instead of CRefine
?
1dbb4fc
to
bfd342f
Compare
@@ -70,6 +70,11 @@ atcbContextSet uc atcb = atcb { atcbContext = uc } | |||
atcbContextGet :: ArchTCB -> UserContext | |||
atcbContextGet = atcbContext | |||
|
|||
data ArchTcbFlag = FpuDisabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in some cases when we have datatypes that are boringly similar to what we have in ASpec, we don't translate them and instead introduce an alias in the skeleton files; not sure if that's useful here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that would make sense, also for any future flags. Not sure of there we have a good location to put these in for arch specific data types, but it's worth looking.
spec/abstract/AARCH64/FPU_A.thy
Outdated
\<comment> \<open>FIXME: maybe use a case instead of the if (depends on if wpc or if_split is easier)\<close> | ||
definition switch_local_fpu_owner :: "obj_ref option \<Rightarrow> (unit,'z::state_ext) s_monad" where | ||
"switch_local_fpu_owner new_owner \<equiv> do | ||
do_machine_op enableFpu; | ||
cur_fpu_owner \<leftarrow> gets (arm_current_fpu_owner \<circ> arch_state); | ||
when (cur_fpu_owner \<noteq> None) $ save_fpu_state (the cur_fpu_owner); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would generally prefer case
for option if you have both branches, because it allows you to avoid using the
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just seeing that we don't really have both branches here. Don't we have a maybeM
or similar combinator in the nondetmonad for running something only when the argument is Some
? Don't quite remember.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That comment was actually for the if
statement just after this when
, which does have both branches. I'll have a dig around for a helpful combinator. Assuming one does exist, would we want something similar in the Haskell?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, having them structurally the same would be nice. (It's not that super important, it's correct as it is, just a style question, so if we don't already have a combinator, we can also leave it as is.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Context: the FIXME was originally because we weren't sure whether dealing with if
or case
would be easier in the corres
proof, so the plan was to check and then remove the FIXME afterwards
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made this change now but it's a little bit more complicated in Haskell, as to the best of my knowledge there isn't an easily accessible equivalent to maybeM
. The most likely option that I found is https://hackage.haskell.org/package/extra-1.7.16/docs/Control-Monad-Extra.html#v:whenJust, but using that would introduce a new dependency on the extra
package. I've currently used the underlying for
from Data.Traversable
, but that feels a bit unreadable and will require some care when translating to the design spec. Thoughts?
l4v/spec/haskell/src/SEL4/Object/FPU/AARCH64.hs
Lines 33 to 41 in 285ecfc
switchLocalFpuOwner :: Maybe (PPtr TCB) -> Kernel () | |
switchLocalFpuOwner newOwner = do | |
doMachineOp enableFpu | |
curFpuOwner <- gets (armKSCurFPUOwner . ksArchState) | |
for curFpuOwner saveFpuState | |
case newOwner of | |
Nothing -> doMachineOp disableFpu | |
Just tcbPtr -> loadFpuState tcbPtr | |
modifyArchState (\s -> s { armKSCurFPUOwner = newOwner }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a good solution here. There's a function maybe
in Data.Maybe
that we could use with maybe (return ()) saveFpuState curFpuOwner
that we could make an alias for to remove the return ()
part, but then the return values have to match so it would only work for unit returns. Otherwise you could return undefined
with the correct type (whatever 'b
the function returns). How does for
get through the Haskell translator? I don't think we have something like that in Isabelle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, for
won't get through the translator without doing something manual, so on second thought probably shouldn't use it.
I think I'm ok with your maybe
idea, particularly since now that I look at it, that's basically how whenJust
is implemented. It lines up pretty well with maybeM
as well, which requires a unit return.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Context: the FIXME was originally because we weren't sure whether dealing with
if
orcase
would be easier in thecorres
proof, so the plan was to check and then remove the FIXME afterwards
Good point, and also works as a reminder that there's two things going on here. There's switching the when
to a maybeM
which I think we all agree is nice to avoid the
, and there's whether it should if
or case
, where case
is again nice in that it avoids the
but it is unknown which will be easier in the proofs. How about for now I switch it to case
but leave the FIXME until we get to the proofs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I'd be happy with that
definition isFpuEnable :: "bool machine_monad" where | ||
"isFpuEnable \<equiv> return True" | ||
"isFpuEnable \<equiv> gets fpu_enabled" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does anyone remember why this is called isFpuEnable
in C and not isFpuEnabled
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably Englishes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, no idea beyond that. Should we give it the better name here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to, but then it would be good to also rename it in C.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! I only had cosmetic comments.
We should probably target this to a new branch to use until the proofs are done and the entire thing can be merged into master.
3aaac5d
to
285ecfc
Compare
7a5943d
to
f1fb45c
Compare
This includes extending the machine interface with new ops, adding the current owner of the FPU state to the kernel state, and adding the new seL4_TCB_Set_Flags syscall and related functions. Signed-off-by: Corey Lewis <[email protected]>
Signed-off-by: Corey Lewis <[email protected]>
f1fb45c
to
31b2feb
Compare
This PR has now been updated with a commit making equivalent changes to the FPU handling code in the x64 specification, and a commit making the required changes to the architectures that are not configured to have FPUs enabled so that they can still be built. |
Signed-off-by: Corey Lewis <[email protected]>
Signed-off-by: Corey Lewis <[email protected]>
Signed-off-by: Corey Lewis <[email protected]>
31b2feb
to
c45b235
Compare
Good to see all tests passing up to AInvs. Nice work! |
These are the preliminary spec changes to seL4 to implement RFC-18. They include extending the machine interface with new ops, adding the current owner of the FPU state to the kernel state, and adding the new seL4_TCB_Set_Flags syscall and related functions.