Skip to content

Fix RISC-V vector state preservation across context switches - #145

Open
whensun wants to merge 4 commits into
IBM:mainfrom
whensun:fix/vector-context-switch
Open

whensun wants to merge 4 commits into
IBM:mainfrom
whensun:fix/vector-context-switch

Conversation

@whensun

@whensun whensun commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Description of the changes

This PR fixes missing RISC-V Vector architectural state preservation during context switches between confidential VMs and the hypervisor.

Previously, vector registers and control/status registers were not saved and restored during context switches, potentially causing vector state corruption.

This PR introduces vector state preservation for:

  • Vector registers v0–v31
  • Vector CSRs vl, vtype, vstart, and vcsr
  • Vector fixed-point state vxrm and vxsat through vcsr

The implementation integrates vector state management into the existing hart architectural state and context-switching mechanisms.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature
  • Breaking change
  • Refactorization

How to test this PR?

  1. Build ACE-RISCV with the RISC-V Vector extension enabled.
  2. Initialize vector registers and CSRs with known values.
  3. Trigger context switches between confidential VMs (VS → VS).
  4. Trigger context switches between a confidential VM and the hypervisor (VS → HS → VS).
  5. Verify that the original vector state is restored.

Signed-off-by: whensun <theodoruswensanfebruanto025@gmail.com>
Signed-off-by: whensun <theodoruswensanfebruanto025@gmail.com>
Signed-off-by: whensun <theodoruswensanfebruanto025@gmail.com>
csrs: ControlStatusRegisters,
fprs: FloatingPointUnit,
sstc: SupervisorTimerExtension,
vector: VectorUnit,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to follow naming convention, should we name it vrs (vector registers) instead of vector?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Renamed vector to vrs in HartArchitecturalState and updated all related accessors and references.

}

if HardwareSetup::is_extension_supported(HardwareExtension::VectorExtension) {
self.csrs().mstatus.read_and_set_bits(SR_VS_DIRTY);

@wojciechozga wojciechozga Nov 6, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a comment (like in FPU-related code) explaining that SR_VS_DIRTY flag enables the vector unit in mstatus, allowing accessing vector-related registers and instructions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Added comments explaining that setting SR_VS_DIRTY enables access to vector registers and instructions.

asm!(
".option push",
".option arch, +v",
concat!("vs1r.v v", stringify!($index), ", ({address})"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vs8r.v stores more registers at a time what reduces the total number of instructions per context switch. An analog approach should be followed for the load from memory

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Replaced the 32 individual register store/load instructions with four vs8r.v instructions and four vl8re8.v instructions.


assert!(vlenb > 0);

let length = NUMBER_OF_VECTOR_REGISTERS.checked_mul(vlenb).expect("Invalid vector register size");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please return an error instead of panicking

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed VectorUnit::empty() to return Result<Self, Error>, with explicit error handling for invalid vector register sizes and allocation failures. I've updated the callers to propagate these errors.

Comment on lines +16 to +20
vlenb: usize,
vl: usize,
vtype: usize,
vstart: usize,
vcsr: usize,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please reuse ReadWriteRiscvCsr similarly to FPU code. Then minimize custom assembly blocks by calling respective functions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

pub unsafe fn save_in_main_memory(&mut self) {
unsafe { self.validate_vlenb() };

@wojciechozga wojciechozga Nov 6, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this checks for every context switch? Wouldn't it be enough to check vlenb once? If vlenb could differ among harts, we should then check it when deciding if V ext should be supported in the initialization procedure. Otherwise, the validate_vlenb should return an error and not panic on a mismatch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved the VLEN validation to initialization instead of checking it during every context switch. The boot hart records the expected vlenb, and each hart validates its value during setup. Invalid or inconsistent values return an error from the validation function.

@wojciechozga wojciechozga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this PR. I left a few comments, please have a look

@whensun

whensun commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

Hi Wojciech,

Thank you for the review. I have addressed all six comments in the latest commit.

The changes include:

  • Renamed vector to vrs.
  • Added comments explaining SR_VS_DIRTY.
  • Replaced individual vector register loads/stores with vs8r.v and vl8re8.v.
  • Added error handling for vector state initialization.
  • Reused ReadWriteRiscvCsr for vector CSRs.
  • Moved VLEN validation to initialization, including per-hart compatibility checks.

Validation:

  • Rust compilation: PASS
  • OpenSBI firmware build: PASS
  • ACE-RISCV regression 8 test cases: PASS

The regression test cases cover vector CSR preservation across VS-to-VS and VS-to-HS-to-VS context switches.

Could you please review the updated implementation when you have a chance?

Thanks!

Signed-off-by: whensun <theodoruswensanfebruanto025@gmail.com>
@whensun
whensun force-pushed the fix/vector-context-switch branch from 9854224 to d237db4 Compare November 7, 2026 21:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants