• 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

29.41
/alioth/src/hv/hvf/vm.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
#[cfg(test)]
16
#[path = "vm_test.rs"]
17
mod tests;
18

19
use std::cmp;
20
use std::collections::HashMap;
21
use std::io::ErrorKind;
22
use std::os::fd::{AsFd, BorrowedFd};
23
use std::ptr::null_mut;
24
use std::sync::mpsc::Sender;
25
use std::sync::{Arc, mpsc};
26
use std::thread::JoinHandle;
27

28
use parking_lot::Mutex;
29
use snafu::ResultExt;
30

31
use crate::arch::reg::{MpidrEl1, SReg};
32
use crate::hv::hvf::bindings::{
33
    HvMemoryFlag, hv_gic_config_create, hv_gic_config_set_distributor_base,
34
    hv_gic_config_set_msi_interrupt_range, hv_gic_config_set_msi_region_base,
35
    hv_gic_config_set_redistributor_base, hv_gic_create, hv_gic_get_spi_interrupt_range,
36
    hv_gic_send_msi, hv_gic_set_spi, hv_vcpu_create, hv_vcpu_set_sys_reg, hv_vcpus_exit,
37
    hv_vm_destroy, hv_vm_map, hv_vm_unmap,
38
};
39
use crate::hv::hvf::vcpu::HvfVcpu;
40
use crate::hv::hvf::{OsObject, check_ret};
41
use crate::hv::{
42
    GicV2, GicV2m, GicV3, IoeventFd, IoeventFdRegistry, IrqFd, IrqSender, Its, MemMapOption,
43
    MsiSender, Result, Vm, VmMemory, error,
44
};
45

46
fn encode_mpidr(id: u32) -> MpidrEl1 {
3✔
47
    let mut mpidr = MpidrEl1(0);
6✔
48
    mpidr.set_aff1(id as u64 >> 3);
9✔
49
    mpidr.set_aff0(id as u64 & 0x7);
9✔
50
    mpidr
3✔
51
}
52

53
#[derive(Debug)]
54
pub struct HvfMemory;
55

56
impl VmMemory for HvfMemory {
57
    fn deregister_encrypted_range(&self, _range: &[u8]) -> Result<()> {
58
        Err(ErrorKind::Unsupported.into()).context(error::EncryptedRegion)
59
    }
60

61
    fn mem_map(&self, gpa: u64, size: u64, hva: usize, option: MemMapOption) -> Result<()> {
62
        if option.log_dirty {
63
            return error::Capability { cap: "log dirty" }.fail();
64
        }
65
        let mut flags = HvMemoryFlag::empty();
66
        if option.read {
67
            flags |= HvMemoryFlag::READ;
68
        }
69
        if option.write {
70
            flags |= HvMemoryFlag::WRITE;
71
        }
72
        if option.exec {
73
            flags |= HvMemoryFlag::EXEC;
74
        }
75
        let ret = unsafe { hv_vm_map(hva as *const u8, gpa, size as usize, flags) };
76
        check_ret(ret).context(error::GuestMap { hva, gpa, size })
77
    }
78

79
    fn register_encrypted_range(&self, _range: &[u8]) -> Result<()> {
80
        Err(ErrorKind::Unsupported.into()).context(error::EncryptedRegion)
81
    }
82

83
    fn unmap(&self, gpa: u64, size: u64) -> Result<()> {
84
        let ret = unsafe { hv_vm_unmap(gpa, size as usize) };
85
        check_ret(ret).context(error::GuestUnmap { gpa, size })?;
86
        Ok(())
87
    }
88

89
    fn mark_private_memory(&self, _gpa: u64, _size: u64, _private: bool) -> Result<()> {
90
        Err(ErrorKind::Unsupported.into()).context(error::EncryptedRegion)
91
    }
92

93
    fn reset(&self) -> Result<()> {
94
        Ok(())
95
    }
96
}
97

98
#[derive(Debug)]
99
pub struct HvfIrqSender {
100
    spi: u32,
101
}
102

103
impl IrqSender for HvfIrqSender {
104
    fn send(&self) -> Result<()> {
105
        let ret = unsafe { hv_gic_set_spi(self.spi, true) };
106
        check_ret(ret).context(error::SendInterrupt)
107
    }
108
}
109

110
#[derive(Debug)]
111
pub struct HvfIrqFd {}
112
impl AsFd for HvfIrqFd {
113
    fn as_fd(&self) -> BorrowedFd<'_> {
114
        unimplemented!()
115
    }
116
}
117
impl IrqFd for HvfIrqFd {
118
    fn get_addr_hi(&self) -> u32 {
119
        unimplemented!()
120
    }
121

122
    fn get_addr_lo(&self) -> u32 {
123
        unimplemented!()
124
    }
125

126
    fn get_data(&self) -> u32 {
127
        unimplemented!()
128
    }
129

130
    fn get_masked(&self) -> bool {
131
        unimplemented!()
132
    }
133

134
    fn set_addr_hi(&self, _val: u32) -> Result<()> {
135
        unimplemented!()
136
    }
137

138
    fn set_addr_lo(&self, _val: u32) -> Result<()> {
139
        unimplemented!()
140
    }
141

142
    fn set_data(&self, _val: u32) -> Result<()> {
143
        unimplemented!()
144
    }
145

146
    fn set_masked(&self, _val: bool) -> Result<bool> {
147
        unimplemented!()
148
    }
149
}
150

151
#[derive(Debug)]
152
pub struct HvfMsiSender;
153

154
impl MsiSender for HvfMsiSender {
155
    type IrqFd = HvfIrqFd;
156

157
    fn create_irqfd(&self) -> Result<Self::IrqFd> {
158
        unimplemented!()
159
    }
160

161
    fn send(&self, addr: u64, data: u32) -> Result<()> {
162
        let ret = unsafe { hv_gic_send_msi(addr, data) };
163
        check_ret(ret).context(error::SendInterrupt)
164
    }
165
}
166

167
#[derive(Debug)]
168
pub struct HvfIoeventFd {}
169

170
impl IoeventFd for HvfIoeventFd {}
171

172
impl AsFd for HvfIoeventFd {
173
    fn as_fd(&self) -> BorrowedFd<'_> {
174
        unreachable!()
175
    }
176
}
177

178
#[derive(Debug)]
179
pub struct HvfIoeventFdRegistry;
180

181
impl IoeventFdRegistry for HvfIoeventFdRegistry {
182
    type IoeventFd = HvfIoeventFd;
183

184
    fn create(&self) -> Result<Self::IoeventFd> {
185
        Err(ErrorKind::Unsupported.into()).context(error::IoeventFd)
186
    }
187

188
    fn deregister(&self, _fd: &Self::IoeventFd) -> Result<()> {
189
        unreachable!()
190
    }
191

192
    fn register(
193
        &self,
194
        _fd: &Self::IoeventFd,
195
        _gpa: u64,
196
        _len: u8,
197
        _data: Option<u64>,
198
    ) -> Result<()> {
199
        unreachable!()
200
    }
201
}
202

203
#[derive(Debug)]
204
pub struct HvfGicV2;
205

206
impl GicV2 for HvfGicV2 {
207
    fn init(&self) -> Result<()> {
208
        unreachable!()
209
    }
210

211
    fn get_dist_reg(&self, _cpu_index: u32, _offset: u16) -> Result<u32> {
212
        unreachable!()
213
    }
214

215
    fn set_dist_reg(&self, _cpu_index: u32, _offset: u16, _val: u32) -> Result<()> {
216
        unreachable!()
217
    }
218

219
    fn get_cpu_reg(&self, _cpu_index: u32, _offset: u16) -> Result<u32> {
220
        unreachable!()
221
    }
222

223
    fn set_cpu_reg(&self, _cpu_index: u32, _offset: u16, _val: u32) -> Result<()> {
224
        unreachable!()
225
    }
226

227
    fn get_num_irqs(&self) -> Result<u32> {
228
        unreachable!()
229
    }
230

231
    fn set_num_irqs(&self, _val: u32) -> Result<()> {
232
        unreachable!()
233
    }
234
}
235

236
#[derive(Debug)]
237
pub struct HvfGicV3;
238

239
impl GicV3 for HvfGicV3 {
240
    fn init(&self) -> Result<()> {
241
        Ok(())
242
    }
243
}
244

245
#[derive(Debug)]
246
pub struct HvfGicV2m;
247

248
impl GicV2m for HvfGicV2m {
249
    fn init(&self) -> Result<()> {
250
        Ok(())
251
    }
252
}
253

254
#[derive(Debug)]
255
pub struct HvfIts;
256

257
impl Its for HvfIts {
258
    fn init(&self) -> Result<()> {
259
        unreachable!()
260
    }
261
}
262

263
#[derive(Debug)]
264
pub enum VcpuEvent {
265
    PowerOn { pc: u64, context: u64 },
266
    PowerOff,
267
}
268

269
#[derive(Debug)]
270
pub struct HvfVm {
271
    pub(super) gic_config: Mutex<(OsObject, bool)>,
272
    pub(super) vcpus: Mutex<HashMap<u32, u64>>,
273
    pub(super) senders: Arc<Mutex<HashMap<MpidrEl1, Sender<VcpuEvent>>>>,
274
}
275

276
impl Drop for HvfVm {
277
    fn drop(&mut self) {
278
        let ret = unsafe { hv_vm_destroy() };
279
        if let Err(e) = check_ret(ret) {
280
            log::error!("hv_vm_destroy: {e:?}");
281
        }
282
    }
283
}
284

285
impl Vm for HvfVm {
286
    type GicV2 = HvfGicV2;
287
    type GicV2m = HvfGicV2m;
288
    type GicV3 = HvfGicV3;
289
    type IoeventFdRegistry = HvfIoeventFdRegistry;
290
    type IrqSender = HvfIrqSender;
291
    type Its = HvfIts;
292
    type Memory = HvfMemory;
293
    type MsiSender = HvfMsiSender;
294
    type Vcpu = HvfVcpu;
295

296
    fn create_ioeventfd_registry(&self) -> Result<Self::IoeventFdRegistry> {
297
        Ok(HvfIoeventFdRegistry)
298
    }
299

300
    fn create_msi_sender(&self, _devid: u32) -> Result<Self::MsiSender> {
301
        Ok(HvfMsiSender)
302
    }
303

304
    fn create_vcpu(&self, id: u32) -> Result<Self::Vcpu> {
305
        let (config, created) = &mut *self.gic_config.lock();
306
        if config.addr != 0 && !*created {
307
            let ret = unsafe { hv_gic_create(config.addr as *mut _) };
308
            check_ret(ret).context(error::CreateDevice)?;
309
            *created = true;
310
        }
311

312
        let mut exit = null_mut();
313
        let mut vcpu_id = 0;
314
        let ret = unsafe { hv_vcpu_create(&mut vcpu_id, &mut exit, null_mut()) };
315
        check_ret(ret).context(error::CreateVcpu)?;
316

317
        let mpidr = encode_mpidr(id);
318
        let ret = unsafe { hv_vcpu_set_sys_reg(vcpu_id, SReg::MPIDR_EL1, mpidr.0) };
319
        check_ret(ret).context(error::VcpuReg)?;
320

321
        let (sender, receiver) = mpsc::channel();
322
        self.senders.lock().insert(mpidr, sender);
323

324
        self.vcpus.lock().insert(id, vcpu_id);
325
        Ok(HvfVcpu {
326
            exit,
327
            vcpu_id,
328
            vmexit: None,
329
            exit_reg: None,
330
            senders: self.senders.clone(),
331
            receiver,
332
            power_on: false,
333
        })
334
    }
335

336
    fn create_vm_memory(&mut self) -> Result<Self::Memory> {
337
        Ok(HvfMemory)
338
    }
339

NEW
340
    fn stop_vcpu<T>(&self, id: u32, _handle: &JoinHandle<T>) -> Result<()> {
×
NEW
341
        let vcpus = self.vcpus.lock();
×
NEW
342
        let senders = self.senders.lock();
×
NEW
343
        let Some(vcpu_id) = vcpus.get(&id) else {
×
NEW
344
            return Err(ErrorKind::NotFound.into()).context(error::StopVcpu);
×
345
        };
NEW
346
        let mpidr = encode_mpidr(id);
×
NEW
347
        let Some(sender) = senders.get(&mpidr) else {
×
NEW
348
            return Err(ErrorKind::NotFound.into()).context(error::StopVcpu);
×
349
        };
NEW
350
        if sender.send(VcpuEvent::PowerOff).is_err() {
×
NEW
351
            return Err(ErrorKind::BrokenPipe.into()).context(error::StopVcpu);
×
352
        };
NEW
353
        let ret = unsafe { hv_vcpus_exit(vcpu_id, 1) };
×
NEW
354
        check_ret(ret).context(error::StopVcpu)
×
355
    }
356

357
    fn create_gic_v2(
358
        &self,
359
        _distributor_base: u64,
360
        _cpu_interface_base: u64,
361
    ) -> Result<Self::GicV2> {
362
        Err(ErrorKind::Unsupported.into()).context(error::CreateDevice)
363
    }
364

365
    fn create_irq_sender(&self, pin: u8) -> Result<Self::IrqSender> {
366
        let mut spi_base = 0;
367
        let mut count = 0;
368
        let ret = unsafe { hv_gic_get_spi_interrupt_range(&mut spi_base, &mut count) };
369
        check_ret(ret).context(error::CreateDevice)?;
370
        Ok(HvfIrqSender {
371
            spi: spi_base + pin as u32,
372
        })
373
    }
374

375
    fn create_gic_v3(
376
        &self,
377
        distributor_base: u64,
378
        redistributor_base: u64,
379
        _redistributor_count: u32,
380
    ) -> Result<Self::GicV3> {
381
        let (config, _) = &mut *self.gic_config.lock();
382
        if config.addr == 0 {
383
            *config = OsObject {
384
                addr: unsafe { hv_gic_config_create() } as usize,
385
            };
386
        }
387
        let ptr = config.addr as *mut _;
388
        let ret = unsafe { hv_gic_config_set_distributor_base(ptr, distributor_base) };
389
        check_ret(ret).context(error::CreateDevice)?;
390
        let ret = unsafe { hv_gic_config_set_redistributor_base(ptr, redistributor_base) };
391
        check_ret(ret).context(error::CreateDevice)?;
392

393
        Ok(HvfGicV3)
394
    }
395

396
    fn create_gic_v2m(&self, base: u64) -> Result<Self::GicV2m> {
397
        let (config, _) = &mut *self.gic_config.lock();
398
        if config.addr == 0 {
399
            *config = OsObject {
400
                addr: unsafe { hv_gic_config_create() } as usize,
401
            };
402
        }
403

404
        let ptr = config.addr as *mut _;
405
        let ret = unsafe { hv_gic_config_set_msi_region_base(ptr, base) };
406
        check_ret(ret).context(error::CreateDevice)?;
407

408
        let mut spi_base = 0;
409
        let mut count = 0;
410
        let ret = unsafe { hv_gic_get_spi_interrupt_range(&mut spi_base, &mut count) };
411
        check_ret(ret).context(error::CreateDevice)?;
412
        let count = cmp::min(count, 987);
413
        let ret = unsafe { hv_gic_config_set_msi_interrupt_range(ptr, spi_base + 32, count - 32) };
414
        check_ret(ret).context(error::CreateDevice)?;
415

416
        Ok(HvfGicV2m)
417
    }
418

419
    fn create_its(&self, _base: u64) -> Result<Self::Its> {
420
        Err(ErrorKind::Unsupported.into()).context(error::CreateDevice)
421
    }
422
}
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