├── .dockerignore ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── docs ├── authorizations.md ├── interfaces.md ├── introduction.md └── messages.md ├── interface-wrappers ├── disk │ ├── Cargo.toml │ └── src │ │ ├── disk.rs │ │ ├── ffi.rs │ │ └── lib.rs ├── ethernet │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ ├── interface.rs │ │ └── lib.rs ├── framebuffer │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ └── lib.rs ├── hardware │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ ├── lib.rs │ │ └── malloc.rs ├── interface │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ └── lib.rs ├── kernel-debug │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── kernel-log │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ └── lib.rs ├── loader │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ └── lib.rs ├── log │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ └── lib.rs ├── pci │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ └── lib.rs ├── random │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ └── lib.rs ├── syscalls │ ├── Cargo.toml │ └── src │ │ ├── block_on.rs │ │ ├── emit.rs │ │ ├── ffi.rs │ │ ├── lib.rs │ │ ├── response.rs │ │ └── traits.rs ├── system-time │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ └── lib.rs ├── tcp │ ├── Cargo.toml │ └── src │ │ ├── ffi.rs │ │ └── lib.rs ├── time │ ├── Cargo.toml │ └── src │ │ ├── delay.rs │ │ ├── ffi.rs │ │ ├── instant.rs │ │ └── lib.rs └── video-output │ ├── Cargo.toml │ └── src │ ├── ffi.rs │ ├── lib.rs │ └── video_output.rs ├── kernel-standalone-builder ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── res │ ├── rpi-firmware │ │ └── boot │ │ │ ├── COPYING.linux │ │ │ ├── LICENCE.broadcom │ │ │ ├── bcm2711-rpi-4-b.dtb │ │ │ ├── bootcode.bin │ │ │ ├── fixup.dat │ │ │ ├── fixup4.dat │ │ │ ├── start.elf │ │ │ └── start4.elf │ └── specs │ │ ├── aarch64-freestanding.json │ │ ├── aarch64-freestanding.ld │ │ ├── arm-freestanding.json │ │ ├── arm-freestanding.ld │ │ ├── riscv-hifive.json │ │ ├── riscv-hifive.ld │ │ ├── x86_64-multiboot2.json │ │ └── x86_64-multiboot2.ld ├── simpleboot │ ├── README.md │ ├── simpleboot │ │ ├── .gitignore │ │ ├── Kconfig │ │ ├── Kconfig.name │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── distrib │ │ │ ├── PKGBUILD │ │ │ ├── coreboot.rom.gz │ │ │ ├── simpleboot │ │ │ ├── simpleboot-1.0.0.ebuild │ │ │ ├── simpleboot-9999.ebuild │ │ │ ├── simpleboot.exe │ │ │ ├── simpleboot_1.0.0-amd64.deb │ │ │ └── simpleboot_1.0.0-armhf.deb │ │ ├── docs │ │ │ ├── ABI.md │ │ │ ├── README.md │ │ │ └── coreboot.md │ │ ├── example │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── bochs.rc │ │ │ ├── gdb.rc │ │ │ ├── kernel.c │ │ │ ├── linux.c │ │ │ └── simpleboot.cfg │ │ ├── simpleboot.h │ │ └── src │ │ │ ├── Makefile │ │ │ ├── boot_x86.asm │ │ │ ├── cdemu_x86.asm │ │ │ ├── data.h │ │ │ ├── inflate.h │ │ │ ├── loader.h │ │ │ ├── loader_cb.c │ │ │ ├── loader_rpi.c │ │ │ ├── loader_x86.c │ │ │ ├── misc │ │ │ ├── bin2h.c │ │ │ ├── deb_control │ │ │ └── simpleboot.1.gz │ │ │ ├── rombios_x86.asm │ │ │ ├── romfoss_x86.asm │ │ │ └── simpleboot.c │ └── wrapper.c └── src │ ├── bin │ └── main.rs │ ├── binary.rs │ ├── build.rs │ ├── emulator.rs │ ├── image.rs │ ├── lib.rs │ ├── simpleboot.rs │ └── test.rs ├── kernel ├── core-proc-macros │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── core │ ├── Cargo.toml │ ├── benches │ │ ├── keccak.rs │ │ └── keccak.wasm │ └── src │ │ ├── extrinsics.rs │ │ ├── extrinsics │ │ ├── log_calls.rs │ │ └── wasi.rs │ │ ├── id_pool.rs │ │ ├── lib.rs │ │ ├── module.rs │ │ ├── primitives.rs │ │ ├── scheduler.rs │ │ ├── scheduler │ │ ├── extrinsics.rs │ │ ├── extrinsics │ │ │ └── calls.rs │ │ ├── ipc.rs │ │ ├── ipc │ │ │ ├── notifications_queue.rs │ │ │ └── waiting_threads.rs │ │ ├── processes.rs │ │ ├── processes │ │ │ ├── tests.rs │ │ │ └── wakers.rs │ │ ├── tests.rs │ │ ├── tests │ │ │ ├── basic_module.rs │ │ │ ├── emit_not_available.rs │ │ │ └── trapping_module.rs │ │ └── vm.rs │ │ ├── system.rs │ │ └── system │ │ ├── interfaces.rs │ │ └── pending_answers.rs └── standalone │ ├── Cargo.toml │ ├── build.rs │ ├── src │ ├── arch.rs │ ├── arch │ │ ├── arm.rs │ │ ├── arm │ │ │ ├── executor.rs │ │ │ ├── log.rs │ │ │ ├── misc.rs │ │ │ ├── time_aarch64.rs │ │ │ └── time_arm.rs │ │ ├── riscv.rs │ │ ├── riscv │ │ │ ├── executor.rs │ │ │ ├── interrupts.rs │ │ │ ├── log.rs │ │ │ └── misc.rs │ │ ├── x86_64.rs │ │ └── x86_64 │ │ │ ├── acpi.rs │ │ │ ├── ap_boot.rs │ │ │ ├── apic.rs │ │ │ ├── apic │ │ │ ├── io_apic.rs │ │ │ ├── io_apics.rs │ │ │ ├── local.rs │ │ │ ├── pic.rs │ │ │ ├── timers.rs │ │ │ └── tsc_sync.rs │ │ │ ├── boot.rs │ │ │ ├── executor.rs │ │ │ ├── gdt.rs │ │ │ ├── interrupts.rs │ │ │ ├── panic.rs │ │ │ └── pit.rs │ ├── hardware.rs │ ├── kernel.rs │ ├── klog.rs │ ├── klog │ │ ├── logger.rs │ │ ├── native.rs │ │ └── video.rs │ ├── lib.rs │ ├── mem_alloc.rs │ ├── pci.rs │ ├── pci │ │ ├── native.rs │ │ └── pci.rs │ ├── random.rs │ ├── random │ │ ├── native.rs │ │ └── rng.rs │ └── time.rs │ └── vcr_osd_mono.ttf ├── programs ├── .cargo │ └── config.toml ├── .dockerignore ├── Cargo.lock ├── Cargo.toml ├── compositor │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── main.rs │ │ └── rect.rs ├── diagnostics-http-server │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── dummy-system-time │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── e1000 │ ├── Cargo.toml │ └── src │ │ ├── device.rs │ │ └── main.rs ├── hello-world │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── log-to-kernel │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── network-manager │ ├── Cargo.toml │ └── src │ │ ├── interface.rs │ │ ├── lib.rs │ │ ├── main.rs │ │ ├── manager.rs │ │ └── port_assign.rs ├── pci-printer │ ├── Cargo.toml │ ├── build.rs │ ├── build │ │ └── pci.ids │ └── src │ │ └── main.rs ├── rpi-framebuffer │ ├── Cargo.toml │ └── src │ │ ├── mailbox.rs │ │ ├── main.rs │ │ └── property.rs ├── stub │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── third-party │ ├── README.md │ └── wasm-timer │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs └── vga-vbe │ ├── Cargo.toml │ └── src │ ├── interpreter.rs │ ├── interpreter │ ├── i386.pdf │ ├── test-mem.bin │ └── tests.rs │ ├── main.rs │ └── vbe.rs └── rust-toolchain /.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | labels: [] 6 | rebase-strategy: disabled # Redundant with mergify 7 | schedule: 8 | interval: daily 9 | - package-ecosystem: cargo 10 | directory: "/kernel-standalone-builder" 11 | labels: [] 12 | rebase-strategy: disabled # Redundant with mergify 13 | schedule: 14 | interval: daily 15 | - package-ecosystem: cargo 16 | directory: "/programs" 17 | labels: [] 18 | rebase-strategy: disabled # Redundant with mergify 19 | schedule: 20 | interval: daily 21 | - package-ecosystem: cargo 22 | directory: "/" 23 | labels: [] 24 | rebase-strategy: disabled # Redundant with mergify 25 | schedule: 26 | interval: daily 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "kernel/core", 4 | "kernel/core-proc-macros", 5 | "kernel/standalone", 6 | "interface-wrappers/disk", 7 | "interface-wrappers/ethernet", 8 | "interface-wrappers/framebuffer", 9 | "interface-wrappers/hardware", 10 | "interface-wrappers/interface", 11 | "interface-wrappers/kernel-debug", 12 | "interface-wrappers/kernel-log", 13 | "interface-wrappers/loader", 14 | "interface-wrappers/log", 15 | "interface-wrappers/pci", 16 | "interface-wrappers/random", 17 | "interface-wrappers/syscalls", 18 | "interface-wrappers/system-time", 19 | "interface-wrappers/tcp", 20 | "interface-wrappers/time", 21 | "interface-wrappers/video-output", 22 | ] 23 | 24 | [profile.dev] 25 | opt-level = 1 26 | 27 | [profile.dev.package."*"] 28 | opt-level = 3 29 | 30 | [profile.test.package."*"] 31 | opt-level = 3 32 | 33 | [profile.release] 34 | opt-level = 3 35 | lto = true 36 | codegen-units = 1 37 | panic = 'abort' 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The **redshirt** operating system is an experiment to build some kind of operating-system-like 2 | environment where executables are all in Wasm and are loaded from an IPFS-like decentralized 3 | network. 4 | 5 | See the `docs/introduction.md` file for an introduction. 6 | 7 | # How to test 8 | 9 | **Important**: At the moment, most of the compilation requires a nightly version of Rust. See also https://github.com/tomaka/redshirt/issues/300. 10 | Your C compiler must be recent enough to be capable of compiling to WebAssembly. This is for example the case for clang 9. See also https://github.com/tomaka/redshirt/issues/257. 11 | 12 | You also need to install the `wasm32-wasip1` target, as the Wasm programs are compiled for Wasi, and the `rust-src` component in order to build the standalone kernel. 13 | 14 | ``` 15 | rustup toolchain install --target=wasm32-wasip1 nightly 16 | rustup component add --toolchain=nightly rust-src 17 | ``` 18 | 19 | Building the freestanding kernel is then done through the utility called `standalone-builder`: 20 | 21 | ``` 22 | cd kernel-standalone-builder 23 | cargo +nightly run -- emulator-run --emulator qemu --target x86_64-multiboot2 24 | ``` 25 | 26 | # Repository structure 27 | 28 | Short overview of the structure of the repository: 29 | 30 | - `docs` contains a description of what redshirt is and how it works. Start with `docs/introduction.md`. 31 | - `interface-wrappers` contains crates that provide definitions and helpers for Wasm programs to use 32 | (examples: `tcp` for TCP/IP, `window` for windowing). 33 | - `kernel` contains the code required to run the kernel. 34 | - `kernel-standalone-kernel` contains a utility allowing to run and test the standalone kernel. 35 | - `programs` contains Wasm programs. 36 | 37 | # Contributing 38 | 39 | Please note that so far this is mostly a personal project. I reserve the right to change anything 40 | at any time, including the license. 41 | -------------------------------------------------------------------------------- /docs/authorizations.md: -------------------------------------------------------------------------------- 1 | It is generally desirable to limit as much as possible the rights that a program has. 2 | 3 | In redshirt, there is no system-wide rights management. Instead, each interface holds a list of which program can have access to the capabilities that they provide. 4 | 5 | For example, it is the network manager program that holds a list of the programs that are allowed to open TCP connections. 6 | 7 | By default, all programs should be banned from using anything, and must instead be whitelisted. For example, when you create a new process, it is by default prevented from using the TCP connection. One must then send a message to the TCP interface to inform the network manager that the newly-created process is allowed to open TCP connections. 8 | -------------------------------------------------------------------------------- /interface-wrappers/disk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-disk-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = "0.3.13" 10 | redshirt-syscalls = { path = "../syscalls" } 11 | parity-scale-codec = { version = "1.3.6", features = ["derive"] } 12 | rand = "0.8.3" 13 | -------------------------------------------------------------------------------- /interface-wrappers/disk/src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use parity_scale_codec::{Decode, Encode}; 17 | use redshirt_syscalls::InterfaceHash; 18 | 19 | // TODO: this has been randomly generated; instead should be a hash or something 20 | pub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([ 21 | 0x99, 0x94, 0xca, 0x60, 0xcf, 0x73, 0x7b, 0x59, 0xf7, 0xdc, 0x0c, 0xc4, 0xf0, 0x57, 0x42, 0x2e, 22 | 0x79, 0xa7, 0xb6, 0x81, 0xbb, 0xf8, 0x4e, 0x24, 0x8e, 0xbf, 0x1a, 0x8f, 0x2c, 0xf6, 0xea, 0xc8, 23 | ]); 24 | 25 | #[derive(Debug, Encode, Decode)] 26 | pub enum DiskMessage { 27 | /// Notify of the existence of a new disk. 28 | // TODO: what if this id was already registered? 29 | RegisterDisk { 30 | /// Unique per-process identifier. 31 | id: u64, 32 | /// True if writing to this disk is allowed. 33 | allow_write: bool, 34 | /// Size, in bytes, of a sector of the disk. 35 | sector_size: u32, 36 | /// Number of sectors on the disk. 37 | num_sectors: u32, 38 | }, 39 | 40 | /// Removes a previously-registered disk. 41 | UnregisterDisk(u64), 42 | 43 | /// Asks for the next command the disk must execute. 44 | /// 45 | /// Must answer with a [`DiskCommand`]. 46 | DiskNextCommand(u64), 47 | 48 | /// Report that a [`DiskCommand::StartRead`] has finished. 49 | /// 50 | /// Has no response. 51 | ReadFinished(ReadId, Vec), 52 | 53 | /// Report that a [`DiskCommand::StartWrite`] has finished. 54 | /// 55 | /// Has no response. 56 | WriteFinished(WriteId), 57 | } 58 | 59 | #[derive(Debug, Encode, Decode)] 60 | pub enum DiskCommand { 61 | StartRead { 62 | id: ReadId, 63 | sector_lba: u64, 64 | num_sectors: u32, 65 | }, 66 | StartWrite { 67 | id: WriteId, 68 | sector_lba: u64, 69 | data: Vec, 70 | }, 71 | } 72 | 73 | #[derive(Debug, Encode, Decode, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 74 | pub struct ReadId(pub u64); 75 | 76 | #[derive(Debug, Encode, Decode, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 77 | pub struct WriteId(pub u64); 78 | -------------------------------------------------------------------------------- /interface-wrappers/disk/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Disk registration and commands issuance. 17 | //! 18 | //! # Overview 19 | //! 20 | //! This interface allows indicating the presence of a disk on the machine by registering it. The 21 | //! registered disk can then receive commands (such as reading and writing data) that it must 22 | //! execute. 23 | //! 24 | //! The word "disk" should be understood as in a hard disk drive (HDD), solid-state drive (SSD), 25 | //! CD-ROM drive, floppy disk drive, and anything similar. 26 | //! 27 | //! It is recommended to **not** register disks that aren't actual physical objects connected to 28 | //! the machine (such as disks accessed over the network, or equivalents to UNIX's `losetup`). 29 | //! Redshirt tries to be as explicit as possible and to keep its abstractions as close as possible 30 | //! to the objects being abstracted. 31 | //! 32 | //! Users of this interface are expected to be ATA/ATAPI drivers, USB drivers, and similar. The 33 | //! handler of this interface is expected to be a filesystem manager that determines the list of 34 | //! partitions and handles the file systems. 35 | //! 36 | //! # About disks 37 | //! 38 | //! In the abstraction exposed by this interface, a disk is composed of a certain number of 39 | //! sectors, each having a certain size. The size of all sectors is identical. These sectors are 40 | //! indexed from `0` to `num_sectors - 1`. 41 | //! 42 | //! The sector index is typically referred to by the term "LBA sector". *LBA* designates the fact 43 | //! that each sector is addressed through a index ranging linearly from `0` to `num_sectors - 1`, 44 | //! as opposed to the older *CHS* addressing where sectors were referred to a by a head number, 45 | //! cylinder number, and sectors offset. CHS addressing isn't used in this interface. 46 | //! 47 | //! It is not possible to partially read or write a sector. The sector has to be read entirely, 48 | //! or written entirely. 49 | //! 50 | //! # Flushing 51 | //! 52 | //! The interface requires each disk write to be confirmed by sending a message on the interface 53 | //! after it has been performed. This is important in order for the upper layer to be capable of 54 | //! handling problematic situations such as a power outage. 55 | //! 56 | //! Consequently, while the disk driver is allowed to maintain a write cache, it must not report 57 | //! a write success after the data has been put in cache, but after it has been written to disk. 58 | //! 59 | //! In the interval of time between the moment the writing is issued and the moment it is 60 | //! confirmed, the upper layers should consider that the sector is physically in an undefined 61 | //! state. 62 | 63 | pub mod disk; 64 | pub mod ffi; 65 | -------------------------------------------------------------------------------- /interface-wrappers/ethernet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-ethernet-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = "0.3.13" 10 | redshirt-syscalls = { path = "../syscalls" } 11 | parity-scale-codec = { version = "1.3.6", features = ["derive"] } 12 | rand = "0.8.3" 13 | -------------------------------------------------------------------------------- /interface-wrappers/ethernet/src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use parity_scale_codec::{Decode, Encode}; 17 | use redshirt_syscalls::InterfaceHash; 18 | 19 | // TODO: this has been randomly generated; instead should be a hash or something 20 | pub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([ 21 | 0x56, 0xf0, 0xad, 0x54, 0x6c, 0x6d, 0x91, 0xce, 0xc2, 0x10, 0x88, 0xf6, 0x32, 0x2b, 0x66, 0x45, 22 | 0xd4, 0xcf, 0xbe, 0xa3, 0xf7, 0x03, 0x13, 0xcd, 0x04, 0x65, 0xfd, 0x7f, 0x06, 0xd4, 0x24, 0xa1, 23 | ]); 24 | 25 | #[derive(Debug, Encode, Decode)] 26 | pub enum NetworkMessage { 27 | /// Notify of the existence of a new Ethernet interface. 28 | // TODO: what if this id was already registered? 29 | RegisterInterface { 30 | /// Unique per-process identifier. 31 | id: u64, 32 | /// MAC address of the interface. 33 | mac_address: [u8; 6], 34 | }, 35 | 36 | /// Removes a previously-registered interface. 37 | UnregisterInterface(u64), 38 | 39 | /// Notify when an interface has received data (e.g. from the outside world). Must answer with 40 | /// a `()` when the send is finished and we're ready to accept a new packet. 41 | /// 42 | /// The packet must be an Ethernet frame without the CRC. 43 | InterfaceOnData(u64, Vec), 44 | 45 | /// Asks for the next packet of data to send out through this interface (e.g. going towards 46 | /// the outside world). Must answer with a `Vec`. 47 | /// 48 | /// The packet must be an Ethernet frame without the CRC. 49 | InterfaceWaitData(u64), 50 | } 51 | -------------------------------------------------------------------------------- /interface-wrappers/ethernet/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Ethernet interfaces. 17 | //! 18 | //! This interface allows registering Ethernet interfaces that conform to the requirements 19 | //! described in [RFC1122](https://tools.ietf.org/html/rfc1122). 20 | //! 21 | //! Users of this interface can notify of the presence of an Ethernet interface, after which it 22 | //! can notify of Ethernet frames having been received on this interface, and request Ethernet 23 | //! frames to be sent on the interface. 24 | //! 25 | //! The Ethernet frames that are communicated contain: 26 | //! 27 | //! - The destination MAC. 28 | //! - The source MAC. 29 | //! - An optional 802.1Q tag. 30 | //! - The Ethertype field. 31 | //! - The payload. 32 | //! 33 | //! Most notably, they **don't** include any preamble, delimiter, interpacket gap, and checksum. 34 | //! 35 | //! # Networking overview 36 | //! 37 | //! This section provides some overview of networking in general. 38 | //! 39 | //! ## Link layer routing 40 | //! 41 | //! Each Ethernet interface registered with this interface possesses a MAC address, and is assumed 42 | //! to be directly connected to zero, one, or more other machines. 43 | //! 44 | //! Thanks to the ARP or NDP protocols, it is possible to broadcast a request on the Ethernet 45 | //! interface asking who we are connected to. The nodes that receive the request respond with their 46 | //! IP and MAC address. If later we want to send a direct message to one of these nodes, we simply 47 | //! emit an Ethernet frame with the MAC address of the destination. 48 | //! 49 | //! Note that being "directly connected" to a node doesn't necessarily mean that there exists a 50 | //! physical cable between us and this node. Hubs, switches, or Wifi routers, can act as an 51 | //! intermediary. 52 | //! 53 | //! ## IP layer routing 54 | //! 55 | //! All of the registered Ethernet interfaces are considered as being part of one single network 56 | //! (typically the Internet). 57 | //! 58 | //! > **Note**: This doesn't mean that we are free to send out packets on any interface that we 59 | //! > want and expect the routing to make the packet find its way. In particular, this 60 | //! > single network can be disjoint. 61 | //! 62 | //! Nodes on this network (i.e. something with an IP address) can be split into two categories: 63 | //! 64 | //! - Nodes we are directly connected to, as described in the previous section. It is possible to 65 | //! send a direct message to these nodes by writing bytes on the right interface. 66 | //! - Nodes we are *not* directly connected to. 67 | //! 68 | //! The implementer of this interface maintains what we call a *routing table*. A routing table is 69 | //! a collection of entries, each entry consisting of: 70 | //! 71 | //! - A "pattern", kind of similar to a regex for example. This pattern consists of an IP address 72 | //! and mask. An IP address matches that pattern if 73 | //! `(ip_addr & pattern.mask) == (pattern.ip & pattern.mask)`. 74 | //! - A gateway. This is the IP address of a node that we are physically connected to and that is 75 | //! in charge of relaying packets to nodes that match the given pattern. 76 | //! - The network interface the gateway is connected to. 77 | //! 78 | //! When we want to reach the node with a specific IP address, we look through the table until 79 | //! we find an entry whose pattern matches the target IP address. If multiple entries are matching, 80 | //! we pick the one with the most specific mask. 81 | //! 82 | //! The gateway is then expected to properly direct the packet towards its rightful destination. 83 | //! 84 | 85 | pub mod ffi; 86 | pub mod interface; 87 | -------------------------------------------------------------------------------- /interface-wrappers/framebuffer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-framebuffer-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = "0.3" 10 | parity-scale-codec = { version = "1.3.6", features = ["derive"] } 11 | redshirt-random-interface = { path = "../random", default-features = false } 12 | redshirt-syscalls = { path = "../syscalls", default-features = false } 13 | -------------------------------------------------------------------------------- /interface-wrappers/framebuffer/src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! 17 | //! 18 | //! Message format: 19 | //! 20 | //! The type of message depends on the first byte: 21 | //! 22 | //! - 0: Creates a framebuffer. Next 4 bytes are a "framebuffer ID" as decided by the message 23 | //! emitter. Next 4 bytes are the width in little endian. Next 4 bytes are the height in little 24 | //! endian. 25 | //! - 1: Destroys a framebuffer. Next 4 bytes are the framebuffer ID. 26 | //! - 2: Set framebuffer content. Next 4 bytes are the framebuffer ID. The rest is 3 * width * 27 | //! height values. The rest is RGB triplets. 28 | //! - 3: Send back the next input event. Next 4 bytes are the framebuffer ID. The answer consists 29 | //! in an input event whose format is a SCALE-encoding of the [`Event`] struct below. 30 | //! 31 | //! There actually exists two interfaces that use the same messages format: with events, or without 32 | //! events. Messages whose first byte is `3` are invalid in the "without events" interface. 33 | 34 | use redshirt_syscalls::InterfaceHash; 35 | 36 | // TODO: this has been randomly generated; instead should be a hash or something 37 | pub const INTERFACE_WITH_EVENTS: InterfaceHash = InterfaceHash::from_raw_hash([ 38 | 0xfc, 0x60, 0x2e, 0x6e, 0xf2, 0x43, 0x9c, 0xa0, 0x40, 0x88, 0x81, 0x7d, 0xe5, 0xaf, 0xb6, 0x90, 39 | 0x9e, 0x57, 0xc6, 0xc2, 0x5e, 0xbf, 0x02, 0x5b, 0x87, 0x7f, 0xaa, 0xae, 0xbe, 0xd5, 0x19, 0x9c, 40 | ]); 41 | 42 | // TODO: this has been randomly generated; instead should be a hash or something 43 | pub const INTERFACE_WITHOUT_EVENTS: InterfaceHash = InterfaceHash::from_raw_hash([ 44 | 0xdf, 0x67, 0x74, 0x34, 0xd8, 0x0d, 0xc5, 0x9e, 0xf0, 0x6e, 0xb9, 0x44, 0xce, 0xaa, 0xc4, 0xde, 45 | 0x8d, 0x2f, 0xdf, 0x39, 0x0a, 0xe6, 0xa8, 0x29, 0x3c, 0x8f, 0x88, 0x76, 0x5b, 0xe9, 0x1c, 0x70, 46 | ]); 47 | 48 | /// Event that can be reported by a framebuffer. 49 | /// 50 | /// > **Note**: These events are designed to take into account the possibility that some events are 51 | /// > lost. This can happen if the recipient queues messages too slowly. 52 | #[derive(Debug, Clone, parity_scale_codec::Encode, parity_scale_codec::Decode)] 53 | pub enum Event { 54 | /// A keyboard key has been pressed or released. 55 | KeyboardChange { 56 | /// Scancode as defined in the USB HID Usage tables. 57 | /// 58 | /// See table 12 on page 53: 59 | /// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf 60 | scancode: u16, 61 | 62 | /// New state of the given key. 63 | new_state: ElementState, 64 | }, 65 | 66 | /// The cursor has moved over the framebuffer. 67 | CursorMoved { 68 | /// New position of the cursor in millipixels relative to the top-left hand corner of the 69 | /// framebuffer. `None` if the cursor is not on the framebuffer. 70 | /// 71 | /// Please note that these are millipixels. As such, you have to divide them by 1000 to 72 | /// obtain a value in pixels. 73 | new_position: Option<(u64, u64)>, 74 | }, 75 | 76 | /// A mouse button has been pressed or released. 77 | MouseButtonChange { 78 | /// Which mouse button is concerned. 79 | button: MouseButton, 80 | 81 | /// New state of the given button. 82 | new_state: ElementState, 83 | }, 84 | } 85 | 86 | #[derive(Debug, Clone, parity_scale_codec::Encode, parity_scale_codec::Decode)] 87 | pub enum MouseButton { 88 | /// Typically but not necessarily the left mouse button. 89 | Main, 90 | /// Typically but not necessarily the right mouse button. 91 | Secondary, 92 | } 93 | 94 | #[derive(Debug, Clone, parity_scale_codec::Encode, parity_scale_codec::Decode)] 95 | pub enum ElementState { 96 | Pressed, 97 | Released, 98 | } 99 | -------------------------------------------------------------------------------- /interface-wrappers/hardware/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-hardware-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = { version = "0.3.13", default-features = false } 10 | redshirt-syscalls = { path = "../syscalls", default-features = false } 11 | parity-scale-codec = { version = "1.3.6", default-features = false, features = ["derive"] } 12 | 13 | [features] 14 | default = ["std"] 15 | std = [] 16 | -------------------------------------------------------------------------------- /interface-wrappers/interface/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-interface-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = { version = "0.3.13", default-features = false, features = ["alloc"] } 10 | parity-scale-codec = { version = "1.3.6", default-features = false, features = ["derive"] } 11 | redshirt-syscalls = { path = "../syscalls", default-features = false } 12 | -------------------------------------------------------------------------------- /interface-wrappers/kernel-debug/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-kernel-debug-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | redshirt-syscalls = { path = "../syscalls", default-features = false } 10 | -------------------------------------------------------------------------------- /interface-wrappers/kernel-debug/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Gathering kernel metrics. 17 | //! 18 | //! This interface provides a way to gather information from the kernel. In particular, the kernel 19 | //! returns [Prometheus](https://prometheus.io) metrics. 20 | //! 21 | //! # Message format 22 | //! 23 | //! - Sender sends a message with an empty body. 24 | //! - Handler sends back a Prometheus-compatible UTF-8 message. 25 | //! 26 | //! See [this page](https://prometheus.io/docs/instrumenting/exposition_formats/#text-format-details) 27 | //! for more information about the format. 28 | //! 29 | 30 | #![no_std] 31 | 32 | extern crate alloc; 33 | 34 | use alloc::{string::String, vec::Vec}; 35 | use redshirt_syscalls::InterfaceHash; 36 | 37 | // TODO: this has been randomly generated; instead should be a hash or something 38 | pub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([ 39 | 0x8c, 0xb4, 0xc6, 0xee, 0xc9, 0x29, 0xc5, 0xce, 0xaf, 0x46, 0x28, 0x74, 0x9e, 0x96, 0x72, 0x58, 40 | 0xea, 0xd2, 0xa2, 0xa2, 0xd6, 0xeb, 0x7d, 0xc8, 0xe3, 0x95, 0x0c, 0x0e, 0x53, 0xde, 0x8c, 0xba, 41 | ]); 42 | 43 | /// Loads metrics from the kernel, as a Prometheus-compatible UTF-8 string. 44 | pub async fn get_prometheus_metrics() -> String { 45 | unsafe { 46 | let response: redshirt_syscalls::EncodedMessage = 47 | redshirt_syscalls::emit_message_with_response( 48 | &INTERFACE, 49 | redshirt_syscalls::EncodedMessage(Vec::new()), 50 | ) 51 | .unwrap() 52 | .await; 53 | 54 | String::from_utf8(response.0).unwrap() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /interface-wrappers/kernel-log/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-kernel-log-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | parity-scale-codec = { version = "1.3.6", default-features = false, features = ["derive"] } 10 | redshirt-syscalls = { path = "../syscalls", default-features = false } 11 | -------------------------------------------------------------------------------- /interface-wrappers/kernel-log/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Kernel logging. 17 | //! 18 | //! This interface permits two things: 19 | //! 20 | //! - Send logs for the kernel to print. 21 | //! - Configure how the kernel prints logs. 22 | //! 23 | //! It is important for programs such as video drivers to keep the kernel up-to-date with how 24 | //! logs should be displayed. In the case of a kernel panic, the kernel will use the information 25 | //! contained in the latest received message in order to show diagnostics to the user. 26 | 27 | #![no_std] 28 | 29 | extern crate alloc; 30 | 31 | use parity_scale_codec::Encode as _; 32 | 33 | pub mod ffi; 34 | pub use ffi::KernelLogMethod; 35 | 36 | /// Appends a single ASCII string to the kernel logs. 37 | /// 38 | /// This function always adds a single entry to the logs. An entry can made up of multiple lines 39 | /// (separated with `\n`), but the lines are notably *not* split into multiple entries. 40 | /// 41 | /// > **Note**: The message is expected to be in ASCII. It will otherwise be considered invalid 42 | /// > and get discarded. 43 | /// 44 | /// # About `\r` vs `\n` 45 | /// 46 | /// In order to follow the Unix world, the character `\n` (LF, 0xA) means "new line". The 47 | /// character `\r` (CR, 0xD) is ignored. 48 | /// 49 | pub fn log(msg: &[u8]) { 50 | unsafe { 51 | redshirt_syscalls::MessageBuilder::new() 52 | .add_data_raw(&[0][..]) 53 | .add_data_raw(msg) 54 | .emit_without_response(&ffi::INTERFACE) 55 | .unwrap(); 56 | } 57 | } 58 | 59 | /// Sets how the kernel should log messages. 60 | pub async fn configure_kernel(method: KernelLogMethod) { 61 | unsafe { 62 | let encoded = method.encode(); 63 | redshirt_syscalls::MessageBuilder::new() 64 | .add_data_raw(&[1][..]) 65 | .add_data_raw(&encoded) 66 | .emit_with_response::<()>(&ffi::INTERFACE) 67 | .unwrap() 68 | .await; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /interface-wrappers/loader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-loader-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = { version = "0.3.13", default-features = false } 10 | redshirt-syscalls = { path = "../syscalls", default-features = false } 11 | parity-scale-codec = { version = "1.3.6", default-features = false, features = ["derive"] } 12 | -------------------------------------------------------------------------------- /interface-wrappers/loader/src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use alloc::vec::Vec; 17 | use parity_scale_codec::{Decode, Encode}; 18 | use redshirt_syscalls::InterfaceHash; 19 | 20 | // TODO: this has been randomly generated; instead should be a hash or something 21 | pub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([ 22 | 0x1c, 0x72, 0xb5, 0x18, 0x7f, 0x73, 0x52, 0xfd, 0xf7, 0xa7, 0x81, 0xe2, 0xa8, 0x46, 0x51, 0xd7, 23 | 0xb3, 0xc6, 0x2d, 0x24, 0x31, 0x88, 0x96, 0x95, 0x6e, 0xfc, 0x7d, 0x4d, 0x86, 0x3f, 0xff, 0xa6, 24 | ]); 25 | 26 | #[derive(Debug, Encode, Decode)] 27 | pub enum LoaderMessage { 28 | /// Load the data corresponding to the blake3 hash passed as parameter. 29 | Load([u8; 32]), 30 | } 31 | 32 | #[derive(Debug, Encode, Decode)] 33 | pub struct LoadResponse { 34 | pub result: Result, ()>, 35 | } 36 | -------------------------------------------------------------------------------- /interface-wrappers/loader/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Loading WASM programs. 17 | //! 18 | //! This interface is a bit special, as it is used by the kernel in order to load WASM programs. 19 | 20 | #![no_std] 21 | 22 | extern crate alloc; 23 | 24 | use alloc::vec::Vec; 25 | use futures::prelude::*; 26 | 27 | pub mod ffi; 28 | 29 | /// Tries to load a WASM module based on its hash. 30 | /// 31 | /// Returns either the binary content of the module, or an error if no module with that hash 32 | /// could be found. 33 | // TODO: better error type 34 | pub fn load(hash: [u8; 32]) -> impl Future, ()>> { 35 | unsafe { 36 | let msg = ffi::LoaderMessage::Load(hash); 37 | match redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg) { 38 | Ok(fut) => fut.map(|rep: ffi::LoadResponse| rep.result).left_future(), 39 | Err(_) => future::ready(Err(())).right_future(), 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /interface-wrappers/log/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-log-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | log = "0.4.14" 10 | redshirt-syscalls = { path = "../syscalls", default-features = false } 11 | -------------------------------------------------------------------------------- /interface-wrappers/log/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Logging. 17 | //! 18 | //! This interface allows a program to send out messages for the purpose of being logged. 19 | //! 20 | //! How these logs are handled is at the discretion of the rest of the system, but the intent is 21 | //! for them to be shown to a human being if desired. 22 | //! 23 | //! # The `log` crate 24 | //! 25 | //! This interface provides a backend for the `log` crate. 26 | //! 27 | //! Example usage: 28 | //! 29 | //! ```no_run 30 | //! redshirt_log_interface::init(); 31 | //! log::debug!("debug log message here"); 32 | //! ``` 33 | 34 | #![no_std] 35 | 36 | extern crate alloc; 37 | 38 | use alloc::format; 39 | 40 | pub mod ffi; 41 | 42 | pub use ffi::Level; 43 | pub use log; 44 | 45 | /// Appends a single string to the logs of the program. 46 | /// 47 | /// This function always adds a single entry to the logs. An entry can made up of multiple lines 48 | /// (separated with `\n`), but the lines are notably *not* split into multiple entries. 49 | /// 50 | /// # About `\r` vs `\n` 51 | /// 52 | /// In order to follow the Unix world, the character `\n` (LF, 0xA) means "new line". The 53 | /// character `\r` (CR, 0xD) is ignored. 54 | /// 55 | pub fn emit_log(level: Level, msg: &str) { 56 | unsafe { 57 | let level: [u8; 1] = [u8::from(level)]; 58 | redshirt_syscalls::MessageBuilder::new() 59 | .add_data_raw(&level[..]) 60 | .add_data_raw(msg.as_bytes()) 61 | .emit_without_response(&ffi::INTERFACE) 62 | .unwrap(); 63 | } 64 | } 65 | 66 | /// Attempts to initializes the global logger. 67 | /// 68 | /// # Panic 69 | /// 70 | /// This function will panic if it is called more than once, or if another library has already 71 | /// initialized a global logger. 72 | pub fn try_init() -> Result<(), log::SetLoggerError> { 73 | static LOGGER: GlobalLogger = GlobalLogger; 74 | let res = log::set_logger(&LOGGER); 75 | if res.is_ok() { 76 | log::set_max_level(log::LevelFilter::Trace); 77 | } 78 | res 79 | } 80 | 81 | /// Initializes the global logger. 82 | /// 83 | /// # Panic 84 | /// 85 | /// This function will panic if it is called more than once, or if another library has already 86 | /// initialized a global logger. 87 | pub fn init() { 88 | try_init().unwrap(); 89 | } 90 | 91 | /// The logger. 92 | /// 93 | /// Implements the [`Log`](log::Log) trait. 94 | pub struct GlobalLogger; 95 | 96 | impl log::Log for GlobalLogger { 97 | fn enabled(&self, _: &log::Metadata) -> bool { 98 | true 99 | } 100 | 101 | fn log(&self, record: &log::Record) { 102 | let level = match record.level() { 103 | log::Level::Error => Level::Error, 104 | log::Level::Warn => Level::Warn, 105 | log::Level::Info => Level::Info, 106 | log::Level::Debug => Level::Debug, 107 | log::Level::Trace => Level::Trace, 108 | }; 109 | 110 | let message = format!("{} -- {}", record.target(), record.args()); 111 | emit_log(level, &message) 112 | } 113 | 114 | fn flush(&self) {} 115 | } 116 | -------------------------------------------------------------------------------- /interface-wrappers/pci/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-pci-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = { version = "0.3.13", default-features = false } 10 | redshirt-syscalls = { path = "../syscalls", default-features = false } 11 | parity-scale-codec = { version = "1.3.6", default-features = false, features = ["derive"] } 12 | -------------------------------------------------------------------------------- /interface-wrappers/random/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-random-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | redshirt-syscalls = { path = "../syscalls", default-features = false } 10 | parity-scale-codec = { version = "1.3.6", default-features = false, features = ["derive"] } 11 | 12 | [features] 13 | default = ["std"] 14 | std = [] 15 | -------------------------------------------------------------------------------- /interface-wrappers/random/src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use alloc::vec::Vec; 17 | use parity_scale_codec::{Decode, Encode}; 18 | use redshirt_syscalls::InterfaceHash; 19 | 20 | // TODO: this has been randomly generated; instead should be a hash or something 21 | pub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([ 22 | 0xfb, 0x83, 0xa5, 0x46, 0xfd, 0xf1, 0x50, 0x7a, 0xef, 0x8c, 0xb6, 0x8f, 0xa5, 0x44, 0x49, 0x21, 23 | 0x53, 0xe5, 0x83, 0xda, 0xf0, 0x66, 0xbc, 0x1a, 0xd2, 0x18, 0xfd, 0x00, 0x54, 0x7f, 0xdb, 0x25, 24 | ]); 25 | 26 | #[derive(Debug, Encode, Decode)] 27 | pub enum RandomMessage { 28 | /// Ask to generate cryptographically-secure list of random numbers of the given length. 29 | /// 30 | /// The length is a `u16`, so the maximum size is 64kiB and there's no need to handle potential 31 | /// errors about the length being too long to fit in memory. Call multiple times to obtain 32 | /// more. 33 | Generate { len: u16 }, 34 | } 35 | 36 | #[derive(Debug, Encode, Decode)] 37 | pub struct GenerateResponse { 38 | /// Random bytes. Must be of the requested length. 39 | pub result: Vec, 40 | } 41 | -------------------------------------------------------------------------------- /interface-wrappers/random/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Generating cryptographically-secure random data. 17 | 18 | #![cfg_attr(not(feature = "std"), no_std)] 19 | 20 | extern crate alloc; 21 | 22 | use alloc::vec::Vec; 23 | use core::convert::TryFrom as _; 24 | 25 | pub mod ffi; 26 | 27 | /// Generate `len` bytes of random data and returns them. 28 | pub async fn generate(len: usize) -> Vec { 29 | unsafe { 30 | let mut out = Vec::with_capacity(len); 31 | out.set_len(len); 32 | generate_in(&mut out).await; 33 | out 34 | } 35 | } 36 | 37 | /// Fills `out` with randomly-generated data. 38 | pub async fn generate_in(out: &mut [u8]) { 39 | for chunk in out.chunks_mut(usize::from(u16::max_value())) { 40 | let msg = ffi::RandomMessage::Generate { 41 | len: u16::try_from(chunk.len()).unwrap(), 42 | }; 43 | let rep: ffi::GenerateResponse = unsafe { 44 | redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg) 45 | .unwrap() 46 | .await 47 | }; 48 | chunk.copy_from_slice(&rep.result); 49 | } 50 | } 51 | 52 | /// Generates a random `u8`. 53 | pub async fn generate_u8() -> u8 { 54 | let mut buf = [0; 1]; 55 | generate_in(&mut buf).await; 56 | buf[0] 57 | } 58 | 59 | /// Generates a random `u16`. 60 | pub async fn generate_u16() -> u16 { 61 | let mut buf = [0; 2]; 62 | generate_in(&mut buf).await; 63 | u16::from_ne_bytes(buf) 64 | } 65 | 66 | /// Generates a random `u32`. 67 | pub async fn generate_u32() -> u32 { 68 | let mut buf = [0; 4]; 69 | generate_in(&mut buf).await; 70 | u32::from_ne_bytes(buf) 71 | } 72 | 73 | /// Generates a random `u64`. 74 | pub async fn generate_u64() -> u64 { 75 | let mut buf = [0; 8]; 76 | generate_in(&mut buf).await; 77 | u64::from_ne_bytes(buf) 78 | } 79 | 80 | /// Generates a random `u128`. 81 | pub async fn generate_u128() -> u128 { 82 | let mut buf = [0; 16]; 83 | generate_in(&mut buf).await; 84 | u128::from_ne_bytes(buf) 85 | } 86 | -------------------------------------------------------------------------------- /interface-wrappers/syscalls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-syscalls" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = { version = "0.3.13", default-features = false, features = ["alloc"] } 10 | generic-array = { version = "0.14.4", default-features = false } 11 | hashbrown = { version = "0.9.1", default-features = false } 12 | lazy_static = { version = "1.4.0", features = ["spin_no_std"] } 13 | nohash-hasher = { version = "0.2.0", default-features = false } 14 | parity-scale-codec = { version = "1.3.6", default-features = false, features = ["derive"] } 15 | pin-project = "1.0.5" 16 | slab = { version = "0.4.9", default-features = false } 17 | spinning_top = "0.2.2" 18 | -------------------------------------------------------------------------------- /interface-wrappers/syscalls/src/traits.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use alloc::vec::Vec; 17 | use core::fmt; 18 | 19 | /// Message already encoded. 20 | /// 21 | /// The [`Encode`] and [`Decode`] trait implementations are no-op. 22 | // TODO: make field private 23 | #[derive(Clone, PartialEq, Eq)] 24 | pub struct EncodedMessage(pub Vec); 25 | 26 | /// Objects that represent messages that can be serialized in order to be sent on an interface. 27 | pub trait Encode { 28 | /// Turn the object into bytes ready to be transmitted. 29 | fn encode(self) -> EncodedMessage; 30 | } 31 | 32 | /// Objects that represent messages that can be unserialized. 33 | pub trait Decode { 34 | type Error: fmt::Debug; 35 | 36 | /// Decode the raw data passed as parameter. 37 | // TODO: consider EncodedMessageRef? 38 | fn decode(buffer: EncodedMessage) -> Result 39 | where 40 | Self: Sized; 41 | } 42 | 43 | impl EncodedMessage { 44 | pub fn decode(self) -> Result { 45 | T::decode(self) 46 | } 47 | } 48 | 49 | impl Encode for EncodedMessage { 50 | fn encode(self) -> EncodedMessage { 51 | self 52 | } 53 | } 54 | 55 | impl Encode for T 56 | where 57 | T: parity_scale_codec::Encode, 58 | { 59 | fn encode(self) -> EncodedMessage { 60 | EncodedMessage(parity_scale_codec::Encode::encode(&self)) 61 | } 62 | } 63 | 64 | impl Decode for EncodedMessage { 65 | type Error = core::convert::Infallible; // TODO: `!` 66 | 67 | fn decode(buffer: EncodedMessage) -> Result { 68 | Ok(buffer) 69 | } 70 | } 71 | 72 | impl Decode for T 73 | where 74 | T: parity_scale_codec::DecodeAll, 75 | { 76 | type Error = (); 77 | 78 | fn decode(buffer: EncodedMessage) -> Result { 79 | parity_scale_codec::DecodeAll::decode_all(&buffer.0).map_err(|_| ()) 80 | } 81 | } 82 | 83 | impl<'a> From> for EncodedMessage { 84 | fn from(msg: EncodedMessageRef<'a>) -> Self { 85 | EncodedMessage(msg.0.into()) 86 | } 87 | } 88 | 89 | impl AsRef<[u8]> for EncodedMessage { 90 | fn as_ref(&self) -> &[u8] { 91 | &self.0 92 | } 93 | } 94 | 95 | impl fmt::Debug for EncodedMessage { 96 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 97 | fmt::Debug::fmt(&self.0, f) 98 | } 99 | } 100 | 101 | /// Reference to an [`EncodedMessage`]. 102 | #[derive(Copy, Clone, PartialEq, Eq)] 103 | pub struct EncodedMessageRef<'a>(&'a [u8]); 104 | 105 | impl<'a> From<&'a [u8]> for EncodedMessageRef<'a> { 106 | fn from(buf: &'a [u8]) -> EncodedMessageRef<'a> { 107 | EncodedMessageRef(buf) 108 | } 109 | } 110 | 111 | impl<'a> AsRef<[u8]> for EncodedMessageRef<'a> { 112 | fn as_ref(&self) -> &[u8] { 113 | self.0 114 | } 115 | } 116 | 117 | impl<'a> From<&'a EncodedMessage> for EncodedMessageRef<'a> { 118 | fn from(msg: &'a EncodedMessage) -> Self { 119 | EncodedMessageRef(&msg.0) 120 | } 121 | } 122 | 123 | impl<'a> fmt::Debug for EncodedMessageRef<'a> { 124 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 125 | fmt::Debug::fmt(&self.0, f) 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /interface-wrappers/system-time/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-system-time-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = { version = "0.3.13", default-features = false, features = ["alloc"] } 10 | redshirt-syscalls = { path = "../syscalls", default-features = false } 11 | parity-scale-codec = { version = "1.3.6", default-features = false, features = ["derive"] } 12 | pin-project = "1.0.5" 13 | -------------------------------------------------------------------------------- /interface-wrappers/system-time/src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use parity_scale_codec::{Decode, Encode}; 17 | use redshirt_syscalls::InterfaceHash; 18 | 19 | // TODO: this has been randomly generated; instead should be a hash or something 20 | pub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([ 21 | 0xc2, 0xf9, 0xf8, 0xc5, 0xd5, 0xcb, 0x84, 0xb5, 0xc5, 0xfe, 0x34, 0x1d, 0x21, 0xb2, 0xc3, 0x6f, 22 | 0xed, 0xfb, 0x86, 0xd1, 0xdb, 0xd6, 0x76, 0x41, 0x07, 0x02, 0x49, 0xeb, 0xfe, 0x1b, 0xa7, 0xc4, 23 | ]); 24 | 25 | #[derive(Debug, Encode, Decode)] 26 | pub enum TimeMessage { 27 | /// Must respond with a `u128`. 28 | GetSystem, 29 | } 30 | -------------------------------------------------------------------------------- /interface-wrappers/system-time/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Time. 17 | 18 | #![no_std] 19 | 20 | extern crate alloc; 21 | 22 | use futures::prelude::*; 23 | 24 | pub mod ffi; 25 | 26 | /// Returns the number of nanoseconds since the Epoch (January 1st, 1970 at midnight UTC). 27 | pub fn system_clock() -> impl Future { 28 | unsafe { 29 | let msg = ffi::TimeMessage::GetSystem; 30 | redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg).unwrap() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /interface-wrappers/tcp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-tcp-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | derive_more = "0.99.11" 10 | futures = "0.3.13" 11 | redshirt-syscalls = { path = "../syscalls" } 12 | parity-scale-codec = { version = "1.3.6", features = ["derive"] } 13 | tokio = { version = "1.2.0", default-features = false } 14 | -------------------------------------------------------------------------------- /interface-wrappers/time/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-time-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = { version = "0.3.13", default-features = false, features = ["alloc"] } 10 | redshirt-syscalls = { path = "../syscalls", default-features = false } 11 | parity-scale-codec = { version = "1.3.6", default-features = false, features = ["derive"] } 12 | pin-project = "1.0.5" 13 | -------------------------------------------------------------------------------- /interface-wrappers/time/src/delay.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use crate::{monotonic_wait_until, Instant}; 17 | use alloc::boxed::Box; 18 | use core::{fmt, future::Future, pin::Pin, task::Context, task::Poll, time::Duration}; 19 | 20 | /// Mimics the API of `futures_timer::Delay`. 21 | pub struct Delay { 22 | when: Instant, 23 | inner: Pin + Send>>, 24 | } 25 | 26 | impl Delay { 27 | pub fn new(dur: Duration) -> Delay { 28 | Delay::new_at(Instant::now() + dur) 29 | } 30 | 31 | pub fn new_at(at: Instant) -> Delay { 32 | Delay { 33 | when: at, 34 | inner: Box::pin(monotonic_wait_until(at.inner)), 35 | } 36 | } 37 | 38 | pub fn when(&self) -> Instant { 39 | self.when 40 | } 41 | 42 | pub fn reset(&mut self, at: Instant) { 43 | *self = Delay::new_at(at); 44 | } 45 | } 46 | 47 | impl fmt::Debug for Delay { 48 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 49 | f.debug_struct("Delay").field("when", &self.when).finish() 50 | } 51 | } 52 | 53 | impl Future for Delay { 54 | type Output = (); 55 | 56 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { 57 | Future::poll(self.inner.as_mut(), cx) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /interface-wrappers/time/src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use parity_scale_codec::{Decode, Encode}; 17 | use redshirt_syscalls::InterfaceHash; 18 | 19 | // TODO: this has been randomly generated; instead should be a hash or something 20 | pub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([ 21 | 0x19, 0x97, 0x70, 0x2f, 0x6f, 0xd9, 0x52, 0xcd, 0xb2, 0xc3, 0x75, 0x1c, 0x11, 0xb4, 0x95, 0x41, 22 | 0x81, 0xa6, 0x4f, 0x91, 0x67, 0x63, 0xb5, 0xb1, 0x8d, 0x31, 0xdf, 0xb1, 0x47, 0x03, 0xa6, 0xbf, 23 | ]); 24 | 25 | #[derive(Debug, Encode, Decode)] 26 | pub enum TimeMessage { 27 | /// Must respond with a `u128`. 28 | GetMonotonic, 29 | /// Send response when the monotonic clock reaches this value. Responds with nothing (`()`). 30 | WaitMonotonic(u128), 31 | } 32 | -------------------------------------------------------------------------------- /interface-wrappers/time/src/instant.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use crate::monotonic_clock; 17 | use core::{convert::TryFrom, ops::Add, ops::Sub, time::Duration}; 18 | 19 | /// Mimics the API of `std::time::Instant`, except that it works. 20 | /// 21 | /// > **Note**: This struct should be removed in the future, as `std::time::Instant` should work 22 | /// > when compiling to WASI. 23 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 24 | pub struct Instant { 25 | pub(crate) inner: u128, 26 | } 27 | 28 | impl Instant { 29 | pub fn now() -> Instant { 30 | let val = redshirt_syscalls::block_on(monotonic_clock()); 31 | Instant { inner: val } 32 | } 33 | 34 | pub fn duration_since(&self, earlier: Instant) -> Duration { 35 | *self - earlier 36 | } 37 | 38 | pub fn elapsed(&self) -> Duration { 39 | Instant::now() - *self 40 | } 41 | } 42 | 43 | impl Add for Instant { 44 | type Output = Instant; 45 | 46 | fn add(self, other: Duration) -> Instant { 47 | let new_val = self.inner + other.as_nanos(); 48 | Instant { inner: new_val } 49 | } 50 | } 51 | 52 | impl Sub for Instant { 53 | type Output = Instant; 54 | 55 | fn sub(self, other: Duration) -> Instant { 56 | let new_val = self.inner - other.as_nanos(); 57 | Instant { inner: new_val } 58 | } 59 | } 60 | 61 | impl Sub for Instant { 62 | type Output = Duration; 63 | 64 | fn sub(self, other: Instant) -> Duration { 65 | let ns = self.inner - other.inner; 66 | // TODO: not great to unwrap, but we don't care 67 | Duration::from_nanos(u64::try_from(ns).unwrap()) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /interface-wrappers/time/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Time. 17 | 18 | #![no_std] 19 | 20 | extern crate alloc; 21 | 22 | use core::time::Duration; 23 | use futures::prelude::*; 24 | 25 | pub use self::delay::Delay; 26 | pub use self::instant::Instant; 27 | 28 | mod delay; 29 | mod instant; 30 | 31 | pub mod ffi; 32 | 33 | /// Returns the number of nanoseconds since an arbitrary point in time in the past. 34 | pub fn monotonic_clock() -> impl Future { 35 | unsafe { 36 | let msg = ffi::TimeMessage::GetMonotonic; 37 | redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg).unwrap() 38 | } 39 | } 40 | 41 | /// Returns a `Future` that yields when the monotonic clock reaches this value. 42 | pub fn monotonic_wait_until(until: u128) -> impl Future { 43 | unsafe { 44 | let msg = ffi::TimeMessage::WaitMonotonic(until); 45 | redshirt_syscalls::emit_message_with_response(&ffi::INTERFACE, msg).unwrap() 46 | } 47 | } 48 | 49 | /// Returns a `Future` that outputs after `duration` has elapsed. 50 | pub fn monotonic_wait(duration: Duration) -> impl Future { 51 | let dur_nanos = u128::from(duration.as_secs()) 52 | .saturating_mul(1_000_000_000) 53 | .saturating_add(u128::from(duration.subsec_nanos())); 54 | 55 | // TODO: meh for two syscalls 56 | monotonic_clock().then(move |now| monotonic_wait_until(now.saturating_add(dur_nanos))) 57 | } 58 | -------------------------------------------------------------------------------- /interface-wrappers/video-output/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-video-output-interface" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | futures = "0.3.13" 10 | redshirt-random-interface = { path = "../random" } 11 | redshirt-syscalls = { path = "../syscalls" } 12 | parity-scale-codec = { version = "1.3.6", features = ["derive"] } 13 | -------------------------------------------------------------------------------- /interface-wrappers/video-output/src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use parity_scale_codec::{Decode, Encode}; 17 | use redshirt_syscalls::InterfaceHash; 18 | 19 | // TODO: this has been randomly generated; instead should be a hash or something 20 | pub const INTERFACE: InterfaceHash = InterfaceHash::from_raw_hash([ 21 | 0x87, 0x9d, 0xe0, 0xda, 0x61, 0x13, 0x26, 0x1d, 0x1f, 0x3e, 0xfa, 0x79, 0x4c, 0x9e, 0xa4, 0x67, 22 | 0xf2, 0x81, 0xe8, 0x00, 0x39, 0x5e, 0xbe, 0x94, 0x1e, 0x49, 0xb8, 0xf8, 0xd4, 0x3b, 0x07, 0xce, 23 | ]); 24 | 25 | #[derive(Debug, Encode, Decode)] 26 | pub enum VideoOutputMessage { 27 | /// Notify of the existence of a new video output. 28 | // TODO: what if this id was already registered? 29 | Register { 30 | /// Unique per-process identifier. 31 | id: u64, 32 | /// Width in pixels of the output. 33 | width: u32, 34 | /// Height in pixels of the output. 35 | height: u32, 36 | /// Expected format of the output. 37 | format: Format, 38 | }, 39 | 40 | /// Removes a previously-registered video output. 41 | Unregister(u64), 42 | 43 | /// Asks for the next image to present on this output. Must answer with a `NextImage`. 44 | NextImage(u64), 45 | } 46 | 47 | #[derive(Debug, Encode, Decode, Clone)] 48 | pub struct NextImage { 49 | pub changes: Vec, 50 | } 51 | 52 | #[derive(Debug, Encode, Decode, Clone)] 53 | pub struct NextImageChange { 54 | pub screen_x_start: u32, 55 | // TODO: not necessary? 56 | pub screen_x_len: u32, 57 | pub screen_y_start: u32, 58 | /// Rows of pixels. 59 | pub pixels: Vec>, 60 | } 61 | 62 | #[derive(Debug, Encode, Decode, Clone)] 63 | pub enum Format { 64 | R8G8B8X8, 65 | } 66 | -------------------------------------------------------------------------------- /interface-wrappers/video-output/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Video output interface. 17 | //! 18 | //! This interface serves to register devices capable of presenting an image to the user. Usually 19 | //! a monitor. 20 | //! 21 | //! This interface is extremely naive at the moment. In the future, it should include: 22 | //! 23 | //! - Giving the list of supported video modes, and allowing changing the video mode of the output. 24 | //! - Generic graphics rendering. One would register graphics accelerators, connected to 0 or more 25 | //! monitors. 26 | //! - Still registering devices in "linear framebuffer mode", for compatibility with VGA/VBE on PC, 27 | //! or more primitive hardware on embedded devices. 28 | //! 29 | //! The main inspiration for designing "graphics commands" should be Vulkan and WebGPU. 30 | //! 31 | 32 | pub mod ffi; 33 | pub mod video_output; 34 | -------------------------------------------------------------------------------- /kernel-standalone-builder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-standalone-builder" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | build = "build.rs" 9 | 10 | [workspace] 11 | 12 | [dependencies] 13 | fatfs = "0.3.5" 14 | fscommon = "0.1.1" 15 | futures = "0.3.21" 16 | futures-timer = "3.0.2" 17 | cargo_metadata = "0.12" 18 | mbrman = "0.4.0" 19 | serde_json = "1.0.79" 20 | structopt = "0.3.26" 21 | tempdir = "0.3.7" 22 | thiserror = "1.0" 23 | toml = "0.5.8" 24 | walkdir = "2.3.2" 25 | 26 | [build-dependencies] 27 | cc = "1.2.16" 28 | 29 | [profile.dev] 30 | opt-level = 1 31 | 32 | [profile.dev.package."*"] 33 | opt-level = 3 34 | 35 | [profile.test.package."*"] 36 | opt-level = 3 37 | -------------------------------------------------------------------------------- /kernel-standalone-builder/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | fn main() { 17 | println!("cargo::rerun-if-changed=simpleboot"); 18 | cc::Build::new() 19 | .file("simpleboot/wrapper.c") 20 | .compile("simpleboot"); 21 | } 22 | -------------------------------------------------------------------------------- /kernel-standalone-builder/res/rpi-firmware/boot/LICENCE.broadcom: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006, Broadcom Corporation. 2 | Copyright (c) 2015, Raspberry Pi (Trading) Ltd 3 | All rights reserved. 4 | 5 | Redistribution. Redistribution and use in binary form, without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * This software may only be used for the purposes of developing for, 10 | running or using a Raspberry Pi device, or authorised derivative 11 | device manufactured via the element14 Raspberry Pi Customization Service 12 | * Redistributions must reproduce the above copyright notice and the 13 | following disclaimer in the documentation and/or other materials 14 | provided with the distribution. 15 | * Neither the name of Broadcom Corporation nor the names of its suppliers 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 20 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 21 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 26 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 28 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 29 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 30 | DAMAGE. 31 | 32 | -------------------------------------------------------------------------------- /kernel-standalone-builder/res/rpi-firmware/boot/bcm2711-rpi-4-b.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/res/rpi-firmware/boot/bcm2711-rpi-4-b.dtb -------------------------------------------------------------------------------- /kernel-standalone-builder/res/rpi-firmware/boot/bootcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/res/rpi-firmware/boot/bootcode.bin -------------------------------------------------------------------------------- /kernel-standalone-builder/res/rpi-firmware/boot/fixup.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/res/rpi-firmware/boot/fixup.dat -------------------------------------------------------------------------------- /kernel-standalone-builder/res/rpi-firmware/boot/fixup4.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/res/rpi-firmware/boot/fixup4.dat -------------------------------------------------------------------------------- /kernel-standalone-builder/res/rpi-firmware/boot/start.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/res/rpi-firmware/boot/start.elf -------------------------------------------------------------------------------- /kernel-standalone-builder/res/rpi-firmware/boot/start4.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/res/rpi-firmware/boot/start4.elf -------------------------------------------------------------------------------- /kernel-standalone-builder/res/specs/aarch64-freestanding.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "aarch64", 3 | "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", 4 | "disable-redzone": true, 5 | "env": "", 6 | "executables": true, 7 | "features": "+strict-align,+neon,+fp-armv8", 8 | "linker": "rust-lld", 9 | "linker-flavor": "ld.lld", 10 | "linker-is-gnu": true, 11 | "llvm-target": "aarch64-unknown-none", 12 | "max-atomic-width": 128, 13 | "os": "none", 14 | "panic-strategy": "abort", 15 | "relocation-model": "static", 16 | "target-c-int-width": "32", 17 | "target-endian": "little", 18 | "target-pointer-width": "64", 19 | "unsupported-abis": [ 20 | "stdcall", 21 | "fastcall", 22 | "vectorcall", 23 | "thiscall", 24 | "win64", 25 | "sysv64" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /kernel-standalone-builder/res/specs/aarch64-freestanding.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_entry_point) 2 | 3 | SECTIONS { 4 | . = 0x80000; 5 | .text : AT(ADDR(.text)) { 6 | _entry_point = .; 7 | /* Same as above, jump to the address of `_start` */ 8 | /* TODO: this always fails, no clue why: ASSERT(((_start - 0x80000) >> 2) == ((_start >> 2) & 0x1FFFFFF), "_start too far away") */ 9 | LONG(0x14000000 | (((_start - 0x80000) >> 2) & 0x1FFFFFF)) 10 | 11 | *(.text*) 12 | *(.rodata*) 13 | } 14 | 15 | /* Garbage that the compiler seems to introduce for stack unwinding purposes */ 16 | .ARM.exidx : AT(ADDR(.ARM.exidx)) { 17 | *(.ARM.exidx*) 18 | *(.gnu.linkonce.armexidx.*) 19 | } 20 | 21 | .data : AT(ADDR(.data)) { 22 | *(.data*) 23 | } 24 | 25 | .bss : AT(ADDR(.bss)) ALIGN(8) { 26 | __bss_start = .; 27 | *(.bss*) 28 | *(COMMON*) 29 | __bss_end = .; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /kernel-standalone-builder/res/specs/arm-freestanding.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "arm", 3 | "data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", 4 | "emit-debug-gdb-scripts": false, 5 | "env": "", 6 | "executables": true, 7 | "features": "+armv7-a,-slowfpvmlx,-vfp2,-vfp3,-vfp4,+soft-float", 8 | "linker": "ld.lld", 9 | "linker-flavor": "ld", 10 | "lld-flavor": "link", 11 | "llvm-target": "armv7a-unknown-none-eabi", 12 | "max-atomic-width": 32, 13 | "os": "none", 14 | "panic-strategy": "abort", 15 | "relocation-model": "static", 16 | "target-c-int-width": "32", 17 | "target-endian": "little", 18 | "target-pointer-width": "32", 19 | "unsupported-abis": [ 20 | "stdcall", 21 | "fastcall", 22 | "vectorcall", 23 | "thiscall", 24 | "win64", 25 | "sysv64" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /kernel-standalone-builder/res/specs/arm-freestanding.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_entry_point) 2 | 3 | SECTIONS { 4 | . = 0x8000; 5 | .text : AT(ADDR(.text)) { 6 | _entry_point = .; 7 | /* Same as above, jump to the address of `_start` */ 8 | /* TODO: this always fails, no clue why: ASSERT((((_start - 0x8000) >> 2) - 2) == (((_start >> 2) - 2) & 0x1FFFFFF), "_start too far away") */ 9 | LONG(0xea000000 | ((((_start - 0x8000) >> 2) - 2) & 0x1FFFFFF)) 10 | 11 | *(.text*) 12 | *(.rodata*) 13 | } 14 | 15 | /* Garbage that the compiler seems to introduce for stack unwinding purposes */ 16 | .ARM.exidx : AT(ADDR(.ARM.exidx)) { 17 | *(.ARM.exidx*) 18 | *(.gnu.linkonce.armexidx.*) 19 | } 20 | 21 | .data : AT(ADDR(.data)) { 22 | *(.data*) 23 | } 24 | 25 | .bss : AT(ADDR(.bss)) ALIGN(8) { 26 | __bss_start = .; 27 | *(.bss*) 28 | *(COMMON*) 29 | __bss_end = .; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /kernel-standalone-builder/res/specs/riscv-hifive.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "riscv32", 3 | "cpu": "generic-rv32", 4 | "data-layout": "e-m:e-p:32:32-i64:64-n32-S128", 5 | "eliminate-frame-pointer": false, 6 | "emit-debug-gdb-scripts": false, 7 | "env": "", 8 | "executables": true, 9 | "features": "+m,+a,+c", 10 | "is-builtin": true, 11 | "linker": "rust-lld", 12 | "linker-flavor": "ld.lld", 13 | "llvm-target": "riscv32", 14 | "max-atomic-width": 32, 15 | "os": "none", 16 | "panic-strategy": "abort", 17 | "relocation-model": "static", 18 | "target-c-int-width": "32", 19 | "target-endian": "little", 20 | "target-pointer-width": "32", 21 | "unsupported-abis": [ 22 | "cdecl", 23 | "stdcall", 24 | "fastcall", 25 | "vectorcall", 26 | "thiscall", 27 | "aapcs", 28 | "win64", 29 | "sysv64", 30 | "ptx-kernel", 31 | "msp430-interrupt", 32 | "x86-interrupt", 33 | "amdgpu-kernel" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /kernel-standalone-builder/res/specs/riscv-hifive.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH("riscv") 2 | ENTRY(_entry_point) 3 | 4 | MEMORY { 5 | RAM : ORIGIN = 0x80000000, LENGTH = 16K 6 | FLASH : ORIGIN = 0x20400000, LENGTH = 512M 7 | } 8 | 9 | SECTIONS { 10 | .text : { 11 | . = 0x20400000; 12 | _entry_point = .; 13 | 14 | /* Jump to the address of `_start` */ 15 | ASSERT((_start - 0x20400000) < (1 << 21), "_start too far away") 16 | LONG( 17 | 0x6f | 18 | ((((_start - 0x20400000) >> 12) & 0xff) << 12) | 19 | ((((_start - 0x20400000) >> 11) & 0x1) << 20) | 20 | ((((_start - 0x20400000) >> 1) & 0x3ff) << 21) | 21 | ((((_start - 0x20400000) >> 20) & 0x1) << 31) 22 | ) 23 | 24 | *(.text) 25 | *(.text.*) 26 | *(.rodata) 27 | *(.rodata.*) 28 | *(.sdata) 29 | *(.sdata.*) 30 | } > FLASH 31 | 32 | .data : { 33 | *(.data) 34 | *(.data.*) 35 | } > RAM AT > FLASH 36 | 37 | .bss : { 38 | __bss_start = .; 39 | *(.bss) 40 | *(.bss.*) 41 | *(COMMON) 42 | __bss_end = .; 43 | } > RAM 44 | 45 | /DISCARD/ : { 46 | *(.eh_frame); 47 | *(.eh_frame_hdr); 48 | *(.comment); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /kernel-standalone-builder/res/specs/x86_64-multiboot2.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "x86_64", 3 | "code-model": "kernel", 4 | "cpu": "x86-64", 5 | "crt-objects-fallback": "false", 6 | "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", 7 | "disable-redzone": true, 8 | "eliminate-frame-pointer": true, 9 | "executables": true, 10 | "features": "+mmx,+sse,+sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-soft-float", 11 | "linker": "rust-lld", 12 | "linker-flavor": "gnu-lld", 13 | "lld-flavor": "link", 14 | "llvm-target": "x86_64-unknown-none-elf", 15 | "max-atomic-width": 64, 16 | "os": "none", 17 | "panic-strategy": "abort", 18 | "plt-by-default": false, 19 | "position-independent-executables": true, 20 | "relocation-model": "static", 21 | "singlethread": false, 22 | "stack-probes": { 23 | "kind": "inline" 24 | }, 25 | "target-c-int-width": "32", 26 | "target-endian": "little", 27 | "target-pointer-width": "64" 28 | } 29 | -------------------------------------------------------------------------------- /kernel-standalone-builder/res/specs/x86_64-multiboot2.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64") 2 | OUTPUT_ARCH("i386:x86-64") 3 | ENTRY(_start) 4 | 5 | MULTIBOOT2_MAGIC = 0xe85250d6; 6 | MULTIBOOT2_ARCH = 0; 7 | MULTIBOOT2_HEADER_LEN = mboot_end - mboot_start; 8 | MULTIBOOT2_CHECKSUM = -(MULTIBOOT2_MAGIC + MULTIBOOT2_ARCH + MULTIBOOT2_HEADER_LEN); 9 | 10 | SECTIONS { 11 | . = 4M; 12 | 13 | .mboot ALIGN(4) : AT(ADDR(.mboot)) { 14 | mboot_start = .; 15 | 16 | LONG(MULTIBOOT2_MAGIC) 17 | LONG(MULTIBOOT2_ARCH) 18 | LONG(MULTIBOOT2_HEADER_LEN) 19 | LONG(MULTIBOOT2_CHECKSUM) 20 | 21 | /* Flags tag, indicating that we support graphics */ 22 | . = ALIGN(8); 23 | SHORT(4) 24 | SHORT(1) /* flags = 1 means this tag can be ignored if not supported */ 25 | LONG(12) 26 | LONG(1) /* 0 = text, 1 = graphics 27 | 28 | /* Framebuffer tag, indicating the preferred graphics mode */ 29 | . = ALIGN(8); 30 | SHORT(5) 31 | SHORT(1) /* flags = 1 means this tag can be ignored if not supported */ 32 | LONG(20) 33 | LONG(1024) /* width */ 34 | LONG(768) /* height */ 35 | LONG(32) /* depth */ 36 | 37 | /* end of tags */ 38 | . = ALIGN(8); 39 | SHORT(0) 40 | SHORT(0) 41 | LONG(8) 42 | 43 | mboot_end = .; 44 | } 45 | 46 | .text ALIGN(4096) : AT(ADDR(.text)) { 47 | *(.text) 48 | *(.text.*) 49 | } 50 | 51 | .rodata ALIGN(4096) : AT(ADDR(.rodata)) { 52 | *(.rodata) 53 | *(.rodata.*) 54 | } 55 | 56 | .data ALIGN(4096) : AT(ADDR(.data)) { 57 | *(.data) 58 | *(.data.*) 59 | } 60 | 61 | .bss ALIGN(4096) : AT(ADDR(.bss)) { 62 | __bss_start = .; 63 | *(.bss) 64 | *(.bss.*) 65 | *(COMMON) 66 | __bss_end = .; 67 | } 68 | 69 | /DISCARD/ : { 70 | *(.eh_frame) 71 | *(.debug_*) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/README.md: -------------------------------------------------------------------------------- 1 | The `simpleboot` directory contains a copy of , 2 | except that the `main` function has been renamed to `simpleboot_main` in order to 3 | make it usable as a library. 4 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.img 3 | *.bin 4 | *.rom 5 | *.efi 6 | *.elf 7 | example/boot 8 | example/mnt 9 | src/simpleboot 10 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/Kconfig: -------------------------------------------------------------------------------- 1 | if PAYLOAD_SIMPLEBOOT 2 | 3 | config PAYLOAD_FILE 4 | default "payloads/external/simpleboot/src/loader_cb.elf" 5 | 6 | endif 7 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/Kconfig.name: -------------------------------------------------------------------------------- 1 | config PAYLOAD_SIMPLEBOOT 2 | bool "Simpleboot" 3 | depends on ARCH_X86 || ARCH_ARM64 4 | select WANT_LINEAR_FRAMEBUFFER 5 | select COMPRESSED_PAYLOAD_NONE 6 | select DEFAULT_CONSOLE_LOGLEVEL_3 7 | help 8 | Select this option if you want to build a coreboot image 9 | with Simpleboot (simplified Multiboot2 Protocol) payload. 10 | 11 | See https://gitlab.com/bztsrc/simpleboot for more information. 12 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2023 bzt (bztsrc@gitlab) 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, copy, 7 | modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 18 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 | 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 21 | DEALINGS IN THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/Makefile: -------------------------------------------------------------------------------- 1 | # for coreboot integration only 2 | # normally you'll need src/Makefile and that's it. 3 | 4 | ifeq ($(CONFIG_COREBOOT_BUILD),) 5 | include ../../../.config 6 | endif 7 | libpayload_dir=../../libpayload 8 | 9 | unexport KCONFIG_AUTOHEADER 10 | unexport KCONFIG_AUTOCONFIG 11 | unexport KCONFIG_DEPENDENCIES 12 | unexport KCONFIG_SPLITCONFIG 13 | unexport KCONFIG_TRISTATE 14 | unexport KCONFIG_NEGATIVES 15 | 16 | all: simpleboot 17 | 18 | payloads/external/simpleboot/src/loader_cb.elf: simpleboot 19 | 20 | simpleboot: $(libpayload_dir)/build/libpayload.a 21 | @echo " MAKE src/loader_cb.elf" 22 | @$(MAKE) -C src LIBPAYLOAD_PATH=../$(libpayload_dir) loader_cb.elf 23 | 24 | $(libpayload_dir)/build/libpayload.a: 25 | @$(MAKE) -C $(libpayload_dir) defconfig 26 | @sed -i "s|.*CONFIG_LP_BASE_ADDRESS=.*|CONFIG_LP_BASE_ADDRESS=0x03000000|" $(libpayload_dir)/.config 27 | @sed -i "s|.*CONFIG_LP_MULTIBOOT=y.*|# CONFIG_LP_MULTIBOOT is not set|" $(libpayload_dir)/.config 28 | @sed -i "s|.*CONFIG_LP_CURSES=y.*|# CONFIG_LP_CURSES is not set|" $(libpayload_dir)/.config 29 | @sed -i "s|.*CONFIG_LP_TINYCURSES=y.*|# CONFIG_LP_TINYCURSES is not set|" $(libpayload_dir)/.config 30 | @sed -i "s|.*CONFIG_LP_PDCURSES=y.*|# CONFIG_LP_PDCURSES is not set|" $(libpayload_dir)/.config 31 | @sed -i "s|.*# CONFIG_LP_CBFS is not set.*|CONFIG_LP_CBFS=y|" $(libpayload_dir)/.config 32 | @sed -i "s|.*CONFIG_LP_DEBUG_CBFS=y.*|# CONFIG_LP_DEBUG_CBFS is not set|" $(libpayload_dir)/.config 33 | @sed -i "s|.*CONFIG_LP_ENABLE_CBFS_FALLBACK=y.*|# CONFIG_LP_ENABLE_CBFS_FALLBACK is not set|" $(libpayload_dir)/.config 34 | @sed -i "s|.*CONFIG_LP_LZMA=y.*|# CONFIG_LP_LZMA is not set|" $(libpayload_dir)/.config 35 | @sed -i "s|.*CONFIG_LP_LZ4=y.*|# CONFIG_LP_LZ4 is not set|" $(libpayload_dir)/.config 36 | @sed -i "s|.*CONFIG_LP_VBOOT_LIB=y.*|# CONFIG_LP_VBOOT_LIB is not set|" $(libpayload_dir)/.config 37 | @sed -i "s|.*CONFIG_LP_CBMEM_CONSOLE=y.*|# CONFIG_LP_CBMEM_CONSOLE is not set|" $(libpayload_dir)/.config 38 | @sed -i "s|.*# CONFIG_LP_SERIAL_CONSOLE is not set.*|CONFIG_LP_SERIAL_CONSOLE=y|" $(libpayload_dir)/.config 39 | @sed -i "s|.*# CONFIG_LP_VIDEO_CONSOLE is not set.*|CONFIG_LP_VIDEO_CONSOLE=y|" $(libpayload_dir)/.config 40 | @sed -i "s|.*CONFIG_LP_VGA_VIDEO_CONSOLE=y.*|# CONFIG_LP_VGA_VIDEO_CONSOLE is not set|" $(libpayload_dir)/.config 41 | @sed -i "s|.*# CONFIG_LP_COREBOOT_VIDEO_CONSOLE is not set.*|CONFIG_LP_COREBOOT_VIDEO_CONSOLE=y|" $(libpayload_dir)/.config 42 | @sed -i "s|.*CONFIG_LP_MOUSE_CURSOR=y.*|# CONFIG_LP_MOUSE_CURSOR is not set|" $(libpayload_dir)/.config 43 | @sed -i "s|.*# CONFIG_LP_STORAGE is not set.*|CONFIG_LP_STORAGE=y|" $(libpayload_dir)/.config 44 | @sed -i "s|.*# CONFIG_LP_IGNORE_UNKNOWN_INTERRUPTS is not set.*|CONFIG_LP_IGNORE_UNKNOWN_INTERRUPTS=y|" $(libpayload_dir)/.config 45 | @sed -i "s|.*CONFIG_LP_DIE_ON_UNKNOWN_INTERRUPT=y.*|# CONFIG_LP_DIE_ON_UNKNOWN_INTERRUPT is not set|" $(libpayload_dir)/.config 46 | @# patch that extremely annoying cbfs (we can't use an empty macro either...) 47 | @sed -i "s|.*LOG.*;|{}|" $(libpayload_dir)/libcbfs/cbfs.c 48 | $(MAKE) -C $(libpayload_dir) 49 | 50 | clean: 51 | $(MAKE) -C src clean 52 | 53 | distclean: clean 54 | $(MAKE) -C $(libpayload_dir) clean 55 | 56 | print-repo-info: 57 | echo "https://gitlab.com/bztsrc/simpleboot.git Simpleboot" 58 | 59 | .PHONY: simpleboot libpayload clean distclean print-repo-info 60 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/distrib/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: bzt 2 | # Contributor: Ramadan Ali (alicavus) 3 | pkgname=simpleboot 4 | pkgver=1.0.0 5 | pkgrel=1 6 | pkgdesc="Dependency-free, all-in-one boot loader and bootable disk image creator." 7 | arch=("x86_64" "aarch64") 8 | url="https://gitlab.com/bztsrc/simpleboot" 9 | license=("MIT") 10 | makedepends=("clang") 11 | source=("${url}/-/archive/main/${pkgname}-main.tar.gz") 12 | b2sums=("SKIP") 13 | 14 | pkgver() { 15 | cd "${pkgname}-main/src" 16 | printf "%s" `grep -m 1 sbver simpleboot.c | cut -d '"' -f 2` 17 | } 18 | 19 | build() { 20 | cd "${pkgname}-main/src" 21 | make clean all 22 | } 23 | 24 | package() { 25 | cd "${pkgname}-main/src" 26 | DESTDIR=$pkgdir/ make install 27 | } 28 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/distrib/coreboot.rom.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/simpleboot/simpleboot/distrib/coreboot.rom.gz -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot-1.0.0.ebuild: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2023 dzsolt 2 | # Distributed under the terms of the GNU General Public License v2 3 | 4 | EAPI=7 5 | 6 | DESCRIPTION="Dependency-free, all-in-one boot loader and bootable disk image creator." 7 | HOMEPAGE="https://gitlab.com/bztsrc/simpleboot" 8 | 9 | LICENSE="MIT" 10 | SLOT="0" 11 | IUSE="rebuild" 12 | 13 | # If PV starts with 9999, use git-r3 for version control 14 | if [[ ${PV} == 9999* ]]; then 15 | inherit git-r3 16 | EGIT_REPO_URI='https://gitlab.com/bztsrc/simpleboot.git' 17 | else 18 | SRC_URI="https://gitlab.com/bztsrc/simpleboot/-/archive/${PV}/simpleboot-${PV}.tar.gz -> ${P}.tar.gz" 19 | KEYWORDS="~amd64 ~x86 ~arm64 ~arm" 20 | fi 21 | 22 | BDEPEND=" 23 | rebuild? ( 24 | dev-lang/fasm 25 | sys-devel/llvm 26 | sys-devel/lld 27 | ) 28 | " 29 | 30 | src_prepare() { 31 | default 32 | # Nothing specific to prepare 33 | } 34 | 35 | src_compile() { 36 | if use rebuild; then 37 | emake -C src distclean || die "Failed to execute 'make -C src distclean'" 38 | fi 39 | emake -C src -j1 || die "Failed to build simpleboot" 40 | } 41 | 42 | src_install() { 43 | dobin src/simpleboot || die "Failed to install simpleboot" 44 | doman src/misc/simpleboot.1.gz 45 | doheader simpleboot.h 46 | } 47 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot-9999.ebuild: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2023 dzsolt 2 | # Distributed under the terms of the GNU General Public License v2 3 | 4 | EAPI=7 5 | 6 | DESCRIPTION="Dependency-free, all-in-one boot loader and bootable disk image creator." 7 | HOMEPAGE="https://gitlab.com/bztsrc/simpleboot" 8 | 9 | LICENSE="MIT" 10 | SLOT="0" 11 | IUSE="rebuild" 12 | 13 | # If PV starts with 9999, use git-r3 for version control 14 | if [[ ${PV} == 9999* ]]; then 15 | inherit git-r3 16 | EGIT_REPO_URI='https://gitlab.com/bztsrc/simpleboot.git' 17 | else 18 | SRC_URI="https://gitlab.com/bztsrc/simpleboot/-/archive/${PV}/simpleboot-${PV}.tar.gz -> ${P}.tar.gz" 19 | KEYWORDS="~amd64 ~x86 ~arm64 ~arm" 20 | fi 21 | 22 | BDEPEND=" 23 | rebuild? ( 24 | dev-lang/fasm 25 | sys-devel/llvm 26 | sys-devel/lld 27 | ) 28 | " 29 | 30 | src_prepare() { 31 | default 32 | # Nothing specific to prepare 33 | } 34 | 35 | src_compile() { 36 | if use rebuild; then 37 | emake -C src distclean || die "Failed to execute 'make -C src distclean'" 38 | fi 39 | emake -C src -j1 || die "Failed to build simpleboot" 40 | } 41 | 42 | src_install() { 43 | dobin src/simpleboot || die "Failed to install simpleboot" 44 | doman src/misc/simpleboot.1.gz 45 | doheader simpleboot.h 46 | } 47 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot.exe -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot_1.0.0-amd64.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot_1.0.0-amd64.deb -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot_1.0.0-armhf.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/simpleboot/simpleboot/distrib/simpleboot_1.0.0-armhf.deb -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/example/README.md: -------------------------------------------------------------------------------- 1 | Simpleboot Example Kernels 2 | ========================== 3 | 4 | This directory contains the source for very minimal kernels, that can be booted with Simpleboot (and 5 | [Easyboot](https://gitlab.com/bztsrc/easyboot) as well). All they do is dumping the received boot parameters to the serial console. 6 | 7 | Compilation 8 | ----------- 9 | 10 | `make all` 11 | 12 | Will compile the example 64-bit [Multiboot2](https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html)-compatible ELF 13 | kernel and create the bootable disk image `disk.img`. 14 | 15 | `LINUX=1 make all` 16 | 17 | Creates a disk image with an example kernel that speaks the 18 | [Linux/x86 Boot Protocol](https://www.kernel.org/doc/html/latest/arch/x86/boot.html) v2.12+ (needs objcopy). 19 | 20 | `MB32=1 make all` 21 | 22 | Creates a disk image with a 32-bit Multiboot2-compatible ELF kernel. 23 | 24 | `PE=1 make clean all` 25 | 26 | Creates a disk image with a 64-bit Multiboot2-compatible COFF/PE kernel (requires Clang + lld). 27 | 28 | `MB32=1 PE=1 make all` 29 | 30 | Creates a disk image with a 32-bit Multiboot2-compatible COFF/PE kernel (requires Clang + lld). 31 | 32 | `RPI=1 make clean all` 33 | 34 | Creates a disk image with a 64-bit Multiboot2-compatible kernel for the Raspberry Pi (requires Clang + lld). 35 | 36 | `RPI=1 PE=1 make clean all` 37 | 38 | Creates a disk image with a 64-bit Multiboot2-compatible COFF/PE kernel for the Raspberry Pi (requires Clang + lld). 39 | 40 | `make clean` 41 | 42 | Cleans the repo from the compiled binaries. 43 | 44 | Plus all cases can be prefixed by `HI=1` which will compile a higher half kernel, and `SMP=1` will test Symmetric 45 | MultiProcessing (latter only with 64-bit Multiboot2-compatible ELF/COFF kernels, no Linux and no 32-bit). 46 | 47 | Testing 48 | ------- 49 | 50 | `make mnt` 51 | 52 | Mounts the boot partition inside the disk image so that you can examine its contents. 53 | 54 | `make qemu` 55 | 56 | Boots the disk image in qemu using BIOS (or Raspberry Pi if `RPI` set). 57 | 58 | `make efi` 59 | 60 | Boots the disk image in qemu using UEFI (you have to provide your own OVMF). 61 | 62 | `make cdrom` 63 | 64 | Boots the disk image in qemu using BIOS and El Torito "no emulation" mode. 65 | Use `CDROM=1 make disk.img` to generate a hybrid disk / cdrom image. 66 | 67 | `make eficdrom` 68 | 69 | Boots the disk image in qemu using UEFI and El Torito "no emulation" mode (you have to provide your own OVMF). 70 | Use `CDROM=1 make disk.img` to generate a hybrid disk / cdrom image. 71 | 72 | `make bochs` 73 | 74 | Boots the disk image in bochs using BIOS. 75 | 76 | `make rpi` 77 | 78 | Boots the disk image in qemu on Raspberry Pi. 79 | 80 | `make cb` 81 | 82 | Boots the disk image using coreboot. Note: this toolchain generates `boot/mykernel`, and coreboot will complain about not finding 83 | the kernel. To fix, either add `boot/simpleboot.cfg` too or use `mv boot/mykernel boot/kernel; make cb` (unlike with the other 84 | loaders, you cannot change the default name with `-k` because coreboot is a read-only ROM image, so only config file works). 85 | 86 | Debugging 87 | --------- 88 | 89 | `make qemudbg` 90 | 91 | Boots the disk image in qemu using BIOS, but does not start the VM. 92 | 93 | `make efidbg` 94 | 95 | Boots the disk image in qemu using UEFI, but does not start the VM. 96 | 97 | `make gdb` 98 | 99 | Run this in another terminal. It runs gdb, connects it to the stopped VM and starts execution. 100 | Because there's no symbol file, it's a bit tricky to use. Place `1:jmp 1b` anywhere in the code, and press Ctrl+ 101 | C in the gdb's window. You'll see that the VM is running that jump. Use `set $pc += 2` to step over the jump 102 | instruction, and after that you can do step by step execution with `si`, or continue with `c`. 103 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/example/bochs.rc: -------------------------------------------------------------------------------- 1 | # configuration file generated by Bochs 2 | plugin_ctrl: unmapped=1, biosdev=1, speaker=0, extfpuirq=1, parallel=0, serial=1, iodebug=0 3 | config_interface: textconfig 4 | display_library: x 5 | memory: host=128, guest=128 6 | romimage: file="/usr/share/bochs/BIOS-bochs-latest" 7 | vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest" 8 | #boot: cdrom 9 | boot: disk 10 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 11 | ata0-master: type=disk, path="disk.img", mode=flat, cylinders=2, heads=16, spt=63, model="Generic 1234", biosdetect=auto, translation=auto 12 | #ata0-slave: type=cdrom, path="disk.img", status=inserted 13 | ata0-slave: type=none 14 | ata1: enabled=0 15 | ata2: enabled=0 16 | ata3: enabled=0 17 | pci: enabled=1, chipset=i440fx 18 | vga: extension=vbe, update_freq=10, realtime=1 19 | cpu: count=2, ips=4000000, model=corei7_ivy_bridge_3770k, reset_on_triple_fault=0, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 20 | cpuid: level=6, apic=x2apic, simd=avx, aes=1 21 | print_timestamps: enabled=0 22 | debugger_log: - 23 | magic_break: enabled=1 24 | port_e9_hack: enabled=1 25 | private_colormap: enabled=0 26 | clock: sync=realtime, time0=local, rtc_sync=1 27 | log: - 28 | logprefix: %t%e%d 29 | debug: action=ignore 30 | info: action=report 31 | error: action=report 32 | panic: action=ask 33 | keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none 34 | mouse: type=imps2, enabled=0, toggle=ctrl+mbutton 35 | com1: enabled=1, mode=file, dev=/dev/stdout 36 | #optromimage1: file="sb_bios.rom", address=0xCA000 37 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/example/gdb.rc: -------------------------------------------------------------------------------- 1 | target remote localhost:1234 2 | set architecture i386:x86-64 3 | set style enabled off 4 | display/4i $pc 5 | c 6 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/src/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(LIBPAYLOAD_PATH),) 2 | include $(LIBPAYLOAD_PATH)/build/xcompile 3 | ifneq ($(CONFIG_LP_ARCH_ARM64),) 4 | STRIP=$(STRIP_arm64) 5 | else 6 | STRIP=$(STRIP_x86_32) 7 | endif 8 | ifneq ($(DEBUG),) 9 | CFLAGS+=-DDEBUG=1 10 | endif 11 | CFLAGS+=-fshort-wchar -fno-strict-aliasing -fno-stack-protector -fno-stack-check -mno-red-zone -Wall -Wextra -Werror 12 | else 13 | PREFIX?=usr/ 14 | INSTDIR?=$(DESTDIR:/=)/$(PREFIX:/=) 15 | ARCH=$(shell uname -m) 16 | TMP=$(ARCH:x86_64=amd64) 17 | TMP2=$(TMP:armv7l=armhf) 18 | DEBARCH=$(TMP2:aarch64=arm64) 19 | VERSION=$(shell grep -m 1 sbver simpleboot.c|cut -d '"' -f 2) 20 | CFLAGS=-fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check -mno-red-zone \ 21 | -nostdlib -Wall -Wextra -Werror -Wno-long-long 22 | endif 23 | 24 | all: simpleboot 25 | 26 | romfoss_x86.bin: romfoss_x86.asm 27 | fasm romfoss_x86.asm romfoss_x86.bin 28 | 29 | rombios_x86.bin: rombios_x86.asm 30 | fasm rombios_x86.asm rombios_x86.bin 31 | 32 | cdemu_x86.bin: cdemu_x86.asm 33 | fasm cdemu_x86.asm cdemu_x86.bin 34 | 35 | boot_x86.bin: boot_x86.asm 36 | fasm boot_x86.asm boot_x86.bin 37 | 38 | loader_x86.efi: loader_x86.c loader.h ../simpleboot.h 39 | clang --target=x86_64-pc-win32-coff $(CFLAGS) -Wframe-larger-than=512 -c loader_x86.c -o loader_x86.o 40 | lld -flavor link -subsystem:efi_application -Brepro -nodefaultlib -dll -dynamicbase -base:0x7000 -entry:_start loader_x86.o -out:loader_x86.efi 41 | @rm loader_x86.o loader_x86.lib 2>/dev/null 42 | 43 | loader_rpi.bin: loader_rpi.c loader.h ../simpleboot.h 44 | clang --target=aarch64-elf $(CFLAGS) -Wl,-Ttext=0x80000 -Wl,--omagic loader_rpi.c -o loader_rpi.o 45 | 46 | loader_cb.elf: loader_cb.c loader.h ../simpleboot.h 47 | $(LIBPAYLOAD_PATH)/bin/lpgcc $(CFLAGS) -o loader_cb.elf loader_cb.c 48 | ifeq ($(DEBUG),) 49 | @$(STRIP) loader_cb.elf 50 | endif 51 | 52 | data.h: romfoss_x86.bin rombios_x86.bin cdemu_x86.bin boot_x86.bin loader_x86.efi loader_rpi.bin 53 | @$(CC) misc/bin2h.c -o bin2h 54 | @./bin2h romfoss_x86.bin rombios_x86.bin cdemu_x86.bin boot_x86.bin loader_x86.efi loader_rpi.o 55 | @rm bin2h 56 | @touch data.h 57 | 58 | simpleboot: loader.h simpleboot.c 59 | @test -f data.h || make --no-print-directory data.h 60 | $(CC) -ansi -Wall -Wextra simpleboot.c -o simpleboot 61 | @strip simpleboot 2>/dev/null || true 62 | @strip simpleboot.exe 2>/dev/null || true 63 | 64 | install: simpleboot 65 | ifneq ("$(INSTDIR)","") 66 | install -D -m 755 -o root -g root simpleboot -t $(INSTDIR)/bin 67 | @mkdir -p $(INSTDIR)/share/man/man1 2>/dev/null || true 68 | cp misc/simpleboot.1.gz $(INSTDIR)/share/man/man1 69 | cp ../simpleboot.h $(INSTDIR)/include 70 | else 71 | @echo "INSTDIR variable not set, not installing." 72 | @false 73 | endif 74 | 75 | deb: 76 | @rm -rf DEBIAN usr 2>/dev/null || true 77 | @mkdir -p DEBIAN usr/bin usr/include usr/share/man/man1 78 | @cp simpleboot usr/bin 79 | @cp ../simpleboot.h usr/include 80 | @cp misc/simpleboot.1.gz usr/share/man/man1 81 | @cat misc/deb_control | sed s/ARCH/$(DEBARCH)/g | sed s/VERSION/$(VERSION)/g | sed s/SIZE/`du -s usr|cut -f 1`/g >DEBIAN/control 82 | @md5sum `find usr -type f` >DEBIAN/md5sums 83 | @cp ../LICENSE DEBIAN/copyright 84 | @echo "2.0" >debian-binary 85 | @tar -czvf data.tar.gz usr 86 | @tar -C DEBIAN -czvf control.tar.gz control copyright md5sums 87 | ar r ../distrib/simpleboot_$(VERSION)-$(DEBARCH).deb debian-binary control.tar.gz data.tar.gz 88 | @rm -rf debian-binary control.tar.gz data.tar.gz DEBIAN usr 89 | 90 | clean: 91 | rm *.bin loader_*.o loader_*.lib loader_*.efi loader_*.elf simpleboot 2>/dev/null || true 92 | 93 | distclean: clean 94 | rm data.h 2>/dev/null || true 95 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/src/misc/deb_control: -------------------------------------------------------------------------------- 1 | Package: simpleboot 2 | Version: VERSION 3 | Architecture: ARCH 4 | Essential: no 5 | Section: tools 6 | Priority: optional 7 | Maintainer: bzt 8 | Homepage: https://codeberg.org/bzt/simpleboot 9 | Installed-Size: SIZE 10 | Description: Dependency-free, all-in-one boot loader and bootable disk image creator. 11 | It creates a bootable disk image that can boot Linux kernels or any other 12 | Multiboot2 compliant kernels in various formats. 13 | -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/simpleboot/src/misc/simpleboot.1.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel-standalone-builder/simpleboot/simpleboot/src/misc/simpleboot.1.gz -------------------------------------------------------------------------------- /kernel-standalone-builder/simpleboot/wrapper.c: -------------------------------------------------------------------------------- 1 | #include "simpleboot/src/simpleboot.c" 2 | 3 | // Note that unfortunately simpleboot calls `exit(1)` whenever something problematic happens 4 | // instead of doing proper error management, but we just cope with this. 5 | extern int simpleboot_wrapper(int argc, char **argv) { 6 | return simpleboot_main(argc, argv); 7 | } 8 | -------------------------------------------------------------------------------- /kernel-standalone-builder/src/binary.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use std::{io, path::Path, process::Command}; 17 | 18 | #[derive(Debug)] 19 | pub enum Architecture { 20 | /// 32bits ARM. 21 | Arm, 22 | /// 64bits ARM. 23 | Aarch64, 24 | } 25 | 26 | /// Turn an ELF file into a binary. 27 | // TODO: implement this in pure Rust? 28 | // TODO: define exact semantics of what this function does on the file 29 | pub fn elf_to_binary( 30 | architecture: Architecture, 31 | src: impl AsRef, 32 | dest: impl AsRef, 33 | ) -> Result<(), io::Error> { 34 | let binary = match architecture { 35 | Architecture::Arm => "arm-linux-gnu-objcopy", 36 | Architecture::Aarch64 => "aarch64-linux-gnu-objcopy", 37 | }; 38 | 39 | let status = Command::new(binary) 40 | .args(&["-O", "binary"]) 41 | .arg(src.as_ref()) 42 | .arg(dest.as_ref()) 43 | .status()?; 44 | // TODO: make it configurable where stdout/stderr go? 45 | if !status.success() { 46 | return Err(io::Error::from(io::ErrorKind::Other)); 47 | } 48 | 49 | Ok(()) 50 | } 51 | -------------------------------------------------------------------------------- /kernel-standalone-builder/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Collection of commands that can build a kernel. 17 | 18 | pub mod binary; 19 | pub mod build; 20 | pub mod emulator; 21 | pub mod image; 22 | pub mod test; 23 | 24 | mod simpleboot; 25 | -------------------------------------------------------------------------------- /kernel-standalone-builder/src/simpleboot.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use std::{ffi::CString, iter}; 17 | 18 | extern "C" { 19 | fn simpleboot_wrapper( 20 | argc: std::os::raw::c_int, 21 | argv: *mut *mut std::os::raw::c_char, 22 | ) -> std::os::raw::c_int; 23 | } 24 | 25 | pub fn run_simpleboot<'a>(args: impl IntoIterator) -> Result<(), ()> { 26 | let args = iter::once(CString::new("simpleboot").unwrap()) 27 | .chain(args.into_iter().map(|s| CString::new(s).unwrap())) 28 | .collect::>(); 29 | let args_ptrs = args 30 | .iter() 31 | .map(|a| a.as_c_str().as_ptr()) 32 | .collect::>(); 33 | 34 | let out = unsafe { 35 | simpleboot_wrapper( 36 | args.len() as std::os::raw::c_int, 37 | args_ptrs.as_ptr().cast_mut().cast(), 38 | ) 39 | }; 40 | 41 | if out == 0 { 42 | Ok(()) 43 | } else { 44 | Err(()) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /kernel/core-proc-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-core-proc-macros" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [lib] 10 | proc-macro = true 11 | 12 | [dependencies] 13 | cargo_metadata = "0.12" 14 | proc-macro2 = "1.0" 15 | serde_json = "1.0" 16 | syn = "1.0" 17 | wat = "1.0.36" 18 | 19 | [features] 20 | default = [] 21 | nightly = [] 22 | -------------------------------------------------------------------------------- /kernel/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-core" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [features] 10 | default = [] 11 | nightly = ["redshirt-core-proc-macros/nightly"] 12 | 13 | [dependencies] 14 | atomic = "0.5.0" 15 | blake3 = { version = "1.6.1", default-features = false } 16 | bs58 = { version = "0.4.0", default-features = false, features = ["alloc"] } 17 | crossbeam-queue = { version = "0.3.1", default-features = false, features = [ 18 | "alloc", 19 | ] } 20 | either = { version = "1.6.1", default-features = false } 21 | fnv = { version = "1.0.7", default-features = false } 22 | futures = { version = "0.3.13", default-features = false } 23 | hashbrown = { version = "0.9.1", default-features = false } 24 | itertools = { version = "0.14.0", default-features = false } 25 | nohash-hasher = { version = "0.2.0", default-features = false } 26 | redshirt-core-proc-macros = { path = "../core-proc-macros" } 27 | redshirt-interface-interface = { path = "../../interface-wrappers/interface", default-features = false } 28 | redshirt-kernel-debug-interface = { path = "../../interface-wrappers/kernel-debug", default-features = false } 29 | redshirt-loader-interface = { path = "../../interface-wrappers/loader", default-features = false } 30 | redshirt-log-interface = { path = "../../interface-wrappers/log", default-features = false } 31 | redshirt-random-interface = { path = "../../interface-wrappers/random", default-features = false } 32 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls", default-features = false } 33 | redshirt-system-time-interface = { path = "../../interface-wrappers/system-time", default-features = false } 34 | redshirt-time-interface = { path = "../../interface-wrappers/time", default-features = false } 35 | rand = { version = "0.8.3", default-features = false } 36 | rand_chacha = { version = "0.3.0", default-features = false } 37 | rand_core = { version = "0.6.0", default-features = false } 38 | slab = { version = "0.4.9", default-features = false } 39 | smallvec = { version = "1.6.1", default-features = false } 40 | spinning_top = "0.3.0" 41 | wasi = { git = "https://github.com/bytecodealliance/wasi", rev = "45536ac956a6211e3cff047f36cf19d6da82fd95", default-features = false } # TODO: dependabot cannot parse the versioning scheme (`0.10.0+wasi-snapshot-preview1`) of this crate on crates.io 42 | wasmi = { version = "0.42.1", default-features = false } 43 | 44 | [dev-dependencies] 45 | criterion = "0.3" 46 | futures = { version = "0.3.13", default-features = false, features = [ 47 | "executor", 48 | ] } 49 | tiny-keccak = { version = "2.0.2", features = ["keccak"] } 50 | 51 | [[bench]] 52 | name = "keccak" 53 | harness = false 54 | -------------------------------------------------------------------------------- /kernel/core/benches/keccak.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use criterion::{criterion_group, criterion_main, Criterion}; 17 | use redshirt_core::{extrinsics::wasi::WasiExtrinsics, Module, SystemBuilder, SystemRunOutcome}; 18 | 19 | fn bench(c: &mut Criterion) { 20 | /* Original code: 21 | #![feature(alloc_error_handler)] 22 | #![no_std] 23 | #![no_main] 24 | 25 | #[global_allocator] 26 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 27 | 28 | #[cfg(not(any(test, doc, doctest)))] 29 | #[panic_handler] 30 | fn panic(_: &core::panic::PanicInfo) -> ! { 31 | unsafe { core::hint::unreachable_unchecked() } 32 | } 33 | 34 | #[cfg(not(any(test, doc, doctest)))] 35 | #[alloc_error_handler] 36 | fn alloc_error_handler(_: core::alloc::Layout) -> ! { 37 | panic!() 38 | } 39 | 40 | extern crate alloc; 41 | use alloc::vec; 42 | use futures::prelude::*; 43 | use tiny_keccak::*; 44 | 45 | #[no_mangle] 46 | fn _start() { 47 | let data = [254u8; 4096]; 48 | 49 | let mut res: [u8; 32] = [0; 32]; 50 | let mut keccak = tiny_keccak::Keccak::v256(); 51 | keccak.update(&data); 52 | keccak.finalize(&mut res); 53 | 54 | assert_ne!(res[0] as isize, 0); 55 | } 56 | */ 57 | let module = Module::from_bytes(&include_bytes!("keccak.wasm")[..]).unwrap(); 58 | 59 | c.bench_function("keccak-wasm-4096-bytes", |b| { 60 | let system = SystemBuilder::::new([0; 64]) 61 | .build() 62 | .unwrap(); 63 | b.iter(|| { 64 | system.execute(&module).unwrap(); 65 | futures::executor::block_on(async { 66 | loop { 67 | match system.run().await { 68 | SystemRunOutcome::ProgramFinished { outcome, .. } => break outcome, 69 | _ => panic!(), 70 | } 71 | } 72 | }) 73 | .unwrap(); 74 | }) 75 | }); 76 | 77 | c.bench_function("keccak-native-4096-bytes", |b| { 78 | b.iter(|| { 79 | use tiny_keccak::*; 80 | 81 | let data = [254u8; 4096]; 82 | 83 | let mut res: [u8; 32] = [0; 32]; 84 | let mut keccak = tiny_keccak::Keccak::v256(); 85 | keccak.update(&data); 86 | keccak.finalize(&mut res); 87 | 88 | assert_ne!(res[0] as isize, 0); 89 | }) 90 | }); 91 | } 92 | 93 | criterion_group!(benches, bench); 94 | criterion_main!(benches); 95 | -------------------------------------------------------------------------------- /kernel/core/benches/keccak.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel/core/benches/keccak.wasm -------------------------------------------------------------------------------- /kernel/core/src/id_pool.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use core::{convert::TryFrom, fmt}; 17 | use crossbeam_queue::SegQueue; 18 | use rand::distributions::{Distribution as _, Uniform}; 19 | use rand_chacha::ChaCha20Rng; 20 | use rand_core::SeedableRng as _; 21 | use spinning_top::Spinlock; 22 | 23 | // Maths note: after 3 billion iterations, there's a 2% chance of a collision 24 | // 25 | // Chance of collision is approximately: 1 - exp(-n^2 / 2^(b+1)) 26 | // where `n` is the number of generated IDs, `b` number of bits in the ID (64 here) 27 | 28 | /// Lock-free pool of identifiers. Can assign new identifiers from it. 29 | pub struct IdPool { 30 | /// Sources of randomness. 31 | /// Every time we need a random number, we pop a state from this list, then push it back when 32 | /// we're done. 33 | rngs: SegQueue, 34 | /// Distribution of IDs. 35 | distribution: Uniform, 36 | /// PRNG used to seed the other thread-specific PRNGs stored in `rngs`. 37 | master_rng: Spinlock, 38 | } 39 | 40 | impl IdPool { 41 | /// Initializes a new pool. 42 | pub fn with_seed(seed: [u8; 32]) -> Self { 43 | IdPool { 44 | rngs: SegQueue::new(), 45 | distribution: Uniform::from(0..=u64::max_value()), 46 | master_rng: Spinlock::new(ChaCha20Rng::from_seed(seed)), 47 | } 48 | } 49 | 50 | /// Assigns a new PID from this pool. 51 | /// 52 | /// The returned value must implement the `TryFrom` trait. `u64`s are rolled as long as 53 | /// as calling `TryFrom` returns an error. 54 | pub fn assign>(&self) -> T { 55 | if let Some(mut rng) = self.rngs.pop() { 56 | return loop { 57 | let raw_id = self.distribution.sample(&mut rng); 58 | if let Ok(id) = TryFrom::try_from(raw_id) { 59 | self.rngs.push(rng); 60 | break id; 61 | } 62 | }; 63 | } 64 | 65 | let mut master_rng = self.master_rng.lock(); 66 | let mut new_rng = match ChaCha20Rng::from_rng(&mut *master_rng) { 67 | Ok(r) => r, 68 | Err(_) => unreachable!(), 69 | }; 70 | 71 | loop { 72 | let raw_id = self.distribution.sample(&mut new_rng); 73 | if let Ok(id) = TryFrom::try_from(raw_id) { 74 | self.rngs.push(new_rng); 75 | break id; 76 | } 77 | } 78 | } 79 | } 80 | 81 | impl fmt::Debug for IdPool { 82 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 83 | f.debug_tuple("IdPool").finish() 84 | } 85 | } 86 | 87 | #[cfg(test)] 88 | mod tests { 89 | use nohash_hasher::BuildNoHashHasher; 90 | 91 | #[test] 92 | fn ids_different() { 93 | let mut ids = hashbrown::HashSet::>::default(); 94 | let pool = super::IdPool::with_seed([0; 32]); 95 | for _ in 0..5000 { 96 | assert!(ids.insert(pool.assign())); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /kernel/core/src/module.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use core::fmt; 17 | 18 | /// Hash of a module. 19 | #[derive(Clone, PartialEq, Eq, Hash)] 20 | pub struct ModuleHash([u8; 32]); 21 | 22 | /// Error that can happen when calling [`ModuleHash::from_base58`]. 23 | #[derive(Debug)] 24 | pub struct FromBase58Error {} 25 | 26 | impl From<[u8; 32]> for ModuleHash { 27 | fn from(hash: [u8; 32]) -> ModuleHash { 28 | ModuleHash(hash) 29 | } 30 | } 31 | 32 | impl From for [u8; 32] { 33 | fn from(hash: ModuleHash) -> [u8; 32] { 34 | hash.0 35 | } 36 | } 37 | 38 | impl ModuleHash { 39 | /// Returns the hash of the given bytes. 40 | pub fn from_bytes(buffer: impl AsRef<[u8]>) -> Self { 41 | ModuleHash(blake3::hash(buffer.as_ref()).into()) 42 | } 43 | 44 | /// Decodes the given base58-encoded string into a hash. 45 | /// 46 | /// See also https://en.wikipedia.org/wiki/Base58. 47 | // TODO: check that we return an error if the string is too long 48 | pub fn from_base58(encoding: &str) -> Result { 49 | let mut out = [0; 32]; 50 | let written = bs58::decode(encoding) 51 | .into(&mut out) 52 | .map_err(|_| FromBase58Error {})?; 53 | let mut out2 = [0; 32]; 54 | out2[32 - written..].copy_from_slice(&out[..written]); 55 | Ok(ModuleHash(out2)) 56 | } 57 | } 58 | 59 | impl fmt::Debug for ModuleHash { 60 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 61 | write!(f, "ModuleHash({})", bs58::encode(&self.0).into_string()) 62 | } 63 | } 64 | 65 | impl fmt::Display for FromBase58Error { 66 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 67 | write!(f, "FromBase58Error") 68 | } 69 | } 70 | 71 | #[cfg(test)] 72 | mod tests { 73 | #[test] 74 | fn empty_wat_works() { 75 | let _ = from_wat!(local, "(module)"); 76 | } 77 | 78 | #[test] 79 | fn simple_wat_works() { 80 | let _ = from_wat!( 81 | local, 82 | r#" 83 | (module 84 | (func $add (param i32 i32) (result i32) 85 | local.get 0 86 | local.get 1 87 | i32.add) 88 | (export "add" (func $add))) 89 | "# 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /kernel/core/src/scheduler.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Core system that includes executing Wasm programs passing messages to each other. 17 | //! 18 | //! This module is lower-level than [`system`](super::system). It doesn't hardcode any interface. 19 | 20 | mod extrinsics; 21 | mod ipc; 22 | mod processes; 23 | mod tests; 24 | mod vm; 25 | 26 | pub use self::ipc::{Core, CoreBuilder, CoreProcess, CoreRunOutcome, ExecuteOut, ReadyToRun}; 27 | pub use self::vm::NewErr; 28 | -------------------------------------------------------------------------------- /kernel/core/src/scheduler/processes/wakers.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use core::{fmt, task::Waker}; 17 | use slab::Slab; 18 | use spinning_top::Spinlock; 19 | 20 | /// Collection of wakers. 21 | #[derive(Default)] 22 | pub struct Wakers { 23 | // TODO: could avoid the mutex by knowing in advance the number of registrations 24 | list: Spinlock>>, 25 | } 26 | 27 | impl Wakers { 28 | pub fn register(&self) -> Registration { 29 | let mut list = self.list.lock(); 30 | let index = list.insert(None); 31 | Registration { 32 | list: &self.list, 33 | index, 34 | } 35 | } 36 | 37 | /// Wakes up one registered waker. Has no effect if the list is empty. 38 | pub fn notify_one(&self) { 39 | let mut list = self.list.lock(); 40 | for (_, elem) in list.iter_mut() { 41 | if let Some(elem) = elem.take() { 42 | elem.wake(); 43 | return; 44 | } 45 | } 46 | } 47 | } 48 | 49 | impl fmt::Debug for Wakers { 50 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 51 | f.debug_tuple("Wakers").finish() 52 | } 53 | } 54 | 55 | pub struct Registration<'a> { 56 | list: &'a Spinlock>>, 57 | index: usize, 58 | } 59 | 60 | impl<'a> Registration<'a> { 61 | pub fn set_waker(&mut self, waker: &Waker) { 62 | let mut list = self.list.lock(); 63 | let entry = &mut list[self.index]; 64 | if let Some(entry) = entry { 65 | if entry.will_wake(waker) { 66 | return; 67 | } 68 | } 69 | *entry = Some(waker.clone()); 70 | } 71 | } 72 | 73 | impl<'a> fmt::Debug for Registration<'a> { 74 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 75 | f.debug_tuple("Registration").finish() 76 | } 77 | } 78 | 79 | impl<'a> Drop for Registration<'a> { 80 | fn drop(&mut self) { 81 | self.list.lock().remove(self.index); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /kernel/core/src/scheduler/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #![cfg(test)] 17 | 18 | use crate::extrinsics::NoExtrinsics; 19 | 20 | mod basic_module; 21 | mod emit_not_available; 22 | mod trapping_module; 23 | 24 | #[test] 25 | fn send_sync() { 26 | fn is_send_sync() {} 27 | is_send_sync::>() 28 | } 29 | -------------------------------------------------------------------------------- /kernel/core/src/scheduler/tests/basic_module.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use crate::extrinsics::NoExtrinsics; 17 | use crate::scheduler::{CoreBuilder, CoreRunOutcome}; 18 | use futures::prelude::*; 19 | 20 | #[test] 21 | fn basic_module() { 22 | let module = from_wat!( 23 | local, 24 | r#"(module 25 | (func $_start (result i32) 26 | i32.const 5) 27 | (export "_start" (func $_start))) 28 | "# 29 | ); 30 | 31 | let core = CoreBuilder::::with_seed([0; 64]).build(); 32 | let expected_pid = core.execute(&module).unwrap().0.pid(); 33 | 34 | let event = loop { 35 | if let Some(ev) = core.run().now_or_never().unwrap().or_run() { 36 | break ev; 37 | } 38 | }; 39 | 40 | match event { 41 | CoreRunOutcome::ProgramFinished { 42 | pid, 43 | outcome: Ok(ret_val), 44 | .. 45 | } => { 46 | assert_eq!(pid, expected_pid); 47 | assert!(matches!(ret_val, Some(crate::WasmValue::I32(5)))); 48 | } 49 | _ => panic!(), 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /kernel/core/src/scheduler/tests/emit_not_available.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use crate::extrinsics::NoExtrinsics; 17 | use crate::scheduler::{CoreBuilder, CoreRunOutcome}; 18 | use crate::InterfaceHash; 19 | use futures::prelude::*; 20 | 21 | #[test] 22 | fn emit_not_available() { 23 | /* Original code: 24 | 25 | let interface = redshirt_syscalls::InterfaceHash::from_raw_hash([ 26 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 27 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 28 | ]); 29 | 30 | unsafe { 31 | let _ = redshirt_syscalls::MessageBuilder::default() 32 | .add_data_raw(&[1, 2, 3, 4, 5, 6, 7, 8]) 33 | .emit_without_response(&interface); 34 | } 35 | 36 | */ 37 | let module = from_wat!( 38 | local, 39 | r#" 40 | (module 41 | (type $t0 (func (param i32 i32 i32 i64 i32) (result i32))) 42 | (import "redshirt" "emit_message" (func $_ZN27redshirt_syscalls3ffi12emit_message17h508280f1400e36efE (type $t0))) 43 | (func $_start (result i32) 44 | (local $l0 i32) 45 | global.get $g0 46 | i32.const 64 47 | i32.sub 48 | local.tee $l0 49 | global.set $g0 50 | local.get $l0 51 | i64.const 3978425819141910832 52 | i64.store offset=32 53 | local.get $l0 54 | i64.const 2820983053732684064 55 | i64.store offset=24 56 | local.get $l0 57 | i64.const 1663540288323457296 58 | i64.store offset=16 59 | local.get $l0 60 | i64.const 506097522914230528 61 | i64.store offset=8 62 | local.get $l0 63 | i32.const 1048576 64 | i64.extend_i32_s 65 | i64.const 34359738368 66 | i64.or 67 | i64.store offset=41 align=1 68 | local.get $l0 69 | i32.const 1 70 | i32.store8 offset=40 71 | local.get $l0 72 | i32.const 8 73 | i32.add 74 | local.get $l0 75 | i32.const 40 76 | i32.add 77 | i32.const 1 78 | i32.or 79 | i32.const 1 80 | i64.const 2 81 | local.get $l0 82 | i32.const 56 83 | i32.add 84 | call $_ZN27redshirt_syscalls3ffi12emit_message17h508280f1400e36efE 85 | drop 86 | local.get $l0 87 | i32.const 64 88 | i32.add 89 | global.set $g0 90 | i32.const 0) 91 | (table $T0 1 1 funcref) 92 | (memory $memory 17) 93 | (global $g0 (mut i32) (i32.const 1048576)) 94 | (export "memory" (memory 0)) 95 | (export "_start" (func $_start)) 96 | (data (i32.const 1048576) "\01\02\03\04\05\06\07\08"))"# 97 | ); 98 | 99 | let core = CoreBuilder::::with_seed([0; 64]).build(); 100 | core.execute(&module).unwrap(); 101 | 102 | match core.run().now_or_never().unwrap().or_run() { 103 | Some(CoreRunOutcome::InterfaceMessage { interface, .. }) => { 104 | assert_eq!( 105 | interface, 106 | InterfaceHash::from_raw_hash([ 107 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 108 | 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x30, 0x31, 109 | 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 110 | ]) 111 | ); 112 | } 113 | _ => panic!(), 114 | } 115 | 116 | assert!(core.run().now_or_never().is_none()); 117 | } 118 | -------------------------------------------------------------------------------- /kernel/core/src/scheduler/tests/trapping_module.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use crate::extrinsics::NoExtrinsics; 17 | use crate::scheduler::{CoreBuilder, CoreRunOutcome}; 18 | use futures::prelude::*; 19 | 20 | #[test] 21 | fn trapping_module() { 22 | let module = from_wat!( 23 | local, 24 | r#"(module 25 | (func $_start 26 | unreachable) 27 | (export "_start" (func $_start))) 28 | "# 29 | ); 30 | 31 | let core = CoreBuilder::::with_seed([0; 64]).build(); 32 | let expected_pid = core.execute(&module).unwrap().0.pid(); 33 | 34 | let event = loop { 35 | if let Some(ev) = core.run().now_or_never().unwrap().or_run() { 36 | break ev; 37 | } 38 | }; 39 | 40 | match event { 41 | CoreRunOutcome::ProgramFinished { 42 | pid, 43 | outcome: Err(_), 44 | .. 45 | } => { 46 | assert_eq!(pid, expected_pid); 47 | } 48 | _ => panic!(), 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /kernel/core/src/system/pending_answers.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Delivered messages waiting to be answered. 17 | //! 18 | //! The [`PendingAnswers`] struct holds a list of messages that have been successfully delivered 19 | //! to interface handles but haven't been answered yet. 20 | 21 | use alloc::vec::Vec; 22 | use hashbrown::HashMap; 23 | use nohash_hasher::BuildNoHashHasher; 24 | use redshirt_syscalls::{MessageId, Pid}; 25 | 26 | pub struct PendingAnswers { 27 | // TODO: smarter than a spinloop? 28 | inner: spinning_top::Spinlock, 29 | } 30 | 31 | struct Inner { 32 | // TODO: call shrink_to_fit from time to time? 33 | messages: HashMap>, 34 | } 35 | 36 | impl PendingAnswers { 37 | pub fn new() -> Self { 38 | PendingAnswers { 39 | inner: spinning_top::Spinlock::new(Inner { 40 | messages: Default::default(), 41 | }), 42 | } 43 | } 44 | 45 | pub fn add(&self, message_id: MessageId, answerer_pid: Pid) { 46 | let _inserted = self.inner.lock().messages.insert(message_id, answerer_pid); 47 | debug_assert!(_inserted.is_none()); 48 | } 49 | 50 | pub fn remove(&self, message_id: &MessageId, if_answerer_equal: &Pid) -> Result<(), ()> { 51 | let mut inner = self.inner.lock(); 52 | match inner.messages.remove(message_id) { 53 | Some(pid) if pid == *if_answerer_equal => Ok(()), 54 | Some(pid) => { 55 | // Cancel the removal. 56 | inner.messages.insert(message_id.clone(), pid); 57 | Err(()) 58 | } 59 | None => Err(()), 60 | } 61 | } 62 | 63 | /// Removes from the collection all messages whose answerer is the given PID. 64 | pub fn drain_by_answerer(&self, answerer_pid: &Pid) -> Vec { 65 | // TODO: O(n) complexity 66 | let mut inner = self.inner.lock(); 67 | 68 | let list = inner 69 | .messages 70 | .iter() 71 | .filter(|(_, a)| *a == answerer_pid) 72 | .map(|(m, _)| *m) 73 | .collect::>(); 74 | 75 | for message in &list { 76 | let _was_removed = inner.messages.remove(message); 77 | debug_assert!(_was_removed.is_some()); 78 | } 79 | 80 | list 81 | } 82 | } 83 | 84 | impl Default for PendingAnswers { 85 | fn default() -> Self { 86 | PendingAnswers::new() 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /kernel/standalone/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redshirt-standalone-kernel" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [dependencies] 10 | atomic = { version = "0.5.0", default-features = false } 11 | blake3 = { version = "1.6.1", default-features = false } 12 | crossbeam-queue = { version = "0.3.1", default-features = false, features = ["alloc"] } 13 | derive_more = { version = "2.0.0", default-features = false, features = ["full"] } 14 | either = { version = "1.6.1", default-features = false } 15 | fnv = { version = "1.0.7", default-features = false } 16 | futures = { version = "0.3.13", default-features = false, features = ["alloc"] } 17 | hashbrown = { version = "0.9.1", default-features = false } 18 | lazy_static = "1.4" 19 | libm = "0.2.1" 20 | linked_list_allocator = { version = "0.9.0", features = ["alloc_ref"] } 21 | nohash-hasher = { version = "0.2.0", default-features = false } 22 | pin-project = "1.0.5" 23 | rand_chacha = { version = "0.2.0", default-features = false } 24 | rand_core = { version = "0.5.1", default-features = false } 25 | rand_jitter = { version = "0.3.0", default-features = false } 26 | redshirt-core = { path = "../core", features = ["nightly"] } 27 | redshirt-hardware-interface = { path = "../../interface-wrappers/hardware", default-features = false } 28 | redshirt-interface-interface = { path = "../../interface-wrappers/interface", default-features = false } 29 | redshirt-kernel-log-interface = { path = "../../interface-wrappers/kernel-log", default-features = false } 30 | redshirt-log-interface = { path = "../../interface-wrappers/log", default-features = false } 31 | redshirt-pci-interface = { path = "../../interface-wrappers/pci", default-features = false } 32 | redshirt-random-interface = { path = "../../interface-wrappers/random", default-features = false } 33 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls", default-features = false } 34 | redshirt-time-interface = { path = "../../interface-wrappers/time", default-features = false } 35 | rlibc = "1.0.0" 36 | smallvec = { version = "1.6.1", default-features = false } 37 | spinning_top = "0.3.0" 38 | 39 | [build-dependencies] 40 | rusttype = "0.9.2" 41 | 42 | [target.'cfg(target_arch = "x86_64")'.dependencies] 43 | acpi = "4.1.0" 44 | aml = "0.16.4" 45 | crossbeam-utils = { version = "0.8.3", default-features = false } 46 | multiboot2 = "0.23.1" 47 | rdrand = { version = "0.7.0", default-features = false } 48 | x86_64 = "0.15.2" 49 | -------------------------------------------------------------------------------- /kernel/standalone/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use std::{convert::TryFrom as _, env, fs, path::Path}; 17 | 18 | fn main() { 19 | let font_data = gen_font(); 20 | assert_eq!(font_data.len(), 128 * 8 * 8); 21 | 22 | let out_dir = env::var("OUT_DIR").unwrap(); 23 | fs::write(Path::new(&out_dir).join("font.bin"), &font_data).unwrap(); 24 | } 25 | 26 | /// Generates a font sprite sheet of the 128 ASCII characters. 27 | /// 28 | /// Each character is 8x8 pixel. Each pixel is a single byte indicating its opacity. A value 29 | /// of 0x0 means transparent, and a value of 0xff means opaque. 30 | /// 31 | /// In other words, the returned data is 128 * 8 * 8 bytes. 32 | fn gen_font() -> Vec { 33 | let font_data: &[u8] = include_bytes!("vcr_osd_mono.ttf"); 34 | let font = rusttype::Font::try_from_bytes(font_data).unwrap(); 35 | 36 | let mut out_data = vec![0; 128 * 8 * 8]; 37 | for ascii_chr in 0..128u8 { 38 | let glyph = font 39 | .glyph(char::from(ascii_chr)) 40 | .scaled(rusttype::Scale { x: 8.0, y: 8.0 }) 41 | .positioned(rusttype::Point { x: 0.0, y: 0.0 }); 42 | 43 | // `pixel_bound_box` returns `None` for glyphs that are empty (like the space character) 44 | let bbox = match glyph.pixel_bounding_box() { 45 | Some(b) => b, 46 | None => continue, 47 | }; 48 | 49 | glyph.draw(|x, y, value| { 50 | let x = i32::try_from(x).unwrap() + bbox.min.x; 51 | let y = 8 + i32::try_from(y).unwrap() + bbox.min.y; 52 | if x < 0 || x >= 8 || y < 0 || y >= 8 { 53 | return; 54 | } 55 | 56 | // Sometimes the value is negative zero or slightly above 1.0 (e.g. 1.000000001) 57 | // We clamp it to be certain that the conversion below works as expected. 58 | let value = value.clamp(0.0, 1.0); 59 | 60 | let value = (value * 255.0) as u8; 61 | let b_pos = usize::from(ascii_chr) * 8 * 8 + usize::try_from(x + y * 8).unwrap(); 62 | out_data[b_pos] = value; 63 | }); 64 | } 65 | 66 | out_data 67 | } 68 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/arm/executor.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Futures executor that works on bare metal. 17 | 18 | use alloc::sync::Arc; 19 | use core::{ 20 | arch::asm, 21 | future::Future, 22 | sync::atomic, 23 | task::{Context, Poll}, 24 | }; 25 | use futures::task::{waker, ArcWake}; 26 | 27 | /// Waits for the `Future` to resolve to a value. 28 | /// 29 | /// This function is similar to [`futures::executor::block_on`]. 30 | pub fn block_on(future: impl Future) -> R { 31 | futures::pin_mut!(future); 32 | 33 | let local_wake = Arc::new(LocalWake { 34 | woken_up: atomic::AtomicBool::new(false), 35 | }); 36 | 37 | let waker = waker(local_wake.clone()); 38 | let mut context = Context::from_waker(&waker); 39 | 40 | loop { 41 | if let Poll::Ready(val) = Future::poll(future.as_mut(), &mut context) { 42 | return val; 43 | } 44 | 45 | // Loop until `woken_up` is true. 46 | loop { 47 | if local_wake 48 | .woken_up 49 | .compare_exchange( 50 | true, 51 | false, 52 | atomic::Ordering::Acquire, 53 | atomic::Ordering::Acquire, 54 | ) 55 | .is_ok() 56 | { 57 | break; 58 | } 59 | 60 | // Enter a low-power state and wait for an event to happen. 61 | // 62 | // ARM CPUs have a non-accessible 1bit "event register" that is set when an event 63 | // happens and cleared only by the `wfe` instruction. 64 | // 65 | // Thanks to this, if an event happens between the moment when we check the value of 66 | // `local_waken.woken_up` and the moment when we call `wfe`, then the `wfe` 67 | // instruction will immediately return and we will check the value again. 68 | unsafe { asm!("wfe", options(nomem, nostack, preserves_flags)) } 69 | } 70 | } 71 | } 72 | 73 | struct LocalWake { 74 | woken_up: atomic::AtomicBool, 75 | } 76 | 77 | impl ArcWake for LocalWake { 78 | fn wake_by_ref(arc_self: &Arc) { 79 | unsafe { 80 | arc_self.woken_up.store(true, atomic::Ordering::Release); 81 | // Wakes up all the CPUs that called `wfe`. 82 | // Note that this wakes up *all* CPUs, but the ARM architecture doesn't provide any 83 | // way to target a single CPU for wake-up. 84 | asm!("dsb sy ; sev", options(nomem, nostack, preserves_flags)) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/arm/log.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Panic handling code. 17 | 18 | use crate::klog::KLogger; 19 | 20 | use core::{ 21 | arch::asm, 22 | fmt::{self, Write as _}, 23 | }; 24 | use redshirt_kernel_log_interface::ffi::KernelLogMethod; 25 | use spinning_top::Spinlock; 26 | 27 | pub static PANIC_LOGGER: KLogger = KLogger::disabled(); 28 | 29 | #[cfg(not(any(test, doc, doctest)))] 30 | #[panic_handler] 31 | fn panic(panic_info: &core::panic::PanicInfo) -> ! { 32 | // TODO: somehow freeze all CPUs? 33 | 34 | let mut printer = PANIC_LOGGER.panic_printer(); 35 | let _ = writeln!(printer, "Kernel panic!"); 36 | let _ = writeln!(printer, "{}", panic_info); 37 | let _ = writeln!(printer, ""); 38 | 39 | // Freeze forever. 40 | loop { 41 | unsafe { 42 | asm!("wfe", options(nomem, nostack, preserves_flags)); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/arm/misc.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | // TODO: figure out how to remove these 17 | 18 | #[cfg(target_arch = "aarch64")] 19 | #[no_mangle] 20 | pub extern "C" fn fmod(x: f64, y: f64) -> f64 { 21 | libm::fmod(x, y) 22 | } 23 | #[cfg(target_arch = "aarch64")] 24 | #[no_mangle] 25 | pub extern "C" fn fmodf(x: f32, y: f32) -> f32 { 26 | libm::fmodf(x, y) 27 | } 28 | #[no_mangle] 29 | pub extern "C" fn fmin(a: f64, b: f64) -> f64 { 30 | libm::fmin(a, b) 31 | } 32 | #[no_mangle] 33 | pub extern "C" fn fminf(a: f32, b: f32) -> f32 { 34 | libm::fminf(a, b) 35 | } 36 | #[no_mangle] 37 | pub extern "C" fn fmax(a: f64, b: f64) -> f64 { 38 | libm::fmax(a, b) 39 | } 40 | #[no_mangle] 41 | pub extern "C" fn fmaxf(a: f32, b: f32) -> f32 { 42 | libm::fmaxf(a, b) 43 | } 44 | #[no_mangle] 45 | pub extern "C" fn __aeabi_d2f(a: f64) -> f32 { 46 | libm::trunc(a) as f32 // TODO: correct? 47 | } 48 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/arm/time_aarch64.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #![cfg(target_arch = "aarch64")] 17 | 18 | //! This module is a draft. 19 | // TODO: implement properly 20 | 21 | use alloc::sync::Arc; 22 | use core::{ 23 | arch::asm, 24 | future::Future, 25 | pin::Pin, 26 | task::{Context, Poll}, 27 | }; 28 | 29 | pub struct TimeControl {} 30 | 31 | pub struct TimerFuture {} 32 | 33 | impl TimeControl { 34 | pub unsafe fn init() -> Arc { 35 | Arc::new(TimeControl {}) 36 | } 37 | 38 | pub fn monotonic_clock(self: &Arc) -> u128 { 39 | unsafe { 40 | // TODO: stub 41 | let val: u64; 42 | asm!("mrs {}, CNTPCT_EL0", out(reg) val, options(nostack, nomem, preserves_flags)); 43 | u128::from(val) 44 | } 45 | } 46 | 47 | pub fn timer(self: &Arc, deadline: u128) -> TimerFuture { 48 | TimerFuture {} 49 | } 50 | } 51 | 52 | impl Future for TimerFuture { 53 | type Output = (); 54 | 55 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> { 56 | Poll::Pending 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/riscv/executor.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Futures executor that works on bare metal. 17 | 18 | use alloc::sync::Arc; 19 | use core::arch::asm; 20 | use core::future::Future; 21 | use core::sync::atomic; 22 | use core::task::{Context, Poll}; 23 | use futures::task::{waker, ArcWake}; 24 | 25 | /// Waits for the `Future` to resolve to a value. 26 | /// 27 | /// This function is similar to [`futures::executor::block_on`]. 28 | pub fn block_on(future: impl Future) -> R { 29 | futures::pin_mut!(future); 30 | 31 | let local_wake = Arc::new(LocalWake { 32 | woken_up: atomic::AtomicBool::new(false), 33 | }); 34 | 35 | let waker = waker(local_wake.clone()); 36 | let mut context = Context::from_waker(&waker); 37 | 38 | loop { 39 | if let Poll::Ready(val) = Future::poll(future.as_mut(), &mut context) { 40 | return val; 41 | } 42 | 43 | // Loop until `woken_up` is true. 44 | loop { 45 | if local_wake 46 | .woken_up 47 | .compare_exchange( 48 | true, 49 | false, 50 | atomic::Ordering::Acquire, 51 | atomic::Ordering::Acquire, 52 | ) 53 | .is_ok() 54 | { 55 | break; 56 | } 57 | 58 | // Enter a low-power state and wait for an event to happen. 59 | // TODO: can an interrupt happen between `local_wake` and here? 60 | // contrary to other platforms, the manual doesn't mention anything about enabling 61 | // instructions having a delay 62 | unsafe { asm!("wfi", options(nomem, nostack, preserves_flags)) } 63 | } 64 | } 65 | } 66 | 67 | struct LocalWake { 68 | woken_up: atomic::AtomicBool, 69 | } 70 | 71 | impl ArcWake for LocalWake { 72 | fn wake_by_ref(arc_self: &Arc) { 73 | arc_self.woken_up.store(true, atomic::Ordering::Release); 74 | // TODO: there doesn't seem to be a standard way to wake up another processor 75 | // For now we are single-CPUed. 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/riscv/log.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Panic handling code. 17 | 18 | use crate::klog::KLogger; 19 | 20 | use core::arch::asm; 21 | use core::fmt::{self, Write as _}; 22 | use redshirt_kernel_log_interface::ffi::KernelLogMethod; 23 | use spinning_top::Spinlock; 24 | 25 | pub static PANIC_LOGGER: KLogger = KLogger::disabled(); 26 | 27 | #[cfg(not(any(test, doc, doctest)))] 28 | #[panic_handler] 29 | fn panic(panic_info: &core::panic::PanicInfo) -> ! { 30 | // TODO: somehow freeze all CPUs? 31 | 32 | let mut printer = PANIC_LOGGER.panic_printer(); 33 | let _ = writeln!(printer, "Kernel panic!"); 34 | let _ = writeln!(printer, "{}", panic_info); 35 | let _ = writeln!(printer, ""); 36 | 37 | // Freeze forever. 38 | loop { 39 | unsafe { 40 | asm!("ebreak ; wfi", options(nomem, nostack, preserves_flags)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/riscv/misc.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | // TODO: figure out how to remove these 17 | 18 | #[no_mangle] 19 | pub extern "C" fn fmod(x: f64, y: f64) -> f64 { 20 | libm::fmod(x, y) 21 | } 22 | #[no_mangle] 23 | pub extern "C" fn fmodf(x: f32, y: f32) -> f32 { 24 | libm::fmodf(x, y) 25 | } 26 | #[no_mangle] 27 | pub extern "C" fn fmin(a: f64, b: f64) -> f64 { 28 | libm::fmin(a, b) 29 | } 30 | #[no_mangle] 31 | pub extern "C" fn fminf(a: f32, b: f32) -> f32 { 32 | libm::fminf(a, b) 33 | } 34 | #[no_mangle] 35 | pub extern "C" fn fmax(a: f64, b: f64) -> f64 { 36 | libm::fmax(a, b) 37 | } 38 | #[no_mangle] 39 | pub extern "C" fn fmaxf(a: f32, b: f32) -> f32 { 40 | libm::fmaxf(a, b) 41 | } 42 | #[no_mangle] 43 | pub extern "C" fn __aeabi_d2f(a: f64) -> f32 { 44 | libm::trunc(a) as f32 // TODO: correct? 45 | } 46 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/x86_64/apic.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | // TODO: do re-exports here instead 17 | 18 | pub use local::ApicId; 19 | 20 | pub mod io_apic; 21 | pub mod io_apics; 22 | pub mod local; 23 | pub mod pic; 24 | pub mod timers; 25 | pub mod tsc_sync; 26 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/x86_64/apic/pic.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use x86_64::structures::port::PortWrite as _; 17 | 18 | /// Remap and disable the PIC. 19 | /// 20 | /// The PIC (Programmable Interrupt Controller) is the old chip responsible for triggering 21 | /// on the CPU interrupts coming from the hardware. 22 | /// 23 | /// Because of poor design decisions, it will by default trigger interrupts 0 to 15 on the CPU, 24 | /// which are normally reserved for software-related concerns. For example, the timer will by 25 | /// default trigger interrupt 8, which is also the double fault exception handler. 26 | /// 27 | /// In order to solve this issue, one has to reconfigure the PIC in order to make it trigger 28 | /// interrupts between 32 and 47 rather than 0 to 15. 29 | /// 30 | /// Note that this code disables the PIC altogether. Despite the PIC being disabled, it is 31 | /// still possible to receive spurious interrupts. Hence the remapping. 32 | /// 33 | /// # Safety 34 | /// 35 | /// This function is not thread-safe. It must only be called once simultaneously and while nothing 36 | /// else is accessing the PIC. 37 | /// 38 | pub unsafe fn init_and_disable_pic() { 39 | u8::write_to_port(0xa1, 0xff); 40 | u8::write_to_port(0x21, 0xff); 41 | u8::write_to_port(0x20, 0x10 | 0x01); 42 | u8::write_to_port(0xa0, 0x10 | 0x01); 43 | u8::write_to_port(0x21, 0x20); 44 | u8::write_to_port(0xa1, 0x28); 45 | u8::write_to_port(0x21, 4); 46 | u8::write_to_port(0xa1, 2); 47 | u8::write_to_port(0x21, 0x01); 48 | u8::write_to_port(0xa1, 0x01); 49 | u8::write_to_port(0xa1, 0xff); 50 | u8::write_to_port(0x21, 0xff); 51 | } 52 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/x86_64/gdt.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! In the 16bits and 32bits modes of the x86/x86_64 architecture, memory can be divided into 17 | //! *segments*. Each segment has a base address, a length, and a few miscellaneous 18 | //! characteristics. 19 | //! 20 | //! In 32bits modes, the processor holds in a register called the GDTR the location of a data 21 | //! structure named the GDT (Global Descriptor Table). When the CS, DS, ES, FS, GS, or SS register 22 | //! is loaded with a non-zero value, the processor loads from the GDT the characteristics of the 23 | //! corresponding segment. 24 | //! 25 | //! Segmentation is a deprecated feature in 64bits mode. While loading the value of the segment 26 | //! registers works the same ways as in 32bits mode, the processor then ignores these registers 27 | //! altogether when performing memory accesses. 28 | //! For this reason, most operating systems don't rely on memory segmentation, even in 32bits 29 | //! modes. 30 | //! 31 | //! However, because processors don't immediately start in 64bits mode, one can never completely 32 | //! ignore segmentation. 33 | //! In order to switch to 64bits mode, one must load the CS register with a segment whose 34 | //! descriptor has a certain bit set. This bit determined whether the processor should run in 35 | //! extended-32bits or 64bits mode. 36 | 37 | /// Global Descriptor Table (GDT) with two entries: 38 | /// 39 | /// - Since loading a zero value in a segment register doesn't perform any actual loading, the 40 | /// first entry is a dummy entry. 41 | /// - The second entry is a code segment with the `L` bit set to 1, indicating a 64-bit code 42 | /// segment. 43 | /// 44 | /// In order to switch to 64bits mode, load the `GDTR` with this table, then load the value `8` in 45 | /// the `CS` register. 46 | /// 47 | /// The memory address is guaranteed to fit in 32bits. 48 | pub static GDT: Gdt = Gdt([0, (1 << 53) | (1 << 47) | (1 << 44) | (1 << 43)]); 49 | 50 | // TODO: assert that GDT has a 32bits memory address, once Rust makes this possible 51 | // see https://github.com/rust-lang/rust/issues/51910 52 | 53 | /// Opaque type of the GDT table. 54 | pub struct Gdt([u64; 2]); 55 | 56 | /// Pointer to [`GDT`] suitable for the `lgdt` instruction. 57 | /// 58 | /// # 32-bit vs 64-bit LGDT instruction 59 | /// 60 | /// In 32-bit mode the LGDT instruction expects a 32-bits GDT address, while in 64-bit mode it 61 | /// expects as 64-bits GDT address. 62 | /// 63 | /// The pointer below contains a 64-bits-long address, but with an address that is guaranteed to 64 | /// fit in 32 bits. In other words, the 32 upper bits are 0s. Since x86/x86_64 is a little endian 65 | /// platform, this pointer works for both the 32-bits and 64-bits versions of the LGDT 66 | /// instruction. 67 | /// 68 | /// # Example 69 | /// 70 | /// ```ignore 71 | /// asm!("lgdt {gdt_ptr}", gdt_ptr = sym GDT_POINTER); 72 | /// ``` 73 | /// 74 | pub static GDT_POINTER: GdtPtr = GdtPtr(GdtPtr2 { 75 | _size: 15, 76 | _pointer: &GDT, 77 | }); 78 | 79 | /// Opaque type of the GDT pointer. 80 | #[repr(align(8))] 81 | pub struct GdtPtr(GdtPtr2); 82 | 83 | // We need a second inner type in order to be able to apply both `repr(packed)` and 84 | // `repr(align(8))`. 85 | #[repr(packed)] 86 | struct GdtPtr2 { 87 | _size: u16, 88 | // TODO: must be 64bits, as explained above; see https://github.com/rust-lang/rust/issues/51910 89 | _pointer: *const Gdt, 90 | } 91 | 92 | // TODO: remove once `GdtPtr2::_pointer` is a u64 93 | unsafe impl Send for GdtPtr {} 94 | unsafe impl Sync for GdtPtr {} 95 | -------------------------------------------------------------------------------- /kernel/standalone/src/arch/x86_64/panic.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Panic handling code. 17 | 18 | use crate::klog::KLogger; 19 | 20 | use core::fmt::Write as _; 21 | 22 | pub static PANIC_LOGGER: KLogger = KLogger::disabled(); 23 | 24 | #[cfg(not(any(test, doc, doctest)))] 25 | #[panic_handler] 26 | fn panic(panic_info: &core::panic::PanicInfo) -> ! { 27 | let mut printer = PANIC_LOGGER.panic_printer(); 28 | let _ = writeln!(printer, "Kernel panic!"); 29 | let _ = writeln!(printer, "{}", panic_info); 30 | let _ = writeln!(printer, ""); 31 | drop(printer); 32 | 33 | // Freeze forever. 34 | loop { 35 | x86_64::instructions::interrupts::disable(); 36 | x86_64::instructions::hlt(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /kernel/standalone/src/klog.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Kernel logs handling. 17 | //! 18 | //! This module handles the way the kernel prints logs. It provides the [`KLogger`] structure 19 | //! that needs to be configured with a certain logging output method, and is then capable of 20 | //! outputting logs. 21 | //! 22 | //! # Panic-free code 23 | //! 24 | //! The code within this module is designed to be as panic-free as possible. In other words, you 25 | //! can assume that a [`KLogger`] will be capable of printing a panic message without itself 26 | //! triggering a nested panic. In particular, none of the code within this module does any heap 27 | //! allocation. 28 | 29 | pub use logger::KLogger; 30 | pub use native::KernelLogNativeProgram; 31 | 32 | mod logger; 33 | mod native; 34 | mod video; 35 | -------------------------------------------------------------------------------- /kernel/standalone/src/klog/native.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Native program that handles the `kernel_log` interface. 17 | 18 | use crate::arch::PlatformSpecific; 19 | 20 | use alloc::sync::Arc; 21 | use core::{pin::Pin, str}; 22 | use redshirt_core::{extrinsics::Extrinsics, system::NativeInterfaceMessage}; 23 | 24 | /// State machine for `kernel_log` interface messages handling. 25 | pub struct KernelLogNativeProgram { 26 | /// Platform-specific hooks. 27 | platform_specific: Pin>, 28 | /// Lock used to ensure ordering of logs messages. 29 | lock: spinning_top::Spinlock<()>, 30 | } 31 | 32 | impl KernelLogNativeProgram { 33 | /// Initializes the native program. 34 | pub fn new(platform_specific: Pin>) -> Self { 35 | KernelLogNativeProgram { 36 | platform_specific, 37 | lock: spinning_top::Spinlock::new(()), 38 | } 39 | } 40 | 41 | pub fn interface_message(&self, message: NativeInterfaceMessage) { 42 | let _lock = self.lock.lock(); 43 | let message = message.extract(); 44 | match message.0.get(0) { 45 | Some(0) => { 46 | // Log message. 47 | let message = &message.0[1..]; 48 | if message.is_ascii() { 49 | self.platform_specific 50 | .write_log(str::from_utf8(message).unwrap()); 51 | } 52 | } 53 | Some(1) => { 54 | // New log method. 55 | unimplemented!(); // TODO: 56 | /*if let Ok(method) = KernelLogMethod::decode(&message.0[1..]) { 57 | self.klogger.set_method(method); 58 | if let Some(message_id) = notification.message_id { 59 | self.pending_messages_tx.unbounded_send((message_id, Ok(().encode()))) 60 | } 61 | } else { 62 | if let Some(message_id) = notification.message_id { 63 | self.pending_messages_tx.unbounded_send((message_id, Err(()))) 64 | } 65 | }*/ 66 | } 67 | _ => {} 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /kernel/standalone/src/mem_alloc.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use core::ops::Range; 17 | 18 | /// Initialize the memory allocator. 19 | /// 20 | /// Pass to this function a list of memory ranges that are available for use. 21 | /// 22 | /// After this function returns, you can use heap allocations. 23 | /// 24 | /// > **Note**: It is "safe" to try to perform memory allocations before this function has been 25 | /// > called, but doing so will result in a panic. 26 | /// 27 | /// # Panics 28 | /// 29 | /// Panics if `range.end` is inferior to `range.start` for any of the elements. 30 | /// 31 | /// # Safety 32 | /// 33 | /// The memory ranges have to be RAM or behave like RAM (i.e. both readable and writable, 34 | /// consistent, and so on). The memory ranges must not be touched by anything (other than the 35 | /// allocator) afterwards. 36 | /// 37 | pub unsafe fn initialize(ranges: impl Iterator>) { 38 | // We choose the largest range. 39 | let range = ranges.max_by_key(|r| { 40 | assert!(r.end >= r.start); 41 | r.end - r.start 42 | }); 43 | 44 | let range = match range { 45 | Some(r) => r, 46 | // If the iterator was empty, return with initializing the allocator. 47 | None => return, 48 | }; 49 | 50 | // Don't initialize the allocator if all the ranges were 0. 51 | if range.start == range.end { 52 | return; 53 | } 54 | 55 | assert!(range.end >= range.start); 56 | ALLOCATOR.lock().init(range.start, range.end - range.start); 57 | } 58 | 59 | #[global_allocator] 60 | static ALLOCATOR: linked_list_allocator::LockedHeap = linked_list_allocator::LockedHeap::empty(); 61 | -------------------------------------------------------------------------------- /kernel/standalone/src/pci.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | pub mod native; 17 | pub mod pci; 18 | -------------------------------------------------------------------------------- /kernel/standalone/src/random.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | pub mod native; 17 | pub mod rng; 18 | -------------------------------------------------------------------------------- /kernel/standalone/src/random/native.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Native program that handles the `random` interface. 17 | 18 | use crate::{arch::PlatformSpecific, random::rng::KernelRng}; 19 | 20 | use alloc::{sync::Arc, vec}; 21 | use core::pin::Pin; 22 | use crossbeam_queue::SegQueue; 23 | use rand_core::RngCore as _; 24 | use redshirt_core::{ 25 | extrinsics::Extrinsics, system::NativeInterfaceMessage, Decode as _, Encode as _, 26 | EncodedMessage, 27 | }; 28 | use redshirt_random_interface::ffi::{GenerateResponse, RandomMessage}; 29 | 30 | /// State machine for `random` interface messages handling. 31 | pub struct RandomNativeProgram { 32 | /// Queue of random number generators. If it is empty, we generate a new one. 33 | rngs: SegQueue, 34 | /// Platform-specific hooks. 35 | platform_specific: Pin>, 36 | } 37 | 38 | impl RandomNativeProgram { 39 | /// Initializes the new state machine for random messages handling. 40 | pub fn new(platform_specific: Pin>) -> Self { 41 | RandomNativeProgram { 42 | rngs: SegQueue::new(), 43 | platform_specific, 44 | } 45 | } 46 | 47 | /// Fills the given buffer with random bytes. 48 | pub fn fill_bytes(&self, out: &mut [u8]) { 49 | let mut rng = if let Some(rng) = self.rngs.pop() { 50 | rng 51 | } else { 52 | KernelRng::new(self.platform_specific.clone()) 53 | }; 54 | 55 | rng.fill_bytes(out); 56 | self.rngs.push(rng); 57 | } 58 | 59 | pub fn interface_message( 60 | &self, 61 | message: NativeInterfaceMessage, 62 | ) -> Result { 63 | match RandomMessage::decode(message.extract()) { 64 | Ok(RandomMessage::Generate { len }) => { 65 | let mut out = vec![0; usize::from(len)]; 66 | self.fill_bytes(&mut out); 67 | Ok(GenerateResponse { result: out }.encode()) 68 | } 69 | Err(_) => Err(()), 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /kernel/standalone/src/time.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Implements the `time` interface. 17 | 18 | use crate::arch::PlatformSpecific; 19 | 20 | use alloc::{boxed::Box, sync::Arc}; 21 | use core::pin::Pin; 22 | use futures::{prelude::*, stream::FuturesUnordered, task::Poll}; 23 | use redshirt_core::{ 24 | extrinsics::Extrinsics, system::NativeInterfaceMessage, Decode as _, Encode as _, 25 | EncodedMessage, MessageId, 26 | }; 27 | use redshirt_time_interface::ffi::TimeMessage; 28 | use spinning_top::Spinlock; 29 | 30 | /// State machine for `time` interface messages handling. 31 | pub struct TimeHandler { 32 | /// Platform-specific hooks. 33 | platform_specific: Pin>, 34 | /// List of active timers. 35 | timers: Spinlock + Send>>>>, 36 | } 37 | 38 | impl TimeHandler { 39 | /// Initializes the new state machine for time accesses. 40 | pub fn new(platform_specific: Pin>) -> Self { 41 | TimeHandler { 42 | platform_specific, 43 | timers: Spinlock::new(FuturesUnordered::new()), 44 | } 45 | } 46 | 47 | pub fn interface_message( 48 | &self, 49 | message_id: MessageId, 50 | message: NativeInterfaceMessage, 51 | ) -> Option> { 52 | match TimeMessage::decode(message.extract()) { 53 | Ok(TimeMessage::GetMonotonic) => { 54 | let now = self.platform_specific.as_ref().monotonic_clock(); 55 | Some(Ok(now.encode())) 56 | } 57 | Ok(TimeMessage::WaitMonotonic(value)) => { 58 | let timers = self.timers.lock(); 59 | timers.push( 60 | self.platform_specific 61 | .as_ref() 62 | .timer(value) 63 | .map(move |_| message_id) 64 | .boxed(), 65 | ); 66 | None 67 | } 68 | Err(_) => Some(Err(())), 69 | } 70 | } 71 | 72 | pub async fn next_response(&self) -> (MessageId, EncodedMessage) { 73 | future::poll_fn(move |cx| { 74 | let mut timers = self.timers.lock(); 75 | if timers.is_empty() { 76 | return Poll::Pending; 77 | } 78 | 79 | let message_id = match timers.poll_next_unpin(cx) { 80 | Poll::Ready(Some(id)) => id, 81 | Poll::Ready(None) => unreachable!(), 82 | Poll::Pending => return Poll::Pending, 83 | }; 84 | 85 | Poll::Ready((message_id, ().encode())) 86 | }) 87 | .await 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /kernel/standalone/vcr_osd_mono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/kernel/standalone/vcr_osd_mono.ttf -------------------------------------------------------------------------------- /programs/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | # Note: this file exists in order to provide a more convenient development environment in the 2 | # redshirt repository. It is not mandatory to put a similar file next to programs developed for 3 | # redshirt. The redshirt programs builder automatically makes sure (in `redshirt-core`) makes sure 4 | # that the module is built with the appropriate options. 5 | 6 | [build] 7 | target = "wasm32-wasip1" 8 | 9 | [target.'wasm32-wasip1'] 10 | rustflags = ["-C", "link-arg=--export-table", "-C", "link-arg=--import-memory"] 11 | -------------------------------------------------------------------------------- /programs/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /programs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "compositor", 4 | "diagnostics-http-server", 5 | "dummy-system-time", 6 | "e1000", 7 | "hello-world", 8 | "network-manager", 9 | "log-to-kernel", 10 | "pci-printer", 11 | "rpi-framebuffer", 12 | "stub", 13 | "third-party/wasm-timer", 14 | "vga-vbe", 15 | ] 16 | 17 | [profile.dev] 18 | opt-level = 1 19 | 20 | [profile.dev.package."*"] 21 | opt-level = 3 22 | 23 | [profile.test.package."*"] 24 | opt-level = 3 25 | 26 | [profile.release] 27 | opt-level = 3 28 | lto = true 29 | codegen-units = 1 30 | panic = 'abort' 31 | 32 | [patch.crates-io] 33 | wasm-timer = { path = "./third-party/wasm-timer" } 34 | -------------------------------------------------------------------------------- /programs/compositor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "compositor" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [dependencies] 10 | ahash = { version = "0.6.2", default-features = false } 11 | futures = "0.3.21" 12 | hashbrown = { version = "0.12.0", default-features = false } 13 | rand = "0.8.5" 14 | redshirt-framebuffer-interface = { path = "../../interface-wrappers/framebuffer" } 15 | redshirt-interface-interface = { path = "../../interface-wrappers/interface" } 16 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 17 | redshirt-time-interface = { path = "../../interface-wrappers/time" } 18 | redshirt-video-output-interface = { path = "../../interface-wrappers/video-output" } 19 | -------------------------------------------------------------------------------- /programs/compositor/src/rect.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use core::cmp; 17 | 18 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 19 | pub struct Rect { 20 | pub x: u32, 21 | pub y: u32, 22 | pub width: u32, 23 | pub height: u32, 24 | } 25 | 26 | impl Rect { 27 | /// Returns the intersection between this rectangle and another. 28 | /// 29 | /// Returns `None` if the two rectangles don't overlap. 30 | pub fn intersection(&self, other: &Rect) -> Option { 31 | let (x, width) = line_intersect(self.x, self.width, other.x, other.width)?; 32 | let (y, height) = line_intersect(self.y, self.height, other.y, other.height)?; 33 | 34 | Some(Rect { 35 | x, 36 | y, 37 | width, 38 | height, 39 | }) 40 | } 41 | } 42 | 43 | fn line_intersect(base: u32, len: u32, other_base: u32, other_len: u32) -> Option<(u32, u32)> { 44 | if base < other_base { 45 | let overlap_len = len.checked_sub(other_base - base)?; 46 | Some((other_base, cmp::min(overlap_len, other_len))) 47 | } else { 48 | let overlap_len = other_len.checked_sub(base - other_base)?; 49 | Some((base, cmp::min(overlap_len, len))) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /programs/diagnostics-http-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diagnostics-http-server" 3 | version = "0.1.0" 4 | authors = ["Pierre Krieger "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | futures = "0.3.21" 10 | hyper = { version = "0.14.17", default-features = false, features = ["server", "http1"] } 11 | log = "0.4.14" 12 | redshirt-kernel-debug-interface = { path = "../../interface-wrappers/kernel-debug" } 13 | redshirt-log-interface = { path = "../../interface-wrappers/log" } 14 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 15 | redshirt-tcp-interface = { path = "../../interface-wrappers/tcp" } 16 | -------------------------------------------------------------------------------- /programs/dummy-system-time/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dummy-system-time" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [dependencies] 10 | redshirt-interface-interface = { path = "../../interface-wrappers/interface" } 11 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 12 | redshirt-system-time-interface = { path = "../../interface-wrappers/system-time" } 13 | -------------------------------------------------------------------------------- /programs/dummy-system-time/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use redshirt_interface_interface::DecodedInterfaceOrDestroyed; 17 | use redshirt_syscalls::Decode as _; 18 | use redshirt_system_time_interface::ffi as sys_time_ffi; 19 | 20 | fn main() { 21 | redshirt_syscalls::block_on(async_main()) 22 | } 23 | 24 | async fn async_main() { 25 | let mut registration = 26 | redshirt_interface_interface::register_interface(sys_time_ffi::INTERFACE) 27 | .await 28 | .unwrap(); 29 | 30 | loop { 31 | let interface_event = registration.next_message_raw().await; 32 | let msg = match interface_event { 33 | DecodedInterfaceOrDestroyed::Interface(msg) => msg, 34 | DecodedInterfaceOrDestroyed::ProcessDestroyed(_) => continue, 35 | }; 36 | 37 | let msg_data = sys_time_ffi::TimeMessage::decode(msg.actual_data).unwrap(); 38 | let sys_time_ffi::TimeMessage::GetSystem = msg_data; 39 | 40 | if let Some(id) = msg.message_id { 41 | redshirt_interface_interface::emit_answer(id, &0u128); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /programs/e1000/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "e1000" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [dependencies] 10 | derive_more = "0.99.17" 11 | futures = "0.3.21" 12 | redshirt-ethernet-interface = { path = "../../interface-wrappers/ethernet" } 13 | redshirt-hardware-interface = { path = "../../interface-wrappers/hardware" } 14 | redshirt-pci-interface = { path = "../../interface-wrappers/pci" } 15 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 16 | redshirt-time-interface = { path = "../../interface-wrappers/time" } 17 | smallvec = "1.8.0" 18 | -------------------------------------------------------------------------------- /programs/hello-world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-world" 3 | version = "0.1.0" 4 | authors = ["Pierre Krieger "] 5 | edition = "2018" 6 | publish = false 7 | -------------------------------------------------------------------------------- /programs/hello-world/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | fn main() { 17 | println!("hello world"); 18 | } 19 | -------------------------------------------------------------------------------- /programs/log-to-kernel/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "log-to-kernel" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [dependencies] 10 | redshirt-interface-interface = { path = "../../interface-wrappers/interface" } 11 | redshirt-kernel-log-interface = { path = "../../interface-wrappers/kernel-log" } 12 | redshirt-log-interface = { path = "../../interface-wrappers/log" } 13 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 14 | -------------------------------------------------------------------------------- /programs/log-to-kernel/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Implements the log interface by redirecting the logs as kernel logs. 17 | 18 | use redshirt_log_interface::ffi; 19 | use redshirt_syscalls::Decode as _; 20 | 21 | fn main() { 22 | redshirt_syscalls::block_on(async_main()); 23 | } 24 | 25 | async fn async_main() -> ! { 26 | let mut registration = redshirt_interface_interface::register_interface(ffi::INTERFACE) 27 | .await 28 | .unwrap(); 29 | 30 | loop { 31 | let msg = match registration.next_message_raw().await { 32 | redshirt_interface_interface::DecodedInterfaceOrDestroyed::Interface(m) => m, 33 | redshirt_interface_interface::DecodedInterfaceOrDestroyed::ProcessDestroyed(_) => { 34 | continue 35 | } 36 | }; 37 | 38 | assert_eq!(msg.interface, ffi::INTERFACE); 39 | 40 | if let Ok(message) = ffi::DecodedLogMessage::decode(msg.actual_data) { 41 | let level = match message.level() { 42 | ffi::Level::Error => "ERR ", 43 | ffi::Level::Warn => "WARN", 44 | ffi::Level::Info => "INFO", 45 | ffi::Level::Debug => "DEBG", 46 | ffi::Level::Trace => "TRCE", 47 | }; 48 | 49 | let kernel_message = 50 | format!("[{:?}] [{}] {}", msg.emitter_pid, level, message.message()); 51 | redshirt_kernel_log_interface::log(kernel_message.as_bytes()); 52 | } else { 53 | let kernel_message = format!("[{:?}] Bad log message", msg.emitter_pid); 54 | redshirt_kernel_log_interface::log(kernel_message.as_bytes()); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /programs/network-manager/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "network-manager" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [dependencies] 10 | fnv = { version = "1.0.7", default-features = false } 11 | futures = "0.3" 12 | hashbrown = { version = "0.12.0", default-features = false } 13 | log = "0.4" 14 | parity-scale-codec = "1.3.6" 15 | rand = "0.8.5" 16 | redshirt-ethernet-interface = { path = "../../interface-wrappers/ethernet" } 17 | redshirt-interface-interface = { path = "../../interface-wrappers/interface" } 18 | redshirt-log-interface = { path = "../../interface-wrappers/log" } # TODO: remove 19 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 20 | redshirt-tcp-interface = { path = "../../interface-wrappers/tcp" } 21 | redshirt-time-interface = { path = "../../interface-wrappers/time" } 22 | thiserror = "1.0.30" 23 | 24 | [dependencies.smoltcp] 25 | version = "0.7.5" 26 | default-features = false 27 | features = ["ethernet", "proto-dhcpv4", "proto-ipv4", "proto-ipv6", "socket-udp", "socket-tcp", "std"] 28 | -------------------------------------------------------------------------------- /programs/network-manager/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | mod interface; 17 | mod manager; 18 | mod port_assign; 19 | 20 | pub use manager::{NetworkManager, NetworkManagerEvent, SocketId, TcpSocket}; 21 | -------------------------------------------------------------------------------- /programs/network-manager/src/port_assign.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use hashbrown::HashSet; 17 | use rand::distributions::{Distribution as _, Uniform}; 18 | 19 | /// Port assignment system. Keeps track of which port is used. 20 | /// 21 | /// This struct doesn't know and doesn't care whether it is used by TCP, UDP, or something else. 22 | /// It is expected that one instance of this struct exists for each protocol. 23 | pub struct PortAssign { 24 | occupied: HashSet, 25 | } 26 | 27 | impl PortAssign { 28 | /// Builds a new [`PortAssign`] with no port assigned. 29 | pub fn new() -> PortAssign { 30 | PortAssign { 31 | occupied: Default::default(), 32 | } 33 | } 34 | 35 | /// Try to reserve a specific port. Returns an error if the port was already reserved. 36 | pub fn reserve(&mut self, port: u16) -> Result<(), ()> { 37 | if self.occupied.insert(port) { 38 | Ok(()) 39 | } else { 40 | Err(()) 41 | } 42 | } 43 | 44 | /// Reserves a port whose value is superior to `min`. Returns `None` if no port is available. 45 | pub fn reserve_any(&mut self, min: u16) -> Option { 46 | if (min..=u16::max_value()).all(|p| self.occupied.contains(&p)) { 47 | return None; 48 | } 49 | 50 | loop { 51 | let attempt = 52 | Uniform::new_inclusive(min, u16::max_value()).sample(&mut rand::thread_rng()); 53 | if self.occupied.insert(attempt) { 54 | debug_assert!(attempt >= min); 55 | return Some(attempt); 56 | } 57 | } 58 | } 59 | 60 | /// Un-reserves a port. Returns an error if the port wasn't reserved. 61 | pub fn free(&mut self, port: u16) -> Result<(), ()> { 62 | if self.occupied.remove(&port) { 63 | Ok(()) 64 | } else { 65 | Err(()) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /programs/pci-printer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pci-printer" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [dependencies] 10 | fnv = { version = "1.0.7", default-features = false } 11 | hashbrown = { version = "0.12.0", default-features = false } 12 | lazy_static = "1" 13 | log = "0.4" 14 | redshirt-pci-interface = { path = "../../interface-wrappers/pci" } 15 | redshirt-log-interface = { path = "../../interface-wrappers/log" } 16 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 17 | parity-scale-codec = { version = "1.3.6", default-features = false } 18 | 19 | [build-dependencies] 20 | regex = "1.4.6" 21 | -------------------------------------------------------------------------------- /programs/pci-printer/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | use regex::Regex; 17 | use std::{env, fs::File, io::Write, path::Path}; 18 | 19 | fn main() { 20 | let out_dir = env::var("OUT_DIR").unwrap(); 21 | let dest_path = Path::new(&out_dir).join("build-pci.rs"); 22 | let mut f = File::create(&dest_path).unwrap(); 23 | 24 | write!(f, r#" 25 | fn build_pci_info() -> hashbrown::HashMap<(u16, u16), (&'static str, &'static str), fnv::FnvBuildHasher> {{ 26 | [ 27 | "# 28 | ) 29 | .unwrap(); 30 | 31 | let mut current_vendor_id = None::; 32 | let mut current_vendor_name = None; 33 | 34 | let vendor_regex = Regex::new(r"^(\w{4}) (.*)$").unwrap(); 35 | let device_regex = Regex::new(r"^\t(\w{4}) (.*)$").unwrap(); 36 | 37 | for line in include_str!("build/pci.ids").lines() { 38 | // Strip comments. 39 | let line = if let Some(pos) = line.find('#') { 40 | line.split_at(pos).0 41 | } else { 42 | line 43 | }; 44 | 45 | if let Some(regex_match) = device_regex.captures(line) { 46 | let device_id = u16::from_str_radix(regex_match.get(1).unwrap().as_str(), 16).unwrap(); 47 | let device_name = regex_match.get(2).unwrap().as_str(); 48 | 49 | write!( 50 | f, 51 | r##" 52 | ((0x{:x}, 0x{:x}), (r#"{}"#, r#"{}"#)), 53 | "##, 54 | current_vendor_id.unwrap(), 55 | device_id, 56 | current_vendor_name.clone().unwrap(), 57 | device_name 58 | ) 59 | .unwrap(); 60 | } else if let Some(regex_match) = vendor_regex.captures(line) { 61 | current_vendor_id = 62 | Some(u16::from_str_radix(regex_match.get(1).unwrap().as_str(), 16).unwrap()); 63 | current_vendor_name = Some(regex_match.get(2).unwrap().as_str().to_string()); 64 | } else if !line.is_empty() && !line.starts_with("\t\t") { 65 | write!( 66 | f, 67 | r##" 68 | // Couldn't parse line: {} 69 | "##, 70 | line 71 | ) 72 | .unwrap(); 73 | } 74 | } 75 | 76 | write!( 77 | f, 78 | r#" 79 | ].iter().cloned().collect() 80 | }} 81 | "# 82 | ) 83 | .unwrap(); 84 | } 85 | -------------------------------------------------------------------------------- /programs/rpi-framebuffer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rpi-framebuffer" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [dependencies] 10 | redshirt-hardware-interface = { path = "../../interface-wrappers/hardware" } 11 | redshirt-interface-interface = { path = "../../interface-wrappers/interface" } 12 | redshirt-log-interface = { path = "../../interface-wrappers/log" } 13 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 14 | parity-scale-codec = { version = "1.3.6", default-features = false } 15 | -------------------------------------------------------------------------------- /programs/rpi-framebuffer/src/mailbox.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | // TODO: more docs at https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface 17 | 18 | use std::convert::TryFrom as _; 19 | 20 | /// Message to write to the mailbox, or read from the mailbox. 21 | /// 22 | /// A message is composed of a channel number and data. 23 | pub struct Message { 24 | /// Raw representation of the message, as written in memory or read from memory. 25 | /// 26 | /// 4 lowest bits are the channel. 28 highest bits are the data. 27 | value: u32, 28 | } 29 | 30 | impl Message { 31 | /// Builds a message from its raw components. 32 | /// 33 | /// # Panic 34 | /// 35 | /// Panics if `data` doesn't fit in 28 bits or `channel` doesn't fit in 4 bits. 36 | /// 37 | pub fn new(channel: u8, data: u32) -> Message { 38 | assert!(channel < (1 << 4)); 39 | assert!(data < (1 << 28)); 40 | Message { 41 | value: (data << 4) | u32::from(channel), 42 | } 43 | } 44 | 45 | /// Returns the channel of this message. 46 | pub fn channel(&self) -> u8 { 47 | u8::try_from(self.value & 0xf).unwrap() 48 | } 49 | 50 | /// Returns the data of this message. 51 | pub fn data(&self) -> u32 { 52 | self.value >> 4 53 | } 54 | } 55 | 56 | const BASE_IO_PERIPH: u64 = 0x3f000000; // 0x20000000 for raspi 1 57 | const MAILBOX_BASE: u64 = BASE_IO_PERIPH + 0xb880; 58 | 59 | /// Reads one message from the mailbox. 60 | pub async fn read_mailbox() -> Message { 61 | unsafe { 62 | // Wait for status register to indicate a message. 63 | loop { 64 | let val = redshirt_hardware_interface::read_one_u32(MAILBOX_BASE + 0x18).await; 65 | if val & (1 << 30) == 0 { 66 | break; 67 | } 68 | } 69 | 70 | let mut read = redshirt_hardware_interface::HardwareOperationsBuilder::new(); 71 | let mut out = [0]; 72 | read.read_u32(MAILBOX_BASE + 0x0, &mut out); 73 | read.send().await; 74 | Message { value: out[0] } 75 | } 76 | } 77 | 78 | /// Writes one message from the mailbox. 79 | pub async fn write_mailbox(message: Message) { 80 | unsafe { 81 | // Wait for status register to indicate a message. 82 | loop { 83 | let val = redshirt_hardware_interface::read_one_u32(MAILBOX_BASE + 0x18).await; 84 | if val & (1 << 31) == 0 { 85 | break; 86 | } 87 | } 88 | 89 | redshirt_hardware_interface::write_one_u32(MAILBOX_BASE + 0x20, message.value); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /programs/rpi-framebuffer/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | // TODO: doc https://jsandler18.github.io/ 17 | 18 | use parity_scale_codec::DecodeAll; 19 | use std::{convert::TryFrom as _, fmt}; 20 | 21 | mod mailbox; 22 | mod property; 23 | 24 | fn main() { 25 | redshirt_syscalls::block_on(async_main()); 26 | } 27 | 28 | async fn async_main() { 29 | property::init().await; 30 | } 31 | -------------------------------------------------------------------------------- /programs/stub/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stub" 3 | version = "0.1.0" 4 | authors = ["Pierre Krieger "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | futures = { version = "0.3.21", default-features = false } 10 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 11 | wee_alloc = "0.4.5" 12 | -------------------------------------------------------------------------------- /programs/stub/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! Draft for a module, with the purpose of inspecting the WASM output. 17 | //! 18 | //! This module doesn't do much by itself and isn't meant to be actually executed. 19 | //! This code exists with the intent of being compiled in release mode so that one can inspect 20 | //! the WASM output. 21 | 22 | #![no_std] 23 | #![no_main] 24 | 25 | #[global_allocator] 26 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 27 | 28 | #[cfg(not(any(test, doc, doctest)))] 29 | #[panic_handler] 30 | fn panic(_: &core::panic::PanicInfo) -> ! { 31 | unsafe { core::hint::unreachable_unchecked() } 32 | } 33 | 34 | extern crate alloc; 35 | use alloc::vec; 36 | use futures::prelude::*; 37 | 38 | #[no_mangle] 39 | fn _start(_: isize, _: *const *const u8) -> isize { 40 | redshirt_syscalls::block_on(async_main()); 41 | 0 42 | } 43 | 44 | fn async_main() -> impl Future { 45 | let interface = redshirt_syscalls::InterfaceHash::from_raw_hash([ 46 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 47 | 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 48 | 0x36, 0x37, 49 | ]); 50 | 51 | redshirt_syscalls::next_interface_message().then(move |msg| { 52 | let msg = match msg { 53 | redshirt_syscalls::DecodedInterfaceOrDestroyed::Interface(m) => m, 54 | redshirt_syscalls::DecodedInterfaceOrDestroyed::ProcessDestroyed(_) => panic!(), 55 | }; 56 | assert_eq!(msg.interface, interface); 57 | assert_eq!( 58 | msg.actual_data, 59 | redshirt_syscalls::EncodedMessage(vec![1, 2, 3, 4, 5, 6, 7, 8]) 60 | ); 61 | future::ready(()) 62 | }) 63 | } 64 | -------------------------------------------------------------------------------- /programs/third-party/README.md: -------------------------------------------------------------------------------- 1 | Contains libraries that were not written specifically for this OS, but that need some tweaks in 2 | order to properly run on redshirt. 3 | -------------------------------------------------------------------------------- /programs/third-party/wasm-timer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-timer" 3 | version = "0.2.4" 4 | authors = ["Pierre Krieger "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | pin-project = "1.0.10" 9 | 10 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 11 | futures-timer = "3.0" 12 | 13 | [target.'cfg(target_arch = "wasm32")'.dependencies] 14 | redshirt-time-interface = { path = "../../../interface-wrappers/time" } 15 | -------------------------------------------------------------------------------- /programs/third-party/wasm-timer/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2020 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #[cfg(target_arch = "wasm32")] 17 | pub use redshirt_time_interface::Instant; 18 | #[cfg(not(target_arch = "wasm32"))] 19 | pub use std::time::Instant; 20 | 21 | use std::{fmt, future::Future, io, pin::Pin, task::Context, task::Poll, time::Duration}; 22 | 23 | /// Mimics the API of `futures_timer::Delay`. 24 | #[pin_project::pin_project] 25 | pub struct Delay { 26 | #[cfg(not(target_arch = "wasm32"))] 27 | #[pin] 28 | inner: futures_timer::Delay, 29 | #[cfg(not(target_arch = "wasm32"))] 30 | when: Instant, 31 | #[cfg(target_arch = "wasm32")] 32 | #[pin] 33 | inner: redshirt_time_interface::Delay, 34 | } 35 | 36 | #[cfg(target_arch = "wasm32")] 37 | impl Delay { 38 | pub fn new(dur: Duration) -> Delay { 39 | Delay { 40 | inner: redshirt_time_interface::Delay::new(dur), 41 | } 42 | } 43 | 44 | pub fn new_at(at: Instant) -> Delay { 45 | Delay { 46 | inner: redshirt_time_interface::Delay::new_at(at), 47 | } 48 | } 49 | 50 | pub fn when(&self) -> Instant { 51 | self.inner.when() 52 | } 53 | 54 | pub fn reset(&mut self, dur: Duration) { 55 | *self = Delay::new(dur); 56 | } 57 | 58 | pub fn reset_at(&mut self, at: Instant) { 59 | *self = Delay::new_at(at); 60 | } 61 | } 62 | 63 | #[cfg(not(target_arch = "wasm32"))] 64 | impl Delay { 65 | pub fn new(dur: Duration) -> Delay { 66 | // Instant is grabbed before creating the future. 67 | let when = Instant::now() + dur; 68 | Delay { 69 | inner: futures_timer::Delay::new(dur), 70 | when, 71 | } 72 | } 73 | 74 | pub fn new_at(at: Instant) -> Delay { 75 | let now = Instant::now(); 76 | Delay { 77 | inner: futures_timer::Delay::new({ 78 | if at > now { 79 | at - now 80 | } else { 81 | Duration::new(0, 0) 82 | } 83 | }), 84 | when: at, 85 | } 86 | } 87 | 88 | pub fn when(&self) -> Instant { 89 | self.when 90 | } 91 | 92 | pub fn reset(&mut self, dur: Duration) { 93 | *self = Delay::new(dur); 94 | } 95 | 96 | pub fn reset_at(&mut self, at: Instant) { 97 | self.reset({ 98 | let now = Instant::now(); 99 | if at > now { 100 | at - now 101 | } else { 102 | Duration::new(0, 0) 103 | } 104 | }); 105 | } 106 | } 107 | 108 | impl fmt::Debug for Delay { 109 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 110 | fmt::Debug::fmt(&self.inner, f) 111 | } 112 | } 113 | 114 | impl Future for Delay { 115 | type Output = io::Result<()>; 116 | 117 | fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { 118 | let mut this = self.project(); 119 | Future::poll(this.inner.as_mut(), cx).map(Ok) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /programs/vga-vbe/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vga-vbe" 3 | version = "0.1.0" 4 | license = "GPL-3.0-or-later" 5 | authors = ["Pierre Krieger "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [dependencies] 10 | derive_more = "0.99.17" 11 | fnv = { version = "1.0.7", default-features = false } 12 | hashbrown = { version = "0.12.0", default-features = false } 13 | iced-x86 = { version = "1.14.0", default-features = false, features = ["decoder", "instr_info", "op_code_info", "std"] } 14 | lazy_static = "1" 15 | log = "0.4" 16 | redshirt-hardware-interface = { path = "../../interface-wrappers/hardware" } 17 | redshirt-interface-interface = { path = "../../interface-wrappers/interface" } 18 | redshirt-kernel-log-interface = { path = "../../interface-wrappers/kernel-log" } 19 | redshirt-log-interface = { path = "../../interface-wrappers/log" } 20 | redshirt-pci-interface = { path = "../../interface-wrappers/pci" } 21 | redshirt-syscalls = { path = "../../interface-wrappers/syscalls" } 22 | redshirt-video-output-interface = { path = "../../interface-wrappers/video-output" } 23 | 24 | [dev-dependencies] 25 | futures = "0.3.21" 26 | -------------------------------------------------------------------------------- /programs/vga-vbe/src/interpreter/i386.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/programs/vga-vbe/src/interpreter/i386.pdf -------------------------------------------------------------------------------- /programs/vga-vbe/src/interpreter/test-mem.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaka/redshirt/9bf924ce2997ea28383aab3980aa48ed4713f055/programs/vga-vbe/src/interpreter/test-mem.bin -------------------------------------------------------------------------------- /programs/vga-vbe/src/interpreter/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2021 Pierre Krieger 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #![cfg(test)] 17 | 18 | use super::Interpreter; 19 | 20 | #[test] 21 | fn basic_entry_point_works() { 22 | futures::executor::block_on(async move { 23 | let mut interpreter = 24 | Interpreter::from_memory(include_bytes!("test-mem.bin").to_vec()).await; 25 | interpreter.disable_io_operations(); 26 | interpreter.set_ax(0x4f00); 27 | interpreter.set_es_di(0x50, 0x0); 28 | interpreter.write_memory(0x500, &b"VBE2"[..]); 29 | interpreter.int10h().unwrap(); 30 | assert_eq!(interpreter.ax(), 0x4f); 31 | 32 | let mut info_out = [0; 512]; 33 | interpreter.read_memory(0x500, &mut info_out[..]); 34 | assert_eq!(&info_out[0..4], b"VESA"); 35 | 36 | let video_modes = { 37 | let vmodes_seg = interpreter.read_memory_u16(0x510); 38 | let vmodes_ptr = interpreter.read_memory_u16(0x50e); 39 | let mut vmodes_addr = (u32::from(vmodes_seg) << 4) + u32::from(vmodes_ptr); 40 | let mut modes = Vec::new(); 41 | loop { 42 | let mode = interpreter.read_memory_u16(vmodes_addr); 43 | if mode == 0xffff { 44 | break modes; 45 | } 46 | vmodes_addr += 2; 47 | modes.push(mode); 48 | } 49 | }; 50 | log::info!("Video modes = {:?}", video_modes); 51 | 52 | let total_memory = u32::from(interpreter.read_memory_u16(0x512)) * 64 * 1024; 53 | log::info!("Total memory = 0x{:x}", total_memory); 54 | 55 | let oem_string = { 56 | let seg = interpreter.read_memory_u16(0x508); 57 | let ptr = interpreter.read_memory_u16(0x506); 58 | let addr = (u32::from(seg) << 4) + u32::from(ptr); 59 | interpreter.read_memory_nul_terminated_str(addr) 60 | }; 61 | log::info!("OEM string: {}", oem_string); 62 | 63 | for mode in video_modes.iter().take(1) { 64 | // TODO: remove take(1) 65 | interpreter.set_ax(0x4f01); 66 | interpreter.set_cx(*mode); 67 | interpreter.set_es_di(0x50, 0x0); 68 | interpreter.int10h().unwrap(); 69 | log::error!("EAX after call: 0x{:x}", interpreter.ax()); 70 | 71 | let mut info_out = [0; 256]; 72 | interpreter.read_memory(0x500, &mut info_out[..]); 73 | log::debug!("Mode info: {:?}", &info_out[..]); 74 | } 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2025-03-14" 3 | targets = ["wasm32-wasip1"] 4 | --------------------------------------------------------------------------------