• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / alioth / 17385983897

01 Sep 2025 07:41PM UTC coverage: 18.009% (-0.1%) from 18.149%
17385983897

Pull #281

github

web-flow
Merge 782c57b11 into 6ec9a6d6b
Pull Request #281: Port to Apple Hypervisor framework

0 of 154 new or added lines in 11 files covered. (0.0%)

1166 existing lines in 29 files now uncovered.

1362 of 7563 relevant lines covered (18.01%)

18.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/alioth/src/hv/hvf/vcpu/vcpu.rs
1
// Copyright 2024 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
mod vmentry;
16
mod vmexit;
17

18
use std::collections::HashMap;
19
use std::io::ErrorKind;
20
use std::sync::Arc;
21
use std::sync::mpsc::{Receiver, Sender};
22

23
use parking_lot::Mutex;
24
use snafu::ResultExt;
25

26
use crate::arch::reg::{MpidrEl1, Reg, SReg};
27
use crate::hv::hvf::bindings::{
28
    HvExitReason, HvReg, HvVcpuExit, hv_vcpu_destroy, hv_vcpu_get_reg, hv_vcpu_get_sys_reg,
29
    hv_vcpu_run, hv_vcpu_set_reg, hv_vcpu_set_sys_reg,
30
};
31
use crate::hv::hvf::check_ret;
32
use crate::hv::hvf::vm::VcpuEvent;
33
use crate::hv::{Result, Vcpu, VmEntry, VmExit, error};
34

35
#[derive(Debug)]
36
pub struct HvfVcpu {
37
    pub exit: *mut HvVcpuExit,
38
    pub vcpu_id: u64,
39
    pub vmexit: Option<VmExit>,
40
    pub exit_reg: Option<HvReg>,
41
    pub senders: Arc<Mutex<HashMap<MpidrEl1, Sender<VcpuEvent>>>>,
42
    pub receiver: Receiver<VcpuEvent>,
43
    pub power_on: bool,
44
}
45

46
impl HvfVcpu {
NEW
47
    fn handle_event(&mut self, event: &VcpuEvent) -> Result<()> {
×
NEW
48
        match event {
×
NEW
49
            VcpuEvent::PowerOn { pc, context } => {
×
NEW
50
                self.set_regs(&[(Reg::Pc, *pc), (Reg::X0, *context), (Reg::Pstate, 5)])?;
×
NEW
51
                self.power_on = true;
×
52
            }
NEW
53
            VcpuEvent::PowerOff => self.power_on = false,
×
54
        }
NEW
55
        Ok(())
×
56
    }
57
}
58

59
impl Drop for HvfVcpu {
60
    fn drop(&mut self) {
×
61
        let ret = unsafe { hv_vcpu_destroy(self.vcpu_id) };
×
62
        if let Err(e) = check_ret(ret) {
×
63
            log::error!("hv_vcpu_destroy: {e:?}");
×
64
        }
65
    }
66
}
67

68
enum HvfReg {
69
    Reg(HvReg),
70
    SReg(SReg),
71
}
72

73
impl Reg {
74
    fn to_hvf_reg(self) -> HvfReg {
×
75
        match self {
×
76
            Reg::X0 => HvfReg::Reg(HvReg::X0),
×
77
            Reg::X1 => HvfReg::Reg(HvReg::X1),
×
78
            Reg::X2 => HvfReg::Reg(HvReg::X2),
×
79
            Reg::X3 => HvfReg::Reg(HvReg::X3),
×
80
            Reg::X4 => HvfReg::Reg(HvReg::X4),
×
81
            Reg::X5 => HvfReg::Reg(HvReg::X5),
×
82
            Reg::X6 => HvfReg::Reg(HvReg::X6),
×
83
            Reg::X7 => HvfReg::Reg(HvReg::X7),
×
84
            Reg::X8 => HvfReg::Reg(HvReg::X8),
×
85
            Reg::X9 => HvfReg::Reg(HvReg::X9),
×
86
            Reg::X10 => HvfReg::Reg(HvReg::X10),
×
87
            Reg::X11 => HvfReg::Reg(HvReg::X11),
×
88
            Reg::X12 => HvfReg::Reg(HvReg::X12),
×
89
            Reg::X13 => HvfReg::Reg(HvReg::X13),
×
90
            Reg::X14 => HvfReg::Reg(HvReg::X14),
×
91
            Reg::X15 => HvfReg::Reg(HvReg::X15),
×
92
            Reg::X16 => HvfReg::Reg(HvReg::X16),
×
93
            Reg::X17 => HvfReg::Reg(HvReg::X17),
×
94
            Reg::X18 => HvfReg::Reg(HvReg::X18),
×
95
            Reg::X19 => HvfReg::Reg(HvReg::X19),
×
96
            Reg::X20 => HvfReg::Reg(HvReg::X20),
×
97
            Reg::X21 => HvfReg::Reg(HvReg::X21),
×
98
            Reg::X22 => HvfReg::Reg(HvReg::X22),
×
99
            Reg::X23 => HvfReg::Reg(HvReg::X23),
×
100
            Reg::X24 => HvfReg::Reg(HvReg::X24),
×
101
            Reg::X25 => HvfReg::Reg(HvReg::X25),
×
102
            Reg::X26 => HvfReg::Reg(HvReg::X26),
×
103
            Reg::X27 => HvfReg::Reg(HvReg::X27),
×
104
            Reg::X28 => HvfReg::Reg(HvReg::X28),
×
105
            Reg::X29 => HvfReg::Reg(HvReg::X29),
×
106
            Reg::X30 => HvfReg::Reg(HvReg::X30),
×
107
            Reg::Sp => HvfReg::SReg(SReg::SP_EL0),
×
108
            Reg::Pc => HvfReg::Reg(HvReg::PC),
×
109
            Reg::Pstate => HvfReg::Reg(HvReg::CPSR),
×
110
        }
111
    }
112
}
113

114
impl Vcpu for HvfVcpu {
NEW
115
    fn reset(&mut self, is_bsp: bool) -> Result<()> {
×
NEW
116
        self.power_on = is_bsp;
×
NEW
117
        Ok(())
×
118
    }
119

120
    fn dump(&self) -> Result<()> {
×
121
        unimplemented!()
122
    }
123

124
    fn run(&mut self, entry: VmEntry) -> Result<VmExit> {
×
125
        match entry {
×
126
            VmEntry::None => {}
×
NEW
127
            VmEntry::Mmio { data } => self.entry_mmio(data)?,
×
128
            VmEntry::Shutdown => return Ok(VmExit::Shutdown),
×
129
            _ => unimplemented!("{entry:?}"),
130
        }
NEW
131
        if !self.power_on {
×
NEW
132
            let Ok(event) = self.receiver.recv() else {
×
NEW
133
                return Err(ErrorKind::BrokenPipe.into()).context(error::RunVcpu);
×
134
            };
NEW
135
            self.handle_event(&event)?;
×
NEW
136
            if !self.power_on {
×
NEW
137
                return Ok(VmExit::Shutdown);
×
138
            }
139
        }
140
        loop {
NEW
141
            let ret = unsafe { hv_vcpu_run(self.vcpu_id) };
×
NEW
142
            check_ret(ret).context(error::RunVcpu)?;
×
143

NEW
144
            while let Ok(event) = self.receiver.try_recv() {
×
NEW
145
                log::info!("received {event:?}");
×
NEW
146
                self.handle_event(&event)?;
×
NEW
147
                if !self.power_on {
×
NEW
148
                    return Ok(VmExit::Shutdown);
×
149
                }
150
            }
151

NEW
152
            let exit = unsafe { &*self.exit };
×
NEW
153
            match exit.reason {
×
154
                HvExitReason::EXCEPTION => {
NEW
155
                    self.handle_exception(&exit.exception)?;
×
156
                }
157
                _ => {
NEW
158
                    break error::VmExit {
×
NEW
159
                        msg: format!("{exit:x?}"),
×
160
                    }
NEW
161
                    .fail();
×
162
                }
163
            }
NEW
164
            if let Some(exit) = self.vmexit.take() {
×
165
                break Ok(exit);
166
            }
167
        }
168
    }
169

170
    fn get_reg(&self, reg: Reg) -> Result<u64> {
×
171
        let hvf_reg = reg.to_hvf_reg();
×
172
        let mut val = 0;
×
173
        let ret = match hvf_reg {
×
174
            HvfReg::Reg(r) => unsafe { hv_vcpu_get_reg(self.vcpu_id, r, &mut val) },
×
175
            HvfReg::SReg(r) => unsafe { hv_vcpu_get_sys_reg(self.vcpu_id, r, &mut val) },
×
176
        };
177
        check_ret(ret).context(error::VcpuReg)?;
×
178
        Ok(val)
×
179
    }
180

181
    fn set_regs(&mut self, vals: &[(Reg, u64)]) -> Result<()> {
×
182
        for (reg, val) in vals {
×
183
            let hvf_reg = reg.to_hvf_reg();
×
184
            let ret = match hvf_reg {
×
185
                HvfReg::Reg(r) => unsafe { hv_vcpu_set_reg(self.vcpu_id, r, *val) },
×
186
                HvfReg::SReg(r) => unsafe { hv_vcpu_set_sys_reg(self.vcpu_id, r, *val) },
×
187
            };
188
            check_ret(ret).context(error::VcpuReg)?;
×
189
        }
190
        Ok(())
×
191
    }
192

193
    fn get_sreg(&self, reg: SReg) -> Result<u64> {
×
194
        let mut val = 0;
×
195
        let ret = unsafe { hv_vcpu_get_sys_reg(self.vcpu_id, reg, &mut val) };
×
196
        check_ret(ret).context(error::VcpuReg)?;
×
197
        Ok(val)
×
198
    }
199

200
    fn set_sregs(&mut self, sregs: &[(SReg, u64)]) -> Result<()> {
×
201
        for (reg, val) in sregs {
×
202
            let ret = unsafe { hv_vcpu_set_sys_reg(self.vcpu_id, *reg, *val) };
×
203
            check_ret(ret).context(error::VcpuReg)?;
×
204
        }
205
        Ok(())
×
206
    }
207
}
208

209
#[cfg(test)]
210
mod test {
211
    use std::ptr::null_mut;
212

213
    use assert_matches::assert_matches;
214
    use libc::{MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, PROT_READ, PROT_WRITE, mmap};
215

216
    use crate::arch::reg::Reg;
217
    use crate::ffi;
218
    use crate::hv::{Hvf, Hypervisor, MemMapOption, Vcpu, Vm, VmConfig, VmEntry, VmExit, VmMemory};
219

220
    #[test]
221
    #[cfg_attr(not(feature = "test-hv"), ignore)]
222
    fn test_vcpu_regs() {
223
        let hvf = Hvf {};
224
        let config = VmConfig { coco: None };
225
        let vm = hvf.create_vm(&config).unwrap();
226
        let mut vcpu = vm.create_vcpu(0).unwrap();
227
        let regs = [
228
            (Reg::X0, 0),
229
            (Reg::X1, 1),
230
            (Reg::X2, 2),
231
            (Reg::X3, 3),
232
            (Reg::X4, 4),
233
            (Reg::X5, 5),
234
            (Reg::X6, 6),
235
            (Reg::X7, 7),
236
            (Reg::X8, 8),
237
            (Reg::X9, 9),
238
            (Reg::X10, 10),
239
            (Reg::X11, 11),
240
            (Reg::X12, 12),
241
            (Reg::X13, 13),
242
            (Reg::X14, 14),
243
            (Reg::X15, 15),
244
            (Reg::X16, 16),
245
            (Reg::X17, 17),
246
            (Reg::X18, 18),
247
            (Reg::X19, 19),
248
            (Reg::X20, 20),
249
            (Reg::X21, 21),
250
            (Reg::X22, 22),
251
            (Reg::X23, 23),
252
            (Reg::X24, 24),
253
            (Reg::X25, 25),
254
            (Reg::X26, 26),
255
            (Reg::X27, 27),
256
            (Reg::X28, 28),
257
            (Reg::X29, 29),
258
            (Reg::X30, 30),
259
            (Reg::Sp, 0x1000),
260
            (Reg::Pc, 0x2000),
261
            (Reg::Pstate, 0xf << 28),
262
        ];
263
        vcpu.set_regs(&regs).unwrap();
264
        for (reg, val) in regs {
265
            assert_eq!(vcpu.get_reg(reg).unwrap(), val);
266
        }
267
    }
268

269
    #[test]
270
    #[cfg_attr(not(feature = "test-hv"), ignore)]
271
    fn test_vcpu_run() {
272
        let hvf = Hvf {};
273
        let config = VmConfig { coco: None };
274
        let mut vm = hvf.create_vm(&config).unwrap();
275
        let memory = vm.create_vm_memory().unwrap();
276

277
        let prot = PROT_WRITE | PROT_READ;
278
        let flag = MAP_ANONYMOUS | MAP_PRIVATE;
279
        let user_mem = ffi!(
280
            unsafe { mmap(null_mut(), 0x4000, prot, flag, -1, 0,) },
281
            MAP_FAILED
282
        )
283
        .unwrap();
284
        let mmap_option = MemMapOption {
285
            read: true,
286
            write: true,
287
            exec: true,
288
            ..Default::default()
289
        };
290
        memory
291
            .mem_map(0, 0x4000, user_mem as usize, mmap_option)
292
            .unwrap();
293

294
        const CODE: [u8; 20] = [
295
            0x00, 0x00, 0x8a, 0xd2, // mov x0, #0x5000
296
            0x01, 0x00, 0x40, 0xf9, // ldr x1, [x0]
297
            0x21, 0x10, 0x00, 0x91, // add x1, x1, #4
298
            0x00, 0x01, 0x8a, 0xd2, // mov x0, #0x5008
299
            0x01, 0x00, 0x00, 0xf9, // str x1, [x0]
300
        ];
301
        unsafe { ((user_mem as usize + 0x1000) as *mut [u8; 20]).write(CODE) };
302

303
        let mut vcpu = vm.create_vcpu(0).unwrap();
304
        vcpu.reset(true).unwrap();
305
        vcpu.set_regs(&[(Reg::Pc, 0x1000)]).unwrap();
306
        assert_matches!(
307
            vcpu.run(VmEntry::None),
308
            Ok(VmExit::Mmio {
309
                addr: 0x5000,
310
                write: None,
311
                size: 8
312
            })
313
        );
314
        assert_matches!(
315
            vcpu.run(VmEntry::Mmio { data: 0x10 }),
316
            Ok(VmExit::Mmio {
317
                addr: 0x5008,
318
                write: Some(0x14),
319
                size: 8
320
            })
321
        );
322
        assert_matches!(vcpu.run(VmEntry::Shutdown), Ok(VmExit::Shutdown))
323
    }
324
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc