├── .cargo └── config.toml ├── .github ├── scripts │ ├── add-doc-index.sh │ └── make-qemu.sh └── workflows │ ├── build.yml │ ├── docs.yml │ └── test.yml ├── .gitignore ├── .gitmodules ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README-arch.md ├── README.md ├── config └── machine-features.toml ├── docs ├── README-C910.md ├── README-D1.md ├── README-fu740.md ├── README-visionfive.md ├── README_EN.md ├── for-developers.md ├── img │ ├── c906-amo-1.jpg │ ├── c906-amo-2.jpg │ ├── c906-clear-bss.jpeg │ ├── c910-jtag.jpg │ ├── c910-light.jpeg │ ├── c910-linux-pg.png │ ├── c910-maee.jpeg │ ├── c910-mxstatus.png │ ├── c910-pte-flags.png │ ├── c910-run-uart.png │ └── c910-zcore-run.png ├── porting-rv64.md ├── structure.svg └── visionfive.jpg ├── drivers ├── Cargo.toml └── src │ ├── builder │ ├── devicetree.rs │ └── mod.rs │ ├── bus │ ├── mod.rs │ └── pci.rs │ ├── display │ ├── mod.rs │ ├── resource │ │ └── cursor.bin │ └── uefi.rs │ ├── input │ ├── input_event_codes.rs │ ├── mod.rs │ └── mouse.rs │ ├── io │ ├── mmio.rs │ ├── mod.rs │ └── pmio.rs │ ├── irq │ ├── gic_400.rs │ ├── mod.rs │ ├── riscv_intc.rs │ ├── riscv_plic.rs │ └── x86_apic │ │ ├── consts.rs │ │ ├── ioapic.rs │ │ ├── lapic.rs │ │ └── mod.rs │ ├── lib.rs │ ├── mock │ ├── display.rs │ ├── graphic │ │ ├── mod.rs │ │ └── sdl.rs │ ├── input.rs │ ├── mod.rs │ └── uart.rs │ ├── net │ ├── e1000.rs │ ├── loopback.rs │ ├── mod.rs │ ├── realtek │ │ ├── mii.rs │ │ ├── mod.rs │ │ ├── rtl8211f.rs │ │ └── utils.rs │ └── rtlx.rs │ ├── nvme │ ├── interface.rs │ ├── mod.rs │ └── nvme_queue.rs │ ├── prelude.rs │ ├── scheme │ ├── block.rs │ ├── display.rs │ ├── event.rs │ ├── input.rs │ ├── irq.rs │ ├── mod.rs │ ├── net.rs │ └── uart.rs │ ├── uart │ ├── buffered.rs │ ├── mod.rs │ ├── uart_16550.rs │ ├── uart_allwinner.rs │ ├── uart_pl011.rs │ └── uart_u740.rs │ ├── utils │ ├── devicetree.rs │ ├── event_listener.rs │ ├── graphic_console.rs │ ├── id_allocator.rs │ ├── irq_manager.rs │ └── mod.rs │ └── virtio │ ├── blk.rs │ ├── console.rs │ ├── gpu.rs │ ├── input.rs │ └── mod.rs ├── kernel-hal ├── Cargo.toml └── src │ ├── bare │ ├── arch │ │ ├── aarch64 │ │ │ ├── config.rs │ │ │ ├── cpu.rs │ │ │ ├── drivers.rs │ │ │ ├── interrupt.rs │ │ │ ├── mem.rs │ │ │ ├── mod.rs │ │ │ ├── timer.rs │ │ │ ├── trap.rs │ │ │ └── vm.rs │ │ ├── riscv │ │ │ ├── config.rs │ │ │ ├── cpu.rs │ │ │ ├── drivers.rs │ │ │ ├── interrupt.rs │ │ │ ├── mem.rs │ │ │ ├── mod.rs │ │ │ ├── sbi.rs │ │ │ ├── timer.rs │ │ │ ├── trap.rs │ │ │ └── vm.rs │ │ └── x86_64 │ │ │ ├── config.rs │ │ │ ├── cpu.rs │ │ │ ├── drivers.rs │ │ │ ├── interrupt.rs │ │ │ ├── mem.rs │ │ │ ├── mod.rs │ │ │ ├── special.rs │ │ │ ├── timer.rs │ │ │ ├── trap.rs │ │ │ └── vm.rs │ ├── boot.rs │ ├── mem.rs │ ├── mod.rs │ ├── net.rs │ ├── thread.rs │ └── timer.rs │ ├── common │ ├── addr.rs │ ├── console.rs │ ├── context.rs │ ├── defs.rs │ ├── future.rs │ ├── ipi.rs │ ├── mem.rs │ ├── mod.rs │ ├── thread.rs │ ├── user.rs │ ├── vdso.rs │ └── vm.rs │ ├── config.rs │ ├── drivers.rs │ ├── hal_fn.rs │ ├── kernel_handler.rs │ ├── lib.rs │ ├── libos │ ├── boot.rs │ ├── config.rs │ ├── cpu.rs │ ├── drivers.rs │ ├── dummy.rs │ ├── interrupt.rs │ ├── macos.rs │ ├── mem.rs │ ├── mock_mem.rs │ ├── mod.rs │ ├── net.rs │ ├── special.rs │ ├── thread.rs │ ├── timer.rs │ ├── vdso.rs │ └── vm.rs │ ├── macros.rs │ └── utils │ ├── init_once.rs │ ├── lazy_init.rs │ ├── mod.rs │ ├── mpsc_queue.rs │ └── page_table.rs ├── linux-object ├── Cargo.toml └── src │ ├── error.rs │ ├── fs │ ├── devfs │ │ ├── fbdev.rs │ │ ├── input │ │ │ ├── event.rs │ │ │ ├── mice.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── random.rs │ │ └── uartdev.rs │ ├── file.rs │ ├── ioctl.rs │ ├── mock.rs │ ├── mod.rs │ ├── pipe.rs │ ├── pseudo.rs │ ├── rcore_fs_wrapper.rs │ └── stdio.rs │ ├── ipc │ ├── mod.rs │ ├── semary.rs │ └── shared_mem.rs │ ├── lib.rs │ ├── loader │ ├── abi.rs │ └── mod.rs │ ├── net │ ├── mod.rs │ ├── netlink.rs │ ├── raw.rs │ ├── socket_address.rs │ ├── tcp.rs │ └── udp.rs │ ├── process.rs │ ├── signal │ ├── action.rs │ └── mod.rs │ ├── sync │ ├── event_bus.rs │ ├── mod.rs │ └── semaphore.rs │ ├── thread.rs │ └── time.rs ├── linux-syscall ├── Cargo.toml ├── build.rs ├── src │ ├── aarch64_syscall.h.in │ ├── file │ │ ├── dir.rs │ │ ├── fd.rs │ │ ├── file.rs │ │ ├── mod.rs │ │ ├── poll.rs │ │ └── stat.rs │ ├── ipc.rs │ ├── lib.rs │ ├── misc.rs │ ├── net.rs │ ├── riscv64_syscall.h.in │ ├── signal.rs │ ├── syscall.h.in │ ├── task.rs │ ├── time.rs │ └── vm.rs └── test │ ├── testpipe1.c │ ├── testpipe2.c │ ├── testpoll.c │ ├── testrandom.c │ ├── testselect.c │ ├── testsem1.c │ ├── testsem2.c │ ├── testshm1.c │ ├── testshm2.c │ └── testtime.c ├── loader ├── Cargo.toml ├── examples │ ├── linux-libos.rs │ └── zircon-libos.rs ├── src │ ├── lib.rs │ ├── linux.rs │ └── zircon.rs └── tests │ ├── linux.rs │ └── zircon.rs ├── prebuilt └── firmware │ ├── aarch64 │ ├── Boot.json │ ├── QEMU_EFI.fd │ └── aarch64_uefi.efi │ └── riscv │ ├── c910_fw_dynamic.bin │ ├── d1_fw_payload.elf │ ├── fu740_fdt.its │ ├── hifive-unmatched-a00.dtb │ ├── starfive.dtb │ └── starfive_fdt.its ├── rust-toolchain.toml ├── scripts ├── gen-prebuilt.sh ├── script.sh ├── zcore.patch └── zircon-libos.patch ├── tools └── docker │ ├── README.md │ ├── build_docker_image.sh │ ├── start_container.sh │ └── zcore-ubuntu.dockerfile ├── xtask ├── CHANGELOG.md ├── Cargo.toml ├── build.rs └── src │ ├── arch.rs │ ├── build.rs │ ├── commands.rs │ ├── dump.rs │ ├── errors.rs │ ├── linux │ ├── image.rs │ ├── mod.rs │ ├── opencv.rs │ └── test.rs │ └── main.rs ├── z-config ├── Cargo.toml └── src │ └── lib.rs ├── zCore ├── .gdbinit_riscv64 ├── .gdbinit_x86_64 ├── Cargo.toml ├── Makefile ├── aarch64.json ├── build.rs ├── rboot.conf ├── rboot.conf.default ├── riscv64.json ├── src │ ├── fs.rs │ ├── handler.rs │ ├── lang.rs │ ├── logging.rs │ ├── main.rs │ ├── memory.rs │ ├── memory_x86_64.rs │ ├── platform │ │ ├── aarch64 │ │ │ ├── consts.rs │ │ │ ├── entry.rs │ │ │ ├── linker.ld │ │ │ ├── mod.rs │ │ │ └── space.s │ │ ├── libos │ │ │ ├── consts.rs │ │ │ ├── entry.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── riscv │ │ │ ├── boot.asm │ │ │ ├── boot_page_table.rs │ │ │ ├── consts.rs │ │ │ ├── entry.rs │ │ │ ├── entry64.rs │ │ │ ├── linker.ld │ │ │ └── mod.rs │ │ └── x86 │ │ │ ├── consts.rs │ │ │ ├── entry.rs │ │ │ ├── linker.ld │ │ │ └── mod.rs │ └── utils.rs └── x86_64.json ├── zircon-object ├── Cargo.toml └── src │ ├── debuglog.rs │ ├── dev │ ├── bti.rs │ ├── interrupt │ │ ├── event_interrupt.rs │ │ ├── mod.rs │ │ ├── pci_interrupt.rs │ │ └── virtual_interrupt.rs │ ├── iommu.rs │ ├── mod.rs │ ├── pci │ │ ├── bus.rs │ │ ├── caps.rs │ │ ├── config.rs │ │ ├── mod.rs │ │ ├── nodes.rs │ │ ├── pci_init_args.rs │ │ └── pmio.rs │ ├── pmt.rs │ └── resource.rs │ ├── error.rs │ ├── hypervisor │ ├── guest.rs │ ├── mod.rs │ └── vcpu.rs │ ├── ipc │ ├── channel.rs │ ├── fifo.rs │ ├── mod.rs │ └── socket.rs │ ├── lib.rs │ ├── object │ ├── handle.rs │ ├── mod.rs │ ├── rights.rs │ └── signal.rs │ ├── signal │ ├── event.rs │ ├── eventpair.rs │ ├── futex.rs │ ├── mod.rs │ ├── port.rs │ ├── port_packet.rs │ └── timer.rs │ ├── task │ ├── exception.rs │ ├── job.rs │ ├── job_policy.rs │ ├── mod.rs │ ├── process.rs │ ├── suspend_token.rs │ ├── thread.rs │ └── thread │ │ └── thread_state.rs │ ├── util │ ├── block_range.rs │ ├── elf_loader.rs │ ├── kcounter.rs │ └── mod.rs │ └── vm │ ├── mod.rs │ ├── stream.rs │ ├── vmar.rs │ └── vmo │ ├── mod.rs │ ├── paged.rs │ ├── physical.rs │ └── slice.rs ├── zircon-syscall ├── Cargo.toml ├── build.rs └── src │ ├── channel.rs │ ├── consts.rs │ ├── cprng.rs │ ├── ddk.rs │ ├── debug.rs │ ├── debuglog.rs │ ├── exception.rs │ ├── fifo.rs │ ├── futex.rs │ ├── handle.rs │ ├── hypervisor.rs │ ├── lib.rs │ ├── object.rs │ ├── pci.rs │ ├── port.rs │ ├── resource.rs │ ├── signal.rs │ ├── socket.rs │ ├── stream.rs │ ├── system.rs │ ├── task.rs │ ├── time.rs │ ├── vmar.rs │ ├── vmo.rs │ └── zx-syscall-numbers.h └── zircon-user ├── .cargo └── config ├── Cargo.lock ├── Cargo.toml ├── Makefile ├── rust-toolchain.toml └── src └── bin └── hello.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | xtask = "run --package xtask --release --" 3 | git-proxy = "xtask git-proxy" 4 | zircon-init = "xtask zircon-init" 5 | update-all = "xtask update-all" 6 | 7 | check-style = "xtask check-style" 8 | 9 | rootfs = "xtask rootfs" 10 | musl-libs = "xtask musl-libs" 11 | opencv = "xtask opencv" 12 | ffmpeg = "xtask ffmpeg" 13 | libc-test = "xtask libc-test" 14 | other-test = "xtask other-test" 15 | image = "xtask image" 16 | 17 | linux-libos = "xtask linux-libos" 18 | 19 | asm = "xtask asm" 20 | bin = "xtask bin" 21 | qemu = "xtask qemu" 22 | gdb = "xtask gdb" 23 | -------------------------------------------------------------------------------- /.github/scripts/add-doc-index.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cat > target/doc/index.html << EOF 4 | 5 | 6 | 7 | Redirection 8 | 9 | 10 |

Redirecting to kernel_hal/index.html...

11 | 12 | 13 | EOF -------------------------------------------------------------------------------- /.github/scripts/make-qemu.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | wget https://download.qemu.org/qemu-$1.tar.xz 4 | tar -xJf qemu-$1.tar.xz 5 | cd qemu-$1 6 | ./configure --target-list=x86_64-softmmu,riscv64-softmmu,aarch64-softmmu 7 | make -j > /dev/null 2>&1 8 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy docs 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | env: 8 | rust_toolchain: nightly-2022-08-05 9 | 10 | jobs: 11 | doc: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - uses: actions-rs/toolchain@v1 17 | with: 18 | profile: minimal 19 | toolchain: ${{ env.rust_toolchain }} 20 | 21 | - name: Pull prebuilt images 22 | run: make zircon-init 23 | 24 | - name: Build docs 25 | run: | 26 | cargo doc --no-deps --all-features --workspace 27 | .github/scripts/add-doc-index.sh 28 | 29 | - name: Deploy to Github Pages 30 | if: ${{ github.ref == 'refs/heads/master' }} 31 | uses: JamesIves/github-pages-deploy-action@releases/v3 32 | with: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | BRANCH: gh-pages 35 | FOLDER: target/doc 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.*/* 2 | !.github/* 3 | !.cargo/* 4 | 5 | **/target 6 | *.img 7 | 8 | /ignored 9 | /rootfs 10 | # for aarch64 only 11 | /zCore/disk 12 | 13 | .DS_Store 14 | __pycache__ 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rboot"] 2 | path = rboot 3 | url = https://github.com/rcore-os/rboot.git 4 | [submodule "tests"] 5 | path = tests 6 | url = https://github.com/rcore-os/zcore-tests.git 7 | [submodule "libc-test"] 8 | path = libc-test 9 | url = https://github.com/rcore-os/libc-test 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "drivers", 4 | "kernel-hal", 5 | "zircon-object", 6 | "zircon-syscall", 7 | "linux-object", 8 | "linux-syscall", 9 | "loader", 10 | "zCore", 11 | "z-config", 12 | "xtask", 13 | ] 14 | default-members = ["xtask"] 15 | exclude = ["zircon-user", "rboot"] 16 | 17 | [profile.release] 18 | lto = true 19 | debug = true 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 rCore Developers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for top level of zCore 2 | 3 | ARCH ?= x86_64 4 | XTASK ?= 1 5 | 6 | STRIP := $(ARCH)-linux-musl-strip 7 | export PATH=$(shell printenv PATH):$(CURDIR)/ignored/target/$(ARCH)/$(ARCH)-linux-musl-cross/bin/ 8 | 9 | .PHONY: help zircon-init update rootfs libc-test other-test image check doc clean 10 | 11 | # print top level help 12 | help: 13 | cargo xtask 14 | 15 | # download zircon binaries 16 | zircon-init: 17 | cargo zircon-init 18 | 19 | # update toolchain and dependencies 20 | update: 21 | cargo update-all 22 | 23 | # put rootfs for linux mode 24 | rootfs: 25 | ifeq ($(XTASK), 1) 26 | cargo rootfs --arch $(ARCH) 27 | else ifeq ($(ARCH), riscv64) 28 | @rm -rf rootfs/riscv && mkdir -p rootfs/riscv/bin 29 | @wget https://github.com/rcore-os/busybox-prebuilts/raw/master/busybox-1.30.1-riscv64/busybox -O rootfs/riscv/bin/busybox 30 | @ln -s busybox rootfs/riscv/bin/ls 31 | endif 32 | 33 | # put libc tests into rootfs 34 | libc-test: 35 | cargo libc-test --arch $(ARCH) 36 | find rootfs/$(ARCH)/libc-test -type f \ 37 | -name "*so" -o -name "*exe" -exec $(STRIP) {} \; 38 | 39 | # put other tests into rootfs 40 | other-test: 41 | cargo other-test --arch $(ARCH) 42 | 43 | # build image from rootfs 44 | image: 45 | ifeq ($(XTASK), 1) 46 | cargo image --arch $(ARCH) 47 | else ifeq ($(ARCH), riscv64) 48 | @echo building riscv.img 49 | @rcore-fs-fuse zCore/riscv64.img rootfs/riscv zip 50 | @qemu-img resize -f raw zCore/riscv64.img +5M 51 | endif 52 | 53 | # check code style 54 | check: 55 | cargo check-style 56 | 57 | # build and open project document 58 | doc: 59 | cargo doc --open 60 | 61 | # clean targets 62 | clean: 63 | cargo clean 64 | rm -f *.asm 65 | rm -rf rootfs 66 | rm -rf zCore/disk 67 | find zCore -maxdepth 1 -name "*.img" -delete 68 | find zCore -maxdepth 1 -name "*.bin" -delete 69 | 70 | # delete targets, including those that are large and compile slowly 71 | cleanup: clean 72 | rm -rf ignored/target 73 | 74 | # delete everything, including origin files that are downloaded directly 75 | clean-everything: clean 76 | rm -rf ignored 77 | 78 | # rt-test: 79 | # cd rootfs/x86_64 && git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/clrkwllms/rt-tests --depth 1 80 | # cd rootfs/x86_64/rt-tests && make 81 | # echo x86 gcc build rt-test,now need manual modificy. 82 | -------------------------------------------------------------------------------- /config/machine-features.toml: -------------------------------------------------------------------------------- 1 | [qemu.virt-riscv64] 2 | arch = "riscv64" 3 | 4 | [qemu.virt-aarch64] 5 | arch = "aarch64" 6 | 7 | [qemu.virt-x86_64] 8 | arch = "x86_64" 9 | 10 | [allwinner.nezha] 11 | arch = "riscv64" 12 | link-user-img = "zCore/riscv64.img" 13 | pci-support = false 14 | features = ["allwinner-drivers"] 15 | 16 | [cvitek.cr1825] 17 | arch = "riscv64" 18 | link-user-img = "zCore/riscv64.img" 19 | pci-support = false 20 | features = ["thead-maee"] 21 | 22 | [starfive.visionfive] 23 | arch = "riscv64" 24 | link-user-img = "zCore/riscv64.img" 25 | pci-support = false 26 | 27 | [sifive.fu740] 28 | arch = "riscv64" 29 | link-user-img = "zCore/riscv64.img" 30 | pci-support = true 31 | features = ["fu740-drivers"] 32 | -------------------------------------------------------------------------------- /docs/README-fu740.md: -------------------------------------------------------------------------------- 1 | # zCore on riscv64 for fu740 2 | 3 | ### 编译zCore for fu740系统镜像 4 | 5 | 先在源码根目录下编译 riscv64 的文件系统。 6 | 7 | 然后进入子目录 zCore 编译内核,会生成系统镜像`zcore-fu740.itb` 8 | 9 | 系统镜像会包含fu740板子的设备树, dtb设备树可以从fu740自带的Linux中的`/boot`目录中获取; 10 | 也可以从sifive官方镜像中获取:https://github.com/sifive/freedom-u-sdk/releases/download/2022.04.00/demo-coreip-cli-unmatched-2022.04.00.rootfs.wic.xz 11 | 12 | ```sh 13 | make riscv-image 14 | cd zCore 15 | make build MODE=release LINUX=1 ARCH=riscv64 PLATFORM=fu740 16 | ``` 17 | 18 | ### 基于U-Boot启动系统镜像 19 | 20 | 首先搭建一台tftp服务器, 例如,在Linux服务器中安装`tftpd-hpa`, 一般tftp服务的目录会在`/srv/tftp/`; 21 | 22 | 然后把编译出的zCore for fu740系统镜像`zcore-fu740.itb`拷贝到tftp服务目录; 23 | 24 | 开发板fu740开机,并进入U-Boot命令行: 25 | 26 | ``` 27 | # 配置开发板IP地址和服务器IP地址 28 | setenv ipaddr 29 | setenv serverip 30 | 31 | # 通过tftp协议加载系统镜像 32 | tftp 0xa0000000 zcore-fu740.itb 33 | 34 | # 运行 35 | bootm 0xa0000000 36 | ``` 37 | 38 | ### fu740资料汇集 39 | Unmatched fu740 板子资料整理, 请见: 40 | https://github.com/oscomp/DocUnmatchedU740/blob/main/unmatched.md 41 | -------------------------------------------------------------------------------- /docs/img/c906-amo-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c906-amo-1.jpg -------------------------------------------------------------------------------- /docs/img/c906-amo-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c906-amo-2.jpg -------------------------------------------------------------------------------- /docs/img/c906-clear-bss.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c906-clear-bss.jpeg -------------------------------------------------------------------------------- /docs/img/c910-jtag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c910-jtag.jpg -------------------------------------------------------------------------------- /docs/img/c910-light.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c910-light.jpeg -------------------------------------------------------------------------------- /docs/img/c910-linux-pg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c910-linux-pg.png -------------------------------------------------------------------------------- /docs/img/c910-maee.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c910-maee.jpeg -------------------------------------------------------------------------------- /docs/img/c910-mxstatus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c910-mxstatus.png -------------------------------------------------------------------------------- /docs/img/c910-pte-flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c910-pte-flags.png -------------------------------------------------------------------------------- /docs/img/c910-run-uart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c910-run-uart.png -------------------------------------------------------------------------------- /docs/img/c910-zcore-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/img/c910-zcore-run.png -------------------------------------------------------------------------------- /docs/visionfive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/docs/visionfive.jpg -------------------------------------------------------------------------------- /drivers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zcore-drivers" 3 | version = "0.1.0" 4 | authors = ["Yuekai Jia "] 5 | edition = "2018" 6 | description = "Device drivers of zCore" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [features] 11 | graphic = ["rcore-console"] 12 | mock = ["async-std", "sdl2"] 13 | virtio = ["virtio-drivers"] 14 | loopback = [] 15 | no-pci = [] 16 | 17 | # special drivers for hardwares 18 | 19 | allwinner = ["d1-pac"] 20 | fu740 = [] 21 | 22 | [dependencies] 23 | log = "0.4" 24 | cfg-if = "1.0" 25 | bitflags = "1.3" 26 | lazy_static = "1.4" 27 | numeric-enum-macro = "0.2" 28 | device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2f2e55f" } 29 | bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "88e871a5" } 30 | pci = { git = "https://github.com/elliott10/pci-rs", rev = "8f33774b" } 31 | virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2aaf7d6", optional = true } 32 | rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "ca5b1bc", optional = true } 33 | lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "8486b8" } 34 | isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers", rev = "f7cd97a8", features = [ 35 | "log", 36 | ] } 37 | smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = [ 38 | "log", 39 | "alloc", 40 | "verbose", 41 | "proto-ipv4", 42 | "proto-ipv6", 43 | "proto-igmp", 44 | "medium-ip", 45 | "medium-ethernet", 46 | "socket-raw", 47 | "socket-udp", 48 | "socket-tcp", 49 | "socket-icmp", 50 | "async", 51 | ] } 52 | d1-pac = { version = "0.0.27", optional = true } 53 | volatile = "0.3" 54 | 55 | # LibOS mode 56 | [target.'cfg(not(target_os = "none"))'.dependencies] 57 | async-std = { version = "1.10", optional = true } 58 | sdl2 = { version = "0.34", optional = true } 59 | 60 | [target.'cfg(target_arch = "x86_64")'.dependencies] 61 | acpi = "4.1" 62 | x2apic = "0.4" 63 | x86_64 = "0.14" 64 | 65 | [target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies] 66 | riscv = "0.9" 67 | -------------------------------------------------------------------------------- /drivers/src/builder/mod.rs: -------------------------------------------------------------------------------- 1 | //! Various builders to probe devices and create corresponding drivers 2 | //! (e.g. device tree, ACPI table, ...) 3 | 4 | mod devicetree; 5 | 6 | pub use devicetree::DevicetreeDriverBuilder; 7 | 8 | use crate::{PhysAddr, VirtAddr}; 9 | 10 | /// A trait implemented in kernel to translate device physical addresses to virtual 11 | /// addresses. 12 | pub trait IoMapper { 13 | /// Translate the device physical address to virtual address. If not mapped 14 | /// in the kernel page table, map the region specified by the given `size`. 15 | /// 16 | /// If an error accurs during translation or mapping, returns `None`. 17 | fn query_or_map(&self, paddr: PhysAddr, size: usize) -> Option; 18 | } 19 | -------------------------------------------------------------------------------- /drivers/src/bus/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] 2 | pub mod pci; 3 | 4 | pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { 5 | unsafe { drivers_phys_to_virt(paddr) } 6 | } 7 | 8 | pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { 9 | unsafe { drivers_virt_to_phys(vaddr) } 10 | } 11 | 12 | #[allow(unused)] 13 | extern "C" { 14 | fn drivers_dma_alloc(pages: usize) -> PhysAddr; 15 | fn drivers_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32; 16 | fn drivers_phys_to_virt(paddr: PhysAddr) -> VirtAddr; 17 | fn drivers_virt_to_phys(vaddr: VirtAddr) -> PhysAddr; 18 | } 19 | 20 | pub const PAGE_SIZE: usize = 4096; 21 | 22 | type VirtAddr = usize; 23 | type PhysAddr = usize; 24 | 25 | use core::ptr::{read_volatile, write_volatile}; 26 | #[inline(always)] 27 | pub fn write(addr: usize, content: T) { 28 | let cell = (addr) as *mut T; 29 | unsafe { 30 | write_volatile(cell, content); 31 | } 32 | } 33 | #[inline(always)] 34 | pub fn read(addr: usize) -> T { 35 | let cell = (addr) as *const T; 36 | unsafe { read_volatile(cell) } 37 | } 38 | -------------------------------------------------------------------------------- /drivers/src/display/mod.rs: -------------------------------------------------------------------------------- 1 | //! Only UEFI Display currently. 2 | 3 | mod uefi; 4 | 5 | pub use uefi::UefiDisplay; 6 | -------------------------------------------------------------------------------- /drivers/src/display/resource/cursor.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/drivers/src/display/resource/cursor.bin -------------------------------------------------------------------------------- /drivers/src/display/uefi.rs: -------------------------------------------------------------------------------- 1 | //! UEFI Graphics Output Protocol 2 | 3 | use crate::prelude::{DisplayInfo, FrameBuffer}; 4 | use crate::scheme::{DisplayScheme, Scheme}; 5 | 6 | pub struct UefiDisplay { 7 | info: DisplayInfo, 8 | } 9 | 10 | impl UefiDisplay { 11 | pub fn new(info: DisplayInfo) -> Self { 12 | Self { info } 13 | } 14 | } 15 | 16 | impl Scheme for UefiDisplay { 17 | fn name(&self) -> &str { 18 | "mock-display" 19 | } 20 | } 21 | 22 | impl DisplayScheme for UefiDisplay { 23 | #[inline] 24 | fn info(&self) -> DisplayInfo { 25 | self.info 26 | } 27 | 28 | #[inline] 29 | fn fb(&self) -> FrameBuffer { 30 | unsafe { 31 | FrameBuffer::from_raw_parts_mut(self.info.fb_base_vaddr as *mut u8, self.info.fb_size) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /drivers/src/input/mod.rs: -------------------------------------------------------------------------------- 1 | //! Only Mouse currently. 2 | 3 | mod mouse; 4 | 5 | pub mod input_event_codes; 6 | 7 | pub use mouse::{Mouse, MouseFlags, MouseState}; 8 | -------------------------------------------------------------------------------- /drivers/src/io/mmio.rs: -------------------------------------------------------------------------------- 1 | use super::Io; 2 | use core::ops::{BitAnd, BitOr, Not}; 3 | 4 | // 主存映射 I/O。 5 | /// Memory-mapped I/O. 6 | #[repr(transparent)] 7 | pub struct Mmio(T); 8 | 9 | impl Mmio { 10 | /// # Safety 11 | /// 12 | /// This function is unsafe because `base_addr` may be an arbitrary address. 13 | pub unsafe fn from_base_as<'a, R>(base_addr: usize) -> &'a mut R { 14 | assert_eq!(base_addr % core::mem::size_of::(), 0); 15 | &mut *(base_addr as *mut R) 16 | } 17 | 18 | /// # Safety 19 | /// 20 | /// This function is unsafe because `base_addr` may be an arbitrary address. 21 | pub unsafe fn from_base<'a>(base_addr: usize) -> &'a mut Self { 22 | Self::from_base_as(base_addr) 23 | } 24 | 25 | pub fn add<'a>(&self, offset: usize) -> &'a mut Self { 26 | unsafe { Self::from_base((&self.0 as *const T).add(offset) as _) } 27 | } 28 | } 29 | 30 | impl Io for Mmio 31 | where 32 | T: Copy + BitAnd + BitOr + Not, 33 | { 34 | type Value = T; 35 | 36 | fn read(&self) -> T { 37 | #[allow(clippy::let_and_return)] 38 | unsafe { 39 | let val = core::ptr::read_volatile(&self.0 as *const _); 40 | #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] 41 | core::arch::asm!("fence i,r"); 42 | val 43 | } 44 | } 45 | 46 | fn write(&mut self, value: T) { 47 | unsafe { 48 | #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] 49 | core::arch::asm!("fence w,o"); 50 | core::ptr::write_volatile(&mut self.0 as *mut _, value) 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /drivers/src/io/mod.rs: -------------------------------------------------------------------------------- 1 | // 封装对外设地址空间的访问,包括内存映射 IO 和端口映射 IO。 2 | // 3 | // 要了解这两种访问外设的方式,查看[维基百科](https://en.wikipedia.org/wiki/Memory-mapped_I/O)。 4 | //! Peripheral address space access, including memory-mapped IO and port-mapped IO. 5 | //! 6 | //! About these two methods of performing I/O, see [wikipedia](https://en.wikipedia.org/wiki/Memory-mapped_I/O). 7 | 8 | use core::ops::{BitAnd, BitOr, Not}; 9 | 10 | mod mmio; 11 | #[cfg(target_arch = "x86_64")] 12 | mod pmio; 13 | 14 | pub use mmio::Mmio; 15 | #[cfg(target_arch = "x86_64")] 16 | pub use pmio::Pmio; 17 | 18 | // 用于处理外设地址空间访问的接口。 19 | /// An interface for dealing with device address space access. 20 | pub trait Io { 21 | // 可访问的对象的类型。 22 | /// The type of object to access. 23 | type Value: Copy 24 | + BitAnd 25 | + BitOr 26 | + Not; 27 | 28 | // 从外设读取值。 29 | /// Reads value from device. 30 | fn read(&self) -> Self::Value; 31 | 32 | // 向外设写入值。 33 | /// Writes `value` to device. 34 | fn write(&mut self, value: Self::Value); 35 | } 36 | 37 | // 外设地址空间的一个只读单元。 38 | /// A readonly unit in device address space. 39 | #[repr(transparent)] 40 | pub struct ReadOnly(I); 41 | 42 | impl ReadOnly { 43 | // 构造外设地址空间的一个只读单元。 44 | /// Constructs a readonly unit in device address space. 45 | pub const fn new(inner: I) -> Self { 46 | Self(inner) 47 | } 48 | } 49 | 50 | impl ReadOnly { 51 | // 从外设读取值。 52 | /// Reads value from device. 53 | #[inline(always)] 54 | pub fn read(&self) -> I::Value { 55 | self.0.read() 56 | } 57 | } 58 | 59 | // 外设地址空间的一个只写单元。 60 | /// A write-only unit in device address space. 61 | #[repr(transparent)] 62 | pub struct WriteOnly(I); 63 | 64 | impl WriteOnly { 65 | // 构造外设地址空间的一个只写单元。 66 | /// Constructs a write-only unit in device address space. 67 | pub const fn new(inner: I) -> Self { 68 | Self(inner) 69 | } 70 | } 71 | 72 | impl WriteOnly { 73 | // 向外设写入值。 74 | /// Writes `value` to device. 75 | #[inline(always)] 76 | pub fn write(&mut self, value: I::Value) { 77 | self.0.write(value); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /drivers/src/irq/mod.rs: -------------------------------------------------------------------------------- 1 | //! External interrupt request and handle. 2 | 3 | cfg_if::cfg_if! { 4 | if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { 5 | mod riscv_intc; 6 | mod riscv_plic; 7 | 8 | /// Implementation of risc-v interrupt controller. 9 | #[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))] 10 | pub mod riscv { 11 | pub use super::riscv_intc::{Intc, ScauseIntCode}; 12 | pub use super::riscv_plic::Plic; 13 | } 14 | } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { 15 | mod x86_apic; 16 | /// Implementation of x86 Advanced Programmable Interrupt Controller. 17 | #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))] 18 | pub mod x86 { 19 | pub use super::x86_apic::Apic; 20 | } 21 | } else if #[cfg(target_arch = "aarch64")] { 22 | pub mod gic_400; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /drivers/src/irq/x86_apic/consts.rs: -------------------------------------------------------------------------------- 1 | // TODO: configurable 2 | 3 | pub const X86_INT_BASE: usize = 0x20; 4 | 5 | pub const X86_INT_LOCAL_APIC_BASE: usize = 0xf0; 6 | pub const X86_INT_APIC_SPURIOUS: usize = X86_INT_LOCAL_APIC_BASE; 7 | pub const X86_INT_APIC_TIMER: usize = X86_INT_LOCAL_APIC_BASE + 0x1; 8 | pub const X86_INT_APIC_ERROR: usize = X86_INT_LOCAL_APIC_BASE + 0x2; 9 | -------------------------------------------------------------------------------- /drivers/src/irq/x86_apic/lapic.rs: -------------------------------------------------------------------------------- 1 | use x2apic::lapic::{ 2 | xapic_base, LocalApic as LocalApicInner, LocalApicBuilder, TimerDivide, TimerMode, 3 | }; 4 | 5 | use super::{consts, Phys2VirtFn}; 6 | 7 | static mut LOCAL_APIC: Option = None; 8 | static mut BSP_ID: Option = None; 9 | 10 | pub struct LocalApic { 11 | inner: LocalApicInner, 12 | } 13 | 14 | impl LocalApic { 15 | pub unsafe fn get<'a>() -> &'a mut LocalApic { 16 | LOCAL_APIC 17 | .as_mut() 18 | .expect("Local APIC is not initialized by BSP") 19 | } 20 | 21 | pub unsafe fn init_bsp(phys_to_virt: Phys2VirtFn) { 22 | let base_vaddr = phys_to_virt(xapic_base() as usize); 23 | let mut inner = LocalApicBuilder::new() 24 | .timer_vector(consts::X86_INT_APIC_TIMER) 25 | .error_vector(consts::X86_INT_APIC_ERROR) 26 | .spurious_vector(consts::X86_INT_APIC_SPURIOUS) 27 | .set_xapic_base(base_vaddr as u64) 28 | .build() 29 | .unwrap_or_else(|err| panic!("{}", err)); 30 | inner.enable(); 31 | 32 | assert!(inner.is_bsp()); 33 | BSP_ID = Some((inner.id() >> 24) as u8); 34 | LOCAL_APIC = Some(LocalApic { inner }); 35 | } 36 | 37 | pub unsafe fn init_ap() { 38 | Self::get().inner.enable(); 39 | } 40 | 41 | pub fn bsp_id() -> u8 { 42 | unsafe { BSP_ID.unwrap() } 43 | } 44 | 45 | pub fn id(&mut self) -> u8 { 46 | unsafe { (self.inner.id() >> 24) as u8 } 47 | } 48 | 49 | pub fn eoi(&mut self) { 50 | unsafe { self.inner.end_of_interrupt() } 51 | } 52 | 53 | pub fn disable_timer(&mut self) { 54 | unsafe { self.inner.disable_timer() } 55 | } 56 | 57 | pub fn enable_timer(&mut self) { 58 | unsafe { self.inner.enable_timer() } 59 | } 60 | 61 | pub fn set_timer_mode(&mut self, mode: TimerMode) { 62 | unsafe { self.inner.set_timer_mode(mode) } 63 | } 64 | 65 | pub fn set_timer_divide(&mut self, divide: TimerDivide) { 66 | unsafe { self.inner.set_timer_divide(divide) } 67 | } 68 | 69 | pub fn set_timer_initial(&mut self, initial: u32) { 70 | unsafe { self.inner.set_timer_initial(initial) } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /drivers/src/mock/display.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | 3 | use crate::prelude::{ColorFormat, DisplayInfo, FrameBuffer}; 4 | use crate::scheme::{DisplayScheme, Scheme}; 5 | 6 | pub struct MockDisplay { 7 | info: DisplayInfo, 8 | fb: Vec, 9 | } 10 | 11 | impl MockDisplay { 12 | pub fn new(width: u32, height: u32, format: ColorFormat) -> Self { 13 | let fb_size = (width * height * format.bytes() as u32) as usize; 14 | let fb = vec![0; fb_size]; 15 | let info = DisplayInfo { 16 | width, 17 | height, 18 | format, 19 | fb_base_vaddr: fb.as_ptr() as usize, 20 | fb_size, 21 | }; 22 | Self { info, fb } 23 | } 24 | 25 | /// # Safety 26 | /// 27 | /// This function is unsafe, the caller must ensure the `ptr` points to the 28 | /// start of a valid frame buffer. 29 | pub unsafe fn from_raw_parts( 30 | width: u32, 31 | height: u32, 32 | format: ColorFormat, 33 | ptr: *mut u8, 34 | ) -> Self { 35 | let fb_size = (width * height * format.bytes() as u32) as usize; 36 | let fb = Vec::from_raw_parts(ptr, fb_size, fb_size); 37 | let info = DisplayInfo { 38 | width, 39 | height, 40 | format, 41 | fb_base_vaddr: fb.as_ptr() as usize, 42 | fb_size, 43 | }; 44 | Self { info, fb } 45 | } 46 | } 47 | 48 | impl Scheme for MockDisplay { 49 | fn name(&self) -> &str { 50 | "mock-display" 51 | } 52 | } 53 | 54 | impl DisplayScheme for MockDisplay { 55 | #[inline] 56 | fn info(&self) -> DisplayInfo { 57 | self.info 58 | } 59 | 60 | #[inline] 61 | fn fb(&self) -> FrameBuffer { 62 | unsafe { FrameBuffer::from_raw_parts_mut(self.fb.as_ptr() as _, self.info.fb_size) } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /drivers/src/mock/graphic/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod sdl; 2 | -------------------------------------------------------------------------------- /drivers/src/mock/input.rs: -------------------------------------------------------------------------------- 1 | use crate::input::input_event_codes::{ev::*, key::*, rel::*}; 2 | use crate::prelude::{CapabilityType, InputCapability, InputEvent}; 3 | use crate::scheme::{impl_event_scheme, InputScheme, Scheme}; 4 | use crate::utils::EventListener; 5 | 6 | #[derive(Default)] 7 | pub struct MockMouse { 8 | listener: EventListener, 9 | } 10 | 11 | impl_event_scheme!(MockMouse, InputEvent); 12 | 13 | impl Scheme for MockMouse { 14 | fn name(&self) -> &str { 15 | "mock-mouse-input" 16 | } 17 | } 18 | 19 | impl InputScheme for MockMouse { 20 | fn capability(&self, cap_type: CapabilityType) -> InputCapability { 21 | let mut cap = InputCapability::empty(); 22 | match cap_type { 23 | CapabilityType::Event => cap.set_all(&[EV_KEY, EV_REL]), 24 | CapabilityType::Key => cap.set_all(&[BTN_LEFT, BTN_RIGHT, BTN_MIDDLE]), 25 | CapabilityType::RelAxis => cap.set_all(&[REL_X, REL_Y, REL_HWHEEL]), 26 | _ => {} 27 | } 28 | cap 29 | } 30 | } 31 | 32 | #[derive(Default)] 33 | pub struct MockKeyboard { 34 | listener: EventListener, 35 | } 36 | 37 | impl_event_scheme!(MockKeyboard, InputEvent); 38 | 39 | impl Scheme for MockKeyboard { 40 | fn name(&self) -> &str { 41 | "mock-keyboard-input" 42 | } 43 | } 44 | 45 | impl InputScheme for MockKeyboard { 46 | fn capability(&self, cap_type: CapabilityType) -> InputCapability { 47 | let mut cap = InputCapability::empty(); 48 | match cap_type { 49 | CapabilityType::Event => cap.set(EV_KEY), 50 | CapabilityType::Key => { 51 | // TODO 52 | } 53 | _ => {} 54 | } 55 | cap 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /drivers/src/mock/mod.rs: -------------------------------------------------------------------------------- 1 | //! Mock devices, including display, input, uart and graphic. 2 | 3 | pub mod display; 4 | pub mod input; 5 | pub mod uart; 6 | 7 | #[cfg(any(feature = "graphic", doc))] 8 | #[doc(cfg(feature = "graphic"))] 9 | pub mod graphic; 10 | -------------------------------------------------------------------------------- /drivers/src/net/loopback.rs: -------------------------------------------------------------------------------- 1 | // smoltcp 2 | use smoltcp::{iface::Interface, phy::Loopback, time::Instant}; 3 | 4 | use crate::net::get_sockets; 5 | use alloc::sync::Arc; 6 | 7 | use alloc::string::String; 8 | use lock::Mutex; 9 | 10 | use crate::scheme::{NetScheme, Scheme}; 11 | use crate::{DeviceError, DeviceResult}; 12 | 13 | use alloc::vec::Vec; 14 | use smoltcp::wire::EthernetAddress; 15 | use smoltcp::wire::IpCidr; 16 | 17 | #[derive(Clone)] 18 | pub struct LoopbackInterface { 19 | pub iface: Arc>>, 20 | pub name: String, 21 | } 22 | 23 | impl Scheme for LoopbackInterface { 24 | fn name(&self) -> &str { 25 | "loopback" 26 | } 27 | 28 | fn handle_irq(&self, _cause: usize) {} 29 | } 30 | 31 | impl NetScheme for LoopbackInterface { 32 | fn recv(&self, _buf: &mut [u8]) -> DeviceResult { 33 | unimplemented!() 34 | } 35 | fn send(&self, _buf: &[u8]) -> DeviceResult { 36 | unimplemented!() 37 | } 38 | fn poll(&self) -> DeviceResult { 39 | let timestamp = Instant::from_millis(0); 40 | let sockets = get_sockets(); 41 | let mut sockets = sockets.lock(); 42 | match self.iface.lock().poll(&mut sockets, timestamp) { 43 | Ok(_) => Ok(()), 44 | Err(err) => { 45 | debug!("poll got err {}", err); 46 | Err(DeviceError::IoError) 47 | } 48 | } 49 | } 50 | 51 | fn get_mac(&self) -> EthernetAddress { 52 | self.iface.lock().ethernet_addr() 53 | } 54 | 55 | fn get_ifname(&self) -> String { 56 | self.name.clone() 57 | } 58 | 59 | fn get_ip_address(&self) -> Vec { 60 | Vec::from(self.iface.lock().ip_addrs()) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /drivers/src/net/mod.rs: -------------------------------------------------------------------------------- 1 | //! LAN driver, only for Realtek currently. 2 | #![allow(unused)] 3 | 4 | use alloc::{sync::Arc, vec}; 5 | use lock::Mutex; 6 | use smoltcp::socket::SocketSet; 7 | 8 | pub mod e1000; 9 | pub mod loopback; 10 | pub use isomorphic_drivers::provider::Provider; 11 | pub use loopback::LoopbackInterface; 12 | 13 | cfg_if::cfg_if! { 14 | if #[cfg(target_arch = "riscv64")] { 15 | mod realtek; 16 | mod rtlx; 17 | 18 | pub use rtlx::*; 19 | } 20 | } 21 | 22 | /* 23 | /// External functions that drivers must use 24 | pub trait Provider { 25 | /// Page size (usually 4K) 26 | const PAGE_SIZE: usize; 27 | 28 | /// Allocate consequent physical memory for DMA. 29 | /// Return (`virtual address`, `physical address`). 30 | /// The address is page aligned. 31 | fn alloc_dma(size: usize) -> (usize, usize); 32 | 33 | /// Deallocate DMA 34 | fn dealloc_dma(vaddr: usize, size: usize); 35 | } 36 | */ 37 | 38 | pub struct ProviderImpl; 39 | 40 | impl Provider for ProviderImpl { 41 | const PAGE_SIZE: usize = PAGE_SIZE; 42 | 43 | fn alloc_dma(size: usize) -> (usize, usize) { 44 | let paddr = unsafe { drivers_dma_alloc(size / PAGE_SIZE) }; 45 | let vaddr = phys_to_virt(paddr); 46 | (vaddr, paddr) 47 | } 48 | 49 | fn dealloc_dma(vaddr: usize, size: usize) { 50 | let paddr = virt_to_phys(vaddr); 51 | unsafe { drivers_dma_dealloc(paddr, size / PAGE_SIZE) }; 52 | } 53 | } 54 | 55 | pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { 56 | unsafe { drivers_phys_to_virt(paddr) } 57 | } 58 | 59 | pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { 60 | unsafe { drivers_virt_to_phys(vaddr) } 61 | } 62 | 63 | pub fn timer_now_as_micros() -> u64 { 64 | unsafe { drivers_timer_now_as_micros() } 65 | } 66 | 67 | extern "C" { 68 | fn drivers_dma_alloc(pages: usize) -> PhysAddr; 69 | fn drivers_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32; 70 | fn drivers_phys_to_virt(paddr: PhysAddr) -> VirtAddr; 71 | fn drivers_virt_to_phys(vaddr: VirtAddr) -> PhysAddr; 72 | fn drivers_timer_now_as_micros() -> u64; 73 | } 74 | 75 | pub const PAGE_SIZE: usize = 4096; 76 | 77 | type VirtAddr = usize; 78 | type PhysAddr = usize; 79 | 80 | lazy_static::lazy_static! { 81 | pub static ref SOCKETS: Arc>> = 82 | Arc::new(Mutex::new(SocketSet::new(vec![]))); 83 | } 84 | 85 | // 注意!这个容易出现死锁 86 | pub fn get_sockets() -> Arc>> { 87 | SOCKETS.clone() 88 | } 89 | -------------------------------------------------------------------------------- /drivers/src/net/realtek/mod.rs: -------------------------------------------------------------------------------- 1 | use super::{phys_to_virt, virt_to_phys, Provider}; 2 | 3 | #[macro_use] 4 | mod log { 5 | macro_rules! trace { 6 | ($($arg:expr),*) => { $( let _ = $arg; )* }; 7 | } 8 | macro_rules! debug { 9 | ($($arg:expr),*) => { $( let _ = $arg; )* }; 10 | } 11 | macro_rules! info { 12 | ($($arg:expr),*) => { $( let _ = $arg; )*}; 13 | } 14 | macro_rules! warn { 15 | ($($arg:expr),*) => { $( let _ = $arg; )*}; 16 | } 17 | macro_rules! error { 18 | ($($arg:expr),*) => { $( let _ = $arg; )* }; 19 | } 20 | } 21 | 22 | pub mod mii; 23 | pub mod rtl8211f; 24 | mod utils; 25 | -------------------------------------------------------------------------------- /drivers/src/net/realtek/utils.rs: -------------------------------------------------------------------------------- 1 | // c906 2 | use core::arch::asm; 3 | 4 | const FREQUENCY: u64 = 24_000_000; // C906: 24_000_000, Qemu: 10_000_000 5 | const MMIO_MTIMECMP0: *mut u64 = 0x0200_4000usize as *mut u64; 6 | const MMIO_MTIME: *const u64 = 0x0200_BFF8 as *const u64; 7 | 8 | const L1_CACHE_BYTES: u64 = 64; 9 | const CACHE_LINE_SIZE: u64 = 64; 10 | 11 | pub fn flush_cache(addr: u64, size: u64) { 12 | flush_dcache_range(addr, addr + size); 13 | } 14 | 15 | pub fn invalidate_dcache(addr: u64, size: u64) { 16 | invalidate_dcache_range(addr, addr + size); 17 | } 18 | 19 | // 注意start输入物理地址 20 | pub fn flush_dcache_range(start: u64, end: u64) { 21 | // CACHE_LINE 64对齐 22 | let end = (end + (CACHE_LINE_SIZE - 1)) & !(CACHE_LINE_SIZE - 1); 23 | 24 | // 地址对齐到L1 Cache的节 25 | let mut i: u64 = start & !(L1_CACHE_BYTES - 1); 26 | while i < end { 27 | unsafe { 28 | // 老风格的llvm asm 29 | // DCACHE 指定物理地址清脏表项 30 | // llvm_asm!("dcache.cpa $0"::"r"(i)); 31 | 32 | // 新asm 33 | asm!(".long 0x0295000b", in("a0") i); // dcache.cpa a0, 因编译器无法识别该指令 34 | } 35 | 36 | i += L1_CACHE_BYTES; 37 | } 38 | 39 | unsafe { 40 | //llvm_asm!("sync.is"); 41 | 42 | asm!(".long 0x01b0000b"); // sync.is 43 | } 44 | } 45 | 46 | // start 物理地址 47 | pub fn invalidate_dcache_range(start: u64, end: u64) { 48 | let end = (end + (CACHE_LINE_SIZE - 1)) & !(CACHE_LINE_SIZE - 1); 49 | let mut i: u64 = start & !(L1_CACHE_BYTES - 1); 50 | while i < end { 51 | unsafe { 52 | //llvm_asm!("dcache.ipa $0"::"r"(i)); // DCACHE 指定物理地址无效表项 53 | asm!(".long 0x02a5000b", in("a0") i); // dcache.ipa a0 54 | } 55 | 56 | i += L1_CACHE_BYTES; 57 | } 58 | 59 | unsafe { 60 | //llvm_asm!("sync.is"); 61 | asm!(".long 0x01b0000b"); // sync.is 62 | } 63 | } 64 | 65 | pub fn fence_w() { 66 | unsafe { 67 | //llvm_asm!("fence ow, ow" ::: "memory"); 68 | asm!("fence ow, ow"); 69 | } 70 | } 71 | 72 | pub fn get_cycle() -> u64 { 73 | unsafe { MMIO_MTIME.read_volatile() } 74 | } 75 | 76 | // Timer, Freq = 24000000Hz 77 | // TIMER_CLOCK = (24 * 1000 * 1000) 78 | // 微秒(us) 79 | pub fn usdelay(us: u64) { 80 | let mut t1: u64 = get_cycle(); 81 | let t2 = t1 + us * 24; 82 | 83 | while t2 >= t1 { 84 | t1 = get_cycle(); 85 | } 86 | } 87 | 88 | // 毫秒(ms) 89 | #[allow(unused)] 90 | pub fn msdelay(ms: u64) { 91 | usdelay(ms * 1000); 92 | } 93 | -------------------------------------------------------------------------------- /drivers/src/nvme/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod interface; 2 | pub mod nvme_queue; 3 | 4 | pub use interface::*; 5 | pub use nvme_queue::*; 6 | -------------------------------------------------------------------------------- /drivers/src/prelude.rs: -------------------------------------------------------------------------------- 1 | //! Re-export most commonly used driver types. 2 | 3 | pub use crate::scheme::display::{ColorFormat, DisplayInfo, FrameBuffer, Rectangle, RgbColor}; 4 | pub use crate::scheme::input::{CapabilityType, InputCapability, InputEvent, InputEventType}; 5 | pub use crate::scheme::irq::{IrqHandler, IrqPolarity, IrqTriggerMode}; 6 | pub use crate::{Device, DeviceError, DeviceResult}; 7 | 8 | /// Re-export types from [`input`](crate::input). 9 | pub mod input { 10 | pub use crate::input::{Mouse, MouseFlags, MouseState}; 11 | } 12 | -------------------------------------------------------------------------------- /drivers/src/scheme/block.rs: -------------------------------------------------------------------------------- 1 | use super::Scheme; 2 | use crate::DeviceResult; 3 | 4 | pub trait BlockScheme: Scheme { 5 | fn read_block(&self, block_id: usize, buf: &mut [u8]) -> DeviceResult; 6 | fn write_block(&self, block_id: usize, buf: &[u8]) -> DeviceResult; 7 | fn flush(&self) -> DeviceResult; 8 | } 9 | -------------------------------------------------------------------------------- /drivers/src/scheme/event.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::EventHandler; 2 | 3 | pub trait EventScheme { 4 | type Event; 5 | 6 | /// Trigger the event manually and call its handler immediately. 7 | fn trigger(&self, event: Self::Event); 8 | 9 | /// Subscribe events, call the `handler` when an input event occurs. 10 | /// If `once` is ture, unsubscribe automatically after handling. 11 | fn subscribe(&self, handler: EventHandler, once: bool); 12 | } 13 | 14 | macro_rules! impl_event_scheme { 15 | ($struct:ident $(, $event_ty:ty)?) => { 16 | impl_event_scheme!(@impl_base $struct $(, $event_ty)?); 17 | }; 18 | ($struct:ident<'_> $(, $event_ty:ty)?) => { 19 | impl_event_scheme!(@impl_base $struct<'_> $(, $event_ty)?); 20 | }; 21 | ($struct:ident < $($types:ident),* > $(where $($preds:tt)+)? $(, $event_ty:ty)?) => { 22 | impl_event_scheme!(@impl_base $struct < $($types),* > $(where $($preds)+)? $(, $event_ty)?); 23 | }; 24 | 25 | (@impl_base $struct:ident $(, $event_ty:ty)?) => { 26 | impl $crate::scheme::EventScheme for $struct { 27 | impl_event_scheme!(@impl_body $(, $event_ty)?); 28 | } 29 | }; 30 | (@impl_base $struct:ident<'_> $(, $event_ty:ty)?) => { 31 | impl $crate::scheme::EventScheme for $struct<'_> { 32 | impl_event_scheme!(@impl_body $(, $event_ty)?); 33 | } 34 | }; 35 | (@impl_base $struct:ident < $($types:ident),* > $(where $($preds:tt)+)? $(, $event_ty:ty)?) => { 36 | impl < $($types),* > $crate::scheme::EventScheme for $struct < $($types),* > 37 | $(where $($preds)+)? 38 | { 39 | impl_event_scheme!(@impl_body $(, $event_ty)?); 40 | } 41 | }; 42 | 43 | (@impl_assoc_type) => { 44 | type Event = (); 45 | }; 46 | (@impl_assoc_type, $event_ty:ty) => { 47 | type Event = $event_ty; 48 | }; 49 | (@impl_body $(, $event_ty:ty)?) => { 50 | impl_event_scheme!(@impl_assoc_type $(, $event_ty)?); 51 | 52 | #[inline] 53 | fn trigger(&self, event: Self::Event) { 54 | self.listener.trigger(event); 55 | } 56 | 57 | #[inline] 58 | fn subscribe(&self, handler: $crate::utils::EventHandler, once: bool) { 59 | self.listener.subscribe(handler, once); 60 | } 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /drivers/src/scheme/mod.rs: -------------------------------------------------------------------------------- 1 | //! The [`Scheme`] describe some functions must be implemented for different type of devices, 2 | //! there are many [`Scheme`] traits in this mod. 3 | //! 4 | //! If you need to develop a new device, just implement the corresponding trait. 5 | //! 6 | //! The [`Scheme`] trait is suitable for any architecture. 7 | 8 | pub(super) mod block; 9 | pub(super) mod display; 10 | pub(super) mod input; 11 | pub(super) mod irq; 12 | pub(super) mod net; 13 | pub(super) mod uart; 14 | 15 | #[macro_use] 16 | pub(super) mod event; 17 | pub(super) use impl_event_scheme; 18 | 19 | use alloc::sync::Arc; 20 | 21 | pub use block::BlockScheme; 22 | pub use display::DisplayScheme; 23 | pub use event::EventScheme; 24 | pub use input::InputScheme; 25 | pub use irq::IrqScheme; 26 | pub use net::NetScheme; 27 | pub use uart::UartScheme; 28 | 29 | /// Common of all device drivers. 30 | /// 31 | /// Every device must says its name and handles interrupts. 32 | pub trait Scheme: SchemeUpcast + Send + Sync { 33 | /// Returns name of the driver. 34 | fn name(&self) -> &str; 35 | 36 | /// Handles an interrupt. 37 | fn handle_irq(&self, _irq_num: usize) {} 38 | } 39 | 40 | /// Used to convert a concrete type pointer to a general [`Scheme`] pointer. 41 | pub trait SchemeUpcast { 42 | /// Performs the conversion. 43 | fn upcast<'a>(self: Arc) -> Arc 44 | where 45 | Self: 'a; 46 | } 47 | 48 | impl SchemeUpcast for T { 49 | fn upcast<'a>(self: Arc) -> Arc 50 | where 51 | Self: 'a, 52 | { 53 | self 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /drivers/src/scheme/net.rs: -------------------------------------------------------------------------------- 1 | use super::Scheme; 2 | use crate::DeviceResult; 3 | use alloc::string::String; 4 | use alloc::vec::Vec; 5 | use smoltcp::wire::{EthernetAddress, IpCidr}; 6 | 7 | pub trait NetScheme: Scheme { 8 | fn recv(&self, buf: &mut [u8]) -> DeviceResult; 9 | fn send(&self, buf: &[u8]) -> DeviceResult; 10 | fn get_mac(&self) -> EthernetAddress; 11 | fn get_ifname(&self) -> String; 12 | fn get_ip_address(&self) -> Vec; 13 | fn poll(&self) -> DeviceResult; 14 | } 15 | -------------------------------------------------------------------------------- /drivers/src/scheme/uart.rs: -------------------------------------------------------------------------------- 1 | use super::{event::EventScheme, Scheme}; 2 | use crate::DeviceResult; 3 | 4 | pub trait UartScheme: Scheme + EventScheme { 5 | fn try_recv(&self) -> DeviceResult>; 6 | fn send(&self, ch: u8) -> DeviceResult; 7 | fn write_str(&self, s: &str) -> DeviceResult { 8 | for c in s.bytes() { 9 | self.send(c)?; 10 | } 11 | Ok(()) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /drivers/src/uart/buffered.rs: -------------------------------------------------------------------------------- 1 | use alloc::{boxed::Box, collections::VecDeque, string::String, sync::Arc}; 2 | 3 | use lock::Mutex; 4 | 5 | use crate::scheme::{impl_event_scheme, Scheme, UartScheme}; 6 | use crate::utils::EventListener; 7 | use crate::DeviceResult; 8 | 9 | const BUF_CAPACITY: usize = 4096; 10 | 11 | pub struct BufferedUart { 12 | inner: Arc, 13 | buf: Mutex>, 14 | listener: EventListener, 15 | name: String, 16 | } 17 | 18 | impl_event_scheme!(BufferedUart); 19 | 20 | impl BufferedUart { 21 | pub fn new(uart: Arc) -> Arc { 22 | let ret = Arc::new(Self { 23 | inner: uart.clone(), 24 | name: alloc::format!("{}-buffered", uart.name()), 25 | buf: Mutex::new(VecDeque::with_capacity(BUF_CAPACITY)), 26 | listener: EventListener::new(), 27 | }); 28 | let cloned = ret.clone(); 29 | uart.subscribe(Box::new(move |_| cloned.handle_irq(0)), false); 30 | ret 31 | } 32 | } 33 | 34 | impl Scheme for BufferedUart { 35 | fn name(&self) -> &str { 36 | self.name.as_str() 37 | } 38 | 39 | fn handle_irq(&self, _unused: usize) { 40 | while let Some(c) = self.inner.try_recv().unwrap_or(None) { 41 | let mut buf = self.buf.lock(); 42 | if buf.len() < BUF_CAPACITY { 43 | let c = if c == b'\r' { b'\n' } else { c }; 44 | buf.push_back(c); 45 | } 46 | } 47 | if self.buf.lock().len() > 0 { 48 | self.listener.trigger(()); 49 | } 50 | } 51 | } 52 | 53 | impl UartScheme for BufferedUart { 54 | fn try_recv(&self) -> DeviceResult> { 55 | Ok(self.buf.lock().pop_front()) 56 | } 57 | fn send(&self, ch: u8) -> DeviceResult { 58 | self.inner.send(ch) 59 | } 60 | fn write_str(&self, s: &str) -> DeviceResult { 61 | self.inner.write_str(s) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /drivers/src/uart/mod.rs: -------------------------------------------------------------------------------- 1 | //! Uart device driver. 2 | 3 | mod buffered; 4 | mod uart_16550; 5 | 6 | pub use buffered::BufferedUart; 7 | pub use uart_16550::Uart16550Mmio; 8 | 9 | #[cfg(target_arch = "x86_64")] 10 | pub use uart_16550::Uart16550Pmio; 11 | 12 | #[cfg(target_arch = "aarch64")] 13 | mod uart_pl011; 14 | 15 | #[cfg(target_arch = "aarch64")] 16 | pub use uart_pl011::Pl011Uart; 17 | 18 | #[cfg(feature = "allwinner")] 19 | mod uart_allwinner; 20 | 21 | #[cfg(feature = "allwinner")] 22 | pub use uart_allwinner::UartAllwinner; 23 | 24 | #[cfg(feature = "fu740")] 25 | mod uart_u740; 26 | 27 | #[cfg(feature = "fu740")] 28 | pub use uart_u740::UartU740Mmio; 29 | -------------------------------------------------------------------------------- /drivers/src/utils/event_listener.rs: -------------------------------------------------------------------------------- 1 | use alloc::{boxed::Box, vec::Vec}; 2 | 3 | use lock::Mutex; 4 | 5 | /// A type alias for the closure to handle device event. 6 | pub type EventHandler = Box; 7 | 8 | /// Device event listener. 9 | /// 10 | /// It keeps a series of [`EventHandler`]s that handle events of one single type. 11 | pub struct EventListener { 12 | events: Mutex, bool)>>, 13 | } 14 | 15 | impl EventListener { 16 | /// Construct a new, empty `EventListener`. 17 | pub fn new() -> Self { 18 | Self { 19 | events: Mutex::new(Vec::new()), 20 | } 21 | } 22 | 23 | /// Register a new `handler` into this `EventListener`. 24 | /// 25 | /// If `once` is `true`, the `handler` will be removed once it handles an event. 26 | pub fn subscribe(&self, handler: EventHandler, once: bool) { 27 | self.events.lock().push((handler, once)); 28 | } 29 | 30 | /// Send an event to the `EventListener`. 31 | /// 32 | /// All the handlers handle the event, and those marked `once` will be removed immediately. 33 | pub fn trigger(&self, event: T) { 34 | self.events.lock().retain(|(f, once)| { 35 | f(&event); 36 | !once 37 | }); 38 | } 39 | } 40 | 41 | impl Default for EventListener { 42 | fn default() -> Self { 43 | Self::new() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /drivers/src/utils/graphic_console.rs: -------------------------------------------------------------------------------- 1 | use alloc::sync::Arc; 2 | use core::convert::Infallible; 3 | use core::ops::{Deref, DerefMut}; 4 | 5 | use rcore_console::{Console, ConsoleOnGraphic, DrawTarget, OriginDimensions, Pixel, Rgb888, Size}; 6 | 7 | use crate::scheme::DisplayScheme; 8 | 9 | pub struct DisplayWrapper(Arc); 10 | 11 | pub struct GraphicConsole { 12 | inner: ConsoleOnGraphic, 13 | } 14 | 15 | impl GraphicConsole { 16 | pub fn new(display: Arc) -> Self { 17 | Self { 18 | inner: Console::on_frame_buffer(DisplayWrapper(display)), 19 | } 20 | } 21 | } 22 | 23 | impl DrawTarget for DisplayWrapper { 24 | type Color = Rgb888; 25 | type Error = Infallible; 26 | 27 | fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> 28 | where 29 | I: IntoIterator>, 30 | { 31 | for p in pixels { 32 | let color = unsafe { core::mem::transmute(p.1) }; 33 | self.0.draw_pixel(p.0.x as u32, p.0.y as u32, color); 34 | } 35 | Ok(()) 36 | } 37 | } 38 | 39 | impl OriginDimensions for DisplayWrapper { 40 | fn size(&self) -> Size { 41 | let info = self.0.info(); 42 | Size::new(info.width, info.height) 43 | } 44 | } 45 | 46 | impl Deref for GraphicConsole { 47 | type Target = ConsoleOnGraphic; 48 | 49 | fn deref(&self) -> &Self::Target { 50 | &self.inner 51 | } 52 | } 53 | 54 | impl DerefMut for GraphicConsole { 55 | fn deref_mut(&mut self) -> &mut Self::Target { 56 | &mut self.inner 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /drivers/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | //! Event handler and device tree. 2 | 3 | mod event_listener; 4 | mod id_allocator; 5 | mod irq_manager; 6 | 7 | #[cfg(feature = "graphic")] 8 | mod graphic_console; 9 | 10 | pub mod devicetree; 11 | 12 | pub(super) use id_allocator::IdAllocator; 13 | pub(super) use irq_manager::IrqManager; 14 | 15 | pub use event_listener::{EventHandler, EventListener}; 16 | 17 | #[cfg(feature = "graphic")] 18 | pub use graphic_console::GraphicConsole; 19 | -------------------------------------------------------------------------------- /drivers/src/virtio/blk.rs: -------------------------------------------------------------------------------- 1 | use lock::Mutex; 2 | use virtio_drivers::{VirtIOBlk as InnerDriver, VirtIOHeader}; 3 | 4 | use crate::scheme::{BlockScheme, Scheme}; 5 | use crate::DeviceResult; 6 | 7 | pub struct VirtIoBlk<'a> { 8 | inner: Mutex>, 9 | } 10 | 11 | impl<'a> VirtIoBlk<'a> { 12 | pub fn new(header: &'static mut VirtIOHeader) -> DeviceResult { 13 | Ok(Self { 14 | inner: Mutex::new(InnerDriver::new(header)?), 15 | }) 16 | } 17 | } 18 | 19 | impl<'a> Scheme for VirtIoBlk<'a> { 20 | fn name(&self) -> &str { 21 | "virtio-blk" 22 | } 23 | 24 | fn handle_irq(&self, _irq_num: usize) { 25 | self.inner.lock().ack_interrupt(); 26 | } 27 | } 28 | 29 | impl<'a> BlockScheme for VirtIoBlk<'a> { 30 | fn read_block(&self, block_id: usize, buf: &mut [u8]) -> DeviceResult { 31 | self.inner.lock().read_block(block_id, buf)?; 32 | Ok(()) 33 | } 34 | 35 | fn write_block(&self, block_id: usize, buf: &[u8]) -> DeviceResult { 36 | self.inner.lock().write_block(block_id, buf)?; 37 | Ok(()) 38 | } 39 | 40 | fn flush(&self) -> DeviceResult { 41 | Ok(()) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /drivers/src/virtio/console.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{Result, Write}; 2 | 3 | use lock::Mutex; 4 | use virtio_drivers::{VirtIOConsole as InnerDriver, VirtIOHeader}; 5 | 6 | use crate::prelude::DeviceResult; 7 | use crate::scheme::{impl_event_scheme, Scheme, UartScheme}; 8 | use crate::utils::EventListener; 9 | 10 | pub struct VirtIoConsole<'a> { 11 | inner: Mutex>, 12 | listener: EventListener, 13 | } 14 | 15 | impl_event_scheme!(VirtIoConsole<'_>); 16 | 17 | impl<'a> VirtIoConsole<'a> { 18 | pub fn new(header: &'static mut VirtIOHeader) -> DeviceResult { 19 | Ok(Self { 20 | inner: Mutex::new(InnerDriver::new(header)?), 21 | listener: EventListener::new(), 22 | }) 23 | } 24 | } 25 | 26 | impl<'a> Scheme for VirtIoConsole<'a> { 27 | fn name(&self) -> &str { 28 | "virtio-console" 29 | } 30 | 31 | fn handle_irq(&self, _irq_num: usize) { 32 | self.inner.lock().ack_interrupt().unwrap(); 33 | self.listener.trigger(()); 34 | } 35 | } 36 | 37 | impl<'a> UartScheme for VirtIoConsole<'a> { 38 | fn try_recv(&self) -> DeviceResult> { 39 | Ok(self.inner.lock().recv(true)?) 40 | } 41 | 42 | fn send(&self, ch: u8) -> DeviceResult { 43 | self.inner.lock().send(ch)?; 44 | Ok(()) 45 | } 46 | } 47 | 48 | impl<'a> Write for VirtIoConsole<'a> { 49 | fn write_str(&mut self, s: &str) -> Result { 50 | for b in s.bytes() { 51 | self.send(b).unwrap() 52 | } 53 | Ok(()) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /drivers/src/virtio/gpu.rs: -------------------------------------------------------------------------------- 1 | use lock::Mutex; 2 | use virtio_drivers::{VirtIOGpu as InnerDriver, VirtIOHeader}; 3 | 4 | use crate::prelude::{ColorFormat, DisplayInfo, FrameBuffer}; 5 | use crate::scheme::{DisplayScheme, Scheme}; 6 | use crate::DeviceResult; 7 | 8 | pub struct VirtIoGpu<'a> { 9 | info: DisplayInfo, 10 | inner: Mutex>, 11 | } 12 | 13 | const CURSOR_HOT_X: u32 = 13; 14 | const CURSOR_HOT_Y: u32 = 11; 15 | static CURSOR_IMG: &[u8] = include_bytes!("../display/resource/cursor.bin"); // 64 x 64 x 4 16 | 17 | impl<'a> VirtIoGpu<'a> { 18 | pub fn new(header: &'static mut VirtIOHeader) -> DeviceResult { 19 | let mut gpu = InnerDriver::new(header)?; 20 | let fb = gpu.setup_framebuffer()?; 21 | let fb_base_vaddr = fb.as_ptr() as usize; 22 | let fb_size = fb.len(); 23 | let (width, height) = gpu.resolution(); 24 | let info = DisplayInfo { 25 | width, 26 | height, 27 | format: ColorFormat::ARGB8888, 28 | fb_base_vaddr, 29 | fb_size, 30 | }; 31 | gpu.setup_cursor( 32 | CURSOR_IMG, 33 | width / 2, 34 | height / 2, 35 | CURSOR_HOT_X, 36 | CURSOR_HOT_Y, 37 | )?; 38 | Ok(Self { 39 | info, 40 | inner: Mutex::new(gpu), 41 | }) 42 | } 43 | } 44 | 45 | impl<'a> Scheme for VirtIoGpu<'a> { 46 | fn name(&self) -> &str { 47 | "virtio-gpu" 48 | } 49 | 50 | fn handle_irq(&self, _irq_num: usize) { 51 | self.inner.lock().ack_interrupt(); 52 | } 53 | } 54 | 55 | impl<'a> DisplayScheme for VirtIoGpu<'a> { 56 | #[inline] 57 | fn info(&self) -> DisplayInfo { 58 | self.info 59 | } 60 | 61 | #[inline] 62 | fn fb(&self) -> FrameBuffer { 63 | unsafe { 64 | FrameBuffer::from_raw_parts_mut(self.info.fb_base_vaddr as *mut u8, self.info.fb_size) 65 | } 66 | } 67 | 68 | #[inline] 69 | fn need_flush(&self) -> bool { 70 | true 71 | } 72 | 73 | fn flush(&self) -> DeviceResult { 74 | self.inner.lock().flush()?; 75 | Ok(()) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /drivers/src/virtio/mod.rs: -------------------------------------------------------------------------------- 1 | //! Packaging of [`virtio-drivers` library](https://github.com/rcore-os/virtio-drivers). 2 | 3 | mod blk; 4 | mod console; 5 | mod gpu; 6 | mod input; 7 | 8 | pub use blk::VirtIoBlk; 9 | pub use console::VirtIoConsole; 10 | pub use gpu::VirtIoGpu; 11 | pub use input::VirtIoInput; 12 | pub use virtio_drivers::VirtIOHeader; 13 | 14 | use crate::DeviceError; 15 | use core::convert::From; 16 | use virtio_drivers::Error; 17 | 18 | impl From for DeviceError { 19 | fn from(err: Error) -> Self { 20 | match err { 21 | Error::BufferTooSmall => Self::BufferTooSmall, 22 | Error::NotReady => Self::NotReady, 23 | Error::InvalidParam => Self::InvalidParam, 24 | Error::DmaError => Self::DmaError, 25 | Error::AlreadyUsed => Self::AlreadyExists, 26 | Error::IoError => Self::IoError, 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/aarch64/config.rs: -------------------------------------------------------------------------------- 1 | //! Kernel configuration. 2 | use crate::PAGE_SIZE; 3 | 4 | /// Kernel configuration passed by kernel when calls [`crate::primary_init_early()`]. 5 | #[repr(C)] 6 | #[derive(Debug, Clone)] 7 | pub struct KernelConfig { 8 | /// boot cmd line 9 | pub cmdline: &'static str, 10 | /// firmware type 11 | pub firmware_type: &'static str, 12 | /// UART base address 13 | pub uart_base: usize, 14 | /// GIC base address 15 | pub gic_base: usize, 16 | /// phystovirt offset 17 | pub phys_to_virt_offset: usize, 18 | } 19 | 20 | pub const PHYS_MEMORY_BASE: usize = 0x4000_0000; 21 | pub const UART_SIZE: usize = 0x1000; 22 | pub const VIRTIO_BASE: usize = 0x0a00_0000; 23 | pub const VIRTIO_SIZE: usize = 0x100; 24 | pub const PA_1TB_BITS: usize = 40; 25 | pub const PHYS_ADDR_MAX: usize = (1 << PA_1TB_BITS) - 1; 26 | pub const PHYS_ADDR_MASK: usize = PHYS_ADDR_MAX & !(PAGE_SIZE - 1); 27 | pub const PHYS_MEMORY_END: usize = PHYS_MEMORY_BASE + 100 * 1024 * 1024; 28 | pub const USER_TABLE_FLAG: usize = 0xabcd_0000_0000_0000; 29 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/aarch64/cpu.rs: -------------------------------------------------------------------------------- 1 | //! CPU information. 2 | 3 | use cortex_a::registers::*; 4 | use tock_registers::interfaces::Readable; 5 | 6 | hal_fn_impl! { 7 | impl mod crate::hal_fn::cpu { 8 | fn cpu_id() -> u8 { 9 | let id = MPIDR_EL1.get() & 0x3; 10 | id as u8 11 | } 12 | 13 | fn cpu_frequency() -> u16 { 14 | 0 15 | } 16 | 17 | fn reset() -> ! { 18 | info!("shutdown..."); 19 | let psci_system_off = 0x8400_0008_usize; 20 | unsafe { 21 | core::arch::asm!( 22 | "hvc #0", 23 | in("x0") psci_system_off 24 | ); 25 | } 26 | unreachable!() 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/aarch64/drivers.rs: -------------------------------------------------------------------------------- 1 | use crate::arch::timer::set_next_trigger; 2 | use crate::drivers; 3 | use crate::hal_fn::mem::phys_to_virt; 4 | use crate::imp::config::VIRTIO_BASE; 5 | use crate::KCONFIG; 6 | use alloc::boxed::Box; 7 | use alloc::sync::Arc; 8 | use zcore_drivers::irq::gic_400; 9 | use zcore_drivers::scheme::IrqScheme; 10 | use zcore_drivers::uart::{BufferedUart, Pl011Uart}; 11 | use zcore_drivers::virtio::{VirtIOHeader, VirtIoBlk}; 12 | use zcore_drivers::Device; 13 | 14 | pub fn init_early() { 15 | let uart = Pl011Uart::new(phys_to_virt(KCONFIG.uart_base)); 16 | let uart = Arc::new(uart); 17 | let gic = gic_400::init( 18 | phys_to_virt(KCONFIG.gic_base + 0x1_0000), 19 | phys_to_virt(KCONFIG.gic_base), 20 | ); 21 | gic.irq_enable(30); 22 | gic.irq_enable(33); 23 | gic.register_handler(33, Box::new(handle_uart_irq)).ok(); 24 | gic.register_handler(30, Box::new(set_next_trigger)).ok(); 25 | drivers::add_device(Device::Irq(Arc::new(gic))); 26 | drivers::add_device(Device::Uart(BufferedUart::new(uart))); 27 | } 28 | 29 | pub fn init() { 30 | let virtio_blk = Arc::new( 31 | VirtIoBlk::new(unsafe { &mut *(phys_to_virt(VIRTIO_BASE) as *mut VirtIOHeader) }).unwrap(), 32 | ); 33 | drivers::add_device(Device::Block(virtio_blk)); 34 | } 35 | 36 | fn handle_uart_irq() { 37 | crate::drivers::all_uart().first_unwrap().handle_irq(0); 38 | } 39 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/aarch64/interrupt.rs: -------------------------------------------------------------------------------- 1 | //! Interrupts management. 2 | use crate::HalResult; 3 | use alloc::vec::Vec; 4 | use cortex_a::asm::wfi; 5 | 6 | hal_fn_impl! { 7 | impl mod crate::hal_fn::interrupt { 8 | fn wait_for_interrupt() { 9 | intr_on(); 10 | wfi(); 11 | intr_off(); 12 | } 13 | 14 | fn handle_irq(vector: usize) { 15 | // TODO: timer and other devices with GIC interrupt controller 16 | crate::drivers::all_irq().first_unwrap().handle_irq(vector); 17 | if vector == 30 { 18 | debug!("Timer"); 19 | } 20 | } 21 | 22 | fn intr_off() { 23 | unsafe { 24 | core::arch::asm!("msr daifset, #2"); 25 | } 26 | } 27 | 28 | fn intr_on() { 29 | unsafe { 30 | core::arch::asm!("msr daifclr, #2"); 31 | } 32 | } 33 | 34 | fn intr_get() -> bool { 35 | use cortex_a::registers::DAIF; 36 | use tock_registers::interfaces::Readable; 37 | !DAIF.is_set(DAIF::I) 38 | } 39 | 40 | fn send_ipi(cpuid: usize, reason: usize) -> HalResult { 41 | trace!("ipi [{}] => [{}]: {:x}", super::cpu::cpu_id(), cpuid, reason); 42 | panic!("send_ipi unsupported for aarch64"); 43 | } 44 | 45 | fn ipi_reason() -> Vec { 46 | panic!("ipi_reason unsupported for aarch64"); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/aarch64/mem.rs: -------------------------------------------------------------------------------- 1 | use crate::imp::config::*; 2 | use crate::PhysAddr; 3 | use alloc::vec::Vec; 4 | use core::ops::Range; 5 | 6 | extern "C" { 7 | fn ekernel(); 8 | } 9 | 10 | pub fn free_pmem_regions() -> Vec> { 11 | let mut regions = Vec::new(); 12 | let start = ekernel as usize & PHYS_ADDR_MASK; 13 | regions.push(start as PhysAddr..PHYS_MEMORY_END as PhysAddr); 14 | regions 15 | } 16 | 17 | /// Flush the physical frame. 18 | pub fn frame_flush(_target: PhysAddr) { 19 | unimplemented!() 20 | } 21 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/aarch64/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod cpu; 3 | pub mod drivers; 4 | pub mod interrupt; 5 | pub mod mem; 6 | pub mod timer; 7 | pub mod trap; 8 | pub mod vm; 9 | 10 | use crate::KCONFIG; 11 | use crate::{mem::phys_to_virt, utils::init_once::InitOnce, PhysAddr}; 12 | use alloc::string::{String, ToString}; 13 | use core::ops::Range; 14 | 15 | hal_fn_impl_default!(crate::hal_fn::console); 16 | 17 | static INITRD_REGION: InitOnce>> = InitOnce::new_with_default(None); 18 | static CMDLINE: InitOnce = InitOnce::new_with_default(String::new()); 19 | 20 | pub fn cmdline() -> String { 21 | CMDLINE.clone() 22 | } 23 | 24 | pub fn init_ram_disk() -> Option<&'static mut [u8]> { 25 | INITRD_REGION.as_ref().map(|range| unsafe { 26 | core::slice::from_raw_parts_mut(phys_to_virt(range.start) as *mut u8, range.len()) 27 | }) 28 | } 29 | 30 | pub fn primary_init_early() { 31 | CMDLINE.init_once_by(KCONFIG.cmdline.to_string()); 32 | drivers::init_early(); 33 | } 34 | 35 | pub fn primary_init() { 36 | vm::init(); 37 | drivers::init(); 38 | } 39 | 40 | pub fn secondary_init() { 41 | unimplemented!() 42 | } 43 | 44 | pub const fn timer_interrupt_vector() -> usize { 45 | 30 46 | } 47 | 48 | pub fn timer_init() { 49 | timer::init(); 50 | } 51 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/aarch64/timer.rs: -------------------------------------------------------------------------------- 1 | //! ARM Generic Timer. 2 | 3 | use crate::timer::TICKS_PER_SEC; 4 | use core::time::Duration; 5 | use cortex_a::{asm::barrier, registers::*}; 6 | use tock_registers::interfaces::{Readable, Writeable}; 7 | 8 | pub fn timer_now() -> Duration { 9 | unsafe { barrier::isb(barrier::SY) } 10 | let cur_cnt = CNTPCT_EL0.get() * 1_000_000_000; 11 | let freq = CNTFRQ_EL0.get() as u64; 12 | Duration::from_nanos(cur_cnt / freq) 13 | } 14 | 15 | pub fn set_next_trigger() { 16 | CNTP_TVAL_EL0.set(CNTFRQ_EL0.get() / TICKS_PER_SEC); 17 | } 18 | 19 | pub fn init() { 20 | CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET); 21 | set_next_trigger(); 22 | } 23 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/aarch64/trap.rs: -------------------------------------------------------------------------------- 1 | use crate::context::TrapReason; 2 | use crate::{Info, Kind, Source, KCONFIG}; 3 | use cortex_a::registers::FAR_EL1; 4 | use tock_registers::interfaces::Readable; 5 | use trapframe::TrapFrame; 6 | use zcore_drivers::irq::gic_400::get_irq_num; 7 | 8 | #[no_mangle] 9 | pub extern "C" fn trap_handler(tf: &mut TrapFrame) { 10 | let info = Info { 11 | source: Source::from(tf.trap_num & 0xffff), 12 | kind: Kind::from((tf.trap_num >> 16) & 0xffff), 13 | }; 14 | trace!("Exception from {:?}", info.source); 15 | match info.kind { 16 | Kind::Synchronous => { 17 | sync_handler(tf); 18 | } 19 | Kind::Irq => { 20 | use crate::hal_fn::mem::phys_to_virt; 21 | crate::interrupt::handle_irq(get_irq_num( 22 | phys_to_virt(KCONFIG.gic_base + 0x1_0000), 23 | phys_to_virt(KCONFIG.gic_base), 24 | )); 25 | } 26 | _ => { 27 | panic!( 28 | "Unsupported exception type: {:?}, TrapFrame: {:?}", 29 | info.kind, tf 30 | ); 31 | } 32 | } 33 | trace!("Exception end"); 34 | } 35 | 36 | fn breakpoint(elr: &mut usize) { 37 | info!("Exception::Breakpoint: A breakpoint set @0x{:x} ", elr); 38 | *elr += 4; 39 | } 40 | 41 | fn sync_handler(tf: &mut TrapFrame) { 42 | match TrapReason::from(tf.trap_num) { 43 | TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags), 44 | TrapReason::SoftwareBreakpoint => breakpoint(&mut tf.elr), 45 | other => error!( 46 | "Unsupported trap in kernel: {:?}, FAR_EL1: {:#x?}", 47 | other, 48 | FAR_EL1.get() 49 | ), 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/riscv/config.rs: -------------------------------------------------------------------------------- 1 | //! Kernel configuration. 2 | 3 | /// Kernel configuration passed by kernel when calls [`crate::primary_init_early()`]. 4 | #[derive(Debug)] 5 | pub struct KernelConfig { 6 | pub phys_to_virt_offset: usize, 7 | pub dtb_paddr: usize, 8 | pub dtb_size: usize, 9 | } 10 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/riscv/cpu.rs: -------------------------------------------------------------------------------- 1 | //! CPU information. 2 | use crate::utils::init_once::InitOnce; 3 | 4 | pub(super) static CPU_FREQ_MHZ: InitOnce = InitOnce::new_with_default(1000); // 1GHz 5 | 6 | hal_fn_impl! { 7 | impl mod crate::hal_fn::cpu { 8 | fn cpu_id() -> u8 { 9 | let mut cpu_id; 10 | unsafe { core::arch::asm!("mv {0}, tp", out(reg) cpu_id) }; 11 | cpu_id 12 | } 13 | 14 | fn cpu_frequency() -> u16 { 15 | *CPU_FREQ_MHZ 16 | } 17 | 18 | fn reset() -> ! { 19 | info!("shutdown..."); 20 | sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::NoReason); 21 | unreachable!() 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/riscv/interrupt.rs: -------------------------------------------------------------------------------- 1 | //! Interrupts management. 2 | use crate::{HalError, HalResult}; 3 | use alloc::vec::Vec; 4 | use riscv::{asm, register::sstatus}; 5 | 6 | hal_fn_impl! { 7 | impl mod crate::hal_fn::interrupt { 8 | fn wait_for_interrupt() { 9 | let enable = sstatus::read().sie(); 10 | if !enable { 11 | unsafe { sstatus::set_sie() }; 12 | } 13 | unsafe { asm::wfi(); } 14 | if !enable { 15 | unsafe { sstatus::clear_sie() }; 16 | } 17 | } 18 | 19 | fn handle_irq(cause: usize) { 20 | trace!("Handle irq cause: {}", cause); 21 | let irq = crate::drivers::all_irq() 22 | .find(alloc::format!("riscv-intc-cpu{}", crate::cpu::cpu_id()).as_str()) 23 | .expect("IRQ device 'riscv-intc' not initialized!"); 24 | irq.handle_irq(cause) 25 | } 26 | 27 | fn intr_on() { 28 | unsafe { sstatus::set_sie() }; 29 | } 30 | 31 | fn intr_off() { 32 | unsafe { sstatus::clear_sie() }; 33 | } 34 | 35 | fn intr_get() -> bool { 36 | sstatus::read().sie() 37 | } 38 | 39 | #[allow(deprecated)] 40 | fn send_ipi(cpuid: usize, reason: usize) -> HalResult { 41 | trace!("ipi [{}] => [{}]", super::cpu::cpu_id(), cpuid); 42 | let queue = crate::common::ipi::ipi_queue(cpuid); 43 | let idx = queue.alloc_entry(); 44 | if let Some(idx) = idx { 45 | let entry = queue.entry_at(idx); 46 | *entry = reason; 47 | queue.commit_entry(idx); 48 | let mask:usize = 1 << cpuid; 49 | sbi_rt::legacy::send_ipi(&mask as *const usize as usize); 50 | return Ok(()); 51 | } 52 | Err(HalError) 53 | } 54 | 55 | fn ipi_reason() -> Vec { 56 | crate::common::ipi::ipi_reason() 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/riscv/mem.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use core::ops::Range; 3 | 4 | use crate::addr::{align_down, align_up}; 5 | use crate::utils::init_once::InitOnce; 6 | use crate::{PhysAddr, KCONFIG, PAGE_SIZE}; 7 | 8 | fn cut_off(total: Range, cut: &Range) -> Vec> { 9 | let mut regions = Vec::new(); 10 | // no overlap at all 11 | if cut.end <= total.start || total.end <= cut.start { 12 | regions.push(total); 13 | } else { 14 | // no overlap on the left 15 | if total.start < cut.start { 16 | regions.push(total.start..align_down(cut.start)); 17 | } 18 | // no overlap on the right 19 | if cut.end < total.end { 20 | regions.push(align_up(cut.end)..total.end); 21 | } 22 | } 23 | regions 24 | } 25 | 26 | pub fn free_pmem_regions() -> Vec> { 27 | extern "C" { 28 | fn end(); 29 | } 30 | 31 | static FREE_PMEM_REGIONS: InitOnce>> = InitOnce::new(); 32 | FREE_PMEM_REGIONS.init_once(|| { 33 | let initrd = super::INITRD_REGION.as_ref(); 34 | let dtb = Range:: { 35 | start: KCONFIG.dtb_paddr, 36 | end: KCONFIG.dtb_paddr + KCONFIG.dtb_size, 37 | }; 38 | let min_start = align_up(end as usize + PAGE_SIZE) - KCONFIG.phys_to_virt_offset; 39 | 40 | let mut regions = Vec::new(); 41 | for r in super::MEMORY_REGIONS.iter() { 42 | let base = align_up(r.start.max(min_start))..align_down(r.end); 43 | let mut no_dtb = cut_off(base, &dtb); 44 | if let Some(initrd) = initrd { 45 | for range in no_dtb { 46 | let mut no_initrd = cut_off(range, initrd); 47 | regions.append(&mut no_initrd); 48 | } 49 | } else { 50 | regions.append(&mut no_dtb); 51 | } 52 | } 53 | regions 54 | }); 55 | FREE_PMEM_REGIONS.clone() 56 | } 57 | 58 | pub fn frame_flush(_target: crate::PhysAddr) { 59 | unimplemented!() 60 | } 61 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/riscv/mod.rs: -------------------------------------------------------------------------------- 1 | mod drivers; 2 | mod trap; 3 | 4 | pub mod config; 5 | pub mod cpu; 6 | pub mod interrupt; 7 | pub mod mem; 8 | pub mod sbi; 9 | pub mod timer; 10 | pub mod vm; 11 | 12 | use crate::{mem::phys_to_virt, utils::init_once::InitOnce, PhysAddr}; 13 | use alloc::{string::String, vec::Vec}; 14 | use core::ops::Range; 15 | use zcore_drivers::utils::devicetree::Devicetree; 16 | 17 | static CMDLINE: InitOnce = InitOnce::new_with_default(String::new()); 18 | static INITRD_REGION: InitOnce>> = InitOnce::new_with_default(None); 19 | static MEMORY_REGIONS: InitOnce>> = InitOnce::new_with_default(Vec::new()); 20 | 21 | pub const fn timer_interrupt_vector() -> usize { 22 | trap::SUPERVISOR_TIMER_INT_VEC 23 | } 24 | 25 | pub fn cmdline() -> String { 26 | CMDLINE.clone() 27 | } 28 | 29 | pub fn init_ram_disk() -> Option<&'static mut [u8]> { 30 | INITRD_REGION.as_ref().map(|range| unsafe { 31 | core::slice::from_raw_parts_mut(phys_to_virt(range.start) as *mut u8, range.len()) 32 | }) 33 | } 34 | 35 | pub fn primary_init_early() { 36 | let dt = Devicetree::from(phys_to_virt(crate::KCONFIG.dtb_paddr)).unwrap(); 37 | if let Some(cmdline) = dt.bootargs() { 38 | info!("Load kernel cmdline from DTB: {:?}", cmdline); 39 | CMDLINE.init_once_by(cmdline.into()); 40 | } 41 | if let Some(time_freq) = dt.timebase_frequency() { 42 | info!("Load CPU clock frequency from DTB: {} Hz", time_freq); 43 | super::cpu::CPU_FREQ_MHZ.init_once_by((time_freq / 1_000_000) as u16); 44 | } 45 | if let Some(initrd_region) = dt.initrd_region() { 46 | info!("Load initrd regions from DTB: {:#x?}", initrd_region); 47 | INITRD_REGION.init_once_by(Some(initrd_region)); 48 | } 49 | if let Ok(regions) = dt.memory_regions() { 50 | info!("Load memory regions from DTB: {:#x?}", regions); 51 | MEMORY_REGIONS.init_once_by(regions); 52 | } 53 | } 54 | 55 | pub fn primary_init() { 56 | vm::init(); 57 | drivers::init().unwrap(); 58 | } 59 | 60 | pub fn timer_init() { 61 | timer::init(); 62 | } 63 | 64 | pub fn secondary_init() { 65 | vm::init(); 66 | info!("cpu {} drivers init ...", crate::cpu::cpu_id()); 67 | drivers::intc_init().unwrap(); 68 | let plic = crate::drivers::all_irq() 69 | .find("riscv-plic") 70 | .expect("IRQ device 'riscv-plic' not initialized!"); 71 | info!( 72 | "cpu {} enable plic: {:?}", 73 | crate::cpu::cpu_id(), 74 | plic.name() 75 | ); 76 | plic.init_hart(); 77 | } 78 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/riscv/timer.rs: -------------------------------------------------------------------------------- 1 | use core::time::Duration; 2 | 3 | fn get_cycle() -> u64 { 4 | riscv::register::time::read() as u64 5 | } 6 | 7 | pub(super) fn timer_set_next() { 8 | let cycles = 9 | super::cpu::cpu_frequency() as u64 * 1_000_000 / super::super::timer::TICKS_PER_SEC; 10 | sbi_rt::set_timer(get_cycle() + cycles); 11 | } 12 | 13 | pub(super) fn init() { 14 | timer_set_next(); 15 | } 16 | 17 | pub(crate) fn timer_now() -> Duration { 18 | Duration::from_nanos(get_cycle() * 1000 / super::cpu::cpu_frequency() as u64) 19 | } 20 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/riscv/trap.rs: -------------------------------------------------------------------------------- 1 | use crate::context::TrapReason; 2 | use crate::thread::{get_current_thread, set_current_thread}; 3 | use crate::IpiReason; 4 | use alloc::vec::Vec; 5 | use riscv::register::scause; 6 | use trapframe::TrapFrame; 7 | pub(super) const SUPERVISOR_TIMER_INT_VEC: usize = 5; // scause::Interrupt::SupervisorTimer 8 | 9 | fn breakpoint(sepc: &mut usize) { 10 | info!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc); 11 | 12 | //sepc为触发中断指令ebreak的地址 13 | //防止无限循环中断,让sret返回时跳转到sepc的下一条指令地址 14 | *sepc += 2 15 | } 16 | 17 | pub(super) fn super_timer() { 18 | super::timer::timer_set_next(); 19 | crate::timer::timer_tick(); 20 | //发生外界中断时,epc的指令还没有执行,故无需修改epc到下一条 21 | } 22 | 23 | pub(super) fn super_soft() { 24 | #[allow(deprecated)] 25 | sbi_rt::legacy::clear_ipi(); 26 | let reasons: Vec = crate::interrupt::ipi_reason() 27 | .iter() 28 | .map(|x| IpiReason::from(*x)) 29 | .collect(); 30 | debug!("Interrupt::SupervisorSoft, reason = {:?}", reasons); 31 | } 32 | 33 | #[no_mangle] 34 | pub extern "C" fn trap_handler(tf: &mut TrapFrame) { 35 | let scause = scause::read(); 36 | trace!("kernel trap happened: {:?}", TrapReason::from(scause)); 37 | trace!( 38 | "sepc = 0x{:x} pgtoken = 0x{:x}", 39 | tf.sepc, 40 | crate::vm::current_vmtoken() 41 | ); 42 | match TrapReason::from(scause) { 43 | TrapReason::SoftwareBreakpoint => breakpoint(&mut tf.sepc), 44 | TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags), 45 | TrapReason::Interrupt(vector) => { 46 | crate::interrupt::handle_irq(vector); 47 | if vector == SUPERVISOR_TIMER_INT_VEC { 48 | let current_thread = get_current_thread(); 49 | set_current_thread(None); 50 | executor::handle_timeout(); 51 | set_current_thread(current_thread); 52 | } 53 | } 54 | other => panic!("Undefined trap: {:x?} {:#x?}", other, tf), 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/x86_64/config.rs: -------------------------------------------------------------------------------- 1 | //! Kernel configuration. 2 | 3 | use uefi::proto::console::gop::ModeInfo; 4 | use uefi::table::boot::MemoryDescriptor; 5 | 6 | /// Kernel configuration passed by kernel when calls [`crate::primary_init_early()`]. 7 | #[derive(Debug)] 8 | pub struct KernelConfig { 9 | pub cmdline: &'static str, 10 | pub initrd_start: u64, 11 | pub initrd_size: u64, 12 | 13 | pub memory_map: &'static [&'static MemoryDescriptor], 14 | pub phys_to_virt_offset: usize, 15 | 16 | pub fb_mode: ModeInfo, 17 | pub fb_addr: u64, 18 | pub fb_size: u64, 19 | 20 | pub acpi_rsdp: u64, 21 | pub smbios: u64, 22 | pub ap_fn: fn() -> !, 23 | } 24 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/x86_64/cpu.rs: -------------------------------------------------------------------------------- 1 | //! CPU information. 2 | 3 | use raw_cpuid::CpuId; 4 | 5 | hal_fn_impl! { 6 | impl mod crate::hal_fn::cpu { 7 | fn cpu_id() -> u8 { 8 | CpuId::new() 9 | .get_feature_info() 10 | .unwrap() 11 | .initial_local_apic_id() as u8 12 | } 13 | 14 | fn cpu_frequency() -> u16 { 15 | static CPU_FREQ_MHZ: spin::Once = spin::Once::new(); 16 | *CPU_FREQ_MHZ.call_once(|| { 17 | const DEFAULT: u16 = 4000; 18 | CpuId::new() 19 | .get_processor_frequency_info() 20 | .map(|info| info.processor_base_frequency()) 21 | .unwrap_or(DEFAULT) 22 | .max(DEFAULT) 23 | }) 24 | } 25 | 26 | fn reset() -> ! { 27 | info!("shutdown..."); 28 | loop { 29 | use zcore_drivers::io::{Io, Pmio}; 30 | Pmio::::new(0x604).write(0x2000); 31 | super::interrupt::wait_for_interrupt(); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/x86_64/mem.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use core::arch::x86_64::{__cpuid, _mm_clflush, _mm_mfence}; 3 | use core::ops::Range; 4 | 5 | use uefi::table::boot::MemoryType; 6 | 7 | use crate::{mem::phys_to_virt, PhysAddr, KCONFIG, PAGE_SIZE}; 8 | 9 | pub fn free_pmem_regions() -> Vec> { 10 | KCONFIG 11 | .memory_map 12 | .iter() 13 | .filter_map(|r| { 14 | if r.ty == MemoryType::CONVENTIONAL { 15 | let start = r.phys_start as usize; 16 | let end = start + r.page_count as usize * PAGE_SIZE; 17 | Some(start..end) 18 | } else { 19 | None 20 | } 21 | }) 22 | .collect() 23 | } 24 | 25 | // Get cache line size in bytes. 26 | fn cacheline_size() -> usize { 27 | let leaf = unsafe { __cpuid(1).ebx }; 28 | (((leaf >> 8) & 0xff) << 3) as usize 29 | } 30 | 31 | /// Flush the physical frame. 32 | pub fn frame_flush(target: PhysAddr) { 33 | unsafe { 34 | for paddr in (target..target + PAGE_SIZE).step_by(cacheline_size()) { 35 | _mm_clflush(phys_to_virt(paddr) as *const u8); 36 | } 37 | _mm_mfence(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/x86_64/mod.rs: -------------------------------------------------------------------------------- 1 | mod drivers; 2 | mod trap; 3 | 4 | pub mod config; 5 | pub mod cpu; 6 | pub mod interrupt; 7 | pub mod mem; 8 | pub mod timer; 9 | pub mod vm; 10 | 11 | #[doc(cfg(target_arch = "x86_64"))] 12 | pub mod special; 13 | 14 | hal_fn_impl_default!(crate::hal_fn::console); 15 | 16 | use crate::{mem::phys_to_virt, KCONFIG}; 17 | use x86_64::registers::control::{Cr4, Cr4Flags}; 18 | 19 | pub const fn timer_interrupt_vector() -> usize { 20 | trap::X86_INT_APIC_TIMER 21 | } 22 | 23 | pub fn cmdline() -> alloc::string::String { 24 | KCONFIG.cmdline.into() 25 | } 26 | 27 | pub fn init_ram_disk() -> Option<&'static mut [u8]> { 28 | let start = phys_to_virt(KCONFIG.initrd_start as usize); 29 | Some(unsafe { core::slice::from_raw_parts_mut(start as *mut u8, KCONFIG.initrd_size as usize) }) 30 | } 31 | 32 | pub fn primary_init_early() { 33 | // init serial output first 34 | drivers::init_early().unwrap(); 35 | } 36 | 37 | pub fn primary_init() { 38 | drivers::init().unwrap(); 39 | 40 | let stack_fn = |pid: usize| -> usize { 41 | // split and reuse the current stack 42 | let mut stack: usize; 43 | unsafe { core::arch::asm!("mov {}, rsp", out(reg) stack) }; 44 | stack -= 0x4000 * pid; 45 | stack 46 | }; 47 | unsafe { 48 | // enable global page 49 | Cr4::update(|f| f.insert(Cr4Flags::PAGE_GLOBAL)); 50 | // start multi-processors 51 | x86_smpboot::start_application_processors( 52 | || (crate::KCONFIG.ap_fn)(), 53 | stack_fn, 54 | phys_to_virt, 55 | ); 56 | } 57 | } 58 | 59 | pub fn timer_init() { 60 | timer::init(); 61 | } 62 | 63 | pub fn secondary_init() { 64 | zcore_drivers::irq::x86::Apic::init_local_apic_ap(); 65 | } 66 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/x86_64/special.rs: -------------------------------------------------------------------------------- 1 | //! Functions only available on x86 platforms. 2 | 3 | pub use zcore_drivers::io::{Io, Pmio}; 4 | 5 | /// Get physical address of `acpi_rsdp` and `smbios` on x86_64. 6 | pub fn pc_firmware_tables() -> (u64, u64) { 7 | (crate::KCONFIG.acpi_rsdp, crate::KCONFIG.smbios) 8 | } 9 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/x86_64/timer.rs: -------------------------------------------------------------------------------- 1 | use core::time::Duration; 2 | 3 | pub fn timer_now() -> Duration { 4 | let cycle = unsafe { core::arch::x86_64::_rdtsc() }; 5 | Duration::from_nanos(cycle * 1000 / super::cpu::cpu_frequency() as u64) 6 | } 7 | 8 | pub fn init() { 9 | let irq = crate::drivers::all_irq().first_unwrap(); 10 | irq.apic_timer_enable(); 11 | } 12 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/arch/x86_64/trap.rs: -------------------------------------------------------------------------------- 1 | use crate::context::TrapReason; 2 | use trapframe::TrapFrame; 3 | 4 | pub(super) const X86_INT_LOCAL_APIC_BASE: usize = 0xf0; 5 | pub(super) const _X86_INT_APIC_SPURIOUS: usize = X86_INT_LOCAL_APIC_BASE; 6 | pub(super) const X86_INT_APIC_TIMER: usize = X86_INT_LOCAL_APIC_BASE + 0x1; 7 | pub(super) const _X86_INT_APIC_ERROR: usize = X86_INT_LOCAL_APIC_BASE + 0x2; 8 | 9 | // ISA IRQ numbers 10 | pub(super) const _X86_ISA_IRQ_PIT: usize = 0; 11 | pub(super) const _X86_ISA_IRQ_KEYBOARD: usize = 1; 12 | pub(super) const _X86_ISA_IRQ_PIC2: usize = 2; 13 | pub(super) const X86_ISA_IRQ_COM2: usize = 3; 14 | pub(super) const X86_ISA_IRQ_COM1: usize = 4; 15 | pub(super) const _X86_ISA_IRQ_CMOSRTC: usize = 8; 16 | pub(super) const _X86_ISA_IRQ_MOUSE: usize = 12; 17 | pub(super) const _X86_ISA_IRQ_IDE: usize = 14; 18 | 19 | fn breakpoint() { 20 | panic!("\nEXCEPTION: Breakpoint"); 21 | } 22 | 23 | pub(super) fn super_timer() { 24 | crate::timer::timer_tick(); 25 | } 26 | 27 | #[no_mangle] 28 | pub extern "C" fn trap_handler(tf: &mut TrapFrame) { 29 | trace!( 30 | "Interrupt: {:#x} @ CPU{}", 31 | tf.trap_num, 32 | super::cpu::cpu_id() 33 | ); 34 | 35 | match TrapReason::from(tf.trap_num, tf.error_code) { 36 | TrapReason::HardwareBreakpoint | TrapReason::SoftwareBreakpoint => breakpoint(), 37 | TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags), 38 | TrapReason::Interrupt(vector) => { 39 | crate::interrupt::handle_irq(vector); 40 | if vector == X86_INT_APIC_TIMER { 41 | executor::handle_timeout(); 42 | } 43 | } 44 | other => panic!("Unhandled trap {:x?} {:#x?}", other, tf), 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/boot.rs: -------------------------------------------------------------------------------- 1 | //! Bootstrap and initialization. 2 | 3 | use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER}; 4 | 5 | hal_fn_impl! { 6 | impl mod crate::hal_fn::boot { 7 | fn cmdline() -> alloc::string::String { 8 | super::arch::cmdline() 9 | } 10 | 11 | fn init_ram_disk() -> Option<&'static mut [u8]> { 12 | super::arch::init_ram_disk() 13 | } 14 | 15 | fn primary_init_early(cfg: KernelConfig, handler: &'static impl KernelHandler) { 16 | info!("Primary CPU {} init early...", crate::cpu::cpu_id()); 17 | KCONFIG.init_once_by(cfg); 18 | KHANDLER.init_once_by(handler); 19 | super::arch::primary_init_early(); 20 | } 21 | 22 | fn primary_init() { 23 | info!("Primary CPU {} init...", crate::cpu::cpu_id()); 24 | unsafe { trapframe::init() }; 25 | super::arch::primary_init(); 26 | } 27 | 28 | fn secondary_init() { 29 | // info!("Secondary CPU {} init...", crate::cpu::cpu_id()); 30 | // we can't print anything here, see reason: zcore/main.rs::secondary_main() 31 | unsafe { trapframe::init() }; 32 | super::arch::secondary_init(); 33 | // now can print 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/mem.rs: -------------------------------------------------------------------------------- 1 | //! Physical memory operations. 2 | 3 | use alloc::vec::Vec; 4 | use core::ops::Range; 5 | 6 | use crate::{PhysAddr, VirtAddr, KCONFIG}; 7 | 8 | hal_fn_impl! { 9 | impl mod crate::hal_fn::mem { 10 | fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { 11 | KCONFIG.phys_to_virt_offset + paddr 12 | } 13 | 14 | fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { 15 | vaddr - KCONFIG.phys_to_virt_offset 16 | } 17 | 18 | fn free_pmem_regions() -> Vec> { 19 | super::arch::mem::free_pmem_regions() 20 | } 21 | 22 | fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) { 23 | trace!("pmem_read: paddr={:#x}, len={:#x}", paddr, buf.len()); 24 | let src = phys_to_virt(paddr) as _; 25 | unsafe { buf.as_mut_ptr().copy_from_nonoverlapping(src, buf.len()) }; 26 | } 27 | 28 | fn pmem_write(paddr: PhysAddr, buf: &[u8]) { 29 | trace!("pmem_write: paddr={:#x}, len={:#x}", paddr, buf.len()); 30 | let dst = phys_to_virt(paddr) as *mut u8; 31 | unsafe { dst.copy_from_nonoverlapping(buf.as_ptr(), buf.len()) }; 32 | } 33 | 34 | fn pmem_zero(paddr: PhysAddr, len: usize) { 35 | trace!("pmem_zero: paddr={:#x}, len={:#x}", paddr, len); 36 | unsafe { core::ptr::write_bytes(phys_to_virt(paddr) as *mut u8, 0, len) }; 37 | } 38 | 39 | fn pmem_copy(dst: PhysAddr, src: PhysAddr, len: usize) { 40 | trace!("pmem_copy: {:#x} <- {:#x}, len={:#x}", dst, src, len); 41 | let dst = phys_to_virt(dst) as *mut u8; 42 | unsafe { dst.copy_from_nonoverlapping(phys_to_virt(src) as _, len) }; 43 | } 44 | 45 | fn frame_flush(target: PhysAddr) { 46 | super::arch::mem::frame_flush(target) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/mod.rs: -------------------------------------------------------------------------------- 1 | cfg_if! { 2 | if #[cfg(target_arch = "x86_64")] { 3 | #[path = "arch/x86_64/mod.rs"] 4 | mod arch; 5 | pub use self::arch::{special as x86_64, timer_interrupt_vector}; 6 | } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { 7 | #[path = "arch/riscv/mod.rs"] 8 | pub mod arch; 9 | pub use self::arch::{sbi, timer_interrupt_vector}; 10 | } else if #[cfg(target_arch = "aarch64")] { 11 | #[path = "arch/aarch64/mod.rs"] 12 | pub mod arch; 13 | pub use self::arch::timer_interrupt_vector; 14 | } 15 | } 16 | 17 | pub mod boot; 18 | pub mod mem; 19 | pub mod net; 20 | pub mod thread; 21 | pub mod timer; 22 | 23 | pub use self::arch::{config, cpu, interrupt, vm}; 24 | pub use super::hal_fn::{rand, vdso}; 25 | 26 | hal_fn_impl_default!(rand, vdso); 27 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/net.rs: -------------------------------------------------------------------------------- 1 | // May need move to drivers 2 | use smoltcp::{ 3 | iface::{InterfaceBuilder, NeighborCache, Route, Routes}, 4 | phy::{Loopback, Medium}, 5 | wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}, 6 | }; 7 | 8 | use alloc::collections::BTreeMap; 9 | use alloc::vec::Vec; 10 | 11 | // use zcore_drivers::net::get_sockets; 12 | use alloc::sync::Arc; 13 | 14 | use alloc::string::String; 15 | use lock::Mutex; 16 | 17 | use crate::drivers::add_device; 18 | use crate::drivers::all_net; 19 | use zcore_drivers::net::LoopbackInterface; 20 | use zcore_drivers::scheme::NetScheme; 21 | use zcore_drivers::Device; 22 | 23 | pub fn init() { 24 | let name = String::from("loopback"); 25 | warn!("name : {}", name); 26 | // 初始化 一个 协议栈 27 | // 从外界 接受 一些 配置 参数 如果 没有 选择 默认 的 28 | 29 | // 网络 设备 30 | // 默认 loopback 31 | let loopback = Loopback::new(Medium::Ethernet); 32 | 33 | // 为 设备 分配 网络 身份 34 | 35 | // 物理地址 36 | let mac: [u8; 6] = [0x52, 0x54, 0x98, 0x76, 0x54, 0x32]; 37 | let ethernet_addr = EthernetAddress::from_bytes(&mac); 38 | // ip 地址 39 | let ip_addrs = [IpCidr::new(IpAddress::v4(127, 0, 0, 1), 24)]; 40 | // qemu 41 | // let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 2, 15), 24)]; 42 | // 路由 43 | let default_gateway = Ipv4Address::new(127, 0, 0, 1); 44 | // qemu route 45 | // let default_gateway = Ipv4Address::new(10, 0, 2, 2); 46 | static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1]; 47 | let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) }; 48 | routes.add_default_ipv4_route(default_gateway).unwrap(); 49 | // arp缓存 50 | let neighbor_cache = NeighborCache::new(BTreeMap::new()); 51 | 52 | // 设置 主要 设置 iface 53 | let iface = InterfaceBuilder::new(loopback) 54 | .ethernet_addr(ethernet_addr) 55 | .ip_addrs(ip_addrs) 56 | .routes(routes) 57 | .neighbor_cache(neighbor_cache) 58 | .finalize(); 59 | 60 | let loopback_iface = LoopbackInterface { 61 | iface: Arc::new(Mutex::new(iface)), 62 | name, 63 | }; 64 | // loopback_iface 65 | let dev = Device::Net(Arc::new(loopback_iface)); 66 | add_device(dev); 67 | } 68 | 69 | pub fn get_net_device() -> Vec> { 70 | all_net().as_vec().clone() 71 | } 72 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/thread.rs: -------------------------------------------------------------------------------- 1 | //! Thread spawning. 2 | 3 | use alloc::sync::Arc; 4 | use core::{any::Any, future::Future}; 5 | 6 | use crate::{config::MAX_CORE_NUM, utils::PerCpuCell}; 7 | 8 | #[allow(clippy::declare_interior_mutable_const)] 9 | const DEFAULT_THREAD: PerCpuCell>> = PerCpuCell::new(None); 10 | 11 | static CURRENT_THREAD: [PerCpuCell>>; MAX_CORE_NUM] = 12 | [DEFAULT_THREAD; MAX_CORE_NUM]; 13 | 14 | hal_fn_impl! { 15 | impl mod crate::hal_fn::thread { 16 | fn spawn(future: impl Future + Send + 'static) { 17 | executor::spawn(future); 18 | } 19 | 20 | fn set_current_thread(thread: Option>) { 21 | let cpu_id = super::cpu::cpu_id() as usize; 22 | *CURRENT_THREAD[cpu_id].get_mut() = thread; 23 | } 24 | 25 | fn get_current_thread() -> Option> { 26 | let cpu_id = super::cpu::cpu_id() as usize; 27 | if let Some(arc_thread) = CURRENT_THREAD[cpu_id].get().as_ref() { 28 | Some(arc_thread.clone()) 29 | } else { 30 | None 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /kernel-hal/src/bare/timer.rs: -------------------------------------------------------------------------------- 1 | //! Time and clock functions. 2 | 3 | use alloc::boxed::Box; 4 | use core::time::Duration; 5 | 6 | use lock::Mutex; 7 | use naive_timer::Timer; 8 | 9 | #[allow(dead_code)] 10 | pub(super) const TICKS_PER_SEC: u64 = 1; 11 | 12 | lazy_static::lazy_static! { 13 | static ref NAIVE_TIMER:Mutex = Mutex::new(Timer::default()); 14 | } 15 | 16 | hal_fn_impl! { 17 | impl mod crate::hal_fn::timer { 18 | fn timer_enable() { 19 | super::arch::timer_init(); 20 | } 21 | 22 | fn timer_now() -> Duration { 23 | super::arch::timer::timer_now() 24 | } 25 | 26 | fn timer_set(deadline: Duration, callback: Box) { 27 | debug!("Set timer at: {:?}", deadline); 28 | NAIVE_TIMER.lock().add(deadline, callback); 29 | } 30 | 31 | fn timer_tick() { 32 | NAIVE_TIMER.lock().expire(timer_now()); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /kernel-hal/src/common/addr.rs: -------------------------------------------------------------------------------- 1 | //! Definition of phyical, virtual addresses and helper functions. 2 | 3 | use crate::PAGE_SIZE; 4 | 5 | /// Physical address. 6 | pub type PhysAddr = usize; 7 | 8 | /// Virtual address. 9 | pub type VirtAddr = usize; 10 | 11 | /// Device address. 12 | pub type DevVAddr = usize; 13 | 14 | pub const fn align_down(addr: usize) -> usize { 15 | addr & !(PAGE_SIZE - 1) 16 | } 17 | 18 | pub const fn align_up(addr: usize) -> usize { 19 | (addr + PAGE_SIZE - 1) & !(PAGE_SIZE - 1) 20 | } 21 | 22 | pub const fn is_aligned(addr: usize) -> bool { 23 | page_offset(addr) == 0 24 | } 25 | 26 | pub const fn page_count(size: usize) -> usize { 27 | align_up(size) / PAGE_SIZE 28 | } 29 | 30 | pub const fn page_offset(addr: usize) -> usize { 31 | addr & (PAGE_SIZE - 1) 32 | } 33 | -------------------------------------------------------------------------------- /kernel-hal/src/common/mod.rs: -------------------------------------------------------------------------------- 1 | pub(super) mod defs; 2 | pub(super) mod future; 3 | pub(super) mod mem; 4 | pub(super) mod thread; 5 | pub(super) mod vdso; 6 | pub(super) mod vm; 7 | 8 | pub mod addr; 9 | pub mod console; 10 | pub mod context; 11 | pub mod ipi; 12 | pub mod user; 13 | -------------------------------------------------------------------------------- /kernel-hal/src/common/thread.rs: -------------------------------------------------------------------------------- 1 | use core::time::Duration; 2 | 3 | use super::future::{SleepFuture, YieldFuture}; 4 | 5 | /// Sleeps until the specified of time. 6 | pub async fn sleep_until(deadline: Duration) { 7 | SleepFuture::new(deadline).await 8 | } 9 | 10 | /// Yields execution back to the async runtime. 11 | pub async fn yield_now() { 12 | YieldFuture::default().await 13 | } 14 | -------------------------------------------------------------------------------- /kernel-hal/src/config.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::init_once::InitOnce; 2 | 3 | pub use super::imp::config::KernelConfig; 4 | 5 | #[cfg(feature = "libos")] 6 | pub(crate) static KCONFIG: InitOnce = InitOnce::new_with_default(KernelConfig); 7 | 8 | #[cfg(not(feature = "libos"))] 9 | pub(crate) static KCONFIG: InitOnce = InitOnce::new(); 10 | 11 | pub const MAX_CORE_NUM: usize = 8; 12 | -------------------------------------------------------------------------------- /kernel-hal/src/kernel_handler.rs: -------------------------------------------------------------------------------- 1 | //! Handlers implemented in kernel and called by HAL. 2 | 3 | use crate::{utils::init_once::InitOnce, MMUFlags, PhysAddr, VirtAddr}; 4 | 5 | /// Functions implemented in the kernel and used by HAL funtions. 6 | pub trait KernelHandler: Send + Sync + 'static { 7 | /// Allocate one physical frame. 8 | fn frame_alloc(&self) -> Option { 9 | unimplemented!() 10 | } 11 | 12 | /// Allocate contiguous `frame_count` physical frames. 13 | fn frame_alloc_contiguous(&self, _frame_count: usize, _align_log2: usize) -> Option { 14 | unimplemented!() 15 | } 16 | 17 | /// Deallocate a physical frame. 18 | fn frame_dealloc(&self, _paddr: PhysAddr) { 19 | unimplemented!() 20 | } 21 | 22 | /// Handle kernel mode page fault. 23 | fn handle_page_fault(&self, _fault_vaddr: VirtAddr, _access_flags: MMUFlags) { 24 | // do nothing 25 | } 26 | } 27 | 28 | #[allow(dead_code)] 29 | pub(crate) struct DummyKernelHandler; 30 | 31 | #[cfg(feature = "libos")] 32 | pub(crate) static KHANDLER: InitOnce<&dyn KernelHandler> = 33 | InitOnce::new_with_default(&DummyKernelHandler); 34 | 35 | #[cfg(not(feature = "libos"))] 36 | pub(crate) static KHANDLER: InitOnce<&dyn KernelHandler> = InitOnce::new(); 37 | -------------------------------------------------------------------------------- /kernel-hal/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Hardware Abstraction Layer 2 | 3 | #![cfg_attr(not(feature = "libos"), no_std)] 4 | #![cfg_attr(feature = "libos", feature(thread_id_value))] 5 | #![feature(doc_cfg)] 6 | #![feature(if_let_guard)] 7 | // #![feature(core_intrinsics)] 8 | #![allow(clippy::uninit_vec)] 9 | #![deny(warnings)] 10 | // JUST FOR DEBUG 11 | #![allow(dead_code)] 12 | 13 | extern crate alloc; 14 | #[macro_use] 15 | extern crate log; 16 | #[macro_use] 17 | extern crate cfg_if; 18 | #[macro_use] 19 | extern crate lazy_static; 20 | 21 | #[macro_use] 22 | mod macros; 23 | 24 | mod common; 25 | mod config; 26 | mod hal_fn; 27 | mod kernel_handler; 28 | mod utils; 29 | 30 | pub mod drivers; 31 | 32 | cfg_if! { 33 | if #[cfg(feature = "libos")] { 34 | #[path = "libos/mod.rs"] 35 | mod imp; 36 | } else { 37 | #[path = "bare/mod.rs"] 38 | mod imp; 39 | } 40 | } 41 | 42 | pub(crate) use config::KCONFIG; 43 | pub(crate) use kernel_handler::KHANDLER; 44 | 45 | pub use common::{addr, console, context, defs::*, ipi::*, user}; 46 | pub use config::KernelConfig; 47 | pub use imp::{ 48 | boot::{primary_init, primary_init_early, secondary_init}, 49 | *, 50 | }; 51 | pub use kernel_handler::KernelHandler; 52 | pub use utils::{lazy_init::LazyInit, mpsc_queue::MpscQueue}; 53 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/boot.rs: -------------------------------------------------------------------------------- 1 | //! Bootstrap and initialization. 2 | 3 | use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER}; 4 | 5 | hal_fn_impl! { 6 | impl mod crate::hal_fn::boot { 7 | fn primary_init_early(cfg: KernelConfig, handler: &'static impl KernelHandler) { 8 | KCONFIG.init_once_by(cfg); 9 | KHANDLER.init_once_by(handler); 10 | super::drivers::init_early(); 11 | } 12 | 13 | fn primary_init() { 14 | super::drivers::init(); 15 | 16 | #[cfg(target_os = "macos")] 17 | unsafe { 18 | super::macos::register_sigsegv_handler(); 19 | } 20 | 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/config.rs: -------------------------------------------------------------------------------- 1 | //! Kernel configuration. 2 | 3 | /// Kernel configuration passed by kernel when calls [`crate::primary_init_early()`]. 4 | #[derive(Debug)] 5 | pub struct KernelConfig; 6 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/cpu.rs: -------------------------------------------------------------------------------- 1 | //! CPU information. 2 | 3 | hal_fn_impl! { 4 | impl mod crate::hal_fn::cpu { 5 | fn cpu_id() -> u8 { 6 | std::thread::current().id().as_u64().get() as u8 7 | } 8 | 9 | fn reset() -> ! { 10 | info!("shutdown..."); 11 | std::process::exit(0); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/drivers.rs: -------------------------------------------------------------------------------- 1 | use alloc::sync::Arc; 2 | 3 | use crate::drivers; 4 | use zcore_drivers::mock::uart::MockUart; 5 | use zcore_drivers::{scheme::Scheme, Device}; 6 | 7 | cfg_if! { 8 | if #[cfg(feature = "graphic")] { 9 | use crate::{addr::page_count, mem::PhysFrame}; 10 | use alloc::vec::Vec; 11 | use zcore_drivers::prelude::ColorFormat; 12 | 13 | const FB_WIDTH: u32 = 1280; 14 | const FB_HEIGHT: u32 = 720; 15 | const FB_FORMAT: ColorFormat = ColorFormat::ARGB8888; 16 | 17 | lazy_static! { 18 | /// Put the framebuffer into the physical frames pool to support mmap. 19 | static ref FB_FRAMES: Vec = PhysFrame::new_contiguous( 20 | page_count((FB_WIDTH * FB_HEIGHT * FB_FORMAT.bytes() as u32) as usize), 21 | 0, 22 | ); 23 | } 24 | } 25 | } 26 | 27 | pub(super) fn init_early() { 28 | let uart = Arc::new(MockUart::new()); 29 | drivers::add_device(Device::Uart(uart.clone())); 30 | MockUart::start_irq_service(move || uart.handle_irq(0)); 31 | } 32 | 33 | pub(super) fn init() { 34 | #[cfg(feature = "graphic")] 35 | { 36 | use zcore_drivers::mock::display::MockDisplay; 37 | use zcore_drivers::mock::input::{MockKeyboard, MockMouse}; 38 | 39 | let display = Arc::new(unsafe { 40 | MockDisplay::from_raw_parts(FB_WIDTH, FB_HEIGHT, FB_FORMAT, FB_FRAMES[0].as_mut_ptr()) 41 | }); 42 | drivers::add_device(Device::Display(display.clone())); 43 | drivers::add_device(Device::Input(Arc::new(MockKeyboard::default()))); 44 | drivers::add_device(Device::Input(Arc::new(MockMouse::default()))); 45 | 46 | crate::console::init_graphic_console(display); 47 | } 48 | 49 | #[cfg(feature = "loopback")] 50 | { 51 | use crate::net; 52 | net::init(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/dummy.rs: -------------------------------------------------------------------------------- 1 | use bitmap_allocator::BitAlloc; 2 | 3 | use super::mem::FRAME_ALLOCATOR; 4 | use crate::kernel_handler::{DummyKernelHandler, KernelHandler}; 5 | use crate::{PhysAddr, PAGE_SIZE}; 6 | 7 | impl KernelHandler for DummyKernelHandler { 8 | fn frame_alloc(&self) -> Option { 9 | let ret = FRAME_ALLOCATOR.lock().alloc().map(|id| id * PAGE_SIZE); 10 | trace!("Allocate frame: {:x?}", ret); 11 | ret 12 | } 13 | 14 | fn frame_alloc_contiguous(&self, frame_count: usize, align_log2: usize) -> Option { 15 | let ret = FRAME_ALLOCATOR 16 | .lock() 17 | .alloc_contiguous(frame_count, align_log2) 18 | .map(|id| id * PAGE_SIZE); 19 | trace!( 20 | "Allocate contiguous frames: {:x?} ~ {:x?}", 21 | ret, 22 | ret.map(|x| x + frame_count) 23 | ); 24 | ret 25 | } 26 | 27 | fn frame_dealloc(&self, paddr: PhysAddr) { 28 | trace!("Deallocate frame: {:x}", paddr); 29 | FRAME_ALLOCATOR.lock().dealloc(paddr / PAGE_SIZE); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/interrupt.rs: -------------------------------------------------------------------------------- 1 | use crate::HalResult; 2 | 3 | hal_fn_impl! { 4 | impl mod crate::hal_fn::interrupt { 5 | fn wait_for_interrupt() {} 6 | fn intr_on() {} 7 | fn intr_off() {} 8 | fn intr_get() -> bool { 9 | false 10 | } 11 | fn send_ipi(cpuid: usize, reason: usize) -> HalResult { 12 | trace!("ipi [{}] => [{}]: {:x}", super::cpu::cpu_id(), cpuid, reason); 13 | Ok(()) 14 | } 15 | fn ipi_reason() -> Vec { 16 | Vec::new() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/mod.rs: -------------------------------------------------------------------------------- 1 | mod drivers; 2 | mod dummy; 3 | mod mock_mem; 4 | 5 | pub mod boot; 6 | pub mod config; 7 | pub mod cpu; 8 | pub mod interrupt; 9 | pub mod mem; 10 | pub mod net; 11 | pub mod thread; 12 | pub mod timer; 13 | pub mod vdso; 14 | pub mod vm; 15 | 16 | #[path = "special.rs"] 17 | #[doc(cfg(feature = "libos"))] 18 | pub mod libos; 19 | 20 | pub use super::hal_fn::rand; 21 | 22 | hal_fn_impl_default!(rand, super::hal_fn::console); 23 | 24 | #[cfg(target_os = "macos")] 25 | mod macos; 26 | 27 | /// Non-SMP initialization. 28 | pub fn init() { 29 | drivers::init_early(); 30 | boot::primary_init(); 31 | } 32 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/net.rs: -------------------------------------------------------------------------------- 1 | // May need move to drivers 2 | use smoltcp::{ 3 | iface::{InterfaceBuilder, NeighborCache, Route, Routes}, 4 | phy::{Loopback, Medium}, 5 | wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}, 6 | }; 7 | 8 | use alloc::collections::BTreeMap; 9 | use alloc::vec::Vec; 10 | 11 | // use zcore_drivers::net::get_sockets; 12 | use alloc::sync::Arc; 13 | 14 | use alloc::string::String; 15 | use lock::Mutex; 16 | 17 | use crate::drivers::add_device; 18 | use crate::drivers::all_net; 19 | use zcore_drivers::net::LoopbackInterface; 20 | use zcore_drivers::scheme::NetScheme; 21 | use zcore_drivers::Device; 22 | 23 | pub fn init() { 24 | let name = String::from("loopback"); 25 | warn!("name : {}", name); 26 | // 初始化 一个 协议栈 27 | // 从外界 接受 一些 配置 参数 如果 没有 选择 默认 的 28 | 29 | // 网络 设备 30 | // 默认 loopback 31 | let loopback = Loopback::new(Medium::Ethernet); 32 | 33 | // 为 设备 分配 网络 身份 34 | 35 | // 物理地址 36 | let mac: [u8; 6] = [0x52, 0x54, 0x98, 0x76, 0x54, 0x32]; 37 | let ethernet_addr = EthernetAddress::from_bytes(&mac); 38 | // ip 地址 39 | let ip_addrs = [IpCidr::new(IpAddress::v4(127, 0, 0, 1), 24)]; 40 | // qemu 41 | // let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 2, 15), 24)]; 42 | // 路由 43 | let default_gateway = Ipv4Address::new(127, 0, 0, 1); 44 | // qemu route 45 | // let default_gateway = Ipv4Address::new(10, 0, 2, 2); 46 | static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1]; 47 | let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) }; 48 | routes.add_default_ipv4_route(default_gateway).unwrap(); 49 | // arp缓存 50 | let neighbor_cache = NeighborCache::new(BTreeMap::new()); 51 | 52 | // 设置 主要 设置 iface 53 | let iface = InterfaceBuilder::new(loopback) 54 | .ethernet_addr(ethernet_addr) 55 | .ip_addrs(ip_addrs) 56 | .routes(routes) 57 | .neighbor_cache(neighbor_cache) 58 | .finalize(); 59 | 60 | let loopback_iface = LoopbackInterface { 61 | iface: Arc::new(Mutex::new(iface)), 62 | name, 63 | }; 64 | // loopback_iface 65 | let dev = Device::Net(Arc::new(loopback_iface)); 66 | add_device(dev); 67 | } 68 | 69 | pub fn get_net_device() -> Vec> { 70 | all_net().as_vec().clone() 71 | } 72 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/special.rs: -------------------------------------------------------------------------------- 1 | //! Functions only available on the libos mode. 2 | 3 | #[cfg(feature = "graphic")] 4 | pub fn run_graphic_service() { 5 | use crate::drivers::{all_display, all_input}; 6 | use zcore_drivers::mock::graphic::sdl::SdlWindow; 7 | 8 | let mut window = SdlWindow::new("zcore-libos", all_display().first_unwrap()); 9 | if let Some(i) = all_input().find("mock-mouse-input") { 10 | window.register_mouse(i); 11 | } 12 | if let Some(i) = all_input().find("mock-keyboard-input") { 13 | window.register_keyboard(i); 14 | } 15 | 16 | while !window.is_quit() { 17 | window.handle_events(); 18 | window.flush(); 19 | std::thread::sleep(std::time::Duration::from_millis(30)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/thread.rs: -------------------------------------------------------------------------------- 1 | //! Thread spawning. 2 | 3 | use alloc::sync::Arc; 4 | use async_std::task_local; 5 | use core::{any::Any, cell::RefCell, future::Future}; 6 | 7 | task_local! { 8 | static CURRENT_THREAD: RefCell>> = RefCell::new(None); 9 | } 10 | 11 | hal_fn_impl! { 12 | impl mod crate::hal_fn::thread { 13 | fn spawn(future: impl Future + Send + 'static) { 14 | async_std::task::spawn(future); 15 | } 16 | 17 | fn set_current_thread(thread: Option>) { 18 | CURRENT_THREAD.with(|t| *t.borrow_mut() = thread); 19 | } 20 | 21 | fn get_current_thread() -> Option> { 22 | CURRENT_THREAD.try_with(|t| { 23 | t.borrow().as_ref().cloned() 24 | }).unwrap_or(None) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/timer.rs: -------------------------------------------------------------------------------- 1 | //! Time and clock functions. 2 | 3 | use async_std::task; 4 | use std::time::{Duration, SystemTime}; 5 | 6 | hal_fn_impl! { 7 | impl mod crate::hal_fn::timer { 8 | fn timer_now() -> Duration { 9 | SystemTime::now() 10 | .duration_since(SystemTime::UNIX_EPOCH) 11 | .unwrap() 12 | } 13 | 14 | fn timer_set(deadline: Duration, callback: Box) { 15 | task::spawn(async move { 16 | let dur = deadline - timer_now(); 17 | task::sleep(dur).await; 18 | callback(timer_now()); 19 | }); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /kernel-hal/src/libos/vdso.rs: -------------------------------------------------------------------------------- 1 | //! VDSO constants. 2 | 3 | hal_fn_impl! { 4 | impl mod crate::hal_fn::vdso { 5 | fn vdso_constants() -> VdsoConstants { 6 | let mut constants = vdso_constants_template(); 7 | constants.physmem = super::mem::PMEM_SIZE as u64; 8 | constants 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /kernel-hal/src/utils/init_once.rs: -------------------------------------------------------------------------------- 1 | use spin::Once; 2 | 3 | pub struct InitOnce { 4 | inner: Once, 5 | default: Option, 6 | } 7 | 8 | impl InitOnce { 9 | #[cfg(any(doc, not(feature = "libos"), feature = "graphic"))] 10 | pub const fn new() -> Self { 11 | Self { 12 | inner: Once::new(), 13 | default: None, 14 | } 15 | } 16 | 17 | #[cfg(any(doc, not(target_arch = "x86_64"), feature = "libos"))] 18 | pub const fn new_with_default(value: T) -> Self { 19 | Self { 20 | inner: Once::new(), 21 | default: Some(value), 22 | } 23 | } 24 | 25 | pub fn init_once_by(&self, value: T) { 26 | self.inner.call_once(|| value); 27 | } 28 | 29 | #[cfg(any(doc, target_arch = "riscv64"))] 30 | pub fn init_once(&self, f: F) 31 | where 32 | F: FnOnce() -> T, 33 | { 34 | self.inner.call_once(f); 35 | } 36 | 37 | pub fn default(&self) -> Option<&T> { 38 | self.default.as_ref() 39 | } 40 | 41 | #[cfg(any(doc, feature = "graphic"))] 42 | pub fn try_get(&self) -> Option<&T> { 43 | self.inner.get() 44 | } 45 | } 46 | 47 | impl core::ops::Deref for InitOnce { 48 | type Target = T; 49 | fn deref(&self) -> &Self::Target { 50 | self.inner 51 | .get() 52 | .or_else(|| self.default()) 53 | .unwrap_or_else(|| panic!("uninitialized InitOnce<{}>", core::any::type_name::())) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /kernel-hal/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(feature = "libos"))] 2 | use core::cell::UnsafeCell; 3 | 4 | cfg_if! { 5 | if #[cfg(not(feature = "libos"))] { 6 | pub(crate) mod page_table; 7 | } 8 | } 9 | 10 | pub(crate) mod init_once; 11 | 12 | pub mod lazy_init; 13 | pub mod mpsc_queue; 14 | 15 | #[cfg(not(feature = "libos"))] 16 | pub struct PerCpuCell(pub UnsafeCell); 17 | 18 | #[cfg(not(feature = "libos"))] 19 | // #Safety: Only the corresponding cpu will access it. 20 | unsafe impl Sync for PerCpuCell {} 21 | 22 | #[cfg(not(feature = "libos"))] 23 | impl PerCpuCell { 24 | pub const fn new(t: T) -> Self { 25 | Self(UnsafeCell::new(t)) 26 | } 27 | 28 | pub fn get(&self) -> &T { 29 | unsafe { &*self.0.get() } 30 | } 31 | 32 | #[allow(clippy::mut_from_ref)] 33 | pub fn get_mut(&self) -> &mut T { 34 | unsafe { &mut *self.0.get() } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /linux-object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linux-object" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Linux kernel objects" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [features] 11 | mock-disk = [] 12 | 13 | [dependencies] 14 | async-trait = "0.1" 15 | log = "0.4" 16 | xmas-elf = "0.7" 17 | bitflags = "1.3" 18 | hashbrown = "0.9" 19 | numeric-enum-macro = "0.2" 20 | zircon-object = { path = "../zircon-object", features = ["elf"] } 21 | kernel-hal = { path = "../kernel-hal", default-features = false } 22 | downcast-rs = { version = "1.2", default-features = false } 23 | lazy_static = { version = "1.4", features = ["spin_no_std"] } 24 | rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 25 | rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 26 | rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 27 | rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 28 | rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 29 | cfg-if = "1.0" 30 | zcore-drivers = { path = "../drivers", features = ["virtio"] } 31 | lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "8486b8" } 32 | smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = [ 33 | "log", 34 | "alloc", 35 | "verbose", 36 | "proto-ipv4", 37 | "proto-ipv6", 38 | "proto-igmp", 39 | "medium-ip", 40 | "medium-ethernet", 41 | "socket-raw", 42 | "socket-udp", 43 | "socket-tcp", 44 | "socket-icmp", 45 | "async", 46 | ] } 47 | -------------------------------------------------------------------------------- /linux-object/src/fs/devfs/input/mod.rs: -------------------------------------------------------------------------------- 1 | mod event; 2 | mod mice; 3 | 4 | pub use self::event::EventDev; 5 | pub use self::mice::MiceDev; 6 | -------------------------------------------------------------------------------- /linux-object/src/fs/devfs/mod.rs: -------------------------------------------------------------------------------- 1 | mod fbdev; 2 | mod input; 3 | mod random; 4 | mod uartdev; 5 | 6 | pub use fbdev::FbDev; 7 | pub use input::{EventDev, MiceDev}; 8 | pub use random::RandomINode; 9 | pub use uartdev::UartDev; 10 | -------------------------------------------------------------------------------- /linux-object/src/fs/devfs/random.rs: -------------------------------------------------------------------------------- 1 | //! Implement INode for RandomINode 2 | 3 | use alloc::sync::Arc; 4 | use core::any::Any; 5 | 6 | use lock::Mutex; 7 | use rcore_fs::vfs::*; 8 | use rcore_fs_devfs::DevFS; 9 | 10 | /// random INode data struct 11 | pub struct RandomINodeData { 12 | seed: u32, 13 | } 14 | 15 | /// random INode struct 16 | #[derive(Clone)] 17 | pub struct RandomINode { 18 | secure: bool, 19 | inode_id: usize, 20 | data: Arc>, 21 | } 22 | 23 | impl RandomINode { 24 | /// create a random INode 25 | /// - urandom -> secure = true 26 | /// - random -> secure = false 27 | pub fn new(secure: bool) -> RandomINode { 28 | RandomINode { 29 | secure, 30 | inode_id: DevFS::new_inode_id(), 31 | data: Arc::new(Mutex::new(RandomINodeData { seed: 1 })), 32 | } 33 | } 34 | } 35 | 36 | impl INode for RandomINode { 37 | fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { 38 | if self.secure { 39 | kernel_hal::rand::fill_random(buf) 40 | } else { 41 | let mut data = self.data.lock(); 42 | // from K&R 43 | for x in buf.iter_mut() { 44 | data.seed = data.seed.wrapping_mul(1_103_515_245).wrapping_add(12345); 45 | *x = (data.seed / 65536) as u8; 46 | } 47 | } 48 | Ok(buf.len()) 49 | } 50 | 51 | fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { 52 | Err(FsError::NotSupported) 53 | } 54 | 55 | fn poll(&self) -> Result { 56 | Ok(PollStatus { 57 | read: true, 58 | write: false, 59 | error: false, 60 | }) 61 | } 62 | 63 | fn metadata(&self) -> Result { 64 | Ok(Metadata { 65 | dev: 1, 66 | inode: self.inode_id, 67 | size: 0, 68 | blk_size: 0, 69 | blocks: 0, 70 | atime: Timespec { sec: 0, nsec: 0 }, 71 | mtime: Timespec { sec: 0, nsec: 0 }, 72 | ctime: Timespec { sec: 0, nsec: 0 }, 73 | type_: FileType::CharDevice, 74 | mode: 0o666, 75 | nlinks: 1, 76 | uid: 0, 77 | gid: 0, 78 | rdev: make_rdev(1, if self.secure { 9 } else { 8 }), 79 | }) 80 | } 81 | 82 | fn as_any_ref(&self) -> &dyn Any { 83 | self 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /linux-object/src/fs/ioctl.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | // for IOR and IOW: 4 | // 32bits total, command in lower 16bits, size of the parameter structure in the lower 14 bits of the upper 16 bits 5 | // higher 2 bits: 01 = write, 10 = read 6 | 7 | #[cfg(not(target_arch = "mips"))] 8 | pub const TCGETS: usize = 0x5401; 9 | #[cfg(target_arch = "mips")] 10 | pub const TCGETS: usize = 0x540D; 11 | 12 | #[cfg(not(target_arch = "mips"))] 13 | pub const TIOCGPGRP: usize = 0x540F; 14 | // _IOR('t', 119, int) 15 | #[cfg(target_arch = "mips")] 16 | pub const TIOCGPGRP: usize = 0x4_004_74_77; 17 | 18 | #[cfg(not(target_arch = "mips"))] 19 | pub const TIOCSPGRP: usize = 0x5410; 20 | // _IOW('t', 118, int) 21 | #[cfg(target_arch = "mips")] 22 | pub const TIOCSPGRP: usize = 0x8_004_74_76; 23 | 24 | #[cfg(not(target_arch = "mips"))] 25 | pub const TIOCGWINSZ: usize = 0x5413; 26 | // _IOR('t', 104, struct winsize) 27 | #[cfg(target_arch = "mips")] 28 | pub const TIOCGWINSZ: usize = 0x4_008_74_68; 29 | 30 | #[cfg(not(target_arch = "mips"))] 31 | pub const FIONCLEX: usize = 0x5450; 32 | #[cfg(target_arch = "mips")] 33 | pub const FIONCLEX: usize = 0x6602; 34 | 35 | #[cfg(not(target_arch = "mips"))] 36 | pub const FIOCLEX: usize = 0x5451; 37 | #[cfg(target_arch = "mips")] 38 | pub const FIOCLEX: usize = 0x6601; 39 | 40 | // rustc using pipe and ioctl pipe file with this request id 41 | // for non-blocking/blocking IO control setting 42 | pub const FIONBIO: usize = 0x5421; 43 | -------------------------------------------------------------------------------- /linux-object/src/fs/pseudo.rs: -------------------------------------------------------------------------------- 1 | //! Pseudo file system INode 2 | 3 | use alloc::vec::Vec; 4 | use core::any::Any; 5 | 6 | use rcore_fs::vfs::*; 7 | 8 | /// Pseudo INode struct 9 | pub struct Pseudo { 10 | content: Vec, 11 | type_: FileType, 12 | } 13 | 14 | impl Pseudo { 15 | /// create a Pseudo INode 16 | pub fn new(s: &str, type_: FileType) -> Self { 17 | Pseudo { 18 | content: Vec::from(s.as_bytes()), 19 | type_, 20 | } 21 | } 22 | } 23 | 24 | impl INode for Pseudo { 25 | fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { 26 | if offset >= self.content.len() { 27 | return Ok(0); 28 | } 29 | let len = (self.content.len() - offset).min(buf.len()); 30 | buf[..len].copy_from_slice(&self.content[offset..offset + len]); 31 | Ok(len) 32 | } 33 | fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { 34 | Err(FsError::NotSupported) 35 | } 36 | fn poll(&self) -> Result { 37 | Ok(PollStatus { 38 | read: true, 39 | write: false, 40 | error: false, 41 | }) 42 | } 43 | fn metadata(&self) -> Result { 44 | Ok(Metadata { 45 | dev: 0, 46 | inode: 0, 47 | size: self.content.len(), 48 | blk_size: 0, 49 | blocks: 0, 50 | atime: Timespec { sec: 0, nsec: 0 }, 51 | mtime: Timespec { sec: 0, nsec: 0 }, 52 | ctime: Timespec { sec: 0, nsec: 0 }, 53 | type_: self.type_, 54 | mode: 0, 55 | nlinks: 0, 56 | uid: 0, 57 | gid: 0, 58 | rdev: 0, 59 | }) 60 | } 61 | fn as_any_ref(&self) -> &dyn Any { 62 | self 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /linux-object/src/fs/rcore_fs_wrapper.rs: -------------------------------------------------------------------------------- 1 | //! Device wrappers that implement `rcore_fs::dev::Device`, which can loaded 2 | //! file systems on (e.g. `rcore_fs_sfs::SimpleFileSystem::open()`). 3 | 4 | use alloc::sync::Arc; 5 | 6 | extern crate rcore_fs; 7 | 8 | use kernel_hal::drivers::scheme::BlockScheme; 9 | use lock::RwLock; 10 | use rcore_fs::dev::{BlockDevice, DevError, Device, Result}; 11 | 12 | /// A naive LRU cache layer for `BlockDevice`, re-exported from `rcore-fs`. 13 | pub use rcore_fs::dev::block_cache::BlockCache; 14 | 15 | /// Memory buffer for device. 16 | pub struct MemBuf(RwLock<&'static mut [u8]>); 17 | 18 | impl MemBuf { 19 | /// create a [`MemBuf`] struct. 20 | pub fn new(buf: &'static mut [u8]) -> Self { 21 | MemBuf(RwLock::new(buf)) 22 | } 23 | } 24 | 25 | impl Device for MemBuf { 26 | fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { 27 | let slice = self.0.read(); 28 | let len = buf.len().min(slice.len() - offset); 29 | buf[..len].copy_from_slice(&slice[offset..offset + len]); 30 | Ok(len) 31 | } 32 | fn write_at(&self, offset: usize, buf: &[u8]) -> Result { 33 | let mut slice = self.0.write(); 34 | let len = buf.len().min(slice.len() - offset); 35 | slice[offset..offset + len].copy_from_slice(&buf[..len]); 36 | Ok(len) 37 | } 38 | fn sync(&self) -> Result<()> { 39 | Ok(()) 40 | } 41 | } 42 | 43 | /// Block device implements [`BlockScheme`]. 44 | pub struct Block(Arc); 45 | 46 | impl Block { 47 | /// create a [`Block`] struct. 48 | pub fn new(block: Arc) -> Self { 49 | Self(block) 50 | } 51 | } 52 | 53 | impl BlockDevice for Block { 54 | const BLOCK_SIZE_LOG2: u8 = 9; // 512 55 | 56 | fn read_at(&self, block_id: usize, buf: &mut [u8]) -> Result<()> { 57 | self.0.read_block(block_id, buf).map_err(|_| DevError) 58 | } 59 | 60 | fn write_at(&self, block_id: usize, buf: &[u8]) -> Result<()> { 61 | self.0.write_block(block_id, buf).map_err(|_| DevError) 62 | } 63 | 64 | fn sync(&self) -> Result<()> { 65 | self.0.flush().map_err(|_| DevError) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /linux-object/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Linux kernel objects 2 | 3 | #![no_std] 4 | #![deny(warnings)] 5 | // #![deny(missing_docs)] 形同虚设了 6 | #![allow(clippy::upper_case_acronyms)] 7 | #![allow(clippy::uninit_vec)] 8 | #![feature(map_first_last)] 9 | #![feature(core_intrinsics)] 10 | 11 | #[macro_use] 12 | extern crate alloc; 13 | 14 | #[macro_use] 15 | extern crate log; 16 | 17 | // layer 0 18 | pub mod error; 19 | 20 | // layer 1 21 | pub mod fs; 22 | 23 | // layer 2 24 | pub mod ipc; 25 | pub mod loader; 26 | pub mod net; 27 | pub mod process; 28 | pub mod signal; 29 | pub mod sync; 30 | pub mod thread; 31 | pub mod time; 32 | -------------------------------------------------------------------------------- /linux-object/src/sync/mod.rs: -------------------------------------------------------------------------------- 1 | //! Useful synchronization primitives. 2 | #![deny(missing_docs)] 3 | 4 | pub use self::event_bus::*; 5 | pub use self::semaphore::*; 6 | 7 | mod event_bus; 8 | mod semaphore; 9 | -------------------------------------------------------------------------------- /linux-syscall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linux-syscall" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Linux syscalls implementation" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | bitflags = "1.3" 13 | numeric-enum-macro = "0.2" 14 | static_assertions = "1.1.0" 15 | zircon-object = { path = "../zircon-object" } 16 | linux-object = { path = "../linux-object" } 17 | kernel-hal = { path = "../kernel-hal", default-features = false } 18 | rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 19 | lazy_static = { version = "1.4", features = ["spin_no_std"] } 20 | bitvec = { version = "0.22", default-features = false, features = ["alloc"] } 21 | lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "8486b8" } 22 | futures = { version = "0.3", default-features = false, features = [ 23 | "alloc", 24 | "async-await", 25 | ] } 26 | 27 | [dev-dependencies] 28 | async-std = { version = "1.10", features = ["unstable"] } 29 | -------------------------------------------------------------------------------- /linux-syscall/build.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | fn main() { 4 | let syscall_in = match std::env::var("CARGO_CFG_TARGET_ARCH") { 5 | Ok(s) if s == "riscv64" => "src/riscv64_syscall.h.in", 6 | Ok(s) if s == "aarch64" => "src/aarch64_syscall.h.in", 7 | _ => "src/syscall.h.in", 8 | }; 9 | println!("cargo:rerun-if-changed={}", syscall_in); 10 | 11 | let mut fout = std::fs::File::create(std::env::var("OUT_DIR").unwrap() + "/consts.rs").unwrap(); 12 | writeln!(fout, "// Generated by build.rs. DO NOT EDIT.").unwrap(); 13 | writeln!(fout, "use numeric_enum_macro::numeric_enum;\n").unwrap(); 14 | writeln!(fout, "numeric_enum! {{").unwrap(); 15 | writeln!(fout, "#[repr(u32)]").unwrap(); 16 | writeln!(fout, "#[derive(Debug, Eq, PartialEq)]").unwrap(); 17 | writeln!(fout, "#[allow(non_camel_case_types)]").unwrap(); 18 | writeln!(fout, "pub enum SyscallType {{").unwrap(); 19 | 20 | let data = std::fs::read_to_string(syscall_in).unwrap(); 21 | 22 | for line in data.lines() { 23 | if !line.starts_with("#define") { 24 | continue; 25 | } 26 | let mut iter = line.split_whitespace(); 27 | let _ = iter.next().unwrap(); 28 | let name = iter.next().unwrap(); 29 | let id = iter.next().unwrap(); 30 | 31 | let name = &name[5..].to_uppercase(); 32 | writeln!(fout, " {} = {},", name, id).unwrap(); 33 | } 34 | writeln!(fout, "}}").unwrap(); 35 | writeln!(fout, "}}").unwrap(); 36 | } 37 | -------------------------------------------------------------------------------- /linux-syscall/src/file/mod.rs: -------------------------------------------------------------------------------- 1 | //! Syscalls for files 2 | #![deny(missing_docs)] 3 | use super::*; 4 | use bitflags::bitflags; 5 | use linux_object::fs::vfs::{FileType, FsError}; 6 | use linux_object::fs::*; 7 | 8 | mod dir; 9 | mod fd; 10 | #[allow(clippy::module_inception)] 11 | mod file; 12 | mod poll; 13 | mod stat; 14 | 15 | use self::dir::AtFlags; 16 | -------------------------------------------------------------------------------- /linux-syscall/test/testpipe1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() 11 | { 12 | pid_t pid; 13 | int cnt = 0; 14 | int pipefd[2]; 15 | char buf; 16 | char received[20]; 17 | int receivep = 0; 18 | char w[12]; 19 | char r[12]; 20 | 21 | if (pipe(pipefd) == -1) 22 | { 23 | printf("pipe"); 24 | exit(-1); 25 | } 26 | write(pipefd[1], "test", strlen("test")); 27 | close(pipefd[1]); 28 | while (read(pipefd[0], &buf, 1) > 0) 29 | received[receivep++] = buf; 30 | received[receivep] = 0; 31 | receivep = 0; 32 | assert(strcmp(received, "test") == 0); 33 | close(pipefd[0]); 34 | 35 | if (pipe(pipefd) == -1) 36 | { 37 | printf("pipe"); 38 | exit(-1); 39 | } 40 | sprintf(w, "%d", pipefd[1]); 41 | sprintf(r, "%d", pipefd[0]); 42 | pid = vfork(); 43 | if (pid < 0) 44 | printf("error in fork!\n"); 45 | else if (pid == 0) 46 | { 47 | execl("/bin/testpipe2", "/bin/testpipe2", r, w, NULL); 48 | exit(0); 49 | } 50 | else if (pid > 0) 51 | { 52 | close(pipefd[1]); 53 | while (read(pipefd[0], &buf, 1) > 0) 54 | received[receivep++] = buf; 55 | received[receivep] = 0; 56 | assert(strcmp(received, "hello pipe") == 0); 57 | close(pipefd[0]); 58 | } 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /linux-syscall/test/testpipe2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | int writefd, readfd; 10 | sscanf(argv[2], "%d", &writefd); 11 | sscanf(argv[1], "%d", &readfd); 12 | close(readfd); 13 | write(writefd, "hello pipe", strlen("hello pipe")); 14 | close(writefd); 15 | exit(0); 16 | } 17 | -------------------------------------------------------------------------------- /linux-syscall/test/testpoll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char **argv) 11 | { 12 | int i; 13 | int ret; 14 | int fd; 15 | unsigned char keys_val; 16 | struct pollfd fds[2]; 17 | int pipefd[2]; 18 | struct timespec ts; 19 | 20 | // test poll using pipe 21 | if (pipe(pipefd) == -1) 22 | { 23 | printf("pipe"); 24 | exit(-1); 25 | } 26 | 27 | // test time out 28 | fds[0].fd = 0; 29 | fds[0].events = POLLIN; 30 | ret = poll(fds, 1, 1000); 31 | assert(ret == 0); 32 | 33 | fds[0].fd = pipefd[0]; 34 | fds[0].events = POLLIN; 35 | fds[1].fd = pipefd[1]; 36 | fds[1].events = POLLOUT; 37 | 38 | ret = poll(fds, 2, 5000); 39 | assert(ret == 1); 40 | assert(fds[1].revents == POLLOUT); 41 | 42 | write(pipefd[1], "test", strlen("test")); 43 | 44 | ts.tv_sec = 5; 45 | ts.tv_nsec = 0; 46 | 47 | ret = ppoll(fds, 2, &ts, NULL); 48 | assert(ret == 2); 49 | assert(fds[0].revents == POLLIN); 50 | 51 | close(pipefd[0]); 52 | close(pipefd[1]); 53 | return 0; 54 | } -------------------------------------------------------------------------------- /linux-syscall/test/testrandom.c: -------------------------------------------------------------------------------- 1 | #ifdef HAVE_GETRANDOM 2 | #include 3 | #else 4 | #include 5 | #include 6 | #endif 7 | #include 8 | 9 | int main(){ 10 | int buf; 11 | #ifdef HAVE_GETRANDOM 12 | getrandom((void *)&buf,sizeof(buf),GRND_RANDOM); 13 | #else 14 | syscall(SYS_getrandom, (void *)&buf, sizeof(buf), GRND_RANDOM); 15 | #endif 16 | printf("random: %d\n",buf); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /linux-syscall/test/testselect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(void) 11 | { 12 | fd_set rfds, wfds; 13 | struct timeval tv; 14 | struct timespec ts; 15 | int retval; 16 | 17 | int pipefd[2]; 18 | 19 | // test time out 1s 20 | FD_ZERO(&rfds); 21 | FD_SET(0, &rfds); 22 | tv.tv_sec = 1; 23 | tv.tv_usec = 0; 24 | assert(select(1, &rfds, NULL, NULL, &tv) == 0); 25 | assert(!FD_ISSET(0, &rfds)); 26 | 27 | FD_ZERO(&wfds); 28 | FD_SET(1, &wfds); 29 | ts.tv_sec = 5; 30 | ts.tv_nsec = 0; 31 | assert(pselect(2, NULL, &wfds, NULL, &ts, NULL) == 1); 32 | assert(FD_ISSET(1, &wfds)); 33 | 34 | if (pipe(pipefd) == -1) 35 | { 36 | exit(-1); 37 | } 38 | write(pipefd[1], "test", strlen("test")); 39 | 40 | FD_ZERO(&rfds); 41 | FD_SET(pipefd[0], &rfds); 42 | FD_ZERO(&wfds); 43 | FD_SET(pipefd[1], &wfds); 44 | tv.tv_sec = 0; 45 | tv.tv_usec = 0; 46 | retval = select(pipefd[0] + 1, &rfds, &wfds, NULL, &tv); 47 | assert(FD_ISSET(pipefd[0], &rfds)); 48 | assert(FD_ISSET(pipefd[1], &wfds)); 49 | 50 | assert(retval == 2); 51 | 52 | close(pipefd[0]); 53 | close(pipefd[1]); 54 | exit(EXIT_SUCCESS); 55 | } 56 | -------------------------------------------------------------------------------- /linux-syscall/test/testsem1.c: -------------------------------------------------------------------------------- 1 | #ifndef _XOPEN_SOURCE 2 | #define _XOPEN_SOURCE 700 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | static const char path[] = "."; 18 | static const int id = 's'; 19 | 20 | #define T(f) assert((f) != -1) 21 | 22 | static void inc() 23 | { 24 | time_t t; 25 | key_t k; 26 | int semid, semval, sempid, semncnt, semzcnt; 27 | struct semid_ds semid_ds; 28 | union semun { 29 | int val; 30 | struct semid_ds *buf; 31 | unsigned short *array; 32 | } arg; 33 | struct sembuf sops; 34 | 35 | T(t = time(0)); 36 | T(k = ftok(path, id)); 37 | 38 | /* make sure we get a clean semaphore id */ 39 | T(semid = semget(k, 1, IPC_CREAT | 0666)); 40 | T(semctl(semid, 0, IPC_RMID)); 41 | T(semid = semget(k, 1, IPC_CREAT | IPC_EXCL | 0666)); 42 | 43 | /* check IPC_EXCL */ 44 | errno = 0; 45 | if (semget(k, 1, IPC_CREAT | IPC_EXCL | 0666) != -1 || errno != EEXIST) 46 | printf("semget(IPC_CREAT|IPC_EXCL) should have failed with EEXIST, got %s\n", strerror(errno)); 47 | 48 | /* check if msgget initilaized the msqid_ds structure correctly */ 49 | arg.buf = &semid_ds; 50 | T(semctl(semid, 0, IPC_STAT, arg)); 51 | if (semid_ds.sem_ctime < t) 52 | printf("semid_ds.sem_ctime >= t failed: got %lld, want >= %lld\n", (long long)semid_ds.sem_ctime, (long long)t); 53 | if (semid_ds.sem_ctime > t + 5) 54 | printf("semid_ds.sem_ctime <= t+5 failed: got %lld, want <= %lld\n", (long long)semid_ds.sem_ctime, (long long)t + 5); 55 | 56 | /* test sem_op > 0 */ 57 | sops.sem_num = 0; 58 | sops.sem_op = 1; 59 | sops.sem_flg = 0; 60 | T(semval = semctl(semid, 0, GETVAL)); 61 | assert(semval == 0); 62 | T(semop(semid, &sops, 1)); 63 | T(semval = semctl(semid, 0, GETVAL)); 64 | assert(semval == 1); 65 | T(sempid = semctl(semid, 0, GETPID)); 66 | assert(sempid == getpid()); 67 | T(semncnt = semctl(semid, 0, GETNCNT)); 68 | assert(semncnt == 0); 69 | T(semzcnt = semctl(semid, 0, GETZCNT)); 70 | assert(semzcnt == 0); 71 | } 72 | 73 | int main(void) 74 | { 75 | int p; 76 | int status; 77 | inc(); 78 | int pid = vfork(); 79 | if (pid < 0) 80 | printf("error in fork!\n"); 81 | else if (pid == 0) 82 | { 83 | execl("/bin/testsem2", "/bin/testsem2", NULL); 84 | exit(0); 85 | } 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /linux-syscall/test/testsem2.c: -------------------------------------------------------------------------------- 1 | #ifndef _XOPEN_SOURCE 2 | #define _XOPEN_SOURCE 700 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | static const char path[] = "."; 16 | static const int id = 's'; 17 | 18 | #define T(f) assert((f) != -1) 19 | 20 | static void dec() 21 | { 22 | key_t k; 23 | int semid, semval; 24 | struct sembuf sops; 25 | 26 | T(k = ftok(path, id)); 27 | T(semid = semget(k, 0, 0)); 28 | 29 | /* test sem_op < 0 */ 30 | sops.sem_num = 0; 31 | sops.sem_op = -1; 32 | sops.sem_flg = 0; 33 | T(semop(semid, &sops, 1)); 34 | T(semval = semctl(semid, 0, GETVAL)); 35 | assert(semval == 0); 36 | 37 | /* cleanup */ 38 | T(semctl(semid, 0, IPC_RMID)); 39 | } 40 | 41 | int main(void) 42 | { 43 | int p; 44 | int status; 45 | 46 | dec(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /linux-syscall/test/testshm1.c: -------------------------------------------------------------------------------- 1 | #ifndef _XOPEN_SOURCE 2 | #define _XOPEN_SOURCE 700 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static const char path[] = "."; 15 | static const int id = 'h'; 16 | 17 | #define T(f) assert((f)+1 != 0) 18 | #define EQ(a,b) assert((a) == (b)) 19 | 20 | static void set() 21 | { 22 | time_t t; 23 | key_t k; 24 | int shmid; 25 | struct shmid_ds shmid_ds; 26 | void *p; 27 | 28 | T(t = time(0)); 29 | T(k = ftok(path, id)); 30 | 31 | /* make sure we get a clean shared memory id */ 32 | T(shmid = shmget(k, 100, IPC_CREAT|0666)); 33 | T(shmctl(shmid, IPC_RMID, 0)); 34 | T(shmid = shmget(k, 100, IPC_CREAT|IPC_EXCL|0666)); 35 | 36 | /* check IPC_EXCL */ 37 | errno = 0; 38 | if (shmget(k, 100, IPC_CREAT|IPC_EXCL|0666) != -1 || errno != EEXIST) 39 | printf("shmget(IPC_CREAT|IPC_EXCL) should have failed with EEXIST, got %s\n", strerror(errno)); 40 | 41 | /* check if shmget initilaized the msshmid_ds structure correctly */ 42 | 43 | T(shmctl(shmid, IPC_STAT, &shmid_ds)); 44 | EQ(shmid_ds.shm_perm.mode & 0x1ff, 0666); 45 | EQ(shmid_ds.shm_segsz, 100); 46 | EQ(shmid_ds.shm_lpid, 0); 47 | EQ(shmid_ds.shm_cpid, getpid()); 48 | EQ((int)shmid_ds.shm_nattch, 0); 49 | EQ((long long)shmid_ds.shm_atime, 0); 50 | EQ((long long)shmid_ds.shm_dtime, 0); 51 | if (shmid_ds.shm_ctime < t) 52 | printf("shmid_ds.shm_ctime >= t failed: got %lld, want >= %lld\n", (long long)shmid_ds.shm_ctime, (long long)t); 53 | if (shmid_ds.shm_ctime > t+5) 54 | printf("shmid_ds.shm_ctime <= t+5 failed: got %lld, want <= %lld\n", (long long)shmid_ds.shm_ctime, (long long)t+5); 55 | 56 | /* test attach */ 57 | if ((p=shmat(shmid, 0, 0)) == 0) 58 | printf("shmat failed: %s\n", strerror(errno)); 59 | 60 | T(shmctl(shmid, IPC_STAT, &shmid_ds)); 61 | EQ((int)shmid_ds.shm_nattch, 1); 62 | EQ(shmid_ds.shm_lpid, getpid()); 63 | if (shmid_ds.shm_atime < t) 64 | printf("shm_atime is %lld want >= %lld\n", (long long)shmid_ds.shm_atime, (long long)t); 65 | if (shmid_ds.shm_atime > t+5) 66 | printf("shm_atime is %lld want <= %lld\n", (long long)shmid_ds.shm_atime, (long long)t+5); 67 | 68 | strcpy((char *)p, "test data"); 69 | T(shmdt(p)); 70 | } 71 | 72 | int main(void) 73 | { 74 | int p; 75 | int status; 76 | set(); 77 | int pid = vfork(); 78 | if (pid < 0) 79 | printf("error in fork!\n"); 80 | else if (pid == 0) 81 | { 82 | execl("/bin/testshm2", "/bin/testshm2", NULL); 83 | exit(0); 84 | } 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /linux-syscall/test/testshm2.c: -------------------------------------------------------------------------------- 1 | #ifndef _XOPEN_SOURCE 2 | #define _XOPEN_SOURCE 700 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | static const char path[] = "."; 16 | static const int id = 'h'; 17 | 18 | #define T(f) assert((f)+1 != 0) 19 | #define EQ(a,b) assert((a) == (b)) 20 | 21 | static void get() 22 | { 23 | key_t k; 24 | int shmid; 25 | void *p; 26 | 27 | T(k = ftok(path, id)); 28 | T(shmid = shmget(k, 0, 0)); 29 | 30 | errno = 0; 31 | if ((p=shmat(shmid, 0, SHM_RDONLY)) == 0) 32 | printf("shmat failed: %s\n", strerror(errno)); 33 | 34 | if (strcmp((char *)p, "test data") != 0) 35 | printf("reading shared mem failed: got \"%.100s\" want \"test data\"\n", (char *)p); 36 | 37 | /* cleanup */ 38 | T(shmdt(p)); 39 | T(shmctl(shmid, IPC_RMID, 0)); 40 | } 41 | 42 | int main(void) 43 | { 44 | int p; 45 | int status; 46 | 47 | get(); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /linux-syscall/test/testtime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char **argv) 11 | { 12 | struct timespec ts = {0, 0}; 13 | clock_gettime(CLOCK_REALTIME, &ts); 14 | printf("timespec: %ld sec, %ld nsec\n", ts.tv_sec, ts.tv_nsec); 15 | assert(ts.tv_sec != 0 && ts.tv_nsec != 0); 16 | 17 | struct timeval tv; 18 | 19 | // the musl-libc call clock_gettime instead..qwq 20 | gettimeofday(&tv, NULL); 21 | printf("timeval: %ld sec, %ld usec\n", tv.tv_sec, tv.tv_usec); 22 | assert(tv.tv_sec != 0 && tv.tv_usec != 0); 23 | 24 | // the musl-libc call clock_gettime instead..qwq 25 | time_t seconds; 26 | seconds = time(NULL); 27 | printf("time: %ld\n", seconds); 28 | assert(seconds != 0); 29 | 30 | struct tms tmp; 31 | clock_t t = times(&tmp); 32 | printf("times return: %ld\n", t); 33 | assert(times != 0); 34 | 35 | struct rusage usage; 36 | getrusage(0, &usage); 37 | printf("timeval getrusage user: %ld sec, %ld usec\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec); 38 | printf("timeval getrusage system: %ld sec, %ld usec\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec); 39 | assert(usage.ru_utime.tv_sec != 0 && usage.ru_utime.tv_usec != 0); 40 | 41 | return 0; 42 | } -------------------------------------------------------------------------------- /loader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zcore-loader" 3 | version = "0.1.0" 4 | authors = [ 5 | "Runji Wang ", 6 | "Yuekai Jia ", 7 | ] 8 | edition = "2018" 9 | description = "Linux and Zircon user programs loader and runner." 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | log = "0.4" 15 | cfg-if = "1.0" 16 | xmas-elf = { version = "0.7", optional = true } 17 | kernel-hal = { path = "../kernel-hal", default-features = false } 18 | zircon-object = { path = "../zircon-object", features = ["elf"] } 19 | linux-object = { path = "../linux-object", optional = true } 20 | zircon-syscall = { path = "../zircon-syscall", optional = true } 21 | linux-syscall = { path = "../linux-syscall", optional = true } 22 | executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler", rev = "e8cd353" } 23 | 24 | [features] 25 | default = ["libos", "linux", "zircon"] 26 | linux = ["linux-object", "linux-syscall"] 27 | zircon = ["zircon-syscall", "xmas-elf"] 28 | libos = ["kernel-hal/libos", "zircon-object/aspace-separate"] 29 | 30 | [dev-dependencies] 31 | env_logger = "0.9" 32 | async-std = { version = "1.10", features = ["attributes"] } 33 | rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 34 | 35 | [[example]] 36 | name = "linux-libos" 37 | required-features = ["linux", "libos"] 38 | 39 | [[example]] 40 | name = "zircon-libos" 41 | required-features = ["zircon", "libos"] 42 | -------------------------------------------------------------------------------- /loader/examples/linux-libos.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::Path; 3 | 4 | #[async_std::main] 5 | async fn main() { 6 | env_logger::init(); 7 | kernel_hal::init(); 8 | 9 | let args = std::env::args().collect::>(); 10 | if args.len() < 2 { 11 | println!("Usage: {} PROGRAM", args[0]); 12 | std::process::exit(-1); 13 | } 14 | 15 | let envs = vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin".into()]; 16 | let rootfs_path = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join("../rootfs/libos"); 17 | let hostfs = rcore_fs_hostfs::HostFS::new(rootfs_path); 18 | 19 | let proc = zcore_loader::linux::run(args[1..].to_vec(), envs, hostfs); 20 | let code = proc.wait_for_exit().await; 21 | std::process::exit(code as i32); 22 | } 23 | -------------------------------------------------------------------------------- /loader/examples/zircon-libos.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use zircon_object::object::{KernelObject, Signal}; 3 | 4 | #[async_std::main] 5 | async fn main() { 6 | env_logger::init(); 7 | kernel_hal::init(); 8 | 9 | let args = std::env::args().collect::>(); 10 | if args.len() < 2 { 11 | println!("Usage: {} ZBI_FILE [CMDLINE]", args[0]); 12 | std::process::exit(-1); 13 | } 14 | 15 | let zbi = std::fs::read(&args[1]).expect("failed to read zbi file"); 16 | let cmdline = args.get(2).map(String::as_str).unwrap_or_default(); 17 | 18 | let proc: Arc = zcore_loader::zircon::run_userboot(zbi, cmdline); 19 | proc.wait_signal(Signal::USER_SIGNAL_0).await; 20 | } 21 | -------------------------------------------------------------------------------- /loader/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Linux and Zircon user programs loader and runner. 2 | 3 | #![no_std] 4 | #![deny(warnings, missing_docs)] 5 | #![feature(doc_cfg)] 6 | 7 | extern crate alloc; 8 | #[macro_use] 9 | extern crate log; 10 | #[macro_use] 11 | extern crate cfg_if; 12 | 13 | cfg_if! { 14 | if #[cfg(any(feature = "linux", doc))] { 15 | #[doc(cfg(feature = "linux"))] 16 | pub mod linux; 17 | } 18 | } 19 | 20 | cfg_if! { 21 | if #[cfg(any(feature = "zircon", doc))] { 22 | #[doc(cfg(feature = "zircon"))] 23 | pub mod zircon; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /loader/tests/zircon.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_arch = "x86_64")] 2 | #[async_std::test] 3 | async fn userboot() { 4 | kernel_hal::init(); 5 | let zbi = std::fs::read("../prebuilt/zircon/x64/bringup.zbi").expect("failed to read zbi file"); 6 | let proc = zcore_loader::zircon::run_userboot(zbi, ""); 7 | proc.wait_for_exit().await; 8 | } 9 | -------------------------------------------------------------------------------- /prebuilt/firmware/aarch64/Boot.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmdline": "LOG=warn:ROOTPROC=/bin/busybox?sh", 3 | "firmware_type": "QEMU", 4 | "uart_base": 150994944, 5 | "gic_base": 134217728, 6 | "offset": 18446462598732840960 7 | } 8 | -------------------------------------------------------------------------------- /prebuilt/firmware/aarch64/QEMU_EFI.fd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/prebuilt/firmware/aarch64/QEMU_EFI.fd -------------------------------------------------------------------------------- /prebuilt/firmware/aarch64/aarch64_uefi.efi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/prebuilt/firmware/aarch64/aarch64_uefi.efi -------------------------------------------------------------------------------- /prebuilt/firmware/riscv/c910_fw_dynamic.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/prebuilt/firmware/riscv/c910_fw_dynamic.bin -------------------------------------------------------------------------------- /prebuilt/firmware/riscv/d1_fw_payload.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/prebuilt/firmware/riscv/d1_fw_payload.elf -------------------------------------------------------------------------------- /prebuilt/firmware/riscv/fu740_fdt.its: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple U-Boot uImage source file containing a single kernel and FDT blob 3 | */ 4 | 5 | /dts-v1/; 6 | 7 | / { 8 | description = "Simple image with single zCore kernel and FDT blob for fu740"; 9 | #address-cells = <1>; 10 | 11 | images { 12 | kernel { 13 | description = "zCore kernel for fu740"; 14 | data = /incbin/("../../../zCore/zcore.bin.gz"); 15 | type = "kernel"; 16 | arch = "riscv"; 17 | os = "linux"; 18 | compression = "gzip"; 19 | load = <0x80200000>; 20 | entry = <0x80200000>; 21 | }; 22 | fdt-1 { 23 | description = "Flattened Device Tree blob"; 24 | data = /incbin/("./hifive-unmatched-a00.dtb"); 25 | type = "flat_dt"; 26 | arch = "riscv"; 27 | compression = "none"; 28 | }; 29 | }; 30 | 31 | configurations { 32 | default = "conf-1"; 33 | conf-1 { 34 | description = "Boot zCore kernel with FDT blob for fu740"; 35 | kernel = "kernel"; 36 | fdt = "fdt-1"; 37 | }; 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /prebuilt/firmware/riscv/hifive-unmatched-a00.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/prebuilt/firmware/riscv/hifive-unmatched-a00.dtb -------------------------------------------------------------------------------- /prebuilt/firmware/riscv/starfive.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore/43ff1c9d09f55010741c7f7d2c50284a9d4dca6b/prebuilt/firmware/riscv/starfive.dtb -------------------------------------------------------------------------------- /prebuilt/firmware/riscv/starfive_fdt.its: -------------------------------------------------------------------------------- 1 | /* 2 | * U-Boot uImage source file for "zCore-visionfive" 3 | */ 4 | 5 | /dts-v1/; 6 | 7 | / { 8 | description = "U-Boot uImage source file for zCore-visionfive"; 9 | #address-cells = <1>; 10 | 11 | images { 12 | kernel { 13 | description = "Linux kernel for zCore-visionfive"; 14 | data = /incbin/("../../../zcore.bin.gz"); 15 | type = "kernel"; 16 | arch = "riscv"; 17 | os = "linux"; 18 | compression = "gzip"; 19 | load = <0x80200000>; 20 | entry = <0x80200000>; 21 | }; 22 | fdt { 23 | description = "Flattened Device Tree blob for zCore-visionfive"; 24 | data = /incbin/("./starfive.dtb"); 25 | type = "flat_dt"; 26 | arch = "riscv"; 27 | compression = "none"; 28 | }; 29 | }; 30 | 31 | configurations { 32 | default = "conf"; 33 | conf { 34 | description = "Boot Linux kernel with FDT blob"; 35 | kernel = "kernel"; 36 | fdt = "fdt"; 37 | }; 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | profile = "minimal" 3 | channel = "nightly-2022-08-05" 4 | components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] 5 | -------------------------------------------------------------------------------- /scripts/gen-prebuilt.sh: -------------------------------------------------------------------------------- 1 | # Generate prebuilt/zircon from modified fuchsia source 2 | 3 | OUTDIR=zcore_prebuilt 4 | ARCH=${1:-x64} 5 | mkdir -p ${OUTDIR} 6 | 7 | # set build target 8 | ./scripts/fx set bringup.${ARCH} --with-base //garnet/packages/tests:zircon --with //src/tests/microbenchmarks --with //src/virtualization/tests:hypervisor_tests_pkg 9 | 10 | # apply zircon-libos.patch and build once 11 | patch -p1 < zircon-libos.patch 12 | ./scripts/fx build default.zircon 13 | patch -p1 -R < zircon-libos.patch 14 | cp out/default.zircon/userboot-${ARCH}-clang/obj/kernel/lib/userabi/userboot/userboot.so ${OUTDIR}/userboot-libos.so 15 | cp out/default.zircon/user.vdso-${ARCH}-clang.shlib/obj/system/ulib/zircon/libzircon.so.debug ${OUTDIR}/libzircon-libos.so 16 | 17 | # apply zcore.patch and build again 18 | patch -p1 < zcore.patch 19 | ./scripts/fx build 20 | patch -p1 -R < zcore.patch 21 | cp out/default.zircon/userboot-${ARCH}-clang/obj/kernel/lib/userabi/userboot/userboot.so ${OUTDIR} 22 | cp out/default.zircon/user.vdso-${ARCH}-clang.shlib/obj/system/ulib/zircon/libzircon.so.debug ${OUTDIR}/libzircon.so 23 | cp out/default/bringup.zbi ${OUTDIR} 24 | cp out/default/obj/zircon/system/utest/core/core-tests.zbi ${OUTDIR} 25 | 26 | # remove kernel and cmdline from zbi 27 | cd ${OUTDIR} 28 | ../out/default.zircon/tools/zbi -x bringup.zbi -D bootfs 29 | ../out/default.zircon/tools/zbi bootfs -o bringup.zbi 30 | rm -r bootfs 31 | cd .. 32 | 33 | # finished 34 | echo 'generate prebuilt at' ${OUTDIR} 35 | -------------------------------------------------------------------------------- /scripts/script.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash 3 | 4 | cd .. && make baremetal-test-rv64 ROOTPROC=/libc-test/regression/printf-1e9-oob.exe? 5 | -------------------------------------------------------------------------------- /tools/docker/README.md: -------------------------------------------------------------------------------- 1 | # zCore develop docker image 2 | 3 | Build docker image 4 | 5 | ``` 6 | git clone https://github.com/rcore-os/zCore --recursive 7 | cd tools/docker 8 | OS_TYPE=ubuntu 9 | OS_TAG=20.04 10 | IMAGE_TAG=latest 11 | ./build_docker_image.sh ${OS_TYPE} ${OS_TAG} ${IMAGE_TAG} 12 | ``` 13 | 14 | Start docker container 15 | 16 | ``` 17 | IMAGE_NAME=zcore:${OS_TYPE}-${OS_TAG}-${IMAGE_TAG} 18 | ./start_container.sh ${IMAGE_NAME} 19 | ``` 20 | -------------------------------------------------------------------------------- /tools/docker/build_docker_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | OS_TYPE=ubuntu 5 | if [ -n "$1" ] && [ "$1" != "${OS_TYPE}" ]; then 6 | OS_TYPE=$1 7 | fi 8 | DOCKER_FILE=zcore-${OS_TYPE}.dockerfile 9 | 10 | OS_TAG=20.04 11 | if [ -n "$2" ] && [ "$2" != "${OS_TAG}" ]; then 12 | OS_TAG=$2 13 | fi 14 | BASE_IMAGE=${OS_TYPE}:${OS_TAG} 15 | 16 | IMAGE_TAG=latest 17 | if [ -n "$3" ] && [ "$3" != "${IMAGE_TAG}" ]; then 18 | IMAGE_TAG=$3 19 | fi 20 | IMAGE_NAME=zcore:${OS_TYPE}-${OS_TAG}-${IMAGE_TAG} 21 | 22 | http_proxy="" 23 | https_proxy="${http_proxy}" 24 | no_proxy="localhost,127.0.0.1" 25 | DOCKER_BUILDKIT=0 26 | 27 | docker build \ 28 | -f ${DOCKER_FILE} \ 29 | -t ${IMAGE_NAME} \ 30 | --network=host \ 31 | --build-arg no_proxy=${no_proxy} \ 32 | --build-arg http_proxy=${http_proxy} \ 33 | --build-arg https_proxy=${https_proxy} \ 34 | --build-arg BASE_IMAGE=${BASE_IMAGE} \ 35 | ../.. 36 | -------------------------------------------------------------------------------- /tools/docker/start_container.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | if [ ! -n "$1" ] ; then 4 | image=zcore:ubuntu-20.04-latest 5 | else 6 | image=$1 7 | fi 8 | 9 | export http_proxy="" 10 | export http_proxy=${http_proxy} 11 | export no_proxy="localhost,127.0.0.1" 12 | 13 | docker run -itd \ 14 | --restart=unless-stopped \ 15 | --privileged=true \ 16 | --net=host \ 17 | --ipc=host \ 18 | -e http_proxy=${http_proxy} \ 19 | -e https_proxy=${https_proxy} \ 20 | -e no_proxy=${no_proxy} \ 21 | -v /home:/home/host-home:rw \ 22 | ${image} 23 | -------------------------------------------------------------------------------- /tools/docker/zcore-ubuntu.dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMAGE=ubuntu:20.04 2 | FROM ${BASE_IMAGE} 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | ENV INSTALL_PREFIX=/opt/zcore 6 | 7 | RUN apt-get update \ 8 | && apt-get install -y \ 9 | build-essential \ 10 | pkg-config \ 11 | python3 \ 12 | python3-pip \ 13 | meson \ 14 | libglib2.0-dev \ 15 | libpixman-1-dev \ 16 | xz-utils \ 17 | wget \ 18 | curl \ 19 | vim \ 20 | && apt-get clean all \ 21 | && rm -rf /var/lib/apt/lists/* \ 22 | && rm -rf ~/.cache/pip/* \ 23 | && rm -rf /tmp/* 24 | 25 | # Install git lfs 26 | RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash \ 27 | && apt-get install -y git-lfs \ 28 | && git lfs install 29 | 30 | # Install QEMU 31 | RUN mkdir -p ${INSTALL_PREFIX} \ 32 | && wget https://download.qemu.org/qemu-7.0.0.tar.xz \ 33 | && tar -xvJf qemu-7.0.0.tar.xz -C ${INSTALL_PREFIX} \ 34 | && rm -rf qemu-7.0.0.tar.xz \ 35 | && ln -s ${INSTALL_PREFIX}/qemu-7.0.0 ${INSTALL_PREFIX}/qemu \ 36 | && cd ${INSTALL_PREFIX}/qemu \ 37 | && ./configure --target-list=x86_64-softmmu,x86_64-linux-user,riscv64-softmmu,riscv64-linux-user,aarch64-softmmu,aarch64-linux-user \ 38 | && make -j `nproc` \ 39 | && make install \ 40 | && rm -rf ${INSTALL_PREFIX}/qemu/* 41 | 42 | # Install rust 43 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 44 | 45 | ENV PATH="$HOME/.cargo/bin:$PATH" 46 | ENV WORK_SPACE_PATH=${INSTALL_PREFIX}/zcore 47 | 48 | WORKDIR ${WORK_SPACE_PATH} 49 | COPY . . 50 | -------------------------------------------------------------------------------- /xtask/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xtask" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["YdrMaster "] 6 | build = "build.rs" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | z-config = { path = "../z-config" } 12 | clap = { version = "4.0", features = ["derive"] } 13 | dircpy = "0.3" 14 | rand = "0.8" 15 | once_cell = "1.15.0" 16 | num_cpus = "1" 17 | rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 18 | rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 19 | rcore-fs-fuse = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" } 20 | os-xtask-utils = "0.0.0" 21 | 22 | [target.'cfg(not(target_arch = "riscv64"))'.dependencies] 23 | shadow-rs = "0.11" 24 | 25 | [target.'cfg(not(target_arch = "riscv64"))'.build-dependencies] 26 | shadow-rs = "0.11" 27 | -------------------------------------------------------------------------------- /xtask/build.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_arch = "riscv64")] 2 | fn main() {} 3 | 4 | #[cfg(not(target_arch = "riscv64"))] 5 | fn main() -> shadow_rs::SdResult<()> { 6 | shadow_rs::new() 7 | } 8 | -------------------------------------------------------------------------------- /xtask/src/arch.rs: -------------------------------------------------------------------------------- 1 | //! 支持架构的定义。 2 | 3 | use crate::{commands::wget, LinuxRootfs, XError, ARCHS, TARGET}; 4 | use os_xtask_utils::{dir, CommandExt, Tar}; 5 | use std::{path::PathBuf, str::FromStr}; 6 | 7 | /// 支持的 CPU 架构。 8 | #[derive(Clone, Copy)] 9 | pub(crate) enum Arch { 10 | Riscv64, 11 | X86_64, 12 | Aarch64, 13 | } 14 | 15 | impl Arch { 16 | /// Returns the name of Arch. 17 | #[inline] 18 | pub const fn name(&self) -> &'static str { 19 | match self { 20 | Self::Riscv64 => "riscv64", 21 | Self::X86_64 => "x86_64", 22 | Self::Aarch64 => "aarch64", 23 | } 24 | } 25 | 26 | /// Returns the path to store arch-dependent files from network. 27 | #[inline] 28 | pub fn origin(&self) -> PathBuf { 29 | ARCHS.join(self.name()) 30 | } 31 | 32 | /// Returns the path to cache arch-dependent generated files durning processes. 33 | #[inline] 34 | pub fn target(&self) -> PathBuf { 35 | TARGET.join(self.name()) 36 | } 37 | 38 | /// Downloads linux musl toolchain, and returns its path. 39 | pub fn linux_musl_cross(&self) -> PathBuf { 40 | let name = format!("{}-linux-musl-cross", self.name().to_lowercase()); 41 | 42 | let origin = self.origin(); 43 | let target = self.target(); 44 | 45 | let tgz = origin.join(format!("{name}.tgz")); 46 | let dir = target.join(&name); 47 | 48 | dir::create_parent(&dir).unwrap(); 49 | dir::rm(&dir).unwrap(); 50 | 51 | wget( 52 | format!("https://github.com/YdrMaster/zCore/releases/download/musl-cache/{name}.tgz"), 53 | &tgz, 54 | ); 55 | Tar::xf(&tgz, Some(target)).invoke(); 56 | 57 | dir 58 | } 59 | } 60 | 61 | impl FromStr for Arch { 62 | type Err = XError; 63 | 64 | fn from_str(s: &str) -> Result { 65 | match s.to_lowercase().as_str() { 66 | "riscv64" => Ok(Self::Riscv64), 67 | "x86_64" => Ok(Self::X86_64), 68 | "aarch64" => Ok(Self::Aarch64), 69 | _ => Err(XError::EnumParse { 70 | type_name: "Arch", 71 | value: s.into(), 72 | }), 73 | } 74 | } 75 | } 76 | 77 | #[derive(Clone, Copy, Args)] 78 | pub(crate) struct ArchArg { 79 | /// Build architecture, `riscv64` or `x86_64`. 80 | #[clap(short, long)] 81 | pub arch: Arch, 82 | } 83 | 84 | impl ArchArg { 85 | /// Returns the [`LinuxRootfs`] object related to selected architecture. 86 | #[inline] 87 | pub fn linux_rootfs(&self) -> LinuxRootfs { 88 | LinuxRootfs::new(self.arch) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /xtask/src/commands.rs: -------------------------------------------------------------------------------- 1 | use std::{ffi::OsStr, path::Path}; 2 | 3 | macro_rules! fetch_online { 4 | ($dst:expr, $f:expr) => {{ 5 | use os_xtask_utils::{dir, CommandExt}; 6 | use std::{fs, path::PathBuf}; 7 | 8 | dir::rm(&$dst).unwrap(); 9 | let tmp: usize = rand::random(); 10 | let tmp = PathBuf::from("/tmp").join(tmp.to_string()); 11 | let mut ext = $f(tmp.clone()); 12 | let status = ext.status(); 13 | if status.success() { 14 | dir::create_parent(&$dst).unwrap(); 15 | if tmp.is_dir() { 16 | dircpy::copy_dir(&tmp, &$dst).unwrap(); 17 | } else { 18 | fs::copy(&tmp, &$dst).unwrap(); 19 | } 20 | dir::rm(tmp).unwrap(); 21 | } else { 22 | dir::rm(tmp).unwrap(); 23 | panic!( 24 | "Failed with code {} from {:?}", 25 | status.code().unwrap(), 26 | ext.info() 27 | ); 28 | } 29 | }}; 30 | } 31 | 32 | pub(crate) use fetch_online; 33 | 34 | pub(crate) fn wget(url: impl AsRef, dst: impl AsRef) { 35 | use os_xtask_utils::Ext; 36 | 37 | let dst = dst.as_ref(); 38 | if dst.exists() { 39 | println!("{dst:?} already exist. You can delete it manually to re-download."); 40 | return; 41 | } 42 | 43 | println!("wget {} from {:?}", dst.display(), url.as_ref()); 44 | fetch_online!(dst, |tmp| { 45 | let mut wget = Ext::new("wget"); 46 | wget.arg(&url).arg("-O").arg(tmp); 47 | wget 48 | }); 49 | } 50 | -------------------------------------------------------------------------------- /xtask/src/dump.rs: -------------------------------------------------------------------------------- 1 | shadow_rs::shadow!(build); 2 | 3 | /// 打印仓库和编译信息。 4 | pub fn dump_config() { 5 | println!( 6 | "\ 7 | * ------------------------ 8 | | Build 9 | | Host {os} 10 | | Mode {mode} 11 | | Rustc {rustc} 12 | | Cargo {cargo} 13 | | Time {build_time} 14 | * ------------------------ 15 | | Version Control 16 | | Branch {branch} ({rev}) 17 | | Author {name} <{email}> 18 | | Time {vc_time} 19 | * ------------------------", 20 | os = build::BUILD_OS, 21 | mode = build::BUILD_RUST_CHANNEL, 22 | rustc = build::RUST_VERSION, 23 | cargo = build::CARGO_VERSION, 24 | build_time = build::BUILD_TIME, 25 | branch = build::BRANCH, 26 | name = build::COMMIT_AUTHOR, 27 | email = build::COMMIT_EMAIL, 28 | rev = build::SHORT_COMMIT, 29 | vc_time = build::COMMIT_DATE, 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /xtask/src/errors.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | #[derive(Debug)] 4 | pub(crate) enum XError { 5 | EnumParse { 6 | type_name: &'static str, 7 | value: String, 8 | }, 9 | } 10 | 11 | impl Display for XError { 12 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 13 | match self { 14 | XError::EnumParse { type_name, value } => { 15 | write!(f, "Parse {type_name} from {value} failed.") 16 | } 17 | } 18 | } 19 | } 20 | 21 | impl std::error::Error for XError {} 22 | -------------------------------------------------------------------------------- /xtask/src/linux/image.rs: -------------------------------------------------------------------------------- 1 | use crate::{commands::wget, Arch, PROJECT_DIR}; 2 | use os_xtask_utils::{dir, CommandExt, Qemu, Tar}; 3 | use std::{fs, path::Path}; 4 | 5 | impl super::LinuxRootfs { 6 | /// 生成镜像。 7 | pub fn image(&self) { 8 | // 递归 rootfs 9 | self.make(false); 10 | // 镜像路径 11 | let inner = PROJECT_DIR.join("zCore"); 12 | let image = inner.join(format!("{arch}.img", arch = self.0.name())); 13 | // aarch64 还需要下载 firmware 14 | if let Arch::Aarch64 = self.0 { 15 | const URL:&str = "https://github.com/Luchangcheng2333/rayboot/releases/download/2.0.0/aarch64_firmware.tar.gz"; 16 | let aarch64_tar = self.0.origin().join("Aarch64_firmware.zip"); 17 | wget(URL, &aarch64_tar); 18 | 19 | let fw_dir = self.0.target().join("firmware"); 20 | dir::clear(&fw_dir).unwrap(); 21 | Tar::xf(&aarch64_tar, Some(&fw_dir)).invoke(); 22 | 23 | let boot_dir = inner.join("disk").join("EFI").join("Boot"); 24 | dir::clear(&boot_dir).unwrap(); 25 | fs::copy( 26 | fw_dir.join("aarch64_uefi.efi"), 27 | boot_dir.join("bootaa64.efi"), 28 | ) 29 | .unwrap(); 30 | fs::copy(fw_dir.join("Boot.json"), boot_dir.join("Boot.json")).unwrap(); 31 | } 32 | // 生成镜像 33 | fuse(self.path(), &image); 34 | // 扩充一些额外空间,供某些测试使用 35 | Qemu::img() 36 | .arg("resize") 37 | .args(&["-f", "raw"]) 38 | .arg(image) 39 | .arg("+5M") 40 | .invoke(); 41 | } 42 | } 43 | 44 | /// 制作镜像。 45 | fn fuse(dir: impl AsRef, image: impl AsRef) { 46 | use rcore_fs::vfs::FileSystem; 47 | use rcore_fs_fuse::zip::zip_dir; 48 | use rcore_fs_sfs::SimpleFileSystem; 49 | use std::sync::{Arc, Mutex}; 50 | 51 | let file = fs::OpenOptions::new() 52 | .read(true) 53 | .write(true) 54 | .create(true) 55 | .truncate(true) 56 | .open(image) 57 | .expect("failed to open image"); 58 | const MAX_SPACE: usize = 1024 * 1024 * 1024; // 1GiB 59 | let fs = SimpleFileSystem::create(Arc::new(Mutex::new(file)), MAX_SPACE) 60 | .expect("failed to create sfs"); 61 | zip_dir(dir.as_ref(), fs.root_inode()).expect("failed to zip fs"); 62 | } 63 | -------------------------------------------------------------------------------- /z-config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "z-config" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | serde = "1.0" 10 | serde_derive = "1.0" 11 | toml = "0.5.9" 12 | -------------------------------------------------------------------------------- /z-config/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | 3 | use serde_derive::Deserialize; 4 | use std::{ 5 | collections::HashMap, 6 | fs, 7 | path::{Path, PathBuf}, 8 | }; 9 | 10 | #[derive(Debug)] 11 | pub struct MachineConfig { 12 | pub manufacturer: String, 13 | pub arch: String, 14 | pub user_img: Option, 15 | pub pci_support: bool, 16 | pub features: Vec, 17 | } 18 | 19 | impl MachineConfig { 20 | pub fn select(hardware: impl AsRef) -> Option { 21 | type ConfigFile = HashMap>; 22 | 23 | #[derive(Deserialize, Debug)] 24 | struct RawHardwareConfig { 25 | arch: String, 26 | #[serde(rename(deserialize = "link-user-img"))] 27 | user_img: Option, 28 | #[serde(rename(deserialize = "pci-support"))] 29 | pci_support: Option, 30 | features: Option>, 31 | } 32 | 33 | let file = Path::new(std::env!("CARGO_MANIFEST_DIR")) 34 | .parent() 35 | .unwrap() 36 | .join("config") 37 | .join("machine-features.toml"); 38 | let file = fs::read_to_string(file).unwrap(); 39 | let config = toml::from_str::(&file).unwrap(); 40 | for (manufacturer, products) in config { 41 | for (name, raw) in products { 42 | if name == hardware.as_ref() { 43 | return Some(Self { 44 | manufacturer, 45 | arch: raw.arch, 46 | user_img: raw.user_img, 47 | pci_support: raw.pci_support.unwrap_or(true), 48 | features: raw.features.unwrap_or_default(), 49 | }); 50 | } 51 | } 52 | } 53 | None 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /zCore/.gdbinit_riscv64: -------------------------------------------------------------------------------- 1 | set confirm off 2 | set architecture riscv:rv64 3 | target remote 127.0.0.1:15234 4 | symbol-file ../target/riscv64/release/zcore 5 | display/10i $pc 6 | # tbreak *(&jump_higher - 0xffffffff00000000) 7 | tbreak *0x8023763a 8 | c 9 | si 10 | si 11 | si 12 | -------------------------------------------------------------------------------- /zCore/.gdbinit_x86_64: -------------------------------------------------------------------------------- 1 | target remote 127.0.0.1:15234 2 | symbol-file ../target/x86_64/release/zcore 3 | b _start 4 | # b __alltraps 5 | b syscall_return 6 | # b syscall_entry 7 | display/10i $rip 8 | 9 | -------------------------------------------------------------------------------- /zCore/aarch64.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 | "executables": true, 6 | "features": "+strict-align,+neon,+fp-armv8", 7 | "linker": "rust-lld", 8 | "linker-flavor": "ld.lld", 9 | "llvm-target": "aarch64-unknown-linux-gnu", 10 | "max-atomic-width": 128, 11 | "panic-strategy": "abort", 12 | "relocation-model": "static", 13 | "pre-link-args": { 14 | "ld.lld": [ 15 | "-TzCore/src/platform/aarch64/linker.ld" 16 | ] 17 | }, 18 | "target-pointer-width": "64" 19 | } 20 | -------------------------------------------------------------------------------- /zCore/build.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | fn main() { 4 | if std::env::var("TARGET").unwrap().contains("riscv64") { 5 | let board = std::env::var("PLATFORM"); 6 | let kernel_base_addr: u64 = if board.map_or(false, |x| x.contains("c910light")) { 7 | 0xffffffe000200000 8 | } else { 9 | 0xffffffc080200000 10 | }; 11 | 12 | let mut fout = std::fs::File::create("src/platform/riscv/kernel-vars.ld").unwrap(); 13 | writeln!(fout, "/* Generated by build.rs. DO NOT EDIT. */").unwrap(); 14 | writeln!( 15 | fout, 16 | "PROVIDE_HIDDEN(BASE_ADDRESS = {:#x});", 17 | kernel_base_addr 18 | ) 19 | .unwrap(); 20 | } 21 | 22 | // 如果需要链接 rootfs 镜像,将镜像路径设置到环境变量 23 | #[cfg(feature = "link-user-img")] 24 | println!( 25 | "cargo:rustc-env=USER_IMG=zCore/{}.img", 26 | std::env::var("TARGET").unwrap() 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /zCore/rboot.conf: -------------------------------------------------------------------------------- 1 | # The config file for rboot. 2 | # Place me at \EFI\Boot\rboot.conf 3 | 4 | # The address at which the kernel stack is placed. 5 | # kernel_stack_address=0xFFFFFF8000000000 6 | 7 | # The size of the kernel stack, given in number of 4KiB pages. Defaults to 512. 8 | # kernel_stack_size=128 9 | 10 | # The virtual address offset from which physical memory is mapped, as described in 11 | # https://os.phil-opp.com/paging-implementation/#map-the-complete-physical-memory 12 | physical_memory_offset=0xFFFF800000000000 13 | 14 | # The path of kernel ELF 15 | kernel_path=\EFI\zCore\zcore.elf 16 | 17 | # The resolution of graphic output 18 | resolution=800x600 19 | 20 | initramfs=\EFI\zCore\fuchsia.zbi 21 | # LOG=debug/info/error/warn/trace 22 | # add ROOTPROC info ? split CMD and ARG : ROOTPROC=/libc-test/src/functional/argv.exe? OR ROOTPROC=/bin/busybox?sh 23 | cmdline=LOG=warn:TERM=xterm-256color:console.shell=true:virtcon.disable=true 24 | -------------------------------------------------------------------------------- /zCore/rboot.conf.default: -------------------------------------------------------------------------------- 1 | # The config file for rboot. 2 | # Place me at \EFI\Boot\rboot.conf 3 | 4 | # The address at which the kernel stack is placed. 5 | # kernel_stack_address=0xFFFFFF8000000000 6 | 7 | # The size of the kernel stack, given in number of 4KiB pages. Defaults to 512. 8 | # kernel_stack_size=128 9 | 10 | # The virtual address offset from which physical memory is mapped, as described in 11 | # https://os.phil-opp.com/paging-implementation/#map-the-complete-physical-memory 12 | physical_memory_offset=0xFFFF800000000000 13 | 14 | # The path of kernel ELF 15 | kernel_path=\EFI\zCore\zcore.elf 16 | 17 | # The resolution of graphic output 18 | resolution=1024x768 19 | 20 | initramfs=\EFI\zCore\fuchsia.zbi 21 | # LOG=debug/info/error/warn/trace 22 | # add ROOTPROC info ? split CMD and ARG : ROOTPROC=/libc-test/src/functional/argv.exe? OR ROOTPROC=/bin/busybox?sh 23 | cmdline=LOG=info:TERM=xterm-256color:console.shell=true:virtcon.disable=true 24 | -------------------------------------------------------------------------------- /zCore/riscv64.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "riscv64", 3 | "arch": "riscv64", 4 | "os": "none", 5 | "code-model": "medium", 6 | "cpu": "generic-rv64", 7 | "data-layout": "e-m:e-p:64:64-i64:64-i128:128-n64-S128", 8 | "target-c-int-width": "32", 9 | "target-endian": "little", 10 | "target-pointer-width": "64", 11 | "eh-frame-header": false, 12 | "emit-debug-gdb-scripts": false, 13 | "executables": true, 14 | "features": "+m,+a,+c", 15 | "is-builtin": false, 16 | "linker": "rust-lld", 17 | "linker-flavor": "ld.lld", 18 | "pre-link-args": { 19 | "ld.lld": [ 20 | "-TzCore/src/platform/riscv/linker.ld" 21 | ] 22 | }, 23 | "max-atomic-width": 64, 24 | "panic-strategy": "abort", 25 | "relocation-model": "static" 26 | } 27 | -------------------------------------------------------------------------------- /zCore/src/handler.rs: -------------------------------------------------------------------------------- 1 | use kernel_hal::{KernelHandler, MMUFlags}; 2 | use zircon_object::task::Thread; 3 | 4 | use super::memory; 5 | 6 | pub struct ZcoreKernelHandler; 7 | 8 | impl KernelHandler for ZcoreKernelHandler { 9 | fn frame_alloc(&self) -> Option { 10 | memory::frame_alloc(1, 0) 11 | } 12 | 13 | fn frame_alloc_contiguous(&self, frame_count: usize, align_log2: usize) -> Option { 14 | memory::frame_alloc(frame_count, align_log2) 15 | } 16 | 17 | fn frame_dealloc(&self, paddr: usize) { 18 | memory::frame_dealloc(paddr) 19 | } 20 | 21 | fn handle_page_fault(&self, fault_vaddr: usize, access_flags: MMUFlags) { 22 | if let Some(thread) = kernel_hal::thread::get_current_thread() { 23 | let thread = thread.downcast::().unwrap(); 24 | let vmar = thread.proc().vmar(); 25 | if let Err(err) = vmar.handle_page_fault(fault_vaddr, access_flags) { 26 | panic!( 27 | "handle kernel page fault error: {:?} vaddr(0x{:x}) flags({:?})", 28 | err, fault_vaddr, access_flags 29 | ); 30 | } 31 | } else { 32 | panic!( 33 | "page fault from kernel private address 0x{:x}, flags = {:?}", 34 | fault_vaddr, access_flags 35 | ); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /zCore/src/lang.rs: -------------------------------------------------------------------------------- 1 | // Rust language features implementations 2 | 3 | use core::panic::PanicInfo; 4 | 5 | #[panic_handler] 6 | fn panic(info: &PanicInfo) -> ! { 7 | println!("\n\npanic cpu={}\n{}", kernel_hal::cpu::cpu_id(), info); 8 | error!("\n\n{info}"); 9 | 10 | if cfg!(feature = "baremetal-test") { 11 | kernel_hal::cpu::reset(); 12 | } else { 13 | loop { 14 | core::hint::spin_loop(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /zCore/src/platform/aarch64/consts.rs: -------------------------------------------------------------------------------- 1 | // aarch64 2 | 3 | use spin::Once; 4 | 5 | static OFFSET: Once = Once::new(); 6 | 7 | #[inline] 8 | pub(super) fn save_offset(offset: usize) { 9 | OFFSET.call_once(|| offset); 10 | } 11 | 12 | #[inline] 13 | pub fn phys_to_virt_offset() -> usize { 14 | *OFFSET.wait() 15 | } 16 | -------------------------------------------------------------------------------- /zCore/src/platform/aarch64/entry.rs: -------------------------------------------------------------------------------- 1 | use super::consts::save_offset; 2 | use kernel_hal::KernelConfig; 3 | use rayboot::Aarch64BootInfo; 4 | core::arch::global_asm!(include_str!("space.s")); 5 | 6 | #[naked] 7 | #[no_mangle] 8 | #[link_section = ".text.entry"] 9 | unsafe extern "C" fn _start() -> ! { 10 | core::arch::asm!( 11 | " 12 | adrp x19, boot_stack_top 13 | mov sp, x19 14 | b rust_main", 15 | options(noreturn), 16 | ) 17 | } 18 | 19 | #[no_mangle] 20 | extern "C" fn rust_main(boot_info: &'static Aarch64BootInfo) -> ! { 21 | let config = KernelConfig { 22 | cmdline: boot_info.cmdline, 23 | firmware_type: boot_info.firmware_type, 24 | uart_base: boot_info.uart_base, 25 | gic_base: boot_info.gic_base, 26 | phys_to_virt_offset: boot_info.offset, 27 | }; 28 | save_offset(boot_info.offset); 29 | crate::primary_main(config); 30 | unreachable!() 31 | } 32 | -------------------------------------------------------------------------------- /zCore/src/platform/aarch64/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | BASE_ADDRESS = 0xffff000040080000; 3 | 4 | SECTIONS 5 | { 6 | . = BASE_ADDRESS; 7 | skernel = .; 8 | 9 | .text : { 10 | stext = .; 11 | *(.text.entry) 12 | *(.text .text.*) 13 | . = ALIGN(4K); 14 | etext = .; 15 | } 16 | 17 | .rodata : { 18 | srodata = .; 19 | *(.rodata .rodata.*) 20 | *(.srodata .srodata.*) 21 | . = ALIGN(4K); 22 | erodata = .; 23 | } 24 | 25 | .data : { 26 | sdata = .; 27 | *(.data .data.*) 28 | *(.sdata .sdata.*) 29 | . = ALIGN(4K); 30 | edata = .; 31 | } 32 | 33 | .bss : { 34 | boot_stack = .; 35 | *(.bss.stack) 36 | . = ALIGN(4K); 37 | boot_stack_top = .; 38 | 39 | sbss = .; 40 | *(.bss .bss.*) 41 | *(.sbss .sbss.*) 42 | . = ALIGN(4K); 43 | ebss = .; 44 | } 45 | 46 | ekernel = .; 47 | 48 | /DISCARD/ : { 49 | *(.eh_frame) *(.eh_frame_hdr) 50 | } 51 | } -------------------------------------------------------------------------------- /zCore/src/platform/aarch64/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod consts; 2 | pub mod entry; 3 | -------------------------------------------------------------------------------- /zCore/src/platform/aarch64/space.s: -------------------------------------------------------------------------------- 1 | .section .data 2 | .align 12 3 | sdata: 4 | .space 0x8000 // 32K 5 | 6 | .section .bss.stack 7 | .align 12 8 | boot_stack: 9 | .space 0x8000 // 32K 10 | boot_stack_top: -------------------------------------------------------------------------------- /zCore/src/platform/libos/consts.rs: -------------------------------------------------------------------------------- 1 | //! Nothing 2 | -------------------------------------------------------------------------------- /zCore/src/platform/libos/entry.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | fn main() { 3 | crate::primary_main(kernel_hal::KernelConfig); 4 | } 5 | -------------------------------------------------------------------------------- /zCore/src/platform/libos/mod.rs: -------------------------------------------------------------------------------- 1 | mod entry; 2 | 3 | pub mod consts; 4 | -------------------------------------------------------------------------------- /zCore/src/platform/mod.rs: -------------------------------------------------------------------------------- 1 | cfg_if! { 2 | if #[cfg(feature = "libos")] { 3 | #[path = "libos/mod.rs"] 4 | mod arch; 5 | } else if #[cfg(target_arch = "x86_64")] { 6 | #[path = "x86/mod.rs"] 7 | mod arch; 8 | } else if #[cfg(target_arch = "riscv64")] { 9 | #[path = "riscv/mod.rs"] 10 | mod arch; 11 | } else if #[cfg(target_arch = "aarch64")] { 12 | #[path = "aarch64/mod.rs"] 13 | mod arch; 14 | } 15 | } 16 | 17 | pub use arch::consts::*; 18 | -------------------------------------------------------------------------------- /zCore/src/platform/riscv/boot.asm: -------------------------------------------------------------------------------- 1 | .equ STACK_MAX, 4096 * 16 2 | .equ STACK_MAX_HARTS, 8 3 | 4 | .section .text.entry 5 | .globl _start 6 | _start: 7 | #关中断 8 | csrw sie, zero 9 | csrw sip, zero 10 | 11 | #关闭mmu 12 | #csrw satp, zero 13 | 14 | #BSS节清零 15 | la t0, sbss 16 | la t1, ebss 17 | bgeu t0, t1, primary_hart 18 | 19 | clear_bss_loop: 20 | # sd: store double word (64 bits) 21 | sd zero, (t0) 22 | addi t0, t0, 8 23 | bltu t0, t1, clear_bss_loop 24 | 25 | primary_hart: 26 | call init_vm 27 | la t0, primary_rust_main 28 | la t1, PHY_MEM_OFS 29 | ld t1, (t1) 30 | add t0, t0, t1 31 | jr t0 32 | 33 | .globl secondary_hart_start 34 | secondary_hart_start: 35 | csrw sie, zero 36 | csrw sip, zero 37 | call init_vm 38 | la t0, secondary_rust_main 39 | la t1, PHY_MEM_OFS 40 | ld t1, (t1) 41 | add t0, t0, t1 42 | jr t0 43 | 44 | init_vm: 45 | #获取页表的物理地址 46 | la t0, boot_page_table_sv39 47 | 48 | #右移12位,变为satp的PPN 49 | srli t0, t0, 12 50 | 51 | #satp的MODE设为Sv39 52 | li t1, 8 << 60 53 | 54 | #写satp 55 | or t0, t0, t1 56 | 57 | #刷新TLB 58 | sfence.vma 59 | 60 | csrw satp, t0 61 | 62 | #此时在虚拟内存空间,设置sp为虚拟地址 63 | li t0, STACK_MAX 64 | mul t0, t0, a0 65 | 66 | la t1, boot_stack_top 67 | la t2, PHY_MEM_OFS 68 | ld t2, (t2) 69 | add sp, t1, t2 70 | 71 | #计算多个核的sp偏移 72 | sub sp, sp, t0 73 | ret 74 | 75 | .section .data 76 | .align 12 #12位对齐 77 | boot_page_table_sv39: 78 | #1G的一个大页: 0x00000000_00000000 --> 0x00000000 79 | #1G的一个大页: 0x00000000_80000000 --> 0x80000000 80 | #1G的一个大页: 0xffffffe0_00000000 --> 0x00000000 81 | #1G的一个大页: 0xffffffe0_80000000 --> 0x80000000 82 | 83 | .quad (0 << 10) | 0xef 84 | .zero 8 85 | .quad (0x80000 << 10) | 0xef 86 | 87 | .zero 8 * 381 88 | .quad (0 << 10) | 0xef 89 | .zero 8 90 | .quad (0x80000 << 10) | 0xef 91 | .zero 8 * 125 92 | 93 | .section .bss.stack 94 | .align 12 95 | .global boot_stack 96 | boot_stack: 97 | .space STACK_MAX * STACK_MAX_HARTS 98 | .global boot_stack_top 99 | boot_stack_top: 100 | -------------------------------------------------------------------------------- /zCore/src/platform/riscv/consts.rs: -------------------------------------------------------------------------------- 1 | // RISCV 2 | 3 | /// 内核每个硬件线程的栈页数。 4 | pub const STACK_PAGES_PER_HART: usize = 32; 5 | 6 | /// 最大的对称多核硬件线程数量。 7 | pub const MAX_HART_NUM: usize = 5; 8 | 9 | #[inline] 10 | pub fn phys_to_virt_offset() -> usize { 11 | kernel_mem_info().offset() 12 | } 13 | 14 | use spin::Once; 15 | 16 | /// 内核位置信息 17 | pub struct KernelMemInfo { 18 | /// 内核在物理地址空间的起始地址。 19 | pub paddr_base: usize, 20 | 21 | /// 内核所在虚拟地址空间的起始地址。 22 | /// 23 | /// 实际上是虚地址空间的最后一个 GiB 页的起始地址, 24 | /// 并与物理内存保持 2 MiB 页内偏移对齐。 25 | /// 与链接时设定的地址保持一致。 26 | pub vaddr_base: usize, 27 | 28 | /// 内核链接区域长度。 29 | pub size: usize, 30 | } 31 | 32 | impl KernelMemInfo { 33 | /// 初始化物理内存信息。 34 | /// 35 | /// # Safety 36 | /// 37 | /// 为了获取内核的物理地址, 38 | /// 这个函数必须在 `pc` 仍在物理地址空间时调用! 39 | unsafe fn new() -> Self { 40 | extern "C" { 41 | fn start(); 42 | fn end(); 43 | } 44 | let paddr_base = start as usize; 45 | let vaddr_base = 0xffff_ffc0_8020_0000; 46 | Self { 47 | paddr_base, 48 | vaddr_base, 49 | size: end as usize - paddr_base, 50 | } 51 | } 52 | 53 | /// 计算内核虚存空间到物理地址空间的偏移。 54 | #[inline] 55 | pub fn offset(&self) -> usize { 56 | self.vaddr_base - self.paddr_base 57 | } 58 | } 59 | 60 | static KERNEL_MEM_INFO: Once = Once::new(); 61 | 62 | #[inline] 63 | pub fn kernel_mem_info() -> &'static KernelMemInfo { 64 | KERNEL_MEM_INFO.wait() 65 | } 66 | 67 | #[inline] 68 | pub(super) unsafe fn kernel_mem_probe() -> &'static KernelMemInfo { 69 | KERNEL_MEM_INFO.call_once(|| KernelMemInfo::new()) 70 | } 71 | -------------------------------------------------------------------------------- /zCore/src/platform/riscv/linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(riscv) 2 | ENTRY(_start) 3 | INCLUDE zCore/src/platform/riscv/kernel-vars.ld 4 | SECTIONS 5 | { 6 | . = BASE_ADDRESS; 7 | start = .; 8 | 9 | .text : { 10 | stext = .; 11 | *(.text.entry) 12 | *(.text .text.*) 13 | etext = .; 14 | } 15 | 16 | .rodata ALIGN(4K) : { 17 | srodata = .; 18 | *(.rodata .rodata.*) 19 | *(.srodata .srodata.*) 20 | erodata = .; 21 | } 22 | 23 | .data ALIGN(4K) : { 24 | sdata = .; 25 | *(.data .data.*) 26 | *(.sdata .sdata.*) 27 | edata = .; 28 | } 29 | 30 | .stack ALIGN(4K) : { 31 | sstack = .; 32 | *(.bss.stack) 33 | } 34 | 35 | .bss ALIGN(4K) : { 36 | bootstack = .; 37 | *(.bss.bootstack) 38 | bootstacktop = .; 39 | 40 | . = ALIGN(4K); 41 | sbss = .; 42 | *(.bss .bss.*) 43 | *(.sbss .sbss.*) 44 | ebss = .; 45 | } 46 | 47 | PROVIDE(end = .); 48 | } 49 | -------------------------------------------------------------------------------- /zCore/src/platform/riscv/mod.rs: -------------------------------------------------------------------------------- 1 | cfg_if! { 2 | if #[cfg(feature = "board-c910light")] { 3 | mod entry64; 4 | pub use entry64::consts; 5 | } else { 6 | mod boot_page_table; 7 | pub mod consts; 8 | mod entry; 9 | }} 10 | -------------------------------------------------------------------------------- /zCore/src/platform/x86/consts.rs: -------------------------------------------------------------------------------- 1 | //! Nothing 2 | -------------------------------------------------------------------------------- /zCore/src/platform/x86/entry.rs: -------------------------------------------------------------------------------- 1 | use kernel_hal::KernelConfig; 2 | use rboot::BootInfo; 3 | 4 | #[no_mangle] 5 | pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { 6 | let info = boot_info.graphic_info; 7 | let config = KernelConfig { 8 | cmdline: boot_info.cmdline, 9 | initrd_start: boot_info.initramfs_addr, 10 | initrd_size: boot_info.initramfs_size, 11 | 12 | memory_map: boot_info.memory_map.as_slice(), 13 | phys_to_virt_offset: boot_info.physical_memory_offset as _, 14 | 15 | fb_mode: info.mode, 16 | fb_addr: info.fb_addr, 17 | fb_size: info.fb_size, 18 | 19 | acpi_rsdp: boot_info.acpi2_rsdp_addr, 20 | smbios: boot_info.smbios_addr, 21 | ap_fn: crate::secondary_main, 22 | }; 23 | crate::primary_main(config); 24 | unreachable!() 25 | } 26 | -------------------------------------------------------------------------------- /zCore/src/platform/x86/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | KERNEL_BEGIN = 0xffffff0000000000; 4 | 5 | SECTIONS { 6 | 7 | . = KERNEL_BEGIN; 8 | 9 | .text ALIGN(4K): 10 | { 11 | stext = .; 12 | _copy_user_start = .; 13 | *(.text.copy_user) 14 | _copy_user_end = .; 15 | *(.text .text.*) 16 | etext = .; 17 | } 18 | 19 | .rodata ALIGN(4K): 20 | { 21 | *(.rodata .rodata.*) 22 | *(.srodata .srodata.*) 23 | } 24 | 25 | .kcounter.desc ALIGN(4K): 26 | { 27 | PROVIDE_HIDDEN(kcounters_desc_vmo_start = .); 28 | KEEP(*(.kcounter.desc.header)) 29 | QUAD(kcounters_desc_end - kcounters_desc_start); 30 | ASSERT(. - kcounters_desc_vmo_start == 24, "wrong size of the kcounter descriptor VMO header"); 31 | 32 | PROVIDE_HIDDEN(kcounters_desc_start = .); 33 | KEEP(*(SORT_BY_NAME(.kcounter.desc.*))) 34 | PROVIDE_HIDDEN(kcounters_desc_end = .); 35 | } :rodata 36 | 37 | .data ALIGN(4K): 38 | { 39 | *(.data .data.*) 40 | *(.sdata .sdata.*) 41 | } 42 | 43 | .got ALIGN(4K): 44 | { 45 | *(.got .got.*) 46 | } 47 | 48 | .bss ALIGN(4K): 49 | { 50 | PROVIDE_HIDDEN(kcounters_arena_start = .); 51 | KEEP(*(SORT_BY_NAME(.bss.kcounter.*))) 52 | PROVIDE_HIDDEN(kcounters_arena_end = .); 53 | ASSERT(kcounters_arena_end - kcounters_arena_start == (kcounters_desc_end - kcounters_desc_start) * 8 / 64, 54 | "kcounters_arena size mismatch"); 55 | 56 | *(.bss .bss.*) 57 | *(.sbss .sbss.*) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /zCore/src/platform/x86/mod.rs: -------------------------------------------------------------------------------- 1 | mod entry; 2 | 3 | pub mod consts; 4 | -------------------------------------------------------------------------------- /zCore/x86_64.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "x86_64-unknown-none", 3 | "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", 4 | "linker-flavor": "ld.lld", 5 | "target-endian": "little", 6 | "target-pointer-width": "64", 7 | "target-c-int-width": "32", 8 | "arch": "x86_64", 9 | "os": "none", 10 | "executables": true, 11 | "linker": "rust-lld", 12 | "pre-link-args": { 13 | "ld.lld": [ 14 | "-TzCore/src/platform/x86/linker.ld" 15 | ] 16 | }, 17 | "disable-redzone": true, 18 | "features": "-mmx,-sse,+soft-float", 19 | "panic-strategy": "abort" 20 | } 21 | -------------------------------------------------------------------------------- /zircon-object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-object" 3 | version = "0.1.0" 4 | authors = [ 5 | "Runji Wang ", 6 | "Qinglin Pan ", 7 | ] 8 | edition = "2018" 9 | description = "Zircon kernel objects" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [features] 14 | aspace-separate = [] 15 | elf = ["xmas-elf"] 16 | #hypervisor = ["rvm"] 17 | 18 | libos = [ 19 | "kernel-hal/libos", 20 | ] 21 | 22 | [dependencies] 23 | bitflags = "1.3" 24 | log = "0.4" 25 | hashbrown = "0.9" 26 | downcast-rs = { version = "1.2", default-features = false } 27 | kernel-hal = { path = "../kernel-hal", default-features = false } 28 | numeric-enum-macro = "0.2" 29 | futures = { version = "0.3", default-features = false, features = [ 30 | "alloc", 31 | "async-await", 32 | ] } 33 | xmas-elf = { version = "0.7", optional = true } 34 | region-alloc = { git = "https://github.com/rzswh/region-allocator", rev = "122c7a71" } 35 | lazy_static = { version = "1.4", features = ["spin_no_std"] } 36 | cfg-if = "1.0" 37 | #rvm = { git = "https://github.com/rcore-os/RVM", rev = "382fc60", optional = true } 38 | lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "8486b8" } 39 | 40 | [dev-dependencies] 41 | async-std = { version = "1.10", features = ["attributes", "unstable"] } 42 | -------------------------------------------------------------------------------- /zircon-object/src/dev/interrupt/event_interrupt.rs: -------------------------------------------------------------------------------- 1 | use kernel_hal::interrupt; 2 | use {super::*, lock::Mutex}; 3 | 4 | pub struct EventInterrupt { 5 | vector: usize, 6 | inner: Mutex, 7 | } 8 | 9 | #[derive(Default)] 10 | struct EventInterruptInner { 11 | register: bool, 12 | } 13 | 14 | impl EventInterrupt { 15 | pub fn new(vector: usize) -> Box { 16 | // TODO check vector is a vaild IRQ number 17 | Box::new(EventInterrupt { 18 | vector, 19 | inner: Default::default(), 20 | }) 21 | } 22 | } 23 | 24 | impl InterruptTrait for EventInterrupt { 25 | fn mask(&self) { 26 | let inner = self.inner.lock(); 27 | if inner.register { 28 | interrupt::mask_irq(self.vector).unwrap(); 29 | } 30 | } 31 | 32 | fn unmask(&self) { 33 | let inner = self.inner.lock(); 34 | if inner.register { 35 | interrupt::unmask_irq(self.vector).unwrap(); 36 | } 37 | } 38 | 39 | fn register_handler(&self, handle: Box) -> ZxResult { 40 | let mut inner = self.inner.lock(); 41 | if inner.register { 42 | return Err(ZxError::ALREADY_BOUND); 43 | } 44 | if interrupt::register_irq_handler(self.vector, handle).is_ok() { 45 | inner.register = true; 46 | Ok(()) 47 | } else { 48 | Err(ZxError::ALREADY_BOUND) 49 | } 50 | } 51 | 52 | fn unregister_handler(&self) -> ZxResult { 53 | let mut inner = self.inner.lock(); 54 | if !inner.register { 55 | return Ok(()); 56 | } 57 | if interrupt::unregister_irq_handler(self.vector).is_ok() { 58 | inner.register = false; 59 | Ok(()) 60 | } else { 61 | Err(ZxError::NOT_FOUND) 62 | } // maybe a better error code? 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /zircon-object/src/dev/interrupt/pci_interrupt.rs: -------------------------------------------------------------------------------- 1 | use alloc::{boxed::Box, sync::Arc}; 2 | use lock::Mutex; 3 | 4 | use super::InterruptTrait; 5 | use crate::dev::pci::{constants::PCIE_IRQRET_MASK, IPciNode}; 6 | use crate::{ZxError, ZxResult}; 7 | 8 | pub struct PciInterrupt { 9 | device: Arc, 10 | irq_id: usize, 11 | maskable: bool, 12 | inner: Mutex, 13 | } 14 | 15 | #[derive(Default)] 16 | struct PciInterruptInner { 17 | register: bool, 18 | } 19 | 20 | impl PciInterrupt { 21 | pub fn new(device: Arc, vector: u32, maskable: bool) -> Box { 22 | // TODO check vector is a vaild IRQ number 23 | Box::new(PciInterrupt { 24 | device, 25 | irq_id: vector as _, 26 | maskable, 27 | inner: Default::default(), 28 | }) 29 | } 30 | } 31 | 32 | impl InterruptTrait for PciInterrupt { 33 | fn mask(&self) { 34 | let inner = self.inner.lock(); 35 | if self.maskable && inner.register { 36 | self.device.disable_irq(self.irq_id); 37 | } 38 | } 39 | 40 | fn unmask(&self) { 41 | let inner = self.inner.lock(); 42 | if self.maskable && inner.register { 43 | self.device.enable_irq(self.irq_id); 44 | } 45 | } 46 | 47 | fn register_handler(&self, handle: Box) -> ZxResult { 48 | let mut inner = self.inner.lock(); 49 | if inner.register { 50 | return Err(ZxError::ALREADY_BOUND); 51 | } 52 | self.device.register_irq_handle( 53 | self.irq_id, 54 | Box::new(move || { 55 | handle(); 56 | PCIE_IRQRET_MASK 57 | }), 58 | ); 59 | inner.register = true; 60 | Ok(()) 61 | } 62 | 63 | fn unregister_handler(&self) -> ZxResult { 64 | let mut inner = self.inner.lock(); 65 | if !inner.register { 66 | return Ok(()); 67 | } 68 | self.device.unregister_irq_handle(self.irq_id); 69 | inner.register = false; 70 | Ok(()) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /zircon-object/src/dev/interrupt/virtual_interrupt.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[derive(Default)] 4 | pub struct VirtualInterrupt {} 5 | 6 | impl VirtualInterrupt { 7 | pub fn new() -> Box { 8 | Default::default() 9 | } 10 | } 11 | 12 | impl InterruptTrait for VirtualInterrupt { 13 | fn mask(&self) {} 14 | fn unmask(&self) {} 15 | fn register_handler(&self, _handle: Box) -> ZxResult { 16 | Ok(()) 17 | } 18 | fn unregister_handler(&self) -> ZxResult { 19 | Ok(()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /zircon-object/src/dev/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Device Drivers. 2 | 3 | mod bti; 4 | mod interrupt; 5 | mod iommu; 6 | pub mod pci; 7 | mod pmt; 8 | mod resource; 9 | 10 | pub use self::{bti::*, interrupt::*, iommu::*, pmt::*, resource::*}; 11 | -------------------------------------------------------------------------------- /zircon-object/src/dev/pci/mod.rs: -------------------------------------------------------------------------------- 1 | mod bus; 2 | mod caps; 3 | mod config; 4 | mod nodes; 5 | pub mod pci_init_args; 6 | mod pmio; 7 | 8 | pub use bus::{ 9 | MmioPcieAddressProvider, PCIeBusDriver, PcieDeviceInfo, PcieDeviceKObject, 10 | PmioPcieAddressProvider, 11 | }; 12 | pub use nodes::{IPciNode, PcieIrqMode}; 13 | pub use pmio::{pio_config_read, pio_config_write}; 14 | 15 | /// Type of PCI address space. 16 | #[derive(PartialEq, Eq, Debug)] 17 | #[allow(clippy::upper_case_acronyms)] 18 | pub enum PciAddrSpace { 19 | /// Memory mapping I/O. 20 | MMIO, 21 | /// Port I/O. 22 | PIO, 23 | } 24 | 25 | /// ECAM Region. 26 | pub struct PciEcamRegion { 27 | /// Physical address of the memory mapped config region. 28 | pub phys_base: u64, 29 | /// Size (in bytes) of the memory mapped config region. 30 | pub size: usize, 31 | /// Inclusive ID of the first bus controlled by this region. 32 | pub bus_start: u8, 33 | /// Inclusive ID of the last bus controlled by this region. 34 | pub bus_end: u8, 35 | } 36 | 37 | /// Mapped ECAM Region. 38 | pub struct MappedEcamRegion { 39 | ecam: PciEcamRegion, 40 | vaddr: u64, 41 | } 42 | 43 | #[allow(missing_docs)] 44 | pub mod constants { 45 | pub const PCI_MAX_DEVICES_PER_BUS: usize = 32; 46 | pub const PCI_MAX_FUNCTIONS_PER_DEVICE: usize = 8; 47 | pub const PCI_MAX_LEGACY_IRQ_PINS: usize = 4; 48 | pub const PCI_MAX_FUNCTIONS_PER_BUS: usize = 49 | PCI_MAX_FUNCTIONS_PER_DEVICE * PCI_MAX_DEVICES_PER_BUS; 50 | pub const PCI_MAX_IRQS: usize = 224; 51 | 52 | pub const PCI_NO_IRQ_MAPPING: u32 = u32::MAX; 53 | pub const PCIE_PIO_ADDR_SPACE_MASK: u64 = 0xFFFF_FFFF; 54 | pub const PCIE_MAX_BUSSES: usize = 256; 55 | pub const PCIE_ECAM_BYTES_PER_BUS: usize = 56 | 4096 * PCI_MAX_DEVICES_PER_BUS * PCI_MAX_FUNCTIONS_PER_DEVICE; 57 | pub const PCIE_INVALID_VENDOR_ID: usize = 0xFFFF; 58 | 59 | pub const PCI_CFG_SPACE_TYPE_PIO: u8 = 0; 60 | pub const PCI_CFG_SPACE_TYPE_MMIO: u8 = 1; 61 | pub const PCIE_IRQRET_MASK: u32 = 0x1; 62 | pub const PCIE_MAX_MSI_IRQS: usize = 32; 63 | } 64 | -------------------------------------------------------------------------------- /zircon-object/src/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for IPC. 2 | 3 | mod channel; 4 | mod fifo; 5 | mod socket; 6 | 7 | pub use self::{channel::*, fifo::*, socket::*}; 8 | -------------------------------------------------------------------------------- /zircon-object/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Zircon kernel objects 2 | //! 3 | //! # Feature flags 4 | //! 5 | //! - `elf`: Enables `zircon_object::util::elf_loader`. 6 | //! - `hypervisor`: Enables `zircon_object::hypervisor` (`Guest` and `Vcpu`). 7 | 8 | #![no_std] 9 | #![deny(warnings)] 10 | // #![deny(missing_docs)] 形同虚设了 11 | 12 | extern crate alloc; 13 | 14 | #[macro_use] 15 | extern crate log; 16 | 17 | #[cfg(test)] 18 | #[macro_use] 19 | extern crate std; 20 | 21 | pub mod debuglog; 22 | pub mod dev; 23 | mod error; 24 | #[cfg(feature = "hypervisor")] 25 | pub mod hypervisor; 26 | pub mod ipc; 27 | pub mod object; 28 | pub mod signal; 29 | pub mod task; 30 | pub mod util; 31 | pub mod vm; 32 | 33 | pub use self::error::*; 34 | -------------------------------------------------------------------------------- /zircon-object/src/signal/event.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::object::*; 3 | use alloc::sync::Arc; 4 | 5 | /// Signalable event for concurrent programming 6 | /// 7 | /// ## SYNOPSIS 8 | /// 9 | /// Events are user-signalable objects. The 8 signal bits reserved for 10 | /// userspace (`ZX_USER_SIGNAL_0` through `ZX_USER_SIGNAL_7`) may be set, 11 | /// cleared, and waited upon. 12 | pub struct Event { 13 | base: KObjectBase, 14 | _counter: CountHelper, 15 | } 16 | 17 | impl_kobject!(Event 18 | fn allowed_signals(&self) -> Signal { 19 | Signal::USER_ALL | Signal::SIGNALED 20 | } 21 | ); 22 | define_count_helper!(Event); 23 | 24 | impl Event { 25 | /// Create a new `Event`. 26 | pub fn new() -> Arc { 27 | Arc::new(Event { 28 | base: KObjectBase::default(), 29 | _counter: CountHelper::new(), 30 | }) 31 | } 32 | } 33 | 34 | #[cfg(test)] 35 | mod tests { 36 | use super::*; 37 | 38 | #[test] 39 | fn test_allowed_signals() { 40 | let event = Event::new(); 41 | assert!(Signal::verify_user_signal( 42 | event.allowed_signals(), 43 | (Signal::USER_SIGNAL_5 | Signal::SIGNALED).bits().into() 44 | ) 45 | .is_ok()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /zircon-object/src/signal/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for signaling and waiting. 2 | 3 | use super::*; 4 | 5 | mod event; 6 | mod eventpair; 7 | mod futex; 8 | mod port; 9 | mod timer; 10 | 11 | pub use self::{event::*, eventpair::*, futex::*, port::*, timer::*}; 12 | -------------------------------------------------------------------------------- /zircon-object/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Task Management. 2 | 3 | use super::*; 4 | use alloc::sync::Arc; 5 | 6 | mod exception; 7 | mod job; 8 | mod job_policy; 9 | mod process; 10 | mod suspend_token; 11 | mod thread; 12 | 13 | pub use { 14 | self::exception::*, self::job::*, self::job_policy::*, self::process::*, 15 | self::suspend_token::*, self::thread::*, 16 | }; 17 | 18 | /// Task (Thread, Process, or Job) 19 | pub trait Task: Sync + Send { 20 | /// Kill the task. The task do not terminate immediately when killed. 21 | /// It will terminate after all its children are terminated or some cleanups are finished. 22 | fn kill(&self); 23 | 24 | /// Suspend the task. Currently only thread or process handles may be suspended. 25 | fn suspend(&self); 26 | 27 | /// Resume the task 28 | fn resume(&self); 29 | 30 | /// Get the exceptionate. 31 | fn exceptionate(&self) -> Arc; 32 | 33 | /// Get the debug exceptionate. 34 | fn debug_exceptionate(&self) -> Arc; 35 | } 36 | 37 | /// The return code set when a task is killed via zx_task_kill(). 38 | pub const TASK_RETCODE_SYSCALL_KILL: i64 = -1028; 39 | -------------------------------------------------------------------------------- /zircon-object/src/task/suspend_token.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | crate::object::*, 4 | alloc::sync::{Arc, Weak}, 5 | }; 6 | 7 | /// Suspend the given task. 8 | /// 9 | /// Currently only thread or process handles may be suspended. 10 | /// 11 | /// # Example 12 | /// ``` 13 | /// # use std::sync::Arc; 14 | /// # use zircon_object::task::*; 15 | /// # use zircon_object::object::{KernelObject, Signal}; 16 | /// # kernel_hal::init(); 17 | /// let job = Job::root(); 18 | /// let proc = Process::create(&job, "proc").unwrap(); 19 | /// let thread = Thread::create(&proc, "thread").unwrap(); 20 | /// 21 | /// // start the thread and never terminate 22 | /// thread.start(|thread| Box::pin(async move { 23 | /// loop { async_std::task::yield_now().await } 24 | /// let _ = thread; 25 | /// })).unwrap(); 26 | /// 27 | /// // wait for the thread running 28 | /// let object: Arc = thread.clone(); 29 | /// async_std::task::block_on(object.wait_signal(Signal::THREAD_RUNNING)); 30 | /// assert_eq!(thread.state(), ThreadState::Running); 31 | /// 32 | /// // suspend the thread 33 | /// { 34 | /// let task: Arc = thread.clone(); 35 | /// let suspend_token = SuspendToken::create(&task); 36 | /// assert_eq!(thread.state(), ThreadState::Suspended); 37 | /// } 38 | /// // suspend token dropped, resume the thread 39 | /// assert_eq!(thread.state(), ThreadState::Running); 40 | /// ``` 41 | pub struct SuspendToken { 42 | base: KObjectBase, 43 | task: Weak, 44 | } 45 | 46 | impl_kobject!(SuspendToken); 47 | 48 | impl SuspendToken { 49 | /// Create a `SuspendToken` which can suspend the given task. 50 | pub fn create(task: &Arc) -> Arc { 51 | task.suspend(); 52 | Arc::new(SuspendToken { 53 | base: KObjectBase::new(), 54 | task: Arc::downgrade(task), 55 | }) 56 | } 57 | } 58 | 59 | impl Drop for SuspendToken { 60 | fn drop(&mut self) { 61 | if let Some(task) = self.task.upgrade() { 62 | task.resume(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /zircon-object/src/task/thread/thread_state.rs: -------------------------------------------------------------------------------- 1 | use crate::{ZxError, ZxResult}; 2 | use kernel_hal::context::UserContext; 3 | use numeric_enum_macro::numeric_enum; 4 | 5 | numeric_enum! { 6 | #[repr(u32)] 7 | /// Possible values for "kind" in zx_thread_read_state and zx_thread_write_state. 8 | #[allow(missing_docs)] 9 | #[derive(Debug, Copy, Clone)] 10 | pub enum ThreadStateKind { 11 | General = 0, 12 | FloatPoint = 1, 13 | Vector = 2, 14 | Debug = 4, 15 | SingleStep = 5, 16 | } 17 | } 18 | 19 | pub(super) trait ContextAccessState { 20 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult; 21 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult; 22 | } 23 | 24 | impl ContextAccessState for UserContext { 25 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult { 26 | match kind { 27 | ThreadStateKind::General => buf.write_struct(self.general()), 28 | _ => Err(ZxError::NOT_SUPPORTED), 29 | } 30 | } 31 | 32 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult { 33 | match kind { 34 | ThreadStateKind::General => *self.general_mut() = buf.read_struct()?, 35 | _ => return Err(ZxError::NOT_SUPPORTED), 36 | } 37 | Ok(()) 38 | } 39 | } 40 | 41 | trait BufExt { 42 | fn read_struct(&self) -> ZxResult; 43 | fn write_struct(&mut self, value: &T) -> ZxResult; 44 | } 45 | 46 | #[allow(unsafe_code)] 47 | impl BufExt for [u8] { 48 | fn read_struct(&self) -> ZxResult { 49 | if self.len() < core::mem::size_of::() { 50 | return Err(ZxError::BUFFER_TOO_SMALL); 51 | } 52 | Ok(unsafe { (self.as_ptr() as *const T).read() }) 53 | } 54 | 55 | fn write_struct(&mut self, value: &T) -> ZxResult { 56 | if self.len() < core::mem::size_of::() { 57 | return Err(ZxError::BUFFER_TOO_SMALL); 58 | } 59 | unsafe { 60 | *(self.as_mut_ptr() as *mut T) = *value; 61 | } 62 | Ok(core::mem::size_of::()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /zircon-object/src/util/block_range.rs: -------------------------------------------------------------------------------- 1 | /// Given a range and iterate sub-range for each block 2 | #[derive(Debug)] 3 | pub struct BlockIter { 4 | pub begin: usize, 5 | pub end: usize, 6 | pub block_size_log2: u8, 7 | } 8 | 9 | #[derive(Debug, Eq, PartialEq)] 10 | pub struct BlockRange { 11 | pub block: usize, 12 | pub begin: usize, 13 | pub end: usize, 14 | pub block_size_log2: u8, 15 | } 16 | 17 | impl BlockRange { 18 | pub fn len(&self) -> usize { 19 | self.end - self.begin 20 | } 21 | pub fn origin_begin(&self) -> usize { 22 | (self.block << self.block_size_log2) + self.begin 23 | } 24 | pub fn origin_end(&self) -> usize { 25 | (self.block << self.block_size_log2) + self.end 26 | } 27 | } 28 | 29 | impl Iterator for BlockIter { 30 | type Item = BlockRange; 31 | 32 | fn next(&mut self) -> Option<::Item> { 33 | if self.begin >= self.end { 34 | return None; 35 | } 36 | let block_size_log2 = self.block_size_log2; 37 | let block_size = 1usize << self.block_size_log2; 38 | let block = self.begin / block_size; 39 | let begin = self.begin % block_size; 40 | let end = if block == self.end / block_size { 41 | self.end % block_size 42 | } else { 43 | block_size 44 | }; 45 | self.begin += end - begin; 46 | Some(BlockRange { 47 | block, 48 | begin, 49 | end, 50 | block_size_log2, 51 | }) 52 | } 53 | } 54 | 55 | #[cfg(test)] 56 | mod test { 57 | use super::*; 58 | 59 | #[test] 60 | fn block_iter() { 61 | let mut iter = BlockIter { 62 | begin: 0x123, 63 | end: 0x2018, 64 | block_size_log2: 12, 65 | }; 66 | assert_eq!( 67 | iter.next(), 68 | Some(BlockRange { 69 | block: 0, 70 | begin: 0x123, 71 | end: 0x1000, 72 | block_size_log2: 12 73 | }) 74 | ); 75 | assert_eq!( 76 | iter.next(), 77 | Some(BlockRange { 78 | block: 1, 79 | begin: 0, 80 | end: 0x1000, 81 | block_size_log2: 12 82 | }) 83 | ); 84 | assert_eq!( 85 | iter.next(), 86 | Some(BlockRange { 87 | block: 2, 88 | begin: 0, 89 | end: 0x18, 90 | block_size_log2: 12 91 | }) 92 | ); 93 | assert_eq!(iter.next(), None); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /zircon-object/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | //! Utilities. 2 | pub(crate) mod block_range; 3 | #[cfg(feature = "elf")] 4 | pub mod elf_loader; 5 | pub mod kcounter; 6 | -------------------------------------------------------------------------------- /zircon-syscall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-syscall" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Zircon syscalls implementation" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [features] 11 | # hypervisor = ["zircon-object/hypervisor"] 12 | deny-page-fault = [] 13 | 14 | [dependencies] 15 | log = "0.4" 16 | bitflags = "1.3" 17 | numeric-enum-macro = "0.2" 18 | zircon-object = { path = "../zircon-object" } 19 | kernel-hal = { path = "../kernel-hal", default-features = false } 20 | futures = { version = "0.3", default-features = false, features = [ 21 | "alloc", 22 | "async-await", 23 | ] } 24 | cfg-if = "1.0" 25 | lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "8486b8" } 26 | -------------------------------------------------------------------------------- /zircon-syscall/build.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | fn main() { 4 | println!("cargo:rerun-if-changed=src/zx-syscall-numbers.h"); 5 | 6 | let mut fout = std::fs::File::create("src/consts.rs").unwrap(); 7 | writeln!(fout, "// Generated by build.rs. DO NOT EDIT.").unwrap(); 8 | writeln!(fout, "use numeric_enum_macro::numeric_enum;\n").unwrap(); 9 | writeln!(fout, "numeric_enum! {{").unwrap(); 10 | writeln!(fout, "#[repr(u32)]").unwrap(); 11 | writeln!(fout, "#[derive(Debug, Eq, PartialEq)]").unwrap(); 12 | writeln!(fout, "#[allow(non_camel_case_types)]").unwrap(); 13 | writeln!(fout, "#[allow(clippy::upper_case_acronyms)]").unwrap(); 14 | writeln!(fout, "pub enum SyscallType {{").unwrap(); 15 | 16 | let data = std::fs::read_to_string("src/zx-syscall-numbers.h").unwrap(); 17 | for line in data.lines() { 18 | if !line.starts_with("#define") { 19 | continue; 20 | } 21 | let mut iter = line.split(' '); 22 | let _ = iter.next().unwrap(); 23 | let name = iter.next().unwrap(); 24 | let id = iter.next().unwrap(); 25 | 26 | let name = &name[7..].to_uppercase(); 27 | writeln!(fout, " {} = {},", name, id).unwrap(); 28 | } 29 | writeln!(fout, "}}").unwrap(); 30 | writeln!(fout, "}}").unwrap(); 31 | } 32 | -------------------------------------------------------------------------------- /zircon-syscall/src/cprng.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl Syscall<'_> { 4 | /// Draw random bytes from the kernel CPRNG. 5 | /// 6 | /// This data should be suitable for cryptographic applications. 7 | /// 8 | /// Clients that require a large volume of randomness should consider using these bytes to seed a user-space random number generator for better performance. 9 | pub fn sys_cprng_draw_once(&self, mut buf: UserOutPtr, len: usize) -> ZxResult { 10 | info!("cprng_draw_once: buf=({:?}; {:?})", buf, len); 11 | let mut res = vec![0u8; len]; 12 | // Fill random bytes to the buffer 13 | kernel_hal::rand::fill_random(&mut res); 14 | buf.write_array(&res)?; 15 | Ok(()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /zircon-syscall/src/debug.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use zircon_object::dev::*; 3 | 4 | impl Syscall<'_> { 5 | /// Write debug info to the serial port. 6 | pub fn sys_debug_write(&self, buf: UserInPtr, len: usize) -> ZxResult { 7 | info!("debug.write: buf=({:?}; {:#x})", buf, len); 8 | kernel_hal::console::console_write_str(buf.as_str(len)?); 9 | Ok(()) 10 | } 11 | 12 | /// Read debug info from the serial port. 13 | pub async fn sys_debug_read( 14 | &self, 15 | handle: HandleValue, 16 | mut buf: UserOutPtr, 17 | buf_size: u32, 18 | mut actual: UserOutPtr, 19 | ) -> ZxResult { 20 | info!( 21 | "debug.read: handle={:#x}, buf=({:?}; {:#x})", 22 | handle, buf, buf_size 23 | ); 24 | let proc = self.thread.proc(); 25 | proc.get_object::(handle)? 26 | .validate(ResourceKind::ROOT)?; 27 | let mut vec = vec![0u8; buf_size as usize]; 28 | let len = kernel_hal::console::console_read(&mut vec).await; 29 | buf.write_array(&vec[..len])?; 30 | actual.write(len as u32)?; 31 | Ok(()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /zircon-syscall/src/port.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | zircon_object::{signal::*, task::*}, 4 | }; 5 | 6 | impl Syscall<'_> { 7 | /// Create an IO port. 8 | pub fn sys_port_create(&self, options: u32, mut out: UserOutPtr) -> ZxResult { 9 | info!("port.create: options={:#x}", options); 10 | let port_handle = Handle::new(Port::new(options)?, Rights::DEFAULT_PORT); 11 | let handle_value = self.thread.proc().add_handle(port_handle); 12 | out.write(handle_value)?; 13 | Ok(()) 14 | } 15 | 16 | /// Wait for a packet arrival in a port. 17 | pub async fn sys_port_wait( 18 | &self, 19 | handle_value: HandleValue, 20 | deadline: Deadline, 21 | mut packet_res: UserOutPtr, 22 | ) -> ZxResult { 23 | info!( 24 | "port.wait: handle={}, deadline={:?}", 25 | handle_value, deadline 26 | ); 27 | assert_eq!(core::mem::size_of::(), 48); 28 | let proc = self.thread.proc(); 29 | let port = proc.get_object_with_rights::(handle_value, Rights::READ)?; 30 | let future = port.wait(); 31 | pin_mut!(future); 32 | let packet = self 33 | .thread 34 | .blocking_run(future, ThreadState::BlockedPort, deadline.into(), None) 35 | .await?; 36 | packet_res.write(packet)?; 37 | Ok(()) 38 | } 39 | 40 | /// Queue a packet to a port. 41 | pub fn sys_port_queue( 42 | &self, 43 | handle_value: HandleValue, 44 | packcet_in: UserInPtr, 45 | ) -> ZxResult { 46 | let proc = self.thread.proc(); 47 | let port = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; 48 | let packet = packcet_in.read()?; 49 | info!( 50 | "port.queue: handle={:#x}, packet={:?}", 51 | handle_value, packet 52 | ); 53 | port.push_user(packet)?; 54 | Ok(()) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /zircon-syscall/src/resource.rs: -------------------------------------------------------------------------------- 1 | use {super::*, core::convert::TryFrom, zircon_object::dev::*}; 2 | 3 | impl Syscall<'_> { 4 | #[allow(clippy::too_many_arguments)] 5 | /// Create a resource object for use with other DDK syscalls. 6 | pub fn sys_resource_create( 7 | &self, 8 | parent_rsrc: HandleValue, 9 | options: u32, 10 | base: u64, 11 | size: u64, 12 | name: UserInPtr, 13 | name_size: u64, 14 | mut out: UserOutPtr, 15 | ) -> ZxResult { 16 | info!( 17 | "resource.create: parent={:#x}, options={:#x}, base={:#X}, size={:#x}", 18 | parent_rsrc, options, base, size 19 | ); 20 | let name = name.as_str(name_size as usize)?; 21 | info!("name={:?}", name); 22 | let proc = self.thread.proc(); 23 | let parent_rsrc = proc.get_object_with_rights::(parent_rsrc, Rights::WRITE)?; 24 | let kind = ResourceKind::try_from(options & 0xFFFF).map_err(|_| ZxError::INVALID_ARGS)?; 25 | let flags = ResourceFlags::from_bits(options & 0xFFFF_0000).ok_or(ZxError::INVALID_ARGS)?; 26 | parent_rsrc.validate_ranged_resource(kind, base as usize, size as usize)?; 27 | parent_rsrc.check_exclusive(flags)?; 28 | let rsrc = Resource::create(name, kind, base as usize, size as usize, flags); 29 | let handle = proc.add_handle(Handle::new(rsrc, Rights::DEFAULT_RESOURCE)); 30 | out.write(handle)?; 31 | Ok(()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /zircon-syscall/src/system.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use zircon_object::{signal::Event, task::Job}; 3 | 4 | impl Syscall<'_> { 5 | /// Retrieve a handle to a system event. 6 | /// 7 | /// `root_job: HandleValue`, must be a handle to the root job of the system. 8 | /// `kind: u32`, must be one of the following: 9 | /// ```rust 10 | /// const EVENT_OUT_OF_MEMORY: u32 = 1; 11 | /// const EVENT_MEMORY_PRESSURE_CRITICAL: u32 = 2; 12 | /// const EVENT_MEMORY_PRESSURE_WARNING: u32 = 3; 13 | /// const EVENT_MEMORY_PRESSURE_NORMAL: u32 = 4; 14 | /// ``` 15 | pub fn sys_system_get_event( 16 | &self, 17 | root_job: HandleValue, 18 | kind: u32, 19 | mut out: UserOutPtr, 20 | ) -> ZxResult { 21 | info!( 22 | "system.get_event: root_job={:#x}, kind={:#x}, out_ptr={:#x?}", 23 | root_job, kind, out 24 | ); 25 | match kind { 26 | EVENT_OUT_OF_MEMORY => { 27 | let proc = self.thread.proc(); 28 | proc.get_object_with_rights::(root_job, Rights::MANAGE_PROCESS)? 29 | .check_root_job()?; 30 | // TODO: out-of-memory event 31 | let event = Event::new(); 32 | let event_handle = proc.add_handle(Handle::new(event, Rights::DEFAULT_EVENT)); 33 | out.write(event_handle)?; 34 | Ok(()) 35 | } 36 | _ => unimplemented!(), 37 | } 38 | } 39 | } 40 | 41 | const EVENT_OUT_OF_MEMORY: u32 = 1; 42 | const _EVENT_MEMORY_PRESSURE_CRITICAL: u32 = 2; 43 | const _EVENT_MEMORY_PRESSURE_WARNING: u32 = 3; 44 | const _EVENT_MEMORY_PRESSURE_NORMAL: u32 = 4; 45 | -------------------------------------------------------------------------------- /zircon-user/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "x86_64-fuchsia" 3 | 4 | [target.x86_64-fuchsia] 5 | rustflags = [ 6 | "-L", "../prebuilt/zircon/x64", 7 | ] 8 | -------------------------------------------------------------------------------- /zircon-user/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "zircon-user" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /zircon-user/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-user" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /zircon-user/Makefile: -------------------------------------------------------------------------------- 1 | MODE ?= debug 2 | 3 | zbi_in := ../prebuilt/zircon/x64/bringup.zbi 4 | zbi_out := target/zcore-user.zbi 5 | build_dir := target/x86_64-fuchsia/$(MODE) 6 | bootfs := $(build_dir)/bootfs 7 | bins := $(patsubst src/bin/%.rs, $(bootfs)/bin/%, $(wildcard src/bin/*.rs)) 8 | 9 | ifeq ($(MODE), release) 10 | build_args += --release 11 | endif 12 | 13 | ifeq ($(shell uname), Darwin) 14 | zbi_cli := ../prebuilt/zircon/x64/zbi-macos 15 | else 16 | zbi_cli := ../prebuilt/zircon/x64/zbi-linux 17 | endif 18 | 19 | .PHONY: zbi 20 | 21 | all: zbi 22 | 23 | zbi: $(zbi_out) 24 | 25 | build: 26 | cargo build $(build_args) 27 | 28 | $(bootfs)/bin/%: $(build_dir)/% 29 | mkdir -p $(bootfs)/bin 30 | cp $^ $@ 31 | 32 | $(zbi_out): build $(bins) 33 | $(zbi_cli) $(zbi_in) $(bootfs) -o $@ 34 | -------------------------------------------------------------------------------- /zircon-user/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-01-20" 3 | targets = ["x86_64-fuchsia"] 4 | -------------------------------------------------------------------------------- /zircon-user/src/bin/hello.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, zCore!"); 3 | } 4 | --------------------------------------------------------------------------------