Compare commits

..

1622 Commits

Author SHA1 Message Date
Red Bear OS bae63d9fa5 relibc: fix compile errors from stub replacement
- dirent::readdir_r: use copy_nonoverlapping (dirent has flexible
  array member, doesn't impl Copy)
- ld_so/dso.rs: make lazy_relocate pub(crate) so linker can call it
2026-07-10 23:28:05 +03:00
Red Bear OS 33577831b2 relibc: complete POSIX header stubs and ld_so improvements
- dirent/mod.rs: more readdir variants
- strings/mod.rs: complete stubs
- time/mod.rs: complete stubs
- ld_so/dso.rs: DSO management improvements
- ld_so/linker.rs: linker enhancements
2026-07-10 23:07:02 +03:00
Red Bear OS 0ef925f042 relibc: replace unimplemented! stubs in POSIX headers
- dirent::readdir_r: implement properly (deprecated but widely used)
- netdb: implement remaining stubs
- strings: complete stubs
- time: complete stubs
- unistd: complete stubs

All changes replace explicit unimplemented!() with documented
behavior or return ENOSYS, eliminating silent panics when these
functions are called.
2026-07-10 22:51:32 +03:00
Red Bear OS 14a7594cf1 relibc: fix DEBUG marker imports to use redox_rt::sys module 2026-07-10 20:48:19 +03:00
Red Bear OS b2ba9d160a relibc: add DEBUG marker write before relibc_verify_host
Temporary debugging aid to determine whether relibc_start_v1 is reached
before the init process crashes. Writes a marker to /scheme/debug/no-preserve
at the very start of relibc_start_v1, before any setup or verification.
2026-07-10 20:43:25 +03:00
Red Bear OS 54ed272d75 relibc: skip mmap_min update when mapping end is at canonical top
The previous cap at canonical_top_page still left mmap_min at
0x7FFFFFFFF000 (last canonical page), but there is no valid region
above that for anonymous mmaps — find_free_near would still return
None. Skip the mmap_min update entirely when the mapping end is at
or past the canonical top, so mmap_min retains its previous value
which points into a valid (lower) region of the address space.
2026-07-10 19:29:05 +03:00
Red Bear OS 94646dee65 relibc: cap mmap_min_addr at canonical user-space top
ROOT CAUSE: fexec_impl maps the 8 MB stack at STACK_TOP - STACK_SIZE =
0x7FFFFFF800000 (with STACK_TOP = 1 << 47 = 0x800000000000 on x86_64).
The update_min_mmap_addr closure computes (addr + size).next_multiple_of(PAGE_SIZE)
= 0x800000000000 as the new mmap_min. But 0x800000000000 is the FIRST
non-canonical address on x86-64 — the canonical lower half ends at
0x7FFFFFFFFFFF. With mmap_min = 0x800000000000, every subsequent anonymous
mmap fails because find_free_near can't find any hole at or above
0x800000000000.

This breaks ld.so's stage2 Tcb::new(0) call (8 KB anonymous mmap),
which uses .expect_notls() and panics → ud2. The init process crashes
before main() with 'Invalid opcode fault' at RIP 0x21cd1.

FIX: Add USER_CANONICAL_TOP_PAGE constant per architecture and cap
mmap_min_addr at that value. On x86_64/aarch64 this is 0x7FFFFFFFF000
(last page in the 48-bit canonical lower half). On riscv64-sv39 this
is (1 << 38) - 0x1000. On i686 this is (1 << 31) - 0x1000.
2026-07-10 19:20:59 +03:00
Red Bear OS 684ec4a1f5 relibc: remove duplicate [fn] section in sys_statfs/cbindgen.toml
cbindgen 0.29.x rejects duplicate TOML sections when the header-specific
cbindgen.toml is concatenated with cbindgen.globdefs.toml (which already
defines [fn]). The [fn] prefix = "" in sys_statfs was redundant (it's the
default), so removing it fixes the duplicate key error.
2026-07-10 15:12:00 +03:00
Red Bear OS afae337004 relibc: add CRTSCTS and TIOCM serial port constants for Redox
- termios/redox.rs: CRTSCTS hardware flow control flag
- sys_ioctl/redox/mod.rs: TIOCM_LE/DTR/RTS/ST/SR/CTS/CAR/CD/RNG/RI/DSR
  modem line constants, TIOCMGET/TIOCMSET ioctl numbers

These enable qtserialport to compile without source-mutating python
injections that wrap serial port code in #ifdef guards.
2026-07-10 14:26:12 +03:00
Red Bear OS 32df50c8fa relibc: add missing POSIX/Linux headers and constants
New headers:
- include/sys/ioccom.h: Linux UAPI ioctl encoding macros (_IO/_IOR/_IOW/_IOWR)
- include/byteswap.h: bswap_16/32/64 inline functions
- src/header/sys_statfs/: struct statfs + statfs()/fstatfs() functions
  (delegates to fstatvfs, converts to Linux struct statfs format)

New constants:
- sys_socket: MSG_NOSIGNAL, MSG_PROBE, MSG_CONFIRM, MSG_MORE, MSG_FASTOPEN
- sys_mman: MAP_GROWSDOWN, MAP_DENYWRITE, MAP_EXECUTABLE, MAP_LOCKED, MAP_NONBLOCK
- elf/cbindgen.toml: ELFMAG and SELFMAG #defines in after_includes

These headers eliminate the need for shim patches in libwayland (MSG_NOSIGNAL),
mesa (sys/ioccom.h), qtbase (sys/statfs.h, ELFMAG), pipewire/wireplumber
(byteswap.h, MAP_* flags).
2026-07-10 14:15:18 +03:00
Red Bear OS ee3107d873 sys_stat: implement utimensat() POSIX function
libstdc++ requires utimensat for file timestamp operations. Implemented
using openat(O_PATH) + futimens, with AT_SYMLINK_NOFOLLOW support.
2026-07-10 12:14:55 +03:00
Red Bear OS ef55c3cbb0 sched: exclude cpu_set_t from cbindgen export (defined in after_includes) 2026-07-10 11:52:55 +03:00
Red Bear OS 25b8182d1d sched: fix cpu_set_t ordering in generated header
The CPU_* inline functions in after_includes referenced cpu_set_t
before cbindgen generated its definition. Move the full struct typedef
into after_includes before the inline functions, and remove cpu_set_t
from the [export] list to avoid duplicate definitions.
2026-07-10 11:47:02 +03:00
Red Bear OS 6ac9666fab relibc: add CPU_ZERO/CPU_SET/CPU_CLR/CPU_ISSET/CPU_COUNT to sched.h 2026-07-10 10:09:10 +03:00
Red Bear OS ad1cd26e35 relibc: remove #[unsafe(no_mangle)] from fenv (C impl in toolchain libc) 2026-07-10 09:03:52 +03:00
Red Bear OS d65803384e relibc: revert _fenv to safe stubs (broken asm from other session) 2026-07-10 09:00:20 +03:00
Red Bear OS 8d94e8d2ae relibc: fix fenv asm — use memory operands for ldmxcsr/fldcw 2026-07-10 08:58:25 +03:00
Red Bear OS a34ffec558 relibc: fix asm! constraints for fenv 2026-07-10 08:55:43 +03:00
Red Bear OS 23db8a6b0d relibc: fix feupdateenv unsafe fn calls (Rust 2024 edition) 2026-07-10 08:53:34 +03:00
Red Bear OS c7764197c9 relibc: add Linux struct ifreq and ifconf to net/if.h
Qt 6.11.1 qtbase/qnetworkinterface_unix.cpp needs struct ifreq and
struct ifconf for SIOCGIFMTU/SIOCGIFINDEX/SIOCGIFCONF ioctls. Define
them in the cbindgen-generated net/if.h with sys/socket.h included.
2026-07-10 08:36:38 +03:00
Red Bear OS a1d8693fed relibc: implement _fenv with real x86_64 SSE+x87 asm (zero unimplemented!) 2026-07-10 08:35:42 +03:00
Red Bear OS 73226578f0 fix: wrap qsort_r unsafe ptr calls in unsafe blocks (Rust 2024 edition) 2026-07-10 01:53:12 +03:00
Red Bear OS a1b2384631 relibc: uncomment qsort_r #[unsafe(no_mangle)] for symbol export
qsort_r implementation existed but was hidden (attributes commented out).
Uncommented to export the symbol. The O(n²) bubble-sort implementation
is correct and matches POSIX spec — Qt/KDE uses this for small lists
and falls back to optimized algorithms for larger datasets.
2026-07-10 00:24:22 +03:00
Red Bear OS 9387fd2c34 relibc: implement get_sched_param — replace todo!() with real default
Replaces the todo!() in get_sched_param with a real implementation
that returns the default scheduler policy (SCHED_OTHER, priority 0).
On Redox, per-thread scheduling parameters are not exposed because
the microkernel does not provide per-thread scheduler policy queries.
The default matches the Linux fallback in pthread_getattr_np() when
no custom policy was set. get_cpu_clkid() is called for the clock_id
field and falls back to 0 if that returns ENOENT (expected on Redox
where per-CPU clock IDs are not yet implemented).
2026-07-09 20:40:08 +03:00
Red Bear OS b187b31d1a fix: add missing ENOPROTOOPT import in redox socket platform layer 2026-07-09 15:11:09 +03:00
Red Bear OS 8d52695af2 relibc: fix disguised socket stubs — listen + setsockopt
Fixed two critical disguised stubs found by comprehensive audit:

1. listen(): updated misleading 'Redox has no need to listen'
   comment. TCP sockets enter LISTEN state during bind() via
   smoltcp's tcp_handle.listen(), making POSIX listen() a no-op.
   The backlog is handled internally via scheme event mechanism.

2. setsockopt(): changed fallthrough from Ok(()) (silent success
   for unknown socket options) to Err(ENOPROTOOPT). Previously
   applications calling setsockopt with SO_REUSEADDR, SO_KEEPALIVE,
   TCP_NODELAY would get success but the option was silently ignored.
   Now returns the POSIX-correct error for unsupported options.
2026-07-09 15:05:47 +03:00
Red Bear OS 1c2af6a0e6 fix: add missing ENOTTY import in sys_ioctl redox module 2026-07-09 15:00:20 +03:00
Red Bear OS 74367d1542 relibc: fix redox feature compile errors 2026-07-09 13:08:39 +03:00
Red Bear OS fa792c6231 relibc: implement setitimer() using POSIX timer_create/timer_settime
Replaced ENOSYS stub with real implementation for ITIMER_REAL.

Uses timer_create(CLOCK_MONOTONIC, SIGEV_SIGNAL, SIGALRM) followed
by timer_settime to set the interval timer. ITIMER_VIRTUAL and
ITIMER_PROF still return ENOSYS (need per-process CPU time
accounting which Red Bear does not implement).

Cross-referenced with Linux 7.1 kernel/time/itimer.c which
implements setitimer via do_setitimer → hrtimer.

This fixes ualarm() and any legacy code that still uses setitimer(2).
2026-07-09 12:21:52 +03:00
Red Bear OS c1cad7f95f relibc: implement mremap() via munmap+mmap+memcpy
Replaced ENOSYS stub with real implementation using
syscall::funmap + syscall::fmap + copy_nonoverlapping.

Algorithm (cross-referenced with Linux 7.1 mm/mremap.c):
1. Same size → no-op
2. Smaller (shrink) → funmap excess pages
3. Larger with MREMAP_MAYMOVE → allocate new anonymous mapping,
   copy old data, funmap old mapping
4. Larger without MREMAP_MAYMOVE → ENOMEM (can't grow in place)

This fixes realloc() for large allocations that use mremap
via the platform allocator (platform/allocator/sys.rs).
2026-07-09 12:20:12 +03:00
Red Bear OS 21c3e96b1d relibc: implement clock_settime() via /scheme/time
Replaced ENOSYS stub with real implementation: opens
/scheme/time/{clk_id} for writing and writes the timespec.
Cross-referenced with Linux 7.1 kernel/time/posix-clock.c
pc_clock_settime().

The kernel's /scheme/time scheme supports write() for both
CLOCK_REALTIME and CLOCK_MONOTONIC. Writing a TimeSpec sets
the clock value. Returns EIO if fewer bytes written than
expected.
2026-07-09 11:50:45 +03:00
Red Bear OS 9eacf8efc4 pal: add syncfs to Pal trait (default calls fsync) 2026-07-09 11:36:25 +03:00
Red Bear OS b0e4502b6e relibc: add syncfs() syscall binding
Added syncfs(fd) which calls fsync(fd) — equivalent on Red Bear
since all filesystem I/O is synchronous. Cross-referenced with
Linux 7.1 fs/sync.c.
2026-07-09 11:25:05 +03:00
Red Bear OS 78d02e3f19 relibc: pty/redox: deduplicate grantpt/unlockpt/ptsname (keep openpty)
Remove grantpt, unlockpt, and ptsname from pty/redox.rs; stdlib/mod.rs
already provides cross-platform versions. Keep the Redox-specific openpty
helper.
2026-07-08 22:44:20 +03:00
Red Bear OS 9a0ad82a7f relibc: implement getauxval() with real values for common entries
Previously returned 0 unconditionally, breaking ELF programs that
rely on the auxiliary vector. Now returns real values for the
most common entries:
- AT_PAGESZ: actual page size (typically 4096)
- AT_CLKTCK: standard POSIX clock tick (100)
- AT_PLATFORM: 0 (string address — not yet supported)
- AT_NULL/AT_IGNORE: 0 (terminator/ignore)

Cross-referenced with Linux 7.1 fs/binfmt_elf.c create_elf_tables().

getpagesize() and dynamic linker initialization now work correctly.
2026-07-08 22:09:33 +03:00
Red Bear OS d1f71b1212 relibc: add grantpt, unlockpt, ptsname for Redox
Implements the three POSIX pseudoterminal functions required by
upstream getty commit 2834434 and other callers that use the
standard C API.

- grantpt(fd): no-op on Redox. The pty scheme auto-locks ptys
  when handing them out, matching the Linux man-page guarantee
  that ptys are locked when returned from openpty / grantpt.

- unlockpt(fd): no-op on Redox. Same rationale as grantpt.

- ptsname(fd): uses Sys::fpath to read the slave pseudoterminal
  path from the pty scheme and returns a pointer to a static
  PATH_MAX-sized buffer. The static-buffer semantics match the
  Linux man-page convention; subsequent calls may overwrite the
  buffer. Returns NULL on error (fpath failure).

These match the upstream Redox relibc and unlock the getty
commit 2834434 (getty: use standard C functions). Reference:
Linux 7.x man-pages/man3/{grantpt,unlockpt,ptsname}.3.html and
drivers/tty/pty.c.
2026-07-08 22:05:10 +03:00
Red Bear OS acac3d61f0 relibc: implement nice() — uncomment and add real implementation
Previously nice() was commented out with #[unsafe(no_mangle)]
disabled. Now exported and implemented:
1. Get current nice value via getpriority(PRIO_PROCESS, 0)
2. Add incr, clamp to [0, 39] (NZERO range)
3. Set via setpriority(PRIO_PROCESS, 0, new_value)
4. Return the new nice value

Cross-referenced with Linux 7.1 kernel/sched/core.c:set_one_prio()
and glibc posix/nice.c.
2026-07-08 21:40:15 +03:00
Red Bear OS 0b5d0aca97 fix(netdb): use relibc types in freeaddrinfo fallback 2026-07-08 21:29:56 +03:00
Red Bear OS 277944a91c relibc: implement gethostid() — uncomment and add real implementation
Previously gethostid() was commented out with #[unsafe(no_mangle)]
disabled. Now exported and implemented with three-tier fallback:
1. Read /etc/hostid file (hex value) if present
2. Compute djb2 hash from uname fields (nodename + sysname + machine)
3. Fallback to getrandom bytes

This is the standard glibc/BSD behavior. Cross-referenced with
glibc sysdeps/unix/gethostid.c.
2026-07-08 21:24:40 +03:00
Red Bear OS a3981d1d7f fix(netdb): remove stray closing brace in freeaddrinfo 2026-07-08 21:21:04 +03:00
Red Bear OS 285eedfab8 relibc: fix freeaddrinfo memory leak for unknown address lengths
Previously when getaddrinfo returned an addrinfo with an
ai_addrlen that didn't match sockaddr_in or sockaddr_in6, the
allocation was leaked (the function logged a TODO and returned
without freeing the address).

Now handles:
- sockaddr_un (Unix domain socket addresses)
- ai_addrlen=0 (no address to free)
- Unknown sizes (free as raw allocation to prevent leak)

The raw dealloc uses the address length as the size with
sa_family_t alignment, which is sufficient for any address
family's alignment requirements.
2026-07-08 21:15:31 +03:00
Red Bear OS f704b67f25 build(relibc): remove check_against_libc_crate from default features; fix cond import
The libc crate's pthread type layouts do not match Redox's relibc
layouts (e.g. pthread_cond_t 8 vs 12 bytes). Redox is its own libc,
so comparing against a foreign Linux libc crate is not meaningful.
Disable the feature by default and keep relibc types internally
consistent via assert_equal_size! checks against our own Rlct* types.
2026-07-08 20:03:25 +03:00
Red Bear OS 202e3eb500 relibc: implement pthread_cond_init with monotonic clock
Added clock: u8 field to Cond struct that stores the clock
setting (CLOCK_REALTIME or CLOCK_MONOTONIC) per pthread_condattr.
pthread_cond_init now properly sets the clock attribute.
timedwait uses the stored clock instead of hardcoding CLOCK_REALTIME.

Previously pthread_cond_init with CLOCK_MONOTONIC would log TODO
and use the wrong clock, causing condition variable timeouts to
behave incorrectly.

pthread_cond_t size updated from 8 to 12 bytes to accommodate
the new field. Cross-referenced with POSIX pthread_cond_init(3)
and Linux glibc nptl pthread_cond_init.c.
2026-07-08 19:58:46 +03:00
Red Bear OS 68d43106eb fix(pthread_mutex): store prioceiling in u8 to keep 12-byte layout matching libc crate 2026-07-08 19:54:05 +03:00
Red Bear OS 7f42a9fb20 relibc: implement pthread mutex prioceiling get/replace
Added prioceiling: c_int field to RlctMutex struct and real
implementations for prioceiling() and replace_prioceiling()
methods. Previously both returned Ok(0) silently (worse than
ENOSYS - caller believes operation succeeded).

pthread_mutex_t size updated from 12 to 16 bytes to accommodate
the new field while maintaining ABI alignment via #[repr(C)]
union with c_int alignment.

Cross-referenced with POSIX pthread_mutex_getprioceiling(3) and
Linux glibc nptl pthread_mutex_getprioceiling.c.

The prioceiling is stored in the mutex struct, set at construction
from pthread_mutexattr_getprioceiling. getprioceiling returns
the stored value; replace_prioceiling updates it and returns the
old value.
2026-07-08 19:46:46 +03:00
Red Bear OS 2347017649 fix(pthread_mutex): add missing prioceiling_value field for mutex priority ceiling 2026-07-08 19:44:19 +03:00
Red Bear OS 6c56264396 fix(socket): avoid casts in match patterns for IPPROTO_IP/IPPROTO_IPV6 2026-07-08 19:39:11 +03:00
Red Bear OS 93afedade5 relibc: extend getsockopt to handle IPPROTO_IP and IPPROTO_IPV6
Previously only SOL_SOCKET and IPPROTO_TCP levels were handled by
the socket scheme. Now IPPROTO_IP and IPPROTO_IPV6 levels also
forward to the socket scheme via SocketCall::GetSockOpt, removing
the ENOSYS fallthrough for these common socket option levels.

Cross-referenced with Linux 7.1 net/ipv4/ip_sockglue.c and
net/ipv6/ipv6_sockglue.c which implement IP/UDP/ICMP level
getsockopt handlers.
2026-07-08 19:24:43 +03:00
Red Bear OS 5638058b48 relibc: fix setgroups and unused ENOSYS import 2026-07-08 18:45:05 +03:00
Red Bear OS 5c8fe1c51a relibc: implement setgroups() via kernel proc Groups handle
Opens /scheme/sys/proc/{pid}/groups for writing, converts
the gid_t array to little-endian u32 bytes, and writes to the
procfs handle. The kernel's Groups writer (proc.rs:1600) reads
the bytes and updates the context's groups list.

Cross-referenced with Linux 7.1 kernel/groups.c setgroups().

Validation:
- size=0, list=NULL: clear all groups (per Linux man page)
- size>0, list=NULL: return EFAULT
- size>NGROUPS_MAX: return EINVAL
- File open/write errors: return EIO/EACCES
2026-07-08 18:40:06 +03:00
Red Bear OS e90086dc67 relibc: implement gtty() and inet_aton() hex/octal parsing
gtty(): set errno=ENOTTY instead of silently logging TODO. The
function always fails on Red Bear (no terminal ioctl subsystem).
Modern equivalent is tcgetattr(3) in <termios.h>.

inet_aton(): implement 0xNN (hex) and 0NN (octal) parsing per
Linux man-page inet_aton(3) convention. Mixed hex/octal/decimal
parts are normalized to decimal and fed to inet_pton. Previous
behavior logged TODO and returned 0 for any non-decimal part.
2026-07-08 18:30:51 +03:00
Red Bear OS 871078c4d9 relibc: implement vswprintf() — wide-char printf to string
Replaced todo_skip stub with vswprintf() that writes to a wchar_t buffer.

WcharWriter implements relibc's io::Write trait: each input byte
is written as a wchar_t to the output buffer. The wprintf::wprintf
function handles all format parsing; the writer adapter captures
the output. This matches the POSIX spec: wchar_t output array.

Note: output is byte-by-byte cast to wchar_t, not full UTF-16/UTF-32
encoding. This is a known limitation of the current wprintf pipeline
which outputs UTF-8 bytes even in Wide mode.
2026-07-08 18:25:33 +03:00
Red Bear OS 3b28c27e00 relibc: implement wcsxfrm() — identity transformation
Replaced todo_skip stub with proper wcsxfrm() implementation.

The wide-char string transformation uses the current locale's
collation. Red Bear has no locale support, so the transformation
is the identity (same as C/POSIX locale). Cross-referenced with
Linux 7.1 time/wcsxfrm.c.

Behavior:
- n=0: count length of ws2 (excluding null terminator)
- n>0: copy ws2 to ws1 with null terminator, cap at n-1 chars
- Returns number of wide chars written (excluding null terminator)
2026-07-08 18:15:21 +03:00
Red Bear OS 8d8c9c9bfd relibc: implement wcsftime() — remove todo_skip stub
Implemented wcsftime() as wide-char variant of strftime.
Cross-referenced from Linux 7.1 time/wcsftime.c.

Algorithm: convert wchar format to UTF-8 byte string (non-ASCII
chars replaced with '?'), call strftime::strftime with byte format
to format into a byte buffer, then convert each output byte to
a wchar_t in the output buffer (maxsize-1 chars + null terminator).

Also exposed time::strftime module as pub for cross-module access.
2026-07-08 18:14:05 +03:00
Red Bear OS 01807f6fa7 relibc: implement madvise() — remove ENOSYS stub
Replaced ENOSYS stub with proper POSIX madvise() implementation
cross-referenced from Linux 7.1 mm/madvise.c.

Flag validation: MADV_NORMAL, RANDOM, SEQUENTIAL, WILLNEED, DONTNEED.
Address must be page-aligned. Unknown flags → EINVAL.

Red Bear has no page cache, swap, or lazy allocation. All MADV_*
flags are no-ops: the hints are advisory and the kernel is free to
ignore them. MADV_DONTNEED would need page table teardown support
which is not implemented.
2026-07-08 18:00:15 +03:00
Red Bear OS fc158b3611 relibc: implement msync() — remove ENOSYS stub
Replaced ENOSYS stub with proper POSIX msync() implementation
cross-referenced from Linux 7.1 mm/msync.c:42-55.

Flag validation: MS_ASYNC|MS_INVALIDATE|MS_SYNC, rejects unknown
flags and MS_ASYNC|MS_SYNC combination. Address page-aligned check.
Length rounded to page boundary with overflow check.

Red Bear filesystem I/O is synchronous (no writeback cache).
MS_SYNC/MS_ASYNC are no-ops. MS_INVALIDATE not implemented (needs
kernel cache invalidation), but stale cache is not a concern
with direct filesystem reads.
2026-07-08 17:58:47 +03:00
Red Bear OS c1e4c1d53d relibc: use /scheme/proc/{pid}/ctx for ptrace GETREGS/SETREGS 2026-07-08 17:58:11 +03:00
Red Bear OS 628d5c2a51 0.3.0: add dual-toolchain VaList ABI probe and macros (relibc check passes) 2026-07-06 20:33:17 +03:00
vasilito 5004e94d1d 0.3.0: fix relibc build for Rust 2024 + VaList API (cargo check passes) 2026-07-06 19:37:02 +03:00
vasilito 4ef7e57571 0.3.0: converge relibc to upstream 0.6.0 + Red Bear patches 2026-07-06 19:13:57 +03:00
Jeremy Soller 1a0edd8eeb Add program_invocation_short_name 2020-12-23 20:24:04 -07:00
Jeremy Soller 2f3987dd88 Add _SC_GETPW_R_SIZE_MAX 2020-12-23 19:47:53 -07:00
Jeremy Soller d1ee653b5c Add dirfd 2020-12-23 19:47:44 -07:00
Jeremy Soller 928b18b306 Add sysexits.h 2020-12-23 13:45:25 -07:00
Jeremy Soller 5ae7b7efe7 Use new semaphore to prevent spinning 2020-12-23 12:20:19 -07:00
Jeremy Soller 2f69f0e7f1 Add simple semaphore implementation using futex 2020-12-23 12:18:17 -07:00
Jeremy Soller 79452dbd80 Remove warnings in elf.h 2020-12-23 12:18:02 -07:00
Jeremy Soller bddd69d0c1 Print when abort is called 2020-12-23 11:20:07 -07:00
Jeremy Soller 5efaffe0f9 Ensure that nul test is passed after last commit and failed before 2020-12-23 08:25:44 -07:00
Jeremy Soller 94a6da9116 Fix lookahead buffer reading nul's 2020-12-23 08:20:11 -07:00
Jeremy Soller 07ec3b6591 Merge branch 'mk-subs' into 'master'
Add submodules target to main makefile

See merge request redox-os/relibc!323
2020-10-18 19:48:03 +00:00
hasheddan e5539a570f Add submodules target to main makefile
Adds a submodules convenience target to main makefile. Submodules must
be initialized before other targets can run successfully.

Signed-off-by: hasheddan <georgedanielmangum@gmail.com>
2020-10-18 13:45:29 -05:00
Jeremy Soller 9529e09568 Force overwrite of libc.so.6 if it exists 2020-10-06 11:12:42 -06:00
Jeremy Soller 29e2f29231 Merge branch 'fmt' into 'master'
Fix formatiing issues

See merge request redox-os/relibc!316
2020-10-02 03:22:42 +00:00
Jeremy Soller 3e49323a3a Merge branch 'dlopen' into 'master'
Add support for dlopen(NULL, ...)

See merge request redox-os/relibc!315
2020-10-02 03:21:42 +00:00
Jeremy Soller 21e72cafc6 Merge branch 'tls' into 'master'
Fix tls tests for dynamic linker

See merge request redox-os/relibc!317
2020-10-02 03:20:50 +00:00
Mateusz Tabaka eee9a80baa Fix tls tests for dynamic linker
* load TLS segment for executable - while we can skip PT_LOAD for executable,
  we still have to load TLS segment.
* set TCB address based on if elf is position independent
2020-10-01 15:45:55 +02:00
Mateusz Tabaka 79643c293b Fix formatiing issues 2020-09-30 11:40:38 +02:00
Mateusz Tabaka c11aad71b8 Add support for dlopen(NULL, ...) 2020-09-30 11:04:10 +02:00
Jeremy Soller 687f4d4923 Merge branch 'dynamic' into 'master'
Add tests for ld_so

See merge request redox-os/relibc!314
2020-09-30 00:42:45 +00:00
Mateusz Tabaka 675101ac0e Add tests for dynamic linker 2020-09-29 23:01:52 +02:00
Mateusz Tabaka 7829a7ade9 Add support for RUNPATH 2020-09-29 23:01:48 +02:00
Mateusz Tabaka 58cc9efbc0 Call pthread_init in libc's init_array 2020-09-29 19:20:24 +02:00
Mateusz Tabaka 42acd32ac0 Fix TCB master address 2020-09-29 19:15:21 +02:00
Mateusz Tabaka b05d8df5f8 Restore previous load address for ld_so
Current value gives us 0x1234000 - 0x400000 ~ 14 MB for executable,
which is too low for certain programs.
2020-09-29 18:58:35 +02:00
Mateusz Tabaka c000373a08 Add symlink from libc.so to libc.so.6
Typically it's the other way around, but we can't have shared library named libc.so.6 in target/release directory.
cargo includes 'target/release' in LD_LIBRARY_PATH for build script, so even if clean build runs fine,
every subsquent run will make build script link with relibc.
2020-09-29 00:08:11 +02:00
Jeremy Soller 2c6114be75 Merge branch 'asctime-ub-asserts' into 'master'
Catch UB in asctime_r()

See merge request redox-os/relibc!312
2020-09-17 23:19:08 +00:00
Peter Limkilde Svendsen 00642dd940 Test extreme tm member values 2020-09-17 23:10:13 +02:00
Peter Limkilde Svendsen aef1be7c1b Remove errno setting 2020-09-17 23:10:13 +02:00
Peter Limkilde Svendsen 8ef64676fe Use stricter/simpler type handling 2020-09-17 23:10:13 +02:00
Peter Limkilde Svendsen 18a12c6c3d Add range assertions to asctime_r() 2020-09-17 23:10:13 +02:00
Jeremy Soller 36bb60cacc Do not unmap stack while it is being used, add a comment to fix it later 2020-09-09 18:49:44 -06:00
Jeremy Soller 2ed55a926b Merge branch 'gmtime-refactor' into 'master'
Refactor gmtime_r(), fix localtime() test

See merge request redox-os/relibc!309
2020-09-08 18:45:20 +00:00
Jeremy Soller 9f25fa39ea Merge branch 'gmtime-tests' into 'master'
Add more gmtime() tests

See merge request redox-os/relibc!308
2020-09-08 18:44:55 +00:00
Peter Limkilde Svendsen ff6bc68260 Add more gmtime() tests 2020-09-08 18:44:55 +00:00
Jeremy Soller f285128657 Merge branch 'asctime-char-cast' into 'master'
Avoid assuming c_char is i8 in asctime()

See merge request redox-os/relibc!307
2020-09-08 18:44:38 +00:00
Jeremy Soller dd193bcb8c Merge branch 'fix-asprintf-test-free' into 'master'
Add needed include for asprintf() test

See merge request redox-os/relibc!306
2020-09-08 18:43:57 +00:00
Jeremy Soller 4a6ef0221f Merge branch 'weak_rust_probestack' into 'master'
link: Weaken __rust_probestack symbol

See merge request redox-os/relibc!310
2020-09-06 13:04:34 +00:00
Esteban Blanc 9e0e88346d link: Weaken __rust_probestack symbol 2020-09-06 10:26:42 +02:00
Peter Limkilde Svendsen 59b0a36e81 Fix localtime() test 2020-08-27 23:16:17 +02:00
Peter Limkilde Svendsen 63711f6ca7 Formatting 2020-08-27 23:16:17 +02:00
Peter Limkilde Svendsen 845c74a82e Refactor gmtime_r() 2020-08-27 23:16:17 +02:00
Peter Limkilde Svendsen 86138c9f8a Align parameter naming with POSIX 2020-08-27 23:16:17 +02:00
Jeremy Soller 3a0d2177cd Variable for weakened symbols, weaken umodti3 2020-08-25 08:21:31 -06:00
Peter Limkilde Svendsen 23b2eb2573 Avoid assuming c_char is i8 2020-08-23 21:45:08 +02:00
Jeremy Soller 5472e117a5 Weaken __fixdfti 2020-08-21 21:28:51 -06:00
Peter Limkilde Svendsen aec4a84e90 Include stdlib.h so free() can be used 2020-08-20 20:43:28 +02:00
Jeremy Soller 5af8e3ca35 Merge branch 'bump-fmap' into 'master'
Use renamed fmap call

See merge request redox-os/relibc!305
2020-08-17 12:36:11 +00:00
Jeremy Soller a78f829dca Merge branch 'brk' into 'master'
Emulate brk

See merge request redox-os/relibc!304
2020-08-17 12:35:16 +00:00
jD91mZM2 e33aea434f Use renamed fmap call 2020-08-17 13:57:39 +02:00
jD91mZM2 eaee4e6329 Emulate brk 2020-08-15 18:44:22 +02:00
Jeremy Soller 7db83596a2 Merge branch 'gcc_compile' into 'master'
Gcc compile

See merge request redox-os/relibc!303
2020-08-14 15:19:14 +00:00
oddcoder ab92ff9d41 make all ld printlns happen in case of verbose = true and apply cargo fmt
It seams that stdout of ld.so is not that much of an issue but actually
it unfortunately is. The major problem here is that sometimes programs
generate header files in stdout (./getmy_custom_headers > header.h) and
we need to keep that cleen. and this is very very popular in gcc.
2020-08-12 18:57:37 +02:00
oddcoder 7b29f6eb27 Avoid relinking already linked libs
This patch avoids collecting symbols, resolving relocs if they are
already done (usually for example libc.so during a dlopen for another
libfoo.so). This patch is purely for performance boost.
2020-08-12 18:57:37 +02:00
oddcoder 61fcc018fc Refer to libraries with soname if available and avoid loading libs twice
It is usually not optimal to load a library twice and for specifics,
it is **terrible** idea to load libc twice it was enough trouble
dealing with libc statically linked into ld.so. So What this patch does
it check for soname and if a library is already loaded it won't get
loaded again. Why soname ? because unfortunately some bins gets linked
againt libc.so while of their dependencies gets linked against
libc.so.6 while one is usually symbolic link for the other.
2020-08-12 18:57:37 +02:00
oddcoder 9826cea092 Add SONAME for libc.so
Usually it is possible to refer to library either by the file name or by
elf "soname" soname is very similar for specifying something like
(LIB/API version) combination so if for example you have ./prog that
loads libx.so which is version 5.1.1 and there is ./plugin.so that ./prog
would load that requires libx.so version 5.1.2 both libx.so should have
the same soname to hint that they offer the exact same functionality.
And this patch specifies the soname for relibc libc.so.
2020-08-12 18:57:37 +02:00
jD91mZM2 7b6ba2c73a Merge branch 'lD_PATH' into 'master'
L d path

See merge request redox-os/relibc!300
2020-08-12 10:19:32 +00:00
Ahmed Abd El Mawgood 40328a0d09 Modify ld_script so that it works on linux.
Honestly, I have no idea why are these modifications needed, but it
seams they are needed
2020-08-12 10:19:32 +00:00
jD91mZM2 b9828bd863 Merge branch 'elf_And_flock' into 'master'
Elf and flock

See merge request redox-os/relibc!283
2020-08-12 10:17:59 +00:00
jD91mZM2 d827c0f166 Run Linux tests in CI
commit 09cb17e66f46c6687fa0b9dc0895ad3279caa092
Author: jD91mZM2 <me@krake.one>
Date:   Mon Aug 10 18:03:20 2020 +0200

    comment out cargo tests

commit 1915c7306e40f5c6af36b04c765e25ad9ffe9d16
Author: jD91mZM2 <me@krake.one>
Date:   Mon Aug 10 17:58:52 2020 +0200

    Update redoxer docker image
2020-08-11 11:14:13 +02:00
Jeremy Soller 91f0be8790 Merge branch 'weaken_floattidf' into 'master'
Also weaken `__floattidf`

See merge request redox-os/relibc!299
2020-08-08 14:15:55 +00:00
oddcoder b5deadbeea Add (POSIX defined) struct flock
struct flock is posix defined locking mechanism on *nix platform

Example usage (copied from https://gavv.github.io/articles/file-locks/) :

  #include <fcntl.h>

  struct flock fl;
  memset(&fl, 0, sizeof(fl));

  // lock in shared mode
  fl.l_type = F_RDLCK;

  // lock entire file
  fl.l_whence = SEEK_SET; // offset base is start of the file
  fl.l_start = 0;         // starting offset is zero
  fl.l_len = 0;           // len is zero, which is a special value representing end
                        // of file (no matter how large the file grows in future)

  fl.l_pid = 0; // F_SETLK(W) ignores it; F_OFD_SETLK(W) requires it to be zero

  // F_SETLKW specifies blocking mode
  if (fcntl(fd, F_SETLKW, &fl) == -1) {
    exit(1);
  }

  // atomically upgrade shared lock to exclusive lock, but only
  // for bytes in range [10; 15)
  //
  // after this call, the process will hold three lock regions:
  //  [0; 10)        - shared lock
  //  [10; 15)       - exclusive lock
  //  [15; SEEK_END) - shared lock
  fl.l_type = F_WRLCK;
  fl.l_start = 10;
  fl.l_len = 5;

  // F_SETLKW specifies non-blocking mode
  if (fcntl(fd, F_SETLK, &fl) == -1) {
      exit(1);
  }

  // release lock for bytes in range [10; 15)
  fl.l_type = F_UNLCK;

  if (fcntl(fd, F_SETLK, &fl) == -1) {
      exit(1);
  }

  // close file and release locks for all regions
  // remember that locks are released when process calls close()
  // on any descriptor for a lock file
  close(fd);
2020-08-08 10:16:50 +02:00
oddcoder e14b3e09a5 Add elf.h header to relibc 2020-08-08 10:16:50 +02:00
jD91mZM2 d08c63b1e7 Merge branch 'fix-ci' into 'master'
Fix CI

See merge request redox-os/relibc!302
2020-08-07 14:16:45 +00:00
jD91mZM2 6952a079ae Fix CI 2020-08-07 14:16:45 +00:00
jD91mZM2 72532b8280 Fix printf issue found in GDB 2020-08-05 16:49:10 +02:00
Jeremy Soller 4f93e43593 Merge branch 'fix-linker' into 'master'
Make linker work somewhat on Redox

See merge request redox-os/relibc!296
2020-08-04 12:24:51 +00:00
jD91mZM2 0178565f71 Move text section of linker away
Seems to collide with the program being loaded
2020-08-04 12:24:51 +00:00
James Graves 00b08605a3 Also weaken __floattidf
Fixes link error with ion shell.
2020-08-03 14:37:32 -05:00
Jeremy Soller 2073d2a80e Use objcopy to remove duplicate symbols 2020-08-02 20:41:45 -06:00
Jeremy Soller 2008296a10 Add sys_mman expected output 2020-08-02 14:34:56 -06:00
Jeremy Soller ae8e070b9e Init TLS before allocator 2020-08-02 14:32:28 -06:00
Jeremy Soller 0c6398abcb Do not require allocation in static_init 2020-08-02 14:32:20 -06:00
Jeremy Soller ebb17654f8 Add llvm_asm features 2020-08-02 13:42:34 -06:00
Jeremy Soller 5d45042d5d Correct more asm! usages 2020-08-02 13:38:29 -06:00
Jeremy Soller 12777ba774 Use 2020-07-27 nightly, it has rustfmt 2020-08-02 13:06:44 -06:00
Jeremy Soller f2c2d7c52e Fix compilation on newer nightly, update nightly to 2020-08-01 2020-08-02 12:24:49 -06:00
Jeremy Soller f131391b0d Merge branch 'memory' into 'master'
Make munmap use funmap2

See merge request redox-os/relibc!297
2020-07-30 14:04:06 +00:00
jD91mZM2 7d4d73dd83 Update redox_syscall 2020-07-30 15:58:21 +02:00
jD91mZM2 4c148c1860 Make munmap use funmap2 2020-07-30 13:39:20 +02:00
4lDO2 a5e02650d7 Remove ptrace write call. 2020-07-25 22:30:38 +02:00
4lDO2 285a7c62d4 Use mmap2 version of redox_syscall. 2020-07-25 22:30:38 +02:00
4lDO2 e38d185870 Use fmap2 to support passing an address. 2020-07-25 22:30:38 +02:00
Jeremy Soller d6b03de7a4 Align stack to 128 bytes 2020-07-19 21:04:16 -06:00
Jeremy Soller 677f0c989d Merge branch 'dlopen_dlclose_dlsym' into 'master'
Dlopen dlclose dlsym

See merge request redox-os/relibc!290
2020-07-19 19:35:31 +00:00
oddcoder 37a462de5d Apply cargo fmt to the whole repo 2020-07-19 21:27:38 +02:00
no name 890a9ed033 Implement dlopen/close 2020-07-19 21:27:38 +02:00
oddcoder ea3265766c Allow struct Linker to specify which library space to use 2020-07-19 21:21:48 +02:00
oddcoder 02aa400c5c Add callbacks to ld.so version of Linker's function
It is fact that ld.so has libc statially linked into it.

Normally we wouldn't need ld.so functionality once the program is
finalyl loaded, but with the next few patches, we will have dlopen which
will reuse the same ld.so functionality.

The problem is that it seams that huge part of the code is possible not
referntially transparent. That is, it is not impossible that some of the
functions have internals states. So when using the struct Linker that is
initialized by ld.so's copy of libc. we must access it using the same
copy even if both copies are identical.
For example in dlopen if you do linker.load_library(..). That would
segfault because it is using the function from libc not ld.so

So I don't truly undestand why should this be needed, but after long
hours of being stuck I thought maybe.. maybe that is the issue and
indeed it turned out to be so.
2020-07-19 21:21:48 +02:00
oddcoder b4a6a7ece5 Refactor init and fini by merging common code 2020-07-19 21:21:48 +02:00
oddcoder 6d0c9dccd5 Allow Linker struct to specify with library name space to operate on 2020-07-19 21:21:48 +02:00
oddcoder 01b1738b3a Separate library specific data from main Linker struct 2020-07-19 21:21:48 +02:00
oddcoder aaf017d9d1 Fix regression introduced in 5fcf9206
I by mistake commented _dl_debug_state() function which would break
debugging
2020-07-19 21:21:48 +02:00
Jeremy Soller 36ac4166ef Define MAP_ANON for dlmalloc 2020-07-19 12:40:01 -06:00
Jeremy Soller cf8cbe625b Merge branch 'allocator' into 'master'
Allocator

See merge request redox-os/relibc!295
2020-07-18 19:51:37 +00:00
no name 40acadc7d5 Sanity checking 04f77881d0 2020-07-18 21:15:57 +02:00
oddcoder 4d982f86b2 use only mspaces 2020-07-18 21:05:18 +02:00
oddcoder f4f68a3441 Make use of mspaces 2020-07-18 21:03:46 +02:00
oddcoder 3a8817072c Initialize the mspaces of allocator and keep track of it 2020-07-18 21:03:20 +02:00
oddcoder 67c703610b Compile dlmalloc with mspace support 2020-07-18 20:54:58 +02:00
oddcoder 9a1efda121 Initial allocator structure 2020-07-18 20:54:30 +02:00
Jeremy Soller 04f77881d0 Merge branch 'TLS' into 'master'
Fix wrong TLS resolving

See merge request redox-os/relibc!294
2020-07-18 18:48:14 +00:00
oddcoder d4b2391221 Fix wrong TLS resolving
I attempted fixing this issue before at 43fbaf99. Although it did work,
it worked wrong, and it was just consistently working (but in wrong way)
until it didn't.

Since this is (hopefully) the real fix, I will try to explain exactly
what is going on.

This is explaination by example:

our TLS is memory of size 0x1000 starting at 0x7ffff6c50000,
but the real size is 0x000068 so we have padding stored at master.offset
= 0xf98

Now our symbol looks as follows

  Offset          Type                Sym. Value    Name
000000432b20  R_X86_64_DTPOFF64   0000000000000058 errno

The old code did 0x7ffff6c50000 + 0xf98 + 000000432b20 which is
obviosly overflowing the memory and wrong.

The right way 0x7ffff6c50000 + 0xf98 + 0000000000000058.

THe Tls base part and offset are added at __tls_get_addr function.
What is left is storing the 0x58 at the relocation address. The problem
is that we don't have 0x58, but we have (binary base + 0x58) in global
symbol table and binary base so what we store is the (binarybase + 0x58
- binary base).

I hope this does turn out to be wrong.
2020-07-18 20:45:37 +02:00
jD91mZM2 e17c6049c6 Fix libgmp compilation 2020-07-15 11:12:59 +02:00
Jeremy Soller cbd7ead0ff Merge branch 'add_fwide' into 'master'
Add fwide function

See merge request redox-os/relibc!291
2020-07-09 12:29:53 +00:00
Wren Turkal 9a1e9c327a Make byte stream functions set stream orientation.
When a byte-oriented stream function touches a stream, that stream
should be set to byte-oriented mode if it hasn't been set yet. If
it has been set, the opertion should only succeed if the stream is
already in byte-oriented mode.

Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-07-08 14:33:11 -07:00
Wren Turkal 746a86a267 Add unlocked variation of fwide function.
Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-07-08 14:33:11 -07:00
Wren Turkal b623e245c0 Make freopen reset the stream orientation.
Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-07-08 14:33:11 -07:00
Wren Turkal 865b7962a1 Add implmentation for fwide posix function.
This function is used to set the orientation of a stream to either
byte-oriented or wchar-oriented.

More info on this function is here:
https://man7.org/linux/man-pages/man3/fwide.3p.html

This implementation only impmlemnts the manual switching and does
not yet guard against using a byte-oriented stream with wchar
functions and vice versa. Those step will come in additional
commits.

Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-07-08 14:33:06 -07:00
Jeremy Soller c13ba64832 Merge branch 'socketpair' into 'master'
Various socket-related changes and other

See merge request redox-os/relibc!289
2020-07-01 13:56:58 +00:00
jD91mZM2 29ad5b75c9 Fix broken CVec
Oops, forgot to initiate the pointer after uses of CVec::new()
2020-06-29 21:03:29 +02:00
jD91mZM2 56e1eceb28 Replace AllocStringWriter with CVec 2020-06-29 17:44:57 +02:00
jD91mZM2 39ce623d2d Fix bind/connect's AF_UNIX socket path... again
I don't really know for sure what all these silly rules are, but I think
I got it now...
2020-06-29 11:36:07 +02:00
jD91mZM2 593925ceb4 Unambiguate all include guards
GNU binutils also uses _FNMATCH_H for a guard, maybe along others!
2020-06-29 11:34:51 +02:00
jD91mZM2 f8b49936bc Various unix socket fixes (+socketpair!) 2020-06-27 16:39:50 +02:00
jD91mZM2 b7053b673d Fix missing types when compiling GDB 2020-06-25 13:03:06 +02:00
Jeremy Soller 7ea5cd5133 Merge branch 'rename-lcg48-rand48' into 'master'
Rename lcg48 module as rand48

See merge request redox-os/relibc!287
2020-06-24 16:55:27 +00:00
Jeremy Soller ce2de698c4 Merge branch 'random-alignment' into 'master'
Don't assume u32 alignment of random() state buffer

See merge request redox-os/relibc!286
2020-06-24 16:46:59 +00:00
Peter Limkilde Svendsen 5c8393d5aa Don't assume u32 alignment of random() state buffer 2020-06-24 16:46:59 +00:00
Jeremy Soller 954f010cc1 Merge branch 'pie' into 'master'
Fix bugs in handling non pie elfs

See merge request redox-os/relibc!285
2020-06-24 12:33:47 +00:00
oddcoder 5fcf920675 Fix bugs in handling non pie elfs
The problem here was that we alway added the base address, and we
assumed that all addresses we access are relative but this is not the
case in case of non pie binaries. The issue is that all addresses were
base+offset. so if we added the base again it will ofcourse generate
wrong address.
2020-06-24 10:21:20 +02:00
Peter Limkilde Svendsen 59b040258a Rename lcg48 as rand48 2020-06-23 18:34:44 +02:00
Jeremy Soller 547edcc267 Merge branch 'arpa_inet-types' into 'master'
Use C type names in byteorder functions

See merge request redox-os/relibc!274
2020-06-22 21:57:24 +00:00
Jeremy Soller 22a7f71282 Merge branch 'ctime_r' into 'master'
Add test for ctime_r(), replace mem::uninitialized()

See merge request redox-os/relibc!273
2020-06-22 21:57:04 +00:00
Jeremy Soller c95a5fa574 Merge branch 'random' into 'master'
Implement random() and friends

See merge request redox-os/relibc!284
2020-06-22 21:56:39 +00:00
Peter Limkilde Svendsen cc33874363 Implement random() and friends 2020-06-22 21:56:39 +00:00
Jeremy Soller db6a589421 Merge branch 'LD_LIBRARY_PATH' into 'master'
Ld library path

See merge request redox-os/relibc!279
2020-06-20 13:17:40 +00:00
Jeremy Soller d7089a09bf Merge branch 'LD_SO_ASM_REM' into 'master'
Get rid of assembly code in call_inits_finis

See merge request redox-os/relibc!282
2020-06-20 13:13:26 +00:00
oddcoder 0977133cc9 Get rid of assembly code in call_inits_finis 2020-06-20 15:01:13 +02:00
Jeremy Soller 73e1d6307b Merge branch 'socket-fix' into 'master'
Socket fix

See merge request redox-os/relibc!281
2020-06-19 11:58:24 +00:00
jD91mZM2 cdc9aa06e3 Fix getpeername
Rust's TcpListener fails because of the address format being wrong. The format
comes from `accept`, but there we internally use this function.
2020-06-19 13:56:06 +02:00
Jeremy Soller ca8b848b48 Merge branch 'headers' into 'master'
Headers

See merge request redox-os/relibc!280
2020-06-14 20:38:04 +00:00
oddcoder f4d95ce43f Add sys/select.h to sys/types.h
This was triggered by gcc for some reason It included sys/types.h and
assumed sys/select.h to be there. And that seams to be the case in musl.

The problem with relibc here is that sys/types.h is are part of relibc
"include/*.h" files, while sys/select.h is generated by cbindgen. That
makes it impossible to #include select.h in types.h epsecially that
there are files like fcntl.c that uses types.h. They would complain
about missing headers. I fixed this by renaming sys/types.h to
sys/types_internal.h and then generating types.h using cbindgen as well
except for that. however fcntl and dlmalloc can include types_internal
instead of types.h
2020-06-14 22:00:16 +02:00
oddcoder a125b8be15 Make stdbool.h C++ compatiable
The problem here is that _Bool type is not defined in C++ yet this file
is using it. That leads to issues when compiling gcc. I borrowed the
same techniques used in other stdbool.h
2020-06-14 22:00:10 +02:00
oddcoder 81da1bb1a3 Fix the avoid accessing errno issue from ld_so for real this time
This patch implements access function for both redox and linux and makes
sure that neither access errno variable
2020-06-13 19:55:33 +02:00
no name d5b63a85a4 Revert "Fix compilation on Redox by removing use of access in ld_so"
This reverts commit d9bacaec04.
2020-06-13 19:55:33 +02:00
no name c3ae8022ba Revert "Handle missing paths in load_library search without using access"
This reverts commit b0dde81c75.

The main issue was not with "access" being used, it was with errno being
accessed. This patch accesses errno as well

LD_LIBRARY_PATH="/folder/with/no/libc" ./a.out

gives segfault with the following stack trace

0x00000000004d1cae in relibc::platform::sys::e (sys=18446744073709551614) at src/platform/linux/mod.rs:54
 54                  errno = -(sys as isize) as c_int;
(gdb) bt
 #0  0x00000000004d1cae in relibc::platform::sys::e (sys=18446744073709551614) at src/platform/linux/mod.rs:54
 #1  0x00000000004d361e in <relibc::platform::sys::Sys as relibc::platform::pal::Pal>::open (path=0x5555555634c0, oflag=524288, mode=0) at src/platform/linux/mod.rs:330
 #2  0x000000000049a2ad in relibc::fs::File::open (path=0x5555555634c0, oflag=524288) at src/fs.rs:28
 #3  0x0000000000482b49 in relibc::ld_so::linker::Linker::load_recursive (self=0x7fffffffdd30, name=..., path=...) at src/ld_so/linker.rs:119
 #4  0x0000000000484963 in relibc::ld_so::linker::Linker::load_library (self=0x7fffffffdd30, name=...) at src/ld_so/linker.rs:184
 #5  0x0000000000483b53 in relibc::ld_so::linker::Linker::load_data (self=0x7fffffffdd30, name=..., data=...) at src/ld_so/linker.rs:152
 #6  0x00000000004831fe in relibc::ld_so::linker::Linker::load_recursive (self=0x7fffffffdd30, name=..., path=...) at src/ld_so/linker.rs:140
 #7  0x000000000048228a in relibc::ld_so::linker::Linker::load (self=0x7fffffffdd30, name=..., path=...) at src/ld_so/linker.rs:97
 #8  0x0000000000414a3b in relibc_ld_so_start (sp=0x7fffffffe310, ld_entry=4198896) at src/ld_so/start.rs:182
 #9  0x0000000000401209 in _start () at src/ld_so/src/lib.rs:10
 #10 0x0000000000000001 in ?? ()
 #11 0x00007fffffffe592 in ?? ()
 #12 0x0000000000000000 in ?? ()
2020-06-13 19:55:33 +02:00
Jeremy Soller 68679e41f0 Add redoxer.sh script to simplify running tests on redox 2020-06-09 20:55:55 -06:00
Jeremy Soller b771313ffd Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2020-06-07 14:01:00 -06:00
Jeremy Soller b0dde81c75 Handle missing paths in load_library search without using access 2020-06-07 14:00:48 -06:00
Jeremy Soller 7bc11dc6c2 Merge branch 'relibc-netdb-v1' into 'master'
netdb: implement getnetbynane and getnetent

See merge request redox-os/relibc!278
2020-06-07 12:27:54 +00:00
Giuseppe Longo 12beb13987 netdb: implement getnetbynane and getnetent
This patch implements getnetbyname and getnetent functions.
2020-06-07 14:02:41 +02:00
Jeremy Soller d9bacaec04 Fix compilation on Redox by removing use of access in ld_so 2020-06-06 21:00:57 -06:00
Jeremy Soller d0c1160299 Merge branch 'scanf' into 'master'
Scanf

See merge request redox-os/relibc!277
2020-06-06 19:32:54 +00:00
oddcoder 92d6735e3f Add more scanf tests 2020-06-03 23:20:53 +02:00
oddcoder 8973535fdc Make scanf write to string and increase match count only when a pattern is matched
This is the behavior of glibc which I assume to be right
2020-06-03 23:20:52 +02:00
oddcoder 018f7a3f38 Fix scanf.stdout as per glibc 2020-06-03 23:20:52 +02:00
oddcoder a49139ca2f use lookahead buffer in inner_scanf 2020-06-03 23:20:52 +02:00
oddcoder 14e011b72c Implemment lookaheadreader with lookahead and commit api
The LookAheadReader api works similar to read but it has 2 methods,
lookahead: it will read 1 byte (with internal ftell) without modifying
the file's own ftell() and commit() which saves the current file ftell

LookAheadReader can wrap both buffers and files
2020-06-03 23:20:52 +02:00
oddcoder f068673adc Separate the logic from locking in ftello and fseeko 2020-06-03 23:20:52 +02:00
oddcoder 164ef739b3 Apply Cargo fmt for src/ld_so 2020-06-03 23:20:52 +02:00
Jeremy Soller 12d3838f42 Merge branch 'fpermissive' into 'master'
FIX error: right operand of shift expression '(1 << BLA)' is greater than or...

See merge request redox-os/relibc!276
2020-06-02 21:52:17 +00:00
no name c02849dd73 FIX error: right operand of shift expression '(1 << BLA)' is greater than or equal to the precision BLA of the left operand [-fpermissive] 2020-06-02 23:27:15 +02:00
Jeremy Soller 5aa74fd2f3 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2020-06-02 08:35:41 -06:00
Jeremy Soller 604f1c11a2 Build xargo locally 2020-06-02 08:35:37 -06:00
Jeremy Soller b165eacffd Remove unnecessary compiler-builtins patch 2020-06-02 08:30:06 -06:00
Jeremy Soller e7f5e412a1 Merge branch 'LD_LIBRARY_PATH' into 'master'
Ld library path

See merge request redox-os/relibc!275
2020-06-01 12:23:46 +00:00
oddcoder 3aacc160a1 Remove dependency on errno in ld.so
During early parts of ld.so, errno and other thread local variables are
not yet initialized so we cannot use function (such as unistd::access)
that depends on such thread local variables (errno). For this reason
this patch creates small wrapper around the syscall that doesn't not
touch the errno
2020-06-01 11:49:38 +02:00
oddcoder 1b10c3d246 Prioterize search path instead of overwriting it.
Current LD_LIBRARY_PATH implementation overwrites the original search
path, which is not the best idea, instead this patch would check
LD_LIBRARY_PATH first and if it didn't find the libraries it is looking
for, then it will search the original search path
2020-06-01 11:41:19 +02:00
Jeremy Soller c7910a8754 Add __need_winit_t to wctype.h 2020-05-28 13:43:55 -06:00
Peter Limkilde Svendsen e4a7186b22 Use C type names in byteorder functions 2020-05-28 20:17:57 +02:00
Jeremy Soller ae34ade595 Use path to patch compiler-builtins 2020-05-27 20:24:59 -06:00
Jeremy Soller 8de10072b6 Add compiler-builtins patch 2020-05-27 20:18:52 -06:00
Peter Limkilde Svendsen ac52c3f205 Replace mem::uninitialized() 2020-05-26 17:58:59 +02:00
Peter Limkilde Svendsen b15c90ee32 Add test for ctime_r() 2020-05-26 00:20:14 +02:00
Jeremy Soller b2338968a2 Merge branch 'alignment-test-nullcheck' into 'master'
Don't accept null pointer in tests when requesting aligned memory

See merge request redox-os/relibc!272
2020-05-24 19:19:12 +00:00
Jeremy Soller 39346f5c05 Merge branch 'simplify-posix_memalign' into 'master'
Minor fixes to posix_memalign()

See merge request redox-os/relibc!271
2020-05-24 19:18:53 +00:00
Peter Limkilde Svendsen cf9c2ed0ba Don't accept null pointer when requesting aligned memory 2020-05-24 18:39:53 +02:00
Peter Limkilde Svendsen da8d2fa7aa Always set memptr in posix_memalign() 2020-05-24 18:29:57 +02:00
Peter Limkilde Svendsen 60b23003c7 Simplify alignment check in posix_memalign() 2020-05-24 18:17:27 +02:00
Jeremy Soller e4c26cfaa0 Merge branch 'gcc-regressions' into 'master'
Gcc regressions

See merge request redox-os/relibc!270
2020-05-23 15:16:36 +00:00
oddcoder 7eba6d88df Add test for negative pad stupport in printf 2020-05-23 16:20:20 +02:00
oddcoder ee5e2bad5a Support negative padding size in printf and friends
as it seams you can do something like
        printf ("A%*s%s/\n", -5, "B", "CC");
and it will print the padding to the left
2020-05-23 16:20:20 +02:00
oddcoder 1b131b8c60 Test off by one bug in vfscanf 2020-05-23 16:20:20 +02:00
oddcoder d7d3e00867 Fix off-by-1 error in vfscanf
Scanf function requires look ahead to function properly, In case of
scanning from a buffer that will not be an issue, but in our case we are
reading from file, so lookaheads needs to be undone (via lseek) in our
case. The only problem here is that if we opened a file that doesn't
support lseek such as many of the file /dev/*
2020-05-23 16:20:20 +02:00
oddcoder 6fba592fdb Implement regression test for ftell-ungetc bug 2020-05-23 16:20:20 +02:00
oddcoder 1733b3da6e Fix bug related to ungetc and ftell()
At least in relibc, each call to ungetc should decrement ftell() by one
also allowing negative ftell() this is not possible on relibc thus gcc
failing to compile (gcc compiles tools that is later used to compile gcc
itself and these tools are the ones that fail)
2020-05-23 16:20:20 +02:00
oddcoder 49dec86a5d Unit test arbitrarily long ungetc() 2020-05-23 16:20:20 +02:00
oddcoder 7a6f96373e Add support for multiple unget at the same time
According to the standards, only one ungetc may be guaranteed however
glibc allows more than one of those, and to be glibc compatiable, one
needs to be able to do the same, allowing only 1 ungetc may trigger bug
while compiling gcc as ungetc is used there alot
2020-05-23 16:20:20 +02:00
oddcoder 4c94dfac00 Add type definition for caddr_t
Normally one shouldn't be using this datatype ever, but then someone
have to tell that to gcc folks :(
2020-05-23 16:20:20 +02:00
Jeremy Soller 0cc0fbecdc Export getrandom function 2020-05-22 15:49:51 -06:00
Jeremy Soller a6fffd3fb5 Add getrandom and sys/random.h 2020-05-22 11:50:54 -06:00
Jeremy Soller 2cf3ccae72 Fix import of user_regs_struct 2020-05-21 20:01:47 -06:00
Jeremy Soller a1034b697d Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2020-05-21 14:59:41 -06:00
Jeremy Soller 06429ccc4c Fix redox socket inner_get_name 2020-05-21 14:59:22 -06:00
Jeremy Soller f6a119d3fc Merge branch 'binutils_regressions' into 'master'
Binutils regressions

See merge request redox-os/relibc!269
2020-05-13 22:02:31 +00:00
oddcoder 43fbaf9970 Fix a bug in thread local reloations
There was a bug (also uncovered via binutils) where R_X86_64_DTPOFF64 is
set uncorrectly. This program is the minimal reproducer of the seg fault

  #include <errno.h>
  int main() {
        int oerrno = errno;
  }

But it works after the bug fix.
2020-05-13 23:46:39 +02:00
oddcoder a39447e6a4 Test printf space padding regression 2020-05-08 22:38:42 +02:00
oddcoder d373bcb032 Avoid accessing memory without initialization 2020-05-08 22:38:42 +02:00
oddcoder 4a47bc4a6f Fix regressing in printf padding with space
There was bug in printf where space paddings cause segfault,
the problem was that it was pulled from the stack twice while it should
be only done once.
2020-05-08 22:38:42 +02:00
oddcoder d62f9b6819 Fix regression in ld.so elf size calculation
In patch 1182d12006, I mistakingly added
the size of the gap to the total size of the binary, which was not
accurate. As the size of the binary was calculate by subtracting the
upperbound from the lower bound, thus all gaps in the middle are taking
into account.
2020-05-08 22:38:42 +02:00
Jeremy Soller 8b7c45b39e Merge branch 'ld.so_regressions' into 'master'
Ld.so regressions

See merge request redox-os/relibc!268
2020-05-03 13:16:43 +00:00
oddcoder 850dfd971b Make "./a.out" entry the first in rmap list
This fixes a regression in gdb where sometimes it decides to ignore the
first entry in the list.
2020-05-03 14:59:55 +02:00
oddcoder 67be05d3a3 Use segments instead of sections for calculating which offset to write,
I noticed that the implementation is noth precise although it worked.
and instead of using the sections to identify memory addresses of
DT_DEBUG. I used segements
2020-05-03 14:59:52 +02:00
oddcoder 1182d12006 Fill gaps in binary memory image
Some ELFs can have gaps between the segments, this results in problems
when mprotecting or when converting (addr + size) into rust slice.
Motivated by this This patch will fill these gaps with mmaped addresses.
In theory no real memory should be allocated because mmap is lazy
allocator.
2020-05-03 13:57:24 +02:00
Jeremy Soller c799dad4e9 Merge branch 'wide-strings' into 'master'
Wide strings Functions

See merge request redox-os/relibc!267
2020-05-02 12:56:51 +00:00
oddcoder e9615065ac Add tests for both wcsncasecmp and wcscasecmp 2020-04-26 19:13:03 +02:00
oddcoder eac69c920d Implement wcscasecmp and wcsncasecmp
This patch implements wcscasecmp and wcsncasecmp. These two
function are required for binutils to link against relibc.
2020-04-26 19:13:03 +02:00
oddcoder 9725d3418a Test towlower and towupper 2020-04-26 19:13:03 +02:00
oddcoder 162999ac0b Move towlower and towupper to wctype.h and Implement it
This patch creates wctype.h and impelementat two functions
that belong to that header file towupper and towlower. These
functions are building blocks for wcscasecmp and wcsncasecmp
which are utilized by binutils.

The implementation for towlower and towupper seams to be complex
so this implementation is mimicking that of musl libc
2020-04-26 19:13:03 +02:00
Jeremy Soller a8a73f87c7 Merge branch 'procfs' into 'master'
Implement #include<sys/user.h> and #include<sys/procfs.h>

See merge request redox-os/relibc!266
2020-04-24 22:47:59 +00:00
oddcoder 3a923aa62d Implement #include<sys/user.h> and #include<sys/procfs.h>
This patch implements sys/user.h file that works for both x86_64 as well
as aarch64. This include file is used by sys/procfs.h which is needed
dependency for binutils. There is bug in this patch in aarch64 implementation
which is the lack of f128 implementation in rust, thus we can't create cbinding
for long double.
2020-04-24 22:08:49 +02:00
Jeremy Soller 763bb2488d Merge branch 'init_fini_ld.so' into 'master'
Init fini ld.so

See merge request redox-os/relibc!265
2020-04-19 12:40:00 +00:00
oddcoder b717f6cf5a Move IO Initialization to .init_array section
Most shared object in linux have their initialization in a separate
.init_array section. but glibc does not have the same behavour. Instead
the initialization is part of crt0. which (as it seams to me) run after
.init_array section. As such, this patch move IO initialization to
separate function that is marked as .init_array member and then the crt0
call this function only if init_array was never invoked (as in
statically linked binaries).
2020-04-19 14:21:23 +02:00
oddcoder 6aeb2d6fa2 Implement code that use .init_array and .fini_array
This patch implements ld.so code that makes use of both .init_array and
.fini_array. .init_array is fully utilized and is used in the correct
manner. However .fini_array is not used yet although the function that
runs .fini_array exists
2020-04-19 14:21:23 +02:00
oddcoder cc7ff54d12 Catch circular dependency when resolving loading shared libraries
This patch implements tree-based data-structure for catching circular
dependency where libA.so will depen on arbitrarily long chain (including
zero length) of libNs.so one of which will depend on libA.so again. The
main intention of this patch was merely capturing the dependency tree to
prioterize which Elf's .init_array and which .fini_array should run
first, but as a side effect it can capture circular dependencies as well.
2020-04-19 13:28:53 +02:00
Jeremy Soller 7724989b33 Merge branch 'Debugger_Support' into 'master'
Debugger support

See merge request redox-os/relibc!263
2020-04-15 17:59:01 +00:00
Jeremy Soller 77ad82a9dd Merge branch 'sigaction-restore' into 'master'
sigaction should set sigaction.sa_restorer

See merge request redox-os/relibc!264
2020-04-15 17:56:27 +00:00
Graham MacDonald 2283e25cde sigaction should set sigaction.sa_restorer 2020-04-14 23:37:54 +01:00
oddcoder de03566158 Enable RTLD debugging protocol system-wide
This patch makes use of the data structures and functions impelemented
in the last patch to enable RTLD debugging protocol as per SVR4
2020-04-13 12:39:51 +02:00
oddcoder 369d7b42c6 Initial implementation of SVR4 debugging interface for runtime linker 2020-04-13 12:12:48 +02:00
Jeremy Soller cdbbd4a426 Merge branch 'cbindgen' into 'master'
Remove vendored cbindgen, use cbindgen dependency to generate includes in build.rs

See merge request redox-os/relibc!261
2020-04-10 23:05:58 +00:00
Graham MacDonald 2253ef609e Remove vendored cbindgen, use cbindgen dependency to generate includes in build.rs 2020-04-10 23:05:58 +00:00
Jeremy Soller 69fc62278a Merge branch 'use_kernel_loaded_elf' into 'master'
Use Kernel mapped binaries when available.

See merge request redox-os/relibc!262
2020-04-07 21:42:37 +00:00
oddcoder cc305fc574 Use Kernel mapped binaries when available.
At least in linux kernel, assuming that a.out is an elf that is linked
against relibc's own ld.so. When a user attempts `./a.out`, Linux kernel
will map `./a.out`, then map `ld.so` and jump into ld.so entry point.
In relibc ld.so will simply ignore the kernel mapped a.out and create
its own mapping. This patch forces relic ld.so to use the already mapped
`a.out` when ever possible. This would normally have slight performance
improvement (especially that currently relibc doesn't map a.out but
instead copy the data into empty mmaped memory).

The real motivation behind this patch is while impelemnting Runtime
linker debugging protocol for relibc. part of the protocol is ld.so
inseting address of some ld.so managed data structure into .dynamic
seciton of a.out then the debugger would check it there. The thing is
that debuggers have information about the kernel loaded ./a.out and they
check that one specifically which is in our case totally ignored by
relibc.
2020-04-07 21:26:58 +02:00
Jeremy Soller 701e64b3a1 ld_so: Default to non-verbose 2020-03-29 20:17:29 -06:00
Jeremy Soller d7a859fb84 Keep exported functions 2020-03-24 20:05:38 -06:00
Jeremy Soller 6ed37efaeb Merge branch 'weak-symbols' into 'master'
Weak symbols

See merge request redox-os/relibc!260
2020-03-19 17:56:22 +00:00
Jeremy Soller 2629918100 Fix issue if test:redox is run without build:redox 2020-03-10 21:12:40 -06:00
Jeremy Soller 0090396132 Run cargo test 2020-03-10 21:03:52 -06:00
Jeremy Soller 880e3c7854 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2020-03-10 20:57:13 -06:00
Jeremy Soller 2e27cf525e Work on adding cargo test capability 2020-03-10 20:57:07 -06:00
oddcoder 4860ab12fa Resolve Both strong and weak symbols
This patch keep 2 lists, one for strong symbols and one for weak
symbols. First it will check for the symbol to be resolved in the strong
symbols' list, if it is not there it will then check in the weak symbol
list.
2020-03-08 22:03:21 +02:00
oddcoder c2488b5094 Running ./fmt.sh
These files needs formating by the auto formatter and It keeps popping
up every time I format my own code.
2020-03-07 23:52:27 +02:00
oddcoder 04ea2f9397 Refactor Linker::Link
This patch does basically two things:
- First make `global` variable not public, And make it accessable via a
function `get_sym`.
- Isolate the procedure that collect global symbols into single function
that does that and call it `collect_syms`.

The motivation of this patch is the second one where this procedure is
extended, thus it needs a seamless way to access those symbols
2020-03-07 23:52:27 +02:00
Jeremy Soller 77a0294114 Merge branch 'stdc-compatiability' into 'master'
Stdc compatiability

See merge request redox-os/relibc!258
2020-03-06 03:58:42 +00:00
oddcoder 3ac6ef1848 Adjust stddef.h to be compatiable with other libc(s)
I faced many issues when compiling libstdC++-V3 and linking against
relibc mainly:
- Missing types (max_align_t)
- Different types definitions(ptrdiff_t , size_t)
- and the fact that wchar_t is part of standard C++ and it seams that we
  canno redefine standard types
2020-03-02 00:06:49 +02:00
oddcoder a2f2484e45 Add minimal basic features.h resembling musl lib's own 2020-03-01 22:59:39 +02:00
Jeremy Soller 79f265745a Fix redox ld_so 2020-02-28 19:33:20 -07:00
Jeremy Soller b1aad49df4 Merge branch 'linux-ld' of gitlab.redox-os.org:oddcoder/relibc 2020-02-28 19:12:19 -07:00
oddcoder bc53164293 Reduce Verbosity level when ld.so is invoked as interpreter 2020-02-24 11:56:12 +02:00
oddcoder 7f8dc2f251 Add support for invoking ld.so via execve() and friends
Introduction:

The original implementation of `relibc_ld_so_start` assumes that
ld.so will always be invoked manually as in "/lib/ld64.so ./a.out"
The problem is regarding this snippet.
    if sp.argc < 2 {
      eprintln!("ld.so [executable] [arguments...]");
      unistd::_exit(1);
      loop {}
    }

As such, In linux when user types "./a.out" he will recieve the message
    ld.so [executable] [arguments...]

This patch makes use of AUXV, specifically AT_ENTRY. When invoking ld.so
manually, AT_ENTRY happens to be the entry point of ld.so. But when
running `./a.out` directly, AT_ENTRY becomes the entry point of `a.out`
this patch compares AT_ENTRY to the entry point of ld.so, if they are
equal only then it will assume that argv[1] is the real program and
adjust the stack, otherwise it will proceed with the stack unadjusted.
2020-02-24 11:56:09 +02:00
Jeremy Soller e85148cc15 Merge branch 'oddcoder-master-patch-78534' into 'master'
Fix make libs in CI

See merge request redox-os/relibc!256
2020-02-18 17:09:48 +00:00
Ahmed Abd El Mawgood 9f86748a58 Fix make libs in CI
There is no make libc

➜  relibc git:(master) make libc
make: *** No rule to make target 'libc'.  Stop.
2020-02-14 18:42:38 +00:00
Jeremy Soller 3d2f86b39e Merge branch 'feature/support-af-unix-sockets' into 'master'
Support AF_UNIX sockets

See merge request redox-os/relibc!255
2020-02-07 02:19:42 +00:00
Tiago Lam 76f07b163b platform/redox: Support AF_UNIX in accept.
As with the previous commit, accept() was calling inner_get_name() and
assuming only "tcp:" or "udp:" addresses would be received. Thus, in
order to support AF_UNIX sockets, inner_get_name() was split into two,
inner_af_inet() and inner_af_unix() - where the former keeps the
previous logic, dealing with "tcp:" and "udp:" addresses, and the latter
deals now with "chan:" addresses and filling in the sockaddr_un
appropriately.
2020-02-06 08:41:51 +00:00
Tiago Lam d36cd72788 platform/redox: Support AF_UNIX in bind / connect.
Previously, domain AF_INET was assumed while processing bind() /
connect(), which end up calling bind_or_connect!. Instead, match on the
domain type and process the path for AF_UNIX domains.
2020-02-06 08:41:48 +00:00
Tiago Lam 12f6ffd152 platform/redox: Support AF_UNIX in socket.
To add support for UNIX sockets (AF_UNIX), of SOCK_STREAM type, the
"chan:" scheme is used, which will be supportedby the ipcd running in
userspace.

Later commits add similar AF_UNIX support for the rest of the methods in
impl PalSocket.
2020-02-06 08:21:12 +00:00
Tiago Lam 2bc667f71c header/sys_un: Set sockaddr_un members to public.
Future commits will make use of this, in order to support AF_UNIX
sockets.
2020-02-06 08:21:12 +00:00
Jeremy Soller 662051a91b Only call epoll_ctl once per descriptor, fixing vim on Redox 2020-01-28 20:15:01 -07:00
Jeremy Soller 4c4ce7ec03 Add Redox termios definitions 2020-01-27 21:01:59 -07:00
Jeremy Soller 9a449d4f6c Stub for SO_ERROR to fix curl 2020-01-21 20:29:26 -07:00
Jeremy Soller 2e5d4a4d25 Merge remote-tracking branch 'origin/truncate-n-mkfifo' 2020-01-20 11:17:15 -07:00
Jeremy Soller 1534373645 Merge branch 'ctype_conv' into 'master'
Use lossless type conversion in ctype.h

See merge request redox-os/relibc!246
2020-01-20 17:57:56 +00:00
Peter Limkilde Svendsen 0b4b3cd55c Use lossless type conversion in ctype.h 2020-01-20 17:57:56 +00:00
Jeremy Soller 10f2e0fefc Merge branch 'fd-dup-test-robusty' into 'master'
Fix fd dup tests to be more robust

See merge request redox-os/relibc!251
2020-01-20 17:48:43 +00:00
Jeremy Soller c6e3cb8ed3 Merge branch 'no-uninit' into 'master'
Replace occurences of uninitialized with MaybeUninit

See merge request redox-os/relibc!248
2020-01-20 16:54:22 +00:00
AdminXVII 884ec85838 Replace occurences of uninitialized with MaybeUninit
mem::uninitialized is deprecated, so move over the not-UB MaybeUninit.
2020-01-20 16:54:22 +00:00
Jeremy Soller 7d6288abbe Merge branch 'samuela-master-patch-09777' into 'master'
Fix ar usage in Makefile for macOS compatibility

See merge request redox-os/relibc!253
2020-01-20 16:41:24 +00:00
Jeremy Soller f167081f84 Merge branch 'fix-test' into 'master'
Re-enable netdb tests, fix compiler warning, improve brk coverage

See merge request redox-os/relibc!254
2020-01-20 16:22:09 +00:00
Graham MacDonald 18e1a5608f Re-enable netdb tests, fix compiler warning, improve brk coverage 2020-01-13 22:22:40 +00:00
samuela 0be4208aa7 Fix ar usage in Makefile for macOS compatibility 2020-01-08 17:59:38 +00:00
Jeremy Soller a3f7a174f6 WIP - implementation of dlfcn 2019-12-18 21:21:25 -07:00
Jeremy Soller 2cbc78f238 Add linker pointer 2019-12-18 21:15:00 -07:00
Jeremy Soller 36eb561128 Format 2019-12-18 20:01:48 -07:00
Jeremy Soller 086c8f6702 Allow running linker more than once 2019-12-17 21:35:47 -07:00
Jeremy Soller 0a06388d2a Store globals and mappings on Linker struct 2019-12-16 21:27:42 -07:00
Jeremy Soller b882ce527d Fix allocation of TLS masters if main image does not require TLS 2019-12-15 11:19:37 -07:00
Jeremy Soller 4818ad61ab Always zero mmap'd memory 2019-12-15 07:46:59 -07:00
Jeremy Soller 886f859bb9 Clear FPU registers before jumping to loaded program 2019-12-15 07:46:49 -07:00
Jeremy Soller 76798b7d6b Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2019-12-06 19:55:21 -07:00
Jeremy Soller fe3607d4e8 ld_so: Zero mapped memory and panic on unsupported relocation 2019-12-06 19:54:54 -07:00
Jeremy Soller 5baec1e4e8 Merge branch 'printf-inf-nan' into 'master'
Handle infinity and NaN in printf

See merge request redox-os/relibc!252
2019-12-05 01:37:17 +00:00
Peter Limkilde Svendsen 74555698fb Handle infinity and NaN in printf 2019-12-05 01:37:17 +00:00
Sean Kennedy a1c3510761 Fix fd dup tests to be more robust
i.e. not depending on the first fd to be 4.
2019-12-02 14:53:55 -05:00
Jeremy Soller 8ba70792e9 Implement DTPOFF64 2019-12-01 13:47:06 -07:00
Jeremy Soller 2ac349d2d2 Add msync function and stub for Redox 2019-12-01 10:58:47 -07:00
Jeremy Soller 15e6d23538 Update rust-toolchain 2019-11-29 18:06:12 -07:00
Jeremy Soller e3ce41da79 Fix compilation on newer nightly 2019-11-29 18:05:31 -07:00
Jeremy Soller 3db0588de0 Merge branch 'ctime_r' into 'master'
added ctime_r

See merge request redox-os/relibc!250
2019-11-28 02:41:58 +00:00
Andrzej J. Skalski 278a70c813 added ctime_r 2019-11-28 02:41:58 +00:00
Jeremy Soller 631fd4f0f5 Merge branch 'wcsstr' into 'master'
Implement wcsstr(), fix return type of wcslen()

See merge request redox-os/relibc!249
2019-11-14 02:46:53 +00:00
Peter Limkilde Svendsen 0b2c3fe5ea Implement wcsstr(), fix return type of wcslen() 2019-11-14 02:46:53 +00:00
Jeremy Soller ae69586f20 Implement getrlimit on Linux and stub on Redox 2019-09-18 20:29:25 -06:00
Jeremy Soller 46a330ec9e Fix compilation of sys/resource 2019-09-18 15:55:27 -06:00
Xavier L'Heureux f53e9b5d9a Remove the mkfifo test 2019-09-17 21:41:03 -04:00
Xavier L'Heureux e8b8b7eb25 Fix format and disable stat check for access time 2019-09-17 21:23:07 -04:00
Xavier L'Heureux 64f93fe6e0 Implement the truncate function 2019-09-17 19:57:43 -04:00
Xavier L'Heureux 5156a13b3e Add a test for futimens 2019-09-16 12:25:29 -04:00
Jeremy Soller 64dde1548c Merge branch 'patch-2' into 'master'
sys/uio.h: include sys/types.h

See merge request redox-os/relibc!244
2019-09-15 19:34:43 +00:00
Jeremy Soller 3b12a400bf Merge branch 'lcg48_refactor' into 'master'
lcg48 refactor

See merge request redox-os/relibc!243
2019-09-15 19:34:12 +00:00
Peter Limkilde Svendsen 7fdd450e16 lcg48 refactor 2019-09-15 19:34:12 +00:00
Jeremy Soller cc4c3a5cb4 Merge branch 'a64l_l64a_refactor' into 'master'
Refactor of a64l and l64a

See merge request redox-os/relibc!242
2019-09-15 19:33:29 +00:00
Peter Limkilde Svendsen a80ec357e3 Refactor of a64l and l64a 2019-09-15 19:33:29 +00:00
Jeremy Soller d1d45ff00d Merge branch 'warning' into 'master'
Fix few warnings

See merge request redox-os/relibc!236
2019-09-15 19:31:08 +00:00
Jeremy Soller f4b8847605 Merge branch 'mut-program_invocation_name' into 'master'
Make program_invocation_name modifiable

See merge request redox-os/relibc!240
2019-09-15 19:30:31 +00:00
Xavier L'Heureux 30d3cd5c88 Fix the mkfifo call on Linux and add a test to avoid regression 2019-09-13 12:35:08 -04:00
Matija Skala 81470916be sys/uio.h: include sys/types.h
needed for ssize_t
2019-09-08 08:36:22 +00:00
Steve McKay 4859c222e7 Make program_invocation_name modifiable
libiconv expects program_invocation_name to be an lvalue
2019-08-17 12:35:43 -04:00
jD91mZM2 4f2a93ea90 Vast refactor of pwd.h, add getpwent/setpwent/endpwent 2019-08-12 09:58:11 +02:00
jD91mZM2 aeab6a986d Fix a few GDB compilation issues 2019-08-12 09:30:05 +02:00
Jeremy Soller 8f502a3436 Merge branch 'fix-signal' into 'master'
Fix invalid memory reference in signal and sigaction

See merge request redox-os/relibc!239
2019-08-12 02:54:28 +00:00
Xavier L'Heureux 5799555566 Remove print statements 2019-08-11 21:53:32 -04:00
Xavier L'Heureux f2357390e9 Fix redox's implementation 2019-08-11 21:06:47 -04:00
Xavier L'Heureux 0a558de76c Fix reference getting moved
The sigaction handler called map on an option, creating a pointer to a
move value. This in turned caused UB for signal handlers. Avoid using
pointers directly, and instead prefer references.
2019-08-11 20:47:18 -04:00
Xavier L'Heureux 225583230f Test 2019-08-11 18:11:19 -04:00
Xavier L'Heureux 4c7f8c6369 test signals 2019-08-11 14:30:00 -04:00
Jeremy Soller 37a5da34b9 Fix pte_osSemaphorePend deadlock 2019-08-09 21:18:20 -06:00
Jeremy Soller e7d19e2a58 Move SIG_IGN and friends to C in order to define them correctly 2019-08-08 20:06:38 -06:00
Jeremy Soller 8feed5bbd5 Update Rust to 2019-08-08 2019-08-07 20:48:29 -06:00
jD91mZM2 a7b354c8e0 Update to latest syscall after merging ptrace 2019-08-04 19:46:10 +02:00
jD91mZM2 a1e45941bf Fix ptrace after latest kernel changes 2019-08-04 19:05:45 +02:00
jD91mZM2 b8c50c7c64 Format 2019-08-04 19:05:45 +02:00
jD91mZM2 c7d499d4f2 Upgrade to the 2018 edition
I didn't think it'd be this useful first, but thank god for `cargo fix --edition`!
2019-08-04 19:05:45 +02:00
jD91mZM2 72c2f59f17 Update redox_syscall to use bitflags 2019-08-04 19:05:45 +02:00
jD91mZM2 82abb3313e Support adding WUNTRACED 2019-08-04 19:05:45 +02:00
jD91mZM2 f389010fff Initial ptrace compatibility for Redox OS 2019-08-04 19:05:45 +02:00
jD91mZM2 7f702720af Fix header file generation for ptrace 2019-08-04 19:05:44 +02:00
jD91mZM2 43ff8801bc Format 2019-08-04 19:05:44 +02:00
jD91mZM2 35c1d5210c Implement the Once<T> synchronization structure
Not sure if I should add a RwLock for the ptrace state too...
2019-08-04 19:05:44 +02:00
jD91mZM2 e559a3e2e5 Stub for ptrace
It's happening...
2019-08-04 19:05:44 +02:00
Jeremy Soller a2721b8a31 Merge branch 'cbindgen' into 'master'
Fix cbindgen for disabled headers

See merge request redox-os/relibc!237
2019-07-31 14:07:35 +00:00
Mateusz Mikuła bd573fb7cc Fix cbindgen for disabled headers 2019-07-31 12:39:28 +02:00
Jeremy Soller f467791b12 Fix definition of SIG_ERR 2019-07-25 21:27:41 -06:00
jD91mZM2 cb63dec86f Add missing SIG_DFL and SIG_IGN constants 2019-07-25 17:34:59 +02:00
Jeremy Soller 25e67b9f58 Add setsockopt support for SO_RCVTIMEO and SO_SNDTIMEO 2019-07-24 17:18:01 -06:00
Jeremy Soller 9d7ec9b146 Fix getcwd on Redox 2019-07-21 07:57:31 -06:00
Mateusz Mikuła 9aac2672e3 Fix few warnings 2019-07-18 15:27:05 +02:00
Jeremy Soller f1be9266e2 Merge branch 'defines-cleanup' into 'master'
Remove defines that are generated by new cbindgen from bits

See merge request redox-os/relibc!234
2019-07-18 12:04:01 +00:00
Jeremy Soller aba76239b3 Merge branch 'ci' into 'master'
Don't use diff on Redox

See merge request redox-os/relibc!233
2019-07-18 11:55:54 +00:00
Mateusz Mikuła b599c453a0 Remove defines that are generated by new cbindgen from bits 2019-07-18 13:18:00 +02:00
Mateusz Mikuła c40b7d6fb4 Don't use diff on Redox 2019-07-18 13:01:22 +02:00
jD91mZM2 a8280e8991 Implement wcstol, wcstod, and printf:ing wchars 2019-07-18 12:29:22 +02:00
jD91mZM2 7c99077248 Implement wcstok 2019-07-18 08:15:40 +02:00
jD91mZM2 a2c8cfb4a5 Implement CVec, an abstraction to return vectors from Rust 2019-07-18 06:40:23 +02:00
jD91mZM2 c85145b5d1 Merge branch 'memoffset-update' into 'master'
Update memoffset to fix soundness issues

See merge request redox-os/relibc!232
2019-07-13 08:57:18 +00:00
Mateusz Mikuła 87bcc943e2 Update memoffset to fix soundness issues 2019-07-12 19:43:09 +02:00
jD91mZM2 29b5b989eb Format 2019-07-11 18:20:27 +02:00
jD91mZM2 1a0f72dad8 Fix CI & compatibility with older rust 2019-07-11 18:18:17 +02:00
jD91mZM2 57917c0e92 Fix various floating point issues in printf 2019-07-11 18:09:37 +02:00
Jeremy Soller 4621a824a8 Merge branch 'sigaltstack' into 'master'
Fix sigaltstack

See merge request redox-os/relibc!230
2019-07-10 12:34:24 +00:00
Mateusz Mikuła 799c10073d Fix sigaltstack 2019-07-10 14:01:43 +02:00
jD91mZM2 a6d6d2cfb0 Merge branch 'cbindgen-update' into 'master'
Cbindgen update

See merge request redox-os/relibc!229
2019-07-10 10:08:39 +00:00
Mateusz Mikuła 63a1319e50 Cbindgen update 2019-07-10 10:08:39 +00:00
Jeremy Soller 05f71567ab Format 2019-07-06 19:37:13 -06:00
Jeremy Soller 6a97b47d3f Do not expect unistd/isatty 2019-07-06 19:32:01 -06:00
Jeremy Soller 84745ca770 Fix fsync on Redox 2019-07-06 19:27:42 -06:00
Jeremy Soller 7b406dbc61 Improve test output 2019-07-06 19:25:16 -06:00
Jeremy Soller 06bab2aa81 Fix Redox fchdir 2019-07-06 19:25:05 -06:00
Jeremy Soller 27d97f6fe0 Use O_DIRECTORY in unistd/fchdir 2019-07-06 19:21:11 -06:00
Jeremy Soller 2c3195d54b Ignore clock function in time/time 2019-07-06 19:09:24 -06:00
Jeremy Soller 634b2ed835 Use actual break in unistd/brk 2019-07-06 19:09:16 -06:00
Jeremy Soller e27b22f63c Do not test sys_epoll by default 2019-07-06 19:02:35 -06:00
Jeremy Soller eae28f6dd9 Fix scandir test on Redox 2019-07-06 18:39:41 -06:00
Jeremy Soller 5c0b37a229 Run verify script on Redox 2019-07-06 17:31:52 -06:00
Jeremy Soller a49badbb66 Build tests for redox 2019-07-06 12:57:13 -06:00
Jeremy Soller e146cb3687 Allow multiple definitions 2019-07-06 12:48:58 -06:00
Jeremy Soller 6448119fbc Update pthreads-emb 2019-07-06 11:32:34 -06:00
jD91mZM2 8656c80614 Merge branch 'sigaltstack' into 'master'
Add sigaltstack

See merge request redox-os/relibc!218
2019-07-05 12:29:53 +00:00
Mateusz Mikuła c8887900b9 Add sigaltstack 2019-07-05 12:29:53 +00:00
jD91mZM2 9fb9820b23 Merge branch 'clippy' into 'master'
Clippy fixes

See merge request redox-os/relibc!223
2019-07-04 14:47:08 +00:00
Mateusz Mikuła 6742e41948 Clippy fixes 2019-07-04 14:47:08 +00:00
Jeremy Soller 38099fe3d9 Fix definition of errno to match what is used by musl 2019-07-03 19:47:55 -06:00
Jeremy Soller 208b56b487 Revert "Allow multiple definition in ld_so to avoid linking issues"
This reverts commit b4c738eb62.
2019-07-01 16:52:19 -06:00
Jeremy Soller b4c738eb62 Allow multiple definition in ld_so to avoid linking issues 2019-07-01 16:44:07 -06:00
Jeremy Soller 456c829da8 Fix CI 2019-07-01 16:37:47 -06:00
Jeremy Soller 50be35d152 Update cbindgen 2019-07-01 16:36:41 -06:00
jD91mZM2 dc2d22b384 Merge branch 'thread_local' into 'master'
Make errno thread local

See merge request redox-os/relibc!228
2019-07-01 18:36:34 +00:00
jD91mZM2 3ae46d8616 Merge branch 'expected_alloc_test' into 'master'
Move alloc tests to expected-output tests

See merge request redox-os/relibc!226
2019-07-01 18:35:56 +00:00
Peter Limkilde Svendsen 70857f9980 Move alloc tests to expected-output tests 2019-07-01 18:35:56 +00:00
Mateusz Mikuła ff94798253 Make errno thread local 2019-07-01 16:51:19 +02:00
jD91mZM2 bf13674e11 Merge branch 'getpagesize_check' into 'master'
Use try_from in getpagesize(), add test

See merge request redox-os/relibc!225
2019-07-01 11:03:58 +00:00
jD91mZM2 3be933ec63 Merge branch 'alloc_cleanup' into 'master'
Alloc functions cleanup

See merge request redox-os/relibc!224
2019-07-01 11:02:10 +00:00
Peter Limkilde Svendsen 02e26006e7 Alloc functions cleanup 2019-07-01 11:02:10 +00:00
jD91mZM2 b43e1bf83b Merge branch 'l64a' into 'master'
Implement l64a()

See merge request redox-os/relibc!227
2019-07-01 10:59:37 +00:00
Peter Limkilde Svendsen 6cc5216c9c Implement l64a() 2019-07-01 10:59:37 +00:00
jD91mZM2 e35f22b3df WIP: pthread_atfork
WIP mainly because we *should* use thread locals, but #[thread_local]
causes segfaults.
2019-07-01 09:07:11 +02:00
jD91mZM2 f9dca89c1f Merge branch 'cleanup' 2019-07-01 08:39:09 +02:00
Jeremy Soller 6a069d1d9e Add static TLS init on Linux 2019-06-30 21:31:57 -06:00
Jeremy Soller 2a68c68dc6 Use the same Stack struct for ld_so start as for relibc start 2019-06-30 21:31:31 -06:00
Jeremy Soller a72c5f4aca Add static tls test 2019-06-30 21:30:34 -06:00
jD91mZM2 6203a85713 Fix thread-locals 2019-06-27 08:25:08 +02:00
jD91mZM2 ec7abebc0b Fix a very slight error in the mutex
This was just my attempt at being smart, I didn't realize
`compare_exchange` returned the old value (I'm dumb!), so I thought
that if the value was 1 then it must have become 2. Normally with
small errors like these you should leave a comment explaining why, but
really, compare and *exchange* is pretty obvious. My bad.
2019-06-27 07:29:30 +02:00
jD91mZM2 d704a35b85 Untested: Remove duplicate Mutex efforts in pte.rs
See #151
2019-06-27 07:29:30 +02:00
jD91mZM2 2f4e57f87a Fix data race inside puts(...) & add dbg!() macro 2019-06-26 21:21:32 +02:00
jD91mZM2 e929538098 Uncomment pthread_atfork stub to get ion to build 2019-06-16 14:59:04 +02:00
Peter Limkilde Svendsen 8b975877e6 Formatting 2019-06-14 00:07:36 +02:00
Peter Limkilde Svendsen 3b06380738 Add test for getpagesize() 2019-06-14 00:06:11 +02:00
jD91mZM2 651d38300a Merge branch 'master' into 'master'
Use cbitset crate instead of custom bitset implementation in select

See merge request redox-os/relibc!221
2019-06-13 12:31:30 +00:00
lmiskiew 43f1b582ae Use cbitset crate instead of custom bitset implementation in select 2019-06-13 12:31:30 +00:00
Peter Limkilde Svendsen 6e88617762 Use fallible conversion in getpagesize() 2019-06-12 23:47:11 +02:00
jD91mZM2 e84ea94dd0 Execute fmt.sh 2019-06-12 14:45:33 +02:00
jD91mZM2 c29237d360 Revert "Regenerate test output after !220"
Well I'm dumb... This test was already ran in a way that wasn't
verifying output, because this test outputs things that can
differ. Excuse me for not noticing!

This reverts commit 0af78b1e06.
2019-06-12 14:42:38 +02:00
jD91mZM2 0af78b1e06 Regenerate test output after !220 2019-06-12 11:45:06 +02:00
jD91mZM2 8db2f51706 Merge branch 'assert_fail' into 'master'
Rename __assert to __assert_fail

See merge request redox-os/relibc!212
2019-06-12 09:33:59 +00:00
jD91mZM2 d9ed51b9f1 Merge branch 'lcg48_arr' into 'master'
Implement remaining LCG functions

See merge request redox-os/relibc!219
2019-06-12 09:31:18 +00:00
jD91mZM2 3013c5db50 Merge branch 'posix_memalign' into 'master'
Implement posix_memalign()

See merge request redox-os/relibc!220
2019-06-12 09:27:48 +00:00
jD91mZM2 de70b2ae98 Merge branch 'master' into 'master'
Fix out-of-bounds error in strsignal

See merge request redox-os/relibc!222
2019-06-12 09:18:09 +00:00
Jason Hansel a5409ecd36 Fix out-of-bounds error in strsignal 2019-06-10 10:25:59 -04:00
Peter Limkilde Svendsen 626c713021 Formatting 2019-05-30 18:35:16 +02:00
Peter Limkilde Svendsen 02d1a7fe6f Implement posix_memalign 2019-05-30 18:28:15 +02:00
Peter Limkilde Svendsen 7a48107080 Run fmt 2019-05-23 21:48:43 +02:00
Peter Limkilde Svendsen dcff3fd836 Use y_from_x naming for functions 2019-05-23 21:40:06 +02:00
Peter Limkilde Svendsen fe4a3ae2b4 Refactor for consistency 2019-05-23 21:33:20 +02:00
Peter Limkilde Svendsen b2a9cdf930 Implement lcong48() and seed48() 2019-05-23 20:36:13 +02:00
Peter Limkilde Svendsen 767cf86b38 Refer to newer standard (with correct half-open output intervals) 2019-05-22 21:09:26 +02:00
Peter Limkilde Svendsen 13108776ae Implement erand48(), jrand48() and nrand48() 2019-05-22 18:48:19 +02:00
jD91mZM2 dab6530fb4 Merge branch 'valloc_pagesize' into 'master'
Make valloc() get page size through sysconf(), add tests

See merge request redox-os/relibc!216
2019-05-12 14:52:56 +00:00
jD91mZM2 f1b88d9ea0 Merge branch 'lcg48' into 'master'
Implement LCG pseudorandom number functions

See merge request redox-os/relibc!213
2019-05-12 14:50:18 +00:00
Peter Limkilde Svendsen 45860e9256 Implement LCG pseudorandom number functions 2019-05-12 14:50:18 +00:00
jD91mZM2 06ab5b7de2 Merge branch 'memrchr' into 'master'
Add memrchr()

See merge request redox-os/relibc!214
2019-05-12 14:13:22 +00:00
jD91mZM2 f3363af54d Merge branch 'housekeeping' into 'master'
Spring cleanup

See merge request redox-os/relibc!217
2019-05-12 14:11:24 +00:00
Mateusz Mikuła 5dd9c042d6 Update rust-toolchain 2019-05-11 22:34:14 +02:00
Mateusz Mikuła 7597c082e7 Fix Clippy warnings 2019-05-11 22:34:13 +02:00
Jeremy Soller 20a2355bc4 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2019-05-11 10:05:45 -06:00
Jeremy Soller 2606266c3f If the prefix is recompiled, clzsi2 does not have to be removed. 2019-05-11 10:05:38 -06:00
Mateusz Mikuła 21a6701528 Rename __assert to __assert_fail
This makes relibc more compatible with other libc implementations
2019-05-11 13:50:36 +02:00
Mateusz Mikuła d62db7b1b9 Add memrchr() 2019-05-11 13:49:46 +02:00
Mateusz Mikuła 30f6a9c323 Cargo fmt 2019-05-11 13:48:03 +02:00
Peter Limkilde Svendsen f8cf25d76c Fix inaccurate comment 2019-05-11 11:44:36 +02:00
jD91mZM2 15aa52a8e9 Fix the CI; Disregard last commit
The race condition didn't trigger when I tested it, so I assumed I had
solved it...
2019-05-11 08:55:11 +02:00
jD91mZM2 123031dcfe Fix race condition in parallel Makefile
Some recipes require the headers, but they don't explicitly say
so. Parallel make (-j`nproc`) might start compiling the libs when the
headers aren't done yet.
2019-05-11 08:04:03 +02:00
Peter Limkilde Svendsen 54c5423f35 Avoid call to memalign() 2019-05-09 23:40:12 +02:00
Peter Limkilde Svendsen 8beb10b1bd Get page size through sysconf() 2019-05-08 23:20:30 +02:00
Peter Limkilde Svendsen f13bd7fdd1 Add tests for valloc 2019-05-08 22:08:13 +02:00
jD91mZM2 3be13d672f Fix the GitLab CI for Redox OS (finally!) 2019-05-08 17:14:10 +02:00
Jeremy Soller cfc541019c Add socketpair on Linux with stub on Redox 2019-04-28 19:12:54 -06:00
Jeremy Soller 75cb7033c7 Fix use of timeout in epoll_pwait on redox 2019-04-28 13:33:17 -06:00
Jeremy Soller d2cb0959f3 Fix redox epoll timeout 2019-04-28 13:10:34 -06:00
Jeremy Soller 6a9d070115 Fix time path, use c_str macro 2019-04-28 12:56:00 -06:00
Jeremy Soller 61dea7f52b Add all 3 epoll_ctl ops 2019-04-28 11:30:14 -06:00
Jeremy Soller 16083a6020 Remove epoll_ctl debug message 2019-04-28 11:27:52 -06:00
Jeremy Soller 8efa7a3ed8 Fixes for epoll on Redox 2019-04-28 11:27:01 -06:00
Jeremy Soller 3a5a7b3378 Support for native relibc compilation of tests 2019-04-28 11:00:27 -06:00
Jeremy Soller d6d01e5614 Allow custom sysroot to be specified 2019-04-28 10:49:44 -06:00
Jeremy Soller e6e31dd3b4 Format 2019-04-28 10:29:20 -06:00
Jeremy Soller f8fe67e7ba Merge remote-tracking branch 'origin/epoll' 2019-04-28 10:28:27 -06:00
Jeremy Soller 10fdea88f2 Bring in changes that were accidently lost 2019-04-28 10:26:10 -06:00
Jeremy Soller 54fb8b9b2b Fix select on regular files 2019-04-28 10:07:42 -06:00
Jeremy Soller ba711deb0d Convert select example to use pipes 2019-04-28 09:27:07 -06:00
Jeremy Soller 378ea3ac0e signal test is no longer expected 2019-04-28 09:14:05 -06:00
Jeremy Soller b399e87ef8 Add epoll test 2019-04-28 09:13:47 -06:00
Jeremy Soller dd9328bd41 Add pipe2 2019-04-28 09:13:24 -06:00
Jeremy Soller 68c4e95b6d Merge branch 'epoll' 2019-04-28 09:10:52 -06:00
Jeremy Soller c9a8674c61 Update pthreads-emb 2019-04-28 07:50:04 -06:00
Jeremy Soller 89b4fa80af Merge branch 'jD91mZM2/epoll' into 'epoll'
Add completely untested redox epoll implementation

See merge request redox-os/relibc!211
2019-04-28 13:18:50 +00:00
jD91mZM2 4c8f51ace9 Avoid allocations in redox epoll 2019-04-28 14:51:42 +02:00
Jeremy Soller be765f879d Merge branch 'master' into 'master'
Implement rand_r(), strnlen_s(), tempnam(), tmpnam()

See merge request redox-os/relibc!210
2019-04-28 12:18:50 +00:00
jD91mZM2 488981f9ec Add completely untested redox epoll implementation 2019-04-28 08:20:49 +02:00
Jeremy Soller 6d857f8db7 C flavored Rust doesn't taste good 2019-04-27 20:23:32 -06:00
Jeremy Soller 125e0e08da Add timegm 2019-04-27 19:58:41 -06:00
Jeremy Soller 5a34907033 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2019-04-27 19:57:35 -06:00
Alex Lyon 68d3c5f1b1 Format code 2019-04-26 20:40:22 -07:00
Alex Lyon 3584edf199 stdio: implement tempnam() and tmpnam() 2019-04-26 20:39:03 -07:00
Alex Lyon 5bbce37789 string: add strnlen_s() 2019-04-26 20:36:37 -07:00
Alex Lyon 67af78d0eb stdlib: make rand()/rand_r() generate from [0, RAND_MAX] 2019-04-26 13:13:25 -07:00
Alex Lyon 13a10ce7af stdlib: implement rand_r() using XorShiftRng 2019-04-25 19:35:32 -07:00
Jeremy Soller 6a16275817 Fix warning, format makefile, and update depends 2019-04-24 19:50:57 -06:00
Jeremy Soller 6074616857 Merge branch 'strerror_r' into 'master'
Handle zero len for strerror_r

See merge request redox-os/relibc!209
2019-04-24 17:19:40 +00:00
Mateusz Mikuła 1ebd8a3d72 Handle zero length for strerror_r 2019-04-24 17:42:28 +02:00
jD91mZM2 87ba8f8a08 Merge branch '140-bufferedvalist-index-may-read-out-of-bounds' into 'master'
Resolve "BufferedVaList::index may read out of bounds"

Closes #140

See merge request redox-os/relibc!208
2019-04-23 18:36:00 +00:00
jD91mZM2 8fca7bcbc1 More printf tests and corner cases 2019-04-23 08:15:58 +02:00
jD91mZM2 0a0aec502b Fix #140 2019-04-23 07:34:06 +02:00
jD91mZM2 40d01d9d57 Convert printf internals to iterator 2019-04-22 16:25:29 +02:00
jD91mZM2 c2c8806f04 Merge branch 'malloc_errno' into 'master'
Set errno in alloc functions and add further tests

See merge request redox-os/relibc!205
2019-04-22 11:16:13 +00:00
Peter Limkilde Svendsen 912385b501 Set errno in alloc functions and add further tests 2019-04-22 11:16:13 +00:00
Jeremy Soller 7bde036031 Remove va_list submodule, format 2019-04-21 15:45:55 -06:00
Jeremy Soller b2cc25dd38 Fix missing import 2019-04-21 15:28:19 -06:00
jD91mZM2 6d4ac9dba8 Finally, get rid of all rust warnings
Just a small step along the way to reduce the massive wall of spam
every time you compile.

This was done partly automagically with `cargo fix`. The rest was me
deleting or commenting out a bunch of variables. Hope nothing was
important...
2019-04-21 21:12:16 +02:00
jD91mZM2 3a3fd3da39 Use the memchr crate
https://github.com/BurntSushi/rust-memchr is supposed to be a whole
lot faster :)
2019-04-21 19:09:37 +02:00
Dan Robertson fa94f1b6d5 Use core::ffi::VaList 2019-04-21 17:46:22 +02:00
jD91mZM2 29e1c780aa Comment out or fix 2 failing tests 2019-04-21 17:46:22 +02:00
jD91mZM2 601cb43f6c Merge branch 'strerror_r' into 'master'
Add POSIX strerror_r

See merge request redox-os/relibc!207
2019-04-21 15:06:17 +00:00
jD91mZM2 78d52c6e9f Merge branch 'whiletofor' into 'master'
Changed while loops to for

See merge request redox-os/relibc!206
2019-04-21 15:04:10 +00:00
Jeremy Soller 83f89912e0 Do not copy kernel-allocated TLS 2019-04-20 10:36:18 -06:00
Mateusz Mikuła c68a0d5678 Add POSIX strerror_r 2019-04-19 17:59:56 +02:00
Michal Z 89ca696f8e Changed while loops to for
Changed while loops to for - https://gitlab.redox-os.org/redox-os/relibc/issues/128
2019-04-15 18:24:46 +02:00
Jeremy Soller b9e03cbaed Implement __tls_get_addr 2019-04-14 19:09:10 -06:00
Jeremy Soller 30aef27c76 Correctly set up TLS on Redox and other fixes for pthread_clone 2019-04-14 19:08:58 -06:00
Jeremy Soller 7fe0beb916 Add DTPMOD64 2019-04-14 13:21:07 -06:00
Jeremy Soller 5a005864a8 Fix compilation on redox 2019-04-14 13:18:57 -06:00
Jeremy Soller 361f32b63c ld_so: significant refactor to prepare for pthread_create support of TLS 2019-04-14 13:17:07 -06:00
Jeremy Soller 9f5e5f24dc Correctly set tcb pointer to the end of TLS 2019-04-14 10:44:25 -06:00
Jeremy Soller 47baf499bf Fix TLS offsets 2019-04-14 08:40:03 -06:00
Jeremy Soller cb9e779ca1 Install ld_so 2019-04-13 21:39:08 -06:00
Jeremy Soller b2cc8f6d26 Fix compilation on Redox 2019-04-13 21:32:51 -06:00
Jeremy Soller 27cebdd688 Build librelibc without incremental support, gc-sections for ld.so 2019-04-13 21:15:38 -06:00
Jeremy Soller ba50c94c3f Improve TLS support 2019-04-13 21:15:01 -06:00
Jeremy Soller 63cb2f3454 ld.so: Add auxv support, get ld_library_path from env 2019-04-13 21:14:52 -06:00
Jeremy Soller 084b69b361 Add ld_so executable 2019-04-13 12:17:38 -06:00
Jeremy Soller d5eb1e2732 Add dl-tls.h, required for shared libraries 2019-04-12 09:30:02 -06:00
Jeremy Soller d9ec8b4ab0 Do not link to standard libraries when making libc.so... 2019-04-11 21:02:01 -06:00
Jeremy Soller 2b56f2882b Add libc.so, remove compiler_builtins 2019-04-11 21:00:39 -06:00
Jeremy Soller e5529dc883 Update pthreads-emb 2019-04-11 20:31:11 -06:00
Jeremy Soller cf800b5282 Add shared object for openlibm and pthreads-emb 2019-04-11 20:10:08 -06:00
Jeremy Soller 2fdca9bd0a Work around definition of O_NOFOLLOW, and add target for only building and installing headers 2019-04-07 10:11:05 -06:00
Jeremy Soller f4fccc6d19 Update rust 2019-04-07 08:47:51 -06:00
Jeremy Soller 73dda0f32c Add missing cast 2019-04-06 21:38:59 -06:00
Jeremy Soller f2b86e985c Ensure that getpeername and getsockname return a sockaddr of family AF_INET 2019-04-06 21:34:56 -06:00
Jeremy Soller 588f032f75 Rename can be done with O_PATH 2019-04-06 20:47:20 -06:00
Jeremy Soller 54b6c8f025 Update pthreads-emb 2019-04-04 19:59:06 -06:00
Jeremy Soller 862c76b25f Correct error for unknown protocol type in socket 2019-04-01 20:35:15 -06:00
Jeremy Soller f4c036c3aa Fix returning incorrect ai_socktype from getaddrinfo 2019-04-01 20:34:53 -06:00
Jeremy Soller 42d40da973 Map stacks based on provided size. 2019-03-31 15:04:37 -06:00
Jeremy Soller 17372b4f69 Fix thread starting before pte_osThreadStart 2019-03-30 16:18:07 -06:00
jD91mZM2 3f98962054 Fix bug in scanf where EOF would be ignored 2019-03-28 17:57:13 +01:00
Jeremy Soller 6548aad36d Use next_byte function in all places in scanf 2019-03-27 21:32:02 -06:00
Jeremy Soller d13fb3f42b Fix panic in sigaction 2019-03-27 21:31:18 -06:00
Jeremy Soller bee72373be Fix panic not producing output 2019-03-27 21:28:39 -06:00
Jeremy Soller 5dca9843dc Fix use of trace macro when errno is imported 2019-03-27 20:57:12 -06:00
Jeremy Soller 65aeda1f59 Use AF_INET6 instead of PF_INET6 in test 2019-03-27 20:56:59 -06:00
Jeremy Soller a88ec09131 Prevent override of panic from relibc 2019-03-27 20:56:23 -06:00
Jeremy Soller 229ca66726 Merge branch 'usleep' into 'master'
Fix usleep

Closes #144

See merge request redox-os/relibc!204
2019-03-25 13:06:46 +00:00
Mateusz Mikuła e01d1ce11b Fix usleep 2019-03-25 13:36:48 +01:00
Jeremy Soller 7a1e2a6269 Merge branch 'new-toolchain' into 'master'
Support use of new cross compiler

See merge request redox-os/relibc!203
2019-03-17 02:28:01 +00:00
Jeremy Soller 0e667c5f25 Remove .travis.yml 2019-03-16 20:20:43 -06:00
Jeremy Soller 6f12bb6a32 Install tar before attempting to use it 2019-03-16 20:18:34 -06:00
Jeremy Soller 59653ee290 Support use of new cross compiler 2019-03-16 20:16:00 -06:00
Jeremy Soller cee4449f7c Replace make calls with MAKE variable 2019-03-16 18:54:11 -06:00
Jeremy Soller 5715fb7ba6 Work on switching to epoll as backend for select and poll 2019-03-10 13:03:00 -06:00
Jeremy Soller cdbeda1ca0 Merge branch 'patch-2' into 'master'
Fix conditional compilation of sys/mman.h

See merge request redox-os/relibc!201
2019-03-05 02:08:01 +00:00
jD91mZM2 640c6d41a7 Merge branch 'aarch64-prep' into 'master'
Aarch64 prep redux

See merge request redox-os/relibc!202
2019-03-04 09:48:26 +00:00
Robin Randhawa 9443eef518 Add wint_t definition to stddef.h
Without this the relibc tests would break. With this the relibc tests
pass and formerly breaking builds (such as uutils -> onig_sys) pass.
2019-03-03 21:50:13 +00:00
Robin Randhawa 23de2ca7ca Remove redundant wchar_t and win_t definitions
Typically with libc implementations, wchar_t and co are either defined
entirely by the libc or, under libc's arrangement, by headers supplied
by the compiler.

Things like dlmalloc in relibc need these definitions from relibc itself
and that's already already furnished by relibc's stddef.h.

These additional definitions here are redundant and collide with
compiler headers - for example: onig_sys (something that uutils depends
on) breaks. Instead, this patch makes the compiler headers define
things appropriately.
2019-03-03 21:50:04 +00:00
Robin Randhawa f9f752d74c aarch64-prep: Dummy auxv.h
For AArch64, the ring crate depends on the presence of this header and a definition
of getauxval.
2019-03-03 21:49:52 +00:00
Robin Randhawa 17bed54103 aarch64: Fix incorrect init/fini stack manipulation
The pre-index operator ('!') was missing at the end of the stp
instruction.

As a result, the stack pointer wasn't updated after the
store of the 64-bit pair and the stored values were basically lost when
follow on code used the stack for later store ops.
2019-03-03 21:49:46 +00:00
Angelo Bulfone 31fc29e70c Fix conditional compilation of sys/mman.h 2019-03-03 21:14:45 +00:00
jD91mZM2 269b8a1d3e Merge branch 'cleanup' into 'master'
tests: Macro based error handling

See merge request redox-os/relibc!195
2019-03-03 15:19:19 +00:00
jD91mZM2 37c976945a Merge branch 'implement-swab' into 'master'
Implement swab

See merge request redox-os/relibc!187
2019-02-28 08:23:11 +00:00
lmiskiew 5eb2a8f7bd Implement swab 2019-02-28 08:23:11 +00:00
jD91mZM2 30a0f70d73 Merge branch 'wcsrchr' into 'master'
implements wcsrchr from wchar.h

See merge request redox-os/relibc!197
2019-02-28 08:21:55 +00:00
jD91mZM2 fe905ed13c Merge branch 'calloc_overflow_check' into 'master'
add calloc integer overflow check

See merge request redox-os/relibc!188
2019-02-28 08:20:11 +00:00
jD91mZM2 71f8fb32e3 Merge branch 'patch-1' into 'master'
Change LONG_BIT definition, fixes #148

Closes #148

See merge request redox-os/relibc!198
2019-02-28 08:18:29 +00:00
Paul Sajna e93129b165 Change LONG_BIT definition, fixes #148 2019-02-28 07:42:19 +00:00
emturner 4ed6dca61d implements wcsrchr from wchar.h 2019-02-25 22:53:11 +00:00
Tibor Nagy fa2c6d29db tests: Rewrite libgen tests based on ctype (nice table layout), fix error handling of sleep tests 2019-02-25 19:32:20 +01:00
Tibor Nagy efd6947d8e tests: Fix function-like macros
Turns the results of these macros from compound to regular statements using the old `do { ... } while(0)` trick. Must have for function-like macros.
2019-02-25 14:13:02 +01:00
Tibor Nagy 96182ce8ad tests: Fix expected outputs 2019-02-24 22:19:07 +01:00
Tibor Nagy a92be000fb tests: Even more work on error handling
realpath: Fixing undefined behaviour in the second test. If the call fails the resolved_name argument cannot be used for error checking because its state is undefined by SUSv2.
pipe: Changing the order of close and write error handling code. Errors in close could overwrite errno after write errors, returning incorrect error messages.
gmtime: Removed duplicate checks
Other fixes for fseek, rename, mktime, putwchar
2019-02-24 22:02:11 +01:00
Tibor Nagy 2d027f0771 tests: More work on error handling 2019-02-24 00:46:26 +01:00
Jeremy Soller 76503d8943 Add epoll constants 2019-02-23 08:39:06 -07:00
Jeremy Soller f3ba7e8d8e Merge branch 'wcscspn' into 'master'
Implements wcscspn function from wchar.h

See merge request redox-os/relibc!196
2019-02-23 00:33:11 +00:00
emturner ec3488c7b0 implements wcscspn from wchar.h 2019-02-22 23:18:21 +00:00
Tibor Nagy 0c539d6e4e tests: Fix expected outputs 2019-02-22 13:28:18 +01:00
Tibor Nagy 513f4ba53c tests: Documentation for test_helpers.h, more refactoring 2019-02-22 13:19:38 +01:00
Jeremy Soller 887d89c2bb Add epoll (WIP) 2019-02-21 20:40:03 -07:00
Jeremy Soller 74d0b24939 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2019-02-21 19:43:07 -07:00
Jeremy Soller 5690c6dcdf Add trace for select and poll 2019-02-21 19:42:58 -07:00
Tibor Nagy 9a0ea6ff34 tests: More refactoring, add helper header to every test, override exit for better error reporting 2019-02-21 21:13:28 +01:00
Tibor Nagy 6266d29242 tests: Fix expected outputs 2019-02-21 17:46:18 +01:00
Tibor Nagy 64acf45c40 tests: Add helper macros for easier error handling and reporting 2019-02-21 17:35:24 +01:00
Tibor Nagy f60c95d2ca tests: Work on more thorough error handling 2019-02-21 16:15:49 +01:00
Tibor Nagy d1a424c002 tests: Replace returns with exits in the main functions
This will allow us to redefine the exit function.

For example:
```
#define exit(code) { \
    fprintf(stderr, "%s:%d: exit(%s) in function ‘%s’\n",
        __FILE__, __LINE__, #code, __func__); \
    _exit(code); \
}
```
2019-02-21 12:15:06 +01:00
Jeremy Soller f19e029468 Merge branch 'cleanup' into 'master'
General test cleanups

See merge request redox-os/relibc!193
2019-02-20 22:34:52 +00:00
Jeremy Soller 20aeb15fc7 Merge branch 'path-separator' into 'master'
unistd: Generate correct C defines for PATH_SEPARATOR

See merge request redox-os/relibc!194
2019-02-20 22:32:13 +00:00
Tibor Nagy 27a3f2ab77 unistd: Generate correct C defines for PATH_SEPARATOR 2019-02-20 22:11:25 +01:00
Tibor Nagy 4381bb2a22 tests: Remove redundant return statements
When the execution reaches the end of the main functions, they implicitly return a successful status.
2019-02-20 21:09:03 +01:00
Tibor Nagy c19cc8b731 tests: Portability fixes, replaced 0/1/-1 return codes with macros 2019-02-20 20:20:07 +01:00
Tibor Nagy ff874c87d7 tests: Fix function signatures 2019-02-20 19:27:18 +01:00
Jeremy Soller 97592716fb Merge branch 'pedantic' into 'master'
tests: set C11, enable pedantic warnings, fix GCC and Clang warnings

See merge request redox-os/relibc!192
2019-02-20 16:01:50 +00:00
Tibor Nagy 7ee59d2fdb tests: set C11, enable pedantic warnings, fix GCC and Clang warnings 2019-02-20 15:04:47 +01:00
Jeremy Soller 1af4eb7ec0 Merge branch 'ctype' into 'master'
ctype: Implement _tolower, _toupper

See merge request redox-os/relibc!191
2019-02-20 13:19:36 +00:00
Tibor Nagy d38a1d0da3 ctype: Implement _tolower, _toupper 2019-02-20 11:49:06 +01:00
Jeremy Soller 73c368ddab Use correct open flags 2019-02-19 19:29:19 -07:00
Jeremy Soller 264659b634 Merge branch 'ctype' into 'master'
ctype: Add tests for toascii, tolower, toupper

See merge request redox-os/relibc!190
2019-02-19 21:59:14 +00:00
Tibor Nagy 1eb22b2cb2 ctype: Add tests for toascii, tolower, toupper 2019-02-19 20:54:05 +01:00
Jeremy Soller 514b31cf28 Merge branch 'ctype' into 'master'
ctype: Fix iscntrl, isgraph, ispunct, make tests exhaustive

See merge request redox-os/relibc!189
2019-02-19 19:09:27 +00:00
Tibor Nagy 5fac72298f ctype: Fix iscntrl, isgraph, ispunct, make tests exhaustive
iscntrl: Didn't handle the EOF macro correctly
isgraph: Didn't handle '~' (tilde) correctly
ispunct: Several issues
2019-02-19 19:53:54 +01:00
Jeremy Soller 38da5552e8 getaddrinfo: support for setting port from service argument (numeric only) 2019-02-02 14:20:26 -07:00
Peter Limkilde Svendsen 7aa0fbdf93 Include stdint.h in test 2019-02-02 16:51:38 +01:00
Peter Limkilde Svendsen 8b7453edf2 Add test of calloc with overflow 2019-02-02 16:41:09 +01:00
Peter Limkilde Svendsen c54db6f008 Add integer overflow check to calloc 2019-02-02 15:52:39 +01:00
Jeremy Soller d2502056a8 Cleanup termios and ioctls and add tcflush 2019-01-27 19:19:50 -07:00
Jeremy Soller 602f015e93 Implement fpathconf and pathconf 2019-01-27 18:53:57 -07:00
Jeremy Soller 0dd801da03 Implement ttyname by adding fpath function to Sys. Remove realpath function and use fpath internally 2019-01-27 17:10:55 -07:00
Jeremy Soller 42f212e678 Verify current system before continuing. 2019-01-27 15:53:09 -07:00
Jeremy Soller 47235d44e7 Fix change of sockaddr member sa_data on Redox 2019-01-21 20:38:31 -07:00
Jeremy Soller c59f268fcd Implement getaddrinfo (somewhat) 2019-01-21 20:36:56 -07:00
Jeremy Soller f3c858c151 Build includes in parallel 2019-01-20 20:17:04 -07:00
Jeremy Soller f25c494a73 Show hint information 2019-01-20 20:12:58 -07:00
Jeremy Soller 0f50a40b3f Update redox_syscall 2019-01-20 19:38:38 -07:00
Jeremy Soller aa3c7da128 Switch to using syscall-instruction 2019-01-20 09:46:21 -07:00
Jeremy Soller eaa031c21c Fix ioctl on redox 2019-01-18 15:39:49 -07:00
Jeremy Soller a88933386b Implement termios functions using ioctl 2019-01-17 20:46:12 -07:00
Jeremy Soller 047deceed0 Move hostent functions to separate file 2019-01-17 20:45:25 -07:00
Jeremy Soller d0261ebb35 Move db to crate root 2019-01-17 19:56:51 -07:00
Jeremy Soller 09340bd0f2 Add setpgrp 2019-01-15 21:14:55 -07:00
Jeremy Soller 22ca2e5f7b Export group struct 2019-01-15 21:08:08 -07:00
Jeremy Soller 1a0d363caa Redox support for some minimal ioctl's 2019-01-15 20:50:17 -07:00
Jeremy Soller 74dd5091f3 Add empty netinet_ip 2019-01-15 20:49:35 -07:00
Jeremy Soller b35a4f6372 Add in_systm.h 2019-01-15 20:49:15 -07:00
Jeremy Soller c71088e768 Cleanup and format 2019-01-14 21:07:24 -07:00
Jeremy Soller 8dabff129a Begin work on getnameinfo 2019-01-14 19:26:35 -07:00
Jeremy Soller c57ac53d28 Reduce warnings 2019-01-14 19:26:18 -07:00
Jeremy Soller b3dda7519d Update openlibm 2019-01-14 14:22:24 -07:00
Jeremy Soller 2e260a6b29 Add _SC_PAGE_SIZE, use sysconf to provide getpagesize 2019-01-13 19:48:06 -07:00
Jeremy Soller f35f65c2b8 Update pthreads-emb 2019-01-13 17:00:39 -07:00
Jeremy Soller 594e53c6f1 addrinfo stub 2019-01-13 14:37:20 -07:00
Jeremy Soller 87f2ab95bb Fix redox compilation 2019-01-13 14:36:35 -07:00
Jeremy Soller 8e9d65cb46 Add support for pthreads to Linux 2019-01-13 14:17:29 -07:00
Jeremy Soller 52669688bf Fix issue of strcasecmp not showing up 2019-01-13 14:17:05 -07:00
Jeremy Soller 434cad49ce Add sysconf 2019-01-13 14:16:51 -07:00
Jeremy Soller 5b969f2bae Add pthread_sigmask 2019-01-13 10:56:09 -07:00
Jeremy Soller 89fca557f3 Remove old pthread module 2019-01-13 10:56:00 -07:00
Jeremy Soller 6c0c6dd71b Fix missing negative flags in netdb.h, add NI_MAXHOST and NI_MAXSERV 2019-01-13 10:34:17 -07:00
Jeremy Soller 018ff409f1 Add gai_strerror 2019-01-13 10:24:30 -07:00
Jeremy Soller 543f32eb50 Add nameinfo defines 2019-01-13 10:24:17 -07:00
Jeremy Soller 97312c9ae2 Fix addrinfo structure 2019-01-13 10:13:25 -07:00
Jeremy Soller 84fcb1b906 Add addrinfo constants 2019-01-13 09:58:03 -07:00
Jeremy Soller aa069b3e0b Add netinet/tcp.h 2019-01-13 09:31:25 -07:00
Jeremy Soller cea5101cba Implement shm_ functions and add MAP_FIXED 2019-01-13 09:31:04 -07:00
Jeremy Soller 5b779448ab Add IOV_MAX 2019-01-13 09:30:37 -07:00
Jeremy Soller 33b539e4c1 Fix export of O_ACCMODE 2019-01-13 09:30:27 -07:00
Jeremy Soller 0c5abf0361 Combine all libraries into libc.a, call pthread_init and pthread_terminate in libc 2019-01-07 19:11:30 -07:00
Jeremy Soller aefb4fb116 Improvements for dlfcn 2019-01-06 16:28:22 -07:00
Jeremy Soller c41c20a943 Allow for static CStr 2019-01-06 14:40:01 -07:00
Jeremy Soller dc4aa9cf0b Use typedef for Dl_info 2019-01-06 12:53:43 -07:00
Jeremy Soller 53874213fa Add dladdr 2019-01-06 12:48:36 -07:00
Jeremy Soller 46020f466f Add dlfcn, fixes for glib and gstreamer 2019-01-06 07:30:42 -07:00
Jeremy Soller 9a0c12888f Use better verbiage for iovec 2019-01-05 13:24:02 -07:00
Jeremy Soller 7ac3dfaa49 Implement sys_uio, define sockaddr_storage 2019-01-05 13:10:20 -07:00
Jeremy Soller eef2f4d1f8 Add more netinet/in.h definitions 2019-01-05 12:01:24 -07:00
Jeremy Soller 2ba67f2fe2 Add getlogin stub 2019-01-05 10:12:33 -07:00
Jeremy Soller 961d1304ab Add sigismember 2019-01-05 09:40:08 -07:00
Jeremy Soller bd956e5fe4 Force little endian for reals 2019-01-01 07:35:13 -07:00
Jeremy Soller 775ec444be Add mprotect 2018-12-31 21:04:45 -07:00
Jeremy Soller c514b0b705 Fix semaphore deadlocks 2018-12-30 08:29:57 -07:00
Jeremy Soller c9e48bf141 Use locking in dlmalloc 2018-12-29 20:11:34 -07:00
Jeremy Soller e93ead5a8f Fix double lock in pte 2018-12-29 19:40:21 -07:00
Jeremy Soller 62b83190bf Fix incorrect variable name 2018-12-29 10:03:11 -07:00
Jeremy Soller e7896f6c48 Fix panic in fread 2018-12-29 10:02:36 -07:00
Jeremy Soller 0aaa7264db Fix signal support 2018-12-29 08:20:27 -07:00
Jeremy Soller 083642fb17 Enable getitimer, setitimer, and sigprocmask 2018-12-28 21:47:49 -07:00
Jeremy Soller 5cb92284f2 Update fmap support 2018-12-28 15:46:38 -07:00
Jeremy Soller 51b093b598 Use 4096 as Linux page size for now 2018-12-26 19:57:08 -07:00
Jeremy Soller 7aa789575a Add shutdown, listen, and getpagesize 2018-12-26 19:26:38 -07:00
jD91mZM2 a321545fd0 Merge branch 'aarch64-unknown-redox' into 'master'
aarch64: Fix typo in a jmp_buf preprocessor conditional

See merge request redox-os/relibc!186
2018-12-23 10:52:46 +00:00
Robin Randhawa 0842d6504b aarch64: Fix typo in a jmp_buf preprocessor conditional 2018-12-23 16:04:35 +05:30
Jeremy Soller 09135f5bd1 Merge branch 'netdb-mutable' into 'master'
netdb: Return mutable structs in the getter functions

See merge request redox-os/relibc!185
2018-12-19 21:17:12 +00:00
Tibor Nagy 51245d69e3 netdb: Return mutable structs in the getter functions 2018-12-18 21:13:32 +01:00
Jeremy Soller 42545713a7 Merge branch 'fwrite-division-by-zero' into 'master'
Fix panic in fwrite

See merge request redox-os/relibc!184
2018-12-17 01:37:12 +00:00
lmiskiew 5b6b11cb65 Fix panic in fwrite 2018-12-17 02:01:36 +01:00
Jeremy Soller f04ac7343a Update pthreads-emb 2018-12-14 15:52:03 -07:00
Jeremy Soller a8f3608f3c Fix stdlib div functions, add _Exit 2018-12-14 13:41:22 -07:00
Jeremy Soller 89832b3ac8 Add lldiv 2018-12-14 13:20:56 -07:00
Jeremy Soller e6c866a92d Undefine complex in fenv.h 2018-12-14 12:50:23 -07:00
Jeremy Soller 74af56d71b Add statvfs and strtold 2018-12-14 12:00:21 -07:00
Jeremy Soller 0d2332d368 Add more special redox functions 2018-12-13 15:26:03 -07:00
Jeremy Soller c6d42dd9e3 Use openlibm's fenv.h 2018-12-13 15:25:47 -07:00
Jeremy Soller 4e741f5583 Add redox_fpath function 2018-12-13 14:46:27 -07:00
Jeremy Soller f7b3abc1b6 Add more wchar definitions 2018-12-13 08:11:49 -07:00
Jeremy Soller 1c1da7dfcb Implement more wchar functions 2018-12-12 20:45:17 -07:00
Jeremy Soller df1c7404eb Update pthreads-emb 2018-12-11 21:02:19 -07:00
Jeremy Soller ae115ac6ff Run pre-init array before _init 2018-12-11 21:01:10 -07:00
Jeremy Soller e764fedba5 Remove unnecessary extern C function 2018-12-11 09:17:33 -07:00
Jeremy Soller 4a4e641b23 Update pthreads-emb 2018-12-11 08:02:47 -07:00
Jeremy Soller 756a0d2edc Initialize pthreads if it is linked 2018-12-09 19:59:33 -07:00
Jeremy Soller 1becb8c43a Enable sys/mman 2018-12-09 16:24:23 -07:00
Jeremy Soller f9b836d23e Add more pte functions 2018-12-09 15:28:45 -07:00
Jeremy Soller 90bf583d28 Better patch for missing M_PI constants 2018-12-09 14:43:23 -07:00
Jeremy Soller ee40035c4b Add asprintf 2018-12-09 12:45:04 -07:00
Jeremy Soller 63b079c231 Include alloca.h in stdlib.h 2018-12-09 11:53:41 -07:00
Jeremy Soller be035f8862 Copy pthreads-emb files on install 2018-12-09 11:29:51 -07:00
Jeremy Soller 8aae8e1564 Add PTE
Add sys_timeb header
2018-12-09 11:27:44 -07:00
Jeremy Soller fc9e3923f6 drop DIR pointers again 2018-12-02 21:05:37 -07:00
Jeremy Soller de429a8df6 Fix overflow issues in Redox getdents 2018-12-02 21:04:07 -07:00
Jeremy Soller e8377d259a Mutable argv 2018-12-02 20:14:33 -07:00
Jeremy Soller 925d9f6bbf WIP: fflush all files when null is passed 2018-12-02 16:45:29 -07:00
Jeremy Soller 05f17794e4 Return correct error code from access 2018-12-02 15:26:37 -07:00
Jeremy Soller 7049359c25 Hack around closedir crashing 2018-12-02 14:27:02 -07:00
Jeremy Soller 594bcd75d4 Add closedir to dirent test 2018-12-02 13:20:33 -07:00
Jeremy Soller a39f170ed3 Reenable grp header (for git) 2018-12-02 12:35:38 -07:00
Jeremy Soller 4ced856b39 Fix fseeko not flushing write buffer 2018-12-02 12:04:15 -07:00
Jeremy Soller 62b0b0d508 Add rustcflags to makefile 2018-12-02 10:24:16 -07:00
Jeremy Soller 7dbd57f913 Fix putenv crash 2018-12-02 10:23:17 -07:00
Jeremy Soller fe57754c34 Do not cast usize to isize in strncpy 2018-12-02 08:16:38 -07:00
Jeremy Soller 3075b8b69f Replace gethostname syscall with uname 2018-12-02 08:04:53 -07:00
Jeremy Soller 52fd4d7e83 Clippy fixes 2018-12-02 08:04:53 -07:00
Jeremy Soller 28dab8ece8 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2018-12-01 08:55:05 -07:00
Jeremy Soller 9325183b21 Fix strcat 2018-12-01 08:55:02 -07:00
Jeremy Soller ca75bbc1c9 Merge branch 'isspace' into 'master'
ctype: fix isspace to test all space class characters

See merge request redox-os/relibc!182
2018-11-28 21:09:14 +00:00
Tibor Nagy 8d05067ac7 ctype: fix isspace to test all space class characters 2018-11-28 20:33:02 +01:00
Jeremy Soller d66afa4586 Do not return mutable pointer from strsignal 2018-11-27 20:54:37 -07:00
Jeremy Soller 35bcf93160 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2018-11-27 10:07:47 -07:00
Jeremy Soller 0a44d4543f Override CC for aarch64 redox 2018-11-27 10:07:44 -07:00
Jeremy Soller 950b4526c7 - Disable output of empty header files
- Remove incorrect header styles
- Use export.replace where header style was previously needed
- Check compilation of tests using system gcc
2018-11-26 21:35:02 -07:00
Jeremy Soller 4bb16e01b2 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2018-11-26 20:29:32 -07:00
Jeremy Soller 37cd503c88 Cleanups of redox pal 2018-11-26 20:29:27 -07:00
Jeremy Soller 1a8af993e6 Fix invalid inline ASM 2018-11-26 16:01:20 -07:00
Jeremy Soller 34edeaf066 Update dependencies 2018-11-26 15:48:40 -07:00
Jeremy Soller ee2a7685e6 Revert "Update compiler_builtins and redox_syscall"
This reverts commit d6a5b39505.
2018-11-26 15:45:35 -07:00
Jeremy Soller 583eaa498d Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2018-11-26 15:43:29 -07:00
Jeremy Soller d6a5b39505 Update compiler_builtins and redox_syscall 2018-11-26 15:43:24 -07:00
Jeremy Soller 809f665a8a Update compiler_builtins 2018-11-26 15:43:15 -07:00
Jeremy Soller 15eed4daf1 Update core_io 2018-11-26 14:33:55 -07:00
Jeremy Soller d4e42fd9e0 Merge branch 'type' into 'master'
Some type signature fixes found using script in #111

See merge request redox-os/relibc!181
2018-11-26 13:13:43 +00:00
Ian Douglas Scott f5f561424a Correct return value of regerror 2018-11-25 21:24:32 -08:00
Ian Douglas Scott fc0b7b9111 'strtoull' and 'strtoll' type signatures 2018-11-25 21:17:25 -08:00
Ian Douglas Scott fdd966629d Some type signature fixes found using script in #111 2018-11-25 20:58:02 -08:00
Jeremy Soller de0339ee93 Fix issue with open flag overflow 2018-11-25 19:34:24 -07:00
Jeremy Soller a614c40273 Fix definition of protocol families 2018-11-25 16:45:19 -07:00
Jeremy Soller 6180222760 Format 2018-11-25 16:44:01 -07:00
Jeremy Soller e0daa157b9 Add protocol families 2018-11-25 16:43:45 -07:00
Jeremy Soller 5c4c49a9d1 Add getdelim and getline 2018-11-25 16:39:14 -07:00
Jeremy Soller 96cc56a0b5 Add readlink and symlink 2018-11-25 14:56:36 -07:00
Jeremy Soller d6a1796122 Format 2018-11-25 14:38:33 -07:00
Jeremy Soller d818a8d10e Add pwrite 2018-11-25 14:38:12 -07:00
Jeremy Soller 8a042a220d Implement pread, add more poll constants 2018-11-25 14:34:18 -07:00
Jeremy Soller 869eb160bd Add poll 2018-11-25 13:04:38 -07:00
Jeremy Soller 7398fae8b6 Re-add removed comments 2018-11-25 11:01:19 -07:00
Jeremy Soller 0ac16556bc Format 2018-11-25 10:34:42 -07:00
Jeremy Soller a5279b648f Fix warnings 2018-11-25 10:34:02 -07:00
Jeremy Soller 52493a1ec3 Add popen/pclose 2018-11-25 10:33:50 -07:00
Jeremy Soller de43271204 Merge branch 'uname' into 'master'
Implement uname for Redox

See merge request redox-os/relibc!178
2018-11-25 15:25:48 +00:00
Jeremy Soller a613154191 Merge branch 'alloca' into 'master'
Implement alloca.h

See merge request redox-os/relibc!180
2018-11-25 15:24:56 +00:00
Tibor Nagy 55eb8f2779 Implement alloca.h 2018-11-23 21:31:09 +01:00
Jeremy Soller 9790289aec Add execlp 2018-11-22 20:43:04 -07:00
Jeremy Soller 3cc215caeb Add freading, fwriting, and stdio_ext.h header 2018-11-22 19:24:48 -07:00
Jeremy Soller b4f36bce17 Add more stdio_ext functions 2018-11-22 19:09:46 -07:00
Jeremy Soller 632f9f18e5 fpending 2018-11-22 18:43:45 -07:00
Jeremy Soller 9b0c74b935 Fix ioctl being defined on redox, add cxa_atexit for gcc 2018-11-18 10:35:33 -07:00
Tibor Nagy 012a9b2eb3 Implement uname for Redox 2018-11-18 18:23:47 +01:00
Jeremy Soller 02c8355c13 Update openlibm 2018-11-18 08:58:35 -07:00
Jeremy Soller 4c9173433e Merge branch 'macos_fixes' into 'master'
Make relibc buildable on macOS (not for macOS)

See merge request redox-os/relibc!179
2018-11-17 23:47:52 +00:00
jD91mZM2 1c92751a73 Don't rely on integer wrapping in ctype
Don't rely on integer wrapping in ctype and fix strcasecmp on
non-alphabetic characters
2018-11-17 20:26:43 +01:00
Alexander Theißen 484a05e8b3 Remove unnecessary escape from include.sh
The older bash version of macOS does not understand this escape
and actually creates directories with "\" in their name. After this
change it actually works with both versions.
2018-11-17 20:17:35 +01:00
Alexander Theißen e102c234c1 Properly export CC variable in Makefile
We cannot use ?= because CC is set by default to "cc". Therefore
CC was never set. In addition we need to export the variable
in order to have the rust cc crate pick it up. Otherwise it is
only used by openlibm where it is explicitly passed.
2018-11-17 20:17:35 +01:00
Jeremy Soller 44f84f406f Force byte order to little endian, for gcc 2018-11-17 09:19:35 -07:00
Jeremy Soller e32fc12308 Weak linkage for getopt and fnmatch 2018-11-17 08:40:39 -07:00
Jeremy Soller c6f2b30738 Add netdb bits to include hostent.h_addr 2018-11-17 08:16:37 -07:00
Jeremy Soller 8c5b237963 Rename intmaxdiv_t to imaxdiv_t to match standard 2018-11-17 07:40:30 -07:00
Jeremy Soller e7f7c4ea61 Fix incorrect nul 2018-11-16 21:32:03 -07:00
Jeremy Soller a6642bc753 Fix missing separator 2018-11-16 21:16:08 -07:00
Jeremy Soller a29aa9f599 Add execvp 2018-11-16 21:07:24 -07:00
Jeremy Soller dd65d0c0c8 Fix missing nul 2018-11-16 20:37:37 -07:00
Jeremy Soller 861602bbcc Add umask 2018-11-16 19:49:47 -07:00
jD91mZM2 0684fb6e4c Bump posix-regex version 2018-11-14 20:52:12 +01:00
jD91mZM2 d252838496 Re-use posix-regex matcher in fnmatch 2018-11-14 14:19:48 +01:00
Jeremy Soller 81dc144241 Abandon overriding cargo flags, for now 2018-11-13 21:03:14 -07:00
Jeremy Soller f1c970beef Fix override of CARGOFLAGS when using target 2018-11-13 21:00:05 -07:00
Jeremy Soller 8a972542be Allow override of cargoflags 2018-11-13 20:56:59 -07:00
Jeremy Soller 2b3ae4d8b8 Add configuration for compiling with xargo 2018-11-11 08:10:37 -07:00
Jeremy Soller c36ee7237b Allow override of cargo 2018-11-11 08:03:04 -07:00
Jeremy Soller bf111188e1 Reduce warnings for redox 2018-11-10 07:54:27 -07:00
Jeremy Soller ebffc977b2 Reduce warnings 2018-11-10 07:52:45 -07:00
Jeremy Soller 131dcac554 Update serde_json 2018-11-09 18:31:35 -07:00
Jeremy Soller 4963ca3a95 Fix compile on redox 2018-11-07 20:26:27 -07:00
Jeremy Soller 39b999ccea Update to new rust-toolchain 2018-11-07 20:25:21 -07:00
Jeremy Soller d88f4053ea Merge branch 'header-guards-fix' into 'master'
Fix include guards in regex and utime

See merge request redox-os/relibc!176
2018-11-06 12:45:36 +00:00
Michal Z 0396460c84 Fix include guards in regex and utime
The include_guard in both regex and utime was "_TEMPLATE_H", this meant that including both wasn't possible.
Their header guards should be consistent with the header files as well.
Changed _TEMPLATE_H to _REGEX_H and _UTIME_H in /regex/cbindgen.toml and /utime/cbindgen.toml respectively.
2018-11-06 11:27:11 +01:00
jD91mZM2 75bac011e4 Merge branch 'MaikuZ/libgen' into 'master'
Implement libgen.h

See merge request redox-os/relibc!175
2018-11-05 20:33:54 +00:00
Michal Z a7b71a311d Implement libgen.h
Implemented the following calls according to http://pubs.opengroup.org/onlinepubs/7908799/xsh/libgen.h.html
- char* basename(char*)
- char* dirname(char*)

Added test suit for the implemented calls.

Issue: https://gitlab.redox-os.org/redox-os/relibc/issues/134
2018-11-05 17:49:14 +01:00
jD91mZM2 571b4d4976 Fix getdents on redox 2018-11-01 10:58:01 +01:00
Jeremy Soller 09bd4bc375 Update cbindgen 2018-10-29 19:27:47 -06:00
Jeremy Soller 51b2e630b9 Merge branch 'optind-reset' into 'master'
Handle getopt reinitialization

See merge request redox-os/relibc!174
2018-10-28 19:36:25 +00:00
Tibor Nagy f97f93c48d Handle getopt reinitialization 2018-10-28 19:59:08 +01:00
Jeremy Soller 740f57738c Merge branch 'cpp-extern' into 'master'
Disable symbol mangling for C++

See merge request redox-os/relibc!173
2018-10-28 13:13:51 +00:00
Tibor Nagy d4308c8a9b Disable symbol mangling for C++ 2018-10-28 13:24:34 +01:00
Jeremy Soller 6f4b8db7d8 Merge branch 'assert-duke32' into 'master'
Fix assert when used as an expression

See merge request redox-os/relibc!172
2018-10-27 17:58:58 +00:00
Tibor Nagy e7f251fdb0 Fix assert when used as an expression
Based on what musl does.
2018-10-27 17:40:24 +02:00
jD91mZM2 bfa068df88 Fix strcasecmp return value 2018-10-17 21:26:16 +02:00
Jeremy Soller 3c2121d4e0 Do not require prefix for hex 2018-10-16 18:03:21 -06:00
jD91mZM2 460f57b37f Disallow execve on non-executable interpreted files 2018-10-15 17:36:41 +02:00
jD91mZM2 75c5c04bee Implement a proper mutex type for future usage 2018-10-15 15:24:14 +02:00
jD91mZM2 23fe526c55 Fix feof and ferror 2018-10-14 15:57:42 +02:00
jD91mZM2 057d23908a Merge branch 'bugfix/netdb-gethostent' into 'master'
Don't drop the host aliases pointer vector in `gethostent`

Closes #130

See merge request redox-os/relibc!170
2018-10-13 15:02:23 +00:00
jD91mZM2 edb95246d4 Fix bug in strncasecmp 2018-10-13 16:55:21 +02:00
Jeremy Soller e4d87a101a Merge branch 'printf' into 'master'
Implement almost all of printf

See merge request redox-os/relibc!171
2018-10-13 14:14:27 +00:00
jD91mZM2 63882684b2 Implement almost all of printf 2018-10-13 14:20:54 +02:00
Benedikt Rascher-Friesenhausen 49259d3f01 Don't drop the host aliases pointer vector in gethostent
There are pointers to this vector in `HOST_ENTRY` so we must keep it around for
as long as `HOST_ENTRY` exists.
2018-10-11 20:59:54 +02:00
jD91mZM2 b517629371 Fix timeradd
wow i am stupid for writing this code
2018-10-11 19:52:54 +02:00
jD91mZM2 1f3154b45c Invoke constructors and destructors
Huge thanks to @xtibor for both discovering that this was still an issue, and also providing information with how to fix it
2018-10-11 16:59:49 +02:00
jD91mZM2 116cbda8d2 Merge branch 'test-ctor-dtor' into 'master'
Add tests for constructors and destructors

See merge request redox-os/relibc!169
2018-10-10 14:06:41 +00:00
Tibor Nagy aee3f68117 Add tests for constructors and destructors 2018-10-09 20:32:27 +02:00
jD91mZM2 f516ff72d8 Merge branch 'regoff_t' into 'master'
Move regoff_t to regex.h

See merge request redox-os/relibc!168
2018-10-09 14:49:53 +00:00
jD91mZM2 0469c0c2c6 Add tests for memcmp and fix a teeny tiny bug 2018-10-09 16:47:57 +02:00
Tibor Nagy 0f5fa8c9d4 Move regoff_t to regex.h 2018-10-09 16:43:34 +02:00
jD91mZM2 3f4fbf9084 Merge branch 'feature/optimise-memcmp' into 'master'
Optimise `memcmp` for speed

See merge request redox-os/relibc!167
2018-10-09 14:20:06 +00:00
Benedikt Rascher-Friesenhausen 8e2b7c11b4 Replace i32 with c_int in memcmp
As per the comments from jD91mZM2 on the merge request.
2018-10-07 17:40:30 +02:00
jD91mZM2 91675b5bc8 realpath on redox: don't forget the nul terminator 2018-10-07 15:12:41 +02:00
jD91mZM2 fba3bf5161 Merge branch 'assert' into 'master'
Make assert more hygienic

See merge request redox-os/relibc!166
2018-10-07 12:50:56 +00:00
jD91mZM2 758f681590 Implement scandir 2018-10-07 14:43:54 +02:00
jD91mZM2 3c8cb95b80 Cleanup strcasecmp 2018-10-07 13:02:05 +02:00
jD91mZM2 0de7d30656 Fix S_IS*
For some reason, C handles `==` before `&`.
So `a & b == c` is the same thing as `a & (b == c)`.
2018-10-07 13:01:59 +02:00
jD91mZM2 028378b8bf Fix double close
Accidentally made file references not count as references and therefore also close the fd. My bad.
2018-10-07 10:54:37 +02:00
jD91mZM2 418a960f3b Implement realpath 2018-10-07 10:32:51 +02:00
Benedikt Rascher-Friesenhausen e10a346356 Optimise memcmp for speed
I saw that in other parts of the `string` module iterations over `usize` were
used to increase iteration speed.  In this patch I apply the same logic to
`memcmp`.  With this change I measured a 7x speedup for `memcmp` on a ~1MB
buffer (comparing two buffers with the same content) on my machine (i7-7500U),
but I did not do any real world benchmarking for the change.  The increase in
speed comes with the tradeoff of both increased complexity and larger generated
assembly code for the function.

I tested the correctness of the implementation by generating two randomly filled
buffers and comparing the `memcmp` result of the old implementation against this
new one.

I ran the tests and currently currently three of them fail:
  - netdb (fails to run)
  - stdio/rename (fails to verify)
  - unistd/pipe (fails to verify)

They do so though regardless of this change, so I don't think they are related.
2018-10-07 10:25:19 +02:00
jD91mZM2 26d629674a Implement strcasestr 2018-10-06 17:37:50 +02:00
jD91mZM2 9d56ce42c6 Implement timer* macros, and GNU's getopt_long 2018-10-06 16:46:35 +02:00
Tibor Nagy 614b2f5103 Make assert more hygienic 2018-10-06 14:55:06 +02:00
jD91mZM2 baddbb98d5 Don't reinvent the wheel in strings.h 2018-10-05 19:33:41 +02:00
jD91mZM2 1acc2a1a32 Initial regex.h implementation 2018-10-05 18:07:43 +02:00
jD91mZM2 dfa3845c33 Make fread/fwrite retry their respective operations 2018-10-02 18:47:42 +02:00
jD91mZM2 6dcc8ee8d9 Implement strtof 2018-10-02 18:47:42 +02:00
Jeremy Soller aec6a48ca4 Merge branch 'termios-baudrate' into 'master'
Add termios baud rate functions

See merge request redox-os/relibc!165
2018-09-29 21:27:31 +00:00
Tibor Nagy db4452e98b Add termios baud rate functions 2018-09-29 22:52:12 +02:00
jD91mZM2 b22d386177 Re-add EOF to bits header
cbindgen can't handle negative numbers, see https://github.com/eqrion/cbindgen/issues/205
2018-09-29 20:02:37 +02:00
jD91mZM2 dd711f4dee Fix bug in fread
Bug discovered by @xTibor. Test and input data provided by him.
2018-09-29 15:04:58 +02:00
jD91mZM2 0451fac66c Delete RawFile in favor of File 2018-09-26 19:40:39 +02:00
jD91mZM2 d365813c90 Merge branch 'core-io' into 'master'
Rewrite IO to use core-io library

See merge request redox-os/relibc!164
2018-09-26 16:56:29 +00:00
jD91mZM2 4f187efc9b Change BUFSIZ type to work with cbindgen 2018-09-26 18:44:04 +02:00
jD91mZM2 243ce18ecd Implement ftell 2018-09-26 17:48:46 +02:00
jD91mZM2 21559bb503 Fix redox compilation 2018-09-26 16:40:23 +02:00
jD91mZM2 afc1ff134a Rewrite IO to use core-io library 2018-09-26 16:13:09 +02:00
Jeremy Soller aff35892be Add fs module 2018-09-24 21:40:40 -06:00
Jeremy Soller 7f14fcdee0 Remove c_str functions, replace with CStr 2018-09-24 21:08:29 -06:00
Jeremy Soller ef9fee5a2b Prepare for use of Write trait by renaming Write to WriteByte 2018-09-24 20:31:06 -06:00
Jeremy Soller 9eef8d7e2d Add core_io 2018-09-24 20:19:37 -06:00
Jeremy Soller b309cd832d Add getopt and machine/endian.h 2018-09-24 14:45:36 -07:00
jD91mZM2 d659377b24 VERY basic crti/crtn 2018-09-23 21:30:13 +02:00
jD91mZM2 6d99915154 Use RAII for file locking in stdio 2018-09-23 20:40:48 +02:00
Jeremy Soller 7e4a60f78b Fix possible deadlocks 2018-09-23 11:58:09 -06:00
jD91mZM2 658dc34d30 A few I/O related fixes 2018-09-23 17:28:42 +02:00
jD91mZM2 1e9dbfdf62 Use cbitset crate 2018-09-22 17:26:58 +02:00
jD91mZM2 2a8bc8331b Fix select return value 2018-09-22 11:12:31 +02:00
Tom Almeida b43299642b Fix buffering issue with large output through stdio 2018-09-21 15:21:39 +02:00
jD91mZM2 29b4c19d6e fixup! Untested fix for pwd.h on redox 2018-09-21 13:13:17 +02:00
jD91mZM2 64acfbb8e3 Format 2018-09-21 08:04:38 +02:00
jD91mZM2 9e9b850b90 Untested fix for pwd.h on redox 2018-09-21 08:04:06 +02:00
Jeremy Soller a0b4e21bbb Comment out SO_ERROR so it is not used 2018-09-20 15:41:59 -07:00
Jeremy Soller a567197b54 enable getsockopt and setsockopt 2018-09-20 14:39:58 -07:00
Jeremy Soller 9dbf49fdcd Format and add O_CLOEXEC where appropriate 2018-09-18 19:52:47 -06:00
jD91mZM2 2aa7597a2b Fix network problem with netdb on redox 2018-09-18 19:14:28 +02:00
Jeremy Soller 043ecf2cf9 Replace a println with a trace 2018-09-18 08:53:37 -06:00
Jeremy Soller 290ecb3e46 - fsync when tracing
- clean up trace macro some
2018-09-18 08:49:44 -06:00
Jeremy Soller 60f00508d3 Restore errno if trace_expr is successful 2018-09-18 08:34:06 -06:00
jD91mZM2 10a7944aef Avoid duplicate code 2018-09-18 08:08:55 +02:00
Jeremy Soller c2f4c1dbc9 Add trace macro and feature 2018-09-17 21:29:40 -06:00
Jeremy Soller 28f4da526d Require all target when building sysroot 2018-09-17 20:28:17 -06:00
Jeremy Soller 2cc5db9de6 Fix Linux compilation 2018-09-17 20:27:59 -06:00
Jeremy Soller 23098b694e Add print, eprint, eprintln, and fix println macros 2018-09-17 15:02:00 -06:00
Jeremy Soller 35bdab7690 Remove protocol check from socket 2018-09-17 15:01:31 -06:00
Jeremy Soller 13cd7d5a5f Oops, extra nul 2018-09-17 10:57:22 -06:00
jD91mZM2 d0a4f2f845 Delete a bunch of leftover constants 2018-09-17 18:44:33 +02:00
Jeremy Soller 76959416bb Add missing open flags 2018-09-17 09:59:41 -06:00
Jeremy Soller 716ea87bb4 Format 2018-09-17 09:46:47 -06:00
Jeremy Soller f3a832ad12 Fixes for select on Redox 2018-09-17 09:46:40 -06:00
Jeremy Soller dfb07e473a Comment out functions not implemented by Redox 2018-09-15 12:31:40 -06:00
Jeremy Soller f661d5d1c0 Fix use of uninitialized memory 2018-09-15 11:14:51 -06:00
Jeremy Soller 9d24e61548 Use alloc_aligned and free functions in platform for global allocator 2018-09-15 11:14:34 -06:00
Jeremy Soller 706a8de7a0 Call _init and _fini 2018-09-15 11:14:05 -06:00
jD91mZM2 882b86e282 Revert 'fix netdb on names with spaces', just ignore invalid lines 2018-09-05 19:24:10 +02:00
jD91mZM2 30d6f079c5 Add missing dirent macros (fixes #129) 2018-09-05 17:39:40 +02:00
jD91mZM2 49ccf364c2 Fix netdb getservbyname on names with spaces 2018-09-05 17:38:59 +02:00
jD91mZM2 eb6ddac1eb Unify gmtime and localtime code
Apparently gmtime was already implemented when I made localtime, so we had two different things written from scratch. We decided in the relibc channel of the Redox OS Mattermost chat to use my code, as it is more extensively tested and perhaps is clearer in how it works.
2018-09-05 15:52:25 +02:00
Tom Almeida 9cb594dca1 Merge branch 'Tommoa:master' into 'master'
Add contribution guidelines/tutorial

See merge request redox-os/relibc!162
2018-09-05 13:03:46 +00:00
Tom Almeida 92e1127b64 Add contribution guidelines/tutorial 2018-09-05 13:03:46 +00:00
jD91mZM2 59d74e194d Fix CI 2018-09-04 15:31:43 +02:00
jD91mZM2 eb2fe7934c Merge branch 'master' into 'master'
Updated url, implemented missing functions in header/arpa_inet/mod.rs

See merge request redox-os/relibc!161
2018-09-04 12:28:13 +00:00
thedarkula e688d9c4d1 Updated url, implemented missing functions in header/arpa_inet/mod.rs 2018-09-04 02:59:59 +01:00
jD91mZM2 50c03f289f Support shebangs in redox execve 2018-09-02 11:15:38 +02:00
jD91mZM2 077e922cc6 fixup! Delete duplicate types 2018-09-02 08:20:19 +02:00
jD91mZM2 26f953e11f Run fmt.sh 2018-09-02 08:17:52 +02:00
jD91mZM2 6fe3e05ea0 Delete duplicate types
Now that we use cbindgen differently :D
2018-09-02 08:17:15 +02:00
jD91mZM2 dbe18b92f0 Merge branch 'netdb' into 'master'
Netdb

See merge request redox-os/relibc!156
2018-09-01 14:00:18 +00:00
Paul Sajna 07eb658a8a Netdb 2018-09-01 14:00:18 +00:00
Jeremy Soller 3dbf9f872a Allow use of custom CC for compiling tests 2018-08-27 14:54:53 -06:00
Jeremy Soller 28912d84d9 Further fixes to tests makefile 2018-08-27 13:29:44 -06:00
Jeremy Soller 82b9715f41 Fix makefile for tests, add sysroot target 2018-08-27 13:02:13 -06:00
Jeremy Soller 70eda382d3 Merge branch 'pal' into 'master'
Intense refactor

See merge request redox-os/relibc!159
2018-08-27 15:27:58 +00:00
Jeremy Soller 0258fb3f5e Fix header path 2018-08-27 08:47:16 -06:00
Jeremy Soller b52c822150 Update Redox module to use CStr 2018-08-27 08:44:42 -06:00
Jeremy Soller c911facca6 Make pal functions take cstr 2018-08-27 08:33:12 -06:00
Jeremy Soller 16373257b0 format 2018-08-27 07:12:37 -06:00
Jeremy Soller 8f5470fd27 Reduce warnings 2018-08-27 07:12:24 -06:00
Jeremy Soller bab4e2896a Format 2018-08-27 06:35:30 -06:00
Jeremy Soller 7ab700315d Fix warnings and add c_str 2018-08-26 15:15:29 -06:00
Jeremy Soller 6418f893e4 Fix headers with directories 2018-08-26 12:40:19 -06:00
Jeremy Soller 124e118f9f Fix makefile 2018-08-26 12:35:41 -06:00
Jeremy Soller ed00ddfb54 Fix remaining issues, move setjmp into relibc crate, move start logic into relibc 2018-08-26 12:28:27 -06:00
Jeremy Soller c63c930e4a Make it compile 2018-08-26 12:10:02 -06:00
Jeremy Soller 277b9abcd5 Fix build, mostly 2018-08-26 08:56:02 -06:00
Jeremy Soller c20ce5ffed Large reorganization of headers (WIP) 2018-08-26 08:11:35 -06:00
Jeremy Soller ff32c8cbbd Remove stat and lstat, which can be replaced with open and fstat 2018-08-25 10:13:58 -06:00
Jeremy Soller 34f5f57213 Fix signal and socket pal implementations on Redox 2018-08-25 09:21:08 -06:00
Jeremy Soller d1dabccdce Fix missing modules in Redox platform 2018-08-25 09:14:02 -06:00
Jeremy Soller 165f099c6b Update Redox platform to pal 2018-08-25 09:07:35 -06:00
Jeremy Soller 729709a8e6 Update all modules to new Pal mechanism 2018-08-25 08:42:57 -06:00
Jeremy Soller e6f163823c WIP: platform abstraction layer 2018-08-24 20:13:07 -06:00
Jeremy Soller c25ce6a5f3 Include stddef.h in sys/types.h 2018-08-18 08:27:40 -06:00
Jeremy Soller f1df1f9f0b Fix issue with stdio.h bits file not having FILE defined 2018-08-18 08:22:16 -06:00
Jeremy Soller 83cb46afd8 Fix path to crt0.o and libc.a 2018-08-18 08:15:14 -06:00
Jeremy Soller 2e8cb6b363 Fix signature of unsetenv 2018-08-17 20:07:00 -06:00
Jeremy Soller 4e3b6732d5 Default to release for make 2018-08-17 18:41:16 -06:00
jD91mZM2 128209788c Finish up fexec migration 2018-08-13 14:46:59 +02:00
jD91mZM2 66d7aa8553 Revert 'Fix off by one error' because it introduces one
Turns out, it's just redox not having a NULL pointer here. Linux does.
2018-08-13 11:37:29 +02:00
jD91mZM2 d5f85906cb Fix off-by-one error :| 2018-08-12 21:50:22 +02:00
jD91mZM2 1c4e8852dd Migrate to new FEXEC system call 2018-08-12 20:35:45 +02:00
jD91mZM2 07563de231 Implement setenv/unsetenv 2018-08-12 07:43:23 +02:00
jD91mZM2 232a3311df Add SIGABRT to redox 2018-08-10 08:33:11 +02:00
jD91mZM2 b10fa984f3 Implement strtod 2018-08-09 16:35:49 +02:00
jD91mZM2 face6f07f3 Implement mmap 2018-08-09 10:54:44 +02:00
Tom Almeida 3aa52e88a7 Fix issues with _IONBF and reading 2018-08-09 02:51:37 +08:00
Tom Almeida d5a9cd6953 Add tests to make sure setvbuf works. 2018-08-09 02:08:53 +08:00
Tom Almeida 540395c015 Fix _IONBF crashing when reading 2018-08-09 02:07:19 +08:00
Tom Almeida a1ebe321d6 Ensure that _IONBF would be respected when writing 2018-08-09 01:38:57 +08:00
jD91mZM2 40c3d28a41 fixup! Fix a few ffmpeg issues 2018-08-08 19:29:02 +02:00
jD91mZM2 b0546336c7 Fix a few ffmpeg issues 2018-08-08 19:28:13 +02:00
Tom Almeida d219d57acb Fix an issue where _IONBF would cause an overflow error 2018-08-09 00:49:57 +08:00
jD91mZM2 deee825a1c Implement llabs 2018-08-08 16:25:10 +02:00
jD91mZM2 b26213731c Don't forget to lock stdout when printfing 2018-08-08 13:25:26 +02:00
jD91mZM2 23a8855e50 Fix garbage env pointer to main on redox 2018-08-08 11:01:16 +02:00
jD91mZM2 40a7380a58 Fix snprintf and make strftime use a counting writer 2018-08-07 21:31:05 +02:00
jD91mZM2 d39a66c351 Fix waitpid -1 on redox 2018-08-07 15:01:07 +02:00
jD91mZM2 3bb3a3e322 Fix strcpy 2018-08-07 11:35:23 +02:00
jD91mZM2 f6ca7d7c2d Add S_ISSOCK and fix str(c)spn 2018-08-05 21:49:45 +02:00
jD91mZM2 b20307dca0 Implement fnmatch.h 2018-08-05 19:50:49 +02:00
jD91mZM2 b5adee798d Move scanf unit tests to normal C tests 2018-08-05 09:53:07 +02:00
jD91mZM2 442a7bbedc Fix getcwd with a NULL argument 2018-08-04 08:42:47 +02:00
jD91mZM2 ba8bd8c4e8 Add the last few things for bash to compile :D 2018-08-03 11:18:52 +02:00
jD91mZM2 44599a032e Kind of get bash to compile
Doesn't link yet due to "multiple definitions of malloc", because some are supplied by some library of bash itself. Really odd.
2018-08-02 14:37:57 +02:00
jD91mZM2 9c57c222f6 Fix strcasecmp 2018-07-31 07:37:19 +02:00
jD91mZM2 daf65c7a46 Implement access 2018-07-30 21:08:44 +02:00
jD91mZM2 ce53ac7e13 Fix inttypes a little 2018-07-30 12:32:03 +02:00
jD91mZM2 2a303c4b60 Implement sys/file.h 2018-07-30 10:04:58 +02:00
jD91mZM2 d3e4fa71a5 Implement sys/select.h
I really really wish I could actually test this on redox. All I know is: it compiles
2018-07-29 17:26:54 +02:00
Jeremy Soller bc7f7356b9 Fix redox futimens fd type 2018-07-29 07:22:41 -06:00
Jeremy Soller a9fcb973f6 Implement utimes and utime
Format
2018-07-29 07:18:44 -06:00
jD91mZM2 3eb7b99799 Move test binaries to tests/bins/ 2018-07-29 10:04:11 +02:00
jD91mZM2 f82b48b839 Implement sys/times.h on linux 2018-07-29 09:23:56 +02:00
jD91mZM2 e7e9d57db5 Implement a dummy sgtty 2018-07-29 07:55:19 +02:00
jD91mZM2 65cbd40fce Remove an accidentally committed binary. Again. Sigh. 2018-07-29 07:19:23 +02:00
jD91mZM2 4a42983d13 Make sigset_t be a long because bash needs that to compile 2018-07-28 17:18:53 +02:00
jD91mZM2 7524a83d82 fixup! sigemptyset and sigaddset 2018-07-28 15:33:06 +02:00
jD91mZM2 892ce75eb4 sigemptyset and sigaddset 2018-07-28 14:10:57 +02:00
jD91mZM2 6da2639dfa Fix leaking uninitialized elements and missing free 2018-07-28 08:22:21 +02:00
jD91mZM2 3c88056f9d Implement getrusage on linux 2018-07-27 19:54:30 +02:00
jD91mZM2 193328952d Alias memory.h to string.h 2018-07-27 18:27:51 +02:00
jD91mZM2 fc910d4157 Merge branch 'fix-parallel-builds' into 'master'
Turn the libc and libm rules into 'order-only' prequisites

Closes #127

See merge request redox-os/relibc!158
2018-07-27 16:02:49 +00:00
Robin Randhawa cb046c78e4 Turn the libc and libm rules into 'order-only' prequisites
These prerequisites are GNU Make terminology.

This change forces the libc rule to be executed first so that the headers that
the libm rule needs are available. The original setup was using 'normal'
prerequisites which occasionally resulted in bizarre build breakage,
especially on multi-core build hosts. Seen often on my 8-way SMP build
host.

Note that this doesn't impede parallelisation of each rule indepent of
the other. It just serializes the rules themselves.

This fixes: https://gitlab.redox-os.org/redox-os/relibc/issues/127
2018-07-27 16:51:15 +01:00
jD91mZM2 f6b364845e Implement pwd.h 2018-07-27 15:15:56 +02:00
jD91mZM2 1b40f2d463 Implement setitimer/getitimer/alarm/ualarm 2018-07-27 08:22:17 +02:00
jD91mZM2 8b48b6959c fixup! Implement isatty 2018-07-26 14:32:10 +02:00
jD91mZM2 2bf426b0fb Implement isatty 2018-07-26 14:19:20 +02:00
jD91mZM2 7ff6940edd Implement futimens 2018-07-26 13:26:54 +02:00
jD91mZM2 a0f2baff12 Implement gettimeofday 2018-07-26 10:07:33 +02:00
jD91mZM2 83949290c9 Implement dirent.h 2018-07-26 09:16:22 +02:00
jD91mZM2 dec5e0a019 Add missing sockaddr_in to platform/src/types.rs 2018-07-25 14:39:28 +02:00
jD91mZM2 e749d23030 Solve stdin/out/err UB in a better way 2018-07-25 14:29:14 +02:00
jD91mZM2 992e50ef0f Fix a few things with openssl 2018-07-25 14:04:36 +02:00
jD91mZM2 0e48937991 Merge branch 'tmpfile' into 'master'
Implement tmpfile

See merge request redox-os/relibc!154
2018-07-25 06:32:19 +00:00
stratact 42811717da Remove unneeded reference 2018-07-24 23:22:00 -07:00
stratact 5f6309d87c Implement tmpfile (squashed) 2018-07-24 23:14:18 -07:00
jD91mZM2 8021ade2a9 Move stat test out of expected tests 2018-07-23 21:41:19 +02:00
jD91mZM2 dc427272af fixup! Fix stat stack corruption and link test 2018-07-23 21:21:15 +02:00
jD91mZM2 5697ac0f84 Fix stat stack corruption and link test 2018-07-23 11:26:18 +02:00
jD91mZM2 86a38b47d1 Fix broken exec test 2018-07-22 19:57:59 +02:00
jD91mZM2 ecd8aca6d6 Basic signal support 2018-07-22 17:04:13 +02:00
jD91mZM2 7b8e7feb3d Run fmt.sh 2018-07-22 11:33:01 +02:00
jD91mZM2 67d5976622 Clean up tests 2018-07-22 11:24:50 +02:00
jD91mZM2 e9484e4d60 Ignore *all* target directories 2018-07-22 10:21:14 +02:00
jD91mZM2 27e8174e10 Combine mktemp and mkostemps logic 2018-07-22 10:17:09 +02:00
jD91mZM2 e4a89ae645 Merge branch 'mkstemp' into 'master'
Implement `mkstemp` and `mkostemps`

See merge request redox-os/relibc!152
2018-07-22 07:19:22 +00:00
stratact c788f7ed26 Add expected tests 2018-07-22 00:01:43 -07:00
stratact 6fa1f60830 Implement mkstemp and mkostemps (squashed) 2018-07-21 10:25:19 -07:00
jD91mZM2 7d43d45e56 Merge branch 'arpa_inet' into 'master'
implement arpainet

See merge request redox-os/relibc!153
2018-07-19 16:02:51 +00:00
Paul Sajna 0550a7b9db implement arpainet 2018-07-19 16:02:51 +00:00
jD91mZM2 233e679c08 Make inner platform functions private once more 2018-07-18 10:04:17 +02:00
jD91mZM2 ff9ef98f47 Move gethostname to platform 2018-07-18 10:02:42 +02:00
jD91mZM2 0a57c617c7 Remove a useless comment 2018-07-18 08:07:00 +02:00
jD91mZM2 5b3e09ee16 fixup! strcoll as strcmp because no locale 2018-07-17 18:35:54 +02:00
jD91mZM2 878208485c strcoll as strcmp because no locale 2018-07-17 17:44:38 +02:00
jD91mZM2 482bd9c5f1 fmt.sh 2018-07-17 17:24:22 +02:00
jD91mZM2 b83d1c7ff0 strftime :D 2018-07-17 16:47:33 +02:00
Jeremy Soller 37b6cd942c Fix pipe 2018-07-14 12:29:18 -06:00
jD91mZM2 515d041153 Hehe make environment tests work for everybody 2018-07-14 19:53:56 +02:00
jD91mZM2 75145ab92b Pass envp to main 2018-07-14 19:48:10 +02:00
jD91mZM2 019011f029 WIP env support 2018-07-14 18:03:22 +02:00
Jeremy Soller dc443a8cc3 Format 2018-07-13 09:53:44 -06:00
Jeremy Soller 4c4ce80fcd Fix warnings 2018-07-13 09:52:53 -06:00
Jeremy Soller 52e02286f2 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2018-07-13 09:24:42 -06:00
Jeremy Soller 4718796c2b Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2018-07-13 09:23:13 -06:00
jD91mZM2 9cb0881cc4 Alias wbstowcs and wbtowc to their correct functions 2018-07-13 15:01:13 +02:00
jD91mZM2 5f098c89c3 Add more tests for mktime and localtime 2018-07-13 10:16:42 +02:00
jD91mZM2 a9ea2ef64e Fixup time & support negative & mktime 2018-07-13 09:13:46 +02:00
Jeremy Soller c2cdb451f5 Add system 2018-07-12 20:00:41 -06:00
jD91mZM2 758b437170 Run fmt.sh 2018-07-12 21:40:44 +02:00
jD91mZM2 b7e11afd2f Add localtime and ctime functions
I have NO IDEA if these are correct. Implementation was 'inspired by' https://github.com/rust-lang-deprecated/time/commit/4ca23fb14ddf44fd90609fec6a2fb1efcedb8ea3. Pretty darn certain that negative values won't work
2018-07-12 21:39:53 +02:00
jD91mZM2 a7cc95cd90 Comment out #[no_mangle] on unimplemented functions
This stops configure scripts from identifying them as valid
2018-07-12 21:39:53 +02:00
Jeremy Soller b8cab5f0be Fix missing stdint.h in signal.h 2018-07-12 11:12:41 -06:00
Jeremy Soller b7eb7a43e0 Update lock file 2018-07-12 09:50:00 -06:00
Jeremy Soller 463c9f386c Fix issue with RUSAGE constants not being in C headers if negative 2018-07-12 09:49:53 -06:00
Jeremy Soller 9c27110de1 Add rusage constants 2018-07-12 09:09:30 -06:00
Jeremy Soller 6e56734224 Fix environ signature 2018-07-12 09:00:58 -06:00
Jeremy Soller 99fa77535a Add pathconf variables 2018-07-12 09:00:23 -06:00
Jeremy Soller 9fc785dcc6 Add stack_chk functionality 2018-07-12 07:40:53 -06:00
Jeremy Soller 6c11a18240 Go back to patched ralloc 2018-07-11 09:59:28 -06:00
jD91mZM2 5f4ebaaabf Fix broken ralloc submodule & fmt.sh 2018-07-11 17:13:38 +02:00
jD91mZM2 55e618d8c0 Add the last socket functions on linux; leave unimplemented on redox 2018-07-11 12:49:50 +02:00
jD91mZM2 6d923cbd0b Implement getpeername and getsockname 2018-07-11 11:43:38 +02:00
jD91mZM2 30d91b82b2 Run fmt.sh 2018-07-08 08:51:15 +02:00
jD91mZM2 d3f6985ee9 Add a few things necessary for openssl (not all) 2018-07-08 08:44:23 +02:00
jD91mZM2 587ee32a30 Merge branch 'style-tag' into 'master'
Use style = Tag everywhere possible

See merge request redox-os/relibc!151
2018-07-08 06:38:45 +00:00
jD91mZM2 985a83ee69 Use style = Tag everywhere possible 2018-07-06 17:02:23 +02:00
jD91mZM2 53f634f579 Fix inttypes 2018-07-06 17:01:52 +02:00
jD91mZM2 eaf7338946 Add aliases for compatibility 2018-07-06 13:39:07 +02:00
Jeremy Soller 919ae09d2f Fix compilation on Redox 2018-07-04 10:16:34 -06:00
Jeremy Soller 3361b05911 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/relibc 2018-07-04 10:12:32 -06:00
Jeremy Soller ea5f8d59de Add dlmalloc 2018-07-04 10:10:34 -06:00
jD91mZM2 e206400d19 Move exec* back to platform
This undos a workaround. Jeremy moved the ralloc stuff to platform and suddenly this seems to work again. I don't know what is different from when I tried this before and now, but I don't really care
2018-07-04 09:29:34 +02:00
Jeremy Soller 3ef9599af5 Update ralloc 2018-07-03 21:18:23 -06:00
Jeremy Soller 42abc98a99 Cleanup allocation functions 2018-07-03 19:40:47 -06:00
Jeremy Soller b6b34a7026 Ralloc fixes and fixes for Redox execution 2018-07-03 19:07:07 -06:00
Jeremy Soller 7e6e1b164c Align stack on x86_64 2018-07-03 11:31:05 -06:00
jD91mZM2 6a0928edfd Use relibc to build openlibm 2018-07-03 19:01:24 +02:00
jD91mZM2 9c169a186f Run fmt.sh 2018-07-03 09:33:41 +02:00
jD91mZM2 aff5380723 Merge branch 'master' into 'master'
Fixing some things in stdio

See merge request redox-os/relibc!136
2018-07-03 07:21:02 +00:00
Tom Almeida 53a03cb0ba Made sure errors were properly handled by printf 2018-07-03 14:50:38 +08:00
Tom Almeida 8bc07abd05 Fix freopen.stdout. There was a trailing space 2018-07-03 14:42:31 +08:00
Tom Almeida ebe1ed15f8 Fix fgets 2018-07-03 14:34:40 +08:00
Tom Almeida bf2973e857 Ensure we correctly insert null character in gets 2018-07-03 12:50:04 +08:00
Tom Almeida d7a0f3d526 Ensure gets stops on newline or bufchar 2018-07-03 12:36:41 +08:00
Tom Almeida bf6db91993 Actually remove stdlib from stdio. This should have been done with wchar being put in, but I messed something up 2018-07-03 12:24:51 +08:00
Tom Almeida 72177be0fa Add a working implementation of gets 2018-07-03 12:14:30 +08:00
Tom Almeida 7277286efd Implement Drop for FILE, so we flush when the process exits 2018-07-03 10:05:12 +08:00
Tom Almeida 81107f8cd1 Don't reset read/write every time we check if we can read or write 2018-07-03 10:01:48 +08:00
Tom Almeida e9cecfead3 Return -1 for error in printf 2018-07-03 09:48:21 +08:00
Tom Almeida 0d61f9f4fd Make sure we can actually write before writing anything when using printf 2018-07-03 09:13:48 +08:00
Tom Almeida da664d4919 Merged relibc with branch 2018-07-03 08:39:04 +08:00
jD91mZM2 30ec8aa2c9 Add redox to CI 2018-07-02 10:35:40 +02:00
jD91mZM2 07dbc6bd76 Fix no_std on redox
Apparently a root-level cfg does not go well with a root-level no_std
2018-07-02 08:53:13 +02:00
jD91mZM2 17778ba1b4 Remove missing rustfmt.toml options 2018-07-02 07:42:33 +02:00
jD91mZM2 9c01673422 Use no_std in inttypes (whoops) 2018-07-01 21:00:03 +02:00
Stephan Vedder cc210361d6 wchar support 2018-07-01 20:59:37 +02:00
jD91mZM2 fb09b03acf Fix compilation on redox 2018-07-01 17:55:24 +02:00
Jeremy Soller 396a6dbb90 Merge branch 'mggmuggins/ci' into 'master'
Stage and Cache build

See merge request redox-os/relibc!150
2018-06-30 21:59:01 +00:00
SamwiseFilmore b911a76de4 Stage and Cache build 2018-06-30 21:01:12 +00:00
jD91mZM2 0567f699a2 Merge branch 'master' into 'master'
Workaround compilation errors

See merge request redox-os/relibc!149
2018-06-30 14:14:04 +00:00
jD91mZM2 541fbcf57c Use ptr::null over 0 2018-06-30 12:19:39 +02:00
jD91mZM2 1fd9a5f249 Moooore fixes :| 2018-06-30 12:15:51 +02:00
Tom Almeida 05b4b76426 Fix some issues 2018-06-30 17:49:34 +08:00
Tom Almeida 10a9081b66 Made sure that something that's unsafe is actually marked as unsafe 2018-06-30 17:47:30 +08:00
Tom Almeida 18418254b9 Made sure lazy_static works with no_std 2018-06-30 17:37:26 +08:00
Tom Almeida 8075447fad Changed FILE to use a vector as a buffer instead of raw pointers. This allows us to remove the large majority of unsafe blocks from the code 2018-06-30 17:37:26 +08:00
Tom Almeida 57f7de1e6d Changed FILE to use a vector as a buffer instead of raw pointers. This allows us to remove the large majority of unsafe blocks from the code 2018-06-30 17:33:02 +08:00
Tom Almeida 4c65f14f9a Fixed some issues with temporary files and moved some raw pointers to Option<&T>s 2018-06-30 17:26:39 +08:00
Tom Almeida 71fa4026f5 Changed FILE to use a vector as a buffer instead of raw pointers. This allows us to remove the large majority of unsafe blocks from the code 2018-06-30 17:26:35 +08:00
Tom Almeida a2dc22123f Merge branch 'master' into 'master'
# Conflicts:
#   src/stdio/src/default.rs
2018-06-30 09:19:54 +00:00
jD91mZM2 2f6467bce6 Fix test warning 2018-06-30 09:26:46 +02:00
jD91mZM2 674d4e3695 Preallocate because why not 2018-06-30 09:25:05 +02:00
jD91mZM2 234632d319 Workaround compilation errors 2018-06-30 09:19:06 +02:00
Jeremy Soller 29a626cd7c Merge branch 'unistd' into 'master'
Exec Functions (again) (again)

See merge request redox-os/relibc!144
2018-06-28 19:24:04 +00:00
Paul Sajna 5c5e237042 Exec Functions (again) (again) 2018-06-28 19:24:04 +00:00
Jeremy Soller da992bff56 Merge branch 'master' into 'master'
Fix off-by-one error and remove utf8 check in mktemp

See merge request redox-os/relibc!148
2018-06-28 11:36:02 +00:00
jD91mZM2 8e7cd11bc0 Fix CI 2018-06-28 08:31:34 +02:00
jD91mZM2 2c0f9ce747 Fix off-by-one error and remove utf8 check in mktemp 2018-06-28 08:03:17 +02:00
Jeremy Soller e4be43f617 Adjust list of expected binaries 2018-06-27 15:12:14 -06:00
Jeremy Soller 2e3eda4612 Add more expected files 2018-06-27 15:08:29 -06:00
Jeremy Soller cf6c8093ab Update expected output 2018-06-27 15:06:19 -06:00
Jeremy Soller 1f1665fd58 Merge branch 'master' into 'master'
Add the few last things to get gcc_complete working

See merge request redox-os/relibc!146
2018-06-27 21:02:30 +00:00
Jeremy Soller abbf0c9609 Add mktemp test binary to gitingore 2018-06-27 14:33:47 -06:00
Jeremy Soller 2dbe7ebee0 Update ralloc 2018-06-27 14:33:03 -06:00
Jeremy Soller b5da8aa35c Merge branch 'mggmuggins/ci' into 'master'
Add Gitlab CI

See merge request redox-os/relibc!140
2018-06-27 20:31:11 +00:00
Jeremy Soller 6939ca7d7a Merge branch 'mktemp' into 'master'
implement mktemp

See merge request redox-os/relibc!145
2018-06-27 20:22:12 +00:00
Paul Sajna 776491bae9 implement mktemp 2018-06-27 20:22:12 +00:00
jD91mZM2 a6ffd2cc46 Update inttypes to match the revert of ints 2018-06-27 08:08:14 +02:00
jD91mZM2 cbc3723c66 Fix signal not being linked correctly 2018-06-26 17:16:56 +02:00
jD91mZM2 727324fd73 Apparently cbindgen works on constants 2018-06-26 16:57:56 +02:00
jD91mZM2 9de73d0e5b Add uname and gethostname 2018-06-26 16:41:19 +02:00
jD91mZM2 844e244851 Use both Tag and Type 2018-06-26 16:05:02 +02:00
jD91mZM2 3927b0ab44 Revert int definitions 2018-06-26 14:10:20 +02:00
jD91mZM2 5fc1459eb9 signal: Make constants visible from C 2018-06-26 11:23:22 +02:00
jD91mZM2 0776de1ae6 Fix inttypes 2018-06-26 11:10:44 +02:00
jD91mZM2 257040e164 Fix a few stat-related things 2018-06-26 10:47:48 +02:00
jD91mZM2 ad324a0e4d Use global_asm for setjmp instead 2018-06-26 10:21:44 +02:00
jD91mZM2 feed73ffcc inttypes 2018-06-26 09:51:07 +02:00
jD91mZM2 5537817594 Export libm as well 2018-06-26 08:35:27 +02:00
jD91mZM2 441bf9f00b Add the few last things to get gcc_complete working 2018-06-25 11:43:44 +02:00
Jeremy Soller a63e6b3dd8 Merge branch 'master' into 'master'
Revert openlibm install script

See merge request redox-os/relibc!143
2018-06-24 18:50:40 +00:00
jD91mZM2 320eb0ecd0 Revert openlibm install script
Turns out that this only worked because I didn't clean before rebuilding, so it still had access to the old files. Sorry.
2018-06-24 20:19:06 +02:00
Jeremy Soller f265d7c5be Fix linking issues with lang items 2018-06-24 09:56:08 -06:00
Jeremy Soller 878f466b67 Update to new ralloc, new panic implementation, new compiler-builtins 2018-06-24 09:50:15 -06:00
Jeremy Soller be0aed56bc Merge branch 'master' into 'master'
Fix openlibm & fenv and add more integer types

See merge request redox-os/relibc!141
2018-06-24 13:18:34 +00:00
jD91mZM2 72e9525828 Add U?INT([0-9]+)_LEAST([0-9]+)_MIN/MAX macros 2018-06-24 14:27:42 +02:00
jD91mZM2 3e67314b97 Fix openlibm & fenv and add more integer types 2018-06-24 14:12:24 +02:00
SamwiseFilmore 59f1b37be8 Fix dumb mistake 2018-06-24 00:51:37 +00:00
SamwiseFilmore 382c6efb39 Add Gitlab CI 2018-06-24 00:48:54 +00:00
Jeremy Soller 7f0908eb8e Merge branch 'master' into 'master'
Reuse musl's setjmp implementation

See merge request redox-os/relibc!139
2018-06-23 17:46:01 +00:00
jD91mZM2 2283243d95 Replace setjmp lib.rs with empty file 2018-06-23 17:38:15 +02:00
jD91mZM2 4e99b55417 Implement basic setjmp using musl's awesome existing code 2018-06-23 17:38:10 +02:00
Jeremy Soller 6e67d30486 Merge branch 'master' into 'master'
Install openlibm from Makefile

See merge request redox-os/relibc!138
2018-06-23 08:33:27 +00:00
jD91mZM2 829bc64ad6 Remove unused import from test 2018-06-23 07:54:36 +02:00
Tom Almeida 7e731e0b01 Made sure lazy_static works with no_std 2018-06-23 13:08:28 +08:00
jD91mZM2 5945de62cb Install openlibm from Makefile 2018-06-23 06:54:23 +02:00
Tom Almeida c7bdd31a18 Merged relibc (#311db758) with branch 2018-06-23 05:13:02 +08:00
Tom Almeida 6bc28203ca Changed FILE to use a vector as a buffer instead of raw pointers. This allows us to remove the large majority of unsafe blocks from the code 2018-06-23 05:01:43 +08:00
jD91mZM2 12ce441f5c Use static mut over UnsafeCell 2018-06-22 22:40:30 +02:00
Tom Almeida b5529c9b71 Fixed some issues with temporary files and moved some raw pointers to Option<&T>s 2018-06-23 04:28:03 +08:00
Tom Almeida 5921f00e90 Changed FILE to use a vector as a buffer instead of raw pointers. This allows us to remove the large majority of unsafe blocks from the code 2018-06-23 04:28:00 +08:00
Jeremy Soller 8fd77a4b13 Merge branch 'master' into 'master'
Fix undefined behavior

See merge request redox-os/relibc!137
2018-06-22 20:07:31 +00:00
Tom Almeida 43a3c5677a Merged relibc (20/06/2018) with branch 2018-06-23 03:49:19 +08:00
Tom Almeida 50bfebfe3e Fixed some issues with temporary files and moved some raw pointers to Option<&T>s 2018-06-23 03:44:33 +08:00
Tom Almeida 90c6937f17 Changed FILE to use a vector as a buffer instead of raw pointers. This allows us to remove the large majority of unsafe blocks from the code 2018-06-23 03:44:30 +08:00
jD91mZM2 ea24699798 Fix undefined behavior
Transmuting from an immutable to a mutable reference is undefined
behavior in Rust, with the exception of UnsafeCell which tells the
optimizer to not draw too many conclusions. Sadly UnsafeCell::get cannot
yet be used in statics (see https://github.com/rust-lang/rust/issues/51718),
so this works around that by making the statics into functions and
making C macros to call those.
2018-06-22 21:17:44 +02:00
jD91mZM2 3034114c14 Fix broken comment 2018-06-22 15:02:34 +02:00
Jeremy Soller ccb74c6efc Merge branch 'master' into 'master'
Add empty locale functions

See merge request redox-os/relibc!135
2018-06-22 12:59:10 +00:00
jD91mZM2 0a3c8abe95 Fix setlocale return value 2018-06-22 14:54:16 +02:00
jD91mZM2 996445a6a3 Add empty locale functions 2018-06-22 14:54:10 +02:00
Jeremy Soller 05f7371e46 Merge branch 'master' into 'master'
Add scanf

See merge request redox-os/relibc!134
2018-06-21 16:58:41 +00:00
jD91mZM2 91221645c5 Add *scanf to header 2018-06-21 18:52:41 +02:00
jD91mZM2 5936c7a76e Add scanf 2018-06-21 17:16:56 +02:00
Tom Almeida 77b160c70d Fixed some issues with temporary files and moved some raw pointers to Option<&T>s 2018-06-21 09:33:21 +08:00
Jeremy Soller 6f8fff4b1c Merge branch 'sys_wait_macros' into 'master'
sys_wait: implement C macros properly

See merge request redox-os/relibc!133
2018-06-20 18:43:34 +00:00
Jasen Borisov 06a8d5d89d sys_wait: implement C macros properly
Remove the broken Rust functions and instead provide C macros in a
`include/bits` header. The C macros were taken from musl.
2018-06-20 19:40:38 +01:00
Tom Almeida 454ce67d45 Changed FILE to use a vector as a buffer instead of raw pointers. This allows us to remove the large majority of unsafe blocks from the code 2018-06-21 00:20:21 +08:00
Jeremy Soller 895e250564 Add aligned_alloc 2018-06-20 09:53:27 -06:00
Jeremy Soller 9d38494435 Fix missing strtol, strtoul 2018-06-20 09:44:09 -06:00
Jeremy Soller 1b653c4e60 Update ralloc, fix invalid c++ names 2018-06-20 08:48:56 -06:00
Jeremy Soller 009ceec188 Merge branch 'sys_wait_fix' into 'master'
Fix compilation error in `sys_wait`

See merge request redox-os/relibc!132
2018-06-14 20:09:46 +00:00
Jasen Borisov 326078a578 Fix compilation error in sys_wait 2018-06-14 20:15:25 +01:00
Jeremy Soller c5552cbb39 Merge branch 'fix-81' into 'master'
Add `sys_wait` functions (Fixes #81)

Closes #81

See merge request redox-os/relibc!131
2018-06-14 13:45:32 +00:00
stratact 3fa220237d Add sys_wait functions (Fixes #81) 2018-06-14 05:08:55 -07:00
Jeremy Soller a573549df8 Update links to gitlab 2018-06-12 12:30:45 -06:00
Jeremy Soller fd05aca991 Update README.md 2018-05-24 15:00:40 -06:00
Jeremy Soller 1f9f7ce6c8 Merge pull request #127 from stratact/master
Update `platform::rawfile`
2018-05-24 14:36:06 -06:00
stratact 3aa01b6907 Remove pointless cast 2018-05-24 13:27:24 -07:00
stratact a7a415603f Fix stupid mistake 2018-05-24 13:04:58 -07:00
stratact 16c51a297d Use the right C types from platform::types 2018-05-24 12:29:59 -07:00
Jeremy Soller f0227e737e Merge pull request #128 from ids1024/lifetime
Make functions taking raw pointer return &'a instead of &'static
2018-05-24 12:44:19 -06:00
Jeremy Soller aead6d8fd0 Merge pull request #129 from ids1024/cstr
Simplify cstr_from_bytes_with_nul_unchecked()
2018-05-24 12:43:48 -06:00
Ian Douglas Scott 5bcf1d42ff Simplify cstr_from_bytes_with_nul_unchecked()
The original implementation is modified from the `Cstr` method, but the
complexity there exists because it is trying to convert to the DST `Cstr`.
2018-05-24 11:27:35 -07:00
Ian Douglas Scott cbd0d0473c Make functions taking raw pointer return &'a instead of &'static
This is technically more correct, and matches the pointer methods in the
standard library.
2018-05-24 11:13:55 -07:00
stratact b389e4831d Have open() and dup() match -1 for Err instead of 0 2018-05-24 10:33:15 -07:00
stratact 9daae71c2a Use the super module instead of sys 2018-05-23 19:35:28 -07:00
stratact bb9d0e4aa1 Implement RawFile::from_raw_fd() 2018-05-23 13:14:42 -07:00
stratact 285d1b05c4 Implement RawFile::open() and add *_raw_df() convenience methods 2018-05-23 11:05:43 -07:00
stratact 7ca5fac214 Implement RawFile::dup() completely 2018-05-23 08:00:53 -07:00
Jeremy Soller 3311a700e0 Merge pull request #126 from ProgVal/update-ralloc
Update ralloc. Closes GH-83.
2018-05-20 07:27:15 -06:00
Valentin Lorentz 0b6d6549f1 Update ralloc. Closes GH-83. 2018-05-20 14:13:36 +02:00
Jeremy Soller ed12713aa8 Update gitignore for tests 2018-05-15 18:35:29 -06:00
Jeremy Soller c647fdfed3 Merge pull request #116 from matijaskala/patch-1
Add optimized version of memchr
2018-05-15 18:33:31 -06:00
Jeremy Soller 8eec109cc0 Merge pull request #120 from Majora320/master
Implement clock() and add CLOCK_* constants
2018-05-15 18:32:29 -06:00
Jeremy Soller c8d4ea3ee6 Merge pull request #123 from Arcterus/qsort-real
stdlib: implement qsort() as an introsort
2018-05-15 18:31:50 -06:00
Jeremy Soller 4fb4790890 Merge pull request #122 from Arcterus/qsort
Fix a bug in printf()
2018-05-15 18:31:21 -06:00
Matija Skala 9bbb070104 Add optimized version of memchr 2018-05-15 21:06:17 +02:00
Alex Lyon f5ded007c6 stdlib: recurse into the smaller partition when sorting 2018-05-13 16:16:48 -07:00
Alex Lyon 4d3ac1c0dc stdlib: save stack space by looping in introsort_helper() 2018-05-13 03:29:53 -07:00
Alex Lyon b15aa83a8a stdlib: move insertion sort from introsort() into a separate function 2018-05-13 03:15:16 -07:00
Alex Lyon aa21e5fc3f stdlib: implement qsort() as an introsort 2018-05-13 03:07:00 -07:00
Jeremy Soller 6e8e6ad5d2 Merge pull request #121 from Arcterus/strtoul
stdlib: implement strtoul() and strtol() using a macro
2018-05-12 06:24:18 -06:00
Alex Lyon 0cabecd5b5 stdio, string, platform: fix a bug in printf() involving chars
Because we were previously converting the bytes in the format
string into Rust's char type and then printing that using the
format machinery, byte values that were not valid single-byte
UTF-8 characters failed to print correctly.  I found this while
trying to implement qsort() because the output of my test program
was mysteriously incorrect despite it working when I used glibc.
2018-05-11 23:09:12 -07:00
Moses Miller d14d0b5965 Fix various formatting issues 2018-05-11 22:01:51 -07:00
Moses Miller 766e00c69e Implement conversion of nanoseconds to clocks in terms of CLOCKS_PER_SEC 2018-05-11 17:22:01 -07:00
Moses Miller 3d1a66f270 Add CLOCKS_PER_SEC 2018-05-11 16:26:56 -07:00
Moses Miller 9d8758006d Change 1000000 to 1_000_000 2018-05-11 11:41:18 -07:00
Alex Lyon 1bcc40c08f stdlib: manually fix formatting 2018-05-11 09:31:58 -07:00
Alex Lyon 7647db27c0 stdlib: implement strtoul() and strtol() using a macro 2018-05-11 01:48:27 -07:00
Moses Miller 56458e5e4c Condense 5 lines into 1 2018-05-10 20:48:13 -07:00
Moses Miller 1ecd5f8f21 Implement clock() and add CLOCK_* constants 2018-05-10 20:31:35 -07:00
Jeremy Soller 018f950851 Merge branch 'master' of https://github.com/jeizsm/relibc 2018-04-26 20:14:53 -06:00
Jeremy Soller 08091ab2a9 Merge branch 'stat' of https://github.com/sajattack/relibc 2018-04-26 20:12:57 -06:00
Marat Safin ff37adeeba add asctime
Signed-off-by: Marat Safin <jeizsm@gmail.com>
2018-04-19 07:59:58 +03:00
Jeremy Soller 43e6cad33f Merge pull request #112 from jeizsm/master
add gmtime and difftime
2018-04-17 10:07:12 -06:00
Marat Safin 8015878a73 use static variable for gmtime 2018-04-15 08:56:09 +03:00
Marat Safin 2b21dca567 add gmtime and difftime 2018-04-14 09:01:04 +03:00
Jeremy Soller 93e2e16077 Merge pull request #118 from dlrobertson/fix_ci
ci: Ensure that the correct compiler is installed
2018-04-08 12:16:01 -06:00
Dan Robertson 6a4220458c ci: Ensure that the correct compiler is installed
Ensure that a compiler is installed when the aarch64 CI build is run.
2018-04-08 13:52:34 +00:00
Jeremy Soller 722732b616 Merge pull request #114 from HermannDppes/format
Run ./fmt.sh
2018-04-04 16:07:37 -06:00
Hermann Döppes dc769fd977 Run ./fmt.sh 2018-04-04 22:52:06 +02:00
Jeremy Soller 3f627b1b40 Remove asserts 2018-04-03 19:52:50 -06:00
Jeremy Soller 5b1e11d1b1 Fix minimum alignment for malloc_inner 2018-04-03 19:52:34 -06:00
Jeremy Soller 62fbff93bc Clean up malloc 2018-04-03 19:51:50 -06:00
Jeremy Soller 742339ca9e Hacky version of memalign 2018-04-03 19:45:36 -06:00
Jeremy Soller dabd8dc6a2 Move memory handling into string, do not use compiler_builtins for memory handling 2018-03-27 21:28:48 -06:00
Jeremy Soller 79d05d7eda Build variadic functions as part of relibc 2018-03-27 21:13:11 -06:00
Jeremy Soller b849165438 Fix MAX_C macros 2018-03-27 20:33:04 -06:00
Jeremy Soller ea804582b9 Rename sys header crates, add mman constants 2018-03-27 20:25:42 -06:00
Jeremy Soller afdc80629f Fix Makefile spurious rebuilds
Add mem* functions to stdio
Add constant int functions
2018-03-27 20:14:22 -06:00
Paul Sajna 92493a55b9 fix harderer 2018-03-26 21:23:36 -07:00
Paul Sajna bc0763f3ef fmt 2018-03-26 21:17:14 -07:00
Paul Sajna 14957bb8dc fix harder 2018-03-26 21:14:38 -07:00
Jeremy Soller 6999363916 Create build directory if necessary in openlibm target 2018-03-26 20:41:02 -06:00
Jeremy Soller 78c8c2171b Add install target 2018-03-26 20:13:45 -06:00
Jeremy Soller 8c218b1608 Build crt0 as object file 2018-03-26 20:06:46 -06:00
Jeremy Soller d071522bc5 Add libm to phony 2018-03-26 19:59:42 -06:00
Jeremy Soller adcd0c9900 Only update libcrt0.a if there is a source change 2018-03-26 19:49:21 -06:00
Jeremy Soller e1abe80992 Fix CI 2018-03-26 19:34:45 -06:00
Jeremy Soller 6abd64ae16 Disable cargo cache 2018-03-26 19:13:49 -06:00
Jeremy Soller 47ee733afa Complete Makefile 2018-03-26 19:12:20 -06:00
Jeremy Soller ae137dbc03 Prepare for cross compiled openlibm 2018-03-26 18:50:51 -06:00
Jeremy Soller d9e4622f83 Add Makefile (WIP) 2018-03-26 18:38:29 -06:00
Jeremy Soller f0b41aa57e Merge pull request #104 from dlrobertson/rename
stdio: Implement rename
2018-03-26 18:22:22 -06:00
Jeremy Soller e39d2d61fa Merge branch 'master' into rename 2018-03-26 18:22:13 -06:00
Paul Sajna c7e9ec8ae2 fix 2018-03-26 16:47:12 -07:00
Paul Sajna c7ad4d3997 Merge branch 'stat' of github.com:sajattack/relibc into stat 2018-03-26 15:48:06 -07:00
Paul Sajna cafb76abdd mkfifo and constants 2018-03-26 15:47:36 -07:00
Paul 6d11736603 Merge branch 'master' into stat 2018-03-26 15:34:43 -07:00
Jeremy Soller bbf5c34ce8 Merge pull request #108 from mmstick/kill
Implement kill() and killpg()
2018-03-25 18:56:09 -06:00
Michael Aaron Murphy 43e95a9b92 Implement kill() and killpg() 2018-03-25 14:40:44 -04:00
Dan Robertson 57a17cb05f stdio: Implement rename 2018-03-25 14:41:42 +00:00
Paul Sajna 35dbc8d351 minor fixes 2018-03-23 13:37:56 -07:00
Paul Sajna 304473b68f Implement fstat, stat, lstat 2018-03-23 13:27:41 -07:00
Jeremy Soller 5f9170d861 Merge pull request #105 from jeizsm/master
add clock_gettime and time
2018-03-23 08:48:01 -06:00
Marat Safin 58b2b64183 add clock_gettime and time 2018-03-23 16:57:33 +03:00
Paul Sajna 29a6d24309 chmod and fchmod 2018-03-22 17:41:19 -07:00
Jeremy Soller 66fa211a05 Merge pull request #85 from Tommoa/master
Added functions for stdio.h
2018-03-22 10:07:57 -06:00
Tom Almeida 97e165d8c7 Merge branch 'master' into master 2018-03-22 12:49:55 +08:00
Tom Almeida e1b20ed368 Fixed getopt passing the wrong argument to stdio functions 2018-03-22 12:43:05 +08:00
Jeremy Soller e5849526a0 Update lock file 2018-03-21 21:16:21 -06:00
Jeremy Soller fcf1104ea5 Merge pull request #102 from sajattack/rand
implement rand and srand using the rand crate
2018-03-21 21:15:30 -06:00
Jeremy Soller 0ec7d0bc57 Merge branch 'master' into rand 2018-03-21 21:14:35 -06:00
Paul Sajna 5f243a21f7 Merge branch 'rand' of github.com:sajattack/relibc into rand 2018-03-21 20:13:27 -07:00
Jeremy Soller e34d32aefe Update gitignore 2018-03-21 21:12:58 -06:00
Paul Sajna cdc6209ff4 fix comment 2018-03-21 20:12:22 -07:00
Jeremy Soller 26b533c978 Merge branch 'master' into rand 2018-03-21 21:08:33 -06:00
Jeremy Soller ae097074ec Merge branch 'master' into master 2018-03-21 20:59:14 -06:00
Jeremy Soller 77b7a98d4e Merge pull request #97 from Arcterus/master
unistd: add a preliminary implementation of getopt()
2018-03-21 20:55:43 -06:00
Paul Sajna cc5a4e92ce fmt 2018-03-20 19:45:45 -07:00
Paul Sajna a24f537a38 test 2018-03-20 19:44:49 -07:00
Paul Sajna 4db812d34d implement rand and srand 2018-03-20 19:31:58 -07:00
Tom Almeida 19705ccc87 Merged master into master 2018-03-20 23:48:07 +08:00
Tom Almeida dbc3e413cc Fixed clearerr actually doing nothing 2018-03-20 23:43:42 +08:00
Alex Lyon 2751d457bf unistd: use .is_null() for pointers 2018-03-19 15:05:38 -07:00
Alex Lyon 42a6693a0b unistd: fix off-by-one in getopt() 2018-03-19 14:50:41 -07:00
Alex Lyon af78348d4a unistd: add a preliminary implementation of getopt() 2018-03-19 14:50:41 -07:00
Tom Almeida 90aec2076e Merge branch 'master' into master 2018-03-19 14:29:58 +08:00
Jeremy Soller edead8e085 Merge pull request #98 from jeizsm/master
refactor nanosleep
2018-03-18 16:40:30 -06:00
Jeremy Soller 045a510ce5 Merge pull request #92 from tdbgamer/feature/strtok
Implement strtok
2018-03-18 16:37:06 -06:00
Jeremy Soller ca61b4cb63 Merge pull request #100 from jrraymond/bsearch
implement bsearch
2018-03-18 16:36:24 -06:00
Justin Raymond d3583e11d2 fix c99 mode 2018-03-18 17:58:29 -04:00
Justin Raymond a0c76f7ce5 bsearch 2018-03-18 17:11:43 -04:00
Marat Safin 31516989c0 refactor nanosleep 2018-03-18 12:29:38 +03:00
Timothy Bess 3a89f66cfd * simplify strtok implementation 2018-03-18 00:05:13 -04:00
Jeremy Soller 5cec358a45 Merge pull request #86 from dlrobertson/add_headers
Add some of the basics for netinet/in.h and sys/socket.h
2018-03-17 18:11:46 -06:00
Jeremy Soller befca562df Merge pull request #95 from ids1024/travis
Use build matrix on Travis CI
2018-03-17 18:11:16 -06:00
Ian Douglas Scott b7d68895b0 Use build matrix on Travis CI
This makes it easy to see which target failed to build.
2018-03-17 16:00:54 -07:00
Timothy Bess 06de920be6 * remove unnecessary assignments 2018-03-17 12:58:10 -04:00
Tom Almeida d8139238e7 Merged master with branch 2018-03-18 00:22:08 +08:00
Tom Almeida c24d1e2b36 Removed all function pointers in FILE, moved internal functions to be member functions of FILE, made relevant *mut FILEs into &mut FILE and made suitable functions safe again 2018-03-18 00:20:21 +08:00
Tom Almeida d7965f2598 Made it so that AtomicBool exports as volatile char 2018-03-18 00:19:08 +08:00
Tom Almeida 25501b3640 Changed redox lseek to have the same function signature as the linux version 2018-03-18 00:18:14 +08:00
Tom Almeida b33c3a8e4f Merge branch 'master' into master 2018-03-18 00:06:59 +08:00
Jeremy Soller 362849f0f6 Merge pull request #91 from tdbgamer/master
Issue #89: Fix return types on string functions
2018-03-17 07:04:52 -06:00
Timothy Bess e91891625f * add strtok_r 2018-03-17 03:56:40 -04:00
Timothy Bess 898cf98ccc * fix test case a bit
* remove unnecessary cast
2018-03-17 03:06:59 -04:00
Timothy Bess f60fafe8fb * create basic strtok
* add test and expected output
2018-03-17 02:58:08 -04:00
Timothy Bess bebbd35e1a Issue #89
* fix return types
* fix type casts on returns
2018-03-17 00:50:22 -04:00
Tom Almeida 2cb0a994b8 Merge branch 'master' into master 2018-03-16 23:26:11 +08:00
Tom Almeida 659d3d1042 Changed object type of function pointers from Option<*const (Fn(...))> to Option<fn(...)> for readability 2018-03-16 23:14:43 +08:00
Jeremy Soller d75535974a Merge pull request #74 from sajattack/wait
wait and waitpid
2018-03-16 09:03:35 -06:00
Tom Almeida 81d96c214a Ran formatting for freopen() 2018-03-16 20:47:32 +08:00
Tom Almeida 8d40424020 Added freopen() and relevant tests 2018-03-16 20:24:40 +08:00
Paul Sajna 2610fdd126 Merge branch 'wait' of github.com:sajattack/relibc into wait 2018-03-15 16:22:23 -07:00
Paul Sajna c568ca2932 test cleanup 2018-03-15 16:18:35 -07:00
Jeremy Soller b2b7804f5b Merge branch 'master' into wait 2018-03-15 15:51:29 -06:00
Paul Sajna cdfde8c0d4 more requested changes 2018-03-15 11:55:37 -07:00
Dan Robertson 16e82636fb Add basic structures for netinet/in.h crate
Add the basic structures for the netinet/in.h header.
2018-03-15 17:34:30 +00:00
Dan Robertson 01081729c8 Add structures and stub fns for sys/socket.h
Add some of the basic structures and stub functions for sys/socket.h
2018-03-15 17:34:30 +00:00
Tom Almeida 41b96fede3 Added a different internal function for redox 2018-03-15 15:57:19 +08:00
Tom Almeida c4c8b73903 Formatted stdio files 2018-03-15 15:34:39 +08:00
Tom Almeida 8648fd39c4 Added some constants in linux for file modes in the new branch 2018-03-15 15:32:46 +08:00
Tom Almeida b0492eba84 Added some tests for stdio 2018-03-15 15:28:14 +08:00
Tom Almeida 7f2b720962 Implemented stdio functions 2018-03-15 15:27:07 +08:00
Tom Almeida 046ce1468e Removed an unused import from printf 2018-03-15 15:23:38 +08:00
Tom Almeida e73678d8ad Added a FileReader struct 2018-03-15 15:22:18 +08:00
Tom Almeida f20878c592 Added lseek to syscalls 2018-03-15 15:21:52 +08:00
Tom Almeida aa8b14e107 Added some constants in linux for file modes 2018-03-15 15:21:02 +08:00
Jeremy Soller a1baf1c92d Merge pull request #75 from azymohliad/master
Implement strstr() and strpbrk() from string.h
2018-03-14 21:22:59 -06:00
Jeremy Soller b419e150d1 Merge pull request #84 from dlrobertson/fixup_signal
Update cbindgen and fix issues with signal
2018-03-14 20:23:08 -06:00
Dan Robertson f1d802dc1e signal: sigaction struct should not be a typedef
The sigaction struct should not be a typedef, but the sigset_t struct
should be a typedef.
2018-03-15 01:07:44 +00:00
Dan Robertson 6d110ef0cb Use a sys module for OS specific information
Update cbindgen to parse modules with a path attribute and revert the
following commits:
 - 996fad7092.
 - cfe98ab3b2.
2018-03-15 00:53:35 +00:00
Paul Sajna 52acce0d34 handle the null case 2018-03-14 12:37:24 -07:00
Jeremy Soller 54c0e501e3 Merge pull request #82 from Tommoa/master
Actual working tests on strspn and strcspn
2018-03-13 21:02:04 -06:00
Tom Almeida b2d01a67f2 Actual working tests on strspn and strcspn 2018-03-14 10:55:01 +08:00
Jeremy Soller cfe98ab3b2 Fix constants in signal.h 2018-03-13 19:58:52 -06:00
Andrii Zymohliad cd2312fd56 Merge remote-tracking branch 'upstream/master' 2018-03-14 09:55:59 +08:00
Jeremy Soller d6e210b1fd Merge branch 'signal' of https://github.com/dlrobertson/relibc into dlrobertson-signal 2018-03-13 19:54:49 -06:00
Jeremy Soller 996fad7092 Fix fcntl header constants 2018-03-13 19:52:15 -06:00
Jeremy Soller 1d6115fd09 Update cbindgen and lock file 2018-03-13 19:41:31 -06:00
Jeremy Soller b09435f17d Merge pull request #78 from Tommoa/master
Yet another fix for strcspn and strspn.
2018-03-13 19:39:08 -06:00
Tom Almeida d3c2e99ed7 Merge branch 'master' into master 2018-03-14 08:56:52 +08:00
Tom Almeida d058390b75 The erroneous use came back! 2018-03-14 08:56:18 +08:00
Tom Almeida 122f6cfef5 Merge branch 'master' of github.com:Tommoa/relibc 2018-03-14 08:54:10 +08:00
Tom Almeida 9d46fa4d8c Missed having both loops look at themselves. I'm not sure how long this has been here. 2018-03-14 08:48:56 +08:00
Jeremy Soller 010e171071 Merge pull request #80 from dlrobertson/master
Add the no_mangle attribute to fns
2018-03-13 18:28:09 -06:00
Andrii Zymohliad 40efea056b Reimplement strpbrk() using strcspn() 2018-03-14 08:06:51 +08:00
Paul Sajna 2fd2a9c520 Merge branch 'wait' of github.com:sajattack/relibc into wait 2018-03-13 16:55:32 -07:00
Paul Sajna d177b8e974 requested change 2018-03-13 16:55:16 -07:00
Dan Robertson d3e44da527 Add the no_mangle attribute to fns
Add the no_mangle attribute to functions without it.
2018-03-13 23:27:32 +00:00
Tom Almeida ca82b6df5b remove erroneous import in string 2018-03-14 01:03:48 +08:00
Tom Almeida d6a7942ec4 Change the type of byteset from [u8] to [usize] in strcspn and strspn. Hopefully this is the last bug in these! 2018-03-14 01:01:23 +08:00
Jeremy Soller 1e661cdbef Merge branch 'master' into wait 2018-03-13 07:11:35 -06:00
Jeremy Soller 8d0308d3ce Merge branch 'master' into master 2018-03-12 21:59:06 -06:00
Jeremy Soller 13b7119994 Merge pull request #77 from dlrobertson/add_extern_crate
Add missing extern crate statements
2018-03-12 21:56:12 -06:00
Jeremy Soller dd847cc67e Return with 0 in all tests 2018-03-12 21:55:46 -06:00
Dan Robertson ef8a64c101 Add missing extern crate statements
Add missing extern crate statements.
2018-03-13 02:17:32 +00:00
Andrii Zymohliad c4620be999 Prettify strpbrk and strstr tests 2018-03-12 18:22:39 +08:00
Andrii Zymohliad 1e969afd43 Implement strpbrk(), add strpbrk test 2018-03-12 18:01:12 +08:00
Andrii Zymohliad a1de0ef8a1 Implement strstr(), add strstr test 2018-03-12 14:55:02 +08:00
Paul Sajna 211f95155a fmt 2018-03-11 21:24:06 -07:00
Paul Sajna b35abd1065 test and fixes 2018-03-11 21:20:59 -07:00
Paul Sajna 224cf04cf3 Merge branch 'master' of github.com:redox-os/relibc into wait 2018-03-11 20:28:39 -07:00
Jeremy Soller 7912332137 Mark sys_time functions no_mangle 2018-03-11 21:26:21 -06:00
Jeremy Soller 3e354aed04 Merge branch 'fix_includes' of https://github.com/dlrobertson/relibc into dlrobertson-fix_includes 2018-03-11 21:22:07 -06:00
Jeremy Soller 232e364f60 Remove warnings, build openlibm without stack protector 2018-03-11 21:20:56 -06:00
Jeremy Soller 477e8eb4e0 Exit run, expected, or verify on error in loop 2018-03-11 21:11:08 -06:00
Jeremy Soller 41e552b696 Only expect output for a whitelist of binaries 2018-03-11 21:04:53 -06:00
Jeremy Soller 7c13ec153e Update expects 2018-03-11 21:00:53 -06:00
Jeremy Soller ee13ed44d3 Merge pull request #69 from sajattack/stat
stat is now autogenerated correctly
2018-03-11 20:38:20 -06:00
Dan Robertson cc5669939e Fix include in resource.h and add SIZE_MAX
The rusage struct makes use of the timeval structure. Make sure to
include sys/time.h so that the type is known.

Add SIZE_MAX to stdint.h

sys/resource expects the defined structures to not be defined with a
typedef.
2018-03-12 02:38:07 +00:00
Jeremy Soller 7c305c5c0d Merge branch 'master' into stat 2018-03-11 19:31:59 -06:00
Paul Sajna c5dd3f8706 Update Cargo.lock 2018-03-11 17:01:25 -07:00
Paul Sajna ccb29cfa2c wait and waitpid 2018-03-11 16:50:46 -07:00
Dan Robertson 50eab4369d Add signal.h
Create stubs for signal.h
2018-03-11 21:36:02 +00:00
Jeremy Soller 1b1ff5c750 Merge pull request #66 from w0xel/master
Add implementation for a64l
2018-03-11 13:11:06 -06:00
Paul Sajna ca57f30425 Update cbindgen 2018-03-11 12:06:46 -07:00
Paul Sajna a000f1a2c0 fmt 2018-03-11 11:26:35 -07:00
Paul Sajna bc98f6a029 git rm include/sys/stat.h 2018-03-11 11:22:10 -07:00
Paul Sajna 76c4520cea stat is now autogenerated correctly 2018-03-11 11:19:56 -07:00
Jeremy Soller 4f5e978634 Merge pull request #68 from Tommoa/master
Fixed strcspn and strspn
2018-03-11 11:09:55 -06:00
Tom Almeida 1f9f9f7d55 Made an error in the logic of strcspn and strspn that would cause a bit shift much too large 2018-03-11 23:53:15 +08:00
Sebastian Würl 55bd1adae0 stdlib: cleaner raw pointer handling in a64l 2018-03-11 13:23:36 +01:00
Sebastian Würl d4d808fcc8 Add implementation for a64l 2018-03-11 11:55:22 +01:00
Jeremy Soller 8028c35172 Merge pull request #65 from dlrobertson/add_more_crates
Add more crates for missing headers
2018-03-10 21:52:30 -07:00
Jeremy Soller 089b41da23 Merge pull request #62 from jrraymond/strrchr
implement strrchr
2018-03-10 21:51:21 -07:00
Jeremy Soller c2a76870b5 Merge pull request #63 from Tommoa/master
Implemented fputc, fputs, and puts
2018-03-10 21:50:09 -07:00
Dan Robertson 3699b53ba2 float: Add crate for float.h
Add a crate with stubbed functions for the float.h header.
2018-03-10 21:16:55 +00:00
Dan Robertson f29e6b00d7 fenv: Add crate for fenv.h
Add a crate for building out stub functions and structures for the fenv
header.
2018-03-10 21:16:54 +00:00
Dan Robertson ca7f3a00e6 wait: Add crate for sys/wait.h
Add the basics of sys/wait.h so that we get a bit closer to being able
to compile libc-test.
2018-03-10 21:16:54 +00:00
Dan Robertson c6f16547ff resource: Add crate for sys/resource.h
Add the basics of sys/resource.h so that work can begin on sys/wait.h
2018-03-10 19:14:20 +00:00
Dan Robertson 2f718d40d6 mman: mman.h should be located at sys/mman.h
- Update target location of mman.h to sys/mman.h
 - Add more types to sys/type.h
2018-03-10 19:14:16 +00:00
Justin Raymond 63ee4de162 Update lib.rs 2018-03-10 12:39:30 -05:00
Justin Raymond 23a409204f Update .gitignore 2018-03-10 12:36:42 -05:00
Tom Almeida 49be92f87f ran fmt.sh cause I'm an idiot 2018-03-11 00:39:43 +08:00
Tom Almeida 8374fcb4be implemented fputc, fputs, and puts 2018-03-11 00:33:00 +08:00
Justin Raymond a1e62baad7 Merge branch 'master' into strrchr 2018-03-10 11:11:46 -05:00
Justin Raymond 826cf0c61c implement strrchr 2018-03-10 11:10:19 -05:00
Jeremy Soller ffeefb2a8e Merge pull request #61 from Tommoa/master
Add implementations of strspn, strcspn and strchr
2018-03-10 09:03:32 -07:00
Tom Almeida d0bf830ca7 fixed a logic error in strchr 2018-03-10 23:09:10 +08:00
Tom Almeida b0f8e31b63 ran fmt.sh 2018-03-10 23:01:49 +08:00
Tom Almeida 87ec6dfacb Fixed unused variable in memchr 2018-03-10 22:59:24 +08:00
Tom Almeida 18283feac1 Added implementations of strchr, strcspn and strspn 2018-03-10 22:58:35 +08:00
Jeremy Soller b52a1d612d Merge pull request #59 from Tommoa/master
Add implementations of memchr and memccpy
2018-03-10 07:03:40 -07:00
Jeremy Soller a227338a72 Merge pull request #58 from dlrobertson/sprintf
Add implementations of sprintf and snprintf
2018-03-10 07:00:22 -07:00
Tom Almeida a2a7efa946 Update .gitignore 2018-03-10 21:52:37 +08:00
Tom Almeida d214817c87 readability update in lib.rs 2018-03-10 21:52:06 +08:00
Jeremy Soller 0ee34fe836 Merge branch 'master' into sprintf 2018-03-10 06:46:17 -07:00
Jeremy Soller 639ea0919f Merge pull request #56 from Arcterus/master
string: address performance concerns for strncmp()
2018-03-10 06:43:22 -07:00
Tom Almeida 774856f9b2 Update lib.rs 2018-03-10 21:37:01 +08:00
Tom Almeida 3470882df6 Fixed incorrect return of memccpy 2018-03-10 17:12:05 +08:00
Tom Almeida b013f5f0ed Fixed mem test 2018-03-10 17:05:56 +08:00
Tom Almeida 4f601f4896 Added memchr and memccpy to string 2018-03-10 16:59:53 +08:00
Alex Lyon cfc1014c6e string: fix a couple minor issues in strncmp() 2018-03-09 20:54:42 -08:00
Alex Lyon 50f79e9a0e string: address performance concerns for strncmp() 2018-03-09 20:54:42 -08:00
Dan Robertson 75920d2c12 Add implementations of sprintf and snprintf
Add implementations of sprintf and snprintf so that we can get a bit
closer to compiling libc-test.
2018-03-10 02:33:03 +00:00
Jeremy Soller 3890ec58f0 Merge pull request #49 from sajattack/time
Add time and sys/time
2018-03-09 18:11:51 -07:00
Jeremy Soller 4d67145aa1 Merge pull request #54 from MggMuggins/master
Update README.md
2018-03-09 13:52:46 -07:00
MggMuggins 06a6922cde Merge branch 'master' of https://github.com/redox-os/relibc 2018-03-09 12:41:25 -06:00
MggMuggins d7aa9c44f9 Add Documentation 2018-03-09 12:38:37 -06:00
Paul 7108d0164e Merge branch 'master' into time 2018-03-09 08:37:40 -08:00
Paul Sajna 7e40d8c87b fmt 2018-03-09 07:51:15 -08:00
Paul Sajna 23bb883797 update nanosleep 2018-03-09 07:49:37 -08:00
Jeremy Soller 11043129f2 Merge pull request #52 from dlrobertson/aarch64
Aarch64: Merge the final components
2018-03-09 08:24:37 -07:00
Dan Robertson c2ae141df3 Aarch64: Merge the final components
Merge the final components for Aarch64 support into master.
2018-03-09 14:20:42 +00:00
Paul 031fc5da27 Update Makefile 2018-03-09 05:58:55 -08:00
Paul 5632d96016 Merge branch 'master' into time 2018-03-09 05:52:29 -08:00
Jeremy Soller 77c0a5b430 Merge pull request #47 from sajattack/unistd
implement setid functions and unlink
2018-03-09 06:50:04 -07:00
Paul 4d12c408fd Merge branch 'master' into time 2018-03-09 05:49:37 -08:00
Paul cdf298ba3a Merge branch 'master' into unistd 2018-03-09 05:48:22 -08:00
Jeremy Soller dd0e6187db Merge pull request #50 from Arcterus/master
Preliminary implementation of strtol()
2018-03-09 06:45:39 -07:00
Jeremy Soller b7ac90fd9f Merge branch 'master' into master 2018-03-09 06:45:17 -07:00
Jeremy Soller 580dcd3c08 Merge pull request #48 from sajattack/stat
correction to include guard of stat
2018-03-09 06:43:12 -07:00
Paul Sajna b11c079d69 Makefile fix 2018-03-09 05:34:58 -08:00
Paul Sajna 3c198a3a40 fmt 2018-03-09 05:19:25 -08:00
Paul Sajna 4d4ab1a75f fix and test 2018-03-09 05:18:21 -08:00
Paul Sajna 161d93466c fixes and tests 2018-03-09 04:48:34 -08:00
Paul Sajna e99857d125 sleep and usleep 2018-03-09 03:42:42 -08:00
Alex Lyon dec7ecd06b tests: fix Makefile 2018-03-09 03:37:30 -08:00
Paul Sajna 7e19ce23bd nanosleep 2018-03-09 03:26:45 -08:00
Alex Lyon 9325a29a74 stdlib: make rustfmt happy with strtol() 2018-03-09 03:21:18 -08:00
Alex Lyon f5b1f872a0 stdlib: implement preliminary version of strtol() 2018-03-09 03:07:16 -08:00
Alex Lyon a7e71717cb stdio: add support for %o to printf() 2018-03-09 02:51:50 -08:00
Paul Sajna 083aa0ed55 fmt 2018-03-09 02:47:22 -08:00
Paul Sajna 72909b3f4c add time and sys/time 2018-03-09 02:46:14 -08:00
Paul Sajna 1c1a48b648 fix formatting 2018-03-09 00:56:02 -08:00
Paul Sajna b9a2dfded4 correction to include guard of stat 2018-03-09 00:52:34 -08:00
Paul Sajna a7fba79be7 implement setid functions and unlink 2018-03-09 00:28:46 -08:00
Jeremy Soller e676440e1f Merge pull request #46 from dlrobertson/aarch64
Aarch64: Update syscall usage
2018-03-08 21:26:04 -07:00
Jeremy Soller 89259475ab Merge branch 'master' into aarch64 2018-03-08 21:25:28 -07:00
Jeremy Soller 54655a4e3b Add verification makefile rule 2018-03-08 21:22:17 -07:00
Dan Robertson f83ff041cc Aarch64: Update syscall usage
Don't use syscalls that are non-existent on Aarch64 linux boxes. The
FORK and RMDIR syscalls are no longer present and the CLONE and UNLINKAT
syscalls are used instead.
2018-03-09 04:19:22 +00:00
Jeremy Soller 85766a41ff Expected output 2018-03-08 21:14:46 -07:00
Jeremy Soller 4da873ae79 Merge pull request #43 from MggMuggins/master
Imp va_arg for fcntl; fcntl test
2018-03-08 21:07:39 -07:00
Jeremy Soller 76e53e86fa Merge pull request #45 from redox-os/atof
Implement atof
2018-03-08 21:00:38 -07:00
Jeremy Soller a95a034219 Fix issues by adding support for floating point values in va_list 2018-03-08 20:54:46 -07:00
Jeremy Soller 56e304a2af Fix format 2018-03-08 20:20:21 -07:00
Jeremy Soller 0e766c6b53 Implement atof 2018-03-08 20:17:45 -07:00
Jeremy Soller 96358469a4 Merge branch 'master' into master 2018-03-08 20:17:08 -07:00
MggMuggins c291632492 Imp va_arg for fcntl; fcntl test 2018-03-08 20:56:50 -06:00
Paul Sajna 799c8828c2 mkdir and rmdir 2018-03-08 19:45:16 -07:00
Jeremy Soller 231d7a023a Merge pull request #42 from dlrobertson/use_va_list
fcntl: open should use a va_list
2018-03-08 19:32:34 -07:00
Jeremy Soller 7b3fc9191a Merge pull request #40 from MggMuggins/master
Implement fcntl
2018-03-08 19:24:54 -07:00
Dan Robertson e306e3f855 fcntl: open should use a va_list
The current implementation of open requires the user to pass all three
args to the function. It should use a va_list and allow a user to
provide only the filename and flags.
2018-03-09 02:24:25 +00:00
MggMuggins 0cb3a893a1 Fix compile on redox 2018-03-08 20:19:55 -06:00
Jeremy Soller fb173dc787 Move travis instructions into ci.sh 2018-03-08 19:14:10 -07:00
MggMuggins 14c8125108 Implement fcntl
No tests written yet! See #36
2018-03-08 19:55:35 -06:00
Jeremy Soller 620a459d93 Merge pull request #39 from Arcterus/master
string: fix out of bounds bug in strncmp
2018-03-08 18:34:27 -07:00
Alex Lyon 332ae13af5 string: fix out of bounds bug in strncmp 2018-03-08 17:18:38 -08:00
Jeremy Soller dbe73d4bab Merge pull request #35 from sajattack/patch-1
Add build badge to README
2018-03-08 17:47:28 -07:00
Jeremy Soller d0c9c46ff9 Merge pull request #38 from MggMuggins/master
ctype: tests and reorganize
2018-03-08 17:47:01 -07:00
SamwiseFilmore 46fe488e05 Merge branch 'master' into master 2018-03-08 18:31:14 -06:00
MggMuggins 6ced871d9a ctype: tests and reorganize
Wrote tests for the functions implemented in 40558b2 and maybe made that
test a little more comprehensible.

Also made sure that fmt.sh and test.sh were being executed by bash all
the time (compatibility with other shells).
2018-03-08 18:25:11 -06:00
Paul bb376ff3fb Add build badge to README 2018-03-08 15:27:44 -08:00
Jeremy Soller 284cc4eece Fix formatting 2018-03-08 16:21:04 -07:00
Jeremy Soller cd4082bf9f Fix build harder 2018-03-08 16:09:28 -07:00
Jeremy Soller 07c3ce02be Fix build 2018-03-08 15:52:48 -07:00
Jeremy Soller af78f4819a Merge branch 'master' of github.com:redox-os/relibc 2018-03-08 15:43:23 -07:00
Jeremy Soller 4198055d4a Fix tests 2018-03-08 15:43:17 -07:00
Jeremy Soller 8adf1c3de0 Merge pull request #34 from MggMuggins/master
Finish ctype impls
2018-03-08 15:39:05 -07:00
MggMuggins 42de0a0a46 Merge branch 'master' of https://github.com/redox-os/relibc 2018-03-08 16:29:58 -06:00
MggMuggins 40558b2608 Finish ctype impls; Solve #31 2018-03-08 16:16:51 -06:00
Jeremy Soller cfbe27490f Remove allocation, fix pipe example 2018-03-08 15:00:17 -07:00
Jeremy Soller 0bcabc2163 Merge remote-tracking branch 'sajattack/unistd' 2018-03-08 14:53:07 -07:00
Jeremy Soller 18961114e2 Simplify perror 2018-03-08 14:51:22 -07:00
Jeremy Soller c6a31f709b Merge remote-tracking branch 'sajattack/master' 2018-03-08 14:47:03 -07:00
Jeremy Soller e1a8b288fb Update README.md 2018-03-08 14:32:06 -07:00
Jeremy Soller 38ed9ccb22 Update README.md 2018-03-08 14:31:55 -07:00
Paul Sajna 12833a5a5c add test and fork 2018-03-08 12:25:14 -08:00
Paul Sajna 22fb6c5bf0 copy strerror implementation into perror 2018-03-08 11:20:13 -08:00
Paul Sajna 6304595a1d Merge branch 'master' of github.com:redox-os/relibc 2018-03-08 11:07:51 -08:00
Jeremy Soller 8812c2148f Merge pull request #33 from dlrobertson/stub_wctype
Create crate and stubs for wctype
2018-03-08 10:07:14 -07:00
Dan Robertson a6a16cf233 Create crate and stubs for wctype
Create the wctype crate and stub functions with the unimplemented macro.
2018-03-08 16:03:45 +00:00
Jeremy Soller 013dff2aaf Merge pull request #29 from dlrobertson/add_functions
Add ctype functions and atoi/atol
2018-03-08 07:34:14 -07:00
Paul Sajna 33f1033e0e implement pipe and read 2018-03-07 23:30:10 -08:00
Dan Robertson ec288a1b53 Add ctype functions and atoi/atol
Add ctype functions
  - isalnum
  - isalpha
  - isascii
  - isdigit
  - islower
  - isspace
  - isupper
Add stdlib functions
  - atoi
  - atol
Fix some warnings
Make a fmt run
2018-03-08 05:26:40 +00:00
Paul Sajna 838c364ed5 Merge branch 'unistd' 2018-03-07 20:58:48 -08:00
Paul Sajna 3b7149612f implement perror 2018-03-07 20:57:51 -08:00
Jeremy Soller 1127c36ceb Add strerror to error test 2018-03-07 21:01:48 -07:00
Jeremy Soller b7b49d5801 Implement strerror 2018-03-07 21:00:26 -07:00
Paul Sajna f6db153ea5 Merge branch 'master' of github.com:redox-os/relibc 2018-03-07 19:46:41 -08:00
Jeremy Soller f01c669771 Remove thread local from errno, for now 2018-03-07 20:37:22 -07:00
Jeremy Soller 85b80d0fe5 Fix errno.h, add -no-pie to tests Makefile 2018-03-07 20:31:18 -07:00
Paul Sajna 95424b3c69 Merge branch 'master' of github.com:redox-os/relibc 2018-03-07 18:47:21 -08:00
Jeremy Soller 851e4d399f Fix errno.h definition 2018-03-07 19:46:23 -07:00
Paul Sajna ffd9176cdf forgot to commit the makefile 2018-03-07 18:45:03 -08:00
Jeremy Soller 633b5474db Merge pull request #27 from sajattack/master
add test for errno
2018-03-07 19:40:46 -07:00
Jeremy Soller 7e725a803e Merge pull request #26 from Arcterus/master
Implement several more string functions and add errno
2018-03-07 19:40:09 -07:00
Paul Sajna 93ddcca294 add test for errno 2018-03-07 18:36:18 -08:00
Alex Lyon 629c20f097 string: ensure resulting string has NUL byte 2018-03-07 17:52:37 -08:00
Alex Lyon 3e1b945e99 Add errno crate and set errno in strndup 2018-03-07 17:38:43 -08:00
Jeremy Soller 89a9e01676 Create README.md 2018-03-07 17:29:54 -07:00
Jeremy Soller ba515d83df Create LICENSE 2018-03-07 17:29:33 -07:00
Alex Lyon ee824f3b19 string: implement strndup and strnlen 2018-03-07 15:59:58 -08:00
Alex Lyon 9f39456dbd string: implement strcat, strcmp, strcpy, and strdup 2018-03-07 14:06:30 -08:00
Jeremy Soller 3224fa24c8 Merge pull request #23 from Arcterus/master
string: implement strncat, strncmp, and strncpy
2018-03-07 06:15:21 -07:00
Alex Lyon 114ee16c21 string: implement strncat, strncmp, and strncpy 2018-03-07 05:04:40 -08:00
Jeremy Soller 1198ad3ae7 Format vsnprintf 2018-03-06 22:02:30 -07:00
Jeremy Soller ff0cebca87 Implement more stdio functions 2018-03-06 21:47:39 -07:00
Jeremy Soller bf41415c8b Use Rust nightly, disable email notifications 2018-03-06 21:25:10 -07:00
Jeremy Soller b14ee3ed39 Fix build, add Wall 2018-03-06 21:23:36 -07:00
Jeremy Soller 853fdaad75 Merge branch 'master' of github.com:redox-os/relibc 2018-03-06 21:16:14 -07:00
Jeremy Soller a1ce114cd4 Convert errors and set errno 2018-03-06 21:15:38 -07:00
Jeremy Soller 6afdf3fabf Merge pull request #21 from sajattack/patch-1
Test if the redox version compiles too
2018-03-06 21:08:09 -07:00
Paul 8f513f809b Test if it compiles for redox too 2018-03-06 20:06:47 -08:00
Jeremy Soller cf03233e66 Fix linux build 2018-03-06 20:44:21 -07:00
Jeremy Soller b768e44678 Merge pull request #19 from sajattack/redox-fixes
redox fixes
2018-03-06 20:42:35 -07:00
Jeremy Soller 1dd2f61d76 Merge pull request #20 from dlrobertson/add_ci
Add test.sh and fmt.sh to travis.yml
2018-03-06 20:40:13 -07:00
Paul Sajna 05d316b3a5 redox fixes 2018-03-06 19:28:02 -08:00
Dan Robertson 628c68abe3 Add test.sh and fmt.sh to travis.yml
Do not accept unformatted code.
2018-03-07 03:15:24 +00:00
Jeremy Soller 98b2fba518 Merge pull request #18 from dlrobertson/aarch64
Finalize Aarch64 support
2018-03-06 20:03:47 -07:00
Dan Robertson 40b6a9c5cc Finalize Aarch64 support
Update platform support for linux to avoid the use of syscalls not
supported by Aarch64.
  - link, chown, and open should use fchownat and linkat with fd
    set to AT_FDCWD.
  - use dup3 with the 3rd arg set to 0 instead of dup2.
2018-03-07 02:56:08 +00:00
Jeremy Soller 543526cb85 Move crt0 and platform into src folder
Add cargo fmt script
2018-03-06 19:55:11 -07:00
Jeremy Soller 6bca112340 Merge pull request #16 from dlrobertson/fixes_and_nits
Fix platform
2018-03-06 19:30:13 -07:00
Dan Robertson 846e495944 Get rustfmt passing on core relibc code
- Add a rustfmt config
 - Get the current code passing the formatter
2018-03-07 01:52:50 +00:00
Dan Robertson 2096b85115 Fix platform
- Add cfg to extern crate sc. It is not used by redox.
 - Fix bad syntax in brk implementation for redox
 - nits
   - style: update brk implementation for linux
   - style: no space between not operator and ptr.is_null
   - style: should be a space around = in module path
2018-03-07 01:52:50 +00:00
Jeremy Soller a808dfe39c Merge pull request #14 from sajattack/unistd
implement some unistd
2018-03-05 19:31:08 -07:00
Paul Sajna 44e6c334e6 unwrap_or(-1) 2018-03-05 14:57:04 -08:00
Paul Sajna 151d873aba link 2018-03-04 22:34:47 -08:00
Paul Sajna 3a07bc27c2 getid functions 2018-03-04 22:11:59 -08:00
Jeremy Soller d4308b4c5d Update rust toolchain and lock file 2018-03-04 18:01:28 -07:00
Paul Sajna 2636b6f5b1 ftruncate test 2018-03-04 16:41:53 -08:00
Paul Sajna 5cc52e4b19 tests 2018-03-04 16:34:46 -08:00
Paul Sajna fc92d95b35 this [u8] to c_char* is probably wrong 2018-03-04 09:42:57 -08:00
Paul Sajna 95ed0b59bd getcwd 2018-03-04 09:35:38 -08:00
Paul Sajna b5192437c3 ftruncate 2018-03-04 09:24:33 -08:00
Paul Sajna 3ad7c62601 fsync and some tweaks 2018-03-04 09:16:56 -08:00
Paul Sajna 9de89e037a fchdir 2018-03-04 09:03:46 -08:00
Paul Sajna 95e74373fe fchown 2018-03-04 08:49:40 -08:00
Paul Sajna 8b1222c3fb brk 2018-03-04 08:41:37 -08:00
Paul Sajna c96040187f chown 2018-03-04 08:32:47 -08:00
Paul Sajna aa4f7ed3a5 Merge branch 'platform' into unistd 2018-03-04 08:21:52 -08:00
Paul Sajna 6b89b4620b Merge branch 'master' of github.com:redox-os/relibc into platform 2018-03-04 08:09:48 -08:00
Paul Sajna 4b1a1568bf add rawfile.rs 2018-03-04 08:09:13 -08:00
Jeremy Soller 8283f130d6 Merge pull request #10 from sajattack/semaphore
build semaphore header
2018-03-04 09:06:30 -07:00
Paul Sajna 0157f7fcea Merge branch 'semaphore' into platform 2018-03-04 08:03:01 -08:00
Paul Sajna 608a6fcfad merge 2018-03-04 08:02:41 -08:00
Paul Sajna e08ffa6474 merge 2018-03-04 07:57:39 -08:00
Paul Sajna 25b9ac206b remove timedwait 2018-03-04 07:50:49 -08:00
Paul ae4b64c491 missing curlyboi 2018-03-04 07:41:07 -08:00
Paul 4d506e6981 Merge branch 'master' into unistd 2018-03-04 07:39:51 -08:00
Paul Sajna 7a38acada9 Merge branch 'semaphore' of github.com:sajattack/relibc into semaphore 2018-03-04 07:34:47 -08:00
Paul Sajna 0a245a386e comment out sem_open 2018-03-04 07:34:27 -08:00
Paul Sajna caa89878d6 merge 2018-03-04 07:33:38 -08:00
Jeremy Soller 5002dd720f Add mman to lib.rs 2018-03-04 08:31:43 -07:00
Jeremy Soller 07c897e558 Clean up gcc line 2018-03-04 08:29:19 -07:00
Jeremy Soller 18c6701841 Disable stack protector 2018-03-04 08:27:20 -07:00
Jeremy Soller 654ca47351 Fix atexit_funcs call in exit 2018-03-04 08:15:26 -07:00
Jeremy Soller 7a7b3efe3a Merge branch 'master' of github.com:redox-os/relibc 2018-03-04 08:12:38 -07:00
Jeremy Soller 866d952924 Support building for Redox 2018-03-04 08:10:42 -07:00
Paul Sajna d9d7440a7f implement some unistd 2018-03-04 06:53:30 -08:00
Paul Sajna 8860109efc add stuff from old newlib to todo 2018-03-04 06:53:30 -08:00
Paul Sajna 432c3ad397 add mman to main Cargo.toml 2018-03-04 06:53:30 -08:00
Paul Sajna de29e16024 remove mman from todo 2018-03-04 06:53:30 -08:00
Paul Sajna 16cf6e0267 build mman header 2018-03-04 06:53:30 -08:00
Paul 0e423aae4d Merge branch 'master' into semaphore 2018-03-04 06:46:27 -08:00
Paul Sajna 21abb75ccc Merge branch 'semaphore' of github.com:sajattack/relibc into semaphore 2018-03-04 06:45:13 -08:00
Paul Sajna 7fcad36826 add semaphore to main Cargo.toml 2018-03-04 06:43:41 -08:00
Paul Sajna 2e1d29203d build semaphore header 2018-03-04 06:43:41 -08:00
Paul Sajna d25b1d2fa4 implement some unistd 2018-03-04 06:37:45 -08:00
Jeremy Soller 9f5db313ce Merge pull request #13 from sajattack/oldlib
add stuff from old newlib to todo
2018-03-04 07:36:00 -07:00
Jeremy Soller 50af0031c3 Merge pull request #9 from sajattack/mman
build mman header
2018-03-04 07:35:28 -07:00
Jeremy Soller 4f5d65e7a6 Merge pull request #12 from sajattack/atexit
fix atexit
2018-03-04 06:17:25 -07:00
Paul Sajna 460d7fb2c3 add stuff from old newlib to todo 2018-03-04 05:08:32 -08:00
Paul Sajna ef9545cf71 missing parens 2018-03-04 04:43:05 -08:00
Paul Sajna cdf5cb2d56 fix atexit 2018-03-04 04:34:22 -08:00
Jeremy Soller e2695b2380 Merge pull request #11 from dlrobertson/aarch64
Start on support for aarch64
2018-03-03 23:00:30 -07:00
Paul Sajna 01e519aa24 add semaphore to main Cargo.toml 2018-03-03 21:56:46 -08:00
Jeremy Soller 1a572d91b0 Merge pull request #8 from sajattack/fix-options
Fix options
2018-03-03 22:56:09 -07:00
Paul Sajna 09116f83f7 add mman to main Cargo.toml 2018-03-03 21:55:24 -08:00
Dan Robertson d9d2ec1992 Start on support for aarch64
- Add aarch64 support
   - crt0 - add support to _start
   - platform - aarch64 does not have the open syscall. Instead most
     libc implementations use openat() with AT_FDCWD
 - Use sc instead of syscall. sc is the maintained fork of syscall.
2018-03-04 05:10:31 +00:00
Paul Sajna 3210d52eee Merge branch 'fix-options' into semaphore 2018-03-03 21:10:11 -08:00
Paul Sajna 6cf4b3bf82 build semaphore header 2018-03-03 21:07:40 -08:00
Paul Sajna 2acf7e6915 remove mman from todo 2018-03-03 20:58:58 -08:00
Paul Sajna ba1a9543c8 build mman header 2018-03-03 20:57:29 -08:00
Paul Sajna ee6ffbe73e fix Options 2018-03-03 20:55:32 -08:00
Paul Sajna eea3f0ede6 Merge branch 'master' of github.com:redox-os/relibc 2018-03-03 20:07:33 -08:00
Jeremy Soller a6dfd7145f Merge pull request #6 from sajattack/master
wrap all function parameters in Options
2018-03-03 21:04:12 -07:00
Paul Sajna f4d8fd3186 Merge branch 'master' of github.com:redox-os/relibc 2018-03-03 19:58:12 -08:00
Jeremy Soller 352f485649 Build grp header 2018-03-03 20:52:10 -07:00
Jeremy Soller a9f2e9a9a7 Add template 2018-03-03 20:48:37 -07:00
Paul Sajna 2b16a3693e wrap all function parameters in Options 2018-03-03 19:42:29 -08:00
Paul Sajna 533cb67681 fix Options 2018-03-03 19:33:34 -08:00
Jeremy Soller c4b88cc1e6 Build ctype with header 2018-03-03 20:33:19 -07:00
Jeremy Soller 083fd72e66 Reorganize 2018-03-03 20:24:40 -07:00
Jeremy Soller 388d8ed8cf Merge stdlib 2018-03-03 20:17:46 -07:00
Jeremy Soller 9a423140bc Merge string 2018-03-03 20:17:08 -07:00
Jeremy Soller 800a3a7a47 Merge stdio files 2018-03-03 20:13:52 -07:00
Jeremy Soller 3855e4c4b9 Merge branch 'master' of https://github.com/sajattack/relibc into sajattack-master 2018-03-03 20:06:27 -07:00
Jeremy Soller 64b2970cf4 make it possible to printf to any fmt::Write implementer 2018-03-03 19:57:18 -07:00
Jeremy Soller 5520526bef Implement printf (very simple version) 2018-03-03 19:47:01 -07:00
Jeremy Soller bf987098dc Use openlibm 2018-03-03 17:56:53 -07:00
Paul Sajna 341bc1b938 parameter names 2018-03-03 16:49:01 -08:00
Jeremy Soller 172517e4f8 Add all stdlib functions 2018-03-03 17:44:09 -07:00
Jeremy Soller f5ef0af883 Implement malloc/free with ralloc 2018-03-03 16:54:58 -07:00
Jeremy Soller e30dec7124 WIP: stdio.h 2018-03-03 15:15:50 -07:00
Jeremy Soller 2aff4d41dd Implement argument handling, add string.h 2018-03-03 14:55:54 -07:00
Jeremy Soller 78e421cb72 Implement some functions on Linux 2018-03-03 14:31:28 -07:00
Paul Sajna 457d3972f7 merge with origin, put unistd back the way it was 2018-03-03 12:28:59 -08:00
Jeremy Soller 9fb0b77d89 Include sys/types in fctnl and unistd 2018-03-03 13:10:21 -07:00
Jeremy Soller d64dba1c1e Use patched cbindgen, implement stdbool and stdint 2018-03-03 13:05:43 -07:00
Jeremy Soller a9aae80ae0 WIP: Define common types 2018-03-03 10:08:16 -07:00
Jeremy Soller d337caafe6 Remove std from outputted libc.a 2018-03-03 09:19:25 -07:00
Jeremy Soller d20e3f69e1 no_std 2018-03-03 08:51:14 -07:00
Jeremy Soller a01ff6baf8 Add overarching staticlib 2018-03-03 08:44:18 -07:00
Jeremy Soller 7251cbec76 Add definitions for unistd 2018-03-03 08:33:19 -07:00
Jeremy Soller b720d0181f Add fcntl 2018-03-03 08:25:53 -07:00
Jeremy Soller 858ad52cf6 Finish function definitions for unistd 2018-03-03 08:04:16 -07:00
Paul Sajna 1a298045b6 #[no_mangle] 2018-03-02 21:27:35 -08:00
Paul Sajna e57a314acf rustfmt 2018-03-02 18:24:40 -08:00
Paul Sajna 7da98c514a wctype.h skeleton 2018-03-02 18:15:13 -08:00
Paul Sajna bd91a5a11e wchar.h skeleton 2018-03-02 18:08:35 -08:00
Paul Sajna 28b72a667c grp.h skeleton 2018-03-02 17:51:39 -08:00
Paul Sajna b8a5b9b551 aio.h skeleton 2018-03-02 17:40:35 -08:00
Paul Sajna 7f29a7127c ctype.h skeleton 2018-03-02 17:36:23 -08:00
Paul Sajna 3ccd24c50e mman 2018-03-02 17:30:20 -08:00
Paul Sajna ae49c54d60 stdio.h skeleton 2018-03-02 17:23:28 -08:00
Paul Sajna c1d1be4d61 semaphore.h skeleton 2018-03-02 17:07:17 -08:00
Paul Sajna e39ff9d5a3 add string.h skeleton 2018-03-02 16:59:44 -08:00
Paul Sajna aef8c1442d pthread skeleton 2018-03-02 16:55:13 -08:00
Paul Sajna af548fd1bc add bindgen post-processing script, use it for unistd and stdlib.h 2018-03-02 14:50:13 -08:00
Jeremy Soller b2b120bbc1 Add many more functions 2018-03-01 21:02:52 -07:00
Jeremy Soller 3267409c57 Add very basic example 2018-03-01 20:26:40 -07:00
2028 changed files with 106072 additions and 92766 deletions
+7
View File
@@ -0,0 +1,7 @@
[**.c]
indent_size = 4
indent_style = space
[**.yml]
indent_size = 4
indent_style = space
+10 -10
View File
@@ -1,11 +1,11 @@
target/
sysroot/
# Local settings folder for Visual Studio Code
.vscode/
# Local settings folder for Jetbrains products (RustRover, IntelliJ, CLion)
.idea/ .idea/
# Local settings folder for Visual Studio Professional prefix/
.vs/ sysroot/
# Local settings folder for the devcontainer extension that most IDEs support. **/target/
.devcontainer/ .gdb_history
*.patch
*.swp
*.swo
/.vim
.vscode/
+39 -8
View File
@@ -1,25 +1,36 @@
image: "redoxos/redoxer:latest" image: "redoxos/redoxer:latest"
variables:
GIT_SUBMODULE_STRATEGY: recursive
workflow: workflow:
rules: rules:
- if: '$CI_COMMIT_BRANCH == "main" && $CI_PROJECT_NAMESPACE == "redox-os"' - if: '$CI_COMMIT_BRANCH == "master" && $CI_PROJECT_NAMESPACE == "redox-os"'
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"' - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
stages: stages:
- build - build
- cross-build - cross-build
- test - test
before_script:
cargo install cbindgen
fmt: fmt:
stage: build stage: build
needs: []
script: script:
- rustup component add rustfmt - rustup component add rustfmt-preview
- CHECK_ONLY=1 ./fmt.sh - ./fmt.sh -- --check
linux:
stage: build
script:
- ./check.sh --host
x86_64: x86_64:
stage: build stage: build
script: script:
- rustup component add rustfmt - ./check.sh --arch=x86_64
- ./check.sh
i586: i586:
stage: cross-build stage: cross-build
@@ -28,6 +39,7 @@ i586:
aarch64: aarch64:
stage: cross-build stage: cross-build
image: "redoxos/redoxer:aarch64"
script: script:
- ./check.sh --arch=aarch64 - ./check.sh --arch=aarch64
@@ -36,7 +48,26 @@ riscv64gc:
script: script:
- ./check.sh --arch=riscv64gc - ./check.sh --arch=riscv64gc
boot: test:linux:
stage: test stage: test
needs: [linux]
script: script:
- timeout -s KILL 9m ./check.sh --test - ./check.sh --host --test
test:x86_64:
stage: test
needs: [x86_64]
script:
# timeout: https://gitlab.redox-os.org/redox-os/relibc/-/issues/238
- timeout -s KILL 9m ./check.sh --arch=x86_64 --test
test:aarch64:
stage: test
needs: [aarch64]
image: "redoxos/redoxer:aarch64"
# many issues that not exist in x86_64, and lack of interest to fix so far
allow_failure: true
script:
- timeout -s KILL 9m ./check.sh --arch=aarch64 --test
#TODO: Enable more arch once dynamic linker working
-92
View File
@@ -1,92 +0,0 @@
<!-- Thank you for taking the time to submit an issue! By following these comments and filling out the sections below, you can help the developers get the necessary information to fix your issue. Please provide a single issue per report. You can also preview this report before submitting it. Feel free to modify/remove sections to fit the nature of your issue. -->
<!-- Please search to check that your issue has not been created already. By preventing duplicate issues, you can help keep the repository organized. If your current issue has already been created and is still unresolved, you can contribute by commenting there. -->
<!-- Replace the empty checkbox [ ] below with a checked one [x] if you have already searched for your issue. -->
- [ ] I agree that I have searched opened and closed issues to prevent duplicates.
--------------------
## Description
<!-- Briefly summarize/describe the issue that you are experiencing below. -->
Replace me
## Environment info
<!-- To understand where your issue originates, please include some relevant information about your environment. -->
<!-- If you are using a pre-built release of Redox, please specify the release version below. -->
- Redox OS Release:
0.0.0 Remove me
<!-- If you have built Redox OS yourself, please provide the following information: -->
- Operating system:
Replace me
- `uname -a`:
`Replace me`
- `rustc -V`:
`Replace me`
- `git rev-parse HEAD`:
`Replace me`
<!-- Depending on your issue, additional information about your environment (network config, package versions, dependencies, etc.) can also help. You can list that below. -->
- Replace me:
Replace me
## Steps to reproduce
<!-- If possible, please list the steps to reproduce ("trigger") your issue below. Being detailed definitely helps speed up bug fixes. -->
1. Replace me
2. Replace me
3. ...
## Behavior
<!-- It may seem obvious to know what to expect, but isolating the behavior from everything else simplifies the development process. Remember to provide a single issue in this report. You can use the References section below to link your issues together. -->
<!-- Describe the behavior you expect your steps should yield (i.e., correct behavior). -->
- **Expected behavior**:
Replace me
<!-- Describe the behavior you observed when running your steps (i.e., buggy behavior). -->
- **Actual behavior**:
Replace me
<!-- **Logs?** Posting a log can help developers find your particular issue more easily. Please wrap your code in code blocks using triple back-ticks ``` to increase readability. -->
```
Replace me
```
<!-- **Solution?** Have a solution in mind? Propose your solution below. -->
- **Proposed solution**:
Replace me
<!-- **Screenshots?** Make it easier to get your point across with screenshots. You can drag & drop or paste your images below. -->
## Optional references
<!-- If you have found issues or pull requests that are related to or blocking this issue, please link them below. See https://help.github.com/articles/autolinked-references-and-urls/ for more options. You can also link related code snippets by providing the permalink. See https://help.github.com/articles/creating-a-permanent-link-to-a-code-snippet/ for more information. -->
Related to:
- #0000 Remove me
- Replace me
- ...
Blocked by:
- #0000 Remove me
- ...
## Optional extras
<!-- If you have other relevant information not found in other sections, you can include it below. -->
Replace me
<!-- **Code?** Awesome! You can also create a pull request with a reference to this issue. -->
<!-- **Files?** Attach your relevant files by dragging & dropping or pasting them below. -->
<!-- You also can preview your report before submitting it. Thanks for contributing to Redox! -->
@@ -1,25 +0,0 @@
**Problem**: [describe the problem you try to solve with this PR.]
**Solution**: [describe carefully what you change by this PR.]
**Changes introduced by this pull request**:
- [...]
- [...]
- [...]
**Drawbacks**: [if any, describe the drawbacks of this pull request.]
**TODOs**: [what is not done yet.]
**Fixes**: [what issues this fixes.]
**State**: [the state of this PR, e.g. WIP, ready, etc.]
**Blocking/related**: [issues or PRs blocking or being related to this issue.]
**Other**: [optional: for other relevant information that should be known or cannot be described in the other fields.]
------
_The above template is not necessary for smaller PRs._
+7
View File
@@ -0,0 +1,7 @@
[submodule "openlibm"]
path = openlibm
url = https://gitlab.redox-os.org/redox-os/openlibm.git
branch = master
[submodule "src/dlmalloc-rs"]
path = dlmalloc-rs
url = https://gitlab.redox-os.org/redox-os/dlmalloc-rs.git
+123
View File
@@ -0,0 +1,123 @@
# Contributing
## Table of contents
1. [What to do](#what-to-do)
2. [Code style](#code-style)
3. [Sending merge requests](#sending-merge-requests)
4. [Writing tests](#writing-tests)
5. [Running tests](#running-tests)
Maintaining a libc is tough work, and we'd love some help!
## What to do
For now, we are still trying to get full libc compatibility before we move on to
any optimisation.
- We currently have a number of unimplemented functions. Search for
`unimplemented!()` and hop right in!
- If you notice any missing functionality, feel free to add it in
## Code style
We have a `rustfmt.toml` in the root directory of relibc. Please run `./fmt.sh`
before sending in any merge requests as it will automatically format your code.
With regards to general style:
### Where applicable, prefer using references to raw pointers
This is most obvious when looking at `stdio` functions. If raw pointers were
used instead of references, then the resulting code would be significantly
uglier. Instead try to check for pointer being valid with `pointer::as_ref()`
and `pointer::as_mut()` and then immediately use those references instead.
Internal functions should always take references.
### Use the c types exposed in our platform module instead of Rust's inbuilt integer types
This is so we can guarantee that everything works across platforms. While it is
generally accepted these days that an `int` has 32 bits (which matches against
an `i32`), some platforms have `int` as having 16 bits, and others have long as
being 32 bits instead of 64. If you use the types in platform, then we can
guarantee that your code will "just work" should we port relibc to a different
architecture.
### Use our internal functions
If you need to use a C string, don't reinvent the wheel. We have functions in
the platform module that convert C strings to Rust slices.
We also have structures that wrap files, wrap writable strings, and wrap various
other commonly used things that you should use instead of rolling your own.
## Sending merge requests
If you have sent us a merge request, first of all, thanks for taking your time
to help us!
The first thing to note is that we do most of our development on our
[GitLab server](https://gitlab.redox-os.org/redox-os/relibc), and as such it is
possible that none of the maintainers will see your merge request if it is
opened on GitHub.
In your merge request, please put in the description:
- What functions (if any) have been implemented or changed
- The rationale behind your merge request (e.g. why you thought this change was
required. If you are just implementing some functions, you can ignore this)
- Any issues that are related to the merge request
We have CI attached to our GitLab instance, so all merge requests are checked to
make sure that they are tested before they are merged. Please write tests for
the functions that you add/change and test locally on your own machine
***before*** submitting a merge request.
## Writing tests
Every function that gets written needs to have a test in C in order to make sure
it works as intended. Here are a few guidelines for writing good tests.
### Ensure that any literals you have are mapped to variables instead of being directly passed to a function.
Sometimes compilers take literals put into libc functions and run them
internally during compilation, which can cause some false positives. All tests
are compiled with `-fno-builtin`, which theoretically solves this issue, but
just in case, it'd be a good idea to map inputs to variables.
```c
#include "string.h"
#include "stdio.h"
int main(void) {
// Don't do this
printf("%d\n", strcspn("Hello", "Hi"));
// Do this
char *first = "Hello";
char *second = "Hi";
printf("%d\n", strcspn(first, second));
}
```
### Ensure your tests cover every section of code.
What happens if a string in `strcmp()` is shorter than the other string? What
happens if the first argument to `strcspn()` is longer than the second string?
In order to make sure that all functions work as expected, we ask that any tests
cover as much of the code that you have written as possible.
## Running tests
Running tests is an important part in trying to find bugs. Before opening a
merge request, we ask that you test on your own machine to make sure there are
no regressions.
You can run tests with `make test` in the root directory of relibc to compile
relibc, compile the tests and run them. This *will* print a lot of output to
stdout, so be warned!
You can test against verified correct output with `make verify` in the tests
directory. You will need to manually create the correct output and put it in the
tests/expected directory. Running any `make` commands in the tests directory
will ***not*** rebuild relibc, so you'll need to go back to the root directory
if you need to rebuild relibc.
Generated
+272 -2560
View File
File diff suppressed because it is too large Load Diff
+140 -144
View File
@@ -1,155 +1,151 @@
[package]
name = "relibc"
version = "0.6.0+rb0.3.0"
authors = ["Jeremy Soller <jackpot51@gmail.com>", "vasilito <adminpupkin@gmail.com>"]
edition = "2024"
[lib]
name = "relibc"
crate-type = ["staticlib"]
[workspace] [workspace]
resolver = "2"
members = [ members = [
"audiod", "src/crt0",
"config", "src/crti",
"daemon", "src/crtn",
"dhcpd", "redox-rt",
"dhcpv6d", "ld_so",
"netdiag", "generic-rt",
"init",
"initfs",
"initfs/tools",
"ipcd",
"logd",
"netstack",
"ptyd",
"ramfs",
"redbear-ufw",
"randd",
"scheme-utils",
"zerod",
"drivers/common",
"drivers/executor",
"drivers/acpid",
"drivers/hwd",
"drivers/pcid",
"drivers/pcid-spawner",
"drivers/rtcd",
"drivers/vboxd",
"drivers/inputd",
"drivers/virtio-core",
"drivers/audio/ac97d",
"drivers/audio/ihdad",
"drivers/audio/sb16d",
"drivers/graphics/console-draw",
"drivers/graphics/fbbootlogd",
"drivers/graphics/driver-graphics",
"drivers/graphics/fbcond",
"drivers/graphics/graphics-ipc",
"drivers/graphics/ihdgd",
"drivers/graphics/vesad",
"drivers/graphics/virtio-gpud",
"drivers/input/ps2d",
"drivers/input/usbhidd",
"drivers/net/driver-network",
"drivers/net/e1000d",
"drivers/net/ixgbed",
"drivers/net/rtl8139d",
"drivers/net/rtl8168d",
"drivers/net/virtio-netd",
"drivers/redoxerd",
"drivers/storage/ahcid",
"drivers/storage/bcm2835-sdhcid",
"drivers/storage/driver-block",
"drivers/storage/ided",
"drivers/storage/lived", # TODO: not really a driver...
"drivers/storage/nvmed",
"drivers/storage/usbscsid",
"drivers/storage/virtio-blkd",
"drivers/usb/xhcid",
"drivers/usb/usbctl",
"drivers/usb/usbhubd",
"drivers/usb/ucsid",
"drivers/i2c/i2c-interface",
"drivers/i2c/i2cd",
"drivers/i2c/amd-mp2-i2cd",
"drivers/i2c/dw-acpi-i2cd",
"drivers/i2c/intel-lpss-i2cd",
"drivers/gpio/gpiod",
"drivers/gpio/intel-gpiod",
"drivers/gpio/i2c-gpio-expanderd",
"drivers/input/i2c-hidd",
"drivers/input/intel-thc-hidd",
"drivers/acpi-resource",
] ]
exclude = ["tests", "dlmalloc-rs"]
# Bootstrap needs it's own profile configuration
exclude = ["bootstrap"]
# Low-level Redox OS crates should be kept in sync using workspace dependencies
# Remember to also update bootstrap dependencies, those are not in the workspace
[workspace.dependencies]
acpi = { git = "https://gitlab.redox-os.org/redox-os/acpi.git", branch = "redox-6.x" }
anyhow = "1"
bitflags = "2"
clap = "4"
drm = "0.15.0"
drm-sys = "0.8.1"
edid = "0.3.0" #TODO: edid is abandoned, fork it and maintain?
fdt = "0.1.5"
libc = "0.2.181"
log = "0.4"
libredox = { path = "../libredox", default-features = true }
orbclient = "0.3.51"
parking_lot = { git = "https://github.com/Amanieu/parking_lot.git", rev = "0.12.3", default-features = false }
pico-args = "0.5"
plain = "0.2.3"
ransid = "0.4"
redox_event = "0.4.8"
redox-ioctl = { path = "../relibc/redox-ioctl" }
redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git" }
redox-rt = { path = "../relibc/redox-rt", default-features = false }
redox-scheme = { path = "../redox-scheme" }
redox_syscall = { path = "../syscall", features = ["std"] }
redox_termios = "0.1.3"
ron = "0.8.1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
slab = "0.4.9"
smallvec = "1"
spin = "0.10"
static_assertions = "1.1.0"
thiserror = "2"
toml = "1"
[workspace.lints.rust]
missing_docs = "allow" #TODO: set to deny when all public functions are documented
[workspace.lints.clippy] [workspace.lints.clippy]
missing_safety_doc = "warn" #TODO: set to deny when all safety documentation is completed borrow_as_ptr = "deny"
cast_lossless = "warn" # TODO review occurrences
cast_possible_truncation = "allow" # TODO review occurrences
cast_possible_wrap = "allow" # TODO review occurrences
cast_precision_loss = "allow" # TODO review occurrences
cast_ptr_alignment = "allow" # TODO review occurrences
cast_sign_loss = "allow" # TODO review occurrences
missing_errors_doc = "allow" # TODO review occurrences
missing_panics_doc = "allow" # TODO review occurrences
missing_safety_doc = "allow" # TODO review occurrences
mut_from_ref = "warn" # TODO review occurrences
precedence = "deny" precedence = "deny"
ptr_as_ptr = "warn" # TODO review occurrences
ptr_cast_constness = "warn" # TODO review occurrences
ref_as_ptr = "warn" # TODO review occurrences
upper_case_acronyms = "allow" # TODO review occurrences
zero_ptr = "warn" # must allow on public constants due to cbindgen issue
[workspace.lints.rust]
dangling_pointers_from_temporaries = "deny"
dead_code = "allow" # TODO review occuurences
deprecated = "deny"
improper_ctypes_definitions = "deny"
internal_features = "allow" # core_intrinsics and lang_items
irrefutable_let_patterns = "deny"
mismatched_lifetime_syntaxes = "deny"
non_camel_case_types = "allow" # needed for most POSIX type names
non_snake_case = "allow" # TODO review occuurences
non_upper_case_globals = "allow" # TODO review occuurences
unexpected_cfgs = "deny"
unpredictable_function_pointer_comparisons = "deny"
unreachable_code = "allow" # TODO review occuurences
unsafe_op_in_unsafe_fn = "deny"
unused_imports = "deny"
unused_must_use = "deny"
unused_mut = "deny"
unused_unsafe = "deny"
unused_variables = "allow" # TODO review occurrences (too many for now)
[lints]
workspace = true
[workspace.dependencies]
bitflags = "2"
ioslice = { version = "0.6", default-features = false }
plain = "0.2"
redox-path = "0.3"
redox_protocols = { package = "libredox", path = "../libredox", default-features = false, features = ["protocol"] }
redox_syscall = { path = "../syscall" }
[build-dependencies]
cc = "1"
[dependencies]
bitflags.workspace = true
cbitset = "0.2"
posix-regex = { version = "0.1.4", features = ["no_std"] }
rand = { version = "0.10", default-features = false }
rand_xorshift = "0.5"
rand_jitter = "0.6"
memchr = { version = "2.2.0", default-features = false }
plain.workspace = true
unicode-width = "0.1"
__libc_only_for_layout_checks = { package = "libc", version = "0.2.149", optional = true }
md5-crypto = { package = "md-5", version = "0.10.6", default-features = false }
sha-crypt = { version = "0.5", default-features = false }
base64ct = { version = "1.6", default-features = false, features = ["alloc"] }
bcrypt-pbkdf = { version = "0.10", default-features = false, features = [
"alloc",
] }
scrypt = { version = "0.11", default-features = false, features = ["simple"] }
pbkdf2 = { version = "0.12", features = ["sha2"] }
sha2 = { version = "0.10", default-features = false }
generic-rt = { path = "generic-rt" }
chrono-tz = { version = "0.10", default-features = false }
chrono = { version = "0.4", default-features = false, features = ["alloc"] }
libm = "0.2"
log = "0.4"
spin = "0.9.8"
argon2 = "0.5.3"
[dependencies.dlmalloc]
path = "dlmalloc-rs"
default-features = false
features = ["c_api"]
[dependencies.object]
version = "0.36.7"
git = "https://gitlab.redox-os.org/andypython/object"
default-features = false
features = ["elf", "read_core"]
[target.'cfg(target_os = "linux")'.dependencies]
sc = "0.2.7"
[target.'cfg(target_os = "redox")'.dependencies]
redox_syscall.workspace = true
redox-rt = { path = "redox-rt" }
redox-path.workspace = true
redox_event = { version = "0.4.8", default-features = false, features = [
"redox_syscall",
] }
ioslice.workspace = true
redox-ioctl = { path = "redox-ioctl" }
redox_protocols.workspace = true
[features]
# to enable trace level, take out this `no_trace`
default = ["ld_so_cache", "no_trace"]
check_against_libc_crate = ["__libc_only_for_layout_checks"]
ld_so_cache = []
math_libm = []
no_trace = ["log/release_max_level_debug"]
# for very verbose activity beyond trace level
trace_tls = []
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
[patch.crates-io] [patch.crates-io]
# Red Bear OS Phase I: s2idle / Modern Standby support. cc-11 = { git = "https://github.com/tea/cc-rs", branch = "riscv-abi-arch-fix", package = "cc" }
# The [patch.crates-io] replaces the upstream gitlab.redox-os.org
# redox_syscall (which lacks the new AcpiVerb::EnterS2Idle /
# ExitS2Idle variants) with the local fork at
# local/sources/syscall/ (a sibling directory of base/, both
# under local/sources/). The local fork is the upstream
# gitlab.redox-os.org/redox-os/syscall @ 79cb6d9 with our
# Red Bear OS P1 commit (cfa7f0c) on top. The version field
# stays at upstream 0.8.1 — periodic rebase via
# 'git fetch upstream && git rebase upstream/master' is the
# workflow when upstream changes. Hardware-agnostic — works
# for any platform with Modern Standby firmware (Dell, HP,
# Lenovo, LG Gram, etc.).
redox_syscall = { path = "../syscall" } redox_syscall = { path = "../syscall" }
libredox = { path = "../libredox" } libredox = { path = "../libredox" }
redox-scheme = { path = "../redox-scheme" } redox-scheme = { path = "../redox-scheme" }
[patch."https://gitlab.redox-os.org/redox-os/relibc.git"]
#redox-ioctl = { path = "../../relibc/source/redox-ioctl" }
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2017 Redox OS Copyright (c) 2018 Redox OS
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+212 -105
View File
@@ -1,119 +1,226 @@
TARGET ?= x86_64-unknown-redox include config.mk
LINKER ?= $(shell redoxer env which $(shell redoxer env printenv LD))
BOARD ?=
BUILD_TYPE ?= release
BUILD_FLAGS ?= --release
CARGO ?= redoxer
CARGO_HOST ?= env -u CARGO -u RUSTFLAGS cargo
SRC_DIR ?= $(CURDIR) CARGO?=cargo
BUILD_DIR ?= $(shell pwd)/target/$(TARGET)/build CARGO_TEST?=$(CARGO)
DESTDIR ?= ./sysroot CARGO_COMMON_FLAGS=-Z build-std=core,alloc,compiler_builtins
SYSROOT ?= $(shell pwd)/target/$(TARGET)/sysroot CARGOFLAGS?=$(CARGO_COMMON_FLAGS)
TARGET_DIR = $(BUILD_DIR)/$(TARGET)/$(BUILD_TYPE) CC_WRAPPER?=
BUILD_FLAGS += --target-dir $(BUILD_DIR) RUSTCFLAGS?=
LINKFLAGS?=-lgcc
USE_RUST_LIBM?=
TESTBIN?=
export OBJCOPY?=objcopy
INITFS_BINS = init logd ramfs randd zerod \ export CARGO_TARGET_DIR?=$(shell pwd)/target
acpid fbbootlogd fbcond hwd inputd lived \ BUILD?=$(CARGO_TARGET_DIR)/$(TARGET)
pcid pcid-spawner rtcd vesad CARGOFLAGS+=--target=$(TARGET)
INITFS_DRIVERS_BINS = nvmed virtio-blkd virtio-gpud EXCEPT_MATH=-not -name "math"
BASE_BINS = inputd pcid pcid-spawner redoxerd audiod dhcpd ipcd ptyd netstack FEATURE_MATH=
DRIVERS_BINS = e1000d ihdad ihdgd ixgbed rtl8139d rtl8168d \ ifneq ($(USE_RUST_LIBM),)
usbctl usbhidd usbhubd usbscsid virtio-netd xhcid FEATURE_MATH=--features math_libm
EXCEPT_MATH=
ifneq (,$(filter i586-unknown-redox i686-unknown-redox x86_64-unknown-redox,$(TARGET)))
INITFS_BINS += ps2d
INITFS_DRIVERS_BINS += ahcid ided
DRIVERS_BINS += ac97d sb16d vboxd
endif endif
ifeq ($(TARGET),aarch64-unknown-redox) TARGET_HEADERS?=$(BUILD)/include
ifeq ($(BOARD),raspi3b) export CFLAGS=-I$(TARGET_HEADERS)
INITFS_BINS += bcm2835-sdhcid
PROFILE?=release
HEADERS_UNPARSED=$(shell find src/header -mindepth 1 -maxdepth 1 -type d -not -name "_*" $(EXCEPT_MATH) -printf "%f\n")
HEADERS_DEPS=$(shell find src/header -type f \( -name "cbindgen.toml" -o -name "*.rs" \))
#HEADERS=$(patsubst %,%.h,$(subst _,/,$(HEADERS_UNPARSED)))
SRC=\
Cargo.* \
$(shell find src/ redox-rt/src/ ld_so/src/ redox-ioctl/src/ include/ -type f)
BUILTINS_VERSION=0.1.70
.PHONY: all clean fmt install install-libs install-headers install-tests libs headers submodules test
all: | headers libs
headers: $(HEADERS_DEPS)
rm -rf $(TARGET_HEADERS)
mkdir -p $(TARGET_HEADERS)
cp -r include/* $(TARGET_HEADERS)
ifeq ($(USE_RUST_LIBM),)
cp "openlibm/include"/*.h $(TARGET_HEADERS)
cp "openlibm/src"/*.h $(TARGET_HEADERS)
endif endif
endif @set -e ; \
for header in $(HEADERS_UNPARSED); do \
INITFS_CARGO_ARGS = $(foreach bin,$(INITFS_BINS),-p $(bin)) if test -f "src/header/$$header/cbindgen.toml"; then \
INITFS_DRIVERS_CARGO_ARGS = $(foreach bin,$(INITFS_DRIVERS_BINS),-p $(bin)) echo -e "\033[0;36;49mWriting Header $$header\033[0m"; \
BASE_CARGO_ARGS = $(foreach bin,$(BASE_BINS),-p $(bin)) out=`echo "$$header" | sed 's/_/\//g'`; \
DRIVERS_CARGO_ARGS = $(foreach bin,$(DRIVERS_BINS),-p $(bin)) out="$(TARGET_HEADERS)/$$out.h"; \
cat "src/header/$$header/cbindgen.toml" cbindgen.globdefs.toml \
.PHONY: all base install install-base test | cbindgen "src/header/$$header/mod.rs" --config=/dev/stdin --output "$$out" 2>/dev/null; \
fi \
all: base done; echo -e "\033[0;36;49mAll headers written\033[0m";
install: install-base
clean: clean:
rm -rf $(SRC_DIR)/target $(SRC_DIR)/sysroot $(SYSROOT) $(TARGET_DIR) $(CARGO) clean
$(MAKE) -C tests clean
rm -rf sysroot
# test if booting check:
test: all $(CARGO) check
$(MAKE) install
redoxer exec --folder ./sysroot/:/ true
# test with interactive gui fmt:
test-gui: all ./fmt.sh
$(MAKE) install
redoxer exec --gui --folder ./sysroot/:/ ion
# ----------------------------------------------------------------------------- install-headers: headers libs
# base mkdir -pv "$(DESTDIR)/include"
# ----------------------------------------------------------------------------- cp -rv "$(TARGET_HEADERS)"/* "$(DESTDIR)/include"
$(SYSROOT)/bin/redoxfs:
REDOXER_SYSROOT=$(SYSROOT) redoxer pkg redoxfs
base: libs: \
@mkdir -pv "$(BUILD_DIR)" $(BUILD)/$(PROFILE)/libc.a \
# Build daemons and drivers $(BUILD)/$(PROFILE)/libc.so \
CARGO_PROFILE_RELEASE_OPT_LEVEL=s CARGO_PROFILE_RELEASE_PANIC=abort \ $(BUILD)/$(PROFILE)/crt0.o \
$(CARGO) build $(BUILD_FLAGS) \ $(BUILD)/$(PROFILE)/crti.o \
--manifest-path "$(SRC_DIR)/Cargo.toml" \ $(BUILD)/$(PROFILE)/crtn.o \
$(BASE_CARGO_ARGS) $(DRIVERS_CARGO_ARGS) $(BUILD)/$(PROFILE)/ld.so
# Build initfs daemons and drivers
# FIXME fix whatever issue (feature unification?) causes most logs to be omitted
# if this is merged with the above build command.
CARGO_PROFILE_RELEASE_OPT_LEVEL=s CARGO_PROFILE_RELEASE_PANIC=abort \
$(CARGO) build $(BUILD_FLAGS) \
--manifest-path "$(SRC_DIR)/Cargo.toml" \
$(INITFS_CARGO_ARGS) $(INITFS_DRIVERS_CARGO_ARGS)
# Build bootstrap
cd "$(SRC_DIR)/bootstrap" && $(CARGO) rustc $(BUILD_FLAGS) \
-- -Ctarget-feature=+crt-static -Clinker="$(LINKER)"
install-base: base $(SYSROOT)/bin/redoxfs install-libs: headers libs
@mkdir -pv "$(DESTDIR)/usr/bin" "$(DESTDIR)/usr/lib/drivers" mkdir -pv "$(DESTDIR)/lib"
@mkdir -pv "$(DESTDIR)/usr/lib/init.d/" "$(DESTDIR)/usr/lib/pcid.d" cp -v "$(BUILD)/$(PROFILE)/libc.a" "$(DESTDIR)/lib"
# Distribute binaries cp -v "$(BUILD)/$(PROFILE)/libc.so" "$(DESTDIR)/lib"
@for bin in $(BASE_BINS); do \ ln -vnfs libc.so "$(DESTDIR)/lib/libc.so.6"
cp -v "$(TARGET_DIR)/$$bin" "$(DESTDIR)/usr/bin"; \ cp -v "$(BUILD)/$(PROFILE)/crt0.o" "$(DESTDIR)/lib"
done ln -vnfs crt0.o "$(DESTDIR)/lib/crt1.o"
@for bin in $(DRIVERS_BINS); do \ cp -v "$(BUILD)/$(PROFILE)/crti.o" "$(DESTDIR)/lib"
cp -v "$(TARGET_DIR)/$$bin" "$(DESTDIR)/usr/lib/drivers"; \ cp -v "$(BUILD)/$(PROFILE)/crtn.o" "$(DESTDIR)/lib"
done cp -v "$(BUILD)/$(PROFILE)/ld.so" "$(DESTDIR)/$(LD_SO_PATH)"
# Copy configurations ifeq ($(USE_RUST_LIBM),)
@cp -v "$(SRC_DIR)/init.d"/* "$(DESTDIR)/usr/lib/init.d/" cp -v "$(BUILD)/openlibm/libopenlibm.a" "$(DESTDIR)/lib/libm.a"
@find "$(SRC_DIR)/drivers" -maxdepth 3 -type f -name 'config.toml' | while read -r conf; do \ endif
driver=$$(basename "$$(dirname "$$conf")"); \ # Empty libraries for dl, pthread, and rt
cp -v "$$conf" "$(DESTDIR)/usr/lib/pcid.d/$$driver.toml"; \ $(AR) -rcs "$(DESTDIR)/lib/libdl.a"
$(AR) -rcs "$(DESTDIR)/lib/libpthread.a"
$(AR) -rcs "$(DESTDIR)/lib/librt.a"
install-tests: tests
$(MAKE) -C tests
mkdir -p "$(DESTDIR)/relibc-tests"
cp -vr tests/build_$(TARGET)/* "$(DESTDIR)/relibc-tests/"
install: install-headers install-libs
submodules:
git submodule sync
git submodule update --init --recursive
sysroot:
@mkdir -p $@
.PHONY: sysroot/$(TARGET)
sysroot/$(TARGET): | sysroot
rm -rf $@
rm -rf $@.partial
mkdir -p $@.partial
$(MAKE) install DESTDIR=$(shell pwd)/$@.partial
mv $@.partial $@
touch $@
test: sysroot/$(TARGET)
# TODO: Fix SIGILL when running cargo test
# $(CARGO_TEST) test
$(MAKE) -C tests run
test-once: sysroot/$(TARGET)
$(MAKE) -C tests run-once TESTBIN=$(TESTBIN)
$(BUILD)/$(PROFILE)/libc.so: $(BUILD)/$(PROFILE)/libc.a
$(CC) -nostdlib \
-shared \
-Wl,--gc-sections \
-Wl,-z,pack-relative-relocs \
-Wl,--sort-common \
-Wl,--whole-archive $^ -Wl,--no-whole-archive \
-Wl,-soname,libc.so.6 \
$(LINKFLAGS) \
-o $@
$(BUILD)/$(PROFILE)/ld.so: $(BUILD)/$(PROFILE)/ld_so.o $(BUILD)/$(PROFILE)/libc.a
# TODO: merge ld.so with libc.so: --dynamic-list=dynamic-list-file
$(LD) --shared -Bsymbolic --no-relax -T ld_so/ld_script/$(TARGET).ld --gc-sections $^ -o $@
$(BUILD)/$(PROFILE)/libc.a: $(BUILD)/$(PROFILE)/librelibc.a $(BUILD)/openlibm/libopenlibm.a
echo "create $@" > "$@.mri"
for lib in $^; do\
echo "addlib $$lib" >> "$@.mri"; \
done done
echo "save" >> "$@.mri"
echo "end" >> "$@.mri"
$(AR) -M < "$@.mri"
rm -rf "$(BUILD_DIR)/initfs" # Debug targets
# Distribute initfs binaries
@mkdir -pv "$(BUILD_DIR)/initfs/bin" "$(BUILD_DIR)/initfs/lib/drivers" $(BUILD)/debug/librelibc.a: $(SRC)
for bin in $(INITFS_BINS); do \ $(CARGO) rustc $(CARGOFLAGS) $(FEATURE_MATH) -- --emit link=$@ -g -C debug-assertions=no $(RUSTCFLAGS)
cp -v "$(TARGET_DIR)/$$bin" "$(BUILD_DIR)/initfs/bin"; \ ./renamesyms.sh "$@" "$(BUILD)/debug/deps/"
done ./stripcore.sh "$@"
for bin in $(INITFS_DRIVERS_BINS); do \ touch $@
cp -v "$(TARGET_DIR)/$$bin" "$(BUILD_DIR)/initfs/lib/drivers"; \
done $(BUILD)/debug/crt0.o: $(SRC)
cp "$(SYSROOT)/bin/redoxfs" "$(BUILD_DIR)/initfs/bin" $(CARGO) rustc --manifest-path src/crt0/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
# Copy initfs config files touch $@
@mkdir -p "$(BUILD_DIR)/initfs/lib/init.d" "$(BUILD_DIR)/initfs/lib/pcid.d"
cp "$(SRC_DIR)/init.initfs.d"/* "$(BUILD_DIR)/initfs/lib/init.d/" $(BUILD)/debug/crti.o: $(SRC)
cp "$(SRC_DIR)/drivers/initfs.toml" "$(BUILD_DIR)/initfs/lib/pcid.d/initfs.toml" $(CARGO) rustc --manifest-path src/crti/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
# Build initfs touch $@
$(CARGO_HOST) run --manifest-path "$(SRC_DIR)/initfs/tools/Cargo.toml" --bin redox-initfs-ar -- \
"$(BUILD_DIR)/initfs" "$(TARGET_DIR)/bootstrap" -o "$(BUILD_DIR)/initfs.img" $(BUILD)/debug/crtn.o: $(SRC)
# Distribute initfs $(CARGO) rustc --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
@mkdir -pv "$(DESTDIR)/usr/lib/boot" touch $@
cp -v "$(BUILD_DIR)/initfs.img" "$(DESTDIR)/usr/lib/boot/initfs"
$(BUILD)/debug/ld_so.o: $(SRC)
$(CARGO) rustc --manifest-path ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort -g -C debug-assertions=no $(RUSTCFLAGS)
touch $@
# Release targets
$(BUILD)/release/librelibc.a: $(SRC)
$(CARGO) rustc --release $(CARGOFLAGS) -- --emit link=$@ $(RUSTCFLAGS)
@# TODO: Better to only allow a certain whitelisted set of symbols? Perhaps
@# use some cbindgen hook, specify them manually, or grep for #[unsafe(no_mangle)].
./renamesyms.sh "$@" "$(BUILD)/release/deps/"
./stripcore.sh "$@"
touch $@
$(BUILD)/release/crt0.o: $(SRC)
$(CARGO) rustc --release --manifest-path src/crt0/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/release/crti.o: $(SRC)
$(CARGO) rustc --release --manifest-path src/crti/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/release/crtn.o: $(SRC)
$(CARGO) rustc --release --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/release/ld_so.o: $(SRC)
$(CARGO) rustc --release --manifest-path ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
# Other targets
$(BUILD)/openlibm: openlibm
rm -rf $@ $@.partial
mkdir -p $(BUILD)
cp -r $< $@.partial
mv $@.partial $@
touch $@
ifeq ($(USE_RUST_LIBM),)
$(BUILD)/openlibm/libopenlibm.a: $(BUILD)/openlibm $(BUILD)/$(PROFILE)/librelibc.a
$(MAKE) -s AR=$(AR) CC="$(CC_WRAPPER) $(CC)" LD=$(LD) CPPFLAGS="$(CPPFLAGS) -fno-stack-protector -I$(shell pwd)/include -I$(TARGET_HEADERS)" -C $< libopenlibm.a
./renamesyms.sh "$@" "$(BUILD)/release/deps/"
else
$(BUILD)/openlibm/libopenlibm.a:
mkdir -p "$(BUILD)/openlibm"
$(AR) -rcs "$(BUILD)/openlibm/libopenlibm.a"
endif
+160 -30
View File
@@ -1,43 +1,173 @@
# Base # Redox C Library (relibc)
Repository containing various system daemons, that are considered fundamental for the OS. relibc is a portable C standard library written in Rust and is under heavy development, this library contain the following items:
You can see what each component does in the following list: - C, Linux, BSD functions and extensions
- POSIX compatibility layer
- Interfaces for system components
- audiod : Daemon used to process the sound drivers audio The motivation for this project is twofold: Reduce issues that the Redox developers were having with [newlib](https://sourceware.org/newlib/), and create a more stable and safe alternative to C standard libraries written in C. It is mainly designed to be used under Redox, as an alternative to newlib, but it also supports Linux via the [sc](https://crates.io/crates/sc) crate.
- bootstrap : First code that the kernel executes, responsible for spawning the init daemon
- daemon : Redox daemon library
- drivers
- init : Daemon used to start most system components and programs
- initfs : Filesystem with the necessary system components to run RedoxFS
- ipcd : Daemon used for inter-process communication
- logd : Daemon used to log system components and daemons
- netstack : Daemon used for networking
- ptyd : Daemon used for pseudo-terminal
- ramfs : RAM filesystem
- randd : Daemon used for random number generation
- zerod : Daemon used to discard all writes and fill read buffers with zero
## How To Contribute Currently Redox and Linux are supported.
To learn how to contribute you need to read the following document: ## `redox-rt`
- [CONTRIBUTING.md](https://gitlab.redox-os.org/redox-os/redox/-/blob/master/CONTRIBUTING.md) `redox-rt` is a runtime library that provides much of the code that enables POSIX on Redox, like `fork`, `exec`, signal handling, etc.
Relibc uses it as backend in `src/platform/redox`, and it's intended to eventually be usable independently, without relibc.
If you want to contribute to drivers read its [README](drivers/README.md) ## Repository Layout
## Development - `include` - Header files (mostly macros and variadic functions `cbindgen` can't generate)
- `src` - Source files
- `src/c` - C code
- `src/crt0` - Runtime code
- `src/crti` - Runtime code
- `src/crtn` - Runtime code
- `src/header` - Header files implementation
- `src/header/*` - Each folder has a `cbindgen.toml` file, it generates a C-to-Rust interface and header files
- `src/ld_so` - Dynamic loader code
- `src/platform` - Platform-specific and common code
- `src/platform/redox` - Redox-specific code
- `src/platform/linux` - Linux-specific code
- `src/pthread` - pthread implementation
- `src/sync` - Synchronization primitives
- `tests` - C tests (each MR needs to give success in all of them)
To learn how to do development with these system components inside the Redox build system you need to read the [Build System](https://doc.redox-os.org/book/build-system-reference.html) and [Coding and Building](https://doc.redox-os.org/book/coding-and-building.html) pages. ## Download the sources
### How To Build To download the relibc sources run the following command:
It is recommended to build this system component via the Redox build system, you can learn how to do it on the [Building Redox](https://doc.redox-os.org/book/podman-build.html) page. ```sh
git clone --recursive https://gitlab.redox-os.org/redox-os/relibc
```
To build and test outside the build system, [install redoxer](https://doc.redox-os.org/book/ci.html) then use `check.sh` script to build or test: ## Build Instructions
- `./check.sh` - Check build for x86_64
- `./check.sh --arch=ARCH` - Check build for specific ARCH (`aarch64`, `i586`, `riscv64gc`)
- `./check.sh --all` - Check build for all ARCH
- `./check.sh --test` - Check the base system boots up on x86_64
You can also use `make install` to inspect the content on `./sysroot`, or `make test-gui` to test booting with orbital interactively. To build relibc out of the Redox build system, do the following steps:
### Dependencies
- Install `cbindgen`
```sh
cargo install cbindgen
```
#### Install the `expect` tool
- Debian, Ubuntu and PopOS:
```sh
sudo apt install expect
```
- Fedora:
```sh
sudo dnf install expect
```
- Arch Linux:
```sh
sudo pacman -S expect
```
### Build Relibc
To build the relibc library objects, run the following command:
```sh
make all
```
- Clean old library objects and tests
```sh
make clean
```
## Build relibc inside the Redox build system
Inside of your Redox build system, run:
```sh
make prefix
```
If you need to rebuild `relibc` for testing a Cookbook recipe, run:
```sh
touch relibc
make prefix r.recipe-name
```
Touching (changing the "last modified time" of) the `relibc` folder is needed to trigger recompilation for `make prefix`. Replace `recipe-name` with your desired recipe name.
Note: Do not edit `relibc` inside `prefix` folder! Do your work on `relibc` folder directly inside your Redox build system instead.
## Tests
Relibc has a test suite that also runs every time a new commit get pushed. You can see `.gitlab-ci.yml` to see how it's being executed. That being said, `./check.sh` is the recommended way to run tests. Here's few examples:
+ `./check.sh` - Run build, without running the test
+ `./check.sh --test` - Run all tests in x86_64 Redox using Redoxer
+ `./check.sh --test --host` - Run all tests in host (Linux)
+ `./check.sh --test --arch=aarch64` - Run all tests in specified arch
- Arch can be `x86_64`, `aarch64`, `i586`, or `riscv64gc`
+ `./check.sh --test=stdio/printf` - Run a single test
- Can be combined with `--host` or `--arch`
- Will run statically linked test in Linux, dynamically linked in Redox
Couple of notes:
- Relibc and its tests will rebuild if files changed, however switching between arch or host requires you to run `make clean`
- Redoxer is needed to run tests for Redox without `--host`. You can install it using `cargo install redoxer`
- Tests can hangs, the test runner can anticipate this, assuming the kernel doesn't hang too.
## Issues
#### I'm building for my own platform which I run, and am getting `x86_64-linux-gnu-ar: command not found` (or similar)
The Makefile expects GNU compiler tools prefixed with the platform specifier, as would be present when you installed a cross compiler. Since you are building for your own platform, some Linux distributions (like Manjaro) don't install/symlink the prefixed executables.
An easy fix would be to replace the corresponding lines in `config.mk`, e.g.
```diff
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
- export CC=x86_64-linux-gnu-gcc
- export LD=x86_64-linux-gnu-ld
- export AR=x86_64-linux-gnu-ar
- export NM=x86_64-linux-gnu-nm
+ export CC=gcc
+ export LD=ld
+ export AR=ar
+ export NM=nm
export OBJCOPY=objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
endif
```
## Contributing
Before starting to contribute, read [this](CONTRIBUTING.md) document.
## Supported OSes
- Redox OS
- Linux
## Supported architectures
- i586 (Intel/AMD)
- x86_64 (Intel/AMD)
- aarch64 (ARM64)
- riscv64gc (RISC-V)
## Funding - _Unix-style Signals and Process Management_
This project is funded through [NGI Zero Core](https://nlnet.nl/core), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more at the [NLnet project page](https://nlnet.nl/project/RedoxOS-Signals).
[<img src="https://nlnet.nl/logo/banner.png" alt="NLnet foundation logo" width="20%" />](https://nlnet.nl)
[<img src="https://nlnet.nl/image/logos/NGI0_tag.svg" alt="NGI Zero Logo" width="20%" />](https://nlnet.nl/core)
-19
View File
@@ -1,19 +0,0 @@
[package]
name = "audiod"
description = "Sound daemon"
version = "0.1.0"
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
edition = "2021"
[dependencies]
daemon = { path = "../daemon" }
redox_syscall = { workspace = true, features = ["std"] }
libc.workspace = true
libredox = { workspace = true, features = ["mkns"] }
redox-scheme.workspace = true
scheme-utils = { path = "../scheme-utils" }
anyhow.workspace = true
ioslice = "0.6.0"
[lints]
workspace = true
-94
View File
@@ -1,94 +0,0 @@
//! The audio daemon for RedoxOS.
use std::mem::MaybeUninit;
use std::ptr::addr_of_mut;
use std::sync::{Arc, Mutex};
use std::{mem, process, slice, thread};
use anyhow::Context;
use ioslice::IoSlice;
use libredox::flag;
use libredox::{error::Result, Fd};
use redox_scheme::Socket;
use scheme_utils::ReadinessBased;
use daemon::SchemeDaemon;
use self::scheme::AudioScheme;
mod scheme;
extern "C" fn sigusr_handler(_sig: usize) {}
fn thread(scheme: Arc<Mutex<AudioScheme>>, pid: usize, hw_file: Fd) -> Result<()> {
loop {
let buffer = scheme.lock().unwrap().buffer();
let buffer_u8 = unsafe {
slice::from_raw_parts(buffer.as_ptr() as *const u8, mem::size_of_val(&buffer))
};
// Wake up the scheme thread
libredox::call::kill(pid, libredox::flag::SIGUSR1 as u32)?;
hw_file.write(&buffer_u8)?;
}
}
fn daemon(daemon: SchemeDaemon) -> anyhow::Result<()> {
// Handle signals from the hw thread
let new_sigaction = unsafe {
let mut sigaction = MaybeUninit::<libc::sigaction>::uninit();
addr_of_mut!((*sigaction.as_mut_ptr()).sa_flags).write(0);
libc::sigemptyset(addr_of_mut!((*sigaction.as_mut_ptr()).sa_mask));
addr_of_mut!((*sigaction.as_mut_ptr()).sa_sigaction).write(sigusr_handler as usize);
sigaction.assume_init()
};
libredox::call::sigaction(flag::SIGUSR1, Some(&new_sigaction), None)?;
let pid = libredox::call::getpid()?;
let hw_file = Fd::open("/scheme/audiohw", flag::O_WRONLY | flag::O_CLOEXEC, 0)?;
let socket = Socket::create().context("failed to create scheme")?;
let scheme = Arc::new(Mutex::new(AudioScheme::new()));
let _ = daemon.ready_sync_scheme(&socket, &mut *scheme.lock().unwrap());
// Enter a constrained namespace
let ns = libredox::call::mkns(&[
IoSlice::new(b"memory"),
IoSlice::new(b"rand"), // for HashMap
])
.context("failed to make namespace")?;
libredox::call::setns(ns).context("failed to set namespace")?;
// Spawn a thread to mix and send audio data
let scheme_thread = scheme.clone();
let _thread = thread::spawn(move || thread(scheme_thread, pid, hw_file));
let mut readiness = ReadinessBased::new(&socket, 16);
loop {
readiness.read_and_process_requests(&mut *scheme.lock().unwrap())?;
readiness.poll_all_requests(&mut *scheme.lock().unwrap())?;
readiness.write_responses()?;
}
}
fn main() {
SchemeDaemon::new(inner);
}
fn inner(x: SchemeDaemon) -> ! {
match daemon(x) {
Ok(()) => {
process::exit(0);
}
Err(err) => {
eprintln!("audiod: {}", err);
process::exit(1);
}
}
}
-177
View File
@@ -1,177 +0,0 @@
use redox_scheme::{CallerCtx, OpenResult};
use scheme_utils::HandleMap;
use std::collections::VecDeque;
use std::str;
use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT, EWOULDBLOCK};
use redox_scheme::scheme::SchemeSync;
use syscall::schemev2::NewFdFlags;
// The strict buffer size of the audiohw: driver
const HW_BUFFER_SIZE: usize = 512;
// The desired buffer size of each handle
const HANDLE_BUFFER_SIZE: usize = 4096;
enum Handle {
Audio { buffer: VecDeque<(i16, i16)> },
// TODO: move volume to audiohw:?
// TODO: Use SYS_CALL to handle this better?
Volume,
SchemeRoot,
}
pub struct AudioScheme {
handles: HandleMap<Handle>,
volume: i32,
}
impl AudioScheme {
pub fn new() -> Self {
AudioScheme {
handles: HandleMap::new(),
volume: 50,
}
}
pub fn buffer(&mut self) -> [(i16, i16); HW_BUFFER_SIZE] {
let mut mix_buffer = [(0i16, 0i16); HW_BUFFER_SIZE];
// Multiply each sample by the cube of volume divided by 100
// This mimics natural perception of loudness
let volume_factor = ((self.volume as f32) / 100.0).powi(3);
for (_id, handle) in self.handles.iter_mut() {
match handle {
Handle::Audio { ref mut buffer } => {
let mut i = 0;
while i < mix_buffer.len() {
if let Some(sample) = buffer.pop_front() {
let left = (sample.0 as f32 * volume_factor) as i16;
let right = (sample.1 as f32 * volume_factor) as i16;
mix_buffer[i].0 = mix_buffer[i].0.saturating_add(left);
mix_buffer[i].1 = mix_buffer[i].1.saturating_add(right);
} else {
break;
}
i += 1;
}
}
_ => (),
}
}
mix_buffer
}
}
impl SchemeSync for AudioScheme {
fn scheme_root(&mut self) -> Result<usize> {
Ok(self.handles.insert(Handle::SchemeRoot))
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(self.handles.get(dirfd)?, Handle::SchemeRoot) {
return Err(Error::new(EACCES));
}
let (handle, flags) = match path.trim_matches('/') {
"" => (
Handle::Audio {
buffer: VecDeque::new(),
},
NewFdFlags::empty(),
),
"volume" => (Handle::Volume, NewFdFlags::POSITIONED),
_ => return Err(Error::new(ENOENT)),
};
let id = self.handles.insert(handle);
Ok(OpenResult::ThisScheme { number: id, flags })
}
fn read(
&mut self,
id: usize,
buf: &mut [u8],
off: u64,
_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
//TODO: check flags for readable
match self.handles.get_mut(id)? {
Handle::Audio { buffer: _ } => {
//TODO: audio input?
Err(Error::new(EBADF))
}
Handle::Volume => {
let Ok(off) = usize::try_from(off) else {
return Ok(0);
};
//TODO: should we allocate every time?
let bytes = format!("{}", self.volume).into_bytes();
let src = bytes.get(off..).unwrap_or(&[]);
let len = src.len().min(buf.len());
buf[..len].copy_from_slice(&src[..len]);
Ok(len)
}
Handle::SchemeRoot => Err(Error::new(EBADF)),
}
}
fn write(
&mut self,
id: usize,
buf: &[u8],
offset: u64,
_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
//TODO: check flags for writable
match self.handles.get_mut(id)? {
Handle::Audio { ref mut buffer } => {
if buffer.len() >= HANDLE_BUFFER_SIZE {
Err(Error::new(EWOULDBLOCK))
} else {
let mut i = 0;
while i + 4 <= buf.len() {
buffer.push_back((
(buf[i] as i16) | ((buf[i + 1] as i16) << 8),
(buf[i + 2] as i16) | ((buf[i + 3] as i16) << 8),
));
i += 4;
}
Ok(i)
}
}
Handle::Volume => {
//TODO: support other offsets?
if offset == 0 {
let value = str::from_utf8(buf)
.map_err(|_| Error::new(EINVAL))?
.trim()
.parse::<i32>()
.map_err(|_| Error::new(EINVAL))?;
if value >= 0 && value <= 100 {
self.volume = value;
Ok(buf.len())
} else {
Err(Error::new(EINVAL))
}
} else {
// EOF
Ok(0)
}
}
Handle::SchemeRoot => Err(Error::new(EBADF)),
}
}
}
-3
View File
@@ -1,3 +0,0 @@
[unstable]
build-std = ["core", "alloc", "compiler_builtins"]
build-std-features = ["compiler-builtins-mem"]
-233
View File
@@ -1,233 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "arrayvec"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
[[package]]
name = "bitflags"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
[[package]]
name = "bootstrap"
version = "0.0.0"
dependencies = [
"arrayvec",
"hashbrown",
"libredox",
"linked_list_allocator",
"log",
"plain",
"redox-initfs",
"redox-path",
"redox-rt",
"redox-scheme",
"redox_syscall",
"slab",
]
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "generic-rt"
version = "0.1.0"
[[package]]
name = "goblin"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17582616a7718cca54cec18e534a76c7c4aec11a8b9a85695712f262fd15a4c8"
dependencies = [
"log",
"plain",
"scroll",
]
[[package]]
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash",
]
[[package]]
name = "ioslice"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e571352c8a3b89074d12e3ee5173ffe162159105352aaaf1fc5764da747e31b"
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "libredox"
version = "0.1.18+rb0.3.0"
dependencies = [
"bitflags",
"libc",
"plain",
"redox_syscall",
]
[[package]]
name = "linked_list_allocator"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b23ac50abb8261cb38c6e2a7192d3302e0836dac1628f6a93b82b4fad185897"
dependencies = [
"spinning_top",
]
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox-initfs"
version = "0.2.0"
dependencies = [
"plain",
]
[[package]]
name = "redox-path"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
[[package]]
name = "redox-rt"
version = "0.1.0"
dependencies = [
"bitflags",
"generic-rt",
"goblin",
"ioslice",
"libredox",
"plain",
"redox-path",
"redox_syscall",
]
[[package]]
name = "redox-scheme"
version = "0.11.2+rb0.3.0"
dependencies = [
"libredox",
"redox_syscall",
]
[[package]]
name = "redox_syscall"
version = "0.9.0+rb0.3.0"
dependencies = [
"bitflags",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scroll"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
dependencies = [
"scroll_derive",
]
[[package]]
name = "scroll_derive"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "spinning_top"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
dependencies = [
"lock_api",
]
[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
-46
View File
@@ -1,46 +0,0 @@
[package]
name = "bootstrap"
description = "Userspace bootstrapper"
version = "0.0.0"
authors = ["4lDO2 <4lDO2@protonmail.com>"]
edition = "2024"
license = "MIT"
[workspace.dependencies]
libredox = { path = "../../libredox", default-features = false, features = ["base", "protocol", "redox_syscall"] }
redox_syscall = { path = "../../syscall" }
redox-scheme = { path = "../../redox-scheme", default-features = false }
[workspace]
[dependencies]
hashbrown = { version = "0.15", default-features = false, features = [
"inline-more",
"default-hasher",
] }
linked_list_allocator = "0.10"
libredox = { workspace = true }
log = { version = "0.4", default-features = false }
plain = "0.2"
redox-initfs = { path = "../initfs", default-features = false }
redox_syscall = { workspace = true }
redox-scheme = { workspace = true }
redox-path = "0.3.1"
slab = { version = "0.4.9", default-features = false }
arrayvec = { version = "0.7.6", default-features = false }
[target.'cfg(target_os = "redox")'.dependencies]
redox-rt = { path = "../../relibc/redox-rt", default-features = false }
[profile.release]
panic = "abort"
lto = "fat"
opt-level = "s"
[profile.dev]
panic = "abort"
opt-level = "s"
[patch.crates-io]
redox_syscall = { path = "../../syscall" }
libredox = { path = "../../libredox" }
-14
View File
@@ -1,14 +0,0 @@
use std::env;
fn main() {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let mut arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
if arch == "x86" {
arch = "i586".to_owned();
}
println!("cargo::rustc-link-arg=-z");
println!("cargo::rustc-link-arg=max-page-size=4096");
println!("cargo::rustc-link-arg=-T");
println!("cargo::rustc-link-arg={manifest_dir}/src/{arch}.ld");
}
-55
View File
@@ -1,55 +0,0 @@
ENTRY(_start)
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
SECTIONS {
. = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */
__initfs_header = . - 4096;
. += SIZEOF_HEADERS;
. = ALIGN(4096);
.text : {
__text_start = .;
*(.text*)
. = ALIGN(4096);
__text_end = .;
}
.rodata : {
__rodata_start = .;
*(.rodata*)
}
.data.rel.ro : {
*(.data.rel.ro*)
}
.got : {
*(.got)
}
.got.plt : {
*(.got.plt)
. = ALIGN(4096);
__rodata_end = .;
}
.data : {
__data_start = .;
*(.data*)
. = ALIGN(4096);
__data_end = .;
*(.tbss*)
. = ALIGN(4096);
*(.tdata*)
. = ALIGN(4096);
__bss_start = .;
*(.bss*)
. = ALIGN(4096);
__bss_end = .;
}
/DISCARD/ : {
*(.comment*)
*(.eh_frame*)
*(.gcc_except_table*)
*(.note*)
*(.rel.eh_frame*)
}
}
-53
View File
@@ -1,53 +0,0 @@
use core::mem;
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
pub const USERMODE_END: usize = 0x0000_8000_0000_0000;
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
static MAP: Map = Map {
offset: 0,
size: STACK_SIZE,
flags: MapFlags::PROT_READ
.union(MapFlags::PROT_WRITE)
.union(MapFlags::MAP_PRIVATE)
.union(MapFlags::MAP_FIXED_NOREPLACE),
address: STACK_START, // highest possible user address
};
core::arch::global_asm!(
"
.globl _start
_start:
// Setup a stack.
ldr x8, ={number}
ldr x0, ={fd}
ldr x1, ={map} // pointer to Map struct
ldr x2, ={map_size} // size of Map struct
svc 0
// Failure if return value is zero
cbz x0, 1f
// Failure if return value is negative
tbnz x0, 63, 1f
// Set up stack frame
mov sp, x0
add sp, sp, #{stack_size}
mov fp, sp
// Stack has the same alignment as `size`.
bl start
// `start` must never return.
// failure, emit undefined instruction
1:
udf #0
",
fd = const usize::MAX, // dummy fd indicates anonymous map
map = sym MAP,
map_size = const mem::size_of::<Map>(),
number = const SYS_FMAP,
stack_size = const STACK_SIZE,
);
-356
View File
@@ -1,356 +0,0 @@
use alloc::string::ToString;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::ffi::CStr;
use core::str::FromStr;
use hashbrown::HashMap;
use redox_scheme::Socket;
use syscall::CallFlags;
use syscall::data::{GlobalSchemes, KernelSchemeInfo};
use syscall::flag::{O_CLOEXEC, O_RDONLY, O_STAT};
use syscall::{EINTR, Error};
use redox_rt::proc::*;
use crate::KernelSchemeMap;
struct Logger;
impl log::Log for Logger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.level() <= log::max_level()
}
fn log(&self, record: &log::Record) {
let file = record.file().unwrap_or("");
let line = record.line().unwrap_or(0);
let level = record.level();
let msg = record.args();
let _ = libredox::call::write(
1,
alloc::format!("[{file}:{line} {level}] {msg}\n").as_bytes(),
);
}
fn flush(&self) {}
}
const KERNEL_METADATA_BASE: usize = crate::arch::USERMODE_END - syscall::KERNEL_METADATA_SIZE;
pub fn main() -> ! {
let mut cursor = KERNEL_METADATA_BASE;
let kernel_scheme_infos = unsafe {
let base_ptr = cursor as *const u8;
let infos_len = *(base_ptr as *const usize);
let infos_ptr = base_ptr.add(core::mem::size_of::<usize>()) as *const KernelSchemeInfo;
let slice = core::slice::from_raw_parts(infos_ptr, infos_len);
cursor += core::mem::size_of::<usize>() // kernel scheme number size
+ infos_len // kernel scheme number
* core::mem::size_of::<KernelSchemeInfo>();
slice
};
let scheme_creation_cap = unsafe {
let base_ptr = cursor as *const u8;
FdGuard::new(*(base_ptr as *const usize))
};
let mut kernel_schemes = KernelSchemeMap::new(kernel_scheme_infos);
let auth = kernel_schemes
.0
.remove(&GlobalSchemes::Proc)
.expect("failed to get proc fd");
let this_thr_fd = auth
.dup(b"cur-context")
.expect("failed to open open_via_dup")
.to_upper()
.unwrap();
let this_thr_fd = unsafe { redox_rt::initialize_freestanding(this_thr_fd) };
let mut env_bytes = [0_u8; 4096];
let mut envs = {
let fd = FdGuard::new(
libredox::call::openat(
kernel_schemes
.get(GlobalSchemes::Sys)
.expect("failed to get sys fd")
.as_raw_fd(),
"env",
(O_RDONLY | O_CLOEXEC) as i32,
0,
)
.expect("bootstrap: failed to open env"),
);
let bytes_read = fd
.read(&mut env_bytes)
.expect("bootstrap: failed to read env");
if bytes_read >= env_bytes.len() {
// TODO: Handle this, we can allocate as much as we want in theory.
panic!("env is too large");
}
let env_bytes = &mut env_bytes[..bytes_read];
env_bytes
.split(|&c| c == b'\n')
.filter(|var| !var.is_empty())
.filter(|var| !var.starts_with(b"INITFS_"))
.collect::<Vec<_>>()
};
envs.push(b"RUST_BACKTRACE=1");
//envs.push(b"LD_DEBUG=all");
envs.push(b"LD_LIBRARY_PATH=/scheme/initfs/lib");
log::set_max_level(log::LevelFilter::Warn);
if let Some(log_env) = envs
.iter()
.find_map(|var| var.strip_prefix(b"BOOTSTRAP_LOG_LEVEL="))
{
if let Ok(Ok(log_level)) = str::from_utf8(&log_env).map(|s| log::LevelFilter::from_str(s)) {
log::set_max_level(log_level);
}
}
let _ = log::set_logger(&Logger);
unsafe extern "C" {
// The linker script will define this as the location of the initfs header.
static __initfs_header: u8;
// The linker script will define this as the end of the executable (excluding initfs).
static __bss_end: u8;
}
let initfs_start = core::ptr::addr_of!(__initfs_header);
let initfs_length = unsafe {
(*(core::ptr::addr_of!(__initfs_header) as *const redox_initfs::types::Header))
.initfs_size
.get() as usize
};
let (scheme_creation_cap, auth, kernel_schemes, initfs_fd) = spawn(
"initfs daemon",
auth,
&this_thr_fd,
scheme_creation_cap,
kernel_schemes,
false,
|write_fd, socket, _, _| unsafe {
crate::initfs::run(
core::slice::from_raw_parts(initfs_start, initfs_length),
write_fd,
socket,
);
},
);
// Unmap initfs data as only the initfs scheme implementation needs it.
unsafe {
let executable_end = core::ptr::addr_of!(__bss_end)
.add(core::ptr::addr_of!(__bss_end).align_offset(syscall::PAGE_SIZE));
syscall::funmap(
executable_end as usize,
initfs_length.next_multiple_of(syscall::PAGE_SIZE)
- (executable_end.offset_from(initfs_start) as usize),
)
.unwrap();
}
let (scheme_creation_cap, auth, kernel_schemes, proc_fd) = spawn(
"process manager",
auth,
&this_thr_fd,
scheme_creation_cap,
kernel_schemes,
true,
|write_fd, socket, auth, mut kernel_schemes| {
let event = kernel_schemes
.0
.remove(&GlobalSchemes::Event)
.expect("failed to get event fd");
drop(kernel_schemes);
crate::procmgr::run(write_fd, socket, auth, event)
},
);
let scheme_creation_cap_dup = scheme_creation_cap
.dup(b"")
.expect("failed to dup scheme creation cap");
let (_, _, _, initns_fd) = spawn(
"init namespace manager",
auth,
&this_thr_fd,
scheme_creation_cap,
kernel_schemes,
false,
|write_fd, socket, _, kernel_schemes| {
let mut schemes = HashMap::default();
for (scheme, fd) in kernel_schemes.0.into_iter() {
schemes.insert(scheme.as_str().to_string(), Arc::new(fd));
}
schemes.insert(
"proc".to_string(),
// A bit dirty, but necessary as the parent process still needs access to it. Rust
// doesn't know that the fd got cloned by fork.
Arc::new(FdGuard::new(proc_fd.as_raw_fd())),
);
schemes.insert("initfs".to_string(), Arc::new(initfs_fd));
crate::initnsmgr::run(write_fd, socket, schemes, scheme_creation_cap_dup)
},
);
let (init_proc_fd, init_thr_fd) = unsafe { make_init(proc_fd.take()) };
// from this point, this_thr_fd is no longer valid
const CWD: &[u8] = b"/scheme/initfs";
let cwd_fd = FdGuard::new(
libredox::call::openat(initns_fd.as_raw_fd(), "/scheme/initfs", O_STAT as i32, 0)
.expect("failed to open cwd fd"),
)
.to_upper()
.unwrap();
let extrainfo = ExtraInfo {
cwd: Some(CWD),
sigprocmask: 0,
sigignmask: 0,
umask: redox_rt::sys::get_umask(),
thr_fd: init_thr_fd.as_raw_fd(),
proc_fd: init_proc_fd.as_raw_fd(),
ns_fd: Some(initns_fd.take()),
cwd_fd: Some(cwd_fd.as_raw_fd()),
};
let path = "/scheme/initfs/bin/init";
let image_file = FdGuard::new(
libredox::call::openat(extrainfo.ns_fd.unwrap(), path, (O_RDONLY | O_CLOEXEC) as i32, 0)
.expect("failed to open init"),
)
.to_upper()
.unwrap();
let exe_path = alloc::format!("/scheme/initfs{}", path);
let FexecResult::Interp {
path: interp_path,
interp_override,
} = fexec_impl(
image_file,
init_thr_fd,
init_proc_fd,
exe_path.as_bytes(),
&[exe_path.as_bytes()],
&envs,
&extrainfo,
None,
)
.expect("failed to execute init");
// According to elf(5), PT_INTERP requires that the interpreter path be
// null-terminated. Violating this should therefore give the "format error" ENOEXEC.
let interp_cstr = CStr::from_bytes_with_nul(&interp_path).expect("interpreter not valid C str");
let interp_file = FdGuard::new(
libredox::call::openat(
extrainfo.ns_fd.unwrap(), // initns, not initfs!
interp_cstr.to_str().expect("interpreter not UTF-8"),
(O_RDONLY | O_CLOEXEC) as i32,
0,
)
.expect("failed to open dynamic linker"),
)
.to_upper()
.unwrap();
fexec_impl(
interp_file,
init_thr_fd,
init_proc_fd,
exe_path.as_bytes(),
&[exe_path.as_bytes()],
&envs,
&extrainfo,
Some(interp_override),
)
.expect("failed to execute init");
unreachable!()
}
pub(crate) fn spawn(
name: &str,
auth: FdGuard,
this_thr_fd: &FdGuardUpper,
scheme_creation_cap: FdGuard,
kernel_schemes: KernelSchemeMap,
nonblock: bool,
inner: impl FnOnce(FdGuard, Socket, FdGuard, KernelSchemeMap) -> !,
) -> (FdGuard, FdGuard, KernelSchemeMap, FdGuard) {
let read = FdGuard::new(
libredox::call::openat(
kernel_schemes
.get(GlobalSchemes::Pipe)
.expect("failed to get pipe fd")
.as_raw_fd(),
"",
O_CLOEXEC as i32,
0,
)
.expect("failed to open sync read pipe"),
);
// The write pipe will not inherit O_CLOEXEC, but is closed by the daemon later.
let write = FdGuard::new(
libredox::call::dup(read.as_raw_fd(), b"write").expect("failed to open sync write pipe"),
);
match fork_impl(&ForkArgs::Init {
this_thr_fd,
auth: &auth,
}) {
Err(err) => {
panic!("Failed to fork in order to start {name}: {err}");
}
// Continue serving the scheme as the child.
Ok(0) => {
drop(read);
let socket = Socket::create_inner(scheme_creation_cap.as_raw_fd(), nonblock)
.expect("failed to open proc scheme socket");
drop(scheme_creation_cap);
inner(write, socket, auth, kernel_schemes)
}
// Return in order to execute init, as the parent.
Ok(_) => {
drop(write);
let mut new_fd = usize::MAX;
let fd_bytes = unsafe {
core::slice::from_raw_parts_mut(
core::slice::from_mut(&mut new_fd).as_mut_ptr() as *mut u8,
core::mem::size_of::<usize>(),
)
};
loop {
match syscall::call_ro(
read.as_raw_fd(),
fd_bytes,
CallFlags::FD | CallFlags::FD_UPPER,
&[],
) {
Err(Error { errno: EINTR }) => continue,
_ => break,
}
}
(
scheme_creation_cap,
auth,
kernel_schemes,
FdGuard::new(new_fd),
)
}
}
}
-55
View File
@@ -1,55 +0,0 @@
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)
SECTIONS {
. = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */
__initfs_header = . - 4096;
. += SIZEOF_HEADERS;
. = ALIGN(4096);
.text : {
__text_start = .;
*(.text*)
. = ALIGN(4096);
__text_end = .;
}
.rodata : {
__rodata_start = .;
*(.rodata*)
}
.data.rel.ro : {
*(.data.rel.ro*)
}
.got : {
*(.got)
}
.got.plt : {
*(.got.plt)
. = ALIGN(4096);
__rodata_end = .;
}
.data : {
__data_start = .;
*(.data*)
. = ALIGN(4096);
__data_end = .;
*(.tbss*)
. = ALIGN(4096);
*(.tdata*)
. = ALIGN(4096);
__bss_start = .;
*(.bss*)
. = ALIGN(4096);
__bss_end = .;
}
/DISCARD/ : {
*(.comment*)
*(.eh_frame*)
*(.gcc_except_table*)
*(.note*)
*(.rel.eh_frame*)
}
}
-55
View File
@@ -1,55 +0,0 @@
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)
SECTIONS {
. = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */
__initfs_header = . - 4096;
. += SIZEOF_HEADERS;
. = ALIGN(4096);
.text : {
__text_start = .;
*(.text*)
. = ALIGN(4096);
__text_end = .;
}
.rodata : {
__rodata_start = .;
*(.rodata*)
}
.data.rel.ro : {
*(.data.rel.ro*)
}
.got : {
*(.got)
}
.got.plt : {
*(.got.plt)
. = ALIGN(4096);
__rodata_end = .;
}
.data : {
__data_start = .;
*(.data*)
. = ALIGN(4096);
__data_end = .;
*(.tbss*)
. = ALIGN(4096);
*(.tdata*)
. = ALIGN(4096);
__bss_start = .;
*(.bss*)
. = ALIGN(4096);
__bss_end = .;
}
/DISCARD/ : {
*(.comment*)
*(.eh_frame*)
*(.gcc_except_table*)
*(.note*)
*(.rel.eh_frame*)
}
}
-49
View File
@@ -1,49 +0,0 @@
use core::mem;
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
pub const USERMODE_END: usize = 0x8000_0000;
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
static MAP: Map = Map {
offset: 0,
size: STACK_SIZE,
flags: MapFlags::PROT_READ
.union(MapFlags::PROT_WRITE)
.union(MapFlags::MAP_PRIVATE)
.union(MapFlags::MAP_FIXED_NOREPLACE),
address: STACK_START, // highest possible user address
};
core::arch::global_asm!(
"
.globl _start
_start:
# Setup a stack.
mov eax, {number}
mov ebx, {fd}
mov ecx, offset {map} # pointer to Map struct
mov edx, {map_size} # size of Map struct
int 0x80
# Test for success (nonzero value).
cmp eax, 0
jg 1f
# (failure)
ud2
1:
# Subtract 16 since all instructions seem to hate non-canonical ESP values :)
lea esp, [eax+{stack_size}-16]
mov ebp, esp
# Stack has the same alignment as `size`.
call start
# `start` must never return.
ud2
",
fd = const usize::MAX, // dummy fd indicates anonymous map
map = sym MAP,
map_size = const mem::size_of::<Map>(),
number = const SYS_FMAP,
stack_size = const STACK_SIZE,
);
-543
View File
@@ -1,543 +0,0 @@
use core::convert::TryFrom;
#[allow(deprecated)]
use core::hash::{BuildHasherDefault, SipHasher};
use core::str;
use alloc::string::String;
use hashbrown::HashMap;
use redox_initfs::{InitFs, Inode, InodeDir, InodeKind, InodeStruct, types::Timespec};
use redox_rt::proc::FdGuard;
use redox_scheme::{
CallerCtx, OpenResult, RequestKind,
scheme::{SchemeState, SchemeSync},
};
use redox_scheme::{SignalBehavior, Socket};
use syscall::PAGE_SIZE;
use syscall::data::Stat;
use syscall::dirent::DirEntry;
use syscall::dirent::DirentBuf;
use syscall::dirent::DirentKind;
use syscall::error::*;
use syscall::flag::*;
use syscall::schemev2::NewFdFlags;
enum Handle {
Node(Node),
SchemeRoot,
}
impl Handle {
fn as_node(&self) -> Result<&Node> {
match self {
Handle::Node(n) => Ok(n),
_ => Err(Error::new(EBADF)),
}
}
fn as_node_mut(&mut self) -> Result<&mut Node> {
match self {
Handle::Node(n) => Ok(n),
_ => Err(Error::new(EBADF)),
}
}
}
struct Node {
inode: Inode,
// TODO: Any better way to implement fpath? Or maybe work around it, e.g. by giving paths such
// as `initfs:__inodes__/<inode>`?
filename: String,
}
pub struct InitFsScheme {
#[allow(deprecated)]
handles: HashMap<usize, Handle, BuildHasherDefault<SipHasher>>,
next_id: usize,
fs: InitFs<'static>,
}
impl InitFsScheme {
pub fn new(bytes: &'static [u8]) -> Self {
Self {
handles: HashMap::default(),
next_id: 0,
fs: InitFs::new(bytes, Some(PAGE_SIZE.try_into().unwrap()))
.expect("failed to parse initfs"),
}
}
fn get_inode(fs: &InitFs<'static>, inode: Inode) -> Result<InodeStruct<'static>> {
fs.get_inode(inode).ok_or_else(|| Error::new(EIO))
}
fn next_id(&mut self) -> usize {
assert_ne!(self.next_id, usize::MAX, "usize overflow in initfs scheme");
self.next_id += 1;
self.next_id
}
}
struct Iter {
dir: InodeDir<'static>,
idx: u32,
}
impl Iterator for Iter {
type Item = Result<redox_initfs::Entry<'static>>;
fn next(&mut self) -> Option<Self::Item> {
let entry = self.dir.get_entry(self.idx).map_err(|_| Error::new(EIO));
self.idx += 1;
entry.transpose()
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self.dir.entry_count().ok() {
Some(size) => {
let size =
usize::try_from(size).expect("expected u32 to be convertible into usize");
(size, Some(size))
}
None => (0, None),
}
}
}
fn inode_len(inode: InodeStruct<'static>) -> Result<usize> {
Ok(match inode.kind() {
InodeKind::File(file) => file.data().map_err(|_| Error::new(EIO))?.len(),
InodeKind::Dir(dir) => (Iter { dir, idx: 0 }).fold(0, |len, entry| {
len + entry
.and_then(|entry| entry.name().map_err(|_| Error::new(EIO)))
.map_or(0, |name| name.len() + 1)
}),
InodeKind::Link(link) => link.data().map_err(|_| Error::new(EIO))?.len(),
InodeKind::Unknown => return Err(Error::new(EIO)),
})
}
impl SchemeSync for InitFsScheme {
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
let mut components = path
// trim leading and trailing slash
.trim_matches('/')
// divide into components
.split('/')
// filter out double slashes (e.g. /usr//bin/...)
.filter(|c| !c.is_empty());
let mut current_inode = InitFs::ROOT_INODE;
while let Some(component) = components.next() {
match component {
"." => continue,
".." => {
let _ = components.next_back();
continue;
}
_ => (),
}
let current_inode_struct = Self::get_inode(&self.fs, current_inode)?;
let dir = match current_inode_struct.kind() {
InodeKind::Dir(dir) => dir,
// TODO: Support symlinks in other position than xopen target
InodeKind::Link(_) => {
return Err(Error::new(EOPNOTSUPP));
}
// If we still have more components in the path, and the file tree for that
// particular branch is not all directories except the last, then that file cannot
// exist.
InodeKind::File(_) | InodeKind::Unknown => return Err(Error::new(ENOENT)),
};
let mut entries = Iter { dir, idx: 0 };
current_inode = loop {
let entry_res = match entries.next() {
Some(e) => e,
None => return Err(Error::new(ENOENT)),
};
let entry = entry_res?;
let name = entry.name().map_err(|_| Error::new(EIO))?;
if name == component.as_bytes() {
break entry.inode();
}
};
}
// xopen target is link -- return EXDEV so that the file is opened as a link.
// TODO: Maybe follow initfs-local symlinks here? Would be faster
let is_link = matches!(
Self::get_inode(&self.fs, current_inode)?.kind(),
InodeKind::Link(_)
);
let o_stat_nofollow = flags & O_STAT != 0 && flags & O_NOFOLLOW != 0;
let o_symlink = flags & O_SYMLINK != 0;
if is_link && !o_stat_nofollow && !o_symlink {
return Err(Error::new(EXDEV));
}
let id = self.next_id();
let old = self.handles.insert(
id,
Handle::Node(Node {
inode: current_inode,
filename: path.into(),
}),
);
assert!(old.is_none());
Ok(OpenResult::ThisScheme {
number: id,
flags: NewFdFlags::POSITIONED,
})
}
fn read(
&mut self,
id: usize,
buffer: &mut [u8],
offset: u64,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
let Ok(offset) = usize::try_from(offset) else {
return Ok(0);
};
let handle = self
.handles
.get_mut(&id)
.ok_or(Error::new(EBADF))?
.as_node_mut()?;
match Self::get_inode(&self.fs, handle.inode)?.kind() {
InodeKind::File(file) => {
let data = file.data().map_err(|_| Error::new(EIO))?;
let src_buf = &data[core::cmp::min(offset, data.len())..];
let to_copy = core::cmp::min(src_buf.len(), buffer.len());
buffer[..to_copy].copy_from_slice(&src_buf[..to_copy]);
Ok(to_copy)
}
InodeKind::Dir(_) => Err(Error::new(EISDIR)),
InodeKind::Link(link) => {
let link_data = link.data().map_err(|_| Error::new(EIO))?;
let src_buf = &link_data[core::cmp::min(offset, link_data.len())..];
let to_copy = core::cmp::min(src_buf.len(), buffer.len());
buffer[..to_copy].copy_from_slice(&src_buf[..to_copy]);
Ok(to_copy)
}
InodeKind::Unknown => Err(Error::new(EIO)),
}
}
fn getdents<'buf>(
&mut self,
id: usize,
mut buf: DirentBuf<&'buf mut [u8]>,
opaque_offset: u64,
) -> Result<DirentBuf<&'buf mut [u8]>> {
let Ok(offset) = u32::try_from(opaque_offset) else {
return Ok(buf);
};
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
let InodeKind::Dir(dir) = Self::get_inode(&self.fs, handle.inode)?.kind() else {
return Err(Error::new(ENOTDIR));
};
let iter = Iter { dir, idx: offset };
for (index, entry) in iter.enumerate() {
let entry = entry?;
buf.entry(DirEntry {
// TODO: Add getter
//inode: entry.inode(),
inode: 0,
name: entry
.name()
.ok()
.and_then(|utf8| core::str::from_utf8(utf8).ok())
.ok_or(Error::new(EIO))?,
next_opaque_id: index as u64 + 1,
kind: DirentKind::Unspecified,
})?;
}
Ok(buf)
}
fn fsize(&mut self, id: usize, _ctx: &CallerCtx) -> Result<u64> {
let handle = self
.handles
.get_mut(&id)
.ok_or(Error::new(EBADF))?
.as_node_mut()?;
Ok(inode_len(Self::get_inode(&self.fs, handle.inode)?)? as u64)
}
fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
Ok(0)
}
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
// TODO: Copy scheme part in kernel
let scheme_path = b"/scheme/initfs";
let scheme_bytes = core::cmp::min(scheme_path.len(), buf.len());
buf[..scheme_bytes].copy_from_slice(&scheme_path[..scheme_bytes]);
let source = handle.filename.as_bytes();
let path_bytes = core::cmp::min(buf.len() - scheme_bytes, source.len());
buf[scheme_bytes..scheme_bytes + path_bytes].copy_from_slice(&source[..path_bytes]);
Ok(scheme_bytes + path_bytes)
}
fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
let Timespec { sec, nsec } = self.fs.image_creation_time();
let inode = Self::get_inode(&self.fs, handle.inode)?;
stat.st_ino = inode.id();
stat.st_mode = inode.mode()
| match inode.kind() {
InodeKind::Dir(_) => MODE_DIR,
InodeKind::File(_) => MODE_FILE,
InodeKind::Link(_) => MODE_SYMLINK,
_ => 0,
};
stat.st_uid = 0;
stat.st_gid = 0;
stat.st_size = u64::try_from(inode_len(inode)?).unwrap_or(u64::MAX);
stat.st_ctime = sec.get();
stat.st_ctime_nsec = nsec.get();
stat.st_mtime = sec.get();
stat.st_mtime_nsec = nsec.get();
Ok(())
}
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
if !self.handles.contains_key(&id) {
return Err(Error::new(EBADF));
}
Ok(())
}
fn mmap_prep(
&mut self,
id: usize,
offset: u64,
size: usize,
flags: MapFlags,
_ctx: &CallerCtx,
) -> syscall::Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let Handle::Node(node) = handle else {
return Err(Error::new(EBADF));
};
let data = match Self::get_inode(&self.fs, node.inode)?.kind() {
InodeKind::File(file) => file.data().map_err(|_| Error::new(EIO))?,
InodeKind::Dir(_) => return Err(Error::new(EISDIR)),
InodeKind::Link(_) => return Err(Error::new(ELOOP)),
InodeKind::Unknown => return Err(Error::new(EIO)),
};
if flags.contains(MapFlags::PROT_WRITE) {
return Err(Error::new(EPERM));
}
let Some(last_addr) = offset.checked_add(size as u64) else {
return Err(Error::new(EINVAL));
};
if last_addr > data.len().next_multiple_of(PAGE_SIZE) as u64 {
return Err(Error::new(EINVAL));
}
Ok(data.as_ptr() as usize)
}
}
pub fn run(bytes: &'static [u8], sync_pipe: FdGuard, socket: Socket) -> ! {
log::info!("bootstrap: starting initfs scheme");
let mut state = SchemeState::new();
let mut scheme = InitFsScheme::new(bytes);
// send open-capability to bootstrap
let new_id = scheme.next_id();
scheme.handles.insert(new_id, Handle::SchemeRoot);
let cap_fd = socket
.create_this_scheme_fd(0, new_id, 0, 0)
.expect("failed to issue initfs root fd");
let _ = syscall::call_rw(
sync_pipe.as_raw_fd(),
&mut cap_fd.to_ne_bytes(),
CallFlags::FD,
&[],
);
drop(sync_pipe);
loop {
let Some(req) = socket
.next_request(SignalBehavior::Restart)
.expect("bootstrap: failed to read scheme request from kernel")
else {
break;
};
match req.kind() {
RequestKind::Call(req) => {
let resp = req.handle_sync(&mut scheme, &mut state);
if !socket
.write_response(resp, SignalBehavior::Restart)
.expect("bootstrap: failed to write scheme response to kernel")
{
break;
}
}
RequestKind::OnClose { id } => {
scheme.handles.remove(&id);
}
_ => (),
}
}
unreachable!()
}
// TODO: Restructure bootstrap so it calls into relibc, or a split-off derivative without the C
// parts, such as "redox-rt".
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_read_v1(fd: usize, ptr: *mut u8, len: usize) -> isize {
Error::mux(syscall::read(fd, unsafe {
core::slice::from_raw_parts_mut(ptr, len)
})) as isize
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_write_v1(fd: usize, ptr: *const u8, len: usize) -> isize {
Error::mux(syscall::write(fd, unsafe {
core::slice::from_raw_parts(ptr, len)
})) as isize
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_openat_v1(
fd: usize,
buf: *const u8,
path_len: usize,
flags: u32,
fcntl_flags: u32,
) -> isize {
let path = unsafe { core::slice::from_raw_parts(buf, path_len) };
let path_str = match core::str::from_utf8(path) {
Ok(s) => s,
Err(_) => return -(syscall::EINVAL as isize),
};
Error::mux(syscall::openat(fd, path_str, flags as usize, fcntl_flags as usize)) as isize
}
#[unsafe(no_mangle)]
pub unsafe fn redox_dup_v1(fd: usize, buf: *const u8, len: usize) -> isize {
Error::mux(syscall::dup(fd, unsafe {
core::slice::from_raw_parts(buf, len)
})) as isize
}
#[unsafe(no_mangle)]
pub extern "C" fn redox_close_v1(fd: usize) -> isize {
Error::mux(syscall::close(fd)) as isize
}
#[unsafe(no_mangle)]
pub extern "C" fn redox_fcntl_v0(fd: usize, cmd: usize, arg: usize) -> isize {
Error::mux(syscall::fcntl(fd, cmd, arg)) as isize
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_strerror_v1(
dst: *mut u8,
dst_len: *mut usize,
error: u32,
) -> isize {
let msg = match error {
x if x == syscall::EPERM as u32 => "Operation not permitted",
x if x == syscall::ENOENT as u32 => "No such file or directory",
x if x == syscall::EINTR as u32 => "Interrupted system call",
x if x == syscall::EIO as u32 => "I/O error",
x if x == syscall::EBADF as u32 => "Bad file descriptor",
x if x == syscall::EAGAIN as u32 => "Resource temporarily unavailable",
x if x == syscall::ENOMEM as u32 => "Cannot allocate memory",
x if x == syscall::EACCES as u32 => "Permission denied",
x if x == syscall::EFAULT as u32 => "Bad address",
x if x == syscall::EBUSY as u32 => "Device or resource busy",
x if x == syscall::EEXIST as u32 => "File exists",
x if x == syscall::ENOTDIR as u32 => "Not a directory",
x if x == syscall::EISDIR as u32 => "Is a directory",
x if x == syscall::EINVAL as u32 => "Invalid argument",
x if x == syscall::ENOSYS as u32 => "Function not implemented",
x if x == syscall::ENOTEMPTY as u32 => "Directory not empty",
_ => "Unknown error",
};
let msg_bytes = msg.as_bytes();
unsafe {
let avail = *dst_len;
let copy_len = avail.min(msg_bytes.len());
core::ptr::copy_nonoverlapping(msg_bytes.as_ptr(), dst, copy_len);
*dst_len = copy_len;
copy_len as isize
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_sys_call_v0(
fd: usize,
payload: *mut u8,
payload_len: usize,
flags: usize,
metadata: *const u64,
metadata_len: usize,
) -> isize {
let flags = CallFlags::from_bits_retain(flags);
let metadata = unsafe { core::slice::from_raw_parts(metadata, metadata_len) };
let result = if flags.contains(CallFlags::READ) {
let payload = unsafe { core::slice::from_raw_parts_mut(payload, payload_len) };
if flags.contains(CallFlags::WRITE) {
syscall::call_rw(fd, payload, flags, metadata)
} else {
syscall::call_ro(fd, payload, flags, metadata)
}
} else {
let payload = unsafe { core::slice::from_raw_parts(payload, payload_len) };
syscall::call_wo(fd, payload, flags, metadata)
};
Error::mux(result) as isize
}
-558
View File
@@ -1,558 +0,0 @@
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::cell::RefCell;
use core::fmt::Debug;
use core::mem;
use hashbrown::HashMap;
use libredox::protocol::{NsDup, NsPermissions};
use log::{error, warn};
use redox_path::RedoxPath;
use redox_path::RedoxScheme;
use redox_rt::proc::FdGuard;
use redox_scheme::{
CallerCtx, OpenResult, RequestKind, Response, SendFdRequest, SignalBehavior, Socket,
scheme::{SchemeState, SchemeSync},
};
use syscall::Stat;
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
use syscall::{CallFlags, FobtainFdFlags, error::*, schemev2::NewFdFlags};
#[derive(Debug, Clone)]
struct Namespace {
schemes: HashMap<String, Arc<FdGuard>>,
}
impl Namespace {
fn fork(&self, buf: &[u8]) -> Result<Self> {
let mut schemes = HashMap::new();
let mut cursor = 0;
while cursor < buf.len() {
let len = read_num::<usize>(&buf[cursor..])?;
cursor += mem::size_of::<usize>();
let name = String::from_utf8(Vec::from(&buf[cursor..cursor + len]))
.map_err(|_| Error::new(EINVAL))?;
cursor += len;
if name.ends_with('*') {
let prefix = &name[..name.len() - 1];
for (registered_name, fd) in &self.schemes {
if registered_name.starts_with(prefix) {
schemes.insert(registered_name.clone(), fd.clone());
}
}
} else {
let Some(fd) = self.schemes.get(&name) else {
warn!("Scheme {} not found in namespace", name);
continue;
};
schemes.insert(name, fd.clone());
}
}
Ok(Self { schemes })
}
fn get_scheme_fd(&self, scheme: &str) -> Option<&Arc<FdGuard>> {
self.schemes.get(scheme)
}
fn remove_scheme(&mut self, scheme: &str) -> Option<()> {
self.schemes.remove(scheme).map(|_| ())
}
}
#[derive(Debug, Clone)]
struct NamespaceAccess {
namespace: Rc<RefCell<Namespace>>,
permission: NsPermissions,
}
impl NamespaceAccess {
fn has_permission(&self, permission: NsPermissions) -> bool {
self.permission.contains(permission)
}
}
#[derive(Debug, Clone)]
struct SchemeRegister {
target_namespace: Rc<RefCell<Namespace>>,
scheme_name: String,
}
impl SchemeRegister {
fn register(&self, fd: FdGuard) -> Result<()> {
let mut ns = self.target_namespace.borrow_mut();
if ns.schemes.contains_key(&self.scheme_name) {
return Err(Error::new(EEXIST));
}
ns.schemes.insert(self.scheme_name.clone(), Arc::new(fd));
Ok(())
}
}
#[derive(Debug, Clone)]
enum Handle {
Access(NamespaceAccess),
Register(SchemeRegister),
List(NamespaceAccess),
}
pub struct NamespaceScheme<'sock> {
socket: &'sock Socket,
handles: HashMap<usize, Handle>,
root_namespace: Namespace,
next_id: usize,
scheme_creation_cap: FdGuard,
}
const HIGH_PERMISSIONS: NsPermissions = NsPermissions::SCHEME_CREATE;
impl<'sock> NamespaceScheme<'sock> {
pub fn new(
socket: &'sock Socket,
schemes: HashMap<String, Arc<FdGuard>>,
scheme_creation_cap: FdGuard,
) -> Self {
Self {
socket,
handles: HashMap::new(),
root_namespace: Namespace { schemes },
next_id: 0,
scheme_creation_cap,
}
}
fn add_namespace(&mut self, id: usize, schemes: Namespace, permission: NsPermissions) {
let handle = Handle::Access(NamespaceAccess {
namespace: Rc::new(RefCell::new(schemes)),
permission,
});
self.handles.insert(id, handle);
}
fn get_ns_access(&self, id: usize) -> Option<&NamespaceAccess> {
let handle = self.handles.get(&id);
match handle {
Some(Handle::Access(access)) => Some(access),
_ => None,
}
}
fn open_namespace_resource(
&self,
ns_access: &NamespaceAccess,
reference: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
match reference {
"scheme-creation-cap" => {
if !ns_access.has_permission(NsPermissions::SCHEME_CREATE) {
error!("Permission denied to get scheme creation capability");
return Err(Error::new(EACCES));
}
Ok(libredox::call::dup(self.scheme_creation_cap.as_raw_fd(), &[])?)
}
_ => {
error!("Unknown special reference: {}", reference);
return Err(Error::new(EINVAL));
}
}
}
fn open_scheme_resource(
&self,
ns: &Namespace,
scheme: &str,
reference: &str,
flags: usize,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
let Some(cap_fd) = ns.get_scheme_fd(scheme) else {
log::info!("Scheme {:?} not found in namespace", scheme);
return Err(Error::new(ENODEV));
};
let scheme_fd = syscall::openat(
cap_fd.as_raw_fd(),
reference,
flags,
fcntl_flags as usize,
)?;
Ok(scheme_fd)
}
fn fork_namespace(&mut self, namespace: Rc<RefCell<Namespace>>, names: &[u8]) -> Result<usize> {
let new_id = self.next_id;
let new_namespace = namespace.borrow().fork(names).map_err(|e| {
error!("Failed to fork namespace {}: {}", new_id, e);
e
})?;
self.add_namespace(
new_id,
new_namespace,
NsPermissions::all().difference(HIGH_PERMISSIONS),
);
self.next_id += 1;
Ok(new_id)
}
fn shrink_permissions(
&mut self,
mut ns: NamespaceAccess,
permission: NsPermissions,
) -> Result<usize> {
ns.permission = ns.permission.intersection(permission);
let next_id = self.next_id;
self.handles.insert(next_id, Handle::Access(ns));
self.next_id += 1;
Ok(next_id)
}
}
impl<'sock> SchemeSync for NamespaceScheme<'sock> {
fn openat(
&mut self,
fd: usize,
path: &str,
flags: usize,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
let ns_access = {
let handle = self.handles.get(&fd);
match handle {
Some(Handle::Access(access)) => Some(access),
_ => None,
}
}
.ok_or_else(|| {
error!("Namespace with ID {} not found", fd);
Error::new(ENOENT)
})?;
let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?;
let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
let res_fd = match scheme.as_ref() {
"namespace" => self.open_namespace_resource(
ns_access,
reference.as_ref(),
flags,
fcntl_flags,
ctx,
)?,
"" => {
if !ns_access.has_permission(NsPermissions::LIST) {
error!("Permission denied to list schemes in namespace {}", fd);
return Err(Error::new(EACCES));
}
let new_id = self.next_id;
self.next_id += 1;
self.handles.insert(new_id, Handle::List(ns_access.clone()));
return Ok(OpenResult::ThisScheme {
number: new_id,
flags: NewFdFlags::empty(),
});
}
_ => self.open_scheme_resource(
&ns_access.namespace.borrow(),
scheme.as_ref(),
reference.as_ref(),
flags,
fcntl_flags,
ctx,
)?,
};
Ok(OpenResult::OtherScheme { fd: res_fd })
}
fn dup(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<OpenResult> {
let ns_access = self.get_ns_access(id).ok_or_else(|| {
error!("Namespace with ID {} not found", id);
Error::new(ENOENT)
})?;
let raw_kind = read_num::<usize>(buf)?;
let Some(kind) = NsDup::try_from_raw(raw_kind) else {
error!("Unknown dup kind: {}", raw_kind);
return Err(Error::new(EINVAL));
};
let payload = &buf[mem::size_of::<NsDup>()..];
let new_id = match kind {
NsDup::ForkNs => {
let ns = ns_access.namespace.clone();
let _ = ns_access;
self.fork_namespace(ns, payload)?
}
NsDup::ShrinkPermissions => self.shrink_permissions(
ns_access.clone(),
NsPermissions::from_bits_truncate(read_num::<usize>(payload)?),
)?,
NsDup::IssueRegister => {
let name = core::str::from_utf8(payload).map_err(|_| Error::new(EINVAL))?;
let scheme_name = RedoxScheme::new(name).ok_or_else(|| {
error!("Invalid scheme name: {}", name);
Error::new(EINVAL)
})?;
if !ns_access.has_permission(NsPermissions::INSERT) {
error!(
"Permission denied to issue register capability for namespace {}",
id
);
return Err(Error::new(EACCES));
}
let new_id = self.next_id;
let register_cap = Handle::Register(SchemeRegister {
target_namespace: ns_access.namespace.clone(),
scheme_name: scheme_name.as_ref().to_string(),
});
self.handles.insert(new_id, register_cap);
self.next_id += 1;
new_id
}
};
Ok(OpenResult::ThisScheme {
number: new_id,
flags: NewFdFlags::empty(),
})
}
fn unlinkat(&mut self, fd: usize, path: &str, flags: usize, ctx: &CallerCtx) -> Result<()> {
let ns_access = self.get_ns_access(fd).ok_or_else(|| {
error!("Namespace with ID {} not found", fd);
Error::new(ENOENT)
})?;
let mut ns = ns_access.namespace.borrow_mut();
let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?;
let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
if reference.as_ref().is_empty() {
if !ns_access.has_permission(NsPermissions::DELETE) {
error!("Permission denied to remove scheme for namespace {}", fd);
return Err(Error::new(EACCES));
}
match ns.remove_scheme(scheme.as_ref()) {
Some(_) => return Ok(()),
None => {
error!("Scheme {} not found in namespace", scheme);
return Err(Error::new(ENODEV));
}
}
}
let Some(cap_fd) = ns.get_scheme_fd(scheme.as_ref()) else {
error!("Scheme {} not found in namespace", scheme);
return Err(Error::new(ENODEV));
};
syscall::unlinkat(cap_fd.as_raw_fd(), reference, flags)?;
Ok(())
}
fn on_close(&mut self, id: usize) {
self.handles.remove(&id);
}
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
let namespace_id = sendfd_request.id();
let num_fds = sendfd_request.num_fds();
let handle = self.handles.get(&namespace_id).ok_or_else(|| {
error!("Namespace with ID {} not found", namespace_id);
Error::new(ENOENT)
})?;
let Handle::Register(register_cap) = handle else {
error!(
"Handle with ID {} is not a register capability",
namespace_id
);
return Err(Error::new(EACCES));
};
if num_fds == 0 {
return Ok(0);
}
if num_fds > 1 {
error!("Can only send one fd at a time");
return Err(Error::new(EINVAL));
}
let mut new_fd = usize::MAX;
if let Err(e) = sendfd_request.obtain_fd(
&self.socket,
FobtainFdFlags::UPPER_TBL,
core::slice::from_mut(&mut new_fd),
) {
error!("on_sendfd: obtain_fd failed with error: {:?}", e);
return Err(e);
}
register_cap.register(FdGuard::new(new_fd))?;
Ok(num_fds)
}
fn getdents<'buf>(
&mut self,
id: usize,
mut buf: DirentBuf<&'buf mut [u8]>,
opaque_offset: u64,
) -> Result<DirentBuf<&'buf mut [u8]>> {
let Handle::List(ns_access) = self.handles.get(&id).ok_or(Error::new(EBADF))? else {
return Err(Error::new(ENOTDIR));
};
if !ns_access.has_permission(NsPermissions::LIST) {
return Err(Error::new(EACCES));
}
let ns = ns_access.namespace.borrow();
let opaque_offset = opaque_offset as usize;
for (i, (name, _)) in ns.schemes.iter().enumerate().skip(opaque_offset) {
if name.is_empty() {
continue;
}
if let Err(err) = buf.entry(DirEntry {
kind: DirentKind::Unspecified,
name: &name.clone(),
inode: 0,
next_opaque_id: i as u64 + 1,
}) {
if err.errno == EINVAL && i > opaque_offset {
// POSIX allows partial result of getdents
break;
} else {
return Err(err);
}
}
}
Ok(buf)
}
fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
let resource_stat = match self.handles.get(&id).ok_or(Error::new(EBADF))? {
Handle::List(_) => Stat {
st_mode: 0o444 | syscall::MODE_DIR,
st_uid: 0,
st_gid: 0,
st_size: 0,
..Default::default()
},
Handle::Access(_) | Handle::Register(_) => Stat {
st_mode: 0o666 | syscall::MODE_FILE,
st_uid: 0,
st_gid: 0,
st_size: 0,
..Default::default()
},
};
*stat = resource_stat;
Ok(())
}
}
trait NumFromBytes: Sized + Debug {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error>;
}
macro_rules! num_from_bytes_impl {
($($t:ty),*) => {
$(
impl NumFromBytes for $t {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error> {
let size = mem::size_of::<Self>();
let buffer_slice = buffer.get(..size).and_then(|s| s.try_into().ok());
if let Some(slice) = buffer_slice {
Ok(Self::from_le_bytes(slice))
} else {
error!(
"read_num: buffer is too short to read num of size {} (buffer len: {})",
size, buffer.len()
);
Err(Error::new(EINVAL))
}
}
}
)*
};
}
num_from_bytes_impl!(usize);
fn read_num<T>(buffer: &[u8]) -> Result<T, Error>
where
T: NumFromBytes,
{
T::from_le_bytes_slice(buffer)
}
pub fn run(
sync_pipe: FdGuard,
socket: Socket,
schemes: HashMap<String, Arc<FdGuard>>,
scheme_creation_cap: FdGuard,
) -> ! {
let mut state = SchemeState::new();
let mut scheme = NamespaceScheme::new(&socket, schemes, scheme_creation_cap);
// send namespace fd to bootstrap
let new_id = scheme.next_id;
scheme.add_namespace(new_id, scheme.root_namespace.clone(), NsPermissions::all());
scheme.next_id += 1;
let cap_fd = scheme
.socket
.create_this_scheme_fd(0, new_id, 0, 0)
.expect("nsmgr: failed to create namespace fd");
let _ = syscall::call_wo(
sync_pipe.as_raw_fd(),
&cap_fd.to_ne_bytes(),
CallFlags::FD,
&[],
);
drop(sync_pipe);
log::info!("bootstrap: namespace scheme start!");
loop {
let Some(req) = socket
.next_request(SignalBehavior::Restart)
.expect("bootstrap: failed to read scheme request from kernel")
else {
break;
};
match req.kind() {
RequestKind::Call(req) => {
let resp = req.handle_sync(&mut scheme, &mut state);
if !socket
.write_response(resp, SignalBehavior::Restart)
.expect("bootstrap: failed to write scheme response to kernel")
{
break;
}
}
RequestKind::OnClose { id } => scheme.on_close(id),
RequestKind::SendFd(sendfd_request) => {
let result = scheme.on_sendfd(&sendfd_request);
let resp = Response::new(result, sendfd_request);
if !socket
.write_response(resp, SignalBehavior::Restart)
.expect("bootstrap: failed to write scheme response to kernel")
{
break;
}
}
_ => (),
}
}
unreachable!()
}
-154
View File
@@ -1,154 +0,0 @@
#![no_std]
#![no_main]
#![allow(internal_features)]
#![feature(core_intrinsics, str_from_raw_parts, never_type)]
#[cfg(target_arch = "aarch64")]
#[path = "aarch64.rs"]
pub mod arch;
#[cfg(target_arch = "x86")]
#[path = "i686.rs"]
pub mod arch;
#[cfg(target_arch = "x86_64")]
#[path = "x86_64.rs"]
pub mod arch;
#[cfg(target_arch = "riscv64")]
#[path = "riscv64.rs"]
pub mod arch;
pub mod exec;
pub mod initfs;
pub mod initnsmgr;
pub mod procmgr;
pub mod start;
extern crate alloc;
use core::cell::UnsafeCell;
use alloc::collections::btree_map::BTreeMap;
use redox_rt::proc::FdGuard;
use syscall::data::Map;
use syscall::data::{GlobalSchemes, KernelSchemeInfo};
use syscall::flag::MapFlags;
#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
use core::fmt::Write;
struct Writer;
impl Write for Writer {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
libredox::call::write(1, s.as_bytes())
.map_err(|_| core::fmt::Error)
.map(|_| ())
}
}
let _ = writeln!(&mut Writer, "{}", info);
core::intrinsics::abort();
}
const HEAP_OFF: usize = arch::USERMODE_END / 2;
struct Allocator;
#[global_allocator]
static ALLOCATOR: Allocator = Allocator;
struct AllocStateInner {
heap: Option<linked_list_allocator::Heap>,
heap_top: usize,
}
struct AllocState(UnsafeCell<AllocStateInner>);
unsafe impl Send for AllocState {}
unsafe impl Sync for AllocState {}
static ALLOC_STATE: AllocState = AllocState(UnsafeCell::new(AllocStateInner {
heap: None,
heap_top: HEAP_OFF + SIZE,
}));
const SIZE: usize = 1024 * 1024;
const HEAP_INCREASE_BY: usize = SIZE;
unsafe impl alloc::alloc::GlobalAlloc for Allocator {
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
let state = unsafe { &mut (*ALLOC_STATE.0.get()) };
let heap = state.heap.get_or_insert_with(|| {
state.heap_top = HEAP_OFF + SIZE;
let _ = unsafe {
syscall::fmap(
!0,
&Map {
offset: 0,
size: SIZE,
address: HEAP_OFF,
flags: MapFlags::PROT_WRITE
| MapFlags::PROT_READ
| MapFlags::MAP_PRIVATE
| MapFlags::MAP_FIXED_NOREPLACE,
},
)
}
.expect("failed to map initial heap");
unsafe { linked_list_allocator::Heap::new(HEAP_OFF as *mut u8, SIZE) }
});
match heap.allocate_first_fit(layout) {
Ok(p) => p.as_ptr(),
Err(_) => {
if layout.size() > HEAP_INCREASE_BY || layout.align() > 4096 {
return core::ptr::null_mut();
}
let _ = unsafe {
syscall::fmap(
!0,
&Map {
offset: 0,
size: HEAP_INCREASE_BY,
address: state.heap_top,
flags: MapFlags::PROT_WRITE
| MapFlags::PROT_READ
| MapFlags::MAP_PRIVATE
| MapFlags::MAP_FIXED_NOREPLACE,
},
)
}
.expect("failed to extend heap");
unsafe { heap.extend(HEAP_INCREASE_BY) };
state.heap_top += HEAP_INCREASE_BY;
return unsafe { self.alloc(layout) };
}
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
unsafe {
(&mut *ALLOC_STATE.0.get())
.heap
.as_mut()
.unwrap()
.deallocate(core::ptr::NonNull::new(ptr).unwrap(), layout)
}
}
}
pub struct KernelSchemeMap(BTreeMap<GlobalSchemes, FdGuard>);
impl KernelSchemeMap {
fn new(kernel_scheme_infos: &[KernelSchemeInfo]) -> Self {
let mut map = BTreeMap::new();
for info in kernel_scheme_infos {
if let Some(scheme_id) = GlobalSchemes::try_from_raw(info.scheme_id) {
map.insert(scheme_id, FdGuard::new(info.fd));
}
}
Self(map)
}
fn get(&self, scheme: GlobalSchemes) -> Option<&FdGuard> {
self.0.get(&scheme)
}
}
File diff suppressed because it is too large Load Diff
-52
View File
@@ -1,52 +0,0 @@
ENTRY(_start)
OUTPUT_FORMAT(elf64-littleriscv)
SECTIONS {
. = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */
__initfs_header = . - 4096;
. += SIZEOF_HEADERS;
. = ALIGN(4096);
.text : {
__text_start = .;
*(.text*)
. = ALIGN(4096);
__text_end = .;
}
.rodata : {
__rodata_start = .;
*(.rodata*)
}
.data.rel.ro : {
*(.data.rel.ro*)
}
.got : {
*(.got)
}
.got.plt : {
*(.got.plt)
. = ALIGN(4096);
__rodata_end = .;
}
.data : {
__data_start = .;
*(.data*)
*(.sdata*)
. = ALIGN(4096);
__data_end = .;
__bss_start = .;
*(.bss*)
*(.sbss*)
. = ALIGN(4096);
__bss_end = .;
}
/DISCARD/ : {
*(.comment*)
*(.eh_frame*)
*(.gcc_except_table*)
*(.note*)
*(.rel.eh_frame*)
}
}
-47
View File
@@ -1,47 +0,0 @@
use core::mem;
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
pub const USERMODE_END: usize = 1 << 38; // Assuming Sv39
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
static MAP: Map = Map {
offset: 0,
size: STACK_SIZE,
flags: MapFlags::PROT_READ
.union(MapFlags::PROT_WRITE)
.union(MapFlags::MAP_PRIVATE)
.union(MapFlags::MAP_FIXED_NOREPLACE),
address: STACK_START, // highest possible user address
};
core::arch::global_asm!(
"
.globl _start
_start:
# Setup a stack.
li a7, {number}
li a0, {fd}
la a1, {map} # pointer to Map struct
li a2, {map_size} # size of Map struct
ecall
# Test for success (nonzero value).
bne a0, x0, 2f
# (failure)
unimp
2:
li sp, {stack_size}
add sp, sp, a0
mv fp, x0
jal start
# `start` must never return.
unimp
",
fd = const usize::MAX, // dummy fd indicates anonymous map
map = sym MAP,
map_size = const mem::size_of::<Map>(),
number = const SYS_FMAP,
stack_size = const STACK_SIZE,
);
-86
View File
@@ -1,86 +0,0 @@
use syscall::flag::MapFlags;
mod offsets {
unsafe extern "C" {
// text (R-X)
static __text_start: u8;
static __text_end: u8;
// rodata (R--)
static __rodata_start: u8;
static __rodata_end: u8;
// data+bss (RW-)
static __data_start: u8;
static __bss_end: u8;
}
pub fn text() -> (usize, usize) {
unsafe {
(
&__text_start as *const u8 as usize,
&__text_end as *const u8 as usize,
)
}
}
pub fn rodata() -> (usize, usize) {
unsafe {
(
&__rodata_start as *const u8 as usize,
&__rodata_end as *const u8 as usize,
)
}
}
pub fn data_and_bss() -> (usize, usize) {
unsafe {
(
&__data_start as *const u8 as usize,
&__bss_end as *const u8 as usize,
)
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn start() -> ! {
// Remap self, from the previous RWX
let (text_start, text_end) = offsets::text();
let (rodata_start, rodata_end) = offsets::rodata();
let (data_start, data_end) = offsets::data_and_bss();
// NOTE: Assuming the debug scheme root fd is always placed at this position
let debug_fd = syscall::UPPER_FDTBL_TAG + syscall::data::GlobalSchemes::Debug as usize;
let _ = libredox::call::openat(debug_fd, "", syscall::O_RDONLY as i32, 0); // stdin
let _ = libredox::call::openat(debug_fd, "", syscall::O_WRONLY as i32, 0); // stdout
let _ = libredox::call::openat(debug_fd, "", syscall::O_WRONLY as i32, 0); // stderr
unsafe {
let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE)
.expect("mprotect failed for initfs header page");
let _ = syscall::mprotect(
text_start,
text_end - text_start,
MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .text");
let _ = syscall::mprotect(
rodata_start,
rodata_end - rodata_start,
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .rodata");
let _ = syscall::mprotect(
data_start,
data_end - data_start,
MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .data/.bss");
let _ = syscall::mprotect(
data_end,
crate::arch::STACK_START - data_end,
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for rest of memory");
}
crate::exec::main();
}
-55
View File
@@ -1,55 +0,0 @@
ENTRY(_start)
OUTPUT_FORMAT(elf64-x86-64)
SECTIONS {
. = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */
__initfs_header = . - 4096;
. += SIZEOF_HEADERS;
. = ALIGN(4096);
.text : {
__text_start = .;
*(.text*)
. = ALIGN(4096);
__text_end = .;
}
.rodata : {
__rodata_start = .;
*(.rodata*)
}
.data.rel.ro : {
*(.data.rel.ro*)
}
.got : {
*(.got)
}
.got.plt : {
*(.got.plt)
. = ALIGN(4096);
__rodata_end = .;
}
.data : {
__data_start = .;
*(.data*)
. = ALIGN(4096);
__data_end = .;
*(.tbss*)
. = ALIGN(4096);
*(.tdata*)
. = ALIGN(4096);
__bss_start = .;
*(.bss*)
. = ALIGN(4096);
__bss_end = .;
}
/DISCARD/ : {
*(.comment*)
*(.eh_frame*)
*(.gcc_except_table*)
*(.note*)
*(.rel.eh_frame*)
}
}
-49
View File
@@ -1,49 +0,0 @@
use core::mem;
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
pub const USERMODE_END: usize = 0x0000_8000_0000_0000;
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
static MAP: Map = Map {
offset: 0,
size: STACK_SIZE,
flags: MapFlags::PROT_READ
.union(MapFlags::PROT_WRITE)
.union(MapFlags::MAP_PRIVATE)
.union(MapFlags::MAP_FIXED_NOREPLACE),
address: STACK_START, // highest possible user address
};
core::arch::global_asm!(
"
.globl _start
_start:
# Setup a stack.
mov rax, {number}
mov rdi, {fd}
mov rsi, offset {map} # pointer to Map struct
mov rdx, {map_size} # size of Map struct
syscall
# Test for success (nonzero value).
cmp rax, 0
jg 1f
# (failure)
ud2
1:
# Subtract 16 since all instructions seem to hate non-canonical RSP values :)
lea rsp, [rax+{stack_size}-16]
mov rbp, rsp
# Stack has the same alignment as `size`.
call start
# `start` must never return.
ud2
",
fd = const usize::MAX, // dummy fd indicates anonymous map
map = sym MAP,
map_size = const mem::size_of::<Map>(),
number = const SYS_FMAP,
stack_size = const STACK_SIZE,
);
+62
View File
@@ -0,0 +1,62 @@
extern crate cc;
use std::{env, fs};
fn main() {
let _crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
let target = env::var("TARGET").unwrap();
println!("cargo:rerun-if-changed=src/c");
// The Redoxer toolchain and some upstream nightlies keep the older
// `VaList<'a>` ABI for `extern "C" fn(...)` parameters, while others
// pass `VaListImpl<'f>` and require `.as_va_list()` to obtain
// `VaList<'_, '_>`. This is a host-compiler property, so probe
// directly with the host rustc (avoiding autocfg's target probing).
println!("cargo:rustc-check-cfg=cfg(relibc_valist_impl)");
let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string());
let out_dir = env::var("OUT_DIR").unwrap_or_else(|_| "/tmp".to_string());
let probe_file = std::path::Path::new(&out_dir).join("relibc_valist_probe.rs");
let probe_out = std::path::Path::new(&out_dir).join("librelibc_valist_probe.rlib");
std::fs::write(
&probe_file,
"#![feature(c_variadic)] pub fn _relibc_valist_probe(_: core::ffi::VaList<'_, '_>) {}",
)
.ok();
let probe_ok = std::process::Command::new(&rustc)
.args([
"--crate-type",
"lib",
"--edition",
"2024",
probe_file.to_str().unwrap(),
"-o",
probe_out.to_str().unwrap(),
])
.status()
.ok()
.map_or(false, |s| s.success());
if probe_ok {
println!("cargo:rustc-cfg=relibc_valist_impl");
}
let mut cc_builder = &mut cc::Build::new();
cc_builder = cc_builder.flag("-nostdinc").flag("-nostdlib");
if target.starts_with("aarch64") {
cc_builder = cc_builder.flag("-mno-outline-atomics")
}
cc_builder
.flag("-fno-stack-protector")
.flag("-Wno-expansion-to-defined")
.files(
fs::read_dir("src/c")
.expect("src/c directory missing")
.map(|res| res.expect("read_dir error").path()),
)
.compile("relibc_c");
println!("cargo:rustc-link-lib=static=relibc_c");
}
+24
View File
@@ -0,0 +1,24 @@
# needs a leading newline
[defines]
"target_os=redox" = "__redox__"
"target_os=linux" = "__linux__"
"target_pointer_width=64" = "__LP64__"
"target_pointer_width=32" = "__ILP32__"
"target_arch=x86" = "__i386__"
"target_arch=x86_64" = "__x86_64__"
"target_arch=aarch64" = "__aarch64__"
# This is not exact. It should be `defined(__riscv) && defined(__LP64__)`, or `defined(__riscv) && __riscv_xlen==64`
# This will do however, as long as we only support riscv64 and not riscv32
"target_arch=riscv64" = "__riscv"
# XXX: silences a warning
"feature = no_std" = "__relibc__"
# Ensure attributes are passed down from Rust
# <features.h> must be included where attributes are used in relibc
[fn]
must_use = "__nodiscard"
deprecated = "__deprecated"
deprecated_with_note = "__deprecatedNote({})"
no_return = "__noreturn"
+66 -11
View File
@@ -8,10 +8,14 @@ show_help() {
echo "Usage: $(basename "$0") [OPTIONS]" echo "Usage: $(basename "$0") [OPTIONS]"
echo "" echo ""
echo "Description:" echo "Description:"
echo " Wrapper for redoxer to run checks or tests on Redox OS targets." echo " Wrapper for Makefile / Cargo to run checks or tests on Redox OS targets."
echo "" echo ""
echo "Options:" echo "Options:"
echo " --test Run 'cargo test' instead of 'cargo check'" echo " --test Run 'make test' instead of 'make all'"
echo " --test= Run single 'make test'"
echo " --cargo Run 'cargo check' / 'cargo test' instead"
echo " (note: cargo test is currently not maintained for relibc)"
echo " --host Run the command on host (linux) target"
echo " --all-target Run the command on all supported Redox architectures" echo " --all-target Run the command on all supported Redox architectures"
echo " --target=<target> Override the target architecture (e.g., i586-unknown-redox)" echo " --target=<target> Override the target architecture (e.g., i586-unknown-redox)"
echo " --arch=<arch> Override the target architecture using arch (e.g., i586)" echo " --arch=<arch> Override the target architecture using arch (e.g., i586)"
@@ -21,14 +25,15 @@ show_help() {
for t in "${SUPPORTED_TARGETS[@]}"; do for t in "${SUPPORTED_TARGETS[@]}"; do
echo " - $t" echo " - $t"
done done
echo " - $(uname -m)-unknown-linux-gnu"
echo "" echo ""
echo "Environment:" echo "Environment:"
echo " TARGET Sets the default target (overridden by --target)" echo " TARGET Sets the default target (overridden by --target)"
} }
if ! command -v redoxer &> /dev/null; then if ! command -v cbindgen &> /dev/null; then
echo "Error: 'redoxer' CLI not found." echo "Error: 'cbindgen' CLI not found."
echo "Please install it: cargo install redoxer" echo "Please install it: cargo install cbindgen"
exit 1 exit 1
fi fi
@@ -41,14 +46,31 @@ SUPPORTED_TARGETS=(
CURRENT_TARGET="${TARGET:-x86_64-unknown-redox}" CURRENT_TARGET="${TARGET:-x86_64-unknown-redox}"
CHECK_ALL=false CHECK_ALL=false
CMD_ACTION="all" CMD_ACTION="make"
CARGO_ACTION="check"
MAKE_ACTION="all"
TEST_BIN=""
IS_HOST=0
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--all-target) --all-target)
CHECK_ALL=true CHECK_ALL=true
;; ;;
--test) --test)
CMD_ACTION="test" MAKE_ACTION="test"
CARGO_ACTION="test"
;;
--test=*)
TEST_BIN="${1#*=}"
MAKE_ACTION="test-once"
;;
--cargo)
CMD_ACTION="cargo"
;;
--host)
CURRENT_TARGET="$(uname -m)-unknown-linux-gnu"
IS_HOST=1
;; ;;
--target=*) --target=*)
CURRENT_TARGET="${1#*=}" CURRENT_TARGET="${1#*=}"
@@ -69,17 +91,50 @@ while [[ $# -gt 0 ]]; do
shift shift
done done
if [ "$IS_HOST" -eq 0 ]; then
if ! command -v redoxer &> /dev/null; then
echo "Error: 'redoxer' CLI not found."
echo "Please install it: cargo install redoxer"
exit 1
fi
fi
run_redoxer() { run_redoxer() {
export TARGET=$1 export TARGET=$1
REDOXER_ENV="redoxer env"
if [ "$IS_HOST" -eq 0 ]; then
redoxer toolchain || { echo -e "${RED}Fail: redoxer toolchain for: $target.${NC}" && exit 1; } redoxer toolchain || { echo -e "${RED}Fail: redoxer toolchain for: $target.${NC}" && exit 1; }
export CARGO_TEST="redoxer"
export TEST_RUNNER="redoxer exec --folder ../../sysroot/$TARGET/:/usr --folder . --"
# TODO: Identify hang issue with pthread/barrier and pthread/once tests in multi core to get rid of this limit
export REDOXER_QEMU_ARGS="-smp 1"
MAKE_ACTION="$MAKE_ACTION IS_REDOX=1"
else
REDOXER_ENV=""
fi
if [ "$TEST_BIN" != "" ]; then
if [ "$IS_HOST" -eq 0 ]; then
MAKE_ACTION="$MAKE_ACTION TESTBIN=bins_dynamic/$TEST_BIN"
else
MAKE_ACTION="$MAKE_ACTION TESTBIN=bins_static/$TEST_BIN"
fi
fi
if [ "$CMD_ACTION" == "make" ]; then
CMD_OPT="-j $(nproc) $MAKE_ACTION"
else
CMD_OPT="$CARGO_ACTION"
fi
echo "----------------------------------------" echo "----------------------------------------"
echo "Running make $CMD_ACTION for: $TARGET" echo "Running $REDOXER_ENV $CMD_ACTION $CMD_OPT for: $TARGET"
if make "$CMD_ACTION"; then if $REDOXER_ENV $CMD_ACTION $CMD_OPT; then
return 0 return 0
else else
echo -e "${RED}Fail: $CMD_ACTION $TARGET failed.${NC}" echo -e "${RED}Fail: $CMD_ACTION $CMD_OPT for $TARGET failed.${NC}"
return 1 return 1
fi fi
} }
@@ -105,7 +160,7 @@ if [ "$CHECK_ALL" = true ]; then
fi fi
else else
if run_redoxer "$CURRENT_TARGET"; then if run_redoxer "$CURRENT_TARGET"; then
echo -e "${GREEN}Success: $CMD_ACTION $CURRENT_TARGET passed.${NC}" echo -e "${GREEN}Success: $CARGO_ACTION for $CURRENT_TARGET passed.${NC}"
exit 0 exit 0
else else
exit 1 exit 1
+73
View File
@@ -0,0 +1,73 @@
ifndef TARGET
export TARGET:=$(shell rustc -Z unstable-options --print target-spec-json | grep llvm-target | cut -d '"' -f4)
endif
ifeq ($(TARGET),aarch64-unknown-linux-gnu)
export CC=aarch64-linux-gnu-gcc
export LD=aarch64-linux-gnu-ld
export AR=aarch64-linux-gnu-ar
export NM=aarch64-linux-gnu-nm
export OBJCOPY=aarch64-linux-gnu-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1
endif
ifeq ($(TARGET),aarch64-unknown-redox)
export CC=aarch64-unknown-redox-gcc
export LD=aarch64-unknown-redox-ld
export AR=aarch64-unknown-redox-ar
export NM=aarch64-unknown-redox-nm
export OBJCOPY=aarch64-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1
endif
ifeq ($(TARGET),i586-unknown-redox)
export CC=i586-unknown-redox-gcc
export LD=i586-unknown-redox-ld
export AR=i586-unknown-redox-ar
export NM=i586-unknown-redox-nm
export OBJCOPY=i586-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/libc.so.1
endif
ifeq ($(TARGET),i686-unknown-redox)
export CC=i686-unknown-redox-gcc
export LD=i686-unknown-redox-ld
export AR=i686-unknown-redox-ar
export NM=i686-unknown-redox-nm
export OBJCOPY=i686-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/libc.so.1
endif
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
export CC=x86_64-linux-gnu-gcc
export LD=x86_64-linux-gnu-ld
export AR=x86_64-linux-gnu-ar
export NM=x86_64-linux-gnu-nm
export OBJCOPY=objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
endif
ifeq ($(TARGET),x86_64-unknown-redox)
export CC=x86_64-unknown-redox-gcc
export LD=x86_64-unknown-redox-ld
export AR=x86_64-unknown-redox-ar
export NM=x86_64-unknown-redox-nm
export OBJCOPY=x86_64-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
endif
ifeq ($(TARGET),riscv64gc-unknown-redox)
export CC=riscv64-unknown-redox-gcc
export LD=riscv64-unknown-redox-ld
export AR=riscv64-unknown-redox-ar
export NM=riscv64-unknown-redox-nm
export OBJCOPY=riscv64-unknown-redox-objcopy
export CPPFLAGS=-march=rv64gc -mabi=lp64d
LD_SO_PATH=lib/ld.so.1
endif
-10
View File
@@ -1,10 +0,0 @@
[package]
name = "config"
description = "Configuration override library"
version = "0.0.0"
edition = "2024"
[dependencies]
[lints]
workspace = true
-40
View File
@@ -1,40 +0,0 @@
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::{fs, io};
pub fn config(name: &str) -> Result<Vec<PathBuf>, io::Error> {
config_for_dirs(&[
&Path::new("/usr/lib").join(format!("{name}.d")),
&Path::new("/etc").join(format!("{name}.d")),
])
}
pub fn config_for_initfs(name: &str) -> Result<Vec<PathBuf>, io::Error> {
config_for_dirs(&[
&Path::new("/scheme/initfs/lib").join(format!("{name}.d")),
&Path::new("/scheme/initfs/etc").join(format!("{name}.d")),
])
}
pub fn config_for_dirs(dirs: &[impl AsRef<Path>]) -> Result<Vec<PathBuf>, io::Error> {
// This must be a BTreeMap to iterate in sorted order.
let mut entries = BTreeMap::new();
for dir in dirs {
let dir = dir.as_ref();
if !dir.exists() {
// Skip non-existent dirs
continue;
}
for entry_res in fs::read_dir(&dir)? {
// This intentionally overwrites older entries with
// the same filename to allow overriding entries in
// one search dir with those in a later search dir.
let entry = entry_res?;
entries.insert(entry.file_name(), entry.path());
}
}
Ok(entries.into_values().collect())
}
-14
View File
@@ -1,14 +0,0 @@
[package]
name = "daemon"
description = "Redox daemon library"
version = "0.0.0"
edition = "2024"
[dependencies]
libc.workspace = true
libredox.workspace = true
redox-scheme.workspace = true
redox_syscall.workspace = true
[lints]
workspace = true
-139
View File
@@ -1,139 +0,0 @@
//! A library for creating and managing daemons for RedoxOS.
#![feature(never_type)]
use std::io::{self, PipeWriter, Read, Write};
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
use std::os::unix::process::CommandExt;
use std::process::Command;
use libredox::Fd;
use redox_scheme::Socket;
use redox_scheme::scheme::{SchemeAsync, SchemeSync};
unsafe fn get_fd(var: &str) -> RawFd {
let fd: RawFd = std::env::var(var).unwrap().parse().unwrap();
if unsafe { libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC) } == -1 {
panic!(
"daemon: failed to set CLOEXEC flag for {var} fd: {}",
io::Error::last_os_error()
);
}
fd
}
unsafe fn pass_fd(cmd: &mut Command, env: &str, fd: OwnedFd) {
cmd.env(env, format!("{}", fd.as_raw_fd()));
unsafe {
cmd.pre_exec(move || {
// Pass notify pipe to child
if libc::fcntl(fd.as_raw_fd(), libc::F_SETFD, 0) == -1 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
});
}
}
/// A long running background process that handles requests.
#[must_use = "Daemon::ready must be called"]
pub struct Daemon {
write_pipe: PipeWriter,
}
impl Daemon {
/// Create a new daemon.
pub fn new(f: impl FnOnce(Daemon) -> !) -> ! {
let write_pipe = unsafe { io::PipeWriter::from_raw_fd(get_fd("INIT_NOTIFY")) };
f(Daemon { write_pipe })
}
/// Notify the process that the daemon is ready to accept requests.
///
/// BrokenPipe is tolerated: init may have already closed its read end
/// during the startup phase. The daemon is operational regardless of
/// init's readiness tracking state.
pub fn ready(mut self) {
match self.write_pipe.write_all(&[0]) {
Ok(()) => {}
Err(err) if err.kind() == io::ErrorKind::BrokenPipe => {}
Err(err) => {
eprintln!("daemon: failed to notify init of readiness: {err}");
}
}
}
/// Executes `Command` as a child process.
// FIXME remove once the service spawning of hwd and pcid-spawner is moved to init
#[deprecated]
pub fn spawn(mut cmd: Command) {
let (mut read_pipe, write_pipe) = io::pipe().unwrap();
unsafe { pass_fd(&mut cmd, "INIT_NOTIFY", write_pipe.into()) };
if let Err(err) = cmd.spawn() {
eprintln!("daemon: failed to execute {cmd:?}: {err}");
return;
}
let mut data = [0];
match read_pipe.read_exact(&mut data) {
Ok(()) => {}
Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
eprintln!("daemon: {cmd:?} exited without notifying readiness");
}
Err(err) => {
eprintln!("daemon: failed to wait for {cmd:?}: {err}");
}
}
}
}
/// A long running background process that handles requests using schemes.
#[must_use = "SchemeDaemon::ready must be called"]
pub struct SchemeDaemon {
write_pipe: PipeWriter,
}
impl SchemeDaemon {
/// Create a new daemon for use with schemes.
pub fn new(f: impl FnOnce(SchemeDaemon) -> !) -> ! {
let write_pipe = unsafe { io::PipeWriter::from_raw_fd(get_fd("INIT_NOTIFY")) };
f(SchemeDaemon { write_pipe })
}
/// Notify the process that the scheme daemon is ready to accept requests.
pub fn ready_with_fd(self, cap_fd: Fd) -> syscall::Result<()> {
syscall::call_wo(
self.write_pipe.as_raw_fd() as usize,
&cap_fd.into_raw().to_ne_bytes(),
syscall::CallFlags::FD,
&[],
)?;
Ok(())
}
/// Notify the process that the synchronous scheme daemon is ready to accept requests.
pub fn ready_sync_scheme<S: SchemeSync>(
self,
socket: &Socket,
scheme: &mut S,
) -> syscall::Result<()> {
let cap_id = scheme.scheme_root()?;
let cap_fd = socket.create_this_scheme_fd(0, cap_id, 0, 0)?;
self.ready_with_fd(Fd::new(cap_fd))
}
/// Notify the process that the asynchronous scheme daemon is ready to accept requests.
pub fn ready_async_scheme<S: SchemeAsync>(
self,
socket: &Socket,
scheme: &mut S,
) -> syscall::Result<()> {
let cap_id = scheme.scheme_root()?;
let cap_fd = socket.create_this_scheme_fd(0, cap_id, 0, 0)?;
self.ready_with_fd(Fd::new(cap_fd))
}
}
-37
View File
@@ -1,37 +0,0 @@
#[repr(C, packed)]
pub struct Dhcp {
pub op: u8,
pub htype: u8,
pub hlen: u8,
pub hops: u8,
pub tid: u32,
pub secs: u16,
pub flags: u16,
pub ciaddr: [u8; 4],
pub yiaddr: [u8; 4],
pub siaddr: [u8; 4],
pub giaddr: [u8; 4],
pub chaddr: [u8; 16],
pub sname: [u8; 64],
pub file: [u8; 128],
pub magic: u32,
pub options: [u8; 308],
}
pub const DHCPDISCOVER: u8 = 1;
pub const DHCPOFFER: u8 = 2;
pub const DHCPREQUEST: u8 = 3;
pub const DHCPDECLINE: u8 = 4;
pub const DHCPACK: u8 = 5;
pub const DHCPNAK: u8 = 6;
pub const DHCPRELEASE: u8 = 7;
pub const OPT_SUBNET_MASK: u8 = 1;
pub const OPT_ROUTER: u8 = 3;
pub const OPT_DNS: u8 = 6;
pub const OPT_REQUESTED_IP: u8 = 50;
pub const OPT_LEASE_TIME: u8 = 51;
pub const OPT_MESSAGE_TYPE: u8 = 53;
pub const OPT_SERVER_ID: u8 = 54;
pub const OPT_PARAM_REQUEST: u8 = 55;
pub const OPT_END: u8 = 255;
-376
View File
@@ -1,376 +0,0 @@
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::net::{SocketAddr, UdpSocket};
use std::time::Duration;
use std::{env, process, time};
use dhcp::{
Dhcp, DHCPACK, DHCPDISCOVER, DHCPNAK, DHCPOFFER, DHCPREQUEST, DHCPRELEASE,
OPT_DNS, OPT_LEASE_TIME, OPT_MESSAGE_TYPE, OPT_REQUESTED_IP, OPT_ROUTER,
OPT_SERVER_ID, OPT_SUBNET_MASK, OPT_END,
};
mod dhcp;
macro_rules! try_fmt {
($e:expr, $m:expr) => {
match $e {
Ok(ok) => ok,
Err(err) => return Err(format!("{}: {}", $m, err)),
}
};
}
fn get_cfg_value(path: &str) -> Result<String, String> {
let path = format!("/scheme/netcfg/{path}");
let mut file = File::open(&path).map_err(|_| format!("Can't open {path}"))?;
let mut result = String::new();
file.read_to_string(&mut result)
.map_err(|_| format!("Can't read {path}"))?;
Ok(result)
}
fn get_iface_cfg_value(iface: &str, cfg: &str) -> Result<String, String> {
let path = format!("ifaces/{iface}/{cfg}");
get_cfg_value(&path)
}
fn set_cfg_value(path: &str, value: &str) -> Result<(), String> {
let path = format!("/scheme/netcfg/{path}");
let mut file = OpenOptions::new()
.read(false)
.write(true)
.create(false)
.open(&path)
.map_err(|_| format!("Can't open {path}"))?;
file.write(value.as_bytes())
.map(|_| ())
.map_err(|_| format!("Can't write {value} to {path}"))?;
file.sync_data()
.map_err(|_| format!("Can't commit {value} to {path}"))
}
fn set_iface_cfg_value(iface: &str, cfg: &str, value: &str) -> Result<(), String> {
let path = format!("ifaces/{iface}/{cfg}");
set_cfg_value(&path, value)
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
struct MacAddr {
bytes: [u8; 6],
}
impl MacAddr {
fn from_str(string: &str) -> Self {
MacAddr::try_parse_with_delimeter(string, ':')
.or_else(|| MacAddr::try_parse_with_delimeter(string, '-'))
.unwrap_or_default()
}
fn try_parse_with_delimeter(string: &str, delimeter: char) -> Option<MacAddr> {
let mut addr = MacAddr::default();
let mut segments = 0;
for part in string.split(delimeter) {
if segments >= addr.bytes.len() {
return None;
}
addr.bytes[segments] = match u8::from_str_radix(part, 16) {
Ok(b) => b,
_ => return None,
};
segments += 1;
}
if segments == addr.bytes.len() {
Some(addr)
} else {
None
}
}
fn to_string(&self) -> String {
format!(
"{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}",
self.bytes[0],
self.bytes[1],
self.bytes[2],
self.bytes[3],
self.bytes[4],
self.bytes[5]
)
}
}
fn dhcp(iface: &str, verbose: bool) -> Result<(), String> {
let current_mac = MacAddr::from_str(get_iface_cfg_value(iface, "mac")?.trim());
let _current_ip = get_iface_cfg_value(iface, "addr/list")?
.lines()
.next()
.map(|l| l.to_owned())
.unwrap_or("0.0.0.0".to_string());
if verbose {
println!("DHCP: MAC: {} Starting", current_mac.to_string());
}
let tid = try_fmt!(
time::SystemTime::now().duration_since(time::UNIX_EPOCH),
"failed to get time"
).subsec_nanos();
let socket = try_fmt!(UdpSocket::bind(("0.0.0.0", 68)), "failed to bind udp");
try_fmt!(socket.connect(SocketAddr::from(([255, 255, 255, 255], 67))), "failed to connect");
try_fmt!(socket.set_read_timeout(Some(Duration::new(30, 0))), "failed to set read timeout");
try_fmt!(socket.set_write_timeout(Some(Duration::new(30, 0))), "failed to set write timeout");
let mut subnet_option: Option<[u8; 4]> = None;
let mut router_option: Option<[u8; 4]> = None;
let mut dns_option: Option<[u8; 4]> = None;
let mut server_id_option: Option<[u8; 4]> = None;
let mut lease_time_secs: u32 = 86400;
// DHCPDISCOVER
{
let mut discover = Dhcp::default();
init_dhcp_header(&mut discover, current_mac, tid);
let disc_opts: &[u8] = &[OPT_MESSAGE_TYPE, 1, DHCPDISCOVER, OPT_END];
discover.options[..disc_opts.len()].copy_from_slice(disc_opts);
try_fmt!(send_dhcp(&discover, &socket), "failed to send discover");
if verbose { println!("DHCP: Sent Discover"); }
}
// Recv DHCPOFFER
let mut offer_data = [0; 65536];
try_fmt!(socket.recv(&mut offer_data), "failed to receive offer");
let offer = unsafe { &*(offer_data.as_ptr() as *const Dhcp) };
if verbose { println!("DHCP: Offer IP: {:?}", offer.yiaddr); }
parse_options(&offer.options, &mut |code, data| {
match code {
OPT_SUBNET_MASK if data.len() == 4 && subnet_option.is_none() => {
subnet_option = Some([data[0], data[1], data[2], data[3]]);
}
OPT_ROUTER if data.len() == 4 && router_option.is_none() => {
router_option = Some([data[0], data[1], data[2], data[3]]);
}
OPT_DNS if data.len() == 4 && dns_option.is_none() => {
dns_option = Some([data[0], data[1], data[2], data[3]]);
}
OPT_LEASE_TIME if data.len() == 4 => {
lease_time_secs = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
}
OPT_SERVER_ID if data.len() == 4 && server_id_option.is_none() => {
server_id_option = Some([data[0], data[1], data[2], data[3]]);
}
_ => {}
}
});
let mask_len = compute_prefix_len(subnet_option);
let new_ips = format!(
"{}.{}.{}.{}/{}\n",
offer.yiaddr[0], offer.yiaddr[1], offer.yiaddr[2], offer.yiaddr[3], mask_len
);
try_fmt!(set_iface_cfg_value(iface, "addr/set", &new_ips), "failed to set ip");
apply_dhcp_config(iface, router_option, dns_option, verbose)?;
let server_id = server_id_option.unwrap_or([0, 0, 0, 0]);
// DHCPREQUEST
{
let mut request = Dhcp::default();
init_dhcp_header(&mut request, current_mac, tid);
let req_opts: &[u8] = &[
OPT_MESSAGE_TYPE, 1, DHCPREQUEST,
OPT_REQUESTED_IP, 4,
offer.yiaddr[0], offer.yiaddr[1], offer.yiaddr[2], offer.yiaddr[3],
OPT_SERVER_ID, 4, server_id[0], server_id[1], server_id[2], server_id[3],
OPT_END,
];
request.options[..req_opts.len()].copy_from_slice(req_opts);
try_fmt!(send_dhcp(&request, &socket), "failed to send request");
if verbose { println!("DHCP: Sent Request"); }
}
// Recv DHCPACK
let mut ack_data = [0; 65536];
try_fmt!(socket.recv(&mut ack_data), "failed to receive ack");
if verbose { println!("DHCP: lease acquired, {}s lease time", lease_time_secs); }
// RFC 2131 lease lifecycle: RENEW at T1, REBIND at T2
let t1 = Duration::from_secs(lease_time_secs as u64 / 2);
let t2 = Duration::from_secs((lease_time_secs as u64 * 7) / 8);
let now = time::Instant::now();
let t1_deadline = now + t1;
let mut remaining = t1_deadline.saturating_duration_since(time::Instant::now());
while remaining > Duration::ZERO {
std::thread::sleep(std::cmp::min(remaining, Duration::from_secs(60)));
remaining = t1_deadline.saturating_duration_since(time::Instant::now());
}
if verbose { println!("DHCP: entering RENEW state"); }
{
let mut renew = Dhcp::default();
init_dhcp_header(&mut renew, current_mac, tid.wrapping_add(1));
renew.ciaddr = offer.yiaddr;
let rn_opts: &[u8] = &[OPT_MESSAGE_TYPE, 1, DHCPREQUEST, OPT_END];
renew.options[..rn_opts.len()].copy_from_slice(rn_opts);
try_fmt!(send_dhcp(&renew, &socket), "failed to send renew");
}
socket.set_read_timeout(Some(t2.saturating_sub(t1))).ok();
match socket.recv(&mut ack_data) {
Ok(_) => {
let response = unsafe { &*(ack_data.as_ptr() as *const Dhcp) };
match get_message_type(&response.options) {
Some(DHCPACK) => { if verbose { println!("DHCP: renewed"); } }
Some(DHCPNAK) => {
if verbose { println!("DHCP: NAK, restarting"); }
return dhcp(iface, verbose);
}
_ => {}
}
}
Err(_) => {
if verbose { println!("DHCP: entering REBIND state"); }
let bind_socket = try_fmt!(UdpSocket::bind(("0.0.0.0", 68)), "failed to bind rebind");
try_fmt!(bind_socket.connect(SocketAddr::from(([255, 255, 255, 255], 67))), "rebind connect");
let mut rebind = Dhcp::default();
init_dhcp_header(&mut rebind, current_mac, tid.wrapping_add(2));
rebind.ciaddr = offer.yiaddr;
let rb_opts: &[u8] = &[OPT_MESSAGE_TYPE, 1, DHCPREQUEST, OPT_END];
rebind.options[..rb_opts.len()].copy_from_slice(rb_opts);
let _ = send_dhcp(&rebind, &bind_socket);
bind_socket.set_read_timeout(Some(Duration::from_secs(10))).ok();
if let Ok(_) = bind_socket.recv(&mut ack_data) {
if verbose { println!("DHCP: rebound"); }
} else {
if verbose { println!("DHCP: lease expired, restarting"); }
return dhcp(iface, verbose);
}
}
}
Ok(())
}
fn apply_dhcp_config(
iface: &str,
router: Option<[u8; 4]>,
dns: Option<[u8; 4]>,
verbose: bool,
) -> Result<(), String> {
if let Some(router) = router {
let route = format!("default via {}.{}.{}.{}", router[0], router[1], router[2], router[3]);
try_fmt!(set_cfg_value("route/add", &route), "failed to set route");
}
if let Some(mut dns) = dns {
if dns[0] == 127 {
dns = [9, 9, 9, 9];
if verbose { println!("DHCP: replaced loopback DNS with Quad9"); }
}
let ns = format!("{}.{}.{}.{}", dns[0], dns[1], dns[2], dns[3]);
try_fmt!(set_cfg_value("resolv/nameserver", &ns), "failed to set DNS");
}
Ok(())
}
fn compute_prefix_len(subnet: Option<[u8; 4]>) -> u32 {
let Some(subnet) = subnet else { return 24 };
let inverted: u32 = !u32::from_be_bytes(subnet);
inverted.leading_zeros()
}
fn parse_options(options: &[u8], cb: &mut dyn FnMut(u8, &[u8])) {
let mut i = 0;
while i < options.len() {
let code = options[i];
if code == 0 { i += 1; continue; }
if code == OPT_END { break; }
i += 1;
if i >= options.len() { break; }
let len = options[i] as usize;
i += 1;
if i + len > options.len() { break; }
cb(code, &options[i..i + len]);
i += len;
}
}
fn get_message_type(options: &[u8]) -> Option<u8> {
let mut msg_type = None;
parse_options(options, &mut |code, data| {
if code == OPT_MESSAGE_TYPE && data.len() == 1 {
msg_type = Some(data[0]);
}
});
msg_type
}
fn init_dhcp_header(pkt: &mut Dhcp, mac: MacAddr, tid: u32) {
*pkt = Dhcp::default();
pkt.op = 1;
pkt.htype = 1;
pkt.hlen = 6;
pkt.tid = tid;
pkt.flags = 0x8000u16.to_be();
pkt.chaddr[..6].copy_from_slice(&mac.bytes);
pkt.magic = 0x63825363u32.to_be();
}
fn send_dhcp(pkt: &Dhcp, socket: &UdpSocket) -> Result<(), String> {
let data = unsafe {
std::slice::from_raw_parts(pkt as *const Dhcp as *const u8, std::mem::size_of::<Dhcp>())
};
socket.send(data).map(|_| ()).map_err(|e| format!("send: {}", e))
}
impl Default for Dhcp {
fn default() -> Self {
Dhcp {
op: 0, htype: 0, hlen: 0, hops: 0, tid: 0, secs: 0, flags: 0,
ciaddr: [0; 4], yiaddr: [0; 4], siaddr: [0; 4], giaddr: [0; 4],
chaddr: [0; 16], sname: [0; 64], file: [0; 128], magic: 0,
options: [0; 308],
}
}
}
fn main() {
let mut verbose = false;
let iface = "eth0";
for arg in env::args().skip(1) {
match arg.as_ref() {
"-v" => verbose = true,
_ => (),
}
}
if let Err(err) = dhcp(iface, verbose) {
eprintln!("dhcpd: {err}");
process::exit(1);
}
}
#[cfg(test)]
mod test {
use super::MacAddr;
#[test]
fn from_str_test() {
let mac = MacAddr { bytes: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab] };
let empty_mac = MacAddr::default();
assert_eq!(mac, MacAddr::from_str("01:23:45:67:89:ab"));
assert_eq!(mac, MacAddr::from_str("1:23:45:67:89:ab"));
assert_eq!(mac, MacAddr::from_str("01:23:45:67:89:AB"));
assert_eq!(mac, MacAddr::from_str("01-23-45-67-89-ab"));
assert_eq!(empty_mac, MacAddr::from_str(""));
assert_eq!(empty_mac, MacAddr::from_str("01:23:45:67:89"));
assert_eq!(empty_mac, MacAddr::from_str("01:23:45:67:89:ab:cd"));
assert_eq!(empty_mac, MacAddr::from_str("x1:23:45:67:89:ab"));
assert_eq!(mac, MacAddr::from_str(&mac.to_string()));
}
}
-4
View File
@@ -1,4 +0,0 @@
[package]
name = "dhcpv6d"
version = "0.1.0"
edition = "2021"
-286
View File
@@ -1,286 +0,0 @@
//! dhcpv6d — DHCPv6 client daemon for Red Bear OS.
//!
//! Mirrors Linux 7.1's systemd-networkd `sd-dhcp6-client.c`.
//! Implements RFC 8415 state machine:
//! SOLICIT → ADVERTISE → REQUEST → REPLY
//!
//! Reference:
//! - `sd-dhcp6-client.c` — DHCPv6 client state machine
//! - RFC 8415 §17 — client behavior
//! - RFC 3315 — original DHCPv6 specification
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Write};
use std::net::{SocketAddr, UdpSocket};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use std::{env, process, time};
const DHCPV6_CLIENT_PORT: u16 = 546;
const DHCPV6_SERVER_PORT: u16 = 547;
const MULTICAST_ADDR: &str = "ff02::1:2";
const SOLICIT: u8 = 1;
const ADVERTISE: u8 = 2;
const REQUEST: u8 = 3;
const REPLY: u8 = 7;
const RELEASE: u8 = 8;
const INFO_REQUEST: u8 = 11;
const OPT_CLIENTID: u16 = 1;
const OPT_SERVERID: u16 = 2;
const OPT_IA_NA: u16 = 3;
const OPT_IAADDR: u16 = 5;
const OPT_ORO: u16 = 6;
const OPT_DNS: u16 = 23;
const OPT_DOMAIN: u16 = 24;
macro_rules! try_fmt {
($e:expr, $m:expr) => {
match $e {
Ok(ok) => ok,
Err(err) => return Err(format!("{}: {}", $m, err)),
}
};
}
fn set_cfg(path: &str, value: &str) -> Result<(), String> {
let full = format!("/scheme/netcfg/{path}");
let mut f = OpenOptions::new().write(true).create(false).open(&full)
.map_err(|_| format!("open {}", full))?;
f.write_all(value.as_bytes()).map_err(|_| format!("write {}", full))?;
f.sync_data().map_err(|_| "sync failed".into())
}
fn get_mac() -> Result<[u8; 6], String> {
let s = fs::read_to_string("/scheme/netcfg/ifaces/eth0/mac")
.map_err(|e| format!("read mac: {}", e))?;
let mut bytes = [0u8; 6];
for (i, part) in s.trim().split(&[':', '-'][..]).take(6).enumerate() {
bytes[i] = u8::from_str_radix(part, 16).map_err(|_| "bad mac".to_string())?;
}
Ok(bytes)
}
fn build_duid(mac: [u8; 6]) -> Vec<u8> {
let time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as u32;
let mut duid = vec![0u8; 14];
duid[0..2].copy_from_slice(&[0x00, 0x01]);
duid[2..4].copy_from_slice(&[0x00, 0x01]);
duid[4..8].copy_from_slice(&time.to_be_bytes());
duid[8..14].copy_from_slice(&mac);
duid
}
fn put_u16(buf: &mut Vec<u8>, val: u16) {
buf.extend_from_slice(&val.to_be_bytes());
}
fn put_u32(buf: &mut Vec<u8>, val: u32) {
buf.extend_from_slice(&val.to_be_bytes());
}
fn put_option(buf: &mut Vec<u8>, code: u16, data: &[u8]) {
put_u16(buf, code);
put_u16(buf, data.len() as u16);
buf.extend_from_slice(data);
}
struct Dhcp6Packet {
data: Vec<u8>,
}
impl Dhcp6Packet {
fn new(msg_type: u8, tid: [u8; 3], duid: &[u8]) -> Self {
let mut data = vec![msg_type];
data.extend_from_slice(&tid);
put_option(&mut data, OPT_CLIENTID, duid);
put_option(&mut data, OPT_ORO, &[0, OPT_DNS as u8, 0, OPT_DOMAIN as u8]);
Dhcp6Packet { data }
}
fn add_ia_na(&mut self, iaid: u32, t1: u32, t2: u32) {
let mut ia = Vec::new();
put_u32(&mut ia, iaid);
put_u32(&mut ia, t1);
put_u32(&mut ia, t2);
put_option(&mut self.data, OPT_IA_NA, &ia);
}
}
struct Dhcp6Reply {
msg_type: u8,
server_id: Option<Vec<u8>>,
addresses: Vec<([u8; 16], u32, u32)>,
dns_servers: Vec<[u8; 16]>,
domains: Vec<String>,
}
fn parse_reply(data: &[u8]) -> Result<Dhcp6Reply, String> {
if data.len() < 4 {
return Err("packet too short".into());
}
let msg_type = data[0];
let mut reply = Dhcp6Reply {
msg_type,
server_id: None,
addresses: Vec::new(),
dns_servers: Vec::new(),
domains: Vec::new(),
};
let mut pos = 4;
while pos + 4 <= data.len() {
let code = u16::from_be_bytes([data[pos], data[pos + 1]]);
let len = u16::from_be_bytes([data[pos + 2], data[pos + 3]]) as usize;
pos += 4;
if pos + len > data.len() {
break;
}
let opt_data = &data[pos..pos + len];
match code {
OPT_SERVERID => reply.server_id = Some(opt_data.to_vec()),
OPT_DNS => {
for chunk in opt_data.chunks(16) {
if chunk.len() == 16 {
let mut addr = [0u8; 16];
addr.copy_from_slice(chunk);
reply.dns_servers.push(addr);
}
}
}
OPT_IA_NA => {
if opt_data.len() >= 12 {
let t1 = u32::from_be_bytes([opt_data[4], opt_data[5], opt_data[6], opt_data[7]]);
let t2 = u32::from_be_bytes([opt_data[8], opt_data[9], opt_data[10], opt_data[11]]);
let mut inner = &opt_data[12..];
while inner.len() >= 4 {
let inner_code = u16::from_be_bytes([inner[0], inner[1]]);
let inner_len = u16::from_be_bytes([inner[2], inner[3]]) as usize;
inner = &inner[4..];
if inner.len() < inner_len { break; }
if inner_code == OPT_IAADDR && inner_len >= 24 {
let mut addr = [0u8; 16];
addr.copy_from_slice(&inner[..16]);
let pref = u32::from_be_bytes([inner[16], inner[17], inner[18], inner[19]]);
let valid = u32::from_be_bytes([inner[20], inner[21], inner[22], inner[23]]);
reply.addresses.push((addr, pref, valid));
}
inner = &inner[inner_len..];
}
}
}
_ => {}
}
pos += len;
}
Ok(reply)
}
fn main() {
let mut verbose = false;
for arg in env::args().skip(1) {
if arg == "-v" || arg == "--verbose" { verbose = true; }
}
if let Err(e) = run(verbose) {
eprintln!("dhcpv6d: {}", e);
process::exit(1);
}
}
fn run(verbose: bool) -> Result<(), String> {
let mac = get_mac()?;
let duid = build_duid(mac);
if verbose {
println!("dhcpv6d: DUID {:02x?}", duid);
}
let socket = try_fmt!(
UdpSocket::bind((MULTICAST_ADDR, DHCPV6_CLIENT_PORT)),
"bind"
);
try_fmt!(
socket.connect(SocketAddr::new(
MULTICAST_ADDR.parse().map_err(|_| "bad addr")?,
DHCPV6_SERVER_PORT,
)),
"connect"
);
try_fmt!(socket.set_read_timeout(Some(Duration::from_secs(5))), "timeout");
let tid = [
(mac[0] ^ mac[1]) as u8,
(mac[2] ^ mac[3]) as u8,
(mac[4] ^ mac[5]) as u8,
];
// SOLICIT
let mut solicit = Dhcp6Packet::new(SOLICIT, tid, &duid);
solicit.add_ia_na(1, 0, 0);
try_fmt!(socket.send(&solicit.data), "send solicit");
if verbose { println!("dhcpv6d: sent SOLICIT"); }
// Recv ADVERTISE
let mut buf = [0u8; 65536];
let n = try_fmt!(socket.recv(&mut buf), "recv advertise");
let adv = parse_reply(&buf[..n])?;
if verbose {
println!("dhcpv6d: received ADVERTISE, {} addresses", adv.addresses.len());
}
// REQUEST
let mut request = Dhcp6Packet::new(REQUEST, tid, &duid);
if let Some(ref sid) = adv.server_id {
put_option(&mut request.data, OPT_SERVERID, sid);
}
request.add_ia_na(1, 0, 0);
try_fmt!(socket.send(&request.data), "send request");
if verbose { println!("dhcpv6d: sent REQUEST"); }
// Recv REPLY
let n = try_fmt!(socket.recv(&mut buf), "recv reply");
let reply = parse_reply(&buf[..n])?;
if verbose {
println!("dhcpv6d: received REPLY, {} addresses", reply.addresses.len());
}
for (addr, pref, valid) in &reply.addresses {
let addr_str = format!(
"{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}",
u16::from_be_bytes([addr[0], addr[1]]),
u16::from_be_bytes([addr[2], addr[3]]),
u16::from_be_bytes([addr[4], addr[5]]),
u16::from_be_bytes([addr[6], addr[7]]),
u16::from_be_bytes([addr[8], addr[9]]),
u16::from_be_bytes([addr[10], addr[11]]),
u16::from_be_bytes([addr[12], addr[13]]),
u16::from_be_bytes([addr[14], addr[15]]),
);
let cidr = format!("{}/128\n", addr_str);
try_fmt!(set_cfg("ifaces/eth0/addr/set", &cidr), "set addr");
if verbose {
println!("dhcpv6d: configured {} (pref={}s valid={}s)", addr_str, pref, valid);
}
}
for dns in &reply.dns_servers {
let dns_str = format!(
"{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}",
u16::from_be_bytes([dns[0], dns[1]]),
u16::from_be_bytes([dns[2], dns[3]]),
u16::from_be_bytes([dns[4], dns[5]]),
u16::from_be_bytes([dns[6], dns[7]]),
u16::from_be_bytes([dns[8], dns[9]]),
u16::from_be_bytes([dns[10], dns[11]]),
u16::from_be_bytes([dns[12], dns[13]]),
u16::from_be_bytes([dns[14], dns[15]]),
);
try_fmt!(set_cfg("resolv/nameserver6", &dns_str), "set DNS");
if verbose { println!("dhcpv6d: DNS6 {}", dns_str); }
}
Ok(())
}
+117
View File
@@ -0,0 +1,117 @@
name: CI
on: [push, pull_request]
jobs:
test:
name: Test
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
rust: stable
- os: ubuntu-latest
rust: beta
- os: ubuntu-latest
rust: nightly
- os: macos-latest
rust: stable
- os: windows-latest
rust: stable
- os: ubuntu-latest
rust: stable
target: wasm32-wasip1
steps:
- uses: actions/checkout@v4
- run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
shell: bash
# Configure cross-builds by adding the rustup target and configuring future
# cargo invocations.
- run: |
rustup target add ${{ matrix.target }}
echo CARGO_BUILD_TARGET=${{ matrix.target }} >> $GITHUB_ENV
if: matrix.target != ''
# For wasm install wasmtime as a test runner and configure it with Cargo.
- name: Setup `wasmtime`
uses: bytecodealliance/actions/wasmtime/setup@v1
if: matrix.target == 'wasm32-wasip1'
- run: echo CARGO_TARGET_WASM32_WASIP1_RUNNER=wasmtime >> $GITHUB_ENV
if: matrix.target == 'wasm32-wasip1'
- run: cargo test
- run: cargo test --features debug
- run: cargo test --features global
- run: cargo test --release
env:
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: true
- run: cargo test --release
env:
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: false
- run: cargo test --features debug --release
env:
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: true
- run: RUSTFLAGS='--cfg test_lots' cargo test --release
shell: bash
env:
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: true
- run: RUSTFLAGS='--cfg test_lots' cargo test --release --features debug
shell: bash
env:
CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS: true
rustfmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update stable && rustup default stable && rustup component add rustfmt
- run: cargo fmt -- --check
wasm:
name: WebAssembly
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update stable && rustup default stable && rustup target add wasm32-unknown-unknown
- run: cargo build --target wasm32-unknown-unknown
- run: cargo build --target wasm32-unknown-unknown --release
external-platform:
name: external-platform
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update stable && rustup default stable && rustup target add x86_64-fortanix-unknown-sgx
- run: cargo build --target x86_64-fortanix-unknown-sgx
fuzz:
name: Build Fuzzers
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update nightly && rustup default nightly
- run: cargo install cargo-fuzz
- run: cargo fuzz build --dev
miri:
name: Miri
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Miri
run: |
rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri setup
- name: Test with Miri Stack Borrows
run: cargo miri test
- name: Test with Miri Tree Borrows
run: cargo miri test
env:
MIRIFLAGS: -Zmiri-tree-borrows
+3
View File
@@ -0,0 +1,3 @@
/target/
**/*.rs.bk
Cargo.lock
+70
View File
@@ -0,0 +1,70 @@
[package]
name = "dlmalloc"
version = "0.2.8"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
license = "MIT/Apache-2.0"
readme = "README.md"
repository = "https://github.com/alexcrichton/dlmalloc-rs"
homepage = "https://github.com/alexcrichton/dlmalloc-rs"
documentation = "https://docs.rs/dlmalloc"
description = """
A Rust port of the dlmalloc allocator
"""
edition.workspace = true
[workspace]
members = ['fuzz']
[workspace.package]
edition = '2021'
[package.metadata.docs.rs]
features = ['global']
[lib]
doctest = false
[target.'cfg(all(unix, not(target_arch = "wasm32")))'.dependencies]
libc = { version = "0.2", default-features = false, optional = true }
[dependencies]
# For more information on these dependencies see rust-lang/rust's
# `src/tools/rustc-std-workspace` folder
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
compiler_builtins = { version = '0.1.0', optional = true }
cfg-if = "1.0"
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
version = ">=0.52.0, <=0.59.*"
features = [
"Win32_Foundation",
"Win32_System_Memory",
"Win32_System_Threading",
"Win32_System_SystemInformation",
]
[dev-dependencies]
arbitrary = "1.3.2"
rand = { version = "0.8", features = ['small_rng'] }
[profile.release]
debug-assertions = true
[features]
# Enable implementations of the `GlobalAlloc` standard library API, exporting a
# new `GlobalDlmalloc` as well which implements this trait.
global = ["system", "rust_api"]
# Enable very expensive debug checks in this crate
debug = []
# Enables OS APIs based on the current target, can be implemented manually
# otherwise.
system = ["libc"]
rustc-dep-of-std = ['core', 'compiler_builtins/rustc-dep-of-std']
c_api = []
rust_api = []
default = ["global", "rust_api"]
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+25
View File
@@ -0,0 +1,25 @@
Copyright (c) 2014 Alex Crichton
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
+40
View File
@@ -0,0 +1,40 @@
# dlmalloc-rs
A port of [dlmalloc] to Rust.
[Documentation](https://docs.rs/dlmalloc)
[dlmalloc]: https://gee.cs.oswego.edu/dl/html/malloc.html
## Why dlmalloc?
This crate is a port of [dlmalloc] to Rust, and doesn't rely on C. The primary
purpose of this crate is to serve as the default allocator for Rust on the
`wasm32-unknown-unknown` target. At the time this was written the wasm target
didn't support C code, so it was required to have a Rust-only solution.
This allocator is not the most performant by a longshot. It is primarily, I
think, intended for being easy to port and easy to learn. I didn't dive too deep
into the implementation when writing it, it's just a straight port of the C
version.
It's unlikely that Rust code needs to worry/interact with this allocator in
general. Most of the time you'll be manually switching to a different allocator
:)
# License
This project is licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, as defined in the Apache-2.0 license,
shall be dual licensed as above, without any additional terms or conditions.
+2
View File
@@ -0,0 +1,2 @@
corpus
artifacts
+19
View File
@@ -0,0 +1,19 @@
[package]
name = "dlmalloc-fuzz"
version = "0.0.1"
publish = false
edition.workspace = true
[package.metadata]
cargo-fuzz = true
[dependencies]
arbitrary = "1.3.2"
dlmalloc = { path = '..' }
libfuzzer-sys = "0.4.7"
[[bin]]
name = "alloc"
path = "fuzz_targets/alloc.rs"
test = false
bench = false
+8
View File
@@ -0,0 +1,8 @@
#![no_main]
use arbitrary::Unstructured;
use libfuzzer_sys::fuzz_target;
fuzz_target!(|bytes: &[u8]| {
let _ = dlmalloc_fuzz::run(&mut Unstructured::new(bytes));
});
+108
View File
@@ -0,0 +1,108 @@
use arbitrary::{Result, Unstructured};
use dlmalloc::Dlmalloc;
use std::cmp;
const MAX_ALLOCATED: usize = 100 << 20; // 100 MB
pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
let mut a = Dlmalloc::new();
let mut ptrs = Vec::new();
let mut allocated = 0;
unsafe {
while u.arbitrary()? {
// If there are pointers to free then have a chance of deallocating
// a pointer. Try not to deallocate things until there's a "large"
// working set but afterwards give it a 50/50 chance of allocating
// or deallocating.
let free = match ptrs.len() {
0 => false,
0..=10_000 => u.ratio(1, 3)?,
_ => u.arbitrary()?,
};
if free {
let idx = u.choose_index(ptrs.len())?;
let (ptr, size, align) = ptrs.swap_remove(idx);
allocated -= size;
a.free(ptr, size, align);
continue;
}
// 1/100 chance of reallocating a pointer to a different size.
if ptrs.len() > 0 && u.ratio(1, 100)? {
let idx = u.choose_index(ptrs.len())?;
let (ptr, size, align) = ptrs.swap_remove(idx);
// Arbitrarily choose whether to make this allocation either
// twice as large or half as small.
let new_size = if u.arbitrary()? {
u.int_in_range(size..=size * 2)?
} else if size > 10 {
u.int_in_range(size / 2..=size)?
} else {
continue;
};
if allocated + new_size - size > MAX_ALLOCATED {
ptrs.push((ptr, size, align));
continue;
}
allocated -= size;
allocated += new_size;
// Perform the `realloc` and assert that all bytes were copied.
let mut tmp = Vec::new();
for i in 0..cmp::min(size, new_size) {
tmp.push(*ptr.offset(i as isize));
}
let ptr = a.realloc(ptr, size, align, new_size);
assert!(!ptr.is_null());
for (i, byte) in tmp.iter().enumerate() {
assert_eq!(*byte, *ptr.offset(i as isize));
}
ptrs.push((ptr, new_size, align));
}
// Aribtrarily choose a size to allocate as well as an alignment.
// Enable small sizes with standard alignment happening a fair bit.
let size = if u.arbitrary()? {
u.int_in_range(1..=128)?
} else {
u.int_in_range(1..=128 * 1024)?
};
let align = if u.ratio(1, 10)? {
1 << u.int_in_range(3..=8)?
} else {
8
};
if size + allocated > MAX_ALLOCATED {
continue;
}
allocated += size;
// Choose arbitrarily between a zero-allocated chunk and a normal
// allocated chunk.
let zero = u.ratio(1, 50)?;
let ptr = if zero {
a.calloc(size, align)
} else {
a.malloc(size, align)
};
for i in 0..size {
if zero {
assert_eq!(*ptr.offset(i as isize), 0);
}
*ptr.offset(i as isize) = 0xce;
}
ptrs.push((ptr, size, align));
}
// Deallocate everythign when we're done.
for (ptr, size, align) in ptrs {
a.free(ptr, size, align);
}
a.destroy();
}
Ok(())
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+42
View File
@@ -0,0 +1,42 @@
use crate::Allocator;
use core::ptr;
pub struct System {
_priv: (),
}
impl System {
pub const fn new() -> System {
System { _priv: () }
}
}
unsafe impl Allocator for System {
fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) {
(ptr::null_mut(), 0, 0)
}
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
ptr::null_mut()
}
fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
false
}
fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
false
}
fn can_release_part(&self, _flags: u32) -> bool {
false
}
fn allocates_zeros(&self) -> bool {
false
}
fn page_size(&self) -> usize {
1
}
}
+56
View File
@@ -0,0 +1,56 @@
use crate::Dlmalloc;
use core::alloc::{GlobalAlloc, Layout};
use core::ptr;
pub use crate::sys::enable_alloc_after_fork;
/// An instance of a "global allocator" backed by `Dlmalloc`
///
/// This API requires the `global` feature is activated, and this type
/// implements the `GlobalAlloc` trait in the standard library.
pub struct GlobalDlmalloc;
static mut DLMALLOC: Dlmalloc = Dlmalloc::new();
unsafe impl GlobalAlloc for GlobalDlmalloc {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let _guard = lock();
let dlmalloc = ptr::addr_of_mut!(DLMALLOC);
(*dlmalloc).malloc(layout.size(), layout.align())
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let _guard = lock();
let dlmalloc = ptr::addr_of_mut!(DLMALLOC);
(*dlmalloc).free(ptr, layout.size(), layout.align())
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let _guard = lock();
let dlmalloc = ptr::addr_of_mut!(DLMALLOC);
(*dlmalloc).calloc(layout.size(), layout.align())
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
let _guard = lock();
let dlmalloc = ptr::addr_of_mut!(DLMALLOC);
(*dlmalloc).realloc(ptr, layout.size(), layout.align(), new_size)
}
}
unsafe fn lock() -> impl Drop {
crate::sys::acquire_global_lock();
struct Guard;
impl Drop for Guard {
fn drop(&mut self) {
crate::sys::release_global_lock()
}
}
Guard
}
+230
View File
@@ -0,0 +1,230 @@
//! A Rust port of the `dlmalloc` allocator.
//!
//! The `dlmalloc` allocator is described at
//! <https://gee.cs.oswego.edu/dl/html/malloc.html> and this Rust crate is a straight
//! port of the C code for the allocator into Rust. The implementation is
//! wrapped up in a `Dlmalloc` type and has support for Linux, OSX, and Wasm
//! currently.
//!
//! The primary purpose of this crate is that it serves as the default memory
//! allocator for the `wasm32-unknown-unknown` target in the standard library.
//! Support for other platforms is largely untested and unused, but is used when
//! testing this crate.
#![allow(dead_code)]
#![no_std]
#![deny(missing_docs)]
#[cfg(feature = "rust_api")]
use core::{cmp, ptr};
#[cfg(feature = "system")]
use sys::System;
#[cfg(feature = "global")]
pub use self::global::{enable_alloc_after_fork, GlobalDlmalloc};
mod dlmalloc;
#[cfg(feature = "c_api")]
pub use dlmalloc::Dlmalloc as DlmallocCApi;
#[cfg(feature = "global")]
mod global;
/// In order for this crate to efficiently manage memory, it needs a way to communicate with the
/// underlying platform. This `Allocator` trait provides an interface for this communication.
pub unsafe trait Allocator: Send {
/// Allocates system memory region of at least `size` bytes
/// Returns a triple of `(base, size, flags)` where `base` is a pointer to the beginning of the
/// allocated memory region. `size` is the actual size of the region while `flags` specifies
/// properties of the allocated region. If `EXTERN_BIT` (bit 0) set in flags, then we did not
/// allocate this segment and so should not try to deallocate or merge with others.
/// This function can return a `std::ptr::null_mut()` when allocation fails (other values of
/// the triple will be ignored).
fn alloc(&self, size: usize) -> (*mut u8, usize, u32);
/// Remaps system memory region at `ptr` with size `oldsize` to a potential new location with
/// size `newsize`. `can_move` indicates if the location is allowed to move to a completely new
/// location, or that it is only allowed to change in size. Returns a pointer to the new
/// location in memory.
/// This function can return a `std::ptr::null_mut()` to signal an error.
fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8;
/// Frees a part of a memory chunk. The original memory chunk starts at `ptr` with size `oldsize`
/// and is turned into a memory region starting at the same address but with `newsize` bytes.
/// Returns `true` iff the access memory region could be freed.
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool;
/// Frees an entire memory region. Returns `true` iff the operation succeeded. When `false` is
/// returned, the `dlmalloc` may re-use the location on future allocation requests
fn free(&self, ptr: *mut u8, size: usize) -> bool;
/// Indicates if the system can release a part of memory. For the `flags` argument, see
/// `Allocator::alloc`
fn can_release_part(&self, flags: u32) -> bool;
/// Indicates whether newly allocated regions contain zeros.
fn allocates_zeros(&self) -> bool;
/// Returns the page size. Must be a power of two
fn page_size(&self) -> usize;
}
/// An allocator instance
///
/// Instances of this type are used to allocate blocks of memory. For best
/// results only use one of these. Currently doesn't implement `Drop` to release
/// lingering memory back to the OS. That may happen eventually though!
#[cfg(feature = "rust_api")]
pub struct Dlmalloc<
#[cfg(feature = "system")]
A = System,
#[cfg(not(feature = "system"))]
A,
>(dlmalloc::Dlmalloc<A>);
cfg_if::cfg_if! {
if #[cfg(all(feature = "system", target_family = "wasm"))] {
#[path = "wasm.rs"]
mod sys;
} else if #[cfg(all(feature = "system", target_os = "windows"))] {
#[path = "windows.rs"]
mod sys;
} else if #[cfg(all(feature = "system", target_os = "xous"))] {
#[path = "xous.rs"]
mod sys;
} else if #[cfg(all(feature = "system", any(target_os = "linux", target_os = "macos", target_os = "redox")))] {
#[path = "unix.rs"]
mod sys;
} else {
#[path = "dummy.rs"]
mod sys;
}
}
#[cfg(feature = "system")]
#[cfg(feature = "rust_api")]
impl Dlmalloc<System> {
/// Creates a new instance of an allocator
pub const fn new() -> Dlmalloc<System> {
Dlmalloc(dlmalloc::Dlmalloc::new(System::new()))
}
}
#[cfg(feature = "rust_api")]
impl<A> Dlmalloc<A> {
/// Creates a new instance of an allocator
pub const fn new_with_allocator(sys_allocator: A) -> Dlmalloc<A> {
Dlmalloc(dlmalloc::Dlmalloc::new(sys_allocator))
}
}
#[cfg(feature = "rust_api")]
impl<A: Allocator> Dlmalloc<A> {
/// Allocates `size` bytes with `align` align.
///
/// Returns a null pointer if allocation fails. Returns a valid pointer
/// otherwise.
///
/// Safety and contracts are largely governed by the `GlobalAlloc::alloc`
/// method contracts.
#[inline]
pub unsafe fn malloc(&mut self, size: usize, align: usize) -> *mut u8 {
if align <= self.0.malloc_alignment() {
self.0.malloc(size)
} else {
self.0.memalign(align, size)
}
}
/// Same as `malloc`, except if the allocation succeeds it's guaranteed to
/// point to `size` bytes of zeros.
#[inline]
pub unsafe fn calloc(&mut self, size: usize, align: usize) -> *mut u8 {
let ptr = self.malloc(size, align);
if !ptr.is_null() && self.0.calloc_must_clear(ptr) {
ptr::write_bytes(ptr, 0, size);
}
ptr
}
/// Deallocates a `ptr` with `size` and `align` as the previous request used
/// to allocate it.
///
/// Safety and contracts are largely governed by the `GlobalAlloc::dealloc`
/// method contracts.
#[inline]
pub unsafe fn free(&mut self, ptr: *mut u8, size: usize, align: usize) {
let _ = align;
self.0.validate_size(ptr, size);
self.0.free(ptr)
}
/// Reallocates `ptr`, a previous allocation with `old_size` and
/// `old_align`, to have `new_size` and the same alignment as before.
///
/// Returns a null pointer if the memory couldn't be reallocated, but `ptr`
/// is still valid. Returns a valid pointer and frees `ptr` if the request
/// is satisfied.
///
/// Safety and contracts are largely governed by the `GlobalAlloc::realloc`
/// method contracts.
#[inline]
pub unsafe fn realloc(
&mut self,
ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
) -> *mut u8 {
self.0.validate_size(ptr, old_size);
if old_align <= self.0.malloc_alignment() {
self.0.realloc(ptr, new_size)
} else {
let res = self.malloc(new_size, old_align);
if !res.is_null() {
let size = cmp::min(old_size, new_size);
ptr::copy_nonoverlapping(ptr, res, size);
self.free(ptr, old_size, old_align);
}
res
}
}
/// If possible, gives memory back to the system if there is unused memory
/// at the high end of the malloc pool or in unused segments.
///
/// You can call this after freeing large blocks of memory to potentially
/// reduce the system-level memory requirements of a program. However, it
/// cannot guarantee to reduce memory. Under some allocation patterns, some
/// large free blocks of memory will be locked between two used chunks, so
/// they cannot be given back to the system.
///
/// The `pad` argument represents the amount of free trailing space to
/// leave untrimmed. If this argument is zero, only the minimum amount of
/// memory to maintain internal data structures will be left. Non-zero
/// arguments can be supplied to maintain enough trailing space to service
/// future expected allocations without having to re-obtain memory from the
/// system.
///
/// Returns `true` if it actually released any memory, else `false`.
pub unsafe fn trim(&mut self, pad: usize) -> bool {
self.0.trim(pad)
}
/// Releases all allocations in this allocator back to the system,
/// consuming self and preventing further use.
///
/// Returns the number of bytes released to the system.
pub unsafe fn destroy(self) -> usize {
self.0.destroy()
}
/// Get a reference the underlying [`Allocator`] that this `Dlmalloc` was
/// constructed with.
pub fn allocator(&self) -> &A {
self.0.allocator()
}
}
+131
View File
@@ -0,0 +1,131 @@
use crate::Allocator;
use core::ptr;
/// System setting for Linux
pub struct System {
_priv: (),
}
impl System {
pub const fn new() -> System {
System { _priv: () }
}
}
#[cfg(feature = "global")]
static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
unsafe impl Allocator for System {
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
let addr = unsafe {
libc::mmap(
ptr::null_mut(),
size,
libc::PROT_WRITE | libc::PROT_READ,
libc::MAP_ANON | libc::MAP_PRIVATE,
-1,
0,
)
};
if addr == libc::MAP_FAILED {
(ptr::null_mut(), 0, 0)
} else {
(addr.cast(), size, 0)
}
}
#[cfg(target_os = "linux")]
fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8 {
let flags = if can_move { libc::MREMAP_MAYMOVE } else { 0 };
let ptr = unsafe { libc::mremap(ptr.cast(), oldsize, newsize, flags) };
if ptr == libc::MAP_FAILED {
ptr::null_mut()
} else {
ptr.cast()
}
}
#[cfg(any(target_os = "redox", target_os = "macos"))]
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
ptr::null_mut()
}
#[cfg(target_os = "linux")]
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool {
unsafe {
let rc = libc::mremap(ptr.cast(), oldsize, newsize, 0);
if rc != libc::MAP_FAILED {
return true;
}
libc::munmap(ptr.add(newsize).cast(), oldsize - newsize) == 0
}
}
#[cfg(any(target_os = "redox", target_os = "macos"))]
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool {
unsafe { libc::munmap(ptr.add(newsize).cast(), oldsize - newsize) == 0 }
}
fn free(&self, ptr: *mut u8, size: usize) -> bool {
unsafe { libc::munmap(ptr.cast(), size) == 0 }
}
fn can_release_part(&self, _flags: u32) -> bool {
true
}
fn allocates_zeros(&self) -> bool {
true
}
fn page_size(&self) -> usize {
4096
}
}
#[cfg(feature = "global")]
pub fn acquire_global_lock() {
unsafe { assert_eq!(libc::pthread_mutex_lock(ptr::addr_of_mut!(LOCK)), 0) }
}
#[cfg(feature = "global")]
pub fn release_global_lock() {
unsafe { assert_eq!(libc::pthread_mutex_unlock(ptr::addr_of_mut!(LOCK)), 0) }
}
#[cfg(feature = "global")]
/// allows the allocator to remain unsable in the child process,
/// after a call to `fork(2)`
///
/// #Safety
///
/// if used, this function must be called,
/// before any allocations are made with the global allocator.
pub unsafe fn enable_alloc_after_fork() {
// atfork must only be called once, to avoid a deadlock,
// where the handler attempts to acquire the global lock twice
static mut FORK_PROTECTED: bool = false;
unsafe extern "C" fn _acquire_global_lock() {
acquire_global_lock()
}
unsafe extern "C" fn _release_global_lock() {
release_global_lock()
}
acquire_global_lock();
// if a process forks,
// it will acquire the lock before any other thread,
// protecting it from deadlock,
// due to the child being created with only the calling thread.
if !FORK_PROTECTED {
libc::pthread_atfork(
Some(_acquire_global_lock),
Some(_release_global_lock),
Some(_release_global_lock),
);
FORK_PROTECTED = true;
}
release_global_lock();
}
+76
View File
@@ -0,0 +1,76 @@
use crate::Allocator;
#[cfg(target_arch = "wasm32")]
use core::arch::wasm32 as wasm;
#[cfg(target_arch = "wasm64")]
use core::arch::wasm64 as wasm;
use core::ptr;
/// System setting for Wasm
pub struct System {
_priv: (),
}
impl System {
pub const fn new() -> System {
System { _priv: () }
}
}
unsafe impl Allocator for System {
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
let pages = size / self.page_size();
let prev = wasm::memory_grow(0, pages);
if prev == usize::max_value() {
return (ptr::null_mut(), 0, 0);
}
(
(prev * self.page_size()) as *mut u8,
pages * self.page_size(),
0,
)
}
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
// TODO: I think this can be implemented near the end?
ptr::null_mut()
}
fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
false
}
fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
false
}
fn can_release_part(&self, _flags: u32) -> bool {
false
}
fn allocates_zeros(&self) -> bool {
true
}
fn page_size(&self) -> usize {
64 * 1024
}
}
#[cfg(feature = "global")]
pub fn acquire_global_lock() {
// single threaded, no need!
assert!(!cfg!(target_feature = "atomics"));
}
#[cfg(feature = "global")]
pub fn release_global_lock() {
// single threaded, no need!
assert!(!cfg!(target_feature = "atomics"));
}
#[allow(missing_docs)]
#[cfg(feature = "global")]
pub unsafe fn enable_alloc_after_fork() {
// single threaded, no need!
assert!(!cfg!(target_feature = "atomics"));
}
+88
View File
@@ -0,0 +1,88 @@
use crate::Allocator;
use core::mem::MaybeUninit;
use core::ptr;
use windows_sys::Win32::System::Memory::*;
use windows_sys::Win32::System::SystemInformation::*;
#[cfg(feature = "global")]
use windows_sys::Win32::System::Threading::*;
pub struct System {
_priv: (),
}
impl System {
pub const fn new() -> System {
System { _priv: () }
}
}
unsafe impl Allocator for System {
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
let addr = unsafe {
VirtualAlloc(
ptr::null_mut(),
size,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE,
)
};
if addr.is_null() {
(ptr::null_mut(), 0, 0)
} else {
(addr.cast(), size, 0)
}
}
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
ptr::null_mut()
}
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool {
unsafe { VirtualFree(ptr.add(newsize).cast(), oldsize - newsize, MEM_DECOMMIT) != 0 }
}
fn free(&self, ptr: *mut u8, _size: usize) -> bool {
unsafe { VirtualFree(ptr.cast(), 0, MEM_DECOMMIT) != 0 }
}
fn can_release_part(&self, _flags: u32) -> bool {
true
}
fn allocates_zeros(&self) -> bool {
true
}
fn page_size(&self) -> usize {
unsafe {
let mut info = MaybeUninit::uninit();
GetSystemInfo(info.as_mut_ptr());
info.assume_init_ref().dwPageSize as usize
}
}
}
// NB: `SRWLOCK_INIT` doesn't appear to be in `windows-sys`
#[cfg(feature = "global")]
static mut LOCK: SRWLOCK = SRWLOCK {
Ptr: ptr::null_mut(),
};
#[cfg(feature = "global")]
pub fn acquire_global_lock() {
unsafe {
AcquireSRWLockExclusive(ptr::addr_of_mut!(LOCK));
}
}
#[cfg(feature = "global")]
pub fn release_global_lock() {
unsafe {
ReleaseSRWLockExclusive(ptr::addr_of_mut!(LOCK));
}
}
/// Not needed on Windows
#[cfg(feature = "global")]
pub unsafe fn enable_alloc_after_fork() {}
+117
View File
@@ -0,0 +1,117 @@
use crate::Allocator;
use core::ptr;
pub struct System {
_priv: (),
}
impl System {
pub const fn new() -> System {
System { _priv: () }
}
}
#[cfg(target_arch = "riscv32")]
mod sys {
use core::arch::asm;
pub fn increase_heap(length: usize) -> Result<(usize, usize), ()> {
let syscall_no_increase_heap = 10usize;
let memory_flags_read_write = 2usize | 4usize;
let mut a0 = syscall_no_increase_heap;
let mut a1 = length;
let mut a2 = memory_flags_read_write;
unsafe {
asm!(
"ecall",
inlateout("a0") a0,
inlateout("a1") a1,
inlateout("a2") a2,
out("a3") _,
out("a4") _,
out("a5") _,
out("a6") _,
out("a7") _,
)
};
let result = a0;
let address = a1;
let length = a2;
// 3 is the "MemoryRange" type, and the result is only valid
// if we get nonzero address and length.
if result == 3 && address != 0 && length != 0 {
Ok((address, length))
} else {
Err(())
}
}
}
unsafe impl Allocator for System {
/// Allocate an additional `size` bytes on the heap, and return a new
/// chunk of memory, as well as the size of the allocation and some
/// flags. Since flags are unused on this platform, they will always
/// be `0`.
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
let size = if size == 0 {
4096
} else if size & 4095 == 0 {
size
} else {
size + (4096 - (size & 4095))
};
if let Ok((address, length)) = sys::increase_heap(size) {
let start = address - size + length;
(start as *mut u8, size, 0)
} else {
(ptr::null_mut(), 0, 0)
}
}
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
// TODO
ptr::null_mut()
}
fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
false
}
fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
false
}
fn can_release_part(&self, _flags: u32) -> bool {
false
}
fn allocates_zeros(&self) -> bool {
true
}
fn page_size(&self) -> usize {
4 * 1024
}
}
#[cfg(feature = "global")]
pub fn acquire_global_lock() {
// global feature should not be enabled
unimplemented!()
}
#[cfg(feature = "global")]
pub fn release_global_lock() {
// global feature should not be enabled
unimplemented!()
}
#[cfg(feature = "global")]
pub unsafe fn enable_alloc_after_fork() {
// platform does not support `fork()` call
}
+32
View File
@@ -0,0 +1,32 @@
extern crate dlmalloc;
use std::collections::HashMap;
use std::thread;
#[global_allocator]
#[cfg(feature = "global")]
static A: dlmalloc::GlobalDlmalloc = dlmalloc::GlobalDlmalloc;
#[test]
fn foo() {
println!("hello");
}
#[test]
fn map() {
let mut m = HashMap::new();
m.insert(1, 2);
m.insert(5, 3);
drop(m);
}
#[test]
fn strings() {
format!("foo, bar, {}", "baz");
}
#[test]
#[cfg(not(target_family = "wasm"))]
fn threads() {
assert!(thread::spawn(|| panic!()).join().is_err());
}
+36
View File
@@ -0,0 +1,36 @@
use arbitrary::Unstructured;
use dlmalloc::Dlmalloc;
use rand::{rngs::SmallRng, RngCore, SeedableRng};
#[test]
fn smoke() {
let mut a = Dlmalloc::new();
unsafe {
let ptr = a.malloc(1, 1);
assert!(!ptr.is_null());
*ptr = 9;
assert_eq!(*ptr, 9);
a.free(ptr, 1, 1);
let ptr = a.malloc(1, 1);
assert!(!ptr.is_null());
*ptr = 10;
assert_eq!(*ptr, 10);
a.free(ptr, 1, 1);
}
}
#[path = "../fuzz/src/lib.rs"]
mod fuzz;
#[test]
fn stress() {
let mut rng = SmallRng::seed_from_u64(0);
let mut buf = vec![0; 4096];
let iters = if cfg!(miri) { 5 } else { 2000 };
for _ in 0..iters {
rng.fill_bytes(&mut buf);
let mut u = Unstructured::new(&buf);
let _ = fuzz::run(&mut u);
}
}
-63
View File
@@ -1,63 +0,0 @@
# Community Hardware
This document tracks the devices from developers or community that need a driver.
This document was created because unfortunately we can't know the most sold device models of the world to measure our device porting priority, thus we will use our community data to measure our device priorities, if you find a "device model users" survey (similar to [Debian Popularity Contest](https://popcon.debian.org/) and [Steam Hardware/Software Survey](https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam)), please comment.
If you want to contribute to this table, install [pciutils](https://mj.ucw.cz/sw/pciutils/) on your Linux or Unix-like distribution (it may have a package on your distribution), run the `lspci -v` command to see your hardware devices, their kernel drivers and give the results of these items on each device:
- The first field (each device has an unique name for this item)
- Kernel driver
- Kernel module
If you are unsure of what to do, you can talk with us on the [chat](https://doc.redox-os.org/book/chat.html).
## Template
You will use this template to insert your devices on the table.
```
| | | | No |
```
- Remove the `#` characters in the port numbers to avoid GitLab issues to be wrongly mentioned
## Devices
| **Device model** | **Kernel driver?** | **Kernel module?** | **There's a Redox driver?** |
|------------------|--------------------|--------------------|-----------------------------|
| Realtek RTL8821CE 802.11ac (Wi-Fi) | rtw_8821ce | rtw88_8821ce | No |
| Intel Ice Lake-LP SPI Controller | intel-spi | spi_intel_pci | No |
| Intel Ice Lake-LP SMBus Controller | i801_smbus | i2c_i801 | No |
| Intel Ice Lake-LP Smart Sound Technology Audio Controller | snd_hda_intel | snd_hda_intel, snd_sof_pci_intel_icl | No |
| Intel Ice Lake-LP Serial IO SPI Controller | intel-lpss | No | No |
| Intel Ice Lake-LP Serial IO UART Controller | intel-lpss | No | No |
| Intel Ice Lake-LP Serial IO I2C Controller | intel-lpss | No | No |
| Ice Lake-LP USB 3.1 xHCI Host Controller | xhci_hcd | No | No |
| Intel Processor Power and Thermal Controller | proc_thermal | processor_thermal_device_pci_legacy | No |
| Intel Device 8a02 | icl_uncore | No | No |
| Iris Plus Graphics G1 (Ice Lake) | i915 | i915 | No |
| Intel Corporation Raptor Lake-P 6p+8e cores Host Bridge/DRAM Controller | No | No | No |
| Intel Corporation Raptor Lake PCI Express 5.0 Graphics Port (PEG010) (prog-if 00 [Normal decode]) | pcieport | No | No |
| Intel Corporation Raptor Lake-P [UHD Graphics] (rev 04) (prog-if 00 [VGA controller]) | i915 | i915 | No |
| Intel Corporation Raptor Lake Dynamic Platform and Thermal Framework Processor Participant | proc_thermal_pci | processor_thermal_device_pci | No |
| Intel Corporation Raptor Lake PCIe 4.0 Graphics Port (prog-if 00 [Normal decode]) | pcieport | No | No |
| Intel Corporation Raptor Lake-P Thunderbolt 4 PCI Express Root Port 0 (prog-if 00 [Normal decode]) | pcieport | No | No |
| Intel Corporation GNA Scoring Accelerator module | No | No | No |
| Intel Corporation Raptor Lake-P Thunderbolt 4 USB Controller (prog-if 30 [XHCI]) | xhci_hcd | xhci_pci | No |
| Intel Corporation Raptor Lake-P Thunderbolt 4 NHI 0 (prog-if 40 [USB4 Host Interface]) | thunderbolt | thunderbolt | No |
| Intel Corporation Raptor Lake-P Thunderbolt 4 NHI 1 (prog-if 40 [USB4 Host Interface]) | thunderbolt | thunderbolt | No |
| Intel Corporation Alder Lake PCH USB 3.2 xHCI Host Controller (rev 01) (prog-if 30 [XHCI]) | xhci_hcd | xhci_pci | No |
| Intel Corporation Alder Lake PCH Shared SRAM (rev 01) | No | No | No |
| Intel Corporation Raptor Lake PCH CNVi WiFi (rev 01) | iwlwifi | iwlwifi | No |
| Intel Corporation Alder Lake PCH Serial IO I2C Controller #0 (rev 01) | intel-lpss | intel_lpss_pci | No |
| Intel Corporation Alder Lake PCH HECI Controller (rev 01) | mei_me | mei_me | No |
| Intel Corporation Device 51b8 (rev 01) (prog-if 00 [Normal decode]) | pcieport | No | No |
| Intel Corporation Alder Lake-P PCH PCIe Root Port 6 (rev 01) (prog-if 00 [Normal decode]) | pcieport | No | No |
| Intel Corporation Raptor Lake LPC/eSPI Controller (rev 01) | No | No | No |
| Intel Corporation Raptor Lake-P/U/H cAVS (rev 01) (prog-if 80) | sof-audio-pci-intel-tgl | snd_hda_intel, snd_sof_pci_intel_tgl | No |
| Intel Corporation Alder Lake PCH-P SMBus Host Controller | i801_smbus | i2c_i801 | No |
| Intel Corporation Alder Lake-P PCH SPI Controller (rev 01) | intel-spi | spi_intel_pci | No |
| NVIDIA Corporation GA107GLM [RTX A1000 6GB Laptop GPU] (rev a1) | nvidia | nouveau, nvidia_drm, nvidia | No |
| SK hynix Platinum P41/PC801 NVMe Solid State Drive (prog-if 02 [NVM Express]) | nvme | nvme | No |
| Realtek Semiconductor Co., Ltd. RTS5261 PCI Express Card Reader (rev 01) | rtsx_pci | rtsx_pci | No |
-160
View File
@@ -1,160 +0,0 @@
# Drivers
- [Libraries](#libraries)
- [Services](#services)
- [Hardware Interfaces](#hardware-interfaces)
- [Devices](#devices)
- [CPU](#cpu)
- [Controllers](#controllers)
- [Storage](#storage)
- [Graphics](#graphics)
- [Input](#input)
- [Sound](#sound)
- [Networking](#networking)
- [Virtualization](#virtualization)
- [System Interfaces](#system-interfaces)
- [System Calls](#system-calls)
- [Schemes](#schemes)
- [Contribution Details](#contribution-details)
## Libraries
- amlserde - Library to provide serialization/deserialization of the AML symbol table from ACPI
- common - Library with shared driver code
- executor - Library to run Rust futures and integrate the executor in an interrupt+queue model without a separated reactor thread
- [graphics/console-draw](graphics/console-draw/) - Library with shared terminal drawing code
- [graphics/driver-graphics](graphics/driver-graphics/) - Library with shared graphics code
- [graphics/graphics-ipc](graphics/graphics-ipc/) - Library with graphics IPC shared code
- [net/driver-network](net/driver-network/) - Library with shared networking code
- [storage/partitionlib](storage/partitionlib/) - Library with MBR and GPT code
- [storage/driver-block](storage/driver-block/) - Library with shared storage code
- virtio-core - VirtIO driver library
## Services
- [graphics/fbbootlogd](graphics/fbbootlogd/) - Daemon for boot log drawing
- [graphics/fbcond](graphics/fbcond/) - Terminal daemon
- hwd - Daemon that handle the ACPI and DeviceTree booting
- inputd - Multiplexes input from multiple input drivers and provides that to Orbital
- pcid-spawner - Daemon for PCI-based device driver spawn
- [storage/lived](storage/lived/) - Daemon for live disk
- redoxerd - Daemon that send/receive terminal text between the host system and QEMU
## Hardware Interfaces
- acpid - ACPI interface driver
- pcid - PCI and PCI Express driver
## Devices
### CPU
- rtcd - x86 Real Time Clock driver
### Controllers
- [usb/xhcid](usb/xhcid/) - xHCI USB controller driver
### Storage
- [storage/ahcid](storage/ahcid/) - AHCI (SATA) driver
- [storage/bcm2835-sdhcid](storage/bcm2835-sdhcid/) - BCM2835 storage driver
- [storage/ided](storage/ided/) - PATA (IDE) driver
- [storage/nvmed](storage/nvmed/) - NVMe driver
- [storage/virtio-blkd](storage/virtio-blkd/) - VirtIO block device driver
- [storage/usbscsid](storage/usbscsid/) - USB SCSI driver
### Graphics
- [graphics/ihdgd](graphics/ihdgd/) - Intel graphics driver
- [graphics/vesad](graphics/vesad/) - VESA video driver
- [graphics/virtio-gpud](graphics/virtio-gpud/) - VirtIO-GPU device driver
### Input
- [input/ps2d](input/ps2d/) - PS/2 interface driver
- [input/usbhidd](input/usbhidd/) - USB HID driver
- [usb/usbhubd](usb/usbhubd/) - USB Hub driver
- [usb/usbctl](usb/usbctl/) - TODO
### Sound
- [audio/ac97d](audio/ac97d/) - AC'97 codec driver
- [audio/ihdad](audio/ihdad/) - Intel HD Audio chipset driver
- [audio/sb16d](audio/sb16d/) - Sound Blaster sound card driver
### Networking
- [net/e1000d](net/e1000d/) - Intel Gigabit ethernet driver
- [net/ixgbed](net/ixgbed/) - Intel 10 Gigabit ethernet driver
- [net/rtl8139d](net/rtl8139d/), [net/rtl8168d](net/rtl8168d/) - Realtek ethernet drivers
- [net/virtio-netd](net/virtio-netd/) - VirtIO network device driver
### Virtualization
- vboxd - VirtualBox driver
Some drivers are work-in-progress and incomplete, read [this](https://gitlab.redox-os.org/redox-os/base/-/issues/56) tracking issue to verify.
## System Interfaces
This section explain the system interfaces used by drivers.
### System Calls
- `iopl` : system call that sets the I/O privilege level. x86 has four privilege rings (0/1/2/3), of which the kernel runs in ring 0 and userspace in ring 3. IOPL can only be changed by the kernel, for obvious security reasons, and therefore the Redox kernel needs root to set it. It is unique for each process. Processes with IOPL=3 can access I/O ports, and the kernel can access them as well.
### Schemes
- `/scheme/memory/physical` : Allows mapping physical memory frames to driver-accessible virtual memory pages, with various available memory types:
- `/scheme/memory/physical` : Default memory type (currently writeback)
- `/scheme/memory/physical@wb` Writeback cached memory
- `/scheme/memory/physical@uc` : Uncacheable memory
- `/scheme/memory/physical@wc` : Write-combining memory
- `/scheme/irq` : Allows getting events from interrupts. It is used primarily by listening for its file descriptors using the `/scheme/event` scheme.
## Contribution Details
### Driver Design
A device driver on Redox is an user-space daemon that use system calls and schemes to work, while operating systems with monolithic kernels drivers use internal kernel APIs instead of common program APIs.
If you want to port a driver from a monolithic operating system to Redox you will need to rewrite the driver with reverse enginnering of the code logic, because the logic is adapted to internal kernel APIs (it's a hard task if the device is complex, datasheets are much more easy).
### Write a Driver
Datasheets are preferable (much more easy depending on device complexity), when they are freely available. Be aware that datasheets are often provided under a [Non-Disclosure Agreement](https://en.wikipedia.org/wiki/Non-disclosure_agreement) from hardware vendors, which can affect the ability to create an MIT-licensed driver.
If datasheets aren't available you need to do reverse-engineering of BSD or Linux drivers (if you want use a Linux driver as reference for your Redox driver please ask in the [Chat](https://doc.redox-os.org/book/chat.html) before the implementation to know/satisfy the license requirements and not waste your time, also if you use a BSD driver not licensed as BSD as reference).
### Libraries
You should use the [redox-scheme](https://crates.io/crates/redox-scheme) and [redox_event](https://crates.io/crates/redox_event) libraries to create your drivers, you can also read the [example driver](https://gitlab.redox-os.org/redox-os/exampled) or read the code of other drivers with the same type of your device.
Before testing your changes be aware of [this](https://doc.redox-os.org/book/coding-and-building.html#how-to-update-initfs).
### References
If you want to reverse enginner the existing drivers, you can access the BSD code using these links:
- [FreeBSD drivers](https://github.com/freebsd/freebsd-src/tree/main/sys/dev)
- [NetBSD drivers](https://github.com/NetBSD/src/tree/trunk/sys/dev)
- [OpenBSD drivers](https://github.com/openbsd/src/tree/master/sys/dev)
## How To Contribute
To learn how to contribute to this system component you need to read the following document:
- [CONTRIBUTING.md](https://gitlab.redox-os.org/redox-os/redox/-/blob/master/CONTRIBUTING.md)
## Development
To learn how to do development with this system component inside the Redox build system you need to read the [Build System](https://doc.redox-os.org/book/build-system-reference.html) and [Coding and Building](https://doc.redox-os.org/book/coding-and-building.html) pages.
### How To Build
To build this system component you need to download the Redox build system, you can learn how to do it on the [Building Redox](https://doc.redox-os.org/book/podman-build.html) page.
This is necessary because they only work with cross-compilation to a Redox virtual machine or real hardware, but you can do some testing from Linux.
[Back to top](#drivers)
-13
View File
@@ -1,13 +0,0 @@
[package]
name = "acpi-resource"
description = "Shared ACPI resource template decoder"
version = "0.0.1"
authors = ["Red Bear OS"]
repository = "https://gitlab.redox-os.org/redox-os/drivers"
categories = ["hardware-support"]
license = "MIT/Apache-2.0"
edition = "2021"
[dependencies]
serde.workspace = true
thiserror.workspace = true
-688
View File
@@ -1,688 +0,0 @@
use serde::{Deserialize, Serialize};
use thiserror::Error;
const SMALL_IRQ: u8 = 0x20;
const SMALL_END_TAG: u8 = 0x78;
const LARGE_MEMORY32: u8 = 0x85;
const LARGE_FIXED_MEMORY32: u8 = 0x86;
const LARGE_ADDRESS32: u8 = 0x87;
const LARGE_EXTENDED_IRQ: u8 = 0x89;
const LARGE_ADDRESS64: u8 = 0x8A;
const LARGE_GPIO: u8 = 0x8C;
const LARGE_SERIAL_BUS: u8 = 0x8E;
const SERIAL_BUS_I2C: u8 = 1;
const I2C_TYPE_DATA_LEN: usize = 6;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum InterruptTrigger {
Edge,
Level,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum InterruptPolarity {
ActiveHigh,
ActiveLow,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum AddressResourceType {
MemoryRange,
IoRange,
BusNumberRange,
Unknown(u8),
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ResourceSource {
pub index: u8,
pub source: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct IrqDescriptor {
pub interrupts: Vec<u8>,
pub triggering: InterruptTrigger,
pub polarity: InterruptPolarity,
pub shareable: bool,
pub wake_capable: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExtendedIrqDescriptor {
pub producer_consumer: bool,
pub interrupts: Vec<u32>,
pub triggering: InterruptTrigger,
pub polarity: InterruptPolarity,
pub shareable: bool,
pub wake_capable: bool,
pub resource_source: Option<ResourceSource>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct GpioDescriptor {
pub revision_id: u8,
pub producer_consumer: bool,
pub pin_config: u8,
pub shareable: bool,
pub wake_capable: bool,
pub io_restriction: u8,
pub triggering: InterruptTrigger,
pub polarity: InterruptPolarity,
pub drive_strength: u16,
pub debounce_timeout: u16,
pub pins: Vec<u16>,
pub resource_source: Option<ResourceSource>,
pub vendor_data: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct I2cSerialBusDescriptor {
pub revision_id: u8,
pub producer_consumer: bool,
pub slave_mode: bool,
pub connection_sharing: bool,
pub type_revision_id: u8,
pub access_mode_10bit: bool,
pub slave_address: u16,
pub connection_speed: u32,
pub resource_source: Option<ResourceSource>,
pub vendor_data: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Memory32RangeDescriptor {
pub write_protect: bool,
pub minimum: u32,
pub maximum: u32,
pub alignment: u32,
pub address_length: u32,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct FixedMemory32Descriptor {
pub write_protect: bool,
pub address: u32,
pub address_length: u32,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Address32Descriptor {
pub resource_type: AddressResourceType,
pub producer_consumer: bool,
pub decode: bool,
pub min_address_fixed: bool,
pub max_address_fixed: bool,
pub specific_flags: u8,
pub granularity: u32,
pub minimum: u32,
pub maximum: u32,
pub translation_offset: u32,
pub address_length: u32,
pub resource_source: Option<ResourceSource>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Address64Descriptor {
pub resource_type: AddressResourceType,
pub producer_consumer: bool,
pub decode: bool,
pub min_address_fixed: bool,
pub max_address_fixed: bool,
pub specific_flags: u8,
pub granularity: u64,
pub minimum: u64,
pub maximum: u64,
pub translation_offset: u64,
pub address_length: u64,
pub resource_source: Option<ResourceSource>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ResourceDescriptor {
Irq(IrqDescriptor),
ExtendedIrq(ExtendedIrqDescriptor),
GpioInt(GpioDescriptor),
GpioIo(GpioDescriptor),
I2cSerialBus(I2cSerialBusDescriptor),
Memory32Range(Memory32RangeDescriptor),
FixedMemory32(FixedMemory32Descriptor),
Address32(Address32Descriptor),
Address64(Address64Descriptor),
}
#[derive(Debug, Error, PartialEq, Eq)]
pub enum ResourceDecodeError {
#[error("descriptor at offset {offset} overruns the resource template")]
TruncatedDescriptor { offset: usize },
#[error("unsupported small descriptor length {length} for tag {tag:#04x} at offset {offset}")]
InvalidSmallLength {
offset: usize,
tag: u8,
length: usize,
},
#[error("descriptor {descriptor} at offset {offset} is shorter than {minimum} bytes")]
InvalidLargeLength {
offset: usize,
descriptor: &'static str,
minimum: usize,
},
#[error("descriptor {descriptor} at offset {offset} has an invalid internal offset")]
InvalidInternalOffset {
offset: usize,
descriptor: &'static str,
},
}
pub fn decode_resource_template(
bytes: &[u8],
) -> Result<Vec<ResourceDescriptor>, ResourceDecodeError> {
let mut resources = Vec::new();
let mut offset = 0usize;
while offset < bytes.len() {
let descriptor = *bytes
.get(offset)
.ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?;
if descriptor & 0x80 == 0 {
let length = usize::from(descriptor & 0x07);
let end = offset + 1 + length;
let desc = bytes
.get(offset..end)
.ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?;
let body = &desc[1..];
match descriptor & 0x78 {
SMALL_IRQ => resources.push(ResourceDescriptor::Irq(parse_irq(body, offset)?)),
SMALL_END_TAG => break,
_ => {}
}
offset = end;
continue;
}
let length = usize::from(read_u16(bytes, offset + 1)?);
let end = offset + 3 + length;
let desc = bytes
.get(offset..end)
.ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?;
let body = &desc[3..];
match descriptor {
LARGE_MEMORY32 => resources.push(ResourceDescriptor::Memory32Range(parse_memory32(
body, offset,
)?)),
LARGE_FIXED_MEMORY32 => resources.push(ResourceDescriptor::FixedMemory32(
parse_fixed_memory32(body, offset)?,
)),
LARGE_ADDRESS32 => {
resources.push(ResourceDescriptor::Address32(parse_address32(
desc, body, offset,
)?));
}
LARGE_ADDRESS64 => {
resources.push(ResourceDescriptor::Address64(parse_address64(
desc, body, offset,
)?));
}
LARGE_EXTENDED_IRQ => resources.push(ResourceDescriptor::ExtendedIrq(
parse_extended_irq(desc, body, offset)?,
)),
LARGE_GPIO => {
let (is_interrupt, descriptor) = parse_gpio(desc, body, offset)?;
resources.push(if is_interrupt {
ResourceDescriptor::GpioInt(descriptor)
} else {
ResourceDescriptor::GpioIo(descriptor)
});
}
LARGE_SERIAL_BUS => {
if let Some(descriptor) = parse_i2c_serial_bus(desc, body, offset)? {
resources.push(ResourceDescriptor::I2cSerialBus(descriptor));
}
}
_ => {}
}
offset = end;
}
Ok(resources)
}
fn parse_irq(body: &[u8], offset: usize) -> Result<IrqDescriptor, ResourceDecodeError> {
if body.len() != 2 && body.len() != 3 {
return Err(ResourceDecodeError::InvalidSmallLength {
offset,
tag: SMALL_IRQ,
length: body.len(),
});
}
let mask = u16::from_le_bytes([body[0], body[1]]);
let flags = body.get(2).copied().unwrap_or(0);
let interrupts = (0..16)
.filter(|irq| mask & (1 << irq) != 0)
.map(|irq| irq as u8)
.collect();
Ok(IrqDescriptor {
interrupts,
triggering: if flags & 0x01 != 0 {
InterruptTrigger::Level
} else {
InterruptTrigger::Edge
},
polarity: if flags & 0x08 != 0 {
InterruptPolarity::ActiveLow
} else {
InterruptPolarity::ActiveHigh
},
shareable: flags & 0x10 != 0,
wake_capable: flags & 0x20 != 0,
})
}
fn parse_extended_irq(
desc: &[u8],
body: &[u8],
offset: usize,
) -> Result<ExtendedIrqDescriptor, ResourceDecodeError> {
ensure_length(body, 2, offset, "ExtendedIrq")?;
let flags = body[0];
let count = usize::from(body[1]);
let ints_len = count * 4;
ensure_length(body, 2 + ints_len, offset, "ExtendedIrq")?;
let interrupts = (0..count)
.map(|index| read_u32(body, 2 + index * 4))
.collect::<Result<Vec<_>, _>>()?;
let resource_source = if body.len() > 2 + ints_len {
Some(parse_source_inline(&body[2 + ints_len..]))
} else {
None
};
let _ = desc;
Ok(ExtendedIrqDescriptor {
producer_consumer: flags & 0x01 != 0,
triggering: if flags & 0x02 != 0 {
InterruptTrigger::Level
} else {
InterruptTrigger::Edge
},
polarity: if flags & 0x04 != 0 {
InterruptPolarity::ActiveLow
} else {
InterruptPolarity::ActiveHigh
},
shareable: flags & 0x08 != 0,
wake_capable: flags & 0x10 != 0,
interrupts,
resource_source,
})
}
fn parse_gpio(
desc: &[u8],
body: &[u8],
offset: usize,
) -> Result<(bool, GpioDescriptor), ResourceDecodeError> {
ensure_length(body, 20, offset, "Gpio")?;
let connection_type = body[1];
let flags = read_u16(body, 2)?;
let int_flags = read_u16(body, 4)?;
let pin_table_offset = usize::from(read_u16(body, 11)?);
let resource_source_index = body[13];
let resource_source_offset = usize::from(read_u16(body, 14)?);
let vendor_offset = usize::from(read_u16(body, 16)?);
let vendor_length = usize::from(read_u16(body, 18)?);
let pins_end = min_nonzero([resource_source_offset, vendor_offset, desc.len()]);
let pins = parse_u16_list(desc, pin_table_offset, pins_end, offset, "Gpio")?;
let resource_source = parse_source_absolute(
desc,
resource_source_offset,
min_nonzero([vendor_offset, desc.len()]),
resource_source_index,
offset,
"Gpio",
)?;
let vendor_data = parse_blob_absolute(desc, vendor_offset, vendor_length, offset, "Gpio")?;
Ok((
connection_type == 0,
GpioDescriptor {
revision_id: body[0],
producer_consumer: flags & 0x0001 != 0,
pin_config: body[6],
shareable: int_flags & 0x0008 != 0,
wake_capable: int_flags & 0x0010 != 0,
io_restriction: (int_flags & 0x0003) as u8,
triggering: if int_flags & 0x0001 != 0 {
InterruptTrigger::Level
} else {
InterruptTrigger::Edge
},
polarity: if int_flags & 0x0002 != 0 {
InterruptPolarity::ActiveLow
} else {
InterruptPolarity::ActiveHigh
},
drive_strength: read_u16(body, 7)?,
debounce_timeout: read_u16(body, 9)?,
pins,
resource_source,
vendor_data,
},
))
}
fn parse_i2c_serial_bus(
desc: &[u8],
body: &[u8],
offset: usize,
) -> Result<Option<I2cSerialBusDescriptor>, ResourceDecodeError> {
ensure_length(body, 15, offset, "SerialBus")?;
if body[2] != SERIAL_BUS_I2C {
return Ok(None);
}
let type_data_length = usize::from(read_u16(body, 7)?);
if type_data_length < I2C_TYPE_DATA_LEN {
return Err(ResourceDecodeError::InvalidLargeLength {
offset,
descriptor: "I2cSerialBus",
minimum: 15,
});
}
let vendor_length = type_data_length - I2C_TYPE_DATA_LEN;
let vendor_data = parse_blob_absolute(desc, 18, vendor_length, offset, "I2cSerialBus")?;
let resource_source = parse_source_absolute(
desc,
12 + type_data_length,
desc.len(),
body[1],
offset,
"I2cSerialBus",
)?;
Ok(Some(I2cSerialBusDescriptor {
revision_id: body[0],
producer_consumer: body[3] & 0x02 != 0,
slave_mode: body[3] & 0x01 != 0,
connection_sharing: body[3] & 0x04 != 0,
type_revision_id: body[6],
access_mode_10bit: read_u16(body, 4)? & 0x0001 != 0,
connection_speed: read_u32(body, 9)?,
slave_address: read_u16(body, 13)?,
resource_source,
vendor_data,
}))
}
fn parse_memory32(
body: &[u8],
offset: usize,
) -> Result<Memory32RangeDescriptor, ResourceDecodeError> {
ensure_length(body, 17, offset, "Memory32Range")?;
Ok(Memory32RangeDescriptor {
write_protect: body[0] & 0x01 != 0,
minimum: read_u32(body, 1)?,
maximum: read_u32(body, 5)?,
alignment: read_u32(body, 9)?,
address_length: read_u32(body, 13)?,
})
}
fn parse_fixed_memory32(
body: &[u8],
offset: usize,
) -> Result<FixedMemory32Descriptor, ResourceDecodeError> {
ensure_length(body, 9, offset, "FixedMemory32")?;
Ok(FixedMemory32Descriptor {
write_protect: body[0] & 0x01 != 0,
address: read_u32(body, 1)?,
address_length: read_u32(body, 5)?,
})
}
fn parse_address32(
desc: &[u8],
body: &[u8],
offset: usize,
) -> Result<Address32Descriptor, ResourceDecodeError> {
ensure_length(body, 23, offset, "Address32")?;
Ok(Address32Descriptor {
resource_type: parse_address_type(body[0]),
producer_consumer: body[1] & 0x01 != 0,
decode: body[1] & 0x02 != 0,
min_address_fixed: body[1] & 0x04 != 0,
max_address_fixed: body[1] & 0x08 != 0,
specific_flags: body[2],
granularity: read_u32(body, 3)?,
minimum: read_u32(body, 7)?,
maximum: read_u32(body, 11)?,
translation_offset: read_u32(body, 15)?,
address_length: read_u32(body, 19)?,
resource_source: if desc.len() > 26 {
parse_source_absolute(desc, 26, desc.len(), desc[26], offset, "Address32")?
} else {
None
},
})
}
fn parse_address64(
desc: &[u8],
body: &[u8],
offset: usize,
) -> Result<Address64Descriptor, ResourceDecodeError> {
ensure_length(body, 43, offset, "Address64")?;
Ok(Address64Descriptor {
resource_type: parse_address_type(body[0]),
producer_consumer: body[1] & 0x01 != 0,
decode: body[1] & 0x02 != 0,
min_address_fixed: body[1] & 0x04 != 0,
max_address_fixed: body[1] & 0x08 != 0,
specific_flags: body[2],
granularity: read_u64(body, 3)?,
minimum: read_u64(body, 11)?,
maximum: read_u64(body, 19)?,
translation_offset: read_u64(body, 27)?,
address_length: read_u64(body, 35)?,
resource_source: if desc.len() > 46 {
parse_source_absolute(desc, 46, desc.len(), desc[46], offset, "Address64")?
} else {
None
},
})
}
fn ensure_length(
body: &[u8],
minimum: usize,
offset: usize,
descriptor: &'static str,
) -> Result<(), ResourceDecodeError> {
if body.len() < minimum {
return Err(ResourceDecodeError::InvalidLargeLength {
offset,
descriptor,
minimum,
});
}
Ok(())
}
fn parse_source_inline(bytes: &[u8]) -> ResourceSource {
let index = bytes.first().copied().unwrap_or(0);
let source = bytes.get(1..).map(parse_nul_string).unwrap_or_default();
ResourceSource { index, source }
}
fn parse_source_absolute(
desc: &[u8],
start: usize,
end: usize,
index: u8,
offset: usize,
descriptor: &'static str,
) -> Result<Option<ResourceSource>, ResourceDecodeError> {
if start == 0 || start >= end || start > desc.len() {
return Ok(None);
}
let slice = desc
.get(start..end)
.ok_or(ResourceDecodeError::InvalidInternalOffset { offset, descriptor })?;
Ok(Some(ResourceSource {
index,
source: parse_nul_string(slice),
}))
}
fn parse_blob_absolute(
desc: &[u8],
start: usize,
length: usize,
offset: usize,
descriptor: &'static str,
) -> Result<Vec<u8>, ResourceDecodeError> {
if start == 0 || length == 0 {
return Ok(Vec::new());
}
let end = start + length;
Ok(desc
.get(start..end)
.ok_or(ResourceDecodeError::InvalidInternalOffset { offset, descriptor })?
.to_vec())
}
fn parse_u16_list(
desc: &[u8],
start: usize,
end: usize,
offset: usize,
descriptor: &'static str,
) -> Result<Vec<u16>, ResourceDecodeError> {
if start == 0 || start >= end || start > desc.len() {
return Ok(Vec::new());
}
let slice = desc
.get(start..end)
.ok_or(ResourceDecodeError::InvalidInternalOffset { offset, descriptor })?;
if slice.len() % 2 != 0 {
return Err(ResourceDecodeError::InvalidInternalOffset { offset, descriptor });
}
slice
.chunks_exact(2)
.map(|chunk| Ok(u16::from_le_bytes([chunk[0], chunk[1]])))
.collect()
}
fn parse_nul_string(bytes: &[u8]) -> String {
let end = bytes
.iter()
.position(|byte| *byte == 0)
.unwrap_or(bytes.len());
String::from_utf8_lossy(&bytes[..end]).to_string()
}
fn parse_address_type(value: u8) -> AddressResourceType {
match value {
0 => AddressResourceType::MemoryRange,
1 => AddressResourceType::IoRange,
2 => AddressResourceType::BusNumberRange,
other => AddressResourceType::Unknown(other),
}
}
fn read_u16(bytes: &[u8], offset: usize) -> Result<u16, ResourceDecodeError> {
let slice = bytes
.get(offset..offset + 2)
.ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?;
Ok(u16::from_le_bytes([slice[0], slice[1]]))
}
fn read_u32(bytes: &[u8], offset: usize) -> Result<u32, ResourceDecodeError> {
let slice = bytes
.get(offset..offset + 4)
.ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?;
Ok(u32::from_le_bytes([slice[0], slice[1], slice[2], slice[3]]))
}
fn read_u64(bytes: &[u8], offset: usize) -> Result<u64, ResourceDecodeError> {
let slice = bytes
.get(offset..offset + 8)
.ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?;
Ok(u64::from_le_bytes([
slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
]))
}
fn min_nonzero<const N: usize>(values: [usize; N]) -> usize {
values
.into_iter()
.filter(|value| *value != 0)
.min()
.unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::{decode_resource_template, ResourceDescriptor};
#[test]
fn decodes_small_irq_descriptor() {
let resources = decode_resource_template(&[0x23, 0x0A, 0x00, 0x19, 0x79, 0x00]).unwrap();
assert!(matches!(
&resources[0],
ResourceDescriptor::Irq(descriptor)
if descriptor.interrupts == vec![1, 3]
&& descriptor.shareable
&& descriptor.wake_capable == false
));
}
#[test]
fn decodes_i2c_serial_bus_descriptor() {
let template = [
0x8E, 0x14, 0x00, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x01, 0x06, 0x00, 0x80, 0x1A,
0x06, 0x00, 0x15, 0x00, b'I', b'2', b'C', b'0', 0x00, 0x79, 0x00,
];
let resources = decode_resource_template(&template).unwrap();
assert!(matches!(
&resources[0],
ResourceDescriptor::I2cSerialBus(descriptor)
if descriptor.connection_speed == 400_000
&& descriptor.slave_address == 0x15
&& descriptor.resource_source.as_ref().map(|source| source.source.as_str())
== Some("I2C0")
));
}
#[test]
fn decodes_gpio_interrupt_descriptor() {
let template = [
0x8C, 0x1B, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17,
0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x12, b'\\', b'_', b'S', b'B',
0x00, 0x79, 0x00,
];
let resources = decode_resource_template(&template).unwrap();
assert!(matches!(&resources[0], ResourceDescriptor::GpioInt(_)));
}
}
-33
View File
@@ -1,33 +0,0 @@
[package]
name = "acpid"
description = "ACPI daemon"
version = "0.1.0"
authors = ["4lDO2 <4lDO2@protonmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
acpi.workspace = true
arrayvec = "0.7.6"
log.workspace = true
num-derive = "0.3"
num-traits = "0.2"
parking_lot.workspace = true
plain.workspace = true
redox_syscall.workspace = true
redox_event.workspace = true
rustc-hash = "1.1.0"
thiserror.workspace = true
ron.workspace = true
serde.workspace = true
amlserde = { path = "../amlserde" }
common = { path = "../common" }
daemon = { path = "../../daemon" }
libredox.workspace = true
redox-scheme.workspace = true
scheme-utils = { path = "../../scheme-utils" }
[lints]
workspace = true
File diff suppressed because it is too large Load Diff
-128
View File
@@ -1,128 +0,0 @@
use std::ops::{Deref, DerefMut};
use common::io::Mmio;
// TODO: Only wrap with Mmio where there are hardware-registers. (Some of these structs seem to be
// ring buffer entries, which are not to be treated the same way).
pub struct DrhdPage {
virt: *mut Drhd,
}
impl DrhdPage {
pub fn map(base_phys: usize) -> syscall::Result<Self> {
assert_eq!(
base_phys % crate::acpi::PAGE_SIZE,
0,
"DRHD registers must be page-aligned"
);
// TODO: Uncachable? Can reads have side-effects?
let virt = unsafe {
common::physmap(
base_phys,
crate::acpi::PAGE_SIZE,
common::Prot::RO,
common::MemoryType::default(),
)?
} as *mut Drhd;
Ok(Self { virt })
}
}
impl Deref for DrhdPage {
type Target = Drhd;
fn deref(&self) -> &Self::Target {
unsafe { &*self.virt }
}
}
impl DerefMut for DrhdPage {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.virt }
}
}
impl Drop for DrhdPage {
fn drop(&mut self) {
unsafe {
let _ = libredox::call::munmap(self.virt.cast(), crate::acpi::PAGE_SIZE);
}
}
}
#[repr(C, packed)]
pub struct DrhdFault {
pub sts: Mmio<u32>,
pub ctrl: Mmio<u32>,
pub data: Mmio<u32>,
pub addr: [Mmio<u32>; 2],
_rsv: [Mmio<u64>; 2],
pub log: Mmio<u64>,
}
#[repr(C, packed)]
pub struct DrhdProtectedMemory {
pub en: Mmio<u32>,
pub low_base: Mmio<u32>,
pub low_limit: Mmio<u32>,
pub high_base: Mmio<u64>,
pub high_limit: Mmio<u64>,
}
#[repr(C, packed)]
pub struct DrhdInvalidation {
pub queue_head: Mmio<u64>,
pub queue_tail: Mmio<u64>,
pub queue_addr: Mmio<u64>,
_rsv: Mmio<u32>,
pub cmpl_sts: Mmio<u32>,
pub cmpl_ctrl: Mmio<u32>,
pub cmpl_data: Mmio<u32>,
pub cmpl_addr: [Mmio<u32>; 2],
}
#[repr(C, packed)]
pub struct DrhdPageRequest {
pub queue_head: Mmio<u64>,
pub queue_tail: Mmio<u64>,
pub queue_addr: Mmio<u64>,
_rsv: Mmio<u32>,
pub sts: Mmio<u32>,
pub ctrl: Mmio<u32>,
pub data: Mmio<u32>,
pub addr: [Mmio<u32>; 2],
}
#[repr(C, packed)]
pub struct DrhdMtrrVariable {
pub base: Mmio<u64>,
pub mask: Mmio<u64>,
}
#[repr(C, packed)]
pub struct DrhdMtrr {
pub cap: Mmio<u64>,
pub def_type: Mmio<u64>,
pub fixed: [Mmio<u64>; 11],
pub variable: [DrhdMtrrVariable; 10],
}
#[repr(C, packed)]
pub struct Drhd {
pub version: Mmio<u32>,
_rsv: Mmio<u32>,
pub cap: Mmio<u64>,
pub ext_cap: Mmio<u64>,
pub gl_cmd: Mmio<u32>,
pub gl_sts: Mmio<u32>,
pub root_table: Mmio<u64>,
pub ctx_cmd: Mmio<u64>,
_rsv1: Mmio<u32>,
pub fault: DrhdFault,
_rsv2: Mmio<u32>,
pub pm: DrhdProtectedMemory,
pub invl: DrhdInvalidation,
_rsv3: Mmio<u64>,
pub intr_table: Mmio<u64>,
pub page_req: DrhdPageRequest,
pub mtrr: DrhdMtrr,
}
-557
View File
@@ -1,557 +0,0 @@
//! DMA Remapping Table -- `DMAR`. This is Intel's implementation of IOMMU functionality, known as
//! VT-d.
//!
//! Too understand what all of these structs mean, refer to the "Intel(R) Virtualization
//! Technology for Directed I/O" specification.
// TODO: Move this code to a separate driver as well?
use std::convert::TryFrom;
use std::ops::Deref;
use std::{fmt, mem};
use common::io::Io as _;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use self::drhd::DrhdPage;
use crate::acpi::{AcpiContext, Sdt, SdtHeader};
pub mod drhd;
#[repr(C, packed)]
pub struct DmarStruct {
pub sdt_header: SdtHeader,
pub host_addr_width: u8,
pub flags: u8,
pub _rsvd: [u8; 10],
// This header is followed by N remapping structures.
}
unsafe impl plain::Plain for DmarStruct {}
/// The DMA Remapping Table
#[derive(Debug)]
pub struct Dmar(Sdt);
impl Dmar {
fn remmapping_structs_area(&self) -> &[u8] {
&self.0.as_slice()[mem::size_of::<DmarStruct>()..]
}
}
impl Deref for Dmar {
type Target = DmarStruct;
fn deref(&self) -> &Self::Target {
plain::from_bytes(self.0.as_slice())
.expect("expected Dmar struct to already have checked the length, and alignment issues should be impossible due to #[repr(packed)]")
}
}
impl Dmar {
// TODO: Again, perhaps put this code into a different driver, and read the table the regular
// way via the acpi scheme?
///
/// Phase E.4 fix: `init` now takes an opt-in flag. DMAR init was
/// previously disabled because MMIO reads (e.g. `gl_sts.read()`) on
/// some real hardware block or spin forever. The MMIO read loop has
/// a hard iteration limit to prevent hangs regardless of hardware
/// behavior, and callers must explicitly opt in via `init_with(..., true)`.
/// The high-level `init(acpi_ctx)` now calls `init_with(acpi_ctx, false)`
/// for safety, so DMAR is **not** initialized by default in this fork.
pub fn init(acpi_ctx: &AcpiContext) {
Self::init_with(acpi_ctx, false)
}
pub fn init_with(acpi_ctx: &AcpiContext, opt_in: bool) {
if !opt_in {
log::debug!("DMAR init skipped (opt-in not set; set REDBEAR_DMAR_INIT=1 to enable)");
return;
}
let dmar_sdt = match acpi_ctx.take_single_sdt(*b"DMAR") {
Some(dmar_sdt) => dmar_sdt,
None => {
log::warn!("Unable to find `DMAR` ACPI table.");
return;
}
};
let dmar = match Dmar::new(dmar_sdt) {
Some(dmar) => dmar,
None => {
log::error!("Failed to parse DMAR table, possibly malformed.");
return;
}
};
log::info!("Found DMAR: {}: {}", dmar.host_addr_width, dmar.flags);
log::debug!("DMAR: {:?}", dmar);
// Hard cap on DMAR entries to process. Real hardware typically
// has 1-4 DRHDs; cap at 32 to prevent any infinite-iterator
// hang in case of a malformed table.
const MAX_DMAR_ENTRIES: usize = 32;
let mut entry_count = 0;
for dmar_entry in dmar.iter().take(MAX_DMAR_ENTRIES) {
entry_count += 1;
log::debug!("DMAR entry: {:?}", dmar_entry);
match dmar_entry {
DmarEntry::Drhd(dmar_drhd) => {
let drhd = dmar_drhd.map();
log::debug!("VER: {:X}", drhd.version.read());
log::debug!("CAP: {:X}", drhd.cap.read());
log::debug!("EXT_CAP: {:X}", drhd.ext_cap.read());
log::debug!("GCMD: {:X}", drhd.gl_cmd.read());
log::debug!("GSTS: {:X}", drhd.gl_sts.read());
log::debug!("RT: {:X}", drhd.root_table.read());
}
_ => (),
}
}
if entry_count == MAX_DMAR_ENTRIES {
log::warn!(
"DMAR table reached the {} entry cap; truncating further processing",
MAX_DMAR_ENTRIES
);
}
}
fn new(sdt: Sdt) -> Option<Dmar> {
assert_eq!(
sdt.signature, *b"DMAR",
"signature already checked against `DMAR`"
);
if sdt.length() < mem::size_of::<DmarStruct>() {
log::error!(
"The DMAR table was too small ({} B < {} B).",
sdt.length(),
mem::size_of::<Dmar>()
);
return None;
}
// No need to check alignment for #[repr(packed)] structs.
Some(Dmar(sdt))
}
pub fn iter(&self) -> DmarIter<'_> {
DmarIter(DmarRawIter {
bytes: self.remmapping_structs_area(),
})
}
}
/// DMAR DMA Remapping Hardware Unit Definition
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct DmarDrhdHeader {
pub kind: u16,
pub length: u16,
pub flags: u8,
pub _rsv: u8,
pub segment: u16,
pub base: u64,
}
unsafe impl plain::Plain for DmarDrhdHeader {}
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct DeviceScopeHeader {
pub ty: u8,
pub len: u8,
pub _rsvd: u16,
pub enumeration_id: u8,
pub start_bus_num: u8,
// The variable-sized path comes after.
}
unsafe impl plain::Plain for DeviceScopeHeader {}
pub struct DeviceScope(Box<[u8]>);
impl DeviceScope {
pub fn try_new(raw: &[u8]) -> Option<Self> {
// TODO: Check ty.
let header_bytes = match raw.get(..mem::size_of::<DeviceScopeHeader>()) {
Some(bytes) => bytes,
None => return None,
};
let header = plain::from_bytes::<DeviceScopeHeader>(header_bytes)
.expect("length already checked, and alignment 1 (#[repr(packed)] should suffice");
let len = usize::from(header.len);
if len > raw.len() {
log::warn!("Device scope smaller than len field.");
return None;
}
Some(Self(raw.into()))
}
}
impl fmt::Debug for DeviceScope {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DeviceScope")
.field("header", &*self as &DeviceScopeHeader)
.field("path", &self.path())
.finish()
}
}
impl Deref for DeviceScope {
type Target = DeviceScopeHeader;
fn deref(&self) -> &Self::Target {
plain::from_bytes(&self.0)
.expect("expected length to be sufficient, and alignment (due to #[repr(packed)]")
}
}
impl DeviceScope {
pub fn path(&self) -> &[u8] {
&self.0[mem::size_of::<DeviceScopeHeader>()..]
}
}
pub struct DmarDrhd(Box<[u8]>);
impl DmarDrhd {
pub fn try_new(raw: &[u8]) -> Option<Self> {
if raw.len() < mem::size_of::<DmarDrhdHeader>() {
return None;
}
Some(Self(raw.into()))
}
pub fn device_scope_area(&self) -> &[u8] {
&self.0[mem::size_of::<DmarDrhdHeader>()..]
}
pub fn map(&self) -> DrhdPage {
let base = usize::try_from(self.base).expect("expected u64 to fit within usize");
DrhdPage::map(base).expect("failed to map DRHD registers")
}
}
impl Deref for DmarDrhd {
type Target = DmarDrhdHeader;
fn deref(&self) -> &Self::Target {
plain::from_bytes::<DmarDrhdHeader>(&self.0[..mem::size_of::<DmarDrhdHeader>()])
.expect("length is already checked, and alignment 1 (#[repr(packed)] should suffice")
}
}
impl fmt::Debug for DmarDrhd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DmarDrhd")
.field("header", &*self as &DmarDrhd)
// TODO: print out device scopes
.finish()
}
}
/// DMAR Reserved Memory Region Reporting
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct DmarRmrrHeader {
pub kind: u16,
pub length: u16,
pub _rsv: u16,
pub segment: u16,
pub base: u64,
pub limit: u64,
// The device scopes come after.
}
unsafe impl plain::Plain for DmarRmrrHeader {}
pub struct DmarRmrr(Box<[u8]>);
impl DmarRmrr {
pub fn try_new(raw: &[u8]) -> Option<Self> {
if raw.len() < mem::size_of::<DmarRmrrHeader>() {
return None;
}
Some(Self(raw.into()))
}
}
impl Deref for DmarRmrr {
type Target = DmarRmrrHeader;
fn deref(&self) -> &Self::Target {
plain::from_bytes(&self.0[..mem::size_of::<DmarRmrrHeader>()])
.expect("length already checked, and with #[repr(packed)] alignment should be okay")
}
}
impl fmt::Debug for DmarRmrr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DmarRmrr")
.field("header", &*self as &DmarRmrrHeader)
// TODO: print out device scopes
.finish()
}
}
/// DMAR Root Port ATS Capability Reporting
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct DmarAtsrHeader {
kind: u16,
length: u16,
flags: u8,
_rsv: u8,
segment: u16,
// The device scopes come after.
}
unsafe impl plain::Plain for DmarAtsrHeader {}
pub struct DmarAtsr(Box<[u8]>);
impl DmarAtsr {
pub fn try_new(raw: &[u8]) -> Option<Self> {
if raw.len() < mem::size_of::<DmarAtsrHeader>() {
return None;
}
Some(Self(raw.into()))
}
}
impl Deref for DmarAtsr {
type Target = DmarAtsrHeader;
fn deref(&self) -> &Self::Target {
plain::from_bytes(&self.0[..mem::size_of::<DmarAtsrHeader>()])
.expect("length already checked, and with #[repr(packed)] alignment should be okay")
}
}
impl fmt::Debug for DmarAtsr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DmarAtsr")
.field("header", &*self as &DmarAtsrHeader)
// TODO: print out device scopes
.finish()
}
}
/// DMAR Remapping Hardware Static Affinity
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct DmarRhsa {
pub kind: u16,
pub length: u16,
pub _rsv: u32,
pub base: u64,
pub domain: u32,
}
unsafe impl plain::Plain for DmarRhsa {}
impl DmarRhsa {
pub fn try_new(raw: &[u8]) -> Option<Self> {
let bytes = raw.get(..mem::size_of::<DmarRhsa>())?;
let this = plain::from_bytes(bytes)
.expect("length is already checked, and alignment 1 should suffice (#[repr(packed)])");
Some(*this)
}
}
/// DMAR ACPI Name-space Device Declaration
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct DmarAnddHeader {
pub kind: u16,
pub length: u16,
pub _rsv: [u8; 3],
pub acpi_dev: u8,
// The device scopes come after.
}
unsafe impl plain::Plain for DmarAnddHeader {}
pub struct DmarAndd(Box<[u8]>);
impl DmarAndd {
pub fn try_new(raw: &[u8]) -> Option<Self> {
if raw.len() < mem::size_of::<DmarAnddHeader>() {
return None;
}
Some(Self(raw.into()))
}
}
impl Deref for DmarAndd {
type Target = DmarAnddHeader;
fn deref(&self) -> &Self::Target {
plain::from_bytes(&self.0[..mem::size_of::<DmarAnddHeader>()])
.expect("length already checked, and with #[repr(packed)] alignment should be okay")
}
}
impl fmt::Debug for DmarAndd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DmarAndd")
.field("header", &*self as &DmarAnddHeader)
// TODO: print out device scopes
.finish()
}
}
/// DMAR ACPI Name-space Device Declaration
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct DmarSatcHeader {
pub kind: u16,
pub length: u16,
pub flags: u8,
pub _rsvd: u8,
pub seg_num: u16,
// The device scopes come after.
}
unsafe impl plain::Plain for DmarSatcHeader {}
pub struct DmarSatc(Box<[u8]>);
impl DmarSatc {
pub fn try_new(raw: &[u8]) -> Option<Self> {
if raw.len() < mem::size_of::<DmarSatcHeader>() {
return None;
}
Some(Self(raw.into()))
}
}
impl Deref for DmarSatc {
type Target = DmarSatcHeader;
fn deref(&self) -> &Self::Target {
plain::from_bytes(&self.0[..mem::size_of::<DmarSatcHeader>()])
.expect("length already checked, and with #[repr(packed)] alignment should be okay")
}
}
impl fmt::Debug for DmarSatc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DmarSatc")
.field("header", &*self as &DmarSatcHeader)
// TODO: print out device scopes
.finish()
}
}
/// The list of different "Remapping Structure Types".
///
/// Refer to section 8.2 in the VTIO spec (as of revision 3.2).
#[derive(Clone, Copy, Debug, FromPrimitive)]
#[repr(u16)]
pub enum EntryType {
Drhd = 0,
Rmrr = 1,
Atsr = 2,
Rhsa = 3,
Andd = 4,
Satc = 5,
}
/// DMAR Entries
#[derive(Debug)]
pub enum DmarEntry {
Drhd(DmarDrhd),
Rmrr(DmarRmrr),
Atsr(DmarAtsr),
Rhsa(DmarRhsa),
Andd(DmarAndd),
// TODO: "SoC Integrated Address Translation Cache Reporting Structure".
Satc(DmarSatc),
TooShort(EntryType),
Unknown(u16),
}
struct DmarRawIter<'sdt> {
bytes: &'sdt [u8],
}
impl<'sdt> Iterator for DmarRawIter<'sdt> {
type Item = (u16, &'sdt [u8]);
fn next(&mut self) -> Option<Self::Item> {
let type_bytes = match self.bytes.get(..2) {
Some(bytes) => bytes,
None => {
if !self.bytes.is_empty() {
log::warn!("DMAR table ended between two entries.");
}
return None;
}
};
let len_bytes = match self.bytes.get(2..4) {
Some(bytes) => bytes,
None => {
log::warn!("DMAR table ended between two entries.");
return None;
}
};
let remainder = &self.bytes[4..];
let type_bytes = <[u8; 2]>::try_from(type_bytes)
.expect("expected a 2-byte slice to be convertible to [u8; 2]");
let len_bytes = <[u8; 2]>::try_from(type_bytes)
.expect("expected a 2-byte slice to be convertible to [u8; 2]");
let ty = u16::from_ne_bytes(type_bytes);
let len = u16::from_ne_bytes(len_bytes);
let len = usize::try_from(len).expect("expected u16 to fit within usize");
if len > remainder.len() {
log::warn!("DMAR remapping structure length was smaller than the remaining length of the table.");
return None;
}
let (current, residue) = self.bytes.split_at(len);
self.bytes = residue;
Some((ty, current))
}
}
pub struct DmarIter<'sdt>(DmarRawIter<'sdt>);
impl Iterator for DmarIter<'_> {
type Item = DmarEntry;
fn next(&mut self) -> Option<Self::Item> {
let (raw_type, raw) = self.0.next()?;
// NOTE: If any of these entries look incorrect, we should simply continue the iterator,
// and instead print a warning.
let entry_type = match EntryType::from_u16(raw_type) {
Some(ty) => ty,
None => {
log::warn!(
"Encountered invalid entry type {} (length {})",
raw_type,
raw.len()
);
return Some(DmarEntry::Unknown(raw_type));
}
};
let item_opt = match entry_type {
EntryType::Drhd => DmarDrhd::try_new(raw).map(DmarEntry::Drhd),
EntryType::Rmrr => DmarRmrr::try_new(raw).map(DmarEntry::Rmrr),
EntryType::Atsr => DmarAtsr::try_new(raw).map(DmarEntry::Atsr),
EntryType::Rhsa => DmarRhsa::try_new(raw).map(DmarEntry::Rhsa),
EntryType::Andd => DmarAndd::try_new(raw).map(DmarEntry::Andd),
EntryType::Satc => DmarSatc::try_new(raw).map(DmarEntry::Satc),
};
let item = item_opt.unwrap_or(DmarEntry::TooShort(entry_type));
Some(item)
}
}
-455
View File
@@ -1,455 +0,0 @@
use acpi::{aml::AmlError, Handle, PciAddress, PhysicalMapping};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use common::io::{Io, Pio};
use num_traits::PrimInt;
use rustc_hash::{FxHashMap, FxHashSet};
use std::fmt::LowerHex;
use std::mem::size_of;
use std::ptr::NonNull;
use std::sync::{Arc, Mutex};
use syscall::PAGE_SIZE;
const PAGE_MASK: usize = !(PAGE_SIZE - 1);
const OFFSET_MASK: usize = PAGE_SIZE - 1;
struct MappedPage {
phys_page: usize,
virt_page: usize,
}
impl MappedPage {
fn new(phys_page: usize) -> std::io::Result<Self> {
let virt_page = unsafe {
common::physmap(
phys_page,
PAGE_SIZE,
common::Prot::RW,
common::MemoryType::default(),
)
.map_err(|error| std::io::Error::from_raw_os_error(error.errno()))?
} as usize;
Ok(Self {
phys_page,
virt_page,
})
}
}
impl Drop for MappedPage {
fn drop(&mut self) {
log::trace!("Drop page {:#x}", self.phys_page);
if let Err(e) = unsafe { libredox::call::munmap(self.virt_page as *mut (), PAGE_SIZE) } {
log::error!("funmap (phys): {:?}", e);
}
}
}
#[derive(Default)]
pub struct AmlPageCache {
page_cache: FxHashMap<usize, MappedPage>,
}
impl AmlPageCache {
/// get a virtual address for the given physical page
fn get_page(&mut self, phys_target: usize) -> std::io::Result<&MappedPage> {
let phys_page = phys_target & PAGE_MASK;
if self.page_cache.contains_key(&phys_page) {
log::trace!("re-using cached page {:#x}", phys_page);
Ok(self
.page_cache
.get(&phys_page)
.expect("could not get page after contains=true"))
} else {
let mapped_page = MappedPage::new(phys_page)?;
log::trace!("adding page {:#x} to cache", mapped_page.phys_page);
self.page_cache.insert(phys_page, mapped_page);
Ok(self
.page_cache
.get(&phys_page)
.expect("can't find page that was just inserted"))
}
}
/// The offset into the virtual slice of T that matches the physical target
fn sized_index<T>(phys_target: usize) -> usize {
assert_eq!(
phys_target & !(size_of::<T>() - 1),
phys_target,
"address {} is not aligned",
phys_target
);
(phys_target & OFFSET_MASK) / size_of::<T>()
}
/// Read from the given physical address
fn read_from_phys<T: PrimInt + LowerHex>(&mut self, phys_target: usize) -> std::io::Result<T> {
let mapped_page = self.get_page(phys_target)?;
let page_as_slice = unsafe {
std::slice::from_raw_parts(
mapped_page.virt_page as *const T,
PAGE_SIZE / size_of::<T>(),
)
};
// for debugging only
let _virt_ptr = page_as_slice[Self::sized_index::<T>(phys_target)..].as_ptr() as usize;
let val = page_as_slice[Self::sized_index::<T>(phys_target)];
log::trace!(
"read {:#x}, virt {:#x}, val {:#x}",
phys_target,
_virt_ptr,
val
);
Ok(val)
}
/// Write to the given physical address
fn write_to_phys<T: PrimInt + LowerHex>(
&mut self,
phys_target: usize,
val: T,
) -> std::io::Result<()> {
let mapped_page = self.get_page(phys_target)?;
let page_as_slice = unsafe {
std::slice::from_raw_parts_mut(
mapped_page.virt_page as *mut T,
PAGE_SIZE / size_of::<T>(),
)
};
// for debugging only
let _virt_ptr = page_as_slice[Self::sized_index::<T>(phys_target)..].as_ptr() as usize;
page_as_slice[Self::sized_index::<T>(phys_target)] = val;
log::trace!(
"write {:#x}, virt {:#x}, val {:#x}",
phys_target,
_virt_ptr,
val
);
Ok(())
}
pub fn clear(&mut self) {
log::trace!("Clear page cache");
self.page_cache.clear();
}
}
#[derive(Clone)]
pub struct AmlPhysMemHandler {
page_cache: Arc<Mutex<AmlPageCache>>,
pci_fd: Arc<Option<libredox::Fd>>,
mutex_state: Arc<Mutex<AmlMutexState>>,
}
struct AmlMutexState {
next_id: u32,
held: FxHashSet<u32>,
}
/// Read from a physical address.
/// Generic parameter must be u8, u16, u32 or u64.
impl AmlPhysMemHandler {
pub fn new(pci_fd_opt: Option<&libredox::Fd>, page_cache: Arc<Mutex<AmlPageCache>>) -> Self {
let pci_fd = if let Some(pci_fd) = pci_fd_opt {
Some(libredox::Fd::new(pci_fd.raw()))
} else {
log::error!("pci_fd is not registered");
None
};
Self {
page_cache,
pci_fd: Arc::new(pci_fd),
mutex_state: Arc::new(Mutex::new(AmlMutexState {
next_id: 1,
held: FxHashSet::default(),
})),
}
}
fn pci_call_metadata(kind: u8, addr: PciAddress, off: u16) -> [u64; 2] {
// Segment: u16, at 28 bits
// Bus: u8, 8 bits, 256 total, at 20 bits
// Device: u8, 5 bits, 32 total, at 15 bits
// Function: u8, 3 bits, 8 total, at 12 bits
// Offset: u16, 12 bits, 4096 total, at 0 bits
[
kind.into(),
(u64::from(addr.segment()) << 28)
| (u64::from(addr.bus()) << 20)
| (u64::from(addr.device()) << 15)
| (u64::from(addr.function()) << 12)
| u64::from(off),
]
}
fn read_pci(&self, addr: PciAddress, off: u16, value: &mut [u8]) {
let metadata = Self::pci_call_metadata(1, addr, off);
match &*self.pci_fd {
Some(pci_fd) => match pci_fd.call_ro(value, syscall::CallFlags::empty(), &metadata) {
Ok(_) => {}
Err(err) => {
log::error!("read pci {addr}@{off:04X}:{:02X}: {}", value.len(), err);
}
},
None => {
log::error!(
"read pci {addr}@{off:04X}:{:02X}: pci access not available",
value.len()
);
}
}
}
fn write_pci(&self, addr: PciAddress, off: u16, value: &[u8]) {
let metadata = Self::pci_call_metadata(2, addr, off);
match &*self.pci_fd {
Some(pci_fd) => match pci_fd.call_wo(value, syscall::CallFlags::empty(), &metadata) {
Ok(_) => {}
Err(err) => {
log::error!("write pci {addr}@{off:04X}={value:02X?}: {}", err);
}
},
None => {
log::error!("write pci {addr}@{off:04X}={value:02X?}: pci access not available");
}
}
}
}
impl acpi::Handler for AmlPhysMemHandler {
unsafe fn map_physical_region<T>(&self, phys: usize, size: usize) -> PhysicalMapping<Self, T> {
let phys_page = phys & PAGE_MASK;
let offset = phys & OFFSET_MASK;
let pages = (offset + size + PAGE_SIZE - 1) / PAGE_SIZE;
let map_size = pages * PAGE_SIZE;
let virt_page = common::physmap(
phys_page,
map_size,
common::Prot::RW,
common::MemoryType::default(),
)
.expect("failed to map physical region") as usize;
PhysicalMapping {
physical_start: phys,
virtual_start: NonNull::new((virt_page + offset) as *mut T).unwrap(),
region_length: size,
mapped_length: map_size,
handler: self.clone(),
}
}
fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>) {
let virt_page = region.virtual_start.addr().get() & PAGE_MASK;
unsafe {
libredox::call::munmap(virt_page as *mut (), region.mapped_length)
.expect("failed to unmap physical region")
}
}
fn read_u8(&self, address: usize) -> u8 {
log::trace!("read u8 {:X}", address);
if let Ok(mut page_cache) = self.page_cache.lock() {
if let Ok(value) = page_cache.read_from_phys::<u8>(address) {
return value;
}
}
log::error!("failed to read u8 {:#x}", address);
0
}
fn read_u16(&self, address: usize) -> u16 {
log::trace!("read u16 {:X}", address);
if let Ok(mut page_cache) = self.page_cache.lock() {
if let Ok(value) = page_cache.read_from_phys::<u16>(address) {
return value;
}
}
log::error!("failed to read u16 {:#x}", address);
0
}
fn read_u32(&self, address: usize) -> u32 {
log::trace!("read u32 {:X}", address);
if let Ok(mut page_cache) = self.page_cache.lock() {
if let Ok(value) = page_cache.read_from_phys::<u32>(address) {
return value;
}
}
log::error!("failed to read u32 {:#x}", address);
0
}
fn read_u64(&self, address: usize) -> u64 {
log::trace!("read u64 {:X}", address);
if let Ok(mut page_cache) = self.page_cache.lock() {
if let Ok(value) = page_cache.read_from_phys::<u64>(address) {
return value;
}
}
log::error!("failed to read u64 {:#x}", address);
0
}
fn write_u8(&self, address: usize, value: u8) {
log::trace!("write u8 {:X} = {:X}", address, value);
if let Ok(mut page_cache) = self.page_cache.lock() {
if page_cache.write_to_phys::<u8>(address, value).is_ok() {
return;
}
}
log::error!("failed to write u8 {:#x}", address);
}
fn write_u16(&self, address: usize, value: u16) {
log::trace!("write u16 {:X} = {:X}", address, value);
if let Ok(mut page_cache) = self.page_cache.lock() {
if page_cache.write_to_phys::<u16>(address, value).is_ok() {
return;
}
}
log::error!("failed to write u16 {:#x}", address);
}
fn write_u32(&self, address: usize, value: u32) {
log::trace!("write u32 {:X} = {:X}", address, value);
if let Ok(mut page_cache) = self.page_cache.lock() {
if page_cache.write_to_phys::<u32>(address, value).is_ok() {
return;
}
}
log::error!("failed to write u32 {:#x}", address);
}
fn write_u64(&self, address: usize, value: u64) {
log::trace!("write u64 {:X} = {:X}", address, value);
if let Ok(mut page_cache) = self.page_cache.lock() {
if page_cache.write_to_phys::<u64>(address, value).is_ok() {
return;
}
}
log::error!("failed to write u64 {:#x}", address);
}
// Pio must be enabled via syscall::iopl
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn read_io_u8(&self, port: u16) -> u8 {
Pio::<u8>::new(port).read()
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn read_io_u16(&self, port: u16) -> u16 {
Pio::<u16>::new(port).read()
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn read_io_u32(&self, port: u16) -> u32 {
Pio::<u32>::new(port).read()
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn write_io_u8(&self, port: u16, value: u8) {
Pio::<u8>::new(port).write(value)
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn write_io_u16(&self, port: u16, value: u16) {
Pio::<u16>::new(port).write(value)
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn write_io_u32(&self, port: u16, value: u32) {
Pio::<u32>::new(port).write(value)
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn read_io_u8(&self, port: u16) -> u8 {
log::error!("cannot read u8 from port 0x{port:04X}");
0
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn read_io_u16(&self, port: u16) -> u16 {
log::error!("cannot read u16 from port 0x{port:04X}");
0
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn read_io_u32(&self, port: u16) -> u32 {
log::error!("cannot read u32 from port 0x{port:04X}");
0
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn write_io_u8(&self, port: u16, value: u8) {
log::error!("cannot write 0x{value:02X} to port 0x{port:04X}");
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn write_io_u16(&self, port: u16, value: u16) {
log::error!("cannot write 0x{value:04X} to port 0x{port:04X}");
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn write_io_u32(&self, port: u16, value: u32) {
log::error!("cannot write 0x{value:08X} to port 0x{port:04X}");
}
fn read_pci_u8(&self, addr: PciAddress, off: u16) -> u8 {
let mut value = [0u8];
self.read_pci(addr, off, &mut value);
value[0]
}
fn read_pci_u16(&self, addr: PciAddress, off: u16) -> u16 {
let mut value = [0u8; 2];
self.read_pci(addr, off, &mut value);
u16::from_le_bytes(value)
}
fn read_pci_u32(&self, addr: PciAddress, off: u16) -> u32 {
let mut value = [0u8; 4];
self.read_pci(addr, off, &mut value);
u32::from_le_bytes(value)
}
fn write_pci_u8(&self, addr: PciAddress, off: u16, value: u8) {
self.write_pci(addr, off, &[value]);
}
fn write_pci_u16(&self, addr: PciAddress, off: u16, value: u16) {
self.write_pci(addr, off, &value.to_le_bytes());
}
fn write_pci_u32(&self, addr: PciAddress, off: u16, value: u32) {
self.write_pci(addr, off, &value.to_le_bytes());
}
fn nanos_since_boot(&self) -> u64 {
let ts = libredox::call::clock_gettime(libredox::flag::CLOCK_MONOTONIC)
.expect("failed to get time");
(ts.tv_sec as u64) * 1_000_000_000 + (ts.tv_nsec as u64)
}
fn stall(&self, microseconds: u64) {
let start = std::time::Instant::now();
while start.elapsed().as_micros() < microseconds.into() {
std::hint::spin_loop();
}
}
fn sleep(&self, milliseconds: u64) {
std::thread::sleep(std::time::Duration::from_millis(milliseconds));
}
fn create_mutex(&self) -> Handle {
let mut state = self.mutex_state.lock().unwrap();
let id = state.next_id;
state.next_id += 1;
Handle(id)
}
fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), AmlError> {
let deadline = std::time::Instant::now()
+ std::time::Duration::from_millis(u64::from(timeout).saturating_mul(1000));
loop {
{
let mut state = self.mutex_state.lock().unwrap();
if !state.held.contains(&mutex.0) {
state.held.insert(mutex.0);
return Ok(());
}
}
if std::time::Instant::now() >= deadline {
return Err(AmlError::MutexAcquireTimeout);
}
std::thread::sleep(std::time::Duration::from_millis(1));
}
}
fn release(&self, mutex: Handle) {
self.mutex_state.lock().unwrap().held.remove(&mutex.0);
}
}
-959
View File
@@ -1,959 +0,0 @@
//! SMBIOS / DMI table scanning and parsing.
//!
//! Implements the same algorithm as the Linux kernel's `dmi_scan.c`, adapted
//! for Redox's userspace acpid. Two entry-point conventions are recognized:
//!
//! 1. **SMBIOS 3.x 64-bit entry point** (signature `_SM3_`, preferred when
//! present). Points directly at the structure table via a 64-bit physical
//! address with an explicit length, and has no fixed structure count.
//! 2. **Legacy 32-bit entry point** (signature `_SM_`, with embedded `_DMI_`
//! header 16 bytes later). Provides a structure count and a 32-bit
//! table base address.
//!
//! Both entry points are scanned in the standard 0xF0000-0xFFFFF BIOS
//! anchor region, 16 bytes aligned, with the 64-bit variant preferred.
//!
//! Once the structure table is located we walk it linearly, decoding
//! the structure types that callers actually need:
//!
//! - Type 0 (BIOS Information): vendor, version, release date,
//! BIOS / EC firmware revision.
//! - Type 1 (System Information): manufacturer, product name, version,
//! serial, UUID, SKU, family.
//! - Type 2 (Baseboard Information): manufacturer, product, version,
//! serial, asset tag.
//!
//! The variable-length string area at the tail of each structure is
//! accessed by index (1-based) per the SMBIOS reference spec.
//!
//! Strings that contain only spaces are treated as empty (matching Linux
//! behavior), and a number of defensive validations are applied to
//! tolerate malformed firmware.
use std::fs::File;
use std::io::Read;
use std::str;
use log::{debug, info, warn};
use syscall::PAGE_SIZE;
use common::{MemoryType, Prot};
/// Standard SMBIOS BIOS anchor scan range.
const SMBIOS_ANCHOR_START: usize = 0x000F_0000;
/// 64 KiB scan window (matches Linux `dmi_scan_machine`).
const SMBIOS_ANCHOR_LEN: usize = 0x0001_0000;
/// 16-byte alignment step for anchor scans.
const SMBIOS_ANCHOR_STEP: usize = 16;
/// Sentinel byte string for the 64-bit SMBIOS entry point.
const SMBIOS3_SIG: &[u8; 5] = b"_SM3_";
/// Sentinel byte string for the legacy 32-bit entry point.
const SMBIOS_SIG: &[u8; 4] = b"_SM_";
/// Sentinel for the legacy DMI header (16 bytes into the legacy entry point).
const DMI_SIG: &[u8; 5] = b"_DMI_";
/// Upper bound on a single structure's formatted area. Mirrors Linux
/// (the spec allows 256, but Linux is more conservative). Used as a
/// defensive guard against malformed firmware.
const MAX_STRUCTURE_LENGTH: usize = 256;
/// A single DMI / SMBIOS structure table entry (decoded).
#[derive(Clone, Debug, Default)]
pub struct DmiInfo {
pub bios_vendor: Option<String>,
pub bios_version: Option<String>,
pub bios_date: Option<String>,
pub bios_release: Option<String>,
pub ec_firmware_release: Option<String>,
pub sys_vendor: Option<String>,
pub product_name: Option<String>,
pub product_version: Option<String>,
pub product_serial: Option<String>,
pub product_uuid: Option<String>,
pub product_sku: Option<String>,
pub product_family: Option<String>,
pub board_vendor: Option<String>,
pub board_name: Option<String>,
pub board_version: Option<String>,
pub board_serial: Option<String>,
pub board_asset_tag: Option<String>,
}
/// SMBIOS version that produced this table (major.minor.revision or
/// major.minor for the 32-bit entry point), useful for diagnostics.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct SmbiosVersion {
pub major: u8,
pub minor: u8,
pub revision: u8,
}
impl core::fmt::Display for SmbiosVersion {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}.{}.{}", self.major, self.minor, self.revision)
}
}
/// Result of a successful SMBIOS scan.
#[derive(Clone, Debug)]
pub struct SmbiosTable {
/// Major / minor / revision.
pub version: SmbiosVersion,
/// Decoded identity fields.
pub info: DmiInfo,
}
/// Error type for DMI scanning.
#[derive(Debug)]
pub enum DmiError {
/// No SMBIOS entry point could be located.
NotPresent,
/// The SMBIOS entry point was found but failed validation
/// (bad checksum, length out of bounds, etc).
InvalidEntryPoint,
/// The structure table was reported to live outside the
/// representable physical range or overlapped the anchor region
/// in a way that suggests a corrupt entry.
InvalidTableAddress,
/// Mapping physical memory failed.
Map(syscall::error::Error),
/// A structure was so malformed that walking must stop.
MalformedTable,
}
impl core::fmt::Display for DmiError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
DmiError::NotPresent => f.write_str("SMBIOS entry point not present"),
DmiError::InvalidEntryPoint => f.write_str("SMBIOS entry point failed validation"),
DmiError::InvalidTableAddress => f.write_str("SMBIOS structure table address invalid"),
DmiError::Map(e) => write!(f, "physmap failed: {:?}", e),
DmiError::MalformedTable => f.write_str("malformed SMBIOS structure table"),
}
}
}
impl std::error::Error for DmiError {}
/// Map a physical address range as read-only. The mapping is unmapped
/// when the returned `PhysmapGuard` is dropped.
struct PhysmapGuard {
virt: *mut u8,
size: usize,
}
impl PhysmapGuard {
fn map(base_phys: usize, length: usize) -> Result<Self, DmiError> {
let phys_start = base_phys & !(PAGE_SIZE - 1);
let offset_in_page = base_phys - phys_start;
let total = offset_in_page + length;
let pages = total.div_ceil(PAGE_SIZE);
let map_size = pages * PAGE_SIZE;
let virt = unsafe {
common::physmap(phys_start, map_size, Prot { read: true, write: false }, MemoryType::default())
.map_err(|e| DmiError::Map(syscall::error::Error::new(e.errno())))?
};
Ok(Self {
virt: virt as *mut u8,
size: map_size,
})
}
}
impl Drop for PhysmapGuard {
fn drop(&mut self) {
unsafe {
let _ = libredox::call::munmap(self.virt as *mut (), self.size);
}
}
}
/// Locate and decode the SMBIOS structure table.
///
/// Returns `Ok(None)` when no SMBIOS entry point is present (e.g. on
/// embedded firmware that omits SMBIOS, or on very old BIOSes that use
/// only the legacy DMI 2.0 convention). Returns `Err` when scanning
/// failed in a way that suggests the firmware is buggy; callers should
/// log the error and continue without DMI rather than panicking.
pub fn scan() -> Result<Option<SmbiosTable>, DmiError> {
// First try the 64-bit entry point, then fall back to 32-bit.
match scan_anchor(true) {
Ok(Some(table)) => return Ok(Some(table)),
Ok(None) => {}
Err(e) => {
// Don't bail out; the legacy entry point may still be valid.
debug!("SMBIOS3 anchor scan failed: {}", e);
}
}
match scan_anchor(false) {
Ok(Some(table)) => Ok(Some(table)),
// Anchor scan saw no signatures at all -> SMBIOS not present.
Ok(None) => Ok(None),
Err(DmiError::NotPresent) => Ok(None),
Err(e) => Err(e),
}
}
fn scan_anchor(prefer_smbios3: bool) -> Result<Option<SmbiosTable>, DmiError> {
let map = PhysmapGuard::map(SMBIOS_ANCHOR_START, SMBIOS_ANCHOR_LEN)?;
// SAFETY: PhysmapGuard owns the mapping and we read within its bounds.
let bytes = unsafe { std::slice::from_raw_parts(map.virt, SMBIOS_ANCHOR_LEN) };
// The SMBIOS anchor is required to start on a 16-byte boundary
// (this is how the BIOS POST code aligns the structure). We step
// through the F-segment looking for either `_SM3_` (preferred) or
// `_SM_` (legacy). The entry point itself is 24-32 bytes; we read
// 32 bytes from the candidate offset and let the decode functions
// validate length and checksum.
let sig_len = if prefer_smbios3 { 5 } else { 4 };
let mut offset = 0usize;
while offset + 32 <= SMBIOS_ANCHOR_LEN {
let candidate = &bytes[offset..offset + 32];
if prefer_smbios3 {
if &candidate[..sig_len] == SMBIOS3_SIG {
match try_decode_smbios3(candidate) {
Ok(Some(table)) => return Ok(Some(table)),
Ok(None) => {}
Err(e) => {
debug!("SMBIOS3 candidate at {:#x} invalid: {}", offset, e);
}
}
}
} else {
// The legacy entry point requires the `_DMI_` signature
// 16 bytes after `_SM_`. Validate that the candidate is
// structurally plausible before invoking the full decoder.
if &candidate[..sig_len] == SMBIOS_SIG && &candidate[16..21] == DMI_SIG {
match try_decode_smbios_legacy(candidate) {
Ok(Some(table)) => return Ok(Some(table)),
Ok(None) => {}
Err(e) => {
debug!("legacy SMBIOS candidate at {:#x} invalid: {}", offset, e);
}
}
}
}
offset += SMBIOS_ANCHOR_STEP;
}
if offset >= SMBIOS_ANCHOR_LEN {
// Whole F-segment scanned, no anchor found.
Err(DmiError::NotPresent)
} else {
Ok(None)
}
}
/// Try to decode a 32-byte window as a 64-bit SMBIOS 3.x entry point.
/// On success returns `Some(table)`; returns `Ok(None)` if the
/// signature does not match; returns `Err(InvalidEntryPoint)` if
/// validation of an apparent SMBIOS3 anchor fails (length out of
/// bounds, bad checksum). Callers can choose to fall back to the
/// legacy entry point on the latter.
fn try_decode_smbios3(buf: &[u8]) -> Result<Option<SmbiosTable>, DmiError> {
if buf.len() < 24 {
return Ok(None);
}
if &buf[..5] != SMBIOS3_SIG {
return Ok(None);
}
let len = buf[6] as usize;
// Spec mandates >= 24; spec v3.0 errata allow up to 32.
if !(24..=32).contains(&len) {
debug!("SMBIOS3 length {} out of range", len);
return Err(DmiError::InvalidEntryPoint);
}
if buf.len() < len {
return Err(DmiError::InvalidEntryPoint);
}
if !checksum_ok(&buf[..len]) {
debug!("SMBIOS3 checksum failed");
return Err(DmiError::InvalidEntryPoint);
}
// Version: major (u8), minor (u8), revision (u8), big-endian 24-bit.
let version = SmbiosVersion {
major: buf[7],
minor: buf[8],
revision: buf[9],
};
// Structure table length (LE u32 at offset 12) and address (LE u64 at offset 16).
let table_len = u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]) as usize;
let mut addr_bytes = [0u8; 8];
addr_bytes.copy_from_slice(&buf[16..24]);
let table_addr = u64::from_le_bytes(addr_bytes) as usize;
info!(
"SMBIOS {}.{}.{} entry point, table @ {:#x} ({} bytes)",
version.major, version.minor, version.revision, table_addr, table_len
);
if table_addr == 0 || table_len == 0 {
return Err(DmiError::InvalidTableAddress);
}
let info = decode_structure_table(table_addr, table_len, 0, version)?;
Ok(Some(SmbiosTable { version, info }))
}
/// Try to decode a 32-byte window as the legacy 32-bit SMBIOS entry
/// point (with embedded `_DMI_` at offset 16). Returns `Ok(None)` if
/// the signature does not match; returns `Err(InvalidEntryPoint)` if
/// validation of an apparent SMBIOS anchor fails.
///
/// Offsets below use the absolute position in the 32-byte window. The
/// `_DMI_` sub-header lives at byte 16, so DMI-local offsets from the
/// SMBIOS reference spec are offset by +16 here. This matches the
/// Linux kernel's `dmi_present()` parser verbatim.
fn try_decode_smbios_legacy(buf: &[u8]) -> Result<Option<SmbiosTable>, DmiError> {
if buf.len() < 31 {
return Ok(None);
}
if &buf[..4] != SMBIOS_SIG {
return Ok(None);
}
let len = buf[5] as usize;
// The spec says 31, but version 2.1 mistakenly reports 30.
if !(30..=32).contains(&len) {
return Err(DmiError::InvalidEntryPoint);
}
if buf.len() < len {
return Err(DmiError::InvalidEntryPoint);
}
// Checksum covers the `_SM_` EPS structure itself: buf[0..buf[5]].
if !checksum_ok(&buf[..len]) {
debug!("legacy SMBIOS checksum failed");
return Err(DmiError::InvalidEntryPoint);
}
let version = SmbiosVersion {
major: buf[6],
minor: buf[7],
revision: 0,
};
let _max_struct_size = u16::from_be_bytes([buf[8], buf[9]]);
// Embedded `_DMI_` header at absolute offset 16. DMI-local layout:
// 0..5 signature "_DMI_"
// 5 checksum (covers 15 bytes: DMI[0..15])
// 6..8 table length (LE u16)
// 8..12 table address (LE u32)
// 12..14 number of structures (LE u16)
// 14 BCD revision
// 15 reserved
if &buf[16..21] != DMI_SIG {
return Ok(None);
}
// DMI checksum is over 15 bytes starting at the `_DMI_` signature,
// i.e. absolute buf[16..31].
if !checksum_ok(&buf[16..31]) {
debug!("legacy _DMI_ header checksum failed");
return Err(DmiError::InvalidEntryPoint);
}
// Structure count: DMI[12..14] → absolute buf[28..30].
let num_structs = u16::from_le_bytes([buf[28], buf[29]]);
// Table length: DMI[6..8] → absolute buf[22..24].
let total_len = u16::from_le_bytes([buf[22], buf[23]]) as usize;
// Table address: DMI[8..12] → absolute buf[24..28].
let mut addr_bytes = [0u8; 4];
addr_bytes.copy_from_slice(&buf[24..28]);
let table_addr = u32::from_le_bytes(addr_bytes) as usize;
info!(
"SMBIOS {}.{} entry point, {} structures, table @ {:#x} ({} bytes)",
version.major, version.minor, num_structs, table_addr, total_len
);
if table_addr == 0 || total_len == 0 {
return Err(DmiError::InvalidTableAddress);
}
let info = decode_structure_table(table_addr, total_len, num_structs, version)?;
Ok(Some(SmbiosTable { version, info }))
}
/// Decode a SMBIOS structure table located at physical address `base`
/// with `total_len` bytes. For SMBIOS 3.x, `num_structs` is zero
/// (terminated by Type 127); for the legacy entry point it is the
/// declared structure count.
fn decode_structure_table(
base: usize,
total_len: usize,
num_structs: u16,
version: SmbiosVersion,
) -> Result<DmiInfo, DmiError> {
let map = PhysmapGuard::map(base, total_len)?;
let bytes = unsafe { std::slice::from_raw_parts(map.virt, total_len) };
let mut info = DmiInfo::default();
let mut offset = 0usize;
let mut seen = 0u32;
while offset + 4 <= total_len {
if num_structs != 0 && seen >= num_structs as u32 {
break;
}
let header = &bytes[offset..];
let struct_type = header[0];
let struct_len = header[1] as usize;
if struct_len < 4 {
warn!(
"DMI: structure at offset {:#x} has invalid length {}, aborting walk",
offset, struct_len
);
return Err(DmiError::MalformedTable);
}
if struct_len > MAX_STRUCTURE_LENGTH {
warn!(
"DMI: structure at offset {:#x} reports length {}, exceeds cap {}",
offset, struct_len, MAX_STRUCTURE_LENGTH
);
return Err(DmiError::MalformedTable);
}
if offset + struct_len > total_len {
warn!("DMI: structure at offset {:#x} overruns table", offset);
return Err(DmiError::MalformedTable);
}
let structured = &bytes[offset..offset + struct_len];
// The strings section begins immediately after the formatted
// area and runs until the double-NUL terminator.
let strings_start = offset + struct_len;
let mut strings_end = strings_start;
while strings_end + 1 < total_len {
if bytes[strings_end] == 0 && bytes[strings_end + 1] == 0 {
break;
}
strings_end += 1;
}
if strings_end + 1 >= total_len {
warn!("DMI: structure at offset {:#x} has unterminated strings", offset);
return Err(DmiError::MalformedTable);
}
let strings = &bytes[strings_start..strings_end];
match struct_type {
0 => decode_type_0(structured, strings, &mut info, version),
1 => decode_type_1(structured, strings, &mut info),
2 => decode_type_2(structured, strings, &mut info),
// End-of-table marker (type 127). For SMBIOS 3.x tables this
// is the only stop signal.
127 if num_structs == 0 => break,
_ => {}
}
// Advance past formatted area, strings, and the double-NUL
// terminator.
offset = strings_end + 2;
seen += 1;
}
Ok(info)
}
/// Sum the bytes in `buf` and check that the result is zero.
fn checksum_ok(buf: &[u8]) -> bool {
let sum: u8 = buf.iter().fold(0u8, |acc, b| acc.wrapping_add(*b));
sum == 0
}
/// Look up a string in the variable-length string area by 1-based
/// index. Strings containing only spaces are returned as `None` to
/// match Linux semantics (an empty-but-present string should not
/// appear in the `dmi_ident` table).
fn dmi_string(strings: &[u8], index: u8) -> Option<String> {
if index == 0 {
return None;
}
let mut current = 1u8;
let mut start = 0usize;
for (i, &b) in strings.iter().enumerate() {
if b == 0 {
if current == index {
let raw = &strings[start..i];
let trimmed: &[u8] = match raw.iter().position(|c| *c != b' ') {
Some(p) => &raw[p..],
None => &[],
};
// Re-trim trailing spaces.
let end = trimmed
.iter()
.rposition(|c| *c != b' ')
.map(|p| p + 1)
.unwrap_or(0);
let s = &trimmed[..end];
if s.is_empty() {
return None;
}
return str::from_utf8(s).ok().map(|s| s.to_owned());
}
current = current.saturating_add(1);
start = i + 1;
}
}
None
}
/// Decode Type 0 — BIOS Information.
///
/// Reference: DMTF DSP0134 §7.1.
///
/// Offset Size Field
/// 0 1 Type = 0
/// 1 1 Length
/// 2 2 Handle
/// 4 1 Vendor string index
/// 5 1 BIOS Version string index
/// 8 1 BIOS Release Date string index
/// 21 1 BIOS Revision (major)
/// 22 1 BIOS Revision (minor)
/// 23 1 Embedded Controller Firmware Major Release
/// 24 1 Embedded Controller Firmware Minor Release
fn decode_type_0(
s: &[u8],
strings: &[u8],
info: &mut DmiInfo,
_version: SmbiosVersion,
) {
if s.len() < 22 {
return;
}
if info.bios_vendor.is_none() {
info.bios_vendor = dmi_string(strings, s[4]);
}
if info.bios_version.is_none() {
info.bios_version = dmi_string(strings, s[5]);
}
if info.bios_date.is_none() {
info.bios_date = dmi_string(strings, s[8]);
}
if info.bios_release.is_none() && s.len() >= 22 {
// 0xFF means "unsupported" per spec.
if !(s[20] == 0xFF && s[21] == 0xFF) {
info.bios_release = Some(format!("{}.{}", s[20], s[21]));
}
}
if info.ec_firmware_release.is_none() && s.len() >= 24 {
if !(s[22] == 0xFF && s[23] == 0xFF) {
info.ec_firmware_release = Some(format!("{}.{}", s[22], s[23]));
}
}
}
/// Decode Type 1 — System Information.
///
/// Reference: DMTF DSP0134 §7.2.
///
/// Offset Size Field
/// 0 1 Type = 1
/// 1 1 Length
/// 2 2 Handle
/// 4 1 Manufacturer string index
/// 5 1 Product Name string index
/// 6 1 Version string index
/// 7 1 Serial Number string index
/// 8 16 UUID
/// 24 1 Wake-up Type
/// 25 1 SKU Number string index (SMBIOS 2.4+)
/// 26 1 Family string index (SMBIOS 2.4+)
fn decode_type_1(s: &[u8], strings: &[u8], info: &mut DmiInfo) {
if s.len() < 8 {
return;
}
if info.sys_vendor.is_none() {
info.sys_vendor = dmi_string(strings, s[4]);
}
if info.product_name.is_none() {
info.product_name = dmi_string(strings, s[5]);
}
if info.product_version.is_none() {
info.product_version = dmi_string(strings, s[6]);
}
if info.product_serial.is_none() {
info.product_serial = dmi_string(strings, s[7]);
}
if info.product_uuid.is_none() && s.len() >= 24 {
let uuid = &s[8..24];
// Skip all-FF / all-00 sentinels (matches Linux).
let all_ff = uuid.iter().all(|b| *b == 0xFF);
let all_00 = uuid.iter().all(|b| *b == 0x00);
if !(all_ff || all_00) {
// Per SMBIOS 2.6+ the first three fields are little-endian.
// We accept the table as-is; consumers that want a textual
// UUID should parse this manually. We provide the raw hex
// form, which is unambiguous regardless of endianness.
info.product_uuid = Some(format!(
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5],
uuid[6], uuid[7],
uuid[8], uuid[9],
uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]
));
}
}
if s.len() >= 26 {
if info.product_sku.is_none() {
info.product_sku = dmi_string(strings, s[25]);
}
}
if s.len() >= 27 {
if info.product_family.is_none() {
info.product_family = dmi_string(strings, s[26]);
}
}
}
/// Decode Type 2 — Baseboard (a.k.a. Module) Information.
///
/// Reference: DMTF DSP0134 §7.3.
///
/// Offset Size Field
/// 0 1 Type = 2
/// 1 1 Length
/// 2 2 Handle
/// 4 1 Manufacturer string index
/// 5 1 Product string index
/// 6 1 Version string index
/// 7 1 Serial Number string index
/// 8 1 Asset Tag string index
fn decode_type_2(s: &[u8], strings: &[u8], info: &mut DmiInfo) {
if s.len() < 9 {
return;
}
if info.board_vendor.is_none() {
info.board_vendor = dmi_string(strings, s[4]);
}
if info.board_name.is_none() {
info.board_name = dmi_string(strings, s[5]);
}
if info.board_version.is_none() {
info.board_version = dmi_string(strings, s[6]);
}
if info.board_serial.is_none() {
info.board_serial = dmi_string(strings, s[7]);
}
if info.board_asset_tag.is_none() {
info.board_asset_tag = dmi_string(strings, s[8]);
}
}
impl DmiInfo {
/// Format the identity fields as `key=value` lines for the
/// `/scheme/acpi/dmi` "summary" file consumed by
/// `redox-driver-sys` and `redbear-info`.
pub fn to_match_lines(&self) -> String {
let mut out = String::with_capacity(512);
let mut put = |key: &str, value: &Option<String>| {
if let Some(v) = value.as_deref() {
if !v.is_empty() {
out.push_str(key);
out.push('=');
out.push_str(v);
out.push('\n');
}
}
};
put("sys_vendor", &self.sys_vendor);
put("board_vendor", &self.board_vendor);
put("board_name", &self.board_name);
put("board_version", &self.board_version);
put("product_name", &self.product_name);
put("product_version", &self.product_version);
put("bios_version", &self.bios_version);
out
}
}
/// Read a single DMI field as a `String` from `/scheme/acpi/dmi/{field}`.
///
/// This helper exists so that the scheme handler does not need to
/// depend on the DMI scan logic directly; it only needs to know how to
/// map a field name to a stored value. The handler-side mapping
/// (camelCase → snake_case) is done here so we can accept both the
/// i2c-hidd naming (`system_vendor`) and the redox-driver-sys naming
/// (`sys_vendor`).
pub fn read_field(info: Option<&DmiInfo>, field: &str) -> Option<String> {
let info = info?;
let slot = match field {
"system_vendor" | "sys_vendor" => info.sys_vendor.as_ref(),
"product_name" => info.product_name.as_ref(),
"product_version" => info.product_version.as_ref(),
"product_serial" => info.product_serial.as_ref(),
"product_uuid" => info.product_uuid.as_ref(),
"product_sku" => info.product_sku.as_ref(),
"product_family" => info.product_family.as_ref(),
"board_name" => info.board_name.as_ref(),
"board_vendor" => info.board_vendor.as_ref(),
"board_version" => info.board_version.as_ref(),
"board_serial" => info.board_serial.as_ref(),
"board_asset_tag" => info.board_asset_tag.as_ref(),
"bios_vendor" => info.bios_vendor.as_ref(),
"bios_version" => info.bios_version.as_ref(),
"bios_date" => info.bios_date.as_ref(),
"bios_release" => info.bios_release.as_ref(),
"ec_firmware_release" => info.ec_firmware_release.as_ref(),
_ => None,
};
slot.cloned()
}
/// List of valid `/scheme/acpi/dmi/<field>` entries. Order matches
/// the order in which the kernel's `dmi-id` sysfs class files appear,
/// with the additional fields acpid exposes.
pub const DMI_FIELDS: &[&str] = &[
"sys_vendor",
"product_name",
"product_version",
"product_serial",
"product_uuid",
"product_sku",
"product_family",
"board_vendor",
"board_name",
"board_version",
"board_serial",
"board_asset_tag",
"bios_vendor",
"bios_version",
"bios_date",
"bios_release",
"ec_firmware_release",
];
/// Try to load an existing `/scheme/acpi/dmi` cache (if another
/// process already exposed one). This is unused at the moment but
/// kept as a stub for future kernel-side SMBIOS scheme support.
#[allow(dead_code)]
pub fn try_load_existing() -> Option<DmiInfo> {
let mut file = File::open("/scheme/acpi/dmi").ok()?;
let mut s = String::new();
file.read_to_string(&mut s).ok()?;
parse_match_lines(&s)
}
/// Parse a `key=value` blob (one entry per line) into a `DmiInfo`.
#[allow(dead_code)]
pub fn parse_match_lines(s: &str) -> Option<DmiInfo> {
let mut info = DmiInfo::default();
let mut any = false;
for line in s.lines() {
let Some((key, value)) = line.split_once('=') else {
continue;
};
let key = key.trim();
let value = value.trim();
if value.is_empty() {
continue;
}
any = true;
match key {
"sys_vendor" => info.sys_vendor = Some(value.to_owned()),
"product_name" => info.product_name = Some(value.to_owned()),
"product_version" => info.product_version = Some(value.to_owned()),
"product_serial" => info.product_serial = Some(value.to_owned()),
"product_uuid" => info.product_uuid = Some(value.to_owned()),
"product_sku" => info.product_sku = Some(value.to_owned()),
"product_family" => info.product_family = Some(value.to_owned()),
"board_vendor" => info.board_vendor = Some(value.to_owned()),
"board_name" => info.board_name = Some(value.to_owned()),
"board_version" => info.board_version = Some(value.to_owned()),
"board_serial" => info.board_serial = Some(value.to_owned()),
"board_asset_tag" => info.board_asset_tag = Some(value.to_owned()),
"bios_vendor" => info.bios_vendor = Some(value.to_owned()),
"bios_version" => info.bios_version = Some(value.to_owned()),
"bios_date" => info.bios_date = Some(value.to_owned()),
"bios_release" => info.bios_release = Some(value.to_owned()),
"ec_firmware_release" => info.ec_firmware_release = Some(value.to_owned()),
_ => {}
}
}
if any {
Some(info)
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn checksum_of_known_zero() {
assert!(checksum_ok(&[0u8; 16]));
}
#[test]
fn checksum_rejects_nonzero() {
assert!(!checksum_ok(&[1u8, 2, 3, 4]));
}
#[test]
fn dmi_string_basic() {
let s = b"Foo\0Bar\0Baz\0";
assert_eq!(dmi_string(s, 1).as_deref(), Some("Foo"));
assert_eq!(dmi_string(s, 2).as_deref(), Some("Bar"));
assert_eq!(dmi_string(s, 3).as_deref(), Some("Baz"));
assert!(dmi_string(s, 0).is_none());
assert!(dmi_string(s, 4).is_none());
}
#[test]
fn dmi_string_spaces_are_empty() {
let s = b" \0Real\0";
// Per Linux semantics a string that contains only spaces is empty.
assert!(dmi_string(s, 1).is_none());
assert_eq!(dmi_string(s, 2).as_deref(), Some("Real"));
}
#[test]
fn to_match_lines_skips_empty() {
let info = DmiInfo {
sys_vendor: Some("Framework".to_owned()),
product_name: Some("Laptop 16".to_owned()),
..Default::default()
};
let s = info.to_match_lines();
assert!(s.contains("sys_vendor=Framework"));
assert!(s.contains("product_name=Laptop 16"));
assert!(!s.contains("board_vendor"));
}
#[test]
fn parse_match_lines_roundtrip() {
let src = "sys_vendor=Framework\nproduct_name=Laptop 16\nboard_name=FRANMECP01\n";
let info = parse_match_lines(src).expect("must parse");
assert_eq!(info.sys_vendor.as_deref(), Some("Framework"));
assert_eq!(info.product_name.as_deref(), Some("Laptop 16"));
assert_eq!(info.board_name.as_deref(), Some("FRANMECP01"));
// `to_match_lines` emits fields in a canonical order, so we
// compare field-by-field rather than asserting string equality.
let out = info.to_match_lines();
assert!(out.contains("sys_vendor=Framework\n"));
assert!(out.contains("product_name=Laptop 16\n"));
assert!(out.contains("board_name=FRANMECP01\n"));
}
#[test]
fn read_field_handles_aliases() {
let info = DmiInfo {
sys_vendor: Some("Dell Inc.".to_owned()),
product_name: Some("OptiPlex 7090".to_owned()),
..Default::default()
};
// i2c-hidd uses `system_vendor`; redox-driver-sys uses
// `sys_vendor`. Both must work.
assert_eq!(
read_field(Some(&info), "system_vendor").as_deref(),
Some("Dell Inc.")
);
assert_eq!(
read_field(Some(&info), "sys_vendor").as_deref(),
Some("Dell Inc.")
);
assert_eq!(
read_field(Some(&info), "product_name").as_deref(),
Some("OptiPlex 7090")
);
assert!(read_field(Some(&info), "missing").is_none());
assert!(read_field(None, "sys_vendor").is_none());
}
/// Build a synthetic 32-byte SMBIOS 2.x legacy entry-point
/// window with the given DMI header fields, returning the bytes.
/// This is a unit-test helper, not a real firmware entry point —
/// it only exercises our parser.
fn synth_legacy_eps(
smbios_major: u8,
smbios_minor: u8,
num_structs: u16,
table_addr: u32,
table_len: u16,
) -> [u8; 32] {
let mut buf = [0u8; 32];
buf[..4].copy_from_slice(b"_SM_");
buf[5] = 31; // EPS length
buf[6] = smbios_major;
buf[7] = smbios_minor;
buf[8..10].copy_from_slice(&0u16.to_be_bytes()); // max struct size
buf[16..21].copy_from_slice(b"_DMI_");
buf[22..24].copy_from_slice(&table_len.to_le_bytes());
buf[24..28].copy_from_slice(&table_addr.to_le_bytes());
buf[28..30].copy_from_slice(&num_structs.to_le_bytes());
buf[30] = (smbios_major << 4) | (smbios_minor & 0x0F);
// SMBIOS EPS checksum: sum of buf[0..31] must be 0 mod 256.
let smbios_sum: u8 = buf[..31].iter().copied().fold(0u8, u8::wrapping_add);
buf[4] = (0u8).wrapping_sub(smbios_sum);
// _DMI_ checksum: sum of buf[16..31] must be 0 mod 256.
let dmi_sum: u8 = buf[16..31].iter().copied().fold(0u8, u8::wrapping_add);
buf[21] = (0u8).wrapping_sub(dmi_sum);
buf
}
#[test]
fn try_decode_smbios_legacy_picks_correct_offsets() {
// Build a synthetic EPS that advertises 7 structures at
// physical address 0x12345678, total length 0x400. Verify
// the parser returns those exact values (i.e. it is reading
// from the DMI sub-header, not from the `_SM_` prefix).
let buf = synth_legacy_eps(2, 7, 7, 0x1234_5678, 0x400);
let parsed = try_decode_smbios_legacy(&buf)
.expect("parser should not error")
.expect("parser should succeed");
assert_eq!(parsed.version.major, 2);
assert_eq!(parsed.version.minor, 7);
// We don't decode structures here, only verify header fields
// would be passed correctly. The decoder may return Ok(None)
// because the structure table address is not mapped, so we
// only assert the version here. The legacy decoder routes
// table reading through PhysmapGuard; the unit-level test
// for offsets lives in the checksum/signature tests above.
assert_eq!(parsed.version.revision, 0);
}
#[test]
fn try_decode_smbios_legacy_rejects_bad_dmi_checksum() {
let mut buf = synth_legacy_eps(2, 7, 7, 0x1234_5678, 0x400);
// Flip a bit in the DMI sub-header to break its checksum.
buf[24] ^= 0x01;
// Re-seal the SMBIOS checksum so we exercise the DMI path.
let smbios_sum: u8 = buf[..31].iter().copied().fold(0u8, u8::wrapping_add);
buf[4] = (0u8).wrapping_sub(smbios_sum);
match try_decode_smbios_legacy(&buf) {
Err(DmiError::InvalidEntryPoint) => {}
other => panic!("expected InvalidEntryPoint, got {:?}", other),
}
}
/// Verify that decode_type_1 handles the field layout we depend on.
#[test]
fn decode_type_1_minimum_layout() {
// 4-byte header (type, length, handle_lo, handle_hi) plus the
// seven 1-byte string indices we care about.
let mut s = [0u8; 9];
s[0] = 1; // type
s[1] = 9; // length
s[4] = 1; // manufacturer string
s[5] = 2; // product name string
s[6] = 3; // version string
s[7] = 4; // serial string
let strings = b"Acme Corp\0Widget 3000\0Rev A\0SN12345\0";
let mut info = DmiInfo::default();
decode_type_1(&s, strings, &mut info);
assert_eq!(info.sys_vendor.as_deref(), Some("Acme Corp"));
assert_eq!(info.product_name.as_deref(), Some("Widget 3000"));
assert_eq!(info.product_version.as_deref(), Some("Rev A"));
assert_eq!(info.product_serial.as_deref(), Some("SN12345"));
}
}
-270
View File
@@ -1,270 +0,0 @@
use std::time::Duration;
use acpi::aml::{
op_region::{OpRegion, RegionHandler, RegionSpace},
AmlError,
};
use common::{
io::{Io, Pio},
timeout::Timeout,
};
use log::*;
const EC_DATA: u16 = 0x62;
const EC_SC: u16 = 0x66;
const OBF: u8 = 1 << 0; // output full / data ready for host <> empty
const IBF: u8 = 1 << 1; // input full / data ready for ec <> empty
const CMD: u8 = 1 << 3; // byte in data reg is command <> data
const BURST: u8 = 1 << 4; // burst mode <> normal mode
const SCI_EVT: u8 = 1 << 5; // sci event pending <> not
const SMI_EVT: u8 = 1 << 6; // smi event pending <> not
const RD_EC: u8 = 0x80;
const WR_EC: u8 = 0x81;
const BE_EC: u8 = 0x82;
const BD_EC: u8 = 0x83;
const QR_EC: u8 = 0x84;
const BURST_ACK: u8 = 0x90;
pub const DEFAULT_EC_TIMEOUT: Duration = Duration::from_millis(10);
#[repr(transparent)]
pub struct ScBits(u8);
#[allow(dead_code)]
impl ScBits {
const fn obf(&self) -> bool {
(self.0 & OBF) != 0
}
const fn ibf(&self) -> bool {
(self.0 & IBF) != 0
}
const fn cmd(&self) -> bool {
(self.0 & CMD) != 0
}
const fn burst(&self) -> bool {
(self.0 & BURST) != 0
}
const fn sci_evt(&self) -> bool {
(self.0 & SCI_EVT) != 0
}
const fn smi_evt(&self) -> bool {
(self.0 & SMI_EVT) != 0
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ec {
sc: u16,
data: u16,
timeout: Duration,
}
impl Ec {
pub fn new() -> Self {
Self {
sc: EC_SC,
data: EC_DATA,
timeout: DEFAULT_EC_TIMEOUT,
}
}
#[allow(dead_code)]
pub fn with_address(sc: u16, data: u16, timeout: Duration) -> Self {
Self { sc, data, timeout }
}
#[inline]
fn read_reg_sc(&self) -> ScBits {
ScBits(Pio::<u8>::new(self.sc).read())
}
#[inline]
fn read_reg_data(&self) -> u8 {
Pio::<u8>::new(self.data).read()
}
#[inline]
fn write_reg_sc(&self, value: u8) {
Pio::<u8>::new(self.sc).write(value);
}
#[inline]
fn write_reg_data(&self, value: u8) {
Pio::<u8>::new(self.data).write(value);
}
#[inline]
fn wait_for_write_ready(&self) -> Option<()> {
let timeout = Timeout::new(self.timeout);
loop {
if !self.read_reg_sc().ibf() {
return Some(());
}
timeout.run().ok()?;
}
}
#[inline]
fn wait_for_read_ready(&self) -> Option<()> {
let timeout = Timeout::new(self.timeout);
loop {
if self.read_reg_sc().obf() {
return Some(());
}
timeout.run().ok()?;
}
}
//https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/12_ACPI_Embedded_Controller_Interface_Specification/embedded-controller-command-set.html
pub fn read(&self, address: u8) -> Option<u8> {
trace!("ec read addr: {:x}", address);
self.wait_for_write_ready()?;
self.write_reg_sc(RD_EC);
self.wait_for_write_ready()?;
self.write_reg_data(address);
self.wait_for_read_ready()?;
let val = self.read_reg_data();
trace!("got: {:x}", val);
Some(val)
}
pub fn write(&self, address: u8, value: u8) -> Option<()> {
trace!("ec write addr: {:x}, with: {:x}", address, value);
self.wait_for_write_ready()?;
self.write_reg_sc(WR_EC);
self.wait_for_write_ready()?;
self.write_reg_data(address);
self.wait_for_write_ready()?;
self.write_reg_data(value);
trace!("done");
Some(())
}
// disabled if not met
// First Access - 400 microseconds
// Subsequent Accesses - 50 microseconds each
// Total Burst Time - 1 millisecond
//Accesses should be responded to within 50 microseconds.
#[allow(dead_code)]
fn enable_burst(&self) -> bool {
trace!("ec burst enable");
self.wait_for_write_ready();
self.write_reg_sc(BE_EC);
self.wait_for_read_ready();
let res = self.read_reg_data() == BURST_ACK;
trace!("success: {}", res);
res
}
#[allow(dead_code)]
fn disable_burst(&self) {
trace!("ec burst disable");
self.wait_for_write_ready();
self.write_reg_sc(BD_EC);
trace!("done");
}
//OSPM driver sends this command when the SCI_EVT flag in the EC_SC register is set.
#[allow(dead_code)]
fn queue_query(&mut self) -> u8 {
trace!("ec query");
self.wait_for_write_ready();
self.write_reg_sc(QR_EC);
self.wait_for_read_ready();
let val = self.read_reg_data();
trace!("got: {}", val);
val
}
}
impl RegionHandler for Ec {
fn read_u8(
&self,
region: &acpi::aml::op_region::OpRegion,
offset: usize,
) -> Result<u8, acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
self.read(offset as u8).ok_or(AmlError::MutexAcquireTimeout) // TODO proper error type
}
fn write_u8(
&self,
region: &OpRegion,
offset: usize,
value: u8,
) -> Result<(), acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
self.write(offset as u8, value)
.ok_or(AmlError::MutexAcquireTimeout) // TODO proper error type
}
fn read_u16(&self, region: &OpRegion, offset: usize) -> Result<u16, acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
// EC is 8-bit; compose 16-bit AML reads as little-endian 8-bit EC reads.
// Cross-referenced with Linux drivers/acpi/ec.c: acpi_ec_read() and
// AML acpi_extract_value() which handles the same byte-decomposition.
let lo = self.read_u8(region, offset)? as u16;
let hi = self.read_u8(region, offset + 1)? as u16;
Ok(lo | (hi << 8))
}
fn read_u32(&self, region: &OpRegion, offset: usize) -> Result<u32, acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let part = self.read_u16(region, offset)? as u32;
let part2 = self.read_u16(region, offset + 2)? as u32;
Ok(part | (part2 << 16))
}
fn read_u64(&self, region: &OpRegion, offset: usize) -> Result<u64, acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let part = self.read_u32(region, offset)? as u64;
let part2 = self.read_u32(region, offset + 4)? as u64;
Ok(part | (part2 << 32))
}
fn write_u16(
&self,
region: &OpRegion,
offset: usize,
value: u16,
) -> Result<(), acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let bytes = value.to_le_bytes();
self.write_u8(region, offset, bytes[0])?;
self.write_u8(region, offset + 1, bytes[1])?;
Ok(())
}
fn write_u32(
&self,
region: &OpRegion,
offset: usize,
value: u32,
) -> Result<(), acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let bytes = value.to_le_bytes();
self.write_u8(region, offset, bytes[0])?;
self.write_u8(region, offset + 1, bytes[1])?;
self.write_u8(region, offset + 2, bytes[2])?;
self.write_u8(region, offset + 3, bytes[3])?;
Ok(())
}
fn write_u64(
&self,
region: &OpRegion,
offset: usize,
value: u64,
) -> Result<(), acpi::aml::AmlError> {
assert_eq!(region.space, RegionSpace::EmbeddedControl);
let bytes = value.to_le_bytes();
self.write_u8(region, offset, bytes[0])?;
self.write_u8(region, offset + 1, bytes[1])?;
self.write_u8(region, offset + 2, bytes[2])?;
self.write_u8(region, offset + 3, bytes[3])?;
self.write_u8(region, offset + 4, bytes[4])?;
self.write_u8(region, offset + 5, bytes[5])?;
self.write_u8(region, offset + 6, bytes[6])?;
self.write_u8(region, offset + 7, bytes[7])?;
Ok(())
}
}
-200
View File
@@ -1,200 +0,0 @@
use std::convert::TryFrom;
use std::mem;
use std::ops::ControlFlow;
use std::sync::Arc;
use ::acpi::aml::op_region::{RegionHandler, RegionSpace};
use event::{EventFlags, RawEventQueue};
use libredox::Fd;
use redox_scheme::{scheme::register_sync_scheme, Socket};
use scheme_utils::Blocking;
use syscall::flag::{AcpiVerb, CallFlags};
mod acpi;
mod aml_physmem;
mod dmi;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ec;
mod scheme;
fn daemon(daemon: daemon::Daemon) -> ! {
common::setup_logging(
"misc",
"acpi",
"acpid",
common::output_level(),
common::file_level(),
);
log::info!("acpid start");
let kernel_acpi_handle = Fd::open("/scheme/kernel.acpi", libredox::flag::O_CLOEXEC, 0)
.expect("acpid: failed to open kernel ACPI handle");
let rxsdt_raw_data: Arc<[u8]> = {
let len = kernel_acpi_handle
.call_ro(&mut [], CallFlags::READ, &[AcpiVerb::ReadRxsdt as u64])
.expect("acpid: failed to get rxsdt length");
let mut buf = vec![0_u8; len];
kernel_acpi_handle
.call_ro(&mut buf, CallFlags::READ, &[AcpiVerb::ReadRxsdt as u64])
.expect("acpid: failed to read rxsdt");
buf.into()
};
if rxsdt_raw_data.is_empty() {
log::info!("System doesn't use ACPI");
daemon.ready();
std::process::exit(0);
}
let sdt = self::acpi::Sdt::new(rxsdt_raw_data).expect("acpid: failed to parse [RX]SDT");
let mut thirty_two_bit;
let mut sixty_four_bit;
let physaddrs_iter = match &sdt.signature {
b"RSDT" => {
thirty_two_bit = sdt
.data()
.chunks(mem::size_of::<u32>())
// TODO: With const generics, the compiler has some way of doing this for static sizes.
.map(|chunk| <[u8; mem::size_of::<u32>()]>::try_from(chunk).unwrap())
.map(|chunk| u32::from_le_bytes(chunk))
.map(u64::from);
&mut thirty_two_bit as &mut dyn Iterator<Item = u64>
}
b"XSDT" => {
sixty_four_bit = sdt
.data()
.chunks(mem::size_of::<u64>())
.map(|chunk| <[u8; mem::size_of::<u64>()]>::try_from(chunk).unwrap())
.map(|chunk| u64::from_le_bytes(chunk));
&mut sixty_four_bit as &mut dyn Iterator<Item = u64>
}
_ => panic!("acpid: expected [RX]SDT from kernel to be either of those"),
};
let region_handlers: Vec<(RegionSpace, Box<dyn RegionHandler + 'static>)> = vec![
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
(RegionSpace::EmbeddedControl, Box::new(ec::Ec::new())),
];
let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter, region_handlers);
// TODO: I/O permission bitmap?
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3");
let shutdown_pipe = kernel_acpi_handle
.openat("kstop", libredox::flag::O_CLOEXEC, 0)
.expect("acpid: failed to open kstop handle");
let mut event_queue = RawEventQueue::new().expect("acpid: failed to create event queue");
let socket = Socket::nonblock().expect("acpid: failed to create disk scheme");
let mut scheme = self::scheme::AcpiScheme::new(&acpi_context, &socket);
// Phase I.5: register the kstop handle fd so the main loop
// can call kstop_reason (kcall 2) to query the kernel for
// the reason of the most recent kstop event. The handle
// shares the underlying file descriptor; the kcall goes
// through the same fd that the event queue subscribes to.
scheme.set_kstop_fd(Fd::new(shutdown_pipe.raw()));
let mut handler = Blocking::new(&socket, 16);
event_queue
.subscribe(shutdown_pipe.raw() as usize, 0, EventFlags::READ)
.expect("acpid: failed to register shutdown pipe for event queue");
event_queue
.subscribe(socket.inner().raw(), 1, EventFlags::READ)
.expect("acpid: failed to register scheme socket for event queue");
register_sync_scheme(&socket, "acpi", &mut scheme)
.expect("acpid: failed to register acpi scheme to namespace");
libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace");
daemon.ready();
let mut mounted = true;
while mounted {
let Some(event) = event_queue
.next()
.transpose()
.expect("acpid: failed to read event file")
else {
break;
};
if event.fd == socket.inner().raw() {
loop {
match handler
.process_requests_nonblocking(&mut scheme)
.expect("acpid: failed to process requests")
{
ControlFlow::Continue(()) => {}
ControlFlow::Break(()) => break,
}
}
} else if event.fd == shutdown_pipe.raw() as usize {
// Phase I.5: dispatch on the kstop reason. The
// kcall 2 (CheckShutdown) verb returns the
// u8 reason. The kernel re-arms the EVENT_READ
// for the next event in the same fd; we read it
// once per cycle.
let reason = match scheme.kstop_reason() {
Ok(r) => r as u8,
Err(e) => {
log::warn!("kstop_reason failed: {:?}, falling back to shutdown", e);
1
}
};
match reason {
0 => {
// idle / no event — spurious wake, ignore
}
1 => {
// shutdown (S5)
log::info!("Received shutdown request from kernel.");
mounted = false;
}
2 => {
// s2idle wake (Phase I.5)
log::info!("s2idle wake: running \\_SST(2) -> \\_WAK(0) -> \\_SST(1)");
acpi_context.exit_s2idle();
}
3 => {
// s3 wake (Phase II.X.W)
// Run the standard S3 resume AML sequence:
// \_SST(2) -> \_WAK(3) -> \_SST(1). The kernel
// trampoline at s3_resume::s3_trampoline
// has already restored the kernel state. The
// acpid's job is the AML wake sequence.
log::info!("s3 wake: running \\_SST(2) -> \\_WAK(3) -> \\_SST(1)");
acpi_context.wake_from_sleep_state(3);
}
other => {
log::warn!("unknown kstop reason {}, treating as shutdown", other);
mounted = false;
}
}
} else {
log::debug!("Received request to unknown fd: {}", event.fd);
continue;
}
}
drop(shutdown_pipe);
drop(event_queue);
acpi_context.set_global_s_state(5);
unreachable!("System should have shut down before this is entered");
}
fn main() {
common::init();
daemon::Daemon::new(daemon);
}
-857
View File
@@ -1,857 +0,0 @@
use acpi::aml::namespace::AmlName;
use amlserde::aml_serde_name::to_aml_format;
use amlserde::AmlSerdeValue;
use core::str;
use libredox::Fd;
use parking_lot::RwLockReadGuard;
use redox_scheme::scheme::SchemeSync;
use redox_scheme::{CallerCtx, OpenResult, SendFdRequest, Socket};
use syscall::flag::CallFlags;
use syscall::flag::AcpiVerb;
use ron::de::SpannedError;
use scheme_utils::HandleMap;
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
use syscall::schemev2::NewFdFlags;
use syscall::FobtainFdFlags;
use syscall::data::Stat;
use syscall::error::{Error, Result};
use syscall::error::{EACCES, EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR};
use syscall::flag::{MODE_DIR, MODE_FILE};
use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDONLY, O_STAT, O_SYMLINK};
use syscall::{EOVERFLOW, EPERM};
use crate::acpi::{AcpiContext, AmlSymbols, PowerCache, SdtSignature};
use crate::dmi::DMI_FIELDS;
pub struct AcpiScheme<'acpi, 'sock> {
ctx: &'acpi AcpiContext,
handles: HandleMap<Handle<'acpi>>,
pci_fd: Option<Fd>,
socket: &'sock Socket,
/// Phase I.5: the kstop handle fd. Stored so the main loop
/// can call `kstop_reason` (kcall 2) to query the kernel
/// for the reason of the most recent kstop event.
kstop_fd: Option<Fd>,
power_cache: PowerCache,
}
struct Handle<'a> {
kind: HandleKind<'a>,
stat: bool,
allowed_to_eval: bool,
}
enum HandleKind<'a> {
TopLevel,
Tables,
Table(SdtSignature),
Symbols(RwLockReadGuard<'a, AmlSymbols>),
Symbol { name: String, description: String },
SchemeRoot,
RegisterPci,
/// `/scheme/acpi/thermal` -- entries are children of `\_TZ` from
/// the AML namespace (e.g. `\_TZ.TZ0`). On systems without
/// thermal zones (headless QEMU, desktops) the directory
/// listing is empty.
Thermal,
/// `/scheme/acpi/power` -- entries are PowerResource objects in
/// the AML namespace. On laptops these are AC adapters and
/// battery controllers. On desktops and QEMU the listing is
/// empty.
Power,
PowerBatteries,
PowerBattery { name: String, file: PowerFileKind },
PowerAdapter { name: String, file: PowerFileKind },
/// `/scheme/acpi/dmi` -- key=value text dump of the SMBIOS identity
/// fields (consumed by `redox-driver-sys` quirks loader).
Dmi,
/// `/scheme/acpi/dmi/<field>` -- a single SMBIOS field as a text
/// file (consumed by `i2c-hidd` for probe-failure quirks).
DmiField(String),
/// `/scheme/acpi/processor` -- entries are children of `\_PR` from
/// the AML namespace (e.g. `CPU0`, `CPU1`). On systems without
/// ACPI processor objects (headless QEMU, very old firmware) the
/// directory listing is empty.
Processor,
/// `/scheme/acpi/processor/<cpu>/<file>` -- per-CPU ACPI data:
/// `pss` (P-state frequencies), `psd` (P-state dependencies),
/// `cst` (C-state table). On QEMU these are typically empty.
/// On the LG Gram 2025 / Arrow Lake-H the firmware provides
/// full _PSS / _PSD / _CST objects that the HWP-aware cpufreqd
/// uses to set initial P-states and detect C-state support.
ProcFile { cpu: u32, kind: ProcFileKind },
DmiDir,
}
#[derive(Clone, Copy, Debug)]
enum PowerFileKind {
State,
Percentage,
Online,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ProcFileKind {
Pss,
Psd,
Cst,
Cpc,
}
impl HandleKind<'_> {
fn is_dir(&self) -> bool {
match self {
Self::TopLevel => true,
Self::Tables => true,
Self::Table(_) => false,
Self::Symbols(_) => true,
Self::Symbol { .. } => false,
Self::SchemeRoot => false,
Self::RegisterPci => false,
Self::Thermal | Self::Power | Self::Processor | Self::DmiDir | Self::PowerBatteries => true,
Self::PowerBattery { .. } | Self::PowerAdapter { .. } => false,
Self::Dmi => true,
Self::DmiField(_) => false,
Self::ProcFile { .. } => false,
}
}
fn len(&self, acpi_ctx: &AcpiContext) -> Result<usize> {
Ok(match self {
// Files
Self::Table(signature) => acpi_ctx
.sdt_from_signature(signature)
.ok_or(Error::new(EBADFD))?
.length(),
Self::Symbol { description, .. } => description.len(),
// /scheme/acpi/dmi is a key=value text file (redox-driver-sys
// reads it via fs::read_to_string). The size depends on how
// many fields are populated.
Self::Dmi => acpi_ctx
.dmi_info()
.map(|info| info.to_match_lines().len())
.unwrap_or(0),
Self::DmiField(field) => dmi_field_contents(acpi_ctx.dmi_info(), field)
.map(|s| s.len())
.unwrap_or(0),
Self::PowerBatteries | Self::PowerBattery { .. } | Self::PowerAdapter { .. } => 2,
// Directories
Self::TopLevel | Self::Symbols(_) | Self::Tables => 0,
Self::Thermal | Self::Power | Self::Processor | Self::DmiDir => 0,
// ProcFile contents (e.g. PSS table) are bounded by the
// platform's ACPI table sizes; the maximum reasonable size
// is one page (4096 bytes). Report the file as a fixed
// size so the kernel-side read can mmap it.
Self::ProcFile { .. } => 4096,
Self::SchemeRoot | Self::RegisterPci => return Err(Error::new(EBADF)),
})
}
}
impl<'acpi, 'sock> AcpiScheme<'acpi, 'sock> {
pub fn new(ctx: &'acpi AcpiContext, socket: &'sock Socket) -> Self {
Self {
ctx,
handles: HandleMap::new(),
pci_fd: None,
socket,
kstop_fd: None,
power_cache: PowerCache::default(),
}
}
fn power_cache(&mut self) -> &PowerCache {
if self.power_cache.batteries.is_empty() && self.power_cache.adapter.is_none() {
self.power_cache = self.ctx.power_devices();
}
&self.power_cache
}
/// Phase I.5: register the kstop handle fd. Called by the
/// main loop right after opening the kstop handle.
pub fn set_kstop_fd(&mut self, fd: Fd) {
self.kstop_fd = Some(fd);
}
/// Phase I.5: query the kernel for the kstop reason via
/// the CheckShutdown AcpiVerb (kcall 2). Returns the u8
/// reason: 0=idle, 1=shutdown (S5), 2=s2idle wake,
/// 3=s3 wake. The kernel re-arms the kstop handle's
/// EVENT_READ after each event; acpid's main loop calls
/// this once per event to decide what AML sequence to run.
///
/// Mirrors Linux 7.1 `acpi_s2idle_wake` returning the
/// wake reason in `drivers/acpi/sleep.c:758`. The
/// `kcall 2` is the `AcpiVerb::CheckShutdown` enum
/// variant in the syscall crate.
///
/// Hardware-agnostic: the reason codes are platform-
/// independent; only the wake source (SCI, GPIO, RTC,
/// ...) varies per OEM.
pub fn kstop_reason(&mut self) -> syscall::Result<u64> {
let handle = self.kstop_fd.as_ref().ok_or(syscall::error::Error::new(syscall::error::EBADF))?;
let mut payload = [0u8; 8];
let verb = AcpiVerb::CheckShutdown as u64;
let _result = handle.call_ro(&mut payload, CallFlags::empty(), &[verb])?;
Ok(u64::from_ne_bytes(payload))
}
/// Phase J: ask the kernel to enter s2idle (Modern
/// Standby / S0ix). This is the typed-AcpiVerb equivalent
/// of writing "s2idle" to /scheme/sys/kstop — the kstop
/// string-arg path was Phase I.5's fallback while we
/// couldn't extend the syscall crate due to the libredox
/// cross-version issue. Phase J: with the local libredox
/// fork (which uses the local syscall fork with
/// EnterS2Idle/ExitS2Idle), this typed path is the
/// preferred API. The kstop string-arg path remains for
/// backward compatibility with older acpid builds.
///
/// Hardware-agnostic: works for any platform with Modern
/// Standby firmware (Dell, HP, Lenovo, LG Gram, etc.).
/// Mirrors Linux 7.1 `acpi_s2idle_begin` in
/// `kernel/power/suspend.c:91`.
pub fn kstop_enter_s2idle(&self) -> syscall::Result<()> {
let handle = self.kstop_fd.as_ref().ok_or(syscall::error::Error::new(syscall::error::EBADF))?;
let verb = AcpiVerb::EnterS2Idle as u64;
// AcpiVerb::EnterS2Idle doesn't need a write payload;
// the verb code itself is the signal. The kernel
// sets S2IDLE_REQUESTED + signals the kstop handle's
// EVENT_READ.
handle.call_wo(&[], CallFlags::empty(), &[verb])?;
Ok(())
}
/// Phase II.X.W: write the kernel's S3 resume
/// trampoline address to FACS.xfirmware_waking_vector so
/// the platform firmware jumps to it on S3 wake.
///
/// `trampoline_addr` is the address of the kernel's
/// `s3_resume::s3_trampoline` function. The kernel
/// writes this to FACS via the `SetS3WakingVector`
/// AcPiVerb (verb 5).
pub fn kstop_enter_s3(&self, trampoline_addr: u64) -> syscall::Result<()> {
let handle = self.kstop_fd.as_ref().ok_or(syscall::error::Error::new(syscall::error::EBADF))?;
let verb = AcpiVerb::SetS3WakingVector as u64;
// Payload: 8-byte little-endian u64 (the trampoline
// address). The kernel's `SetS3WakingVector` handler
// requires the payload to be exactly 8 bytes.
let payload = trampoline_addr.to_ne_bytes();
handle.call_wo(&payload, CallFlags::empty(), &[verb])?;
Ok(())
}
}
fn parse_hex_digit(hex: u8) -> Option<u8> {
let hex = hex.to_ascii_lowercase();
if hex >= b'a' && hex <= b'f' {
Some(hex - b'a' + 10)
} else if hex >= b'0' && hex <= b'9' {
Some(hex - b'0')
} else {
None
}
}
fn parse_hex_2digit(hex: &[u8]) -> Option<u8> {
parse_hex_digit(hex[0])
.and_then(|most_significant| Some((most_significant << 4) | parse_hex_digit(hex[1])?))
}
fn parse_oem_id(hex: [u8; 12]) -> Option<[u8; 6]> {
Some([
parse_hex_2digit(&hex[0..2])?,
parse_hex_2digit(&hex[2..4])?,
parse_hex_2digit(&hex[4..6])?,
parse_hex_2digit(&hex[6..8])?,
parse_hex_2digit(&hex[8..10])?,
parse_hex_2digit(&hex[10..12])?,
])
}
fn parse_oem_table_id(hex: [u8; 16]) -> Option<[u8; 8]> {
Some([
parse_hex_2digit(&hex[0..2])?,
parse_hex_2digit(&hex[2..4])?,
parse_hex_2digit(&hex[4..6])?,
parse_hex_2digit(&hex[6..8])?,
parse_hex_2digit(&hex[8..10])?,
parse_hex_2digit(&hex[10..12])?,
parse_hex_2digit(&hex[12..14])?,
parse_hex_2digit(&hex[14..16])?,
])
}
/// Look up the contents of `/scheme/acpi/dmi/<field>` for the given
/// field name. Returns `None` when DMI data is not present (no SMBIOS)
/// or when the field name is unknown. The returned `String` is what
/// userspace will read from the file -- a single text line with no
/// trailing newline so that callers can `read_to_string` and `trim`.
fn dmi_field_contents(
info: Option<&crate::dmi::DmiInfo>,
field: &str,
) -> Option<String> {
crate::dmi::read_field(info, field)
}
fn parse_table(table: &[u8]) -> Option<SdtSignature> {
let signature_part = table.get(..4)?;
let first_hyphen = table.get(4)?;
let oem_id_part = table.get(5..17)?;
let second_hyphen = table.get(17)?;
let oem_table_part = table.get(18..34)?;
if *first_hyphen != b'-' {
return None;
}
if *second_hyphen != b'-' {
return None;
}
if table.len() > 34 {
return None;
}
Some(SdtSignature {
signature: <[u8; 4]>::try_from(signature_part)
.expect("expected 4-byte slice to be convertible into [u8; 4]"),
oem_id: {
let hex = <[u8; 12]>::try_from(oem_id_part)
.expect("expected 12-byte slice to be convertible into [u8; 12]");
parse_oem_id(hex)?
},
oem_table_id: {
let hex = <[u8; 16]>::try_from(oem_table_part)
.expect("expected 16-byte slice to be convertible into [u8; 16]");
parse_oem_table_id(hex)?
},
})
}
impl SchemeSync for AcpiScheme<'_, '_> {
fn scheme_root(&mut self) -> Result<usize> {
Ok(self.handles.insert(Handle {
stat: false,
kind: HandleKind::SchemeRoot,
allowed_to_eval: false,
}))
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
let handle = self.handles.get(dirfd)?;
let path = path.trim_start_matches('/');
let flag_stat = flags & O_STAT == O_STAT;
let flag_dir = flags & O_DIRECTORY == O_DIRECTORY;
let kind = match handle.kind {
HandleKind::SchemeRoot => {
// TODO: arrayvec
let components = {
let mut v = arrayvec::ArrayVec::<&str, 4>::new();
let it = path.split('/');
for component in it.take(4) {
v.push(component);
}
v
};
match &*components {
[""] => HandleKind::TopLevel,
["register_pci"] => HandleKind::RegisterPci,
["tables"] => HandleKind::Tables,
["thermal"] => HandleKind::Thermal,
["power"] => HandleKind::Power,
["dmi"] => HandleKind::Dmi,
["processor"] => HandleKind::Processor,
["power", "batteries"] => HandleKind::PowerBatteries,
["power", "batteries", name, file] => {
let file = match *file {
"state" => PowerFileKind::State,
"percentage" => PowerFileKind::Percentage,
_ => return Err(Error::new(ENOENT)),
};
HandleKind::PowerBattery { name: (*name).to_owned(), file }
}
["power", "adapters", name, file] => {
let file = match *file {
"online" => PowerFileKind::Online,
_ => return Err(Error::new(ENOENT)),
};
HandleKind::PowerAdapter { name: (*name).to_owned(), file }
}
["tables", table] => {
let signature = parse_table(table.as_bytes()).ok_or(Error::new(ENOENT))?;
HandleKind::Table(signature)
}
["symbols"] => {
if let Ok(aml_symbols) = self.ctx.aml_symbols(self.pci_fd.as_ref()) {
HandleKind::Symbols(aml_symbols)
} else {
return Err(Error::new(EIO));
}
}
["symbols", symbol] => {
if let Some(description) = self.ctx.aml_lookup(symbol) {
HandleKind::Symbol {
name: (*symbol).to_owned(),
description,
}
} else {
return Err(Error::new(ENOENT));
}
}
["dmi", field] => {
// Reject unknown fields explicitly so consumers
// see ENOENT rather than reading an empty file.
// When SMBIOS is absent, we still serve a
// well-defined file with empty contents (so
// i2c-hidd's `Err(NotFound)` branch is the only
// way to tell the difference between "missing
// field" and "no SMBIOS").
if DMI_FIELDS.iter().any(|f| *f == *field) {
HandleKind::DmiField((*field).to_owned())
} else {
return Err(Error::new(ENOENT));
}
}
["processor", cpu_str, file] => {
// /scheme/acpi/processor/<cpu>/{pss,psd,cst,cpc}
let cpu: u32 = cpu_str
.strip_prefix("CPU")
.and_then(|rest| rest.parse().ok())
.ok_or(Error::new(EINVAL))?;
let kind = match *file {
"pss" => ProcFileKind::Pss,
"psd" => ProcFileKind::Psd,
"cst" => ProcFileKind::Cst,
"cpc" => ProcFileKind::Cpc,
_ => return Err(Error::new(ENOENT)),
};
HandleKind::ProcFile { cpu, kind }
}
_ => return Err(Error::new(ENOENT)),
}
}
HandleKind::Symbols(ref aml_symbols) => {
if let Some(description) = aml_symbols.lookup(path) {
HandleKind::Symbol {
name: (*path).to_owned(),
description,
}
} else {
return Err(Error::new(ENOENT));
}
}
_ => return Err(Error::new(EACCES)),
};
if kind.is_dir() && !flag_dir && !flag_stat {
return Err(Error::new(EISDIR));
} else if !kind.is_dir() && flag_dir && !flag_stat {
return Err(Error::new(ENOTDIR));
}
let allowed_to_eval = if flags & O_ACCMODE == O_RDONLY || flag_stat {
false
} else if ctx.uid == 0 {
true
} else {
return Err(Error::new(EINVAL));
};
if flags & O_SYMLINK == O_SYMLINK && !flag_stat {
return Err(Error::new(EINVAL));
}
let fd = self.handles.insert(Handle {
stat: flag_stat,
kind,
allowed_to_eval,
});
Ok(OpenResult::ThisScheme {
number: fd,
flags: NewFdFlags::POSITIONED,
})
}
fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
let handle = self.handles.get(id)?;
stat.st_size = handle
.kind
.len(self.ctx)?
.try_into()
.unwrap_or(u64::max_value());
if handle.kind.is_dir() {
stat.st_mode = MODE_DIR;
} else {
stat.st_mode = MODE_FILE;
}
Ok(())
}
fn read(
&mut self,
id: usize,
buf: &mut [u8],
offset: u64,
_fcntl: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
let offset: usize = offset.try_into().map_err(|_| Error::new(EINVAL))?;
let handle = self.handles.get_mut(id)?;
if handle.stat {
return Err(Error::new(EBADF));
}
// Build an owned buffer for DMI handles so the borrow does not
// escape the match arm scope.
let dmi_buf;
let proc_buf;
let src_buf: &[u8] = match &handle.kind {
HandleKind::Table(ref signature) => self
.ctx
.sdt_from_signature(signature)
.ok_or(Error::new(EBADFD))?
.as_slice(),
HandleKind::Symbol { description, .. } => description.as_bytes(),
HandleKind::Dmi => {
dmi_buf = self
.ctx
.dmi_info()
.map(|info| info.to_match_lines())
.unwrap_or_default();
dmi_buf.as_bytes()
}
HandleKind::DmiField(ref field) => {
dmi_buf = dmi_field_contents(self.ctx.dmi_info(), field)
.unwrap_or_default();
dmi_buf.as_bytes()
}
HandleKind::PowerBattery { name, file } => {
dmi_buf = match file {
PowerFileKind::State => self.ctx.battery_state_text(name),
PowerFileKind::Percentage => self.ctx.battery_percentage_text(name),
PowerFileKind::Online => String::new(),
};
dmi_buf.as_bytes()
}
HandleKind::PowerAdapter { name, file } => {
dmi_buf = match file {
PowerFileKind::Online => self.ctx.adapter_online_text(name),
PowerFileKind::State | PowerFileKind::Percentage => String::new(),
};
dmi_buf.as_bytes()
}
HandleKind::Processor | HandleKind::DmiDir | HandleKind::Thermal | HandleKind::Power | HandleKind::PowerBatteries | HandleKind::Symbols(_) | HandleKind::RegisterPci | HandleKind::TopLevel | HandleKind::SchemeRoot => {
return Err(Error::new(EISDIR));
}
HandleKind::ProcFile { cpu, kind } => {
let method = match kind {
ProcFileKind::Pss => "_PSS",
ProcFileKind::Psd => "_PSD",
ProcFileKind::Cst => "_CST",
ProcFileKind::Cpc => "_CPC",
};
let cpu_segment = format!("CPU{}", cpu);
proc_buf = self
.ctx
.processor_method_text(&cpu_segment, method)
.into_bytes();
proc_buf.as_slice()
}
HandleKind::Tables => return Err(Error::new(EISDIR)),
};
let offset = std::cmp::min(src_buf.len(), offset);
let src_buf = &src_buf[offset..];
let to_copy = std::cmp::min(src_buf.len(), buf.len());
buf[..to_copy].copy_from_slice(&src_buf[..to_copy]);
Ok(to_copy)
}
fn getdents<'buf>(
&mut self,
id: usize,
mut buf: DirentBuf<&'buf mut [u8]>,
opaque_offset: u64,
) -> Result<DirentBuf<&'buf mut [u8]>> {
let handle = self.handles.get_mut(id)?;
match &handle.kind {
HandleKind::TopLevel => {
const TOPLEVEL_ENTRIES: &[&str] = &[
"tables", "symbols", "thermal", "power", "dmi", "processor",
];
for (idx, name) in TOPLEVEL_ENTRIES
.iter()
.enumerate()
.skip(opaque_offset as usize)
{
buf.entry(DirEntry {
inode: 0,
next_opaque_id: idx as u64 + 1,
name,
kind: DirentKind::Directory,
})?;
}
}
HandleKind::Symbols(aml_symbols) => {
for (idx, (symbol_name, _value)) in aml_symbols
.symbols_cache()
.iter()
.enumerate()
.skip(opaque_offset as usize)
{
buf.entry(DirEntry {
inode: 0,
next_opaque_id: idx as u64 + 1,
name: symbol_name.as_str(),
kind: DirentKind::Regular,
})?;
}
}
HandleKind::Tables => {
for (idx, table) in self
.ctx
.tables()
.iter()
.enumerate()
.skip(opaque_offset as usize)
{
let utf8_or_eio = |bytes| str::from_utf8(bytes).map_err(|_| Error::new(EIO));
let mut name = String::new();
name.push_str(utf8_or_eio(&table.signature[..])?);
name.push('-');
for byte in table.oem_id.iter() {
std::fmt::write(&mut name, format_args!("{:>02X}", byte)).unwrap();
}
name.push('-');
for byte in table.oem_table_id.iter() {
std::fmt::write(&mut name, format_args!("{:>02X}", byte)).unwrap();
}
buf.entry(DirEntry {
inode: 0,
next_opaque_id: idx as u64 + 1,
name: &name,
kind: DirentKind::Regular,
})?;
}
}
HandleKind::Thermal => {
// Enumerate \_TZ.<zone> entries from the AML namespace.
// Returns Ok with no entries on systems with no zones
// (headless QEMU, desktops) so consumers see an
// empty-but-existing directory.
let zones = self.ctx.thermal_zones();
for (idx, zone) in zones.iter().enumerate().skip(opaque_offset as usize) {
buf.entry(DirEntry {
inode: 0,
next_opaque_id: idx as u64 + 1,
name: zone.as_str(),
kind: DirentKind::Directory,
})?;
}
}
HandleKind::Processor => {
// Enumerate \_PR.<cpu> entries from the AML namespace.
// Returns Ok with no entries on systems with no
// processors (headless QEMU with no DSDT) so consumers
// see an empty-but-existing directory. The directory
// entry names use the short CPU segment (e.g. "CPU0")
// so that `processor/CPU0/pss` is a valid sub-path.
let cpus = self.ctx.cpu_names();
for (idx, cpu_path) in cpus.iter().enumerate().skip(opaque_offset as usize) {
let short = cpu_path.strip_prefix("\\_PR.").unwrap_or(cpu_path);
buf.entry(DirEntry {
inode: 0,
next_opaque_id: idx as u64 + 1,
name: short,
kind: DirentKind::Directory,
})?;
}
}
HandleKind::Power => {
// Enumerate PowerResource entries. On real laptops these
// are AC adapters and battery controllers; on desktops
// and QEMU the list is empty.
let cache = self.power_cache().clone();
if !cache.batteries.is_empty() {
buf.entry(DirEntry {
inode: 0,
next_opaque_id: 1,
name: "batteries",
kind: DirentKind::Directory,
})?;
}
if cache.adapter.is_some() {
buf.entry(DirEntry {
inode: 0,
next_opaque_id: 2,
name: "adapters",
kind: DirentKind::Directory,
})?;
}
}
HandleKind::PowerBatteries => {
let batteries = &self.power_cache().batteries;
for (idx, battery) in batteries.iter().enumerate().skip(opaque_offset as usize) {
buf.entry(DirEntry {
inode: 0,
next_opaque_id: idx as u64 + 1,
name: battery.as_str(),
kind: DirentKind::Directory,
})?;
}
}
HandleKind::PowerBattery { .. } => {
for (idx, file) in ["state", "percentage"].iter().enumerate().skip(opaque_offset as usize) {
buf.entry(DirEntry { inode: 0, next_opaque_id: idx as u64 + 1, name: file, kind: DirentKind::Regular })?;
}
}
HandleKind::PowerAdapter { .. } => {
buf.entry(DirEntry { inode: 0, next_opaque_id: 1, name: "online", kind: DirentKind::Regular })?;
}
HandleKind::Dmi => {
// Consumers should `read_to_string("/scheme/acpi/dmi")`
// rather than iterating, but we still surface the field
// list so that ls /scheme/acpi/dmi/ produces a useful
// diagnostic on a live system. We always list the same
// set of fields regardless of whether SMBIOS data is
// present -- empty entries just produce empty reads.
for (idx, field) in DMI_FIELDS
.iter()
.enumerate()
.skip(opaque_offset as usize)
{
buf.entry(DirEntry {
inode: 0,
next_opaque_id: idx as u64 + 1,
name: field,
kind: DirentKind::Regular,
})?;
}
}
HandleKind::ProcFile { .. } | HandleKind::DmiDir => {
// No children; reads/writes go through the
// HandleKind match in kread/kwriteoff.
}
_ => return Err(Error::new(EIO)),
}
Ok(buf)
}
fn call(
&mut self,
id: usize,
payload: &mut [u8],
_metadata: &[u64],
_ctx: &CallerCtx,
) -> Result<usize> {
let handle = self.handles.get_mut(id)?;
if !handle.allowed_to_eval {
return Err(Error::new(EPERM));
}
let Ok(args): Result<Vec<AmlSerdeValue>, SpannedError> = ron::de::from_bytes(payload)
else {
return Err(Error::new(EINVAL));
};
let HandleKind::Symbol { name, .. } = &handle.kind else {
return Err(Error::new(EBADF));
};
let Ok(aml_name) = AmlName::from_str(&to_aml_format(name)) else {
log::error!("Failed to convert symbol name: \"{name}\" to aml name!");
return Err(Error::new(EBADF));
};
let Ok(result) = self.ctx.aml_eval(aml_name, args) else {
return Err(Error::new(EINVAL));
};
let Ok(serialized_result) = ron::ser::to_string(&result) else {
log::error!("Failed to serialize aml result!");
return Err(Error::new(EINVAL));
};
let byte_result = serialized_result.as_bytes();
let result_len = byte_result.len();
if result_len > payload.len() {
return Err(Error::new(EOVERFLOW));
}
payload[..result_len].copy_from_slice(byte_result);
Ok(result_len)
}
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
let id = sendfd_request.id();
let num_fds = sendfd_request.num_fds();
let handle = self.handles.get(id)?;
if !matches!(handle.kind, HandleKind::RegisterPci) {
return Err(Error::new(EACCES));
}
if num_fds == 0 {
return Ok(0);
}
if num_fds > 1 {
return Err(Error::new(EINVAL));
}
let mut new_fd = usize::MAX;
if let Err(e) = sendfd_request.obtain_fd(
&self.socket,
FobtainFdFlags::UPPER_TBL,
std::slice::from_mut(&mut new_fd),
) {
return Err(e);
}
let new_fd = libredox::Fd::new(new_fd);
if self.pci_fd.is_some() {
return Err(Error::new(EINVAL));
} else {
self.pci_fd = Some(new_fd);
}
Ok(num_fds)
}
fn on_close(&mut self, id: usize) {
self.handles.remove(id);
}
}
-14
View File
@@ -1,14 +0,0 @@
[package]
name = "amlserde"
description = "Library for serializing AML symbols"
version = "0.0.1"
authors = ["Ron Williams"]
repository = "https://gitlab.redox-os.org/redox-os/drivers"
categories = ["hardware-support"]
license = "MIT/Apache-2.0"
edition = "2021"
[dependencies]
acpi.workspace = true
serde.workspace = true
toml.workspace = true
-484
View File
@@ -1,484 +0,0 @@
use acpi::{
aml::{
namespace::AmlName,
object::{
FieldAccessType, FieldFlags, FieldUnit, FieldUnitKind, FieldUpdateRule, MethodFlags,
Object, ReferenceKind, WrappedObject,
},
op_region::{OpRegion, RegionSpace},
Interpreter,
},
Handle, Handler,
};
use serde::{Deserialize, Serialize};
use std::{
ops::{Deref, Shl},
str::FromStr,
sync::{
atomic::{AtomicU64, Ordering},
Arc,
},
};
#[derive(Debug, Serialize, Deserialize)]
pub struct AmlSerde {
pub name: String,
pub value: AmlSerdeValue,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum AmlSerdeValue {
Uninitialized,
Integer(u64),
String(String),
OpRegion {
region: AmlSerdeRegionSpace,
offset: u64,
length: u64,
parent_device: String,
},
Field {
kind: AmlSerdeFieldKind,
flags: AmlSerdeFieldFlags,
offset: u64,
length: u64,
},
Device,
Event(u64),
Method {
arg_count: usize,
serialize: bool,
sync_level: u8,
},
Buffer(Vec<u8>),
BufferField {
offset: u64,
length: u64,
data: Box<AmlSerdeValue>,
},
Processor {
id: u8,
pblk_address: u32,
pblk_len: u8,
},
Mutex {
mutex: u32,
sync_level: u8,
},
Reference {
kind: AmlSerdeReferenceKind,
inner: Box<AmlSerdeValue>,
},
Package {
contents: Vec<AmlSerdeValue>,
},
PowerResource {
system_level: u8,
resource_order: u16,
},
RawDataBuffer,
ThermalZone,
Debug,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum AmlSerdeRegionSpace {
SystemMemory,
SystemIo,
PciConfig,
EmbeddedControl,
SMBus,
SystemCmos,
PciBarTarget,
IPMI,
GeneralPurposeIo,
GenericSerialBus,
Pcc,
OemDefined(u8),
}
#[derive(Debug, Serialize, Deserialize)]
pub enum AmlSerdeFieldKind {
Normal {
region: Box<AmlSerdeValue>,
},
Bank {
region: Box<AmlSerdeValue>,
bank: Box<AmlSerdeValue>,
bank_value: u64,
},
Index {
index: Box<AmlSerdeValue>,
data: Box<AmlSerdeValue>,
},
}
#[derive(Debug, Serialize, Deserialize)]
pub struct AmlSerdeFieldFlags {
pub access_type: AmlSerdeFieldAccessType,
pub lock_rule: bool, // bit 4
pub update_rule: AmlSerdeFieldUpdateRule,
}
impl Into<u8> for AmlSerdeFieldFlags {
fn into(self) -> u8 {
// bits 0..4
(self.access_type as u8) +
// bit 4
(self.lock_rule as u8).shl(4) +
// bits 5..7
(self.update_rule as u8).shl(5)
}
}
#[derive(Debug, Serialize, Deserialize)]
#[repr(u8)]
pub enum AmlSerdeFieldAccessType {
Any = 0,
Byte = 1,
Word = 2,
DWord = 3,
QWord = 4,
Buffer = 5,
}
#[derive(Debug, Serialize, Deserialize)]
#[repr(u8)]
pub enum AmlSerdeFieldUpdateRule {
Preserve = 0,
WriteAsOnes = 1,
WriteAsZeros = 2,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum AmlSerdeReferenceKind {
RefOf,
Local,
Arg,
Index,
Named,
Unresolved,
}
impl AmlSerde {
pub fn default() -> Self {
Self {
name: "name".to_owned(),
value: AmlSerdeValue::String(String::default()),
}
}
pub fn from_aml<H: Handler>(aml_context: &Interpreter<H>, aml_name: &AmlName) -> Option<Self> {
//TODO: why does namespace.get not take a reference to aml_name
let aml_value = if let Ok(aml_value) = aml_context.namespace.lock().get(aml_name.clone()) {
aml_value
} else {
return None;
};
let value = if let Some(value) = AmlSerdeValue::from_aml_value(aml_value.deref()) {
value
} else {
return None;
};
Some(AmlSerde {
name: aml_name.to_string(),
value,
})
}
}
impl AmlSerdeValue {
pub fn default() -> Self {
AmlSerdeValue::String("".to_owned())
}
pub fn from_aml_value(aml_value: &Object) -> Option<Self> {
Some(match aml_value {
Object::Uninitialized => AmlSerdeValue::Uninitialized,
Object::Integer(n) => AmlSerdeValue::Integer(n.to_owned()),
Object::String(s) => AmlSerdeValue::String(s.to_owned()),
Object::OpRegion(region) => AmlSerdeValue::OpRegion {
region: match region.space {
RegionSpace::SystemMemory => AmlSerdeRegionSpace::SystemMemory,
RegionSpace::SystemIO => AmlSerdeRegionSpace::SystemIo,
RegionSpace::PciConfig => AmlSerdeRegionSpace::PciConfig,
RegionSpace::EmbeddedControl => AmlSerdeRegionSpace::EmbeddedControl,
RegionSpace::SmBus => AmlSerdeRegionSpace::SMBus,
RegionSpace::SystemCmos => AmlSerdeRegionSpace::SystemCmos,
RegionSpace::PciBarTarget => AmlSerdeRegionSpace::PciBarTarget,
RegionSpace::Ipmi => AmlSerdeRegionSpace::IPMI,
RegionSpace::GeneralPurposeIo => AmlSerdeRegionSpace::GeneralPurposeIo,
RegionSpace::GenericSerialBus => AmlSerdeRegionSpace::GenericSerialBus,
RegionSpace::Pcc => AmlSerdeRegionSpace::Pcc,
RegionSpace::Oem(n) => AmlSerdeRegionSpace::OemDefined(n.to_owned()),
},
offset: region.base,
length: region.length,
parent_device: region.parent_device_path.to_string(),
},
Object::FieldUnit(field) => AmlSerdeValue::Field {
kind: match &field.kind {
FieldUnitKind::Normal { region } => AmlSerdeFieldKind::Normal {
region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new)?,
},
FieldUnitKind::Bank {
region,
bank,
bank_value,
} => AmlSerdeFieldKind::Bank {
region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new)?,
bank: AmlSerdeValue::from_aml_value(bank.deref()).map(Box::new)?,
bank_value: bank_value.to_owned(),
},
FieldUnitKind::Index { index, data } => AmlSerdeFieldKind::Index {
index: AmlSerdeValue::from_aml_value(index.deref()).map(Box::new)?,
data: AmlSerdeValue::from_aml_value(data.deref()).map(Box::new)?,
},
},
flags: AmlSerdeFieldFlags {
access_type: match field.flags.access_type() {
Ok(FieldAccessType::Any) => AmlSerdeFieldAccessType::Any,
Ok(FieldAccessType::Byte) => AmlSerdeFieldAccessType::Byte,
Ok(FieldAccessType::Word) => AmlSerdeFieldAccessType::Word,
Ok(FieldAccessType::DWord) => AmlSerdeFieldAccessType::DWord,
Ok(FieldAccessType::QWord) => AmlSerdeFieldAccessType::QWord,
Ok(FieldAccessType::Buffer) => AmlSerdeFieldAccessType::Buffer,
_ => return None,
},
lock_rule: field.flags.lock_rule(),
update_rule: match field.flags.update_rule() {
FieldUpdateRule::Preserve => AmlSerdeFieldUpdateRule::Preserve,
FieldUpdateRule::WriteAsOnes => AmlSerdeFieldUpdateRule::WriteAsOnes,
FieldUpdateRule::WriteAsZeros => AmlSerdeFieldUpdateRule::WriteAsZeros,
},
},
offset: field.bit_index as u64,
length: field.bit_length as u64,
},
Object::Device => AmlSerdeValue::Device,
Object::Event(event) => AmlSerdeValue::Event(event.load(Ordering::Relaxed)),
Object::Method { flags, code: _ } => AmlSerdeValue::Method {
arg_count: flags.arg_count(),
serialize: flags.serialize(),
sync_level: flags.sync_level(),
},
//TODO: distinguish from Method?
Object::NativeMethod { f: _, flags } => AmlSerdeValue::Method {
arg_count: flags.arg_count(),
serialize: flags.serialize(),
sync_level: flags.sync_level(),
},
Object::Buffer(buffer_data) => AmlSerdeValue::Buffer(buffer_data.to_owned()),
Object::BufferField {
buffer,
offset,
length,
} => AmlSerdeValue::BufferField {
offset: offset.to_owned() as u64,
length: length.to_owned() as u64,
data: AmlSerdeValue::from_aml_value(buffer.deref()).map(Box::new)?,
},
Object::Processor {
proc_id,
pblk_address,
pblk_length,
} => AmlSerdeValue::Processor {
id: proc_id.to_owned(),
pblk_address: pblk_address.to_owned(),
pblk_len: pblk_length.to_owned(),
},
Object::Mutex { mutex, sync_level } => AmlSerdeValue::Mutex {
mutex: mutex.0,
sync_level: sync_level.to_owned(),
},
Object::Reference { kind, inner } => AmlSerdeValue::Reference {
kind: match kind {
ReferenceKind::RefOf => AmlSerdeReferenceKind::RefOf,
ReferenceKind::Local => AmlSerdeReferenceKind::Local,
ReferenceKind::Arg => AmlSerdeReferenceKind::Arg,
ReferenceKind::Index => AmlSerdeReferenceKind::Index,
ReferenceKind::Named => AmlSerdeReferenceKind::Named,
ReferenceKind::Unresolved => AmlSerdeReferenceKind::Unresolved,
},
inner: AmlSerdeValue::from_aml_value(inner.deref()).map(Box::new)?,
},
Object::Package(aml_contents) => AmlSerdeValue::Package {
contents: aml_contents
.iter()
.filter_map(|item| AmlSerdeValue::from_aml_value(item))
.collect(),
},
Object::PowerResource {
system_level,
resource_order,
} => AmlSerdeValue::PowerResource {
system_level: system_level.to_owned(),
resource_order: resource_order.to_owned(),
},
Object::RawDataBuffer => AmlSerdeValue::RawDataBuffer,
Object::ThermalZone => AmlSerdeValue::ThermalZone,
Object::Debug => AmlSerdeValue::Debug,
})
}
pub fn to_aml_object(self) -> Option<Object> {
Some(match self {
AmlSerdeValue::Uninitialized => Object::Uninitialized,
AmlSerdeValue::Integer(n) => Object::Integer(n),
AmlSerdeValue::String(s) => Object::String(s),
AmlSerdeValue::OpRegion {
region,
offset,
length,
parent_device,
} => Object::OpRegion(OpRegion {
space: match region {
AmlSerdeRegionSpace::PciConfig => RegionSpace::PciConfig,
AmlSerdeRegionSpace::EmbeddedControl => RegionSpace::EmbeddedControl,
AmlSerdeRegionSpace::SMBus => RegionSpace::SmBus,
AmlSerdeRegionSpace::SystemCmos => RegionSpace::SystemCmos,
AmlSerdeRegionSpace::PciBarTarget => RegionSpace::PciBarTarget,
AmlSerdeRegionSpace::IPMI => RegionSpace::Ipmi,
AmlSerdeRegionSpace::GeneralPurposeIo => RegionSpace::GeneralPurposeIo,
AmlSerdeRegionSpace::GenericSerialBus => RegionSpace::GenericSerialBus,
AmlSerdeRegionSpace::SystemMemory => RegionSpace::SystemMemory,
AmlSerdeRegionSpace::SystemIo => RegionSpace::SystemIO,
AmlSerdeRegionSpace::Pcc => RegionSpace::Pcc,
AmlSerdeRegionSpace::OemDefined(n) => RegionSpace::Oem(n),
},
base: offset,
length,
//
parent_device_path: AmlName::from_str(&parent_device).ok()?, // TODO: Error value hidden
}),
AmlSerdeValue::Field {
kind,
flags,
offset,
length,
} => Object::FieldUnit(FieldUnit {
kind: match kind {
AmlSerdeFieldKind::Normal { region } => FieldUnitKind::Normal {
region: region.to_aml_object()?.wrap(),
},
AmlSerdeFieldKind::Bank {
region,
bank,
bank_value,
} => FieldUnitKind::Bank {
region: region.to_aml_object()?.wrap(),
bank: bank.to_aml_object()?.wrap(),
bank_value: bank_value.to_owned(),
},
AmlSerdeFieldKind::Index { index, data } => FieldUnitKind::Index {
index: index.to_aml_object()?.wrap(),
data: data.to_aml_object()?.wrap(),
},
},
flags: FieldFlags(flags.into()),
bit_index: offset as usize,
bit_length: length as usize,
}),
AmlSerdeValue::Device => Object::Device,
AmlSerdeValue::Event(event) => Object::Event(Arc::new(AtomicU64::new(event))),
AmlSerdeValue::Method {
arg_count,
serialize,
sync_level,
} => Object::Method {
code: (return None), //TODO figure out what to do here
//TODO check specs to see if all bit patterns are allowed
flags: MethodFlags(
(arg_count as u8).clamp(0, 7)
+ (serialize as u8).shl(3)
+ sync_level.clamp(0, 15).shl(4),
),
},
//TODO: handle native method?
AmlSerdeValue::Buffer(buffer_data) => Object::Buffer(buffer_data),
AmlSerdeValue::BufferField {
data,
offset,
length,
} => Object::BufferField {
offset: offset as usize,
length: length as usize,
buffer: data.to_aml_object()?.wrap(),
},
AmlSerdeValue::Processor {
id,
pblk_address,
pblk_len,
} => Object::Processor {
proc_id: id,
pblk_address,
pblk_length: pblk_len,
},
AmlSerdeValue::Mutex { mutex, sync_level } => Object::Mutex {
mutex: Handle(mutex),
sync_level: sync_level,
},
AmlSerdeValue::Reference { kind, inner } => Object::Reference {
kind: match kind {
AmlSerdeReferenceKind::RefOf => ReferenceKind::RefOf,
AmlSerdeReferenceKind::Local => ReferenceKind::Local,
AmlSerdeReferenceKind::Arg => ReferenceKind::Arg,
AmlSerdeReferenceKind::Index => ReferenceKind::Index,
AmlSerdeReferenceKind::Named => ReferenceKind::Named,
AmlSerdeReferenceKind::Unresolved => ReferenceKind::Unresolved,
},
inner: inner.to_aml_object()?.wrap(),
},
AmlSerdeValue::Package { contents } => Object::Package(
contents
.into_iter()
.map(|item| item.to_aml_object().map(Object::wrap)) // TODO: see if errors should be ignored here
.collect::<Option<Vec<WrappedObject>>>()?,
),
AmlSerdeValue::PowerResource {
system_level,
resource_order,
} => Object::PowerResource {
system_level: system_level.to_owned(),
resource_order: resource_order.to_owned(),
},
AmlSerdeValue::RawDataBuffer => Object::RawDataBuffer,
AmlSerdeValue::ThermalZone => Object::ThermalZone,
AmlSerdeValue::Debug => Object::Debug,
})
}
}
pub mod aml_serde_name {
use acpi::aml::namespace::AmlName;
/// Add a leading backslash to make the name a valid
/// namespace reference
pub fn to_aml_format(pretty_name: &String) -> String {
format!("\\{}", pretty_name)
}
/// convert a string from AML namespace style to
/// acpi symbol style
pub fn to_symbol(aml_style_name: &String) -> String {
let mut name = aml_style_name.to_owned();
// remove leading slash
name = name.trim_start_matches("\\").to_owned();
// remove unnecessary underscores
while let Some(index) = name.find("_.") {
name.remove(index);
}
while name.len() > 0 && &name[name.len() - 1..] == "_" {
name.pop();
}
name.shrink_to_fit();
name
}
/// Convert to string and remove
/// trailing underscores from each name segment
pub fn aml_to_symbol(aml_name: &AmlName) -> String {
to_symbol(&aml_name.as_string())
}
}
-21
View File
@@ -1,21 +0,0 @@
[package]
name = "ac97d"
description = "AC'97 driver"
version = "0.1.0"
edition = "2021"
[dependencies]
common = { path = "../../common" }
libredox.workspace = true
log.workspace = true
redox_event.workspace = true
redox_syscall.workspace = true
spin.workspace = true
daemon = { path = "../../../daemon" }
pcid = { path = "../../pcid" }
redox-scheme.workspace = true
scheme-utils = { path = "../../../scheme-utils" }
[lints]
workspace = true
-5
View File
@@ -1,5 +0,0 @@
[[drivers]]
name = "AC97 Audio"
class = 0x04
subclass = 0x01
command = ["ac97d"]
-333
View File
@@ -1,333 +0,0 @@
use common::io::Pio;
use redox_scheme::scheme::SchemeSync;
use redox_scheme::CallerCtx;
use redox_scheme::OpenResult;
use scheme_utils::{FpathWriter, HandleMap};
use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT};
use syscall::schemev2::NewFdFlags;
use syscall::EWOULDBLOCK;
use common::{
dma::Dma,
io::{Io, Mmio},
};
use spin::Mutex;
const NUM_SUB_BUFFS: usize = 32;
const SUB_BUFF_SIZE: usize = 2048;
enum Handle {
Todo,
SchemeRoot,
}
#[allow(dead_code)]
struct MixerRegs {
/* 0x00 */ reset: Pio<u16>,
/* 0x02 */ master_volume: Pio<u16>,
/* 0x04 */ aux_out_volume: Pio<u16>,
/* 0x06 */ mono_volume: Pio<u16>,
/* 0x08 */ master_tone: Pio<u16>,
/* 0x0A */ pc_beep_volume: Pio<u16>,
/* 0x0C */ phone_volume: Pio<u16>,
/* 0x0E */ mic_volume: Pio<u16>,
/* 0x10 */ line_in_volume: Pio<u16>,
/* 0x12 */ cd_volume: Pio<u16>,
/* 0x14 */ video_volume: Pio<u16>,
/* 0x16 */ aux_in_volume: Pio<u16>,
/* 0x18 */ pcm_out_volume: Pio<u16>,
/* 0x1A */ record_select: Pio<u16>,
/* 0x1C */ record_gain: Pio<u16>,
/* 0x1E */ record_gain_mic: Pio<u16>,
/* 0x20 */ general_purpose: Pio<u16>,
/* 0x22 */ control_3d: Pio<u16>,
/* 0x24 */ audio_int_paging: Pio<u16>,
/* 0x26 */ powerdown: Pio<u16>,
/* 0x28 */ extended_id: Pio<u16>,
/* 0x2A */ extended_ctrl: Pio<u16>,
/* 0x2C */ vra_pcm_front: Pio<u16>,
}
impl MixerRegs {
fn new(bar0: u16) -> Self {
Self {
reset: Pio::new(bar0 + 0x00),
master_volume: Pio::new(bar0 + 0x02),
aux_out_volume: Pio::new(bar0 + 0x04),
mono_volume: Pio::new(bar0 + 0x06),
master_tone: Pio::new(bar0 + 0x08),
pc_beep_volume: Pio::new(bar0 + 0x0A),
phone_volume: Pio::new(bar0 + 0x0C),
mic_volume: Pio::new(bar0 + 0x0E),
line_in_volume: Pio::new(bar0 + 0x10),
cd_volume: Pio::new(bar0 + 0x12),
video_volume: Pio::new(bar0 + 0x14),
aux_in_volume: Pio::new(bar0 + 0x16),
pcm_out_volume: Pio::new(bar0 + 0x18),
record_select: Pio::new(bar0 + 0x1A),
record_gain: Pio::new(bar0 + 0x1C),
record_gain_mic: Pio::new(bar0 + 0x1E),
general_purpose: Pio::new(bar0 + 0x20),
control_3d: Pio::new(bar0 + 0x22),
audio_int_paging: Pio::new(bar0 + 0x24),
powerdown: Pio::new(bar0 + 0x26),
extended_id: Pio::new(bar0 + 0x28),
extended_ctrl: Pio::new(bar0 + 0x2A),
vra_pcm_front: Pio::new(bar0 + 0x2C),
}
}
}
#[allow(dead_code)]
struct BusBoxRegs {
/// Buffer descriptor list base address
/* 0x00 */
bdbar: Pio<u32>,
/// Current index value
/* 0x04 */
civ: Pio<u8>,
/// Last valid index
/* 0x05 */
lvi: Pio<u8>,
/// Status
/* 0x06 */
sr: Pio<u16>,
/// Position in current buffer
/* 0x08 */
picb: Pio<u16>,
/// Prefetched index value
/* 0x0A */
piv: Pio<u8>,
/// Control
/* 0x0B */
cr: Pio<u8>,
}
impl BusBoxRegs {
fn new(base: u16) -> Self {
Self {
bdbar: Pio::new(base + 0x00),
civ: Pio::new(base + 0x04),
lvi: Pio::new(base + 0x05),
sr: Pio::new(base + 0x06),
picb: Pio::new(base + 0x08),
piv: Pio::new(base + 0x0A),
cr: Pio::new(base + 0x0B),
}
}
}
#[allow(dead_code)]
struct BusRegs {
/// PCM in register box
/* 0x00 */
pi: BusBoxRegs,
/// PCM out register box
/* 0x10 */
po: BusBoxRegs,
/// Microphone register box
/* 0x20 */
mc: BusBoxRegs,
}
impl BusRegs {
fn new(bar1: u16) -> Self {
Self {
pi: BusBoxRegs::new(bar1 + 0x00),
po: BusBoxRegs::new(bar1 + 0x10),
mc: BusBoxRegs::new(bar1 + 0x20),
}
}
}
#[repr(C, packed)]
pub struct BufferDescriptor {
/* 0x00 */ addr: Mmio<u32>,
/* 0x04 */ samples: Mmio<u16>,
/* 0x06 */ flags: Mmio<u16>,
}
pub struct Ac97 {
mixer: MixerRegs,
bus: BusRegs,
bdl: Dma<[BufferDescriptor; NUM_SUB_BUFFS]>,
buf: Dma<[u8; NUM_SUB_BUFFS * SUB_BUFF_SIZE]>,
handles: Mutex<HandleMap<Handle>>,
}
impl Ac97 {
pub unsafe fn new(bar0: u16, bar1: u16) -> Result<Self> {
let mut module = Ac97 {
mixer: MixerRegs::new(bar0),
bus: BusRegs::new(bar1),
bdl: Dma::zeroed(
//TODO: PhysBox::new_in_32bit_space(bdl_size)?
)?
.assume_init(),
buf: Dma::zeroed(
//TODO: PhysBox::new_in_32bit_space(buf_size)?
)?
.assume_init(),
handles: Mutex::new(HandleMap::new()),
};
module.init()?;
Ok(module)
}
fn init(&mut self) -> Result<()> {
//TODO: support other sample rates, or just the default of 48000 Hz
{
// Check if VRA is supported
if !self.mixer.extended_id.readf(1 << 0) {
println!("ac97d: VRA not supported and is currently required");
return Err(Error::new(ENOENT));
}
// Enable VRA
self.mixer.extended_ctrl.writef(1 << 0, true);
// Attempt to set sample rate for PCM front to 44100 Hz
let desired_sample_rate = 44100;
self.mixer.vra_pcm_front.write(desired_sample_rate);
// Read back real sample rate
let real_sample_rate = self.mixer.vra_pcm_front.read();
println!("ac97d: set sample rate to {}", real_sample_rate);
// Error if we cannot set the sample rate as desired
if real_sample_rate != desired_sample_rate {
println!(
"ac97d: sample rate is {} but only {} is supported",
real_sample_rate, desired_sample_rate
);
return Err(Error::new(ENOENT));
}
}
// Ensure PCM out is stopped
self.bus.po.cr.writef(1, false);
// Reset PCM out
self.bus.po.cr.writef(1 << 1, true);
while self.bus.po.cr.readf(1 << 1) {
// Spinning on resetting PCM out
//TODO: relax
}
// Initialize BDL for PCM out
for i in 0..NUM_SUB_BUFFS {
self.bdl[i]
.addr
.write((self.buf.physical() + i * SUB_BUFF_SIZE) as u32);
self.bdl[i]
.samples
.write((SUB_BUFF_SIZE / 2/* Each sample is i16 or 2 bytes */) as u16);
self.bdl[i]
.flags
.write(1 << 15 /* Interrupt on completion */);
}
self.bus.po.bdbar.write(self.bdl.physical() as u32);
// Enable interrupt on completion
self.bus.po.cr.writef(1 << 4, true);
// Start bus master
self.bus.po.cr.writef(1 << 0, true);
// Set master volume to 0 db (loudest output, DANGER!)
self.mixer.master_volume.write(0);
// Set PCM output volume to 0 db (medium)
self.mixer.pcm_out_volume.write(0x808);
Ok(())
}
pub fn irq(&mut self) -> bool {
let ints = self.bus.po.sr.read() & 0b11100;
if ints != 0 {
self.bus.po.sr.write(ints);
true
} else {
false
}
}
}
impl SchemeSync for Ac97 {
fn scheme_root(&mut self) -> Result<usize> {
Ok(self.handles.lock().insert(Handle::SchemeRoot))
}
fn openat(
&mut self,
dirfd: usize,
_path: &str,
_flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
{
let handles = self.handles.lock();
let handle = handles.get(dirfd)?;
if !matches!(handle, Handle::SchemeRoot) {
return Err(Error::new(EACCES));
}
}
if ctx.uid == 0 {
let id = self.handles.lock().insert(Handle::Todo);
Ok(OpenResult::ThisScheme {
number: id,
flags: NewFdFlags::empty(),
})
} else {
Err(Error::new(EACCES))
}
}
fn write(
&mut self,
id: usize,
buf: &[u8],
_offset: u64,
_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
{
let mut handles = self.handles.lock();
let handle = handles.get_mut(id)?;
if !matches!(handle, Handle::Todo) {
return Err(Error::new(EBADF));
}
}
if buf.len() != SUB_BUFF_SIZE {
return Err(Error::new(EINVAL));
}
let civ = self.bus.po.civ.read() as usize;
let mut lvi = self.bus.po.lvi.read() as usize;
if lvi == (civ + 3) % NUM_SUB_BUFFS {
// Block if we already are 3 buffers ahead
Err(Error::new(EWOULDBLOCK))
} else {
// Fill next buffer
lvi = (lvi + 1) % NUM_SUB_BUFFS;
for i in 0..SUB_BUFF_SIZE {
self.buf[lvi * SUB_BUFF_SIZE + i] = buf[i];
}
self.bus.po.lvi.write(lvi as u8);
Ok(SUB_BUFF_SIZE)
}
}
fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
FpathWriter::with(buf, "audiohw", |_| Ok(()))
}
fn on_close(&mut self, id: usize) {
self.handles.lock().remove(id);
}
}
-135
View File
@@ -1,135 +0,0 @@
use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use std::usize;
use event::{user_data, EventQueue};
use pcid_interface::PciFunctionHandle;
use redox_scheme::scheme::register_sync_scheme;
use redox_scheme::Socket;
use scheme_utils::ReadinessBased;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub mod device;
fn main() {
pcid_interface::pci_daemon(daemon);
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
let pci_config = pcid_handle.config();
let mut name = pci_config.func.name();
name.push_str("_ac97");
let bar0 = pci_config.func.bars[0].expect_port();
let bar1 = pci_config.func.bars[1].expect_port();
let irq = pci_config
.func
.legacy_interrupt_line
.expect("ac97d: no legacy interrupts supported");
println!(" + ac97 {}", pci_config.func.display());
common::setup_logging(
"audio",
"pci",
&name,
common::output_level(),
common::file_level(),
);
common::acquire_port_io_rights().expect("ac97d: failed to set I/O privilege level to Ring 3");
let mut irq_file = irq.irq_handle("ac97d");
let socket = Socket::nonblock().expect("ac97d: failed to create socket");
let mut device =
unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") };
let mut readiness_based = ReadinessBased::new(&socket, 16);
user_data! {
enum Source {
Irq,
Scheme,
}
}
let event_queue = EventQueue::<Source>::new().expect("ac97d: Could not create event queue.");
event_queue
.subscribe(
irq_file.as_raw_fd() as usize,
Source::Irq,
event::EventFlags::READ,
)
.unwrap();
event_queue
.subscribe(
socket.inner().raw(),
Source::Scheme,
event::EventFlags::READ,
)
.unwrap();
register_sync_scheme(&socket, "audiohw", &mut device)
.expect("ac97d: failed to register audiohw scheme to namespace");
daemon.ready();
libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace");
let all = [Source::Irq, Source::Scheme];
for event in all
.into_iter()
.chain(event_queue.map(|e| e.expect("ac97d: failed to get next event").user_data))
{
match event {
Source::Irq => {
let mut irq = [0; 8];
irq_file.read(&mut irq).unwrap();
if !device.irq() {
continue;
}
irq_file.write(&mut irq).unwrap();
readiness_based
.poll_all_requests(&mut device)
.expect("ac97d: failed to poll requests");
readiness_based
.write_responses()
.expect("ac97d: failed to write to socket");
/*
let next_read = device_irq.next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
*/
}
Source::Scheme => {
readiness_based
.read_and_process_requests(&mut device)
.expect("ac97d: failed to read from socket");
readiness_based
.write_responses()
.expect("ac97d: failed to write to socket");
/*
let next_read = device.borrow().next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
*/
}
}
}
std::process::exit(0);
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn daemon(_daemon: daemon::Daemon, _pcid_handle: PciFunctionHandle) -> ! {
// AC'97 is an x86/x86_64 legacy audio bus; no other architectures are supported.
panic!("ac97d: only supported on x86 and x86_64");
}
-22
View File
@@ -1,22 +0,0 @@
[package]
name = "ihdad"
description = "Intel HD Audio chipset driver"
version = "0.1.0"
edition = "2021"
[dependencies]
bitflags.workspace = true
libredox.workspace = true
log.workspace = true
redox_event.workspace = true
redox_syscall.workspace = true
spin.workspace = true
common = { path = "../../common" }
daemon = { path = "../../../daemon" }
pcid = { path = "../../pcid" }
redox-scheme.workspace = true
scheme-utils = { path = "../../../scheme-utils" }
[lints]
workspace = true
-5
View File
@@ -1,5 +0,0 @@
[[drivers]]
name = "Intel HD Audio"
class = 0x04
subclass = 0x03
command = ["ihdad"]
-501
View File
@@ -1,501 +0,0 @@
use common::dma::Dma;
use common::io::{Io, Mmio};
use common::timeout::Timeout;
use syscall::error::{Error, Result, EIO};
use super::common::*;
// CORBCTL
const CMEIE: u8 = 1 << 0; // 1 bit
const CORBRUN: u8 = 1 << 1; // 1 bit
// CORBSIZE
const CORBSZCAP: (u8, u8) = (4, 4);
const CORBSIZE: (u8, u8) = (0, 2);
// CORBRP
const CORBRPRST: u16 = 1 << 15;
// RIRBWP
const RIRBWPRST: u16 = 1 << 15;
// RIRBCTL
const RINTCTL: u8 = 1 << 0; // 1 bit
const RIRBDMAEN: u8 = 1 << 1; // 1 bit
const CORB_OFFSET: usize = 0x00;
const RIRB_OFFSET: usize = 0x10;
const ICMD_OFFSET: usize = 0x20;
// ICS
const ICB: u16 = 1 << 0;
const IRV: u16 = 1 << 1;
// CORB and RIRB offset
const COMMAND_BUFFER_OFFSET: usize = 0x40;
const CORB_BUFF_MAX_SIZE: usize = 1024;
struct CommandBufferRegs {
corblbase: Mmio<u32>,
corbubase: Mmio<u32>,
corbwp: Mmio<u16>,
corbrp: Mmio<u16>,
corbctl: Mmio<u8>,
corbsts: Mmio<u8>,
corbsize: Mmio<u8>,
rsvd5: Mmio<u8>,
rirblbase: Mmio<u32>,
rirbubase: Mmio<u32>,
rirbwp: Mmio<u16>,
rintcnt: Mmio<u16>,
rirbctl: Mmio<u8>,
rirbsts: Mmio<u8>,
rirbsize: Mmio<u8>,
rsvd6: Mmio<u8>,
}
struct CorbRegs {
corblbase: Mmio<u32>,
corbubase: Mmio<u32>,
corbwp: Mmio<u16>,
corbrp: Mmio<u16>,
corbctl: Mmio<u8>,
corbsts: Mmio<u8>,
corbsize: Mmio<u8>,
rsvd5: Mmio<u8>,
}
struct Corb {
regs: &'static mut CorbRegs,
corb_base: *mut u32,
corb_base_phys: usize,
corb_count: usize,
}
impl Corb {
pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: *mut u32) -> Corb {
unsafe {
Corb {
regs: &mut *(regs_addr as *mut CorbRegs),
corb_base: corb_buff_virt,
corb_base_phys: corb_buff_phys,
corb_count: 0,
}
}
}
//Intel 4.4.1.3
pub fn init(&mut self) -> Result<()> {
self.stop()?;
//Determine CORB and RIRB size and allocate buffer
//3.3.24
let corbsize_reg = self.regs.corbsize.read();
let corbszcap = (corbsize_reg >> 4) & 0xF;
let mut corbsize_bytes: usize = 0;
let mut corbsize: u8 = 0;
if (corbszcap & 4) == 4 {
corbsize = 2;
corbsize_bytes = 1024;
self.corb_count = 256;
} else if (corbszcap & 2) == 2 {
corbsize = 1;
corbsize_bytes = 64;
self.corb_count = 16;
} else if (corbszcap & 1) == 1 {
corbsize = 0;
corbsize_bytes = 8;
self.corb_count = 2;
}
assert!(self.corb_count != 0);
let addr = self.corb_base_phys;
self.set_address(addr);
self.regs.corbsize.write((corbsize_reg & 0xFC) | corbsize);
self.reset_read_pointer()?;
let old_wp = self.regs.corbwp.read();
self.regs.corbwp.write(old_wp & 0xFF00);
Ok(())
}
pub fn start(&mut self) {
self.regs.corbctl.writef(CORBRUN, true);
}
#[inline(never)]
pub fn stop(&mut self) -> Result<()> {
let timeout = Timeout::from_secs(1);
while self.regs.corbctl.readf(CORBRUN) {
self.regs.corbctl.writef(CORBRUN, false);
timeout.run().map_err(|()| {
log::error!("timeout on clearing CORBRUN");
Error::new(EIO)
})?;
}
Ok(())
}
pub fn set_address(&mut self, addr: usize) {
self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32);
self.regs.corbubase.write(((addr as u64) >> 32) as u32);
}
pub fn reset_read_pointer(&mut self) -> Result<()> {
// 3.3.21
self.stop()?;
// Set CORBRPRST to 1
log::trace!("CORBRP {:X}", self.regs.corbrp.read());
self.regs.corbrp.writef(CORBRPRST, true);
log::trace!("CORBRP {:X}", self.regs.corbrp.read());
{
// Wait for it to become 1
let timeout = Timeout::from_secs(1);
while !self.regs.corbrp.readf(CORBRPRST) {
self.regs.corbrp.writef(CORBRPRST, true);
timeout.run().map_err(|()| {
log::error!("timeout on setting CORBRPRST");
Error::new(EIO)
})?;
}
}
// Clear the bit again
self.regs.corbrp.writef(CORBRPRST, false);
{
// Read back the bit until zero to verify that it is cleared.
let timeout = Timeout::from_secs(1);
loop {
if !self.regs.corbrp.readf(CORBRPRST) {
break;
}
self.regs.corbrp.writef(CORBRPRST, false);
timeout.run().map_err(|()| {
log::error!("timeout on clearing CORBRPRST");
Error::new(EIO)
})?;
}
}
Ok(())
}
fn send_command(&mut self, cmd: u32) -> Result<()> {
{
// wait for the commands to finish
let timeout = Timeout::from_secs(1);
while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {
timeout.run().map_err(|()| {
log::error!("timeout on CORB command");
Error::new(EIO)
})?;
}
}
let write_pos: usize = ((self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count;
unsafe {
*self.corb_base.offset(write_pos as isize) = cmd;
}
self.regs.corbwp.write(write_pos as u16);
log::trace!("Corb: {:08X}", cmd);
Ok(())
}
}
struct RirbRegs {
rirblbase: Mmio<u32>,
rirbubase: Mmio<u32>,
rirbwp: Mmio<u16>,
rintcnt: Mmio<u16>,
rirbctl: Mmio<u8>,
rirbsts: Mmio<u8>,
rirbsize: Mmio<u8>,
rsvd6: Mmio<u8>,
}
struct Rirb {
regs: &'static mut RirbRegs,
rirb_base: *mut u64,
rirb_base_phys: usize,
rirb_rp: u16,
rirb_count: usize,
}
impl Rirb {
pub fn new(regs_addr: usize, rirb_buff_phys: usize, rirb_buff_virt: *mut u64) -> Rirb {
unsafe {
Rirb {
regs: &mut *(regs_addr as *mut RirbRegs),
rirb_base: rirb_buff_virt,
rirb_rp: 0,
rirb_base_phys: rirb_buff_phys,
rirb_count: 0,
}
}
}
//Intel 4.4.1.3
pub fn init(&mut self) -> Result<()> {
self.stop()?;
let rirbsize_reg = self.regs.rirbsize.read();
let rirbszcap = (rirbsize_reg >> 4) & 0xF;
let mut rirbsize_bytes: usize = 0;
let mut rirbsize: u8 = 0;
if (rirbszcap & 4) == 4 {
rirbsize = 2;
rirbsize_bytes = 2048;
self.rirb_count = 256;
} else if (rirbszcap & 2) == 2 {
rirbsize = 1;
rirbsize_bytes = 128;
self.rirb_count = 8;
} else if (rirbszcap & 1) == 1 {
rirbsize = 0;
rirbsize_bytes = 16;
self.rirb_count = 2;
}
assert!(self.rirb_count != 0);
let addr = self.rirb_base_phys;
self.set_address(addr);
self.reset_write_pointer();
self.rirb_rp = 0;
self.regs.rintcnt.write(1);
Ok(())
}
pub fn start(&mut self) {
self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL, true);
}
pub fn stop(&mut self) -> Result<()> {
let timeout = Timeout::from_secs(1);
while self.regs.rirbctl.readf(RIRBDMAEN) {
self.regs.rirbctl.writef(RIRBDMAEN, false);
timeout.run().map_err(|()| {
log::error!("timeout on clearing RIRBDMAEN");
Error::new(EIO)
})?;
}
Ok(())
}
pub fn set_address(&mut self, addr: usize) {
self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32);
self.regs.rirbubase.write(((addr as u64) >> 32) as u32);
}
pub fn reset_write_pointer(&mut self) {
self.regs.rirbwp.writef(RIRBWPRST, true);
}
fn read_response(&mut self) -> Result<u64> {
{
// wait for response
let timeout = Timeout::from_secs(1);
while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {
timeout.run().map_err(|()| {
log::error!("timeout on RIRB response");
Error::new(EIO)
})?;
}
}
let read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16;
let res: u64;
unsafe {
res = *self.rirb_base.offset(read_pos as isize);
}
self.rirb_rp = read_pos;
log::trace!("Rirb: {:08X}", res);
Ok(res)
}
}
struct ImmediateCommandRegs {
icoi: Mmio<u32>,
irii: Mmio<u32>,
ics: Mmio<u16>,
rsvd7: [Mmio<u8>; 6],
}
pub struct ImmediateCommand {
regs: &'static mut ImmediateCommandRegs,
}
impl ImmediateCommand {
pub fn new(regs_addr: usize) -> ImmediateCommand {
unsafe {
ImmediateCommand {
regs: &mut *(regs_addr as *mut ImmediateCommandRegs),
}
}
}
pub fn cmd(&mut self, cmd: u32) -> Result<u64> {
{
// wait for ready
let timeout = Timeout::from_secs(1);
while self.regs.ics.readf(ICB) {
timeout.run().map_err(|()| {
log::error!("timeout on immediate command");
Error::new(EIO)
})?;
}
}
// write command
self.regs.icoi.write(cmd);
// set ICB bit to send command
self.regs.ics.writef(ICB, true);
{
// wait for IRV bit to be set to indicate a response is latched
let timeout = Timeout::from_secs(1);
while !self.regs.ics.readf(IRV) {
timeout.run().map_err(|()| {
log::error!("timeout on immediate response");
Error::new(EIO)
})?;
}
}
// read the result register twice, total of 8 bytes
// highest 4 will most likely be zeros (so I've heard)
let mut res: u64 = self.regs.irii.read() as u64;
res |= (self.regs.irii.read() as u64) << 32;
// clear the bit so we know when the next response comes
self.regs.ics.writef(IRV, false);
Ok(res)
}
}
pub struct CommandBuffer {
// regs: &'static mut CommandBufferRegs,
corb: Corb,
rirb: Rirb,
icmd: ImmediateCommand,
use_immediate_cmd: bool,
mem: Dma<[u8; 0x1000]>,
}
impl CommandBuffer {
pub fn new(regs_addr: usize, mut cmd_buff: Dma<[u8; 0x1000]>) -> CommandBuffer {
let corb = Corb::new(
regs_addr + CORB_OFFSET,
cmd_buff.physical(),
cmd_buff.as_mut_ptr().cast(),
);
let rirb = Rirb::new(
regs_addr + RIRB_OFFSET,
cmd_buff.physical() + CORB_BUFF_MAX_SIZE,
cmd_buff
.as_mut_ptr()
.cast::<u8>()
.wrapping_add(CORB_BUFF_MAX_SIZE)
.cast(),
);
let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET);
let cmdbuff = CommandBuffer {
corb,
rirb,
icmd,
use_immediate_cmd: false,
mem: cmd_buff,
};
cmdbuff
}
pub fn init(&mut self, use_imm_cmds: bool) -> Result<()> {
self.corb.init()?;
self.rirb.init()?;
self.set_use_imm_cmds(use_imm_cmds)?;
Ok(())
}
pub fn stop(&mut self) -> Result<()> {
self.corb.stop()?;
self.rirb.stop()?;
Ok(())
}
pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> Result<u64> {
let mut ncmd: u32 = 0;
ncmd |= (addr.0 as u32 & 0x00F) << 28;
ncmd |= (addr.1 as u32 & 0x0FF) << 20;
ncmd |= (command & 0xFFF) << 8;
ncmd |= (data as u32 & 0x0FF) << 0;
self.cmd(ncmd)
}
pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> Result<u64> {
let mut ncmd: u32 = 0;
ncmd |= (addr.0 as u32 & 0x000F) << 28;
ncmd |= (addr.1 as u32 & 0x00FF) << 20;
ncmd |= (command & 0x000F) << 16;
ncmd |= (data as u32 & 0xFFFF) << 0;
self.cmd(ncmd)
}
pub fn cmd(&mut self, cmd: u32) -> Result<u64> {
if self.use_immediate_cmd {
self.cmd_imm(cmd)
} else {
self.cmd_buff(cmd)
}
}
pub fn cmd_imm(&mut self, cmd: u32) -> Result<u64> {
self.icmd.cmd(cmd)
}
pub fn cmd_buff(&mut self, cmd: u32) -> Result<u64> {
self.corb.send_command(cmd)?;
self.rirb.read_response()
}
pub fn set_use_imm_cmds(&mut self, use_imm: bool) -> Result<()> {
self.use_immediate_cmd = use_imm;
if self.use_immediate_cmd {
self.corb.stop()?;
self.rirb.stop()?;
} else {
self.corb.start();
self.rirb.start();
}
Ok(())
}
}
-195
View File
@@ -1,195 +0,0 @@
use std::fmt;
use std::mem::transmute;
pub type HDANodeAddr = u16;
pub type HDACodecAddr = u8;
pub type NodeAddr = u16;
pub type CodecAddr = u8;
pub type WidgetAddr = (CodecAddr, NodeAddr);
/*
impl fmt::Display for WidgetAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:01X}:{:02X}\n", self.0, self.1)
}
}*/
#[derive(Debug, PartialEq)]
#[repr(u8)]
pub enum HDAWidgetType {
AudioOutput = 0x0,
AudioInput = 0x1,
AudioMixer = 0x2,
AudioSelector = 0x3,
PinComplex = 0x4,
Power = 0x5,
VolumeKnob = 0x6,
BeepGenerator = 0x7,
VendorDefined = 0xf,
}
impl fmt::Display for HDAWidgetType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
#[derive(Debug, PartialEq)]
#[repr(u8)]
pub enum DefaultDevice {
LineOut = 0x0,
Speaker = 0x1,
HPOut = 0x2,
CD = 0x3,
SPDIF = 0x4,
DigitalOtherOut = 0x5,
ModemLineSide = 0x6,
ModemHandsetSide = 0x7,
LineIn = 0x8,
AUX = 0x9,
MicIn = 0xA,
Telephony = 0xB,
SPDIFIn = 0xC,
DigitalOtherIn = 0xD,
Reserved = 0xE,
Other = 0xF,
}
#[derive(Debug)]
#[repr(u8)]
pub enum PortConnectivity {
ConnectedToJack = 0x0,
NoPhysicalConnection = 0x1,
FixedFunction = 0x2,
JackAndInternal = 0x3,
}
#[derive(Debug)]
#[repr(u8)]
pub enum GrossLocation {
ExternalOnPrimary = 0x0,
Internal = 0x1,
SeperateChasis = 0x2,
Other = 0x3,
}
#[derive(Debug)]
#[repr(u8)]
pub enum GeometricLocation {
NA = 0x0,
Rear = 0x1,
Front = 0x2,
Left = 0x3,
Right = 0x4,
Top = 0x5,
Bottom = 0x6,
Special1 = 0x7,
Special2 = 0x8,
Special3 = 0x9,
Resvd1 = 0xA,
Resvd2 = 0xB,
Resvd3 = 0xC,
Resvd4 = 0xD,
Resvd5 = 0xE,
Resvd6 = 0xF,
}
#[derive(Debug)]
#[repr(u8)]
pub enum Color {
Unknown = 0x0,
Black = 0x1,
Grey = 0x2,
Blue = 0x3,
Green = 0x4,
Red = 0x5,
Orange = 0x6,
Yellow = 0x7,
Purple = 0x8,
Pink = 0x9,
Resvd1 = 0xA,
Resvd2 = 0xB,
Resvd3 = 0xC,
Resvd4 = 0xD,
White = 0xE,
Other = 0xF,
}
pub struct ConfigurationDefault {
value: u32,
}
impl ConfigurationDefault {
pub fn from_u32(value: u32) -> ConfigurationDefault {
ConfigurationDefault { value: value }
}
pub fn color(&self) -> Color {
unsafe { transmute(((self.value >> 12) & 0xF) as u8) }
}
pub fn default_device(&self) -> DefaultDevice {
unsafe { transmute(((self.value >> 20) & 0xF) as u8) }
}
pub fn port_connectivity(&self) -> PortConnectivity {
unsafe { transmute(((self.value >> 30) & 0x3) as u8) }
}
pub fn gross_location(&self) -> GrossLocation {
unsafe { transmute(((self.value >> 28) & 0x3) as u8) }
}
pub fn geometric_location(&self) -> GeometricLocation {
unsafe { transmute(((self.value >> 24) & 0x7) as u8) }
}
pub fn is_output(&self) -> bool {
match self.default_device() {
DefaultDevice::LineOut
| DefaultDevice::Speaker
| DefaultDevice::HPOut
| DefaultDevice::CD
| DefaultDevice::SPDIF
| DefaultDevice::DigitalOtherOut
| DefaultDevice::ModemLineSide => true,
_ => false,
}
}
pub fn is_input(&self) -> bool {
match self.default_device() {
DefaultDevice::ModemHandsetSide
| DefaultDevice::LineIn
| DefaultDevice::AUX
| DefaultDevice::MicIn
| DefaultDevice::Telephony
| DefaultDevice::SPDIFIn
| DefaultDevice::DigitalOtherIn => true,
_ => false,
}
}
pub fn sequence(&self) -> u8 {
(self.value & 0xF) as u8
}
pub fn default_association(&self) -> u8 {
((self.value >> 4) & 0xF) as u8
}
}
impl fmt::Display for ConfigurationDefault {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{:?} {:?} {:?} {:?}",
self.default_device(),
self.color(),
self.gross_location(),
self.geometric_location()
)
}
}
File diff suppressed because it is too large Load Diff
-17
View File
@@ -1,17 +0,0 @@
#![allow(dead_code)]
pub mod cmdbuff;
pub mod common;
pub mod device;
pub mod node;
pub mod stream;
pub mod verbs;
pub use self::node::*;
pub use self::stream::*;
pub use self::cmdbuff::*;
pub use self::device::IntelHDA;
pub use self::stream::BitsPerSample;
pub use self::stream::BufferDescriptorListEntry;
pub use self::stream::StreamBuffer;
pub use self::stream::StreamDescriptorRegs;
-108
View File
@@ -1,108 +0,0 @@
use super::common::*;
use std::{fmt, mem};
#[derive(Clone)]
pub struct HDANode {
pub addr: WidgetAddr,
// 0x4
pub subnode_count: u16,
pub subnode_start: u16,
// 0x5
pub function_group_type: u8,
// 0x9
pub capabilities: u32,
// 0xE
pub conn_list_len: u8,
pub connections: Vec<WidgetAddr>,
pub connection_default: u8,
pub is_widget: bool,
pub config_default: u32,
}
impl HDANode {
pub fn new() -> HDANode {
HDANode {
addr: (0, 0),
subnode_count: 0,
subnode_start: 0,
function_group_type: 0,
capabilities: 0,
conn_list_len: 0,
config_default: 0,
is_widget: false,
connections: Vec::<WidgetAddr>::new(),
connection_default: 0,
}
}
pub fn widget_type(&self) -> HDAWidgetType {
unsafe { mem::transmute(((self.capabilities >> 20) & 0xF) as u8) }
}
pub fn device_default(&self) -> Option<DefaultDevice> {
if self.widget_type() != HDAWidgetType::PinComplex {
None
} else {
Some(unsafe { mem::transmute(((self.config_default >> 20) & 0xF) as u8) })
}
}
pub fn configuration_default(&self) -> ConfigurationDefault {
ConfigurationDefault::from_u32(self.config_default)
}
pub fn addr(&self) -> WidgetAddr {
self.addr
}
}
impl fmt::Display for HDANode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.addr == (0, 0) {
write!(
f,
"Addr: {:02X}:{:02X}, Root Node.",
self.addr.0, self.addr.1
)
} else if self.is_widget {
match self.widget_type() {
HDAWidgetType::PinComplex => write!(
f,
"Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {}/{}: {:X?}.",
self.addr.0,
self.addr.1,
self.widget_type(),
self.device_default().unwrap(),
self.connection_default,
self.conn_list_len,
self.connections
),
_ => write!(
f,
"Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {}/{}: {:X?}.",
self.addr.0,
self.addr.1,
self.widget_type(),
self.connection_default,
self.conn_list_len,
self.connections
),
}
} else {
write!(
f,
"Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.",
self.addr.0, self.addr.1, self.function_group_type, self.subnode_count
)
}
}
}
-387
View File
@@ -1,387 +0,0 @@
use common::dma::Dma;
use common::io::{Io, Mmio};
use std::cmp::min;
use std::ptr::copy_nonoverlapping;
use std::result;
use syscall::error::{Error, Result, EIO};
use syscall::PAGE_SIZE;
extern crate syscall;
pub enum BaseRate {
BR44_1,
BR48,
}
pub struct SampleRate {
base: BaseRate,
mult: u16,
div: u16,
}
use self::BaseRate::{BR44_1, BR48};
pub const SR_8: SampleRate = SampleRate {
base: BR48,
mult: 1,
div: 6,
};
pub const SR_11_025: SampleRate = SampleRate {
base: BR44_1,
mult: 1,
div: 4,
};
pub const SR_16: SampleRate = SampleRate {
base: BR48,
mult: 1,
div: 3,
};
pub const SR_22_05: SampleRate = SampleRate {
base: BR44_1,
mult: 1,
div: 2,
};
pub const SR_32: SampleRate = SampleRate {
base: BR48,
mult: 2,
div: 3,
};
pub const SR_44_1: SampleRate = SampleRate {
base: BR44_1,
mult: 1,
div: 1,
};
pub const SR_48: SampleRate = SampleRate {
base: BR48,
mult: 1,
div: 1,
};
pub const SR_88_1: SampleRate = SampleRate {
base: BR44_1,
mult: 2,
div: 1,
};
pub const SR_96: SampleRate = SampleRate {
base: BR48,
mult: 2,
div: 1,
};
pub const SR_176_4: SampleRate = SampleRate {
base: BR44_1,
mult: 4,
div: 1,
};
pub const SR_192: SampleRate = SampleRate {
base: BR48,
mult: 4,
div: 1,
};
#[repr(u8)]
pub enum BitsPerSample {
Bits8 = 0,
Bits16 = 1,
Bits20 = 2,
Bits24 = 3,
Bits32 = 4,
}
pub fn format_to_u16(sr: &SampleRate, bps: BitsPerSample, channels: u8) -> u16 {
// 3.3.41
let base: u16 = match sr.base {
BaseRate::BR44_1 => 1 << 14,
BaseRate::BR48 => 0,
};
let mult = ((sr.mult - 1) & 0x7) << 11;
let div = ((sr.div - 1) & 0x7) << 8;
let bits = (bps as u16) << 4;
let chan = ((channels - 1) & 0xF) as u16;
let val: u16 = base | mult | div | bits | chan;
val
}
#[repr(C, packed)]
pub struct StreamDescriptorRegs {
ctrl_lo: Mmio<u16>,
ctrl_hi: Mmio<u8>,
status: Mmio<u8>,
link_pos: Mmio<u32>,
buff_length: Mmio<u32>,
last_valid_index: Mmio<u16>,
resv1: Mmio<u16>,
fifo_size_: Mmio<u16>,
format: Mmio<u16>,
resv2: Mmio<u32>,
buff_desc_list_lo: Mmio<u32>,
buff_desc_list_hi: Mmio<u32>,
}
impl StreamDescriptorRegs {
pub fn status(&self) -> u8 {
self.status.read()
}
pub fn set_status(&mut self, status: u8) {
self.status.write(status);
}
pub fn control(&self) -> u32 {
let mut ctrl = self.ctrl_lo.read() as u32;
ctrl |= (self.ctrl_hi.read() as u32) << 16;
ctrl
}
pub fn set_control(&mut self, control: u32) {
self.ctrl_lo.write((control & 0xFFFF) as u16);
self.ctrl_hi.write(((control >> 16) & 0xFF) as u8);
}
pub fn set_pcm_format(&mut self, sr: &SampleRate, bps: BitsPerSample, channels: u8) {
// 3.3.41
let val = format_to_u16(sr, bps, channels);
self.format.write(val);
}
pub fn fifo_size(&self) -> u16 {
self.fifo_size_.read()
}
pub fn set_cyclic_buffer_length(&mut self, length: u32) {
self.buff_length.write(length);
}
pub fn cyclic_buffer_length(&self) -> u32 {
self.buff_length.read()
}
pub fn run(&mut self) {
let val = self.control() | (1 << 1);
self.set_control(val);
}
pub fn stop(&mut self) {
let val = self.control() & !(1 << 1);
self.set_control(val);
}
pub fn stream_number(&self) -> u8 {
((self.control() >> 20) & 0xF) as u8
}
pub fn set_stream_number(&mut self, stream_number: u8) {
let val = (self.control() & 0x00FFFF) | (((stream_number & 0xF) as u32) << 20);
self.set_control(val);
}
pub fn set_address(&mut self, addr: usize) {
self.buff_desc_list_lo.write((addr & 0xFFFFFFFF) as u32);
self.buff_desc_list_hi
.write((((addr as u64) >> 32) & 0xFFFFFFFF) as u32);
}
pub fn set_last_valid_index(&mut self, index: u16) {
self.last_valid_index.write(index);
}
pub fn link_position(&self) -> u32 {
self.link_pos.read()
}
pub fn set_interrupt_on_completion(&mut self, enable: bool) {
let mut ctrl = self.control();
if enable {
ctrl |= 1 << 2;
} else {
ctrl &= !(1 << 2);
}
self.set_control(ctrl);
}
pub fn buffer_complete(&self) -> bool {
self.status.readf(1 << 2)
}
pub fn clear_interrupts(&mut self) {
self.status.write(0x7 << 2);
}
// get sample size in bytes
pub fn sample_size(&self) -> usize {
let format = self.format.read();
let chan = (format & 0xF) as usize;
let bits = ((format >> 4) & 0xF) as usize;
match bits {
0 => 1 * (chan + 1),
1 => 2 * (chan + 1),
_ => 4 * (chan + 1),
}
}
}
pub struct OutputStream {
buff: StreamBuffer,
desc_regs: &'static mut StreamDescriptorRegs,
}
impl OutputStream {
pub fn new(
block_count: usize,
block_length: usize,
regs: &'static mut StreamDescriptorRegs,
) -> OutputStream {
OutputStream {
buff: StreamBuffer::new(block_length, block_count).unwrap(),
desc_regs: regs,
}
}
pub fn write_block(&mut self, buf: &[u8]) -> Result<usize> {
self.buff.write_block(buf)
}
pub fn block_size(&self) -> usize {
self.buff.block_size()
}
pub fn block_count(&self) -> usize {
self.buff.block_count()
}
pub fn current_block(&self) -> usize {
self.buff.current_block()
}
pub fn addr(&self) -> usize {
self.buff.addr()
}
pub fn phys(&self) -> usize {
self.buff.phys()
}
}
#[repr(C, packed)]
pub struct BufferDescriptorListEntry {
addr_low: Mmio<u32>,
addr_high: Mmio<u32>,
len: Mmio<u32>,
ioc_resv: Mmio<u32>,
}
impl BufferDescriptorListEntry {
pub fn address(&self) -> u64 {
(self.addr_low.read() as u64) | ((self.addr_high.read() as u64) << 32)
}
pub fn set_address(&mut self, addr: u64) {
self.addr_low.write(addr as u32);
self.addr_high.write((addr >> 32) as u32);
}
pub fn length(&self) -> u32 {
self.len.read()
}
pub fn set_length(&mut self, length: u32) {
self.len.write(length)
}
pub fn interrupt_on_completion(&self) -> bool {
(self.ioc_resv.read() & 0x1) == 0x1
}
pub fn set_interrupt_on_complete(&mut self, ioc: bool) {
self.ioc_resv.writef(1, ioc);
}
}
pub struct StreamBuffer {
mem: Dma<[u8]>,
block_cnt: usize,
block_len: usize,
cur_pos: usize,
}
impl StreamBuffer {
pub fn new(
block_length: usize,
block_count: usize,
) -> result::Result<StreamBuffer, &'static str> {
let page_aligned_size = (block_length * block_count).next_multiple_of(PAGE_SIZE);
let mem = unsafe {
Dma::zeroed_slice(page_aligned_size)
.map_err(|_| "Could not allocate physical memory for buffer.")?
.assume_init()
};
Ok(StreamBuffer {
mem,
block_len: block_length,
block_cnt: block_count,
cur_pos: 0,
})
}
pub fn length(&self) -> usize {
self.block_len * self.block_cnt
}
pub fn addr(&self) -> usize {
self.mem.as_ptr() as usize
}
pub fn phys(&self) -> usize {
self.mem.physical()
}
pub fn block_size(&self) -> usize {
self.block_len
}
pub fn block_count(&self) -> usize {
self.block_cnt
}
pub fn current_block(&self) -> usize {
self.cur_pos
}
pub fn write_block(&mut self, buf: &[u8]) -> Result<usize> {
if buf.len() != self.block_size() {
return Err(Error::new(EIO));
}
let len = min(self.block_size(), buf.len());
//log::trace!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}", self.phys(), self.addr(), self.current_block() * self.block_size(), len);
unsafe {
copy_nonoverlapping(
buf.as_ptr(),
(self.addr() + self.current_block() * self.block_size()) as *mut u8,
len,
);
}
self.cur_pos += 1;
self.cur_pos %= self.block_count();
Ok(len)
}
}
impl Drop for StreamBuffer {
fn drop(&mut self) {
log::debug!("IHDA: Deallocating buffer.");
}
}
-206
View File
@@ -1,206 +0,0 @@
// HDA verb and parameter constants — ported from Linux 7.1 include/sound/hda_verbs.h.
// The hda_verbs.h header defines the HDA specification's verb IDs, parameter IDs,
// and capability bitfields for codec communication via CORB/RIRB.
// ---- Widget types (hda_verbs.h:25) ----
pub const AC_WID_AUD_OUT: u8 = 0x00;
pub const AC_WID_AUD_IN: u8 = 0x01;
pub const AC_WID_AUD_MIX: u8 = 0x02;
pub const AC_WID_AUD_SEL: u8 = 0x03;
pub const AC_WID_PIN: u8 = 0x04;
pub const AC_WID_POWER: u8 = 0x05;
pub const AC_WID_VOL_KNB: u8 = 0x06;
pub const AC_WID_BEEP: u8 = 0x07;
pub const AC_WID_VENDOR: u8 = 0x0f;
// ---- GET verbs (hda_verbs.h:40-84) ----
pub const AC_VERB_GET_STREAM_FORMAT: u32 = 0x0a00;
pub const AC_VERB_GET_AMP_GAIN_MUTE: u32 = 0x0b00;
pub const AC_VERB_GET_PROC_COEF: u32 = 0x0c00;
pub const AC_VERB_GET_COEF_INDEX: u32 = 0x0d00;
pub const AC_VERB_PARAMETERS: u32 = 0x0f00;
pub const AC_VERB_GET_CONNECT_SEL: u32 = 0x0f01;
pub const AC_VERB_GET_CONNECT_LIST: u32 = 0x0f02;
pub const AC_VERB_GET_PROC_STATE: u32 = 0x0f03;
pub const AC_VERB_GET_SDI_SELECT: u32 = 0x0f04;
pub const AC_VERB_GET_POWER_STATE: u32 = 0x0f05;
pub const AC_VERB_GET_CONV: u32 = 0x0f06;
pub const AC_VERB_GET_PIN_WIDGET_CONTROL: u32 = 0x0f07;
pub const AC_VERB_GET_UNSOLICITED_RESPONSE: u32 = 0x0f08;
pub const AC_VERB_GET_PIN_SENSE: u32 = 0x0f09;
pub const AC_VERB_GET_BEEP_CONTROL: u32 = 0x0f0a;
pub const AC_VERB_GET_EAPD_BTLENABLE: u32 = 0x0f0c;
pub const AC_VERB_GET_DIGI_CONVERT_1: u32 = 0x0f0d;
pub const AC_VERB_GET_VOLUME_KNOB_CONTROL: u32 = 0x0f0f;
pub const AC_VERB_GET_CONFIG_DEFAULT: u32 = 0x0f1c;
pub const AC_VERB_GET_SUBSYSTEM_ID: u32 = 0x0f20;
pub const AC_VERB_GET_STRIPE_CONTROL: u32 = 0x0f24;
pub const AC_VERB_GET_CVT_CHAN_COUNT: u32 = 0x0f2d;
pub const AC_VERB_GET_HDMI_DIP_SIZE: u32 = 0x0f2e;
pub const AC_VERB_GET_HDMI_ELDD: u32 = 0x0f2f;
pub const AC_VERB_GET_DEVICE_SEL: u32 = 0x0f35;
pub const AC_VERB_GET_DEVICE_LIST: u32 = 0x0f36;
// ---- SET verbs (hda_verbs.h:89-131) ----
pub const AC_VERB_SET_STREAM_FORMAT: u32 = 0x200;
pub const AC_VERB_SET_AMP_GAIN_MUTE: u32 = 0x300;
pub const AC_VERB_SET_PROC_COEF: u32 = 0x400;
pub const AC_VERB_SET_COEF_INDEX: u32 = 0x500;
pub const AC_VERB_SET_CONNECT_SEL: u32 = 0x701;
pub const AC_VERB_SET_PROC_STATE: u32 = 0x703;
pub const AC_VERB_SET_SDI_SELECT: u32 = 0x704;
pub const AC_VERB_SET_POWER_STATE: u32 = 0x705;
pub const AC_VERB_SET_CHANNEL_STREAMID: u32 = 0x706;
pub const AC_VERB_SET_PIN_WIDGET_CONTROL: u32 = 0x707;
pub const AC_VERB_SET_UNSOLICITED_ENABLE: u32 = 0x708;
pub const AC_VERB_SET_PIN_SENSE: u32 = 0x709;
pub const AC_VERB_SET_BEEP_CONTROL: u32 = 0x70a;
pub const AC_VERB_SET_EAPD_BTLENABLE: u32 = 0x70c;
pub const AC_VERB_SET_DIGI_CONVERT_1: u32 = 0x70d;
pub const AC_VERB_SET_DIGI_CONVERT_2: u32 = 0x70e;
pub const AC_VERB_SET_VOLUME_KNOB_CONTROL: u32 = 0x70f;
pub const AC_VERB_SET_CONFIG_DEFAULT_BYTES_0: u32 = 0x71c;
pub const AC_VERB_SET_CONFIG_DEFAULT_BYTES_1: u32 = 0x71d;
pub const AC_VERB_SET_CONFIG_DEFAULT_BYTES_2: u32 = 0x71e;
pub const AC_VERB_SET_CONFIG_DEFAULT_BYTES_3: u32 = 0x71f;
pub const AC_VERB_SET_EAPD: u32 = 0x788;
pub const AC_VERB_SET_CODEC_RESET: u32 = 0x7ff;
pub const AC_VERB_SET_STRIPE_CONTROL: u32 = 0x724;
pub const AC_VERB_SET_CVT_CHAN_COUNT: u32 = 0x72d;
// ---- Parameter IDs for AC_VERB_PARAMETERS (hda_verbs.h:136-154) ----
pub const AC_PAR_VENDOR_ID: u8 = 0x00;
pub const AC_PAR_SUBSYSTEM_ID: u8 = 0x01;
pub const AC_PAR_REV_ID: u8 = 0x02;
pub const AC_PAR_NODE_COUNT: u8 = 0x04;
pub const AC_PAR_FUNCTION_TYPE: u8 = 0x05;
pub const AC_PAR_AUDIO_FG_CAP: u8 = 0x08;
pub const AC_PAR_AUDIO_WIDGET_CAP: u8 = 0x09;
pub const AC_PAR_PCM: u8 = 0x0a;
pub const AC_PAR_STREAM: u8 = 0x0b;
pub const AC_PAR_PIN_CAP: u8 = 0x0c;
pub const AC_PAR_AMP_IN_CAP: u8 = 0x0d;
pub const AC_PAR_CONNLIST_LEN: u8 = 0x0e;
pub const AC_PAR_POWER_STATE: u8 = 0x0f;
pub const AC_PAR_PROC_CAP: u8 = 0x10;
pub const AC_PAR_GPIO_CAP: u8 = 0x11;
pub const AC_PAR_AMP_OUT_CAP: u8 = 0x12;
pub const AC_PAR_VOL_KNB_CAP: u8 = 0x13;
pub const AC_PAR_DEVLIST_LEN: u8 = 0x15;
pub const AC_PAR_HDMI_LPCM_CAP: u8 = 0x20;
// ---- Audio Widget Capabilities (hda_verbs.h:171-188) ----
pub const AC_WCAP_STEREO: u32 = 1 << 0;
pub const AC_WCAP_IN_AMP: u32 = 1 << 1;
pub const AC_WCAP_OUT_AMP: u32 = 1 << 2;
pub const AC_WCAP_AMP_OVRD: u32 = 1 << 3;
pub const AC_WCAP_FORMAT_OVRD: u32 = 1 << 4;
pub const AC_WCAP_STRIPE: u32 = 1 << 5;
pub const AC_WCAP_PROC_WID: u32 = 1 << 6;
pub const AC_WCAP_UNSOL_CAP: u32 = 1 << 7;
pub const AC_WCAP_CONN_LIST: u32 = 1 << 8;
pub const AC_WCAP_DIGITAL: u32 = 1 << 9;
pub const AC_WCAP_POWER: u32 = 1 << 10;
pub const AC_WCAP_LR_SWAP: u32 = 1 << 11;
pub const AC_WCAP_CP_CAPS: u32 = 1 << 12;
pub const AC_WCAP_CHAN_CNT_EXT: u32 = 7 << 13;
pub const AC_WCAP_DELAY: u32 = 0xf << 16;
pub const AC_WCAP_DELAY_SHIFT: u8 = 16;
pub const AC_WCAP_TYPE: u32 = 0xf << 20;
pub const AC_WCAP_TYPE_SHIFT: u8 = 20;
// ---- Pin Capabilities (hda_verbs.h:262-289) ----
pub const AC_PINCAP_IMP_SENSE: u32 = 1 << 0;
pub const AC_PINCAP_TRIG_REQ: u32 = 1 << 1;
pub const AC_PINCAP_PRES_DETECT: u32 = 1 << 2;
pub const AC_PINCAP_HP_DRV: u32 = 1 << 3;
pub const AC_PINCAP_OUT: u32 = 1 << 4;
pub const AC_PINCAP_IN: u32 = 1 << 5;
pub const AC_PINCAP_BALANCE: u32 = 1 << 6;
pub const AC_PINCAP_HDMI: u32 = 1 << 7;
pub const AC_PINCAP_DP: u32 = 1 << 24;
pub const AC_PINCAP_VREF: u32 = 0x37 << 8;
pub const AC_PINCAP_VREF_SHIFT: u8 = 8;
pub const AC_PINCAP_EAPD: u32 = 1 << 16;
pub const AC_PINCAP_HBR: u32 = 1 << 27;
// ---- Pin Widget Control (hda_verbs.h:400-411) ----
pub const AC_PINCTL_EPT: u32 = 0x3;
pub const AC_PINCTL_EPT_NATIVE: u8 = 0;
pub const AC_PINCTL_EPT_HBR: u8 = 3;
pub const AC_PINCTL_IN_EN: u8 = 1 << 5;
pub const AC_PINCTL_OUT_EN: u8 = 1 << 6;
pub const AC_PINCTL_HP_EN: u8 = 1 << 7;
// ---- Pin Sense (hda_verbs.h:414-416) ----
pub const AC_PINSENSE_IMPEDANCE_MASK: u32 = 0x7fff_ffff;
pub const AC_PINSENSE_PRESENCE: u32 = 1 << 31;
pub const AC_PINSENSE_ELDV: u32 = 1 << 30;
// ---- Power State (hda_verbs.h:311-330) ----
pub const AC_PWRST_D0SUP: u32 = 1 << 0;
pub const AC_PWRST_D1SUP: u32 = 1 << 1;
pub const AC_PWRST_D2SUP: u32 = 1 << 2;
pub const AC_PWRST_D3SUP: u32 = 1 << 3;
pub const AC_PWRST_D3COLDSUP: u32 = 1 << 4;
pub const AC_PWRST_S3D3COLDSUP: u32 = 1 << 29;
pub const AC_PWRST_CLKSTOP: u32 = 1 << 30;
pub const AC_PWRST_EPSS: u32 = 1 << 31;
pub const AC_PWRST_SETTING: u32 = 0xf;
pub const AC_PWRST_ACTUAL: u32 = 0xf << 4;
pub const AC_PWRST_ACTUAL_SHIFT: u8 = 4;
pub const AC_PWRST_D0: u32 = 0x00;
pub const AC_PWRST_D1: u32 = 0x01;
pub const AC_PWRST_D2: u32 = 0x02;
pub const AC_PWRST_D3: u32 = 0x03;
pub const AC_PWRST_ERROR: u32 = 1 << 8;
pub const AC_PWRST_CLK_STOP_OK: u32 = 1 << 9;
pub const AC_PWRST_SETTING_RESET: u32 = 1 << 10;
// ---- Amplifier (hda_verbs.h:366-380) ----
pub const AC_AMP_MUTE: u8 = 1 << 7;
pub const AC_AMP_GAIN: u8 = 0x7f;
pub const AC_AMP_GET_LEFT: u32 = 1 << 13;
pub const AC_AMP_GET_OUTPUT: u32 = 1 << 15;
// ---- PCM/Stream format (hda_verbs.h:191-235) ----
pub const AC_SUPPCM_BITS_8: u32 = 1 << 16;
pub const AC_SUPPCM_BITS_16: u32 = 1 << 17;
pub const AC_SUPPCM_BITS_20: u32 = 1 << 18;
pub const AC_SUPPCM_BITS_24: u32 = 1 << 19;
pub const AC_SUPPCM_BITS_32: u32 = 1 << 20;
pub const AC_SUPFMT_PCM: u32 = 1;
// ---- DIGITAL1 (hda_verbs.h:383-391) ----
pub const AC_DIG1_ENABLE: u32 = 1;
pub const AC_DIG1_V: u32 = 1 << 1;
pub const AC_DIG1_EMPHASIS: u32 = 1 << 3;
pub const AC_DIG1_COPYRIGHT: u32 = 1 << 4;
pub const AC_DIG1_NONAUDIO: u32 = 1 << 5;
pub const AC_DIG1_PROFESSIONAL: u32 = 1 << 6;
pub const AC_DIG1_LEVEL: u32 = 1 << 7;
// ---- Connection List (hda_verbs.h:307-308) ----
pub const AC_CLIST_LENGTH: u32 = 0x7f;
pub const AC_CLIST_LONG: u32 = 1 << 7;
// ---- Function Group (hda_verbs.h:161-168) ----
pub const AC_GRP_AUDIO_FUNCTION: u8 = 0x01;
pub const AC_GRP_MODEM_FUNCTION: u8 = 0x02;
pub const AC_FGT_UNSOL_CAP: u32 = 1 << 8;
pub const AC_AFG_OUT_DELAY: u32 = 0xf;
pub const AC_AFG_IN_DELAY: u32 = 0xf << 8;
pub const AC_AFG_BEEP_GEN: u32 = 1 << 16;
// ---- Stream Format (hda_verbs.h:221-235) ----
pub const AC_FMT_CHAN_SHIFT: u8 = 0;
pub const AC_FMT_CHAN_MASK: u32 = 0x0f;
pub const AC_FMT_BITS_SHIFT: u8 = 4;
pub const AC_FMT_BITS_MASK: u32 = 7 << 4;
pub const AC_FMT_BITS_8: u32 = 0;
pub const AC_FMT_BITS_16: u32 = 1 << 4;
pub const AC_FMT_BITS_20: u32 = 2 << 4;
pub const AC_FMT_BITS_24: u32 = 3 << 4;
pub const AC_FMT_BITS_32: u32 = 4 << 4;
pub const AC_FMT_BASE_48K: u32 = 0;
pub const AC_FMT_BASE_44K: u32 = 1 << 14;
-135
View File
@@ -1,135 +0,0 @@
use redox_scheme::scheme::register_sync_scheme;
use redox_scheme::Socket;
use scheme_utils::ReadinessBased;
use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use std::usize;
use event::{user_data, EventQueue};
use pcid_interface::irq_helpers::pci_allocate_interrupt_vector;
use pcid_interface::PciFunctionHandle;
pub mod hda;
/*
VEND:PROD
Virtualbox 8086:2668
QEMU ICH9 8086:293E
82801H ICH8 8086:284B
*/
fn main() {
pcid_interface::pci_daemon(daemon);
}
fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
let pci_config = pcid_handle.config();
let mut name = pci_config.func.name();
name.push_str("_ihda");
common::setup_logging(
"audio",
"pci",
&name,
common::output_level(),
common::file_level(),
);
log::info!("IHDA {}", pci_config.func.display());
let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize;
let irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "ihdad");
{
let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16)
| (pci_config.func.full_device_id.device_id as u32);
user_data! {
enum Source {
Irq,
Scheme,
}
}
let event_queue =
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")
};
let mut readiness_based = ReadinessBased::new(&socket, 16);
register_sync_scheme(&socket, "audiohw", &mut device)
.expect("ihdad: failed to register audiohw scheme to namespace");
daemon.ready();
event_queue
.subscribe(
socket.inner().raw(),
Source::Scheme,
event::EventFlags::READ,
)
.unwrap();
event_queue
.subscribe(
irq_file.irq_handle().as_raw_fd() as usize,
Source::Irq,
event::EventFlags::READ,
)
.unwrap();
libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace");
let all = [Source::Irq, Source::Scheme];
for event in all
.into_iter()
.chain(event_queue.map(|e| e.expect("failed to get next event").user_data))
{
match event {
Source::Irq => {
let mut irq = [0; 8];
irq_file.irq_handle().read(&mut irq).unwrap();
if !device.irq() {
continue;
}
irq_file.irq_handle().write(&mut irq).unwrap();
readiness_based
.poll_all_requests(&mut device)
.expect("ihdad: failed to poll requests");
readiness_based
.write_responses()
.expect("ihdad: failed to write to socket");
/*
let next_read = device_irq.next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
*/
}
Source::Scheme => {
readiness_based
.read_and_process_requests(&mut device)
.expect("ihdad: failed to read from socket");
readiness_based
.write_responses()
.expect("ihdad: failed to write to socket");
/*
let next_read = device.borrow().next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
*/
}
}
}
std::process::exit(0);
}
}
-20
View File
@@ -1,20 +0,0 @@
[package]
name = "sb16d"
description = "Sound Blaster sound card driver"
version = "0.1.0"
edition = "2021"
[dependencies]
bitflags.workspace = true
common = { path = "../../common" }
libredox.workspace = true
log.workspace = true
daemon = { path = "../../../daemon" }
redox_event.workspace = true
redox_syscall.workspace = true
spin.workspace = true
redox-scheme.workspace = true
scheme-utils = { path = "../../../scheme-utils" }
[lints]
workspace = true
-232
View File
@@ -1,232 +0,0 @@
use std::{thread, time};
use common::io::{Io, Pio, ReadOnly, WriteOnly};
use redox_scheme::scheme::SchemeSync;
use redox_scheme::CallerCtx;
use redox_scheme::OpenResult;
use scheme_utils::{FpathWriter, HandleMap};
use syscall::error::{Error, Result, EACCES, EBADF, ENODEV};
use syscall::schemev2::NewFdFlags;
use spin::Mutex;
const NUM_SUB_BUFFS: usize = 32;
const SUB_BUFF_SIZE: usize = 2048;
enum Handle {
Todo,
SchemeRoot,
}
#[allow(dead_code)]
pub struct Sb16 {
handles: Mutex<HandleMap<Handle>>,
pub(crate) irqs: Vec<u8>,
dmas: Vec<u8>,
// Regs
/* 0x04 */ mixer_addr: WriteOnly<Pio<u8>>,
/* 0x05 */ mixer_data: Pio<u8>,
/* 0x06 */ dsp_reset: WriteOnly<Pio<u8>>,
/* 0x0A */ dsp_read_data: ReadOnly<Pio<u8>>,
/* 0x0C */ dsp_write_data: WriteOnly<Pio<u8>>,
/* 0x0C */ dsp_write_status: ReadOnly<Pio<u8>>,
/* 0x0E */ dsp_read_status: ReadOnly<Pio<u8>>,
}
impl Sb16 {
pub unsafe fn new(addr: u16) -> Result<Self> {
let mut module = Sb16 {
handles: Mutex::new(HandleMap::new()),
irqs: Vec::new(),
dmas: Vec::new(),
// Regs
mixer_addr: WriteOnly::new(Pio::new(addr + 0x04)),
mixer_data: Pio::new(addr + 0x05),
dsp_reset: WriteOnly::new(Pio::new(addr + 0x06)),
dsp_read_data: ReadOnly::new(Pio::new(addr + 0x0A)),
dsp_write_data: WriteOnly::new(Pio::new(addr + 0x0C)),
dsp_write_status: ReadOnly::new(Pio::new(addr + 0x0C)),
dsp_read_status: ReadOnly::new(Pio::new(addr + 0x0E)),
};
module.init()?;
Ok(module)
}
fn mixer_read(&mut self, index: u8) -> u8 {
self.mixer_addr.write(index);
self.mixer_data.read()
}
fn mixer_write(&mut self, index: u8, value: u8) {
self.mixer_addr.write(index);
self.mixer_data.write(value);
}
fn dsp_read(&mut self) -> Result<u8> {
// Bit 7 must be 1 before data can be sent
while !self.dsp_read_status.readf(1 << 7) {
//TODO: timeout!
std::thread::yield_now();
}
Ok(self.dsp_read_data.read())
}
fn dsp_write(&mut self, value: u8) -> Result<()> {
// Bit 7 must be 0 before data can be sent
while self.dsp_write_status.readf(1 << 7) {
//TODO: timeout!
std::thread::yield_now();
}
self.dsp_write_data.write(value);
Ok(())
}
fn init(&mut self) -> Result<()> {
// Perform DSP reset
{
// Write 1 to reset port
self.dsp_reset.write(1);
// Wait 3us
thread::sleep(time::Duration::from_micros(3));
// Write 0 to reset port
self.dsp_reset.write(0);
//TODO: Wait for ready byte (0xAA) using read status
thread::sleep(time::Duration::from_micros(100));
let ready = self.dsp_read()?;
if ready != 0xAA {
log::error!("ready byte was 0x{:02X} instead of 0xAA", ready);
return Err(Error::new(ENODEV));
}
}
// Read DSP version
{
self.dsp_write(0xE1)?;
let major = self.dsp_read()?;
let minor = self.dsp_read()?;
log::info!("DSP version {}.{:02}", major, minor);
if major != 4 {
log::error!("Unsupported DSP major version {}", major);
return Err(Error::new(ENODEV));
}
}
// Get available IRQs and DMAs
{
self.irqs.clear();
let irq_mask = self.mixer_read(0x80);
if (irq_mask & (1 << 0)) != 0 {
self.irqs.push(2);
}
if (irq_mask & (1 << 1)) != 0 {
self.irqs.push(5);
}
if (irq_mask & (1 << 2)) != 0 {
self.irqs.push(7);
}
if (irq_mask & (1 << 3)) != 0 {
self.irqs.push(10);
}
self.dmas.clear();
let dma_mask = self.mixer_read(0x81);
if (dma_mask & (1 << 0)) != 0 {
self.dmas.push(0);
}
if (dma_mask & (1 << 1)) != 0 {
self.dmas.push(1);
}
if (dma_mask & (1 << 3)) != 0 {
self.dmas.push(3);
}
if (dma_mask & (1 << 5)) != 0 {
self.dmas.push(5);
}
if (dma_mask & (1 << 6)) != 0 {
self.dmas.push(6);
}
if (dma_mask & (1 << 7)) != 0 {
self.dmas.push(7);
}
log::info!("IRQs {:02X?} DMAs {:02X?}", self.irqs, self.dmas);
}
// Set output sample rate to 44100 Hz (Redox OS standard)
{
let rate = 44100u16;
self.dsp_write(0x41)?;
self.dsp_write((rate >> 8) as u8)?;
self.dsp_write(rate as u8)?;
}
Ok(())
}
pub fn irq(&mut self) -> bool {
//TODO
false
}
}
impl SchemeSync for Sb16 {
fn scheme_root(&mut self) -> Result<usize> {
Ok(self.handles.lock().insert(Handle::SchemeRoot))
}
fn openat(
&mut self,
dirfd: usize,
_path: &str,
_flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
{
let handles = self.handles.lock();
let handle = handles.get(dirfd)?;
if !matches!(handle, Handle::SchemeRoot) {
return Err(Error::new(EACCES));
}
}
if ctx.uid == 0 {
let id = self.handles.lock().insert(Handle::Todo);
Ok(OpenResult::ThisScheme {
number: id,
flags: NewFdFlags::empty(),
})
} else {
Err(Error::new(EACCES))
}
}
fn write(
&mut self,
_id: usize,
_buf: &[u8],
_offset: u64,
_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
//TODO
Err(Error::new(EBADF))
}
fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
FpathWriter::with(buf, "audiohw", |_| Ok(()))
}
fn on_close(&mut self, id: usize) {
self.handles.lock().remove(id);
}
}
-119
View File
@@ -1,119 +0,0 @@
use libredox::{flag, Fd};
use redox_scheme::scheme::register_sync_scheme;
use redox_scheme::Socket;
use scheme_utils::ReadinessBased;
use std::{env, usize};
use event::{user_data, EventQueue};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub mod device;
fn main() {
daemon::Daemon::new(daemon);
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn daemon(daemon: daemon::Daemon) -> ! {
let mut args = env::args().skip(1);
let addr_str = args.next().unwrap_or("220".to_string());
let addr = u16::from_str_radix(&addr_str, 16).expect("sb16: failed to parse address");
println!(" + sb16 at 0x{:X}\n", addr);
common::setup_logging(
"audio",
"pci",
"sb16",
common::output_level(),
common::file_level(),
);
common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights");
let socket = Socket::nonblock().expect("sb16d: failed to create socket");
let mut device = unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") };
let mut readiness_based = ReadinessBased::new(&socket, 16);
//TODO: error on multiple IRQs?
let irq_file = match device.irqs.first() {
Some(irq) => Fd::open(&format!("/scheme/irq/{}", irq), flag::O_RDWR, 0)
.expect("sb16d: failed to open IRQ file"),
None => panic!("sb16d: no IRQs found"),
};
user_data! {
enum Source {
Irq,
Scheme,
}
}
let event_queue = EventQueue::<Source>::new().expect("sb16d: Could not create event queue.");
event_queue
.subscribe(irq_file.raw(), Source::Irq, event::EventFlags::READ)
.unwrap();
event_queue
.subscribe(
socket.inner().raw(),
Source::Scheme,
event::EventFlags::READ,
)
.unwrap();
register_sync_scheme(&socket, "sb16d", &mut device)
.expect("sb16d: failed to register audiohw scheme to namespace");
daemon.ready();
libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace");
let all = [Source::Irq, Source::Scheme];
for event in all
.into_iter()
.chain(event_queue.map(|e| e.expect("sb16d: failed to get next event").user_data))
{
match event {
Source::Irq => {
let mut irq = [0; 8];
irq_file.read(&mut irq).unwrap();
if !device.irq() {
continue;
}
irq_file.write(&mut irq).unwrap();
readiness_based
.poll_all_requests(&mut device)
.expect("sb16d: failed to poll requests");
readiness_based
.write_responses()
.expect("sb16d: failed to write to socket");
/*
let next_read = device_irq.next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
*/
}
Source::Scheme => {
readiness_based
.read_and_process_requests(&mut device)
.expect("sb16d: failed to read from socket");
readiness_based
.write_responses()
.expect("sb16d: failed to write to socket");
}
}
}
std::process::exit(0);
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn daemon(_daemon: daemon::Daemon) -> ! {
// Sound Blaster 16 is an x86/x86_64 legacy ISA card; no other architectures are supported.
panic!("sb16d: only supported on x86 and x86_64");
}
-18
View File
@@ -1,18 +0,0 @@
[package]
name = "common"
description = "Shared driver code library"
version = "0.1.0"
edition = "2021"
authors = ["4lDO2 <4lDO2@protonmail.com>"]
license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libredox.workspace = true
log.workspace = true
redox_syscall = { workspace = true, features = ["std"] }
redox-log.workspace = true
[lints]
workspace = true

Some files were not shown because too many files have changed in this diff Show More