Skip to content

Commit 9a6c884

Browse files
committed
Merge branch 'main' into next
2 parents 076bea9 + 515a7ec commit 9a6c884

File tree

6 files changed

+65
-34
lines changed

6 files changed

+65
-34
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cargo-features = ["profile-rustflags"]
22

33
[package]
44
name = "bootloader"
5-
version = "0.11.0-alpha.0"
5+
version = "0.10.13"
66
authors = ["Philipp Oppermann <dev@phil-opp.com>"]
77
license = "MIT/Apache-2.0"
88
description = "An experimental x86_64 bootloader that works on both BIOS and UEFI systems."
@@ -96,7 +96,7 @@ llvm-tools = "0.1.1"
9696
default-target = "x86_64-unknown-linux-gnu"
9797

9898
[package.metadata.release]
99-
no-dev-version = true
99+
dev-version = false
100100
pre-release-replacements = [
101101
{ file = "Changelog.md", search = "# Unreleased", replace = "# Unreleased\n\n# {{version}} – {{date}}", exactly = 1 },
102102
]

Changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Unreleased
22

3+
# 0.10.13 – 2022-09-25
4+
5+
- Add dynamic range configuration ([#229](https://github.com/rust-osdev/bootloader/pull/229))
6+
- Fix boot for machines that report memory regions at high physical addresses (see [#259](https://github.com/rust-osdev/bootloader/issues/259))
7+
- Limit BIOS bootloader's `max_phys_addr` to 4 GiB ([#260](https://github.com/rust-osdev/bootloader/pull/260))
8+
- fix `get_free_address` for large sizes (0.10) ([#263](https://github.com/rust-osdev/bootloader/pull/263))
9+
- Only perform a single TLB flush after identity mapping ([#265](https://github.com/rust-osdev/bootloader/pull/265))
10+
- Correct typos in `src/binary/level_4_entries.rs` ([#228](https://github.com/rust-osdev/bootloader/pull/228))
11+
312
# 0.10.12 – 2022-02-06
413

514
- Add support for position independent executables ([#206](https://github.com/rust-osdev/bootloader/pull/206))

bios/stage-4/src/main.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ use bootloader_x86_64_common::{
88
legacy_memory_region::LegacyFrameAllocator, load_and_switch_to_kernel, Kernel, PageTables,
99
SystemInfo,
1010
};
11-
use core::slice;
11+
use core::{cmp, slice};
1212
use usize_conversions::usize_from;
1313
use x86_64::structures::paging::{FrameAllocator, OffsetPageTable};
1414
use x86_64::structures::paging::{
1515
Mapper, PageTable, PageTableFlags, PhysFrame, Size2MiB, Size4KiB,
1616
};
1717
use x86_64::{PhysAddr, VirtAddr};
1818

19+
const GIGABYTE: u64 = 4096 * 512 * 512;
20+
1921
mod memory_descriptor;
2022

2123
#[no_mangle]
@@ -34,14 +36,20 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! {
3436

3537
memory_map.sort_unstable_by_key(|e| e.start_addr);
3638

37-
let max_phys_addr = memory_map
38-
.iter()
39-
.map(|r| {
40-
log::info!("start: {:#x}, len: {:#x}", r.start_addr, r.len);
41-
r.start_addr + r.len
42-
})
43-
.max()
44-
.expect("no physical memory regions found");
39+
let max_phys_addr = {
40+
let max = memory_map
41+
.iter()
42+
.map(|r| {
43+
log::info!("start: {:#x}, len: {:#x}", r.start_addr, r.len);
44+
r.start_addr + r.len
45+
})
46+
.max()
47+
.expect("no physical memory regions found");
48+
// Don't consider addresses > 4GiB when determining the maximum physical
49+
// address for the bootloader, as we are in protected mode and cannot
50+
// address more than 4 GiB of memory anyway.
51+
cmp::min(max, 4 * GIGABYTE)
52+
};
4553

4654
let kernel_start = {
4755
assert!(info.kernel.start != 0, "kernel start address must be set");
@@ -68,22 +76,31 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! {
6876
// identity-map remaining physical memory (first 10 gigabytes are already identity-mapped)
6977
{
7078
let start_frame: PhysFrame<Size2MiB> =
71-
PhysFrame::containing_address(PhysAddr::new(4096 * 512 * 512 * 10));
79+
PhysFrame::containing_address(PhysAddr::new(GIGABYTE * 10));
7280
let end_frame = PhysFrame::containing_address(PhysAddr::new(max_phys_addr - 1));
7381
for frame in PhysFrame::range_inclusive(start_frame, end_frame) {
74-
unsafe {
82+
let flusher = unsafe {
7583
bootloader_page_table
7684
.identity_map(
7785
frame,
7886
PageTableFlags::PRESENT | PageTableFlags::WRITABLE,
7987
&mut frame_allocator,
8088
)
8189
.unwrap()
82-
.flush()
8390
};
91+
// skip flushing the entry from the TLB for now, as we will
92+
// flush the entire TLB at the end of the loop.
93+
flusher.ignore();
8494
}
8595
}
8696

97+
// once all the physical memory is mapped, flush the TLB by reloading the
98+
// CR3 register.
99+
//
100+
// we perform a single flush here rather than flushing each individual entry as
101+
// it's mapped using `invlpg`, for efficiency.
102+
x86_64::instructions::tlb::flush_all();
103+
87104
log::info!("BIOS boot");
88105

89106
let page_tables = create_page_tables(&mut frame_allocator);

common/src/level_4_entries.rs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,18 @@ impl UsedLevel4Entries {
134134
}
135135
}
136136

137-
/// Returns an unused level 4 entry and marks it as used. If `CONFIG.aslr` is
138-
/// enabled, this will return a random available entry.
137+
/// Returns the first index of a `num` contiguous unused level 4 entries and marks them as
138+
/// used. If `CONFIG.aslr` is enabled, this will return random contiguous available entries.
139139
///
140140
/// Since this method marks each returned index as used, it can be used multiple times
141141
/// to determine multiple unused virtual memory regions.
142-
pub fn get_free_entry(&mut self) -> PageTableIndex {
143-
// Create an iterator over all available p4 indices.
142+
pub fn get_free_entries(&mut self, num: u64) -> PageTableIndex {
143+
// Create an iterator over all available p4 indices with `num` contiguous free entries.
144144
let mut free_entries = self
145145
.entry_state
146-
.iter()
147-
.copied()
146+
.windows(num.into_usize())
148147
.enumerate()
149-
.filter(|(_, used)| !used)
148+
.filter(|(_, entries)| entries.iter().all(|used| !used))
150149
.map(|(idx, _)| idx);
151150

152151
// Choose the free entry index.
@@ -157,30 +156,36 @@ impl UsedLevel4Entries {
157156
// Choose the first index.
158157
free_entries.next()
159158
};
160-
let idx = idx_opt.expect("no usable level 4 entry found");
159+
let idx = idx_opt.expect("no usable level 4 entries found");
161160

162-
// Mark the entry as used.
163-
self.entry_state[idx] = true;
161+
// Mark the entries as used.
162+
for i in 0..num.into_usize() {
163+
self.entry_state[idx + i] = true;
164+
}
164165

165166
PageTableIndex::new(idx.try_into().unwrap())
166167
}
167168

168-
/// Returns a virtual address in an unused level 4 entry and marks it as used.
169+
/// Returns a virtual address in one or more unused level 4 entries and marks them as used.
169170
///
170-
/// This function calls [`get_free_entry`] internally, so all of its docs applies here
171+
/// This function calls [`get_free_entries`] internally, so all of its docs applies here
171172
/// too.
172173
pub fn get_free_address(&mut self, size: u64, alignment: u64) -> VirtAddr {
173174
assert!(alignment.is_power_of_two());
174175

175-
let base =
176-
Page::from_page_table_indices_1gib(self.get_free_entry(), PageTableIndex::new(0))
177-
.start_address();
176+
const LEVEL_4_SIZE: u64 = 4096 * 512 * 512 * 512;
177+
178+
let level_4_entries = (size + (LEVEL_4_SIZE - 1)) / LEVEL_4_SIZE;
179+
let base = Page::from_page_table_indices_1gib(
180+
self.get_free_entries(level_4_entries),
181+
PageTableIndex::new(0),
182+
)
183+
.start_address();
178184

179185
let offset = if let Some(rng) = self.rng.as_mut() {
180186
// Choose a random offset.
181-
const LEVEL_4_SIZE: u64 = 4096 * 512 * 512 * 512;
182-
let end = LEVEL_4_SIZE - size;
183-
let uniform_range = Uniform::from(0..end / alignment);
187+
let max_offset = LEVEL_4_SIZE - (size % LEVEL_4_SIZE);
188+
let uniform_range = Uniform::from(0..max_offset / alignment);
184189
uniform_range.sample(rng) * alignment
185190
} else {
186191
0

common/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ where
281281
let recursive_index = if let Some(mapping) = config.mappings.page_table_recursive {
282282
log::info!("Map page table recursively");
283283
let index = match mapping {
284-
Mapping::Dynamic => used_entries.get_free_entry(),
284+
Mapping::Dynamic => used_entries.get_free_entries(1),
285285
Mapping::FixedAddress(offset) => {
286286
let offset = VirtAddr::new(offset);
287287
let table_level = PageTableLevel::Four;

0 commit comments

Comments
 (0)