kernel/protocols: Introduce OCP support#1138
Conversation
7fc1d46 to
bb9de70
Compare
|
Is this meant to be a Coconut specific protocol or a general any SVSM implementation protocol. If the latter, then it needs to be worked out properly and added to the SVSM specification. If the former, then it will need to use one of the reserved reference implementation protocol numbers and needs to be documented for Coconut. |
|
v2:
|
@tlendacky This is part of my work for google summer of code in the coconut-svsm[1]. This is based on the draft proposal of @joergroedel posted in the mailing list [2]. I believe this will be general for any SVSM implementation protocol. Sorry for not mentioning this earlier in the PR description. Now it's updated. [1] https://wiki.qemu.org/Google_Summer_of_Code_2026 |
The discussion on the protocol died off without conclusion, so I'll use the opportunity to resume it here. I still think it makes sense to include some information what type of data is returned by a source in the SVSM_OCP_LIST reply (i.e. what became The other two ideas from my mail ( |
bb9de70 to
aafa334
Compare
|
v3:
|
aafa334 to
23bae4b
Compare
|
v4:
|
23bae4b to
27937c4
Compare
|
v5:
|
| fn write(&self, _offset: u32, _gpa: PhysAddr, _size: u32) -> Result<u32, SvsmReqError> { | ||
| Err(SvsmReqError::unsupported_call()) | ||
| } | ||
| fn get_source_entry(&self) -> &OcpSource; |
There was a problem hiding this comment.
Does it make sense to allow the trait support multiple sources, so objects implementing the trait are not limited to one?
There was a problem hiding this comment.
Wouldn't we lose direct indexing of the source array in this case?
There was a problem hiding this comment.
It would make things a bit more complicated, yes. You'd need an array with pointer and source index for example. Not fully sure this is a good path forward, maybe it is easier to just create one object per source.
I was wondering if -- for example -- the snp platform object wants allow multiple things being observed such as platform feature flags and cbit position. How would that be done? I see two possible approaches:
- Implement the Trait for the platform object + allow multiple sources, or
- Create one object (may or may not be embedded in the platform struct) per source.
The new observability and configuration protocol requires an additional register `r9` to exchange data between svsm and the guest os. Add it to the `RequestParams` structure to fulfil this requirement. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
Add a new structure, based on OCP protocol specifications. A source entry has a 4-byte bitfield flag field, where the least significant bit specifies if a sources is writable or not. The other bits are reserved. Additionally, a source entry includes a 120-byte utf-8 encoded name. Introduce a new const constructor which can be used for initializing a source. This function will fail if the name is greater than or equal to 120 bytes, as we want the name to be null terminated. If the name is less than that value, it will be padded with zeros. Also include a `kind` field to store information on the source type. This will help the guest understand which data is transmitted and the dimension required for the buffer to store these values. As these sources will be passed to the linux guest, it is useful to derive `IntoBytes` and `Immutable` for the transfer. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
Add a trait that must be implemented by each source in order to be used in the protocol. The trait includes a default implementation for the `read` and `write` methods, as each source may not have that functionality, in which case an error is returned. The trait also includes a way to retrieve a reference to the source. This can be useful for iterating over the list of sources, getting the entry and assembling the reply to the guest OS. Require the `Sync` bound as we want to share objects between threads safely. Introduce the new OCP source array, where each entry should implement the new trait, making it an array of trait objects. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
The new Observability and Configuration Protocol (OCP) has a protocol ID value of 5. Add it to the list of known protocols in svsm. Link it to the correct handler during request processing. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
Add the new call identifier (`0`) to the OCP handler and implement `SVSM_OCP_LIST` following the spec. If some guest params are incorrect, like buffer alignment or zero entries requested, an appropriate error will be returned. The index and the number of entries are 4-bytes, so make sure to use only the low 32 bits. Since ranges require usize and the constants are usize, convert these values to usize before using them for simplicity. Since the guest address is untrusted, handle the check for a valid and non overlapping region. Additionally, use `PerCPUPageMappingGuard` and `GuestPtr` to safely map and point that region. As this call requires SVSM to provide a list of entries, compute the correct range of entries and extract them from the static `OCP_SOURCES` by iterating over the array and exploiting the `get_source_entry` method from the new trait. Once an entry is available, it is possible to copy it directly to the guest memory without using temporary heap allocation to store all the entries together. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
Add the new call identifier (`1`) to the OCP handler and implement `SVSM_OCP_READ` following the spec. If some guest params are incorrect, like buffer alignment or out of bound index, an appropriate error will be returned. The index, the offset and the number of bytes to read are 4-bytes, so make sure to use only the low 32 bits. Since constants are usize, convert these values to usize before using them for simplicity. Since each entry is required to implement the `OcpSourceOperations` trait, the read method can be exploited to read the bytes from the source. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
Add the new call identifier (`2`) to the OCP handler and implement `SVSM_OCP_WRITE` following the spec. If some guest params are incorrect, like buffer alignment or out of bound index, an appropriate error will be returned. The index, the offset and the number of bytes to write are 4-bytes, so make sure to use only the low 32 bits. Since constants are usize, convert these values to usize before using them for simplicity. Since each entry is required to implement the `OcpSourceOperations` trait, the write method can be exploited to write the bytes into the source. Only sources marked with the `writable` flag can be written, otherwise an error is returned. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
The query protocol is used to check the availability of a protocol at a given version. It should take into account every available protocol. Add the new OCP protocol management. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
Introduce a read only source that only returns a static string containing the current SVSM version. As the string will always be the same, it can be classified as a static string. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
Add a source who read and write on an atomic value. Write operations simply add 1 to the current value. Signed-off-by: Nicola Ramacciotti <niko.ramak@gmail.com>
27937c4 to
0b6a3b6
Compare
|
v6:
Todo:
|
RFC PR for observability and configuration protocol.
This is part of my work for Google Summer of code [1] based on the draft protocol posted in the mailing list[2].
For the moment only
SVSM_OCP_LISTcall is tested.SVSM_OCP_READandSVSM_OCP_WRITEare here, but yet to be tested.I'm not sure what should be the name of the 124-byte sources.Commit messages should be improved. For now, I just wanted to share the current state.
The basic structure forSVSM_OCP_WRITEandSVSM_OCP_READis here, but for the moment it only returns an error.To test this, it is possible to use one of these two branches in my linux fork (based on tag v7.1):
ocp.komodule that can be loaded and will do a single call toSVSM_OCP_LISTduring initialization. The parameter of this call can be changed based on a configuration parameter that can be specified when inserting the module. This can be inserted and removed multiple times.These tests print to the log with
pr_err. ( For some reason, I couldn't seepr_info, but I don't think that for now is a problem). The tests respectively:note: This is not the final linux driver version, but can be useful for testing the svsm side.
note: This require the vm to have a custom guest kernel with the above commits.
In the next few days, I will probably open a PR with the first version to better show the difference in the coconut linux fork. (edit: see coconut-svsm/linux#20)
Tested on a SNP machine. (Thanks @joergroedel )
/cc @stefano-garzarella @kraxel
TODO:
For read and write, is required the index. I'm not sure if it is needed to modify theOcpSourceto add some function. Another array based on the index of the source can be used to keep track of the correct entry function. I should look more into this.[1] https://wiki.qemu.org/Google_Summer_of_Code_2026
[2] https://lore.kernel.org/coconut-svsm/aeiLnWdClMC6YuLi@sirius.home.kraxel.org/T/#t