• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! RISC-V 64-bit architecture support.
6 
7 #![cfg(target_arch = "riscv64")]
8 
9 use std::collections::BTreeMap;
10 use std::io::{self};
11 use std::path::PathBuf;
12 use std::sync::mpsc;
13 use std::sync::Arc;
14 
15 use arch::get_serial_cmdline;
16 use arch::CpuSet;
17 use arch::DtbOverlay;
18 use arch::GetSerialCmdlineError;
19 use arch::RunnableLinuxVm;
20 use arch::VmComponents;
21 use arch::VmImage;
22 use base::Event;
23 use base::SendTube;
24 use devices::serial_device::SerialHardware;
25 use devices::serial_device::SerialParameters;
26 use devices::Bus;
27 use devices::BusDeviceObj;
28 use devices::BusError;
29 use devices::BusType;
30 use devices::IrqChipRiscv64;
31 use devices::PciAddress;
32 use devices::PciConfigMmio;
33 use devices::PciDevice;
34 use devices::PciRootCommand;
35 #[cfg(feature = "gdb")]
36 use gdbstub::arch::Arch;
37 #[cfg(feature = "gdb")]
38 use gdbstub_arch::riscv::Riscv64 as GdbArch;
39 use hypervisor::CoreRegister;
40 use hypervisor::CpuConfigRiscv64;
41 use hypervisor::Hypervisor;
42 use hypervisor::ProtectionType;
43 use hypervisor::TimerRegister;
44 use hypervisor::VcpuInitRiscv64;
45 use hypervisor::VcpuRegister;
46 use hypervisor::VcpuRiscv64;
47 use hypervisor::Vm;
48 use hypervisor::VmRiscv64;
49 #[cfg(windows)]
50 use jail::FakeMinijailStub as Minijail;
51 #[cfg(any(target_os = "android", target_os = "linux"))]
52 use minijail::Minijail;
53 use remain::sorted;
54 use resources::AddressRange;
55 use resources::SystemAllocator;
56 use resources::SystemAllocatorConfig;
57 #[cfg(any(target_os = "android", target_os = "linux"))]
58 use sync::Condvar;
59 use sync::Mutex;
60 use thiserror::Error;
61 use vm_control::BatteryType;
62 use vm_memory::GuestAddress;
63 #[cfg(feature = "gdb")]
64 use vm_memory::GuestMemory;
65 use vm_memory::MemoryRegionOptions;
66 
67 mod fdt;
68 
69 // We place the kernel at offset 8MB
70 const RISCV64_KERNEL_OFFSET: u64 = 0x20_0000;
71 const RISCV64_INITRD_ALIGN: u64 = 8;
72 const RISCV64_FDT_ALIGN: u64 = 0x40_0000;
73 
74 // This indicates the start of DRAM inside the physical address space.
75 const RISCV64_PHYS_MEM_START: u64 = 0x8000_0000;
76 
77 // PCI MMIO configuration region base address.
78 const RISCV64_PCI_CFG_BASE: u64 = 0x1_0000;
79 // PCI MMIO configuration region size.
80 const RISCV64_PCI_CFG_SIZE: u64 = 0x100_0000;
81 // This is the base address of MMIO devices.
82 const RISCV64_MMIO_BASE: u64 = 0x0300_0000;
83 // Size of the whole MMIO region.
84 const RISCV64_MMIO_SIZE: u64 = 0x10_0000;
85 
86 const RISCV64_FDT_MAX_SIZE: u64 = 0x1_0000;
87 
get_kernel_addr() -> GuestAddress88 fn get_kernel_addr() -> GuestAddress {
89     GuestAddress(RISCV64_PHYS_MEM_START + RISCV64_KERNEL_OFFSET)
90 }
91 
92 const RISCV64_IRQ_BASE: u32 = 1;
93 
94 #[sorted]
95 #[derive(Error, Debug)]
96 pub enum Error {
97     #[error("unable to clone an Event: {0}")]
98     CloneEvent(base::Error),
99     #[error("failed to clone IRQ chip: {0}")]
100     CloneIrqChip(base::Error),
101     #[error("the given kernel command line was invalid: {0}")]
102     Cmdline(kernel_cmdline::Error),
103     #[error("unable to make an Event: {0}")]
104     CreateEvent(base::Error),
105     #[error("FDT could not be created: {0}")]
106     CreateFdt(cros_fdt::Error),
107     #[error("failed to create a PCI root hub: {0}")]
108     CreatePciRoot(arch::DeviceRegistrationError),
109     #[error("failed to create platform bus: {0}")]
110     CreatePlatformBus(arch::DeviceRegistrationError),
111     #[error("unable to create serial devices: {0}")]
112     CreateSerialDevices(arch::DeviceRegistrationError),
113     #[error("failed to create socket: {0}")]
114     CreateSocket(io::Error),
115     #[error("failed to create VCPU: {0}")]
116     CreateVcpu(base::Error),
117     #[error("vm created wrong kind of vcpu")]
118     DowncastVcpu,
119     #[error("failed to finalize devices: {0}")]
120     FinalizeDevices(base::Error),
121     #[error("failed to finalize IRQ chip: {0}")]
122     FinalizeIrqChip(base::Error),
123     #[error("failed to get serial cmdline: {0}")]
124     GetSerialCmdline(GetSerialCmdlineError),
125     #[error("Failed to get the timer base frequency: {0}")]
126     GetTimebase(base::Error),
127     #[error("Image type not supported on riscv")]
128     ImageTypeUnsupported,
129     #[error("initrd could not be loaded: {0}")]
130     InitrdLoadFailure(arch::LoadImageError),
131     #[error("kernel could not be loaded: {0}")]
132     KernelLoadFailure(arch::LoadImageError),
133     #[error("protected vms not supported on riscv(yet)")]
134     ProtectedVmUnsupported,
135     #[error("ramoops address is different from high_mmio_base: {0} vs {1}")]
136     RamoopsAddress(u64, u64),
137     #[error("failed to register irq fd: {0}")]
138     RegisterIrqfd(base::Error),
139     #[error("error registering PCI bus: {0}")]
140     RegisterPci(BusError),
141     #[error("error registering virtual socket device: {0}")]
142     RegisterVsock(arch::DeviceRegistrationError),
143     #[error("failed to set device attr: {0}")]
144     SetDeviceAttr(base::Error),
145     #[error("failed to set register: {0}")]
146     SetReg(base::Error),
147     #[error("Timebase frequency too large")]
148     TimebaseTooLarge,
149     #[error("this function isn't supported")]
150     Unsupported,
151     #[error("failed to initialize VCPU: {0}")]
152     VcpuInit(base::Error),
153 }
154 
155 pub type Result<T> = std::result::Result<T, Error>;
156 
157 pub struct Riscv64;
158 
159 impl arch::LinuxArch for Riscv64 {
160     type Error = Error;
161 
162     /// Returns a Vec of the valid memory addresses.
163     /// These should be used to configure the GuestMemory structure for the platfrom.
guest_memory_layout( components: &VmComponents, _hypervisor: &impl Hypervisor, ) -> std::result::Result<Vec<(GuestAddress, u64, MemoryRegionOptions)>, Self::Error>164     fn guest_memory_layout(
165         components: &VmComponents,
166         _hypervisor: &impl Hypervisor,
167     ) -> std::result::Result<Vec<(GuestAddress, u64, MemoryRegionOptions)>, Self::Error> {
168         Ok(vec![(
169             GuestAddress(RISCV64_PHYS_MEM_START),
170             components.memory_size,
171             Default::default(),
172         )])
173     }
174 
get_system_allocator_config<V: Vm>(vm: &V) -> SystemAllocatorConfig175     fn get_system_allocator_config<V: Vm>(vm: &V) -> SystemAllocatorConfig {
176         get_resource_allocator_config(vm.get_memory().memory_size(), vm.get_guest_phys_addr_bits())
177     }
178 
build_vm<V, Vcpu>( mut components: VmComponents, _vm_evt_wrtube: &SendTube, system_allocator: &mut SystemAllocator, serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>, serial_jail: Option<Minijail>, (_bat_type, _bat_jail): (Option<BatteryType>, Option<Minijail>), mut vm: V, ramoops_region: Option<arch::pstore::RamoopsRegion>, devices: Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>, irq_chip: &mut dyn IrqChipRiscv64, vcpu_ids: &mut Vec<usize>, _dump_device_tree_blob: Option<PathBuf>, _debugcon_jail: Option<Minijail>, #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>, #[cfg(any(target_os = "android", target_os = "linux"))] _guest_suspended_cvar: Option< Arc<(Mutex<bool>, Condvar)>, >, device_tree_overlays: Vec<DtbOverlay>, ) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error> where V: VmRiscv64, Vcpu: VcpuRiscv64,179     fn build_vm<V, Vcpu>(
180         mut components: VmComponents,
181         _vm_evt_wrtube: &SendTube,
182         system_allocator: &mut SystemAllocator,
183         serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
184         serial_jail: Option<Minijail>,
185         (_bat_type, _bat_jail): (Option<BatteryType>, Option<Minijail>),
186         mut vm: V,
187         ramoops_region: Option<arch::pstore::RamoopsRegion>,
188         devices: Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>,
189         irq_chip: &mut dyn IrqChipRiscv64,
190         vcpu_ids: &mut Vec<usize>,
191         _dump_device_tree_blob: Option<PathBuf>,
192         _debugcon_jail: Option<Minijail>,
193         #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
194         #[cfg(any(target_os = "android", target_os = "linux"))] _guest_suspended_cvar: Option<
195             Arc<(Mutex<bool>, Condvar)>,
196         >,
197         device_tree_overlays: Vec<DtbOverlay>,
198     ) -> std::result::Result<RunnableLinuxVm<V, Vcpu>, Self::Error>
199     where
200         V: VmRiscv64,
201         Vcpu: VcpuRiscv64,
202     {
203         if components.hv_cfg.protection_type == ProtectionType::Protected {
204             return Err(Error::ProtectedVmUnsupported);
205         }
206 
207         let mem = vm.get_memory().clone();
208 
209         let mmio_bus = Arc::new(Bus::new(BusType::Mmio));
210 
211         // Riscv doesn't really use the io bus like x86, so just create an empty bus.
212         let io_bus = Arc::new(Bus::new(BusType::Io));
213 
214         let com_evt_1_3 = Event::new().map_err(Error::CreateEvent)?;
215         let com_evt_2_4 = Event::new().map_err(Error::CreateEvent)?;
216         let serial_devices = arch::add_serial_devices(
217             components.hv_cfg.protection_type,
218             &mmio_bus,
219             // TODO: the IRQ numbers are bogus since the events aren't actually wired up
220             (0, &com_evt_1_3),
221             (0, &com_evt_2_4),
222             serial_parameters,
223             serial_jail,
224             #[cfg(feature = "swap")]
225             swap_controller,
226         )
227         .map_err(Error::CreateSerialDevices)?;
228 
229         let (pci_devices, others): (Vec<_>, Vec<_>) = devices
230             .into_iter()
231             .partition(|(dev, _)| dev.as_pci_device().is_some());
232         let pci_devices = pci_devices
233             .into_iter()
234             .map(|(dev, jail_orig)| (dev.into_pci_device().unwrap(), jail_orig))
235             .collect();
236         let (pci, pci_irqs, mut pid_debug_label_map, _amls, _gpe_scope_amls) =
237             arch::generate_pci_root(
238                 pci_devices,
239                 irq_chip.as_irq_chip_mut(),
240                 Arc::clone(&mmio_bus),
241                 GuestAddress(RISCV64_PCI_CFG_BASE),
242                 8,
243                 Arc::clone(&io_bus),
244                 system_allocator,
245                 &mut vm,
246                 devices::IMSIC_MAX_INT_IDS as usize,
247                 None,
248                 #[cfg(feature = "swap")]
249                 swap_controller,
250             )
251             .map_err(Error::CreatePciRoot)?;
252 
253         let pci_root = Arc::new(Mutex::new(pci));
254         let pci_bus = Arc::new(Mutex::new(PciConfigMmio::new(pci_root.clone(), 8)));
255         let (platform_devices, _others): (Vec<_>, Vec<_>) = others
256             .into_iter()
257             .partition(|(dev, _)| dev.as_platform_device().is_some());
258 
259         let platform_devices = platform_devices
260             .into_iter()
261             .map(|(dev, jail_orig)| (*(dev.into_platform_device().unwrap()), jail_orig))
262             .collect();
263         let (platform_devices, mut platform_pid_debug_label_map, dev_resources) =
264             arch::sys::linux::generate_platform_bus(
265                 platform_devices,
266                 irq_chip.as_irq_chip_mut(),
267                 &mmio_bus,
268                 system_allocator,
269                 &mut vm,
270                 #[cfg(feature = "swap")]
271                 swap_controller,
272                 components.hv_cfg.protection_type,
273             )
274             .map_err(Error::CreatePlatformBus)?;
275         pid_debug_label_map.append(&mut platform_pid_debug_label_map);
276 
277         let mut cmdline = get_base_linux_cmdline();
278 
279         if let Some(ramoops_region) = ramoops_region {
280             arch::pstore::add_ramoops_kernel_cmdline(&mut cmdline, &ramoops_region)
281                 .map_err(Error::Cmdline)?;
282         }
283 
284         mmio_bus
285             .insert(pci_bus, RISCV64_PCI_CFG_BASE, RISCV64_PCI_CFG_SIZE)
286             .map_err(Error::RegisterPci)?;
287 
288         get_serial_cmdline(&mut cmdline, serial_parameters, "mmio", &serial_devices)
289             .map_err(Error::GetSerialCmdline)?;
290         for param in components.extra_kernel_params {
291             cmdline.insert_str(&param).map_err(Error::Cmdline)?;
292         }
293 
294         // Event used by PMDevice to notify crosvm that guest OS is trying to suspend.
295         let suspend_evt = Event::new().map_err(Error::CreateEvent)?;
296 
297         // separate out image loading from other setup to get a specific error for
298         // image loading
299         let initrd;
300         let kernel_initrd_end = match components.vm_image {
301             VmImage::Bios(ref _bios) => {
302                 return Err(Error::ImageTypeUnsupported);
303             }
304             VmImage::Kernel(ref mut kernel_image) => {
305                 let kernel_size =
306                     arch::load_image(&mem, kernel_image, get_kernel_addr(), u64::max_value())
307                         .map_err(Error::KernelLoadFailure)?;
308                 let kernel_end = get_kernel_addr().offset() + kernel_size as u64;
309                 initrd = match components.initrd_image {
310                     Some(initrd_file) => {
311                         let mut initrd_file = initrd_file;
312                         let initrd_addr =
313                             (kernel_end + (RISCV64_INITRD_ALIGN - 1)) & !(RISCV64_INITRD_ALIGN - 1);
314                         let initrd_max_size =
315                             components.memory_size - (initrd_addr - RISCV64_PHYS_MEM_START);
316                         let initrd_addr = GuestAddress(initrd_addr);
317                         let initrd_size =
318                             arch::load_image(&mem, &mut initrd_file, initrd_addr, initrd_max_size)
319                                 .map_err(Error::InitrdLoadFailure)?;
320                         Some((initrd_addr, initrd_size))
321                     }
322                     None => None,
323                 };
324                 if let Some((initrd_addr, initrd_size)) = initrd {
325                     initrd_addr.offset() + initrd_size as u64 - RISCV64_PHYS_MEM_START
326                 } else {
327                     kernel_end - RISCV64_PHYS_MEM_START
328                 }
329             }
330         };
331 
332         // Creates vcpus early as the irqchip needs them created to attach interrupts.
333         let vcpu_count = components.vcpu_count;
334         let mut vcpus = Vec::with_capacity(vcpu_count);
335         for vcpu_id in 0..vcpu_count {
336             let vcpu: Vcpu = *vm
337                 .create_vcpu(vcpu_id)
338                 .map_err(Error::CreateVcpu)?
339                 .downcast::<Vcpu>()
340                 .map_err(|_| Error::DowncastVcpu)?;
341             vcpus.push(vcpu);
342             vcpu_ids.push(vcpu_id);
343         }
344 
345         irq_chip.finalize().map_err(Error::FinalizeIrqChip)?;
346 
347         irq_chip
348             .finalize_devices(system_allocator, &io_bus, &mmio_bus)
349             .map_err(Error::FinalizeDevices)?;
350         let (aia_num_ids, aia_num_sources) = irq_chip.get_num_ids_sources();
351 
352         let pci_cfg = fdt::PciConfigRegion {
353             base: RISCV64_PCI_CFG_BASE,
354             size: RISCV64_PCI_CFG_SIZE,
355         };
356 
357         let pci_ranges: Vec<fdt::PciRange> = system_allocator
358             .mmio_pools()
359             .iter()
360             .map(|range| fdt::PciRange {
361                 space: fdt::PciAddressSpace::Memory64,
362                 bus_address: range.start,
363                 cpu_physical_address: range.start,
364                 size: range.len().unwrap(),
365                 prefetchable: false,
366             })
367             .collect();
368 
369         let fdt_offset = (kernel_initrd_end + (RISCV64_FDT_ALIGN - 1)) & !(RISCV64_FDT_ALIGN - 1);
370 
371         let timebase_freq: u32 = vcpus[0]
372             .get_one_reg(VcpuRegister::Timer(TimerRegister::TimebaseFrequency))
373             .map_err(Error::GetTimebase)?
374             .try_into()
375             .map_err(|_| Error::TimebaseTooLarge)?;
376 
377         fdt::create_fdt(
378             RISCV64_FDT_MAX_SIZE as usize,
379             &mem,
380             pci_irqs,
381             pci_cfg,
382             &pci_ranges,
383             dev_resources,
384             components.vcpu_count as u32,
385             fdt_offset,
386             aia_num_ids,
387             aia_num_sources,
388             cmdline.as_str(),
389             initrd,
390             timebase_freq,
391             device_tree_overlays,
392         )
393         .map_err(Error::CreateFdt)?;
394 
395         let vcpu_init = vec![
396             VcpuInitRiscv64::new(GuestAddress(fdt_offset + RISCV64_PHYS_MEM_START));
397             vcpu_count
398         ];
399 
400         Ok(RunnableLinuxVm {
401             vm,
402             vcpu_count: components.vcpu_count,
403             vcpus: Some(vcpus),
404             vcpu_init,
405             vcpu_affinity: components.vcpu_affinity,
406             no_smt: false,
407             irq_chip: irq_chip.try_box_clone().map_err(Error::CloneIrqChip)?,
408             io_bus,
409             mmio_bus,
410             pid_debug_label_map,
411             resume_notify_devices: Vec::new(),
412             root_config: pci_root,
413             platform_devices,
414             hotplug_bus: BTreeMap::new(),
415             rt_cpus: components.rt_cpus,
416             delay_rt: components.delay_rt,
417             suspend_evt,
418             bat_control: None,
419             #[cfg(feature = "gdb")]
420             gdb: components.gdb,
421             pm: None,
422             devices_thread: None,
423             vm_request_tube: None,
424         })
425     }
426 
configure_vcpu<V: Vm>( _vm: &V, _hypervisor: &dyn Hypervisor, _irq_chip: &mut dyn IrqChipRiscv64, vcpu: &mut dyn VcpuRiscv64, _vcpu_init: VcpuInitRiscv64, vcpu_id: usize, _num_cpus: usize, cpu_config: Option<CpuConfigRiscv64>, ) -> std::result::Result<(), Self::Error>427     fn configure_vcpu<V: Vm>(
428         _vm: &V,
429         _hypervisor: &dyn Hypervisor,
430         _irq_chip: &mut dyn IrqChipRiscv64,
431         vcpu: &mut dyn VcpuRiscv64,
432         _vcpu_init: VcpuInitRiscv64,
433         vcpu_id: usize,
434         _num_cpus: usize,
435         cpu_config: Option<CpuConfigRiscv64>,
436     ) -> std::result::Result<(), Self::Error> {
437         vcpu.set_one_reg(VcpuRegister::Core(CoreRegister::Pc), get_kernel_addr().0)
438             .map_err(Self::Error::SetReg)?;
439         vcpu.set_one_reg(VcpuRegister::Core(CoreRegister::A0), vcpu_id as u64)
440             .map_err(Self::Error::SetReg)?;
441         vcpu.set_one_reg(
442             VcpuRegister::Core(CoreRegister::A1),
443             cpu_config.unwrap().fdt_address.0,
444         )
445         .map_err(Self::Error::SetReg)?;
446 
447         Ok(())
448     }
449 
register_pci_device<V: VmRiscv64, Vcpu: VcpuRiscv64>( _linux: &mut RunnableLinuxVm<V, Vcpu>, _device: Box<dyn PciDevice>, _minijail: Option<Minijail>, _resources: &mut SystemAllocator, _tube: &mpsc::Sender<PciRootCommand>, #[cfg(feature = "swap")] _swap_controller: &mut Option<swap::SwapController>, ) -> std::result::Result<PciAddress, Self::Error>450     fn register_pci_device<V: VmRiscv64, Vcpu: VcpuRiscv64>(
451         _linux: &mut RunnableLinuxVm<V, Vcpu>,
452         _device: Box<dyn PciDevice>,
453         _minijail: Option<Minijail>,
454         _resources: &mut SystemAllocator,
455         _tube: &mpsc::Sender<PciRootCommand>,
456         #[cfg(feature = "swap")] _swap_controller: &mut Option<swap::SwapController>,
457     ) -> std::result::Result<PciAddress, Self::Error> {
458         // hotplug function isn't verified on Riscv64, so set it unsupported here.
459         Err(Error::Unsupported)
460     }
461 
get_host_cpu_frequencies_khz() -> Result<BTreeMap<usize, Vec<u32>>>462     fn get_host_cpu_frequencies_khz() -> Result<BTreeMap<usize, Vec<u32>>> {
463         Ok(BTreeMap::new())
464     }
465 
get_host_cpu_capacity() -> Result<BTreeMap<usize, u32>>466     fn get_host_cpu_capacity() -> Result<BTreeMap<usize, u32>> {
467         Ok(BTreeMap::new())
468     }
469 
get_host_cpu_clusters() -> Result<Vec<CpuSet>>470     fn get_host_cpu_clusters() -> Result<Vec<CpuSet>> {
471         Ok(Vec::new())
472     }
473 }
474 
475 #[cfg(feature = "gdb")]
476 impl<T: VcpuRiscv64> arch::GdbOps<T> for Riscv64 {
477     type Error = Error;
478 
read_memory( _vcpu: &T, _guest_mem: &GuestMemory, _vaddr: GuestAddress, _len: usize, ) -> Result<Vec<u8>>479     fn read_memory(
480         _vcpu: &T,
481         _guest_mem: &GuestMemory,
482         _vaddr: GuestAddress,
483         _len: usize,
484     ) -> Result<Vec<u8>> {
485         unimplemented!();
486     }
487 
write_memory( _vcpu: &T, _guest_mem: &GuestMemory, _vaddr: GuestAddress, _buf: &[u8], ) -> Result<()>488     fn write_memory(
489         _vcpu: &T,
490         _guest_mem: &GuestMemory,
491         _vaddr: GuestAddress,
492         _buf: &[u8],
493     ) -> Result<()> {
494         unimplemented!();
495     }
496 
read_registers(_vcpu: &T) -> Result<<GdbArch as Arch>::Registers>497     fn read_registers(_vcpu: &T) -> Result<<GdbArch as Arch>::Registers> {
498         unimplemented!();
499     }
500 
write_registers(_vcpu: &T, _regs: &<GdbArch as Arch>::Registers) -> Result<()>501     fn write_registers(_vcpu: &T, _regs: &<GdbArch as Arch>::Registers) -> Result<()> {
502         unimplemented!();
503     }
504 
read_register(_vcpu: &T, _reg_id: <GdbArch as Arch>::RegId) -> Result<Vec<u8>>505     fn read_register(_vcpu: &T, _reg_id: <GdbArch as Arch>::RegId) -> Result<Vec<u8>> {
506         unimplemented!();
507     }
508 
write_register(_vcpu: &T, _reg_id: <GdbArch as Arch>::RegId, _data: &[u8]) -> Result<()>509     fn write_register(_vcpu: &T, _reg_id: <GdbArch as Arch>::RegId, _data: &[u8]) -> Result<()> {
510         unimplemented!();
511     }
512 
enable_singlestep(_vcpu: &T) -> Result<()>513     fn enable_singlestep(_vcpu: &T) -> Result<()> {
514         unimplemented!();
515     }
516 
get_max_hw_breakpoints(_vcpu: &T) -> Result<usize>517     fn get_max_hw_breakpoints(_vcpu: &T) -> Result<usize> {
518         unimplemented!();
519     }
520 
set_hw_breakpoints(_vcpu: &T, _breakpoints: &[GuestAddress]) -> Result<()>521     fn set_hw_breakpoints(_vcpu: &T, _breakpoints: &[GuestAddress]) -> Result<()> {
522         unimplemented!();
523     }
524 }
525 
get_high_mmio_base_size(mem_size: u64, guest_phys_addr_bits: u8) -> (u64, u64)526 fn get_high_mmio_base_size(mem_size: u64, guest_phys_addr_bits: u8) -> (u64, u64) {
527     let guest_phys_end = 1u64 << guest_phys_addr_bits;
528     let high_mmio_base = RISCV64_PHYS_MEM_START + mem_size;
529     let size = guest_phys_end
530         .checked_sub(high_mmio_base)
531         .unwrap_or_else(|| {
532             panic!(
533                 "guest_phys_end {:#x} < high_mmio_base {:#x}",
534                 guest_phys_end, high_mmio_base,
535             );
536         });
537     (high_mmio_base, size)
538 }
539 
get_base_linux_cmdline() -> kernel_cmdline::Cmdline540 fn get_base_linux_cmdline() -> kernel_cmdline::Cmdline {
541     let mut cmdline = kernel_cmdline::Cmdline::new(base::pagesize());
542     cmdline.insert_str("panic=-1").unwrap();
543     cmdline
544 }
545 
546 /// Returns a system resource allocator coniguration.
547 ///
548 /// # Arguments
549 ///
550 /// * `mem_size` - Size of guest memory (RAM) in bytes.
551 /// * `guest_phys_addr_bits` - Size of guest physical addresses (IPA) in bits.
get_resource_allocator_config(mem_size: u64, guest_phys_addr_bits: u8) -> SystemAllocatorConfig552 fn get_resource_allocator_config(mem_size: u64, guest_phys_addr_bits: u8) -> SystemAllocatorConfig {
553     let (high_mmio_base, high_mmio_size) = get_high_mmio_base_size(mem_size, guest_phys_addr_bits);
554     SystemAllocatorConfig {
555         io: None,
556         low_mmio: AddressRange::from_start_and_size(RISCV64_MMIO_BASE, RISCV64_MMIO_SIZE)
557             .expect("invalid mmio region"),
558         high_mmio: AddressRange::from_start_and_size(high_mmio_base, high_mmio_size)
559             .expect("invalid high mmio region"),
560         platform_mmio: None,
561         first_irq: RISCV64_IRQ_BASE,
562     }
563 }
564