Skip to content

Commit 0cc7bf5

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 0cc7bf5

File tree

25 files changed

+520
-190
lines changed

25 files changed

+520
-190
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: 16 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,27 @@ 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+
146+
let buf = concat_115_9(
143147
buf,
144148
match minimum_framebuffer_width {
145149
Option::None => [0; 9],
146150
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
147151
},
148152
);
153+
let buf = concat_124_1(buf, (*log_level as u8).to_le_bytes());
149154

150-
concat_115_1(buf, (*log_level as u8).to_le_bytes())
155+
buf
151156
}
152157

153158
/// Tries to deserialize a config byte array that was created using [`Self::serialize`].
@@ -205,6 +210,7 @@ impl BootloaderConfig {
205210
let (&dynamic_range_start, s) = split_array_ref(s);
206211
let (&dynamic_range_end_some, s) = split_array_ref(s);
207212
let (&dynamic_range_end, s) = split_array_ref(s);
213+
let (&ramdisk_memory, s) = split_array_ref(s);
208214

209215
let mappings = Mappings {
210216
kernel_stack: Mapping::deserialize(&kernel_stack)?,
@@ -235,6 +241,7 @@ impl BootloaderConfig {
235241
[1] => Option::Some(u64::from_le_bytes(dynamic_range_end)),
236242
_ => return Err("invalid dynamic range end value"),
237243
},
244+
ramdisk_memory: Mapping::deserialize(&ramdisk_memory)?,
238245
};
239246
(mappings, s)
240247
};
@@ -398,6 +405,9 @@ pub struct Mappings {
398405
///
399406
/// Defaults to `0xffff_ffff_ffff_f000`.
400407
pub dynamic_range_end: Option<u64>,
408+
/// Virtual address to map ramdisk image, if present on disk
409+
/// Defaults to dynamic
410+
pub ramdisk_memory: Mapping,
401411
}
402412

403413
impl Mappings {
@@ -414,6 +424,7 @@ impl Mappings {
414424
aslr: false,
415425
dynamic_range_start: None,
416426
dynamic_range_end: None,
427+
ramdisk_memory: Mapping::new_default(),
417428
}
418429
}
419430

@@ -446,6 +457,7 @@ impl Mappings {
446457
} else {
447458
Option::None
448459
},
460+
ramdisk_memory: Mapping::random(),
449461
}
450462
}
451463
}

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: 37 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,23 @@ 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(
104+
"ramdisk-x86_64",
105+
RAMDISK_DST,
106+
&mut fs,
107+
&mut disk,
108+
disk_buffer,
109+
) {
110+
Some(s) => s,
111+
None => 0u64,
112+
};
113+
114+
if ramdisk_len == 0 {
115+
writeln!(screen::Writer, "No ramdisk found, skipping.").unwrap();
116+
} else {
117+
writeln!(screen::Writer, "Loaded ramdisk at {RAMDISK_DST:#p}").unwrap();
118+
}
101119

102120
let memory_map = unsafe { memory_map::query_memory_map() }.unwrap();
103121
writeln!(screen::Writer, "{memory_map:x?}").unwrap();
@@ -129,6 +147,10 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! {
129147
start: KERNEL_DST as u64,
130148
len: kernel_len,
131149
},
150+
ramdisk: Region {
151+
start: RAMDISK_DST as u64,
152+
len: ramdisk_len,
153+
},
132154
memory_map_addr: memory_map.as_mut_ptr() as u32,
133155
memory_map_len: memory_map.len().try_into().unwrap(),
134156
framebuffer: BiosFramebufferInfo {
@@ -151,17 +173,16 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! {
151173
}
152174
}
153175

154-
fn load_file(
176+
fn try_load_file(
155177
file_name: &str,
156178
dst: *mut u8,
157179
fs: &mut fat::FileSystem<disk::DiskAccess>,
158180
disk: &mut disk::DiskAccess,
159181
disk_buffer: &mut AlignedArrayBuffer<16384>,
160-
) -> u64 {
182+
) -> Option<u64> {
161183
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");
184+
let file = fs.find_file_in_root_dir(file_name, disk_buffer)?;
185+
165186
let file_size = file.file_size().into();
166187

167188
let mut total_offset = 0;
@@ -195,7 +216,17 @@ fn load_file(
195216
total_offset += usize::try_from(len).unwrap();
196217
}
197218
}
198-
file_size
219+
Some(file_size)
220+
}
221+
222+
fn load_file(
223+
file_name: &str,
224+
dst: *mut u8,
225+
fs: &mut fat::FileSystem<disk::DiskAccess>,
226+
disk: &mut disk::DiskAccess,
227+
disk_buffer: &mut AlignedArrayBuffer<16384>,
228+
) -> u64 {
229+
try_load_file(file_name, dst, fs, disk, disk_buffer).expect("file not found")
199230
}
200231

201232
/// 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: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! {
121121
info: framebuffer_info,
122122
}),
123123
rsdp_addr: detect_rsdp(),
124+
ramdisk_addr: match info.ramdisk.len {
125+
0 => None,
126+
_ => Some(info.ramdisk.start),
127+
},
128+
ramdisk_len: info.ramdisk.len,
124129
};
125130

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

common/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ pub struct SystemInfo {
6060
pub framebuffer: Option<RawFrameBufferInfo>,
6161
/// Address of the _Root System Description Pointer_ structure of the ACPI standard.
6262
pub rsdp_addr: Option<PhysAddr>,
63+
pub ramdisk_addr: Option<u64>,
64+
pub ramdisk_len: u64,
6365
}
6466

6567
/// The physical address of the framebuffer and information about the framebuffer.
@@ -475,6 +477,8 @@ where
475477
info.recursive_index = mappings.recursive_index.map(Into::into).into();
476478
info.rsdp_addr = system_info.rsdp_addr.map(|addr| addr.as_u64()).into();
477479
info.tls_template = mappings.tls_template.into();
480+
info.ramdisk_addr = system_info.ramdisk_addr.into();
481+
info.ramdisk_len = system_info.ramdisk_len;
478482
info
479483
});
480484

src/lib.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,31 @@ mod mbr;
1717
mod pxe;
1818

1919
const KERNEL_FILE_NAME: &str = "kernel-x86_64";
20+
const RAMDISK_FILE_NAME: &str = "ramdisk-x86_64";
2021
const BIOS_STAGE_3: &str = "boot-stage-3";
2122
const BIOS_STAGE_4: &str = "boot-stage-4";
2223

2324
/// Create disk images for booting on legacy BIOS systems.
2425
pub struct BiosBoot {
2526
kernel: PathBuf,
27+
ramdisk: Option<PathBuf>,
2628
}
2729

2830
impl BiosBoot {
2931
/// Start creating a disk image for the given bootloader ELF executable.
3032
pub fn new(kernel_path: &Path) -> Self {
3133
Self {
3234
kernel: kernel_path.to_owned(),
35+
ramdisk: None,
3336
}
3437
}
3538

39+
/// Add a ramdisk file to the image
40+
pub fn set_ramdisk(&mut self, ramdisk_path: &Path) -> &mut Self {
41+
self.ramdisk = Some(ramdisk_path.to_owned());
42+
self
43+
}
44+
3645
/// Create a bootable UEFI disk image at the given path.
3746
pub fn create_disk_image(&self, out_path: &Path) -> anyhow::Result<()> {
3847
let bootsector_path = Path::new(env!("BIOS_BOOT_SECTOR_PATH"));
@@ -61,12 +70,15 @@ impl BiosBoot {
6170
fn create_fat_partition(&self) -> anyhow::Result<NamedTempFile> {
6271
let stage_3_path = Path::new(env!("BIOS_STAGE_3_PATH"));
6372
let stage_4_path = Path::new(env!("BIOS_STAGE_4_PATH"));
73+
let kernel_path = self.kernel.as_path();
6474

6575
let mut files = BTreeMap::new();
66-
files.insert(KERNEL_FILE_NAME, self.kernel.as_path());
76+
files.insert(KERNEL_FILE_NAME, kernel_path);
6777
files.insert(BIOS_STAGE_3, stage_3_path);
6878
files.insert(BIOS_STAGE_4, stage_4_path);
69-
79+
if let Some(ramdisk_path) = &self.ramdisk {
80+
files.insert(RAMDISK_FILE_NAME, ramdisk_path);
81+
}
7082
let out_file = NamedTempFile::new().context("failed to create temp file")?;
7183
fat::create_fat_filesystem(files, out_file.path())
7284
.context("failed to create BIOS FAT filesystem")?;
@@ -78,16 +90,24 @@ impl BiosBoot {
7890
/// Create disk images for booting on UEFI systems.
7991
pub struct UefiBoot {
8092
kernel: PathBuf,
93+
ramdisk: Option<PathBuf>,
8194
}
8295

8396
impl UefiBoot {
8497
/// Start creating a disk image for the given bootloader ELF executable.
8598
pub fn new(kernel_path: &Path) -> Self {
8699
Self {
87100
kernel: kernel_path.to_owned(),
101+
ramdisk: None,
88102
}
89103
}
90104

105+
/// Add a ramdisk file to the disk image
106+
pub fn set_ramdisk(&mut self, ramdisk_path: &Path) -> &mut Self {
107+
self.ramdisk = Some(ramdisk_path.to_owned());
108+
self
109+
}
110+
91111
/// Create a bootable BIOS disk image at the given path.
92112
pub fn create_disk_image(&self, out_path: &Path) -> anyhow::Result<()> {
93113
let fat_partition = self
@@ -121,10 +141,14 @@ impl UefiBoot {
121141
/// Creates an UEFI-bootable FAT partition with the kernel.
122142
fn create_fat_partition(&self) -> anyhow::Result<NamedTempFile> {
123143
let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH"));
124-
144+
let kernel_path = self.kernel.as_path();
125145
let mut files = BTreeMap::new();
126146
files.insert("efi/boot/bootx64.efi", bootloader_path);
127-
files.insert(KERNEL_FILE_NAME, self.kernel.as_path());
147+
files.insert(KERNEL_FILE_NAME, kernel_path);
148+
149+
if let Some(ramdisk_path) = &self.ramdisk {
150+
files.insert(RAMDISK_FILE_NAME, ramdisk_path);
151+
}
128152

129153
let out_file = NamedTempFile::new().context("failed to create temp file")?;
130154
fat::create_fat_filesystem(files, out_file.path())

0 commit comments

Comments
 (0)