Open grayresearch opened 8 months ago
On further consideration, I propose these replacments for IStateContext custom functions:
Stateful CX CSRs
Guy requests a new scxs_status bit to indicate whether the selected CX state context is online and able to receive custom instructions or is paused or in a process of being saved or reloaded during a CX state context swithc.
CSR reads / read-writes of of scxs_data are idempotent. Not so, scxs_data_incr. The latter speeds up save and reload of multi-word state context save data.
In addition, Guy has requested uniform optional means to interrogate the current CX's CX_GUID and CXU_GUID. I propose: Stateless or stateful CX CSRs -- all of these are read-only user custom CSRs:
In discussion above, we note we need a replacement for a uniform "probe" sequence to determine if mcx_selector's CXU_ID and STATE_ID are valid. If cx_guid0 custom CSR is compulsory then csrr x0,cx_guid0
is a fine CX selector probe instruction.
If compulsory it should be OK to return 0.0.0.0 for cx_guid and for cxu_guid.
I'm not sure we need to XLEN-ize/32b/64b these.
"Simple, frugal, fast" is an important CX design tenet. How does this redesign of IStateContext now with 5 32b custom CSRs, and then adding another 8 read-only CSRs comport with that?
As for the read-only CSRs, if cx_guid and cxu_guid are mandatory CX CSRs, but may read as 0, we just need a way for any CXU to respond with zero without requiring that every CXU contain a separate copy of logic to generate a 0 value on resp_data.
If cx_guid* is not mandatory you can still do a mcx_selector probe with this sequence
csrw cx_status,x0
csrr x0,cx_guid0 ; probe!
csrr x1,cx_status
; if x1==0 or x1.IF, the selector is valid.
; if x1.IC or x1.IS, the selector is invalid.
Not as efficient as just testing x1 == 0
though.
Should there be a way for a stateful CX to indicate "I am NOT serializable" or even "I am NOT serializable AT THIS MOMENT" in the read-only system composition information (i.e. CXU Map) or in the CX state context CSRs?
In this ongoing redesign with CX CSRs, let's discuss some issues of CX state context initialization and reinitialization.
(First note that since each CX state context is isolated, the state of a CX is usually determined solely by the prior series of CX operations issued since initialization. In some cases, but not always, a CX is deterministic in that the same series of CX operations since initialization always produces the same series of results.)
The spec proposes CX-agnostic CX state context management. The acid test is that a CX-aware OS can manage the CX state context of any CX without change, and without any CX-specific code. This requires the OS to access configured-CX-specific data and behavior, perhaps provided statically in the CXU Map, perhaps provided dynamically by the CXU hardware.
Context management includes context save and context restore, but it also includes context initialization / reinitialization.
Presently the spec provides CX-agnostic initialization via the .CS field of the CX state context status word, accessed by the IStateContext custom function instructions cf_{read,write}_status
. Initialization: "On system reset, each state context of a serializable stateful extension CXU is in the initial state." Reinitialization: "A write .cs=1 has the side effect of resetting the entire current state context to its initial (power up) state."
This provides simple CX-agnostic initialization, but there are several problems:
mstatus
work when set to Initial. For example, the priv spec notes "nor does setting FS=Initial clear the contents. Rather (per priv spec) software must perform an extension-specific set of instructions to re-initialize the extension state context. But this (extension-specific code) is not what we want for CX.(TODO: We need a new Issue tracking configurable maximum latency of any CX operation.)
Note that for every CXU that requires O(size) cycles for initialization, there will be others with "flash clear" in O(1) cycles, using flop resets, seqnum-tagged structures, or other methods. For a large CX state context, flash clear initialization may be the difference between a CX code speedup and a code slowdown. The spec should support both O(size) and O(1) type initialization CXUs.
scxs_status.cs=init=1
. CSR-writing this would start initialization but would not block on its completion. A new read-only scxs_status.busy
status bit could signal to software that CX state context initialization is underway but has not completed. Software could spin-wait until !scxs_status.busy
-- and perhaps do something else useful in the meantime. This would allow software to request a (hopefully O(1)) CX state context flash clear init, but also cope with an O(size) initialization when necessary, and perhaps do something else useful while it waits for !busy
.By keeping initialization as the sole responsibility of a CXU, operating autonomously and asynchronously to the CPU, it spares the CPU from wasteful energy sending O(size) CXU requests and receiving O(size) CXU responses, as a context reload would. (It is not perfect as there is still the energy of !scxs_status.busy
spin-waiting. Perhaps a new wait instruction could sleep pending any CXU operation becoming unbusy. (Ugh!) This would require a small change to CXU-LI.)
Background
CX State Contexts: A composable extension may be stateful. Abstractly that means the behavior of a CX instruction may depend upon the history of CX instructions previously issued. More concretely, a CX may have one or more state contexts, each encompassing state machines, registers, register files, RAMs, channels, etc. For correct composition, CX state is private and isolated to a CX. It is not manifest as shared memory. The only way to access, observe, or modify CX state is to issue CX instructions. When CX multiplexing is enabled, the current CX selector identifies the hart's current CX and CX state context. This determines the CX that receives CX (custom) instructions and which state context is accessed.
Stateful CXs are common and therefore merit uniform programming models, uniform resource management, etc.
IStateContext: The Spec (%1.4.4 %2.1 %2.5 %2.6) defines a composable extension basetype IStateContext with four mandatory custom instructions: cf{read,write}{status,state}. Every stateful CX must implement these four instructions. They are used by a resource manager (RM) such as an operating system to uniformly manage, initialize, save, and restore a CX's state context. With this interface an RM can manage and context-switch any CX state context, in other words, CX-agnostic context switching. This works even for CXs that have yet to be designed. This is in contrast to systems where every new bit of architectural state requires OS updates or device drivers.
The spec'd cf_read_status and cs_write_status instructions read and write the CX state context status word. This word's fields:
provides:
The cf_read_state and cf_write_state instructions read and write specified words of the state context.
As described in %2.6 Resource management and context switching, an RM uses read_status to determine how large the CX's context save record must be; it then uses read_state to read each word of state out of the CX state context. Later on state context reload (restore), the RAM uses write_status to restore the state context state word, and write_state to restore the state context data words. The RM will also use write_status to reinitialize a CX state context to its initial state.
Some current shortcomings of the IStateContext instructions
CX State Context CX CSRs
Assuming we adopt #27, we might replace the four mandatory IStateContext instructions with a few mandatory CX CSRs. For example, cf_read_status, cf_write_status instructions, which R/W the CX state context status word, might be directly replaced by a new S-priv accessible R/W CX CSR, scxct_status. Similarly, cf_read_state and cf_write_state might be replaced by a new S-priv accessable R/W CX CSR, scxct_data.
scxct_status: this CX CSR would carry forward the .cs, .state_size, and .error fields of the %2.5.1 state context status word, and retain the various behaviors and semantics detailed in %2.5.2 cf_read_status and %2.5.3 cf_write_status.
scxct_data: not so straightforward! Both cf_read_state and cf_write_state instructions have an index operand specifying which word of the context data to access. This affords random access to CX state context save data words.
However, there is no way to specify that index with a CSR access instruction. Compare:
As discussed above ("too expensive"), perhaps random access to state context save data words is overkill. Instead, imagine an implicit index counter, or other state machine, is kept by each CX state context. That "index" might be reset to 0 / first word by reading or writing scxct_status. Then each success read or write of scxct_data might advance the "index".
Then you can save a CX state context via:
Note this new design does not allow you to:
That may be unacceptable. These use cases can be addressed by reifying the state context's internal data index counter, i.e., add an scxct_index counter CX CSR that determines the next state context data word to be access. So e.g., to restore the 10th, 11th, 12th words of a CX state context, issue:
It is still a bit fragile. Please comment on better ideas for the specific CX State Context CX CSRs.
We also note that since scxct_status is not U-mode accessible, it can no longer be used to access custom error state. The .error field will have to be moved to a new user-mode CX CSR.
CX state front door vs back door
A brief aside to note that there are two access paths to CX state, and how these relate.
The front door, if you will, are the user-mode CX CSRs provided by the CX. A CX might provide CX CSRs to set up operating modes, parameters, vector widths, etc. In addition there are the CX custom instructions themselves, which can also be used to obtain various facets of a CX's state. These front door access paths are specific to that CX.
The back door, in contrast, is the CX State Context CX CSRs. These are used by RMs to initialize, save, restore, and otherwise manage CX state contexts. This back door access path is generic to any CX. The RM must not interpret the context save data it obtains and maintains. Each context save data array is just a blob of bits. (*) The RM should not use CX-specific CX CSRs.
(*) Indeed, as %2.5.1 notes "
The CXU that implements the CX provides CX-specific CX CSRs that change its internal state, but that state, as well as other CX state, is nevertheless serialized and deserialized by RMs using the CX-agnostic CX State Context CX CSRs.
It goes in both forwards and backwards directions. Start: User code sets its CX properties "MyCX-props" with a CX CSR write. Context save: The RM serializes the CX state into a blob, using csrr scxct_status and csrr scxct_state. Somewhere in the blob are the properties the user set. The RM doesn't know or care. ... context switch ... context switch ... etc ... Context restore: The RM deserializes the CX state from the blob, using csrw scxct_status and csrw scxct_state. User code retrieves its "MyCX-props" with a CX CSR read. User code observes the property settings it previously set at 'Start'.
No more reserved CX custom instructions?
Assuming we replace IStateContext, it is possible there is no further need for the reserved CX custom instruction CF_IDs.
%2.5: "CF_IDs 1008-1023 (0x3F0-0x3FF) are reserved for standard custom functions. It is recommended, not mandatory, that these CF_IDs not be used for another purpose. ... Any CF instruction with CF_ID=1023 must be side effect free, i.e., never modify any CXU state."
We have no present use for these now. But if we delete this reservation it will be more difficult to add mandatory CX custom instructions later.
Also note the spec uses cf_read_status to provide a specific way to probe that a selected CXU is actually present:
%2.5.2: "cx_read_status may be used as a probe after a mcx_selector write, to check whether the selector addresses a valid CXU and state context:
But eliminating cf_read_status we no longer have a CX-agnostic way to do this probe. The analogy would be to
except that stateless CXs need not implement scxct_status CX CSR, and scxct_status is not accessible to user code!
Oops. Not sure what to do here. I think the cleanest thing to do is split scxct_status into two CX CSRs. One would be a user-accessible R/W custom CX CSR that carries e.g. the custom error number. The second would be a system-accessible R/W custom CX CSR used for CX context managment. Hmm.
Summary
We recommend replacing IStateContext instructions with CX State Context CX CSRs. The CX State Context CX CSRs are mandatory for all stateful CXs. These CSRs addresses can be specified so as to deny state context management access to user mode code.
The specific CX State Context CX CSRs should include a state context status CSR and a state context data CSR. We may require additional CX CSRs to specify phases of context save or restore, or to specify random access into state context data. TBD.
We recommend eliminating the 16 reserved CX custom instructions. Unclear if scxct_status is mandatory for stateless CXs.