From 35340a80c41466ca08d87205cb056fface805cb3 Mon Sep 17 00:00:00 2001 From: R Aadarsh Date: Sun, 5 Jul 2026 15:01:48 +0530 Subject: [PATCH] * Add ACPI-NUMA parsing code for ARM * Fix bug in the x86 code that caused incorrect cpu-node mapping * Remove the usage of page mappers. Instead use the already existing linear mapping --- src/acpi/srat/aarch64.rs | 103 +++++++++++++++++++++++++++++++++++++-- src/acpi/srat/x86.rs | 36 +++++--------- src/numa.rs | 16 +++++- 3 files changed, 125 insertions(+), 30 deletions(-) diff --git a/src/acpi/srat/aarch64.rs b/src/acpi/srat/aarch64.rs index e6b4e6363e..4cd126ccb3 100644 --- a/src/acpi/srat/aarch64.rs +++ b/src/acpi/srat/aarch64.rs @@ -1,8 +1,105 @@ -use crate::acpi::srat::Srat; +use core::{ops::Add, slice, u32}; -pub fn init_srat( +use rmm::{Arch, BumpAllocator, FrameAllocator, FrameCount, PhysicalAddress}; + +use crate::{ + acpi::srat::{to_usize, Srat, SratEntry}, + cpu_set::MAX_CPU_COUNT, + memory::{round_up_pages, PAGE_SIZE}, + numa::{self, assign_memory_id, assign_node_id, NumaMemory}, +}; + +pub fn init_srat( allocator: &mut BumpAllocator, srat: &Srat, ) -> (&'static [u32], &'static [u32], &'static [NumaMemory]) { - // todo + let dom_node_map_ptr = allocator + .allocate(FrameCount::new( + round_up_pages(numa::MAX_DOMAINS * size_of::()) / PAGE_SIZE, + )) + .expect("Failed to allocate pages for domain-node-map") + .data(); + + let va = crate::memory::RmmA::phys_to_virt(PhysicalAddress::new(dom_node_map_ptr)).data(); + let dom_node_map_ptr = va.data() as *mut u32; + + // occupies 521 bytes + let dom_node_map = unsafe { slice::from_raw_parts_mut(dom_node_map_ptr, numa::MAX_DOMAINS) }; + + // occupies 512 bytes + let cpus = unsafe { + slice::from_raw_parts_mut( + dom_node_map_ptr.add(numa::MAX_DOMAINS as usize * size_of::()), + MAX_CPU_COUNT as usize, + ) + }; + + // remaining 3072 bytes: can accomodate 128 Mem entries + let mem = unsafe { + slice::from_raw_parts_mut( + dom_node_map_ptr + .add(numa::MAX_DOMAINS) + .add(MAX_CPU_COUNT as usize) as *mut NumaMemory, + numa::MAX_DOMAINS * size_of::(), + ) + }; + + cpus.fill(u32::MAX); + dom_node_map.fill(u32::MAX); + mem.fill(NumaMemory { + start: 0, + length: 0, + node_id: 0, + _pad: [0; 4], + }); + + for affinity in srat { + match affinity { + SratEntry::MemoryAffinity(memory_affinity) => { + let start = to_usize( + memory_affinity.base_address_low, + memory_affinity.base_address_high, + ); + let length = to_usize(memory_affinity.length_low, memory_affinity.length_high); + if length == 0 { + continue; + } + if memory_affinity.flags & 1 == 0 { + // memory disabled + continue; + } + if memory_affinity.flags & (1 << 1) != 0 { + // memory hot-pluggable + continue; + } + if dom_node_map[memory_affinity.proximity_domain as usize] == u32::MAX { + let node = assign_node_id(true); + dom_node_map[memory_affinity.proximity_domain as usize] = node as u32; + } + let mem_id = assign_memory_id() as u32; + mem[mem_id as usize] = NumaMemory { + start, + length, + node_id: dom_node_map[memory_affinity.proximity_domain as usize], + _pad: [0u8; 4], + }; + } + SratEntry::GiccAffinity(gicc_affinity) => { + if gicc_affinity.flags & 1 == 0 { + // disabled + continue; + } + let id = gicc_affinity.processor_uid; + let dom = gicc_affinity.proximity_domain; + if dom_node_map[dom as usize] == u32::MAX { + let node = assign_node_id(true); + dom_node_map[dom as usize] = node as u32; + } + cpus[id as usize] = dom_node_map[dom as usize]; + } + _ => continue, + } + } + + (dom_node_map, cpus, mem) } diff --git a/src/acpi/srat/x86.rs b/src/acpi/srat/x86.rs index e65e71c4be..78bb835ec9 100644 --- a/src/acpi/srat/x86.rs +++ b/src/acpi/srat/x86.rs @@ -1,13 +1,13 @@ use core::{iter, slice}; use hashbrown::HashMap; -use rmm::{Arch, BumpAllocator, FrameAllocator}; +use rmm::{Arch, BumpAllocator, FrameAllocator, PhysicalAddress}; use crate::{ acpi::srat::{to_usize, Srat, SratEntry}, cpu_set, memory::{self, PAGE_SIZE}, - numa::{self, NumaMemory}, + numa::{self, assign_memory_id, NumaMemory}, }; #[inline(always)] @@ -27,16 +27,9 @@ pub fn init_srat( memory::round_up_pages(numa::MAX_DOMAINS * size_of::()) / PAGE_SIZE, )) .expect("Failed to allocate memory for storing NUMA info"); - let mut mapper = unsafe { rmm::PageMapper::current(rmm::TableKind::Kernel, allocator) }; - let mut flags = rmm::PageFlags::::new(); - let flags = flags.write(true); - let dom_node_map_ptr = unsafe { - let (va, flush) = mapper - .map_linearly(dom_node_map, flags) - .expect("Failed to map NUMA info pages"); - flush.flush(); - va.data() as *mut u32 - }; + + let dom_node_map_ptr = + unsafe { crate::memory::RmmA::phys_to_virt(dom_node_map).data() as *mut u32 }; // Occupies 512 bytes (1/8th of a page) let dom_node_map: &'static mut [u32] = unsafe { slice::from_raw_parts_mut(dom_node_map_ptr, numa::MAX_DOMAINS) }; @@ -86,7 +79,7 @@ pub fn init_srat( memories.fill(NumaMemory { start: 0, length: 0, - dom: 0, + node_id: 0, _pad: [0; 4], }); @@ -129,10 +122,11 @@ pub fn init_srat( let node_id = numa::assign_node_id(true); dom_node_map[dom as usize] = node_id as u32; } - memories[dom_node_map[dom as usize] as usize] = numa::NumaMemory { + let mem_id = assign_memory_id() as u32; + memories[mem_id as usize] = numa::NumaMemory { start, length, - dom: dom_node_map[dom as usize], + node_id: dom_node_map[dom as usize], _pad: [0u8; 4], }; } @@ -146,19 +140,11 @@ pub fn init_srat( let node_id = numa::assign_node_id(true); dom_node_map[dom as usize] = node_id as u32; } - cpus[dom_node_map[dom as usize] as usize] = - processor_local_affinity.proximity_domain; + cpus[processor_local_affinity.x2apic_id as usize] = dom_node_map[dom as usize]; } _ => continue, } } - let mut flags = rmm::PageFlags::::new(); - let flags = flags.write(false); - let flush = unsafe { - mapper - .remap(rmm::VirtualAddress::new(dom_node_map_ptr.addr()), flags) - .expect("Unable to make NUMA info page read-only") - }; - flush.flush(); + (dom_node_map, cpus, memories) } diff --git a/src/numa.rs b/src/numa.rs index df5a326fb9..a8429c68c6 100644 --- a/src/numa.rs +++ b/src/numa.rs @@ -1,3 +1,5 @@ +use core::ops::Add; + use crate::{ acpi, cpu_set::LogicalCpuId, @@ -19,7 +21,7 @@ static DISTANCES: Once<&'static [u8]> = Once::new(); pub struct NumaMemory { pub start: usize, pub length: usize, - pub dom: u32, + pub node_id: u32, pub _pad: [u8; 4], } @@ -51,6 +53,16 @@ pub fn assign_node_id(modify: bool) -> u8 { } } +pub fn assign_memory_id() -> u8 { + static mut MEMORY_ID: u8 = 0; + if unsafe { MEMORY_ID } >= 128 { + panic!("Maximum number of memory regions supported is 128"); + } + let old = unsafe { MEMORY_ID }; + unsafe { MEMORY_ID = MEMORY_ID.add(1) }; + old +} + pub fn domain_to_node_id(domain_id: u32) -> Option { Some(*DOMAIN_NODE_MAP.get()?.get(domain_id as usize)?) } @@ -79,7 +91,7 @@ pub fn dump_info() { } println!( "Memory Block starting at address {:#x} of size {:#x} bytes : Node {}", - memories[i].start, memories[i].length, memories[i].dom + memories[i].start, memories[i].length, memories[i].node_id ); } } else {