Compare commits

..

2 Commits

Author SHA1 Message Date
vasilito cfd5d30f74 fix: handle PS/2 mouse RESEND (0xFE) response during init
MouseTx::handle() treated 0xFE (PS/2 RESEND) as an unknown response,
causing mouse init to fail on hardware where the mouse requests a
resend during the reset/command exchange. Now resends the current
command byte when the mouse returns 0xFE, matching the PS/2 protocol.
2026-05-04 00:58:15 +01:00
vasilito bbd0bd0ffd 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.
2026-05-04 00:46:48 +01:00
6 changed files with 219 additions and 2 deletions
-1
View File
@@ -411,7 +411,6 @@ requires_weak = [
cmd = "getty"
args = ["/scheme/debug/no-preserve", "-J"]
type = "oneshot_async"
respawn = true
"""
[[files]]
@@ -0,0 +1,13 @@
--- a/drivers/input/ps2d/src/mouse.rs 2026-05-04 00:50:32.328708003 +0100
+++ b/drivers/input/ps2d/src/mouse.rs 2026-05-04 00:50:46.622536346 +0100
@@ -61,6 +61,10 @@
if data == 0xFA {
self.write_i += 1;
self.try_write(ps2)?;
+ } else if data == 0xFE {
+ // PS/2 RESEND: mouse asks us to resend the current command byte
+ log::debug!("mouse requested resend for byte {:02X}, resending", self.write.get(self.write_i).unwrap_or(&0));
+ self.try_write(ps2)?;
} else {
log::error!("unknown mouse response {:02X}", data);
return Err(());
@@ -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
View File
@@ -0,0 +1 @@
../../../local/patches/base/P3-ps2d-mouse-resend.patch
+1
View File
@@ -25,6 +25,7 @@ patches = [
"P9-fix-so-pecred.patch",
"P3-inputd-keymap-bridge.patch",
"P3-ps2d-led-feedback.patch",
"P3-ps2d-mouse-resend.patch",
"P3-usbhidd-hardening.patch",
"P3-init-colored-output.patch",
"P4-logd-persistent-logging.patch",
+1 -1
View File
@@ -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"