diff --git a/config/redbear-full.toml b/config/redbear-full.toml index d000bce7..e3fef1da 100644 --- a/config/redbear-full.toml +++ b/config/redbear-full.toml @@ -411,7 +411,6 @@ requires_weak = [ cmd = "getty" args = ["/scheme/debug/no-preserve", "-J"] type = "oneshot_async" -respawn = true """ [[files]] diff --git a/local/patches/bootloader/P0-gpt-partition-offset.patch b/local/patches/bootloader/P0-gpt-partition-offset.patch new file mode 100644 index 00000000..0abfc486 --- /dev/null +++ b/local/patches/bootloader/P0-gpt-partition-offset.patch @@ -0,0 +1,203 @@ +--- 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, diff --git a/recipes/core/bootloader/recipe.toml b/recipes/core/bootloader/recipe.toml index 6ab1f1ff..32431b01 100644 --- a/recipes/core/bootloader/recipe.toml +++ b/recipes/core/bootloader/recipe.toml @@ -1,6 +1,6 @@ [source] git = "https://gitlab.redox-os.org/redox-os/bootloader.git" -patches = ["redox.patch", "fix-uefi-alloc-panic.patch"] +patches = ["redox.patch", "fix-uefi-alloc-panic.patch", "P0-gpt-partition-offset.patch"] [build] template = "custom"