Open diegonehab opened 1 month ago
After some thought, here is a possibility.
A machine is halted if tohost
has dev=HTIF_DEV_HALT
, cmd=HTIF_HALT_CMD_HALT
, and (data & 1)
.
A machine is yielded manually if tohost
has dev = HTIF_DEV_YIELD
and cmd = HTIF_YIELD_CMD_MANUAL
.
We change the part of the interpret loop that checks for fixed-point yield/halt to the following:
tohost = read_tohost();
if (halted(tohost)) { // dev=HTIF_DEV_HALT, cmd=HTIF_HALT_CMD_HALT, (data & 1)
return break_reason::halted;
}
if (yielded(tohost)) { // dev = HTIF_DEV_YIELD, cmd = HTIF_YIELD_CMD_MANUAL
formhost = read_fromhost();
if (!yielded(fromhost)) { // unless host wrote a response to this htif-yield command...
return break_reason::yielded_manually;
}
// here we know the host responded, so we clear tohost and the machine is not yielded anymore
write_tohost(0);
}
We change the HTIF protocol to be as follows:
From the inside, to use HTIF, guest code writes dev+cmd+data to tohost
. HTIF device itself then clears fromhost
. If device is halt or yield, the run()
returns. From the outside, host can check tohost
to see what is up. To respond to a yield, host copies dev+cmd to fromhost
, but changes the data as desired and resumes the machine. If device was yield and fromhost
has the right combination of dev+cmd
, the machine clears tohost
. From the inside, guest code reads the response in fromhost
.
We also change write_tohost()
to guard against the removal of a halted combination of dev+cmd even from the outside.
Context
Controlling a machine engaged with rollups involves reading and writing to a bunch of different machine CSRs. The introduction of the
send_cmio_response
simplified, but it is still complicated.run
now returns thebreak_reason
, which simplifies it further. But now there are unnecessary redundancies that may cause confusion.Possible solutions
At the moment,
iflags
has fieldsPRV
and theX
,Y
, andH
flags.PRV
really is something internal that the host should never mess with (the current machine privilege level).Let's promote
iflags.PRV
to its own full CSRiprv
. This will simplify the state-access implementations, since they won't have to do field manipulation there anymore.X
,Y
, andH
, on the other hand, are things the host needs to look at and, in the case ofY
, change.There is never a case in which more than one of these flags is set. They are always set via HTIF from the inside.
In the case of
X
andY
, the host will also need to look intohtif.tohost
. This is becausehtif.tohost
contains thereason
for the yield and the amount of data written totx_buffer
.X
is set when the machine returns from an automatic yield. Let's removeX
altogether, since the machinerun
already returns this as a break reason andX
is cleared automatically.Y
when it returns from a manual yield.H
when it is permanently halted.Let's relocate
Y
andH
tohtif.tohost
. With some reorganization there, we can make this happen. (This will also simplify HTIF implementation, since it won't need to change the iflags register anymore.) Let's renameY
toYM
to make the distinction obvious. It's not a generic yield flag, but rather a Manual Yield flag.Perhaps we can be smart and use the
device+cmd
fields together as "the flag", with a few changes to make them uniquely identify the halt and the manual yields.There already are many
WARL
CSRs that prevent certain bits from being changed.htif.tohost
would be one of these. IfH
is set, it would remain set forever. I think we can even use a write tohtif.fromhost
to clearYM
, saving the need to modifyhtif.tohost
when returning from a manual yield.