bbd0bd0ffd
Bootloader hardcoded RedoxFS partition offset at 2 MiB, which fails when efi_partition_size > 1 (redbear-full, redbear-grub use 16 MiB, placing RedoxFS at LBA 34816 = 17 MiB). Added GPT partition table parser that scans for Linux filesystem GUID (0FC63DAF) to find the actual offset. Also removed invalid 'respawn = true' from 31_debug_console.service in redbear-full.toml — init's service format does not support this field. Verified: all three ISOs boot in QEMU UEFI and reach login prompt.
204 lines
7.1 KiB
Diff
204 lines
7.1 KiB
Diff
--- a/src/os/uefi/device.rs 2026-05-04 00:20:20.137148917 +0100
|
|
+++ b/src/os/uefi/device.rs 2026-05-04 00:22:16.976840526 +0100
|
|
@@ -12,6 +12,146 @@
|
|
use uefi_std::{fs::FileSystem, loaded_image::LoadedImage, proto::Protocol};
|
|
|
|
use super::disk::{DiskEfi, DiskOrFileEfi};
|
|
+use redoxfs::Disk;
|
|
+
|
|
+const LINUX_FS_GUID: [u8; 16] = [
|
|
+ 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47,
|
|
+ 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4,
|
|
+];
|
|
+
|
|
+fn gpt_find_redoxfs_offset(disk: &mut DiskEfi) -> u64 {
|
|
+ let block_size = disk.0.Media.BlockSize as u64;
|
|
+ if block_size == 0 {
|
|
+ return 2 * crate::MIBI as u64;
|
|
+ }
|
|
+
|
|
+ let mut header_buf = [0u8; 512];
|
|
+ let lba1_block = block_size / redoxfs::BLOCK_SIZE;
|
|
+ let header_read_len = if 512 <= redoxfs::BLOCK_SIZE as usize {
|
|
+ redoxfs::BLOCK_SIZE as usize
|
|
+ } else {
|
|
+ 512
|
|
+ };
|
|
+ let mut read_buf = vec![0u8; header_read_len];
|
|
+ if unsafe { disk.read_at(lba1_block, &mut read_buf) }.is_err() {
|
|
+ log::warn!("GPT: failed to read LBA 1");
|
|
+ return 2 * crate::MIBI as u64;
|
|
+ }
|
|
+ let copy_len = 512.min(read_buf.len());
|
|
+ header_buf[..copy_len].copy_from_slice(&read_buf[..copy_len]);
|
|
+
|
|
+ if &header_buf[0..8] != b"EFI PART" {
|
|
+ log::warn!("GPT: no valid signature at LBA 1");
|
|
+ return 2 * crate::MIBI as u64;
|
|
+ }
|
|
+
|
|
+ let read_le_u32 = |off: usize| -> u32 {
|
|
+ u32::from_le_bytes(header_buf[off..off + 4].try_into().unwrap_or([0; 4]))
|
|
+ };
|
|
+ let read_le_u64 = |off: usize| -> u64 {
|
|
+ u64::from_le_bytes(header_buf[off..off + 8].try_into().unwrap_or([0; 8]))
|
|
+ };
|
|
+
|
|
+ let _revision = read_le_u32(8);
|
|
+ let _header_size = read_le_u32(12);
|
|
+ let partition_entry_start_lba = read_le_u64(72);
|
|
+ let num_entries = read_le_u32(80);
|
|
+ let entry_size = read_le_u32(84);
|
|
+
|
|
+ if num_entries == 0 || entry_size == 0 || num_entries > 128 {
|
|
+ log::warn!("GPT: invalid entry count {} or size {}", num_entries, entry_size);
|
|
+ return 2 * crate::MIBI as u64;
|
|
+ }
|
|
+
|
|
+ let entries_byte_offset = partition_entry_start_lba * block_size;
|
|
+ let entries_start_block = entries_byte_offset / redoxfs::BLOCK_SIZE;
|
|
+
|
|
+ let total_entries_bytes = num_entries as usize * entry_size as usize;
|
|
+ let read_size = total_entries_bytes.min(4096);
|
|
+ let mut entries_buf = vec![0u8; read_size + redoxfs::BLOCK_SIZE as usize];
|
|
+ let entries_read_blocks = (read_size as u64).div_ceil(redoxfs::BLOCK_SIZE) as usize;
|
|
+ if unsafe { disk.read_at(entries_start_block, &mut entries_buf[..entries_read_blocks * redoxfs::BLOCK_SIZE as usize]) }.is_err() {
|
|
+ log::warn!("GPT: failed to read partition entries");
|
|
+ return 2 * crate::MIBI as u64;
|
|
+ }
|
|
+
|
|
+ let entries_per_chunk = read_size / entry_size as usize;
|
|
+ for i in 0..entries_per_chunk.min(num_entries as usize) {
|
|
+ let off = i * entry_size as usize;
|
|
+ if off + entry_size as usize > entries_buf.len() {
|
|
+ break;
|
|
+ }
|
|
+ let entry = &entries_buf[off..off + entry_size as usize];
|
|
+
|
|
+ let type_guid = &entry[0..16];
|
|
+ if type_guid == [0u8; 16] {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if type_guid == LINUX_FS_GUID {
|
|
+ let first_lba = u64::from_le_bytes(
|
|
+ entry[32..40].try_into().unwrap_or([0; 8]),
|
|
+ );
|
|
+ let offset_bytes = first_lba * block_size;
|
|
+ log::debug!("GPT: found REDOXFS/Linux partition at LBA {} (offset {} bytes)", first_lba, offset_bytes);
|
|
+ return offset_bytes;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ log::warn!("GPT: no Linux filesystem partition found, falling back to 2 MiB");
|
|
+ 2 * crate::MIBI as u64
|
|
+}
|
|
+
|
|
+fn gpt_find_redoxfs_offset_from_slice(data: &[u8]) -> u64 {
|
|
+ if data.len() < 520 {
|
|
+ return 2 * crate::MIBI as u64;
|
|
+ }
|
|
+
|
|
+ let header = &data[512..];
|
|
+ if &header[0..8] != b"EFI PART" {
|
|
+ return 2 * crate::MIBI as u64;
|
|
+ }
|
|
+
|
|
+ let read_le_u32 = |off: usize| -> u32 {
|
|
+ u32::from_le_bytes(header[off..off + 4].try_into().unwrap_or([0; 4]))
|
|
+ };
|
|
+ let read_le_u64 = |off: usize| -> u64 {
|
|
+ u64::from_le_bytes(header[off..off + 8].try_into().unwrap_or([0; 8]))
|
|
+ };
|
|
+
|
|
+ let partition_entry_start_lba = read_le_u64(72);
|
|
+ let num_entries = read_le_u32(80);
|
|
+ let entry_size = read_le_u32(84);
|
|
+
|
|
+ if num_entries == 0 || entry_size == 0 || num_entries > 128 {
|
|
+ return 2 * crate::MIBI as u64;
|
|
+ }
|
|
+
|
|
+ let gpt_lba_size: u64 = 512;
|
|
+ let entries_byte_offset = partition_entry_start_lba * gpt_lba_size;
|
|
+
|
|
+ for i in 0..num_entries as usize {
|
|
+ let off = entries_byte_offset as usize + i * entry_size as usize;
|
|
+ if off + entry_size as usize > data.len() {
|
|
+ break;
|
|
+ }
|
|
+ let entry = &data[off..off + entry_size as usize];
|
|
+
|
|
+ let type_guid = &entry[0..16];
|
|
+ if type_guid == [0u8; 16] {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if type_guid == LINUX_FS_GUID {
|
|
+ let first_lba = u64::from_le_bytes(
|
|
+ entry[32..40].try_into().unwrap_or([0; 8]),
|
|
+ );
|
|
+ return first_lba * gpt_lba_size;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ 2 * crate::MIBI as u64
|
|
+}
|
|
|
|
#[derive(Debug)]
|
|
enum DevicePathRelation {
|
|
@@ -126,17 +266,15 @@
|
|
};
|
|
|
|
if cfg!(feature = "live") {
|
|
- // First try to get a live image from redox-live.iso. This is required to support netbooting.
|
|
if let Some(buffer) = esp_live_image(esp_handle, esp_device_path.0) {
|
|
+ let partition_offset = if buffer.len() > 520 && &buffer[512..520] == b"EFI PART" {
|
|
+ gpt_find_redoxfs_offset_from_slice(&buffer)
|
|
+ } else {
|
|
+ 0
|
|
+ };
|
|
return vec![DiskDevice {
|
|
handle: esp_handle,
|
|
- // Support both a copy of livedisk.iso and a standalone redoxfs partition
|
|
- partition_offset: if &buffer[512..520] == b"EFI PART" {
|
|
- //TODO: get block from partition table
|
|
- 2 * crate::MIBI as u64
|
|
- } else {
|
|
- 0
|
|
- },
|
|
+ partition_offset,
|
|
disk: DiskOrFileEfi::File(buffer),
|
|
device_path: esp_device_path,
|
|
file_path: Some("redox-live.iso"),
|
|
@@ -154,7 +292,7 @@
|
|
};
|
|
let mut devices = Vec::with_capacity(handles.len());
|
|
for handle in handles {
|
|
- let disk = match DiskEfi::handle_protocol(handle) {
|
|
+ let mut disk = match DiskEfi::handle_protocol(handle) {
|
|
Ok(ok) => ok,
|
|
Err(err) => {
|
|
log::warn!(
|
|
@@ -182,14 +320,14 @@
|
|
}
|
|
};
|
|
|
|
+ let partition_offset = if disk.0.Media.LogicalPartition {
|
|
+ 0
|
|
+ } else {
|
|
+ gpt_find_redoxfs_offset(&mut disk)
|
|
+ };
|
|
devices.push(DiskDevice {
|
|
handle,
|
|
- partition_offset: if disk.0.Media.LogicalPartition {
|
|
- 0
|
|
- } else {
|
|
- //TODO: get block from partition table
|
|
- 2 * crate::MIBI as u64
|
|
- },
|
|
+ partition_offset,
|
|
disk: DiskOrFileEfi::Disk(disk),
|
|
device_path,
|
|
file_path: None,
|