Skip to content

Commit e87f462

Browse files
committed
bzimage: Improve initrd memory allocation
Simplified checks for address/size out of range but also a new check to limit to identity mapped 4GiB region. The potential address is now clamped to the max start address if that is in the range. This fixes the issue with booting with more than 2GiB as the Linux max is just under 2GiB and previously the potential address would be at the top of the 3GiB boundary when running with more than 2GiB. Tested with image boot with initrd with 1GiB and 4GiB RAM. Fixes: #175 Signed-off-by: Rob Bradford <[email protected]>
1 parent fe76bbb commit e87f462

File tree

1 file changed

+31
-11
lines changed

1 file changed

+31
-11
lines changed

src/bzimage.rs

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,30 +82,50 @@ impl Kernel {
8282
0 => 0x37FF_FFFF,
8383
a => a as u64,
8484
};
85+
86+
// Limit to 4GiB identity mapped area
87+
let initrd_addr_max = u64::min(initrd_addr_max, (4 << 30) - 1);
88+
8589
let max_start = (initrd_addr_max + 1) - size;
8690

87-
let mut option_addr = None;
91+
// Align address to 2MiB boundary as we use 2 MiB pages
92+
let max_start = max_start & !((2 << 20) - 1);
93+
94+
let mut current_addr = None;
8895
for i in 0..self.0.num_entries() {
8996
let entry = self.0.entry(i);
9097
if entry.entry_type != E820Entry::RAM_TYPE {
9198
continue;
9299
}
93-
let addr = entry.addr + entry.size - size;
94-
// Align address to 2MiB boundary as we use 2 MiB pages
95-
let addr = addr & !((2 << 20) - 1);
96-
// The ramdisk must fit in the region completely
97-
if addr > max_start || addr < entry.addr {
100+
101+
// Disregard regions beyond the max
102+
if entry.addr > max_start {
98103
continue;
99104
}
100-
// Use the largest address we can find
101-
if let Some(load_addr) = option_addr {
102-
if load_addr >= addr {
105+
106+
// Disregard regions that are too small
107+
if size > entry.size {
108+
continue;
109+
}
110+
111+
// Place at the top of the region
112+
let potential_addr = entry.addr + entry.size - size;
113+
114+
// Align address to 2MiB boundary as we use 2 MiB pages
115+
let potential_addr = potential_addr & !((2 << 20) - 1);
116+
117+
// But clamp to the maximum start
118+
let potential_addr = u64::min(potential_addr, max_start);
119+
120+
// Use the higest address we can find
121+
if let Some(current_addr) = current_addr {
122+
if current_addr >= potential_addr {
103123
continue;
104124
}
105125
}
106-
option_addr = Some(addr)
126+
current_addr = Some(potential_addr)
107127
}
108-
option_addr
128+
current_addr
109129
}
110130

111131
pub fn load_initrd(&mut self, f: &mut dyn Read) -> Result<(), Error> {

0 commit comments

Comments
 (0)