fix: GPT partition offset parsing in bootloader + remove invalid respawn field
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.
This commit is contained in:
@@ -411,7 +411,6 @@ requires_weak = [
|
|||||||
cmd = "getty"
|
cmd = "getty"
|
||||||
args = ["/scheme/debug/no-preserve", "-J"]
|
args = ["/scheme/debug/no-preserve", "-J"]
|
||||||
type = "oneshot_async"
|
type = "oneshot_async"
|
||||||
respawn = true
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[[files]]
|
[[files]]
|
||||||
|
|||||||
@@ -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,
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[source]
|
[source]
|
||||||
git = "https://gitlab.redox-os.org/redox-os/bootloader.git"
|
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]
|
[build]
|
||||||
template = "custom"
|
template = "custom"
|
||||||
|
|||||||
Reference in New Issue
Block a user