Skip to content

Commit 2ceeb26

Browse files
committed
memory: Fix SMP safety and perf issues
1 parent a1a5c13 commit 2ceeb26

12 files changed

Lines changed: 227 additions & 181 deletions

File tree

kernel/src/arch/x86_64/consts.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,3 +282,4 @@ pub const IDT_SX: u8 = 0x1E;
282282
pub const IDT_IPI_PANIC: u8 = 0xFF;
283283
pub const IDT_IPI_RESCHED: u8 = 0xFE;
284284
pub const IDT_IPI_SHOOTDOWN: u8 = 0xFD;
285+
pub const IDT_TIMER: u8 = 0xFC;

kernel/src/arch/x86_64/irq.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,20 @@ unsafe extern "C" fn idt_handler(context: *mut Context) {
269269
consts::IDT_IPI_PANIC => {
270270
halt();
271271
}
272-
consts::IDT_IPI_RESCHED => {
273-
clock::handle_tick();
274-
unsafe { crate::arch::sched::preempt_disable() };
275-
let should_reschedule = unsafe { crate::arch::sched::preempt_enable() };
272+
consts::IDT_TIMER => {
273+
if CpuData::get().id == 0 {
274+
clock::handle_tick();
275+
}
276+
let should_reschedule = CpuData::get().scheduler.tick();
276277
LAPIC.get().eoi();
277278
if should_reschedule {
278-
CpuData::get().scheduler.reschedule();
279+
CpuData::get().scheduler.request_reschedule();
279280
}
280281
}
282+
consts::IDT_IPI_RESCHED => {
283+
LAPIC.get().eoi();
284+
CpuData::get().scheduler.handle_remote_reschedule(from_user);
285+
}
281286
// Any other ISR is an IRQ with a dynamic handler.
282287
_ => {
283288
match &mut IRQ_LINES.get().lock()[isr as usize - 0x20] {

kernel/src/arch/x86_64/system/apic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
arch::x86_64::{
33
asm,
4-
consts::{self, IDT_IPI_RESCHED},
4+
consts::{self, IDT_TIMER},
55
irq::IRQ_LINES,
66
},
77
clock,
@@ -151,7 +151,7 @@ impl LocalApic {
151151
);
152152

153153
// Finally, run the periodic timer interrupt.
154-
lapic.write_reg(lapic_regs::LVT_TR, IDT_IPI_RESCHED as u64 | 0x20000);
154+
lapic.write_reg(lapic_regs::LVT_TR, IDT_TIMER as u64 | 0x20000);
155155
lapic.write_reg(lapic_regs::DCR, 3);
156156
lapic.write_reg(
157157
lapic_regs::ICR_TIMER,

kernel/src/arch/x86_64/system/smp.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,6 @@ fn start_ap(temp_cr3: u32, id: u32) {
322322

323323
unsafe {
324324
KernelAlloc::dealloc(mem, 1);
325-
KernelAlloc::dealloc_bytes(stack_mem, KERNEL_STACK_SIZE);
326325
}
327326
}
328327

kernel/src/memory/bump.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Early memory setup and allocator.
22
33
use super::{
4-
PhysAddr,
54
pmm::{AllocFlags, PageAllocator},
5+
PhysAddr,
66
};
77
use crate::arch::{self};
88
use alloc::alloc::AllocError;
@@ -25,7 +25,7 @@ impl PageAllocator for BumpAllocator {
2525
let mem = PhysAddr(BUMP_CURRENT.fetch_add(bytes, Ordering::Relaxed));
2626

2727
if !flags.contains(AllocFlags::NoZero) {
28-
unsafe { (mem.as_hhdm() as *mut u8).write_bytes(0, bytes) };
28+
mem.zero_hhdm(bytes);
2929
}
3030
return Ok(mem);
3131
}
@@ -38,4 +38,10 @@ impl PageAllocator for BumpAllocator {
3838
"The bump allocator is not supposed to free anything. Remove this .dealloc()"
3939
)
4040
}
41+
42+
unsafe fn dealloc_bytes(_addr: PhysAddr, _bytes: usize) {
43+
unimplemented!(
44+
"The bump allocator is not supposed to free anything. Remove this .dealloc_bytes()"
45+
)
46+
}
4147
}

kernel/src/memory/mod.rs

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
arch::{self, virt::get_page_size},
2222
boot::{BootInfo, PhysMemoryUsage},
2323
memory::virt::{allocator::VirtualAllocator, mmu::PageTable},
24-
util::{align_down, align_up, mutex::spin::SpinMutex},
24+
util::{align_down, align_up, divide_up, mutex::spin::SpinMutex},
2525
};
2626
use alloc::sync::Arc;
2727
use bump::BumpAllocator;
@@ -44,6 +44,10 @@ impl PhysAddr {
4444
pub fn as_hhdm<T>(self) -> *mut T {
4545
VirtAddr(self.0 + HHDM_START.get().0).as_ptr()
4646
}
47+
48+
pub(crate) fn zero_hhdm(self, len: usize) {
49+
unsafe { ptr::write_bytes(self.as_hhdm::<u8>(), 0, len) };
50+
}
4751
}
4852

4953
/// Represents a virtual address. It can't be directly read from or written to.
@@ -325,36 +329,28 @@ pub fn MEMORY_STAGE() {
325329
arch::virt::get_hhdm_base().value()
326330
);
327331

328-
// We record metadata for every single page of available memory in a large array.
329-
// This array is contiguous in virtual memory, but is sparsely populated.
330-
// Only those array entries which represent usable memory are mapped.
332+
// We record metadata for every single physical page in a large array.
333+
// This array is contiguous in virtual memory so it can be represented as
334+
// an ordinary Rust slice by the physical allocator.
331335

332336
// The offset where we start mapping the page array.
333337
log!("Highest physical address is {:#018x}", highest_phys.0);
334338
let page_base = arch::virt::get_pfndb_base();
335-
let page_length = highest_phys.0 / size_of::<Page>();
336339
let page_size = get_page_size();
337-
338-
memory_map
339-
.iter()
340-
.filter(|x| x.length != 0)
341-
.for_each(|entry| {
342-
let length = align_up((entry.length / page_size) * size_of::<Page>(), page_size);
343-
let virt = align_down(
344-
(page_base + entry.address.0 / page_size * size_of::<Page>()).value(),
345-
page_size,
346-
);
347-
348-
for page in (0..=length).step_by(page_size) {
349-
table
350-
.map_single::<BumpAllocator>(
351-
(virt + page).into(),
352-
BumpAllocator::alloc(1, AllocFlags::empty()).unwrap(),
353-
VmFlags::Read | VmFlags::Write,
354-
)
355-
.unwrap();
356-
}
357-
});
340+
let page_length = divide_up(highest_phys.0, page_size);
341+
let page_array_len = align_up(page_length * size_of::<Page>(), page_size);
342+
343+
// The physical allocator keeps the PFN database as a Rust slice, which
344+
// requires the whole range to be mapped and backed by memory.
345+
for page in (0..page_array_len).step_by(page_size) {
346+
table
347+
.map_single::<BumpAllocator>(
348+
(page_base.value() + page).into(),
349+
BumpAllocator::alloc(1, AllocFlags::empty()).unwrap(),
350+
VmFlags::Read | VmFlags::Write,
351+
)
352+
.unwrap();
353+
}
358354

359355
log!(
360356
"Initalized page array region at {:#018x}",
@@ -386,7 +382,8 @@ pub fn MEMORY_STAGE() {
386382
// ----------------------------------------
387383

388384
// Initialize the physical memory allocator.
389-
pmm::init(&memory_map, (page_base.as_ptr(), page_length));
385+
let page_db = unsafe { core::slice::from_raw_parts_mut(page_base.as_ptr(), page_length) };
386+
pmm::init(&memory_map, page_db);
390387

391388
// Save the page table.
392389
unsafe { virt::KERNEL_PAGE_TABLE.init(Arc::new(table)) };

0 commit comments

Comments
 (0)