Skip to content

Commit 445778e

Browse files
task: reduce the amount of OOMs
Signed-off-by: Andy-Python-Programmer <[email protected]>
1 parent bcd5897 commit 445778e

File tree

7 files changed

+116
-18
lines changed

7 files changed

+116
-18
lines changed

aero.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,9 +470,11 @@ def run_in_emulator(args, iso_path):
470470
print("Running with KVM acceleration enabled")
471471

472472
if platform.system() == 'Darwin':
473-
qemu_args += ['-accel', 'hvf', '-cpu', 'qemu64,+la57' if args.la57 else 'qemu64']
473+
qemu_args += ['-accel', 'hvf', '-cpu',
474+
'qemu64,+la57' if args.la57 else 'qemu64']
474475
else:
475-
qemu_args += ['-enable-kvm', '-cpu', 'host,+la57' if args.la57 else 'host']
476+
qemu_args += ['-enable-kvm', '-cpu',
477+
'host,+la57' if args.la57 else 'host']
476478
else:
477479
qemu_args += ["-cpu", "qemu64,+la57" if args.la57 else "qemu64"]
478480

src/aero_kernel/src/arch/x86_64/task.rs

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,10 @@ const USERLAND_STACK_BOTTOM: VirtAddr = USERLAND_STACK_TOP.const_sub_u64(USERLAN
114114

115115
pub struct ArchTask {
116116
context: Unique<Context>,
117+
117118
address_space: AddressSpace,
118119
context_switch_rsp: VirtAddr,
120+
user: bool,
119121

120122
fs_base: VirtAddr,
121123
gs_base: VirtAddr,
@@ -130,29 +132,32 @@ impl ArchTask {
130132
// Since the IDLE task is a special kernel task, we use the kernel's
131133
// address space here and we also use the kernel privilage level here.
132134
address_space: AddressSpace::this(),
135+
user: false,
133136

134137
fs_base: VirtAddr::zero(),
135138
gs_base: VirtAddr::zero(),
136139
}
137140
}
138141

139142
pub fn new_kernel(entry_point: VirtAddr, enable_interrupts: bool) -> Self {
143+
let switch_stack = Self::alloc_switch_stack().unwrap().as_mut_ptr::<u8>();
144+
140145
let task_stack = unsafe {
141146
let layout = Layout::from_size_align_unchecked(4096 * 16, 0x1000);
142147
alloc_zeroed(layout).add(layout.size())
143148
};
144149

145150
let address_space = AddressSpace::this();
146151

147-
let mut stack_ptr = task_stack as u64;
152+
let mut stack_ptr = switch_stack as u64;
148153
let mut stack = StackHelper::new(&mut stack_ptr);
149154

150155
let kframe = unsafe { stack.offset::<InterruptErrorStack>() };
151156

152157
kframe.stack.iret.ss = 0x10; // kernel stack segment
153158
kframe.stack.iret.cs = 0x08; // kernel code segment
154159
kframe.stack.iret.rip = entry_point.as_u64();
155-
kframe.stack.iret.rsp = unsafe { task_stack.sub(8) as u64 };
160+
kframe.stack.iret.rsp = task_stack as u64;
156161
kframe.stack.iret.rflags = if enable_interrupts { 0x200 } else { 0x00 };
157162

158163
extern "C" {
@@ -168,7 +173,8 @@ impl ArchTask {
168173
Self {
169174
context: unsafe { Unique::new_unchecked(context) },
170175
address_space,
171-
context_switch_rsp: VirtAddr::new(task_stack as u64),
176+
context_switch_rsp: VirtAddr::new(switch_stack as u64),
177+
user: false,
172178

173179
fs_base: VirtAddr::zero(),
174180
gs_base: VirtAddr::zero(),
@@ -184,6 +190,8 @@ impl ArchTask {
184190
}
185191

186192
pub fn fork(&self) -> Result<Self, MapToError<Size4KiB>> {
193+
assert!(self.user, "cannot fork a kernel task");
194+
187195
let new_address_space = AddressSpace::this().offset_page_table().fork()?;
188196

189197
// Since the fork function marks all of the userspace entries in both the forked
@@ -193,15 +201,7 @@ impl ArchTask {
193201
asm!("mov cr3, {}", in(reg) controlregs::read_cr3_raw(), options(nostack));
194202
}
195203

196-
let switch_stack = unsafe {
197-
let frame: PhysFrame = FRAME_ALLOCATOR.allocate_frame().unwrap();
198-
199-
frame
200-
.start_address()
201-
.as_hhdm_virt()
202-
.as_mut_ptr::<u8>()
203-
.add(Size4KiB::SIZE as usize)
204-
};
204+
let switch_stack = Self::alloc_switch_stack()?.as_mut_ptr::<u8>();
205205

206206
let mut old_stack_ptr = self.context_switch_rsp.as_u64();
207207
let mut old_stack = StackHelper::new(&mut old_stack_ptr);
@@ -232,6 +232,7 @@ impl ArchTask {
232232
context: unsafe { Unique::new_unchecked(context) },
233233
context_switch_rsp: VirtAddr::new(switch_stack as u64),
234234
address_space: new_address_space,
235+
user: false,
235236

236237
// The FS and GS bases are inherited from the parent process.
237238
fs_base: self.fs_base.clone(),
@@ -247,9 +248,18 @@ impl ArchTask {
247248
argv: Option<ExecArgs>,
248249
envv: Option<ExecArgs>,
249250
) -> Result<(), MapToError<Size4KiB>> {
250-
let address_space = AddressSpace::new()?;
251+
let address_space = if self.user {
252+
self.unref_pt();
253+
AddressSpace::new()?
254+
} else {
255+
AddressSpace::new()?
256+
};
257+
251258
let loaded_binary = vm.load_bin(executable).expect("exec: failed to load ELF");
252259

260+
// a kernel task can only execute a user executable
261+
self.user = true;
262+
253263
// mmap the userland stack...
254264
vm.mmap(
255265
USERLAND_STACK_BOTTOM,
@@ -335,6 +345,49 @@ impl ArchTask {
335345
Ok(())
336346
}
337347

348+
/// Allocates a new context switch stack for the process and returns the stack
349+
/// top address. See the module level documentation for more information.
350+
fn alloc_switch_stack() -> Result<VirtAddr, MapToError<Size4KiB>> {
351+
let frame: PhysFrame<Size4KiB> = FRAME_ALLOCATOR
352+
.allocate_frame()
353+
.ok_or(MapToError::FrameAllocationFailed)?;
354+
355+
Ok(frame.start_address().as_hhdm_virt() + Size4KiB::SIZE)
356+
}
357+
358+
fn unref_pt(&mut self) {
359+
self.address_space
360+
.offset_page_table()
361+
.page_table()
362+
.for_each_entry(
363+
PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE,
364+
|entry| {
365+
entry.unref_vm_frame();
366+
entry.set_unused();
367+
368+
Ok(())
369+
},
370+
)
371+
.expect("dealloc: failed to unref the page table");
372+
}
373+
374+
/// Deallocates the architecture-specific task resources. This function is called
375+
/// when the process is turned into a zombie.
376+
pub fn dealloc(&mut self) {
377+
if self.user {
378+
self.unref_pt();
379+
}
380+
381+
// deallocate the switch stack
382+
{
383+
let frame: PhysFrame<Size4KiB> = PhysFrame::containing_address(
384+
(self.context_switch_rsp - Size4KiB::SIZE).as_hhdm_phys(),
385+
);
386+
387+
FRAME_ALLOCATOR.deallocate_frame(frame);
388+
}
389+
}
390+
338391
/// Returns the saved GS base for this task.
339392
pub fn get_gs_base(&self) -> VirtAddr {
340393
self.gs_base

src/aero_kernel/src/mem/paging/addr.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ impl VirtAddr {
111111
}
112112
}
113113

114+
/// Converts this HHDM (Higher Half Direct Map) virtual address to its physical address.
115+
pub fn as_hhdm_phys(&self) -> PhysAddr {
116+
unsafe { PhysAddr::new(self.clone() - crate::PHYSICAL_MEMORY_OFFSET) }
117+
}
118+
114119
/// Returns if the address is valid to read `sizeof(T)` bytes at the address.
115120
fn validate_read<T: Sized>(&self) -> bool {
116121
(*self + core::mem::size_of::<T>()) <= crate::arch::task::userland_last_address()

src/aero_kernel/src/mem/paging/frame.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ unsafe impl FrameAllocator<Size4KiB> for LockedFrameAllocator {
6161
.map(|f| PhysFrame::containing_address(f))
6262
})
6363
.unwrap_or(None)
64+
.map(|frame| {
65+
frame.as_slice_mut().fill(0);
66+
frame
67+
})
6468
}
6569

6670
fn deallocate_frame(&self, frame: PhysFrame<Size4KiB>) {
@@ -81,6 +85,10 @@ unsafe impl FrameAllocator<Size2MiB> for LockedFrameAllocator {
8185
.map(|f| PhysFrame::containing_address(f))
8286
})
8387
.unwrap_or(None)
88+
.map(|frame| {
89+
frame.as_slice_mut().fill(0);
90+
frame
91+
})
8492
}
8593

8694
fn deallocate_frame(&self, frame: PhysFrame<Size2MiB>) {
@@ -548,8 +556,9 @@ impl VmFrame {
548556
pub fn dec_ref_count(&self) {
549557
let mut this = self.lock.lock();
550558

551-
assert!(this.use_count > 0);
552-
this.use_count -= 1;
559+
if this.use_count > 0 {
560+
this.use_count -= 1;
561+
}
553562
}
554563

555564
pub fn inc_ref_count(&self) {
@@ -574,6 +583,14 @@ mod tests {
574583
let mut offset_table = address_space.offset_page_table();
575584

576585
let frame: PhysFrame = unsafe { FRAME_ALLOCATOR.allocate_frame().unwrap() };
586+
587+
assert!(!FRAME_ALLOCATOR
588+
.0
589+
.get()
590+
.unwrap()
591+
.lock()
592+
.is_free(frame.start_address(), 0));
593+
577594
let page = Page::<Size4KiB>::containing_address(VirtAddr::new(0xcafebabedea));
578595

579596
let vm_frame = frame.start_address().as_vm_frame().unwrap();

src/aero_kernel/src/mem/paging/mapper.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,10 @@ impl<'a> OffsetPageTable<'a> {
10451045
inner: MappedPageTable::new(page_table, phys_offset),
10461046
}
10471047
}
1048+
1049+
pub fn page_table(&mut self) -> &mut PageTable {
1050+
self.inner.page_table
1051+
}
10481052
}
10491053

10501054
#[derive(Debug)]

src/aero_kernel/src/mem/paging/page_table.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,23 @@ impl PageTable {
283283
}
284284
}
285285

286+
pub fn for_each_entry(
287+
&mut self,
288+
flags: PageTableFlags,
289+
mut fun: impl FnMut(&mut PageTableEntry) -> Result<(), MapToError<Size4KiB>>,
290+
) -> Result<(), MapToError<Size4KiB>> {
291+
self.for_entries_mut(flags, |_, _entry, table| {
292+
table.for_entries_mut(flags, |_, _entry, table| {
293+
table.for_entries_mut(flags, |_, _entry, table| {
294+
table.for_entries_mut(flags, |_, entry, _| fun(entry))?;
295+
Ok(())
296+
})?;
297+
Ok(())
298+
})?;
299+
Ok(())
300+
})
301+
}
302+
286303
pub fn for_entries_mut(
287304
&mut self,
288305
flags: PageTableFlags,

src/aero_kernel/src/userland/task.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ impl Task {
543543
}
544544

545545
pub(super) fn into_zombie(&self) {
546-
// TODO: Deallocate the arch task's resources.
546+
self.arch_task_mut().dealloc();
547547

548548
if let Some(parent) = self.get_parent() {
549549
parent.remove_child(self);

0 commit comments

Comments
 (0)