Skip to content

Commit 9c8bad2

Browse files
committed
Identify the kernel's stack guard page, shifted stack
The main two changes here are to document and identify the guard page before the kernel's stack to help detect stack overflows, and to shift the stack down a page so it ends on a neater address. I've also updated the docs in a few places to be clearer. I would have liked to update the double fault handler to identify kernel stack overflows with more confidence, but the stack pointer could still be in valid stack space. I may come back to this later. Signed-off-by: SlyMarbo <[email protected]>
1 parent e11563e commit 9c8bad2

File tree

6 files changed

+28
-11
lines changed

6 files changed

+28
-11
lines changed

kernel/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ run-command = [
3131

3232
[package.metadata.bootloader]
3333
boot-info-address = "0xffff800040000000"
34-
kernel-stack-address = "0xffff800055550000"
34+
kernel-stack-address = "0xffff80005554f000"
3535
kernel-stack-size = 128
3636
physical-memory-offset = "0xffff800060000000"
3737

kernel/src/memory/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ Firefly uses the following layout of virtual memory:
44

55
| Region | Start address | Last address | Pages | Size |
66
| ------------------- | ----------------------: | ----------------------: | --------------------: | --------: |
7-
| NULL page | `0x0` | `0x1f_ffff` | 1x 2 MiB page | 2 MiB |
7+
| NULL page | `0x0` | `0x1f_ffff` | not mapped | 2 MiB |
88
| Userspace | `0x20_0000` | `0x7fff_ffff_ffff` | rest of memory | < 128 TiB |
99
| Kernel binary | `0xffff_8000_0000_0000` | `0xffff_8000_3fff_ffff` | up to 512x 2 MiB page | 1 GiB |
10-
| Bootloader info | `0xffff_8000_4000_0000` | `0xffff_8000_4000_0fff` | 1x 4 kiB page | 4 kiB |
11-
| Kernel heap | `0xffff_8000_4444_0000` | `0xffff_8000_444b_ffff` | 128x 4 kiB page | 512 kiB |
12-
| Kernel stack | `0xffff_8000_5555_1000` | `0xffff_8000_555d_0fff` | 128x 4 kiB page | 512 kiB |
10+
| Bootloader info | `0xffff_8000_4000_0000` | `0xffff_8000_4000_0fff` | 1x 4 KiB page | 4 KiB |
11+
| Kernel heap | `0xffff_8000_4444_0000` | `0xffff_8000_444b_ffff` | 128x 4 KiB page | 512 KiB |
12+
| Kernel stack guard | `0xffff_8000_5554_f000` | `0xffff_8000_5554_ffff` | not mapped | 4 KiB |
13+
| Kernel stack | `0xffff_8000_5555_0000` | `0xffff_8000_555c_ffff` | 128x 4 KiB page | 512 KiB |
1314
| Physical memory map | `0xffff_8000_6000_0000` | `0xffff_ffff_ffff_ffff` | rest of memory | < 128 TiB |

kernel/src/memory/constants.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use x86_64::{PhysAddr, VirtAddr};
2121
// | Kernel binary | 0xffff_8000_0000_0000 | 0xffff_8000_3fff_ffff |
2222
// | Bootloader info | 0xffff_8000_4000_0000 | 0xffff_8000_4000_0fff |
2323
// | Kernel heap | 0xffff_8000_4444_0000 | 0xffff_8000_444b_ffff |
24-
// | Kernel stack | 0xffff_8000_5555_1000 | 0xffff_8000_555d_0fff |
24+
// | Kernel stack guard | 0xffff_8000_5554_f000 | 0xffff_8000_5554_ffff |
25+
// | Kernel stack | 0xffff_8000_5555_0000 | 0xffff_8000_555c_ffff |
2526
// | Physical memory map | 0xffff_8000_6000_0000 | 0xffff_ffff_ffff_ffff |
2627

2728
/// NULL_PAGE is reserved and always unmapped to ensure that null pointer
@@ -59,14 +60,22 @@ pub const KERNEL_HEAP: VirtAddrRange = VirtAddrRange::new(KERNEL_HEAP_START, KER
5960
const KERNEL_HEAP_START: VirtAddr = const_virt_addr(0xffff_8000_4444_0000 as u64);
6061
const KERNEL_HEAP_END: VirtAddr = const_virt_addr(0xffff_8000_444b_ffff as u64);
6162

63+
/// KERNEL_STACK_GUARD is the area of memory we deliberately leave unmapped
64+
/// so we can diagnose stack overflows by spotting page faults in this region.
65+
///
66+
pub const KERNEL_STACK_GUARD: VirtAddrRange =
67+
VirtAddrRange::new(KERNEL_STACK_GUARD_START, KERNEL_STACK_GUARD_END);
68+
const KERNEL_STACK_GUARD_START: VirtAddr = const_virt_addr(0xffff_8000_5554_f000 as u64);
69+
const KERNEL_STACK_GUARD_END: VirtAddr = const_virt_addr(0xffff_8000_5554_ffff as u64);
70+
6271
/// KERNEL_STACK is the virtual address of the kernel's stack.
6372
///
6473
/// Note that the stack counts downwards, so the start address is larger than
6574
/// the end address.
6675
///
6776
pub const KERNEL_STACK: VirtAddrRange = VirtAddrRange::new(KERNEL_STACK_END, KERNEL_STACK_START);
68-
const KERNEL_STACK_START: VirtAddr = const_virt_addr(0xffff_8000_555d_0fff as u64);
69-
const KERNEL_STACK_END: VirtAddr = const_virt_addr(0xffff_8000_5555_1000 as u64);
77+
const KERNEL_STACK_START: VirtAddr = const_virt_addr(0xffff_8000_555c_ffff as u64);
78+
const KERNEL_STACK_END: VirtAddr = const_virt_addr(0xffff_8000_5555_0000 as u64);
7079

7180
/// PHYSICAL_MEMORY_OFFSET is the virtual address at which the mapping of
7281
/// all physical memory begins. That is, for any valid physical address,

kernel/src/memory/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ pub mod vmm;
189189

190190
pub use crate::memory::constants::{
191191
phys_to_virt_addr, VirtAddrRange, BOOT_INFO, KERNEL_BINARY, KERNEL_HEAP, KERNEL_STACK,
192-
NULL_PAGE, PHYSICAL_MEMORY, PHYSICAL_MEMORY_OFFSET, USERSPACE,
192+
KERNEL_STACK_GUARD, NULL_PAGE, PHYSICAL_MEMORY, PHYSICAL_MEMORY_OFFSET, USERSPACE,
193193
};
194194

195195
// PML4 functionality.

kernel/src/memory/vmm/mapping.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
use crate::memory::{
55
phys_to_virt_addr, VirtAddrRange, BOOT_INFO, KERNEL_BINARY, KERNEL_HEAP, KERNEL_STACK,
6-
NULL_PAGE, PHYSICAL_MEMORY, USERSPACE,
6+
KERNEL_STACK_GUARD, NULL_PAGE, PHYSICAL_MEMORY, USERSPACE,
77
};
88
use alloc::vec::Vec;
99
use core::fmt;
@@ -154,6 +154,8 @@ pub unsafe fn level_4_table(pml4: &PageTable) -> Vec<Mapping> {
154154
PagePurpose::KernelHeap
155155
} else if KERNEL_STACK.contains(&range) {
156156
PagePurpose::KernelStack
157+
} else if KERNEL_STACK_GUARD.contains(&range) {
158+
PagePurpose::KernelStackGuard
157159
} else if PHYSICAL_MEMORY.contains(&range) {
158160
PagePurpose::AllPhysicalMemory
159161
} else {
@@ -210,6 +212,7 @@ pub enum PagePurpose {
210212
KernelStatics,
211213
KernelBinaryUnknown,
212214
KernelStack,
215+
KernelStackGuard,
213216
KernelHeap,
214217
AllPhysicalMemory,
215218
}
@@ -227,6 +230,7 @@ impl fmt::Display for PagePurpose {
227230
PagePurpose::KernelStatics => write!(f, " (kernel statics)"),
228231
PagePurpose::KernelBinaryUnknown => write!(f, " (kernel binary unknown)"),
229232
PagePurpose::KernelStack => write!(f, " (kernel stack)"),
233+
PagePurpose::KernelStackGuard => write!(f, " (kernel stack guard)"),
230234
PagePurpose::KernelHeap => write!(f, " (kernel heap)"),
231235
PagePurpose::AllPhysicalMemory => write!(f, " (all physical memory)"),
232236
}

kernel/src/memory/vmm/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ unsafe fn remap_kernel(mapper: &mut OffsetPageTable) {
7575
for mapping in mappings.iter() {
7676
match mapping.purpose {
7777
// Unmap pages we no longer need.
78-
PagePurpose::Unknown | PagePurpose::NullPage | PagePurpose::Userspace => {
78+
PagePurpose::Unknown
79+
| PagePurpose::NullPage
80+
| PagePurpose::Userspace
81+
| PagePurpose::KernelStackGuard => {
7982
mapping.unmap(mapper).expect("failed to unmap page");
8083
}
8184
// Global and read-write (kernel stack, heap, data, physical memory).

0 commit comments

Comments
 (0)