Compare commits

..

258 Commits

Author SHA1 Message Date
Luoyuan Xiao d74dfad991
Merge pull request #302 from elliott10/master
Enable PCI scan and e1000 driver in RISCV
2022-05-30 16:29:30 +08:00
Luoyuan Xiao b9e13aaab1 Merge remote-tracking branch 'remotes/origin/master' 2022-05-30 16:28:39 +08:00
shzhxh 6d951829b6 According to the result of CI test, change the status of some testcases from OK to PARTIAL 2022-05-30 16:19:19 +08:00
Luoyuan Xiao 6ab43eb9d8 To meet test CI conditions 2022-05-27 14:21:33 +08:00
Luoyuan Xiao 0f1ea71bfb Enable PCI scan in RISCV and x86_64
Get e1000e network driver to work in RISCV
Test net testcases
2022-05-27 13:33:14 +08:00
Luoyuan Xiao 3daccb7e42 Merge remote-tracking branch 'remotes/origin/master' 2022-05-26 17:53:58 +08:00
Luoyuan Xiao 00b10bd880 Update tests subdir
Fixed to pass cargo clippy
2022-05-26 16:31:09 +08:00
Luoyuan Xiao 42eb5c0708
Merge pull request #301 from YdrMaster/main
适用于 libos 的 musl libc so 不再依赖 git lfs
2022-05-21 15:18:02 +08:00
YdrMaster 0aa57d8021 fix: 提前退出 2022-05-21 13:35:24 +08:00
YdrMaster b67cbc2398 feat(ci): 重新打开依赖 lfs 的测例 2022-05-21 12:47:42 +08:00
YdrMaster 302ecf1990 feat(ci): 适用于 libos 的 musl libc so 不再依赖 git lfs 2022-05-21 12:27:40 +08:00
Luoyuan Xiao 0e984e9777
Merge pull request #285 from DeathWish5/master
Singal bug fix and Executor update
2022-05-21 10:20:40 +08:00
DeathWish5 6ef8dc7a59 Merge branch 'master' of github.com:rcore-os/zCore 2022-05-20 20:46:29 +08:00
DeathWish5 f1ffe1d60e cargo fmt and clippy 2022-05-20 20:45:35 +08:00
DeathWish5 bba9878981 bug fix: some signal testcases may fail 2022-05-20 19:54:33 +08:00
Luoyuan Xiao 19f5cf712f Add e1000 driver, and some test cases
Modify smoltcp reference link
2022-05-20 14:33:30 +08:00
workerwork 6b30fe8b40 fix: github ci 2022-05-19 15:21:26 +08:00
workerwork 3b9b255ec9 fix: github ci 2022-05-19 15:21:26 +08:00
workerwork 181b577cae refactor: github ci 2022-05-19 15:21:26 +08:00
DeathWish5 e41bf17a84 feat: add init of x86 apic timer 2022-05-18 23:24:38 +08:00
DeathWish5 c3ab0d38c4 bug fix: unknown syscall may happened. log: add some debug log 2022-05-18 17:13:13 +08:00
DeathWish5 19bc2b7991 Merge branch 'master' of github.com:rcore-os/zCore 2022-05-17 13:40:55 +08:00
Luoyuan Xiao 13fb9eebbc
Merge pull request #296 from YdrMaster/main
增加基于 xtask 的调试操作
2022-05-16 09:48:53 +08:00
YdrMaster 4dd51126b6 fix(driver): 跳过不支持的中断号,不要退出 2022-05-15 19:28:30 +08:00
YdrMaster 939b6395c5 refactor(drivers): 使用重构的设备树解析 2022-05-15 18:54:50 +08:00
YdrMaster f542b3cc6f fix(xtask): 适应 riscv64
让 xtask 不要影响 rust-analyzer 在 riscv64 target 下的扫描
2022-05-14 20:08:24 +08:00
YdrMaster 1e74f6a988 style 2022-05-14 08:53:07 +08:00
YdrMaster 794c807e34 feat(xtask): 增加 riscv64 gdb 2022-05-13 18:50:30 +08:00
YdrMaster 6f4dfd7273 fix(xtask): rename 无法跨 mount 文件系统 2022-05-13 16:59:25 +08:00
YdrMaster e1de630c4f feat(xtask): 增加 asm 命令,将内核反汇编输出到文件 2022-05-13 14:57:02 +08:00
YdrMaster 6749cd5179 refactor(xtask): 选择架构改用参数 2022-05-13 13:34:25 +08:00
YdrMaster 3fcc1f42f3 feat(xtask): 下载 rustsbi 2022-05-12 22:06:55 +08:00
Ydr 3b706cf262
Merge branch 'rcore-os:master' into main 2022-05-12 22:04:27 +08:00
YdrMaster 9d8316b9b6 feat(xtask): 从顶层启动 qemu 2022-05-12 19:43:45 +08:00
Ydr f2aaa8d8f6
Merge pull request #294 from YdrMaster/main
修复 d1 的启动问题
2022-05-12 18:46:10 +08:00
Zhenxing 134a31f0c3
Merge pull request #293 from elliott10/master
To accommodate large user programs
2022-05-12 17:32:42 +08:00
YdrMaster 3d0186d95e feat(xtask): cargo check-style 现在和 CI/build 一致 2022-05-12 17:01:37 +08:00
YdrMaster ebd4de4682 style 2022-05-12 16:56:55 +08:00
Luoyuan Xiao 9490e5d7a8 To accommodate large user programs
increased user stack, kernel stack and heap
2022-05-12 16:35:35 +08:00
YdrMaster b6bca47e94 fix(d1): 修复在 d1 无法启动的问题 2022-05-12 15:10:53 +08:00
Luoyuan Xiao 0f658c8158
Merge pull request #292 from YdrMaster/main
完善 xtask
2022-05-12 14:19:22 +08:00
YdrMaster 72c2191039 feat(xtask): 为常用 busybox 子命令建立符号链接 2022-05-11 19:26:23 +08:00
YdrMaster 6ba9602e8f feat(xtask): 重构 rootfs -> image 过程 2022-05-11 19:08:25 +08:00
YdrMaster 7de17ef115 temp 2022-05-11 13:57:59 +08:00
YdrMaster 922312a430 cleanup 2022-05-11 11:37:49 +08:00
YdrMaster fa155fe95b fix: 修正 libos 找 rootfs 的方式 2022-05-11 11:18:45 +08:00
YdrMaster e70eecb5ba refactor(xtask): miniroofs.tar.* 撤离 prebuilt 目录 2022-05-11 10:24:09 +08:00
YdrMaster 64bf09c596 fix(xtask): 下载时创建父目录 2022-05-11 09:51:56 +08:00
Ydr 9f991c6b4c
Merge branch 'rcore-os:master' into main 2022-05-11 09:37:34 +08:00
YdrMaster b8f66237d7 feat(xtask): 统一 rootfs 存放,libc-test 成为子模块 2022-05-11 09:36:50 +08:00
Luoyuan Xiao 359066bd89
Merge pull request #291 from shzhxh/master-merge
update module: tests , change status of some testcases.
2022-05-10 19:48:31 +08:00
Luoyuan Xiao 0fd2263a46
Merge pull request #290 from YdrMaster/main
完善 xtask
2022-05-10 19:48:17 +08:00
YdrMaster 35306f14c1 fix: rust-cache 不好用,放弃,准备缓存 lfs 2022-05-10 19:13:47 +08:00
YdrMaster 55cc6438f7 fix: 改正 git lfs 用法,只下载必要的文件
todo:lfs 内置于 xtask,用什么拉什么
2022-05-10 18:53:31 +08:00
YdrMaster 0b6aa1f958 cleanup 2022-05-10 18:31:43 +08:00
YdrMaster c55c72de43 feat(xtask): 直接内联编译 fs-fuse 功能,不必再安装应用程序 2022-05-10 18:22:51 +08:00
YdrMaster 05bd6b0943 feat(xtask): 封装 make 和 tar 2022-05-10 16:57:08 +08:00
YdrMaster 3434c151a7 feat(xtask): 先 git clone 到随机临时位置 2022-05-10 16:29:42 +08:00
YdrMaster cfb86710f4 feat(xtask): 命令自动构造错误信息 2022-05-10 15:31:03 +08:00
shzhxh 26912df809 update module: tests .
change status of some testcases.
2022-05-10 14:56:08 +08:00
YdrMaster 74f7a23bd6 build: update deps 2022-05-10 14:07:40 +08:00
YdrMaster e4c1b8a397 feat: 封装 git cargo 命令 2022-05-10 13:20:56 +08:00
YdrMaster 207449af67 feat(xtask): 下载文件先放到临时位置
feat(xtask): libc-test 和 image 递归 rootfs

docs: 增加说明文档
2022-05-09 20:16:07 +08:00
DeathWish5 e3fa672f59 merge master 2022-05-09 16:14:36 +08:00
Zhenxing 8b36294ffe
Merge pull request #288 from YdrMaster/dev-ci
优化 CI

    增加 rust cache 缓存依赖项
    将多个架构的 QEMU 一起缓存以节约总缓存占用
    Build 测试集矩阵化
    clippy 可复用 build 的结果,build 后立即 clippy 以节约时间
2022-05-09 08:26:40 +08:00
Ydr 77ff4eafeb
Merge branch 'rcore-os:master' into main 2022-05-08 22:20:35 +08:00
Luoyuan Xiao 803bbd9962
Merge pull request #287 from YdrMaster/dev-xtask
增加 xtask 模块
2022-05-08 22:12:46 +08:00
YdrMaster cf4629ec9d ci(test): cache qemu dir 2022-05-08 22:02:22 +08:00
YdrMaster 0afb263958 ci(build): use matrix 2022-05-08 18:35:54 +08:00
YdrMaster ce199ad9a7 ci: test matrix 2022-05-08 17:33:51 +08:00
YdrMaster 04ab8a380b build: 统一 make 参数形式 2022-05-08 16:47:19 +08:00
YdrMaster f4d395500d ci(build): rust-cache 2022-05-08 10:48:53 +08:00
YdrMaster 8947cecf3c ci(test): cache all qemu in one tar 2022-05-08 10:42:16 +08:00
YdrMaster 231f1a1266 ci(test): toolchain & rust-cache 2022-05-08 10:06:22 +08:00
YdrMaster eeb318cc9a ci: update checkout@v3 2022-05-06 18:06:15 +08:00
YdrMaster 7c9abada74 fix(ci): make 2022-05-06 17:28:28 +08:00
YdrMaster 261344d381 ci: cache compiled qemu 2022-05-06 17:03:33 +08:00
YdrMaster fee725d5f9 try: 降低 alphine 版本看 remquol 现象 2022-05-06 13:10:55 +08:00
YdrMaster 6e29f418f9 docs(xtask): 更新 README.md 2022-05-06 12:49:53 +08:00
YdrMaster bb7604c434 feat: 整合 image 2022-05-06 11:50:24 +08:00
YdrMaster 2f7685f23a feat: 整合 libc-test 2022-05-06 11:03:34 +08:00
YdrMaster 9f878044c9 feat: 分解 riscv-image,与 x86_64 实现流程一致 2022-05-06 08:52:14 +08:00
YdrMaster d9531cec75 try: 整合 libc-test 2022-05-06 07:12:18 +08:00
YdrMaster c72952df94 try: 合并 收缩 2022-05-05 22:13:05 +08:00
YdrMaster 5d93a4dbee try: 合并 Makefile 任务 2022-05-05 18:04:52 +08:00
Ydr c309b03d08
Merge branch 'rcore-os:master' into dev-xtask 2022-05-05 17:49:32 +08:00
Luoyuan Xiao f5efe3b8c4
Merge pull request #284 from YdrMaster/dev-boot-riscv
完全移除 riscv 启动流程部分的汇编文件
2022-05-05 17:29:28 +08:00
YdrMaster 6fb1f20f97 feat: image x86_64 前半部分 2022-05-05 17:26:40 +08:00
YdrMaster c307eb8620 feat: clone libc-test 2022-05-05 15:17:10 +08:00
YdrMaster 42f2f0affb fix: set ARCH env 2022-05-05 12:48:03 +08:00
YdrMaster 0af4593e45 try: modify Makefile 2022-05-05 12:10:10 +08:00
YdrMaster e239d7ceb5 feat: 支持修改全局 git 代理 2022-05-05 11:06:51 +08:00
YdrMaster 1688fd9651 Revert "try: 修改 Makefile"
This reverts commit e67a7301e3.
2022-05-05 11:05:52 +08:00
YdrMaster e67a7301e3 try: 修改 Makefile 2022-05-04 13:21:06 +08:00
YdrMaster ef6c6adf37 docs(xtask):
- 为一些工具函数增加文档
- 增加项目愿景和日志
2022-05-04 11:37:41 +08:00
YdrMaster cfca262b55 feat: 增加下载交叉编译工具 2022-05-04 02:29:51 +08:00
DeathWish5 ca19f4fa8f minor update: update git commit of 2022-05-03 15:41:05 +08:00
DeathWish5 33f9ec9333 minor update. Makefile: typo in debugrun. .gdbinit: start from jump_higher 2022-05-03 15:35:42 +08:00
YdrMaster 51af7f4ed1 feat: 完成 riscv-rootfs 2022-05-02 22:48:51 +08:00
YdrMaster 4e3b53469c feat: 实现安装 rcore-fs-fuse、下载 prebuilt 2022-05-02 19:44:47 +08:00
YdrMaster 5af92cb723 fix: Build CI 2022-05-02 18:17:26 +08:00
YdrMaster ecea18fe1f build: try xtask 2022-05-02 16:02:09 +08:00
YdrMaster 909765bfb2 build: 移除 boot 文件夹 2022-05-02 04:06:55 +08:00
YdrMaster 2ea758a810 feat: 从设备树解析 smp 2022-05-01 14:34:31 +08:00
YdrMaster b3b113bc00 refactor(zCore): 为内核支持 2021 风格的 print 2022-04-30 20:08:25 +08:00
YdrMaster 4f6e3b2a50 refactor: 启动页表定义分离到独立的文件 2022-04-29 12:52:40 +08:00
YdrMaster 0181726f14 refactor: 依赖 r0 库清零 bss 2022-04-29 11:53:31 +08:00
YdrMaster aa86a412cd refactor: 利用链接脚本传递全局符号,移除 global_asm 2022-04-29 10:45:46 +08:00
YdrMaster 1efacbffc9 refactor: naked_function
利用 naked_fuction 内联汇编,减少全局符号表内容,并移除独立的汇编文件
2022-04-29 09:58:04 +08:00
Luoyuan Xiao 4711359b38
Merge pull request #283 from DeathWish5/master
Bug fix: multi-core boot will dead-lock in qemu
2022-04-28 12:19:45 +08:00
DeathWish5 fdd852abfc comment: minor update 2022-04-27 17:10:53 +08:00
DeathWish5 42d7540439 buf fix: net::init() should not be called in secondary_init 2022-04-25 22:44:34 +08:00
Zhenxing 9bad3e20d2
Merge pull request #282 from shzhxh/master-merge
update submodule : tests, some bugs of pthread are fixed
2022-04-25 16:18:09 +08:00
shzhxh 84b4143d45 update submodule : tests. some bugs of pthread are fixed. 2022-04-25 09:07:17 +08:00
Luoyuan Xiao 5741f12e5f
Merge pull request #280 from YdrMaster/dev-boot-riscv
整理 riscv 启动逻辑,并为汇编增加注释
2022-04-22 17:00:12 +08:00
YdrMaster 010f316a22 refactor(zCore): riscv 各开发板兼容 2022-04-22 04:54:59 +08:00
YdrMaster fde18af386 refactor(zCore): 启动过程完全 rust 化
todo: 适配 d1
2022-04-22 00:29:52 +08:00
Ydr e9b863b59d
Merge branch 'rcore-os:master' into dev-boot-riscv 2022-04-21 17:16:44 +08:00
Luoyuan Xiao 3544db899f
Merge pull request #279 from OSLab-zCore/master
Update pthread implementation
2022-04-21 16:03:28 +08:00
YdrMaster b1c89d7cfe perf(zCore): 优化启动栈设置操作 2022-04-21 05:03:19 +08:00
YdrMaster 0fc50e5996 build: 修改一些配置文件 2022-04-21 04:46:25 +08:00
Zichun Yu 0b390fd825 Remove 91chi.fun 2022-04-20 13:59:52 +08:00
YdrMaster e78ead64ee Merge branch 'rcore-os-master' into dev-boot-riscv 2022-04-20 11:17:11 +08:00
YdrMaster c59d6aa88c Merge branch 'master' of https://github.com/rcore-os/zCore into rcore-os-master 2022-04-20 11:16:01 +08:00
YdrMaster 1750123a36 docs(zCore): 补全 riscv 启动过程注释 2022-04-20 09:41:43 +08:00
YdrMaster 0a4f6dbf38 refactor(zCore): 整理 riscv 启动流程 2022-04-20 04:53:04 +08:00
Zichun Yu b51c8ebea3 Merge lsm-yzc-merge 2022-04-19 23:10:34 +08:00
Zichun Yu 3734039a5e Merge branch 'lsm-yzc-merge' of github.com:OSLab-zCore/zCore into lsm-yzc-merge 2022-04-19 21:16:12 +08:00
Zichun Yu 55299ff1da Update tests commit 2022-04-19 21:15:57 +08:00
Yiren Zhang b1eb0c8d64
Merge pull request #277 from DeathWish5/zcore-thread-and-lock
Update `executor` and `lock` to enable kernel interrupt and thread based scheduling.
2022-04-19 20:26:26 +08:00
DeathWish5 b700eec2d6 delete unused code, format some code 2022-04-19 19:37:54 +08:00
liusm18 d2bc0b5fb7 Fix align issues in riscv 2022-04-19 17:34:35 +08:00
Zichun Yu b052a9666b Update tests commit 2022-04-19 15:42:34 +08:00
Zichun Yu 8497aeea23 Merge master 2022-04-19 15:40:12 +08:00
Zichun Yu 4746413d3a Update tests commit 2022-04-19 11:12:14 +08:00
DeathWish5 565abc371d merge master 2022-04-18 15:29:29 +08:00
liusm18 b3efbcfe09 Fix a coding style issue: add safety docs for unsafe function 2022-04-17 12:04:17 +08:00
liusm18 59c6de2d74 Fix a code format 2022-04-17 11:53:10 +08:00
liusm18 a191f57ff3 Fix some codeing style issues 2022-04-17 11:43:01 +08:00
Zichun Yu 296766831a Add UserInPtr in thread.rs 2022-04-16 12:29:14 +08:00
Zichun Yu e3066c23ae Change format in thread.rs 2022-04-16 11:56:59 +08:00
Zichun Yu 08ab919633 Reset tests commit 2022-04-16 11:44:18 +08:00
Zichun Yu 7a35b4fd5c Fix test.yml --no-failed 2022-04-16 11:38:56 +08:00
Zichun Yu 4d346d263e Fix conflicts 2022-04-16 11:19:54 +08:00
Zichun Yu dd3f2790e9 Update pthread tests 2022-04-15 20:16:06 +08:00
Zichun Yu 5d3c254f47 Fix conflicts 2022-04-15 19:22:13 +08:00
Zichun Yu 4028d6cb1a Fix conflicts 2022-04-15 19:18:39 +08:00
liusm18 c1e5bc0897 Fix align issues 2022-04-15 19:12:04 +08:00
liusm18 cd0f4ee40d Add tips for hard code path 2022-04-15 18:18:55 +08:00
liusm18 028ecea082 Add x86_64 support 2022-04-15 18:15:14 +08:00
Zichun Yu 7b7911a2dc Fix Makefile LINUX 2022-04-15 17:08:19 +08:00
DeathWish5 980ccb164c delete some unused debug code 2022-04-13 23:23:00 +08:00
Zichun Yu 7eff7cf67b Fix for CI 2022-04-13 21:30:14 +08:00
DeathWish5 0d1da32724 cargo fmt and clippy 2022-04-13 19:59:55 +08:00
Zichun Yu 2cb5d05b9a Fix for CI 2022-04-13 19:52:40 +08:00
Zichun Yu 2cb5cae22b Fix for CI 2022-04-13 19:42:42 +08:00
Zichun Yu 861bac0498 Fix for CI 2022-04-13 19:31:29 +08:00
Zichun Yu 7deff3e73b Fix for CI 2022-04-13 17:32:41 +08:00
DeathWish5 0a28678a9f switch future when TimerInt happend in user mode, switch executor when TiemrInt happened in kernel mode 2022-04-13 16:58:52 +08:00
Zhenxing 5389c418fa
Merge pull request #275 from shzhxh/master-merge
Some update of CI test
1. Create a new set of testcases called linux-other-test, to contain non-libc testcases.
2. Change linux-libc-test-riscv64 from prebuild binary to cross compiling.
2022-04-13 10:53:35 +08:00
DeathWish5 16206b1a52 merge master 2022-04-12 22:56:29 +08:00
DeathWish5 d585b87b09 add .gdbinit for debugrun 2022-04-12 20:42:54 +08:00
shzhxh dbbde19546 change testcase libc-test-riscv64 from prebuilt to cross-compile 2022-04-12 17:48:16 +08:00
shzhxh 689a43fc30 update submodule : tests, to separate non-libc testcases from libc testcases 2022-04-12 17:23:28 +08:00
Zichun Yu de77f11988 Remove hard codes & Fix warn 2022-04-11 19:15:21 +08:00
liusm18 3b8eaa17be Remove hard codes in handle_signal() 2022-04-11 14:32:13 +08:00
Luoyuan Xiao d8e4efad25
Merge pull request #274 from YdrMaster/dev-io
refactor(drivers): 修改 device io
2022-04-11 12:35:38 +08:00
liusm18 008175ce2b Remove some useless comments 2022-04-11 11:10:39 +08:00
liusm18 fa16615683 Remove some hard codes for sys_kill tkill tgkill 2022-04-11 10:35:54 +08:00
YdrMaster 99f21ba488 refactor(drivers): 修改 io
- 根据 wikipedia,pio 改名 pmio
- 为 mmio 读写增加内存屏障
- 为 io 补充文档
2022-04-09 23:14:45 +08:00
DeathWish5 41a0ce76d2 update tests 2022-04-09 21:47:34 +08:00
DeathWish5 3e165fe444 update lock of buddy_system_allocator 2022-04-09 15:59:54 +08:00
Zichun Yu 2888c273b2 Polish code 2022-04-09 10:04:29 +08:00
DeathWish5 a266160212 implement intrrupt for kernel_hal::libos 2022-04-06 23:13:29 +08:00
DeathWish5 8b6f0c0e00 remove kernel-sync feature 2022-04-06 17:23:51 +08:00
DeathWish5 9156ebc6dd bug fix: x86_64 rsp aliged error 2022-04-06 16:41:58 +08:00
Zichun Yu 3c1e8f66a3 Fix conflicts 2022-04-05 20:32:45 +08:00
liusm18 9caed02182 Implement signals 2022-04-05 07:44:57 +08:00
Zichun Yu 767e9dd745 Fix pthread_cond & pthread_tsd & ... 2022-04-04 19:30:52 +08:00
DeathWish5 d6687d9a65 bug fix: pthread_mutex page fault 2022-04-03 18:38:55 +08:00
Zichun Yu 65eec60ac6 Try to fix mutex and robust (still have bugs) 2022-04-03 00:04:48 +08:00
liusm18 a55017a967 Implement sys_tgkill 2022-04-01 10:54:06 +08:00
Luoyuan Xiao fcc46ebfc5
Merge pull request #253 from rcore-os/mergeBranch
Update some socket function about file
2022-03-31 22:19:45 +08:00
Luoyuan Xiao 06579b597f
Makefile configure the socket test
Makefile configure the socket test
2022-03-31 20:07:50 +08:00
Luoyuan Xiao cc9e06fc16 Check build errors
Fix warning: Linking two modules of different data layouts
2022-03-31 19:38:16 +08:00
liusm18 9961dba5e2 Implement tkill syscall 2022-03-31 17:27:59 +08:00
Luoyuan Xiao 6e1cc2297d
Merge branch 'master' into mergeBranch 2022-03-31 15:56:30 +08:00
Zhenxing 8cc8898de2
Merge pull request #272 from shzhxh/master-merge
change the url of libc-test, in order to fix some compile error.
2022-03-31 15:27:13 +08:00
shzhxh 25a389f06a change the url of libc-test, in order to fix some compile error.
update submodule : tests, change status of some testcases.
2022-03-31 11:24:52 +08:00
Luoyuan Xiao 9358545f1e
Merge pull request #255 from elliott10/master
Supporting PCI devices scanning based on rCore and Fix build error
2022-03-31 10:49:56 +08:00
elliott10 98a85ae9cb Fix riscv64 build error
error: instruction requires the following: M (Integer Multiplication and Division)
    mul t0, t0, a0
    ^
Check Code
2022-03-30 18:13:55 +08:00
elliott10 3f3d5e2acc Merge branch 'm' 2022-03-30 17:37:21 +08:00
Luoyuan Xiao b32d71b71c
Merge pull request #271 from YdrMaster/dev-uart
TimeSpec & uart device file
2022-03-29 21:24:16 +08:00
YdrMaster a6e227aa1f feat(drivers): 为 x86_64 支持开启第二个串口并映射到宿主系统临时文件,方便测试 2022-03-29 16:51:19 +08:00
Ydr 4cddebe2be
Merge pull request #1 from YdrMaster/dev-uart
Merge
2022-03-29 13:43:59 +08:00
Ydr 91a23d3f09
Merge branch 'rcore-os:master' into dev-uart 2022-03-29 13:33:35 +08:00
Luoyuan Xiao 69587e8049
Merge pull request #269 from YdrMaster/dev-user-ptr
refactor(kernel-hal): 尽量减少对通过 `UserPtr` 传入的参数的拷贝
2022-03-29 13:33:31 +08:00
YdrMaster 297a95d0d4 feat: 实现串口设备伪文件及其挂载 2022-03-29 12:24:33 +08:00
YdrMaster 0d5602bca0 build: 依赖新版本的 `rcore-fs` 2022-03-29 12:24:33 +08:00
YdrMaster c9d90f97de fix: 修正 TimeSpec 定义 2022-03-29 12:24:33 +08:00
YdrMaster 92fca7a6a6 fix: 在执行新应用程序之前将重要信息从旧应用程序的用户空间中拷贝出来 2022-03-29 12:05:22 +08:00
DeathWish5 090b6af383 cargo fmt and clippy 2022-03-28 17:50:16 +08:00
DeathWish5 202f6296b2 add lock support for libos mode 2022-03-28 17:39:54 +08:00
elliott10 4793db27ea Merge branch 'main' 2022-03-28 17:29:22 +08:00
DeathWish5 b517f543f8 cargo fmt and clippy 2022-03-28 17:26:07 +08:00
DeathWish5 a32e503498 fix x86-smpboot rev 2022-03-28 17:18:02 +08:00
DeathWish5 d7a9741f06 Merge branch 'master' into zcore-lock 2022-03-28 17:14:20 +08:00
DeathWish5 0bf5b1dc6c x86 out of date, upadte some crate version 2022-03-28 16:13:09 +08:00
Luoyuan Xiao c565c3299f
Merge pull request #270 from shzhxh/master
update submodule : tests, workaround of zircon-core-test-libos
2022-03-28 15:39:05 +08:00
shzhxh 491694989c update submodule : tests, workaround of zircon-core-test-libos 2022-03-28 14:15:17 +08:00
YdrMaster 4276b63ef4 docs(kernel-hal): 为 `UserPtr` 提供一份不会导出的中文文档 2022-03-25 13:16:03 +08:00
YdrMaster 3cc3374c87 refactor: 尽量减少对用户指针传入的数组的拷贝 2022-03-25 11:36:56 +08:00
YdrMaster 5783d60f9b refactor(kernel-hal): 移除全部对用户指针传入的字符串的拷贝 2022-03-25 09:15:20 +08:00
DeathWish5 f8bd0ae4a2 minor udpate 2022-03-24 18:04:08 +08:00
DeathWish5 974c5a887a delete unused comments/output 2022-03-24 17:50:34 +08:00
YdrMaster 8038eee630 fix: doc 2022-03-24 16:57:10 +08:00
YdrMaster bfe7339816 fix: 修正 zircon 专用 2022-03-24 16:51:28 +08:00
DeathWish5 3559a39b1f remove Mutex in drivers::irq::intc::{xxx_handler} 2022-03-24 15:07:05 +08:00
YdrMaster 497a70d15a style: 修改风格,减少提前 return 2022-03-24 13:06:23 +08:00
YdrMaster f5f2a6aedc docs: add docs to UserPtr 2022-03-24 12:43:04 +08:00
YdrMaster 25402e96ee test(linux-syscall): 增加编译期测试以保证 linux 定义的类型定义正确
docs(linux-syscall): 改正文档引用了非公开类型的问题
2022-03-23 16:56:21 +08:00
YdrMaster c46f80c8eb build: 依赖最新的 rcore-fs 2022-03-23 16:42:04 +08:00
YdrMaster 6fc573cec8 feat: 实现 `statfs` 和 `fstatfs` 两个系统调用 2022-03-23 16:35:37 +08:00
DeathWish5 682d274998 restore to spin_lock 2022-03-23 16:06:43 +08:00
DeathWish5 5b8c17cc2e merge master 2022-03-22 22:26:25 +08:00
DeathWish5 3bfdae5cac udpate toolchain 2022-03-22 22:22:20 +08:00
DeathWish5 e01dd6973f add rcore-user 2022-03-22 18:22:22 +08:00
DeathWish5 04f018d198 ... 2022-03-22 18:10:07 +08:00
DeathWish5 9916e19a83 refactor lock to kernel-sync 2022-03-22 17:25:43 +08:00
liusm18 d13f66b7f3 Change urls for git & modify default make params 2022-03-20 16:57:11 +08:00
GCYYfun 51b305d27f
Update lib.rs 2022-03-16 19:19:46 +08:00
GCYYfun 32fab8b318
Update lib.rs 2022-03-16 19:14:54 +08:00
GCYYfun 770242c7e9
Update net.rs 2022-03-16 19:09:43 +08:00
GCYYfun 1f387b745b
Merge branch 'master' into mergeBranch 2022-03-16 19:07:36 +08:00
YdrMaster b573dec4d7 docs(zcore-drivers): add some docs 2022-03-16 14:33:07 +08:00
YdrMaster 75faf43872 docs(zcore-drivers): add docs to top mods and types 2022-03-15 23:01:36 +08:00
YdrMaster 00e5a49b60 docs(linux-syscall):
- add doc to `ipc.rs`
- add api menu to `ipc.rs` `vm.rs` and `task.rs`
2022-03-15 11:53:44 +08:00
DeathWish5 8770e25478 ... 2022-03-14 14:17:01 +08:00
YdrMaster 56c29d7c28 docs: update `task.rs` and `vm.rs` syscall 2022-03-14 11:09:10 +08:00
YdrMaster cd4476faec docs: 根据具体实现改正 `vm.rs` 的文档 2022-03-14 09:39:52 +08:00
YdrMaster e4de7167c5 docs: add some docs to task.rs. 2022-03-13 23:16:56 +08:00
YdrMaster d90b5780c2 docs: add docs to `vm.rs`,
there are 3 syscalls in it.
2022-03-11 18:12:00 +08:00
DeathWish5 afc4951b23 ... 2022-03-07 21:21:41 +08:00
DeathWish5 e9a417963c add no-irq rwlock 2022-03-07 17:41:23 +08:00
DeathWish5 d6d80b0bf6 ... 2022-03-07 15:07:42 +08:00
DeathWish5 596a8a7c5f update rboot 2022-03-07 14:54:20 +08:00
elliott10 1e5992690d Fixed an ioapic bug, which occurred when
the ioapic redirection table memory was not clean during init,
Causing x86 hardware to
fail to boot
2022-02-25 16:54:11 +08:00
DeathWish5 e153f5713e use intrrupt Mutex instead of spin::Mutex 2022-02-25 15:11:37 +08:00
GCYYfun 8278dc13b3 feat: new add clock_nanosleep syscall interface in linux-syscall 2022-01-28 15:19:21 +08:00
elliott10 47612fd312 Supporting PCI devices scanning based on rCore 2022-01-27 15:31:07 +08:00
GCYYfun d410fde88a feat: add route in rtlx nic 2022-01-04 14:02:39 +08:00
GCYYfun 0ecd206d6f style: format code 2021-12-31 14:29:00 +08:00
GCYYfun f450d37021 fix: previous insufficient declaration period error 2021-12-31 14:25:13 +08:00
GCYYfun eec570837d fix: replace SOCKETS to get_sockets() 2021-12-31 11:59:12 +08:00
GCYYfun a983b14f06 fix: a blank line caused format error 2021-12-31 01:14:24 +08:00
GCYYfun d3ec807ae0 fix: move libos loopback init form boot to drivers 2021-12-31 01:06:21 +08:00
GCYYfun d7a86f331c fix: remove some unused code and format code 2021-12-31 00:53:27 +08:00
GCYYfun f4983a8a2e feat: support socket operation with file 2021-12-31 00:40:32 +08:00
218 changed files with 5835 additions and 2097 deletions

16
.cargo/config.toml Normal file
View File

@ -0,0 +1,16 @@
[alias]
xtask = "run --package xtask --release --"
git-proxy = "xtask git-proxy"
setup = "xtask setup"
update-all = "xtask update-all"
check-style = "xtask check-style"
rootfs = "xtask rootfs"
libc-test = "xtask libc-test"
other-test = "xtask other-test"
image = "xtask image"
asm = "xtask asm"
qemu = "xtask qemu"
gdb = "xtask gdb"

13
.github/scripts/add-doc-index.sh vendored Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
cat > target/doc/index.html << EOF
<html>
<head>
<meta http-equiv="refresh" content="0;URL=kernel_hal/index.html">
<title>Redirection</title>
</head>
<body onload="window.location = 'kernel_hal/index.html'">
<p>Redirecting to <a href="kernel_hal/index.html">kernel_hal/index.html</a>...</p>
</body>
</html>
EOF

5
.github/scripts/install-deps.sh vendored Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
sudo apt-get update
sudo apt-get install -y $@
pip3 install -r tests/requirements.txt

7
.github/scripts/install-qemu.sh vendored Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
wget https://download.qemu.org/qemu-$1.tar.xz
tar -xJf qemu-$1.tar.xz
cd qemu-$1
./configure --target-list=x86_64-softmmu,riscv64-softmmu
make -j$nproc > /dev/null 2>&1

View File

@ -6,65 +6,58 @@ on:
schedule:
- cron: '0 22 * * *' # every day at 22:00 UTC
env:
rust_toolchain: nightly-2022-01-20
jobs:
check:
workspace:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-01-20
toolchain: ${{ env.rust_toolchain }}
override: true
components: rust-src, rustfmt, clippy
- name: Check code format
run: cargo fmt --all -- --check
- name: Clippy LibOS
run: cargo clippy --all-features
- name: Clippy x86_64 bare-metal
run: cd zCore && make clippy ARCH=x86_64
- name: Clippy riscv64 bare-metal
run: cd zCore && make clippy ARCH=riscv64 LINUX=1
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, macos-latest]
steps:
- uses: actions/checkout@v2
- name: Check format
uses: actions-rs/cargo@v1
with:
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
command: fmt
args: --all -- --check
- name: Build
uses: actions-rs/cargo@v1
with:
profile: minimal
toolchain: nightly-2022-01-20
components: rust-src, llvm-tools-preview
- uses: actions-rs/install@v0.1
command: build
args: --all-features
- name: Clippy
uses: actions-rs/cargo@v1
with:
crate: cargo-binutils
version: latest
- name: Build all packages
run: cargo build
- name: Build linux LibOS
run: cargo build --features "linux libos"
- name: Build zircon LibOS
run: cargo build --features "zircon libos"
- name: Build x86_64 bare-metal
run: cd zCore && make build ARCH=x86_64
- name: Build riscv64 bare-metal
run: cd zCore && make build ARCH=riscv64 LINUX=1
command: clippy
args: --all-features
- name: Build docs
uses: actions-rs/cargo@v1
with:
command: doc
args: --all-features --no-deps
build-aarch64:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-01-20
toolchain: ${{ env.rust_toolchain }}
override: true
target: aarch64-unknown-linux-gnu
- uses: actions-rs/cargo@v1
with:
command: build
@ -72,25 +65,85 @@ jobs:
args: --target aarch64-unknown-linux-gnu --workspace --exclude linux-syscall --exclude zcore-loader --exclude zcore
build-user:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, macos-latest]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/zircon/x64/libc.so,prebuilt/zircon/x64/libfdio.so,prebuilt/zircon/x64/libunwind.so,prebuilt/zircon/x64/libzircon.so,prebuilt/zircon/x64/Scrt1.o
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-01-20
toolchain: ${{ env.rust_toolchain }}
target: x86_64-fuchsia
- name: Build Zircon user programs
run: cd zircon-user && make build MODE=release
build-doc:
runs-on: ubuntu-20.04
test-libos:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
mode: [linux, zircon]
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v2
- name: Build docs
run: cargo doc --no-deps --all-features
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, clippy
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --package zcore --features "${{ matrix.mode }} libos"
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --package zcore --features "${{ matrix.mode }} libos"
test-bare-metal:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
arch: [x86_64, riscv64]
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, clippy
- uses: actions-rs/install@v0.1
with:
crate: cargo-binutils
version: latest
- name: Build ${{ matrix.arch }} bare-metal zircon
if: matrix.arch == 'x86_64'
run: cd zCore && make build ARCH=${{ matrix.arch }}
- name: Clippy ${{ matrix.arch }} bare-metal zircon
if: matrix.arch == 'x86_64'
run: cd zCore && make clippy ARCH=${{ matrix.arch }}
- name: Build ${{ matrix.arch }} bare-metal linux
if: matrix.arch == 'riscv64'
run: cd zCore && make build ARCH=${{ matrix.arch }} LINUX=1
- name: Clippy ${{ matrix.arch }} bare-metal linux
if: matrix.arch == 'riscv64'
run: cd zCore && make clippy ARCH=${{ matrix.arch }} LINUX=1

View File

@ -4,25 +4,25 @@ on:
push:
pull_request:
env:
rust_toolchain: nightly-2022-01-20
jobs:
doc:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
- name: Build docs
run: |
cargo doc --no-deps --all-features
cat >target/doc/index.html <<EOF
<html>
<head>
<meta http-equiv="refresh" content="0;URL=kernel_hal/index.html">
<title>Redirection</title>
</head>
<body onload="window.location = 'kernel_hal/index.html'">
<p>Redirecting to <a href="kernel_hal/index.html">kernel_hal/index.html</a>...</p>
</body>
</html>
EOF
.github/scripts/add-doc-index.sh
- name: Deploy to Github Pages
if: ${{ github.ref == 'refs/heads/master' }}
uses: JamesIves/github-pages-deploy-action@releases/v3

View File

@ -6,26 +6,39 @@ on:
schedule:
- cron: '0 22 * * *' # every day at 22:00 UTC
env:
rust_toolchain: nightly-2022-01-20
qemu_version: 7.0.0
jobs:
test:
unit-test:
name: Unit Test
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/linux/libc-libos.so,prebuilt/zircon/x64/bringup.zbi,prebuilt/zircon/x64/libzircon-libos.so,prebuilt/zircon/x64/userboot-libos.so
- name: Prepare rootfs
run: make rootfs
- name: Test
run: cargo test --no-fail-fast
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Run unit test
uses: actions-rs/cargo@v1
with:
command: test
args: --no-fail-fast
env:
CARGO_INCREMENTAL: '0'
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
RUSTDOCFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
- name: Cache grcov
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-grcov
- name: Gather coverage data
id: coverage
uses: actions-rs/grcov@v0.1
@ -36,142 +49,233 @@ jobs:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# path-to-lcov: ${{ steps.coverage.outputs.report }}
bench:
bench-test:
name: Bench Test
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Run benchmarks
run: cargo bench
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Run bench test
uses: actions-rs/cargo@v1
with:
command: bench
zircon-core-test-libos:
name: Zircon Core Test Libos
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/zircon/x64/core-tests.zbi,prebuilt/zircon/x64/libzircon-libos.so,prebuilt/zircon/x64/userboot-libos.so
- name: Install dependencies
run: pip3 install -r tests/requirements.txt
run: |
git lfs pull -I prebuilt/zircon/x64/core-tests.zbi
git lfs pull -I prebuilt/zircon/x64/libzircon-libos.so
git lfs pull -I prebuilt/zircon/x64/userboot-libos.so
- name: Install python dependencies
run: .github/scripts/install-deps.sh
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 zircon_core_test.py --libos --fast
run: cd tests && python3 zircon_core_test.py --libos --fast --no-failed
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 zircon_core_test.py --libos
zircon-core-test-baremetal:
linux-libc-test-libos:
name: Linux Libc Test Libos
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
arch: [x86_64]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/zircon/x64/core-tests.zbi,prebuilt/zircon/x64/libzircon.so,prebuilt/zircon/x64/userboot.so
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-01-20
components: rust-src
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install ninja-build -y
pip3 install -r tests/requirements.txt
- name: Cache QEMU
uses: actions/cache@v1
with:
path: qemu-6.1.0
key: qemu-6.1.0-${{ matrix.arch }}
- name: Install QEMU
run: |
[ ! -d qemu-6.1.0 ] && wget https://download.qemu.org/qemu-6.1.0.tar.xz \
&& tar xJf qemu-6.1.0.tar.xz > /dev/null \
&& cd qemu-6.1.0 && ./configure --target-list=${{ matrix.arch }}-softmmu && cd ..
cd qemu-6.1.0 && sudo make install -j
qemu-system-${{ matrix.arch }} --version
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 zircon_core_test.py --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 zircon_core_test.py
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
linux-libc-test-libos:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/linux/libc-libos.so
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install musl-tools musl-dev -y
pip3 install -r tests/requirements.txt
run: .github/scripts/install-deps.sh musl-tools musl-dev
- name: Prepare rootfs
run: make rootfs && make libc-test
run: make libc-test
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 linux_libc_test.py --libos --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 linux_libc_test.py --libos
zircon-core-test-baremetal:
name: Zircon Core Test Baremetal
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Pull prebuilt images
run: |
git lfs pull -I prebuilt/zircon/x64/core-tests.zbi
git lfs pull -I prebuilt/zircon/x64/libzircon.so
git lfs pull -I prebuilt/zircon/x64/userboot.so
- name: Install dependencies
run: .github/scripts/install-deps.sh ninja-build
- name: Cache QEMU
id: cache-qemu
uses: actions/cache@v3
with:
path: qemu-${{ env.qemu_version }}
key: qemu-${{ env.qemu_version }}-x86_64-riscv64
- name: Download and Compile QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: .github/scripts/install-qemu.sh ${{ env.qemu_version }}
- name: Install QEMU
run: |
cd qemu-${{ env.qemu_version }} && sudo make install
qemu-system-x86_64 --version
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 zircon_core_test.py --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 zircon_core_test.py
linux-libc-test-baremetal:
name: Linux Libc Test Baremetal
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
arch: [x86_64, riscv64]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/linux/libc-libos.so
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-01-20
components: rust-src, llvm-tools-preview
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- if: matrix.arch == 'riscv64'
uses: actions-rs/install@v0.1
with:
crate: cargo-binutils
version: latest
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install musl-tools musl-dev ninja-build -y
pip3 install -r tests/requirements.txt
run: .github/scripts/install-deps.sh musl-tools musl-dev ninja-build
- name: Cache QEMU
uses: actions/cache@v1
id: cache-qemu
uses: actions/cache@v3
with:
path: qemu-6.1.0
key: qemu-6.1.0-${{ matrix.arch }}
path: qemu-${{ env.qemu_version }}
key: qemu-${{ env.qemu_version }}-x86_64-riscv64
- name: Download and Compile QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: .github/scripts/install-qemu.sh ${{ env.qemu_version }}
- name: Install QEMU
run: |
[ ! -d qemu-6.1.0 ] && wget https://download.qemu.org/qemu-6.1.0.tar.xz \
&& tar xJf qemu-6.1.0.tar.xz > /dev/null \
&& cd qemu-6.1.0 && ./configure --target-list=${{ matrix.arch }}-softmmu && cd ..
cd qemu-6.1.0 && sudo make install -j
cd qemu-${{ env.qemu_version }} && sudo make install
qemu-system-${{ matrix.arch }} --version
- name: Prepare rootfs
run: |
if [ "${{ matrix.arch }}" = "x86_64" ]; then
make baremetal-test-img
elif [ "${{ matrix.arch }}" = "riscv64" ]; then
make riscv-image
fi
run: make libc-test ARCH=${{ matrix.arch }} && make image ARCH=${{ matrix.arch }}
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 linux_libc_test.py --arch ${{ matrix.arch }} --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 linux_libc_test.py --arch ${{ matrix.arch }}
linux-other-test-baremetal:
name: Linux Other Test Baremetal
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
arch: [x86_64, riscv64]
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- if: matrix.arch == 'riscv64'
uses: actions-rs/install@v0.1
with:
crate: cargo-binutils
version: latest
- name: Install dependencies
run: .github/scripts/install-deps.sh musl-tools musl-dev ninja-build
- name: Cache QEMU
id: cache-qemu
uses: actions/cache@v3
with:
path: qemu-${{ env.qemu_version }}
key: qemu-${{ env.qemu_version }}-x86_64-riscv64
- name: Download and Compile QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: .github/scripts/install-qemu.sh ${{ env.qemu_version }}
- name: Install QEMU
run: |
cd qemu-${{ env.qemu_version }} && sudo make install
qemu-system-${{ matrix.arch }} --version
- name: Prepare rootfs
run: make other-test ARCH=${{ matrix.arch }} && make image ARCH=${{ matrix.arch }}
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 linux_other_test.py --arch ${{ matrix.arch }} --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 linux_other_test.py --arch ${{ matrix.arch }}

21
.gitignore vendored
View File

@ -1,15 +1,18 @@
/target
**/.*
!.github/
!.cargo/
!.vscode/settings.json
**/target
**/*.rs.bk
Cargo.lock
/rootfs
/riscv_rootfs
/prebuilt/linux/alpine*
/prebuilt/linux/riscv64/prebuild*
zCore/src/platform/riscv/boot/kernel-vars.ld
*.img
*.bin
*.log
.idea
Cargo.lock
/ignored
/rootfs
zCore/src/platform/riscv/kernel-vars.ld
.DS_Store
.vscode/
__pycache__

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "tests"]
path = tests
url = https://github.com/rcore-os/zcore-tests.git
[submodule "libc-test"]
path = libc-test
url = https://github.com/rcore-os/libc-test

10
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// Prevent "can't find crate for `test`" error on no_std
// Ref: https://github.com/rust-lang/vscode-rust/issues/729
// For vscode-rust plugin users:
"rust.target": "riscv64imac-unknown-none-elf",
"rust.all_targets": false,
// For Rust Analyzer plugin users:
"rust-analyzer.cargo.target": "riscv64imac-unknown-none-elf",
"rust-analyzer.checkOnSave.enable": false
}

View File

@ -8,12 +8,10 @@ members = [
"linux-syscall",
"loader",
"zCore",
"xtask",
]
exclude = [
"zircon-user",
"rboot",
]
default-members = ["xtask"]
exclude = ["zircon-user", "rboot"]
[profile.release]
lto = true

121
Makefile
View File

@ -1,100 +1,53 @@
ROOTFS_TAR := alpine-minirootfs-3.12.0-x86_64.tar.gz
ROOTFS_URL := http://dl-cdn.alpinelinux.org/alpine/v3.12/releases/x86_64/$(ROOTFS_TAR)
RISCV64_ROOTFS_TAR := prebuild.tar.xz
RISCV64_ROOTFS_URL := https://github.com/rcore-os/libc-test-prebuilt/releases/download/0.1/$(RISCV64_ROOTFS_TAR)
# Makefile for top level of zCore
ARCH ?= x86_64
rcore_fs_fuse_revision := 7f5eeac
OUT_IMG := zCore/$(ARCH).img
TMP_ROOTFS := /tmp/rootfs
# for linux syscall tests
TEST_DIR := linux-syscall/test/
DEST_DIR := rootfs/bin/
TEST_PATH := $(wildcard $(TEST_DIR)*.c)
BASENAMES := $(notdir $(basename $(TEST_PATH)))
.PHONY: help setup update rootfs libc-test other-test image check doc clean
CFLAG := -Wl,--dynamic-linker=/lib/ld-musl-x86_64.so.1
# print top level help
help:
cargo xtask help
.PHONY: rootfs libc-test rcore-fs-fuse image
# setup git lfs and git submodules
setup:
cargo setup
prebuilt/linux/$(ROOTFS_TAR):
wget $(ROOTFS_URL) -O $@
# update toolchain and dependencies
update:
cargo update-all
prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR):
@wget $(RISCV64_ROOTFS_URL) -O $@
rootfs: prebuilt/linux/$(ROOTFS_TAR)
rm -rf rootfs && mkdir -p rootfs
tar xf $< -C rootfs
# libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
@for VAR in $(BASENAMES); do gcc $(TEST_DIR)$$VAR.c -o $(DEST_DIR)$$VAR $(CFLAG); done
riscv-rootfs:prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR)
@rm -rf riscv_rootfs && mkdir -p riscv_rootfs
@tar -xvf $< -C riscv_rootfs --strip-components 1
@ln -s busybox riscv_rootfs/bin/ls
# put rootfs for linux mode
rootfs:
cargo rootfs --arch $(ARCH)
# put libc tests into rootfs
libc-test:
cd rootfs && git clone git://repo.or.cz/libc-test --depth 1
cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j
cargo libc-test --arch $(ARCH)
rcore-fs-fuse:
ifneq ($(shell rcore-fs-fuse dir image git-version), $(rcore_fs_fuse_revision))
@echo Installing rcore-fs-fuse
@cargo install rcore-fs-fuse --git https://github.com/rcore-os/rcore-fs --rev $(rcore_fs_fuse_revision) --force
endif
# put other tests into rootfs
other-test:
cargo other-test --arch $(ARCH)
$(OUT_IMG): prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse
@echo Generating $(ARCH).img
@rm -rf $(TMP_ROOTFS)
@mkdir -p $(TMP_ROOTFS)
@tar xf $< -C $(TMP_ROOTFS)
@cp $(TMP_ROOTFS)/lib/ld-musl-x86_64.so.1 rootfs/lib/
@rcore-fs-fuse $@ rootfs zip
# recover rootfs/ld-musl-x86_64.so.1 for zcore usr libos
# libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
@cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
# build image from rootfs
image:
cargo image --arch $(ARCH)
image: $(OUT_IMG)
@echo Resizing $(ARCH).img
@qemu-img resize $(OUT_IMG) +5M
riscv-image: rcore-fs-fuse riscv-rootfs
@echo building riscv.img
@rcore-fs-fuse zCore/riscv64.img riscv_rootfs zip
@qemu-img resize -f raw zCore/riscv64.img +5M
clean:
cargo clean
find zCore -maxdepth 1 -name "*.img" -delete
rm -rf rootfs
rm -rf riscv-rootfs
find zCore/target -type f -name "*.zbi" -delete
find zCore/target -type f -name "*.elf" -delete
cd linux-syscall/test-oscomp && make clean
cd linux-syscall/busybox && make clean
cd linux-syscall/lua && make clean
cd linux-syscall/lmbench && make clean
# check code style
check:
cargo check-style
# build and open project document
doc:
cargo doc --open
baremetal-test-img: prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse
@echo Generating $(ARCH).img
@rm -rf $(TMP_ROOTFS)
@mkdir -p $(TMP_ROOTFS)
@tar xf $< -C $(TMP_ROOTFS)
@mkdir -p rootfs/lib
@cp $(TMP_ROOTFS)/lib/ld-musl-x86_64.so.1 rootfs/lib/
@cd rootfs && rm -rf libc-test && git clone git://repo.or.cz/libc-test --depth 1
@cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j
@rcore-fs-fuse $(OUT_IMG) rootfs zip
# recover rootfs/ld-musl-x86_64.so.1 for zcore usr libos
# libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
@cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
@echo Resizing $(ARCH).img
@qemu-img resize $(OUT_IMG) +5M
# clean targets
clean:
cargo clean
rm -rf rootfs
rm -rf ignored/target
find zCore -maxdepth 1 -name "*.img" -delete
rt-test:
cd rootfs/x86_64 && git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/clrkwllms/rt-tests --depth 1
cd rootfs/x86_64/rt-tests && make
echo x86 gcc build rt-test,now need manual modificy.

View File

@ -6,6 +6,10 @@
Reimplement [Zircon][zircon] microkernel in safe Rust as a userspace program!
## Manual
[This](docs/Manual.md) is a new simple chinese manual.
## Dev Status
🚧 Working In Progress
@ -24,9 +28,9 @@ make run ARCH=riscv64 LINUX=1
Environments
* [Rust toolchain](http://rustup.rs)
* [QEMU](https://www.qemu.org)
* [Git LFS](https://git-lfs.github.com)
- [Rust toolchain](http://rustup.rs)
- [QEMU](https://www.qemu.org)
- [Git LFS](https://git-lfs.github.com)
### Developing environment info
@ -48,15 +52,18 @@ For users in China, there's a mirror you can try:
```sh
git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
```
### Run zcore in libos mode
#### Run zcore in linux-libos mode
* step 1: Prepare Alpine Linux rootfs:
- step 1: Prepare Alpine Linux rootfs:
```sh
make rootfs
```
* step 2: Compile & Run native Linux program (Busybox) in libos mode:
- step 2: Compile & Run native Linux program (Busybox) in libos mode:
```sh
cargo run --release --features "linux libos" -- /bin/busybox [args]
@ -68,7 +75,7 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
#### Run native Zircon program (shell) in zircon-libos mode:
* step 1: Compile and Run Zircon shell
- step 1: Compile and Run Zircon shell
```sh
cargo run --release --features "zircon libos" -- prebuilt/zircon/x64/bringup.zbi
@ -77,15 +84,16 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
The `graphic` and `LOG` options are the same as Linux.
### Run zcore in bare-metal mode
#### Run Linux shell in linux-bare-metal mode:
* step 1: Prepare Alpine Linux rootfs:
- step 1: Prepare Alpine Linux rootfs:
```sh
make rootfs
```
* step 2: Create Linux rootfs image:
- step 2: Create Linux rootfs image:
Note: Before below step, you can add some special apps in zCore/rootfs
@ -93,7 +101,7 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
make image
```
* step 3: Build and run zcore in linux-bare-metal mode:
- step 3: Build and run zcore in linux-bare-metal mode:
```sh
cd zCore && make run MODE=release LINUX=1 [LOG=warn] [GRAPHIC=on] [ACCEL=1]
@ -101,13 +109,13 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
#### Run Zircon shell in zircon-bare-metal mode:
* step 1: Build and run zcore in zircon-bare-metal mode:
- step 1: Build and run zcore in zircon-bare-metal mode:
```sh
cd zCore && make run MODE=release [LOG=warn] [GRAPHIC=on] [ACCEL=1]
```
* step 2: Build and run your own Zircon user programs:
- step 2: Build and run your own Zircon user programs:
```sh
# See template in zircon-user
@ -118,6 +126,7 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
```
## Testing
### LibOS Mode Testing
#### Zircon related
@ -148,6 +157,7 @@ cd scripts && python3 libos-libc-tests.py
```
### Bare-metal Mode Testing
#### Zircon related
Run Zircon official core-tests on bare-metal:
@ -167,6 +177,7 @@ cd scripts && python3 core-tests.py
#### x86-64 Linux related
Run Linux musl libc-tests for CI:
```sh
## Prepare rootfs with libc-test apps
make baremetal-test-img
@ -184,6 +195,7 @@ You can use [`scripts/baremetal-libc-test-ones.py`](./scripts/baremetal-libc-tes
#### riscv-64 Linux related
Run Linux musl libc-tests for CI:
```sh
## Prepare rootfs with libc-test & oscomp apps
make riscv-image
@ -192,25 +204,28 @@ cd scripts && python3 baremetal-test-riscv64.py
##
```
You can use[ `scripts/baremetal-libc-test-ones-riscv64.py`](./scripts/baremetal-libc-test-ones-riscv64.py) & [`scripts/linux/baremetal-test-ones-rv64.txt`](scripts/linux/baremetal-test-ones-rv64.txt)to test
You can use[scripts/baremetal-libc-test-ones-riscv64.py](./scripts/baremetal-libc-test-ones-riscv64.py) & [`scripts/linux/baremetal-test-ones-rv64.txt`](scripts/linux/baremetal-test-ones-rv64.txt)to test
specified apps.
[`scripts/linux/baremetal-test-fail-riscv64.txt`](./scripts/linux/baremetal-test-fail-riscv64.txt)includes all failed riscv-64 apps (We need YOUR HELP to fix bugs!)
## Graph/Game
snake game: https://github.com/rcore-os/rcore-user/blob/master/app/src/snake.c
snake game: <https://github.com/rcore-os/rcore-user/blob/master/app/src/snake.c>
### Step1: compile usr app
We can use musl-gcc compile it in x86_64 mode
### Step2: change zcore for run snake app first.
change zCore/zCore/main.rs L176
vec!["/bin/busybox".into(), "sh".into()]
TO
vec!["/bin/snake".into(), "sh".into()]
### Step3: prepare root fs image, run zcore in linux-bare-metal mode
exec:
```sh
@ -235,12 +250,15 @@ Operation
- `Middle`: Pause/Resume
## Doc
```
make doc
```
### RISC-V 64 porting info
- [porting riscv64 doc](./docs/porting-rv64.md)
## Components
### Overview
@ -260,4 +278,5 @@ make doc
| Exception Handling | Interrupt | Signal |
### Small Goal & Little Plans
- https://github.com/rcore-os/zCore/wiki/Plans
- <https://github.com/rcore-os/zCore/wiki/Plans>

86
docs/Manual.md Normal file
View File

@ -0,0 +1,86 @@
# zCore 项目使用指南
## 预定功能
预定功能指的是 zCore 作为一个项目,为开发者和用户常用操作提供的封装。
由于历史原因,目前预定功能分为顶层预定功能和内核预定功能。
所有顶层提供的预定功能都定义于 [顶层 Makefile](../Makefile)
并且所有预定功能最终都将移动到顶层。
## 常规操作流程
对于一般开发者和用户,可以按以下步骤设置 zCore 项目。
1. 先决条件
目前已测试的开发环境包括 Ubuntu20.04、Ubuntu22.04 和 Debian11
Ubuntu22.04 不能正确编译 x86_64 的 libc 测试。
若不需要烧写到物理硬件,使用 WSL2 或其他虚拟机的操作与真机并无不同之处。
在开始之前,确保你的计算机上安装了 git 和 rustup。要在虚拟环境开发或测试需要 QEMU。
2. 克隆项目
```bash
git clone https://github.com/rcore-os/zCore.git
```
3. 初始化存储库
```bash
make setup
```
4. 保持更新
```bash
make update
```
5. 探索更多操作
```bash
make help
```
6. 推到仓库前,现在本机执行测试
```bash
make check # CI/build 的一部分,未来会实现更多快速测试指令
```
## Linux 模式
zCore 根据向用户提供的系统调用的不同,可分为 zircon 模式和 linux 模式。
要以 linux 模式启动,需要先构建 linux 的启动文件系统。
这个指令构建适于 x86_64 架构的启动文件系统。
```bash
make rootfs ARCH=x86_64
```
这个指令构建适于 riscv64 架构的启动文件系统。
```bash
make rootfs ARCH=riscv64
```
要执行 musl-libc 测试集,需要向文件系统中添加 libc 测试集:
```bash
make libc-test <ARCH=?>
```
要执行 CI 的其他测试,需要向文件系统中添加相应测试集:
```bash
make other-test <ARCH=?>
```
要以裸机模式启动 zCore需要构造将放到设备或虚拟环境中的镜像文件
```bash
make image <ARCH=?>
```

View File

@ -20,19 +20,27 @@ bitflags = "1.3"
lazy_static = "1.4"
numeric-enum-macro = "0.2"
device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2f2e55f" }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51" }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "88e871a5" }
pci = { git = "https://github.com/elliott10/pci-rs", rev = "8f33774b" }
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2aaf7d6", optional = true }
rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "ca5b1bc", optional = true }
# smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp"] }
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "01b2e70" }
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers", rev = "f7cd97a8", features = ["log"] }
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "async"] }
# LibOS mode
[target.'cfg(not(target_os = "none"))'.dependencies]
async-std = { version = "1.10", optional = true }
sdl2 = { version = "0.34", optional = true }
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
[target.'cfg(target_arch = "x86_64")'.dependencies]
acpi = "4.0"
acpi = "4.1"
x2apic = "0.4"
x86_64 = "0.14"
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }
riscv = "0.8"

View File

@ -1,3 +1,18 @@
// 解析设备树,创建已知的设备并为它们注册中断。
//
// 涉及到中断的设备包括:
//
// - 接收中断的中断控制器
// - 发出中断的设备
//
// 有效的中断控制器应该具有下列三个属性:
//
// - `interrupt-controller`: 指示这是一个中断控制器
// - `interrupt-cells`: 只是要向此控制器注册中断需要几个参数
// - `phandle`: 向此控制器注册中断时使用的一个号码,如果没有设备需要向它注册,可能不存在
//
// 设备注册中断需要 `interrupts_extended` 属性,这是一个 `Vec<u32>`,形式为 `[{phandle, ...,}*]`
// 即控制器引用和控制器指定数量的参数。
//! Probe devices and create drivers from device tree.
//!
//! Specification: <https://github.com/devicetree-org/devicetree-specification/releases/download/v0.3/devicetree-specification-v0.3.pdf>.
@ -5,24 +20,27 @@
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
use super::IoMapper;
use crate::utils::devicetree::{parse_interrupts, parse_reg};
use crate::utils::devicetree::{Devicetree, InheritProps, InterruptsProp, Node, StringList};
use crate::{Device, DeviceError, DeviceResult, VirtAddr};
use crate::{
utils::devicetree::{
parse_interrupts, parse_reg, Devicetree, InheritProps, InterruptsProp, Node, StringList,
},
Device, DeviceError, DeviceResult, VirtAddr,
};
/// A wrapper of [`Device`] which provides interrupt information additionally.
#[derive(Debug)]
struct DevWithInterrupt {
/// For interrupt controller, represent the `phandle` property, otherwise
/// is `None`.
phandle: Option<u32>,
/// For interrupt controller, represent the `interrupt_cells` property,
/// otherwise is `None`.
interrupt_cells: Option<u32>,
/// A unified representation of the `interrupts` and `interrupts_extended`
/// properties for any interrupt generating device.
interrupts_extended: InterruptsProp,
/// The inner [`Device`] structure.
dev: Device,
const MODULE: &str = "device-tree";
type DevWithInterrupt = (Device, InterruptsProp);
/// 设备树中中断控制器特有的属性
struct IntcProps {
phandle: u32,
interrupt_cells: u32,
}
/// 查找表保存的中断控制器信息
struct Intc {
index: usize,
cells: usize,
}
/// A builder to probe devices and create drivers from device tree.
@ -42,26 +60,78 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
/// Parse the device tree from root, and returns an array of [`Device`] it found.
pub fn build(&self) -> DeviceResult<Vec<Device>> {
let mut intc_map = BTreeMap::new();
let mut dev_list = Vec::new();
let mut intc_map = BTreeMap::new(); // phandle -> intc
let mut dev_list = Vec::new(); // devices
// 解析设备树
self.dt.walk(&mut |node, comp, props| {
if let Ok(dev) = self.parse_device(node, comp, props) {
// create the phandle-device mapping
if node.has_prop("interrupt-controller") {
if let Some(phandle) = dev.phandle {
intc_map.insert(phandle, dev_list.len());
debug!(
"{MODULE}: parsing node {:?} with compatible {comp:?}",
node.name
);
// parse interrupt controller
let res = if node.has_prop("interrupt-controller") {
self.parse_intc(node, comp, props).map(|(dev, intc)| {
intc_map.insert(
intc.phandle,
Intc {
index: dev_list.len(),
cells: intc.interrupt_cells as _,
},
);
dev
})
} else {
// parse other device
match comp {
#[cfg(feature = "virtio")]
c if c.contains("virtio,mmio") => self.parse_virtio(node, props),
c if c.contains("allwinner,sunxi-gmac") => {
self.parse_ethernet(node, comp, props)
}
c if c.contains("ns16550a") || c.contains("allwinner,sun20i-uart") => {
self.parse_uart(node, comp, props)
}
_ => Err(DeviceError::NotSupported),
}
dev_list.push(dev);
};
match res {
Ok(dev) => dev_list.push(dev),
Err(DeviceError::NotSupported) => {}
Err(err) => warn!("{MODULE}: failed to parsing node {:?}: {err:?}", node.name),
}
});
for dev in &dev_list {
register_interrupt(dev, &dev_list, &intc_map).ok();
// 注册中断
for (device, interrupts_extended) in &dev_list {
let mut extended = interrupts_extended.as_slice();
// 分解 interrupts_extended
while let [phandle, irq_num, ..] = extended {
if let Some(Intc { index, cells }) = intc_map.get(phandle) {
let (intc, _) = &dev_list[*index];
extended = &extended[1 + cells..];
if let Device::Irq(irq) = intc {
if *irq_num != 0xffff_ffff {
info!("{MODULE}: register interrupts for {intc:?}: {device:?}, irq_num={irq_num}");
if irq.register_device(*irq_num as _, device.inner()).is_ok() {
irq.unmask(*irq_num as _)?;
}
}
} else {
warn!("{MODULE}: node with phandle {phandle:#x} is not an interrupt-controller");
return Err(DeviceError::InvalidParam);
}
} else {
warn!(
"{MODULE}: no such node with phandle {phandle:#x} as the interrupt-parent"
);
return Err(DeviceError::InvalidParam);
}
}
}
Ok(dev_list.into_iter().map(|d| d.dev).collect())
// 丢弃中断信息
Ok(dev_list.into_iter().map(|(dev, _)| dev).collect())
}
}
@ -70,56 +140,20 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
#[allow(unused_variables)]
#[allow(unreachable_code)]
impl<M: IoMapper> DevicetreeDriverBuilder<M> {
/// Parse device nodes
fn parse_device(
&self,
node: &Node,
comp: &StringList,
props: &InheritProps,
) -> DeviceResult<DevWithInterrupt> {
debug!(
"device-tree: parsing node {:?} with compatible {:?}",
node.name, comp
);
// parse interrupt controller
let res = if node.has_prop("interrupt-controller") {
self.parse_intc(node, comp, props)
} else {
// parse other device
match comp {
#[cfg(feature = "virtio")]
c if c.contains("virtio,mmio") => self.parse_virtio(node, props),
c if c.contains("allwinner,sunxi-gmac") => self.parse_ethernet(node, comp, props),
c if c.contains("ns16550a") => self.parse_uart(node, comp, props),
c if c.contains("allwinner,sun20i-uart") => self.parse_uart(node, comp, props),
_ => Err(DeviceError::NotSupported),
}
};
if let Err(err) = &res {
if !matches!(err, DeviceError::NotSupported) {
warn!(
"device-tree: failed to parsing node {:?}: {:?}",
node.name, err
);
}
}
res
}
/// Parse nodes for interrupt controllers.
fn parse_intc(
&self,
node: &Node,
comp: &StringList,
props: &InheritProps,
) -> DeviceResult<DevWithInterrupt> {
let phandle = node.prop_u32("phandle").ok();
let interrupt_cells = node.prop_u32("#interrupt-cells").ok();
) -> DeviceResult<(DevWithInterrupt, IntcProps)> {
let phandle = node
.prop_u32("phandle")
.map_err(|_| DeviceError::InvalidParam)?;
let interrupt_cells = node
.prop_u32("#interrupt-cells")
.map_err(|_| DeviceError::InvalidParam)?;
let interrupts_extended = parse_interrupts(node, props)?;
if phandle.is_none() || interrupt_cells.is_none() {
return Err(DeviceError::InvalidParam);
}
let base_vaddr = parse_reg(node, props).and_then(|(paddr, size)| {
self.io_mapper
.query_or_map(paddr as usize, size as usize)
@ -134,12 +168,13 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
_ => return Err(DeviceError::NotSupported),
});
Ok(DevWithInterrupt {
phandle,
interrupt_cells,
interrupts_extended,
dev,
})
Ok((
(dev, interrupts_extended),
IntcProps {
phandle,
interrupt_cells,
},
))
}
/// Parse nodes for virtio devices over MMIO.
@ -159,7 +194,7 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
return Err(DeviceError::NotSupported);
}
info!(
"device-tree: detected virtio device: vendor_id={:#X}, type={:?}",
"{MODULE}: detected virtio device: vendor_id={:#X}, type={:?}",
header.vendor_id(),
header.device_type()
);
@ -172,12 +207,7 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
_ => return Err(DeviceError::NotSupported),
};
Ok(DevWithInterrupt {
phandle: None,
interrupt_cells: None,
interrupts_extended,
dev,
})
Ok((dev, interrupts_extended))
}
/// Parse nodes for Ethernet devices.
@ -207,12 +237,7 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
_ => return Err(DeviceError::NotSupported),
});
Ok(DevWithInterrupt {
phandle: None,
interrupt_cells: None,
interrupts_extended,
dev,
})
Ok((dev, interrupts_extended))
}
/// Parse nodes for UART devices.
@ -240,57 +265,6 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
_ => return Err(DeviceError::NotSupported),
});
Ok(DevWithInterrupt {
phandle: None,
interrupt_cells: None,
interrupts_extended,
dev,
})
Ok((dev, interrupts_extended))
}
}
/// Register interrupts for `dev` according to its interrupt parent, which can
/// be found from the phandle-device mapping.
fn register_interrupt(
dev: &DevWithInterrupt,
dev_list: &[DevWithInterrupt],
intc_map: &BTreeMap<u32, usize>,
) -> DeviceResult {
let mut pos = 0;
while pos < dev.interrupts_extended.len() {
let parent = dev.interrupts_extended[pos];
// find the interrupt parent in `dev_list`
if let Some(intc) = intc_map.get(&parent).map(|&i| &dev_list[i]) {
let cells = intc.interrupt_cells.ok_or(DeviceError::InvalidParam)?;
if let Device::Irq(irq) = &intc.dev {
// get irq_num from the `interrupts_extended` property
let irq_num = dev.interrupts_extended[pos + 1] as usize;
if irq_num != 0xffff_ffff {
info!(
"device-tree: register interrupts for {:?}: {:?}, irq_num={}",
intc.dev, dev.dev, irq_num
);
irq.register_device(irq_num, dev.dev.inner())?;
// enable the interrupt after registration
irq.unmask(irq_num)?;
}
} else {
warn!(
"device-tree: node with phandle {:#x} is not an interrupt-controller",
parent
);
return Err(DeviceError::InvalidParam);
}
// process the next interrupt parent
pos += 1 + cells as usize;
} else {
warn!(
"device-tree: no such node with phandle {:#x} as the interrupt-parent",
parent
);
return Err(DeviceError::InvalidParam);
}
}
Ok(())
}

38
drivers/src/bus/mod.rs Normal file
View File

@ -0,0 +1,38 @@
#![allow(unused)]
#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
pub mod pci;
pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
unsafe { drivers_phys_to_virt(paddr) }
}
pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
unsafe { drivers_virt_to_phys(vaddr) }
}
extern "C" {
fn drivers_dma_alloc(pages: usize) -> PhysAddr;
fn drivers_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32;
fn drivers_phys_to_virt(paddr: PhysAddr) -> VirtAddr;
fn drivers_virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
}
pub const PAGE_SIZE: usize = 4096;
type VirtAddr = usize;
type PhysAddr = usize;
use core::ptr::{read_volatile, write_volatile};
#[inline(always)]
pub fn write<T>(addr: usize, content: T) {
let cell = (addr) as *mut T;
unsafe {
write_volatile(cell, content);
}
}
#[inline(always)]
pub fn read<T>(addr: usize) -> T {
let cell = (addr) as *const T;
unsafe { read_volatile(cell) }
}

327
drivers/src/bus/pci.rs Normal file
View File

@ -0,0 +1,327 @@
use super::{phys_to_virt, PAGE_SIZE};
use crate::builder::IoMapper;
use crate::{Device, DeviceError, DeviceResult, VirtAddr};
use alloc::{collections::BTreeMap, format, sync::Arc, vec::Vec};
use pci::*;
use spin::Mutex;
const PCI_COMMAND: u16 = 0x04;
const BAR0: u16 = 0x10;
const PCI_CAP_PTR: u16 = 0x34;
const PCI_INTERRUPT_LINE: u16 = 0x3c;
const PCI_INTERRUPT_PIN: u16 = 0x3d;
const PCI_MSI_CTRL_CAP: u16 = 0x00;
const PCI_MSI_ADDR: u16 = 0x04;
const PCI_MSI_UPPER_ADDR: u16 = 0x08;
const PCI_MSI_DATA_32: u16 = 0x08;
const PCI_MSI_DATA_64: u16 = 0x0C;
const PCI_CAP_ID_MSI: u8 = 0x05;
struct PortOpsImpl;
#[cfg(target_arch = "x86_64")]
use x86_64::instructions::port::Port;
#[cfg(target_arch = "x86_64")]
impl PortOps for PortOpsImpl {
unsafe fn read8(&self, port: u16) -> u8 {
Port::new(port).read()
}
unsafe fn read16(&self, port: u16) -> u16 {
Port::new(port).read()
}
unsafe fn read32(&self, port: u32) -> u32 {
Port::new(port as u16).read()
}
unsafe fn write8(&self, port: u16, val: u8) {
Port::new(port).write(val);
}
unsafe fn write16(&self, port: u16, val: u16) {
Port::new(port).write(val);
}
unsafe fn write32(&self, port: u32, val: u32) {
Port::new(port as u16).write(val);
}
}
#[cfg(target_arch = "x86_64")]
const PCI_BASE: usize = 0; //Fix me
#[cfg(any(target_arch = "mips", target_arch = "riscv64"))]
use super::{read, write};
#[cfg(feature = "board_malta")]
const PCI_BASE: usize = 0xbbe00000;
#[cfg(target_arch = "riscv64")]
const PCI_BASE: usize = 0x30000000;
#[cfg(target_arch = "riscv64")]
const E1000_BASE: usize = 0x40000000;
// riscv64 Qemu
#[cfg(target_arch = "x86_64")]
const PCI_ACCESS: CSpaceAccessMethod = CSpaceAccessMethod::IO;
#[cfg(not(target_arch = "x86_64"))]
const PCI_ACCESS: CSpaceAccessMethod = CSpaceAccessMethod::MemoryMapped(PCI_BASE as *mut u8);
#[cfg(any(target_arch = "mips", target_arch = "riscv64"))]
impl PortOps for PortOpsImpl {
unsafe fn read8(&self, port: u16) -> u8 {
read(phys_to_virt(PCI_BASE) + port as usize)
}
unsafe fn read16(&self, port: u16) -> u16 {
read(phys_to_virt(PCI_BASE) + port as usize)
}
unsafe fn read32(&self, port: u32) -> u32 {
read(phys_to_virt(PCI_BASE) + port as usize)
}
unsafe fn write8(&self, port: u16, val: u8) {
write(phys_to_virt(PCI_BASE) + port as usize, val);
}
unsafe fn write16(&self, port: u16, val: u16) {
write(phys_to_virt(PCI_BASE) + port as usize, val);
}
unsafe fn write32(&self, port: u32, val: u32) {
write(phys_to_virt(PCI_BASE) + port as usize, val);
}
}
/// Enable the pci device and its interrupt
/// Return assigned MSI interrupt number when applicable
unsafe fn enable(loc: Location, paddr: u64) -> Option<usize> {
let ops = &PortOpsImpl;
//let am = CSpaceAccessMethod::IO;
let am = PCI_ACCESS;
if paddr != 0 {
// reveal PCI regs by setting paddr
let bar0_raw = am.read32(ops, loc, BAR0);
am.write32(ops, loc, BAR0, (paddr & !0xfff) as u32); //Only for 32-bit decoding
debug!(
"BAR0 set from {:#x} to {:#x}",
bar0_raw,
am.read32(ops, loc, BAR0)
);
}
// 23 and lower are used
static mut MSI_IRQ: u32 = 23;
let orig = am.read16(ops, loc, PCI_COMMAND);
// IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable
am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32);
// find MSI cap
let mut msi_found = false;
let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16;
let mut assigned_irq = None;
while cap_ptr > 0 {
let cap_id = am.read8(ops, loc, cap_ptr);
if cap_id == PCI_CAP_ID_MSI {
let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP);
// The manual Volume 3 Chapter 10.11 Message Signalled Interrupts
// 0 is (usually) the apic id of the bsp.
//am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12));
am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000);
MSI_IRQ += 1;
let irq = MSI_IRQ;
assigned_irq = Some(irq as usize);
// we offset all our irq numbers by 32
if (orig_ctrl >> 16) & (1 << 7) != 0 {
// 64bit
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_64, irq + 32);
} else {
// 32bit
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_32, irq + 32);
}
// enable MSI interrupt, assuming 64bit for now
am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000);
debug!(
"MSI control {:#b}, enabling MSI interrupt {}",
orig_ctrl >> 16,
irq
);
msi_found = true;
}
debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr);
cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16;
}
if !msi_found {
// Use PCI legacy interrupt instead
// IO Space | MEM Space | Bus Mastering | Special Cycles
am.write32(ops, loc, PCI_COMMAND, (orig | 0xf) as u32);
debug!("MSI not found, using PCI interrupt");
}
info!("pci device enable done");
assigned_irq
}
pub fn init_driver(dev: &PCIDevice, mapper: &Option<Arc<dyn IoMapper>>) -> DeviceResult<Device> {
let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function);
match (dev.id.vendor_id, dev.id.device_id) {
(0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => {
// 0x100e
// 82540EM Gigabit Ethernet Controller
// 0x100f
// 82545EM Gigabit Ethernet Controller (Copper)
// 0x10d3
// 82574L Gigabit Network Connection
// (e1000e 8086:10d3)
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
info!("Found e1000e dev {:?} BAR0 {:#x?}", dev, addr);
#[cfg(target_arch = "riscv64")]
let addr = if addr == 0 { E1000_BASE as u64 } else { addr };
if let Some(m) = mapper {
m.query_or_map(addr as usize, PAGE_SIZE * 8);
}
let irq = unsafe { enable(dev.loc, addr) };
let vaddr = phys_to_virt(addr as usize);
let dev = Device::Net(Arc::new(crate::net::e1000::init(
name,
irq.unwrap_or(0),
vaddr,
len as usize,
0,
)?));
return Ok(dev);
}
}
(0x8086, 0x10fb) => {
// 82599ES 10-Gigabit SFI/SFP+ Network Connection
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
let irq = unsafe { enable(dev.loc, 0) };
let vaddr = phys_to_virt(addr as usize);
info!("Found ixgbe dev {:#x}, irq: {:?}", vaddr, irq);
/*
let index = NET_DRIVERS.read().len();
PCI_DRIVERS.lock().insert(
dev.loc,
ixgbe::ixgbe_init(name, irq, vaddr, len as usize, index),
);
*/
return Err(DeviceError::NotSupported);
}
}
(0x8086, 0x1533) => {
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
info!("Intel Corporation I210 Gigabit Network Connection");
info!("DEV: {:?}, BAR0: {:#x}", dev, addr);
return Err(DeviceError::NotSupported);
}
}
(0x8086, 0x1539) => {
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
info!(
"Found Intel I211 ethernet controller dev {:?}, addr: {:x?}",
dev, addr
);
return Err(DeviceError::NotSupported);
}
}
_ => {}
}
if dev.id.class == 0x01 && dev.id.subclass == 0x06 {
// Mass storage class
// SATA subclass
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] {
info!("Found AHCI dev {:?} BAR5 {:x?}", dev, addr);
/*
let irq = unsafe { enable(dev.loc) };
assert!(len as usize <= PAGE_SIZE);
let vaddr = phys_to_virt(addr as usize);
if let Some(driver) = ahci::init(irq, vaddr, len as usize) {
PCI_DRIVERS.lock().insert(dev.loc, driver);
}
*/
return Err(DeviceError::NotSupported);
}
}
Err(DeviceError::NoResources)
}
pub fn detach_driver(loc: &Location) -> bool {
/*
match PCI_DRIVERS.lock().remove(loc) {
Some(driver) => {
DRIVERS
.write()
.retain(|dri| dri.get_id() != driver.get_id());
NET_DRIVERS
.write()
.retain(|dri| dri.get_id() != driver.get_id());
true
}
None => false,
}
*/
false
}
pub fn init(mapper: Option<Arc<dyn IoMapper>>) -> DeviceResult<Vec<Device>> {
let mapper_driver = if let Some(m) = mapper {
m.query_or_map(PCI_BASE, PAGE_SIZE * 256 * 32 * 8);
Some(m)
} else {
None
};
let mut dev_list = Vec::new();
let pci_iter = unsafe { scan_bus(&PortOpsImpl, PCI_ACCESS) };
info!("");
info!("--------- PCI bus:device:function ---------");
for dev in pci_iter {
info!(
"pci: {}:{}:{} {:04x}:{:04x} ({} {}) irq: {}:{:?}",
dev.loc.bus,
dev.loc.device,
dev.loc.function,
dev.id.vendor_id,
dev.id.device_id,
dev.id.class,
dev.id.subclass,
dev.pic_interrupt_line,
dev.interrupt_pin,
);
let res = init_driver(&dev, &mapper_driver);
match res {
Ok(d) => dev_list.push(d),
Err(e) => warn!(
"{:?}, failed to initialize PCI device: {:04x}:{:04x}",
e, dev.id.vendor_id, dev.id.device_id
),
}
}
info!("---------");
info!("");
Ok(dev_list)
}
pub fn find_device(vendor: u16, product: u16) -> Option<Location> {
let pci_iter = unsafe { scan_bus(&PortOpsImpl, PCI_ACCESS) };
for dev in pci_iter {
if dev.id.vendor_id == vendor && dev.id.device_id == product {
return Some(dev.loc);
}
}
None
}
pub fn get_bar0_mem(loc: Location) -> Option<(usize, usize)> {
unsafe { probe_function(&PortOpsImpl, loc, PCI_ACCESS) }
.and_then(|dev| dev.bars[0])
.map(|bar| match bar {
BAR::Memory(addr, len, _, _) => (addr as usize, len as usize),
_ => unimplemented!(),
})
}
// all devices stored inAllDeviceList

View File

@ -1,3 +1,5 @@
//! Only UEFI Display currently.
mod uefi;
pub use uefi::UefiDisplay;

View File

@ -1,3 +1,5 @@
//! Only Mouse currently.
mod mouse;
pub mod input_event_codes;

View File

@ -1,6 +1,6 @@
use alloc::{boxed::Box, sync::Arc};
use spin::Mutex;
use lock::Mutex;
use crate::prelude::{CapabilityType, InputEvent, InputEventType};
use crate::scheme::{impl_event_scheme, InputScheme};

View File

@ -1,12 +1,10 @@
use core::mem::MaybeUninit;
use super::Io;
use core::ops::{BitAnd, BitOr, Not};
use super::Io;
// 主存映射 I/O。
/// Memory-mapped I/O.
#[repr(transparent)]
pub struct Mmio<T> {
value: MaybeUninit<T>,
}
pub struct Mmio<T>(T);
impl<T> Mmio<T> {
/// # Safety
@ -25,9 +23,7 @@ impl<T> Mmio<T> {
}
pub fn add<'a>(&self, offset: usize) -> &'a mut Self {
unsafe {
Self::from_base(self.value.as_ptr() as usize + offset * core::mem::size_of::<T>())
}
unsafe { Self::from_base((&self.0 as *const T).add(offset) as _) }
}
}
@ -38,10 +34,20 @@ where
type Value = T;
fn read(&self) -> T {
unsafe { core::ptr::read_volatile(self.value.as_ptr()) }
#[allow(clippy::let_and_return)]
unsafe {
let val = core::ptr::read_volatile(&self.0 as *const _);
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
core::arch::asm!("fence i,r");
val
}
}
fn write(&mut self, value: T) {
unsafe { core::ptr::write_volatile(self.value.as_mut_ptr(), value) };
unsafe {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
core::arch::asm!("fence w,o");
core::ptr::write_volatile(&mut self.0 as *mut _, value)
};
}
}

View File

@ -1,55 +1,79 @@
// 封装对外设地址空间的访问,包括内存映射 IO 和端口映射 IO。
//
// 要了解这两种访问外设的方式,查看[维基百科](https://en.wikipedia.org/wiki/Memory-mapped_I/O)。
//! Peripheral address space access, including memory-mapped IO and port-mapped IO.
//!
//! About these two methods of performing I/O, see [wikipedia](https://en.wikipedia.org/wiki/Memory-mapped_I/O).
use core::ops::{BitAnd, BitOr, Not};
mod mmio;
#[cfg(target_arch = "x86_64")]
mod pio;
mod pmio;
pub use mmio::Mmio;
#[cfg(target_arch = "x86_64")]
pub use pio::Pio;
pub use pmio::Pmio;
// 用于处理外设地址空间访问的接口。
/// An interface for dealing with device address space access.
pub trait Io {
// 可访问的对象的类型。
/// The type of object to access.
type Value: Copy
+ BitAnd<Output = Self::Value>
+ BitOr<Output = Self::Value>
+ Not<Output = Self::Value>;
// 从外设读取值。
/// Reads value from device.
fn read(&self) -> Self::Value;
// 向外设写入值。
/// Writes `value` to device.
fn write(&mut self, value: Self::Value);
}
// 外设地址空间的一个只读单元。
/// A readonly unit in device address space.
#[repr(transparent)]
pub struct ReadOnly<I> {
inner: I,
}
pub struct ReadOnly<I>(I);
impl<I> ReadOnly<I> {
pub const fn new(inner: I) -> ReadOnly<I> {
ReadOnly { inner }
// 构造外设地址空间的一个只读单元。
/// Constructs a readonly unit in device address space.
pub const fn new(inner: I) -> Self {
Self(inner)
}
}
impl<I: Io> ReadOnly<I> {
// 从外设读取值。
/// Reads value from device.
#[inline(always)]
pub fn read(&self) -> I::Value {
self.inner.read()
self.0.read()
}
}
// 外设地址空间的一个只写单元。
/// A write-only unit in device address space.
#[repr(transparent)]
pub struct WriteOnly<I> {
inner: I,
}
pub struct WriteOnly<I>(I);
impl<I> WriteOnly<I> {
pub const fn new(inner: I) -> WriteOnly<I> {
WriteOnly { inner }
// 构造外设地址空间的一个只写单元。
/// Constructs a write-only unit in device address space.
pub const fn new(inner: I) -> Self {
Self(inner)
}
}
impl<I: Io> WriteOnly<I> {
// 向外设写入值。
/// Writes `value` to device.
#[inline(always)]
pub fn write(&mut self, value: I::Value) {
self.inner.write(value)
self.0.write(value);
}
}

View File

@ -1,30 +1,35 @@
use core::arch::asm;
use core::marker::PhantomData;
// 端口映射 I/O。
//! Port-mapped I/O.
use super::Io;
use core::{arch::asm, marker::PhantomData};
/// Generic PIO
// 端口映射 I/O。
/// Port-mapped I/O.
#[derive(Copy, Clone)]
pub struct Pio<T> {
pub struct Pmio<T> {
port: u16,
_phantom: PhantomData<T>,
}
impl<T> Pio<T> {
/// Create a PIO from a given port
impl<T> Pmio<T> {
// 映射指定端口进行外设访问。
/// Maps a given port to assess device.
pub const fn new(port: u16) -> Self {
Pio::<T> {
Self {
port,
_phantom: PhantomData,
}
}
}
/// Read/Write for byte PIO
impl Io for Pio<u8> {
// 逐字节端口映射读写。
/// Read/Write for byte PMIO.
impl Io for Pmio<u8> {
type Value = u8;
/// Read
// 读。
/// Read.
#[inline(always)]
fn read(&self) -> u8 {
let value: u8;
@ -34,7 +39,8 @@ impl Io for Pio<u8> {
value
}
/// Write
// 写。
/// Write.
#[inline(always)]
fn write(&mut self, value: u8) {
unsafe {
@ -43,11 +49,13 @@ impl Io for Pio<u8> {
}
}
/// Read/Write for word PIO
impl Io for Pio<u16> {
// 逐字端口映射读写。
/// Read/Write for word PMIO.
impl Io for Pmio<u16> {
type Value = u16;
/// Read
// 读。
/// Read.
#[inline(always)]
fn read(&self) -> u16 {
let value: u16;
@ -57,7 +65,8 @@ impl Io for Pio<u16> {
value
}
/// Write
// 写。
/// Write.
#[inline(always)]
fn write(&mut self, value: u16) {
unsafe {
@ -66,11 +75,13 @@ impl Io for Pio<u16> {
}
}
/// Read/Write for doubleword PIO
impl Io for Pio<u32> {
// 逐双字端口映射读写。
/// Read/Write for double-word PMIO.
impl Io for Pmio<u32> {
type Value = u32;
/// Read
// 读。
/// Read.
#[inline(always)]
fn read(&self) -> u32 {
let value: u32;
@ -80,7 +91,8 @@ impl Io for Pio<u32> {
value
}
/// Write
// 写。
/// Write.
#[inline(always)]
fn write(&mut self, value: u32) {
unsafe {

View File

@ -1,8 +1,11 @@
//! External interrupt request and handle.
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
mod riscv_intc;
mod riscv_plic;
/// Implementation of risc-v interrupt controller.
#[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))]
pub mod riscv {
pub use super::riscv_intc::{Intc, ScauseIntCode};
@ -10,7 +13,7 @@ cfg_if::cfg_if! {
}
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
mod x86_apic;
/// Implementation of x86 Advanced Programmable Interrupt Controller.
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
pub mod x86 {
pub use super::x86_apic::Apic;

View File

@ -1,5 +1,5 @@
use lock::Mutex;
use riscv::register::sie;
use spin::Mutex;
use crate::prelude::IrqHandler;
use crate::scheme::{IrqScheme, Scheme};

View File

@ -1,6 +1,7 @@
use core::arch::asm;
use core::ops::Range;
use spin::Mutex;
use lock::Mutex;
use crate::io::{Io, Mmio};
use crate::prelude::IrqHandler;
@ -38,8 +39,7 @@ impl PlicUnlocked {
let hart_id = cpu_id() as usize;
let mmio = self
.enable_base
.add(PLIC_ENABLE_HART_OFFSET * hart_id)
.add(irq_num / 32);
.add(PLIC_ENABLE_HART_OFFSET * hart_id + irq_num / 32);
let mask = 1 << (irq_num % 32);
if enable {
@ -54,8 +54,7 @@ impl PlicUnlocked {
let hart_id = cpu_id() as usize;
let irq_num = self
.context_base
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
.add(PLIC_CONTEXT_CLAIM)
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id + PLIC_CONTEXT_CLAIM)
.read() as usize;
if irq_num == 0 {
None
@ -69,8 +68,7 @@ impl PlicUnlocked {
debug_assert!(IRQ_RANGE.contains(&irq_num));
let hart_id = cpu_id() as usize;
self.context_base
.add(PLIC_CONTEXT_CLAIM)
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
.add(PLIC_CONTEXT_CLAIM + PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
.write(irq_num as _);
}
@ -84,8 +82,7 @@ impl PlicUnlocked {
fn set_threshold(&mut self, threshold: u8) {
let hart_id = cpu_id() as usize;
self.context_base
.add(PLIC_PRIORITY_HART_OFFSET * hart_id)
.add(PLIC_CONTEXT_THRESHOLD)
.add(PLIC_PRIORITY_HART_OFFSET * hart_id + PLIC_CONTEXT_THRESHOLD)
.write(threshold as _);
}

View File

@ -3,7 +3,7 @@ use core::{fmt, ptr::NonNull};
use acpi::platform::interrupt::InterruptModel;
use acpi::{AcpiHandler, AcpiTables, PhysicalMapping};
use spin::Mutex;
use lock::Mutex;
use x2apic::ioapic::{IoApic as IoApicInner, IrqFlags, IrqMode};
use super::{IrqPolarity, IrqTriggerMode, Phys2VirtFn};
@ -66,9 +66,23 @@ impl IoApic {
let mut inner = unsafe { IoApicInner::new(base_vaddr as u64) };
let max_entry = unsafe { inner.max_table_entry() };
unsafe { assert_eq!(id, inner.id()) };
// disable all interrupts
unsafe {
inner.init(super::X86_INT_BASE as u8);
}
for i in 0..max_entry + 1 {
unsafe { inner.disable_irq(i) }
unsafe {
// disable all interrupts
inner.disable_irq(i);
// Clean the redirection table
let mut entry = inner.table_entry(i);
entry.set_vector(0);
entry.set_dest(0);
entry.set_mode(IrqMode::Fixed);
entry.set_flags(IrqFlags::MASKED);
inner.set_table_entry(i, entry);
}
}
Self {
id,

View File

@ -1,4 +1,6 @@
use x2apic::lapic::{xapic_base, LocalApic as LocalApicInner, LocalApicBuilder};
use x2apic::lapic::{
xapic_base, LocalApic as LocalApicInner, LocalApicBuilder, TimerDivide, TimerMode,
};
use super::{consts, Phys2VirtFn};
@ -47,4 +49,24 @@ impl LocalApic {
pub fn eoi(&mut self) {
unsafe { self.inner.end_of_interrupt() }
}
pub fn disable_timer(&mut self) {
unsafe { self.inner.disable_timer() }
}
pub fn enable_timer(&mut self) {
unsafe { self.inner.enable_timer() }
}
pub fn set_timer_mode(&mut self, mode: TimerMode) {
unsafe { self.inner.set_timer_mode(mode) }
}
pub fn set_timer_divide(&mut self, divide: TimerDivide) {
unsafe { self.inner.set_timer_divide(divide) }
}
pub fn set_timer_initial(&mut self, initial: u32) {
unsafe { self.inner.set_timer_initial(initial) }
}
}

View File

@ -2,22 +2,21 @@ mod consts;
mod ioapic;
mod lapic;
use core::ops::Range;
use spin::Mutex;
use self::consts::{X86_INT_BASE, X86_INT_LOCAL_APIC_BASE};
use self::ioapic::{IoApic, IoApicList};
use self::lapic::LocalApic;
use crate::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
use crate::scheme::{IrqScheme, Scheme};
use crate::{utils::IrqManager, DeviceError, DeviceResult, PhysAddr, VirtAddr};
use core::ops::Range;
use lock::Mutex;
const IOAPIC_IRQ_RANGE: Range<usize> = X86_INT_BASE..X86_INT_LOCAL_APIC_BASE;
const LAPIC_IRQ_RANGE: Range<usize> = 0..16;
type Phys2VirtFn = fn(paddr: PhysAddr) -> VirtAddr;
/// Advanced Programmable Interrupt Controller
pub struct Apic {
ioapic_list: IoApicList,
manager_ioapic: Mutex<IrqManager<256>>,
@ -25,6 +24,7 @@ pub struct Apic {
}
impl Apic {
/// Construct a new `Apic`.
pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self {
Self {
ioapic_list: IoApicList::new(acpi_rsdp, phys_to_virt),
@ -81,9 +81,8 @@ impl Scheme for Apic {
fn handle_irq(&self, vector: usize) {
Self::local_apic().eoi();
let res = if vector >= X86_INT_LOCAL_APIC_BASE {
self.manager_lapic
.lock()
.handle(vector - X86_INT_LOCAL_APIC_BASE)
let handler = self.manager_lapic.lock();
handler.handle(vector - X86_INT_LOCAL_APIC_BASE)
} else {
self.manager_ioapic.lock().handle(vector)
};
@ -169,4 +168,9 @@ impl IrqScheme for Apic {
Err(DeviceError::InvalidParam)
}
}
fn apic_timer_enable(&self) {
// SAFETY: this will called only once for every core
Apic::local_apic().enable_timer();
}
}

View File

@ -1,3 +1,5 @@
//! Device drivers of zCore.
#![cfg_attr(not(feature = "mock"), no_std)]
#![feature(doc_cfg)]
@ -18,6 +20,7 @@ pub mod mock;
pub mod virtio;
pub mod builder;
pub mod bus;
pub mod display;
pub mod input;
pub mod io;
@ -28,6 +31,7 @@ pub mod scheme;
pub mod uart;
pub mod utils;
/// The error type for external device.
#[derive(Debug)]
pub enum DeviceError {
/// The buffer is too small.
@ -48,19 +52,28 @@ pub enum DeviceError {
NotSupported,
}
/// A type alias for the result of a device operation.
pub type DeviceResult<T = ()> = core::result::Result<T, DeviceError>;
/// Static shell of shared dynamic device [`Scheme`](crate::scheme::Scheme) types.
#[derive(Clone)]
pub enum Device {
/// Block device
Block(Arc<dyn scheme::BlockScheme>),
/// Display device
Display(Arc<dyn scheme::DisplayScheme>),
/// Input device
Input(Arc<dyn scheme::InputScheme>),
/// Interrupt request and handle
Irq(Arc<dyn scheme::IrqScheme>),
/// Network device
Net(Arc<dyn scheme::NetScheme>),
/// Uart port
Uart(Arc<dyn scheme::UartScheme>),
}
impl Device {
/// Get a general [`Scheme`](scheme::Scheme) from the device.
pub fn inner(&self) -> Arc<dyn scheme::Scheme> {
match self {
Self::Block(d) => d.clone().upcast(),

View File

@ -1,3 +1,5 @@
//! Mock devices, including display, input, uart and graphic.
pub mod display;
pub mod input;
pub mod uart;

View File

@ -1,7 +1,7 @@
use std::collections::VecDeque;
use async_std::{io, io::prelude::*, task};
use spin::Mutex;
use lock::Mutex;
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
use crate::utils::EventListener;

218
drivers/src/net/e1000.rs Normal file
View File

@ -0,0 +1,218 @@
//! Intel PRO/1000 Network Adapter i.e. e1000 network driver
//! Datasheet: https://www.intel.ca/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use smoltcp::iface::*;
use smoltcp::phy::{self, DeviceCapabilities};
use smoltcp::time::Instant;
use smoltcp::wire::*;
use smoltcp::Result;
use super::ProviderImpl;
use super::PAGE_SIZE;
use crate::net::get_sockets;
use crate::scheme::{NetScheme, Scheme};
use crate::{DeviceError, DeviceResult};
use isomorphic_drivers::net::ethernet::intel::e1000::E1000;
use isomorphic_drivers::net::ethernet::structs::EthernetAddress as DriverEthernetAddress;
use lock::Mutex;
#[derive(Clone)]
pub struct E1000Driver(Arc<Mutex<E1000<ProviderImpl>>>);
#[derive(Clone)]
pub struct E1000Interface {
iface: Arc<Mutex<Interface<'static, E1000Driver>>>,
driver: E1000Driver,
name: String,
irq: usize,
}
impl Scheme for E1000Interface {
fn name(&self) -> &str {
"e1000"
}
fn handle_irq(&self, irq: usize) {
if irq != self.irq {
// not ours, skip it
return;
}
let data = self.driver.0.lock().handle_interrupt();
if data {
//let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
// Fix me
let timestamp = Instant::from_millis(0);
let sockets = get_sockets();
let mut sockets = sockets.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(p) => {
//SOCKET_ACTIVITY.notify_all();
info!("e1000 try_handle_interrupt poll: {:?}", p);
}
Err(err) => {
warn!("poll got err {}", err);
}
}
}
}
}
impl NetScheme for E1000Interface {
fn get_mac(&self) -> EthernetAddress {
self.iface.lock().ethernet_addr()
}
fn get_ifname(&self) -> String {
self.name.clone()
}
// get ip addresses
fn get_ip_address(&self) -> Vec<IpCidr> {
Vec::from(self.iface.lock().ip_addrs())
}
fn poll(&self) -> DeviceResult {
//let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
let timestamp = Instant::from_millis(0);
let sockets = get_sockets();
let mut sockets = sockets.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(p) => {
//SOCKET_ACTIVITY.notify_all();
info!("e1000 NetScheme poll: {:?}", p);
Ok(())
}
Err(err) => {
warn!("poll got err {}", err);
Err(DeviceError::IoError)
}
}
}
fn recv(&self, buf: &mut [u8]) -> DeviceResult<usize> {
if let Some(vec_recv) = self.driver.0.lock().receive() {
buf.copy_from_slice(&vec_recv);
Ok(vec_recv.len())
} else {
Err(DeviceError::NotReady)
}
}
fn send(&self, data: &[u8]) -> DeviceResult<usize> {
if self.driver.0.lock().can_send() {
let mut driver = self.driver.0.lock();
driver.send(data);
Ok(data.len())
} else {
Err(DeviceError::NotReady)
}
}
}
pub struct E1000RxToken(Vec<u8>);
pub struct E1000TxToken(E1000Driver);
impl phy::Device<'_> for E1000Driver {
type RxToken = E1000RxToken;
type TxToken = E1000TxToken;
fn receive(&mut self) -> Option<(Self::RxToken, Self::TxToken)> {
self.0
.lock()
.receive()
.map(|vec| (E1000RxToken(vec), E1000TxToken(self.clone())))
}
fn transmit(&mut self) -> Option<Self::TxToken> {
if self.0.lock().can_send() {
Some(E1000TxToken(self.clone()))
} else {
None
}
}
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = 1536;
caps.max_burst_size = Some(64);
caps
}
}
impl phy::RxToken for E1000RxToken {
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> Result<R>
where
F: FnOnce(&mut [u8]) -> Result<R>,
{
f(&mut self.0)
}
}
impl phy::TxToken for E1000TxToken {
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
where
F: FnOnce(&mut [u8]) -> Result<R>,
{
let mut buffer = [0u8; PAGE_SIZE];
let result = f(&mut buffer[..len]);
let mut driver = (self.0).0.lock();
driver.send(&buffer);
result
}
}
// JudgeDuck-OS/kern/e1000.c
pub fn init(
name: String,
irq: usize,
header: usize,
size: usize,
index: usize,
) -> DeviceResult<E1000Interface> {
info!("Probing e1000 {}", name);
// randomly generated
let mac: [u8; 6] = [0x54, 0x51, 0x9F, 0x71, 0xC0, index as u8];
let e1000 = E1000::new(header, size, DriverEthernetAddress::from_bytes(&mac));
let net_driver = E1000Driver(Arc::new(Mutex::new(e1000)));
let ethernet_addr = EthernetAddress::from_bytes(&mac);
let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 2, (15 + index) as u8), 24)];
let default_v4_gw = Ipv4Address::new(10, 0, 2, 2); //Qemu user network gateway: 10.0.2.2
static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1];
let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) };
routes.add_default_ipv4_route(default_v4_gw).unwrap();
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let iface = InterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr)
.neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs)
.routes(routes)
.finalize();
info!(
"e1000 interface {} up with addr 10.0.2.{}/24",
name,
15 + index
);
let e1000_iface = E1000Interface {
iface: Arc::new(Mutex::new(iface)),
driver: net_driver,
name,
irq,
};
Ok(e1000_iface)
}

View File

@ -5,7 +5,7 @@ use crate::net::get_sockets;
use alloc::sync::Arc;
use alloc::string::String;
use spin::Mutex;
use lock::Mutex;
use crate::scheme::{NetScheme, Scheme};
use crate::{DeviceError, DeviceResult};
@ -54,7 +54,7 @@ impl NetScheme for LoopbackInterface {
fn get_ifname(&self) -> String {
unimplemented!()
}
fn get_ip_addrrs(&self) -> Vec<IpCidr> {
fn get_ip_address(&self) -> Vec<IpCidr> {
unimplemented!()
}
}

View File

@ -1,3 +1,6 @@
//! LAN driver, only for Realtek currently.
pub mod e1000;
cfg_if::cfg_if! {
if #[cfg(target_arch = "riscv64")] {
mod realtek;
@ -7,6 +10,7 @@ pub use rtlx::*;
}
}
/*
/// External functions that drivers must use
pub trait Provider {
/// Page size (usually 4K)
@ -20,6 +24,8 @@ pub trait Provider {
/// Deallocate DMA
fn dealloc_dma(vaddr: usize, size: usize);
}
*/
pub use isomorphic_drivers::provider::Provider;
pub struct ProviderImpl;
@ -63,7 +69,7 @@ pub use loopback::LoopbackInterface;
use alloc::sync::Arc;
use alloc::vec;
use spin::Mutex;
use lock::Mutex;
use smoltcp::socket::SocketSet;

View File

@ -214,7 +214,6 @@ impl<P> RTL8211F<P>
where
P: Provider,
{
#[allow(clippy::clone_on_copy)]
pub fn new(mac_addr: &[u8; 6]) -> Self {
assert_eq!(size_of::<dma_desc>(), 16);
@ -235,7 +234,7 @@ where
mac[i] = u8::from_str_radix(s, 16).unwrap();
}
} else {
mac = mac_addr.clone();
mac = *mac_addr;
}
info!(
@ -1142,12 +1141,10 @@ where
status = tx_dma_irq_status::tx_hard_error as i32;
}
#[allow(clippy::collapsible_if)]
/* 正常的 TX/RX NORMAL interrupts */
if (intr_status & (TX_INT | RX_INT | RX_EARLY_INT | TX_UA_INT)) != 0 {
if (intr_status & (TX_INT | RX_INT)) != 0 {
status = tx_dma_irq_status::handle_tx_rx as i32;
}
// (intr_status & (TX_INT | RX_INT | RX_EARLY_INT | TX_UA_INT)) != 0
if (intr_status & (TX_INT | RX_INT)) != 0 {
status = tx_dma_irq_status::handle_tx_rx as i32;
}
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
write_volatile((self.base + GETH_INT_STA) as *mut u32, intr_status & 0x3FFF);
@ -1434,7 +1431,6 @@ where
match speed {
1000 => ctrl &= !0x0C,
/*100 | 10 |*/
_ => {
ctrl |= 0x08;
if (speed == 100) {

View File

@ -1,6 +1,6 @@
// c906
use core::arch::asm;
// c906
const FREQUENCY: u64 = 24_000_000; // C906: 24_000_000, Qemu: 10_000_000
const MMIO_MTIMECMP0: *mut u64 = 0x0200_4000usize as *mut u64;
const MMIO_MTIME: *const u64 = 0x0200_BFF8 as *const u64;

View File

@ -1,13 +1,13 @@
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec;
// use alloc::vec;
use alloc::vec::Vec;
use spin::Mutex;
use lock::Mutex;
use smoltcp::iface::*;
use smoltcp::phy::{self, Device, DeviceCapabilities, Medium};
use smoltcp::socket::SocketSet;
// use smoltcp::socket::SocketSet;
use smoltcp::time::Instant;
use smoltcp::wire::*;
use smoltcp::Result;
@ -18,6 +18,7 @@ use super::ProviderImpl;
use super::PAGE_SIZE;
//use kernel_hal::drivers::{Driver, DeviceType, NetDriver, DRIVERS, NET_DRIVERS, SOCKETS};
use crate::net::get_sockets;
use crate::scheme::{NetScheme, Scheme};
use crate::{DeviceError, DeviceResult};
@ -48,13 +49,13 @@ impl Scheme for RTLxInterface {
let handle_tx_rx = 3;
if status == handle_tx_rx {
let timestamp = Instant::from_millis(0);
let mut sockets = SOCKETS.lock(); //引发死锁?
let sockets = get_sockets();
let mut sockets = sockets.lock();
self.driver.0.lock().int_disable();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(_) => {
//SOCKET_ACTIVITY.notify_all();
debug!("try_handle_interrupt SOCKET_ACTIVITY unimplemented");
Ok(b) => {
debug!("nic poll, is changed ?: {}", b);
}
Err(err) => {
error!("poll got err {}", err);
@ -75,17 +76,17 @@ impl NetScheme for RTLxInterface {
self.name.clone()
}
fn get_ip_addrrs(&self) -> Vec<IpCidr> {
fn get_ip_address(&self) -> Vec<IpCidr> {
Vec::from(self.iface.lock().ip_addrs())
}
fn poll(&self) -> DeviceResult {
let timestamp = Instant::from_millis(0);
let mut sockets = SOCKETS.lock();
let sockets = get_sockets();
let mut sockets = sockets.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(_) => {
//SOCKET_ACTIVITY.notify_all();
error!("poll, SOCKET_ACTIVITY unimplemented");
Ok(b) => {
debug!("nic poll, is changed ?: {}", b);
Ok(())
}
Err(err) => {
@ -192,14 +193,20 @@ pub fn rtlx_init<F: Fn(usize, usize) -> Option<usize>>(
let ethernet_addr = EthernetAddress::from_bytes(&mac);
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 0, 123), 24)];
let default_gateway = Ipv4Address::new(192, 168, 0, 1);
static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1];
let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) };
routes.add_default_ipv4_route(default_gateway).unwrap();
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let iface = InterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr)
.neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs)
.routes(routes)
.finalize();
info!("rtl8211f interface up with addr 192.168.0.123/24");
info!("rtl8211f interface up with route 192.168.0.1/24");
let rtl8211f_iface = RTLxInterface {
iface: Arc::new(Mutex::new(iface)),
driver: net_driver,
@ -211,7 +218,7 @@ pub fn rtlx_init<F: Fn(usize, usize) -> Option<usize>>(
}
//TODO: Global SocketSet
lazy_static::lazy_static! {
pub static ref SOCKETS: Mutex<SocketSet<'static>> =
Mutex::new(SocketSet::new(vec![]));
}
// lazy_static::lazy_static! {
// pub static ref SOCKETS: Mutex<SocketSet<'static>> =
// Mutex::new(SocketSet::new(vec![]));
// }

View File

@ -1,8 +1,11 @@
//! Re-export most commonly used driver types.
pub use crate::scheme::display::{ColorFormat, DisplayInfo, FrameBuffer, Rectangle, RgbColor};
pub use crate::scheme::input::{CapabilityType, InputCapability, InputEvent, InputEventType};
pub use crate::scheme::irq::{IrqHandler, IrqPolarity, IrqTriggerMode};
pub use crate::{Device, DeviceError, DeviceResult};
/// Re-export types from [`input`](crate::input).
pub mod input {
pub use crate::input::{Mouse, MouseFlags, MouseState};
}

View File

@ -5,6 +5,7 @@ use core::ops::Range;
use super::Scheme;
use crate::DeviceResult;
/// A type alias for
pub type IrqHandler = Box<dyn Fn() + Send + Sync>;
#[derive(Debug)]
@ -75,4 +76,9 @@ pub trait IrqScheme: Scheme {
fn init_hart(&self) {
unimplemented!()
}
/// [for x86_64] enable apic timer
fn apic_timer_enable(&self) {
unimplemented!()
}
}

View File

@ -1,5 +1,5 @@
//! The [`Scheme`] describe some functions must be implemented for device, there are
//! many [`Scheme`] traits in this mod.
//! The [`Scheme`] describe some functions must be implemented for different type of devices,
//! there are many [`Scheme`] traits in this mod.
//!
//! If you need to develop a new device, just implement the corresponding trait.
//!
@ -26,12 +26,20 @@ pub use irq::IrqScheme;
pub use net::NetScheme;
pub use uart::UartScheme;
/// Common of all device drivers.
///
/// Every device must says its name and handles interrupts.
pub trait Scheme: SchemeUpcast + Send + Sync {
/// Returns name of the driver.
fn name(&self) -> &str;
/// Handles an interrupt.
fn handle_irq(&self, _irq_num: usize) {}
}
/// Used to convert a concrete type pointer to a general [`Scheme`] pointer.
pub trait SchemeUpcast {
/// Performs the conversion.
fn upcast<'a>(self: Arc<Self>) -> Arc<dyn Scheme + 'a>
where
Self: 'a;

View File

@ -9,6 +9,6 @@ pub trait NetScheme: Scheme {
fn send(&self, buf: &[u8]) -> DeviceResult<usize>;
fn get_mac(&self) -> EthernetAddress;
fn get_ifname(&self) -> String;
fn get_ip_addrrs(&self) -> Vec<IpCidr>;
fn get_ip_address(&self) -> Vec<IpCidr>;
fn poll(&self) -> DeviceResult;
}

View File

@ -1,6 +1,6 @@
use alloc::{boxed::Box, collections::VecDeque, string::String, sync::Arc};
use spin::Mutex;
use lock::Mutex;
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
use crate::utils::EventListener;

View File

@ -1,3 +1,5 @@
//! Uart device driver.
mod buffered;
mod uart_16550;
@ -5,4 +7,4 @@ pub use buffered::BufferedUart;
pub use uart_16550::Uart16550Mmio;
#[cfg(target_arch = "x86_64")]
pub use uart_16550::Uart16550Pio;
pub use uart_16550::Uart16550Pmio;

View File

@ -2,7 +2,7 @@ use core::convert::TryInto;
use core::ops::{BitAnd, BitOr, Not};
use bitflags::bitflags;
use spin::Mutex;
use lock::Mutex;
use crate::io::{Io, Mmio, ReadOnly};
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
@ -106,6 +106,7 @@ where
}
}
/// MMIO driver for UART 16550
pub struct Uart16550Mmio<V: 'static>
where
V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V>,
@ -200,20 +201,21 @@ impl Uart16550Mmio<u32> {
}
#[cfg(target_arch = "x86_64")]
mod pio {
mod pmio {
use super::*;
use crate::io::Pio;
use crate::io::Pmio;
pub struct Uart16550Pio {
inner: Mutex<Uart16550Inner<Pio<u8>>>,
/// Pmio driver for UART 16550
pub struct Uart16550Pmio {
inner: Mutex<Uart16550Inner<Pmio<u8>>>,
listener: EventListener,
}
impl_event_scheme!(Uart16550Pio);
impl_event_scheme!(Uart16550Pmio);
impl Scheme for Uart16550Pio {
impl Scheme for Uart16550Pmio {
fn name(&self) -> &str {
"uart16550-pio"
"uart16550-Pmio"
}
fn handle_irq(&self, _irq_num: usize) {
@ -221,7 +223,7 @@ mod pio {
}
}
impl UartScheme for Uart16550Pio {
impl UartScheme for Uart16550Pmio {
fn try_recv(&self) -> DeviceResult<Option<u8>> {
self.inner.lock().try_recv()
}
@ -235,16 +237,17 @@ mod pio {
}
}
impl Uart16550Pio {
impl Uart16550Pmio {
/// Construct a `Uart16550Pmio` whose address starts at `base`.
pub fn new(base: u16) -> Self {
let mut uart = Uart16550Inner::<Pio<u8>> {
data: Pio::new(base),
int_en: Pio::new(base + 1),
fifo_ctrl: Pio::new(base + 2),
line_ctrl: Pio::new(base + 3),
modem_ctrl: Pio::new(base + 4),
line_sts: ReadOnly::new(Pio::new(base + 5)),
modem_sts: ReadOnly::new(Pio::new(base + 6)),
let mut uart = Uart16550Inner::<Pmio<u8>> {
data: Pmio::new(base),
int_en: Pmio::new(base + 1),
fifo_ctrl: Pmio::new(base + 2),
line_ctrl: Pmio::new(base + 3),
modem_ctrl: Pmio::new(base + 4),
line_sts: ReadOnly::new(Pmio::new(base + 5)),
modem_sts: ReadOnly::new(Pmio::new(base + 6)),
};
uart.init();
Self {
@ -256,4 +259,4 @@ mod pio {
}
#[cfg(target_arch = "x86_64")]
pub use pio::Uart16550Pio;
pub use pmio::Uart16550Pmio;

View File

@ -1,9 +1,9 @@
use alloc::vec::Vec;
use core::ops::Range;
use device_tree::{DeviceTree as DeviceTreeInner, PropError};
//! Package of [`device_tree`].
use crate::{DeviceError, DeviceResult, PhysAddr, VirtAddr};
use alloc::vec::Vec;
use core::ops::Range;
use device_tree::{DeviceTree as DeviceTreeInner, PropError};
pub use device_tree::{util::StringList, Node};

View File

@ -1,24 +1,35 @@
use alloc::{boxed::Box, vec::Vec};
use spin::Mutex;
use lock::Mutex;
/// A type alias for the closure to handle device event.
pub type EventHandler<T = ()> = Box<dyn Fn(&T) + Send + Sync>;
/// Device event listener.
///
/// It keeps a series of [`EventHandler`]s that handle events of one single type.
pub struct EventListener<T = ()> {
events: Mutex<Vec<(EventHandler<T>, bool)>>,
}
impl<T> EventListener<T> {
/// Construct a new, empty `EventListener`.
pub fn new() -> Self {
Self {
events: Mutex::new(Vec::new()),
}
}
/// Register a new `handler` into this `EventListener`.
///
/// If `once` is `true`, the `handler` will be removed once it handles an event.
pub fn subscribe(&self, handler: EventHandler<T>, once: bool) {
self.events.lock().push((handler, once));
}
/// Send an event to the `EventListener`.
///
/// All the handlers handle the event, and those marked `once` will be removed immediately.
pub fn trigger(&self, event: T) {
self.events.lock().retain(|(f, once)| {
f(&event);

View File

@ -1,3 +1,5 @@
//! Event handler and device tree.
#![allow(unused_imports)]
mod event_listener;

View File

@ -1,4 +1,4 @@
use spin::Mutex;
use lock::Mutex;
use virtio_drivers::{VirtIOBlk as InnerDriver, VirtIOHeader};
use crate::scheme::{BlockScheme, Scheme};

View File

@ -1,6 +1,6 @@
use core::fmt::{Result, Write};
use spin::Mutex;
use lock::Mutex;
use virtio_drivers::{VirtIOConsole as InnerDriver, VirtIOHeader};
use crate::prelude::DeviceResult;

View File

@ -1,4 +1,4 @@
use spin::Mutex;
use lock::Mutex;
use virtio_drivers::{VirtIOGpu as InnerDriver, VirtIOHeader};
use crate::prelude::{ColorFormat, DisplayInfo, FrameBuffer};

View File

@ -1,6 +1,6 @@
use core::convert::TryFrom;
use spin::Mutex;
use lock::Mutex;
use virtio_drivers::{InputConfigSelect, VirtIOHeader, VirtIOInput as InnerDriver};
use crate::prelude::{CapabilityType, InputCapability, InputEvent, InputEventType};

View File

@ -1,3 +1,5 @@
//! Packaging of [`virtio-drivers` library](https://github.com/rcore-os/virtio-drivers).
mod blk;
mod console;
mod gpu;

View File

@ -1,7 +1,10 @@
[package]
name = "kernel-hal"
version = "0.1.0"
authors = ["Runji Wang <wangrunji0408@163.com>", "Yuekai Jia <equation618@gmail.com>"]
authors = [
"Runji Wang <wangrunji0408@163.com>",
"Yuekai Jia <equation618@gmail.com>",
]
edition = "2018"
description = "Kernel HAL interface definations."
@ -10,32 +13,40 @@ description = "Kernel HAL interface definations."
[features]
default = ["libos"]
smp = []
libos = ["nix", "tempfile", "async-std", "bitmap-allocator", "zcore-drivers/mock"]
libos = [
"nix",
"tempfile",
"async-std",
"bitmap-allocator",
"zcore-drivers/mock",
]
graphic = ["zcore-drivers/graphic"]
loopback = []
[dependencies]
log = "0.4"
spin = "0.9"
cfg-if = "1.0"
bitflags = "1.3"
trapframe = "0.9"
trapframe = "0.9.0"
git-version = "0.3"
numeric-enum-macro = "0.2"
lazy_static = { version = "1.4", features = ["spin_no_std"] }
zcore-drivers = { path = "../drivers", features = ["virtio"] }
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "01b2e70" }
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "async"] }
# LibOS mode
[target.'cfg(not(target_os = "none"))'.dependencies]
nix = { version = "0.23", optional = true }
tempfile = { version = "3", optional = true }
async-std = { version = "1.10", optional = true }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51", optional = true }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator.git", rev = "88e871a5", optional = true }
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
executor = { git = "https://github.com/rcore-os/executor.git", rev = "85b9335" }
executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler", rev = "3b04ba4" }
naive-timer = "0.2.0"
# All mode on x86_64
@ -48,7 +59,8 @@ x86_64 = "0.14"
uefi = "0.11"
raw-cpuid = "9.0"
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "1069df3" }
x2apic = "0.4"
# Bare-metal mode on riscv64
[target.'cfg(all(target_os = "none", target_arch = "riscv64"))'.dependencies]
riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }
riscv = "0.8"

View File

@ -1,5 +1,4 @@
//! CPU information.
use crate::utils::init_once::InitOnce;
pub(super) static CPU_FREQ_MHZ: InitOnce<u16> = InitOnce::new_with_default(10);

View File

@ -62,6 +62,37 @@ pub(super) fn init() -> DeviceResult {
}
}
#[cfg(not(feature = "loopback"))]
{
use alloc::sync::Arc;
use zcore_drivers::bus::pci;
let pci_devs = pci::init(Some(Arc::new(IoMapperImpl)))?;
for d in pci_devs.into_iter() {
drivers::add_device(d);
}
}
intc_init()?;
#[cfg(feature = "graphic")]
if let Some(display) = drivers::all_display().first() {
crate::console::init_graphic_console(display.clone());
if display.need_flush() {
// TODO: support nested interrupt to render in time
crate::thread::spawn(crate::common::future::DisplayFlushFuture::new(display, 30));
}
}
#[cfg(feature = "loopback")]
{
use crate::net;
net::init();
}
Ok(())
}
pub(super) fn intc_init() -> DeviceResult {
let irq = drivers::all_irq()
.find(format!("riscv-intc-cpu{}", crate::cpu::cpu_id()).as_str())
.expect("IRQ device 'riscv-intc' not initialized!");
@ -78,14 +109,5 @@ pub(super) fn init() -> DeviceResult {
irq.unmask(ScauseIntCode::SupervisorSoft as _)?;
irq.unmask(ScauseIntCode::SupervisorTimer as _)?;
#[cfg(feature = "graphic")]
if let Some(display) = drivers::all_display().first() {
crate::console::init_graphic_console(display.clone());
if display.need_flush() {
// TODO: support nested interrupt to render in time
crate::thread::spawn(crate::common::future::DisplayFlushFuture::new(display, 30));
}
}
Ok(())
}

View File

@ -5,11 +5,13 @@ use riscv::{asm, register::sstatus};
hal_fn_impl! {
impl mod crate::hal_fn::interrupt {
fn wait_for_interrupt() {
unsafe {
// enable interrupt and disable
sstatus::set_sie();
asm::wfi();
sstatus::clear_sie();
let enable = sstatus::read().sie();
if !enable {
unsafe { sstatus::set_sie() };
}
unsafe { asm::wfi(); }
if !enable {
unsafe { sstatus::clear_sie() };
}
}
@ -17,5 +19,17 @@ hal_fn_impl! {
trace!("Handle irq cause: {}", cause);
crate::drivers::all_irq().first_unwrap().handle_irq(cause)
}
fn intr_on() {
unsafe { sstatus::set_sie() };
}
fn intr_off() {
unsafe { sstatus::clear_sie() };
}
fn intr_get() -> bool {
sstatus::read().sie()
}
}
}

View File

@ -23,12 +23,12 @@ pub fn free_pmem_regions() -> Vec<Range<PhysAddr>> {
}
if let Some(initrd) = initrd {
// no overlap at all
if initrd.end <= start || initrd.start >= end {
if initrd.end <= start || end <= initrd.start {
regions.push(start..end);
continue;
}
// no overlap on the left
if initrd.start > start {
if start < initrd.start {
regions.push(start..align_down(initrd.start));
}
// no overlap on the right

View File

@ -9,9 +9,8 @@ pub mod sbi;
pub mod timer;
pub mod vm;
use alloc::{boxed::Box, format, string::String, vec::Vec};
use alloc::{string::String, vec::Vec};
use core::ops::Range;
use zcore_drivers::irq::riscv::ScauseIntCode;
use zcore_drivers::utils::devicetree::Devicetree;
use crate::{mem::phys_to_virt, utils::init_once::InitOnce, PhysAddr};
@ -20,6 +19,10 @@ static CMDLINE: InitOnce<String> = InitOnce::new_with_default(String::new());
static INITRD_REGION: InitOnce<Option<Range<PhysAddr>>> = InitOnce::new_with_default(None);
static MEMORY_REGIONS: InitOnce<Vec<Range<PhysAddr>>> = InitOnce::new_with_default(Vec::new());
pub const fn timer_interrupt_vector() -> usize {
trap::SUPERVISOR_TIMER_INT_VEC
}
pub fn cmdline() -> String {
CMDLINE.clone()
}
@ -53,33 +56,19 @@ pub fn primary_init_early() {
pub fn primary_init() {
vm::init();
drivers::init().unwrap();
// We should set first time interrupt before run into first user program
// timer::init();
}
pub fn timer_init() {
timer::init();
}
pub fn secondary_init() {
vm::init();
let intc = crate::drivers::all_irq()
.find(format!("riscv-intc-cpu{}", crate::cpu::cpu_id()).as_str())
.expect("IRQ device 'riscv-intc' not initialized!");
// register soft interrupts handler
intc.register_handler(
ScauseIntCode::SupervisorSoft as _,
Box::new(trap::super_soft),
)
.unwrap();
// register timer interrupts handler
intc.register_handler(
ScauseIntCode::SupervisorTimer as _,
Box::new(trap::super_timer),
)
.unwrap();
intc.unmask(ScauseIntCode::SupervisorSoft as _).unwrap();
intc.unmask(ScauseIntCode::SupervisorTimer as _).unwrap();
drivers::intc_init().unwrap();
let plic = crate::drivers::all_irq()
.find("riscv-plic")
.expect("IRQ device 'riscv-plic' not initialized!");
plic.init_hart();
timer::init();
}

View File

@ -2,6 +2,7 @@ use riscv::register::scause;
use trapframe::TrapFrame;
use crate::context::TrapReason;
pub(super) const SUPERVISOR_TIMER_INT_VEC: usize = 5; // scause::Interrupt::SupervisorTimer
fn breakpoint(sepc: &mut usize) {
info!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc);
@ -14,7 +15,6 @@ fn breakpoint(sepc: &mut usize) {
pub(super) fn super_timer() {
super::timer::timer_set_next();
crate::timer::timer_tick();
//发生外界中断时epc的指令还没有执行故无需修改epc到下一条
}
@ -25,16 +25,22 @@ pub(super) fn super_soft() {
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
// log::warn!("in trap handler");
let scause = scause::read();
trace!("kernel trap happened: {:?}", TrapReason::from(scause));
trace!(
"sepc = 0x{:x} pgtoken = 0x{:x}",
tf.sepc,
crate::vm::current_vmtoken()
);
match TrapReason::from(scause) {
TrapReason::SoftwareBreakpoint => breakpoint(&mut tf.sepc),
TrapReason::PageFault(vaddr, flags) => {
// log::warn!("sepc={:x}", riscv::register::sepc::read());
// log::warn!("sstatus.spp={:?}", riscv::register::sstatus::read().spp());
crate::KHANDLER.handle_page_fault(vaddr, flags)
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
TrapReason::Interrupt(vector) => {
crate::interrupt::handle_irq(vector);
if vector == SUPERVISOR_TIMER_INT_VEC {
executor::handle_timeout();
}
}
TrapReason::Interrupt(vector) => crate::interrupt::handle_irq(vector),
other => panic!("Undefined trap: {:x?} {:#x?}", other, tf),
}
}

View File

@ -3,8 +3,8 @@
use core::fmt::{Debug, Formatter, Result};
use core::slice;
use lock::Mutex;
use riscv::{asm, register::satp};
use spin::Mutex;
use crate::utils::page_table::{GenericPTE, PageTableImpl, PageTableLevel3};
use crate::{mem::phys_to_virt, MMUFlags, PhysAddr, VirtAddr, KCONFIG};

View File

@ -26,8 +26,8 @@ hal_fn_impl! {
fn reset() -> ! {
info!("shutdown...");
loop {
use zcore_drivers::io::{Io, Pio};
Pio::<u16>::new(0x604).write(0x2000);
use zcore_drivers::io::{Io, Pmio};
Pmio::<u16>::new(0x604).write(0x2000);
super::interrupt::wait_for_interrupt();
}
}

View File

@ -2,14 +2,16 @@ use alloc::{boxed::Box, sync::Arc};
use zcore_drivers::irq::x86::Apic;
use zcore_drivers::scheme::IrqScheme;
use zcore_drivers::uart::{BufferedUart, Uart16550Pio};
use zcore_drivers::uart::{BufferedUart, Uart16550Pmio};
use zcore_drivers::{Device, DeviceResult};
use super::trap;
use crate::drivers;
pub(super) fn init_early() -> DeviceResult {
let uart = Arc::new(Uart16550Pio::new(0x3F8));
let uart = Arc::new(Uart16550Pmio::new(0x3F8));
drivers::add_device(Device::Uart(BufferedUart::new(uart)));
let uart = Arc::new(Uart16550Pmio::new(0x2F8));
drivers::add_device(Device::Uart(BufferedUart::new(uart)));
Ok(())
}
@ -20,14 +22,41 @@ pub(super) fn init() -> DeviceResult {
super::special::pc_firmware_tables().0 as usize,
crate::mem::phys_to_virt,
));
irq.register_device(
trap::X86_ISA_IRQ_COM1,
drivers::all_uart().first_unwrap().upcast(),
)?;
irq.unmask(trap::X86_ISA_IRQ_COM1)?;
irq.register_local_apic_handler(trap::X86_INT_APIC_TIMER, Box::new(crate::timer::timer_tick))?;
let uarts = drivers::all_uart();
if let Some(u) = uarts.try_get(0) {
irq.register_device(trap::X86_ISA_IRQ_COM1, u.clone().upcast())?;
irq.unmask(trap::X86_ISA_IRQ_COM1)?;
if let Some(u) = uarts.try_get(1) {
irq.register_device(trap::X86_ISA_IRQ_COM2, u.clone().upcast())?;
irq.unmask(trap::X86_ISA_IRQ_COM2)?;
}
}
use x2apic::lapic::{TimerDivide, TimerMode};
irq.register_local_apic_handler(trap::X86_INT_APIC_TIMER, Box::new(super::trap::super_timer))?;
// SAFETY: this will be called once and only once for every core
Apic::local_apic().set_timer_mode(TimerMode::Periodic);
Apic::local_apic().set_timer_divide(TimerDivide::Div256); // indeed it is Div1, the name is confusing.
let cycles =
super::cpu::cpu_frequency() as u64 * 1_000_000 / super::super::timer::TICKS_PER_SEC;
Apic::local_apic().set_timer_initial(cycles as u32);
Apic::local_apic().disable_timer();
drivers::add_device(Device::Irq(irq));
#[cfg(not(feature = "loopback"))]
{
// PCI scan
use zcore_drivers::bus::pci;
let pci_devs = pci::init(None)?;
for d in pci_devs.into_iter() {
drivers::add_device(d);
}
}
#[cfg(feature = "graphic")]
{
use crate::KCONFIG;
@ -46,6 +75,12 @@ pub(super) fn init() -> DeviceResult {
crate::console::init_graphic_console(display);
}
#[cfg(feature = "loopback")]
{
use crate::net;
net::init();
}
info!("Drivers init end.");
Ok(())
}

View File

@ -5,19 +5,34 @@ use core::ops::Range;
use crate::drivers::all_irq;
use crate::drivers::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
use crate::HalResult;
use x86_64::instructions::interrupts;
hal_fn_impl! {
impl mod crate::hal_fn::interrupt {
fn wait_for_interrupt() {
use x86_64::instructions::interrupts;
let enable = interrupts::are_enabled();
interrupts::enable_and_hlt();
interrupts::disable();
if !enable {
interrupts::disable();
}
}
fn is_valid_irq(gsi: usize) -> bool {
all_irq().first_unwrap().is_valid_irq(gsi)
}
fn intr_on() {
interrupts::enable();
}
fn intr_off() {
interrupts::disable();
}
fn intr_get() -> bool {
interrupts::are_enabled()
}
fn mask_irq(gsi: usize) -> HalResult {
Ok(all_irq().first_unwrap().mask(gsi)?)
}

View File

@ -16,6 +16,10 @@ hal_fn_impl_default!(crate::hal_fn::console);
use crate::{mem::phys_to_virt, KCONFIG};
use x86_64::registers::control::{Cr4, Cr4Flags};
pub const fn timer_interrupt_vector() -> usize {
trap::X86_INT_APIC_TIMER
}
pub fn cmdline() -> alloc::string::String {
KCONFIG.cmdline.into()
}
@ -52,6 +56,10 @@ pub fn primary_init() {
}
}
pub fn timer_init() {
timer::init();
}
pub fn secondary_init() {
zcore_drivers::irq::x86::Apic::init_local_apic_ap();
}

View File

@ -1,6 +1,6 @@
//! Functions only available on x86 platforms.
pub use zcore_drivers::io::{Io, Pio};
pub use zcore_drivers::io::{Io, Pmio};
/// Get physical address of `acpi_rsdp` and `smbios` on x86_64.
pub fn pc_firmware_tables() -> (u64, u64) {

View File

@ -4,3 +4,8 @@ pub fn timer_now() -> Duration {
let cycle = unsafe { core::arch::x86_64::_rdtsc() };
Duration::from_nanos(cycle * 1000 / super::cpu::cpu_frequency() as u64)
}
pub fn init() {
let irq = crate::drivers::all_irq().first_unwrap();
irq.apic_timer_enable();
}

View File

@ -24,6 +24,10 @@ fn breakpoint() {
panic!("\nEXCEPTION: Breakpoint");
}
pub(super) fn super_timer() {
crate::timer::timer_tick();
}
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
trace!(
@ -31,10 +35,16 @@ pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
tf.trap_num,
super::cpu::cpu_id()
);
match TrapReason::from(tf.trap_num, tf.error_code) {
TrapReason::HardwareBreakpoint | TrapReason::SoftwareBreakpoint => breakpoint(),
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
TrapReason::Interrupt(vector) => crate::interrupt::handle_irq(vector),
TrapReason::Interrupt(vector) => {
crate::interrupt::handle_irq(vector);
if vector == X86_INT_APIC_TIMER {
executor::handle_timeout();
}
}
other => panic!("Unhandled trap {:x?} {:#x?}", other, tf),
}
}

View File

@ -1,6 +1,5 @@
//! Bootstrap and initialization.
use super::net;
use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER};
hal_fn_impl! {
@ -24,7 +23,6 @@ hal_fn_impl! {
info!("Primary CPU {} init...", crate::cpu::cpu_id());
unsafe { trapframe::init() };
super::arch::primary_init();
net::init();
}
fn secondary_init() {

View File

@ -2,11 +2,11 @@ cfg_if! {
if #[cfg(target_arch = "x86_64")] {
#[path = "arch/x86_64/mod.rs"]
mod arch;
pub use self::arch::special as x86_64;
pub use self::arch::{special as x86_64, timer_interrupt_vector};
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
#[path = "arch/riscv/mod.rs"]
pub mod arch;
pub use self::arch::sbi;
pub use self::arch::{sbi, timer_interrupt_vector};
}
}

View File

@ -1,3 +1,4 @@
// May need move to drivers
use smoltcp::{
iface::{InterfaceBuilder, NeighborCache, Route, Routes},
phy::{Loopback, Medium},
@ -11,7 +12,7 @@ use alloc::vec::Vec;
use alloc::sync::Arc;
use alloc::string::String;
use spin::Mutex;
use lock::Mutex;
use crate::drivers::add_device;
use crate::drivers::all_net;

View File

@ -3,18 +3,27 @@
use alloc::boxed::Box;
use core::time::Duration;
use core::sync::atomic::{AtomicBool, Ordering};
use lock::Mutex;
use naive_timer::Timer;
use spin::Mutex;
#[allow(dead_code)]
pub(super) const TICKS_PER_SEC: u64 = 100;
lazy_static! {
static ref NAIVE_TIMER: Mutex<Timer> = Mutex::new(Timer::default());
static ref FIRST: AtomicBool = AtomicBool::new(false);
}
hal_fn_impl! {
impl mod crate::hal_fn::timer {
fn timer_enable() {
if !FIRST.load(Ordering::Relaxed) {
FIRST.store(true, Ordering::Relaxed);
super::arch::timer_init();
}
}
fn timer_now() -> Duration {
super::arch::timer::timer_now()
}

View File

@ -2,7 +2,7 @@
use crate::drivers;
use core::fmt::{Arguments, Result, Write};
use spin::Mutex;
use lock::Mutex;
struct SerialWriter;

View File

@ -27,7 +27,7 @@ pub enum UserContextField {
}
/// Reason of the trap.
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq)]
pub enum TrapReason {
Syscall,
Interrupt(usize),
@ -39,6 +39,9 @@ pub enum TrapReason {
GernelFault(usize),
}
#[cfg(not(feature = "libos"))]
pub const TIMER_INTERRUPT_VEC: usize = crate::timer_interrupt_vector();
impl TrapReason {
/// Get [`TrapReason`] from `trap_num` and `error_code` in trap frame for x86.
#[cfg(target_arch = "x86_64")]
@ -113,7 +116,7 @@ impl TrapReason {
/// User context saved on trap.
#[repr(transparent)]
#[derive(Clone)]
#[derive(Clone, Copy)]
pub struct UserContext(UserContextInner);
impl UserContext {
@ -124,35 +127,53 @@ impl UserContext {
}
/// Initialize the context for entry into userspace.
pub fn setup_uspace(&mut self, pc: usize, sp: usize, arg1: usize, arg2: usize) {
/// Note: if the number of args < 3, please fill with zeros
/// Eg: ctx.setup_uspace(pc_, sp_, &[arg1, arg2, 0])
pub fn setup_uspace(&mut self, pc: usize, sp: usize, args: &[usize; 3]) {
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
self.0.general.rip = pc;
self.0.general.rsp = sp;
self.0.general.rdi = arg1;
self.0.general.rsi = arg2;
self.0.general.rdi = args[0];
self.0.general.rsi = args[1];
self.0.general.rdx = args[2];
// IOPL = 3, IF = 1
// FIXME: set IOPL = 0 when IO port bitmap is supporte
self.0.general.rflags = 0x3000 | 0x200 | 0x2;
} else if #[cfg(target_arch = "aarch64")] {
self.0.elr = pc;
self.0.sp = sp;
self.0.general.x0 = arg1;
self.0.general.x1 = arg2;
self.0.general.x0 = args[0];
self.0.general.x1 = args[1];
self.0.general.x2 = args[2];
// Mask SError exceptions (currently unhandled).
// TODO
self.0.spsr = 1 << 8;
} else if #[cfg(target_arch = "riscv64")] {
self.0.sepc = pc;
self.0.general.sp = sp;
self.0.general.a0 = arg1;
self.0.general.a1 = arg2;
self.0.general.a0 = args[0];
self.0.general.a1 = args[1];
self.0.general.a2 = args[2];
// SUM = 1, FS = 0b11, SPIE = 1
self.0.sstatus = 1 << 18 | 0b11 << 13 | 1 << 5;
}
}
}
/// Setup return addr
pub fn set_ra(&mut self, _ra: usize) {
cfg_if! {
if #[cfg(target_arch = "riscv64")] {
self.0.general.ra = _ra;
} else if #[cfg(target_arch = "x86_64")] {
error!("Please set return addr via stack!");
} else {
unimplemented!("Unsupported arch!");
}
}
}
/// Switch to user mode.
pub fn enter_uspace(&mut self) {
cfg_if! {

View File

@ -1,23 +1,42 @@
//! Read/write user space pointer.
// 来自用户空间的裸指针
//! Raw pointer from user land.
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter};
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use crate::VirtAddr;
use alloc::{string::String, vec::Vec};
use core::{
fmt::{Debug, Formatter},
marker::PhantomData,
ops::{Deref, DerefMut},
};
#[repr(C)]
pub struct UserPtr<T, P: Policy> {
ptr: *mut T,
mark: PhantomData<P>,
}
// 来自用户空间的裸指针
/// Raw pointer from user land.
#[repr(transparent)]
pub struct UserPtr<T, P: Policy>(*mut T, PhantomData<P>);
// 标识用户指针功能的基特征。
/// Base trait for Markers of user pointer policy.
pub trait Policy {}
// 标记一个用于输入的指针。
/// Marks a pointer used to read.
pub trait Read: Policy {}
// 标记一个用于输出的指针。
/// Marks a pointer used to write.
pub trait Write: Policy {}
pub enum In {}
pub enum Out {}
pub enum InOut {}
// 输入指针的类型参数。
/// Type argument for user pointer used to read.
pub struct In;
// 输出指针的类型参数。
/// Type argument for user pointer used to write.
pub struct Out;
// 既用于输入有用于输出的指针的类型参数。
/// Type argument for user pointer used to both read and write.
pub struct InOut;
impl Policy for In {}
impl Policy for Out {}
@ -31,9 +50,8 @@ pub type UserInPtr<T> = UserPtr<T, In>;
pub type UserOutPtr<T> = UserPtr<T, Out>;
pub type UserInOutPtr<T> = UserPtr<T, InOut>;
type Result<T> = core::result::Result<T, Error>;
/// The error type which is returned from user pointer.
// 用户指针操作的异常类型。
/// The error type which is returned from user pointer operation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Error {
InvalidUtf8,
@ -43,9 +61,13 @@ pub enum Error {
InvalidVectorAddress,
}
// 本模块用到的只是用户指针操作结果的类型。
type Result<T> = core::result::Result<T, Error>;
impl<T, P: Policy> Debug for UserPtr<T, P> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.ptr)
// 打印用户指针就是打印裸指针
write!(f, "{:?}", self.0)
}
}
@ -54,154 +76,210 @@ unsafe impl<T, P: Policy> Send for UserPtr<T, P> {}
unsafe impl<T, P: Policy> Sync for UserPtr<T, P> {}
impl<T, P: Policy> From<usize> for UserPtr<T, P> {
fn from(x: usize) -> Self {
UserPtr {
ptr: x as _,
mark: PhantomData,
}
fn from(ptr: usize) -> Self {
UserPtr(ptr as _, PhantomData)
}
}
impl<T, P: Policy> UserPtr<T, P> {
// 检查 `size` 是否足够放下一个 `T` 的值,
// 并从 `addr` 构造一个用户指针。
/// Checks if `size` is enough to save a value of `T`,
/// then constructs a user pointer from its value `addr`.
pub fn from_addr_size(addr: usize, size: usize) -> Result<Self> {
if size < core::mem::size_of::<T>() {
return Err(Error::BufferTooSmall);
if size >= core::mem::size_of::<T>() {
Ok(Self::from(addr))
} else {
Err(Error::BufferTooSmall)
}
Ok(Self::from(addr))
}
// 如果指针为空,返回 `true`。
/// Returns `true` if the pointer is null.
pub fn is_null(&self) -> bool {
self.ptr.is_null()
self.0.is_null()
}
// 偏移指针。
// `count` 表示 `T` 的数量;
// 例如,`count` 为 3 表示将指针移动 `3 * size_of::<T>()` 个字节。
/// Calculates the offset from a pointer.
/// `count` is in units of `T`;
/// e.g., a `count` of 3 represents a pointer offset of `3 * size_of::<T>()` bytes.
pub fn add(&self, count: usize) -> Self {
UserPtr {
ptr: unsafe { self.ptr.add(count) },
mark: PhantomData,
}
Self(unsafe { self.0.add(count) }, PhantomData)
}
pub fn as_ptr(&self) -> *mut T {
self.ptr
// 返回指针对应的虚地址。
/// Returns the virtual address represented by the pointer.
pub fn as_addr(&self) -> VirtAddr {
self.0 as _
}
// 检查用户指针是否合法。
//
// 如果指针非空且对齐则返回 `OK(())`。
/// Checks avaliability of the user pointer.
///
/// Returns [`Ok(())`] if it is neither null nor unaligned.
pub fn check(&self) -> Result<()> {
if self.ptr.is_null() {
return Err(Error::InvalidPointer);
if !self.0.is_null() && (self.0 as usize) % core::mem::align_of::<T>() == 0 {
Ok(())
} else {
Err(Error::InvalidPointer)
}
if (self.ptr as usize) % core::mem::align_of::<T>() != 0 {
return Err(Error::InvalidPointer);
}
Ok(())
}
}
impl<T, P: Read> UserPtr<T, P> {
pub fn as_ref(&self) -> Result<&'static T> {
Ok(unsafe { &*self.ptr })
// 取出指针值的引用(不要用于小于 8 字节的类型)。
/// Converts to reference.
#[allow(clippy::should_implement_trait)]
pub fn as_ref(&self) -> &'static T {
unsafe { &*self.0 }
}
// 读取但不移动指针所指的值(通过逐字节拷贝,但不需要 `Copy` 特征)。
// 指针所指的值保持不变。
/// Reads the value from `self` without moving it.
/// This leaves the memory in self unchanged.
pub fn read(&self) -> Result<T> {
// TODO: check ptr and return err
self.check()?;
Ok(unsafe { self.ptr.read() })
Ok(unsafe { self.0.read() })
}
// 和读取一样,
// 但若指针为空,返回 `None`。
/// Same as [`read`](Self::read),
/// but returns [`None`] when pointer is null.
pub fn read_if_not_null(&self) -> Result<Option<T>> {
if self.ptr.is_null() {
return Ok(None);
if !self.0.is_null() {
Ok(Some(self.read()?))
} else {
Ok(None)
}
let value = self.read()?;
Ok(Some(value))
}
// 构造一个从指针指向开始,长度为 `len` 的切片。
/// Forms a slice from a user pointer and a `len`.
pub fn as_slice(&self, len: usize) -> Result<&'static [T]> {
if len == 0 {
Ok(&[])
} else {
self.check()?;
Ok(unsafe { core::slice::from_raw_parts(self.0, len) })
}
}
// 拷贝对象来构造一个 `Vec`。
//
// `len` 是成员的数量,而不是字节数。
/// Copies elements into a new [`Vec`].
///
/// The `len` argument is the number of **elements**, not the number of bytes.
pub fn read_array(&self, len: usize) -> Result<Vec<T>> {
if len == 0 {
return Ok(Vec::default());
Ok(Vec::default())
} else {
self.check()?;
let mut ret = Vec::<T>::with_capacity(len);
unsafe {
ret.set_len(len);
ret.as_mut_ptr().copy_from_nonoverlapping(self.0, len);
}
Ok(ret)
}
self.check()?;
let mut ret = Vec::<T>::with_capacity(len);
unsafe {
ret.set_len(len);
ret.as_mut_ptr().copy_from_nonoverlapping(self.ptr, len);
}
Ok(ret)
}
}
impl<P: Read> UserPtr<u8, P> {
pub fn read_string(&self, len: usize) -> Result<String> {
self.check()?;
let src = unsafe { core::slice::from_raw_parts(self.ptr, len) };
let s = core::str::from_utf8(src).map_err(|_| Error::InvalidUtf8)?;
Ok(String::from(s))
// 构造一个从指针指向开始,长度为 `len` 的字符切片。
/// Forms an utf-8 string slice from a user pointer and a `len`.
pub fn as_str(&self, len: usize) -> Result<&'static str> {
core::str::from_utf8(self.as_slice(len)?).map_err(|_| Error::InvalidUtf8)
}
pub fn read_cstring(&self) -> Result<String> {
self.check()?;
let len = unsafe { (0usize..).find(|&i| *self.ptr.add(i) == 0).unwrap() };
self.read_string(len)
// 从一个 C 风格的零结尾字符串构造一个字符切片。
/// Forms a zero-terminated string slice from a user pointer to a c style string.
pub fn as_c_str(&self) -> Result<&'static str> {
self.as_str(unsafe { (0usize..).find(|&i| *self.0.add(i) == 0).unwrap() })
}
}
impl<P: Read> UserPtr<UserPtr<u8, P>, P> {
impl<P: 'static + Read> UserPtr<UserPtr<u8, P>, P> {
// 拷贝一组 C 风格的零结尾字符串到 `String`
// 并收集到一个 `Vec` 中。
/// Copies a group of zero-terminated string into [`String`]s,
/// and collect them into a [`Vec`].
pub fn read_cstring_array(&self) -> Result<Vec<String>> {
self.check()?;
let len = unsafe {
(0usize..)
.find(|&i| self.ptr.add(i).read().is_null())
.unwrap()
};
self.read_array(len)?
.into_iter()
.map(|ptr| ptr.read_cstring())
.collect()
let mut result = Vec::new();
let mut pptr = self.0;
loop {
let sptr = unsafe { pptr.read() };
if sptr.is_null() {
break;
}
result.push(sptr.as_c_str()?.into());
pptr = unsafe { pptr.add(1) };
}
Ok(result)
}
}
impl<T, P: Write> UserPtr<T, P> {
// 用指定的值覆盖指针位置。
// 旧的值直接被覆盖,不会调用释放逻辑。
/// Overwrites a memory location with the given `value`
/// **without** reading or dropping the old value.
pub fn write(&mut self, value: T) -> Result<()> {
self.check()?;
unsafe {
self.ptr.write(value);
}
unsafe { self.0.write(value) };
Ok(())
}
// 类似于写,
// 但指针为空时返回 `Ok(())`。
/// Same as [`write`](Self::write),
/// but does nothing and returns [`Ok`] when pointer is null.
pub fn write_if_not_null(&mut self, value: T) -> Result<()> {
if self.ptr.is_null() {
return Ok(());
if !self.0.is_null() {
self.write(value)
} else {
Ok(())
}
self.write(value)
}
// 写入 `values.len() * size_of<T>` 字节到指针位置。
// 写入的区间与目标区间不可重叠。
/// Copies `values.len() * size_of<T>` bytes from `values` to `self`.
/// The source and destination may not overlap.
pub fn write_array(&mut self, values: &[T]) -> Result<()> {
if values.is_empty() {
return Ok(());
}
self.check()?;
unsafe {
self.ptr
.copy_from_nonoverlapping(values.as_ptr(), values.len());
if !values.is_empty() {
self.check()?;
unsafe {
self.0
.copy_from_nonoverlapping(values.as_ptr(), values.len())
};
}
Ok(())
}
}
impl<P: Write> UserPtr<u8, P> {
// 拷贝指定字符串到目标位置并写入一个 `\0` 来模拟 C 风格零结尾字符串。
/// Copies `s` to `self`, then write a `'\0'` for c style string.
pub fn write_cstring(&mut self, s: &str) -> Result<()> {
let bytes = s.as_bytes();
self.write_array(bytes)?;
unsafe {
self.ptr.add(bytes.len()).write(0);
}
unsafe { self.0.add(bytes.len()).write(0) };
Ok(())
}
}
#[derive(Debug)]
#[repr(C)]
pub struct IoVec<P: Policy> {
pub struct IoVec<P: 'static + Policy> {
/// Starting address
ptr: UserPtr<u8, P>,
/// Number of bytes to transfer
@ -213,13 +291,13 @@ pub type IoVecOut = IoVec<Out>;
/// A valid IoVecs request from user
#[derive(Debug)]
pub struct IoVecs<P: Policy> {
pub struct IoVecs<P: 'static + Policy> {
vec: Vec<IoVec<P>>,
}
impl<P: Policy> UserInPtr<IoVec<P>> {
pub fn read_iovecs(&self, count: usize) -> Result<IoVecs<P>> {
if self.ptr.is_null() {
if self.0.is_null() {
return Err(Error::InvalidPointer);
}
let vec = self.read_array(count)?;
@ -246,7 +324,7 @@ impl<P: Read> IoVecs<P> {
pub fn read_to_vec(&self) -> Result<Vec<u8>> {
let mut buf = Vec::new();
for vec in self.vec.iter() {
buf.extend(vec.ptr.read_array(vec.len)?);
buf.extend_from_slice(vec.ptr.as_slice(vec.len)?);
}
Ok(buf)
}
@ -299,20 +377,14 @@ impl<P: Policy> IoVec<P> {
}
pub fn as_slice(&self) -> Result<&[u8]> {
if self.ptr.is_null() {
return Err(Error::InvalidVectorAddress);
}
let slice = unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) };
Ok(slice)
self.as_mut_slice().map(|s| &*s)
}
}
impl<P: Write> IoVec<P> {
pub fn as_mut_slice(&mut self) -> Result<&mut [u8]> {
if self.ptr.is_null() {
return Err(Error::InvalidVectorAddress);
pub fn as_mut_slice(&self) -> Result<&mut [u8]> {
if !self.ptr.is_null() {
Ok(unsafe { core::slice::from_raw_parts_mut(self.ptr.0, self.len) })
} else {
Err(Error::InvalidVectorAddress)
}
let slice = unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) };
Ok(slice)
}
}

View File

@ -3,7 +3,7 @@
use alloc::{sync::Arc, vec::Vec};
use core::convert::From;
use spin::{RwLock, RwLockReadGuard};
use lock::{RwLock, RwLockReadGuard};
use zcore_drivers::scheme::{
BlockScheme, DisplayScheme, InputScheme, IrqScheme, NetScheme, Scheme, UartScheme,

View File

@ -97,6 +97,15 @@ hal_fn_def! {
/// Is a valid IRQ number.
pub fn is_valid_irq(vector: usize) -> bool;
/// Enable the interrupts
pub fn intr_on();
/// Disable the interrupts
pub fn intr_off();
/// Test weather interrupt is enabled
pub fn intr_get() -> bool;
/// Disable IRQ.
pub fn mask_irq(vector: usize) -> HalResult;
@ -148,6 +157,9 @@ hal_fn_def! {
/// Time and clock functions.
pub mod timer {
/// Set the first time interrupt
pub fn timer_enable();
/// Get current time.
/// TODO: use `Instant` as return type.
pub fn timer_now() -> Duration;

View File

@ -1,6 +1,5 @@
//! Bootstrap and initialization.
use super::net;
use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER};
hal_fn_impl! {
@ -19,7 +18,6 @@ hal_fn_impl! {
super::macos::register_sigsegv_handler();
}
net::init();
}
}
}

View File

@ -45,4 +45,10 @@ pub(super) fn init() {
crate::console::init_graphic_console(display);
}
#[cfg(feature = "loopback")]
{
use crate::net;
net::init();
}
}

View File

@ -0,0 +1,10 @@
hal_fn_impl! {
impl mod crate::hal_fn::interrupt {
fn wait_for_interrupt() {}
fn intr_on() {}
fn intr_off() {}
fn intr_get() -> bool {
false
}
}
}

View File

@ -5,6 +5,7 @@ mod mock_mem;
pub mod boot;
pub mod config;
pub mod cpu;
pub mod interrupt;
pub mod mem;
pub mod net;
pub mod thread;
@ -16,9 +17,9 @@ pub mod vm;
#[doc(cfg(feature = "libos"))]
pub mod libos;
pub use super::hal_fn::{interrupt, rand};
pub use super::hal_fn::rand;
hal_fn_impl_default!(interrupt, rand, super::hal_fn::console);
hal_fn_impl_default!(rand, super::hal_fn::console);
#[cfg(target_os = "macos")]
mod macos;

View File

@ -1,3 +1,4 @@
// May need move to drivers
use smoltcp::{
iface::{InterfaceBuilder, NeighborCache, Route, Routes},
phy::{Loopback, Medium},

View File

@ -69,7 +69,7 @@ impl GenericPageTable for PageTable {
fn query(&self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, MMUFlags, PageSize)> {
debug_assert!(is_aligned(vaddr));
if PMEM_MAP_VADDR <= vaddr && vaddr < PMEM_MAP_VADDR + PMEM_SIZE {
if (PMEM_MAP_VADDR..PMEM_MAP_VADDR + PMEM_SIZE).contains(&vaddr) {
Ok((
vaddr - PMEM_MAP_VADDR,
MMUFlags::READ | MMUFlags::WRITE,
@ -95,7 +95,7 @@ mod tests {
use super::*;
/// A valid virtual address base to mmap.
const VBASE: VirtAddr = 0x2_00000000;
const VBASE: VirtAddr = 0x0002_0000_0000;
#[test]
fn map_unmap() {

View File

@ -6,6 +6,8 @@ use core::{fmt::Debug, marker::PhantomData, slice};
use crate::common::vm::*;
use crate::{mem::PhysFrame, MMUFlags, PhysAddr, VirtAddr};
use lock::Mutex;
pub trait PageTableLevel: Sync + Send {
const LEVEL: usize;
}
@ -150,7 +152,7 @@ impl<L: PageTableLevel, PTE: GenericPTE> PageTableImpl<L, PTE> {
}
fn dump(&self, limit: usize, print_fn: impl Fn(core::fmt::Arguments)) {
static LOCK: spin::Mutex<()> = spin::Mutex::new(());
static LOCK: Mutex<()> = Mutex::new(());
let _lock = LOCK.lock();
print_fn(format_args!("Root: {:x?}\n", self.table_phys()));

1
libc-test Submodule

@ -0,0 +1 @@
Subproject commit 1426bea9f3482dec1aa98c31dcc3733a750fb090

View File

@ -19,11 +19,18 @@ zircon-object = { path = "../zircon-object", features = ["elf"] }
kernel-hal = { path = "../kernel-hal", default-features = false }
downcast-rs = { version = "1.2", default-features = false }
lazy_static = { version = "1.4", features = ["spin_no_std"] }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
cfg-if = "1.0"
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
zcore-drivers = { path = "../drivers", features = ["virtio"] }
zcore-drivers = { path = "../drivers", features = ["virtio"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "01b2e70" }
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "async"] }
# LibOS mode
[target.'cfg(not(target_os = "none"))'.dependencies]
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]

View File

@ -111,6 +111,8 @@ pub enum LxError {
EISCONN = 106,
/// Transport endpoint is not connected
ENOTCONN = 107,
/// Connection timeout
ETIMEDOUT = 110,
/// Connection refused
ECONNREFUSED = 111,
}
@ -184,6 +186,7 @@ impl From<ZxError> for LxError {
ZxError::SHOULD_WAIT => LxError::EAGAIN,
ZxError::PEER_CLOSED => LxError::EPIPE,
ZxError::BAD_HANDLE => LxError::EBADF,
ZxError::TIMED_OUT => LxError::ETIMEDOUT,
_ => unimplemented!("unknown error type: {:?}", e),
}
}

View File

@ -1,7 +1,9 @@
mod fbdev;
mod input;
mod random;
mod uartdev;
pub use fbdev::FbDev;
pub use input::{EventDev, MiceDev};
pub use random::RandomINode;
pub use uartdev::UartDev;

View File

@ -0,0 +1,109 @@
use alloc::sync::Arc;
use core::any::Any;
use rcore_fs::vfs::{make_rdev, FileType, FsError, INode, Metadata, PollStatus, Result, Timespec};
use rcore_fs_devfs::DevFS;
use zcore_drivers::{scheme::UartScheme, DeviceError};
/// Uart device.
pub struct UartDev {
index: usize,
port: Arc<dyn UartScheme>,
inode_id: usize,
}
impl UartDev {
pub fn new(index: usize, port: Arc<dyn UartScheme>) -> Self {
Self {
index,
port,
inode_id: DevFS::new_inode_id(),
}
}
}
impl INode for UartDev {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
info!(
"uart read_at: offset={:#x} buf_len={:#x}",
offset,
buf.len()
);
let mut len = 0;
for b in buf.iter_mut() {
match self.port.try_recv() {
Ok(Some(b_)) => {
*b = b_;
len += 1;
}
Ok(None) => break,
Err(e) => return Err(convert_error(e)),
}
}
Ok(len)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
info!(
"uart write_at: offset={:#x} buf_len={:#x}",
offset,
buf.len()
);
for b in buf {
self.port.send(*b).map_err(convert_error)?;
}
Ok(buf.len())
}
fn poll(&self) -> Result<PollStatus> {
Ok(PollStatus {
// TOKNOW and TODO
read: true,
write: false,
error: false,
})
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 1,
inode: self.inode_id,
size: 0,
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: FileType::CharDevice,
mode: 0o600, // owner read & write
nlinks: 1,
uid: 0,
gid: 0,
rdev: make_rdev(4, self.index),
})
}
#[allow(unsafe_code)]
fn io_control(&self, _cmd: u32, _data: usize) -> Result<usize> {
warn!("uart ioctl unimplemented");
Ok(0)
}
fn as_any_ref(&self) -> &dyn Any {
self
}
}
fn convert_error(e: DeviceError) -> FsError {
match e {
DeviceError::NotSupported => FsError::NotSupported,
DeviceError::NotReady => FsError::Busy,
DeviceError::InvalidParam => FsError::InvalidParam,
DeviceError::BufferTooSmall
| DeviceError::DmaError
| DeviceError::IoError
| DeviceError::AlreadyExists
| DeviceError::NoResources => FsError::DeviceError,
}
}

View File

@ -1,7 +1,7 @@
//! Implement Device
use rcore_fs::dev::{Device, Result};
use spin::RwLock;
use lock::RwLock;
/// memory buffer for device
pub struct MemBuf(RwLock<&'static mut [u8]>);

View File

@ -17,15 +17,18 @@ use downcast_rs::impl_downcast;
use kernel_hal::drivers;
use rcore_fs::vfs::{FileSystem, FileType, INode, PollStatus, Result};
use rcore_fs_devfs::special::{NullINode, ZeroINode};
use rcore_fs_devfs::DevFS;
use rcore_fs_devfs::{
special::{NullINode, ZeroINode},
DevFS,
};
use rcore_fs_mountfs::MountFS;
use rcore_fs_ramfs::RamFS;
use zircon_object::{object::KernelObject, vm::VmObject};
use self::{devfs::RandomINode, pseudo::Pseudo};
use crate::error::{LxError, LxResult};
use crate::process::LinuxProcess;
use devfs::RandomINode;
use pseudo::Pseudo;
pub use file::{File, OpenFlags, SeekFrom};
pub use pipe::Pipe;
@ -126,9 +129,11 @@ pub fn create_root_fs(rootfs: Arc<dyn FileSystem>) -> Arc<dyn INode> {
devfs_root
.add("urandom", Arc::new(RandomINode::new(true)))
.expect("failed to mknod /dev/urandom");
devfs_root
.add("shm", Arc::new(RandomINode::new(true)))
.expect("failed to mknod /dev/shm");
if let Some(display) = drivers::all_display().first() {
use self::devfs::{EventDev, FbDev, MiceDev};
use devfs::{EventDev, FbDev, MiceDev};
// Add framebuffer device at `/dev/fb0`
if let Err(e) = devfs_root.add("fb0", Arc::new(FbDev::new(display.clone()))) {
@ -156,6 +161,14 @@ pub fn create_root_fs(rootfs: Arc<dyn FileSystem>) -> Arc<dyn INode> {
}
}
// Add uart devices at `/dev/ttyS{i}`
for (i, uart) in drivers::all_uart().as_vec().iter().enumerate() {
let fname = format!("ttyS{}", i);
if let Err(e) = devfs_root.add(&fname, Arc::new(devfs::UartDev::new(i, uart.clone()))) {
warn!("failed to mknod /dev/{}: {:?}", &fname, e);
}
}
// mount DevFS at /dev
let dev = root.find(true, "dev").unwrap_or_else(|_| {
root.create("dev", FileType::Dir, 0o666)

View File

@ -12,8 +12,8 @@ use core::pin::Pin;
use core::task::{Context, Poll};
use kernel_hal::console::{self, ConsoleWinSize};
use lazy_static::lazy_static;
use lock::Mutex;
use rcore_fs::vfs::*;
use spin::Mutex;
lazy_static! {
/// STDIN global reference

View File

@ -8,6 +8,7 @@ pub use self::shared_mem::*;
use alloc::collections::BTreeMap;
use alloc::sync::Arc;
use bitflags::*;
use spin::Mutex;
/// Semaphore table in a process
#[derive(Default)]
@ -130,7 +131,7 @@ impl Drop for SemProc {
impl ShmProc {
/// Insert the `SharedGuard` and return its ID
pub fn add(&mut self, shared_guard: Arc<spin::Mutex<ShmGuard>>) -> ShmId {
pub fn add(&mut self, shared_guard: Arc<Mutex<ShmGuard>>) -> ShmId {
let id = self.get_free_id();
let shm_identifier = ShmIdentifier {
addr: 0,

View File

@ -6,8 +6,7 @@ use crate::time::*;
use alloc::{collections::BTreeMap, sync::Arc, sync::Weak, vec::Vec};
use core::ops::Index;
use lazy_static::*;
use spin::Mutex;
use spin::RwLock;
use spin::{Mutex, RwLock};
/// semid data structure
///

View File

@ -4,13 +4,11 @@ use crate::error::LxError;
use crate::time::TimeSpec;
use alloc::{collections::BTreeMap, sync::Arc, sync::Weak};
use lazy_static::lazy_static;
use spin::Mutex;
use spin::RwLock;
use spin::{Mutex, RwLock};
use zircon_object::vm::*;
lazy_static! {
static ref KEY2SHM: RwLock<BTreeMap<u32, Weak<spin::Mutex<ShmGuard>>>> =
RwLock::new(BTreeMap::new());
static ref KEY2SHM: RwLock<BTreeMap<u32, Weak<Mutex<ShmGuard>>>> = RwLock::new(BTreeMap::new());
}
/// shmid data structure
@ -43,7 +41,7 @@ pub struct ShmIdentifier {
/// Shared memory address
pub addr: usize,
/// Shared memory buffer and data
pub guard: Arc<spin::Mutex<ShmGuard>>,
pub guard: Arc<Mutex<ShmGuard>>,
}
/// shared memory buffer and data
@ -66,7 +64,7 @@ impl ShmIdentifier {
memsize: usize,
flags: usize,
cpid: u32,
) -> Result<Arc<spin::Mutex<ShmGuard>>, LxError> {
) -> Result<Arc<Mutex<ShmGuard>>, LxError> {
let mut key2shm = KEY2SHM.write();
let flag = IpcGetFlag::from_bits_truncate(flags);
@ -80,7 +78,7 @@ impl ShmIdentifier {
return Ok(guard);
}
}
let shared_guard = Arc::new(spin::Mutex::new(ShmGuard {
let shared_guard = Arc::new(Mutex::new(ShmGuard {
shared_guard: VmObject::new_paged(pages(memsize)),
shmid_ds: Mutex::new(ShmidDs {
perm: IpcPerm {

View File

@ -3,6 +3,7 @@
/// missing documentation
pub mod socket_address;
use smoltcp::wire::IpEndpoint;
pub use socket_address::*;
/// missing documentation
@ -14,6 +15,7 @@ pub mod udp;
pub use udp::*;
use spin::Mutex;
/// missing documentation
// pub mod raw;
// pub use raw::*;
@ -111,24 +113,8 @@ impl Drop for GlobalSocketHandle {
}
}
// #[cfg(feature = "e1000")]
use kernel_hal::net::get_net_device;
#[cfg(feature = "loopback")]
use hashbrown::HashMap;
#[cfg(feature = "loopback")]
use kernel_hal::timer_now;
// #[cfg(feature = "loopback")]
// use net_stack::{NetStack, NET_STACK};
#[cfg(feature = "loopback")]
use smoltcp::time::Instant;
// /// miss doc
// #[cfg(feature = "loopback")]
// pub fn get_net_stack() -> HashMap<usize, Arc<dyn NetStack>> {
// NET_STACK.read().clone()
// }
/// miss doc
fn poll_ifaces() {
for iface in get_net_device().iter() {
@ -141,67 +127,8 @@ fn poll_ifaces() {
}
}
// use core::future::Future;
// use core::pin::Pin;
// use core::task::Context;
// use core::task::Poll;
// use smoltcp::socket::TcpSocket;
// ============= SocketHandle =============
// ============= Endpoint =============
use smoltcp::wire::IpEndpoint;
/// missing documentation
#[derive(Clone, Debug)]
pub enum Endpoint {
/// missing documentation
Ip(IpEndpoint),
/// missing documentation
LinkLevel(LinkLevelEndpoint),
/// missing documentation
Netlink(NetlinkEndpoint),
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct LinkLevelEndpoint {
/// missing documentation
pub interface_index: usize,
}
impl LinkLevelEndpoint {
/// missing documentation
pub fn new(ifindex: usize) -> Self {
LinkLevelEndpoint {
interface_index: ifindex,
}
}
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct NetlinkEndpoint {
/// missing documentation
pub port_id: u32,
/// missing documentation
pub multicast_groups_mask: u32,
}
impl NetlinkEndpoint {
/// missing documentation
pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self {
NetlinkEndpoint {
port_id,
multicast_groups_mask,
}
}
}
// ============= Endpoint =============
// ============= Rand Port =============
/// !!!! need riscv rng

View File

@ -5,12 +5,11 @@ use core::mem::size_of;
// crate
use crate::error::LxError;
use crate::net::Endpoint;
// use crate::net::Endpoint;
// smoltcp
pub use smoltcp::wire::{IpAddress, Ipv4Address};
// #
use crate::net::*;
use kernel_hal::user::{UserInOutPtr, UserOutPtr};
// use numeric_enum_macro::numeric_enum;
@ -91,6 +90,58 @@ pub struct SockAddrPlaceholder {
pub data: [u8; 14],
}
// ============= Endpoint =============
use smoltcp::wire::IpEndpoint;
/// missing documentation
#[derive(Clone, Debug)]
pub enum Endpoint {
/// missing documentation
Ip(IpEndpoint),
/// missing documentation
LinkLevel(LinkLevelEndpoint),
/// missing documentation
Netlink(NetlinkEndpoint),
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct LinkLevelEndpoint {
/// missing documentation
pub interface_index: usize,
}
impl LinkLevelEndpoint {
/// missing documentation
pub fn new(ifindex: usize) -> Self {
LinkLevelEndpoint {
interface_index: ifindex,
}
}
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct NetlinkEndpoint {
/// missing documentation
pub port_id: u32,
/// missing documentation
pub multicast_groups_mask: u32,
}
impl NetlinkEndpoint {
/// missing documentation
pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self {
NetlinkEndpoint {
port_id,
multicast_groups_mask,
}
}
}
// ============= Endpoint =============
impl From<Endpoint> for SockAddr {
fn from(endpoint: Endpoint) -> Self {
#[allow(warnings)]
@ -112,32 +163,29 @@ impl From<Endpoint> for SockAddr {
},
_ => unimplemented!("only ipv4"),
}
// unix socket 暂时 未开启
// } else if let Endpoint::LinkLevel(link_level) = endpoint {
// SockAddr {
// addr_ll: SockAddrLl {
// sll_family: AddressFamily::Packet.into(),
// sll_protocol: 0,
// sll_ifindex: link_level.interface_index as u32,
// sll_hatype: 0,
// sll_pkttype: 0,
// sll_halen: 0,
// sll_addr: [0; 8],
// },
// }
// } else if let Endpoint::Netlink(netlink) = endpoint {
// SockAddr {
// addr_nl: SockAddrNl {
// nl_family: AddressFamily::Netlink.into(),
// nl_pad: 0,
// nl_pid: netlink.port_id,
// nl_groups: netlink.multicast_groups_mask,
// },
// }
} else if let Endpoint::LinkLevel(link_level) = endpoint {
SockAddr {
addr_ll: SockAddrLl {
sll_family: AddressFamily::Packet.into(),
sll_protocol: 0,
sll_ifindex: link_level.interface_index as u32,
sll_hatype: 0,
sll_pkttype: 0,
sll_halen: 0,
sll_addr: [0; 8],
},
}
} else if let Endpoint::Netlink(netlink) = endpoint {
SockAddr {
addr_nl: SockAddrNl {
nl_family: AddressFamily::Netlink.into(),
nl_pad: 0,
nl_pid: netlink.port_id,
nl_groups: netlink.multicast_groups_mask,
},
}
} else {
unimplemented!("only ip");
unimplemented!("not match");
}
}
}

View File

@ -70,7 +70,7 @@ impl TcpSocketState {
/// missing documentation
pub async fn read(&self, data: &mut [u8]) -> (LxResult<usize>, Endpoint) {
warn!("tcp read");
info!("tcp read");
loop {
poll_ifaces();
let net_sockets = get_sockets();
@ -96,60 +96,9 @@ impl TcpSocketState {
}
}
/// missing documentation
#[cfg(feature = "e1000")]
pub async fn read(&self, data: &mut [u8]) -> (LxResult<usize>, Endpoint) {
warn!("tcp read");
use core::task::Poll;
futures::future::poll_fn(|cx| {
self.with(|s| {
if s.can_recv() {
warn!("can recv ok");
if let Ok(size) = s.recv_slice(data) {
warn!("--------------Ok size {}", size);
if size > 0 {
let endpoint = s.remote_endpoint();
Poll::Ready((Ok(size), Endpoint::Ip(endpoint)))
} else {
warn!("wait size > 0");
s.register_recv_waker(cx.waker());
s.register_send_waker(cx.waker());
Poll::Pending
}
} else {
warn!("recv_slice not Oksize");
Poll::Ready((
Err(LxError::ENOTCONN),
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
))
}
} else {
error!("can not recv");
s.register_recv_waker(cx.waker());
s.register_send_waker(cx.waker());
Poll::Pending
}
})
})
.await
// let net_sockets = get_net_sockets();
// let mut sockets = net_sockets.lock();
// let mut socket = sockets.get::<TcpSocket>(self.handle.0);
// // if socket.may_recv() {
// if let Ok(size) = socket.recv_slice(data) {
// let endpoint = socket.remote_endpoint();
// return (Ok(size), Endpoint::Ip(endpoint));
// } else {
// return (
// Err(LxError::ENOTCONN),
// Endpoint::Ip(IpEndpoint::UNSPECIFIED),
// );
// }
}
/// missing documentation
pub fn write(&self, data: &[u8], _sendto_endpoint: Option<Endpoint>) -> SysResult {
warn!("tcp write");
info!("tcp write");
let net_sockets = get_sockets();
let mut sockets = net_sockets.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
@ -241,194 +190,6 @@ impl TcpSocketState {
Err(LxError::EINVAL)
}
}
/// missing documentation
#[cfg(feature = "e1000")]
pub async fn connect(&self, endpoint: Endpoint) -> SysResult {
warn!("tcp connect");
// if let Endpoint::Ip(ip) = endpoint {
// let local_port = get_ephemeral_port();
// self.with(|ss| ss.connect(ip, local_port).map_err(|_| LxError::ENOBUFS))?;
// // use crate::net::IFaceFuture;
// // IFaceFuture { flag: false }.await;
// // warn!("no");
// // use smoltcp::socket::TcpState;
// // let ret = self.with(|ss| match ss.state() {
// // TcpState::SynSent => {
// // // still connecting
// // warn!("SynSent");
// // Ok(0)
// // }
// // TcpState::Established => Ok(0),
// // _ => Err(LxError::ECONNREFUSED),
// // });
// // Ok(0)
// // socket
// // .connect(ip, local_port)
// // .map_err(|_| LxError::ENOBUFS)?;
// // use crate::net::ConnectFuture;
// // use smoltcp::socket::SocketRef;
// // let c = ConnectFuture {
// // socket: SocketRef::into_inner(socket),
// // }
// // .await;
// // drop(c);
// // use core::future::Future;
// // use core::pin::Pin;
// // use core::task::Context;
// use crate::net::IFaceFuture;
// IFaceFuture.await;
// // warn!("no");
// // IFaceFuture.await;
// // warn!("no");
// // IFaceFuture.await;
// // warn!("no");
// // IFaceFuture.await;
// // warn!("no");
// use core::task::Poll;
// use smoltcp::socket::TcpState;
// let ret = futures::future::poll_fn(|cx| {
// self.with(|s| {
// // s.connect(ip, local_port).map_err(|_| LxError::ENOBUFS)?;
// match s.state() {
// TcpState::Closed | TcpState::TimeWait => {
// warn!("Closed|TimeWait");
// Poll::Ready(Err(LxError::ECONNREFUSED))
// }
// TcpState::Listen => {
// warn!("Listen");
// Poll::Ready(Err(LxError::ECONNREFUSED))
// }
// TcpState::SynSent => {
// warn!("SynSent");
// s.register_recv_waker(cx.waker());
// s.register_send_waker(cx.waker());
// // drop(s);
// // #[cfg(feature = "e1000")]
// // poll_ifaces_e1000();
// // IFaceFuture.await
// Poll::Pending
// }
// TcpState::SynReceived => {
// warn!("SynReceived");
// s.register_recv_waker(cx.waker());
// s.register_send_waker(cx.waker());
// Poll::Pending
// }
// TcpState::Established => {
// warn!("Established");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// // TcpState::TimeWait => {
// // warn!("TimeWait");
// // // s.register_recv_waker(cx.waker());
// // // s.register_send_waker(cx.waker());
// // Poll::Ready(Ok(0))
// // // Poll::Pending
// // }
// TcpState::FinWait1 => {
// warn!("------------------------------------FinWait1");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// TcpState::FinWait2 => {
// warn!("----------------------------------------FinWait2");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// TcpState::Closing => {
// warn!("-------------------------------------------Closing");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// TcpState::LastAck => {
// warn!("-------------------------------------------LastAck");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// _ => {
// warn!("_");
// Poll::Ready(Err(LxError::ECONNREFUSED))
// }
// }
// })
// })
// .await;
// // #[cfg(feature = "e1000")]
// // poll_ifaces_e1000();
// IFaceFuture.await;
// warn!("ret {:?}", ret);
// ret
// // Ok(0)
// } else {
// return Err(LxError::EINVAL);
// }
let net_sockets = get_net_sockets();
let mut sockets = net_sockets.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
#[allow(warnings)]
if let Endpoint::Ip(ip) = endpoint {
let local_port = get_ephemeral_port();
socket
.connect(ip, local_port)
.map_err(|_| LxError::ENOBUFS)?;
// avoid deadlock
drop(socket);
drop(sockets);
#[cfg(feature = "e1000")]
poll_ifaces_e1000();
#[cfg(feature = "loopback")]
poll_ifaces_loopback();
// wait for connection result
loop {
warn!("loop");
let net_sockets = get_net_sockets();
let mut sockets = net_sockets.lock();
let socket = sockets.get::<TcpSocket>(self.handle.0);
use smoltcp::socket::TcpState;
match socket.state() {
TcpState::SynSent => {
// still connecting
warn!("SynSent");
drop(socket);
drop(sockets);
#[cfg(feature = "e1000")]
poll_ifaces_e1000();
#[cfg(feature = "loopback")]
poll_ifaces_loopback();
}
TcpState::Established => {
warn!("estab");
break Ok(0);
}
_ => {
break Err(LxError::ECONNREFUSED);
}
}
}
} else {
drop(socket);
drop(sockets);
return Err(LxError::EINVAL);
}
}
/// missing documentation
fn bind(&mut self, endpoint: Endpoint) -> SysResult {
@ -511,54 +272,6 @@ impl TcpSocketState {
drop(sockets);
}
}
#[cfg(feature = "e1000")]
async fn accept(&mut self) -> Result<(Arc<Mutex<dyn Socket>>, Endpoint), LxError> {
let endpoint = self.local_endpoint.ok_or(LxError::EINVAL)?;
// let net_sockets = get_net_sockets();
// let mut sockets = net_sockets.lock();
// let socket = sockets.get::<TcpSocket>(self.handle.0);
// if socket.is_active() {
// use crate::net::AcceptFuture;
// AcceptFuture {
// socket: &mut socket,
// }
// .await;
use core::task::Poll;
futures::future::poll_fn(|cx| {
self.with(|s| {
if s.is_active() {
Poll::Ready(())
} else {
s.register_recv_waker(cx.waker());
s.register_send_waker(cx.waker());
Poll::Pending
}
})
})
.await;
let remote_endpoint = self.with(|s| s.remote_endpoint());
// drop(socket);
let new_socket = {
let rx_buffer = TcpSocketBuffer::new(vec![0; TCP_RECVBUF]);
let tx_buffer = TcpSocketBuffer::new(vec![0; TCP_SENDBUF]);
let mut socket = TcpSocket::new(rx_buffer, tx_buffer);
socket.listen(endpoint).unwrap();
let net_sockets = get_net_sockets();
let mut sockets = net_sockets.lock();
let new_handle = GlobalSocketHandle(sockets.add(socket));
let old_handle = ::core::mem::replace(&mut self.handle, new_handle);
Arc::new(Mutex::new(TcpSocketState {
// base: KObjectBase::new(),
handle: old_handle,
local_endpoint: self.local_endpoint,
is_listening: false,
}))
};
return Ok((new_socket, Endpoint::Ip(remote_endpoint)));
}
/// missing documentation
fn endpoint(&self) -> Option<Endpoint> {

View File

@ -31,7 +31,6 @@ use alloc::sync::Arc;
use alloc::vec;
// smoltcp
use smoltcp::socket::UdpPacketMetadata;
use smoltcp::socket::UdpSocket;
use smoltcp::socket::UdpSocketBuffer;
@ -121,34 +120,6 @@ impl UdpSocketState {
drop(sockets);
}
}
/// missing documentation
#[cfg(feature = "e1000")]
pub async fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
use core::task::Poll;
futures::future::poll_fn(|cx| {
self.with(|s| {
if s.can_recv() {
if let Ok((size, remote_endpoint)) = s.recv_slice(data) {
let endpoint = remote_endpoint;
warn!("udp read => size : {} , enpoint : {} ", size, endpoint);
Poll::Ready((Ok(size), Endpoint::Ip(endpoint)))
} else {
warn!("recv faill message");
Poll::Ready((
Err(LxError::ENOTCONN),
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
))
}
} else {
warn!("udp can not recv ,because rx buffer is null");
s.register_recv_waker(cx.waker());
s.register_send_waker(cx.waker());
Poll::Pending
}
})
})
.await
}
/// missing documentation
pub fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {

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