├── rust-toolchain ├── .gitattributes ├── .gitmodules ├── .gitignore ├── zircon-object ├── src │ ├── util │ │ ├── mod.rs │ │ ├── kcounter.rs │ │ └── block_range.rs │ ├── ipc │ │ └── mod.rs │ ├── dev │ │ ├── mod.rs │ │ ├── interrupt │ │ │ ├── virtual_interrupt.rs │ │ │ ├── event_interrupt.rs │ │ │ └── pci_interrupt.rs │ │ ├── pci │ │ │ ├── pio.rs │ │ │ └── mod.rs │ │ ├── iommu.rs │ │ ├── resource.rs │ │ ├── bti.rs │ │ └── pmt.rs │ ├── signal │ │ ├── mod.rs │ │ ├── event.rs │ │ ├── eventpair.rs │ │ ├── timer.rs │ │ └── port_packet.rs │ ├── lib.rs │ ├── task │ │ ├── suspend_token.rs │ │ ├── mod.rs │ │ ├── exception.rs │ │ └── thread │ │ │ └── thread_state.rs │ ├── vm │ │ ├── mod.rs │ │ └── vmo │ │ │ └── slice.rs │ ├── object │ │ ├── handle.rs │ │ └── signal.rs │ └── debuglog.rs └── Cargo.toml ├── linux-syscall ├── src │ ├── file │ │ ├── poll.rs │ │ ├── mod.rs │ │ └── fd.rs │ ├── time.rs │ ├── util.rs │ ├── misc.rs │ └── vm.rs ├── Cargo.toml └── build.rs ├── prebuilt ├── linux │ └── libc-libos.so └── zircon │ ├── arm64 │ ├── bringup.zbi │ ├── libzircon.so │ ├── userboot.so │ ├── core-tests.zbi │ ├── libzircon-libos.so │ └── userboot-libos.so │ └── x64 │ ├── bringup.zbi │ ├── core-tests.zbi │ ├── libzircon.so │ ├── userboot.so │ ├── libzircon-libos.so │ └── userboot-libos.so ├── Cargo.toml ├── kernel-hal-bare ├── src │ └── arch │ │ ├── mod.rs │ │ ├── x86_64 │ │ ├── keyboard.rs │ │ └── acpi_table.rs │ │ └── riscv.rs └── Cargo.toml ├── zircon-syscall ├── src │ ├── cprng.rs │ ├── debug.rs │ ├── system.rs │ ├── resource.rs │ ├── exception.rs │ ├── port.rs │ ├── fifo.rs │ ├── handle.rs │ ├── debuglog.rs │ ├── signal.rs │ ├── socket.rs │ ├── futex.rs │ └── time.rs ├── Cargo.toml └── build.rs ├── linux-object ├── src │ ├── lib.rs │ ├── fs │ │ ├── device.rs │ │ ├── ioctl.rs │ │ ├── pseudo.rs │ │ ├── random.rs │ │ └── stdio.rs │ ├── thread.rs │ └── loader │ │ ├── mod.rs │ │ └── abi.rs └── Cargo.toml ├── Makefile ├── kernel-hal ├── Cargo.toml └── src │ ├── context.rs │ ├── lib.rs │ ├── user_io_vec.rs │ ├── future.rs │ └── vdso.rs ├── zCore ├── src │ ├── lang.rs │ ├── arch │ │ └── x86_64 │ │ │ └── linker.ld │ ├── logging.rs │ ├── main.rs │ └── memory.rs ├── x86_64.json ├── rboot.conf ├── Cargo.toml └── Makefile ├── kernel-hal-unix ├── Cargo.toml └── src │ └── macos.rs ├── zircon-loader ├── Cargo.toml └── src │ ├── main.rs │ └── kcounter.rs ├── linux-loader ├── Cargo.toml └── src │ ├── main.rs │ └── lib.rs ├── LICENSE ├── scripts ├── gen-prebuilt.sh ├── testcases.txt ├── core-tests.py └── zcore.patch ├── README.md └── .github └── workflows └── main.yml /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly-2020-06-04 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | prebuilt/**/* filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rboot"] 2 | path = rboot 3 | url = https://github.com/rcore-os/rboot.git 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/target 3 | **/*.rs.bk 4 | Cargo.lock 5 | /rootfs 6 | /prebuilt/linux/alpine* 7 | .idea 8 | -------------------------------------------------------------------------------- /zircon-object/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod block_range; 2 | #[cfg(feature = "elf")] 3 | pub mod elf_loader; 4 | pub mod kcounter; 5 | -------------------------------------------------------------------------------- /linux-syscall/src/file/poll.rs: -------------------------------------------------------------------------------- 1 | //! IO Multiplex operations 2 | //! 3 | //! - select4 4 | //! - poll, ppoll 5 | //! - epoll: create, ctl, wait 6 | -------------------------------------------------------------------------------- /zircon-object/src/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for IPC. 2 | 3 | mod channel; 4 | mod fifo; 5 | mod socket; 6 | 7 | pub use self::{channel::*, fifo::*, socket::*}; 8 | -------------------------------------------------------------------------------- /prebuilt/linux/libc-libos.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:82b99308868cdd5c455c33717ad6a1ab8c9cb14300bd254cda076c64c0b34709 3 | size 2858080 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/arm64/bringup.zbi: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:80a7f5448c118d32d72587ea239cfcb2b8b155fdcff99aace7adebed260e607d 3 | size 36028904 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/arm64/libzircon.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3eac9dbed9e12d792b82fa34947f97bdf7a2501101761f11b9cd4b728ac00d1c 3 | size 173688 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/arm64/userboot.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:6930cec1065da04d018f29f8bfbf86d7b2975518c705a891556cbf47a19afc1e 3 | size 705192 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/x64/bringup.zbi: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:d1c6921c22c6b3b224c7f0887438ccf00506a53d8bd36c9730499ab537d17f0a 3 | size 43867640 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/x64/core-tests.zbi: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:1c9a1caeb0a72bf31f895b5684690901890b664a85245bd4a31884c667476009 3 | size 4761264 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/x64/libzircon.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:f3d8c44a25ba8dba31458d2a54025a7dfe6b2af24e20e25562f258fc64c3dd02 3 | size 165448 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/x64/userboot.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2fb2ab1e425fc8f36db9d244caaee983dfd939006ac3a7e20f40ba51985b32a3 3 | size 841584 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/arm64/core-tests.zbi: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2e4a78b14a4351e52625d318889de2baff719c137c8d545b82371444f6fd1bef 3 | size 3625864 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/arm64/libzircon-libos.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:32e92b46c5272d4c452e4f484efc38a758fd4cd963b33c9e648d01bdffe8e4e7 3 | size 181512 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/arm64/userboot-libos.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:b2bc2ee5b1faffd6345caa411d210d50b4a59eb5fd1879083715808989ba68a9 3 | size 705192 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/x64/libzircon-libos.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:8c89bd7b81faf645fe4fddfdb3d5b92fce24f49499f31a22a049b361e2d4cd9f 3 | size 162784 4 | -------------------------------------------------------------------------------- /prebuilt/zircon/x64/userboot-libos.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:faa39e06c2f70d851f45e19ad0efd50f328d912ecc1cb8bcfd6933f169a669ad 3 | size 841584 4 | -------------------------------------------------------------------------------- /zircon-object/src/dev/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod bti; 4 | mod interrupt; 5 | mod iommu; 6 | mod pci; 7 | mod pmt; 8 | mod resource; 9 | 10 | pub use self::{bti::*, interrupt::*, iommu::*, pci::*, pmt::*, resource::*}; 11 | -------------------------------------------------------------------------------- /zircon-object/src/signal/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for signaling and waiting. 2 | 3 | use super::*; 4 | 5 | mod event; 6 | mod eventpair; 7 | mod futex; 8 | mod port; 9 | mod timer; 10 | 11 | pub use self::{event::*, eventpair::*, futex::*, port::*, timer::*}; 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "zircon-object", 4 | "zircon-syscall", 5 | "zircon-loader", 6 | "linux-object", 7 | "linux-syscall", 8 | "linux-loader", 9 | "kernel-hal-unix", 10 | "kernel-hal", 11 | ] 12 | 13 | exclude = [ 14 | "zCore", 15 | "rboot", 16 | ] 17 | -------------------------------------------------------------------------------- /linux-syscall/src/file/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use bitflags::bitflags; 3 | use linux_object::fs::vfs::{FileType, FsError}; 4 | use linux_object::fs::*; 5 | 6 | mod dir; 7 | mod fd; 8 | #[allow(clippy::module_inception)] 9 | mod file; 10 | mod poll; 11 | mod stat; 12 | 13 | use self::dir::AtFlags; 14 | -------------------------------------------------------------------------------- /kernel-hal-bare/src/arch/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] 2 | mod riscv; 3 | #[cfg(target_arch = "x86_64")] 4 | mod x86_64; 5 | 6 | #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] 7 | pub use self::riscv::*; 8 | #[cfg(target_arch = "x86_64")] 9 | pub use self::x86_64::*; 10 | -------------------------------------------------------------------------------- /zircon-syscall/src/cprng.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl Syscall<'_> { 4 | pub fn sys_cprng_draw_once(&self, mut buf: UserOutPtr, len: usize) -> ZxResult { 5 | info!("cprng_draw_once: buf=({:?}; {:?})", buf, len); 6 | let mut res = vec![0u8; len]; 7 | kernel_hal::fill_random(&mut res); 8 | buf.write_array(&res)?; 9 | Ok(()) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /linux-object/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Linux kernel objects 2 | 3 | #![no_std] 4 | #![deny(warnings, unsafe_code, unused_must_use, unreachable_patterns)] 5 | #![feature(bool_to_option)] 6 | 7 | extern crate alloc; 8 | 9 | #[macro_use] 10 | extern crate log; 11 | 12 | // layer 0 13 | pub mod error; 14 | 15 | // layer 1 16 | pub mod fs; 17 | 18 | // layer 2 19 | pub mod loader; 20 | pub mod process; 21 | pub mod thread; 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ROOTFS_TAR := alpine-minirootfs-3.12.0-x86_64.tar.gz 2 | ROOTFS_URL := http://dl-cdn.alpinelinux.org/alpine/v3.12/releases/x86_64/$(ROOTFS_TAR) 3 | 4 | .PHONY: rootfs 5 | 6 | prebuilt/linux/$(ROOTFS_TAR): 7 | wget $(ROOTFS_URL) -O $@ 8 | 9 | rootfs: prebuilt/linux/$(ROOTFS_TAR) 10 | rm -rf rootfs && mkdir -p rootfs 11 | tar xf $< -C rootfs 12 | cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1 13 | -------------------------------------------------------------------------------- /kernel-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL interface definations." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | bitflags = "1.2" 12 | trapframe = "0.4.1" 13 | numeric-enum-macro = "0.2" 14 | acpi = "1.0.0" 15 | -------------------------------------------------------------------------------- /zCore/src/lang.rs: -------------------------------------------------------------------------------- 1 | // Rust language features implementations 2 | 3 | use core::alloc::Layout; 4 | use core::panic::PanicInfo; 5 | use core::sync::atomic::spin_loop_hint; 6 | use log::*; 7 | use zircon_object::util::kcounter::KCounterDescriptorArray; 8 | 9 | #[panic_handler] 10 | fn panic(info: &PanicInfo) -> ! { 11 | error!("\n\n{}", info); 12 | error!("{:#?}", KCounterDescriptorArray::get()); 13 | loop { 14 | spin_loop_hint(); 15 | } 16 | } 17 | 18 | #[lang = "oom"] 19 | fn oom(_: Layout) -> ! { 20 | panic!("out of memory"); 21 | } 22 | -------------------------------------------------------------------------------- /zircon-object/src/dev/interrupt/virtual_interrupt.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[derive(Default)] 4 | pub struct VirtualInterrupt {} 5 | 6 | impl VirtualInterrupt { 7 | pub fn new() -> Box { 8 | Default::default() 9 | } 10 | } 11 | 12 | impl InterruptTrait for VirtualInterrupt { 13 | fn mask(&self) {} 14 | fn unmask(&self) {} 15 | fn register_handler(&self, _handle: Box) -> ZxResult { 16 | Ok(()) 17 | } 18 | fn unregister_handler(&self) -> ZxResult { 19 | Ok(()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /linux-syscall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linux-syscall" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Linux syscalls implementation" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | spin = "0.5" 13 | bitflags = "1.2" 14 | numeric-enum-macro = "0.2" 15 | zircon-object = { path = "../zircon-object" } 16 | linux-object = { path = "../linux-object" } 17 | kernel-hal = { path = "../kernel-hal" } 18 | -------------------------------------------------------------------------------- /kernel-hal-unix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal-unix" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL implementation on Linux and macOS." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | libc = "0.2" 13 | tempfile = "3" 14 | bitflags = "1.2" 15 | lazy_static = "1.4" 16 | kernel-hal = { path = "../kernel-hal" } 17 | async-std = "1.5" 18 | git-version = "0.3" 19 | trapframe = "0.4.1" 20 | -------------------------------------------------------------------------------- /zircon-syscall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-syscall" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Zircon syscalls implementation" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | spin = "0.5" 13 | bitflags = "1.2" 14 | numeric-enum-macro = "0.2" 15 | zircon-object = { path = "../zircon-object" } 16 | kernel-hal = { path = "../kernel-hal" } 17 | futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] } 18 | -------------------------------------------------------------------------------- /zCore/x86_64.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "x86_64-unknown-none", 3 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", 4 | "linker-flavor": "ld.lld", 5 | "target-endian": "little", 6 | "target-pointer-width": "64", 7 | "target-c-int-width": "32", 8 | "arch": "x86_64", 9 | "os": "none", 10 | "executables": true, 11 | "linker": "rust-lld", 12 | "pre-link-args": { 13 | "ld.lld": [ 14 | "-Tsrc/arch/x86_64/linker.ld" 15 | ] 16 | }, 17 | "disable-redzone": true, 18 | "features": "-mmx,-sse,+soft-float", 19 | "panic-strategy": "abort", 20 | "eliminate-frame-pointer": false 21 | } 22 | -------------------------------------------------------------------------------- /linux-syscall/src/time.rs: -------------------------------------------------------------------------------- 1 | //use super::*; 2 | 3 | use crate::Syscall; 4 | use kernel_hal::{timer_now, user::UserOutPtr}; 5 | use linux_object::error::SysResult; 6 | 7 | #[repr(C)] 8 | #[derive(Debug, Copy, Clone)] 9 | pub struct TimeSpec { 10 | sec: usize, 11 | nsec: usize, 12 | } 13 | 14 | impl Syscall<'_> { 15 | pub fn sys_clock_gettime(&self, clock: usize, mut buf: UserOutPtr) -> SysResult { 16 | info!("clock_gettime: id={:?} buf={:?}", clock, buf); 17 | 18 | let time = timer_now(); 19 | let ts = TimeSpec { 20 | sec: time.as_secs() as usize, 21 | nsec: (time.as_nanos() % 1_000_000_000) as usize, 22 | }; 23 | buf.write(ts)?; 24 | 25 | Ok(0) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /zircon-object/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Zircon kernel objects 2 | 3 | #![no_std] 4 | #![deny(warnings, unsafe_code, unused_must_use)] 5 | #![feature(asm)] 6 | #![feature(linkage)] 7 | #![feature(drain_filter)] 8 | #![feature(get_mut_unchecked)] 9 | #![feature(naked_functions)] 10 | #![feature(ptr_offset_from)] 11 | #![feature(range_is_empty)] 12 | #![feature(new_uninit)] 13 | #![feature(const_in_array_repeat_expressions)] 14 | 15 | extern crate alloc; 16 | 17 | #[macro_use] 18 | extern crate log; 19 | 20 | #[cfg(test)] 21 | #[macro_use] 22 | extern crate std; 23 | 24 | pub mod debuglog; 25 | pub mod dev; 26 | mod error; 27 | pub mod ipc; 28 | pub mod object; 29 | pub mod signal; 30 | pub mod task; 31 | pub mod util; 32 | pub mod vm; 33 | 34 | pub use self::error::*; 35 | -------------------------------------------------------------------------------- /zircon-object/src/task/suspend_token.rs: -------------------------------------------------------------------------------- 1 | use { 2 | // super::thread::Thread, 3 | super::*, 4 | crate::object::*, 5 | alloc::sync::{Arc, Weak}, 6 | }; 7 | 8 | pub struct SuspendToken { 9 | base: KObjectBase, 10 | task: Weak, 11 | } 12 | 13 | impl_kobject!(SuspendToken); 14 | 15 | impl SuspendToken { 16 | pub fn create(task: &Arc) -> Arc { 17 | task.suspend(); 18 | Arc::new(SuspendToken { 19 | base: KObjectBase::new(), 20 | task: Arc::downgrade(task), 21 | }) 22 | } 23 | } 24 | 25 | impl Drop for SuspendToken { 26 | fn drop(&mut self) { 27 | if let Some(task) = self.task.upgrade() { 28 | task.resume(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /zCore/rboot.conf: -------------------------------------------------------------------------------- 1 | # The config file for rboot. 2 | # Place me at \EFI\Boot\rboot.conf 3 | 4 | # The address at which the kernel stack is placed. 5 | # kernel_stack_address=0xFFFFFF8000000000 6 | 7 | # The size of the kernel stack, given in number of 4KiB pages. Defaults to 512. 8 | # kernel_stack_size=128 9 | 10 | # The virtual address offset from which physical memory is mapped, as described in 11 | # https://os.phil-opp.com/paging-implementation/#map-the-complete-physical-memory 12 | physical_memory_offset=0xFFFF800000000000 13 | 14 | # The path of kernel ELF 15 | kernel_path=\EFI\zCore\zcore.elf 16 | 17 | # The resolution of graphic output 18 | resolution=1024x768 19 | 20 | initramfs=\EFI\zCore\fuchsia.zbi 21 | 22 | cmdline=LOG=warn:console.shell=true:virtcon.disable=true 23 | -------------------------------------------------------------------------------- /zircon-object/src/signal/event.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::object::*; 3 | use alloc::sync::Arc; 4 | 5 | /// Signalable event for concurrent programming 6 | /// 7 | /// ## SYNOPSIS 8 | /// 9 | /// Events are user-signalable objects. The 8 signal bits reserved for 10 | /// userspace (`ZX_USER_SIGNAL_0` through `ZX_USER_SIGNAL_7`) may be set, 11 | /// cleared, and waited upon. 12 | pub struct Event { 13 | base: KObjectBase, 14 | _counter: CountHelper, 15 | } 16 | 17 | impl_kobject!(Event 18 | fn allowed_signals(&self) -> Signal { 19 | Signal::USER_ALL | Signal::SIGNALED 20 | } 21 | ); 22 | define_count_helper!(Event); 23 | 24 | impl Event { 25 | pub fn new() -> Arc { 26 | Arc::new(Event { 27 | base: KObjectBase::default(), 28 | _counter: CountHelper::new(), 29 | }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /zircon-loader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-loader" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Zircon user program (userboot) loader" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | xmas-elf = "0.7" 13 | zircon-object = { path = "../zircon-object", features = ["elf"] } 14 | zircon-syscall = { path = "../zircon-syscall" } 15 | kernel-hal = { path = "../kernel-hal" } 16 | env_logger = { version = "0.7", optional = true } 17 | structopt = { version = "0.3", default-features = false, optional = true } 18 | kernel-hal-unix = { path = "../kernel-hal-unix", optional = true } 19 | async-std = { version = "1.5", features = ["attributes"], optional = true } 20 | 21 | [features] 22 | default = ["std"] 23 | std = ["env_logger", "structopt", "async-std", "kernel-hal-unix"] 24 | -------------------------------------------------------------------------------- /linux-object/src/fs/device.rs: -------------------------------------------------------------------------------- 1 | //! Implement Device 2 | 3 | use rcore_fs::dev::*; 4 | use spin::RwLock; 5 | 6 | pub struct MemBuf(RwLock<&'static mut [u8]>); 7 | 8 | impl MemBuf { 9 | pub fn new(buf: &'static mut [u8]) -> Self { 10 | MemBuf(RwLock::new(buf)) 11 | } 12 | } 13 | 14 | impl Device for MemBuf { 15 | fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { 16 | let slice = self.0.read(); 17 | let len = buf.len().min(slice.len() - offset); 18 | buf[..len].copy_from_slice(&slice[offset..offset + len]); 19 | Ok(len) 20 | } 21 | fn write_at(&self, offset: usize, buf: &[u8]) -> Result { 22 | let mut slice = self.0.write(); 23 | let len = buf.len().min(slice.len() - offset); 24 | slice[offset..offset + len].copy_from_slice(&buf[..len]); 25 | Ok(len) 26 | } 27 | fn sync(&self) -> Result<()> { 28 | Ok(()) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /zCore/src/arch/x86_64/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | KERNEL_BEGIN = 0xffffff0000000000; 4 | 5 | SECTIONS { 6 | 7 | . = KERNEL_BEGIN; 8 | 9 | .rodata ALIGN(4K): 10 | { 11 | *(.rodata .rodata.*) 12 | } 13 | 14 | .text ALIGN(4K): 15 | { 16 | stext = .; 17 | _copy_user_start = .; 18 | *(.text.copy_user) 19 | _copy_user_end = .; 20 | *(.text .text.*) 21 | etext = .; 22 | } 23 | 24 | .data ALIGN(4K): 25 | { 26 | PROVIDE_HIDDEN(kcounter_descriptor_begin = .); 27 | KEEP(*(.kcounter.descriptor)) 28 | PROVIDE_HIDDEN(kcounter_descriptor_end = .); 29 | 30 | *(.data .data.*) 31 | } 32 | 33 | .got ALIGN(4K): 34 | { 35 | *(.got .got.*) 36 | } 37 | 38 | .bss ALIGN(4K): 39 | { 40 | . = ALIGN(4096); 41 | PROVIDE_HIDDEN(kcounters_arena_start = .); 42 | KEEP(*(.kcounter.items)) 43 | PROVIDE_HIDDEN(kcounters_arena_end = .); 44 | . = ALIGN(4096); 45 | 46 | *(.bss .bss.*) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /linux-loader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linux-loader" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Linux programs loader and runner." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | xmas-elf = "0.7" 13 | linux-syscall = { path = "../linux-syscall" } 14 | linux-object = { path = "../linux-object" } 15 | zircon-object = { path = "../zircon-object" } 16 | kernel-hal = { path = "../kernel-hal" } 17 | rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b", optional = true } 18 | env_logger = { version = "0.7", optional = true } 19 | kernel-hal-unix = { path = "../kernel-hal-unix", optional = true } 20 | async-std = { version = "1.5", features = ["attributes"], optional = true } 21 | 22 | [features] 23 | default = ["std"] 24 | std = ["env_logger", "async-std", "kernel-hal-unix", "rcore-fs-hostfs"] 25 | -------------------------------------------------------------------------------- /zircon-object/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Task Management. 2 | 3 | use {super::*, crate::ipc::Channel, crate::signal::Port}; 4 | 5 | mod exception; 6 | mod job; 7 | mod job_policy; 8 | mod process; 9 | mod suspend_token; 10 | mod thread; 11 | 12 | pub use { 13 | self::job::*, self::job_policy::*, self::process::*, self::suspend_token::*, self::thread::*, 14 | }; 15 | 16 | /// Task (Thread, Process, or Job) 17 | pub trait Task: Sync + Send { 18 | /// Kill the task. 19 | fn kill(&self); 20 | 21 | /// Suspend the task. Currently only thread or process handles may be suspended. 22 | fn suspend(&self); 23 | 24 | /// Resume the task 25 | fn resume(&self); 26 | 27 | /// Create an exception channel on the task. 28 | fn create_exception_channel(&mut self, options: u32) -> ZxResult; 29 | 30 | /// Resume the task from a previously caught exception. 31 | fn resume_from_exception(&mut self, port: &Port, options: u32) -> ZxResult; 32 | } 33 | 34 | pub const TASK_RETCODE_SYSCALL_KILL: i64 = -1024; 35 | -------------------------------------------------------------------------------- /linux-object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linux-object" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Linux kernel objects" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | spin = "0.5" 13 | xmas-elf = "0.7" 14 | hashbrown = "0.7" 15 | zircon-object = { path = "../zircon-object", features = ["elf"] } 16 | kernel-hal = { path = "../kernel-hal" } 17 | downcast-rs = { git = "https://github.com/rcore-os/downcast-rs", rev = "a632ce1", default-features = false } 18 | rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b" } 19 | rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b" } 20 | rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b" } 21 | rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b" } 22 | rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b" } 23 | -------------------------------------------------------------------------------- /kernel-hal-bare/src/arch/x86_64/keyboard.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; 3 | use spin::Mutex; 4 | use x86_64::instructions::port::Port; 5 | 6 | /// Receive character from keyboard 7 | /// Should be called on every interrupt 8 | pub fn receive() -> Option { 9 | lazy_static! { 10 | static ref KEYBOARD: Mutex> = Mutex::new( 11 | Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore) 12 | ); 13 | } 14 | 15 | let mut keyboard = KEYBOARD.lock(); 16 | let mut data_port = Port::::new(0x60); 17 | let mut status_port = Port::::new(0x64); 18 | 19 | // Output buffer status = 1 20 | if unsafe { status_port.read() } & 1 != 0 { 21 | let scancode = unsafe { data_port.read() }; 22 | if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { 23 | return keyboard.process_keyevent(key_event); 24 | } 25 | } 26 | None 27 | } 28 | -------------------------------------------------------------------------------- /zircon-object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-object" 3 | version = "0.1.0" 4 | authors = ["Runji Wang ", "Qinglin Pan "] 5 | edition = "2018" 6 | description = "Zircon kernel objects" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [features] 11 | elf = ["xmas-elf"] 12 | 13 | [dependencies] 14 | bitflags = "1.2" 15 | spin = "0.5" 16 | log = "0.4" 17 | hashbrown = "0.7" 18 | downcast-rs = { git = "https://github.com/rcore-os/downcast-rs", rev = "a632ce1", default-features = false } 19 | kernel-hal = { path = "../kernel-hal" } 20 | numeric-enum-macro = "0.2" 21 | futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] } 22 | xmas-elf = { version = "0.7", optional = true } 23 | region-alloc = { git = "https://github.com/rzswh/region-allocator", rev = "122c7a71" } 24 | lazy_static = { version = "1.4", features = ["spin_no_std" ] } 25 | acpi = "1.0.0" 26 | 27 | [dev-dependencies] 28 | kernel-hal-unix = { path = "../kernel-hal-unix" } 29 | async-std = { version = "1.5", features = ["attributes"] } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 rCore Developers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /linux-syscall/build.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | fn main() { 4 | println!("cargo:rerun-if-changed=src/syscall.h.in"); 5 | 6 | let mut fout = std::fs::File::create("src/consts.rs").unwrap(); 7 | writeln!(fout, "// Generated by build.rs. DO NOT EDIT.").unwrap(); 8 | writeln!(fout, "use numeric_enum_macro::numeric_enum;\n").unwrap(); 9 | writeln!(fout, "numeric_enum! {{").unwrap(); 10 | writeln!(fout, "#[repr(u32)]").unwrap(); 11 | writeln!(fout, "#[derive(Debug, Eq, PartialEq)]").unwrap(); 12 | writeln!(fout, "#[allow(non_camel_case_types)]").unwrap(); 13 | writeln!(fout, "pub enum SyscallType {{").unwrap(); 14 | 15 | let data = std::fs::read_to_string("src/syscall.h.in").unwrap(); 16 | for line in data.lines() { 17 | if !line.starts_with("#define") { 18 | continue; 19 | } 20 | let mut iter = line.split_whitespace(); 21 | let _ = iter.next().unwrap(); 22 | let name = iter.next().unwrap(); 23 | let id = iter.next().unwrap(); 24 | 25 | let name = &name[5..].to_uppercase(); 26 | writeln!(fout, " {} = {},", name, id).unwrap(); 27 | } 28 | writeln!(fout, "}}").unwrap(); 29 | writeln!(fout, "}}").unwrap(); 30 | } 31 | -------------------------------------------------------------------------------- /zircon-syscall/build.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | fn main() { 4 | println!("cargo:rerun-if-changed=src/zx-syscall-numbers.h"); 5 | 6 | let mut fout = std::fs::File::create("src/consts.rs").unwrap(); 7 | writeln!(fout, "// Generated by build.rs. DO NOT EDIT.").unwrap(); 8 | writeln!(fout, "use numeric_enum_macro::numeric_enum;\n").unwrap(); 9 | writeln!(fout, "numeric_enum! {{").unwrap(); 10 | writeln!(fout, "#[repr(u32)]").unwrap(); 11 | writeln!(fout, "#[derive(Debug, Eq, PartialEq)]").unwrap(); 12 | writeln!(fout, "#[allow(non_camel_case_types)]").unwrap(); 13 | writeln!(fout, "pub enum SyscallType {{").unwrap(); 14 | 15 | let data = std::fs::read_to_string("src/zx-syscall-numbers.h").unwrap(); 16 | for line in data.lines() { 17 | if !line.starts_with("#define") { 18 | continue; 19 | } 20 | let mut iter = line.split(' '); 21 | let _ = iter.next().unwrap(); 22 | let name = iter.next().unwrap(); 23 | let id = iter.next().unwrap(); 24 | 25 | let name = &name[7..].to_uppercase(); 26 | writeln!(fout, " {} = {},", name, id).unwrap(); 27 | } 28 | writeln!(fout, "}}").unwrap(); 29 | writeln!(fout, "}}").unwrap(); 30 | } 31 | -------------------------------------------------------------------------------- /kernel-hal/src/context.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | 3 | #[repr(C, align(16))] 4 | #[derive(Debug, Copy, Clone)] 5 | pub struct VectorRegs { 6 | pub fcw: u16, 7 | pub fsw: u16, 8 | pub ftw: u8, 9 | pub _pad0: u8, 10 | pub fop: u16, 11 | pub fip: u32, 12 | pub fcs: u16, 13 | pub _pad1: u16, 14 | 15 | pub fdp: u32, 16 | pub fds: u16, 17 | pub _pad2: u16, 18 | pub mxcsr: u32, 19 | pub mxcsr_mask: u32, 20 | 21 | pub mm: [U128; 8], 22 | pub xmm: [U128; 16], 23 | pub reserved: [U128; 3], 24 | pub available: [U128; 3], 25 | } 26 | 27 | // https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol1/o_7281d5ea06a5b67a-274.html 28 | impl Default for VectorRegs { 29 | fn default() -> Self { 30 | VectorRegs { 31 | fcw: 0x37f, 32 | mxcsr: 0x1f80, 33 | ..unsafe { core::mem::zeroed() } 34 | } 35 | } 36 | } 37 | 38 | // workaround: libcore has bug on Debug print u128 ?? 39 | #[derive(Default, Clone, Copy)] 40 | #[repr(C, align(16))] 41 | pub struct U128(pub [u64; 2]); 42 | 43 | impl fmt::Debug for U128 { 44 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 45 | write!(f, "{:#016x}{:016x}", self.0[1], self.0[0]) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /kernel-hal-bare/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal-bare" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL implementation for bare metal environment." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | spin = "0.5" 13 | git-version = "0.3" 14 | executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" } 15 | trapframe = "0.4.1" 16 | kernel-hal = { path = "../kernel-hal" } 17 | naive-timer = "0.1.0" 18 | lazy_static = { version = "1.4", features = ["spin_no_std" ] } 19 | 20 | [target.'cfg(target_arch = "x86_64")'.dependencies] 21 | x86_64 = "0.11" 22 | uart_16550 = "0.2.6" 23 | raw-cpuid = "8.0" 24 | pc-keyboard = "0.5" 25 | apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" } 26 | x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "257d695" } 27 | rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "a980897b" } 28 | acpi = "1.0.0" 29 | 30 | [target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies] 31 | riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"], rev = "c62af46" } 32 | -------------------------------------------------------------------------------- /zircon-syscall/src/debug.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use zircon_object::dev::*; 3 | 4 | impl Syscall<'_> { 5 | pub fn sys_debug_write(&self, buf: UserInPtr, len: usize) -> ZxResult { 6 | info!("debug.write: buf=({:?}; {:#x})", buf, len); 7 | let data = buf.read_array(len)?; 8 | kernel_hal::serial_write(core::str::from_utf8(&data).unwrap()); 9 | Ok(()) 10 | } 11 | 12 | pub async fn sys_debug_read( 13 | &self, 14 | handle: HandleValue, 15 | mut buf: UserOutPtr, 16 | buf_size: u32, 17 | mut actual: UserOutPtr, 18 | ) -> ZxResult { 19 | info!( 20 | "debug.read: handle={:#x}, buf=({:?}; {:#x})", 21 | handle, buf, buf_size 22 | ); 23 | let proc = self.thread.proc(); 24 | proc.get_object::(handle)? 25 | .validate(ResourceKind::ROOT)?; 26 | // FIXME: To make 'console' work, now debug_read is a blocking call. 27 | // But it should be non-blocking. 28 | // let mut vec = vec![0u8; buf_size as usize]; 29 | // let len = kernel_hal::serial_read(&mut vec); 30 | // buf.write_array(&vec[..len])?; 31 | // actual.write(len as u32)?; 32 | let c = kernel_hal::serial_getchar().await; 33 | buf.write_array(&[c])?; 34 | actual.write(1)?; 35 | Ok(()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /zircon-syscall/src/system.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use { 3 | super::*, 4 | alloc::boxed::Box, 5 | zircon_object::{signal::Event, task::Job}, 6 | }; 7 | 8 | impl Syscall<'_> { 9 | pub fn sys_system_get_event( 10 | &self, 11 | root_job: HandleValue, 12 | kind: u32, 13 | mut out: UserOutPtr, 14 | ) -> ZxResult { 15 | info!( 16 | "system.get_event: root_job={:#x}, kind={:#x}, out_ptr={:#x?}", 17 | root_job, kind, out 18 | ); 19 | match kind { 20 | EVENT_OUT_OF_MEMORY => { 21 | let proc = self.thread.proc(); 22 | proc.get_object_with_rights::(root_job, Rights::MANAGE_PROCESS)? 23 | .check_root_job()?; 24 | let event = Event::new(); 25 | event.add_signal_callback(Box::new(|_| { 26 | panic!("Out Of Memory!"); 27 | })); 28 | let event_handle = proc.add_handle(Handle::new(event, Rights::DEFAULT_EVENT)); 29 | out.write(event_handle)?; 30 | Ok(()) 31 | } 32 | _ => unimplemented!(), 33 | } 34 | } 35 | } 36 | 37 | const EVENT_OUT_OF_MEMORY: u32 = 1; 38 | const EVENT_MEMORY_PRESSURE_CRITICAL: u32 = 2; 39 | const EVENT_MEMORY_PRESSURE_WARNING: u32 = 3; 40 | const EVENT_MEMORY_PRESSURE_NORMAL: u32 = 4; 41 | -------------------------------------------------------------------------------- /kernel-hal/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Hardware Abstraction Layer 2 | 3 | #![no_std] 4 | #![feature(linkage)] 5 | #![deny(warnings)] 6 | 7 | extern crate alloc; 8 | 9 | pub mod defs { 10 | use bitflags::bitflags; 11 | use numeric_enum_macro::numeric_enum; 12 | 13 | bitflags! { 14 | pub struct MMUFlags: usize { 15 | #[allow(clippy::identity_op)] 16 | const CACHE_1 = 1 << 0; 17 | const CACHE_2 = 1 << 1; 18 | const READ = 1 << 2; 19 | const WRITE = 1 << 3; 20 | const EXECUTE = 1 << 4; 21 | const USER = 1 << 5; 22 | } 23 | } 24 | numeric_enum! { 25 | #[repr(u32)] 26 | #[derive(Debug, PartialEq, Clone, Copy)] 27 | pub enum CachePolicy { 28 | Cached = 0, 29 | Uncached = 1, 30 | UncachedDevice = 2, 31 | WriteCombining = 3, 32 | } 33 | } 34 | pub const CACHE_POLICY_MASK: u32 = 3; 35 | 36 | pub type PhysAddr = usize; 37 | pub type VirtAddr = usize; 38 | pub type DevVAddr = usize; 39 | pub const PAGE_SIZE: usize = 0x1000; 40 | } 41 | 42 | mod context; 43 | mod dummy; 44 | mod future; 45 | pub mod user; 46 | pub mod user_io_vec; 47 | pub mod vdso; 48 | 49 | pub use self::context::*; 50 | pub use self::defs::*; 51 | pub use self::dummy::*; 52 | pub use self::future::*; 53 | pub use trapframe::{GeneralRegs, UserContext}; 54 | -------------------------------------------------------------------------------- /zircon-syscall/src/resource.rs: -------------------------------------------------------------------------------- 1 | use {super::*, core::convert::TryFrom, zircon_object::dev::*}; 2 | 3 | impl Syscall<'_> { 4 | #[allow(clippy::too_many_arguments)] 5 | pub fn sys_resource_create( 6 | &self, 7 | parent_rsrc: HandleValue, 8 | options: u32, 9 | base: u64, 10 | size: u64, 11 | name: UserInPtr, 12 | name_size: u64, 13 | mut out: UserOutPtr, 14 | ) -> ZxResult { 15 | info!( 16 | "resource.create: parent={:#x}, options={:#x}, base={:#X}, size={:#x}", 17 | parent_rsrc, options, base, size 18 | ); 19 | let name = name.read_string(name_size as usize)?; 20 | info!("name={:?}", name); 21 | let proc = self.thread.proc(); 22 | let parent_rsrc = proc.get_object_with_rights::(parent_rsrc, Rights::WRITE)?; 23 | let kind = ResourceKind::try_from(options & 0xFFFF).map_err(|_| ZxError::INVALID_ARGS)?; 24 | let flags = ResourceFlags::from_bits(options & 0xFFFF_0000).ok_or(ZxError::INVALID_ARGS)?; 25 | parent_rsrc.validate_ranged_resource(kind, base as usize, size as usize)?; 26 | parent_rsrc.check_exclusive(flags)?; 27 | let rsrc = Resource::create(&name, kind, base as usize, size as usize, flags); 28 | let handle = proc.add_handle(Handle::new(rsrc, Rights::DEFAULT_RESOURCE)); 29 | out.write(handle)?; 30 | Ok(()) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /linux-object/src/fs/ioctl.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | // for IOR and IOW: 4 | // 32bits total, command in lower 16bits, size of the parameter structure in the lower 14 bits of the upper 16 bits 5 | // higher 2 bits: 01 = write, 10 = read 6 | 7 | #[cfg(not(target_arch = "mips"))] 8 | pub const TCGETS: usize = 0x5401; 9 | #[cfg(target_arch = "mips")] 10 | pub const TCGETS: usize = 0x540D; 11 | 12 | #[cfg(not(target_arch = "mips"))] 13 | pub const TIOCGPGRP: usize = 0x540F; 14 | // _IOR('t', 119, int) 15 | #[cfg(target_arch = "mips")] 16 | pub const TIOCGPGRP: usize = 0x4_004_74_77; 17 | 18 | #[cfg(not(target_arch = "mips"))] 19 | pub const TIOCSPGRP: usize = 0x5410; 20 | // _IOW('t', 118, int) 21 | #[cfg(target_arch = "mips")] 22 | pub const TIOCSPGRP: usize = 0x8_004_74_76; 23 | 24 | #[cfg(not(target_arch = "mips"))] 25 | pub const TIOCGWINSZ: usize = 0x5413; 26 | // _IOR('t', 104, struct winsize) 27 | #[cfg(target_arch = "mips")] 28 | pub const TIOCGWINSZ: usize = 0x4_008_74_68; 29 | 30 | #[cfg(not(target_arch = "mips"))] 31 | pub const FIONCLEX: usize = 0x5450; 32 | #[cfg(target_arch = "mips")] 33 | pub const FIONCLEX: usize = 0x6602; 34 | 35 | #[cfg(not(target_arch = "mips"))] 36 | pub const FIOCLEX: usize = 0x5451; 37 | #[cfg(target_arch = "mips")] 38 | pub const FIOCLEX: usize = 0x6601; 39 | 40 | // rustc using pipe and ioctl pipe file with this request id 41 | // for non-blocking/blocking IO control setting 42 | pub const FIONBIO: usize = 0x5421; 43 | -------------------------------------------------------------------------------- /zCore/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zcore" 3 | version = "0.1.0" 4 | authors = ["PanQL "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [features] 10 | graphic = [] 11 | zircon = ["zircon-loader"] 12 | linux = ["linux-loader", "linux-object", "rcore-fs-sfs"] 13 | 14 | [profile.release] 15 | lto = true 16 | 17 | [dependencies] 18 | log = "0.4" 19 | spin = "0.5" 20 | buddy_system_allocator = "0.4.0" 21 | rlibc-opt = { git = "https://github.com/rcore-os/rlibc-opt.git", rev = "0ab1d1e" } 22 | rboot = { path = "../rboot", default-features = false } 23 | kernel-hal-bare = { path = "../kernel-hal-bare" } 24 | lazy_static = { version = "1.4", features = ["spin_no_std" ] } 25 | bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "03bd9909" } 26 | trapframe = "0.4.1" 27 | executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" } 28 | zircon-object = { path = "../zircon-object" } 29 | zircon-loader = { path = "../zircon-loader", default-features = false, optional = true } 30 | linux-loader = { path = "../linux-loader", default-features = false, optional = true } 31 | linux-object = { path = "../linux-object", default-features = false, optional = true } 32 | rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b", optional = true } 33 | 34 | [target.'cfg(target_arch = "x86_64")'.dependencies] 35 | x86_64 = "0.11" 36 | -------------------------------------------------------------------------------- /scripts/gen-prebuilt.sh: -------------------------------------------------------------------------------- 1 | # Generate prebuilt/zircon from modified fuchsia source 2 | 3 | OUTDIR=zcore_prebuilt 4 | ARCH=${1:-x64} 5 | mkdir -p ${OUTDIR} 6 | 7 | # set build target 8 | ./scripts/fx set bringup.${ARCH} --with-base //garnet/packages/tests:zircon --with //src/tests/microbenchmarks --with //src/virtualization/tests:hypervisor_tests_pkg 9 | 10 | # apply zircon-libos.patch and build once 11 | patch -p1 < zircon-libos.patch 12 | ./scripts/fx build default.zircon 13 | patch -p1 -R < zircon-libos.patch 14 | cp out/default.zircon/userboot-${ARCH}-clang/obj/kernel/lib/userabi/userboot/userboot.so ${OUTDIR}/userboot-libos.so 15 | cp out/default.zircon/user.vdso-${ARCH}-clang.shlib/obj/system/ulib/zircon/libzircon.so.debug ${OUTDIR}/libzircon-libos.so 16 | 17 | # apply zcore.patch and build again 18 | patch -p1 < zcore.patch 19 | ./scripts/fx build 20 | patch -p1 -R < zcore.patch 21 | cp out/default.zircon/userboot-${ARCH}-clang/obj/kernel/lib/userabi/userboot/userboot.so ${OUTDIR} 22 | cp out/default.zircon/user.vdso-${ARCH}-clang.shlib/obj/system/ulib/zircon/libzircon.so.debug ${OUTDIR}/libzircon.so 23 | cp out/default/bringup.zbi ${OUTDIR} 24 | cp out/default/obj/zircon/system/utest/core/core-tests.zbi ${OUTDIR} 25 | 26 | # remove kernel and cmdline from zbi 27 | cd ${OUTDIR} 28 | ../out/default.zircon/tools/zbi -x bringup.zbi -D bootfs 29 | ../out/default.zircon/tools/zbi bootfs -o bringup.zbi 30 | rm -r bootfs 31 | cd .. 32 | 33 | # finished 34 | echo 'generate prebuilt at' ${OUTDIR} 35 | -------------------------------------------------------------------------------- /zircon-syscall/src/exception.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | zircon_object::{ipc::Channel, task::*}, 4 | }; 5 | 6 | impl Syscall<'_> { 7 | pub fn sys_create_exception_channel( 8 | &self, 9 | task: HandleValue, 10 | option: u32, 11 | mut out: UserOutPtr, 12 | ) -> ZxResult { 13 | info!( 14 | "create_exception_channel: task={:#x}, options={:#x}, out={:#x?}", 15 | task, option, out 16 | ); 17 | let proc = self.thread.proc(); 18 | let task = proc.get_dyn_object_with_rights( 19 | task, 20 | Rights::INSPECT | Rights::DUPLICATE | Rights::TRANSFER | Rights::MANAGE_THREAD, 21 | )?; 22 | let exceptionate = task 23 | .clone() 24 | .downcast_arc::() 25 | .map(|x| x.get_exceptionate()) 26 | .or_else(|_| { 27 | task.clone() 28 | .downcast_arc::() 29 | .map(|x| x.get_exceptionate()) 30 | }) 31 | .or_else(|_| { 32 | task.clone() 33 | .downcast_arc::() 34 | .map(|x| x.get_exceptionate()) 35 | }) 36 | .map_err(|_| ZxError::WRONG_TYPE)?; 37 | let (end0, end1) = Channel::create(); 38 | exceptionate.set_channel(end0); 39 | let user_end = proc.add_handle(Handle::new(end1, Rights::DEFAULT_CHANNEL)); 40 | out.write(user_end)?; 41 | Ok(()) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/testcases.txt: -------------------------------------------------------------------------------- 1 | * 2 | -Bti.NoDelayedUnpin 3 | -Bti.DecommitRace 4 | -ProcessDebugVDSO.* 5 | -HandleCloseTest.ManyDuplicateTest* 6 | -JobTest.* 7 | -JobGetInfoTest.InfoJobProcessesPartiallyUnmappedBufferIsInvalidArgs 8 | -JobGetInfoTest.InfoJobChildrenPartiallyUnmappedBufferIsInvalidArgs 9 | -PortTest.AsyncWaitInvalidOption 10 | -PortTest.Timestamp 11 | -PortStressTest.WaitSignalCancel 12 | -PortStressTest.SignalCloseWait 13 | -ProcessTest.ProcessWaitAsyncCancelSelf 14 | -Pthread.* 15 | -PThreadBarrierTest.SingleThreadWinsBarrierObjectResetsBetweenIterations 16 | -SyncMutex.NoRecursion 17 | -Threads.ThreadStartWithZeroInstructionPointer 18 | -Threads.SuspendMultiple 19 | -Threads.Reading*State 20 | -Threads.WriteReadDebugRegisterState 21 | -Threads.DebugRegistersValidation 22 | -Threads.NoncanonicalRipAddressIRETQ 23 | -Threads.KillSuspendedThread 24 | -Threads.StartSuspendedThread 25 | -Vmar.ProtectOverDemandPagedTest 26 | -Vmar.ProtectLargeUncomittedTest 27 | -Vmar.UnmapLargeUncommittedTest 28 | -Vmar.NestedRegionPermsTest 29 | -Vmar.MapSpecificOverwriteTest 30 | -Vmar.MapOverDestroyedTest 31 | -VmoTestCase.ReadOnlyMap 32 | -VmoTestCase.NoPermMap 33 | -VmoTestCase.NoPermProtect 34 | -VmoTestCase.Commit 35 | -VmoTestCase.CacheOp 36 | -VmoTestCase.ResizeHazard 37 | -VmoTestCase.Cache* 38 | -VmoClone2TestCase.PinClonePages 39 | -VersionTest.* 40 | -BadAccessTest.* 41 | -DefaultExceptionHandlerTest.* 42 | -InterruptTest.BindTriggeredIrqToPort 43 | -InterruptTest.WaitThreadFunctionsAfterSuspendResume 44 | -*Profile* 45 | -SystemEvent.* 46 | -Resource.* 47 | -------------------------------------------------------------------------------- /linux-syscall/src/util.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use kernel_hal::user::*; 3 | use linux_object::error::LxResult; 4 | 5 | #[derive(Debug)] 6 | #[repr(C)] 7 | pub struct IoVec { 8 | /// Starting address 9 | base: UserPtr, 10 | /// Number of bytes to transfer 11 | len: usize, 12 | } 13 | 14 | /// A valid IoVecs request from user 15 | #[derive(Debug)] 16 | pub struct IoVecs { 17 | vec: Vec>, 18 | } 19 | 20 | impl IoVecs

{ 21 | pub fn new(ptr: UserInPtr>, count: usize) -> LxResult { 22 | Ok(IoVecs { 23 | vec: ptr.read_array(count)?, 24 | }) 25 | } 26 | 27 | pub fn total_len(&self) -> usize { 28 | self.vec.iter().map(|vec| vec.len).sum() 29 | } 30 | } 31 | 32 | impl IoVecs

{ 33 | pub fn read_to_vec(&self) -> LxResult> { 34 | let mut buf = Vec::new(); 35 | for vec in self.vec.iter() { 36 | buf.extend(vec.base.read_array(vec.len)?); 37 | } 38 | Ok(buf) 39 | } 40 | } 41 | 42 | impl IoVecs

{ 43 | pub fn write_from_buf(&mut self, mut buf: &[u8]) -> LxResult { 44 | let buf_len = buf.len(); 45 | for vec in self.vec.iter_mut() { 46 | let copy_len = vec.len.min(buf.len()); 47 | if copy_len == 0 { 48 | continue; 49 | } 50 | vec.base.write_array(&buf[..copy_len])?; 51 | buf = &buf[copy_len..]; 52 | } 53 | Ok(buf_len - buf.len()) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /linux-object/src/fs/pseudo.rs: -------------------------------------------------------------------------------- 1 | //! Pseudo file system INode 2 | 3 | use alloc::vec::Vec; 4 | use core::any::Any; 5 | 6 | use rcore_fs::vfs::*; 7 | 8 | pub struct Pseudo { 9 | content: Vec, 10 | type_: FileType, 11 | } 12 | 13 | impl Pseudo { 14 | pub fn new(s: &str, type_: FileType) -> Self { 15 | Pseudo { 16 | content: Vec::from(s.as_bytes()), 17 | type_, 18 | } 19 | } 20 | } 21 | 22 | impl INode for Pseudo { 23 | fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { 24 | if offset >= self.content.len() { 25 | return Ok(0); 26 | } 27 | let len = (self.content.len() - offset).min(buf.len()); 28 | buf[..len].copy_from_slice(&self.content[offset..offset + len]); 29 | Ok(len) 30 | } 31 | fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { 32 | Err(FsError::NotSupported) 33 | } 34 | fn poll(&self) -> Result { 35 | Ok(PollStatus { 36 | read: true, 37 | write: false, 38 | error: false, 39 | }) 40 | } 41 | fn metadata(&self) -> Result { 42 | Ok(Metadata { 43 | dev: 0, 44 | inode: 0, 45 | size: self.content.len(), 46 | blk_size: 0, 47 | blocks: 0, 48 | atime: Timespec { sec: 0, nsec: 0 }, 49 | mtime: Timespec { sec: 0, nsec: 0 }, 50 | ctime: Timespec { sec: 0, nsec: 0 }, 51 | type_: self.type_, 52 | mode: 0, 53 | nlinks: 0, 54 | uid: 0, 55 | gid: 0, 56 | rdev: 0, 57 | }) 58 | } 59 | fn as_any_ref(&self) -> &dyn Any { 60 | self 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /zircon-object/src/task/exception.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use { 4 | super::*, crate::ipc::Channel, crate::object::*, alloc::sync::Arc, alloc::vec::Vec, 5 | core::mem::size_of, spin::Mutex, 6 | }; 7 | 8 | /// Kernel-owned exception channel endpoint. 9 | pub struct Exceptionate { 10 | type_: ExceptionChannelType, 11 | inner: Mutex, 12 | } 13 | 14 | struct ExceptionateInner { 15 | channel: Option>, 16 | thread_rights: Rights, 17 | process_rights: Rights, 18 | } 19 | 20 | impl Exceptionate { 21 | pub fn new(type_: ExceptionChannelType) -> Arc { 22 | Arc::new(Exceptionate { 23 | type_, 24 | inner: Mutex::new(ExceptionateInner { 25 | channel: None, 26 | thread_rights: Rights::empty(), 27 | process_rights: Rights::empty(), 28 | }), 29 | }) 30 | } 31 | 32 | pub fn set_channel(&self, channel: Arc) { 33 | let mut inner = self.inner.lock(); 34 | inner.channel.replace(channel); 35 | } 36 | 37 | pub fn get_channel(&self) -> Option> { 38 | let inner = self.inner.lock(); 39 | inner.channel.clone() 40 | } 41 | } 42 | 43 | #[repr(C)] 44 | pub struct ExceptionInfo { 45 | pub tid: KoID, 46 | pub pid: KoID, 47 | pub type_: ExceptionChannelType, 48 | pub padding: u32, 49 | } 50 | 51 | #[repr(u32)] 52 | pub enum ExceptionChannelType { 53 | None = 0, 54 | Debugger = 1, 55 | Thread = 2, 56 | Process = 3, 57 | Job = 4, 58 | JobDebugger = 5, 59 | } 60 | 61 | impl ExceptionInfo { 62 | #[allow(unsafe_code)] 63 | pub fn pack(&self) -> Vec { 64 | let buf: [u8; size_of::()] = unsafe { core::mem::transmute_copy(self) }; 65 | Vec::from(buf) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /zircon-syscall/src/port.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | zircon_object::{signal::*, task::*}, 4 | }; 5 | 6 | impl Syscall<'_> { 7 | pub fn sys_port_create(&self, options: u32, mut out: UserOutPtr) -> ZxResult { 8 | info!("port.create: options={:#x}", options); 9 | let port_handle = Handle::new(Port::new(options), Rights::DEFAULT_PORT); 10 | let handle_value = self.thread.proc().add_handle(port_handle); 11 | out.write(handle_value)?; 12 | Ok(()) 13 | } 14 | 15 | pub async fn sys_port_wait( 16 | &self, 17 | handle_value: HandleValue, 18 | deadline: Deadline, 19 | mut packet_res: UserOutPtr, 20 | ) -> ZxResult { 21 | info!( 22 | "port.wait: handle={}, deadline={:?}", 23 | handle_value, deadline 24 | ); 25 | assert_eq!(core::mem::size_of::(), 48); 26 | let proc = self.thread.proc(); 27 | let port = proc.get_object_with_rights::(handle_value, Rights::READ)?; 28 | let future = port.wait(); 29 | pin_mut!(future); 30 | let packet = self 31 | .thread 32 | .blocking_run(future, ThreadState::BlockedPort, deadline.into()) 33 | .await?; 34 | packet_res.write(packet)?; 35 | Ok(()) 36 | } 37 | 38 | pub fn sys_port_queue( 39 | &self, 40 | handle_value: HandleValue, 41 | packcet_in: UserInPtr, 42 | ) -> ZxResult { 43 | let proc = self.thread.proc(); 44 | let port = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; 45 | let packet = packcet_in.read()?; 46 | info!( 47 | "port.queue: handle={:#x}, packet={:?}", 48 | handle_value, packet 49 | ); 50 | port.push_user(packet)?; 51 | Ok(()) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /kernel-hal/src/user_io_vec.rs: -------------------------------------------------------------------------------- 1 | use super::user::*; 2 | use core::slice; 3 | 4 | type VecResult = core::result::Result; 5 | 6 | const MAX_LENGTH: usize = 0x1000; 7 | 8 | #[repr(C)] 9 | pub struct IoVec { 10 | ptr: UserPtr, 11 | len: usize, 12 | } 13 | 14 | pub type InIoVec = IoVec; 15 | pub type OutIoVec = IoVec; 16 | 17 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 18 | pub enum VecError { 19 | PtrErr(Error), 20 | LengthErr, 21 | } 22 | 23 | impl From for VecError { 24 | fn from(err: Error) -> VecError { 25 | VecError::PtrErr(err) 26 | } 27 | } 28 | 29 | impl IoVec { 30 | pub fn is_null(&self) -> bool { 31 | self.ptr.is_null() 32 | } 33 | 34 | pub fn len(&self) -> usize { 35 | self.len 36 | } 37 | 38 | pub fn is_empty(&self) -> bool { 39 | self.len == 0 40 | } 41 | 42 | pub fn as_user_ptr(&self) -> UserPtr { 43 | unimplemented!() 44 | } 45 | 46 | pub fn as_ptr(&self) -> *const T { 47 | self.ptr.as_ptr() 48 | } 49 | 50 | pub fn check(&self) -> VecResult<()> { 51 | self.ptr.check()?; 52 | if self.len > MAX_LENGTH { 53 | return Err(VecError::LengthErr); 54 | } 55 | Ok(()) 56 | } 57 | 58 | pub fn as_slice(&self) -> VecResult<&[T]> { 59 | self.check()?; 60 | let slice = unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }; 61 | Ok(slice) 62 | } 63 | } 64 | 65 | impl IoVec { 66 | pub fn as_mut_slice(&self) -> VecResult<&mut [T]> { 67 | self.check()?; 68 | let slice = unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }; 69 | Ok(slice) 70 | } 71 | 72 | pub fn as_mut_ptr(&self) -> *mut T { 73 | self.ptr.as_ptr() 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /zircon-object/src/dev/interrupt/event_interrupt.rs: -------------------------------------------------------------------------------- 1 | use kernel_hal::InterruptManager; 2 | use {super::*, spin::Mutex}; 3 | 4 | pub struct EventInterrupt { 5 | vector: u32, 6 | inner: Mutex, 7 | } 8 | 9 | #[derive(Default)] 10 | struct EventInterruptInner { 11 | register: bool, 12 | } 13 | 14 | impl EventInterrupt { 15 | pub fn new(vector: usize) -> Box { 16 | // TODO check vector is a vaild IRQ number 17 | Box::new(EventInterrupt { 18 | vector: vector as u32, 19 | inner: Default::default(), 20 | }) 21 | } 22 | } 23 | 24 | impl InterruptTrait for EventInterrupt { 25 | fn mask(&self) { 26 | let inner = self.inner.lock(); 27 | if inner.register { 28 | InterruptManager::disable(self.vector as u32); 29 | } 30 | } 31 | 32 | fn unmask(&self) { 33 | let inner = self.inner.lock(); 34 | if inner.register { 35 | InterruptManager::enable(self.vector as u32); 36 | } 37 | } 38 | 39 | fn register_handler(&self, handle: Box) -> ZxResult { 40 | let mut inner = self.inner.lock(); 41 | if inner.register { 42 | return Err(ZxError::ALREADY_BOUND); 43 | } 44 | if InterruptManager::set_ioapic_handle(self.vector, handle).is_some() { 45 | inner.register = true; 46 | Ok(()) 47 | } else { 48 | Err(ZxError::ALREADY_BOUND) 49 | } 50 | } 51 | 52 | fn unregister_handler(&self) -> ZxResult { 53 | let mut inner = self.inner.lock(); 54 | if !inner.register { 55 | return Ok(()); 56 | } 57 | if InterruptManager::reset_ioapic_handle(self.vector) { 58 | inner.register = false; 59 | Ok(()) 60 | } else { 61 | Err(ZxError::ALREADY_BOUND) 62 | } // maybe a better error code? 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /zircon-object/src/dev/interrupt/pci_interrupt.rs: -------------------------------------------------------------------------------- 1 | use {super::super::pci::PCIE_IRQRET_MASK, super::super::IPciNode, super::*, spin::Mutex}; 2 | 3 | pub struct PciInterrupt { 4 | device: Arc, 5 | irq_id: usize, 6 | maskable: bool, 7 | inner: Mutex, 8 | } 9 | 10 | #[derive(Default)] 11 | struct PciInterruptInner { 12 | register: bool, 13 | } 14 | 15 | impl PciInterrupt { 16 | pub fn new(device: Arc, vector: u32, maskable: bool) -> Box { 17 | // TODO check vector is a vaild IRQ number 18 | Box::new(PciInterrupt { 19 | device, 20 | irq_id: vector as _, 21 | maskable, 22 | inner: Default::default(), 23 | }) 24 | } 25 | } 26 | 27 | impl InterruptTrait for PciInterrupt { 28 | fn mask(&self) { 29 | let inner = self.inner.lock(); 30 | if self.maskable && inner.register { 31 | self.device.disable_irq(self.irq_id); 32 | } 33 | } 34 | 35 | fn unmask(&self) { 36 | let inner = self.inner.lock(); 37 | if self.maskable && inner.register { 38 | self.device.enable_irq(self.irq_id); 39 | } 40 | } 41 | 42 | fn register_handler(&self, handle: Box) -> ZxResult { 43 | let mut inner = self.inner.lock(); 44 | if inner.register { 45 | return Err(ZxError::ALREADY_BOUND); 46 | } 47 | self.device.register_irq_handle( 48 | self.irq_id, 49 | Box::new(move || { 50 | handle(); 51 | PCIE_IRQRET_MASK 52 | }), 53 | ); 54 | inner.register = true; 55 | Ok(()) 56 | } 57 | 58 | fn unregister_handler(&self) -> ZxResult { 59 | let mut inner = self.inner.lock(); 60 | if !inner.register { 61 | return Ok(()); 62 | } 63 | self.device.unregister_irq_handle(self.irq_id); 64 | inner.register = false; 65 | Ok(()) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /linux-object/src/fs/random.rs: -------------------------------------------------------------------------------- 1 | //! Implement INode for RandomINode 2 | 3 | use alloc::sync::Arc; 4 | use core::any::Any; 5 | 6 | use rcore_fs::vfs::*; 7 | use spin::Mutex; 8 | 9 | pub struct RandomINodeData { 10 | seed: u32, 11 | } 12 | 13 | #[derive(Clone)] 14 | pub struct RandomINode { 15 | data: Arc>, 16 | secure: bool, 17 | } 18 | 19 | impl RandomINode { 20 | // urandom -> secure=true 21 | // random -> secure=false 22 | pub fn new(secure: bool) -> RandomINode { 23 | RandomINode { 24 | secure, 25 | data: Arc::new(Mutex::new(RandomINodeData { seed: 1 })), 26 | } 27 | } 28 | } 29 | 30 | impl INode for RandomINode { 31 | fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { 32 | let mut data = self.data.lock(); 33 | // from K&R 34 | for x in buf.iter_mut() { 35 | data.seed = data.seed.wrapping_mul(1_103_515_245).wrapping_add(12345); 36 | *x = (data.seed / 65536) as u8; 37 | } 38 | Ok(buf.len()) 39 | } 40 | 41 | fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { 42 | Err(FsError::NotSupported) 43 | } 44 | 45 | fn poll(&self) -> Result { 46 | Ok(PollStatus { 47 | read: true, 48 | write: false, 49 | error: false, 50 | }) 51 | } 52 | 53 | fn metadata(&self) -> Result { 54 | Ok(Metadata { 55 | dev: 1, 56 | inode: 1, 57 | size: 0, 58 | blk_size: 0, 59 | blocks: 0, 60 | atime: Timespec { sec: 0, nsec: 0 }, 61 | mtime: Timespec { sec: 0, nsec: 0 }, 62 | ctime: Timespec { sec: 0, nsec: 0 }, 63 | type_: FileType::CharDevice, 64 | mode: 0o666, 65 | nlinks: 1, 66 | uid: 0, 67 | gid: 0, 68 | rdev: make_rdev(1, if self.secure { 9 } else { 8 }), 69 | }) 70 | } 71 | 72 | fn as_any_ref(&self) -> &dyn Any { 73 | self 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /scripts/core-tests.py: -------------------------------------------------------------------------------- 1 | import pexpect 2 | import sys 3 | 4 | TIMEOUT = 300 5 | ZCORE_PATH = '../zCore' 6 | OUTPUT_FILE = 'test-output.txt' 7 | RESULT_FILE = 'test-result.txt' 8 | CHECK_FILE = 'test-check-passed.txt' 9 | TEST_CASE_FILE = 'testcases.txt' 10 | 11 | 12 | class Tee: 13 | def __init__(self, name, mode): 14 | self.file = open(name, mode) 15 | self.stdout = sys.stdout 16 | sys.stdout = self 17 | 18 | def __del__(self): 19 | sys.stdout = self.stdout 20 | self.file.close() 21 | 22 | def write(self, data): 23 | self.file.write(data) 24 | self.stdout.write(data) 25 | 26 | def flush(self): 27 | self.file.flush() 28 | 29 | 30 | with open(TEST_CASE_FILE, "r") as f: 31 | lines = f.readlines() 32 | positive = [line for line in lines if not line.startswith('-')] 33 | negative = [line[1:] for line in lines if line.startswith('-')] 34 | test_filter = (','.join(positive) + '-' + ','.join(negative)).replace('\n', '') 35 | 36 | child = pexpect.spawn("make -C %s test mode=release test_filter='%s'" % (ZCORE_PATH, test_filter), 37 | timeout=TIMEOUT, encoding='utf-8') 38 | child.logfile = Tee(OUTPUT_FILE, 'w') 39 | 40 | index = child.expect(['finished!', 'panicked', pexpect.EOF, pexpect.TIMEOUT]) 41 | result = ['FINISHED', 'PANICKED', 'EOF', 'TIMEOUT'][index] 42 | print(result) 43 | 44 | passed = [] 45 | failed = [] 46 | passed_case = set() 47 | with open(OUTPUT_FILE, "r") as f: 48 | for line in f.readlines(): 49 | if line.startswith('[ OK ]'): 50 | passed += line 51 | passed_case.add(line[13:].split(' ')[0]) 52 | elif line.startswith('[ FAILED ]') and line.endswith(')\n'): 53 | failed += line 54 | 55 | with open(RESULT_FILE, "w") as f: 56 | f.writelines(passed) 57 | f.writelines(failed) 58 | 59 | with open(CHECK_FILE, 'r') as f: 60 | check_case = set([case.strip() for case in f.readlines()]) 61 | 62 | not_passed = check_case - passed_case 63 | if not_passed: 64 | print('=== Failed cases ===') 65 | for case in not_passed: 66 | print(case) 67 | exit(1) 68 | else: 69 | print('All checked case passed!') 70 | -------------------------------------------------------------------------------- /zircon-object/src/dev/pci/pio.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use kernel_hal::{inpd, outpd}; 3 | use spin::Mutex; 4 | 5 | static PIO_LOCK: Mutex<()> = Mutex::new(()); 6 | const PCI_CONFIG_ADDR: u16 = 0xcf8; 7 | const PCI_CONFIG_DATA: u16 = 0xcfc; 8 | const PCI_CONFIG_ENABLE: u32 = 1 << 31; 9 | 10 | pub fn pci_bdf_raw_addr(bus: u8, dev: u8, func: u8, offset: u8) -> u32 { 11 | ((bus as u32 & 0xff) << 16) // bits 23-16 bus 12 | | ((dev as u32 & 0x1f) << 11) // bits 15-11 device 13 | | ((func as u32 & 0x7) << 8) // bits 10-8 func 14 | | (offset as u32 & 0xff) // bits 7-2 reg, with bottom 2 bits as well 15 | } 16 | 17 | pub fn pio_config_read(bus: u8, dev: u8, func: u8, offset: u8, width: usize) -> ZxResult { 18 | pio_config_read_addr(pci_bdf_raw_addr(bus, dev, func, offset), width) 19 | } 20 | 21 | pub fn pio_config_read_addr(addr: u32, width: usize) -> ZxResult { 22 | let _lock = PIO_LOCK.lock(); 23 | let shift = ((addr & 0x3) << 3) as usize; 24 | if shift + width > 32 { 25 | return Err(ZxError::INVALID_ARGS); 26 | } 27 | outpd(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE); 28 | let tmp_val = u32::from_le(inpd(PCI_CONFIG_DATA)); 29 | Ok((tmp_val >> shift) & (((1u64 << width) - 1) as u32)) 30 | } 31 | 32 | pub fn pio_config_write( 33 | bus: u8, 34 | dev: u8, 35 | func: u8, 36 | offset: u8, 37 | val: u32, 38 | width: usize, 39 | ) -> ZxResult { 40 | pio_config_write_addr(pci_bdf_raw_addr(bus, dev, func, offset), val, width) 41 | } 42 | 43 | pub fn pio_config_write_addr(addr: u32, val: u32, width: usize) -> ZxResult { 44 | let _lock = PIO_LOCK.lock(); 45 | let shift = ((addr & 0x3) << 3) as usize; 46 | if shift + width > 32 { 47 | return Err(ZxError::INVALID_ARGS); 48 | } 49 | outpd(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE); 50 | let width_mask = ((1u64 << width) - 1) as u32; 51 | let val = val & width_mask; 52 | let tmp_val = if width < 32 { 53 | (u32::from_le(inpd(PCI_CONFIG_DATA)) & !(width_mask << shift)) | (val << shift) 54 | } else { 55 | val 56 | }; 57 | outpd(PCI_CONFIG_DATA, u32::to_le(tmp_val)); 58 | Ok(()) 59 | } 60 | -------------------------------------------------------------------------------- /linux-loader/src/main.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, unused_must_use)] 2 | #![feature(thread_id_value)] 3 | 4 | extern crate log; 5 | 6 | use linux_loader::*; 7 | use rcore_fs_hostfs::HostFS; 8 | use std::io::Write; 9 | use std::sync::Arc; 10 | use zircon_object::object::*; 11 | 12 | #[async_std::main] 13 | async fn main() { 14 | init_logger(); 15 | kernel_hal_unix::init(); 16 | 17 | let args: Vec<_> = std::env::args().skip(1).collect(); 18 | let envs = vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()]; 19 | 20 | let hostfs = HostFS::new("rootfs"); 21 | let proc: Arc = run(args, envs, hostfs); 22 | proc.wait_signal(Signal::PROCESS_TERMINATED).await; 23 | } 24 | 25 | fn init_logger() { 26 | env_logger::builder() 27 | .format(|buf, record| { 28 | use env_logger::fmt::Color; 29 | use log::Level; 30 | 31 | let tid = async_std::task::current().id(); 32 | let mut style = buf.style(); 33 | match record.level() { 34 | Level::Trace => style.set_color(Color::Black).set_intense(true), 35 | Level::Debug => style.set_color(Color::White), 36 | Level::Info => style.set_color(Color::Green), 37 | Level::Warn => style.set_color(Color::Yellow), 38 | Level::Error => style.set_color(Color::Red).set_bold(true), 39 | }; 40 | let level = style.value(record.level()); 41 | writeln!(buf, "[{:>5}][{}] {}", level, tid, record.args()) 42 | }) 43 | .init(); 44 | } 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | use super::*; 49 | 50 | async fn test(cmdline: &str) { 51 | kernel_hal_unix::init(); 52 | 53 | let args: Vec = cmdline.split(' ').map(|s| s.into()).collect(); 54 | let envs = vec![]; // TODO 55 | let hostfs = HostFS::new("../rootfs"); 56 | let proc = run(args, envs, hostfs); 57 | let proc: Arc = proc; 58 | proc.wait_signal(Signal::PROCESS_TERMINATED).await; 59 | } 60 | 61 | #[async_std::test] 62 | async fn busybox() { 63 | test("/bin/busybox").await; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /linux-object/src/thread.rs: -------------------------------------------------------------------------------- 1 | //! Linux Thread 2 | 3 | use crate::process::ProcessExt; 4 | use alloc::sync::Arc; 5 | use kernel_hal::user::{Out, UserOutPtr, UserPtr}; 6 | use kernel_hal::VirtAddr; 7 | use spin::{Mutex, MutexGuard}; 8 | use zircon_object::task::{Process, Thread}; 9 | use zircon_object::ZxResult; 10 | 11 | pub trait ThreadExt { 12 | fn create_linux(proc: &Arc) -> ZxResult>; 13 | fn lock_linux(&self) -> MutexGuard<'_, LinuxThread>; 14 | fn set_tid_address(&self, tidptr: UserOutPtr); 15 | fn exit_linux(&self, exit_code: i32); 16 | } 17 | 18 | impl ThreadExt for Thread { 19 | fn create_linux(proc: &Arc) -> ZxResult> { 20 | let linux_thread = Mutex::new(LinuxThread { 21 | clear_child_tid: 0.into(), 22 | }); 23 | Thread::create_with_ext(proc, "", linux_thread) 24 | } 25 | 26 | fn lock_linux(&self) -> MutexGuard<'_, LinuxThread> { 27 | self.ext() 28 | .downcast_ref::>() 29 | .unwrap() 30 | .lock() 31 | } 32 | 33 | /// Set pointer to thread ID. 34 | fn set_tid_address(&self, tidptr: UserPtr) { 35 | self.lock_linux().clear_child_tid = tidptr; 36 | } 37 | 38 | /// Exit current thread for Linux. 39 | fn exit_linux(&self, _exit_code: i32) { 40 | let mut linux_thread = self.lock_linux(); 41 | let clear_child_tid = &mut linux_thread.clear_child_tid; 42 | // perform futex wake 1 43 | // ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html 44 | if !clear_child_tid.is_null() { 45 | info!("exit: do futex {:?} wake 1", clear_child_tid); 46 | clear_child_tid.write(0).unwrap(); 47 | let uaddr = clear_child_tid.as_ptr() as VirtAddr; 48 | let futex = self.proc().linux().get_futex(uaddr); 49 | futex.wake(1); 50 | } 51 | self.exit(); 52 | } 53 | } 54 | 55 | /// Linux specific thread information. 56 | pub struct LinuxThread { 57 | /// Kernel performs futex wake when thread exits. 58 | /// Ref: [http://man7.org/linux/man-pages/man2/set_tid_address.2.html] 59 | clear_child_tid: UserOutPtr, 60 | } 61 | -------------------------------------------------------------------------------- /kernel-hal/src/future.rs: -------------------------------------------------------------------------------- 1 | use crate::timer_now; 2 | use alloc::boxed::Box; 3 | use core::future::Future; 4 | use core::pin::Pin; 5 | use core::task::{Context, Poll}; 6 | use core::time::Duration; 7 | 8 | /// Yields execution back to the async runtime. 9 | pub fn yield_now() -> impl Future { 10 | YieldFuture::default() 11 | } 12 | 13 | #[must_use = "yield_now does nothing unless polled/`await`-ed"] 14 | #[derive(Default)] 15 | struct YieldFuture { 16 | flag: bool, 17 | } 18 | 19 | impl Future for YieldFuture { 20 | type Output = (); 21 | 22 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { 23 | if self.flag { 24 | Poll::Ready(()) 25 | } else { 26 | self.flag = true; 27 | cx.waker().clone().wake(); 28 | Poll::Pending 29 | } 30 | } 31 | } 32 | 33 | /// Sleeps until the specified of time. 34 | pub fn sleep_until(deadline: Duration) -> impl Future { 35 | SleepFuture { deadline } 36 | } 37 | 38 | #[must_use = "sleep does nothing unless polled/`await`-ed"] 39 | pub struct SleepFuture { 40 | deadline: Duration, 41 | } 42 | 43 | impl Future for SleepFuture { 44 | type Output = (); 45 | 46 | fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { 47 | if timer_now() >= self.deadline { 48 | return Poll::Ready(()); 49 | } 50 | if self.deadline.as_nanos() < i64::max_value() as u128 { 51 | let waker = cx.waker().clone(); 52 | crate::timer_set(self.deadline, Box::new(move |_| waker.wake())); 53 | } 54 | Poll::Pending 55 | } 56 | } 57 | 58 | /// Get a char from serial. 59 | pub fn serial_getchar() -> impl Future { 60 | SerialFuture 61 | } 62 | 63 | #[must_use = "serial_getchar does nothing unless polled/`await`-ed"] 64 | pub struct SerialFuture; 65 | 66 | impl Future for SerialFuture { 67 | type Output = u8; 68 | 69 | fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { 70 | let mut buf = [0u8]; 71 | if crate::serial_read(&mut buf) != 0 { 72 | return Poll::Ready(buf[0]); 73 | } 74 | let waker = cx.waker().clone(); 75 | crate::serial_set_callback(Box::new(move || waker.wake())); 76 | Poll::Pending 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /zircon-object/src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Virtual Memory Management. 2 | 3 | mod stream; 4 | mod vmar; 5 | mod vmo; 6 | 7 | pub use self::{stream::*, vmar::*, vmo::*}; 8 | use super::{ZxError, ZxResult}; 9 | use alloc::sync::Arc; 10 | pub use kernel_hal::{CachePolicy, MMUFlags}; 11 | use lazy_static::*; 12 | 13 | /// Physical Address 14 | pub type PhysAddr = usize; 15 | 16 | /// Virtual Address 17 | pub type VirtAddr = usize; 18 | 19 | /// Device Address 20 | pub type DevVAddr = usize; 21 | 22 | /// Size of a page 23 | pub const PAGE_SIZE: usize = 0x1000; 24 | pub const PAGE_SIZE_LOG2: usize = 12; 25 | 26 | pub fn page_aligned(x: usize) -> bool { 27 | x % PAGE_SIZE == 0 28 | } 29 | 30 | pub fn check_aligned(x: usize, align: usize) -> bool { 31 | x % align == 0 32 | } 33 | 34 | /// How many pages the `size` needs. 35 | /// To avoid overflow and pass more unit tests, use wrapping add 36 | pub fn pages(size: usize) -> usize { 37 | size.wrapping_add(PAGE_SIZE - 1) / PAGE_SIZE 38 | } 39 | 40 | pub fn ceil(x: usize, align: usize) -> usize { 41 | x.wrapping_add(align - 1) / align 42 | } 43 | 44 | pub fn roundup_pages(size: usize) -> usize { 45 | if page_aligned(size) { 46 | size 47 | } else { 48 | pages(size) * PAGE_SIZE 49 | } 50 | } 51 | 52 | pub fn round_down_pages(size: usize) -> usize { 53 | size / PAGE_SIZE * PAGE_SIZE 54 | } 55 | 56 | lazy_static! { 57 | pub static ref KERNEL_ASPACE: Arc = VmAddressRegion::new_kernel(); 58 | } 59 | 60 | pub fn kernel_allocate_physical( 61 | size: usize, 62 | paddr: PhysAddr, 63 | mmu_flags: MMUFlags, 64 | cache_policy: CachePolicy, 65 | ) -> ZxResult { 66 | if !page_aligned(paddr) { 67 | return Err(ZxError::INVALID_ARGS); 68 | } 69 | let size = roundup_pages(size); 70 | let vmo = VmObject::new_physical(paddr, pages(size)); 71 | vmo.set_cache_policy(cache_policy)?; 72 | let flags = mmu_flags - MMUFlags::CACHE_1 - MMUFlags::CACHE_2; 73 | KERNEL_ASPACE.map(None, vmo, 0, size, flags) 74 | } 75 | 76 | #[cfg(test)] 77 | mod test { 78 | use super::*; 79 | #[test] 80 | fn test_round_pages() { 81 | assert_eq!(roundup_pages(0), 0); 82 | assert_eq!(roundup_pages(core::usize::MAX), 0); 83 | assert_eq!( 84 | roundup_pages(core::usize::MAX - PAGE_SIZE + 1), 85 | core::usize::MAX - PAGE_SIZE + 1 86 | ); 87 | assert_eq!(roundup_pages(PAGE_SIZE * 3 - 1), PAGE_SIZE * 3); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /linux-syscall/src/misc.rs: -------------------------------------------------------------------------------- 1 | use super::time::TimeSpec; 2 | use super::*; 3 | use bitflags::bitflags; 4 | 5 | impl Syscall<'_> { 6 | #[cfg(target_arch = "x86_64")] 7 | pub fn sys_arch_prctl(&mut self, code: i32, addr: usize) -> SysResult { 8 | const ARCH_SET_FS: i32 = 0x1002; 9 | match code { 10 | ARCH_SET_FS => { 11 | info!("sys_arch_prctl: set FSBASE to {:#x}", addr); 12 | self.regs.fsbase = addr; 13 | Ok(0) 14 | } 15 | _ => Err(LxError::EINVAL), 16 | } 17 | } 18 | 19 | pub fn sys_uname(&self, buf: UserOutPtr) -> SysResult { 20 | info!("uname: buf={:?}", buf); 21 | 22 | let strings = ["rCore", "orz", "0.1.0", "1", "machine", "domain"]; 23 | for (i, &s) in strings.iter().enumerate() { 24 | const OFFSET: usize = 65; 25 | buf.add(i * OFFSET).write_cstring(s)?; 26 | } 27 | Ok(0) 28 | } 29 | 30 | pub async fn sys_futex( 31 | &self, 32 | uaddr: usize, 33 | op: u32, 34 | val: i32, 35 | timeout: UserInPtr, 36 | ) -> SysResult { 37 | bitflags! { 38 | struct FutexFlags: u32 { 39 | const WAIT = 0; 40 | const WAKE = 1; 41 | const PRIVATE = 0x80; 42 | } 43 | } 44 | let op = FutexFlags::from_bits_truncate(op); 45 | info!( 46 | "futex: uaddr: {:#x}, op: {:?}, val: {}, timeout_ptr: {:?}", 47 | uaddr, op, val, timeout 48 | ); 49 | if op.contains(FutexFlags::PRIVATE) { 50 | warn!("process-shared futex is unimplemented"); 51 | } 52 | let futex = self.linux_process().get_futex(uaddr); 53 | match op.bits & 0xf { 54 | 0 => { 55 | // FIXME: support timeout 56 | let _timeout = timeout.read_if_not_null()?; 57 | match futex.wait(val).await { 58 | Ok(_) => Ok(0), 59 | Err(ZxError::BAD_STATE) => Err(LxError::EAGAIN), 60 | Err(e) => Err(e.into()), 61 | } 62 | } 63 | 1 => { 64 | let woken_up_count = futex.wake(val as usize); 65 | Ok(woken_up_count) 66 | } 67 | _ => { 68 | warn!("unsupported futex operation: {:?}", op); 69 | Err(LxError::ENOSYS) 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /zCore/src/logging.rs: -------------------------------------------------------------------------------- 1 | use { 2 | core::fmt, 3 | log::{self, Level, LevelFilter, Log, Metadata, Record}, 4 | }; 5 | 6 | pub fn init(level: &str) { 7 | static LOGGER: SimpleLogger = SimpleLogger; 8 | log::set_logger(&LOGGER).unwrap(); 9 | log::set_max_level(match level { 10 | "error" => LevelFilter::Error, 11 | "warn" => LevelFilter::Warn, 12 | "info" => LevelFilter::Info, 13 | "debug" => LevelFilter::Debug, 14 | "trace" => LevelFilter::Trace, 15 | _ => LevelFilter::Off, 16 | }); 17 | } 18 | 19 | #[macro_export] 20 | macro_rules! print { 21 | ($($arg:tt)*) => ({ 22 | $crate::logging::print(format_args!($($arg)*)); 23 | }); 24 | } 25 | 26 | #[macro_export] 27 | macro_rules! println { 28 | ($fmt:expr) => (print!(concat!($fmt, "\n"))); 29 | ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); 30 | } 31 | 32 | /// Add escape sequence to print with color in Linux console 33 | macro_rules! with_color { 34 | ($args: ident, $color_code: ident) => {{ 35 | format_args!("\u{1B}[{}m{}\u{1B}[0m", $color_code as u8, $args) 36 | }}; 37 | } 38 | 39 | fn print_in_color(args: fmt::Arguments, color_code: u8) { 40 | kernel_hal_bare::arch::putfmt(with_color!(args, color_code)); 41 | } 42 | 43 | #[allow(dead_code)] 44 | pub fn print(args: fmt::Arguments) { 45 | kernel_hal_bare::arch::putfmt(args); 46 | } 47 | 48 | struct SimpleLogger; 49 | 50 | impl Log for SimpleLogger { 51 | fn enabled(&self, _metadata: &Metadata) -> bool { 52 | true 53 | } 54 | fn log(&self, record: &Record) { 55 | if !self.enabled(record.metadata()) { 56 | return; 57 | } 58 | 59 | let (tid, pid) = kernel_hal_bare::Thread::get_tid(); 60 | print_in_color( 61 | format_args!( 62 | "[{:?} {:>5} {} {}:{}] {}\n", 63 | kernel_hal_bare::timer_now(), 64 | record.level(), 65 | kernel_hal_bare::apic_local_id(), 66 | pid, 67 | tid, 68 | record.args() 69 | ), 70 | level_to_color_code(record.level()), 71 | ); 72 | } 73 | fn flush(&self) {} 74 | } 75 | 76 | fn level_to_color_code(level: Level) -> u8 { 77 | match level { 78 | Level::Error => 31, // Red 79 | Level::Warn => 93, // BrightYellow 80 | Level::Info => 34, // Blue 81 | Level::Debug => 32, // Green 82 | Level::Trace => 90, // BrightBlack 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /kernel-hal/src/vdso.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{Debug, Error, Formatter}; 2 | 3 | /// This struct contains constants that are initialized by the kernel 4 | /// once at boot time. From the vDSO code's perspective, they are 5 | /// read-only data that can never change. Hence, no synchronization is 6 | /// required to read them. 7 | #[repr(C)] 8 | #[derive(Debug)] 9 | pub struct VdsoConstants { 10 | /// Maximum number of CPUs that might be online during the lifetime 11 | /// of the booted system. 12 | pub max_num_cpus: u32, 13 | /// Bit map indicating features. 14 | pub features: Features, 15 | /// Number of bytes in a data cache line. 16 | pub dcache_line_size: u32, 17 | /// Number of bytes in an instruction cache line. 18 | pub icache_line_size: u32, 19 | /// Conversion factor for zx_ticks_get return values to seconds. 20 | pub ticks_per_second: u64, 21 | /// Ratio which relates ticks (zx_ticks_get) to clock monotonic. 22 | /// 23 | /// Specifically: ClockMono(ticks) = (ticks * N) / D 24 | pub ticks_to_mono_numerator: u32, 25 | pub ticks_to_mono_denominator: u32, 26 | /// Total amount of physical memory in the system, in bytes. 27 | pub physmem: u64, 28 | /// Actual length of `version_string`, not including the NUL terminator. 29 | pub version_string_len: u64, 30 | /// A NUL-terminated UTF-8 string returned by `zx_system_get_version_string`. 31 | pub version_string: VersionString, 32 | } 33 | 34 | /// Bit map indicating features. 35 | /// 36 | /// For specific feature bits, see zircon/features.h. 37 | #[repr(C)] 38 | #[derive(Debug)] 39 | pub struct Features { 40 | pub cpu: u32, 41 | /// Total amount of debug registers available in the system. 42 | pub hw_breakpoint_count: u32, 43 | pub hw_watchpoint_count: u32, 44 | } 45 | 46 | impl VdsoConstants { 47 | /// Set version string. 48 | pub fn set_version_string(&mut self, s: &str) { 49 | let len = s.len().min(64); 50 | self.version_string_len = len as u64; 51 | self.version_string.0[..len].copy_from_slice(s.as_bytes()); 52 | } 53 | } 54 | 55 | #[repr(C)] 56 | pub struct VersionString([u8; 64]); 57 | 58 | impl Default for VersionString { 59 | fn default() -> Self { 60 | VersionString([0; 64]) 61 | } 62 | } 63 | 64 | impl Debug for VersionString { 65 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { 66 | for &c in self.0.iter().take_while(|&&c| c != 0) { 67 | write!(f, "{}", c as char)?; 68 | } 69 | Ok(()) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /zircon-object/src/util/kcounter.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{Debug, Error, Formatter}; 2 | use core::sync::atomic::{AtomicUsize, Ordering}; 3 | 4 | /// Kernel counter. 5 | #[repr(transparent)] 6 | #[derive(Debug)] 7 | pub struct KCounter(AtomicUsize); 8 | 9 | impl KCounter { 10 | /// Create a new KCounter. 11 | pub const fn new() -> Self { 12 | KCounter(AtomicUsize::new(0)) 13 | } 14 | 15 | /// Add a value to the counter. 16 | pub fn add(&self, x: usize) { 17 | self.0.fetch_add(x, Ordering::Relaxed); 18 | } 19 | 20 | /// Get the value of counter. 21 | pub fn get(&self) -> usize { 22 | self.0.load(Ordering::Relaxed) 23 | } 24 | } 25 | 26 | #[repr(C)] 27 | pub struct KCounterDescriptor { 28 | pub counter: &'static KCounter, 29 | pub name: &'static str, 30 | } 31 | 32 | /// Define a new KCounter. 33 | #[macro_export] 34 | macro_rules! kcounter { 35 | ($var:ident, $name:expr) => { 36 | #[used] 37 | #[cfg_attr(target_os = "none", link_section = ".kcounter.items")] 38 | static $var: $crate::util::kcounter::KCounter = { 39 | #[used] 40 | #[cfg_attr(target_os = "none", link_section = ".kcounter.descriptor")] 41 | static DESCRIPTOR: $crate::util::kcounter::KCounterDescriptor = 42 | $crate::util::kcounter::KCounterDescriptor { 43 | counter: &$var, 44 | name: $name, 45 | }; 46 | $crate::util::kcounter::KCounter::new() 47 | }; 48 | }; 49 | } 50 | 51 | pub struct KCounterDescriptorArray(pub &'static [KCounterDescriptor]); 52 | 53 | impl KCounterDescriptorArray { 54 | /// Get kcounter descriptor array from symbols. 55 | #[allow(unsafe_code)] 56 | pub fn get() -> Self { 57 | extern "C" { 58 | fn kcounter_descriptor_begin(); 59 | fn kcounter_descriptor_end(); 60 | } 61 | let start = kcounter_descriptor_begin as usize as *const KCounterDescriptor; 62 | let end = kcounter_descriptor_end as usize as *const KCounterDescriptor; 63 | let descs = unsafe { core::slice::from_raw_parts(start, end.offset_from(start) as usize) }; 64 | KCounterDescriptorArray(descs) 65 | } 66 | } 67 | 68 | impl Debug for KCounterDescriptorArray { 69 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { 70 | f.write_str("KCounters ")?; 71 | f.debug_map() 72 | .entries(self.0.iter().map(|desc| (desc.name, desc.counter.get()))) 73 | .finish() 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /zircon-object/src/task/thread/thread_state.rs: -------------------------------------------------------------------------------- 1 | use crate::{ZxError, ZxResult}; 2 | use kernel_hal::UserContext; 3 | use numeric_enum_macro::numeric_enum; 4 | 5 | numeric_enum! { 6 | #[repr(u32)] 7 | #[derive(Debug, Copy, Clone)] 8 | pub enum ThreadStateKind { 9 | General = 0, 10 | FloatPoint = 1, 11 | Vector = 2, 12 | Debug = 4, 13 | SingleStep = 5, 14 | FS = 6, 15 | GS = 7, 16 | } 17 | } 18 | 19 | pub trait ContextExt { 20 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult; 21 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult; 22 | } 23 | 24 | impl ContextExt for UserContext { 25 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult { 26 | match kind { 27 | ThreadStateKind::General => buf.write_struct(&self.general), 28 | #[cfg(target_arch = "x86_64")] 29 | ThreadStateKind::FS => buf.write_struct(&self.general.fsbase), 30 | #[cfg(target_arch = "x86_64")] 31 | ThreadStateKind::GS => buf.write_struct(&self.general.gsbase), 32 | _ => unimplemented!(), 33 | } 34 | } 35 | 36 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult { 37 | match kind { 38 | ThreadStateKind::General => self.general = buf.read_struct()?, 39 | #[cfg(target_arch = "x86_64")] 40 | ThreadStateKind::FS => self.general.fsbase = buf.read_struct()?, 41 | #[cfg(target_arch = "x86_64")] 42 | ThreadStateKind::GS => self.general.gsbase = buf.read_struct()?, 43 | _ => unimplemented!(), 44 | } 45 | Ok(()) 46 | } 47 | } 48 | 49 | trait BufExt { 50 | fn read_struct(&self) -> ZxResult; 51 | fn write_struct(&mut self, value: &T) -> ZxResult; 52 | } 53 | 54 | #[allow(unsafe_code)] 55 | impl BufExt for [u8] { 56 | fn read_struct(&self) -> ZxResult { 57 | if self.len() < core::mem::size_of::() { 58 | return Err(ZxError::BUFFER_TOO_SMALL); 59 | } 60 | Ok(unsafe { (self.as_ptr() as *const T).read() }) 61 | } 62 | 63 | fn write_struct(&mut self, value: &T) -> ZxResult { 64 | if self.len() < core::mem::size_of::() { 65 | return Err(ZxError::BUFFER_TOO_SMALL); 66 | } 67 | unsafe { 68 | *(self.as_mut_ptr() as *mut T) = *value; 69 | } 70 | Ok(core::mem::size_of::()) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /zircon-object/src/signal/eventpair.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::object::*; 3 | use alloc::sync::{Arc, Weak}; 4 | 5 | /// Mutually signalable pair of events for concurrent programming 6 | /// 7 | /// ## SYNOPSIS 8 | /// 9 | /// Event Pairs are linked pairs of user-signalable objects. The 8 signal 10 | /// bits reserved for userspace (`ZX_USER_SIGNAL_0` through 11 | /// `ZX_USER_SIGNAL_7`) may be set or cleared on the local or opposing 12 | /// endpoint of an Event Pair. 13 | pub struct EventPair { 14 | base: KObjectBase, 15 | _counter: CountHelper, 16 | peer: Weak, 17 | } 18 | 19 | impl_kobject!(EventPair 20 | fn allowed_signals(&self) -> Signal { 21 | Signal::USER_ALL | Signal::SIGNALED 22 | } 23 | fn peer(&self) -> ZxResult> { 24 | let peer = self.peer.upgrade().ok_or(ZxError::PEER_CLOSED)?; 25 | Ok(peer) 26 | } 27 | fn related_koid(&self) -> KoID { 28 | self.peer.upgrade().map(|p| p.id()).unwrap_or(0) 29 | } 30 | ); 31 | define_count_helper!(EventPair); 32 | 33 | impl EventPair { 34 | /// Create a pair of event. 35 | #[allow(unsafe_code)] 36 | pub fn create() -> (Arc, Arc) { 37 | let mut event0 = Arc::new(EventPair { 38 | base: KObjectBase::default(), 39 | _counter: CountHelper::new(), 40 | peer: Weak::default(), 41 | }); 42 | let event1 = Arc::new(EventPair { 43 | base: KObjectBase::default(), 44 | _counter: CountHelper::new(), 45 | peer: Arc::downgrade(&event0), 46 | }); 47 | // no other reference of `channel0` 48 | unsafe { 49 | Arc::get_mut_unchecked(&mut event0).peer = Arc::downgrade(&event1); 50 | } 51 | (event0, event1) 52 | } 53 | 54 | /// Get the peer event. 55 | pub fn peer(&self) -> ZxResult> { 56 | self.peer.upgrade().ok_or(ZxError::PEER_CLOSED) 57 | } 58 | } 59 | 60 | impl Drop for EventPair { 61 | fn drop(&mut self) { 62 | if let Some(peer) = self.peer.upgrade() { 63 | peer.base.signal_set(Signal::PEER_CLOSED); 64 | } 65 | } 66 | } 67 | 68 | #[cfg(test)] 69 | mod tests { 70 | use super::*; 71 | 72 | #[test] 73 | fn peer_closed() { 74 | let (event0, event1) = EventPair::create(); 75 | assert!(Arc::ptr_eq(&event0.peer().unwrap(), &event1)); 76 | 77 | drop(event1); 78 | assert_eq!(event0.signal(), Signal::PEER_CLOSED); 79 | assert_eq!(event0.peer().err(), Some(ZxError::PEER_CLOSED)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /zircon-object/src/object/handle.rs: -------------------------------------------------------------------------------- 1 | use {super::*, alloc::sync::Arc}; 2 | 3 | /// The value refers to a Handle in user space. 4 | pub type HandleValue = u32; 5 | 6 | /// Invalid handle value. 7 | pub const INVALID_HANDLE: HandleValue = 0; 8 | 9 | /// A Handle is how a specific process refers to a specific kernel object. 10 | #[derive(Debug, Clone)] 11 | pub struct Handle { 12 | pub object: Arc, 13 | pub rights: Rights, 14 | } 15 | 16 | impl Handle { 17 | pub fn new(object: Arc, rights: Rights) -> Self { 18 | Handle { object, rights } 19 | } 20 | 21 | pub fn get_info(&self) -> HandleBasicInfo { 22 | HandleBasicInfo { 23 | koid: self.object.id(), 24 | rights: self.rights.bits(), 25 | obj_type: obj_type(&self.object), 26 | related_koid: self.object.related_koid(), 27 | props: if self.rights.contains(Rights::WAIT) { 28 | 1 29 | } else { 30 | 0 31 | }, 32 | padding: 0, 33 | } 34 | } 35 | 36 | pub fn get_handle_info(&self) -> HandleInfo { 37 | HandleInfo { 38 | obj_type: obj_type(&self.object), 39 | rights: self.rights.bits(), 40 | ..Default::default() 41 | } 42 | } 43 | } 44 | 45 | #[repr(C)] 46 | #[derive(Default, Debug)] 47 | pub struct HandleBasicInfo { 48 | koid: u64, 49 | rights: u32, 50 | obj_type: u32, 51 | related_koid: u64, 52 | props: u32, 53 | padding: u32, 54 | } 55 | 56 | pub fn obj_type(object: &Arc) -> u32 { 57 | match object.type_name() { 58 | "Process" => 1, 59 | "Thread" => 2, 60 | "VmObject" => 3, 61 | "Channel" => 4, 62 | "Event" => 5, 63 | "Port" => 6, 64 | "Interrupt" => 9, 65 | "PciDevice" => 11, 66 | "Log" | "DebugLog" => 12, 67 | "Socket" => 14, 68 | "Resource" => 15, 69 | "EventPair" => 16, 70 | "Job" => 17, 71 | "VmAddressRegion" => 18, 72 | "Fifo" => 19, 73 | "Guest" => 20, 74 | "VCpu" => 21, 75 | "Timer" => 22, 76 | "Iommu" => 23, 77 | "Bti" => 24, 78 | "Profile" => 25, 79 | "Pmt" => 26, 80 | "SuspendToken" => 27, 81 | "Pager" => 28, 82 | "Exception" => 29, 83 | "Clock" => 30, 84 | "Stream" => 31, 85 | "PcieDeviceKObject" => 32, 86 | _ => unimplemented!("unknown type"), 87 | } 88 | } 89 | 90 | #[repr(C)] 91 | #[derive(Default, Debug)] 92 | pub struct HandleInfo { 93 | pub handle: HandleValue, 94 | obj_type: u32, 95 | rights: u32, 96 | unused: u32, 97 | } 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zCore 2 | 3 | [![CI](https://github.com/rcore-os/zCore/workflows/CI/badge.svg?branch=master)](https://github.com/rcore-os/zCore/actions) 4 | [![Docs](https://img.shields.io/badge/docs-alpha-blue)](https://rcore-os.github.io/zCore/zircon_object/) 5 | [![Coverage Status](https://coveralls.io/repos/github/rcore-os/zCore/badge.svg?branch=master)](https://coveralls.io/github/rcore-os/zCore?branch=master) 6 | 7 | Reimplement [Zircon][zircon] microkernel in safe Rust as a userspace program! 8 | 9 | ## Dev Status 10 | 11 | 🚧 Working In Progress 12 | 13 | - 2020.04.16: Zircon console is working on zCore! 🎉 14 | 15 | ## Getting started 16 | 17 | Environments: 18 | 19 | * [Rust toolchain](http://rustup.rs) 20 | * [QEMU](https://www.qemu.org) 21 | * [Git LFS](https://git-lfs.github.com) 22 | 23 | Clone repo and pull prebuilt fuchsia images: 24 | 25 | ```sh 26 | git clone https://github.com/rcore-os/zCore --recursive 27 | cd zCore 28 | git lfs pull 29 | ``` 30 | 31 | For users in China, there's a mirror you can try: 32 | 33 | ```sh 34 | git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive 35 | ``` 36 | 37 | Prepare Alpine Linux rootfs: 38 | 39 | ```sh 40 | make rootfs 41 | ``` 42 | 43 | Run native Linux program (Busybox): 44 | 45 | ```sh 46 | cargo run --release -p linux-loader /bin/busybox [args] 47 | ``` 48 | 49 | Run native Zircon program (shell): 50 | 51 | ```sh 52 | cargo run --release -p zircon-loader prebuilt/zircon/x64 53 | ``` 54 | 55 | Run Zircon on bare-metal (zCore): 56 | 57 | ```sh 58 | cd zCore && make run mode=release [graphic=on] [accel=1] 59 | ``` 60 | 61 | To debug, set `RUST_LOG` environment variable to one of `error`, `warn`, `info`, `debug`, `trace`. 62 | 63 | ## Testing 64 | 65 | Run Zircon official core-tests: 66 | 67 | ```sh 68 | cd zCore && make test mode=release [accel=1] test_filter='Channel.*' 69 | ``` 70 | 71 | Run all (non-panicked) core-tests for CI: 72 | 73 | ```sh 74 | pip3 install pexpect 75 | cd script && python3 core-tests.py 76 | ``` 77 | 78 | Check `test-result.txt` for results. 79 | 80 | ## Components 81 | 82 | ### Overview 83 | 84 | ![](./docs/structure.svg) 85 | 86 | [zircon]: https://fuchsia.googlesource.com/fuchsia/+/master/zircon/README.md 87 | [kernel-objects]: https://github.com/PanQL/zircon/blob/master/docs/objects.md 88 | [syscalls]: https://github.com/PanQL/zircon/blob/master/docs/syscalls.md 89 | 90 | ### Hardware Abstraction Layer 91 | 92 | | | Bare Metal | Linux / macOS | 93 | | :------------------------ | ---------- | ----------------- | 94 | | Virtual Memory Management | Page Table | Mmap | 95 | | Thread Management | `executor` | `async-std::task` | 96 | | Exception Handling | Interrupt | Signal | 97 | 98 | -------------------------------------------------------------------------------- /zircon-object/src/dev/iommu.rs: -------------------------------------------------------------------------------- 1 | use {crate::object::*, crate::vm::*, alloc::sync::Arc, bitflags::bitflags}; 2 | 3 | /// Iommu refers to DummyIommu in zircon. 4 | /// 5 | /// A dummy implementation, do not take it serious. 6 | pub struct Iommu { 7 | base: KObjectBase, 8 | } 9 | 10 | impl_kobject!(Iommu); 11 | 12 | impl Iommu { 13 | /// Create a new `IOMMU`. 14 | pub fn create() -> Arc { 15 | Arc::new(Iommu { 16 | base: KObjectBase::new(), 17 | }) 18 | } 19 | 20 | pub fn is_valid_bus_txn_id(&self) -> bool { 21 | true 22 | } 23 | 24 | pub fn minimum_contiguity(&self) -> usize { 25 | PAGE_SIZE as usize 26 | } 27 | 28 | pub fn aspace_size(&self) -> usize { 29 | usize::MAX 30 | } 31 | 32 | pub fn map( 33 | &self, 34 | vmo: Arc, 35 | offset: usize, 36 | size: usize, 37 | perms: IommuPerms, 38 | ) -> ZxResult<(DevVAddr, usize)> { 39 | if perms == IommuPerms::empty() { 40 | return Err(ZxError::INVALID_ARGS); 41 | } 42 | if offset + size > vmo.len() { 43 | return Err(ZxError::INVALID_ARGS); 44 | } 45 | let mut flags = MMUFlags::empty(); 46 | if perms.contains(IommuPerms::PERM_READ) { 47 | flags |= MMUFlags::READ; 48 | } 49 | if perms.contains(IommuPerms::PERM_WRITE) { 50 | flags |= MMUFlags::WRITE; 51 | } 52 | if perms.contains(IommuPerms::PERM_EXECUTE) { 53 | flags |= MMUFlags::EXECUTE; 54 | } 55 | let p_addr = vmo.commit_page(offset / PAGE_SIZE, flags)?; 56 | if vmo.is_paged() { 57 | Ok((p_addr, PAGE_SIZE)) 58 | } else { 59 | Ok((p_addr, pages(size))) 60 | } 61 | } 62 | 63 | pub fn map_contiguous( 64 | &self, 65 | vmo: Arc, 66 | offset: usize, 67 | size: usize, 68 | perms: IommuPerms, 69 | ) -> ZxResult<(DevVAddr, usize)> { 70 | if perms == IommuPerms::empty() { 71 | return Err(ZxError::INVALID_ARGS); 72 | } 73 | if offset + size > vmo.len() { 74 | return Err(ZxError::INVALID_ARGS); 75 | } 76 | let p_addr = vmo.commit_page(offset, MMUFlags::empty())?; 77 | if vmo.is_paged() { 78 | Ok((p_addr, PAGE_SIZE)) 79 | } else { 80 | Ok((p_addr, pages(size) * PAGE_SIZE)) 81 | } 82 | } 83 | } 84 | 85 | bitflags! { 86 | pub struct IommuPerms: u32 { 87 | #[allow(clippy::identity_op)] 88 | const PERM_READ = 1 << 0; 89 | const PERM_WRITE = 1 << 1; 90 | const PERM_EXECUTE = 1 << 2; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /kernel-hal-bare/src/arch/x86_64/acpi_table.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use crate::get_acpi_table; 3 | pub use acpi::{ 4 | interrupt::{InterruptModel, InterruptSourceOverride, IoApic, Polarity, TriggerMode}, 5 | Acpi, 6 | }; 7 | use alloc::vec::Vec; 8 | use lazy_static::*; 9 | use spin::Mutex; 10 | pub struct AcpiTable { 11 | inner: Acpi, 12 | } 13 | 14 | lazy_static! { 15 | static ref ACPI_TABLE: Mutex> = Mutex::default(); 16 | } 17 | 18 | impl AcpiTable { 19 | fn initialize_check() { 20 | #[cfg(target_arch = "x86_64")] 21 | { 22 | let mut table = ACPI_TABLE.lock(); 23 | if table.is_none() { 24 | *table = get_acpi_table().map(|x| AcpiTable { inner: x }); 25 | } 26 | } 27 | } 28 | pub fn invalidate() { 29 | *ACPI_TABLE.lock() = None; 30 | } 31 | pub fn get_ioapic() -> Vec { 32 | Self::initialize_check(); 33 | let table = ACPI_TABLE.lock(); 34 | match &*table { 35 | None => Vec::default(), 36 | Some(table) => match table.inner.interrupt_model.as_ref().unwrap() { 37 | InterruptModel::Apic(apic) => { 38 | apic.io_apics.iter().map(|x| IoApic { ..*x }).collect() 39 | } 40 | _ => Vec::default(), 41 | }, 42 | } 43 | } 44 | pub fn get_interrupt_source_overrides() -> Vec { 45 | Self::initialize_check(); 46 | let table = ACPI_TABLE.lock(); 47 | match &*table { 48 | None => Vec::default(), 49 | Some(table) => match table.inner.interrupt_model.as_ref().unwrap() { 50 | InterruptModel::Apic(apic) => apic 51 | .interrupt_source_overrides 52 | .iter() 53 | .map(|x| InterruptSourceOverride { 54 | polarity: Self::clone_polarity(&x.polarity), 55 | trigger_mode: Self::clone_trigger_mode(&x.trigger_mode), 56 | ..*x 57 | }) 58 | .collect(), 59 | _ => Vec::default(), 60 | }, 61 | } 62 | } 63 | fn clone_polarity(x: &Polarity) -> Polarity { 64 | match x { 65 | Polarity::SameAsBus => Polarity::SameAsBus, 66 | Polarity::ActiveHigh => Polarity::ActiveHigh, 67 | Polarity::ActiveLow => Polarity::ActiveLow, 68 | } 69 | } 70 | fn clone_trigger_mode(x: &TriggerMode) -> TriggerMode { 71 | match x { 72 | TriggerMode::SameAsBus => TriggerMode::SameAsBus, 73 | TriggerMode::Edge => TriggerMode::Edge, 74 | TriggerMode::Level => TriggerMode::Level, 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /scripts/zcore.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/lib/process_builder/src/lib.rs b/src/lib/process_builder/src/lib.rs 2 | index 0d49b5bf37a..7929530fe6e 100644 3 | --- a/src/lib/process_builder/src/lib.rs 4 | +++ b/src/lib/process_builder/src/lib.rs 5 | @@ -834,7 +834,7 @@ impl ReservationVmar { 6 | // (base+len) represents the full address space, assuming this is used with a root VMAR and 7 | // length extends to the end of the address space, including a region the kernel reserves 8 | // at the start of the space. 9 | - let reserve_size = util::page_end((info.base + info.len) / 2) - info.base; 10 | + let reserve_size = util::page_end(info.len / 2); 11 | let (reserve_vmar, reserve_base) = 12 | vmar.allocate(0, reserve_size, zx::VmarFlags::SPECIFIC).map_err(|s| { 13 | ProcessBuilderError::GenericStatus("Failed to allocate reservation VMAR", s) 14 | diff --git a/zircon/kernel/lib/userabi/userboot/start.cc b/zircon/kernel/lib/userabi/userboot/start.cc 15 | index 70188140fe1..777eccb1403 100644 16 | --- a/zircon/kernel/lib/userabi/userboot/start.cc 17 | +++ b/zircon/kernel/lib/userabi/userboot/start.cc 18 | @@ -81,9 +81,9 @@ zx_handle_t reserve_low_address_space(zx_handle_t log, zx_handle_t root_vmar) { 19 | "zx_object_get_info failed on child root VMAR handle"); 20 | zx_handle_t vmar; 21 | uintptr_t addr; 22 | - size_t reserve_size = (((info.base + info.len) / 2) + PAGE_SIZE - 1) & -PAGE_SIZE; 23 | + size_t reserve_size = (info.len / 2 + PAGE_SIZE - 1) & -PAGE_SIZE; 24 | zx_status_t status = 25 | - zx_vmar_allocate(root_vmar, ZX_VM_SPECIFIC, 0, reserve_size - info.base, &vmar, &addr); 26 | + zx_vmar_allocate(root_vmar, ZX_VM_SPECIFIC, 0, reserve_size, &vmar, &addr); 27 | check(log, status, "zx_vmar_allocate failed for low address space reservation"); 28 | if (addr != info.base) 29 | fail(log, "zx_vmar_allocate gave wrong address?!?"); 30 | diff --git a/zircon/system/ulib/launchpad/launchpad.c b/zircon/system/ulib/launchpad/launchpad.c 31 | index 1a538fadc53..c465e6ae5c4 100644 32 | --- a/zircon/system/ulib/launchpad/launchpad.c 33 | +++ b/zircon/system/ulib/launchpad/launchpad.c 34 | @@ -468,8 +468,8 @@ static zx_status_t reserve_low_address_space(launchpad_t* lp) { 35 | } 36 | 37 | uintptr_t addr; 38 | - size_t reserve_size = (((info.base + info.len) / 2) + PAGE_SIZE - 1) & -PAGE_SIZE; 39 | - status = zx_vmar_allocate(lp_vmar(lp), ZX_VM_SPECIFIC, 0, reserve_size - info.base, 40 | + size_t reserve_size = (info.len / 2 + PAGE_SIZE - 1) & -PAGE_SIZE; 41 | + status = zx_vmar_allocate(lp_vmar(lp), ZX_VM_SPECIFIC, 0, reserve_size, 42 | &lp->reserve_vmar, &addr); 43 | if (status != ZX_OK) { 44 | return lp_error(lp, status, "zx_vmar_allocate failed for low address space reservation"); 45 | -------------------------------------------------------------------------------- /zircon-object/src/object/signal.rs: -------------------------------------------------------------------------------- 1 | use {super::*, bitflags::bitflags}; 2 | 3 | bitflags! { 4 | /// Signals that waitable kernel objects expose to applications. 5 | #[derive(Default)] 6 | pub struct Signal: u32 { 7 | #[allow(clippy::identity_op)] 8 | const READABLE = 1 << 0; 9 | const WRITABLE = 1 << 1; 10 | const PEER_CLOSED = 1 << 2; 11 | const SIGNALED = 1 << 3; 12 | const HANDLE_CLOSED = 1 << 23; 13 | 14 | const KERNEL_ALL = 0xff_ffff; 15 | const USER_ALL = 0xff << 24; 16 | 17 | const CLOCK_STARTED = 1 << 4; 18 | 19 | const SOCKET_PEER_WRITE_DISABLED = 1 << 4; 20 | const SOCKET_WRITE_DISABLED = 1 << 5; 21 | const SOCKET_CONTROL_READABLE = 1 << 6; 22 | const SOCKET_CONTROL_WRITABLE = 1 << 7; 23 | const SCOEKT_ACCEPT = 1 << 8; 24 | const SOCKET_SHARE = 1 << 9; 25 | const SOCKET_READ_THRESHOLD = 1 << 10; 26 | const SOCKET_WRITE_THRESHOLD = 1 << 11; 27 | 28 | 29 | const TASK_TERMINATED = Self::SIGNALED.bits; 30 | 31 | const JOB_TERMINATED = Self::SIGNALED.bits; 32 | const JOB_NO_JOBS = 1 << 4; 33 | const JOB_NO_PROCESSES = 1 << 5; 34 | 35 | const PROCESS_TERMINATED = Self::SIGNALED.bits; 36 | 37 | const THREAD_TERMINATED = Self::SIGNALED.bits; 38 | const THREAD_RUNNING = 1 << 4; 39 | const THREAD_SUSPENDED = 1 << 5; 40 | 41 | const VMO_ZERO_CHILDREN = Self::SIGNALED.bits; 42 | 43 | const INTERRUPT_SIGNAL = 1 << 4; 44 | 45 | // for Linux 46 | const SIGCHLD = 1 << 6; 47 | 48 | // for user 49 | const USER_SIGNAL_0 = 1 << 24; 50 | const USER_SIGNAL_1 = 1 << 25; 51 | const USER_SIGNAL_2 = 1 << 26; 52 | const USER_SIGNAL_3 = 1 << 27; 53 | const USER_SIGNAL_4 = 1 << 28; 54 | const USER_SIGNAL_5 = 1 << 29; 55 | const USER_SIGNAL_6 = 1 << 30; 56 | const USER_SIGNAL_7 = 1 << 31; 57 | } 58 | } 59 | 60 | impl Signal { 61 | pub fn verify_user_signal(allowed_signals: Signal, number: u32) -> ZxResult { 62 | if (number & !allowed_signals.bits()) != 0 { 63 | Err(ZxError::INVALID_ARGS) 64 | } else { 65 | Ok(Signal::from_bits(number).ok_or(ZxError::INVALID_ARGS)?) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /linux-object/src/loader/mod.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::error::LxResult, 3 | crate::fs::INodeExt, 4 | alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec}, 5 | rcore_fs::vfs::INode, 6 | xmas_elf::ElfFile, 7 | zircon_object::{util::elf_loader::*, vm::*, ZxError}, 8 | }; 9 | 10 | mod abi; 11 | 12 | /// Linux ELF Program Loader. 13 | pub struct LinuxElfLoader { 14 | pub syscall_entry: usize, 15 | pub stack_pages: usize, 16 | pub root_inode: Arc, 17 | } 18 | 19 | impl LinuxElfLoader { 20 | pub fn load( 21 | &self, 22 | vmar: &Arc, 23 | data: &[u8], 24 | mut args: Vec, 25 | envs: Vec, 26 | ) -> LxResult<(VirtAddr, VirtAddr)> { 27 | let elf = ElfFile::new(data).map_err(|_| ZxError::INVALID_ARGS)?; 28 | if let Ok(interp) = elf.get_interpreter() { 29 | info!("interp: {:?}", interp); 30 | let inode = self.root_inode.lookup(interp)?; 31 | let data = inode.read_as_vec()?; 32 | args.insert(0, interp.into()); 33 | return self.load(vmar, &data, args, envs); 34 | } 35 | 36 | let size = elf.load_segment_size(); 37 | let image_vmar = vmar.allocate(None, size, VmarFlags::CAN_MAP_RXW, PAGE_SIZE)?; 38 | let base = image_vmar.addr(); 39 | let vmo = image_vmar.load_from_elf(&elf)?; 40 | let entry = base + elf.header.pt2.entry_point() as usize; 41 | 42 | // fill syscall entry 43 | if let Some(offset) = elf.get_symbol_address("rcore_syscall_entry") { 44 | vmo.write(offset as usize, &self.syscall_entry.to_ne_bytes())?; 45 | } 46 | 47 | elf.relocate(base).map_err(|_| ZxError::INVALID_ARGS)?; 48 | 49 | let stack_vmo = VmObject::new_paged(self.stack_pages); 50 | let flags = MMUFlags::READ | MMUFlags::WRITE | MMUFlags::USER; 51 | let stack_bottom = vmar.map(None, stack_vmo.clone(), 0, stack_vmo.len(), flags)?; 52 | let mut sp = stack_bottom + stack_vmo.len(); 53 | 54 | let info = abi::ProcInitInfo { 55 | args, 56 | envs, 57 | auxv: { 58 | let mut map = BTreeMap::new(); 59 | map.insert(abi::AT_BASE, base); 60 | map.insert(abi::AT_PHDR, base + elf.header.pt2.ph_offset() as usize); 61 | map.insert(abi::AT_ENTRY, entry); 62 | map.insert(abi::AT_PHENT, elf.header.pt2.ph_entry_size() as usize); 63 | map.insert(abi::AT_PHNUM, elf.header.pt2.ph_count() as usize); 64 | map.insert(abi::AT_PAGESZ, PAGE_SIZE); 65 | map 66 | }, 67 | }; 68 | let init_stack = info.push_at(sp); 69 | stack_vmo.write(self.stack_pages * PAGE_SIZE - init_stack.len(), &init_stack)?; 70 | sp -= init_stack.len(); 71 | 72 | Ok((entry, sp)) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /zircon-loader/src/main.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, unused_must_use)] 2 | 3 | extern crate log; 4 | 5 | use std::sync::Arc; 6 | use {std::path::PathBuf, structopt::StructOpt, zircon_loader::*, zircon_object::object::*}; 7 | 8 | #[derive(Debug, StructOpt)] 9 | #[structopt()] 10 | struct Opt { 11 | #[structopt(parse(from_os_str))] 12 | prebuilt_path: PathBuf, 13 | 14 | #[structopt(default_value = "")] 15 | cmdline: String, 16 | } 17 | 18 | #[async_std::main] 19 | async fn main() { 20 | kernel_hal_unix::init(); 21 | init_logger(); 22 | 23 | let opt = Opt::from_args(); 24 | let images = open_images(&opt.prebuilt_path).expect("failed to read file"); 25 | 26 | let proc: Arc = run_userboot(&images, &opt.cmdline); 27 | drop(images); 28 | 29 | proc.wait_signal(Signal::USER_SIGNAL_0).await; 30 | } 31 | 32 | fn open_images(path: &PathBuf) -> std::io::Result>> { 33 | Ok(Images { 34 | userboot: std::fs::read(path.join("userboot-libos.so"))?, 35 | vdso: std::fs::read(path.join("libzircon-libos.so"))?, 36 | zbi: std::fs::read(path.join("bringup.zbi"))?, 37 | }) 38 | } 39 | 40 | fn init_logger() { 41 | env_logger::builder() 42 | .format(|buf, record| { 43 | use env_logger::fmt::Color; 44 | use log::Level; 45 | use std::io::Write; 46 | 47 | let (tid, pid) = kernel_hal::Thread::get_tid(); 48 | let mut style = buf.style(); 49 | match record.level() { 50 | Level::Trace => style.set_color(Color::Black).set_intense(true), 51 | Level::Debug => style.set_color(Color::White), 52 | Level::Info => style.set_color(Color::Green), 53 | Level::Warn => style.set_color(Color::Yellow), 54 | Level::Error => style.set_color(Color::Red).set_bold(true), 55 | }; 56 | let now = kernel_hal_unix::timer_now(); 57 | let level = style.value(record.level()); 58 | let args = record.args(); 59 | writeln!(buf, "[{:?} {:>5} {}:{}] {}", now, level, pid, tid, args) 60 | }) 61 | .init(); 62 | } 63 | 64 | #[cfg(test)] 65 | mod tests { 66 | use super::*; 67 | 68 | #[async_std::test] 69 | async fn userboot() { 70 | kernel_hal_unix::init(); 71 | 72 | let opt = Opt { 73 | #[cfg(target_arch = "x86_64")] 74 | prebuilt_path: PathBuf::from("../prebuilt/zircon/x64"), 75 | #[cfg(target_arch = "aarch64")] 76 | prebuilt_path: PathBuf::from("../prebuilt/zircon/arm64"), 77 | cmdline: String::from(""), 78 | }; 79 | let images = open_images(&opt.prebuilt_path).expect("failed to read file"); 80 | 81 | let proc: Arc = run_userboot(&images, &opt.cmdline); 82 | drop(images); 83 | 84 | proc.wait_signal(Signal::PROCESS_TERMINATED).await; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /zircon-object/src/util/block_range.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | /// Given a range and iterate sub-range for each block 4 | pub struct BlockIter { 5 | pub begin: usize, 6 | pub end: usize, 7 | pub block_size_log2: u8, 8 | } 9 | 10 | #[derive(Debug, Eq, PartialEq)] 11 | pub struct BlockRange { 12 | pub block: usize, 13 | pub begin: usize, 14 | pub end: usize, 15 | pub block_size_log2: u8, 16 | } 17 | 18 | impl BlockRange { 19 | pub fn len(&self) -> usize { 20 | self.end - self.begin 21 | } 22 | pub fn is_full(&self) -> bool { 23 | self.len() == (1usize << self.block_size_log2) 24 | } 25 | pub fn is_empty(&self) -> bool { 26 | self.len() == 0 27 | } 28 | pub fn origin_begin(&self) -> usize { 29 | (self.block << self.block_size_log2) + self.begin 30 | } 31 | pub fn origin_end(&self) -> usize { 32 | (self.block << self.block_size_log2) + self.end 33 | } 34 | } 35 | 36 | impl Iterator for BlockIter { 37 | type Item = BlockRange; 38 | 39 | fn next(&mut self) -> Option<::Item> { 40 | if self.begin >= self.end { 41 | return None; 42 | } 43 | let block_size_log2 = self.block_size_log2; 44 | let block_size = 1usize << self.block_size_log2; 45 | let block = self.begin / block_size; 46 | let begin = self.begin % block_size; 47 | let end = if block == self.end / block_size { 48 | self.end % block_size 49 | } else { 50 | block_size 51 | }; 52 | self.begin += end - begin; 53 | Some(BlockRange { 54 | block, 55 | begin, 56 | end, 57 | block_size_log2, 58 | }) 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod test { 64 | use super::*; 65 | 66 | #[test] 67 | fn block_iter() { 68 | let mut iter = BlockIter { 69 | begin: 0x123, 70 | end: 0x2018, 71 | block_size_log2: 12, 72 | }; 73 | assert_eq!( 74 | iter.next(), 75 | Some(BlockRange { 76 | block: 0, 77 | begin: 0x123, 78 | end: 0x1000, 79 | block_size_log2: 12 80 | }) 81 | ); 82 | assert_eq!( 83 | iter.next(), 84 | Some(BlockRange { 85 | block: 1, 86 | begin: 0, 87 | end: 0x1000, 88 | block_size_log2: 12 89 | }) 90 | ); 91 | assert_eq!( 92 | iter.next(), 93 | Some(BlockRange { 94 | block: 2, 95 | begin: 0, 96 | end: 0x18, 97 | block_size_log2: 12 98 | }) 99 | ); 100 | assert_eq!(iter.next(), None); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /zircon-syscall/src/fifo.rs: -------------------------------------------------------------------------------- 1 | use {super::*, zircon_object::ipc::Fifo}; 2 | 3 | impl Syscall<'_> { 4 | pub fn sys_fifo_create( 5 | &self, 6 | elem_count: usize, 7 | elem_size: usize, 8 | options: u32, 9 | mut out0: UserOutPtr, 10 | mut out1: UserOutPtr, 11 | ) -> ZxResult { 12 | info!( 13 | "fifo.create: count={:#x}, item_size={:#x}, options={:#x}", 14 | elem_count, elem_size, options, 15 | ); 16 | if options != 0 { 17 | return Err(ZxError::OUT_OF_RANGE); 18 | } 19 | if !elem_count.is_power_of_two() || elem_size == 0 || elem_count * elem_size > 4096 { 20 | return Err(ZxError::OUT_OF_RANGE); 21 | } 22 | let (end0, end1) = Fifo::create(elem_count, elem_size); 23 | let proc = self.thread.proc(); 24 | let handle0 = proc.add_handle(Handle::new(end0, Rights::DEFAULT_FIFO)); 25 | let handle1 = proc.add_handle(Handle::new(end1, Rights::DEFAULT_FIFO)); 26 | out0.write(handle0)?; 27 | out1.write(handle1)?; 28 | Ok(()) 29 | } 30 | 31 | pub fn sys_fifo_write( 32 | &self, 33 | handle_value: HandleValue, 34 | elem_size: usize, 35 | user_bytes: UserInPtr, 36 | count: usize, 37 | mut actual_count_ptr: UserOutPtr, 38 | ) -> ZxResult { 39 | info!( 40 | "fifo.write: handle={:?}, item_size={}, count={:#x}", 41 | handle_value, elem_size, count 42 | ); 43 | if count == 0 { 44 | return Err(ZxError::OUT_OF_RANGE); 45 | } 46 | let proc = self.thread.proc(); 47 | let fifo = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; 48 | let data = user_bytes.read_array(count * elem_size)?; 49 | let actual_count = fifo.write(elem_size, &data, count)?; 50 | actual_count_ptr.write_if_not_null(actual_count)?; 51 | Ok(()) 52 | } 53 | 54 | pub fn sys_fifo_read( 55 | &self, 56 | handle_value: HandleValue, 57 | elem_size: usize, 58 | mut user_bytes: UserOutPtr, 59 | count: usize, 60 | mut actual_count_ptr: UserOutPtr, 61 | ) -> ZxResult { 62 | info!( 63 | "fifo.read: handle={:?}, item_size={}, count={:#x}", 64 | handle_value, elem_size, count 65 | ); 66 | if count == 0 { 67 | return Err(ZxError::OUT_OF_RANGE); 68 | } 69 | let proc = self.thread.proc(); 70 | let fifo = proc.get_object_with_rights::(handle_value, Rights::READ)?; 71 | // TODO: uninit buffer 72 | let mut data = vec![0; elem_size * count]; 73 | let actual_count = fifo.read(elem_size, count, &mut data)?; 74 | actual_count_ptr.write_if_not_null(actual_count)?; 75 | user_bytes.write_array(&data)?; 76 | Ok(()) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /zircon-syscall/src/handle.rs: -------------------------------------------------------------------------------- 1 | use {super::*, core::convert::TryFrom}; 2 | 3 | impl Syscall<'_> { 4 | pub fn sys_handle_duplicate( 5 | &self, 6 | handle_value: HandleValue, 7 | rights: u32, 8 | mut new_handle_value: UserOutPtr, 9 | ) -> ZxResult { 10 | let rights = Rights::try_from(rights)?; 11 | info!( 12 | "handle.dup: handle={:#x?}, rights={:?}", 13 | handle_value, rights 14 | ); 15 | let proc = self.thread.proc(); 16 | let new_value = proc.dup_handle_operating_rights(handle_value, |handle_rights| { 17 | if !handle_rights.contains(Rights::DUPLICATE) { 18 | return Err(ZxError::ACCESS_DENIED); 19 | } 20 | if !rights.contains(Rights::SAME_RIGHTS) { 21 | if (handle_rights & rights).bits() != rights.bits() { 22 | return Err(ZxError::INVALID_ARGS); 23 | } 24 | Ok(rights) 25 | } else { 26 | Ok(handle_rights) 27 | } 28 | })?; 29 | new_handle_value.write(new_value)?; 30 | Ok(()) 31 | } 32 | 33 | pub fn sys_handle_close(&self, handle: HandleValue) -> ZxResult { 34 | info!("handle.close: handle={:?}", handle); 35 | if handle == INVALID_HANDLE { 36 | return Ok(()); 37 | } 38 | let proc = self.thread.proc(); 39 | proc.remove_handle(handle)?; 40 | Ok(()) 41 | } 42 | 43 | pub fn sys_handle_close_many( 44 | &self, 45 | handles: UserInPtr, 46 | num_handles: usize, 47 | ) -> ZxResult { 48 | info!( 49 | "handle.close_many: handles=({:#x?}; {:#x?})", 50 | handles, num_handles, 51 | ); 52 | let proc = self.thread.proc(); 53 | let handles = handles.read_array(num_handles)?; 54 | for handle in handles { 55 | if handle == INVALID_HANDLE { 56 | continue; 57 | } 58 | proc.remove_handle(handle)?; 59 | } 60 | Ok(()) 61 | } 62 | 63 | pub fn sys_handle_replace( 64 | &self, 65 | handle_value: HandleValue, 66 | rights: u32, 67 | mut out: UserOutPtr, 68 | ) -> ZxResult { 69 | let rights = Rights::try_from(rights)?; 70 | info!( 71 | "handle.replace: handle={:#x?}, rights={:?}", 72 | handle_value, rights 73 | ); 74 | let proc = self.thread.proc(); 75 | let new_value = proc.dup_handle_operating_rights(handle_value, |handle_rights| { 76 | if !rights.contains(Rights::SAME_RIGHTS) 77 | && (handle_rights & rights).bits() != rights.bits() 78 | { 79 | return Err(ZxError::INVALID_ARGS); 80 | } 81 | Ok(rights) 82 | })?; 83 | proc.remove_handle(handle_value)?; 84 | out.write(new_value)?; 85 | Ok(()) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /kernel-hal-unix/src/macos.rs: -------------------------------------------------------------------------------- 1 | /// Register signal handler for SIGSEGV (Segmentation Fault). 2 | /// 3 | /// 4 | unsafe fn register_sigsegv_handler() { 5 | let sa = libc::sigaction { 6 | sa_sigaction: handler as usize, 7 | sa_flags: libc::SA_SIGINFO, 8 | sa_mask: 0, 9 | }; 10 | libc::sigaction(libc::SIGSEGV, &sa, core::ptr::null_mut()); 11 | 12 | #[repr(C)] 13 | struct Ucontext { 14 | uc_onstack: i32, 15 | uc_sigmask: u32, 16 | uc_stack: [u32; 5], 17 | uc_link: usize, 18 | uc_mcsize: usize, 19 | uc_mcontext: *const Mcontext, 20 | } 21 | 22 | #[repr(C)] 23 | #[derive(Debug)] 24 | struct Mcontext { 25 | trapno: u16, 26 | cpu: u16, 27 | err: u32, 28 | faultvaddr: u64, 29 | rax: u64, 30 | rbx: u64, 31 | rcx: u64, 32 | rdx: u64, 33 | rdi: u64, 34 | rsi: u64, 35 | rbp: u64, 36 | rsp: u64, 37 | r8: u64, 38 | r9: u64, 39 | r10: u64, 40 | r11: u64, 41 | r12: u64, 42 | r13: u64, 43 | r14: u64, 44 | r15: u64, 45 | rip: u64, 46 | rflags: u64, 47 | cs: u64, 48 | fs: u64, 49 | gs: u64, 50 | } 51 | 52 | /// Signal handler for when code tries to use %fs. 53 | /// 54 | /// Ref: https://github.com/NuxiNL/cloudabi-utils/blob/38d845bc5cc6fcf441fe0d3c2433f9298cbeb760/src/libemulator/tls.c#L30-L53 55 | unsafe extern "C" fn handler( 56 | _sig: libc::c_int, 57 | _si: *const libc::siginfo_t, 58 | uc: *const Ucontext, 59 | ) { 60 | let mut rip = (*(*uc).uc_mcontext).rip as *mut u8; 61 | // skip data16 prefix 62 | while rip.read() == 0x66 { 63 | rip = rip.add(1); 64 | } 65 | match rip.read() { 66 | // Instruction starts with 0x64, meaning it tries to access %fs. By 67 | // changing the first byte to 0x65, it uses %gs instead. 68 | 0x64 => rip.write(0x65), 69 | // Instruction has already been patched up, but it may well be the 70 | // case that this was done by another CPU core. There is nothing 71 | // else we can do than return and try again. This may cause us to 72 | // get stuck indefinitely. 73 | 0x65 => {} 74 | // Segmentation violation on an instruction that does not try to 75 | // access %fs. Reset the handler to its default action, so that the 76 | // segmentation violation is rethrown. 77 | _ => { 78 | // switch back to kernel gs 79 | asm!( 80 | " 81 | mov rdi, gs:48 82 | syscall 83 | ", 84 | in("eax") 0x3000003, 85 | out("rdi") _, 86 | out("rcx") _, 87 | out("r11") _, 88 | ); 89 | panic!("catch SIGSEGV: {:#x?}", *(*uc).uc_mcontext); 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /zircon-syscall/src/debuglog.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | zircon_object::{debuglog::*, dev::*}, 4 | }; 5 | 6 | impl Syscall<'_> { 7 | pub fn sys_debuglog_create( 8 | &self, 9 | rsrc: HandleValue, 10 | options: u32, 11 | mut target: UserOutPtr, 12 | ) -> ZxResult { 13 | info!( 14 | "debuglog.create: resource_handle={:#x?}, options={:#x?}", 15 | rsrc, options, 16 | ); 17 | let proc = self.thread.proc(); 18 | if rsrc != 0 { 19 | proc.get_object::(rsrc)? 20 | .validate(ResourceKind::ROOT)?; 21 | } 22 | let dlog = DebugLog::create(options); 23 | const FLAG_READABLE: u32 = 0x4000_0000u32; 24 | let dlog_right = if options & FLAG_READABLE == 0 { 25 | Rights::DEFAULT_DEBUGLOG 26 | } else { 27 | Rights::DEFAULT_DEBUGLOG | Rights::READ 28 | }; 29 | let dlog_handle = proc.add_handle(Handle::new(dlog, dlog_right)); 30 | target.write(dlog_handle)?; 31 | Ok(()) 32 | } 33 | 34 | pub fn sys_debuglog_write( 35 | &self, 36 | handle_value: HandleValue, 37 | options: u32, 38 | buf: UserInPtr, 39 | len: usize, 40 | ) -> ZxResult { 41 | info!( 42 | "debuglog.write: handle={:#x?}, options={:#x?}, buf=({:#x?}; {:#x?})", 43 | handle_value, options, buf, len, 44 | ); 45 | const LOG_FLAGS_MASK: u32 = 0x10; 46 | if options & !LOG_FLAGS_MASK != 0 { 47 | return Err(ZxError::INVALID_ARGS); 48 | } 49 | let datalen = len.min(224); 50 | let data = buf.read_string(datalen as usize)?; 51 | let proc = self.thread.proc(); 52 | let dlog = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; 53 | dlog.write(Severity::Info, options, self.thread.id(), proc.id(), &data); 54 | // print to kernel console 55 | kernel_hal::serial_write(&data); 56 | if data.as_bytes().last() != Some(&b'\n') { 57 | kernel_hal::serial_write("\n"); 58 | } 59 | Ok(()) 60 | } 61 | 62 | #[allow(unsafe_code)] 63 | pub fn sys_debuglog_read( 64 | &self, 65 | handle_value: HandleValue, 66 | options: u32, 67 | mut buf: UserOutPtr, 68 | len: usize, 69 | ) -> ZxResult { 70 | info!( 71 | "debuglog.read: handle={:#x?}, options={:#x?}, buf=({:#x?}; {:#x?})", 72 | handle_value, options, buf, len, 73 | ); 74 | if options != 0 { 75 | return Err(ZxError::INVALID_ARGS); 76 | } 77 | let proc = self.thread.proc(); 78 | let mut buffer = [0; DLOG_MAX_LEN]; 79 | let dlog = proc.get_object_with_rights::(handle_value, Rights::READ)?; 80 | let actual_len = dlog.read(&mut buffer).min(len); 81 | if actual_len == 0 { 82 | return Err(ZxError::SHOULD_WAIT); 83 | } 84 | buf.write_array(&buffer[..actual_len])?; 85 | // special case: return actual_len as status 86 | Err(unsafe { core::mem::transmute(actual_len as u32) }) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /zircon-object/src/dev/resource.rs: -------------------------------------------------------------------------------- 1 | use {crate::object::*, alloc::sync::Arc, bitflags::bitflags, numeric_enum_macro::numeric_enum}; 2 | 3 | numeric_enum! { 4 | #[repr(u32)] 5 | /// ResourceKind definition from fuchsia/zircon/system/public/zircon/syscalls/resource.h 6 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 7 | pub enum ResourceKind { 8 | MMIO = 0, 9 | IRQ = 1, 10 | IOPORT = 2, 11 | HYPERVISOR = 3, 12 | ROOT = 4, 13 | VMEX = 5, 14 | SMC = 6, 15 | COUNT = 7, 16 | } 17 | } 18 | 19 | bitflags! { 20 | pub struct ResourceFlags: u32 { 21 | #[allow(clippy::identity_op)] 22 | const EXCLUSIVE = 1 << 16; 23 | } 24 | } 25 | 26 | /// Address space rights and accounting. 27 | pub struct Resource { 28 | base: KObjectBase, 29 | kind: ResourceKind, 30 | addr: usize, 31 | len: usize, 32 | flags: ResourceFlags, 33 | } 34 | 35 | impl_kobject!(Resource); 36 | 37 | impl Resource { 38 | /// Create a new `Resource`. 39 | pub fn create( 40 | name: &str, 41 | kind: ResourceKind, 42 | addr: usize, 43 | len: usize, 44 | flags: ResourceFlags, 45 | ) -> Arc { 46 | Arc::new(Resource { 47 | base: KObjectBase::with_name(name), 48 | kind, 49 | addr, 50 | len, 51 | flags, 52 | }) 53 | } 54 | 55 | pub fn validate(&self, kind: ResourceKind) -> ZxResult { 56 | if self.kind == kind || self.kind == ResourceKind::ROOT { 57 | Ok(()) 58 | } else { 59 | Err(ZxError::WRONG_TYPE) 60 | } 61 | } 62 | 63 | pub fn validate_ranged_resource( 64 | &self, 65 | kind: ResourceKind, 66 | addr: usize, 67 | len: usize, 68 | ) -> ZxResult { 69 | self.validate(kind)?; 70 | if addr >= self.addr && (addr + len) <= (self.addr + self.len) { 71 | Ok(()) 72 | } else { 73 | Err(ZxError::OUT_OF_RANGE) 74 | } 75 | } 76 | 77 | pub fn check_exclusive(&self, flags: ResourceFlags) -> ZxResult { 78 | if self.kind != ResourceKind::ROOT 79 | && (self.flags.contains(ResourceFlags::EXCLUSIVE) 80 | || flags.contains(ResourceFlags::EXCLUSIVE)) 81 | { 82 | Err(ZxError::INVALID_ARGS) 83 | } else { 84 | Ok(()) 85 | } 86 | } 87 | 88 | pub fn get_info(&self) -> ResourceInfo { 89 | let name = self.base.name(); 90 | let name = name.as_bytes(); 91 | let mut name_vec = [0 as u8; 32]; 92 | name_vec[..name.len()].clone_from_slice(name); 93 | ResourceInfo { 94 | kind: self.kind as _, 95 | flags: self.flags.bits, 96 | base: self.addr as _, 97 | size: self.len as _, 98 | name: name_vec, 99 | } 100 | } 101 | } 102 | 103 | #[repr(C)] 104 | #[derive(Default)] 105 | pub struct ResourceInfo { 106 | kind: u32, 107 | flags: u32, 108 | base: u64, 109 | size: u64, 110 | name: [u8; 32], // should be [char; 32], but I cannot compile it 111 | } 112 | -------------------------------------------------------------------------------- /zircon-syscall/src/signal.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | core::time::Duration, 4 | zircon_object::{signal::*, task::PolicyCondition}, 5 | }; 6 | 7 | impl Syscall<'_> { 8 | pub fn sys_timer_create( 9 | &self, 10 | options: u32, 11 | clock_id: u32, 12 | mut out: UserOutPtr, 13 | ) -> ZxResult { 14 | info!( 15 | "timer.create: options={:#x}, clock_id={:#x}", 16 | options, clock_id 17 | ); 18 | if clock_id != 0 { 19 | return Err(ZxError::INVALID_ARGS); 20 | } 21 | let proc = self.thread.proc(); 22 | proc.check_policy(PolicyCondition::NewTimer)?; 23 | let slack = match options { 24 | 0 => Slack::Center, 25 | 1 => Slack::Early, 26 | 2 => Slack::Late, 27 | _ => return Err(ZxError::INVALID_ARGS), 28 | }; 29 | let handle = Handle::new(Timer::with_slack(slack), Rights::DEFAULT_TIMER); 30 | out.write(proc.add_handle(handle))?; 31 | Ok(()) 32 | } 33 | 34 | pub fn sys_event_create(&self, options: u32, mut out: UserOutPtr) -> ZxResult { 35 | info!("event.create: options={:#x}", options); 36 | if options != 0 { 37 | return Err(ZxError::INVALID_ARGS); 38 | } 39 | let proc = self.thread.proc(); 40 | proc.check_policy(PolicyCondition::NewEvent)?; 41 | let handle = Handle::new(Event::new(), Rights::DEFAULT_EVENT); 42 | out.write(proc.add_handle(handle))?; 43 | Ok(()) 44 | } 45 | 46 | pub fn sys_eventpair_create( 47 | &self, 48 | options: u32, 49 | mut out0: UserOutPtr, 50 | mut out1: UserOutPtr, 51 | ) -> ZxResult { 52 | info!("eventpair.create: options={:#x}", options); 53 | if options != 0 { 54 | return Err(ZxError::NOT_SUPPORTED); 55 | } 56 | let proc = self.thread.proc(); 57 | proc.check_policy(PolicyCondition::NewEvent)?; 58 | let (event0, event1) = EventPair::create(); 59 | let handle0 = Handle::new(event0, Rights::DEFAULT_EVENTPAIR); 60 | let handle1 = Handle::new(event1, Rights::DEFAULT_EVENTPAIR); 61 | out0.write(proc.add_handle(handle0))?; 62 | out1.write(proc.add_handle(handle1))?; 63 | Ok(()) 64 | } 65 | 66 | pub fn sys_timer_set(&self, handle: HandleValue, deadline: Deadline, slack: i64) -> ZxResult { 67 | info!( 68 | "timer.set: handle={:#x}, deadline={:#x?}, slack={:#x}", 69 | handle, deadline, slack 70 | ); 71 | if slack.is_negative() { 72 | return Err(ZxError::OUT_OF_RANGE); 73 | } 74 | let proc = self.thread.proc(); 75 | let timer = proc.get_object_with_rights::(handle, Rights::WRITE)?; 76 | timer.set(Duration::from(deadline), Duration::from_nanos(slack as u64)); 77 | Ok(()) 78 | } 79 | 80 | pub fn sys_timer_cancel(&self, handle: HandleValue) -> ZxResult { 81 | info!("timer.cancel: handle={:#x}", handle); 82 | let proc = self.thread.proc(); 83 | let timer = proc.get_object_with_rights::(handle, Rights::WRITE)?; 84 | timer.cancel(); 85 | Ok(()) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /zircon-object/src/dev/bti.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | crate::object::*, 4 | crate::vm::*, 5 | alloc::{sync::Arc, vec::Vec}, 6 | dev::Iommu, 7 | spin::Mutex, 8 | }; 9 | 10 | /// Bus Transaction Initiator. 11 | /// 12 | /// Bus Transaction Initiators (BTIs) represent the bus mastering/DMA capability 13 | /// of a device, and can be used for granting a device access to memory. 14 | pub struct BusTransactionInitiator { 15 | base: KObjectBase, 16 | iommu: Arc, 17 | #[allow(dead_code)] 18 | bti_id: u64, 19 | inner: Mutex, 20 | } 21 | 22 | #[derive(Default)] 23 | struct BtiInner { 24 | /// A BTI manages a list of quarantined PMTs. 25 | pmts: Vec>, 26 | } 27 | 28 | impl_kobject!(BusTransactionInitiator); 29 | 30 | impl BusTransactionInitiator { 31 | /// Create a new bus transaction initiator. 32 | pub fn create(iommu: Arc, bti_id: u64) -> Arc { 33 | Arc::new(BusTransactionInitiator { 34 | base: KObjectBase::new(), 35 | iommu, 36 | bti_id, 37 | inner: Mutex::new(BtiInner::default()), 38 | }) 39 | } 40 | 41 | /// Get information of BTI. 42 | pub fn get_info(&self) -> BtiInfo { 43 | BtiInfo { 44 | minimum_contiguity: self.iommu.minimum_contiguity() as u64, 45 | aspace_size: self.iommu.aspace_size() as u64, 46 | pmo_count: self.pmo_count() as u64, 47 | quarantine_count: self.quarantine_count() as u64, 48 | } 49 | } 50 | 51 | /// Pin memory and grant access to it to the BTI. 52 | pub fn pin( 53 | self: &Arc, 54 | vmo: Arc, 55 | offset: usize, 56 | size: usize, 57 | perms: IommuPerms, 58 | ) -> ZxResult> { 59 | if size == 0 { 60 | return Err(ZxError::INVALID_ARGS); 61 | } 62 | let pmt = PinnedMemoryToken::create(self, vmo, perms, offset, size)?; 63 | self.inner.lock().pmts.push(pmt.clone()); 64 | Ok(pmt) 65 | } 66 | 67 | /// Releases all quarantined PMTs. 68 | pub fn release_quarantine(&self) { 69 | let mut inner = self.inner.lock(); 70 | // remove no handle, the only Arc is from self.pmts 71 | inner.pmts.retain(|pmt| Arc::strong_count(pmt) > 1); 72 | } 73 | 74 | /// Release a PMT by KoID. 75 | pub(super) fn release_pmt(&self, id: KoID) { 76 | let mut inner = self.inner.lock(); 77 | inner.pmts.retain(|pmt| pmt.id() != id); 78 | } 79 | 80 | pub(super) fn iommu(&self) -> Arc { 81 | self.iommu.clone() 82 | } 83 | 84 | fn pmo_count(&self) -> usize { 85 | self.inner.lock().pmts.len() 86 | } 87 | 88 | fn quarantine_count(&self) -> usize { 89 | self.inner 90 | .lock() 91 | .pmts 92 | .iter() 93 | .filter(|pmt| Arc::strong_count(pmt) == 1) 94 | .count() 95 | } 96 | } 97 | 98 | #[repr(C)] 99 | #[derive(Default)] 100 | pub struct BtiInfo { 101 | minimum_contiguity: u64, 102 | aspace_size: u64, 103 | pmo_count: u64, 104 | quarantine_count: u64, 105 | } 106 | -------------------------------------------------------------------------------- /linux-object/src/loader/abi.rs: -------------------------------------------------------------------------------- 1 | #![allow(unsafe_code)] 2 | 3 | use alloc::collections::btree_map::BTreeMap; 4 | use alloc::string::String; 5 | use alloc::vec::Vec; 6 | use core::mem::{align_of, size_of}; 7 | use core::ops::Deref; 8 | use core::ptr::null; 9 | 10 | pub struct ProcInitInfo { 11 | pub args: Vec, 12 | pub envs: Vec, 13 | pub auxv: BTreeMap, 14 | } 15 | 16 | impl ProcInitInfo { 17 | pub fn push_at(&self, stack_top: usize) -> Stack { 18 | let mut writer = Stack::new(stack_top); 19 | // from stack_top: 20 | // program name 21 | writer.push_str(&self.args[0]); 22 | // environment strings 23 | let envs: Vec<_> = self 24 | .envs 25 | .iter() 26 | .map(|arg| { 27 | writer.push_str(arg.as_str()); 28 | writer.sp 29 | }) 30 | .collect(); 31 | // argv strings 32 | let argv: Vec<_> = self 33 | .args 34 | .iter() 35 | .map(|arg| { 36 | writer.push_str(arg.as_str()); 37 | writer.sp 38 | }) 39 | .collect(); 40 | // auxiliary vector entries 41 | writer.push_slice(&[null::(), null::()]); 42 | for (&type_, &value) in self.auxv.iter() { 43 | writer.push_slice(&[type_ as usize, value]); 44 | } 45 | // envionment pointers 46 | writer.push_slice(&[null::()]); 47 | writer.push_slice(envs.as_slice()); 48 | // argv pointers 49 | writer.push_slice(&[null::()]); 50 | writer.push_slice(argv.as_slice()); 51 | // argc 52 | writer.push_slice(&[argv.len()]); 53 | writer 54 | } 55 | } 56 | 57 | pub struct Stack { 58 | sp: usize, 59 | stack_top: usize, 60 | data: Vec, 61 | } 62 | 63 | impl Stack { 64 | fn new(sp: usize) -> Self { 65 | let mut data = Vec::with_capacity(0x4000); 66 | unsafe { 67 | data.set_len(0x4000); 68 | } 69 | Stack { 70 | sp, 71 | stack_top: sp, 72 | data, 73 | } 74 | } 75 | fn push_slice(&mut self, vs: &[T]) { 76 | self.sp -= vs.len() * size_of::(); 77 | self.sp -= self.sp % align_of::(); 78 | assert!(self.stack_top - self.sp <= self.data.len()); 79 | let offset = self.data.len() - (self.stack_top - self.sp); 80 | unsafe { 81 | core::slice::from_raw_parts_mut(self.data.as_mut_ptr().add(offset) as *mut T, vs.len()) 82 | } 83 | .copy_from_slice(vs); 84 | } 85 | fn push_str(&mut self, s: &str) { 86 | self.push_slice(&[b'\0']); 87 | self.push_slice(s.as_bytes()); 88 | } 89 | } 90 | 91 | impl Deref for Stack { 92 | type Target = [u8]; 93 | 94 | fn deref(&self) -> &Self::Target { 95 | let offset = self.data.len() - (self.stack_top - self.sp); 96 | &self.data[offset..] 97 | } 98 | } 99 | 100 | pub const AT_PHDR: u8 = 3; 101 | pub const AT_PHENT: u8 = 4; 102 | pub const AT_PHNUM: u8 = 5; 103 | pub const AT_PAGESZ: u8 = 6; 104 | pub const AT_BASE: u8 = 7; 105 | pub const AT_ENTRY: u8 = 9; 106 | -------------------------------------------------------------------------------- /zCore/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(lang_items)] 4 | #![feature(asm)] 5 | #![feature(panic_info_message)] 6 | #![deny(unused_must_use)] 7 | #![deny(warnings)] // comment this on develop 8 | 9 | extern crate alloc; 10 | #[macro_use] 11 | extern crate log; 12 | extern crate rlibc_opt; 13 | 14 | #[macro_use] 15 | mod logging; 16 | mod lang; 17 | mod memory; 18 | 19 | use rboot::BootInfo; 20 | 21 | pub use memory::{hal_frame_alloc, hal_frame_dealloc, hal_pt_map_kernel}; 22 | 23 | #[no_mangle] 24 | pub extern "C" fn _start(boot_info: &BootInfo) -> ! { 25 | logging::init(get_log_level(boot_info.cmdline)); 26 | memory::init_heap(); 27 | memory::init_frame_allocator(boot_info); 28 | #[cfg(feature = "graphic")] 29 | init_framebuffer(boot_info); 30 | info!("{:#x?}", boot_info); 31 | kernel_hal_bare::init(kernel_hal_bare::Config { 32 | acpi_rsdp: boot_info.acpi2_rsdp_addr, 33 | smbios: boot_info.smbios_addr, 34 | ap_fn: run, 35 | }); 36 | 37 | let ramfs_data = unsafe { 38 | core::slice::from_raw_parts_mut( 39 | (boot_info.initramfs_addr + boot_info.physical_memory_offset) as *mut u8, 40 | boot_info.initramfs_size as usize, 41 | ) 42 | }; 43 | main(ramfs_data, boot_info.cmdline); 44 | unreachable!(); 45 | } 46 | 47 | #[cfg(feature = "zircon")] 48 | fn main(ramfs_data: &[u8], cmdline: &str) { 49 | use zircon_loader::{run_userboot, Images}; 50 | let images = Images::<&[u8]> { 51 | userboot: include_bytes!("../../prebuilt/zircon/x64/userboot.so"), 52 | vdso: include_bytes!("../../prebuilt/zircon/x64/libzircon.so"), 53 | zbi: ramfs_data, 54 | }; 55 | let _proc = run_userboot(&images, cmdline); 56 | run(); 57 | } 58 | 59 | #[cfg(feature = "linux")] 60 | fn main(ramfs_data: &'static mut [u8], _cmdline: &str) { 61 | use alloc::sync::Arc; 62 | use alloc::vec; 63 | use linux_object::fs::MemBuf; 64 | 65 | let args = vec!["/bin/busybox".into()]; 66 | let envs = vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()]; 67 | 68 | let device = Arc::new(MemBuf::new(ramfs_data)); 69 | let rootfs = rcore_fs_sfs::SimpleFileSystem::open(device).unwrap(); 70 | let _proc = linux_loader::run(args, envs, rootfs); 71 | run(); 72 | } 73 | 74 | fn run() -> ! { 75 | loop { 76 | executor::run_until_idle(); 77 | x86_64::instructions::interrupts::enable_interrupts_and_hlt(); 78 | x86_64::instructions::interrupts::disable(); 79 | } 80 | } 81 | 82 | fn get_log_level(cmdline: &str) -> &str { 83 | for opt in cmdline.split(':') { 84 | // parse 'key=value' 85 | let mut iter = opt.trim().splitn(2, '='); 86 | let key = iter.next().expect("failed to parse key"); 87 | let value = iter.next().expect("failed to parse value"); 88 | if key == "LOG" { 89 | return value; 90 | } 91 | } 92 | "" 93 | } 94 | 95 | #[cfg(feature = "graphic")] 96 | fn init_framebuffer(boot_info: &BootInfo) { 97 | let (width, height) = boot_info.graphic_info.mode.resolution(); 98 | let fb_addr = boot_info.graphic_info.fb_addr as usize; 99 | kernel_hal_bare::init_framebuffer(width as u32, height as u32, fb_addr); 100 | } 101 | -------------------------------------------------------------------------------- /zCore/src/memory.rs: -------------------------------------------------------------------------------- 1 | //! Define the FrameAllocator for physical memory 2 | //! x86_64 -- 64GB 3 | 4 | use { 5 | bitmap_allocator::BitAlloc, 6 | buddy_system_allocator::LockedHeap, 7 | rboot::{BootInfo, MemoryType}, 8 | spin::Mutex, 9 | x86_64::structures::paging::page_table::{PageTable, PageTableFlags as EF}, 10 | }; 11 | 12 | #[cfg(target_arch = "x86_64")] 13 | type FrameAlloc = bitmap_allocator::BitAlloc16M; 14 | 15 | static FRAME_ALLOCATOR: Mutex = Mutex::new(FrameAlloc::DEFAULT); 16 | 17 | const MEMORY_OFFSET: usize = 0; 18 | const KERNEL_OFFSET: usize = 0xffffff00_00000000; 19 | const PHYSICAL_MEMORY_OFFSET: usize = 0xffff8000_00000000; 20 | const KERNEL_HEAP_SIZE: usize = 16 * 1024 * 1024; // 16 MB 21 | 22 | const KERNEL_PM4: usize = (KERNEL_OFFSET >> 39) & 0o777; 23 | const PHYSICAL_MEMORY_PM4: usize = (PHYSICAL_MEMORY_OFFSET >> 39) & 0o777; 24 | 25 | const PAGE_SIZE: usize = 1 << 12; 26 | 27 | #[used] 28 | #[export_name = "hal_pmem_base"] 29 | static PMEM_BASE: usize = PHYSICAL_MEMORY_OFFSET; 30 | 31 | pub fn init_frame_allocator(boot_info: &BootInfo) { 32 | let mut ba = FRAME_ALLOCATOR.lock(); 33 | for region in boot_info.memory_map.clone().iter { 34 | if region.ty == MemoryType::CONVENTIONAL { 35 | let start_frame = region.phys_start as usize / PAGE_SIZE; 36 | let end_frame = start_frame + region.page_count as usize; 37 | ba.insert(start_frame..end_frame); 38 | } 39 | } 40 | info!("Frame allocator init end"); 41 | } 42 | 43 | pub fn init_heap() { 44 | const MACHINE_ALIGN: usize = core::mem::size_of::(); 45 | const HEAP_BLOCK: usize = KERNEL_HEAP_SIZE / MACHINE_ALIGN; 46 | static mut HEAP: [usize; HEAP_BLOCK] = [0; HEAP_BLOCK]; 47 | unsafe { 48 | HEAP_ALLOCATOR 49 | .lock() 50 | .init(HEAP.as_ptr() as usize, HEAP_BLOCK * MACHINE_ALIGN); 51 | } 52 | info!("heap init end"); 53 | } 54 | 55 | #[no_mangle] 56 | pub extern "C" fn hal_frame_alloc() -> Option { 57 | // get the real address of the alloc frame 58 | let ret = FRAME_ALLOCATOR 59 | .lock() 60 | .alloc() 61 | .map(|id| id * PAGE_SIZE + MEMORY_OFFSET); 62 | trace!("Allocate frame: {:x?}", ret); 63 | ret 64 | } 65 | 66 | #[no_mangle] 67 | pub extern "C" fn hal_frame_alloc_contiguous(page_num: usize, align_log2: usize) -> Option { 68 | let ret = FRAME_ALLOCATOR 69 | .lock() 70 | .alloc_contiguous(page_num, align_log2) 71 | .map(|id| id * PAGE_SIZE + MEMORY_OFFSET); 72 | trace!( 73 | "Allocate contiguous frames: {:x?} ~ {:x?}", 74 | ret, 75 | ret.map(|x| x + page_num) 76 | ); 77 | ret 78 | } 79 | 80 | #[no_mangle] 81 | pub extern "C" fn hal_frame_dealloc(target: &usize) { 82 | trace!("Deallocate frame: {:x}", *target); 83 | FRAME_ALLOCATOR 84 | .lock() 85 | .dealloc((*target - MEMORY_OFFSET) / PAGE_SIZE); 86 | } 87 | 88 | #[no_mangle] 89 | pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) { 90 | let ekernel = current[KERNEL_PM4].clone(); 91 | let ephysical = current[PHYSICAL_MEMORY_PM4].clone(); 92 | pt[KERNEL_PM4].set_addr(ekernel.addr(), ekernel.flags() | EF::GLOBAL); 93 | pt[PHYSICAL_MEMORY_PM4].set_addr(ephysical.addr(), ephysical.flags() | EF::GLOBAL); 94 | } 95 | 96 | /// Global heap allocator 97 | /// 98 | /// Available after `memory::init_heap()`. 99 | #[global_allocator] 100 | static HEAP_ALLOCATOR: LockedHeap = LockedHeap::new(); 101 | -------------------------------------------------------------------------------- /zircon-object/src/debuglog.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | crate::object::*, 4 | alloc::{sync::Arc, vec::Vec}, 5 | kernel_hal::timer_now, 6 | lazy_static::lazy_static, 7 | spin::Mutex, 8 | }; 9 | 10 | lazy_static! { 11 | static ref DLOG: Mutex = Mutex::new(DlogBuffer { 12 | buf: Vec::with_capacity(0x1000), 13 | }); 14 | } 15 | 16 | pub struct DebugLog { 17 | base: KObjectBase, 18 | flags: u32, 19 | read_offset: Mutex, 20 | } 21 | 22 | struct DlogBuffer { 23 | /// Append only buffer 24 | buf: Vec, 25 | } 26 | 27 | impl_kobject!(DebugLog); 28 | 29 | impl DebugLog { 30 | /// Create a new `DebugLog`. 31 | pub fn create(flags: u32) -> Arc { 32 | Arc::new(DebugLog { 33 | base: KObjectBase::new(), 34 | flags, 35 | read_offset: Default::default(), 36 | }) 37 | } 38 | 39 | /// Read a log, return the actual read size. 40 | pub fn read(&self, buf: &mut [u8]) -> usize { 41 | let mut offset = self.read_offset.lock(); 42 | let len = DLOG.lock().read_at(*offset, buf); 43 | *offset += len; 44 | len 45 | } 46 | 47 | /// Write a log. 48 | pub fn write(&self, severity: Severity, flags: u32, tid: u64, pid: u64, data: &str) { 49 | DLOG.lock() 50 | .write(severity, flags | self.flags, tid, pid, data.as_bytes()); 51 | } 52 | } 53 | 54 | #[repr(C)] 55 | #[derive(Debug)] 56 | struct DlogHeader { 57 | rollout: u32, 58 | datalen: u16, 59 | severity: Severity, 60 | flags: u8, 61 | timestamp: u64, 62 | pid: u64, 63 | tid: u64, 64 | } 65 | 66 | #[repr(u8)] 67 | #[derive(Debug)] 68 | pub enum Severity { 69 | Trace = 0x10, 70 | Debug = 0x20, 71 | Info = 0x30, 72 | Warning = 0x40, 73 | Error = 0x50, 74 | Fatal = 0x60, 75 | } 76 | 77 | const HEADER_SIZE: usize = core::mem::size_of::(); 78 | pub const DLOG_MAX_LEN: usize = 256; 79 | 80 | #[allow(unsafe_code)] 81 | impl DlogBuffer { 82 | /// Read one record at offset. 83 | #[allow(clippy::cast_ptr_alignment)] 84 | fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> usize { 85 | assert!(buf.len() >= DLOG_MAX_LEN); 86 | if offset == self.buf.len() { 87 | return 0; 88 | } 89 | let header_buf = &self.buf[offset..offset + HEADER_SIZE]; 90 | buf[..HEADER_SIZE].copy_from_slice(header_buf); 91 | let header = unsafe { &*(header_buf.as_ptr() as *const DlogHeader) }; 92 | let len = (header.rollout & 0xFFF) as usize; 93 | buf[HEADER_SIZE..len].copy_from_slice(&self.buf[offset + HEADER_SIZE..offset + len]); 94 | len 95 | } 96 | 97 | fn write(&mut self, severity: Severity, flags: u32, tid: u64, pid: u64, data: &[u8]) { 98 | let wire_size = HEADER_SIZE + align_up_4(data.len()); 99 | let size = HEADER_SIZE + data.len(); 100 | let header = DlogHeader { 101 | rollout: ((size as u32) << 12) | (wire_size as u32), 102 | datalen: data.len() as u16, 103 | severity, 104 | flags: flags as u8, 105 | timestamp: timer_now().as_nanos() as u64, 106 | pid, 107 | tid, 108 | }; 109 | let header_buf: [u8; HEADER_SIZE] = unsafe { core::mem::transmute(header) }; 110 | self.buf.extend(header_buf.iter()); 111 | self.buf.extend(data); 112 | self.buf.extend(&[0u8; 4][..wire_size - size]); 113 | } 114 | } 115 | 116 | fn align_up_4(x: usize) -> usize { 117 | (x + 3) & !3 118 | } 119 | -------------------------------------------------------------------------------- /linux-object/src/fs/stdio.rs: -------------------------------------------------------------------------------- 1 | //! Implement INode for Stdin & Stdout 2 | #![allow(unsafe_code)] 3 | 4 | use super::ioctl::*; 5 | use core::any::Any; 6 | use rcore_fs::vfs::*; 7 | //use spin::Mutex; 8 | 9 | //#[derive(Default)] 10 | //pub struct Stdin { 11 | // buf: Mutex>, 12 | // pub pushed: Condvar, 13 | //} 14 | // 15 | //impl Stdin { 16 | // pub fn push(&self, c: char) { 17 | // self.buf.lock().push_back(c); 18 | // self.pushed.notify_one(); 19 | // } 20 | // pub fn pop(&self) -> char { 21 | // loop { 22 | // let mut buf_lock = self.buf.lock(); 23 | // match buf_lock.pop_front() { 24 | // Some(c) => return c, 25 | // None => { 26 | // self.pushed.wait(buf_lock); 27 | // } 28 | // } 29 | // } 30 | // } 31 | // pub fn can_read(&self) -> bool { 32 | // return self.buf.lock().len() > 0; 33 | // } 34 | //} 35 | 36 | #[derive(Default)] 37 | pub struct Stdout; 38 | 39 | //impl INode for Stdin { 40 | // fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { 41 | // if self.can_read() { 42 | // buf[0] = self.pop() as u8; 43 | // Ok(1) 44 | // } else { 45 | // Err(FsError::Again) 46 | // } 47 | // } 48 | // fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { 49 | // unimplemented!() 50 | // } 51 | // fn poll(&self) -> Result { 52 | // Ok(PollStatus { 53 | // read: self.can_read(), 54 | // write: false, 55 | // error: false, 56 | // }) 57 | // } 58 | // fn io_control(&self, cmd: u32, data: usize) -> Result<()> { 59 | // match cmd as usize { 60 | // TCGETS | TIOCGWINSZ | TIOCSPGRP => { 61 | // // pretend to be tty 62 | // Ok(()) 63 | // } 64 | // TIOCGPGRP => { 65 | // // pretend to be have a tty process group 66 | // // TODO: verify pointer 67 | // unsafe { *(data as *mut u32) = 0 }; 68 | // Ok(()) 69 | // } 70 | // _ => Err(FsError::NotSupported), 71 | // } 72 | // } 73 | // fn as_any_ref(&self) -> &dyn Any { 74 | // self 75 | // } 76 | //} 77 | 78 | impl INode for Stdout { 79 | fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { 80 | unimplemented!() 81 | } 82 | fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { 83 | // we do not care the utf-8 things, we just want to print it! 84 | let s = unsafe { core::str::from_utf8_unchecked(buf) }; 85 | kernel_hal::serial_write(s); 86 | Ok(buf.len()) 87 | } 88 | fn poll(&self) -> Result { 89 | Ok(PollStatus { 90 | read: false, 91 | write: true, 92 | error: false, 93 | }) 94 | } 95 | fn io_control(&self, cmd: u32, data: usize) -> Result<()> { 96 | match cmd as usize { 97 | TCGETS | TIOCGWINSZ | TIOCSPGRP => { 98 | // pretend to be tty 99 | Ok(()) 100 | } 101 | TIOCGPGRP => { 102 | // pretend to be have a tty process group 103 | // TODO: verify pointer 104 | unsafe { *(data as *mut u32) = 0 }; 105 | Ok(()) 106 | } 107 | _ => Err(FsError::NotSupported), 108 | } 109 | } 110 | fn as_any_ref(&self) -> &dyn Any { 111 | self 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /zircon-syscall/src/socket.rs: -------------------------------------------------------------------------------- 1 | use {super::*, zircon_object::ipc::Socket, zircon_object::ipc::SocketFlags}; 2 | 3 | impl Syscall<'_> { 4 | pub fn sys_socket_create( 5 | &self, 6 | options: u32, 7 | mut out0: UserOutPtr, 8 | mut out1: UserOutPtr, 9 | ) -> ZxResult { 10 | info!("socket.create: options={:#x?}", options); 11 | let (end0, end1) = Socket::create(options)?; 12 | let proc = self.thread.proc(); 13 | let handle0 = proc.add_handle(Handle::new(end0, Rights::DEFAULT_SOCKET)); 14 | let handle1 = proc.add_handle(Handle::new(end1, Rights::DEFAULT_SOCKET)); 15 | out0.write(handle0)?; 16 | out1.write(handle1)?; 17 | Ok(()) 18 | } 19 | 20 | pub fn sys_socket_write( 21 | &self, 22 | handle_value: HandleValue, 23 | options: u32, 24 | user_bytes: UserInPtr, 25 | count: usize, 26 | mut actual_count_ptr: UserOutPtr, 27 | ) -> ZxResult { 28 | info!( 29 | "socket.write: socket={:#x?}, options={:#x?}, buffer={:#x?}, size={:#x?}", 30 | handle_value, options, user_bytes, count, 31 | ); 32 | if count > 0 && user_bytes.is_null() { 33 | return Err(ZxError::INVALID_ARGS); 34 | } 35 | let options = SocketFlags::from_bits(options).ok_or(ZxError::INVALID_ARGS)?; 36 | if !(options - SocketFlags::SOCKET_CONTROL).is_empty() { 37 | return Err(ZxError::INVALID_ARGS); 38 | } 39 | let proc = self.thread.proc(); 40 | let socket = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; 41 | let data = user_bytes.read_array(count)?; 42 | let actual_count = socket.write(options, &data)?; 43 | actual_count_ptr.write_if_not_null(actual_count)?; 44 | Ok(()) 45 | } 46 | 47 | pub fn sys_socket_read( 48 | &self, 49 | handle_value: HandleValue, 50 | options: u32, 51 | mut user_bytes: UserOutPtr, 52 | count: usize, 53 | mut actual_count_ptr: UserOutPtr, 54 | ) -> ZxResult { 55 | info!( 56 | "socket.read: socket={:#x?}, options={:#x?}, buffer={:#x?}, size={:#x?}", 57 | handle_value, options, user_bytes, count, 58 | ); 59 | if count > 0 && user_bytes.is_null() { 60 | return Err(ZxError::INVALID_ARGS); 61 | } 62 | let options = SocketFlags::from_bits(options).ok_or(ZxError::INVALID_ARGS)?; 63 | if !(options - SocketFlags::SOCKET_CONTROL - SocketFlags::SOCKET_PEEK).is_empty() { 64 | return Err(ZxError::INVALID_ARGS); 65 | } 66 | let proc = self.thread.proc(); 67 | let socket = proc.get_object_with_rights::(handle_value, Rights::READ)?; 68 | let mut data = vec![0; count]; 69 | let actual_count = socket.read(options, &mut data)?; 70 | user_bytes.write_array(&data)?; 71 | actual_count_ptr.write_if_not_null(actual_count)?; 72 | Ok(()) 73 | } 74 | 75 | pub fn sys_socket_shutdown(&self, socket: HandleValue, options: u32) -> ZxResult { 76 | let options = SocketFlags::from_bits_truncate(options); 77 | info!( 78 | "socket.shutdown: socket={:#x?}, options={:#x?}", 79 | socket, options 80 | ); 81 | let proc = self.thread.proc(); 82 | let socket = proc.get_object_with_rights::(socket, Rights::WRITE)?; 83 | let read = options.contains(SocketFlags::SHUTDOWN_READ); 84 | let write = options.contains(SocketFlags::SHUTDOWN_WRITE); 85 | socket.shutdown(read, write)?; 86 | Ok(()) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /zircon-loader/src/kcounter.rs: -------------------------------------------------------------------------------- 1 | use { 2 | alloc::sync::Arc, 3 | core::mem::size_of, 4 | zircon_object::{object::KernelObject, util::kcounter::*, vm::*}, 5 | }; 6 | 7 | /// Create kcounter VMOs from kernel memory. 8 | /// Return (KCOUNTER_NAMES_VMO, KCOUNTER_VMO). 9 | #[cfg(target_os = "none")] 10 | pub fn create_kcounter_vmo() -> (Arc, Arc) { 11 | const HEADER_SIZE: usize = size_of::(); 12 | const DESC_SIZE: usize = size_of::(); 13 | let descriptors = KCounterDescriptorArray::get(); 14 | let counter_table_size = descriptors.0.len() * DESC_SIZE; 15 | let counter_name_vmo = VmObject::new_paged(pages(counter_table_size + HEADER_SIZE)); 16 | let header = KCounterVmoHeader { 17 | magic: KCOUNTER_MAGIC, 18 | max_cpu: 1, 19 | counter_table_size, 20 | }; 21 | let serde_header: [u8; HEADER_SIZE] = unsafe { core::mem::transmute(header) }; 22 | counter_name_vmo.write(0, &serde_header).unwrap(); 23 | for (i, descriptor) in descriptors.0.iter().enumerate() { 24 | let serde_counter: [u8; DESC_SIZE] = 25 | unsafe { core::mem::transmute(KCounterDescItem::from(descriptor)) }; 26 | counter_name_vmo 27 | .write(HEADER_SIZE + i * DESC_SIZE, &serde_counter) 28 | .unwrap(); 29 | } 30 | counter_name_vmo.set_name("counters/desc"); 31 | 32 | let kcounters_vmo = { 33 | extern "C" { 34 | fn kcounters_arena_start(); 35 | fn kcounters_arena_end(); 36 | } 37 | let mut pgtable = kernel_hal::PageTable::current(); 38 | let paddr = pgtable.query(kcounters_arena_start as usize).unwrap(); 39 | assert_eq!( 40 | kcounters_arena_start as usize / PAGE_SIZE, 41 | kcounters_arena_end as usize / PAGE_SIZE, 42 | "all kcounters must in the same page" 43 | ); 44 | VmObject::new_physical(paddr, 1) 45 | }; 46 | kcounters_vmo.set_name("counters/arena"); 47 | (counter_name_vmo, kcounters_vmo) 48 | } 49 | 50 | /// Create kcounter VMOs. 51 | /// NOTE: kcounter is not supported in libos. 52 | #[cfg(not(target_os = "none"))] 53 | pub fn create_kcounter_vmo() -> (Arc, Arc) { 54 | const HEADER_SIZE: usize = size_of::(); 55 | let counter_name_vmo = VmObject::new_paged(1); 56 | let header = KCounterVmoHeader { 57 | magic: KCOUNTER_MAGIC, 58 | max_cpu: 1, 59 | counter_table_size: 0, 60 | }; 61 | let serde_header: [u8; HEADER_SIZE] = unsafe { core::mem::transmute(header) }; 62 | counter_name_vmo.write(0, &serde_header).unwrap(); 63 | counter_name_vmo.set_name("counters/desc"); 64 | 65 | let kcounters_vmo = VmObject::new_paged(1); 66 | kcounters_vmo.set_name("counters/arena"); 67 | (counter_name_vmo, kcounters_vmo) 68 | } 69 | 70 | #[repr(C)] 71 | struct KCounterDescItem { 72 | name: [u8; 56], 73 | type_: KCounterType, 74 | } 75 | 76 | #[repr(u64)] 77 | enum KCounterType { 78 | Sum = 1, 79 | } 80 | 81 | impl From<&KCounterDescriptor> for KCounterDescItem { 82 | fn from(desc: &KCounterDescriptor) -> Self { 83 | let mut name = [0u8; 56]; 84 | let length = desc.name.len().min(56); 85 | name[..length].copy_from_slice(&desc.name.as_bytes()[..length]); 86 | KCounterDescItem { 87 | name, 88 | type_: KCounterType::Sum, 89 | } 90 | } 91 | } 92 | 93 | #[repr(C)] 94 | struct KCounterVmoHeader { 95 | magic: u64, 96 | max_cpu: u64, 97 | counter_table_size: usize, 98 | } 99 | 100 | const KCOUNTER_MAGIC: u64 = 1_547_273_975; 101 | -------------------------------------------------------------------------------- /zircon-syscall/src/futex.rs: -------------------------------------------------------------------------------- 1 | use {super::*, zircon_object::task::ThreadState}; 2 | 3 | impl Syscall<'_> { 4 | pub async fn sys_futex_wait( 5 | &self, 6 | value_ptr: UserInPtr, 7 | current_value: i32, 8 | new_futex_owner: HandleValue, 9 | deadline: Deadline, 10 | ) -> ZxResult { 11 | info!( 12 | "futex.wait: value_ptr={:#x?}, current_value={:#x}, new_futex_owner={:#x}, deadline={:?}", 13 | value_ptr, current_value, new_futex_owner, deadline 14 | ); 15 | if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 { 16 | return Err(ZxError::INVALID_ARGS); 17 | } 18 | let value = value_ptr.as_ref()?; 19 | let proc = self.thread.proc(); 20 | let futex = proc.get_futex(value); 21 | let new_owner = if new_futex_owner == INVALID_HANDLE { 22 | None 23 | } else { 24 | Some(proc.get_object::(new_futex_owner)?) 25 | }; 26 | let future = futex.wait_with_owner(current_value, Some(self.thread.clone()), new_owner); 27 | self.thread 28 | .blocking_run(future, ThreadState::BlockedFutex, deadline.into()) 29 | .await?; 30 | Ok(()) 31 | } 32 | 33 | pub fn sys_futex_requeue( 34 | &self, 35 | value_ptr: UserInPtr, 36 | wake_count: u32, 37 | current_value: i32, 38 | requeue_ptr: UserInPtr, 39 | requeue_count: u32, 40 | new_requeue_owner: HandleValue, 41 | ) -> ZxResult { 42 | info!( 43 | "futex.requeue: value_ptr={:?}, wake_count={:#x}, current_value={:#x}, requeue_ptr={:?}, requeue_count={:#x}, new_requeue_owner={:?}", 44 | value_ptr, wake_count, current_value, requeue_ptr, requeue_count, new_requeue_owner 45 | ); 46 | if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 { 47 | return Err(ZxError::INVALID_ARGS); 48 | } 49 | let value = value_ptr.as_ref()?; 50 | let requeue = requeue_ptr.as_ref()?; 51 | if value_ptr.as_ptr() == requeue_ptr.as_ptr() { 52 | return Err(ZxError::INVALID_ARGS); 53 | } 54 | let proc = self.thread.proc(); 55 | let new_requeue_owner = if new_requeue_owner == INVALID_HANDLE { 56 | None 57 | } else { 58 | Some(proc.get_object::(new_requeue_owner)?) 59 | }; 60 | let wake_futex = proc.get_futex(value); 61 | let requeue_futex = proc.get_futex(requeue); 62 | wake_futex.requeue( 63 | current_value, 64 | wake_count as usize, 65 | requeue_count as usize, 66 | &requeue_futex, 67 | new_requeue_owner, 68 | )?; 69 | Ok(()) 70 | } 71 | 72 | pub fn sys_futex_wake(&self, value_ptr: UserInPtr, count: u32) -> ZxResult { 73 | info!("futex.wake: value_ptr={:?}, count={:#x}", value_ptr, count); 74 | if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 { 75 | return Err(ZxError::INVALID_ARGS); 76 | } 77 | let value = value_ptr.as_ref()?; 78 | let proc = self.thread.proc(); 79 | let futex = proc.get_futex(value); 80 | futex.wake(count as usize); 81 | Ok(()) 82 | } 83 | 84 | pub fn sys_futex_wake_single_owner(&self, value_ptr: UserInPtr) -> ZxResult { 85 | info!("futex.wake_single_owner: value_ptr={:?}", value_ptr); 86 | if value_ptr.is_null() || value_ptr.as_ptr() as usize % 4 != 0 { 87 | return Err(ZxError::INVALID_ARGS); 88 | } 89 | let value = value_ptr.as_ref()?; 90 | let proc = self.thread.proc(); 91 | proc.get_futex(value).wake_single_owner(); 92 | Ok(()) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /zircon-object/src/signal/timer.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::object::*; 3 | use alloc::boxed::Box; 4 | use alloc::sync::Arc; 5 | use core::time::Duration; 6 | use spin::Mutex; 7 | 8 | /// An object that may be signaled at some point in the future 9 | /// 10 | /// ## SYNOPSIS 11 | /// 12 | /// A timer is used to wait until a specified point in time has occurred 13 | /// or the timer has been canceled. 14 | pub struct Timer { 15 | base: KObjectBase, 16 | _counter: CountHelper, 17 | #[allow(dead_code)] 18 | slack: Slack, 19 | inner: Mutex, 20 | } 21 | 22 | impl_kobject!(Timer); 23 | define_count_helper!(Timer); 24 | 25 | #[derive(Default)] 26 | struct TimerInner { 27 | deadline: Option, 28 | } 29 | 30 | #[derive(Debug)] 31 | pub enum Slack { 32 | Center, 33 | Early, 34 | Late, 35 | } 36 | 37 | impl Timer { 38 | /// Create a new `Timer`. 39 | pub fn new() -> Arc { 40 | Self::with_slack(Slack::Center) 41 | } 42 | 43 | /// Create a new `Timer` with slack. 44 | pub fn with_slack(slack: Slack) -> Arc { 45 | Arc::new(Timer { 46 | base: KObjectBase::default(), 47 | _counter: CountHelper::new(), 48 | slack, 49 | inner: Mutex::default(), 50 | }) 51 | } 52 | 53 | /// Create a one-shot timer. 54 | pub fn one_shot(deadline: Duration) -> Arc { 55 | let timer = Timer::new(); 56 | timer.set(deadline, Duration::default()); 57 | timer 58 | } 59 | 60 | /// Starts a one-shot timer that will fire when `deadline` passes. 61 | /// 62 | /// If a previous call to `set` was pending, the previous timer is canceled 63 | /// and `Signal::SIGNALED` is de-asserted as needed. 64 | pub fn set(self: &Arc, deadline: Duration, _slack: Duration) { 65 | let mut inner = self.inner.lock(); 66 | inner.deadline = Some(deadline); 67 | self.base.signal_clear(Signal::SIGNALED); 68 | let me = Arc::downgrade(self); 69 | kernel_hal::timer_set( 70 | deadline, 71 | Box::new(move |now| me.upgrade().map(|timer| timer.touch(now)).unwrap_or(())), 72 | ); 73 | } 74 | 75 | /// Cancel the pending timer started by `set`. 76 | pub fn cancel(&self) { 77 | let mut inner = self.inner.lock(); 78 | inner.deadline = None; 79 | } 80 | 81 | /// Called by HAL timer. 82 | fn touch(&self, now: Duration) { 83 | let mut inner = self.inner.lock(); 84 | if let Some(deadline) = inner.deadline { 85 | if now >= deadline { 86 | self.base.signal_set(Signal::SIGNALED); 87 | inner.deadline = None; 88 | } 89 | } 90 | } 91 | } 92 | 93 | #[cfg(test)] 94 | mod tests { 95 | use super::*; 96 | use kernel_hal::timer_now; 97 | 98 | #[test] 99 | fn set() { 100 | let timer = Timer::new(); 101 | timer.set(timer_now() + Duration::from_millis(10), Duration::default()); 102 | timer.set(timer_now() + Duration::from_millis(20), Duration::default()); 103 | 104 | std::thread::sleep(Duration::from_millis(10)); 105 | assert_eq!(timer.signal(), Signal::empty()); 106 | 107 | std::thread::sleep(Duration::from_millis(15)); 108 | assert_eq!(timer.signal(), Signal::SIGNALED); 109 | 110 | timer.set(timer_now() + Duration::from_millis(10), Duration::default()); 111 | assert_eq!(timer.signal(), Signal::empty()); 112 | } 113 | 114 | #[test] 115 | fn cancel() { 116 | let timer = Timer::new(); 117 | timer.set(timer_now() + Duration::from_millis(10), Duration::default()); 118 | 119 | std::thread::sleep(Duration::from_millis(5)); 120 | timer.cancel(); 121 | 122 | std::thread::sleep(Duration::from_millis(50)); 123 | assert_eq!(timer.signal(), Signal::empty()); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /linux-syscall/src/vm.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use bitflags::bitflags; 3 | use zircon_object::vm::*; 4 | 5 | impl Syscall<'_> { 6 | pub fn sys_mmap( 7 | &self, 8 | addr: usize, 9 | len: usize, 10 | prot: usize, 11 | flags: usize, 12 | fd: FileDesc, 13 | offset: u64, 14 | ) -> SysResult { 15 | let prot = MmapProt::from_bits_truncate(prot); 16 | let flags = MmapFlags::from_bits_truncate(flags); 17 | info!( 18 | "mmap: addr={:#x}, size={:#x}, prot={:?}, flags={:?}, fd={:?}, offset={:#x}", 19 | addr, len, prot, flags, fd, offset 20 | ); 21 | 22 | let proc = self.zircon_process(); 23 | let vmar = proc.vmar(); 24 | 25 | if flags.contains(MmapFlags::FIXED) { 26 | // unmap first 27 | vmar.unmap(addr, len)?; 28 | } 29 | let vmar_offset = flags.contains(MmapFlags::FIXED).then(|| addr - vmar.addr()); 30 | if flags.contains(MmapFlags::ANONYMOUS) { 31 | if flags.contains(MmapFlags::SHARED) { 32 | return Err(LxError::EINVAL); 33 | } 34 | let vmo = VmObject::new_paged(pages(len)); 35 | let addr = vmar.map(vmar_offset, vmo.clone(), 0, vmo.len(), prot.to_flags())?; 36 | Ok(addr) 37 | } else { 38 | let file = self.linux_process().get_file(fd)?; 39 | let mut buf = vec![0; len]; 40 | let len = file.read_at(offset, &mut buf)?; 41 | let vmo = VmObject::new_paged(pages(len)); 42 | vmo.write(0, &buf[..len])?; 43 | let addr = vmar.map(vmar_offset, vmo.clone(), 0, vmo.len(), prot.to_flags())?; 44 | Ok(addr) 45 | } 46 | } 47 | 48 | pub fn sys_mprotect(&self, addr: usize, len: usize, prot: usize) -> SysResult { 49 | let prot = MmapProt::from_bits_truncate(prot); 50 | info!( 51 | "mprotect: addr={:#x}, size={:#x}, prot={:?}", 52 | addr, len, prot 53 | ); 54 | warn!("mprotect: unimplemented"); 55 | Ok(0) 56 | } 57 | 58 | pub fn sys_munmap(&self, addr: usize, len: usize) -> SysResult { 59 | info!("munmap: addr={:#x}, size={:#x}", addr, len); 60 | let proc = self.thread.proc(); 61 | let vmar = proc.vmar(); 62 | vmar.unmap(addr, len)?; 63 | Ok(0) 64 | } 65 | } 66 | 67 | bitflags! { 68 | pub struct MmapFlags: usize { 69 | #[allow(clippy::identity_op)] 70 | /// Changes are shared. 71 | const SHARED = 1 << 0; 72 | /// Changes are private. 73 | const PRIVATE = 1 << 1; 74 | /// Place the mapping at the exact address 75 | const FIXED = 1 << 4; 76 | /// The mapping is not backed by any file. (non-POSIX) 77 | const ANONYMOUS = MMAP_ANONYMOUS; 78 | } 79 | } 80 | 81 | #[cfg(target_arch = "mips")] 82 | const MMAP_ANONYMOUS: usize = 0x800; 83 | #[cfg(not(target_arch = "mips"))] 84 | const MMAP_ANONYMOUS: usize = 1 << 5; 85 | 86 | bitflags! { 87 | pub struct MmapProt: usize { 88 | #[allow(clippy::identity_op)] 89 | /// Data can be read 90 | const READ = 1 << 0; 91 | /// Data can be written 92 | const WRITE = 1 << 1; 93 | /// Data can be executed 94 | const EXEC = 1 << 2; 95 | } 96 | } 97 | 98 | impl MmapProt { 99 | fn to_flags(self) -> MMUFlags { 100 | let mut flags = MMUFlags::USER; 101 | if self.contains(MmapProt::READ) { 102 | flags |= MMUFlags::READ; 103 | } 104 | if self.contains(MmapProt::WRITE) { 105 | flags |= MMUFlags::WRITE; 106 | } 107 | if self.contains(MmapProt::EXEC) { 108 | flags |= MMUFlags::EXECUTE; 109 | } 110 | // FIXME: hack for unimplemented mprotect 111 | if self.is_empty() { 112 | flags = MMUFlags::READ | MMUFlags::WRITE; 113 | } 114 | flags 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /linux-loader/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(asm)] 3 | #![feature(global_asm)] 4 | #![deny(warnings, unused_must_use)] 5 | 6 | extern crate alloc; 7 | #[macro_use] 8 | extern crate log; 9 | 10 | use { 11 | alloc::{boxed::Box, string::String, sync::Arc, vec::Vec}, 12 | kernel_hal::{GeneralRegs, MMUFlags}, 13 | linux_object::{ 14 | fs::{vfs::FileSystem, INodeExt}, 15 | loader::LinuxElfLoader, 16 | process::ProcessExt, 17 | thread::ThreadExt, 18 | }, 19 | linux_syscall::Syscall, 20 | zircon_object::task::*, 21 | }; 22 | 23 | pub fn run(args: Vec, envs: Vec, rootfs: Arc) -> Arc { 24 | let job = Job::root(); 25 | let proc = Process::create_linux(&job, rootfs.clone()).unwrap(); 26 | let thread = Thread::create_linux(&proc).unwrap(); 27 | let loader = LinuxElfLoader { 28 | #[cfg(feature = "std")] 29 | syscall_entry: kernel_hal_unix::syscall_entry as usize, 30 | #[cfg(not(feature = "std"))] 31 | syscall_entry: 0, 32 | stack_pages: 8, 33 | root_inode: rootfs.root_inode(), 34 | }; 35 | let inode = rootfs.root_inode().lookup(&args[0]).unwrap(); 36 | let data = inode.read_as_vec().unwrap(); 37 | let (entry, sp) = loader.load(&proc.vmar(), &data, args, envs).unwrap(); 38 | 39 | thread 40 | .start(entry, sp, 0, 0, spawn) 41 | .expect("failed to start main thread"); 42 | proc 43 | } 44 | 45 | fn spawn(thread: Arc) { 46 | let vmtoken = thread.proc().vmar().table_phys(); 47 | let future = async move { 48 | loop { 49 | let mut cx = thread.wait_for_run().await; 50 | trace!("go to user: {:#x?}", cx); 51 | kernel_hal::context_run(&mut cx); 52 | trace!("back from user: {:#x?}", cx); 53 | let mut exit = false; 54 | match cx.trap_num { 55 | 0x100 => exit = handle_syscall(&thread, &mut cx.general).await, 56 | 0x20..=0x3f => { 57 | kernel_hal::InterruptManager::handle(cx.trap_num as u8); 58 | if cx.trap_num == 0x20 { 59 | kernel_hal::yield_now().await; 60 | } 61 | } 62 | 0xe => { 63 | let vaddr = kernel_hal::fetch_fault_vaddr(); 64 | let flags = if cx.error_code & 0x2 == 0 { 65 | MMUFlags::READ 66 | } else { 67 | MMUFlags::WRITE 68 | }; 69 | error!("page fualt from user mode {:#x} {:#x?}", vaddr, flags); 70 | let vmar = thread.proc().vmar(); 71 | match vmar.handle_page_fault(vaddr, flags) { 72 | Ok(()) => {} 73 | Err(_) => { 74 | panic!("Page Fault from user mode {:#x?}", cx); 75 | } 76 | } 77 | } 78 | _ => panic!("not supported interrupt from user mode. {:#x?}", cx), 79 | } 80 | thread.end_running(cx); 81 | if exit { 82 | break; 83 | } 84 | } 85 | }; 86 | kernel_hal::Thread::spawn(Box::pin(future), vmtoken); 87 | } 88 | 89 | async fn handle_syscall(thread: &Arc, regs: &mut GeneralRegs) -> bool { 90 | trace!("syscall: {:#x?}", regs); 91 | let num = regs.rax as u32; 92 | let args = [regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9]; 93 | let mut syscall = Syscall { 94 | thread, 95 | #[cfg(feature = "std")] 96 | syscall_entry: kernel_hal_unix::syscall_entry as usize, 97 | #[cfg(not(feature = "std"))] 98 | syscall_entry: 0, 99 | spawn_fn: spawn, 100 | regs, 101 | exit: false, 102 | }; 103 | let ret = syscall.syscall(num, args).await; 104 | let exit = syscall.exit; 105 | regs.rax = ret as usize; 106 | exit 107 | } 108 | -------------------------------------------------------------------------------- /zCore/Makefile: -------------------------------------------------------------------------------- 1 | arch ?= x86_64 2 | mode ?= debug 3 | zbi_file ?= bringup 4 | graphic ?= 5 | accel ?= 6 | linux ?= 7 | smp ?= 1 8 | test_filter ?= *.* 9 | 10 | build_args := -Z build-std=core,alloc --target $(arch).json 11 | build_path := target/$(arch)/$(mode) 12 | kernel := $(build_path)/zcore 13 | kernel_img := $(build_path)/zcore.img 14 | ESP := $(build_path)/esp 15 | OVMF := ../rboot/OVMF.fd 16 | qemu := qemu-system-x86_64 17 | OBJDUMP := rust-objdump 18 | VMDISK := $(build_path)/boot.vdi 19 | QEMU_DISK := $(build_path)/disk.qcow2 20 | 21 | ifeq ($(mode), release) 22 | build_args += --release 23 | endif 24 | 25 | ifeq ($(linux), 1) 26 | build_args += --features linux 27 | else 28 | build_args += --features zircon 29 | endif 30 | 31 | qemu_opts := \ 32 | -smp $(smp) 33 | 34 | ifeq ($(arch), x86_64) 35 | qemu_opts += \ 36 | -machine q35 \ 37 | -cpu Haswell,+smap,-check,-fsgsbase \ 38 | -drive if=pflash,format=raw,readonly,file=$(OVMF) \ 39 | -drive format=raw,file=fat:rw:$(ESP) \ 40 | -drive format=qcow2,file=$(QEMU_DISK),id=disk,if=none \ 41 | -device ich9-ahci,id=ahci \ 42 | -device ide-drive,drive=disk,bus=ahci.0 \ 43 | -serial mon:stdio \ 44 | -m 4G \ 45 | -nic none \ 46 | -device isa-debug-exit,iobase=0xf4,iosize=0x04 47 | endif 48 | 49 | ifeq ($(accel), 1) 50 | ifeq ($(shell uname), Darwin) 51 | qemu_opts += -accel hvf 52 | else 53 | qemu_opts += -accel kvm -cpu host,migratable=no,+invtsc 54 | endif 55 | endif 56 | 57 | ifeq ($(graphic), on) 58 | build_args += --features graphic 59 | else 60 | ifeq ($(MAKECMDGOALS), vbox) 61 | build_args += --features graphic 62 | else 63 | qemu_opts += -display none -nographic 64 | endif 65 | endif 66 | 67 | run: build justrun 68 | test: build-test justrun 69 | debug: build debugrun 70 | 71 | debugrun: $(QEMU_DISK) 72 | $(qemu) $(qemu_opts) -s -S 73 | 74 | justrun: $(QEMU_DISK) 75 | $(qemu) $(qemu_opts) 76 | 77 | build-test: build 78 | cp ../prebuilt/zircon/x64/core-tests.zbi $(ESP)/EFI/zCore/fuchsia.zbi 79 | echo 'cmdline=LOG=warn:userboot=test/core-standalone-test:userboot.shutdown:core-tests=$(test_filter)' >> $(ESP)/EFI/Boot/rboot.conf 80 | 81 | build: $(kernel_img) 82 | 83 | $(kernel_img): kernel bootloader 84 | mkdir -p $(ESP)/EFI/zCore $(ESP)/EFI/Boot 85 | cp ../rboot/target/x86_64-unknown-uefi/release/rboot.efi $(ESP)/EFI/Boot/BootX64.efi 86 | cp rboot.conf $(ESP)/EFI/Boot/rboot.conf 87 | ifeq ($(linux), 1) 88 | cp x86_64.img $(ESP)/EFI/zCore/fuchsia.zbi 89 | else 90 | cp ../prebuilt/zircon/x64/$(zbi_file).zbi $(ESP)/EFI/zCore/fuchsia.zbi 91 | endif 92 | cp $(kernel) $(ESP)/EFI/zCore/zcore.elf 93 | 94 | kernel: 95 | echo Building zCore kenel 96 | cargo build $(build_args) 97 | 98 | bootloader: 99 | cd ../rboot && make build 100 | 101 | clean: 102 | cargo clean 103 | 104 | image: 105 | # for macOS only 106 | hdiutil create -fs fat32 -ov -volname EFI -format UDTO -srcfolder $(ESP) $(build_path)/zcore.cdr 107 | qemu-img convert -f raw $(build_path)/zcore.cdr -O qcow2 $(build_path)/zcore.qcow2 108 | 109 | header: 110 | $(OBJDUMP) -x $(kernel) | less 111 | 112 | asm: 113 | $(OBJDUMP) -d $(kernel) | less 114 | 115 | vbox: build 116 | ifneq "$(VMDISK)" "$(wildcard $(VMDISK))" 117 | vboxmanage createvm --name zCoreVM --basefolder $(build_path) --register 118 | cp ../prebuilt/zircon/empty.vdi $(VMDISK) 119 | vboxmanage storagectl zCoreVM --name DiskCtrlr --controller IntelAhci --add sata 120 | vboxmanage storageattach zCoreVM --storagectl DiskCtrlr --port 0 --type hdd --medium $(VMDISK) 121 | vboxmanage modifyvm zCoreVM --memory 1024 --firmware efi 122 | tar -cvf $(build_path)/esp.tar -C $(build_path)/esp EFI 123 | sudo LIBGUESTFS_DEBUG=1 guestfish -a $(VMDISK) -m /dev/sda1 tar-in $(build_path)/esp.tar / : quit 124 | endif 125 | # depencency: libguestfs-tools 126 | tar -cvf $(build_path)/esp.tar -C $(build_path)/esp EFI 127 | sudo guestfish -a $(VMDISK) -m /dev/sda1 tar-in $(build_path)/esp.tar / : quit 128 | # sudo LIBGUESTFS_DEBUG=1 guestfish -a $(VMDISK) -m /dev/sda1 tar-in $(build_path)/esp.tar / : quit 129 | # -a $(VMDISK) $(build_path)/esp.tar / 130 | rm $(build_path)/esp.tar 131 | vboxmanage startvm zCoreVM 132 | 133 | $(QEMU_DISK): 134 | qemu-img create -f qcow2 $@ 100M 135 | -------------------------------------------------------------------------------- /zircon-syscall/src/time.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | core::{ 4 | fmt::{Debug, Formatter, Result}, 5 | sync::atomic::{AtomicU64, Ordering}, 6 | time::Duration, 7 | }, 8 | kernel_hal::{sleep_until, timer_now, yield_now}, 9 | zircon_object::{dev::*, task::*}, 10 | }; 11 | 12 | static UTC_OFFSET: AtomicU64 = AtomicU64::new(0); 13 | 14 | const ZX_CLOCK_MONOTONIC: u32 = 0; 15 | const ZX_CLOCK_UTC: u32 = 1; 16 | const ZX_CLOCK_THREAD: u32 = 2; 17 | 18 | impl Syscall<'_> { 19 | pub fn sys_clock_create( 20 | &self, 21 | _options: u64, 22 | _user_args: UserInPtr, 23 | mut _out: UserOutPtr, 24 | ) -> ZxResult { 25 | warn!("clock.create: skip"); 26 | Ok(()) 27 | } 28 | 29 | pub fn sys_clock_get(&self, clock_id: u32, mut time: UserOutPtr) -> ZxResult { 30 | info!("clock.get: id={}", clock_id); 31 | match clock_id { 32 | ZX_CLOCK_MONOTONIC => { 33 | time.write(timer_now().as_nanos() as u64)?; 34 | Ok(()) 35 | } 36 | ZX_CLOCK_UTC => { 37 | time.write(timer_now().as_nanos() as u64 + UTC_OFFSET.load(Ordering::Relaxed))?; 38 | Ok(()) 39 | } 40 | ZX_CLOCK_THREAD => { 41 | time.write(self.thread.get_time())?; 42 | Ok(()) 43 | } 44 | _ => Err(ZxError::NOT_SUPPORTED), 45 | } 46 | } 47 | 48 | pub fn sys_clock_read(&self, handle: HandleValue, mut now: UserOutPtr) -> ZxResult { 49 | info!("clock.read: handle={:#x?}", handle); 50 | warn!("ignore clock handle"); 51 | now.write(timer_now().as_nanos() as u64)?; 52 | Ok(()) 53 | } 54 | 55 | pub fn sys_clock_adjust(&self, resource: HandleValue, clock_id: u32, offset: u64) -> ZxResult { 56 | info!( 57 | "clock.adjust: resource={:#x?}, id={:#x}, offset={:#x}", 58 | resource, clock_id, offset 59 | ); 60 | let proc = self.thread.proc(); 61 | proc.get_object::(resource)? 62 | .validate(ResourceKind::ROOT)?; 63 | match clock_id { 64 | ZX_CLOCK_MONOTONIC => Err(ZxError::ACCESS_DENIED), 65 | ZX_CLOCK_UTC => { 66 | UTC_OFFSET.store(offset, Ordering::Relaxed); 67 | Ok(()) 68 | } 69 | _ => Err(ZxError::INVALID_ARGS), 70 | } 71 | } 72 | 73 | pub fn sys_clock_update( 74 | &self, 75 | _handle: HandleValue, 76 | _options: u64, 77 | _user_args: UserInPtr, 78 | ) -> ZxResult { 79 | warn!("clock.update: skip"); 80 | Ok(()) 81 | } 82 | 83 | pub async fn sys_nanosleep(&self, deadline: Deadline) -> ZxResult { 84 | info!("nanosleep: deadline={:?}", deadline); 85 | if deadline.0 <= 0 { 86 | yield_now().await; 87 | } else { 88 | self.thread 89 | .blocking_run( 90 | sleep_until(deadline.into()), 91 | ThreadState::BlockedSleeping, 92 | Duration::from_nanos(u64::max_value()), 93 | ) 94 | .await?; 95 | } 96 | Ok(()) 97 | } 98 | } 99 | 100 | #[repr(transparent)] 101 | pub struct Deadline(i64); 102 | 103 | impl From for Deadline { 104 | fn from(x: usize) -> Self { 105 | Deadline(x as i64) 106 | } 107 | } 108 | 109 | impl Deadline { 110 | pub fn is_positive(&self) -> bool { 111 | self.0.is_positive() 112 | } 113 | 114 | pub fn forever() -> Self { 115 | Deadline(i64::max_value()) 116 | } 117 | } 118 | 119 | impl From for Duration { 120 | fn from(deadline: Deadline) -> Self { 121 | Duration::from_nanos(deadline.0.max(0) as u64) 122 | } 123 | } 124 | 125 | impl Debug for Deadline { 126 | fn fmt(&self, f: &mut Formatter<'_>) -> Result { 127 | if self.0 <= 0 { 128 | write!(f, "NoWait") 129 | } else if self.0 == i64::max_value() { 130 | write!(f, "Forever") 131 | } else { 132 | write!(f, "At({:?})", Duration::from_nanos(self.0 as u64)) 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /zircon-object/src/vm/vmo/slice.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use core::sync::atomic::{AtomicUsize, Ordering}; 3 | 4 | pub struct VMObjectSlice { 5 | /// Parent node. 6 | parent: Arc, 7 | /// The offset from parent. 8 | offset: usize, 9 | /// The size in bytes. 10 | size: usize, 11 | /// Mapping count. 12 | mapping_count: AtomicUsize, 13 | } 14 | 15 | impl VMObjectSlice { 16 | pub fn new(parent: Arc, offset: usize, size: usize) -> Arc { 17 | Arc::new(VMObjectSlice { 18 | parent, 19 | offset, 20 | size, 21 | mapping_count: AtomicUsize::new(0), 22 | }) 23 | } 24 | 25 | fn check_range(&self, offset: usize, len: usize) -> ZxResult { 26 | if offset + len >= self.size { 27 | return Err(ZxError::OUT_OF_RANGE); 28 | } 29 | Ok(()) 30 | } 31 | } 32 | 33 | impl VMObjectTrait for VMObjectSlice { 34 | fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { 35 | self.check_range(offset, buf.len())?; 36 | self.parent.read(offset + self.offset, buf) 37 | } 38 | 39 | fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { 40 | self.check_range(offset, buf.len())?; 41 | self.parent.write(offset + self.offset, buf) 42 | } 43 | 44 | fn len(&self) -> usize { 45 | self.size 46 | } 47 | 48 | fn set_len(&self, _len: usize) -> ZxResult { 49 | unimplemented!() 50 | } 51 | 52 | fn content_size(&self) -> usize { 53 | unimplemented!() 54 | } 55 | 56 | fn set_content_size(&self, _size: usize) -> ZxResult { 57 | unimplemented!() 58 | } 59 | 60 | fn commit_page(&self, page_idx: usize, flags: MMUFlags) -> ZxResult { 61 | self.parent 62 | .commit_page(page_idx + self.offset / PAGE_SIZE, flags) 63 | } 64 | 65 | fn commit_pages_with( 66 | &self, 67 | f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult) -> ZxResult, 68 | ) -> ZxResult { 69 | self.parent.commit_pages_with(f) 70 | } 71 | 72 | fn commit(&self, offset: usize, len: usize) -> ZxResult { 73 | self.parent.commit(offset + self.offset, len) 74 | } 75 | 76 | fn decommit(&self, offset: usize, len: usize) -> ZxResult { 77 | self.parent.decommit(offset + self.offset, len) 78 | } 79 | 80 | fn create_child( 81 | &self, 82 | _offset: usize, 83 | _len: usize, 84 | _user_id: u64, 85 | ) -> ZxResult> { 86 | Err(ZxError::NOT_SUPPORTED) 87 | } 88 | 89 | fn append_mapping(&self, _mapping: Weak) { 90 | self.mapping_count.fetch_add(1, Ordering::SeqCst); 91 | } 92 | 93 | fn remove_mapping(&self, _mapping: Weak) { 94 | self.mapping_count.fetch_sub(1, Ordering::SeqCst); 95 | } 96 | 97 | fn complete_info(&self, info: &mut VmoInfo) { 98 | self.parent.complete_info(info); 99 | } 100 | 101 | fn cache_policy(&self) -> CachePolicy { 102 | self.parent.cache_policy() 103 | } 104 | 105 | fn set_cache_policy(&self, _policy: CachePolicy) -> ZxResult { 106 | Ok(()) 107 | } 108 | 109 | fn share_count(&self) -> usize { 110 | self.mapping_count.load(Ordering::SeqCst) 111 | } 112 | 113 | fn committed_pages_in_range(&self, start_idx: usize, end_idx: usize) -> usize { 114 | let po = pages(self.offset); 115 | self.parent 116 | .committed_pages_in_range(start_idx + po, end_idx + po) 117 | } 118 | 119 | fn pin(&self, offset: usize, len: usize) -> ZxResult { 120 | self.check_range(offset, len)?; 121 | self.parent.pin(offset + self.offset, len) 122 | } 123 | 124 | fn unpin(&self, offset: usize, len: usize) -> ZxResult { 125 | self.check_range(offset, len)?; 126 | self.parent.unpin(offset + self.offset, len) 127 | } 128 | 129 | fn is_contiguous(&self) -> bool { 130 | self.parent.is_contiguous() 131 | } 132 | 133 | fn is_paged(&self) -> bool { 134 | self.parent.is_paged() 135 | } 136 | 137 | fn zero(&self, offset: usize, len: usize) -> ZxResult { 138 | self.check_range(offset, len)?; 139 | self.parent.zero(offset + self.offset, len) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | check: 7 | runs-on: ubuntu-20.04 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions-rs/toolchain@v1 11 | with: 12 | profile: minimal 13 | toolchain: nightly-2020-06-04 14 | override: true 15 | components: rustfmt, clippy 16 | - name: Check code format 17 | uses: actions-rs/cargo@v1 18 | with: 19 | command: fmt 20 | args: --all -- --check 21 | - name: Clippy 22 | uses: actions-rs/cargo@v1 23 | with: 24 | command: clippy 25 | 26 | build: 27 | runs-on: ${{ matrix.os }} 28 | strategy: 29 | matrix: 30 | os: [ubuntu-20.04, macos-latest] 31 | steps: 32 | - uses: actions/checkout@v2 33 | - name: Checkout submodules 34 | shell: bash 35 | run: | 36 | auth_header="$(git config --local --get http.https://github.com/.extraheader)" 37 | git submodule sync --recursive 38 | git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 39 | - uses: actions-rs/toolchain@v1 40 | with: 41 | profile: minimal 42 | toolchain: nightly-2020-06-04 43 | components: rust-src 44 | - name: Build 45 | uses: actions-rs/cargo@v1 46 | with: 47 | command: build 48 | args: --all-features 49 | - name: Build zCore 50 | run: | 51 | cd zCore 52 | make build 53 | - name: Build docs 54 | uses: actions-rs/cargo@v1 55 | with: 56 | command: doc 57 | 58 | build-aarch64: 59 | runs-on: ubuntu-20.04 60 | steps: 61 | - uses: actions/checkout@v2 62 | - uses: actions-rs/toolchain@v1 63 | with: 64 | profile: minimal 65 | toolchain: nightly-2020-06-04 66 | override: true 67 | target: aarch64-unknown-linux-gnu 68 | - uses: actions-rs/cargo@v1 69 | with: 70 | command: build 71 | use-cross: true 72 | args: -p zircon-loader --all-features --target aarch64-unknown-linux-gnu 73 | 74 | test: 75 | runs-on: ubuntu-20.04 76 | steps: 77 | - uses: actions/checkout@v2 78 | - name: Pull prebuilt images 79 | run: git lfs pull -X prebuilt/zircon/x64/bringup.zbi prebuilt/zircon/x64/core-tests.zbi prebuilt/zircon/arm64 80 | - name: Prepare rootfs 81 | run: make rootfs 82 | - name: Test 83 | uses: actions-rs/cargo@v1 84 | with: 85 | command: test 86 | args: --all-features --no-fail-fast --workspace --exclude zircon-loader 87 | env: 88 | CARGO_INCREMENTAL: '0' 89 | RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Coverflow-checks=off' 90 | - name: Cache grcov 91 | uses: actions/cache@v1 92 | with: 93 | path: ~/.cargo/bin/grcov 94 | key: ${{ runner.os }}-grcov 95 | - name: Gather coverage data 96 | id: coverage 97 | uses: actions-rs/grcov@v0.1 98 | - name: Coveralls upload 99 | uses: coverallsapp/github-action@master 100 | with: 101 | github-token: ${{ secrets.GITHUB_TOKEN }} 102 | path-to-lcov: ${{ steps.coverage.outputs.report }} 103 | 104 | bench: 105 | runs-on: ubuntu-20.04 106 | steps: 107 | - uses: actions/checkout@v2 108 | - name: Run benchmarks 109 | uses: actions-rs/cargo@v1 110 | with: 111 | command: bench 112 | 113 | core-test: 114 | runs-on: ubuntu-20.04 115 | steps: 116 | - uses: actions/checkout@v2 117 | - name: Pull prebuilt images 118 | run: git lfs pull -X prebuilt/zircon/x64/bringup.zbi prebuilt/zircon/arm64 119 | - name: Checkout submodules 120 | shell: bash 121 | run: | 122 | auth_header="$(git config --local --get http.https://github.com/.extraheader)" 123 | git submodule sync --recursive 124 | git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 125 | - uses: actions-rs/toolchain@v1 126 | with: 127 | profile: minimal 128 | toolchain: nightly-2020-06-04 129 | components: rust-src 130 | - name: Install QEMU 131 | run: sudo apt install qemu-system-x86 132 | - name: Build zCore 133 | run: | 134 | cd zCore 135 | make build mode=release 136 | cd .. 137 | - name: Run core-tests 138 | run: | 139 | cd scripts 140 | pip3 install pexpect 141 | python3 core-tests.py 142 | -------------------------------------------------------------------------------- /zircon-object/src/dev/pmt.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | crate::object::*, 4 | crate::vm::*, 5 | alloc::{ 6 | sync::{Arc, Weak}, 7 | vec, 8 | vec::Vec, 9 | }, 10 | }; 11 | 12 | /// Pinned Memory Token. 13 | /// 14 | /// It will pin memory on construction and unpin on drop. 15 | pub struct PinnedMemoryToken { 16 | base: KObjectBase, 17 | bti: Weak, 18 | vmo: Arc, 19 | offset: usize, 20 | size: usize, 21 | mapped_addrs: Vec, 22 | } 23 | 24 | impl_kobject!(PinnedMemoryToken); 25 | 26 | impl Drop for PinnedMemoryToken { 27 | fn drop(&mut self) { 28 | if self.vmo.is_paged() { 29 | self.vmo.unpin(self.offset, self.size).unwrap(); 30 | } 31 | } 32 | } 33 | 34 | impl PinnedMemoryToken { 35 | /// Create a `PinnedMemoryToken` by `BusTransactionInitiator`. 36 | pub(crate) fn create( 37 | bti: &Arc, 38 | vmo: Arc, 39 | perms: IommuPerms, 40 | offset: usize, 41 | size: usize, 42 | ) -> ZxResult> { 43 | if vmo.is_paged() { 44 | vmo.commit(offset, size)?; 45 | vmo.pin(offset, size)?; 46 | } 47 | let mapped_addrs = Self::map_into_iommu(&bti.iommu(), vmo.clone(), offset, size, perms)?; 48 | Ok(Arc::new(PinnedMemoryToken { 49 | base: KObjectBase::new(), 50 | bti: Arc::downgrade(bti), 51 | vmo, 52 | offset, 53 | size, 54 | mapped_addrs, 55 | })) 56 | } 57 | 58 | fn map_into_iommu( 59 | iommu: &Arc, 60 | vmo: Arc, 61 | offset: usize, 62 | size: usize, 63 | perms: IommuPerms, 64 | ) -> ZxResult> { 65 | if vmo.is_contiguous() { 66 | let (vaddr, _mapped_len) = iommu.map_contiguous(vmo, offset, size, perms)?; 67 | Ok(vec![vaddr]) 68 | } else { 69 | assert_eq!(size % iommu.minimum_contiguity(), 0); 70 | let mut mapped_addrs: Vec = Vec::new(); 71 | let mut remaining = size; 72 | let mut cur_offset = offset; 73 | while remaining > 0 { 74 | let (mut vaddr, mapped_len) = 75 | iommu.map(vmo.clone(), cur_offset, remaining, perms)?; 76 | assert_eq!(mapped_len % iommu.minimum_contiguity(), 0); 77 | for _ in 0..mapped_len / iommu.minimum_contiguity() { 78 | mapped_addrs.push(vaddr); 79 | vaddr += iommu.minimum_contiguity(); 80 | } 81 | remaining -= mapped_len; 82 | cur_offset += mapped_len; 83 | } 84 | Ok(mapped_addrs) 85 | } 86 | } 87 | 88 | pub fn encode_addrs( 89 | &self, 90 | compress_results: bool, 91 | contiguous: bool, 92 | ) -> ZxResult> { 93 | let iommu = self.bti.upgrade().unwrap().iommu(); 94 | if compress_results { 95 | if self.vmo.is_contiguous() { 96 | let num_addrs = ceil(self.size, iommu.minimum_contiguity()); 97 | let min_contig = iommu.minimum_contiguity(); 98 | let base = self.mapped_addrs[0]; 99 | Ok((0..num_addrs).map(|i| base + min_contig * i).collect()) 100 | } else { 101 | Ok(self.mapped_addrs.clone()) 102 | } 103 | } else if contiguous { 104 | if !self.vmo.is_contiguous() { 105 | Err(ZxError::INVALID_ARGS) 106 | } else { 107 | Ok(vec![self.mapped_addrs[0]]) 108 | } 109 | } else { 110 | let min_contig = if self.vmo.is_contiguous() { 111 | self.size 112 | } else { 113 | iommu.minimum_contiguity() 114 | }; 115 | let num_pages = self.size / PAGE_SIZE; 116 | let mut encoded_addrs: Vec = Vec::new(); 117 | for base in &self.mapped_addrs { 118 | let mut addr = *base; 119 | while addr < base + min_contig && encoded_addrs.len() < num_pages { 120 | encoded_addrs.push(addr); 121 | addr += PAGE_SIZE; // not sure ... 122 | } 123 | } 124 | Ok(encoded_addrs) 125 | } 126 | } 127 | 128 | /// Unpin pages and revoke device access to them. 129 | pub fn unpin(&self) { 130 | if let Some(bti) = self.bti.upgrade() { 131 | bti.release_pmt(self.base.id); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /zircon-object/src/signal/port_packet.rs: -------------------------------------------------------------------------------- 1 | //! Port packet data structure definition. 2 | 3 | use super::*; 4 | use core::fmt::{Debug, Formatter}; 5 | 6 | // C struct: for storing 7 | 8 | /// A packet sent through a port. 9 | #[repr(C)] 10 | pub struct PortPacket { 11 | pub key: u64, 12 | pub type_: PacketType, 13 | exception_num: u8, 14 | _padding: u16, 15 | pub status: ZxError, 16 | pub data: Payload, 17 | } 18 | 19 | // reference: zircon/system/public/zircon/syscalls/port.h ZX_PKT_TYPE_* 20 | #[repr(u8)] 21 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 22 | #[allow(dead_code)] 23 | pub enum PacketType { 24 | User = 0, 25 | SignalOne = 1, 26 | SignalRep = 2, 27 | GuestBell = 3, 28 | GuestMem = 4, 29 | GuestIo = 5, 30 | GuestVcpu = 6, 31 | Interrupt = 7, 32 | Exception = 8, 33 | PageRequest = 9, 34 | } 35 | 36 | #[repr(C)] 37 | pub union Payload { 38 | signal: PacketSignal, 39 | exception: PacketException, 40 | interrupt: PacketInterrupt, 41 | user: [u8; 32], 42 | } 43 | 44 | #[repr(C)] 45 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 46 | pub struct PacketSignal { 47 | pub trigger: Signal, 48 | pub observed: Signal, 49 | pub count: u64, 50 | pub timestamp: u64, 51 | } 52 | 53 | #[repr(C)] 54 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 55 | pub struct PacketException { 56 | pub pid: KoID, 57 | pub tid: KoID, 58 | pub num: u8, 59 | } 60 | 61 | #[repr(C)] 62 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 63 | pub struct PacketInterrupt { 64 | pub timestamp: i64, 65 | pub reserved0: u64, 66 | pub reserved1: u64, 67 | pub reserved2: u64, 68 | } 69 | 70 | // Rust struct: for internal constructing and debugging 71 | 72 | /// A high-level representation of a packet sent through a port. 73 | #[derive(Debug, Clone, Eq, PartialEq)] 74 | pub struct PortPacketRepr { 75 | pub key: u64, 76 | pub status: ZxError, 77 | pub data: PayloadRepr, 78 | } 79 | 80 | /// A high-level representation of a packet payload. 81 | #[derive(Debug, Clone, Eq, PartialEq)] 82 | pub enum PayloadRepr { 83 | Signal(PacketSignal), 84 | Exception(PacketException), 85 | Interrupt(PacketInterrupt), 86 | User([u8; 32]), 87 | } 88 | 89 | impl PayloadRepr { 90 | fn exception_num(&self) -> u8 { 91 | match self { 92 | PayloadRepr::Exception(exception) => exception.num, 93 | _ => 0, 94 | } 95 | } 96 | fn type_(&self) -> PacketType { 97 | match self { 98 | PayloadRepr::User(_) => PacketType::User, 99 | PayloadRepr::Signal(_) => PacketType::SignalOne, 100 | PayloadRepr::Exception(_) => PacketType::Exception, 101 | PayloadRepr::Interrupt(_) => PacketType::Interrupt, 102 | } 103 | } 104 | fn encode(&self) -> Payload { 105 | match *self { 106 | PayloadRepr::Signal(signal) => Payload { signal }, 107 | PayloadRepr::Exception(exception) => Payload { exception }, 108 | PayloadRepr::Interrupt(interrupt) => Payload { interrupt }, 109 | PayloadRepr::User(user) => Payload { user }, 110 | } 111 | } 112 | #[allow(unsafe_code)] 113 | fn decode(type_: PacketType, exception_num: u8, data: &Payload) -> Self { 114 | unsafe { 115 | match type_ { 116 | PacketType::User => PayloadRepr::User(data.user), 117 | PacketType::SignalOne => PayloadRepr::Signal(data.signal), 118 | PacketType::SignalRep => PayloadRepr::Signal(data.signal), 119 | PacketType::Exception => PayloadRepr::Exception(PacketException { 120 | num: exception_num, 121 | ..data.exception 122 | }), 123 | PacketType::Interrupt => PayloadRepr::Interrupt(data.interrupt), 124 | _ => unimplemented!(), 125 | } 126 | } 127 | } 128 | } 129 | 130 | impl From for PortPacket { 131 | fn from(r: PortPacketRepr) -> Self { 132 | PortPacket { 133 | key: r.key, 134 | type_: r.data.type_(), 135 | exception_num: r.data.exception_num(), 136 | _padding: 0, 137 | status: r.status, 138 | data: r.data.encode(), 139 | } 140 | } 141 | } 142 | 143 | impl From<&PortPacket> for PortPacketRepr { 144 | fn from(p: &PortPacket) -> Self { 145 | PortPacketRepr { 146 | key: p.key, 147 | status: p.status, 148 | data: PayloadRepr::decode(p.type_, p.exception_num, &p.data), 149 | } 150 | } 151 | } 152 | 153 | impl Debug for PortPacket { 154 | fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { 155 | PortPacketRepr::from(self).fmt(f) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /linux-syscall/src/file/fd.rs: -------------------------------------------------------------------------------- 1 | //! File descriptor operations 2 | //! 3 | //! - open(at) 4 | //! - close 5 | //! - dup2 6 | //! - pipe 7 | 8 | use super::*; 9 | 10 | impl Syscall<'_> { 11 | pub fn sys_open(&self, path: UserInPtr, flags: usize, mode: usize) -> SysResult { 12 | self.sys_openat(FileDesc::CWD, path, flags, mode) 13 | } 14 | 15 | pub fn sys_openat( 16 | &self, 17 | dir_fd: FileDesc, 18 | path: UserInPtr, 19 | flags: usize, 20 | mode: usize, 21 | ) -> SysResult { 22 | let proc = self.linux_process(); 23 | let path = path.read_cstring()?; 24 | let flags = OpenFlags::from_bits_truncate(flags); 25 | info!( 26 | "openat: dir_fd={:?}, path={:?}, flags={:?}, mode={:#o}", 27 | dir_fd, path, flags, mode 28 | ); 29 | 30 | let inode = if flags.contains(OpenFlags::CREATE) { 31 | let (dir_path, file_name) = split_path(&path); 32 | // relative to cwd 33 | let dir_inode = proc.lookup_inode_at(dir_fd, dir_path, true)?; 34 | match dir_inode.find(file_name) { 35 | Ok(file_inode) => { 36 | if flags.contains(OpenFlags::EXCLUSIVE) { 37 | return Err(LxError::EEXIST); 38 | } 39 | file_inode 40 | } 41 | Err(FsError::EntryNotFound) => { 42 | dir_inode.create(file_name, FileType::File, mode as u32)? 43 | } 44 | Err(e) => return Err(LxError::from(e)), 45 | } 46 | } else { 47 | proc.lookup_inode_at(dir_fd, &path, true)? 48 | }; 49 | 50 | let file = File::new(inode, flags.to_options(), path); 51 | let fd = proc.add_file(file)?; 52 | Ok(fd.into()) 53 | } 54 | 55 | pub fn sys_close(&self, fd: FileDesc) -> SysResult { 56 | info!("close: fd={:?}", fd); 57 | let proc = self.linux_process(); 58 | proc.close_file(fd)?; 59 | Ok(0) 60 | } 61 | 62 | pub fn sys_dup2(&self, fd1: FileDesc, fd2: FileDesc) -> SysResult { 63 | info!("dup2: from {:?} to {:?}", fd1, fd2); 64 | let proc = self.linux_process(); 65 | // close fd2 first if it is opened 66 | let _ = proc.close_file(fd2); 67 | let file_like = proc.get_file_like(fd1)?; 68 | proc.add_file_at(fd2, file_like); 69 | Ok(fd2.into()) 70 | } 71 | 72 | // pub fn sys_pipe(&self, fds: *mut u32) -> SysResult { 73 | // info!("pipe: fds={:?}", fds); 74 | // 75 | // let proc = self.process(); 76 | // let fds = unsafe { self.vm().check_write_array(fds, 2)? }; 77 | // let (read, write) = Pipe::create_pair(); 78 | // 79 | // let read_fd = proc.add_file(FileLike::File(File::new( 80 | // Arc::new(read), 81 | // OpenOptions { 82 | // read: true, 83 | // write: false, 84 | // append: false, 85 | // nonblock: false, 86 | // }, 87 | // String::from("pipe_r:[]"), 88 | // ))); 89 | // 90 | // let write_fd = proc.add_file(FileLike::File(File::new( 91 | // Arc::new(write), 92 | // OpenOptions { 93 | // read: false, 94 | // write: true, 95 | // append: false, 96 | // nonblock: false, 97 | // }, 98 | // String::from("pipe_w:[]"), 99 | // ))); 100 | // 101 | // fds[0] = read_fd as u32; 102 | // fds[1] = write_fd as u32; 103 | // 104 | // info!("pipe: created rfd={} wfd={}", read_fd, write_fd); 105 | // 106 | // Ok(0) 107 | // } 108 | } 109 | 110 | bitflags! { 111 | struct OpenFlags: usize { 112 | /// read only 113 | const RDONLY = 0; 114 | /// write only 115 | const WRONLY = 1; 116 | /// read write 117 | const RDWR = 2; 118 | /// create file if it does not exist 119 | const CREATE = 1 << 6; 120 | /// error if CREATE and the file exists 121 | const EXCLUSIVE = 1 << 7; 122 | /// truncate file upon open 123 | const TRUNCATE = 1 << 9; 124 | /// append on each write 125 | const APPEND = 1 << 10; 126 | } 127 | } 128 | 129 | impl OpenFlags { 130 | fn readable(self) -> bool { 131 | let b = self.bits() & 0b11; 132 | b == Self::RDONLY.bits() || b == Self::RDWR.bits() 133 | } 134 | fn writable(self) -> bool { 135 | let b = self.bits() & 0b11; 136 | b == Self::WRONLY.bits() || b == Self::RDWR.bits() 137 | } 138 | fn to_options(self) -> OpenOptions { 139 | OpenOptions { 140 | read: self.readable(), 141 | write: self.writable(), 142 | append: self.contains(Self::APPEND), 143 | nonblock: false, 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /zircon-object/src/dev/pci/mod.rs: -------------------------------------------------------------------------------- 1 | // use super::*; 2 | mod bus; 3 | mod caps; 4 | mod config; 5 | mod nodes; 6 | mod pio; 7 | 8 | pub(crate) use nodes::*; 9 | use pio::*; 10 | 11 | pub use self::bus::{ 12 | MmioPcieAddressProvider, PCIeBusDriver, PcieDeviceInfo, PcieDeviceKObject, 13 | PioPcieAddressProvider, 14 | }; 15 | pub use self::nodes::PcieIrqMode; 16 | pub use self::pio::{pio_config_read, pio_config_write}; 17 | 18 | #[derive(PartialEq, Debug)] 19 | pub enum PciAddrSpace { 20 | MMIO, 21 | PIO, 22 | } 23 | 24 | #[repr(C)] 25 | #[derive(Debug)] 26 | pub struct PciInitArgsAddrWindows { 27 | pub base: u64, 28 | pub size: usize, 29 | pub bus_start: u8, 30 | pub bus_end: u8, 31 | pub cfg_space_type: u8, 32 | pub has_ecam: bool, 33 | pub padding1: [u8; 4], 34 | } 35 | 36 | #[repr(C)] 37 | pub struct PciInitArgsIrqs { 38 | pub global_irq: u32, 39 | pub level_triggered: bool, 40 | pub active_high: bool, 41 | pub padding1: [u8; 2], 42 | } 43 | 44 | pub const PCI_MAX_DEVICES_PER_BUS: usize = 32; 45 | pub const PCI_MAX_FUNCTIONS_PER_DEVICE: usize = 8; 46 | pub const PCI_MAX_LEGACY_IRQ_PINS: usize = 4; 47 | pub const PCI_MAX_FUNCTIONS_PER_BUS: usize = PCI_MAX_FUNCTIONS_PER_DEVICE * PCI_MAX_DEVICES_PER_BUS; 48 | pub const PCI_MAX_IRQS: usize = 224; 49 | pub const PCI_INIT_ARG_MAX_ECAM_WINDOWS: usize = 2; 50 | 51 | #[repr(transparent)] 52 | #[derive(Clone, Copy)] 53 | pub struct PciIrqSwizzleLut( 54 | [[[u32; PCI_MAX_LEGACY_IRQ_PINS]; PCI_MAX_FUNCTIONS_PER_DEVICE]; PCI_MAX_DEVICES_PER_BUS], 55 | ); 56 | 57 | #[repr(C)] 58 | pub struct PciInitArgsHeader { 59 | pub dev_pin_to_global_irq: PciIrqSwizzleLut, 60 | pub num_irqs: u32, 61 | pub irqs: [PciInitArgsIrqs; PCI_MAX_IRQS], 62 | pub addr_window_count: u32, 63 | } 64 | 65 | pub struct PciEcamRegion { 66 | pub phys_base: u64, 67 | pub size: usize, 68 | pub bus_start: u8, 69 | pub bus_end: u8, 70 | } 71 | 72 | pub struct MappedEcamRegion { 73 | pub ecam: PciEcamRegion, 74 | pub vaddr: u64, 75 | } 76 | 77 | pub const PCI_INIT_ARG_MAX_SIZE: usize = core::mem::size_of::() 78 | * PCI_INIT_ARG_MAX_ECAM_WINDOWS 79 | + core::mem::size_of::(); 80 | pub const PCI_NO_IRQ_MAPPING: u32 = u32::MAX; 81 | pub const PCIE_PIO_ADDR_SPACE_MASK: u64 = 0xFFFF_FFFF; 82 | pub const PCIE_MAX_BUSSES: usize = 256; 83 | pub const PCIE_ECAM_BYTES_PER_BUS: usize = 84 | 4096 * PCI_MAX_DEVICES_PER_BUS * PCI_MAX_FUNCTIONS_PER_DEVICE; 85 | pub const PCIE_INVALID_VENDOR_ID: usize = 0xFFFF; 86 | 87 | pub const PCI_CFG_SPACE_TYPE_PIO: u8 = 0; 88 | pub const PCI_CFG_SPACE_TYPE_MMIO: u8 = 1; 89 | pub const PCIE_IRQRET_MASK: u32 = 0x1; 90 | pub const PCIE_MAX_MSI_IRQS: u32 = 32; 91 | 92 | use super::*; 93 | use alloc::sync::*; 94 | use kernel_hal::InterruptManager; 95 | 96 | impl PciInitArgsHeader { 97 | pub fn configure_interrupt(&mut self) -> ZxResult { 98 | for i in 0..self.num_irqs as usize { 99 | let irq = &mut self.irqs[i]; 100 | let global_irq = irq.global_irq; 101 | if !is_valid_interrupt(global_irq) { 102 | irq.global_irq = PCI_NO_IRQ_MAPPING; 103 | self.dev_pin_to_global_irq.remove_irq(global_irq); 104 | } else { 105 | irq_configure( 106 | global_irq, 107 | irq.level_triggered, /* Trigger mode */ 108 | irq.active_high, /* Polarity */ 109 | )?; 110 | } 111 | } 112 | Ok(()) 113 | } 114 | } 115 | 116 | fn is_valid_interrupt(irq: u32) -> bool { 117 | InterruptManager::is_valid(irq) 118 | } 119 | 120 | fn irq_configure(irq: u32, level_trigger: bool, active_high: bool) -> ZxResult { 121 | // In fuchsia source code, 'BSP' stands for bootstrap processor 122 | let dest = kernel_hal::apic_local_id(); 123 | if InterruptManager::configure( 124 | irq, 125 | 0, // vector 126 | dest, 127 | level_trigger, 128 | active_high, 129 | ) { 130 | Ok(()) 131 | } else { 132 | Err(ZxError::INVALID_ARGS) 133 | } 134 | } 135 | 136 | impl PciIrqSwizzleLut { 137 | fn swizzle(&self, dev_id: usize, func_id: usize, pin: usize) -> ZxResult { 138 | if dev_id >= PCI_MAX_DEVICES_PER_BUS 139 | || func_id >= PCI_MAX_FUNCTIONS_PER_DEVICE 140 | || pin >= PCI_MAX_LEGACY_IRQ_PINS 141 | { 142 | return Err(ZxError::INVALID_ARGS); 143 | } 144 | let irq = self.0[dev_id][func_id][pin]; 145 | if irq == PCI_NO_IRQ_MAPPING { 146 | Err(ZxError::NOT_FOUND) 147 | } else { 148 | Ok(irq as usize) 149 | } 150 | } 151 | 152 | fn remove_irq(&mut self, irq: u32) { 153 | for dev in self.0.iter_mut() { 154 | for func in dev.iter_mut() { 155 | for pin in func.iter_mut() { 156 | if *pin == irq { 157 | *pin = PCI_NO_IRQ_MAPPING; 158 | } 159 | } 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /kernel-hal-bare/src/arch/riscv.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use riscv::addr::Page; 3 | use riscv::paging::{PageTableFlags as PTF, *}; 4 | use riscv::register::satp; 5 | 6 | /// Page Table 7 | #[repr(C)] 8 | pub struct PageTableImpl { 9 | root_paddr: PhysAddr, 10 | } 11 | 12 | impl PageTableImpl { 13 | /// Create a new `PageTable`. 14 | #[allow(clippy::new_without_default)] 15 | #[export_name = "hal_pt_new"] 16 | pub fn new() -> Self { 17 | let root_frame = Frame::alloc().expect("failed to alloc frame"); 18 | let root_vaddr = phys_to_virt(root_frame.paddr); 19 | let root = unsafe { &mut *(root_vaddr as *mut PageTable) }; 20 | root.zero(); 21 | let current = 22 | phys_to_virt(satp::read().frame().start_address().as_usize()) as *const PageTable; 23 | map_kernel(root_vaddr as _, current as _); 24 | trace!("create page table @ {:#x}", root_frame.paddr); 25 | PageTableImpl { 26 | root_paddr: root_frame.paddr, 27 | } 28 | } 29 | 30 | /// Map the page of `vaddr` to the frame of `paddr` with `flags`. 31 | #[export_name = "hal_pt_map"] 32 | pub fn map( 33 | &mut self, 34 | vaddr: riscv::addr::VirtAddr, 35 | paddr: riscv::addr::PhysAddr, 36 | flags: MMUFlags, 37 | ) -> Result<(), ()> { 38 | let mut pt = self.get(); 39 | let page = Page::of_addr(vaddr); 40 | let frame = riscv::addr::Frame::of_addr(paddr); 41 | pt.map_to(page, frame, flags.to_ptf(), &mut FrameAllocatorImpl) 42 | .unwrap() 43 | .flush(); 44 | trace!("map: {:x?} -> {:x?}, flags={:?}", vaddr, paddr, flags); 45 | Ok(()) 46 | } 47 | 48 | /// Unmap the page of `vaddr`. 49 | #[export_name = "hal_pt_unmap"] 50 | pub fn unmap(&mut self, vaddr: riscv::addr::VirtAddr) -> Result<(), ()> { 51 | let mut pt = self.get(); 52 | let page = Page::of_addr(vaddr); 53 | pt.unmap(page).unwrap().1.flush(); 54 | trace!("unmap: {:x?}", vaddr); 55 | Ok(()) 56 | } 57 | 58 | /// Change the `flags` of the page of `vaddr`. 59 | #[export_name = "hal_pt_protect"] 60 | pub fn protect(&mut self, vaddr: riscv::addr::VirtAddr, flags: MMUFlags) -> Result<(), ()> { 61 | let mut pt = self.get(); 62 | let page = Page::of_addr(vaddr); 63 | pt.update_flags(page, flags.to_ptf()).unwrap().flush(); 64 | trace!("protect: {:x?}, flags={:?}", vaddr, flags); 65 | Ok(()) 66 | } 67 | 68 | /// Query the physical address which the page of `vaddr` maps to. 69 | #[export_name = "hal_pt_query"] 70 | pub fn query(&mut self, vaddr: riscv::addr::VirtAddr) -> Result { 71 | let mut pt = self.get(); 72 | let page = Page::of_addr(vaddr); 73 | let res = pt.ref_entry(page); 74 | trace!("query: {:x?} => {:x?}", vaddr, res); 75 | match res { 76 | Ok(entry) => Ok(entry.addr()), 77 | Err(_) => Err(()), 78 | } 79 | } 80 | 81 | #[cfg(target_arch = "riscv32")] 82 | fn get(&mut self) -> Rv32PageTable<'_> { 83 | let root_vaddr = phys_to_virt(self.root_paddr); 84 | let root = unsafe { &mut *(root_vaddr as *mut PageTable) }; 85 | Rv32PageTable::new(root, phys_to_virt(0)) 86 | } 87 | 88 | #[cfg(target_arch = "riscv64")] 89 | fn get(&mut self) -> Rv39PageTable<'_> { 90 | let root_vaddr = phys_to_virt(self.root_paddr); 91 | let root = unsafe { &mut *(root_vaddr as *mut PageTable) }; 92 | Rv39PageTable::new(root, phys_to_virt(0)) 93 | } 94 | } 95 | 96 | pub unsafe fn set_page_table(vmtoken: usize) { 97 | #[cfg(target_arch = "riscv32")] 98 | let mode = satp::Mode::Sv32; 99 | #[cfg(target_arch = "riscv64")] 100 | let mode = satp::Mode::Sv39; 101 | satp::set(mode, 0, vmtoken >> 12); 102 | } 103 | 104 | trait FlagsExt { 105 | fn to_ptf(self) -> PTF; 106 | } 107 | 108 | impl FlagsExt for MMUFlags { 109 | fn to_ptf(self) -> PTF { 110 | let mut flags = PTF::VALID; 111 | if self.contains(MMUFlags::READ) { 112 | flags |= PTF::READABLE; 113 | } 114 | if self.contains(MMUFlags::WRITE) { 115 | flags |= PTF::WRITABLE; 116 | } 117 | if self.contains(MMUFlags::EXECUTE) { 118 | flags |= PTF::EXECUTABLE; 119 | } 120 | if self.contains(MMUFlags::USER) { 121 | flags |= PTF::USER; 122 | } 123 | flags 124 | } 125 | } 126 | 127 | struct FrameAllocatorImpl; 128 | 129 | impl FrameAllocator for FrameAllocatorImpl { 130 | fn alloc(&mut self) -> Option { 131 | Frame::alloc().map(|f| { 132 | let paddr = riscv::addr::PhysAddr::new(f.paddr); 133 | riscv::addr::Frame::of_addr(paddr) 134 | }) 135 | } 136 | } 137 | 138 | impl FrameDeallocator for FrameAllocatorImpl { 139 | fn dealloc(&mut self, frame: riscv::addr::Frame) { 140 | Frame { 141 | paddr: frame.start_address().as_usize(), 142 | } 143 | .dealloc() 144 | } 145 | } 146 | 147 | pub fn init() {} 148 | --------------------------------------------------------------------------------