Skip to content

Commit e384b17

Browse files
committed
Add RoAfterInit to replace most static mut
1 parent f91adb2 commit e384b17

File tree

13 files changed

+237
-118
lines changed

13 files changed

+237
-118
lines changed

mythril/src/apic.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use crate::{declare_per_core, get_per_core, get_per_core_mut};
66
use raw_cpuid::CpuId;
77
use x86::msr;
88

9+
use core::fmt;
10+
911
/// APIC base physical address mask.
1012
const IA32_APIC_BASE_MASK: u64 = 0xffff_f000;
1113
/// xAPIC global enable mask
@@ -103,6 +105,32 @@ pub unsafe fn get_local_apic_mut() -> &'static mut LocalApic {
103105
.expect("Attempt to get local APIC before initialization")
104106
}
105107

108+
/// A representation of a APIC ID
109+
#[derive(Copy, Clone, Debug, Ord, PartialEq, PartialOrd, Eq)]
110+
pub struct ApicId {
111+
/// The raw ID as an integer
112+
pub raw: u32,
113+
}
114+
115+
impl ApicId {
116+
/// Returns whether this is the BSP core
117+
pub fn is_bsp(&self) -> bool {
118+
self.raw == 0
119+
}
120+
}
121+
122+
impl From<u32> for ApicId {
123+
fn from(value: u32) -> Self {
124+
ApicId { raw: value }
125+
}
126+
}
127+
128+
impl fmt::Display for ApicId {
129+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130+
write!(f, "0x{:x}", self.raw)
131+
}
132+
}
133+
106134
/// Structure defining the interface for a local x2APIC
107135
#[derive(Debug)]
108136
pub struct LocalApic {
@@ -188,8 +216,10 @@ impl LocalApic {
188216
}
189217

190218
/// The APIC ID
191-
pub fn id(&self) -> u32 {
192-
unsafe { msr::rdmsr(msr::IA32_X2APIC_APICID) as u32 }
219+
pub fn id(&self) -> ApicId {
220+
ApicId {
221+
raw: unsafe { msr::rdmsr(msr::IA32_X2APIC_APICID) as u32 },
222+
}
193223
}
194224

195225
/// The Logical APIC ID
@@ -249,15 +279,15 @@ impl LocalApic {
249279
/// Set the Interrupt Command Register
250280
pub fn send_ipi(
251281
&mut self,
252-
dst: u32,
282+
dst: ApicId,
253283
dst_short: DstShorthand,
254284
trigger: TriggerMode,
255285
level: Level,
256286
dst_mode: DstMode,
257287
delivery_mode: DeliveryMode,
258288
vector: u8,
259289
) {
260-
let mut icr: u64 = (dst as u64) << 32;
290+
let mut icr: u64 = (dst.raw as u64) << 32;
261291
icr |= (dst_short as u64) << 18;
262292
icr |= (trigger as u64) << 15;
263293
icr |= (level as u64) << 14;

mythril/src/ioapic.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
1515
use crate::acpi::madt::{Ics, MADT};
1616
use crate::error::{Error, Result};
17+
use crate::lock::ro_after_init::RoAfterInit;
1718
use core::convert::TryFrom;
1819
use core::fmt;
1920
use core::ptr;
@@ -40,16 +41,14 @@ mod reg {
4041

4142
const MAX_IOAPIC_COUNT: usize = 16;
4243

43-
// Interactions with individual IoApics are thread-safe, and this
44-
// vector is only initialized by the BSP, so no mutex is needed.
45-
// TODO(alschwalm): Remove the Option once ArrayVec::new is a const fn
46-
static mut IOAPICS: Option<ArrayVec<[IoApic; MAX_IOAPIC_COUNT]>> = None;
44+
static IOAPICS: RoAfterInit<ArrayVec<[IoApic; MAX_IOAPIC_COUNT]>> =
45+
RoAfterInit::uninitialized();
4746

4847
// Get the IoApic and redirection table entry index corresponding to a given GSI.
4948
// Returns None if there is no such IoApic
5049
// TODO(alschwalm): Support InterruptSourceOverride
51-
fn ioapic_for_gsi(gsi: u32) -> Option<(&'static mut IoApic, u8)> {
52-
for ioapic in unsafe { IOAPICS.as_mut().unwrap() }.iter_mut() {
50+
fn ioapic_for_gsi(gsi: u32) -> Option<(&'static IoApic, u8)> {
51+
for ioapic in IOAPICS.iter() {
5352
let entries = ioapic.max_redirection_entry() as u32;
5453
let base = ioapic.gsi_base;
5554
if gsi > base && gsi < base + entries {
@@ -102,7 +101,7 @@ pub unsafe fn init_ioapics(madt: &MADT) -> Result<()> {
102101
}) {
103102
ioapics.push(ioapic);
104103
}
105-
IOAPICS = Some(ioapics);
104+
RoAfterInit::init(&IOAPICS, ioapics);
106105
Ok(())
107106
}
108107

@@ -115,6 +114,11 @@ pub struct IoApic {
115114
pub gsi_base: u32,
116115
}
117116

117+
// IoApics are actually Send/Sync. This will not be correctly derived
118+
// because raw pointers are not send (even when protected by a mutex).
119+
unsafe impl Send for IoApic {}
120+
unsafe impl Sync for IoApic {}
121+
118122
impl IoApic {
119123
/// Create a new raw IoApic structure from the given
120124
/// base address and global system interrupt base.

mythril/src/kmain.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ extern "C" {
2929

3030
// Temporary helper function to create a vm for a single core
3131
fn default_vm(
32-
core: u32,
32+
core: percore::CoreId,
3333
mem: u64,
3434
info: &BootInfo,
3535
add_uart: bool,
@@ -132,7 +132,8 @@ fn default_vm(
132132
.unwrap();
133133
device_map.register_device(fw_cfg_builder.build()).unwrap();
134134

135-
vm::VirtualMachine::new(core, config, info).expect("Failed to create vm")
135+
vm::VirtualMachine::new(core.raw, config, info)
136+
.expect("Failed to create vm")
136137
}
137138

138139
#[no_mangle]
@@ -201,7 +202,7 @@ unsafe fn kmain(mut boot_info: BootInfo) -> ! {
201202
// TODO(dlrobertson): Check the flags to ensure we can acutally
202203
// use this APIC.
203204
Ok(acpi::madt::Ics::LocalApic { apic_id, .. }) => {
204-
Some(apic_id as u32)
205+
Some(apic::ApicId::from(apic_id as u32))
205206
}
206207
_ => None,
207208
})
@@ -219,10 +220,10 @@ unsafe fn kmain(mut boot_info: BootInfo) -> ! {
219220
for apic_id in apic_ids.iter() {
220221
builder
221222
.insert_machine(default_vm(
222-
*apic_id,
223+
percore::CoreId::from(apic_id.raw),
223224
256,
224225
&boot_info,
225-
*apic_id == 0,
226+
apic_id.is_bsp(),
226227
))
227228
.expect("Failed to insert new vm");
228229
}
@@ -232,7 +233,7 @@ unsafe fn kmain(mut boot_info: BootInfo) -> ! {
232233
debug!("AP_STARTUP address: 0x{:x}", AP_STARTUP_ADDR);
233234

234235
for (idx, apic_id) in apic_ids.into_iter().enumerate() {
235-
if apic_id == local_apic.id() as u32 {
236+
if apic_id == local_apic.id() {
236237
continue;
237238
}
238239

mythril/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub mod interrupt;
3636
pub mod ioapic;
3737
pub mod kmain;
3838
pub mod linux;
39+
pub mod lock;
3940
pub mod logger;
4041
pub mod memory;
4142
pub mod multiboot2;

mythril/src/lock/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod ro_after_init;

mythril/src/lock/ro_after_init.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use core::{cell::UnsafeCell, ops::Deref};
2+
3+
pub struct RoAfterInit<T> {
4+
data: UnsafeCell<Option<T>>,
5+
}
6+
7+
impl<T> RoAfterInit<T> {
8+
pub const fn uninitialized() -> Self {
9+
RoAfterInit {
10+
data: UnsafeCell::new(None),
11+
}
12+
}
13+
14+
pub unsafe fn init(this: &Self, val: T) {
15+
*this.data.get() = Some(val);
16+
}
17+
18+
pub fn is_initialized(this: &Self) -> bool {
19+
unsafe { &*this.data.get() }.is_some()
20+
}
21+
}
22+
23+
// BspOnce is Send/Sync because the contents are immutable after init
24+
unsafe impl<T: Send> Send for RoAfterInit<T> {}
25+
unsafe impl<T: Send + Sync> Sync for RoAfterInit<T> {}
26+
27+
impl<T> Deref for RoAfterInit<T> {
28+
type Target = T;
29+
30+
fn deref(&self) -> &T {
31+
unsafe {
32+
(*self.data.get())
33+
.as_ref()
34+
.expect("Attempt to use BspOnce before init")
35+
}
36+
}
37+
}

mythril/src/percore.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
//! invocation of `init_sections` by the BSP.
99
1010
use crate::error::Result;
11+
use crate::lock::ro_after_init::RoAfterInit;
1112
use alloc::vec::Vec;
13+
use core::fmt;
1214

13-
static mut AP_PER_CORE_SECTIONS: Option<Vec<u8>> = None;
15+
static AP_PER_CORE_SECTIONS: RoAfterInit<Vec<u8>> =
16+
RoAfterInit::uninitialized();
1417

1518
extern "C" {
1619
// The _value_ of the first/last byte of the .per_core section. The
@@ -31,11 +34,9 @@ unsafe fn per_core_address(symbol_addr: *const u8, core: usize) -> *const u8 {
3134
}
3235
let section_len = per_core_section_len();
3336
let offset = symbol_addr as u64 - (&PER_CORE_START as *const _ as u64);
34-
let ap_sections = AP_PER_CORE_SECTIONS
35-
.as_ref()
36-
.expect("Per-core sections not initialized");
3737

38-
&ap_sections[(section_len * (core - 1)) + offset as usize] as *const u8
38+
&AP_PER_CORE_SECTIONS[(section_len * (core - 1)) + offset as usize]
39+
as *const u8
3940
}
4041

4142
/// Initialize the per-core sections
@@ -53,35 +54,53 @@ pub unsafe fn init_sections(ncores: usize) -> Result<()> {
5354
ap_sections.extend_from_slice(per_core_section);
5455
}
5556

56-
AP_PER_CORE_SECTIONS = Some(ap_sections);
57-
57+
RoAfterInit::init(&AP_PER_CORE_SECTIONS, ap_sections);
5858
Ok(())
5959
}
6060

61+
/// The sequential index of a core
62+
#[derive(Copy, Clone, Debug, Ord, PartialEq, PartialOrd, Eq)]
63+
pub struct CoreId {
64+
/// The raw ID as an integer
65+
pub raw: u32,
66+
}
67+
68+
impl From<u32> for CoreId {
69+
fn from(value: u32) -> Self {
70+
CoreId { raw: value }
71+
}
72+
}
73+
74+
impl fmt::Display for CoreId {
75+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76+
write!(f, "0x{:x}", self.raw)
77+
}
78+
}
79+
6180
/// Get this current core's sequential index
62-
pub fn read_core_idx() -> u64 {
81+
pub fn read_core_id() -> CoreId {
6382
unsafe {
6483
let value: u64;
6584
llvm_asm!("mov [%fs], %rax"
6685
: "={rax}"(value)
6786
::: "volatile");
68-
value >> 3 // Shift away the RPL and TI bits (they will always be 0)
87+
((value >> 3) as u32).into() // Shift away the RPL and TI bits (they will always be 0)
6988
}
7089
}
7190

7291
#[doc(hidden)]
7392
pub unsafe fn get_pre_core_impl<T>(t: &T) -> &T {
7493
core::mem::transmute(per_core_address(
7594
t as *const T as *const u8,
76-
read_core_idx() as usize,
95+
read_core_id().raw as usize,
7796
))
7897
}
7998

8099
#[doc(hidden)]
81100
pub unsafe fn get_pre_core_mut_impl<T>(t: &mut T) -> &mut T {
82101
core::mem::transmute(per_core_address(
83102
t as *const T as *const u8,
84-
read_core_idx() as usize,
103+
read_core_id().raw as usize,
85104
))
86105
}
87106

mythril/src/physdev/com.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ impl Uart8250 {
5151
pub fn new(base: u16) -> Result<Self> {
5252
let mut uart = Self { base };
5353
uart.write_ier(IerFlags::RECV_DATA_AVAIL_INTERRUPT);
54-
info!("{:?}", uart.read_ier());
5554
Ok(uart)
5655
}
5756

0 commit comments

Comments
 (0)