Add kwin full source tree, greeter login, zsh, pcid service, and build system improvements

This commit is contained in:
2026-04-26 22:31:07 +01:00
parent d4a6b356eb
commit 70a84cefee
3416 changed files with 1360518 additions and 10522 deletions
@@ -0,0 +1,45 @@
diff --git a/init.initfs.d/40_pcid.service b/init.initfs.d/40_pcid.service
new file mode 100644
--- /dev/null
+++ b/init.initfs.d/40_pcid.service
@@ -0,0 +1,7 @@
+[unit]
+description = "PCI daemon"
+requires_weak = ["41_acpid.service"]
+
+[service]
+cmd = "pcid"
+type = "notify"
diff --git a/init.initfs.d/40_drivers.target b/init.initfs.d/40_drivers.target
--- a/init.initfs.d/40_drivers.target
+++ b/init.initfs.d/40_drivers.target
@@ -3,6 +3,7 @@ description = "Initfs drivers"
requires_weak = [
"10_lived.service",
"20_graphics.target",
+ "40_pcid.service",
"40_ps2d.service",
"40_bcm2835-sdhcid.service",
"40_hwd.service",
diff --git a/init.initfs.d/40_hwd.service b/init.initfs.d/40_hwd.service
--- a/init.initfs.d/40_hwd.service
+++ b/init.initfs.d/40_hwd.service
@@ -1,6 +1,6 @@
[unit]
description = "Hardware manager"
-requires_weak = ["10_inputd.service", "10_lived.service", "20_graphics.target", "41_acpid.service"]
+requires_weak = ["10_inputd.service", "10_lived.service", "20_graphics.target", "40_pcid.service", "41_acpid.service"]
[service]
cmd = "hwd"
diff --git a/init.initfs.d/40_pcid-spawner-initfs.service b/init.initfs.d/40_pcid-spawner-initfs.service
--- a/init.initfs.d/40_pcid-spawner-initfs.service
+++ b/init.initfs.d/40_pcid-spawner-initfs.service
@@ -1,6 +1,6 @@
[unit]
description = "PCI driver spawner"
-requires_weak = ["10_inputd.service", "20_graphics.target", "40_hwd.service"]
+requires_weak = ["10_inputd.service", "20_graphics.target", "40_pcid.service"]
[service]
cmd = "pcid-spawner"
+13 -6
View File
@@ -5,7 +5,6 @@ patches = [
"P2-ac97d-ihdad-main.patch",
"P2-acpi-defer-aml.patch",
"P2-acpi-i2c-resources.patch",
"P2-acpid-core-refactor.patch",
"P2-boot-logging.patch",
"P2-boot-runtime-fixes.patch",
"P2-daemon-hardening.patch",
@@ -14,10 +13,9 @@ patches = [
"P2-ihdad-device-refactor.patch",
"P2-ihdad-hda-stream.patch",
"P2-init-acpid-wiring.patch",
"P2-init-subsystems.patch",
"P2-initfs-pcid-service.patch",
"P2-inputd.patch",
"P2-ixgbed-error-handling.patch",
"P2-logd.patch",
"P2-misc-daemon-fixes.patch",
"P2-network-driver-mains.patch",
"P2-network-error-handling.patch",
@@ -29,6 +27,7 @@ patches = [
"P2-usb-pm-and-drivers.patch",
"P2-virtio-core-vbox.patch",
"P2-xhcid-remaining.patch",
# TODO: P2-acpid-core-refactor.patch needs rebasing against current cumulative state (13/15 hunks fail)
]
[build]
@@ -101,11 +100,19 @@ esac
mkdir -pv "${COOKBOOK_STAGE}/usr/bin" "${COOKBOOK_STAGE}/usr/lib/drivers"
export CARGO_PROFILE_RELEASE_OPT_LEVEL=s
export CARGO_PROFILE_RELEASE_PANIC=abort
# Only build drivers that actually have source Cargo.toml entries
EXISTING_BINS=()
for bin in "${BINS[@]}"
do
if grep -Rqs "^name = \\\"${bin}\\\"$" "${COOKBOOK_SOURCE}"; then
EXISTING_BINS+=("${bin}")
fi
done
"${COOKBOOK_CARGO}" build ${build_flags} \
--manifest-path "${COOKBOOK_SOURCE}/Cargo.toml" \
--target "${TARGET}" \
$(for bin in "${BINS[@]}"; do echo "-p" "${bin}"; done)
for bin in "${BINS[@]}"
$(for bin in "${EXISTING_BINS[@]}"; do echo "-p" "${bin}"; done)
for bin in "${EXISTING_BINS[@]}"
do
if [[ "${bin}" == "gpiod" || "${bin}" == "i2c-gpio-expanderd" || "${bin}" == "intel-gpiod" || "${bin}" == "i2cd" || "${bin}" == "dw-acpi-i2cd" || "${bin}" == "i2c-hidd" || "${bin}" == "inputd" || "${bin}" == "pcid" || "${bin}" == "pcid-spawner" || "${bin}" == "redoxerd" || "${bin}" == "ucsid" ]]; then
cp -v "target/${TARGET}/${build_type}/${bin}" "${COOKBOOK_STAGE}/usr/bin"
@@ -115,7 +122,7 @@ do
done
mkdir -pv "${COOKBOOK_STAGE}/lib/pcid.d"
${FIND} "${COOKBOOK_SOURCE}/drivers" -maxdepth 3 -type f -name 'config.toml' | while read conf
find "${COOKBOOK_SOURCE}/drivers" -maxdepth 3 -type f -name 'config.toml' | while read conf
do
driver="$(basename "$(dirname "$conf")")"
cp -v "$conf" "${COOKBOOK_STAGE}/lib/pcid.d/$driver.toml"
@@ -0,0 +1,392 @@
diff --git a/src/arch/x86/mod.rs b/src/arch/x86/mod.rs
index bda3f5d..55889df 100644
--- a/src/arch/x86/mod.rs
+++ b/src/arch/x86/mod.rs
@@ -3,10 +3,15 @@ use crate::os::Os;
pub(crate) mod x32;
pub(crate) mod x64;
-pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -> Option<usize> {
+pub unsafe fn paging_create(
+ os: &impl Os,
+ kernel_phys: u64,
+ kernel_size: u64,
+ identity_map_end: u64,
+) -> Option<usize> {
unsafe {
if crate::KERNEL_64BIT {
- x64::paging_create(os, kernel_phys, kernel_size)
+ x64::paging_create(os, kernel_phys, kernel_size, identity_map_end)
} else {
x32::paging_create(os, kernel_phys, kernel_size)
}
diff --git a/src/arch/x86/x64.rs b/src/arch/x86/x64.rs
index a0a275a..fcf309d 100644
--- a/src/arch/x86/x64.rs
+++ b/src/arch/x86/x64.rs
@@ -29,7 +29,12 @@ const PRESENT: u64 = 1;
const WRITABLE: u64 = 1 << 1;
const LARGE: u64 = 1 << 7;
-pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -> Option<usize> {
+pub unsafe fn paging_create(
+ os: &impl Os,
+ kernel_phys: u64,
+ kernel_size: u64,
+ identity_map_end: u64,
+) -> Option<usize> {
unsafe {
// Create PML4
let pml4 = paging_allocate(os)?;
@@ -42,8 +47,14 @@ pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -
pml4[0] = pdp.as_ptr() as u64 | WRITABLE | PRESENT;
pml4[256] = pdp.as_ptr() as u64 | WRITABLE | PRESENT;
- // Identity map 8 GiB using 2 MiB pages
- for pdp_i in 0..8 {
+ let mut needed_pdp = identity_map_end.div_ceil(0x4000_0000);
+ if needed_pdp == 0 {
+ needed_pdp = 1;
+ }
+ assert!(needed_pdp <= pdp.len() as u64, "identity map end exceeds paging span");
+
+ // Identity map required physical range using 2 MiB pages
+ for pdp_i in 0..needed_pdp as usize {
let pd = paging_allocate(os)?;
pdp[pdp_i] = pd.as_ptr() as u64 | WRITABLE | PRESENT;
for pd_i in 0..pd.len() {
diff --git a/src/main.rs b/src/main.rs
index 78dabb0..fd8eb81 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -62,6 +62,10 @@ pub static mut KERNEL_64BIT: bool = false;
pub static mut LIVE_OPT: Option<(u64, &'static [u8])> = None;
+fn region_end(base: u64, size: u64) -> u64 {
+ base.saturating_add(size).next_multiple_of(0x1000)
+}
+
struct SliceWriter<'a> {
slice: &'a mut [u8],
i: usize,
@@ -645,9 +649,6 @@ fn main(os: &impl Os) -> (usize, u64, KernelArgs) {
(memory.len() as u64, memory.as_mut_ptr() as u64)
};
- let page_phys = unsafe { paging_create(os, kernel.as_ptr() as u64, kernel.len() as u64) }
- .expect("Failed to set up paging");
-
let max_env_size = 64 * KIBI;
let mut env_size = max_env_size;
let env_base = os.alloc_zeroed_page_aligned(env_size);
@@ -655,6 +656,28 @@ fn main(os: &impl Os) -> (usize, u64, KernelArgs) {
panic!("Failed to allocate memory for stack");
}
+ let mut identity_map_end = region_end(kernel.as_ptr() as u64, kernel.len() as u64)
+ .max(region_end(stack_base as u64, stack_size as u64))
+ .max(region_end(bootstrap_base, bootstrap_size))
+ .max(region_end(env_base as u64, max_env_size as u64));
+
+ if let Some(ref live) = live_opt {
+ identity_map_end = identity_map_end.max(region_end(
+ live.as_ptr() as u64,
+ live.len() as u64,
+ ));
+ }
+
+ let page_phys = unsafe {
+ paging_create(
+ os,
+ kernel.as_ptr() as u64,
+ kernel.len() as u64,
+ identity_map_end,
+ )
+ }
+ .expect("Failed to set up paging");
+
{
let mut w = SliceWriter {
slice: unsafe { slice::from_raw_parts_mut(env_base, max_env_size) },
diff --git a/src/os/uefi/device.rs b/src/os/uefi/device.rs
index 0b7991f..554d88e 100644
--- a/src/os/uefi/device.rs
+++ b/src/os/uefi/device.rs
@@ -13,6 +13,160 @@ use uefi_std::{fs::FileSystem, loaded_image::LoadedImage, proto::Protocol};
use super::disk::{DiskEfi, DiskOrFileEfi};
+#[derive(Clone, Copy)]
+struct GptPartitionInfo {
+ first_lba: u64,
+ last_lba: u64,
+}
+
+fn read_u32_le(bytes: &[u8]) -> Option<u32> {
+ Some(u32::from_le_bytes(bytes.get(..4)?.try_into().ok()?))
+}
+
+fn read_u64_le(bytes: &[u8]) -> Option<u64> {
+ Some(u64::from_le_bytes(bytes.get(..8)?.try_into().ok()?))
+}
+
+fn decode_utf16_name(bytes: &[u8]) -> Option<String> {
+ let mut units = Vec::new();
+ for chunk in bytes.chunks_exact(2) {
+ let unit = u16::from_le_bytes([chunk[0], chunk[1]]);
+ if unit == 0 {
+ break;
+ }
+ units.push(unit);
+ }
+ String::from_utf16(&units).ok()
+}
+
+fn select_partition(best: &mut Option<GptPartitionInfo>, candidate: GptPartitionInfo) {
+ match best {
+ Some(current) if current.last_lba.saturating_sub(current.first_lba) >= candidate.last_lba.saturating_sub(candidate.first_lba) => {}
+ _ => *best = Some(candidate),
+ }
+}
+
+fn parse_gpt_partition_offset_from_bytes(data: &[u8], block_size: usize) -> Option<u64> {
+ let header_offset = block_size;
+ let header = data.get(header_offset..header_offset + 92)?;
+ if header.get(..8)? != b"EFI PART" {
+ return None;
+ }
+
+ let entries_lba = read_u64_le(header.get(72..80)?)?;
+ let entry_count = read_u32_le(header.get(80..84)?)? as usize;
+ let entry_size = read_u32_le(header.get(84..88)?)? as usize;
+ if entry_size < 128 {
+ return None;
+ }
+
+ let entries_offset = entries_lba.checked_mul(block_size as u64)? as usize;
+ let mut redox_partition = None;
+ let mut fallback_partition = None;
+
+ for index in 0..entry_count {
+ let entry_offset = entries_offset.checked_add(index.checked_mul(entry_size)?)?;
+ let entry = data.get(entry_offset..entry_offset + entry_size)?;
+ if entry.get(..16)?.iter().all(|byte| *byte == 0) {
+ continue;
+ }
+
+ let first_lba = read_u64_le(entry.get(32..40)?)?;
+ let last_lba = read_u64_le(entry.get(40..48)?)?;
+ if first_lba == 0 || last_lba < first_lba {
+ continue;
+ }
+
+ let partition = GptPartitionInfo { first_lba, last_lba };
+ let name = decode_utf16_name(entry.get(56..128)?).unwrap_or_default();
+ if name == "REDOX" {
+ redox_partition = Some(partition);
+ break;
+ }
+
+ select_partition(&mut fallback_partition, partition);
+ }
+
+ redox_partition
+ .or(fallback_partition)
+ .map(|partition| partition.first_lba * block_size as u64)
+}
+
+fn parse_gpt_partition_offset_from_parts(
+ entries: &[u8],
+ entry_count: usize,
+ entry_size: usize,
+ block_size: usize,
+) -> Option<u64> {
+ let mut redox_partition = None;
+ let mut fallback_partition = None;
+
+ for index in 0..entry_count {
+ let entry_offset = index.checked_mul(entry_size)?;
+ let entry = entries.get(entry_offset..entry_offset + entry_size)?;
+ if entry.get(..16)?.iter().all(|byte| *byte == 0) {
+ continue;
+ }
+
+ let first_lba = read_u64_le(entry.get(32..40)?)?;
+ let last_lba = read_u64_le(entry.get(40..48)?)?;
+ if first_lba == 0 || last_lba < first_lba {
+ continue;
+ }
+
+ let partition = GptPartitionInfo { first_lba, last_lba };
+ let name = decode_utf16_name(entry.get(56..128)?).unwrap_or_default();
+ if name == "REDOX" {
+ redox_partition = Some(partition);
+ break;
+ }
+
+ select_partition(&mut fallback_partition, partition);
+ }
+ redox_partition
+ .or(fallback_partition)
+ .map(|partition| partition.first_lba * block_size as u64)
+}
+
+fn gpt_partition_offset_from_buffer(data: &[u8]) -> Option<u64> {
+ parse_gpt_partition_offset_from_bytes(data, 512)
+}
+
+fn gpt_partition_offset_from_disk(disk: &mut DiskEfi) -> Option<u64> {
+ const GPT_SECTOR_SIZE: usize = 512;
+
+ if disk.media_block_size() == 0 {
+ return None;
+ }
+
+ let mut boot_region = vec![0_u8; 2048];
+ disk.read_bytes(0, &mut boot_region).ok()?;
+ let header = boot_region.get(GPT_SECTOR_SIZE..GPT_SECTOR_SIZE + 92)?;
+ if header.get(..8)? != b"EFI PART" {
+ return None;
+ }
+
+ let entries_lba = read_u64_le(header.get(72..80)?)?;
+ let entry_count = read_u32_le(header.get(80..84)?)? as usize;
+ let entry_size = read_u32_le(header.get(84..88)?)? as usize;
+ if entry_size < 128 {
+ return None;
+ }
+
+ let entries_bytes = entry_count.checked_mul(entry_size)?;
+ let entries_offset = entries_lba.checked_mul(GPT_SECTOR_SIZE as u64)?;
+ let mut entries = vec![0_u8; entries_bytes];
+ disk.read_bytes(entries_offset, &mut entries).ok()?;
+
+ parse_gpt_partition_offset_from_parts(&entries, entry_count, entry_size, GPT_SECTOR_SIZE)
+}
+
#[derive(Debug)]
enum DevicePathRelation {
This,
@@ -131,12 +285,7 @@ pub fn disk_device_priority() -> Vec<DiskDevice> {
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: gpt_partition_offset_from_buffer(&buffer).unwrap_or(0),
disk: DiskOrFileEfi::File(buffer),
device_path: esp_device_path,
file_path: Some("redox-live.iso"),
@@ -154,7 +303,7 @@ pub fn disk_device_priority() -> Vec<DiskDevice> {
};
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 +331,15 @@ pub fn disk_device_priority() -> Vec<DiskDevice> {
}
};
+ let partition_offset = if disk.0.Media.LogicalPartition {
+ 0
+ } else {
+ gpt_partition_offset_from_disk(&mut disk).unwrap_or(2 * crate::MIBI as u64)
+ };
+
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/src/os/uefi/disk.rs b/src/os/uefi/disk.rs
index 3f920bb..4d109f8 100644
--- a/src/os/uefi/disk.rs
+++ b/src/os/uefi/disk.rs
@@ -117,3 +117,43 @@ impl Disk for DiskEfi {
Err(Error::new(EIO))
}
}
+
+impl DiskEfi {
+ pub fn media_block_size(&self) -> usize {
+ self.0.Media.BlockSize as usize
+ }
+
+ pub fn read_bytes(&mut self, offset: u64, buffer: &mut [u8]) -> Result<()> {
+ let block_size = self.media_block_size();
+ if block_size == 0 || block_size > self.1.len() {
+ return Err(Error::new(EINVAL));
+ }
+
+ let scratch = &mut self.1[..block_size];
+ let mut copied = 0usize;
+
+ while copied < buffer.len() {
+ let absolute = offset as usize + copied;
+ let lba = (absolute / block_size) as u64;
+ let in_block = absolute % block_size;
+
+ match (self.0.ReadBlocks)(
+ self.0,
+ self.0.Media.MediaId,
+ lba,
+ block_size,
+ scratch.as_mut_ptr(),
+ ) {
+ status if status.is_success() => {
+ let chunk_len = core::cmp::min(block_size - in_block, buffer.len() - copied);
+ buffer[copied..copied + chunk_len]
+ .copy_from_slice(&scratch[in_block..in_block + chunk_len]);
+ copied += chunk_len;
+ }
+ _ => return Err(Error::new(EIO)),
+ }
+ }
+
+ Ok(())
+ }
+}
diff --git a/src/os/uefi/mod.rs b/src/os/uefi/mod.rs
index c79266e..86235a4 100644
--- a/src/os/uefi/mod.rs
+++ b/src/os/uefi/mod.rs
@@ -47,17 +47,19 @@ pub(crate) fn alloc_zeroed_page_aligned(size: usize) -> *mut u8 {
let ptr = {
// Max address mapped by src/arch paging code (8 GiB)
let mut ptr = 0x2_0000_0000;
- status_to_result((std::system_table().BootServices.AllocatePages)(
- 1, // AllocateMaxAddress
- MemoryType::EfiRuntimeServicesData, // Keeps this memory out of free space list
+ if status_to_result((std::system_table().BootServices.AllocatePages)(
+ 0, // AllocateAnyPages
+ MemoryType::EfiLoaderData,
pages,
&mut ptr,
))
- .unwrap();
+ .is_err()
+ {
+ return ptr::null_mut();
+ }
ptr as *mut u8
};
- assert!(!ptr.is_null());
unsafe { ptr::write_bytes(ptr, 0, pages * page_size) };
ptr
}
+1 -1
View File
@@ -1,6 +1,6 @@
[source]
git = "https://gitlab.redox-os.org/redox-os/bootloader.git"
patches = ["redox.patch", "P2-live-preload-guard.patch", "P3-uefi-live-image-safe-read.patch"]
patches = ["redox.patch", "P2-live-preload-guard.patch", "P3-uefi-live-image-safe-read.patch", "P4-live-large-iso-boot.patch"]
[build]
template = "custom"
@@ -0,0 +1,17 @@
diff --git a/src/disk/file.rs b/src/disk/file.rs
index 78d51bc..f923d72 100644
--- a/src/disk/file.rs
+++ b/src/disk/file.rs
@@ -43,10 +43,12 @@ impl<T> ResultExt for std::io::Result<T> {
impl DiskFile {
pub fn open(path: impl AsRef<Path>) -> Result<DiskFile> {
+ let path = path.as_ref();
let file = OpenOptions::new()
.read(true)
.write(true)
.open(path)
+ .or_else(|_| OpenOptions::new().read(true).open(path))
.or_eio()?;
Ok(DiskFile { file })
}
+1
View File
@@ -1,5 +1,6 @@
[source]
git = "https://gitlab.redox-os.org/redox-os/redoxfs.git"
patches = ["P2-readonly-live-media-open.patch"]
[build]
template = "custom"
+2 -11
View File
@@ -6,6 +6,7 @@ patches = [
"../../../local/patches/relibc/P3-signalfd.patch",
"../../../local/patches/relibc/P3-signalfd-header.patch",
"../../../local/patches/relibc/P3-timerfd.patch",
"../../../local/patches/relibc/P3-waitid.patch",
"../../../local/patches/relibc/P3-semaphore-fixes.patch",
"../../../local/patches/relibc/P3-socket-cred.patch",
@@ -13,7 +14,7 @@ patches = [
"../../../local/patches/relibc/P3-open-memstream.patch",
"../../../local/patches/relibc/P3-ifaddrs-net_if.patch",
"../../../local/patches/relibc/P3-fd-event-tests.patch",
"../../../local/patches/relibc/P3-eventfd-mod.patch",
"../../../local/patches/relibc/P3-netdb-lookup-retry-fix.patch",
"../../../local/patches/relibc/P3-exec-root-bypass.patch",
"../../../local/patches/relibc/P3-tcp-nodelay.patch",
@@ -25,18 +26,8 @@ patches = [
"../../../local/patches/relibc/P3-dup3.patch",
"../../../local/patches/relibc/P3-vfork.patch",
"../../../local/patches/relibc/P3-clock-nanosleep.patch",
"../../../local/patches/relibc/P3-named-semaphores.patch",
"../../../local/patches/relibc/P3-fcntl-dupfd-cloexec.patch",
"../../../local/patches/relibc/P3-ipc-tests.patch",
"../../../local/patches/relibc/P3-socket-flags.patch",
"../../../local/patches/relibc/P3-syscall-0.7.4-procschemeattrs-ens-to-prio.patch",
"../../../local/patches/relibc/P3-sysv-ipc.patch",
"../../../local/patches/relibc/P3-sysv-sem-impl.patch",
"../../../local/patches/relibc/P3-sysv-shm-impl.patch",
"../../../local/patches/relibc/P3-waitid-header.patch",
"../../../local/patches/relibc/P3-fenv.patch",
"../../../local/patches/relibc/P3-sched.patch",
"../../../local/patches/relibc/P3-aio.patch",
"../../../local/patches/relibc/P3-inet6-pton-ntop.patch",
"../../../local/patches/relibc/P3-tcp-sockopt-forward.patch",
"../../../local/patches/relibc/P3-dns-aaaa-getaddrinfo-ipv6.patch",