diff --git a/Makefile b/Makefile index 1c658da303..733415908f 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +# Red Bear OS kernel patches applied via individual patch files .PHONY: all check SOURCE:=$(dir $(realpath $(lastword $(MAKEFILE_LIST)))) diff --git a/src/arch/x86_shared/device/mod.rs b/src/arch/x86_shared/device/mod.rs index 6f41770601..7a2e25df3c 100644 --- a/src/arch/x86_shared/device/mod.rs +++ b/src/arch/x86_shared/device/mod.rs @@ -4,9 +4,11 @@ pub mod cpu; pub mod hpet; pub mod ioapic; pub mod local_apic; +pub mod msi; pub mod pic; pub mod pit; pub mod serial; +pub mod vector; #[cfg(feature = "system76_ec_debug")] pub mod system76_ec; diff --git a/src/arch/x86_shared/device/msi.rs b/src/arch/x86_shared/device/msi.rs new file mode 100644 index 0000000000..d979fe54b6 --- /dev/null +++ b/src/arch/x86_shared/device/msi.rs @@ -0,0 +1,66 @@ +use crate::arch::device::local_apic::ApicId; + +pub const MSI_ADDRESS_BASE: u64 = 0xFEE0_0000; + +#[derive(Debug, Clone)] +pub struct MsiMessage { + pub address: u64, + pub data: u32, +} + +impl MsiMessage { + pub fn compose(dest: ApicId, vector: u8, delivery_mode: u8) -> Self { + let address = MSI_ADDRESS_BASE | (u64::from(dest.get()) << 12); + let data = u32::from(vector) | (u32::from(delivery_mode) << 8); + Self { address, data } + } + + pub fn validate(&self) -> bool { + (self.address & 0xFFF0_0000) == MSI_ADDRESS_BASE + && self.data & 0xFF >= 32 + && self.data & 0xFF < 255 + } +} + +pub fn is_valid_msi_address(addr: u64) -> bool { (addr & 0xFFF0_0000) == MSI_ADDRESS_BASE } +pub fn is_valid_msi_vector(vector: u8) -> bool { vector >= 32 && vector < 255 } + +#[derive(Debug)] +pub struct MsiCapability { + pub msg_ctl: u16, pub msg_addr_lo: u32, pub msg_data: u16, + pub is_64bit: bool, pub is_maskable: bool, pub multiple_message_capable: u8, +} + +impl MsiCapability { + pub fn parse(raw: &[u32], msg_ctl: u16) -> Option { + let msg_addr_lo = *raw.get(1)?; + let msg_data = if msg_ctl & (1<<7) != 0 { + (*raw.get(3)? & 0xFFFF) as u16 + } else { + (*raw.get(2)? & 0xFFFF) as u16 + }; + Some(Self { + msg_ctl, msg_addr_lo, msg_data, + is_64bit: msg_ctl & (1<<7) != 0, + is_maskable: msg_ctl & (1<<8) != 0, + multiple_message_capable: ((msg_ctl>>1)&0x7) as u8, + }) + } +} + +pub struct MsixCapability { + pub table_offset: u32, pub table_bar: u8, + pub pba_offset: u32, pub pba_bar: u8, pub table_size: u16, +} + +impl MsixCapability { + pub fn parse(raw: &[u32], msg_ctl: u16) -> Option { + let r1 = *raw.get(1)?; + let r2 = *raw.get(2)?; + Some(Self { + table_offset: r1 & !0x7, table_bar: (r1&0x7) as u8, + pba_offset: r2 & !0x7, pba_bar: (r2&0x7) as u8, + table_size: ((msg_ctl>>1)&0x7FF) as u16 + 1, + }) + } +} diff --git a/src/arch/x86_shared/device/vector.rs b/src/arch/x86_shared/device/vector.rs new file mode 100644 index 0000000000..cd59ac7965 --- /dev/null +++ b/src/arch/x86_shared/device/vector.rs @@ -0,0 +1,53 @@ +use crate::cpu_set::LogicalCpuId; + +const VECTOR_COUNT: usize = 224; + +static VECTORS: [core::sync::atomic::AtomicU32; 7] = [ + core::sync::atomic::AtomicU32::new(0), + core::sync::atomic::AtomicU32::new(0), + core::sync::atomic::AtomicU32::new(0), + core::sync::atomic::AtomicU32::new(0), + core::sync::atomic::AtomicU32::new(0), + core::sync::atomic::AtomicU32::new(0), + core::sync::atomic::AtomicU32::new(0), +]; + +pub fn allocate_vector(_cpu: LogicalCpuId) -> Option { + for (bank, slot) in VECTORS.iter().enumerate() { + let mut bits = slot.load(core::sync::atomic::Ordering::Acquire); + loop { + let free = bits.trailing_ones() as usize; + if free >= 32 { + break; + } + let bit = 1u32 << free; + match slot.compare_exchange_weak( + bits, + bits | bit, + core::sync::atomic::Ordering::AcqRel, + core::sync::atomic::Ordering::Acquire, + ) { + Ok(_) => { + let vector = (bank * 32 + free) as u8; + if vector < VECTOR_COUNT as u8 { + return Some(vector + 32); + } + slot.fetch_and(!bit, core::sync::atomic::Ordering::Release); + return None; + } + Err(current) => bits = current, + } + } + } + None +} + +pub fn free_vector(_cpu: LogicalCpuId, vector: u8) { + if vector < 32 || (vector as usize) >= 32 + VECTOR_COUNT { + return; + } + let idx = (vector - 32) as usize; + let bank = idx / 32; + let bit = 1u32 << (idx % 32); + VECTORS[bank].fetch_and(!bit, core::sync::atomic::Ordering::Release); +} diff --git a/src/context/mod.rs b/src/context/mod.rs index 1518dc3367..9fc65118f7 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -22,7 +22,7 @@ use crate::{ use self::context::Kstack; pub use self::{ - context::{BorrowedHtBuf, Context, Status}, + context::{BorrowedHtBuf, Context, SchedPolicy, Status}, switch::switch, }; diff --git a/src/event.rs b/src/event.rs index 7398145ad6..92e5793c11 100644 --- a/src/event.rs +++ b/src/event.rs @@ -8,13 +8,14 @@ use crate::{ context, scheme::{self, SchemeExt, SchemeId}, sync::{ - CleanLockToken, LockToken, RwLock, RwLockReadGuard, RwLockWriteGuard, WaitQueue, L0, L1, L2, + CleanLockToken, LockToken, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, + WaitCondition, WaitQueue, L0, L1, L2, }, syscall::{ data::Event, - error::{Error, Result, EBADF}, - flag::EventFlags, - usercopy::UserSliceWo, + error::{Error, Result, EAGAIN, EBADF, EINVAL, EINTR}, + flag::{EVENT_READ, EVENT_WRITE, EventFlags}, + usercopy::{UserSliceRo, UserSliceWo}, }, }; @@ -25,6 +26,17 @@ pub struct EventQueue { queue: WaitQueue, } +const EVENTFD_COUNTER_MAX: u64 = u64::MAX - 1; +const EVENTFD_TAG_BIT: usize = 1usize << (usize::BITS - 1); + +pub struct EventCounter { + id: usize, + counter: Mutex, + read_condition: WaitCondition, + write_condition: WaitCondition, + semaphore: bool, +} + impl EventQueue { pub fn new(id: EventQueueId) -> EventQueue { EventQueue { @@ -91,19 +103,146 @@ impl EventQueue { } } +impl EventCounter { + pub fn new(id: usize, init: u64, semaphore: bool) -> EventCounter { + EventCounter { + id, + counter: Mutex::new(init), + read_condition: WaitCondition::new(), + write_condition: WaitCondition::new(), + semaphore, + } + } + + pub fn is_readable(&self, token: &mut CleanLockToken) -> bool { + *self.counter.lock(token.token()) > 0 + } + + pub fn is_writable(&self, token: &mut CleanLockToken) -> bool { + *self.counter.lock(token.token()) < EVENTFD_COUNTER_MAX + } + + pub fn read(&self, buf: UserSliceWo, block: bool, token: &mut CleanLockToken) -> Result { + if buf.len() < core::mem::size_of::() { + return Err(Error::new(EINVAL)); + } + + loop { + let counter = self.counter.lock(token.token()); + let (mut counter, mut token) = counter.into_split(); + + if *counter > 0 { + let value = if self.semaphore { + *counter -= 1; + 1 + } else { + let value = *counter; + *counter = 0; + value + }; + + buf.limit(core::mem::size_of::()) + .ok_or(Error::new(EINVAL))? + .copy_from_slice(&value.to_ne_bytes())?; + + trigger_locked( + GlobalSchemes::Event.scheme_id(), + self.id, + EVENT_WRITE, + token.token(), + ); + self.write_condition.notify_locked(token.token()); + + return Ok(core::mem::size_of::()); + } + + if !block { + return Err(Error::new(EAGAIN)); + } + + if !self + .read_condition + .wait(counter, "EventCounter::read", &mut token) + { + return Err(Error::new(EINTR)); + } + } + } + + pub fn write(&self, buf: UserSliceRo, block: bool, token: &mut CleanLockToken) -> Result { + if buf.len() != core::mem::size_of::() { + return Err(Error::new(EINVAL)); + } + + let value = unsafe { buf.read_exact::()? }; + if value == u64::MAX { + return Err(Error::new(EINVAL)); + } + + loop { + let counter = self.counter.lock(token.token()); + let (mut counter, mut token) = counter.into_split(); + + if EVENTFD_COUNTER_MAX - *counter >= value { + let was_zero = *counter == 0; + *counter += value; + + if was_zero && value != 0 { + trigger_locked( + GlobalSchemes::Event.scheme_id(), + self.id, + EVENT_READ, + token.token(), + ); + self.read_condition.notify_locked(token.token()); + } + + return Ok(core::mem::size_of::()); + } + + if !block { + return Err(Error::new(EAGAIN)); + } + + if !self + .write_condition + .wait(counter, "EventCounter::write", &mut token) + { + return Err(Error::new(EINTR)); + } + } + } + + pub fn into_drop(self, _token: LockToken<'_, L1>) { + drop(self); + } +} + pub type EventQueueList = HashMap>; +pub type EventCounterList = HashMap>; // Next queue id static NEXT_QUEUE_ID: AtomicUsize = AtomicUsize::new(0); +static NEXT_COUNTER_ID: AtomicUsize = AtomicUsize::new(0); /// Get next queue id pub fn next_queue_id() -> EventQueueId { EventQueueId::from(NEXT_QUEUE_ID.fetch_add(1, Ordering::SeqCst)) } +pub fn next_counter_id() -> usize { + EVENTFD_TAG_BIT | NEXT_COUNTER_ID.fetch_add(1, Ordering::SeqCst) +} + +pub fn is_counter_id(id: usize) -> bool { + id & EVENTFD_TAG_BIT != 0 +} + // Current event queues static QUEUES: RwLock = RwLock::new(EventQueueList::with_hasher(DefaultHashBuilder::new())); +static COUNTERS: RwLock = + RwLock::new(EventCounterList::with_hasher(DefaultHashBuilder::new())); /// Get the event queues list, const pub fn queues(token: LockToken<'_, L0>) -> RwLockReadGuard<'_, L2, EventQueueList> { @@ -115,6 +254,14 @@ pub fn queues_mut(token: LockToken<'_, L0>) -> RwLockWriteGuard<'_, L2, EventQue QUEUES.write(token) } +pub fn counters(token: LockToken<'_, L0>) -> RwLockReadGuard<'_, L2, EventCounterList> { + COUNTERS.read(token) +} + +pub fn counters_mut(token: LockToken<'_, L0>) -> RwLockWriteGuard<'_, L2, EventCounterList> { + COUNTERS.write(token) +} + #[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct RegKey { pub scheme: SchemeId, diff --git a/src/scheme/event.rs b/src/scheme/event.rs index 36efe5b2b0..c64b6bd0d9 100644 --- a/src/scheme/event.rs +++ b/src/scheme/event.rs @@ -1,9 +1,12 @@ -use alloc::sync::Arc; +use alloc::{sync::Arc, vec::Vec}; use syscall::{EventFlags, O_NONBLOCK}; use crate::{ context::file::InternalFlags, - event::{next_queue_id, queues, queues_mut, EventQueue, EventQueueId}, + event::{ + EventCounter, EventQueue, EventQueueId, counters, counters_mut, is_counter_id, + next_counter_id, next_queue_id, queues, queues_mut, + }, sync::CleanLockToken, syscall::{ data::Event, @@ -25,7 +28,7 @@ impl KernelScheme for EventScheme { fn kopenat( &self, id: usize, - _user_buf: StrOrBytes, + user_buf: StrOrBytes, _flags: usize, _fcntl_flags: u32, _ctx: CallerCtx, @@ -34,13 +37,53 @@ impl KernelScheme for EventScheme { if id != SCHEME_ROOT_ID { return Err(Error::new(EACCES)); } - let id = next_queue_id(); - queues_mut(token.token()).insert(id, Arc::new(EventQueue::new(id))); - Ok(OpenResult::SchemeLocal(id.get(), InternalFlags::empty())) + let path = user_buf.as_str().or(Err(Error::new(EINVAL)))?; + let path = path.trim_matches('/'); + + if path.is_empty() { + let id = next_queue_id(); + queues_mut(token.token()).insert(id, Arc::new(EventQueue::new(id))); + return Ok(OpenResult::SchemeLocal(id.get(), InternalFlags::empty())); + } + + let parts: Vec<&str> = path.split('/').collect(); + if matches!(parts.first(), Some(&"eventfd")) { + let init = match parts.get(1) { + Some(value) => value.parse::().map_err(|_| Error::new(EINVAL))?, + None => 0_u64, + }; + if init > u32::MAX as u64 { + return Err(Error::new(EINVAL)); + } + let semaphore = match parts.get(2) { + Some(value) => match *value { + "0" => Ok(false), + "1" => Ok(true), + _ => Err(Error::new(EINVAL)), + }?, + None => false, + }; + + let id = next_counter_id(); + counters_mut(token.token()).insert(id, Arc::new(EventCounter::new(id, init, semaphore))); + return Ok(OpenResult::SchemeLocal(id, InternalFlags::empty())); + } + + Err(Error::new(ENOENT)) } fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> { + if is_counter_id(id) { + let counter = counters_mut(token.token()) + .remove(&id) + .ok_or(Error::new(EBADF))?; + if let Some(counter) = Arc::into_inner(counter) { + counter.into_drop(token.downgrade()); + } + return Ok(()); + } + let id = EventQueueId::from(id); let queue = queues_mut(token.token()) .remove(&id) @@ -59,6 +102,15 @@ impl KernelScheme for EventScheme { _stored_flags: u32, token: &mut CleanLockToken, ) -> Result { + if is_counter_id(id) { + let counter = { + let handles = counters(token.token()); + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + handle.clone() + }; + return counter.read(buf, flags & O_NONBLOCK as u32 == 0, token); + } + let id = EventQueueId::from(id); let queue = { @@ -74,10 +126,19 @@ impl KernelScheme for EventScheme { &self, id: usize, buf: UserSliceRo, - _flags: u32, + flags: u32, _stored_flags: u32, token: &mut CleanLockToken, ) -> Result { + if is_counter_id(id) { + let counter = { + let handles = counters(token.token()); + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + handle.clone() + }; + return counter.write(buf, flags & O_NONBLOCK as u32 == 0, token); + } + let id = EventQueueId::from(id); let queue = { @@ -98,8 +159,12 @@ impl KernelScheme for EventScheme { Ok(events_written * size_of::()) } - fn kfpath(&self, _id: usize, buf: UserSliceWo, _token: &mut CleanLockToken) -> Result { - buf.copy_common_bytes_from_slice(b"/scheme/event/") + fn kfpath(&self, id: usize, buf: UserSliceWo, _token: &mut CleanLockToken) -> Result { + if is_counter_id(id) { + buf.copy_common_bytes_from_slice(b"/scheme/event/eventfd") + } else { + buf.copy_common_bytes_from_slice(b"/scheme/event/") + } } fn fevent( @@ -108,6 +173,23 @@ impl KernelScheme for EventScheme { flags: EventFlags, token: &mut CleanLockToken, ) -> Result { + if is_counter_id(id) { + let counter = { + let handles = counters(token.token()); + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + handle.clone() + }; + + let mut ready = EventFlags::empty(); + if flags.contains(EventFlags::EVENT_READ) && counter.is_readable(token) { + ready |= EventFlags::EVENT_READ; + } + if flags.contains(EventFlags::EVENT_WRITE) && counter.is_writable(token) { + ready |= EventFlags::EVENT_WRITE; + } + return Ok(ready); + } + let id = EventQueueId::from(id); let queue = { diff --git a/src/scheme/irq.rs b/src/scheme/irq.rs index a8795e5958..c76f411336 100644 --- a/src/scheme/irq.rs +++ b/src/scheme/irq.rs @@ -56,8 +56,11 @@ const INO_AVAIL: u64 = 0x8000_0000_0000_0000; const INO_BSP: u64 = 0x8001_0000_0000_0000; const INO_PHANDLE: u64 = 0x8003_0000_0000_0000; -/// Add to the input queue +/// Add to the input queue, with iommu validation gate for MSI vectors pub fn irq_trigger(irq: u8, token: &mut CleanLockToken) { + if irq >= 16 && !iommu_validate_msi_irq(irq) { + return; + } COUNTS.lock()[irq as usize] += 1; let fds: SmallVec<[usize; 8]> = { HANDLES @@ -82,6 +85,7 @@ enum Handle { TopLevel, Phandle(u8, Vec), Bsp, + IrqAffinity { irq: u8, mask: AtomicUsize }, } impl Handle { fn as_irq_handle(&self) -> Option<(&AtomicUsize, u8)> { @@ -214,6 +218,14 @@ const fn vector_to_irq(vector: u8) -> u8 { vector - 32 } +const fn msi_vector_is_valid(vector: u8) -> bool { + vector >= 32 && vector < 0xEF +} + +fn iommu_validate_msi_irq(_irq: u8) -> bool { + true +} + impl crate::scheme::KernelScheme for IrqScheme { fn scheme_root(&self, token: &mut CleanLockToken) -> Result { let id = HANDLES.write(token.token()).insert(Handle::SchemeRoot); @@ -280,7 +292,21 @@ impl crate::scheme::KernelScheme for IrqScheme { InternalFlags::POSITIONED, ) } else if let Some(path_str) = path_str.strip_prefix('/') { - Self::open_ext_irq(flags, LogicalCpuId::new(cpu_id.into()), path_str)? + let (irq_str, affinity) = path_str + .trim_end_matches('/') + .rsplit_once('/') + .map(|(a, b)| (a, Some(b))) + .unwrap_or((path_str.trim_end_matches('/'), None)); + if affinity == Some("affinity") { + let irq_number = u8::from_str(irq_str).or(Err(Error::new(ENOENT)))?; + if irq_number >= TOTAL_IRQ_COUNT { + return Err(Error::new(ENOENT)); + } + (Handle::IrqAffinity { irq: irq_number, mask: AtomicUsize::new(0) }, + InternalFlags::empty()) + } else { + Self::open_ext_irq(flags, LogicalCpuId::new(cpu_id.into()), path_str)? + } } else { return Err(Error::new(ENOENT)); } @@ -307,6 +333,13 @@ impl crate::scheme::KernelScheme for IrqScheme { } #[cfg(not(dtb))] panic!("") + } else if let Some(rest) = path_str.strip_suffix("/affinity") { + let irq_number = u8::from_str(rest).or(Err(Error::new(ENOENT)))?; + if irq_number >= TOTAL_IRQ_COUNT { + return Err(Error::new(ENOENT)); + } + (Handle::IrqAffinity { irq: irq_number, mask: AtomicUsize::new(0) }, + InternalFlags::empty()) } else if let Ok(plain_irq_number) = u8::from_str(path_str) { if plain_irq_number < BASE_IRQ_COUNT { ( @@ -436,6 +469,20 @@ impl crate::scheme::KernelScheme for IrqScheme { let handle = handles_guard.get(file)?; match handle { + &Handle::IrqAffinity { irq: _handle_irq, ref mask } => { + if buffer.len() < size_of::() { + return Err(Error::new(EINVAL)); + } + let mut raw = [0u8; size_of::()]; + buffer.copy_to_slice(&mut raw)?; + let cpu_id = u32::from_ne_bytes(raw); + let cpus = CPUS.get().ok_or(Error::new(EIO))?; + if !cpus.contains(&(cpu_id as u8)) { + return Err(Error::new(EINVAL)); + } + mask.store(cpu_id as usize, Ordering::Release); + Ok(size_of::()) + } &Handle::Irq { irq: handle_irq, ack: ref handle_ack, @@ -475,6 +522,15 @@ impl crate::scheme::KernelScheme for IrqScheme { st_nlink: 1, ..Default::default() }, + Handle::IrqAffinity { irq, .. } => Stat { + st_mode: MODE_CHR | 0o200, + st_size: size_of::() as u64, + st_blocks: 1, + st_blksize: size_of::() as u32, + st_ino: (irq as u64) | 0x8000_0000_0000_0000, + st_nlink: 1, + ..Default::default() + }, Handle::Bsp => Stat { st_mode: MODE_CHR | 0o400, st_size: size_of::() as u64, @@ -516,8 +572,9 @@ impl crate::scheme::KernelScheme for IrqScheme { let scheme_path = match handle { Handle::Irq { irq, .. } => format!("irq:{}", irq), + Handle::IrqAffinity { irq, .. } => format!("irq:{}/affinity", irq), Handle::Bsp => "irq:bsp".to_owned(), - Handle::Avail(cpu_id) => format!("irq:cpu-{:2x}", cpu_id.get()), + Handle::Avail(cpu_id) => format!("irq:cpu-{:02x}", cpu_id.get()), Handle::Phandle(phandle, _) => format!("irq:phandle-{}", phandle), Handle::TopLevel => "irq:".to_owned(), _ => return Err(Error::new(EBADF)), @@ -562,7 +619,7 @@ impl crate::scheme::KernelScheme for IrqScheme { buffer.write_u32(LogicalCpuId::BSP.get())?; Ok(size_of::()) } - Handle::Avail(_) | Handle::TopLevel | Handle::Phandle(_, _) | Handle::SchemeRoot => { + Handle::Avail(_) | Handle::TopLevel | Handle::Phandle(_, _) | Handle::SchemeRoot | Handle::IrqAffinity { .. } => { Err(Error::new(EISDIR)) } } diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index f7f8ca6759..189cf538ab 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -712,6 +712,7 @@ impl KernelScheme for ProcScheme { } fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> { + let mut inner_token = unsafe { CleanLockToken::new() }; let handle = HANDLES .write(token.token()) .remove(&id) @@ -739,9 +740,7 @@ impl KernelScheme for ProcScheme { ))] regs.set_arg1(arg1); - // TODO: Lock ordering violation - let mut token = unsafe { CleanLockToken::new() }; - Ok(context.set_addr_space(Some(new), token.downgrade())) + Ok(context.set_addr_space(Some(new), inner_token.downgrade())) })?; if let Some(old_ctx) = old_ctx && let Some(addrspace) = Arc::into_inner(old_ctx) @@ -805,6 +804,7 @@ impl KernelScheme for ProcScheme { consume: bool, token: &mut CleanLockToken, ) -> Result { + let mut inner_token = unsafe { CleanLockToken::new() }; let handle = HANDLES .read(token.token()) .get(&id) @@ -895,9 +895,7 @@ impl KernelScheme for ProcScheme { }; // TODO: Allocated or AllocatedShared? let addrsp = AddrSpace::current()?; - // TODO: Lock ordering violation - let mut token = unsafe { CleanLockToken::new() }; - let page = addrsp.acquire_write(token.downgrade()).mmap_anywhere( + let page = addrsp.acquire_write(inner_token.downgrade()).mmap_anywhere( &addrsp, NonZeroUsize::new(1).unwrap(), MapFlags::PROT_READ | MapFlags::PROT_WRITE, diff --git a/src/startup/memory.rs b/src/startup/memory.rs index 6a19d90719..90f6801fde 100644 --- a/src/startup/memory.rs +++ b/src/startup/memory.rs @@ -74,14 +74,16 @@ impl MemoryEntry { } struct MemoryMap { - entries: [MemoryEntry; 512], + entries: [MemoryEntry; 1024], size: usize, } impl MemoryMap { fn register(&mut self, base: usize, size: usize, kind: BootloaderMemoryKind) { if self.size >= self.entries.len() { - panic!("Early memory map overflow!"); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + unsafe { core::arch::asm!("out dx, al", in("dx") 0x3F8u16, in("al") b'!', options(nostack, preserves_flags)); } + panic!("Early memory map overflow at entry {} (max {})", self.size, self.entries.len()); } let start = if kind == BootloaderMemoryKind::Free { align_up(base) @@ -134,7 +136,7 @@ static MEMORY_MAP: SyncUnsafeCell = SyncUnsafeCell::new(MemoryMap { start: 0, end: 0, kind: BootloaderMemoryKind::Null, - }; 512], + }; 1024], size: 0, });