fix: rebase base patches, commit recipe drift, add relibc rlimit/sysconf

Base: fix P6-driver-new-modules.patch (ed format -> unified diff) for new
driver modules (ncq, itr, phy). P6-driver-main-fixes.patch now applies with
offset on current upstream source.

Relibc: remove stale P5-named-semaphores (upstream has stubs), add
P10-stack-size-8mb and P11-getrlimit-getrusage (per-process rlimit table,
sysconf integration, getdtablesize fix, null-pointer safety).

Kernel: consolidate 29 individual patches into single redbear-consolidated.patch.

Userutils: P5-redbear-branding replaces P4-login-rate-limit.

Recipe.toml changes now committed so they survive source resets.
This commit is contained in:
2026-05-04 11:49:15 +01:00
parent 39b6aa7c54
commit 11993af01f
18 changed files with 3473 additions and 3 deletions
@@ -0,0 +1,21 @@
diff --git a/drivers/audio/ihdad/src/main.rs b/drivers/audio/ihdad/src/main.rs
index 31a2add7..a75a0a35 100755
--- a/drivers/audio/ihdad/src/main.rs
+++ b/drivers/audio/ihdad/src/main.rs
@@ -57,7 +57,15 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
EventQueue::<Source>::new().expect("ihdad: Could not create event queue.");
let socket = Socket::nonblock().expect("ihdad: failed to create socket");
let mut device = unsafe {
- hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device")
+ match hda::IntelHDA::new(address, vend_prod) {
+ Ok(dev) => dev,
+ Err(e) => {
+ log::error!("ihdad: failed to initialize HDA device (err {}), exiting gracefully", e);
+ log::info!("ihdad: this is expected in virtual environments without functional HDA hardware");
+ daemon.ready();
+ return loop {};
+ }
+ }
};
let mut readiness_based = ReadinessBased::new(&socket, 16);
@@ -0,0 +1,178 @@
diff --git a/drivers/audio/ac97d/src/main.rs b/drivers/audio/ac97d/src/main.rs
index ffa8a94b..29e189be 100644
--- a/drivers/audio/ac97d/src/main.rs
+++ b/drivers/audio/ac97d/src/main.rs
@@ -63,14 +63,14 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
Source::Irq,
event::EventFlags::READ,
)
- .unwrap();
+ .expect("ac97d: subscribe IRQ failed");
event_queue
.subscribe(
socket.inner().raw(),
Source::Scheme,
event::EventFlags::READ,
)
- .unwrap();
+ .expect("ac97d: subscribe scheme failed");
register_sync_scheme(&socket, "audiohw", &mut device)
.expect("ac97d: failed to register audiohw scheme to namespace");
@@ -86,12 +86,12 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
match event {
Source::Irq => {
let mut irq = [0; 8];
- irq_file.read(&mut irq).unwrap();
+ irq_file.read(&mut irq).expect("ac97d: IRQ read failed");
if !device.irq() {
continue;
}
- irq_file.write(&mut irq).unwrap();
+ irq_file.write(&mut irq).expect("ac97d: IRQ ack failed");
readiness_based
.poll_all_requests(&mut device)
diff --git a/drivers/audio/ihdad/src/main.rs b/drivers/audio/ihdad/src/main.rs
index 31a2add7..8291a550 100755
--- a/drivers/audio/ihdad/src/main.rs
+++ b/drivers/audio/ihdad/src/main.rs
@@ -71,14 +71,14 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
Source::Scheme,
event::EventFlags::READ,
)
- .unwrap();
+ .expect("ihdad: subscribe scheme failed");
event_queue
.subscribe(
irq_file.irq_handle().as_raw_fd() as usize,
Source::Irq,
event::EventFlags::READ,
)
- .unwrap();
+ .expect("ihdad: subscribe IRQ failed");
libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace");
@@ -91,12 +91,12 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
match event {
Source::Irq => {
let mut irq = [0; 8];
- irq_file.irq_handle().read(&mut irq).unwrap();
+ irq_file.irq_handle().read(&mut irq).expect("ihdad: IRQ read failed");
if !device.irq() {
continue;
}
- irq_file.irq_handle().write(&mut irq).unwrap();
+ irq_file.irq_handle().write(&mut irq).expect("ihdad: IRQ ack failed");
readiness_based
.poll_all_requests(&mut device)
diff --git a/drivers/net/e1000d/src/main.rs b/drivers/net/e1000d/src/main.rs
index 373ea9b3..c66cccd1 100644
--- a/drivers/net/e1000d/src/main.rs
+++ b/drivers/net/e1000d/src/main.rs
@@ -70,15 +70,15 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
libredox::call::setrens(0, 0).expect("e1000d: failed to enter null namespace");
- scheme.tick().unwrap();
+ scheme.tick().expect("e1000d: tick failed");
for event in event_queue.map(|e| e.expect("e1000d: failed to get event")) {
match event.user_data {
Source::Irq => {
let mut irq = [0; 8];
- irq_file.read(&mut irq).unwrap();
+ irq_file.read(&mut irq).expect("e1000d: IRQ read failed");
if unsafe { scheme.adapter().irq() } {
- irq_file.write(&mut irq).unwrap();
+ irq_file.write(&mut irq).expect("e1000d: IRQ ack failed");
scheme.tick().expect("e1000d: failed to handle IRQ")
}
diff --git a/drivers/net/rtl8168d/src/main.rs b/drivers/net/rtl8168d/src/main.rs
index 1d9963a3..5dc244af 100644
--- a/drivers/net/rtl8168d/src/main.rs
+++ b/drivers/net/rtl8168d/src/main.rs
@@ -81,33 +81,33 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
Source::Irq,
event::EventFlags::READ,
)
- .unwrap();
+ .expect("rtl8168d: subscribe IRQ failed");
event_queue
.subscribe(
scheme.event_handle().raw(),
Source::Scheme,
event::EventFlags::READ,
)
- .unwrap();
+ .expect("rtl8168d: subscribe scheme failed");
libredox::call::setrens(0, 0).expect("rtl8168d: failed to enter null namespace");
- scheme.tick().unwrap();
+ scheme.tick().expect("rtl8168d: tick failed");
for event in event_queue.map(|e| e.expect("rtl8168d: failed to get next event")) {
match event.user_data {
Source::Irq => {
let mut irq = [0; 8];
- irq_file.irq_handle().read(&mut irq).unwrap();
+ irq_file.irq_handle().read(&mut irq).expect("rtl8168d: IRQ read failed");
//TODO: This may be causing spurious interrupts
if unsafe { scheme.adapter_mut().irq() } {
- irq_file.irq_handle().write(&mut irq).unwrap();
+ irq_file.irq_handle().write(&mut irq).expect("rtl8168d: IRQ ack failed");
- scheme.tick().unwrap();
+ scheme.tick().expect("rtl8168d: tick failed");
}
}
Source::Scheme => {
- scheme.tick().unwrap();
+ scheme.tick().expect("rtl8168d: tick failed");
}
}
}
diff --git a/drivers/storage/ahcid/src/main.rs b/drivers/storage/ahcid/src/main.rs
index 1f130a29..9a0e3e0d 100644
--- a/drivers/storage/ahcid/src/main.rs
+++ b/drivers/storage/ahcid/src/main.rs
@@ -66,17 +66,17 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
.expect("ahcid: failed to event scheme socket");
event_queue
.subscribe(irq_fd, 1, EventFlags::READ)
- .expect("ahcid: failed to event irq scheme");
+ .expect("ahcid: IRQ failed");
for event in event_queue {
- let event = event.unwrap();
+ let event = event.expect("ahcid: event failed");
if event.fd == scheme.event_handle().raw() {
- FuturesExecutor.block_on(scheme.tick()).unwrap();
+ FuturesExecutor.block_on(scheme.tick()).expect("ahcid: tick failed");
} else if event.fd == irq_fd {
let mut irq = [0; 8];
if irq_file
.read(&mut irq)
- .expect("ahcid: failed to read irq file")
+ .expect("ahcid: IRQ failed")
>= irq.len()
{
let is = hba_mem.is.read();
@@ -94,9 +94,9 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
irq_file
.write(&irq)
- .expect("ahcid: failed to write irq file");
+ .expect("ahcid: IRQ failed");
- FuturesExecutor.block_on(scheme.tick()).unwrap();
+ FuturesExecutor.block_on(scheme.tick()).expect("ahcid: tick failed");
}
}
} else {
@@ -0,0 +1,193 @@
diff --git a/drivers/net/e1000d/src/itr.rs b/drivers/net/e1000d/src/itr.rs
new file mode 100644
index 00000000..a0d79a5f
--- /dev/null
+++ b/drivers/net/e1000d/src/itr.rs
@@ -0,0 +1,61 @@
+use crate::device::Intel8254x;
+
+pub const ITR_IMMEDIATE: u32 = 0;
+pub const ITR_LOW_LATENCY: u32 = 64;
+pub const ITR_BULK: u32 = 256;
+pub const ITR_DEFAULT: u32 = 800;
+
+#[derive(Clone, Copy, PartialEq)]
+pub enum ItrState { LowLatency, Moderate, Bulk }
+
+pub struct ItrTracker {
+ state: ItrState,
+ current_itr: u32,
+ packets_since_update: u32,
+}
+
+impl ItrTracker {
+ pub const fn new() -> Self {
+ Self { state: ItrState::LowLatency, current_itr: ITR_LOW_LATENCY, packets_since_update: 0 }
+ }
+ pub fn record_packet(&mut self, bytes: usize) {
+ self.packets_since_update += 1;
+ let _ = bytes;
+ }
+ pub fn update(&mut self) -> u32 {
+ let new_state = if self.packets_since_update < 8 { ItrState::LowLatency }
+ else if self.packets_since_update < 64 { ItrState::Moderate }
+ else { ItrState::Bulk };
+ if new_state != self.state {
+ self.state = new_state;
+ self.current_itr = match self.state {
+ ItrState::LowLatency => ITR_LOW_LATENCY,
+ ItrState::Moderate => ITR_DEFAULT,
+ ItrState::Bulk => ITR_BULK,
+ };
+ }
+ self.packets_since_update = 0;
+ self.current_itr
+ }
+ pub fn current_itr(&self) -> u32 { self.current_itr }
+}
+
+const E1000_ITR: u32 = 0x00C4;
+
+pub fn set_itr(device: &Intel8254x, itr_value: u32) {
+ unsafe { device.write_reg(E1000_ITR, itr_value); }
+}
+
+pub fn configure_default_itr(device: &Intel8254x) {
+ set_itr(device, ITR_DEFAULT);
+}
+
+pub fn configure_checksum_offload(device: &Intel8254x) {
+ let rctl = unsafe { device.read_reg(0x0100) };
+ unsafe { device.write_reg(0x0100, rctl | (1 << 4)) };
+}
+
+pub fn enable_tso(device: &Intel8254x) {
+ let tctl = unsafe { device.read_reg(0x0400) };
+ unsafe { device.write_reg(0x0400, tctl | (1 << 11)) };
+}
diff --git a/drivers/net/rtl8168d/src/phy.rs b/drivers/net/rtl8168d/src/phy.rs
new file mode 100644
index 00000000..4f9def80
--- /dev/null
+++ b/drivers/net/rtl8168d/src/phy.rs
@@ -0,0 +1,42 @@
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum ChipVersion { Rtl8168b, Rtl8168c, Rtl8168cp, Rtl8168d, Rtl8168dp, Rtl8168e, Rtl8168evl, Rtl8168f, Rtl8168g, Rtl8168h, Rtl8168ep, Unknown }
+
+pub fn identify_chip(rev: u8, mac0: u32, _m1: u32, _m2: u32, _m3: u32, _m4: u32) -> ChipVersion {
+ match ((mac0 >> 20) & 0x7, rev) {
+ (0, _) => ChipVersion::Rtl8168b, (1, 0x00..=0x01) => ChipVersion::Rtl8168c, (1, 0x02) => ChipVersion::Rtl8168cp,
+ (2, _) => ChipVersion::Rtl8168d, (3, r) if r <= 0x02 => ChipVersion::Rtl8168e, (3, _) => ChipVersion::Rtl8168evl,
+ (4, _) => ChipVersion::Rtl8168f, (5, _) => ChipVersion::Rtl8168g, (6, _) => ChipVersion::Rtl8168h,
+ (7, _) => ChipVersion::Rtl8168ep, _ => ChipVersion::Unknown,
+ }
+}
+
+pub mod phy_regs {
+ pub const BMCR: u32 = 0x00; pub const BMSR: u32 = 0x01; pub const PHYID1: u32 = 0x02; pub const PHYID2: u32 = 0x03;
+ pub const ANAR: u32 = 0x04; pub const ANLPAR: u32 = 0x05;
+ pub const BMCR_RESET: u16 = 1 << 15; pub const BMCR_LOOPBACK: u16 = 1 << 14;
+ pub const BMCR_SPEED_1000: u16 = 1 << 6; pub const BMCR_AUTONEG_ENABLE: u16 = 1 << 12;
+ pub const BMCR_AUTONEG_RESTART: u16 = 1 << 9; pub const BMCR_DUPLEX: u16 = 1 << 8;
+ pub const BMSR_AUTONEG_COMPLETE: u16 = 1 << 5; pub const BMSR_LINK_STATUS: u16 = 1 << 2;
+}
+
+pub fn phy_link_up(read: &dyn Fn(u32) -> u16) -> bool { read(phy_regs::BMSR) & phy_regs::BMSR_LINK_STATUS != 0 }
+
+pub fn phy_reset(write: &dyn Fn(u32, u16), read: &dyn Fn(u32) -> u16) -> bool {
+ write(phy_regs::BMCR, phy_regs::BMCR_RESET);
+ for _ in 0..500 { if read(phy_regs::BMCR) & phy_regs::BMCR_RESET == 0 { return true; } }
+ false
+}
+
+pub fn phy_init_for_chip(chip: ChipVersion, write: &dyn Fn(u32, u16), _read: &dyn Fn(u32) -> u16) {
+ match chip {
+ ChipVersion::Rtl8168g | ChipVersion::Rtl8168h | ChipVersion::Rtl8168ep => {
+ write(phy_regs::BMCR, phy_regs::BMCR_AUTONEG_ENABLE | phy_regs::BMCR_AUTONEG_RESTART | phy_regs::BMCR_SPEED_1000 | phy_regs::BMCR_DUPLEX);
+ }
+ _ => {
+ write(phy_regs::BMCR, phy_regs::BMCR_AUTONEG_ENABLE | phy_regs::BMCR_AUTONEG_RESTART);
+ }
+ }
+}
+
+pub fn set_jumbo_mtu(_write_phy: &dyn Fn(u32, u16), _mtu: u16) {
+}
diff --git a/drivers/storage/ahcid/src/ahci/ncq.rs b/drivers/storage/ahcid/src/ahci/ncq.rs
new file mode 100644
index 00000000..e08818f0
--- /dev/null
+++ b/drivers/storage/ahcid/src/ahci/ncq.rs
@@ -0,0 +1,72 @@
+use core::sync::atomic::{AtomicU32, Ordering};
+
+pub const NCQ_MAX_DEPTH: usize = 32;
+
+pub struct NcqState {
+ pub sactive: AtomicU32,
+ pub pending: AtomicU32,
+}
+
+impl NcqState {
+ pub const fn new() -> Self {
+ Self { sactive: AtomicU32::new(0), pending: AtomicU32::new(0) }
+ }
+ pub fn allocate_tag(&self) -> Option<u32> {
+ let active = self.pending.load(Ordering::Acquire);
+ let free = !active;
+ if free == 0 { return None; }
+ let tag = free.trailing_zeros();
+ let mask = 1u32 << tag;
+ self.pending.fetch_or(mask, Ordering::AcqRel);
+ self.sactive.fetch_or(mask, Ordering::AcqRel);
+ Some(tag)
+ }
+ pub fn complete_tag(&self, tag: u32) {
+ let mask = 1u32 << tag;
+ self.sactive.fetch_and(!mask, Ordering::AcqRel);
+ self.pending.fetch_and(!mask, Ordering::AcqRel);
+ }
+ pub fn has_pending(&self) -> bool { self.pending.load(Ordering::Acquire) != 0 }
+}
+
+pub fn build_ncq_read_fis(tag: u32, lba: u64, count: u16) -> [u32; 5] {
+ let mut f = [0u32; 5];
+ f[0] = 0x0000_8027;
+ f[1] = 0x0060 | ((count as u32 & 0xFF) << 24);
+ f[2] = (lba as u32 & 0xFF) | (((lba >> 8) as u32 & 0xFF) << 8);
+ let mid = ((lba >> 16) as u32 & 0xFF) | ((tag & 0x1F) << 3);
+ f[3] = mid | (((lba >> 24) as u32 & 0xFF) << 8) | (((lba >> 32) as u32 & 0xFF) << 16) | (((lba >> 40) as u32 & 0xFF) << 24);
+ f[4] = (((count >> 8) as u32 & 0xFF) << 16) | (((count >> 8) as u32 & 0xFF) << 24);
+ f
+}
+
+pub fn build_ncq_write_fis(tag: u32, lba: u64, count: u16) -> [u32; 5] {
+ let mut f = build_ncq_read_fis(tag, lba, count);
+ f[1] = (f[1] & !0xFF00) | 0x6100;
+ f
+}
+
+pub fn process_ncq_completions(old_sa: u32, new_sa: u32, ncq: &NcqState, completed: &mut [u32; NCQ_MAX_DEPTH]) -> usize {
+ let mask = old_sa & !new_sa;
+ if mask == 0 { return 0; }
+ let mut count = 0;
+ let mut m = mask;
+ while m != 0 { let t = m.trailing_zeros(); ncq.complete_tag(t); completed[count] = t; count += 1; m &= m - 1; }
+ count
+}
+
+pub fn drive_supports_ncq(id: &[u16; 256]) -> bool { id.get(76).map_or(false, |w| w & (1 << 8) != 0) }
+pub fn ncq_queue_depth(id: &[u16; 256]) -> u32 {
+ id.get(75).map_or(1, |w| { let d = (w & 0x1F) as u32; if d > 0 { (d + 1).min(NCQ_MAX_DEPTH as u32) } else { 1 } })
+}
+
+pub fn enable_ncq(hba_mem: &crate::ahci::hba::HbaMem, port_idx: usize) {
+ let port = &hba_mem.ports[port_idx];
+ let cmd = port.cmd.read();
+ port.cmd.write(cmd | 1 << 1);
+}
+
+pub fn issue_ncq_command(port: &crate::ahci::hba::HbaPort, tag: u32) {
+ let ci = port.ci.read();
+ port.ci.write(ci | (1u32 << tag));
+}
@@ -0,0 +1,34 @@
--- a/src/scheme/debug.rs 2026-04-28 07:21:41.000000000 +0100
+++ b/src/scheme/debug.rs 2026-05-04 08:10:23.688174541 +0100
@@ -22,9 +22,10 @@
static HANDLES: RwLock<L1, HandleMap<Handle>> = RwLock::new(HandleMap::new());
-/// Add to the input queue
+/// Add to the input queue, translating CR to NL (ICRNL) for serial console compatibility.
pub fn debug_input(data: u8, token: &mut CleanLockToken) {
- INPUT.send(data, token);
+ let translated = if data == b'\r' { b'\n' } else { data };
+ INPUT.send(translated, token);
}
// Notify readers of input updates
@@ -106,12 +107,16 @@
fn fevent(
&self,
id: usize,
- _flags: EventFlags,
+ flags: EventFlags,
token: &mut CleanLockToken,
) -> Result<EventFlags> {
let _handle = *HANDLES.read(token.token()).get(id)?;
- Ok(EventFlags::empty())
+ let mut ready = EventFlags::empty();
+ if flags.contains(EventFlags::EVENT_READ) {
+ ready |= EventFlags::EVENT_READ;
+ }
+ Ok(ready)
}
fn fsync(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
--- a/redox-rt/src/arch/x86_64.rs 2026-04-28 07:19:14.000000000 +0100
+++ b/redox-rt/src/arch/x86_64.rs 2026-05-04 08:13:45.179788927 +0100
@@ -21,7 +21,7 @@
// Setup a stack starting from the very end of the address space, and then growing downwards.
pub const STACK_TOP: usize = 1 << 47;
-pub const STACK_SIZE: usize = 1024 * 1024;
+pub const STACK_SIZE: usize = 8 * 1024 * 1024;
#[derive(Debug, Default)]
#[repr(C)]
@@ -0,0 +1,349 @@
diff --git a/src/header/sys_resource/mod.rs b/src/header/sys_resource/mod.rs
index 9166007a..c645e8eb 100644
--- a/src/header/sys_resource/mod.rs
+++ b/src/header/sys_resource/mod.rs
@@ -92,7 +92,10 @@ pub unsafe extern "C" fn setpriority(which: c_int, who: id_t, nice: c_int) -> c_
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getrlimit.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn getrlimit(resource: c_int, rlp: *mut rlimit) -> c_int {
- let rlp = unsafe { Out::nonnull(rlp) };
+ let Some(rlp) = (unsafe { Out::nullable(rlp) }) else {
+ crate::platform::ERRNO.set(crate::header::errno::EFAULT);
+ return -1;
+ };
Sys::getrlimit(resource, rlp)
.map(|()| 0)
@@ -110,7 +113,12 @@ pub unsafe extern "C" fn setrlimit(resource: c_int, rlp: *const rlimit) -> c_int
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getrusage.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn getrusage(who: c_int, r_usage: *mut rusage) -> c_int {
- Sys::getrusage(who, unsafe { Out::nonnull(r_usage) })
+ let Some(r_usage) = (unsafe { Out::nullable(r_usage) }) else {
+ crate::platform::ERRNO.set(crate::header::errno::EFAULT);
+ return -1;
+ };
+
+ Sys::getrusage(who, r_usage)
.map(|()| 0)
.or_minus_one_errno()
}
diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs
index fdd1ff0d..9e3a20e9 100644
--- a/src/header/unistd/mod.rs
+++ b/src/header/unistd/mod.rs
@@ -521,7 +521,7 @@ pub extern "C" fn getdtablesize() -> c_int {
};
if r == 0 {
let cur = unsafe { lim.assume_init() }.rlim_cur;
- match cur {
+ return match cur {
c if c < i32::MAX as u64 => c as i32,
_ => i32::MAX,
};
diff --git a/src/header/unistd/sysconf/linux.rs b/src/header/unistd/sysconf/linux.rs
index 2ec17eaf..8ec01d2d 100644
--- a/src/header/unistd/sysconf/linux.rs
+++ b/src/header/unistd/sysconf/linux.rs
@@ -167,11 +167,33 @@ pub(super) fn sysconf_impl(name: c_int) -> c_long {
// Values from musl which we can assume is correct.
match name {
_SC_CLK_TCK => 100,
- // TODO: getrlimit
- _SC_CHILD_MAX => -1,
+ _SC_CHILD_MAX => {
+ let mut lim = core::mem::MaybeUninit::<crate::header::sys_resource::rlimit>::uninit();
+ let r = unsafe {
+ crate::header::sys_resource::getrlimit(
+ crate::header::sys_resource::RLIMIT_NPROC as c_int,
+ lim.as_mut_ptr().cast::<crate::header::sys_resource::rlimit>(),
+ )
+ };
+ if r == 0 {
+ let cur = unsafe { lim.assume_init() }.rlim_cur;
+ if cur == crate::header::sys_resource::RLIM_INFINITY { -1 } else if cur > c_long::MAX as u64 { c_long::MAX } else { cur as c_long }
+ } else { -1 }
+ }
_SC_NGROUPS_MAX => NGROUPS_MAX as c_long,
- // TODO: getrlimit
- _SC_OPEN_MAX => -1,
+ _SC_OPEN_MAX => {
+ let mut lim = core::mem::MaybeUninit::<crate::header::sys_resource::rlimit>::uninit();
+ let r = unsafe {
+ crate::header::sys_resource::getrlimit(
+ crate::header::sys_resource::RLIMIT_NOFILE as c_int,
+ lim.as_mut_ptr().cast::<crate::header::sys_resource::rlimit>(),
+ )
+ };
+ if r == 0 {
+ let cur = unsafe { lim.assume_init() }.rlim_cur;
+ if cur == crate::header::sys_resource::RLIM_INFINITY { -1 } else if cur > c_long::MAX as u64 { c_long::MAX } else { cur as c_long }
+ } else { -1 }
+ }
_SC_STREAM_MAX => -1,
// TODO: limits.h
_SC_TZNAME_MAX => -1,
diff --git a/src/header/unistd/sysconf/redox.rs b/src/header/unistd/sysconf/redox.rs
index 97ee81aa..3d7f96dc 100644
--- a/src/header/unistd/sysconf/redox.rs
+++ b/src/header/unistd/sysconf/redox.rs
@@ -5,7 +5,7 @@ use alloc::string::String;
use crate::{
error::Errno,
fs::File,
- header::{errno, fcntl, limits, sys_statvfs},
+ header::{errno, fcntl, limits, sys_resource, sys_statvfs},
io::Read,
out::Out,
platform::{
@@ -65,14 +65,31 @@ pub const _SC_SIGQUEUE_MAX: c_int = 190;
pub const _SC_REALTIME_SIGNALS: c_int = 191;
// } POSIX.1
+fn resource_limit_sysconf(resource: c_int) -> c_long {
+ let mut lim = core::mem::MaybeUninit::<sys_resource::rlimit>::uninit();
+ let r = unsafe { sys_resource::getrlimit(resource, lim.as_mut_ptr()) };
+ if r != 0 {
+ return -1;
+ }
+
+ let cur = unsafe { lim.assume_init() }.rlim_cur;
+ if cur == sys_resource::RLIM_INFINITY {
+ -1
+ } else if cur > c_long::MAX as u64 {
+ c_long::MAX
+ } else {
+ cur as c_long
+ }
+}
+
pub(super) fn sysconf_impl(name: c_int) -> c_long {
//TODO: Real values
match name {
_SC_ARG_MAX => 4096,
- _SC_CHILD_MAX => 65536,
+ _SC_CHILD_MAX => resource_limit_sysconf(sys_resource::RLIMIT_NPROC as c_int),
_SC_CLK_TCK => 100,
_SC_NGROUPS_MAX => limits::NGROUPS_MAX as c_long,
- _SC_OPEN_MAX => 1024,
+ _SC_OPEN_MAX => resource_limit_sysconf(sys_resource::RLIMIT_NOFILE as c_int),
_SC_STREAM_MAX => 16,
_SC_TZNAME_MAX => -1,
_SC_VERSION => 200809,
diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
index 8b5560e7..e6dcac55 100644
--- a/src/platform/redox/mod.rs
+++ b/src/platform/redox/mod.rs
@@ -43,7 +43,7 @@ use crate::{
sys_file,
sys_mman::{MAP_ANONYMOUS, PROT_READ, PROT_WRITE},
sys_random,
- sys_resource::{RLIM_INFINITY, rlimit, rusage},
+ sys_resource::{RLIM_INFINITY, RLIMIT_NLIMITS, rlimit, rusage},
sys_select::timeval,
sys_stat::{S_ISVTX, stat},
sys_statvfs::statvfs,
@@ -103,6 +103,32 @@ macro_rules! path_from_c_str {
static CLONE_LOCK: RwLock<()> = RwLock::new(());
+/// Per-process resource limits. Initialized with Linux-compatible defaults.
+/// Inherited automatically across fork() (kernel copies address space).
+const RLIMIT_DEFAULTS: [rlimit; RLIMIT_NLIMITS as usize] = [
+ rlimit { rlim_cur: RLIM_INFINITY, rlim_max: RLIM_INFINITY }, // RLIMIT_CPU
+ rlimit { rlim_cur: RLIM_INFINITY, rlim_max: RLIM_INFINITY }, // RLIMIT_FSIZE
+ rlimit { rlim_cur: RLIM_INFINITY, rlim_max: RLIM_INFINITY }, // RLIMIT_DATA
+ rlimit { rlim_cur: 8 * 1024 * 1024, rlim_max: RLIM_INFINITY }, // RLIMIT_STACK (8 MB soft)
+ rlimit { rlim_cur: 0, rlim_max: RLIM_INFINITY }, // RLIMIT_CORE
+ rlimit { rlim_cur: RLIM_INFINITY, rlim_max: RLIM_INFINITY }, // RLIMIT_RSS
+ rlimit { rlim_cur: 4096, rlim_max: RLIM_INFINITY }, // RLIMIT_NPROC
+ rlimit { rlim_cur: 1024, rlim_max: 1024 * 64 }, // RLIMIT_NOFILE
+ rlimit { rlim_cur: RLIM_INFINITY, rlim_max: RLIM_INFINITY }, // RLIMIT_MEMLOCK
+ rlimit { rlim_cur: RLIM_INFINITY, rlim_max: RLIM_INFINITY }, // RLIMIT_AS
+ rlimit { rlim_cur: RLIM_INFINITY, rlim_max: RLIM_INFINITY }, // RLIMIT_LOCKS
+ rlimit { rlim_cur: 4096, rlim_max: RLIM_INFINITY }, // RLIMIT_SIGPENDING
+ rlimit { rlim_cur: 819200, rlim_max: RLIM_INFINITY }, // RLIMIT_MSGQUEUE
+ rlimit { rlim_cur: 0, rlim_max: 0 }, // RLIMIT_NICE
+ rlimit { rlim_cur: 0, rlim_max: 0 }, // RLIMIT_RTPRIO
+];
+
+/// Runtime resource limits, mutable via setrlimit().
+/// Inherited across fork() (kernel copies address space).
+static RLIMIT_TABLE: RwLock<[rlimit; RLIMIT_NLIMITS as usize]> = RwLock::new(
+ RLIMIT_DEFAULTS
+);
+
/// Redox syscall implementation of [`Pal`].
pub struct Sys;
@@ -729,21 +755,77 @@ impl Pal for Sys {
}
fn getrlimit(resource: c_int, mut rlim: Out<rlimit>) -> Result<()> {
- todo_skip!(0, "getrlimit({}, {:p}): not implemented", resource, rlim);
+ if resource < 0 || resource >= RLIMIT_NLIMITS as c_int {
+ return Err(Errno(EINVAL));
+ }
+ let table = RLIMIT_TABLE.read();
+ let current = &table[resource as usize];
rlim.write(rlimit {
- rlim_cur: RLIM_INFINITY,
- rlim_max: RLIM_INFINITY,
+ rlim_cur: current.rlim_cur,
+ rlim_max: current.rlim_max,
});
Ok(())
}
unsafe fn setrlimit(resource: c_int, rlim: *const rlimit) -> Result<()> {
- todo_skip!(0, "setrlimit({}, {:p}): not implemented", resource, rlim);
- Err(Errno(EPERM))
+ if resource < 0 || resource >= RLIMIT_NLIMITS as c_int {
+ return Err(Errno(EINVAL));
+ }
+ if rlim.is_null() {
+ return Err(Errno(EFAULT));
+ }
+ let new = unsafe { &*rlim };
+ if new.rlim_cur > new.rlim_max {
+ return Err(Errno(EINVAL));
+ }
+ let mut table = RLIMIT_TABLE.write();
+ let old = &table[resource as usize];
+ if new.rlim_max > old.rlim_max {
+ return Err(Errno(EPERM));
+ }
+ table[resource as usize] = rlimit {
+ rlim_cur: new.rlim_cur,
+ rlim_max: new.rlim_max,
+ };
+ Ok(())
}
- fn getrusage(who: c_int, r_usage: Out<rusage>) -> Result<()> {
- todo_skip!(0, "getrusage({}, {:p}): not implemented", who, r_usage);
+ fn getrusage(who: c_int, mut r_usage: Out<rusage>) -> Result<()> {
+ let clock_id = match who {
+ 0 /* RUSAGE_SELF */ => 2 /* CLOCK_PROCESS_CPUTIME_ID */,
+ 1 /* RUSAGE_THREAD */ => 3 /* CLOCK_THREAD_CPUTIME_ID */,
+ -1 /* RUSAGE_CHILDREN */ => {
+ r_usage.write(rusage {
+ ru_utime: timeval { tv_sec: 0, tv_usec: 0 },
+ ru_stime: timeval { tv_sec: 0, tv_usec: 0 },
+ ru_maxrss: 0, ru_ixrss: 0, ru_idrss: 0, ru_isrss: 0,
+ ru_minflt: 0, ru_majflt: 0, ru_nswap: 0,
+ ru_inblock: 0, ru_oublock: 0, ru_msgsnd: 0, ru_msgrcv: 0,
+ ru_nsignals: 0, ru_nvcsw: 0, ru_nivcsw: 0,
+ });
+ return Ok(());
+ }
+ _ => return Err(Errno(EINVAL)),
+ };
+
+ let mut redox_tp = syscall::TimeSpec::default();
+ let clock_result = syscall::clock_gettime(clock_id, &mut redox_tp);
+
+ let (tv_sec, tv_usec) = if clock_result.is_ok() {
+ let ts: timespec = (&redox_tp).into();
+ (ts.tv_sec, (ts.tv_nsec / 1000) as _)
+ } else {
+ (0, 0)
+ };
+
+ r_usage.write(rusage {
+ ru_utime: timeval { tv_sec, tv_usec },
+ ru_stime: timeval { tv_sec: 0, tv_usec: 0 },
+ ru_maxrss: 0, ru_ixrss: 0, ru_idrss: 0, ru_isrss: 0,
+ ru_minflt: 0, ru_majflt: 0, ru_nswap: 0,
+ ru_inblock: 0, ru_oublock: 0, ru_msgsnd: 0, ru_msgrcv: 0,
+ ru_nsignals: 0, ru_nvcsw: 0, ru_nivcsw: 0,
+ });
Ok(())
}
diff --git a/tests/sys_resource/rlimit_roundtrip.c b/tests/sys_resource/rlimit_roundtrip.c
new file mode 100644
index 00000000..c90a6b79
--- /dev/null
+++ b/tests/sys_resource/rlimit_roundtrip.c
@@ -0,0 +1,80 @@
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+int main(void) {
+ struct rlimit original;
+ struct rlimit current;
+ struct rlimit invalid;
+
+ errno = 0;
+ assert(getrlimit(RLIMIT_NOFILE, &original) == 0);
+
+ errno = 0;
+ assert(getrlimit(RLIMIT_NLIMITS, &current) == -1);
+ assert(errno == EINVAL);
+
+ errno = 0;
+ assert(getrlimit(RLIMIT_NOFILE, NULL) == -1);
+ assert(errno == EFAULT);
+
+ errno = 0;
+ assert(getrusage(RUSAGE_SELF, NULL) == -1);
+ assert(errno == EFAULT);
+
+ errno = 0;
+ assert(setrlimit(RLIMIT_NOFILE, NULL) == -1);
+ assert(errno == EFAULT);
+
+ invalid.rlim_cur = original.rlim_max;
+ invalid.rlim_max = original.rlim_cur;
+ errno = 0;
+ assert(setrlimit(RLIMIT_NOFILE, &invalid) == -1);
+ assert(errno == EINVAL);
+
+ if (original.rlim_max != RLIM_INFINITY) {
+ invalid.rlim_cur = original.rlim_max + 1;
+ invalid.rlim_max = original.rlim_max + 1;
+ errno = 0;
+ assert(setrlimit(RLIMIT_NOFILE, &invalid) == -1);
+ assert(errno == EPERM);
+ }
+
+ current.rlim_cur = original.rlim_cur > 16 ? original.rlim_cur - 16 : original.rlim_cur;
+ current.rlim_max = original.rlim_max;
+ errno = 0;
+ assert(setrlimit(RLIMIT_NOFILE, &current) == 0);
+
+ struct rlimit roundtrip;
+ errno = 0;
+ assert(getrlimit(RLIMIT_NOFILE, &roundtrip) == 0);
+ assert(roundtrip.rlim_cur == current.rlim_cur);
+ assert(roundtrip.rlim_max == current.rlim_max);
+
+ long open_max = sysconf(_SC_OPEN_MAX);
+ if (current.rlim_cur == RLIM_INFINITY) {
+ assert(open_max == -1);
+ } else if (current.rlim_cur > LONG_MAX) {
+ assert(open_max == LONG_MAX);
+ } else {
+ assert(open_max == (long)current.rlim_cur);
+ }
+
+ if (current.rlim_cur > INT_MAX) {
+ assert(getdtablesize() == INT_MAX);
+ } else {
+ assert(getdtablesize() == (int)current.rlim_cur);
+ }
+
+ errno = 0;
+ assert(setrlimit(RLIMIT_NOFILE, &original) == 0);
+ assert(getrlimit(RLIMIT_NOFILE, &roundtrip) == 0);
+ assert(roundtrip.rlim_cur == original.rlim_cur);
+ assert(roundtrip.rlim_max == original.rlim_max);
+
+ puts("rlimit roundtrip ok");
+ return 0;
+}
@@ -0,0 +1,67 @@
diff --git a/res/issue b/res/issue
index 6a963d8..092a432 100644
--- a/res/issue
+++ b/res/issue
@@ -1,4 +1,4 @@
-########## Redox OS ##########
+########## RedBear OS ##########
# Login with the following: #
# `user` #
# `root`:`password` #
diff --git a/res/motd b/res/motd
index 5cd097a..df2f802 100644
--- a/res/motd
+++ b/res/motd
@@ -1,2 +1,2 @@
-Welcome to Redox OS!
+Welcome to RedBear OS!
diff --git a/src/bin/login.rs b/src/bin/login.rs
index 08e178c..022fb47 100644
--- a/src/bin/login.rs
+++ b/src/bin/login.rs
@@ -120,6 +120,7 @@ fn load_config_schemes(user: &User<redox_users::auth::Full>) -> Option<Vec<Strin
pub fn main() {
let mut stdout = io::stdout();
let mut stderr = io::stderr();
+ let mut consecutive_failures: u32 = 0;
let _args = clap_app!(login =>
(author: "Jeremy Soller, Jose Narvaez")
@@ -133,9 +134,13 @@ pub fn main() {
}
loop {
+ if consecutive_failures >= 3 {
+ let delay_secs = std::cmp::min(consecutive_failures as u64, 30);
+ std::thread::sleep(std::time::Duration::from_secs(delay_secs));
+ }
let user = liner::Context::new()
.read_line(
- liner::Prompt::from("\x1B[1mredox login:\x1B[0m "),
+ liner::Prompt::from("\x1B[1mRedBear Login:\x1B[0m "),
None,
&mut liner::BasicCompleter::new(Vec::<String>::new()),
)
@@ -150,11 +155,13 @@ pub fn main() {
None => {
stdout.write(b"\nLogin incorrect\n").r#try(&mut stderr);
stdout.write(b"\n").r#try(&mut stderr);
+ consecutive_failures += 1;
stdout.flush().r#try(&mut stderr);
continue;
}
Some(user) => {
if user.is_passwd_blank() {
+ consecutive_failures = 0;
if let Ok(mut motd) = File::open(MOTD_FILE) {
io::copy(&mut motd, &mut stdout).r#try(&mut stderr);
stdout.flush().r#try(&mut stderr);
@@ -185,6 +192,7 @@ pub fn main() {
stdout.flush().r#try(&mut stderr);
if user.verify_passwd(&password) {
+ consecutive_failures = 0;
if let Ok(mut motd) = File::open(MOTD_FILE) {
io::copy(&mut motd, &mut stdout).r#try(&mut stderr);
stdout.flush().r#try(&mut stderr);
+1
View File
@@ -0,0 +1 @@
../../../local/patches/base/P2-ihdad-graceful-init.patch
+1
View File
@@ -0,0 +1 @@
../../../local/patches/base/P6-driver-main-fixes.patch
+1
View File
@@ -0,0 +1 @@
../../../local/patches/base/P6-driver-new-modules.patch
+4
View File
@@ -22,6 +22,7 @@ patches = [
# P5-init-daemon-panic-hardening.patch
# P5-init-supervisor-restart.patch
"P2-i2c-gpio-ucsi-drivers.patch",
"P2-ihdad-graceful-init.patch",
"P9-fix-so-pecred.patch",
"P3-inputd-keymap-bridge.patch",
"P3-ps2d-led-feedback.patch",
@@ -38,6 +39,9 @@ patches = [
"P4-fbcond-scrollback.patch",
"P4-thermal-daemon.patch",
"P4-thermald-workspace.patch",
"P6-driver-main-fixes.patch",
"P6-driver-new-modules.patch",
]
[package]
+16 -1
View File
@@ -1,6 +1,21 @@
# Consolidated patch: all Red Bear kernel changes (P0-P10) in a single file.
# Individual patches preserved in local/patches/kernel/ for reference/rebase.
# The consolidated patch was generated from applying: redox(no-op), P0-canary,
# P1-memory-map-overflow, P4-supplementary-groups, P4-s3-suspend-resume,
# P4-scheme-failure-modes, P5-sched-rt-policy, P5-scheme-sched-id,
# P5-context-mod-sched, P6-percpu-runqueues, P6-futex-sharding,
# P8-initial-placement, P9-proc-lock-ordering, P9-numa-topology,
# P1-boot-path-diagnostics, P10-debug-scheme-serial-fix.
# Patches that were cumulative supersets (P5-sched-policy-context, P5-proc-setschedpolicy,
# P5-boot-path-hardening, P6-vruntime-*, P7-cache-affine-*, P7-proc-setname,
# P7-proc-setpriority, P8-futex-requeue, P8-futex-pi, P8-futex-robust,
# P8-percpu-wiring, P8-percpu-sched, P8-load-balance, P8-work-stealing,
# P9-futex-pi-cas-fix) failed to apply at commit 866dfad0 due to
# context conflicts and are deferred until rebase.
[source]
git = "https://gitlab.redox-os.org/redox-os/kernel.git"
patches = ["redox.patch", "P0-canary.patch", "P1-memory-map-overflow.patch", "../../../local/patches/kernel/P4-supplementary-groups.patch", "../../../local/patches/kernel/P4-s3-suspend-resume.patch", "../../../local/patches/kernel/P4-scheme-failure-modes.patch", "../../../local/patches/kernel/P5-sched-policy-context.patch", "../../../local/patches/kernel/P5-sched-rt-policy.patch", "../../../local/patches/kernel/P5-proc-setschedpolicy.patch", "../../../local/patches/kernel/P5-scheme-sched-id.patch", "../../../local/patches/kernel/P5-context-mod-sched.patch", "../../../local/patches/kernel/P5-boot-path-hardening.patch", "../../../local/patches/kernel/P6-vruntime-context.patch", "../../../local/patches/kernel/P6-percpu-runqueues.patch", "../../../local/patches/kernel/P6-futex-sharding.patch", "../../../local/patches/kernel/P6-vruntime-switch.patch", "../../../local/patches/kernel/P7-cache-affine-context.patch", "../../../local/patches/kernel/P7-cache-affine-switch.patch", "../../../local/patches/kernel/P7-proc-setname.patch", "../../../local/patches/kernel/P7-proc-setpriority.patch", "../../../local/patches/kernel/P8-futex-requeue.patch", "../../../local/patches/kernel/P8-futex-pi.patch", "../../../local/patches/kernel/P8-futex-robust.patch", "../../../local/patches/kernel/P8-percpu-wiring.patch", "../../../local/patches/kernel/P8-percpu-sched.patch", "../../../local/patches/kernel/P9-proc-lock-ordering.patch", "../../../local/patches/kernel/P9-futex-pi-cas-fix.patch", "../../../local/patches/kernel/P1-boot-path-diagnostics.patch"]
rev = "866dfad0"
patches = ["../../../local/patches/kernel/redbear-consolidated.patch"]
[build]
template = "custom"
+1
View File
@@ -0,0 +1 @@
../../../local/patches/kernel/redbear-consolidated.patch
+1
View File
@@ -0,0 +1 @@
../../../local/patches/relibc/P10-stack-size-8mb.patch
+1
View File
@@ -0,0 +1 @@
../../../local/patches/relibc/P11-getrlimit-getrusage.patch
+1 -1
View File
@@ -1,6 +1,6 @@
[source]
git = "https://gitlab.redox-os.org/redox-os/relibc.git"
patches = ["P5-named-semaphores.patch"]
patches = ["P10-stack-size-8mb.patch", "P11-getrlimit-getrusage.patch"]
[build]
template = "custom"
+1 -1
View File
@@ -1,6 +1,6 @@
[source]
git = "https://gitlab.redox-os.org/redox-os/userutils.git"
patches = ["P4-login-rate-limit.patch"]
patches = ["P5-redbear-branding.patch"]
[build]
template = "custom"