Skip to content

Commit 0ad45b7

Browse files
committed
Rewrite
1 parent 0d2656f commit 0ad45b7

8 files changed

+343
-216
lines changed

Cargo.lock

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ panic = "abort"
1919

2020
[profile.release]
2121
panic = "abort"
22-
lto = true
22+
lto = false
23+
debug = true

linker.ld

+9-1
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,24 @@ SECTIONS {
77
. += 512;
88
/* page tables */
99
. = ALIGN(0x1000);
10+
__page_table_start = .;
1011
_p4 = .;
1112
. += 0x1000;
1213
_p3 = .;
1314
. += 0x1000;
1415
_p2 = .;
1516
. += 0x1000;
17+
_p1 = .;
18+
. += 0x1000;
19+
__page_table_end = .;
20+
__bootloader_start = .;
1621
_memory_map = .;
1722
. += 0x1000;
1823

19-
/* bootloader */
24+
_stack_start = .;
2025
. = 0x7c00;
26+
_stack_end = .;
27+
2128
.bootloader :
2229
{
2330
/* first stage */
@@ -39,5 +46,6 @@ SECTIONS {
3946
. += 512; /* kernel info block */
4047
_kernel_info_block_end = .;
4148

49+
__bootloader_end = .;
4250
_kernel_start_addr = .;
4351
}

src/context_switch.s

+1-6
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,14 @@
22
.code64
33

44
# Expected arguments:
5-
# - p4 address in `rdi`
5+
# - boot info ptr in `rdi`
66
# - entry point address in `rsi`
77
# - stack pointer in `rdx`
8-
# - boot info ptr in `rcx`
98
context_switch:
10-
# load new P4 table
11-
mov cr3, rdi
129

1310
# load stack pointer
1411
mov rsp, rdx
1512

16-
mov rdi, rcx
17-
1813
# jump to entry point
1914
jmp rsi
2015
context_switch_spin:

src/frame_allocator.rs

+95-62
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use x86_64::PhysAddr;
21
use x86_64::structures::paging::{PAGE_SIZE, PhysFrame};
32
use os_bootinfo::{MemoryMap, MemoryRegion, MemoryRegionType};
43

@@ -7,97 +6,131 @@ pub(crate) struct FrameAllocator<'a> {
76
}
87

98
impl<'a> FrameAllocator<'a> {
10-
pub(crate) fn allocate_frame(&mut self) -> PhysFrame {
9+
pub(crate) fn allocate_frame(&mut self, region_type: MemoryRegionType) -> Option<PhysFrame> {
1110
let page_size = u64::from(PAGE_SIZE);
1211
let mut frame = None;
1312
for region in self.memory_map.iter_mut() {
14-
if region.start_addr < PhysAddr::new(1024 * 1024) {
15-
// don't allocate memory below 1M, since it might be used by bootloader or BIOS
16-
continue;
17-
}
1813
if region.region_type != MemoryRegionType::Usable {
1914
continue;
2015
}
2116
if region.len < page_size {
2217
continue;
2318
}
2419
assert_eq!(0, region.start_addr.as_u64() & 0xfff,
25-
"Region start address must be aligned");
20+
"Region start address is not page aligned: {:?}", region);
2621

2722
frame = Some(PhysFrame::containing_address(region.start_addr));
2823
region.start_addr += page_size;
24+
region.len -= page_size;
2925
break;
3026
}
3127
if let Some(frame) = frame {
32-
self.mark_as_used(frame.start_address(), page_size);
33-
frame
28+
self.add_region(MemoryRegion {
29+
start_addr: frame.start_address(),
30+
len: page_size,
31+
region_type
32+
});
33+
Some(frame)
3434
} else {
35-
panic!("Out of physical memory");
35+
None
3636
}
3737
}
3838

39-
pub(crate) fn mark_as_used(&mut self, addr: PhysAddr, len: u64) {
40-
let mut used_region = Some(MemoryRegion {
41-
start_addr: addr,
42-
len,
43-
region_type: MemoryRegionType::InUse,
44-
});
45-
let mut new_region = None;
39+
pub(crate) fn deallocate_frame(&mut self, frame: PhysFrame) {
40+
let page_size = u64::from(PAGE_SIZE);
41+
self.add_region_overwrite(MemoryRegion {
42+
start_addr: frame.start_address(),
43+
len: page_size,
44+
region_type: MemoryRegionType::Usable,
45+
}, true);
46+
}
4647

47-
// check if it overlaps with another region
48-
for region in self.memory_map.iter_mut() {
49-
let region_start = region.start_addr;
50-
let region_end = region.start_addr + region.len;
51-
let used_start = addr;
52-
let used_end = addr + len;
48+
/// Adds the passed region to the memory map.
49+
///
50+
/// This function automatically adjusts the existing regions so that no overlap occurs.
51+
///
52+
/// Panics if a non-usable region (e.g. a reserved region) overlaps with the passed region.
53+
pub(crate) fn add_region(&mut self, region: MemoryRegion)
54+
{
55+
self.add_region_overwrite(region, false);
56+
}
57+
58+
fn add_region_overwrite(&mut self, region: MemoryRegion, overwrite: bool) {
59+
assert_eq!(0, region.start_addr.as_u64() & 0xfff,
60+
"Region start address is not page aligned: {:?}", region);
5361

54-
if region_start < used_end && region_end > used_start {
55-
// used area overlaps with region
56-
assert!(region.region_type == MemoryRegionType::Usable);
57-
if region_start < used_start && region_end > used_end {
58-
// Case: (R = region, U = used_area)
59-
// ----RRRRRRRRRRR----
60-
// ------UUUU---------
61-
region.len = used_start - region_start;
62-
assert!(new_region.is_none(), "area overlaps with multiple regions");
63-
new_region = Some(MemoryRegion {
64-
start_addr: used_end,
65-
len: region_end - used_end,
66-
region_type: MemoryRegionType::Usable,
62+
let mut region_already_inserted = false;
63+
let mut split_region = None;
64+
65+
for r in self.memory_map.iter_mut() {
66+
// check if region overlaps with another region
67+
if r.start_addr() < region.end_addr() && r.end_addr() > region.start_addr() {
68+
// region overlaps with `r`
69+
match r.region_type {
70+
MemoryRegionType::Usable => {
71+
if region.region_type == MemoryRegionType::Usable {
72+
panic!("region {:?} overlaps with other usable region {:?}", region, r)
73+
}
74+
}
75+
MemoryRegionType::InUse => {},
76+
MemoryRegionType::Bootloader | MemoryRegionType::Kernel
77+
| MemoryRegionType::PageTable if overwrite => {}
78+
_ => {
79+
panic!("can't override region {:?} with {:?}", r, region);
80+
}
81+
}
82+
if r.start_addr() < region.start_addr() && r.end_addr() > region.end_addr() {
83+
// Case: (r = `r`, R = `region`)
84+
// ----rrrrrrrrrrr----
85+
// ------RRRR---------
86+
r.len = region.start_addr() - r.start_addr();
87+
assert!(split_region.is_none(), "area overlaps with multiple regions");
88+
split_region = Some(MemoryRegion {
89+
start_addr: region.end_addr(),
90+
len: r.end_addr() - region.end_addr(),
91+
region_type: r.region_type,
6792
});
68-
} else if used_start <= region_start {
69-
// Case: (R = region, U = used_area)
70-
// ----RRRRRRRRRRR----
71-
// --UUUU-------------
72-
region.start_addr = used_end;
73-
} else if used_end >= used_end {
74-
// Case: (R = region, U = used_area)
75-
// ----RRRRRRRRRRR----
76-
// -------------UUUU--
77-
region.len = used_start - region_start;
93+
} else if region.start_addr() <= r.start_addr() {
94+
// Case: (r = `r`, R = `region`)
95+
// ----rrrrrrrrrrr----
96+
// --RRRR-------------
97+
r.len -= region.end_addr() - r.start_addr();
98+
r.start_addr = region.end_addr();
99+
} else if region.end_addr() >= r.end_addr() {
100+
// Case: (r = `r`, R = `region`)
101+
// ----rrrrrrrrrrr----
102+
// -------------RRRR--
103+
r.len = region.start_addr() - r.start_addr();
104+
} else {
105+
unreachable!("region overlaps in an unexpected way")
78106
}
79107
}
80-
if region.region_type == MemoryRegionType::InUse {
81-
if used_end == region_start {
82-
// merge regions
83-
if let Some(used_region) = used_region.take() {
84-
region.start_addr = used_region.start_addr;
85-
region.len += used_region.len;
86-
}
87-
} else if region_end == used_start {
88-
// merge regions
89-
if let Some(used_region) = used_region.take() {
90-
region.len += used_region.len;
91-
}
108+
// check if region is adjacent to already existing region (only if same type)
109+
if r.region_type == region.region_type {
110+
if region.end_addr() == r.start_addr() {
111+
// Case: (r = `r`, R = `region`)
112+
// ------rrrrrrrrrrr--
113+
// --RRRR-------------
114+
// => merge regions
115+
r.start_addr = region.start_addr();
116+
r.len += region.len;
117+
region_already_inserted = true;
118+
} else if region.start_addr() == r.end_addr() {
119+
// Case: (r = `r`, R = `region`)
120+
// --rrrrrrrrrrr------
121+
// -------------RRRR--
122+
// => merge regions
123+
r.len += region.len;
124+
region_already_inserted = true;
92125
}
93126
}
94127
}
95128

96-
if let Some(new_region) = new_region {
97-
self.memory_map.add_region(new_region);
129+
if let Some(split_region) = split_region {
130+
self.memory_map.add_region(split_region);
98131
}
99-
if let Some(used_region) = used_region {
100-
self.memory_map.add_region(used_region);
132+
if !region_already_inserted {
133+
self.memory_map.add_region(region);
101134
}
102135
}
103136
}

0 commit comments

Comments
 (0)