Skip to content

Commit 68ce2ee

Browse files
committed
Add ramdisk support
This adds support for loading a ramdisk/initrd, and an API to add one to the boot image.
1 parent fffa7ce commit 68ce2ee

File tree

26 files changed

+584
-194
lines changed

26 files changed

+584
-194
lines changed

Cargo.lock

Lines changed: 14 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ members = [
2323
"tests/test_kernels/higher_half",
2424
"tests/test_kernels/pie",
2525
"tests/test_kernels/lto",
26+
"tests/test_kernels/ramdisk"
2627
]
2728
exclude = ["examples/basic", "examples/test_framework"]
2829

@@ -50,6 +51,7 @@ test_kernel_default_settings = { path = "tests/test_kernels/default_settings", a
5051
test_kernel_higher_half = { path = "tests/test_kernels/higher_half", artifact = "bin", target = "x86_64-unknown-none" }
5152
test_kernel_map_phys_mem = { path = "tests/test_kernels/map_phys_mem", artifact = "bin", target = "x86_64-unknown-none" }
5253
test_kernel_pie = { path = "tests/test_kernels/pie", artifact = "bin", target = "x86_64-unknown-none" }
54+
test_kernel_ramdisk = { path = "tests/test_kernels/ramdisk", artifact = "bin", target = "x86_64-unknown-none" }
5355

5456
[profile.dev]
5557
panic = "abort"

api/build.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ fn main() {
2222
(88, 9),
2323
(97, 9),
2424
(106, 9),
25-
(115, 1),
25+
(115, 9),
26+
(124, 1),
2627
];
2728

2829
let mut code = String::new();

api/src/config.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ impl BootloaderConfig {
3939
0x3D,
4040
];
4141
#[doc(hidden)]
42-
pub const SERIALIZED_LEN: usize = 116;
42+
pub const SERIALIZED_LEN: usize = 125;
4343

4444
/// Creates a new default configuration with the following values:
4545
///
@@ -83,6 +83,7 @@ impl BootloaderConfig {
8383
aslr,
8484
dynamic_range_start,
8585
dynamic_range_end,
86+
ramdisk_memory,
8687
} = mappings;
8788
let FrameBuffer {
8889
minimum_framebuffer_height,
@@ -131,23 +132,26 @@ impl BootloaderConfig {
131132
},
132133
);
133134

134-
let buf = concat_97_9(
135+
let buf = concat_97_9(buf, ramdisk_memory.serialize());
136+
137+
let buf = concat_106_9(
135138
buf,
136139
match minimum_framebuffer_height {
137140
Option::None => [0; 9],
138141
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
139142
},
140143
);
141144

142-
let buf = concat_106_9(
145+
let buf = concat_115_9(
143146
buf,
144147
match minimum_framebuffer_width {
145148
Option::None => [0; 9],
146149
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
147150
},
148151
);
152+
let buf = concat_124_1(buf, (*log_level as u8).to_le_bytes());
149153

150-
concat_115_1(buf, (*log_level as u8).to_le_bytes())
154+
buf
151155
}
152156

153157
/// Tries to deserialize a config byte array that was created using [`Self::serialize`].
@@ -205,6 +209,7 @@ impl BootloaderConfig {
205209
let (&dynamic_range_start, s) = split_array_ref(s);
206210
let (&dynamic_range_end_some, s) = split_array_ref(s);
207211
let (&dynamic_range_end, s) = split_array_ref(s);
212+
let (&ramdisk_memory, s) = split_array_ref(s);
208213

209214
let mappings = Mappings {
210215
kernel_stack: Mapping::deserialize(&kernel_stack)?,
@@ -235,6 +240,7 @@ impl BootloaderConfig {
235240
[1] => Option::Some(u64::from_le_bytes(dynamic_range_end)),
236241
_ => return Err("invalid dynamic range end value"),
237242
},
243+
ramdisk_memory: Mapping::deserialize(&ramdisk_memory)?,
238244
};
239245
(mappings, s)
240246
};
@@ -398,6 +404,9 @@ pub struct Mappings {
398404
///
399405
/// Defaults to `0xffff_ffff_ffff_f000`.
400406
pub dynamic_range_end: Option<u64>,
407+
/// Virtual address to map ramdisk image, if present on disk
408+
/// Defaults to dynamic
409+
pub ramdisk_memory: Mapping,
401410
}
402411

403412
impl Mappings {
@@ -414,6 +423,7 @@ impl Mappings {
414423
aslr: false,
415424
dynamic_range_start: None,
416425
dynamic_range_end: None,
426+
ramdisk_memory: Mapping::new_default(),
417427
}
418428
}
419429

@@ -446,6 +456,7 @@ impl Mappings {
446456
} else {
447457
Option::None
448458
},
459+
ramdisk_memory: Mapping::random(),
449460
}
450461
}
451462
}

api/src/info.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ pub struct BootInfo {
5252
pub rsdp_addr: Optional<u64>,
5353
/// The thread local storage (TLS) template of the kernel executable, if present.
5454
pub tls_template: Optional<TlsTemplate>,
55+
/// Ramdisk address, if loaded
56+
pub ramdisk_addr: Optional<u64>,
57+
/// Ramdisk image size, set to 0 if addr is None
58+
pub ramdisk_len: u64,
5559
}
5660

5761
impl BootInfo {
@@ -67,6 +71,8 @@ impl BootInfo {
6771
recursive_index: Optional::None,
6872
rsdp_addr: Optional::None,
6973
tls_template: Optional::None,
74+
ramdisk_addr: Optional::None,
75+
ramdisk_len: 0,
7076
}
7177
}
7278
}

bios/common/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod racy_cell;
77
pub struct BiosInfo {
88
pub stage_4: Region,
99
pub kernel: Region,
10+
pub ramdisk: Region,
1011
pub framebuffer: BiosFramebufferInfo,
1112
pub memory_map_addr: u32,
1213
pub memory_map_len: u16,

bios/stage-2/src/main.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const BOOTLOADER_SECOND_STAGE_PARTITION_TYPE: u8 = 0x20;
2727
const STAGE_3_DST: *mut u8 = 0x0010_0000 as *mut u8; // 1MiB (typically 14MiB accessible here)
2828
const STAGE_4_DST: *mut u8 = 0x0020_0000 as *mut u8; // 2MiB (typically still 13MiB accessible here)
2929
const KERNEL_DST: *mut u8 = 0x0100_0000 as *mut u8; // 16MiB
30+
const RAMDISK_DST: *mut u8 = 0x0400_0000 as *mut u8; // 64MiB
3031

3132
static mut DISK_BUFFER: AlignedArrayBuffer<0x4000> = AlignedArrayBuffer {
3233
buffer: [0; 0x4000],
@@ -98,6 +99,17 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! {
9899
writeln!(screen::Writer, "loading kernel...").unwrap();
99100
let kernel_len = load_file("kernel-x86_64", KERNEL_DST, &mut fs, &mut disk, disk_buffer);
100101
writeln!(screen::Writer, "kernel loaded at {KERNEL_DST:#p}").unwrap();
102+
writeln!(screen::Writer, "Loading ramdisk...").unwrap();
103+
let ramdisk_len = match try_load_file("ramdisk", RAMDISK_DST, &mut fs, &mut disk, disk_buffer) {
104+
Some(s) => s,
105+
None => 0u64,
106+
};
107+
108+
if ramdisk_len == 0 {
109+
writeln!(screen::Writer, "No ramdisk found, skipping.").unwrap();
110+
} else {
111+
writeln!(screen::Writer, "Loaded ramdisk at {RAMDISK_DST:#p}").unwrap();
112+
}
101113

102114
let memory_map = unsafe { memory_map::query_memory_map() }.unwrap();
103115
writeln!(screen::Writer, "{memory_map:x?}").unwrap();
@@ -129,6 +141,10 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! {
129141
start: KERNEL_DST as u64,
130142
len: kernel_len,
131143
},
144+
ramdisk: Region {
145+
start: RAMDISK_DST as u64,
146+
len: ramdisk_len,
147+
},
132148
memory_map_addr: memory_map.as_mut_ptr() as u32,
133149
memory_map_len: memory_map.len().try_into().unwrap(),
134150
framebuffer: BiosFramebufferInfo {
@@ -151,17 +167,16 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! {
151167
}
152168
}
153169

154-
fn load_file(
170+
fn try_load_file(
155171
file_name: &str,
156172
dst: *mut u8,
157173
fs: &mut fat::FileSystem<disk::DiskAccess>,
158174
disk: &mut disk::DiskAccess,
159175
disk_buffer: &mut AlignedArrayBuffer<16384>,
160-
) -> u64 {
176+
) -> Option<u64> {
161177
let disk_buffer_size = disk_buffer.buffer.len();
162-
let file = fs
163-
.find_file_in_root_dir(file_name, disk_buffer)
164-
.expect("file not found");
178+
let file = fs.find_file_in_root_dir(file_name, disk_buffer)?;
179+
165180
let file_size = file.file_size().into();
166181

167182
let mut total_offset = 0;
@@ -195,7 +210,17 @@ fn load_file(
195210
total_offset += usize::try_from(len).unwrap();
196211
}
197212
}
198-
file_size
213+
Some(file_size)
214+
}
215+
216+
fn load_file(
217+
file_name: &str,
218+
dst: *mut u8,
219+
fs: &mut fat::FileSystem<disk::DiskAccess>,
220+
disk: &mut disk::DiskAccess,
221+
disk_buffer: &mut AlignedArrayBuffer<16384>,
222+
) -> u64 {
223+
try_load_file(file_name, dst, fs, disk, disk_buffer).expect("file not found")
199224
}
200225

201226
/// Taken from https://github.com/rust-lang/rust/blob/e100ec5bc7cd768ec17d75448b29c9ab4a39272b/library/core/src/slice/mod.rs#L1673-L1677

bios/stage-4/src/main.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,21 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! {
5656
PhysAddr::new(info.kernel.start)
5757
};
5858
let kernel_size = info.kernel.len;
59-
let mut frame_allocator = {
59+
let mut frame_allocator = if info.ramdisk.start == 0 {
6060
let kernel_end = PhysFrame::containing_address(kernel_start + kernel_size - 1u64);
6161
let next_free = kernel_end + 1;
6262
LegacyFrameAllocator::new_starting_at(
6363
next_free,
6464
memory_map.iter().copied().map(MemoryRegion),
6565
)
66+
} else {
67+
let ramdisk_end =
68+
PhysFrame::containing_address(PhysAddr::new(info.ramdisk.start + info.ramdisk.len));
69+
let next_free = ramdisk_end + 1;
70+
LegacyFrameAllocator::new_starting_at(
71+
next_free,
72+
memory_map.iter().copied().map(MemoryRegion),
73+
)
6674
};
6775

6876
// We identity-mapped all memory, so the offset between physical and virtual addresses is 0
@@ -121,6 +129,11 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! {
121129
info: framebuffer_info,
122130
}),
123131
rsdp_addr: detect_rsdp(),
132+
ramdisk_addr: match info.ramdisk.len {
133+
0 => None,
134+
_ => Some(info.ramdisk.start),
135+
},
136+
ramdisk_len: info.ramdisk.len,
124137
};
125138

126139
load_and_switch_to_kernel(kernel, frame_allocator, page_tables, system_info);

0 commit comments

Comments
 (0)