2755 Commits

Author SHA1 Message Date
vasilito ec8e88c364 0.3.0: kernel build fixes - syscall aliases and FADT length type cast
- Add SYS_OPENAT/SYS_DUP aliases in local syscall fork for upstream 0.9.0 renamed constants.

- Cast FADT_MIN_SIZE_ACPI_2_0 to u32 to match sdt.length() return type.

- Keep Cargo.lock based on upstream master with only redox_syscall sourced from local fork.
2026-07-06 18:57:41 +03:00
vasilito ca67b1da37 0.3.0: converge kernel onto upstream master
- Rebase all Red Bear kernel changes onto upstream master (4d5d36d4).
- Update version to 0.5.12+rb0.3.0 and add Red Bear author attribution.
- Switch redox_syscall direct dependency to local fork path (../syscall).
- Bump rust-toolchain.toml to nightly-2026-05-24.
- Regenerate Cargo.lock for +rb0.3.0 suffixes and path deps.
2026-07-06 18:43:52 +03:00
R Aadarsh 4d5d36d44e Extract code that is common to both x86 and ARM to srat::init 2026-07-05 20:16:00 +05:30
R Aadarsh 35340a80c4 * Add ACPI-NUMA parsing code for ARM
* Fix bug in the x86 code that caused incorrect cpu-node mapping

* Remove the usage of page mappers. Instead use the already existing
  linear mapping
2026-07-05 15:01:48 +05:30
R Aadarsh cb88ed59a2 Parse ACPI tables for NUMA information without allocating from the heap 2026-07-03 20:19:46 +05:30
Wildan M 372cd19b6f Remove irq from handles on close 2026-07-02 08:41:11 +07:00
R Aadarsh aa7e7d2f44 Fix the bug in RxsdtIter that caused u32 pointers to be used regardless of ACPI table kind 2026-07-01 10:36:07 -06:00
R Aadarsh a03c545f3c Fix build failure for ARM 2026-07-01 10:36:07 -06:00
R Aadarsh a2a3df33c6 Split acpi::init to perform two stage initialisation 2026-07-01 10:36:07 -06:00
Ibuki Omatsu 6c3d5d28c6 refactor: Move fd allocation logic into userspace 2026-07-01 08:02:47 -06:00
R Aadarsh 8171dc616b Fix panic due to using uninitialised NUMA_NODES 2026-06-21 14:30:07 +05:30
R Aadarsh 2ad76496c4 * Store addresses as pointers
* Remove lots of unsafe code by initialising in the closure passed to
  `call_once`

* Remove `NUMBER_OF_DOMAINS` as size can always be inferred from the
  hashmap's len
2026-06-21 14:03:49 +05:30
R Aadarsh 4106dcbbfa Gate behind a feature flag 2026-06-21 14:03:49 +05:30
R Aadarsh 969c905d8e Account for the case when distance information is not available 2026-06-21 14:03:49 +05:30
R Aadarsh 9ecc75029c * Correctly put cpus and memories for adoption
* Test on x86_64 (works)
2026-06-21 14:03:49 +05:30
R Aadarsh 16c59588b0 * Fix endianness
* Remove ITS affinity and numa
2026-06-21 14:03:49 +05:30
R Aadarsh ee2a61088e * Parse SLIT for distance information
* Order by distance, reorganise domains into nodes
2026-06-21 14:03:49 +05:30
R Aadarsh 63d1171ffb Initial commit 2026-06-21 14:03:49 +05:30
Wildan M 002fff546d Clear cloexec flag on Dup2 2026-06-20 06:35:01 +07:00
Wildan M ed31b800c4 Revert "Use weak context for Proc" 2026-06-19 17:36:41 +07:00
Wildan M 622a4fb3cd Solve context leak when switching 2026-06-19 17:33:46 +07:00
Wildan M 101f090ef9 Fmt 2026-06-19 16:50:14 +07:00
Akshit Gaur b93260ed2d Migrating run_queue to BTreeMap 2026-06-18 10:39:33 +05:30
4lDO2 56947e1a0f Revert drop of kstack in exit_this_context. 2026-06-04 13:37:57 +02:00
4lDO2 bd6d9acd3c Compile on other arches. 2026-06-03 19:06:12 +02:00
4lDO2 c27568e1fe profiling: allow walking across syscall boundaries 2026-06-03 19:01:35 +02:00
4lDO2 42613ddc06 WIP: simultaneous NMI-based user+kernel profiling. 2026-06-03 19:01:35 +02:00
R Aadarsh f8bc19747a Make necessary changes to the kernel in order for relibc to support posix_spawn and posix_spawnp
* `syscall::sendfd`, now, when called with a `ContextHandle::FileTable` adds the fd to the filetable removing it from the calling process's filetable

* Files can now be added to, removed from another process, and can be duplicated using `ProcScheme::kcall`

* Files of another process with the flag O_CLOEXEC can now be closed by using `kcall`
2026-06-03 15:29:02 +05:30
4lDO2 8011f3f648 Simplify acpi scheme. 2026-06-02 16:23:08 +02:00
4lDO2 6fc2d32497 Remove redundant methods from KernelScheme. 2026-06-02 11:24:37 +02:00
4lDO2 da3d235af5 remove syscall debug for removed syscalls 2026-06-02 11:24:37 +02:00
4lDO2 3e210ff169 Remove 5 obsolete syscalls. 2026-06-02 11:24:37 +02:00
Wildan M 8701e8165b Fix compilation for aarch64 after rust update 2026-05-31 06:55:02 +07:00
4lDO2 cee451af38 Use ArrayVec for kcall fd nums, 8% better perf! 2026-05-31 20:24:57 +02:00
Wildan M 973ac667e3 Use syscall time helper functions 2026-05-30 12:29:38 +07:00
Wildan M a47b3a8d57 Add timeout for events 2026-05-30 13:44:31 -06:00
Wildan M ec1395b554 Wrap unmap loop with handle_notify_files 2026-05-30 08:40:49 -06:00
Akshit Gaur 58283f63fe EEVDF 2026-05-30 08:39:48 -06:00
Ibuki Omatsu e847768f2b feat: Implement multiple fds variant for call and std_fs_call 2026-05-29 13:07:36 +02:00
bjorn3 91ab8301f2 Fix warnings after updating rustc
Couple of features got stabilized, cpuid was made safe and there is a
new lint for function item to integer casts.
2026-05-27 20:53:10 +02:00
Jeremy Soller d254309fdb Support nightly 2026-05-24 2026-05-25 17:41:48 -06:00
Wildan M f70905d439 Resolve warnings 2026-05-23 00:04:34 +07:00
Wildan M 40e76875d7 Prevent kstack from leaking 2026-05-20 13:35:47 +07:00
Wildan M 805f921e10 Use weak context for Proc and Futex 2026-05-20 12:57:37 +07:00
Wildan M 7c653c5182 Possible fix to race condition to EBADF 2026-05-15 22:46:03 +07:00
Wildan M 8c9def2d73 Lazily clean up futex 2026-05-13 20:49:02 +07:00
Wildan M ff11f47404 Add futex, pipe, timeout subscribers 2026-05-13 10:46:38 +07:00
Wildan M bd44956e96 Capture event stat, change stat source for contexts 2026-05-12 12:24:49 +07:00
Wildan M 97bd0fb4a6 Don't compare QueueKey data to fix epoll ctl del 2026-05-10 17:33:04 +07:00
bjorn3 3dab161d30 Copy the flags set from physmap MemoryType over on scheme mmap
Propagating flags like uncachable or writecombining is necessary both
for correctness and for performance.
2026-05-06 21:05:16 +02:00
Speedy_Lex 678a8c5631 Fail softly on bad RSDP 2026-05-05 19:35:33 +02:00
Speedy_Lex 6b55ffea38 Make rsdp pointer NonNull 2026-05-05 19:35:33 +02:00
Speedy_Lex 6af9afb75d Fix check
Co-Author: 4lDO2
2026-05-05 19:35:33 +02:00
Speedy_Lex 6e539f9cd9 Fix bit check in src/profiling.rs 2026-05-05 19:35:33 +02:00
Speedy_Lex f49c7d991a RSDP validation and fixing a few clippy lints 2026-05-05 19:35:31 +02:00
Wildan M 51f32e9edb Allow cd to sys scheme 2026-05-02 18:25:44 +07:00
Wildan M 85c98314a9 Unwrap select_next_context result 2026-05-02 06:23:13 -06:00
Wildan M abb429d0c5 Revert "Split wait queue mutex" 2026-05-02 05:55:27 +07:00
Wildan M a297bfcc82 Use smallvec for memory and notify_files 2026-04-30 22:00:35 +07:00
Wildan M 1070efaec8 Solve some lock ordering 2026-04-30 21:59:19 +07:00
Wildan M 3914801f1e Speed up vector removal 2026-04-30 21:59:19 +07:00
Wildan M 00232b456c Optimize new mmap grant 2026-04-30 11:12:01 -06:00
Wildan M fb137f8001 Avoid reaccessing AddrSpace when switching 2026-04-30 11:09:59 -06:00
Wildan M 844f393ae8 Downgrade context sigcontrol to read 2026-04-29 21:48:31 +07:00
Wildan M ba28216ae8 Downgrade locks to read 2026-04-29 21:26:44 +07:00
Wildan M ab08d47aa8 Add commented out switch debug print 2026-04-29 11:21:20 +07:00
Wildan M e7ac009f31 Fix deadlock on contended switch 2026-04-29 11:21:02 +07:00
Wildan M fd5a04a121 Use status helpers 2026-04-29 11:20:43 +07:00
Wildan M baf329c120 Fix dead contexts clobber idle pools 2026-04-29 11:20:21 +07:00
Wildan M 866dfad0af Lower WaitQueue incoming lock level 2026-04-27 06:51:45 -06:00
Wildan M b8615790ea Lock wait queue together when receive_into_user 2026-04-27 06:51:45 -06:00
Wildan M 746c158465 Split wait queue mutex 2026-04-27 06:51:45 -06:00
Wildan M b3a6154445 Move dst_space_lock lower to Solve AddrSpaceWrapper lock 2026-04-27 06:50:20 -06:00
Wildan M 8dcb508413 Make AddrSpaceWrapper lock lower without solving borrow checker 2026-04-27 06:50:20 -06:00
Wildan M 2bca47923c Avoid reaccessing AddrSpace when switching 2026-04-27 02:18:42 +07:00
Wildan M c2b20abc03 Avoid locking current context on capture_inner 2026-04-27 01:54:43 +07:00
Wildan M e9f50698dd Remove ContextRef upgrade 2026-04-26 15:37:40 +07:00
Wildan M 2df7467d13 Use weak ContextRef for run contexts 2026-04-26 12:08:24 +07:00
Wildan M ea1d915bbc Make wake up optional 2026-04-26 07:15:10 +07:00
Wildan M 643726852b Reduce deadlock cap 2026-04-26 06:49:55 +07:00
Wildan M 0534ab6377 Replace enqueue with dedicated idle contexts 2026-04-26 06:49:55 +07:00
Wildan M de7926e05e Do not push idle context to queue 2026-04-26 06:49:54 +07:00
Wildan M 7adceb6e80 Add idle context 2026-04-26 06:49:54 +07:00
bjorn3 7827cb6c78 Unify context list again now that we have a run queue
This simplifies code and ensures that exiting a context will properly
remove it from the list of contexts.
2026-04-26 06:49:54 +07:00
Wildan M af1bc5d5e2 Fix relibc CI 2026-04-25 09:48:34 -06:00
Wildan M 58660a9170 Handle AddrSpace munmap 2026-04-24 17:52:05 +07:00
Wildan M f773d3e50d don't loop from idle to kernel context 2026-04-23 16:40:12 +07:00
Wildan M 8262fa7da9 Don't account idle time 2026-04-23 16:33:15 +07:00
Wildan M 2ca610193b Add kernel version to relibc CI test 2026-04-20 10:50:42 +07:00
Wildan Mubarok df07d65c05 Apply 1 suggestion(s) to 1 file(s)
Co-authored-by: bjorn3 <4397-bjorn3@users.noreply.gitlab.redox-os.org>
2026-04-19 08:46:05 -06:00
Wildan M bbfbe30445 Exclude PhysBorrowed from counting shared memory 2026-04-19 08:46:05 -06:00
Wildan M aee49d747a Update relibc test in CI 2026-04-19 16:52:29 +07:00
aarch e80379e6c6 Actually switch to Sv39 2026-04-18 18:49:21 +02:00
aarch f7c48049f5 RISCV64: Change VA scheme to Sv39 for real hardware support + Sv57 definitions 2026-04-18 09:46:34 -06:00
bjorn3 30b967022f Fix a couple of warnings 2026-04-17 20:20:16 +02:00
Akshit Gaur 976756991a Deficit Weighted Round Robin Scheduler 2026-04-17 06:52:03 -06:00
Wildan M 4531e15ba1 Add shared memory stats to contexts 2026-04-16 09:53:30 +07:00
bjorn3 219d707362 Introduce HandleMap helper type 2026-04-13 20:51:24 +02:00
bjorn3 f673afa839 Fix a duplicate log
This got moved into allocate, but forgot to save the change.
2026-04-13 20:22:18 +02:00
bjorn3 2174f86543 Fix debugger 2026-04-13 19:43:44 +02:00
bjorn3 4929783030 Improve fdstat 2026-04-13 19:43:44 +02:00
bjorn3 3a2200198a Always compile the code of sys_fdstat 2026-04-13 19:43:44 +02:00
bjorn3 3ff7872cd6 Fix warnings for sys_fdstat 2026-04-13 19:43:44 +02:00
bjorn3 38f36d406b Use cfg!() instead of #[cfg] for most profiling code
This makes it less likely that it breaks again in the future as most
code gets checked by the compiler even when profiling support is not
enabled.
2026-04-13 19:43:43 +02:00
Jacob Lorentzon 142871660e profiling: infer number of CPUs dynamically 2026-04-13 06:44:27 -06:00
bjorn3 2405a7ebb3 Move kmain and kmain_ap to startup/mod.rs 2026-04-12 18:41:00 +02:00
bjorn3 572bb4ce1f Avoid re-exporting arch specific modules in the crate root 2026-04-12 18:25:52 +02:00
Jacob Lorentzon 141c87650f Fix profiling and add check to CI 2026-04-12 06:51:26 -06:00
bjorn3 2f39aade30 Use mmap_anywhere in a couple of places 2026-04-10 20:23:01 +02:00
bjorn3 f792faf571 Avoid a Once for event::REGISTRY 2026-04-10 20:22:58 +02:00
bjorn3 a46f37976b Use div_ceil in LogicalCpuSet Display impl 2026-04-10 20:22:58 +02:00
bjorn3 aab33e46c3 Fix a couple of warnings 2026-04-10 20:22:26 +02:00
Wildan M 8f54fd8cb2 Fix displaying affinity in sys/context 2026-04-09 15:24:36 -06:00
bjorn3 654ee6ca3e size_of and align_of are part of the prelude nowadays 2026-04-09 15:23:34 -06:00
bjorn3 2e784dfe46 Remove unused feature gate 2026-04-09 15:23:34 -06:00
bjorn3 89a29f4e56 Reduce usage of wildcard imports 2026-04-09 15:23:34 -06:00
bjorn3 b0b0ec2d71 Deduplicate definition of FLAG_SINGLESTEP between x86 and x86_64 2026-04-09 15:23:34 -06:00
bjorn3 e98e12780e Inline BorrowedHtBuf::tail 2026-04-09 15:23:34 -06:00
bjorn3 bdf82a958a Use call instead of call_inner for fmap_inner 2026-04-09 15:23:34 -06:00
Wildan M cd3b18068f Improve mem precision in sys/context 2026-04-09 15:22:38 -06:00
Wildan M ce08b60502 Solve lock token and contexts for fdstat and debugger 2026-04-09 15:22:38 -06:00
Wildan M 0ad905f26e Fix sys stats to reveal contexts in all CPU 2026-04-09 15:22:38 -06:00
Speedy_Lex ee1260363c Fix many clippy lints 2026-04-08 19:40:41 +01:00
bjorn3 b7456d5bcc Avoid PHYS_OFFSET in dtb/serial.rs 2026-04-04 21:53:34 +02:00
bjorn3 d029ccfe20 Deduplicate a bunch of serial port initialization between arm64 and riscv 2026-04-04 16:36:30 +02:00
bjorn3 bbb9d98570 Unconditionally compile part of the DTB code 2026-04-04 14:01:19 +02:00
bjorn3 8eefc8a6a6 Remove unused dependency 2026-04-04 13:52:26 +02:00
bjorn3 f339467372 Remove dead_code lint allow for ACPI 2026-04-04 13:50:48 +02:00
bjorn3 62f220b1b9 Use cfg! rather than #[cfg] for ACPI enabling 2026-04-04 13:49:07 +02:00
bjorn3 49d005b450 Use RmmA::phys_to_virt instead of PHYS_OFFSET in the acpi code 2026-04-04 13:33:26 +02:00
bjorn3 2fba663274 Fix expect message 2026-04-04 13:14:14 +02:00
bjorn3 7aa7aa463f Use map_device_memory where possible 2026-04-04 13:10:05 +02:00
bjorn3 dee230ffca Use map_linearly in many places 2026-04-04 13:10:04 +02:00
bjorn3 a1b6bd965e Fix rmm example 2026-04-04 12:02:07 +02:00
bjorn3 50c68cd746 Remove ACPI search from the kernel
The bootloader provides the RSDP address to the kernel. If the
bootloader can't find it, there is no RSDP.
2026-04-04 11:50:24 +02:00
bjorn3 1352fafd00 Remove unused InactiveFlusher 2026-04-03 22:15:00 +02:00
bjorn3 ab4abf63c9 Deduplicate Page and other paging related things between architectures 2026-04-03 22:15:00 +02:00
bjorn3 b805336cfc Fix a bunch of warnings 2026-04-03 22:15:00 +02:00
bjorn3 3cbce1b9ac Move BSP_READY and AP_READY to platform-independent code 2026-04-02 20:29:36 +02:00
bjorn3 0f540e6f15 Don't physmap the kernel itself
We don't actually need to and this is a bit safer against memory corruption.
2026-04-02 20:29:36 +02:00
bjorn3 49eb21ce0e Use KERNEL_OFFSET from linker script 2026-04-02 20:29:36 +02:00
bjorn3 dc7e823f70 Deduplicate kernel page flags 2026-04-02 20:29:36 +02:00
bjorn3 980f1c6af8 Remove unused and deduplicate identical arch specific consts 2026-04-02 20:29:36 +02:00
bjorn3 10b1ae2ecc Remove unused arch consts 2026-04-02 20:29:36 +02:00
bjorn3 2ce7621a80 Fix a bunch of warnings masked by #[allow(unused)] 2026-04-02 20:29:36 +02:00
Wildan M d835a3d8f0 Solve all borrow checker leaving some violation 2026-04-01 08:42:18 -06:00
Wildan M a42ec44dbf Partially solve borrow rules 2026-04-01 08:42:18 -06:00
Wildan M 3161a44c25 Solve borrow rules for memory.rs 2026-04-01 08:42:18 -06:00
Wildan M 55e6fe9add Remove remnants of AddrSpace::used_by 2026-04-01 08:42:18 -06:00
Wildan M ca2a7048d0 Move spin loop hint to crate lock 2026-04-01 08:42:18 -06:00
Wildan M 3b5a0e4c60 Apply ordered lock to AddrSpaceWrapper without solving borrow checker 2026-04-01 08:42:18 -06:00
Wildan M 2989b5375f Add deadlock debug to AddrSpaceWrapper 2026-04-01 08:42:18 -06:00
Akshit Gaur 004509587d Fix ForceKill 2026-04-01 13:58:27 +05:30
Wildan M 6e0143cf0d Store context to per cpu 2026-03-31 15:29:47 +07:00
bjorn3 efa6b00189 rmm: Remove magic constants for x86 PAT indices 2026-03-30 22:18:10 +02:00
bjorn3 c8879531ae rmm: Add device_memory and uncachable flags to PageFlags 2026-03-30 20:34:45 +02:00
bjorn3 e311b41821 rmm: Make it a bit easier to change the MAIR_EL1 config on arm64 2026-03-30 20:34:45 +02:00
bjorn3 a5fd001dcb Use PageFlags::write_combining instead of custom flag 2026-03-30 20:34:45 +02:00
bjorn3 c0065bc893 rmm: Add some comments to init_pat 2026-03-30 20:34:44 +02:00
bjorn3 6b00f4ca25 Move MAIR_EL1 initialization to rmm
Rmm needs to know the exact MAIR_EL1 configuration to produce the
correct bits in the page table.
2026-03-30 19:26:41 +02:00
bjorn3 6e5c25b7a0 Move PAT initialization to rmm
Rmm needs to know the exact PAT configuration to produce the correct
bits in the page table.
2026-03-30 18:59:42 +02:00
bjorn3 c4b064ea44 Move arch specific EntryFlags into rmm 2026-03-30 18:49:15 +02:00
bjorn3 04645353f2 rmm: Fix EmulateArch compilation 2026-03-30 18:46:53 +02:00
bjorn3 8b217edac0 Fix two unsafe block related warnings 2026-03-30 18:42:38 +02:00
bjorn3 2fc2d5897a Fix a couple of unused import warnings 2026-03-30 18:38:25 +02:00
bjorn3 675ba2ea51 rmm: Make a couple more methods safe 2026-03-29 17:00:36 +02:00
bjorn3 c51aa1ef86 rmm: Make a couple of methods safe 2026-03-29 14:16:53 +02:00
bjorn3 a5aeea9cfc rmm: Remove PageMapper::{map,unmap}
There is already (un)map_phys.
2026-03-29 14:16:53 +02:00
bjorn3 a876d66648 rmm: Reduce visibility of PageTable methods
This disallows direct manipulation of the page tables. Only manipulation
through PageMapper is allowed.
2026-03-29 14:16:53 +02:00
bjorn3 abf710b4a2 Move handling of kernel page table entry copying to RMM
This way it can ensure those page table entries never get unmapped,
ensuring they are kept in sync between all processes.
2026-03-29 14:16:53 +02:00
bjorn3 604e1729cb Rustfmt 2026-03-29 14:16:53 +02:00
bjorn3 882007f827 Remove unused UserSlice::read_u64
This fixes a warning. It can always be re-introduced if we ever need it.
2026-03-29 14:16:36 +02:00
bjorn3 f5aff74fc9 Explicitly ignore field of PageQueueEntry::Other
This fixes a warning
2026-03-29 14:16:35 +02:00
bjorn3 b5603422be Check at compile time that KernelMapper is writable if necessary 2026-03-28 23:22:19 +01:00
bjorn3 0d578775f9 rmm: Indicate which PageMapper methods can allocate 2026-03-28 22:51:32 +01:00
bjorn3 d02312055e rmm: Couple of minor cleanups 2026-03-28 22:35:26 +01:00
bjorn3 3593c53146 rmm: Remove Arch::init
No architectures implement it.
2026-03-28 22:07:48 +01:00
bjorn3 db85237114 rmm: Partially hard code main.rs to EmulateArch 2026-03-28 22:06:24 +01:00
bjorn3 d06ade297d rmm: Remove fallback impl of invalidate_all
It doesn't work on all non-x86 architectures.
2026-03-28 22:02:34 +01:00
bjorn3 a913414c7f rmm: Nicer formatting of unsafe blocks 2026-03-28 22:00:43 +01:00
bjorn3 cc20bcd405 rmm: Fix warnings on x86 2026-03-28 21:57:51 +01:00
bjorn3 a3843f8fb5 rmm: Assert constants at compile time 2026-03-28 21:57:41 +01:00
bjorn3 5c480806be Add rmm to the workspace 2026-03-28 21:39:34 +01:00
bjorn3 ef508cc0ba Add 'rmm/' from commit 'e543cbe621b21875549c9d12a73810633f3d0c63'
git-subtree-dir: rmm
git-subtree-mainline: 76b0691e14
git-subtree-split: e543cbe621
2026-03-28 20:44:33 +01:00
bjorn3 76b0691e14 Remove rmm submodule 2026-03-28 20:43:48 +01:00
bjorn3 f8d93023dd Fix a couple of warnings 2026-03-28 17:07:33 +01:00
Philipp Bartsch 5865ec0790 /scheme/sys/cpu: Add aarch64 feature detection
This only lists features from ID_AA64ISAR0_EL1 and ID_AA64ISAR1_EL1.
For other features one would have to evaluate more registers.
2026-03-26 22:15:03 +01:00
Philipp Bartsch 2d5e2b39f5 Drop extra debug print 2026-03-26 00:49:33 +01:00
Philipp Bartsch a60cc25015 Update aarch64 implementers list
Two vendors were missing compared to ARM's official list.

https://developer.arm.com/documentation/ddi0601/2025-12/AArch64-Registers/MIDR-EL1--Main-ID-Register
2026-03-26 00:49:11 +01:00
Ron Williams fde164b2a0 Revert "Deficit based Weighted Round Robin Scheduler"
This reverts commit b7dabfc3c2.
2026-03-22 18:44:41 +00:00
Akshit Gaur b7dabfc3c2 Deficit based Weighted Round Robin Scheduler 2026-03-22 07:00:31 -06:00
Wildan M 74895c4f0f Fix ecpect file 2026-03-17 19:30:17 +07:00
Wildan M c70035865e Fix expect files 2026-03-17 19:24:10 +07:00
Wildan M 727f9658ed Fix CI sysroot 2026-03-17 18:57:21 +07:00
Wildan M bbcb3d19be Try using uname, fix relibc 2026-03-17 18:44:28 +07:00
Wildan M 65bd8e3264 Add boot check to CI 2026-03-17 18:32:51 +07:00
Wildan M 52d9fcc962 Try use relibc tests 2026-03-17 18:20:47 +07:00
Wildan M d317f84cd4 Change uname to kernel commit, Fix CI build 2026-03-17 17:51:29 +07:00
Connor-GH d81ba0645b /scheme/sys/uname: use commit hash instead of time for reproducibility 2026-03-15 17:21:46 -05:00
Connor-GH ea47151757 /scheme/sys/uname: include the "version" info
With this change, we use the recently-added `COOKBOOK_TIME_IDENT`
environment variable at compile time to get the "version" info for the
uname scheme. This field is unspecified by POSIX what it should have,
but most kernels (including Linux, XNU, NetBSD, etc.) put the build
time here.
2026-03-15 15:53:02 -05:00
Wildan M 44b6a58032 Add more context to deadlock debug messages 2026-03-14 08:49:40 -06:00
Ibuki.O 3934ea454d feat: Implement translation of std_fs_call to each function 2026-03-14 11:37:07 +09:00
Connor-GH 8f468ec106 syscall: remove comment about test vs bt x86 instructions
According to Agner Fog's documentation
(https://agner.org/optimize/instruction_tables.pdf), the following information
is true:

These instructions have identical latency and throughput, except for Zen
5, which lists `test` as having reciprocal throughput of 0.25 cycles,
and `bt` having reciprocal throughput of 0.33 cycles. This rules out the
`bt` instruction for being the ideal instruction.

The other `test` instructions were removed as candidates because,
regardless of the size of the memory fetched at the address, at least 64
bytes will need to be fetched because it will be stored in the cache
line. The WORD and DWORD cases can be ruled out because we cannot assume
that `rsp + 16` or `rsp + 17` will not be on a 64-byte alignment
boundary, which would cause two cachelines to be essentially filled with
garbage we don't care about. The best case scenario is that we only need
to fill one cache line with garbage, which is what the BYTE version does
every time.
2026-03-12 09:41:29 -05:00
Wildan M 84754dfc5d Solve borrow checking by downgrading waitqueue lock 2026-03-11 09:42:06 +07:00
Wildan M f07725682f Add ordered lock for WaitQueue mutex without solving borrow check 2026-03-11 09:24:45 +07:00
Wildan M 60573e24f3 Solve borrow checking by downgrading condition.wait lock 2026-03-11 09:07:52 +07:00
Wildan M 046c8ced0d Add lock token to pipe queue without solving borrow checker 2026-03-11 08:12:07 +07:00
Wildan M 7ebb5f2a3d Solve borrow checking by downgrading locks 2026-03-11 08:00:48 +07:00
Wildan M 44f2214971 Partially solve borrow checking with WaitQueue 2026-03-11 07:27:21 +07:00
Wildan M 771ebdb39f Partially solve borrow checking with PreemptGuard L1 2026-03-11 06:34:37 +07:00
Wildan M 73c2df9e33 Add lock token to user states, without solving borrow check 2026-03-10 23:56:15 +07:00
Wildan M eeb03bdcb1 Revert "Add ordered lock for WaitQueue mutex"
This reverts commit 735c68ec30.
2026-03-10 12:11:09 +07:00
Wildan M d5ed9d8007 Optimize context spawn and init 2026-03-10 05:59:35 +07:00
Wildan M c4e86bfffd Change time offset to RwLock 2026-03-10 05:58:26 +07:00
Wildan M 7fa253cf6a Add deadlock detection 2026-03-09 16:32:11 +07:00
Wildan M 6307446ede Solve borrow rules to LockedFdTbl 2026-03-09 15:57:38 +07:00
Wildan M 8412321568 Add lock token to FdTbl without borrow check 2026-03-09 13:12:19 +07:00
Wildan M 206f82709a Demote LockedFileDescription to solve borrow rules 2026-03-09 12:29:24 +07:00
Wildan M 8f270795da Partialy solve borrow checking 2026-03-09 11:47:07 +07:00
Wildan M f40b84a5cc Add lock token to FileDescription, without borrow check 2026-03-09 11:23:51 +07:00
bjorn3 6085c8935c Remove unused WaitQueue::receive method 2026-03-07 21:44:29 +01:00
bjorn3 6a10af6f77 Fully remove the broken support for unmounting schemes
It has been broken since we moved namespaces into userspace. Fixing it
can be done entirely inside userspace. Either by introducing a SYS_CALL
for the root capability or by treating closing the last fd as unmount.
2026-03-07 21:42:46 +01:00
Wildan M fd9c651410 Do not allocate on unneeded Vec 2026-03-07 09:15:20 -07:00
Wildan M 547722767a Optimize sys/stat a bit 2026-03-07 20:42:25 +07:00
Wildan M a5adc0cc69 Avoid heap allocation on event 2026-03-07 06:33:52 -07:00
bjorn3 4ccc521156 Show grant flags in the debugger 2026-03-07 12:19:40 +01:00
bjorn3 ea847f428f Fix compilation with the debugger feature enabled 2026-03-07 12:19:24 +01:00
auronandace 4c734e461a prefer saturating methods over direct arithetic 2026-03-05 10:58:45 +00:00
auronandace fc6ffd59ff avoid direct indexing in MemoryMap register function 2026-03-03 17:22:44 +00:00
auronandace 14b8c2b0c1 enforce two lints and collapse some ifs 2026-03-03 14:51:32 +00:00
auronandace f0f158e5d6 eliminate 2 unwraps in syscall fs 2026-03-02 17:11:51 -07:00
auronandace f7b0f5ec37 eliminate an unwrap in gdt for x86_shared 2026-03-02 10:56:28 +00:00
Ibuki Omatsu 4faa1bad45 feat: Implment std_fs_call kfstatvfs handling to memory scheme 2026-02-28 08:06:47 -07:00
Marsman 507d899587 fix: validate timespec in nanosleep 2026-02-28 07:02:30 +00:00
Wildan M fbe129918c Handle address release on flink 2026-02-27 15:43:19 +07:00
Wildan M 1b74bea620 EventQueue may dropped at trigger_inner 2026-02-27 15:29:58 +07:00
Wildan M 2e759a9cc5 Prevent drop on BorrowedHtBuf 2026-02-27 13:54:05 +07:00
Wildan M 437f762339 Prevent drop on WaitCondition 2026-02-27 12:34:13 +07:00
Wildan M 159e67f26d Add lock token for global REGISTRY 2026-02-27 11:16:57 +07:00
Wildan M c72e0a67f9 Prevent drop on AddrSpace 2026-02-27 10:47:45 +07:00
Jeremy Soller d34090f352 Accurately strip ANSI escape sequences in graphical debug display 2026-02-26 10:33:46 -07:00
Wildan M ac0bd2af74 Fix compilation 2026-02-26 04:33:10 +07:00
Anhad Singh ba94676fe4 chore: update redox_syscall
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-02-25 08:21:36 -07:00
Anhad Singh 8eb6d22ab4 misc(scheme/user): remove some debug logs
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-02-25 08:21:36 -07:00
Anhad Singh 955b4b2a1c feat(stdfscall): flocking
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-02-25 08:21:36 -07:00
Wildan M 14349d1649 Propagate ordered lock of event trigger 2026-02-25 11:42:31 +07:00
Wildan M 3c2b1a11c5 Add ordered lock for time offset mutex 2026-02-25 11:42:17 +07:00
Wildan M 735c68ec30 Add ordered lock for WaitQueue mutex 2026-02-25 09:48:13 +07:00
auronandace bf396c7f61 replace manual stripping 2026-02-23 15:49:32 +00:00
auronandace 8138826200 avoid direct indexing in wait_condition 2026-02-23 06:34:20 -07:00
auronandace 7770a9452c avoid direct indexing futexes 2026-02-23 11:57:28 +00:00
auronandace a19be5da11 avoid direct indexing in AlignedBox 2026-02-22 13:43:37 +00:00
auronandace aeb75d577f add assert to ensure both arrays are equal length 2026-02-21 20:37:08 +00:00
auronandace 8689e31674 remove an instance of direct indexing 2026-02-21 15:28:55 +00:00
auronandace df469ddcb3 apply is_multiple_of lint 2026-02-21 08:39:26 +00:00
auronandace 02a68d3c87 change static_mut_refs back to warn 2026-02-20 16:06:16 +00:00
auronandace 28ba26cc2b move lints to Cargo.toml file 2026-02-20 15:59:27 +00:00
Anhad Singh fc60dcced0 misc(main): add feature btree_cursors
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-02-21 00:59:24 +11:00
Anhad Singh a8699a7e72 feat(memory): handle grant merges when mutating
This commit fixes the following panic when running nodejs:
```
KERNEL PANIC: panicked at src/context/memory.rs:267:18:
grant cannot magically disappear while we hold the lock!
  FP ffff80002021f650: PC ffffffff8005e45b
    FFFFFFFF8005E2E0+017B
    kernel::panic::panic_handler_inner
  FP ffff80002021f730: PC ffffffff80057559
  FP ffff80002021f740: PC ffffffff8009a0ff
  FP ffff80002021f770: PC ffffffff8009c214
  FP ffff80002021f7d0: PC ffffffff80010997
    FFFFFFFF8000FDD0+0BC7
    kernel::context::memory::AddrSpaceWrapper::mprotect
  FP ffff80002021fd40: PC ffffffff8008cb0b
    FFFFFFFF8008CA40+00CB
    kernel::syscall::process::mprotect
  FP ffff80002021fd70: PC ffffffff8006ce6c
    FFFFFFFF8006CBE0+028C
    kernel::syscall::syscall
  FP ffff80002021fe90: PC ffffffff8008d3cf
    FFFFFFFF8008D320+00AF
    __inner_syscall_instruction
  FP ffff80002021ff50: PC ffffffff800830c3
    FFFFFFFF80083080+0043
    kernel::arch::x86_64::interrupt::syscall::syscall_instruction
  00007ffffffffaf0: GUARD PAGE
CPU #1, CID 0xffffff7f8015b910
NAME: /usr/bin/node, DEBUG ID: 74
SYSCALL: mprotect(0x203C0000, 262144, Some(MapFlags(0x0)))
HALT
```

The grant did not magically disappear. When going through the
`grant_span_res` regions, the function adds (and removes) grants to the
`self.grants` tree. The insertion and deletion functions also merge
adjacent grants together when possible. This is an issue since we can no
longer use the keys we established before we started iterating. This
commit modifies the places where `remove` is used in this fashion to use
`remove_containing` instead. The `remove_containing` function will
remove the grant that *contains* the page.

Should it be done this way (requires unstable feature `btree_cursors`)?

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-02-21 00:59:24 +11:00
auronandace 6853592ce4 add precedence clippy lint 2026-02-20 13:15:32 +00:00
Anhad Singh b85c2d7889 misc(rmm): update submodule
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-02-20 00:26:47 +11:00
Jeremy Soller e543cbe621 Merge branch 'master' into 'master'
feat(mapper/remap_with_full): conditional remap

See merge request redox-os/rmm!20
2026-02-19 06:23:39 -07:00
Anhad Singh 124b74e816 fix(context/memory): Grant::remap delegate write
`Grant::remap` should not directly mark entries as writeable because the
entry could be private and requires Copy-On-Write (COW) handling. This
bug fixes the random panics that occur when running programs that
incorrectly mark private memory regions as writeable. This also
inadvertently caused other systems to crash. This is because The Zeroed
Frame is mapped instead of allocating a new zeroed memory region every
time. Only after the first write is the frame actually allocated. This
means that with this bug one could remap a freshly mmap'ed ANONYMOUS
region with the write flag and rewrite the contents of The Zeroed Frame,
which is a big problem. This means that any program that allocated
memory with the ANONYMOUS flag after this would not receive zeroed
memory.

Example of `make` hitting this bug when the shared `ld.so` patches are
applied:
```
....
[page at 0x48bd000] is mapped to the zeroed frame with PageFlags { present: true, write: false, executable: false, user: true, bits: 0x8000000000000005 }
[page at 0x49b1000] is mapped to the zeroed frame with PageFlags { present: true, write: true, executable: false, user: true, bits: 0x8000000000000007 }
[page at 0x49b2000] is mapped to the zeroed frame with PageFlags { present: true, write: true, executable: false, user: true, bits: 0x8000000000000007 }
[page at 0x49b3000] is mapped to the zeroed frame with PageFlags { present: true, write: true, executable: false, user: true, bits: 0x8000000000000007 }
[page at 0x49b4000] is mapped to the zeroed frame with PageFlags { present: true, write: true, executable: false, user: true, bits: 0x8000000000000007 }
0x43ff000..0x49b5000 :: MapFlags(PROT_WRITE | PROT_READ)
[page at 0x49b5000] is mapped to the zeroed frame with PageFlags { present: true, write: false, executable: false, user: true, bits: 0x8000000000000005 }
[page at 0x49b6000] is mapped to the zeroed frame with PageFlags { present: true, write: false, executable: false, user: true, bits: 0x8000000000000005 }
....
```

and causing the following crash:

```
Page fault: 0000000000001718 P | WR | US
RFLAG: 0000000000010202
CS:    000000000000002b
RIP:   00000000004125fd
RSP:   00007fffffffdd80
SS:    0000000000000023
FSBASE  00000000003f6000
GSBASE  0000000000000000
KGSBASE ffff80007a800000
RAX:   0000000000001718
RCX:   0000000000000000
RDX:   ffffffffffffffff
RDI:   000000000043b5a0
RSI:   00000000004537e0
R8:    0000000000000030
R9:    000000000043b5a0
R10:   0000000000000030
R11:   00000000000000ff
RBX:   0000000000000000
RBP:   00007fffffffddb0
R12:   000000000043b5a0
R13:   00000000004537e0
R14:   00000000004537e0
R15:   000000000043b5a0
  FP 00007fffffffddb0: PC 000000000042614a
  FP 00007fffffffde40: PC 0000000000411ae9
  FP 00007fffffffde80: PC 0000000000417187
  FP 00007fffffffdee0: PC 0000000000411d39
  FP 00007fffffffdf90: PC 000000000041207d
  FP 00007fffffffe020: PC 000000000040bc4c
  FP 00007fffffffe0c0: PC 000000000040c7c9
  FP 00007fffffffe0f0: PC 00000000004276ba
  FP 00007fffffffe1a0: PC 0000000000428087
  FP 00007fffffffe210: PC 000000000041eb6a
  FP 00007fffffffe400: PC 00000000004205c3
  FP 00007fffffffe490: PC 00000000004208dd
  FP 00007fffffffe4d0: PC 000000000040747e
  FP 00007ffffffffd60: PC 000000000092111c
  <Invalid next frame pointer 0x0000000000438490; stack walk ended>
  FP ffff80001b5bfe80: PC ffffffff80046dad
    FFFFFFFF80046BD0+01DD
    kernel::arch::x86_shared::interrupt::exception::page::inner
  FP ffff80001b5bff50: PC ffffffff8003ffbb
    FFFFFFFF8003FF84+0037
    kernel::arch::x86_shared::interrupt::exception::page
  00007fffffffddb0: GUARD PAGE
kernel::context::signal:INFO -- UNHANDLED EXCEPTION, CPU #1, PID 6548, NAME /usr/bin/make, CONTEXT 0xffffff7f8013fdc0
```

Also the crash info would vary every time you run the program since the
contents of The Zeroed Frame would have been mutated. Sneaky bug :^)

This also fixes the crashes that happen when running node.js (and maybe
other programs): https://gitlab.redox-os.org/redox-os/relibc/-/issues/229

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-02-19 19:54:14 +11:00
Anhad Singh d82ba37de8 feat(mapper/remap_with_full): conditional remap
This commit modifies the transform function (`f`) argument of
`remap_with_full` to return an `Option`. This allows the caller to skip
remaps based on the previous frame and page flags. It can alternatively
be done by first translating the address and then remapping based on
that but that would mean we have to walk the page tables twice :|

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-02-19 19:50:00 +11:00
Anhad Singh f299c885e6 feat(lib): implement Debug for PhysicalAddress
Make it consistent with the debug output for `VirtualAddress`

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-02-19 19:32:10 +11:00
Ibuki Omatsu 5a8858ff81 refactor: Initialize sys schem resources when they are first accessed. 2026-02-12 06:24:43 -07:00
Jeremy Soller 934162f35a Implement stdfscall 2026-02-11 12:12:49 -07:00
bjorn3 858b712df5 Use naked_asm!() instead of global_asm!() where possible 2026-02-09 22:28:38 +01:00
bjorn3 d51fe0c7e0 Avoid concat!() in inline asm
It is no longer necessary in modern rustc versions.
2026-02-09 22:12:20 +01:00
bjorn3 6bd204e1a3 Remove always true supports_on_close field 2026-02-08 17:23:50 +01:00
bjorn3 4c2c2b6757 Remove Option from State::Waiting.fds 2026-02-08 17:08:59 +01:00
bjorn3 0576db1fb4 Inline UserInner::call and rename call_extended to call 2026-02-08 13:01:14 +01:00
bjorn3 3d1188cf1e Introduce Response::as_regular 2026-02-08 12:54:04 +01:00
bjorn3 99ff55ee1b Demux results as soon as we receive them from a user scheme 2026-02-08 12:50:53 +01:00
bjorn3 f88cbf96ee Remove unnecessary clones and pass CallerCtx to call() 2026-02-08 12:46:08 +01:00
bjorn3 5c6af01a9a Remove two unnecessary uses of spin::Once 2026-02-07 13:14:48 +01:00
bjorn3 e14a20aae2 Mark two functions as private 2026-02-07 12:59:24 +01:00
bjorn3 4e41ed987a Fix /scheme/sys/context header 2026-02-07 12:31:42 +01:00
bjorn3 2f8a3b3d67 Remove unused SchemeNamespace type 2026-02-06 22:05:42 +01:00
bjorn3 f334e760bb Remove ens field from Context
It is no longer used due to the capability rework.
2026-02-06 22:00:18 +01:00
bjorn3 9f218c5b3a Fix assertion in Args::args() 2026-02-06 21:07:16 +01:00
bjorn3 7ff1898765 Fix a couple of warnings 2026-02-06 20:54:42 +01:00
bjorn3 6ddd0a9098 Replace scheme::schemes() with scheme::get_scheme()
We never need to iterate over all schemes. We only ever need to access
individual schemes.
2026-02-06 20:54:42 +01:00
bjorn3 ace9038720 Reduce visibility of a couple of methods 2026-02-06 20:34:16 +01:00
Jeremy Soller 2055a205f1 Remove legacy path message 2026-01-29 10:12:04 -07:00
Ibuki Omatsu 5ac00f5533 Remove namespace management from the kernel. 2026-01-20 20:43:34 -07:00
Jeremy Soller 1c850605d0 Only read time once during context switch 2026-01-20 14:18:33 -07:00
Jeremy Soller 81a49d211b Fix potential preempt guard deadlock 2026-01-20 13:58:31 -07:00
Anhad Singh 7d42e8d966 fix(switch): deadlock
During the snapshot shown, interrupts would be _disabled_ on both CPUs and both
would have have the _same_ address space (i.e.
`PercpuBlock::current().current_addrsp`).

```rs
// CPU 0                                                                                             CPU 1 (inside `context::switch()`)
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// let guard = current_addrsp.acquire_write()
// let flusher = Flusher::with_cpu_set(&addrsp.used_by, &current_addrsp.tlb_ack);
// ...
// drop(flusher); // Flusher::flush()
//     // send IPI to CPU 1 as it is in the `active_set`
//     shootdown_tlb_ipi(Some(1));
//                                                                                                    percpu::switch_arch_hook();
//     // spin until TLB shootdown IPI has been acknowledged by CPU 1                                 // acquire_read() to remove the CPU from the `used_by` set in `prev_addrsp`
//     while ackword < affected_cpu_count                                                             prev_addrsp.acquire_read()
//         PercpuBlock::current().maybe_handle_tlb_shootdown();
//         spin_loop();
//     }
// drop(guard);
```

Now CPU 0 will spin _until_ CPU 1 has acknowledged the IPI. However, CPU 1 has
interrupts disabled and is in the middle of a context switch. To complete the
context switch it needs to remove itself from the `used_by` set in
`prev_addrsp` (which is the current address space atm). To do that it needs to
`acquire_read()` lock but it cannot since it is held by CPU 0 and won't release
it until CPU 1 has acknowledged the IPI; creating a deadlock.

Also note:

```rs
// src/context/memory.rs
// NOTE: Lock must be held, which must be guaranteed by the caller.
pub fn flush(&mut self) {
```

Here is some output from GDB to back this up:

```
pwndbg> info threads
  Id   Target Id                    Frame
  1    Thread 1.1 (CPU#0 [running]) core::sync::atomic::atomic_compare_exchange_weak<usize> (dst=0xffffff7f801972f0, old=0, new=1, success=core::sync::atomic::Ordering::Acquire, failure=core::sync::atomic::Ordering::Relaxed)
    at /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/sync/atomic.rs:4100
  2    Thread 1.2 (CPU#1 [running]) kernel::context::memory::Flusher::flush (self=0xffff80004212f4b8) at src/context/memory.rs:2827
  3    Thread 1.3 (CPU#2 [running]) spin::rwlock::RwLock<kernel::context::context::Context, spin::relax::Spin>::write<kernel::context::context::Context, spin::relax::Spin> (self=0xffffff7f801a99c0)
    at /root/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/spin-0.9.8/src/rwlock.rs:239
* 4    Thread 1.4 (CPU#3 [running]) 0xffffffff80059cf9 in kernel::context::memory::AddrSpaceWrapper::acquire_read (self=0xffffff7f80188110)
    at /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/../../stdarch/crates/core_arch/src/x86/sse2.rs:25
pwndbg> p kernel::context::arch::CONTEXT_SWITCH_LOCK
$1 = core::sync::atomic::AtomicBool {
  v: core::cell::UnsafeCell<u8> {
    value: 1
  }
}
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[0].p.value).wants_tlb_shootdown.v.value
$2 = 0
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[1].p.value).wants_tlb_shootdown.v.value
$3 = 0
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[2].p.value).wants_tlb_shootdown.v.value
$4 = 1
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[3].p.value).wants_tlb_shootdown.v.value
$5 = 0
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[3].p.value).current_addrsp
$6 = core::cell::RefCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
  borrow: core::cell::Cell<isize> {
    value: core::cell::UnsafeCell<isize> {
      value: 0
    }
  },
  value: core::cell::UnsafeCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
    value: core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>::Some(alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global> {
        ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>> {
          pointer: 0xffffff7f80188100
        },
        phantom: core::marker::PhantomData<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>>,
        alloc: alloc::alloc::Global
      })
  }
}
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[2].p.value).current_addrsp
$7 = core::cell::RefCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
  borrow: core::cell::Cell<isize> {
    value: core::cell::UnsafeCell<isize> {
      value: 0
    }
  },
  value: core::cell::UnsafeCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
    value: core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>::Some(alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global> {
        ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>> {
          pointer: 0xffffff7f80188100
        },
        phantom: core::marker::PhantomData<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>>,
        alloc: alloc::alloc::Global
      })
  }
}
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[1].p.value).current_addrsp
$8 = core::cell::RefCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
  borrow: core::cell::Cell<isize> {
    value: core::cell::UnsafeCell<isize> {
      value: 0
    }
  },
  value: core::cell::UnsafeCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
    value: core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>::Some(alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global> {
        ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>> {
          pointer: 0xffffff7f80188100
        },
        phantom: core::marker::PhantomData<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>>,
        alloc: alloc::alloc::Global
      })
  }
}
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[0].p.value).current_addrsp
$9 = core::cell::RefCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
  borrow: core::cell::Cell<isize> {
    value: core::cell::UnsafeCell<isize> {
      value: 0
    }
  },
  value: core::cell::UnsafeCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
    value: core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>::Some(alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global> {
        ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>> {
          pointer: 0xffffff7f80133ac8
        },
        phantom: core::marker::PhantomData<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>>,
        alloc: alloc::alloc::Global
      })
  }
}
```

```
pwndbg> thread 4
[Switching to thread 4 (Thread 1.4)]
25	in /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/../../stdarch/crates/core_arch/src/x86/sse2.rs
pwndbg> info threads
  Id   Target Id                    Frame
  1    Thread 1.1 (CPU#0 [running]) core::sync::atomic::atomic_compare_exchange_weak<usize> (dst=0xffffff7f801972f0, old=0, new=1, success=core::sync::atomic::Ordering::Acquire, failure=core::sync::atomic::Ordering::Relaxed)
    at /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/sync/atomic.rs:4100
  2    Thread 1.2 (CPU#1 [running]) kernel::context::memory::Flusher::flush (self=0xffff80004212f4b8) at src/context/memory.rs:2827
  3    Thread 1.3 (CPU#2 [running]) spin::rwlock::RwLock<kernel::context::context::Context, spin::relax::Spin>::write<kernel::context::context::Context, spin::relax::Spin> (self=0xffffff7f801a99c0)
    at /root/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/spin-0.9.8/src/rwlock.rs:239
* 4    Thread 1.4 (CPU#3 [running]) 0xffffffff80059cf9 in kernel::context::memory::AddrSpaceWrapper::acquire_read (self=0xffffff7f80188110)
    at /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/../../stdarch/crates/core_arch/src/x86/sse2.rs:25
pwndbg> thread 4
[Switching to thread 4 (Thread 1.4)]
25	in /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/../../stdarch/crates/core_arch/src/x86/sse2.rs
pwndbg> bt
```

This is *after* everything freezes.

For relibc tests, if I run `while true; do
/root/relibc-tests/pthread/once; done` it eventually does freeze up and
does so at the same location:

```
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ THREADS (4 TOTAL) ]──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  ► 1   "" stopped: 0xffffffff800750a2 <kernel::context::switch::switch+1282>
    4   "" stopped: 0xffffffff80074d5a <kernel::context::switch::switch+442>
    3   "" stopped: 0xffffffff80059cf9 <kernel::context::context::Context::set_addr_space+217>
    2   "" stopped: 0xffffffff80020839 <kernel::context::memory::Flusher::flush+361>
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
```

Related: https://gitlab.redox-os.org/redox-os/kernel/-/issues/175

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-01-19 15:21:13 +11:00
Pascal Reich a919d2626b Inline Documentation Fixes 2026-01-10 16:19:34 -07:00
Jeremy Soller ea06685903 Do not allow recursively registering the same event queue 2026-01-09 12:08:16 -07:00
Anhad Singh a245e49e75 fix(syscalls/futex): premature timeout
Previously, if a futex with a timeout was woken up (even via
`futex_wake`), it was treated as though the timeout had expired. When
the timeout expires, the scheduler sets `wake` to `None` and unblocks
the process. Hence if `wake` is `None` and if a timeout was given to
futex, it has expired. Otherwise the process was woken up by
`futex_wake`.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-01-07 14:45:01 +11:00
Anhad Singh 5ccd2414af fix(context/memory): incorrect remaining_src_span
The `AddrSpaceWrapper::r#move` is used by `mremap` to move, expand or
shrink existing mappings.

`src_span.count`: Size of old region in pages
`new_page_count`: Size of new region in pages

Fixes the following panic when running `cargo`:

```
KERNEL PANIC: panicked at src/context/memory.rs:1969:9:
assertion failed: self.info.can_extract(false)
  FP ffff80000cbbf2c0: PC ffffffff8004ced5
    FFFFFFFF8004CD50+0185
    kernel::panic::panic_handler_inner
  FP ffff80000cbbf3a0: PC ffffffff8004ac99
  FP ffff80000cbbf3b0: PC ffffffff800a34df
  FP ffff80000cbbf3e0: PC ffffffff800a34b4
  FP ffff80000cbbf430: PC ffffffff8001c029
    FFFFFFFF8001BF10+0119
    kernel::context::memory::Grant::extract
  FP ffff80000cbbf4a0: PC ffffffff800181ac
    FFFFFFFF80016D30+147C
    kernel::context::memory::AddrSpaceWrapper::move
  FP ffff80000cbbfd30: PC ffffffff80037c08
    FFFFFFFF80035660+25A8
    kernel::syscall::syscall
  FP ffff80000cbbfe90: PC ffffffff8008efbf
    FFFFFFFF8008EF10+00AF
    __inner_syscall_instruction
  FP ffff80000cbbff50: PC ffffffff80085d33
    FFFFFFFF80085CF0+0043
    kernel::arch::x86_64::interrupt::syscall::syscall_instruction
  0000000000004455: GUARD PAGE
CPU #2, CID 0xffffff7f80133690
NAME: /scheme/initfs/bin/redoxfs, DEBUG ID: 43
SYSCALL: mremap(0x2177F000, 0x8000, 0x0, 0xC7000, 0x60000)
HALT
```

```
mremap_flags = MremapFlags(
    0x0,
)
prot_flags = MapFlags(
    PROT_WRITE | PROT_READ,
)
```

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-01-03 22:56:03 +11:00
Wildan M 92132132c1 Implement clock_getres and handle path to time scheme 2025-12-21 05:24:13 +07:00
Ibuki Omatsu e30ed9ab6a Introduce syscall6. Add unlinkat and remove unlink and rmdir. 2025-12-17 18:31:04 -07:00
Anhad Singh d9eae6bb75 fix(sync/wait_condition): deadlock in WaitCondition::wait
Instead of using a simple switch to determine if preemption is enabled
(`is_preemptable: bool`), a counter is used instead. This handles the
case where a function holding a `PreemptGuard` calls another function
that creates a new `PreemptGuard`.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-12-15 13:05:29 +11:00
bjorn3 62a572a0f0 Use compiler-builtins for the memcpy family of functions 2025-12-14 16:38:04 +01:00
bjorn3 c089667ade Remove support for the legacy packet user schemes 2025-12-13 15:52:30 +01:00
bjorn3 3091f40c13 Warn against opening a legacy scheme version 2025-12-13 15:12:01 +01:00
Wildan M e06f908b1b Add CI workflow 2025-12-11 01:07:33 +07:00
bjorn3 3bf880e008 Correctly handle MAP_FIXED with a zero address 2025-12-09 23:09:19 +01:00
bjorn3 5a11067f10 Support non-fixed and anonymous remote mmap 2025-12-09 20:55:19 +01:00
Jeremy Soller d33fc3b5b0 Merge branch 'mmu_flags' into 'master'
Set RISCV MMU marker flags by default

See merge request redox-os/rmm!18
2025-12-09 06:28:44 -07:00
aarch 5b149b7fe4 Set RISCV MMU marker flags by default 2025-12-09 06:28:44 -07:00
bjorn3 58a362844a Add a binary variant for the filetable read operation
This is a lot easier to parse in no_alloc scenarios than the current
textual format. This would help with moving the cloexec handling from
relibc to redox-rt.
2025-12-08 21:55:03 +01:00
Anhad Singh ac713a061c misc(scheme/user): treat all spurious wakeups as signal
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-11-28 15:24:32 +11:00
Anhad Singh 45aae5f963 misc(scheme/user): use preempt guard
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-11-27 16:23:31 +11:00
Anhad Singh b2c9e5defd misc(scheme/user): unblock the process *after* setting the state
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-11-27 16:21:03 +11:00
Anhad Singh 4ff82ad8b5 fix(scheme/user): deadlocks inside call_extended_inner
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-11-27 14:39:14 +11:00
Jeremy Soller 27465b6132 Make CPU announcements debug level 2025-11-23 07:41:09 -07:00
Jeremy Soller 7ffc046d46 Enable serial interrupts on aarch64 ACPI 2025-11-21 08:39:38 -07:00
Jeremy Soller e3cafc975f Format 2025-11-17 17:41:04 -07:00
Jeremy Soller 91ba44e2fa Implement F_DUPFD_CLOEXEC 2025-11-17 17:40:39 -07:00
aarch 2bdc5d2109 Implement kfpath for dtb kernel scheme 2025-11-15 17:45:39 +00:00
Jeremy Soller e14f935063 Ensure pipe is_alive is set before triggering event or condition 2025-11-14 20:59:44 -07:00
Jeremy Soller 2d9f2015d0 Add upper table fds to kernel.proc filetable 2025-11-14 15:06:37 -07:00
Jeremy Soller 42f9f04188 Require kfpath implementation, add to acpi scheme 2025-11-14 14:19:33 -07:00
Jeremy Soller 61ad67fbfe Improve display of upper table in iostat 2025-11-14 13:55:55 -07:00
4lDO2 33dbf2458e only clear RC_USED_NOT_FREE with freelist locked 2025-11-14 20:06:18 +01:00
4lDO2 96552163f6 Clear RC_USED_NOT_FREE even for contention case. 2025-11-14 20:06:18 +01:00
4lDO2 dc33c67997 Fix potential refcount underflow from fetch_sub. 2025-11-14 20:06:18 +01:00
Jeremy Soller cbea1aca3d Implement kfpath on more schemes 2025-11-14 11:36:49 -07:00
Jeremy Soller 64ea4251ee Debug SYS_MREMAP 2025-11-13 15:55:02 -07:00
Jeremy Soller e6edef2d8e Downgrade addrspace outside futex loop 2025-11-12 10:34:18 -07:00
Jeremy Soller 7834392dba Use hashmap for futex 2025-11-12 08:03:24 -07:00
Jeremy Soller f9d9a3414b Update rmm 2025-11-12 07:37:14 -07:00
Jeremy Soller 409a1c02f5 Derive Hash for PhysicalAddress 2025-11-12 07:36:54 -07:00
4lDO2 70256a5b2f Revert "Fix i686 using cmpxchg8b-based AtomicU64 for stats."
This reverts commit 21f2d8f3e4.
2025-11-12 11:07:09 +01:00
4lDO2 21f2d8f3e4 Fix i686 using cmpxchg8b-based AtomicU64 for stats. 2025-11-12 10:59:51 +01:00
bjorn3 00fdfaf11c Remove -Csoft-float from clippy.sh
It doesn't do anything and will be removed in a future rustc version.
Usage was already removed from the Makefile previously.
2025-11-11 13:40:48 +00:00
Jeremy Soller 01ec650b1e Add support for userspace stack traces using usercopy 2025-11-10 08:54:06 -07:00
Jeremy Soller c66423cec6 Sort target json and allow AtomicU64 on i586/i686 2025-11-10 08:53:47 -07:00
Jeremy Soller 531dfaa3e1 Format 2025-11-06 22:14:25 -07:00
Jeremy Soller 8ae1ced55d Recursively trigger event queues 2025-11-06 22:14:13 -07:00
Jeremy Soller c3437ab6eb Ignore any opens with event: or time: 2025-11-06 09:15:52 -07:00
Jeremy Soller 60af085356 Improve cpu stat accuracy 2025-11-03 20:42:08 -07:00
Jeremy Soller aa50069e15 Remove unnecessary log 2025-11-01 20:49:06 -06:00
Jeremy Soller 91b835d29f Reduce logging significantly 2025-11-01 20:24:11 -06:00
Jeremy Soller 64f2314e2c Fix makefile ifeq 2025-11-01 14:02:34 -06:00
bjorn3 301f163112 Handle building for i586-unknown-redox 2025-11-01 19:30:40 +01:00
bjorn3 65273ea898 Replace all Arc::try_new with Arc::new
The global allocator panics when out of memory rather than returning an
errors. In addition there are plenty of other places where we don't
handle allocation failure anyway. At some point in the future we should
systematically handle out of memory conditions, but until then let's not
pretend we do and get rid of the usage of the unstable allocator_api
feature that is unlikely to get stabilized any time soon.
2025-10-26 12:44:52 -06:00
bjorn3 e101629377 Inline a bunch of functions in KernelMapper 2025-10-26 12:44:52 -06:00
bjorn3 85b5487b5b Couple minor cleanups to the global allocator 2025-10-26 12:44:52 -06:00
bjorn3 3b1fd27431 Remove byteorder dependency 2025-10-26 12:43:08 -06:00
bjorn3 bc3a59abb3 Minor simplification to profiling::nmi_handler 2025-10-26 18:27:29 +01:00
bjorn3 0f7b16d89d Partially use cfg!() rather than #[cfg] for controlling the profiling module
This only adds a pointer worth of overhead per cpu core in the
PerCpuBlock struct.

Also fix a bunch of unsafe_op_in_unsafe_fn warnings in the profiling
code.
2025-10-26 18:27:29 +01:00
bjorn3 53640e67b7 Remove rustc_cfg dependency 2025-10-26 16:32:42 +01:00
bjorn3 8367462abe Update rmm submodule 2025-10-26 16:25:01 +01:00
Jeremy Soller 7e14945bc5 Merge branch 'stable' into 'master'
Remove all nighly feature gates

See merge request redox-os/rmm!17
2025-10-26 09:18:30 -06:00
bjorn3 4b89feab41 Fix a couple of dead code warnings 2025-10-26 12:07:56 +01:00
bjorn3 075d52f153 Fix example binary 2025-10-26 11:58:43 +01:00
bjorn3 e6d42dda19 Fix compilation of EmulateArch 2025-10-26 11:55:42 +01:00
bjorn3 5b5bbe5643 Remove VirtualAddress::is_canonical
This way the last remaining feature gate can be removed. It also matches
how other architectures handle this functionality.
2025-10-25 20:02:55 +02:00
bjorn3 e371f47f51 Remove let_chain feature gate
It is now stable.
2025-10-25 20:01:32 +02:00
bjorn3 1498376360 Unify generic irq handling between x86 and x86_64 2025-10-25 19:44:03 +02:00
bjorn3 3652b693ba Remove usage of iterator_try_collect 2025-10-25 11:34:55 -06:00
bjorn3 164c890830 Remove thread_local feature gate
We use the PerCpuBlock instead of ELF TLS
2025-10-25 11:34:55 -06:00
bjorn3 cb718f767a Remove a bunch of unused __*_start/end symbols 2025-10-25 19:20:01 +02:00
bjorn3 e8acd82074 Directly define __usercopy_{start,end} in the usercopy functions
As opposed to requiring a linker script
2025-10-25 19:12:27 +02:00
bjorn3 cc01d14d3b Unconditionally enable sys_stat 2025-10-25 18:52:07 +02:00
bjorn3 a57c8e410d Avoid warnings from rust-analyzer for the panic handler
Rust-analyzer runs cargo check --all-targets which also checks the test
configuration where previously there would be a bunch of warnings for
unused things due to the panic handler being configured out.
2025-10-19 14:30:53 +02:00
bjorn3 021cdf47f4 Fix a bunch of warnings 2025-10-19 14:27:43 +02:00
bjorn3 9d5ad06b30 Move some code from the trampoline to global_asm!() 2025-10-19 06:23:39 -06:00
bjorn3 4b16e66164 Set arm64 exception handler before entering the rust world 2025-10-19 06:23:39 -06:00
bjorn3 d31e552d08 Set riscv exception handler before entering the rust world 2025-10-19 06:23:39 -06:00
bjorn3 ff65afd003 Don't depend on the stack setup by the bootloader
This way we can choose our own size for the stack and don't have to
identity map it manually. Also this way the bootloader doesn't have to
change the stack pointer right before calling into the kernel (which it
currently does in an unsound way)
2025-10-19 06:23:39 -06:00
bjorn3 b7a69a26ba Reduce indentation in madt x86 init 2025-10-19 06:23:39 -06:00
bjorn3 7ea41f4fee Remove no longer necessary lint allow 2025-10-19 11:49:14 +02:00
bjorn3 b09659ac25 Remove unnecessary unsafe blocks in naked functions 2025-10-19 11:48:46 +02:00
Jeremy Soller 3c3eaa0004 Enable sys_stat by default for sysinfo 2025-10-12 15:49:35 -06:00
Jeremy Soller c9653525a0 Fix compilation with sys_stat feature 2025-10-12 15:45:50 -06:00
Speedy_Lex 0931a7f49f Resolve a huge portion of the clippy lints 2025-10-06 06:30:23 -06:00
Jeremy Soller db8fb14614 Fix compilation on other archs 2025-10-04 11:58:04 -06:00
Jeremy Soller 18bf5d904b Fix aarch64 kernel target 2025-10-04 11:53:51 -06:00
Jeremy Soller e635e7a911 Fix i686 kernel target 2025-10-04 11:53:01 -06:00
Jeremy Soller f7fa2491ac Add rust-toolchain.toml 2025-10-04 09:18:10 -06:00
Jeremy Soller 84385222e2 Use x86-softfloat rustc-abi for x86_64 target 2025-10-04 08:21:00 -06:00
4lDO2 8d50ebd69d Fix target spec int vs string. 2025-10-04 16:12:54 +02:00
Speedy_Lex ea812e8f2a Run cargo fmt 2025-10-04 01:06:15 +02:00
Speedy_Lex d38002969c Fixes for rust update 2025-10-04 00:55:26 +02:00
bjorn3 bc9273057d Remove a bunch of double references from AddrSpaceWrapper::move 2025-10-03 20:53:26 +02:00
bjorn3 db5e6184af Remove unnecessary add_ref in ProcScheme::kfmap
Grant::allocated_shared_one_page already adds a reference. This fixes a
memory leak
2025-09-27 19:44:26 +02:00
bjorn3 6445f04ac4 Avoid overwriting expected count for special frames used by multiple contexts 2025-09-26 23:38:30 +02:00
bjorn3 4db2c919ef Nicer printing of frame refcount mismatch 2025-09-26 23:28:01 +02:00
bjorn3 cd761ee679 Handle all cases in foreach_addrsp 2025-09-26 23:28:01 +02:00
bjorn3 12f908b1ba Take sighandler frames into account during the integrity check 2025-09-26 23:28:01 +02:00
bjorn3 4c85131e36 Always take syscall_head/tail into account during the integrity check
Previously it wouldn't be taken into account if currently used by the
kernel.
2025-09-26 23:28:01 +02:00
bjorn3 ede9a47f9c Move .bss and .data tests to inline asm
If .bss is not properly cleared or .data is incorrectly cleared, there
is no way to tell what will happen if we try to run Rust code.
2025-09-25 09:46:17 -06:00
bjorn3 ac35b7984a Fix kernel debugger 2025-09-25 17:26:31 +02:00
Jeremy Soller 0203ad750a Fix compilation on aarch64/riscv64gc 2025-09-23 13:46:44 -06:00
Jeremy Soller 4526acc259 Drop comment about fixed multi_core issues 2025-09-23 13:09:32 -06:00
Jeremy Soller b0d5fa0993 Copy all higher PML4 entries in setup_new_utable (fixes some AMD CPUs) 2025-09-23 13:09:12 -06:00
Jeremy Soller 89c182cca1 Restore return in percpu::switch_arch_hook 2025-09-23 13:08:34 -06:00
Jeremy Soller b6a5245556 Require passing loopback test for hard-coded serial 2025-09-23 11:33:37 -06:00
Jeremy Soller 6ce2101cf4 Do not mark soc ranges as device memory 2025-09-23 10:31:34 -06:00
Jeremy Soller 5dc6f7c3ba lock ordering 2025-09-22 07:48:48 -06:00
bjorn3 e7358e3e5b Deduplicate a bunch of things that use KernelArgs between archs 2025-09-20 19:10:19 +02:00
bjorn3 3f385ba79d Unify KernelArgs type between architectures 2025-09-20 19:10:19 +02:00
bjorn3 c35c17c67e Merge display.rs into debug.rs 2025-09-20 17:59:19 +02:00
bjorn3 b36deffa61 Replace scrolling with wraparound in graphical debug
Inspired by how Haiku does printing for its kernel debugger, this commit
gets rid of the scrolling when the bootlog reaches the end of the screen
and instead wraps around to the start of the screen. Between the last
written line and the first visible written line there is always a blank
line to provide visual separation.

Getting rid of the scrolling significantly simplifies the implementation
of graphical debug and removes the need for double buffering for
performance as we no longer need to read back the framebuffer when
scrolling which is very expensive on write-combining memory like the
framebuffer.
2025-09-20 17:15:02 +02:00
bjorn3 84ac36ca2f Inline DebugDisplay::write_char 2025-09-20 15:42:08 +02:00
bjorn3 3db8bf878e Remove workaround for Meteor Lake having an AP with hardware cpu id 0 2025-09-20 15:33:08 +02:00
bjorn3 f58bcd584e Separate logical and hardware cpu ids 2025-09-20 15:33:08 +02:00
bjorn3 3a47c3becc Move most HPET logs to the trace log level
This significantly reduces the amount of boot logs produced by the
kernel by default on x86. With this the full kernel boot logs now fit on
a single screen on my system.
2025-09-20 15:21:54 +02:00
bjorn3 99b626845d Cleanup after removing INIT_THREAD 2025-09-20 15:21:38 +02:00
Jeremy Soller 229a5de6ff Remove INIT_THREAD 2025-09-19 20:30:26 -06:00
Jeremy Soller 7abe4e1051 Remove slab allocator 2025-09-19 20:29:53 -06:00
Jeremy Soller eb69d37323 Apply 1 suggestion(s) to 1 file(s)
Co-authored-by: bjorn3 <4397-bjorn3@users.noreply.gitlab.redox-os.org>
2025-09-19 06:43:19 -06:00
Elle Rhumsaa 8255e74ffd fixup: scheme: remove unnecessary braces
Removes unnecessary braces to fix compilation error.

Signed-off-by: Elle Rhumsaa <elle@weathered-steel.dev>
2025-09-19 06:43:19 -06:00
Elle Rhumsaa 0022bd448c dtb: remove allocation for in-memory DTB
Replaces the `Once<Vec<u8>>` with `Once<&'static [u8]>` to avoid an
unnecessary allocation.

Adds some basic documentation.

Signed-off-by: Elle Rhumsaa <elle@weathered-steel.dev>
2025-09-19 06:43:19 -06:00
bjorn3 68526b2af5 Use naked asm for riscv exception handler 2025-09-18 17:29:50 +02:00
bjorn3 081efd6cfa Allocate IDT for APs on the BSP and statically allocate BSP IDT
This allows them to be immediately installed by kstart/kstart_ap without
having to wait for the page tables to be set up correctly. This removes
the initial IDT.
2025-09-17 21:03:36 +02:00
bjorn3 e81db007b7 Couple of cleanups to the IDT handling 2025-09-17 21:03:36 +02:00
bjorn3 742a7f4492 Remove Option around IDTs HashMap 2025-09-17 21:03:36 +02:00
Jeremy Soller 2bf580b260 Reimplement iostat 2025-09-16 20:39:06 -06:00
bjorn3 25d526e9a1 Inline load_segments 2025-09-16 19:58:56 +02:00
bjorn3 647c87c5a0 Allocate PCR for APs on the BSP
This allows them to be immediately installed by kstart_ap without having
to wait for the page tables to be set up correctly. This removes the
initial GDT.
2025-09-16 19:57:31 +02:00
bjorn3 dbe25b78e3 Make it possible to change KernelArgsAp without changing the trampolines 2025-09-16 19:33:07 +02:00
bjorn3 019564ee0e Statically allocate PCR for the BSP 2025-09-15 22:01:15 +02:00
bjorn3 4884d749af Make PercpuBlock const constructable 2025-09-15 19:00:03 +02:00
bjorn3 3329a41121 Unify set_tss_stack and set_userspace_io_allowed signatures between x86 and x86_64 2025-09-15 18:37:27 +02:00
bjorn3 05e344bd9e Unify tss alignment method between x86 and x86_64 2025-09-15 18:23:29 +02:00
bjorn3 9a14f9a80d Unify gdt handling between x86 and x86_64 2025-09-14 20:30:57 +02:00
bjorn3 d1c7177038 Remove unused macro 2025-09-14 20:21:46 +02:00
bjorn3 200aeac2ba Reduce visibility of a couple of idt things 2025-09-14 19:10:09 +02:00
bjorn3 d3b17177b2 Avoid allocating during panics and infer kernel image size without explicitly storing it 2025-09-14 13:11:13 +02:00
bjorn3 9f71f02532 Reduce indentation in stack_trace 2025-09-13 21:34:02 +02:00
bjorn3 6334977090 Inline symbol_trace into strack_trace 2025-09-13 21:34:02 +02:00
bjorn3 30bbafdfa4 Use the object crate for panic backtraces
This increases the kernel image size by about 16kb, but in return
significantly simplifies things.
2025-09-13 21:34:02 +02:00
bjorn3 ad4ea619e8 Fix interrupt race condition on arm64 and riscv64 2025-09-13 20:29:32 +02:00
bjorn3 9e37ccaae8 Fix enable_and_halt on arm64
I accidentally used nop instead of wfi
2025-09-13 19:07:01 +02:00
bjorn3 83b4538d7c Merge two asm blocks
There is no guarantee they will be atomic otherwise
2025-09-13 18:55:16 +02:00
bjorn3 61db2b2ad5 Use core::hint::spin_loop() where possible 2025-09-13 18:55:16 +02:00
bjorn3 711ea9a4ed Move system76_ec::init() into serial::init() 2025-09-13 18:55:16 +02:00
bjorn3 5a6117b5ae Replace the log crate with a custom logging system
This avoids the need to explicitly set a logger early during boot, which
reduces the amount of moving parts that could go wrong slightly. And it
cuts the kernel image size by 13kb.
2025-09-13 18:55:16 +02:00
Jeremy Soller 8a2aa411e2 Explicitly scope all locks, fixing multi_core hangs. Allow contexts on any CPU 2025-09-13 10:10:07 -06:00
bjorn3 da6f7adb42 Use HashMap rather than BTreeMap for scheme handles
According to the comments this previously wasn't done due to hashbrown
not having a const constructor. While it is true that HashMap::new() is
not const, HashMap::with_hasher() is const. HashMap::new() becoming
const is likely blocked on const traits.

This shrinks the kernel image by about 35kb.
2025-09-13 12:00:37 +02:00
bjorn3 9aef07372e Make insert_global panic on errors
All callers unwrap the result anyway
2025-09-12 19:56:14 +02:00
bjorn3 6ae6f571c7 Use cfg!() rather than #[cfg] for configuring lpss_debug 2025-09-12 19:36:17 +02:00
bjorn3 92e5397efa Introduce SerialKind::NotPresent 2025-09-12 19:36:17 +02:00
bjorn3 2394db2dc5 Move most of the arch debug::Writer impls into a common location 2025-09-12 19:36:17 +02:00
bjorn3 fbbe24c82b Use writeln!() rather than print!() + concat!() in println!()
This fixes using format arg captures
2025-09-12 19:36:17 +02:00
bjorn3 b3522b19e6 Replace a writeln!() with println!() 2025-09-12 19:36:16 +02:00
bjorn3 a782c1f9e1 Fix warning about unused function 2025-09-12 19:03:39 +02:00
bjorn3 8aa08e1e3d Unconditionally enable serial_debug on arm64 and riscv64 2025-09-12 18:59:48 +02:00
bjorn3 520453f779 Move x86 serial port assignment to the init function 2025-09-12 18:46:11 +02:00
bjorn3 31cbb3b361 Remove duplicate serial port initialization on x86 2025-09-12 18:41:42 +02:00
bjorn3 7a4dd1a1a9 Use SerialKind on x86 2025-09-12 18:40:21 +02:00
bjorn3 f0eea47896 Fix compilation with lpss_debug feature enabled 2025-09-12 18:33:16 +02:00
bjorn3 eb06f5676f Unify SerialKind between arm64 and riscv64 2025-09-12 18:19:15 +02:00
bjorn3 6ca9a9a806 Move uart_pl011.rs to src/devices 2025-09-12 18:02:30 +02:00
bjorn3 f9a4178898 Always enable graphical_debug
We already gracefully handle a missing framebuffer.
2025-09-11 21:41:30 +02:00
bjorn3 9a2203076a Merge aarch64 and x86/x86_64 debugger implementations
And make the debugger partially work on riscv64.
2025-09-11 20:02:56 +02:00
bjorn3 e131bf219d Merge x86 and x86_64 debugger implementations 2025-09-11 20:02:56 +02:00
bjorn3 d1668e232a Begin deduplicating debugger code between architectures 2025-09-11 20:02:56 +02:00
bjorn3 40605e643e Move stac/clac for SMAP in debugger to just around the stack read loop
This fixes a crash when returning from the debugger on x86_64.
2025-09-11 20:02:56 +02:00
bjorn3 26dd87b1ff Fix debugger feature on arm64
And fix unsafe_op_in_unsafe_fn warnings
2025-09-11 20:02:56 +02:00
bjorn3 38188b0640 Expand a macro invocation 2025-09-10 18:45:13 +02:00
bjorn3 786c9eabcb Share print! and println! between architectures 2025-09-10 18:40:30 +02:00
bjorn3 1268472103 Move arch::x86_64::cpuid into arch::x86_shared::cpuid 2025-09-10 18:35:36 +02:00
bjorn3 ad6c6c5e41 Share external interrupt handlers between x86 and x86_64 2025-09-10 18:31:28 +02:00
bjorn3 5e6d681fcb Share exception interrupt handlers between x86 and x86_64 2025-09-10 18:25:22 +02:00
bjorn3 d6c5d0d268 Move semicolons 2025-09-10 18:25:09 +02:00
bjorn3 35a0f2d440 Remove usage of array_chunks
It has been removed in newer rustc versions
2025-09-10 18:00:02 +02:00
bjorn3 a3700fa446 Remove the unsafe block from the inner function in interrupt!() 2025-09-10 18:00:02 +02:00
Elle Rhumsaa cec902e6be main: refactor unsafe block for C offsets
Uses the `&raw const` syntax to convert the pointer location of static
offsets from C.
2025-09-10 14:55:36 +00:00
bjorn3 fe1c2f460e Fix a bunch of errors and warnings after moving to the 2024 edition 2025-09-10 16:44:36 +02:00
bjorn3 cea93f7647 cargo fix --edition & rustfmt
Or to be precise:
RUST_TARGET_PATH=$(pwd)/targets cargo fix --edition \
--target targets/x86_64-unknown-kernel.json \
--target targets/i686-unknown-kernel.json \
--target targets/aarch64-unknown-kernel.json \
--target targets/riscv64-unknown-kernel.json \
-Zbuild-std=core,alloc --allow-dirty --bin kernel
cargo fmt
2025-09-10 16:44:36 +02:00
bjorn3 ff48830c0b Update rmm submodule 2025-09-10 16:44:33 +02:00
Jeremy Soller 5f983a02fe Merge branch 'edition_2024' into 'master'
Update to the 2024 edition

See merge request redox-os/rmm!16
2025-09-10 08:40:36 -06:00
bjorn3 08c00a434d Update to the 2024 edition
On newer rustc versions let_chain is only allowed with the 2024 edition.
2025-09-10 15:37:19 +02:00
4lDO2 dd366f01c4 Make ForceKilled meaningful, += Dead && SIGKILL. 2025-09-10 13:22:29 +02:00
Paul Sajna 172a0ffd02 remove dtb unwraps 2025-09-07 22:53:39 -07:00
Jeremy Soller 53c3342e9f snps,dw-apb-uart is usually 32-bit mmio 2025-09-07 20:41:28 -06:00
Jeremy Soller f1492729d2 riscv64: support snps,dw-apb-uart serial 2025-09-07 20:36:05 -06:00
bjorn3 5658fc258b Disable debugger feature by default
It currently doesn't compile on aarch64
2025-09-07 13:35:22 +02:00
bjorn3 c404598296 Use cfg!() rather than #[cfg] for the cfg in map_memory 2025-09-07 13:26:04 +02:00
bjorn3 e42fc3811f Fix compiling with profiling feature enabled 2025-09-07 13:20:19 +02:00
bjorn3 b7566e66bd Fix 32bit x86 2025-09-07 13:00:40 +02:00
bjorn3 48f3592bf3 Mostly use cfg!() rather than #[cfg] for controlling syscall_debug
This only adds 40 bytes overhead per cpu core in the PerCpuBlock struct.
2025-09-07 12:38:57 +02:00
bjorn3 fefede0d67 Use cfg!() rather than #[cfg] for controlling self_modifying 2025-09-07 12:30:33 +02:00
bjorn3 b5822ac118 Mostly use cfg!() rather than #[cfg] for controlling sys_stat
This only adds 48 bytes overhead per cpu core in the PerCpuBlock struct.
Also fixes compilation with sys_stat enabled on x86_64.
2025-09-07 12:27:04 +02:00
bjorn3 0a58e9e806 Allow cfg(dtb) for check-cfg 2025-09-07 12:03:37 +02:00
bjorn3 f05be85966 Use cfg!() rather than #[cfg] for controlling multi_core 2025-09-07 12:02:16 +02:00
bjorn3 d6e9022c4a Rustfmt 2025-09-06 17:10:32 +02:00
bjorn3 869a664172 Remove allow(unexpected_cfgs) 2025-09-06 17:06:31 +02:00
bjorn3 cf019ab9a5 Remove some unused unsafe blocks 2025-09-06 16:51:05 +02:00
bjorn3 c4c605630a Remove an allow(unused) for the elf module 2025-09-06 16:49:45 +02:00
bjorn3 7975d2aa8f Remove Unique
It is only used for AlignedBox which can just directly implement Send
and Sync. Additionally make the Send and Sync impls more restrictive by
requiring the inner type to be Send cq Sync, previously AlignedBox was
always Send and Sync, which is not sound.
2025-09-06 16:23:30 +02:00
bjorn3 afed3bc84b Fix a couple of warnings 2025-09-06 16:17:05 +02:00
bjorn3 7f63a5c8f0 Don't mark irq_trigger as no_mangle 2025-09-01 17:19:09 +00:00
Jeremy Soller c6f38f05e4 Disable multi_core again (for demo) 2025-08-28 10:00:16 -06:00
Wildan Mubarok 7d91390f04 Detect if ARM virtual timer should be used 2025-08-16 12:58:09 +00:00
Wildan Mubarok e071bdcef4 Use ARM virtual timer to fix HVF acceleration 2025-08-16 11:20:48 +00:00
Wildan M 39cb82d91d Optimize graphical debug scrolling 2025-08-09 18:30:51 +07:00
lebakassemmerl 6bf8c0c26c fix build-error on aarch64 and probably on riscv 2025-08-04 20:39:02 +02:00
Wildan Mubarok 1ff46c8482 Fix Linter CI 2025-08-04 06:34:31 -06:00
Jeremy Soller af7591bc26 Clarify vector number in IPI 2025-08-03 20:56:18 -06:00
Jeremy Soller 5d06ad4e6a Ensure that APIC ID is uses for all IPIs, enable multi_core feature 2025-08-03 20:53:58 -06:00
Jeremy Soller b4f566dab2 Rebuild if Cargo.toml or Cargo.lock change 2025-08-03 16:04:49 -06:00
Wildan Mubarok c67fc7b099 Backfill aarch64 serial log 2025-07-31 03:22:52 +00:00
Ibuki Omatsu e3d8ae1b79 feat: Introduce FdTbl and make Context.files use it for separate file tables. 2025-07-30 15:33:06 -06:00
Darley Barreto 66ea2b46ee Adding openat syscall 2025-07-13 06:43:20 -06:00
bjorn3 caf5fa955b Fix freeing of phys_contiguous frames
Previously the deallocation would be rounded to the next power of two
preventing partial deallocation. But more importantly previously trying
to free phys_contiguous frames while another processes still borrows
them. Now this should just cause the deallocation to be delayed.
2025-07-06 16:13:13 +02:00
bjorn3 08ea1da2f9 Trigger read event for user schemes when an fd is closed 2025-07-05 17:54:19 +02:00
bjorn3 7a440bcd67 Merge close and on_close scheme calls 2025-07-05 16:59:08 +02:00
bjorn3 48ad866d02 Add some explanation to the multi_core todo 2025-06-28 20:16:29 +02:00
bjorn3 751803553f Unify paging between x86 and x86_64 2025-06-28 20:09:16 +02:00
bjorn3 ba66388ca7 Unify rmm.rs between x86 and x86_64 2025-06-28 20:03:06 +02:00
bjorn3 b06aa61676 Remove reference to no longer existing 3dnow target feature
This silences a lot of warnings.
2025-06-28 19:58:15 +02:00
bjorn3 219dedda32 Unify start.rs between x86 and x86_64 2025-06-28 19:57:52 +02:00
bjorn3 ba051b781f Shorten the message about the RSDP 2025-06-28 19:37:56 +02:00
bjorn3 1864f12913 Make the HPET debug logs more compact 2025-06-28 19:37:56 +02:00
bjorn3 2a2139c46e Fix a couple of warnings 2025-06-28 19:37:56 +02:00
bjorn3 e77257bb6e Remove unused core_intrinsics feature gate 2025-06-28 19:37:56 +02:00
Ibuki Omatsu 90643abbad feat: Store caller's PID in Sqe during SYS_CALL 2025-06-25 08:44:51 -06:00
Wildan Mubarok fa907f02ae Move aarch64 interrupt init func 2025-06-25 08:37:50 -06:00
Jeremy Soller f32d018d85 Format 2025-06-13 20:26:41 -06:00
Jeremy Soller 5b88d1a845 Debug using pid 2025-06-13 20:26:35 -06:00
Jeremy Soller 22cc551450 Sort /scheme/sys files 2025-06-13 20:26:21 -06:00
Ivan Tan e67cca7bce raspi3b+: sloved programs can not be waken up on time from sleep 2025-05-19 15:27:35 +08:00
Ivan Tan f5aeb0b43a implement monotonic for aarch64 2025-05-13 15:30:45 +08:00
Jeremy Soller 407c0c1403 Disable syscall debug 2025-05-06 08:21:09 -06:00
Jeremy Soller d712ff5158 Add flink 2025-05-03 12:25:46 -06:00
4lDO2 4a1cd73da4 Fix same-thread scheme use-after-free. 2025-04-26 16:33:10 +02:00
bjorn3 03ebb3491b Show pid of process on unhandled exceptions 2025-04-24 20:53:50 +02:00
bjorn3 8e6ff4341e Don't crash on GICv3
Serial input is still broken though.
2025-04-21 16:56:12 +02:00
bjorn3 75edd1d34c Fix infinite panicking when panicking during early boot 2025-04-21 16:44:27 +02:00
4lDO2 9be617132a Fix 'sys:exe' as required by libstd. 2025-04-20 14:09:31 +02:00
4lDO2 98999e76b2 Fix sendfd error handling. 2025-04-20 13:57:37 +02:00
4lDO2 952b1483d8 Pass the sendfd arg: u64 to userspace. 2025-04-20 12:36:33 +02:00
4lDO2 f7d413e1bb Use redox-os/syscall for git dep. 2025-04-19 19:23:57 +02:00
4lDO2 e6df56cf1b Use saner debug IDs for kmain. 2025-04-19 16:30:49 +02:00
4lDO2 6ed49d2ecb Reduce outdated header in sys/context. 2025-04-19 16:30:49 +02:00
4lDO2 1e3e961b78 Simplify context debug names. 2025-04-19 16:30:49 +02:00
4lDO2 22afbde451 Fix being_sigkilled todo! 2025-04-19 16:30:49 +02:00
4lDO2 1227f2222e Fix compilation on riscv64gc. 2025-04-19 16:30:48 +02:00
4lDO2 4d49f1a8e4 Refer to NLnet funding. 2025-04-19 16:30:48 +02:00
4lDO2 9447986889 Remove ksignal from aarch64. 2025-04-19 16:30:48 +02:00
4lDO2 b13ef6ada3 Fix i686. 2025-04-19 16:30:48 +02:00
4lDO2 2e6122bc7e Allow procmgr to recognize unhandled exceptions. 2025-04-19 16:30:48 +02:00
4lDO2 020b8ad415 Compile on aarch64. 2025-04-19 16:30:48 +02:00
4lDO2 10c53aef10 Remove RtSigInfo import. 2025-04-19 16:30:48 +02:00
4lDO2 10ef631fc3 Remove WaitMap from existence. 2025-04-19 16:30:48 +02:00
4lDO2 f3af1be69f Never return from ForceKill caller. 2025-04-19 16:30:48 +02:00
4lDO2 3a17f50ea8 Remove ContextHandle::Signal. 2025-04-19 16:30:47 +02:00
4lDO2 fa6dee36da Report all being_sigkilled contexts as Dead. 2025-04-19 16:30:47 +02:00
4lDO2 5df7031eb1 Add Interrupt ContextVerb. 2025-04-19 16:30:47 +02:00
4lDO2 ab11e6b346 Support stopping contexts, by procmgr. 2025-04-19 16:30:47 +02:00
4lDO2 2f977bbc52 Support getting intra-page off and mapping sig [tp]ctl. 2025-04-19 16:30:47 +02:00
4lDO2 e002d0be33 Remove commented-out syscalls and SigState.rtqs 2025-04-19 16:30:47 +02:00
4lDO2 cb1a838f05 Start moving kill to procmgr. 2025-04-19 16:30:47 +02:00
4lDO2 d0e09d9e87 Remove SYS_IOPL and SYS_VIRTTOPHYS debug. 2025-04-19 16:30:47 +02:00
4lDO2 ef78ac57b0 Add fd-based virttophys replacement. 2025-04-19 16:30:47 +02:00
4lDO2 b4b2ac312b Add interface for setting iopl. 2025-04-19 16:30:46 +02:00
4lDO2 2815800164 Support reading context status. 2025-04-19 16:30:46 +02:00
4lDO2 7b06ca16b1 Make thread kill API async. 2025-04-19 16:30:46 +02:00
4lDO2 f40ec48b3e Send event on thread death. 2025-04-19 16:30:46 +02:00
4lDO2 db5931504d Remove nonexisted import. 2025-04-19 16:30:46 +02:00
4lDO2 ce77a018ec Reach init again, with proc mgr. 2025-04-19 16:30:46 +02:00
4lDO2 a9fb2dcb93 Simplify proc scheme security. 2025-04-19 16:30:46 +02:00
4lDO2 0ccc825bfb Patch syscall. 2025-04-19 16:30:46 +02:00
4lDO2 a78d36f7f2 Reach init in userspace. 2025-04-19 16:30:46 +02:00
4lDO2 6d1a3e9a4c Convert Handle::Context -> Handle. 2025-04-19 16:30:45 +02:00
4lDO2 2a5bd36899 Reimplement context creation. 2025-04-19 16:30:45 +02:00
4lDO2 8883818501 Make kernel compile. 2025-04-19 16:30:45 +02:00
4lDO2 1d5f8fd46d Move proc code to userspace. 2025-04-19 16:30:42 +02:00
Andrey Turkin 1b9fcbf593 riscv: Remove SBI logger
SBI needs a physical address; it used to work before because of the buggy code by sheer chance.
Rather than trying to fix it the right way (find a mapping from virtual to physical both before
and after RMM) let's just throw it away. Serial logger works just fine for the early init logging.
2025-04-19 10:03:35 +03:00
Jeremy Soller e5f4795024 Fix riscv64 ABI 2025-04-17 20:01:14 -06:00
Jeremy Soller fab76e7dca Fix compilation on riscv64 2025-04-17 15:34:24 -06:00
4lDO2 5d41cd7c53 Remove unimplemented itimer scheme. 2025-04-13 18:13:00 +02:00
bjorn3 f5f877ca22 Fix saving and restoring of float registers on arm64 2025-04-12 17:11:04 +02:00
Jeremy Soller a926baefaf aarch64 fp_load/fp_save do not need to be naked
There is a bug with LLVM and Rust causing naked functions to not support
target_enable directives.

https://github.com/rust-lang/rust/issues/136280
2025-04-12 08:14:38 -06:00
Jeremy Soller 551443d641 Revert "aarch64 must have fp-armv8 feature to use some instructions"
This reverts commit a24192235e.
2025-04-12 08:05:55 -06:00
Jeremy Soller 0140e2a382 Fix compilation of emergency_stop on x86 2025-04-11 20:55:56 -06:00
Jeremy Soller a24192235e aarch64 must have fp-armv8 feature to use some instructions 2025-04-11 18:26:09 -06:00
Jeremy Soller 25f422b53f Update data layout for aarch64 2025-04-11 18:20:35 -06:00
4lDO2 f4d643e87c Fixes for netstack cancellation to work. 2025-04-10 19:32:41 +00:00
bjorn3 8f589f7b88 Disable graphical debug only once writing to the fd
This allows obtaining an fd for this before calling setrens while doing
the actual disabling after calling it.
2025-04-06 17:13:26 +02:00
4lDO2 81374e6f7b Add support for CallFlags::CONSUME. 2025-04-06 15:50:32 +02:00
Jeremy Soller ceccc40a1d Disable multi_core feature 2025-04-04 14:25:26 -06:00
4lDO2 ef5de94150 Use sys scheme for kstop rather than signals. 2025-03-31 14:59:00 +02:00
4lDO2 92fcb4472b Use more reliable triple fault for emerg..._reset. 2025-03-31 14:58:05 +02:00
4lDO2 3ae117b812 Outsource x86 RTC handling to rtcd. 2025-03-30 15:28:25 +02:00
Jeremy Soller ce60a7939e Update redox_syscall in Cargo.lock 2025-03-20 10:50:39 -06:00
bjorn3 23fd308745 Reduce verbosity of debug logs during booting
A bunch of things are now printed a bit more compactly or without
interleaving of logs on a single line. Also a bunch of not that useful
logs are no longer printed by default at all.
2025-03-15 20:52:06 +01:00
bjorn3 81210b9ed0 Update and re-enable the legacy scheme deprecation warnings
I've tested booting, several cosmic apps and netsurf as not causing any
warning with the new set of exclusions and all my recent MR's merged.
2025-03-13 18:51:37 +01:00
Jacob Lorentzon 4607576006 Implement bidirectional SYS_CALL support 2025-03-03 23:21:56 +00:00
Ribbon 8f24d894eb Fix a typo on the documentation command in the README 2025-03-03 07:41:42 +00:00
Ron Williams ba613ce628 Nanosleep: Return time remaining after interrupt 2025-02-26 21:00:23 +00:00
Majoneza 06f2c93140 chore: validate_region return PageSpan
Changed validate_region function to return PageSpan instead of a tuple. All the code
using validate_region function was updated to use PageSpan as well.
2025-02-25 23:38:38 +01:00
Vincent Berthier 2da88c18c0 Add the sys:stat scheme 2025-02-22 14:27:10 +00:00
4lDO2 84632ab708 Disable warning when opening "old" schemes. 2025-02-21 16:56:53 +01:00
4lDO2 ef0758b9cc Always use close message when available. 2025-02-21 16:50:16 +01:00
4lDO2 7295777985 Add one-way close message for schemes. 2025-02-21 15:56:05 +01:00
4lDO2 f044ffb03b Remove stable #![feature] and most x86_64 static mut. 2025-02-21 14:16:58 +01:00
4lDO2 09eaf12201 Add optional fdstat sys scheme statistic. 2025-02-19 11:55:18 +01:00
Anhad Singh 79de74bf3a fix(scheme/itimer): wrong chunk size
Chunk size of the scheme (`size_of::<ITimerScheme>() == 0`) was being
provided instead of `size_of::<ITimerSpec>()`. This resulted in a kernel
panic (division by zero) when kread was called for this scheme.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-01-16 03:10:01 +00:00
Jeremy Soller 7a530cf0ec Update dependencies 2025-01-14 15:59:14 -07:00
Jeremy Soller 668a123b9a Switch to naked_asm 2025-01-14 15:59:07 -07:00
Ribbon 495c3708f3 Document how to contribute and do development in the README 2025-01-09 12:00:00 +00:00
Andrey Turkin 7db6667e6b Better parsing of IRQ specifications in DTB
Fixes Raspberry 3B+ DTB parsing (as generated by Qemu)
2024-12-18 21:11:46 +03:00
Andrey Turkin 7f38f51b20 dtb: Apply bus mappings 2024-12-18 21:11:46 +03:00
Zhouqi Jiang 52763e7e70 arch: riscv64: use sbi-rt crate to process SBI calls, save code sizes 2024-12-18 14:06:08 +00:00
Anhad Singh d4797bbf50 chore: update redox_syscall
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2024-12-12 13:34:49 +11:00
Anhad Singh af36ae12b0 fix(mremap): fix referencing
Before it was first add_ref'ed by `borrow_frame_enforce_rw_allocated`,
manually and then by `allocated_shared_one_page`.

Now it is only done by `borrow_frame_enforce_rw_allocated` and does not
get unref-ed as take() is called on the returned `RaiiFrame`.

Now the page is manually mapped and an `Allocated` type grant is
constructed (synonymous to `MAP_PRIVATE`). Before by using `allocated_shared_one_page`
an `AllocatedShared` provided grant was constructed (synonymous to
`MAP_SHARED`), which was wrong as the TCB would've not got CoW-ed
after fork(), making the Tcb malformed.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2024-12-11 16:37:01 +11:00
Anhad Singh 08231eb4df feat(mremap): KEEP_OLD
Signed-off-by: Anhad Singh <andypython@protonmail.com>
Co-authored-by: @4lDO2
2024-12-11 16:08:08 +11:00
Andrey Turkin 7af6dd1f88 Restore riscv,plic0 compatible check 2024-11-07 05:09:24 +03:00
Andrey Turkin 9fe8f759af Fix formatting and a warning 2024-11-06 12:13:13 +03:00
Andrey Turkin ee89d02282 Change PLIC compatible string from riscv,plic0 to sifive,plic-1.0.0
Former one is deprecated and apparently only used by QEMU. Latter is used by QEMU as well as others.
2024-11-06 12:09:36 +03:00
Jeremy Soller 99fbdf426c Fix assumption that CPU ID must equal APIC ID 2024-11-04 14:46:46 -07:00
Andrey Turkin 7b1d135057 Use redoxer for CI jobs 2024-11-01 06:51:13 +03:00
Jeremy Soller 4db9673e2a Support SPCR and clean up device memory allocation 2024-10-31 10:53:58 -06:00
Arthur Paulino e19c1404f7 chore: enrich context/switch
* Add documentation and more code comments to `src/context/switch.rs`
* Eliminate a `context.wake.expect(...)` where `context.wake.is_some()`
* Eliminate a TODO item about updating contexts' timestamps in `switch_to`
* Eliminate a dangling `else { continue }` at the end of the loop that iterates
  on contexts
2024-10-31 10:22:21 +00:00
Jeremy Soller df9db9291a Fix AP CPU ID on newer Intel CPUs 2024-10-30 21:09:06 -06:00
Jeremy Soller 9b6d1549b5 Support GTDT for aarch64 2024-10-30 18:17:11 -06:00
Jeremy Soller 34a6a441f1 Initial aarch64 ACPI support 2024-10-30 16:16:24 -06:00
Jeremy Soller b221bb6c51 Make it possible to boot aarch64 with invalid DTB 2024-10-30 12:34:50 -06:00
Jeremy Soller 4dd6a26742 Make it possible to compile acpi system on any arch 2024-10-30 11:43:21 -06:00
Jeremy Soller 939c9567ee Support 16550 uarts for aarch64 debug output 2024-10-29 14:06:00 -06:00
Jeremy Soller 161e578f29 Use null driver for unknown IRQ controllers on aarch64 2024-10-29 08:01:38 -06:00
Jeremy Soller 380532aea5 Improve reliability of aarch64 startup code 2024-10-29 08:00:57 -06:00
Jeremy Soller 15b0133b7b Add arm,gic-400 support to GIC driver 2024-10-29 08:00:17 -06:00
Jeremy Soller e4e55103ad Remove old aarch64 asm code 2024-10-29 07:59:12 -06:00
Arthur Paulino ea0356b26a Address minor warts
* Mention the need to have `nasm` available on the PATH in the README
* Replace the deprecated `hide_parse_errors` by `show_parse_errors` in `rustfmt.toml`
* Mark unused variables in `src/scheme/proc.rs`
2024-10-27 18:14:12 -03:00
Andrey Turkin 8dcf850919 Update rmm 2024-10-23 04:06:26 +03:00
Jeremy Soller 63669069f4 Merge branch 'bump_fix' into 'master'
Fix a bump allocator error

See merge request redox-os/rmm!15
2024-10-22 21:26:17 +00:00
Andrey Turkin 91ccf4e6aa Fix a bump allocator error 2024-10-22 22:14:39 +03:00
Andrey Turkin 505425bec9 Expose riscv64/aarch64 legacy irqs (requiring remapping) to the irq scheme 2024-10-22 20:26:40 +03:00
Andrey Turkin cba02a26fa Rework irqchip to support risc-v irqs, and add risc-v irq chips handling 2024-10-22 19:16:21 +03:00
Andrey Turkin 906259c024 Pull irqchip from aarch64 code into more generic place 2024-10-21 19:56:32 +03:00
Jeremy Soller 6a731d0c84 Delete syscall directory 2024-10-20 07:31:35 -06:00
Andrey Turkin 1921c6814b Initial RISC-V implementation
Has no IRQ handling yet
2024-10-20 16:24:21 +03:00
Andrey Turkin db32f5f7a3 Move some conditionally compiled code from common files into arch-gated files 2024-10-19 21:59:14 +03:00
Andrey Turkin 55041e2eeb Use a custom config flag to conditionally compile DTB-specific areas
Would be great if we could use a feature instead, but Cargo can't do target-specific defaults features
2024-10-19 21:03:43 +03:00
Andrey Turkin 0a6a90415a Refactor initial memory paging 2024-10-19 08:44:46 +03:00
James 3fbd52a212 Made a change in context to the way arrays are resized. Slight change to the logic but resize_with should be slightly more efficient 2024-10-15 21:24:32 +11:00
Ron Williams 865122e92f Fix serial console login 2024-10-10 18:45:14 +00:00
4lDO2 0965c1e22b Allow aarch64 test to fail. 2024-10-07 10:20:51 +02:00
4lDO2 8d4ee26ff1 Fix profiling && + toggle support via debug scheme. 2024-10-07 10:20:51 +02:00
Dmitry Mottl dc1ba28f91 Updates .helix config to the new file format 2024-10-01 14:36:11 +00:00
4lDO2 ad16b747ea Restrict auto-fcntl to non-v2 schemes. 2024-09-27 21:36:22 +02:00
IncompententPirate fc5d246b30 remove wrapper functions 2024-09-26 22:34:55 +00:00
Andrey Turkin 14eb140f7a Refactor panic stack walking 2024-09-26 19:22:21 +03:00
Andrey Turkin 755694494b Factor KernelMapper out of arch
Same implementation on all the platforms. Also remove mutable Deref as it allowed circumventing RO check
2024-09-25 21:51:39 +03:00
4lDO2 539dc5a24e Remove SYS_UMASK. 2024-09-25 19:55:39 +02:00
Andrey Turkin d08861e586 Upgrade fdt library to the very latest
The new helpers remove a lot of boilerplace. Unfortunately some rough edges still remain (in particular issue gh#12 which renders interrupts() helper useless)
2024-09-25 06:51:02 +03:00
4lDO2 32e114885b Update RMM. 2024-09-24 19:33:27 +02:00
4lDO2 0a3ce63d40 Update syscall 2024-09-24 19:18:23 +02:00
4lDO2 71538efc06 Allow thread exit to optionally deallocate stack. 2024-09-24 19:18:23 +02:00
4lDO2 9a0192fc94 Prevent duplicate idempotent signals. 2024-09-24 19:18:23 +02:00
4lDO2 fcb2e2be3a Pass si_uid and si_pid to kill signals. 2024-09-24 19:18:23 +02:00
4lDO2 7def7ce6e3 Extend size of sig{en,de}queue payload. 2024-09-24 19:18:22 +02:00
4lDO2 54b1fbe453 Implement queued signals.
This currently needs to be done in the kernel for synchronization
reasons, but it's possible all delivery parts can later be moved to
userspace.
2024-09-24 19:18:22 +02:00
4lDO2 6d9cf30445 WIP: realtime signals 2024-09-24 19:18:20 +02:00
Andrey Turkin dbbbfcf48a Update RMM 2024-09-24 19:23:08 +03:00
Jeremy Soller edb3a87578 Merge branch 'riscv' into 'master'
Fixes and changes to make RISC-V paging work

See merge request redox-os/rmm!14
2024-09-24 12:51:39 +00:00
Andrey Turkin ed8bcfca1f Add write combining page flags where applicable 2024-09-24 08:26:02 +03:00
Andrey Turkin 192dd8283f RISC-V: implement TLB flush 2024-09-24 08:26:01 +03:00
Andrey Turkin f51cd00f00 Remove read/write flags from common PDE flags.
RISC-V convention marks PDE with no read/write/execute, so we can't have none of this flags set there. Remove their setting from PDE handling code and instead set them as appropriate in arch-specific defaults.

Also enable both readonly and readwrite flags to be non-zero (as long as their intersection completely masks both of them), as required for RISC-V PTE handling.
2024-09-24 08:24:18 +03:00
Andrey Turkin a96ea6f5f3 Allow physical address bits be anywhere in PTE entry
Before this commit, RMM assumed base physical address was presented in PTE as is, i.e. physical page address was shifted exactly to PAGE_SHIFT, so physical address can be extracted from PTE by simply masking off some bits and can be placed in PTE by simple addition/OR.

This is not the case for RISC-V which has 4Kb base page so 12 bits PAGE_SHIFT, yet physical page address is only shifted 10 bits in PTE.

This commit removes this assumption.

 NOTE: This commit changes meaning of constants:
 * ENTRY_ADDRESS_SIZE from "total physical size in bytes" to "total physical size in PAGES"
 * ENTRY_ADDRESS_MASK from "mask of physical bits in PTE" to "mask of physical bits starting at bit 0"
2024-09-23 08:47:27 +03:00
Andrey Turkin b7d3acf606 Separate leaf page and directory pages USER flag
This is required for RISC-V. Privileged spec says:

> For non-leaf PTEs, the D, A, and U bits are reserved for future standard use.
> Until their use is defined by a standard extension, they must be cleared by software
> for forward compatibility.

QEMU fails address translation if it sees any of these flags set on non-leaf page entry.
2024-09-23 08:47:23 +03:00
4lDO2 b485b1b3ea Update RMM. 2024-09-22 15:22:01 +02:00
Jeremy Soller bb27f57228 Merge branch 'fix_bump' into 'master'
Fix bump allocator initialization

See merge request redox-os/rmm!13
2024-09-22 13:20:33 +00:00
4lDO2 d95ea6598f Fix bump allocator. 2024-09-22 10:27:06 +02:00
4lDO2 960e79b107 Treat broken pipes as IO-capable in fevent. 2024-09-19 10:41:40 +02:00
4lDO2 ce9f699f8f Add unit tests to CI. 2024-09-17 23:10:36 +02:00
4lDO2 d498eefb2f Disable userspace feature in redox-syscall.
This prevents the kernel from being able to accidentally call itself
using the syscall instruction.
2024-09-17 19:24:26 +02:00
4lDO2 ef499f81fc Support compiling for host, allowing unit tests. 2024-09-17 19:24:23 +02:00
4lDO2 a0d0eac8aa Optimally divide responsibility for borrow free.
This appears to slightly improve performance.
2024-09-14 10:49:40 +02:00
4lDO2 031fdea089 Discard empty names in root scheme getdents. 2024-09-13 15:26:24 +02:00
4lDO2 97ea7ea6ec Disable syscall debug 2024-09-12 10:29:11 +02:00
4lDO2 e3e05ebca8 Fix root scheme order by using indexmap (tmp). 2024-09-11 22:09:29 +02:00
4lDO2 97f60de4ef WIP: Add getdents opaque_id 2024-09-11 22:09:29 +02:00
4lDO2 339271b4d7 Add getdents syscall, and switch schemes to it. 2024-09-11 22:09:26 +02:00
Kamil Koczurek 548fd63264 tsc: calculate elapsed ticks using saturating_sub
RDTSC readouts might not actually be monotonically increasing due to
desynchronization between CPU cores, so checked_sub was causing a kernel
panic.
2024-09-10 14:16:38 +02:00
4lDO2 652cdc7ef2 Replace repr(packed) with repr(C, packed). 2024-09-08 20:56:50 +02:00
4lDO2 5f9a587968 Convert repr(packed) to repr(C, packed). 2024-09-08 20:48:05 +02:00
4lDO2 815ac3da4a Revert "Fix possible UB in rmm::init."
This reverts commit 4626c74b78.
2024-09-08 20:22:46 +02:00
4lDO2 9673fa26b6 Expand Cargo features to separate lines.
This is much more diff- and by extension rebase-friendly.
2024-09-08 00:09:49 +02:00
4lDO2 4626c74b78 Fix possible UB in rmm::init.
I tested compiling the kernel with a more recent rustc, and this
triggered UB. Don't know for sure why there was an invalid entry passed
to the kernel, but it did.
2024-09-07 23:14:55 +02:00
Jeremy Soller 0c99e1bd0a Set xcr0 in all cases 2024-09-06 20:08:40 -06:00
Jeremy Soller 1c00450127 Use 64-bit versions of xsave and xrstor 2024-09-04 21:22:10 -06:00
4lDO2 09e7e66e00 Move scheme borrow unmap to cqe write. 2024-09-04 19:23:21 +02:00
4lDO2 181df19b24 Update rmm 2024-09-04 19:23:19 +02:00
Andrey Turkin a558860e88 Fix BSS sanity check
mark the canaries mutable so they go into data and bss and not in rodata
2024-09-04 10:55:20 +03:00
Andrey Turkin 7a9a5f024f Validate bootstrap memory allocation 2024-09-04 10:55:16 +03:00
Andrey Turkin ba154c0387 Fix a debug-build assertion
A range of usable memory could be small enough not to have any MAX_ORDER sized frames.
2024-09-04 10:55:11 +03:00
Andrey Turkin d2ebc7ff05 Wholesale fix of warnings
Pretty straightforward changes. This commit tries to avoid making any non-trivial fixes.
2024-09-04 10:55:01 +03:00
Jacob Lorentzon 643d7400db Implement paravirtualized KVM TSC support 2024-09-03 21:20:06 +00:00
bjorn3 d43eb74da3 Use softfloat abi in the target spec for aarch64
This allows removing the -Csoft-float argument when building.
2024-09-03 14:30:11 +00:00
Jeremy Soller ea4cfb2cbf Merge branch 'fix' into 'master'
Revived tests

See merge request redox-os/rmm!12
2024-09-02 21:16:38 +00:00
4lDO2 441385ddb2 Always map the kernel itself using global pages.
This avoids TLB stalls after context switching, that are very visible
from flamegraphs.
2024-08-31 10:44:54 +02:00
Ron Williams 19cd3ad287 Fix APIC reference in profiling.rs 2024-08-26 21:06:47 -07:00
Ron Williams 12eca4a0f5 Comment out error message for old scheme path 2024-08-26 11:51:01 -07:00
Ron Williams 47799a896d Don't warn about path for COSMIC apps 2024-08-24 11:49:49 -07:00
bjorn3 0876bed222 Remove a couple of exceptions from the deprecated scheme syntax warning 2024-08-19 19:13:42 +02:00
bjorn3 d4b979fb21 Log a deprecation message for usage of the legacy scheme syntax 2024-08-18 22:05:51 +02:00
Jeremy Soller 5cb6af6b8c Fix aarch64 build 2024-08-01 13:00:59 -06:00
bjorn3 f55da93b33 Fix building for AArch64
I broke this in !321
2024-08-01 20:45:59 +02:00
bjorn3 8f186a692f Allow writing messages to debug: without preserving them in sys:log
This would allow logd to write all received log messages to debug:
without causing an infinite loop when it at the same time reads all
messages in sys:log.
2024-07-25 12:49:43 +02:00
4lDO2 4158d899b5 Probably fix TLB shootdown "diagonal" livelock.
Diagonal as in

Thread A        Thread B
Send to B       Send to A
Wait for B      Wait for A.

I haven't reproduced this bug, but this should fix it, since the wait
steps now checks the local percpu block for pending TLB shootdowns onto
itself.
2024-07-24 22:48:56 +02:00
4lDO2 49b94047a8 Fix significant memory leak. 2024-07-24 22:48:56 +02:00
bjorn3 e7a46c3422 Let userspace control when graphical_debug gets disabled
Rather than disabling it right before entering userspace. This allows
showing debug messages while the graphics subsystem hasn't initialized
yet.
2024-07-24 20:59:40 +02:00
bjorn3 34cab9edba Fix typos and call graphical_debug::init_heap on arm64 2024-07-24 18:48:27 +02:00
bjorn3 98c28a3d60 Store a raw pointer in Display for the framebuffer 2024-07-24 17:45:31 +02:00
bjorn3 befd5175bb Limit visibilities 2024-07-24 17:10:35 +02:00
bjorn3 ebc4aeac85 Enable graphical_debug for aarch64
This doesn't give any issues both for UEFI boot (with framebuffer
present) and U-Boot boot (without framebuffer present).
2024-07-24 17:03:29 +02:00
bjorn3 e0855d0cb6 Fix typo 2024-07-22 16:47:35 +02:00
bjorn3 d3ccba0943 Avoid int2ptr cast in DebugDisplay 2024-07-22 14:26:44 +02:00
bjorn3 a89f93ff00 Move all drawing code from Display to DebugDisplay 2024-07-22 14:22:15 +02:00
bjorn3 dc36d18812 Remove unnecessary discard of return value in debug::Writer 2024-07-22 14:15:20 +02:00
4lDO2 51c4be10e0 Allow waitpid to be interrupted. 2024-07-20 23:17:31 +02:00
4lDO2 005635083d Fix thread cleanup during active file ops.
This fixes a bug where the window of `viewer` does not exit, due to a
leaked file descriptor.
2024-07-20 22:14:54 +02:00
4lDO2 29170ccbc7 Fix sigchld test. 2024-07-18 19:38:47 +02:00
4lDO2 05bde858f9 Fix SIGCONT deadlock. 2024-07-18 16:47:16 +02:00
4lDO2 daa11c911f Fix syscall debug, more success in sigchld test. 2024-07-18 16:14:07 +02:00
4lDO2 c54195f10d Ensure process signals can also interrupt. 2024-07-17 17:31:05 +02:00
4lDO2 2d50055dfb WIP: support thread/process-specific kill. 2024-07-17 15:29:05 +02:00
4lDO2 3c540efb00 Support sending signals to individual threads. 2024-07-16 22:06:21 +02:00
4lDO2 8de850e7e9 Ensure all threads stop in exit(). 2024-07-16 20:33:37 +02:00
4lDO2 79bbf79656 Fix some proc scheme FIXMEs. 2024-07-16 20:28:17 +02:00
4lDO2 cc465c008b Remove rustc hack. 2024-07-16 19:52:18 +02:00
4lDO2 bda12fe55e Print MXCSR in the SIMD exception handler. 2024-07-16 13:14:42 +02:00
4lDO2 cde108439c Fix kill deadlock. 2024-07-16 13:05:42 +02:00
4lDO2 6bd01513c5 Simplify and improve thread/process cleanup. 2024-07-15 18:08:43 +02:00
4lDO2 a3dedb0639 Do proper resource cleanup for thread exit too. 2024-07-15 18:08:43 +02:00
4lDO2 8259ed281c Boot to desktop with process/context changes. 2024-07-15 18:08:43 +02:00
4lDO2 40f5c01586 Flatten syscall match statement. 2024-07-15 18:08:43 +02:00
4lDO2 e67c040f69 WIP: Separate process status from context status. 2024-07-15 18:08:43 +02:00
4lDO2 7fbe5c72e9 Use strong references in context set. 2024-07-15 18:08:42 +02:00
4lDO2 80fe891c6e WIP: Replace ContextId with direct Arcs. 2024-07-15 18:08:42 +02:00
4lDO2 038ff03996 Fix waitpid and improve debug. 2024-07-15 18:08:42 +02:00
4lDO2 0de23a1141 Use correct context for proc scheme 'new-thread'. 2024-07-15 18:08:42 +02:00
4lDO2 4202bc3ba0 WIP: add new-thread 2024-07-15 18:08:42 +02:00
4lDO2 208d74899a Fix fork & process creation, now boots to desktop. 2024-07-15 18:08:42 +02:00
4lDO2 25974bec6e It compiles. 2024-07-15 18:08:42 +02:00
4lDO2 de1bd46c84 Make proc scheme almost compile. 2024-07-15 18:08:42 +02:00
4lDO2 89d532a267 Fix half of proc scheme errors. 2024-07-15 18:08:42 +02:00
4lDO2 89d1d49a4e Fix most code except proc scheme. 2024-07-15 18:08:41 +02:00
4lDO2 8f452b0b0f WIP: continue the process transition 2024-07-15 18:08:41 +02:00
4lDO2 0da2fce64a Separate context and process IDs. 2024-07-15 18:08:41 +02:00
4lDO2 74b824f40f Add rustfmt to CI. 2024-07-15 17:54:27 +02:00
4lDO2 d94baa2712 Run rustfmt. 2024-07-15 17:50:18 +02:00
4lDO2 f3532f4549 Fix static mut ref warnings. 2024-07-15 17:48:46 +02:00
4lDO2 5e7db80285 Fix a bunch of warnings. 2024-07-15 17:48:45 +02:00
4lDO2 c86f107344 Switch back to upstream syscall submodule. 2024-07-15 17:20:58 +02:00
4lDO2 9259a36f5e Run more of sigchld test correctly. 2024-07-15 17:20:58 +02:00
4lDO2 5abbcd8e34 Send SIGCHLD to parent after child stop/exit. 2024-07-15 17:20:57 +02:00
4lDO2 d70ad544e6 Fix SIGKILL and allow SYS_EXIT to pass 16 bits. 2024-07-15 17:20:57 +02:00
4lDO2 8f3e40a99e Fix aarch64 compilation. 2024-07-15 17:20:57 +02:00
4lDO2 465128da26 Don't block nanosleep/futex <= signals are pending. 2024-07-15 17:20:57 +02:00
4lDO2 9198ee7e52 Reimplement shutdown and restart. 2024-07-15 17:20:57 +02:00
4lDO2 4dba818c83 Check pending unblocked signals before blocking.
This is not a perfect solution, since the kernel technically already has
all the information it needs to synchronize this between the kill()
invocation and the time WaitCondition::wait is called, but it should not
have any noticeable performance impact.
2024-07-15 17:20:57 +02:00
4lDO2 e9de24c097 Only return EINTR in kill() if self was killed. 2024-07-15 17:20:57 +02:00
4lDO2 965f5879b7 Never clear sig pending bits in the kernel. 2024-07-15 17:20:57 +02:00
4lDO2 ae8e13525f Remove is_pending flag, read word directly instead. 2024-07-15 17:20:57 +02:00
4lDO2 f91b90445d Force userspace to do post-syscall EINTR check. 2024-07-15 17:20:56 +02:00
4lDO2 e8060b259d Only save ip and 'archdep' regs when signalling. 2024-07-15 17:20:56 +02:00
4lDO2 12cfcfc6f2 TMP: change syscall gitmodule to fork 2024-07-15 17:20:56 +02:00
4lDO2 93a3401df4 Fix bug causing raise() to not deliver any signals. 2024-07-15 17:20:56 +02:00
4lDO2 13720f59d5 Make signals masked when clear rather than set. 2024-07-15 17:20:56 +02:00
4lDO2 87046b77c7 Compile on aarch64. 2024-07-15 17:20:56 +02:00
4lDO2 c1ce1d76f9 Compile on i686. 2024-07-15 17:20:56 +02:00
4lDO2 5b25e2cda7 Fix excp_handler deadlock. 2024-07-15 17:20:56 +02:00
4lDO2 b94904a660 Use correct addrsp when setting sighandler. 2024-07-15 17:20:56 +02:00
4lDO2 cc406804c0 Don't double-clear is_pending flag. 2024-07-15 17:20:55 +02:00
4lDO2 35aa24800b Implement correct context sig unblocking behavior. 2024-07-15 17:20:55 +02:00
4lDO2 93f0573b5d Use improved signal control struct defs. 2024-07-15 17:20:55 +02:00
4lDO2 d6e0eef065 Implement signal delivery code (untested). 2024-07-15 17:20:55 +02:00
4lDO2 9b68d4de80 Fix add_ref(Shared) refcounting bug. 2024-07-15 17:20:55 +02:00
4lDO2 7d5b2e6c21 Prevent infinite userspace crash loops. 2024-07-15 17:20:55 +02:00
4lDO2 55fe58adf6 WIP: implement kill syscall prototype 2024-07-15 17:20:55 +02:00
4lDO2 639ba74a7e Fix kernel compilation. 2024-07-15 17:20:55 +02:00
4lDO2 295cc820e6 WIP: userspace signal handling 2024-07-15 17:20:55 +02:00
Andrey Turkin 198151a355 Make sure aarch64 kernel doesn't use any FP registers 2024-07-13 12:06:50 +00:00
Andrey Turkin 9c639af217 Fix debug assertion bug 2024-07-12 23:15:33 +03:00
Andrey Turkin 7c0995ee24 Revived tests
Also fixed debug build failure on i686, and reformatted the code
2024-07-12 21:10:37 +03:00
Andrey Turkin 2663873d45 Fix Dtb scheme reads 2024-07-09 09:52:16 +03:00
4lDO2 a80dc4dc9c Try fixing CI. 2024-06-25 12:58:53 +02:00
4lDO2 c73e2ffecf Add Makefile.
This will both improve CI, and decouple the kernel build script from
cookbook.
2024-06-25 12:46:02 +02:00
Jeremy Soller 15c7e10d52 Implement kreadoff for dtb scheme 2024-06-24 11:57:20 -06:00
4lDO2 d4997150d8 Temporarily suppress some cases of EINVAL for unknown SKMSGs. 2024-06-15 15:12:04 +02:00
4lDO2 6aa5ed020e Add missing fevent impl for RootScheme. 2024-06-15 12:29:05 +02:00
4lDO2 10714a4659 Make explicit flags optional for SYS_{READ,WRITE}2. 2024-06-14 13:58:10 +02:00
4lDO2 dd8661bcb3 Add debug print for SYS_READ2/SYS_WRITE2. 2024-06-14 13:57:56 +02:00
Jacob Lorentzon bf0fc66ac1 Improved scheme protocol. 2024-06-14 11:31:51 +00:00
4lDO2 e9ba024aaa Remove redundant .cargo/config
All options are already set by ../recipe.toml, and removing this file
will make Cargo stop complaining about missing -Zbuild-std when for
example compiling RMM for the host arch.
2024-06-10 11:52:59 +02:00
Jeremy Soller 81e6fc70d2 Enable use of MmapMode::Cow 2024-06-05 12:56:29 -06:00
Jeremy Soller 593959a7c3 Allow fp-armv8 in order to compile for aarch64 on new nightly 2024-05-11 14:45:44 -06:00
Jeremy Soller c9698b5d2d Update to new nightly 2024-05-11 14:13:41 -06:00
Jeremy Soller e7d00a8e05 Add driver for arm,gic-v3 2024-05-08 11:24:46 -06:00
Jeremy Soller 9e3688b507 Revert "Support arm,gic-v3"
This reverts commit e33015a5f8.
2024-05-07 15:24:50 -06:00
Jeremy Soller e33015a5f8 Support arm,gic-v3 2024-05-07 15:20:34 -06:00
4lDO2 7f409d46bf Fix futex wakeup when CoW has occurred. 2024-04-28 15:17:32 +02:00
Jeremy Soller 3ad6427e28 Disable AP if it has the same ID as BSP 2024-04-13 10:01:36 -06:00
Jeremy Soller 5b5b2dbc97 Debug messages during device init 2024-04-13 09:34:00 -06:00
4lDO2 0060dd326b Update rmm 2024-04-12 16:25:58 +02:00
4lDO2 99fcfc5fae Skip insufficiently large bump alloc regions. 2024-04-11 22:02:44 +02:00
4lDO2 161a92c9c2 Forbid strong fdtbl refs after setting context's.
This fixes a possible file table leak if a filetable contains an fd
referring (strongly) to the filetable itself. Now, it will automatically
be downgraded to a weak reference after it becomes a context's active
file table.

TODO: maybe support consuming a context's filetable to get a strong
reference back, provided it's exclusively owned.
2024-04-10 21:49:43 +02:00
Jeremy Soller e4246d6704 Re-enable sys:log 2024-04-10 10:38:46 -06:00
4lDO2 3fc9103826 Fix altreloc remap, always NOP-fill padding bytes.
This fixes a very rare (requires that an altreloc span two pages) kernel
crash where it writes past the region that was remapped as RWX, thus
triggering an in-kernel "wrote without write access" page fault.

Additionally, this fixes the logic for unavailable features. It fixes
the short-circuit that would forget to remap the memory back from RWX to
R-X. NOP bytes are also now replaced with multi-byte NOP regardless of
whether the CPU supports the given feature.
2024-04-10 16:16:37 +02:00
Jacob Lorentzon cd3f937861 Make futex timeout absolute, and properly return ETIMEDOUT 2024-04-05 20:31:03 +00:00
4lDO2 fbaa93e8fa Fix profiling stack trace bp bounds checking. 2024-04-04 15:45:47 +02:00
4lDO2 68e072aac9 Return correct fevent flags in PipeScheme.
This fixes a Cargo deadlock.
2024-04-02 15:04:39 +02:00
4lDO2 ed075474b0 Fix syscall_debug feature. 2024-03-31 14:40:57 +02:00
4lDO2 2f1551a6bb Mark allocated p2frame used *before* freelist unlock. 2024-03-26 17:07:37 +01:00
Jeremy Soller 168692f09d x86: use initial_top for tss stack 2024-03-25 14:15:43 -06:00
4lDO2 c17279f5bf Allocate kernel stacks using the frame allocator. 2024-03-25 16:31:16 +01:00
4lDO2 9253e16240 Fix kernel stack sizes, other arches. 2024-03-25 16:29:07 +01:00
4lDO2 b5523df187 Only support power-of-two frame allocations. 2024-03-24 14:40:15 +01:00
4lDO2 b2d52d6736 Implement allocator free/used bookkeeping. 2024-03-24 14:27:25 +01:00
4lDO2 12282439b6 Reduce dead code, fix aarch64. 2024-03-23 23:51:12 +01:00
4lDO2 e6dc0e96f0 Fix aarch64. 2024-03-23 19:16:53 +01:00
4lDO2 7261dccb72 Fix i686. 2024-03-23 16:54:47 +01:00
4lDO2 1b3e024f7d Fix profiling code. 2024-03-23 15:52:18 +01:00
4lDO2 299a829ff3 Remove debug code. 2024-03-22 17:21:17 +01:00
4lDO2 676368f5d2 Fix booting to desktop. 2024-03-22 16:35:29 +01:00
4lDO2 c0f3b6ccca Fix refcount assert 2024-03-22 13:32:14 +01:00
4lDO2 660acb4d94 Improve debugging 2024-03-22 13:32:14 +01:00
4lDO2 343f89f240 Fix unaligned section end append_pages. 2024-03-22 13:32:14 +01:00
4lDO2 baf46a3555 Far more progress 2024-03-22 13:32:13 +01:00
4lDO2 f4d270c7ce Ensure freelist does not contain used pages. 2024-03-22 13:31:24 +01:00
4lDO2 a847e4745c More progress 2024-03-22 13:31:24 +01:00
4lDO2 d2dc3302a7 Remove RefCount::Zero.
Only the allocator is allowed to switch between 0 and 1. Refcounts above
1 are however controlled by the virtual memory system.
2024-03-22 13:31:22 +01:00
4lDO2 3a8821e73b Hopefully fix most UB 2024-03-22 13:28:21 +01:00
4lDO2 08784e7166 More progress 2024-03-22 13:27:50 +01:00
4lDO2 c349e4cd83 Fix allocate_frames_complex 2024-03-22 13:26:03 +01:00
4lDO2 4fccc4b87b Some of userspace now boots! 2024-03-22 13:26:03 +01:00
4lDO2 bb01f0af66 More allocation progress 2024-03-22 13:26:03 +01:00
4lDO2 cfe153eb85 Fix section creation. 2024-03-22 13:25:57 +01:00
4lDO2 fe7244a8cd Ensure both set_next and set_prev are called. 2024-03-22 13:25:08 +01:00
4lDO2 2ba9ff720c Doubly-linked list. 2024-03-22 13:25:07 +01:00
4lDO2 0e8c187a50 WIP: Implement more of deallocate_p2frame. 2024-03-22 13:21:52 +01:00
4lDO2 fc19d63af9 Store aligned addrs rather than PFNs in Frame. 2024-03-22 13:19:19 +01:00
4lDO2 fd86bb4860 Try to naturally align sections. 2024-03-22 13:18:07 +01:00
4lDO2 d5b1ad2cd5 WIP: Improve allocation performance 2024-03-22 13:17:59 +01:00
Jeremy Soller 8f09b4aa06 Do not use HPET on i686 2024-03-19 20:44:47 -06:00
4lDO2 66eb3361d3 Use saved regs instead of costly context.syscall. 2024-03-19 11:33:55 +01:00
4lDO2 4862977fa5 Optimize syscall fast path without tracing. 2024-03-18 20:38:11 +01:00
4lDO2 33f0fa8709 Fix IOBITMAP_SIZE type. 2024-03-18 14:34:32 +01:00
4lDO2 ff0bd96abd Improve readability 2024-03-18 14:26:00 +01:00
4lDO2 f7900df0e2 Update syscall 2024-03-18 10:27:51 +01:00
4lDO2 d62aada7ad Replace iopl with either empty or full PIO bitmap. 2024-03-18 10:27:51 +01:00
bjorn3 de137fe58d Fix acpi::init call for i686 2024-03-17 19:34:14 +01:00
bjorn3 e1f4bf4356 Misc arm device tree fixes 2024-03-17 19:28:58 +01:00
4lDO2 c583745ede Update syscall 2024-03-16 17:49:32 +01:00
4lDO2 4a3dc2dadd Fix the SIGKILL fd leak bug. 2024-03-16 17:49:32 +01:00
4lDO2 8e19da338b Fix kstop and kreset. 2024-03-16 17:49:31 +01:00
4lDO2 b97e733d94 Boot to desktop on aarch64. 2024-03-16 17:49:31 +01:00
4lDO2 57c3119a83 Fix i686 triple fault by always initializing int stack. 2024-03-16 17:49:31 +01:00
4lDO2 7d8ee58df3 Fix aarch64 link step. 2024-03-16 17:49:31 +01:00
4lDO2 5ff26ca967 Remove paste dependency completely. 2024-03-16 17:49:31 +01:00
4lDO2 5ecba176f4 Compile on aarch64. 2024-03-16 17:49:31 +01:00
4lDO2 776a140212 Fix rax being overwritten, and compile on i686. 2024-03-16 17:49:31 +01:00
4lDO2 239bd317e9 Fix signal ordering wrt syscall return. 2024-03-16 17:49:31 +01:00
4lDO2 13bc46a30b WIP: Implement scheme call cancelation. 2024-03-16 17:49:31 +01:00
4lDO2 e57573c428 Ensure signals can't start new contexts too early. 2024-03-16 17:49:30 +01:00
4lDO2 e012d6cfca Fix altstack calculation typo. 2024-03-16 17:49:30 +01:00
4lDO2 c7da5a438c Replace incorrect interrupt IA32-isms.
The code incorrectly documents and states that SS and RSP are
conditionally pushed, based on whether the privilege level changed. This
is correct on IA-32, but wrong on x86-64.
2024-03-16 17:49:30 +01:00
4lDO2 6d1e436d29 Remove some dead code. 2024-03-16 17:49:30 +01:00
4lDO2 0cf2ce632a Only call sig handler in switch, not after EINTR. 2024-03-16 17:49:30 +01:00
4lDO2 6bf8238fb1 Unset procmask for kmain. 2024-03-16 17:49:30 +01:00
4lDO2 5ac0be7ec1 Start with full procmask, fix signal delivery. 2024-03-16 17:49:30 +01:00
4lDO2 5336cbd9e5 Improve signal interfaces and implementation. 2024-03-16 17:49:30 +01:00
4lDO2 10256b331c Ensure only the kernel can return EINTR. 2024-03-16 17:49:26 +01:00
bjorn3 04f689cee7 Accept a single RSDP from the bootloader 2024-03-15 11:43:27 +01:00
bjorn3 08bb2537b5 Remove the deprecated bootstrap_entry field from KernelArgs 2024-03-15 10:59:58 +01:00
bjorn3 502016815d Avoid unaligned access in the XsdtIter
The pointers in the XSDT table are only 4 byte aligned.
2024-03-15 10:53:45 +01:00
bjorn3 d5e1188b8e Remove doc feature 2024-03-15 09:55:27 +01:00
bjorn3 672e36f401 Force the zero page of the kernel to be part of a segment
This will be necessary for limine and likely multiboot support. See the
comment in the linker scripts.
2024-03-14 21:22:13 +01:00
bjorn3 b5f94a5a2e Fix bug in the unmapping code
Previously trying to funmap an address after the start of the grant
would result in an overflow only caught when compiling the kernel with
debug assertions enabled.
2024-03-14 12:15:43 +01:00
bjorn3 e81113349c Fix get_page_info for frames in the last memory section 2024-03-13 19:41:24 +01:00
bjorn3 ecbc2b7e8d Directly read the bootstrap entry point from the initfs header 2024-03-11 14:26:08 +01:00
bjorn3 fb66a8628f Use PAGE_SIZE instead of hard coded constant 2024-03-10 21:39:55 +01:00
bjorn3 616c7d4398 Load the bootstrap blob at 4096 instead of 0
This way the NULL page can stay unmapped and the bootstrap code can
avoid UB when reading the initfs header (which is at the start of the
bootstrap code.
2024-03-10 21:14:46 +01:00
4lDO2 ec58d6c541 Compile on aarch64 as well. 2024-03-05 10:40:54 +01:00
4lDO2 d38d8b66bd Fix i686 compilation. 2024-03-05 10:26:57 +01:00
4lDO2 b35c9d1e62 Properly free phys-contiguous grants, TLB-delayed. 2024-03-04 19:03:01 +01:00
4lDO2 4e392d05e4 Delay cow() dealloc until after TLB shootdown. 2024-03-04 19:03:01 +01:00
4lDO2 fa3e2a24d4 Optimize TLB flushing. 2024-03-04 19:03:01 +01:00
4lDO2 716f147cd4 Fix synchronization so acid tlb succeeds! 2024-03-04 19:03:01 +01:00
4lDO2 846d914a55 Improve synchronization. 2024-03-04 19:03:01 +01:00
4lDO2 1f8d7bc67c Always check shootdown reqs when locking addrsp. 2024-03-04 19:03:01 +01:00
4lDO2 3a592b9079 Use regular non-NMI IPIs for TLB shootdown. 2024-03-04 19:03:00 +01:00
4lDO2 3a915c7fd5 Fix lock/guard mismatch, move r#move to wrapper. 2024-03-04 19:03:00 +01:00
4lDO2 b5efaceb51 Fix more synchronization. 2024-03-04 19:03:00 +01:00
4lDO2 098cdd6067 Fix flusher, currently only with -smp 1 2024-03-04 19:03:00 +01:00
4lDO2 79381249a2 Implement a TLB shootdown draft. 2024-03-04 19:03:00 +01:00
4lDO2 6bf90f9eee Build the foundation for TLB shootdown. 2024-03-04 19:03:00 +01:00
4lDO2 156017a25d Refactor: wrap RwLock<AddrSpace>. 2024-03-04 19:03:00 +01:00
4lDO2 749df4c869 Fail successfully with todo! 2024-03-04 19:03:00 +01:00
4lDO2 bb30530ea0 Track which CPUs are using any given AddrSpace. 2024-03-04 19:03:00 +01:00
4lDO2 0c6c857012 Improve LogicalCpu{Id,Set}, make set atomic.
Technically there should be an atomic and nonatomic set type, but perf
should be the same, as the nonatomic one would only be used when setting
the sched_affinity.
2024-03-04 19:02:56 +01:00
Jeremy Soller 15cbb40802 Format 2024-02-28 12:10:17 -07:00
Jeremy Soller 8390277eb2 Fix affinity alignment 2024-02-28 12:10:06 -07:00
bjorn3 e08eadf64a Don't pass CallerCtx in file_op_generic
It isn't used by any of the callers.
2024-02-25 21:05:21 +01:00
bjorn3 24187b5f80 Move set_tss_stack call to switch_to 2024-02-25 20:10:49 +01:00
bjorn3 96f1a14115 Remove some dead code 2024-02-25 20:06:22 +01:00
bjorn3 52f4aaf741 Avoid unaligned access for serial over x86 io port 2024-02-25 18:36:41 +01:00
bjorn3 782ec87f27 Fix UB in the locking code of context switching
The spin crate considers it UB to call force_write_unlock while there is
a threads trying to obtain a read lock on the same rwlock.

This also switches to the spinning_lot crate for the context rwlock as
it has support for a write guard keeping a reference to the rwlock using
an Arc instead of a reference.
2024-02-25 17:07:41 +01:00
bjorn3 449abb8925 Share bootstrap_mem between all archs 2024-02-25 15:53:04 +01:00
bjorn3 e23f0ed66b Share idt.rs between x86 and x86_64 2024-02-25 15:49:29 +01:00
bjorn3 f92b4c9608 Unify cpuid between x86 and x86_64 and don't return an Option
Systems without cpuid support aren't supported anyway.
2024-02-25 15:07:31 +01:00
bjorn3 eecfbb19d2 Share the functions in interrupt/mod.rs between x86 and x86_64 2024-02-25 14:48:28 +01:00
bjorn3 fbe2980b3d Share interrupt/ipi.rs between x86 and x86_64 2024-02-25 14:48:15 +01:00
bjorn3 62614db9ac Share interrupt/trace.rs between x86 and x86_64 2024-02-25 14:48:12 +01:00
bjorn3 c1d0c11a1b Fix typo in irq.rs 2024-02-25 14:31:52 +01:00
bjorn3 3610dd7e03 Remove unused interrupt handler 2024-02-25 14:31:28 +01:00
bjorn3 e9e3b4487d Reduce the difference of idt.rs between x86 and x86_64 2024-02-25 14:31:28 +01:00
Jeremy Soller 39c20720ee Fix compilation on x86_64 2024-02-16 22:05:57 -07:00
Jeremy Soller e4eb4031bd Fix APIC offsets for x86 32-bit 2024-02-16 22:02:47 -07:00
Jeremy Soller 6c6fc18f8e Format 2024-02-16 21:40:42 -07:00
Jeremy Soller 86589aa7fa Only switch to idle process when no other processes can run 2024-02-13 14:46:21 -07:00
Jeremy Soller 98f12fd750 Hack to workaround hangs by pinning to one cpu 2024-02-10 09:18:57 -07:00
Ron Williams 9331452bdb Use RedoxPath::as_parts. redox-path from crates.io 2024-02-09 15:05:45 +00:00
Ron Williams eeee40ae0c update unlink for new path format 2024-02-01 00:50:33 -08:00
Ivan Tan e7d47d10c6 aarch64: fix compile error 2024-01-27 23:29:37 +08:00
bjorn3 58314e6a47 Share a whole lot more code between x86 and x86_64 2024-01-25 13:34:04 +00:00
bjorn3 785975089b Dedup the last remaining piece of code in the driver module between x86 and x86_64 2024-01-25 13:34:04 +00:00
bjorn3 0d86348e41 Dedup the apic code between x86 and x86_64 2024-01-25 13:34:04 +00:00
bjorn3 86fb4208f2 Dedup some more code between x86 and x86_64 2024-01-25 13:34:04 +00:00
bjorn3 0d092d7921 Dedup code for most x86 and x86_64 device drivers 2024-01-25 13:34:04 +00:00
bjorn3 9404e9f892 Mark the sections used by alternative!() as allocated
This prevents the linker from discarding any function which uses the
alternative!() macro which would result in runtime relocation crashing.
2024-01-25 11:51:34 +01:00
bjorn3 5e71f6f9df Correctly mark unaligned write as such to avoid UB 2024-01-24 19:43:34 +01:00
bjorn3 fa58f5887e The kernel now works fine without optimizations
It is relatively slow without optimizations, but it is still usable.
2024-01-24 14:15:09 +01:00
bjorn3 3085b31336 Ensure __altrelocs_start is correctly aligned 2024-01-24 14:13:27 +01:00
bjorn3 732fad0593 Fix disabling the self_modifying feature 2024-01-24 14:13:18 +01:00
bjorn3 e5c93ae334 Fix some UB and debug assertions
The UB has been found by rustc's new UB checks with debug assertions
enabled.
2024-01-24 13:51:20 +01:00
Jeremy Soller 87ee68998c Handle new path format 2024-01-18 12:35:32 -07:00
Jeremy Soller 0e58953259 Update redox-path 2024-01-18 11:22:23 -07:00
Jeremy Soller 0fde840f83 Add redox-path submodule 2024-01-18 11:15:04 -07:00
Jeremy Soller 45f1c4e29e Add rustfmt from relibc and apply it with cargo fmt 2024-01-17 13:52:01 -07:00
Jeremy Soller 73897bd83d scheme/pipe: allow removing fevent 2024-01-08 16:59:48 -07:00
Jeremy Soller d18c316012 Add session ID 2024-01-08 14:43:11 -07:00
4lDO2 5e75df56c5 More BumpAllocator APIs. 2023-12-18 11:16:15 +01:00
4lDO2 ed455915ca Allow arbitrary bump allocation size. 2023-12-18 11:16:11 +01:00
4lDO2 529c491fa0 Allow disabling profiling at compile time. 2023-12-17 00:49:28 +01:00
4lDO2 fac0e783ef Refactor profiling code. 2023-12-17 00:49:28 +01:00
4lDO2 99ad6a0a2c Support toggling profiling. 2023-12-17 00:49:28 +01:00
4lDO2 0f27d55c0a Advance profiling buffer correctly. 2023-12-17 00:49:28 +01:00
4lDO2 14abf0cbc6 Exclude kmain from profile. 2023-12-17 00:49:27 +01:00
4lDO2 f973bc4128 Profiling 2023-12-17 00:49:24 +01:00
Jeremy Soller a285863335 Update syscall 2023-12-16 11:12:21 -07:00
Jeremy Soller 364896c6e7 Update syscall 2023-12-16 11:10:28 -07:00
4lDO2 dae3726057 Update syscall 2023-12-15 15:14:40 +01:00
4lDO2 ee3aafa1d9 Remove PhysBorrowed hacks. 2023-12-15 15:14:40 +01:00
4lDO2 52df9dd1bc Remove the AddrSpace ref when exiting, not reaping. 2023-12-15 15:14:40 +01:00
4lDO2 d4a120188f Ensure PhysBorrowed iff !alloc-owned, vice versa.
This is allowed now that the old physalloc/physfree syscalls have been
removed.
2023-12-15 15:14:40 +01:00
4lDO2 eda462fd11 Remove SYS_PHYSMAP. 2023-12-15 15:14:40 +01:00
4lDO2 875a130843 Remove SYS_PHYSALLOC* and SYS_PHYSFREE. 2023-12-15 15:14:40 +01:00
4lDO2 a42e406569 Fix contiguous mmap. 2023-12-15 15:14:40 +01:00
4lDO2 cd19831ffb Improved options for memory: files. 2023-12-15 15:14:40 +01:00
4lDO2 77400f63ee Add a memory: file for phys-contiguous mmaps. 2023-12-15 15:14:36 +01:00
Ivan Tan ebf96fa843 aarch64: fix dtb scheme 2023-12-14 03:34:37 +00:00
Jeremy Soller 1cc5804333 Allow CPUs to take any context 2023-12-13 17:20:43 -07:00
Jeremy Soller 4386e0716d Missed change for last commit 2023-12-13 17:20:21 -07:00
Jeremy Soller fbaa4306e3 Add unblock_no_ipi function and use in context switch 2023-12-13 17:19:43 -07:00
bjorn3 2d065083df Use HashMap instead of BTreeMap where possible
This shrinks the kernel from 905840 bytes to 862408 bytes.
2023-12-13 19:55:20 +01:00
4lDO2 78beae5c92 Fix aarch64 2023-12-13 11:08:12 +01:00
4lDO2 d531c6f1bf Context switch correctly in UserInner::call. 2023-12-13 11:08:12 +01:00
4lDO2 6b642d62a6 Disable trigger_debugger again. 2023-12-13 11:08:12 +01:00
4lDO2 88508a2cb7 Remove as_user_inner. 2023-12-13 11:08:12 +01:00
4lDO2 3a35338aa7 Remove as_{filetable,sigaction,addrspace}. 2023-12-13 11:08:12 +01:00
4lDO2 f3ce5b167d Make proc: and thisproc: global. 2023-12-13 11:08:11 +01:00
4lDO2 3be015ce4d Make sys: global. 2023-12-13 11:08:11 +01:00
4lDO2 fe0e3103f4 Make itimer: global. 2023-12-13 11:08:11 +01:00
4lDO2 87b0c568a0 Make time: global. 2023-12-13 11:08:11 +01:00
4lDO2 f6002e839d Centralize global scheme constructors. 2023-12-13 11:08:11 +01:00
4lDO2 ce313ba28d Add global scheme IDs to map, for now. 2023-12-13 11:08:11 +01:00
4lDO2 d9c2443ae3 Make irq: a GlobalScheme. 2023-12-13 11:08:11 +01:00
4lDO2 10e86ea89d Hardcode global scheme IDs. 2023-12-13 11:08:11 +01:00
4lDO2 679c26c03b s/Arc<dyn KernelScheme>/enum, but deref as dyn. 2023-12-13 11:08:07 +01:00
Jeremy Soller d7d824552b Merge branch 'derive_hash_virtual_address' into 'master'
Derive Hash for VirtualAddress

See merge request redox-os/rmm!11
2023-12-13 00:10:02 +00:00
bjorn3 aad492f805 Derive Hash for VirtualAddress 2023-12-12 22:21:22 +01:00
bjorn3 a7165f822f Switch from the memoffset crate to the offset_of feature
The memoffset crate requires const_refs_to_cell to work in const
contexts. This feature has some known issues around it's semantics. The
offset_of feature however is currently on track for stabilization.
2023-12-12 20:21:31 +00:00
bjorn3 2aea52a94b Remove the sole usage of the const_option feature 2023-12-12 20:21:31 +00:00
bjorn3 82a87be7d5 Avoid usage of the unstable Allocator trait
And also optimize init_sections to use the fact that allocate_frames
returns zeroed frames.
2023-12-12 20:21:31 +00:00
bjorn3 5bce3a5bb5 Move -z max-page-size from the target spec to the cookbook 2023-12-12 18:15:05 +01:00
bjorn3 3188a44b23 Don't use target_family="redox" for the kernel
This cfg is meant for redox userspace programs.
2023-12-12 18:14:18 +01:00
bjorn3 2e689eb5d4 Remove unnecessary no_mangle and extern "C" from the panic handler
#[panic_handler] handles all linkage related details.
2023-12-12 15:01:29 +00:00
bjorn3 c99e582c86 Use the default panicking alloc error handler 2023-12-12 15:01:29 +00:00
bjorn3 6b1c154847 Use kernel_executable_offsets on AArch64 and x86 2023-12-12 15:01:29 +00:00
bjorn3 017702d3d2 Remove a lot of dead code 2023-12-12 15:01:29 +00:00
bjorn3 00d0b8fb6b Remove all pub from main.rs
This will cause rustc to emit warnings for all unused items.
2023-12-12 15:01:29 +00:00
bjorn3 5ce7d1df8a Remove unnecessary extern crate item
This was only necessary in the 2015 edition
2023-12-12 15:01:29 +00:00
bjorn3 6045b0cc59 Remove unused feature gates 2023-12-12 15:01:29 +00:00
Jeremy Soller 4e3103a48a x86: fix enter/exit gs and usercopy asm 2023-12-11 15:25:54 -07:00
Ivan Tan 1f1a57e1f7 support userspace program ioremapping device memory 2023-12-11 16:07:53 +00:00
Ivan Tan 9b6197d686 aarch64: code clean up 2023-12-11 16:07:53 +00:00
Ivan Tan a8329956ca support raspi3b+ serial && uart interrupt 2023-12-11 16:07:53 +00:00
Ivan Tan 44b14f994a fix qemu-arm64 run error 2023-12-11 16:07:53 +00:00
Ivan Tan 1c1c541f0e bringup raspi3b+, add device memory, disable uart init 2023-12-11 16:07:53 +00:00
Ivan Tan bfbf435546 draft: aarch64: add irq_bcm2835. Need refactoring 2023-12-11 16:07:53 +00:00
Ivan Tan 9a5b9798ca remove qemu-aarch64-virt hard code 2023-12-11 16:07:53 +00:00
Ivan Tan ed68c98b42 aarch64: add irq-bcm2836 for raspi3b+ && refactor irq module 2023-12-11 16:07:53 +00:00
Ivan Tan b65a7e9103 move gic into irqchip module 2023-12-11 16:07:53 +00:00
Ivan Tan 01d0e9a4b5 aarch64: add irqchip module to initialize all irq chip. 2023-12-11 16:07:53 +00:00
Ivan Tan 78a8568932 update dtb syscall scheme to kernelscheme 2023-12-11 16:07:53 +00:00
Ribbon 4f98319a92 Improve the README and fix the docs badge link 2023-12-07 15:32:45 +00:00
Ron Williams 02087065c1 don't panic when adding an existing name to a namespace 2023-11-15 22:18:50 +00:00
4lDO2 036a4bdee4 Replace syscall::Scheme with KernelScheme. 2023-11-15 20:00:47 +01:00
4lDO2 192d663d84 Forbid / in scheme names. 2023-11-09 14:40:20 +01:00
Ron Williams 29803e7865 setrens: always ignore -1 2023-11-08 23:29:08 -08:00
4lDO2 431dba9563 Update syscall 2023-10-19 17:07:17 +02:00
4lDO2 2d04b76a2c Close sendfd file descriptor unless consumed. 2023-10-14 15:38:21 +02:00
4lDO2 2f2e76c0ca Inform SYS_SENDFD scheme if the fd was exclusive. 2023-10-14 14:56:40 +02:00
4lDO2 1546a4a08f Implement SYS_SENDFD and SKMSG_FOBTAINFD. 2023-10-14 12:44:38 +02:00
4lDO2 da491fd5fc Disable sys:trigger_debugger by default. 2023-10-08 11:21:59 +02:00
4lDO2 6f6f69c728 Fix test instruction reg length in paranoid swapgs. 2023-10-08 11:21:23 +02:00
bjorn3 d819277d56 Make rustc directly invoke the linker 2023-10-03 09:53:37 +02:00
bjorn3 b9299224ea Move debuginfo option to Cargo.toml 2023-10-03 09:39:14 +02:00
Enver Balalic 750e566a27 Get aarch64 to compile
Fixes enough errors to get the kernel to compile
2023-10-01 23:55:24 +02:00
4lDO2 c481f6b5d4 Track state for all UserScheme calls. 2023-09-30 12:53:37 +02:00
Jeremy Soller e794f2fe9b Fix panic when there is no xsave support 2023-09-18 15:01:39 -06:00
Ivan Tan eb0d48ac81 aarch64: add dtb scheme 2023-09-18 20:45:23 +00:00
Ivan Tan a76cbc9f31 aarch64: trap msr, mrs or system instruction 2023-09-18 20:45:23 +00:00
4lDO2 5eace9997a Compile successfully on i686 as well. 2023-09-16 10:48:25 +02:00
4lDO2 0b9c5bbf49 Pass both original and padded length in altrelocs. 2023-09-16 10:33:09 +02:00
4lDO2 ed3d2d7832 Allow disabling overwrite-based optimizations. 2023-09-14 16:44:12 +02:00
4lDO2 ce0d474cb9 Fail if a feature is force-enabled but unsupported. 2023-09-14 16:28:14 +02:00
4lDO2 dfc372d241 Replace with rdgsbase dynamically in paranoid ISRs. 2023-09-14 14:43:46 +02:00
4lDO2 d90aeef62e Fix nop-filling code. 2023-09-14 14:34:04 +02:00
4lDO2 dde8f78903 Support XSAVE, XSAVEOPT, and AVX2. 2023-09-14 10:54:30 +02:00
4lDO2 38e669c807 Dynamic fsgsbase support, enable by default. 2023-09-14 09:25:30 +02:00
4lDO2 f581c71c7c Allow code-overwriting optimizations, use for smap. 2023-09-14 08:38:49 +02:00
4lDO2 dd30ae109a Ensure altcode/data/features sections are kept. 2023-09-14 08:38:08 +02:00
4lDO2 e005619b78 Add alternative! macro. 2023-09-12 21:43:37 +02:00
4lDO2 f028b77412 Use config.toml instead of x86_* Cargo feature. 2023-09-12 21:19:06 +02:00
4lDO2 c210e59a75 Add a config.toml to the kernel. 2023-09-12 21:13:58 +02:00
4lDO2 9fd2488d64 Use a compact push+jump table for IRQs. 2023-09-10 21:42:02 +02:00
Jeremy Soller 5c4961d139 Update Cargo.lock 2023-09-09 12:31:14 -06:00
Jeremy Soller 4cd76ea9e3 arch/x86: sync LogicalCpuId changes 2023-09-09 12:31:04 -06:00
Jeremy Soller a4d0960b3f Update redox syscall 2023-09-08 11:16:53 -06:00
4lDO2 6d65a93606 Remove live scheme. 2023-09-08 01:57:34 +00:00
Jeremy Soller 40a3601ca5 Update syscall 2023-09-07 16:17:57 -06:00
4lDO2 eeb0d8c1e6 Unify Interrupt{,Error}Stack. 2023-09-06 22:45:29 +02:00
4lDO2 c4a5abb34a Remove AtomicSchemeId. 2023-09-06 09:22:59 +02:00
4lDO2 126c7b7d8a Pass scheme ID to UserInner cleaner. 2023-09-06 09:21:53 +02:00
4lDO2 0d4f3125cd Use Once<SchemeId> for debug:, simplify other Once. 2023-09-06 08:58:59 +02:00
4lDO2 27d350955a Replace atomic with Once<SchemeId> for irq: 2023-09-06 08:49:37 +02:00
4lDO2 2862f7abb5 Once<SchemeId> for serio, simplify queue globals. 2023-09-06 08:48:22 +02:00
4lDO2 16cb32b178 Make WaitQueue::new() const fn. 2023-09-06 08:47:52 +02:00
4lDO2 68b03d69c0 Downgrade int_like const fn default to trait. 2023-09-06 08:46:58 +02:00
4lDO2 f025ece614 Replace from/into with get/new when necessary. 2023-09-06 08:38:10 +02:00
4lDO2 9d742387ac Replace int_like from/into with get/new, impl From. 2023-09-06 08:37:13 +02:00
4lDO2 45d1c256ea Add LogicalCpuSet as a sched affinity mask. 2023-09-04 21:57:54 +02:00
4lDO2 3b725b2c27 Add logical CPU ID newtype, switch to u32. 2023-09-04 21:27:48 +02:00
4lDO2 45e1eb7ba4 Set IA32_TSC_AUX if present. 2023-09-04 21:07:30 +02:00
4lDO2 303c96494c Improve sysretq checks. 2023-09-03 15:50:28 +02:00
4lDO2 ad02f5cbba Remove SYS_PIPE2. 2023-09-01 17:17:15 +02:00
Jeremy Soller da6e9fd8d1 Merge branch 'ivan/raspi3b' into 'master'
aarch64: init serial port by parsing dtb file

See merge request redox-os/kernel!241
2023-08-12 13:40:24 +00:00
Ivan Tan ca6699a11e aarch64: init serial port by parsing dtb file 2023-08-12 12:45:50 +08:00
Jeremy Soller 4d7d86d47c Merge branch 'mvk2' into 'master'
Set relocation-model=static

Closes #107

See merge request redox-os/kernel!240
2023-08-12 00:57:46 +00:00
4lDO2 cbd02a8489 Set relocation-model=static 2023-08-12 00:57:45 +00:00
Jeremy Soller 652aa4f1ac Merge branch 'no_more_tls' into 'master'
Replace #[thread_local]

See merge request redox-os/kernel!239
2023-08-09 14:18:16 +00:00
4lDO2 de23cd447e Fix aarch64 build. 2023-08-08 12:01:43 +02:00
4lDO2 28d4e60beb Set relocation-model=static for i686. 2023-08-08 12:01:43 +02:00
4lDO2 0dd464d428 Unset TLS model on i686. 2023-08-08 12:01:42 +02:00
4lDO2 ca92eda5e6 Remove TLS on aarch64 too. 2023-08-08 12:01:42 +02:00
4lDO2 ed2febb289 Disable thread-local storage entirely. 2023-08-08 12:01:42 +02:00
4lDO2 a78d6e42f8 Stop using #[thread_local] on x86_*. 2023-08-08 12:01:42 +02:00
4lDO2 bdd5c954dc Move PIT_TICKS to context::switch. 2023-08-08 12:01:42 +02:00
4lDO2 0c90802ae0 Fix RaiiFrame deallocation. 2023-08-08 11:57:57 +02:00
Jeremy Soller 5cabe38a78 Merge branch 'mmu' into 'master'
Demand paging

See merge request redox-os/kernel!238
2023-08-07 15:36:58 +00:00
4lDO2 4688090dea Fix RaiiFrame typo. 2023-08-03 16:46:42 +02:00
4lDO2 8f98d5b987 Extend mremap, eager mappings for real hardware. 2023-08-03 12:37:58 +02:00
4lDO2 8af63e3aae Update syscall 2023-08-03 11:50:02 +02:00
4lDO2 c7714992f3 Fix clone_grant_using_fmap test. 2023-08-02 14:17:26 +02:00
4lDO2 2070fa44b7 Fix warnings. 2023-08-02 13:07:49 +02:00
4lDO2 05a9530ac7 Temporarily disable CoW fmaps. 2023-08-01 17:29:36 +02:00
4lDO2 ef879b35ba Update RMM. 2023-08-01 15:52:34 +02:00
Jeremy Soller a992ae89ed Merge branch 'mmu' into 'master'
Demand paging related improvements

See merge request redox-os/rmm!10
2023-08-01 13:51:37 +00:00
4lDO2 34708bd1be Temporarily disable MAP_LAZY. 2023-08-01 15:44:41 +02:00
4lDO2 fe88b23d09 Use a single cow zeroed page for RO maps + eager mapping. 2023-08-01 13:11:00 +02:00
4lDO2 1e670645e4 Bypass kernel heap for storing PageInfo.
Since these are stored in arrays that are typically 512 KiB each
(i.e. which in turn typically store metadata for 128 MiB), they will
certainly be a page-size multiple, and large contiguous allocations are
allowed at least at boot time. Not only is the linked-list allocator
less efficient for that, but this change will also help reduce TLB
overhead.
2023-08-01 11:22:42 +02:00
4lDO2 8a8c04685e Merge adjacent frame sections. 2023-08-01 10:55:01 +02:00
4lDO2 0cdfb886c0 Fix debugger for x86_64, disable sc debug. 2023-07-28 13:40:00 +02:00
4lDO2 86aba2dbe5 Better VirtualAddress Debug impl. 2023-07-28 13:39:32 +02:00
4lDO2 b5937b7b91 Set aarch64 "not global" flag by default. 2023-07-28 13:38:39 +02:00
4lDO2 e28fef09e3 Improve aarch64 debugger. 2023-07-28 13:23:44 +02:00
4lDO2 d16569110e Don't mess up x18 in aarch64 exc handler. 2023-07-28 12:56:55 +02:00
4lDO2 ce35deed4b Support aarch64 page consistency checking. 2023-07-28 12:38:25 +02:00
4lDO2 f454df38eb Fix get_page_info. 2023-07-28 10:47:18 +02:00
4lDO2 ec9c24f841 WIP: aarch64 2023-07-27 19:05:33 +02:00
4lDO2 8b7fc8a468 Compile and mostly run properly on i686. 2023-07-27 16:45:36 +02:00
4lDO2 f4bdb5388e Remove AtomicU64 requirement for starting APs. 2023-07-27 16:44:52 +02:00
4lDO2 885f88b777 Fix futex for non-AtomicU64-capable targets. 2023-07-27 16:44:26 +02:00
4lDO2 25d26b3b93 Arch-independent x86-modeled page fault handler. 2023-07-27 15:56:45 +02:00
4lDO2 7a3b453fbb Declare __usercopy_{start,end} as functions. 2023-07-27 15:34:33 +02:00
4lDO2 4d2cd6ce0f Remove redundant log msg. 2023-07-27 15:25:51 +02:00
4lDO2 a4a84775d6 Fix MMAP_PREP order. 2023-07-26 22:31:56 +02:00
4lDO2 d6e1732d44 Stop using feature(arbitrary_self_types). 2023-07-25 11:22:36 +02:00
4lDO2 3cfec39b47 Pass MunmapFlags to scheme. 2023-07-25 10:52:24 +02:00
4lDO2 c9aa5ca851 WIP: Add SYS_MREMAP. 2023-07-25 10:52:24 +02:00
4lDO2 2660c3e07a WIP: Pin fmap grants that are borrowed too.
This might not be the most ideal solution, since a GiB grant can be
EBUSY blocked if a single page is used by an indefinitely-blocking
UserScheme. But, the alternatives would impose lots of additional
complexity, such as increasing the PageInfo size, adding more
refcounting arrays to grants, etc.
2023-07-25 10:52:24 +02:00
4lDO2 e054a5b211 Add debugger checks for correct CoW page flags. 2023-07-25 10:52:24 +02:00
4lDO2 37579601b2 Remove one level of indirection in get_page_info. 2023-07-25 10:52:24 +02:00
4lDO2 e2b736140f Make PageInfo atomic once again. 2023-07-25 10:52:24 +02:00
4lDO2 d58ddc35fe Complete PageInfo cleanup.
This enables proper CoW ^ shared enforcement, so that e.g. acquiring a
new CoW page from already shared memory, or vice versa, will enforce
that they aren't both simultaneously.
2023-07-25 10:52:23 +02:00
4lDO2 0f1b5b9b6f WIP: Make cow/shared refcounts mutually exclusive. 2023-07-25 10:52:23 +02:00
4lDO2 113cb5ed4e Ensure pages cannot be both CoW and shared. 2023-07-25 10:52:23 +02:00
4lDO2 d3ecedefd9 Notify schemes when mmaps are unmapped. 2023-07-25 10:52:23 +02:00
4lDO2 02f04752e8 Use proper locks for PageInfo. 2023-07-25 10:52:23 +02:00
4lDO2 7bdf5e9af3 Pass unaligned length to scheme for fmap. 2023-07-25 10:52:23 +02:00
4lDO2 afa3d7dc7b Support anonymous MAP_SHARED mmaps. 2023-07-25 10:52:23 +02:00
4lDO2 70b4d99c96 Implement MAP_FIXED without MAP_FIXED_NOREPLACE. 2023-07-25 10:52:23 +02:00
4lDO2 f0341280f7 Fix frame deallocation. 2023-07-25 10:52:23 +02:00
4lDO2 3a80528d13 Fix MAP_LAZY mappings. 2023-07-25 10:52:23 +02:00
4lDO2 cbec83215a Lazy-evaluate pages returned by fmap. 2023-07-25 10:52:22 +02:00
4lDO2 9182722f84 WIP: Allow listing address space grants again. 2023-07-25 10:52:22 +02:00
4lDO2 0466e87e59 Error if scheme fmap returns unaligned address. 2023-07-25 10:52:22 +02:00
4lDO2 ba62c0606e Pin PhysBorrowed head/tail UserScheme grants too. 2023-07-25 10:52:22 +02:00
4lDO2 329d60848c WIP: Support CoW fmap. 2023-07-25 10:52:22 +02:00
4lDO2 b24cf821c2 Support transferring grants again. 2023-07-25 10:52:22 +02:00
4lDO2 55f1829e77 Call funmap if applicable. 2023-07-25 10:52:22 +02:00
4lDO2 4ec8712fb0 Adjust fmap offsets in Grant::extract. 2023-07-25 10:52:22 +02:00
4lDO2 c5eb44d968 Increase refcount for borrowed fmap too. 2023-07-25 10:52:22 +02:00
4lDO2 b3a6a6744a Pin grants that are used in UserScheme. 2023-07-25 10:52:22 +02:00
4lDO2 954a8d00fe Make page fault handler recursive.
This is probably a bad idea, but it works for now, and can only cause
problems, if grants that borrow grants that borrow grants etc., are
used.
2023-07-25 10:52:21 +02:00
4lDO2 da6f6a316c Return only one grant, External, for Grant::borrow. 2023-07-25 10:52:21 +02:00
4lDO2 b5430359d8 Forbid scheme calls with non-RAM physmapped memory. 2023-07-25 10:52:21 +02:00
4lDO2 43c433a3f0 Remove FmapCtxt. 2023-07-25 10:52:21 +02:00
4lDO2 bf6ad5c41a Disable debugging again. 2023-07-25 10:52:21 +02:00
4lDO2 8553bc7a59 WIP: Support userspace-backed borrowing mmaps. 2023-07-25 10:52:21 +02:00
4lDO2 024f3e3828 Fix deadlock, booting to shell works now. 2023-07-25 10:52:21 +02:00
4lDO2 ad78dcc5a1 WIP: Rudimentary MAP_SHARED fmap implementation. 2023-07-25 10:52:21 +02:00
4lDO2 afa61601c4 Add ContextStatus::HardBlocked. 2023-07-25 10:52:21 +02:00
4lDO2 23fede5db0 Remove scheme funmap methods. 2023-07-25 10:52:20 +02:00
4lDO2 0c365f54e6 WIP: FmapBorrowed. 2023-07-25 10:52:20 +02:00
4lDO2 20c3adf38d WIP: Start rewriting fmap impl. 2023-07-25 10:52:20 +02:00
4lDO2 99975c0e42 WIP: Ensure that Grant::borrow does not borrow nonpresent grants. 2023-07-25 10:52:20 +02:00
4lDO2 dffc8ec9fc Do not expect PageInfo for PhysMap grants. 2023-07-25 10:52:20 +02:00
4lDO2 20a84decdf Fix MemoryScheme fmap. 2023-07-25 10:52:20 +02:00
4lDO2 15ce84164b Reminder that borrow does handle "lack of grant". 2023-07-25 10:52:20 +02:00
4lDO2 50e2f51ab3 Remove outdated #[must_use]. 2023-07-25 10:52:20 +02:00
4lDO2 f7bffacef0 Implement Drop for AddrSpace. 2023-07-25 10:52:20 +02:00
4lDO2 829d2276fb Remove Context::vfork.
Since clone is no longer exists as a syscall, it makes little sense to
manage vfork in the kernel. Implementing vfork in userspace would still
be possible.
2023-07-25 10:52:20 +02:00
4lDO2 e34a3cee42 Fix mmap/munmap, invert borrowed/owned refcount. 2023-07-25 10:52:19 +02:00
4lDO2 45ec3ecc70 Track Allocated and CoW External the same way. 2023-07-25 10:52:19 +02:00
4lDO2 7aca53753e Call init_mm from correct function. 2023-07-25 10:52:19 +02:00
4lDO2 a599d9b389 WIP: Store PageInfo in separate data structure. 2023-07-25 10:52:19 +02:00
4lDO2 760fc2ba5a WIP: Global page info structs. 2023-07-25 10:52:19 +02:00
4lDO2 593e21d95e Support schemes. 2023-07-25 10:52:19 +02:00
4lDO2 f53a1ffd53 Remove proc:pid/memory. 2023-07-25 10:52:19 +02:00
4lDO2 0a5b6ce656 Reach proc:memory access in userspace. 2023-07-25 10:52:19 +02:00
4lDO2 11fdb3bb46 Copy on writes to CoW pages. 2023-07-25 10:52:19 +02:00
4lDO2 565db7694f Add cow_refcount. 2023-07-25 10:52:19 +02:00
4lDO2 276f051d19 Further userspace progress, fix RMM bug. 2023-07-25 10:52:18 +02:00
4lDO2 8cfbc39b9f Get further in userspace. 2023-07-25 10:52:18 +02:00
4lDO2 490e1b2777 WIP: Track grant ownership. 2023-07-25 10:52:18 +02:00
4lDO2 e7d94ddff5 WIP: Lazy zeroed mapping and page fault handler. 2023-07-25 10:52:18 +02:00
4lDO2 8dfa73db35 Post-refactor fixes. 2023-07-25 10:52:18 +02:00
4lDO2 34b4512dbd Refactor Grants.
Page alignment is now verified at compile time, for example.
2023-07-25 10:52:13 +02:00
4lDO2 d4b5899c53 Remove allocator_owned hack. 2023-07-25 10:49:55 +02:00
Jeremy Soller 5cc05a281e Merge branch 'less_unstable_use' into 'master'
Reduce usage of unstable features

See merge request redox-os/kernel!230
2023-07-24 19:18:53 +00:00
Jeremy Soller c61fd1837a Merge branch 'fix_mmap' into 'master'
Fix fmap typo and remove warning.

See merge request redox-os/kernel!237
2023-07-18 18:04:42 +00:00
4lDO2 c130b18ee7 Fix fmap typo and remove warning. 2023-07-18 16:54:44 +02:00
Jeremy Soller 16912bca82 Merge branch 'replace_physmap' into 'master'
Alternative physmap via memory:physical@<mem type>.

See merge request redox-os/kernel!236
2023-07-17 16:48:32 +00:00
4lDO2 8e22e69c94 Add remap_with{,_full}. 2023-07-17 13:31:51 +02:00
4lDO2 0aa7fea250 Fix remap bug: require present before remapping. 2023-07-17 13:31:46 +02:00
Jeremy Soller eaab222011 Merge branch 'fix_is_global' into 'master'
Fix is_global.

See merge request redox-os/rmm!9
2023-07-16 16:36:55 +00:00
4lDO2 339984e49b Fix is_global. 2023-07-16 18:32:34 +02:00
4lDO2 37eb577ada Support physmap via memory:physical@<mem type>. 2023-07-15 00:28:56 +02:00
Jeremy Soller 5a9a38a948 Merge branch 'fix' into 'master'
Set space in copy_and_capture_tail.

See merge request redox-os/kernel!235
2023-07-14 13:30:42 +00:00
4lDO2 797c81eb3b Set space in copy_and_capture_tail. 2023-07-14 12:51:26 +02:00
bjorn3 e73e42be66 Replace intrinsics::abort() call in switch_finish_hook with safer abort mechanism
abort will still run the illegal instruction interrupt handler which may
not be safe.
2023-07-10 17:03:36 +02:00
bjorn3 7500ffaa5a Remove uses of the arbitrary_self_types feature 2023-07-10 17:03:36 +02:00
bjorn3 174e38a851 Remove all uses of concat_idents!() 2023-07-10 17:03:34 +02:00
bjorn3 437b70838f Replace uses of atomic_* intrinsics with Atomic* types 2023-07-10 17:02:01 +02:00
bjorn3 0d01f7be57 Use core::ptr wrappers instead of the unstable volatile_* intrinsics 2023-07-10 17:02:01 +02:00
bjorn3 6803c2c33c Remove a couple of unused feature gates 2023-07-10 17:02:01 +02:00
Jeremy Soller c1b28af544 Merge branch 'fix_debug_scheme' into 'master'
Fix debug: scheme.

See merge request redox-os/kernel!233
2023-07-10 14:29:52 +00:00
4lDO2 f700958642 Fix debug: scheme. 2023-07-10 16:26:52 +02:00
Jeremy Soller 4d6b4c24a9 Merge branch 'better_percpu' into 'master'
Simplify x86_64 percpu and GSBASE calculation

See merge request redox-os/kernel!222
2023-07-10 14:13:12 +00:00
4lDO2 3ded84c945 Simplify x86_64 percpu and GSBASE calculation 2023-07-10 14:13:12 +00:00
Jeremy Soller 5c99d73bbe Merge branch 'no_static_mut_thread_local' into 'master'
Avoid static mut thread locals

See merge request redox-os/kernel!228
2023-07-10 14:03:41 +00:00
Jeremy Soller 6440f2dcbc Merge branch 'fix_live' into 'master'
Fix live scheme

See merge request redox-os/kernel!232
2023-07-07 13:34:10 +00:00
4lDO2 9e6dfc82d0 Fix live scheme. 2023-07-07 15:00:46 +02:00
Jeremy Soller 6fca481a0a Merge branch 'mm' into 'master'
Usercopy migration

Closes #82 and #115

See merge request redox-os/kernel!219
2023-07-06 13:03:21 +00:00
4lDO2 56f88e80c2 Usercopy migration 2023-07-06 13:03:21 +00:00
Jeremy Soller b1d0851a7b Merge branch 'sys_scheme_remove_indirection' into 'master'
Replace Box<dyn Fn> with fn in sys: scheme.

See merge request redox-os/kernel!231
2023-07-06 12:56:13 +00:00
4lDO2 fa7d1c821f Replace Box<dyn Fn> with fn in sys: scheme. 2023-07-05 17:08:00 +02:00
bjorn3 56b16ce897 Avoid static mut thread locals
Instead use UnsafeCell inside the thread locals.
2023-07-05 14:50:17 +02:00
Jeremy Soller 846aa32f21 Merge branch 'panic_abort' into 'master'
Build the kernel with panic=abort

See merge request redox-os/kernel!229
2023-07-04 18:00:53 +00:00
Jeremy Soller 74e74ce633 Merge branch 'no_idtr_thread_local' into 'master'
Move IDTR thread local to a stack variable

See merge request redox-os/kernel!227
2023-07-04 17:30:43 +00:00
bjorn3 8c0be73224 Build the kernel with panic=abort
This reduces the kernel size and avoids the need to define the
eh_personality lang item.
2023-07-04 19:14:36 +02:00
bjorn3 13733fb943 Move IDTR thread local to a stack variable 2023-07-04 12:17:52 +02:00
Jeremy Soller acefb8888e Merge branch 'pipe_scheme' into 'master'
Improved pipe scheme.

Closes #84

See merge request redox-os/kernel!226
2023-06-27 13:35:14 +00:00
4lDO2 5abf16a51e Improved pipe scheme. 2023-06-26 13:54:13 +02:00
Jeremy Soller 7269f9c6f1 Merge branch 'fix_df' into 'master'
Always clear DF when entering the kernel

See merge request redox-os/kernel!223
2023-06-18 12:54:19 +00:00
4lDO2 416269eeaf Always clear DF when entering the kernel. 2023-06-18 14:47:00 +02:00
Jeremy Soller 78a8173f62 Merge branch 'aarch64-stuff' into 'master'
More aarch64 stuff

See merge request redox-os/kernel!221
2023-06-13 13:49:25 +00:00
uuuvn a5d4ccba57 More aarch64 stuff 2023-06-13 10:15:47 +00:00
Jeremy Soller 2849510892 Copy HPET divide by zero workaround to x86 arch 2023-06-12 09:19:34 -06:00
Jeremy Soller 503a21d461 Merge branch 'aarch64-stuff' into 'master'
Improve aarch64 code + memory management and crush some bugs

See merge request redox-os/kernel!220
2023-06-12 15:17:51 +00:00
uuuvn 63290429b2 Improve aarch64 code + memory management and crush some bugs 2023-06-12 14:46:02 +00:00
Jeremy Soller e24e8485ba Merge branch 'aarch64-stuff' into 'master'
Add GLOBAL flag and prettify some stuff

See merge request redox-os/rmm!8
2023-06-12 12:12:09 +00:00
uuuvn d89e6008e8 Add GLOBAL flag and prettify some stuff 2023-06-12 10:23:40 +00:00
Jeremy Soller 0ae3958a8c Merge branch 'fix-lsp-helix' into 'master'
Fix LSP in helix

See merge request redox-os/kernel!218
2023-06-10 12:18:52 +00:00
uuuvn ffe9bb8593 Fix LSP in helix 2023-06-10 08:50:25 +00:00
Jeremy Soller 0deb0d79e1 Merge branch 'file_forwarding_v2' into 'master'
Allow schemes to return external file descriptors

See merge request redox-os/kernel!215
2023-06-08 12:02:35 +00:00
4lDO2 aa1420d599 Update syscall. 2023-06-08 11:11:20 +02:00
Jeremy Soller 37746c0743 Merge branch 'fix-aarch64' into 'master'
Fix aarch64

See merge request redox-os/kernel!217
2023-06-07 13:42:02 +00:00
uuuvn d502418e49 Fix aarch64 2023-06-06 15:36:30 +00:00
Jeremy Soller a9bdb51deb Merge branch 'master' into 'master'
Update README.md: add command to build docs

See merge request redox-os/kernel!216
2023-06-05 23:03:28 +00:00
Florian Meißner 33bdf8e5b6 Update README.md: add command to build docs 2023-06-05 19:14:42 +00:00
4lDO2 ce77703146 Move forwarded files rather than copying them. 2023-06-02 14:50:44 +02:00
4lDO2 b1d4f55e0a Use kopen and kdup in syscall handlers. 2023-06-02 14:50:44 +02:00
4lDO2 c7ba937bbf Support forwarding in UserScheme. 2023-06-02 14:50:40 +02:00
Jeremy Soller da5063375e Merge branch 'context_name' into 'master'
Remove one level of indirection for Context::name.

See merge request redox-os/kernel!214
2023-05-30 13:36:48 +00:00
4lDO2 58c0c5d040 Remove one level of indirection for Context::name. 2023-05-27 14:27:34 +02:00
Jeremy Soller 34894e3d73 Merge branch 'fix_aarch64' into 'master'
Fix unaligned_references error on aarch64

See merge request redox-os/kernel!213
2023-05-06 16:37:06 +00:00
4lDO2 a451c0aa1b Fix aarch64 build. 2023-05-06 17:49:39 +02:00
Jeremy Soller 89d560e6e5 Merge branch 'fix-sigreturn-dos' into 'master'
Fix kernel DoS via sigreturn from non-signal context

See merge request redox-os/kernel!211
2023-05-04 12:32:24 +00:00
uuuvn 4621cd674d Fix kernel DoS via sigreturn from non-signal context 2023-05-04 15:58:05 +04:00
Jeremy Soller 3a6732eaad Merge branch 'updated_rustc_and_futex_fixes' into 'master'
Fixes for futex and newer rustc

See merge request redox-os/kernel!209
2023-05-02 22:11:53 +00:00
Jeremy Soller 37ba7c63b4 Merge branch 'qemu_hpet_bug' into 'master'
Qemu hpet bug

See merge request redox-os/kernel!210
2023-05-02 16:19:01 +00:00
Andrew Mackenzie d3a2fe7083 Qemu hpet bug 2023-05-02 16:19:01 +00:00
4lDO2 50b877d1aa Remove ignored unaligned_references exception. 2023-04-30 18:13:55 +02:00
4lDO2 c604d6b051 Make IDT #[repr(C)]. 2023-04-30 18:13:27 +02:00
4lDO2 99ffc370e8 Work around repr(packed) but not fixing UB. 2023-04-30 18:11:34 +02:00
4lDO2 a5168b4442 Fix warnings. 2023-04-30 18:11:20 +02:00
4lDO2 45f031b50d Improve clone_entry lock granularity. 2023-04-30 17:54:05 +02:00
4lDO2 6c3f577f05 Also translate the 12-bit page offset in SYS_FUTEX. 2023-04-30 17:53:17 +02:00
4lDO2 62eab8a2fe Retry rather than panic if clone_entry is unset. 2023-04-09 12:04:08 +02:00
Jeremy Soller 4bf307d88e Merge branch 'fix_mem_fns' into 'master'
Fix memcpy, memmove, memset, and memcmp.

Closes #99

See merge request redox-os/kernel!208
2023-04-01 21:17:54 +00:00
4lDO2 78557eff18 Fix memcpy, memmove, memset, and memcmp. 2023-04-01 21:30:10 +02:00
Jeremy Soller 42de1f3e9c Merge branch 'master' into 'master'
Add QEMU tip.

See merge request redox-os/kernel!206
2023-03-14 15:25:59 +00:00
Jeremy Soller 295bcbdac8 Update redox_syscall 2023-03-14 09:25:17 -06:00
Ribbon 32300c2d9e Add QEMU tip. 2023-03-12 15:16:05 +00:00
Jeremy Soller 6fb14edcb0 Merge branch 'context-switch-optimization' into 'master'
Context switch optimization

See merge request redox-os/kernel!205
2023-03-09 21:33:27 +00:00
Jeremy Soller 12688a929e Context switch optimization
- Contexts for other CPUs will never be evaluated for switch
- Running contexts will never be evaluated for switch
- Arc::clone is only called for previous and next context when there is a context to switch to
- Lots of cleanup to the switch function
2023-03-09 14:30:12 -07:00
Jeremy Soller 3bf381caf8 Do not panic if ACPI is not available 2023-03-03 18:56:23 -07:00
Jeremy Soller 11e6dd7b24 Merge branch 'master' into 'master'
Improve text organization.

See merge request redox-os/kernel!202
2023-02-28 14:11:38 +00:00
Ribbon f1b45f658f Improve text organization. 2023-02-28 12:46:34 +00:00
Jeremy Soller 4b3337e479 Merge branch 'master' into 'master'
Kernel notes (moved from CONTRIBUTING).

See merge request redox-os/kernel!201
2023-02-28 12:27:09 +00:00
Ribbon 2c593fb0b9 Move from CONTRIBUTING to kernel README. 2023-02-28 08:10:33 +00:00
Jeremy Soller 12d5830097 Merge branch 'pin_kmain_contexts' into 'master'
Pin kmain contexts

Closes #111

See merge request redox-os/kernel!200
2023-02-27 16:22:46 +00:00
4lDO2 b73922bc95 Also fix outdated-#![feature(...)] warnings. 2023-02-24 23:16:57 +01:00
4lDO2 ac913e49f9 Pin kmain contexts to corresponding CPUs. 2023-02-24 23:05:11 +01:00
Jeremy Soller 87e1689b56 Merge branch 'sched_affinity' into 'master'
Support scheduler CPU affinity.

See merge request redox-os/kernel!199
2023-02-15 15:44:39 +00:00
4lDO2 8d14d54fa9 Support scheduler CPU affinity. 2023-02-15 14:50:01 +01:00
Jeremy Soller cb58500b68 Update for new Rust 2023-02-11 14:50:55 -07:00
Jeremy Soller 7aeb9f0ac8 Remove rust-toolchain 2023-02-11 14:50:26 -07:00
Jeremy Soller 55fd7dfff7 Add centiseconds to context time 2023-01-30 10:51:32 -07:00
Jeremy Soller e5c3be86cd Ensure unmounting is read from atomic in all cases 2023-01-12 07:33:54 -07:00
Jeremy Soller 85e0a7c368 Record mappings in funmap with page aligned size, always 2022-12-21 18:29:15 -07:00
Jeremy Soller 523d00eeac Make it possible to track syscall time when debugging 2022-12-19 10:11:59 -07:00
Jeremy Soller d298459686 Add sys:irq 2022-11-18 14:18:06 -07:00
Jeremy Soller 1e81c9d78b Fix compilation without ACPI feature 2022-11-16 13:53:04 -07:00
Jeremy Soller 111606ccdc Increase PIT divisor again to reduce wasted interrupt handling time 2022-11-15 11:50:23 -07:00
Jeremy Soller 33aa263deb Fixes for hpet counter read, choose better PIT divisor 2022-11-14 13:58:55 -07:00
Jeremy Soller 2052cc8cdc Allow arch to provide higher precision time 2022-11-14 11:12:44 -07:00
Jeremy Soller 31868077f0 Use u128 for time, store CPU time of processes 2022-11-14 10:10:17 -07:00
Jeremy Soller ee6c9f4020 Fix compilation on i686 2022-11-11 13:23:07 -07:00
Jeremy Soller 8e0f54cb31 Clippy fixes 2022-11-11 13:19:14 -07:00
Jeremy Soller 515a03b870 Fix warnings 2022-11-11 12:51:07 -07:00
Jeremy Soller 6bef3afee6 Support bootloader stride 2022-09-16 12:29:38 -06:00
Jeremy Soller 3bef7d7bad Simplify ps2 interrupts to reduce latency to reading bytes 2022-09-08 10:33:31 -06:00
Jeremy Soller f5bdae2d0c Reduce schreduler time slices to reduce latency 2022-09-07 18:21:30 -06:00
Jeremy Soller 07ed93225e 0.3.4: Update syscall to matching version 2022-08-31 16:15:25 -06:00
Jeremy Soller 6753251af3 Do not allow mmap with page_count 0 2022-08-31 16:14:27 -06:00
Jeremy Soller 21108d57fe Update syscall 2022-08-30 10:33:22 -06:00
Jeremy Soller 7fbe5112ca Allow physmap with unaligned size 2022-08-29 09:41:35 -06:00
Jeremy Soller 1b3c6a957d Add aarch64 debugger 2022-08-28 09:27:38 -06:00
Jeremy Soller 8d8437a5d3 Update rmm 2022-08-28 09:19:17 -06:00
Jeremy Soller 81b03cc693 Improve aarch64 tlb flushing 2022-08-28 09:19:07 -06:00
Jeremy Soller 91b5d64c22 Use current address space for proc kfmap workaround 2022-08-27 18:05:20 -06:00
Jeremy Soller 2278fd7fe1 Workaround to ensure proc kfmap does not try to map kernel memory 2022-08-27 10:55:52 -06:00
Jeremy Soller 1fadde3ee8 Eliminate deadlock in capture_inner 2022-08-27 07:48:47 -06:00
Jeremy Soller 6f6648c4d2 Disable HPET use on x86 2022-08-26 11:13:53 -06:00
Jeremy Soller 6dbb85d4c9 Static mapping of some CPU devices outside of physmap 2022-08-26 11:08:13 -06:00
Jeremy Soller 27bb8e44dd Do not allow phys_to_virt overflow 2022-08-26 11:07:21 -06:00
Jeremy Soller 002425d625 Fix trampoline on x86 2022-08-26 08:24:04 -06:00
Jeremy Soller 33b8fcecfb Sync x86_64 trampoline with bootloader 2022-08-26 08:08:24 -06:00
Jeremy Soller fb1bdf7c3e Ignore null bytes from pl011 uart 2022-08-25 20:10:35 -06:00
Jeremy Soller 6a3fc5a68a Send SIGSEGV on aarch64 exception 2022-08-25 20:00:53 -06:00
Jeremy Soller 80b8382cd7 Fix aarch64 kfx size 2022-08-25 18:40:19 -06:00
Jeremy Soller 82ac7a66f7 Only save preserved regs in aarch64 context switch 2022-08-25 18:23:51 -06:00
Jeremy Soller 52434b359c Disable building aarch64 asm 2022-08-25 18:12:43 -06:00
Jeremy Soller ff738074d2 Cleanup aarch64 code 2022-08-25 15:46:27 -06:00
Jeremy Soller afd82ba4bb Save/restore aarch64 FPU regs 2022-08-25 09:30:53 -06:00
Jeremy Soller 31680bf5b9 Do not set tpidr_el0 from kernel 2022-08-25 08:46:26 -06:00
Jeremy Soller b3b5bb8a91 Simplify handling of aarch64 env regs 2022-08-25 08:12:07 -06:00
Jeremy Soller f7e8026494 Set aarch64 thread pointers 2022-08-24 19:21:36 -06:00
Jeremy Soller 545a561a26 Set ptrace regs for aarch64 2022-08-24 19:03:30 -06:00
Jeremy Soller 84704353af Support address space change on aarch64 2022-08-24 18:54:42 -06:00
Jeremy Soller 6d3fa8b374 Enable clone_handler on aarch64 2022-08-24 15:50:10 -06:00
Jeremy Soller b20a71113c Implement aarch64 switch_to_inner using naked function 2022-08-24 13:24:37 -06:00
Jeremy Soller fb34e4eddf Partially implement stack trace on aarch64 2022-08-24 12:34:31 -06:00
Jeremy Soller 0ed9f03317 Use push/pop scratch for aarch64 signal handler 2022-08-24 12:29:48 -06:00
Jeremy Soller 613968dc30 Use push/pop scratch for x86 signal handler 2022-08-24 11:39:31 -06:00
Jeremy Soller 113a7164bb Use push/pup scratch for x86_64 signal handler 2022-08-24 11:11:50 -06:00
Jeremy Soller 310a0dda08 Some aarch64 register struct updates 2022-08-24 08:56:57 -06:00
Jeremy Soller bb12da2b68 Update syscall 2022-08-24 08:53:37 -06:00
Jeremy Soller 54d9d011aa Use framebuffer virtual address 2022-08-23 20:07:30 -06:00
Jeremy Soller 2b8af1cf07 Ignore areas outside 1GiB and combine memory areas on x86 2022-08-23 15:41:29 -06:00
Jeremy Soller aa51e9812d Use PAT flags on x86 2022-08-22 19:54:14 -06:00
Jeremy Soller f3e23af9ec Update rmm 2022-08-22 18:49:42 -06:00
Jeremy Soller 61ba2e6c8e Fix unmap_parents 2022-08-22 18:49:32 -06:00
Jeremy Soller 06d952979f Implement debugger for x86 2022-08-22 08:41:35 -06:00
Jeremy Soller 58104649db Set limits for x86 GDT entries 2022-08-21 14:56:59 -06:00
Jeremy Soller 538ad9e57f Remove debug message when writing x86 EnvRegisters 2022-08-21 13:22:58 -06:00
Jeremy Soller d3fbbd5918 Pre-allocate x86 kernel PD entries 2022-08-21 13:21:59 -06:00
Jeremy Soller 0d4ff5d4f3 Add functions for accessing mapper allocator 2022-08-21 13:20:44 -06:00
Jeremy Soller bdba700c21 Disable syscall debugging 2022-08-20 21:52:09 -06:00
Jeremy Soller 76a46c54b8 Fix stack selector on x86 2022-08-20 21:51:21 -06:00
Jeremy Soller c750ee26a8 Implement setting FS/GS offset on x86 2022-08-20 21:21:32 -06:00
Jeremy Soller 01e4bc899e Fix compilation on x86 2022-08-20 18:11:57 -06:00
Jeremy Soller d3f42989c9 Fix compilation on x86_64 2022-08-20 14:51:05 -06:00
Jeremy Soller 9dd069c8ca Support proc partially with aarch64 2022-08-20 14:45:45 -06:00
Jeremy Soller 9b8abfc5d7 Copy exception handlers from early_init 2022-08-20 13:48:13 -06:00
Jeremy Soller 44d5e6573a Updated utable switching code for aarch64 2022-08-20 13:31:20 -06:00
Jeremy Soller fe7def2797 Update to use TableKind on x86_64 2022-08-20 13:16:23 -06:00
Jeremy Soller 01df1c20da Use TableKind everywhere 2022-08-20 13:06:52 -06:00
Jeremy Soller 3911fc616a Update rmm 2022-08-20 13:01:01 -06:00
Jeremy Soller df733ed571 Use TableKind for most table operations 2022-08-20 13:00:48 -06:00
Jeremy Soller 849b854bd0 Implement usermode for aarch64 2022-08-20 09:34:12 -06:00
Jeremy Soller c7e5466bd7 Fix aarch64 switch_to_inner functino definition 2022-08-20 09:15:26 -06:00
Jeremy Soller 157dbc7b4d Convert aarch64 context switching to asm macro 2022-08-20 09:08:14 -06:00
Jeremy Soller 9ca2484079 Get aarch64 kernel to boot to the point of needing context switch 2022-08-19 21:40:04 -06:00
Jeremy Soller 82ad6e2fa7 Remove devmap region from aarch64, use physmap instead 2022-08-19 21:01:10 -06:00
Jeremy Soller ba64d82818 Make kstart the aarch64 entry point 2022-08-19 21:00:47 -06:00
Jeremy Soller 97b4d31355 Match aarch64 PHYS_OFFSET with x86_64 2022-08-19 20:54:02 -06:00
Jeremy Soller c5eb435d79 Match PHYS_OFFSET accross archs 2022-08-19 20:53:15 -06:00
Jeremy Soller a1411353a9 Update rmm 2022-08-19 19:52:39 -06:00
Jeremy Soller e05868e1dc Improve aarch64 paging instructions 2022-08-19 19:52:00 -06:00
Jeremy Soller 49fcafac45 Fix building on aarch64 2022-08-19 16:12:42 -06:00
Jeremy Soller 38361661e6 Add proc scheme stubs for aarch64 2022-08-19 16:00:35 -06:00
Jeremy Soller 80fc1d7fd4 Remove phys_offset stack hack 2022-08-18 15:03:35 -06:00
Jeremy Soller 6b2439f1b9 Improved 32-bit x86 support 2022-08-18 14:57:15 -06:00
Jeremy Soller c09be1770b Use registers for switch_to_inner instead of stack 2022-08-18 09:09:11 -06:00
Jeremy Soller 472081f8ba Save/restore GS segment on interrupt 2022-08-17 21:13:35 -06:00
Jeremy Soller bd9ee98ba9 Use same code for clone_handler on 32-bit and 64-bit x86 2022-08-17 14:40:30 -06:00
Jeremy Soller d47ba636a0 Support x86 in proc scheme 2022-08-17 14:32:12 -06:00
Jeremy Soller 679662c99e Name bootstrap process 2022-08-17 13:25:13 -06:00
Jeremy Soller 4bd137f36e Fixes for x86 32-bit 2022-08-17 10:48:23 -06:00
Jeremy Soller 1eda828877 Merge branch 'userspace_cwd' into 'master'
Remove SYS_CHMOD and cwd related syscalls/files.

See merge request redox-os/kernel!198
2022-08-16 09:17:37 +00:00
4lDO2 67c0b911b4 Update syscall 2022-08-16 10:45:04 +02:00
4lDO2 c3c135cb1d Remove chmod from UserScheme 2022-08-13 19:44:44 +02:00
4lDO2 431407aff0 Remove SYS_CHMOD and cwd related syscalls/files. 2022-08-13 19:44:44 +02:00
Jeremy Soller ac70c76922 Fix TSS and IDT structures on 32-bit x86 2022-08-12 09:03:56 -06:00
Jeremy Soller 9c78219a6a Use 32-bit TSS for x86 32-bit 2022-08-12 08:44:05 -06:00
Jeremy Soller d33ff704ba Implement usermode for x86 32-bit 2022-08-12 08:21:49 -06:00
Jeremy Soller 4602b81a2f Fix debugger when dumping kernel threads 2022-08-03 11:08:49 -06:00
Jeremy Soller 3ba1b018b7 Warn but otherwise allow unaligned sizes in funmap 2022-08-03 11:08:18 -06:00
Jeremy Soller 7a390c2a1d Sync some paging code for aarch64 with x86_64 2022-08-01 08:25:33 -06:00
Jeremy Soller 2191308d15 setup_new_utable for aarch64 2022-07-29 18:58:19 -06:00
Jeremy Soller 358abbd40f Fix copy paste error and update rmm 2022-07-29 18:53:27 -06:00
Jeremy Soller e9950ee6da Fix more warnings 2022-07-29 18:53:12 -06:00
Jeremy Soller 07015d17ba Sync x86 and x86_64 2022-07-29 18:49:55 -06:00
Jeremy Soller 166e1e304b Update syscall 2022-07-29 18:39:34 -06:00
Jeremy Soller 62c62c4e7c Update rmm 2022-07-29 18:38:12 -06:00
Jeremy Soller 23d4995e50 Fix warnings 2022-07-29 18:37:37 -06:00
Jeremy Soller 5d55d4eb87 Fix warnings 2022-07-29 18:33:54 -06:00
Jeremy Soller cc6c974c91 Bump kernel to 0.3.0 to match syscall 2022-07-29 18:18:27 -06:00
Jeremy Soller be12d0f1bd Add initial i686 arch module 2022-07-29 18:12:49 -06:00
Jeremy Soller 9b74fb3ff1 Update syscall 2022-07-29 18:07:44 -06:00
Jeremy Soller e99cbcf5d2 Fixes for compiling aarch64 2022-07-29 18:06:53 -06:00
Jeremy Soller 897cd4c9f4 Add graphical_debug module 2022-07-29 15:57:02 -06:00
Jeremy Soller 0c80643077 Make graphical_debug arch independent and fix lots of warnings 2022-07-29 15:56:44 -06:00
Jeremy Soller 87acffe859 Fix kernel TLS permissions in INIT_GDT 2022-07-29 09:28:13 -06:00
Jeremy Soller 4d1c41232b Support inner_physmap on 32-bit systems 2022-07-29 09:27:54 -06:00
Jeremy Soller 059f2a0d07 Support ContextList::spawn on i686 2022-07-29 09:27:35 -06:00
Jeremy Soller a1d9edee52 Use Mutex<u64> instead of AtomicU64 for user scheme packet ID 2022-07-29 09:25:40 -06:00
Jeremy Soller bf9e630f65 Fix building proc scheme on non-x86_64 2022-07-29 09:25:17 -06:00
Jeremy Soller f0d3e3281c Use acpi on i686 2022-07-28 08:22:55 -06:00
Jeremy Soller 8db4596f73 Use x86 crate on i686 as well 2022-07-28 08:22:26 -06:00
Jeremy Soller fdb4ad8e88 Only build debugger on x86_64 for now 2022-07-28 08:21:31 -06:00
Jeremy Soller 8d5ca62499 Add linker and target for i686 2022-07-28 08:20:49 -06:00
Jeremy Soller a45a7c696e Merge branch 'fix-bootstrap' into 'master'
Fix bootstrap

See merge request redox-os/kernel!196
2022-07-28 13:38:27 +00:00
4lDO2 f3faf33e3f Add a workaround to treat bootstrap mem as owned. 2022-07-28 14:17:02 +02:00
4lDO2 ca4525462d Return right number of bytes written for addrspace. 2022-07-28 14:16:07 +02:00
4lDO2 2d935ca6d3 Update cargo.lock 2022-07-27 18:01:58 +02:00
Jeremy Soller 7fcdd8f6e2 Merge branch 'userspace_fexec' into 'master'
Userspace fexec

See merge request redox-os/kernel!195
2022-07-27 15:40:58 +00:00
4lDO2 e58bf714d8 Update rmm and syscall 2022-07-27 17:39:16 +02:00
4lDO2 5700899e9a Merge branch 'migrate_kernel_to_rmm' into 'master'
Add necessary functionality for migrating kernel paging code to RMM

See merge request redox-os/rmm!6
2022-07-27 15:10:52 +00:00
4lDO2 99362f98d2 Add a better interface for modifying addrspaces. 2022-07-27 10:52:52 +02:00
4lDO2 939feacdc5 Add fn for validating user memory range bounds. 2022-07-27 10:52:46 +02:00
4lDO2 5bbfdcda6b Add mmap-min-addr and support unmapping parent PTs. 2022-07-27 10:52:45 +02:00
4lDO2 0720db2265 Remove SYS_EXEC debug code. 2022-07-27 10:52:29 +02:00
4lDO2 308c2cc711 Support modifying processes' sigactions.
This is, other than vfork, the last piece of functionality that the
previous clone() offered (CLONE_SIGHAND) which previously was not
implemented.
2022-07-27 10:52:29 +02:00
4lDO2 b766501896 Fix deadlock while starting APs. 2022-07-27 10:52:29 +02:00
4lDO2 bf82387f3b Fix KernelMapper unlocking code. 2022-07-27 10:52:29 +02:00
4lDO2 e60321d4a0 Partial: migrate remaining parts to RMM. 2022-07-27 10:52:23 +02:00
4lDO2 dc8ce1c22b Partial: migrate context handling code to RMM. 2022-07-27 10:52:23 +02:00
4lDO2 c912d9e0db Partial: migrate syscall handling code to RMM. 2022-07-27 10:52:23 +02:00
4lDO2 6589083238 Partial: Migrate schemes to RMM. 2022-07-27 10:52:23 +02:00
4lDO2 486d296d6d Remove old x86_64 paging code, migrate to RMM. 2022-07-27 10:52:23 +02:00
4lDO2 302e55098c Migrate misc x86_64 parts to RMM. 2022-07-27 10:52:23 +02:00
4lDO2 2bb019bc44 Partial: migrate debugger, add consistency check. 2022-07-27 10:52:23 +02:00
4lDO2 648b0edb41 Partial: migrate allocator to RMM. 2022-07-27 10:52:23 +02:00
4lDO2 0aec4d3341 Partial: migrate ACPI to RMM. 2022-07-27 10:52:23 +02:00
4lDO2 8970ce1fe7 Benefit from addrspace abstraction in switch. 2022-07-27 10:52:22 +02:00
4lDO2 1cdd462244 Move the initfs scheme to userspace. 2022-07-27 10:52:22 +02:00
4lDO2 351d77ad9b Improve floating point handling. 2022-07-27 10:52:22 +02:00
4lDO2 94578efd1e Use alloc_zeroed when allocating FX. 2022-07-27 10:52:22 +02:00
4lDO2 db3b834f19 Also inherit pgid, umask, sigmask. 2022-07-27 10:52:22 +02:00
4lDO2 4aea0cfd0c Fix AddrSpace memory leak. 2022-07-27 10:52:22 +02:00
4lDO2 b141cdaad2 Fail if funmap's length isn't page size divisible. 2022-07-27 10:52:22 +02:00
4lDO2 60e3e0af34 Flush less frequently in funmap. 2022-07-27 10:52:22 +02:00
4lDO2 549c023398 Return correct bytes written in proc:X/addrspace. 2022-07-27 10:52:22 +02:00
4lDO2 59d74689dc Copy filetable more efficiently. 2022-07-27 10:52:22 +02:00
4lDO2 0b67997c7b Fix "id == current" check in set_addr_space. 2022-07-27 10:52:21 +02:00
4lDO2 240d91f951 Set address space/files when closing, not writing.
This fixes file descriptor leaks. Suppose relibc is just about to set
the address space. For this, it needs to write the address space fd to
the selection fd. To avoid having to close them in the kernel, it rather
memorizes what the file descriptors refer to internally, and then do the
actual operation when they are gone, i.e. when closing.
2022-07-27 10:52:19 +02:00
4lDO2 fa48c7aa97 Deduplicate code for transferring/creating grants. 2022-07-27 10:52:11 +02:00
4lDO2 cb40eb3792 Support reading all grants and transferring grants. 2022-07-27 10:52:10 +02:00
4lDO2 b50495bfa5 WIP: Support clone in userspace
Everything seems to work for the most part, but now there are tons of
daemons which rely on syscall::clone, which is now implemented in relibc
:(
2022-07-27 10:52:04 +02:00
4lDO2 283ada82a0 WIP: Remove SYS_CLONE (to be done in userspace). 2022-07-27 10:52:03 +02:00
4lDO2 563121596d Fix running on multi_core.
Turns out the problem all along was that the ActivePageTable was never
dropped in usermode_bootstrap. So as soon as any other hardware thread
tried to do page table business, it deadlocked!
2022-07-27 10:51:45 +02:00
4lDO2 6e5015dcab WIP: Add necessary interfaces for setuid/setgid. 2022-07-27 10:51:45 +02:00
4lDO2 37f9b292f1 Add kfmap to fix properly reobtaining grants. 2022-07-27 10:51:45 +02:00
4lDO2 de28cc4918 Add a Scheme supertrait for kernel-only methods. 2022-07-27 10:51:45 +02:00
4lDO2 31c4bc8a1c Remove kernel support for fmap_old and funmap_old. 2022-07-27 10:51:45 +02:00
4lDO2 23f49414bd Fix phys offset, lock grants correctly. 2022-07-27 10:51:45 +02:00
4lDO2 15b029de36 Fix everything all the way to booting to desktop. 2022-07-27 10:51:45 +02:00
4lDO2 e6e1348072 Implement exec, and change UserGrant allocator. 2022-07-27 10:51:44 +02:00
4lDO2 f7f722f81c Don't use identity mapping for ACPI.
This is so that any process can use pointers to ACPI tables, since they
now point to the universally-accessible KERNEL_OFFSET+physaddr virtual
addresses.
2022-07-27 10:51:44 +02:00
4lDO2 846318e716 WIP: Attempt implementing fexec in userspace. 2022-07-27 10:51:43 +02:00
4lDO2 67edfbfc42 Remove the unused USER_HEAP_PML4. 2022-07-27 10:50:53 +02:00
4lDO2 9462df03e7 Add support for unmapping parents.
Currently, this uses a relatively naive method of simply scanning the
512 entries for the PRESENT flag. But, unless the optimizer cannot, it
can be reduced to calculating the bitwise OR of every entry and then
checking that.

If this turns out to be too slow, which it might be when unmapping lots
of pages, then we can (1) either fall back to using a counter like the
old paging code did, or even better (2) use the now-1:1 grants tree to
check if it became empty. Putting the grants code in RMM might be
suboptimal, so instead we can add "unmap_range" and have the kernel
paging code take the offset of the next grant, if any, and then possibly
unmap entire P1s/P2s/P3s -- whatever is in the page tables within that
range.

Note that I am fairly certain that method (1) was the cause of the
visually notorious orbital memory corruption bug.
2022-07-27 10:49:49 +02:00
4lDO2 229ae5da40 Add remaining interfaces to user RMM for user mem. 2022-07-27 10:49:49 +02:00
4lDO2 efc67a2012 Use wrapped flags for PageEntry. 2022-07-27 10:49:49 +02:00
4lDO2 fad6afa7d8 Flush on Drop, unless explicitly ignored. 2022-07-27 10:49:49 +02:00
4lDO2 7a209c83c9 Implement Debug for X8664Arch. 2022-07-27 10:49:49 +02:00
4lDO2 c847b1e2a8 Implement FrameAllocator for mutable refs of impls. 2022-07-27 10:49:49 +02:00
4lDO2 2f16dddf25 Add a page flusher trait. 2022-07-27 10:49:49 +02:00
Jeremy Soller 76d29bac78 Update rmm 2022-07-26 20:16:47 -06:00
Jeremy Soller 0944b17983 Add initial x86 32-bit support 2022-07-26 20:13:55 -06:00
Jeremy Soller ec284ca8e3 Update rust-toolchain 2022-07-26 19:01:42 -06:00
Jeremy Soller ac38e62398 Update syscall 2022-07-26 15:30:51 -06:00
Jeremy Soller b5a9301706 Map live disk only if not already mapped 2022-04-26 12:01:55 -06:00
Jeremy Soller 65bbd50416 Update kernel version to match syscall version 2022-04-26 08:28:05 -06:00
Jeremy Soller e88e7d6df1 Fix HPET on real hardware with better debugging 2022-04-25 15:08:09 -06:00
Jeremy Soller 6f83a0800a Set graphical_debug by default 2022-04-25 08:47:10 -06:00
Jeremy Soller 6e98736c94 Do not map live disk twice 2022-04-25 08:43:51 -06:00
Jeremy Soller 7205dd7463 Unmap xAPIC page if already mapped 2022-04-12 20:17:27 -06:00
Jeremy Soller 8f06672153 Merge branch 'external-initfs' into 'master'
External initfs

See merge request redox-os/kernel!192
2022-04-11 21:09:08 +00:00
4lDO2 df37b1f634 External initfs 2022-04-11 21:09:08 +00:00
Jeremy Soller dc9e6eaf0c Merge branch 'clone_grant_using_fmap_v2' into 'master'
Fix "clone grant using fmap"

See merge request redox-os/kernel!193
2022-04-11 20:19:41 +00:00
4lDO2 4d7da495f5 Fix "clone grant using fmap"
This does the same as the previous MR, but fixes the issue where the
parent process got the mapping (and at the wrong address) and not the
child process.
2022-04-11 21:31:36 +02:00
4lDO2 e72fd5a0e4 Fix a kernel deadlock in empty().
For more information, see https://gitlab.redox-os.org/4lDO2/kernel/-/commit/b3b5d1b864eec030d53ccd2ab907c68958f140aa
2022-04-09 13:38:59 +02:00
Jeremy Soller 87b3bef06c Revert "Merge branch 'clone_grant_using_fmap' into 'master'"
This reverts merge request !190
2022-03-30 14:54:49 +00:00
Jeremy Soller 37ebef2d35 Merge branch 'pipe_list_const_fn' into 'master'
Move more of `pipe:`'s initialization to compile time.

See merge request redox-os/kernel!182
2022-03-30 13:54:27 +00:00
Jeremy Soller cbc2902852 Merge branch 'context_list_const_fn' into 'master'
Pre-initialize the context list at compile time.

See merge request redox-os/kernel!181
2022-03-30 13:53:57 +00:00
Jeremy Soller c5c5b33b6a Merge branch 'clone_grant_using_fmap' into 'master'
Clone grant using fmap

See merge request redox-os/kernel!190
2022-03-30 13:53:08 +00:00
4lDO2 b9c34b3c05 Merge branch 'update-toolchain-2022' into 'master'
Update to latest toolchain.

See merge request redox-os/kernel!191
2022-03-27 09:17:09 +00:00
4lDO2 51e339c973 Update rmm and syscall. 2022-03-24 15:55:16 +01:00
Jeremy Soller 507f7ccd4a Merge branch 'update-toolchain-2022' into 'master'
Update to latest toolchain.

See merge request redox-os/rmm!5
2022-03-23 18:06:11 +00:00
4lDO2 a5f4e9a52a Update syscall. 2022-03-19 22:09:17 +01:00
4lDO2 8644f82b48 Remove unused Xargo.toml. 2022-03-19 22:09:03 +01:00
4lDO2 6255bea143 Update to latest toolchain.
Multi-core is slightly broken when using the latest version of spin
(0.9.2). I believe this is because Once used to do SeqCst loads/stores
everywhere, which might have made any possible data race much harder to
come by.
2022-03-12 17:10:36 +01:00
Jeremy Soller 80376a95dc Improve graphical debug performance 2022-03-08 07:36:01 -07:00
Jeremy Soller 150717f18e Enable local apic error interrupt on all processors 2022-03-07 13:56:46 -07:00
Jeremy Soller b62496f50e Debug HPET init 2022-03-07 13:56:17 -07:00
4lDO2 e2648005ba Update to latest toolchain. 2022-03-06 11:34:22 +01:00
Jeremy Soller 7e2e7b8c21 Log reasons why HPET not used 2022-03-02 08:43:11 -07:00
Jeremy Soller ae3bdea4bc Update raw-cpuid 2022-03-01 18:12:06 -07:00
Jeremy Soller d234df37c9 Improve RMM logging 2022-03-01 17:57:03 -07:00
Jeremy Soller fe468aa1ab Improvements for graphical debug and system76 EC debug 2022-03-01 16:25:15 -07:00
Jeremy Soller 2b5aa1f375 Cleanup of graphical debug to allow it to run much earlier 2022-03-01 15:50:26 -07:00
Jeremy Soller ae0d48d9ab Identity map ACPI 2022-03-01 12:52:06 -07:00
Jeremy Soller 47c3bbe13a Update syscall 2022-03-01 09:28:17 -07:00
Jeremy Soller 81e700708d Get memory areas as argument instead of from hardcoded pointer 2022-02-14 11:52:02 -07:00
Jeremy Soller 933b3b8fc0 Respect min flag to allocate_frames_complex 2022-02-14 10:29:12 -07:00
Jeremy Soller c1aa76bf3c Fill in st_dev in fstat 2022-02-14 09:57:24 -07:00
Jeremy Soller 52ad689d37 Notify debug: readers of new input after all input is processed 2022-02-14 08:49:34 -07:00
Jeremy Soller 1aae949fc4 Support for getting live disk from bootloader 2022-02-10 15:49:34 -07:00
Jeremy Soller 9e6664fb82 Fix additional page mapping in graphical debug 2022-02-10 14:48:52 -07:00
Jeremy Soller 7d9a33c63a Add debugger (dumps all kernel state) 2022-02-10 14:10:04 -07:00
Jeremy Soller f92fe90069 Use requested page table in trampoline 2022-02-07 17:49:23 -07:00
Jeremy Soller 1b2a28a4f0 Use FRAMEBUFFER variables for graphical debug 2022-02-07 17:38:52 -07:00
Jeremy Soller 413238a0a6 Prevent re-use of real mode areas, adjust areas instead of panic 2022-02-07 16:36:05 -07:00
Jeremy Soller b109263e77 Ensure ACPI RSDPs are not re-used 2022-02-05 19:59:02 -07:00
Jeremy Soller 308c5ad3d9 Make sure kernel, stack, and env are identity mapped 2022-02-04 11:16:54 -07:00
Jeremy Soller 941f59283b Map kernel to KERNEL_OFFSET, remove bump_offset 2022-02-03 20:21:00 -07:00
Jeremy Soller 5104437423 WIP: changes for rust bios bootloader 2022-02-03 17:15:28 -07:00
Jeremy Soller bbc4a4aefe workaround for crash on graphical debug finish 2022-01-28 09:47:47 -07:00
Jeremy Soller 3f2a9f7f0a Fix graphical debug feature 2022-01-28 09:15:03 -07:00
4lDO2 a3356c3fdd Clone grant using fmap 2021-12-30 11:27:44 +01:00
Jeremy Soller 0ab4529eaa Make register dumps lowercase 2021-12-01 09:53:33 -07:00
Jeremy Soller cd3dcf153e Do not print interpreter 2021-12-01 08:40:11 -07:00
Jeremy Soller 63fcc204cb x86 paging refactor for debugger 2021-11-30 20:56:55 -07:00
Jeremy Soller 77b8215a66 Getter for Grant region, remove set_mapped, and make region_mut private 2021-11-30 20:06:45 -07:00
Jeremy Soller 4f259e3589 Workaround for thread race conditions 2021-11-30 18:03:34 -07:00
Jeremy Soller 515cab03eb Fix a number of warnings 2021-11-29 20:01:27 -07:00
Jeremy Soller 61279db991 Remove no_threaded_syscalls feature 2021-10-27 20:48:16 -06:00
Jeremy Soller 61d8b0ff32 Fix allocator race condition 2021-10-27 20:29:00 -06:00
Jeremy Soller 063881d2ca Show context name and syscall when panicking 2021-10-27 20:28:40 -06:00
Jeremy Soller 9ea278997c Disable threaded syscalls until threaded allocation issues are solved 2021-10-20 20:05:47 -06:00
Jeremy Soller 64f1533d6f Implement anonymous fmap 2021-09-22 21:04:04 -06:00
Jeremy Soller 17309754d6 Merge branch 'no-more-recursive-mapping' into 'master'
No more recursive mapping

See merge request redox-os/kernel!187
2021-08-13 02:13:07 +00:00
4lDO2 307fcf3ad7 Remove now unused TLS struct. 2021-08-11 17:46:40 +02:00
4lDO2 d6e1797620 Make Mapper::map fallible. 2021-08-11 17:46:40 +02:00
4lDO2 df145ea0a9 Utilize linear_phys_to_virt where applicable. 2021-08-11 17:46:40 +02:00
4lDO2 16a31b0cd1 Add linear_phys_to_virt and vice versa.
However, since not all platforms will allow the entire physical address
space to be simultaneously mapped to part of the virtual address space,
we may still require some dynamic mapping.
2021-08-11 17:46:40 +02:00
4lDO2 5f4978a6dc Return ENOMEM rather than panicking for PML4 alloc. 2021-08-11 17:46:40 +02:00
4lDO2 67cc6799bd Fix possible UB by checking for null allocating FX.
Namely, the global allocator API in Rust, actually only returns a null
pointer on failure, rather than wrapping it in a Result, which AllocRef
does. Since Box::from_raw(null) is direct UB, this can in theory lead to
very strange behavior.
2021-08-11 17:46:40 +02:00
4lDO2 465c461b60 WIP: Stop using recursive mapping.
Note that this is very preliminary, and I merely got my already freezing
kernel branch not to triple fault, but I would probably apply this patch
to upstream.

What is changed here, is that rather than relying on recursive mapping
for accessing page table frames, it now uses linear translation
(virt=phys+KERNEL_OFFSET). The only problem is that the paging code now
makes assumptions that the entire physical address space remains mapped,
which is not necessarily the case on x86_64 architecturally, even though
systems with RAM more than a PML4 are very rare. We'd probably lazily
(but linearly) map physical address space using huge pages.
2021-08-11 17:46:33 +02:00
Jeremy Soller 0c3542ff51 Store funmap data with the context's grants 2021-08-10 20:46:30 -06:00
Jeremy Soller f94dc3beb8 Allow current process to access its own proc data 2021-08-10 16:33:49 -06:00
Jeremy Soller 0b1445f8bd Merge branch 'fix_interrupt_handlers' into 'master'
Fix TLS in paranoid interrupt handlers

See merge request redox-os/kernel!186
2021-08-09 21:19:39 +00:00
4lDO2 1a80351a2c Fix TLS in paranoid entries. 2021-08-09 14:25:15 +02:00
4lDO2 41d5a2a786 Use naked functions in syscall inst handler too. 2021-08-06 18:08:04 +02:00
4lDO2 d7a1c6255b Fix possible race condition in paranoid ISRs.
Additionally, because it turned out to be infeasible to rely on
link-time constants in global_asm! code, I have also converted the
interrupt handlers to naked fns. This removes the proc-macro-reliant
"paste" dependency, but inserts a tiny ud2 at the end of every ISR.
2021-08-06 17:34:56 +02:00
4lDO2 1047728f35 Only set process regs for faults from ring 3.
This fixes a deadlock that might occur if a page fault is triggered
while a lock to the current context is held.
2021-08-06 15:41:38 +02:00
4lDO2 862265f150 Merge branch 'fsgsbase' into 'master'
FSGSBASE and user-controlled TLS

See merge request redox-os/kernel!185
2021-08-06 13:22:45 +00:00
4lDO2 25a82eeb1b Update syscall again. 2021-08-06 15:09:32 +02:00
4lDO2 57a1e37535 Update syscall. 2021-08-06 14:46:47 +02:00
4lDO2 87241a9d3c Pass AT_PHDR via a grant rather than the stack. 2021-08-01 14:57:41 +02:00
4lDO2 3eedbeb14d WIP: Let userspace manage fsbase/gsbase and TLS. 2021-08-01 12:09:22 +02:00
4lDO2 0968e4f87e Support fsgsbase at compile time. 2021-07-31 10:12:59 +02:00
Jeremy Soller 9c3cf84453 Merge branch 'futex_wait64' into 'master'
Add support for full 64-bit futex words

See merge request redox-os/kernel!183
2021-07-11 22:14:10 +00:00
4lDO2 6993c98e0f Update rmm and syscall. 2021-07-12 00:10:48 +02:00
Jeremy Soller 37e88ff4d3 Merge branch 'virt_is_canonical' into 'master'
Add Arch::virt_is_valid

See merge request redox-os/rmm!4
2021-07-11 21:33:34 +00:00
4lDO2 bbe6b4650a Futex: check for lower-half addrs manually. 2021-07-08 16:08:02 +02:00
4lDO2 6bc59e7013 Remove virt_kind, impl virt_is_valid() for riscv.
All there is left now is AArch64.
2021-07-08 16:06:51 +02:00
4lDO2 bcfd7b175e Update rmm. 2021-07-08 13:47:16 +02:00
4lDO2 b75c329a27 Add virt_kind and virt_is_valid for emulation. 2021-07-08 13:35:51 +02:00
4lDO2 9e9d025bb5 Add support for FUTEX_WAIT64. 2021-07-08 13:28:46 +02:00
4lDO2 32caee3095 Add arch functions for checking canonical addrs. 2021-07-08 13:27:08 +02:00
4lDO2 e92ff831b7 Move more of pipe:s init to compile time. 2021-07-05 11:54:11 +02:00
4lDO2 f2926f5f25 Pre-initialize the context list at compile time. 2021-07-05 11:30:08 +02:00
Jeremy Soller b973c5db95 Merge branch 'dont-hardcode-reg-offsets' into 'master'
Use offset_of! in context::arch::switch_to.

See merge request redox-os/kernel!180
2021-06-21 19:06:56 +00:00
4lDO2 3e5cf387d5 Use offset_of! in context::arch::switch_to.
This is definitely better than hardcoding the offsets!
2021-06-21 10:16:41 +02:00
4lDO2 6039026349 Merge branch 'update_toolchain' into 'master'
Update toolchain

See merge request redox-os/kernel!179
2021-06-18 15:15:15 +00:00
4lDO2 ecfcedb9bf Remove explicit .intel_syntax directive.
It is now default, and the new compiler generated a lot of warnings now
that Intel syntax has (luckily) become the default.
2021-06-18 09:20:13 +02:00
4lDO2 1cf5f5ea22 Update dependencies to work with latest nightly. 2021-06-17 22:42:54 +02:00
4lDO2 2dc899dc3b Update paste and align interrupt handlers. 2021-06-17 22:42:50 +02:00
4lDO2 7594dd60d2 Remove compare_and_swap from int_like!. 2021-06-17 22:42:44 +02:00
4lDO2 7d4defa5e5 Use weak CAS and use abort() in context::switch.
Previously context::switch used compare_and_swap for acquiring the
global context switch lock, but given its deprecation in more recent
Rust versions, it has been replaced with compare_exchange_weak (which
can be further optimized on some architectures).

It also replaces panic!() with abort() in switch_finish_hook, because
unwinding from assembly is not that fun.
2021-06-17 22:42:38 +02:00
4lDO2 cc6f792a03 Use options(noreturn) in all naked functions. 2021-06-17 22:42:31 +02:00
4lDO2 dc5f1fe055 Update toolchain. 2021-06-17 22:42:23 +02:00
4lDO2 c66956ca2a Remove unused #![feature(const_fn)]. 2021-06-17 18:42:03 +02:00
Jeremy Soller d3cf4db47b Prerequisites for risv64 support 2021-05-12 20:23:53 -06:00
Jeremy Soller 0a79c17307 Show meaning of CODE on page fault 2021-05-10 11:34:14 -06:00
Jeremy Soller 8130e4752b Map TSS using RMM 2021-05-07 09:13:25 -06:00
Jeremy Soller 77f6887fbc Debug use of memory map and env data 2021-05-07 08:54:36 -06:00
Jeremy Soller 38f7884e21 Improvements for aarch64 serial driver on real hardware 2021-05-06 21:25:15 -06:00
Jeremy Soller 2c474f98f9 Merge branch 'higher_half_percpu' into 'master'
Put the KPCRs in high memory, in their own PML4.

See merge request redox-os/kernel!173
2021-05-06 19:25:16 +00:00
4lDO2 36b3a4a49e Add KERNEL_PERCPU_PML4 on AArch64. 2021-05-06 21:22:48 +02:00
4lDO2 558109a9cb Put the KPCRs in high memory, in their own PML4.
This also removes the need to do another semi-expensive remap when
cloning processes, since the KPCRs (for kernel TLS) are no longer stored
in the user PML4.
2021-05-06 21:21:37 +02:00
Jeremy Soller 2e38fab913 Do not hardcode aarch64 uart 2021-05-06 13:16:50 -06:00
Jeremy Soller c4617c0bce Merge branch 'outsource-most-acpi' into 'master'
Move most of ACPI to userspace

See merge request redox-os/kernel!175
2021-05-06 18:36:06 +00:00
4lDO2 3eacbdda2a Remove unnecessary exit() diff. 2021-05-06 19:49:58 +02:00
4lDO2 fd97fa80bb Move pid back to inner scope in exit() handler. 2021-05-06 19:49:58 +02:00
4lDO2 a771ca699a Move all DMAR parsing to userspace.
We may also want to do this with the MADT and the HPET tables, and let
user drivers specify what the tables mean independent of ACPI. That is,
adding an interface for registering new CPUs, and specifying the main
timer IRQ.
2021-05-06 19:49:58 +02:00
4lDO2 e816d4801f Remove the empty fadt module. 2021-05-06 19:49:58 +02:00
4lDO2 9b4ce0d0cc WIP: Fix userspace ACPI shutdown. 2021-05-06 19:49:58 +02:00
4lDO2 b2e131b57b Fix ACPI scheme fevent warning. 2021-05-06 19:49:58 +02:00
4lDO2 7ac5bdbae0 WIP: Implement userspace-driven shutdown. 2021-05-06 19:49:58 +02:00
4lDO2 64b2dd238a Rename the kernel ACPI scheme to kernel/acpi:. 2021-05-06 19:49:57 +02:00
4lDO2 bea6747643 Move all AML code to userspace.
Currently, there are some things that need to be set up by userspace
that the kernel previously did. These include telling firmware when the
I/O APIC is used, and most importantly, shutting down the system.

The former is not particularly important, but for the latter I think
that we could implement this using a "shutdown pipe". Essentially it
will be a file that triggers an event shutting down, which would be used
to notify to acpid that the kernel is requesting a shutdown.
2021-05-06 19:49:57 +02:00
Jeremy Soller 28d1d7e847 Update version to 0.2.8 2021-05-05 21:21:57 -06:00
Jeremy Soller 46a364471c Re-init aarch64 serial port for interrupts 2021-05-05 20:46:51 -06:00
Jeremy Soller 11a3315255 Re-enable acpi feature and gate it for x86_64 only 2021-05-04 08:33:00 -06:00
Jeremy Soller ac8c7834ef Update linked branch of rmm and syscall 2021-05-04 08:14:43 -06:00
Jeremy Soller bdccce4a1b Update rmm and syscall 2021-05-04 08:12:18 -06:00
Jeremy Soller c81c4de223 Add method to get TableKind from VirtualAddress 2021-05-04 08:10:44 -06:00
Jeremy Soller 5e47692b8d Support more operations on PageFlags 2021-05-04 08:10:44 -06:00
Jeremy Soller 2f74326384 Add riscv64 sv39 and sv48 2021-05-04 08:10:34 -06:00
Jeremy Soller 3dc08c878f Fix aarch64 switch_to function 2021-05-04 08:07:44 -06:00
Jeremy Soller b9a89f2160 More fixes for building aarch64 2021-05-03 22:07:40 -06:00
Jeremy Soller 8f50785781 Fixes for building aarch64 2021-05-03 21:57:45 -06:00
Jeremy Soller c646cb76e5 Update rmm 2021-05-03 21:29:44 -06:00
Jeremy Soller 8d61c79b23 Use RMM TableKind and fix x86_64 compilation 2021-05-03 21:15:46 -06:00
Jeremy Soller 2aa4d8caf5 Merge remote-tracking branch 'origin/aarch64-rebase' into riscv64 2021-05-03 20:52:59 -06:00
Jeremy Soller 17c261553b Fixes for building x86_64 2021-05-03 20:43:18 -06:00
Jeremy Soller dfdb562e6b Use RMM PhysicalAddress 2021-05-03 20:33:31 -06:00
Jeremy Soller 9f0532b1d5 Remove unused flags from old EntryFlags 2021-05-03 17:29:55 -06:00
Jeremy Soller b9448274fc Switch to using RMM PageFlags 2021-05-03 17:28:08 -06:00
Jeremy Soller 826180659c Update rmm and syscall 2021-05-03 17:16:59 -06:00
Jeremy Soller ff8cb8abe8 Enforce must_use 2021-05-03 15:02:32 -06:00
Jeremy Soller dd0616cc8f Use RMM for TLB flushing 2021-05-03 12:42:16 -06:00
Jeremy Soller 29460e0bff Use RMM for some arch-specific paging functions 2021-05-03 12:14:49 -06:00
Jeremy Soller c46d148e26 Fix tests for aarch64 2021-05-02 21:25:27 -06:00
Jeremy Soller ad39568fe9 Fix unwrapping stack when there are kernel addresses (and there always are) 2021-05-02 19:53:31 -06:00
4lDO2 af17eeec3a Give schemes a dangling address for empty slices.
This allows schemes to avoid checking the length against zero before
constructing a slice from pointer+len that the kernel gave.
Additionally, the address is now non-canonical on x86, meaning that
userspace will fail instead of continuing with UB, if they would ever
forget to check the length.
2021-04-29 07:40:50 -06:00
Jeremy Soller 73c77d756d Print context name in exception 2021-04-28 21:15:21 -06:00
Jeremy Soller 37e6951501 Print CPU and PID when exception occurs 2021-04-28 20:59:52 -06:00
Jeremy Soller d331f72f2a Use UTF-8 for all paths 2021-04-28 20:06:07 -06:00
Jeremy Soller 8fcd375bd9 Switch Context::grants to RwLock 2021-04-28 20:04:27 -06:00
Jeremy Soller 41bea0086f Switch Context::actions to RwLock 2021-04-28 20:03:29 -06:00
Jeremy Soller 83dea72a50 Switch Context::files to RwLock 2021-04-28 20:03:25 -06:00
Jeremy Soller c7aba8fdfd Switch Context::cwd to using RwLock 2021-04-28 20:03:18 -06:00
Jeremy Soller a9bee0bbdc Require UTF-8 for context name 2021-04-28 20:03:12 -06:00
Jeremy Soller b26c3e0ae9 Make context name a RwLock 2021-04-28 20:03:05 -06:00
Jeremy Soller f90033e0e1 Use PHYS_OFFSET instead of KERNEL_OFFSET to refer to the physmap 2021-04-13 20:38:54 -06:00
Jeremy Soller afca4da382 Update syscall 2021-04-13 19:34:38 -06:00
Jeremy Soller 959a917ba2 Update RMM 2021-04-13 19:34:27 -06:00
Jeremy Soller 7fd1218465 Merge remote-tracking branch 'origin/aarch64-rebase' 2021-04-13 19:12:48 -06:00
Jeremy Soller 5fe8dcf6af Merge branch 'chown-perms' into 'master'
UserScheme: permission check EUID and EGID before proceeding with chown

See merge request redox-os/kernel!176
2021-03-21 13:02:41 +00:00
Joshua Abraham ee6493d02e UserScheme: permission check EUID and EGID before proceeding with chown
Fixes redox#1327.
2021-03-20 20:42:02 -05:00
Jeremy Soller 47048102ef Fix typo in ContextList 2021-03-02 19:57:44 -07:00
Jeremy Soller b8e47f6b8f Merge branch 'fix-invalid-grant-state' into 'master'
Fix "Grant should not exist" errors.

See merge request redox-os/kernel!174
2021-03-02 13:30:03 +00:00
4lDO2 031496ff0d Fix "Grant should not exist" errors.
This is done by making sure that when empty() is called on a context,
the grants Arc will be replaced with a new unused Arc, hence
decrementing the refcount. Previously this was only done when the
context was actually reaped, but since there is no guarantee as far as I
am aware about when this must happen, the grants could be completely
leaked, leading to the error.
2021-02-27 15:36:12 +01:00
Jeremy Soller f873fc7e1a Merge branch '4lDO2/kernel-use_gs_for_tls' 2021-02-23 09:21:00 -07:00
Jeremy Soller ba330ffc9a Merge branch 'fix-utf8-userspace-ub' into 'master'
Give schemes a dangling address for empty slices, fixing UB in userspace

See merge request redox-os/kernel!172
2021-02-23 16:17:30 +00:00
4lDO2 ad58ca1de6 Give schemes a dangling address for empty slices.
This allows schemes to avoid checking the length against zero before
constructing a slice from pointer+len that the kernel gave.
Additionally, the address is now non-canonical on x86, meaning that
userspace will fail instead of continuing with UB, if they would ever
forget to check the length.
2021-02-20 17:20:30 +01:00
4lDO2 bdc925d275 Use GS for TLS!
Previously, the kernel used the regular FS segment for Thread-Local
Storage. The problem however, is that userspace code also uses FS for
TLS, meaning that the kernel would have to switch the FS segment between
user and kernel, _upon every syscall_. This is obviously suboptimal for
performance (especially with fast syscalls such as futex, nanosleep, or
yield).

I had to search LLVM for hours, just to find out that the insertion of
the memory load with FS was actually done in the linker, so I added a
flag for that.

I haven't done any proper benchmarking, but the boot process seems to
have gotten much faster!
2021-02-17 14:44:45 +01:00
Jeremy Soller a283160c14 Merge branch 'sysretq-fix2' into 'master'
FIX: Forbid lower-half noncanonical addresses too.

See merge request redox-os/kernel!170
2021-02-17 13:32:26 +00:00
4lDO2 1988583e23 Forbid lower-half noncanonical addresses too. 2021-02-17 13:00:07 +01:00
Jeremy Soller 98af1405e6 Merge branch 'sysretq-fix' into 'master'
Fix mistyped instructions in sysretq

See merge request redox-os/kernel!169
2021-02-15 19:12:05 +00:00
4lDO2 a4b3af34a5 Use correct jump instruction. 2021-02-15 20:05:00 +01:00
4lDO2 c19581282d Use the correct add instruction when popping CS. 2021-02-15 20:02:35 +01:00
Jeremy Soller 2a9b7a0fc8 Merge branch 'sysretq' into 'master'
Use faster sysretq when returning from system calls

See merge request redox-os/kernel!168
2021-02-15 18:59:19 +00:00
4lDO2 8eb58891aa Simplify sysretq code. 2021-02-15 19:53:49 +01:00
4lDO2 5b2df9f504 Document why usermode() can omit rcx check. 2021-02-15 19:53:49 +01:00
4lDO2 ff33090fd0 Check whether RCX is canonical in sysretq. 2021-02-15 19:53:41 +01:00
4lDO2 a183953ee8 Motivate usage of the IST without SWAPGS involved. 2021-02-15 19:53:37 +01:00
4lDO2 a3583a10ce Only swapgs when leaving/entering userspace code. 2021-02-15 19:53:37 +01:00
4lDO2 05db0f5977 Temporarily fix sysretq by swapping gs 4 times.
In order words, it swaps gs both directly at the start of the syscall
handler, then swaps it back, and the at the end of the syscall handler.
I cannot tell for sure why this is necessary, but probably since some
interrupt handler will execute swapgs in the wrong order or something.
2021-02-15 19:53:37 +01:00
4lDO2 1a8016b985 Give NMI, #DF, and #MC handlers a special stack.
This is done by allocating an extra 64 KiB per CPU, and putting it in
the Interrupt Stack Table.
2021-02-15 19:53:37 +01:00
4lDO2 5a638691e0 Treat GS as always pointing to TSS in kernel space. 2021-02-15 19:53:37 +01:00
4lDO2 c913c3be80 Use sysretq in usermode(). 2021-02-15 19:53:24 +01:00
4lDO2 a8dc3fcaf1 Begin using sysretq in the system call handler. 2021-02-15 19:53:01 +01:00
Jeremy Soller 6db78cce24 Use UTF-8 for all paths 2021-02-14 13:45:03 -07:00
Jeremy Soller 11b5e2fe59 Merge branch 'switch_to_safer' into 'master'
Prevent possible UB, and use naked functions correctly.

See merge request redox-os/kernel!167
2021-02-13 22:42:18 +00:00
4lDO2 a706a0dae4 Rewrite signal_handler_wrapper as single asm block.
The reason for these types of rewrites, is that more recent Rust
compilers have started to deprecate naked functions that consist of more
than only a single asm block, as they can trigger all sorts of UB.
2021-02-13 21:55:40 +01:00
4lDO2 47c3b2269f Fix context switching.
Previously there was a triple fault, due to a combination of reasons
(e.g. rsp and rbp being ordered in the struct and in the assembly).

Now, the locks will be held __all the way until the new context__ has
been switched to, which completely eliminates any possibility that the
"pcid fault" originates here.

While I am unsure whether this will work, this could also be an
opportunity to be able to remove CONTEXT_SWITCH_LOCK fully.
2021-02-13 21:55:40 +01:00
4lDO2 ef4270e473 WIP: Attempt to rewrite switch_to in assembly.
This is due to a warning in more recent compilers, which forbid anything
but a single inline assembly block, in naked functions. It does
unfortunately triple fault right now, but I hope I may be able to fix it
soon.
2021-02-13 21:55:36 +01:00
Jeremy Soller c19bd573b5 Switch Context::grants to RwLock 2021-02-13 13:06:13 -07:00
Jeremy Soller 2611985a38 Switch Context::actions to RwLock 2021-02-13 13:01:20 -07:00
Jeremy Soller bfaf8438a1 Switch Context::files to RwLock 2021-02-13 12:57:53 -07:00
Jeremy Soller 55d2467420 Switch Context::cwd to using RwLock 2021-02-13 12:24:19 -07:00
Jeremy Soller cd6ede84fe Fix warnings from futex changes 2021-02-13 12:16:55 -07:00
Jeremy Soller 238702f7d1 Require UTF-8 for context name 2021-02-13 12:16:47 -07:00
Jeremy Soller b9f4a915ea Make context name a RwLock 2021-02-13 11:10:21 -07:00
Jeremy Soller 76d8c1074c Merge branch 'futex-fix' into 'master'
Use physical addresses internally in futex, and fix a context switching data race

See merge request redox-os/kernel!166
2021-02-13 17:52:09 +00:00
4lDO2 6f3fc3a4f4 Make cpu_id_opt non-mutable. 2021-02-03 18:10:39 +01:00
4lDO2 44527a8340 Fix a very annoying multi_core data race*.
So, when I first introduced io_uring, it was not compiled with the
`multi_core` kernel feature, mainly to make development easier (I
thought). However, since io_uring allows multiple simultaneous system
calls, we cannot longer make the in-kernel contexts block, for example
when receiving a message from a pipe, if there can be multiple such
requests simultaneously.

This has required me to change WaitCondition into allowing multiple
simultaneous tasks; although, it introduces a potential race condition:
since a future can only return Pending and not block directly before
releasing the lock (condvar logic), we need some way to make sure that
nothing happens after the context finds out that it has to wait, and the
actual waiting. If a message is pushed in between, and the waker is
called (Context::unblock), just before it was going to block itself,
then we miss the message, and potentially cause a deadlock.

Fortunately, in order to block and unblock contexts, we need to
exclusively lock the context. So, what we can do to ensure that waking
while running is no longer a no-op, is to introduce a "wake flag", which
is set only if the context is currently running, and Runnable.

But, this still caused all weird kinds of hard-to-debug problems, with
arbitrary CPU exceptions and possibly memory corruption. The reason for
this, is that the context switching logic uses really unsafe operations,
which is why context switching (at the moment) requires an exclusive
lock. Before this commit, it would modify the `running` field after the
lock had been released, which obviously can cause a data race, when the
regular context waker code that is run within a system call, locks the
context but not the global switching lock.

The solution was to make sure that the locks were held, all the way
until the actual switching, which was done in assembly. There can still
be a race condition here, since it modifies memory containing registers
after the lock has been released, even if it may be behind &mut on
another context, which can be UB, but it has not contributed to any
actual bugs... yet.

* I have not yet done that rigorous testing, but it appears to work well
enough, and I have not encountered the bug after like 10 tries.
2021-02-03 18:06:42 +01:00
4lDO2 fec8f4aa0c Use physical addresses internally for futexes.
This solves a bug, that allows processes in different address spaces to
be the target of a futex wakeup call, even though that process is in
another address space!
2021-02-03 18:06:42 +01:00
Jeremy Soller 31887bf532 Merge branch 'floating-point-fixups' into 'aarch64-rebase'
Floating point fixups

See merge request redox-os/kernel!165
2021-01-28 17:02:32 +00:00
Robin Randhawa 1e10cac3e1 aarch64: Increase storage for FP context to consider AArch64's needs
Brute-forcing this at present. Would be better to wrap this
conditionally for the architecture.
2021-01-28 16:51:50 +00:00
Robin Randhawa afca6ab31c aarch64: Fix incorrect FP save/restore 2021-01-28 16:50:07 +00:00
Jeremy Soller a06636b77f Update syscall 2021-01-27 10:44:52 -07:00
Jeremy Soller f8f1596f67 Merge branch 'add-floating-point-support' into 'aarch64-rebase'
Add floating point support

See merge request redox-os/kernel!164
2021-01-27 17:43:57 +00:00
Robin Randhawa 4dbfaf3ec1 Nit: Add missing close brace in code comment 2021-01-27 17:19:37 +00:00
Robin Randhawa 1462fe8638 aarch64: context: Align with x86_64 code 2021-01-27 17:17:59 +00:00
Robin Randhawa 3afa0f0895 aarch64: Basic Floating-point/SIMD support 2021-01-27 17:17:11 +00:00
Robin Randhawa 00723c4ac2 aarch64: Make IRQs use the exception macros 2021-01-26 19:37:23 +00:00
Jeremy Soller 9621c64991 Update syscall 2021-01-26 11:46:09 -07:00
Jeremy Soller 81c33a3f6a Merge branch 'aarch64-base' into 'aarch64-rebase'
Misc exception handling fixups

See merge request redox-os/kernel!163
2021-01-26 18:41:53 +00:00
Robin Randhawa 28dfc0f46b aarch64: Basic exception handlers 2021-01-26 18:18:19 +00:00
Robin Randhawa 4a215c7c2c aarch64: exception management and clone fixups 2021-01-26 18:17:09 +00:00
Jeremy Soller fa62b48285 Merge branch 'fixes-for-grant-maps-and-others' into 'aarch64-rebase'
Fixes for grant maps and others

See merge request redox-os/kernel!162
2021-01-22 15:15:08 +00:00
Robin Randhawa 78d1cd1798 syscall: process: empty: Use user-space specific page table 2021-01-21 11:53:35 +00:00
Robin Randhawa 6cacbb47f6 scheme: user: Use user-space specific pagt table 2021-01-21 11:53:07 +00:00
Robin Randhawa 591775874b ptrace: with_context_memory: use user-space specific page table 2021-01-21 11:50:56 +00:00
Robin Randhawa 65448c2d48 aarch64: context: memory: Grant::map_inactive: Bugfix
When mapping one (from) virtual address range to another (to) virtual
address range, be mindful of which mapper type to use for each range.

Before this, the same mapper type was used for both ranges. This meant
that if from and to were different (as in not both kernel virtual
addresses or user virtual addresses) then it would appear that either
from or to was not mapped previously and the kernel would panic.
2021-01-21 11:41:26 +00:00
Robin Randhawa 75870a655f aarch64: context: Add separate kspace and uspace page table getters 2021-01-21 11:40:02 +00:00
Robin Randhawa 3da345867a aarch64: paging: Derive Debug, PartialEq for VirtualAddressType
This makes asserts on VirtualAddressType equality possible.
2021-01-21 11:38:46 +00:00
Robin Randhawa 452196b81f aarch64: consts: Use the same USER_TLS_SIZE as x86_64 2021-01-21 11:37:32 +00:00
Jeremy Soller d76298b3f8 Merge branch 'wip-clone-and-misc-fixes' into 'aarch64-rebase'
Wip clone and misc fixes

See merge request redox-os/kernel!161
2021-01-18 23:00:00 +00:00
Robin Randhawa f1db56f026 aarch64: clone: Further uspace and kspace mods 2021-01-18 21:55:42 +00:00
Robin Randhawa 9429032cec aarch64: clone: Further clone_ret + tpidr_el0 fixes 2021-01-18 21:53:04 +00:00
Robin Randhawa fd0336692d aarch64: clone: Introduce kernel and user space specific mods
At present these are done 'wholesale' without any regard for x86_64.
That needs to change eventually.
2021-01-18 21:50:19 +00:00
Robin Randhawa c188a60871 aarch64: Fix clone_ret
FIXME: Explain the magic numbers here later.
2021-01-18 21:47:28 +00:00
Robin Randhawa 95bd8f2013 clone: Make stack manipulation arch specific 2021-01-17 10:26:49 +00:00
Robin Randhawa ae0aebd036 aarch64: clone: Return from clone syscall
No CLONE_STACK functionality yet.
2021-01-17 10:12:42 +00:00
Robin Randhawa 67ec6c23e7 aarch64: Move tpidr_el0 setup from spawn to switch 2021-01-17 10:09:03 +00:00
Robin Randhawa 67d72532a9 aarch64: usermode: Remove tpidr_el0 manipulation
Was using the incorrect USER_TLS_OFFSET instead of USER_TCB_OFFSET. In
any case, this is better done in process::clone.
2021-01-17 10:06:04 +00:00
Robin Randhawa 3585f620b0 aarch64: clone: Fix incorrect stack offset in clone_ret 2021-01-17 10:03:50 +00:00
Robin Randhawa 208fb681f4 aarch64: vectors: Manage unhandled exceptions
So we can more clearly see when things go wrong.
2021-01-17 10:01:34 +00:00
Jeremy Soller 17fd135017 Merge branch 'pagetabletype-and-misc-fixes' into 'aarch64-rebase'
Pagetabletype and misc fixes

See merge request redox-os/kernel!158
2021-01-15 19:50:13 +00:00
Jeremy Soller e124fa171b Merge branch 'misc-fixes' into 'aarch64-rebase'
Misc fixes

See merge request redox-os/kernel!160
2021-01-15 19:43:23 +00:00
Robin Randhawa 5bc9dea242 aarch64: context::switch: update the CONTEXT_SWITCH_LOCK 2021-01-15 19:03:42 +00:00
Robin Randhawa 6677cfbf1e aarch64: Make interrupt::pause use nop so we can move ahead before interrupts are enabled 2021-01-15 19:02:43 +00:00
Robin Randhawa 825bc4a02d aarch64: spawn: split out arch specific mods 2021-01-15 09:12:30 -07:00
Robin Randhawa 14d79927af aarch64: Add a set_tcb method to setup tpidr_el0 2021-01-15 09:12:30 -07:00
Robin Randhawa ae3a55f5d1 Introduce a PageTableType enum to help distinguish User and Kernel Tables 2021-01-15 09:12:30 -07:00
Robin Randhawa 76129ddf75 aarch64: Mirror PRESENT and VALID bits in Page and Table descriptors 2021-01-15 15:54:25 +00:00
Robin Randhawa c5e077546a aarch64: spawn: split out arch specific mods 2021-01-15 15:51:47 +00:00
Robin Randhawa e0a7471cf8 aarch64: Add a set_tcb method to setup tpidr_el0 2021-01-15 15:50:00 +00:00
Robin Randhawa 9c3f6e3660 Introduce a PageTableType enum to help distinguish User and Kernel Tables 2021-01-15 15:49:04 +00:00
Jeremy Soller bdea7f553a Remove PRESENT flag from aarch64 descriptors 2021-01-15 06:57:02 -07:00
Jeremy Soller 5f8b004476 Fix typo in InterruptStack parameter 2021-01-15 06:56:36 -07:00
Robin Randhawa 252ec24905 aarch64: Use target-feature for NEON insn suppression and tpidr_el1 use 2021-01-15 06:09:42 -07:00
Robin Randhawa aa3839605f aarch64: Remove code-model from the JSON spec
We use a target-feature for this now.
2021-01-15 06:09:42 -07:00
Robin Randhawa ea21fba3aa build.rs: aarch64: Specify target for cc::Build
Oddly, not specifying this or using aarch64-unknown-none (which would be
the default that cc gets from the TARGET environment variable) both
fail to invoke the appropriate compiler to build the asm code.

Using aarch64-unknown-redox works but shouldn't really be needed. This
is perhaps because of some odd arrangement of KTARGET, TARGET, the
installed prefix toolchain and the kernel target JSON spec.

The early_init asm code shall be replaced by a pure Rust bootloader
eventually so let's move with this for the moment.
2021-01-15 06:09:42 -07:00
Robin Randhawa 02c37d3fae WIP: aarch64 rebase 2021-01-15 05:54:42 -07:00
Jeremy Soller 132d91d3aa Fixed page flags for aarch64 2021-01-14 15:54:51 -07:00
Jeremy Soller cb6b44d69e Use devmap offset for physmap on aarch64 2021-01-14 12:35:27 -07:00
Jeremy Soller 1214f3dcdc Add PageFlags to abstract differences between architectures 2021-01-14 10:01:36 -07:00
Jeremy Soller c5774c5529 Add TableKind for future use 2021-01-14 09:16:46 -07:00
Jeremy Soller dafd9cb3c4 Add ENTRY_FLAG_DEFAULT_PAGE and ENTRY_FLAG_DEFAULT_TABLE 2021-01-14 09:16:37 -07:00
Jeremy Soller fad48af985 WIP: aarch64 support 2021-01-13 10:47:35 -07:00
Jeremy Soller 5e10feeaeb Fix whitespace in linker file 2021-01-12 19:59:05 -07:00
Jeremy Soller 6c4c19a95c Move consts to arch 2021-01-12 19:57:42 -07:00
Jeremy Soller ed55b49093 Update aarch64 target to new Rust 2021-01-12 19:57:07 -07:00
Jeremy Soller ea6b1e7f8b Update redox_syscall to 0.2.4 2021-01-11 07:01:05 -07:00
Jeremy Soller 334584b3d5 Use rmm::PhysicalAddress and rmm::VirtualAddress directly 2021-01-09 21:16:11 -07:00
Jeremy Soller ccddabadf7 Make x86 specific dependencies, x86 specific 2021-01-09 20:12:59 -07:00
Jeremy Soller e771e6a4d9 Reduce duplication in context::switch 2020-12-27 20:03:13 -07:00
Jeremy Soller 9033902830 Better messaging about which timer is used 2020-12-23 10:33:09 -07:00
Jeremy Soller 04cc8a2d9c Simplify reserved memory hack 2020-12-23 09:55:03 -07:00
Jeremy Soller 7355ae1671 Hack to ensure kernel is mapped even if it uses reserved memory 2020-12-23 09:46:34 -07:00
Jeremy Soller b1c7b9638d Merge branch 'fix-repr-packed' into 'master'
Fix possible UB by implementing Copy and Clone manually for BuddyEntry.

See merge request redox-os/rmm!1
2020-12-20 16:08:31 +00:00
4lDO2 9a716604fc Implement Copy and Clone manually for BuddyEntry.
This fixes a warning that may in the future become an error, about the
possibility for unaligned references, since the derive macros apparently
rely on creating references to fields. Unaligned references are direct
UB.
2020-12-20 16:36:52 +01:00
Jeremy Soller cff858b455 Merge branch 'rmm' into 'master'
Support for RMM

See merge request redox-os/kernel!155
2020-11-27 16:49:39 +00:00
Jeremy Soller f5ac405db6 Support for RMM 2020-11-27 16:49:39 +00:00
Jeremy Soller cdbeecfffe Remove some warnings 2020-09-14 09:47:29 -06:00
Jeremy Soller 936352a049 FrameCount::new function 2020-09-14 09:47:23 -06:00
Jeremy Soller 8e0df608e2 Add allocator usage information 2020-09-14 09:41:56 -06:00
Jeremy Soller e94d7e7772 Rewrite buddy allocator 2020-09-14 09:41:42 -06:00
Jeremy Soller a775c9e987 Require Arch to implement Clone and Copy 2020-09-14 09:08:28 -06:00
Jeremy Soller a12be1b172 Keep track of last free page 2020-09-09 20:19:28 -06:00
Jeremy Soller f17a1b52bd Test multi-page allocation 2020-09-09 16:02:59 -06:00
Jeremy Soller 0c44dde349 Implement multi-page allocations in buddy allocator (poorly) 2020-09-09 16:02:44 -06:00
Jeremy Soller 711414223b Fix buddy map footer read address 2020-09-09 11:11:39 -06:00
Jeremy Soller fed3110ae8 Better unimplemented messages 2020-09-09 10:55:29 -06:00
Jeremy Soller 811dd09de4 Remove unused function for empty buddy allocator 2020-09-08 20:20:56 -06:00
Jeremy Soller fb88d1669f Add unmap function 2020-09-08 19:59:13 -06:00
Jeremy Soller e6d93d5743 Allow const creation of buddy allocator 2020-09-08 15:51:13 -06:00
Jeremy Soller 5990a04e13 Rename Mapper::active to Mapper:make_current 2020-09-08 15:13:01 -06:00
Jeremy Soller f97a80fecb Flush user table changes 2020-09-08 15:11:26 -06:00
Jeremy Soller e8ea483832 Add page flushing, add support for mapping anonymous pages 2020-09-08 14:56:57 -06:00
Jeremy Soller 6375c175f7 Do not zero tables when not necessary in buddy allocator 2020-09-08 13:52:45 -06:00
Jeremy Soller db7869d995 Add table function for mapper, to get inner page table 2020-09-08 13:52:22 -06:00
Jeremy Soller b4c8ab797d Zero all allocations 2020-09-08 12:41:46 -06:00
Jeremy Soller 8484d4447c Fix compilation using no_std 2020-09-08 11:16:59 -06:00
Jeremy Soller 1b58d2a956 Add FrameCount struct, improve zeroing page performance 2020-09-08 11:13:49 -06:00
Jeremy Soller a64e790471 Fix warnings 2020-09-08 10:54:59 -06:00
Jeremy Soller fcb64422c4 Add FrameAllocator trait, move frame allocator and mapper to library 2020-09-08 10:52:52 -06:00
Jeremy Soller 29945b84b1 no_std building support 2020-09-08 10:24:53 -06:00
Jeremy Soller d153af8b83 Fix calculation of free areas 2020-09-08 10:24:43 -06:00
Jeremy Soller 62da3afef5 Add clearing of freed pages in BuddyAllocator 2020-09-08 09:35:34 -06:00
Jeremy Soller 52a08e70fd Add buddy allocation 2020-09-08 09:27:40 -06:00
Jeremy Soller 57d66236b7 WIP buddy allocator free pages using bitmap 2020-09-07 22:02:52 -06:00
Jeremy Soller 4eb4f579df Set entry when performing allocation 2020-09-07 22:02:24 -06:00
Jeremy Soller 21d7f28fdc Allocate and clear buddy maps 2020-09-07 21:44:23 -06:00
Jeremy Soller d752c5c91e WIP: buddy allocator 2020-09-07 21:05:04 -06:00
Jeremy Soller 011212905d Add WIP slab allocator 2020-09-07 20:01:40 -06:00
Jeremy Soller d450cafad6 Add mapping functionality 2020-09-06 21:07:14 -06:00
Jeremy Soller 03d3264085 Add index_of function to PageTable 2020-09-06 21:06:58 -06:00
Jeremy Soller d9500dc24e Fix excess size of emulated memory, do not print emulated mapping 2020-09-06 21:06:41 -06:00
Jeremy Soller 2dc0853903 Add constants for sizes 2020-09-06 21:06:12 -06:00
Jeremy Soller 4bf43652c3 Only use offset mapping 2020-09-06 14:38:31 -06:00
Jeremy Soller d5111d429e Implement PHYS_OFFSET mapping 2020-09-06 14:30:50 -06:00
Jeremy Soller a40b26293b Do not use explicit register fo x86_64 table operations 2020-09-06 14:20:29 -06:00
Jeremy Soller 379294b59f Implement x86_64 arch functions 2020-09-06 14:18:01 -06:00
Jeremy Soller f801a40908 Add function for addresses 2020-09-06 14:17:49 -06:00
Jeremy Soller 5fc0a080ad Update nightly 2020-09-06 14:17:26 -06:00
Jeremy Soller a482e506c5 Use physical and virtual address abstraction for arch functions 2020-09-06 13:58:40 -06:00
Jeremy Soller ab07997bbe Add derives for physical and virtual addresses 2020-09-06 13:55:38 -06:00
Jeremy Soller 8efc425b07 Add phys_to_virt function 2020-09-06 13:54:58 -06:00
Jeremy Soller 023bb5811a Add definition of physical address size 2020-09-06 13:25:21 -06:00
Jeremy Soller 2df212f48d Add tests to ensure correct constant calculation 2020-09-06 13:00:01 -06:00
Jeremy Soller f5e8c031ca Move constants into Arch trait 2020-09-06 08:30:56 -06:00
Jeremy Soller 8c8e09d23e Refactor, use trait for arch differences 2020-09-05 21:02:27 -06:00
Jeremy Soller 58323aadd0 Implement recursive mapping 2020-09-05 19:00:32 -06:00
Jeremy Soller 556b777386 Define for page levels, enable recursive mapping by default 2020-09-04 21:19:57 -06:00
Jeremy Soller adad6bbe65 Add recursive mapping 2020-09-04 21:07:31 -06:00
Jeremy Soller a55e19868e Add abstraction for page table 2020-09-04 20:56:48 -06:00
Jeremy Soller a70bc00264 Improve machine read/write functions 2020-09-04 15:42:42 -06:00
Jeremy Soller 048298d65b Add README.md 2020-09-04 21:24:43 +00:00
Jeremy Soller 21dc9624d7 Add LICENSE 2020-09-04 21:23:23 +00:00
Jeremy Soller e7ae8e6812 init 2020-09-04 15:22:35 -06:00
Jeremy Soller 8b27de416b Update Cargo.lock 2020-08-27 10:26:56 -06:00
Jeremy Soller afa175f778 Merge branch 'jD91mZM2/kernel-remove-brk' into HEAD 2020-08-27 10:26:29 -06:00
Jeremy Soller 1baeb5a891 Format memory entries using hex 2020-08-27 09:43:39 -06:00
Jeremy Soller 8211e92c02 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/kernel 2020-08-27 09:43:23 -06:00
Jeremy Soller 858dd6ef51 Update syscall 2020-08-27 09:43:15 -06:00
Jeremy Soller 45b48f8078 Merge branch 'fix-deprecate' into 'master'
Fix printing of deprecation warning

See merge request redox-os/kernel!151
2020-08-27 15:33:12 +00:00
Jeremy Soller 853b77e3a4 Unmap owned grants, use owned grants to calculate memory usage 2020-08-25 10:35:55 -06:00
Jeremy Soller 4e3df8b953 Merge branch 'aj-chdir-initfs-message' into 'master'
Add more descriptive error message for when initfs chdir fails

See merge request redox-os/kernel!150
2020-08-17 16:25:46 +00:00
Jeremy Soller 6ba3850042 Merge branch 'aj-logging' into 'master'
Use logging instead of println in src/lib.rs

See merge request redox-os/kernel!149
2020-08-17 16:18:08 +00:00
jD91mZM2 5fc6acacc4 Fix printing of deprecation warning 2020-08-17 15:25:14 +02:00
Aaron Janse dc6132dc06 elaborate error message for initfs chdir failure 2020-08-17 03:24:56 -07:00
Aaron Janse dfcf5be778 use logging instead of println 2020-08-17 02:55:40 -07:00
jD91mZM2 922b3d0437 Remove brk 2020-08-15 17:36:50 +02:00
Jeremy Soller 0590a71b87 Merge branch 'mynameissherlockholmes' into 'master'
Investigate why user heap isn't mapped

See merge request redox-os/kernel!147
2020-08-15 15:27:33 +00:00
jD91mZM2 da7b813fa9 Investigate why user heap isn't mapped
Took me way too long to spot this :D
2020-08-15 17:22:34 +02:00
Jeremy Soller e3814c1ca2 Merge branch 'deprecate-stuff' into 'master'
Deprecate the original fmap/funmap

See merge request redox-os/kernel!146
2020-08-14 15:20:36 +00:00
jD91mZM2 78e5c71103 Deprecate the original fmap/funmap
The cool thing here is that we're temporarily binary compatible with the
old stuff, so if anyone would use an old version of redox_syscall we can
easily find them with these prints.
2020-08-14 15:18:47 +02:00
Jeremy Soller 2057b889ae Merge branch 'log_experiment' into 'master'
Log experiment

See merge request redox-os/kernel!144
2020-08-09 13:01:39 +00:00
Wren Turkal 4c009530a8 Make x86_64 log writer not use println!.
This opens the door to completely elimnating println! usage from the
kernel.

Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-08-09 00:00:26 -07:00
Wren Turkal 5301057324 Convert some println -> log::info!.
Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-08-08 21:18:18 -07:00
Wren Turkal dafd2e9f98 Add a way to customize how logging is done.
Each architecture may have a different method to enable logging. Now
that can be customized with a function passed to the init_logger
function.

Also, provide a minimal x86_64 implementation.

This is the first commit where you can see logging coming from the log
crate.

Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-08-08 21:18:15 -07:00
Wren Turkal 29a9592e7b Re-export log::set_max_level.
Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-08-08 20:50:55 -07:00
Wren Turkal 50675842af Add logger init and initialize on x86_64.
Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-08-08 20:50:53 -07:00
Wren Turkal 03e60f7da6 Add log crate and add a generic logger.
This is the first step of integrating the log crate as the main way to
log messages from the kernel.

Also, reexport all log macros. This module should eventually be the
only logging API used in the kernel.

Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-08-08 20:48:41 -07:00
Jeremy Soller d8a0a8182d Merge branch 'add_debug_to_structs' into 'master'
Implement Debug for a couple structs.

See merge request redox-os/kernel!142
2020-08-08 12:55:53 +00:00
Jeremy Soller ad6035c7de Merge branch 'idiomatic-rust' into 'master'
Replace llvm_asm with asm

See merge request redox-os/kernel!141
2020-08-03 15:09:08 +00:00
jD91mZM2 bdc504f862 Update redox_syscall again 2020-08-03 16:08:15 +02:00
Wren Turkal efb5b47463 Implement Debug for a couple structs.
I am finding it useful to be able to pretty print Mappers and
ActivePageTable structs.

Signed-off-by: Wren Turkal <wt@penguintechs.org>
2020-08-02 22:13:24 -07:00
Jeremy Soller 1a8f47330e Add a message when user heap is not mapped, do not panic 2020-08-02 17:07:57 -06:00
Jeremy Soller ec1809e7c0 Add memory: to null namespace, temporarily 2020-08-02 17:05:17 -06:00
Jeremy Soller 6f3094cb2b Work around unmapping user heap 2020-08-02 16:33:56 -06:00
Jeremy Soller 220e53c24d Show CPU and PID in kernel panic 2020-08-02 12:12:59 -06:00
jD91mZM2 9ab778d649 Update redox_syscall 2020-08-01 16:53:39 +02:00
jD91mZM2 f07603902d Replace all llvm_asm! uses with asm! 2020-08-01 14:56:46 +02:00
Jeremy Soller c8263cc4bd Merge branch 'latest-rust' into 'master'
Support latest rust

See merge request redox-os/kernel!140
2020-08-01 12:22:17 +00:00
jD91mZM2 895c0c11da Use cargo for lto over manually entering rustflags 2020-08-01 13:19:12 +02:00
jD91mZM2 fbeb297949 Fix compilation since last rust
Thanks to @4lDO2 for all this. I just moved his changes to io_uring onto
the master branch of the kernel. I take no credit.
2020-08-01 13:00:52 +02:00
jD91mZM2 93856b43b9 s/\basm!/llvm_asm!/g 2020-08-01 12:31:56 +02:00
Jeremy Soller c8fb3792a9 Merge branch 'memory' into 'master'
Implement funmap2

See merge request redox-os/kernel!139
2020-07-30 13:36:59 +00:00
jD91mZM2 877259257c Update syscall submodule 2020-07-30 15:05:46 +02:00
jD91mZM2 55c3377c5c Use VirtualAddress wrapper in user.rs 2020-07-30 14:21:57 +02:00
jD91mZM2 3fca287bcc Remove debug prints 2020-07-30 13:21:17 +02:00
jD91mZM2 34194e2b79 Implement partial funmap-ing for user schemes 2020-07-30 13:08:03 +02:00
jD91mZM2 0ffa9b0be6 Track region instead of address in user.rs 2020-07-30 11:42:49 +02:00
jD91mZM2 9eb2aebd43 Implement unmapping multiple whole maps 2020-07-28 11:34:50 +02:00
jD91mZM2 639e603c4f WIP: Add funmap2 2020-07-25 22:29:21 +02:00
jD91mZM2 a811774c58 Add necessary functions for funmap2 2020-07-23 16:45:35 +02:00
jD91mZM2 ccc577b3a1 Abstract over finding nice addresses 2020-07-23 11:22:54 +02:00
jD91mZM2 57c167d2fa Make grants be a BTreeSet 2020-07-22 15:09:28 +02:00
Jeremy Soller 2f94031221 Merge branch 'auxv' into 'master'
Implement auxiliary vector

See merge request redox-os/kernel!136
2020-07-21 14:16:05 +00:00
jD91mZM2 9c41424d3a Apply suggestion to src/syscall/process.rs 2020-07-21 14:10:58 +00:00
jD91mZM2 2782a5a7a9 Apply suggestion to src/syscall/process.rs 2020-07-21 14:10:43 +00:00
jD91mZM2 5dc65a920f Add restrictions on fmap 2020-07-21 16:08:28 +02:00
jD91mZM2 cf709783d6 Reverse mod/syscall.rs 2020-07-20 11:17:36 +02:00
jD91mZM2 07baf70c7a Don't push interpreter as argv[0] 2020-07-20 11:09:56 +02:00
Jeremy Soller 854149ee97 Support for debugging to system76 EC 2020-07-19 10:24:15 -06:00
jD91mZM2 ff5354b5b5 Fix mmap when using out-of-place address 2020-07-18 15:03:23 +02:00
jD91mZM2 2d63009ba4 Add debug entry for fmap2 2020-07-18 13:40:12 +02:00
jD91mZM2 310a425c65 Merge branch 'master' into auxv 2020-07-18 12:19:11 +02:00
jD91mZM2 615e516585 Add extra assembler metadata 2020-07-16 17:13:30 +02:00
jD91mZM2 11f26140f5 Fix most MR concerns 2020-07-16 16:59:58 +02:00
jD91mZM2 895a4a5656 Deprecate int 0x80
Mainly because I think the code could be cleaner if we can remove
support entirely :)
2020-07-16 16:33:25 +02:00
jD91mZM2 4fbe86a9ce Fix random userspace page faults
I was an idiot and forgot rbx wasn't always backed up. As a result, we
should never ever write to it
2020-07-16 16:32:48 +02:00
jD91mZM2 acebd1a8d1 Merge remote-tracking branch 'origin/master' into global-asm 2020-07-16 15:35:42 +02:00
jD91mZM2 b00456dbb9 WIP: Continue trying to fix clone_ret 2020-07-16 13:46:53 +02:00
Jeremy Soller c78b69969f Include trampoline in kernel to fix multi_core on EFI 2020-07-15 21:46:15 -06:00
Jeremy Soller 1e44f157d0 Fix graphical_debug feature 2020-07-15 16:10:51 -06:00
jD91mZM2 145c1898be Merge branch 'master' into global-asm 2020-07-15 12:05:34 +02:00
jD91mZM2 3bb234009a WIP: Ensure clone_ret correctness 2020-07-15 11:43:17 +02:00
Jeremy Soller 93303af931 Merge branch 'catch-kernel-signal' into 'master'
Catch kernel signal

See merge request redox-os/kernel!135
2020-07-14 12:53:46 +00:00
Jeremy Soller 6b2302f92e Merge branch 'paging-packed-use-unsafe' into 'master'
Wrap borrows of page table entries in unsafe

See merge request redox-os/kernel!126
2020-07-14 12:53:21 +00:00
jD91mZM2 ca3ddcdeca Add TODOs for mapping PTI properly
I think we need to reimplement these functions in assembly :(
2020-07-14 09:14:16 +02:00
jD91mZM2 701c31cee0 Fix PTI compilation
It's broken on master anyway
2020-07-13 15:49:37 +02:00
jD91mZM2 5927743ff8 fixup! WIP: Rewrite interrupts as global assembly 2020-07-13 15:25:15 +02:00
jD91mZM2 aa3279455d Merge branch 'master' into auxv 2020-07-13 12:48:48 +02:00
jD91mZM2 ec2c42dc66 WIP: Work around fmap quirks 2020-07-13 12:48:29 +02:00
jD91mZM2 fbdfcd2ba0 WIP: Rewrite interrupts as global assembly
Because the way we were using inline assembly was technically incorrect
and breaking the laws of rust

This *finally* compiles. That doesn't mean it works!
2020-07-11 16:15:25 +02:00
jD91mZM2 4b8d2e45c6 Add AT_PHDR 2020-07-10 12:56:08 +02:00
jD91mZM2 3430eadc9a Add auxiliery vector 2020-07-10 12:34:32 +02:00
Jeremy Soller dbfc8ab188 Merge branch 'no_mprotect_crashes' into 'master'
Don't panic on mprotect for unmapped pages

See merge request redox-os/kernel!134
2020-07-09 12:01:33 +00:00
bjorn3 7b76ab3356 Don't panic on mprotect for unmapped pages 2020-07-09 11:03:02 +02:00
4lDO2 01041a5d8a Implement (mostly) fmap2 for memory: 2020-07-08 20:49:16 +02:00
jD91mZM2 56f55a3b97 Always save proccess registers
Not sure if this is going to be required, and I'm not sure if this will
hurt performance, y'know, *always* doing this.
2020-07-08 11:47:12 +02:00
jD91mZM2 103ed1b17f Make interrupt stack readable on kernel signals 2020-07-08 11:44:04 +02:00
Jeremy Soller 92cad589d9 Merge branch 'moar-gdb' into 'master'
Simplify EXEC catching + add signal handling

See merge request redox-os/kernel!132
2020-07-07 12:49:16 +00:00
jD91mZM2 184824234e Update submodule 2020-07-07 14:47:21 +02:00
jD91mZM2 039f7f5c83 Simplify EXEC catching
Instead of having a separate flag, let's reuse STOP_SINGLESTEP :)

I wasn't thinking enough when making this flag!
2020-07-07 14:16:42 +02:00
jD91mZM2 cdcb34486b Keep singlestep across signals 2020-07-07 13:32:10 +02:00
Jeremy Soller 77f3a17c14 Fix warnings in live: 2020-06-30 09:36:19 -06:00
Jeremy Soller d82eb57e9c Update live: to new seek function 2020-06-30 09:08:55 -06:00
Jeremy Soller 7989aa0327 Merge branch 'signed-seek' into 'master'
change seek sig to match posix - signed pos and result

See merge request redox-os/kernel!123
2020-06-27 13:26:53 +00:00
Graham MacDonald af63c9773c Merge remote-tracking branch 'origin/master' into signed-seek 2020-06-27 14:20:51 +01:00
Graham MacDonald 2d8b2d94b9 hopefully update syscall submodule 2020-06-27 14:10:15 +01:00
Jeremy Soller 35ca4c221e Merge branch 'proc-fexec' into 'master'
Changes required for GDB

See merge request redox-os/kernel!131
2020-06-25 13:06:45 +00:00
jD91mZM2 fed36d49e3 Bump submodule 2020-06-25 15:04:49 +02:00
jD91mZM2 4701838118 Fix RIP register on int3 2020-06-23 19:47:44 +02:00
jD91mZM2 7fc49eed74 ptrace: Allow stopping on fexec 2020-06-22 13:11:32 +02:00
Graham MacDonald aa1b11cc8a move calc_seek_offset* to syscall 2020-06-19 23:53:30 +01:00
Graham MacDonald 01f95b644d change seek sig to match posix - signed pos and result 2020-06-19 23:31:55 +01:00
jD91mZM2 e18a877995 Implement proc:<pid>/exe for getting exe name 2020-06-17 19:06:48 +02:00
Jeremy Soller fcea6e06dd Merge branch 'complex-physalloc' into 'master'
More complex physalloc

See merge request redox-os/kernel!127
2020-06-16 21:20:00 +00:00
4lDO2 003bd6a0d2 More complex physalloc 2020-06-16 21:20:00 +00:00
Jeremy Soller 654c0a7bbc Merge branch 'ptrace-sane-block' into 'master'
Ptrace sane block

See merge request redox-os/kernel!129
2020-06-16 12:10:47 +00:00
Jeremy Soller 484f4c13fe Merge branch 'moar-ptrace' into 'master'
Misc ptrace cleanup

See merge request redox-os/kernel!128
2020-06-16 12:09:26 +00:00
jD91mZM2 edcc39929d Fix unused import
I added that assert, because I managed to get an error I couldn't reproduce
2020-06-16 13:58:36 +02:00
jD91mZM2 9c891384ea Fix ptrace returning ENODEV when process exists 2020-06-16 13:42:04 +02:00
jD91mZM2 cbb17327aa ptrace: Block on read, not on write 2020-06-16 13:00:27 +02:00
jD91mZM2 12f632837a Misc proc code cleanup 2020-06-16 10:08:49 +02:00
jD91mZM2 4effb97c04 fixup! Fix acid test-bench issues 2020-06-16 09:28:42 +02:00
jD91mZM2 727217ad42 Fix acid test-bench issues 2020-06-15 17:14:52 +02:00
jD91mZM2 3420339c04 proc scheme: Rewrite try_stop_context 2020-06-15 15:08:59 +02:00
jD91mZM2 75872cc5f8 ptrace: Fix WaitCondition mutex 2020-06-13 16:05:57 +02:00
4lDO2 1c0e6c253f Fix test. 2020-06-11 16:11:46 +02:00
4lDO2 8117119d8e Wrap borrows of page table entries in unsafe.
This is safe because `Entry` is `#[repr(8)]` which is the minimum
alignment for qwords. Since the size of a qword is equal to that
alignment (8), they can also be borrowed from the array.
2020-06-11 16:05:00 +02:00
Jeremy Soller 5d53c65f0b Merge branch 'resolve-kernel-warnings' into 'master'
Fix various kernel warnings.

See merge request redox-os/kernel!125
2020-06-11 13:18:58 +00:00
Jeremy Soller b90233bc30 Merge branch 'paging-repr-packed' into 'master'
Use #[repr(packed)] with correct alignment for paging.

See merge request redox-os/kernel!124
2020-06-11 13:17:51 +00:00
4lDO2 e7d00d4735 Fix various kernel warnings. 2020-06-11 12:58:03 +02:00
4lDO2 c7b207f4dc Use #[repr(packed)] with correct align for paging. 2020-06-11 11:58:58 +02:00
Jeremy Soller 93e0db1aa3 Merge branch 'noacpi-fix' into 'master'
Fix conditional compilation without the acpi feature.

See merge request redox-os/kernel!122
2020-05-22 11:38:16 +00:00
4lDO2 3289b95a7a Fix conditional compilation without acpi feature. 2020-05-22 10:21:22 +02:00
Jeremy Soller 30b109d288 Update dependencies 2020-05-06 09:05:58 -06:00
Jeremy Soller 4245dff4d8 Merge branch 'separate-idt' of gitlab.redox-os.org:4lDO2/kernel 2020-05-06 08:58:10 -06:00
4lDO2 0585c2b4d9 Make the IDTs of APs visible to irq:. 2020-05-03 16:57:32 +02:00
4lDO2 9232736bf1 Rename some things, and fix a map insertion. 2020-05-03 16:57:32 +02:00
4lDO2 f4246deabf WIP: Use a different IDT for each processor. 2020-05-03 16:57:32 +02:00
4lDO2 0d1ca687fb Use the correct interrupt method for spurious IRQs. 2020-05-03 16:57:03 +02:00
4lDO2 1165445602 Add spurious IRQ handling, using a visible counter. 2020-05-03 16:56:50 +02:00
Jeremy Soller dd4e82f4ce Merge branch 'cpuid' into 'master'
bump raw-cpuid dep to avoid pulling in serde

See merge request redox-os/kernel!121
2020-05-02 17:41:05 +00:00
Graham MacDonald 0614d3298d bump raw-cpuid dep to avoid pulling in serde 2020-05-02 14:11:23 +01:00
Jeremy Soller 582e3fd8eb Unlock CONTEXT_SWITCH_LOCK after loading registers but before switch 2020-04-21 21:03:17 -06:00
Jeremy Soller c79f308f07 Unlock CONTEXT_SWITCH_LOCK after switch happens 2020-04-21 20:45:15 -06:00
Jeremy Soller 0bfd830f3c Work around spurious nanosleep wakes 2020-04-20 21:08:56 -06:00
Jeremy Soller dd0633a3d2 Kernel reading of ps2 bytes 2020-04-20 13:10:06 -06:00
Jeremy Soller 2fa85ed303 Remove unused import 2020-04-19 21:47:58 -06:00
Jeremy Soller fa58651b70 Add serio scheme, based on debug scheme, for supporting ps2 devices 2020-04-19 21:40:12 -06:00
Jeremy Soller 5fd8f0430b Cleanup debug scheme 2020-04-19 21:39:53 -06:00
Jeremy Soller 02abd58c10 Merge branch 'multi_core' into 'master'
Multi core

See merge request redox-os/kernel!118
2020-04-19 20:28:15 +00:00
Jeremy Soller e528aa8fdc Fix order of masking IRQ and eoi 2020-04-19 10:50:03 -06:00
Jeremy Soller abf971eaee Only require alignment of 4 bytes for rsdp 2020-04-19 08:49:42 -06:00
Jeremy Soller 315343be41 Add a way to snapshot context state 2020-04-19 08:46:50 -06:00
Jeremy Soller 123918ed43 Track the namespace that a description was opened from 2020-04-19 08:46:50 -06:00
Jeremy Soller 051a275c94 Remove unused import 2020-04-19 08:46:50 -06:00
Jeremy Soller 3c86af57b7 Allow contexts sharing process space to run on different CPUs 2020-04-19 08:46:50 -06:00
Jeremy Soller fdf46d8043 Fix multi_core livelocks and add livelock debugging 2020-04-19 08:46:50 -06:00
Jeremy Soller 9d67e3dc28 Merge branch 'ioapic' into 'master'
Support the I/O APIC alongside the 8259 PIC

See merge request redox-os/kernel!117
2020-04-19 13:02:42 +00:00
4lDO2 9413475119 Don't use the I/O APIC by default,
since this would require pcid to know the _PRT (PCI routing table) to
use and map the interrupt pins to the correct IRQs. xhcid is unaffected
by this though, since it uses MSI-X.

All ACPI handling will be done in userspace before the infrastructure
necessary would make sense (I don't think adding serde to the kernel
would be optimal, and how else would all of the ACPI namespace be
parsed?).
2020-04-19 13:25:43 +02:00
4lDO2 00312bdf32 Revert to old default-features. 2020-04-19 13:21:59 +02:00
4lDO2 3bc4b9a691 Allow the MADT to be read from userspace,
and fix a typo that prevented multiple tables from being listed
correctly.
2020-04-19 09:41:42 +02:00
4lDO2 02ca8edfc5 Execute AML code after IOAPIC init,
which tells the firmware that the I/O APIC is used rather than the 8259
PIC.
2020-04-19 09:41:40 +02:00
4lDO2 8c351e0768 Use the I/O APIC when applicable. 2020-04-19 09:41:09 +02:00
4lDO2 45fe040625 rustfmt. 2020-04-19 09:39:57 +02:00
4lDO2 d1ece2c811 Add a basic acpi: scheme, currently only for MCFG. 2020-04-19 09:39:57 +02:00
4lDO2 dc3452650c Execute AML code after IOAPIC init,
which tells the firmware that the I/O APIC is used rather than the 8259
PIC.
2020-04-18 23:17:37 +02:00
4lDO2 290098b5a4 impl Debug for AmlValue. 2020-04-18 18:21:04 +02:00
4lDO2 5490de9fd2 Fix a page fault. 2020-04-18 17:33:03 +02:00
4lDO2 de4b66150d Remove unnecessary kernel args. 2020-04-18 17:06:45 +02:00
4lDO2 f0b5d51793 Use the I/O APIC when applicable. 2020-04-18 16:36:18 +02:00
4lDO2 da6de394e4 Add a new backwards-compatible v2 boot protocol. 2020-04-18 11:28:11 +02:00
Jeremy Soller 5d4aa75133 Merge branch 'schemes-no-arc-box' into 'master'
Replace Arc<Box<dyn Scheme>> with Arc<dyn Scheme>.

See merge request redox-os/kernel!116
2020-04-11 12:09:20 +00:00
4lDO2 0e2e515dbd Replace Arc<Box<dyn Scheme>> with Arc<dyn Scheme>. 2020-04-11 12:29:35 +02:00
Jeremy Soller 0ccf3b4e53 Merge branch 'lapic' into 'master'
Extend the IRQ scheme to allow allocation of all available interrupt vectors.

See merge request redox-os/kernel!115
2020-04-04 12:54:44 +00:00
4lDO2 0fd24f6061 Cleanup. 2020-04-04 10:57:00 +02:00
4lDO2 b716ec4bc1 Remove currently unused APIC timer code. 2020-03-28 13:37:03 +01:00
4lDO2 d23ed0cfc3 Remove debug local APIC functions. 2020-03-28 13:37:03 +01:00
4lDO2 157a3e5c0d Improve MSI. 2020-03-28 13:37:03 +01:00
4lDO2 772003138d Add a backwards-compatible interface for more IRQs. 2020-03-28 13:37:03 +01:00
4lDO2 c154effd1c Get a working local apic timer. 2020-03-28 13:37:03 +01:00
4lDO2 c11d6d9e46 Update the x86 crate. 2020-03-28 13:37:03 +01:00
4lDO2 65e8abb449 Allow multiple processes to share IRQs.
I haven't been able to receive xhc interrupt anyway.
2020-03-28 13:37:03 +01:00
Jeremy Soller 53570f0164 Merge branch 'fix-warnings' into 'master'
Fix warnings

See merge request redox-os/kernel!114
2020-03-06 20:46:01 +00:00
Skallwar ae14eda866 Run rustfmt 2020-03-06 21:05:26 +01:00
Skallwar b82f596ef6 Fix unnecessary syntax 2020-03-06 21:02:20 +01:00
Skallwar 7671e92216 Fix borrow of packed field 2020-03-06 21:01:18 +01:00
Jeremy Soller b616fdb067 Keep track of ticks each context uses 2020-02-18 21:16:53 -07:00
Jeremy Soller d4d14c78c3 Ensure page table locking at runtime 2020-02-12 20:34:49 -07:00
Jeremy Soller b892603501 Require mutable context to perform page table modifications 2020-02-10 17:58:44 -07:00
Jeremy Soller 7721a0a4c6 Fix assignment of cpu_id 2020-02-09 11:05:02 -07:00
Jeremy Soller d42c1ba14e Remove unused feature 2020-02-09 09:50:48 -07:00
Jeremy Soller 388ab2c87d option -> opt 2020-02-09 09:50:40 -07:00
Jeremy Soller aec92c1617 Make PIT_TICKS thread_local 2020-02-09 09:49:49 -07:00
Jeremy Soller c860322cfc Merge branch 'master' of https://gitlab.redox-os.org/redox-os/kernel 2020-02-07 20:06:39 -07:00
Jeremy Soller 7658193271 Remove some warnings 2020-02-07 20:06:33 -07:00
Jeremy Soller 8eaa809b29 Merge branch 'master' into 'master'
Update README's debugging instructions

See merge request redox-os/kernel!113
2020-01-26 01:12:22 +00:00
Joshua Abraham 4a4d8601d1 Update README's debugging instructions 2020-01-25 20:03:57 -05:00
Jeremy Soller 64f962e02b Merge branch 'master' into 'master'
Fix deadlock in sys: scheme

See merge request redox-os/kernel!112
2020-01-25 23:07:24 +00:00
Joshua Abraham 6a48ae3d8b Fix deadlock in sys: scheme
This patch fixes a deadlock in the sys: scheme that is triggered
when the iostat resource() is called in the same scope where the RwLock
protecting the scheme's handles is write-locked.
2020-01-25 17:39:51 -05:00
Jeremy Soller 57a6359333 Do not add newline to sys:exe 2019-12-22 18:23:36 -07:00
Jeremy Soller 72ea559da4 Do not log mprotects 2019-12-06 19:59:18 -07:00
Jeremy Soller e13107b441 Remove warning 2019-11-13 19:41:34 -07:00
Jeremy Soller f7f4013cf0 Do not use COM3 or COM4 2019-11-13 19:39:45 -07:00
Jeremy Soller 90b113f047 Add lpss_debug 2019-11-13 19:33:21 -07:00
Jeremy Soller 331590e129 Support COM3 and COM4 2019-11-01 20:35:02 -06:00
Jeremy Soller c27a6c149b Support SerialPort<Mmio<u32>> 2019-11-01 20:34:03 -06:00
Jeremy Soller 752138de1d Merge branch 'nanosleep' into 'master'
implement remainder for nanosleep

See merge request redox-os/kernel!110
2019-10-08 19:01:15 +00:00
Timothy DeHerrera f75e1c4802 implement remaninder for nanosleep 2019-10-08 11:54:02 -06:00
Jeremy Soller af93866c41 Add more clippy lints 2019-10-06 11:15:01 -06:00
Jeremy Soller 63e2a835e0 Fix clippy.sh script and fix a number of clippy warnings 2019-10-06 11:04:06 -06:00
Jeremy Soller a57ea6a72b Merge branch 'ptrace-end' into 'master'
Final few ptrace changes

See merge request redox-os/kernel!109
2019-08-21 21:00:13 +00:00
jD91mZM2 ab1a12ad4a Remove deadlock-prone mutex in proc.rs
I believe this could cause a deadlock if a blocking I/O operation was
interrupted by a signal or otherwise, and decided to exit and close
all files. It's unlikely to happen, but it can happen nontheless. This
removes the mutex, but it's difficult to keep the code tidy. Hopefully
this is good enough.
2019-08-15 16:07:38 +02:00
jD91mZM2 cf0a7620df Add ptrace exit breakpoint
This will let you stop at process exit and inspect it right before the
process dies.
2019-08-15 14:23:54 +02:00
jD91mZM2 070f1fa913 Delete ptrace-related TODO 2019-08-15 12:26:29 +02:00
jD91mZM2 2544feb33f Disallow changing CS which contains CPL 2019-08-15 12:26:29 +02:00
Jeremy Soller 6160de495f Make multi_core require acpi 2019-08-12 19:33:50 -06:00
Jeremy Soller 3694395dfb Fix compilation of acpi feature 2019-08-12 19:33:03 -06:00
Jeremy Soller 8c6e1d0541 Update syscall 2019-07-31 18:30:57 -06:00
Jeremy Soller d28b578681 Merge branch 'ptrace-6' into 'master'
Ptrace overhaul & bitflags

See merge request redox-os/kernel!107
2019-07-31 20:29:54 +00:00
jD91mZM2 40449d32b5 Allow catching int3 2019-07-31 16:43:49 +02:00
jD91mZM2 ad5f3814fa Add way to ignore signals 2019-07-30 15:54:25 +02:00
jD91mZM2 62cd298202 Merge ProtFlags with MapFlags 2019-07-30 11:45:54 +02:00
jD91mZM2 a7b2bd22c1 More cleanup... 2019-07-27 15:39:09 +02:00
jD91mZM2 538ca49ee2 Suggestion: Switch to bitflags 2019-07-26 12:23:21 +02:00
jD91mZM2 0e2b0d0fd4 Fix a few details 2019-07-26 10:29:31 +02:00
jD91mZM2 3ac1416dba First step for ptrace overhaul 2019-07-24 21:42:33 +02:00
Jeremy Soller e95cb74d0b Resolve cross-scheme links 2019-07-23 21:06:16 -06:00
Jeremy Soller e570f35279 Update syscall 2019-07-23 20:04:43 -06:00
Jeremy Soller 3533cb3757 Merge branch 'ptrace-5' into 'master'
Drive ptrace into a wall, prepare for overhaul

See merge request redox-os/kernel!106
2019-07-24 02:04:06 +00:00
jD91mZM2 1137692809 WIP(ptrace): Allow setting RIP 2019-07-23 19:55:11 +02:00
jD91mZM2 a7da393cf5 WIP(ptrace): Better support for signals
Signals now cause an event, and there's a way to continue until the
next signal. I can see this being used for detection of `int3`
although I'm not entirely sure as it may prove being too late to stop
abortion of process.
2019-07-21 19:58:32 +02:00
jD91mZM2 7426e48105 WIP(ptrace): Extract repeated arch-specific code to ptrace module 2019-07-21 13:28:31 +02:00
jD91mZM2 4c2d8599d8 Add missing debug definitions
See [strace-redox#ea42589d](https://gitlab.redox-os.org/redox-os/strace-redox/commit/ea42589d36923e9c018a4d802a5cd0c3449d0e6c)
2019-07-21 10:06:28 +02:00
jD91mZM2 6a3825d408 WIP(ptrace): Only use non-signal stack when using a default handler
This is a curious problem and it's really hard to solve it in a way
that doesn't feel hacky. On one hand, of course you want to be able to
modify and intercept what happens when you use a signal, right? On the
other hand, changes made to the context (especially singlestepping)
while a signal is handled (such as `SIGSTOP`) are not preserved since
the stack is restored after the signal handler was invoked.

I think what we have in this change makes sense anyway, as we don't
really want users modifying registers and other data in the default
signal behavior that occurs **in kernel mode**. Also trying to use
`PTRACE_SINGLESTEP` will set the singlestep flag only if in a
user-mode signal handler, else it will set it on the instruction after
the signal handling, which I guess makes sense since it can't affect
the kernel-mode code that runs the default handler.

I don't know. Help. Pls.
2019-07-20 22:45:33 +02:00
jD91mZM2 8695ecd82b Fix sigaction Undefind Behavior
Rust does not allow a `fn`-pointer to be null. This fixes that, while
luckily doing it in a way that leaves system calls
backwards-compatible :)
2019-07-20 22:41:54 +02:00
jD91mZM2 be867ae5f1 WIP(ptrace): Add ptrace event system for catching child forks 2019-07-20 09:45:07 +02:00
jD91mZM2 3d44242407 WIP(ptrace): Finally add stronger security checks 2019-07-20 09:45:07 +02:00
jD91mZM2 e3d8f23c71 WIP(ptrace): Add dbg! macro and fix waitpid immediately after exit 2019-07-20 09:45:01 +02:00
Jeremy Soller 532ffe25cf Unmounting support 2019-07-18 21:00:36 -06:00
Jeremy Soller 113af69434 Remove scheme if closed 2019-07-18 20:58:06 -06:00
Jeremy Soller 4b2c15f0b9 Remove scheme by ID 2019-07-18 20:57:51 -06:00
Jeremy Soller 5af7f71a99 Fix warning 2019-07-18 20:57:41 -06:00
Jeremy Soller 5a42b6dd76 Add notify_signal method to WaitCondition to simulate being woken by a signal 2019-07-18 19:48:54 -06:00
Jeremy Soller 76e0ed2e37 Make all wait_map members public 2019-07-18 19:48:27 -06:00
Jeremy Soller bfc559a8a7 Merge branch 'master' of https://gitlab.redox-os.org/redox-os/kernel 2019-07-14 11:17:52 -06:00
Jeremy Soller 6e8729bac2 Disable RTC NMI and do not wait for an entire update cycle before reading time 2019-07-14 11:17:45 -06:00
Jeremy Soller cbc892d1d5 Merge branch 'ptrace-3' into 'master'
Ptrace memory reading and floating point registers support

See merge request redox-os/kernel!104
2019-07-07 17:07:05 +00:00
jD91mZM2 6fbb4fbae1 Ptrace memory reading and floating point registers support 2019-07-07 17:07:04 +00:00
Jeremy Soller 788526a3b3 Bare-bones ptracing functionality
Since even a very basic ptrace can be nice to have, I thought I would split
the, perhaps rather big, ptrace project up in multiple PRs to make as few
changes as necessary in each. This PR contains the initial registry modifying
bits and only a very basic security measure. Letting this out to the community
should be good for spotting bugs and maybe getting some hype ;)
2019-07-02 07:38:26 -06:00
Jeremy Soller 45ea634798 Revert "Merge branch 'ptrace' into 'master'"
This reverts merge request !103
2019-07-02 11:56:11 +00:00
Jeremy Soller 527353d377 Merge branch 'ptrace' into 'master'
Bare-bones ptracing functionality

See merge request redox-os/kernel!103
2019-07-01 22:50:19 +00:00
jD91mZM2 effe02bd45 Remove change I am faaairly certain I did NOT add :O
I'm guessing it's some issue after a rebase or something...
2019-07-01 22:50:19 +00:00
Jeremy Soller 42f977e7da Disable debug messages 2019-06-27 16:29:28 -06:00
Jeremy Soller 144ac70b12 Allow access to other thread's TLS with pointers 2019-06-23 20:21:22 -06:00
Jeremy Soller 78e79fc4d6 Merge branch '2018' into 'master'
Switch to 2018 edition

See merge request redox-os/kernel!102
2019-06-21 12:19:38 +00:00
jD91mZM2 fe705d9b63 Switch to 2018 edition
Most of this was generated by the absolutely extraordinary `cargo fix`
subcommand. There were still 2 errors and a few warnings to patch up,
but compared to the normal 600+ errors, I'd say the fixer did a damn
good job! I'm also amazed that I could still start the VM after this,
I half expected some kinds of runtime failure...
2019-06-21 12:12:01 +02:00
Jeremy Soller 1be77c2ab4 Store sigmask 2019-06-02 18:45:06 -06:00
Jeremy Soller fcd8ce7e1b Fix event logic for pipes 2019-04-28 13:32:24 -06:00
Jeremy Soller afa3f38310 Allow seek in root scheme directory listings 2019-04-27 08:13:20 -06:00
Jeremy Soller afab96fa06 Do not allow unreachable patterns (often a logic issue) 2019-04-27 08:10:49 -06:00
Jeremy Soller eecc9a442c Fix missing name override option when calling fexec_kernel 2019-04-15 21:01:19 -06:00
Jeremy Soller 126009f83c Keep process name when using interpreter 2019-04-15 21:00:42 -06:00
Jeremy Soller b66fef0479 Copy TCB if it was not initialized using kernel-allocated TLS 2019-04-15 20:47:27 -06:00
Jeremy Soller 6da3ab283e Clone grants 2019-04-15 20:47:03 -06:00
Jeremy Soller dc198cef6e Keep track of leaked grants and allow for cloning of grants 2019-04-15 20:42:41 -06:00
Jeremy Soller d432f7ce8c Add debugging for mprotect 2019-04-14 21:32:31 -06:00
Jeremy Soller 3a0671d20f Fix dropping grants without unmapping if they have no file descriptor (such as those from anonymous maps) 2019-04-14 19:23:23 -06:00
Jeremy Soller 339d68ac8d Remove debugging messages 2019-04-14 19:12:13 -06:00
Jeremy Soller 434e799f2a Place TCB at thread-specific location to avoid overlapping TCBs 2019-04-14 19:05:25 -06:00
Jeremy Soller 21e46b6a55 More cleanup of TLS mapping 2019-04-14 14:50:29 -06:00
Jeremy Soller 9762431a33 Cleanup TLS mapping 2019-04-13 22:00:27 -06:00
Jeremy Soller 8120131897 Add interpreter capability 2019-04-13 21:59:46 -06:00
Jeremy Soller dc28023be1 Remove unnecessary clone 2019-04-13 21:58:34 -06:00
Jeremy Soller 28cd51efed Update goblin 2019-04-13 21:57:58 -06:00
Jeremy Soller 58f9e5a801 0.1.54 - Add support for cache disable 2019-04-08 17:57:25 -06:00
Jeremy Soller f042bd5d07 Update for new rust 2019-04-07 10:57:33 -06:00
Jeremy Soller ff2ad4322a Update syscall 2019-04-07 10:51:51 -06:00
Jeremy Soller f36506613b Update funmap support 2019-04-06 20:13:55 -06:00
Jeremy Soller 4329aa4366 Update syscall 2019-04-06 18:58:34 -06:00
Jeremy Soller c8104a70b9 Merge branch 'prevent-race-condition' into 'master'
Lock resources before checking if we need to clean them.

See merge request redox-os/kernel!101
2019-04-01 15:38:00 +00:00
Noam Kleinburd 129d4e3ae5 Lock resources before checking if we need to clean them.
See the comments deleted by this commit for more details as to how
the race condition could effect the system.
2019-04-01 17:01:29 +03:00
Jeremy Soller e5cf6efa64 Support specification of stack with clone system call and CLONE_STACK flag 2019-03-31 14:35:45 -06:00
Jeremy Soller 9ccaed7103 Remove bochs breakpoint in kernel 2019-03-31 08:36:55 -06:00
Jeremy Soller ec66bf2ed1 Rerun build script if INITFS_FOLDER changes 2019-03-24 11:35:54 -06:00
Jeremy Soller d2095d8d0f Add in-memory logging, retrievable from sys:log 2019-03-17 09:31:34 -06:00
Jeremy Soller f7c9712977 Fix warning in irq scheme 2019-03-17 09:31:03 -06:00
Jeremy Soller e2a6233c12 New fevent functionality to prevent missing events 2019-03-13 13:57:07 -06:00
Jeremy Soller 483ee05ebc Fix unused import 2019-03-12 20:48:28 -06:00
Jeremy Soller a0e9f4a8a0 Use serial for debugging by default 2019-03-11 19:54:54 -06:00
Jeremy Soller b80f38b039 More debugging output options 2019-03-11 19:50:50 -06:00
Jeremy Soller 445b8ad96d Merge branch 'rustc-demangle' into 'master'
Use rustc-demangle in the stack traces

See merge request redox-os/kernel!100
2019-02-22 02:35:13 +00:00
Tibor Nagy 2ec775905a Use rustc-demangle in the stack traces 2019-02-14 15:54:17 +01:00
Jeremy Soller 6042cdb0a2 Remove unused import 2019-02-02 14:04:53 -07:00
Jeremy Soller b4575711c7 Fix logic error when cloning file descriptor in user scheme fmap 2019-02-02 08:11:07 -07:00
Jeremy Soller ca511b98f3 Add code to shut down QEMU with it's default ACPI settings, run cli hlt in loop 2019-02-01 20:12:06 -07:00
Jeremy Soller 504e93d11b Store file descriptor for mapped files until they are unmapped 2019-01-28 19:27:20 -07:00
Jeremy Soller 78d07d41cb FileDescriptor is now must_use 2019-01-28 19:26:50 -07:00
Jeremy Soller 613e5b45f7 Update dependencies 2019-01-20 19:47:50 -07:00
Jeremy Soller f6e2d44383 Add syscall setup to kstart_ap 2019-01-20 19:41:18 -07:00
Jeremy Soller 5c31c0991c 0.1.51 2019-01-20 19:37:55 -07:00
Jeremy Soller 36820c0346 Add somewhat magical code for syscall instruction 2019-01-20 19:35:52 -07:00
Jeremy Soller 931a7bb251 WIP: Support for syscall instruction 2019-01-20 15:49:18 -07:00
Jeremy Soller 30f1265c36 Add pages to use for head and tail of buffers in userscheme 2019-01-01 12:37:23 -07:00
Jeremy Soller 257e4a6eb5 WIP: improve speed of Grant::map_inactive
Use recursive page table address to calculate p4 entry
2019-01-01 12:28:45 -07:00
Jeremy Soller 8fcbf152eb Add mprotect 2018-12-31 21:04:21 -07:00
Jeremy Soller b18e322c3f WIP: itimer and sigprocmask 2018-12-28 21:53:40 -07:00
Jeremy Soller 0df93423a2 Add no_execute to heap now that mmap prot_exec is working 2018-12-28 19:57:51 -07:00
Jeremy Soller a31af81f8b Update fmap support 2018-12-28 15:35:21 -07:00
Jeremy Soller ef919f3d52 Implement EINTR for anything using wait_queue 2018-12-22 08:02:00 -07:00
Jeremy Soller 46a6325678 Update lock file 2018-12-14 20:08:21 -07:00
Jeremy Soller 69cbb548fb Mark heap executable for mesa (temporary) 2018-12-11 21:03:57 -07:00
Jeremy Soller 876e01e539 Update syscall 2018-12-11 21:03:40 -07:00
Jeremy Soller ecc0e747fc Prevent adding empty variables to environment 2018-12-02 19:25:28 -07:00
Jeremy Soller e356262f03 Correct init path 2018-12-02 19:14:13 -07:00
Jeremy Soller 69e3fe105d Update debugging to ignore clock_gettime 2018-12-02 16:31:24 -07:00
Jeremy Soller fe74ecee95 Update lock file 2018-12-01 09:28:14 -07:00
Jeremy Soller f443126dff Update syscall 2018-11-26 11:45:39 -07:00
Jeremy Soller 9af4d6a2e0 Fix compilation of graphical_debug feature and remove live feature warnings. 2018-11-21 19:38:14 -07:00
Jeremy Soller ee5c43ed45 Add umask to debug 2018-11-16 21:22:38 -07:00
Jeremy Soller 7e2a7d0cea Update lock file 2018-11-16 20:08:08 -07:00
Jeremy Soller efff2cb797 Update syscall to 0.1.42 2018-11-16 19:48:50 -07:00
Jeremy Soller 14c15d3bbb Update syscall 2018-11-16 19:45:13 -07:00
Jeremy Soller 4c38107055 Add umask 2018-11-16 19:43:37 -07:00
Jeremy Soller 885fe7d0ae update syscall 2018-11-12 20:55:49 -07:00
Jeremy Soller 5b31bf57be Update to latest rust 2018-11-08 17:25:57 -07:00
Jeremy Soller 120b4733ff Update for new rust 2018-11-08 17:11:06 -07:00
Jeremy Soller 1b091d3c9f Set name of process using full path of executable 2018-10-26 10:31:47 -06:00
Jeremy Soller 15313f98af Remove unnecessary dup implementations 2018-10-20 08:08:31 -06:00
Jeremy Soller 9570de21d1 Merge remote-tracking branch 'origin/relibc' 2018-10-14 16:43:54 -06:00
Jeremy Soller 3b1bf1bac1 Call TLB IPI when mapping grants 2018-09-25 20:58:24 -06:00
Jeremy Soller b08fa10277 Implement tlb IPI 2018-09-25 20:57:59 -06:00
Jeremy Soller f5fcbc12b8 Move ipi for pit to after EOI 2018-09-25 18:05:10 -06:00
Jeremy Soller e867326df1 Attempt to schedule other processors more often by waking them up with a context switch when a process is created 2018-09-25 18:01:38 -06:00
Jeremy Soller 0d510a4f74 Remove multi-core and acpi again 2018-09-23 11:44:34 -06:00
Jeremy Soller 7a97867868 Make multi-core support the default
Make IPIs less architecture specific
2018-09-23 10:40:55 -06:00
Jeremy Soller 22aa5f48d7 Merge branch 'master' into 'master'
Implement fmap for memory:

See merge request redox-os/kernel!93
2018-09-22 15:51:18 +00:00
Jeremy Soller a2ce83f60a Merge branch 'trace' into 'master'
trace: Break on RBP OVERFLOW

See merge request redox-os/kernel!96
2018-08-17 12:10:20 +00:00
Jeremy Soller 2ba21b33ad Merge branch 'relibc' into 'relibc'
Push null after argv

See merge request redox-os/kernel!97
2018-08-13 11:47:24 +00:00
jD91mZM2 1d817fa41d Push null after argv 2018-08-13 12:14:29 +02:00
Jeremy Soller 1718d28d39 Push null pointer to indicate end of environment 2018-08-12 08:30:12 -06:00
Jeremy Soller 69766ce3b9 Update syscall 2018-08-11 16:47:48 -06:00
Jeremy Soller 23f4c76ebb Fixes for launching init 2018-08-11 11:51:58 -06:00
Jeremy Soller 30e68f917e Remove env scheme and env field on context, fix all warnings 2018-08-11 11:34:32 -06:00
Jeremy Soller fe90664e33 Copy variables to USER_ARG_OFFSET 2018-08-11 11:18:45 -06:00
Jeremy Soller c7b3765d6f Remove execve, replace with fexec 2018-08-11 11:14:32 -06:00
Jeremy Soller a198cb22f5 Merge remote-tracking branch 'origin/master' into relibc 2018-08-11 09:03:35 -06:00
Ian Douglas Scott 8455d2bad4 trace: Break on RBP OVERFLOW
There's not point in continuing the loop once this occurs. It just
results in printing 'RBP OVERFLOW' repeatedly.
2018-08-08 12:35:04 -07:00
Jeremy Soller 875d89cef8 Merge branch 'master' into 'master'
Add more documentation to the redox kernel

See merge request redox-os/kernel!95
2018-07-30 12:28:11 +00:00
17liamnaddell 2de83eb932 fix small documentation bug 2018-07-21 21:46:11 -04:00
17liamnaddell 2c2a96a935 futex and slight changes 2018-07-21 21:41:47 -04:00
17liamnaddell c06f403dd2 second round of documentation 2018-07-21 20:48:33 -04:00
17liamnaddell 9d1fb3013d First round of documentation changes 2018-07-18 22:48:08 -04:00
jD91mZM2 55f2303d2c Implement fmap for memory: 2018-07-05 14:17:58 +02:00
Jeremy Soller b86672b81e Support for relibc 2018-07-03 19:42:23 -06:00
Jeremy Soller 054fc41beb Merge commit 'c28c147' 2018-06-19 18:18:36 -06:00
Jeremy Soller c28c147add Update to new dependencies 2018-06-19 18:17:16 -06:00
Jeremy Soller 9a7f04723b Merge branch 'fix-linked-list-allocator' into 'master'
Use older linked_list_allocator version

See merge request redox-os/kernel!92
2018-06-15 18:52:06 +00:00
Deepak Sirone 231cab75fe Use older linked_list_allocator verison 2018-06-15 23:46:07 +05:30
Jeremy Soller 3f08676e21 Merge branch 'fix-graphical-debug' into 'master'
Fix compilation error for graphical_debug

See merge request redox-os/kernel!91
2018-06-15 16:54:24 +00:00
Deepak Sirone ccbd858043 Fix compilation error for graphical_debug 2018-06-15 22:08:02 +05:30
Jeremy Soller 145785e206 Update links to gitlab 2018-06-12 12:30:44 -06:00
Jeremy Soller fc0db71dd4 Update syscall 2018-05-30 09:43:22 -06:00
Jeremy Soller 897b583360 Update lock file 2018-05-30 09:19:19 -06:00
Jeremy Soller 41bdb31645 Update syscall 2018-05-30 09:19:06 -06:00
Jeremy Soller 92ebd4d16a Merge branch 'master' of https://github.com/redox-os/kernel 2018-05-24 08:31:59 -06:00
Jeremy Soller 764f28ada5 Update cargo.lock 2018-05-24 08:31:52 -06:00
Jeremy Soller 3f2bd559bf Merge pull request #90 from jabedude/master
Fix TODO: Use triple fault to guarantee reboot
2018-05-22 06:33:20 -06:00
Josh Abraham aff0c339b4 Fix TODO: Use triple fault to guarantee reboot
Cause interrupt, since the IDT is dorked we can't find the INT 3
handler (double fault), and the double fault handler can't be
found (triple fault).
2018-05-21 17:14:58 -10:00
Jeremy Soller 5cfe3f822b Update syscall 2018-05-20 16:26:45 -06:00
Jeremy Soller 94c6550580 Reduce messages from fevent warning 2018-05-20 16:25:11 -06:00
Jeremy Soller 7d0f9a7ce8 Require correct event id return 2018-05-20 13:18:51 -06:00
Jeremy Soller 43a163d8d6 Debug scheme will return correct event id 2018-05-20 12:56:37 -06:00
Jeremy Soller 4ec46ee786 Send new flags to scheme 2018-05-20 12:48:22 -06:00
Jeremy Soller cb94d334ac Fix issue with debug fevent 2018-05-20 12:33:54 -06:00
Jeremy Soller 99a3bff2da WIP: New event system 2018-05-20 11:08:37 -06:00
Jeremy Soller 63351f4ca6 Fix documentation in pipe scheme 2018-05-20 07:18:13 -06:00
Jeremy Soller e01d397dc1 Return ECHILD if child process does not exist before blocking on it 2018-05-14 20:34:47 -06:00
Jeremy Soller d0b78cd8ff Remove stop print 2018-05-14 20:03:48 -06:00
Jeremy Soller be1e87922c Set rust_oom no_mangle 2018-04-28 22:08:23 -06:00
Jeremy Soller 48007b8f1e Update to new allocation API (WIP) 2018-04-28 22:07:43 -06:00
Jeremy Soller 36989e21f2 Merge branch 'master' of https://github.com/redox-os/kernel 2018-04-28 21:45:23 -06:00
Jeremy Soller c5752242d0 Update linked_list_allocator 2018-04-28 21:45:19 -06:00
Jeremy Soller a64522e580 Merge pull request #88 from raw-bin/aarch64
Add a toolchain target spec for AArch64
2018-04-16 06:39:10 -06:00
Robin Randhawa 19d4868e6c Add a toolchain target spec for AArch64 2018-04-16 15:36:59 +05:30
Jeremy Soller 9dc42102bf Merge pull request #87 from raw-bin/aarch64-redox-port-outline-doc
Add an outline document for a port of the Redox kernel to the Arm AAr…
2018-04-15 17:57:10 -06:00
Robin Randhawa 9a0f8391a6 Update status: Toolchain spec done
Also fix a typo with the device_crate URL.
2018-04-16 02:53:59 +05:30
Robin Randhawa 09a7eaea4b Add an outline document for a port of the Redox kernel to the Arm AArch64 architecture. 2018-04-14 14:10:51 +05:30
Jeremy Soller 9ddda9bbfb Ensure GDT and IDT state is sane before attempting to set up paging 2018-04-11 21:06:13 -06:00
Jeremy Soller f83f61b51a Enable graphical debug 2018-03-20 20:33:49 -06:00
Jeremy Soller d9ee3e05cc Merge pull request #86 from ids1024/sig0
kill: support signal number 0
2018-03-19 10:50:41 -06:00
Ian Douglas Scott 3b09c8f858 kill: support signal number 0
Tests process existence, but does not send a signal. Matches POSIX
behavior.
2018-03-18 21:52:48 -07:00
Jeremy Soller 6dfed91ac3 Fix index check for accessfield 2018-03-11 12:58:43 -06:00
Jeremy Soller 402266e3e4 Check length on more objects 2018-03-11 12:56:48 -06:00
Jeremy Soller 74e673e68d Return errors if data is too small when parsing acpi objects 2018-03-11 12:52:30 -06:00
Jeremy Soller 734622fb9a Fix mapping code for physbaseptr 2018-03-11 12:16:51 -06:00
Jeremy Soller 9c7c010cc0 Fix graphical debug sync error, add unmapping, map with write combine 2018-03-11 12:12:54 -06:00
Jeremy Soller 819f77daf3 Add support for graphical debug, to be used during ACPI phase 2018-03-11 11:36:58 -06:00
Jeremy Soller 133c433f60 Fix warning in context::switch 2018-03-11 11:35:41 -06:00
Jeremy Soller c020ce7d8a Fix delivery of signals when a signal uses the default handler, make context status update on every switch 2018-02-24 17:47:46 -07:00
Jeremy Soller 3af2964955 Add ACPI feature 2018-02-18 16:24:34 -07:00
Jeremy Soller 797d86b7a7 Remove debug message 2018-01-29 21:36:17 -07:00
Jeremy Soller 761fe30bf3 Add linked list allocator with automatic resizing
Fix memory leaks in exec
Remove warnings
2018-01-29 21:29:24 -07:00
Jeremy Soller 015b79430e Updates for new nightly 2018-01-28 14:59:01 -07:00
Jeremy Soller 50bbdd3f5e Update lock file 2018-01-28 14:45:52 -07:00
Jeremy Soller fdaf3c2fbc Merge pull request #76 from weclaw1/master
Use slab allocator for kernel heap
2018-01-28 14:16:23 -07:00
Jeremy Soller 86ef2c4eb3 Merge pull request #83 from biotty/memword
Operate on word size as possible
2018-01-25 06:57:54 -07:00
Christian Øien c2e972f21a Operate on word size as possible 2018-01-24 22:15:30 -06:00
Jeremy Soller f3205e6e34 Fix #81 by limiting arguments to 4095
Fix #79 by limiting mappable sections to the 2GB mark
2018-01-21 20:46:53 -07:00
Jeremy Soller dcb49be481 Fix potential overflows in validate_slice and validate_slice_mut, require memory to be userspace 2018-01-21 19:21:43 -07:00
Jeremy Soller 89df5e5343 Remove debugging print 2018-01-19 20:26:41 -07:00
Jeremy Soller fee95a0406 Disable PTI by default 2018-01-19 20:07:18 -07:00
Jeremy Soller dd0376ed69 Merge branch 'pti' 2018-01-19 20:06:59 -07:00
Robert Węcławski 3e06a37215 Use slab allocator for kernel heap 2018-01-17 23:31:27 +01:00
Jeremy Soller 1e17bfdd53 Merge pull request #75 from dlrobertson/master
Update debugging docs
2018-01-10 19:49:40 -07:00
Jeremy Soller 98fb50a086 Remove comment from linker file 2018-01-10 19:27:05 -07:00
Jeremy Soller 1e533b3ad5 Use fninit in start 2018-01-10 19:26:33 -07:00
Jeremy Soller 5b389c7ffa Update PTI patch to inline PTI functions 2018-01-10 17:25:31 -07:00
Dan Robertson a16b9230a8 Update debugging docs 2018-01-10 21:31:28 +00:00
Jeremy Soller d82ffd16cb WIP: Add per-cpu interrupt stack used before mapping kernel heap 2018-01-09 22:16:14 -07:00
Jeremy Soller 192a8ce793 Add rbx to saved registers in syscall stack 2018-01-09 21:46:48 -07:00
Jeremy Soller a6550341bb Add trampolines for PTI support 2018-01-08 22:31:50 -07:00
Jeremy Soller 670d7b00d3 Add PML4 constants 2018-01-08 20:32:27 -07:00
Jeremy Soller 32028f66fe Merge pull request #74 from wartman4404/master
Write hpet timer twice
2018-01-07 19:46:08 -07:00
wartman4404 4f90a0f5c1 Write hpet timer 0 twice to set accumulator and period
This allows booting with implementations that require them to be set separately.
Also, check for the availability of legacy-replacement mode and periodic interrupts before using hpet
2018-01-07 17:06:07 -06:00
Jeremy Soller 083c444a68 Implement waitpid on PGID 2018-01-05 20:31:15 -07:00
Jeremy Soller 9313909fe9 Fix stop signal by switching context after stopping 2018-01-04 09:03:41 -07:00
Jeremy Soller 49d5c33928 Add support for WCONTINUED and WUNTRACED
Fix issues with SIGCONT
2018-01-03 22:34:50 -07:00
Jeremy Soller b6878760c7 Use seperate stopped status 2018-01-03 21:33:56 -07:00
Jeremy Soller c912f42800 Fix TLS when forking, fix signal delivery to self 2018-01-03 21:33:24 -07:00
Jeremy Soller 7906f6891e Add support for stop/cont signals 2018-01-02 22:05:29 -07:00
Jeremy Soller 22aca69ac9 Use TLS alignment to fix https://github.com/redox-os/redox/issues/1124 2017-12-29 14:58:04 -07:00
Jeremy Soller caa607eb28 Merge pull request #70 from redox-os/clippy
Add clippy lints, action some clippy items
2017-12-27 21:32:23 -07:00
Jeremy Soller 059cc8078d Add frename 2017-12-27 20:19:37 -07:00
Jeremy Soller 58e1d92eb5 Add clippy lints, action some clippy items 2017-12-24 22:19:00 -07:00
Jeremy Soller e08f56a2de Merge pull request #69 from NilSet/check_namespace
Check if current namespace exists
2017-12-24 07:28:35 -07:00
Tommie Levy 04e1034088 Check if current namespace exists 2017-12-24 02:36:11 -05:00
Jeremy Soller 7bfe1739fd Merge pull request #67 from Arcterus/master
Move null and zero from kernel space to user space
2017-12-18 16:25:11 -07:00
Alex Lyon 66a5379ff6 Move null and zero from kernel space to user space 2017-12-18 14:33:06 -08:00
Jeremy Soller a9fa08fd72 Merge pull request #66 from weclaw1/page_table_optimization
Page table optimization
2017-12-17 19:19:15 -07:00
Robert Węcławski 3c466892de change assert to debug_assert 2017-12-17 20:29:35 +01:00
Robert Węcławski a8ecfc86dd Better comment and mask representation 2017-12-17 19:54:52 +01:00
Robert Węcławski 08a4c33b77 New entries are set to zero 2017-12-17 19:46:19 +01:00
Robert Węcławski 2d041bbb51 don't change counter in set_unused 2017-12-17 18:45:41 +01:00
Robert Węcławski 82bae0b314 entry::set doesn't reset counter, counter mask is a const 2017-12-17 18:22:27 +01:00
Robert Węcławski ab687852d3 Convert entry count to u64, remove unnecessary parentheses 2017-12-17 17:19:06 +01:00
Robert Węcławski a48ec82f20 Use unused bits 52-61 in first entry of each page table as counter for number of page table entries 2017-12-17 16:53:20 +01:00
Jeremy Soller c2644adf3d Improve multi_core support 2017-12-05 21:26:45 -07:00
Jeremy Soller cd54352f47 Merge branch 'master' of https://github.com/redox-os/kernel 2017-12-05 20:24:43 -07:00
Jeremy Soller dd7c61b830 Allow other processors to pick up work 2017-12-05 20:24:03 -07:00
Jeremy Soller 8ad13539dc Merge pull request #65 from dlrobertson/master
Add documentation on using gdb
2017-12-04 20:29:08 -07:00
Dan Robertson 2e6949e66d Add documentation on using gdb 2017-12-05 01:25:54 +00:00
Jeremy Soller 9b327ccba8 Update Cargo.lock 2017-12-03 08:53:47 -07:00
Jeremy Soller 45e8effa8a Merge pull request #64 from dlrobertson/master
Do not discard .debug section
2017-12-02 19:27:45 -07:00
Dan Robertson 025ec0def2 Do not discard .debug section
Do not discard the .debug section. If the builder would like to discard
this section, they can do so explicitly with objcopy.
2017-12-02 19:38:16 +00:00
Jeremy Soller 578c57840a 0.1.32 2017-11-28 21:48:28 -07:00
Jeremy Soller 789e290c9b Add fchown, fchmod 2017-11-28 21:48:10 -07:00
Jeremy Soller ed05564011 Remove SwitchResult, use out of band data to detect interruption
Update debugging code
2017-11-14 21:16:35 -07:00
Jeremy Soller da954096e0 Merge pull request #62 from xTibor/fix-nightly
Fix for the latest nightly
2017-11-14 20:28:03 -07:00
Jeremy Soller 9368b2ba4c Merge pull request #63 from pzmarzly/patch-1
elf.rs: do not inline constant from goblin library
2017-11-13 12:38:26 -07:00
Paweł Zmarzły 20f262c4ed elf.rs: do not inline constant from goblin library
SELFMAG is declared [here](https://github.com/m4b/goblin/blob/de8aecc8f1e7f3de7d66a1511d3976cdf0335e0c/src/elf/header.rs#L91).
2017-11-13 20:24:50 +01:00
Tibor Nagy eadade4c0f Fix for the latest nightly 2017-11-10 21:42:28 +01:00
Jeremy Soller 9e9f80ef13 Add futex timeout 2017-11-06 22:04:42 -07:00
Jeremy Soller 2de7bd7f79 Merge pull request #61 from sajattack/patch-1
add a LOC badge
2017-11-05 06:29:35 -07:00
Paul b5dac25d55 add a LOC badge 2017-11-05 00:30:20 -07:00
Jeremy Soller 1e553b744c Fix errors from waitpid 2017-10-29 16:02:54 -06:00
Jeremy Soller eebf12bec5 Fix returning too many errors from waitpid 2017-10-29 15:41:59 -06:00
Jeremy Soller 1f99d038c4 Make debug function never return error 2017-10-29 15:31:35 -06:00
Jeremy Soller ffad0f2ace Merge pull request #59 from xTibor/libcollections
Migrate from collections
2017-10-27 21:39:51 -06:00
Tibor Nagy e6b9f850d1 Migrate from collections 2017-10-28 02:42:08 +02:00
Jeremy Soller 8ec5d4726b Hack to allow rustc to wait on non-child process.
Add sys:syscall for seeing active system calls
2017-10-22 21:13:29 -06:00
Jeremy Soller ef70cd257c Uncomment AML value variant 2017-10-22 19:41:31 -06:00
Jeremy Soller 58c6ef0ecf Merge branch 'master' of https://github.com/redox-os/kernel 2017-10-21 20:30:26 -06:00
Jeremy Soller 51339cb8c9 Cleanup warnings
Implement interrupt on signal in pipe:
2017-10-21 20:30:20 -06:00
Jeremy Soller 62e0713d9b Merge pull request #58 from GabrielMajeri/update-bitflags
Update to `bitflags` version 1.0
2017-10-11 07:44:49 -06:00
Gabriel Majeri 305e7980d8 Update to bitflags 1.0 2017-10-11 15:59:14 +03:00
Jeremy Soller 31d742e6be Merge pull request #57 from redox-os/cap
Capability mode support using null namespace
2017-10-09 20:24:22 -06:00
Jeremy Soller e07c3ac0b9 Set init namespace to 1 2017-10-09 20:20:38 -06:00
Jeremy Soller 244069cf43 Implement a capability namespace with no available schemes 2017-10-09 20:12:08 -06:00
Jeremy Soller b023a715f9 Merge pull request #56 from jaje/externs
Deduplicate memcpy, memmove, memset and memcmp functions
2017-10-05 08:54:07 -06:00
Jan Jedelský 05dc9140a4 Update comment in externs.rs 2017-10-05 14:27:01 +02:00
Jan Jedelský 528ffa985a Deduplicate memcpy, memmove, memset and memcmp functions 2017-10-05 14:19:25 +02:00
Jeremy Soller c417f0cf00 Add target-c-int-width to x86_64 target 2017-10-04 18:25:59 -06:00
Jeremy Soller 808447cbfb Move location of live disk 2017-10-01 14:24:21 -06:00
Jeremy Soller 0794926493 Pass env to first function 2017-09-30 18:09:48 -06:00
Jeremy Soller 41ee250eea Reformat kernel arguments 2017-09-30 16:12:37 -06:00
Jeremy Soller ce87b7fc6c Allow listing of root scheme 2017-09-30 14:52:57 -06:00
Jeremy Soller 49ef95a156 Downgrade goblin 2017-09-26 20:04:48 -06:00
Jeremy Soller aa3c1515a0 Update README.md 2017-09-26 14:35:05 -06:00
Jeremy Soller 01a881243b hybrid -> micro 2017-09-26 14:15:01 -06:00
Jeremy Soller fcf8120eec Update features for latest nightly 2017-09-26 14:12:30 -06:00
Jeremy Soller bdff0dd004 Fix documentation 2017-09-26 13:57:16 -06:00
Jeremy Soller 9a9f5d17cb Update dependencies 2017-09-26 13:29:21 -06:00
Jeremy Soller 37c9250a52 Fix output of build script 2017-09-26 13:17:15 -06:00
Jeremy Soller 23e30c14a8 Create LICENSE 2017-09-26 12:57:43 -06:00
Jeremy Soller 735802366f Update README.md 2017-09-26 12:57:04 -06:00
Jeremy Soller 55ed5f81c3 Update README.md 2017-09-26 12:55:34 -06:00
Jeremy Soller 1fa963be45 Merge pull request #54 from L3nn0x/patch-1
Correct small bug in memcpy 32bits implementation
2017-09-20 07:52:41 -06:00
L3nn0x eebba9291a Update externs.rs
I'm not entirely sure about it, but the rest of the file treats 32 bits as groups of 4 so it makes sense that memcpy does the same.
2017-09-20 09:49:40 +01:00
Jeremy Soller d6b9768dc3 More efficient live filesystem method
Reduce kernel heap to 64 MB
Fix issue in build.rs
2017-09-19 20:21:04 -06:00
Jeremy Soller 1f81866afa Update dependencies 2017-09-19 19:28:43 -06:00
Jeremy Soller 5248ce70db Merge pull request #52 from ids1024/spin-override
Add temporary override for spin-rs
2017-09-19 17:22:11 -06:00
Ian Douglas Scott fee3561282 Add temporary override for spin-rs 2017-09-19 16:17:48 -07:00
Jeremy Soller bec9610947 Change unreachable to enosys 2017-09-17 16:49:34 -06:00
Jeremy Soller 5839641b41 Update debugging code 2017-09-17 09:40:29 -06:00
Jeremy Soller 18a911578c Merge pull request #51 from ids1024/debug_syscall
Add commented out system call debug printing code
2017-09-16 21:34:41 -06:00
Ian Douglas Scott 29a2b9fbcd Add commented out system call debug printing code 2017-09-16 20:25:54 -07:00
Jeremy Soller 6e8de21b7c Implement events on pipe
Add syscall name debugging
Update debugging code
2017-09-16 12:04:20 -06:00
Jeremy Soller 917d30c193 Fix the mapping of TLS - it will now be page aligned 2017-09-13 22:16:02 -06:00
Jeremy Soller a5f3e5057b Remove warnings
Improve error information
Cleanup interrupt macros
2017-09-13 21:32:08 -06:00
Jeremy Soller cf45bd34e1 Merge pull request #48 from CWood1/master
Fully implemented AML parser, some amendments to ACPI infrastructure
2017-08-31 17:53:16 -06:00
Connor Wood f0bc8cca23 Merge 2017-08-31 13:28:24 +01:00
Connor Wood 7145e2390c Converted DDB handle to integer and vice versa 2017-08-31 11:25:08 +01:00
Connor Wood 1cce42b691 Moved DDB handles over to using signature scheme 2017-08-31 11:07:01 +01:00
Connor Wood 1bcd8530d2 Stored signature to include OEM signature and OEM table ID 2017-08-31 10:52:59 +01:00
Connor Wood 5592484d07 Eliminated dead code 2017-08-30 19:09:08 +01:00
Connor Wood c3d07e4caa Refactored ACPI initialisation code to be better conducive to DDB Handle stuff 2017-08-30 19:03:39 +01:00
Connor Wood 9f55367906 Implemented notification API 2017-08-29 17:29:07 +01:00
Connor Wood d23241d800 Implemented copy 2017-08-29 12:25:41 +01:00
Connor Wood d75dfd3c20 Implemented externam 2017-08-29 12:02:03 +01:00
Connor Wood 71c5301448 Implemented concat 2017-08-29 11:32:48 +01:00
Connor Wood 60edb9da68 Implemented type checking and coersion upon store 2017-08-29 10:11:01 +01:00
Connor Wood b78f7139b9 Completed Get method 2017-08-29 09:38:36 +01:00
Jeremy Soller d487e1d23f Make syscall a submodule 2017-08-27 10:54:11 -06:00
Jeremy Soller 9fcaf30513 Fix PIT 2017-08-21 20:27:13 -06:00
Connor Wood d5d156a3d2 Implemented buffer field index modify 2017-08-19 15:10:47 +01:00
Jeremy Soller 81a931629f Merge pull request #47 from ids1024/exec
Support arguments in #!
2017-08-16 14:08:31 -06:00
Ian Douglas Scott f60d9fc969 Support arguments in #! 2017-08-16 12:30:20 -07:00
Connor Wood aa35967f72 Made index modification recursion resolve 2017-08-13 19:02:25 +02:00
Connor Wood f0a185741a Implemented recursive index modifications 2017-08-13 16:13:57 +02:00
Connor Wood 328a89c224 Completed context modify, aside from BufferFields and nested Indexes 2017-08-10 14:28:30 +02:00
Jeremy Soller 5c5e5da7c2 Update syscall crate 2017-08-09 21:06:00 -06:00
Jeremy Soller b43f1503b7 Merge pull request #46 from ids1024/dupfd
Implement F_DUPFD
2017-08-08 14:58:49 -06:00
Ian Douglas Scott 1623baa137 Implement F_DUPFD in fcntl 2017-08-08 10:59:11 -07:00
Ian Douglas Scott 9e2d39b5b8 Move duplication in dup() and dup2() to new function 2017-08-07 21:57:25 -07:00
Jeremy Soller 64d7d24174 Merge pull request #45 from ids1024/filelock
Prevent freezing due to double locking
2017-08-06 13:39:50 -06:00
Ian Douglas Scott ade6e0d421 Prevent freezing due to double locking 2017-08-06 12:08:50 -07:00
Jeremy Soller d8d78ffbef Update Cargo.lock 2017-08-02 19:06:59 -06:00
Jeremy Soller 8932daf04a Merge pull request #44 from ids1024/fifo
Use fifo flag for pipe
2017-08-02 12:41:48 -06:00
Ian Douglas Scott 2eab3ea6b0 Use fifo flag for pipe 2017-08-02 11:13:44 -07:00
Jeremy Soller b364d052f2 Merge pull request #43 from cookie545445/machdep
Move x86_64-specific code to arch/x86_64
2017-07-30 20:52:21 -06:00
Tommy Hudson 0e1d664bf0 Rearrange serial I/O code and make 16550 driver generic over T: Io 2017-07-30 20:54:36 +01:00
Tommy Hudson 621b657f87 Move x86_64-specific code to arch/x86_64 2017-07-30 15:46:34 +01:00
Connor Wood 94f27a1a9c Merge branch 'aml-namespace' of github.com:cwood1/kernel into aml-namespace 2017-07-30 13:38:50 +03:00
Connor Wood 41ce7fdf1f Implemented much of ctx::modify and ctx::get 2017-07-30 11:23:32 +03:00
Jeremy Soller 21d033a1a8 Update syscall 2017-07-29 08:17:28 -06:00
Connor Wood 6122b21997 Moved event signal/wait code into context 2017-07-29 12:57:53 +03:00
Connor Wood ab98746879 Moved lock manipulation into context 2017-07-29 12:39:08 +03:00
Jeremy Soller 2e66912ce1 Merge pull request #42 from ids1024/description
Use file descriptions, shared between file descriptors
2017-07-28 17:41:55 -06:00
Ian Douglas Scott 374213f155 F_GETFD and F_SETFD 2017-07-28 15:06:50 -07:00
Ian Douglas Scott 6b504a9493 Remove unused imports 2017-07-28 14:26:15 -07:00
Ian Douglas Scott 3756fb5606 Use file description alongside file descriptior, matching posix 2017-07-28 13:59:31 -07:00
Jeremy Soller 2261452492 Update to new nightly API 2017-07-26 20:58:40 -06:00
Jeremy Soller b474136af4 Add cargo.lock 2017-07-26 07:44:24 -06:00
Connor Wood f25df99a41 Implemented derefof 2017-07-25 14:48:07 +01:00
Connor Wood ada5ba6dbc Implemented condrefof 2017-07-25 13:12:42 +01:00
Connor Wood afc93f82a9 Implemented RefOf 2017-07-25 13:06:10 +01:00
Connor Wood 968fd30b0a Fixed object references 2017-07-25 11:51:43 +01:00
Connor Wood 8a5ec3a26b Implemented SizeOf 2017-07-25 11:37:49 +01:00
Connor Wood 0652bc8099 Implemented ToBuffer 2017-07-25 11:29:32 +01:00
Connor Wood 6df99953dc Implemented defBuffer 2017-07-25 11:25:29 +01:00
Connor Wood 1cd124a852 Fixed bank name issue 2017-07-25 10:36:56 +01:00
Connor Wood a115d21495 Converted all types to string 2017-07-24 19:02:09 +01:00
Connor Wood a5382534e6 Converted to integer fully 2017-07-24 18:53:21 +01:00
Connor Wood d7229d7132 Completed simple type conversions 2017-07-24 17:50:41 +01:00
Connor Wood fdcacd7d18 Implemented numerous "simple" type conversions 2017-07-24 17:27:01 +01:00
Connor Wood e7edaceec0 All conversions to BufferField, dependent on the conversion to Buffer 2017-07-24 16:15:18 +01:00
Connor Wood 9408e71dcd Converted BufferField into Buffer 2017-07-24 16:02:19 +01:00
Connor Wood 82762863df Converted string to buffer 2017-07-24 09:56:54 +01:00
Connor Wood c6ecf105ad Converted Integer to Buffer 2017-07-24 09:48:27 +01:00
Connor Wood a70b26555e Error handling in namespace path assembly 2017-07-24 09:21:53 +01:00
Connor Wood 59b176c24e Implemented path parent character "^" when calculating scope paths 2017-07-24 09:09:07 +01:00
Jeremy Soller a3b0c8ebff Merge pull request #40 from ids1024/components
Strip extra slashes from path
2017-07-23 20:23:40 -06:00
Ian Douglas Scott 1367c7814f Strip extra slashes from path
Fixes strange behavior like 'cd .//////; pwd'
2017-07-23 18:09:49 -07:00
Jeremy Soller ef8c120533 Prevent nested signals, fix check for PID > 0 2017-07-23 16:02:48 -06:00
Jeremy Soller 07262fd866 Implement sending signals to process groups. Modify max context value to fit inside of isize 2017-07-23 15:55:47 -06:00
Jeremy Soller d6848a1995 Add PGID 2017-07-23 14:47:41 -06:00
Connor Wood c79eb0eeab Implemented table API in full 2017-07-23 13:42:30 +01:00
Connor Wood 4288182106 Implemented Load 2017-07-23 10:34:50 +01:00
Jeremy Soller 6a061665e4 Use EINVAL instead of ENOENT 2017-07-22 13:21:15 -06:00
Jeremy Soller fc914e0cae Make it an error to supply a dup buffer to schemes that do not handle it 2017-07-22 12:54:28 -06:00
Connor Wood 82e814469c Shutdown on fatal error 2017-07-22 13:52:48 +01:00
Connor Wood 3c2b3b3f5e Fixed a bunch of warnings 2017-07-22 13:32:02 +01:00
Connor Wood 76316aa8d6 Implemented toHexString 2017-07-22 13:10:45 +01:00
Connor Wood 5873e553e9 Implemented toDecimalString 2017-07-22 12:56:53 +01:00
Connor Wood 797262df5c Several conversion operators 2017-07-22 12:48:23 +01:00
Connor Wood 79b6afd608 Implemented to integer 2017-07-22 12:12:31 +01:00
Connor Wood f8e433c4e7 Implemented sleep 2017-07-22 11:13:30 +01:00
Connor Wood ff23827155 Implemented stall 2017-07-22 11:02:53 +01:00
Connor Wood b7d9ad60bb Implemented Event synchronisation objects 2017-07-22 10:55:09 +01:00
Connor Wood b0b8a7e85d Handled mutexes 2017-07-22 10:06:20 +01:00
Connor Wood 8e98cdf971 Processed acquire mutex 2017-07-22 09:57:44 +01:00
Connor Wood 8412339ae9 Every context has an ID 2017-07-22 09:10:37 +01:00
Connor Wood 1938ca0435 Memory handler API 2017-07-21 14:11:29 +01:00
Connor Wood 0365b6f2b7 Created a function to control the global S state 2017-07-21 12:51:30 +01:00
Connor Wood 5c05b48921 GenericAddressStructure now handles reads and writes itself 2017-07-21 12:42:11 +01:00
Connor Wood 2256e0288b Removed spurious file 2017-07-21 12:04:36 +01:00
Connor Wood a14266fc82 Parallelized ACPI subsystem 2017-07-21 12:03:55 +01:00
Jeremy Soller 4ae6ed9d4c Pass syscall data to syscall, implement iopl 2017-07-19 14:51:12 -06:00
Jeremy Soller f7b961ddff Reduce scope of contexts lock 2017-07-18 22:02:22 -06:00
Jeremy Soller b4d502c763 Add reset code 2017-07-18 20:55:00 -06:00
Jeremy Soller 76aa3116d7 Merge pull request #39 from ids1024/uname
sys:uname
2017-07-18 18:48:35 -06:00
Ian Douglas Scott 2ab539d2e4 sys:uname 2017-07-18 15:42:42 -07:00
Connor Wood dba65f3128 Remove all namespace changes made within methods 2017-07-18 10:16:26 +01:00
Jeremy Soller c7664674d3 Update fs.rs 2017-07-17 21:25:20 -06:00
Connor Wood 258cab878c Implemented index references 2017-07-17 13:22:06 +01:00
Connor Wood c01a04148b Implemented method return values 2017-07-17 12:20:04 +01:00
Connor Wood d315914f29 Implmented method execution and method invocations 2017-07-17 11:54:19 +01:00
Connor Wood d38b1d7aa9 Implemented loop control 2017-07-17 11:26:33 +01:00
Connor Wood af80bfa258 Timer now returns monotonic counter 2017-07-15 10:51:59 +01:00
Connor Wood fe681d57a1 Implemented opcodes 2017-07-15 10:14:53 +01:00
Connor Wood eeea65f5c1 Implemented match 2017-07-15 10:14:53 +01:00
Connor Wood e0bd497bb8 Implemented further opcodes in full, added get to context 2017-07-15 10:14:53 +01:00
Connor Wood 38263bf700 Fixed number of bugs 2017-07-15 10:14:53 +01:00
Connor Wood 2a6bbeb584 Added object modification 2017-07-15 10:14:53 +01:00
Connor Wood 7527915027 Added a context manager 2017-07-15 10:14:53 +01:00
Connor Wood 6c74a02382 Refactored parser to execute in the parse step for efficiency and simplicity 2017-07-15 10:14:52 +01:00
Connor Wood f131cc6f1f Rolled parsing and execution steps into one for namespace modifiers 2017-07-15 10:14:52 +01:00
Connor Wood 5213d59237 Namespaces can now be concatenated, handling of SSDTs is now performed 2017-07-15 10:14:52 +01:00
Connor Wood 21c9d824cc Finalized ACPIType 2017-07-15 10:14:52 +01:00
Connor Wood a79e275cc0 Moved AccessType into namespace 2017-07-15 10:14:52 +01:00
Connor Wood 82124a59d5 Moved ConnectFieldBufferData to the namespace 2017-07-15 10:14:52 +01:00
Connor Wood 1babfb4b32 Moved ConnectFieldNameString into namespace 2017-07-15 10:14:52 +01:00
Connor Wood ee012a482b Moved DataRegion into namespace - more infrastructure required 2017-07-15 10:14:52 +01:00
Connor Wood 94b8bd19d6 Moved indexfield to namespace 2017-07-15 10:14:51 +01:00
Connor Wood 7911853951 Moved arbitrary length buffer field into namespace 2017-07-15 10:14:51 +01:00
Connor Wood f287638996 Moved BufferFields into namespace 2017-07-15 10:14:51 +01:00
Connor Wood 9ae9e3b190 Moved BankField to the namespace 2017-07-15 10:14:51 +01:00
Connor Wood 61776f7af8 Removed temporary files 2017-07-15 10:14:51 +01:00
Connor Wood 94b0e7de37 Moved Event to namespace 2017-07-15 10:14:51 +01:00
Connor Wood 9575c6fed3 Moved Mutex to namespace 2017-07-15 10:14:51 +01:00
Connor Wood e52d4c98a3 Moved PowerResource into namespace 2017-07-15 10:14:51 +01:00
Connor Wood b4ddaeadbb Moved Processor to namespace, and refactored namespace layout to use BTreeMap 2017-07-15 10:14:50 +01:00
Connor Wood 73562b3f56 Moved ComputationalData::String into namespace 2017-07-15 10:14:01 +01:00
Connor Wood c58aa38247 Moved DefDevice and DefThermalZone to namespace 2017-07-15 10:14:01 +01:00
Connor Wood 07cf7385e9 Moved Alias to the namespace 2017-07-15 10:14:01 +01:00
Jeremy Soller 1085fa3838 Merge pull request #38 from ids1024/espipe
Make seek on pipe return ESPIPE
2017-07-14 17:15:31 -06:00
Ian Douglas Scott 89f695dd28 Make seek on pipe return ESPIPE 2017-07-14 15:58:24 -07:00
Jeremy Soller ff9f2322a6 Merge pull request #37 from ids1024/cloexec
Make dup/dup2 clear cloexec
2017-07-14 12:56:28 -06:00
Ian Douglas Scott 09a4980442 Make dup/dup2 clear cloexec 2017-07-14 08:48:42 -07:00
Jeremy Soller 30385fec48 Merge pull request #36 from CWood1/hpet
HPET Driver
2017-07-14 08:32:52 -06:00
Connor Wood 0b6bde7c68 Moved PIT driver into kernel 2017-07-14 15:26:04 +01:00
Connor Wood 0bd6f11a4f Implemented HPET driver 2017-07-14 13:58:06 +01:00
Connor Wood 0cbdb2d0c0 Saved HPET table for global access 2017-07-14 10:39:50 +01:00
Connor Wood 387cd41e5e Implemented ACPI table 2017-07-14 10:36:27 +01:00
Jeremy Soller 56ba795845 Merge pull request #34 from ids1024/dup2
Make dup2() work if second file descriptor doesn't exist
2017-07-13 15:55:16 -06:00
Ian Douglas Scott 6f081f4bbd Make dup2() work if second file descriptor doesn't exist 2017-07-13 14:43:55 -07:00
Jeremy Soller 2c0cc3a8a1 Merge pull request #33 from ids1024/path
Pass relative, not canonicalized, path to script
2017-07-13 09:49:59 -06:00
Ian Douglas Scott f020fe2ac5 Pass relative, not canonicalized, path to script 2017-07-13 08:09:36 -07:00
Jeremy Soller 6981f0cd36 Merge pull request #32 from ids1024/process
Strip whitspaces after #!
2017-07-13 07:11:39 -06:00
Ian Douglas Scott b5da98396e Strip whitspaces after #!
Autotools configure scripts seem to use "#! /bin/sh"
2017-07-12 23:03:53 -07:00
Jeremy Soller 687f991ab4 Merge pull request #31 from ids1024/fstat
Implement fstat() for pipe scheme
2017-07-12 07:05:46 -06:00
Ian Douglas Scott f81a276536 Implement fstat() for pipe scheme 2017-07-11 21:26:35 -07:00
Jeremy Soller a03457a9eb Simpler debug message 2017-07-10 20:33:29 -06:00
Jeremy Soller a3493d16fd Allow simple signal delivery to PID 1 (the kernel idle process) 2017-07-10 20:28:10 -06:00
Jeremy Soller 268ba3ece7 Remove syscall replacement 2017-07-10 20:13:01 -06:00
Jeremy Soller a0b06a2835 Merge branch 'master' of https://github.com/redox-os/kernel 2017-07-10 20:09:01 -06:00
Jeremy Soller ab738cede5 Restore kernel parameters on sigreturn 2017-07-10 20:08:57 -06:00
Jeremy Soller 8f6268eef7 Merge pull request #30 from ids1024/pipe
Revert "pipe: make read() return when write end is closed"
2017-07-10 17:10:16 -06:00
Ian Douglas Scott 79a45a2580 Revert "pipe: make read() return when write end is closed"
This reverts commit 09a67641c6.
2017-07-10 11:15:45 -07:00
Jeremy Soller b5ff0aabd5 WIP: Signal handling 2017-07-09 21:34:38 -06:00
Jeremy Soller 7e52541f39 Implement passthrough of futimens 2017-07-09 15:43:26 -06:00
Jeremy Soller 3f40af0687 Update to new allocator API 2017-07-08 19:50:58 -06:00
Jeremy Soller 22e87d94d4 Merge pull request #29 from ids1024/pipe
pipe: make read() return when write end is closed
2017-07-08 06:56:36 -06:00
Connor Wood fa24650ca7 Implemented opcodes 2017-07-08 10:20:33 +01:00
Ian Douglas Scott 09a67641c6 pipe: make read() return when write end is closed 2017-07-07 21:05:38 -07:00
Connor Wood 59936e25e6 Implemented match 2017-07-07 11:39:08 +01:00
Connor Wood 00591235e1 Implemented further opcodes in full, added get to context 2017-07-07 10:37:09 +01:00
Jeremy Soller ae5a32cf98 Merge pull request #28 from ids1024/dup
Pass empty second argument to dup in exec
2017-07-06 18:29:07 -06:00
Ian Douglas Scott 074ce2e57d Pass empty second argument to dup in exec 2017-07-06 16:44:54 -07:00
Jeremy Soller d0c3a5d2aa Merge pull request #27 from ids1024/clone
Pass empty second argument to dup() call in clone
2017-07-06 05:54:59 -06:00
Ian Douglas Scott b2df8d676f Pass empty second argument to dup() call in clone
I don't know if this was there for a reason, but it was making the dup()
fail with tcpd, and I don't seem this being handled specially in redoxfs
or anywhere else.
2017-07-05 22:45:27 -07:00
Jeremy Soller d4e295a385 Revert syscall path 2017-07-05 21:46:40 -06:00
Jeremy Soller 0e8e1b5c4e WIP: Signal handling 2017-07-05 21:45:53 -06:00
Connor Wood 980065d4d6 Fixed number of bugs 2017-07-05 14:36:40 +01:00
Connor Wood def456a8e5 Added object modification 2017-07-03 11:11:07 +01:00
Connor Wood 50ac9d3abe Added a context manager 2017-07-03 10:31:01 +01:00
Connor Wood 590610f4a5 Refactored parser to execute in the parse step for efficiency and simplicity 2017-07-02 13:07:43 +01:00
Jeremy Soller a4c3afb446 Merge pull request #26 from ids1024/getppid
Implement getppid system call
2017-06-29 06:34:49 -06:00
Ian Douglas Scott dddd87c2c3 Implement getppid system call 2017-06-28 22:05:01 -07:00
Jeremy Soller 12d487ec9c Merge pull request #19 from bjorn3/fix_warnings
Fix most lint warnings, check multicore code even if disabled
2017-06-26 06:52:50 -06:00
bjorn3 2dcd563709 Merge branch 'master' into fix_warnings 2017-06-26 14:22:17 +02:00
Connor Wood f72f97ef36 Rolled parsing and execution steps into one for namespace modifiers 2017-06-23 14:02:40 +01:00
Connor Wood 9fb15e7e92 Namespaces can now be concatenated, handling of SSDTs is now performed 2017-06-22 19:12:40 +01:00
Connor Wood be1a75e472 Finalized ACPIType 2017-06-22 16:25:19 +01:00
Connor Wood c83cefee08 Moved AccessType into namespace 2017-06-22 15:43:00 +01:00
Connor Wood fb0e5137e8 Moved ConnectFieldBufferData to the namespace 2017-06-22 15:22:19 +01:00
Connor Wood c8eca653b8 Moved ConnectFieldNameString into namespace 2017-06-22 15:09:04 +01:00
Connor Wood 0a67ad4b23 Moved DataRegion into namespace - more infrastructure required 2017-06-22 13:34:05 +01:00
Connor Wood 443c1ac1f8 Moved indexfield to namespace 2017-06-22 12:45:58 +01:00
Connor Wood 94e391c9b6 Moved arbitrary length buffer field into namespace 2017-06-22 12:23:14 +01:00
Connor Wood cef562c832 Moved BufferFields into namespace 2017-06-22 12:16:30 +01:00
Connor Wood 12e7d1ad4d Moved BankField to the namespace 2017-06-22 12:02:17 +01:00
Connor Wood 2e64cea81f Removed temporary files 2017-06-21 20:54:29 +01:00
Connor Wood 312aff03c4 Moved Event to namespace 2017-06-21 20:50:08 +01:00
Connor Wood 19ccb3612b Moved Mutex to namespace 2017-06-21 20:27:46 +01:00
Connor Wood fceba822eb Moved PowerResource into namespace 2017-06-21 20:13:44 +01:00
Connor Wood 636d94fd20 Moved Processor to namespace, and refactored namespace layout to use BTreeMap 2017-06-21 20:02:05 +01:00
Jeremy Soller 0478e5f7fb Merge pull request #25 from ids1024/env
Make env: return ENOENT on non-existent; support unlink()
2017-06-20 17:06:13 -06:00
Ian Douglas Scott b9f659dadf Make env: return ENOENT on non-existent; support unlink() 2017-06-20 15:56:44 -07:00
Connor Wood 7095219316 Moved ComputationalData::String into namespace 2017-06-19 14:12:26 +01:00
Connor Wood 3ed94405aa Moved DefDevice and DefThermalZone to namespace 2017-06-19 13:49:37 +01:00
Connor Wood 190686a853 Moved Alias to the namespace 2017-06-19 13:33:20 +01:00
Jeremy Soller cd67aabd5a Switch collections::boxed for alloc::boxed 2017-06-18 20:05:19 -06:00
Jeremy Soller bbcd5197a4 Aml parser (#24)
* Initial parser proof of concept

* Added better error handling to the parser

* Refactored into a better directory structure

* Parse package length

* Implemented named string, scope op

* Properly bounds checked namestring

* Fixed namestring regressions

* Started work parsing DefRegionOp. NB: As TermArg is not yet implemented, a bug is present parsing the address offset and length. Additionally, a bug was fixed in NameString

* Completed DefOpRegion implementation. TermArg remains unimplemented, stubbed out

* Implemented TermArg parsing

* Implemented integer parts of computational data

* Implemented defField, and associated FieldList. FieldElement still remains stubbed

* Implmenented FieldElement

* Implmenented named field

* Parsed DefMethod

* Parsed ToHexString

* Parsed ToBuffer

* Parsed both subtract and sizeof

* Fixed size bug in sizeof parsing

* Parsed Store, fixed a parse bug where Target should be a SuperName not a TermArg

* Parsed while

* Parsed LLess

* Parsed DerefOf

* Parse Index

* Parse increment

* Parse device

* Parse device

* Parsed create dword field

* Parsed if/else block

* Properly parsed Target, rendered an AST from existing parse code, and stubbed out MethodInvocation parser method

* Implemented deferred loading, and deferred method invocation parses

* Parsed Or

* Fixed a bunch of off-by-one errors. Shows what I get for copying code around

* Parsed Return

* Fixed a boolean logic error in the handling of the extended instruction namespace

* Added DefBuffer to ComputationalData

* Removed a temporary file

* Parsed ReservedField

* Parsed DefPackage, DefAnd, and ComputationalData::String

* Parsed DefMutex

* Parsed DefAlias and RevisionOp

* Parsed DebugObj

* Parsed DefRefOf

* Parsed type 6 opcodes

* Added ObjectReference and DDBHandle to DataRefObj parsing

* Parsed DefVarPackage, in both Type2OpCode, and in DataObj

* Parsed DefBankField

* Parsed AccessField

* Parsed ConnectField

* Parsed CreateBitField

* Parsed CreateByteField

* Parsed CreateWordField

* Parsed CreateQWordField

* Parsed CreateField

* Parsed DefDataRegion

* Parsed DefEvent

* Parsed IndexField

* Parsed DefPowerRes

* Parsed DefProcessor

* Parsed DefThermalZone:

* Parsed ExtendedAccessField

* Parsed DefBreak, DefBreakPoint, DefContinue and DefNoop (all type 1 opcodes with no parameters and one byte)

* Parsed DefFatal

* Parsed DefLoad

* Parsed DefNotify

* Parsed DefRelease

* Parsed DefReset

* Parsed DefSignal

* Parsed DefSleep

* Parsed DefStall

* Parsed DefUnload

* Parsed DefAcquire

* Parsed DefAnd

* Parsed DefConcat

* Parsed ConcatRes

* Switched Concat and ConcatRes opcodes

* Parsed CondRefOf

* Parsed DefDecrement and DefCopyObject

* Parsed DefDivide, fixed length calculation bug in a bunch of parse routines

* Parsed DefFindSetLeftBit

* Parsed DefFindSetRightBit

* Parsed DefFromBCD

* Parsed DefLAnd

* Parsed DefLGreater

* Parsed LNot

* Parsed DefLOr

* Parsed DefLoadTable

* Parsed DefMatch

* Parsed DefMid

* Parsed DefMod

* Parsed DefMultiply

* Parsed DefNAnd

* Parsed DefNOr

* Parsed DefNot

* Parsed DefObjectType

* Parsed DefShiftLeft and DefShiftRight

* Parsed DefTimer

* Parsed DefToBCD, DefToDecimalString, DefToInteger and DefToString

* Parsed DefXor

* Parsed DefWait

* Implemented a parser, abstract syntax tree, and basic infrastructure for the AML subsystem of the ACPI module. The entire AML grammar is parsed and placed into an abstract syntax tree, with one exception: method invocations, rather than parsing, defer the load until later on in the process, due to the way the grammar works.

Still to be done:
 - Refactor the code: a lot of the parser is very repetitive, and could easily be refactored with the aid of macros. This would reduce the length and improve legibility, though not affect function.
 - More rigorous testing of parser: the parser has, thus far, only been tested on the DSDT in QEMU. There may be bugs present that are hidden.
 - Parse the SSDTs: the SSDTs should be parsed after the DSDT, and contain more AML bytecode to be treated as modifying the same namespace. Adding this would be simple, though not urgent.
 - Transform the AST into a concrete executable tree: the CET is what will hold all information necessary to execute control methods and evaluate namespace objects. While this could be done in the AST, due to the way AML is laid out this would be very inefficient and require a lot of repetitive transformations every time something is to be executed. Therefore, perform the transformations upfront.
 - Parse the deferred loads, and the method invocations contained within: Once the AST has been rendered into a CET, sufficient information will be present to parse method invocations and add those to the namespace.
 - Bytecode interpreter: Once the CET has been finalized with method invocation parsing, it can then be called and executed.
 - Control method executor: this should walk the namespace, locating the relevant control method, then calling the interpreter on it.
 - Namespace enumerator: the executor shall use this to walk the namespace, and it should also be publicly accessible to allow outside code to determine what devices are present in the system.
 - Memory accessor API: ACPI AML has a concept of memory access in certain device domains - for example, the PCI BAR registers. These are all device specific offsets, therefore device drivers, or more accurately bus drivers, should be capable of installing handlers to manage this memory access.
 - CET concatenation: The DSDT and SSDTs all affect the same namespace, therefore concatenating the resulting trees should be possible.
 - Type checking: some operations in AML are typed. This should be handled at tree transformation time or earlier, and could indeed done in the parse step with some modification to the parser. This is currently not the case.

* Initial parser proof of concept

* Added better error handling to the parser

* Refactored into a better directory structure

* Parse package length

* Implemented named string, scope op

* Properly bounds checked namestring

* Fixed namestring regressions

* Started work parsing DefRegionOp. NB: As TermArg is not yet implemented, a bug is present parsing the address offset and length. Additionally, a bug was fixed in NameString

* Completed DefOpRegion implementation. TermArg remains unimplemented, stubbed out

* Implemented TermArg parsing

* Implemented integer parts of computational data

* Implemented defField, and associated FieldList. FieldElement still remains stubbed

* Implmenented FieldElement

* Implmenented named field

* Parsed DefMethod

* Parsed ToHexString

* Parsed ToBuffer

* Parsed both subtract and sizeof

* Fixed size bug in sizeof parsing

* Parsed Store, fixed a parse bug where Target should be a SuperName not a TermArg

* Parsed while

* Parsed LLess

* Parsed DerefOf

* Parse Index

* Parse increment

* Parse device

* Parse device

* Parsed create dword field

* Parsed if/else block

* Properly parsed Target, rendered an AST from existing parse code, and stubbed out MethodInvocation parser method

* Implemented deferred loading, and deferred method invocation parses

* Parsed Or

* Fixed a bunch of off-by-one errors. Shows what I get for copying code around

* Parsed Return

* Fixed a boolean logic error in the handling of the extended instruction namespace

* Added DefBuffer to ComputationalData

* Removed a temporary file

* Parsed ReservedField

* Parsed DefPackage, DefAnd, and ComputationalData::String

* Parsed DefMutex

* Parsed DefAlias and RevisionOp

* Parsed DebugObj

* Parsed DefRefOf

* Parsed type 6 opcodes

* Added ObjectReference and DDBHandle to DataRefObj parsing

* Parsed DefVarPackage, in both Type2OpCode, and in DataObj

* Parsed DefBankField

* Parsed AccessField

* Parsed ConnectField

* Parsed CreateBitField

* Parsed CreateByteField

* Parsed CreateWordField

* Parsed CreateQWordField

* Parsed CreateField

* Parsed DefDataRegion

* Parsed DefEvent

* Parsed IndexField

* Parsed DefPowerRes

* Parsed DefProcessor

* Parsed DefThermalZone:

* Parsed ExtendedAccessField

* Parsed DefBreak, DefBreakPoint, DefContinue and DefNoop (all type 1 opcodes with no parameters and one byte)

* Parsed DefFatal

* Parsed DefLoad

* Parsed DefNotify

* Parsed DefRelease

* Parsed DefReset

* Parsed DefSignal

* Parsed DefSleep

* Parsed DefStall

* Parsed DefUnload

* Parsed DefAcquire

* Parsed DefAnd

* Parsed DefConcat

* Parsed ConcatRes

* Switched Concat and ConcatRes opcodes

* Parsed CondRefOf

* Parsed DefDecrement and DefCopyObject

* Parsed DefDivide, fixed length calculation bug in a bunch of parse routines

* Parsed DefFindSetLeftBit

* Parsed DefFindSetRightBit

* Parsed DefFromBCD

* Parsed DefLAnd

* Parsed DefLGreater

* Parsed LNot

* Parsed DefLOr

* Parsed DefLoadTable

* Parsed DefMatch

* Parsed DefMid

* Parsed DefMod

* Parsed DefMultiply

* Parsed DefNAnd

* Parsed DefNOr

* Parsed DefNot

* Parsed DefObjectType

* Parsed DefShiftLeft and DefShiftRight

* Parsed DefTimer

* Parsed DefToBCD, DefToDecimalString, DefToInteger and DefToString

* Parsed DefXor

* Parsed DefWait

* Implemented a parser, abstract syntax tree, and basic infrastructure for the AML subsystem of the ACPI module. The entire AML grammar is parsed and placed into an abstract syntax tree, with one exception: method invocations, rather than parsing, defer the load until later on in the process, due to the way the grammar works.

Still to be done:
 - Refactor the code: a lot of the parser is very repetitive, and could easily be refactored with the aid of macros. This would reduce the length and improve legibility, though not affect function.
 - More rigorous testing of parser: the parser has, thus far, only been tested on the DSDT in QEMU. There may be bugs present that are hidden.
 - Parse the SSDTs: the SSDTs should be parsed after the DSDT, and contain more AML bytecode to be treated as modifying the same namespace. Adding this would be simple, though not urgent.
 - Transform the AST into a concrete executable tree: the CET is what will hold all information necessary to execute control methods and evaluate namespace objects. While this could be done in the AST, due to the way AML is laid out this would be very inefficient and require a lot of repetitive transformations every time something is to be executed. Therefore, perform the transformations upfront.
 - Parse the deferred loads, and the method invocations contained within: Once the AST has been rendered into a CET, sufficient information will be present to parse method invocations and add those to the namespace.
 - Bytecode interpreter: Once the CET has been finalized with method invocation parsing, it can then be called and executed.
 - Control method executor: this should walk the namespace, locating the relevant control method, then calling the interpreter on it.
 - Namespace enumerator: the executor shall use this to walk the namespace, and it should also be publicly accessible to allow outside code to determine what devices are present in the system.
 - Memory accessor API: ACPI AML has a concept of memory access in certain device domains - for example, the PCI BAR registers. These are all device specific offsets, therefore device drivers, or more accurately bus drivers, should be capable of installing handlers to manage this memory access.
 - CET concatenation: The DSDT and SSDTs all affect the same namespace, therefore concatenating the resulting trees should be possible.
 - Type checking: some operations in AML are typed. This should be handled at tree transformation time or earlier, and could indeed done in the parse step with some modification to the parser. This is currently not the case.

* Partial refactor of AML code

* Further refactoring

* Fully refactored type 2 opcode selector

* Refactored type 6 opcode selector

* Further refactored Type 2 opcode parsing

* Implemented basic infrastructure in order to render the AST down to a namespace object

* Resolved scopes into the namespace

* Put OpRegion into namespace

* Rendered field parsing to the namespace object

* Methods now placed in namespace

* Moved DefName into the namespace

* Moved packages into the namespace

* Converted shutdown sequence to use AML parser

* Moved shutdown over to use AML parsing fully

* Removed the no longer needed DSDT code

* Better messages on unmapping failure

* Disable preemption until paging bug is fixed

* Refactor kernel mapping so that symbol table is mapped

* Add symbol lookup (still very WIP)

* Improve method of getting symbol name

* Reenable preemption

* Demangle symbols

* Fix overallocation

* Remove tilde files
2017-06-17 18:47:27 -06:00
Jeremy Soller 73a71a7d85 Increase size of kernel heap when live disk is loaded 2017-06-17 14:32:31 -06:00
Jeremy Soller 85c02365c9 Fix overallocation 2017-06-14 20:26:05 -06:00
Jeremy Soller c9cbdab9f1 Demangle symbols 2017-06-14 20:25:49 -06:00
Jeremy Soller 7ef2401db3 Reenable preemption 2017-06-14 20:25:38 -06:00
Jeremy Soller 9b19ab9439 Improve method of getting symbol name 2017-06-13 21:56:20 -06:00
Jeremy Soller acab23d1e1 Add symbol lookup (still very WIP) 2017-06-13 21:43:37 -06:00
Jeremy Soller d6354aeb56 Refactor kernel mapping so that symbol table is mapped 2017-06-13 20:42:04 -06:00
Jeremy Soller 8b05863ebb Disable preemption until paging bug is fixed 2017-06-13 19:10:32 -06:00
Jeremy Soller e3020db04f Better messages on unmapping failure 2017-06-11 08:40:27 -06:00
Jeremy Soller 8d89925842 Align ELF segments to avoid subtract overflow 2017-06-04 18:34:45 -06:00
Jeremy Soller 138463b74a Merge pull request #21 from ids1024/unique
Update for changes in std::ptr::Unique API
2017-06-02 20:56:01 -06:00
Ian Douglas Scott 3c5b262b0e Update for changes in std::ptr::Unique API 2017-05-21 13:44:10 -07:00
Jeremy Soller 4d2808a012 Remove free count print 2017-05-12 21:04:52 -06:00
Jeremy Soller 32b0c06314 Remove hardcoded live filesystem 2017-05-11 21:16:07 -06:00
Jeremy Soller 62d3f4bd93 Add Xargo support 2017-05-10 21:38:40 -06:00
bjorn3 586f249069 Add trailing newline to Cargo.toml 2017-04-29 17:52:55 +02:00
bjorn3 6f6f8f7391 Check multicore code even if disabled 2017-04-29 17:46:36 +02:00
bjorn3 37b4ac151b Fix some warnings 2017-04-29 17:45:43 +02:00
Jeremy Soller b3a25bd3a3 Merge pull request #14 from bjorn3/ls_root_scheme
Ls root scheme
2017-04-29 06:49:55 -06:00
Jeremy Soller d8630faccb Merge pull request #15 from bjorn3/remove_pit_ticks_assert
Remove PIT_TICKS assert
2017-04-29 06:40:28 -06:00
bjorn3 248cfa51ae Remove PIT_TICKS assert 2017-04-29 10:46:07 +02:00
bjorn3 ca8b6f522e Fix closing ls handle 2017-04-29 10:43:50 +02:00
bjorn3 8ffe704e7a Remove yet another unnecessary change 2017-04-28 18:44:37 +02:00
bjorn3 4441b750cf Remove unnecessary change 2017-04-28 18:43:39 +02:00
bjorn3 c9fdc4beae Make it working 2017-04-28 18:42:33 +02:00
bjorn3 4c006bca48 Remove UserOrListHandle 2017-04-28 16:18:41 +02:00
bjorn3 80afcc8879 Implement listing all schemes using : scheme 2017-04-28 15:40:15 +02:00
Jeremy Soller 0a457bdced Merge pull request #12 from InsidiousMind/fix-pit-not-context-switching
Fix PIT Interrupt Not Context Switching [irq]
2017-04-25 17:41:55 -06:00
Andrew Plaza 2fc4454f5e set PIT_TICKS to 0 in context::switch() 2017-04-25 16:59:14 -04:00
Andrew Plaza 5ba02ca940 Reset PIT_TICKS to 0 on context::switch, change condition for context::switch [irq]
Set the counter to 0 when context is to be switched in the PIT interrupt,
and change the condition for context switching from % 10 to >= 10.
2017-04-25 14:40:23 -04:00
Andrew Plaza 7127e14b5d Fix PIT Interrupt Not Context Switching [irq]
PIT interrupt should context switch or else all of redox crashes.
This will fix programs like the Snake game crashing all of Redox.
A global AtomicUSize counter was added, and a line to switch contexts
on every 10 PIT interrupts in irq.rs.
2017-04-24 22:07:32 -04:00
Jeremy Soller dd98bfec5c Fix typo in live scheme 2017-04-19 22:00:30 -06:00
Jeremy Soller efd64d55e1 Bug fixes for fcntl and o_cloexec
Add fcntl to schemes
Fix debug: hang
2017-04-19 21:56:09 -06:00
Jeremy Soller 40ff16e42d Add __rust_allocate_zeroed to work with newest nightly 2017-04-18 21:26:18 -06:00
Jeremy Soller d036c667a1 Perform cloexec logic in kernel 2017-04-16 12:49:54 -06:00
Jeremy Soller ea1150cd9b Implement CLOEXEC for root scheme and initfs 2017-04-15 22:35:05 -06:00
Jeremy Soller 9d39317f95 Fix issue where ppid changes during child close 2017-04-15 20:29:08 -06:00
Jeremy Soller 66120cf201 Fix deallocation issues by ignoring deallocation on temporary page 2017-04-15 19:56:48 -06:00
Jeremy Soller 800e6c6de7 Free page tables during unmap, if empty 2017-04-15 19:22:17 -06:00
Jeremy Soller 1e8df4b905 Add sys:iostat 2017-04-15 09:58:03 -06:00
Jeremy Soller a38f32c735 Add path implementation to most kernel schemes 2017-04-15 09:50:02 -06:00
Jeremy Soller 7b5873e460 Allow allocation of larger sizes 2017-04-14 21:17:31 -06:00
Jeremy Soller b3a3caf191 Fix memmove 2017-04-14 21:07:02 -06:00
Jeremy Soller 6fef10bcb1 Merge branch 'master' of https://github.com/redox-os/kernel 2017-04-14 20:59:32 -06:00
Jeremy Soller a9d92df5fa Implement frame recycler 2017-04-14 20:59:27 -06:00
Jeremy Soller 903432f057 Fix issue with reusing temporary page frame 2017-04-14 20:59:01 -06:00
Jeremy Soller 7c1d5d8306 Disable SMP startup, fix issue with reusing trampoline frame 2017-04-14 20:58:23 -06:00
Jeremy Soller 0a72d1cbd8 Merge pull request #11 from pi-pi3/faster-externs
A faster implementation of the memcpy family
2017-04-14 16:49:58 -06:00
pi_pi3 5c1e619063 Avoid multiplication in memcpy family functions
Instead of multiplying everything by 8[/4], now addition is used. That
way code is prettier.
2017-04-14 14:51:04 +02:00
pi_pi3 c4fc76f844 A faster implementation of the memcpy family
The default implementation of the memcpy, memmove, memset and memcmp
functions in the kernel file `extern.rs` uses a naive implementation
by copying, assigning or comparing bytes ony by one. This can be slow.
This commit proposes a reimplementation of those functions by copying,
assigning or comparing in group of 8 bytes by using the u64 type and
its respective pointers instead of u8. Alternative version for 32-bit
architectures are also supplied for future compatibility with x86.
Both version first copy whatever they can with wide word types. The
tail, i.e. the final few bytes that do not fit in a dword or qword
are then copied byte by byte.

Here is a comparison of copying 64kiB (65536 bytes) on stack:

x86_64-unknown-linux-gnu: (64-bit)
       | naive (ns) | fast (ns) | speedup (x)
-------|------------|-----------|------------
memcpy |   204430   |   32994   |   ~6.20
memmove|   202540   |   33186   |   ~6.10
memset |   163391   |   23884   |   ~6.84
memcmp |   205663   |   34385   |   ~5.98

i686-unknown-linux-gnu: (32-bit)
       | naive (ns) | fast (ns) | speedup (x)
-------|------------|-----------|------------
memcpy |   206297   |   66858   |   ~3.09
memmove|   204576   |   70326   |   ~2.91
memset |   165599   |   50227   |   ~3.30
memcmp |   204262   |   70572   |   ~2.89

Copying on the heap behaves simmilarly.

All tests performed on Intel i5 6600K (4x4.2GHz),
ArchLinux Kernel 4.8.12-3 x86_64.
2017-04-14 14:37:32 +02:00
Jeremy Soller 56a533fbbc Add linker flavor 2017-04-13 19:46:48 -06:00
Jeremy Soller 4204d9905e Merge branch 'master' of https://github.com/redox-os/kernel 2017-04-11 21:27:44 -06:00
Jeremy Soller c4fb60f216 Implement script file support 2017-04-11 21:27:39 -06:00
Jeremy Soller d9e95448a4 Merge pull request #10 from xTibor/fix_initfs
Fix the listing of `initfs:` directories
2017-04-11 06:23:28 -06:00
xTibor 1f5bea611d Fix the listing of initfs: directories
There was a bug at the `initfs` generation which made the listing of the contents of the `initfs:`subdirectories impossible from the command line.

The subdirectory listing data had the full paths of the files (like `bin/ahcid\nbin/bgad\n...`) when it should just only be the names of the files (`ahcid\nbgad\n...`)
2017-04-11 05:26:10 +02:00
Jeremy Soller e43f5dda81 Implement timeouts
Cleanup utf8 path error handling
2017-04-08 21:59:30 -06:00
Jeremy Soller b286e69c9d Fix shutdown by disabling APs 2017-04-07 21:49:32 -06:00
Jeremy Soller a7f35e14cc Cleanup debug scheme 2017-04-05 20:11:51 -06:00
Jeremy Soller d26a9ee990 Fix goblin include 2017-04-05 19:10:17 -06:00
Jeremy Soller e860c9efdc Merge pull request #9 from redox-os/refactor
Refactor
2017-04-05 17:36:36 -06:00
Jeremy Soller 2087544ea7 Move all files to src 2017-04-03 21:47:01 -06:00
Jeremy Soller ff93e9cb82 Cleanup some 2017-04-03 21:16:50 -06:00
Jeremy Soller be7f8d64e6 Increase kernel heap, use crates version of goblin 2017-04-01 21:10:55 -06:00
Jeremy Soller cbacd0eea7 Merge pull request #7 from AdamNiederer/patch-1
Fix spelling & grammar in README.md
2017-03-27 06:56:01 -06:00
Adam Niederer 0ae08c52f6 Fix spelling & grammar in README.md 2017-03-26 22:51:28 -04:00
Jeremy Soller 7817122662 Loop on serial input
Fix issue with serial and cascade interrupts not being ackd
2017-03-24 20:38:02 -06:00
Jeremy Soller 906ef94ffd Fix bug with sleep - wake is not cleared after it occurs
Do not initialize waitcondition with capacity
2017-03-21 20:30:46 -06:00
Jeremy Soller ffd7594971 Disable century register for now 2017-03-20 21:47:18 -06:00
Jeremy Soller 228cd79cd4 Refactor ACPI, implement poweroff correctly using the DSDT in ACPI 2017-03-19 16:45:19 -06:00
Jeremy Soller e726234bc6 Fix style of new ACPI code, reduce warnings 2017-03-19 09:34:54 -06:00
Jeremy Soller 643e1f6552 Merge pull request #6 from CWood1/rtc-century
Implemented reading from RTC Century counter in x86_64 arch, if available
2017-03-19 07:29:30 -06:00
Connor Wood f79424aeac Fully implemented reading the RTC century counter, and laid out initial infrastructure for ACPI information to be used across the kernel, in the x86_64 architecture.
- Implemented a global variable, ACPI_TABLE, behind a mutex, which contains the ACPI information pertinent to the rest of the kernel, currently solely containing a pointer to the FADT.
- Split device initialization into two categories - "core" devices, such as the PIC and local APIC, necessary for initializing the rest of the kernel, and "non-core" devices such as serial and RTC, which are to be initialized last.
- Checked for the presence of the century register, and consequentially read from, in the RTC code, now factored into the date calculation. The location of the register is pulled from the "century" field in the FADT.
- Modified page unmapping in the ACPI code, such that any tables to be stored globally (currently only the FADT) are not unmapped after reading, such that they can be stored in globally accessible pointers without causing page faults.
2017-03-18 16:08:45 +00:00
Connor Wood 661ebb6390 Saved FADT in a pointer accessible elsewhere in the kernel 2017-03-18 15:12:42 +00:00
Jeremy Soller 1d5c7d6a4e Merge branch 'master' of https://github.com/redox-os/kernel 2017-03-16 22:50:16 -06:00
Jeremy Soller 05bb497fe4 Use normal EOI mode 2017-03-16 22:50:09 -06:00
Jeremy Soller ab4193d4fc Merge pull request #5 from tones111/cpuid_panic
Prevent cpuid get_extended_function_info panic
2017-03-16 22:15:02 -06:00
Paul Sbarra d667fa61e6 Prevent cpuid get_extended_function_info panic
A kernel panic occurs on some CPUs (notably qemu-system-x86_64) when
calling rust-cpuid's get_extended_function_info.  This is fixed upstream
in commit c3ebfc553cdff98d19d29777fd85c4f9182bfb66 but has yet to make
it crates.io.

The panic can by triggered by running "ls sys:" from ion and causes
redox to become unresponsive.
2017-03-16 22:32:57 -05:00
Jeremy Soller 7dd8de777d Merge pull request #3 from kolipka/standalone_support
Remove hardcoded initfs folder
2017-02-27 11:18:03 -07:00
Konrad Lipner 5ccbd788f3 Remove hardcoded initfs folder
initfs folder should be specified in INITFS_FOLDER environment variable
As a result kernel module can be compiled on it's own.
2017-02-15 21:54:38 +01:00
Jeremy Soller b9793deb59 Disable secondary processors with hlt 2017-02-13 22:15:42 -07:00
Jeremy Soller 473a7b6832 USe auto-eoi mode, mask off interrupts that happen and allow userspace to clear the mask 2017-02-11 21:09:16 -07:00
Jeremy Soller 0e22ba24be Initialize PIC in Rust 2017-02-11 20:54:14 -07:00
Jeremy Soller 571b2aa2e7 Add reminder 2017-02-07 22:14:53 -07:00
Jeremy Soller 776bb83a70 Unstick system by acknowledging IRQs on boot 2017-02-07 22:14:28 -07:00
Jeremy Soller be43673df6 Merge pull request #2 from little-dude/master
remove unused #[macro_use]
2017-01-24 12:48:08 -07:00
Corentin Henry 4d2499e4d3 remove unused #[macro_use] 2017-01-24 11:14:12 -08:00
Jeremy Soller 0d3aa234ff Add target definitions 2017-01-16 10:10:16 -07:00
Jeremy Soller 04d9d6b40a Specify crates.io versions 2017-01-13 15:09:56 -07:00
Jeremy Soller 35c2297724 Fix from @yoric - incorrect initialization of spin loop 2017-01-11 13:59:10 -07:00
Jeremy Soller ed69fac232 Allow memory: to be accessed in all namespaces 2017-01-10 09:59:30 -07:00
Jeremy Soller ba4588e84f Simplify path parsing 2017-01-10 09:22:59 -07:00
Jeremy Soller 433746e13c Move skipping to loop encompasing entire path 2017-01-10 09:19:02 -07:00
Jeremy Soller e20135575c Refactor to move alloc_kernel in tree, and move io into syscall 2017-01-09 20:35:54 -07:00
Jeremy Soller 1c7b5680a4 Use syscall crate from git 2017-01-09 19:47:44 -07:00
Jeremy Soller 375e8addd2 Merge pull request #1 from cactorium/master
Allow for more complicated directory paths
2017-01-07 07:37:10 -07:00
Kelvin Ly b0cafc1890 Correctly handle relative paths starting from the root directory 2017-01-07 08:00:16 -05:00
Kelvin Ly 046d8ac0c5 Fix typo and add functionality to more properly handle the parent of the root of the filesystem 2017-01-07 00:49:45 -05:00
Kelvin Ly fc94bd411a Allow for more complicated directory paths 2017-01-07 00:41:32 -05:00
Jeremy Soller 06118a23dd Remove profiles 2017-01-04 16:33:51 -07:00
Jeremy Soller 882e64bdb9 Ignore Cargo.lock and target 2017-01-04 15:52:38 -07:00
Jeremy Soller 0c8ba636f4 Cleanup Redox repo, update Rust, remove old target 2017-01-03 15:55:00 -07:00
Jeremy Soller 04ed700216 Force flush of tables 2017-01-03 14:09:15 -07:00
Jeremy Soller 2cb8b1fd53 Use variable for temporary page location 2017-01-01 18:00:24 -07:00
Jeremy Soller 5ddd2ca458 Update coreutils, remove sys:memory 2016-12-28 17:22:10 -07:00
Jeremy Soller aebe7152ce Add memory scheme to live configuration 2016-12-28 12:42:54 -07:00
Jeremy Soller eb3f76f204 Add memory scheme, implement fstatvfs 2016-12-28 11:38:42 -07:00
Jeremy Soller 164648c200 Compile using real libstd, with no crate overrides 2016-12-27 16:47:08 -07:00
Jeremy Soller 515aa3671b Implement dup2. Add debugging lines. 2016-12-27 11:18:41 -07:00
Jeremy Soller 6c308ada46 Workaround for an issue where a leftover grant is not unmapped before reap 2016-12-13 20:41:43 -07:00
Jeremy Soller 4b5271b52b Remove debug message 2016-12-06 15:27:49 -07:00
Jeremy Soller a46a68b5c7 Use isohybrid to generate a USB stick friendly ISO
Add assertions to verify that grants are unmapped
Fix grant unmapping in exec and exit, thus fixing some crashes without network cards
2016-12-06 14:47:05 -07:00
Jeremy Soller 528ce22617 More path cleanup 2016-11-29 18:15:53 -07:00
Jeremy Soller ddac22a242 Cleanup path usage 2016-11-29 18:14:10 -07:00
Jeremy Soller cc9fd700cf Update to make libstd use redox_syscall 2016-11-28 18:14:21 -07:00
Jeremy Soller 2b302bd6ea Implement O_DIRECTORY, switch to open for mkdir 2016-11-25 18:24:38 -07:00
Jeremy Soller bbe2dd0ff4 Implement rfc 4 2016-11-25 12:09:54 -07:00
Jeremy Soller 5ef013eecf Fix warnings, increase size of fs 2016-11-19 20:23:25 -07:00
Jeremy Soller b17444e3ce Allow compiling both livedisk and harddrive 2016-11-19 20:19:41 -07:00
Jeremy Soller 6b084d3ff5 Allow initfs to be written 2016-11-18 08:46:11 -07:00
Jeremy Soller 71fbf2e8f4 Add statvfs 2016-11-18 08:44:03 -07:00
Jeremy Soller f2e15b81bd Update orbutils, fix warnings 2016-11-17 14:23:41 -07:00
Jeremy Soller a5f95cd2b1 Replace setuid, setgid with setreuid, setregid 2016-11-17 14:16:39 -07:00
Jeremy Soller 1fe0dae848 Cleanup zombies in container - show scheme namespace in context list 2016-11-17 12:24:46 -07:00
Jeremy Soller 93d43f7dbc Add signal support - exit on signal 2016-11-17 12:12:02 -07:00
Jeremy Soller 3da2ea9d9a More advanced setns syscall 2016-11-16 22:14:02 -07:00
Jeremy Soller c290fd78db Add ability to contain a process in a scheme sandbox 2016-11-16 20:54:38 -07:00
Jeremy Soller 0dd2befe4d Pass through fcntl 2016-11-15 17:09:28 -07:00
Jeremy Soller a9c7a4e773 Update to add chmod 2016-11-15 17:08:14 -07:00
Jeremy Soller 3e5a43d47d Update syscall and rust, add fcntl for permissions 2016-11-15 16:12:51 -07:00
Jeremy Soller 3363859cb7 FileHandle from in exec close 2016-11-15 14:09:08 -07:00
Jeremy Soller 7c35351dc2 Merge branch 'cap2' of https://github.com/Yoric/redox into Yoric-cap2 2016-11-15 14:05:43 -07:00
Jeremy Soller 41f8e349af Pass clone and exec to dup to identify dup location, make exec dup to implement cloexec 2016-11-14 20:55:31 -07:00
Jeremy Soller 7a241b28bf Add sys:exe to get current executable 2016-11-14 20:54:33 -07:00
Jeremy Soller 3469310a19 Add fcntl 2016-11-14 12:15:34 -07:00
Jeremy Soller a7bfe1232a Implement more test arch features 2016-11-14 11:04:31 -07:00
Jeremy Soller c3f38be7ca Use core intrinsics instead of memset 2016-11-14 10:50:00 -07:00
David Teller 53c2c7a332 Converting file handles into a new type FileHandle
Keeping file handles (and pids, and scheme id, ...) as usize is a
footgun. Let's remove it.
2016-11-14 07:46:43 +01:00
David Teller 008ca3c207 Converting pids into a new type ContextId
Keeping pid (and file descriptor, and scheme id, ...) as usize is a
footgun. Let's remove it.
2016-11-14 07:46:43 +01:00
David Teller 3aa2f2d0c4 Converting scheme ids into a new type SchemeId
Keeping scheme ids (and pids, and file handles, ...) as usize is a
footgun. Let's remove it.
2016-11-14 07:46:43 +01:00
David Teller c7735dd177 Introducing macros for defining SchemeId, Pid, ... 2016-11-14 07:46:43 +01:00
Jeremy Soller 99a15e791d Get CPU features 2016-11-07 13:56:02 -07:00
Jeremy Soller 25988d6b71 Add memory information 2016-11-07 12:47:32 -07:00
Jeremy Soller e3f7c9a692 Update scheme documentation 2016-11-04 13:38:40 -06:00
Jeremy Soller 194b674155 Add some documentation 2016-11-03 20:29:19 -06:00
Jeremy Soller e9ae9b190c Fix eventing in kernel 2016-11-03 16:02:44 -06:00
David Teller dcf0a21da2 Improving self-documentation of the implementation of Registry. (#732) 2016-11-03 09:06:44 -06:00
pythoneer 6b8b7c03ab increase process id range (#729) 2016-11-03 07:36:12 -06:00
Jeremy Soller 3fc5e52c64 Remove resource_sceme, Fix syscall crate name, add fmap 2016-11-02 19:48:25 -06:00
Jeremy Soller 190ccc2ef1 Fix #725 by checking mode in chdir 2016-11-01 14:49:51 -06:00
Jeremy Soller fb20ed5436 Add contributing and readme 2016-11-01 12:04:50 -06:00
Jeremy Soller dc53add6a9 Correct init process, allow waiting on any children, reap zombies in init 2016-11-01 11:04:53 -06:00
Jeremy Soller a33ddef38f remove take message 2016-10-31 22:12:10 -06:00
Jeremy Soller 7952e3ed63 Add null: and zero: 2016-10-31 21:54:56 -06:00
Jeremy Soller aad20b0e8b Remove debugging 2016-10-31 19:40:27 -06:00
Jeremy Soller fd71b5e3f1 Fixes for TLS 2016-10-31 19:09:22 -06:00
Jeremy Soller b98a814dfc Remove rd/wrfsbase 2016-10-31 18:04:28 -06:00
Jeremy Soller ed9c2b9d6c Smp (#23)
* Fire up multiple processors

* Use IPIs to wake up secondary processors

* Much better exception information

* Modifications to show more information on fault

* WIP: Use real libstd

* Add TLS (not complete)

* Add random function, export getpid, cleanup

* Do not spin APs until new context

* Update rust

* Update rust

* Use rd/wrfsbase

* Implement TLS

* Implement compiler builtins and update rust

* Update rust

* Back to Redox libstd

* Update rust
2016-10-31 10:49:00 -06:00
Jeremy Soller 1a1fb1f5e1 Redo networking (#22)
* Rewriting network functions

* Add buffer to dup
Fix non-blocking handling by triggering once on enabling events to read to EOF

* Modifications for UDP API

* Implement TCP client side

* Add active close

* Add DMAR parser

* Implement basic TCP listening. Need to improve the state machine

* Reduce debugging

* Fixes for close procedure

* Updates to fix path processing in libstd
2016-10-26 13:19:56 -06:00
David Teller 580f30e520 Documenting use of enable_and_halt(). (#21) 2016-10-24 16:03:03 -06:00
Jeremy Soller e7a4b786b0 Add CPU ID lock 2016-10-23 11:24:10 -06:00
Jeremy Soller c680f2531e Make all perCPU mappings available in all contexts - this will allow APs to pick up threads 2016-10-23 09:13:12 -06:00
Jeremy Soller ad152ad968 Remove unnecessary context switch in waitpid 2016-10-20 21:50:11 -06:00
Jeremy Soller a97aa95c23 Improve wait condition performance 2016-10-20 21:49:47 -06:00
Jeremy Soller 962836aa47 Do not block on IRQ read, add more debugging to RTL8168/9 2016-10-20 15:49:17 -06:00
Jeremy Soller 9c3a06b8f9 Add nonblocking root scheme 2016-10-20 12:31:39 -06:00
Jeremy Soller 71ff7af970 Send multiple events if there are multiple packets 2016-10-14 22:06:43 -06:00
Jeremy Soller 99fee86ef9 Significant improvements for events - switch to event queue in orbital 2016-10-14 20:12:21 -06:00
Jeremy Soller bc72488851 Allow O_NONBLOCK to be passed to pipe 2016-10-14 19:34:00 -06:00
Jeremy Soller f852450610 Add specification to vesad
Fix piping
Fix bug where resources are not closed
Add arpd
Remove question_mark features
2016-10-14 18:22:57 -06:00
Jeremy Soller 92b4514895 Fixes for updating submodules 2016-10-14 12:00:25 -06:00
Jeremy Soller c294b5b92c Disable orbital by default 2016-10-13 21:19:02 -06:00
Jeremy Soller 2fc605a88d Allow schemes to be listed 2016-10-13 21:13:37 -06:00
Jeremy Soller c484241e1c Add sys scheme to allow inspection of processes. WIP: Signals. 2016-10-13 21:00:51 -06:00
Jeremy Soller d778f0b040 Orbital (#16)
* Port previous ethernet scheme

* Add ipd

* Fix initfs rebuilds, use QEMU user networking addresses in ipd

* Add tcp/udp, netutils, dns, and network config

* Add fsync to network driver

* Add dns, router, subnet by default

* Fix e1000 driver. Make ethernet and IP non-blocking to avoid deadlocks

* Add orbital server, WIP

* Add futex

* Add orbutils and orbital

* Update libstd, orbutils, and orbital
Move ANSI key encoding to vesad

* Add orbital assets

* Update orbital

* Update to add login manager

* Add blocking primitives, block for most things except waitpid, update orbital

* Wait in waitpid and IRQ, improvements for other waits

* Fevent in root scheme

* WIP: Switch to using fevent

* Reorganize

* Event based e1000d driver

* Superuser-only access to some network schemes, display, and disk

* Superuser root and irq schemes

* Fix orbital
2016-10-13 17:21:42 -06:00
Jeremy Soller 7841f3617a Time (#11)
* WIP: Time syscalls

* Count time from PIT using low tickrate

* Implement realtime

* Implement nanosleep with a tight loop
2016-10-06 20:50:14 -06:00
Jeremy Soller 7a96e6c9be Add pipe2 2016-10-06 18:46:24 -06:00
Jeremy Soller df87992af4 Add sudo command, add effective UID and GID, and groups file 2016-10-05 20:31:59 -06:00
Jeremy Soller 965941cd1c Implement unix permissions 2016-10-05 18:01:05 -06:00
Jeremy Soller ea4fa78f72 Merge branch 'encoded_syscall' 2016-10-05 15:43:35 -06:00
Jeremy Soller 82d2c49543 Add permissions to the filesystem, preliminary permissions to the syscalls 2016-10-05 14:24:08 -06:00
Jeremy Soller 4f73b7b5a5 Implement vfork 2016-09-28 21:33:54 -06:00
Jeremy Soller fc5a35d22a 64-bit stat size, read entire executable in one go 2016-09-28 20:42:03 -06:00
Jeremy Soller bfaa564afd Fix CWD without trainling slash 2016-09-28 11:52:29 -06:00
Jeremy Soller d50a1485a7 mkdir and rmdir 2016-09-28 11:26:49 -06:00
Jeremy Soller af5b43ca0b Fix dup 2016-09-28 11:22:01 -06:00
Jeremy Soller 62d151c9e8 Unlink syscall 2016-09-28 11:18:28 -06:00
Jeremy Soller f79570d42f Fix kernel user scheme fpath 2016-09-28 10:29:17 -06:00
Jeremy Soller 2c9a953295 Remove unnecessary slash 2016-09-26 17:39:58 -06:00
Jeremy Soller bc4f29d3c8 WIP: AHCI drivers and more memory syscalls 2016-09-26 17:00:06 -06:00
Jeremy Soller 5877c8ac16 Encode many of the file syscalls 2016-09-25 11:20:59 -06:00
Jeremy Soller 1e2e5a5d31 Event support - demonstration in example scheme 2016-09-23 17:54:39 -06:00
Jeremy Soller e390c2d00c WIP: Kevent 2016-09-23 15:47:53 -06:00
Jeremy Soller 3034daac31 Add env 2016-09-23 11:01:53 -06:00
Jeremy Soller 750a2c1f9d Fix path lookup 2016-09-22 21:27:33 -06:00
Jeremy Soller 879d582e44 Implement fpath in initfs 2016-09-22 21:13:17 -06:00
Jeremy Soller bbacabce4f Trim in env scheme, do not debug initfs 2016-09-22 20:49:28 -06:00
Jeremy Soller 733a812259 Folders in initfs 2016-09-22 20:26:33 -06:00
Jeremy Soller fcc701cf66 Bring in some coreutils 2016-09-22 19:38:09 -06:00
Jeremy Soller 35ad65bbda Enable SSE and FPU 2016-09-22 16:14:45 -06:00
Jeremy Soller 2e9697353c Add wnohang, make PS/2 driver write input to display scheme, which then passes it to the shell 2016-09-22 10:10:27 -06:00
Jeremy Soller 57b50ba819 Add login process. Remove debugging. Fix order of arguments 2016-09-22 08:43:22 -06:00
Jeremy Soller 10a6e148f0 WIP: Userspace console 2016-09-21 12:18:48 -06:00
Jeremy Soller ec240ef778 Clone grants 2016-09-20 22:14:08 -06:00
Jeremy Soller b01eb8e47b WIP: VESA driver. Make initfs generated by code 2016-09-20 21:52:45 -06:00
Jeremy Soller 2b6fae0138 Validate memory pointers 2016-09-20 18:03:14 -06:00
Jeremy Soller e2ec6fd220 Implement more system calls 2016-09-20 16:57:45 -06:00
Jeremy Soller 4ee9a6b492 Create example userspace scheme. Remove kernel duplication of syscalls, use syscall crate instead 2016-09-20 16:23:28 -06:00
Jeremy Soller 3ae7dc8d98 Grant to allow passing data to scheme handler 2016-09-20 14:50:04 -06:00
Jeremy Soller 863c59d3c2 Increase buffer size when reading executable, update libstd 2016-09-20 09:51:26 -06:00
Jeremy Soller eeb1cd0a52 Fix deadlock 2016-09-20 09:21:54 -06:00
Jeremy Soller 7a5d9d440c Implement user schemes. Example in pcid. Currently deadlocks in UserInner 2016-09-20 08:47:16 -06:00
Jeremy Soller 2f06e18743 WIP: User scheme 2016-09-19 21:24:54 -06:00
Jeremy Soller fcbc8951da Minimize locking in schemes. Reenable pcid and ion launch in init. WIP: Userspace schemes 2016-09-19 18:29:28 -06:00
Jeremy Soller fe234e4bf1 Remove warnings 2016-09-19 17:28:22 -06:00
Jeremy Soller 5276c76963 PS/2 driver convert to char 2016-09-19 10:24:19 -06:00
Jeremy Soller 298d999300 Seperate PS/2 keyboard and mouse driver 2016-09-19 09:43:30 -06:00
Jeremy Soller 4403e3e7ac Allow userspace to handle IRQs (WIP). Create basic keyboard handler 2016-09-18 20:17:08 -06:00
Jeremy Soller de53701ed9 Add mechanism to read IRQ count 2016-09-18 18:59:46 -06:00
Jeremy Soller af2f6fc6df Add fsync. Add env scheme, currently hardcoded to get ion to launch. Make serial IRQ send data to debug scheme 2016-09-18 17:55:35 -06:00
Jeremy Soller 8ba97b8cff Canonicalize paths in open 2016-09-18 12:54:10 -06:00
Jeremy Soller 4821357934 Complete execve - add argument support using safe ABI 2016-09-17 21:44:50 -06:00
Jeremy Soller 75016bfe39 Update libstd. Add CWD and associated syscalls. Remove debugging 2016-09-17 19:01:34 -06:00
Jeremy Soller c5afb10b00 Add exit status to status enum 2016-09-17 09:23:36 -06:00
Jeremy Soller 959ecdad04 Fix creation of kstack 2016-09-17 09:18:35 -06:00
Jeremy Soller 9bc242c179 Implement the typical use of waitpid 2016-09-16 18:50:47 -06:00
Jeremy Soller 5f570fa5b4 Allow cloning of files and memory 2016-09-16 18:27:54 -06:00
Jeremy Soller 91fc7c96ab work on shared memory accross threads 2016-09-16 17:51:27 -06:00
Jeremy Soller 236b2f0e04 Panic upon use of unsupported flags 2016-09-16 13:45:00 -06:00
Jeremy Soller 356ba325ea Collapse status of context into one status variable 2016-09-16 11:10:53 -06:00
Jeremy Soller 0f27cd24ce Organize context module 2016-09-16 10:44:52 -06:00
Jeremy Soller 5cbd30988c Do not have interrupts enabled during context switch 2016-09-15 08:40:16 -06:00
Jeremy Soller dee5b4dd9e Remove debugging 2016-09-15 08:39:20 -06:00
Jeremy Soller 1711303ef8 Fix implementation of clone and exec. Now the init process can load and execute the pci driver 2016-09-15 08:35:07 -06:00
Jeremy Soller 8607367058 WIP: Create new page table for clone 2016-09-14 22:21:52 -06:00
Jeremy Soller 1acb84afbb Higher-half kernel mapping. Unmap where possible, freeing up lower memory 2016-09-14 20:47:55 -06:00
Jeremy Soller 932026fed8 WIP: Copy usermode stack 2016-09-13 21:27:27 -06:00
Jeremy Soller b042f40847 Fix userspace clone by clobbering all variables on clone 2016-09-13 20:31:45 -06:00
Jeremy Soller d3ace7dcad Allow cloning of kernel threads. Userspace breaks potentially due to stack aliasing 2016-09-13 20:06:39 -06:00
Jeremy Soller d1c0e3b5da Use flush_all instead of flush for performance 2016-09-13 11:20:55 -06:00
Jeremy Soller efaeb22163 Map kernel TLS to general area 2016-09-12 15:02:03 -06:00
Jeremy Soller d4ca131391 cr3 in context 2016-09-12 12:21:34 -06:00
Jeremy Soller 70bf79a977 Implement exit, partly 2016-09-11 22:03:03 -06:00
Jeremy Soller 0bb1ad38c9 Clear memory on demand 2016-09-11 21:47:44 -06:00
Jeremy Soller db3255dd82 Add comments 2016-09-11 21:35:02 -06:00
Jeremy Soller 011c8f7f2b Cleanup heap management 2016-09-11 21:18:18 -06:00
Jeremy Soller efd41a857e Store context memory information 2016-09-11 21:04:34 -06:00
Jeremy Soller 86597331cc Allow exec, emulate clone by pretending to be child 2016-09-11 18:03:10 -06:00
Jeremy Soller cf27b3a3ad Fix close, add dup 2016-09-11 17:31:21 -06:00
Jeremy Soller 7a928a5f97 Improve init process, debug missing syscalls, fix error codes in syscall return 2016-09-11 16:48:58 -06:00
Jeremy Soller 038cf5aba1 PCI driver WIP 2016-09-11 15:56:48 -06:00
Jeremy Soller 9371120f0f Flush TLB correctly when remapping
Seperate mouse and keyboard structs in PS/2 driver
2016-09-11 15:02:35 -06:00
Jeremy Soller 9b17495dd6 Implement exec
Implement brk
2016-09-10 22:06:09 -06:00
Jeremy Soller 4692e9b267 Load init from initfs 2016-09-10 19:42:26 -06:00
Jeremy Soller c30f4208d4 Implement sched_yield, enable interrupts in userspace 2016-09-10 19:18:59 -06:00
Jeremy Soller 486bfea62c Remove debugging messages, launch elf on APs 2016-09-10 19:03:31 -06:00
Jeremy Soller 0d115508be Seperate kernel and userspace targets 2016-09-09 19:08:04 -06:00
Jeremy Soller 531497d7af Remove debug warnings 2016-09-09 17:30:22 -06:00
Jeremy Soller 3837b2606f Connect schemes so that they can be used 2016-09-08 20:06:33 -06:00
Jeremy Soller 7036ed4c63 Cleanup to use question mark 2016-09-08 19:31:26 -06:00
Jeremy Soller ef9a7c0988 Add syscall library, make init program Rust 2016-09-08 19:10:50 -06:00
Jeremy Soller 44e57773a3 Debug reads writes better, set up stdio for BSP 2016-09-07 21:32:09 -06:00
Jeremy Soller 7c0b17d070 Load a very simple ELF and launch it in usermode 2016-09-07 21:16:30 -06:00
Jeremy Soller 4b98fb8ca3 Improve efficiency of kernel console 2016-09-01 14:39:45 -06:00
Jeremy Soller 5c91017579 Draw on VESA for console using ransid 2016-09-01 11:51:33 -06:00
Jeremy Soller ac9a475ef5 Warnings removal 2016-09-01 11:14:47 -06:00
Jeremy Soller 6269f68b03 Fill in all exception and IRQ entries. Handle PIT, keyboard IRQs 2016-08-31 17:45:21 -06:00
ticki b8f1971329 Merge branch 'master' of github.com:redox-os/kernel 2016-08-31 17:02:47 +02:00
ticki 4966842d72 Add the Fd definition file.
Damn, I forgot to `git add` it.
2016-08-31 17:01:08 +02:00
Jeremy Soller 8c0191564f Add file descriptor type 2016-08-30 16:27:10 -06:00
Jeremy Soller 2ccc13d212 Merge branch 'master' of https://github.com/redox-os/kernel 2016-08-30 16:23:56 -06:00
Jeremy Soller 9bddf55e93 Improvements for context switching 2016-08-30 16:23:51 -06:00
ticki 9ca3559cc8 Newtype file descriptors.
To avoid various bugs regarding the typing of file descriptors, we
newtype them into a simple wrapper type.

- Document some stuff.
2016-08-29 11:58:31 +02:00
Jeremy Soller f2d2b233f3 Simple, unsafe context switch 2016-08-28 18:38:53 -06:00
Jeremy Soller 5c2b6878a6 Arm! 2016-08-25 17:03:01 -06:00
Jeremy Soller 24bfb2c81f Fix the build. Sorry 2016-08-24 19:30:14 -06:00
Jeremy Soller 84873532af Arch context in kernel context 2016-08-24 10:35:42 -06:00
Jeremy Soller aecfa50029 Initialize contexts, add getpid 2016-08-20 14:32:45 -06:00
Jeremy Soller 47280a921a Context list class, static context ID magic 2016-08-20 13:43:35 -06:00
Jeremy Soller 645524fdf5 Setup independent page tables, map heap to a single location 2016-08-19 14:53:16 -06:00
Jeremy Soller 74b40f0a25 Switch to goblin as executable parser 2016-08-19 07:57:24 -06:00
Jeremy Soller b46c7e71c0 Add syscall handler, still work in progress
Add elf files
2016-08-18 19:44:31 -06:00
Jeremy Soller 954af453dc Remove clone from context 2016-08-18 09:02:31 -06:00
Jeremy Soller 8fc113adef Refactor context list 2016-08-18 08:30:45 -06:00
Jeremy Soller 0bd1cda1b6 Cleanup schemes list, remove lazy_static 2016-08-18 08:10:08 -06:00
Jeremy Soller b9e721d4e1 Print out more useful information about AP and BSP, create kmain_ap 2016-08-17 19:38:04 -06:00
Jeremy Soller 996996b0a9 Keep track of AP count, allocate bigger AP stack, stack trace function 2016-08-17 19:34:33 -06:00
Jeremy Soller 1993e701dd Remove warnings 2016-08-17 16:54:48 -06:00
Jeremy Soller 9f79abe542 Lazy static init of schemes 2016-08-16 11:04:14 -06:00
Jeremy Soller 26397084f6 Cleanup, use spinlock for allocator 2016-08-15 15:01:24 -06:00
Jeremy Soller e0daabde05 GDT and IDT in kernel space
Paging constructs completed, remap kernel before jumping to kmain
Panic will do a stack trace
Remove SSE from none target
2016-08-15 14:34:20 -06:00
Jeremy Soller 7da6696a34 Add simple paging, use rust libcore and compile without sse 2016-08-15 11:30:14 -06:00
Jeremy Soller 74ccbaa4a6 Bump allocator 2016-08-14 22:05:32 -06:00
Jeremy Soller 38f1a4fb76 WIP: Schemes 2016-08-14 21:38:32 -06:00
Jeremy Soller 946fd79e83 Test for BadFile 2016-08-14 19:17:55 -06:00
Jeremy Soller dd280a5d1a Add stdout/stderr tests 2016-08-14 18:22:50 -06:00
Jeremy Soller f79d6ce12b Add context and file structs 2016-08-14 18:16:56 -06:00
Jeremy Soller 04a6a45fac WIP: Exec 2016-08-14 16:07:41 -06:00
Jeremy Soller 6cfa38c5ba Add syscall module 2016-08-14 15:58:35 -06:00
Jeremy Soller 621de7fa8a Add test architecture 2016-08-14 14:59:18 -06:00
ticki 916a87fb33 Merge branch 'master' of github.com:redox-os/kernel 2016-08-14 20:55:19 +02:00
ticki 2b50588c29 Interrupt tables.
We add lookup table for interrupt descriptions containing information
about the CPU exceptions etc.
2016-08-14 20:54:23 +02:00
Jeremy Soller faa2b3ac63 Add comment 2016-08-14 12:11:53 -06:00
Jeremy Soller 4cb9df8fa8 Move arch to seperate crate 2016-08-14 11:45:47 -06:00
ticki fb99ec7e6d Strongly typed virtual/physical memory seperation.
This minicommit introduces two newtpyes, `Physical` and `Virtual`,
respectively. These serves as a way to segregate the different forms of
addresses to avoid the issues we had in the old kernel.
2016-08-14 19:21:21 +02:00
ticki b2fe1799fd Rename the src directory to kernel. 2016-08-14 18:42:32 +02:00
672 changed files with 41540 additions and 80739 deletions
+5
View File
@@ -0,0 +1,5 @@
[build]
rustflags = [
# Kernel should preserve floating-point registers
"-Ctarget-feature=-sse,-sse2",
]
+3 -11
View File
@@ -1,11 +1,3 @@
target/
sysroot/
# Local settings folder for Visual Studio Code
.vscode/
# Local settings folder for Jetbrains products (RustRover, IntelliJ, CLion)
.idea/
# Local settings folder for Visual Studio Professional
.vs/
# Local settings folder for the devcontainer extension that most IDEs support.
.devcontainer/
target
/config.toml
.gitlab-ci-local/
+75 -27
View File
@@ -1,42 +1,90 @@
image: "redoxos/redoxer:latest"
variables:
GIT_SUBMODULE_STRATEGY: recursive
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == "main" && $CI_PROJECT_NAMESPACE == "redox-os"'
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"'
- if: '$CI_PROJECT_NAMESPACE == "redox-os"'
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
stages:
- build
- cross-build
- test
fmt:
stage: build
script:
- rustup component add rustfmt
- CHECK_ONLY=1 ./fmt.sh
- other-features
# TODO: benchmarks and profiling (maybe manually enabled for relevant MRs)?
x86_64:
stage: build
script:
- rustup component add rustfmt
- ./check.sh
i586:
stage: cross-build
script:
- ./check.sh --arch=i586
stage: build
script:
- mkdir -p target/${ARCH}
- redoxer env make BUILD=target/${ARCH}
variables:
ARCH: "x86_64"
aarch64:
stage: cross-build
script:
- ./check.sh --arch=aarch64
stage: cross-build
image: "redoxos/redoxer:aarch64"
script:
- mkdir -p target/${ARCH}
- redoxer env make BUILD=target/${ARCH}
variables:
ARCH: "aarch64"
i586:
stage: cross-build
script:
- mkdir -p target/${ARCH}
- TARGET=${ARCH}-unknown-redox redoxer env make BUILD=target/${ARCH}
variables:
ARCH: "i586"
riscv64gc:
stage: cross-build
script:
- ./check.sh --arch=riscv64gc
stage: cross-build
script:
- mkdir -p target/${ARCH}
- TARGET=${ARCH}-unknown-redox redoxer env make BUILD=target/${ARCH}
variables:
ARCH: "riscv64gc"
boot:
stage: test
script:
- timeout -s KILL 9m ./check.sh --test
fmt:
stage: build
script:
- rustup component add rustfmt
- rustfmt --check
x86_64:boot:
stage: test
needs: [x86_64]
script:
- mkdir -p target/${ARCH}
- export COOKBOOK_SOURCE_IDENT=$CI_COMMIT_SHA
- redoxer env make BUILD=target/${ARCH}
- timeout -s KILL 9m redoxer exec --folder target/${ARCH}/:/usr/lib/boot uname -a
variables:
ARCH: "x86_64"
x86_64:relibc:
stage: test
needs: [x86_64]
script:
- redoxer pkg relibc-tests-bins
- export COOKBOOK_SOURCE_IDENT=$CI_COMMIT_SHA
- mkdir -p target/${TARGET}/sysroot/{usr/lib/boot,root} target/${TARGET}/root
- redoxer env make BUILD=target/${TARGET}/sysroot/usr/lib/boot
- (cd target/${TARGET}/sysroot && mv home/user/relibc-tests/* root/)
- timeout -s KILL 9m redoxer exec --folder target/${TARGET}/sysroot/:/ make run
# It is fine if failing sometimes
allow_failure: true
variables:
TARGET: "x86_64-unknown-redox"
profiling-compile:
stage: other-features
allow_failure: true
script:
make check
variables:
ARCH: "x86_64"
KERNEL_CHECK_FEATURES: profiling
-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._
+4
View File
@@ -0,0 +1,4 @@
[submodule "redox-path"]
path = redox-path
url = https://gitlab.redox-os.org/redox-os/redox-path.git
branch = main
+2
View File
@@ -0,0 +1,2 @@
[editor]
auto-format = false
+13
View File
@@ -0,0 +1,13 @@
[[language]]
name = "rust"
[[language-server.rust-analyzer.config.cargo]]
extraEnv = ["RUST_TARGET_PATH=targets"]
# Select one of targets to make lsp work for your confguration
# Do not commit this change
# TODO: find a better way to do this
# target = "aarch64-unknown-kernel"
[[language-server.rust-analyzer.config.check]]
targets = ["x86_64-unknown-kernel", "i686-unknown-kernel", "aarch64-unknown-kernel"]
+79
View File
@@ -0,0 +1,79 @@
# Porting the core Redox kernel to arm AArch64: An outline
## Intro
This document is [my](https://github.com/raw-bin) attempt at:
* Capturing thinking on the work needed for a core Redox kernel port
* Sharing progress with the community as things evolve
* Creating a template that can be used for ports to other architectures
Core Redox kernel means everything needed to get to a non-graphical console-only multi-user shell.
Only the 64-bit execution state (AArch64) with the 64-bit instruction set architecture (A64) shall be supported for the moment. For more background/context read [this](https://developer.arm.com/products/architecture/a-profile/docs/den0024/latest/introduction).
This document is intended to be kept *live*. It will be updated to reflect the current state of work and any feedback received.
It is hard~futile to come up with a strict sequence of work for such ports but this document is a reasonable template to follow.
## Intended target platform
The primary focus is on [qemu's virt machine platform emulation for the AArch64 architecture](https://github.com/qemu/qemu/blob/master/hw/arm/virt.c#L127).
Targeting a virtual platform is a convenient way to bring up the mechanics of architectural support and makes the jump to silicon easier. The preferred boot chain for AArch64 (explained later) is well supported on this platform and boot-over-tftp from localhost makes the debug cycle very efficient.
Once the core kernel port is complete a similar follow on document will be created that is dedicated to silicon bring-up.
## Boot protocol elements
| Item | Notes |
|------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Linux kernel boot protocol for AArch64](https://www.kernel.org/doc/Documentation/arm64/booting.txt) | The linked document describes assumptions made from the bootloader which are field tested and worthwhile to have for Redox an AArch64. <br/> The intent is to consider most of the document except anything tied to the Linux kernel itself. |
| [Flattened Device Tree](https://elinux.org/Device_Tree_Reference) | FDT binary blobs supplied by the bootloader shall provide the Redox kernel with misc platform \{memory, interrupt, devicemem} maps. Qemu's virt machine platform synthetically creates an FDT blob at a specific address which is very handy. |
## Boot flow elements
The following table lists the boot flow in order.
| Item | Notes |
|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [ARM Trusted Firmware (TF-A)](https://github.com/ARM-software/arm-trusted-firmware) | TF-A is a de-facto standard reference firmware implementation and proven in the field. <br/> TF-A runs post power-on on Armv8-A implementations and eventually hands off to further stages of the boot flow.<br />For qemu's virt machine platform, it is essentially absent but I mean to rely on it heavily for silicon bring up hence mentioning it here. |
| [u-boot](https://www.denx.de/wiki/U-Boot) | u-boot will handle early console access, media access for fetching redox kernel images from non-volatile storage/misc disk subsystems/off the network. <br /> u-boot supports loading EFI applications. If EFI support to AArch64 Redox is added in the future that should essentially work out of the box. <br /> u-boot will load redox and FDT binary blobs into RAM and jump to the redox kernel. |
| Redox early-init stub | For AArch64, the redox kernel will contain an A64 assembly stub that will setup the MMU from scratch. This is akin to the [x86_64 redox bootloader](https://github.com/redox-os/bootloader/blob/master/x86_64/startup-x86_64.asm). <br /> This stub sets up identity maps for MMU initialization, maps the kernel image itself as well as the device memory for the UART console. At present this stub shall be a part of the kernel itself for simplicity. |
| Redox kstart entry | The early init stub hands off here. kstart will then re-init the MMU more comprehensively. |
## Supported devices
The following devices shall be supported. All necessary information specific to these devices will be provided to the redox kernel by the platform specific FDT binary blob.
| Device | Notes |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Generic Interrupt Controller v2](https://developer.arm.com/products/architecture/a-profile/docs/ihi0048/b/arm-generic-interrupt-controller-architecture-version-20-architecture-specification) | The GIC is an Arm-v8A architectural element and is supported by all architecturally compliant processor implementations. GICv2 is supported by qemu's virt machine emulation and most subsequent GIC implementations are backward compatible to GICv2. |
| [Generic Timer](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500d/BGBBIJCB.html) | The Generic Timer Architecture is an Arm-v8A architectural element and is implemented by all compliant processor implementations. It is supported by qemu. |
| [PrimeCell UART PL011](http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf) | The PL011 UART is supported by qemu and most ARM systems. |
## Intended development sequence and status
| Item | Description | Status | Notes |
|--------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|-------------------------------------------------------------------------------|
| Redox AArch64 toolchain | Create an usable redox AArch64 toolchain specification | Done | Using this JSON spec in isolated tests produces valid AArch64 soft float code |
| Stubbed kernel image | Stub out AArch64 kernel support using the existing x86_64 arch code as a template <br /> Modify redox kernel build glue and work iteratively to get a linkable (non-functional) image | Not done yet | |
| Boot flow | Create a self hosted u-boot -> redox kernel workflow <br /> Should obtain the stubbed image from a local TFTP server, load it into RAM and jump to it | Not done yet | |
| GDB Debug flow | Create a debug workflow centered around qemu's GDB stub <br /> This should allow connecting to qemu's GDB stub and debug u-boot/redox stub via a GDB client and single stepping through code | Not done yet | |
| Verify Redox entry | Verify that control reaches the redox kernel from u-boot | Not done yet | |
| AArch64 early init stub | Add support for raw asm code for early AArch64 init in the redox kernel <br /> Verify that this code is located appropriately in the link map and that control reaches this code from u-boot | Not done yet | |
| Basic DTB support | Integrate the [device_tree crate](https://mbr.github.io/device_tree-rs/device_tree/) <br /> Use the crate to access the qemu supplied DTB image and extract the memory map | Not done yet | |
| Basic UART support | Use the device_tree crate to get the UART address from the DTB image and set up the initial console <br /> This is a polling mode only setup | Not done yet | |
| Initial MMU support | Implement initial MMU support in the early init stub <br /> This forces the MMU into a clean state overriding any bootloader specific setup <br /> Create an identity map for MMU init <br /> Create a mapping for the kernel image <br /> Create a mapping for any devices needed at this stage (UART) | Not done yet | |
| kmain entry | Verify that kmain entry works post early MMU init | Not done yet | |
| Basic Redox MMU support | Get Redox to create a final set of mappings for everything <br /> Verify that this works as expected | Not done yet | |
| Basic libc support | Flesh out a basic set of libc calls as required for simple user-land apps | Not done yet | |
| userspace_init entry | Verify user-space entry and /sbin/init invocation | Not done yet | |
| Basic Interrupt controller support | Add a GIC driver <br /> Verify functionality | Not done yet | |
| Basic Timer support | Add a Generic Timer driver <br /> Verify functionality | Not done yet | |
| UART interrupt support | Add support for UART interrupts | Not done yet | |
| Task context switch support | Add context switching support <br /> Verify functionality | Not done yet | |
| Login shell | Iteratively add and verify multi-user login shell support | Not done yet | |
| Publish development branch on github | Work with the community to post work done after employer approval | Not done yet | |
| Break out the Bubbly | Drink copious quantities of alcohol to celebrate | Not done yet | |
| Silicon bring-up | Plan silicon bring-up | Not done yet | |
Generated
+130 -2705
View File
File diff suppressed because it is too large Load Diff
+118 -153
View File
@@ -1,172 +1,137 @@
[workspace]
resolver = "2"
members = [
"audiod",
"config",
"daemon",
"dhcpd",
"init",
"initfs",
"initfs/tools",
"ipcd",
"logd",
"netstack",
"ptyd",
"ramfs",
"randd",
"scheme-utils",
"zerod",
resolver = "3"
members = [".", "rmm"]
"drivers/common",
"drivers/executor",
[package]
name = "kernel"
version = "0.5.12+rb0.3.0"
authors = ["Jeremy Soller <jackpot51@gmail.com>", "vasilito <adminpupkin@gmail.com>"]
build = "build.rs"
edition = "2024"
"drivers/acpid",
"drivers/hwd",
"drivers/pcid",
"drivers/pcid-spawner",
"drivers/rtcd",
"drivers/vboxd",
"drivers/inputd",
"drivers/virtio-core",
[build-dependencies]
cc = "1.0"
toml = "0.8"
"drivers/audio/ac97d",
"drivers/audio/ihdad",
"drivers/audio/sb16d",
[dependencies]
arrayvec = { version = "0.7.4", default-features = false }
bitfield = "0.13.2"
bitflags = "2"
fdt = { git = "https://github.com/repnop/fdt.git", rev = "2fb1409edd1877c714a0aa36b6a7c5351004be54" }
hashbrown = { version = "0.14.3", default-features = false, features = ["ahash", "inline-more"] }
linked_list_allocator = "0.9.0"
redox-path = "0.2.0"
redox_syscall = { path = "../syscall", default-features = false }
rmm = { path = "rmm", default-features = false }
slab = { version = "0.4", default-features = false }
smallvec = { version = "1.15.1", default-features = false }
spin = { version = "0.9.8" }
"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",
[dependencies.object]
version = "0.37.1"
default-features = false
features = ["read_core", "elf"]
"drivers/input/ps2d",
"drivers/input/usbhidd",
[dependencies.rustc-demangle]
version = "0.1.16"
default-features = false
"drivers/net/driver-network",
"drivers/net/e1000d",
"drivers/net/ixgbed",
"drivers/net/rtl8139d",
"drivers/net/rtl8168d",
"drivers/net/virtio-netd",
[lints.clippy]
# Overflows are very, very bad in kernel code as it may provide an attack vector for
# userspace applications, and it is only checked in debug builds
# TODO: address occurrences and then deny
arithmetic_side_effects = "warn"
cast_ptr_alignment = "warn" # TODO: address occurrences and then deny
identity_op = "allow" # Used to allow stuff like 1 << 0 and 1 * 1024 * 1024
if_same_then_else = "allow" # Useful for adding comments about different branches
# Indexing a slice can cause panics and that is something we always want to avoid
# in kernel code. Use .get and return an error instead
# TODO: address occurrences and then deny
indexing_slicing = "warn"
many_single_char_names = "allow" # Useful in the syscall function
module_inception = "allow" # Used for context::context
# Not implementing default is sometimes useful in the case something has significant cost
# to allocate. If you implement default, it can be allocated without evidence using the
# ..Default::default() syntax. Not fun in kernel space
new_without_default = "allow"
not_unsafe_ptr_arg_deref = "deny"
or_fun_call = "allow" # Used to make it nicer to return errors, for example, .ok_or(Error::new(ESRCH))
precedence = "deny"
ptr_cast_constness = "deny"
too_many_arguments = "allow" # This is needed in some cases, like for syscall
# Avoid panicking in the kernel without information about the panic. Use expect
# TODO: address occurrences and then deny
unwrap_used = "warn"
"drivers/redoxerd",
[lints.rust]
static_mut_refs = "warn" # FIXME deny once all occurrences are fixed
# This is usually a serious issue - a missing import of a define where it is interpreted
# as a catch-all variable in a match, for example
unreachable_patterns = "deny"
unused_must_use = "deny" # Ensure that all must_use results are used
"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",
[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies]
raw-cpuid = "10.2.0"
x86 = { version = "0.47.0", default-features = false }
"drivers/usb/xhcid",
"drivers/usb/usbctl",
"drivers/usb/usbhubd",
"drivers/usb/ucsid",
[target.'cfg(any(target_arch = "riscv64", target_arch = "riscv32"))'.dependencies]
sbi-rt = "0.0.3"
"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",
[features]
default = [
"acpi",
#"debugger",
"multi_core",
"serial_debug",
"self_modifying",
"x86_kvm_pv",
#"busy_panic",
#"drop_panic",
#"syscall_debug"
]
# Bootstrap needs it's own profile configuration
exclude = ["bootstrap"]
# Activates some limited code-overwriting optimizations, based on CPU features.
self_modifying = []
# 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"
acpi = []
lpss_debug = []
multi_core = ["acpi"]
profiling = []
#TODO: remove when threading issues are fixed
pti = []
drop_panic = []
busy_panic = []
qemu_debug = []
serial_debug = []
system76_ec_debug = []
x86_kvm_pv = []
[workspace.lints.rust]
missing_docs = "allow" #TODO: set to deny when all public functions are documented
debugger = ["syscall_debug"]
syscall_debug = []
[workspace.lints.clippy]
missing_safety_doc = "warn" #TODO: set to deny when all safety documentation is completed
precedence = "deny"
sys_fdstat = []
[profile.dev]
# Avoids having to define the eh_personality lang item and reduces kernel size
panic = "abort"
[profile.release]
# Avoids having to define the eh_personality lang item and reduces kernel size
panic = "abort"
#lto = true
debug = "full"
# Red Bear OS Phase J: see local/sources/base/Cargo.toml for
# the rationale. Both the kernel and the base workspace need
# the libredox override so that the libredox::error::Error
# type is the same compile-time type as syscall::Error. With
# the local libredox fork at local/sources/libredox/ using
# the local syscall fork at local/sources/syscall/, the
# libredox::error::Error (re-exported from the local syscall)
# and syscall::Error (also the local syscall) are now the
# same type, so `?` conversions in scheme-utils / daemon
# compile cleanly.
[patch.crates-io]
# Red Bear OS Phase I: s2idle / Modern Standby support.
# 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" }
# Red Bear OS Phase J: libredox 0.1.17 has its own vendored
# redox_syscall dep. Without the libredox override here,
# libredox::error::Error is the upstream syscall::error::Error
# (a different compile-time type than the local fork's
# syscall::Error) and the conversion `?` operator in
# scheme-utils / daemon fails with E0277. Override libredox
# to use the local fork at ../libredox/ (which itself uses
# the local syscall fork). Now libredox::error::Error and
# syscall::Error are the same type.
# Local fork dependency rule: every crate with a local fork MUST resolve through it.
libredox = { path = "../libredox" }
# Red Bear OS Phase J (extended): redox-scheme 0.11.x from crates.io
# pins redox_syscall = "0.9.0" exactly, which Cargo refuses to
# satisfy with the local +rb0.3.0 fork (0.9.0+rb0.3.0). Without this
# patch, Cargo pulls crates.io redox-scheme which transitively
# pulls crates.io redox_syscall 0.9.0, leading to two different
# `syscall::Error` types and E0277 errors in scheme-utils / daemon.
# Patch redox-scheme to the local fork at ../redox-scheme/ which
# has its redox_syscall and libredox dep requirements bumped to
# the +rb0.3.0 versions. The local fork is a thin pass-through of
# upstream redox-scheme 0.11.2 source with only the dep versions
# updated — no behavioural changes.
redox-scheme = { path = "../redox-scheme" }
[patch."https://gitlab.redox-os.org/redox-os/relibc.git"]
#redox-ioctl = { path = "../../relibc/source/redox-ioctl" }
redox_syscall = { path = "../syscall" }
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017 Redox OS
Copyright (c) 2017 Jeremy Soller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+52 -105
View File
@@ -1,119 +1,66 @@
TARGET ?= x86_64-unknown-redox
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
.PHONY: all check
SRC_DIR ?= $(CURDIR)
BUILD_DIR ?= $(shell pwd)/target/$(TARGET)/build
DESTDIR ?= ./sysroot
SYSROOT ?= $(shell pwd)/target/$(TARGET)/sysroot
TARGET_DIR = $(BUILD_DIR)/$(TARGET)/$(BUILD_TYPE)
BUILD_FLAGS += --target-dir $(BUILD_DIR)
SOURCE:=$(dir $(realpath $(lastword $(MAKEFILE_LIST))))
BUILD?=$(CURDIR)
export RUST_TARGET_PATH=$(SOURCE)/targets
INITFS_BINS = init logd ramfs randd zerod \
acpid fbbootlogd fbcond hwd inputd lived \
pcid pcid-spawner rtcd vesad
INITFS_DRIVERS_BINS = nvmed virtio-blkd virtio-gpud
BASE_BINS = inputd pcid pcid-spawner redoxerd audiod dhcpd ipcd ptyd netstack
DRIVERS_BINS = e1000d ihdad ihdgd ixgbed rtl8139d rtl8168d \
usbctl usbhidd usbhubd usbscsid virtio-netd xhcid
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
ifeq ($(TARGET),)
ARCH?=$(shell uname -m)
else
ARCH?=$(shell echo "$(TARGET)" | cut -d - -f1)
endif
ifeq ($(TARGET),aarch64-unknown-redox)
ifeq ($(BOARD),raspi3b)
INITFS_BINS += bcm2835-sdhcid
endif
ifeq ($(ARCH),riscv64gc)
override ARCH:=riscv64
GNU_TARGET=riscv64-unknown-redox
else ifeq ($(ARCH),i686)
override ARCH:=i586
GNU_TARGET=i686-unknown-redox
else
GNU_TARGET=$(ARCH)-unknown-redox
endif
INITFS_CARGO_ARGS = $(foreach bin,$(INITFS_BINS),-p $(bin))
INITFS_DRIVERS_CARGO_ARGS = $(foreach bin,$(INITFS_DRIVERS_BINS),-p $(bin))
BASE_CARGO_ARGS = $(foreach bin,$(BASE_BINS),-p $(bin))
DRIVERS_CARGO_ARGS = $(foreach bin,$(DRIVERS_BINS),-p $(bin))
.PHONY: all base install install-base test
all: $(BUILD)/kernel $(BUILD)/kernel.sym
all: base
install: install-base
LD_SCRIPT=$(SOURCE)/linkers/$(ARCH).ld
LOCKFILE=$(SOURCE)/Cargo.lock
MANIFEST=$(SOURCE)/Cargo.toml
TARGET_SPEC=$(RUST_TARGET_PATH)/$(ARCH)-unknown-kernel.json
clean:
rm -rf $(SRC_DIR)/target $(SRC_DIR)/sysroot $(SYSROOT) $(TARGET_DIR)
KERNEL_CARGO_FEATURES?=
# test if booting
test: all
$(MAKE) install
redoxer exec --folder ./sysroot/:/ true
$(BUILD)/kernel.all: $(LD_SCRIPT) $(LOCKFILE) $(MANIFEST) $(TARGET_SPEC) $(shell find $(SOURCE) -name "*.rs" -type f)
cargo rustc \
--bin kernel \
--manifest-path "$(MANIFEST)" \
--target "$(TARGET_SPEC)" \
--release \
-Z build-std=core,alloc -Zbuild-std-features=compiler-builtins-mem -Z json-target-spec \
--features=$(KERNEL_CARGO_FEATURES) \
-- \
-C link-arg=-T -Clink-arg="$(LD_SCRIPT)" \
-C link-arg=-z -Clink-arg=max-page-size=0x1000 \
--emit link="$(BUILD)/kernel.all"
# test with interactive gui
test-gui: all
$(MAKE) install
redoxer exec --gui --folder ./sysroot/:/ ion
$(BUILD)/kernel.sym: $(BUILD)/kernel.all
$(GNU_TARGET)-objcopy \
--only-keep-debug \
"$(BUILD)/kernel.all" \
"$(BUILD)/kernel.sym"
# -----------------------------------------------------------------------------
# base
# -----------------------------------------------------------------------------
$(SYSROOT)/bin/redoxfs:
REDOXER_SYSROOT=$(SYSROOT) redoxer pkg redoxfs
$(BUILD)/kernel: $(BUILD)/kernel.all
$(GNU_TARGET)-objcopy \
--strip-debug \
"$(BUILD)/kernel.all" \
"$(BUILD)/kernel"
base:
@mkdir -pv "$(BUILD_DIR)"
# Build daemons and drivers
CARGO_PROFILE_RELEASE_OPT_LEVEL=s CARGO_PROFILE_RELEASE_PANIC=abort \
$(CARGO) build $(BUILD_FLAGS) \
--manifest-path "$(SRC_DIR)/Cargo.toml" \
$(BASE_CARGO_ARGS) $(DRIVERS_CARGO_ARGS)
# 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)"
KERNEL_CHECK_FEATURES?=
install-base: base $(SYSROOT)/bin/redoxfs
@mkdir -pv "$(DESTDIR)/usr/bin" "$(DESTDIR)/usr/lib/drivers"
@mkdir -pv "$(DESTDIR)/usr/lib/init.d/" "$(DESTDIR)/usr/lib/pcid.d"
# Distribute binaries
@for bin in $(BASE_BINS); do \
cp -v "$(TARGET_DIR)/$$bin" "$(DESTDIR)/usr/bin"; \
done
@for bin in $(DRIVERS_BINS); do \
cp -v "$(TARGET_DIR)/$$bin" "$(DESTDIR)/usr/lib/drivers"; \
done
# Copy configurations
@cp -v "$(SRC_DIR)/init.d"/* "$(DESTDIR)/usr/lib/init.d/"
@find "$(SRC_DIR)/drivers" -maxdepth 3 -type f -name 'config.toml' | while read -r conf; do \
driver=$$(basename "$$(dirname "$$conf")"); \
cp -v "$$conf" "$(DESTDIR)/usr/lib/pcid.d/$$driver.toml"; \
done
rm -rf "$(BUILD_DIR)/initfs"
# Distribute initfs binaries
@mkdir -pv "$(BUILD_DIR)/initfs/bin" "$(BUILD_DIR)/initfs/lib/drivers"
for bin in $(INITFS_BINS); do \
cp -v "$(TARGET_DIR)/$$bin" "$(BUILD_DIR)/initfs/bin"; \
done
for bin in $(INITFS_DRIVERS_BINS); do \
cp -v "$(TARGET_DIR)/$$bin" "$(BUILD_DIR)/initfs/lib/drivers"; \
done
cp "$(SYSROOT)/bin/redoxfs" "$(BUILD_DIR)/initfs/bin"
# Copy initfs config files
@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/"
cp "$(SRC_DIR)/drivers/initfs.toml" "$(BUILD_DIR)/initfs/lib/pcid.d/initfs.toml"
# Build initfs
$(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"
# Distribute initfs
@mkdir -pv "$(DESTDIR)/usr/lib/boot"
cp -v "$(BUILD_DIR)/initfs.img" "$(DESTDIR)/usr/lib/boot/initfs"
check:
cargo check \
--bin kernel \
--manifest-path "$(MANIFEST)" \
--target "$(TARGET_SPEC)" \
-Z build-std=core,alloc -Zbuild-std-features=compiler-builtins-mem -Z json-target-spec \
--features=$(KERNEL_CHECK_FEATURES)
+65 -27
View File
@@ -1,43 +1,81 @@
# Base
# Kernel
Repository containing various system daemons, that are considered fundamental for the OS.
Redox OS Microkernel
You can see what each component does in the following list:
[![docs](https://img.shields.io/badge/docs-master-blue.svg)](https://docs.rs/redox_syscall/latest/syscall/)
[![SLOCs counter](https://tokei.rs/b1/github/redox-os/kernel?category=code)](https://github.com/XAMPPRocky/tokei)
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
- audiod : Daemon used to process the sound drivers audio
- 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
## Requirements
* [`nasm`](https://nasm.us/) needs to be available on the PATH at build time.
## Building The Documentation
Use this command:
```sh
cargo doc --open --target x86_64-unknown-none
```
## Debugging
### QEMU
Running [QEMU](https://www.qemu.org) with the `-s` flag will set up QEMU to listen on port `1234` for a GDB client to connect to it. To debug the redox kernel run.
```sh
make qemu gdb=yes
```
This will start a virtual machine with and listen on port `1234` for a GDB or LLDB client.
### GDB
If you are going to use [GDB](https://www.gnu.org/software/gdb/), run these commands to load debug symbols and connect to your running kernel:
```
(gdb) symbol-file build/kernel.sym
(gdb) target remote localhost:1234
```
### LLDB
If you are going to use [LLDB](https://lldb.llvm.org/), run these commands to start debugging:
```
(lldb) target create -s build/kernel.sym build/kernel
(lldb) gdb-remote localhost:1234
```
After connecting to your kernel you can set some interesting breakpoints and `continue`
the process. See your debuggers man page for more information on useful commands to run.
## Notes
- Always use `foo.get(n)` instead of `foo[n]` and try to cover for the possibility of `Option::None`. Doing the regular way may work fine for applications, but never in the kernel. No possible panics should ever exist in kernel space, because then the whole OS would just stop working.
- If you receive a kernel panic in QEMU, use `pkill qemu-system` to kill the frozen QEMU process.
## How To Contribute
To learn how to contribute you need to read the following document:
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)
If you want to contribute to drivers read its [README](drivers/README.md)
## Development
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.
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
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.
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.
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:
- `./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
This is necessary because they only work with cross-compilation to a Redox virtual machine, but you can do some testing from Linux.
You can also use `make install` to inspect the content on `./sysroot`, or `make test-gui` to test booting with orbital interactively.
## 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
}
-560
View File
@@ -1,560 +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_with_filter(
cap_fd.as_raw_fd(),
reference,
flags,
fcntl_flags as usize,
ctx.uid,
ctx.gid,
)?;
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_with_filter(cap_fd.as_raw_fd(), reference, flags, ctx.uid, ctx.gid)?;
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,
);
+100
View File
@@ -0,0 +1,100 @@
#![allow(clippy::unwrap_used)] // the build script can panic
use std::{env, path::Path, process::Command};
use toml::Table;
fn parse_kconfig(arch: &str) -> Option<()> {
println!("cargo:rerun-if-changed=config.toml");
assert!(Path::new("config.toml.example").try_exists().unwrap());
if !Path::new("config.toml").try_exists().unwrap() {
std::fs::copy("config.toml.example", "config.toml").unwrap();
}
let config_str = std::fs::read_to_string("config.toml").unwrap();
let root: Table = toml::from_str(&config_str).unwrap();
let altfeatures = root
.get("arch")?
.as_table()
.unwrap()
.get(arch)?
.as_table()
.unwrap()
.get("features")?
.as_table()
.unwrap();
#[expect(clippy::format_collect)] // TODO: remove once version is bumped
let features_list = altfeatures
.keys()
.map(|feat| format!(", {feat:?}"))
.collect::<String>();
println!("cargo::rustc-check-cfg=cfg(cpu_feature_always, values(\"\"{features_list}))");
println!("cargo::rustc-check-cfg=cfg(cpu_feature_auto, values(\"\"{features_list}))");
println!("cargo::rustc-check-cfg=cfg(cpu_feature_never, values(\"\"{features_list}))");
let self_modifying = env::var("CARGO_FEATURE_SELF_MODIFYING").is_ok();
for (name, value) in altfeatures {
let mut choice = value.as_str().unwrap();
assert!(matches!(choice, "always" | "never" | "auto"));
if !self_modifying && choice == "auto" {
choice = "never";
}
println!("cargo:rustc-cfg=cpu_feature_{choice}=\"{name}\"");
}
Some(())
}
fn main() {
println!("cargo::rustc-env=TARGET={}", env::var("TARGET").unwrap());
println!("cargo::rustc-check-cfg=cfg(dtb)");
let out_dir = env::var("OUT_DIR").unwrap();
let arch_str = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
match &*arch_str {
"aarch64" => {
println!("cargo::rustc-cfg=dtb");
}
"x86" => {
println!("cargo::rerun-if-changed=src/asm/x86/trampoline.asm");
let status = Command::new("nasm")
.arg("-f")
.arg("bin")
.arg("-o")
.arg(format!("{}/trampoline", out_dir))
.arg("src/asm/x86/trampoline.asm")
.status()
.expect("failed to run nasm");
if !status.success() {
panic!("nasm failed with exit status {}", status);
}
}
"x86_64" => {
println!("cargo::rerun-if-changed=src/asm/x86_64/trampoline.asm");
let status = Command::new("nasm")
.arg("-f")
.arg("bin")
.arg("-o")
.arg(format!("{}/trampoline", out_dir))
.arg("src/asm/x86_64/trampoline.asm")
.status()
.expect("failed to run nasm");
if !status.success() {
panic!("nasm failed with exit status {}", status);
}
}
"riscv64" => {
println!("cargo::rustc-cfg=dtb");
}
_ => (),
}
let _ = parse_kconfig(&arch_str);
}
-113
View File
@@ -1,113 +0,0 @@
#!/bin/bash
RED='\033[1;38;5;196m'
GREEN='\033[1;38;5;46m'
NC='\033[0m'
show_help() {
echo "Usage: $(basename "$0") [OPTIONS]"
echo ""
echo "Description:"
echo " Wrapper for redoxer to run checks or tests on Redox OS targets."
echo ""
echo "Options:"
echo " --test Run 'cargo test' instead of 'cargo check'"
echo " --all-target Run the command on all supported Redox architectures"
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 " --help Show this help message"
echo ""
echo "Supported Targets:"
for t in "${SUPPORTED_TARGETS[@]}"; do
echo " - $t"
done
echo ""
echo "Environment:"
echo " TARGET Sets the default target (overridden by --target)"
}
if ! command -v redoxer &> /dev/null; then
echo "Error: 'redoxer' CLI not found."
echo "Please install it: cargo install redoxer"
exit 1
fi
SUPPORTED_TARGETS=(
"x86_64-unknown-redox"
"i586-unknown-redox"
"aarch64-unknown-redox"
"riscv64gc-unknown-redox"
)
CURRENT_TARGET="${TARGET:-x86_64-unknown-redox}"
CHECK_ALL=false
CMD_ACTION="all"
while [[ $# -gt 0 ]]; do
case "$1" in
--all-target)
CHECK_ALL=true
;;
--test)
CMD_ACTION="test"
;;
--target=*)
CURRENT_TARGET="${1#*=}"
;;
--arch=*)
CURRENT_TARGET="${1#*=}-unknown-redox"
;;
--help)
show_help
exit 0
;;
*)
echo -e "${RED}Error: Unknown option '$1'${NC}"
show_help
exit 1
;;
esac
shift
done
run_redoxer() {
export TARGET=$1
redoxer toolchain || { echo -e "${RED}Fail: redoxer toolchain for: $target.${NC}" && exit 1; }
echo "----------------------------------------"
echo "Running make $CMD_ACTION for: $TARGET"
if make "$CMD_ACTION"; then
return 0
else
echo -e "${RED}Fail: $CMD_ACTION $TARGET failed.${NC}"
return 1
fi
}
if [ "$CHECK_ALL" = true ]; then
echo "Running $CMD_ACTION for all supported Redox targets..."
has_error=false
for target in "${SUPPORTED_TARGETS[@]}"; do
if ! run_redoxer "$target"; then
has_error=true
fi
done
echo "----------------------------------------"
if [ "$has_error" = true ]; then
echo -e "${RED}Summary: One or more targets failed.${NC}"
exit 1
else
echo -e "${GREEN}Summary: All targets passed!${NC}"
exit 0
fi
else
if run_redoxer "$CURRENT_TARGET"; then
echo -e "${GREEN}Success: $CMD_ACTION $CURRENT_TARGET passed.${NC}"
exit 0
else
exit 1
fi
fi
Executable
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
export RUST_TARGET_PATH="${PWD}/targets"
export RUSTFLAGS="-C debuginfo=2"
cargo clippy --lib --release --target x86_64-unknown-none "$@"
+7
View File
@@ -0,0 +1,7 @@
[arch.x86_64.features]
smap = "auto"
fsgsbase = "auto"
xsave = "auto"
xsaveopt = "auto"
# vim: ft=toml
-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))
}
}
-10
View File
@@ -1,10 +0,0 @@
[package]
name = "dhcpd"
version = "0.0.0"
edition = "2024"
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
[dependencies]
[lints]
workspace = true
-19
View File
@@ -1,19 +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],
}
-497
View File
@@ -1,497 +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;
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: {} Current IP: {}",
current_mac.to_string(),
current_ip.trim()
);
}
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 udp"
);
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 discover = Dhcp {
op: 1,
htype: 1,
hlen: 6,
hops: 0,
tid,
secs: 0,
flags: 0x8000u16.to_be(),
ciaddr: [0, 0, 0, 0],
yiaddr: [0, 0, 0, 0],
siaddr: [0, 0, 0, 0],
giaddr: [0, 0, 0, 0],
chaddr: [
current_mac.bytes[0],
current_mac.bytes[1],
current_mac.bytes[2],
current_mac.bytes[3],
current_mac.bytes[4],
current_mac.bytes[5],
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
],
sname: [0; 64],
file: [0; 128],
magic: 0x63825363u32.to_be(),
options: [0; 308],
};
for (s, d) in [
// DHCP Message Type (Discover)
53, 1, 1, // End
255,
]
.iter()
.zip(discover.options.iter_mut())
{
*d = *s;
}
let discover_data = unsafe {
std::slice::from_raw_parts(
(&discover as *const Dhcp) as *const u8,
std::mem::size_of::<Dhcp>(),
)
};
let _sent = try_fmt!(socket.send(discover_data), "failed to send discover");
if verbose {
println!("DHCP: Sent Discover");
}
}
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: {:?}, Server IP: {:?}",
offer.yiaddr, offer.siaddr
);
}
let mut subnet_option = None;
let mut router_option = None;
let mut dns_option = None;
let mut server_id_option = None;
{
let mut options = offer.options.iter();
while let Some(option) = options.next() {
match *option {
0 => (),
255 => break,
_ => {
if let Some(len) = options.next() {
if *len as usize <= options.as_slice().len() {
let data = &options.as_slice()[..*len as usize];
for _data_i in 0..*len {
options.next();
}
match *option {
1 => {
if verbose {
println!("DHCP: Subnet Mask: {data:?}");
}
if data.len() == 4 && subnet_option.is_none() {
subnet_option = Some(Vec::from(data));
}
}
3 => {
if verbose {
println!("DHCP: Router: {data:?}");
}
if data.len() == 4 && router_option.is_none() {
router_option = Some(Vec::from(data));
}
}
6 => {
if verbose {
println!("DHCP: Domain Name Server: {data:?}");
}
if data.len() == 4 && dns_option.is_none() {
dns_option = Some(Vec::from(data));
}
}
51 => {
if verbose {
println!("DHCP: Lease Time: {data:?}");
}
}
53 => {
if verbose {
println!("DHCP: Message Type: {data:?}");
}
}
54 => {
if verbose {
println!("DHCP: Server ID: {data:?}");
}
if data.len() == 4 {
// Store the server ID
server_id_option =
Some([data[0], data[1], data[2], data[3]]);
}
}
_ => {
if verbose {
println!("DHCP: {option}: {data:?}");
}
}
}
}
}
}
}
}
let mask_len = if let Some(subnet) = subnet_option {
let mut subnet: u32 = (subnet[0] as u32) << 24
| (subnet[1] as u32) << 16
| (subnet[2] as u32) << 8
| subnet[3] as u32;
subnet = !subnet;
subnet.leading_zeros()
} else {
0
};
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"
);
if verbose {
let new_ip = try_fmt!(get_iface_cfg_value(iface, "addr/list"), "failed to get ip");
println!("DHCP: New IP: {}", new_ip.trim());
}
if let Some(router) = router_option {
let default_route = format!(
"default via {}.{}.{}.{}",
router[0], router[1], router[2], router[3]
);
try_fmt!(
set_cfg_value("route/add", &default_route),
"failed to set default route"
);
if verbose {
let new_router = try_fmt!(get_cfg_value("route/list"), "failed to get ip router");
println!("DHCP: New Router: {}", new_router.trim());
}
}
if let Some(mut dns) = dns_option {
if dns[0] == 127 {
let quad9 = [9, 9, 9, 9].to_vec();
if verbose {
println!(
"DHCP: Received sarcastic DNS suggestion {}.{}.{}.{}, using {}.{}.{}.{} instead",
dns[0], dns[1], dns[2], dns[3], quad9[0], quad9[1], quad9[2], quad9[3]
);
}
dns = quad9;
}
let nameserver = format!("{}.{}.{}.{}", dns[0], dns[1], dns[2], dns[3]);
try_fmt!(
set_cfg_value("resolv/nameserver", &nameserver),
"failed to set name server"
);
if verbose {
let new_dns = try_fmt!(get_cfg_value("resolv/nameserver"), "failed to get dns");
println!("DHCP: New DNS: {}", new_dns.trim());
}
}
}
{
let mut request = Dhcp {
op: 1,
htype: 1,
hlen: 6,
hops: 0,
tid,
secs: 0,
flags: 0,
ciaddr: [0; 4],
yiaddr: [0; 4],
siaddr: [0; 4],
giaddr: [0; 4],
chaddr: [
current_mac.bytes[0],
current_mac.bytes[1],
current_mac.bytes[2],
current_mac.bytes[3],
current_mac.bytes[4],
current_mac.bytes[5],
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
],
sname: [0; 64],
file: [0; 128],
magic: 0x63825363u32.to_be(),
options: [0; 308],
};
// If the server_id_option was None, use "0.0.0.0"
let server_id = server_id_option.unwrap_or([0, 0, 0, 0]);
for (s, d) in [
// DHCP Message Type (Request)
53,
1,
3,
// Requested IP Address
50,
4,
offer.yiaddr[0],
offer.yiaddr[1],
offer.yiaddr[2],
offer.yiaddr[3],
// Server Identifier - use Option 54 from the Offer
54,
4,
server_id[0],
server_id[1],
server_id[2],
server_id[3],
// End
255,
]
.iter()
.zip(request.options.iter_mut())
{
*d = *s;
}
let request_data = unsafe {
std::slice::from_raw_parts(
(&request as *const Dhcp) as *const u8,
std::mem::size_of::<Dhcp>(),
)
};
let _sent = try_fmt!(socket.send(request_data), "failed to send request");
if verbose {
println!("DHCP: Sent Request");
}
}
{
let mut ack_data = [0; 65536];
try_fmt!(socket.recv(&mut ack_data), "failed to receive ack");
let ack = unsafe { &*(ack_data.as_ptr() as *const Dhcp) };
if verbose {
println!(
"DHCP: Ack IP: {:?}, Server IP: {:?}",
ack.yiaddr, ack.siaddr
);
}
}
Ok(())
}
fn main() {
let mut verbose = false;
let iface = "eth0";
//TODO: parse iface from the args
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!(empty_mac, MacAddr::from_str("01:23-45-67-89-ab"));
assert_eq!(empty_mac, MacAddr::from_str("01-23-45-67-89-ag"));
assert_eq!(empty_mac, MacAddr::from_str("01.23.45.67.89.ab"));
assert_eq!(empty_mac, MacAddr::from_str("01234-23-45-67-89-ab"));
assert_eq!(empty_mac, MacAddr::from_str("01--23-45-67-89-ab"));
assert_eq!(empty_mac, MacAddr::from_str("12"));
assert_eq!(empty_mac, MacAddr::from_str("0:0:0:0:0:0"));
assert_eq!(mac, MacAddr::from_str(&mac.to_string()));
assert_eq!(empty_mac, MacAddr::from_str(&empty_mac.to_string()));
}
}
-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"));
}
}
-256
View File
@@ -1,256 +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> {
warn!("Got u16 EC read from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
}
fn read_u32(&self, _region: &OpRegion, _offset: usize) -> Result<u32, acpi::aml::AmlError> {
warn!("Got u32 EC read from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
}
fn read_u64(&self, _region: &OpRegion, _offset: usize) -> Result<u64, acpi::aml::AmlError> {
warn!("Got u64 EC read from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
}
fn write_u16(
&self,
_region: &OpRegion,
_offset: usize,
_value: u16,
) -> Result<(), acpi::aml::AmlError> {
warn!("Got u16 EC write from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
}
fn write_u32(
&self,
_region: &OpRegion,
_offset: usize,
_value: u32,
) -> Result<(), acpi::aml::AmlError> {
warn!("Got u32 EC write from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
}
fn write_u64(
&self,
_region: &OpRegion,
_offset: usize,
_value: u64,
) -> Result<(), acpi::aml::AmlError> {
warn!("Got u64 EC write from AML!");
Err(acpi::aml::AmlError::NoHandlerForRegionAccess(
RegionSpace::EmbeddedControl,
)) // TODO proper error type
}
}
-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);
}
-778
View File
@@ -1,778 +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, 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>,
}
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,
/// `/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, 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 => true,
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),
// 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,
}
}
/// 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,
["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::Processor | HandleKind::DmiDir | HandleKind::Thermal | HandleKind::Power | 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 adapters = self.ctx.power_adapters();
for (idx, adapter) in adapters.iter().enumerate().skip(opaque_offset as usize) {
buf.entry(DirEntry {
inode: 0,
next_opaque_id: idx as u64 + 1,
name: adapter.as_str(),
kind: DirentKind::Directory,
})?;
}
}
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);
}
}
-134
View File
@@ -1,134 +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) -> ! {
unimplemented!()
}
-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
-16
View File
@@ -1,16 +0,0 @@
#![allow(dead_code)]
pub mod cmdbuff;
pub mod common;
pub mod device;
pub mod node;
pub mod stream;
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.");
}
}
-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);
}
}
-118
View File
@@ -1,118 +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) -> ! {
unimplemented!()
}
-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
-265
View File
@@ -1,265 +0,0 @@
use std::mem::{self, size_of, MaybeUninit};
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::sync::LazyLock;
use libredox::call::MmapArgs;
use libredox::{error::Result, flag, Fd};
use syscall::PAGE_SIZE;
use crate::{memory_root_fd, MemoryType, VirtaddrTranslationHandle};
/// Defines the platform-specific memory type for DMA operations
///
/// - On x86 systems, DMA uses Write-back memory ([`MemoryType::Writeback`])
/// - On aarch64 systems, DMA uses uncacheable memory ([`MemoryType::Uncacheable`])
const DMA_MEMTY: MemoryType = {
if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
// x86 ensures cache coherence with DMA memory
MemoryType::Writeback
} else if cfg!(target_arch = "aarch64") {
// aarch64 currently must map DMA memory without caching to ensure coherence
MemoryType::Uncacheable
} else if cfg!(target_arch = "riscv64") {
// FIXME check this out more
MemoryType::Uncacheable
} else {
panic!("invalid arch")
}
};
/// Returns a file descriptor for zeroized physically-contiguous DMA memory.
///
/// # Returns
///
/// A [Result] containing:
/// - '[Ok]' - A [Fd] (file descriptor) to zeroized, physically continuous DMA usable memory
/// - '[Err]' - The error returned by the provider of the /scheme/memory/zeroed scheme.
///
/// # Errors
///
/// This function can return an error in the following case:
///
/// - The request for the physical memory fails.
pub(crate) fn phys_contiguous_fd() -> Result<Fd> {
memory_root_fd().openat(
&format!("zeroed@{DMA_MEMTY}?phys_contiguous"),
flag::O_CLOEXEC,
0,
)
}
/// Allocates a chunk of physical memory for DMA, and then maps it to virtual memory.
///
/// # Arguments
/// 'length: [usize]' - The length of the memory region. Must be a multiple of [`PAGE_SIZE`]
///
/// # Returns
///
/// This function returns a [Result] containing the following:
/// - A '[Ok]([usize], *[mut] ())' containing a Tuple of the physical address of the region, and a raw pointer to that region in virtual memory.
/// - An '[Err]' - containing the error for the operation.
///
/// # Errors
///
/// This function asserts if:
/// - length is not a multiple of [`PAGE_SIZE`]
///
/// This function returns an error if:
/// - A file descriptor to physically contiguous memory of type [`DMA_MEMTY`] could not be acquired
/// - A virtual mapping for the physically contiguous memory could not be created
/// - The virtual address returned by the memory manager was invalid.
fn alloc_and_map(length: usize, handle: &VirtaddrTranslationHandle) -> Result<(usize, *mut ())> {
assert_eq!(length % PAGE_SIZE, 0);
unsafe {
let fd = phys_contiguous_fd()?;
let virt = libredox::call::mmap(MmapArgs {
fd: fd.raw(),
offset: 0, // ignored
addr: core::ptr::null_mut(), // ignored
length,
flags: flag::MAP_PRIVATE,
prot: flag::PROT_READ | flag::PROT_WRITE,
})?;
let phys = handle.translate(virt as usize)?;
for i in 1..length.div_ceil(PAGE_SIZE) {
debug_assert_eq!(
handle.translate(virt as usize + i * PAGE_SIZE),
Ok(phys + i * PAGE_SIZE),
"NOT CONTIGUOUS"
);
}
Ok((phys, virt as *mut ()))
}
}
/// A safe accessor for DMA memory.
pub struct Dma<T: ?Sized> {
/// The physical address of the memory
phys: usize,
/// The page-aligned length of the memory. Will be a multiple of [`PAGE_SIZE`]
aligned_len: usize,
/// The pointer to the Dma memory in the virtual address space.
virt: *mut T,
}
impl<T> Dma<T> {
/// [Dma] constructor that allocates and initializes a region of DMA memory with the page-aligned
/// size and initial value of some T
///
/// # Arguments
/// 'value: T' - The initial value to write to the allocated region
///
/// # Returns
///
/// This function returns a [Result] containing the following:
///
/// - A '[Ok] (`[Dma]<T>`)' containing the initialized region
/// - An '[Err]' containing an error.
pub fn new(value: T) -> Result<Self> {
unsafe {
let mut zeroed = Self::zeroed()?;
zeroed.as_mut_ptr().write(value);
Ok(zeroed.assume_init())
}
}
/// [Dma] constructor that allocates and zeroizes a memory region of the page-aligned size of T
///
/// # Returns
///
/// This function returns a [Result] containing the following:
///
/// - A '[Ok] (`[Dma]<[MaybeUninit]<T>>`)' containing the allocated and zeroized memory
/// - An '[Err]' containing an error.
pub fn zeroed() -> Result<Dma<MaybeUninit<T>>> {
let aligned_len = size_of::<T>().next_multiple_of(PAGE_SIZE);
let (phys, virt) = alloc_and_map(aligned_len, &*VIRTTOPHYS_HANDLE)?;
Ok(Dma {
phys,
virt: virt.cast(),
aligned_len,
})
}
}
impl<T> Dma<MaybeUninit<T>> {
/// Assumes that possibly uninitialized DMA memory has been initialized, and returns a new
/// instance of an object of type `[Dma]<T>`.
///
/// # Returns
/// - `[Dma]<T>` - The original structure without the [`MaybeUninit`] wrapper around its contents.
///
/// # Notes
/// - This is unsafe because it assumes that the memory stored within the `[Dma]<T>` is a valid
/// instance of T. If it isn't (for example -- if it was initialized with [`Dma::zeroed`]),
/// then the underlying memory may not contain the expected T structure.
pub unsafe fn assume_init(self) -> Dma<T> {
let Dma {
phys,
aligned_len,
virt,
} = self;
mem::forget(self);
Dma {
phys,
aligned_len,
virt: virt.cast(),
}
}
}
impl<T: ?Sized> Dma<T> {
/// Returns the physical address of the physical memory that this [Dma] structure references.
///
/// # Returns
/// [usize] - The physical address of the memory.
pub fn physical(&self) -> usize {
self.phys
}
}
// TODO: there should exist a "context" struct that drivers create at start, which would be passed
// to the respective functions
static VIRTTOPHYS_HANDLE: LazyLock<VirtaddrTranslationHandle> = LazyLock::new(|| {
VirtaddrTranslationHandle::new().expect("failed to acquire virttophys translation handle")
});
impl<T> Dma<[T]> {
/// Returns a [Dma] object containing a zeroized slice of T with a given count.
///
/// # Arguments
///
/// - 'count: [usize]' - The number of elements of type T in the allocated slice.
pub fn zeroed_slice(count: usize) -> Result<Dma<[MaybeUninit<T>]>> {
let aligned_len = count
.checked_mul(size_of::<T>())
.unwrap()
.next_multiple_of(PAGE_SIZE);
let (phys, virt) = alloc_and_map(aligned_len, &*VIRTTOPHYS_HANDLE)?;
Ok(Dma {
phys,
aligned_len,
virt: ptr::slice_from_raw_parts_mut(virt.cast(), count),
})
}
/// Casts the slice from type T to type U.
///
/// # Returns
/// '`[DMA]<U>`' - A cast handle to the Dma memory.
pub unsafe fn cast_slice<U>(self) -> Dma<[U]> {
let Dma {
phys,
virt,
aligned_len,
} = self;
core::mem::forget(self);
Dma {
phys,
virt: virt as *mut [U],
aligned_len,
}
}
}
impl<T> Dma<[MaybeUninit<T>]> {
/// See [`Dma<MaybeUninit<T>>::assume_init`]
pub unsafe fn assume_init(self) -> Dma<[T]> {
let &Dma {
phys,
aligned_len,
virt,
} = &self;
mem::forget(self);
Dma {
phys,
aligned_len,
virt: virt as *mut [T],
}
}
}
impl<T: ?Sized> Deref for Dma<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.virt }
}
}
impl<T: ?Sized> DerefMut for Dma<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.virt }
}
}
impl<T: ?Sized> Drop for Dma<T> {
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(self.virt);
let _ = libredox::call::munmap(self.virt as *mut (), self.aligned_len);
}
}
}
-95
View File
@@ -1,95 +0,0 @@
use core::{
cmp::PartialEq,
ops::{BitAnd, BitOr, Not},
};
mod mmio;
mod mmio_ptr;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod pio;
pub use mmio::*;
pub use mmio_ptr::*;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use pio::*;
/// IO abstraction
pub trait Io {
/// Value type for IO, usually some unsigned number
type Value: Copy
+ PartialEq
+ BitAnd<Output = Self::Value>
+ BitOr<Output = Self::Value>
+ Not<Output = Self::Value>;
/// Read the underlying valu2e
fn read(&self) -> Self::Value;
/// Write the underlying value
fn write(&mut self, value: Self::Value);
/// Check whether the underlying value contains bit flags
#[inline(always)]
fn readf(&self, flags: Self::Value) -> bool {
(self.read() & flags) as Self::Value == flags
}
/// Enable or disable specific bit flags
#[inline(always)]
fn writef(&mut self, flags: Self::Value, value: bool) {
let tmp: Self::Value = match value {
true => self.read() | flags,
false => self.read() & !flags,
};
self.write(tmp);
}
}
/// Read-only IO
#[repr(transparent)]
pub struct ReadOnly<I> {
inner: I,
}
impl<I: Io> ReadOnly<I> {
/// Wraps IO
pub const fn new(inner: I) -> ReadOnly<I> {
ReadOnly { inner }
}
}
impl<I: Io> ReadOnly<I> {
/// Calls [`Io::read`]
#[inline(always)]
pub fn read(&self) -> I::Value {
self.inner.read()
}
/// Calls [`Io::readf`]
#[inline(always)]
pub fn readf(&self, flags: I::Value) -> bool {
self.inner.readf(flags)
}
}
#[repr(transparent)]
/// Write-only IO
pub struct WriteOnly<I> {
inner: I,
}
impl<I: Io> WriteOnly<I> {
/// Wraps IO
pub const fn new(inner: I) -> WriteOnly<I> {
WriteOnly { inner }
}
}
impl<I: Io> WriteOnly<I> {
/// Calls [`Io::write`]
#[inline(always)]
pub fn write(&mut self, value: I::Value) {
self.inner.write(value)
}
// writef requires read which is not valid when write-only
}
-173
View File
@@ -1,173 +0,0 @@
use core::{mem::MaybeUninit, ptr};
use super::Io;
/// MMIO abstraction
#[repr(C, packed)]
pub struct Mmio<T> {
value: MaybeUninit<T>,
}
impl<T> Mmio<T> {
/// Creates a zeroed instance
pub unsafe fn zeroed() -> Self {
Self {
value: MaybeUninit::zeroed(),
}
}
/// Creates an unitialized instance
pub unsafe fn uninit() -> Self {
Self {
value: MaybeUninit::uninit(),
}
}
/// Creates a new instance
pub const fn new(value: T) -> Self {
Self {
value: MaybeUninit::new(value),
}
}
}
// Generic implementation (WARNING: requires aligned pointers!)
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
impl<T> Io for Mmio<T>
where
T: Copy
+ PartialEq
+ core::ops::BitAnd<Output = T>
+ core::ops::BitOr<Output = T>
+ core::ops::Not<Output = T>,
{
type Value = T;
fn read(&self) -> T {
unsafe { ptr::read_volatile(ptr::addr_of!(self.value).cast::<T>()) }
}
fn write(&mut self, value: T) {
unsafe { ptr::write_volatile(ptr::addr_of_mut!(self.value).cast::<T>(), value) };
}
}
// x86 u8 implementation
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl Io for Mmio<u8> {
type Value = u8;
fn read(&self) -> Self::Value {
unsafe {
let value: Self::Value;
let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::<Self::Value>();
core::arch::asm!(
"mov {}, [{}]",
out(reg_byte) value,
in(reg) ptr
);
value
}
}
fn write(&mut self, value: Self::Value) {
unsafe {
let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::<Self::Value>();
core::arch::asm!(
"mov [{}], {}",
in(reg) ptr,
in(reg_byte) value,
);
}
}
}
// x86 u16 implementation
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl Io for Mmio<u16> {
type Value = u16;
fn read(&self) -> Self::Value {
unsafe {
let value: Self::Value;
let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::<Self::Value>();
core::arch::asm!(
"mov {:x}, [{}]",
out(reg) value,
in(reg) ptr
);
value
}
}
fn write(&mut self, value: Self::Value) {
unsafe {
let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::<Self::Value>();
core::arch::asm!(
"mov [{}], {:x}",
in(reg) ptr,
in(reg) value,
);
}
}
}
// x86 u32 implementation
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl Io for Mmio<u32> {
type Value = u32;
fn read(&self) -> Self::Value {
unsafe {
let value: Self::Value;
let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::<Self::Value>();
core::arch::asm!(
"mov {:e}, [{}]",
out(reg) value,
in(reg) ptr
);
value
}
}
fn write(&mut self, value: Self::Value) {
unsafe {
let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::<Self::Value>();
core::arch::asm!(
"mov [{}], {:e}",
in(reg) ptr,
in(reg) value,
);
}
}
}
// x86 u64 implementation (x86_64 only)
#[cfg(target_arch = "x86_64")]
impl Io for Mmio<u64> {
type Value = u64;
fn read(&self) -> Self::Value {
unsafe {
let value: Self::Value;
let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::<Self::Value>();
core::arch::asm!(
"mov {:r}, [{}]",
out(reg) value,
in(reg) ptr
);
value
}
}
fn write(&mut self, value: Self::Value) {
unsafe {
let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::<Self::Value>();
core::arch::asm!(
"mov [{}], {:r}",
in(reg) ptr,
in(reg) value,
);
}
}
}
-157
View File
@@ -1,157 +0,0 @@
use super::Io;
/// MMIO using pointer instead of wrapped type
pub struct MmioPtr<T> {
ptr: *mut T,
}
impl<T> MmioPtr<T> {
//TODO: reads and writes are unsafe, not new.
/// Creates a `MmioPtr`.
pub unsafe fn new(ptr: *mut T) -> Self {
Self { ptr }
}
/// Creates a const pointer from a `MmioPtr`.
pub const fn as_ptr(&self) -> *const T {
self.ptr
}
/// Creates a mutable pointer from a `MmioPtr`.
pub const fn as_mut_ptr(&mut self) -> *mut T {
self.ptr
}
}
// Generic implementation (WARNING: requires aligned pointers!)
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
impl<T> Io for MmioPtr<T>
where
T: Copy
+ PartialEq
+ core::ops::BitAnd<Output = T>
+ core::ops::BitOr<Output = T>
+ core::ops::Not<Output = T>,
{
type Value = T;
fn read(&self) -> T {
unsafe { core::ptr::read_volatile(self.ptr) }
}
fn write(&mut self, value: T) {
unsafe { core::ptr::write_volatile(self.ptr, value) };
}
}
// x86 u8 implementation
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl Io for MmioPtr<u8> {
type Value = u8;
fn read(&self) -> Self::Value {
unsafe {
let value: Self::Value;
core::arch::asm!(
"mov {}, [{}]",
out(reg_byte) value,
in(reg) self.ptr
);
value
}
}
fn write(&mut self, value: Self::Value) {
unsafe {
core::arch::asm!(
"mov [{}], {}",
in(reg) self.ptr,
in(reg_byte) value,
);
}
}
}
// x86 u16 implementation
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl Io for MmioPtr<u16> {
type Value = u16;
fn read(&self) -> Self::Value {
unsafe {
let value: Self::Value;
core::arch::asm!(
"mov {:x}, [{}]",
out(reg) value,
in(reg) self.ptr
);
value
}
}
fn write(&mut self, value: Self::Value) {
unsafe {
core::arch::asm!(
"mov [{}], {:x}",
in(reg) self.ptr,
in(reg) value,
);
}
}
}
// x86 u32 implementation
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl Io for MmioPtr<u32> {
type Value = u32;
fn read(&self) -> Self::Value {
unsafe {
let value: Self::Value;
core::arch::asm!(
"mov {:e}, [{}]",
out(reg) value,
in(reg) self.ptr
);
value
}
}
fn write(&mut self, value: Self::Value) {
unsafe {
core::arch::asm!(
"mov [{}], {:e}",
in(reg) self.ptr,
in(reg) value,
);
}
}
}
// x86 u64 implementation (x86_64 only)
#[cfg(target_arch = "x86_64")]
impl Io for MmioPtr<u64> {
type Value = u64;
fn read(&self) -> Self::Value {
unsafe {
let value: Self::Value;
core::arch::asm!(
"mov {:r}, [{}]",
out(reg) value,
in(reg) self.ptr
);
value
}
}
fn write(&mut self, value: Self::Value) {
unsafe {
core::arch::asm!(
"mov [{}], {:r}",
in(reg) self.ptr,
in(reg) value,
);
}
}
}
-89
View File
@@ -1,89 +0,0 @@
use core::{arch::asm, marker::PhantomData};
use super::Io;
/// Generic PIO
#[derive(Copy, Clone)]
pub struct Pio<T> {
port: u16,
value: PhantomData<T>,
}
impl<T> Pio<T> {
/// Create a PIO from a given port
pub const fn new(port: u16) -> Self {
Pio::<T> {
port,
value: PhantomData,
}
}
}
/// Read/Write for byte PIO
impl Io for Pio<u8> {
type Value = u8;
/// Read
#[inline(always)]
fn read(&self) -> u8 {
let value: u8;
unsafe {
asm!("in al, dx", in("dx") self.port, out("al") value, options(nostack, nomem, preserves_flags));
}
value
}
/// Write
#[inline(always)]
fn write(&mut self, value: u8) {
unsafe {
asm!("out dx, al", in("dx") self.port, in("al") value, options(nostack, nomem, preserves_flags));
}
}
}
/// Read/Write for word PIO
impl Io for Pio<u16> {
type Value = u16;
/// Read
#[inline(always)]
fn read(&self) -> u16 {
let value: u16;
unsafe {
asm!("in ax, dx", in("dx") self.port, out("ax") value, options(nostack, nomem, preserves_flags));
}
value
}
/// Write
#[inline(always)]
fn write(&mut self, value: u16) {
unsafe {
asm!("out dx, ax", in("dx") self.port, in("ax") value, options(nostack, nomem, preserves_flags));
}
}
}
/// Read/Write for doubleword PIO
impl Io for Pio<u32> {
type Value = u32;
/// Read
#[inline(always)]
fn read(&self) -> u32 {
let value: u32;
unsafe {
asm!("in eax, dx", in("dx") self.port, out("eax") value, options(nostack, nomem, preserves_flags));
}
value
}
/// Write
#[inline(always)]
fn write(&mut self, value: u32) {
unsafe {
asm!("out dx, eax", in("dx") self.port, in("eax") value, options(nostack, nomem, preserves_flags));
}
}
}
-371
View File
@@ -1,371 +0,0 @@
//! This crate provides various abstractions for use by all drivers in the Redox drivers repo.
//!
//! This includes direct memory access via [dma], and Scatter-Gather List support via [sgl]. It also
//! provides various memory management structures for use with drivers, and some logging support.
use libredox::call::MmapArgs;
use libredox::flag::{self, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY};
use libredox::{
errno::EINVAL,
error::{Error, Result},
Fd,
};
use syscall::{ProcSchemeVerb, PAGE_SIZE};
/// The Direct Memory Access (DMA) API for drivers
pub mod dma;
/// MMIO utilities
pub mod io;
mod logger;
/// The Scatter Gather List (SGL) API for drivers.
pub mod sgl;
/// Low latency timeout for driver loops
pub mod timeout;
pub use logger::{file_level, output_level, setup_logging};
use std::sync::OnceLock;
static MEMORY_ROOT_FD: OnceLock<libredox::Fd> = OnceLock::new();
/// Initializes a file descriptor to be used as the root memory for a driver.
///
/// # Panics
///
/// This function will panic if:
/// - `libredox` is unable to open a file descriptor.
/// - The memory root file descriptor has already been set (this function has already been called).
pub fn init() {
if MEMORY_ROOT_FD
.set(
libredox::Fd::open("/scheme/memory/scheme-root", 0, 0)
.expect("drivers common: failed to open memory root fd"),
)
.is_err()
{
panic!("drivers common: failed to set memory root fd");
}
}
/// Gets the memory root file descriptor.
///
/// # Panics
///
/// This function will panic if `init` has not already been called first.
pub fn memory_root_fd() -> &'static libredox::Fd {
MEMORY_ROOT_FD
.get()
.expect("drivers common: memory root fd not initialized. Please call `common::init` in your main function.")
}
/// Specifies the write behavior for a specific region of memory
///
/// These types indicate to the driver how writes to a specific memory region are handled by the
/// system. This usually refers to the caching behavior that the processor or I/O device responsible
/// for that memory implements.
///
/// aarch64 and x86 have very different cache-coherency rules, so this API as written is likely
/// not sufficient to describe the memory caching behavior in a cross-platform manner. As such,
/// consider this API unstable.
#[derive(Clone, Copy, Debug)]
pub enum MemoryType {
/// A region of memory that implements Write-back caching.
///
/// In write-back caching, the processor will first store data in its local cache, and then
/// flush it to the actual storage location at regular intervals, or as applications access
/// the data.
Writeback,
/// A region of memory that does not implement caching. Writes to these regions are immediate.
Uncacheable,
/// A region of memory that implements write combining.
///
/// Write combining memory regions store all writes in a temporary buffer called a Write
/// Combine Buffer. Multiple writes to the location are stored in a single buffer, and then
/// released to the memory location in an unspecified order. Write-Combine memory does not
/// guarantee that the order at which you write to it is the order at which those writes are
/// committed to memory.
WriteCombining,
/// Memory stored in an intermediate Write Combine Buffer and released later
/// Memory-Mapped I/O. This is an aarch64-specific term.
DeviceMemory,
}
impl Default for MemoryType {
fn default() -> Self {
Self::Writeback
}
}
/// Represents the protection level of an area of memory.
///
/// This structure shouldn't be used directly -- instead, use the [`Prot::RO`] (Read-Only),
/// [`Prot::WO`] (Write-Only) and [`Prot::RW`] (Read-Write) constants to specify the memory's protection
/// level.
#[derive(Clone, Copy, Debug)]
pub struct Prot {
/// The memory is readable
pub read: bool,
/// The memory is writeable
pub write: bool,
}
/// Implements the memory protection level constants
impl Prot {
/// A constant representing Read-Only memory.
pub const RO: Self = Self {
read: true,
write: false,
};
/// A constant representing Write-Only memory
pub const WO: Self = Self {
read: false,
write: true,
};
/// A constant representing Read-Write memory
pub const RW: Self = Self {
read: true,
write: true,
};
}
/// Maps physical memory to virtual memory
///
/// # Arguments
///
/// * '`base_phys`: [usize]' - The base address of the physical memory to map.
/// * 'len: [usize]' - The length of the physical memory to map (Should be a multiple of [`PAGE_SIZE`]
/// * '_: [Prot]' - The memory protection level of the mapping.
/// * 'type: [`MemoryType`]' - The caching behavior specification of the memory.
///
/// # Returns
///
/// A '[Result]<*mut ()>' which is:
/// - '[Ok]' containing a raw pointer to the mapped memory.
/// - '[Err]' which contains an error on failure.
///
/// # Errors
///
/// This function will return an error if:
/// - An invalid value is provided to 'read' or 'write'
/// - The system could not open a file descriptor to the memory scheme for the specified [`MemoryType`].
/// - The system failed to map the physical address to a virtual address. See [`libredox::call::mmap`]
///
/// # Safety
///
/// Safe, as the kernel ensures it doesn't conflict with any other memory described in the memory
/// map for regular RAM.
///
/// # Notes
/// - This function is unsafe, and upon using it you will be responsible for freeing the memory with
/// [`libredox::call::munmap`]. If you want a safe accessor, use [`PhysBorrowed`] instead.
/// - The `MemoryType` specified is used to tell the function which memory scheme to access. (i.e
/// /scheme/memory/physical@wb, /scheme/memory/physical@uc, etc).
pub unsafe fn physmap(
base_phys: usize,
len: usize,
Prot { read, write }: Prot,
ty: MemoryType,
) -> Result<*mut ()> {
// TODO: arraystring?
//Return an error rather than potentially crash the kernel.
if base_phys == 0 {
return Err(Error::new(EINVAL));
}
let path = format!(
"physical@{}",
match ty {
MemoryType::Writeback => "wb",
MemoryType::Uncacheable => "uc",
MemoryType::WriteCombining => "wc",
MemoryType::DeviceMemory => "dev",
}
);
let mode = match (read, write) {
(true, true) => O_RDWR,
(true, false) => O_RDONLY,
(false, true) => O_WRONLY,
(false, false) => return Err(Error::new(EINVAL)),
};
let mut prot = 0;
if read {
prot |= flag::PROT_READ;
}
if write {
prot |= flag::PROT_WRITE;
}
let fd = memory_root_fd().openat(&path, O_CLOEXEC | mode, 0)?;
Ok(libredox::call::mmap(MmapArgs {
fd: fd.raw(),
offset: base_phys as u64,
length: len.next_multiple_of(PAGE_SIZE),
flags: flag::MAP_SHARED,
prot,
addr: core::ptr::null_mut(),
})? as *mut ())
}
impl std::fmt::Display for MemoryType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Writeback => "wb",
Self::Uncacheable => "uc",
Self::WriteCombining => "wc",
Self::DeviceMemory => "dev",
}
)
}
}
/// A safe virtual mapping to physical memory that unmaps the memory when the structure goes out
/// of scope.
///
/// This function provides a safe binding to [physmap]. It implements Drop to free the mapped memory
/// when the structure goes out of scope.
pub struct PhysBorrowed {
mem: *mut (),
len: usize,
}
impl PhysBorrowed {
/// Constructs a `PhysBorrowed` instance.
///
/// # Arguments
/// See [physmap] for a description of the parameters.
///
/// # Returns
/// A '[Result]' which contains the following:
/// - A '[`PhysBorrowed`]' which represents the newly mapped region.
/// - An 'Err' if a memory mapping error occurs.
///
/// # Errors
/// See [physmap] for a description of the error cases.
pub fn map(base_phys: usize, len: usize, prot: Prot, ty: MemoryType) -> Result<Self> {
let mem = unsafe { physmap(base_phys, len, prot, ty)? };
Ok(Self {
mem,
len: len.next_multiple_of(PAGE_SIZE),
})
}
/// Gets a raw pointer to the borrowed region.
///
/// # Returns
/// - self.mem - A pointer to the mapped region in virtual memory.
///
/// # Notes
/// - The pointer may live beyond the lifetime of [`PhysBorrowed`], so dereferences to the pointer
/// must be treated as unsafe.
///
pub fn as_ptr(&self) -> *mut () {
self.mem
}
/// Gets the length of the mapped region.
///
/// # Returns
/// - self.len - The length of the mapped region. It should be a multiple of [`PAGE_SIZE`]
pub fn mapped_len(&self) -> usize {
self.len
}
}
impl Drop for PhysBorrowed {
/// Frees the mapped memory region.
fn drop(&mut self) {
unsafe {
let _ = libredox::call::munmap(self.mem, self.len);
}
}
}
/// Instructs the kernel to enable I/O ports for this (usermode) process (x86-specific).
///
/// On Redox, x86 privilege ring 3 represents userspace. Most Redox drivers run in userspace to
/// prevent system instability caused by a faulty driver. Processes with (bitmap-enabled) IO port
/// rights can use the IN/OUT instructions. This is not the same as IOPL 3; the CLI instruction is
/// still not allowed.
pub fn acquire_port_io_rights() -> Result<()> {
extern "C" {
fn redox_cur_thrfd_v0() -> usize;
}
let kernel_fd = libredox::call::dup(unsafe { redox_cur_thrfd_v0() }, b"open_via_dup")?;
let res = libredox::call::call_wo(
kernel_fd,
&[],
syscall::CallFlags::empty(),
&[ProcSchemeVerb::Iopl as u64],
);
let _ = libredox::call::close(kernel_fd);
res?;
Ok(())
}
/// Kernel handle for translating virtual addresses in the current address space, to their
/// underlying physical addresses.
///
/// It is currently unspecified whether this handle is specific to the address space at the time it
/// was created, or whether all calls reference the currently active address space.
pub struct VirtaddrTranslationHandle {
fd: Fd,
}
impl VirtaddrTranslationHandle {
/// Create a new handle, requires uid=0 but this may change.
pub fn new() -> Result<Self> {
Ok(Self {
fd: memory_root_fd().openat("translation", O_CLOEXEC, 0)?,
})
}
/// Translate physical => virtual.
pub fn translate(&self, physical: usize) -> Result<usize> {
let mut buf = physical.to_ne_bytes();
libredox::call::call_ro(self.fd.raw(), &mut buf, syscall::CallFlags::empty(), &[])?;
Ok(usize::from_ne_bytes(buf))
}
}
#[cfg(test)]
mod physmap_type_assertions {
use super::*;
/// If `physmap` ever changes its error type, this test fails to
/// compile and surfaces the regression at `cargo check` time on the
/// host rather than during a full Redox cross-build.
///
/// The check uses `std::mem::size_of_val` on a constructed error
/// value. `libredox::error::Error` is `pub struct { errno: u16 }`,
/// so its `size_of_val` is exactly `size_of::<u16>() == 2`. A
/// future change to a different error type (e.g.
/// `syscall::error::Error { errno: i32 }` which would be 4 bytes)
/// would change this constant and force a maintainer to update
/// both the assertion and the downstream `map_err` adapters in
/// lockstep — making the type drift visible at review time rather
/// than at build time.
#[test]
fn physmap_returns_libredox_error_result() {
// Reference layout: `libredox::error::Error { errno: u16 }`.
// If this changes the size assertion below must be updated.
const EXPECTED_SIZE: usize = std::mem::size_of::<u16>();
// Reference error type used at the assertion site.
let reference: libredox::error::Error = libredox::error::Error::new(0);
assert_eq!(std::mem::size_of_val(&reference), EXPECTED_SIZE);
// Coercion check: the function pointer signature must be
// mappable to the expected return type. If physmap's error
// type drifts (e.g. from `libredox::error::Error` to
// `syscall::error::Error` or `std::io::Error`), this coercion
// fails to compile. We never call `f` — we only borrow its
// signature.
let _f: PhysmapSig = physmap;
}
/// Concrete signature of `physmap` for the assertion above.
type PhysmapSig = unsafe fn(usize, usize, Prot, MemoryType) -> libredox::error::Result<*mut ()>;
}
-108
View File
@@ -1,108 +0,0 @@
use std::str::FromStr;
use libredox::{flag, Fd};
use redox_log::{OutputBuilder, RedoxLogger};
/// Get the log verbosity for the output level.
pub fn output_level() -> log::LevelFilter {
log::LevelFilter::Info
}
/// Get the log verbosity for the file level.
pub fn file_level() -> log::LevelFilter {
log::LevelFilter::Info
}
/// Configures logging for a single driver.
#[cfg_attr(not(target_os = "redox"), allow(unused_variables, unused_mut))]
pub fn setup_logging(
category: &str,
subcategory: &str,
logfile_base: &str,
mut output_level: log::LevelFilter,
file_level: log::LevelFilter,
) {
RedoxLogger::init_timezone();
if let Some(log_level) = read_bootloader_log_level_env(category, subcategory) {
output_level = log_level;
}
let mut logger = RedoxLogger::new().with_output(
OutputBuilder::stderr()
.with_filter(output_level) // limit global output to important info
.with_ansi_escape_codes()
.flush_on_newline(true)
.build(),
);
#[cfg(target_os = "redox")]
match OutputBuilder::in_redox_logging_scheme(
category,
subcategory,
format!("{logfile_base}.log"),
) {
Ok(b) => {
logger = logger.with_output(b.with_filter(file_level).flush_on_newline(true).build())
}
Err(error) => eprintln!("Failed to create {logfile_base}.log: {}", error),
}
#[cfg(target_os = "redox")]
match OutputBuilder::in_redox_logging_scheme(
category,
subcategory,
format!("{logfile_base}.ansi.log"),
) {
Ok(b) => {
logger = logger.with_output(
b.with_filter(file_level)
.with_ansi_escape_codes()
.flush_on_newline(true)
.build(),
)
}
Err(error) => eprintln!("Failed to create {logfile_base}.ansi.log: {}", error),
}
logger.enable().expect("failed to set default logger");
}
fn read_bootloader_log_level_env(category: &str, subcategory: &str) -> Option<log::LevelFilter> {
let mut env_bytes = [0_u8; 4096];
// TODO: Have the kernel env can specify prefixed env key instead of having to read all of them
let envs = {
let Ok(fd) = Fd::open("/scheme/sys/env", flag::O_RDONLY | flag::O_CLOEXEC, 0) else {
return None;
};
let Ok(bytes_read) = fd.read(&mut env_bytes) else {
return None;
};
if bytes_read >= env_bytes.len() {
return None;
}
let env_bytes = &mut env_bytes[..bytes_read];
env_bytes
.split(|&c| c == b'\n')
.filter(|var| var.starts_with(b"DRIVER_"))
.collect::<Vec<_>>()
};
let log_env_keys = [
format!("DRIVER_{}_LOG_LEVEL=", subcategory.to_ascii_uppercase()),
format!("DRIVER_{}_LOG_LEVEL=", category.to_ascii_uppercase()),
"DRIVER_LOG_LEVEL=".to_string(),
];
for log_env_key in log_env_keys {
let log_env_key = log_env_key.as_bytes();
if let Some(log_env) = envs.iter().find_map(|var| var.strip_prefix(log_env_key)) {
if let Ok(Ok(log_level)) = str::from_utf8(&log_env).map(log::LevelFilter::from_str) {
return Some(log_level);
}
}
}
None
}
-130
View File
@@ -1,130 +0,0 @@
use std::num::NonZeroUsize;
use libredox::call::MmapArgs;
use libredox::errno::EINVAL;
use libredox::error::{Error, Result};
use libredox::flag::{MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
use syscall::{MAP_FIXED, PAGE_SIZE};
use crate::dma::phys_contiguous_fd;
use crate::VirtaddrTranslationHandle;
/// A Scatter-Gather List data structure
///
/// See: <https://en.wikipedia.org/wiki/Gather/scatter_(vector_addressing)>
#[derive(Debug)]
pub struct Sgl {
/// A raw pointer to the SGL in virtual memory
virt: *mut u8,
/// The length of the allocated memory, guaranteed to be a multiple of [`PAGE_SIZE`].
aligned_length: usize,
/// The length of the allocated memory. This value is NOT guaranteed to be a multiple of [`PAGE_SIZE`]
unaligned_length: NonZeroUsize,
/// The vector of chunks tracked by this [Sgl] object. This is the sparsely-populated vector in the SGL algorithm.
chunks: Vec<Chunk>,
}
/// A structure representing a chunk of memory in the sparsely-populated vector of the SGL
#[derive(Debug)]
pub struct Chunk {
/// The offset of the chunk in the sparsely-populated vector.
pub offset: usize,
/// The physical address of the chunk
pub phys: usize,
/// A raw pointer to the chunk in virtual memory
pub virt: *mut u8,
/// The length of the chunk in bytes.
pub length: usize,
}
impl Sgl {
/// Constructor for the scatter/gather list.
///
/// # Arguments
///
/// '`unaligned_length`: [usize]' - The length of the SGL, not necessarily aligned to the nearest
/// page.
pub fn new(unaligned_length: usize) -> Result<Self> {
let unaligned_length = NonZeroUsize::new(unaligned_length).ok_or(Error::new(EINVAL))?;
// TODO: Both PAGE_SIZE and MAX_ALLOC_SIZE should be dynamic.
let aligned_length = unaligned_length.get().next_multiple_of(PAGE_SIZE);
const MAX_ALLOC_SIZE: usize = 1 << 22;
unsafe {
let virt = libredox::call::mmap(MmapArgs {
flags: MAP_PRIVATE,
prot: PROT_NONE,
length: aligned_length,
offset: 0,
fd: !0,
addr: core::ptr::null_mut(),
})?
.cast::<u8>();
let mut this = Self {
virt,
aligned_length,
unaligned_length,
chunks: Vec::new(),
};
// TODO: SglContext to avoid reopening these fds?
let phys_contiguous_fd = phys_contiguous_fd()?;
let virttophys_handle = VirtaddrTranslationHandle::new()?;
let mut offset = 0;
while offset < aligned_length {
let preferred_chunk_length = (aligned_length - offset)
.min(MAX_ALLOC_SIZE)
.next_power_of_two();
let chunk_length = if preferred_chunk_length > aligned_length - offset {
preferred_chunk_length / 2
} else {
preferred_chunk_length
};
libredox::call::mmap(MmapArgs {
addr: virt.add(offset).cast(),
flags: MAP_PRIVATE | (MAP_FIXED.bits() as u32),
prot: PROT_READ | PROT_WRITE,
length: chunk_length,
fd: phys_contiguous_fd.raw(),
offset: 0,
})?;
let phys = virttophys_handle.translate(virt as usize + offset)?;
this.chunks.push(Chunk {
offset,
phys,
length: (unaligned_length.get() - offset).min(chunk_length),
virt: virt.add(offset),
});
offset += chunk_length;
}
Ok(this)
}
}
/// Returns an immutable reference to the vector of chunks
pub fn chunks(&self) -> &[Chunk] {
&self.chunks
}
/// Returns a raw pointer to the vector of chunks in virtual memory
pub fn as_ptr(&self) -> *mut u8 {
self.virt
}
/// Returns the length of the scatter-gather list.
pub fn len(&self) -> usize {
self.unaligned_length.get()
}
}
impl Drop for Sgl {
fn drop(&mut self) {
unsafe {
let _ = libredox::call::munmap(self.virt.cast(), self.aligned_length);
}
}
}
-56
View File
@@ -1,56 +0,0 @@
use std::time::{Duration, Instant};
/// Represents an amount of time for a driver to give up to the OS scheduler.
pub struct Timeout {
instant: Instant,
duration: Duration,
}
impl Timeout {
/// Create a new `Timeout` from a `Duration`.
#[inline]
pub fn new(duration: Duration) -> Self {
Self {
instant: Instant::now(),
duration,
}
}
/// Create a new `Timeout` by specifying the amount of microseconds.
#[inline]
pub fn from_micros(micros: u64) -> Self {
Self::new(Duration::from_micros(micros))
}
/// Create a new `Timeout` by specifying the amount of milliseconds.
#[inline]
pub fn from_millis(millis: u64) -> Self {
Self::new(Duration::from_millis(millis))
}
/// Create a new `Timeout` by specifying the amount of seconds.
#[inline]
pub fn from_secs(secs: u64) -> Self {
Self::new(Duration::from_secs(secs))
}
/// Execute the `Timeout`.
///
/// # Errors
///
/// Returns an `Err` if the duration of the `Timeout` has already elapsed
/// between creating the `Timeout` and calling this function.
#[inline]
pub fn run(&self) -> Result<(), ()> {
if self.instant.elapsed() < self.duration {
// Sleeps in Redox are only evaluated on PIT ticks (a few ms), which is not
// short enough for a reasonably responsive timeout. However, the clock is
// highly accurate. So, we yield instead of sleep to reduce latency.
//TODO: allow timeout that spins instead of yields?
std::thread::yield_now();
Ok(())
} else {
Err(())
}
}
}
-15
View File
@@ -1,15 +0,0 @@
[package]
name = "executor"
description = "Asynchronous framework for queue-based hardware interfaces"
authors = ["4lDO2 <4lDO2@protonmail.com>"]
version = "0.1.0"
edition = "2021"
license = "MIT"
[dependencies]
log.workspace = true
redox_event.workspace = true
slab.workspace = true
[lints]
workspace = true
-396
View File
@@ -1,396 +0,0 @@
use std::cell::{Cell, RefCell};
use std::collections::{HashMap, VecDeque};
use std::fmt::Debug;
use std::fs::File;
use std::future::{Future, IntoFuture};
use std::hash::Hash;
use std::io::{Read, Write};
use std::marker::PhantomData;
use std::os::fd::AsRawFd;
use std::panic::AssertUnwindSafe;
use std::pin::Pin;
use std::ptr::NonNull;
use std::rc::Rc;
use std::task;
use event::{EventFlags, RawEventQueue};
use slab::Slab;
type EventUserData = usize;
type FutIdx = usize;
pub trait Hardware: Sized {
type CmdId: Clone + Copy + Debug + Hash + Eq + PartialEq;
type CqId: Clone + Copy + Debug + Hash + Eq + PartialEq;
type SqId: Clone + Copy + Debug + Hash + Eq + PartialEq;
type Sqe: Debug + Clone + Copy;
type Cqe;
type Iv: Clone + Copy + Debug;
type GlobalCtxt;
// TODO: the kernel should also do this automatically before sending EOI messages to the IC
fn mask_vector(ctxt: &Self::GlobalCtxt, iv: Self::Iv);
fn unmask_vector(ctxt: &Self::GlobalCtxt, iv: Self::Iv);
fn set_sqe_cmdid(sqe: &mut Self::Sqe, id: Self::CmdId);
fn get_cqe_cmdid(cqe: &Self::Cqe) -> Self::CmdId;
// TODO: support multiple SQs per CQ or vice versa?
fn sq_cq(ctxt: &Self::GlobalCtxt, id: Self::CqId) -> Self::SqId;
fn current() -> Rc<LocalExecutor<Self>>;
fn vtable() -> &'static task::RawWakerVTable;
fn try_submit(
ctxt: &Self::GlobalCtxt,
sq_id: Self::SqId,
success: impl FnOnce(Self::CmdId) -> Self::Sqe,
fail: impl FnOnce(),
) -> Option<(Self::CqId, Self::CmdId)>;
fn poll_cqes(ctxt: &Self::GlobalCtxt, handle: impl FnMut(Self::CqId, Self::Cqe));
}
/// Async executor, single IV, thread-per-core architecture
pub struct LocalExecutor<Hw: Hardware> {
global_ctxt: Hw::GlobalCtxt,
queue: RawEventQueue,
vector: Hw::Iv,
irq_handle: File,
intx: bool,
// TODO: One IV and SQ/CQ per core (where the admin queue can be managed by the main thread).
awaiting_submission: RefCell<HashMap<Hw::SqId, VecDeque<FutIdx>>>,
awaiting_completion:
RefCell<HashMap<Hw::CqId, HashMap<Hw::CmdId, (FutIdx, NonNull<Option<Hw::Cqe>>)>>>,
external_event: RefCell<HashMap<EventUserData, (FutIdx, NonNull<EventFlags>)>>,
next_user_data: Cell<usize>,
ready_futures: RefCell<VecDeque<FutIdx>>,
futures: RefCell<Slab<Pin<Box<dyn Future<Output = ()> + 'static>>>>,
is_polling: Cell<bool>,
}
impl<Hw: Hardware> LocalExecutor<Hw> {
pub fn register_external_event(
&self,
fd: usize,
flags: event::EventFlags,
) -> ExternalEventSource<Hw> {
let user_data = self.next_user_data.get();
self.next_user_data.set(user_data.checked_add(1).unwrap());
self.queue
.subscribe(fd, user_data, flags)
.expect("failed to subscribe to event");
ExternalEventSource {
flags: event::EventFlags::empty(),
user_data,
_not_send_or_unpin: PhantomData,
}
}
pub fn current() -> Rc<Self> {
Hw::current()
}
pub fn poll(&self) -> usize {
assert!(!self.is_polling.replace(true));
let mut finished = 0;
for future_idx in self.ready_futures.borrow_mut().drain(..) {
let waker = waker::<Hw>(future_idx);
let mut futures = self.futures.borrow_mut();
let res = match std::panic::catch_unwind(AssertUnwindSafe(|| {
futures[future_idx]
.as_mut()
.poll(&mut task::Context::from_waker(&waker))
})) {
Ok(r) => r,
Err(_) => {
log::error!("Task panicked!");
core::mem::forget(futures.remove(future_idx));
continue;
}
};
if res.is_ready() {
drop(futures.remove(future_idx));
finished += 1;
}
}
self.is_polling.set(false);
finished
}
pub fn spawn(&self, fut: impl IntoFuture<Output = ()> + 'static) {
let idx = self
.futures
.borrow_mut()
.insert(Box::pin(fut.into_future()));
self.ready_futures.borrow_mut().push_back(idx);
}
pub fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture<Output = O> + 'a) -> O {
let retval = Rc::new(RefCell::new(None));
let retval2 = Rc::clone(&retval);
let idx = self.futures.borrow_mut().insert({
let t1: Pin<Box<dyn Future<Output = ()> + 'a>> = Box::pin(async move {
*retval2.borrow_mut() = Some(fut.await);
});
// SAFETY: Apart from the lifetimes, the types are exactly the same. We also know
// block_on simply cannot return without having fully awaited and dropped the future,
// even if that future panics (cf. the catch_unwind invocation).
let t2: Pin<Box<dyn Future<Output = ()> + 'static>> =
unsafe { std::mem::transmute(t1) };
t2
});
self.ready_futures.borrow_mut().push_front(idx);
loop {
let finished = self.poll();
if retval.borrow().is_some() {
break;
}
if finished == 0 {
self.react();
}
}
let o = retval.borrow_mut().take().unwrap();
o
}
fn react(&self) {
let event = self.queue.next_event().expect("failed to get next event");
if event.user_data != 0 {
let Some((fut_idx, flags_ptr)) =
self.external_event.borrow_mut().remove(&event.user_data)
else {
// Spurious event
return;
};
unsafe {
flags_ptr
.as_ptr()
.write(event::EventFlags::from_bits_retain(event.flags));
}
self.ready_futures.borrow_mut().push_back(fut_idx);
return;
}
if self.intx {
let mut buf = [0_u8; core::mem::size_of::<usize>()];
if (&self.irq_handle).read(&mut buf).unwrap() != 0 {
(&self.irq_handle).write(&buf).unwrap();
}
}
// TODO: The kernel should probably do the masking (when using MSI/MSI-X at least), which
// should happen before EOI messages to the interrupt controller.
Hw::mask_vector(&self.global_ctxt, self.vector);
Hw::poll_cqes(&self.global_ctxt, |cq_id, cqe| {
if let Some((fut_idx, comp_ptr)) = self
.awaiting_completion
.borrow_mut()
.get_mut(&cq_id)
.and_then(|per_cmd| per_cmd.remove(&Hw::get_cqe_cmdid(&cqe)))
{
unsafe {
comp_ptr.as_ptr().write(Some(cqe));
}
self.ready_futures.borrow_mut().push_back(fut_idx);
if let Some(submitting) = self
.awaiting_submission
.borrow_mut()
.get_mut(&Hw::sq_cq(&self.global_ctxt, cq_id))
.and_then(|q| q.pop_front())
{
self.ready_futures.borrow_mut().push_back(submitting);
}
}
});
Hw::unmask_vector(&self.global_ctxt, self.vector);
}
pub async fn submit(&self, sq_id: Hw::SqId, cmd: Hw::Sqe) -> Hw::Cqe {
CqeFuture::<Hw> {
state: State::<Hw>::Submitting { sq_id, cmd },
comp: None,
_not_send: PhantomData,
}
.await
}
}
struct CqeFuture<Hw: Hardware> {
pub state: State<Hw>,
pub comp: Option<Hw::Cqe>,
pub _not_send: PhantomData<*const ()>,
}
enum State<Hw: Hardware> {
Submitting { sq_id: Hw::SqId, cmd: Hw::Sqe },
Completing { cq_id: Hw::CqId, cmd_id: Hw::CmdId },
}
fn current_executor_and_idx<Hw: Hardware>(
cx: &mut task::Context<'_>,
) -> (Rc<LocalExecutor<Hw>>, FutIdx) {
let executor = LocalExecutor::current();
let idx = cx.waker().data() as FutIdx;
assert_eq!(
cx.waker().vtable() as *const _,
Hw::vtable(),
"incompatible executor for CqeFuture"
);
(executor, idx)
}
impl<Hw: Hardware> Future for CqeFuture<Hw> {
type Output = Hw::Cqe;
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
let (executor, idx) = current_executor_and_idx::<Hw>(cx);
match this.state {
State::Submitting { sq_id, mut cmd } => {
let mut awaiting = executor.awaiting_submission.borrow_mut();
if let Some((cq_id, cmd_id)) = Hw::try_submit(
&executor.global_ctxt,
sq_id,
|cmd_id| {
Hw::set_sqe_cmdid(&mut cmd, cmd_id);
log::trace!("About to submit {cmd:?}");
cmd
},
|| {
awaiting.entry(sq_id).or_default().push_back(idx);
},
) {
executor
.awaiting_completion
.borrow_mut()
.entry(cq_id)
.or_default()
.insert(cmd_id, (idx, (&mut this.comp).into()));
this.state = State::Completing { cq_id, cmd_id };
}
task::Poll::Pending
}
State::Completing { cq_id, cmd_id } => match this.comp.take() {
Some(comp) => {
log::trace!("ready!");
task::Poll::Ready(comp)
}
// Shouldn't technically be possible
None => {
log::trace!("spurious poll");
executor
.awaiting_completion
.borrow_mut()
.entry(cq_id)
.or_default()
.insert(cmd_id, (idx, (&mut this.comp).into()));
task::Poll::Pending
}
},
}
}
}
unsafe fn vt_clone<Hw: Hardware>(idx: *const ()) -> task::RawWaker {
task::RawWaker::new(idx, Hw::vtable())
}
unsafe fn vt_drop(_idx: *const ()) {}
unsafe fn vt_wake<Hw: Hardware>(idx: *const ()) {
Hw::current()
.ready_futures
.borrow_mut()
.push_back(idx as FutIdx);
}
fn waker<Hw: Hardware>(idx: FutIdx) -> task::Waker {
unsafe { task::Waker::from_raw(task::RawWaker::new(idx as *const (), Hw::vtable())) }
}
pub const fn vtable<Hw: Hardware>() -> task::RawWakerVTable {
task::RawWakerVTable::new(vt_clone::<Hw>, vt_wake::<Hw>, vt_wake::<Hw>, vt_drop)
}
pub struct ExternalEventSource<Hw: Hardware> {
flags: event::EventFlags,
user_data: EventUserData,
_not_send_or_unpin: PhantomData<(*const (), fn() -> Hw)>,
}
pub struct Event {
flags: event::EventFlags,
_not_send: PhantomData<*const ()>,
}
impl Event {
pub fn flags(&self) -> event::EventFlags {
self.flags
}
}
impl<Hw: Hardware> ExternalEventSource<Hw> {
fn poll_next(self: Pin<&mut Self>, cx: &mut task::Context) -> task::Poll<Option<Event>> {
let this = unsafe { self.get_unchecked_mut() };
let flags = std::mem::take(&mut this.flags);
if flags.is_empty() {
let (executor, idx) = current_executor_and_idx::<Hw>(cx);
executor
.external_event
.borrow_mut()
.insert(this.user_data, (idx, (&mut this.flags).into()));
return task::Poll::Pending;
}
task::Poll::Ready(Some(Event {
flags,
_not_send: PhantomData,
}))
}
pub async fn next(mut self: Pin<&mut Self>) -> Option<Event> {
core::future::poll_fn(|cx| self.as_mut().poll_next(cx)).await
}
}
pub fn init_raw<Hw: Hardware>(
global_ctxt: Hw::GlobalCtxt,
vector: Hw::Iv,
intx: bool,
irq_handle: File,
) -> LocalExecutor<Hw> {
let queue = RawEventQueue::new().expect("failed to allocate event queue for local executor");
// TODO: Multiple CPUs
queue
.subscribe(irq_handle.as_raw_fd() as usize, 0, EventFlags::READ)
.expect("failed to subscribe to IRQ event");
LocalExecutor {
global_ctxt,
queue,
vector,
intx,
irq_handle,
awaiting_submission: RefCell::new(HashMap::new()),
awaiting_completion: RefCell::new(HashMap::new()),
external_event: RefCell::new(HashMap::new()),
next_user_data: Cell::new(1),
ready_futures: RefCell::new(VecDeque::new()),
futures: RefCell::new(Slab::with_capacity(16)),
is_polling: Cell::new(false),
}
}
-21
View File
@@ -1,21 +0,0 @@
[package]
name = "gpiod"
description = "GPIO controller registry daemon"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
log.workspace = true
redox_syscall = { workspace = true, features = ["std"] }
libredox.workspace = true
redox-scheme.workspace = true
ron.workspace = true
serde.workspace = true
common = { path = "../../common" }
daemon = { path = "../../../daemon" }
scheme-utils = { path = "../../../scheme-utils" }
[lints]
workspace = true
-496
View File
@@ -1,496 +0,0 @@
use std::collections::BTreeMap;
use std::process;
use anyhow::{Context, Result};
use redox_scheme::scheme::SchemeSync;
use redox_scheme::{CallerCtx, OpenResult, Socket};
use scheme_utils::{Blocking, HandleMap};
use serde::{Deserialize, Serialize};
use syscall::schemev2::NewFdFlags;
use syscall::{Error as SysError, EACCES, EBADF, EINVAL, ENOENT};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct GpioControllerInfo {
pub id: u32,
pub name: String,
pub pin_count: usize,
pub supports_interrupt: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum GpioControlRequest {
RegisterController { info: GpioControllerInfo },
ReadPin { controller_id: u32, pin: u32 },
WritePin { controller_id: u32, pin: u32, value: bool },
ConfigurePin { controller_id: u32, pin: u32, config: PinConfig },
ListControllers,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PinConfig {
pub direction: PinDirection,
pub pull: PullMode,
pub interrupt_mode: Option<InterruptMode>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum PinDirection {
Input,
Output,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum PullMode {
None,
Up,
Down,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum InterruptMode {
EdgeRising,
EdgeFalling,
EdgeBoth,
LevelHigh,
LevelLow,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
enum GpioControlResponse {
ControllerRegistered { id: u32 },
Controllers(Vec<GpioControllerInfo>),
Controller(GpioControllerInfo),
PinValue(bool),
Ack,
Error(String),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum PinOpKind {
Read,
Write,
Configure,
}
enum Handle {
SchemeRoot,
Register { pending: Vec<u8> },
Provider { controller_id: u32, pending: Vec<u8> },
ControllersDir { pending: Vec<u8> },
ControllerDetail { id: u32, pending: Vec<u8> },
PinOp { kind: PinOpKind, pending: Vec<u8> },
}
struct ControllerEntry {
info: GpioControllerInfo,
provider_handle: usize,
}
struct GpioDaemon {
handles: HandleMap<Handle>,
controllers: BTreeMap<u32, ControllerEntry>,
next_id: u32,
}
impl GpioDaemon {
fn new() -> Self {
Self {
handles: HandleMap::new(),
controllers: BTreeMap::new(),
next_id: 0,
}
}
fn controller_list(&self) -> Vec<GpioControllerInfo> {
self.controllers
.values()
.map(|entry| entry.info.clone())
.collect()
}
fn serialize_response(response: &GpioControlResponse) -> syscall::Result<Vec<u8>> {
ron::ser::to_string(response)
.map(|text| text.into_bytes())
.map_err(|err| {
log::error!("gpiod: failed to serialize control response: {err}");
SysError::new(EINVAL)
})
}
fn deserialize_request(buf: &[u8]) -> syscall::Result<GpioControlRequest> {
let text = std::str::from_utf8(buf).map_err(|err| {
log::warn!("gpiod: invalid UTF-8 request payload: {err}");
SysError::new(EINVAL)
})?;
ron::from_str(text).map_err(|err| {
log::warn!("gpiod: failed to decode control request: {err}");
SysError::new(EINVAL)
})
}
fn set_pending_response(handle: &mut Handle, response: GpioControlResponse) -> syscall::Result<()> {
let pending = Self::serialize_response(&response)?;
Self::set_pending_bytes(handle, pending)
}
fn set_pending_bytes(handle: &mut Handle, pending: Vec<u8>) -> syscall::Result<()> {
match handle {
Handle::Register { pending: slot }
| Handle::Provider { pending: slot, .. }
| Handle::ControllersDir { pending: slot }
| Handle::ControllerDetail { pending: slot, .. }
| Handle::PinOp { pending: slot, .. } => {
*slot = pending;
Ok(())
}
Handle::SchemeRoot => Err(SysError::new(EBADF)),
}
}
fn copy_pending(handle: &mut Handle, buf: &mut [u8], offset: u64) -> syscall::Result<usize> {
let pending = match handle {
Handle::Register { pending }
| Handle::Provider { pending, .. }
| Handle::ControllersDir { pending }
| Handle::ControllerDetail { pending, .. }
| Handle::PinOp { pending, .. } => pending,
Handle::SchemeRoot => return Err(SysError::new(EBADF)),
};
let offset = usize::try_from(offset).map_err(|_| SysError::new(EINVAL))?;
if offset >= pending.len() {
return Ok(0);
}
let copy_len = buf.len().min(pending.len() - offset);
buf[..copy_len].copy_from_slice(&pending[offset..offset + copy_len]);
Ok(copy_len)
}
fn validate_pin_target(
&self,
controller_id: u32,
pin: u32,
) -> std::result::Result<GpioControllerInfo, String> {
let entry = self
.controllers
.get(&controller_id)
.ok_or_else(|| format!("unknown controller {controller_id}"))?;
if usize::try_from(pin)
.ok()
.filter(|pin| *pin < entry.info.pin_count)
.is_none()
{
return Err(format!(
"pin {pin} is out of range for controller {} (pin_count={})",
entry.info.name, entry.info.pin_count
));
}
Ok(entry.info.clone())
}
}
impl SchemeSync for GpioDaemon {
fn scheme_root(&mut self) -> syscall::Result<usize> {
Ok(self.handles.insert(Handle::SchemeRoot))
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> syscall::Result<OpenResult> {
let handle = self.handles.get(dirfd)?;
let segments = path.trim_matches('/');
let new_handle = match handle {
Handle::SchemeRoot => {
if segments.is_empty() {
return Err(SysError::new(EINVAL));
}
let mut parts = segments.split('/');
match parts.next() {
Some("register") if parts.next().is_none() => Handle::Register {
pending: Vec::new(),
},
Some("controllers") => match parts.next() {
None => Handle::ControllersDir {
pending: Vec::new(),
},
Some(id) if parts.next().is_none() => Handle::ControllerDetail {
id: id.parse::<u32>().map_err(|_| SysError::new(EINVAL))?,
pending: Vec::new(),
},
_ => return Err(SysError::new(EINVAL)),
},
Some("read_pin") if parts.next().is_none() => Handle::PinOp {
kind: PinOpKind::Read,
pending: Vec::new(),
},
Some("write_pin") if parts.next().is_none() => Handle::PinOp {
kind: PinOpKind::Write,
pending: Vec::new(),
},
Some("configure_pin") if parts.next().is_none() => Handle::PinOp {
kind: PinOpKind::Configure,
pending: Vec::new(),
},
_ => return Err(SysError::new(ENOENT)),
}
}
Handle::ControllersDir { .. } => {
if segments.is_empty() {
return Err(SysError::new(EINVAL));
}
Handle::ControllerDetail {
id: segments.parse::<u32>().map_err(|_| SysError::new(EINVAL))?,
pending: Vec::new(),
}
}
_ => return Err(SysError::new(EACCES)),
};
let fd = self.handles.insert(new_handle);
Ok(OpenResult::ThisScheme {
number: fd,
flags: NewFdFlags::empty(),
})
}
fn read(
&mut self,
id: usize,
buf: &mut [u8],
offset: u64,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> syscall::Result<usize> {
let controllers = self.controller_list();
let detail = match self.handles.get(id)? {
Handle::ControllerDetail { id, .. } => self.controllers.get(id).map(|entry| entry.info.clone()),
_ => None,
};
let handle = self.handles.get_mut(id)?;
match handle {
Handle::ControllersDir { pending } if pending.is_empty() => {
*pending = Self::serialize_response(&GpioControlResponse::Controllers(controllers))?;
}
Handle::ControllerDetail { id, pending } if pending.is_empty() => {
let info = detail.ok_or(SysError::new(ENOENT))?;
*pending = Self::serialize_response(&GpioControlResponse::Controller(info))?;
log::debug!("gpiod: served controller detail for id={id}");
}
_ => {}
}
Self::copy_pending(handle, buf, offset)
}
fn write(
&mut self,
id: usize,
buf: &[u8],
_offset: u64,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> syscall::Result<usize> {
let request = Self::deserialize_request(buf)?;
match request {
GpioControlRequest::RegisterController { mut info } => {
if !matches!(self.handles.get(id)?, Handle::Register { .. }) {
return Err(SysError::new(EINVAL));
}
let controller_id = self.next_id;
self.next_id = self.next_id.checked_add(1).ok_or(SysError::new(EINVAL))?;
info.id = controller_id;
self.controllers.insert(
controller_id,
ControllerEntry {
info: info.clone(),
provider_handle: id,
},
);
let handle = self.handles.get_mut(id)?;
*handle = Handle::Provider {
controller_id,
pending: Self::serialize_response(&GpioControlResponse::ControllerRegistered {
id: controller_id,
})?,
};
log::info!(
"RB_GPIOD_CONTROLLER_REGISTERED id={} name={} pin_count={} supports_interrupt={}",
info.id,
info.name,
info.pin_count,
info.supports_interrupt,
);
Ok(buf.len())
}
GpioControlRequest::ListControllers => {
let controllers = self.controller_list();
let handle = self.handles.get_mut(id)?;
Self::set_pending_response(handle, GpioControlResponse::Controllers(controllers))?;
Ok(buf.len())
}
GpioControlRequest::ReadPin { controller_id, pin } => {
let validation = self.validate_pin_target(controller_id, pin);
let handle = self.handles.get_mut(id)?;
match handle {
Handle::PinOp {
kind: PinOpKind::Read,
..
} => {
match validation {
Ok(info) => {
log::info!(
"RB_GPIOD_PIN_READ controller_id={} name={} pin={} routed=stub",
controller_id,
info.name,
pin,
);
Self::set_pending_response(handle, GpioControlResponse::PinValue(false))?;
}
Err(message) => {
Self::set_pending_response(handle, GpioControlResponse::Error(message))?;
}
}
Ok(buf.len())
}
_ => Err(SysError::new(EINVAL)),
}
}
GpioControlRequest::WritePin {
controller_id,
pin,
value,
} => {
let validation = self.validate_pin_target(controller_id, pin);
let handle = self.handles.get_mut(id)?;
match handle {
Handle::PinOp {
kind: PinOpKind::Write,
..
} => {
match validation {
Ok(info) => {
log::info!(
"RB_GPIOD_PIN_WRITE controller_id={} name={} pin={} value={} routed=stub",
controller_id,
info.name,
pin,
value,
);
Self::set_pending_response(handle, GpioControlResponse::Ack)?;
}
Err(message) => {
Self::set_pending_response(handle, GpioControlResponse::Error(message))?;
}
}
Ok(buf.len())
}
_ => Err(SysError::new(EINVAL)),
}
}
GpioControlRequest::ConfigurePin {
controller_id,
pin,
config,
} => {
let validation = self.validate_pin_target(controller_id, pin);
let handle = self.handles.get_mut(id)?;
match handle {
Handle::PinOp {
kind: PinOpKind::Configure,
..
} => {
match validation {
Ok(info) => {
log::info!(
"RB_GPIOD_PIN_CONFIG controller_id={} name={} pin={} direction={:?} pull={:?} interrupt={:?} routed=stub",
controller_id,
info.name,
pin,
config.direction,
config.pull,
config.interrupt_mode,
);
Self::set_pending_response(handle, GpioControlResponse::Ack)?;
}
Err(message) => {
Self::set_pending_response(handle, GpioControlResponse::Error(message))?;
}
}
Ok(buf.len())
}
_ => Err(SysError::new(EINVAL)),
}
}
}
}
fn on_close(&mut self, id: usize) {
let Some(handle) = self.handles.remove(id) else {
return;
};
if let Handle::Provider { controller_id, .. } = handle {
if let Some(entry) = self.controllers.remove(&controller_id) {
log::info!(
"RB_GPIOD_CONTROLLER_REMOVED id={} name={} provider_handle={}",
controller_id,
entry.info.name,
entry.provider_handle,
);
}
}
}
}
fn run_daemon(daemon: daemon::SchemeDaemon) -> Result<()> {
let socket = Socket::create().context("failed to create gpio scheme socket")?;
let mut scheme = GpioDaemon::new();
let handler = Blocking::new(&socket, 16);
daemon
.ready_sync_scheme(&socket, &mut scheme)
.context("failed to publish gpio scheme root")?;
log::info!("RB_GPIOD_SCHEMA version=1");
libredox::call::setrens(0, 0).context("failed to enter null namespace")?;
handler
.process_requests_blocking(scheme)
.context("failed to process gpiod requests")?;
}
fn daemon_runner(daemon: daemon::SchemeDaemon) -> ! {
if let Err(err) = run_daemon(daemon) {
log::error!("gpiod: {err:#}");
process::exit(1);
}
process::exit(0);
}
fn main() {
common::setup_logging(
"gpio",
"gpio",
"gpiod",
common::output_level(),
common::file_level(),
);
daemon::SchemeDaemon::new(daemon_runner);
}
@@ -1,21 +0,0 @@
[package]
name = "i2c-gpio-expanderd"
description = "I2C GPIO expander bridge daemon"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
log.workspace = true
redox_syscall = { workspace = true, features = ["std"] }
libredox.workspace = true
serde.workspace = true
ron.workspace = true
acpi-resource = { path = "../../acpi-resource" }
common = { path = "../../common" }
daemon = { path = "../../../daemon" }
i2c-interface = { path = "../../i2c/i2c-interface" }
[lints]
workspace = true
-454
View File
@@ -1,454 +0,0 @@
use std::collections::BTreeMap;
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;
use std::process;
use acpi_resource::{GpioDescriptor, I2cSerialBusDescriptor, ResourceDescriptor};
use anyhow::{Context, Result};
use i2c_interface::{
I2cAdapterInfo, I2cControlRequest, I2cControlResponse, I2cTransferRequest,
I2cTransferResponse, I2cTransferSegment,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
struct AmlSymbol {
name: String,
value: AmlValue,
}
#[derive(Debug, Deserialize)]
enum AmlValue {
Integer(u64),
String(String),
}
#[derive(Clone, Debug)]
struct ExpanderResources {
i2c: I2cSerialBusDescriptor,
pin_count: usize,
gpio_int_count: usize,
gpio_io_count: usize,
}
#[derive(Debug)]
struct ExpanderDescriptor {
device: String,
hid: String,
resources: ExpanderResources,
}
struct RegisteredExpander {
_registration: File,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
struct GpioControllerInfo {
id: u32,
name: String,
pin_count: usize,
supports_interrupt: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
enum GpioControlRequest {
RegisterController { info: GpioControllerInfo },
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
enum GpioControlResponse {
ControllerRegistered { id: u32 },
Error(String),
}
fn main() {
common::setup_logging(
"gpio",
"i2c-gpio-expander",
"i2c-gpio-expanderd",
common::output_level(),
common::file_level(),
);
daemon::Daemon::new(daemon_runner);
}
fn daemon_runner(daemon: daemon::Daemon) -> ! {
if let Err(err) = daemon_main(daemon) {
log::error!("i2c-gpio-expanderd: {err:#}");
process::exit(1);
}
process::exit(0);
}
fn daemon_main(daemon: daemon::Daemon) -> Result<()> {
let expanders = discover_expanders().context("failed to discover ACPI I2C GPIO expanders")?;
if expanders.is_empty() {
log::info!("i2c-gpio-expanderd: no probable ACPI I2C GPIO expanders found");
}
let adapters = list_i2c_adapters().unwrap_or_else(|err| {
log::warn!("i2c-gpio-expanderd: unable to query i2cd adapters: {err:#}");
Vec::new()
});
let mut registered = Vec::new();
for expander in expanders {
match register_expander(expander, &adapters) {
Ok(expander) => registered.push(expander),
Err(err) => log::warn!("i2c-gpio-expanderd: expander registration skipped: {err:#}"),
}
}
daemon.ready();
libredox::call::setrens(0, 0).context("failed to enter null namespace")?;
log::info!("i2c-gpio-expanderd: registered {} expander(s)", registered.len());
loop {
std::thread::park();
}
}
fn discover_expanders() -> Result<Vec<ExpanderDescriptor>> {
let mut matched = BTreeMap::new();
let entries = match fs::read_dir("/scheme/acpi/symbols") {
Ok(entries) => entries,
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock || err.raw_os_error() == Some(11) => {
log::debug!("i2c-gpio-expanderd: ACPI symbols are not ready yet");
return Ok(Vec::new());
}
Err(err) => return Err(err).context("failed to read /scheme/acpi/symbols"),
};
for entry in entries {
let entry = entry.context("failed to read ACPI symbol directory entry")?;
let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else {
continue;
};
if !file_name.ends_with("_HID") && !file_name.ends_with("_CID") {
continue;
}
let Some(id) = read_symbol_id(&entry.path())? else {
continue;
};
if is_excluded_device_id(&id) {
continue;
}
let Some(device) = file_name
.strip_suffix("_HID")
.or_else(|| file_name.strip_suffix("_CID"))
.map(str::to_owned)
else {
continue;
};
let resources = match read_expander_resources(&device) {
Ok(resources) => resources,
Err(err) => {
log::debug!("i2c-gpio-expanderd: skipping {device}: {err:#}");
continue;
}
};
if resources.gpio_int_count == 0 && resources.gpio_io_count == 0 {
continue;
}
matched.entry(device).or_insert((id, resources));
}
let mut expanders = Vec::new();
for (device, (hid, resources)) in matched {
expanders.push(ExpanderDescriptor {
device,
hid,
resources,
});
}
Ok(expanders)
}
fn read_symbol_id(path: &Path) -> Result<Option<String>> {
let contents = fs::read_to_string(path)
.with_context(|| format!("failed to read ACPI symbol {}", path.display()))?;
let symbol = match ron::from_str::<AmlSymbol>(&contents) {
Ok(symbol) => symbol,
Err(err) => {
log::debug!(
"i2c-gpio-expanderd: skipping {} because the symbol payload was not a scalar ID: {err}",
path.display(),
);
return Ok(None);
}
};
let id = match symbol.value {
AmlValue::Integer(integer) => eisa_id_from_integer(integer),
AmlValue::String(string) => string,
};
log::debug!("i2c-gpio-expanderd: {} -> {id}", symbol.name);
Ok(Some(id))
}
fn read_expander_resources(device: &str) -> Result<ExpanderResources> {
let contents = fs::read_to_string(format!("/scheme/acpi/resources/{device}"))
.with_context(|| format!("failed to read /scheme/acpi/resources/{device}"))?;
let resources = ron::from_str::<Vec<ResourceDescriptor>>(&contents)
.with_context(|| format!("failed to decode RON resources for {device}"))?;
let mut i2c = None;
let mut pin_count = 0usize;
let mut gpio_int_count = 0usize;
let mut gpio_io_count = 0usize;
for resource in resources {
match resource {
ResourceDescriptor::I2cSerialBus(bus) if i2c.is_none() => i2c = Some(bus),
ResourceDescriptor::GpioInt(descriptor) => {
gpio_int_count += 1;
pin_count = pin_count.max(pin_count_from_descriptor(&descriptor));
}
ResourceDescriptor::GpioIo(descriptor) => {
gpio_io_count += 1;
pin_count = pin_count.max(pin_count_from_descriptor(&descriptor));
}
_ => {}
}
}
Ok(ExpanderResources {
i2c: i2c.context("no I2cSerialBus resource was found")?,
pin_count,
gpio_int_count,
gpio_io_count,
})
}
fn pin_count_from_descriptor(descriptor: &GpioDescriptor) -> usize {
descriptor
.pins
.iter()
.copied()
.max()
.map(|pin| usize::from(pin).saturating_add(1))
.unwrap_or(0)
}
fn is_excluded_device_id(id: &str) -> bool {
matches!(
id,
"PNP0C50"
| "ACPI0C50"
| "INT34C5"
| "INTC1055"
| "INT33C2"
| "INT33C3"
| "INT3432"
| "INT3433"
| "INTC10EF"
| "AMDI0010"
| "AMDI0019"
| "AMDI0510"
| "PNP0CA0"
| "AMDI0042"
) || id.starts_with("ELAN")
|| id.starts_with("CYAP")
|| id.starts_with("SYNA")
}
fn register_expander(expander: ExpanderDescriptor, adapters: &[I2cAdapterInfo]) -> Result<RegisteredExpander> {
let ExpanderDescriptor {
device,
hid,
resources,
} = expander;
let adapter_name = resources
.i2c
.resource_source
.as_ref()
.map(|source| source.source.clone())
.filter(|source| !source.is_empty())
.unwrap_or_else(|| String::from("ACPI-I2C"));
let adapter = match match_i2c_adapter(adapters, &adapter_name) {
Some(adapter) => Some(adapter.clone()),
None => {
log::warn!(
"i2c-gpio-expanderd: unable to resolve I2C adapter {} for {}",
adapter_name,
device,
);
None
}
};
if let Some(adapter) = adapter.as_ref() {
if let Err(err) = probe_expander(adapter, &adapter_name, resources.i2c.slave_address) {
log::warn!(
"i2c-gpio-expanderd: expander {} probe on {}@{:04x} failed: {err:#}",
device,
adapter_name,
resources.i2c.slave_address,
);
}
}
let info = GpioControllerInfo {
id: 0,
name: format!("i2c-gpio-expander:{device}"),
pin_count: resources.pin_count,
supports_interrupt: resources.gpio_int_count > 0,
};
let mut registration = register_with_gpiod(&info)
.with_context(|| format!("failed to register {device} with gpiod"))?;
let response = read_gpio_registration_response(&mut registration)
.with_context(|| format!("failed to read gpiod registration response for {device}"))?;
match response {
GpioControlResponse::ControllerRegistered { id } => {
log::info!(
"RB_I2C_GPIO_EXPANDERD_DEVICE device={} hid={} controller_id={} adapter={} addr={:04x} pin_count={} gpio_int={} gpio_io={}",
device,
hid,
id,
adapter_name,
resources.i2c.slave_address,
info.pin_count,
resources.gpio_int_count,
resources.gpio_io_count,
);
}
GpioControlResponse::Error(message) => {
anyhow::bail!("gpiod rejected expander {device}: {message}");
}
}
Ok(RegisteredExpander {
_registration: registration,
})
}
fn list_i2c_adapters() -> Result<Vec<I2cAdapterInfo>> {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open("/scheme/i2c/adapters")
.context("failed to open /scheme/i2c/adapters")?;
let payload = ron::ser::to_string(&I2cControlRequest::ListAdapters)
.context("failed to encode I2C list-adapters request")?;
file.write_all(payload.as_bytes())
.context("failed to request I2C adapter list")?;
let response = read_i2c_control_response(&mut file)?;
match response {
I2cControlResponse::AdapterList(adapters) => Ok(adapters),
I2cControlResponse::Error(message) => anyhow::bail!("i2cd returned an error: {message}"),
other => anyhow::bail!("unexpected i2cd list-adapters response: {other:?}"),
}
}
fn match_i2c_adapter<'a>(adapters: &'a [I2cAdapterInfo], wanted: &str) -> Option<&'a I2cAdapterInfo> {
adapters
.iter()
.find(|adapter| adapter.name == wanted)
.or_else(|| adapters.iter().find(|adapter| adapter.name.ends_with(wanted)))
.or_else(|| adapters.iter().find(|adapter| wanted.ends_with(&adapter.name)))
}
fn probe_expander(adapter: &I2cAdapterInfo, adapter_name: &str, address: u16) -> Result<I2cTransferResponse> {
let request = I2cTransferRequest {
adapter: adapter_name.to_string(),
segments: vec![I2cTransferSegment::read(address, 1)],
stop: true,
};
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open("/scheme/i2c/transfer")
.context("failed to open /scheme/i2c/transfer")?;
let payload = ron::ser::to_string(&I2cControlRequest::Transfer {
adapter_id: adapter.id,
request,
})
.context("failed to encode I2C expander probe request")?;
file.write_all(payload.as_bytes())
.context("failed to send I2C expander probe request")?;
let response = read_i2c_control_response(&mut file)?;
match response {
I2cControlResponse::TransferResult(result) => {
if !result.ok {
let detail = result
.error
.clone()
.unwrap_or_else(|| String::from("unknown I2C transfer failure"));
anyhow::bail!("I2C probe failed: {detail}");
}
Ok(result)
}
I2cControlResponse::Error(message) => anyhow::bail!("i2cd returned an error: {message}"),
other => anyhow::bail!("unexpected I2C transfer response: {other:?}"),
}
}
fn register_with_gpiod(info: &GpioControllerInfo) -> Result<File> {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open("/scheme/gpio/register")
.context("failed to open /scheme/gpio/register")?;
let payload = ron::ser::to_string(&GpioControlRequest::RegisterController { info: info.clone() })
.context("failed to encode GPIO controller registration")?;
file.write_all(payload.as_bytes())
.context("failed to send GPIO controller registration")?;
Ok(file)
}
fn read_gpio_registration_response(file: &mut File) -> Result<GpioControlResponse> {
let mut buffer = vec![0_u8; 4096];
let count = file
.read(&mut buffer)
.context("failed to read GPIO registration response")?;
buffer.truncate(count);
let text = std::str::from_utf8(&buffer).context("GPIO registration response was not UTF-8")?;
ron::from_str(text).context("failed to decode GPIO registration response")
}
fn read_i2c_control_response(file: &mut File) -> Result<I2cControlResponse> {
let mut buffer = vec![0_u8; 4096];
let count = file
.read(&mut buffer)
.context("failed to read I2C control response")?;
buffer.truncate(count);
let text = std::str::from_utf8(&buffer).context("I2C control response was not UTF-8")?;
let trimmed = text.trim();
if trimmed.is_empty() {
return Ok(I2cControlResponse::AdapterList(Vec::new()));
}
ron::from_str(trimmed).context("failed to decode I2C control response")
}
fn eisa_id_from_integer(integer: u64) -> String {
let vendor = integer & 0xFFFF;
let device = (integer >> 16) & 0xFFFF;
let vendor_rev = ((vendor & 0xFF) << 8) | (vendor >> 8);
let vendor_1 = (((vendor_rev >> 10) & 0x1F) as u8 + 64) as char;
let vendor_2 = (((vendor_rev >> 5) & 0x1F) as u8 + 64) as char;
let vendor_3 = (((vendor_rev >> 0) & 0x1F) as u8 + 64) as char;
let device_1 = (device >> 4) & 0xF;
let device_2 = (device >> 0) & 0xF;
let device_3 = (device >> 12) & 0xF;
let device_4 = (device >> 8) & 0xF;
format!(
"{vendor_1}{vendor_2}{vendor_3}{device_1:01X}{device_2:01X}{device_3:01X}{device_4:01X}"
)
}
-20
View File
@@ -1,20 +0,0 @@
[package]
name = "intel-gpiod"
description = "Intel ACPI GPIO registrar daemon"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
log.workspace = true
redox_syscall = { workspace = true, features = ["std"] }
libredox.workspace = true
serde.workspace = true
ron.workspace = true
acpi-resource = { path = "../../acpi-resource" }
common = { path = "../../common" }
daemon = { path = "../../../daemon" }
[lints]
workspace = true
-401
View File
@@ -1,401 +0,0 @@
use std::collections::BTreeMap;
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;
use std::process;
use acpi_resource::{
AddressResourceType, ExtendedIrqDescriptor, FixedMemory32Descriptor, GpioDescriptor,
IrqDescriptor, Memory32RangeDescriptor, ResourceDescriptor,
};
use anyhow::{Context, Result};
use common::{MemoryType, PhysBorrowed, Prot};
use serde::{Deserialize, Serialize};
const SUPPORTED_IDS: &[&str] = &["INT34C5", "INTC1055"];
const PADNFGPIO_OWN_BASE: usize = 0x20;
const PADNFGPIO_PADCFG_BASE: usize = 0x700;
const GPI_INT_STATUS: usize = 0x100;
const GPI_INT_EN: usize = 0x120;
const INTEL_GPIO_MMIO_WINDOW: usize = PADNFGPIO_PADCFG_BASE + core::mem::size_of::<u32>();
#[derive(Debug, Deserialize)]
struct AmlSymbol {
name: String,
value: AmlValue,
}
#[derive(Debug, Deserialize)]
enum AmlValue {
Integer(u64),
String(String),
}
#[derive(Clone, Debug)]
struct ControllerResources {
mmio_base: usize,
mmio_len: usize,
pin_count: usize,
supports_interrupt: bool,
gpio_int_count: usize,
gpio_io_count: usize,
}
#[derive(Debug)]
struct ControllerDescriptor {
device: String,
hid: String,
resources: ControllerResources,
}
struct RegisteredController {
_mmio: Option<PhysBorrowed>,
_registration: File,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
struct GpioControllerInfo {
id: u32,
name: String,
pin_count: usize,
supports_interrupt: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
enum GpioControlRequest {
RegisterController { info: GpioControllerInfo },
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
enum GpioControlResponse {
ControllerRegistered { id: u32 },
Error(String),
}
fn main() {
common::setup_logging(
"gpio",
"intel-gpio",
"intel-gpiod",
common::output_level(),
common::file_level(),
);
daemon::Daemon::new(daemon_runner);
}
fn daemon_runner(daemon: daemon::Daemon) -> ! {
if let Err(err) = daemon_main(daemon) {
log::error!("intel-gpiod: {err:#}");
process::exit(1);
}
process::exit(0);
}
fn daemon_main(daemon: daemon::Daemon) -> Result<()> {
common::init();
let controllers =
discover_controllers(SUPPORTED_IDS).context("failed to discover Intel GPIO controllers")?;
if controllers.is_empty() {
log::info!("intel-gpiod: no supported Intel GPIO ACPI controllers found");
}
let mut registered = Vec::new();
for controller in controllers {
match register_controller(controller) {
Ok(controller) => registered.push(controller),
Err(err) => log::warn!("intel-gpiod: controller registration skipped: {err:#}"),
}
}
daemon.ready();
libredox::call::setrens(0, 0).context("failed to enter null namespace")?;
log::info!("intel-gpiod: registered {} controller(s)", registered.len());
loop {
std::thread::park();
}
}
fn discover_controllers(supported_ids: &[&str]) -> Result<Vec<ControllerDescriptor>> {
let mut matched = BTreeMap::new();
let entries = match fs::read_dir("/scheme/acpi/symbols") {
Ok(entries) => entries,
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock || err.raw_os_error() == Some(11) => {
log::debug!("intel-gpiod: ACPI symbols are not ready yet");
return Ok(Vec::new());
}
Err(err) => return Err(err).context("failed to read /scheme/acpi/symbols"),
};
for entry in entries {
let entry = entry.context("failed to read ACPI symbol directory entry")?;
let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else {
continue;
};
if !file_name.ends_with("_HID") && !file_name.ends_with("_CID") {
continue;
}
let Some(id) = read_symbol_id(&entry.path())? else {
continue;
};
if !supported_ids.iter().any(|candidate| *candidate == id) {
continue;
}
let device = file_name
.strip_suffix("_HID")
.or_else(|| file_name.strip_suffix("_CID"))
.map(str::to_owned);
if let Some(device) = device {
matched.entry(device).or_insert(id);
}
}
let mut controllers = Vec::new();
for (device, hid) in matched {
let resources = read_controller_resources(&device)
.with_context(|| format!("failed to read resources for {device}"))?;
controllers.push(ControllerDescriptor {
device,
hid,
resources,
});
}
Ok(controllers)
}
fn read_symbol_id(path: &Path) -> Result<Option<String>> {
let contents = fs::read_to_string(path)
.with_context(|| format!("failed to read ACPI symbol {}", path.display()))?;
let symbol = match ron::from_str::<AmlSymbol>(&contents) {
Ok(symbol) => symbol,
Err(err) => {
log::debug!(
"intel-gpiod: skipping {} because the symbol payload was not a scalar ID: {err}",
path.display(),
);
return Ok(None);
}
};
let id = match symbol.value {
AmlValue::Integer(integer) => eisa_id_from_integer(integer),
AmlValue::String(string) => string,
};
log::debug!("intel-gpiod: {} -> {id}", symbol.name);
Ok(Some(id))
}
fn read_controller_resources(device: &str) -> Result<ControllerResources> {
let contents = fs::read_to_string(format!("/scheme/acpi/resources/{device}"))
.with_context(|| format!("failed to read /scheme/acpi/resources/{device}"))?;
let resources = ron::from_str::<Vec<ResourceDescriptor>>(&contents)
.with_context(|| format!("failed to decode RON resources for {device}"))?;
let mut mmio = None;
let mut supports_interrupt = false;
let mut gpio_int_count = 0usize;
let mut gpio_io_count = 0usize;
let mut pin_count = 0usize;
for resource in &resources {
match resource {
ResourceDescriptor::FixedMemory32(FixedMemory32Descriptor {
address,
address_length,
..
}) if mmio.is_none() => {
mmio = Some((
*address as usize,
(*address_length as usize).max(INTEL_GPIO_MMIO_WINDOW),
));
}
ResourceDescriptor::Memory32Range(Memory32RangeDescriptor {
minimum,
maximum,
address_length,
..
}) if mmio.is_none() && maximum >= minimum => {
let span = maximum.saturating_sub(*minimum).saturating_add(1) as usize;
mmio = Some((
*minimum as usize,
span.max((*address_length as usize).max(INTEL_GPIO_MMIO_WINDOW)),
));
}
ResourceDescriptor::Address32(descriptor)
if mmio.is_none()
&& matches!(descriptor.resource_type, AddressResourceType::MemoryRange) =>
{
mmio = Some((
descriptor.minimum as usize,
(descriptor.address_length as usize).max(INTEL_GPIO_MMIO_WINDOW),
));
}
ResourceDescriptor::Address64(descriptor)
if mmio.is_none()
&& matches!(descriptor.resource_type, AddressResourceType::MemoryRange) =>
{
let base = usize::try_from(descriptor.minimum)
.context("64-bit MMIO base does not fit in usize")?;
let len = usize::try_from(descriptor.address_length)
.context("64-bit MMIO length does not fit in usize")?;
mmio = Some((base, len.max(INTEL_GPIO_MMIO_WINDOW)));
}
ResourceDescriptor::Irq(IrqDescriptor { interrupts, .. }) => {
supports_interrupt |= !interrupts.is_empty();
}
ResourceDescriptor::ExtendedIrq(ExtendedIrqDescriptor { interrupts, .. }) => {
supports_interrupt |= !interrupts.is_empty();
}
ResourceDescriptor::GpioInt(descriptor) => {
gpio_int_count += 1;
supports_interrupt = true;
pin_count = pin_count.max(pin_count_from_descriptor(descriptor));
}
ResourceDescriptor::GpioIo(descriptor) => {
gpio_io_count += 1;
pin_count = pin_count.max(pin_count_from_descriptor(descriptor));
}
_ => {}
}
}
let (mmio_base, mmio_len) = mmio.context("no MMIO resource was found")?;
Ok(ControllerResources {
mmio_base,
mmio_len,
pin_count,
supports_interrupt,
gpio_int_count,
gpio_io_count,
})
}
fn pin_count_from_descriptor(descriptor: &GpioDescriptor) -> usize {
descriptor
.pins
.iter()
.copied()
.max()
.map(|pin| usize::from(pin).saturating_add(1))
.unwrap_or(0)
}
fn register_controller(controller: ControllerDescriptor) -> Result<RegisteredController> {
let ControllerDescriptor {
device,
hid,
resources,
} = controller;
let mmio = match PhysBorrowed::map(
resources.mmio_base,
resources.mmio_len,
Prot::RW,
MemoryType::Uncacheable,
) {
Ok(mapping) => Some(mapping),
Err(err) => {
log::warn!(
"intel-gpiod: failed to map MMIO for {device} ({:#x}, len {:#x}): {err}",
resources.mmio_base,
resources.mmio_len,
);
None
}
};
log::info!(
"intel-gpiod: discovered {device} hid={hid} mmio={:#x}+{:#x} pin_count={} gpio_int={} gpio_io={} supports_interrupt={}",
resources.mmio_base,
resources.mmio_len,
resources.pin_count,
resources.gpio_int_count,
resources.gpio_io_count,
resources.supports_interrupt,
);
log::debug!(
"intel-gpiod: register model own={PADNFGPIO_OWN_BASE:#x} padcfg={PADNFGPIO_PADCFG_BASE:#x} gpi_int_status={GPI_INT_STATUS:#x} gpi_int_en={GPI_INT_EN:#x}",
);
let info = GpioControllerInfo {
id: 0,
name: format!("intel-gpio:{device}"),
pin_count: resources.pin_count,
supports_interrupt: resources.supports_interrupt,
};
let mut registration = register_with_gpiod(&info)
.with_context(|| format!("failed to register {device} with gpiod"))?;
let response = read_registration_response(&mut registration)
.with_context(|| format!("failed to read gpiod registration response for {device}"))?;
match response {
GpioControlResponse::ControllerRegistered { id } => {
log::info!(
"RB_INTEL_GPIOD_DEVICE device={} hid={} controller_id={} pin_count={} supports_interrupt={}",
device,
hid,
id,
info.pin_count,
info.supports_interrupt,
);
}
GpioControlResponse::Error(message) => {
anyhow::bail!("gpiod rejected Intel GPIO controller {device}: {message}");
}
}
Ok(RegisteredController {
_mmio: mmio,
_registration: registration,
})
}
fn register_with_gpiod(info: &GpioControllerInfo) -> Result<File> {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open("/scheme/gpio/register")
.context("failed to open /scheme/gpio/register")?;
let payload = ron::ser::to_string(&GpioControlRequest::RegisterController { info: info.clone() })
.context("failed to encode GPIO controller registration")?;
file.write_all(payload.as_bytes())
.context("failed to send GPIO controller registration")?;
Ok(file)
}
fn read_registration_response(file: &mut File) -> Result<GpioControlResponse> {
let mut buffer = vec![0_u8; 4096];
let count = file
.read(&mut buffer)
.context("failed to read GPIO registration response")?;
buffer.truncate(count);
let text = std::str::from_utf8(&buffer).context("GPIO registration response was not UTF-8")?;
ron::from_str(text).context("failed to decode GPIO registration response")
}
fn eisa_id_from_integer(integer: u64) -> String {
let vendor = integer & 0xFFFF;
let device = (integer >> 16) & 0xFFFF;
let vendor_rev = ((vendor & 0xFF) << 8) | (vendor >> 8);
let vendor_1 = (((vendor_rev >> 10) & 0x1F) as u8 + 64) as char;
let vendor_2 = (((vendor_rev >> 5) & 0x1F) as u8 + 64) as char;
let vendor_3 = (((vendor_rev >> 0) & 0x1F) as u8 + 64) as char;
let device_1 = (device >> 4) & 0xF;
let device_2 = (device >> 0) & 0xF;
let device_3 = (device >> 12) & 0xF;
let device_4 = (device >> 8) & 0xF;
format!(
"{vendor_1}{vendor_2}{vendor_3}{device_1:01X}{device_2:01X}{device_3:01X}{device_4:01X}"
)
}
-18
View File
@@ -1,18 +0,0 @@
[package]
name = "console-draw"
description = "Shared terminal drawing code library"
version = "0.1.0"
edition = "2021"
[dependencies]
drm.workspace = true
orbclient.workspace = true
ransid.workspace = true
graphics-ipc = { path = "../graphics-ipc" }
[features]
default = []
[lints]
workspace = true
-460
View File
@@ -1,460 +0,0 @@
extern crate ransid;
use std::collections::VecDeque;
use std::convert::{TryFrom, TryInto};
use std::{cmp, io, mem, ptr};
use drm::buffer::{Buffer, DrmFourcc};
use drm::control::{connector, crtc, framebuffer, ClipRect, Device, Mode};
use graphics_ipc::{CpuBackedBuffer, V2GraphicsHandle};
use orbclient::FONT;
#[derive(Debug, Copy, Clone)]
#[repr(C, packed)]
pub struct Damage {
pub x: u32,
pub y: u32,
pub width: u32,
pub height: u32,
}
impl Damage {
pub const NONE: Self = Damage {
x: 0,
y: 0,
width: 0,
height: 0,
};
pub fn merge(self, other: Self) -> Self {
if self.width == 0 || self.height == 0 {
return other;
}
if other.width == 0 || other.height == 0 {
return self;
}
let x = cmp::min(self.x, other.x);
let y = cmp::min(self.y, other.y);
let x2 = cmp::max(self.x + self.width, other.x + other.width);
let y2 = cmp::max(self.y + self.height, other.y + other.height);
Damage {
x,
y,
width: x2 - x,
height: y2 - y,
}
}
}
pub struct V2DisplayMap {
pub display_handle: V2GraphicsHandle,
connector: connector::Handle,
crtc: crtc::Handle,
fb: framebuffer::Handle,
pub buffer: CpuBackedBuffer,
}
impl V2DisplayMap {
pub fn new(display_handle: V2GraphicsHandle) -> io::Result<Self> {
let connector = display_handle.first_display().unwrap();
let connector_info = display_handle.get_connector(connector, true).unwrap();
let mode = connector_info.modes()[0];
let (width, height) = mode.size();
// FIXME do something smarter that avoids conflicts
let crtc = display_handle.resource_handles().unwrap().filter_crtcs(
display_handle
.get_encoder(connector_info.encoders()[0])
.unwrap()
.possible_crtcs(),
)[0];
let buffer = CpuBackedBuffer::new(
&display_handle,
(width.into(), height.into()),
DrmFourcc::Argb8888,
32,
)?;
let fb = display_handle.add_framebuffer(buffer.buffer(), 32, 32)?;
display_handle.set_crtc(crtc, Some(fb), (0, 0), &[connector], Some(mode))?;
Ok(Self {
display_handle,
connector,
crtc,
fb,
buffer,
})
}
unsafe fn console_map(&mut self) -> DisplayMap {
let size = self.buffer.buffer().size();
let shadow_buf = self.buffer.shadow_buf();
DisplayMap {
offscreen: ptr::slice_from_raw_parts_mut(
shadow_buf.as_mut_ptr() as *mut u32,
shadow_buf.len() / 4,
),
width: size.0 as usize,
height: size.1 as usize,
}
}
pub fn dirty_fb(&mut self, damage: Damage) -> io::Result<()> {
self.buffer
.sync_rect(damage.x, damage.y, damage.width, damage.height);
self.display_handle.dirty_framebuffer(
self.fb,
&[ClipRect::new(
damage.x as u16,
damage.y as u16,
(damage.x + damage.width) as u16,
(damage.y + damage.height) as u16,
)],
)
}
}
struct DisplayMap {
offscreen: *mut [u32],
width: usize,
height: usize,
}
pub struct TextScreen {
console: ransid::Console,
}
impl TextScreen {
pub fn new() -> TextScreen {
TextScreen {
// Width and height will be filled in on the next write to the console
console: ransid::Console::new(0, 0),
}
}
/// Draw a rectangle
fn rect(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize, color: u32) {
let start_y = cmp::min(map.height, y);
let end_y = cmp::min(map.height, y + h);
let start_x = cmp::min(map.width, x);
let len = cmp::min(map.width, x + w) - start_x;
let mut offscreen_ptr = map.offscreen as *mut u8 as usize;
let stride = map.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
for i in 0..len {
unsafe {
*(offscreen_ptr as *mut u32).add(i) = color;
}
}
offscreen_ptr += stride;
rows -= 1;
}
}
/// Invert a rectangle
fn invert(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize) {
let start_y = cmp::min(map.height, y);
let end_y = cmp::min(map.height, y + h);
let start_x = cmp::min(map.width, x);
let len = cmp::min(map.width, x + w) - start_x;
let mut offscreen_ptr = map.offscreen as *mut u8 as usize;
let stride = map.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
let mut row_ptr = offscreen_ptr;
let mut cols = len;
while cols > 0 {
unsafe {
let color = *(row_ptr as *mut u32);
*(row_ptr as *mut u32) = !color;
}
row_ptr += 4;
cols -= 1;
}
offscreen_ptr += stride;
rows -= 1;
}
}
/// Draw a character
fn char(
map: &mut DisplayMap,
x: usize,
y: usize,
character: char,
color: u32,
_bold: bool,
_italic: bool,
) {
if x + 8 <= map.width && y + 16 <= map.height {
let mut dst = map.offscreen as *mut u8 as usize + (y * map.width + x) * 4;
let font_i = 16 * (character as usize);
if font_i + 16 <= FONT.len() {
for row in 0..16 {
let row_data = FONT[font_i + row];
for col in 0..8 {
if (row_data >> (7 - col)) & 1 == 1 {
unsafe {
*((dst + col * 4) as *mut u32) = color;
}
}
}
dst += map.width * 4;
}
}
}
}
}
impl TextScreen {
pub fn write(
&mut self,
map: &mut V2DisplayMap,
buf: &[u8],
input: &mut VecDeque<u8>,
) -> Damage {
let map = unsafe { &mut map.console_map() };
let mut min_changed = map.height;
let mut max_changed = 0;
let mut line_changed = |line| {
if line < min_changed {
min_changed = line;
}
if line > max_changed {
max_changed = line;
}
};
self.console.resize(map.width / 8, map.height / 16);
if self.console.state.x >= self.console.state.w {
self.console.state.x = self.console.state.w - 1;
}
if self.console.state.y >= self.console.state.h {
self.console.state.y = self.console.state.h - 1;
}
if self.console.state.cursor
&& self.console.state.x < self.console.state.w
&& self.console.state.y < self.console.state.h
{
let x = self.console.state.x;
let y = self.console.state.y;
Self::invert(map, x * 8, y * 16, 8, 16);
line_changed(y);
}
self.console.write(buf, |event| match event {
ransid::Event::Char {
x,
y,
c,
color,
bold,
..
} => {
Self::char(map, x * 8, y * 16, c, color.as_rgb(), bold, false);
line_changed(y);
}
ransid::Event::Input { data } => input.extend(data),
ransid::Event::Rect { x, y, w, h, color } => {
Self::rect(map, x * 8, y * 16, w * 8, h * 16, color.as_rgb());
for y2 in y..y + h {
line_changed(y2);
}
}
ransid::Event::ScreenBuffer { .. } => (),
ransid::Event::Move {
from_x,
from_y,
to_x,
to_y,
w,
h,
} => {
let width = map.width;
let pixels = unsafe { &mut *map.offscreen };
for raw_y in 0..h {
let y = if from_y > to_y { raw_y } else { h - raw_y - 1 };
for pixel_y in 0..16 {
{
let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8;
let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8;
let len = w * 8;
if off_from + len <= pixels.len() && off_to + len <= pixels.len() {
unsafe {
let data_ptr = pixels.as_mut_ptr() as *mut u32;
ptr::copy(
data_ptr.offset(off_from as isize),
data_ptr.offset(off_to as isize),
len,
);
}
}
}
}
line_changed(to_y + y);
}
}
ransid::Event::Resize { .. } => (),
ransid::Event::Title { .. } => (),
});
if self.console.state.cursor
&& self.console.state.x < self.console.state.w
&& self.console.state.y < self.console.state.h
{
let x = self.console.state.x;
let y = self.console.state.y;
Self::invert(map, x * 8, y * 16, 8, 16);
line_changed(y);
}
let width = map.width.try_into().unwrap();
let damage = Damage {
x: 0,
y: u32::try_from(min_changed).unwrap() * 16,
width,
height: u32::try_from(max_changed.saturating_sub(min_changed) + 1).unwrap() * 16,
};
damage
}
pub fn resize(&mut self, map: &mut V2DisplayMap, mode: Mode) -> io::Result<()> {
// FIXME fold row when target is narrower and maybe unfold when it is wider
fn copy_row(
old_map: &mut DisplayMap,
new_map: &mut DisplayMap,
from_row: usize,
to_row: usize,
) {
for x in 0..cmp::min(old_map.width, new_map.width) {
let old_idx = from_row * old_map.width + x;
let new_idx = to_row * new_map.width + x;
unsafe {
(*new_map.offscreen)[new_idx] = (*old_map.offscreen)[old_idx];
}
}
}
let mut new_buffer = CpuBackedBuffer::new(
&map.display_handle,
(u32::from(mode.size().0), u32::from(mode.size().1)),
DrmFourcc::Argb8888,
32,
)?;
let new_fb = map
.display_handle
.add_framebuffer(new_buffer.buffer(), 24, 32)?;
new_buffer.shadow_buf().fill(0);
{
let old_map = unsafe { &mut map.console_map() };
let new_size = new_buffer.buffer().size();
let new_shadow_buf = new_buffer.shadow_buf();
let new_map = &mut DisplayMap {
offscreen: ptr::slice_from_raw_parts_mut(
new_shadow_buf.as_mut_ptr() as *mut u32,
new_shadow_buf.len() / 4,
),
width: new_size.0 as usize,
height: new_size.1 as usize,
};
if new_map.height >= old_map.height {
for row in 0..old_map.height {
copy_row(old_map, new_map, row, row);
}
} else {
let deleted_rows = (old_map.height - new_map.height).div_ceil(16);
for row in 0..new_map.height {
if row + (deleted_rows + 1) * 16 >= old_map.height {
break;
}
copy_row(old_map, new_map, row + deleted_rows * 16, row);
}
self.console.state.y = self.console.state.y.saturating_sub(deleted_rows);
}
}
let old_buffer = mem::replace(&mut map.buffer, new_buffer);
old_buffer.destroy(&map.display_handle)?;
let old_fb = mem::replace(&mut map.fb, new_fb);
map.display_handle.set_crtc(
map.crtc,
Some(map.fb),
(0, 0),
&[map.connector],
Some(mode),
)?;
let _ = map.display_handle.destroy_framebuffer(old_fb);
Ok(())
}
}
pub struct TextBuffer {
pub lines: VecDeque<Vec<u8>>,
pub lines_max: usize,
}
impl TextBuffer {
pub fn new(max: usize) -> Self {
let mut lines = VecDeque::new();
lines.push_back(Vec::new());
Self {
lines,
lines_max: max,
}
}
pub fn write(&mut self, buf: &[u8]) {
if buf.is_empty() {
return;
}
for &byte in buf {
self.lines.back_mut().unwrap().push(byte);
if byte == b'\n' {
self.lines.push_back(Vec::new());
}
}
let max_len = self.lines_max;
while self.lines.len() > max_len {
self.lines.pop_front();
}
}
}
@@ -1,22 +0,0 @@
[package]
name = "driver-graphics"
description = "Shared video and graphics code library"
version = "0.1.0"
edition = "2021"
[dependencies]
drm-fourcc = "2.2.0"
drm-sys.workspace = true
edid.workspace = true #TODO: edid is abandoned, fork it and maintain?
log.workspace = true
redox-ioctl.workspace = true
redox-scheme.workspace = true
scheme-utils = { path = "../../../scheme-utils" }
redox_syscall.workspace = true
libredox.workspace = true
common = { path = "../../common" }
inputd = { path = "../../inputd" }
[lints]
workspace = true
@@ -1,249 +0,0 @@
use std::ffi::c_char;
use std::fmt::Debug;
use std::sync::Mutex;
use drm_sys::{
drm_mode_modeinfo, DRM_MODE_CONNECTOR_Unknown, DRM_MODE_DPMS_OFF, DRM_MODE_DPMS_ON,
DRM_MODE_DPMS_STANDBY, DRM_MODE_DPMS_SUSPEND, DRM_MODE_TYPE_PREFERRED,
};
use syscall::Result;
use crate::kms::objects::{KmsObjectId, KmsObjects};
use crate::kms::properties::{define_object_props, KmsPropertyData, CRTC_ID, DPMS, EDID};
use crate::GraphicsAdapter;
impl<T: GraphicsAdapter> KmsObjects<T> {
pub fn add_connector(
&mut self,
driver_data: T::Connector,
driver_data_state: <T::Connector as KmsConnectorDriver>::State,
crtcs: &[KmsObjectId],
) -> KmsObjectId {
let mut possible_crtcs = 0;
for &crtc in crtcs {
possible_crtcs = 1 << self.get_crtc(crtc).unwrap().lock().unwrap().crtc_index;
}
let encoder_id = self.add(KmsEncoder {
crtc_id: KmsObjectId::INVALID,
possible_crtcs: possible_crtcs,
possible_clones: 1 << self.encoders.len(),
});
self.encoders.push(encoder_id);
let connector_id = self.add(Mutex::new(KmsConnector {
encoder_id,
modes: vec![],
connector_type: DRM_MODE_CONNECTOR_Unknown,
connector_type_id: self.connectors.len() as u32, // FIXME maybe pick unique id within connector type?
connection: KmsConnectorStatus::Unknown,
mm_width: 0,
mm_height: 0,
subpixel: DrmSubpixelOrder::Unknown,
properties: KmsConnector::base_properties(),
edid: KmsObjectId::INVALID,
state: KmsConnectorState {
dpms: KmsDpms::On,
crtc_id: KmsObjectId::INVALID,
driver_data: driver_data_state,
},
driver_data,
}));
self.connectors.push(connector_id);
connector_id
}
pub fn connector_ids(&self) -> &[KmsObjectId] {
&self.connectors
}
pub fn connectors(&self) -> impl Iterator<Item = &Mutex<KmsConnector<T>>> + use<'_, T> {
self.connectors
.iter()
.map(|&id| self.get_connector(id).unwrap())
}
pub fn get_connector(&self, id: KmsObjectId) -> Result<&Mutex<KmsConnector<T>>> {
self.get(id)
}
pub fn encoder_ids(&self) -> &[KmsObjectId] {
&self.encoders
}
pub fn get_encoder(&self, id: KmsObjectId) -> Result<&KmsEncoder> {
self.get(id)
}
}
pub trait KmsConnectorDriver: Debug {
type State: Clone + Debug;
}
impl KmsConnectorDriver for () {
type State = ();
}
#[derive(Debug)]
pub struct KmsConnector<T: GraphicsAdapter> {
pub encoder_id: KmsObjectId,
pub modes: Vec<drm_mode_modeinfo>,
pub connector_type: u32,
pub connector_type_id: u32,
pub connection: KmsConnectorStatus,
pub mm_width: u32,
pub mm_height: u32,
pub subpixel: DrmSubpixelOrder,
pub properties: Vec<KmsPropertyData<Self>>,
pub edid: KmsObjectId,
pub state: KmsConnectorState<T>,
pub driver_data: T::Connector,
}
#[derive(Debug)]
pub struct KmsConnectorState<T: GraphicsAdapter> {
pub dpms: KmsDpms,
pub crtc_id: KmsObjectId,
pub driver_data: <T::Connector as KmsConnectorDriver>::State,
}
impl<T: GraphicsAdapter> Clone for KmsConnectorState<T> {
fn clone(&self) -> Self {
Self {
dpms: self.dpms.clone(),
crtc_id: self.crtc_id.clone(),
driver_data: self.driver_data.clone(),
}
}
}
define_object_props!(object, KmsConnector<T: GraphicsAdapter> {
EDID {
get => u64::from(object.edid.0),
}
DPMS {
get => object.state.dpms as u64,
}
CRTC_ID {
get => u64::from(object.state.crtc_id.0),
}
});
impl<T: GraphicsAdapter> KmsConnector<T> {
pub fn update_from_size(&mut self, width: u32, height: u32) {
self.modes = vec![modeinfo_for_size(width, height)];
}
pub fn update_from_edid(&mut self, edid: &[u8]) {
let edid = edid::parse(edid).unwrap().1;
if let Some(first_detailed_timing) =
edid.descriptors
.iter()
.find_map(|descriptor| match descriptor {
edid::Descriptor::DetailedTiming(detailed_timing) => Some(detailed_timing),
_ => None,
})
{
self.mm_width = first_detailed_timing.horizontal_size.into();
self.mm_height = first_detailed_timing.vertical_size.into();
} else {
log::error!("No edid timing descriptor detected");
}
self.modes = edid
.descriptors
.iter()
.filter_map(|descriptor| {
match descriptor {
edid::Descriptor::DetailedTiming(detailed_timing) => {
// FIXME extract full information
Some(modeinfo_for_size(
u32::from(detailed_timing.horizontal_active_pixels),
u32::from(detailed_timing.vertical_active_lines),
))
}
_ => None,
}
})
.collect::<Vec<_>>();
// First detailed timing descriptor indicates preferred mode.
for mode in self.modes.iter_mut().skip(1) {
mode.flags &= !DRM_MODE_TYPE_PREFERRED;
}
// FIXME update the EDID property
}
}
pub(crate) fn modeinfo_for_size(width: u32, height: u32) -> drm_mode_modeinfo {
let mut modeinfo = drm_mode_modeinfo {
// The actual visible display size
hdisplay: width as u16,
vdisplay: height as u16,
// These are used to calculate the refresh rate
clock: 60 * width * height / 1000,
htotal: width as u16,
vtotal: height as u16,
vscan: 0,
vrefresh: 60,
type_: drm_sys::DRM_MODE_TYPE_PREFERRED | drm_sys::DRM_MODE_TYPE_DRIVER,
name: [0; 32],
// These only matter when modesetting physical display adapters. For
// those we should be able to parse the EDID blob.
hsync_start: width as u16,
hsync_end: width as u16,
hskew: 0,
vsync_start: height as u16,
vsync_end: height as u16,
flags: 0,
};
let name = format!("{width}x{height}").into_bytes();
for (to, from) in modeinfo.name.iter_mut().zip(name) {
*to = from as c_char;
}
modeinfo
}
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum KmsConnectorStatus {
Disconnected = 0,
Connected = 1,
Unknown = 2,
}
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum DrmSubpixelOrder {
Unknown = 0,
HorizontalRGB,
HorizontalBGR,
VerticalRGB,
VerticalBGR,
None,
}
#[derive(Debug, Copy, Clone)]
#[repr(u64)]
pub enum KmsDpms {
On = DRM_MODE_DPMS_ON as u64,
Standby = DRM_MODE_DPMS_STANDBY as u64,
Suspend = DRM_MODE_DPMS_SUSPEND as u64,
Off = DRM_MODE_DPMS_OFF as u64,
}
// FIXME can we represent connector and encoder using a single struct?
#[derive(Debug)]
pub struct KmsEncoder {
pub crtc_id: KmsObjectId,
pub possible_crtcs: u32,
pub possible_clones: u32,
}

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