1 /*
2 * Copyright (c) 2024 Google Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #![no_std]
25 #![feature(cfg_version)]
26 // C string literals were stabilized in Rust 1.77
27 #![cfg_attr(not(version("1.77")), feature(c_str_literals))]
28
29 use acpi::{AcpiHandler, AcpiTables, PhysicalMapping};
30
31 use rust_support::{
32 init::lk_init_level,
33 mmu::{ARCH_MMU_FLAG_CACHED, ARCH_MMU_FLAG_PERM_NO_EXECUTE, ARCH_MMU_FLAG_PERM_RO, PAGE_SIZE},
34 vmm::{vmm_alloc_physical, vmm_free_region, vmm_get_kernel_aspace},
35 LK_INIT_HOOK,
36 };
37
38 use core::ffi::{c_uint, c_void};
39 use core::ptr::NonNull;
40
41 const PAGE_MASK: usize = PAGE_SIZE as usize - 1;
42
43 #[derive(Clone)]
44 struct LkAcpiHandler;
45
46 impl AcpiHandler for LkAcpiHandler {
47 // SAFETY: map_physical_region get passed a valid physical address range
48 // if the assumptions below are met. It returns a read-only mapping to
49 // that region and the caller must not create any mutable references
50 // from the returned pointe.
map_physical_region<T>( &self, physical_address: usize, size: usize, ) -> PhysicalMapping<Self, T>51 unsafe fn map_physical_region<T>(
52 &self,
53 physical_address: usize,
54 size: usize,
55 ) -> PhysicalMapping<Self, T> {
56 let page_paddr = physical_address & !PAGE_MASK;
57 let offset = physical_address - page_paddr;
58 let aligned_size = (size + offset + PAGE_MASK) & !PAGE_MASK;
59 let mut ptr: *mut c_void = core::ptr::null_mut();
60 let ret = vmm_alloc_physical(
61 vmm_get_kernel_aspace(),
62 c"rust-acpi".as_ptr() as _,
63 aligned_size,
64 &mut ptr,
65 0,
66 page_paddr,
67 0,
68 ARCH_MMU_FLAG_CACHED | ARCH_MMU_FLAG_PERM_RO | ARCH_MMU_FLAG_PERM_NO_EXECUTE,
69 );
70
71 // If vmm_alloc_physical failed, panic.
72 // Ideally we should return an error to the caller in that case, but
73 // the api defined by the acpi crate does not allow that.
74 if ret != 0 {
75 panic!("vmm_alloc_physical failed, but map_physical_region is not allowed to return an error")
76 }
77
78 let nonnullptr = NonNull::new(ptr.wrapping_add(offset) as _).unwrap();
79
80 PhysicalMapping::new(physical_address, nonnullptr, size, aligned_size - offset, Self)
81 }
unmap_physical_region<T>(region: &PhysicalMapping<Self, T>)82 fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>) {
83 let ptr = region.virtual_start().as_ptr() as _;
84 // SAFETY:: ptr came from vmm_alloc_physical
85 unsafe { vmm_free_region(vmm_get_kernel_aspace(), ptr) };
86 }
87 }
88
platform_acpi_init_func(_level: c_uint)89 extern "C" fn platform_acpi_init_func(_level: c_uint) {
90 // SAFETY: search_for_rsdp_bios searches for a RSDP on BIOS systems.
91 // It is not safe to call on a UEFI system. crosvm currently emulates
92 // a BIOS system.
93 let acpi_tables = match unsafe { AcpiTables::search_for_rsdp_bios(LkAcpiHandler) } {
94 Ok(acpi_tables) => acpi_tables,
95 Err(error) => {
96 log::error!("search_for_rsdp_bios failed: {error:?}");
97 return;
98 }
99 };
100 let mcfg_table = match acpi_tables.find_table::<acpi::mcfg::Mcfg>() {
101 Ok(mcfg_table) => mcfg_table,
102 Err(error) => {
103 log::error!("filed to find mcfg_table: {error:?}");
104 return;
105 }
106 };
107 let mcfg_entries = mcfg_table.entries();
108 let entry = mcfg_entries[0];
109
110 let entry_size = (1 + entry.bus_number_end as usize - entry.bus_number_start as usize) << 20;
111
112 log::error!(
113 "TODO: call init function for pci bus at {:#x}, size {entry_size:#x}",
114 entry.base_address as usize
115 );
116 }
117
118 LK_INIT_HOOK!(platform_acpi_init, platform_acpi_init_func, lk_init_level::LK_INIT_LEVEL_THREADING);
119