1use std::os::fd::AsRawFd;
7
8use super::Hcl;
9use super::HclVp;
10use super::MshvVtl;
11use super::NoRunner;
12use super::ProcessorRunner;
13use crate::GuestVtl;
14use crate::ioctl::Error;
15use crate::ioctl::GetRegError;
16use crate::ioctl::HvError;
17use crate::ioctl::SetRegError;
18use crate::ioctl::ioctls::hcl_realm_config;
19use crate::ioctl::ioctls::hcl_rsi_ipa_state_read;
20use crate::ioctl::ioctls::hcl_rsi_set_mem_perm;
21use crate::ioctl::ioctls::hcl_rsi_sysreg_read;
22use crate::ioctl::ioctls::hcl_rsi_sysreg_write;
23use aarch64defs::SystemReg;
24use aarch64defs::rsi::RSI_PLANE_ENTER_FLAGS_TRAP_SIMD;
25use aarch64defs::rsi::RSI_PLANE_GIC_NUM_LRS;
26use aarch64defs::rsi::RSI_PLANE_NR_GPRS;
27use aarch64defs::rsi::cca_rsi_plane_entry;
28use aarch64defs::rsi::cca_rsi_plane_exit;
29use aarch64defs::rsi::cca_rsi_plane_run;
30use hvdef::HV_PAGE_SIZE;
31use hvdef::HvArm64RegisterName;
32use hvdef::HvRegisterName;
33use hvdef::HvRegisterValue;
34use memory_range::MemoryRange;
35use sidecar_client::SidecarVp;
36use user_driver::memory::MemoryBlock;
37
38#[derive(Debug, Error)]
39#[expect(missing_docs)]
40pub enum GetIpaStateError {
41 #[error("RSI IPA state read ioctl failed")]
42 Ioctl(#[source] nix::Error),
43}
44
45#[repr(C, align(0x1000))]
47#[derive(Clone, Copy, Default)]
48#[expect(missing_docs)]
49pub struct mshv_realm_config {
50 pub ipa_width: u64,
51 pub algorithm: u64,
52 pub num_aux_planes: u64,
53 pub gicv3_vtr: u64,
54}
55
56#[repr(C)]
59#[derive(Clone, Copy, Default)]
60#[expect(missing_docs)]
61pub struct mshv_rsi_sysreg_rw {
62 pub vtl: u8,
63 pub _pad: [u8; 7],
64 pub sysreg: u64,
65 pub value: u64,
66}
67
68#[repr(C)]
72#[derive(Clone, Copy, Default)]
73#[expect(missing_docs)]
74pub struct mshv_rsi_set_mem_perm {
75 pub plane: u8,
76 pub _pad: [u8; 7],
77 pub base_addr: u64,
78 pub top_addr: u64,
79}
80
81#[repr(C)]
85#[derive(Clone, Copy, Default)]
86pub struct mshv_rsi_get_ipa_state {
87 pub fipa: u64,
89 pub state: u64,
91}
92
93const fn encode_rsi_sysreg(sysreg: SystemReg) -> u64 {
97 ((sysreg.0.op0() as u64) << 14)
98 | ((sysreg.0.op1() as u64) << 11)
99 | ((sysreg.0.crn() as u64) << 7)
100 | ((sysreg.0.crm() as u64) << 3)
101 | (sysreg.0.op2() as u64)
102}
103
104pub struct Cca {
106 plane_run: MemoryBlock,
107}
108
109impl Cca {
110 pub fn new(plane_run: &MemoryBlock) -> Self {
112 assert_eq!(plane_run.offset_in_page(), 0);
113 assert!(plane_run.len() >= size_of::<cca_rsi_plane_run>());
114
115 Self {
116 plane_run: plane_run.clone(),
117 }
118 }
119
120 fn plane_run_ref(&self) -> &cca_rsi_plane_run {
121 unsafe { &*self.plane_run.base().cast::<cca_rsi_plane_run>() }
125 }
126
127 fn plane_run_mut(&mut self) -> &mut cca_rsi_plane_run {
128 unsafe { &mut *self.plane_run.base().cast_mut().cast::<cca_rsi_plane_run>() }
131 }
132
133 fn plane_run_phys(&self) -> u64 {
134 self.plane_run.pfns()[0] * HV_PAGE_SIZE
135 }
136}
137
138impl ProcessorRunner<'_, Cca> {
139 pub fn cpu_context(&self) -> &u64 {
141 unsafe { &*(&raw mut (*self.run.get()).context).cast() }
144 }
145
146 pub fn cpu_context_mut(&mut self) -> &mut u64 {
148 unsafe { &mut *(&raw mut (*self.run.get()).context).cast() }
151 }
152
153 pub fn cca_rsi_plane_run_mut(&mut self) -> &mut cca_rsi_plane_run {
155 self.state.plane_run_mut()
156 }
157
158 pub fn cca_rsi_plane_entry(&mut self) -> &mut cca_rsi_plane_entry {
160 &mut self.state.plane_run_mut().entry
161 }
162
163 pub fn cca_rsi_plane_exit(&self) -> &cca_rsi_plane_exit {
165 &self.state.plane_run_ref().exit
166 }
167
168 pub fn cca_set_entry_flags(&mut self, value: u64) {
170 self.cca_rsi_plane_entry().flags = value;
171 }
172
173 pub fn cca_set_entry_pc(&mut self, value: u64) {
175 self.cca_rsi_plane_entry().pc = value;
176 }
177
178 pub fn cca_set_entry_gprs(&mut self, values: [u64; RSI_PLANE_NR_GPRS]) {
180 self.cca_rsi_plane_entry().gprs = values;
181 }
182
183 pub fn cca_set_entry_gicv3_hcr(&mut self, value: u64) {
185 self.cca_rsi_plane_entry().gicv3_hcr = value;
186 }
187
188 pub fn cca_set_entry_gicv3_lrs(&mut self, values: [u64; RSI_PLANE_GIC_NUM_LRS]) {
190 self.cca_rsi_plane_entry().gicv3_lrs = values;
191 }
192
193 fn cca_set_entry_gpr(&mut self, register: usize, value: u64) {
195 assert!(register < RSI_PLANE_NR_GPRS);
196 self.cca_rsi_plane_entry().gprs[register] = value;
197 }
198
199 fn cca_get_entry_gpr(&self, register: usize) -> u64 {
201 assert!(register < RSI_PLANE_NR_GPRS);
202 self.cca_rsi_plane_exit().gprs[register]
203 }
204
205 pub fn cca_sysreg_write(
207 &mut self,
208 vtl: GuestVtl,
209 name: SystemReg,
210 value: u64,
211 ) -> Result<(), SetRegError> {
212 self.hcl
213 .rsi_sysreg_write(vtl, encode_rsi_sysreg(name), value)
214 }
215
216 pub fn cca_sysreg_read(
218 &mut self,
219 vtl: GuestVtl,
220 name: SystemReg,
221 value: &mut u64,
222 ) -> Result<(), GetRegError> {
223 self.hcl
224 .rsi_sysreg_read(vtl, encode_rsi_sysreg(name), value)
225 }
226
227 pub fn cca_ipa_state_read(&self, fipa: u64) -> Result<Option<u64>, GetIpaStateError> {
229 self.hcl.rsi_get_ipa_state(fipa)
230 }
231
232 pub fn cca_set_plane_enter(&mut self) {
234 let plane_run: &mut u64 = unsafe { &mut *(&raw mut (*self.run.get()).context).cast() };
238 *plane_run = self.state.plane_run_phys();
239 }
240
241 pub fn cca_plane_trap_simd(&mut self) {
243 let plane_run: &mut cca_rsi_plane_run = self.state.plane_run_mut();
244 plane_run.entry.flags |= RSI_PLANE_ENTER_FLAGS_TRAP_SIMD;
245 }
246
247 pub fn cca_plane_no_trap_simd(&mut self) {
250 let plane_run: &mut cca_rsi_plane_run = self.state.plane_run_mut();
251 plane_run.entry.flags &= !RSI_PLANE_ENTER_FLAGS_TRAP_SIMD;
252 }
253
254 pub fn cca_set_default_pstate(&mut self) {
256 self.cca_rsi_plane_entry().pstate = 0x3c5;
258 }
259}
260
261impl<'a> super::BackingPrivate<'a> for Cca {
264 fn new(vp: &HclVp, sidecar: Option<&SidecarVp<'_>>, _hcl: &Hcl) -> Result<Self, NoRunner> {
265 assert!(sidecar.is_none());
266 let super::BackingState::Cca { plane_run } = &vp.backing else {
267 unreachable!()
268 };
269 let cca = Cca::new(plane_run);
270
271 Ok(cca)
272 }
273
274 fn try_set_reg(
275 runner: &mut ProcessorRunner<'a, Self>,
276 _vtl: GuestVtl,
277 name: HvRegisterName,
278 value: HvRegisterValue,
279 ) -> bool {
280 match name.into() {
285 HvArm64RegisterName::X0
286 | HvArm64RegisterName::X1
287 | HvArm64RegisterName::X2
288 | HvArm64RegisterName::X3
289 | HvArm64RegisterName::X4
290 | HvArm64RegisterName::X5
291 | HvArm64RegisterName::X6
292 | HvArm64RegisterName::X7
293 | HvArm64RegisterName::X8
294 | HvArm64RegisterName::X9
295 | HvArm64RegisterName::X10
296 | HvArm64RegisterName::X11
297 | HvArm64RegisterName::X12
298 | HvArm64RegisterName::X13
299 | HvArm64RegisterName::X14
300 | HvArm64RegisterName::X15
301 | HvArm64RegisterName::X16
302 | HvArm64RegisterName::X17
303 | HvArm64RegisterName::X18
304 | HvArm64RegisterName::X19
305 | HvArm64RegisterName::X20
306 | HvArm64RegisterName::X21
307 | HvArm64RegisterName::X22
308 | HvArm64RegisterName::X23
309 | HvArm64RegisterName::X24
310 | HvArm64RegisterName::X25
311 | HvArm64RegisterName::X26
312 | HvArm64RegisterName::X27
313 | HvArm64RegisterName::X28
314 | HvArm64RegisterName::XFp
315 | HvArm64RegisterName::XLr => {
316 runner.cca_set_entry_gpr(
317 (name.0 - HvArm64RegisterName::X0.0) as usize,
318 value.as_u64(),
319 );
320 true
321 }
322 _ => false,
323 }
324 }
325
326 fn must_flush_regs_on(_runner: &ProcessorRunner<'a, Self>, _name: HvRegisterName) -> bool {
327 false
328 }
329
330 fn try_get_reg(
331 runner: &ProcessorRunner<'a, Self>,
332 _vtl: GuestVtl,
333 name: HvRegisterName,
334 ) -> Option<HvRegisterValue> {
335 match name.into() {
339 HvArm64RegisterName::X0
340 | HvArm64RegisterName::X1
341 | HvArm64RegisterName::X2
342 | HvArm64RegisterName::X3
343 | HvArm64RegisterName::X4
344 | HvArm64RegisterName::X5
345 | HvArm64RegisterName::X6
346 | HvArm64RegisterName::X7
347 | HvArm64RegisterName::X8
348 | HvArm64RegisterName::X9
349 | HvArm64RegisterName::X10
350 | HvArm64RegisterName::X11
351 | HvArm64RegisterName::X12
352 | HvArm64RegisterName::X13
353 | HvArm64RegisterName::X14
354 | HvArm64RegisterName::X15
355 | HvArm64RegisterName::X16
356 | HvArm64RegisterName::X17
357 | HvArm64RegisterName::X18
358 | HvArm64RegisterName::X19
359 | HvArm64RegisterName::X20
360 | HvArm64RegisterName::X21
361 | HvArm64RegisterName::X22
362 | HvArm64RegisterName::X23
363 | HvArm64RegisterName::X24
364 | HvArm64RegisterName::X25
365 | HvArm64RegisterName::X26
366 | HvArm64RegisterName::X27
367 | HvArm64RegisterName::X28
368 | HvArm64RegisterName::XFp
369 | HvArm64RegisterName::XLr => Some(
370 runner
371 .cca_get_entry_gpr((name.0 - HvArm64RegisterName::X0.0) as usize)
372 .into(),
373 ),
374 _ => None,
375 }
376 }
377
378 fn flush_register_page(_runner: &mut ProcessorRunner<'a, Self>) {}
379}
380
381#[derive(Debug, Clone, Copy)]
389pub struct RsiRealmConfig {
390 ipa_width: u64,
391 #[expect(unused)]
392 hash_algo: u64,
393 #[expect(unused)]
394 num_aux_planes: u64,
395 #[expect(unused)]
396 gicv3_vtr: u64,
397}
398
399impl RsiRealmConfig {
400 pub fn ipa_width(&self) -> u64 {
402 self.ipa_width
403 }
404}
405
406impl From<mshv_realm_config> for RsiRealmConfig {
407 fn from(value: mshv_realm_config) -> Self {
408 RsiRealmConfig {
409 ipa_width: value.ipa_width,
410 hash_algo: value.algorithm,
411 num_aux_planes: value.num_aux_planes,
412 gicv3_vtr: value.gicv3_vtr,
413 }
414 }
415}
416
417impl MshvVtl {
418 pub fn get_realm_config(&self) -> Result<RsiRealmConfig, Error> {
420 let mut config = mshv_realm_config::default();
421
422 unsafe {
424 hcl_realm_config(self.file.as_raw_fd(), &mut config)
425 .map_err(|_| Error::InvalidRegisterValue)?;
426 }
427
428 Ok(config.into())
429 }
430
431 pub fn rsi_sysreg_write(
433 &self,
434 vtl: GuestVtl,
435 sysreg: u64,
436 value: u64,
437 ) -> Result<(), SetRegError> {
438 let sysreg_write = mshv_rsi_sysreg_rw {
439 vtl: vtl.into(),
440 sysreg,
441 value,
442 ..Default::default()
443 };
444
445 unsafe {
447 hcl_rsi_sysreg_write(self.file.as_raw_fd(), &sysreg_write)
448 .map_err(SetRegError::Ioctl)?;
449 }
450 Ok(())
451 }
452
453 pub fn rsi_sysreg_read(
455 &self,
456 vtl: GuestVtl,
457 sysreg: u64,
458 value: &mut u64,
459 ) -> Result<(), GetRegError> {
460 let mut sysreg_read = mshv_rsi_sysreg_rw {
461 vtl: vtl.into(),
462 sysreg,
463 ..Default::default()
464 };
465
466 unsafe {
468 hcl_rsi_sysreg_read(self.file.as_raw_fd(), &mut sysreg_read)
469 .map_err(GetRegError::Ioctl)?;
470 }
471
472 *value = sysreg_read.value;
473 Ok(())
474 }
475
476 pub fn rsi_set_mem_perm(&self, vtl: GuestVtl, range: &MemoryRange) -> Result<(), HvError> {
478 let plane = match vtl {
479 GuestVtl::Vtl0 => 1,
480 _ => return Err(HvError::InvalidRegisterValue),
481 };
482
483 let set_mem_perm = mshv_rsi_set_mem_perm {
484 plane,
485 _pad: [0; 7],
486 base_addr: range.start(),
487 top_addr: range.end(),
488 };
489
490 unsafe {
492 hcl_rsi_set_mem_perm(self.file.as_raw_fd(), &set_mem_perm)
493 .map_err(|_| HvError::InvalidRegisterValue)?;
494 }
495 Ok(())
496 }
497
498 pub fn rsi_get_ipa_state(&self, fipa: u64) -> Result<Option<u64>, GetIpaStateError> {
500 let mut plane_state = mshv_rsi_get_ipa_state {
501 fipa,
502 state: u64::MAX,
503 };
504
505 unsafe {
507 hcl_rsi_ipa_state_read(self.file.as_raw_fd(), &mut plane_state)
508 .map_err(GetIpaStateError::Ioctl)?;
509 }
510
511 if plane_state.state >= u8::MAX as u64 {
512 return Ok(None);
513 }
514
515 Ok(Some(plane_state.state))
516 }
517}
518
519impl Hcl {
520 pub fn get_realm_config(&self) -> Result<RsiRealmConfig, Error> {
522 self.mshv_vtl.get_realm_config()
523 }
524
525 pub fn rsi_sysreg_write(
527 &self,
528 vtl: GuestVtl,
529 sysreg: u64,
530 value: u64,
531 ) -> Result<(), SetRegError> {
532 self.mshv_vtl.rsi_sysreg_write(vtl, sysreg, value)
533 }
534
535 pub fn rsi_sysreg_read(
537 &self,
538 vtl: GuestVtl,
539 sysreg: u64,
540 value: &mut u64,
541 ) -> Result<(), GetRegError> {
542 self.mshv_vtl.rsi_sysreg_read(vtl, sysreg, value)
543 }
544
545 pub fn rsi_set_mem_perm(&self, vtl: GuestVtl, range: MemoryRange) -> Result<(), HvError> {
547 self.mshv_vtl.rsi_set_mem_perm(vtl, &range)
548 }
549
550 pub fn rsi_get_ipa_state(&self, fipa: u64) -> Result<Option<u64>, GetIpaStateError> {
552 self.mshv_vtl.rsi_get_ipa_state(fipa)
553 }
554}