diff --git a/.github/workflows/doc_translation.yml b/.github/workflows/doc_translation.yml new file mode 100644 index 00000000..8edeca52 --- /dev/null +++ b/.github/workflows/doc_translation.yml @@ -0,0 +1,65 @@ +name: Docs Translation + +on: + push: + branches: [master] + paths: + - "docs/**" + workflow_dispatch: + +jobs: + translate-and-pr: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - id: get-short_sha + uses: actions/github-script@v7.0.1 + with: + script: | + const short_sha = context.sha.substring(0, 8) + core.setOutput('short_sha', short_sha) + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r docs/requirements.txt + + - name: Run document translator + run: python tools/doc_translator.py + env: + MAX_WORKERS: 20 + OPENAI_API_KEY: ${{ secrets.DRAGONOS_OPENAI_API_KEY }} + OPENAI_MODEL: Qwen/Qwen3-8B + OPENAI_BASE_URL: ${{ secrets.DRAGONOS_OPENAI_API_BASE }} + + - name: Commit translated files + run: | + git config --global user.name "dragonosbot" + git config --global user.email "bot@dragonos.org" + git add docs/locales/ + git commit -m "Update translated documentation" || echo "No changes to commit" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + commit-message: "Update translated documentation" + title: "docs: Translation update [${{steps.get-short_sha.outputs.short_sha}}]" + body: | + Automated translation update triggered by docs changes + Commit: ${{ github.sha }} + branch: "dragonosbot/docs-translation-update" + branch-suffix: "timestamp" + base: ${{ github.ref_name }} + author: bot + delete-branch: true + reviewers: fslongjin + assignees: fslongjin diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index 88ad306a..362f91aa 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -11,14 +11,14 @@ jobs: name: Format check ${{ matrix.arch }} runs-on: ubuntu-latest continue-on-error: true - container: dragonos/dragonos-dev:v1.8 + container: dragonos/dragonos-dev:v1.12 strategy: matrix: - arch: [x86_64, riscv64] + arch: [x86_64, riscv64, loongarch64] steps: - - run: echo "Running in dragonos/dragonos-dev:v1.8" + - run: echo "Running in dragonos/dragonos-dev:v1.12" - uses: actions/checkout@v3 - name: Format check @@ -35,14 +35,14 @@ jobs: name: Kernel static test ${{ matrix.arch }} runs-on: ubuntu-latest continue-on-error: true - container: dragonos/dragonos-dev:v1.8 + container: dragonos/dragonos-dev:v1.12 strategy: matrix: - arch: [x86_64, riscv64] + arch: [x86_64, riscv64, loongarch64] steps: - - run: echo "Running in dragonos/dragonos-dev:v1.8" + - run: echo "Running in dragonos/dragonos-dev:v1.12" - uses: actions/checkout@v3 @@ -53,46 +53,41 @@ jobs: HOME: /root run: bash -c "source /root/.cargo/env && cd kernel && make test && make test-rbpf" - build-x86_64: + build: + name: Build ${{ matrix.arch }} runs-on: ubuntu-latest - container: dragonos/dragonos-dev:v1.8 + container: dragonos/dragonos-dev:v1.12 + continue-on-error: true + strategy: + matrix: + include: + - arch: x86_64 + make_target: all + checkout_params: {} + - arch: riscv64 + make_target: all + checkout_params: + submodules: "recursive" + - arch: loongarch64 + make_target: all + checkout_params: {} steps: - - run: echo "Running in dragonos/dragonos-dev:v1.8" - + - run: echo "Running in dragonos/dragonos-dev:v1.12" + - uses: actions/checkout@v3 - - name: build the DragonOS + with: ${{ matrix.checkout_params }} + + - name: Build the DragonOS env: - ARCH: x86_64 + ARCH: ${{ matrix.arch }} HOME: /root shell: bash -ileo pipefail {0} - run: | - source ~/.bashrc - source ~/.cargo/env - export DragonOS_GCC=$HOME/opt/dragonos-gcc/gcc-x86_64-unknown-none/bin + source $HOME/.bashrc + source $HOME/.cargo/env + if [[ "$ARCH" == "x86_64" ]]; then + export DragonOS_GCC=$HOME/opt/dragonos-gcc/gcc-x86_64-unknown-none/bin + fi sed -i 's/arch = ".*"/arch = "${{ env.ARCH }}"/' dadk-manifest.toml - - make all -j $(nproc) - - build-riscv64: - runs-on: ubuntu-latest - container: dragonos/dragonos-dev:v1.8 - - steps: - - run: echo "Running in dragonos/dragonos-dev:v1.8" - - - uses: actions/checkout@v3 - with: - submodules: "recursive" - - - name: build the DragonOS - shell: bash -ileo pipefail {0} - env: - ARCH: riscv64 - HOME: /root - - run: | - source ~/.bashrc && source ~/.cargo/env - sed -i 's/arch = ".*"/arch = "${{ env.ARCH }}"/' dadk-manifest.toml - make kernel -j $(nproc) + make ${{ matrix.make_target }} -j $(nproc) diff --git a/.github/workflows/publish-dragonos-docker-image.yml b/.github/workflows/publish-dragonos-docker-image.yml index ebd2e2b6..5e882efb 100644 --- a/.github/workflows/publish-dragonos-docker-image.yml +++ b/.github/workflows/publish-dragonos-docker-image.yml @@ -35,5 +35,5 @@ jobs: context: "{{defaultContext}}:tools" file: Dockerfile platforms: linux/amd64 - push: true + push: ${{ github.repository == 'DragonOS-Community/DragonOS' }} tags: dragonos/dragonos-dev:${{ steps.fetch-versions.outputs.build_container_version }} diff --git a/.github/workflows/sync-to-cnb.yml b/.github/workflows/sync-to-cnb.yml new file mode 100644 index 00000000..5eaa34a5 --- /dev/null +++ b/.github/workflows/sync-to-cnb.yml @@ -0,0 +1,23 @@ +name: Sync to CNB.cool +on: [push] + +jobs: + sync: + if: github.repository == 'DragonOS-Community/DragonOS' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Sync to CNB Repository + run: | + docker run --rm \ + -v ${{ github.workspace }}:${{ github.workspace }} \ + -w ${{ github.workspace }} \ + -e PLUGIN_TARGET_URL="https://cnb.cool/DragonOS-Community/DragonOS.git" \ + -e PLUGIN_AUTH_TYPE="https" \ + -e PLUGIN_USERNAME="cnb" \ + -e PLUGIN_PASSWORD=${{ secrets.CNB_GIT_PASSWORD }} \ + -e PLUGIN_FORCE="true" \ + tencentcom/git-sync diff --git a/.gitignore b/.gitignore index 53ab248d..88bb38b0 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ cppcheck.xml .cache compile_commands.json /logs/ +*.log diff --git a/.vscode/settings.json b/.vscode/settings.json index ede91604..dddf29cd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,158 +1,19 @@ { "files.associations": { - "stdbool.h": "c", - "printk.h": "c", - "stdarg.h": "c", - "process.h": "c", - "cpu.h": "c", - "mm.h": "c", - "glib.h": "c", "asm.h": "c", - "memory.h": "c", - "kprint.h": "c", - "ptrace.h": "c", - "mouse.h": "c", - "algorithm": "c", - "array": "c", - "atomic": "c", - "*.tcc": "c", - "bitset": "c", - "cassert": "c", - "cctype": "c", - "cerrno": "c", - "chrono": "c", - "climits": "c", - "clocale": "c", - "cmath": "c", - "codecvt": "c", - "condition_variable": "c", - "cstdarg": "c", - "cstddef": "c", - "cstdint": "c", - "cstdio": "c", - "cstdlib": "c", - "cstring": "c", - "ctime": "c", - "cwchar": "c", - "cwctype": "c", - "deque": "c", - "exception": "c", - "forward_list": "c", - "functional": "c", - "iterator": "c", - "list": "c", - "map": "c", - "memory": "c", - "memory_resource": "c", - "numeric": "c", - "optional": "c", - "random": "c", - "ratio": "c", - "set": "c", - "string": "c", - "string_view": "c", - "system_error": "c", - "tuple": "c", - "type_traits": "c", - "unordered_map": "c", - "utility": "c", - "vector": "c", - "fstream": "c", - "initializer_list": "c", - "ios": "c", - "iosfwd": "c", - "istream": "c", - "limits": "c", - "locale": "c", - "mutex": "c", - "new": "c", - "ostream": "c", - "queue": "c", - "sstream": "c", - "stdexcept": "c", - "streambuf": "c", - "thread": "c", - "cinttypes": "c", - "cstdbool": "c", - "typeinfo": "c", - "unistd.h": "c", - "stdint.h": "c", - "syscall.h": "c", - "fcntl.h": "c", - "types.h": "c", - "string.h": "c", - "math.h": "c", - "arch.h": "c", - "stdio.h": "c", - "wait_queue.h": "c", - "stddef.h": "c", - "spinlock.h": "c", - "stat.h": "c", - "video.h": "c", - "ahci.h": "c", - "slab.h": "c", - "boot_info.h": "c", - "pci.h": "c", - "time.h": "c", - "errno.h": "c", - "bug.h": "c", - "sched.h": "c", - "preempt.h": "c", - "textui.h": "c", - "atomic.h": "c", - "semaphore.h": "c", - "mm-types.h": "c", - "current.h": "c", - "traceback.h": "c", - "bitcount.h": "c", - "limits.h": "c", - "mutex.h": "c", - "mount.h": "c", - "internal.h": "c", - "compiler_attributes.h": "c", - "timer.h": "c", - "hid.h": "c", - "compiler.h": "c", - "err.h": "c", - "list.h": "c", - "irqflags.h": "c", - "dirent.h": "c", - "cmd_help.h": "c", - "wait.h": "c", - "ctype.h": "c", - "stdint-gcc.h": "c", - "acpi.h": "c", - "assert.h": "c", - "sys_version.h": "c", - "cmd.h": "c", - "net.h": "c", - "cmd_test.h": "c", - "cmpxchg.h": "c", - "mman.h": "c", - "clocksource.h": "c", - "ata.h": "c", - "barrier": "c", - "charconv": "c", - "printf.h": "c", - "klog.h": "c", - "malloc.h": "c", - "*.o": "c", - "k_log.h": "c" }, "C_Cpp.errorSquiggles": "enabled", "esbonio.sphinx.confDir": "", - "rust-analyzer.checkOnSave.allTargets": false, "rust-analyzer.linkedProjects": [ "./kernel/Cargo.toml", //"./tools/Cargo.toml", - ], + // "rust-analyzer.cargo.target": "loongarch64-unknown-none", // "rust-analyzer.cargo.target": "riscv64gc-unknown-none-elf", "rust-analyzer.cargo.target": "x86_64-unknown-none", "rust-analyzer.check.overrideCommand": [ "make", "check", - ], "makefile.configureOnOpen": false, } \ No newline at end of file diff --git a/Makefile b/Makefile index fe38c3c5..7664aeb9 100644 --- a/Makefile +++ b/Makefile @@ -74,6 +74,8 @@ clean-docs: gdb: ifeq ($(ARCH), x86_64) rust-gdb -n -x tools/.gdbinit +else ifeq ($(ARCH), loongarch64) + loongarch64-unknown-linux-gnu-gdb -n -x tools/.gdbinit else gdb-multiarch -n -x tools/.gdbinit endif @@ -139,6 +141,11 @@ run-vnc: check_arch $(MAKE) write_diskimage || exit 1 $(MAKE) qemu-vnc +run-nographic: check_arch + $(MAKE) all -j $(NPROCS) + $(MAKE) write_diskimage || exit 1 + $(MAKE) qemu-nographic + # 在docker中编译,并启动QEMU run-docker: check_arch @echo "使用docker构建并运行" diff --git a/README.md b/README.md index 1378864c..e2772c34 100644 --- a/README.md +++ b/README.md @@ -1,129 +1,94 @@
dragonos-logo
-

打造完全自主可控的数字化未来!

- +

Lightweight Cloud-Native Kernel

官网 bbs - - ---
# DragonOS -**Languages** 中文|[English](README_EN.md) - +**Languages** [中文](README_CN.md)|English   -  DragonOS龙操作系统是一个面向云计算轻量化场景的,完全自主内核的,提供Linux二进制兼容性的64位操作系统。它使用Rust语言进行开发,以提供更好的可靠性。目前在Rust操作系统领域,DragonOS在Github排行全国稳居前三位。 +  DragonOS is a 64-bit operating system with a completely independent kernel, designed for lightweight cloud computing scenarios, offering Linux binary compatibility. It aims to provide lightweight, high-performance solutions for containerized workloads. Developed using Rust for enhanced reliability. -  DragonOS开源社区成立于2022年7月,它完全商业中立。我们的目标是,构建一个完全独立自主的、开源的、高性能及高可靠性的服务器操作系统,打造完全自主可控的数字化未来! +  The DragonOS open-source community was established in July 2022 and is entirely commercially neutral. We warmly welcome interested developers and enthusiasts to join us! -  DragonOS具有优秀的、完善的架构设计。相比于同体量的其他系统,DragonOS支持虚拟化,并在设备模型、调度子系统等方面具有一定优势。当前正在大力推进云平台支持、riscv支持等工作,以及编译器、应用软件的移植。力求在5年内实现生产环境大规模应用。 +  DragonOS features excellent and comprehensive architectural design. Compared to other systems of similar scale, DragonOS supports eBPF and virtualization. Currently, we are actively advancing container support, cloud platform compatibility, RISC-V support, as well as porting compilers and application software. Our goal is to achieve large-scale production environment deployment within five years. -  DragonOS目前在社区驱动下正在快速发展中,目前DragonOS已经实现了约1/4的Linux接口,在未来我们将提供对Linux的100%兼容性,并且提供新特性。 +  DragonOS is rapidly evolving under community-driven development. Currently, DragonOS has implemented approximately 1/4 of Linux interfaces. In the future, we will provide 100% Linux compatibility along with new features. +## How to Run? -## 参与开发? +  Running DragonOS is straightforward. You can refer to the following resources to get DragonOS up and running in as little as 15 minutes! -仔细阅读 [DragonOS社区介绍文档] ,能够帮助你了解社区的运作方式,以及如何参与贡献! +- [Building DragonOS — DragonOS dev documentation](https://docs.dragonos.org.cn/locales/en/introduction/build_system.html) -- **了解开发动态、开发任务,请访问DragonOS社区论坛**: [https://bbs.dragonos.org.cn](https://bbs.dragonos.org.cn) -- 您也可以从项目的issue里面了解相关的开发内容。 +## Want to Contribute? +Read the [DragonOS Community Introduction Document] carefully to understand how the community operates and how you can contribute! -  如果你愿意加入我们,你可以查看issue,并在issue下发表讨论、想法,或者访问DragonOS的论坛,了解开发动态、开发任务: [https://bbs.dragonos.org.cn](https://bbs.dragonos.org.cn) +  If you'd like to join us, check out the issues and participate in discussions or share your ideas. You can also visit the DragonOS forum to stay updated on development progress and tasks: [https://bbs.dragonos.org.cn](https://bbs.dragonos.org.cn) -  你也可以带着你的创意与想法,和社区的小伙伴一起讨论,为DragonOS创造一些新的功能。 +  You can also bring your creativity and ideas to discuss with the community and contribute new features to DragonOS. -## 网站 +## Sites +- Official Website: **[DragonOS.org](https://dragonos.org)** +- Documentation: **[docs.dragonos.org](https://docs.dragonos.org)** +- Community Introduction: **[community.dragonos.org](https://community.dragonos.org)** +- QQ Group: 476358494 -- 项目官网 **[DragonOS.org](https://dragonos.org)** -- 文档:**[docs.dragonos.org](https://docs.dragonos.org)** -- 社区介绍文档: **[community.dragonos.org](https://community.dragonos.org)** +## How to Connect with the Community? +Please read the [Contributor Guide](https://community.dragonos.org/contributors/#%E7%A4%BE%E5%8C%BA)~ -## 如何运行? - -  运行DragonOS的步骤非常简单,您可以参考以下几个资料,在最短15分钟内运行DragonOS! - -- [构建DragonOS — DragonOS dev 文档](https://docs.dragonos.org/zh_CN/latest/introduction/build_system.html) - - - -## 如何与社区建立联系? - -请阅读[贡献者指南](https://community.dragonos.org/contributors/#%E7%A4%BE%E5%8C%BA)~ - -- 您可以通过[社区管理团队]信息,与各委员会的成员们建立联系~ -- 同时,您可以通过[SIGs]和[WGs]页面,找到对应的社区团体负责人的联系方式~ - -## 贡献者名单 +- You can find contact details for members of various committees in the [Community Management Team] section. +- You can also locate the contact information for leaders of specific community groups via the [SIGs] and [WGs] pages. +## Contributor List [Contributors to DragonOS-Community/DragonOS · GitHub](https://github.com/DragonOS-Community/DragonOS/graphs/contributors) +## Sponsorship +[![Sponsor this project](https://img.shields.io/badge/Sponsor_This_Project-DragonOS_Community-ff69b4?style=for-the-badge)](https://dragonos.org/?page_id=37) +  DragonOS is a non-profit open-source project, and its development relies on financial support. All sponsors will be publicly acknowledged. Every contribution you make will help advance DragonOS! -## 赞助 +### Where Will Sponsorship Funds Be Used? -  DragonOS是一个公益性质的开源项目,但是它的发展离不开资金的支持,如果您愿意的话,可以通过 **[赞助 - DragonOS](https://dragonos.org/?page_id=37)** ,从而促进这个项目的发展。所有的赞助者的名单都会被公示。您的每一分赞助,都会为DragonOS的发展作出贡献! +We guarantee that all sponsorship funds and items will be used for: -### 赞助的资金都会被用到哪里? +- Event organization, cloud service expenses, and any other purposes beneficial to the development and growth of the DragonOS community. -我们保证,所有赞助的资金及物品,将会用于: +## 🌟 Sponsor List +**Special thanks to these generous financial supporters** (in reverse chronological order): -- 为活跃的社区开发者发放补贴或设备支持 +- **[中国雅云](https://yacloud.net)** 雅安大数据产业园 - 🥇 Long-term supporter -- DragonOS的云服务开支 +### Individual Sponsors List +See [Supporters.md](./SUPPORTERS.md) -- 设备购置 +## Open Source License Notice -- 任何有助于DragonOS发展建设的用途 +This project is open-sourced under the GPLv2 license. You are welcome to use the code in compliance with the open-source license! -### 赞助商列表 +If you encounter any violations of the open-source license, we encourage you to email pmc@dragonos.org to report them. Let's work together to build a trustworthy open-source community. -- **[中国雅云](https://yacloud.net)** 雅安数字经济运营有限公司为DragonOS提供了云服务器支持。 +--- +## 👩💻 Contributors -### 个人赞赏者列表 +> *"Open source shines because of you!"* ✨ -- 万晓兰 -- David Wen -- [YJwu2023](https://github.com/YJwu2023) -- [longjin](https://github.com/fslongjin) -- [黄铭涛](https://github.com/1037827920) -- [许梓毫](https://github.com/Jomocool) -- [谢润霖](https://github.com/xiaolin2004) -- [蔡俊源](https://github.com/SMALLC04) -- Kelly -- [Samuka007](https://github.com/Samuka007) -- [杨璐玮](https://github.com/val213) -- [何懿聪](https://github.com/GnoCiYeH) -- [周凯韬](https://github.com/laokengwt) -- [Seele.Clover](https://github.com/seeleclover) -- [FindWangHao](https://github.com/FindWangHao) -- [ferchiel](https://github.com/ferchiel) -- 叶锦毅 -- 林 -- Albert -- [TerryLeeSCUT · GitHub](https://github.com/TerryLeeSCUT) -- slientbard -- 悟 +**Thanks to all developers who submitted code, fixed issues, or reviewed PRs**: -## 开放源代码声明 + + + -本项目采用GPLv2协议进行开源,欢迎您在遵守开源协议的基础之上,使用本项目的代码! - -**我们支持**:遵守协议的情况下,利用此项目,创造更大的价值,并为本项目贡献代码。 - -**我们谴责**:任何不遵守开源协议的行为。包括但不限于:剽窃该项目的代码作为你的毕业设计等学术不端行为以及商业闭源使用而不付费。 - -若您发现了任何违背开源协议的使用行为,我们欢迎您发邮件到 pmc@dragonos.org 反馈!让我们共同建设诚信的开源社区。 - - -[DragonOS社区介绍文档]: https://community.dragonos.org/ -[社区管理团队]: https://community.dragonos.org/governance/staff-info.html +[DragonOS Community Introduction Document]: https://community.dragonos.org/ +[Community Management Team]: https://community.dragonos.org/governance/staff-info.html [SIGs]: https://community.dragonos.org/sigs/ [WGs]: https://community.dragonos.org/wgs/ diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 00000000..f6ef2e97 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,101 @@ +
+ dragonos-logo
+

轻量级云原生内核

+ +官网 +bbs + +--- + +
+ +# DragonOS + +**Languages** 中文|[English](README.md) + +  + +  DragonOS龙操作系统是一个面向云计算轻量化场景的,完全自主内核的,提供Linux二进制兼容性的64位操作系统,旨在为容器化工作负载提供轻量级、高性能的解决方案。它使用Rust语言进行开发,以提供更好的可靠性。 + +  DragonOS开源社区成立于2022年7月,完全商业中立。我们热烈欢迎感兴趣的开发者和爱好者加入我们! + +  DragonOS具有优秀的、完善的架构设计。相比于同体量的其他系统,DragonOS支持eBPF、虚拟化。当前正在大力推进容器支持、云平台支持、riscv支持等工作,以及编译器、应用软件的移植。力求在5年内实现生产环境大规模应用。 + +  DragonOS目前在社区驱动下正在快速发展中,目前DragonOS已经实现了约1/4的Linux接口,在未来我们将提供对Linux的100%兼容性,并且提供新特性。 + + +## 如何运行? + +  运行DragonOS的步骤非常简单,您可以参考以下几个资料,在最短15分钟内运行DragonOS! + +- [构建DragonOS — DragonOS dev 文档](https://docs.dragonos.org.cn/introduction/build_system.html) + +## 参与开发? + +仔细阅读 [DragonOS社区介绍文档] ,能够帮助你了解社区的运作方式,以及如何参与贡献! + +  如果你愿意加入我们,你可以查看issue,并在issue下发表讨论、想法,或者访问DragonOS的论坛,了解开发动态、开发任务: [https://bbs.dragonos.org.cn](https://bbs.dragonos.org.cn) + +  你也可以带着你的创意与想法,和社区的小伙伴一起讨论,为DragonOS创造一些新的功能。 + +## 站点 + +- 项目官网 **[DragonOS.org](https://dragonos.org)** +- 文档:**[docs.dragonos.org](https://docs.dragonos.org)** +- 社区介绍文档: **[community.dragonos.org](https://community.dragonos.org)** +- QQ群: 476358494 + + +## 如何与社区建立联系? + +请阅读[贡献者指南](https://community.dragonos.org/contributors/#%E7%A4%BE%E5%8C%BA)~ + +- 您可以通过[社区管理团队]信息,与各委员会的成员们建立联系~ +- 同时,您可以通过[SIGs]和[WGs]页面,找到对应的社区团体负责人的联系方式~ + +## 贡献者名单 + +[Contributors to DragonOS-Community/DragonOS · GitHub](https://github.com/DragonOS-Community/DragonOS/graphs/contributors) + +## 赞助 + +[![Sponsor this project](https://img.shields.io/badge/Sponsor_This_Project-DragonOS_Community-ff69b4?style=for-the-badge)](https://dragonos.org/?page_id=37) + +  DragonOS是一个公益性质的开源项目,它的发展离不开资金的支持,所有的赞助者的名单都会被公示。您的每一分赞助,都会为DragonOS的发展作出贡献! + +### 赞助的资金都会被用到哪里? + +我们保证,所有赞助的资金及物品,将会用于: + +- 活动开展、云服务开支,以及任何有利于DragonOS社区发展和建设的用途。 + +## 🌟 赞助商列表 + +**Special thanks to these generous financial supporters** (in reverse chronological order): + +- **[中国雅云](https://yacloud.net)** 雅安大数据产业园 - 🥇 Long-term supporter + +### 个人赞赏者列表 + +请见 [Supporters.md](./SUPPORTERS.md) + +## 开放源代码声明 + +本项目采用GPLv2协议进行开源,欢迎您在遵守开源协议的基础之上,使用本项目的代码! + +若您发现了任何违背开源协议的使用行为,我们欢迎您发邮件到 pmc@dragonos.org 反馈!让我们共同建设诚信的开源社区。 + +## 👩💻 Contributors + +> *"开源因你而更加闪耀!"* ✨ +**感谢所有提交代码、修复问题或审核PR的开发者**: + + + + + + +[DragonOS社区介绍文档]: https://community.dragonos.org/ +[社区管理团队]: https://community.dragonos.org/governance/staff-info.html +[SIGs]: https://community.dragonos.org/sigs/ +[WGs]: https://community.dragonos.org/wgs/ diff --git a/README_EN.md b/README_EN.md deleted file mode 100644 index b83b5bdb..00000000 --- a/README_EN.md +++ /dev/null @@ -1,119 +0,0 @@ -
- dragonos-logo
-

打造完全自主可控的数字化未来!

- -官网 -bbs - - - ---- - -
- -# DragonOS - -**Languages** [中文](README.md)|English - -  - -  DragonOS is a 64-bit operating system designed for lightweight cloud computing scenarios, featuring a fully independent kernel and offering Linux binary compatibility. Developed using the Rust programming language, it aims to provide improved reliability. In the Rust operating system domain, DragonOS consistently ranks among the top three on GitHub nationally. - -  The DragonOS open-source community was established in July 2022 and is entirely business-neutral. Our goal is to build a fully independent, open-source, high-performance, and highly reliable server operating system, fostering a digitally autonomous and controllable future! - -  DragonOS boasts an excellent and comprehensive architecture design. Compared to other systems of similar scale, DragonOS supports virtualization and has certain advantages in terms of device model and调度子系统 (scheduler subsystem).Currently, significant efforts are being made to promote cloud platform support, RISC-V compatibility, and the porting of compilers and application software. The aim is to achieve large-scale application in production environments within five years. - -  Driven by the community, DragonOS is currently evolving rapidly. DragonOS has already implemented about 1/4 of Linux interfaces, and in the future, we will strive to provide 100% compatibility with Linux, along with new features. - - -## Get Involved in Development? - -Carefully read the [DragonOS Community Introduction Document] to understand how the community operates and how you can contribute! - -- **To stay updated on development news and tasks, visit the DragonOS Community Forum**: [https://bbs.dragonos.org.cn](https://bbs.dragonos.org.cn) -- You can also learn about the development progress by checking the project's issues. - -  If you're interested in joining us, you can check out the issues and post your discussions or ideas under them, or visit the DragonOS forum to learn about development updates and tasks: [https://bbs.dragonos.org.cn](https://bbs.dragonos.org.cn) - -  You're also welcome to bring your creative ideas and discuss them with the community members, working together to create new features for DragonOS. - - -## Website - -- **Project's Website**: [DragonOS.org](https://dragonos.org) -- Documentation: [docs.dragonos.org](https://docs.dragonos.org) -- Community Introduction Document: [community.dragonos.org](https://community.dragonos.org) - -## How to Run? - -  Running DragonOS is quite straightforward. You can refer to the following resources and get DragonOS up and running in as little as 15 minutes! - -- [Building DragonOS — DragonOS Development Documentation](https://docs.dragonos.org/zh_CN/latest/introduction/build_system.html) - -## How to Connect with the Community? - -Please read the [Contributor Guide](https://community.dragonos.org/contributors/#%E7%A4%BE%E5%8C%BA)~ - -- You can establish contact with the members of various committees through the [Community Management Team] information. -- Additionally, you can find the contact information of the respective community group leaders via the [SIGs] and [WGs] pages. - - -## Reward - -  DragonOS is an open source public welfare project, but its development cannot be separated from the support of funds. If you want, you can visit **[Sponsor - DragonOS](https://dragonos.org/?page_id=37)** , so as to promote the development of this project. The list of all sponsors will be published. Every bit of your sponsorship will contribute to the development of DragonOS! - -### Where will the sponsorship funds be used? - -We guarantee that all sponsorship funds and items will be used for: - -- Subsidies or equipment support for active community developers -- Cloud service expenditure of DragonOS -- Equipment purchase -- Any use conducive to the development and construction of DragonOS - -### Sponsor List - -**Not yet** - -- **[China YaCloud](https://yacloud.net)** Ya'an Digital Economy Operations Co., Ltd. provides cloud server support for DragonOS. - -### Individual Sponsor List - - -- 万晓兰 -- David Wen -- [YJwu2023](https://github.com/YJwu2023) -- [longjin](https://github.com/fslongjin) -- [黄铭涛](https://github.com/1037827920) -- [许梓毫](https://github.com/Jomocool) -- [谢润霖](https://github.com/xiaolin2004) -- [蔡俊源](https://github.com/SMALLC04) -- Kelly -- [Samuka007](https://github.com/Samuka007) -- [杨璐玮](https://github.com/val213) -- [何懿聪](https://github.com/GnoCiYeH) -- [周凯韬](https://github.com/laokengwt) -- [Seele.Clover](https://github.com/seeleclover) -- [FindWangHao](https://github.com/FindWangHao) -- [ferchiel](https://github.com/ferchiel) -- 叶锦毅 -- 林 -- Albert -- [TerryLeeSCUT · GitHub](https://github.com/TerryLeeSCUT) -- slientbard -- 悟 - -## Open source statement - -  This project adopts GPLv2 LICENSE for open source. You are welcome to use the code of this project on the basis of abiding by the open source license! - -**What we support:** using this project to create greater value and contribute code to this project under the condition of abiding by the agreement. - -**What we condemn**: any non-compliance with the open source license. Including but not limited to: plagiarizing the code of the project as your graduation project and other academic misconduct, as well as commercial closed source use without payment. - -If you find any violation of the open source license, we welcome you to send email feedback! Let's build an honest open source community together! - -[DragonOS Community Introduction Document]: https://community.dragonos.org/ -[Community Management Team]: https://community.dragonos.org/governance/staff-info.html -[SIGs]: https://community.dragonos.org/sigs/ -[WGs]: https://community.dragonos.org/wgs/ diff --git a/SUPPORTERS.md b/SUPPORTERS.md new file mode 100644 index 00000000..2ac75e88 --- /dev/null +++ b/SUPPORTERS.md @@ -0,0 +1,64 @@ +# 🙌 Supporters & Contributors + +Thank you to the following individuals and organizations for supporting this project! Whether through code contributions, issue feedback, or financial sponsorship, your support makes this project better. + +> *"Open source shines because of you!"* ✨ +--- + +## 🌟 Sponsors + +**Special thanks to these generous financial supporters** (in reverse chronological order): + +[![Sponsor this project](https://img.shields.io/badge/Sponsor_This_Project-DragonOS_Community-ff69b4?style=for-the-badge)](https://dragonos.org/?page_id=37) + +- **[中国雅云](https://yacloud.net)** 雅安大数据产业园 - 🥇 Long-term supporter + +### Individual Supporters +- 万晓兰 +- David Wen +- [YJwu2023](https://github.com/YJwu2023) +- [longjin](https://github.com/fslongjin) +- [黄铭涛](https://github.com/1037827920) +- [许梓毫](https://github.com/Jomocool) +- [谢润霖](https://github.com/xiaolin2004) +- [蔡俊源](https://github.com/SMALLC04) +- Kelly +- [Samuka007](https://github.com/Samuka007) +- [杨璐玮](https://github.com/val213) +- [何懿聪](https://github.com/GnoCiYeH) +- [周凯韬](https://github.com/laokengwt) +- [Seele.Clover](https://github.com/seeleclover) +- [FindWangHao](https://github.com/FindWangHao) +- [ferchiel](https://github.com/ferchiel) +- 叶锦毅 +- 林 +- Albert +- [TerryLeeSCUT · GitHub](https://github.com/TerryLeeSCUT) +- slientbard +- 悟 +--- + +## 👩💻 Contributors + +**Thanks to all developers who submitted code, fixed issues, or reviewed PRs**: + + + + + +--- + +## 🤝 Community Supporters + +**Thanks to the following members for suggestions, testing, and promotion** +--- + +## 🙏 How to Join This List? + +If you'd like to support this project, here's how: +1. **Code Contributions**: Submit PRs to address [open issues](https://github.com/DragonOS-Community/DragonOS/issues) +2. **Financial Sponsorship**: [![Sponsor this project](https://img.shields.io/badge/Sponsor_This_Project-DragonOS_Community-ff69b4?style=for-the-badge)](https://dragonos.org/?page_id=37) +3. **Community Help**: Test new releases, share the project, provide feedback + +All valid supporters will be periodically updated to this list (anonymous display available upon request). +--- diff --git a/build-scripts/Cargo.lock b/build-scripts/Cargo.lock index 9510b443..ad11cc79 100644 --- a/build-scripts/Cargo.lock +++ b/build-scripts/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -87,12 +87,6 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" -[[package]] -name = "elf" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" - [[package]] name = "equivalent" version = "1.0.1" @@ -109,6 +103,10 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "gen_kallsyms" +version = "0.1.0" + [[package]] name = "glob" version = "0.3.1" @@ -193,13 +191,6 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" -[[package]] -name = "linux_boot_helper" -version = "0.1.0" -dependencies = [ - "elf", -] - [[package]] name = "log" version = "0.4.20" diff --git a/build-scripts/Cargo.toml b/build-scripts/Cargo.toml index 56299a19..fe62175e 100644 --- a/build-scripts/Cargo.toml +++ b/build-scripts/Cargo.toml @@ -1,5 +1,3 @@ [workspace] -members = [ - "kernel_build", -] +members = ["gen_kallsyms", "kernel_build"] resolver = "2" diff --git a/build-scripts/Makefile b/build-scripts/Makefile index 35c6edd5..9cafbd7d 100644 --- a/build-scripts/Makefile +++ b/build-scripts/Makefile @@ -1,8 +1,9 @@ -.PHONY: fmt +all: + @cargo +nightly-2024-11-05 build --release -p gen_kallsyms fmt: cargo fmt --all $(FMT_CHECK) - clean: @cargo clean check: @cargo +nightly-2024-11-05 check --workspace $(CARGO_ZBUILD) --message-format=json +.PHONY: fmt \ No newline at end of file diff --git a/build-scripts/gen_kallsyms/Cargo.toml b/build-scripts/gen_kallsyms/Cargo.toml new file mode 100644 index 00000000..52b2a5c4 --- /dev/null +++ b/build-scripts/gen_kallsyms/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "gen_kallsyms" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/build-scripts/gen_kallsyms/src/main.rs b/build-scripts/gen_kallsyms/src/main.rs new file mode 100644 index 00000000..140df060 --- /dev/null +++ b/build-scripts/gen_kallsyms/src/main.rs @@ -0,0 +1,122 @@ +use std::str; + +#[derive(Debug, Clone)] +struct KernelSymbolEntry { + vaddr: u64, + #[allow(dead_code)] + symbol_type: char, + symbol: String, + symbol_length: usize, +} + +fn symbol_to_write(vaddr: u64, text_vaddr: u64, etext_vaddr: u64) -> bool { + vaddr >= text_vaddr && vaddr <= etext_vaddr +} +fn read_symbol(line: &str) -> Option { + if line.len() > 512 { + return None; + } // skip line with length >= 512 + let mut parts = line.split_whitespace(); + let vaddr = u64::from_str_radix(parts.next()?, 16).ok()?; + let symbol_type = parts.next()?.chars().next()?; + let symbol = parts.collect::>().join(" "); + if symbol_type != 'T' && symbol_type != 't' { + return None; + } // local symbol or global symbol in text section + if symbol == "$x" { + return None; + } // skip $x symbol + let symbol_length = symbol.len() + 1; // +1 for null terminator + Some(KernelSymbolEntry { + vaddr, + symbol_type, + symbol, + symbol_length, + }) +} + +fn read_map() -> (Vec, u64, u64) { + let mut symbol_table = Vec::new(); + let mut text_vaddr = 0; + let mut etext_vaddr = 0; + let mut line = String::new(); + loop { + let size = std::io::stdin().read_line(&mut line).unwrap(); + if size == 0 { + break; + } + line = line.trim().to_string(); + if let Some(entry) = read_symbol(&line) { + if entry.symbol.starts_with("_text") { + text_vaddr = entry.vaddr; + } else if entry.symbol.starts_with("_etext") { + etext_vaddr = entry.vaddr; + } + symbol_table.push(entry); + } + line.clear(); + } + (symbol_table, text_vaddr, etext_vaddr) +} + +fn generate_result(symbol_table: &[KernelSymbolEntry], text_vaddr: u64, etext_vaddr: u64) { + println!(".section .rodata\n"); + println!(".global kallsyms_address"); + println!(".align 8\n"); + println!("kallsyms_address:"); + + let mut last_vaddr = 0; + let mut total_syms_to_write = 0; + + for entry in symbol_table { + if !symbol_to_write(entry.vaddr, text_vaddr, etext_vaddr) || entry.vaddr == last_vaddr { + continue; + } + + println!("\t.quad\t{:#x}", entry.vaddr); + total_syms_to_write += 1; + last_vaddr = entry.vaddr; + } + + println!("\n.global kallsyms_num"); + println!(".align 8"); + println!("kallsyms_num:"); + println!("\t.quad\t{}", total_syms_to_write); + + println!("\n.global kallsyms_names_index"); + println!(".align 8"); + println!("kallsyms_names_index:"); + + let mut position = 0; + last_vaddr = 0; + + for entry in symbol_table { + if !symbol_to_write(entry.vaddr, text_vaddr, etext_vaddr) || entry.vaddr == last_vaddr { + continue; + } + + println!("\t.quad\t{}", position); + position += entry.symbol_length; + last_vaddr = entry.vaddr; + } + + println!("\n.global kallsyms_names"); + println!(".align 8"); + println!("kallsyms_names:"); + + last_vaddr = 0; + + for entry in symbol_table { + if !symbol_to_write(entry.vaddr, text_vaddr, etext_vaddr) || entry.vaddr == last_vaddr { + continue; + } + + println!("\t.asciz\t\"{}\"", entry.symbol); + last_vaddr = entry.vaddr; + } +} + +fn main() { + let (symbol_table, text_vaddr, etext_vaddr) = read_map(); + generate_result(&symbol_table, text_vaddr, etext_vaddr); +} diff --git a/build-scripts/kernel_build/src/bindgen/arch/loongarch64.rs b/build-scripts/kernel_build/src/bindgen/arch/loongarch64.rs new file mode 100644 index 00000000..ef458970 --- /dev/null +++ b/build-scripts/kernel_build/src/bindgen/arch/loongarch64.rs @@ -0,0 +1,10 @@ +use super::BindgenArch; + +pub struct LoongArch64BindgenArch; +impl BindgenArch for LoongArch64BindgenArch { + fn generate_bindings(&self, builder: bindgen::Builder) -> bindgen::Builder { + builder + .clang_arg("-I./src/arch/loongarch64/include") + .clang_arg("--target=x86_64-none-none") // 由于clang不支持loongarch64,所以使用x86_64作为目标,按理来说问题不大 + } +} diff --git a/build-scripts/kernel_build/src/bindgen/arch/mod.rs b/build-scripts/kernel_build/src/bindgen/arch/mod.rs deleted file mode 100644 index 59ea10a2..00000000 --- a/build-scripts/kernel_build/src/bindgen/arch/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::utils::cargo_handler::{CargoHandler, TargetArch}; - -use self::x86_64::X86_64BindgenArch; - -pub mod riscv64; -pub mod x86_64; - -pub(super) trait BindgenArch { - fn generate_bindings(&self, builder: bindgen::Builder) -> bindgen::Builder; -} - -/// 获取当前的bindgen架构; -pub(super) fn current_bindgenarch() -> &'static dyn BindgenArch { - let arch = CargoHandler::target_arch(); - match arch { - TargetArch::X86_64 => &X86_64BindgenArch, - TargetArch::Riscv64 => &riscv64::RiscV64BindgenArch, - _ => panic!("Unsupported arch: {:?}", arch), - } -} diff --git a/build-scripts/kernel_build/src/bindgen/arch/riscv64.rs b/build-scripts/kernel_build/src/bindgen/arch/riscv64.rs deleted file mode 100644 index c8eb32e6..00000000 --- a/build-scripts/kernel_build/src/bindgen/arch/riscv64.rs +++ /dev/null @@ -1,10 +0,0 @@ -use super::BindgenArch; - -pub struct RiscV64BindgenArch; -impl BindgenArch for RiscV64BindgenArch { - fn generate_bindings(&self, builder: bindgen::Builder) -> bindgen::Builder { - builder - .clang_arg("-I./src/arch/riscv64/include") - .clang_arg("--target=riscv64-none-none-elf") - } -} diff --git a/build-scripts/kernel_build/src/bindgen/arch/x86_64.rs b/build-scripts/kernel_build/src/bindgen/arch/x86_64.rs deleted file mode 100644 index 7f9faf23..00000000 --- a/build-scripts/kernel_build/src/bindgen/arch/x86_64.rs +++ /dev/null @@ -1,11 +0,0 @@ -use super::BindgenArch; - -pub struct X86_64BindgenArch; - -impl BindgenArch for X86_64BindgenArch { - fn generate_bindings(&self, builder: bindgen::Builder) -> bindgen::Builder { - builder - .clang_arg("-I./src/arch/x86_64/include") - .clang_arg("--target=x86_64-none-none") - } -} diff --git a/build-scripts/kernel_build/src/bindgen/mod.rs b/build-scripts/kernel_build/src/bindgen/mod.rs deleted file mode 100644 index 8a5014ae..00000000 --- a/build-scripts/kernel_build/src/bindgen/mod.rs +++ /dev/null @@ -1,50 +0,0 @@ -use std::{path::PathBuf, str::FromStr}; - -use crate::{bindgen::arch::current_bindgenarch, utils::cargo_handler::CargoHandler}; - -mod arch; - -/// 生成 C->Rust bindings -pub fn generate_bindings() { - let wrapper_h = PathBuf::from_str("src/include/bindings/wrapper.h") - .expect("Failed to parse 'wrapper.h' path"); - CargoHandler::emit_rerun_if_files_changed(&[wrapper_h.clone()]); - - let out_path = PathBuf::from(String::from("src/include/bindings/")); - - // The bindgen::Builder is the main entry point - // to bindgen, and lets you build up options for - // the resulting bindings. - - let builder = bindgen::Builder::default() - .clang_arg("-I./src") - .clang_arg("-I./src/include") - // The input header we would like to generate - // bindings for. - .header(wrapper_h.to_str().unwrap()) - .blocklist_file("src/include/bindings/bindings.h") - .clang_arg("-v") - // 使用core,并将c语言的类型改为core::ffi,而不是使用std库。 - .use_core() - .ctypes_prefix("::core::ffi") - .generate_inline_functions(true) - .raw_line("#![allow(dead_code)]") - .raw_line("#![allow(non_upper_case_globals)]") - .raw_line("#![allow(non_camel_case_types)]") - // Tell cargo to invalidate the built crate whenever any of the - // included header files changed. - .parse_callbacks(Box::new(bindgen::CargoCallbacks)); - - // 处理架构相关的绑定 - let builder = current_bindgenarch().generate_bindings(builder); - - // Finish the builder and generate the bindings. - let bindings = builder - .generate() - // Unwrap the Result and panic on failure. - .expect("Unable to generate bindings"); - - bindings - .write_to_file(out_path.join("bindings.rs")) - .expect("Couldn't write bindings!"); -} diff --git a/build-scripts/kernel_build/src/cfiles/arch/loongarch64.rs b/build-scripts/kernel_build/src/cfiles/arch/loongarch64.rs new file mode 100644 index 00000000..d07c7879 --- /dev/null +++ b/build-scripts/kernel_build/src/cfiles/arch/loongarch64.rs @@ -0,0 +1,29 @@ +use std::{collections::HashSet, path::PathBuf}; + +use crate::constant::ARCH_DIR_LOONGARCH64; + +use super::CFilesArch; + +pub(super) struct LoongArch64CFilesArch; + +impl CFilesArch for LoongArch64CFilesArch { + fn setup_defines(&self, c: &mut cc::Build) { + c.define("__loongarch64__", None); + c.define("__loongarch", None); + } + + fn setup_files(&self, _c: &mut cc::Build, _files: &mut HashSet) {} + + fn setup_global_flags(&self, c: &mut cc::Build) { + // 在这里设置编译器,不然的话vscode的rust-analyzer会报错 + c.compiler("loongarch64-unknown-linux-gnu-gcc"); + c.flag("-mcmodel=normal"); + + c.flag("-march=loongarch64"); + } +} + +#[allow(dead_code)] +fn arch_path(relative_path: &str) -> PathBuf { + PathBuf::from(format!("{}/{}", ARCH_DIR_LOONGARCH64, relative_path)) +} diff --git a/build-scripts/kernel_build/src/cfiles/arch/mod.rs b/build-scripts/kernel_build/src/cfiles/arch/mod.rs index 4f52d74e..a8fa7212 100644 --- a/build-scripts/kernel_build/src/cfiles/arch/mod.rs +++ b/build-scripts/kernel_build/src/cfiles/arch/mod.rs @@ -6,17 +6,15 @@ use crate::utils::cargo_handler::{CargoHandler, TargetArch}; use self::x86_64::X86_64CFilesArch; +pub mod loongarch64; pub mod riscv64; pub mod x86_64; pub(super) trait CFilesArch { /// 设置架构相关的宏定义 fn setup_defines(&self, c: &mut Build); - /// 设置架构相关的全局包含目录 - fn setup_global_include_dir(&self, c: &mut HashSet); /// 设置需要编译的架构相关的文件 fn setup_files(&self, c: &mut Build, files: &mut HashSet); - /// 设置架构相关的全局编译标志 fn setup_global_flags(&self, c: &mut Build); } @@ -27,6 +25,8 @@ pub(super) fn current_cfiles_arch() -> &'static dyn CFilesArch { match arch { TargetArch::X86_64 => &X86_64CFilesArch, TargetArch::Riscv64 => &riscv64::RiscV64CFilesArch, + TargetArch::LoongArch64 => &loongarch64::LoongArch64CFilesArch, + _ => panic!("Unsupported arch: {:?}", arch), } } diff --git a/build-scripts/kernel_build/src/cfiles/arch/riscv64.rs b/build-scripts/kernel_build/src/cfiles/arch/riscv64.rs index 655af27e..79339e8b 100644 --- a/build-scripts/kernel_build/src/cfiles/arch/riscv64.rs +++ b/build-scripts/kernel_build/src/cfiles/arch/riscv64.rs @@ -1,8 +1,5 @@ -use std::{collections::HashSet, path::PathBuf}; - -use crate::{constant::ARCH_DIR_RISCV64, utils::FileUtils}; - use super::CFilesArch; +use std::{collections::HashSet, path::PathBuf}; pub(super) struct RiscV64CFilesArch; @@ -12,18 +9,8 @@ impl CFilesArch for RiscV64CFilesArch { c.define("__riscv", None); } - fn setup_global_include_dir(&self, include_dirs: &mut HashSet) { - include_dirs.insert("src/arch/riscv64/include".into()); - } - fn setup_files(&self, _c: &mut cc::Build, files: &mut HashSet) { files.insert(PathBuf::from("src/arch/riscv64/asm/head.S")); - - FileUtils::list_all_files(&arch_path("asm"), Some("c"), true) - .into_iter() - .for_each(|f| { - files.insert(f); - }); } fn setup_global_flags(&self, c: &mut cc::Build) { @@ -37,7 +24,3 @@ impl CFilesArch for RiscV64CFilesArch { c.flag("-march=rv64gc"); } } - -fn arch_path(relative_path: &str) -> PathBuf { - PathBuf::from(format!("{}/{}", ARCH_DIR_RISCV64, relative_path)) -} diff --git a/build-scripts/kernel_build/src/cfiles/arch/x86_64.rs b/build-scripts/kernel_build/src/cfiles/arch/x86_64.rs index 65ef94fc..d8cbdebb 100644 --- a/build-scripts/kernel_build/src/cfiles/arch/x86_64.rs +++ b/build-scripts/kernel_build/src/cfiles/arch/x86_64.rs @@ -1,10 +1,6 @@ -use std::{collections::HashSet, path::PathBuf}; - -use cc::Build; - -use crate::{constant::ARCH_DIR_X86_64, utils::FileUtils}; - use super::CFilesArch; +use cc::Build; +use std::{collections::HashSet, path::PathBuf}; pub(super) struct X86_64CFilesArch; @@ -13,20 +9,7 @@ impl CFilesArch for X86_64CFilesArch { c.define("__x86_64__", None); } - fn setup_global_include_dir(&self, include_dirs: &mut HashSet) { - include_dirs.insert("src/arch/x86_64/include".into()); - } - fn setup_files(&self, _c: &mut Build, files: &mut HashSet) { - const DIRS: [&str; 4] = ["driver/apic", "init", "asm", "interrupt"]; - DIRS.iter().for_each(|dir| { - FileUtils::list_all_files(&arch_path(dir), Some("c"), true) - .into_iter() - .for_each(|f| { - files.insert(f); - }); - }); - // setup asm files files.insert(PathBuf::from("src/arch/x86_64/asm/head.S")); files.insert(PathBuf::from("src/arch/x86_64/asm/entry.S")); @@ -39,7 +22,3 @@ impl CFilesArch for X86_64CFilesArch { c.flag("-mcmodel=large").flag("-m64"); } } - -fn arch_path(relative_path: &str) -> PathBuf { - PathBuf::from(format!("{}/{}", ARCH_DIR_X86_64, relative_path)) -} diff --git a/build-scripts/kernel_build/src/cfiles/common.rs b/build-scripts/kernel_build/src/cfiles/common.rs index 3488e731..679e05c9 100644 --- a/build-scripts/kernel_build/src/cfiles/common.rs +++ b/build-scripts/kernel_build/src/cfiles/common.rs @@ -1,20 +1,7 @@ use std::{collections::HashSet, path::PathBuf}; -use crate::utils::FileUtils; - -pub(super) fn setup_common_files(files: &mut HashSet) { - const DIRS: [&str; 3] = ["src/common", "src/debug/traceback", "src/libs"]; - DIRS.iter().for_each(|dir| { - FileUtils::list_all_files(&dir.into(), Some("c"), true) - .into_iter() - .for_each(|f| { - files.insert(f); - }); - }); -} - pub(super) fn setup_common_include_dir(include_dirs: &mut HashSet) { - const DIRS: [&str; 3] = ["src/include", "src/common", "src"]; + const DIRS: [&str; 2] = ["src/common", "src"]; DIRS.iter().for_each(|dir| { include_dirs.insert(dir.into()); }); diff --git a/build-scripts/kernel_build/src/cfiles/mod.rs b/build-scripts/kernel_build/src/cfiles/mod.rs index 90173d66..94c6ec3c 100644 --- a/build-scripts/kernel_build/src/cfiles/mod.rs +++ b/build-scripts/kernel_build/src/cfiles/mod.rs @@ -20,6 +20,9 @@ impl CFilesBuilder { Self::setup_defines(&mut c); Self::setup_global_include_dir(&mut c); Self::setup_files(&mut c); + if c.get_files().count() == 0 { + return; + } c.compile("dragonos_kernel_cfiles"); } @@ -53,8 +56,6 @@ impl CFilesBuilder { common::setup_common_include_dir(&mut include_dirs); - current_cfiles_arch().setup_global_include_dir(&mut include_dirs); - let include_dirs: Vec = include_dirs.into_iter().collect(); Self::set_rerun_if_files_changed(&include_dirs); @@ -67,7 +68,6 @@ impl CFilesBuilder { fn setup_files(c: &mut Build) { let mut files: HashSet = HashSet::new(); current_cfiles_arch().setup_files(c, &mut files); - common::setup_common_files(&mut files); // 去重 let files: Vec = files.into_iter().collect(); Self::set_rerun_if_files_changed(&files); diff --git a/build-scripts/kernel_build/src/constant/mod.rs b/build-scripts/kernel_build/src/constant.rs similarity index 51% rename from build-scripts/kernel_build/src/constant/mod.rs rename to build-scripts/kernel_build/src/constant.rs index 065e67b7..10f14a20 100644 --- a/build-scripts/kernel_build/src/constant/mod.rs +++ b/build-scripts/kernel_build/src/constant.rs @@ -1,2 +1,5 @@ +#[allow(dead_code)] pub const ARCH_DIR_X86_64: &str = "src/arch/x86_64"; +#[allow(dead_code)] pub const ARCH_DIR_RISCV64: &str = "src/arch/riscv64"; +pub const ARCH_DIR_LOONGARCH64: &str = "src/arch/loongarch64"; diff --git a/build-scripts/kernel_build/src/lib.rs b/build-scripts/kernel_build/src/lib.rs index 21844c53..75f11386 100644 --- a/build-scripts/kernel_build/src/lib.rs +++ b/build-scripts/kernel_build/src/lib.rs @@ -2,7 +2,6 @@ extern crate lazy_static; extern crate cc; -mod bindgen; mod cfiles; mod constant; mod kconfig; @@ -12,7 +11,6 @@ mod utils; pub fn run() { println!("cargo:rustc-link-search=src"); - crate::bindgen::generate_bindings(); crate::cfiles::CFilesBuilder::build(); crate::kconfig::KConfigBuilder::build(); } diff --git a/build-scripts/kernel_build/src/utils/cargo_handler.rs b/build-scripts/kernel_build/src/utils/cargo_handler.rs index 7d196c2f..8f496ba6 100644 --- a/build-scripts/kernel_build/src/utils/cargo_handler.rs +++ b/build-scripts/kernel_build/src/utils/cargo_handler.rs @@ -68,6 +68,7 @@ pub enum TargetArch { Riscv64, Mips64, Powerpc64, + LoongArch64, S390x, Sparc64, Unknown, @@ -85,6 +86,7 @@ impl TargetArch { "riscv64" => TargetArch::Riscv64, "mips64" => TargetArch::Mips64, "powerpc64" => TargetArch::Powerpc64, + "loongarch64" => TargetArch::LoongArch64, "s390x" => TargetArch::S390x, "sparc64" => TargetArch::Sparc64, _ => TargetArch::Unknown, diff --git a/build-scripts/kernel_build/src/utils/mod.rs b/build-scripts/kernel_build/src/utils/mod.rs index f78eaf16..5c56e689 100644 --- a/build-scripts/kernel_build/src/utils/mod.rs +++ b/build-scripts/kernel_build/src/utils/mod.rs @@ -2,8 +2,10 @@ use std::path::PathBuf; pub mod cargo_handler; +#[allow(dead_code)] pub struct FileUtils; +#[allow(dead_code)] impl FileUtils { /// 列出指定目录下的所有文件 /// diff --git a/dadk-manifest.toml b/dadk-manifest.toml index bbb88120..bafabac4 100644 --- a/dadk-manifest.toml +++ b/dadk-manifest.toml @@ -1,7 +1,7 @@ # DADK 总控文件 [metadata] -# Target architecture. Options: x86_64, riscv64 +# Target architecture. Options: x86_64, riscv64, loongarch64 arch = "x86_64" # Hypervisor config path diff --git a/docs/.translation_cache.json b/docs/.translation_cache.json new file mode 100644 index 00000000..fa7d207f --- /dev/null +++ b/docs/.translation_cache.json @@ -0,0 +1,275 @@ +{ + "en:kernel/memory_management/index.rst": { + "hash": "e394aa123a0030c0ec4276485fc764b7" + }, + "en:kernel/debug/index.rst": { + "hash": "6dc058a954b8620162e8293faa4959b2" + }, + "en:kernel/libs/index.rst": { + "hash": "d8667f36cbfe9d9f532737a3fbe39f2d" + }, + "en:kernel/process_management/index.rst": { + "hash": "b200476562e580ee97d8a3ffe19d5605" + }, + "en:kernel/libs/unified-init.md": { + "hash": "28374260f0134386d53392156d749733" + }, + "en:kernel/process_management/load_binary.md": { + "hash": "b7d462c7c6573ecab186c535346d6609" + }, + "en:kernel/core_api/index.rst": { + "hash": "7889b9dd1b120f09f3b7feaa2dbb3c41" + }, + "en:kernel/process_management/kthread.md": { + "hash": "0ce92c5a05a0e78dfceb89c215294e28" + }, + "en:kernel/debug/traceback.md": { + "hash": "f22fcde87181fe9bb5ba97f133506ca1" + }, + "en:kernel/core_api/casting.md": { + "hash": "b86564a0d602dfad61ab0893de43a8f8" + }, + "en:kernel/memory_management/intro.md": { + "hash": "777fe6a902720949596f5a35bdf26372" + }, + "en:kernel/syscall/index.rst": { + "hash": "d94e7cff4242362399e96051df1e7aad" + }, + "en:kernel/libs/lib_ui/scm.md": { + "hash": "a03d756677c64b1247cfe40b6d73f1b1" + }, + "en:kernel/libs/id-allocation.md": { + "hash": "5789b9d1fe4f8f72848412f6e766e099" + }, + "en:kernel/memory_management/allocate-memory.md": { + "hash": "9a5c0ec57bae0576c30fbab60407f178" + }, + "en:kernel/locking/index.rst": { + "hash": "299b0ccecf4ef174fffcce4731a98728" + }, + "en:kernel/sched/index.rst": { + "hash": "76ca73ed6d47a4207d2ca193b88eae0b" + }, + "en:kernel/locking/locks.md": { + "hash": "5514ff361db4677d2b4fa522852aaeea" + }, + "en:kernel/sched/cfs.md": { + "hash": "7c89ba1c0416ec346f2982b3139cc819" + }, + "en:kernel/core_api/notifier_chain.md": { + "hash": "5d21aad4640544ad49348d3cd2e8a386" + }, + "en:kernel/filesystem/index.rst": { + "hash": "52dd12d566da2003602ee21c4a3d007f" + }, + "en:kernel/ktest/index.rst": { + "hash": "5a4565952877c82b9a0ed3b67103c141" + }, + "en:kernel/filesystem/vfs/api.md": { + "hash": "1b0b3fe0cc2918cc2c53a5af392a96ff" + }, + "en:kernel/filesystem/vfs/index.rst": { + "hash": "d0de5d78a2105a1ecfe4ef137c18f7f5" + }, + "en:kernel/debug/profiling-kernel-with-dadk.md": { + "hash": "966d07272ad19e1afbdc64bb6cfcea73" + }, + "en:kernel/filesystem/unionfs/index.rst": { + "hash": "7ee4201508b51b4c5ac9e3b520472cd6" + }, + "en:kernel/core_api/atomic.md": { + "hash": "ff17c6b902baddffff32cb9f70ddefcb" + }, + "en:kernel/libs/lib_ui/textui.md": { + "hash": "dc914079508390cf7544b5b9c7ef7e4f" + }, + "en:kernel/sched/rust_waiting.md": { + "hash": "6777e758cd796a356c8789f4306911ae" + }, + "en:kernel/locking/rwlock.md": { + "hash": "457db706fcf5f4a7e45d15d496a29605" + }, + "en:kernel/configuration/index.rst": { + "hash": "77a375890e3abf508ea1147da0e92a50" + }, + "en:kernel/filesystem/kernfs.md": { + "hash": "da5cf8148a5ab38c6d0efd9ada8a0a29" + }, + "en:kernel/container/namespaces/index.rst": { + "hash": "60c3b1e0726791677414064c2a98e848" + }, + "en:kernel/filesystem/vfs/design.md": { + "hash": "16577686b5f5b15a5cfb25f379e01a03" + }, + "en:kernel/syscall/syscall_table.rst": { + "hash": "dc34f86b55c62bdd1777a97eb7e6bd26" + }, + "en:kernel/filesystem/unionfs/overlayfs.md": { + "hash": "2eba6973dc429ea15ad6ac8f47bfa187" + }, + "en:kernel/container/index.rst": { + "hash": "624e76dd31081ef9304da582d835992f" + }, + "en:kernel/container/namespaces/mnt_namespace.md": { + "hash": "19af9b11f162c0e4be4725d8458fd253" + }, + "en:kernel/memory_management/mmio.md": { + "hash": "e956a9cd454416578996f955cd905a08" + }, + "en:kernel/cpu_arch/x86_64/index.rst": { + "hash": "ff36e992e4dee15f740259d545e161e2" + }, + "en:kernel/sched/rt.md": { + "hash": "913a29f3bccbf0c10a093fd558100e8d" + }, + "en:kernel/cpu_arch/index.rst": { + "hash": "72efe542c7854926ac0f33287345b856" + }, + "en:kernel/ipc/index.rst": { + "hash": "bbc40e0a41a1467dbdd42196c443f1ef" + }, + "en:kernel/boot/index.rst": { + "hash": "8fe854f9c48d4e2e3fee0cf7f3526dfe" + }, + "en:kernel/container/namespaces/pid_namespace.md": { + "hash": "7b78f405306356aec439bfd5bad69967" + }, + "en:kernel/cpu_arch/x86_64/usb_legacy_support.md": { + "hash": "a0c3300d1641f613777d631578e0ea58" + }, + "en:kernel/sched/kernel_timer.md": { + "hash": "95bf320a3e748c7bb41150940fee0e77" + }, + "en:kernel/configuration/arch.md": { + "hash": "a024ea920cdb719454beaae1eb9e09e9" + }, + "en:kernel/filesystem/sysfs.md": { + "hash": "68d5270491432d41b254c750d59aca89" + }, + "en:kernel/core_api/softirq.md": { + "hash": "c931f3fcfca7d8d10cd16a8b68e6274a" + }, + "en:community/ChangeLog/index.rst": { + "hash": "aa1979d81b79f64b12962f885a6820af" + }, + "en:kernel/trace/index.rst": { + "hash": "944a5b865100258ec7957a4cbedd7251" + }, + "en:kernel/configuration/config.md": { + "hash": "dff794c4f3bfb4c3d66e6d0fa8f7c495" + }, + "en:kernel/sched/core.md": { + "hash": "f449acec9b9ad36c4a75e8594d38e44d" + }, + "en:kernel/filesystem/overview.md": { + "hash": "44499f7673a0c68c53b12882258b9f5c" + }, + "en:kernel/boot/bootloader.md": { + "hash": "e6f65060560663ca2ce4d56d750332d8" + }, + "en:kernel/ipc/signal.md": { + "hash": "abe911dac525b44fe083752a1e6bbdc7" + }, + "en:kernel/locking/mutex.md": { + "hash": "a82fa540acd44a93f5cb3c069d5584da" + }, + "en:kernel/boot/cmdline.md": { + "hash": "3d17446c60b72e9cadf82002520ebbf9" + }, + "en:community/code_contribution/index.rst": { + "hash": "38b6fe56ee739723a662cd1fec7a194a" + }, + "en:community/contact/index.rst": { + "hash": "1fbd4c64558614101f195681b92a179e" + }, + "en:kernel/locking/spinlock.md": { + "hash": "b97729ffa1d19fb131a85c72c2411146" + }, + "en:kernel/trace/kprobe.md": { + "hash": "7e92cda81dfc19881d45e7cc0606f8c6" + }, + "en:introduction/mirrors.md": { + "hash": "e5b572a5f5abca55e9ffcbc9827ce6f7" + }, + "en:community/ChangeLog/V0.1.x/V0.1.8.md": { + "hash": "8c26796807713751958810efecaedebd" + }, + "en:community/ChangeLog/V0.1.x/V0.1.7.md": { + "hash": "c74fe7a6db6d59d3d6d5116d4c4e0ceb" + }, + "en:community/ChangeLog/V0.1.x/V0.1.9.md": { + "hash": "bf42117b62c4739a8101b33390b5a4c7" + }, + "en:community/code_contribution/rust-coding-style.md": { + "hash": "db7eddfe4d16166ebe28def72f63fbb6" + }, + "en:community/ChangeLog/V0.1.x/V0.1.1.md": { + "hash": "d94351167179beb0bb1b1f3bb82da2ff" + }, + "en:userland/appdev/index.rst": { + "hash": "78e6747475981b5cc17cd206c135ca4f" + }, + "en:userland/appdev/c-cpp-quick-start.md": { + "hash": "0101f8fa98a0536d43ff897145d4a43d" + }, + "en:community/code_contribution/c-coding-style.md": { + "hash": "ea3c95cc032e4fa7cde32a56359ab328" + }, + "en:community/code_contribution/conventional-commit.md": { + "hash": "31666b2ee98f5fe3698ae234b6ef0f00" + }, + "en:userland/appdev/rust-quick-start.md": { + "hash": "6366c994d75086098469d8ea02555b88" + }, + "en:kernel/debug/debug-kernel-with-gdb.md": { + "hash": "ab7904f52dcf35d0675e48fe8e88ec9a" + }, + "en:community/ChangeLog/V0.1.x/V0.1.3.md": { + "hash": "c302428982363f627bedda89c1ab9232" + }, + "en:introduction/index.rst": { + "hash": "a7c445abd29ce6817b098787f69902b7" + }, + "en:kernel/sched/c_waiting.md": { + "hash": "bb2435e3905e8e71eca8f6a583e31d94" + }, + "en:introduction/build_system.md": { + "hash": "fafac4210fb49c9e160b46c2101df238" + }, + "en:community/ChangeLog/V0.1.x/V0.1.4.md": { + "hash": "5720af929320997f8824bcdfd3a17bdd" + }, + "en:kernel/trace/eBPF.md": { + "hash": "62f8451a2e9e851a67266bf8cbb0fc6d" + }, + "en:community/ChangeLog/V0.1.x/V0.1.6.md": { + "hash": "5517b35f61f5b89d8e825a399581ea0f" + }, + "en:introduction/features.md": { + "hash": "75d47fcb0d83487b28957dace1e24578" + }, + "en:community/ChangeLog/V0.1.x/V0.1.5.md": { + "hash": "898444d989993df55486ca8d454efbb6" + }, + "en:community/ChangeLog/V0.1.x/V0.1.0.md": { + "hash": "26fef9a12925fdcc4729f363ae5b2614" + }, + "en:community/ChangeLog/V0.1.x/V0.1.2.md": { + "hash": "41afa92fde268ffd547a3e4326fba1cd" + }, + "en:community/ChangeLog/V0.1.x/V0.1.10.md": { + "hash": "7a292c40f822e371ea650f3157857844" + }, + "en:kernel/core_api/kernel_api.md": { + "hash": "8b840ec6af5782d8f793f746b1061ed9" + }, + "en:index.rst": { + "hash": "9bdd33a9fc7a2648cded2d463fe29115" + }, + "en:questions/index.rst": { + "hash": "b1cee9bfde04d6375f24c93a29ce3c71" + }, + "en:questions/build_errors.md": { + "hash": "76bf24821bab907c28e8c8287d2895d5" + } +} \ No newline at end of file diff --git a/docs/community/contact/index.rst b/docs/community/contact/index.rst index d85e0443..32f0586a 100644 --- a/docs/community/contact/index.rst +++ b/docs/community/contact/index.rst @@ -1,7 +1,7 @@ .. _get_contact_with_community: 与社区建立联系 -==================================== +==================================================================== 联系方式 ------------------------- @@ -18,7 +18,7 @@ DragonOS官网: https://DragonOS.org 赞助及捐赠 -------------------------- +--------------------------------------------------------- DragonOS是一个开源项目,我们欢迎任何形式的赞助和捐赠,您的捐赠将用于DragonOS的开发和维护,以及社区的运营。 @@ -28,6 +28,7 @@ DragonOS是一个开源项目,我们欢迎任何形式的赞助和捐赠,您 - 联系社区负责人,沟通具体的赞助方式等。联系方式:longjin@dragonos.org 财务及捐赠信息公开 -------------------------- +--------------------------------------------------------- DragonOS社区的捐赠信息将按年进行公开。赞助商、赞助者信息将在收到赞助后,15天内进行公开。 + diff --git a/docs/conf.py b/docs/conf.py index 235cd9ca..e6bcc1c6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,7 +17,7 @@ import os # -- Project information ----------------------------------------------------- project = 'DragonOS' -copyright = '2022-2024, DragonOS Community' +copyright = '2022-2025, DragonOS Community' author = 'longjin' github_org = 'DragonOS-Community' github_repo = 'DragonOS' @@ -31,7 +31,12 @@ release = 'dev' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['myst_parser', 'sphinx_multiversion'] +extensions = [ + 'myst_parser', + 'sphinx_multiversion', + 'sphinxcontrib.mermaid', + 'sphinx.ext.extlinks', +] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -42,6 +47,7 @@ templates_path = ['_templates'] # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = 'zh_CN' +locale_dirs = ['locale/'] # path is example but recommended. # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. diff --git a/docs/index.rst b/docs/index.rst index c9ab406d..30ebea4b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,9 +3,22 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. +.. Note: __EXCLUDE_IN_TRANSLATED_START + 欢迎来到DragonOS的文档! ==================================== +.. raw:: html + +
+

Translations

+ +
+ +.. Note: __EXCLUDE_IN_TRANSLATED_END + .. toctree:: :maxdepth: 1 :caption: 入门 @@ -34,6 +47,7 @@ kernel/libs/index kernel/net/index kernel/trace/index + kernel/syscall/index @@ -45,9 +59,11 @@ .. toctree:: :maxdepth: 1 - :caption: 系统调用api文档 + :caption: Q&A + + questions/index + - syscall_api/index .. toctree:: :maxdepth: 1 @@ -57,6 +73,13 @@ community/contact/index community/ChangeLog/index +.. Note: __EXCLUDE_IN_TRANSLATED_START + +.. toctree:: + :maxdepth: 1 + :caption: Translations + + locales/en/index Indices and tables ================== @@ -64,3 +87,5 @@ Indices and tables * :ref:`genindex` * :ref:`modindex` * :ref:`search` + +.. Note: __EXCLUDE_IN_TRANSLATED_END diff --git a/docs/introduction/build_system.md b/docs/introduction/build_system.md index 8b6cb21c..1e66d16f 100644 --- a/docs/introduction/build_system.md +++ b/docs/introduction/build_system.md @@ -240,6 +240,8 @@ make run-docker - 本地编译,不运行: `make all -j 您的CPU核心数` - 本地编译,并写入磁盘镜像,不运行: `make build` - 本地编译,写入磁盘镜像,并在QEMU中运行: `make run` +- 本地编译,写入磁盘镜像,以无图形模式运行: +`make run-nographic` - Docker编译,并写入磁盘镜像,: `make docker` - Docker编译,写入磁盘镜像,并在QEMU中运行: `make run-docker` - 不编译,直接从已有的磁盘镜像启动: `make qemu` diff --git a/docs/kernel/core_api/kernel_api.md b/docs/kernel/core_api/kernel_api.md index f45d3a42..751a39fa 100644 --- a/docs/kernel/core_api/kernel_api.md +++ b/docs/kernel/core_api/kernel_api.md @@ -572,86 +572,6 @@   第二个字符串 -#### `printk(const char* fmt, ...)` - -##### 描述 - -  该宏能够在控制台上以黑底白字格式化输出字符串. - -##### 参数 - -**fmt** - -  源格式字符串 - -**...** - -  可变参数 - -#### `printk_color(unsigned int FRcolor, unsigned int BKcolor, const char* fmt, ...)` - -##### 描述 - -  在控制台上以指定前景色和背景色格式化输出字符串. - -##### 参数 - -**FRcolor** - -  前景色 - -**BKcolor** - -  背景色 - -**fmt** - -  源格式字符串 - -**...** - -  可变参数 - -#### `int vsprintf(char *buf, const char *fmt, va_list args)` - -##### 描述 - -  按照fmt格式化字符串,并将结果输出到buf中,返回写入buf的字符数量。 - -##### 参数 - -**buf** - -  输出缓冲区 - -**fmt** - -  源格式字符串 - -**args** - -  可变参数列表 - -#### `int sprintk(char *buf, const char *fmt, ...)` - -##### 描述 - -  按照fmt格式化字符串,并将结果输出到buf中,返回写入buf的字符数量。 - -##### 参数 - -**buf** - -  输出缓冲区 - -**fmt** - -  源格式字符串 - -**...** - -  可变参数 - ### 内存操作 #### `void *memcpy(void *dst, const void *src, uint64_t size)` diff --git a/docs/kernel/filesystem/overview.md b/docs/kernel/filesystem/overview.md index 1238f5a8..624a07fc 100644 --- a/docs/kernel/filesystem/overview.md +++ b/docs/kernel/filesystem/overview.md @@ -67,7 +67,7 @@ Syscall: │ sys_open, sys_read, sys_write, sys_close, │ - `sys_fchmod`:修改文件权限(未实现) - 其他系统调用接口(未实现) -  关于接口的具体含义,可以参考 [DragonOS系统调用接口](../../syscall_api/index.rst)。 +  关于接口的具体含义,可以参考Linux的相关文档。 ## 虚拟文件系统(VFS) diff --git a/docs/syscall_api/index.rst b/docs/kernel/syscall/index.rst similarity index 67% rename from docs/syscall_api/index.rst rename to docs/kernel/syscall/index.rst index 1145e005..41d7beee 100644 --- a/docs/syscall_api/index.rst +++ b/docs/kernel/syscall/index.rst @@ -1,10 +1,10 @@ -.. _syscall_api: +.. _syscall: -系统调用API +系统调用 ==================================== .. toctree:: :maxdepth: 1 :caption: 目录 - intro + syscall_table diff --git a/docs/kernel/syscall/syscall_table.rst b/docs/kernel/syscall/syscall_table.rst new file mode 100644 index 00000000..29399917 --- /dev/null +++ b/docs/kernel/syscall/syscall_table.rst @@ -0,0 +1,120 @@ +系统调用表实现方案 +==================== + +.. note:: + Author: longjin + + Date: 2025/05/13 + +概述 +---- + +.. mermaid:: + :align: center + :caption: 系统调用表架构 + + classDiagram + class Syscall { + <> + +num_args() usize + +handle(args, from_user) Result + +entry_format(args) Vec + } + + class SyscallHandle { + +nr: usize + +inner_handle: &dyn Syscall + } + + class SyscallTable { + -entries: [Option<&SyscallHandle>; 512] + +get(nr) Option<&dyn Syscall> + } + + Syscall <|.. SysXXXXXXHandle + SyscallHandle "1" *-- "1" Syscall + SyscallTable "1" *-- "512" SyscallHandle + +相比于将原本集中在一个大match中的系统调用分发,本方案采用基于trait和系统调用表的实现。主要优势包括: + +- 降低栈内存使用:避免单个大函数占用过多栈空间 +- 支持参数打印:通过统一的参数格式化接口 +- 更好的扩展性:新增系统调用无需修改分发逻辑 + +核心设计 +-------- + +Syscall Trait +~~~~~~~~~~~~~ + +所有系统调用处理函数都需要实现 `Syscall` trait: + +.. code-block:: rust + + pub trait Syscall: Send + Sync + 'static { + fn num_args(&self) -> usize; + fn handle(&self, args: &[usize], from_user: bool) -> Result; + fn entry_format(&self, args: &[usize]) -> Vec; + } + +- `num_args()`: 返回该系统调用需要的参数数量 +- `handle()`: 实际执行系统调用处理 +- `entry_format()`: 格式化参数用于调试打印 + +SyscallHandle +~~~~~~~~~~~~~ + +`SyscallHandle` 结构体将系统调用号与处理函数关联: + +.. code-block:: rust + + pub struct SyscallHandle { + pub nr: usize, // 系统调用号 + pub inner_handle: &'static dyn Syscall, // 处理函数 + pub name: &'static str, + } + +SyscallTable +~~~~~~~~~~~~ + +`SyscallTable` 管理所有系统调用: + +- 固定大小512项 +- 编译时初始化 +- 通过系统调用号快速查找处理函数 + +使用方式 +-------- + +实现系统调用 +~~~~~~~~~~~~ + +1. 定义实现``Syscall`` trait的结构体 +2. 实现``handle()``和``entry_format()``方法 +3. 使用``declare_syscall!``宏注册 + +参考实现:`sys_write.rs `_ + +.. _sys_write: + https://github.com/DragonOS-Community/DragonOS/blob/master/kernel/src/filesystem/vfs/syscall/sys_write.rs + +注册系统调用 +~~~~~~~~~~~~ + +使用``declare_syscall!``宏注册系统调用: + +.. code-block:: rust + + syscall_table_macros::declare_syscall!(SYS_WRITE, SysWriteHandle); + +参数说明: + +1. 系统调用名称(用于生成符号) +2. 实现``Syscall`` trait的结构体 + +初始化流程 +---------- + +1. 内核启动时调用``syscall_table_init()`` +2. 从链接器符号``_syscall_table``加载所有注册的系统调用 +3. 填充系统调用表 diff --git a/docs/kernel/trace/eBPF.md b/docs/kernel/trace/eBPF.md index b9a1bf1a..9efdc465 100644 --- a/docs/kernel/trace/eBPF.md +++ b/docs/kernel/trace/eBPF.md @@ -18,7 +18,7 @@ eBPF 从根本上改变了这个方式。通过允许在操作系统中运行沙 ## eBPF的运行流程 -![image-20240909165945192](./ebpf_flow.png) +![image-20240909165945192](/kernel/trace/ebpf_flow.png) 如图所示,eBPF程序的运行过程分为三个主要步骤: diff --git a/docs/kernel/trace/kprobe.md b/docs/kernel/trace/kprobe.md index 53bd3aec..dc886771 100644 --- a/docs/kernel/trace/kprobe.md +++ b/docs/kernel/trace/kprobe.md @@ -14,7 +14,7 @@ kprobes技术依赖硬件架构相关的支持,主要包括CPU的异常处理 ## kprobe工作流程 -xxx +xxx diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.0.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.0.md new file mode 100644 index 00000000..27328307 --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.0.md @@ -0,0 +1,304 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.0.md + +- Translation time: 2025-05-19 01:48:03 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.0 + +:::{note} +Author of this document: Longjin + +November 6, 2022 +::: + +## Preface + +  DragonOS has been under development since January 15, 2022, and has now gone through nearly 300 days. In these many days and nights, it's hard to count how much time has been spent on DragonOS development. I have basically given all my free time to DragonOS, and the estimated total working hours have already exceeded 1000 hours. It feels very rewarding to be able to release the first version. + +  Since July 2022, a number of friends and mentors from six universities or companies have joined the development of DragonOS. I was very happy about this. I think, with everyone's joint efforts, we can create an operating system that is truly practical! We have held 14 discussion meetings. I believe, with everyone's joint efforts, in the future, we will be able to create an independent, open, server-oriented open-source operating system that can be used in production environments. + +  Although DragonOS is currently just a toy-level operating system, it's "only slightly more difficult than a undergraduate graduation project." However, please don't underestimate it. Its internal architecture design targets Linux 5.18 and later distributions. Although it has not yet reached the level of Linux, we are working hard to catch up. Thanks to the relevant resources of Linux, DragonOS has learned a lot of design ideas from Linux during its architecture design. The related components have considered scalability and portability as much as possible. + +  A journey of a thousand miles begins with a single step. The release of DragonOS V0.1.0 is a new beginning. **I hope, in the next ten years, we can work together with many partners, and by 2032, build DragonOS into a practical, widely used open-source operating system in the server field!** + +  **A hundred boats race, the ones who row first win; in the middle stream, the brave win.** I believe, with the continuous efforts of the community developers in the coming time, our goal will become a reality! + +## Special Thanks + +  At the time of the release of DragonOS V0.1.0, I would like to express my sincere gratitude to my teachers, predecessors, and school! + +- **Teacher Yao Zhicheng from Dali Town Central Primary School, Nanhai District, Foshan City**: You are the guide who introduced me to computers and taught me programming. Ten years ago, when we talked, you said, "Our country currently does not have an independent and mature operating system." This sentence planted the seed of my dream. You cultivated my love for computers, so I chose the major of software engineering. Thank you for your guidance back then, I will never forget your kindness! + +- **Shimen Experimental School, Nanhai District, Foshan City**: During the three years I studied at Shimen Experimental School, I am very grateful for the school's "Strength-based Education" philosophy. Under the guidance of the teachers, I was able to fully develop my personality and talents, and achieved good results. During the three years at Shimen Experimental School, I learned C++, Java, and simple algorithms, and I developed several Android apps, accumulating nearly 6,000 lines of code. + +- **Shimen Middle School, Nanhai District, Foshan City**: "The road is long and the task is heavy, never forget to strive" is the school motto of Shimen Middle School. I think this motto should also become the motto of each new generation of youth. During the three years at Shimen Middle School, the education of national sentiment had a great impact on me. I think, as new generation of youth, we should shoulder the responsibility of the times, strive hard, and work for the development of the country, the strength of the nation, and the future of humanity! + +- **South China University of Technology**: "Broad learning, careful thinking, clear discernment, and firm action" – at SCUT, I received further learning and development. I broadened my horizons, learned to communicate with many people. Moreover, in the School of Software, I met a group of conscientious and responsible teachers. I am very grateful for the support of the school, which supported us in establishing the project group. I believe, with the support of the school, DragonOS can achieve better development and go further! + +- **Professor Wang Guohua from the School of Software, South China University of Technology**: Professor Wang is my teacher for the course "Operating System". Under her guidance, I gained a deeper understanding of the principles of operating systems, and participated in the "Pan-Delta+ University Students' Computer Works Competition". In the Guangdong provincial selection in June 2022, DragonOS won the first prize and the Best Innovation Award. + +- **Professor Tang Feng from the School of Software, South China University of Technology**: Professor Tang is our project group's on-campus mentor. Under her careful guidance, we will continue to move forward, keep our direction, and continuously build an open-source community. I sincerely thank Professor Tang for her guidance! + +- **[Yaotian Feng](https://github.com/Codetector1374)**: I met this very capable person on Bilibili. He answered many of my questions. Many times, after I had debugged for several days without any idea, a few words from him would wake me up and help me find the path to solve the problem. He also shared with me the places where I might fall into traps, allowing me to have a psychological expectation when about to fall into a trap, so I wouldn't feel so uncomfortable, ha ha. + +## Contributors List + +The release of DragonOS V0.1.0 could not have been achieved without the joint efforts of the following friends: + +- Longjin +- zzy666-hw +- Guan Jinquan +- Zhou Yuzhe +- kkkkkong +- houmkh +- wang904 <1234366@qq.com> +- Liric Mechan +- Mustang +- Eugene +- kun <1582068144@qq.com> +- zhujikuan <1335289286@qq.com> +- Alloc Alice <1548742234@qq.com> + +## Sponsors List + +Thank you to the following students for their donations. We will keep working hard! + +- TerryLeeSCUT +- Wu +- slientbard + +## Kernel + +### Some Standards and Specifications Followed + +- Bootloader: Multiboot2 +- System Interface: POSIX 2008 + +### Hardware Architecture + +- Currently supports running on x86-64 architecture processors + +### Bootloader + +- Uses Grub 2.06 as the bootloader + +### Memory Management + +- Implemented a bitmap-based page allocator +- Implemented a slab allocator for allocating small, aligned memory blocks +- Abstracted VMA (Virtual Memory Area) +- Implemented VMA reverse mapping mechanism +- Implemented MMIO address space auto-mapping mechanism + +### Multi-core + +- Supports multi-core boot. That is, after DragonOS starts, it will start the AP processor. However, to simplify the implementation of other kernel modules, currently, there are no tasks running on the AP processor. +- Roughly implemented the IPI (Inter-Processor Interrupt) framework + +### Process Management + +- Supports process creation and recycling +- Kernel threads +- Kthread mechanism +- User-space and kernel-space process/thread fork/vfork (note that user-space fork and kernel-space fork have some differences; kernel-space fork is more complex) +- exec allows a process to execute a new executable file +- Process timer sleep (sleep) (supports high-precision sleep with spin/rdtsc, supports sleep via context switching) + +### Synchronization Primitives + +- spinlock spin lock +- mutex mutex +- atomic atomic variable +- wait_queue wait queue +- semaphore semaphore + +### Scheduling Related + +- CFS scheduler +- Single-core scheduling (multi-core load balancing is temporarily not supported) +- completion "completion" mechanism, allowing a process to wait for a task to complete + +### IPC (Inter-Process Communication) + +- Anonymous pipe + +### File System + +- Basic functionality of the VFS virtual file system +- FAT32 file system (does not support deleting folders) +- devfs device file system. Currently, only the keyboard file is registered. +- rootfs root file system, provides support for other pseudo-file systems before the real disk file system is mounted +- Mount point abstraction. Currently, file system mounting is implemented, and all mount points are managed in a stack-like manner (optimization is needed in the future) + +### Exception and Interrupt Handling + +- Handling of processor exceptions +- Support for APIC +- Softirq soft interrupt mechanism +- Ability to trace the kernel stack + +### Kernel Data Structures + +- Ordinary binary tree +- kfifo first-in-first-out buffer +- Circular linked list +- IDR mapping data structure +- IDA ID allocation data component + +### Screen Display + +- VESA VBE display chip driver +- Implemented a screen manager, supporting multiple display frameworks to be registered with the screen manager +- Implemented a TextUI text interface framework, capable of rendering text to the screen. Also reserves support for scrollable pages and multiple display windows +- printk + +### Kernel Utility Library + +- String operation library +- ELF executable file support component +- Basic math library +- CRC function library + +### Software Portability + +- Ported the LZ4 compression library (V1.9.3), laying the foundation for future page compression mechanisms + +### Kernel Testing + +- ktest unit test framework +- Supports outputting screen content to a file via serial port (COM1) + +### Driver Support + +- IDE hard disk +- AHCI hard disk (SATA Native) +- ACPI Advanced Power Configuration module +- PCI bus driver +- XHCI host controller driver (USB 3.0) +- PS/2 keyboard +- PS/2 mouse +- HPET high-precision timer +- RTC clock +- Local APIC timer +- UART serial port (supports RS-232) +- VBE display +- Virtual tty device + +### System Calls + +DragonOS currently has a total of 22 valid system calls. + +- SYS_PUT_STRING Print characters to the screen +- SYS_OPEN Open a file +- SYS_CLOSE Close a file +- SYS_READ Read from a file +- SYS_WRITE Write to a file +- SYS_LSEEK Adjust the file pointer +- SYS_FORK Fork system call +- SYS_VFORK Vfork system call +- SYS_BRK Adjust the heap size to a specified value +- SYS_SBRK Adjust the heap size by a relative value +- SYS_REBOOT Reboot (this system call will be removed after sysfs is improved; please do not rely on this system call excessively) +- SYS_CHDIR Change the working directory of the process +- SYS_GET_DENTS Get metadata of directory entries +- SYS_EXECVE Let the current process execute a new program file +- SYS_WAIT4 Wait for a process to exit +- SYS_EXIT Exit the current process +- SYS_MKDIR Create a directory +- SYS_NANOSLEEP Nanosecond-level sleep (up to 1 second), capable of high-precision sleep when less than 500ns +- SYS_CLOCK Get the current CPU time +- SYS_PIPE Create a pipe +- SYS_MSTAT Get the current memory status information of the system +- SYS_UNLINK_AT Delete a directory or delete a file link + +### Rust Support + +- Implemented a simple "hello world" in Rust. Plan to gradually shift to using Rust for development in the next version. + +## User Environment + +### LibC + +  LibC is the bridge between applications and the operating system. DragonOS's LibC implements some simple functions. + +- malloc heap memory allocator +- Basic math library +- A few simple functions related to files +- pipe +- fork/vfork +- clock +- sleep +- printf + +### Shell Command Line Programs + +- Based on simple string matching parsing (not done through the compilation course's method, so it's simple and crude) +- Supported commands: ls, cd, mkdir, exec, about, rmdir, rm, cat, touch, reboot + +### User-space Driver Programs + +- User-space keyboard driver + +## Source Code and Release Image Download + +  You can obtain the source code in the following ways: + +### Get via Git + +- You can visit [https://github.com/fslongjin/DragonOS/releases](https://github.com/fslongjin/DragonOS/releases) to download the release code and the compiled, runnable disk image. +- We also have a mirror repository on gitee for download: [https://gitee.com/DragonOS/DragonOS](https://gitee.com/DragonOS/DragonOS) + +### Get via DragonOS Software Mirror Site + +  To solve the problem of slow and unstable access to GitHub in China, and to make it convenient for developers to download the code of each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can obtain the DragonOS code archive and the compiled, runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org](https://mirrors.DragonOS.org) +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) + +## Open Source Code Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source protocol. Everyone who can obtain the DragonOS source code and related software products (including but not limited to binary copies and documents) will enjoy the rights granted by us through the GPLv2 protocol, and you must also comply with the obligations stipulated in the protocol. + +This is a rather strict protocol that protects the healthy development of open source software and prevents it from being encroached upon. + +For most people with good intentions, you will not violate our open source protocol. + +We encourage the free spread and promotion of DragonOS, but please ensure that all actions do not infringe on the legitimate rights and interests of others, nor do they violate the GPLv2 protocol. + +Please pay special attention to the fact that those who violate the open source protocol, especially **commercial closed-source use and any plagiarism or academic misconduct**, will be held seriously accountable. (This is the easiest scenario to violate our open source protocol.) + +Also, please note that according to the requirements of the GPLv2 protocol, any software modified or developed based on DragonOS must also be open-sourced under the GPLv2 protocol and must indicate that it is based on DragonOS. It must also ensure that users of these modified versions can easily obtain the original version of DragonOS. + +You must make sure that the DragonOS developers can obtain the source code of your modified version through the same way from public channels, otherwise you will violate the GPLv2 protocol. + +For detailed information about the protocol, please read the **LICENSE** file in the root directory of the project. Please note that according to the requirements of the GPLv2 protocol, **only the English original version has legal effect**. Any translated version is for reference only. +::: + +### Usage of Open Source Software + +  During the development of DragonOS, some open source projects' designs were referenced, or parts of their code were introduced, or they were inspired by them. Below are the list of these open source projects. We sincerely thank the contributors of these open source projects! + +Format: - - + +- Linux - https://git.kernel.org/ - GPLv2 +- skiftOS - https://github.com/skiftOS/skift - MIT +- FYSOS - https://github.com/fysnet/FYSOS - [FYSOS' License](https://github.com/fysnet/FYSOS/blob/9a8968e3d6600de34539c028c843f4c06d134039/license.txt) +- LemonOS - https://github.com/LemonOSProject/LemonOS.git - BSD 2-Clause License +- LZ4 - https://github.com/lz4/lz4 - BSD 2-Clause license +- SerenityOS - https://github.com/SerenityOS/serenity.git - BSD 2-Clause license +- MINE - 《A Design and Implementation of a 64-bit Operating System》Tian Yu; People's Posts and Telecommunications Press +- chcore - 《Modern Operating Systems: Design and Implementation》Chen Haibo, Xia Yubin; Machinery Industry Press +- SimpleKernel - https://github.com/Simple-XX/SimpleKernel - MIT diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.1.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.1.md new file mode 100644 index 00000000..08e09810 --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.1.md @@ -0,0 +1,358 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.1.md + +- Translation time: 2025-05-19 01:41:56 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.1 + +:::{note} +Author: Longjin + +November 27, 2022 +::: + +## Contributors List + +The DragonOS V0.1.1 version was contributed by the following team members: + +- Longjin +- Zhou Yuzhe + +## Sponsors List + +Thank you to the following individuals for their support. We will continue to strive for excellence! + +- David Wen +- TerryLeeSCUT +- Wu +- slientbard + +Among them, we are especially grateful to **David Wen** for his sponsorship of RMB 1000 to the DragonOS project! We will carefully record each donation and ensure that it is used appropriately. + +## Update Content - Kernel + +- Added Rust FFI (#_translated_label__77_en) +- Ported kmalloc and printk to Rust +- Rust macros for kdebug, kinfo, kwarn, kBUG, kerror +- Bugfix: Fixed the issue where the process PCB was not removed from the list when it was reclaimed +- Directory structure optimization: Moved asm.h and cmpxchg.h +- Signal sending +- procfs: View process status +- Resolved the issue of disk image permission errors during the first compilation +- Moved fork-related code to fork.c + +## Update Content - User Environment + +- Shell: Added the kill command, which can send signals to a target process. However, since the signal mechanism is still not fully implemented, the target process cannot currently respond to this signal. + +## Source Code and Release Image Download + +  You can obtain the source code through the following methods: + +### Get via Git + +- You can download the release code and the compiled, runnable disk image from [https://github.com/fslongjin/DragonOS/releases](https://github.com/fslongjin/DragonOS/releases). +- We also have a mirror repository on Gitee for download: [https://gitee.com/DragonOS/DragonOS](https://gitee.com/DragonOS/DragonOS) + +### Get via DragonOS Software Mirror Site + +  To address the slow and unstable access to GitHub in China, and to make it easier for developers to download the code for each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can obtain the compressed package of DragonOS code and the compiled, runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org](https://mirrors.DragonOS.org) +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the DragonOS source code and corresponding software products (including but not limited to binary copies and documentation) will enjoy the rights granted by us through the GPLv2 license, and you must also comply with the obligations stipulated in the agreement. + +This is a rather strict license that protects the healthy development of open source software and prevents it from being encroached upon. + +For most well-intentioned people, you will not violate our open source license. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe on the legitimate rights and interests of others or violate the GPLv2 license. + +Please pay special attention to the fact that violations of the open source license, especially **commercial closed-source use and any plagiarism or academic misconduct**, will be subject to serious accountability. (This is the most common scenario where the open source license is violated.) + +Also, please note that according to the requirements of the GPLv2 license, any software modified or developed based on DragonOS must also be open-sourced under the GPLv2 license and must clearly indicate that it is based on DragonOS. It is also necessary to ensure that users of these modified versions can easily obtain the original version of DragonOS. + +You must make it possible for the developers of DragonOS to obtain the source code of your modified version through public channels, otherwise you will violate the GPLv2 license. + +For detailed information about the agreement, please read the **LICENSE** file in the project root directory. Please note that according to the requirements of the GPLv2 license, **only the English original version is legally binding**. Any translated version is for reference only. +::: + +### Open Source Software Usage + +  During the development of DragonOS, we have referenced the design of some open source projects, or introduced parts of their code, or been inspired by them. Below is a list of these open source projects. We sincerely thank the contributors of these open source projects! + +Format: - - + +- Linux - https://git.kernel.org/ - GPLv2 +- skiftOS - https://github.com/skiftOS/skift - MIT +- FYSOS - https://github.com/fysnet/FYSOS - [FYSOS' License](https://github.com/fysnet/FYSOS/blob/9a8968e3d6600de34539c028c843f4c06d134039/license.txt) +- LemonOS - https://github.com/LemonOSProject/LemonOS.git - BSD 2-Clause License +- LZ4 - https://github.com/lz4/lz4 - BSD 2-Clause license +- SerenityOS - https://github.com/SerenityOS/serenity.git - BSD 2-Clause license +- MINE - 《A Design and Implementation of a 64-bit Operating System》 by Tian Yu; People's Posts and Telecommunications Press +- chcore - 《Modern Operating Systems: Design and Implementation》 by Chen Haibo and Xia Yubin; Machinery Industry Press +- SimpleKernel - https://github.com/Simple-XX/SimpleKernel - MIT + +## All Commit Records of the Current Version + +```text +commit d65ade9c5909076747bd00966a398fe27fbd290d +Author: DaJiYuQia <88259094+DaJiYuQia@users.noreply.github.com> +Date: Sun Nov 27 14:21:31 2022 +0800 + + Patch procf (#95) + + * debug color problem + + Co-authored-by: longjin + +commit 6cb769c423b09e88fea1763210200a716477be0a +Author: login +Date: Sun Nov 27 14:17:36 2022 +0800 + + 将include目录下的rust代码转移到他们应当属于的模块中 (#96) + + * 将include目录下的rust代码转移到他们应当属于的模块下。 + +commit 27a97abd2474b03ad09b562e5ed11e1fdae8eb32 +Author: DaJiYuQia <88259094+DaJiYuQia@users.noreply.github.com> +Date: Sat Nov 26 17:34:00 2022 +0800 + + Patch procf (#90) + + * 1234 + + * 123 + + * 合并master + + * procfs + + * 1 + + * procfs展示进程基本信息 + + * modified code + + * 恢复权限 + + * 恢复权限 + + #恢复权限 + + * modify permission + + * 删除run.sh + + * 解决第一次编译时磁盘镜像权限错误的问题 + + * 恢复.vscode/c_cpp_properties.json + + * 删除process.c中错误的do_fork + + * remake procfs + + * 修改一些变量名 + + * 修改类型 + + * modified + + * data_puts缓冲区溢出后return + + Co-authored-by: longjin + +commit ad23fcddf893d7f92d2bf3efdb66e969416d2852 +Author: login +Date: Wed Nov 23 21:34:35 2022 +0800 + + bugfix: 修复进程退出时未释放signal和sighand && 增加赞赏者名单:David Wen (#93) + + * bugfix: 修复进程退出时未释放signal和sighand的bug + + * 增加赞赏者名单:David Wen + +commit 0274cd6eeec01885232e7418a501857cb76da69e +Author: login +Date: Wed Nov 23 20:43:18 2022 +0800 + + 修正drop signal结构体的box对象的的问题 (#92) + + * fix: exit signal and exit sighand + +commit c8025a88798dc57ecc5d7f20ad69de695445638f +Author: login +Date: Wed Nov 23 20:18:22 2022 +0800 + + new:在fork时拷贝signal和sighand (#91) + + * refcount初始化 + + * new: 实现copy_sighand + del: 删除sighand_struct的wqh, 待将来有需要时,替换成rust版本的 + + * new: 拷贝signal + bugfix: 解决拷贝sighand时的uaf问题 + +commit 66f67c6a95b8aad85cfd2146a86e5e3e6a3568e7 +Author: login +Date: Wed Nov 23 11:38:20 2022 +0800 + + signal的发送(暂时父子进程之间共享信号及相应的结构体) (#89) + + * 解决由于spinlock.h中包含preempt_enable()带来的循环include问题 + + * new: 初步实现signal的数据结构 + + * new:signal相关数据结构 + + * fix: 解决bindings.rs报一堆警告的问题 + + * new: rust下的kdebug kinfo kwarn kBUG kerror宏 + + * 移动asm.h和cmpxchg.h + + * new: signal的发送(暂时只支持父子进程共享信号及处理函数) + +commit 3d729e2069e01ee07525ff83167566dac5322a40 +Author: login +Date: Fri Nov 18 17:59:33 2022 +0800 + + bugfix: 修复进程pcb被回收时,未将其从链表中删除的问题 (#87) + + * bugfix: 修复进程pcb被回收时,未将其从链表中删除的问题 + new: pcb相关api文档 + + * 将文档加入目录 + +commit 0bfe94f46be9bdde1ade81a20e803aa2aafd2964 +Author: login +Date: Fri Nov 18 16:32:15 2022 +0800 + + new: rust下的kdebug kinfo kwarn kBUG kerror宏 (#86) + + * new: rust下的kdebug kinfo kwarn kBUG kerror宏 + +commit c6174797dcf3427f38bfa0f4bd3e039c319f7c5b +Author: login +Date: Thu Nov 17 20:29:29 2022 +0800 + + fix: 解决bindings.rs报了很多警告的问题 (#85) + + * fix: 解决bindings.rs报一堆警告的问题 + +commit cffd7144fbed84f9775e89d7b99602c6ccc5a510 +Author: login +Date: Wed Nov 16 15:18:03 2022 +0800 + + signal相关数据结构&代码结构优化 (#84) + + * 解决由于spinlock.h中包含preempt_enable()带来的循环include问题 + + * new: 初步实现signal的数据结构 + +commit fb6c29d01d4cf92368efec08c01e419c2a941f7d +Author: login +Date: Sun Nov 13 16:43:58 2022 +0800 + + port kmalloc and printk to rust (#83) + + * 暂时移除cbindgen + + * 将lib文件夹更名为libs文件夹(解决rust的冲突) + + * 实现了全局的allocator + + * 实现了printk宏 + + * new: 完善了printk的颜色 + +commit 82d2e446a401e7eee57a847f48a6d162931170c3 +Author: login +Date: Sat Nov 12 15:25:54 2022 +0800 + + new: 暂时移除cbindgen (#82) + +commit 2aaf7808efe44ecfaadd51ae4f8892e667108578 +Author: login +Date: Fri Nov 11 22:21:44 2022 +0800 + + 在内核中引入cbindgen,生成rust-C的FFI (#81) + + + * 解决codeql失败问题 + + * new: 为内核引入cbindgen + +commit 2813126e3190c9b3c1a836a647b259a7adbe0cf3 +Author: login +Date: Fri Nov 11 15:35:37 2022 +0800 + + 新增rust ffi (#77) + + * 引入cargo + + * 取消对Cargo.lock的跟踪 + + * 解决vscode报错问题 + + * new: rust的代码能够调用c语言的printk_color + + * 1、将原本run.sh的工作拆解,变为几个不同的make命令 + 2、在docker镜像中编译rust + + * 更改workflow + + * update workflow + + * new: 解决workflow无法通过编译的问题 + +commit 5e023cf7911333eb05bfe65704dce4b01fa4d0a7 +Author: login +Date: Fri Nov 11 15:21:45 2022 +0800 + + Update makefile.yml + +commit e44795008f7e34d2068cf28dcedbcb91f5ccd66b +Author: login +Date: Fri Nov 11 15:18:13 2022 +0800 + + Update makefile.yml (#80) + +commit ec5fb84b61c313824cc2199ab64e3af4b7e5f895 +Author: login +Date: Fri Nov 11 15:08:09 2022 +0800 + + Update makefile.yml + +commit 6d9dff5f1ff347ea780a0249e54eef356cdcaaea +Author: login +Date: Fri Nov 11 15:07:48 2022 +0800 + + Revert "Update makefile.yml (#78)" (#79) + + This reverts commit badc7d238f2341e844a90be3e357e5dd77a447fc. + +commit badc7d238f2341e844a90be3e357e5dd77a447fc +Author: login +Date: Fri Nov 11 15:05:52 2022 +0800 + + Update makefile.yml (#78) + +``` diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.10.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.10.md new file mode 100644 index 00000000..f98ac4ea --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.10.md @@ -0,0 +1,1075 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.10.md + +- Translation time: 2025-05-19 01:42:56 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.10 + +:::{note} +Author: Longjin + +DragonOS official forum: [bbs.dragonos.org.cn](https://bbs.dragonos.org.cn) + +May 13, 2024 +::: + +## Introduction + +  This version update introduces 42 feature-type PRs, 24 bug fixes, 5 document updates, and some software porting and CI-related content. + +  Key highlights of the current version: + +- Refactored the scheduling subsystem +- Ability to run the "hello world" application on riscv64 +- The memory management subsystem introduces features such as anonymous page reverse mapping, copy-on-write, and delayed allocation +- The file system introduces a large number of new system interfaces +- Implemented pty and can run a simple ssh server + +## Sponsors List + +- **[YaCloud](https://yacloud.net)** Yaan Big Data Industrial Park provides cloud server support for DragonOS. + +## Update Content - Kernel + +- feat(fs): Implemented sys_rename (#_translated_label__578_en) +- feat(fs): Implemented get_pathname (#_translated_label__615_en) +- feat(kernel): Implemented uname system call (#_translated_label__614_en) +- feat(fs): Added mount system call (#_translated_label__561_en) +- feat(smp): Rewrote SMP module (#_translated_label__633_en) +- feat(fs): Added Statx system call (#_translated_label__632_en) +- feat(riscv64): Added flush tlb's IPI (#_translated_label__636_en) +- feat(fs): Implemented SYS_LINK and SYS_LINKAT (#_translated_label__611_en) +- fix(fs): mkdir outputs error message; +- fix(clippy): Fixed kernel clippy check errors (#_translated_label__637_en) +- feat(net): Implemented socketpair (#_translated_label__576_en) +- feat(process/riscv): Process management initialization (#_translated_label__654_en) +- fix(time): Fixed clock_gettime return type error and fixed small time interval duration returning 0 issue (#_translated_label__664_en) +- fix(driver/base): Changed Device trait's set_class to set a Weak pointer to avoid circular reference issues. (#_translated_label__666_en) +- feat(textui): Supports drawing 24-bit and 16-bit deep display buffers (#_translated_label__640_en) +- fix(driver/tty): Fixed bug where tty device appears in /sys directory (#_translated_label__668_en) +- feat(fs): Added struct POSIXSTATFS and SuperBlock for handling statfs system call (#_translated_label__667_en) +- feat(driver/rtc): Implemented rtc abstraction and integrated x86's cmos rtc into device driver model (#_translated_label__674_en) +- fix(net): Fixed udp bind issue with port0 handling (#_translated_label__676_en) +- fix(fs/ramfs): Fixed bug where move_to did not update parent field in ramfs (#_translated_label__673_en) +- feat(mm): Implemented page reverse mapping (#_translated_label__670_en) +- fix(misc): Fixed get_ramdom length error issue () (#_translated_label__677_en) +- feat(process/riscv): riscv64: switch process (#_translated_label__678_en) +- fix(misc): Made nproc correctly obtain the number of CPU cores (#_translated_label__689_en) +- fix(time): Fixed jiffy clock being too fast, enabled gettimeofday test, modified mount test (#_translated_label__680_en) +- feat(driver/pty): Implemented pty with test program (#_translated_label__685_en) +- feat(process/riscv): Implemented copy-thread (#_translated_label__696_en) +- feat(sched): Rewrote scheduling module (#_translated_label__679_en) +- fix(riscv): Changed kernel compilation target to riscv64gc, obtained time csr frequency, and fixed assembly issues with floating point save and restore (#_translated_label__699_en) +- feat(lock): Implemented robust futex (#_translated_label__682_en) +- feat(fs): BlockCache-read cache support (#_translated_label__521_en) +- feat(mm): Implemented SystemV shared memory (#_translated_label__690_en) +- chore(tools): Add bootstrap support for Centos/RHEL8/fedora (#_translated_label__713_en) +- feat(driver/pty): Improved pty, currently pty can support ssh (#_translated_label__708_en) +- fix(smp): Fixed issue where smp startup damaged the idle process's kernel stack of the 0th core (#_translated_label__711_en) +- feat(driver/riscv): Initialized riscv-sbi-timer (#_translated_label__716_en) +- doc: Update DragonOS description and introduction (#_translated_label__717_en) +- feat(riscv): Let riscv64 run hello world user program and complete all initcall (#_translated_label__721_en) +- feat(net): Implemented tcp backlog feature (#_translated_label__714_en) +- feat(mm): Added slab memory allocator (#_translated_label__683_en) +- feat(fs): Introduced Umount system call (#_translated_label__719_en) +- doc: Update build instructions for riscv64 architecture (#_translated_label__725_en) +- fix(fs): Socket uniformly changed to `GlobalSocketHandle`, and fixed fcntl SETFD error (#_translated_label__730_en) +- feat: Alarm system call implementation (#_translated_label__710_en) +- feat(tty): Add dummy console (#_translated_label__735_en) +- fix(driver/pci): pci: Uniformly use ecam root (#_translated_label__744_en) +- feat(driver/pci): pci: Added pci root manager to manage pci root, enabling riscv to scan pci devices normally. (#_translated_label__745_en) +- build: Upgraded smoltcp to version 0.11.0 (#_translated_label__740_en) +- fix(unified-init): Fixed unified-init causing cargo check failure issue (#_translated_label__747_en) +- chore: Update virtio-drivers to commit 61ece509c4 and modify max_queue_size implementation (#_translated_label__748_en) +- feat(net): Implemented raw socket's poll (#_translated_label__739_en) +- feat(mm): Implemented page fault handling, supports page delayed allocation and copy-on-write, and user stack auto-expansion (#_translated_label__715_en) +- feat(driver): Added virtio to sysfs (#_translated_label__752_en) +- fix(dog): Added CC environment variable to solve the problem of not finding musl-gcc during compilation (#_translated_label__753_en) +- doc(community): Added description of conventional commit standard (#_translated_label__754_en) +- feat(driver/virtio): riscv: Added virtio-blk driver, and can correctly mount FAT32 on riscv (#_translated_label__761_en) +- feat(fs): Add sys_dup3 (#_translated_label__755_en) +- feat(riscv): riscv can run hello world user program (#_translated_label__770_en) +- feat(sched): Add sched_yield (#_translated_label__766_en) +- refactor(process): Adjusted arch_switch_to_user function, extracted common logic between riscv and x86_64. (#_translated_label__773_en) +- feat(driver/acpi_pm): Implement ACPI PM Timer (#_translated_label__772_en) +- chore: Adapt to dadk 0.1.11 (#_translated_label__777_en) +- fix(libs/lib_ui): Fixed display errors when system initializes (#_translated_label__779_en) +- fix(riscv/process): Synchronized riscv's scheduling clock tick rate with HZ, and fixed the bug of forgetting to disable interrupts in kernel mode when switching to user mode (#_translated_label__780_en) +- fix: (riscv/timer): Fixed bug where riscv did not update wall clock and did not handle soft interrupts (#_translated_label__783_en) +- feat(mm): Add slab usage calculation (#_translated_label__768_en) +- feat(bitmap): Add bit and for AllocBitMap (#_translated_label__793_en) +- fix(mm): Fixed vma mapping flag error (#_translated_label__801_en) +- feat:(riscv/intr) Implemented riscv plic driver, capable of handling external interrupts (#_translated_label__799_en) +- doc(sched): Scheduling subsystem document and CFS document (#_translated_label__807_en) +- fix(net): Fix TCP Unresponsiveness and Inability to Close Connections (#_translated_label__791_en) +- fix: disable mm debug log to prevent system lockup due to thingbuf issue (#_translated_label__808_en) +- feat(driver/pci): add pci bus into sysfs (#_translated_label__792_en) +- doc: Add Gentoo Linux In build_system.md (#_translated_label__810_en) + +## Update Content - User Environment + +### New Features / New Application Porting + +- Added core utils to the system (#_translated_label__624_en) +- Ported the --tcp functionality of the DNS query tool dog (#_translated_label__652_en) + +## Update Content - CI + +- Introduced triagebot to classify issues and PRs +- Added automated workflow for clippy detection (#_translated_label__649_en) +- ci: import issue checker (#_translated_label__750_en) +- ci: update the match regex of issue checker (#_translated_label__784_en) +- ci: Added one-click installation script for Gentoo system (#_translated_label__809_en) + +## Source Code and Release Image Download + +  You can obtain the source code through the following methods: + +### Through Git + +- You can access the DragonOS repository to get the source code: [https://github.com/DragonOS-Community/DragonOS](https://github.com/DragonOS-Community/DragonOS) +- You can download the release code from [https://github.com/DragonOS-Community/DragonOS/releases](https://github.com/DragonOS-Community/DragonOS/releases). + +### Through DragonOS Software Mirror Site + +  To address the slow and unstable access to GitHub in China, and to make it convenient for developers to download the code of each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can obtain the DragonOS source code archive and the compiled and runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) +- [https://git.mirrors.DragonOS.org.cn](https://git.mirrors.DragonOS.org.cn) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the DragonOS source code and corresponding software products (including but not limited to binary copies and documentation) can enjoy the rights granted by us through the GPLv2 license, while you also need to comply with the obligations stipulated in the agreement. + +This is a rather strict agreement that protects the healthy development of open source software and prevents it from being encroached upon. + +For most well-intentioned people, you will not violate our open source license. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe upon the legitimate rights and interests of others or violate the GPLv2 license. + +Please pay special attention to the fact that violations of the open source license, especially **commercial closed-source usage and any plagiarism or academic misconduct**, will be subject to serious accountability. (This is the most common scenario where the open source license is violated.) + +Also, please note that according to the requirements of the GPLv2 license, any software modified or developed based on DragonOS must also be open-sourced under the GPLv2 license and must clearly indicate that it is based on DragonOS. It is also necessary to ensure that users of these modified versions can easily obtain the original version of DragonOS. + +You must make sure that DragonOS developers can obtain the source code of your modified version through public channels in the same way, otherwise you will violate the GPLv2 license. + +For detailed information about the agreement, please read the **LICENSE** file in the root directory of the project. Please note that according to the requirements of the GPLv2 license, **only the English original version has legal effect**. Any translated version is for reference only. +::: + +### Open Source Software Usage + +  During the development of DragonOS, we have referenced some designs from the Linux community, or introduced parts of their ideas, or been inspired by them. We would like to express our sincere gratitude to the Linux community and its contributors here! + +## All Commit Records of the Current Version + +```text +commit 9a0802fd2ddda39e96342997abbfc30bf65f1f0e +Author: donjuanplatinum <113148619+donjuanplatinum@users.noreply.github.com> +Date: Mon May 13 15:36:23 2024 +0800 + + doc: Add Gentoo Linux In build_system.md (#810) + + * 增加安装文档中的Gentoo Linux提示 + +commit 1f4877a4c512eb5ad232436128a0c52287b39aaa +Author: 曾俊 <110876916+ZZJJWarth@users.noreply.github.com> +Date: Mon May 13 15:27:08 2024 +0800 + + feat(driver/pci): add pci bus into sysfs (#792) + + 把pci设备加入sysfs + +commit 1df85daf8f1b4426fe09d489d815997cdf989a87 +Author: donjuanplatinum <113148619+donjuanplatinum@users.noreply.github.com> +Date: Sun May 12 22:58:59 2024 +0800 + + 添加支持gentoo系统的一键安装脚本 (#809) + +commit 352ee04918f4585ad4f8a896ca6e18b1ef7d7934 +Author: LoGin +Date: Sat May 11 18:02:13 2024 +0800 + + fix: disable mm debug log to prevent system lockup due to thingbuf issue (#808) + +commit 37cef00bb404c9cc01509c12df57548029967dc2 +Author: Samuel Dai +Date: Sat May 11 17:17:43 2024 +0800 + + fix(net): Fix TCP Unresponsiveness and Inability to Close Connections (#791) + + * fix(net): Improve stability. 为RawSocket与UdpSocket实现close时调用close方法,符合smoltcp的行为。为SocketInode实现drop,保证程序任何情况下退出时都能正确close对应socket, 释放被占用的端口。 + + * fix(net): Correct socket close behavior. + +commit b941261d943fac38d3154495e19ec99c90ebea8d +Author: GnoCiYeH +Date: Tue May 7 22:01:01 2024 +0800 + + docs(sched):调度子系统文档即cfs文档 (#807) + + * 调度子系统文档以及cfs文档 + +commit 0102d69fdd231e472d7bb3d609a41ae56a3799ee +Author: LoGin +Date: Wed May 1 21:11:32 2024 +0800 + + feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断 (#799) + + * feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断 + + - 实现riscv plic驱动,能处理外部中断 + - 能收到virtio-blk的中断 + - 实现fasteoi interrupt handler + +commit 17dc558977663433bd0181aa73ad131a1a265c1f +Author: MemoryShore <105195940+MemoryShore@users.noreply.github.com> +Date: Wed May 1 21:09:51 2024 +0800 + + 修复vma映射标志错误 (#801) + +commit 7db6e06354328ea7c6164723f504e8ba58d0c4a4 +Author: LoGin +Date: Tue Apr 30 18:45:01 2024 +0800 + + feat(bitmap): Add bit and for AllocBitMap (#793) + +commit 7401bec5e3c42015399a46e29c370abe7c7388b5 +Author: laokengwt <143977175+laokengwt@users.noreply.github.com> +Date: Mon Apr 29 23:03:33 2024 +0800 + + feat(mm): add slab usage calculation (#768) + + * Add slab free space calculation and add it to freeram of sysinfo + +commit bde4a334c1ff2ae27989de4f6f8b45f5154b684d +Author: 曾俊 <110876916+ZZJJWarth@users.noreply.github.com> +Date: Mon Apr 29 18:55:17 2024 +0800 + + 修复了未初始化时ui显示模块内存越界的问题,优化了代码结构 (#789) + +commit 0722a06a09ed52cb980a6147123453f86d0ea267 +Author: LoGin +Date: Sun Apr 28 19:40:09 2024 +0800 + + fix: (riscv/timer): 修复riscv下没有更新墙上时钟以及没有处理软中断的bug (#783) + +commit ab53b2eb75fe79167aa100e655b3589ee306f793 +Author: Chiichen +Date: Sun Apr 28 19:37:58 2024 +0800 + + ci: update the match regex of issue checker (#784) + + The previous regex can not successfully match the pattern like `feat(driver/pci)`, which has a slash in the scope + +commit 942cf26b48c8b024a6fa7867bb0c8ae39bb1ae09 +Author: LoGin +Date: Sun Apr 28 16:49:40 2024 +0800 + + fix(riscv/process): 把riscv的调度时钟节拍率与HZ同步,并且修复切换到用户态的时候忘了在内核态关中断的bug (#780) + +commit 13b057cc0fda0cf9630c98d246937b85fa01a7c9 +Author: 曾俊 <110876916+ZZJJWarth@users.noreply.github.com> +Date: Sun Apr 28 16:49:19 2024 +0800 + + fix(libs/lib_ui): fix the display errors when system initialize (#779) + + * 修复了系统初启动时会花屏的bug + +commit 182b778a3ca8c633b605ae7dd90a5e9f1131cc6d +Author: LoGin +Date: Sun Apr 28 13:39:51 2024 +0800 + + chore: 适配dadk 0.1.11 (#777) + + * chore: 适配dadk 0.1.11 + +commit dd8e74ef0d7f91a141bd217736bef4fe7dc6df3d +Author: Mingtao Huang <114841534+1037827920@users.noreply.github.com> +Date: Sun Apr 28 13:25:12 2024 +0800 + + feat(driver/acpi_pm): Implement ACPI PM Timer (#772) + + * feat: Implement ACPI PM Timer + +commit f75cb0f8ed754d94c3b2924519b785db3321c1d9 +Author: LoGin +Date: Sat Apr 27 15:35:24 2024 +0800 + + refactor(process): 调整arch_switch_to_user函数,把riscv和x86_64的共用逻辑抽取出来。 (#773) + + * refactor(process): Extract common logic for riscv and x86_64 in arch_switch_to_user to run_init_process + + 调整arch_switch_to_user函数,把riscv和x86_64的共用逻辑抽取出来。写成run_init_process函数,并且能够尝试运行多个不同的init程序,直到某个运行成功 + +commit 173c4567cf4fb2276ef3f4614b69da7913fc8381 +Author: zwb0x00 <163394849+zwb0x00@users.noreply.github.com> +Date: Fri Apr 26 15:33:29 2024 +0800 + + feat(sched): add sched_yield (#766) + + * 实现sched_yield系统调用 + +commit 471d65cf158c9bf741c21f5d0ab92efe7bf1c3d4 +Author: LoGin +Date: Fri Apr 26 11:59:47 2024 +0800 + + feat(riscv): riscv下能够运行hello world用户程序 (#770) + + * feat(riscv): riscv下能够运行hello world用户程序 + +commit 40348dd8d5a008ecc9eb3aab931933e4eba0e6da +Author: zwb0x00 <163394849+zwb0x00@users.noreply.github.com> +Date: Tue Apr 23 19:35:02 2024 +0800 + + feat(fs): add sys_dup3 (#755) + + * feat(fs): add sys_dup3 + +commit 3b799d13beeb80900d728937308e47f8011835e1 +Author: LoGin +Date: Tue Apr 23 19:14:41 2024 +0800 + + Create FUNDING.yml (#763) + +commit 731bc2b32d7b37298883d7a15b6dca659b436ee4 +Author: LoGin +Date: Tue Apr 23 17:19:54 2024 +0800 + + feat(virtio): riscv: 添加virtio-blk driver,并在riscv下能够正确挂载FAT32 (#761) + +commit 0c1ef30087d10035c256fed08097f5897041979d +Author: Chiichen +Date: Tue Apr 23 00:27:05 2024 +0800 + + docs(community): add description of conventional commit standard (#754) + + * docs(community): add description of conventional commit standard + + * docs: add index + +commit 70c991af204167db26ec1d9494efcff010893482 +Author: laokengwt <143977175+laokengwt@users.noreply.github.com> +Date: Mon Apr 22 17:40:03 2024 +0800 + + fix(dog): 添加CC环境变量,解决编译时找不到musl-gcc的问题 (#753) + +commit e32effb1507773d32c216d9e77b963786e275c06 +Author: LoGin +Date: Mon Apr 22 15:11:47 2024 +0800 + + feat(driver): 把virtio添加到sysfs (#752) + +commit a17651b14b86dd70655090381db4a2f710853aa1 +Author: MemoryShore <105195940+MemoryShore@users.noreply.github.com> +Date: Mon Apr 22 15:10:47 2024 +0800 + + feat(mm): 实现缺页中断处理,支持页面延迟分配和写时拷贝,以及用户栈自动拓展 (#715) + + * 实现缺页中断处理 + + * 完善页表拷贝逻辑 + + * 优化代码结构 + + * 完善缺页异常信息 + + * 修改大页映射逻辑 + + * 修正大页映射错误 + + * 添加缺页中断支持标志 + + * 实现用户栈自动拓展功能 + +commit cb02d0bbc213867ac845b7e8a0fb337f723d396a +Author: Chiichen +Date: Sun Apr 21 23:23:21 2024 +0800 + + ci: import issue checker (#750) + + * ci: supprot auto tag on pull request + + * ci: update issue checker config + + * ci: update issue checker & block merge while + +commit 93c379703e3be210799953bc0686d02f97119b39 +Author: sun5etop <146408999+sun5etop@users.noreply.github.com> +Date: Sun Apr 21 13:36:44 2024 +0800 + + feat(net): 实现raw socket的poll (#739) + + feat(net): 实现raw socket的poll + +commit b502fbf0b9c575a4c04e103d0fb708c4e383ab06 +Author: LoGin +Date: Sun Apr 21 13:30:29 2024 +0800 + + chore: Update virtio-drivers to commit 61ece509c4 and modify max_queue_size implementation (#748) + +commit d770de5d53ce9b598fb0024800a347b081f92a73 +Author: LoGin +Date: Sun Apr 21 13:12:31 2024 +0800 + + fix: 修复unified-init导致cargo check失败的问题 (#747) + +commit 881ff6f95e4addc373d815d66cb912bf721c20e6 +Author: yuyi2439 <68320855+yuyi2439@users.noreply.github.com> +Date: Sun Apr 21 11:39:00 2024 +0800 + + 将smoltcp升级到0.11.0版本 (#740) + +commit 370472f7288b568c7b80815f5b150daf4496446c +Author: LoGin +Date: Sun Apr 21 11:27:36 2024 +0800 + + pci: 添加pci root manager来管理pci root,并使得riscv能够正常扫描pci设备. (#745) + + * pci: 添加pci root manager来管理pci root. + pci: 使得riscv能够正常扫描pci设备. + + * doc: 添加注释 + +commit 2709e017d0d216d61b2caed3c7286459de7794c7 +Author: LoGin +Date: Sat Apr 20 18:31:56 2024 +0800 + + pci: 统一使用ecam root (#744) + +commit 418ad41fd84c15ed7e132e56970150ac38fc24a9 +Author: LoGin +Date: Wed Apr 17 10:03:22 2024 +0800 + + Feat(tty): add dummy console (#735) + + 使得riscv能暂时完成stdio_init(将来需要实现riscv的串口console) + +commit 1012552dea71bf04cf1d329d570c4c9ca9b2a2f8 +Author: Saga1718 <161323888+Saga1718@users.noreply.github.com> +Date: Tue Apr 16 21:37:42 2024 +0800 + + 删除无用的hid代码 (#734) + +commit fbd63a301c5648f906eeb802f10ac03518ba1264 +Author: SMALLC <121806694+SMALLC04@users.noreply.github.com> +Date: Tue Apr 16 21:34:36 2024 +0800 + + feat: alarm系统调用实现 (#710) + + * alarm系统调用实现 + +commit d623e90231ef6a31d091c3f611c0af3a83d3343b +Author: GnoCiYeH +Date: Mon Apr 15 22:01:32 2024 +0800 + + socket统一改用`GlobalSocketHandle`,并且修复fcntl SETFD的错误 (#730) + + * socket统一改用`GlobalSocketHandle`,并且修复fcntl SETFD的错误 + + --------- + + Co-authored-by: longjin + +commit 7162a8358d94c7799dd2b5300192b6a794b23d79 +Author: LoGin +Date: Mon Apr 15 13:20:46 2024 +0800 + + doc: Update build instructions for riscv64 architecture (#725) + +commit 1074eb34e784aa2adfc5b9e0d89fa4b7e6ea03ef +Author: Samuel Dai +Date: Mon Apr 15 13:02:04 2024 +0800 + + feat(filesystem): 引入Umount系统调用 (#719) + + * feat(filesystem): 引入Umount系统调用 + + * 将所有ENOSYS误用更正 + + * 修复了一个使同一个挂载点可以挂载2个文件系统的bug + + * 统一注释,增强程序稳定性,统一接口。注意:Umount时在fatfs的路径要使用大写,此受限于当前文件系统设计。 + +commit ceeb2e943ca7645609920ec7ad8bfceea2b13de6 +Author: laokengwt <143977175+laokengwt@users.noreply.github.com> +Date: Mon Apr 15 12:51:14 2024 +0800 + + feat(mm): 添加slab内存分配器 (#683) + + feat(mm): 添加slab内存分配器 + --------- + + Co-authored-by: longjin + +commit c719ddc6312acd7976e0f6fd449a94ff9abad5a6 +Author: Saga1718 <161323888+Saga1718@users.noreply.github.com> +Date: Sun Apr 14 23:51:47 2024 +0800 + + feat(net): 实现tcp backlog功能 (#714) + + * feat:实现tcp的backlog功能 + +commit 9621ab16ef27bc94f223e6254fafb9bb07d46d57 +Author: LoGin +Date: Sun Apr 14 20:39:20 2024 +0800 + + 让riscv64能正常切换进程,并运行完所有的initcall (#721) + +commit 9fab312ea9921618629924ab15c28c2d255b21c6 +Author: LoGin +Date: Fri Apr 12 15:27:44 2024 +0800 + + Update DragonOS description and introduction (#717) + +commit f049d1af01da7b92f312245ed411b22475b76065 +Author: LoGin +Date: Fri Apr 12 14:46:47 2024 +0800 + + 初始化riscv-sbi-timer (#716) + +commit 3959e94df38073fdb80b199777015f95611ba05f +Author: 曾俊 <110876916+ZZJJWarth@users.noreply.github.com> +Date: Wed Apr 10 19:00:32 2024 +0800 + + bugfix: 修复smp启动的时候,损坏0号核心的idle进程的内核栈的问题 (#711) + + --------- + + Co-authored-by: longjin + Co-authored-by: heyicong + +commit 9365e8017b39582eca620ba93c64f1b3c87c73d4 +Author: GnoCiYeH +Date: Wed Apr 10 19:00:12 2024 +0800 + + 完善pty,目前pty能够支持ssh (#708) + +commit 4b0170bd6bb374d0e9699a0076cc23b976ad6db7 +Author: Chiichen +Date: Wed Apr 10 18:58:54 2024 +0800 + + chore(tools): add bootstrap support for Centos/RHEL8/fedora (#713) + + Co-authored-by: kejianchi + +commit 15b94df01adc7e8931961b9b9a89db4e7c014b64 +Author: Jomo +Date: Wed Apr 10 10:58:07 2024 +0800 + + add xuzihao (#712) + +commit 6fc066ac11d2f9a3ac629d57487a6144fda1ac63 +Author: Jomo <2512364506@qq.com> +Date: Sun Apr 7 14:04:19 2024 +0800 + + 实现SystemV共享内存 (#690) + + * 实现SystemV共享内存 + + * 测试shm + + * 添加测试程序 + + * 完善细节 + + * 修正shm的时间数据错误的问题 + + * fix: devfs的metadata权限为0x777的错误 + + --------- + + Co-authored-by: longjin + +commit eb49bb993a39964f92494ec3effafed3fb9adfd8 +Author: 曾俊 <110876916+ZZJJWarth@users.noreply.github.com> +Date: Sun Apr 7 14:03:51 2024 +0800 + + BlockCache-read cache支持 (#521) + + 支持block cache的读缓存 + +commit 06560afa2aa4db352526f4be8b6262719b8b3eac +Author: hmt <114841534+1037827920@users.noreply.github.com> +Date: Sat Apr 6 22:26:34 2024 +0800 + + Patch feat robust futex (#682) + + * feat: 实现robust lock机制 + + * 前面更改vscode,修改回来 + + * 修改dadk的路径 + + * 提交.gitnore和.cargo,删除LICENSE,修改README + + * 修改一个warn + + * 删除.rustc_info.json + + * 删除target文件夹 + + * 恢复DragonOS的LICENSE,删除Cargo.lock + + * 将校验用户空间地址的代码写入函数内;将部分match分支用ok_or代替 + + * 修改wakeup函数获取running queue时unwrap一个None值发生panic + + * 测试程序使用syscalls库进行系统调用 + +commit 23ef2b33d1e3cfd2506eb7449a33df4ec42f11d3 +Author: LoGin +Date: Sat Apr 6 22:13:26 2024 +0800 + + riscv: 把内核编译target改为riscv64gc & 获取time csr的频率 & 修正浮点保存与恢复的汇编的问题 (#699) + + * 1. 把内核编译target改为riscv64gc + 2. fix: 修正浮点保存与恢复的汇编的问题 + + * riscv: 获取time csr的频率 + +commit f0c87a897fe813b7f06bf5a9e93c43ad9519dafd +Author: GnoCiYeH +Date: Fri Apr 5 17:54:48 2024 +0800 + + 重写调度模块 (#679) + + ## PR:重写调度模块 + --- + ### 完成的部分 + - 实现cfs调度策略 + - 搭建框架,后续功能可以迭代开发 + - 目前能跑,未测试性能 + + ### 需要后续接力的部分 + - 实现组内调度(task_group) + - 实现跨核负载均衡(pelt算法) + - 接入sysfs,实现参数动态调节(sched_stat等) + - nice值以及priority等参数的设置及调优 + +commit e8eab1ac824e1b1e638e50debb8326dfed4f05e5 +Author: LoGin +Date: Fri Apr 5 16:37:08 2024 +0800 + + riscv: copy-thread (#696) + +commit dfe53cf087ef4c7b6db63d992906b062dc63e93f +Author: GnoCiYeH +Date: Fri Apr 5 00:21:55 2024 +0800 + + 实现pty,附带测试程序 (#685) + + * 实现pty,附带测试程序 + + * fmt ** clippy + + * 将file层的锁粒度缩小,从而不使用no_preempt。更改pipe在sleep部分的bug + + * 修复拼写错误 + +commit b8ed38251dc255b0c525801b5dbf37d3b0d0d61e +Author: Donkey Kane <109840258+xiaolin2004@users.noreply.github.com> +Date: Fri Apr 5 00:06:26 2024 +0800 + + 修复jiffy时钟过快问题,启用gettimeofday测试,修改mount测试 (#680) + + 1. 把clock tick rate与hpet频率关联起来 + 2. 修复墙上时间同步错误的问题 + 3. 启用时间watch dog. + 4. 修复时间流逝速度异常 + + --------- + + Co-authored-by: longjin + +commit 9430523b465b19db4dd476e9fd3038bdc2aa0c8d +Author: yuyi2439 <68320855+yuyi2439@users.noreply.github.com> +Date: Thu Apr 4 12:41:19 2024 +0800 + + 使nproc可以正确获取到cpu核心数 (#689) + +commit 9b96c5b547c337502db7ec820312f119f95eece1 +Author: LoGin +Date: Sun Mar 31 22:53:01 2024 +0800 + + riscv64: switch process (#678) + + * riscv64: switch process + + * fixname + +commit 7d580ef99d2a52250b384afd49c7f87ab66a8c84 +Author: Val213 <112376067+val213@users.noreply.github.com> +Date: Sun Mar 31 18:01:32 2024 +0800 + + 修复get_ramdom的长度错误问题() (#677) + +commit 56cc4dbe27e132aac5c61b8bd4f4ec9a223b49ee +Author: Jomo <2512364506@qq.com> +Date: Sun Mar 31 16:33:49 2024 +0800 + + 实现页面反向映射 (#670) + + * 实现页面反向映射 + + * 完善PAGE_MANAGER初始化时机 && 封装lock函数 && 删掉过时注释 + +commit 924d64de8def99488f57dc618de763f7aca4a68b +Author: BrahmaMantra <140599389+BrahmaMantra@users.noreply.github.com> +Date: Sun Mar 31 15:19:12 2024 +0800 + + 修复了ramfs中move_to未更新parent字段的bug (#673) + + 修复了ramfs中move_to未更新parent字段的bug + + --------- + + Co-authored-by: Samuel Dai + +commit 9d9a09841ce2d650a41fed776916c0a11d52f92e +Author: sun5etop <146408999+sun5etop@users.noreply.github.com> +Date: Sun Mar 31 15:11:10 2024 +0800 + + 修复udp bind的时候,对port0处理不正确的问题(#676) + +commit da152319797436368304cbc3f85a3b9ec049134b +Author: LoGin +Date: Thu Mar 28 00:28:13 2024 +0800 + + 实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型 (#674) + + * 实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型。 + +commit 597ecc08c2444dcc8f527eb021932718b69c9cc5 +Author: TTaq <103996388+TTaq@users.noreply.github.com> +Date: Tue Mar 26 18:28:26 2024 +0800 + + 新加结构体POSIXSTATFS与SuperBlock用于处理statfs系统调用 (#667) + + * 新加结构体POSIXSTATFS与SuperBlock用于处理statfs系统调用 + +commit 0cb807346cb3c47924538585087d9fc846cf5e6f +Author: LoGin +Date: Tue Mar 26 18:26:02 2024 +0800 + + 修复tty设备显示在/sys目录下的bug (#668) + +commit 2755467c790d6510fa97cbf052ce8e91ad1372c6 +Author: 曾俊 <110876916+ZZJJWarth@users.noreply.github.com> +Date: Mon Mar 25 16:39:36 2024 +0800 + + 支持绘制24位深和16位深显示缓冲区 (#640) + + * 修复了初始化时显示,边界条件的一个bug + + * 解决了内存未初始前字体显示的兼容性问题 + * 支持绘制24位深和16位深显示缓冲区 + +commit 4256da7fb6ad25a3caab6f656607aaf047cb6446 +Author: LoGin +Date: Mon Mar 25 15:47:05 2024 +0800 + + 把Device trait的set_class改为设置Weak指针,以避免循环引用问题。 (#666) + +commit 5c20e05a2eb82da6dd73104fcf51d538500c2856 +Author: LoGin +Date: Mon Mar 25 13:59:00 2024 +0800 + + 修改bug report模版label (#665) + +commit 7c958c9ef0cd25eb15abb21d0d3420aac1c67c88 +Author: Val213 <112376067+val213@users.noreply.github.com> +Date: Mon Mar 25 13:04:53 2024 +0800 + + 移植dns查询工具dog的--tcp功能 (#652) + + * add dog, modify user/Makefile and user.sysconfig + + * add dog, modify user/Makefile and user.sysconfig + + * fix tty unicode + + * 修正无法正确编译dog的问题 + + --------- + + Co-authored-by: val213 + Co-authored-by: GnoCiYeH + Co-authored-by: longjin + +commit 911132c4b8ea0e9c49a4e84b9fa1db114102acbb +Author: Donkey Kane <109840258+xiaolin2004@users.noreply.github.com> +Date: Mon Mar 25 13:04:32 2024 +0800 + + 修复clock_gettime返回类型错误,修复小时间间隔duration返回0问题 (#664) + + * 修复clock_gettime返回类型错误,修正wtm初始化逻辑 + + * 修复duration在小时间间隔下为0的问题 + + * 临时修复时间流逝速度异常,在test-mount中加入运行时间检测 + +commit 401699735b5ec29768c3c0c47df6c529991f108f +Author: LoGin +Date: Sat Mar 23 16:25:56 2024 +0800 + + riscv: 进程管理初始化 (#654) + +commit 6046f77591cf23dc9cc53b68b25c0d74f94fa493 +Author: 裕依 <68320855+yuyi2439@users.noreply.github.com> +Date: Sat Mar 23 15:56:49 2024 +0800 + + Patch socketpair (#576) + + * 将sockets分成inet和unix域 + - 添加File端点 + - 添加SocketPair trait并将Socket trait中的pair相关方法移动 + - 添加对SockAddrUn的处理 + + * 精简SocketHandleItem + + * 重构socketpair相关逻辑 + - 将File端点换成Inode端点 + - 尝试使用SocketInode进行socketpair(未成功) + + + * 将SocketPair trait合并到Socket trait中,去除downcast + +commit 3660256a9ee94abc30b5b22508cbd48c44c86089 +Author: LoGin +Date: Sat Mar 23 11:51:30 2024 +0800 + + 只对x86_64进行clippy check (#651) + +commit 4e4c8c41e90989c1f732995511e0f9a77a33f650 +Author: LoGin +Date: Fri Mar 22 23:56:30 2024 +0800 + + 添加clippy检测的自动化工作流 (#649) + + * 添加clippy检测的自动化工作流 + + * fmt + + * 1 + +commit b5b571e02693d91eb6918d3b7561e088c3e7ee81 +Author: LoGin +Date: Fri Mar 22 23:26:39 2024 +0800 + + 修复内核的clippy检查报错 (#637) + + 修复内核的clippy检查报错 + --------- + + Co-authored-by: Samuel Dai <947309196@qq.com> + Co-authored-by: Donkey Kane <109840258+xiaolin2004@users.noreply.github.com> + Co-authored-by: themildwind <107623059+themildwind@users.noreply.github.com> + Co-authored-by: GnoCiYeH + Co-authored-by: MemoryShore <105195940+MemoryShore@users.noreply.github.com> + Co-authored-by: 曾俊 <110876916+ZZJJWarth@users.noreply.github.com> + Co-authored-by: sun5etop <146408999+sun5etop@users.noreply.github.com> + Co-authored-by: hmt <114841534+1037827920@users.noreply.github.com> + Co-authored-by: laokengwt <143977175+laokengwt@users.noreply.github.com> + Co-authored-by: TTaq <103996388+TTaq@users.noreply.github.com> + Co-authored-by: Jomo <2512364506@qq.com> + Co-authored-by: Samuel Dai + Co-authored-by: sspphh <112558065+sspphh@users.noreply.github.com> + +commit 4695947e1b601c83641676485571d42c692a2bbd +Author: Chenzx <109664121+schulice@users.noreply.github.com> +Date: Fri Mar 22 18:27:07 2024 +0800 + + 实现SYS_LINK和SYS_LINKAT (#611) + + * 实现do_linkat及SYS_LINK和SYS_LINKAT + + * 未在riscv上测试,添加target_arch + + * 将c字符串检查移动到vfs/syscall.rs,修改do_linkat()逻辑 + + * 修改部分注释 + +commit 70f159a3988eab656ea1d2b204fde87948526ecf +Author: LoGin +Date: Thu Mar 21 21:35:39 2024 +0800 + + riscv64: 添加flush tlb的ipi (#636) + + * riscv64: 添加flush tlb的ipi + + * update triagebot + +commit b4eb05a17f0f65668f69e7979660874ef8e01a2e +Author: TTaq <103996388+TTaq@users.noreply.github.com> +Date: Thu Mar 21 19:59:10 2024 +0800 + + Statx (#632) + + + * 实现statx及测试的应用程序 + +commit 8cb2e9b344230227fe5f3ab3ebeb2522f1c5e289 +Author: LoGin +Date: Thu Mar 21 19:19:32 2024 +0800 + + 重写SMP模块 (#633) + + * 修复cpumask的迭代器的错误。 + + * 能进系统(AP核心还没有初始化自身) + + * 初始化ap core + + * 修改percpu + + * 删除无用的cpu.c + + * riscv64编译通过 + +commit 1d37ca6d172e01a98fa6785d2b3e07fb8202a4a9 +Author: Donkey Kane <109840258+xiaolin2004@users.noreply.github.com> +Date: Wed Mar 20 15:31:20 2024 +0800 + + 添加mount系统调用 (#561) + + * Modify dadk config to switch NovaShell revision + + * finish primary build of mount(2), usable now + + * 使用read_from_cstr函数优化代码可读性 , 针对文件系统新增错误EUNSUPFS + + * small changes + + * 添加系统调用文档 + + * cargo fmt + + * Revert "small changes" + + This reverts commit e1991314ce687faa2d652479e8ef64f5bea25fa1. + + * 修复用户程序参数传入错误 + + * Revert "small changes" + + This reverts commit e1991314ce687faa2d652479e8ef64f5bea25fa1. + + * 解决合并冲突,最终提交 + + * 将dadk_config切换为相对路径以修复依赖问题 + + * Update settings.json + + * Delete user/apps/test-mount/LICENSE + + * 换用更好的c字符串读取函数,优化系统调用函数注释,修复错误处理bug,删除无用文件,修改测试程序readme + + * 修改用户程序readme + + * 代码格式化,初级版本 + + * 初级版本,未实现文件系统管理器,未支持设备挂载 + + * 为文件系统添加name方法,返回文件系统名字字符串,为挂载查询服务 + + * mount系统调用:添加统一文件系统初始化管理器 + + * null + + * 解除冲突 + + * 删除无用kdebug + +commit 1cd9bb43f0256aecf19a090dd71e4ac2b86a5e29 +Author: LoGin +Date: Tue Mar 19 21:31:02 2024 +0800 + + 添加core utils到系统 (#624) + +commit 8c6f21840f820a161d4386000aea1d79e3bc8d13 +Author: sspphh <112558065+sspphh@users.noreply.github.com> +Date: Tue Mar 19 17:01:20 2024 +0800 + + 实现uname系统调用 (#614) + + * 实现uname系统调用 + + Co-authored-by: longjin + +commit 82df0a13109e400602ddaec049d04ae230eb485b +Author: hmt <114841534+1037827920@users.noreply.github.com> +Date: Tue Mar 19 16:45:44 2024 +0800 + + fix: mkdir输出错误信息; feat: 实现get_pathname (#615) + + * fix: mkdir输出错误信息; feat: 实现get_pathname + + * fix: 将处理路径的操作放入vfs而不是在syscall/mod.rs中 + + * 调整入参类型 + + --------- + + Co-authored-by: longjin + +commit 9e481b3bfe303e0b104694da9750ae978dfeecae +Author: TTaq <103996388+TTaq@users.noreply.github.com> +Date: Mon Mar 18 14:47:59 2024 +0800 + + 实现了sys_rename (#578) + + * 基本实现了rename的系统调用 + + * 实现相对路径的mv + + * confilct resolve + + * make fmt + + * 更改校验位置, + 增加了SYS_RENAMEAT与SYS_RENAMEAT2两个系统调用,其实现与SYS_RENAME基本一致 + + * 删除了fat中的link + + * fix + + * 修改注释格式,删除管道文件判断 + + * 1 + +commit c3c73444516b7b47b6327cd66f5453133f47998d +Author: LoGin +Date: Sat Mar 16 22:28:59 2024 +0800 + + 更新triagebot配置 (#616) + + * 更新triagebot配置 + +commit 4fd916113e576a1c5d8ca9faae7a9d6b25afb9ae +Author: LoGin +Date: Sat Mar 16 18:09:32 2024 +0800 + + triagebot-add-shortcut (#612) + +commit fbc174499f5200924c732263e461c79b4a936c5b +Author: LoGin +Date: Fri Mar 15 20:06:24 2024 +0800 + + 添加triagebot文件 (#608) + + * 添加triagebot文件 + +``` diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.2.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.2.md new file mode 100644 index 00000000..3b1f00ba --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.2.md @@ -0,0 +1,333 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.2.md + +- Translation time: 2025-05-19 01:42:16 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.2 + +:::{note} +Author: Long Jin + +December 17, 2022 +::: + +## Contributors + +The DragonOS V0.1.2 version has been contributed by the following developers: + +- Long Jin +- Wu Yujian +- Gou Ngai +- Huang Ting +- Wang Wencong <1297389017@qq.com> + +## Sponsors + +Thank you to the following individuals for their support. We will continue to strive hard! + +- David Wen +- [Seele.Clover](https://github.com/seeleclover) +- TerryLeeSCUT +- Wu +- slientbard + +Among them, we are especially grateful to **Seele.Clover** for contributing RMB 500 to the DragonOS project! We will carefully record every sponsorship and ensure that it is used appropriately. + +## Update Content - Kernel + +- Remove rust_helloworld file (#_translated_label__113_en) +- Signal: Allow users to register signal handler functions, enabling custom handlers. (#_translated_label__112_en) + - Support for the kill command + - Allow users to customize signal handling functions + - Add two new system calls: `SYS_SIGACTION`, `SYS_RT_SIGRETURN` + - libc adds `signal()`, `sigaction()` functions. + - Currently only supports the old version of sighandler, i.e., signal handler functions with only one parameter of type `void handler(int signum)`. The other type of signal handler function `void handler(int signum, siginfo_t *info, void* data)` does not currently support passing the third parameter. +- Add a custom stdint.h file in the kernel code (#_translated_label__109_en) +- Adjust the script for compiling grub (#_translated_label__108_en) +- Add 32-bit and 64-bit UEFI boot support (#_translated_label__105_en)(#_translated_label__101_en) +- Use compiled installed grub-2.06 to solve the problem of compilation failure due to incorrect grub version on the client. +- Add a timekeeping module (#_translated_label__106_en) +- Bugfix: Fix the issue where the rtc clock forgot to process the day field when converting to BCD code (#_translated_label__104_en) +- New: Development process documentation (completed half) +- bootstrap.sh solves the problem of slow rust download +- Update the "Build System" documentation +- procfs->status adds display of preempt and virtual runtime (#_translated_label__100_en) +- ffz function: get the first bit that is 0 in a u64 (#_translated_label__100_en) +- Solve the problem of local_irq_restore not being able to get the correct rflags value due to compiler optimization +- Refactor the serial port driver using Rust (#_translated_label__99_en) + +## Update Content - User Environment + +- about app: Display the current git commit sha1 and build time (#_translated_label__114_en) +- shell: Fix the error in the shell's exec command when concatenating absolute paths (#_translated_label__114_en) +- shell: Add "&" background execution option for the exec command (#_translated_label__100_en) +- New: Test app for signal +- Adjust the libc directory and add cargo as the Rust package manager + +## Source Code and Release Image Download + +  You can obtain the source code through the following methods: + +### Get via Git + +- You can download the release code and the compiled, runnable disk image from [https://github.com/fslongjin/DragonOS/releases](https://github.com/fslongjin/DragonOS/releases). +- We also have a mirror repository on gitee for download: [https://gitee.com/DragonOS/DragonOS](https://gitee.com/DragonOS/DragonOS) + +### Get via DragonOS Software Mirror Site + +  To solve the problem of slow and unstable access to GitHub in China, and to make it convenient for developers to download the code of each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can obtain the DragonOS source code package and the compiled, runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org](https://mirrors.DragonOS.org) +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the DragonOS source code and corresponding software products (including but not limited to binary copies and documents) can enjoy the rights granted by us through the GPLv2 protocol, while you also need to comply with the obligations stipulated in the protocol. + +This is a rather strict protocol that protects the healthy development of open source software and prevents it from being encroached upon. + +For most well-intentioned people, you will not violate our open source protocol. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe on the legitimate rights and interests of others or violate the GPLv2 protocol. + +Please pay special attention to the fact that violations of the open source protocol, especially **commercial closed-source use and any plagiarism or academic misconduct**, will be subject to serious accountability. (This is the easiest scenario to violate our open source protocol.) + +Also, please note that according to the requirements of the GPLv2 protocol, any software modified or developed based on DragonOS must also be open-sourced under the GPLv2 protocol and clearly indicate that it is based on DragonOS. It must also ensure that users of these modified versions can easily obtain the original version of DragonOS. + +You must make sure that the developers of DragonOS can obtain the source code of your modified version through public channels in the same way, otherwise you will violate the GPLv2 protocol. + +For detailed information about the protocol, please read the **LICENSE** file in the root directory of the project. Please note that according to the requirements of the GPLv2 protocol, **only the English original version is legally binding**. Any translated version is for reference only. +::: + +### Open Source Software Usage + +  During the development of DragonOS, we have referenced some open source projects' designs, or introduced parts of their code, or been inspired by them. We list them below. We sincerely thank the contributors of these open source projects! + +Format: - - + +- Linux - https://git.kernel.org/ - GPLv2 +- skiftOS - https://github.com/skiftOS/skift - MIT +- FYSOS - https://github.com/fysnet/FYSOS - [FYSOS' License](https://github.com/fysnet/FYSOS/blob/9a8968e3d6600de34539c028c843f4c06d134039/license.txt) +- LemonOS - https://github.com/LemonOSProject/LemonOS.git - BSD 2-Clause License +- LZ4 - https://github.com/lz4/lz4 - BSD 2-Clause license +- SerenityOS - https://github.com/SerenityOS/serenity.git - BSD 2-Clause license +- MINE - 《A Design and Implementation of a 64-bit Operating System》 by Tian Yu; People's Posts and Telecommunications Press +- chcore - 《Modern Operating Systems: Design and Implementation》 by Chen Haibo, Xia Yubin; Machinery Industry Press +- SimpleKernel - https://github.com/Simple-XX/SimpleKernel - MIT + +## All Commit Records of the Current Version + +```text +commit 7a818da88a1c7a1760de7671141b0ce1ca4e3dde +Author: login +Date: Sat Dec 17 17:49:12 2022 +0800 + + Patch about auto gen version string (#114) + + * new: about app中,显示当前构建的git commit sha1以及构建时间 + + * bugfix: 修复shell的exec命令对绝对路径的拼接错误问题 + +commit 83a7aaa46bbc411c43d4fc099c6c8884efbe4771 +Author: login +Date: Sat Dec 17 16:31:50 2022 +0800 + + 删除rust_helloworld文件 (#113) + +commit 6efd4740336205c9bfdd8b164e667cee2f38781e +Author: login +Date: Sat Dec 17 16:27:50 2022 +0800 + + 允许用户自定义信号处理函数 (#112) + + * new: 用户注册信号处理函数,能够进入自定义的handler + + * 修复忘了传信号的数字给用户的处理函数的bug + + * new:sigreturn + + * 删除注释 + +commit 0e0c187484281768391e131495f0655e40d70cf7 +Author: login +Date: Fri Dec 16 16:20:09 2022 +0800 + + 在内核代码中加入自定义的stdint.h文件 (#109) + +commit d02e6ea4112ad520aa4090ff73cdf592e14c0a82 +Author: login +Date: Wed Dec 14 20:01:55 2022 +0800 + + 调整编译grub的脚本的部分 (#108) + + 1、bugfix: 修复编译grub的脚本的部分错误 + 2、将grub下载源替换为tuna + 3、优化写入磁盘镜像的脚本 + 4、将bios文件夹改名为legacy + +commit 38b341b8aa671f75ac26d05059aa2e9a09e653b7 +Author: YJwu2023 <119829947+YJwu2023@users.noreply.github.com> +Date: Wed Dec 14 16:58:49 2022 +0800 + + 新增32位uefi启动 (#105) + + * 新增32位uefi启动 + + * 修复小bug + + * 增加grub本地编译安装 + + * 增加本地grub编译安装脚本 + + * 修正小错误 + + * 修复空文件夹不上传的bug + +commit 01876902fbf6ed43992cc7d153bd8c505cb5224b +Author: Gou Ngai <94795048+AlbertSanoe@users.noreply.github.com> +Date: Wed Dec 14 15:13:54 2022 +0800 + + 增加了timekeeping模块 (#106) + + * 增加了timekeeping模块 + + * 格式化文档和细节更改 + + Co-authored-by: longjin + +commit 728aca308917a7d4d0ba10fe8174e9408d77a9a6 +Author: login +Date: Sun Dec 11 22:59:47 2022 +0800 + + bugfix: 修复rtc时钟对BCD码进行转换的时候,忘了处理day字段的问题 (#104) + +commit 237e95c6ddce72d72ae7fedfeca412fab82b3622 +Author: wwc-15172310230 <78997674+wwc-15172310230@users.noreply.github.com> +Date: Sun Dec 11 22:22:10 2022 +0800 + + 调整user下libs的libc目录结构 (#103) + + * 调整user下libs的libc目录结构 + + * 修正.gitignore文件的问题 + + * 修复无法编译的问题 + + Co-authored-by: longjin + +commit 2291ffdece1dc5a703602f79f74df8a4854d215b +Author: login +Date: Sun Dec 11 20:09:58 2022 +0800 + + 文档更新 (#102) + + * new: 开发过程文档(完成了一半) + + * bootstrap.sh解决下载rust慢的问题 + + * 更新“构建系统”文档 + +commit 7f439c5ddbd2ecffc112149d16983975f523052c +Author: YJwu2023 <119829947+YJwu2023@users.noreply.github.com> +Date: Fri Dec 9 16:08:54 2022 +0800 + + 增加uefi启动 (#101) + + * 增加uefi启动 + + * 修改脚本 + + * uefi修改 + + * 删除错误的注释 + + * 修正写入磁盘镜像的脚本 + + * 修改X86_64为x86_64 + + Co-authored-by: longjin + +commit 1a2eaa402f05f82aaeebe1e03824534a0a425d4d +Author: login +Date: Thu Dec 8 22:59:51 2022 +0800 + + signal的处理(kill命令)以及一些其他的改进 (#100) + + * 将entry.S中冗余的ret_from_syscall代码删除,改为jmp Restore_all + + * new: 增加判断pt_regs是否来自用户态的函数 + + * new: rust的cli和sti封装 + + * 将原有的判断pt_regs是否来自用户态的代码,统一改为调用user_mode函数 + + * ffz函数:获取u64中的第一个值为0的bit + + * spinlock增加 spinlock irq spin_unlock_irq + + * 临时解决显示刷新线程迟迟不运行的问题 + + * 更改ffi_convert的生命周期标签 + + * new: 测试signal用的app + + * 解决由于编译器优化导致local_irq_restore无法获取到正确的rflags的值的问题 + + * new: exec命令增加"&"后台运行选项 + + * procfs->status增加显示preempt和虚拟运行时间 + + * 更改引用计数的FFIBind2Rust trait中的生命周期标签 + + * new: signal处理(kill) + + * 更正在review中发现的一些细节问题 + +commit f8b55f6d3fcbf152a1cb6d6fc722bf1607418b28 +Author: TingHuang <92705854+TingSHub@users.noreply.github.com> +Date: Tue Dec 6 22:15:03 2022 +0800 + + Patch uart (#99) + + * 添加UART驱动相关文件 + + * 添加驱动核心文件,将rust编写的驱动代码加入Package中 + + * 添加glib.h文件生成rust代码,添加uart驱动代码 + + * 添加串口发送及接收相关代码 + + * 添加字符串发送函数,未实现具体功能 + + * 为调用uart驱动的代码添加rust接口 + + * 添加字符串发送函数,修改C语言调用接口 + + * 添加rust串口驱动 + + * 添加uart.h头文件,将串口端口类型改为enum + + * 添加注释,规范代码 + +commit 036acc52ce9d0fb9e7d92768ff74939a29c07f32 +Author: login +Date: Tue Nov 29 21:46:13 2022 +0800 + + 将entry.S中冗余的ret_from_syscall代码删除,改为jmp Restore_all (#98) + + * 将entry.S中冗余的ret_from_syscall代码删除,改为jmp Restore_all + +``` diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.3.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.3.md new file mode 100644 index 00000000..fc12c849 --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.3.md @@ -0,0 +1,504 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.3.md + +- Translation time: 2025-05-19 01:41:49 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.3 + +:::{note} +Author: Longjin + +January 8, 2023 +::: + +## Contributors + +The DragonOS V0.1.3 version was contributed by the following individuals: + +- Longjin +- Wu Yujian +- Guan Jinquan +- Gou Ngai + +## Sponsors + +Thank you to the following individuals for their support. We will continue to strive for excellence! + +- David Wen +- [Seele.Clover](https://github.com/seeleclover) +- TerryLeeSCUT +- Wu +- slientbard + +## Update Content - Kernel + +- syscall: new: Add getpid system call (#_translated_label__120_en) +- signal: update: Add all signals except SIGKILL to SigQueue (#_translated_label__120_en) +- rtc: refactor: Refactor RTC driver using Rust (#_translated_label__118_en) +- doc: new: Add documentation for signal (#_translated_label__126_en) +- Spinlock: new: Add Rust-written RawSpinlock (#_translated_label__127_en) +- arch: update: Change the path of the arch module in lib.rs, so that other modules can use the code in arch without specifying arch::x86_64 (#_translated_label__128_en) +- mm: bugfix: Fix the bug where ZONE_NORMAL_INDEX was always 0 during initialization of the page allocator (#_translated_label__129_en) +- scheduler: new: Refactor CFS scheduler using Rust (#_translated_label__131_en) +- smp: Remove the HPET interrupt forwarding function that has been deprecated in smp (#_translated_label__131_en) +- process: bugfix: Fix the issue where the init process forgot to set the fs and gs registers. (#_translated_label__132_en) +- vfs: update: Rename the VFS folder to vfs (#_translated_label__133_en) +- lockref: new: Add Rust version of lockref (#_translated_label__135_en) +- cpu: new: Rust wrapper for cpu_relax(), using the pause instruction to let the CPU rest for a while, reducing idle power consumption. (#_translated_label__135_en) +- Refactor softirq mechanism using Rust (#_translated_label__138_en) + +## Update Content - User Environment + +- libc: bugfix: Always register sigkill when registering signal handlers (#_translated_label__120_en) +- libc: new: Add raise, kill, abort (#_translated_label__120_en) +- libc: new: Add an arch folder, and add crt0, crti, crtn files under it (#_translated_label__134_en) +- libc: new: Add `fflush()`, `fprintf()`, `stdin`, `stdout`, `stderr`, `ferror()`, `fopen()`, `fclose()`, `putchar()`, `puts()` (#_translated_label__136_en) +- libc: new: Simply add `fopen()` for handling the mode parameter. Please note that it does not fully comply with POSIX, and is inconsistent with Linux. It will be improved when using Rust in the future. (#_translated_label__141_en) +- Porting: new: Add porting and build scripts for gmp, mpfr, and mpc (#_translated_label__136_en) +- Porting: new: Add cross-compilation build scripts for gcc and binutils, as well as patches for gcc-11.3.0 and binutils-2.38 (in the DragonOS-community repository) (#_translated_label__136_en) +- compile: update: Update the include path for the compiler, so that includes do not need the `` prefix (#_translated_label__124_en) + +## Update Content - Others + +- bugfix: Fix the bug where Docker installation would exit abnormally (#_translated_label__116_en) +- new: Add a new GCC bare-metal compiler targeting x86_64-elf, and use it to compile DragonOS (#_translated_label__111_en) +- update: Update the Docker build image to version `dragonos/dragonos-dev:v1.2`, and support building this build image from a Dockerfile (#_translated_label__111_en) +- bugfix: Fix the bug where the MBR disk image did not set the boot flag (#_translated_label__111_en) +- update: Update the GitHub workflow, add cache, and speed up build checks +- bugfix: Fix the error message when downloading grub2.06 (#_translated_label__125_en) + +## Update Content - Software Porting + +- new: gcc 11.3.0 userland cross-compiler, commit: `64a5b1cbf28e3305560e166c1b6624e99745c720`, repository: [https://github.com/DragonOS-Community/gcc](https://github.com/DragonOS-Community/gcc) +- new: binutils 2.38 cross-compile tools, commit: `a0ae560e0065862a9867b9e1f8364749ef38d99e`, repository: [https://github.com/DragonOS-Community/binutils](https://github.com/DragonOS-Community/binutils) +- new: gmp 6.2.1, commit: `dd9eee5778fb6027fafa4fe850aff21b1a71c18e`, repository: [https://github.com/DragonOS-Community/gmp-6.2.1](https://github.com/DragonOS-Community/gmp-6.2.1) +- new: mpfr 4.1.1, commit: `fa8e30cdc2e838fdd82b60fec31fcfc5e118aad6`, repository: [https://github.com/DragonOS-Community/mpfr](https://github.com/DragonOS-Community/mpfr) +- new: mpc 1.2.1, (can be ported without applying patches), repository: [https://github.com/DragonOS-Community/mpc](https://github.com/DragonOS-Community/mpc) + +## Source Code and Release Image Download + +  You can obtain the source code through the following methods: + +### Get via Git + +- You can download the release code and the compiled, runnable disk image from [https://github.com/fslongjin/DragonOS/releases](https://github.com/fslongjin/DragonOS/releases). +- We also have a mirror repository on Gitee for download: [https://gitee.com/DragonOS/DragonOS](https://gitee.com/DragonOS/DragonOS) + +### Get via DragonOS Software Mirror Site + +  To address the slow and unstable access to GitHub in China, and to make it convenient for developers to download the code of each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can obtain the DragonOS source code archive and the compiled, runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org](https://mirrors.DragonOS.org) +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) +- Domestic mirror acceleration: [https://mirrors.ringotek.cn/](https://mirrors.ringotek.cn/) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the DragonOS source code and corresponding software products (including but not limited to binary copies and documentation) can enjoy the rights granted by us through the GPLv2 protocol, while you also need to comply with the obligations stipulated in the protocol. + +This is a rather strict protocol that protects the healthy development of open source software and prevents it from being encroached upon. + +For most well-intentioned people, you will not violate our open source license. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe on the legitimate rights and interests of others or violate the GPLv2 protocol. + +Please pay special attention to the fact that violations of the open source license, especially **commercial closed-source usage and any acts of plagiarism or academic misconduct**, will be subject to serious accountability. (This is the easiest scenario to violate our open source license.) + +Also, please note that according to the requirements of the GPLv2 protocol, software modified or developed based on DragonOS must also be open-sourced under the GPLv2 protocol and must indicate that it is based on DragonOS. It must also ensure that users of these modified versions can easily obtain the original version of DragonOS. + +You must allow the DragonOS developers to obtain the source code of your modified version through the same method from public channels; otherwise, you will violate the GPLv2 protocol. + +For detailed information about the protocol, please read the **LICENSE** file in the root directory of the project. Please note that, according to the requirements of the GPLv2 protocol, **only the English original version has legal effect**. Any translated version is for reference only. +::: + +### Usage of Open Source Software + +  During the development of DragonOS, we have referenced the design of some open source projects, or introduced parts of their code, or been inspired by them. Below is a list of these open source projects. We sincerely thank the contributors of these open source projects! + +Format: - - + +- Linux - https://git.kernel.org/ - GPLv2 +- skiftOS - https://github.com/skiftOS/skift - MIT +- FYSOS - https://github.com/fysnet/FYSOS - [FYSOS' License](https://github.com/fysnet/FYSOS/blob/9a8968e3d6600de34539c028c843f4c06d134039/license.txt) +- LemonOS - https://github.com/LemonOSProject/LemonOS.git - BSD 2-Clause License +- LZ4 - https://github.com/lz4/lz4 - BSD 2-Clause license +- SerenityOS - https://github.com/SerenityOS/serenity.git - BSD 2-Clause license +- MINE - "A Design and Implementation of a 64-bit Operating System" by Tian Yu; People's Posts and Telecommunications Press +- chcore - "Modern Operating Systems: Design and Implementation" by Chen Haibo, Xia Yubin; Machinery Industry Press +- SimpleKernel - https://github.com/Simple-XX/SimpleKernel - MIT +- rcore-fs - https://github.com/rcore-os/rcore-fs.git - MIT + +## All Commit Records of the Current Version + +```text +commit a8b621c8d1fe77251b8e4eafe258dc0ee7366dd5 +Author: login +Date: Sun Jan 8 15:47:44 2023 +0800 + + 修正由于libc中具有crti.S和crtn.S,造成的与x86_64-elf-gcc不兼容的问题 (#144) + +commit 9358ff0f6f7daa18d6fab4497de025736b3d6725 +Author: login +Date: Sun Jan 8 15:06:52 2023 +0800 + + Add v0.1.3 changelog (#143) + + * new: 0.1.3发行日志 + + * 新增输出指定时间范围内的贡献者名单的脚本 + + * 更新bootloader文档 + + * update: 简介文档 + + * new: 镜像站文档 + + * update: 功能特性文档 + +commit fd91905f022b3ceaa59e666d1ff42d91fb8d40ef +Author: login +Date: Sun Jan 8 11:38:59 2023 +0800 + + 解决编译gcc、binutils的脚本中,变量名称错误的问题 (#142) + +commit 62e4613978193aaf5d949a331df0398f2d085a30 +Author: Gou Ngai <94795048+AlbertSanoe@users.noreply.github.com> +Date: Sat Jan 7 23:15:37 2023 +0800 + + 使用rust重构softirq机制;解决Rtc驱动的编译警告问题 (#138) + + * 使用rust重构softirq机制 + * 解决Rtc驱动的编译警告问题 + + Co-authored-by: longjin + +commit e9fdc57bf878f1bc5cc5743dfaeeaef743439291 +Author: login +Date: Sat Jan 7 22:36:49 2023 +0800 + + 简单添加了fopen对mode参数的处理。请注意,它没有完全遵循posix,也与Linux的不一致,将来使用Rust的时候完善它。 (#141) + +commit 2224c93ea968bc74621f7e124b4aca04875b3e6a +Author: guanjinquan <1666320330@qq.com> +Date: Fri Jan 6 21:29:23 2023 +0800 + + 完善libc,构建了OS-specific工具链,编译了基于gcc-11.3.0的DragonOS userland compiler,移植了mpfr,gmp,mpc库 (#134) + + * 修改include路径 + + * 添加了创建libsysapi.a和/bin/sysroot/usr/include/+lib/的代码 + + * 修补.gitignore + + * 删除多余项 + + * 优化脚本可读性 + + * 新增crt0 crti crtn + + * 编译binutils所需的东西 + + * fflush()和fprintf()的简单实现 + + * 应用程序启动前,调用初始化libc的函数 + + * 自动创建sysroot + + * 添加了stderr的初始化 + + * 修改了stderr的初始化 + + * 内核添加对stdio的简略处理 + + * 格式化代码 + + * 修正打开stdio文件描述符的问题 + + * bugfix: 修复fprintf忘记释放buf的问题 + + * 修复shell错误地把入口设置为main而不是_start的问题 + + * 新增__cxa_atexit (gcc要求libc提供这个) + + * 增加putchar puts + + * 更新写入磁盘镜像的脚本,默认无参数时,使用legacy方式安装 + + * 更新编译脚本 + + * stdio增加eof的定义 + + * 新增extern cplusplus + + * mpfr gmp mpc 构建脚本 + + * 更新libsysapi.a为libc.a + + * 加上ferror fopen fclose + + * 更新移植的软件的构建脚本 + + * 更改build_gcc_toolchain.sh中的-save参数名为-save-cache + + Co-authored-by: longjin + +commit 61de2cdc3f29cdc6c441f128119e01e003e6f3ca +Author: login +Date: Tue Jan 3 23:09:25 2023 +0800 + + 新增rust版本的lockref (#135) + + * new:Rust封装cpu_relax(),通过pause指令,让cpu休息一会儿。降低空转功耗 + + * new: Rust版本的lockref + + * Rust的RawSpinlock新增is_locked()和set_value()方法。 + + * lockref文档 + +commit 2726f101b4cc787bbd36a69afffb0112f3a6567f +Author: login +Date: Tue Jan 3 21:01:56 2023 +0800 + + 删除无用的cfs.h (#136) + +commit 587086d3f299f7394559d547c828191be20cfc11 +Author: login +Date: Sun Jan 1 16:53:57 2023 +0800 + + 1、在文件系统目录下增加mod.rs 2、将VFS的路径改为vfs(#133) + + 2、将VFS的路径改为vfs + +commit 843e442971a47693f37a5f8d3452c383f7325359 +Author: login +Date: Sat Dec 31 18:43:05 2022 +0800 + + 修复init进程忘记设定fs gs寄存器的问题。 (#132) + +commit 74bde36e014ff501241bf40dd83653db47a2c8e4 +Author: guanjinquan <1666320330@qq.com> +Date: Sat Dec 31 17:35:39 2022 +0800 + + Patch porting gcc v2 (#124) + + * 更改编译器的Include路径,使得include时不需要加``前缀 + + * 修改include路径 + + Co-authored-by: longjin + +commit d4f3de93a23e4bd4f000a3663768d47d094bf188 +Author: login +Date: Sat Dec 31 17:26:12 2022 +0800 + + 使用Rust重构CFS调度器 (#131) + + * 新建调度器的文件 + + * 把softirq vector移动到c文件中(原来在.h) + + * 将进程切换方式改为“中断返回时切换” + + * new:使用rust重构CFS + + * 删除已经在smp中废弃的HPET中断转发函数 + + * 代码格式化 + + * 删除多余的dunce依赖 + +commit 156949680c83f2d7e3b21ed68b11698b88eaf396 +Author: login +Date: Sat Dec 31 13:47:49 2022 +0800 + + bugfix:修复当使用sched()运行调度器,在切换进程的时候,由于不在中断上下文内,导致当前进程的上下文丢失的问题。 (#130) + + bugfix:修复当使用sched()运行调度器,在切换进程的时候,由于不在中断上下文内,导致当前进程的上下文丢失的问题。 + bugfix:修复切换进程的宏的汇编代码的损坏部分,未声明rax寄存器,从而导致的编译器未定义行为问题。 + +commit 882f0b7e7498dbff8de527b2b9159b7f6e6359c9 +Author: YJwu2023 <119829947+YJwu2023@users.noreply.github.com> +Date: Wed Dec 28 19:35:17 2022 +0800 + + 修复内存bug与grub安装脚本的错误 (#129) + + * 修复内存bug与grub安装脚本的错误 + + * 修改小bug + +commit adc1846b06fb862caed049f435fc0061488a6ff9 +Author: login +Date: Mon Dec 26 13:13:12 2022 +0800 + + 内核:在lib.rs中,将arch模块的路径进行更改,使得其他模块使用arch的代码时,不需要指定arch::x86_64 (#128) + +commit ac643d420b22f9d454ecefccd51ed34a9664586b +Author: login +Date: Sun Dec 25 23:53:35 2022 +0800 + + new:新增rust写的RawSpinlock (#127) + +commit 998390210549b47e6bdcc3fdab49eff4086ad18b +Author: login +Date: Sat Dec 24 23:30:26 2022 +0800 + + 新增signal文档 (#126) + + * 新增signal文档 + +commit a7f5ca7b67160557abf84a1169dd60093220aeb0 +Author: YJwu2023 <119829947+YJwu2023@users.noreply.github.com> +Date: Sat Dec 24 23:29:36 2022 +0800 + + 修复下载grub2.06时的提示错误 (#125) + + * 修复grub下载显示提示显示错误 + +commit 82762007da41148e1ed1df465211eb5c8ba2c15e +Author: login +Date: Fri Dec 23 18:11:47 2022 +0800 + + Update makefile.yml + +commit b975025ec8854ca232152f4ee44cc2226891a34c +Author: login +Date: Fri Dec 23 11:45:19 2022 +0800 + + Update makefile.yml + +commit ad2bb74d949bfcb2935e43ac7b261d7ecce23389 +Author: login +Date: Fri Dec 23 11:21:22 2022 +0800 + + Update makefile.yml + +commit 6b7776d189ab5f19fbab20d6c5c9ed3ab20c7ab6 +Author: login +Date: Fri Dec 23 10:59:15 2022 +0800 + + 修正smp的makefile中没有替换AS的问题 + +commit beb12a188b6c6bc4196796ac2ae1ecd7d8ed8223 +Author: login +Date: Fri Dec 23 10:57:39 2022 +0800 + + Update makefile.yml + +commit d65c527730e5c8a75f6dad0f996c093040699ee3 +Author: login +Date: Thu Dec 22 22:58:28 2022 +0800 + + Update makefile.yml (#121) + +commit 5ed4cd460200cb19aae8c3c67dfd77e1e9f0e105 +Author: guanjinquan <75822481+guanjinquan@users.noreply.github.com> +Date: Thu Dec 22 21:09:12 2022 +0800 + + Patch gcc toolchain (#111) + + * 添加了GCC_cross_compile——tool_chain + + * - 解决环境变量路径拼接时,多了`/`的问题 + - apt安装时增加-y,不需用户确认 + + * 解决添加环境变量的命令有误的问题 + + * 修正编译错误时,还会执行下一步的问题 + + * new: 编译完成后清理临时文件 + + * 更新makefile + + * 调整:把grub安装在 $HOME/opt/dragonos-grub下 + + * new: 新增dockerfile + + * 将镜像源换成中科大的(原因是清华的总是ban掉用于构建镜像的服务器的ip) + + * 修改为基于debian bullseye构建 + + * 取消指定版本 + + * 修复MBR磁盘镜像未设置启动标志的bug + + * 取消在docker中安装grub + + * 安装grub的过程改到客户机上进行 + + * bootstrap.sh 添加--no-docker + + * 使用新版的docker编译镜像 + + * 修补, 添加了一些关于gcc的check + + Co-authored-by: longjin + +commit ba0d93d8b26034abc54bcaf3f0ff04863bbd076e +Author: Gou Ngai <94795048+AlbertSanoe@users.noreply.github.com> +Date: Mon Dec 19 15:04:37 2022 +0800 + + refactor rtc module in rust (#118) + + * 用rust重构rtc模块 + + * refactor the rtc module by rust + + * rtc-updated + + * rtc-updated-4 + + * rtc + +commit c588d6f77f4b38939701b946228218ea81a7c8dc +Author: login +Date: Mon Dec 19 15:03:44 2022 +0800 + + Patch add abort func (#120) + + * 对于除了sigkill以外的信号,也加入队列 + + * bugfix:libc中,注册信号处理函数时,总是注册sigkill的问题 + + * 增加getpid系统调用 + + * 增加了raise、kill、abort + +commit 47f0d12a1f1a1aa11be8e751ecdbf76f0cb596d9 +Author: YJwu2023 <119829947+YJwu2023@users.noreply.github.com> +Date: Mon Dec 19 14:53:51 2022 +0800 + + 修复docker安装时异常退出的bug (#119) + + * 修复docker安装时异常退出的bug + + * 修复grub编译脚本的小bug + +commit 978043e47d1143ca2d5cf22b20793f032e8eb5a5 +Author: login +Date: Sun Dec 18 15:09:15 2022 +0800 + + 修复当系统中不存在dosfstools时,无法正确格式化磁盘镜像的问题 (#117) + + * 修复当系统中不存在dosfstools时,无法正确格式化磁盘镜像的问题 + +commit f9127772dc372a2e607388fdd6818d3f9c4c6d28 +Author: YJwu2023 <119829947+YJwu2023@users.noreply.github.com> +Date: Sat Dec 17 23:43:23 2022 +0800 + + 修复docker安装时异常退出的bug (#116) + +``` diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.4.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.4.md new file mode 100644 index 00000000..a5b1bfea --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.4.md @@ -0,0 +1,279 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.4.md + +- Translation time: 2025-05-19 01:42:41 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.4 + +:::{note} +Author: Longjin + +February 4, 2023 +::: + +## Contributors List + +The DragonOS V0.1.4 version was contributed by the following developers: + +- Longjin +- Gou Ngai +- Kong Weichao +- Hou Jiaying + +## Sponsors List + +Thank you to the following individuals for their support. We will continue to strive for excellence! + +- David Wen (2000 RMB) +- [Seele.Clover](https://github.com/seeleclover) (500 RMB) +- Ye Jinyi (100 RMB) +- Lin (50 RMB) +- Albert (9.99 RMB) +- TerryLeeSCUT (6.66 RMB) +- slientbard (6.66 RMB) +- Wu (2.00 RMB) +- [Other anonymous contributors] (1.00 RMB) + +## Update Content - Kernel + +- Spinlock: new: Added SpinLock with guards, supporting compile-time checking of lock usage. (#_translated_label__148_en) +- Spinlock: feature: Added lock_irqsave and unlock_irqrestore for raw spin lock (#_translated_label__151_en) +- Mutex: new: Rust version of Mutex (#_translated_label__157_en) +- doc: new: Rust code style document (#_translated_label__161_en) +- WaitQueue: new: Rust version of WaitQueue (#_translated_label__162_en) +- WaitQueue: update: For the C version of wait_queue, changed to immediate wake-up (#_translated_label__158_en) +- block io: new: Block IO scheduler. When there are multiple cores, the IO scheduler runs on core 1. (#_translated_label__158_en) +- smp: bugfix: Start apic_timer for AP cores, making them able to run scheduling (#_translated_label__158_en) +- smp: new: Added kick_cpu function, supporting making a specific core run the scheduler immediately (#_translated_label__158_en) +- smp: new: Added process migration functionality between cores (#_translated_label__158_en) +- scheduler: new: Added real-time process scheduler (supporting FIFO and RR strategies) (#_translated_label__139_en) +- scheduler: update: CFS scheduler sets a separate IDLE process pcb (pid is 0) for each core (#_translated_label__158_en) +- scheduler: bugfix: When process_wakeup, reset the virtual runtime for CFS processes. Solves the problem of other processes starving due to small virtual runtime of sleeping processes. (#_translated_label__158_en) +- process: new: Added migrate_to field in pcb (#_translated_label__158_en) + +## Update Content - User Environment + +None + +## Update Content - Others + +None + +## Update Content - Software Porting + +None + +## Source Code and Release Image Download + +  You can obtain the source code through the following methods: + +### Get via Git + +- You can visit [https://github.com/fslongjin/DragonOS/releases](https://github.com/fslongjin/DragonOS/releases) to download the release code, as well as the compiled and runnable disk image. +- We also have a mirror repository on gitee for download: [https://gitee.com/DragonOS/DragonOS](https://gitee.com/DragonOS/DragonOS) + +### Get via DragonOS Software Mirror Site + +  To solve the problem of slow and unstable access to GitHub in China, and to make it convenient for developers to download the code of each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can get the DragonOS code package and the compiled and runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org](https://mirrors.DragonOS.org) +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) +- Domestic mirror acceleration: [https://mirrors.ringotek.cn/](https://mirrors.ringotek.cn/) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the DragonOS source code and corresponding software products (including but not limited to binary copies and documents) will enjoy the rights granted by us through the GPLv2 license, and you must also comply with the obligations stipulated in the agreement. + +This is a rather strict license that protects the healthy development of open source software and prevents it from being encroached upon. + +For most well-intentioned people, you will not violate our open source license. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe on the legitimate rights and interests of others and do not violate the GPLv2 license. + +Please pay special attention to the fact that violations of the open source license, especially **commercial closed-source use and any acts of plagiarism or academic misconduct**, will be subject to serious accountability. (This is the easiest scenario to violate our open source license.) + +Also, please note that according to the requirements of the GPLv2 license, any software modified or developed based on DragonOS must also be open-sourced under the GPLv2 license and must clearly indicate that it is based on DragonOS. It must also ensure that users of these modified versions can conveniently obtain the original version of DragonOS. + +You must make it possible for the DragonOS developers to obtain the source code of your modified version through public channels in the same way, otherwise you will violate the GPLv2 license. + +For detailed information about the license, please read the **LICENSE** file in the root directory of the project. Please note that according to the GPLv2 license, **only the English original version is legally binding**. Any translated version is for reference only. +::: + +### Open Source Software Usage + +  During the development of DragonOS, we have referenced the design of some open source projects, or introduced parts of their code, or been inspired by them. Below is a list of these open source projects. We sincerely thank the contributors of these open source projects! + +Format: - - + +- Linux - https://git.kernel.org/ - GPLv2 +- skiftOS - https://github.com/skiftOS/skift - MIT +- FYSOS - https://github.com/fysnet/FYSOS - [FYSOS' License](https://github.com/fysnet/FYSOS/blob/9a8968e3d6600de34539c028c843f4c06d134039/license.txt) +- LemonOS - https://github.com/LemonOSProject/LemonOS.git - BSD 2-Clause License +- LZ4 - https://github.com/lz4/lz4 - BSD 2-Clause license +- SerenityOS - https://github.com/SerenityOS/serenity.git - BSD 2-Clause license +- MINE - "A Design and Implementation of a 64-bit Operating System" by Tian Yu; People's Posts and Telecommunications Press +- chcore - "Modern Operating Systems: Design and Implementation" by Chen Haibo, Xia Yubin; Machinery Industry Press +- SimpleKernel - https://github.com/Simple-XX/SimpleKernel - MIT +- rcore-fs - https://github.com/rcore-os/rcore-fs.git - MIT + +## All Commit Records of the Current Version + +```text +commit f6ba114bb0420e848ef7fc844c96c0d7a0552d93 +Author: houmkh <100781004+houmkh@users.noreply.github.com> +Date: Sat Feb 4 12:31:15 2023 +0800 + + Block IO Scheduler (#158) + + * Block io调度器 + * process_wakeup时,对cfs的进程,重设虚拟运行时间。解决由于休眠的进程,其虚拟运行时间过小,导致其他进程饥饿的问题 + + * 1、为AP核启动apic_timer,使其能够运行调度 + 2、增加kick_cpu功能,支持让某个特定核心立即运行调度器 + 3、wait_queue的唤醒,改为立即唤醒。 + 4、增加进程在核心间迁移的功能 + 5、CFS调度器为每个核心设置单独的IDLE进程pcb(pid均为0) + 6、pcb中增加migrate_to字段 + 7、当具有多核时,io调度器在核心1上运行。 + + * io调度器文件位置修改 + + * 修改io的makefile + + * 更新makefile中的变量名 + + * 修改io调度器函数名 + + --------- + + Co-authored-by: login + +commit 151251b50b7ed55596edd32ffec49a4041010e2a +Author: login +Date: Tue Jan 31 19:27:02 2023 +0800 + + Patch add rust waitqueue (#162) + + * new: rust版本的waitqueue + + * new:等待队列的文档 + +commit 3c369b1430e8d571bcc74a8ef7fefc1c4cae5dd2 +Author: login +Date: Mon Jan 30 15:43:42 2023 +0800 + + new:新增rust代码风格 (#161) + +commit c28bd540ac856cd9d8d5597852af8f2588a660e4 +Author: login +Date: Mon Jan 30 15:10:24 2023 +0800 + + 更新赞助者名单 (#160) + + * 更新赞赏者列表 + +commit 935f40ec174fec217aed4553d45996327443bc0e +Author: login +Date: Tue Jan 17 21:30:16 2023 +0800 + + new: Rust版本的Mutex (#157) + +commit d8a064128a8a06b90ff4c7b87c193518d9572641 +Author: Gou Ngai <94795048+AlbertSanoe@users.noreply.github.com> +Date: Mon Jan 16 19:58:50 2023 +0800 + + Raw spin lock 增加lock_irqsave、unlock_irqrestore(#151) + + Raw spin lock 增加lock_irqsave、unlock_irqrestore + +commit 06b09f34ed64a006a80ae8df383e3c8b176f02e0 +Author: kong <45937622+kkkkkong@users.noreply.github.com> +Date: Sat Jan 14 22:38:05 2023 +0800 + + Patch sched rust (#139) + + * update + + * 添加rt调度器的rust初步实现 + + * 完善rt调度逻辑 + + * 调试rt调度器 + + * 修改sched的返回值 + + * cargo fmt 格式化 + + * 删除无用代码,修补rt bug + + * 删除无用的代码,和重复的逻辑 + + * 软中断bugfix + + * 删除一些代码 + + * 添加kthread_run_rt文档 + + * 解决sphinix警告_static目录不存在的问题 + + Co-authored-by: longjin + +commit ec53d23ed03347854189d92b7e175f309779321b +Author: login +Date: Sat Jan 14 10:35:49 2023 +0800 + + new: 新增具有守卫的自旋锁SpinLock,支持编译期对锁的使用进行检查。 (#148) + +commit 41474ba3df99b6822ce452dc94dc53a4da62cba1 +Author: login +Date: Tue Jan 10 22:07:41 2023 +0800 + + 更新Readme中关于DragonOS的介绍部分 (#146) + +commit 8ad2e358fd3b05eed2919de50640682e51687fb5 +Author: login +Date: Sun Jan 8 15:51:59 2023 +0800 + + 更新about app中的版本号 (#145) + + * 更新about app中的版本号 + +commit a8b621c8d1fe77251b8e4eafe258dc0ee7366dd5 +Author: login +Date: Sun Jan 8 15:47:44 2023 +0800 + + 修正由于libc中具有crti.S和crtn.S,造成的与x86_64-elf-gcc不兼容的问题 (#144) + +commit 9358ff0f6f7daa18d6fab4497de025736b3d6725 +Author: login +Date: Sun Jan 8 15:06:52 2023 +0800 + + Add v0.1.3 changelog (#143) + + * new: 0.1.3发行日志 + + * 新增输出指定时间范围内的贡献者名单的脚本 + + * 更新bootloader文档 + + * update: 简介文档 + + * new: 镜像站文档 + + * update: 功能特性文档 + + +``` diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.5.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.5.md new file mode 100644 index 00000000..e5ffb3f7 --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.5.md @@ -0,0 +1,321 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.5.md + +- Translation time: 2025-05-19 01:44:14 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.5 + +:::{note} +Author: Longjin + +March 13, 2023 +::: + +## Contributors List + +The DragonOS V0.1.5 version is contributed by the following developers: + +- Longjin +- Guan Jinquan +- Su Jintao +- Kong Weichao +- Hou Jiaying +- Wu Yujian +- Zhou Yuzhe +- Satin Wuker <74630829+SatinWuker@users.noreply.github.com> + +## Sponsors List + +Thank you to the following contributors for their support. We will keep working hard! + +- Wan Xiaolan +- David Wen +- [Seele.Clover](https://github.com/seeleclover) +- [FindWangHao](https://github.com/FindWangHao) +- Ye Jinyi +- Lin +- Albert +- [TerryLeeSCUT · GitHub](https://github.com/TerryLeeSCUT) +- slientbard +- Wu + +## Update Content - Kernel + +- scheduler: doc: Real-time process scheduler documentation (#_translated_label__163_en) +- scheduler: rt: RTQueue now uses a doubly linked list for storage (#_translated_label__174_en) +- scheduler: load balance: Multi-core load balancing (#_translated_label__193_en) +- Semaphore: new: Added a Rust implementation of the semaphore (#_translated_label__183_en) +- mm: refactor: Refactored the MMIO address allocator (#_translated_label__184_en) +- RwLock: new: Added a Rust implementation of the read-write lock (#_translated_label__186_en) +- driver: update: Improved PCI functionality (#_translated_label__194_en) +- driver: new: VirtIO network card driver (still has issues) (#_translated_label__194_en) +- driver: refactor: Rust version of the AHCI driver (#_translated_label__198_en) +- block io: delete: Removed the Block IO scheduler. (#_translated_label__196_en) +- filesystem: refactor: New version of VFS (#_translated_label__198_en) +- filesystem: refactor: New version of ProcFS (#_translated_label__198_en) +- filesystem: refactor: New version of DevS (#_translated_label__198_en) +- filesystem: new: RamFS memory file system (#_translated_label__198_en) +- filesystem: new: FAT12/FAT16/FAT32 file system (#_translated_label__198_en) +- filesystem: new: New device and block device abstraction (#_translated_label__198_en) + +## Update Content - User Environment + +- libc: Adjusted, all apps are now directly linked to libc.a, instead of going through the "search.o" process (#_translated_label__171_en) + +## Update Content - Others + +- bootstrap: Fixed the issue with Ubuntu2210 not being able to compile GRUB correctly, and properly install QEMU (#_translated_label__176_en) +- toolchain: Added a Rust bare bone toolchain (#_translated_label__197_en) + +## Update Content - Software Porting + +None + +## Source Code and Release Image Download + +  You can obtain the source code through the following methods: + +### Get via Git + +- You can download the release code and the compiled, runnable disk image by visiting [https://github.com/DragonOS-Community/DragonOS/releases](https://github.com/DragonOS-Community/DragonOS/releases). +- We also have a mirror repository on Gitee for download: [https://gitee.com/DragonOS/DragonOS](https://gitee.com/DragonOS/DragonOS) + +### Get via DragonOS Software Mirror Site + +  To address the slow and unstable access to GitHub in China, and to make it easier for developers to download the code for each version of DragonOS, we have specifically set up a mirror site. You can access the mirror site through the following address: + +  You can obtain the DragonOS source code archive and the compiled, runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org](https://mirrors.DragonOS.org) +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) +- Domestic mirror acceleration: [https://mirrors.ringotek.cn/](https://mirrors.ringotek.cn/) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the DragonOS source code and related software products (including but not limited to binary copies and documentation) is entitled to the rights granted by us through the GPLv2 license, and you must also comply with the obligations stipulated in the agreement. + +This is a rather strict license that protects the healthy development of open-source software and prevents it from being encroached upon. + +For most well-intentioned people, you will not violate our open-source license. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe on the legitimate rights and interests of others or violate the GPLv2 license. + +Please pay special attention to the fact that violations of the open-source license, especially **commercial closed-source usage and any acts of plagiarism or academic misconduct**, will be subject to serious accountability. (This is the most common scenario where the open-source license is violated.) + +Also, please note that according to the requirements of the GPLv2 license, any software that is modified or developed based on DragonOS must also be open-sourced under the GPLv2 license and must clearly indicate that it is based on DragonOS. It is also necessary to ensure that users of these modified versions can easily obtain the original version of DragonOS. + +You must make it possible for the DragonOS developers to obtain the source code of your modified version through public channels, otherwise you will violate the GPLv2 license. + +For detailed information about the license, please read the **LICENSE** file in the root directory of the project. Please note that according to the requirements of the GPLv2 license, **only the English original version has legal effect**. Any translated versions are for reference only. +::: + +### Usage of Open Source Software + +  During the development of DragonOS, some open-source projects were referenced, or parts of their code were introduced, or they inspired us. Below is a list of these open-source projects. We sincerely thank the contributors of these open-source projects! + +Format: - - + +- Linux - https://git.kernel.org/ - GPLv2 +- skiftOS - https://github.com/skiftOS/skift - MIT +- FYSOS - https://github.com/fysnet/FYSOS - [FYSOS' License](https://github.com/fysnet/FYSOS/blob/9a8968e3d6600de34539c028c843f4c06d134039/license.txt) +- LemonOS - https://github.com/LemonOSProject/LemonOS.git - BSD 2-Clause License +- LZ4 - https://github.com/lz4/lz4 - BSD 2-Clause license +- SerenityOS - https://github.com/SerenityOS/serenity.git - BSD 2-Clause license +- MINE - 《A Design and Implementation of a 64-bit Operating System》 by Tian Yu; People's Posts and Telecommunications Press +- chcore - 《Modern Operating Systems: Design and Implementation》 by Chen Haibo, Xia Yubin; Machinery Industry Press +- SimpleKernel - https://github.com/Simple-XX/SimpleKernel - MIT +- rcore-fs - https://github.com/rcore-os/rcore-fs.git - MIT +- redox - https://gitlab.redox-os.org/redox-os/redox - MIT + +## All Commit Records of the Current Version + +```text +commit 84407d360511c7699938a0f245ae33ff76f16b17 +Author: login +Date: Mon Mar 13 00:26:04 2023 +0800 + + bugfix:解决touch命令失败的问题 (#199) + + * bug fix : 解决touch命令失败的问题 + +commit 004e86ff19727df303c23b42c7a271b9214c6898 +Author: login +Date: Sun Mar 12 22:36:11 2023 +0800 + + 新版文件系统重构完成 (#198) + + 1.重构:VFS + 2. 重构:ProcFS + 3. 重构:DevFS + 4. 重构:FAT32 + 5. 重构:AHCI驱动 + 6. 新增:RamFS + 7. 新增:MountFS + 8. 新增:FAT12 + 9. 新增:FAT16 + 10. 重构:设备抽象 + + Co-authored-by: guanjinquan <1666320330@qq.com> + Co-authored-by: DaJiYuQia <88259094+DaJiYuQia@users.noreply.github.com> + +commit 17041e0e307eaf9e8d8ddbddfa186cd1f10f1bc0 +Author: login +Date: Sun Mar 12 21:04:37 2023 +0800 + + 添加rust的bare bone工具链 (#197) + +commit 26d84a31393c50063ff416bc509316e8d342028c +Author: YJwu2023 <119829947+YJwu2023@users.noreply.github.com> +Date: Sat Mar 11 21:09:50 2023 +0800 + + 新增VirtIO网卡驱动 (#194) + + * 修复内存bug与grub安装脚本的错误 + + * 修改小bug + + * PCI增加功能与virtio-net驱动 + + * little fix + + * virtio-net小修改 + +commit 1d48996375149279a721777b2c600e1b5c3ee1b5 +Author: kong <45937622+kkkkkong@users.noreply.github.com> +Date: Sat Mar 11 18:17:35 2023 +0800 + + 多核负载均衡(#193) + + * feat(sched):CPU负载检测初步实现 + + * fix(smp):调整smp中的apic的头文件声明 + + * fix(smp):简单的负载均衡算法实现 + + * fix(sched):抽离负载均衡方法 + + * fix(sched):修改rt中的运行队列bug,调整负载均衡逻辑 + + * fix(process):移除无用测试代码 + + * reformat code + +commit ef9f9732b09f78d7192f1d0dd3b41be655fb0914 +Author: houmkh <100781004+houmkh@users.noreply.github.com> +Date: Thu Mar 9 23:31:25 2023 +0800 + + 修复了mmio buddy的bug (#189) + + * 修改buddy_query + +commit c1396d277115b371d09ad6d39a1c419f9224ffd0 +Author: Gou Ngai +Date: Mon Mar 6 11:28:32 2023 +0800 + + Rwlock文档 (#186) + + * Rwlock文档 + +commit a7eb62a47a8d701b90a14f83cc9028cfed07c268 +Author: houmkh <100781004+houmkh@users.noreply.github.com> +Date: Mon Mar 6 11:21:29 2023 +0800 + + 修改mmio-buddy代码结构和函数名 (#184) + + * 修改mmio-buddy结构和函数名 + +commit c2481452f81750ec02adec627ab2edbc93d9cd9c +Author: houmkh <100781004+houmkh@users.noreply.github.com> +Date: Sat Mar 4 18:36:55 2023 +0800 + + rust重构mmio_buddy和mmio (#178) + + * rust重构mmio_buddy和mmio + + * mmio-buddy文档 + + --------- + + Co-authored-by: longjin + +commit f1284c35717a2f9f8cee7cecfc835ba1d23a1161 +Author: Gou Ngai +Date: Sat Mar 4 17:47:17 2023 +0800 + + 新增了rust实现的信号量 (#181) + + * 新增了rust实现的信号量 + + --------- + + Co-authored-by: longjin + +commit 83b9512c1c1e8289000084adcafddebee6a23f16 +Author: Gou Ngai +Date: Sat Mar 4 16:54:42 2023 +0800 + + 新增了rust实现的信号量 (#183) + + * 新增了rust实现的信号量 + +commit e532a536a0b244f4590e6eb7910084bd63049704 +Author: login +Date: Thu Mar 2 22:50:07 2023 +0800 + + 添加赞助者:FengWangHao (#179) + +commit b66beefd4e9ead61ee55f335246ebeb8277d3011 +Author: login +Date: Mon Feb 27 01:00:35 2023 +0800 + + 解决ubuntu2210版本无法正确编译grub,以及正确安装qemu的问题 (#176) + +commit 4177d0327c3eacdc606f0b22f99f208fd48cfff3 +Author: kong <45937622+kkkkkong@users.noreply.github.com> +Date: Mon Feb 20 17:03:37 2023 +0800 + + RTQueue改用双向链表存储(#174) + + * RTQueue改用双向链表存储 + +commit 2bf5ee0e3cac3a91dee6a13b71c86a9477c07d9b +Author: login +Date: Sat Feb 11 13:04:24 2023 +0800 + + 修改libc的编译相关内容(#171) + + 1.将libc的include文件夹分为export和internal + 2.将所有app都直接链接libc.a,而不是都执行一遍"搜索.o"的过程 + +commit 90b077f9d3ecd48ca46f8bbb32363620db6ddbe6 +Author: kong <45937622+kkkkkong@users.noreply.github.com> +Date: Thu Feb 9 15:24:37 2023 +0800 + + Sched rt doc (#163) + + * update + + * 完善调度器文档 + + * 更新RT调度器文档 + + * 更新实时调度文档 + +commit 009f92d50fe2e52e425bce397801d3fa204daecd +Author: Satin Wuker <74630829+SatinWuker@users.noreply.github.com> +Date: Tue Feb 7 19:29:09 2023 -0800 + + fix typos 改正README_EN的错别字和语法错误 (#167) + +``` diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.6.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.6.md new file mode 100644 index 00000000..47c7a09b --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.6.md @@ -0,0 +1,319 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.6.md + +- Translation time: 2025-05-19 01:44:51 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.6 + +:::{note} +Author: Longjin + +April 2, 2023 +::: + +## Contributors List + +The DragonOS V0.1.6 version was contributed by the following developers: + +- Longjin +- Guan Jinquan +- Su Jintao +- Hou Jiaying +- Wu Yujian +- Mork <91721145+MorkCarpenter@users.noreply.github.com> +- WaferJay <17383312+WaferJay@users.noreply.github.com> +- HoshuChiu <129569557+HoshuChiu@users.noreply.github.com> + +## Sponsors List + +Thank you to the following individuals for their support. We will continue to strive for excellence! + +- Wan Xiaolan +- David Wen +- [Seele.Clover](https://github.com/seeleclover) +- [FindWangHao](https://github.com/FindWangHao) +- Ye Jinyi +- Lin +- Albert +- [TerryLeeSCUT · GitHub](https://github.com/TerryLeeSCUT) +- slientbard +- Wu +- Anonymous Kind-hearted Person + +## Update Content - Kernel + +- softirq: Refactored softirq (#_translated_label__223_en) +- timer: Refactored system timer (#_translated_label__223_en) +- stdio: Added tty device for standard input and output (#_translated_label__202_en) (#_translated_label__217_en) +- lib: First set of keyboard scan code state machine (#_translated_label__216_en) (#_translated_label__219_en) +- syscall: Added dup and dup2 system calls (#_translated_label__224_en) +- syscall: Added SystemError enum type to make error handling clearer (#_translated_label__205_en) +- driver: Added support for x87 floating-point processor (#_translated_label__212_en) +- driver: VirtIO network card can now send and receive data normally (#_translated_label__204_en) +- filesystem: Fixed FAT32 judgment logic, resolving the issue where the system could not boot normally when the file system was FAT12/16. (#_translated_label__211_en) +- filesystem: Added VFS document and modified document configuration (#_translated_label__209_en) +- textui: Fixed the issue where the process scheduler did not run when "processes output characters continuously" due to textui locking and changes in preempt_count. (#_translated_label__203_en) +- scheduler: Solved the issue of double locking in cpu_queue caused by not disabling interrupts during sched_enqueue outside of interrupt context. (#_translated_label__201_en) + +## Update Content - User Environment + +### New Repositories + +- Added a sub-project: [dsc](https://github.com/DragonOS-Community/dsc.git) +- Transplanted relic: [DragonOS-relibc](https://github.com/DragonOS-Community/relibc.git) + +## Update Content - Others + +- build: Added an option for using VNC as the image output for QEMU (#_translated_label__222_en) + +## Update Content - Software Porting + +None + +## Source Code and Release Image Download + +  You can obtain the source code through the following methods: + +### Get via Git + +- You can download the release code and the compiled, runnable disk image from [https://github.com/DragonOS-Community/DragonOS/releases](https://github.com/DragonOS-Community/DragonOS/releases). +- We also have a mirror repository on gitee for download: [https://gitee.com/DragonOS/DragonOS](https://gitee.com/DragonOS/DragonOS) + +### Get via DragonOS Software Mirror Site + +  To address the slow and unstable access to GitHub in China, and to make it convenient for developers to download the code for each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can obtain the DragonOS source code archive and the compiled, runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org](https://mirrors.DragonOS.org) +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) +- Domestic mirror acceleration: [https://mirrors.ringotek.cn/](https://mirrors.ringotek.cn/) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the DragonOS source code and corresponding software products (including but not limited to binary copies and documentation) can enjoy the rights granted by us through the GPLv2 protocol, while you also need to comply with the obligations stipulated in the protocol. + +This is a rather strict protocol that protects the healthy development of open source software and prevents it from being encroached upon. + +For most well-intentioned people, you will not violate our open source license. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe on the legitimate rights and interests of others or violate the GPLv2 protocol. + +Please pay special attention to the fact that violations of the open source license, especially **commercial closed-source usage and any acts of plagiarism or academic misconduct**, will be subject to serious accountability. (This is the most common scenario of violating our open source license.) + +Also, please note that according to the requirements of the GPLv2 protocol, any software modified or developed based on DragonOS must also be open-sourced under the GPLv2 protocol and must indicate that it is based on DragonOS. It is also necessary to ensure that users of these modified versions can easily access the original version of DragonOS. + +You must make sure that the DragonOS developers can obtain the source code of your modified version through public channels in the same way, otherwise you will violate the GPLv2 protocol. + +For detailed information about the protocol, please read the **LICENSE** file in the root directory of the project. Please note that according to the requirements of the GPLv2 protocol, **only the English original version has legal effect**. Any translated version is for reference only. +::: + +### Usage of Open Source Software + +  During the development of DragonOS, some open source projects were referenced, or parts of their code were introduced, or they inspired us. The following list shows them. We sincerely thank the contributors of these open source projects! + +Format: - - + +- Linux - https://git.kernel.org/ - GPLv2 +- skiftOS - https://github.com/skiftOS/skift - MIT +- FYSOS - https://github.com/fysnet/FYSOS - [FYSOS' License](https://github.com/fysnet/FYSOS/blob/9a8968e3d6600de34539c028c843f4c06d134039/license.txt) +- LemonOS - https://github.com/LemonOSProject/LemonOS.git - BSD 2-Clause License +- LZ4 - https://github.com/lz4/lz4 - BSD 2-Clause license +- SerenityOS - https://github.com/SerenityOS/serenity.git - BSD 2-Clause license +- MINE - "Design and Implementation of a 64-bit Operating System" by Tian Yu; People's Posts and Telecommunications Press +- chcore - "Modern Operating Systems: Design and Implementation" by Chen Haibo and Xia Yubin; Machinery Industry Press +- SimpleKernel - https://github.com/Simple-XX/SimpleKernel - MIT +- rcore-fs - https://github.com/rcore-os/rcore-fs.git - MIT +- redox - https://gitlab.redox-os.org/redox-os/redox - MIT + +## All Commit Records of the Current Version + +```text +commit bacd691c9ef0502b5cc618aad50517f9e59df5e0 +Author: login +Date: Sun Apr 2 17:09:33 2023 +0800 + + 软中断&定时器重构 (#223) + + * 软中断&定时器重构 + + Co-authored-by: houmkh + + * 修改timer的clock() + + * 删除debug信息 + + --------- + + Co-authored-by: houmkh <1119644616@qq.com> + +commit 6d345b774223b0daaf0ee629c7fb595a1912a9e2 +Author: HoshuChiu <129569557+HoshuChiu@users.noreply.github.com> +Date: Sun Apr 2 15:55:24 2023 +0800 + + 添加了qemu使用VNC作为图像输出的选项 (#222) + + * 添加了qemu使用VNC作为图像输出的选项 + + * 设置vnc端口为5900 + + --------- + + Co-authored-by: longjin + +commit 2b771e32f5795e0fdda458e3bb2651ef6b9673ac +Author: Gou Ngai +Date: Sun Apr 2 15:43:53 2023 +0800 + + Add dup,dup2 (#224) + + * dup,dup2 + + * fix: sys_dup2语义与posix不一致的问题 + + --------- + + Co-authored-by: longjin + +commit d7b31a969ff091224a4929496f0278d024f78c77 +Author: Gou Ngai +Date: Fri Mar 31 18:23:58 2023 +0800 + + Patch keyboard capslock alt (#219) + + * keyboard-alt-capslock + + * 解决键盘输入'%'字符的时候无法回显的bug + + --------- + + Co-authored-by: longjin + +commit 20e3152e1eea97f87d644c3023391e172bc83c93 +Author: login +Date: Fri Mar 31 12:54:37 2023 +0800 + + 将TTY与stdio进行连接,实现基本的stdio功能 (#217) + + * 将stdio与tty接上 + +commit 5fb12ce447710edf8566f250655a06cb27519fca +Author: Gou Ngai +Date: Thu Mar 30 18:19:02 2023 +0800 + + 第一套键盘扫描码的状态机 (#216) + + 第一套键盘扫描码的状态机 + --------- + + Co-authored-by: guanjinquan <1666320330@qq.com> + Co-authored-by: longjin + +commit 676b8ef62e1a0a1e52d65b40c53c1636a2954040 +Author: Mork <91721145+MorkCarpenter@users.noreply.github.com> +Date: Wed Mar 29 21:24:11 2023 +0800 + + 部分函数从返回值为Result<<>,i32>修改为Result<<>,SystemError> (#210) + + * 将Result<<>,i32>替换为Result<<>,SystemError> + * bugfix: 显示双缓冲区初始化的时候,连续注册了两次Video Softirq的问题。 + + Co-authored-by: longjin + +commit 64aea4b3494bee7375e1c1ee5739c9fab0db0cb7 +Author: Gou Ngai +Date: Tue Mar 28 20:44:26 2023 +0800 + + 增加x87FPU支持 (#212) + + * remove `ret_from_syscall` + *修复ps2键盘驱动程序inode在进程fork的时候导致死锁的问题. + *更新: VFS每次拷贝文件描述符的时候,都会去调用inode的open函数 + + --------- + + Co-authored-by: longjin + +commit 2286eda6526ed1b46afd79b47dc701034b9e903d +Author: WaferJay <17383312+WaferJay@users.noreply.github.com> +Date: Mon Mar 27 09:32:43 2023 +0800 + + 修正了FAT32判断逻辑,解决了文件系统为FAT12/16时系统无法正常启动的问题。 (#211) + + * fix(fat): fix determination of fat type casue crash if fs is fat12/16 + + * refactor(fat): split BiosParameterBlock.validate() into BiosParameterBlockFAT32.validate() and BiosParameterBlockLegacy.validate() + + * 调整“最大允许的簇号”的常量放置的位置。 + + --------- + + Co-authored-by: longjin + +commit 45b8371173b070028457f7ee64be33f68b4f9ada +Author: login +Date: Sat Mar 25 14:51:16 2023 +0800 + + 新增VFS文档,以及修改文档配置 (#209) + + * 1.新增vfs设计文档 + 2.修改文档版权标志为"2022-2023, DragonOS Community" + 3.修改电脑版文档页面的宽度为90% + + * layout.html末尾加空行 + +commit 73c607aaddf6e4634cad179a81d3f1bc589f7220 +Author: YJwu2023 <119829947+YJwu2023@users.noreply.github.com> +Date: Sat Mar 18 20:43:37 2023 +0800 + + VirtIO网卡能够正常发送、接收数据 (#204) + + * virtio-net小修改 + + * 移动volatile.rs到libs文件夹 + + * 使用virtio-drivers 0.3.0 + + * bugfix: 初始化BAR之后,未正确设置command register的问题 + + + --------- + + Co-authored-by: longjin + +commit 4454d1a2dd1f1078750151c028a794cfd9a04a1b +Author: login +Date: Sat Mar 18 20:26:05 2023 +0800 + + 新增SystemError枚举类型,使得错误处理更清晰 (#205) + +commit 0d48c3c9c21a2dd470d0e1e58b507db60e0887bb +Author: login +Date: Thu Mar 16 19:48:59 2023 +0800 + + new: tty设备(尚未与stdio接上) (#202) + +commit 790d45764090bce3bbfb96b42b2818100a8cef9a +Author: login +Date: Wed Mar 15 11:42:41 2023 +0800 + + 修复由于textui加锁,更改了preempt_count导致“进程长时间连续输出字符”的情况下,进程调度器不运行的问题。 (#203) + +commit c2e757d8cbeed01b16f48bea48ed8447685e6f1a +Author: login +Date: Mon Mar 13 22:22:23 2023 +0800 + + 解决由于在中断上下文以外,sched_enqueue时,未关中断导致cpu_queue双重加锁的问题 (#201) + +``` diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.7.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.7.md new file mode 100644 index 00000000..eb3af81c --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.7.md @@ -0,0 +1,359 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.7.md + +- Translation time: 2025-05-19 01:43:50 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.7 + +:::{note} +Author: Longjin + +April 24, 2023 +::: + +## Contributors List + +The DragonOS V0.1.7 version was contributed by the following contributors: + +- Longjin +- Guan Jinquan +- Huang Ting +- Hou Jiaying +- Wu Yujian +- Su Jintao +- Zhou Hanjie +- HoshuChiu <129569557+HoshuChiu@users.noreply.github.com> +- Bullet <93781792+GP-Bullet@users.noreply.github.com> + +## Sponsors List + +Thank you to the following individuals for their support. We will continue to work hard! + +- Wan Xiaolan +- David Wen +- [Seele.Clover](https://github.com/seeleclover) +- [FindWangHao](https://github.com/FindWangHao) +- [ferchiel](https://github.com/ferchiel) +- Ye Jinyi +- Lin +- Albert +- [TerryLeeSCUT · GitHub](https://github.com/TerryLeeSCUT) +- slientbard +- Wu +- Anonymous Kind-hearted Person + +## Update Content - Kernel + +- scheduler: Change CFSqueue from Vec to Red-Black Tree (#_translated_label__229_en) +- new: lazy_init (#_translated_label__230_en) (#_translated_label__236_en) +- pci: pci restructure + pcie support (#_translated_label__235_en) +- net: Add network subsystem, and support programming in user space (#_translated_label__237_en) (#_translated_label__247_en) +- mm: Adjust brk system call to make parameters and return values consistent with Linux (#_translated_label__238_en) +- Modify errno to be consistent with relicb (#_translated_label__234_en) +- pci: Fix the issue of not being able to get MCFG table with ecam (#_translated_label__241_en) +- libs: DowncastArc and its docs (#_translated_label__244_en) +- softirq: Add timer and softirq documentation, modify the C-oriented interface of softirq (#_translated_label__245_en) +- spinlock: Fix the issue of forgetting to restore rflags in spinlock (#_translated_label__247_en) +- waitqueue: Add wakeup_all and sleep_without_schedule functions (#_translated_label__247_en)(#_translated_label__253_en) +- filesystem: Change the PollStatus structure to use the bitflags library (#_translated_label__247_en) +- filesystem: Add iovec support (brute-force implementation) (#_translated_label__247_en) +- filesystem: Add SysFS (#_translated_label__250_en) (#_translated_label__254_en) +- driver: Improve device driver model according to sysfs (#_translated_label__254_en) +- pipe: Pipe restructure (#_translated_label__253_en) +- irq: Add IrqArch abstraction and IrqFlagsGuard to simplify the process of disabling and restoring interrupts (#_translated_label__253_en) + +## Update Content - User Environment + +### New Repositories + +- New subproject: [dsc](https://github.com/DragonOS-Community/dsc.git) +- New subproject: [DADK](https://github.com/DragonOS-Community/DADK.git) DragonOS Application Development Kit + +### [DragonOS-relibc](https://github.com/DragonOS-Community/relibc.git) + +- Add sys_dup and sys_dup2 support (#_translated_label__2_en) +- Add the original libc memory allocator, fix alignment issues. (#_translated_label__6_en) (#_translated_label__7_en) +- Configure network-related system calls (#_translated_label__8_en) +- Fix the issue of errno not working properly due to DragonOS not supporting TLS (thread local storage). (#_translated_label__8_en) + +## Update Content - Others + +- build: Fix Issue#220; restore VNC port number to 5900 (#_translated_label__243_en) +- bootstrap: Solve the problem of not being able to directly use the one-click initialization script for installation when using zsh to build DragonOS (#_translated_label__252_en) + +## Update Content - Software Porting + +None + +## Source Code and Release Image Download + +  You can obtain the source code through the following ways: + +### Get via Git + +- You can visit [https://github.com/DragonOS-Community/DragonOS/releases](https://github.com/DragonOS-Community/DragonOS/releases) to download the release code and the compiled, runnable disk image. +- We also have a mirror repository on gitee for download: [https://gitee.com/DragonOS/DragonOS](https://gitee.com/DragonOS/DragonOS) + +### Get via DragonOS Software Mirror Site + +  To solve the problem of slow and unstable access to GitHub in China, and to make it convenient for developers to download the code of each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can get the compressed package of DragonOS code and the compiled, runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org](https://mirrors.DragonOS.org) +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) +- Domestic mirror acceleration: [https://mirrors.ringotek.cn/](https://mirrors.ringotek.cn/) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the source code of DragonOS and the corresponding software products (including but not limited to binary copies and documents) can enjoy the rights granted by us through the GPLv2 license, and you must also comply with the obligations stipulated in the agreement. + +This is a rather strict license that protects the healthy development of open source software and prevents it from being encroached upon. + +For most well-intentioned people, you will not violate our open source license. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe on the legitimate rights and interests of others or violate the GPLv2 license. + +Please pay special attention to the fact that violations of the open source license, especially **commercial closed-source use and any acts of plagiarism or academic misconduct**, will be subject to serious accountability. (This is the most common scenario where the open source license is violated.) + +Also, please note that according to the requirements of the GPLv2 license, any software modified or developed based on DragonOS must also be open-sourced under the GPLv2 license and must indicate that it is based on DragonOS. It is also necessary to ensure that users of these modified versions can easily obtain the original version of DragonOS. + +You must make it possible for the developers of DragonOS to obtain the source code of your modified version through the same way from public channels, otherwise you will violate the GPLv2 license. + +For detailed information about the license, please read the **LICENSE** file in the root directory of the project. Please note that according to the requirements of the GPLv2 license, **only the English original version has legal effect**. Any translated version is for reference only. +::: + +### Usage of Open Source Software + +  During the development of DragonOS, some open source projects' designs were referenced, or parts of their code were introduced, or they were inspired by them. The following list shows them. We sincerely thank the contributors of these open source projects! + +Format: - - + +- Linux - https://git.kernel.org/ - GPLv2 +- skiftOS - https://github.com/skiftOS/skift - MIT +- FYSOS - https://github.com/fysnet/FYSOS - [FYSOS' License](https://github.com/fysnet/FYSOS/blob/9a8968e3d6600de34539c028c843f4c06d134039/license.txt) +- LemonOS - https://github.com/LemonOSProject/LemonOS.git - BSD 2-Clause License +- LZ4 - https://github.com/lz4/lz4 - BSD 2-Clause license +- SerenityOS - https://github.com/SerenityOS/serenity.git - BSD 2-Clause license +- MINE - "A Design and Implementation of a 64-bit Operating System" by Tian Yu; People's Posts and Telecommunications Press +- chcore - "Modern Operating Systems: Design and Implementation" by Chen Haibo, Xia Yubin; Machinery Industry Press +- SimpleKernel - https://github.com/Simple-XX/SimpleKernel - MIT +- rcore-fs - https://github.com/rcore-os/rcore-fs.git - MIT +- redox - https://gitlab.redox-os.org/redox-os/redox - MIT + +## All Commit Records of the Current Version + +```text +commit e0de0fd6a52199753a3127cfbb5d12f0a1555aae +Author: TingHuang <92705854+TingSHub@users.noreply.github.com> +Date: Sun Apr 23 22:55:57 2023 +0800 + + 根据sysfs完善设备驱动模型 & 添加sysfs官方文档 (#254) + + * 根据sysfs完善设备驱动模型 + + * 添加sysfs官方文档 + +commit f678331a3315b7847f08ab32b42d5bf49a9f3a6a +Author: hanjiezhou +Date: Sun Apr 23 21:05:10 2023 +0800 + + 匿名管道重构&增加IrqArch trait以及IrqFlags及其守卫 (#253) + + * 实现匿名管道 + + * 增加IrqArch trait以及IrqFlags及其守卫 + + --------- + + Co-authored-by: longjin + +commit 8a1e95abb5e4df5e872bb452efc26c9e9631157d +Author: Bullet <93781792+GP-Bullet@users.noreply.github.com> +Date: Fri Apr 21 23:36:54 2023 +0800 + + 解决使用zsh在构建DragonOS时,无法直接使用一键初始化脚本进行安装的问题 (#252) + +commit dd9f1fc1a42406461e6f0d38cce1e56e22a1a15f +Author: TingHuang <92705854+TingSHub@users.noreply.github.com> +Date: Fri Apr 21 16:03:42 2023 +0800 + + 新增SysFS (#250) + + * 添加sysfs + + * 注册sysfs + + * 添加sysfs相关 + + * 添加rust-anlyzer辅助配置 + + * 将设备与sysfs相关联 + + * 添加单独的文件管理sysfs下的文件夹 + +commit cde5492f725681ed89abe1e6eb088e05d943d793 +Author: login +Date: Wed Apr 19 18:05:02 2023 +0800 + + 新增网络socket的系统调用接口 (#247) + + 1.修复spinlock忘记恢复rflags的问题 + 2.WaitQueue增加wakeup_all的功能 + 3.完善tcp,udp,raw socket + 4.把PollStatus结构体改为使用bitflags + 5.新增iovec结构体 + 6.完成网络的系统调用 + 7.在bootstrap里面添加dnsmasq bridge-utils iptables + + --------- + + Co-authored-by: guanjinquan <1666320330@qq.com> + +commit 8fd71f277271ae68e648f290c67f187b030feae0 +Author: houmkh <1119644616@qq.com> +Date: Mon Apr 17 17:17:06 2023 +0800 + + 增加定时器和软中断文档,修改了softirq面向c的接口 (#245) + + * 增加定时器和软中断文档 + + * 修改softirq对c的接口和文档 + + * 修改文档格式 + +commit 77c928f6ce3192c79ea42ab7bcba2713e289f73b +Author: login +Date: Sun Apr 16 20:29:04 2023 +0800 + + new: DowncastArc and its docs (#244) + +commit 7149abaa49a4ca70f0e42ad3b61fdfd6a941a092 +Author: HoshuChiu <129569557+HoshuChiu@users.noreply.github.com> +Date: Sun Apr 16 14:47:51 2023 +0800 + + 修复Issue#220;vnc的端口号恢复5900 (#243) + + + * 修复Issue#220 + + * qemu-vnc端口号恢复为5900 + +commit 5c1e552cc7f0a6ad75c8a1fa2928e3b9cc619657 +Author: YJwu2023 +Date: Fri Apr 14 12:21:08 2023 +0800 + + 修复ecam无法获取MCFG table的问题 (#241) + +commit 79a452ce8f27ad9c7283ac0bcf4078ed6fa018d7 +Author: houmkh <1119644616@qq.com> +Date: Tue Apr 11 17:05:33 2023 +0800 + + 修改errno,使其与relibc的保持一致 (#234) + + 修改errno,使其与relibc的保持一致 + +commit ac48398d3f17f24ff9b5da5e400ce912d05f0ba2 +Author: login +Date: Tue Apr 11 16:54:14 2023 +0800 + + 调整brk系统调用,使得参数、返回值与Linux一致 (#238) + + * 新增用于测试relibc的app + + * 为适配relibc,修改do_execve中关于用户栈的内容的设置 + + * 调整brk系统调用,使得参数、返回值与Linux一致 + +commit 13776c114b15c406b1e0aaeeb71812ea6e471d2e +Author: login +Date: Mon Apr 10 20:22:39 2023 +0800 + + 增加对dhcpv4的支持(tcp、udp socket已写好,但由于缺少epoll机制,尚未完整测试) (#237) + + * 为virtio网卡完成smoltcp的phy层配置 + + * raw socket + + * 初步写完udp和tcp socket + + * 能够正常通过dhcp获取ipv4地址(具有全局iface btree) + + --------- + + Co-authored-by: guanjinquan <1666320330@qq.com> + +commit 78bf93f02f84bf5e024ddfb559f040e68ce39ccf +Author: YJwu2023 +Date: Sun Apr 9 12:30:02 2023 +0800 + + pci重构+pcie支持 (#235) + + * pci重构+pcie支持 + + * pci重构测试完成 + + * 修正makefile的问题 + + * 小修改 + + * 修改函数名字 + +commit 5c9a63df836eedaca33c8c4c600b7aaeb2caf9a6 +Author: login +Date: Sat Apr 8 23:53:53 2023 +0800 + + Patch add lazy init (#236) + + * 修正并发安全问题 + +commit 766127209ee49465a8086cfd0bec90d8b79a96c0 +Author: login +Date: Thu Apr 6 19:01:30 2023 +0800 + + new: lazy_init (#230) + +commit e0dfd4d5d70d1b50fc7ad3ed4bf84b7ba6dad19d +Author: hanjiezhou +Date: Thu Apr 6 00:50:14 2023 +0800 + + 修改CFSqueue从Vec变成红黑树 (#229) + + 使用了由tickbh编写的rbtree: https://github.com/tickbh/rbtree-rs/blob/master/src/lib.rs + + Co-authored-by: tickbh + +commit 2a7d773d3d39f1cb3d59d6baa817c896c6fd52d1 +Author: TingHuang <92705854+TingSHub@users.noreply.github.com> +Date: Wed Apr 5 13:02:05 2023 +0800 + + 新增设备驱动模型,为设备和驱动提供高层视图 (#227) + + * 添加base mod + + * 添加设备驱动模型相关文件 + + * 删除单独的mod文件,使用mod.rs,修改一些格式上的问题 + + * 移动驱动错误类型到该文件 + + * 修改一些格式上的问题 + +commit 5d00b1852818dd4b25952fd6a30deb20e7c7df53 +Author: login +Date: Wed Apr 5 00:53:35 2023 +0800 + + 修复显示刷新线程的空指针问题 (#228) + +``` diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.8.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.8.md new file mode 100644 index 00000000..d9e700ce --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.8.md @@ -0,0 +1,570 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.8.md + +- Translation time: 2025-05-19 01:43:47 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.8 + +:::{note} +Author: Long Jin + +August 16, 2023 +::: + +## Contributors + +The DragonOS V0.1.8 version was contributed by the following developers: + +- Long Jin +- Hou Jiaying +- Wu Yujian +- Huang Ting +- Kong Weichao +- Cai Jiaxin +- Chi Kejin +- zhaoyao73 +- Zhou Hanjie +- Bullet <93781792+GP-Bullet@users.noreply.github.com> +- Sakura Momoka <89176634+TihayaKousaka@users.noreply.github.com> +- Tptogiar <2528891112@qq.com> + +## Sponsors + +Thank you to the following contributors for their support. We will continue to work hard! + +- Wan Xiaolan +- David Wen +- [Seele.Clover](https://github.com/seeleclover) +- [FindWangHao](https://github.com/FindWangHao) +- [ferchiel](https://github.com/ferchiel) +- Ye Jinyi +- Lin +- Albert +- [TerryLeeSCUT · GitHub](https://github.com/TerryLeeSCUT) +- slientbard +- Wu +- Anonymous enthusiastic person + +## Update Content - Kernel + +### New Features + +- refactor: Refactor system call module (#_translated_label__267_en) +- feature: Add AlignBox and int_like macros (#_translated_label__272_en) +- refactor: Rewrite new IPI function & kick_cpu function (#_translated_label__274_en) +- feature: Implement gettimeofday() system call and clocksource+timekeeping sub-module (#_translated_label__278_en) +- refactor: Reconstruct PCI device interrupts and remove USB-related code (#_translated_label__285_en) +- feature: Register serial device, create character device framework (#_translated_label__290_en) +- refactor: New memory management module (#_translated_label__303_en) +- feature: New binary loader, elf parser (#_translated_label__303_en) +- feature: Add ListenTable to detect port occupation (#_translated_label__291_en) +- feature: Replace local_irq_save with IrqFlagsGuard implementation (#_translated_label__317_en) +- feature: Implement system call Fstat (#_translated_label__295_en) +- feature: Implement kernel notifier chain (#_translated_label__316_en) +- feature: Add fcntl system call (#_translated_label__323_en) +- feature: Add support for per CPU variables (#_translated_label__327_en) +- feature: Spinlock guard adds leak, spinlock adds force unlock function (#_translated_label__329_en) + +### Bug Fixes + +- bugfix: Fix the issue of not being able to read stdin normally (#_translated_label__264_en) +- bugfix: Fix the memory overflow problem when the buffer address passed to the AHCI driver is a user buffer (temporarily solved by allocating a kernel buffer) (#_translated_label__265_en) +- bugfix: Solve the bug caused by the improper assembly of local_irq_save and local_irq_restore functions affecting stack behavior (#_translated_label__303_en) +- bugfix: Solve the error of local_irq_save not disabling interrupts (#_translated_label__303_en) +- bugfix: Solve the error in arch_try_cmpxchg for pointer handling (#_translated_label__307_en) +- bugfix: Fix the exception error in wait4 (#_translated_label__312_en) +- bugfix: Fix the issue of null device and zero device not being able to open and not behaving as expected (#_translated_label__314_en) +- bugfix: Fix the bug in FAT file system not correctly extending file size (#_translated_label__323_en) +- bugfix: Fix the use after free issue caused by not using ManuallyDrop in some places of rwlock (#_translated_label__329_en) + +## Update Content - User Environment + +### New Features + +- feature: Add new HTTP server (#_translated_label__265_en) + +### Bug Fixes + +- bugfix: Solve the issue of the init segment linking error caused by crt*.o not being sorted in ascending order during linking (#_translated_label__265_en) + +## Update Content - Others + +- bugfix: Fix the toolchain and resolve errors caused by the new Rust compiler (#_translated_label__258_en) +- feature: Makefile: Add make help command in the root directory (#_translated_label__271_en) +- doc: Update GitHub issue template (#_translated_label__277_en) +- bugfix: Fix the issue where the relibc header file could not recognize the __dragonos__ definition (#_translated_label__315_en) +- feature: Set the remote for the kernel and relibc to the DragonOS Git mirror site to prevent compilation failure due to domestic network issues (#_translated_label__318_en) +- feature: Automatic installation and update of dadk (#_translated_label__319_en) + +## Update Content - Software Porting + +- feature: Ported sqlite3 (#_translated_label__323_en) + +## Source Code and Release Mirror Download + +  You can obtain the source code through the following methods: + +### Get via Git + +- You can visit [https://github.com/DragonOS-Community/DragonOS/releases](https://github.com/DragonOS-Community/DragonOS/releases) to download the source code of the release version, as well as the compiled and runnable disk image. +- We also have a mirror repository on Gitee for download: [https://gitee.com/DragonOS/DragonOS](https://gitee.com/DragonOS/DragonOS) + +### Get via DragonOS Software Mirror Site + +  To address the slow and unstable access to GitHub in China, and to make it convenient for developers to download the source code of each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can obtain the source code package and the compiled and runnable disk image of DragonOS through the mirror site. + +- [https://mirrors.DragonOS.org](https://mirrors.DragonOS.org) +- [https://git.mirrors.DragonOS.org](https://git.mirrors.DragonOS.org) +- Domestic mirror acceleration: [https://mirrors.ringotek.cn/](https://mirrors.ringotek.cn/) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the source code of DragonOS and the corresponding software products (including but not limited to binary copies and documentation) will enjoy the rights granted by us through the GPLv2 license, and you must also comply with the obligations stipulated in the license. + +This is a very strict license that protects the healthy development of open source software and prevents it from being infringed. + +For most people with good intentions, you will not violate our open source license. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe on the legitimate rights and interests of others and do not violate the GPLv2 license. + +Please pay special attention to the fact that violations of the open source license, especially **commercial closed-source use and any plagiarism or academic misconduct**, will be subject to serious accountability. (This is the easiest scenario to violate our open source license.) + +Also, please note that according to the requirements of the GPLv2 license, any software modified or developed based on DragonOS must also be open-sourced under the GPLv2 license and must indicate that it is based on DragonOS. It must also ensure that users of these modified versions can easily obtain the original version of DragonOS. + +You must ensure that the developers of DragonOS can obtain the source code of your modified version through the same way from public channels. Otherwise, you will violate the GPLv2 license. + +For detailed information about the license, please read the **LICENSE** file in the root directory of the project. Please note that according to the requirements of the GPLv2 license, **only the English original version has legal effect**. Any translated version is for reference only. +::: + +### Usage of Open Source Software + +  During the development of DragonOS, some open source projects were referenced, or parts of their code were introduced, or they were inspired by them. The following list shows them. We sincerely thank the contributors of these open source projects! + +Format: - - + +- Linux - https://git.kernel.org/ - GPLv2 +- skiftOS - https://github.com/skiftOS/skift - MIT +- FYSOS - https://github.com/fysnet/FYSOS - [FYSOS' License](https://github.com/fysnet/FYSOS/blob/9a8968e3d6600de34539c028c843f4c06d134039/license.txt) +- LemonOS - https://github.com/LemonOSProject/LemonOS.git - BSD 2-Clause License +- LZ4 - https://github.com/lz4/lz4 - BSD 2-Clause license +- SerenityOS - https://github.com/SerenityOS/serenity.git - BSD 2-Clause license +- MINE - 《A Design and Implementation of a 64-bit Operating System》 by Tian Yu; People's Posts and Telecommunications Press +- chcore - 《Modern Operating Systems: Design and Implementation》 by Chen Haibo, Xia Yubin; Machinery Industry Press +- SimpleKernel - https://github.com/Simple-XX/SimpleKernel - MIT +- rcore-fs - https://github.com/rcore-os/rcore-fs.git - MIT +- redox - https://gitlab.redox-os.org/redox-os/redox - MIT + +## All Commit Records of the Current Version + +```text +commit 40176b1c6603d487b7eb66fb81e641f0932ab90a +Author: longjin +Date: Tue Aug 15 15:06:57 2023 +0000 + + 删除无用代码,并把about app的版本号更新为0.1.8 + +commit 67b481888770c6469f572f244a4f97e42da77d1f +Author: houmkh <1119644616@qq.com> +Date: Mon Aug 14 12:18:46 2023 +0800 + + 移动fstat (#330) + + * 移动fstat + +commit 90a0a49048fdaf5e31320d0c87f8bed8db1bd882 +Author: LoGin +Date: Mon Aug 14 01:24:49 2023 +0800 + + 修正rwlock有的地方由于未使用ManuallyDrop导致的use after free && spinlock守卫新增leak,spinlock新增force unlock功能.(#329) + + 1.修正rwlock有的地方由于未使用ManuallyDrop导致的use after free + 2. spinlock守卫新增leak,spinlock新增force unlock功能. + +commit c3dad0011d331d782670e14723aa48e98fbac787 +Author: LoGin +Date: Sun Aug 13 16:28:24 2023 +0800 + + 添加per cpu变量支持 (#327) + +commit 42c97fa7f4fee7eeefeda5d2b7ed14f598a58493 +Author: LoGin +Date: Tue Aug 8 23:45:04 2023 +0800 + + 删除旧的libELF (#324) + +commit 6d81180b3b7328466b976b69c5f7782aa66d8a89 +Author: LoGin +Date: Tue Aug 8 23:39:22 2023 +0800 + + 移植sqlite3,并修复一些bug (#323) + + * bugfix: 程序加载器映射内存时,计算要映射的大小不正确的问题。 + + * 修正brk系统调用不符合规范的地方 + + * bugfix: 修正fat文件系统未能正确的扩展文件大小的bug + + * 增加fcntl系统调用 + + * 移植sqlite3 + +commit 26887c6334cdca2d13ad71dec27fb69faa0a57be +Author: LoGin +Date: Mon Aug 7 01:38:52 2023 +0800 + + bugfix: 解决取消低地址映射时,错误的把重映射的物理页释放,从而导致的use after free问题。 (#321) + +commit 729a96ef47f473d535d8317a2ace5ba141fd282a +Author: Xshine +Date: Sun Aug 6 12:53:47 2023 +0800 + + 实现内核通知链 notifier chain (#316) + + * 实现通知链块结构 + + * 实现通知链的基本功能 + + * 实现 atomic notifier chain + + * 实现 blocking notifier chain + + * 使用 rust 范式完成功能 + + * 支持回调次数 nr_to_call + + * 移动至 libs 目录 + + * 完善通知链相关方法 + + * 修正相关格式 + + * 文档编写 + + * 更改文档路径 + +commit be63f3b2b6b472daa3ee17180aa607409cb9d182 +Author: houmkh <1119644616@qq.com> +Date: Sat Aug 5 18:52:46 2023 +0800 + + 实现系统调用Fstat (#295) + + * fstat + + * 修改syscall.rs中的verify_area + +commit 9550910ae1de900e0291a84d268e8873fa142902 +Author: Chiichen <39649411+Chiichen@users.noreply.github.com> +Date: Sat Aug 5 18:30:55 2023 +0800 + + 替换 local_irq_save 为 IrqFlagsGuard 实现 (#317) + +commit abf3f634bf7e13e829556e962e7c73a85d163335 +Author: LoGin +Date: Sat Aug 5 15:30:06 2023 +0800 + + 自动安装、更新dadk (#319) + + * auto install/auto update dadk + +commit d6fd9c1e8025dd679339f9156477cb7d26d3db0d +Author: LoGin +Date: Sat Aug 5 15:04:08 2023 +0800 + + 设置内核、relibc的远程为dragonos的git镜像站,防止国内网络问题导致编译失败 (#318) + +commit 1a62e7767c1215f9668915b42de770e7993711bf +Author: LoGin +Date: Wed Aug 2 18:11:05 2023 +0800 + + 解决relibc的头文件没能识别__dragonos__定义的问题 (#315) + +commit 06500303303ec14711b4f995e2058e12703f0f2c +Author: LoGin +Date: Wed Aug 2 17:33:16 2023 +0800 + + 修正null设备以及zero设备无法open、行为不符合预期的问题 (#314) + +commit 4da3758acf0327d429dfce3d313b50c2e0fc7723 +Author: Chiichen <39649411+Chiichen@users.noreply.github.com> +Date: Wed Aug 2 14:29:59 2023 +0800 + + 修复了wait4的异常报错 (#312) + + * 修复了wait4的异常报错 + +commit 821bb9a2dcfd28f9878d53ba722bdf164cf00f69 +Author: Xshine +Date: Fri Jul 28 17:51:05 2023 +0800 + + 增加 ListenTable 来检测端口占用 (#291) + + * 增加 ListenTable 来检测端口占用 + + + * 使用Arc封装GlobalSocketHandle + + * 删除 listen 处的端口检测逻辑,延至实现端口复用时完成 + + * 设立两张表,分别记录TCP和UDP的端口占用 + + * 实现 meatadata 相关逻辑 + + * 实现socket关闭时,端口在表中移除 + + * 使用端口管理器重构端口记录表 + + * 修正与RawSocket相关的端口管理逻辑 + + * 补充测试文件 + + * 修正 unbind_port 在逻辑错误 + + * 修正格式问题 + + --------- + + Co-authored-by: longjin + +commit 7cc4a02c7ff7bafd798b185beb7b0c2986b9f32f +Author: zhaoyao73 +Date: Fri Jul 28 03:44:45 2023 -0400 + + fix arch_try_cmpxchg macro declaration (#307) + + fix arch_try_cmpxchg in atomic_cmpxchg + + Co-authored-by: Yao Zhao + +commit a30434f5201ca4c60b9515c8c23444fea3b5a8c6 +Author: zhaoyao73 +Date: Tue Jul 25 10:02:42 2023 -0400 + + fix some script bugs (#304) + + add arch linux prerequisited packages + + Co-authored-by: Yao Zhao + +commit 40fe15e0953f989ccfeb74826d61621d43dea6bb +Author: LoGin +Date: Sat Jul 22 16:27:02 2023 +0800 + + 新的内存管理模块 (#303) + +   实现了具有优秀架构设计的新的内存管理模块,对内核空间和用户空间的内存映射、分配、释放、管理等操作进行了封装,使得内核开发者可以更加方便地进行内存管理。 + +   内存管理模块主要由以下类型的组件组成: + + - **硬件抽象层(MemoryManagementArch)** - 提供对具体处理器架构的抽象,使得内存管理模块可以在不同的处理器架构上运行 + - **页面映射器(PageMapper)**- 提供对虚拟地址和物理地址的映射,以及页表的创建、填写、销毁、权限管理等操作。分为两种类型:内核页表映射器(KernelMapper)和用户页表映射器(位于具体的用户地址空间结构中) + - **页面刷新器(PageFlusher)** - 提供对页表的刷新操作(整表刷新、单页刷新、跨核心刷新) + - **页帧分配器(FrameAllocator)** - 提供对页帧的分配、释放、管理等操作。具体来说,包括BumpAllocator、BuddyAllocator + - **小对象分配器** - 提供对小内存对象的分配、释放、管理等操作。指的是内核里面的SlabAllocator (SlabAllocator的实现目前还没有完成) + - **MMIO空间管理器** - 提供对MMIO地址空间的分配、管理操作。(目前这个模块待进一步重构) + - **用户地址空间管理机制** - 提供对用户地址空间的管理。 + - VMA机制 - 提供对用户地址空间的管理,包括VMA的创建、销毁、权限管理等操作 + - 用户映射管理 - 与VMA机制共同作用,管理用户地址空间的映射 + - **系统调用层** - 提供对用户空间的内存管理系统调用,包括mmap、munmap、mprotect、mremap等 + - **C接口兼容层** - 提供对原有的C代码的接口,是的C代码能够正常运行。 + + + 除上面的新增内容以外,其它的更改内容: + - 新增二进制加载器,以及elf的解析器 + - 解决由于local_irq_save、local_irq_restore函数的汇编不规范导致影响栈行为的bug。 + - 解决local_irq_save未关中断的错误。 + - 修复sys_gettimeofday对timezone参数的处理的bug + + --------- + + Co-authored-by: kong + +commit bb5f098a864cee36b7d2c1ab9c029c0280d94a8a +Author: LoGin +Date: Sat Jul 22 16:24:55 2023 +0800 + + Revert "新的内存管理模块 (#301)" (#302) + + This reverts commit d8ad0a5e7724469abd5cc3cf271993538878033e. + +commit d8ad0a5e7724469abd5cc3cf271993538878033e +Author: LoGin +Date: Sat Jul 22 16:22:17 2023 +0800 + + 新的内存管理模块 (#301) + +   实现了具有优秀架构设计的新的内存管理模块,对内核空间和用户空间的内存映射、分配、释放、管理等操作进行了封装,使得内核开发者可以更加方便地进行内存管理。 + +   内存管理模块主要由以下类型的组件组成: + + - **硬件抽象层(MemoryManagementArch)** - 提供对具体处理器架构的抽象,使得内存管理模块可以在不同的处理器架构上运行 + - **页面映射器(PageMapper)**- 提供对虚拟地址和物理地址的映射,以及页表的创建、填写、销毁、权限管理等操作。分为两种类型:内核页表映射器(KernelMapper)和用户页表映射器(位于具体的用户地址空间结构中) + - **页面刷新器(PageFlusher)** - 提供对页表的刷新操作(整表刷新、单页刷新、跨核心刷新) + - **页帧分配器(FrameAllocator)** - 提供对页帧的分配、释放、管理等操作。具体来说,包括BumpAllocator、BuddyAllocator + - **小对象分配器** - 提供对小内存对象的分配、释放、管理等操作。指的是内核里面的SlabAllocator (SlabAllocator的实现目前还没有完成) + - **MMIO空间管理器** - 提供对MMIO地址空间的分配、管理操作。(目前这个模块待进一步重构) + - **用户地址空间管理机制** - 提供对用户地址空间的管理。 + - VMA机制 - 提供对用户地址空间的管理,包括VMA的创建、销毁、权限管理等操作 + - 用户映射管理 - 与VMA机制共同作用,管理用户地址空间的映射 + - **系统调用层** - 提供对用户空间的内存管理系统调用,包括mmap、munmap、mprotect、mremap等 + - **C接口兼容层** - 提供对原有的C代码的接口,是的C代码能够正常运行。 + + + 除上面的新增内容以外,其它的更改内容: + - 新增二进制加载器,以及elf的解析器 + - 解决由于local_irq_save、local_irq_restore函数的汇编不规范导致影响栈行为的bug。 + - 解决local_irq_save未关中断的错误。 + - 修复sys_gettimeofday对timezone参数的处理的bug + +commit 0663027b111ffb6ff93becd60ffef1e2b8fbd4c6 +Author: TingHuang <92705854+TingSHub@users.noreply.github.com> +Date: Wed Jul 12 12:49:45 2023 +0800 + + 注册串口设备,创建字符设备框架(#290) + + * 按照rust规范修改两个函数名称 + + * 修改一些函数句柄以符合rust规范 + + * 添加字符设备相关 + + * 添加字符设备相关文件 + + * 添加字符设备驱动框架代码 + + * 将串口注册 + + * 规范代码 + +commit cc36cf4a186be834e6c2ab857b9b9501ddb8b1eb +Author: YJwu2023 +Date: Sat Jul 8 17:22:42 2023 +0800 + + PCI设备中断重构,删去USB相关代码 (#285) + + * 修复ecam无法获取MCFG table的问题 + + * 完善pcie + + * 完善irq的错误检测机制 + +commit 2311e2f30048d09250afc3e2e4e7029627996655 +Author: 櫻井桃華 <89176634+TihayaKousaka@users.noreply.github.com> +Date: Fri Jul 7 22:50:46 2023 +0800 + + 修改makefile通过编译 (#287) + +commit 36fd013004ee0bd5fc7cfb452ba22531a83a859c +Author: houmkh <1119644616@qq.com> +Date: Sat Jun 17 22:48:15 2023 +0800 + + 实现gettimeofday()系统调用和clocksource+timekeeping子模块 (#278) + + - 实现gettimeofday()系统调用 + - 实现clocksource+timekeeping子模块部分功能 + - 实现了timespec转换成日期时间 + +commit a55ac7b928a6ca08483bbb3355bea55f1446ccab +Author: LoGin +Date: Tue Jun 6 17:44:54 2023 +0800 + + Update issue templates (#277) + +commit 5f57834372f6cb720ba14103effa4799e195a963 +Author: Tptogiar <2528891112@qq.com> +Date: Tue Jun 6 16:41:02 2023 +0800 + + Makefile: 根目录下添加make help命令 (#271) + + * Makefile: 根目录下添加make help命令 + + * Makefile: 补充根目录Makefile的help命令 + +commit aa0367d69e15989684109c5b454e85da9ecb1975 +Author: LoGin +Date: Tue May 30 10:21:11 2023 +0800 + + 新的ipi功能&kick_cpu功能的重写 (#274) + +commit bb24249faabc5006784aa98ca17b4cbdcb788c65 +Author: LoGin +Date: Sun May 28 23:00:37 2023 +0800 + + 添加AlignBox和int_like宏 (#272) + +commit ab5c8ca46db8e7d4793a9791292122b0b9684274 +Author: login +Date: Wed May 24 17:05:33 2023 +0800 + + 重构系统调用模块 (#267) + + * 完成系统调用模块重构 + + * 更新github workflow + +commit 660a04cef803fd73e9b294b30a96421b021a4b9b +Author: login +Date: Sat May 13 21:17:12 2023 +0800 + + 新增http server (#265) + + * 1.修复了当传入ahci驱动的缓冲区地址为用户缓冲区时,产生的内存越界问题.(采用分配内核缓冲区的方式临时解决) + 2.新增http server + + * 把libssl-dev添加到bootstrap.sh + + * http_server增加对父级相对路径的安全检查,防止访问系统内的其他文件 + + * 检查空指针情况 + + * 解决由于链接时,crt*.o未按照升序排列导致init段链接错误的问题 + +commit 49249f4ec94fad7baf923aed68d9a7b2da3de3d4 +Author: Bullet <93781792+GP-Bullet@users.noreply.github.com> +Date: Sat May 13 09:55:24 2023 +0800 + + 把调度器实例的裸指针改为Option (#262) + +commit bfafc102798ab1968ccf6b04315d8d3359a70ca8 +Author: login +Date: Thu May 11 17:41:42 2023 +0800 + + 修复读取stdin时,无法正常读取的问题。 (#264) + +commit 7285c927d95bb4b5c692c51a8f86c47009d07667 +Author: login +Date: Thu May 11 16:17:58 2023 +0800 + + 添加dadk支持 (#263) + + * 引入dadk,使用dadk0.1.1来编译test-relibc程序 + + * 由于gitee仓库体积限制导致无法继续使用gitee上的rust索引,因此更换为清华源 + + * github workflow的环境中,安装dadk + + * Auto configure dragonos rust toolchain + +commit b11bb1b25676f528ec1b0e1da0af82b4652f70c4 +Author: login +Date: Sun May 7 22:20:33 2023 +0800 + + 固定编译工具链、修复由于新版rust编译器问题导致的报错。 (#258) + + * 固定编译工具链、修复由于新版rust编译器问题导致的报错。 + + * 完善github workflow环境配置 + +``` diff --git a/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.9.md b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.9.md new file mode 100644 index 00000000..bf809611 --- /dev/null +++ b/docs/locales/en/community/ChangeLog/V0.1.x/V0.1.9.md @@ -0,0 +1,2326 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/ChangeLog/V0.1.x/V0.1.9.md + +- Translation time: 2025-05-19 01:44:01 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# V0.1.9 + +:::{note} +Author: He Yicong + +DragonOS Official Forum: [bbs.dragonos.org.cn](https://bbs.dragonos.org.cn) + +March 13, 2024 +::: + +## Contributors List + +The DragonOS V0.1.9 version was contributed by the following team members: + +- Long Jin +- He Yicong +- Yu Yi <68320855+yuyi2439@users.noreply.github.com> +- R0ronoa <84278015+2447742618@users.noreply.github.com> +- Chiichen <39649411+Chiichen@users.noreply.github.com> +- Wu Yujian +- zhaoyao73 +- Hu Zhaopeng <105195940+MemoryShore@users.noreply.github.com> +- Zhou Hanjie +- Lizi +- Xshine +- Chenzx <109664121+schulice@users.noreply.github.com> +- MContour +- Donkey Kane <109840258+xiaolin2004@users.noreply.github.com> +- Luo Jia / Zhouqi Jiang +- Wu Mianzhi <31810920+Hdksg10@users.noreply.github.com> +- Xiaoye Zheng +- Plucky923 <107762234+Plucky923@users.noreply.github.com> +- Xu Zihao + +## Sponsors List + +- **[YaCloud China](https://yacloud.net)** Yaan Big Data Industrial Park provided cloud server support for DragonOS. + +## Donors List + +Thank you to the following individuals for their donations. We will keep up the good work! + +- David Wen +- Wan Xiaolan +- Long Jin +- Wu Yujian + +Less than 2000 yuan: + +- [Seele.Clover](https://github.com/seeleclover) +- [FindWangHao](https://github.com/FindWangHao) +- [ferchiel](https://github.com/ferchiel) +- Ye Jinyi +- Lin +- Albert +- [TerryLeeSCUT · GitHub](https://github.com/TerryLeeSCUT) +- slientbard +- Wu +- Anonymous Kind-hearted Person + +## Update Content - Kernel + +### New Features + +- refactor: Refactor process management module ([#_translated_label__380_en](https://github.com/DragonOS-Community/DragonOS/pull/380)) +- feature: Improve device driver model ([#_translated_label__401_en](https://github.com/DragonOS-Community/DragonOS/pull/401)) +- feature: Implement e1000e network card driver ([#_translated_label__393_en](https://github.com/DragonOS-Community/DragonOS/pull/393)) +- feature: DragonOS virtualization framework ([#_translated_label__389_en](https://github.com/DragonOS-Community/DragonOS/pull/389)) +- feature: Support syscall fast system call instruction ([#_translated_label__417_en](https://github.com/DragonOS-Community/DragonOS/pull/417)) +- refactor: Rewrite apic driver ([#_translated_label__425_en](https://github.com/DragonOS-Community/DragonOS/pull/425)) +- feature: Thread mechanism and futex ([#_translated_label__411_en](https://github.com/DragonOS-Community/DragonOS/pull/411)) +- feature: DragonStub boot DragonOS kernel ([#_translated_label__460_en](https://github.com/DragonOS-Community/DragonOS/pull/460)) +- feature: Implement Epoll IO multiplexing mechanism ([#_translated_label__455_en](https://github.com/DragonOS-Community/DragonOS/pull/455)) +- feature: Frame buffer abstraction and vesafb driver ([#_translated_label__483_en](https://github.com/DragonOS-Community/DragonOS/pull/483)) +- feature: Add early io remap fixmap function ([#_translated_label__495_en](https://github.com/DragonOS-Community/DragonOS/pull/495)) +- feature: Implement kernel log system ([#_translated_label__489_en](https://github.com/DragonOS-Community/DragonOS/pull/489)) +- refactor: Rewrite kernel initialization code under x86_64 using Rust ([#_translated_label__507_en](https://github.com/DragonOS-Community/DragonOS/pull/507)) +- feature: Add memory management for riscv64 architecture ([#_translated_label__506_en](https://github.com/DragonOS-Community/DragonOS/pull/506)) +- refactor: Interrupt management module refactored ([#_translated_label__554_en](https://github.com/DragonOS-Community/DragonOS/pull/554)) +- refactor: Refactor tty module, implement UNIX compatible tty ([#_translated_label__577_en](https://github.com/DragonOS-Community/DragonOS/pull/577)) +- feature: Implement several POSIX standard system calls + +### Bug Fixes + +- bugfix: Fix the issue caused by the init proc union and the bug caused by the default sleep behavior of kernel threads leading to the inability to run the init process ([#_translated_label__381_en](https://github.com/DragonOS-Community/DragonOS/pull/381)) +- bugfix: Fix the bug where TLB was not automatically flushed during Flusher Drop ([#_translated_label__384_en](https://github.com/DragonOS-Community/DragonOS/pull/384)) +- bugfix: Fix the bug where multiboot2 startup information was not saved in time, leading to the inability to query it later ([#_translated_label__405_en](https://github.com/DragonOS-Community/DragonOS/pull/405)) +- bugfix: Fix the error in the handling of the unloading logic by bus/device manager ([#_translated_label__385_en](https://github.com/DragonOS-Community/DragonOS/pull/385)) +- bugfix: Solve the bug where the waitqueue sleep caused the sched failure due to preempt count not being zero, leading to the PCB being added multiple times to the scheduling queue on the next wake-up ([#_translated_label__419_en](https://github.com/DragonOS-Community/DragonOS/pull/419)) +- bugfix: Fix the bug where the vm holes were not correctly copied during fork ([#_translated_label__433_en](https://github.com/DragonOS-Community/DragonOS/pull/433)) +- bugfix: Fix the issue where multiple memory areas on the physical machine could not be used correctly, and the memory holes in the kernel code caused the system to fail to run normally ([#_translated_label__448_en](https://github.com/DragonOS-Community/DragonOS/pull/448)) +- bugfix: Fix the bug where the ACPI could not be initialized properly due to the rsdp v1 v2 version issue ([#_translated_label__454_en](https://github.com/DragonOS-Community/DragonOS/pull/454)) +- bugfix: Fix the bug where the bus driver and device strong-weak reference relationship was incorrect, leading to the object being released ([#_translated_label__483_en](https://github.com/DragonOS-Community/DragonOS/pull/483)) +- bugfix: Fix the bug where epoll still held the weak reference of the file descriptor after the file was closed ([#_translated_label__455_en](https://github.com/DragonOS-Community/DragonOS/pull/455)) +- bugfix: Fix the issue of being unable to sleep and the problem where the process in block(true) state could not be awakened by signals and the signals were not handled after waking up ([#_translated_label__470_en](https://github.com/DragonOS-Community/DragonOS/pull/470)) + +## Update Content - User Environment + +### New Features + +- feature: Add the init program dragonreach ([#_translated_label__391_en](https://github.com/DragonOS-Community/DragonOS/pull/391)) +- featurn: Add the shell program NovaShell ([#_translated_label__456_en](https://github.com/DragonOS-Community/DragonOS/pull/456)) +- featurn: Add the text editor Held ([#_translated_label__583_en](https://github.com/DragonOS-Community/DragonOS/pull/583)) +- featurn: Support the execution of programs such as gcc, tar, redis, etc. + +## Source Code and Release Image Download + +  You can obtain the source code through the following methods: + +### Get via Git + +- You can visit [https://github.com/DragonOS-Community/DragonOS/releases](https://github.com/DragonOS-Community/DragonOS/releases) to download the release code and the compiled, runnable disk image. + +### Get via DragonOS Software Mirror Site + +  To solve the problem of slow and unstable access to GitHub in China, and to make it convenient for developers to download the code of each version of DragonOS, we have specially set up a mirror site. You can access the mirror site through the following address: + +  You can get the DragonOS code package and the compiled, runnable disk image through the mirror site. + +- [https://mirrors.DragonOS.org.cn](https://mirrors.DragonOS.org.cn) +- [https://git.mirrors.DragonOS.org.cn](https://git.mirrors.DragonOS.org.cn) + +## Open Source Declaration + +:::{note} +To promote the healthy development of the DragonOS project, DragonOS is released under the GPLv2 open source license. Anyone who can obtain the DragonOS source code and corresponding software products (including but not limited to binary copies and documents) can enjoy the rights granted by us through the GPLv2 license, and you must also comply with the obligations stipulated in the license. + +This is a rather strict license that protects the healthy development of open source software and prevents it from being infringed. + +For most well-intentioned people, you will not violate our open source license. + +We encourage the free dissemination and promotion of DragonOS, but please ensure that all actions do not infringe upon the legitimate rights and interests of others or violate the GPLv2 license. + +Please pay special attention to the fact that violations of the open source license, especially **commercial closed-source use and any acts of plagiarism or academic misconduct**, will be subject to serious accountability. (This is the easiest scenario to violate our open source license.) + +Also, please note that according to the requirements of the GPLv2 license, software modified or developed based on DragonOS must also be open-sourced under the GPLv2 license and must clearly indicate that it is based on DragonOS. It is also necessary to ensure that users of these modified versions can conveniently obtain the original version of DragonOS. + +You must make sure that the DragonOS developers can obtain the source code of your modified version through public channels in the same way, otherwise you will violate the GPLv2 license. + +For detailed information about the license, please read the **LICENSE** file in the root directory of the project. Please note that according to the requirements of the GPLv2 license, **only the English original version is legally binding**. Any translated version is for reference only. +::: + +### Usage of Open Source Software + +  During the development of DragonOS, we have referenced some designs from the Linux community, or introduced some of their ideas, or been inspired by them. We would like to express our sincere gratitude to the Linux community and its contributors here! + +## All Commit Records of the Current Version + +```text +commit af59116e1b8643862598607dbc6ef7233f3791b5 +Author: MemoryShore <105195940+MemoryShore@users.noreply.github.com> +Date: Tue Mar 12 17:52:14 2024 +0800 + + Update NovaShell version to c6454d3220 (#593) + +commit 59fdb447ee4f7b53b1d9c56ec1442aa8c597ac2b +Author: LoGin +Date: Tue Mar 12 16:32:33 2024 +0800 + + fix: 键盘中断上下文不再直接操作tty,而是由专门的kthread来渲染 (#592) + + fix: 键盘中断上下文不再直接操作tty,而是由专门的kthread来渲染 + 1.修正psmouse 日志 + 2. 键盘中断上下文不再直接操作tty,而是由专门的kthread来渲染 + 3. 由于调度器设计问题,load balance会由于时序问题导致错误.因此暂时只启用单核. + +commit 818a64c77613a9c2152739f1cddad78d61e4a94f +Author: LoGin +Date: Tue Mar 12 15:33:01 2024 +0800 + + 暂时禁用load balance (#591) + + 原因见issue: https://github.com/DragonOS-Community/DragonOS/issues/571 + +commit 4374bd1d1177dbf94112aee3ea3f8e8c335a599c +Author: GnoCiYeH +Date: Mon Mar 11 19:40:52 2024 +0800 + + 修复get_random一个问题,添加Held配置文件 (#583) + +commit 52bcb59e9286def2b66d766f6bf6f46745795ec8 +Author: GnoCiYeH +Date: Mon Mar 11 15:13:37 2024 +0800 + + 完善Tty的RawMode (#577) + + * 完善rowmode,改掉一部分bug + + * 增加两个ansi拓展功能功能,以及标记部分函数nerve inline + + * 修改do_signal和其他中断上下文锁未关中断,以及拓展tty功能,修改tty几个算法bug + + * 修改两个锁 + + * 修改syscall_64 + + * update + +commit 840045af94ea3391f29e87e968db5d9c48316981 +Author: LoGin +Date: Sun Mar 10 21:45:34 2024 +0800 + + 引入clippy,并根据clippy的提示,修改部分代码 (#575) + +commit f4a82aa55c55e1a9233e99a5598e180f0858d877 +Author: LoGin +Date: Sun Mar 10 20:42:41 2024 +0800 + + Update Novashell version to 473d5c403c (#574) + + - fix: 用户输入不正确的;以及单独输入单引号和双引号造成系统重启 + - 修改命令解析算法 + - fix: 输出多余的光标和命令信息 + +commit 4f8f484930ed3c09ecf4b5b05b1dea14f7b05d8b +Author: 栗子 +Date: Sat Mar 9 21:20:12 2024 +0800 + + 修复Archlinux下的bootstrap脚本问题, (#552) + + * 修复Archlinux下的bootstrap脚本问题, + + 由于archlinux 的 texinfo版本太新导致的gcc docs构建失败 + 使用 MAKEINFO=true 的make环境变量跳过gcc docs构建,绕过问题 + + + --------- + + Co-authored-by: longjin + +commit 3055390c25bb7b12279df174689ba09ec50c7d46 +Author: Jomo +Date: Sat Mar 9 11:40:44 2024 +0800 + + 完善重映射过程中获取新映射区域时的map_flags (#569) + +commit 5c4224e5a8244cb0fb32512e70354362fccd6321 +Author: LoGin +Date: Fri Mar 8 23:23:06 2024 +0800 + + 在riscv上实现异常处理,能够进入异常处理程序 (#564) + +commit c3dc6f2ff9169c309d1cbf47dcb9e4528d509b2f +Author: LoGin +Date: Fri Mar 8 23:22:48 2024 +0800 + + 删除一些过时的C代码 (#565) + + * 删除C版本的crc库 + + * 删除lockref + + * 删除过时的libc文档以及wait.c + + * 删除过时的C版本kfifo代码及文档 + + * 移除未用到的lz4库 + + * 删除内核的stdlib.c + + * 删除fabs.c + + * fmt + + * 使得put_string系统调用能够通过tty输出颜色 + 暂且这样改,这一部分应该是用户层面提供的功能,后续删除 + + --------- + + Co-authored-by: GnoCiYeH + +commit 5eeefb8c80e5580641d295724f8d2190bd54979c +Author: Chenzx <109664121+schulice@users.noreply.github.com> +Date: Fri Mar 8 16:01:22 2024 +0800 + + 实现SYS_RMDIR (#566) + + * 实现rmdir系统调用,整理do_remove_dir逻辑 + +commit 338f6903262c5031abad3c8e361813355a27fcdb +Author: LoGin +Date: Tue Mar 5 17:22:04 2024 +0800 + + `riscv`: 初始化irq (#560) + + 完成riscv的irqchip初始化的代码。 + + 这是该功能的第一个PR。由于还需要实现timer驱动才能测试,因此该功能将会通过2~3个PR来完成。 + +commit bc6f0a967c8cb1e9379ced184b25a7722fbda2a4 +Author: 裕依 <68320855+yuyi2439@users.noreply.github.com> +Date: Mon Mar 4 14:20:01 2024 +0800 + + 移除relibc和old libc以及旧的shell (#529) + + 移除relibc和old libc以及旧的shell + +commit f3b05a97ec061e766247b18dc12e2a413b977b14 +Author: GnoCiYeH +Date: Mon Mar 4 14:10:26 2024 +0800 + + 将tty输出接入串口 (#555) + +commit cf45dede2e46d9341cec75871fdc1bc5961ba5a2 +Author: MContour +Date: Sun Mar 3 17:20:11 2024 +0800 + + 让 DragonOS 仓库管理 service 文件 (#548) + + * feat: create `user/services` folder to store service files + +commit e28411791f090c421fe4b6fa5956fb1bd362a8d9 +Author: LoGin +Date: Sun Mar 3 16:31:08 2024 +0800 + + 完成中断管理模块重构 (#554) + + - 支持中断共享 + - 把现有驱动程序移植到新的irq模块 + - 使用`ProcessorId`标识处理器id + - 尚未实现threaded_irq + + 性能上,edge irq flow handler里面,对于锁的使用,可能有点问题。为了获取/修改common data还有其他几个结构体的状态,进行了多次加锁和放锁,导致性能降低。这是接下来需要优化的点。 + +commit 44d051e5864adff6f4ace8a234ef57852840f365 +Author: Donkey Kane <109840258+xiaolin2004@users.noreply.github.com> +Date: Sun Mar 3 15:22:45 2024 +0800 + + Modify dadk config to switch NovaShell revision (#550) + +commit 0e7c46939604a02e739546200bea847f4951a963 +Author: GnoCiYeH +Date: Fri Mar 1 15:07:00 2024 +0800 + + 修改事件等待队列对于retain使用方法出错导致唤醒错误 (#551) + +commit be60c929c8285d3050e022aa23312a84129e54b2 +Author: GnoCiYeH +Date: Wed Feb 28 20:18:49 2024 +0800 + + 修改tty几个bug (#549) + + * 更改ioctl一处逻辑错误 + + * 删除不必要的impl + + * 修改一处bug,并且加入tty的link,为pty做准备 + + * 修改一处因为vc的pos和x计算错误导致的溢出 + +commit 52da9a59374752b4d01907b052135a0d317781dd +Author: GnoCiYeH +Date: Mon Feb 26 15:27:19 2024 +0800 + + 完成与Linux兼容的Ntty (#517) + + * 已经完成的功能: + - 写:printf能够正常在tty输出 + - 读:与键盘驱动接上 + - 信号: 能够正常通过ctrl向前台进程发送信号 + + * 支持目前的shell,改动printk使其与新版tty兼容。 + + * 删除原有tty文件夹,并更改新tty文件名 + + * 添加clear清屏程序 + + * 实现tty部分ioctl,更改部分问题 + +commit 9993c0fc61e9603f631bd6748ff0b4fecb7bd483 +Author: R0ronoa <84278015+2447742618@users.noreply.github.com> +Date: Mon Feb 26 15:03:13 2024 +0800 + + 添加i8042驱动 改正serio设备文件结构 (#538) + + * 添加i8042驱动 改正serio设备文件结构 + +commit d2b28acb4d1f160779b25d76afca49ed60ad5d48 +Author: 栗子 +Date: Sun Feb 25 19:57:30 2024 +0800 + + tools/bootstrap.sh: fix archlinux and zsh issue (#535) + + 1. archlinux上没有libssl-dev包,相对应的包名是openssl + 2. zsh用户使用bootstrap.sh 会因为 source ~/.zshrc + 导致bash执行很多zsh built-in 指令出现非常多错误 + 3. mkdir命令加-p选项避免对象目录存在时(反复执行脚本)报错 + 4. 修复简单错误(typo gcc 为 binutils) + 5. 修复bootstrap.sh等脚本无法在非tools/目录执行的错误 + +commit 7d66c3134c1c5566ac8f8b7524e98650d0480a4a +Author: LoGin +Date: Mon Feb 19 21:40:37 2024 +0800 + + 添加简单的cpumask (#533) + +commit b2ca6800f9d943e5d3656d9b50a099da768775a7 +Author: LoGin +Date: Mon Feb 19 19:50:03 2024 +0800 + + 添加动态申请的bitmap (#532) + +commit 0e2c2e8b48369b201f44e0933f775b932b6776ef +Author: 裕依 <68320855+yuyi2439@users.noreply.github.com> +Date: Mon Feb 19 19:31:17 2024 +0800 + + 修正systemerror号 (#527) + + 修正systemerror号 + +commit 4cfa009b87c8431a41fab740ffdbd7b008965c9a +Author: Jomo +Date: Mon Feb 19 14:54:11 2024 +0800 + + 实现mremap系统调用 (#518) + + * mremap系统调用 + +commit 27b967a38a6dd7a266c43b5e705c29dfbbd71ae4 +Author: 裕依 <68320855+yuyi2439@users.noreply.github.com> +Date: Mon Feb 19 14:53:34 2024 +0800 + + 添加pread&pwrite (#528) + + 添加pread&pwrite + +commit 701589559f912deb03eb5176d049d9d07fb29447 +Author: LoGin +Date: Mon Feb 19 11:17:23 2024 +0800 + + 删除无用的C版本bitree和ida/idr. (#526) + + 这些数据结构不再使用,将其删除. + +commit 196b75dc17b5cc2ed84301bce776e496ddfe1ed1 +Author: LoGin +Date: Mon Feb 19 00:56:58 2024 +0800 + + 把irqdesc添加到sysfs (#525) + + * 把irqdesc添加到sysfs + +commit 3bc96fa4a9c01d91cddeb152fe78d6408351c29f +Author: LoGin +Date: Mon Feb 19 00:36:36 2024 +0800 + + 添加irqdesc的抽象,并在系统初始化时创建irqdesc (#522) + + * 添加irqdesc的抽象,并在系统初始化时创建irqdesc + +commit ce5850adbf74ec6c6717bbb5b1749f1fbff4ca0d +Author: LoGin +Date: Sun Feb 18 20:41:41 2024 +0800 + + 添加irqchip这一层的数据结构(尚未接入真实的芯片) (#520) + + * 添加irqchip这一层的数据结构(尚未接入真实的芯片) + +commit ca318c376bd9e39f8fe71f304974f7e99e8e01f4 +Author: LoGin +Date: Sat Feb 17 01:51:10 2024 +0800 + + update dragonreach to 3d99c3a9d9 (#519) + +commit 472f0b3931eadda2bbcc67889d612790f147190b +Author: LoGin +Date: Tue Feb 13 12:14:12 2024 +0800 + + update dragonreach to 40362c48d6 (#516) + +commit d90848514bea7efd5898f5824b98f1bf2e54de8d +Author: Luo Jia / Zhouqi Jiang +Date: Sat Feb 10 23:20:50 2024 +0800 + + riscv: 更新sbi-rt至0.0.3版本 (#512) + + 先前使用git仓库链接的最新更新已发布至crates.io网站 + + Signed-off-by: Zhouqi Jiang + +commit 4ad52e57e612a88ab09413c7ac0072db96a93632 +Author: 裕依2439 <68320855+yuyi2439@users.noreply.github.com> +Date: Wed Feb 7 18:06:15 2024 +0800 + + 添加socketpair (#505) + + * 添加对socketpair系统调用的处理 + + --------- + + Co-authored-by: LoGin + +commit cb23beb255d8e32b45d879ac19386a3597ca4115 +Author: LoGin +Date: Wed Feb 7 17:15:17 2024 +0800 + + riscv: probe sbi extensions (#511) + +commit f2022a8a1cc4a8e2a85e9061e036e9c491a2fa00 +Author: LoGin +Date: Wed Feb 7 13:29:47 2024 +0800 + + 使用rust编写中断/异常的入口 (#509) + + * 使用rust编写中断/异常的入口 + +commit d14e28a8a9b023ee8df7c2e8eee43e523134dbb2 +Author: Luo Jia / Zhouqi Jiang +Date: Wed Feb 7 11:38:15 2024 +0800 + + riscv: 使用sbi-rt库完成SBI操作 (#510) + + 未来的其它SBI操作也将使用sbi-rt + + Signed-off-by: Zhouqi Jiang + +commit fccbe87dcae0f8e8fde611ef60b1f7923126d526 +Author: LoGin +Date: Mon Feb 5 14:50:15 2024 +0800 + + 删除关于zulip的表述,替换为社区论坛 (#508) + +commit 5b59005f930266d0e9c0092373e894826150f862 +Author: LoGin +Date: Sun Feb 4 15:46:24 2024 +0800 + + x86_64: 使用Rust重写内核初始化代码 (#507) + + * x86_64: 使用Rust重写内核初始化代码 + +commit 453452cc02e2766a28d87dd47bdee37caddc4c44 +Author: LoGin +Date: Sun Feb 4 14:35:18 2024 +0800 + + 初始化riscv的内存管理模块,并且设置保留内存 (#506) + +commit a02ce654cf0166720f8569827d0c5b2dfd0ca95a +Author: Chiichen +Date: Sun Jan 28 20:29:01 2024 +0800 + + 支持对动态链接文件的加载,支持通过musl工具链编写用户空间程序 (#504) + + 支持对动态链接文件的加载,支持通过musl工具链编写用户空间程序 + +commit 5d549a76ab0cf66651a6614be92dcb481fe7af2a +Author: Chiichen +Date: Fri Jan 26 20:45:08 2024 +0800 + + 修改一处常量定义 (#503) + + * 修改一处常量定义 + + * 修复ELF加载程序对用户程序加载地址判断不正确的地方 + + --------- + + Co-authored-by: longjin + +commit 9284987850c1da2ce607a539eeae8a353a8f6df9 +Author: LoGin +Date: Fri Jan 26 18:08:39 2024 +0800 + + riscv: 完成UEFI初始化,能正确设置memblock的信息 (#501) + + * riscv: 完成UEFI初始化,能正确设置memblock的信息 + + * sbi增加reset功能 + + * 把虚拟CPU修改为sifive-u54,使qemu能更正确地模拟硬件行为 + + * 修复内存页面映射未设置“DIRTY”、”ACCESSED“、”GLOBAL“位,导致真机page fault的问题 + +commit a381e482cbe742b2e4bbeaacae134a8131bf3f91 +Author: R0ronoa <84278015+2447742618@users.noreply.github.com> +Date: Wed Jan 24 19:17:22 2024 +0800 + + 实现Ps/2鼠标驱动 (#500) + + 实现Ps/2鼠标驱动 + +commit 8d72b68da9339ec97e1b8929bcf2946f0fd83cd5 +Author: Jomo +Date: Wed Jan 24 16:13:15 2024 +0800 + + 实现内核日志系统 (#489) + + * 实现写日志和读取日志,并且能够在用户态下执行dmesg命令查看日志 + + * 通过klogctl实现dmesg + + * 改用ConstGenericRingBuffer作内核缓冲区 + + * 更改缓冲区容量 + + * 将能够输出到控制台的日志级别改为日志级别枚举类,使用SpinLock控制KMSG,使用枚举类定义SYSLOG_ACTION,将do_syslog系统调用接口放在syscall.rs + + * fix warning + + * 完善do_syslog注释 + + * 将KMSG接入kinfo、kdebug等 + + * fix warning + + * 修复显示的秒数不正确,·以及无法通过CI的问题 + +commit d46c6d27941a26de14f55a2bbf956219bcc70871 +Author: 裕依2439 <68320855+yuyi2439@users.noreply.github.com> +Date: Tue Jan 23 23:36:52 2024 +0800 + + 修复tty的buf满时始终阻塞的问题 (#493) + + * 修复tty的buf满时始终阻塞的问题 + +commit 43ef2a0d2b6ec427f6775cd4593c56897dd5bf6d +Author: LoGin +Date: Sun Jan 21 18:45:07 2024 +0800 + + 添加riscv64的github workflow (#499) + + * 添加riscv64的github workflow + +commit 7a29d4fcbcd89a226289c7bf541c2c78623de3ad +Author: LoGin +Date: Sun Jan 21 15:38:12 2024 +0800 + + riscv64: 映射uefi systemtable,并完善了riscv64页表填写的部分内容 (#498) + + * 从fdt的chosen段获取几个需要的字段 + + * merge patch-early-ioremap + + * feature: 增加early io remap的fixmap功能 + + 允许在内存管理初始化之前,使用fixmap功能,映射一些物理内存,并记录. + + * riscv64: 映射uefi systemtable,并完善了riscv64页表填写的部分内容 + + * 更新仓库网址 + +commit 3e3c6316aaac5a8a2932bd1746ec8b900dc5e2c6 +Author: Chiichen +Date: Sun Jan 21 01:38:45 2024 +0800 + + fix: 修复了ps2和tty初始化顺序的错误 (#497) + + * 修复了ps2和tty初始化顺序的错误 + +commit 74ffde667e5e7f4ac8ce6d5a5ec2c1403f36cbb0 +Author: LoGin +Date: Sun Jan 21 01:21:55 2024 +0800 + + feature: 增加early io remap的fixmap功能 (#495) + + 允许在内存管理初始化之前,使用fixmap功能,映射一些物理内存,并记录. + +commit 1f58c8f5cff8e82441b66789c3dc7c009d52f29a +Author: LoGin +Date: Thu Jan 18 22:39:58 2024 +0800 + + Update mini-backtrace版本到e0b1d90940 (#494) + + 内容: + + [https://github.com/DragonOS-Community/mini-backtrace/pull/1](https://github.com/DragonOS-Community/mini-backtrace/pull/1) + + Co-authored-by: Yao Zhao + +commit c75ef4e2126c180bf04c08635ffa5a278619c035 +Author: LoGin +Date: Thu Jan 18 00:09:36 2024 +0800 + + 添加early ioremap支持 (#492) + + * 使用early io remap来映射早期的vesa缓冲区 + +commit d8e29bffeee4fe4fe76ead3c761dd03f5395e6c2 +Author: R0ronoa <84278015+2447742618@users.noreply.github.com> +Date: Wed Jan 17 23:57:49 2024 +0800 + + 增加serio总线和相关trait (#488) + + * 新增serio总线和相关trait + + * 补充SerioDeviceManager和SerioDriverManager + +commit 6994f6b113f6fea7b997ec07130a7bdaecfd67b7 +Author: LoGin +Date: Mon Jan 15 18:13:22 2024 +0800 + + 完成bitmap的static bitmap功能,能够静态声明bitmap (#490) + + * 完成bitmap的static bitmap功能,能够静态声明bitmap + +commit dcf232f378b36fad754799fc121a70cadc8d5cb3 +Author: LoGin +Date: Sun Jan 14 17:00:42 2024 +0800 + + 当找不到内核日志缓冲区的时候,重试 (#491) + +commit 45626c859f95054b76d8b59afcbd24c6b235026f +Author: LoGin +Date: Wed Jan 3 18:00:47 2024 +0800 + + riscv: 解析dtb,获取可用内存空间并添加到memblock (#486) + +commit 02343d0b5b47c07e7f4ec3818940795b1009fae1 +Author: LoGin +Date: Tue Jan 2 14:16:10 2024 +0800 + + 增加/dev/fb0,能够在用户程序读写帧缓冲区 (#485) + +commit e7071df6a47c100381a8bc2000022e82d422361a +Author: LoGin +Date: Mon Jan 1 11:53:49 2024 +0800 + + 把opengrok.ringotek.cn替换为code.dragonos.org.cn (#484) + +commit c566df451ce6dbf2af684333e68b39fdfff86498 +Author: LoGin +Date: Mon Jan 1 11:46:51 2024 +0800 + + 添加帧缓冲区抽象并实现vesafb的驱动 (#483) + + - 添加bootparams对象 + - 修正由于bus的driver、device强弱引用关系 不正确从而导致对象被释放的bug + - 添加vesafb的驱动 + - 实现framebuffer抽象层 + - 为通用帧缓冲区抽象实现sysfs的属性 + - 修改设备号DeviceNumber的定义 + - 仿照linux,添加initcall,并在第一个内核线程中,调用他们。 + +commit e3eb08d4d7148d6dad369e2ef27979d1bcf85bd6 +Author: LoGin +Date: Sat Dec 30 16:23:26 2023 +0800 + + fix: 修复安装musl-gcc的脚本没能正确设置x86_64下的环境变量的问题 (#482) + +commit 81294aa2e6b257f0de5e3c28c3f3c89798330836 +Author: LoGin +Date: Wed Dec 27 20:32:25 2023 +0800 + + fix: 修正bootstrap脚本安装docker后会使得当前终端进入root的问题 (#481) + +commit cfd642e2835eded086b6e944427e4a88f03e2fff +Author: MemoryShore <105195940+MemoryShore@users.noreply.github.com> +Date: Wed Dec 27 15:07:01 2023 +0800 + + 更新nova shell的revision为64ad1b282a (#477) + + - 修复tab补全时始终基于根目录的问题 + - 修复touch命令提示已存在文件的bug + +commit 5e948c56506aa0554d212341a7630587d55ebb87 +Author: GnoCiYeH +Date: Wed Dec 27 15:02:29 2023 +0800 + + 修正pipe逻辑,将pipe接入epoll。 (#478) + +commit 0d6cf65aa124ee55bfee44cbb5196917ea6522fa +Author: LoGin +Date: Wed Dec 27 14:27:12 2023 +0800 + + Patch fix sched and net lockdep error (#479) + + - fix: 修复调度器,软中断,定时器,网络子系统的部分锁的使用不符合锁依赖安全规范的问题 + - fix: 修复创建pcb时内核栈爆栈的问题 + - 把异常的trap gate改成intr gate + + --------- + + Co-authored-by: GnoCiYeH + +commit 91e9d4ab55ef960f57a1b6287bc523ca4341f67a +Author: LoGin +Date: Mon Dec 25 23:12:27 2023 +0800 + + 实现unified-init库,支持收集初始化函数到一个数组,并统一初始化 (#474) + + * 添加“统一初始化”的过程宏,并把SystemError独立成crate + + * 使用unified-init来初始化fbmem + + * 更新workflow,增加内核自动化静态测试 + +commit f110d330d5493f383067b4e82ebbfb72f40457b2 +Author: LoGin +Date: Mon Dec 25 21:54:00 2023 +0800 + + 修复bootstrap在安装riscv gcc依赖时出现冲突的问题 (#476) + +commit 406099704eb939ae23b18f0cfb3ed36c534c1c84 +Author: GnoCiYeH +Date: Mon Dec 25 18:08:12 2023 +0800 + + 增加epoll机制 (#455) + + * ## 增加epoll机制 + - 增加epoll机制 + - 添加事件等待队列,提升socket性能 + - 优化poll,删除不能poll的文件系统中的poll方法 + + * 添加细节注释 + + * 修复文件关闭后epoll还持有对应描述符的文件弱引用的bug + + * 将EPollEvent设计为POSIX标准 + + * 修改s到us转换的计算错误 + +commit 070e991008b268b7103236a46b8651a983522869 +Author: R0ronoa <84278015+2447742618@users.noreply.github.com> +Date: Fri Dec 22 16:01:23 2023 +0800 + + 解决由于Makefile问题导致make run-uefi无法正常启动的问题 (#473) + +commit 08a2ee408498b0db4c76c57b149f1cf047758f3c +Author: LoGin +Date: Wed Dec 20 17:24:05 2023 +0800 + + 添加FrameBuffer的接口抽象&完善设备驱动模型的class相关代码 (#472) + + * 添加FrameBuffer的接口抽象(参考Linux 6.1.9) + + * feature: 完善设备驱动模型的class的抽象,并创建graphics class + + * feature: 完善设备驱动模型中Device对class的处理,使得能够在class下注册设备 + + 目前注册了fbcon设备,但是由于虚拟终端还没写,因此fbcon的到终端以及帧缓冲区的映射还没加上去. + +commit 8612b6ce7afc903999ccf0b65bd65019484d2fad +Author: LoGin +Date: Tue Dec 19 11:56:14 2023 +0800 + + bugfix: 修复无法sleep的问题以及进程处于block(true)状态时无法被信号唤醒&唤醒后不处理信号的问题 (#470) + +commit 24ff1faffb3d610cd55e3c658fd50ea0a0efedfb +Author: LoGin +Date: Mon Dec 18 17:44:53 2023 +0800 + + doc: 修改Rust代码注释风格文档 (#471) + +commit 111c5407ccb7774695c8047cf895481d3387fda9 +Author: LoGin +Date: Sun Dec 17 21:08:03 2023 +0800 + + 设置idle进程的时间片为0,降低调度延迟 (#469) + +commit 666cffedab3da9684e5abf5eebcbddae63590364 +Author: LoGin +Date: Sat Dec 16 22:26:26 2023 +0800 + + riscv: 映射内核到指定的虚拟地址,使得kinfo能正常工作 (#468) + + * riscv: 映射内核到指定的虚拟地址,使得kinfo能正常工作 + +commit cf442324231632df3c3b0da3d2c8e19087863aa0 +Author: LoGin +Date: Wed Dec 13 14:44:57 2023 +0800 + + 修复x86下第二次编译的时候内核没有拷贝到磁盘的问题 (#467) + +commit 1a72a751b18cf5bbe7b5b9e91aff530de0c18501 +Author: LoGin +Date: Thu Dec 7 02:13:22 2023 +0800 + + 在riscv输出hello world (#466) + + 增加了以下内容: + - SBI驱动 + - 把内核的rust工具链升级到2023-08-15版本 + - 输出riscv的helloworld + - 设置内核是PIC的 + +commit fca83acef4ba261453f7c71960eacf83d0cf51f4 +Author: LoGin +Date: Mon Dec 4 22:10:10 2023 +0800 + + 修复cache-toolchain.yml的格式问题 (#464) + +commit 6c7f966c2f3e3ed299168fc97ae346a85cc6e322 +Author: MemoryShore <105195940+MemoryShore@users.noreply.github.com> +Date: Mon Dec 4 22:07:30 2023 +0800 + + NovaShell替换为默认shell (#456) + + * NovaShell替换为默认shell + + * delete some envvar + + * 自动从dragonos镜像站更新dadk + + * 更新github ci环境 + + * 修复yml格式问题 + + * 更新novashell到95738b235f + + --------- + + Co-authored-by: longjin + +commit 09d2bf52a6d048929a879748ae26e4fdea45e5d5 +Author: LoGin +Date: Sun Dec 3 21:27:43 2023 +0800 + + update-dragon-stub-bf2617 (#463) + +commit af3543100543b9ac6159dc9f9367a76ff670b1f3 +Author: LoGin +Date: Sun Dec 3 17:16:03 2023 +0800 + + 使用submodule引入DragonStub (#462) + + * 修正构建系统文档: 使用repo工具克隆代码 + + * 使用submodule管理 + +commit 83ed0ebc293d5a10245089f627f52770fd5b9dd4 +Author: LoGin +Date: Sun Dec 3 14:51:21 2023 +0800 + + 修正构建系统文档: 使用repo工具克隆代码 (#461) + +commit 01090de77ef263b81edf449b77320d5fa28569de +Author: LoGin +Date: Sun Dec 3 14:40:13 2023 +0800 + + 使用DragonStub引导riscv下的DragonOS内核 (#460) + +commit 4fda81ce81939d83b74c8042d6fb4223deff3685 +Author: LoGin +Date: Sat Nov 25 12:07:39 2023 +0800 + + 使得DragonOS kernel 能为riscv64编译通过(尚未能启动) (#457) + + * 使得DragonOS kernel 能为riscv64编译通过(尚未能启动) + + * 修正了系统调用号声明不正确的问题,同时添加了编译配置文档 + +commit a1fd1cf1cbe6934221f95213ce02b21f21add225 +Author: LoGin +Date: Thu Nov 23 21:12:16 2023 +0800 + + 把tar的二进制镜像源更换为国内源 (#458) + +commit cc5feaf67b914ecf701abcba70c01da149755491 +Author: Jomo <2512364506@qq.com> +Date: Thu Nov 23 21:04:32 2023 +0800 + + bugfix: 修复因rsdp v1 v2版本问题,导致ACPI无法正常初始化的bug (#454) + + bugfix: 修复因rsdp v1 v2版本问题,导致ACPI无法正常初始化的bug + +commit c89d0c12377cd406a9b7465d7c087aeb9faefa51 +Author: LoGin +Date: Tue Nov 21 20:24:43 2023 +0800 + + 修复bootstrap的一系列脚本忘了source最新的shell rc的问题 (#453) + +commit c75089286e9d49cef8d039446bf570c1bd4d2550 +Author: LoGin +Date: Tue Nov 21 13:42:18 2023 +0800 + + 调整脚本,使得能够创建riscv的磁盘镜像,并引导进入riscv下的grub (#450) + + * 安装musl toolchain以及riscv相关的工具链 + + * 调整脚本,使得能够创建riscv的磁盘镜像,并引导进入riscv下的grub + + ```shell + export ARCH=riscv64 + make write_diskimage + make qemu + ``` + + 即可在serial_opt.txt看到进入grub的提示信息 + +commit 48a3baa9b1d24dd1fc037cd9961945708c5c9b71 +Author: LoGin +Date: Tue Nov 21 13:42:06 2023 +0800 + + 安装musl toolchain以及riscv相关的工具链 (#449) + +commit 84e7f7100664123d8ebc6b0f983c96242d15c396 +Author: LoGin +Date: Mon Nov 20 15:51:41 2023 +0800 + + 添加赞助商雅安数字经济运营有限公司的信息到readme (#451) + +commit 99dbf38d2e279ea70e9e186753fd37001dbb749f +Author: LoGin +Date: Sun Nov 19 11:42:53 2023 +0800 + + bugfix: 当物理机具有多个memory area的时候,无法正确使用这些区域的问题.以及在内核代码处出现内存空洞而导致无法正常运行的问题. (#448) + + * bugfix: 当物理机具有多个memory area的时候,无法正确使用这些区域的问题.以及在内核代码处出现内存空洞而导致无法正常运行的问题. + + 解决方案: + 1. 分区域把空闲页添加到buddy + 2. 将内核链接到16M的位置,以避免uefi带来的内存空洞. + + 这个值是因为我看到linux的救援内核也是在16M的地址,因此猜测厂商不会使用这块内存. + 尽管uefi规范讲的是固件可以采用任何地址,内核需要使用内核重定位技术去避免遇到内存空洞,但我没有这么做. + +commit 46e234aef65c081393fb7652e0ad2bae26786ce4 +Author: LoGin +Date: Fri Nov 17 21:25:15 2023 +0800 + + 使用cargo管理一些C文件的编译,并且移动部分汇编到arch目录 (#447) + + * 使用cargo管理main.c的编译 + + * 使用build-scripts编译架构相关的c代码 + + * 删除elf.h + +commit e4600f7f7d8f2295dbf970812ab1fcab81eb6eae +Author: Jomo <2512364506@qq.com> +Date: Fri Nov 17 21:23:01 2023 +0800 + + Kconfig (#432) + + * 内核编译配置 + + * 将kernel.config的解析代码搬入crate + + * 将设置feature函数放入CargoHandler中 + +commit 11f78b73e7b18ef04e05e63612f8027eda0740e7 +Author: LoGin +Date: Fri Nov 17 20:05:57 2023 +0800 + + 使用kernel-build脚本来编译所有的asm文件 (#445) + +commit e4fb6c9754e535861a5e67db29fb6e8c2e9c8469 +Author: LoGin +Date: Fri Nov 17 12:26:10 2023 +0800 + + 美化readme (#446) + + * 美化readme + +commit e26ca418df7af685226d12d7f22fe1785ba163e4 +Author: LoGin +Date: Fri Nov 17 11:26:26 2023 +0800 + + 把内核构建脚本单独独立成一个crate (#444) + +commit a0c98cd4df88474f2efd927930862df50e016b73 +Author: Jomo +Date: Thu Nov 16 21:37:04 2023 +0800 + + 解决textui framework初始化成功后串口无法正常换行 (#443) + +commit edaf015400f83967c2fc940f07be0dbb5792246f +Author: LoGin +Date: Wed Nov 15 17:17:56 2023 +0800 + + 默认安装gnu tar到dragonos的/usr/bin目录下 (#442) + +commit 0fb515b011967be01006cf88d788793dbbce2967 +Author: LoGin +Date: Wed Nov 15 15:39:35 2023 +0800 + + 完善pipe系统调用以及openat系统调用 (#441) + +commit bf4a48994a2b284ee34aa49a66b4dec1b6ebc07c +Author: LoGin +Date: Mon Nov 13 23:02:21 2023 +0800 + + 新增系统调用,并对照linux-6.1.9改写sys_wait4 (#440) + + * 1. 新增以下系统调用 + - SYS_LSTAT + - SYS_READV + - SYS_ACCESS + - SYS_UNLINK + - SYS_CHMOD + - SYS_FCHMOD + - SYS_UMASK + - SYS_SYSINFO + - SYS_CLOCK_GETTIME + - SYS_FCHMODAT + - SYS_FACCESSAT + + 2. 修改sys_wait4,使得其部分符合Linux的行为(还是有些地方不符合的,详情请对比linux-6.1.9的sys_wait4接口) + +commit 9b0abe6da72176086c3188e0599fda950562668f +Author: LoGin +Date: Sun Nov 12 21:23:48 2023 +0800 + + 添加access、faccessat、faccessat2 (#439) + +commit 0d9b7d9240ef65c3e603a371db57a80d26a7b9dd +Author: LoGin +Date: Sun Nov 12 18:44:15 2023 +0800 + + 添加prlimit64系统调用 (#438) + + 注意: 目前仅支持读取默认的rlimit值,尚不支持设置rlimit值. + +commit 4a2d7191a3a6208b72e1d163c0235f566720f79a +Author: LoGin +Date: Sun Nov 12 17:53:36 2023 +0800 + + bugfix: 解决shell在exec的时候传递的argv不正确的bug (#437) + +commit 709498cac1f2134b2a5e089366ee7136ee029369 +Author: LoGin +Date: Sun Nov 12 17:40:45 2023 +0800 + + feat: sys_readlink && sys_readlinkat (#436) + +commit be8cdf4b8edcd9579572672411f4489039dea313 +Author: LoGin +Date: Sun Nov 12 16:36:17 2023 +0800 + + 增加getrusage,并把apic timer的频率调整为系统HZ (#435) + +commit 02e249f30bfe08b8a5cde1226ca0161f9e370927 +Author: LoGin +Date: Sun Nov 12 14:11:33 2023 +0800 + + 添加uid、gid的系统调用(暴力封装返回0) (#434) + +commit ea8ad4d42e52016fe581a2451165146f109dfd6e +Author: LoGin +Date: Sun Nov 12 13:40:17 2023 +0800 + + 修正fork的时候没有正确拷贝vm holes的bug (#433) + +commit c47fe90440fb7c6c82953e28a4b9597b22924758 +Author: LoGin +Date: Thu Nov 9 18:20:27 2023 +0800 + + 增加accept4系统调用 (#431) + +commit 393f691574844544e76231379e4938e9046be7b9 +Author: LoGin +Date: Thu Nov 9 16:48:45 2023 +0800 + + 增加gettid以及线程组group leader相关的逻辑 (#430) + + * 增加gettid以及线程组group leader相关的逻辑 + +commit 0facf623d638816d7d01a700e19a52c3c16a8fa1 +Author: LoGin +Date: Thu Nov 9 00:10:34 2023 +0800 + + 修正文件open和写入的错误 (#429) + + 1. 修正文件open的时候可能错误的把inode清空的问题(如果当前inode是mknod创建的) + 2. 修正fat和block device中,对文件写入部分的错误问题 + +commit 04babc3faba81997149ed11fda2ed03b4bbf4700 +Author: MemoryShore <105195940+MemoryShore@users.noreply.github.com> +Date: Wed Nov 8 21:42:51 2023 +0800 + + 实现fat文件系统的truncate方法 (#428) + +commit df2f5051ac645f600f2aefcaff3a9608b2c0de3f +Author: LoGin +Date: Wed Nov 8 20:01:51 2023 +0800 + + 添加read the docs yml文件 (#427) + +commit 5eaf536d5b81c234f9aea560e0c9d994fac3eb76 +Author: LoGin +Date: Wed Nov 8 19:41:08 2023 +0800 + + 添加初始化DragonOS的Rust-Musl工具链的脚本. (#426) + +commit 7b32f5080f42bcbf7d2421013f3ea53c776a063c +Author: LoGin +Date: Tue Nov 7 21:39:27 2023 +0800 + + 增加内存分配日志监视器 (#424) + + * 完成内存日志监视,并输出日志到文件 + * 修复进程退出后,procfs查看进程status文件会崩溃的问题 + * 修复signal唤醒进程的判断条件问题 + +commit 70a4e5550a9fb49b537092287c3ddc36448c5b78 +Author: LoGin +Date: Tue Nov 7 20:32:06 2023 +0800 + + 使用rust重写了apic的驱动 (#425) + + * 使用rust重写了apic的驱动。 + + * 修正signal和调度器的部分加锁逻辑,增加回退策略。 + + * 把pcb的flags字段替换为无锁的 + + * 使用cargo管理apic的编译 + + * 删除makefile中指定PIC的变量 + + --------- + + Co-authored-by: Gou Ngai + Co-authored-by: 櫻井桃華 <89176634+TihayaKousaka@users.noreply.github.com> + +commit 4935c74f326cd4e0854959c0ec8ab1d726c05e41 +Author: LoGin +Date: Mon Nov 6 17:27:05 2023 +0800 + + 添加自定义的crc库(支持crc64) (#423) + +commit 1effcfe519c06f04303340281fe9f62096184a74 +Author: GnoCiYeH +Date: Sun Nov 5 23:15:46 2023 +0800 + + 修复readdir以及读磁盘时buf传错问题 (#422) + + * 修复readdir以及读磁盘时buf传错问题 + + * fix potential memory problem + + --------- + + Co-authored-by: longjin + +commit 1603395155fc166de0ac5f80369526e196526ed2 +Author: GnoCiYeH +Date: Sat Nov 4 21:39:44 2023 +0800 + + 支持syscall快速系统调用指令 (#417) + + * 支持syscall快速系统调用指令 + + --------- + + Co-authored-by: LoGin + +commit 2f6f547ae05c19871138e558ba6943ff07f4c68c +Author: GnoCiYeH +Date: Sat Nov 4 21:35:25 2023 +0800 + + Patch fix sched (#419) + + 1.解决waitqueue sleep的时候,由于preempt count不为0,导致sched失败,从而导致该waitqueue下一次wakeup时,会把pcb多次加入调度队列的bug + 2.修复socket inode 的read和write方法里面没有使用no_preempt的问题 + 3. 修复cpu0的内核栈由于脏数据导致new_idle的时候set pcb报错的问题 + + --------- + + Co-authored-by: longjin + +commit 8058ccb307bbaf06a5810af32bcba3e41ab9fb93 +Author: LoGin +Date: Fri Nov 3 21:01:09 2023 +0800 + + 修复bootstrap.sh未能自动更换gcc镜像源, 未能自动安装docker的问题 (#418) + +commit d470019b1e675a04473cbb3c3eeaf180c8665e6d +Author: LoGin +Date: Wed Nov 1 22:12:19 2023 +0800 + + patch add mini backtrace (#416) + + * support rust panic backtrace + + mini-backtrace has llvm's unwind cpp source to support backtrace/unwind. + as unwind/backtrace needs dynamically allocates memory, mini-backtrace + uses stack memory to capture fixed number of backtrace to avoid heap + allocation. + as unwind library needed, it needs to turn on eh_frame_hdr + + * 修改忘了生成kernel.elf的问题 + + * 设置backtrace是默认的feature + + --------- + + Co-authored-by: Yao Zhao + +commit 8b3d1688daac2aaf4e87403ecda5467a01464f81 +Author: yuyi2439 <68320855+yuyi2439@users.noreply.github.com> +Date: Wed Nov 1 21:11:55 2023 +0800 + + 把pci驱动的读取acpi mcfg的代码,调整为从新的acpi驱动来读取 (#413) + + * 把pci驱动的读取acpi mcfg的代码,调整为从新的acpi驱动来读取 + +commit 971462be94ba0a5c74af7a5f9653dfabd4932a63 +Author: GnoCiYeH +Date: Wed Nov 1 20:55:57 2023 +0800 + + 添加thread和futex机制 (#411) + + * 初步实现clone系统调用 + + * 实现了线程,初步实现futex机制,添加了几个小的系统调用 + + * 更改pcb引用计数问题 + + * 解决死锁bug + + --------- + + Co-authored-by: LoGin + +commit 665f4a7707e33f3b4d2fde77113fa3d13b5b52c4 +Author: Chiichen <39649411+Chiichen@users.noreply.github.com> +Date: Wed Nov 1 14:18:00 2023 +0800 + + 更新了使用clangd的.gitignore (#415) + + Co-authored-by: chiichen + +commit 77799ccaaca276fe127448d169f0e035837cce44 +Author: Wu Mianzhi <31810920+Hdksg10@users.noreply.github.com> +Date: Mon Oct 30 00:08:52 2023 +0800 + + 完成e1000e驱动 (#393) + + * 测试RESET + + * 测试RESET + + * 基于轮询的实现 + + * 规范化部分unsafe的使用 + + * 完成中断处理函数,同时去除了不必要的内存拷贝行为,准备编写napi机制 + + * 实现现有协议栈下的部分napi机制;修复了内存泄漏的问题;添加了一部分代码注释 + + * 去除部分无用代码 + + * 去除一些无用代码 + + * 适配新的驱动模型 + + * 完成msi中断测试 + + * 去除一些无用代码 + + * 格式化代码 + + * 增加了一些注释,提高代码可读性 + + * 去除无关文件 + + * 优化了读取mac地址的方式,提高可读性 + +commit fbe6becd6dd3cd72643707e0088f20364ac1b166 +Author: LoGin +Date: Thu Oct 26 23:08:39 2023 +0800 + + 添加rust重构版本的HPET驱动和tsc驱动,并使用HPET校准tsc频率和cpu总线频率 (#412) + + * 添加rust重构版本的HPET驱动和tsc驱动,并使用HPET校准tsc频率和cpu总线频率 + + * 把hpet.c移动到arch文件夹下 + +commit ad1d649eddee4aa8ac81b2f44bc99da462a6a813 +Author: GnoCiYeH +Date: Tue Oct 24 19:59:01 2023 +0800 + + 更新系统调用号 (#410) + + * 更新系统调用号 + + * 更改DragonReach和relibc版本 + + * update + + * update + + * fix warning + + --------- + + Co-authored-by: longjin + +commit f4082b86b15989a1d43e62050c6ba9b363c91ece +Author: LoGin +Date: Tue Oct 24 16:40:49 2023 +0800 + + 更改系统调用的寄存器传参顺序 (#409) + +commit 40314b30ab2a7e1fd06a05a00f693e644e446035 +Author: Xiaoye Zheng +Date: Tue Oct 24 14:31:56 2023 +0800 + + DragonOS虚拟化 (#389) + + * try some ioctl flow & kvm device + + * add sys ioctl + + * 删掉一些debug信息 + + * 修改run-qemu.sh脚本,在QEMU中enable vmx + + * 修改cr0,cr4,msr寄存器enable VMX operations + + * enable vmx operation + + * allocate memory for vmcs with bug + + * allocate memory for vmcs + + * cpu virt-50% + + * single vcpu virt + + * add vmcs fields + + * CPU virt overall flow with bug + + * run vmlaunch success + + * run CPU virt with bug + + * 成功运行non-root模式的guest + + * 成功运行vmexit,进入vmx_return函数 + + * 成功运行vmlaunch, vmexit, vmresume + + * vmexit handler with bug + + * 完成vmexit cpuid handler + + * fix vmresume guest状态恢复的bug + + * 增加vm ioctl + + * refactor kvm 50% + + * refactor kvm 80% + + * FIXME: kvm vmlaunch failed + + * vmlaunch success + + * FIXME: output error + + * update guest_rsp + + * cpu virt refactor + + * add mmu related struct + + * add usermemory region workflow + + * add mem-virt workflow + + * add mem-virt + + * refactor code + + * add vcpu ioctl set_regs + + * rename hypervisor to vm & solve some deadlock bugs + + * workout mem pipeline + + * fix vmcs control setting bugs + + * refactor segment regs initialization + + * resovle conficts + + * resovle conficts + + * format code + +commit 485e2487616b1d33776b63724d4abc1ae8f506e8 +Author: LoGin +Date: Tue Oct 24 14:19:26 2023 +0800 + + 修改脚本,只有当磁盘未安装Grub的时候,才执行grub-install. 节省编译时间 (#408) + +commit 46795849a29eef77fd6f7af548d05ee6e654c5bb +Author: LoGin +Date: Tue Oct 24 13:56:57 2023 +0800 + + 修复bootstrap.sh安装顺序导致的问题 (#407) + +commit 3c82aa56d1b784ea7371100b3e906365be8332fd +Author: Chiichen <39649411+Chiichen@users.noreply.github.com> +Date: Tue Oct 24 12:02:20 2023 +0800 + + Signal refactor (#402) + + * 初步完成对 signal_types 和 部分signal代码的初始化 + + * 重构了一部分架构相关代码进入 arch 中 + + * 基本修改完成,编译通过,后续补上系统调用 + + * signal基本完成,能实现 Sigaction 系统调用 + + * 增加了一组枚举抽象 + + * 进一步重构了一部分C风格的代码 + + * 继续重构了一部分C风格代码 + + * 继续完善了一部分逻辑 + + * 修改了部分代码逻辑 + + * 补充了 fork 中复制信号信息的逻辑 + + * 修复了 kallsysms 未转义引号的问题 + + * 修复了无法跳转到 sigreturn 的bug + + * 调通了 signal + + * 实现了 signal 架构抽象层的 trait + + * 为信号提供了默认处理函数 + + * 基本完成了 signal 的大体逻辑 + + * 修复了 Sigreturn 的一个小错误,格式化 + + * 修复了一个编译器漏报错误 + + * 删除了多余的代码 + + * 修改测试程序为链接 relibc + + * 修复了信号处理过程中浮点寄存器错误保存的问题 + + * 修复了一个结构体错误引起的无法在relibc下正确运行的错误 + + * 修复了链接 relibc 时无法正常从信号处理返回的 bug + + * 修复了 signal 处理流程中 rsp 指针错误导致的浮点运算触发GP + + * 修复了一个死锁问题,解决了默认处理函数无法进入调度导致的bug + + * 修复了一些错误 + + * 修改了 relibc 依赖版本号 + + * 删除了多余的 imports + + * 删除一些debug日志 + + * 删除内核 signal.h 文件 + + * 删除一个依赖项 + + * 删除了 binding 相关依赖项 + +commit d7f5742a206c6c25ed30009796eb8248429f0a1e +Author: LoGin +Date: Mon Oct 23 21:40:39 2023 +0800 + + 初步编写cpu信息获取的代码 (#406) + + 1. 启动时从acpi获取所有的cpu信息并存到SMP_BOOT_DATA + 2. 注册cpu subsystem/bus到sysfs(暂时未添加内容) + + todo: + 1. build_cpu_map(在X86_64SmpManager中) + 2. 实现cpu mask + 3. 把cpu设备注册到sysfs + +commit 7eda31b2f07c6ef41dc0d2bd13051f0fce5e5976 +Author: LoGin +Date: Sun Oct 22 22:00:16 2023 +0800 + + 在Sysfs中引入ACPI Firmware (#405) + + - bugfix: multiboot2启动的信息因为没及时转存导致后面无法从其中进行查询的bug + - feature: 把acpi表、acpi bus加入sysfs + +commit 01bd5258cf467326819c77584713fbc6ffe4fb32 +Author: LoGin +Date: Sun Oct 22 12:22:41 2023 +0800 + + 解决shell无法输入大写字母'P'的问题 (#404) + +commit a03c4f9dee5705207325c56629c0ccd219168f10 +Author: LoGin +Date: Fri Oct 20 22:11:33 2023 +0800 + + 设备驱动模型:完善platform bus相关内容。并注册串口到sysfs (#403) + + * 完成初始化platform bus + * 删除旧的sysfs + * 把uart驱动移动到tty/serial文件夹下 + * 完成将串口挂载到sysfs + * 修复vfs系统调用未能follow symlink的问题 + * 修复shell未能正确获取pwd的问题 + +commit 06d5e247267cb65b84a80f219853ccd0f384b16e +Author: LoGin +Date: Wed Oct 11 00:53:15 2023 +0800 + + 完善设备驱动模型,基于kset、kobj来维护对象之间的关系 (#401) + + * 使用kobj和kset管理/sys文件夹下的对象 + + * 修改notifier,把action从u64换为泛型。 + + * 完善设备驱动模型,基于kset、kobj来维护对象之间的关系 + +commit 6abb8bd7c0ee7746f0b6cf682a0c4d112a2ef6a3 +Author: LoGin +Date: Mon Oct 9 01:55:58 2023 +0800 + + 在github workflow的工具链配置文件里面添加rust-src组件 (#400) + +commit 9e9ffedfc59cd89f4cdbd7984abbb2ac19ea9575 +Author: Plucky923 <107762234+Plucky923@users.noreply.github.com> +Date: Mon Oct 9 01:11:14 2023 +0800 + + syscall: 完善syscall代码 (#387) + + * syscall: 完善syscall代码 + + 修改代码使这段代码可以使用语法糖。修改SYS_READ和SYS_WRITE的安全检查为userbuffer + + Signed-off-by: plucky + + * syscall: 修改SYS_READ和SYS_WRITE的权限检查为userbuffer + + Signed-off-by: plucky + + * syscall: 有不知道如何修改的错误 + + Signed-off-by: plucky + + * syscall: 修改SYS_READ和SYS_WRITE并编译通过 + + Signed-off-by: plucky + +commit 865f4ba4cdce23b154844d6d297f75033f3dcf70 +Author: GnoCiYeH +Date: Mon Oct 9 01:10:14 2023 +0800 + + 修改shell执行exec时传参错误问题 (#399) + + * 修改shell执行exec时传参错误问题 + +commit b7b843beddea12cdedda90f6129b7c9980876112 +Author: GnoCiYeH +Date: Mon Oct 9 00:58:08 2023 +0800 + + wait4系统调用支持options字段 (#398) + +commit 2dbef7859f0af395ccec348f17cf0b79ed56e003 +Author: GnoCiYeH +Date: Mon Oct 9 00:28:08 2023 +0800 + + 命名管道系统调用以及文件系统兼容特殊文件类型的接口 (#397) + + * 修复pipe2在读端或写端关闭后还阻塞问题。 + + * 实现命名管道机制,增加特殊文件类型兼容普通文件系统的接口。 + + * 普通文件系统能够适配特殊文件(命名管道等) + +commit 34e6d6c80f36494088db3284f85d1a2c63aa18a8 +Author: yuyi2439 <68320855+yuyi2439@users.noreply.github.com> +Date: Sun Oct 8 14:26:17 2023 +0800 + + 实现free指令+修复 mountfs的内存泄露问题(#394) + + * 实现meminfo文件 + + * 成功实现free指令,添加了一些string有关函数,并进行一些无影响的小改动 + + + * 解决内存泄露的问题:mountfs inode的wrap方法使用了Arc::into_raw而没有from_raw,导致inode始终无法释放 + + --------- + + Co-authored-by: LoGin + Co-authored-by: longjin + +commit afc95d5c2541c27c762091ad38fdffabe355db5a +Author: YJwu2023 +Date: Tue Oct 3 12:09:29 2023 +0800 + + 完善pci中断的设计 (#392) + + * 完善pci中断的设计 + +commit 876cb89ecf7c1bf1646bfc392efcbafacad2262f +Author: GnoCiYeH +Date: Tue Oct 3 12:03:34 2023 +0800 + + 修复pipe2在读端或写端关闭后还阻塞问题 (#396) + + * 修复pipe2在读端或写端关闭后还阻塞问题。 + + * update + + * update + + * 修改cloexec + + --------- + + Co-authored-by: longjin + +commit fba5623183378da6b120caafca120615328efa2e +Author: LoGin +Date: Mon Oct 2 20:46:19 2023 +0800 + + 引入intertrait库,支持trait之间的互相转换 (#395) + + * 能过编译(test还没法跑) + + * 初始化intertrait转换库 + + * update license of intertrait + +commit bb0e4d4131046a69bbccdc0cdf1d5db51a2c6126 +Author: GnoCiYeH +Date: Sat Sep 30 16:36:06 2023 +0800 + + 使用DragonReach启动shell,修改getdents (#391) + + * 使用DragonReach启动shell,修改getdents + + * 更改关闭pipe时断言报错问题,以及DragonReach启动shell阶段版本 + + * 修改目录结构 + + * update + + * 解决小问题 + + * 调整dragon reach版本号 + + * 设置make clean的时候不清空应用程序的缓存。 + 指定relibc版本号 + + --------- + + Co-authored-by: longjin + +commit 0dd8ff43325b494ea777dbe6e552fdc77b9dabc8 +Author: YJwu2023 +Date: Thu Sep 21 23:23:57 2023 +0800 + + 添加中断 (#370) + + * 添加中断 + + * dhcp更改为全局socketset + + * 解决异常中断的问题,使得能够使用中断来处理网卡数据 + + --------- + + Co-authored-by: longjin + +commit 6b4e7a2972cc06663754c0e35a0e541987006fa4 +Author: LoGin +Date: Tue Sep 19 19:46:59 2023 +0800 + + 增加kernfs (#386) + + * 增加kernfs + + * kernfs文档 + +commit ae5ede03bebe5c4b593ad7a350f0945f1367be7c +Author: LoGin +Date: Mon Sep 18 07:38:04 2023 +0800 + + bugfix: bus/device manager对卸载逻辑的处理错误 (#385) + + * 移动位置 + + * bugfix: bus/device manager对卸载逻辑的处理错误 + +commit 7ae679ddd6481897a86523a52fad3b060254fa5b +Author: LoGin +Date: Sun Sep 17 15:41:01 2023 +0800 + + ahci内存越界问题修复+ mm的bug修复+在rust中解析acpi table (#384) + + * bugfix: 修复了Flusher Drop的时候没有自动刷新TLB的bug + + * 解决进程管理未初始化时,trap.c尝试打印pid导致错误的问题 + + * 设置kmalloc默认强制清0 + + * 修复ahci驱动的内存越界问题 + * 修复mmio buddy忘记归还buddy block的问题 + * 新增acpi模块,暂时能解析acpi tables + +commit 11110997465e858757da54b5ce28d7c22690aaff +Author: hanjiezhou +Date: Sat Sep 16 20:14:56 2023 +0800 + + 修改 tty 中resize bug (#383) + +commit 71474bc6829b3cd831df7ce24ea059557996524d +Author: LoGin +Date: Sat Sep 16 16:16:43 2023 +0800 + + 修复drop fd时,文件描述符引用不为0的问题 (#382) + +commit de71ec259cd21c782f4031b01635eb8ad3df1943 +Author: LoGin +Date: Fri Sep 15 19:44:11 2023 +0800 + + 修正由于init proc union导致的无法运行的问题 && 修正由于内核线程启动后默认sleep的行为导致init进程无法正常运行的bug (#381) + + 1. 修正由于init proc union导致的无法运行的问题 + 2. 修正由于内核线程启动后默认sleep的行为导致init进程无法正常运行的bug + +commit 1496ba7b24a5e6954291ca9643b9f3cec567479a +Author: LoGin +Date: Fri Sep 15 14:58:19 2023 +0800 + + 进程管理模块重构完成 (#380) + + * 添加新版pcb的数据结构 (#273) + + * 将pcb中的内容分类,分别加锁 (#305) + + * 进程管理重构:完成fork的主体逻辑 (#309) + + 1.完成fork的主体逻辑 + 2.将文件系统接到新的pcb上 + 3.经过思考,暂时弃用signal机制,待进程管理重构完成后,重写signal机制.原因是原本的signal机制太烂了 + + * chdir getcwd pid pgid ppid (#310) + + + --------- + + Co-authored-by: longjin + + * 删除旧的fork以及signal的代码,并调整fork/vfork/execve系统调用 (#325) + + 1.删除旧的fork + 2.删除signal相关代码,等进程管理重构结束之后,再重新写. + 3.调整了fork/vfork/execve系统调用 + + * 实现切换进程的代码 (#331) + + + + * 实现切换进程的代码 + + * Patch modify preempt (#332) + + * 修改设置preempt的代码 + + * 删除rust的list和refcount + + * 为每个核心初始化idle进程 (#333) + + * 为每个核心初始化idle进程 + + * 完成了新的内核线程机制 (#335) + + * 调度器的pcb替换为新的Arc,把调度器队列锁从 RwSpinLock 替换为了 SpinLock (#336) + + * 把调度器的pcb替换为新的Arc + + * 把调度器队列锁从 RwSpinLock 替换为了 SpinLock ,修改了签名以通过编译 + + * 修正一些双重加锁、细节问题 + + --------- + + Co-authored-by: longjin + + * github workflow自动检查代码是否格式化 + + * cache toolchain yml + + * 调整rust版本的waitqueue中的pcb为新版的pcb (#343) + + * 解决设置rust workspace带来的“工具链不一致”的问题 (#344) + + + * 解决设置rust workspace带来的“工具链不一致”的问题 + + 更改workflow + + * 调整pcb的sched_info和rwlock,以避免调度器死锁问题 (#341) + + * 调整pcb的sched_info和rwlock,以避免调度器死锁问题 + + * 修改为在 WriterGuard 中维护 Irq_guard + + * 修正了 write_irqsave方法 + + * 优化了代码 + + * 把 set state 操作从 wakup 移动到 sched_enqueue 中 + + * 修正为在 wakeup 中设置 running ,以保留 set_state 的私有性 + + * 移除了 process_wakeup + + * 实现进程退出的逻辑 (#340) + + 实现进程退出的逻辑 + + * 标志进程sleep + + * 修复wakeup的问题 + + --------- + + Co-authored-by: longjin + + * rust 重构 completion (#350) + + * 完成了completion的基本结构,待完善上级调用 + + * 用SpinLock保护结构体并发安全 + + * 修改原子变量为u32,修复符号错误 + + * irq guard + + * 修改为具有内部可变性的结构体 + + * temp fix + + * 修复了由于进程持有自旋锁导致的不被调度的问题 + + * 对 complete 系列方法上锁,保护 done 数据并发安全 + + * 移除了未使用的依赖 + + * 重写显示刷新驱动 (#363) + + * 重构显示刷新驱动 + + * Patch refactor process management (#366) + + * 维护进程树 + + * 维护进程树 + + * 更改代码结构 + + * 新建进程时,设置cwd + + * 调整adopt childern函数,降低开销 + + --------- + + Co-authored-by: longjin + + * waitqueue兼容C部分 (#351) + + * PATH + + * safe init + + * waitqueue兼容C部分 + + * waitqueue兼容C部分 + + * 删除semaphore.c,在ps2_keyboard中使用waitqueue + + * 删除semaphore.c,在ps2_keyboard中使用waitqueue + + * current_pcb的C兼容 + + * current_pcb的C兼容 + + * current_pcb的C兼容 + + * fmt + + * current_pcb的兼容 + + * 针对修改 + + * 调整代码 + + * fmt + + * 删除pcb的set flags + + * 更改函数名 + + --------- + + Co-authored-by: longjin + + * merge master + + * Patch debug process management refactor (#372) + + * 能够调通,执行完textui_init + + * 能跑到initial kernel thread + + * fmt + + * 能够正常初始化所有服务(尚未能切换到用户程序) + + * 删除部分无用的extern + + * 存在问题:ap处理器启动后,bsp的smp_init函数return之后就出错了,怀疑是栈损坏 + + * 解决smp启动由于未换栈导致的内存访问错误 + + * debug + + * 1 + + * 1 + + * lock no preempt + + * 调通 + + * 优化代码,删除一些调试日志 + + * fix + + * 使用rust重写wait4 (#377) + + * 维护进程树 + + * 维护进程树 + + * 更改代码结构 + + * 新建进程时,设置cwd + + * 调整adopt childern函数,降低开销 + + * wait4 + + * 删除c_sys_wait4 + + * 使用userbuffer保护裸指针 + + --------- + + Co-authored-by: longjin + + * 消除warning + + * 1. 修正未设置cpu executing的问题 + + * 修正kthread机制可能存在的内存泄露问题 + + * 删除pcb文档 + + * 删除C的tss struct + + --------- + + Co-authored-by: Bullet <93781792+GP-Bullet@users.noreply.github.com> + Co-authored-by: Chiichen <39649411+Chiichen@users.noreply.github.com> + Co-authored-by: hanjiezhou + Co-authored-by: GnoCiYeH <118462160+GnoCiYeH@users.noreply.github.com> + Co-authored-by: houmkh <1119644616@qq.com> + +commit b087521e07f601b30e3d48df788fcc2f09f19566 +Author: Chiichen <39649411+Chiichen@users.noreply.github.com> +Date: Wed Sep 13 18:01:52 2023 +0800 + + 完善设备驱动模型&调试串口驱动 (#379) + + * 完成了基本架构重构,正在进行兼容 + + * 重构了所有 Device Driver ,还没有接上具体设备 + + * 基本把 Uart 接上了,还没有测试 + + * 初步完成系统设备初始化 + + * 初步重构 BlockDevice ,使其兼容新的 Device 结构 + + * 修改文件系统内的部分函数调用以满足重构后的接口 + + * 测试完 Uart 设备的功能 + + * 移除了自动添加的文件 + + * 修复了 warning 和部分格式 + + * 解决warning,并且修正sysfs初始化的位置 + + * Patch fix + + * 删除了 sysinfo 的默认实现 + + * 删除了字符设备读写的 offset 参数 + + * 修复了 warning 和一些小逻辑错误 + + --------- + + Co-authored-by: longjin + +commit 9029414af2089cbe7d2d2097be2e116c09beb6dd +Author: zhaoyao73 +Date: Wed Sep 13 01:49:03 2023 -0400 + + use demangled names (#375) + + there is no change for c symbols + rust symbols name will be more readable + +commit 22c9db312a5f02b48a1bf7853dc53434da65e28a +Author: hanjiezhou +Date: Wed Sep 13 00:58:01 2023 +0800 + + Patch pipe2 (#364) + +commit 68312d3c68b9df288589f9636417745d46520ad2 +Author: Xshine +Date: Wed Sep 13 00:26:41 2023 +0800 + + 修正造成 http server 的错误 (#378) + + * 修正造成 http server 的错误 + +commit 285de542f3ddb09bfdcad0a7022bd722f4f1cace +Author: zhaoyao73 +Date: Wed Sep 6 06:08:52 2023 -0400 + + modify kernel link script (#373) + + put rust text between _text and _etext, so rust symbols are included in + kallsyms, traceback could use them. + + modify grub_auto_install.sh to add arch linux support + +commit 3b0bf43bbb196a74a64cee8ecd2d4eb884c5e9ee +Author: zhaoyao73 +Date: Mon Sep 4 00:57:52 2023 -0400 + + fix compiler warnings in pci_irq.c (#371) + + Co-authored-by: Yao Zhao + +commit 607783d7414735d1dc54afb0c7346ed8e13303a2 +Author: zhaoyao73 +Date: Sun Sep 3 01:36:02 2023 -0400 + + fix pci_irq.c - memory leak - wrong irq_name allocated length (#367) + + add function declaration to avoid compiling warning + + add extra packages need for build + + Co-authored-by: Yao Zhao + +commit d9113303d8e1d449a122f7a5f66453fbe7c26a46 +Author: LoGin +Date: Sun Sep 3 13:33:27 2023 +0800 + + relibc与旧的C库同时开始编译 (#369) + +commit 4895ff6968ae8f24c7a0d55dce6ae23082d60e3b +Author: yuyi2439 <68320855+yuyi2439@users.noreply.github.com> +Date: Sat Sep 2 00:27:41 2023 +0800 + + fix: DragonOS-Community/DragonOS#358 (#361) + +commit 8479f19979aa9ddc4e383651cc56a7a24bd94e21 +Author: GnoCiYeH <118462160+GnoCiYeH@users.noreply.github.com> +Date: Fri Sep 1 21:46:36 2023 +0800 + + 添加rust-gdb调试内核文档 (#357) + + * 编写使用GDB调试内核文档 + +commit 863a3cff06e618a5f0fc03920dfd5732452344c9 +Author: LoGin +Date: Thu Aug 31 20:25:00 2023 +0800 + + 添加与rust std接口相同的once库 (#353) + +commit a3ef8f8ad5248e3424113871950eb9c80eeeb99e +Author: GnoCiYeH <118462160+GnoCiYeH@users.noreply.github.com> +Date: Thu Aug 31 19:52:32 2023 +0800 + + 修改RamFS目前存在的BUG (#354) + + * 修改RamFS目前存在的BUG + +commit c757940bd61b0125e037a59eb77565e42470201b +Author: YJwu2023 +Date: Thu Aug 31 17:54:49 2023 +0800 + + 优化makefile (#352) + +commit 2dd9f0c7503d1a325713764fedbce06fcab3a06b +Author: LoGin +Date: Mon Aug 28 15:54:52 2023 +0800 + + mmio buddy新增guard,把映射的职责交由其守卫进行处理,并且守卫被drop的时候自动释放内存 (#346) + + * mmio buddy新增guard,把映射的职责交由其守卫进行处理,并且守卫被drop的时候自动释放内存 + +commit 8d94ea66a3eb3e02039730c8d08e9bead8c344b8 +Author: YJwu2023 +Date: Mon Aug 28 15:43:07 2023 +0800 + + Patch ahci (#348) + + * Modify the ahci module and delete the useless c code + + 修改ahci使其不再依赖旧的pci函数 + 删除旧的pci、msi函数代码 + +commit f5df0e79c67a9508bc6a50fccded9dec78e7ed9d +Author: LoGin +Date: Mon Aug 28 15:29:00 2023 +0800 + + 解决userbufferwriter的长度错误问题,并修复gettimeofday的pagefault问题 (#349) + + * 解决userbufferwriter的长度错误问题,并修复gettimeofday的pagefault问题 + +commit ddb9d91712b6e87aa15b9cc4a8fdec8ae0996a5e +Author: Xshine +Date: Sun Aug 27 15:54:19 2023 +0800 + + 将 io 移动至 vfs 目录,并修正引用路径 (#339) + + * 将 io 移动至 vfs 目录,并修正引用路径 + + * fix bug in makefile + +commit e92d02281005bac31fe80e9070ac4a2a6cef0419 +Author: LoGin +Date: Sat Aug 26 21:36:13 2023 +0800 + + 解决设置rust workspace带来的“工具链不一致”的问题 (#345) + + 更改workflow + +commit 9a367aa7eb1576a235f5f52ee542132a1e5e39df +Author: LoGin +Date: Thu Aug 24 18:50:52 2023 +0800 + + 添加github workflow,检查代码是否已经格式化 (#342) + + * 添加github workflow,检查代码是否已经格式化 + +commit f09a98329c4ec77010de86d126516310b407455a +Author: LoGin +Date: Wed Aug 23 16:09:29 2023 +0800 + + 1. 修复bootstrap.sh在安装libssl-dev之前,安装dadk,从而导致错误的问题 (#338) + + 1. 修复bootstrap.sh在安装libssl-dev之前,安装dadk,从而导致错误的问题 + 2. 构建系统的文档,补充对vnc端口的说明 + +commit 4537ffb7e9afb2d96f2adcee32c8ac84b056d2e5 +Author: Chiichen <39649411+Chiichen@users.noreply.github.com> +Date: Mon Aug 21 18:37:31 2023 +0800 + + 实现了对用户空间传入指针抽象的UserBufferReader/Writer,来检验用户空间指针地址并提供一定的功能抽象 (#326) + + * 构建了 Userbuffer 对用户空间传入的指针进行了抽象,并提供了读写操作 + + * 分成了Reader和Writer,增加了从地址读和写入到指定地址的功能 + + * 删除了多余的注释 + + * 增加了直接获取BufferWriter切片的函数 + + * 通过 where 的一个 Trick 实现了 const generic 和后续功能 + + * 替换为了 core::slice::align_to 实现&[u8}转&[T] + + * 移除了 userbuffer.rs + + * 提供了独立获取缓冲区中不同偏移量位置的数据的函数 + + * 替换了部分系统调用(还未测试 + + * 简化了代码 + + * 修复内存越界的bug + + --------- + + Co-authored-by: longjin + +commit abe3a6ea3c543425e2cad12722e8a658b324d515 +Author: hanjiezhou +Date: Sun Aug 20 00:19:36 2023 +0800 + + Patch refactor scm and textui (#289) + + * 重构屏幕管理器和textui框架 + + * 切换字体为spleen,并增加对字体的抽象 + + * 修正文档 + + --------- + + Co-authored-by: longjin + +``` diff --git a/docs/locales/en/community/ChangeLog/index.rst b/docs/locales/en/community/ChangeLog/index.rst new file mode 100644 index 00000000..0f1e968d --- /dev/null +++ b/docs/locales/en/community/ChangeLog/index.rst @@ -0,0 +1,32 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: community/ChangeLog/index.rst + + - Translation time: 2025-05-19 01:41:22 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Release Notes +===================== + +This is the release log for DragonOS, which records the update content of every version of DragonOS. + +.. toctree:: + :maxdepth: 1 + + V0.1.x/V0.1.10 + V0.1.x/V0.1.9 + V0.1.x/V0.1.8 + V0.1.x/V0.1.7 + V0.1.x/V0.1.6 + V0.1.x/V0.1.5 + V0.1.x/V0.1.4 + V0.1.x/V0.1.3 + V0.1.x/V0.1.2 + V0.1.x/V0.1.1 + V0.1.x/V0.1.0 diff --git a/docs/locales/en/community/code_contribution/c-coding-style.md b/docs/locales/en/community/code_contribution/c-coding-style.md new file mode 100644 index 00000000..6a618e85 --- /dev/null +++ b/docs/locales/en/community/code_contribution/c-coding-style.md @@ -0,0 +1,173 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/code_contribution/c-coding-style.md + +- Translation time: 2025-05-19 01:42:01 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# C Language Code Style + +  This document will briefly introduce the C language code style used in DragonOS. It is completely normal for each person to have their own code style. However, for the maintainability of an open-source project, we hope to establish some code standards so that every developer, including you, can feel more comfortable when reading the code. A project filled with various code styles is difficult to maintain. + +  We propose some recommendations here, and we hope you will follow them as much as possible. These recommendations are similar to those of Linux, but with some differences. DragonOS uses Linux's style for variable naming; for indentation, DragonOS uses Microsoft's style. + +## 0. Code Formatter + +  Before we present the following recommendations, we recommend that you use the `C/C++ Extension Pack` plugin in Visual Studio Code as a code formatter during development. These plugins provide good auto-formatting functionality, ensuring that your code's basic format meets DragonOS's requirements. + +  Pressing `Ctrl+shift+I` or your set code formatting shortcut frequently while coding can help you maintain good code formatting consistently. + +## 1. Indentation + +  The width of a tab is equal to 4 spaces. Code indentation is based on the tab width (usually 4 characters in most editors). + +  This makes your code more readable and helps better identify the control structures in the code. This can avoid many unnecessary troubles! + +For example: In a switch statement, place the switch and case on the same indentation level. And indent each case's code by one tab to the right. This improves code readability. + +```c +switch (cmd) +{ +case AHCI_CMD_READ_DMA_EXT: + pack->blk_pak.end_handler = NULL; + pack->blk_pak.cmd = AHCI_CMD_READ_DMA_EXT; + break; +case AHCI_CMD_WRITE_DMA_EXT: + pack->blk_pak.end_handler = NULL; + pack->blk_pak.cmd = AHCI_CMD_WRITE_DMA_EXT; + break; +default: + pack->blk_pak.end_handler = NULL; + pack->blk_pak.cmd = cmd; + break; +} +``` + +## 2. Line Breaks + +  We recommend that each line should not exceed 120 characters. If it does, unless there is a necessary reason, it should be split into two lines. + +  When breaking lines, we need to indent the second line by one level from the first line's starting part to indicate that it is a sub-line. Using the code formatting shortcut can quickly accomplish this. + +  For log strings, we do not recommend breaking them into multiple lines for easier retrieval. + +  For code line breaks, do not try to place several statements on the same line, as this provides no benefit to code readability: + +```c +// 错误示范(1) +if(a) return 1; + +// 错误示范(2) +if(b) + do_a(),do_b(); +``` + +## 3. Braces and Spaces + +### 3.1 Braces + +  The placement of braces is a matter of personal preference, mainly due to habit rather than technical reasons. We recommend placing the opening and closing braces on new lines, as shown below: + +```c +while(i<10) +{ + ++i; +} +``` + +  This rule applies to all code blocks. + +  The reason for this choice is that, in some editors, placing the braces in this way will result in **a semi-transparent vertical line appearing in the editor, with the line ends being the braces**. This helps developers better understand the hierarchical relationships of the code blocks. + +Let's demonstrate this with some examples: + +  In the following code block, we need to note that the `else if` statement should be on a new line, not after the previous `}`. This is because we require `{` to be at the start of each line and maintain the indentation level. + +```c +if (*fmt == '*') +{ + ++fmt; +} +else if (is_digit(*fmt)) +{ + field_width = skip_and_atoi(&fmt); +} +``` + +  When there are multiple simple statements in a loop, braces should be used. + +```c +while (condition) +{ + if (test) + do_something(); +} +``` + +  When there is only one simple statement, we do not need to use braces. + +```c +if(a) + return 1; +``` + +### 3.2 Spaces + +  For most keywords, we need to add a space after them to improve code readability. + +  Please add a space after all of these keywords: + +```c +if, switch, case, for, do, while +``` + +  Keywords such as sizeof, typeof, alignof, and __attribute__ do not require a space after them, as they are used like functions. + +  For pointer-type variables, the asterisk should be close to the variable name rather than the type name. As shown below: + +```c +char *a; +void *func(char* s, int **p); +``` + +  Use a space on both sides of most binary and ternary operators, as shown below: + +```c += + - < > * / % | & ^ <= >= == != ? : +``` + +  There is no space after these unary operators: + +```c +& * + - ~ ! sizeof typeof alignof __attribute__ defined +``` + +  Special cases: no space is needed before or after the following operators: + +```c +++ -- . -> +``` + +## 4. Naming + +  DragonOS does not use the camelCase naming convention for function names, but instead uses concise and clear names like `tmp`. + +  Note that this refers to our entire project not using the camelCase naming convention. It does not mean that programmers can use obscure abbreviations for variable names. + +  For global variables or globally visible functions and structures, we need to follow the following naming conventions: + +- The name should be easy to understand and not ambiguous. For example, for a function that calculates folder size, we recommend using `count_folder_size()` instead of `cntfs()`, which can confuse others. +- For global, non-static names, unless there is a special need, the naming should follow the format: `模块名缩写前缀_函数/变量名`. This naming convention helps others distinguish which module the name belongs to and reduces the risk of naming conflicts. +- Global names that do not need to be visible to other code files must be prefixed with the `static` modifier. + +  For local variables within functions, the naming convention should be concise. Long names for local variables have little significance. + +[Document not completed, to be continued] diff --git a/docs/locales/en/community/code_contribution/conventional-commit.md b/docs/locales/en/community/code_contribution/conventional-commit.md new file mode 100644 index 00000000..e64d29ad --- /dev/null +++ b/docs/locales/en/community/code_contribution/conventional-commit.md @@ -0,0 +1,62 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/code_contribution/conventional-commit.md + +- Translation time: 2025-05-19 01:41:57 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Code Commit Guidelines + +  This document will briefly introduce the code commit guidelines for the DragonOS GitHub repository, mainly providing the naming conventions based on Conventional Commit, as well as a brief introduction to the DragonOS Bot. + +## Conventional Commit (Conventional Commit) + +  For detailed specifications on Conventional Commit, please refer to the website [Conventional Commit/Conventional Commit](https://www.conventionalcommits.org/zh-hans/v1.0.0/). At the end of this section, we will provide examples (taken from the [Conventional Commit/Conventional Commit](https://www.conventionalcommits.org/zh-hans/v1.0.0/) website), which are optional to read. We make the following special notes: +1. Since the DragonOS kernel ensures external usability primarily through system call interfaces, and up to now (April 22, 2024), considering the software ecosystem, DragonOS has chosen to implement system calls consistent with Linux. Therefore, there is no special explanation for `破坏性变更(BREAKING CHANGES)`, or in the current development environment, there will not be any destructive changes that significantly affect users. Therefore, unless there is a special need, the DragonOS kernel should not use `feat!` to indicate destructive changes. (Outside the kernel, such as dadk, the guidelines still apply.) +2. The DragonOS community strictly follows a squash-based workflow, so we do not require each individual commit in a PR to conform to [Conventional Commit/Conventional Commit](https://www.conventionalcommits.org/zh-hans/v1.0.0/). However, we still strongly recommend using it. +3. Regarding scope: If not specified otherwise, the scope should be the name of the submodule/system/directory. For example, if the code change is adding a feature in `kernel/src/driver/net`, it should be named as `feat(driver/net):`; if it is in `kernel/src/mm/allocator`, it should be named as `feat(mm)`. In short, the scope should be as short as possible to indicate the module it belongs to. Most of the time, it should not use more than two levels of scope identifiers. For example, `fix(x86_64/driver/apic)` is incorrect and should be named as `fix(x86_64/apic)`. +4. In the DragonOS kernel code repository, `issue checker` will perform a simple review of the title format. If it does not conform to the format, it will be marked as `ambiguous`. Contributors are advised to modify it as needed. +5. Use lowercase. + +### Examples + +#### Commit message with a description and a footnote indicating a breaking change +``` +feat: allow provided config object to extend other configs + +BREAKING CHANGE: `extends` key in config file is now used for extending other config files +``` +#### Commit message with the ! character to alert about a breaking change +``` +feat!: send an email to the customer when a product is shipped +``` +#### Commit message with scope and a breaking change ! +``` +feat(api)!: send an email to the customer when a product is shipped +``` +#### Commit message with ! and BREAKING CHANGE footnote +``` +chore!: drop support for Node 6 + +BREAKING CHANGE: use JavaScript features not available in Node 6. +``` +#### Commit message without a body +``` +docs: correct spelling of CHANGELOG +``` +#### Commit message with scope +``` +feat(lang): add polish language +``` + +## DragonOS Bot + +  DragonOS uses triagebot to implement automatic labeling and reviewer assignment. Contributors can also interact with triagebot through some commands. For more details, see [triagebot](https://forge.rust-lang.org/triagebot/index.html) diff --git a/docs/locales/en/community/code_contribution/index.rst b/docs/locales/en/community/code_contribution/index.rst new file mode 100644 index 00000000..b7b995cf --- /dev/null +++ b/docs/locales/en/community/code_contribution/index.rst @@ -0,0 +1,29 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: community/code_contribution/index.rst + + - Translation time: 2025-05-19 01:41:37 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +Contributing to Development +==================================== + + DragonOS community warmly welcomes your participation! While learning technology is important, the following documents will help you understand what DragonOS community needs. + + Reading these documents will help you get involved in development and make your code merge into the mainline more quickly. + +.. toctree:: + :maxdepth: 1 + + how-to-contribute + + c-coding-style + rust-coding-style + conventional-commit diff --git a/docs/locales/en/community/code_contribution/rust-coding-style.md b/docs/locales/en/community/code_contribution/rust-coding-style.md new file mode 100644 index 00000000..3f2e3ee9 --- /dev/null +++ b/docs/locales/en/community/code_contribution/rust-coding-style.md @@ -0,0 +1,107 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: community/code_contribution/rust-coding-style.md + +- Translation time: 2025-05-19 01:41:39 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Rust Language Code Style + +  This document will introduce the Rust language code style used in DragonOS. As development progresses, these styles may change, but we will strive to maintain consistency in the style. + +## 1. Naming + +  This section is based on the naming conventions from the Rust language bible, [Naming Guide](https://course.rs/practice/naming.html). For parts not mentioned in this document, please refer to the [Naming Guide](https://course.rs/practice/naming.html) in the Rust language bible. + +## 2. Formatting + +### 2.1 Indentation + +  Please use the `cargo fmt` command to format the code before submitting it. + +### 2.2 Function Return Values + +  Although Rust allows returning the value of the last line of a function, this approach can reduce code readability. Therefore, we recommend using the `return` statement as the last line of the function, rather than directly returning the value. + +```rust +// 不推荐 +fn foo() -> i32 { + 1 + 2 +} + +// 推荐 +fn foo() -> i32 { + return 1 + 2; +} +``` +### 2.3 Error Handling + +  DragonOS uses returning POSIX error codes as the **inter-module error handling** method. To ensure consistency in error handling code across modules, we recommend returning the `SystemError` type when an error occurs. This approach is especially beneficial when calling functions across modules, as it allows direct return of a generic error code, thereby reducing the coupling of error handling code. + +```rust +// 函数跨越模块边界时(由其他模块调用当前函数),不推荐 +fn foo() -> Result<(), CustomErr> { + if 1 + 2 == 3 { + return Ok(()); + } else { + return Err(CustomErr::error); + } +} + +// 函数跨越模块边界时(由其他模块调用当前函数),推荐 +fn foo() -> Result<(), SystemError> { + if 1 + 2 == 3 { + return Ok(()); + } else { + return Err(SystemError::EINVAL); + } +} +``` + +  Within **modules**, you can either use a custom error enum or return the `SystemError` type. However, we recommend using a custom error enum for error handling within modules, as it makes the error handling code clearer. + +  **TODO**: Convert existing code that uses i32 as an error code to use `SystemError`. + +## 3. Comments + +  The commenting style in DragonOS is consistent with the official Rust style. We also recommend adding as many meaningful comments as possible in your code to help others understand your code. Additionally, variable and function declarations should follow the naming conventions mentioned in Section 1, making them "self-documenting." + +### 3.1 Function Comments + +  Function comments should include the following: + +- The function's purpose +- The function's parameters +- The function's return value +- The function's error handling +- Any side effects or other information that needs to be explained + +  The format for function comments is as follows: + +```rust +/// # 函数的功能 +/// +/// 函数的详细描述 +/// +/// ## 参数 +/// +/// - 参数1: 参数1的说明 +/// - 参数2: 参数2的说明 +/// - ... +/// +/// ## 返回值 +/// - Ok(返回值类型): 返回值的说明 +/// - Err(错误值类型): 错误的说明 +/// +/// ## Safety +/// +/// 函数的安全性说明 +``` diff --git a/docs/locales/en/community/contact/index.rst b/docs/locales/en/community/contact/index.rst new file mode 100644 index 00000000..3c4bab10 --- /dev/null +++ b/docs/locales/en/community/contact/index.rst @@ -0,0 +1,45 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: community/contact/index.rst + + - Translation time: 2025-05-19 02:14:46 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +.. _translated_label__get_contact_with_community_en: + +Get in Touch with the Community +==================================================================== + +Contact Information +------------------------- + +Community Public Email: contact@DragonOS.org + +Community Management Staff Information: https://community.dragonos.org/governance/staff-info.html + +Development Discussion QQ Group: 115763565 + +DragonOS Official Website: https://DragonOS.org + +To learn about development updates and tasks, please visit the DragonOS forum: https://bbs.dragonos.org.cn + +Sponsorship and Donations +--------------------------------------------------------- + +DragonOS is an open-source project, and we welcome any form of sponsorship and donations. Your donations will be used for the development and maintenance of DragonOS, as well as the operation of the community. + +You can sponsor or donate through the following methods: + +- Visit the DragonOS official website at https://DragonOS.org, click the "Sponsor" button in the top right corner, and make a donation. +- Contact the community leader to discuss specific sponsorship methods. Contact information: longjin@dragonos.org + +Financial and Donation Transparency +--------------------------------------------------------- + +The donation information of the DragonOS community will be made public annually. Sponsorship details and sponsor information will be made public within 15 days after receiving the donation. diff --git a/docs/locales/en/index.rst b/docs/locales/en/index.rst new file mode 100644 index 00000000..e6642aff --- /dev/null +++ b/docs/locales/en/index.rst @@ -0,0 +1,68 @@ +English +========================================== +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: index.rst + + - Translation time: 2025-05-22 09:21:59 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +.. DragonOS documentation master file, created by + sphinx-quickstart on Fri Jun 17 23:12:00 2022. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +.. toctree:: + :maxdepth: 1 + :caption: Getting Started + + introduction/index + introduction/build_system + introduction/mirrors + +.. toctree:: + :maxdepth: 1 + :caption: Kernel Layer + + kernel/configuration/index + kernel/boot/index + kernel/core_api/index + kernel/locking/index + kernel/process_management/index + kernel/sched/index + kernel/ipc/index + kernel/memory_management/index + kernel/filesystem/index + kernel/debug/index + kernel/ktest/index + kernel/cpu_arch/index + kernel/container/index + kernel/libs/index + kernel/trace/index + kernel/syscall/index + +.. toctree:: + :maxdepth: 1 + :caption: Userland Layer + + userland/appdev/index + +.. toctree:: + :maxdepth: 1 + :caption: Q&A + + questions/index + +.. toctree:: + :maxdepth: 1 + :caption: DragonOS Community + + community/code_contribution/index + community/contact/index + community/ChangeLog/index diff --git a/docs/locales/en/introduction/build_system.md b/docs/locales/en/introduction/build_system.md new file mode 100644 index 00000000..5ccb93d8 --- /dev/null +++ b/docs/locales/en/introduction/build_system.md @@ -0,0 +1,294 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: introduction/build_system.md + +- Translation time: 2025-05-19 01:44:01 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Building DragonOS + +## 1. Introduction + +  Regardless of which method you use to compile DragonOS in the following sections, you must first follow the steps in this section to initialize your development environment. + +  Before you start, you need a computer running Linux or macOS with an X86-64 processor architecture. + +  For Linux distributions, it is recommended to use newer distributions such as Ubuntu 22, Debian, or Arch Linux, which can save you a lot of trouble. + +### 1.1 Downloading the DragonOS Source Code + +Use `https` to clone: + +```shell +git clone https://github.com/DragonOS-Community/DragonOS.git +cd DragonOS +# 使用镜像源更新子模块 +make update-submodules-by-mirror +``` + +For convenience in subsequent development, we recommend using `ssh` to clone (please configure your GitHub SSH Key first) to avoid cloning failures due to network issues: + +Use `ssh` to clone (please configure your GitHub SSH Key first): + +```shell +# 使用ssh克隆 +git clone git@github.com:DragonOS-Community/DragonOS.git +cd DragonOS +# 使用镜像源更新子模块 +make update-submodules-by-mirror +``` + +## 2. Installation Using One-Click Initialization Script (Recommended) + +  We provide a one-click initialization script that can install everything with a single command. Just run the following command in the terminal: + +```shell +cd DragonOS +cd tools +bash bootstrap.sh # 这里请不要加上sudo, 因为需要安装的开发依赖包是安装在用户环境而非全局环境 +``` + +:::{note} +The one-click configuration script currently supports the following systems: + +- Ubuntu/Debian/Deepin/UOS and other derivatives based on Debian +- Gentoo, due to the characteristics of the Gentoo system, when Gentoo encounters USE or circular dependency issues, please handle them according to the emerge prompt information. Official dependency handling examples [GentooWiki](https://wiki.gentoo.org/wiki/Handbook:AMD64/Full/Working/zh-cn#.E5.BD.93_Portage_.E6.8A.A5.E9.94.99.E7.9A.84.E6.97.B6.E5.80.99) + +We welcome you to improve the build script for other systems! +::: + +**If the one-click initialization script runs normally and outputs the final "Congratulations" interface (as shown below), please close the current terminal and then reopen it.** + +```shell +|-----------Congratulations!---------------| +| | +| 你成功安装了DragonOS所需的依赖项! | +| | +| 请关闭当前终端, 并重新打开一个终端 | +| 然后通过以下命令运行: | +| | +| make run | +| | +|------------------------------------------| +``` + +**Then, please directly jump to {ref}`编译命令讲解 <_build_system_command>` for reading!** + +## 3. Manual Installation + +### 3.1 Dependency List + +  If the automatic installation script does not support your operating system, you need to manually install the required packages. The following is the list of dependencies: + +  Among the following dependencies, except for `docker-ce` and `Rust及其工具链`, the rest can be installed using the system's built-in package manager. For the installation of Docker and Rust, please refer to the following sections. + +- docker-ce +- llvm-dev +- libclang-dev +- clang +- gcc-multilib +- qemu qemu-system qemu-kvm +- build-essential +- fdisk +- lsb-release +- git +- dosfstools +- unzip +- Rust and its toolchain + +**Please note that if your Linux system is running in a virtual machine, please make sure to enable the Intel VT-x or AMD-V option in the processor settings of your VMware/Virtual Box virtual machine, otherwise DragonOS will not be able to run.** + +:::{note} + +*In some Linux distributions, the Qemu built from the software repository may be incompatible with DragonOS due to an outdated version. If you encounter this issue, uninstall Qemu and reinstall it by compiling from source.* + +Download the Qemu source code from this address: https://download.qemu.org/ + +After decompression, enter the source code directory and execute the following command: + +```shell +# 安装编译依赖项 +sudo apt install -y autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \ + gawk build-essential bison flex texinfo gperf libtool patchutils bc \ + zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev libsdl2-dev \ + git tmux python3 python3-pip ninja-build + +./configure --enable-kvm +make -j 8 +sudo make install +# 编译安装完成 +``` +Please note that the compiled QEMU will be linked via VNC mode, so you also need to install a VNC viewer on your computer to connect to the QEMU virtual machine. +::: + +### 3.2 Installing Docker + +  You can download and install docker-ce from the Docker official website. + +> For detailed information, please visit: [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/) + +### 3.3 Installing Rust + +:::{warning} +**[Common Misconception]**: If you plan to compile using Docker, although the Docker image already includes a Rust compilation environment, to enable code hints in VSCode using Rust-Analyzer and for the `make clean` command to run normally, you still need to install the Rust environment on your client machine. +::: + +  You can install Rust by entering the following command in the terminal. + +```shell +# 这两行用于换源,加速Rust的安装过程 +export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static +export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup +# 安装Rust +curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly +# 把Rustup加到环境变量 +echo "export PATH=\"\$HOME/.cargo/bin:\$PATH\"" >> ~/.bashrc +source ~/.cargo/env +source "$HOME/.cargo/env" + +# 更换cargo的索引源 +touch ~/.cargo/config +echo -e "[source.crates-io] \n \ +registry = \"https://github.com/rust-lang/crates.io-index\" \n \ +\n \ +replace-with = 'dragonos-gitee' \n \ +[source.dragonos-gitee] \n \ +registry = \"https://gitee.com/DragonOS/crates.io-index.git\" \n \ +" > ~/.cargo/config + +# 安装DragonOS所需的工具链 +cargo install cargo-binutils +rustup toolchain install nightly +rustup default nightly +rustup component add rust-src +rustup component add llvm-tools-preview +rustup target add x86_64-unknown-none +# Rust安装完成 +``` + +**At this point, the public dependencies have been installed. You can proceed to read the subsequent sections according to your needs.** + +**For the usage of the compilation command, please refer to: {ref}`编译命令讲解 <_build_system_command>`** + +## 4. Building from Docker (Not Recommended) + +  DragonOS provides a Docker compilation environment for developers to run DragonOS. However, since the coding process still needs to be performed on the client machine, you need to install the Rust compilation environment on your client machine. + +  This section assumes that all operations are performed under Linux. + +### 4.1 Installing QEMU Virtual Machine + +  In this section, we recommend installing QEMU via the command line: + +```shell +sudo apt install -y qemu qemu-system qemu-kvm +``` + +### 4.2 Creating a Disk Image + +  First, you need to use the `create_hdd_image.sh` script in the `tools` folder to create a virtual disk image. You need to run this command in the `tools` folder. + +```shell +bash create_hdd_image.sh +``` + +### 4.3 Running DragonOS + +  If everything goes well, this will be the final step to run DragonOS. You just need to execute the following command in the DragonOS root directory to run DragonOS. + +```shell +make run-docker +``` + +  Wait a moment, DragonOS will be started. + +  After the QEMU virtual machine is started, you need to input the letter `c` in the console and press Enter. This will start the virtual machine. + +:::{note} +1. During the first compilation, since it requires downloading Rust-related indexes (hundreds of MB in size), it will take some time. Please be patient! +2. Entering commands may require adding `sudo` +::: + +**For the usage of the compilation command, please refer to: {ref}`编译命令讲解 <_build_system_command>`** + +## 5. Other Notes + +### 5.1 Creating a Disk Image + +  First, you need to run `tools/create_hdd_image.sh` with **normal user** permissions to create a disk image file for DragonOS. This script will automatically complete the creation of the disk image and move it to the `bin/` directory. + +  Please note that due to permission issues, you must run this script with **normal user** permissions. (After running, the system may prompt you to enter a password when you need to elevate permissions.) + +### 5.2 Compiling and Running DragonOS + +1. Install the compilation and runtime environment +2. Enter the DragonOS folder +3. Input `make run` to compile and write to the disk image, and run + +  After the QEMU virtual machine is started, you need to input the letter `c` in the console and press Enter. This will start the virtual machine. + +:::{note} +During the first compilation, since it requires downloading Rust-related indexes (hundreds of MB in size), it will take some time. Please be patient! +::: + +**For the usage of the compilation command, please refer to: {ref}`编译命令讲解 <_build_system_command>`** + +(_translated_label___build_system_command_en)= +## 6. Explanation of Compilation Commands + +- Local compilation, no execution: `make all -j 您的CPU核心数` +- Local compilation, write to disk image, no execution: `make build` +- Local compilation, write to disk image, and run in QEMU: `make run` +- Local compilation, write to disk image, and run in headless mode: +`make run-nographic` +- Docker compilation, write to disk image: `make docker` +- Docker compilation, write to disk image, and run in QEMU: `make run-docker` +- Start directly from an existing disk image without compilation: `make qemu` +- Start directly from an existing disk image without compilation (headless mode): `make qemu-nographic` +- Clean up compiled files: `make clean` +- Compile documentation: `make docs` (requires manual installation of sphinx and dependencies in `requirements.txt`) +- Clean up documentation: `make clean-docs` +- Format code: `make fmt` + +:::{note} +If you need to run DragonOS in VNC, add the `-vnc` suffix to the above command. For example: `make run-vnc` + +The QEMU virtual machine will listen on port 5900 for VNC connections. You can connect to the QEMU virtual machine using a VNC viewer or Remmina. +::: + +## 7. Compiling for riscv64 + +Since DragonOS has not been fully ported to riscv64 yet, the compilation needs to be done as follows: + +1. Modify `env.mk` and `.vscode/settings.json` + +Change the value of `ARCH` in `env.mk` to `riscv64`, and in `setting.json`, comment out `"rust-analyzer.cargo.target": "x86_64-unknown-none",` and change it to the line enabling riscv64. + +2. Restart rust-analyzer + +3. Clean up the compilation cache + +Due to the differences between x86_64 and riscv64 architectures, there may be compilation issues caused by cache. Ensure that you clean up the cache before running. + +```shell +make clean +``` + +4. Compile and run for riscv64 + +```shell +# 下载DragonStub +git submodule update --init --recursive --force + +make run +``` + +Please note that since you are running QEMU in the console, when you want to exit, input `Ctrl+A` and press `X` to do so. diff --git a/docs/locales/en/introduction/features.md b/docs/locales/en/introduction/features.md new file mode 100644 index 00000000..ecfee695 --- /dev/null +++ b/docs/locales/en/introduction/features.md @@ -0,0 +1,154 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: introduction/features.md + +- Translation time: 2025-05-19 01:42:30 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +(_translated_label___genreal_features_en)= + +# Features of DragonOS + +## Specifications + +- [x] Bootloader: Multiboot2 + +- [x] Interface: POSIX 2008 + +## Kernel Layer + +### Memory Management + +- [x] Page Frame Allocator +- [x] Small Object Allocator +- [x] VMA (Virtual Memory Area) +- [x] Automatic MMIO Address Space Allocation +- [x] Page Mapper +- [x] Hardware Abstraction Layer +- [x] Independent User Address Space Management Mechanism +- [x] C Interface Compatibility Layer + +### Multicore + +- [x] Multicore Boot +- [x] IPI (Inter-Processor Interrupt) Framework + +### Process Management + +- [x] Process Creation +- [x] Process Reclamation +- [x] Kernel Threads +- [x] Fork +- [x] Exec +- [x] Process Sleep (Supports High-Precision Sleep) +- [x] Kthread Mechanism +- [x] Extensible Binary Loader + +#### Synchronization Primitives + +- [x] Mutex +- [x] Semaphore +- [x] Atomic Variables +- [x] Spinlock +- [x] Wait Queue + +### Scheduling + +- [x] CFS Scheduler +- [x] Real-Time Scheduler (FIFO, RR) +- [x] Single-Core Scheduling +- [x] Multi-Core Scheduling +- [x] Load Balancing + +### IPC (Inter-Process Communication) + +- [x] Anonymous Pipe +- [x] Signal + +### File System + +- [x] VFS (Virtual File System) +- [x] FAT12/16/32 +- [x] Devfs +- [x] RamFS +- [x] Procfs +- [x] Sysfs + +### Exception and Interrupt Handling + +- [x] APIC +- [x] Softirq (Soft Interrupt) +- [x] Kernel Stack Traceback + +### Kernel Utility Library + +- [x] String Operation Library +- [x] ELF Executable Support +- [x] printk +- [x] Basic Math Library +- [x] Screen Manager +- [x] TextUI Framework +- [x] CRC Function Library +- [x] Notification Chain + +### System Calls + +  [See System Call Documentation](https://docs.dragonos.org/zh_CN/latest/syscall_api/index.html) + +### Test Framework + +- [x] ktest + +### Drivers + +- [x] ACPI (Advanced Configuration and Power Interface) Module +- [x] IDE Hard Disk +- [x] AHCI Hard Disk +- [x] PCI, PCIe Bus +- [x] XHCI (USB 3.0) +- [x] PS/2 Keyboard +- [x] PS/2 Mouse +- [x] HPET (High Precision Event Timer) +- [x] RTC (Real-Time Clock) +- [x] Local APIC Timer +- [x] UART Serial Port +- [x] VBE (Video BIOS Extension) Display +- [x] VirtIO Network Card +- [x] x87 FPU +- [x] TTY Terminal +- [x] Floating Point Processor + +## User Layer + +### LibC + +- [x] Basic System Calls +- [x] Basic Standard Library Functions +- [x] Partial Mathematical Functions + +### Shell Command Line Programs + +- [x] Parsing Based on String Matching +- [x] Basic Commands + +### Http Server + +- A simple Http Server written in C, capable of running static websites. + +## Software Portability + +- [x] GCC 11.3.0 (Currently only supports x86_64 Cross Compiler) [https://github.com/DragonOS-Community/gcc](https://github.com/DragonOS-Community/gcc) +- [x] binutils 2.38 (Currently only supports x86_64 Cross Compiler) [https://github.com/DragonOS-Community/binutils](https://github.com/DragonOS-Community/binutils) +- [x] gmp 6.2.1 [https://github.com/DragonOS-Community/gmp-6.2.1](https://github.com/DragonOS-Community/gmp-6.2.1) +- [x] mpfr 4.1.1 [https://github.com/DragonOS-Community/mpfr](https://github.com/DragonOS-Community/mpfr) +- [x] mpc 1.2.1 [https://github.com/DragonOS-Community/mpc](https://github.com/DragonOS-Community/mpc) +- [x] relibc [https://github.com/DragonOS-Community/relibc](https://github.com/DragonOS-Community/relibc) +- [x] sqlite3 diff --git a/docs/locales/en/introduction/index.rst b/docs/locales/en/introduction/index.rst new file mode 100644 index 00000000..8fdfe91a --- /dev/null +++ b/docs/locales/en/introduction/index.rst @@ -0,0 +1,34 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: introduction/index.rst + + - Translation time: 2025-05-19 01:41:59 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Introduction to DragonOS +==================================== + + DragonOS, the Dragon Operating System, is a 64-bit operating system designed for lightweight cloud computing scenarios. It features a fully self-developed kernel and provides Linux binary compatibility. Developed using the Rust programming language, it offers enhanced reliability. Currently, DragonOS ranks among the top three in the Rust operating system field on GitHub. + + The DragonOS open-source community was established in July 2022. It is completely neutral in commercial matters. Our goal is to build a fully independent, open-source, high-performance, and highly reliable server operating system, **to create a fully self-controlled digital future!** + + DragonOS has an excellent and well-designed architecture. Compared to other systems of similar size, DragonOS supports virtualization and has certain advantages in areas such as device model and scheduling subsystems. Currently, we are actively promoting cloud platform support, RISC-V support, as well as the porting of compilers and application software. We aim to achieve large-scale application in production environments within five years. + + DragonOS is currently developing rapidly under the drive of the community. At present, DragonOS has already implemented about 1/4 of the Linux interface. In the future, we will provide 100% compatibility with Linux and introduce new features. + + The goal of DragonOS is to build a fully independent, open-source, high-performance, and highly reliable server operating system, providing a completely self-controlled core power for the country's digital infrastructure construction. + + As a community-driven open-source operating system, in order to promote the development of the open-source community and avoid potential infringement by commercial companies that do not comply with open-source agreements, we have decided to open the source code under the GPLv2 license, using a strict open-source agreement to protect DragonOS. + + You may be interested in the features that have already been implemented in DragonOS. You can visit here: :ref:`功能特性 <_genreal_features>` + +.. toctree:: + :maxdepth: 1 + + features diff --git a/docs/locales/en/introduction/mirrors.md b/docs/locales/en/introduction/mirrors.md new file mode 100644 index 00000000..f066cd14 --- /dev/null +++ b/docs/locales/en/introduction/mirrors.md @@ -0,0 +1,22 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: introduction/mirrors.md + +- Translation time: 2025-05-19 01:41:42 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# DragonOS Mirror Site + +You can download the source code and other files of DragonOS from the following mirror sites: + +- [DragonOS Mirror Site https://mirrors.dragonos.org/](https://mirrors.dragonos.org/) +- [DragonOS Domestic Mirror Site (RinGoTek)](https://mirrors.RinGoTek.cn) +- [Git Mirror Site](https://git.mirrors.dragonos.org/) diff --git a/docs/locales/en/kernel/boot/bootloader.md b/docs/locales/en/kernel/boot/bootloader.md new file mode 100644 index 00000000..66e3dc30 --- /dev/null +++ b/docs/locales/en/kernel/boot/bootloader.md @@ -0,0 +1,48 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/boot/bootloader.md + +- Translation time: 2025-05-19 01:41:31 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Bootloader + +## X86_64 + +- [x] multiboot2 +- [x] HVM/PVH + +### HVM/PVH Boot on x86_64 + +In the DragonOS note segment, there is a PVH header that allows QEMU to boot the DragonOS kernel using the ``-kernel`` parameter. + +## RISC-V 64 + +DragonOS's boot process on RISC-V 64 is as follows: + +opensbi --> uboot --> DragonStub --> kernel + +This boot process decouples the DragonOS kernel from specific hardware boards, enabling the same binary file to boot and run on different hardware boards. + +## Kernel Boot Callbacks + +DragonOS abstracts the kernel bootloader, which is represented by the trait ``BootCallbacks``. +Different bootloaders implement the corresponding callback to initialize the kernel's bootParams or other data structures. + +When the kernel boots, it automatically registers callbacks based on the type of bootloader. And at the appropriate time, it calls these callback functions. + +## References + +- [Multiboot2 Specification](http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot2) + +- [GNU GRUB Manual 2.06](https://www.gnu.org/software/grub/manual/grub/grub.html) + +- [UEFI/Legacy Boot - yujianwu - DragonOS Community](https://bbs.dragonos.org/forum.php?mod=viewthread&tid=46) diff --git a/docs/locales/en/kernel/boot/cmdline.md b/docs/locales/en/kernel/boot/cmdline.md new file mode 100644 index 00000000..4414923b --- /dev/null +++ b/docs/locales/en/kernel/boot/cmdline.md @@ -0,0 +1,123 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/boot/cmdline.md + +- Translation time: 2025-05-19 01:41:48 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Kernel Boot Command Line Parameters + +:::{note} +Author: +- Longjin +::: + +## Overview + +  The DragonOS kernel boot command line parameter parsing module aims to provide support for parsing kernel boot command line parameters similar to Linux, enabling more flexible behavior for the kernel. This module allows the kernel to receive and parse command line parameters at boot time, and execute corresponding callback functions or set environment variables based on the type of parameters. + +:::{note} +Callback functions are not supported temporarily. +::: + +## Design + +### Parameter Types + +Kernel boot command line parameters are divided into three types: + +- Arg type +- KV type +- EarlyKV type + +#### Arg Type + +Arg type parameters have only a name and no value. They are divided into the following two types: + +- ArgNormal: The default value is `false`. If the parameter is present in the command line, it will be set to `true`. +- ArgInv: The default value is `true`. If the parameter is present in the command line, it will be set to `false`. + +#### KV Type + +KV type parameters are represented in the command line as `name=value`, `value` separated by commas. Kernel modules can provide default values for these parameters. + +#### EarlyKV Type + +EarlyKV type parameters are similar to KV type parameters, but they are parsed before memory management initialization. + +### Module Flags + +Module flags are similar to `usbprobe.xxxx`. + +### Parameter Declaration + +Provides macros to declare kernel command line parameters. +### procfs Support + +:::{note} +TODO: Display the current kernel's boot command line parameters under `/proc/cmdline`. +::: + +## Macros for Declaring Kernel Boot Command Line Parameters + +### Arg Type Parameter Declaration +```rust +kernel_cmdline_param_arg!(varname, name, default_bool, inv); +``` +- `varname`: The variable name of the parameter +- `name`: The name of the parameter +- `default_bool`: The default value +- `inv`: Whether to invert + +### KV Type Parameter Declaration + +```rust +kernel_cmdline_param_kv!(varname, name, default_str); +``` + +- `varname`: The variable name of the parameter +- `name`: The name of the parameter +- `default_str`: The default value + +### KV Type Parameter Declaration Before Memory Management Initialization + +```rust +kernel_cmdline_param_early_kv!(varname, name, default_str); +``` + +- `varname`: The variable name of the parameter +- `name`: The name of the parameter +- `default_str`: The default value + +## Example + +The following example demonstrates how to declare and use KV type parameters: +```rust +kernel_cmdline_param_kv!(ROOTFS_PATH_PARAM, root, ""); +if let Some(rootfs_dev_path) = ROOTFS_PATH_PARAM.value_str() { + ....... +} else { + ....... +}; +``` + +### Usage + +1. In the kernel code, use the `kernel_cmdline_param_kv!` macro to declare the required KV type parameters. +2. During kernel initialization, retrieve the parameter value through the `value_str()` or `value_bool()` method of the parameter. +3. Execute corresponding operations based on the parameter value. + +By following these steps, developers can flexibly use kernel boot command line parameters to control kernel behavior. + +## TODO + +- Support displaying the current kernel's boot command line parameters under `/proc/cmdline` (requires procfs refactoring) +- Support setting callback functions to set parameter values diff --git a/docs/locales/en/kernel/boot/index.rst b/docs/locales/en/kernel/boot/index.rst new file mode 100644 index 00000000..1123daca --- /dev/null +++ b/docs/locales/en/kernel/boot/index.rst @@ -0,0 +1,22 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/boot/index.rst + + - Translation time: 2025-05-19 01:41:19 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Bootloader +==================================== + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + bootloader + cmdline diff --git a/docs/locales/en/kernel/configuration/arch.md b/docs/locales/en/kernel/configuration/arch.md new file mode 100644 index 00000000..27354af1 --- /dev/null +++ b/docs/locales/en/kernel/configuration/arch.md @@ -0,0 +1,45 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/configuration/arch.md + +- Translation time: 2025-05-19 01:41:24 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Target Architecture Configuration + +## Supported Architectures + +- x86_64 +- riscv64 + +## Architecture-Specific Configuration + +In order to support the debugging functionality of VSCode, we need to modify the following line in the `.vscode/settings.json` file: +``` + "rust-analyzer.cargo.target": "riscv64gc-unknown-none-elf", + // "rust-analyzer.cargo.target": "x86_64-unknown-none", +``` + +If you want to compile for the x86_64 architecture, enable the x86_64 line and comment out the others. +If you want to compile for the riscv64 architecture, enable the riscv64 line and comment out the others. + +At the same time, we also need to modify the environment variable configuration in the makefile: + +Please modify the following line in the `env.mk` file: +```Makefile +ifeq ($(ARCH), ) +# !!!!在这里设置ARCH,可选x86_64和riscv64 +# !!!!!!!如果不同时调整这里以及vscode的settings.json,那么自动补全和检查将会失效 +export ARCH=riscv64 +endif +``` + +Please note that changing the architecture requires a recompilation, so please run `make clean` to clean up the compilation results. Then run `make run` to proceed. diff --git a/docs/locales/en/kernel/configuration/config.md b/docs/locales/en/kernel/configuration/config.md new file mode 100644 index 00000000..766096df --- /dev/null +++ b/docs/locales/en/kernel/configuration/config.md @@ -0,0 +1,114 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/configuration/config.md + +- Translation time: 2025-05-19 01:41:17 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Kernel Compilation Configuration Guide + +## Principle + +  Within the kernel directory, the kernel configuration is set using `kernel.config`. This file is parsed in a manner similar to a TOML file, and then the configuration of each module's `d.config` is parsed to determine the status of features. + +## Example + +**kernel.config** + +```toml +[[module.include]] +name = "init" +path = "src/init/" +enable = "y" +description = "" + +[[module.include]] +name = "mm" +path = "src/mm/" +enable = "y" +description = "" +``` + +- **[[module.include]]:** Adds the module to the include list +- **name:** Module name +- **path:** Module path, where the `d.config` file is located +- **enable:** + - **y:** Enabled, parse the `d.config` file of the module + - **n:** Disabled, do not parse +- **description:** Description of the module + +**src/mm/d.config** + +```toml +[module] +name = "mm" +description = "" + +[[module.include]] +name = "allocator" +path = "src/mm/allocator/" +enable = "y" +description = "" + +[[module.features]] +name = "mm_debug" +enable = "y" +description = "" +``` + +- **[module]:** Current module + - **name:** Name of the current module + - **description:** Description of the module +- **[[module.include]]:** Modules included in the current module, same as in `kernel.config` +- **[[module.features]]:** Features in the current module + - **name:** Feature name + - **enable:** Whether the feature is enabled + - **y:** Enabled + - **n:** Disabled + - **description:** Description of the feature + +*The following are the `d.config` files of other modules:* + +**src/mm/allocator/d.config** + +```toml +[module] +name = "allocator" +description = "" + +[[module.features]] +name = "allocator_debug" +enable = "y" +description = "" +``` + +**src/init/d.config** + +```toml +[module] +name = "init" +description = "" + +[[module.features]] +name = "init_debug" +enable = "y" +description = "" +``` + +All features enabled in the `d.config` files of the activated modules will be ultimately generated into the `D.config` file in the kernel directory. That is, `D.config` is the final kernel compilation configuration, as follows: + +**D.config** + +``` +init_debug = y +allocator_debug = y +mm_debug = y +``` diff --git a/docs/locales/en/kernel/configuration/index.rst b/docs/locales/en/kernel/configuration/index.rst new file mode 100644 index 00000000..50b2e4af --- /dev/null +++ b/docs/locales/en/kernel/configuration/index.rst @@ -0,0 +1,22 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/configuration/index.rst + + - Translation time: 2025-05-19 01:41:17 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Kernel Compilation Configuration +==================================== + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + config + arch diff --git a/docs/locales/en/kernel/container/index.rst b/docs/locales/en/kernel/container/index.rst new file mode 100644 index 00000000..0069ca91 --- /dev/null +++ b/docs/locales/en/kernel/container/index.rst @@ -0,0 +1,26 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/container/index.rst + + - Translation time: 2025-05-19 01:41:19 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +Containerization +==================================== + + This is the documentation related to containerization in DragonOS. + + It mainly includes namespace, overlayfs, and cgroup + +.. toctree:: + :maxdepth: 2 + + namespaces/index + ../filesystem/unionfs/index diff --git a/docs/locales/en/kernel/container/namespaces/index.rst b/docs/locales/en/kernel/container/namespaces/index.rst new file mode 100644 index 00000000..61c4ee43 --- /dev/null +++ b/docs/locales/en/kernel/container/namespaces/index.rst @@ -0,0 +1,28 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/container/namespaces/index.rst + + - Translation time: 2025-05-19 01:41:19 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +Namespaces +==================================== + +DragonOS's namespaces currently support pid_namespace and mnt_namespace, and more features are expected to be added in the future. + +Namespaces are an important component in the process of containerization. + +Since the current OS is single-user, user_namespace is globally static. + +.. toctree:: + :maxdepth: 1 + + pid_namespace + mnt_namespace diff --git a/docs/locales/en/kernel/container/namespaces/mnt_namespace.md b/docs/locales/en/kernel/container/namespaces/mnt_namespace.md new file mode 100644 index 00000000..ac145e8d --- /dev/null +++ b/docs/locales/en/kernel/container/namespaces/mnt_namespace.md @@ -0,0 +1,33 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/container/namespaces/mnt_namespace.md + +- Translation time: 2025-05-19 01:41:19 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Mount Namespace + +## Underlying Architecture + +pcb -> nsproxy -> mnt_namespace + +Each mounted file system has its own independent mount point, which is represented in the data structure as a red-black tree of mounts. Each namespace has its own independent mounts, so mounting and unmounting file systems will not affect others. + +## System Call Interface + +- clone + - CLONE_NEWNS is used to create a new MNT namespace. It provides an independent file system mount point. +- unshare + - After calling unshare() with the CLONE_NEWPID flag, all subsequent child processes will run in the new namespace. +- setns + - Adds the process to the specified namespace. +- chroot + - Changes the current process's root directory to the specified path, providing file system isolation. diff --git a/docs/locales/en/kernel/container/namespaces/pid_namespace.md b/docs/locales/en/kernel/container/namespaces/pid_namespace.md new file mode 100644 index 00000000..6da5823d --- /dev/null +++ b/docs/locales/en/kernel/container/namespaces/pid_namespace.md @@ -0,0 +1,38 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/container/namespaces/pid_namespace.md + +- Translation time: 2025-05-19 01:41:31 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Process Namespace +:::{note} Author: Cao Fengyi 1553389239@qq.com + +October 30, 2024 +::: + +`pid_namespace` is a type of namespace in the kernel that is used to achieve process isolation. It allows processes running in different namespaces to have independent views of process IDs (PIDs). + +## Underlying Architecture + +pcb -> nsproxy -> pid_namespace +- `pid_namespace` contains an independent set of process allocators and an orphan process reaper, which independently manages PIDs within the namespace. +- Detailed information about processes is stored in the proc file system. The information corresponding to a specific PID is located within the `pid_namespace`, recording information related to the `pid_namespace`. +- The limitations imposed by `pid_namespace` are controlled and managed by `ucount`. + +## System Call Interface + +- `clone` + - `CLONE_NEWPID` is used to create a new PID namespace. When this flag is used, the child process will run in the new PID namespace, with the process ID starting from 1. +- `unshare` + - After calling `unshare()` with the `CLONE_NEWPID` flag, all subsequent child processes will run within the new namespace. +- `getpid` + - Calling `getpid()` within a namespace returns the process ID of the process within the current PID namespace. diff --git a/docs/locales/en/kernel/core_api/atomic.md b/docs/locales/en/kernel/core_api/atomic.md new file mode 100644 index 00000000..aac92c00 --- /dev/null +++ b/docs/locales/en/kernel/core_api/atomic.md @@ -0,0 +1,112 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/core_api/atomic.md + +- Translation time: 2025-05-19 01:41:25 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Atomic Variables + +## Introduction + +  DragonOS implements atomic variables of type `atomic_t`. Atomic variables are implemented using architecture-specific atomic operation instructions. The specific implementation is located in `kernel/common/atomic.h`. + +## API + +   Note that all the following APIs are atomic operations. + +### `inline void atomic_add(atomic_t *ato, long val)` + +#### Description + +   Atomically adds a specified value to the atomic variable. + +#### Parameters + +**ato** + +   The atomic variable object. + +**val** + +   The value to be added to the variable. + +### `inline void atomic_sub(atomic_t *ato, long val)` + +#### Description + +   Atomically subtracts a specified value from the atomic variable. + +#### Parameters + +**ato** + +   The atomic variable object. + +**val** + +   The value to be subtracted from the variable. + +### `void atomic_inc(atomic_t *ato)` + +#### Description + +   Atomically increments the atomic variable by 1. + +#### Parameters + +**ato** + +   The atomic variable object. + +### `void atomic_dec(atomic_t *ato)` + +#### Description + +   Atomically decrements the atomic variable by 1. + +#### Parameters + +**ato** + +   The atomic variable object. + +### `inline void atomic_set_mask(atomic_t *ato, long mask)` + +#### Description + +   Performs a bitwise OR operation between the atomic variable and the mask variable. + +#### Parameters + +**ato** + +   The atomic variable object. + +**mask** + +   The variable used for the OR operation with the atomic variable. + +### `inline void atomic_clear_mask(atomic_t *ato, long mask)` + +#### Description + +   Performs a bitwise AND operation between the atomic variable and the mask variable. + +#### Parameters + +**ato** + +   The atomic variable object. + +**mask** + +   The variable used for the AND operation with the atomic variable. diff --git a/docs/locales/en/kernel/core_api/casting.md b/docs/locales/en/kernel/core_api/casting.md new file mode 100644 index 00000000..510f08cc --- /dev/null +++ b/docs/locales/en/kernel/core_api/casting.md @@ -0,0 +1,77 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/core_api/casting.md + +- Translation time: 2025-05-19 01:41:11 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Type Conversion Library API + +  The kernel provides some functions to help you convert between different types. These include the following types: + +- Numeric type conversion (using the `num-traits` library) +- Arc type conversion + +  All functions not specially marked are implemented in `kernel/src/libs/casting.rs`. + +## 1. Numeric Type Conversion + +### 1.1 Conversion Between Integer Types and Enum Types + +  You can use macros provided by the `num-traits` library to convert between enum types and integer types. +The SystemError enum type uses this approach, and you can find its usage in `kernel/src/syscall/mod.rs`. + +  It first inherits the `FromPrimitive, ToPrimitive` two traits, and then performs the conversion like this: + +```rust +impl SystemError { + /// @brief 把posix错误码转换为系统错误枚举类型。 + pub fn from_posix_errno(errno: i32) -> Option { + // posix 错误码是小于0的 + if errno >= 0 { + return None; + } + return ::from_i32(-errno); + } + + /// @brief 把系统错误枚举类型转换为负数posix错误码。 + pub fn to_posix_errno(&self) -> i32 { + return -::to_i32(self).unwrap(); + } +} +``` + +  These two functions well illustrate how to use these two traits. + +## 2. Arc Type Conversion + +### 2.1 Conversion from Arc to Arc + +  When we need to convert an `Arc` to a specific type pointer of `Arc`, we need to implement the `DowncastArc` trait for `U`. This trait is defined in `kernel/src/libs/casting.rs`. It requires `trait U` to implement the `Any + Sync + Send` trait. + +  To implement the `DowncastArc` trait for `trait U: Any + Send + Sync`, you need to do the following: + +```rust +impl DowncastArc for dyn U { + fn as_any_arc(self: Arc) -> Arc { + return self; + } +} +``` + +  Using the `DowncastArc` trait, we can convert like this: + +```rust +let arc: Arc = ...; +let arc_t: Arc = arc.downcast_arc::().unwrap(); +``` + +  If the specific type of `arc` is not `Arc`, then `downcast_arc::()` will return `None`. diff --git a/docs/locales/en/kernel/core_api/index.rst b/docs/locales/en/kernel/core_api/index.rst new file mode 100644 index 00000000..b4c6897f --- /dev/null +++ b/docs/locales/en/kernel/core_api/index.rst @@ -0,0 +1,28 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/core_api/index.rst + + - Translation time: 2025-05-19 01:41:08 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +Core API Documentation +==================================== + + This is the core API documentation for DragonOS. + +.. toctree:: + :maxdepth: 1 + :caption: Kernel Utility Library + + kernel_api + atomic + casting + notifier_chain + softirq diff --git a/docs/locales/en/kernel/core_api/kernel_api.md b/docs/locales/en/kernel/core_api/kernel_api.md new file mode 100644 index 00000000..f8c8c430 --- /dev/null +++ b/docs/locales/en/kernel/core_api/kernel_api.md @@ -0,0 +1,630 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/core_api/kernel_api.md + +- Translation time: 2025-05-19 01:43:39 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# DragonOS Kernel Core API + +## Circular Linked List Management Functions + +  Circular linked list is one of the important data structures in the kernel. It is included in `kernel/common/list.h`. + +### `void list_init(struct List *list)` + +#### Description + +  Initialize a List structure so that its prev and next pointers point to itself. + +#### Parameters + +**list** + +  The List structure to be initialized. + +### `void list_add(struct List *entry, struct List *node)` + +#### Description + +  Insert the node after the entry. + +#### Parameters + +**entry** + +  An existing node in the circular linked list. + +**node** + +  The node to be inserted. + +### `void list_append(struct List *entry, struct List *node)` + +#### Description + +  Insert the node before the entry. + +#### Parameters + +**entry** + +  An existing node in the circular linked list. + +**node** + +  The node to be inserted. + +### `void list_del(struct List *entry)` + +#### Description + +  Remove the node from the list. + +#### Parameters + +**entry** + +  The node to be removed. + +### `list_del_init(struct List *entry)` + +#### Description + +  Remove the node from the list and re-initialize the entry using list_init(). + +#### Parameters + +**entry** + +  The node to be removed. + +### `bool list_empty(struct List *entry)` + +#### Description + +  Check if the list is empty. + +#### Parameters + +**entry** + +  A node in the list. + +### `struct List *list_prev(struct List *entry)` + +#### Description + +  Get the previous node of the entry. + +#### Parameters + +**entry** + +  A node in the list. + +### `struct List *list_next(struct List *entry)` + +#### Description + +  Get the next node of the entry. + +#### Parameters + +**entry** + +  A node in the list. + +### `void list_replace(struct List *old, struct List *new)` + +#### Description + +  Replace the old node in the list with the new node. + +#### Parameters + +**old** + +  The node to be removed. + +**new** + +  The new node to be inserted into the list. + +(_translated_label___list_entry_en)= + +### `list_entry(ptr, type, member)` + +#### Description + +  This macro can get the address of the structure that contains the List pointed to by ptr. + +#### Parameters + +**ptr** + +  Pointer to the List structure. + +**type** + +  The type of the structure that contains the List. + +**member** + +  The name of the List structure member in the structure that contains the List. + +### `list_first_entry(ptr, type, member)` + +#### Description + +  Get the first element in the list. Please note that this macro requires the list to be non-empty, otherwise it will cause an error. + +#### Parameters + +  Same as {ref}`list_entry() <_list_entry>` + +### `list_first_entry_or_null(ptr, type, member)` + +#### Description + +  Get the first element in the list. If the list is empty, return NULL. + +#### Parameters + +  Same as {ref}`list_entry() <_list_entry>` + +### `list_last_entry(ptr, type, member)` + +#### Description + +  Get the last element in the list. Please note that this macro requires the list to be non-empty, otherwise it will cause an error. + +#### Parameters + +  Same as {ref}`list_entry() <_list_entry>` + +### `list_last_entry_or_full(ptr, type, member)` + +#### Description + +  Get the last element in the list. If the list is empty, return NULL. + +#### Parameters + +  Same as {ref}`list_entry() <_list_entry>` + +(_translated_label___list_next_entry_en)= +### `list_next_entry(pos, member)` + +#### Description + +  Get the next element in the list. + +#### Parameters + +**pos** + +  Pointer to the outer structure. + +**member** + +  The name of the List structure member in the outer structure. + +### `list_prev_entry(pos, member)` + +#### Description + +  Get the previous element in the list. + +#### Parameters + +  Same as {ref}`list_next_entry() <_list_next_entry>` + +(_translated_label___list_for_each_en)= +### `list_for_each(ptr, head)` + +#### Description + +  Traverse the entire list (from front to back). + +#### Parameters + +**ptr** + +  Pointer to the List structure. + +**head** + +  Pointer to the head node of the list (struct List*). + +### `list_for_each_prev(ptr, head)` + +#### Description + +  Traverse the entire list (from back to front). + +#### Parameters + +  Same as {ref}`list_for_each() <_list_for_each>` + +(_translated_label___list_for_each_safe_en)= +### `list_for_each_safe(ptr, n, head)` + +#### Description + +  Traverse the entire list from front to back (supports deletion of the current list node). + +  This macro uses a temporary variable to prevent errors that may occur during iteration if the current ptr node is deleted. + +#### Parameters + +**ptr** + +  Pointer to the List structure. + +**n** + +  Pointer to store the temporary value (List type). + +**head** + +  Pointer to the head node of the list (struct List*). + +### `list_for_each_prev_safe(ptr, n, head)` + +#### Description + +  Traverse the entire list from back to front (supports deletion of the current list node). + +  This macro uses a temporary variable to prevent errors that may occur during iteration if the current ptr node is deleted. + +#### Parameters + +  Same as {ref}`list_for_each_safe() <_list_for_each_safe>` + +(_translated_label___list_for_each_entry_en)= +### `list_for_each_entry(pos, head, member)` + +#### Description + +  Iterate through the list of a given type from the beginning. + +#### Parameters + +**pos** + +  Pointer to a structure of the specific type. + +**head** + +  Pointer to the head node of the list (struct List*). + +**member** + +  The name of the List member in the structure pointed to by pos. + +### `list_for_each_entry_reverse(pos, head, member)` + +#### Description + +  Iterate through the list of a given type in reverse order. + +#### Parameters + +  Same as {ref}`list_for_each_entry() <_list_for_each_entry>` + +### `list_for_each_entry_safe(pos, n, head, member)` + +#### Description + +  Iterate through the list of a given type from the beginning (supports deletion of the current list node). + +#### Parameters + +**pos** + +  Pointer to a structure of the specific type. + +**n** + +  Pointer to store the temporary value (same type as pos). + +**head** + +  Pointer to the head node of the list (struct List*). + +**member** + +  The name of the List member in the structure pointed to by pos. + +### `list_prepare_entry(pos, head, member)` + +#### Description + +  Prepare a 'pos' structure for {ref}`list_for_each_entry_continue() <_list_for_each_entry_continue>`. + +#### Parameters + +**pos** + +  Pointer to a structure of the specific type, used as the starting point for iteration. + +**head** + +  Pointer to the struct List structure to start iteration from. + +**member** + +  The name of the List member in the structure pointed to by pos. + +(_translated_label___list_for_each_entry_continue_en)= +### `list_for_each_entry_continue(pos, head, member)` + +#### Description + +  Continue iterating through the list from the next element of the specified position. + +#### Parameters + +**pos** + +  Pointer to a structure of the specific type. This pointer is used as the iteration pointer. + +**head** + +  Pointer to the struct List structure to start iteration from. + +**member** + +  The name of the List member in the structure pointed to by pos. + +### `list_for_each_entry_continue_reverse(pos, head, member)` + +#### Description + +  Iterate through the list in reverse order, starting from the previous element of the specified position. + +#### Parameters + +  Same as {ref}`list_for_each_entry_continue() <_list_for_each_entry_continue>` + +### `list_for_each_entry_from(pos, head, member)` + +#### Description + +  Continue iterating through the list from the specified position. + +#### Parameters + +  Same as {ref}`list_for_each_entry_continue() <_list_for_each_entry_continue>` + +(_translated_label___list_for_each_entry_safe_continue_en)= +### `list_for_each_entry_safe_continue(pos, n, head, member)` + +#### Description + +  Continue iterating through the list from the next element of the specified position (supports deletion of the current list node). + +#### Parameters + +**pos** + +  Pointer to a structure of the specific type. This pointer is used as the iteration pointer. + +**n** + +  Pointer to store the temporary value (same type as pos). + +**head** + +  Pointer to the struct List structure to start iteration from. + +**member** + +  The name of the List member in the structure pointed to by pos. + +### `list_for_each_entry_safe_continue_reverse(pos, n, head, member)` + +#### Description + +  Iterate through the list in reverse order, starting from the previous element of the specified position (supports deletion of the current list node). + +#### Parameters + +  Same as {ref}`list_for_each_entry_safe_continue() <_list_for_each_entry_safe_continue>` + +### `list_for_each_entry_safe_from(pos, n, head, member)` + +#### Description + +  Continue iterating through the list from the specified position (supports deletion of the current list node). + +#### Parameters + +  Same as {ref}`list_for_each_entry_safe_continue() <_list_for_each_entry_safe_continue>` + +--- + +## Basic C Function Library + +  Kernel programming differs from application layer programming; you will not be able to use functions from LibC. To address this, the kernel implements some commonly used C language functions, trying to make their behavior as close as possible to standard C library functions. It is important to note that the behavior of these functions may differ from standard C library functions, so it is recommended to carefully read the following documentation, which will be helpful to you. + +### String Operations + +#### `int strlen(const char *s)` + +##### Description + +  Measure and return the length of the string. + +##### Parameters + +**src** + +  Source string. + +#### `long strnlen(const char *src, unsigned long maxlen)` + +##### Description + +  Measure and return the length of the string. If the string length is greater than maxlen, return maxlen. + +##### Parameters + +**src** + +  Source string. + +**maxlen** + +  Maximum length. + +#### `long strnlen_user(const char *src, unsigned long maxlen)` + +##### Description + +  Measure and return the length of the string. If the string length is greater than maxlen, return maxlen. + +  This function performs address space validation, requiring the src string to be from user space. If the source string is from kernel space, it will return 0. + +##### Parameters + +**src** + +  Source string, located in user space. + +**maxlen** + +  Maximum length. + +#### `char *strncpy(char *dst, const char *src, long count)` + +##### Description + +  Copy a string of count bytes and return the dst string. + +##### Parameters + +**src** + +  Source string. + +**dst** + +  Destination string. + +**count** + +  Length of the source string to copy. + +#### `char *strcpy(char *dst, const char *src)` + +##### Description + +  Copy the source string and return the dst string. + +##### Parameters + +**src** + +  Source string. + +**dst** + +  Destination string. + +#### `long strncpy_from_user(char *dst, const char *src, unsigned long size)` + +##### Description + +  Copy a string of count bytes from user space to kernel space, and return the size of the copied string. + +  This function performs address space validation to prevent address space overflow issues. + +##### Parameters + +**src** + +  Source string. + +**dst** + +  Destination string. + +**size** + +  Length of the source string to copy. + +#### `int strcmp(char *FirstPart, char *SecondPart)` + +##### Description + +  Compare the sizes of two strings. + +***Return Value*** + +| Situation | Return Value | +| ----------------------- | --- | +| FirstPart == SecondPart | 0 | +| FirstPart > SecondPart | 1 | +| FirstPart < SecondPart | -1 | + +##### Parameters + +**FirstPart** + +  First string. + +**SecondPart** + +  Second string. + +### Memory Operations + +#### `void *memcpy(void *dst, const void *src, uint64_t size)` + +##### Description + +  Copy memory from src to dst. + +##### Parameters + +**dst** + +  Pointer to the destination address. + +**src** + +  Pointer to the source address. + +**size** + +  Size of data to be copied. + +#### `void *memmove(void *dst, const void *src, uint64_t size)` + +##### Description + +  Similar to `memcpy()`, but this function prevents data from being incorrectly overwritten when the source and destination memory regions overlap. + +##### Parameters + +**dst** + +  Pointer to the destination address. + +**src** + +  Pointer to the source address. + +**size** + +  Size of data to be copied. diff --git a/docs/locales/en/kernel/core_api/notifier_chain.md b/docs/locales/en/kernel/core_api/notifier_chain.md new file mode 100644 index 00000000..d1a20c7e --- /dev/null +++ b/docs/locales/en/kernel/core_api/notifier_chain.md @@ -0,0 +1,48 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/core_api/notifier_chain.md + +- Translation time: 2025-05-19 01:41:30 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Notifier Chain Notification Chain + +## 1. Overview of Principles + +  The notification chain is an event notification mechanism between subsystems within the kernel or between modules within a subsystem. Essentially, a notification chain is a list of event handling functions. Each notification chain is associated with a specific type of event (e.g., reboot event). When a specific event occurs, the corresponding callback functions in the event's notification chain are called, allowing the subsystem/module to respond to the event and perform the appropriate processing. + +  The notification chain is somewhat similar to the subscription mechanism. It can be understood as: there is a "notifier" that maintains a list, and the "subscriber" registers its callback function into this list ("subscriber" can also unregister its callback function). When an event occurs that needs to be notified, the "notifier" traverses all the callback functions in the list and calls them, allowing all registered "subscribers" to respond and handle the event accordingly. + +## 2. Core Features + +### 2.1 Registering Callback Functions + +  The callback function is encapsulated into a specific structure and registered into the designated notification chain. The related method is `register`, which is used by the "subscriber". + +### 2.2 Unregistering Callback Functions + +  The callback function is removed from the designated notification chain, i.e., it is deleted from the notification chain. The related method is `unregister`, which is used by the "subscriber". + +### 2.3 Event Notification + +  When an event occurs, the notification chain related to that event performs the event notification through this method. `call_chain` This method traverses all elements in the notification chain and calls the registered callback functions in sequence. This method is used by the "notifier". + +## 3. Types of Notification Chains + +  Each type of notification chain has corresponding `register`, `unregister`, and `call_chain` interfaces, with functions as described in the core features above. + +- `AtomicNotifierChain`: Atomic notification chain, cannot sleep, recommended for use in interrupt context. +- `BlockingNotifierChain`: Blocking notification chain, can sleep, recommended for use in process context. +- `RawNotifierChain`: Raw notification chain, the caller is responsible for thread safety. + +## 4. Other Issues + +  `BlockingNotifierChain` does not currently support the sleeping functionality. diff --git a/docs/locales/en/kernel/core_api/softirq.md b/docs/locales/en/kernel/core_api/softirq.md new file mode 100644 index 00000000..164c77fa --- /dev/null +++ b/docs/locales/en/kernel/core_api/softirq.md @@ -0,0 +1,178 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/core_api/softirq.md + +- Translation time: 2025-05-19 01:41:38 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Soft Interrupt + +  Software interrupt, also known as the bottom half of an interrupt, is used to delay the processing of work that was not completed by the hard interrupt (the top half of the interrupt). Dividing the interrupt into two stages can effectively solve the problems of long interrupt handling time and interrupt loss. + +## 1. Design Philosophy + +  Each CPU has its own pending status. Soft interrupts are "initiated by which CPU, executed by which CPU", and the pending status of each CPU is not shared. The same soft interrupt vector can run concurrently on multiple cores. + +  When we need to register a new soft interrupt, we need to implement the `SoftirqVec` feature for the soft interrupt handler, and then call the `register_softirq` function to register the soft interrupt handler within the soft interrupt mechanism. + +  Please note that due to the reentrancy and concurrency of soft interrupts, the soft interrupt handler must ensure thread safety itself. + +## 2. Soft Interrupt Vector Number + +```rust +pub enum SoftirqNumber { + /// 时钟软中断信号 + TIMER = 0, + /// 帧缓冲区刷新软中断 + VideoRefresh = 1, +} +``` + +## 3. Soft Interrupt API + +### 3.1. SoftirqVec Feature + +```rust +pub trait SoftirqVec: Send + Sync + Debug { + fn run(&self); +} +``` + +  The feature that the soft interrupt handler needs to implement. It needs to implement the `run` function to handle the soft interrupt. When the soft interrupt is executed, the `run` function will be called. + +### 3.2. Softirq API + +#### 3.2.1. Register Soft Interrupt Vector + +```rust +pub fn register_softirq(&self, + softirq_num: SoftirqNumber, + handler: Arc, + ) -> Result +``` + +- Parameters: + + - softirq_num: Interrupt vector number + + - handler: The structure corresponding to the interrupt function, which needs to point to a structure variable that implements the `SoftirqVec` feature + +- Return: + + - Ok(i32): 0 + + - Err(SystemError): Error code + +#### 3.2.2. Unregister Soft Interrupt Vector + +```rust +pub fn unregister_softirq(&self, softirq_num: SoftirqNumber) +``` + +- Parameters: + + - softirq_num: Interrupt vector number + +#### 3.2.3. Execute Soft Interrupt + +```rust +pub fn do_softirq(&self) +``` + +- Purpose: Execute the soft interrupt function (**only called after hard interrupt execution**) + +#### 3.2.4. Clear the Pending Flag of Soft Interrupt + +```rust +pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) +``` + +- Purpose: Clear the pending flag of the specified soft interrupt on the current CPU. Please note that this function is unsafe because it directly modifies the pending flag without locking. + +- Parameters: + + - softirq_num: Interrupt vector number + +#### 3.2.5. Mark Soft Interrupt as to be Executed + +```rust +pub fn raise_softirq(&self, softirq_num: SoftirqNumber) +``` + +- Purpose: Mark the specified soft interrupt as to be executed on the current CPU + +- Parameters: + + - softirq_num: Interrupt vector number + +### 3.3. Usage Example + +```rust +#[derive(Debug)] +/// SoftirqExample中断结构体 +pub struct SoftirqExample { + running: AtomicBool, +} +/// SoftirqExample中断需要处理的逻辑 +fn softirq_example_func() { + println!("addressed SoftirqExample"); +} +impl SoftirqVec for SoftirqExample { + fn run(&self) { + if self.set_run() == false { + return; + } + + softirq_example_func(); + + self.clear_run(); + } +} +impl SoftirqExample { + pub fn new() -> SoftirqExample { + SoftirqExample { + running: AtomicBool::new(false), + } + } + + fn set_run(&self) -> bool { + let x = self + .running + .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed); + if x.is_ok() { + return true; + } else { + return false; + } + } + + fn clear_run(&self) { + self.running.store(false, Ordering::Release); + } +} +fn main() { + let softirq_example = Arc::new(SoftirqExample::new()); + let softirq_num = 2; + // 注册SoftirqExample中断 + softirq_vectors() + .register_softirq(SoftirqNumber::from(softirq_num as u64), softirq_example) + .expect("failed to register SoftirqExample"); + + // 标志SoftirqExample中断需要执行 + softirq_vectors().raise_softirq(SoftirqNumber::from(softirq_num as u64)); + + // 标志SoftirqExample中断不需要执行 + softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64)); + + // 解注册SoftirqExample中断 + softirq_vectors().unregister_softirq(SoftirqNumber::from(softirq_num as u64)); +} +``` diff --git a/docs/locales/en/kernel/cpu_arch/index.rst b/docs/locales/en/kernel/cpu_arch/index.rst new file mode 100644 index 00000000..6f6a5e86 --- /dev/null +++ b/docs/locales/en/kernel/cpu_arch/index.rst @@ -0,0 +1,23 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/cpu_arch/index.rst + + - Translation time: 2025-05-19 01:41:20 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Processor Architecture +==================================== + + This section of the documentation provides descriptions of some programming implementation details related to the processor architecture. + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + x86_64/index diff --git a/docs/locales/en/kernel/cpu_arch/x86_64/index.rst b/docs/locales/en/kernel/cpu_arch/x86_64/index.rst new file mode 100644 index 00000000..726d8751 --- /dev/null +++ b/docs/locales/en/kernel/cpu_arch/x86_64/index.rst @@ -0,0 +1,21 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/cpu_arch/x86_64/index.rst + + - Translation time: 2025-05-19 01:41:18 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +x86-64 Related Documentation +==================================== + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + usb_legacy_support diff --git a/docs/locales/en/kernel/cpu_arch/x86_64/usb_legacy_support.md b/docs/locales/en/kernel/cpu_arch/x86_64/usb_legacy_support.md new file mode 100644 index 00000000..d45b4d79 --- /dev/null +++ b/docs/locales/en/kernel/cpu_arch/x86_64/usb_legacy_support.md @@ -0,0 +1,24 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/cpu_arch/x86_64/usb_legacy_support.md + +- Translation time: 2025-05-19 01:41:19 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# USB Legacy Support + +## Introduction + +  USB Legacy Support refers to the support provided by the BIOS for USB mice and USB keyboards. On computers that support and enable USB Legacy Support, the USB mouse and keyboard are simulated by the BIOS, making them appear to the operating system as if they were PS/2 mice and keyboards. + +## Related + +- When initializing the USB controller, its USB Legacy Support should be disabled. diff --git a/docs/locales/en/kernel/debug/debug-kernel-with-gdb.md b/docs/locales/en/kernel/debug/debug-kernel-with-gdb.md new file mode 100644 index 00000000..e10aedf0 --- /dev/null +++ b/docs/locales/en/kernel/debug/debug-kernel-with-gdb.md @@ -0,0 +1,375 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/debug/debug-kernel-with-gdb.md + +- Translation time: 2025-05-19 01:41:41 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# How to Use GDB to Debug the Kernel + +## Introduction +  GDB is a powerful open-source debugging tool that can help you better diagnose and fix errors in programs. + +  It provides a rich set of features that allow you to check the execution status of a program, track the execution flow of code, view and modify the values of variables, analyze memory states, and more. It can be used in conjunction with a compiler to allow you to access debugging information during the debugging process. + +  This tutorial will guide you on how to use `rust-gdb` to debug the kernel in DragonOS, including how to start debugging and the corresponding debugging commands. + +:::{note} +If you are already familiar with the various commands of `rust-gdb`, you only need to read the first part of this tutorial. +::: + +--- +## 1. Getting Started + +### 1.1 Preparation + +  Before you start debugging the kernel, you need to enable debug mode in /Kernel/Cargo.toml by changing `debug = false` to `debug = true` in the Cargo.toml file. + +```shell +debug = false +``` +  **Change to** +```shell +debug = true +``` + +### 1.2 Running DragonOS + +  After the preparation is complete, you can compile and run DragonOS to proceed with the subsequent debugging work. + +  Open a terminal in the root directory of DragonOS and use `make run` to start compiling and running DragonOS. For more help with compilation commands, see +> [Building DragonOS](https://docs.dragonos.org/zh_CN/latest/introduction/build_system.html). + +### 1.3 Running GDB +  Once DragonOS has started running, you can start debugging with GDB. + +  **You only need to open a new terminal and run `make gdb` to start the GDB debugger.** + +```shell +❯ make gdb +rust-gdb -n -x tools/.gdbinit +GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1 +Copyright (C) 2022 Free Software Foundation, Inc. +License GPLv3+: GNU GPL version 3 or later +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. +Type "show copying" and "show warranty" for details. +This GDB was configured as "x86_64-linux-gnu". +Type "show configuration" for configuration details. +For bug reporting instructions, please see: +. +Find the GDB manual and other documentation resources online at: + . + +--Type for more, q to quit, c to continue without paging-- +``` + +:::{note} +If you see the above information, input `c` and press Enter. +::: + +--- + +## 2. Debugging + +### 2.1 Start + +  After completing the above steps, you can start debugging. + +```shell +For help, type "help". +Type "apropos word" to search for commands related to "word". +warning: No executable has been specified and target does not support +determining executable automatically. Try using the "file" command. +0xffff8000001f8f63 in ?? () +(gdb) +``` + +:::{note} +The output information from GDB, `0xffff8000001f8f63 in ?? ()`, indicates that DragonOS is still in the process of booting. +::: + +  **Input `continue` or `c` to continue the program execution.** + +```shell +For help, type "help". +Type "apropos word" to search for commands related to "word". +warning: No executable has been specified and target does not support +determining executable automatically. Try using the "file" command. +0xffff8000001f8f63 in ?? () +(gdb) continue +Continuing. +``` + +  While DragonOS is running, you can press `Ctrl+C` at any time to send an interrupt signal to view the current state of the kernel. + +```shell +(gdb) continue +Continuing. +^C +Thread 1 received signal SIGINT, Interrupt. +0xffff800000140c21 in io_in8 (port=113) at common/glib.h:136 +136 __asm__ __volatile__("inb %%dx, %0 \n\t" +(gdb) +``` + +### 2.2 Setting Breakpoints and Watchpoints + +  Setting breakpoints and watchpoints is the most fundamental step in program debugging. + +- **Setting Breakpoints** + +  You can use the `break` or `b` command to set a breakpoint. + +  Regarding the usage of `break` or `b` commands: + +```shell +b #在当前活动源文件的相应行号打断点 + +b : #在对应文件的相应行号打断点 + +b #为一个命名函数打断点 +``` + +- **Setting Watchpoints** + +  You can use the `watch` command to set a watchpoint. + +```shell +watch # 设置对特定变量的监视点,将在特定变量发生变化的时候触发断点 + +watch # 设置对特定表达式的监视点,比如watch *(int*)0x12345678会在内存地址0x12345678处 + # 的整数值发生更改时触发断点。 +``` + +- **Managing Breakpoints and Watchpoints** + +  Once we have set breakpoints, how can we view all the breakpoint information? + +  You can use `info b`, `info break`, or `info breakpoints` to view all breakpoint information: + +```shell +(gdb) b 309 +Breakpoint 12 at 0xffff8000001f8f16: file /home/heyicong/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/thingbuf-0.1.4/src/lib.rs, line 315. +(gdb) watch slots +Watchpoint 13: slots +(gdb) info b +Num Type Disp Enb Address What +12 breakpoint keep y 0xffff8000001f8f16 in thingbuf::Core::pop_ref + at /home/heyicong/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/thingbuf-0.1.4/src/lib.rs:315 +13 watchpoint keep y slots +(gdb) +``` + +  In the above information, the breakpoint with number 12 is the one we set in line 309 of the active source file. If its `Address` is ``, it indicates that there are identical breakpoints at multiple addresses. This is very common in loops. The breakpoint with number 13 is the watchpoint we set for the `slots` variable. + +  We can perform operations on breakpoints or watchpoints using the following commands: + +```shell +delete # 或 d 删除对应编号的断点,在您不再需要使用这个断点的时候可以通过此命令删除断点 +delete # 或 d 删除对应编号的监视点,在您不再需要使用这个监视点的时候可以通过此命令删除监视点 + +disable # 禁用对应编号的断点,这适合于您只是暂时不需要使用这个断点时使用,当您禁用一个断点,下 + # 次程序运行到该断点处将不会停下来 +disable # 禁用对应编号的监视点,这适合于您只是暂时不需要使用这个监视点时使用 + +enable # 启用对应编号的断点 +enable # 启用对应编号的监视点 + +#clear命令 +clear # 清除当前活动源文件的断点以及监视点 +clear # 清除对应编号的所有断点或监视点,这与delete行为是一致的 +clear # 清除指定文件的所有断点与监视点 +``` + +## 2.3 Viewing Variables and Memory + +- **print and display** + +  You can use `print` or `p` to print variable values. + +  The `print` command is used to print the value of a variable or expression. It allows you to view the data in the program during debugging. + +```shell +print # 打印对应变量名的值,例如:print my_variable 或者 p my_variable + +print # 打印合法表达式的值,例如:print a+b 或者 p a+b + +# 示例输出 +(gdb) print order +$3 = core::sync::atomic::Ordering::SeqCst +``` + +```{note} +如果您不仅想打印值,还想显示更多详细信息(例如类型信息),可以使用ptype命令。 +``` + +  You can use the `display` command to continuously track variables or expressions. The `display` command is used to set expressions that need to be tracked and displayed every time the program stops. It is similar to the print command, but unlike print, the display command automatically prints the value of the specified expression every time the program stops, without requiring manual input of a command. + +```shell +display # 打印对应变量名的值,例如:display my_variable + +display # 打印合法表达式的值,例如:display a+b + +# 示例输出 +(gdb) display order +1: order = core::sync::atomic::Ordering::SeqCst #其中1表示display编号, + #您可以通过info display命令来查看所有display编号 +``` + +```{note} +一旦您设置了display命令,每当程序停止(例如,在断点处停止)时,GDB将自动打印指定表达式的值。 + +display命令非常有用,因为它允许您在调试过程中持续监视表达式的值,而无需每次都手动输入print命令。它特别适用于那些您希望持续跟踪的变量或表达式。 +``` + +  **To cancel an already set display command and stop automatically displaying the value of an expression, you can use the undisplay command:** + +```shell +undisplay # 如果不指定,则将取消所有已设置的display命令, + # 您可以通过info display命令来查看所有display编号 +``` + +```{note} +请注意,print和display命令只会在程序暂停执行时评估变量或表达式的值。如果程序正在运行,您需要通过设置断点或使用其他调试命令来暂停程序,然后才能使用print命令查看数据的值,display命令设置的值将会在程序暂停时自动输出。 +``` + +- **Output Format** + +  You can set the output format to get more information you need, for example: `print /a var` +> Refer to [GDB Cheat Sheet](https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf) + +```shell +Format +a Pointer. +c Read as integer, print as character. +d Integer, signed decimal. +f Floating point number. +o Integer, print as octal. +s Try to treat as C string. +t Integer, print as binary (t = „two“). +u Integer, unsigned decimal. +x Integer, print as hexadecimal. +``` + +### 2.4 Viewing the Call Stack + +- **Viewing the Call Stack** + +  When the program is paused at a breakpoint, how should you trace the program's behavior? + +  You can use the `backtarce` command to view the call stack. The `backtrace` command is used to print the backtrace information of the current call stack. It displays all the active function call chains during program execution, including the function names, parameters, and line numbers in the source files. + +```shell +# 示例输出 +(gdb) backtrace +#0 function1 (arg1=10, arg2=20) at file1.c:15 +#1 function2 () at file2.c:25 +#2 xx () at xx.c:8 +``` + +  Each line of backtrace information starts with #, indicating the frame number. Then comes the function name and parameter list, followed by the source file name and line number. +By viewing the backtrace information, you can understand in which functions the program is executing and the position of each function in the call stack. This is very useful for debugging the program and locating problems. + +- **Switching the Stack** + +  You can use the `frame` or `f` command to switch to the corresponding stack frame to get more information and perform operations. + +```shell +frame +f +``` + +  In addition to simply executing the backtrace command, you can also use some options to customize the output of the backtrace information. For example: +```shell +backtrace full #显示完整的符号信息,包括函数参数和局部变量。 +backtrace #限制回溯信息的帧数,只显示指定数量的帧。 +backtrace - #指定要显示的帧范围。 +backtrace thread #显示指定线程的回溯信息。 +``` + +### 2.5 Multi-core + +  When debugging the kernel, you may need to view the running status of each core. + +  You can use the `info threads` command to view the running status of each core. + +```shell +(gdb) info threads + Id Target Id Frame + 1 Thread 1.1 (CPU#0 [halted ]) 0xffff800000140a3e in Start_Kernel () at main.c:227 +* 2 Thread 1.2 (CPU#1 [running]) thingbuf::Core::pop_ref () + at /home/heyicong/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/thingbuf-0.1.4/src/lib.rs:315 +(gdb) +``` + +  You can use the `thread ` command to switch to the context of a specific core to view and debug the status of that core. For example: + +```shell +(gdb) thread 1 +[Switching to thread 1 (Thread 1.1)] +#0 0xffff800000140a3e in Start_Kernel () at main.c:227 +227 hlt(); +``` + +### 2.6 More + +  Next, I will introduce more commands that you may find useful during debugging: + +```shell +step #或者s,逐行执行程序,并进入到函数调用中。可以在step命令后加执行次数,例:step 3 表示要连续执行3个步骤 +step #进入指定的函数,并停止在函数内的第一行。 + +next #或者n,逐行执行程序,但跳过函数调用,直接执行函数调用后的下一行代码。 + #它允许你在不进入函数内部的情况下执行代码,从而快速跳过函数调用的细节。 + #同样,next也可以在命令后加执行次数 + +finish #用于从当前函数中一直执行到函数返回为止,并停在调用该函数的地方。 + #它允许你快速执行完当前函数的剩余部分,并返回到调用函数的上下文中。 + +continue #用于继续程序的执行,直到遇到下一个断点或 + #程序正常结束或者程序暂停。 + +quit #退出调试 + +list #或者l,显示当前活动源文件源代码的片段,以及当前执行的位置。 +list : #显示文件里面的函数的源代码片段 +list : #显示文件里面的附近的源代码片段 +list , #显示当前活动源文件的之间的源代码片段 +set listsize #设置list命令显示的源代码行数。默认情况下,list命令显示当前行和其周围的几行代码。 + +info args #显示当前函数的参数及其值 +info breakpoints #显示断点以及监视点信息 +info display #显示当前设置的display列表 +info locals #显示当前函数/栈帧中的局部变量及其值 +info sharedlibrary #显示当前已加载的共享库(shared library)信息 +info signals #显示当前程序所支持的信号信息。它可以列出程序可以接收和处理的不同信号的列表。 +info threads #显示各个核心/线程信息,它可以列出当前正在运行的核心/线程以及它们的状态。 + +show directories #显示当前源代码文件的搜索路径列表。这些搜索路径决定了GDB在查找源代码文件时的搜索范围。 +show listsize #显示打印源代码时的上下文行数。它确定了在使用list命令(或其简写形式l)时显示的源代码行数。 + +whatis variable_name #查看给定变量或表达式的类型信息。它可以帮助你了解变量的数据类型。 +ptype #显示给定类型或变量的详细类型信息。它可以帮助你了解类型的结构和成员。 + #相较于whatis命令,ptype命令更加详细。 + +set var = #设置变量值 + +return #强制使当前函数返回设定值 +``` + +--- + +## Conclusion + +  Now, you can use rust-gdb to debug the DragonOS kernel code. + +> You can refer to the GDB command documentation for more help: [GDB Cheat Sheet](https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf) diff --git a/docs/locales/en/kernel/debug/index.rst b/docs/locales/en/kernel/debug/index.rst new file mode 100644 index 00000000..92573886 --- /dev/null +++ b/docs/locales/en/kernel/debug/index.rst @@ -0,0 +1,25 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/debug/index.rst + + - Translation time: 2025-05-19 01:41:09 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Kernel Debug Module +==================================== + + This is the documentation for the kernel debug module of DragonOS. + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + traceback + debug-kernel-with-gdb + profiling-kernel-with-dadk diff --git a/docs/locales/en/kernel/debug/profiling-kernel-with-dadk.md b/docs/locales/en/kernel/debug/profiling-kernel-with-dadk.md new file mode 100644 index 00000000..8bc898a9 --- /dev/null +++ b/docs/locales/en/kernel/debug/profiling-kernel-with-dadk.md @@ -0,0 +1,109 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/debug/profiling-kernel-with-dadk.md + +- Translation time: 2025-05-19 01:41:49 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Performance Analysis of the Kernel Using DADK + +## 1. Overview + +This document will teach you how to use DADK to perform performance analysis on the DragonOS kernel, in order to identify and resolve potential performance bottlenecks. + +### 1.1 Preparation + +::: {note} +Before you start, please ensure that you have installed DADK and have set up the compilation environment for the DragonOS kernel. +::: + +### 1.2 What is a Flame Graph? + +If you haven't heard of flame graphs before, you can read this article: [How to Read Flame Graphs? - Ruanyifeng](https://www.ruanyifeng.com/blog/2017/09/flame-graph.html) + +In simple terms, a flame graph is an SVG image generated from performance sampling results, used to display the call stack of the CPU. + +![](https://web-static2.dragonos.org.cn//longjin/flame2.svg?imageSlim) + +The x-axis represents the number of samples. If a function occupies a wider width on the x-axis, it means it was sampled more frequently, indicating longer execution time. Note that the x-axis does not represent time, but rather all call stacks are merged and sorted alphabetically. + +A flame graph is used to identify which function at the top level occupies the largest width. If there is a "plateau" (flat area), it indicates that the function may have performance issues. + +Colors have no special meaning, as flame graphs represent the CPU's busy level, so warm tones are generally chosen. + +## 2. Configuring the DragonOS Kernel + +Since performance analysis requires detailed symbol table data, we need to configure the kernel compilation as follows: + +In `kernel/Cargo.toml`'s `[profile.release]` section, set the following two options: + +```toml +[profile.release] +debug = true +opt-level = 1 +``` + +This will ensure that the compiled kernel includes symbol table data, making it easier for us to perform performance analysis. + +## 3. Using DADK for Performance Analysis + +### 3.1 Booting the Kernel + +First, we need to boot the DragonOS kernel. + +```shell +# 使用你喜欢的方式启动内核,例如: +make run +# 或者 +make build && make qemu-nographic +``` + +### 3.2 Running Your Workload + +After booting the kernel, we need to run some workloads in order to perform performance analysis. + +This can be an application or something else. Even you can choose to do nothing and simply observe the call stack of the DragonOS kernel when it is idle. + +### 3.3 Starting DADK for Performance Analysis + +In the DragonOS project directory, run the following command: + +```shell +dadk profile sample --format flamegraph --output flame.svg --interval 200ms --duration 20s --cpu-mask 0x1 +``` + +The above command will perform performance analysis on the DragonOS kernel and generate a flame graph. + +Detailed explanation: + +- `--format flamegraph`: Specifies the output format as a flame graph. +- `--output flame.svg`: Specifies the output filename as `flame.svg`. +- `--interval 200ms`: Specifies the sampling interval as 200ms. +- `--duration 20s`: Specifies the sampling duration as 20 seconds. +- `--cpu-mask 0x1`: Specifies the CPU to be sampled as CPU 0. (This is a bitmask, meaning if you want to sample CPU 0 and 1, the cpu-mask would be 0x3) + +*For more parameters, please refer to `dadk profile sample --help`.* + +::: {note} +Since sampling will pause vCPU, the sampling time should not be too short, otherwise it may affect the normal operation of the system. +::: + +After waiting for a while, you will get a `flame.svg` file. + +### 3.4 Analyzing the Flame Graph + +Open the `flame.svg` file in a browser, and you will see a flame graph. + +You can click on a function in the flame graph to view its call stack. + +**You can right-click the image below and open it in a new tab to experience the interactive effects.** + +![](https://web-static2.dragonos.org.cn//longjin/flame2.svg?imageSlim) diff --git a/docs/locales/en/kernel/debug/traceback.md b/docs/locales/en/kernel/debug/traceback.md new file mode 100644 index 00000000..cc4baae9 --- /dev/null +++ b/docs/locales/en/kernel/debug/traceback.md @@ -0,0 +1,50 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/debug/traceback.md + +- Translation time: 2025-05-19 01:41:10 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Kernel Stack Traceback + +## Introduction + +  The functionality of the kernel stack traceback is located in the `kernel/debug/traceback/` folder. It provides traceback capabilities for the kernel mode, printing the call stack to the screen. + +--- + +## API + +### `void traceback(struct pt_regs * regs)` + +#### Purpose + +  This interface is defined in `kernel/debug/traceback/traceback.h`, which will perform a traceback on the given kernel stack and print the trace results to the screen. + +#### Parameters + +##### regs + +  The first stack frame of the kernel stack to start the tracing (i.e., the bottom of the stack) + +--- + +## Implementation Principle + +  After the kernel is linked for the first time, the Makefile will run the `kernel/debug/kallsyms` program to extract the symbol table of the kernel file, and then generate `kernel/debug/kallsyms.S`. The rodata segment of this file stores the symbol table of the functions in the text segment. Then, this file will be compiled into `kallsyms.o`. Finally, the Makefile will again call the `ld` command to link the kallsyms.o into the kernel file. + +  When the `traceback` function is called, it will traverse the symbol table to find the corresponding symbols and output them. + +--- + +## Future Development Directions + +- Add the capability to write to a log file diff --git a/docs/locales/en/kernel/filesystem/index.rst b/docs/locales/en/kernel/filesystem/index.rst new file mode 100644 index 00000000..aaf0ff63 --- /dev/null +++ b/docs/locales/en/kernel/filesystem/index.rst @@ -0,0 +1,29 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/filesystem/index.rst + + - Translation time: 2025-05-19 01:41:15 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +File System +==================================== + +The file system module of DragonOS consists of VFS (Virtual File System) and specific file systems. + +todo: Due to the refactoring of the file system module, the documentation is temporarily unavailable and will be completed by April 10, 2023. + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + overview + vfs/index + sysfs + kernfs + unionfs/index diff --git a/docs/locales/en/kernel/filesystem/kernfs.md b/docs/locales/en/kernel/filesystem/kernfs.md new file mode 100644 index 00000000..372c27bd --- /dev/null +++ b/docs/locales/en/kernel/filesystem/kernfs.md @@ -0,0 +1,37 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/filesystem/kernfs.md + +- Translation time: 2025-05-19 01:41:15 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# KernFS + +:::{note} + +Maintainer: +- Long Jin +::: + +## 1. Introduction +  KernFS is a pseudo file system that acts as a container for other kernel file systems, providing a file interface to users. Its core functionality is that when files in KernFS are read/written or trigger callback points, the predefined callback functions will be invoked, triggering operations on other kernel file systems. + +  This design decouples the basic operations of SysFS and file systems. KernFS serves as the carrier of SysFS, allowing SysFS to focus more on the management of KObjects, resulting in more elegant code. + +  In the future, the kernel subsystem of DragonOS or other kernel file systems can use KernFS as a carrier for file system operations, decoupling the system management logic from specific file system operations. + +## 2. Usage + +  Taking SysFS as an example, a new KernFS instance is created as the file system interface for SysFS, and then it is mounted under the directory `/sys`. Then, sysfs implements the upper-layer logic to manage KObjects. Each upper-layer KObject must include a KernFSInode. By setting the PrivateData of KernFSInode, KernFS can retrieve the corresponding KObject or sysfs attribute based on the Inode. Furthermore, when creating a KernFSInode, different callbacks are passed to the specific Inode, enabling "different Inodes to trigger different callback behaviors when read or written." + +  When a callback occurs, KernFS passes the callback information and private information to the callback function, allowing the callback function to retrieve the corresponding KObject or sysfs attribute based on the input information, thus achieving the high-level functionality provided by sysfs. + +  From the above description, we can see that KernFS achieves the purpose of "decoupling specific file operations from high-level management logic" by storing the callback functions and callback information of the upper-layer file systems. diff --git a/docs/locales/en/kernel/filesystem/overview.md b/docs/locales/en/kernel/filesystem/overview.md new file mode 100644 index 00000000..bbc86a7a --- /dev/null +++ b/docs/locales/en/kernel/filesystem/overview.md @@ -0,0 +1,107 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/filesystem/overview.md + +- Translation time: 2025-05-19 01:41:36 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +:::{note} +Author of this article: Long Jin + +Email: +::: + +# Overview + +  In this article, we will introduce the architecture design of the DragonOS file system. + +## Overview + +  As shown in the following diagram, the file system-related mechanisms of DragonOS mainly include the following parts: + +- System call interface +- Virtual File System (VFS) + - File abstraction (File) + - Mount file system (MountFS) +- Specific file systems + +```text + ┌─────────────────────────────────────────────────┐ + │ │ +Syscall: │ sys_open, sys_read, sys_write, sys_close, │ + │ │ + │ sys_lseek, etc.. │ + │ │ + └───────────────────────┬─────────────────────────┘ + │ + │ + VFS: ┌──────▼─────┐ + │ │ + │ File │ + │ │ + └──────┬─────┘ + │ + ┌────────▼────────┐ + │ │ + │ MountFS │ + │ │ + └────┬────────────┘ + │ + Filesystems: ┌─────────────┼─────────────┬────────────┐ + │ │ │ │ + ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼────┐ ┌─────▼─────┐ + │ │ │ │ │ │ │ │ + │ FAT │ │ DevFS │ │ ProcFS │ │ RamFS │ + │ │ │ │ │ │ │ │ + └───────────┘ └───────────┘ └──────────┘ └───────────┘ +``` + +## System Call Interface + +  The file system-related system call interfaces of DragonOS mainly include the following: + +- `sys_open`: Open file +- `sys_read`: Read file +- `sys_write`: Write file +- `sys_close`: Close file +- `sys_lseek`: Set file pointer position +- `sys_mkdir`: Create directory +- `sys_unlink_at`: Delete file or directory (distinguish between file and directory by parameter `flag`) +- `sys_ioctl`: Control device (not implemented) +- `sys_fstat`: Get file status (not implemented) +- `sys_fsync`: Synchronize file (not implemented) +- `sys_ftruncate`: Truncate file (not implemented) +- `sys_fchmod`: Modify file permissions (not implemented) +- Other system call interfaces (not implemented) + +  For the specific meaning of the interfaces, you can refer to the relevant documentation of Linux. + +## Virtual File System (VFS) + +  VFS is the core of the DragonOS file system, providing a unified set of file system interfaces, allowing DragonOS to support various different file systems. The main functions of VFS include: + +- Provide a unified file system interface +- Provide file system mounting and unmounting mechanism (MountFS) +- Provide file abstraction (File) +- Provide file system abstraction (FileSystem) +- Provide IndexNode abstraction +- Provide file system caching and synchronization mechanism (not implemented yet) + +  For detailed introduction of VFS, please see [DragonOS Virtual File System](vfs/index.rst). + +## Specific File Systems + +  The file systems currently supported by DragonOS include: + +- FAT file system (FAT12, FAT16, FAT32) +- DevFS +- ProcFS +- RamFS diff --git a/docs/locales/en/kernel/filesystem/sysfs.md b/docs/locales/en/kernel/filesystem/sysfs.md new file mode 100644 index 00000000..e06fdd28 --- /dev/null +++ b/docs/locales/en/kernel/filesystem/sysfs.md @@ -0,0 +1,124 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/filesystem/sysfs.md + +- Translation time: 2025-05-19 01:41:50 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# SysFS + +:::{note} +Author: Huang Ting + +Email: +::: + +## 1. SysFS and Device Driver Model + +### 1.1. The relationship between devices, drivers, buses, etc., is complex + +  If you want the kernel to run smoothly, you must code these functionalities for each module. This will make the kernel very bloated and redundant. The idea of the device model is to abstract these codes into a shared framework for all modules. This not only makes the code concise, but also allows device driver developers to avoid the headache of this essential but burdensome task, and focus their limited energy on implementing the differences of the devices. + +  The device model provides a template, an optimal approach and process that has been proven. This reduces unnecessary errors during the development process and clears the way for future maintenance. + +### 1.2. sysfs is a memory-based file system, its role is to provide kernel information in the form of files for user programs to use. + +  sysfs can be seen as a file system similar to proc, devfs, and devpty. This file system is virtual and can make it easier to manage system devices. It can generate a hierarchical view of all system hardware, similar to the proc file system that provides process and status information. sysfs organizes the devices and buses connected to the system into a hierarchical file structure, which can be accessed from user space, exporting kernel data structures and their attributes to user space. + +## 2. Device Driver Model in DragonOS + +### 2.1. The basic elements are composed of devices and drivers + +#### 2.1.1. Device + +```rust +/// @brief: 所有设备都应该实现该trait +pub trait Device: Any + Send + Sync + Debug {} +``` + +  DragonOS uses a global device manager to manage all devices in the system. + +```rust +/// @brief Device管理器 +#[derive(Debug, Clone)] +pub struct DeviceManager { + devices: BTreeMap>, // 所有设备 + sys_info: Option>, // sys information +} +``` + +#### 2.1.2. Driver + +```rust +/// @brief: 所有驱动驱动都应该实现该trait +pub trait Driver: Any + Send + Sync + Debug {} +``` + +  Similarly, drivers also use a global driver manager for management. + +```rust +/// @brief: 驱动管理器 +#[derive(Debug, Clone)] +pub struct DriverManager { + drivers: BTreeMap>, // 所有驱动 + sys_info: Option>, // sys information +} +``` + +### 2.2. Bus + +  Bus is a type of device, and it also needs a driver to initialize. Due to the special nature of buses, a global bus manager is used for management. + +```rust +/// @brief: 总线驱动trait,所有总线驱动都应实现该trait +pub trait BusDriver: Driver {} + +/// @brief: 总线设备trait,所有总线都应实现该trait +pub trait Bus: Device {} + +/// @brief: 总线管理结构体 +#[derive(Debug, Clone)] +pub struct BusManager { + buses: BTreeMap>, // 总线设备表 + bus_drvs: BTreeMap>, // 总线驱动表 + sys_info: Option>, // 总线inode +} +``` + +  As can be seen, each manager contains a sys_info. The device model establishes a connection with sysfs through this member, and sys_info points to the unique inode in sysfs. For a device, it corresponds to the devices folder under sysfs, and the same applies to other components. + +## 3. How to Develop Drivers + +  Taking the platform bus as an example, the platform bus is a virtual bus that can match devices and drivers mounted on it and drive the devices. This bus is a type of device and also a type of bus. When programming, you need to create an instance of this device and implement the Device trait and Bus trait for the device instance to indicate that this structure is a bus device. At the same time, the matching rules on the bus should be implemented. Different buses have different matching rules. This bus uses a matching table for matching, and both devices and drivers should have a matching table, indicating the devices supported by the driver and the drivers supported by the device. + +```rust +pub struct CompatibleTable(BTreeSet<&'static str>); +``` + +  For a bus device, you need to call bus_register to register the bus into the system and visualize it in sysfs. + +```rust +/// @brief: 总线注册,将总线加入全局总线管理器中,并根据id table在sys/bus和sys/devices下生成文件夹 +/// @parameter bus: Bus设备实体 +/// @return: 成功:() 失败:DeviceError +pub fn bus_register(bus: Arc) -> Result<(), DeviceError> { + BUS_MANAGER.add_bus(bus.get_id_table(), bus.clone()); + match sys_bus_register(&bus.get_id_table().to_name()) { + Ok(inode) => { + let _ = sys_bus_init(&inode); + return device_register(bus); + } + Err(_) => Err(DeviceError::RegisterError), + } +} +``` + +  From the source code of bus_register, we can see that this function not only generates a bus folder under sysfs/bus, but also internally calls device_register. This function adds the bus to the device manager and generates a device folder under sys/devices. diff --git a/docs/locales/en/kernel/filesystem/unionfs/index.rst b/docs/locales/en/kernel/filesystem/unionfs/index.rst new file mode 100644 index 00000000..ef1771c9 --- /dev/null +++ b/docs/locales/en/kernel/filesystem/unionfs/index.rst @@ -0,0 +1,23 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/filesystem/unionfs/index.rst + + - Translation time: 2025-05-19 01:41:16 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +Union Filesystem +==================================== +Union Filesystem: +OverlayFS merges multiple filesystems (referred to as "layers") into a single logical filesystem, allowing users to see a unified directory structure. + +.. toctree:: + :maxdepth: 1 + + overlayfs diff --git a/docs/locales/en/kernel/filesystem/unionfs/overlayfs.md b/docs/locales/en/kernel/filesystem/unionfs/overlayfs.md new file mode 100644 index 00000000..74267034 --- /dev/null +++ b/docs/locales/en/kernel/filesystem/unionfs/overlayfs.md @@ -0,0 +1,46 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/filesystem/unionfs/overlayfs.md + +- Translation time: 2025-05-19 01:41:18 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# overlayfs + +OverlayFS is currently the most widely used union file system, with a simple principle and convenient usage, mainly used in containers. + +In Docker, OverlayFS is one of the default storage drivers. Docker creates an independent upper directory for each container, while all containers share the same lower image file. This design makes resource sharing between containers more efficient and reduces storage requirements. + +## Architecture Design + +OverlayFS has two layers and a virtual merged layer. + +- **Lower Layer (Lower Layer)**: Usually a read-only file system. It can contain multiple layers. +- **Upper Layer (Upper Layer)**: A writable layer. All write operations are performed on this layer. +- **Merged Layer (Merged Layer)**: The logical view of the upper and lower layers is merged, and the final file system presented to the user is shown. + +## Working Principle + +- **Read Operation**: + - OverlayFS will first read the file from the Upper Layer. If the file does not exist in the upper layer, it will read the content from the Lower Layer. +- **Write Operation**: + - If a file is located in the Lower Layer and an attempt is made to write to it, the system will copy it up to the Upper Layer and then write to it in the upper layer. If the file already exists in the Upper Layer, it will be directly written to that layer. +- **Delete Operation**: + - When deleting a file, OverlayFS creates a whiteout entry in the upper layer, which hides the file in the lower layer. + +## Copy-up + +- **Copy-on-Write (Write-time Copy)** +When a file in the lower layer is modified, it is copied to the upper layer (called copy-up). All subsequent modifications will be performed on the copied file in the upper layer. + +## Implementation Logic + +The implementation is achieved by building `ovlInode` to implement the `indexnode` trait to represent the inode of the upper or lower layer. Specific operations related to files and directories are handled accordingly. diff --git a/docs/locales/en/kernel/filesystem/vfs/api.md b/docs/locales/en/kernel/filesystem/vfs/api.md new file mode 100644 index 00000000..be9450d0 --- /dev/null +++ b/docs/locales/en/kernel/filesystem/vfs/api.md @@ -0,0 +1,16 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/filesystem/vfs/api.md + +- Translation time: 2025-05-19 01:41:12 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# VFS API Documentation diff --git a/docs/locales/en/kernel/filesystem/vfs/design.md b/docs/locales/en/kernel/filesystem/vfs/design.md new file mode 100644 index 00000000..80746546 --- /dev/null +++ b/docs/locales/en/kernel/filesystem/vfs/design.md @@ -0,0 +1,72 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/filesystem/vfs/design.md + +- Translation time: 2025-05-19 01:41:33 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +:::{note} +Author of this article: Long Jin + +Email: +::: + +# Design + +  The architecture design of VFS is shown in the following diagram: + +```text + ┌─────────┐ + │ │ + │ read │ + File │ │ + │ write │ + │ │ │ + │ │ ioctl │ + │ │ │ + │ │ lseek │ + │ │ │ + │ │ etc.. │ + │ └─────────┘ + │ + ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ + MountFS │ Maintain the mount tree and handle the mounting of file systems. │ + │ │ In particular, it handles the "crossing file system boundaries" condition │ + │ │ while doing "lookup" or "find" operations. │ + │ └──────────────────────────────────────────────────────────────────────────────┘ + │ + │ + │ +Filesystems: │ + │ + ▼ ┌────────────────────────────────────────────────────────────────────┐ + xxxFSInode │ Implement corresponding operations based on different file systems │ + └────────────────────────────────────────────────────────────────────┘ +``` + +## 1. File +  The File structure is the most basic abstraction in VFS, representing an opened file. Whenever a process opens a file, a File structure is created to maintain the state information of that file. + +## 2. Traits + +  For each specific file system, the following traits must be implemented: + +- FileSystem: Indicates that a struct is a file system +- IndexNode: Indicates that a struct is an index node + +  Generally, there is a one-to-one relationship between FileSystem and IndexNode, meaning that one file system corresponds to one type of IndexNode. However, for some special file systems, such as DevFS, different IndexNodes may exist based on different device types. Therefore, there is a one-to-many relationship between FileSystem and IndexNode. + +## 3. MountFS + +  Although MountFS implements the FileSystem and IndexNode traits, it is not itself a "file system," but rather a mechanism used to mount different file systems onto the same file system tree. +All file systems that need to be mounted onto the file system tree must go through MountFS to complete the mounting process. In other words, each file system structure in the mount tree is wrapped with a MountFS structure. + +  For most operations, MountFS simply forwards the operation to the specific file system without any processing. At the same time, to support cross-file system operations, such as searching in a directory tree, each lookup or find operation will go through the corresponding method of MountFSInode to determine whether the current inode is a mount point and handle it specially. If the operation is found to cross the boundary of a specific file system, MountFS will forward the operation to the next file system and perform an inode replacement. This functionality is implemented by wrapping a regular Inode structure with a MountFSInode structure. diff --git a/docs/locales/en/kernel/filesystem/vfs/index.rst b/docs/locales/en/kernel/filesystem/vfs/index.rst new file mode 100644 index 00000000..a9e9aed4 --- /dev/null +++ b/docs/locales/en/kernel/filesystem/vfs/index.rst @@ -0,0 +1,33 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/filesystem/vfs/index.rst + + - Translation time: 2025-05-19 01:41:14 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +VFS Virtual File System +==================================== + +In DragonOS, VFS acts as an adapter, hiding the differences between specific file systems and providing a unified file operation interface abstraction to the outside. + +VFS is the core of the file system in DragonOS. It provides a set of unified file system interfaces, enabling DragonOS to support various different file systems. The main functions of VFS include: + +- Providing a unified file system interface +- Providing mount and unmount mechanisms for file systems (MountFS) +- Providing file abstraction (File) +- Providing file system abstraction (FileSystem) +- Providing IndexNode abstraction +- Providing caching and synchronization mechanisms for file systems (not yet implemented) + +.. toctree:: + :maxdepth: 1 + :caption: Directory + + design + api diff --git a/docs/locales/en/kernel/ipc/index.rst b/docs/locales/en/kernel/ipc/index.rst new file mode 100644 index 00000000..31a0a93e --- /dev/null +++ b/docs/locales/en/kernel/ipc/index.rst @@ -0,0 +1,23 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/ipc/index.rst + + - Translation time: 2025-05-19 01:41:19 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +Inter-Process Communication +==================================== + + This is the documentation for DragonOS Inter-Process Communication (IPC). + +.. toctree:: + :maxdepth: 1 + + signal diff --git a/docs/locales/en/kernel/ipc/signal.md b/docs/locales/en/kernel/ipc/signal.md new file mode 100644 index 00000000..1930933a --- /dev/null +++ b/docs/locales/en/kernel/ipc/signal.md @@ -0,0 +1,97 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/ipc/signal.md + +- Translation time: 2025-05-19 01:41:43 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Signal Signal + +:::{note} +This document Maintainer: Longjin + +Email: +::: + +  Signals are a mechanism for inter-process communication. When a signal is sent to a specific process, it can trigger a specific behavior (such as exiting the program or running a signal handler). Signals are asynchronous notifications sent to a process or a specific thread within the same process, used to notify it that an event has occurred. Common uses of signals include interrupting, suspending, terminating, or ending a process. When sending a signal, the operating system interrupts the normal execution flow of the target process to deliver the signal. Execution can be interrupted at any non-atomic instruction. If the process has previously registered a signal handler, the handler routine is executed. Otherwise, the default signal handler is executed. + +  Signals are similar to interrupts, with the difference being that interrupts are mediated by the CPU and handled by the kernel, while signals are generated within the kernel (and can also be generated through system calls) and are handled by the default handlers of individual processes or the kernel. + +## 1. Overview of Signal Handling + +### 1.1 Signal Sending + +  When process A wants to send a signal to process B, it uses the `kill(pid, signal)` interface to send the signal. Then, it enters the `sys_kill()` function in the kernel for processing. The kernel will then add the signal to the `sigpending` in the target process's PCB. + +Illustration: + +```text + ┌────────────┐ + │ Process A: │ + │ │ + │ sys_kill │ + └──────┬─────┘ + │ + │ + ┌──────▼──────┐ ┌────────────────────┐ + │ Send Signal ├────►Add to sigpending of│ + └─────────────┘ │ process B. │ + └────────────────────┘ + +``` + +### 1.2 Signal Handling + +  When a process exits the kernel mode, it jumps into the `do_signal()` function to check if there are any signals that need to be handled. If there are, the signal handling process is initiated. + +Signal handling process illustration: + +```text + + ┌───────────────────────┐ + │ Process B: │ + │ ◄─────────────────────────────────┐ + │ Return from syscall...│ │ + └─────────┬─────────────┘ │ + │ │ + │ │ + │ ┌────────────────┐ │ + ┌─────▼─────┐ default │ │ │ + │ do_signal ├────────► │ stop process B.│ │ + └─────┬─────┘ action │ │ │ + │ └────────────────┘ │ + │ custom action │ + ┌──────▼───────┐ │ + │ setup signal │ │ + │ frame │ │ + └──────┬───────┘ │ + │jump to │ + ┌──────▼───────┐ ┌────────────┐ sys_sigreturn ┌────────┴────────┐ + │ userland ├─►sa_restorer ├──────────────►│Restore the stack│ + │ sig handler │ └────────────┘ │ frame. │ + └──────────────┘ └─────────────────┘ + +``` + +- If the kernel checks and finds that the process has not specified a signal handler and the signal handling action is not "ignore", the process will be terminated. +- If the kernel finds that the signal is not ignored, it will: + - Save the current kernel stack + - Set up the user-mode stack frame for signal handling + - Return to user mode and execute the signal handler + - After the signal handler finishes, it will enter the __sa_restorer__ provided by libc, initiating the `sys_sigreturn()` system call to return to kernel mode + - The kernel restores the kernel stack before handling the signal. + - The signal handling process ends, and the kernel continues with the process of returning to user mode. +- If the kernel finds that the current signal is being ignored, it checks the next signal. +- If no signals need to be handled, it returns to user mode. + +## 2. Other Issues + +  None at present. diff --git a/docs/locales/en/kernel/ktest/index.rst b/docs/locales/en/kernel/ktest/index.rst new file mode 100644 index 00000000..f008c2ab --- /dev/null +++ b/docs/locales/en/kernel/ktest/index.rst @@ -0,0 +1,26 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/ktest/index.rst + + - Translation time: 2025-05-19 01:41:16 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +Kernel Testing +==================================== + + This chapter will introduce how to test the kernel, including manual testing and automated testing. + + We need to perform thorough testing on the kernel as much as possible, so that we can better ensure the stability of the kernel and reduce the difficulty of debugging other modules. + + Setting up comprehensive test cases can help us detect problems as much as possible, preventing us from being "stabbed" by hidden bugs in existing modules when writing new modules. + + Since it is difficult to debug using tools like GDB, manual testing in the kernel is more challenging compared to testing applications. + + For some modules, we can write code for unit testing and output error messages. Unfortunately, not all modules can be unit tested. For example, common modules such as memory management and process management cannot be unit tested. diff --git a/docs/locales/en/kernel/libs/id-allocation.md b/docs/locales/en/kernel/libs/id-allocation.md new file mode 100644 index 00000000..bc0e8a22 --- /dev/null +++ b/docs/locales/en/kernel/libs/id-allocation.md @@ -0,0 +1,26 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/libs/id-allocation.md + +- Translation time: 2025-05-19 01:41:12 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# ID Allocation + +:::{note} +Author: Longjin + +September 25, 2024 +::: + +The kernel provides an ID allocator named `IdAllocator`, located in `kernel/crates/ida`. + +It is capable of allocating and releasing IDs. By default, it increments to allocate IDs. If the ID exceeds the set maximum value, it will search for an available ID starting from the minimum value. If there are no available IDs, the allocation will fail. diff --git a/docs/locales/en/kernel/libs/index.rst b/docs/locales/en/kernel/libs/index.rst new file mode 100644 index 00000000..d30acb99 --- /dev/null +++ b/docs/locales/en/kernel/libs/index.rst @@ -0,0 +1,26 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/libs/index.rst + + - Translation time: 2025-05-19 01:41:11 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +Other Kernel Libraries +==================================== + + This section contains documentation for some libraries in the kernel that do not belong to any subsystem. + +.. toctree:: + :maxdepth: 1 + + lib_ui/scm + lib_ui/textui + unified-init + id-allocation diff --git a/docs/locales/en/kernel/libs/lib_ui/scm.md b/docs/locales/en/kernel/libs/lib_ui/scm.md new file mode 100644 index 00000000..f5e4a1e7 --- /dev/null +++ b/docs/locales/en/kernel/libs/lib_ui/scm.md @@ -0,0 +1,97 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/libs/lib_ui/scm.md + +- Translation time: 2025-05-19 01:41:31 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Screen Manager (SCM) + +:::{note} +Author: Zhou Hanjie <2625553453@qq.com> +::: +  The Screen Manager is used to control all UI frameworks. All frameworks must be registered with the Screen Manager before they can be used. Then, SCM controls which UI framework is currently in use. + +## traits + +### ScmUiFramework +  Each UI framework that is to be registered with SCM must implement the methods defined in this trait, as follows: +```rust +pub trait ScmUiFramework: Sync + Send + Debug { + // 安装ui框架的回调函数 + fn install(&self) -> Result { + return Err(SystemError::ENOSYS); + } + // 卸载ui框架的回调函数 + fn uninstall(&self) -> Result { + return Err(SystemError::ENOSYS); + } + // 启用ui框架的回调函数 + fn enable(&self) -> Result { + return Err(SystemError::ENOSYS); + } + // 禁用ui框架的回调函数 + fn disable(&self) -> Result { + return Err(SystemError::ENOSYS); + } + // 改变ui框架的帧缓冲区的回调函数 + fn change(&self, _buf: ScmBufferInfo) -> Result { + return Err(SystemError::ENOSYS); + } + /// @brief 获取ScmUiFramework的元数据 + /// @return 成功:Ok(ScmUiFramework的元数据) + /// 失败:Err(错误码) + fn metadata(&self) -> Result { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(SystemError::ENOSYS); + } +} +``` +## Main APIs +### scm_init() - Initialize the screen management module +#### Prototype +```rust +pub extern "C" fn scm_init() +``` +#### Description +  scm_init() is mainly used to initialize some global variables used by SCM, such as the flag indicating whether double buffering is used, and some global variables used by textui when it is not initialized. + +### scm_reinit() - Reinitialize the screen management module after the memory management unit is initialized +#### Prototype +```rust +pub extern "C" fn scm_reinit() -> i32 +``` +#### Description +  scm_reinit() is used to reprocess the frame buffer issues after the memory management unit has been initialized. + +### scm_enable_double_buffer() - Enable double buffering +#### Prototype +```rust +pub extern "C" fn scm_enable_double_buffer() -> i32 +``` +#### Description +  scm_enable_double_buffer() is used to enable double buffering for outputting information to the window. After enabling, the information output to the window is temporarily stored in a buffer, and then this buffer's content is output to the window's frame buffer at regular intervals, rendering it to the window. + +### scm_framework_enable() - Enable a specific UI framework and render its frame buffer to the screen +#### Prototype +```rust +pub fn scm_framework_enable(framework: Arc) -> Result +``` +#### Description +  scm_framework_enable is used to enable a specific UI framework and render its frame buffer to the screen. + +### scm_register() - Register a UI framework with the screen manager +#### Prototype +```rust +pub fn scm_register(framework: Arc) -> Result +``` +#### Description +  scm_register is used to register a UI framework with SCM. It mainly calls the callback functions of the UI framework to install and activate it. diff --git a/docs/locales/en/kernel/libs/lib_ui/textui.md b/docs/locales/en/kernel/libs/lib_ui/textui.md new file mode 100644 index 00000000..15aa0dd5 --- /dev/null +++ b/docs/locales/en/kernel/libs/lib_ui/textui.md @@ -0,0 +1,44 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/libs/lib_ui/textui.md + +- Translation time: 2025-05-19 01:41:14 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Text UI Framework (textui) + +:::{note} +Author: Zhou Hanjie <2625553453@qq.com> +::: +  The text framework is primarily used for rendering and displaying text windows in DragonOS. It outputs printed text information to the screen window. Displaying text in the window is divided into two scenarios: one is when the Memory Management Unit (MM) has not been initialized, which prevents dynamic memory allocation, imposing many restrictions (for example, not being able to use vec, mpsc, etc.), so it directly outputs the printed information to the window's frame buffer without using complex structures like virtual lines; the other is when the Memory Management Unit (MM) has been initialized, allowing dynamic memory allocation, which enables the use of more complex structures to handle the text information to be printed. + +## Main APIs +### rs_textui_init() - Text UI framework initialization +#### Prototype +```rust +pub extern "C" fn rs_textui_init() -> i32 +``` +#### Description +  rs_textui_init() is mainly used to initialize some global variable information that the textui framework needs (such as TEXTUIFRAMEWORK, TEXTUI_PRIVATE_INFO, etc.), and to register the textui framework with scm. + +### textui_putchar() - Print text information to the currently used window in the textui framework +#### Prototype +```rust +pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 + +pub fn textui_putchar( + character: char, + fr_color: FontColor, + bk_color: FontColor, +) -> Result<(), SystemError> +``` +#### Description +  textui_putchar() needs to handle two scenarios: one is when the Memory Management Unit (MM) has not been initialized, which prevents dynamic memory allocation, imposing many restrictions (for example, not being able to use vec, mpsc, etc.), so it directly outputs the printed information to the window's frame buffer without using complex structures like virtual lines; the other is when the Memory Management Unit (MM) has been initialized, allowing dynamic memory allocation, which enables the use of more complex structures to handle the text information to be printed. diff --git a/docs/locales/en/kernel/libs/unified-init.md b/docs/locales/en/kernel/libs/unified-init.md new file mode 100644 index 00000000..2693cf5c --- /dev/null +++ b/docs/locales/en/kernel/libs/unified-init.md @@ -0,0 +1,64 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/libs/unified-init.md + +- Translation time: 2025-05-19 01:41:09 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# unified-init Unified Initialization Library + +:::{note} +Author: Longjin + +December 25, 2023 +::: + +## 1. Introduction + +This library is located in `kernel/crates/unified-init`. +It provides unified initialization macros to register functions into a unified initialization list. It facilitates unified initialization. + +It is important to note that the array of initializers is no_mangle, so its naming should follow the rules of `模块_初始化器` to prevent naming conflicts that could lead to unexpected errors. + +## 2. Usage + +```rust +use system_error::SystemError; +use unified_init::define_unified_initializer_slice; +use unified_init_macros::unified_init; + +/// 初始化函数都将会被放到这个列表中 +define_unified_initializer_slice!(INITIALIZER_LIST); + +#[unified_init(INITIALIZER_LIST)] +fn init1() -> Result<(), SystemError> { + Ok(()) +} + +#[unified_init(INITIALIZER_LIST)] +fn init2() -> Result<(), SystemError> { + Ok(()) +} + +fn main() { + assert_eq!(INITIALIZER_LIST.len(), 2); +} + +``` + +## 3. Development + +When testing, you can write test code in `main.rs`, +and then run `cargo expand --bin unified-init-expand` in the current directory to see the code after the proc macro has been expanded. + +## 4. Maintainer + +Longjin diff --git a/docs/locales/en/kernel/locking/index.rst b/docs/locales/en/kernel/locking/index.rst new file mode 100644 index 00000000..a0606231 --- /dev/null +++ b/docs/locales/en/kernel/locking/index.rst @@ -0,0 +1,26 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/locking/index.rst + + - Translation time: 2025-05-19 01:41:08 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +Locks +==================================== + + This is the documentation explaining the lock variables in DragonOS. + +.. toctree:: + :maxdepth: 1 + + locks + spinlock + mutex + rwlock diff --git a/docs/locales/en/kernel/locking/locks.md b/docs/locales/en/kernel/locking/locks.md new file mode 100644 index 00000000..4af743ac --- /dev/null +++ b/docs/locales/en/kernel/locking/locks.md @@ -0,0 +1,63 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/locking/locks.md + +- Translation time: 2025-05-19 01:41:26 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Types of Locks and Their Rules + +## Introduction + +  The DragonOS kernel implements several types of locks, which can be broadly categorized into two types: + +- Sleepable locks +- Spin locks + +## Types of Locks + +### Sleepable Locks + +  Sleepable locks can only be acquired in a context that is preemptible. + +  In DragonOS, the following sleepable locks are implemented: + +- semaphore +- mutex_t + +### Spin Locks + +- spinlock_t +- {ref}`RawSpinLock <_spinlock_doc_rawspinlock>` (Rust version of spinlock_t, but incompatible with spinlock_t) +- {ref}`SpinLock <_spinlock_doc_spinlock>` —— Built on top of RawSpinLock, it wraps a guard, binding the lock and the data it protects into a single structure. This allows for compile-time checks to prevent accessing data without holding the lock. + +  When a process acquires a spin lock, it changes the lock count in the PCB, thereby implicitly disabling preemption. To provide more flexible operations, spinlock also provides the following methods: + +| Suffix | Description | +|----------------------|--------------------------------------------------------| +| _irq() | Disable interrupts when acquiring the lock, enable them when releasing | +| _irqsave()/_irqrestore() | Save the interrupt state when acquiring the lock, and restore it when releasing | + +## Detailed Introduction + +### Detailed Introduction to Spin Locks + +  For a detailed introduction to spin locks, please refer to the document: {ref}`自旋锁 <_spinlock_doc>` + +### Semaphore + +  A semaphore is implemented based on a counter. + +  When the available resources are insufficient, a process attempting to perform a down operation on the semaphore will be put to sleep until the resources become available. + +### Mutex + +  Please refer to {ref}`Mutex文档 <_mutex_doc>` diff --git a/docs/locales/en/kernel/locking/mutex.md b/docs/locales/en/kernel/locking/mutex.md new file mode 100644 index 00000000..ee224eaa --- /dev/null +++ b/docs/locales/en/kernel/locking/mutex.md @@ -0,0 +1,185 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/locking/mutex.md + +- Translation time: 2025-05-19 01:41:16 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +(_translated_label___mutex_doc_en)= + +:::{note} +Author: Longjin +::: + +# Mutex (Mutual Exclusion) + +  A mutex is a lightweight synchronization primitive, with only two states: locked and idle. + +  When a mutex is occupied, any process attempting to lock it will be put to sleep until the resource becomes available. + +## 1. Features + +- Only one task can hold the mutex at a time. +- Recursive locking and unlocking are not allowed. +- Mutex can only be operated through its API. +- Mutex cannot be used in hard interrupts or soft interrupts. + +## 2. Definition + +  The mutex is defined in `lib/mutex.rs`, as shown below: + +```rust +/// @brief Mutex互斥量结构体 +/// 请注意!由于Mutex属于休眠锁,因此,如果您的代码可能在中断上下文内执行,请勿采用Mutex! +#[derive(Debug)] +pub struct Mutex { + /// 该Mutex保护的数据 + data: UnsafeCell, + /// Mutex内部的信息 + inner: SpinLock, +} + +#[derive(Debug)] +struct MutexInner { + /// 当前Mutex是否已经被上锁(上锁时,为true) + is_locked: bool, + /// 等待获得这个锁的进程的链表 + wait_list: LinkedList<&'static mut process_control_block>, +} + +``` + +## 3. Usage + +  Similar to SpinLock, the Rust version of Mutex has a guard. When using it, you need to transfer the ownership of the data to be protected to the Mutex. Moreover, the guard can only be generated after a successful lock, so at any moment, each Mutex can have at most one guard. + +  When you need to read or modify the data protected by the Mutex, you should first use the `lock()` method of the Mutex. This method returns a `MutexGuard`. You can use the member functions of the protected data to perform some operations, or directly read or write the protected data. (This is equivalent to obtaining a mutable reference to the protected data.) + +  A complete example is shown in the code below: + +```rust +let x :Mutex>= Mutex::new(Vec::new()); + { + let mut g :MutexGuard>= x.lock(); + g.push(1); + g.push(2); + g.push(2); + assert!(g.as_slice() == [1, 2, 2] || g.as_slice() == [2, 2, 1]); + // 在此处,Mutex是加锁的状态 + debug!("x={:?}", x); + } + // 由于上方的变量`g`,也就是Mutex守卫的生命周期结束,自动释放了Mutex。因此,在此处,Mutex是放锁的状态 + debug!("x={:?}", x); +``` + +  For variables inside a structure, we can use Mutex to perform fine-grained locking, that is, wrap the member variables that need to be locked in detail with Mutex, for example: + +```rust +pub struct a { + pub data: Mutex, +} +``` + +  Of course, we can also lock the entire structure: + +```rust +struct MyStruct { + pub data: data_struct, +} +/// 被全局加锁的结构体 +pub struct LockedMyStruct(Mutex); +``` + +## 4. API + +### 4.1. new - Initialize Mutex + +#### Prototype + +```rust +pub const fn new(value: T) -> Self +``` + +#### Description + +  The `new()` method is used to initialize a Mutex. This method requires a protected data as a parameter. It returns a Mutex. + +### 4.2. lock - Lock + +#### Prototype + +```rust +pub fn lock(&self) -> MutexGuard +``` + +#### Description + +  Lock the Mutex, returns the guard of the Mutex. You can use this guard to operate the protected data. + +  If the Mutex is already locked, this method will block the current process until the Mutex is released. + +### 4.3. try_lock - Try to Lock + +#### Prototype + +```rust +pub fn try_lock(&self) -> Result, i32> +``` + +#### Description + +  Try to lock the Mutex. If the lock fails, the current process will not be added to the waiting queue. If the lock is successful, it returns the guard of the Mutex; if the Mutex is already locked, it returns `Err(错误码)`. + +## 5. C Version of Mutex (Will be deprecated in the future) + +  The mutex is defined in `common/mutex.h`. Its data type is as follows: + +```c +typedef struct +{ + + atomic_t count; // 锁计数。1->已解锁。 0->已上锁,且有可能存在等待者 + spinlock_t wait_lock; // mutex操作锁,用于对mutex的list的操作进行加锁 + struct List wait_list; // Mutex的等待队列 +} mutex_t; +``` + +### 5.1. API + +#### mutex_init + +**`void mutex_init(mutex_t *lock)`** + +  Initialize a mutex object. + +#### mutex_lock + +**`void mutex_lock(mutex_t *lock)`** + +  Lock a mutex object. If the mutex is currently held by another process, the current process will enter a sleep state. + +#### mutex_unlock + +**`void mutex_unlock(mutex_t *lock)`** + +  Unlock a mutex object. If there are other processes in the mutex's waiting queue, the next process will be awakened. + +#### mutex_trylock + +**`void mutex_trylock(mutex_t *lock)`** + +  Try to lock a mutex object. If the mutex is currently held by another process, it returns 0. Otherwise, the lock is successful and returns 1. + +#### mutex_is_locked + +**`void mutex_is_locked(mutex_t *lock)`** + +  Determine if the mutex is already locked. If the given mutex is in a locked state, it returns 1; otherwise, it returns 0. diff --git a/docs/locales/en/kernel/locking/rwlock.md b/docs/locales/en/kernel/locking/rwlock.md new file mode 100644 index 00000000..365f9280 --- /dev/null +++ b/docs/locales/en/kernel/locking/rwlock.md @@ -0,0 +1,216 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/locking/rwlock.md + +- Translation time: 2025-05-19 01:41:57 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# RwLock Read-Write Lock +:::{note} +Author: sujintao + +Email: +::: + +## 1. Introduction +  A read-write lock is a mechanism used in a concurrent environment to protect shared data among multiple processes. Compared to a regular spinlock, a read-write lock divides access to shared data into two types: read access and write access. Read access to shared data is controlled by a read lock, while write access to shared data is controlled by a write lock. The design of a read-write lock allows for multiple "readers" (read-only access) and a single "writer" (write access) to coexist simultaneously. For shared data that is mostly read-only, using a read-write lock to control access can improve performance to some extent. + +## 2. Implementation of Read-Write Lock in DragonOS +### 2.1 Mechanism of Read-Write Lock +  The purpose of a read-write lock is to maintain the consistency of shared variables in a multi-threaded system. Data is wrapped in an RwLock data structure, and all access and modification must be done through this structure. Each process that accesses shared data will obtain a guard. A read-only process obtains a READER (reader guard), while a process that needs to modify a shared variable obtains a WRITER (writer guard). As a "shadow" of the RwLock, threads perform access and modification operations based on the guard. + +  In practice, in addition to READER and WRITER, a read-write lock also introduces an UPGRADER. This is a guard that lies between READER and WRITER. The role of the UPGRADER is to prevent WRITER starvation. When a process obtains an UPGRADER, it treats it as a READER. However, the UPGRADER can be upgraded, and after upgrading, it becomes a WRITER guard, allowing write operations on shared data. + +  All guards satisfy the RAII mechanism native to Rust. When the scope of a guard ends, the guard will automatically release. + +### 2.2 Relationship Between Read-Write Lock Guards +  At any given time, multiple READERS can exist, meaning that multiple processes can access shared data simultaneously. However, only one WRITER can exist at a time, and when a process obtains a WRITER, no READERS or UPGRADERS can exist. A process can obtain an UPGRADER only if there are no existing UPGRADERS or WRITERS. However, once a process obtains an UPGRADER, it cannot successfully apply for a READER. + +### 2.3 Design Details + +#### 2.3.1 RwLock Data Structure +```rust +pub struct RwLock { + lock: AtomicU32,//原子变量 + data: UnsafeCell, +} +``` + +#### 2.3.2 READER Guard Data Structure +```rust +pub struct RwLockReadGuard<'a, T: 'a> { + data: *const T, + lock: &'a AtomicU32, +} +``` + +#### 2.3.3 UPGRADER Guard Data Structure +```rust +pub struct RwLockUpgradableGuard<'a, T: 'a> { + data: *const T, + inner: &'a RwLock, +} +``` + +#### 2.3.4 WRITER Guard Data Structure +```rust +pub struct RwLockWriteGuard<'a, T: 'a> { + data: *mut T, + inner: &'a RwLock, +} +``` + +#### 2.3.5 Introduction to the lock Structure in RwLock +The lock is a 32-bit atomic variable AtomicU32, and its bit allocation is as follows: +``` + UPGRADER_BIT WRITER_BIT + ^ ^ +OVERFLOW_BIT +------+ +-------+ + ^ | | + | | | ++-+--+--------------------------------------------------------+-+--+-+--+ +| | | | | +| | | | | +| | The number of the readers | | | +| | | | | ++----+--------------------------------------------------------+----+----+ + 31 30 2 1 0 +``` + +  (From right to left) The 0th bit represents whether WRITER is valid. If WRITER_BIT = 1, it indicates that a process has obtained a WRITER guard. If UPGRADER_BIT = 1, it indicates that a process has obtained an UPGRADER guard. Bits 2 to 30 are used to represent the number of processes that have obtained READER guards in binary form. The 31st bit is an overflow detection bit. If OVERFLOW_BIT = 1, new requests for obtaining READER guards will be rejected. + +## 3. Main APIs of Read-Write Lock +### 3.1 Main APIs of RwLock +```rust +///功能: 输入需要保护的数据类型data,返回一个新的RwLock类型. +pub const fn new(data: T) -> Self +``` +```rust +///功能: 获得READER守卫 +pub fn read(&self) -> RwLockReadGuard +``` +```rust +///功能: 尝试获得READER守卫 +pub fn try_read(&self) -> Option> +``` +```rust +///功能: 获得WRITER守卫 +pub fn write(&self) -> RwLockWriteGuard +``` +```rust +///功能: 尝试获得WRITER守卫 +pub fn try_write(&self) -> Option> +``` +```rust +///功能: 获得UPGRADER守卫 +pub fn upgradeable_read(&self) -> RwLockUpgradableGuard +``` +```rust +///功能: 尝试获得UPGRADER守卫 +pub fn try_upgradeable_read(&self) -> Option> +``` +### 3.2 Main APIs of the WRITER Guard RwLockWriteGuard +```rust +///功能: 将WRITER降级为READER +pub fn downgrade(self) -> RwLockReadGuard<'rwlock, T> +``` +```rust +///功能: 将WRITER降级为UPGRADER +pub fn downgrade_to_upgradeable(self) -> RwLockUpgradableGuard<'rwlock, T> +``` +### 3.3 Main APIs of the UPGRADER Guard RwLockUpgradableGuard +```rust +///功能: 将UPGRADER升级为WRITER +pub fn upgrade(mut self) -> RwLockWriteGuard<'rwlock, T> +``` +```rust +///功能: 将UPGRADER降级为READER +pub fn downgrade(self) -> RwLockReadGuard<'rwlock, T> +``` + +## 4. Usage Examples +```rust +static LOCK: RwLock = RwLock::new(100 as u32); + +fn t_read1() { + let guard = LOCK.read(); + let value = *guard; + let readers_current = LOCK.reader_count(); + let writers_current = LOCK.writer_count(); + println!( + "Reader1: the value is {value} + There are totally {writers_current} writers, {readers_current} readers" + ); +} + +fn t_read2() { + let guard = LOCK.read(); + let value = *guard; + let readers_current = LOCK.reader_count(); + let writers_current = LOCK.writer_count(); + println!( + "Reader2: the value is {value} + There are totally {writers_current} writers, {readers_current} readers" + ); +} + +fn t_write() { + let mut guard = LOCK.write(); + *guard += 100; + let writers_current = LOCK.writer_count(); + let readers_current = LOCK.reader_count(); + println!( + "Writers: the value is {guard} + There are totally {writers_current} writers, {readers_current} readers", + guard = *guard + ); + let read_guard=guard.downgrade(); + let value=*read_guard; + println!("After downgraded to read_guard: {value}"); +} + +fn t_upgrade() { + let guard = LOCK.upgradeable_read(); + let value = *guard; + let readers_current = LOCK.reader_count(); + let writers_current = LOCK.writer_count(); + println!( + "Upgrader1 before upgrade: the value is {value} + There are totally {writers_current} writers, {readers_current} readers" + ); + let mut upgraded_guard = guard.upgrade(); + *upgraded_guard += 100; + let writers_current = LOCK.writer_count(); + let readers_current = LOCK.reader_count(); + println!( + "Upgrader1 after upgrade: the value is {temp} + There are totally {writers_current} writers, {readers_current} readers", + temp = *upgraded_guard + ); + let downgraded_guard=upgraded_guard.downgrade_to_upgradeable(); + let value=*downgraded_guard; + println!("value after downgraded: {value}"); + let read_guard=downgraded_guard.downgrade(); + let value_=*read_guard; + println!("value after downgraded to read_guard: {value_}"); +} + +fn main() { + let r2=thread::spawn(t_read2); + let r1 = thread::spawn(t_read1); + let t1 = thread::spawn(t_write); + let g1 = thread::spawn(t_upgrade); + r1.join().expect("r1"); + t1.join().expect("t1"); + g1.join().expect("g1"); + r2.join().expect("r2"); +} +``` diff --git a/docs/locales/en/kernel/locking/spinlock.md b/docs/locales/en/kernel/locking/spinlock.md new file mode 100644 index 00000000..91ac1c5e --- /dev/null +++ b/docs/locales/en/kernel/locking/spinlock.md @@ -0,0 +1,118 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/locking/spinlock.md + +- Translation time: 2025-05-19 01:43:03 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +(_translated_label___spinlock_doc_en)= + +:::{note} +Author: Longjin +::: + +# Spinlock + +## 1. Introduction + +  A spinlock is a type of lock used for synchronization in multi-threaded environments. Threads repeatedly check if the lock variable is available. Since the thread remains in a running state during this process, it is a form of busy waiting. Once a spinlock is acquired, the thread will hold onto it until it is explicitly released. + +  DragonOS implements spinlocks in the `kernel/src/lib/spinlock.rs` file. Based on slight differences in functional characteristics, two types of spinlocks, `RawSpinLock` and `SpinLock`, are provided. + +(_translated_label___spinlock_doc_rawspinlock_en)= +## 2. RawSpinLock - Raw Spinlock + +  `RawSpinLock` is a raw spinlock, whose data part contains an AtomicBool, implementing the basic functionality of a spinlock. Its locking and unlocking require manual determination of the corresponding timing, meaning that, like spinlocks used in other languages, you need to first call the `lock()` method, and then manually call the `unlock()` method when leaving the critical section. We do not explicitly inform the compiler of which data the spinlock is protecting. + +  RawSpinLock provides programmers with very flexible control over locking and unlocking. However, due to its excessive flexibility, it is easy to make mistakes when using it. Common issues include "accessing critical section data without locking", "forgetting to unlock", and "double unlocking". The compiler cannot check for these issues, and they can only be discovered at runtime. + +:::{warning} +`RawSpinLock` is not binary compatible with the C version of `spinlock_t`. If you need to operate on the C version of `spinlock_t` for temporary compatibility reasons, please use the operation functions for the C version of spinlock_t provided in `spinlock.rs`. + +However, for newly developed features, please do not use the C version of `spinlock_t`, as it will be removed as code refactoring progresses. +::: + +(_translated_label___spinlock_doc_spinlock_en)= +## 3. SpinLock - Spinlock with Guard + +  `SpinLock` is an encapsulation of `RawSpinLock`, enabling compile-time checks for issues such as "accessing critical section data without locking", "forgetting to unlock", and "double unlocking"; it also supports internal mutability of data. + +  Its struct prototype is as follows: + +```rust +#[derive(Debug)] +pub struct SpinLock { + lock: RawSpinlock, + /// 自旋锁保护的数据 + data: UnsafeCell, +} +``` + +### 3.1. Usage + +  You can initialize a SpinLock like this: + +```rust +let x = SpinLock::new(Vec::new()); +``` + +  When initializing this SpinLock, you must pass the data you want to protect into the SpinLock, which will then manage it. + +  When you need to read or modify data protected by SpinLock, please first use the `lock()` method of SpinLock. This method will return a `SpinLockGuard`. You can use the member functions of the protected data to perform some operations, or directly read and write the protected data. (This is equivalent to obtaining a mutable reference to the protected data.) + +  The complete example is shown in the code below: + +```rust +let x :SpinLock>= SpinLock::new(Vec::new()); + { + let mut g :SpinLockGuard>= x.lock(); + g.push(1); + g.push(2); + g.push(2); + assert!(g.as_slice() == [1, 2, 2] || g.as_slice() == [2, 2, 1]); + // 在此处,SpinLock是加锁的状态 + debug!("x={:?}", x); + } + // 由于上方的变量`g`,也就是SpinLock守卫的生命周期结束,自动释放了SpinLock。因此,在此处,SpinLock是放锁的状态 + debug!("x={:?}", x); +``` + +  For variables inside a struct, we can use SpinLock to perform fine-grained locking, that is, wrap the member variables that need to be locked in SpinLock, for example: + +```rust +pub struct a { + pub data: SpinLock, +} +``` + +  Of course, we can also lock the entire struct: + +```rust +struct MyStruct { + pub data: data_struct, +} +/// 被全局加锁的结构体 +pub struct LockedMyStruct(SpinLock); +``` + +### 3.2. Principle + +  `SpinLock` can achieve compile-time checking because it introduces a `SpinLockGuard` as a guard. When writing code, we ensure that only after calling the `lock()` method of `SpinLock` to acquire the lock can a `SpinLockGuard` be generated. Moreover, whenever we want to access protected data, we must obtain a guard. We also implement the `Drop` trait for `SpinLockGuard`; when the guard's lifetime ends, the lock will be automatically released. There is no other way to release the lock. Therefore, we can know that, in a context, as long as the `SpinLockGuard`'s lifetime has not ended, it has the right to access the critical section data, and the data access is safe. + +### 3.3. Existing Issues + +#### 3.3.1. Double Locking + +  Please note that the compile-time checks supported by `SpinLock` are not omnipotent. It currently cannot detect the issue of "double locking" at compile time. Consider this scenario: function A acquires the lock, and then function B attempts to lock again, which results in a "double locking" issue. This kind of problem cannot be detected at compile time. + +  To address this issue, we recommend the following programming approach: + +- If function B needs to access data within the critical section, function B should receive a parameter of type `&SpinLockGuard`, which is obtained by function A. In this way, function B can access the data within the critical section. diff --git a/docs/locales/en/kernel/memory_management/allocate-memory.md b/docs/locales/en/kernel/memory_management/allocate-memory.md new file mode 100644 index 00000000..a999b324 --- /dev/null +++ b/docs/locales/en/kernel/memory_management/allocate-memory.md @@ -0,0 +1,42 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/memory_management/allocate-memory.md + +- Translation time: 2025-05-19 01:41:13 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Memory Allocation Guide + +  This document will explain how to perform memory allocation within the kernel. Before starting, please understand a basic point: DragonOS's kernel manages memory using 4KB pages and has a buddy allocator and a slab allocator. It also has specific management mechanisms for both user space and kernel space. + +## 1. Safe Memory Allocation + +  By default, KernelAllocator is bound as the global memory allocator. It automatically selects between using the slab allocator or the buddy allocator based on the size of the memory requested. Therefore, in the kernel, using Rust's native memory allocation functions or creating an `Box` object, etc., is safe. + +## 2. Manual Management of Page Frames + +:::{warning} +**Please be extremely cautious!** Manually managing page frames bypasses Rust's memory safety mechanisms, which may lead to memory leaks or memory errors. +::: + +  In some cases, we need to manually allocate page frames. For example, when we need to create a new page table or a new address space within the kernel. In such situations, we need to manually allocate page frames. Using the `LockedFrameAllocator`'s `allocate()` function can allocate contiguous page frames in physical address space. Please note that since the underlying implementation uses the buddy allocator, the number of page frames must be a power of two, and the maximum size should not exceed 1GB. + +  When you need to release page frames, you can use the `LockedFrameAllocator`'s `deallocate()` function or the `deallocate_page_frames()` function to release contiguous page frames in physical address space. + +  When you need to map page frames, you can use the `KernelMapper::lock()` function to obtain a kernel mapper object and then perform the mapping. Since KernelMapper is an encapsulation of PageMapper, once you obtain a KernelMapper, you can use the PageMapper-related interfaces to manage the mapping in the kernel space. + +:::{warning} +**Never** use KernelMapper to map memory in user address space. This would cause that part of memory to be detached from the user address space management, leading to memory errors. +::: + +## 3. Allocating Memory for User Programs + +  In the kernel, you can use the user address space structure (`AddressSpace`) and its functions such as `mmap()`, `map_anonymous()`, etc., to allocate memory for user programs. These functions will automatically map the user program's memory into the user address space and automatically create VMA structures. You can use the `AddressSpace`'s `munmap()` function to unmap the user program's memory from the user address space and destroy the VMA structure. Functions such as `mprotect()` can be used for adjusting permissions. diff --git a/docs/locales/en/kernel/memory_management/index.rst b/docs/locales/en/kernel/memory_management/index.rst new file mode 100644 index 00000000..fbdff8ec --- /dev/null +++ b/docs/locales/en/kernel/memory_management/index.rst @@ -0,0 +1,27 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/memory_management/index.rst + + - Translation time: 2025-05-19 01:41:10 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +.. _translated_label__memory_management_module_en: + +==================================== +Memory Management +==================================== + + This section explains the design and implementation principles of the memory management module, along with the corresponding interfaces. + +.. toctree:: + :maxdepth: 1 + + intro + allocate-memory + mmio diff --git a/docs/locales/en/kernel/memory_management/intro.md b/docs/locales/en/kernel/memory_management/intro.md new file mode 100644 index 00000000..503f2e73 --- /dev/null +++ b/docs/locales/en/kernel/memory_management/intro.md @@ -0,0 +1,34 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/memory_management/intro.md + +- Translation time: 2025-05-19 01:41:11 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Introduction to the Memory Management Module + +## 1. Overview + +  DragonOS implements a memory management module with excellent architectural design, encapsulating operations such as memory mapping, allocation, release, and management for both kernel space and user space. This allows kernel developers to more conveniently perform memory management tasks. + +  The memory management module of DragonOS is mainly composed of the following types of components: + +- **Hardware Abstraction Layer (MemoryManagementArch)** - Provides abstraction for specific processor architectures, enabling the memory management module to run on different processor architectures. +- **Page Mapper (PageMapper)** - Provides mapping between virtual addresses and physical addresses, as well as operations for creating, filling, destroying, and managing page tables. It is divided into two types: Kernel Page Table Mapper (KernelMapper) and User Page Table Mapper (located within the specific user address space structure). +- **Page Flusher (PageFlusher)** - Provides operations for flushing page tables (full table flush, single page flush, cross-core flush). +- **Frame Allocator (FrameAllocator)** - Provides operations for allocating, releasing, and managing page frames. Specifically, it includes BumpAllocator and BuddyAllocator. +- **Small Object Allocator** - Provides operations for allocating, releasing, and managing small memory objects. This refers to the SlabAllocator within the kernel (the implementation of SlabAllocator is currently not completed). +- **MMIO Space Manager** - Provides operations for allocating and managing MMIO address spaces. (This module is pending further refactoring.) +- **User Address Space Management Mechanism** - Provides management of user address spaces. + - **VMA Mechanism** - Provides management of user address spaces, including creation, destruction, and permission management of VMA. + - **User Mapping Management** - Works together with the VMA mechanism to manage mappings in user address spaces. +- **System Call Layer** - Provides system calls for the user-space memory management system, including mmap, munmap, mprotect, mremap, etc. +- **C Interface Compatibility Layer** - Provides interfaces for existing C code, enabling C code to run normally. diff --git a/docs/locales/en/kernel/memory_management/mmio.md b/docs/locales/en/kernel/memory_management/mmio.md new file mode 100644 index 00000000..7893dcdf --- /dev/null +++ b/docs/locales/en/kernel/memory_management/mmio.md @@ -0,0 +1,204 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/memory_management/mmio.md + +- Translation time: 2025-05-19 01:41:34 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# MMIO + +MMIO stands for "Memory-Mapped I/O," and it is widely used for interaction with hardware devices. + +## Address Space Management + +DragonOS implements a mechanism for managing MMIO address spaces. This section will introduce them. + +### Why is Automatic Allocation of MMIO Address Space Needed? + +  Since many devices on a computer require MMIO address space, and the demand for MMIO address space varies among different devices connected to each computer, manually specifying an MMIO address for each device type would lead to significant waste of virtual address space and increase system complexity. Moreover, we will need to handle exception handling functions for different virtual memory regions in the future. Therefore, we need a mechanism that can automatically allocate MMIO address space. + +### What Features Does This Mechanism Provide? + +- Allocates MMIO virtual address space ranging from 4K to 1GB for drivers +- Adds these virtual address spaces to VMA for unified management +- Allows batch release of these address spaces + +### How Is This Mechanism Implemented? + +  This mechanism essentially uses the buddy system to maintain MMIO virtual address space. In `mm/mm.h`, the MMIO virtual address space range is specified, which starts at `0xffffa10000000000` and covers a 1TB space. In other words, the buddy system maintains this 1TB virtual address space for MMIO. + +### Address Space Allocation Process + +1. Initialize the MMIO-mapping module, creating 512 1GB `__mmio_buddy_addr_region` blocks in the MMIO buddy system. +2. The driver uses `mmio_create` to request address space allocation. +3. `mmio_create` aligns the requested address space size to the nearest power of 2 and allocates memory address space from the buddy. +4. Create a VMA and mark it as `VM_IO|VM_DONTCOPY`. MMIO VMA is only bound under `initial_mm` and will not be copied. +5. Allocation is complete. + +Once the MMIO address space is allocated, it behaves like a regular VMA and can be operated using mmap series functions. + +### MMIO Mapping Process + +  After obtaining the virtual address space, when we attempt to map memory into this address space, we can call the `mm_map` function to map this region. + +  This function performs special handling for MMIO VMA mapping. That is: it creates a `Page` structure and the corresponding `anon_vma`. Then, it fills the corresponding physical address into the page table. + +### Releasing MMIO Virtual Address Space + +  When a device is unmounted, the driver can call the `mmio_release` function to release the specified MMIO address space. + +  During the release process, `mmio_release` performs the following steps: + +1. Remove the MMIO region's mapping from the page table. +2. Release the MMIO region's VMA. +3. Return the address space back to the MMIO buddy system. + +## Buddy Algorithm for MMIO + +### Definition of Buddy + +  Two memory blocks are considered buddy memory blocks if they satisfy the following three conditions: + +1. The sizes of the two memory blocks are the same. +2. The memory addresses of the two memory blocks are contiguous. +3. The two memory blocks are derived from the same larger block of memory. + +### Buddy Algorithm + +  The buddy algorithm is used to manage and organize the allocation and recycling of large contiguous memory blocks to reduce external fragmentation during system runtime. In the buddy system, each memory block size is $2^n$ bytes. In DragonOS, the buddy system memory pool maintains a total of 1TB of contiguous storage space, with the largest memory block size being $1G$ (i.e., $2^{30}B$) and the smallest memory block size being $4K$ (i.e., $2^{12}B$). + +  The core idea of the buddy algorithm is that when an application requests memory, it always allocates the smallest memory block larger than the requested size, and the allocated memory block size is $2^nB$. (e.g., if an application requests $3B$ of memory, there is no integer $n$ such that $2^n = 3$, and $3 \in [2^1, 2^2]$, so the system will allocate a $2^2B$ memory block to the application, and the memory request is successfully completed.) + +  What if there is no such "suitable" memory block in the buddy system? The system will first look for a larger memory block. If found, it will split the larger memory block into suitable memory blocks to allocate to the application. (e.g., if an application requests $3B$ of memory, and the system's smallest memory block larger than $3B$ is $16B$, then the $16B$ block will be split into two $8B$ blocks. One is placed back into the memory pool, and the other is further split into two $4B$ blocks. One of the $4B$ blocks is placed back into the memory pool, and the other is allocated to the application. Thus, the memory request is successfully completed.) + +  If the system cannot find a larger memory block, it will attempt to merge smaller memory blocks until the required size is met. (e.g., if an application requests $3B$ of memory, and the system checks the memory pool and finds only two $2B$ memory blocks, the system will merge these two $2B$ blocks into a $4B$ block and allocate it to the application. Thus, the memory request is successfully completed.) + +  Finally, if the system cannot find a large enough memory block and is unable to successfully merge smaller blocks, it will notify the application that there is not enough memory to allocate. + +### Data Structures of the Buddy Algorithm + +``` + + MmioBuddyMemPool + +┌─────────────────────────────────────────────────────────────────────────────────────┐ +│ │ +│ pool_start_addr │ +│ │ +├─────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ pool_size │ +│ │ +├─────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ │ +│ free_regions │ +│ │ +│ ┌────────────┐ │ +│ │ │ ┌───────┐ ┌────────┐ │ +│ │ ┌────────┬─┼────►│ ├────►│ │ │ +│ │ │ list │ │ │ vaddr │ │ vaddr │ │ +│ │ │ │◄├─────┤ │◄────┤ │ │ +│ MmioFreeRegionList├────────┤ │ └───────┘ └────────┘ │ +│ │ │num_free│ │ │ +│ │ └────────┘ │ MmioBuddyAddrRegion │ +│ MMIO_BUDDY_MIN_EXP - 12 │ 0 │ │ +│ ├────────────┤ │ +│ │ 1 │ │ +│ ├────────────┤ │ +│ │ 2 │ │ +│ ├────────────┤ │ +│ │ 3 │ │ +│ ├────────────┤ │ +│ │ ... │ │ +│ ├────────────┤ │ +│ │ ... │ │ +│ ├────────────┤ │ +│ MMIO_BUDDY_MAX_EXP - 12 │ 18 │ │ +│ └────────────┘ │ +│ │ +│ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────────────┘ +``` + +```rust + +/// 最大的内存块为1G,其幂为30 +const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT; +/// 最小的内存块为4K,其幂为12 +const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT; +/// 内存池数组的大小为18 +const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1; + +/// buddy内存池 +pub struct MmioBuddyMemPool { + /// 内存池的起始地址 + pool_start_addr: u64, + /// 内存池大小:初始化为1TB + pool_size: u64, + /// 空闲内存块链表数组 + /// MMIO_BUDDY_REGION_COUNT = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1 + free_regions: [SpinLock; MMIO_BUDDY_REGION_COUNT as usize], +} + +/// 空闲内存块链表结构体 +pub struct MmioFreeRegionList { + /// 存储了空闲内存块信息的结构体的链表 + list: LinkedList>, + /// 当前链表空闲块的数量 + num_free: i64, +} + +/// mmio伙伴系统内部的地址区域结构体 +pub struct MmioBuddyAddrRegion { + /// 内存块的起始地址 + vaddr: u64, +} + +``` + +### Design Philosophy + +  In DragonOS, the `MmioBuddyMemPool` structure is used as the data structure for the buddy (for convenience of expression, the buddy algorithm is referred to as buddy) memory pool. It records the starting address (pool_start_addr) of the memory pool and the total size of memory blocks in the memory pool (pool_size). It also maintains a bidirectional linked list array (free_regions) of size `MMIO_BUDDY_REGION_COUNT`. Each linked list in `free_regions` maintains several free memory blocks (MmioBuddyAddrRegion). + +  The index of `free_regions` is related to the size of the memory block. Since each memory block size is $2^{n}$ bytes, we can let $exp = n$. The conversion formula between index and exp is as follows: $index = exp - 12$. For example, a memory block of size $2^{12}$ bytes has $exp = 12$, and using the above formula, we get $index = 12 - 12 = 0$, so this memory block is stored in `free_regions[0].list`. Through this conversion formula, each time we take or release a memory block of size $2^n$, we only need to operate on `free_regions[n -12]`. In DragonOS, the largest memory block size in the buddy memory pool is $1G = 2^{30} bytes$, and the smallest is $4K = 2^{12} bytes$, so $index \in [0, 18]$. + +  As a memory allocation mechanism, the buddy serves all processes. To solve the problem of synchronizing the linked list data in free_regions among different processes, the linked list type in `free_regions` uses a SpinLock (denoted as {ref}`自旋锁 <_spinlock_doc_spinlock>`) to protect the free memory block linked list (MmioFreeRegionList). `MmioFreeRegionList` encapsulates a linked list (list) that actually stores information about free memory blocks and the corresponding list length (num_free). With the use of a spinlock, only one process can modify a particular linked list at the same time, such as taking elements from the list (memory allocation) or inserting elements into the list (memory release). + +  The element type in `MmioFreeRegionList` is the `MmioBuddyAddrRegion` structure, which records the starting address (vaddr) of the memory block. + +### Internal APIs of the Buddy Algorithm + +**P.S. The following functions are all members of the MmioBuddyMemPool structure. A global reference of type MmioBuddyMemPool has already been created in the system, denoted as `MMIO_POOL`. To use the following functions, please use them in the form of `MMIO_POOL.xxx()`, which does not require passing self.** + +| **Function Name** | **Description** | +|:----------------------------------------------------------------- |:--------------------------------------------------------- | +| __create_region(&self, vaddr) | Pass the virtual address to create a new memory block address structure | +| __give_back_block(&self, vaddr, exp) | Return the memory block at address vaddr with exponent exp back to the buddy | +| __buddy_split(&self, region, exp, list_guard) | Split the given memory block of size $2^{exp}$ into two and insert the memory blocks of size $2^{exp-1}$ into the list | +| __query_addr_region(&self, exp, list_guard) | Request a memory block of size $2^{exp}$ from the buddy | +| mmio_buddy_query_addr_region(&self, exp) | A wrapper for query_addr_region, **please use this function instead of __query_addr_region** | +| __buddy_add_region_obj(&self, region, list_guard) | Add a memory block to the specified address space list | +| __buddy_block_vaddr(&self, vaddr, exp) | Calculate the virtual memory address of the buddy block based on the address and memory block size | +| __pop_buddy_block( &self, vaddr, exp, list_guard) | Find and pop the buddy block of the specified memory block | +| __buddy_pop_region( &self, list_guard) | Retrieve a memory region from the specified free list | +| __buddy_merge(&self, exp, list_guard, high_list_guard) | Merge all memory blocks of size $2^{exp}$ | +| __buddy_merge_blocks(&self, region_1, region_2, exp, high_list_guard) | Merge two **already removed from the list** memory blocks | + +### External APIs of the Buddy Algorithm + +| **Function Name** | **Description** | +| ----------------------------------------------- | ------------------------------------------- | +| __mmio_buddy_init() | Initialize the buddy system, **called in mmio_init(), do not call it arbitrarily** | +| __exp2index(exp) | Convert the exponent $exp$ of $2^{exp}$ to the index in the memory pool's array | +| mmio_create(size, vm_flags, res_vaddr, res_length) | Create an MMIO region with size aligned to the requested size, and bind its VMA to initial_mm | +| mmio_release(vaddr, length) | Cancel the mapping of MMIO at address vaddr with size length and return it to the buddy | diff --git a/docs/locales/en/kernel/process_management/index.rst b/docs/locales/en/kernel/process_management/index.rst new file mode 100644 index 00000000..47e9eb0d --- /dev/null +++ b/docs/locales/en/kernel/process_management/index.rst @@ -0,0 +1,21 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/process_management/index.rst + + - Translation time: 2025-05-19 01:41:09 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Process Management Module +==================================== + +.. toctree:: + :maxdepth: 1 + + kthread + load_binary diff --git a/docs/locales/en/kernel/process_management/kthread.md b/docs/locales/en/kernel/process_management/kthread.md new file mode 100644 index 00000000..1a9ba159 --- /dev/null +++ b/docs/locales/en/kernel/process_management/kthread.md @@ -0,0 +1,30 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/process_management/kthread.md + +- Translation time: 2025-05-19 01:41:23 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# kthread Kernel Threads + +  The kernel thread module is implemented in `process/kthread.rs`, providing support for kernel threads and related functionalities. Kernel threads act as the "avatars" of the kernel, enhancing the system's parallelism and fault tolerance capabilities. + +## Principles + +  Each kernel thread runs in kernel mode, executing its specific tasks. + +  The creation of a kernel thread is achieved by calling the `KernelThreadMechanism::create()` or `KernelThreadMechanism::create_and_run()` function, which sends a creation task to the `kthreadd` daemon thread. In other words, the creation of a kernel thread is ultimately handled by `kthread_daemon`. + +  After a kernel thread is created, it defaults to a sleeping state. To wake it up, the `ProcessManager::wakeup` function should be used. + +  When other kernel modules wish to stop a kernel thread, they can call the `KernelThreadMechanism::stop()` function to wait for the thread to exit, then obtain the return value and clean up the thread's PCB (Process Control Block). + +  Kernel threads should frequently check the result of `KernelThreadMechanism::should_stop()` to determine whether they should exit. When it is detected that the thread needs to exit, it can return a return code to terminate itself. (Note: resource cleanup is important) diff --git a/docs/locales/en/kernel/process_management/load_binary.md b/docs/locales/en/kernel/process_management/load_binary.md new file mode 100644 index 00000000..bd32fe02 --- /dev/null +++ b/docs/locales/en/kernel/process_management/load_binary.md @@ -0,0 +1,30 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/process_management/load_binary.md + +- Translation time: 2025-05-19 01:41:18 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Loader + +## 1. Binary Program Loading + +  In this section, you will learn about the principles of the binary loader in DragonOS. + +  When DragonOS loads a binary program, it performs a "probe-load" process. + +  During the probe phase, DragonOS reads the file header and sequentially calls the probe functions of each binary loader to determine whether the binary program is suitable for that loader. If it is suitable, the loader will be used to load the program. + +  During the load phase, DragonOS uses the aforementioned loader to load the program. The loader will map the various segments of the binary program into memory and obtain the entry address of the binary program. + +:::{note} +Currently, DragonOS does not support dynamic linking, so all binary programs are statically linked. And only the ELF loader is temporarily supported. +::: diff --git a/docs/locales/en/kernel/sched/c_waiting.md b/docs/locales/en/kernel/sched/c_waiting.md new file mode 100644 index 00000000..92262107 --- /dev/null +++ b/docs/locales/en/kernel/sched/c_waiting.md @@ -0,0 +1,202 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/sched/c_waiting.md + +- Translation time: 2025-05-19 01:43:09 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# APIs Related to "Waiting" (C Language) + +:::{warning} + +As the kernel evolves, we will gradually replace the C language waiting mechanism with the Rust language waiting mechanism. During this process, we will retain both the C and Rust waiting mechanisms to allow for comparison during development. +Once the timing is ripe, we will gradually remove the C language waiting mechanism. +::: + +   If several processes need to wait for an event to occur before they can be executed, a "waiting" mechanism is required to achieve process synchronization. + +## I. wait_queue Waiting Queue + +   wait_queue is a process synchronization mechanism, known as "waiting queue" in Chinese. It can suspend the current process and wake them up when the time is ripe, by another process. + +   When you need to wait for an event to complete, using the wait_queue mechanism can reduce the overhead of process synchronization. Compared to overusing spinlocks and semaphores, or repeatedly calling usleep(1000) functions for synchronization, wait_queue is an efficient solution. + +:::{warning} +The implementation of the wait_queue in `wait_queue.h` does not have an independent queue head and does not consider locking the wait_queue. Therefore, in later development, the queue head implementation in `wait_queue_head_t` was added, which is essentially a linked list plus a spinlock. It is compatible with the queue `wait_queue_node_t` in `wait_queue.h`. When you use `struct wait_queue_head` as the queue head, you can still use the functions to add nodes to the waiting queue. +::: + +### Simple Usage + +   The usage of a waiting queue mainly includes the following parts: + +- Creating and initializing a waiting queue +- Using the `wait_queue_sleep_on_` series of functions to suspend the current process. Processes that are suspended later will be placed at the end of the queue. +- Using the `wait_queue_wakeup()` function to wake up processes waiting in the waiting queue and add them to the scheduling queue + +   To use wait_queue, you need to `#include`, and create a `wait_queue_node_t` type variable as the head of the waiting queue. This structure contains only two member variables: + +```c +typedef struct +{ + struct List wait_list; + struct process_control_block *pcb; +} wait_queue_node_t; +``` + +   For the waiting queue, there is a good naming method: + +```c +wait_queue_node_t wq_keyboard_interrupt_received; +``` + +   This naming convention increases code readability and makes it easier to understand what the code is waiting for. + +### Initializing the Waiting Queue + +   The function `wait_queue_init(wait_queue_node_t *wait_queue, struct process_control_block *pcb)` provides the functionality to initialize a wait_queue node. + +   When you initialize the queue head, you only need to pass the pointer to the wait_queue head node, and set the second parameter to NULL. + +### Inserting a Node into the Waiting Queue + +   You can use the following functions to suspend the current process and insert it into the specified waiting queue. These functions have similar overall functions, but differ in some details. + +| Function Name | Explanation | +| ----------------------------------- | ---------------------------------------------------------------- | +| wait_queue_sleep_on() | Suspends the current process and sets the suspension state to PROC_UNINTERRUPTIBLE | +| wait_queue_sleep_on_unlock() | Suspends the current process and sets the suspension state to PROC_UNINTERRUPTIBLE. After the current process is inserted into the waiting queue, it unlocks the given spinlock | +| wait_queue_sleep_on_interriptible() | Suspends the current process and sets the suspension state to PROC_INTERRUPTIBLE | + +### Waking Up a Process from the Waiting Queue + +   You can use the `void wait_queue_wakeup(wait_queue_node_t * wait_queue_head, int64_t state);` function to wake up the first process in the specified waiting queue that has a suspension state matching the specified `state`. + +   If there are no matching processes, no process will be woken up, as if nothing happened. + +------------------------------------------------------------ +   +   +   + +## II. wait_queue_head Waiting Queue Head + +   The data structure is defined as follows: + +```c +typedef struct +{ + struct List wait_list; + spinlock_t lock; // 队列需要有一个自旋锁,虽然目前内部并没有使用,但是以后可能会用. +} wait_queue_head_t; +``` + +   The usage logic of the waiting queue head is the same as the waiting queue itself, because it is also a node of the waiting queue (just with an additional lock). The functions of wait_queue_head are basically the same as those of wait_queue, except that they include the string \*\*\*\_with\_node\_\*\*\*. + +   Meanwhile, the wait_queue.h file provides many macros that can make your work easier. + +### Provided Macros +| Macro | Explanation | +| ----------------------------------- | ---------------------------------------------------------------- | +| DECLARE_WAIT_ON_STACK(name, pcb) | Declare a wait_queue node on the stack, and bind the pcb-represented process to this node | +| DECLARE_WAIT_ON_STACK_SELF(name) | Declare a wait_queue node on the stack, and bind the current process (i.e., the process itself) to this node | +| DECLARE_WAIT_ALLOC(name, pcb) | Use `kzalloc` to declare a wait_queue node, and bind the pcb-represented process to this node. Remember to use kfree to release the space | +| DECLARE_WAIT_ALLOC_SELF(name) | Use `kzalloc` to declare a wait_queue node, and bind the current process (i.e., the process itself) to this node. Remember to use kfree to release the space | + +### Creating a Waiting Queue Head +   You can directly call the macro +```c +DECLARE_WAIT_QUEUE_HEAD(m_wait_queue_head); // 在栈上声明一个队列头变量 +``` +   Or manually declare +```c +struct wait_queue_head_t m_wait_queue_head = {0}; +wait_queue_head_init(&m_wait_queue_head); +``` + +### Inserting a Node into the Waiting Queue + +| Function Name | Explanation | +| ----------------------------------- | ---------------------------------------------------------------- | +| wait_queue_sleep_with_node(wait_queue_head_t *head, wait_queue_node_t *wait_node) | Pass in a waiting queue node, and set the suspension state of the node to PROC_UNINTERRUPTIBLE | +| wait_queue_sleep_with_node_unlock(wait_queue_head_t *q, wait_queue_node_t *wait, void *lock) | Pass in a waiting queue node, suspend the process pointed to by the node's pcb, and set the suspension state to PROC_UNINTERRUPTIBLE. After the current process is inserted into the waiting queue, unlock the given spinlock | +| wait_queue_sleep_with_node_interriptible(wait_queue_head_t *q, wait_queue_node_t *wait) | Pass in a waiting queue node, suspend the process pointed to by the node's pcb, and set the suspension state to PROC_INTERRUPTIBLE | + +### Waking Up a Process from the Waiting Queue +   The `wait_queue_wakeup` function in `wait_queue.h` directly kfree's the wait_node node. For stack-based wait_node, you can choose `wait_queue_wakeup_on_stack(wait_queue_head_t *q, int64_t state)` to wake up the queue head node in the queue. + +------------------------------------------------------------ +   +   +   + +## III. completion Completion Count + +### Simple Usage +   The usage of completion mainly includes the following parts: + +- Declare a completion (can be on the stack, using kmalloc, or using an array) +- Use wait_for_completion to wait for the event to complete +- Use complete to wake up the waiting processes + +   Waiting operation +```c +void wait_fun() { + DECLARE_COMPLETION_ON_STACK(comp); // 声明一个completion + + // .... do somethind here + // 大部分情况是你使用kthread_run()创建了另一个线程 + // 你需要把comp变量传给这个线程, 然后当前线程就会等待他的完成 + + if (!try_wait_for_completion(&comp)) // 进入等待 + wait_for_completion(&comp); +} +``` + +   Completion operation +```c +void kthread_fun(struct completion *comp) { + // ...... 做一些事 ....... + // 这里你确定你完成了目标事件 + + complete(&comp); + // 或者你使用complete_all + complete_all(&comp); +} +``` + +### More Usage +   In the kernel/sched/completion.c folder, you can see several functions starting with __test__, which are test code for the completion module and cover most of the completion functions. You can refer to these functions to learn how to use them. + +### Initializing Completion +   The function `completion_init(struct completion *x)` provides the functionality to initialize a completion. When you use `DECLARE_COMPLETION_ON_STACK` to create (on the stack), it will be automatically initialized. + +### Completion-related wait series functions + +| Function Name | Explanation | +| ----------------------------------- | ---------------------------------------------------------------- | +| wait_for_completion(struct completion *x) | Suspends the current process and sets the suspension state to PROC_UNINTERRUPTIBLE. | +| wait_for_completion_timeout(struct completion *x, long timeout) | Suspends the current process and sets the suspension state to PROC_UNINTERRUPTIBLE. After waiting for timeout time (jiffies time slice), the process is automatically awakened. | +| wait_for_completion_interruptible(struct completion *x) | Suspends the current process and sets the suspension state to PROC_INTERRUPTIBLE. | +| wait_for_completion_interruptible_timeout(struct completion *x, long timeout) | Suspends the current process and sets the suspension state to PROC_INTERRUPTIBLE. After waiting for timeout time (jiffies time slice), the process is automatically awakened. | +| wait_for_multicompletion(struct completion x[], int n)| Suspends the current process and sets the suspension state to PROC_UNINTERRUPTIBLE. (Waiting for the completion of the array's completions) | + +### Completion-related complete series functions + +| Function Name | Explanation | +| ----------------------------------- | ---------------------------------------------------------------- | +| complete(struct completion *x) | Indicates that an event has been completed, and wakes up one process from the waiting queue | +| complete_all(struct completion *x) | Indicates that the events related to this completion are marked as permanently completed, and wakes up all processes in the waiting queue | + +### Other Functions for Querying Information +| Function Name | Explanation | +| ----------------------------------- | ---------------------------------------------------------------- | +| completion_done(struct completion *x) | Checks if the completion's done variable is greater than 0. If it is, returns true; otherwise, returns false. Adding this function before waiting may accelerate the process? (Not tested experimentally yet, needs further verification) | +| try_wait_for_completion(struct completion *x) | Checks if the completion's done variable is greater than 0. If it is, returns true (and decrements done by 1); otherwise, returns false. Adding this function before waiting may accelerate the process? (This function has the same logic as `completion_done`, but actively decrements the completion's done variable by 1) | diff --git a/docs/locales/en/kernel/sched/cfs.md b/docs/locales/en/kernel/sched/cfs.md new file mode 100644 index 00000000..663c2492 --- /dev/null +++ b/docs/locales/en/kernel/sched/cfs.md @@ -0,0 +1,43 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/sched/cfs.md + +- Translation time: 2025-05-19 01:41:13 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# APIs Related to the Completely Fair Scheduler + +   CFS (Completely Fair Scheduler), as the name suggests, is a fully fair scheduler. CFS is one of the mainline schedulers and is also one of the most typical O(1) schedulers. + +## Structure Introduction + +- `_translated_label__`CompletelyFairScheduler`` +   ``CompletelyFairScheduler``实现了``Scheduler``trait,他是完全调度算法逻辑的主要实施者。 + +- ``FairSchedEntity`` + - **重要字段** + - ``cfs_rq``: 它指向了自己所在的完全公平调度队列。 + - ``my_cfs_rq``: 为一个``Option``变量,当该实体作为一个单独进程时,这个值为``None``,但是若这个实体为一个组,那这个变量必需为这个组内的私有调度队列。这个``cfs_rq``还可以继续往下深入,就构成了上述的树型结构。 + - ``pcb``: 它指向了当前实体对应的``PCB``,同样,若当前实体为一个组,则这个``Weak``指针不指向任何值。 + +  ``FairSchedEntity``是完全公平调度器中最重要的结构体,他代表一个实体单位,它不止表示一个进程,它还可以是一个组或者一个用户,但是它在cfs队列中所表示的就单单是一个调度实体。这样的设计可以为上层提供更多的思路,比如上层可以把不同的进程归纳到一个调度实体从而实现组调度等功能而不需要改变调度算法。 + +  在cfs中,整体的结构是**一棵树**,每一个调度实体作为``cfs_rq``中的一个节点,若该调度实体不是单个进程(它可能是一个进程组),则在该调度实体中还需要维护一个自己的``cfs_rq``,这样的嵌套展开后,每一个叶子节点就是一个单独的进程。需要理解这样一棵树,**在后续文档中会以这棵树为核心讲解**。 + +  该结构体具体的字段意义请查阅源代码。这里提及几个重要的字段: + + +- ``CfsRunQueue`` +  ``CfsRunQueue``完全公平调度算法中管理``FairSchedEntity``的队列,它可以挂在总的``CpuRunQueue``下,也可以作为子节点挂在``FairSchedEntity``上,详见上文``FairSchedEntity``。 + + - **重要字段** + - ``entities``: 存储调度实体的红黑树 + - ``current`_en`: The entity currently running diff --git a/docs/locales/en/kernel/sched/core.md b/docs/locales/en/kernel/sched/core.md new file mode 100644 index 00000000..f4bd2fc7 --- /dev/null +++ b/docs/locales/en/kernel/sched/core.md @@ -0,0 +1,79 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/sched/core.md + +- Translation time: 2025-05-19 01:41:31 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# APIs Related to Process Scheduler + +   This section defines the APIs related to process scheduling in DragonOS, which are the interfaces for the system to perform process scheduling. It also abstracts the Scheduler trait to allow specific scheduler implementations. + +## Introduction to Scheduler + +   Generally, a system handles multiple requests at the same time, but its resources are limited and prioritized. Scheduling is the method used to coordinate each request's usage of these resources. + +## Overall Architecture +   The entire scheduling subsystem is organized in a **tree structure**, with each CPU managing such a tree. Each CPU's ``CpuRunQueue``即可以理解为树的根节点。每个``CpuRunQueue``下会管理着不同调度策略的子树,根据不同的调度策略深入到对应子树中实施调度。大体结构如下: + +- CpuRunQueue + - Cfs + - CfsRunQueue + - FairSchedEntity + - CfsRunQueue + - ...(嵌套) + - Rt + - ... + - Idle + - ... + - RR + - ... + - ... + +  基于这个结构,调度子系统能够更轻松地解耦以及添加其他调度策略。 +   + +## 重要结构 +- ``Scheduler:`` +  ``Scheduler``是各个调度算法提供给上层的接口,实现不同的调度算法,只需要向外提供这样一组接口即可。 + +- ``CpuRunQueue:`` +  ``CpuRunQueue``为总的CPU运行队列,他会根据不同的调度策略来进行调度。他作为调度子系统的根节点来组织调度。 + - **重要字段** + - ``lock``: 过程锁,因为在深入到具体调度策略后的调度过程中还会需要访问``CpuRunQueue``中的信息,在cfs中保存了``CpuRunQueue``对象,我们需要确保在整体过程上锁后,子对象中不需要二次加锁即可访问,所以过程锁比较适合这个场景,若使用对象锁,则在对应调度策略中想要访问``CpuRunQueue``中的信息时需要加锁,但是最外层已经将``CpuRunQueue``对象上锁,会导致内层永远拿不到锁。对于该字段,详见[CpuRunQueue的self_lock方法及其注释](https://code.dragonos.org.cn/xref/DragonOS/kernel/src/sched/mod.rs?r=dd8e74ef0d7f91a141bd217736bef4fe7dc6df3d#360)。 + - ``cfs``: Cfs调度器的根节点,往下伸展为一棵子树,详见完全公平调度文档。 + - ``current``: 当前在CPU上运行的进程。 + - ``idle``: 当前CPU的Idle进程。 + + +## 调度流程 +  一次有效的调度分两种情况,第一是主动调用``__schedule``或者``schedule``函数进行调度,第二是通过时钟中断,判断当前运行的任务时间是否到期。 + +- **主动调度** + - ``__schedule``和``schedule``函数: + - ``__schedule``:真正执行调度。会按照当前调度策略来选择下一个任务执行。 + - ``schedule``: ``__schedule``的上层封装,它需要该任务在内核中的所有资源释放干净才能进行调度,即判断当前进程的``preempt_count``是否为0,若不为0则会**panic**。 + - 参数:这两个函数都需要提供一个参数:``SchedMode``。用于控制此次调度的行为,可选参数主要有以下两个: + - ``SchedMode::SM_NONE``: 标志当前进程没有被抢占而是主动让出,他**不会**被再次加入队列,直到有其他进程主动唤醒它,这个标志位主要用于信号量、等待队列以及一些主动唤醒场景的实现。 + - ``SchedMode::SM_PREEMPT``:标志当前是被**抢占**运行的,他**会**再次被加入调度队列等待下次调度,通俗来说:它是被别的进程抢占了运行时间,有机会运行时他会继续执行。 + +- **时钟调度** +  时钟中断到来的时候,调度系统会进行更新,包括判断是否需要下一次调度。以下为主要的函数调用栈: + - ``LocalApicTimer::handle_irq``: 中断处理函数 + - ``ProcessManager::update_process_times``: 更新当前进程的时钟信息(统计运行时等) + - ``scheduler_tick``: 调度子系统tick入口 + - ``CompletelyFairScheduler::tick``: 以cfs为例,此为cfs调度算法的tick入口 + - ``CfsRunQueue::entity_tick``: 对所有调度实体进行tick + - ``CfsRunQueue::update_current``: 更新当前运行任务的运行时间及判断是否到期 + - ``CfsRunQueue::account_cfs_rq_runtime``: 计算当前队列的运行时间 + - ``CpuRunQueue::resched_current``: 若上一步计算的时间超时则到这一步,这里会设置进程标志为``NEED_SCHEDULE``. + + - 退出中断:退出中断时检查当前进程是否存在标志位``NEED_SCHEDULE``,若存在则调用``__schedule`` performs scheduling. diff --git a/docs/locales/en/kernel/sched/index.rst b/docs/locales/en/kernel/sched/index.rst new file mode 100644 index 00000000..81ebe135 --- /dev/null +++ b/docs/locales/en/kernel/sched/index.rst @@ -0,0 +1,28 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/sched/index.rst + + - Translation time: 2025-05-19 01:41:10 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +==================================== +DragonOS Scheduling +==================================== + + This is the documentation related to process scheduling in DragonOS. + +.. toctree:: + :maxdepth: 1 + + c_waiting + rust_waiting + core + cfs + rt + kernel_timer diff --git a/docs/locales/en/kernel/sched/kernel_timer.md b/docs/locales/en/kernel/sched/kernel_timer.md new file mode 100644 index 00000000..77c4e9f0 --- /dev/null +++ b/docs/locales/en/kernel/sched/kernel_timer.md @@ -0,0 +1,184 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/sched/kernel_timer.md + +- Translation time: 2025-05-19 01:41:48 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Kernel Timer + +## 1. Introduction + +  The kernel timer is a type of timer within the kernel. The working mechanism of the kernel timer is: adding the timer to a queue and setting the expiration time for each timer. When the timer expires, the function corresponding to the timer is executed. + +## 2. Design Concept + +  The timer type is a structure of `Timer`, and `Timer` is composed of `SpinLock`. A global queue `TIMER_LIST` with element type `Arc` is used to store the timers created by the system. When creating a timer, you should call `Timer::new(timer_func,expire_jiffies)`, where timer_func is the function to be executed by the timer, expire_jiffies is the expiration time of the timer, and the type of `timer_func` parameter is a structure that implements the `TimerFunction` characteristic. After creating the timer, you should use `Timer::activate()` to insert the timer into `TIMER_LIST`. + +  **If you only want the current PCB to sleep for a certain period, you should call `schedule_timeout(timeout)`, and timeout specifies the duration of the PCB sleep.** + +## 3. Features That the Timer Should Implement + +  The function to be executed by the timer should implement the `TimerFunction` characteristic, and its definition is as follows: + +```rust +/// 定时器要执行的函数的特征 +pub trait TimerFunction: Send + Sync { + fn run(&mut self); +} +``` + +  A typical implementation method is: creating a zero-length structure, implementing the `TimerFunction` characteristic, and then implementing the operation to be performed by the timer in the `run` function. + +## 4. Timer API + +### 4.1. Timer API + +#### 4.1.1. Create a Timer +```rust +pub fn new(timer_func: Box, expire_jiffies: u64) -> Arc +``` + +**Parameters** + +- timer_func: A structure corresponding to the function that the timer needs to execute, which implements the `TimerFunction` characteristic + +- expire_jiffies: The expiration time of the timer (unit: **jiffies**) + +**Return** + +- Pointer to the timer structure + +#### 4.1.2. Insert the Timer into the Timer List + +```rust +pub fn activate(&self) +``` + +### 4.2. Other APIs + +  **If you want to use the following functions in a .c module, please add rs_ before the function name.** + +#### 4.2.1. Make the Process Sleep for a Certain Period + +```rust +pub fn schedule_timeout(mut timeout: i64) -> Result +``` + +**Function** + +  Make the process sleep for timeout jiffies + +**Parameters** + +- timeout: The time to sleep (unit: **jiffies**) + +**Return Value** + +- Ok(i64): Remaining time to sleep (unit: **jiffies**) +- Err(SystemError): Error code + +#### 4.2.2. Get the Expiration Time of the First Timer in the Queue + +```rust +pub fn timer_get_first_expire() -> Result +``` + +**Function** + +  Get the expiration time of the first timer in the queue, i.e., the expiration time of the earliest expiring timer + +**Return Value** + +- Ok(i64): Expiration time of the earliest expiring timer (unit: **jiffies**) +- Err(SystemError): Error code + +#### 4.2.3. Get the Current System Time + +```rust +pub fn clock() -> u64 +``` + +**Function** + +  Get the current system time (unit: **jiffies**) + +#### 4.2.4. Calculate the Timer Time Slice Corresponding to the Next n Milliseconds or Microseconds + +##### 4.2.4.1. Milliseconds + +```rust +pub fn next_n_ms_timer_jiffies(expire_ms: u64) -> u64 +``` + +**Function** + +  Calculate the timer time slice corresponding to the next n **milliseconds** + +**Parameters** + +- expire_ms: n milliseconds + +**Return Value** + +  The corresponding timer time slice (unit: **milliseconds**) + +##### 4.2.4.2. Microseconds + +```rust +pub fn next_n_us_timer_jiffies(expire_us: u64) -> u64 +``` + +**Function** + +  Calculate the timer time slice corresponding to the next n **microseconds** + +**Parameters** + +- expire_ms: n microseconds + +**Return Value** + +  The corresponding timer time slice (unit: **microseconds**) + +## 5. Creating a Timer Instance + +```rust +struct TimerExample { + /// 结构体的成员对应函数的形参 + example_parameter: i32, +} +impl TimerExample { + pub fn new(para: i32) -> Box { + return Box::new(TimerExample { + example_parameter: para, + }); + } +} +/// 为结构体实现TimerFunction特性 +impl TimerFunction for TimerExample { + /// TimerFunction特性中的函数run + fn run(&mut self) { + // 定时器需要执行的操作 + example_func(self.example_parameter); + } +} +fn example_func(para: i32) { + println!("para is {:?}", para); +} +fn main() { + let timer_example: Box = TimerExample::new(1); + // 创建一个定时器 + let timer: Arc = Timer::new(timer_example, 1); + // 将定时器插入队列 + timer.activate(); +} +``` diff --git a/docs/locales/en/kernel/sched/rt.md b/docs/locales/en/kernel/sched/rt.md new file mode 100644 index 00000000..994e1e4f --- /dev/null +++ b/docs/locales/en/kernel/sched/rt.md @@ -0,0 +1,71 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/sched/rt.md + +- Translation time: 2025-05-19 01:41:17 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# APIs Related to Real-Time Process Scheduler + +   RT (Real-Time Scheduler), real-time scheduler. Real-time scheduling is a method of allocating CPU resources to complete real-time processing tasks. + +   In DragonOS, processes are divided into two categories: "real-time processes" and "normal processes". Real-time processes have higher priority than normal processes. If there are real-time processes in the current system's execution queue, the RT scheduler will prioritize selecting a real-time process. If there are multiple real-time processes in the queue, the scheduler will select the one with the highest priority to execute. + +## 1. Introduction to RTQueue + +   RTQueue is a scheduling queue used to store real-time processes with a state of running. Each CPU maintains its own RTQueue, and it primarily uses Vec as the main storage structure to implement this. + +### 1.1 Main Functions +1. enqueue(): Add the PCB to the queue +2. dequeue(): Remove the PCB from the queue + +## 2. Introduction to SchedulerRT + +   RT Scheduler class, which mainly implements the initialization and scheduling function of the RT scheduler. + +### 2.1 Main Functions +1. pick_next_task_rt(): Get the first PCB that needs to be executed on the current CPU +2. sched(): Implementation of the sched() function for the Scheduler trait. This function handles the logic for scheduling real-time processes and returns the PCB to be executed next. If no suitable PCB is found, it returns None. +3. enqueue(): Also an implementation of the sched() function for the Scheduler trait, which adds a PCB to the scheduler's scheduling queue + +### 2.2 Kernel Scheduling Policies +   Currently, the main scheduling policies in DragonOS are SCHED_NORMAL policy | SCHED_FIFO policy | SCHED_RT policy. The specific scheduling policies are as follows: +1. SCHED_NORMAL policy: +SCHED_NORMAL is an "absolute fair scheduling policy", and processes using this policy are scheduled using CFS. + +2. SCHED_FIFO policy: +SCHED_FIFO is a "real-time process scheduling policy", which is a first-in-first-out scheduling strategy. This policy does not involve the CPU time slice mechanism. Without a higher-priority process, the process can only wait for other processes to release CPU resources. In the SCHED_FIFO policy, the running time of the process scheduled by the scheduler is not limited and can run for an arbitrary length of time. + +3. SCHED_RR policy: +SCHED_RR is a "real-time process scheduling policy", which uses a time-slice rotation mechanism. The time_slice of the corresponding process will decrease during execution. Once the process uses up its CPU time slice, it will be added to the execution queue of the same priority on the same CPU. At the same time, the CPU resource is released, and the CPU usage will be allocated to the next process to execute. + +## 3. Q&A +   Several commonly used methods +1. How to create a real-time process + + ```c + struct process_control_block *pcb_name = kthread_run_rt(&fn_name, NULL, "test create rt pcb"); + ``` + Where kthread_run_rt is a macro for creating a kernel real-time thread + +2. Meaning of fields related to real-time processes in the PCB + 1. policy: The scheduling policy of the real-time process, currently SCHED_FIFO and SCHED_RR + 2. priority: The priority of the real-time process, ranging from 0 to 99. The larger the number, the higher the priority + 3. rt_time_slice: The time slice of the real-time process. The default is 100, which decreases as the CPU runs. When rt_time_slice reaches 0, the time slice is reset to its initial value, and the process is added to the execution queue + +3. How real-time processes are stored in the queue + - Currently, Vec is used to store the processes. Due to the specific implementation logic, the enqueue and dequeue operations are performed at the end of the queue. Therefore, the following phenomenon may occur: when there are multiple real-time processes with the same priority waiting to run, a starvation phenomenon may occur. That is, the process that ran out of its time slice will be executed next, causing starvation among the processes with the same priority waiting. + +4. Todo + 1. Use a doubly linked list (or other methods) to store the queue of real-time processes to solve the above starvation issue + 2. Currently, the real-time scheduling is for a single CPU. It needs to be implemented for multiple CPUs + 3. Implement the bandwidth allocation ratio between real-time processes and normal processes + 4. Achieve load balancing between multiple CPUs diff --git a/docs/locales/en/kernel/sched/rust_waiting.md b/docs/locales/en/kernel/sched/rust_waiting.md new file mode 100644 index 00000000..c401d815 --- /dev/null +++ b/docs/locales/en/kernel/sched/rust_waiting.md @@ -0,0 +1,94 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/sched/rust_waiting.md + +- Translation time: 2025-05-19 01:41:21 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# APIs Related to "Waiting" (Rust Language) + +   If several processes need to wait for a certain event to occur before they can be executed, a "waiting" mechanism is required to achieve process synchronization. + +## 1. WaitQueue Waiting Queue + +   WaitQueue is a process synchronization mechanism, known as "Waiting Queue" in Chinese. It can suspend the current process and, when the time is ripe, another process can wake them up. + +   When you need to wait for an event to complete, using the WaitQueue mechanism can reduce the overhead of process synchronization. Compared to abusing spinlocks and semaphores, or repeatedly using functions like usleep(1000), WaitQueue is an efficient solution. + +### 1.1 Using WaitQueue + +   Using WaitQueue is very simple, requiring just three steps: + +1. Initialize a WaitQueue object. +2. Call the API related to suspending the current process and suspend it. +3. When the event occurs, another process calls the API related to waking up the WaitQueue to wake up a process. + +   Here is a simple example: + +### 1.1.1 Initializing a WaitQueue Object + +   Initializing a WaitQueue object is very simple; you just need to call `WaitQueue::INIT`. + +```rust +let mut wq = WaitQueue::INIT; +``` + +### 1.1.2 Suspending the Process + +   You can suspend the current process as follows: + +```rust +wq.sleep(); +``` + +   The current process will be suspended until another process calls `wq.wakeup()`. + +### 1.1.3 Waking Up the Process + +   You can wake up a process as follows: + +```rust +// 唤醒等待队列头部的进程(如果它的state & PROC_INTERRUPTIBLE 不为0) +wq.wakeup(PROC_INTERRUPTIBLE); + +// 唤醒等待队列头部的进程(如果它的state & PROC_UNINTERRUPTIBLE 不为0) +wq.wakeup(PROC_UNINTERRUPTIBLE); + +// 唤醒等待队列头部的进程(无论它的state是什么) +wq.wakeup((-1) as u64); +``` + +### 1.2 APIs + +### 1.2.1 Suspending the Process + +   You can use the following functions to suspend the current process and insert it into the specified waiting queue. These functions have similar overall functionality, but differ in some details. + +| Function Name | Explanation | +| --------------------------------------- | ---------------------------------------------------------------- | +| sleep() | Suspend the current process and set its state to `PROC_INTERRUPTIBLE` | +| sleep_uninterruptible() | Suspend the current process and set its state to `PROC_UNINTERRUPTIBLE` | +| sleep_unlock_spinlock() | Suspend the current process and set its state to `PROC_INTERRUPTIBLE`. After inserting the current process into the waiting queue, unlock the given spinlock | +| sleep_unlock_mutex() | Suspend the current process and set its state to `PROC_INTERRUPTIBLE`. After inserting the current process into the waiting queue, unlock the given Mutex | +| sleep_uninterruptible_unlock_spinlock() | Suspend the current process and set its state to `PROC_UNINTERRUPTIBLE`. After inserting the current process into the waiting queue, unlock the given spinlock | +| sleep_uninterruptible_unlock_mutex() | Suspend the current process and set its state to `PROC_UNINTERRUPTIBLE`. After inserting the current process into the waiting queue, unlock the given Mutex | + +### 1.2.2 Waking Up the Process + +   You can use the `wakeup(state)` function to wake up the first process in the waiting queue. If the process's state, after performing a bitwise AND operation with the given state, results in a non-zero value, it will be woken up. + +   Return value: Returns `true` if a process is woken up, otherwise returns `false`. + +### 1.2.3 Other APIs + +| Function Name | Explanation | +| ------------- | ------------------ | +| len() | Returns the number of processes in the waiting queue | diff --git a/docs/locales/en/kernel/syscall/index.rst b/docs/locales/en/kernel/syscall/index.rst new file mode 100644 index 00000000..cc39e805 --- /dev/null +++ b/docs/locales/en/kernel/syscall/index.rst @@ -0,0 +1,23 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/syscall/index.rst + + - Translation time: 2025-05-19 01:41:08 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +.. _translated_label__syscall_en: + +System Calls +==================================== + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + syscall_table diff --git a/docs/locales/en/kernel/syscall/syscall_table.rst b/docs/locales/en/kernel/syscall/syscall_table.rst new file mode 100644 index 00000000..5a77080a --- /dev/null +++ b/docs/locales/en/kernel/syscall/syscall_table.rst @@ -0,0 +1,107 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/syscall/syscall_table.rst + + - Translation time: 2025-05-19 01:41:32 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +System Call Table Implementation Plan +===================================== + +.. note:: + Author: longjin + + Date: 2025/05/13 + +Overview +-------- + +.. mermaid:: + :align: center + :caption: System Call Table Architecture + + classDiagram + class Syscall { + <> + +num_args() usize + +handle(args, from_user) Result + +entry_format(args) Vec + } + + class SyscallHandle { + +nr: usize + +inner_handle: &dyn Syscall + } + + class SyscallTable { + -entries: [Option<&SyscallHandle>; 512] + +get(nr) Option<&dyn Syscall> + } + + Syscall <|.. SysXXXXXXHandle + SyscallHandle "1" *-- "1" Syscall + SyscallTable "1" *-- "512" SyscallHandle + +Compared to the original approach of dispatching system calls in a single large match statement, this approach uses a trait-based and system call table-based implementation. The main advantages include: + +- Reduced stack memory usage: Avoids a single large function consuming excessive stack space +- Support for parameter printing: Through a unified parameter formatting interface +- Better extensibility: Adding new system calls does not require modifying the dispatch logic + +Core Design +----------- + +Syscall Trait +~~~~~~~~~~~~~ + +All system call handler functions must implement the `Syscall` trait: + +.. code-block:: rust + + pub trait Syscall: Send + Sync + 'static { + fn num_args(&self) -> usize; + fn handle(&self, args: &[usize], from_user: bool) -> Result; + fn entry_format(&self, args: &[usize]) -> Vec; + } + +- `num_args()`: Returns the number of arguments required by the system call +- `handle()`: Executes the actual system call handling +- `entry_format()`: Formats the parameters for debugging printing + +SyscallHandle +~~~~~~~~~~~~~ + +The `SyscallHandle` struct associates a system call number with its handler: + +.. code-block:: rust + + pub struct SyscallHandle { + pub nr: usize, // System call number + pub inner_handle: &'static dyn Syscall, // Handler function + pub name: &'static str, + } + +SyscallTable +~~~~~~~~~~~~ + +The `SyscallTable` manages all system calls: + +- Fixed size of 512 entries +- Initialized at compile time +- Allows quick lookup of the handler function by system call number + +Usage +----- + +Implementing a System Call +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. Define the implementation of `Syscall` for the specific system call +2. Register the system call in the system call table +3. Load all registered system calls during system initialization diff --git a/docs/locales/en/kernel/trace/eBPF.md b/docs/locales/en/kernel/trace/eBPF.md new file mode 100644 index 00000000..92b27b6b --- /dev/null +++ b/docs/locales/en/kernel/trace/eBPF.md @@ -0,0 +1,332 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/trace/eBPF.md + +- Translation time: 2025-05-19 01:41:41 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# eBPF + +> Author: Chen Linfeng +> +> Email: chenlinfeng25@outlook.com + +## Overview + +eBPF is a revolutionary technology that originated from the Linux kernel. It allows sandboxed programs to run in privileged contexts (such as the operating system kernel). It is used to extend the kernel's functionality in a secure and efficient manner without modifying the kernel source code or loading kernel modules. + +Historically, due to the kernel's privileged position in supervising and controlling the entire system, the operating system has been an ideal place for implementing observability, security, and networking features. At the same time, due to the kernel's core position and high requirements for stability and security, the kernel has been difficult to iterate quickly. Therefore, traditionally, the innovation speed at the operating system level has been slower compared to features implemented outside the operating system itself. + +eBPF fundamentally changes this approach. By allowing sandboxed programs to run within the operating system, application developers can run eBPF programs to add additional functionality to the operating system at runtime. Then, with the help of JIT compilers and verification engines, the operating system ensures that these programs are as secure and efficient as natively compiled programs. This has sparked a wave of eBPF-based projects covering a wide range of use cases, including next-generation network implementations, observability, and security features. + +## eBPF in DragonOS + +Adding eBPF support to a new OS requires understanding the eBPF runtime process. Typically, eBPF needs user-space tools and kernel-related infrastructure to function properly. Since a new OS usually is compatible with Linux applications, this can further simplify the porting work of user-space tools. As long as the kernel implements the relevant system calls and features, it can work with existing tools to support eBPF. + +## eBPF Execution Process + +![image-20240909165945192](/kernel/trace/ebpf_flow.png) + +As shown in the figure, the execution process of an eBPF program is divided into three main steps: + +1. Source code -> Binary + 1. Users can write eBPF programs in Python/C/Rust and compile the source code into a binary program using the relevant toolchain. + 2. In this step, users need to reasonably use helper functions to enrich the functionality of the eBPF program. +2. Loading eBPF program + 1. User-space tool libraries encapsulate the system call interfaces provided by the kernel to simplify the user's work. After preprocessing, user-space tools make system calls to request the kernel to load the eBPF program. + 1. The kernel first verifies the eBPF program to check its correctness and legality, and also performs further processing on the program. + 1. The kernel attaches the eBPF program to the kernel's mount points (kprobe/uprobe/trace_point) based on the user's request. + 1. During kernel operation, when these mount points are triggered by specific events, the eBPF program is executed. +3. Data Interaction + 1. eBPF programs can collect information from the kernel, and user tools can selectively retrieve this information. + 2. eBPF programs can directly output information to a file, and user tools can read and parse the content of the file to obtain the information. + 3. eBPF programs share and exchange data between the kernel and user space through Maps. + +## User-space Support + +There are many user-space eBPF tool libraries, such as C's libbpf, Python's bcc, and Rust's Aya. Overall, the processing flow of these tools is similar. DragonOS currently supports eBPF programs written with the [Aya](https://github.com/aya-rs/aya) framework. As an example, the user-space tool processing flow for Aya is as follows: + +1. Provide helper functions and Map abstractions for eBPF usage, making it easier to implement eBPF programs. +2. Process the compiled eBPF program, call system calls to create Maps, and obtain corresponding file descriptors. +3. Update the values of Maps (.data) as needed. +4. Modify the relevant instructions of the eBPF program based on relocation information. +5. Handle bpf to bpf calls in the eBPF program according to the kernel version. +6. Load the eBPF program into the kernel. +7. Package system calls and provide a large number of functions to help access eBPF information and interact with the kernel. + +DragonOS's support for the Aya library is not complete. By trimming the Aya library, we have implemented a smaller [tiny-aya](https://github.com/DragonOS-Community/tiny-aya). To ensure future compatibility with Aya, tiny-aya only modifies the core tool aya in Aya. Some functions have been disabled because the system calls or files they require are not yet implemented in DragonOS. + +### Tokio + +Aya requires an asynchronous runtime. With the addition of some system calls and fixes for some errors, DragonOS now supports a basic Tokio runtime. + +### Using Aya to Create an eBPF Program + +As described in the [official documentation](https://aya-rs.dev/book/start/development/) provided by Aya, users only need to install the corresponding Rust toolchain according to its process to create an eBPF project based on a template. Taking the current implementation of `syscall_ebf` as an example, this program counts the number of system calls and stores them in a HashMap. + +``` +├── Cargo.toml +├── README.md +├── syscall_ebpf +├── syscall_ebpf-common +├── syscall_ebpf-ebpf +└── xtask +``` + +The project structure in the user/app directory is as follows: + +- `syscall_ebpf-ebpf` is the directory for implementing eBPF code, which will be compiled into bytecode. +- `syscall_ebpf-common` is a common library, convenient for information exchange between the kernel and user space. +- `syscall_ebpf` is the user-space program, responsible for loading the eBPF program and retrieving data generated by the eBPF program. +- `xtask` is a command-line tool, convenient for users to compile and run user-space programs. + +To run user-space programs in DragonOS, the project created using the template cannot be used directly: + +1. This project does not meet DragonOS's requirements for the structure of user programs, but this can be easily modified. +2. Because DragonOS's support for the Tokio runtime is not yet complete, the usage method needs to be slightly modified. + +``` +#[tokio::main(flavor = "current_thread")] +async fn main() -> Result<(), Box> { +``` + +3. Because the support for Aya is not complete, the project's dependencies on aya and aya-log need to be replaced with the implementations in tiny-aya. + +``` +[dependencies] +aya = { git = "https://github.com/DragonOS-Community/tiny-aya.git" } +aya-log = { git = "https://github.com/DragonOS-Community/tiny-aya.git" } +``` + +With slight modifications, eBPF programs can be implemented using the existing tools of Aya. + +## Kernel-space Support + +Kernel-space support mainly consists of three parts: + +1. kprobe implementation: located in directory `kernel/crates/kprobe` +2. rbpf runtime: located in directory `kernel/crates/rbpf` +3. System call support +4. Helper function support + +### rbpf + +Previously, rbpf was used to run some simple eBPF programs. To run more complex programs, it needs to be modified. + +1. Add support for bpf to bpf calls: by adding new stack abstractions and saving and restoring necessary register data. +2. Disable unnecessary internal memory checks, which are usually handled by the kernel's verifier. +3. Add data structures with ownership to avoid limitations on lifetimes. + +### System Calls + +All eBPF-related system calls are concentrated in `bpf()`, and they are further distinguished by the parameter `cmd`. The current support is as follows: + +```rust +pub fn bpf(cmd: bpf_cmd, attr: &bpf_attr) -> Result { + let res = match cmd { + // Map related commands + bpf_cmd::BPF_MAP_CREATE => map::bpf_map_create(attr), + bpf_cmd::BPF_MAP_UPDATE_ELEM => map::bpf_map_update_elem(attr), + bpf_cmd::BPF_MAP_LOOKUP_ELEM => map::bpf_lookup_elem(attr), + bpf_cmd::BPF_MAP_GET_NEXT_KEY => map::bpf_map_get_next_key(attr), + bpf_cmd::BPF_MAP_DELETE_ELEM => map::bpf_map_delete_elem(attr), + bpf_cmd::BPF_MAP_LOOKUP_AND_DELETE_ELEM => map::bpf_map_lookup_and_delete_elem(attr), + bpf_cmd::BPF_MAP_LOOKUP_BATCH => map::bpf_map_lookup_batch(attr), + bpf_cmd::BPF_MAP_FREEZE => map::bpf_map_freeze(attr), + // Program related commands + bpf_cmd::BPF_PROG_LOAD => prog::bpf_prog_load(attr), + // Object creation commands + bpf_cmd::BPF_BTF_LOAD => { + error!("bpf cmd {:?} not implemented", cmd); + return Err(SystemError::ENOSYS); + } + ty => { + unimplemented!("bpf cmd {:?} not implemented", ty) + } + }; + res +} +``` + +Among these, the command for creating a Map is further细分 to determine the specific Map type. Currently, we have added support for general Maps: + +```rust +bpf_map_type::BPF_MAP_TYPE_ARRAY +bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY +bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY +bpf_map_type::BPF_MAP_TYPE_HASH +bpf_map_type::BPF_MAP_TYPE_PERCPU_HASH +bpf_map_type::BPF_MAP_TYPE_QUEUE +bpf_map_type::BPF_MAP_TYPE_STACK +bpf_map_type::BPF_MAP_TYPE_LRU_HASH +bpf_map_type::BPF_MAP_TYPE_LRU_PERCPU_HASH + +bpf_map_type::BPF_MAP_TYPE_CPUMAP +| bpf_map_type::BPF_MAP_TYPE_DEVMAP +| bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH => { + error!("bpf map type {:?} not implemented", map_meta.map_type); + Err(SystemError::EINVAL)? +} +``` + +All Maps implement the defined interface, which is referenced from the Linux implementation: + +```rust +pub trait BpfMapCommonOps: Send + Sync + Debug + CastFromSync { + /// Lookup an element in the map. + /// + /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_lookup_elem/ + fn lookup_elem(&mut self, _key: &[u8]) -> Result> { + Err(SystemError::ENOSYS) + } + /// Update an element in the map. + /// + /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_update_elem/ + fn update_elem(&mut self, _key: &[u8], _value: &[u8], _flags: u64) -> Result<()> { + Err(SystemError::ENOSYS) + } + /// Delete an element from the map. + /// + /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_delete_elem/ + fn delete_elem(&mut self, _key: &[u8]) -> Result<()> { + Err(SystemError::ENOSYS) + } + /// For each element in map, call callback_fn function with map, + /// callback_ctx and other map-specific parameters. + /// + /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_for_each_map_elem/ + fn for_each_elem(&mut self, _cb: BpfCallBackFn, _ctx: *const u8, _flags: u64) -> Result { + Err(SystemError::ENOSYS) + } + /// Look up an element with the given key in the map referred to by the file descriptor fd, + /// and if found, delete the element. + fn lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()> { + Err(SystemError::ENOSYS) + } + /// perform a lookup in percpu map for an entry associated to key on cpu. + fn lookup_percpu_elem(&mut self, _key: &[u8], cpu: u32) -> Result> { + Err(SystemError::ENOSYS) + } + /// Get the next key in the map. If key is None, get the first key. + /// + /// Called from syscall + fn get_next_key(&self, _key: Option<&[u8]>, _next_key: &mut [u8]) -> Result<()> { + Err(SystemError::ENOSYS) + } + /// Push an element value in map. + fn push_elem(&mut self, _value: &[u8], _flags: u64) -> Result<()> { + Err(SystemError::ENOSYS) + } + /// Pop an element value from map. + fn pop_elem(&mut self, _value: &mut [u8]) -> Result<()> { + Err(SystemError::ENOSYS) + } + /// Peek an element value from map. + fn peek_elem(&self, _value: &mut [u8]) -> Result<()> { + Err(SystemError::ENOSYS) + } + /// Freeze the map. + /// + /// It's useful for .rodata maps. + fn freeze(&self) -> Result<()> { + Err(SystemError::ENOSYS) + } + /// Get the first value pointer. + fn first_value_ptr(&self) -> *const u8 { + panic!("value_ptr not implemented") + } +} +``` + +The system call that connects eBPF and kprobe is [`perf_event_open`](https://man7.org/linux/man-pages/man2/perf_event_open.2.html). This system call is very complex in Linux, so DragonOS does not implement it according to Linux. Currently, only two functions are supported: + +```rust +match args.type_ { + // Kprobe + // See /sys/bus/event_source/devices/kprobe/type + perf_type_id::PERF_TYPE_MAX => { + let kprobe_event = kprobe::perf_event_open_kprobe(args); + Box::new(kprobe_event) + } + perf_type_id::PERF_TYPE_SOFTWARE => { + // For bpf prog output + assert_eq!(args.config, perf_sw_ids::PERF_COUNT_SW_BPF_OUTPUT); + assert_eq!( + args.sample_type, + Some(perf_event_sample_format::PERF_SAMPLE_RAW) + ); + let bpf_event = bpf::perf_event_open_bpf(args); + Box::new(bpf_event) + } +} +``` + +- One of them, `PERF_TYPE_SOFTWARE`, is used to create software-defined events, and `PERF_COUNT_SW_BPF_OUTPUT` ensures that this event is used to collect the output of bpf. +- `PERF_TYPE_MAX` usually indicates the creation of kprobe/uprobe events, which is one of the ways users can use kprobe. Users can bind an eBPF program to this event. + +Similarly, different events of perf also implement the defined interface: + +```rust +pub trait PerfEventOps: Send + Sync + Debug + CastFromSync + CastFrom { + fn mmap(&self, _start: usize, _len: usize, _offset: usize) -> Result<()> { + panic!("mmap not implemented for PerfEvent"); + } + fn set_bpf_prog(&self, _bpf_prog: Arc) -> Result<()> { + panic!("set_bpf_prog not implemented for PerfEvent"); + } + fn enable(&self) -> Result<()> { + panic!("enable not implemented"); + } + fn disable(&self) -> Result<()> { + panic!("disable not implemented"); + } + fn readable(&self) -> bool { + panic!("readable not implemented"); + } +} +``` + +This interface is currently not stable. + +### Helper Function Support + +User-space tools communicate with the kernel through system calls to set up and exchange eBPF data. In the kernel, the execution of eBPF programs also requires the help of the kernel. A standalone eBPF program is not very useful, so it calls the kernel-provided `helper` functions to access kernel resources. + +Most of the currently supported `helper` functions are related to Map operations: + +```rust +/// Initialize the helper functions. +pub fn init_helper_functions() { + let mut map = BTreeMap::new(); + unsafe { + // Map helpers::Generic map helpers + map.insert(1, define_func!(raw_map_lookup_elem)); + map.insert(2, define_func!(raw_map_update_elem)); + map.insert(3, define_func!(raw_map_delete_elem)); + map.insert(164, define_func!(raw_map_for_each_elem)); + map.insert(195, define_func!(raw_map_lookup_percpu_elem)); + // map.insert(93,define_func!(raw_bpf_spin_lock); + // map.insert(94,define_func!(raw_bpf_spin_unlock); + // Map helpers::Perf event array helpers + map.insert(25, define_func!(raw_perf_event_output)); + // Probe and trace helpers::Memory helpers + map.insert(4, define_func!(raw_bpf_probe_read)); + // Print helpers + map.insert(6, define_func!(trace_printf)); + + // Map helpers::Queue and stack helpers + map.insert(87, define_func!(raw_map_push_elem)); + map.insert(88, define_func!(raw_map_pop_elem)); + map.insert(89, define_func!(raw_map_peek_elem)); + } + BPF_HELPER_FUN_SET.init(map); +} +``` diff --git a/docs/locales/en/kernel/trace/index.rst b/docs/locales/en/kernel/trace/index.rst new file mode 100644 index 00000000..f5c9dfec --- /dev/null +++ b/docs/locales/en/kernel/trace/index.rst @@ -0,0 +1,24 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: kernel/trace/index.rst + + - Translation time: 2025-05-19 01:41:20 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Kernel Tracing Mechanism +==================================== + + The kernel tracing mechanism consists of many functionalities, such as kprobe, uprobe, tracepoint, ftrace, and eBPF, which is used to extend the observability of the kernel. The kernel currently supports kprobe and eBPF. This chapter will introduce these two mechanisms. + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + eBPF + kprobe diff --git a/docs/locales/en/kernel/trace/kprobe.md b/docs/locales/en/kernel/trace/kprobe.md new file mode 100644 index 00000000..e32f7fb5 --- /dev/null +++ b/docs/locales/en/kernel/trace/kprobe.md @@ -0,0 +1,64 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: kernel/trace/kprobe.md + +- Translation time: 2025-05-19 01:54:55 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# kprobe + +> Author: Chen Linfeng +> Email: chenlinfeng25@outlook.com + +## Overview + +The Linux kprobes debugging technology is a lightweight kernel debugging technique specifically designed by kernel developers to facilitate tracking the execution status of kernel functions. Using kprobes technology, kernel developers can dynamically insert probe points in most specified functions of the kernel to collect the required debugging status information, with minimal impact on the original execution flow of the kernel. + +The kprobes technology relies on hardware architecture support, mainly including CPU exception handling and single-step debugging mechanisms. The former is used to cause the program's execution flow to enter the user-registered callback function, while the latter is used for single-step execution of the probed instruction. It is worth noting that on some architectures, the hardware does not support the single-step debugging mechanism, which can be resolved through software simulation methods (such as RISC-V). + +## kprobe Workflow + +xxx + +1. After registering a kprobe, each registered kprobe corresponds to a kprobe structure, which records the location of the probe point and the original instruction at that location. +2. The location of the probe point is replaced with an exception instruction. When the CPU executes to this location, it will enter an exception state. On x86_64, the instruction is int3 (if the kprobe is optimized, the instruction is jmp). +3. When the exception instruction is executed, the system checks whether it is an exception installed by kprobe. If it is, the pre_handler of the kprobe is executed. Then, using the CPU's single-step debugging (single-step) feature, the relevant registers are set, and the next instruction is set to the original instruction at the probe point, returning from the exception state. +4. The system enters the exception state again. The previous step has set the single-step related registers, so the original instruction is executed and the system will enter the exception state again. At this point, the single-step is cleared, and the post_handler is executed, and the system safely returns from the exception state. +5. When unloading the kprobe, the original instruction at the probe point is restored. + +The kernel currently supports x86 and riscv64. Since riscv64 does not have a single-step execution mode, we use the break exception to simulate it. When saving the probe point instruction, we additionally fill in a break instruction, allowing the execution of the original instruction to trigger the break exception again on the riscv64 architecture. + +## kprobe Interfaces + +```rust +pub fn register_kprobe(kprobe_info: KprobeInfo) -> Result; +pub fn unregister_kprobe(kprobe: LockKprobe) -> Result<(), SystemError>; + +impl KprobeBasic { + pub fn call_pre_handler(&self, trap_frame: &dyn ProbeArgs) + pub fn call_post_handler(&self, trap_frame: &dyn ProbeArgs) + pub fn call_fault_handler(&self, trap_frame: &dyn ProbeArgs) + pub fn call_event_callback(&self, trap_frame: &dyn ProbeArgs) + pub fn update_event_callback(&mut self, callback: Box) + pub fn disable(&mut self) + pub fn enable(&mut self) + pub fn is_enabled(&self) -> bool + pub fn symbol(&self) -> Option<&str> +} +``` + +- `call_pre_handler` Calls the user-defined callback function before the probe point instruction is executed. +- `call_post_handler` Calls the user-defined callback function after the probe point instruction has been executed in single-step mode. +- `call_fault_handler` Calls the user-defined callback function if the first two callback functions fail. +- `call_event_callback` Used to call eBPF-related callback functions, usually called in the same way as `call_post_handler` after the probe point instruction is executed in single-step mode. +- `update_event_callback` Used to update the callback function during runtime. +- `disable` and `enable` are used to dynamically disable the kprobe. After calling `disable`, the kprobe will not execute the callback function when triggered. +- `symbol` Returns the function name of the probe point. diff --git a/docs/locales/en/questions/build_errors.md b/docs/locales/en/questions/build_errors.md new file mode 100644 index 00000000..174b58ac --- /dev/null +++ b/docs/locales/en/questions/build_errors.md @@ -0,0 +1,55 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: questions/build_errors.md + +- Translation time: 2025-05-22 09:22:00 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Common Issues During Build + +Common issues encountered during the build of DragonOS and their solutions. + +## 1. Error Indicates Missing Toolchain + +### Question Detail + +During the build, if you encounter an error like ``xxxx not found``, it is typically due to the absence of the necessary compiler toolchain. + +### Answer + +If you were previously able to compile the code, but after pulling the latest code, you encounter this error, it is likely because the upstream code has updated its requirements for the toolchain. You can try the following steps to resolve this issue: + +```shell +cd tools +bash bootstrap.sh +``` + +Then, restart the terminal and re-run the build command. + +*Note:* The ``bootstrap.sh`` script is designed to be "re-runnable". It can be executed at any time to install the latest required toolchain on your system. + +## 2. Disk Image Write Failure + +### Question Detail + +- During the build of user programs, the content inside the disk image is inconsistent with the actual content. +- Errors related to symbolic links are reported. +- Some applications are not correctly installed into the image. + +### Answer + +If you encounter a disk image write failure during the build process, it could be due to insufficient disk space or permission issues. It could also be due to changes in directory attributes. + +A typical example is when a folder under ``bin/sysroot/xxx`` is actually a directory, but the new version of the application expects the directory ``xxx`` to be treated as a symbolic link. + +In such a case, you can first check whether there is an issue with the script used to compile your application. If you confirm that there is no problem, you can try the following steps: + +- Delete the ``bin/`` directory and rebuild. This can resolve most of the issues. diff --git a/docs/locales/en/questions/index.rst b/docs/locales/en/questions/index.rst new file mode 100644 index 00000000..82b25b4c --- /dev/null +++ b/docs/locales/en/questions/index.rst @@ -0,0 +1,21 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: questions/index.rst + + - Translation time: 2025-05-22 09:21:58 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Frequently Asked Questions +==================================== + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + build_errors diff --git a/docs/locales/en/userland/appdev/c-cpp-quick-start.md b/docs/locales/en/userland/appdev/c-cpp-quick-start.md new file mode 100644 index 00000000..bcf80a03 --- /dev/null +++ b/docs/locales/en/userland/appdev/c-cpp-quick-start.md @@ -0,0 +1,32 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: userland/appdev/c-cpp-quick-start.md + +- Translation time: 2025-05-19 01:41:49 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Developing C/C++ Applications for DragonOS + +## Compilation Environment + +  DragonOS has partial binary compatibility with Linux, so you can use the musl-gcc compiler from Linux. However, since DragonOS does not currently support dynamic linking, you need to add the compilation parameter `-static`. + +For example, you can use the following command: +```shell +musl-gcc -static -o hello hello.c +``` +to compile a hello.c file. + +When porting existing programs, you may need to configure `CFLAGS`, `LDFLAGS`, and `CPPFLAGS` to ensure correct compilation. Please refer to the actual requirements. + +## Configuring DADK + +Please refer to: [Quick Start | DADK](https://docs.dragonos.org.cn/p/dadk/user-manual/quickstart.html) diff --git a/docs/locales/en/userland/appdev/index.rst b/docs/locales/en/userland/appdev/index.rst new file mode 100644 index 00000000..6d592dca --- /dev/null +++ b/docs/locales/en/userland/appdev/index.rst @@ -0,0 +1,24 @@ +.. note:: AI Translation Notice + + This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + + - Source document: userland/appdev/index.rst + + - Translation time: 2025-05-19 02:13:34 + + - Translation model: `Qwen/Qwen3-8B` + + + Please report issues via `Community Channel `_ + +Application Development Documentation +=================================================== + +.. toctree:: + :maxdepth: 1 + :caption: Contents + + rust-quick-start + c-cpp-quick-start + Quick Start to Package an Application to DragonOS Using DADK + DADK Complete Documentation diff --git a/docs/locales/en/userland/appdev/rust-quick-start.md b/docs/locales/en/userland/appdev/rust-quick-start.md new file mode 100644 index 00000000..69f959c3 --- /dev/null +++ b/docs/locales/en/userland/appdev/rust-quick-start.md @@ -0,0 +1,51 @@ +:::{note} +**AI Translation Notice** + +This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only. + +- Source document: userland/appdev/rust-quick-start.md + +- Translation time: 2025-05-19 01:41:52 + +- Translation model: `Qwen/Qwen3-8B` + +Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues) + +::: + +# Quick Start Guide for Rust Application Development + +## Compilation Environment + +  DragonOS has partial binary compatibility with Linux, so you can use the Rust compiler for Linux to compile. + +## Project Configuration + +### Creating from a Template + +:::{note} +This feature requires dadk version 0.2.0 or higher. For older versions, please refer to the historical DragonOS documentation. +::: + +1. Use the `bootstrap.sh` script in the tools directory of DragonOS to initialize the environment. +2. Enter `cargo install cargo-generate` in the terminal. +3. Enter the following command in the terminal: + +```shell +cargo generate --git https://github.com/DragonOS-Community/Rust-App-Template +``` +To create the project. If your network is slow, please use a mirror site. +```shell +cargo generate --git https://git.mirrors.dragonos.org/DragonOS-Community/Rust-App-Template +``` + +4. Use `cargo run` to run the project. +5. In the `user/dadk/config` directory of DragonOS, refer to the template [userapp_config.toml](https://github.com/DragonOS-Community/DADK/blob/main/dadk-config/templates/config/userapp_config.toml) to create a compilation configuration, and install it to the `/` directory of DragonOS. +(When using the compilation command options of dadk, please use the `make install` configuration in the Makefile for compilation and installation) +6. Compile DragonOS to install. + +### Manual Configuration + +If you need to port other libraries or programs to DragonOS, please refer to the configuration in the template. + +Since DragonOS currently does not support dynamic linking, you need to specify `-C target-feature=+crt-static -C link-arg=-no-pie` in RUSTFLAGS. diff --git a/docs/questions/build_errors.md b/docs/questions/build_errors.md new file mode 100644 index 00000000..0f90a762 --- /dev/null +++ b/docs/questions/build_errors.md @@ -0,0 +1,44 @@ +# 构建错误常见问题解答 + +在构建DragonOS时遇到的常见问题及其解决方法。 + + +## 1. 报错信息指示工具链缺失 + +### question detail + +在构建中,如果出现比如`xxxx not found`这样的报错信息,通常是因为缺少必要的编译工具链。 + +### Answer + +如果你之前是可以编译的,但是在拉取最新的代码后,出现了这个错误,那么大概率是因为上游代码更新了对工具链的要求。你可以尝试以下步骤来解决这个问题: + +```shell +cd tools +bash bootstrap.sh +``` + +接着,重启终端并重新运行构建命令。 + +*Note:* `bootstrap.sh`脚本被设计为:“可重复运行”的。他可以在任何时间点运行,把当前最新需要的工具链,安装到你的系统中。 + +## 2. 磁盘镜像写入失败了 + +### question detail + +- 构建用户程序的时候,磁盘镜像里面的内容跟实际的不一致。 +- 报错符号链接相关的错误信息 +- 某些应用程序没有正确安装到镜像中 + +### Answer + + +在构建过程中,如果遇到磁盘镜像写入失败的问题,可能是由于磁盘空间不足或者权限问题。或者是目录属性有些改变。 + +一种典型的例子,`bin/sysroot/xxx`下面的某个文件夹是个实际的目录,但是新版的应用程序期望把目录`xxx`当作一个符号链接来使用。 + +对于这种情形,你可以先检查自己的应用程序编译的脚本是否有问题。如果确认没有问题,那么可以尝试以下步骤: + +- 删掉`bin/`目录,然后重新构建。这能够解决大部分的问题。 + + diff --git a/docs/questions/index.rst b/docs/questions/index.rst new file mode 100644 index 00000000..e9924cae --- /dev/null +++ b/docs/questions/index.rst @@ -0,0 +1,8 @@ +常见问题解答 +==================================== + +.. toctree:: + :maxdepth: 1 + :caption: 目录 + + build_errors diff --git a/docs/requirements.txt b/docs/requirements.txt index ce664001..16ab9161 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,7 @@ sphinx==5.0.2 myst-parser==0.18.0 sphinx-rtd-theme +sphinxcontrib-mermaid==1.0.0 git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/sphinx-multiversion.git@5858b75#egg=sphinx-multiversion +openai~=1.79 +tqdm~=4.65.0 diff --git a/docs/syscall_api/intro.md b/docs/syscall_api/intro.md deleted file mode 100644 index 941a1f85..00000000 --- a/docs/syscall_api/intro.md +++ /dev/null @@ -1 +0,0 @@ -# 简介 \ No newline at end of file diff --git a/docs/userland/appdev/index.rst b/docs/userland/appdev/index.rst index dcda84ed..ccf82118 100644 --- a/docs/userland/appdev/index.rst +++ b/docs/userland/appdev/index.rst @@ -1,5 +1,5 @@ 应用程序开发文档 -==================================== +=================================================== .. toctree:: diff --git a/env.mk b/env.mk index facd546e..e499d50b 100644 --- a/env.mk +++ b/env.mk @@ -1,6 +1,7 @@ ifeq ($(ARCH), ) -# !!!!在这里设置ARCH,可选 x86_64 和 riscv64 +# !!!!在这里设置ARCH,可选: +# x86_64, riscv64, loongarch64 # !!!!!!!如果不同时调整这里以及vscode的settings.json,那么自动补全和检查将会失效 export ARCH?=x86_64 endif diff --git a/kernel/.clippy.toml b/kernel/.clippy.toml index 2655a17f..ec3c9e21 100644 --- a/kernel/.clippy.toml +++ b/kernel/.clippy.toml @@ -1,2 +1,5 @@ # 这是clippy的配置文件,详情请见: -# https://doc.rust-lang.org/clippy/lint_configuration.html \ No newline at end of file +# https://doc.rust-lang.org/clippy/lint_configuration.html + +stack-size-threshold = 4096 +array-size-threshold = 1024 diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 9f00d490..ca935e7d 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -212,7 +212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe05a1a3c09033e9e87f7ba13af35cf2508148d3a97fb6b16475df84207993fa" dependencies = [ "libc", - "windows", + "windows 0.58.0", ] [[package]] @@ -362,20 +362,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] -name = "cstr_core" -version = "0.2.6" +name = "darling" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "cty", - "memchr", + "darling_core", + "darling_macro", ] [[package]] -name = "cty" -version = "0.2.2" +name = "darling_core" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.100", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.100", +] [[package]] name = "defer" @@ -415,6 +434,37 @@ dependencies = [ "thiserror", ] +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.100", +] + [[package]] name = "derive_more" version = "0.99.19" @@ -449,7 +499,9 @@ dependencies = [ "bitfield-struct", "bitflags 1.3.2", "bitmap", + "cfg-if", "defer", + "derive_builder", "driver_base_macros", "elf 0.7.2", "fdt", @@ -464,6 +516,7 @@ dependencies = [ "lazy_static", "linkme", "log", + "loongArch64", "lru", "multiboot2", "num", @@ -478,6 +531,7 @@ dependencies = [ "slabmalloc", "smoltcp", "static-keys", + "syscall_table_macros", "system_error", "uefi", "uefi-raw", @@ -560,6 +614,12 @@ name = "fdt" version = "0.2.0-alpha1" source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/fdt?rev=9862813020#98628130200086c2e55dae0d997ac4daeb590e90" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "foldhash" version = "0.1.5" @@ -682,6 +742,12 @@ dependencies = [ "kdepends", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "indexmap" version = "1.9.3" @@ -871,6 +937,16 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "loongArch64" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9f0d275c70310e2a9d2fc23250c5ac826a73fa828a5f256401f85c5c554283" +dependencies = [ + "bit_field", + "bitflags 2.9.0", +] + [[package]] name = "lru" version = "0.12.5" @@ -1088,12 +1164,9 @@ dependencies = [ [[package]] name = "printf-compat" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b002af28ffe3d3d67202ae717810a28125a494d5396debc43de01ee136ac404" +source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/printf-compat?rev=5f5c9cc363#5f5c9cc363f047411a0dccb37e0efb452ffb61d9" dependencies = [ "bitflags 1.3.2", - "cstr_core", - "cty", "itertools", ] @@ -1461,15 +1534,15 @@ checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "smoltcp" -version = "0.11.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/smoltcp.git?rev=3e61c909fd540d05575068d16dc4574e196499ed#3e61c909fd540d05575068d16dc4574e196499ed" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb" dependencies = [ "bitflags 1.3.2", "byteorder 1.5.0", "cfg-if", "defmt", "heapless", - "log", "managed", ] @@ -1505,14 +1578,14 @@ dependencies = [ [[package]] name = "static-keys" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae6eb9d5e3c88a62145a3f2edd2e45c296bad8ef3e31b06d654acff70272744" +checksum = "aa784228d57f9f47a0f5837289ba92296239c2273f146d97b35bbd8538806777" dependencies = [ "clear-cache", "libc", "mach2", - "windows", + "windows 0.59.0", ] [[package]] @@ -1564,6 +1637,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -1586,6 +1665,10 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syscall_table_macros" +version = "0.1.0" + [[package]] name = "system_error" version = "0.1.0" @@ -1814,7 +1897,8 @@ dependencies = [ [[package]] name = "unwinding" version = "0.2.3" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/unwinding?rev=4eb845da62#4eb845da624f4c9899639ca116beb6d2f87e18bc" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637d511437df708cee34bdec7ba2f1548d256b7acf3ff20e0a1c559f9bf3a987" dependencies = [ "gimli 0.31.1", ] @@ -1837,7 +1921,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "virtio-drivers" version = "0.7.2" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers?rev=f91c807965#f91c8079658dbc7cc230bf041325b94a0ab2e301" +source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers?rev=415ab38ff9#415ab38ff99f3c8e150269c04f65d684ba9d1365" dependencies = [ "bitflags 2.9.0", "log", @@ -1978,23 +2062,46 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core", + "windows-core 0.58.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" +dependencies = [ + "windows-core 0.59.0", + "windows-targets 0.53.0", +] + [[package]] name = "windows-core" version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" +dependencies = [ + "windows-implement 0.59.0", + "windows-interface 0.59.1", + "windows-result 0.3.2", + "windows-strings 0.3.1", + "windows-targets 0.53.0", +] + [[package]] name = "windows-implement" version = "0.58.0" @@ -2006,6 +2113,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "windows-interface" version = "0.58.0" @@ -2017,6 +2135,23 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + [[package]] name = "windows-result" version = "0.2.0" @@ -2026,16 +2161,34 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2078,13 +2231,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -2097,6 +2266,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -2109,6 +2284,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -2121,12 +2302,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -2139,6 +2332,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -2151,6 +2350,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -2163,6 +2368,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -2175,6 +2386,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.4" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 548d1d52..d7384c5a 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -10,14 +10,10 @@ edition = "2021" crate-type = ["staticlib"] [workspace] -members = [ - "crates/*", -] +members = ["crates/*"] [features] -default = ["backtrace", "kvm", "fatfs", "fatfs-secure", "static_keys_test"] -# 内核栈回溯 -backtrace = ["dep:unwinding"] +default = ["fatfs", "kvm", "fatfs-secure", "static_keys_test"] # kvm kvm = [] @@ -51,13 +47,25 @@ klog_types = { path = "crates/klog_types" } linkme = "=0.3.27" num = { version = "=0.4.0", default-features = false } num-derive = "=0.3" -num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false } -smoltcp = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/smoltcp.git", rev = "3e61c909fd540d05575068d16dc4574e196499ed", default-features = false, features = ["log", "alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6", "medium-ip"]} +num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev = "1597c1c", default-features = false } +smoltcp = { version = "=0.12.0", default-features = false, features = [ + "alloc", + "socket-raw", + "socket-udp", + "socket-tcp", + "socket-icmp", + "socket-dhcpv4", + "socket-dns", + "proto-ipv4", + "proto-ipv6", + "medium-ip", +] } +syscall_table_macros = { path = "crates/syscall_table_macros" } system_error = { path = "crates/system_error" } uefi = { version = "=0.26.0", features = ["alloc"] } uefi-raw = "=0.5.0" unified-init = { path = "crates/unified-init" } -virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "f91c807965" } +virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "415ab38ff9" } wait_queue_macros = { path = "crates/wait_queue_macros" } paste = "=1.0.14" slabmalloc = { path = "crates/rust-slabmalloc" } @@ -66,16 +74,14 @@ kprobe = { path = "crates/kprobe" } lru = "0.12.3" rbpf = { path = "crates/rbpf" } -printf-compat = { version = "0.1.1", default-features = false } +printf-compat = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/printf-compat", rev = "5f5c9cc363", default-features = false } + +static-keys = { version = "=0.7" } -static-keys = "=0.6.1" -unwinding = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/unwinding", rev = "4eb845da62", default-features = false, optional = true, features = [ - "unwinder", - "fde-gnu-eh-frame-hdr", - "panic", - "personality" -]} defer = "0.2.1" +cfg-if = { version = "1.0.0" } +derive_builder = { version = "0.20.2", default-features = false, features = ["alloc"] } + # target为x86_64时,使用下面的依赖 [target.'cfg(target_arch = "x86_64")'.dependencies] @@ -86,9 +92,23 @@ x86_64 = "=0.14.10" # target为riscv64时,使用下面的依赖 [target.'cfg(target_arch = "riscv64")'.dependencies] -riscv = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/riscv.git", rev = "4241a97", features = [ "s-mode" ] } +riscv = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/riscv.git", rev = "4241a97", features = [ + "s-mode", +] } sbi-rt = { version = "=0.0.3", features = ["legacy"] } +# target为loongarch64时,使用下面的依赖 +[target.'cfg(target_arch = "loongarch64")'.dependencies] +loongArch64 = "=0.2.5" + +# 由于unwinding库不支持loongarch64架构,因此需要排除该依赖项 +[target.'cfg(not(target_arch = "loongarch64"))'.dependencies] +unwinding = { version = "=0.2.3", default-features = false, features = [ + "unwinder", + "fde-gnu-eh-frame-hdr", + "panic", + "personality", +] } # 构建时依赖项 [build-dependencies] @@ -102,7 +122,7 @@ features = ["spin_no_std"] # The development profile, used for `cargo build` [profile.dev] # opt-level = 0 # Controls the --opt-level the compiler builds with -debug = true # Controls whether the compiler passes `-g` +debug = true # Controls whether the compiler passes `-g` # The release profile, used for `cargo build --release` [profile.release] diff --git a/kernel/Makefile b/kernel/Makefile index c5458a00..9c71c07f 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -7,6 +7,10 @@ ifeq ($(ARCH), x86_64) export TARGET_JSON=arch/x86_64/x86_64-unknown-none.json else ifeq ($(ARCH), riscv64) export TARGET_JSON=arch/riscv64/riscv64gc-unknown-none-elf.json +else ifeq ($(ARCH), loongarch64) + export TARGET_JSON=arch/loongarch64/loongarch64-unknown-none.json +else + $(error "Unsupported ARCH: $(ARCH)") endif export CARGO_ZBUILD=-Z build-std=core,alloc,compiler_builtins -Z build-std-features=compiler-builtins-mem @@ -16,6 +20,7 @@ ECHO: @echo "$@" all: + $(MAKE) -C ../build-scripts all $(MAKE) -C src all ARCH=$(ARCH) || (sh -c "echo 内核编译失败" && exit 1) @@ -26,7 +31,7 @@ clean: fmt: RUSTFLAGS="$(RUSTFLAGS)" cargo fmt --all $(FMT_CHECK) ifeq ($(ARCH), x86_64) - RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 clippy --all-features + RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 clippy --all-features --target x86_64-unknown-none endif diff --git a/kernel/crates/asm_macros/src/lib.rs b/kernel/crates/asm_macros/src/lib.rs index acecab20..4f55d01d 100644 --- a/kernel/crates/asm_macros/src/lib.rs +++ b/kernel/crates/asm_macros/src/lib.rs @@ -5,3 +5,6 @@ pub mod x86_64; #[cfg(target_arch = "riscv64")] pub mod riscv64; + +#[cfg(target_arch = "loongarch64")] +pub mod loongarch64; diff --git a/kernel/crates/asm_macros/src/loongarch64/context.rs b/kernel/crates/asm_macros/src/loongarch64/context.rs new file mode 100644 index 00000000..10ce0ad8 --- /dev/null +++ b/kernel/crates/asm_macros/src/loongarch64/context.rs @@ -0,0 +1,280 @@ +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#48 +#[macro_export] +macro_rules! backup_t0t1 { + () => { + concat!( + " + csrwr $t0, {exception_ks0} + csrwr $t1, {exception_ks1} + " + ) + }; +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#53 +#[macro_export] +macro_rules! reload_t0t1 { + () => { + concat!( + " + csrrd $t0, {exception_ks0} + csrrd $t1, {exception_ks1} + " + ) + }; +} + +/// get_saved_sp returns the SP for the current CPU by looking in the +/// kernelsp array for it. It stores the current sp in t0 and loads the +/// new value in sp. +/// +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h?r=&mo=2487&fi=119#88 +#[macro_export] +macro_rules! get_saved_sp { + () => { + concat!( + " + la.abs $t1, KERNEL_SP + csrrd $t0, {percpu_base_ks} + add.d $t1, $t1, $t0 + + move $t0, $sp + ld.d $sp, $t1, 0 + " + ) + }; +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h?r=&mo=2487&fi=119#101 +#[macro_export] +macro_rules! set_saved_sp { + ($stackp:tt, $temp:tt) => { + concat!( + "la.pcrel ", + stringify!($temp), + ", KERNEL_SP\n", + "add.d ", + stringify!($temp), + ", ", + stringify!($temp), + ", $r21\n", + "st.d ", + stringify!($stackp), + ", ", + stringify!($temp), + ", 0\n" + ) + }; +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#109 +#[macro_export] +macro_rules! save_some { + () => { + concat!( + " + csrrd $t1, {loongarch_csr_prmd} + andi $t1, $t1, 0x3 + move $t0, $sp + beqz $t1, 3f + + ", + get_saved_sp!(), + " + 3: + addi.d $sp, $sp, -{pt_size} + + + st.d $t0, $sp, {off_usp} // 等价于 cfi_st t0, PT_R3, docfi=0 + + st.d $zero, $sp, {off_r0} + csrrd $t0, {loongarch_csr_prmd} + st.d $t0, $sp, {off_csr_prmd} + csrrd $t0, {loongarch_csr_crmd} + st.d $t0, $sp, {off_csr_crmd} + csrrd $t0, {loongarch_csr_euen} + st.d $t0, $sp, {off_csr_euen} + csrrd $t0, {loongarch_csr_ecfg} + st.d $t0, $sp, {off_csr_ecfg} + csrrd $t0, {loongarch_csr_estat} + st.d $t0, $sp, {off_csr_estat} + + st.d $ra, $sp, {off_ra} + st.d $a0, $sp, {off_a0} + st.d $a1, $sp, {off_a1} + st.d $a2, $sp, {off_a2} + st.d $a3, $sp, {off_a3} + st.d $a4, $sp, {off_a4} + st.d $a5, $sp, {off_a5} + st.d $a6, $sp, {off_a6} + st.d $a7, $sp, {off_a7} + + csrrd $ra, {loongarch_csr_era} + st.d $ra, $sp, {off_csr_era} + + st.d $tp, $sp, {off_tp} + st.d $fp, $sp, {off_fp} + + /* Set thread_info if we're coming from user mode */ + csrrd $t0, {loongarch_csr_prmd} + andi $t0, $t0, 0x3 + beqz $t0, 9f + + li.d $tp, ~{thread_mask} + and $tp, $tp, $sp + st.d $r21, $sp, {off_r21} + csrrd $r21, {percpu_base_ks} + 9: + " + ) + }; +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#197 +#[macro_export] +macro_rules! restore_some { + () => { + concat!( + " + ld.d $a0, $sp, {off_csr_prmd} + // extract pplv bit + andi $a0, $a0, 0x3 + beqz $a0, 4f + ld.d $r21, $sp, {off_r21} + + 4: + ld.d $a0, $sp, {off_csr_era} + csrwr $a0, {loongarch_csr_era} + ld.d $a0, $sp, {off_csr_prmd} + csrwr $a0, {loongarch_csr_prmd} + ld.d $ra, $sp, {off_ra} + ld.d $a0, $sp, {off_a0} + ld.d $a1, $sp, {off_a1} + ld.d $a2, $sp, {off_a2} + ld.d $a3, $sp, {off_a3} + ld.d $a4, $sp, {off_a4} + ld.d $a5, $sp, {off_a5} + ld.d $a6, $sp, {off_a6} + ld.d $a7, $sp, {off_a7} + ld.d $tp, $sp, {off_tp} + ld.d $fp, $sp, {off_fp} + " + ) + }; +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#58 +#[macro_export] +macro_rules! save_temp { + () => { + concat!( + reload_t0t1!(), + " + st.d $t0, $sp, {off_t0} + st.d $t1, $sp, {off_t1} + st.d $t2, $sp, {off_t2} + st.d $t3, $sp, {off_t3} + st.d $t4, $sp, {off_t4} + st.d $t5, $sp, {off_t5} + st.d $t6, $sp, {off_t6} + st.d $t7, $sp, {off_t7} + st.d $t8, $sp, {off_t8} + " + ) + }; +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#173 +#[macro_export] +macro_rules! restore_temp { + () => { + concat!( + reload_t0t1!(), + " + ld.d $t0, $sp, {off_t0} + ld.d $t1, $sp, {off_t1} + ld.d $t2, $sp, {off_t2} + ld.d $t3, $sp, {off_t3} + ld.d $t4, $sp, {off_t4} + ld.d $t5, $sp, {off_t5} + ld.d $t6, $sp, {off_t6} + ld.d $t7, $sp, {off_t7} + ld.d $t8, $sp, {off_t8} + " + ) + }; +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#71 +#[macro_export] +macro_rules! save_static { + () => { + concat!( + " + st.d $s0, $sp, {off_s0} + st.d $s1, $sp, {off_s1} + st.d $s2, $sp, {off_s2} + st.d $s3, $sp, {off_s3} + st.d $s4, $sp, {off_s4} + st.d $s5, $sp, {off_s5} + st.d $s6, $sp, {off_s6} + st.d $s7, $sp, {off_s7} + st.d $s8, $sp, {off_s8} + " + ) + }; +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#185 +#[macro_export] +macro_rules! restore_static { + () => { + concat!( + " + ld.d $s0, $sp, {off_s0} + ld.d $s1, $sp, {off_s1} + ld.d $s2, $sp, {off_s2} + ld.d $s3, $sp, {off_s3} + ld.d $s4, $sp, {off_s4} + ld.d $s5, $sp, {off_s5} + ld.d $s6, $sp, {off_s6} + ld.d $s7, $sp, {off_s7} + ld.d $s8, $sp, {off_s8} + " + ) + }; +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#167 +#[macro_export] +macro_rules! save_all { + () => { + concat!(save_some!(), "\n", save_temp!(), "\n", save_static!(),) + }; +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#220 +#[macro_export] +macro_rules! restore_sp_and_ret { + () => { + concat!( + " + ld.d $sp, $sp, {off_usp} + ertn + " + ) + }; +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/include/asm/stackframe.h#225 +#[macro_export] +macro_rules! restore_all_and_ret { + () => { + concat!( + restore_static!(), + restore_temp!(), + restore_some!(), + restore_sp_and_ret!() + ) + }; +} diff --git a/kernel/crates/asm_macros/src/loongarch64/mod.rs b/kernel/crates/asm_macros/src/loongarch64/mod.rs new file mode 100644 index 00000000..9efb2ab1 --- /dev/null +++ b/kernel/crates/asm_macros/src/loongarch64/mod.rs @@ -0,0 +1 @@ +pub mod context; diff --git a/kernel/crates/bitmap/src/bitmap_core.rs b/kernel/crates/bitmap/src/bitmap_core.rs index 384e3277..7ed57a41 100644 --- a/kernel/crates/bitmap/src/bitmap_core.rs +++ b/kernel/crates/bitmap/src/bitmap_core.rs @@ -7,6 +7,12 @@ pub struct BitMapCore { phantom: PhantomData, } +impl Default for BitMapCore { + fn default() -> Self { + Self::new() + } +} + impl BitMapCore { pub const fn new() -> Self { Self { diff --git a/kernel/crates/bitmap/src/lib.rs b/kernel/crates/bitmap/src/lib.rs index 27436bd8..fac2bff4 100644 --- a/kernel/crates/bitmap/src/lib.rs +++ b/kernel/crates/bitmap/src/lib.rs @@ -2,6 +2,7 @@ #![feature(core_intrinsics)] #![allow(incomplete_features)] // for const generics #![feature(generic_const_exprs)] +#![deny(clippy::all)] #![allow(internal_features)] #![allow(clippy::needless_return)] diff --git a/kernel/crates/intertrait/src/lib.rs b/kernel/crates/intertrait/src/lib.rs index 75073dfe..6130e9f3 100644 --- a/kernel/crates/intertrait/src/lib.rs +++ b/kernel/crates/intertrait/src/lib.rs @@ -124,11 +124,11 @@ static mut CASTER_MAP: Option &'static HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher> { - return unsafe { + unsafe { CASTER_MAP.as_ref().unwrap_or_else(|| { panic!("intertrait_caster_map() must be called after CASTER_MAP is initialized") }) - }; + } } /// Initializes the global [`CASTER_MAP`] with [`CASTERS`]. diff --git a/kernel/crates/kprobe/src/arch/loongarch64/mod.rs b/kernel/crates/kprobe/src/arch/loongarch64/mod.rs index 263e7cd7..e05f283d 100644 --- a/kernel/crates/kprobe/src/arch/loongarch64/mod.rs +++ b/kernel/crates/kprobe/src/arch/loongarch64/mod.rs @@ -77,6 +77,7 @@ impl KprobeBuilder { }; let inst_tmp_ptr = point.inst_tmp.as_ptr() as usize; let inst_32 = unsafe { core::ptr::read(address as *const u32) }; + unsafe { core::ptr::write(address as *mut u32, EBREAK_INST); // inst_32 :0-32 @@ -90,6 +91,7 @@ impl KprobeBuilder { self.symbol, inst_32 ); + Arc::new(point) } } diff --git a/kernel/crates/rust-slabmalloc/src/lib.rs b/kernel/crates/rust-slabmalloc/src/lib.rs index c1c84cf8..bde595e3 100644 --- a/kernel/crates/rust-slabmalloc/src/lib.rs +++ b/kernel/crates/rust-slabmalloc/src/lib.rs @@ -23,7 +23,8 @@ #![crate_name = "slabmalloc"] #![crate_type = "lib"] #![feature(maybe_uninit_as_bytes)] - +#![deny(clippy::all)] +#![allow(clippy::needless_return)] extern crate alloc; mod pages; diff --git a/kernel/crates/rust-slabmalloc/src/pages.rs b/kernel/crates/rust-slabmalloc/src/pages.rs index 872d9bf4..67e9ac6d 100644 --- a/kernel/crates/rust-slabmalloc/src/pages.rs +++ b/kernel/crates/rust-slabmalloc/src/pages.rs @@ -33,7 +33,7 @@ impl Bitfield for [AtomicU64] { fn initialize(&mut self, for_size: usize, capacity: usize) { // Set everything to allocated for bitmap in self.iter_mut() { - *bitmap = AtomicU64::new(u64::max_value()); + *bitmap = AtomicU64::new(u64::MAX); } // Mark actual slots as free @@ -56,7 +56,7 @@ impl Bitfield for [AtomicU64] { ) -> Option<(usize, usize)> { for (base_idx, b) in self.iter().enumerate() { let bitval = b.load(Ordering::Relaxed); - if bitval == u64::max_value() { + if bitval == u64::MAX { continue; } else { let negated = !bitval; @@ -117,7 +117,7 @@ impl Bitfield for [AtomicU64] { #[inline(always)] fn is_full(&self) -> bool { self.iter() - .filter(|&x| x.load(Ordering::Relaxed) != u64::max_value()) + .filter(|&x| x.load(Ordering::Relaxed) != u64::MAX) .count() == 0 } @@ -268,10 +268,10 @@ impl<'a> ObjectPage<'a> { } // These needs some more work to be really safe... -unsafe impl<'a> Send for ObjectPage<'a> {} -unsafe impl<'a> Sync for ObjectPage<'a> {} +unsafe impl Send for ObjectPage<'_> {} +unsafe impl Sync for ObjectPage<'_> {} -impl<'a> AllocablePage for ObjectPage<'a> { +impl AllocablePage for ObjectPage<'_> { const SIZE: usize = OBJECT_PAGE_SIZE; fn bitfield(&self) -> &[AtomicU64; 8] { @@ -296,7 +296,7 @@ impl<'a> Default for ObjectPage<'a> { } } -impl<'a> fmt::Debug for ObjectPage<'a> { +impl fmt::Debug for ObjectPage<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "ObjectPage") } @@ -401,6 +401,8 @@ impl<'a, T: AllocablePage> PageList<'a, T> { }); self.elements -= 1; + + #[allow(clippy::manual_inspect)] new_head.map(|node| { *node.prev() = Rawlink::none(); *node.next() = Rawlink::none(); @@ -434,6 +436,7 @@ impl<'a, P: AllocablePage + 'a> Iterator for ObjectPageIterMut<'a, P> { #[inline] fn next(&mut self) -> Option<&'a mut P> { unsafe { + #[allow(clippy::manual_inspect)] self.head.resolve_mut().map(|next| { self.head = match next.next().resolve_mut() { None => Rawlink::none(), diff --git a/kernel/crates/rust-slabmalloc/src/sc.rs b/kernel/crates/rust-slabmalloc/src/sc.rs index cdfa9881..0ece66a7 100644 --- a/kernel/crates/rust-slabmalloc/src/sc.rs +++ b/kernel/crates/rust-slabmalloc/src/sc.rs @@ -71,7 +71,7 @@ macro_rules! new_sc_allocator { SCAllocator { size: $size, allocation_count: 0, - obj_per_page: obj_per_page, + obj_per_page, empty_slabs: PageList::new(), slabs: PageList::new(), full_slabs: PageList::new(), diff --git a/kernel/crates/syscall_table_macros/Cargo.toml b/kernel/crates/syscall_table_macros/Cargo.toml new file mode 100644 index 00000000..709d3861 --- /dev/null +++ b/kernel/crates/syscall_table_macros/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "syscall_table_macros" +version = "0.1.0" +edition = "2021" + +[dependencies] + diff --git a/kernel/crates/syscall_table_macros/src/lib.rs b/kernel/crates/syscall_table_macros/src/lib.rs new file mode 100644 index 00000000..c5c42b50 --- /dev/null +++ b/kernel/crates/syscall_table_macros/src/lib.rs @@ -0,0 +1,19 @@ +#![no_std] +#![deny(clippy::all)] + +#[macro_export] +#[allow(clippy::crate_in_macro_def)] +macro_rules! declare_syscall { + ($nr:ident, $inner_handle:ident) => { + paste::paste! { + #[allow(non_upper_case_globals)] + #[link_section = ".syscall_table"] + #[used] + pub static []: crate::syscall::table::SyscallHandle = crate::syscall::table::SyscallHandle { + nr: $nr, + inner_handle: &$inner_handle, + name: stringify!($nr), + }; + } + }; +} diff --git a/kernel/env.mk b/kernel/env.mk index 871f6e7d..42a645a7 100644 --- a/kernel/env.mk +++ b/kernel/env.mk @@ -5,6 +5,10 @@ ifeq ($(ARCH), x86_64) CCPREFIX=x86_64-linux-gnu- else ifeq ($(ARCH), riscv64) CCPREFIX=riscv64-linux-gnu- +else ifeq ($(ARCH), loongarch64) +CCPREFIX=loongarch64-unknown-linux-gnu- +else +$(error "Unsupported ARCH: $(ARCH)") endif export CC=$(CCPREFIX)gcc @@ -24,6 +28,8 @@ ifeq ($(ARCH), x86_64) GLOBAL_CFLAGS += -mcmodel=large -m64 else ifeq ($(ARCH), riscv64) GLOBAL_CFLAGS += -mcmodel=medany -march=rv64gc -mabi=lp64d +else ifeq ($(ARCH), loongarch64) +GLOBAL_CFLAGS += -mcmodel=large -march=loongarch64 endif ifeq ($(DEBUG), DEBUG) @@ -31,4 +37,4 @@ GLOBAL_CFLAGS += -g endif export RUSTFLAGS := -C link-args=-znostart-stop-gc -export RUSTDOCFLAGS := -C link-args=-znostart-stop-gc \ No newline at end of file +export RUSTDOCFLAGS := -C link-args=-znostart-stop-gc diff --git a/kernel/src/Makefile b/kernel/src/Makefile index 4eb68211..b8895d68 100644 --- a/kernel/src/Makefile +++ b/kernel/src/Makefile @@ -10,17 +10,20 @@ LIB_FILES := $(foreach DIR,$(DIR_LIB),$(addprefix $(DIR)/,$(lib_patterns))) # unwind/backtrace related UNWIND_ENABLE ?= yes + +ifeq ($(ARCH), loongarch64) + UNWIND_ENABLE = no +endif + CFLAGS_UNWIND = LDFLAGS_UNWIND = RUSTFLAGS_UNWIND = ifeq ($(UNWIND_ENABLE), yes) CFLAGS_UNWIND = -funwind-tables LDFLAGS_UNWIND = --eh-frame-hdr - RUSTFLAGS_UNWIND = -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld -Cpanic=unwind + RUSTFLAGS += -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld -Cpanic=unwind endif -RUSTFLAGS += $(RUSTFLAGS_UNWIND) - CFLAGS = $(GLOBAL_CFLAGS) -fno-pie $(CFLAGS_UNWIND) -I $(shell pwd) -I $(shell pwd)/include ifeq ($(ARCH), x86_64) @@ -42,12 +45,16 @@ kernel_rust: all: kernel - + rm -f ./debug/kallsyms.o # if x86_64 ifeq ($(ARCH), x86_64) $(MAKE) __link_x86_64_kernel else ifeq ($(ARCH), riscv64) $(MAKE) __link_riscv64_kernel +else ifeq ($(ARCH), loongarch64) + $(MAKE) __link_loongarch64_kernel +else + $(error Unknown ARCH: $(ARCH)) endif @echo "Kernel Build Done." @@ -62,8 +69,8 @@ kernel: $(kernel_subdirs) kernel_rust __link_riscv64_kernel: @echo "Linking kernel..." - $(LD) -b elf64-littleriscv -z muldefs $(LDFLAGS_UNWIND) -o kernel $(shell find . -name "*.o") ../target/riscv64gc-unknown-none-elf/release/libdragonos_kernel.a -T arch/riscv64/link.ld --no-relax - # 生成kallsyms + $(LD) -b elf64-littleriscv -z muldefs $(LDFLAGS_UNWIND) -o kernel ../target/riscv64gc-unknown-none-elf/release/libdragonos_kernel.a -T arch/riscv64/link.ld --no-relax +# 生成kallsyms current_dir=$(pwd) @dbg='debug';for x in $$dbg; do \ @@ -75,7 +82,7 @@ __link_riscv64_kernel: # 重新链接 @echo "Re-Linking kernel..." @echo $(shell find . -name "*.o") - $(LD) -b elf64-littleriscv -z muldefs $(LDFLAGS_UNWIND) -o kernel $(shell find . -name "*.o") ../target/riscv64gc-unknown-none-elf/release/libdragonos_kernel.a ./debug/kallsyms.o -T arch/riscv64/link.ld --no-relax + $(LD) -b elf64-littleriscv -z muldefs $(LDFLAGS_UNWIND) -o kernel ../target/riscv64gc-unknown-none-elf/release/libdragonos_kernel.a ./debug/kallsyms.o -T arch/riscv64/link.ld --no-relax @echo "Generating kernel ELF file..." ifeq ($(UNWIND_ENABLE), yes) @@ -90,7 +97,7 @@ endif __link_x86_64_kernel: @echo "Linking kernel..." - $(LD) -b elf64-x86-64 -z muldefs $(LDFLAGS_UNWIND) -o kernel $(shell find . -name "*.o") ../target/x86_64-unknown-none/release/libdragonos_kernel.a -T arch/x86_64/link.lds --no-relax + $(LD) -b elf64-x86-64 -z muldefs $(LDFLAGS_UNWIND) -o kernel ../target/x86_64-unknown-none/release/libdragonos_kernel.a -T arch/x86_64/link.lds --no-relax # 生成kallsyms current_dir=$(pwd) @@ -103,7 +110,7 @@ __link_x86_64_kernel: # 重新链接 @echo "Re-Linking kernel..." @echo $(shell find . -name "*.o") - $(LD) -b elf64-x86-64 -z muldefs $(LDFLAGS_UNWIND) -o kernel $(shell find . -name "*.o") ../target/x86_64-unknown-none/release/libdragonos_kernel.a ./debug/kallsyms.o -T arch/x86_64/link.lds --no-relax + $(LD) -b elf64-x86-64 -z muldefs $(LDFLAGS_UNWIND) -o kernel ../target/x86_64-unknown-none/release/libdragonos_kernel.a ./debug/kallsyms.o -T arch/x86_64/link.lds --no-relax @echo "Generating kernel ELF file..." # 生成内核文件 ifeq ($(UNWIND_ENABLE), yes) @@ -113,6 +120,32 @@ else endif rm kernel + +__link_loongarch64_kernel: + @echo "Linking kernel..." + $(LD) -b elf64-loongarch -z muldefs $(LDFLAGS_UNWIND) -o kernel $(shell find . -name "*.o") ../target/loongarch64-unknown-none/release/libdragonos_kernel.a -T arch/loongarch64/link.ld --no-relax +# 生成kallsyms + current_dir=$(pwd) + + @dbg='debug';for x in $$dbg; do \ + cd $$x;\ + $(MAKE) generate_kallsyms kernel_root_path="$(shell pwd)"||exit 1;\ + cd ..;\ + done + +# 重新链接 + @echo "Re-Linking kernel..." + @echo $(shell find . -name "*.o") + $(LD) -b elf64-loongarch -z muldefs $(LDFLAGS_UNWIND) -o kernel $(shell find . -name "*.o") ../target/loongarch64-unknown-none/release/libdragonos_kernel.a ./debug/kallsyms.o -T arch/loongarch64/link.ld --no-relax + @echo "Generating kernel ELF file..." +# 生成内核文件 +ifeq ($(UNWIND_ENABLE), yes) + $(OBJCOPY) -I elf64-loongarch -O elf64-loongarch kernel ../../bin/kernel/kernel.elf +else + $(OBJCOPY) -I elf64-loongarch -O elf64-loongarch -R ".eh_frame" kernel ../../bin/kernel/kernel.elf +endif + rm kernel + __dragon_stub: @echo "Linking dragon_stub..." @mkdir -p $(ROOT_PATH)/bin/sysroot diff --git a/kernel/src/arch/arch.h b/kernel/src/arch/arch.h deleted file mode 100644 index e5257f29..00000000 --- a/kernel/src/arch/arch.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#define ARCH(arch) (defined(AK_ARCH_##arch) && AK_ARCH_##arch) - - -#ifdef __i386__ -# define AK_ARCH_I386 1 -#endif - -#ifdef __x86_64__ -# define AK_ARCH_X86_64 1 -#endif - -#ifdef __riscv -# define AK_ARCH_riscv 1 -#endif - -#ifdef __riscv64 -# define AK_ARCH_riscv64 1 -#endif \ No newline at end of file diff --git a/kernel/src/arch/loongarch64/asm/bitops.rs b/kernel/src/arch/loongarch64/asm/bitops.rs new file mode 100644 index 00000000..d5d570cd --- /dev/null +++ b/kernel/src/arch/loongarch64/asm/bitops.rs @@ -0,0 +1,14 @@ +/// 寻找u64中的第一个0所在的位(从第0位开始寻找) +/// +/// 注意:如果x中没有0,那么结果将是未定义的。请确保传入的x至少存在1个0 +/// +/// # 参数 +/// * `x` - 目标u64 +/// +/// # 返回值 +/// 第一个(最低有效位)0位的位号(0..63) +#[inline] +#[allow(dead_code)] +pub fn ffz(x: u64) -> i32 { + (!x).trailing_zeros() as i32 +} diff --git a/kernel/src/arch/loongarch64/asm/boot.rs b/kernel/src/arch/loongarch64/asm/boot.rs new file mode 100644 index 00000000..f781bd0f --- /dev/null +++ b/kernel/src/arch/loongarch64/asm/boot.rs @@ -0,0 +1,98 @@ +/// +/// The earliest entry point for the primary CPU. +/// +/// 这些代码拷贝、修改自 polyhal (https://github.com/Byte-OS/polyhal.git) +use crate::arch::{cpu::current_cpu_id, init::boot::kernel_main}; + +const QEMU_DTB_PADDR: usize = 0x100000; + +/// The earliest entry point for the primary CPU. +/// +/// We can't use bl to jump to higher address, so we use jirl to jump to higher address. +#[naked] +#[no_mangle] +#[link_section = ".text.entry"] +unsafe extern "C" fn _start() -> ! { + core::arch::naked_asm!(" + + ori $t0, $zero, 0x1 # CSR_DMW1_PLV0 + lu52i.d $t0, $t0, -2048 # UC, PLV0, 0x8000 xxxx xxxx xxxx + csrwr $t0, 0x180 # LOONGARCH_CSR_DMWIN0 + ori $t0, $zero, 0x11 # CSR_DMW1_MAT | CSR_DMW1_PLV0 + lu52i.d $t0, $t0, -1792 # CA, PLV0, 0x9000 xxxx xxxx xxxx + csrwr $t0, 0x181 # LOONGARCH_CSR_DMWIN1 + + # Goto 1 if hart is not 0 + csrrd $t1, 0x20 # read cpu from csr + bnez $t1, 1f + + # Enable PG + li.w $t0, 0xb0 # PLV=0, IE=0, PG=1 + csrwr $t0, 0x0 # LOONGARCH_CSR_CRMD + li.w $t0, 0x00 # PLV=0, PIE=0, PWE=0 + csrwr $t0, 0x1 # LOONGARCH_CSR_PRMD + li.w $t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0 + csrwr $t0, 0x2 # LOONGARCH_CSR_EUEN + + + la.global $sp, {boot_stack} + li.d $t0, {boot_stack_size} + add.d $sp, $sp, $t0 # setup boot stack + csrrd $a0, 0x20 # cpuid + la.global $t0, {entry} + jirl $zero,$t0,0 + 1: + li.w $s0, {MBUF0} + iocsrrd.d $t0, $s0 + la.global $t1, {sec_entry} + bne $t0, $t1, 1b + jirl $zero, $t1, 0 + ", + boot_stack_size = const size_of_val(&crate::arch::process::BSP_IDLE_STACK_SPACE), + boot_stack = sym crate::arch::process::BSP_IDLE_STACK_SPACE, + MBUF0 = const loongArch64::consts::LOONGARCH_CSR_MAIL_BUF0, + entry = sym rust_tmp_main, + sec_entry = sym _start_secondary, + ) +} + +/// The earliest entry point for the primary CPU. +/// +/// We can't use bl to jump to higher address, so we use jirl to jump to higher address. +#[naked] +#[no_mangle] +#[link_section = ".text.entry"] +pub(crate) unsafe extern "C" fn _start_secondary() -> ! { + core::arch::naked_asm!( + " + ori $t0, $zero, 0x1 # CSR_DMW1_PLV0 + lu52i.d $t0, $t0, -2048 # UC, PLV0, 0x8000 xxxx xxxx xxxx + csrwr $t0, 0x180 # LOONGARCH_CSR_DMWIN0 + ori $t0, $zero, 0x11 # CSR_DMW1_MAT | CSR_DMW1_PLV0 + lu52i.d $t0, $t0, -1792 # CA, PLV0, 0x9000 xxxx xxxx xxxx + csrwr $t0, 0x181 # LOONGARCH_CSR_DMWIN1 + + li.w $t0, {MBUF1} + iocsrrd.d $sp, $t0 + + csrrd $a0, 0x20 # cpuid + la.global $t0, {entry} + + jirl $zero,$t0,0 + ", + MBUF1 = const loongArch64::consts::LOONGARCH_CSR_MAIL_BUF1, + entry = sym _rust_secondary_main, + ) +} + +/// Rust temporary entry point +/// +/// This function will be called after assembly boot stage. +fn rust_tmp_main(hart_id: usize) { + unsafe { kernel_main(hart_id, QEMU_DTB_PADDR) }; +} + +/// The entry point for the second core. +pub(crate) extern "C" fn _rust_secondary_main() { + unsafe { kernel_main(current_cpu_id().data() as usize, QEMU_DTB_PADDR) } +} diff --git a/kernel/src/arch/loongarch64/asm/mod.rs b/kernel/src/arch/loongarch64/asm/mod.rs new file mode 100644 index 00000000..8769d0da --- /dev/null +++ b/kernel/src/arch/loongarch64/asm/mod.rs @@ -0,0 +1,44 @@ +use crate::process::KernelStack; + +pub mod bitops; +pub mod boot; + +/* KSave registers */ +pub const LOONGARCH_CSR_KS0: usize = 0x30; +pub const LOONGARCH_CSR_KS1: usize = 0x31; +pub const LOONGARCH_CSR_KS2: usize = 0x32; +pub const LOONGARCH_CSR_KS3: usize = 0x33; +pub const LOONGARCH_CSR_KS4: usize = 0x34; +pub const LOONGARCH_CSR_KS5: usize = 0x35; +pub const LOONGARCH_CSR_KS6: usize = 0x36; +pub const LOONGARCH_CSR_KS7: usize = 0x37; +pub const LOONGARCH_CSR_KS8: usize = 0x38; + +/// Current mode info +pub const LOONGARCH_CSR_CRMD: usize = 0x0; +/// Prev-exception mode info +pub const LOONGARCH_CSR_PRMD: usize = 0x1; + +/// Extended unit enable +pub const LOONGARCH_CSR_EUEN: usize = 0x2; + +/// Exception config +pub const LOONGARCH_CSR_ECFG: usize = 0x4; +/// Exception status +pub const LOONGARCH_CSR_ESTAT: usize = 0x5; + +/// Exception return address. +pub const LOONGARCH_CSR_ERA: usize = 0x6; + +/// Bad virtual address. +pub const LOONGARCH_CSR_BADV: usize = 0x7; + +/* Exception allocated KS0, KS1 and KS2 statically */ +pub const EXCEPTION_KS0: usize = LOONGARCH_CSR_KS0; +pub const EXCEPTION_KS1: usize = LOONGARCH_CSR_KS1; + +/* Percpu-data base allocated KS3 statically */ +pub const PERCPU_BASE_KS: usize = LOONGARCH_CSR_KS3; +pub const PERCPU_KSAVE_MASK: usize = 1 << 3; + +pub const _THREAD_MASK: usize = KernelStack::SIZE - 1; diff --git a/kernel/src/arch/loongarch64/cpu.rs b/kernel/src/arch/loongarch64/cpu.rs new file mode 100644 index 00000000..62d82937 --- /dev/null +++ b/kernel/src/arch/loongarch64/cpu.rs @@ -0,0 +1,18 @@ +use crate::{mm::percpu::PerCpu, smp::cpu::ProcessorId}; + +/// 重置cpu +pub unsafe fn cpu_reset() -> ! { + log::warn!("cpu_reset on loongarch64 platform was not implemented!"); + loop { + unsafe { loongArch64::asm::idle() }; + } +} + +/// 获取当前cpu的id +#[inline] +pub fn current_cpu_id() -> ProcessorId { + ProcessorId::new(loongArch64::register::cpuid::read().core_id() as u32) +} + +#[no_mangle] +pub static mut KERNEL_SP: [usize; PerCpu::MAX_CPU_NUM as usize] = [0; PerCpu::MAX_CPU_NUM as usize]; diff --git a/kernel/src/arch/loongarch64/elf.rs b/kernel/src/arch/loongarch64/elf.rs new file mode 100644 index 00000000..c3b6a57d --- /dev/null +++ b/kernel/src/arch/loongarch64/elf.rs @@ -0,0 +1,10 @@ +use crate::{arch::MMArch, libs::elf::ElfArch, mm::MemoryManagementArch}; + +#[derive(Debug, Clone, Copy, Hash)] +pub struct LoongArch64ElfArch; + +impl ElfArch for LoongArch64ElfArch { + const ELF_ET_DYN_BASE: usize = MMArch::USER_END_VADDR.data() / 3 * 2; + + const ELF_PAGE_SIZE: usize = MMArch::PAGE_SIZE; +} diff --git a/kernel/src/arch/loongarch64/filesystem/mod.rs b/kernel/src/arch/loongarch64/filesystem/mod.rs new file mode 100644 index 00000000..4f22af63 --- /dev/null +++ b/kernel/src/arch/loongarch64/filesystem/mod.rs @@ -0,0 +1 @@ +pub mod stat; diff --git a/kernel/src/arch/loongarch64/filesystem/stat.rs b/kernel/src/arch/loongarch64/filesystem/stat.rs new file mode 100644 index 00000000..6402d6ff --- /dev/null +++ b/kernel/src/arch/loongarch64/filesystem/stat.rs @@ -0,0 +1 @@ +pub use crate::filesystem::vfs::stat::GenericPosixStat as PosixStat; diff --git a/kernel/src/arch/loongarch64/include/asm/asm.h b/kernel/src/arch/loongarch64/include/asm/asm.h new file mode 100644 index 00000000..6f70f09b --- /dev/null +++ b/kernel/src/arch/loongarch64/include/asm/asm.h @@ -0,0 +1 @@ +#pragma once diff --git a/kernel/src/arch/loongarch64/init/boot.rs b/kernel/src/arch/loongarch64/init/boot.rs new file mode 100644 index 00000000..2a18f0f7 --- /dev/null +++ b/kernel/src/arch/loongarch64/init/boot.rs @@ -0,0 +1,57 @@ +use loongArch64::register::{ecfg, eentry}; + +use crate::{arch::interrupt::entry::handle_reserved_, init::init::start_kernel, mm::PhysAddr}; + +static mut BOOT_HARTID: u32 = 0; +static mut BOOT_FDT_PADDR: PhysAddr = PhysAddr::new(0); + +#[no_mangle] +pub unsafe extern "C" fn kernel_main(hartid: usize, fdt_paddr: usize) -> ! { + clear_bss(); + + let fdt_paddr = PhysAddr::new(fdt_paddr); + + unsafe { + BOOT_HARTID = hartid as u32; + BOOT_FDT_PADDR = fdt_paddr; + } + boot_tmp_setup_trap_vector(); + + start_kernel(); +} + +/// 临时设置中断、异常处理函数 +/// +/// 后续需要通过 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#1085 +/// 这里的这个函数来重新设置中断、异常处理函数 +fn boot_tmp_setup_trap_vector() { + let ptr = handle_reserved_ as *const () as usize; + ecfg::set_vs(0); + eentry::set_eentry(ptr); +} + +/// Clear the bss section +fn clear_bss() { + extern "C" { + fn _bss(); + fn _ebss(); + } + unsafe { + let bss_start = _bss as *mut u8; + let bss_end = _ebss as *mut u8; + let bss_size = bss_end as usize - bss_start as usize; + + // Clear in chunks of u128 for efficiency + let u128_count = bss_size / core::mem::size_of::(); + let u128_slice = core::slice::from_raw_parts_mut(bss_start as *mut u128, u128_count); + u128_slice.fill(0); + + // Clear any remaining bytes + let remaining_bytes = bss_size % core::mem::size_of::(); + if remaining_bytes > 0 { + let remaining_start = bss_start.add(u128_count * core::mem::size_of::()); + let remaining_slice = core::slice::from_raw_parts_mut(remaining_start, remaining_bytes); + remaining_slice.fill(0); + } + } +} diff --git a/kernel/src/arch/loongarch64/init/mod.rs b/kernel/src/arch/loongarch64/init/mod.rs new file mode 100644 index 00000000..0bbd5275 --- /dev/null +++ b/kernel/src/arch/loongarch64/init/mod.rs @@ -0,0 +1,28 @@ +use system_error::SystemError; + +use crate::driver::serial::serial8250::send_to_default_serial8250_port; +pub mod boot; + +#[derive(Debug)] +pub struct ArchBootParams {} + +impl ArchBootParams { + pub const DEFAULT: Self = ArchBootParams {}; +} + +#[inline(never)] +pub fn early_setup_arch() -> Result<(), SystemError> { + send_to_default_serial8250_port(b"la64:early_setup_arch"); + loop {} + todo!("la64:early_setup_arch"); +} + +#[inline(never)] +pub fn setup_arch() -> Result<(), SystemError> { + todo!("la64:setup_arch"); +} + +#[inline(never)] +pub fn setup_arch_post() -> Result<(), SystemError> { + todo!("la64:setup_arch_post"); +} diff --git a/kernel/src/arch/loongarch64/interrupt/entry.rs b/kernel/src/arch/loongarch64/interrupt/entry.rs new file mode 100644 index 00000000..439e90be --- /dev/null +++ b/kernel/src/arch/loongarch64/interrupt/entry.rs @@ -0,0 +1,132 @@ +use asm_macros::*; +use kdepends::memoffset::offset_of; + +use crate::arch::{asm::*, interrupt::TrapFrame}; + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/genex.S#55 +macro_rules! build_prep_badv_ { + () => { + concat!( + " + csrrd $t0, {loongarch_csr_badv} + st.d $t0, $sp, {off_csr_badvaddr} + " + ) + }; +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/genex.S#60 +macro_rules! build_prep_fcsr_ { + () => { + concat!( + " + movfcsr2gr $a1, $fcsr0 + " + ) + }; +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/genex.S#64 +macro_rules! build_prep_none_ { + () => { + "" + }; +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/genex.S#67 +macro_rules! build_handler { + ($exception:expr, $handler:expr, $prep:ident) => { + paste::paste! { + /// handle exception的实现请参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/genex.S#69 + #[naked] + #[no_mangle] + #[repr(align(8))] + pub unsafe extern "C" fn []() -> ! { + core::arch::naked_asm!(concat!( + backup_t0t1!(), + save_all!(), + []!(), + " + move $a0, $sp + la.abs $t0, ", stringify!([]), + " + jirl $ra, $t0, 0 + ", + restore_all_and_ret!(), + " + // 以下是为了编译器不报错说变量未使用,才保留的代码 + /* {off_csr_badvaddr} */ + /* {loongarch_csr_badv} */ + " + ), + exception_ks0 = const EXCEPTION_KS0, + exception_ks1 = const EXCEPTION_KS1, + loongarch_csr_prmd = const LOONGARCH_CSR_PRMD, + loongarch_csr_crmd = const LOONGARCH_CSR_CRMD, + loongarch_csr_euen = const LOONGARCH_CSR_EUEN, + loongarch_csr_ecfg = const LOONGARCH_CSR_ECFG, + loongarch_csr_estat = const LOONGARCH_CSR_ESTAT, + loongarch_csr_era = const LOONGARCH_CSR_ERA, + loongarch_csr_badv = const LOONGARCH_CSR_BADV, + percpu_base_ks = const PERCPU_BASE_KS, + thread_mask = const _THREAD_MASK, + pt_size = const core::mem::size_of::(), + off_r0 = const offset_of!(TrapFrame, r0), + off_ra = const offset_of!(TrapFrame, ra), + off_tp = const offset_of!(TrapFrame, tp), + off_usp = const offset_of!(TrapFrame, usp), + off_a0 = const offset_of!(TrapFrame, a0), + off_a1 = const offset_of!(TrapFrame, a1), + off_a2 = const offset_of!(TrapFrame, a2), + off_a3 = const offset_of!(TrapFrame, a3), + off_a4 = const offset_of!(TrapFrame, a4), + off_a5 = const offset_of!(TrapFrame, a5), + off_a6 = const offset_of!(TrapFrame, a6), + off_a7 = const offset_of!(TrapFrame, a7), + off_t0 = const offset_of!(TrapFrame, t0), + off_t1 = const offset_of!(TrapFrame, t1), + off_t2 = const offset_of!(TrapFrame, t2), + off_t3 = const offset_of!(TrapFrame, t3), + off_t4 = const offset_of!(TrapFrame, t4), + off_t5 = const offset_of!(TrapFrame, t5), + off_t6 = const offset_of!(TrapFrame, t6), + off_t7 = const offset_of!(TrapFrame, t7), + off_t8 = const offset_of!(TrapFrame, t8), + off_r21 = const offset_of!(TrapFrame, r21), + off_fp = const offset_of!(TrapFrame, fp), + off_s0 = const offset_of!(TrapFrame, s0), + off_s1 = const offset_of!(TrapFrame, s1), + off_s2 = const offset_of!(TrapFrame, s2), + off_s3 = const offset_of!(TrapFrame, s3), + off_s4 = const offset_of!(TrapFrame, s4), + off_s5 = const offset_of!(TrapFrame, s5), + off_s6 = const offset_of!(TrapFrame, s6), + off_s7 = const offset_of!(TrapFrame, s7), + off_s8 = const offset_of!(TrapFrame, s8), + // off_orig_a0 = const offset_of!(TrapFrame, orig_a0), + off_csr_era = const offset_of!(TrapFrame, csr_era), + off_csr_badvaddr = const offset_of!(TrapFrame, csr_badvaddr), + off_csr_crmd = const offset_of!(TrapFrame, csr_crmd), + off_csr_prmd = const offset_of!(TrapFrame, csr_prmd), + off_csr_euen = const offset_of!(TrapFrame, csr_euen), + off_csr_ecfg = const offset_of!(TrapFrame, csr_ecfg), + off_csr_estat = const offset_of!(TrapFrame, csr_estat), + ) + } + + } + }; +} + +build_handler!(ade, ade, badv); +build_handler!(ale, ale, badv); +build_handler!(bce, bce, none); +build_handler!(bp, bp, none); +build_handler!(fpe, fpe, fcsr); +build_handler!(fpu, fpu, none); +build_handler!(lsx, lsx, none); +build_handler!(lasx, lasx, none); +build_handler!(lbt, lbt, none); +build_handler!(ri, ri, none); +build_handler!(watch, watch, none); +build_handler!(reserved, reserved, none); /* others */ diff --git a/kernel/src/arch/loongarch64/interrupt/handle.rs b/kernel/src/arch/loongarch64/interrupt/handle.rs new file mode 100644 index 00000000..f676d461 --- /dev/null +++ b/kernel/src/arch/loongarch64/interrupt/handle.rs @@ -0,0 +1,87 @@ +use crate::driver::serial::serial8250::send_to_default_serial8250_port; + +use super::TrapFrame; + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#508 +#[no_mangle] +unsafe extern "C" fn do_ade_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_ade_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#522 +#[no_mangle] +unsafe extern "C" fn do_ale_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_ale_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#583 +#[no_mangle] +unsafe extern "C" fn do_bce_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_bce_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#672 +#[no_mangle] +unsafe extern "C" fn do_bp_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_bp_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#481 +#[no_mangle] +unsafe extern "C" fn do_fpe_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_fpe_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#904 +#[no_mangle] +unsafe extern "C" fn do_fpu_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_fpu_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#921 +#[no_mangle] +unsafe extern "C" fn do_lsx_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_lsx_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#943 +#[no_mangle] +unsafe extern "C" fn do_lasx_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_lasx_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#978 +#[no_mangle] +unsafe extern "C" fn do_lbt_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_lbt_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#809 +#[no_mangle] +unsafe extern "C" fn do_ri_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_ri_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#756 +#[no_mangle] +unsafe extern "C" fn do_watch_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_watch_()\n"); + loop {} +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/loongarch/kernel/traps.c#1009 +#[no_mangle] +unsafe extern "C" fn do_reserved_(frame: *mut TrapFrame) { + send_to_default_serial8250_port(b"la64: do_reserved_()\n"); + // loop {} +} diff --git a/kernel/src/arch/loongarch64/interrupt/ipi.rs b/kernel/src/arch/loongarch64/interrupt/ipi.rs new file mode 100644 index 00000000..93ed5787 --- /dev/null +++ b/kernel/src/arch/loongarch64/interrupt/ipi.rs @@ -0,0 +1,6 @@ +use crate::exception::ipi::{IpiKind, IpiTarget}; + +#[inline(always)] +pub fn send_ipi(kind: IpiKind, target: IpiTarget) { + todo!("la64: send_ipi") +} diff --git a/kernel/src/arch/loongarch64/interrupt/mod.rs b/kernel/src/arch/loongarch64/interrupt/mod.rs new file mode 100644 index 00000000..bcc95286 --- /dev/null +++ b/kernel/src/arch/loongarch64/interrupt/mod.rs @@ -0,0 +1,125 @@ +pub mod entry; +mod handle; +pub mod ipi; + +use core::any::Any; + +use kprobe::ProbeArgs; +use loongArch64::register::CpuMode; + +use crate::exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber}; + +pub struct LoongArch64InterruptArch; + +impl InterruptArch for LoongArch64InterruptArch { + unsafe fn arch_irq_init() -> Result<(), system_error::SystemError> { + todo!("arch_irq_init() not implemented for LoongArch64InterruptArch") + } + + unsafe fn interrupt_enable() { + loongArch64::register::crmd::set_ie(true); + } + + unsafe fn interrupt_disable() { + loongArch64::register::crmd::set_ie(false); + } + + fn is_irq_enabled() -> bool { + loongArch64::register::crmd::read().ie() + } + + unsafe fn save_and_disable_irq() -> IrqFlagsGuard { + let ie = loongArch64::register::crmd::read().ie(); + loongArch64::register::crmd::set_ie(false); + IrqFlagsGuard::new(IrqFlags::new(if ie { 1 } else { 0 })) + } + + unsafe fn restore_irq(flags: IrqFlags) { + loongArch64::register::crmd::set_ie(flags.flags() == 1); + } + + fn probe_total_irq_num() -> u32 { + todo!("probe_total_irq_num() not implemented for LoongArch64InterruptArch") + } + + fn ack_bad_irq(irq: IrqNumber) { + todo!("ack_bad_irq() not implemented for LoongArch64InterruptArch") + } +} + +/// 中断栈帧结构体 +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TrapFrame { + pub r0: usize, // 0*8 + pub ra: usize, // 1*8 + pub tp: usize, // 2*8 + pub usp: usize, // 3*8 (user stack pointer) + pub a0: usize, // 4*8 + pub a1: usize, // 5*8 + pub a2: usize, // 6*8 + pub a3: usize, // 7*8 + pub a4: usize, // 8*8 + pub a5: usize, // 9*8 + pub a6: usize, // 10*8 + pub a7: usize, // 11*8 + pub t0: usize, // 12*8 + pub t1: usize, // 13*8 + pub t2: usize, // 14*8 + pub t3: usize, // 15*8 + pub t4: usize, // 16*8 + pub t5: usize, // 17*8 + pub t6: usize, // 18*8 + pub t7: usize, // 19*8 + pub t8: usize, // 20*8 + pub r21: usize, // 21*8 + pub fp: usize, // 22*8 + pub s0: usize, // 23*8 + pub s1: usize, // 24*8 + pub s2: usize, // 25*8 + pub s3: usize, // 26*8 + pub s4: usize, // 27*8 + pub s5: usize, // 28*8 + pub s6: usize, // 29*8 + pub s7: usize, // 30*8 + pub s8: usize, // 31*8 + /// original syscall arg0 + pub orig_a0: usize, + + pub csr_era: usize, + pub csr_badvaddr: usize, + pub csr_crmd: usize, + pub csr_prmd: usize, + pub csr_euen: usize, + pub csr_ecfg: usize, + pub csr_estat: usize, +} + +impl TrapFrame { + /// 中断栈帧结构体的大小 + pub const SIZE: usize = core::mem::size_of::(); + + /// 判断当前中断是否来自用户模式 + pub fn is_from_user(&self) -> bool { + loongArch64::register::crmd::Crmd::from(self.csr_crmd).plv() == CpuMode::Ring3 + } + + #[inline(never)] + pub const fn new() -> Self { + let x = core::mem::MaybeUninit::::zeroed(); + unsafe { x.assume_init() } + } +} + +impl ProbeArgs for TrapFrame { + fn as_any(&self) -> &dyn Any { + self + } + fn break_address(&self) -> usize { + todo!("TrapFrame::break_address()") + } + + fn debug_address(&self) -> usize { + todo!("TrapFrame::debug_address()") + } +} diff --git a/kernel/src/arch/loongarch64/ipc/mod.rs b/kernel/src/arch/loongarch64/ipc/mod.rs new file mode 100644 index 00000000..a3c1b22f --- /dev/null +++ b/kernel/src/arch/loongarch64/ipc/mod.rs @@ -0,0 +1 @@ +pub mod signal; diff --git a/kernel/src/arch/loongarch64/ipc/signal.rs b/kernel/src/arch/loongarch64/ipc/signal.rs new file mode 100644 index 00000000..9ebb34db --- /dev/null +++ b/kernel/src/arch/loongarch64/ipc/signal.rs @@ -0,0 +1,64 @@ +use crate::arch::interrupt::TrapFrame; +pub use crate::ipc::generic_signal::AtomicGenericSignal as AtomicSignal; +pub use crate::ipc::generic_signal::GenericSigChildCode as SigChildCode; +pub use crate::ipc::generic_signal::GenericSigSet as SigSet; +pub use crate::ipc::generic_signal::GenericSignal as Signal; +pub use crate::ipc::generic_signal::GENERIC_MAX_SIG_NUM as MAX_SIG_NUM; +pub use crate::ipc::generic_signal::GENERIC_STACK_ALIGN as STACK_ALIGN; + +pub use crate::ipc::generic_signal::GenericSigFlags as SigFlags; + +use crate::ipc::signal_types::SignalArch; + +pub struct LoongArch64SignalArch; + +impl SignalArch for LoongArch64SignalArch { + // TODO: 为LoongArch64实现信号处理 + // 注意,la64现在在中断/系统调用返回用户态时,没有进入 irqentry_exit() 函数, + // 到时候实现信号处理时,需要修改中断/系统调用返回用户态的代码,进入 irqentry_exit() 函数 + unsafe fn do_signal_or_restart(_frame: &mut TrapFrame) { + todo!("la64:do_signal_or_restart") + } + + fn sys_rt_sigreturn(_trap_frame: &mut TrapFrame) -> u64 { + todo!("la64:sys_rt_sigreturn") + } +} + +/// siginfo中的si_code的可选值 +/// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态 +#[derive(Copy, Debug, Clone)] +#[repr(i32)] +pub enum SigCode { + /// sent by kill, sigsend, raise + User = 0, + /// sent by kernel from somewhere + Kernel = 0x80, + /// 通过sigqueue发送 + Queue = -1, + /// 定时器过期时发送 + Timer = -2, + /// 当实时消息队列的状态发生改变时发送 + Mesgq = -3, + /// 当异步IO完成时发送 + AsyncIO = -4, + /// sent by queued SIGIO + SigIO = -5, +} + +impl SigCode { + /// 为SigCode这个枚举类型实现从i32转换到枚举类型的转换函数 + #[allow(dead_code)] + pub fn from_i32(x: i32) -> SigCode { + match x { + 0 => Self::User, + 0x80 => Self::Kernel, + -1 => Self::Queue, + -2 => Self::Timer, + -3 => Self::Mesgq, + -4 => Self::AsyncIO, + -5 => Self::SigIO, + _ => panic!("signal code not valid"), + } + } +} diff --git a/kernel/src/arch/loongarch64/kprobe.rs b/kernel/src/arch/loongarch64/kprobe.rs new file mode 100644 index 00000000..1d85e6d9 --- /dev/null +++ b/kernel/src/arch/loongarch64/kprobe.rs @@ -0,0 +1,19 @@ +use crate::arch::interrupt::TrapFrame; + +pub fn setup_single_step(frame: &mut TrapFrame, step_addr: usize) { + todo!("la64: setup_single_step") +} + +pub fn clear_single_step(frame: &mut TrapFrame, return_addr: usize) { + todo!("la64: clear_single_step") +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct KProbeContext {} + +impl From<&TrapFrame> for KProbeContext { + fn from(trap_frame: &TrapFrame) -> Self { + todo!("from trap frame to kprobe context"); + } +} diff --git a/kernel/src/arch/loongarch64/link.ld b/kernel/src/arch/loongarch64/link.ld new file mode 100644 index 00000000..be30520b --- /dev/null +++ b/kernel/src/arch/loongarch64/link.ld @@ -0,0 +1,123 @@ +OUTPUT_FORMAT( + "elf64-loongarch", + "elf64-loongarch", + "elf64-loongarch" +) + +OUTPUT_ARCH(loongarch) +ENTRY(_start) + + +SECTIONS +{ + KERNEL_VMA = 0x9000000000200000; + . = KERNEL_VMA; + . = ALIGN(4096); + boot_text_start_pa = .; + .boot.text : + { + KEEP(*(.bootstrap)) + *(.bootstrap) + *(.bootstrap.*) + . = ALIGN(4096); + *(.initial_pgtable_section) + } + + + . = ALIGN(4096); + text_start_pa = .; + __executable_start = .; + .text (text_start_pa): + { + _text = .; + + /* any files' .text */ + *(.text) + + /* any files' .text.*, for example: rust .text._ZN* */ + *(.text.*) + + _etext = .; + __etext = .; + } + . = ALIGN(32768); + data_start_pa = .; + .data (data_start_pa): + { + _data = .; + *(.data) + *(.data.*) + *(.got.plt) + *(.got) + _edata = .; + } + + . = ALIGN(32768); + + rodata_start_pa = .; + .rodata (rodata_start_pa): + { + _rodata = .; + *(.rodata) + *(.rodata.*) + *(.gcc_except_table .gcc_except_table.*) + _erodata = .; + } + + . = ALIGN(32768); + + trace_point_start_pa = .; + .tracepoint (trace_point_start_pa): + { + _tracepoint = .; + *(.tracepoint) + *(.tracepoint.*) + _etracepoint = .; + } + + . = ALIGN(4096); + syscall_table_start_pa = .; + .syscall_table (syscall_table_start_pa): + { + _syscall_table = .; + *(.syscall_table) + *(.syscall_table.*) + _esyscall_table = .; + } + + . = ALIGN(32768); + init_proc_union_start_pa = .; + .data.init_proc_union (init_proc_union_start_pa): + { *(.data.init_proc_union) } + + . = ALIGN(32768); + bss_start_pa = .; + .bss (bss_start_pa): + { + _bss = .; + *(.bss) + *(.bss.*) + *(.sbss) + *(.sbss.*) + _ebss = .; + } + + eh_frame = .; + .eh_frame (eh_frame): + { + __eh_frame_hdr_start = .; + *(.eh_frame_hdr) + __eh_frame_hdr_end = .; + __eh_frame_start = .; + *(.eh_frame) + *(.rela.eh_frame) + __eh_frame_end = .; + } + + _end = .; + + /DISCARD/ : { + /* *(.eh_frame) */ + + } +} diff --git a/kernel/src/arch/loongarch64/loongarch64-unknown-none.json b/kernel/src/arch/loongarch64/loongarch64-unknown-none.json new file mode 100644 index 00000000..56407679 --- /dev/null +++ b/kernel/src/arch/loongarch64/loongarch64-unknown-none.json @@ -0,0 +1,21 @@ +{ + "arch": "loongarch64", + "code-model": "medium", + "crt-objects-fallback": "false", + "data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + "features": "+f,+d", + "linker": "rust-lld", + "linker-flavor": "gnu-lld", + "llvm-abiname": "lp64d", + "llvm-target": "loongarch64-unknown-none", + "max-atomic-width": 64, + "metadata": { + "description": "Freestanding/bare-metal LoongArch64", + "host_tools": false, + "std": false, + "tier": 2 + }, + "panic-strategy": "abort", + "relocation-model": "static", + "target-pointer-width": "64" +} \ No newline at end of file diff --git a/kernel/src/arch/loongarch64/mm/bump.rs b/kernel/src/arch/loongarch64/mm/bump.rs new file mode 100644 index 00000000..47cc861e --- /dev/null +++ b/kernel/src/arch/loongarch64/mm/bump.rs @@ -0,0 +1,7 @@ +use crate::mm::{allocator::bump::BumpAllocator, MemoryManagementArch, PhysMemoryArea}; + +impl BumpAllocator { + pub unsafe fn arch_remain_areas(_ret_areas: &mut [PhysMemoryArea], res_count: usize) -> usize { + todo!("la64: arch_remain_areas") + } +} diff --git a/kernel/src/arch/loongarch64/mm/mod.rs b/kernel/src/arch/loongarch64/mm/mod.rs new file mode 100644 index 00000000..48b687ea --- /dev/null +++ b/kernel/src/arch/loongarch64/mm/mod.rs @@ -0,0 +1,207 @@ +pub mod bump; + +use crate::mm::{ + allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage}, + page::EntryFlags, + MemoryManagementArch, PhysAddr, VirtAddr, VmFlags, +}; + +use crate::arch::MMArch; + +pub type PageMapper = crate::mm::page::PageMapper; + +/// LoongArch64的内存管理架构结构体 +#[derive(Debug, Clone, Copy, Hash)] +pub struct LoongArch64MMArch; + +impl MemoryManagementArch for LoongArch64MMArch { + const PAGE_FAULT_ENABLED: bool = false; + + const PAGE_SHIFT: usize = 0; + + const PAGE_ENTRY_SHIFT: usize = 0; + + const PAGE_LEVELS: usize = 0; + + const ENTRY_ADDRESS_SHIFT: usize = 0; + + const ENTRY_FLAG_DEFAULT_PAGE: usize = 0; + + const ENTRY_FLAG_DEFAULT_TABLE: usize = 0; + + const ENTRY_FLAG_PRESENT: usize = 0; + + const ENTRY_FLAG_READONLY: usize = 0; + + const ENTRY_FLAG_WRITEABLE: usize = 0; + + const ENTRY_FLAG_READWRITE: usize = 0; + + const ENTRY_FLAG_USER: usize = 0; + + const ENTRY_FLAG_WRITE_THROUGH: usize = 0; + + const ENTRY_FLAG_CACHE_DISABLE: usize = 0; + + const ENTRY_FLAG_NO_EXEC: usize = 0; + + const ENTRY_FLAG_EXEC: usize = 0; + + const ENTRY_FLAG_DIRTY: usize = 0; + + const ENTRY_FLAG_ACCESSED: usize = 0; + + const ENTRY_FLAG_HUGE_PAGE: usize = 0; + + const ENTRY_FLAG_GLOBAL: usize = 0; + + const PHYS_OFFSET: usize = 0x9000_0000_0000_0000; + + const KERNEL_LINK_OFFSET: usize = 0; + + const USER_END_VADDR: crate::mm::VirtAddr = VirtAddr::new(0); + + const USER_BRK_START: crate::mm::VirtAddr = VirtAddr::new(0); + + const USER_STACK_START: crate::mm::VirtAddr = VirtAddr::new(0); + + const FIXMAP_START_VADDR: crate::mm::VirtAddr = VirtAddr::new(0); + + const FIXMAP_SIZE: usize = 0; + + const MMIO_BASE: crate::mm::VirtAddr = VirtAddr::new(0); + + const MMIO_SIZE: usize = 0; + + const PAGE_NONE: usize = 0; + + const PAGE_SHARED: usize = 0; + + const PAGE_SHARED_EXEC: usize = 0; + + const PAGE_COPY_NOEXEC: usize = 0; + + const PAGE_COPY_EXEC: usize = 0; + + const PAGE_COPY: usize = 0; + + const PAGE_READONLY: usize = 0; + + const PAGE_READONLY_EXEC: usize = 0; + + const PAGE_READ: usize = 0; + + const PAGE_READ_EXEC: usize = 0; + + const PAGE_WRITE: usize = 0; + + const PAGE_WRITE_EXEC: usize = 0; + + const PAGE_EXEC: usize = 0; + + const PROTECTION_MAP: [crate::mm::page::EntryFlags; 16] = protection_map(); + + unsafe fn init() { + todo!() + } + + unsafe fn invalidate_page(address: crate::mm::VirtAddr) { + todo!() + } + + unsafe fn invalidate_all() { + todo!() + } + + unsafe fn table(table_kind: crate::mm::PageTableKind) -> crate::mm::PhysAddr { + todo!() + } + + unsafe fn set_table(table_kind: crate::mm::PageTableKind, table: crate::mm::PhysAddr) { + todo!() + } + + fn virt_is_valid(virt: crate::mm::VirtAddr) -> bool { + todo!() + } + + fn initial_page_table() -> crate::mm::PhysAddr { + todo!() + } + + fn setup_new_usermapper() -> Result + { + todo!() + } + + fn make_entry(paddr: crate::mm::PhysAddr, page_flags: usize) -> usize { + todo!() + } +} + +/// 获取内核地址默认的页面标志 +pub unsafe fn kernel_page_flags(_virt: VirtAddr) -> EntryFlags { + EntryFlags::from_data(LoongArch64MMArch::ENTRY_FLAG_DEFAULT_PAGE) + .set_user(false) + .set_execute(true) +} + +/// 全局的页帧分配器 +#[derive(Debug, Clone, Copy, Hash)] +pub struct LockedFrameAllocator; + +impl FrameAllocator for LockedFrameAllocator { + unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> { + todo!("LockedFrameAllocator::allocate") + } + + unsafe fn free(&mut self, address: PhysAddr, count: PageFrameCount) { + todo!("LockedFrameAllocator::free") + } + + unsafe fn usage(&self) -> PageFrameUsage { + todo!("LockedFrameAllocator::usage") + } +} + +/// 获取保护标志的映射表 +/// +/// +/// ## 返回值 +/// - `[usize; 16]`: 长度为16的映射表 +const fn protection_map() -> [EntryFlags; 16] { + let mut map = [unsafe { EntryFlags::from_data(0) }; 16]; + unsafe { + map[VmFlags::VM_NONE.bits()] = EntryFlags::from_data(MMArch::PAGE_NONE); + map[VmFlags::VM_READ.bits()] = EntryFlags::from_data(MMArch::PAGE_READONLY); + map[VmFlags::VM_WRITE.bits()] = EntryFlags::from_data(MMArch::PAGE_COPY); + map[VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_COPY); + map[VmFlags::VM_EXEC.bits()] = EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC); + map[VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC); + map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] = + EntryFlags::from_data(MMArch::PAGE_COPY_EXEC); + map[VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_COPY_EXEC); + map[VmFlags::VM_SHARED.bits()] = EntryFlags::from_data(MMArch::PAGE_NONE); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_READONLY); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits()] = + EntryFlags::from_data(MMArch::PAGE_SHARED); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_WRITE.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_SHARED); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits()] = + EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_READ.bits()] = + EntryFlags::from_data(MMArch::PAGE_READONLY_EXEC); + map[VmFlags::VM_SHARED.bits() | VmFlags::VM_EXEC.bits() | VmFlags::VM_WRITE.bits()] = + EntryFlags::from_data(MMArch::PAGE_SHARED_EXEC); + map[VmFlags::VM_SHARED.bits() + | VmFlags::VM_EXEC.bits() + | VmFlags::VM_WRITE.bits() + | VmFlags::VM_READ.bits()] = EntryFlags::from_data(MMArch::PAGE_SHARED_EXEC); + } + + map +} diff --git a/kernel/src/arch/loongarch64/mod.rs b/kernel/src/arch/loongarch64/mod.rs new file mode 100644 index 00000000..9b605480 --- /dev/null +++ b/kernel/src/arch/loongarch64/mod.rs @@ -0,0 +1,31 @@ +pub mod asm; +pub mod cpu; +pub mod elf; +pub mod filesystem; +pub mod init; +pub mod interrupt; +pub mod ipc; +pub mod kprobe; +pub mod mm; +pub mod msi; +pub mod pci; +pub mod pio; +pub mod process; +pub mod rand; +pub mod sched; +pub mod smp; +pub mod syscall; +pub mod time; + +pub use self::elf::LoongArch64ElfArch as CurrentElfArch; +pub use self::interrupt::LoongArch64InterruptArch as CurrentIrqArch; +pub use self::ipc::signal::LoongArch64SignalArch as CurrentSignalArch; +pub use self::mm::LoongArch64MMArch as MMArch; +pub use self::pci::LoongArch64PciArch as PciArch; +pub use self::pio::LoongArch64PortIOArch as CurrentPortIOArch; +pub use self::sched::LoongArch64SchedArch as CurrentSchedArch; +pub use self::smp::LoongArch64SMPArch as CurrentSMPArch; +pub use self::time::LoongArch64TimeArch as CurrentTimeArch; + +pub fn panic_pre_work() {} +pub fn panic_post_work() {} diff --git a/kernel/src/arch/loongarch64/msi.rs b/kernel/src/arch/loongarch64/msi.rs new file mode 100644 index 00000000..863fc8cd --- /dev/null +++ b/kernel/src/arch/loongarch64/msi.rs @@ -0,0 +1,24 @@ +use crate::driver::pci::pci_irq::TriggerMode; + +/// 获得MSI Message Address +/// +/// # 参数 +/// - `processor`: 目标CPU ID号 +/// +/// # 返回值 +/// MSI Message Address +pub fn arch_msi_message_address(_processor: u16) -> u32 { + unimplemented!("loongarch64::arch_msi_message_address()") +} +/// 获得MSI Message Data +/// +/// # 参数 +/// - `vector`: 分配的中断向量号 +/// - `processor`: 目标CPU ID号 +/// - `trigger`: 申请中断的触发模式,MSI默认为边沿触发 +/// +/// # 返回值 +/// MSI Message Address +pub fn arch_msi_message_data(_vector: u16, _processor: u16, _trigger: TriggerMode) -> u32 { + unimplemented!("loongarch64::arch_msi_message_data()") +} diff --git a/kernel/src/arch/loongarch64/pci/mod.rs b/kernel/src/arch/loongarch64/pci/mod.rs new file mode 100644 index 00000000..e2345c4d --- /dev/null +++ b/kernel/src/arch/loongarch64/pci/mod.rs @@ -0,0 +1,20 @@ +use crate::{ + arch::TraitPciArch, + driver::pci::pci::{BusDeviceFunction, PciAddr}, + mm::PhysAddr, +}; + +pub struct LoongArch64PciArch; +impl TraitPciArch for LoongArch64PciArch { + fn read_config(_bus_device_function: &BusDeviceFunction, _offset: u8) -> u32 { + unimplemented!("LoongArch64PciArch::read_config") + } + + fn write_config(_bus_device_function: &BusDeviceFunction, _offset: u8, _data: u32) { + unimplemented!("LoongArch64PciArch pci_root_0().write_config") + } + + fn address_pci_to_physical(pci_address: PciAddr) -> crate::mm::PhysAddr { + return PhysAddr::new(pci_address.data()); + } +} diff --git a/kernel/src/arch/loongarch64/pio.rs b/kernel/src/arch/loongarch64/pio.rs new file mode 100644 index 00000000..0d6ad4bd --- /dev/null +++ b/kernel/src/arch/loongarch64/pio.rs @@ -0,0 +1,35 @@ +use crate::arch::io::PortIOArch; + +pub struct LoongArch64PortIOArch; + +impl PortIOArch for LoongArch64PortIOArch { + #[inline(always)] + unsafe fn in8(_port: u16) -> u8 { + unimplemented!("LoongArch64PortIOArch::in8") + } + + #[inline(always)] + unsafe fn in16(_port: u16) -> u16 { + unimplemented!("LoongArch64PortIOArch::in16") + } + + #[inline(always)] + unsafe fn in32(_port: u16) -> u32 { + unimplemented!("LoongArch64PortIOArch::in32") + } + + #[inline(always)] + unsafe fn out8(_port: u16, _data: u8) { + unimplemented!("LoongArch64PortIOArch::out8") + } + + #[inline(always)] + unsafe fn out16(_port: u16, _data: u16) { + unimplemented!("LoongArch64PortIOArch::out16") + } + + #[inline(always)] + unsafe fn out32(_port: u16, _data: u32) { + unimplemented!("LoongArch64PortIOArch::out32") + } +} diff --git a/kernel/src/arch/loongarch64/process/idle.rs b/kernel/src/arch/loongarch64/process/idle.rs new file mode 100644 index 00000000..e5149680 --- /dev/null +++ b/kernel/src/arch/loongarch64/process/idle.rs @@ -0,0 +1,31 @@ +use core::hint::spin_loop; + +use log::error; + +use crate::{ + arch::CurrentIrqArch, + exception::InterruptArch, + process::{ProcessFlags, ProcessManager}, + sched::{SchedMode, __schedule}, +}; + +impl ProcessManager { + /// 每个核的idle进程 + pub fn arch_idle_func() -> ! { + loop { + let pcb = ProcessManager::current_pcb(); + if pcb.flags().contains(ProcessFlags::NEED_SCHEDULE) { + __schedule(SchedMode::SM_NONE); + } + if CurrentIrqArch::is_irq_enabled() { + todo!("la64: arch_idle_func"); + // unsafe { + // x86::halt(); + // } + } else { + error!("Idle process should not be scheduled with IRQs disabled."); + spin_loop(); + } + } + } +} diff --git a/kernel/src/arch/loongarch64/process/kthread.rs b/kernel/src/arch/loongarch64/process/kthread.rs new file mode 100644 index 00000000..161f61a5 --- /dev/null +++ b/kernel/src/arch/loongarch64/process/kthread.rs @@ -0,0 +1,27 @@ +use system_error::SystemError; + +use alloc::sync::Arc; + +use crate::process::{ + fork::CloneFlags, + kthread::{KernelThreadCreateInfo, KernelThreadMechanism}, + Pid, +}; + +impl KernelThreadMechanism { + /// 伪造trapframe,创建内核线程 + /// + /// ## 返回值 + /// + /// 返回创建的内核线程的pid + pub fn __inner_create( + info: &Arc, + clone_flags: CloneFlags, + ) -> Result { + // WARNING: If create failed, we must drop the info manually or it will cause memory leak. (refcount will not decrease when create failed) + let create_info: *const KernelThreadCreateInfo = + KernelThreadCreateInfo::generate_unsafe_arc_ptr(info.clone()); + + todo!("la64:__inner_create()") + } +} diff --git a/kernel/src/arch/loongarch64/process/mod.rs b/kernel/src/arch/loongarch64/process/mod.rs new file mode 100644 index 00000000..5952b5af --- /dev/null +++ b/kernel/src/arch/loongarch64/process/mod.rs @@ -0,0 +1,90 @@ +use alloc::sync::Arc; +use system_error::SystemError; + +use crate::{ + arch::CurrentIrqArch, + exception::InterruptArch, + mm::VirtAddr, + process::{fork::KernelCloneArgs, KernelStack, ProcessControlBlock, ProcessManager}, +}; + +use super::interrupt::TrapFrame; + +pub mod idle; +pub mod kthread; +pub mod syscall; + +#[repr(align(32768))] +pub union InitProcUnion { + /// 用于存放idle进程的内核栈 + idle_stack: [u8; 32768], +} + +#[link_section = ".data.init_proc_union"] +#[no_mangle] +pub(super) static BSP_IDLE_STACK_SPACE: InitProcUnion = InitProcUnion { + idle_stack: [0; 32768], +}; + +pub unsafe fn arch_switch_to_user(trap_frame: TrapFrame) -> ! { + // 以下代码不能发生中断 + CurrentIrqArch::interrupt_disable(); + + todo!("la64: arch_switch_to_user") +} + +/// PCB中与架构相关的信息 +#[derive(Debug, Clone, Copy)] +#[allow(dead_code)] +#[repr(C)] +pub struct ArchPCBInfo {} + +impl ArchPCBInfo { + /// 创建一个新的ArchPCBInfo + /// + /// ## 参数 + /// + /// - `kstack`:内核栈的引用 + /// + /// ## 返回值 + /// + /// 返回一个新的ArchPCBInfo + pub fn new(kstack: &KernelStack) -> Self { + todo!("la64: ArchPCBInfo::new") + } +} + +impl ProcessControlBlock { + /// 获取当前进程的pcb + pub fn arch_current_pcb() -> Arc { + todo!("la64: arch_current_pcb") + } +} + +impl ProcessManager { + pub fn arch_init() { + // do nothing + } + /// fork的过程中复制线程 + /// + /// 由于这个过程与具体的架构相关,所以放在这里 + pub fn copy_thread( + current_pcb: &Arc, + new_pcb: &Arc, + clone_args: &KernelCloneArgs, + current_trapframe: &TrapFrame, + ) -> Result<(), SystemError> { + todo!("la64: copy_thread") + } + + /// 切换进程 + /// + /// ## 参数 + /// + /// - `prev`:上一个进程的pcb + /// - `next`:下一个进程的pcb + pub unsafe fn switch_process(prev: Arc, next: Arc) { + assert!(!CurrentIrqArch::is_irq_enabled()); + todo!("la64: switch_process"); + } +} diff --git a/kernel/src/arch/loongarch64/process/syscall.rs b/kernel/src/arch/loongarch64/process/syscall.rs new file mode 100644 index 00000000..e9fcbdf3 --- /dev/null +++ b/kernel/src/arch/loongarch64/process/syscall.rs @@ -0,0 +1,28 @@ +use system_error::SystemError; + +use crate::{ + arch::interrupt::TrapFrame, + mm::VirtAddr, + process::{ + exec::{BinaryLoaderResult, ExecParam}, + ProcessManager, + }, + syscall::Syscall, +}; + +impl Syscall { + pub fn arch_do_execve( + regs: &mut TrapFrame, + param: &ExecParam, + load_result: &BinaryLoaderResult, + user_sp: VirtAddr, + argv_ptr: VirtAddr, + ) -> Result<(), SystemError> { + todo!("la64:arch_do_execve not unimplemented"); + } + + /// ## 用于控制和查询与体系结构相关的进程特定选项 + pub fn arch_prctl(option: usize, arg2: usize) -> Result { + todo!("la64:arch_prctl") + } +} diff --git a/kernel/src/arch/loongarch64/rand.rs b/kernel/src/arch/loongarch64/rand.rs new file mode 100644 index 00000000..af25319d --- /dev/null +++ b/kernel/src/arch/loongarch64/rand.rs @@ -0,0 +1,5 @@ +use crate::libs::rand::soft_rand; + +pub fn rand() -> usize { + return soft_rand(); +} diff --git a/kernel/src/arch/loongarch64/sched.rs b/kernel/src/arch/loongarch64/sched.rs new file mode 100644 index 00000000..96e715d8 --- /dev/null +++ b/kernel/src/arch/loongarch64/sched.rs @@ -0,0 +1,17 @@ +use crate::sched::SchedArch; + +pub struct LoongArch64SchedArch; + +impl SchedArch for LoongArch64SchedArch { + fn enable_sched_local() { + todo!("LoongArch64::enable_sched_local") + } + + fn disable_sched_local() { + todo!("LoongArch64::disable_sched_local") + } + + fn initial_setup_sched_local() { + todo!("LoongArch64::initial_setup_sched_local") + } +} diff --git a/kernel/src/arch/loongarch64/smp/mod.rs b/kernel/src/arch/loongarch64/smp/mod.rs new file mode 100644 index 00000000..a9d3f1f5 --- /dev/null +++ b/kernel/src/arch/loongarch64/smp/mod.rs @@ -0,0 +1,29 @@ +use log::warn; +use system_error::SystemError; + +use crate::smp::{ + cpu::{CpuHpCpuState, ProcessorId, SmpCpuManager}, + SMPArch, +}; + +pub struct LoongArch64SMPArch; + +impl SMPArch for LoongArch64SMPArch { + #[inline(never)] + fn prepare_cpus() -> Result<(), SystemError> { + warn!("LoongArch64SMPArch::prepare_cpus() is not implemented"); + Ok(()) + } + + fn start_cpu(_cpu_id: ProcessorId, _hp_state: &CpuHpCpuState) -> Result<(), SystemError> { + warn!("LoongArch64SMPArch::start_cpu() is not implemented"); + Ok(()) + } +} + +impl SmpCpuManager { + pub fn arch_init(_boot_cpu: ProcessorId) { + // todo: 读取所有可用的CPU + todo!("la64:SmpCpuManager::arch_init()") + } +} diff --git a/kernel/src/arch/loongarch64/syscall/mod.rs b/kernel/src/arch/loongarch64/syscall/mod.rs new file mode 100644 index 00000000..80bebe15 --- /dev/null +++ b/kernel/src/arch/loongarch64/syscall/mod.rs @@ -0,0 +1,8 @@ +use system_error::SystemError; + +pub mod nr; + +/// 系统调用初始化 +pub fn arch_syscall_init() -> Result<(), SystemError> { + todo!("la64:arch_syscall_init"); +} diff --git a/kernel/src/arch/loongarch64/syscall/nr.rs b/kernel/src/arch/loongarch64/syscall/nr.rs new file mode 100644 index 00000000..2f47fffa --- /dev/null +++ b/kernel/src/arch/loongarch64/syscall/nr.rs @@ -0,0 +1,307 @@ +#![allow(dead_code)] + +pub const SYS_IO_SETUP: usize = 0; +pub const SYS_IO_DESTROY: usize = 1; +pub const SYS_IO_SUBMIT: usize = 2; +pub const SYS_IO_CANCEL: usize = 3; +pub const SYS_IO_GETEVENTS: usize = 4; +pub const SYS_SETXATTR: usize = 5; +pub const SYS_LSETXATTR: usize = 6; +pub const SYS_FSETXATTR: usize = 7; +pub const SYS_GETXATTR: usize = 8; +pub const SYS_LGETXATTR: usize = 9; +pub const SYS_FGETXATTR: usize = 10; +pub const SYS_LISTXATTR: usize = 11; +pub const SYS_LLISTXATTR: usize = 12; +pub const SYS_FLISTXATTR: usize = 13; +pub const SYS_REMOVEXATTR: usize = 14; +pub const SYS_LREMOVEXATTR: usize = 15; +pub const SYS_FREMOVEXATTR: usize = 16; +pub const SYS_GETCWD: usize = 17; +pub const SYS_LOOKUP_DCOOKIE: usize = 18; +pub const SYS_EVENTFD2: usize = 19; +pub const SYS_EPOLL_CREATE1: usize = 20; +pub const SYS_EPOLL_CTL: usize = 21; +pub const SYS_EPOLL_PWAIT: usize = 22; +pub const SYS_DUP: usize = 23; +pub const SYS_DUP3: usize = 24; +pub const SYS_FCNTL: usize = 25; +pub const SYS_INOTIFY_INIT1: usize = 26; +pub const SYS_INOTIFY_ADD_WATCH: usize = 27; +pub const SYS_INOTIFY_RM_WATCH: usize = 28; +pub const SYS_IOCTL: usize = 29; +pub const SYS_IOPRIO_SET: usize = 30; +pub const SYS_IOPRIO_GET: usize = 31; +pub const SYS_FLOCK: usize = 32; +pub const SYS_MKNODAT: usize = 33; +pub const SYS_MKDIRAT: usize = 34; +pub const SYS_UNLINKAT: usize = 35; +pub const SYS_SYMLINKAT: usize = 36; +pub const SYS_LINKAT: usize = 37; +pub const SYS_UMOUNT2: usize = 39; +pub const SYS_MOUNT: usize = 40; +pub const SYS_PIVOT_ROOT: usize = 41; +pub const SYS_NFSSERVCTL: usize = 42; +pub const SYS_STATFS: usize = 43; +pub const SYS_FSTATFS: usize = 44; +pub const SYS_TRUNCATE: usize = 45; +pub const SYS_FTRUNCATE: usize = 46; +pub const SYS_FALLOCATE: usize = 47; +pub const SYS_FACCESSAT: usize = 48; +pub const SYS_CHDIR: usize = 49; +pub const SYS_FCHDIR: usize = 50; +pub const SYS_CHROOT: usize = 51; +pub const SYS_FCHMOD: usize = 52; +pub const SYS_FCHMODAT: usize = 53; +pub const SYS_FCHOWNAT: usize = 54; +pub const SYS_FCHOWN: usize = 55; +pub const SYS_OPENAT: usize = 56; +pub const SYS_CLOSE: usize = 57; +pub const SYS_VHANGUP: usize = 58; +pub const SYS_PIPE2: usize = 59; +pub const SYS_QUOTACTL: usize = 60; +pub const SYS_GETDENTS64: usize = 61; +pub const SYS_LSEEK: usize = 62; +pub const SYS_READ: usize = 63; +pub const SYS_WRITE: usize = 64; +pub const SYS_READV: usize = 65; +pub const SYS_WRITEV: usize = 66; +pub const SYS_PREAD64: usize = 67; +pub const SYS_PWRITE64: usize = 68; +pub const SYS_PREADV: usize = 69; +pub const SYS_PWRITEV: usize = 70; +pub const SYS_SENDFILE: usize = 71; +pub const SYS_PSELECT6: usize = 72; +pub const SYS_PPOLL: usize = 73; +pub const SYS_SIGNALFD4: usize = 74; +pub const SYS_VMSPLICE: usize = 75; +pub const SYS_SPLICE: usize = 76; +pub const SYS_TEE: usize = 77; +pub const SYS_READLINKAT: usize = 78; +pub const SYS_SYNC: usize = 81; +pub const SYS_FSYNC: usize = 82; +pub const SYS_FDATASYNC: usize = 83; +pub const SYS_SYNC_FILE_RANGE: usize = 84; +pub const SYS_TIMERFD_CREATE: usize = 85; +pub const SYS_TIMERFD_SETTIME: usize = 86; +pub const SYS_TIMERFD_GETTIME: usize = 87; +pub const SYS_UTIMENSAT: usize = 88; +pub const SYS_ACCT: usize = 89; +pub const SYS_CAPGET: usize = 90; +pub const SYS_CAPSET: usize = 91; +pub const SYS_PERSONALITY: usize = 92; +pub const SYS_EXIT: usize = 93; +pub const SYS_EXIT_GROUP: usize = 94; +pub const SYS_WAITID: usize = 95; +pub const SYS_SET_TID_ADDRESS: usize = 96; +pub const SYS_UNSHARE: usize = 97; +pub const SYS_FUTEX: usize = 98; +pub const SYS_SET_ROBUST_LIST: usize = 99; +pub const SYS_GET_ROBUST_LIST: usize = 100; +pub const SYS_NANOSLEEP: usize = 101; +pub const SYS_GETITIMER: usize = 102; +pub const SYS_SETITIMER: usize = 103; +pub const SYS_KEXEC_LOAD: usize = 104; +pub const SYS_INIT_MODULE: usize = 105; +pub const SYS_DELETE_MODULE: usize = 106; +pub const SYS_TIMER_CREATE: usize = 107; +pub const SYS_TIMER_GETTIME: usize = 108; +pub const SYS_TIMER_GETOVERRUN: usize = 109; +pub const SYS_TIMER_SETTIME: usize = 110; +pub const SYS_TIMER_DELETE: usize = 111; +pub const SYS_CLOCK_SETTIME: usize = 112; +pub const SYS_CLOCK_GETTIME: usize = 113; +pub const SYS_CLOCK_GETRES: usize = 114; +pub const SYS_CLOCK_NANOSLEEP: usize = 115; +pub const SYS_SYSLOG: usize = 116; +pub const SYS_PTRACE: usize = 117; +pub const SYS_SCHED_SETPARAM: usize = 118; +pub const SYS_SCHED_SETSCHEDULER: usize = 119; +pub const SYS_SCHED_GETSCHEDULER: usize = 120; +pub const SYS_SCHED_GETPARAM: usize = 121; +pub const SYS_SCHED_SETAFFINITY: usize = 122; +pub const SYS_SCHED_GETAFFINITY: usize = 123; +pub const SYS_SCHED_YIELD: usize = 124; +pub const SYS_SCHED_GET_PRIORITY_MAX: usize = 125; +pub const SYS_SCHED_GET_PRIORITY_MIN: usize = 126; +pub const SYS_SCHED_RR_GET_INTERVAL: usize = 127; +pub const SYS_RESTART_SYSCALL: usize = 128; +pub const SYS_KILL: usize = 129; +pub const SYS_TKILL: usize = 130; +pub const SYS_TGKILL: usize = 131; +pub const SYS_SIGALTSTACK: usize = 132; +pub const SYS_RT_SIGSUSPEND: usize = 133; +pub const SYS_RT_SIGACTION: usize = 134; +pub const SYS_RT_SIGPROCMASK: usize = 135; +pub const SYS_RT_SIGPENDING: usize = 136; +pub const SYS_RT_SIGTIMEDWAIT: usize = 137; +pub const SYS_RT_SIGQUEUEINFO: usize = 138; +pub const SYS_RT_SIGRETURN: usize = 139; +pub const SYS_SETPRIORITY: usize = 140; +pub const SYS_GETPRIORITY: usize = 141; +pub const SYS_REBOOT: usize = 142; +pub const SYS_SETREGID: usize = 143; +pub const SYS_SETGID: usize = 144; +pub const SYS_SETREUID: usize = 145; +pub const SYS_SETUID: usize = 146; +pub const SYS_SETRESUID: usize = 147; +pub const SYS_GETRESUID: usize = 148; +pub const SYS_SETRESGID: usize = 149; +pub const SYS_GETRESGID: usize = 150; +pub const SYS_SETFSUID: usize = 151; +pub const SYS_SETFSGID: usize = 152; +pub const SYS_TIMES: usize = 153; +pub const SYS_SETPGID: usize = 154; +pub const SYS_GETPGID: usize = 155; +pub const SYS_GETSID: usize = 156; +pub const SYS_SETSID: usize = 157; +pub const SYS_GETGROUPS: usize = 158; +pub const SYS_SETGROUPS: usize = 159; +pub const SYS_UNAME: usize = 160; +pub const SYS_SETHOSTNAME: usize = 161; +pub const SYS_SETDOMAINNAME: usize = 162; +pub const SYS_GETRUSAGE: usize = 165; +pub const SYS_UMASK: usize = 166; +pub const SYS_PRCTL: usize = 167; +pub const SYS_GETCPU: usize = 168; +pub const SYS_GETTIMEOFDAY: usize = 169; +pub const SYS_SETTIMEOFDAY: usize = 170; +pub const SYS_ADJTIMEX: usize = 171; +pub const SYS_GETPID: usize = 172; +pub const SYS_GETPPID: usize = 173; +pub const SYS_GETUID: usize = 174; +pub const SYS_GETEUID: usize = 175; +pub const SYS_GETGID: usize = 176; +pub const SYS_GETEGID: usize = 177; +pub const SYS_GETTID: usize = 178; +pub const SYS_SYSINFO: usize = 179; +pub const SYS_MQ_OPEN: usize = 180; +pub const SYS_MQ_UNLINK: usize = 181; +pub const SYS_MQ_TIMEDSEND: usize = 182; +pub const SYS_MQ_TIMEDRECEIVE: usize = 183; +pub const SYS_MQ_NOTIFY: usize = 184; +pub const SYS_MQ_GETSETATTR: usize = 185; +pub const SYS_MSGGET: usize = 186; +pub const SYS_MSGCTL: usize = 187; +pub const SYS_MSGRCV: usize = 188; +pub const SYS_MSGSND: usize = 189; +pub const SYS_SEMGET: usize = 190; +pub const SYS_SEMCTL: usize = 191; +pub const SYS_SEMTIMEDOP: usize = 192; +pub const SYS_SEMOP: usize = 193; +pub const SYS_SHMGET: usize = 194; +pub const SYS_SHMCTL: usize = 195; +pub const SYS_SHMAT: usize = 196; +pub const SYS_SHMDT: usize = 197; +pub const SYS_SOCKET: usize = 198; +pub const SYS_SOCKETPAIR: usize = 199; +pub const SYS_BIND: usize = 200; +pub const SYS_LISTEN: usize = 201; +pub const SYS_ACCEPT: usize = 202; +pub const SYS_CONNECT: usize = 203; +pub const SYS_GETSOCKNAME: usize = 204; +pub const SYS_GETPEERNAME: usize = 205; +pub const SYS_SENDTO: usize = 206; +pub const SYS_RECVFROM: usize = 207; +pub const SYS_SETSOCKOPT: usize = 208; +pub const SYS_GETSOCKOPT: usize = 209; +pub const SYS_SHUTDOWN: usize = 210; +pub const SYS_SENDMSG: usize = 211; +pub const SYS_RECVMSG: usize = 212; +pub const SYS_READAHEAD: usize = 213; +pub const SYS_BRK: usize = 214; +pub const SYS_MUNMAP: usize = 215; +pub const SYS_MREMAP: usize = 216; +pub const SYS_ADD_KEY: usize = 217; +pub const SYS_REQUEST_KEY: usize = 218; +pub const SYS_KEYCTL: usize = 219; +pub const SYS_CLONE: usize = 220; +pub const SYS_EXECVE: usize = 221; +pub const SYS_MMAP: usize = 222; +pub const SYS_FADVISE64: usize = 223; +pub const SYS_SWAPON: usize = 224; +pub const SYS_SWAPOFF: usize = 225; +pub const SYS_MPROTECT: usize = 226; +pub const SYS_MSYNC: usize = 227; +pub const SYS_MLOCK: usize = 228; +pub const SYS_MUNLOCK: usize = 229; +pub const SYS_MLOCKALL: usize = 230; +pub const SYS_MUNLOCKALL: usize = 231; +pub const SYS_MINCORE: usize = 232; +pub const SYS_MADVISE: usize = 233; +pub const SYS_REMAP_FILE_PAGES: usize = 234; +pub const SYS_MBIND: usize = 235; +pub const SYS_GET_MEMPOLICY: usize = 236; +pub const SYS_SET_MEMPOLICY: usize = 237; +pub const SYS_MIGRATE_PAGES: usize = 238; +pub const SYS_MOVE_PAGES: usize = 239; +pub const SYS_RT_TGSIGQUEUEINFO: usize = 240; +pub const SYS_PERF_EVENT_OPEN: usize = 241; +pub const SYS_ACCEPT4: usize = 242; +pub const SYS_RECVMMSG: usize = 243; +//pub const SYS_ARCH_SPECIFIC_SYSCALL: usize = 244; +pub const SYS_WAIT4: usize = 260; +pub const SYS_PRLIMIT64: usize = 261; +pub const SYS_FANOTIFY_INIT: usize = 262; +pub const SYS_FANOTIFY_MARK: usize = 263; +pub const SYS_NAME_TO_HANDLE_AT: usize = 264; +pub const SYS_OPEN_BY_HANDLE_AT: usize = 265; +pub const SYS_CLOCK_ADJTIME: usize = 266; +pub const SYS_SYNCFS: usize = 267; +pub const SYS_SETNS: usize = 268; +pub const SYS_SENDMMSG: usize = 269; +pub const SYS_PROCESS_VM_READV: usize = 270; +pub const SYS_PROCESS_VM_WRITEV: usize = 271; +pub const SYS_KCMP: usize = 272; +pub const SYS_FINIT_MODULE: usize = 273; +pub const SYS_SCHED_SETATTR: usize = 274; +pub const SYS_SCHED_GETATTR: usize = 275; +pub const SYS_RENAMEAT2: usize = 276; +pub const SYS_SECCOMP: usize = 277; +pub const SYS_GETRANDOM: usize = 278; +pub const SYS_MEMFD_CREATE: usize = 279; +pub const SYS_BPF: usize = 280; +pub const SYS_EXECVEAT: usize = 281; +pub const SYS_USERFAULTFD: usize = 282; +pub const SYS_MEMBARRIER: usize = 283; +pub const SYS_MLOCK2: usize = 284; +pub const SYS_COPY_FILE_RANGE: usize = 285; +pub const SYS_PREADV2: usize = 286; +pub const SYS_PWRITEV2: usize = 287; +pub const SYS_PKEY_MPROTECT: usize = 288; +pub const SYS_PKEY_ALLOC: usize = 289; +pub const SYS_PKEY_FREE: usize = 290; +pub const SYS_STATX: usize = 291; +pub const SYS_IO_PGETEVENTS: usize = 292; +pub const SYS_RSEQ: usize = 293; +pub const SYS_KEXEC_FILE_LOAD: usize = 294; +pub const SYS_PIDFD_SEND_SIGNAL: usize = 424; +pub const SYS_IO_URING_SETUP: usize = 425; +pub const SYS_IO_URING_ENTER: usize = 426; +pub const SYS_IO_URING_REGISTER: usize = 427; +pub const SYS_OPEN_TREE: usize = 428; +pub const SYS_MOVE_MOUNT: usize = 429; +pub const SYS_FSOPEN: usize = 430; +pub const SYS_FSCONFIG: usize = 431; +pub const SYS_FSMOUNT: usize = 432; +pub const SYS_FSPICK: usize = 433; +pub const SYS_PIDFD_OPEN: usize = 434; +pub const SYS_CLONE3: usize = 435; +pub const SYS_CLOSE_RANGE: usize = 436; +pub const SYS_OPENAT2: usize = 437; +pub const SYS_PIDFD_GETFD: usize = 438; +pub const SYS_FACCESSAT2: usize = 439; +pub const SYS_PROCESS_MADVISE: usize = 440; +pub const SYS_EPOLL_PWAIT2: usize = 441; +pub const SYS_MOUNT_SETATTR: usize = 442; +pub const SYS_QUOTACTL_FD: usize = 443; +pub const SYS_LANDLOCK_CREATE_RULESET: usize = 444; +pub const SYS_LANDLOCK_ADD_RULE: usize = 445; +pub const SYS_LANDLOCK_RESTRICT_SELF: usize = 446; +pub const SYS_PROCESS_MRELEASE: usize = 448; +pub const SYS_FUTEX_WAITV: usize = 449; +pub const SYS_SET_MEMPOLICY_HOME_NODE: usize = 450; + +// ===以下是为了代码一致性,才定义的调用号=== + +pub const SYS_GETDENTS: usize = SYS_GETDENTS64; diff --git a/kernel/src/arch/loongarch64/time.rs b/kernel/src/arch/loongarch64/time.rs new file mode 100644 index 00000000..28f1613d --- /dev/null +++ b/kernel/src/arch/loongarch64/time.rs @@ -0,0 +1,24 @@ +use crate::time::{clocksource::HZ, TimeArch}; + +/// 这个是系统jiffies时钟源的固有频率(不是调频之后的) +pub const CLOCK_TICK_RATE: u32 = HZ as u32 * 1000000; + +pub struct LoongArch64TimeArch; + +impl TimeArch for LoongArch64TimeArch { + fn get_cycles() -> usize { + todo!("LoongArch64TimeArch::get_cycles") + } + + fn cal_expire_cycles(ns: usize) -> usize { + todo!("LoongArch64TimeArch::cal_expire_cycles") + } + + fn cycles2ns(cycles: usize) -> usize { + todo!("LoongArch64TimeArch::cycles2ns") + } +} + +pub fn time_init() { + todo!("la64:time_init"); +} diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs index 4deb8843..88e7837e 100644 --- a/kernel/src/arch/mod.rs +++ b/kernel/src/arch/mod.rs @@ -13,6 +13,11 @@ pub mod riscv64; #[cfg(target_arch = "riscv64")] pub use self::riscv64::*; // 公开riscv64架构下的函数,使外界接口统一 +#[cfg(target_arch = "loongarch64")] +pub mod loongarch64; +#[cfg(target_arch = "loongarch64")] +pub use self::loongarch64::*; // 公开loongarch64架构下的函数,使外界接口统一 + pub mod io; /// TraitPciArch Pci架构相关函数,任何架构都应独立实现trait里的函数 diff --git a/kernel/src/arch/riscv64/asm/head.S b/kernel/src/arch/riscv64/asm/head.S index 34d78cf4..0bd6e6cc 100644 --- a/kernel/src/arch/riscv64/asm/head.S +++ b/kernel/src/arch/riscv64/asm/head.S @@ -1,5 +1,29 @@ #include "common/asm.h" -#include "asm/csr.h" + +#define CSR_SSTATUS 0x100 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SIP 0x144 +#define CSR_SSCRATCH 0x140 + +#define CSR_TVEC CSR_STVEC +#define CSR_SCRATCH CSR_SSCRATCH + +#define CSR_STATUS CSR_SSTATUS +#define CSR_IE CSR_SIE +#define CSR_IP CSR_SIP + +#define SR_FS 0x00006000 +#define SR_VS 0x00000600 +#define SR_FS_VS (SR_FS | SR_VS) /* Vector and Floating-Point Unit */ + +#define SATP_MODE_39 0x8000000000000000ULL +#define SATP_MODE_48 0x9000000000000000ULL +#define SATP_MODE_57 0xa000000000000000ULL + +#define PAGE_OFFSET 0xffffffc000000000 +#define KERNEL_LINK_OFFSET 0x1000000 +#define KERNEL_VIRT_START (PAGE_OFFSET + KERNEL_LINK_OFFSET) .section .bootstrap diff --git a/kernel/src/arch/riscv64/asm/irqflags.h b/kernel/src/arch/riscv64/asm/irqflags.h deleted file mode 100644 index 13a73926..00000000 --- a/kernel/src/arch/riscv64/asm/irqflags.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include -// 保存当前rflags的值到变量x内并关闭中断 -#define local_irq_save(x) \ - do \ - { \ - } while (1) -// 恢复先前保存的rflags的值x -#define local_irq_restore(x) \ - do \ - { \ - } while (1) -#define local_irq_disable() \ - do \ - { \ - } while (1) -#define local_irq_enable() \ - do \ - { \ - } while (1) diff --git a/kernel/src/arch/riscv64/asm/spinlock.c b/kernel/src/arch/riscv64/asm/spinlock.c deleted file mode 100644 index a5cb9c6e..00000000 --- a/kernel/src/arch/riscv64/asm/spinlock.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -void __arch_spin_lock(spinlock_t *lock) -{ - while(1); - rs_preempt_disable(); -} - -void __arch_spin_unlock(spinlock_t *lock) -{ - while(1); - rs_preempt_enable(); -} - -void __arch_spin_lock_no_preempt(spinlock_t *lock) -{ - while(1); -} - -void __arch_spin_unlock_no_preempt(spinlock_t *lock) -{ - while(1); -} - -long __arch_spin_trylock(spinlock_t *lock) -{ - uint64_t tmp_val = 0; - rs_preempt_disable(); - // 交换tmp_val和lock的值,若tmp_val==1则证明加锁成功 - while(1); - if (!tmp_val) - rs_preempt_enable(); - return tmp_val; -} diff --git a/kernel/src/arch/riscv64/filesystem/mod.rs b/kernel/src/arch/riscv64/filesystem/mod.rs new file mode 100644 index 00000000..4f22af63 --- /dev/null +++ b/kernel/src/arch/riscv64/filesystem/mod.rs @@ -0,0 +1 @@ +pub mod stat; diff --git a/kernel/src/arch/riscv64/filesystem/stat.rs b/kernel/src/arch/riscv64/filesystem/stat.rs new file mode 100644 index 00000000..6402d6ff --- /dev/null +++ b/kernel/src/arch/riscv64/filesystem/stat.rs @@ -0,0 +1 @@ +pub use crate::filesystem::vfs::stat::GenericPosixStat as PosixStat; diff --git a/kernel/src/arch/riscv64/include/asm/asm.h b/kernel/src/arch/riscv64/include/asm/asm.h deleted file mode 100644 index 6f1b1a70..00000000 --- a/kernel/src/arch/riscv64/include/asm/asm.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include "DragonOS/stdint.h" -#include -#include - -// RISC-V 没有直接的开启/关闭中断的指令,你需要通过修改CSR寄存器来实现 -// 你可能需要在你的中断处理程序中处理这些操作 - -#define nop() __asm__ __volatile__("nop\n\t") - -// RISC-V 没有 hlt 指令,你可能需要使用 wfi 指令来等待中断 -#define hlt() __asm__ __volatile__("wfi\n\t") - -// RISC-V 没有 pause 指令,你可能需要使用其他方法来实现处理器等待 - -// RISC-V 使用 fence 指令来实现内存屏障 -#define io_mfence() __asm__ __volatile__("fence rw,rw\n\t" ::: "memory") -#define io_sfence() __asm__ __volatile__("fence w,w\n\t" ::: "memory") -#define io_lfence() __asm__ __volatile__("fence r,r\n\t" ::: "memory") - -// 开启中断 -#define sti() __asm__ __volatile__("csrsi mstatus, 8\n\t" ::: "memory") - -// 关闭中断 -#define cli() __asm__ __volatile__("csrci mstatus, 8\n\t" ::: "memory") - -// 从io口读入8个bit -unsigned char io_in8(unsigned short port) { - while (1) - ; -} - -// 从io口读入32个bit -unsigned int io_in32(unsigned short port) { - while (1) - ; -} - -// 输出8个bit到输出端口 -void io_out8(unsigned short port, unsigned char value) { - while (1) - ; -} - -// 输出32个bit到输出端口 -void io_out32(unsigned short port, unsigned int value) { - while (1) - ; -} - -/** - * @brief 验证地址空间是否为用户地址空间 - * - * @param addr_start 地址起始值 - * @param length 地址长度 - * @return true - * @return false - */ -bool verify_area(uint64_t addr_start, uint64_t length) { - while (1) - ; -} \ No newline at end of file diff --git a/kernel/src/arch/riscv64/include/asm/csr.h b/kernel/src/arch/riscv64/include/asm/csr.h deleted file mode 100644 index 7b42a6b9..00000000 --- a/kernel/src/arch/riscv64/include/asm/csr.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#define CSR_SSTATUS 0x100 -#define CSR_SIE 0x104 -#define CSR_STVEC 0x105 -#define CSR_SIP 0x144 -#define CSR_SSCRATCH 0x140 - -#define CSR_TVEC CSR_STVEC -#define CSR_SCRATCH CSR_SSCRATCH - -#define CSR_STATUS CSR_SSTATUS -#define CSR_IE CSR_SIE -#define CSR_IP CSR_SIP - -#define SR_FS 0x00006000 -#define SR_VS 0x00000600 -#define SR_FS_VS (SR_FS | SR_VS) /* Vector and Floating-Point Unit */ - -#define SATP_MODE_39 0x8000000000000000ULL -#define SATP_MODE_48 0x9000000000000000ULL -#define SATP_MODE_57 0xa000000000000000ULL - -#define PAGE_OFFSET 0xffffffc000000000 -#define KERNEL_LINK_OFFSET 0x1000000 -#define KERNEL_VIRT_START (PAGE_OFFSET + KERNEL_LINK_OFFSET) \ No newline at end of file diff --git a/kernel/src/arch/riscv64/include/asm/irqflags.h b/kernel/src/arch/riscv64/include/asm/irqflags.h deleted file mode 100644 index 8b042bea..00000000 --- a/kernel/src/arch/riscv64/include/asm/irqflags.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -// 保存当前rflags的值到变量x内并关闭中断 -#define local_irq_save(x) \ - do \ - { \ - } while (1) -// 恢复先前保存的rflags的值x -#define local_irq_restore(x) \ - do \ - { \ - } while (1) -#define local_irq_disable() cli(); -#define local_irq_enable() sti(); diff --git a/kernel/src/arch/riscv64/interrupt/handle.rs b/kernel/src/arch/riscv64/interrupt/handle.rs index fc971679..de051d4a 100644 --- a/kernel/src/arch/riscv64/interrupt/handle.rs +++ b/kernel/src/arch/riscv64/interrupt/handle.rs @@ -151,10 +151,18 @@ fn do_trap_insn_page_fault(trap_frame: &mut TrapFrame) -> Result<(), SystemError let vaddr = trap_frame.badaddr; let cause = trap_frame.cause; let epc = trap_frame.epc; - error!( - "riscv64_do_irq: do_insn_page_fault vaddr: {:#x}, cause: {:?} epc: {:#x}", - vaddr, cause, epc - ); + if trap_frame.is_from_user() { + error!( + "riscv64_do_irq: do_trap_insn_page_fault(user mode): epc: {epc:#x}, vaddr={:#x}, cause={:?}", + vaddr, cause + ); + } else { + panic!( + "riscv64_do_irq: do_trap_insn_page_fault(kernel mode): epc: {epc:#x}, vaddr={:#x}, cause={:?}", + vaddr, cause + ); + } + loop { spin_loop(); } @@ -165,10 +173,17 @@ fn do_trap_load_page_fault(trap_frame: &mut TrapFrame) -> Result<(), SystemError let vaddr = trap_frame.badaddr; let cause = trap_frame.cause; let epc = trap_frame.epc; - error!( - "riscv64_do_irq: do_trap_load_page_fault: epc: {epc:#x}, vaddr={:#x}, cause={:?}", - vaddr, cause - ); + if trap_frame.is_from_user() { + error!( + "riscv64_do_irq: do_trap_load_page_fault(user mode): epc: {epc:#x}, vaddr={:#x}, cause={:?}", + vaddr, cause + ); + } else { + panic!( + "riscv64_do_irq: do_trap_load_page_fault(kernel mode): epc: {epc:#x}, vaddr={:#x}, cause={:?}", + vaddr, cause + ); + } loop { spin_loop(); diff --git a/kernel/src/arch/riscv64/ipc/signal.rs b/kernel/src/arch/riscv64/ipc/signal.rs index befb23e2..0c049bb5 100644 --- a/kernel/src/arch/riscv64/ipc/signal.rs +++ b/kernel/src/arch/riscv64/ipc/signal.rs @@ -93,13 +93,14 @@ impl From for Signal { } } -impl Into for Signal { - fn into(self) -> SigSet { +impl From for SigSet { + fn from(val: Signal) -> Self { SigSet { - bits: (1 << (self as usize - 1) as u64), + bits: (1 << (val as usize - 1) as u64), } } } + impl Signal { /// 判断一个数字是否为可用的信号 #[inline] diff --git a/kernel/src/arch/riscv64/link.ld b/kernel/src/arch/riscv64/link.ld index 0f88eaef..6b7de40e 100644 --- a/kernel/src/arch/riscv64/link.ld +++ b/kernel/src/arch/riscv64/link.ld @@ -68,6 +68,27 @@ SECTIONS . = ALIGN(32768); + trace_point_start_pa = .; + .tracepoint (trace_point_start_pa): AT(trace_point_start_pa - KERNEL_VMA) + { + _tracepoint = .; + *(.tracepoint) + *(.tracepoint.*) + _etracepoint = .; + } + + . = ALIGN(4096); + + syscall_table_start_pa = .; + .syscall_table (syscall_table_start_pa): AT(syscall_table_start_pa - KERNEL_VMA) + { + _syscall_table = .; + *(.syscall_table) + *(.syscall_table.*) + _esyscall_table = .; + } + + . = ALIGN(32768); init_proc_union_start_pa = .; .data.init_proc_union (init_proc_union_start_pa): AT(init_proc_union_start_pa - KERNEL_VMA) { *(.data.init_proc_union) } diff --git a/kernel/src/arch/riscv64/mod.rs b/kernel/src/arch/riscv64/mod.rs index fc4ca249..584b8059 100644 --- a/kernel/src/arch/riscv64/mod.rs +++ b/kernel/src/arch/riscv64/mod.rs @@ -2,6 +2,7 @@ pub mod asm; pub mod cpu; pub mod driver; pub mod elf; +pub mod filesystem; pub mod init; pub mod interrupt; pub mod ipc; @@ -32,3 +33,10 @@ pub use self::ipc::signal::RiscV64SignalArch as CurrentSignalArch; pub use crate::arch::smp::RiscV64SMPArch as CurrentSMPArch; pub use crate::arch::sched::RiscV64SchedArch as CurrentSchedArch; + +pub fn panic_pre_work() { + unsafe { riscv::register::sstatus::set_fs(riscv::register::sstatus::FS::Initial) }; +} +pub fn panic_post_work() { + unsafe { riscv::register::sstatus::set_fs(riscv::register::sstatus::FS::Off) }; +} diff --git a/kernel/src/arch/riscv64/rand.rs b/kernel/src/arch/riscv64/rand.rs index 17edfa82..af25319d 100644 --- a/kernel/src/arch/riscv64/rand.rs +++ b/kernel/src/arch/riscv64/rand.rs @@ -1,13 +1,5 @@ +use crate::libs::rand::soft_rand; + pub fn rand() -> usize { - static mut SEED: u64 = 0xdead_beef_cafe_babe; - let mut buf = [0u8; size_of::()]; - for x in buf.iter_mut() { - unsafe { - // from musl - SEED = SEED.wrapping_mul(0x5851_f42d_4c95_7f2d); - *x = (SEED >> 33) as u8; - } - } - let x: usize = unsafe { core::mem::transmute(buf) }; - return x; + return soft_rand(); } diff --git a/kernel/src/arch/riscv64/syscall/mod.rs b/kernel/src/arch/riscv64/syscall/mod.rs index 6f80d244..e43670a6 100644 --- a/kernel/src/arch/riscv64/syscall/mod.rs +++ b/kernel/src/arch/riscv64/syscall/mod.rs @@ -36,16 +36,8 @@ pub(super) fn syscall_handler(syscall_num: usize, frame: &mut TrapFrame) -> () { let args = [frame.a0, frame.a1, frame.a2, frame.a3, frame.a4, frame.a5]; let mut syscall_handle = || -> usize { - #[cfg(feature = "backtrace")] - { - Syscall::catch_handle(syscall_num, &args, frame) - .unwrap_or_else(|e| e.to_posix_errno() as usize) - } - #[cfg(not(feature = "backtrace"))] - { - Syscall::handle(syscall_num, &args, frame) - .unwrap_or_else(|e| e.to_posix_errno() as usize) - } + Syscall::catch_handle(syscall_num, &args, frame) + .unwrap_or_else(|e| e.to_posix_errno() as usize) }; syscall_return!(syscall_handle(), frame, false); } diff --git a/kernel/src/arch/x86_64/asm/apu_boot.S b/kernel/src/arch/x86_64/asm/apu_boot.S index 608258a1..f75c14be 100644 --- a/kernel/src/arch/x86_64/asm/apu_boot.S +++ b/kernel/src/arch/x86_64/asm/apu_boot.S @@ -1,5 +1,4 @@ #include "../common/asm.h" -#include .align 0x1000 // 按照4k对齐 diff --git a/kernel/src/arch/x86_64/asm/cmpxchg.c b/kernel/src/arch/x86_64/asm/cmpxchg.c deleted file mode 100644 index 77c2a4e6..00000000 --- a/kernel/src/arch/x86_64/asm/cmpxchg.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -bool __try_cmpxchg_q(uint64_t *ptr, uint64_t *old_ptr, uint64_t *new_ptr) -{ - bool success = __raw_try_cmpxchg(ptr, old_ptr, *new_ptr, 8); - return success; -} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/asm/head.S b/kernel/src/arch/x86_64/asm/head.S index d7b19234..5a32c34d 100644 --- a/kernel/src/arch/x86_64/asm/head.S +++ b/kernel/src/arch/x86_64/asm/head.S @@ -3,7 +3,6 @@ // 2022/01/20 #include "common/asm.h" -#include // 以下是来自 multiboot2 规范的定义 // How many bytes from the start of the file we search for the header. diff --git a/kernel/src/arch/x86_64/asm/spinlock.c b/kernel/src/arch/x86_64/asm/spinlock.c deleted file mode 100644 index aaafe482..00000000 --- a/kernel/src/arch/x86_64/asm/spinlock.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include - -void __arch_spin_lock(spinlock_t *lock) -{ - __asm__ __volatile__("1: \n\t" - "lock decb %0 \n\t" // 尝试-1 - "jns 3f \n\t" // 加锁成功,跳转到步骤3 - "2: \n\t" // 加锁失败,稍后再试 - "pause \n\t" - "cmpb $0, %0 \n\t" - "jle 2b \n\t" // 若锁被占用,则继续重试 - "jmp 1b \n\t" // 尝试加锁 - "3:" - : "=m"(lock->lock)::"memory"); - rs_preempt_disable(); -} - -void __arch_spin_unlock(spinlock_t *lock) -{ - __asm__ __volatile__("movb $1, %0 \n\t" : "=m"(lock->lock)::"memory"); - rs_preempt_enable(); -} - -void __arch_spin_lock_no_preempt(spinlock_t *lock) -{ - __asm__ __volatile__("1: \n\t" - "lock decb %0 \n\t" // 尝试-1 - "jns 3f \n\t" // 加锁成功,跳转到步骤3 - "2: \n\t" // 加锁失败,稍后再试 - "pause \n\t" - "cmpb $0, %0 \n\t" - "jle 2b \n\t" // 若锁被占用,则继续重试 - "jmp 1b \n\t" // 尝试加锁 - "3:" - : "=m"(lock->lock)::"memory"); -} - -void __arch_spin_unlock_no_preempt(spinlock_t *lock) -{ - __asm__ __volatile__("movb $1, %0 \n\t" : "=m"(lock->lock)::"memory"); -} - -long __arch_spin_trylock(spinlock_t *lock) -{ - uint64_t tmp_val = 0; - rs_preempt_disable(); - // 交换tmp_val和lock的值,若tmp_val==1则证明加锁成功 - asm volatile("lock xchg %%bx, %1 \n\t" // 确保只有1个进程能得到锁 - : "=q"(tmp_val), "=m"(lock->lock) - : "b"(0) - : "memory"); - if (!tmp_val) - rs_preempt_enable(); - return tmp_val; -} diff --git a/kernel/src/arch/x86_64/driver/apic/c_adapter.rs b/kernel/src/arch/x86_64/driver/apic/c_adapter.rs deleted file mode 100644 index ca18d126..00000000 --- a/kernel/src/arch/x86_64/driver/apic/c_adapter.rs +++ /dev/null @@ -1,10 +0,0 @@ -use super::{CurrentApic, LocalAPIC}; - -#[no_mangle] -pub extern "C" fn rs_apic_init_ap() -> i32 { - if CurrentApic.init_current_cpu() { - return 0; - } - - return -1; -} diff --git a/kernel/src/arch/x86_64/driver/apic/mod.rs b/kernel/src/arch/x86_64/driver/apic/mod.rs index af89dedf..6e4050aa 100644 --- a/kernel/src/arch/x86_64/driver/apic/mod.rs +++ b/kernel/src/arch/x86_64/driver/apic/mod.rs @@ -21,7 +21,6 @@ use self::{ }; pub mod apic_timer; -mod c_adapter; pub mod hw_irq; pub mod ioapic; pub mod lapic_vector; diff --git a/kernel/src/arch/x86_64/driver/tsc.rs b/kernel/src/arch/x86_64/driver/tsc.rs index ef97ec6a..80dfee19 100644 --- a/kernel/src/arch/x86_64/driver/tsc.rs +++ b/kernel/src/arch/x86_64/driver/tsc.rs @@ -102,10 +102,7 @@ impl TSCManager { /// 使用pit、hpet、ptimer来测量CPU总线的频率 fn calibrate_cpu_by_pit_hpet_ptimer() -> Result { let hpet = is_hpet_enabled(); - debug!( - "Calibrating TSC with {}", - if hpet { "HPET" } else { "PMTIMER" } - ); + log_for_hpet(hpet); let mut tsc_pit_min = u64::MAX; let mut tsc_ref_min = u64::MAX; @@ -389,3 +386,12 @@ impl TSCManager { } } } + +/// # 从calibrate_cpu_by_pit_hpet_ptimer 解耦出,减少calibrate_cpu_by_pit_hpet_ptimer的栈帧 +#[inline(never)] +fn log_for_hpet(hpet: bool) { + debug!( + "Calibrating TSC with {}", + if hpet { "HPET" } else { "PMTIMER" } + ); +} diff --git a/kernel/src/arch/x86_64/filesystem/mod.rs b/kernel/src/arch/x86_64/filesystem/mod.rs new file mode 100644 index 00000000..4f22af63 --- /dev/null +++ b/kernel/src/arch/x86_64/filesystem/mod.rs @@ -0,0 +1 @@ +pub mod stat; diff --git a/kernel/src/arch/x86_64/filesystem/stat.rs b/kernel/src/arch/x86_64/filesystem/stat.rs new file mode 100644 index 00000000..9eec8d02 --- /dev/null +++ b/kernel/src/arch/x86_64/filesystem/stat.rs @@ -0,0 +1,72 @@ +use system_error::SystemError; + +use crate::filesystem::vfs::stat::KStat; + +#[repr(C)] +#[derive(Default, Clone, Copy)] +pub struct PosixStat { + pub st_dev: usize, + pub st_ino: usize, + pub st_nlink: usize, + pub st_mode: u32, + pub st_uid: u32, + pub st_gid: u32, + pub __pad0: u32, + pub st_rdev: usize, + pub st_size: isize, + pub st_blksize: isize, + /// number of 512B blocks allocated + pub st_blocks: isize, + pub st_atime: usize, + pub st_atime_nsec: usize, + pub st_mtime: usize, + pub st_mtime_nsec: usize, + pub st_ctime: usize, + pub st_ctime_nsec: usize, + pub __unused: [isize; 3], +} + +/// 转换的代码参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#393 +impl TryFrom for PosixStat { + type Error = SystemError; + + fn try_from(kstat: KStat) -> Result { + let mut tmp = PosixStat::default(); + if core::mem::size_of_val(&tmp.st_dev) < 4 && !kstat.dev.old_valid_dev() { + return Err(SystemError::EOVERFLOW); + } + if core::mem::size_of_val(&tmp.st_rdev) < 4 && !kstat.rdev.old_valid_dev() { + return Err(SystemError::EOVERFLOW); + } + + tmp.st_dev = kstat.dev.new_encode_dev() as usize; + tmp.st_ino = kstat.ino as usize; + + if core::mem::size_of_val(&tmp.st_ino) < core::mem::size_of_val(&kstat.ino) + && tmp.st_ino != kstat.ino as usize + { + return Err(SystemError::EOVERFLOW); + } + + tmp.st_mode = kstat.mode.bits(); + tmp.st_nlink = kstat.nlink.try_into().map_err(|_| SystemError::EOVERFLOW)?; + + // todo: 处理user namespace (https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#415) + tmp.st_uid = kstat.uid; + tmp.st_gid = kstat.gid; + + tmp.st_rdev = kstat.rdev.data() as usize; + tmp.st_size = kstat.size as isize; + + tmp.st_atime = kstat.atime.tv_sec as usize; + tmp.st_mtime = kstat.mtime.tv_sec as usize; + tmp.st_ctime = kstat.ctime.tv_sec as usize; + tmp.st_atime_nsec = kstat.atime.tv_nsec as usize; + tmp.st_mtime_nsec = kstat.mtime.tv_nsec as usize; + tmp.st_ctime_nsec = kstat.ctime.tv_nsec as usize; + tmp.st_blocks = kstat.blocks as isize; + tmp.st_blksize = kstat.blksize as isize; + + Ok(tmp) + } +} diff --git a/kernel/src/arch/x86_64/include/asm/apu_boot.h b/kernel/src/arch/x86_64/include/asm/apu_boot.h deleted file mode 100644 index 87957df5..00000000 --- a/kernel/src/arch/x86_64/include/asm/apu_boot.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#define APU_BOOT_TMP_STACK_SIZE 1024 diff --git a/kernel/src/arch/x86_64/include/asm/asm.h b/kernel/src/arch/x86_64/include/asm/asm.h deleted file mode 100644 index cb92daef..00000000 --- a/kernel/src/arch/x86_64/include/asm/asm.h +++ /dev/null @@ -1,410 +0,0 @@ -#pragma once - -#include -#include -#include - - - -#define sti() __asm__ __volatile__("sti\n\t" :: \ - : "memory") // 开启外部中断 -#define cli() __asm__ __volatile__("cli\n\t" :: \ - : "memory") // 关闭外部中断 -#define nop() __asm__ __volatile__("nop\n\t") -#define hlt() __asm__ __volatile__("hlt\n\t") -#define pause() asm volatile("pause\n\t"); // 处理器等待一段时间 - -// 内存屏障 -#define io_mfence() __asm__ __volatile__("mfence\n\t" :: \ - : "memory") // 在mfence指令前的读写操作必须在mfence指令后的读写操作前完成。 -#define io_sfence() __asm__ __volatile__("sfence\n\t" :: \ - : "memory") // 在sfence指令前的写操作必须在sfence指令后的写操作前完成 -#define io_lfence() __asm__ __volatile__("lfence\n\t" :: \ - : "memory") // 在lfence指令前的读操作必须在lfence指令后的读操作前完成。 - -/* - * Macros to generate condition code outputs from inline assembly, - * The output operand must be type "bool". - */ -// 如果编译器支持输出标志寄存器值到变量的话,则会定义__GCC_ASM_FLAG_OUTPUTS__ -#ifdef __GCC_ASM_FLAG_OUTPUTS__ -// CC_SET(c)则是用于设置标志寄存器中的某一位 -#define CC_SET(c) "\n\t/* output condition code " #c "*/\n" -// "=@cccond"的用法是,将标志寄存器中的cond(也就是指令集定义的标准条件)的值输出到变量中 -#define CC_OUT(c) "=@cc" #c -#else -#define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n" -#define CC_OUT(c) [_cc_##c] "=qm" -#endif - -#define rdtsc() ({ \ - uint64_t tmp1 = 0, tmp2 = 0; \ - asm volatile("rdtsc" \ - : "=d"(tmp1), "=a"(tmp2)::"memory"); \ - (tmp1 << 32 | tmp2); \ -}) - -/** - * @brief 读取rsp寄存器的值(存储了页目录的基地址) - * - * @return unsigned* rsp的值的指针 - */ -unsigned long *get_rsp() -{ - uint64_t *tmp; - __asm__ __volatile__( - "movq %%rsp, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} - -/** - * @brief 验证地址空间是否为用户地址空间 - * - * @param addr_start 地址起始值 - * @param length 地址长度 - * @return true - * @return false - */ -bool verify_area(uint64_t addr_start, uint64_t length) -{ - if ((addr_start + length) <= 0x00007fffffffffffUL) // 用户程序可用的的地址空间应<= 0x00007fffffffffffUL - return true; - else - return false; -} - -/** - * @brief 读取rbp寄存器的值(存储了页目录的基地址) - * - * @return unsigned* rbp的值的指针 - */ -unsigned long *get_rbp() -{ - uint64_t *tmp; - __asm__ __volatile__( - "movq %%rbp, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} - -/** - * @brief 读取ds寄存器的值(存储了页目录的基地址) - * - * @return unsigned* ds的值的指针 - */ -unsigned long *get_ds() -{ - uint64_t *tmp; - __asm__ __volatile__( - "movq %%ds, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} - -/** - * @brief 读取rax寄存器的值(存储了页目录的基地址) - * - * @return unsigned* rax的值的指针 - */ -unsigned long *get_rax() -{ - uint64_t *tmp; - __asm__ __volatile__( - "movq %%rax, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} -/** - * @brief 读取rbx寄存器的值(存储了页目录的基地址) - * - * @return unsigned* rbx的值的指针 - */ -unsigned long *get_rbx() -{ - uint64_t *tmp; - __asm__ __volatile__( - "movq %%rbx, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} - -uint64_t get_rflags() -{ - unsigned long tmp = 0; - __asm__ __volatile__("pushfq \n\t" - "movq (%%rsp), %0 \n\t" - "popfq \n\t" - : "=r"(tmp)::"memory"); - return tmp; -} - -void *memset(void *dst, unsigned char C, ul size) -{ - - int d0, d1; - unsigned long tmp = C * 0x0101010101010101UL; - __asm__ __volatile__("cld \n\t" - "rep \n\t" - "stosq \n\t" - "testb $4, %b3 \n\t" - "je 1f \n\t" - "stosl \n\t" - "1:\ttestb $2, %b3 \n\t" - "je 2f\n\t" - "stosw \n\t" - "2:\ttestb $1, %b3 \n\t" - "je 3f \n\t" - "stosb \n\t" - "3: \n\t" - : "=&c"(d0), "=&D"(d1) - : "a"(tmp), "q"(size), "0"(size / 8), "1"(dst) - : "memory"); - return dst; -} - -void *memset_c(void *dst, uint8_t c, size_t count) -{ - uint8_t *xs = (uint8_t *)dst; - - while (count--) - *xs++ = c; - - return dst; -} - -/** - * @brief 内存拷贝函数 - * - * @param dst 目标数组 - * @param src 源数组 - * @param Num 字节数 - * @return void* - */ -static void *memcpy(void *dst, const void *src, long Num) -{ - int d0 = 0, d1 = 0, d2 = 0; - __asm__ __volatile__("cld \n\t" - "rep \n\t" - "movsq \n\t" - "testb $4,%b4 \n\t" - "je 1f \n\t" - "movsl \n\t" - "1:\ttestb $2,%b4 \n\t" - "je 2f \n\t" - "movsw \n\t" - "2:\ttestb $1,%b4 \n\t" - "je 3f \n\t" - "movsb \n\t" - "3: \n\t" - : "=&c"(d0), "=&D"(d1), "=&S"(d2) - : "0"(Num / 8), "q"(Num), "1"(dst), "2"(src) - : "memory"); - return dst; -} - -// 从io口读入8个bit -unsigned char io_in8(unsigned short port) -{ - unsigned char ret = 0; - __asm__ __volatile__("inb %%dx, %0 \n\t" - "mfence \n\t" - : "=a"(ret) - : "d"(port) - : "memory"); - return ret; -} - -// 从io口读入32个bit -unsigned int io_in32(unsigned short port) -{ - unsigned int ret = 0; - __asm__ __volatile__("inl %%dx, %0 \n\t" - "mfence \n\t" - : "=a"(ret) - : "d"(port) - : "memory"); - return ret; -} - -// 输出8个bit到输出端口 -void io_out8(unsigned short port, unsigned char value) -{ - __asm__ __volatile__("outb %0, %%dx \n\t" - "mfence \n\t" - : - : "a"(value), "d"(port) - : "memory"); -} - -// 输出32个bit到输出端口 -void io_out32(unsigned short port, unsigned int value) -{ - __asm__ __volatile__("outl %0, %%dx \n\t" - "mfence \n\t" - : - : "a"(value), "d"(port) - : "memory"); -} - -/** - * @brief 从端口读入n个word到buffer - * - */ -#define io_insw(port, buffer, nr) \ - __asm__ __volatile__("cld;rep;insw;mfence;" ::"d"(port), "D"(buffer), "c"(nr) \ - : "memory") - -/** - * @brief 从输出buffer中的n个word到端口 - * - */ -#define io_outsw(port, buffer, nr) \ - __asm__ __volatile__("cld;rep;outsw;mfence;" ::"d"(port), "S"(buffer), "c"(nr) \ - : "memory") - -/** - * @brief 从用户空间搬运数据到内核空间 - * - * @param dst 目的地址 - * @param src 源地址 - * @param size 搬运的大小 - * @return uint64_t - */ -static inline uint64_t copy_from_user(void *dst, void *src, uint64_t size) -{ - uint64_t tmp0, tmp1; - if (!verify_area((uint64_t)src, size)) - return 0; - - /** - * @brief 先每次搬运8 bytes,剩余就直接一个个byte搬运 - * - */ - asm volatile("rep \n\t" - "movsq \n\t" - "movq %3, %0 \n\t" - "rep \n\t" - "movsb \n\t" - : "=&c"(size), "=&D"(tmp0), "=&S"(tmp1) - : "r"(size & 7), "0"(size >> 3), "1"(dst), "2"(src) - : "memory"); - return size; -} - -/** - * @brief 从内核空间搬运数据到用户空间 - * - * @param dst 目的地址 - * @param src 源地址 - * @param size 搬运的大小 - * @return uint64_t - */ -static inline uint64_t copy_to_user(void *dst, void *src, uint64_t size) -{ - if (verify_area((uint64_t)src, size)) - return 0; - - /** - * @brief 先每次搬运8 bytes,剩余就直接一个个byte搬运 - * - */ - // todo:编译有bug - // asm volatile("rep \n\t" - // "movsq \n\t" - // "movq %3, %0 \n\t" - // "rep \n\t" - // "movsb \n\t" - // : "=&c"(size), "=&D"(tmp0), "=&S"(tmp1) - // : "r"(size & 7), "0"(size >> 3), "1"(dst), "2"(src) - // : "memory"); - memcpy(dst, src, size); - - return size; -} - -/** - * @brief 往指定地址写入8字节 - * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候) - * - * @param vaddr 虚拟地址 - * @param value 要写入的值 - */ -static __always_inline void __write8b(uint64_t vaddr, uint64_t value) -{ - asm volatile("movq %%rdx, 0(%%rax)" ::"a"(vaddr), "d"(value) - : "memory"); -} - -/** - * @brief 往指定地址写入4字节 - * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候) - * - * @param vaddr 虚拟地址 - * @param value 要写入的值 - */ -static __always_inline void __write4b(uint64_t vaddr, uint32_t value) -{ - asm volatile("movl %%edx, 0(%%rax)" ::"a"(vaddr), "d"(value) - : "memory"); -} - -/** - * @brief 从指定地址读取8字节 - * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候) - * - * @param vaddr 虚拟地址 - * @return uint64_t 读取到的值 - */ -static __always_inline uint64_t __read8b(uint64_t vaddr) -{ - uint64_t retval; - asm volatile("movq 0(%%rax), %0" - : "=r"(retval) - : "a"(vaddr) - : "memory"); - return retval; -} - -/** - * @brief 从指定地址读取4字节 - * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候) - * - * @param vaddr 虚拟地址 - * @return uint64_t 读取到的值 - */ -static __always_inline uint32_t __read4b(uint64_t vaddr) -{ - uint32_t retval; - asm volatile("movl 0(%%rax), %0" - : "=d"(retval) - : "a"(vaddr) - : "memory"); - return retval; -} - - -/** - * @brief 逐字节比较指定内存区域的值,并返回s1、s2的第一个不相等的字节i处的差值(s1[i]-s2[i])。 - * 若两块内存区域的内容相同,则返回0 - * - * @param s1 内存区域1 - * @param s2 内存区域2 - * @param len 要比较的内存区域长度 - * @return int s1、s2的第一个不相等的字节i处的差值(s1[i]-s2[i])。若两块内存区域的内容相同,则返回0 - */ -static inline int memcmp(const void *s1, const void *s2, size_t len) -{ - int diff; - - asm("cld \n\t" // 复位DF,确保s1、s2指针是自增的 - "repz; cmpsb\n\t" CC_SET(nz) - : CC_OUT(nz)(diff), "+D"(s1), "+S"(s2) - : "c"(len) - : "memory"); - - if (diff) - diff = *(const unsigned char *)(s1 - 1) - *(const unsigned char *)(s2 - 1); - - return diff; -} diff --git a/kernel/src/arch/x86_64/include/asm/cmpxchg.h b/kernel/src/arch/x86_64/include/asm/cmpxchg.h deleted file mode 100644 index 6b7a5f5d..00000000 --- a/kernel/src/arch/x86_64/include/asm/cmpxchg.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once -#include -#include - -/** - * @brief 通过extern不存在的函数,来让编译器报错。以防止不符合要求的代码的产生。 - */ -extern void __cmpxchg_wrong_size(void) __compiletime_error("Bad argument size for cmpxchg"); - -// 定义常量:操作符涉及到的字节数 -#define __X86_CASE_B 1 -#define __X86_CASE_W 2 -#define __X86_CASE_L 4 -#define __X86_CASE_Q 8 - -/** - * @brief lock cmpxchg指令的包装。 - * 将_ptr指向的值与old_ptr指向的值做比较,如果相等,则将_new指向的值,加载到_ptr指向的值中。 - */ -#define __raw_try_cmpxchg(_ptr, _old_ptr, _new, size) \ - ({ \ - bool is_success = false; \ - typeof(_ptr) _old = (typeof(_ptr))(_old_ptr); \ - typeof(*(_ptr)) __old = *_old; \ - typeof(*(_ptr)) __new = (_new); \ - switch (size) \ - { \ - case __X86_CASE_B: \ - { \ - volatile uint8_t *__ptr = (volatile uint8_t *)(_ptr); \ - asm volatile("lock cmpxchgb %[new], %[ptr]\n\t" \ - : CC_OUT(z)(is_success), \ - [ptr] "+m"(*__ptr), \ - [old] "+a"(__old) \ - : [new] "q"(__new) \ - : "memory"); \ - break; \ - } \ - case __X86_CASE_W: \ - { \ - volatile uint16_t *__ptr = (volatile uint16_t *)(_ptr); \ - asm volatile("lock cmpxchgw %[new], %[ptr]\n\t" \ - : CC_OUT(z)(is_success), \ - [ptr] "+m"(*__ptr), \ - [old] "+a"(__old) \ - : [new] "q"(__new) \ - : "memory"); \ - break; \ - } \ - case __X86_CASE_L: \ - { \ - volatile uint32_t *__ptr = (volatile uint32_t *)(_ptr); \ - asm volatile("lock cmpxchgl %[new], %[ptr]\n\t" \ - : CC_OUT(z)(is_success), \ - [ptr] "+m"(*__ptr), \ - [old] "+a"(__old) \ - : [new] "q"(__new) \ - : "memory"); \ - break; \ - } \ - case __X86_CASE_Q: \ - { \ - volatile uint64_t *__ptr = (volatile uint64_t *)(_ptr); \ - asm volatile("lock cmpxchgq %[new], %[ptr]\n\t" \ - : CC_OUT(z)(is_success), \ - [ptr] "+m"(*__ptr), \ - [old] "+a"(__old) \ - : [new] "q"(__new) \ - : "memory"); \ - break; \ - } \ - default: \ - __cmpxchg_wrong_size(); \ - } \ - if (unlikely(is_success == false)) \ - *_old = __old; \ - likely(is_success); \ - }) - -#define arch_try_cmpxchg(ptr, old_ptr, new) \ - __raw_try_cmpxchg((ptr), (old_ptr), (new), sizeof(*ptr)) - -bool __try_cmpxchg_q(uint64_t *ptr, uint64_t *old_ptr, uint64_t *new_ptr); diff --git a/kernel/src/arch/x86_64/include/asm/irqflags.h b/kernel/src/arch/x86_64/include/asm/irqflags.h deleted file mode 100644 index 3886ba96..00000000 --- a/kernel/src/arch/x86_64/include/asm/irqflags.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include -// 保存当前rflags的值到变量x内并关闭中断 -#define local_irq_save(x) __asm__ __volatile__("pushfq ; popq %0 ; cli" \ - : "=g"(x)::"memory") -// 恢复先前保存的rflags的值x -#define local_irq_restore(x) __asm__ __volatile__("pushq %0 ; popfq" ::"g"(x) \ - : "memory") -#define local_irq_disable() cli(); -#define local_irq_enable() sti(); diff --git a/kernel/src/arch/x86_64/interrupt/entry.rs b/kernel/src/arch/x86_64/interrupt/entry.rs index 072ec4dd..64695fe8 100644 --- a/kernel/src/arch/x86_64/interrupt/entry.rs +++ b/kernel/src/arch/x86_64/interrupt/entry.rs @@ -294,6 +294,13 @@ interrupt_handler!(255); #[inline(never)] pub unsafe fn arch_setup_interrupt_gate() { + arch_setup_interrupt_gate_32_130(); + arch_setup_interrupt_gate_131_255(); +} + +/// # 从arch_setup_interrupt_gate()解耦出,避免函数体过大导致爆栈 +#[inline(never)] +unsafe fn arch_setup_interrupt_gate_32_130() { set_intr_gate(32, 0, VirtAddr::new(irq_handler32 as usize)); set_intr_gate(33, 0, VirtAddr::new(irq_handler33 as usize)); set_intr_gate(34, 0, VirtAddr::new(irq_handler34 as usize)); @@ -401,7 +408,11 @@ pub unsafe fn arch_setup_interrupt_gate() { set_intr_gate(127, 0, VirtAddr::new(irq_handler127 as usize)); set_intr_gate(129, 0, VirtAddr::new(irq_handler129 as usize)); set_intr_gate(130, 0, VirtAddr::new(irq_handler130 as usize)); +} +/// # 从arch_setup_interrupt_gate()解耦出,避免函数体过大导致爆栈 +#[inline(never)] +unsafe fn arch_setup_interrupt_gate_131_255() { set_intr_gate(131, 0, VirtAddr::new(irq_handler131 as usize)); set_intr_gate(132, 0, VirtAddr::new(irq_handler132 as usize)); set_intr_gate(133, 0, VirtAddr::new(irq_handler133 as usize)); diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index 25e9eed6..2fe4428c 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -20,7 +20,7 @@ use crate::{ mm::MemoryManagementArch, process::ProcessManager, sched::{schedule, SchedMode}, - syscall::{user_access::UserBufferWriter, Syscall}, + syscall::user_access::UserBufferWriter, }; /// 信号处理的栈的栈指针的最小对齐数量 @@ -556,8 +556,11 @@ impl SignalArch for X86_64SignalArch { // 如果当前的rsp不来自用户态,则认为产生了错误(或被SROP攻击) if UserBufferWriter::new(frame, size_of::(), true).is_err() { error!("rsp doesn't from user level"); - let _r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32) - .map_err(|e| e.to_posix_errno()); + let _r = crate::ipc::kill::kill_process( + ProcessManager::current_pcb().pid(), + Signal::SIGSEGV, + ) + .map_err(|e| e.to_posix_errno()); return trap_frame.rax; } let mut sigmask: SigSet = unsafe { (*frame).context.oldmask }; @@ -565,8 +568,11 @@ impl SignalArch for X86_64SignalArch { // 从用户栈恢复sigcontext if !unsafe { &mut (*frame).context }.restore_sigcontext(trap_frame) { error!("unable to restore sigcontext"); - let _r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32) - .map_err(|e| e.to_posix_errno()); + let _r = crate::ipc::kill::kill_process( + ProcessManager::current_pcb().pid(), + Signal::SIGSEGV, + ) + .map_err(|e| e.to_posix_errno()); // 如果这里返回 err 值的话会丢失上一个系统调用的返回值 } // 由于系统调用的返回值会被系统调用模块被存放在rax寄存器,因此,为了还原原来的那个系统调用的返回值,我们需要在这里返回恢复后的rax的值 @@ -658,9 +664,9 @@ fn setup_frame( ProcessManager::current_pcb().pid(), sig as i32 ); - let r = Syscall::kill( + let r = crate::ipc::kill::kill_process( ProcessManager::current_pcb().pid(), - Signal::SIGSEGV as i32, + Signal::SIGSEGV, ); if r.is_err() { error!("In setup_sigcontext: generate SIGSEGV signal failed"); @@ -698,7 +704,8 @@ fn setup_frame( if r.is_err() { // 如果地址区域位于内核空间,则直接报错 // todo: 生成一个sigsegv - let r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32); + let r = + crate::ipc::kill::kill_process(ProcessManager::current_pcb().pid(), Signal::SIGSEGV); if r.is_err() { error!("In setup frame: generate SIGSEGV signal failed"); } @@ -709,7 +716,10 @@ fn setup_frame( // 将siginfo拷贝到用户栈 info.copy_siginfo_to_user(unsafe { &mut ((*frame).info) as *mut SigInfo }) .map_err(|e| -> SystemError { - let r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32); + let r = crate::ipc::kill::kill_process( + ProcessManager::current_pcb().pid(), + Signal::SIGSEGV, + ); if r.is_err() { error!("In copy_siginfo_to_user: generate SIGSEGV signal failed"); } @@ -723,7 +733,10 @@ fn setup_frame( .context .setup_sigcontext(oldset, trap_frame) .map_err(|e: SystemError| -> SystemError { - let r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32); + let r = crate::ipc::kill::kill_process( + ProcessManager::current_pcb().pid(), + Signal::SIGSEGV, + ); if r.is_err() { error!("In setup_sigcontext: generate SIGSEGV signal failed"); } diff --git a/kernel/src/arch/x86_64/link.lds b/kernel/src/arch/x86_64/link.lds index 8c9ef16b..79c4d889 100644 --- a/kernel/src/arch/x86_64/link.lds +++ b/kernel/src/arch/x86_64/link.lds @@ -40,7 +40,7 @@ SECTIONS _etext = .; __etext = .; } - . = ALIGN(32768); + . = ALIGN(4096); data_start_pa = .; .data (data_start_pa): AT(data_start_pa - KERNEL_VMA) { @@ -51,7 +51,7 @@ SECTIONS _edata = .; } - . = ALIGN(32768); + . = ALIGN(4096); rodata_start_pa = .; .rodata (rodata_start_pa): AT(rodata_start_pa - KERNEL_VMA) @@ -65,8 +65,28 @@ SECTIONS _erodata = .; } - . = ALIGN(32768); + . = ALIGN(4096); + trace_point_start_pa = .; + .tracepoint (trace_point_start_pa): AT(trace_point_start_pa - KERNEL_VMA) + { + _tracepoint = .; + *(.tracepoint) + *(.tracepoint.*) + _etracepoint = .; + } + . = ALIGN(4096); + + syscall_table_start_pa = .; + .syscall_table (syscall_table_start_pa): AT(syscall_table_start_pa - KERNEL_VMA) + { + _syscall_table = .; + *(.syscall_table) + *(.syscall_table.*) + _esyscall_table = .; + } + + . = ALIGN(32768); init_proc_union_start_pa = .; .data.init_proc_union (init_proc_union_start_pa): AT(init_proc_union_start_pa - KERNEL_VMA) { *(.data.init_proc_union) } diff --git a/kernel/src/arch/x86_64/math/bitcount.h b/kernel/src/arch/x86_64/math/bitcount.h deleted file mode 100644 index dd2a154d..00000000 --- a/kernel/src/arch/x86_64/math/bitcount.h +++ /dev/null @@ -1,69 +0,0 @@ -#include - -/** - * @brief 统计二进制数的前导0 - * - * @param x 待统计的数 - * @return int 结果 - */ -static __always_inline int __clz(uint32_t x) -{ - asm volatile("bsr %%eax, %%eax\n\t" - "xor $0x1f, %%eax\n\t" - : "=a"(x) - : "a"(x) - : "memory"); - return x; -} - -/** - * @brief 统计二进制数的前导0 (宽度为unsigned long) - * - * @param x 待统计的数 - * @return int 结果 - */ -static __always_inline int __clzl(unsigned long x) -{ - int res = 0; - asm volatile("cltq\n\t" - "bsr %%rax, %%rax\n\t" - "xor $0x3f, %%rax\n\t" - "mov %%eax,%0\n\t" - : "=m"(res) - : "a"(x) - : "memory"); - return res; -} - -/** - * @brief 统计二进制数的前导0(宽度为unsigned long long) - * - * @param x 待统计的数 - * @return int 结果 - */ -static __always_inline int __clzll(unsigned long long x) -{ - int res = 0; - asm volatile("cltq\n\t" - "bsr %%rax, %%rax\n\t" - "xor $0x3f, %%rax\n\t" - "mov %%eax,%0\n\t" - : "=m"(res) - : "a"(x) - : "memory"); - return res; -} - -static __always_inline int __ctz(uint32_t x) -{ - asm volatile("tzcnt %%eax, %%eax":"=a"(x):"a"(x):"memory"); - return x; -} - -static __always_inline int __ctzl(unsigned long x) -{ - asm volatile("tzcnt %%rax, %%rax":"=a"(x):"a"(x):"memory"); - return x; -} - -#define __ctzll __ctzl \ No newline at end of file diff --git a/kernel/src/arch/x86_64/mm/fault.rs b/kernel/src/arch/x86_64/mm/fault.rs index e5521624..3122508a 100644 --- a/kernel/src/arch/x86_64/mm/fault.rs +++ b/kernel/src/arch/x86_64/mm/fault.rs @@ -1,9 +1,8 @@ +use alloc::sync::Arc; use core::{ intrinsics::{likely, unlikely}, panic, }; - -use alloc::sync::Arc; use log::error; use x86::{bits64::rflags::RFlags, controlregs::Cr4}; @@ -177,6 +176,10 @@ impl X86_64MMArch { error_code: X86PfErrorCode, address: VirtAddr, ) { + // log::debug!("fault at {:?}:{:?}", + // address, + // error_code, + // ); let rflags = RFlags::from_bits_truncate(regs.rflags); let mut flags: FaultFlags = FaultFlags::FAULT_FLAG_ALLOW_RETRY | FaultFlags::FAULT_FLAG_KILLABLE @@ -225,27 +228,28 @@ impl X86_64MMArch { flags |= FaultFlags::FAULT_FLAG_INSTRUCTION; } + let send_segv = || { + let pid = ProcessManager::current_pid(); + let mut info = SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid)); + Signal::SIGSEGV + .send_signal_info(Some(&mut info), pid) + .expect("failed to send SIGSEGV to process"); + }; + let current_address_space: Arc = AddressSpace::current().unwrap(); let mut space_guard = current_address_space.write_irqsave(); let mut fault; loop { let vma = space_guard.mappings.find_nearest(address); - // let vma = space_guard.mappings.contains(address); - let vma = match vma { Some(vma) => vma, None => { log::error!( - "can not find nearest vma, error_code: {:#b}, address: {:#x}", + "can not find nearest vma, error_code: {:?}, address: {:#x}", error_code, address.data(), ); - let pid = ProcessManager::current_pid(); - let mut info = - SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid)); - Signal::SIGSEGV - .send_signal_info(Some(&mut info), pid) - .expect("failed to send SIGSEGV to process"); + send_segv(); return; } }; @@ -256,38 +260,46 @@ impl X86_64MMArch { if !region.contains(address) { if vm_flags.contains(VmFlags::VM_GROWSDOWN) { + if !space_guard.can_extend_stack(region.start() - address) { + // exceeds stack limit + log::error!( + "stack limit exceeded, error_code: {:?}, address: {:#x}", + error_code, + address.data(), + ); + send_segv(); + return; + } space_guard .extend_stack(region.start() - address) .unwrap_or_else(|_| { panic!( - "user stack extend failed, error_code: {:#b}, address: {:#x}", + "user stack extend failed, error_code: {:?}, address: {:#x}", error_code, address.data(), ) }); } else { log::error!( - "No mapped vma, error_code: {:#b}, address: {:#x}, flags: {:?}", + "No mapped vma, error_code: {:?}, address: {:#x}, flags: {:?}", error_code, address.data(), flags ); - let pid = ProcessManager::current_pid(); - let mut info = - SigInfo::new(Signal::SIGSEGV, 0, SigCode::User, SigType::Kill(pid)); - Signal::SIGSEGV - .send_signal_info(Some(&mut info), pid) - .expect("failed to send SIGSEGV to process"); + log::error!("fault rip: {:#x}", regs.rip); + + send_segv(); return; } } if unlikely(Self::vma_access_error(vma.clone(), error_code)) { - panic!( - "vma access error, error_code: {:#b}, address: {:#x}", + log::error!( + "vma access error, error_code: {:?}, address: {:#x}", error_code, address.data(), ); + send_segv(); } let mapper = &mut space_guard.user_mapper.utable; let message = PageFaultMessage::new(vma.clone(), address, flags, mapper); diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index 94c13059..dc1ee339 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -5,9 +5,7 @@ pub mod pkru; use alloc::sync::Arc; use alloc::vec::Vec; -use hashbrown::HashSet; use log::{debug, info}; -use x86::time::rdtsc; use x86_64::registers::model_specific::EferFlags; use crate::driver::serial::serial8250::send_to_default_serial8250_port; @@ -548,16 +546,15 @@ unsafe fn allocator_init() { compiler_fence(Ordering::SeqCst); mapper.make_current(); compiler_fence(Ordering::SeqCst); - debug!("New page table enabled"); + //debug!("New page table enabled"); } debug!("Successfully enabled new page table"); } -#[no_mangle] -pub extern "C" fn rs_test_buddy() { - test_buddy(); -} +#[cfg(test)] pub fn test_buddy() { + use hashbrown::HashSet; + use x86::time::rdtsc; // 申请内存然后写入数据然后free掉 // 总共申请200MB内存 const TOTAL_SIZE: usize = 200 * 1024 * 1024; diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 73e1a10e..9ebac953 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -4,6 +4,7 @@ mod acpi; pub mod cpu; pub mod driver; pub mod elf; +pub mod filesystem; pub mod fpu; pub mod init; pub mod interrupt; @@ -48,3 +49,6 @@ pub use crate::arch::vm::x86_kvm_ops as kvm_arch_ops; pub use crate::arch::vm::kvm_host::vcpu::X86VcpuArch as VirtCpuArch; pub use crate::arch::vm::kvm_host::KvmVcpuStat as VirtCpuStat; + +pub fn panic_pre_work() {} +pub fn panic_post_work() {} diff --git a/kernel/src/arch/x86_64/process/syscall.rs b/kernel/src/arch/x86_64/process/syscall.rs index a10bd57d..698cf21d 100644 --- a/kernel/src/arch/x86_64/process/syscall.rs +++ b/kernel/src/arch/x86_64/process/syscall.rs @@ -53,6 +53,7 @@ impl Syscall { } /// ## 用于控制和查询与体系结构相关的进程特定选项 + /// https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/kernel/process_64.c#913 pub fn arch_prctl(option: usize, arg2: usize) -> Result { let pcb = ProcessManager::current_pcb(); if let Err(SystemError::EINVAL) = Self::do_arch_prctl_64(&pcb, option, arg2, true) { @@ -109,8 +110,17 @@ impl Syscall { } #[allow(dead_code)] - pub fn do_arch_prctl_common(_option: usize, _arg2: usize) -> Result { - todo!("do_arch_prctl_common not unimplemented"); + pub fn do_arch_prctl_common(option: usize, arg2: usize) -> Result { + // Don't use 0x3001-0x3004 because of old glibcs + if (0x3001..=0x3004).contains(&option) { + return Err(SystemError::EINVAL); + } + + todo!( + "do_arch_prctl_common not unimplemented, option: {}, arg2: {}", + option, + arg2 + ); } } diff --git a/kernel/src/arch/x86_64/process/table.rs b/kernel/src/arch/x86_64/process/table.rs index cbe5d787..40016d0b 100644 --- a/kernel/src/arch/x86_64/process/table.rs +++ b/kernel/src/arch/x86_64/process/table.rs @@ -16,7 +16,9 @@ pub const USER_DS: SegmentSelector = SegmentSelector::new(5, Ring::Ring3); /// 如果改这里,记得改syscall_64里面写死的常量 pub const USER_CS: SegmentSelector = SegmentSelector::new(6, Ring::Ring3); -static mut TSS_MANAGER: TSSManager = TSSManager::new(); +static mut TSS_MANAGER: TSSManager = TSSManager { + tss: [TaskStateSegment::new(); PerCpu::MAX_CPU_NUM as usize], +}; extern "C" { static mut GDT_Table: [u64; 512]; @@ -36,12 +38,6 @@ pub struct TSSManager { } impl TSSManager { - const fn new() -> Self { - return Self { - tss: [TaskStateSegment::new(); PerCpu::MAX_CPU_NUM as usize], - }; - } - /// 获取当前CPU的TSS pub unsafe fn current_tss() -> &'static mut TaskStateSegment { &mut TSS_MANAGER.tss[smp_get_processor_id().data() as usize] diff --git a/kernel/src/arch/x86_64/smp/mod.rs b/kernel/src/arch/x86_64/smp/mod.rs index eec877b8..1963df1c 100644 --- a/kernel/src/arch/x86_64/smp/mod.rs +++ b/kernel/src/arch/x86_64/smp/mod.rs @@ -151,11 +151,16 @@ pub struct X86_64SmpManager { } impl X86_64SmpManager { - pub const fn new() -> Self { + /// 创建一个新的X86_64SmpManager实例 + /// + /// 注:由于该函数只在编译时被调用,因此 `#[allow(clippy::large_stack_frames)]` 是安全的。 + #[allow(clippy::large_stack_frames)] + const fn new() -> Self { return Self { ia64_cpu_to_sapicid: RwLock::new([None; PerCpu::MAX_CPU_NUM as usize]), }; } + /// initialize the logical cpu number to APIC ID mapping pub fn build_cpu_map(&self) -> Result<(), SystemError> { // 参考:https://code.dragonos.org.cn/xref/linux-6.1.9/arch/ia64/kernel/smpboot.c?fi=smp_build_cpu_map#496 diff --git a/kernel/src/arch/x86_64/syscall/mod.rs b/kernel/src/arch/x86_64/syscall/mod.rs index cc475699..92817d4e 100644 --- a/kernel/src/arch/x86_64/syscall/mod.rs +++ b/kernel/src/arch/x86_64/syscall/mod.rs @@ -90,7 +90,7 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { mfence(); let pid = ProcessManager::current_pcb().pid(); let show = false; - // let show = if syscall_num != SYS_SCHED && pid.data() >= 7 { + // let show = if syscall_num != SYS_SCHED && pid.data() >= 9{ // true // } else { // false @@ -120,16 +120,8 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { _ => {} } let mut syscall_handle = || -> u64 { - #[cfg(feature = "backtrace")] - { - Syscall::catch_handle(syscall_num, &args, frame) - .unwrap_or_else(|e| e.to_posix_errno() as usize) as u64 - } - #[cfg(not(feature = "backtrace"))] - { - Syscall::handle(syscall_num, &args, frame) - .unwrap_or_else(|e| e.to_posix_errno() as usize) as u64 - } + Syscall::catch_handle(syscall_num, &args, frame) + .unwrap_or_else(|e| e.to_posix_errno() as usize) as u64 }; syscall_return!(syscall_handle(), frame, show); } diff --git a/kernel/src/arch/x86_64/vm/vmx/mod.rs b/kernel/src/arch/x86_64/vm/vmx/mod.rs index e6e361c7..90360950 100644 --- a/kernel/src/arch/x86_64/vm/vmx/mod.rs +++ b/kernel/src/arch/x86_64/vm/vmx/mod.rs @@ -3743,8 +3743,12 @@ pub static L1TF_VMX_MITIGATION: RwLock = RwLock::new(VmxL1dFlu pub fn vmx_init() -> Result<(), SystemError> { let cpuid = CpuId::new(); - let cpu_feat = cpuid.get_feature_info().ok_or(SystemError::ENOSYS)?; + let cpu_feat = cpuid.get_feature_info().ok_or_else(|| { + log::warn!("Failed to get CPU feature info, perhaps not AMD or Intel CPU"); + SystemError::ENOSYS + })?; if !cpu_feat.has_vmx() { + log::warn!("VMX not supported or enabled"); return Err(SystemError::ENOSYS); } diff --git a/kernel/src/common/asm.h b/kernel/src/common/asm.h index 7220c6f9..ba51cc8c 100644 --- a/kernel/src/common/asm.h +++ b/kernel/src/common/asm.h @@ -2,22 +2,16 @@ #ifndef __ASM__ #define __ASM__ - +#define APU_BOOT_TMP_STACK_SIZE 1024 // 符号名 -#define SYMBOL_NAME(X) X +#define SYMBOL_NAME(X) X // 符号名字符串 -#define SYMBOL_NAME_STR(X) #X +#define SYMBOL_NAME_STR(X) #X // 符号名label #define SYMBOL_NAME_LABEL(X) X##: -#define L1_CACHE_BYTES 32 +#define ENTRY(name) \ + .global SYMBOL_NAME(name); \ + SYMBOL_NAME_LABEL(name) -#define asmlinkage __attribute__((regparm(0))) - -#define ____cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES))) - -#define ENTRY(name) \ -.global SYMBOL_NAME(name); \ -SYMBOL_NAME_LABEL(name) - -#endif \ No newline at end of file +#endif diff --git a/kernel/src/common/atomic.h b/kernel/src/common/atomic.h deleted file mode 100644 index 1488a7ea..00000000 --- a/kernel/src/common/atomic.h +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @file atomic.h - * @author fslongjin (longjin@RinGoTek.cn) - * @brief 原子变量 - * @version 0.1 - * @date 2022-04-12 - * - * @copyright Copyright (c) 2022 - * - */ -#pragma once -#if ARCH(I386) || ARCH(X86_64) - -#include - -#define atomic_read(atomic) ((atomic)->value) // 读取原子变量 -#define atomic_set(atomic, val) (((atomic)->value) = (val)) // 设置原子变量的初始值 - -typedef struct -{ - volatile long value; -} atomic_t; - -/** - * @brief 原子变量增加值 - * - * @param ato 原子变量对象 - * @param val 要增加的值 - */ -inline void atomic_add(atomic_t *ato, long val) -{ - asm volatile("lock addq %1, %0 \n\t" - : "=m"(ato->value) - : "m"(val) - : "memory"); -} - -/** - * @brief 原子变量减少值 - * - * @param ato 原子变量对象 - * @param val 要减少的值 - */ -inline void atomic_sub(atomic_t *ato, long val) -{ - asm volatile("lock subq %1, %0 \n\t" - : "=m"(ato->value) - : "m"(val) - : "memory"); -} - -/** - * @brief 原子变量自增 - * - * @param ato 原子变量对象 - */ -void atomic_inc(atomic_t *ato) -{ - asm volatile("lock incq %0 \n\t" - : "=m"(ato->value) - : "m"(ato->value) - : "memory"); -} - -/** - * @brief 原子变量自减 - * - * @param ato 原子变量对象 - */ -void atomic_dec(atomic_t *ato) -{ - asm volatile("lock decq %0 \n\t" - : "=m"(ato->value) - : "m"(ato->value) - : "memory"); -} - -/** - * @brief 设置原子变量的mask - * - * @param ato 原子变量对象 - */ -inline void atomic_set_mask(atomic_t *ato, long mask) -{ - __asm__ __volatile__("lock orq %1, %0 \n\t" - : "=m"(ato->value) - : "r"(mask) - : "memory"); -} - -/** - * @brief 清除原子变量的mask - * - * @param ato 原子变量对象 - */ -inline void atomic_clear_mask(atomic_t *ato, long mask) -{ - __asm__ __volatile__("lock andq %1, %0 \n\t" - : "=m"(ato->value) - : "r"(mask) - : "memory"); -} - -// cmpxchgq 比较并交换 -inline long atomic_cmpxchg(atomic_t *ato, long oldval, long newval) -{ - bool success = arch_try_cmpxchg(&ato->value, &oldval, newval); - return success ? oldval : newval; -} -#endif \ No newline at end of file diff --git a/kernel/src/common/compiler.h b/kernel/src/common/compiler.h deleted file mode 100644 index 46288165..00000000 --- a/kernel/src/common/compiler.h +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once - -#include - -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) - -#ifndef barrier -// 内存屏障 -#define barrier() __asm__ __volatile__("" :: \ - : "memory"); -#endif - -/** - * @brief 编译时断言,如果condition不为1,则输出msg - * - * @param prefix 一个“不存在的函数名”的前缀 - * @param suffix 一个“不存在的函数名”的后缀 - */ -#define __compiletime_assert(condition, msg, prefix, suffix) \ - do \ - { \ - /** \ - * 声明一个不存在的函数的extern,如果assert失败,就调用它,从而导致 \ - * 链接时出错,进而达到“编译时断言”的功能。 \ - */ \ - __noreturn extern void prefix##suffix(void) \ - __compiletime_error(msg); \ - if (!(condition)) \ - prefix##suffix(); \ - } while (0) - -/** - * @brief 当condition是false时,中断编译,并输出指定的错误信息 - * - * @param condition assert的情况 - * @param msg condition为false时输出的错误信息 - */ -#define complietime_assert(condition, msg) \ - __compiletime_assert(condition, msg, __compiletime_assert__, __COUNTER__) - -/** - * @brief 从src读取数据到dst,该过程避免编译器优化。 - * - * @param dst 目标地址指针 - * @param src 源地址指针 - * @param size 要读取的数据大小(建议1、2、4、8字节,若不满足要求,则采用memcpy读取。) - */ -static __always_inline void __read_once_size(void *dst, const volatile void *src, int size) -{ - switch (size) - { - case 1: - *(__u8_alias_t *)dst = *(volatile __u8_alias_t *)src; - break; - case 2: - *(__u16_alias_t *)dst = *(volatile __u16_alias_t *)src; - break; - case 4: - *(__u32_alias_t *)dst = *(volatile __u32_alias_t *)src; - break; - case 8: - *(__u64_alias_t *)dst = *(volatile __u64_alias_t *)src; - break; - default: - barrier(); - __builtin_memcpy((void *)dst, (const void *)src, size); - barrier(); - break; - } -} - -/** - * @brief 把src处的数据到dst,该过程避免编译器优化。 - * - * @param dst 目标地址指针 - * @param src 源地址指针 - * @param size 要写入的数据大小(建议1、2、4、8字节,若不满足要求,则采用memcpy传输。) - */ -static __always_inline void __write_once_size(volatile void *dst, void *src, int size) -{ - switch (size) - { - case 1: - *(volatile __u8_alias_t *)dst = *(__u8_alias_t *)src; - break; - case 2: - *(volatile __u16_alias_t *)dst = *(__u16_alias_t *)src; - break; - case 4: - *(volatile __u32_alias_t *)dst = *(__u32_alias_t *)src; - break; - case 8: - *(volatile __u64_alias_t *)dst = *(__u64_alias_t *)src; - break; - default: - barrier(); - __builtin_memcpy((void *)dst, (const void *)src, size); - barrier(); - break; - } -} - -/** - * 这两个宏能够避免编译器重排序、合并涉及到的读写操作,从而避免由于编译器优化导致的多线程读写顺序错误。 - * 通过将有顺序要求的两个读/写操作放置在READ_ONCE()和WRITE_ONCE()之中,能够让编译器知道这些操作具有顺序要求。 - * - * 这两个宏同样适用于Union或struct。如果要访问的数据大小不是1、2、4、8字节,则会使用memcpy来处理。 - * - * 这两个宏的主要使用场景: - * 1.两个进程或者中断处理函数之间的信息交流与沟通 - * 2.确保编译器不会折叠、旋转或以其他方式对代码进行优化,从而破坏数据访问顺序。 - * - * 这两个宏的union __u内的__c用作这个union的地址的指针 - * - * 关于READ_ONCE和WRITE_ONCE的简单说明,请转到:https://bbs.dragonos.org/forum.php?mod=viewthread&tid=24 - */ - -/** - * @brief 读取变量x (避免编译器优化) - */ -#define READ_ONCE(x) \ - ({ \ - union \ - { \ - typeof(x) __val; \ - char __c[1]; \ - } __u = {.__c = {0}}; \ - __read_once_size(__u.__c, &(x), sizeof(x)); \ - __u.__val; \ - }) - -/** - * @brief 将val写入变量x (避免编译器优化) - */ -#define WRITE_ONCE(x, val) \ - ({ \ - union \ - { \ - typeof(x) __val; \ - char __c[1]; \ - } __u = {.val = (val)}; \ - __write_once_size(&(x), __u.__c, sizeof(x)); \ - __u.__val; \ - }) diff --git a/kernel/src/common/compiler_attributes.h b/kernel/src/common/compiler_attributes.h deleted file mode 100644 index 12278be6..00000000 --- a/kernel/src/common/compiler_attributes.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include - -// 当函数的返回值未被使用时,编译器抛出警告信息 -#define __must_check __attribute__((__warn_unused_result__)) -#define __force __attribute__((force)) -// 无返回值的属性 -#define __noreturn __attribute__((__noreturn__)) -/* - * Optional: only supported since clang >= 14.0 - * - * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-error-function-attribute - */ -#if __has_attribute(__error__) -#define __compiletime_error(msg) __attribute__((__error__(msg))) -#else -#define __compiletime_error(msg) -#endif - -typedef uint8_t __attribute__((__may_alias__)) __u8_alias_t; -typedef uint16_t __attribute__((__may_alias__)) __u16_alias_t; -typedef uint32_t __attribute__((__may_alias__)) __u32_alias_t; -typedef uint64_t __attribute__((__may_alias__)) __u64_alias_t; \ No newline at end of file diff --git a/kernel/src/common/dirent.h b/kernel/src/common/dirent.h deleted file mode 100644 index ee02b343..00000000 --- a/kernel/src/common/dirent.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include -struct dirent -{ - ino_t d_ino; // 文件序列号 - off_t d_off; // dir偏移量 - unsigned short d_reclen; // 目录下的记录数 - unsigned char d_type; // entry的类型 - char d_name[]; // 文件entry的名字(是一个零长度的数组) -}; diff --git a/kernel/src/common/err.h b/kernel/src/common/err.h deleted file mode 100644 index 20fb2d00..00000000 --- a/kernel/src/common/err.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include -#include -#define MAX_ERRNO 4095 - -#define IS_ERR_VALUE(x) unlikely((x) >= (uint64_t)-MAX_ERRNO) - -/** - * @brief 判断返回的指针是否为errno - * - * @param ptr 待校验的指针 - * @return long 1 => 是错误码 - * 0 => 不是错误码 - */ -static inline long __must_check IS_ERR(const void* ptr) -{ - return IS_ERR_VALUE((uint64_t)ptr); -} - -/** - * @brief 判断返回的指针是否为errno或者为空 - * - * @param ptr 待校验的指针 - * @return long 1 => 是错误码或NULL - * 0 => 不是错误码或NULL - */ -static inline long __must_check IS_ERR_OR_NULL(const void* ptr) -{ - return !ptr || IS_ERR_VALUE((uint64_t)ptr); -} - -/** - * @brief 将错误码转换为指针 - * - * @param error 错误码 - * @return void* 转换后的指针 - */ -static inline void* __must_check ERR_PTR(long error) -{ - return (void*)(error); -} - -static inline long __must_check PTR_ERR(void * ptr) -{ - return (long)ptr; -} \ No newline at end of file diff --git a/kernel/src/common/errno.h b/kernel/src/common/errno.h deleted file mode 100644 index ca0de1c3..00000000 --- a/kernel/src/common/errno.h +++ /dev/null @@ -1,145 +0,0 @@ -/** - * @file errno.h - * @author fslongjin (longjin@RinGoTek.cn) - * @brief - * @version 0.1 - * @date 2022-04-22 - * - * @copyright Copyright (c) 2022 - * - */ -#pragma once -#define EPERM 1 /* 操作不被允许 Operation not permitted. */ -#define ENOENT 2 /* 没有指定的文件或目录 No such file or directory. */ -#define ESRCH 3 /* 没有这样的进程 No such process. */ -#define EINTR 4 /* 被中断的函数 Interrupted function. */ -#define EIO 5 /* I/O错误 I/O error. */ -#define ENXIO 6 /* 没有这样的设备或地址 No such device or address. */ -#define E2BIG 7 /* 参数列表过长,或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */ -#define ENOEXEC 8 /* 可执行文件格式错误 Executable file format error */ -#define EBADF 9 /* 错误的文件描述符 Bad file descriptor. */ -#define ECHILD 10 /* 没有子进程 No child processes. */ -#define EAGAIN 11 /* 资源不可用,请重试。 Resource unavailable try again.(may be the same value as [EWOULDBLOCK]) */ -#define EWOULDBLOCK 11 /* 操作将被禁止 Operation would block.(may be the same value as [EAGAIN]). */ -#define ENOMEM 12 /* 没有足够的空间 Not enough space. */ -#define EACCES 13 /* 访问被拒绝 Permission denied */ -#define EFAULT 14 /* 错误的地址 Bad address */ -#define ENOTBLK 15 /* 需要块设备 Block device required */ -#define EBUSY 16 /* 设备或资源忙 Device or resource busy. */ -#define EEXIST 17 /* 文件已存在 File exists. */ -#define EXDEV 18 /* 跨设备连接 Cross-device link. */ -#define ENODEV 19 /* 没有指定的设备 No such device. */ -#define ENOTDIR 20 /* 不是目录 Not a directory. */ -#define EISDIR 21 /* 是一个目录 Is a directory */ -#define EINVAL 22 /* 不可用的参数 Invalid argument. */ -#define ENFILE 23 /* 系统中打开的文件过多 Too many files open in system. */ -#define EMFILE 24 /* 文件描述符的值过大 File descriptor value too large. */ -#define ENOTTY 25 /* 不正确的I/O控制操作 Inappropriate I/O control operation. */ -#define ETXTBSY 26 /* 文本文件忙 Text file busy. */ -#define EFBIG 27 /* 文件太大 File too large. */ -#define ENOSPC 28 /* 设备上没有空间 No space left on device. */ -#define ESPIPE 29 /* 错误的寻道.当前文件是pipe,不允许seek请求 Invalid seek. */ -#define EROFS 30 /* 只读的文件系统 Read-only file system. */ -#define EMLINK 31 /* 链接数过多 Too many links. */ -#define EPIPE 32 /* 断开的管道 Broken pipe. */ -#define EDOM 33 /* 数学参数超出作用域 Mathematics argument out of domain of function. */ -#define ERANGE 34 /* 结果过大 Result too large. */ -#define EDEADLK 35 /* 资源死锁将要发生 Resource deadlock would occur. */ -#define ENAMETOOLONG 36 /* 文件名过长 Filename too long. */ -#define ENOLCK 37 /* 没有可用的锁 No locks available. */ -#define ENOSYS 38 /* 功能不支持 Function not supported. */ -#define ENOTEMPTY 39 /* 目录非空 Directory not empty. */ -#define ELOOP 40 /* 符号链接级别过多 Too many levels of symbolic links. */ -#define ENOMSG 42 /* 没有期待类型的消息 No message of the desired type. */ -#define EIDRM 43 /* 标志符被移除 Identifier removed. */ -#define ECHRNG 44 /* 通道号超出范围 Channel number out of range */ -#define EL2NSYNC 45 /* 二级不同步 Level 2 not synchronized */ -#define EL3HLT 46 /* 三级暂停 Level 3 halted */ -#define EL3RST 47 /* 三级重置 Level 3 reset */ -#define ELNRNG 48 /* 链接号超出范围 Link number out of range */ -#define EUNATCH 49 /* 未连接协议驱动程序 Protocol driver not attached */ -#define ENOCSI 50 /* 没有可用的CSI结构 No CSI structure available */ -#define EL2HLT 51 /* 二级暂停 Level 2 halted */ -#define EBADE 52 /* 无效交换 Invalid exchange */ -#define EBADR 53 /* 无效的请求描述符 Invalid request descriptor */ -#define EXFULL 54 /* 交换满 Exchange full */ -#define ENOANO 55 /* 无阳极 No anode */ -#define EBADRQC 56 /* 请求码无效 Invalid request code */ -#define EBADSLT 57 /* 无效插槽 Invalid slot */ -#define EDEADLOCK EDEADLK /* 资源死锁 Resource deadlock would occur */ -#define EBFONT 59 /* 错误的字体文件格式 Bad font file format */ -#define ENOSTR 60 /* 不是STREAM Not a STREAM */ -#define ENODATA 61 /* 队列头没有可读取的消息 No message is available on the STREAM head read queue. */ -#define ETIME 62 /* 流式ioctl()超时 Stream ioctl() timeout */ -#define ENOSR 63 /* 没有STREAM资源 No STREAM resources. */ -#define ENONET 64 /* 机器不在网络上 Machine is not on the network */ -#define ENOPKG 65 /* 未安装软件包 Package not installed */ -#define EREMOTE 66 /* 远程对象 Object is remote */ -#define ENOLINK 67 /* 保留 Reserved. */ -#define EADV 68 /* 外设错误 Advertise error. */ -#define ESRMNT 69 /* 安装错误 Srmount error */ -#define ECOMM 70 /* 发送时发生通信错误 Communication error on send */ -#define EPROTO 71 /* 协议错误 Protocol error. */ -#define EMULTIHOP 72 /* 保留使用 Reserved. */ -#define EDOTDOT 73 /* RFS特定错误 RFS specific error */ -#define EBADMSG 74 /* 错误的消息 Bad message. */ -#define EOVERFLOW 75 /* 数值过大,产生溢出 Value too large to be stored in data type. */ -#define ENOTUNIQ 76 /* 名称在网络上不是唯一的 Name not unique on network */ -#define EBADFD 77 /* 处于不良状态的文件描述符 File descriptor in bad state */ -#define EREMCHG 78 /* 远程地址已更改 Remote address changed */ -#define ELIBACC 79 /* 无法访问所需的共享库 Can not access a needed shared library */ -#define ELIBBAD 80 /* 访问损坏的共享库 Accessing a corrupted shared library */ -#define ELIBSCN 81 /* a. out中的.lib部分已损坏 .lib section in a.out corrupted */ -#define ELIBMAX 82 /* 尝试链接太多共享库 Attempting to link in too many shared libraries */ -#define ELIBEXEC 83 /* 无法直接执行共享库 Cannot exec a shared library directly */ -#define EILSEQ 84 /* 不合法的字符序列 Illegal byte sequence. */ -#define ERESTART 85 /* 中断的系统调用应该重新启动 Interrupted system call should be restarted */ -#define ESTRPIPE 86 /* 流管道错误 Streams pipe error */ -#define EUSERS 87 /* 用户太多 Too many users */ -#define ENOTSOCK 88 /* 不是一个套接字 Not a socket. */ -#define EDESTADDRREQ 89 /* 需要目标地址 Destination address required. */ -#define EMSGSIZE 90 /* 消息过大 Message too large. */ -#define EPROTOTYPE 91 /* 对于套接字而言,错误的协议 Protocol wrong type for socket. */ -#define ENOPROTOOPT 92 /* 协议不可用 Protocol not available. */ -#define EPROTONOSUPPORT 93 /* 协议不被支持 Protocol not supported. */ -#define ESOCKTNOSUPPORT 94 /* 不支持套接字类型 Socket type not supported */ -#define EOPNOTSUPP 95 /* 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]). */ -#define ENOTSUP EOPNOTSUPP /* 不被支持 Not supported (may be the same value as [EOPNOTSUPP]). */ -#define EPFNOSUPPORT 96 /* 不支持协议系列 Protocol family not supported */ -#define EAFNOSUPPORT 97 /* 地址family不支持 Address family not supported. */ -#define EADDRINUSE 98 /* 地址正在被使用 Address in use. */ -#define EADDRNOTAVAIL 99 /* 地址不可用 Address not available. */ -#define ENETDOWN 100 /* 网络已关闭 Network is down. */ -#define ENETUNREACH 101 /* 网络不可达 Network unreachable. */ -#define ENETRESET 102 /* 网络连接已断开 Connection aborted by network. */ -#define ECONNABORTED 103 /* 连接已断开 Connection aborted. */ -#define ECONNRESET 104 /* 连接被重置 Connection reset. */ -#define ENOBUFS 105 /* 缓冲区空间不足 No buffer space available. */ -#define EISCONN 106 /* 套接字已连接 Socket is connected. */ -#define ENOTCONN 107 /* 套接字未连接 The socket is not connected. */ -#define ESHUTDOWN 108 /* 传输端点关闭后无法发送 Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 109 /* 引用太多:无法拼接 Too many references: cannot splice */ -#define ETIMEDOUT 110 /* 连接超时 Connection timed out. */ -#define ECONNREFUSED 111 /* 连接被拒绝 Connection refused. */ -#define EHOSTDOWN 112 /* 主机已关闭 Host is down */ -#define EHOSTUNREACH 113 /* 主机不可达 Host is unreachable. */ -#define EALREADY 114 /* 连接已经在处理 Connection already in progress. */ -#define EINPROGRESS 115 /* 操作正在处理 Operation in progress. */ -#define ESTALE 116 /* 保留 Reserved. */ -#define EUCLEAN 117 /* 结构需要清理 Structure needs cleaning */ -#define ENOTNAM 118 /* 不是XENIX命名类型文件 Not a XENIX named type file */ -#define ENAVAIL 119 /* 没有可用的XENIX信号量 No XENIX semaphores available */ -#define EISNAM 120 /* 是命名类型文件 Is a named type file */ -#define EREMOTEIO 121 /* 远程I/O错误 Remote I/O error */ -#define EDQUOT 122 /* 保留使用 Reserved */ -#define ENOMEDIUM 123 /* 没有找到媒介 No medium found */ -#define EMEDIUMTYPE 124 /* 介质类型错误 Wrong medium type */ -#define ECANCELED 125 /* 操作被取消 Operation canceled. */ -#define ENOKEY 126 /* 所需的密钥不可用 Required key not available */ -#define EKEYEXPIRED 127 /* 密钥已过期 Key has expired */ -#define EKEYREVOKED 128 /* 密钥已被撤销 Key has been revoked */ -#define EKEYREJECTED 129 /* 密钥被服务拒绝 Key has been revoked */ -#define EOWNERDEAD 130 /* 之前的拥有者挂了 Previous owner died. */ -#define ENOTRECOVERABLE 131 /* 状态不可恢复 State not recoverable. */ -#define ERFKILL 132 /* 由于射频终止,无法操作 Operation not possible due to RF-kill */ -#define EHWPOISON 132 /* 内存页面有硬件错误 Memory page has hardware error */ diff --git a/kernel/src/common/fcntl.h b/kernel/src/common/fcntl.h deleted file mode 100644 index ab25668f..00000000 --- a/kernel/src/common/fcntl.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file fcntl.h - * @author fslongjin (longjin@RinGoTek.cn) - * @brief - * @version 0.1 - * @date 2022-04-26 - * - * @copyright Copyright (c) 2022 - * - */ -#pragma once - -#define O_RDONLY 00000000 // Open Read-only -#define O_WRONLY 00000001 // Open Write-only -#define O_RDWR 00000002 // Open read/write -#define O_ACCMODE 00000003 // Mask for file access modes - -#define O_CREAT 00000100 // Create file if it does not exist -#define O_EXCL 00000200 // Fail if file already exists -#define O_NOCTTY 00000400 // Do not assign controlling terminal - -#define O_TRUNC 00001000 // 文件存在且是普通文件,并以O_RDWR或O_WRONLY打开,则它会被清空 - -#define O_APPEND 00002000 // 文件指针会被移动到文件末尾 - -#define O_NONBLOCK 00004000 // 非阻塞式IO模式 - -#define O_DSYNC 00010000 // used to be O_SYNC, see below -#define FASYNC 00020000 // fcntl, for BSD compatibility -#define O_DIRECT 00040000 // direct disk access hint -#define O_LARGEFILE 00100000 -#define O_DIRECTORY 00200000 // 打开的必须是一个目录 -#define O_NOFOLLOW 00400000 // Do not follow symbolic links -#define O_NOATIME 01000000 -#define O_CLOEXEC 02000000 // set close_on_exec - -/* - * The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is - * meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to - * unlinkat. The two functions do completely different things and therefore, - * the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to - * faccessat would be undefined behavior and thus treating it equivalent to - * AT_EACCESS is valid undefined behavior. - */ -// 作为当前工作目录的文件描述符(用于指代cwd) -#define AT_FDCWD -100 -#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ -#define AT_EACCESS 0x200 /* Test access permitted for effective IDs, not real IDs. */ -#define AT_REMOVEDIR 0x200 /* Remove directory instead of unlinking file. */ -#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ -#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ -#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ - -#define AT_STATX_SYNC_TYPE 0x6000 /* Type of synchronisation required from statx() */ -#define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */ -#define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */ -#define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */ - -#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */ \ No newline at end of file diff --git a/kernel/src/common/glib.h b/kernel/src/common/glib.h deleted file mode 100644 index 1725cbd6..00000000 --- a/kernel/src/common/glib.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// 内核全局通用库 -// Created by longjin on 2022/1/22. -// - -#pragma once - -// 引入对bool类型的支持 -#include -#include -#include -#include -#include - -#include - -/** - * @brief 根据结构体变量内某个成员变量member的基地址,计算出该结构体变量的基地址 - * @param ptr 指向结构体变量内的成员变量member的指针 - * @param type 成员变量所在的结构体 - * @param member 成员变量名 - * - * 方法:使用ptr减去结构体内的偏移,得到结构体变量的基地址 - */ -#define container_of(ptr, type, member) \ - ({ \ - typeof(((type *)0)->member) *p = (ptr); \ - (type *)((unsigned long)p - (unsigned long)&(((type *)0)->member)); \ - }) - -#define ABS(x) ((x) > 0 ? (x) : -(x)) // 绝对值 -// 最大最小值 -#define max(x, y) ((x > y) ? (x) : (y)) -#define min(x, y) ((x < y) ? (x) : (y)) - -// 遮罩高32bit -#define MASK_HIGH_32bit(x) (x & (0x00000000ffffffffUL)) - -// 四舍五入成整数 -ul round(double x) { return (ul)(x + 0.5); } - -/** - * @brief 地址按照align进行对齐 - * - * @param addr - * @param _align - * @return ul 对齐后的地址 - */ -static __always_inline ul ALIGN(const ul addr, const ul _align) { - return (ul)((addr + _align - 1) & (~(_align - 1))); -} diff --git a/kernel/src/common/hid.h b/kernel/src/common/hid.h deleted file mode 100644 index fd797233..00000000 --- a/kernel/src/common/hid.h +++ /dev/null @@ -1,166 +0,0 @@ -#pragma once -#include - -#define __HID_USAGE_TABLE_SIZE 64 // usage stack的大小 -#define HID_MAX_REPORT 300 // 最大允许的hid report数目(包括feature、input、output) -#define HID_MAX_PATH_SIZE 16 // maximum depth for path - -// 这部分请参考hid_1_11.pdf Section 6.2.2.4 - -#define HID_ITEM_COLLECTION 0xA0 -#define HID_ITEM_END_COLLECTION 0xC0 -#define HID_ITEM_FEATURE 0xB0 -#define HID_ITEM_INPUT 0x80 -#define HID_ITEM_OUTPUT 0x90 - -/** - * @brief 枚举hid的usage page列表。 - * 原始数据请见。 - * 该文件可从usb.org下载 - */ -enum HID_USAGE_PAGE_TYPES -{ - HID_USAGE_PAGE_GEN_DESKTOP = 0x1, - HID_USAGE_PAGE_SIMU_CTRL, // simulation controls - HID_USAGE_PAGE_VR_CTRL, // vr controls page - HID_USAGE_PAGE_SPORT_CTRL, // sport controls - HID_USAGE_PAGE_GAME_CTRL, // game controls - HID_USAGE_PAGE_GEN_DEVICE_CTRL, // general device controls - HID_USAGE_PAGE_KBD_KPD, // keyboard/ keypad page - HID_USAGE_PAGE_LED, // LED - HID_USAGE_PAGE_BUTTON, // button page - HID_USAGE_PAGE_ORDINAL, // ordinal page - HID_USAGE_PAGE_TEL_DEVICE, // telephony device - HID_USAGE_PAGE_CONSUMER, // consumer page - HID_USAGE_PAGE_DIGITIZER, // digitizers page - HID_USAGE_PAGE_HAPTICS, // haptics page - HID_USAGE_PAGE_PHY_INPUT_DEVICE, // physical input device page - HID_USAGE_PAGE_UNICODE = 0x10, // unicode page - HID_USAGE_PAGE_EYE_HEAD_TRACKER = 0x12, // eye and head trackers page - HID_USAGE_PAGE_AUX_DISPLAY = 0x14, // auxiliary display page - HID_USAGE_PAGE_SENSORS = 0x20, // sensors page - HID_USAGE_PAGE_MEDICAL = 0x40, // medical instruments - HID_USAGE_PAGE_BRAILLE_DISPLAY, // barille display - HID_USAGE_PAGE_LIGHTNING_ILLU = 0x59, // lighting and illumination page - HID_USAGE_PAGE_MONITOR = 0x80, // monitor page - HID_USAGE_PAGE_MONITOR_ENUMERATED, // monitor enumerated page - HID_USAGE_PAGE_VESA_VIRT_CTRL, // VESA virtual controls page - HID_USAGE_PAGE_POWER = 0x84, // power page - HID_USAGE_PAGE_BATTERY_SYSTEM, // battery system page - HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, // barcode scanner page - HID_USAGE_PAGE_SCALES, // scales page - HID_USAGE_PAGE_MAGNET_STRIPE_READER, // magnetic stript reader page - HID_USAGE_PAGE_CAMERA_CONTROL = 0x90, // camera control page - HID_USAGE_PAGE_ARCADE, // arcade page - HID_USAGE_PAGE_GAMING_DEVICE, // gaming device page - HID_USAGE_PAGE_FIDO_ALLIANCE = 0xf1d0, // FIDO alliance page -}; - -/** - * @brief usage type for HID_USAGE_PAGE_GEN_DESKTOP page - * - */ -enum USAGE_TYPE_GENDESK -{ - HID_USAGE_GENDESK_UNDEF = 0, // undefined - HID_USAGE_GENDESK_POINTER, - HID_USAGE_GENDESK_MOUSE, - HID_USAGE_GENDESK_KEYBOARD = 0x6, - HID_USAGE_GENDESK_POINTER_X = 0x30, - HID_USAGE_GENDESK_POINTER_Y, - HID_USAGE_GENDESK_WHEEL = 0x38, - HID_USAGE_GENDESK_NOTHING = 0xff, -}; - -/** - * @brief 描述hid path中的一个节点 - * - */ -struct hid_node_t -{ - int u_page; - int usage; -}; - -/** - * @brief 描述一条hid path - * - */ -struct hid_path_t -{ - int size; // 路径中的节点数目 - struct hid_node_t node[HID_MAX_PATH_SIZE]; -}; - -/** - * @brief Describe a HID Data with its location in report - * - */ -struct hid_data_t -{ - int value; // hid对象的值 - struct hid_path_t path; // hid path - - int report_count; // count of reports for this usage type - int offset; // offset of data in report - int size; // size of data in bits - - uint8_t report_id; // report id(from incoming report) - uint8_t type; // 数据类型:FEATURE / INPUT / OUTPUT - uint8_t attribute; // report field attribute. (2 = (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)) - // (6 = (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)) - int8_t unit_exp; // unit exponent; - - uint32_t unit; // HID unit - - int logical_min; // Logical min - int logical_max; // Logical max - int phys_min; // Physical min - int phys_max; // Physical max -}; - -/** - * @brief hid解析器 - * - */ -struct hid_parser -{ - const uint8_t *report_desc; // 指向report descriptor的指针 - int report_desc_size; // report descriptor的大小(字节) - int pos; // report_desc中,当前正在处理的位置 - uint8_t item; // 暂存当前的item - uint32_t value; // 暂存当前的值 - - struct hid_data_t data; // 存储当前的环境 - - int offset_table[HID_MAX_REPORT][3]; // 存储 hid report的ID、type、offset - int report_count; // hid report的数量 - int count; // local items的计数 - - uint32_t u_page; - struct hid_node_t usage_table[__HID_USAGE_TABLE_SIZE]; // Usage stack - int usage_size; // usage的数量 - int usage_min; - int usage_max; - - int cnt_objects; // report descriptor中的对象数目 - - int cnt_report; // report desc中的report数目 -}; - -struct hid_usage_types_string -{ - int value; - const char *string; -}; - -struct hid_usage_pages_string -{ - int value; - struct hid_usage_types_string *types; - const char *string; -}; - -int hid_parse_report(const void *report_data, const int len); - -bool hid_parse_find_object(const void *hid_report, const int report_size, struct hid_data_t *data); \ No newline at end of file diff --git a/kernel/src/common/kprint.h b/kernel/src/common/kprint.h deleted file mode 100644 index 4fb5f3cf..00000000 --- a/kernel/src/common/kprint.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file kprint.h - * @author longjin - * @brief 内核日志打印程序 - * @date 2022-01-28 - * - * @copyright Copyright (c) 2022 longjin - * - */ - -#pragma once -#include "printk.h" - -#define ksuccess(...) \ - do \ - { \ - printk("[ "); \ - printk_color(GREEN, BLACK, "SUCCESS"); \ - printk(" ] "); \ - printk(__VA_ARGS__); \ - printk("\n"); \ - } while (0) - -#define kinfo(...) \ - do \ - { \ - printk("[ INFO ] "); \ - printk(__VA_ARGS__); \ - printk("\n"); \ - } while (0) - -#define kdebug(...) \ - do \ - { \ - printk("[ DEBUG ] (%s:%d)\t", __FILE__, __LINE__); \ - printk(__VA_ARGS__); \ - printk("\n"); \ - } while (0) - -#define kwarn(...) \ - do \ - { \ - printk("[ "); \ - printk_color(YELLOW, BLACK, "WARN"); \ - printk(" ] "); \ - printk(__VA_ARGS__); \ - printk("\n"); \ - } while (0) - -#define kerror(...) \ - do \ - { \ - printk("[ "); \ - printk_color(RED, BLACK, "ERROR"); \ - printk(" ] "); \ - printk(__VA_ARGS__); \ - printk("\n"); \ - } while (0) - -#define kterminated(...) \ - do \ - { \ - printk("[ "); \ - printk_color(RED, BLACK, "TERMINATED"); \ - printk(" ] "); \ - printk(__VA_ARGS__); \ - printk("\n"); \ - } while (0) - -#define kBUG(...) \ - do \ - { \ - printk("[ "); \ - printk_color(RED, BLACK, "BUG"); \ - printk(" ] (%s:%d)\t", __FILE__, __LINE__); \ - printk(__VA_ARGS__); \ - printk("\n"); \ - } while (0) diff --git a/kernel/src/common/math.h b/kernel/src/common/math.h deleted file mode 100644 index d77958ea..00000000 --- a/kernel/src/common/math.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "stddef.h" -#include -#if ARCH(I386) || ARCH(X86_64) - -#if ARCH(I386) || ARCH(X86_64) -#include -#else -#error Arch not supported. -#endif -#endif - -int64_t pow(int64_t x, int y); diff --git a/kernel/src/common/math/libm.h b/kernel/src/common/math/libm.h deleted file mode 100644 index 29249a6a..00000000 --- a/kernel/src/common/math/libm.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#include - -// ===== 描述long double 的数据比特结构 -#if __LDBL_MANT_DIG__ == 53 && __LDBL_MAX_EXP__ == 1024 -#elif __LDBL_MANT_DIG__ == 64 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -union ldshape -{ - long double f; - struct - { - uint64_t m; - uint16_t se; - } i; -}; -#elif __LDBL_MANT_DIG__ == 113 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -union ldshape -{ - long double f; - struct - { - uint64_t lo; - uint32_t mid; - uint16_t top; - uint16_t se; - } i; - struct - { - uint64_t lo; - uint64_t hi; - } i2; -}; -#elif __LDBL_MANT_DIG__ == 113 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __BIG_ENDIAN -union ldshape -{ - long double f; - struct - { - uint16_t se; - uint16_t top; - uint32_t mid; - uint64_t lo; - } i; - struct - { - uint64_t hi; - uint64_t lo; - } i2; -}; -#else -#error Unsupported long double representation -#endif - -#define FORCE_EVAL(x) \ - do \ - { \ - if (sizeof(x) == sizeof(float)) \ - { \ - volatile float __x; \ - __x = (x); \ - (void)__x; \ - } \ - else if (sizeof(x) == sizeof(double)) \ - { \ - volatile double __x; \ - __x = (x); \ - (void)__x; \ - } \ - else \ - { \ - volatile long double __x; \ - __x = (x); \ - (void)__x; \ - } \ - } while (0) diff --git a/kernel/src/common/math/pow.c b/kernel/src/common/math/pow.c deleted file mode 100644 index 9d61672c..00000000 --- a/kernel/src/common/math/pow.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int64_t pow(int64_t x, int y) -{ - if (y == 0) - return 1; - if (y == 1) - return x; - if (y == 2) - return x * x; - int64_t res = 1; - while (y != 0) - { - if (y & 1) - res *= x; - y >>= 1; - x *= x; - } - return res; -} \ No newline at end of file diff --git a/kernel/src/common/math/round.c b/kernel/src/common/math/round.c deleted file mode 100644 index 120cd90f..00000000 --- a/kernel/src/common/math/round.c +++ /dev/null @@ -1,43 +0,0 @@ - - -#include "libm.h" - -#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1 -#define EPS __DBL_EPSILON__ -#elif __FLT_EVAL_METHOD__ == 2 -#define EPS __LDBL_EPSILON__ -#endif -static const double toint = 1 / EPS; - -double round(double x) -{ - union - { - double f; - uint64_t i; - } u = {x}; - - int e = u.i >> 52 & 0x7ff; - double y; - - if (e >= 0x3ff + 52) - return x; - if (u.i >> 63) - x = -x; - if (e < 0x3ff - 1) - { - /* raise inexact if x!=0 */ - FORCE_EVAL(x + toint); - return 0 * u.f; - } - y = x + toint - toint - x; - if (y > 0.5) - y = y + x - 1; - else if (y <= -0.5) - y = y + x + 1; - else - y = y + x; - if (u.i >> 63) - y = -y; - return y; -} \ No newline at end of file diff --git a/kernel/src/common/printk.h b/kernel/src/common/printk.h deleted file mode 100644 index 76a0f171..00000000 --- a/kernel/src/common/printk.h +++ /dev/null @@ -1,79 +0,0 @@ -// -// Created by longjin on 2022/1/21. -// -#pragma once -#pragma GCC push_options -#pragma GCC optimize("O0") -#define PAD_ZERO 1 // 0填充 -#define LEFT 2 // 靠左对齐 -#define RIGHT 4 // 靠右对齐 -#define PLUS 8 // 在正数前面显示加号 -#define SPACE 16 -#define SPECIAL 32 // 在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X' -#define SMALL 64 // 十进制以上数字显示小写字母 -#define SIGN 128 // 显示符号位 - -#define is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏 - -// 字体颜色的宏定义 -#define WHITE 0x00ffffff // 白 -#define BLACK 0x00000000 // 黑 -#define RED 0x00ff0000 // 红 -#define ORANGE 0x00ff8000 // 橙 -#define YELLOW 0x00ffff00 // 黄 -#define GREEN 0x0000ff00 // 绿 -#define BLUE 0x000000ff // 蓝 -#define INDIGO 0x0000ffff // 靛 -#define PURPLE 0x008000ff // 紫 - -// 异常的宏定义 -#define EPOS_OVERFLOW 1 // 坐标溢出 -#define EFB_MISMATCH 2 // 帧缓冲区与指定的屏幕大小不匹配 -#define EUNSUPPORTED 3 // 当前操作暂不被支持 - -#include "glib.h" -#include - -/** - * @brief 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中 - * - * @param buf 结果缓冲区 - * @param fmt 格式化字符串 - * @param args 内容 - * @return 最终字符串的长度 - */ -int vsprintf(char *buf, const char *fmt, va_list args); - -/** - * @brief 将字符串按照fmt和args中的内容进行格式化,截取字符串前buf_size-1,保存到buf中 - * - * @param buf 结果缓冲区,大小为buf_size - * @param fmt 格式化字符串 - * @param buf_size 缓冲区长度 - * @param args 内容 - * @return 最终字符串的长度 - */ -int vsnprintf(char *buf, const char *fmt, int buf_size, va_list args); - -/** - * @brief 格式化打印字符串 - * - * @param FRcolor 前景色 - * @param BKcolor 背景色 - * @param ... 格式化字符串 - */ - -#define printk(...) printk_color(WHITE, BLACK, __VA_ARGS__) - -int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...); - -/** - * @brief 格式化字符串并输出到buf - * - * @param buf 输出缓冲区 - * @param fmt 格式 - * @param ... 参数 - * @return int 字符串长度 - */ -int sprintk(char *buf, const char *fmt, ...); -#pragma GCC pop_options \ No newline at end of file diff --git a/kernel/src/common/spinlock.h b/kernel/src/common/spinlock.h deleted file mode 100644 index 0eb58ca6..00000000 --- a/kernel/src/common/spinlock.h +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file spinlock.h - * @author fslongjin (longjin@RinGoTek.cn) - * @brief 自旋锁 - * @version 0.1 - * @date 2022-04-07 - * - * @copyright Copyright (c) 2022 - * - */ -#pragma once -#include -#include -#include - -/** - * @brief 定义自旋锁结构体 - * - */ -typedef struct -{ - int8_t lock; // 1:unlocked 0:locked -} spinlock_t; - -extern void __arch_spin_lock(spinlock_t *lock); -extern void __arch_spin_unlock(spinlock_t *lock); - -extern void __arch_spin_lock_no_preempt(spinlock_t *lock); -extern void __arch_spin_unlock_no_preempt(spinlock_t *lock); - -extern long __arch_spin_trylock(spinlock_t *lock); - -/** - * @brief 自旋锁加锁 - * - * @param lock - */ -void spin_lock(spinlock_t *lock) -{ - __arch_spin_lock(lock); -} - -/** - * @brief 自旋锁解锁 - * - * @param lock - */ -void spin_unlock(spinlock_t *lock) -{ - __arch_spin_unlock(lock); -} - -/** - * @brief 初始化自旋锁 - * - * @param lock - */ -void spin_init(spinlock_t *lock) -{ - barrier(); - lock->lock = 1; - barrier(); -} - -/** - * @brief 自旋锁加锁(不改变自旋锁持有计数) - * - * @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误 - */ -void spin_lock_no_preempt(spinlock_t *lock) -{ - __arch_spin_lock_no_preempt(lock); -} - -/** - * @brief 自旋锁解锁(不改变自旋锁持有计数) - * - * @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误 - */ -void spin_unlock_no_preempt(spinlock_t *lock) -{ - __arch_spin_unlock_no_preempt(lock); -} - -/** - * @brief 尝试加锁 - * - * @param lock - * @return long 锁变量的值(1为成功加锁,0为加锁失败) - */ -long spin_trylock(spinlock_t *lock) -{ - return __arch_spin_trylock(lock); -} - -/** - * @brief 保存中断状态,关闭中断,并自旋锁加锁 - * - */ -#define spin_lock_irqsave(lock, flags) \ - do \ - { \ - local_irq_save(flags); \ - spin_lock(lock); \ - } while (0) - -/** - * @brief 恢复rflags以及中断状态并解锁自旋锁 - * - */ -#define spin_unlock_irqrestore(lock, flags) \ - do \ - { \ - spin_unlock(lock); \ - local_irq_restore(flags); \ - } while (0) - -/** - * @brief 关闭中断并加锁 - * - */ -#define spin_lock_irq(lock) \ - do \ - { \ - local_irq_disable(); \ - spin_lock(lock); \ - } while (0) - -/** - * @brief 解锁并开启中断 - * - */ -#define spin_unlock_irq(lock) \ - do \ - { \ - spin_unlock(lock); \ - local_irq_enable(); \ - } while (0) - -/** - * @brief 判断自旋锁是否已经加锁 - * - * @param lock 待判断的自旋锁 - * @return true 已经加锁 - * @return false 尚未加锁 - */ -static inline bool spin_is_locked(const spinlock_t *lock) -{ - int x = READ_ONCE(lock->lock); - return (x == 0) ? true : false; -} - -#define assert_spin_locked(lock) BUG_ON(!spin_is_locked(lock)) \ No newline at end of file diff --git a/kernel/src/common/stddef.h b/kernel/src/common/stddef.h deleted file mode 100644 index 3f3fea3c..00000000 --- a/kernel/src/common/stddef.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "./sys/types.h" - -#define NULL (void*)0 - -typedef __PTRDIFF_TYPE__ ptrdiff_t; // Signed integer type of the result of subtracting two pointers. - -#ifndef __always_inline -#define __always_inline __inline__ -#endif - -// 定义类型的缩写 -typedef unsigned char uchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ul; -typedef unsigned long long int ull; -typedef long long int ll; \ No newline at end of file diff --git a/kernel/src/common/stdio.h b/kernel/src/common/stdio.h deleted file mode 100644 index abe28f65..00000000 --- a/kernel/src/common/stdio.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include -#include - -#define SEEK_SET 0 /* Seek relative to start-of-file */ -#define SEEK_CUR 1 /* Seek relative to current position */ -#define SEEK_END 2 /* Seek relative to end-of-file */ - -#define SEEK_MAX 3 - -extern int vsprintf(char *buf, const char *fmt, va_list args); - -extern int sprintk(char *buf, const char *fmt, ...); \ No newline at end of file diff --git a/kernel/src/common/string.h b/kernel/src/common/string.h deleted file mode 100644 index cd7032ee..00000000 --- a/kernel/src/common/string.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "glib.h" - -// 计算字符串的长度(经过测试,该版本比采用repne/scasb汇编的运行速度快16.8%左右) -static inline int strlen(const char *s) { - if (s == NULL) - return 0; - register int __res = 0; - while (s[__res] != '\0') { - ++__res; - } - return __res; -} - - -static inline int strcmp(const char *s1, const char *s2) { - while (*s1 && *s2 && *s1 == *s2) { - ++s1; - ++s2; - } - return *s1 - *s2; -} \ No newline at end of file diff --git a/kernel/src/common/sys/types.h b/kernel/src/common/sys/types.h deleted file mode 100644 index 7d1d8cbc..00000000 --- a/kernel/src/common/sys/types.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include "DragonOS/stdint.h" -#include - -typedef unsigned char u_char; -typedef unsigned short u_short; -typedef unsigned int u_int; -typedef unsigned long u_long; - -typedef uint32_t uid_t; -typedef uint32_t gid_t; -typedef long long ssize_t; - -typedef int64_t pid_t; -typedef __SIZE_TYPE__ size_t; - -typedef char *caddr_t; - -typedef int id_t; - -typedef uint64_t ino_t; -typedef int64_t off_t; - -typedef uint32_t blkcnt_t; -typedef uint32_t blksize_t; -typedef uint32_t dev_t; -typedef uint16_t mode_t; -typedef uint32_t nlink_t; - -typedef int64_t time_t; -typedef uint32_t useconds_t; -typedef int32_t suseconds_t; -typedef uint32_t clock_t; - -typedef uint64_t fsblkcnt_t; -typedef uint64_t fsfilcnt_t; - -typedef uint64_t sector_t; - -#define __socklen_t_defined -#define __socklen_t uint32_t -typedef __socklen_t socklen_t; - -#define pgoff_t unsigned long - -struct utimbuf -{ - time_t actime; - time_t modtime; -}; - -typedef int pthread_t; -typedef int pthread_key_t; -typedef uint32_t pthread_once_t; - -typedef struct __pthread_mutex_t -{ - uint32_t lock; - pthread_t owner; - int level; - int type; -} pthread_mutex_t; - -typedef void *pthread_attr_t; -typedef struct __pthread_mutexattr_t -{ - int type; -} pthread_mutexattr_t; - -typedef struct __pthread_cond_t -{ - pthread_mutex_t *mutex; - uint32_t value; - int clockid; // clockid_t -} pthread_cond_t; - -typedef uint64_t pthread_rwlock_t; -typedef void *pthread_rwlockattr_t; -typedef struct __pthread_spinlock_t -{ - int m_lock; -} pthread_spinlock_t; -typedef struct __pthread_condattr_t -{ - int clockid; // clockid_t -} pthread_condattr_t; - -typedef uint64_t gfp_t; - -// 定义8字节对齐变量属性 -#ifndef __aligned_u64 - #define __aligned_u64 uint64_t __attribute__((aligned(8))) -#endif - -#define aligned_u64 __aligned_u64 \ No newline at end of file diff --git a/kernel/src/common/time.h b/kernel/src/common/time.h deleted file mode 100644 index 3d4cd44f..00000000 --- a/kernel/src/common/time.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "stddef.h" - -// 操作系统定义时间以ns为单位 -#define CLOCKS_PER_SEC 1000000 diff --git a/kernel/src/debug/.gitignore b/kernel/src/debug/.gitignore index 33a5f71f..4b1e7676 100644 --- a/kernel/src/debug/.gitignore +++ b/kernel/src/debug/.gitignore @@ -1,2 +1,3 @@ +gen_kallsyms +kallsyms.S kallsyms -kallsyms.S \ No newline at end of file diff --git a/kernel/src/debug/Makefile b/kernel/src/debug/Makefile index a145970d..91668fa5 100644 --- a/kernel/src/debug/Makefile +++ b/kernel/src/debug/Makefile @@ -4,23 +4,14 @@ all: CFLAGS += -I . -# 请注意,这个不能使用raw的gcc来编译。 -kallsyms.o: kallsyms.c - gcc -o kallsyms kallsyms.c - rm -rf kallsyms.o - -traceback.o: traceback/traceback.c - $(CC) $(CFLAGS) -c traceback/traceback.c -o traceback/traceback.o - - # 生成内核栈符号表的汇编文件 -generate_kallsyms: kallsyms.o - echo "Generating kallsyms..." +generate_kallsyms: + @echo "Generating kallsyms..." # 请注意,这个不能使用raw的nm来处理 - nm -n -C $(kernel_root_path)/kernel | ./kallsyms > kallsyms.S + nm -n -C $(kernel_root_path)/kernel | $(kernel_root_path)/../../build-scripts/target/release/gen_kallsyms > kallsyms.S $(CC) -c kallsyms.S -o kallsyms.o @echo "Kallsyms generated." clean: - rm -rf kallsyms \ No newline at end of file + rm -rf gen_kallsyms \ No newline at end of file diff --git a/kernel/src/debug/bug.h b/kernel/src/debug/bug.h deleted file mode 100644 index db76952d..00000000 --- a/kernel/src/debug/bug.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once -#include -#include - -#pragma GCC push_options -#pragma GCC optimize("O0") - -/** - * @brief 当condition为true时,认为产生了bug - * - */ -#define BUG_ON(condition) ({ \ - int __ret_bug_on = !!(condition); \ - if (unlikely(__ret_bug_on)) \ - kBUG("BUG at %s:%d", __FILE__, __LINE__); \ - unlikely(__ret_bug_on); \ -}) - -/** - * @brief 当condition为true时输出警告信息 - * - */ -#define WARN_ON(condition) ({ \ - int __ret_warn_on = !!(condition); \ - if (unlikely(__ret_warn_on)) \ - kwarn("Assertion failed at %s:%d", __FILE__, __LINE__); \ - unlikely(__ret_warn_on); \ -}) - -/** - * @brief 当condition不为0时输出警告信息,且只会输出一次警告信息 - * - */ -#define WARN_ON_ONCE(condition) ({ \ - static int __warned; \ - int __ret_warn_once = !!(condition); \ - \ - if (unlikely(__ret_warn_once && !__warned)) \ - { \ - __warned = true; \ - WARN_ON(1); \ - } \ - unlikely(__ret_warn_once); \ -}) - -#define FAIL_ON_TO(condition, to) ({ \ - int __ret_warn_on = !!(condition); \ - if (unlikely(__ret_warn_on)) \ - goto to; \ - unlikely(__ret_warn_on); \ -}) - -/** - * @brief 当condition为true时,中断编译,并输出错误信息msg - * - * 如果你的代码依赖于一些能够在编译期间计算出来的值,那么请使用这个宏以防止其他人错误的修改了这些值,从而导致程序运行错误 - */ -#define BUILD_BUG_ON_MSG(condition, msg) complietime_assert(!(condition), msg) - -/** - * @brief 当condition为true时,中断编译。 - * - * 如果你的代码依赖于一些能够在编译期间计算出来的值,那么请使用这个宏以防止其他人错误的修改了这些值,从而导致程序运行错误 - */ -#define BUILD_BUG_ON(condition) \ - BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition) - -#pragma GCC pop_options \ No newline at end of file diff --git a/kernel/src/debug/gen_kallsyms.rs b/kernel/src/debug/gen_kallsyms.rs new file mode 100644 index 00000000..140df060 --- /dev/null +++ b/kernel/src/debug/gen_kallsyms.rs @@ -0,0 +1,122 @@ +use std::str; + +#[derive(Debug, Clone)] +struct KernelSymbolEntry { + vaddr: u64, + #[allow(dead_code)] + symbol_type: char, + symbol: String, + symbol_length: usize, +} + +fn symbol_to_write(vaddr: u64, text_vaddr: u64, etext_vaddr: u64) -> bool { + vaddr >= text_vaddr && vaddr <= etext_vaddr +} +fn read_symbol(line: &str) -> Option { + if line.len() > 512 { + return None; + } // skip line with length >= 512 + let mut parts = line.split_whitespace(); + let vaddr = u64::from_str_radix(parts.next()?, 16).ok()?; + let symbol_type = parts.next()?.chars().next()?; + let symbol = parts.collect::>().join(" "); + if symbol_type != 'T' && symbol_type != 't' { + return None; + } // local symbol or global symbol in text section + if symbol == "$x" { + return None; + } // skip $x symbol + let symbol_length = symbol.len() + 1; // +1 for null terminator + Some(KernelSymbolEntry { + vaddr, + symbol_type, + symbol, + symbol_length, + }) +} + +fn read_map() -> (Vec, u64, u64) { + let mut symbol_table = Vec::new(); + let mut text_vaddr = 0; + let mut etext_vaddr = 0; + let mut line = String::new(); + loop { + let size = std::io::stdin().read_line(&mut line).unwrap(); + if size == 0 { + break; + } + line = line.trim().to_string(); + if let Some(entry) = read_symbol(&line) { + if entry.symbol.starts_with("_text") { + text_vaddr = entry.vaddr; + } else if entry.symbol.starts_with("_etext") { + etext_vaddr = entry.vaddr; + } + symbol_table.push(entry); + } + line.clear(); + } + (symbol_table, text_vaddr, etext_vaddr) +} + +fn generate_result(symbol_table: &[KernelSymbolEntry], text_vaddr: u64, etext_vaddr: u64) { + println!(".section .rodata\n"); + println!(".global kallsyms_address"); + println!(".align 8\n"); + println!("kallsyms_address:"); + + let mut last_vaddr = 0; + let mut total_syms_to_write = 0; + + for entry in symbol_table { + if !symbol_to_write(entry.vaddr, text_vaddr, etext_vaddr) || entry.vaddr == last_vaddr { + continue; + } + + println!("\t.quad\t{:#x}", entry.vaddr); + total_syms_to_write += 1; + last_vaddr = entry.vaddr; + } + + println!("\n.global kallsyms_num"); + println!(".align 8"); + println!("kallsyms_num:"); + println!("\t.quad\t{}", total_syms_to_write); + + println!("\n.global kallsyms_names_index"); + println!(".align 8"); + println!("kallsyms_names_index:"); + + let mut position = 0; + last_vaddr = 0; + + for entry in symbol_table { + if !symbol_to_write(entry.vaddr, text_vaddr, etext_vaddr) || entry.vaddr == last_vaddr { + continue; + } + + println!("\t.quad\t{}", position); + position += entry.symbol_length; + last_vaddr = entry.vaddr; + } + + println!("\n.global kallsyms_names"); + println!(".align 8"); + println!("kallsyms_names:"); + + last_vaddr = 0; + + for entry in symbol_table { + if !symbol_to_write(entry.vaddr, text_vaddr, etext_vaddr) || entry.vaddr == last_vaddr { + continue; + } + + println!("\t.asciz\t\"{}\"", entry.symbol); + last_vaddr = entry.vaddr; + } +} + +fn main() { + let (symbol_table, text_vaddr, etext_vaddr) = read_map(); + generate_result(&symbol_table, text_vaddr, etext_vaddr); +} diff --git a/kernel/src/debug/kallsyms.c b/kernel/src/debug/kallsyms.c deleted file mode 100644 index 3f95550c..00000000 --- a/kernel/src/debug/kallsyms.c +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @file kallsyms.c - * @author longjin (longjin@RinGoTek.cn) - * @brief 内核栈跟踪 - * @version 0.1 - * @date 2022-06-22 - * - * @copyright Copyright (c) 2022 - * - */ -#include -#include -#include -#include - -/** - * @brief 判断符号是否需要被输出(只输出text段内的符号) - * - */ -#define symbol_to_write(vaddr, tv, etv) \ - ((vaddr < tv || vaddr > etv) ? 0 : 1) - -/** - * @brief 使用nm命令提取出来的信息存到这个结构体之中 - * - */ -struct kernel_symbol_entry_t -{ - uint64_t vaddr; - char type; - char *symbol; - int symbol_length; -}; - -struct kernel_symbol_entry_t *symbol_table; -// 符号表最大能容纳的entry数量 -uint64_t table_size = 0; -// 符号表当前的entry数量 -uint64_t entry_count = 0; -// 符号表中,text和etext的下标 -uint64_t text_vaddr, etext_vaddr; - -/** - * @brief 读取一个符号到entry之中 - * - * @param filp stdin的文件指针 - * @param entry 待填写的entry - * @return int 返回码 - */ -int read_symbol(FILE *filp, struct kernel_symbol_entry_t *entry) -{ - // 本函数假设nm命令输出的结果中,每行最大512字节 - char str[512] = {0}; - char *s = fgets(str, sizeof(str), filp); - if (s != str) - { - return -1; - } - - char symbol_name[512] = {0}; - int retval = sscanf(str, "%llx %c %512c", &entry->vaddr, &entry->type, symbol_name); - - // 如果当前行不符合要求 - if (retval != 3) - { - return -1; - } - // malloc一块内存,然后把str的内容拷贝进去,接着修改symbol指针 - size_t len = strlen(symbol_name); - if (len >= 1 && symbol_name[len - 1] == '\n') - { - symbol_name[len - 1] = '\0'; - len--; - } - // 转义双引号 - for (int i = 0; i < len; i++) - { - if (symbol_name[i] == '"') - { - char temp[len - i]; - memcpy(temp, symbol_name + i, len - i); - symbol_name[i] = '\\'; - memcpy(symbol_name + i + 1, temp, len - i); - i++; - } - } - entry->symbol = strdup(symbol_name); - entry->symbol_length = len + 1; // +1的原因是.asciz指令会在字符串末尾自动添加结束符\0 - return 0; -} - -/** - * @brief 接收标准输入流的数据,解析nm命令输出的内容 - * - * @param filp - */ -void read_map(FILE *filp) -{ - // 循环读入数据直到输入流结束 - while (!feof(filp)) - { - // 给符号表扩容 - if (entry_count >= table_size) - { - table_size += 100; - // 由于使用了realloc,因此符号表原有的内容会被自动的copy过去 - symbol_table = (struct kernel_symbol_entry_t *)realloc(symbol_table, sizeof(struct kernel_symbol_entry_t) * table_size); - } - - // 若成功读取符号表的内容,则将计数器+1 - if (read_symbol(filp, &symbol_table[entry_count]) == 0) - ++entry_count; - } - - // 查找符号表中的text和etext标签 - for (uint64_t i = 0; i < entry_count; ++i) - { - if (text_vaddr == 0ULL && strcmp(symbol_table[i].symbol, "_text") == 0) - text_vaddr = symbol_table[i].vaddr; - if (etext_vaddr == 0ULL && strcmp(symbol_table[i].symbol, "_etext") == 0) - etext_vaddr = symbol_table[i].vaddr; - if (text_vaddr != 0ULL && etext_vaddr != 0ULL) - break; - } -} - -/** - * @brief 输出最终的kallsyms汇编代码文件 - * 直接输出到stdout,通过命令行的 > 命令,写入文件 - */ -void generate_result() -{ - printf(".section .rodata\n\n"); - printf(".global kallsyms_address\n"); - printf(".align 8\n\n"); - - printf("kallsyms_address:\n"); // 地址数组 - - uint64_t last_vaddr = 0; - uint64_t total_syms_to_write = 0; // 真正输出的符号的数量 - - // 循环写入地址数组 - for (uint64_t i = 0; i < entry_count; ++i) - { - // 判断是否为text段的符号 - if (!symbol_to_write(symbol_table[i].vaddr, text_vaddr, etext_vaddr)) - continue; - - if (symbol_table[i].vaddr == last_vaddr) - continue; - - // 输出符号地址 - printf("\t.quad\t%#llx\n", symbol_table[i].vaddr); - ++total_syms_to_write; - - last_vaddr = symbol_table[i].vaddr; - } - - putchar('\n'); - - // 写入符号表的表项数量 - printf(".global kallsyms_num\n"); - printf(".align 8\n"); - printf("kallsyms_num:\n"); - printf("\t.quad\t%lld\n", total_syms_to_write); - - putchar('\n'); - - // 循环写入符号名称的下标索引 - printf(".global kallsyms_names_index\n"); - printf(".align 8\n"); - printf("kallsyms_names_index:\n"); - uint64_t position = 0; - last_vaddr = 0; - for (uint64_t i = 0; i < entry_count; ++i) - { - // 判断是否为text段的符号 - if (!symbol_to_write(symbol_table[i].vaddr, text_vaddr, etext_vaddr)) - continue; - - if (symbol_table[i].vaddr == last_vaddr) - continue; - - // 输出符号名称的偏移量 - printf("\t.quad\t%lld\n", position); - position += symbol_table[i].symbol_length; - last_vaddr = symbol_table[i].vaddr; - } - - putchar('\n'); - - // 输出符号名 - printf(".global kallsyms_names\n"); - printf(".align 8\n"); - printf("kallsyms_names:\n"); - - last_vaddr = 0; - for (uint64_t i = 0; i < entry_count; ++i) - { - // 判断是否为text段的符号 - if (!symbol_to_write(symbol_table[i].vaddr, text_vaddr, etext_vaddr)) - continue; - - if (symbol_table[i].vaddr == last_vaddr) - continue; - - // 输出符号名称 - printf("\t.asciz\t\"%s\"\n", symbol_table[i].symbol); - - last_vaddr = symbol_table[i].vaddr; - } - - putchar('\n'); -} -int main(int argc, char **argv) -{ - read_map(stdin); - - generate_result(); -} \ No newline at end of file diff --git a/kernel/src/debug/kprobe/args.rs b/kernel/src/debug/kprobe/args.rs index 33ca4549..3bcff7c4 100644 --- a/kernel/src/debug/kprobe/args.rs +++ b/kernel/src/debug/kprobe/args.rs @@ -1,3 +1,4 @@ +use crate::debug::traceback::addr_from_symbol; use alloc::boxed::Box; use alloc::string::String; use kprobe::{CallBackFunc, KprobeBuilder, ProbeArgs}; @@ -15,10 +16,6 @@ pub struct KprobeInfo { pub enable: bool, } -extern "C" { - fn addr_from_symbol(symbol: *const u8) -> usize; -} - impl TryFrom for KprobeBuilder { type Error = SystemError; fn try_from(kprobe_info: KprobeInfo) -> Result { @@ -30,20 +27,15 @@ impl TryFrom for KprobeBuilder { return Err(SystemError::EINVAL); } let func_addr = if let Some(symbol) = kprobe_info.symbol.clone() { - let mut symbol_sting = symbol; - if !symbol_sting.ends_with("\0") { - symbol_sting.push('\0'); - } - let symbol = symbol_sting.as_ptr(); - let func_addr = unsafe { addr_from_symbol(symbol) }; - if func_addr == 0 { + let func_addr = unsafe { addr_from_symbol(symbol.as_str()) }; + if func_addr.is_none() { warn!( "register_kprobe: the symbol: {:?} not found", kprobe_info.symbol ); return Err(SystemError::ENXIO); } - func_addr + func_addr.unwrap() as usize } else { kprobe_info.addr.unwrap() }; diff --git a/kernel/src/debug/mod.rs b/kernel/src/debug/mod.rs index dcd4c86a..23bc112c 100644 --- a/kernel/src/debug/mod.rs +++ b/kernel/src/debug/mod.rs @@ -2,3 +2,6 @@ pub mod jump_label; pub mod klog; pub mod kprobe; pub mod panic; +pub mod sysfs; +pub mod traceback; +pub mod tracing; diff --git a/kernel/src/debug/panic/hook.rs b/kernel/src/debug/panic/hook.rs index c339a196..271dc157 100644 --- a/kernel/src/debug/panic/hook.rs +++ b/kernel/src/debug/panic/hook.rs @@ -1,27 +1,50 @@ -use unwinding::abi::{UnwindContext, UnwindReasonCode, _Unwind_GetIP}; -use unwinding::panic::UserUnwindTrace; +use crate::libs::spinlock::SpinLock; -extern "C" { - fn lookup_kallsyms(addr: u64, level: i32) -> i32; +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(not(target_arch = "loongarch64"))] + { + use unwinding::abi::{UnwindContext, UnwindReasonCode, _Unwind_Backtrace, _Unwind_GetIP}; + use core::ffi::c_void; + use crate::debug::traceback::lookup_kallsyms; + } } -/// User hook for unwinding -/// -/// During stack backtrace, the user can print the function location of the current stack frame. -pub struct Tracer; -pub struct CallbackData { - pub counter: usize, -} -impl UserUnwindTrace for Tracer { - type Arg = CallbackData; +static GLOBAL_LOCK: SpinLock<()> = SpinLock::new(()); - fn trace(ctx: &UnwindContext<'_>, arg: *mut Self::Arg) -> UnwindReasonCode { - let data = unsafe { &mut *(arg) }; +#[cfg(target_arch = "loongarch64")] +pub fn print_stack_trace() { + let _lock = GLOBAL_LOCK.lock(); + println!("This Arch does not support stack trace printing."); +} + +#[cfg(not(target_arch = "loongarch64"))] +pub fn print_stack_trace() { + let _lock = GLOBAL_LOCK.lock(); + println!("Rust Panic Backtrace:"); + struct CallbackData { + counter: usize, + kernel_main: bool, + } + extern "C" fn callback(unwind_ctx: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode { + let data = unsafe { &mut *(arg as *mut CallbackData) }; + if data.kernel_main { + // If we are in kernel_main, we don't need to print the backtrace. + return UnwindReasonCode::NORMAL_STOP; + } data.counter += 1; - let pc = _Unwind_GetIP(ctx); - unsafe { - lookup_kallsyms(pc as u64, data.counter as i32); + let pc = _Unwind_GetIP(unwind_ctx); + if pc > 0 { + let is_kernel_main = unsafe { lookup_kallsyms(pc as u64, data.counter as i32) }; + data.kernel_main = is_kernel_main; } UnwindReasonCode::NO_REASON } + + let mut data = CallbackData { + counter: 0, + kernel_main: false, + }; + _Unwind_Backtrace(callback, &mut data as *mut _ as _); } diff --git a/kernel/src/debug/panic/mod.rs b/kernel/src/debug/panic/mod.rs index 245058fa..14a2d0f7 100644 --- a/kernel/src/debug/panic/mod.rs +++ b/kernel/src/debug/panic/mod.rs @@ -1,6 +1,36 @@ -#[cfg(feature = "backtrace")] -mod hook; -use core::panic::PanicInfo; +pub mod hook; +use alloc::boxed::Box; +use cfg_if::cfg_if; + +use log::error; + +use crate::process; +use system_error::SystemError; + +cfg_if! { + if #[cfg(target_os = "none")] { + use core::panic::PanicInfo; + use core::sync::atomic::AtomicU8; + + static PANIC_COUNTER: AtomicU8 = AtomicU8::new(0); + } +} + +#[derive(Debug)] +struct PanicGuard; + +impl PanicGuard { + pub fn new() -> Self { + crate::arch::panic_pre_work(); + Self + } +} + +impl Drop for PanicGuard { + fn drop(&mut self) { + crate::arch::panic_post_work(); + } +} /// 全局的panic处理函数 /// @@ -8,10 +38,7 @@ use core::panic::PanicInfo; #[panic_handler] #[no_mangle] pub fn panic(info: &PanicInfo) -> ! { - use log::error; - - use crate::process; - + PANIC_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed); error!("Kernel Panic Occurred."); match info.location() { @@ -28,15 +55,20 @@ pub fn panic(info: &PanicInfo) -> ! { } } println!("Message:\n\t{}", info.message()); - #[cfg(feature = "backtrace")] - { - let mut data = hook::CallbackData { counter: 0 }; - println!("Rust Panic Backtrace:"); - let _res = unwinding::panic::begin_panic_with_hook::( - alloc::boxed::Box::new(()), - &mut data, + if PANIC_COUNTER.load(core::sync::atomic::Ordering::Relaxed) > 8 { + println!( + "Panic Counter: {}, too many panics, halt.", + PANIC_COUNTER.load(core::sync::atomic::Ordering::Relaxed) ); - // log::error!("panic unreachable: {:?}", res.0); + loop {} + } + + #[cfg(not(target_arch = "loongarch64"))] + if info.can_unwind() { + let guard = Box::new(PanicGuard::new()); + hook::print_stack_trace(); + let _res = unwinding::panic::begin_panic(guard); + // log::error!("panic unreachable: {:?}", _res.0); } println!( "Current PCB:\n\t{:?}", @@ -44,3 +76,42 @@ pub fn panic(info: &PanicInfo) -> ! { ); process::ProcessManager::exit(usize::MAX); } + +/// The wrapper of `unwinding::panic::begin_panic`. If the panic is +/// caught, it will return the result of the function. +/// If the panic is not caught, it will return an error. +#[cfg(not(target_arch = "loongarch64"))] +pub fn kernel_catch_unwind R>(f: F) -> Result { + let res = unwinding::panic::catch_unwind(f); + match res { + Ok(r) => Ok(r), + Err(e) => { + log::error!("Catch Unwind Error: {:?}", e); + Err(SystemError::MAXERRNO) + } + } +} + +#[cfg(not(target_arch = "loongarch64"))] +#[allow(unused)] +pub fn test_unwind() { + struct UnwindTest; + impl Drop for UnwindTest { + fn drop(&mut self) { + log::info!("Drop UnwindTest"); + } + } + log::error!("Test unwind"); + let res1 = unwinding::panic::catch_unwind(|| { + let _unwind_test = UnwindTest; + log::error!("Test panic..."); + panic!("Test panic"); + }); + assert!(res1.is_err()); + let res2 = unwinding::panic::catch_unwind(|| { + let _unwind_test = UnwindTest; + log::error!("Test no panic..."); + 0 + }); + assert!(res2.is_ok()); +} diff --git a/kernel/src/debug/sysfs/mod.rs b/kernel/src/debug/sysfs/mod.rs new file mode 100644 index 00000000..0557b04b --- /dev/null +++ b/kernel/src/debug/sysfs/mod.rs @@ -0,0 +1,28 @@ +use crate::driver::base::kset::KSet; +use crate::init::initcall::INITCALL_POSTCORE; +use crate::misc::ksysfs::sys_kernel_kset; +use alloc::string::ToString; +use alloc::sync::Arc; +use system_error::SystemError; +use unified_init::macros::unified_init; + +/// `/sys/kernel/debug`的kset +static mut SYS_KERNEL_DEBUG_KSET_INSTANCE: Option> = None; + +/// 初始化debug模块在sysfs中的目录 +#[unified_init(INITCALL_POSTCORE)] +fn debugfs_init() -> Result<(), SystemError> { + let debug_kset = KSet::new("debug".to_string()); + debug_kset + .register(Some(sys_kernel_kset())) + .expect("register debug kset failed"); + unsafe { + SYS_KERNEL_DEBUG_KSET_INSTANCE = Some(debug_kset); + } + super::tracing::init_debugfs_tracing()?; + return Ok(()); +} + +pub fn debugfs_kset() -> Arc { + unsafe { SYS_KERNEL_DEBUG_KSET_INSTANCE.clone().unwrap() } +} diff --git a/kernel/src/debug/traceback/mod.rs b/kernel/src/debug/traceback/mod.rs new file mode 100644 index 00000000..103fe64e --- /dev/null +++ b/kernel/src/debug/traceback/mod.rs @@ -0,0 +1,75 @@ +use core::ffi::CStr; + +#[linkage = "weak"] +#[no_mangle] +fn kallsyms_address() {} +#[linkage = "weak"] +#[no_mangle] +fn kallsyms_num() {} +#[linkage = "weak"] +#[no_mangle] +fn kallsyms_names_index() {} +#[linkage = "weak"] +#[no_mangle] +fn kallsyms_names() {} + +/// print the func name according to the pc address and +/// return true if the func is kernel_main +pub unsafe fn lookup_kallsyms(addr: u64, level: i32) -> bool { + let sym_names = kallsyms_names as *const u8; + // 由于符号表使用nm -n生成,因此是按照地址升序排列的,因此可以二分 + let sym_num = kallsyms_num as usize; + let kallsyms_address_list = + core::slice::from_raw_parts(kallsyms_address as *const u64, sym_num); + let sym_names_index = kallsyms_names_index as *const u64; + let sym_names_index = core::slice::from_raw_parts(sym_names_index, sym_num); + let mut index = usize::MAX; + for i in 0..sym_num - 1 { + if addr > kallsyms_address_list[i] && addr <= kallsyms_address_list[i + 1] { + index = i; + break; + } + } + let mut is_kernel_main = false; + if index < sym_num { + let sym_name = CStr::from_ptr(sym_names.add(sym_names_index[index] as usize) as _) + .to_str() + .unwrap(); + if sym_name.starts_with("kernel_main") { + is_kernel_main = true; + } + println!( + "[{}] function:{}() \t(+) {:04} address:{:#018x}", + level, + sym_name, + addr - kallsyms_address_list[index], + addr + ); + } else { + println!( + "[{}] function:unknown \t(+) {:04} address:{:#018x}", + level, + addr - kallsyms_address_list[sym_num - 1], + addr + ); + }; + return is_kernel_main; +} + +/// Get the address of the symbol +pub unsafe fn addr_from_symbol(symbol: &str) -> Option { + let sym_num = kallsyms_num as usize; + let sym_names = kallsyms_names as *const u8; + let kallsyms_address_list = + core::slice::from_raw_parts(kallsyms_address as *const u64, sym_num); + let sym_names_index = kallsyms_names_index as *const u64; + let sym_names_index_list = core::slice::from_raw_parts(sym_names_index, sym_num); + for i in 0..sym_num { + let sym_name_cstr = CStr::from_ptr(sym_names.add(sym_names_index_list[i] as usize) as _); + let sym_name = sym_name_cstr.to_str().unwrap(); + if sym_name == symbol { + return Some(kallsyms_address_list[i]); + } + } + None +} diff --git a/kernel/src/debug/traceback/traceback.c b/kernel/src/debug/traceback/traceback.c deleted file mode 100644 index 9a2fb7e7..00000000 --- a/kernel/src/debug/traceback/traceback.c +++ /dev/null @@ -1,84 +0,0 @@ -#include "traceback.h" -#include -#include -#include - -int lookup_kallsyms(uint64_t addr, int level) -{ - const char *str = (const char *)&kallsyms_names; - - // 暴力查找符合要求的symbol - // todo: 改用二分搜索。 - // 由于符号表使用nm -n生成,因此是按照地址升序排列的,因此可以二分 - uint64_t index = 0; - for (index = 0; index < kallsyms_num - 1; ++index) - { - if (addr > kallsyms_address[index] && addr <= kallsyms_address[index + 1]) - break; - } - - if (index < kallsyms_num) // 找到对应的函数 - { - // 依次输出函数名称、rip离函数起始处的偏移量、函数执行的rip - printk("function:%s() \t(+) %04d address:%#018lx\n", &str[kallsyms_names_index[index]], addr - kallsyms_address[index], addr); - return 0; - } - else - return -1; -} - -uint64_t addr_from_symbol(const char *symbol) -{ - const char *str = (const char *)&kallsyms_names; - for (uint64_t i = 0; i < kallsyms_num; ++i) - { - if (strcmp(&str[kallsyms_names_index[i]], symbol) == 0) - return kallsyms_address[i]; - } - return 0; - -} - -/** - * @brief 追溯内核栈调用情况 - * - * @param regs 内核栈结构体 - */ -void traceback(struct pt_regs *regs) -{ - // 先检验是否为用户态出错,若为用户态出错,则直接返回 - if (verify_area(regs->rbp, 0)) - { - printk_color(YELLOW, BLACK, "Kernel traceback: Fault in userland. pid=%ld, rbp=%#018lx\n", rs_current_pcb_pid(), regs->rbp); - return; - } - - uint64_t *rbp = (uint64_t *)regs->rbp; - printk_color(YELLOW, BLACK, "======== Kernel traceback =======\n"); - // printk("&kallsyms_address:%#018lx,kallsyms_address:%#018lx\n", &kallsyms_address, kallsyms_address); - // printk("&kallsyms_syms_num:%#018lx,kallsyms_syms_num:%d\n", &kallsyms_num, kallsyms_num); - // printk("&kallsyms_index:%#018lx\n", &kallsyms_names_index); - // printk("&kallsyms_names:%#018lx,kallsyms_names:%s\n", &kallsyms_names, &kallsyms_names); - - uint64_t ret_addr = regs->rip; - // 最大追踪10层调用栈 - for (int i = 0; i < 10; ++i) - { - if (lookup_kallsyms(ret_addr, i) != 0) - break; - - // 当前栈帧的rbp的地址大于等于内核栈的rbp的时候,表明调用栈已经到头了,追踪结束。 - // 当前rbp的地址为用户空间时,直接退出 - if ((uint64_t)(rbp) >= rs_current_pcb_thread_rbp() || ((uint64_t)rbp < regs->rsp)) - break; - - printk_color(ORANGE, BLACK, "rbp:%#018lx,*rbp:%#018lx\n", rbp, *rbp); - - // 由于x86处理器在执行call指令时,先将调用返回地址压入栈中,然后再把函数的rbp入栈,最后将rsp设为新的rbp。 - // 因此,此处的rbp就是上一层的rsp,那么,*(rbp+1)得到的就是上一层函数的返回地址 - ret_addr = *(rbp + 1); - rbp = (uint64_t *)(*rbp); - printk("\n"); - } - printk_color(YELLOW, BLACK, "======== Kernel traceback end =======\n"); -} \ No newline at end of file diff --git a/kernel/src/debug/traceback/traceback.h b/kernel/src/debug/traceback/traceback.h deleted file mode 100644 index d2b6274c..00000000 --- a/kernel/src/debug/traceback/traceback.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include -#include - -// 使用弱引用属性导出kallsyms中的符号表。 -// 采用weak属性是由于第一次编译时,kallsyms还未链接进来,若不使用weak属性则会报错 -extern const uint64_t kallsyms_address[] __attribute__((weak)); -extern const uint64_t kallsyms_num __attribute__((weak)); -extern const uint64_t kallsyms_names_index[] __attribute__((weak)); -extern const char *kallsyms_names __attribute__((weak)); - -/** - * @brief 追溯内核栈调用情况 - * - * @param regs 内核栈结构体 - */ -void traceback(struct pt_regs *regs); -uint64_t addr_from_symbol(const char *symbol); \ No newline at end of file diff --git a/kernel/src/debug/tracing/events.rs b/kernel/src/debug/tracing/events.rs new file mode 100644 index 00000000..5ab123a0 --- /dev/null +++ b/kernel/src/debug/tracing/events.rs @@ -0,0 +1,195 @@ +use alloc::string::ToString; + +use crate::debug::tracing::TracingDirCallBack; +use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData}; +use crate::filesystem::kernfs::KernFSInode; +use crate::filesystem::vfs::syscall::ModeType; +use crate::filesystem::vfs::PollStatus; +use crate::tracepoint::*; +use alloc::sync::Arc; +use system_error::SystemError; + +#[derive(Debug)] +struct EnableCallBack; + +impl KernFSCallback for EnableCallBack { + fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> { + Ok(()) + } + + fn read( + &self, + data: KernCallbackData, + buf: &mut [u8], + offset: usize, + ) -> Result { + let pri_data = data.private_data().as_ref().unwrap(); + let tracepoint_info = pri_data.debugfs_tracepoint().unwrap(); + let enable_value = tracepoint_info.enable_file().read(); + if offset >= enable_value.as_bytes().len() { + return Ok(0); // Offset is beyond the length of the string + } + let len = buf.len().min(enable_value.as_bytes().len() - offset); + buf[..len].copy_from_slice(&enable_value.as_bytes()[offset..offset + len]); + Ok(len) + } + + fn write( + &self, + data: KernCallbackData, + buf: &[u8], + _offset: usize, + ) -> Result { + let pri_data = data.private_data().as_ref().unwrap(); + let tracepoint = pri_data.debugfs_tracepoint().unwrap(); + if buf.is_empty() { + return Err(SystemError::EINVAL); + } + tracepoint.enable_file().write(buf[0] as _); + Ok(buf.len()) + } + + fn poll(&self, _data: KernCallbackData) -> Result { + Err(SystemError::ENOSYS) + } +} + +#[derive(Debug)] +struct FormatCallBack; + +impl KernFSCallback for FormatCallBack { + fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> { + Ok(()) + } + + fn read( + &self, + data: KernCallbackData, + buf: &mut [u8], + offset: usize, + ) -> Result { + let pri_data = data.private_data().as_ref().unwrap(); + let tracepoint = pri_data.debugfs_tracepoint().unwrap(); + let format_str = tracepoint.format_file().read(); + if offset >= format_str.as_bytes().len() { + return Ok(0); // Offset is beyond the length of the string + } + let len = buf.len().min(format_str.as_bytes().len() - offset); + buf[..len].copy_from_slice(&format_str.as_bytes()[offset..offset + len]); + Ok(len) + } + + fn write( + &self, + _data: KernCallbackData, + _buf: &[u8], + _offset: usize, + ) -> Result { + Err(SystemError::EPERM) + } + + fn poll(&self, _data: KernCallbackData) -> Result { + Err(SystemError::ENOSYS) + } +} + +#[derive(Debug)] +struct IDCallBack; +impl KernFSCallback for IDCallBack { + fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> { + Ok(()) + } + + fn read( + &self, + data: KernCallbackData, + buf: &mut [u8], + offset: usize, + ) -> Result { + let pri_data = data.private_data().as_ref().unwrap(); + let tracepoint = pri_data.debugfs_tracepoint().unwrap(); + let id_str = tracepoint.id_file().read(); + + if offset >= id_str.as_bytes().len() { + return Ok(0); // Offset is beyond the length of the string + } + let len = buf.len().min(id_str.as_bytes().len() - offset); + buf[..len].copy_from_slice(&id_str.as_bytes()[offset..offset + len]); + Ok(len) + } + + fn write( + &self, + _data: KernCallbackData, + _buf: &[u8], + _offset: usize, + ) -> Result { + Err(SystemError::EPERM) + } + + fn poll(&self, _data: KernCallbackData) -> Result { + Err(SystemError::ENOSYS) + } +} + +static mut TRACING_EVENTS_MANAGER: Option = None; + +pub fn tracing_events_manager() -> &'static TracingEventsManager { + unsafe { + TRACING_EVENTS_MANAGER + .as_ref() + .expect("TracingEventsManager not initialized") + } +} + +pub fn init_events(root: Arc) -> Result<(), SystemError> { + let events_manager = crate::tracepoint::global_init_events()?; + // Register the global tracing events manager + for subsystem_name in events_manager.subsystem_names() { + let subsystem = events_manager.get_subsystem(&subsystem_name).unwrap(); + // Register the subsystem in the root inode + let subsystem_inode = root.add_dir( + subsystem_name, + ModeType::from_bits_truncate(0o755), + None, + Some(&TracingDirCallBack), + )?; + for event_name in subsystem.event_names() { + let event_info = subsystem.get_event(&event_name).unwrap(); + let event_inode = subsystem_inode.add_dir( + event_name, + ModeType::from_bits_truncate(0o755), + None, + Some(&TracingDirCallBack), + )?; + // add enable file for the event + let _enable_inode = event_inode.add_file( + "enable".to_string(), + ModeType::from_bits_truncate(0o644), + None, + Some(KernInodePrivateData::DebugFS(event_info.clone())), + Some(&EnableCallBack), + )?; + // add format file for the event + let _format_inode = event_inode.add_file( + "format".to_string(), + ModeType::from_bits_truncate(0o644), + None, + Some(KernInodePrivateData::DebugFS(event_info.clone())), + Some(&FormatCallBack), + )?; + // add id file for the event + let _id_inode = event_inode.add_file( + "id".to_string(), + ModeType::from_bits_truncate(0o644), + None, + Some(KernInodePrivateData::DebugFS(event_info)), + Some(&IDCallBack), + )?; + } + } + unsafe { + TRACING_EVENTS_MANAGER = Some(events_manager); + } + Ok(()) +} diff --git a/kernel/src/debug/tracing/mod.rs b/kernel/src/debug/tracing/mod.rs new file mode 100644 index 00000000..130bebe0 --- /dev/null +++ b/kernel/src/debug/tracing/mod.rs @@ -0,0 +1,135 @@ +mod events; +pub mod trace_pipe; + +use crate::debug::sysfs::debugfs_kset; +use crate::driver::base::kobject::KObject; +use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData}; +use crate::filesystem::kernfs::KernFSInode; +use crate::filesystem::vfs::syscall::ModeType; +use crate::filesystem::vfs::PollStatus; +use crate::libs::spinlock::SpinLock; +use crate::tracepoint::TracePointInfo; +use alloc::string::ToString; +use alloc::sync::Arc; +use system_error::SystemError; + +static mut TRACING_ROOT_INODE: Option> = None; + +static TRACE_RAW_PIPE: SpinLock = + SpinLock::new(crate::tracepoint::TracePipeRaw::new(4096)); + +static TRACE_CMDLINE_CACHE: SpinLock = + SpinLock::new(crate::tracepoint::TraceCmdLineCache::new(128)); + +pub fn trace_pipe_push_raw_record(record: &[u8]) { + TRACE_RAW_PIPE.lock().push_event(record.to_vec()); +} + +pub fn trace_cmdline_push(pid: u32) { + let process = crate::process::ProcessManager::current_pcb(); + let binding = process.basic(); + let pname = binding + .name() + .split(' ') + .next() + .unwrap_or("unknown") + .split('/') + .last() + .unwrap_or("unknown"); + TRACE_CMDLINE_CACHE.lock().insert(pid, pname.to_string()); +} + +#[allow(unused)] +fn tracing_root_inode() -> Arc { + unsafe { TRACING_ROOT_INODE.clone().unwrap() } +} + +#[derive(Debug)] +pub struct TracingDirCallBack; + +impl KernFSCallback for TracingDirCallBack { + fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> { + Ok(()) + } + + fn read( + &self, + _data: KernCallbackData, + _buf: &mut [u8], + _offset: usize, + ) -> Result { + Err(SystemError::EISDIR) + } + + fn write( + &self, + _data: KernCallbackData, + _buf: &[u8], + _offset: usize, + ) -> Result { + Err(SystemError::EISDIR) + } + + fn poll(&self, _data: KernCallbackData) -> Result { + Err(SystemError::EISDIR) + } +} + +impl KernInodePrivateData { + pub fn debugfs_tracepoint(&self) -> Option<&Arc> { + return match self { + KernInodePrivateData::DebugFS(tracepoint) => Some(tracepoint), + _ => None, + }; + } + + pub fn tracepipe(&mut self) -> Option<&mut crate::tracepoint::TracePipeSnapshot> { + return match self { + KernInodePrivateData::TracePipe(snapshot) => Some(snapshot), + _ => None, + }; + } +} + +/// Initialize the debugfs tracing directory +pub fn init_debugfs_tracing() -> Result<(), SystemError> { + let debugfs = debugfs_kset(); + let root_dir = debugfs.inode().ok_or(SystemError::ENOENT)?; + let tracing_root = root_dir.add_dir( + "tracing".to_string(), + ModeType::from_bits_truncate(0o555), + None, + Some(&TracingDirCallBack), + )?; + let events_root = tracing_root.add_dir( + "events".to_string(), + ModeType::from_bits_truncate(0o755), + None, + Some(&TracingDirCallBack), + )?; + + // tracing_root.add_file( + // "trace".to_string(), + // ModeType::from_bits_truncate(0o444), + // Some(4096), + // None, + // Some(&trace_pipe::TraceCallBack), + // )?; + + tracing_root.add_file_lazy("trace".to_string(), trace_pipe::kernel_inode_provider)?; + + tracing_root.add_file( + "trace_pipe".to_string(), + ModeType::from_bits_truncate(0o444), + Some(4096), + None, + Some(&trace_pipe::TracePipeCallBack), + )?; + + events::init_events(events_root)?; + + unsafe { + TRACING_ROOT_INODE = Some(tracing_root); + } + Ok(()) +} diff --git a/kernel/src/debug/tracing/trace_pipe.rs b/kernel/src/debug/tracing/trace_pipe.rs new file mode 100644 index 00000000..6fa849e4 --- /dev/null +++ b/kernel/src/debug/tracing/trace_pipe.rs @@ -0,0 +1,154 @@ +use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData}; +use crate::filesystem::kernfs::{KernFSInodeArgs, KernInodeType}; +use crate::filesystem::vfs::syscall::ModeType; +use crate::filesystem::vfs::PollStatus; +use crate::libs::wait_queue::WaitQueue; +use crate::process::{ProcessFlags, ProcessManager}; +use crate::sched::SchedMode; +use crate::tracepoint::{TraceEntryParser, TracePipeOps}; +use core::fmt::Debug; +use system_error::SystemError; + +fn common_trace_pipe_read( + trace_buf: &mut dyn TracePipeOps, + buf: &mut [u8], +) -> Result { + let manager = super::events::tracing_events_manager(); + let tracepint_map = manager.tracepoint_map(); + let trace_cmdline_cache = super::TRACE_CMDLINE_CACHE.lock(); + // read real trace data + let mut copy_len = 0; + let mut peek_flag = false; + loop { + if let Some(record) = trace_buf.peek() { + let record_str = TraceEntryParser::parse(&tracepint_map, &trace_cmdline_cache, record); + if copy_len + record_str.len() > buf.len() { + break; // Buffer is full + } + let len = record_str.len(); + buf[copy_len..copy_len + len].copy_from_slice(record_str.as_bytes()); + copy_len += len; + peek_flag = true; + } + if peek_flag { + trace_buf.pop(); // Remove the record after reading + peek_flag = false; + } else { + break; // No more records to read + } + } + Ok(copy_len) +} + +#[derive(Debug)] +pub struct TraceCallBack; + +impl KernFSCallback for TraceCallBack { + fn open(&self, mut data: KernCallbackData) -> Result<(), SystemError> { + let pri_data = data.private_data_mut(); + let snapshot = super::TRACE_RAW_PIPE.lock().snapshot(); + pri_data.replace(KernInodePrivateData::TracePipe(snapshot)); + Ok(()) + } + + fn read( + &self, + mut data: KernCallbackData, + buf: &mut [u8], + offset: usize, + ) -> Result { + let pri_data = data.private_data_mut().as_mut().unwrap(); + let snapshot = pri_data.tracepipe().unwrap(); + + let default_fmt_str = snapshot.default_fmt_str(); + if offset >= default_fmt_str.len() { + common_trace_pipe_read(snapshot, buf) + } else { + let len = buf.len().min(default_fmt_str.len() - offset); + buf[..len].copy_from_slice(&default_fmt_str.as_bytes()[offset..offset + len]); + Ok(len) + } + } + + fn write( + &self, + _data: KernCallbackData, + _buf: &[u8], + _offset: usize, + ) -> Result { + Err(SystemError::EPERM) + } + + fn poll(&self, _data: KernCallbackData) -> Result { + Ok(PollStatus::READ) + } +} + +pub fn kernel_inode_provider() -> KernFSInodeArgs { + KernFSInodeArgs { + mode: ModeType::from_bits_truncate(0o444), + callback: Some(&TraceCallBack), + inode_type: KernInodeType::File, + size: Some(4096), + private_data: None, + } +} + +static TracePipeCallBackWaitQueue: WaitQueue = WaitQueue::default(); + +#[derive(Debug)] +pub struct TracePipeCallBack; + +impl TracePipeCallBack { + fn readable(&self) -> bool { + let trace_raw_pipe = super::TRACE_RAW_PIPE.lock(); + !trace_raw_pipe.is_empty() + } +} + +impl KernFSCallback for TracePipeCallBack { + fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> { + Ok(()) + } + + fn read( + &self, + data: KernCallbackData, + buf: &mut [u8], + _offset: usize, + ) -> Result { + drop(data); // We don't need the data here, release the internal lock + let read_len = loop { + let mut trace_raw_pipe = super::TRACE_RAW_PIPE.lock(); + let read_len = common_trace_pipe_read(&mut *trace_raw_pipe, buf).unwrap(); + if read_len != 0 { + break read_len; + } + // Release the lock before waiting + drop(trace_raw_pipe); + // wait for new data + let r = wq_wait_event_interruptible!(TracePipeCallBackWaitQueue, self.readable(), {}); + if r.is_err() { + ProcessManager::current_pcb() + .flags() + .insert(ProcessFlags::HAS_PENDING_SIGNAL); + return Err(SystemError::ERESTARTSYS); + } + // todo!(wq_wait_event_interruptible may has a bug) + }; + Ok(read_len) + } + + fn write( + &self, + _data: KernCallbackData, + _buf: &[u8], + _offset: usize, + ) -> Result { + Err(SystemError::EPERM) + } + + fn poll(&self, _data: KernCallbackData) -> Result { + Ok(PollStatus::READ) + } +} diff --git a/kernel/src/driver/acpi/sysfs.rs b/kernel/src/driver/acpi/sysfs.rs index d382ed12..34b93db3 100644 --- a/kernel/src/driver/acpi/sysfs.rs +++ b/kernel/src/driver/acpi/sysfs.rs @@ -22,6 +22,42 @@ use log::{debug, error, warn}; use system_error::SystemError; use super::{acpi_kset, AcpiManager}; + +// 定义所有ACPI表结构体 +macro_rules! define_acpi_tables { + ($($name:ident),*) => { + $( + #[repr(transparent)] + #[allow(non_snake_case)] + #[allow(non_camel_case_types)] + struct $name { + header: SdtHeader, + } + + unsafe impl acpi::AcpiTable for $name { + const SIGNATURE: acpi::sdt::Signature = acpi::sdt::Signature::$name; + fn header(&self) -> &acpi::sdt::SdtHeader { + return &self.header; + } + } + )* + }; +} + +define_acpi_tables!( + RSDT, XSDT, FADT, HPET, MADT, MCFG, SSDT, BERT, BGRT, CPEP, DSDT, ECDT, EINJ, ERST, FACS, FPDT, + GTDT, HEST, MSCT, MPST, NFIT, PCCT, PHAT, PMTT, PSDT, RASF, SBST, SDEV, SLIT, SRAT, AEST, BDAT, + CDIT, CEDT, CRAT, CSRT, DBGP, DBG2, DMAR, DRTM, ETDT, IBFT, IORT, IVRS, LPIT, MCHI, MPAM, MSDM, + PRMT, RGRT, SDEI, SLIC, SPCR, SPMI, STAO, SVKL, TCPA, TPM2, UEFI, WAET, WDAT, WDRT, WPBT, WSMT, + XENV +); + +macro_rules! handle_read_table { + ($name: ident, $name_str: expr, $tables: expr, $buf: expr, $offset: expr) => {{ + AttrAcpiTable::do_binattr_read_table::<$name>($tables, $name_str, $buf, $offset) + }}; +} + static mut __HOTPLUG_KSET_INSTANCE: Option> = None; static mut __ACPI_TABLES_KSET_INSTANCE: Option> = None; static mut __ACPI_TABLES_DATA_KSET_INSTANCE: Option> = None; @@ -201,6 +237,260 @@ impl AttrAcpiTable { )?; return Ok(result); } + + #[inline(never)] + fn do_binattr_read_table( + tables: &'static acpi::AcpiTables, + name: &str, + buf: &mut [u8], + offset: usize, + ) -> Result { + let table = tables.find_entire_table::().map_err(|e| { + warn!( + "AttrAcpiTable::read(): failed to find table. name: {}, error: {:?}", + name, e + ); + SystemError::ENODEV + })?; + + let from = unsafe { + core::slice::from_raw_parts( + table.virtual_start().as_ptr() as *const u8, + table.region_length(), + ) + }; + if offset >= from.len() { + return Ok(0); + } + let mut count = buf.len(); + if count > from.len() - offset { + count = from.len() - offset; + } + buf[0..count].copy_from_slice(&from[offset..offset + count]); + return Ok(count); + } + + #[inline(never)] + fn do_binattr_read_1( + &self, + tables: &'static acpi::AcpiTables, + name_str: &str, + buf: &mut [u8], + offset: usize, + ) -> Result { + match name_str { + "RSDT" => { + handle_read_table!(RSDT, name_str, tables, buf, offset) + } + "XSDT" => { + handle_read_table!(XSDT, name_str, tables, buf, offset) + } + "FACP" => { + handle_read_table!(FADT, name_str, tables, buf, offset) + } + "HPET" => { + handle_read_table!(HPET, name_str, tables, buf, offset) + } + "APIC" => { + handle_read_table!(MADT, name_str, tables, buf, offset) + } + "MCFG" => { + handle_read_table!(MCFG, name_str, tables, buf, offset) + } + "SSDT" => { + handle_read_table!(SSDT, name_str, tables, buf, offset) + } + "BERT" => { + handle_read_table!(BERT, name_str, tables, buf, offset) + } + "BGRT" => { + handle_read_table!(BGRT, name_str, tables, buf, offset) + } + "CPEP" => { + handle_read_table!(CPEP, name_str, tables, buf, offset) + } + "DSDT" => { + handle_read_table!(DSDT, name_str, tables, buf, offset) + } + "ECDT" => { + handle_read_table!(ECDT, name_str, tables, buf, offset) + } + "EINJ" => { + handle_read_table!(EINJ, name_str, tables, buf, offset) + } + "ERST" => { + handle_read_table!(ERST, name_str, tables, buf, offset) + } + "FACS" => { + handle_read_table!(FACS, name_str, tables, buf, offset) + } + "FPDT" => { + handle_read_table!(FPDT, name_str, tables, buf, offset) + } + "GTDT" => { + handle_read_table!(GTDT, name_str, tables, buf, offset) + } + "HEST" => { + handle_read_table!(HEST, name_str, tables, buf, offset) + } + + _ => Err(SystemError::ENODEV), + } + } + + #[inline(never)] + fn do_binattr_read_2( + &self, + tables: &'static acpi::AcpiTables, + name_str: &str, + buf: &mut [u8], + offset: usize, + ) -> Result { + match name_str { + "MSCT" => { + handle_read_table!(MSCT, name_str, tables, buf, offset) + } + "MPST" => { + handle_read_table!(MPST, name_str, tables, buf, offset) + } + "NFIT" => { + handle_read_table!(NFIT, name_str, tables, buf, offset) + } + "PCCT" => { + handle_read_table!(PCCT, name_str, tables, buf, offset) + } + "PHAT" => { + handle_read_table!(PHAT, name_str, tables, buf, offset) + } + "PMTT" => { + handle_read_table!(PMTT, name_str, tables, buf, offset) + } + "PSDT" => { + handle_read_table!(PSDT, name_str, tables, buf, offset) + } + "RASF" => { + handle_read_table!(RASF, name_str, tables, buf, offset) + } + "SBST" => { + handle_read_table!(SBST, name_str, tables, buf, offset) + } + "SDEV" => { + handle_read_table!(SDEV, name_str, tables, buf, offset) + } + "SLIT" => { + handle_read_table!(SLIT, name_str, tables, buf, offset) + } + "SRAT" => { + handle_read_table!(SRAT, name_str, tables, buf, offset) + } + "AEST" => { + handle_read_table!(AEST, name_str, tables, buf, offset) + } + "BDAT" => { + handle_read_table!(BDAT, name_str, tables, buf, offset) + } + "CDIT" => { + handle_read_table!(CDIT, name_str, tables, buf, offset) + } + "CEDT" => { + handle_read_table!(CEDT, name_str, tables, buf, offset) + } + "CRAT" => { + handle_read_table!(CRAT, name_str, tables, buf, offset) + } + "CSRT" => { + handle_read_table!(CSRT, name_str, tables, buf, offset) + } + "DBGP" => { + handle_read_table!(DBGP, name_str, tables, buf, offset) + } + "DBG2" => { + handle_read_table!(DBG2, name_str, tables, buf, offset) + } + "DMAR" => { + handle_read_table!(DMAR, name_str, tables, buf, offset) + } + "DRTM" => { + handle_read_table!(DRTM, name_str, tables, buf, offset) + } + "ETDT" => { + handle_read_table!(ETDT, name_str, tables, buf, offset) + } + "IBFT" => { + handle_read_table!(IBFT, name_str, tables, buf, offset) + } + "IORT" => { + handle_read_table!(IORT, name_str, tables, buf, offset) + } + "IVRS" => { + handle_read_table!(IVRS, name_str, tables, buf, offset) + } + "LPIT" => { + handle_read_table!(LPIT, name_str, tables, buf, offset) + } + "MCHI" => { + handle_read_table!(MCHI, name_str, tables, buf, offset) + } + "MPAM" => { + handle_read_table!(MPAM, name_str, tables, buf, offset) + } + "MSDM" => { + handle_read_table!(MSDM, name_str, tables, buf, offset) + } + "PRMT" => { + handle_read_table!(PRMT, name_str, tables, buf, offset) + } + "RGRT" => { + handle_read_table!(RGRT, name_str, tables, buf, offset) + } + "SDEI" => { + handle_read_table!(SDEI, name_str, tables, buf, offset) + } + "SLIC" => { + handle_read_table!(SLIC, name_str, tables, buf, offset) + } + "SPCR" => { + handle_read_table!(SPCR, name_str, tables, buf, offset) + } + "SPMI" => { + handle_read_table!(SPMI, name_str, tables, buf, offset) + } + "STAO" => { + handle_read_table!(STAO, name_str, tables, buf, offset) + } + "SVKL" => { + handle_read_table!(SVKL, name_str, tables, buf, offset) + } + "TCPA" => { + handle_read_table!(TCPA, name_str, tables, buf, offset) + } + "TPM2" => { + handle_read_table!(TPM2, name_str, tables, buf, offset) + } + "UEFI" => { + handle_read_table!(UEFI, name_str, tables, buf, offset) + } + "WAET" => { + handle_read_table!(WAET, name_str, tables, buf, offset) + } + "WDAT" => { + handle_read_table!(WDAT, name_str, tables, buf, offset) + } + "WDRT" => { + handle_read_table!(WDRT, name_str, tables, buf, offset) + } + "WPBT" => { + handle_read_table!(WPBT, name_str, tables, buf, offset) + } + "WSMT" => { + handle_read_table!(WSMT, name_str, tables, buf, offset) + } + "XENV" => { + handle_read_table!(XENV, name_str, tables, buf, offset) + } + _ => Err(SystemError::ENODEV), + } + } } impl Attribute for AttrAcpiTable { @@ -247,262 +537,19 @@ impl BinAttribute for AttrAcpiTable { buf: &mut [u8], offset: usize, ) -> Result { - macro_rules! copy_data { - ($table:expr) => { - let from = unsafe { - core::slice::from_raw_parts( - $table.virtual_start().as_ptr() as *const u8, - $table.region_length(), - ) - }; - if offset >= from.len() { - return Ok(0); - } - let mut count = buf.len(); - if count > from.len() - offset { - count = from.len() - offset; - } - buf[0..count].copy_from_slice(&from[offset..offset + count]); - return Ok(count); - }; - } - - macro_rules! define_struct { - ($name:ident) => { - #[repr(transparent)] - #[allow(non_snake_case)] - #[allow(non_camel_case_types)] - struct $name { - header: SdtHeader, - } - - unsafe impl acpi::AcpiTable for $name { - const SIGNATURE: acpi::sdt::Signature = acpi::sdt::Signature::$name; - fn header(&self) -> &acpi::sdt::SdtHeader { - return &self.header; - } - } - }; - } - - macro_rules! handle { - ($name: ident, $tables: expr) => { - define_struct!($name); - let table = $tables.find_entire_table::<$name>().map_err(|e| { - warn!( - "AttrAcpiTable::read(): failed to find table. name: {}, error: {:?}", - self.name, e - ); - SystemError::ENODEV - })?; - - copy_data!(table); - }; - } - let tables = acpi_manager().tables().unwrap(); - match self.name.as_str() { - "RSDT" => { - handle!(RSDT, tables); - } - "XSDT" => { - handle!(XSDT, tables); - } - "FACP" => { - handle!(FADT, tables); - } - "HPET" => { - handle!(HPET, tables); - } - "APIC" => { - handle!(MADT, tables); - } - "MCFG" => { - handle!(MCFG, tables); - } - "SSDT" => { - handle!(SSDT, tables); - } - "BERT" => { - handle!(BERT, tables); - } - "BGRT" => { - handle!(BGRT, tables); - } - "CPEP" => { - handle!(CPEP, tables); - } - "DSDT" => { - handle!(DSDT, tables); - } - "ECDT" => { - handle!(ECDT, tables); - } - "EINJ" => { - handle!(EINJ, tables); - } - "ERST" => { - handle!(ERST, tables); - } - "FACS" => { - handle!(FACS, tables); - } - "FPDT" => { - handle!(FPDT, tables); - } - "GTDT" => { - handle!(GTDT, tables); - } - "HEST" => { - handle!(HEST, tables); - } - "MSCT" => { - handle!(MSCT, tables); - } - "MPST" => { - handle!(MPST, tables); - } - "NFIT" => { - handle!(NFIT, tables); - } - "PCCT" => { - handle!(PCCT, tables); - } - "PHAT" => { - handle!(PHAT, tables); - } - "PMTT" => { - handle!(PMTT, tables); - } - "PSDT" => { - handle!(PSDT, tables); - } - "RASF" => { - handle!(RASF, tables); - } - "SBST" => { - handle!(SBST, tables); - } - "SDEV" => { - handle!(SDEV, tables); - } - "SLIT" => { - handle!(SLIT, tables); - } - "SRAT" => { - handle!(SRAT, tables); - } - "AEST" => { - handle!(AEST, tables); - } - "BDAT" => { - handle!(BDAT, tables); - } - "CDIT" => { - handle!(CDIT, tables); - } - "CEDT" => { - handle!(CEDT, tables); - } - "CRAT" => { - handle!(CRAT, tables); - } - "CSRT" => { - handle!(CSRT, tables); - } - "DBGP" => { - handle!(DBGP, tables); - } - "DBG2" => { - handle!(DBG2, tables); - } - "DMAR" => { - handle!(DMAR, tables); - } - "DRTM" => { - handle!(DRTM, tables); - } - "ETDT" => { - handle!(ETDT, tables); - } - "IBFT" => { - handle!(IBFT, tables); - } - "IORT" => { - handle!(IORT, tables); - } - "IVRS" => { - handle!(IVRS, tables); - } - "LPIT" => { - handle!(LPIT, tables); - } - "MCHI" => { - handle!(MCHI, tables); - } - "MPAM" => { - handle!(MPAM, tables); - } - "MSDM" => { - handle!(MSDM, tables); - } - "PRMT" => { - handle!(PRMT, tables); - } - "RGRT" => { - handle!(RGRT, tables); - } - "SDEI" => { - handle!(SDEI, tables); - } - "SLIC" => { - handle!(SLIC, tables); - } - "SPCR" => { - handle!(SPCR, tables); - } - "SPMI" => { - handle!(SPMI, tables); - } - "STAO" => { - handle!(STAO, tables); - } - "SVKL" => { - handle!(SVKL, tables); - } - "TCPA" => { - handle!(TCPA, tables); - } - "TPM2" => { - handle!(TPM2, tables); - } - "UEFI" => { - handle!(UEFI, tables); - } - "WAET" => { - handle!(WAET, tables); - } - "WDAT" => { - handle!(WDAT, tables); - } - "WDRT" => { - handle!(WDRT, tables); - } - "WPBT" => { - handle!(WPBT, tables); - } - "WSMT" => { - handle!(WSMT, tables); - } - "XENV" => { - handle!(XENV, tables); - } + let name_str = self.name.as_str(); + // 这里分多个函数进行处理,是为了减小栈内存的使用。 + if let Ok(x) = self.do_binattr_read_1(tables, name_str, buf, offset) { + return Ok(x); + } - _ => { - error!("AttrAcpiTable::read(): unknown table. name: {}", self.name); - return Err(SystemError::ENODEV); - } - }; + if let Ok(x) = self.do_binattr_read_2(tables, name_str, buf, offset) { + return Ok(x); + } + + error!("AttrAcpiTable::read(): unknown table. name: {}", self.name); + return Err(SystemError::ENODEV); } fn size(&self) -> usize { diff --git a/kernel/src/driver/base/block/block_device.rs b/kernel/src/driver/base/block/block_device.rs index c02464a0..4b481b63 100644 --- a/kernel/src/driver/base/block/block_device.rs +++ b/kernel/src/driver/base/block/block_device.rs @@ -3,7 +3,7 @@ use crate::driver::{ base::{ device::{ device_number::{DeviceNumber, Major}, - Device, DeviceError, IdTable, BLOCKDEVS, + DevName, Device, DeviceError, IdTable, BLOCKDEVS, }, map::{ DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START, @@ -13,8 +13,8 @@ use crate::driver::{ block::cache::{cached_block_device::BlockCache, BlockCacheError, BLOCK_SIZE}, }; -use alloc::{string::String, sync::Arc, vec::Vec}; -use core::{any::Any, fmt::Display, ops::Deref}; +use alloc::{sync::Arc, vec::Vec}; +use core::any::Any; use log::error; use system_error::SystemError; @@ -221,74 +221,11 @@ pub fn __lba_to_bytes(lba_id: usize, blk_size: usize) -> BlockId { return lba_id * blk_size; } -/// 块设备的名字 -pub struct BlockDevName { - name: Arc, - id: usize, -} - -impl BlockDevName { - pub fn new(name: String, id: usize) -> Self { - return BlockDevName { - name: Arc::new(name), - id, - }; - } - - #[inline] - pub fn id(&self) -> usize { - return self.id; - } -} - -impl core::fmt::Debug for BlockDevName { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - return write!(f, "{}", self.name); - } -} - -impl Display for BlockDevName { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - return write!(f, "{}", self.name); - } -} - -impl Clone for BlockDevName { - fn clone(&self) -> Self { - return BlockDevName { - name: self.name.clone(), - id: self.id, - }; - } -} - -impl core::hash::Hash for BlockDevName { - fn hash(&self, state: &mut H) { - self.name.hash(state); - } -} - -impl Deref for BlockDevName { - type Target = String; - - fn deref(&self) -> &Self::Target { - return self.name.as_ref(); - } -} - -impl PartialEq for BlockDevName { - fn eq(&self, other: &Self) -> bool { - return self.name == other.name; - } -} - -impl Eq for BlockDevName {} - /// @brief 块设备应该实现的操作 pub trait BlockDevice: Device { /// # dev_name /// 返回块设备的名字 - fn dev_name(&self) -> &BlockDevName; + fn dev_name(&self) -> &DevName; fn blkdev_meta(&self) -> &BlockDevMeta; diff --git a/kernel/src/driver/base/block/manager.rs b/kernel/src/driver/base/block/manager.rs index 7fe6c291..0c901178 100644 --- a/kernel/src/driver/base/block/manager.rs +++ b/kernel/src/driver/base/block/manager.rs @@ -6,14 +6,14 @@ use system_error::SystemError; use unified_init::macros::unified_init; use crate::{ - driver::base::block::gendisk::GenDisk, + driver::base::{block::gendisk::GenDisk, device::DevName}, filesystem::mbr::MbrDiskPartionTable, init::initcall::INITCALL_POSTCORE, libs::spinlock::{SpinLock, SpinLockGuard}, }; use super::{ - block_device::{BlockDevName, BlockDevice, GeneralBlockRange}, + block_device::{BlockDevice, GeneralBlockRange}, gendisk::GenDiskMap, }; @@ -38,7 +38,7 @@ pub struct BlockDevManager { } struct InnerBlockDevManager { - disks: HashMap>, + disks: HashMap>, } impl BlockDevManager { pub fn new() -> Self { @@ -207,7 +207,7 @@ impl BlockDevManager { } pub struct BlockDevMeta { - pub devname: BlockDevName, + pub devname: DevName, inner: SpinLock, } @@ -216,7 +216,7 @@ pub struct InnerBlockDevMeta { } impl BlockDevMeta { - pub fn new(devname: BlockDevName) -> Self { + pub fn new(devname: DevName) -> Self { BlockDevMeta { devname, inner: SpinLock::new(InnerBlockDevMeta { diff --git a/kernel/src/driver/base/device/dd.rs b/kernel/src/driver/base/device/dd.rs index e90bea24..f79dabd2 100644 --- a/kernel/src/driver/base/device/dd.rs +++ b/kernel/src/driver/base/device/dd.rs @@ -144,6 +144,7 @@ impl DeviceManager { /// - Err(SystemError): 匹配过程中出现意外错误,没有匹配成功 /// /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/base/dd.c#899 + #[inline(never)] fn do_device_attach_driver( &self, driver: &Arc, diff --git a/kernel/src/driver/base/device/device_number.rs b/kernel/src/driver/base/device/device_number.rs index 41c19f58..1fe3d0ea 100644 --- a/kernel/src/driver/base/device/device_number.rs +++ b/kernel/src/driver/base/device/device_number.rs @@ -24,6 +24,8 @@ impl Major { pub const UNIX98_PTY_SLAVE_MAJOR: Self = Self::new(Self::UNIX98_PTY_MASTER_MAJOR.0 + Self::UNIX98_PTY_MAJOR_COUNT.0); + pub const HVC_MAJOR: Self = Self::new(229); + pub const fn new(x: u32) -> Self { Major(x) } @@ -58,6 +60,17 @@ impl DeviceNumber { pub const fn data(&self) -> u32 { self.data } + + /// acceptable for old filesystems + pub const fn old_valid_dev(&self) -> bool { + (self.major().data() < 256) && (self.minor() < 256) + } + + pub const fn new_encode_dev(&self) -> u32 { + let major = self.major().data(); + let minor = self.minor(); + return (minor & 0xff) | (major << 8) | ((minor & !0xff) << 12); + } } impl Default for DeviceNumber { diff --git a/kernel/src/driver/base/device/driver.rs b/kernel/src/driver/base/device/driver.rs index 3df9878a..a4076291 100644 --- a/kernel/src/driver/base/device/driver.rs +++ b/kernel/src/driver/base/device/driver.rs @@ -170,6 +170,7 @@ impl dyn Driver { /// ## 注意 /// /// 这里的默认实现很低效,请为特定的驱动自行实现高效的查询 + #[inline(never)] pub fn find_device_by_name(&self, name: &str) -> Option> { if let Some(r) = self.__find_device_by_name_fast(name) { return Some(r); diff --git a/kernel/src/driver/base/device/mod.rs b/kernel/src/driver/base/device/mod.rs index 7d05e901..5f2dbd50 100644 --- a/kernel/src/driver/base/device/mod.rs +++ b/kernel/src/driver/base/device/mod.rs @@ -26,8 +26,8 @@ use crate::{ }, }; -use core::intrinsics::unlikely; use core::{any::Any, fmt::Debug}; +use core::{fmt::Display, intrinsics::unlikely, ops::Deref}; use system_error::SystemError; use self::{ @@ -124,6 +124,69 @@ unsafe fn set_sys_devices_virtual_kset(kset: Arc) { DEVICES_VIRTUAL_KSET_INSTANCE = Some(kset); } +/// /dev下面的设备的名字 +pub struct DevName { + name: Arc, + id: usize, +} + +impl DevName { + pub fn new(name: String, id: usize) -> Self { + return DevName { + name: Arc::new(name), + id, + }; + } + + #[inline] + pub fn id(&self) -> usize { + return self.id; + } +} + +impl core::fmt::Debug for DevName { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + return write!(f, "{}", self.name); + } +} + +impl Display for DevName { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + return write!(f, "{}", self.name); + } +} + +impl Clone for DevName { + fn clone(&self) -> Self { + return DevName { + name: self.name.clone(), + id: self.id, + }; + } +} + +impl core::hash::Hash for DevName { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } +} + +impl Deref for DevName { + type Target = String; + + fn deref(&self) -> &Self::Target { + return self.name.as_ref(); + } +} + +impl PartialEq for DevName { + fn eq(&self, other: &Self) -> bool { + return self.name == other.name; + } +} + +impl Eq for DevName {} + /// 设备应该实现的操作 /// /// ## 注意 diff --git a/kernel/src/driver/block/virtio_blk.rs b/kernel/src/driver/block/virtio_blk.rs index 096ad504..a7cc2ca2 100644 --- a/kernel/src/driver/block/virtio_blk.rs +++ b/kernel/src/driver/block/virtio_blk.rs @@ -1,7 +1,9 @@ -use core::{any::Any, fmt::Debug}; +use core::{ + any::Any, + fmt::{Debug, Formatter}, +}; use alloc::{ - collections::LinkedList, string::{String, ToString}, sync::{Arc, Weak}, vec::Vec, @@ -16,7 +18,7 @@ use crate::{ driver::{ base::{ block::{ - block_device::{BlockDevName, BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}, + block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}, disk_info::Partition, manager::{block_dev_manager, BlockDevMeta}, }, @@ -24,7 +26,7 @@ use crate::{ device::{ bus::Bus, driver::{Driver, DriverCommonData}, - Device, DeviceCommonData, DeviceId, DeviceType, IdTable, + DevName, Device, DeviceCommonData, DeviceId, DeviceType, IdTable, }, kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, kset::KSet, @@ -103,7 +105,7 @@ pub struct VirtIOBlkManager { struct InnerVirtIOBlkManager { id_bmp: bitmap::StaticBitmap<{ VirtIOBlkManager::MAX_DEVICES }>, - devname: [Option; VirtIOBlkManager::MAX_DEVICES], + devname: [Option; VirtIOBlkManager::MAX_DEVICES], } impl VirtIOBlkManager { @@ -122,7 +124,7 @@ impl VirtIOBlkManager { self.inner.lock() } - pub fn alloc_id(&self) -> Option { + pub fn alloc_id(&self) -> Option { let mut inner = self.inner(); let idx = inner.id_bmp.first_false_index()?; inner.id_bmp.set(idx, true); @@ -132,9 +134,9 @@ impl VirtIOBlkManager { } /// Generate a new block device name like 'vda', 'vdb', etc. - fn format_name(id: usize) -> BlockDevName { + fn format_name(id: usize) -> DevName { let x = (b'a' + id as u8) as char; - BlockDevName::new(format!("vd{}", x), id) + DevName::new(format!("vd{}", x), id) } #[allow(dead_code)] @@ -148,7 +150,6 @@ impl VirtIOBlkManager { } /// virtio block device -#[derive(Debug)] #[cast_to([sync] VirtIODevice)] #[cast_to([sync] Device)] pub struct VirtIOBlkDevice { @@ -159,6 +160,15 @@ pub struct VirtIOBlkDevice { self_ref: Weak, } +impl Debug for VirtIOBlkDevice { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("VirtIOBlkDevice") + .field("devname", &self.blkdev_meta.devname) + .field("dev_id", &self.dev_id.id()) + .finish() + } +} + unsafe impl Send for VirtIOBlkDevice {} unsafe impl Sync for VirtIOBlkDevice {} @@ -204,7 +214,7 @@ impl VirtIOBlkDevice { } impl BlockDevice for VirtIOBlkDevice { - fn dev_name(&self) -> &BlockDevName { + fn dev_name(&self) -> &DevName { &self.blkdev_meta.devname } @@ -477,7 +487,9 @@ impl KObject for VirtIOBlkDevice { #[unified_init(INITCALL_POSTCORE)] fn virtio_blk_driver_init() -> Result<(), SystemError> { let driver = VirtIOBlkDriver::new(); - virtio_driver_manager().register(driver.clone() as Arc)?; + virtio_driver_manager() + .register(driver.clone() as Arc) + .expect("Add virtio blk driver failed"); unsafe { VIRTIO_BLK_DRIVER = Some(driver); } @@ -544,12 +556,12 @@ impl VirtIODriver for VirtIOBlkDriver { return Ok(()); } - fn virtio_id_table(&self) -> LinkedList { + fn virtio_id_table(&self) -> Vec { self.inner().virtio_driver_common.id_table.clone() } fn add_virtio_id(&self, id: VirtioDeviceId) { - self.inner().virtio_driver_common.id_table.push_back(id); + self.inner().virtio_driver_common.id_table.push(id); } } diff --git a/kernel/src/driver/char/mod.rs b/kernel/src/driver/char/mod.rs new file mode 100644 index 00000000..35d09221 --- /dev/null +++ b/kernel/src/driver/char/mod.rs @@ -0,0 +1 @@ +pub mod virtio_console; diff --git a/kernel/src/driver/char/virtio_console.rs b/kernel/src/driver/char/virtio_console.rs new file mode 100644 index 00000000..eff9ef7c --- /dev/null +++ b/kernel/src/driver/char/virtio_console.rs @@ -0,0 +1,750 @@ +use crate::{ + driver::{ + base::{ + class::Class, + device::{ + bus::Bus, + device_number::Major, + driver::{Driver, DriverCommonData}, + DevName, Device, DeviceCommonData, DeviceId, DeviceType, IdTable, + }, + kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kset::KSet, + }, + tty::{ + console::ConsoleSwitch, + kthread::send_to_tty_refresh_thread, + termios::{WindowSize, TTY_STD_TERMIOS}, + tty_core::{TtyCore, TtyCoreData}, + tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType, TtyOperation}, + virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, VirtConsole}, + }, + video::console::dummycon::dummy_console, + virtio::{ + sysfs::{virtio_bus, virtio_device_manager, virtio_driver_manager}, + transport::VirtIOTransport, + virtio_drivers_error_to_system_error, + virtio_impl::HalImpl, + VirtIODevice, VirtIODeviceIndex, VirtIODriver, VirtIODriverCommonData, VirtioDeviceId, + VIRTIO_VENDOR_ID, + }, + }, + exception::{irqdesc::IrqReturn, IrqNumber}, + filesystem::kernfs::KernFSInode, + init::initcall::INITCALL_POSTCORE, + libs::{ + lazy_init::Lazy, + rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, +}; +use alloc::string::String; +use alloc::string::ToString; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; +use bitmap::traits::BitMapOps; +use core::fmt::Debug; +use core::fmt::Formatter; +use core::{ + any::Any, + sync::atomic::{compiler_fence, Ordering}, +}; +use system_error::SystemError; +use unified_init::macros::unified_init; +use virtio_drivers::device::console::VirtIOConsole; + +const VIRTIO_CONSOLE_BASENAME: &str = "virtio_console"; +const HVC_MINOR: u32 = 0; + +static mut VIRTIO_CONSOLE_DRIVER: Option> = None; +static mut TTY_HVC_DRIVER: Option> = None; + +#[inline(always)] +fn tty_hvc_driver() -> &'static Arc { + unsafe { TTY_HVC_DRIVER.as_ref().unwrap() } +} + +pub fn virtio_console( + transport: VirtIOTransport, + dev_id: Arc, + dev_parent: Option>, +) { + log::debug!( + "virtio_console: dev_id: {:?}, parent: {:?}", + dev_id, + dev_parent.as_ref().map(|x| x.name()) + ); + let device = VirtIOConsoleDevice::new(transport, dev_id.clone()); + if device.is_none() { + return; + } + + let device = device.unwrap(); + + if let Some(dev_parent) = dev_parent { + device.set_dev_parent(Some(Arc::downgrade(&dev_parent))); + } + virtio_device_manager() + .device_add(device.clone() as Arc) + .expect("Add virtio console failed"); +} + +// + +#[cast_to([sync] VirtIODevice)] +#[cast_to([sync] Device)] +pub struct VirtIOConsoleDevice { + dev_name: Lazy, + dev_id: Arc, + _self_ref: Weak, + locked_kobj_state: LockedKObjectState, + inner: SpinLock, +} +unsafe impl Send for VirtIOConsoleDevice {} +unsafe impl Sync for VirtIOConsoleDevice {} + +impl Debug for VirtIOConsoleDevice { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("VirtIOConsoleDevice") + .field( + "devname", + &self + .dev_name + .try_get() + .map(|x| x.as_str()) + .unwrap_or("uninitialized"), + ) + .field("dev_id", &self.dev_id.id()) + .finish() + } +} + +impl VirtIOConsoleDevice { + pub fn new(transport: VirtIOTransport, dev_id: Arc) -> Option> { + // 设置中断 + if let Err(err) = transport.setup_irq(dev_id.clone()) { + log::error!( + "VirtIOConsoleDevice '{dev_id:?}' setup_irq failed: {:?}", + err + ); + return None; + } + + let irq = Some(transport.irq()); + let device_inner = VirtIOConsole::::new(transport); + if let Err(e) = device_inner { + log::error!("VirtIOConsoleDevice '{dev_id:?}' create failed: {:?}", e); + return None; + } + + let mut device_inner: VirtIOConsole = device_inner.unwrap(); + device_inner.enable_interrupts(); + + let dev = Arc::new_cyclic(|self_ref| Self { + dev_id, + dev_name: Lazy::new(), + _self_ref: self_ref.clone(), + locked_kobj_state: LockedKObjectState::default(), + inner: SpinLock::new(InnerVirtIOConsoleDevice { + device_inner, + name: None, + virtio_index: None, + device_common: DeviceCommonData::default(), + kobject_common: KObjectCommonData::default(), + irq, + }), + }); + + Some(dev) + } + + fn inner(&self) -> SpinLockGuard { + self.inner.lock_irqsave() + } +} + +struct InnerVirtIOConsoleDevice { + device_inner: VirtIOConsole, + virtio_index: Option, + name: Option, + device_common: DeviceCommonData, + kobject_common: KObjectCommonData, + irq: Option, +} + +impl Debug for InnerVirtIOConsoleDevice { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("InnerVirtIOConsoleDevice") + .field("virtio_index", &self.virtio_index) + .field("name", &self.name) + .field("device_common", &self.device_common) + .field("kobject_common", &self.kobject_common) + .field("irq", &self.irq) + .finish() + } +} + +impl KObject for VirtIOConsoleDevice { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn name(&self) -> String { + self.device_name() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&self) -> RwLockReadGuard { + self.locked_kobj_state.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.locked_kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.locked_kobj_state.write() = state; + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } +} + +impl Device for VirtIOConsoleDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Char + } + + fn id_table(&self) -> IdTable { + IdTable::new(VIRTIO_CONSOLE_BASENAME.to_string(), None) + } + + fn bus(&self) -> Option> { + self.inner().device_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().device_common.bus = bus; + } + + fn class(&self) -> Option> { + let mut guard = self.inner(); + let r = guard.device_common.class.clone()?.upgrade(); + if r.is_none() { + guard.device_common.class = None; + } + + return r; + } + + fn set_class(&self, class: Option>) { + self.inner().device_common.class = class; + } + + fn driver(&self) -> Option> { + let r = self.inner().device_common.driver.clone()?.upgrade(); + if r.is_none() { + self.inner().device_common.driver = None; + } + + return r; + } + + fn set_driver(&self, driver: Option>) { + self.inner().device_common.driver = driver; + } + + fn is_dead(&self) -> bool { + false + } + + fn can_match(&self) -> bool { + self.inner().device_common.can_match + } + + fn set_can_match(&self, can_match: bool) { + self.inner().device_common.can_match = can_match; + } + + fn state_synced(&self) -> bool { + true + } + + fn dev_parent(&self) -> Option> { + self.inner().device_common.get_parent_weak_or_clear() + } + + fn set_dev_parent(&self, parent: Option>) { + self.inner().device_common.parent = parent; + } +} + +impl VirtIODevice for VirtIOConsoleDevice { + fn handle_irq(&self, _irq: IrqNumber) -> Result { + let mut buf = [0u8; 8]; + let mut index = 0; + // Read up to the size of the buffer + while index < buf.len() { + if let Ok(Some(c)) = self.inner().device_inner.recv(true) { + buf[index] = c; + index += 1; + } else { + break; // No more bytes to read + } + } + + send_to_tty_refresh_thread(&buf[0..index]); + Ok(IrqReturn::Handled) + } + + fn dev_id(&self) -> &Arc { + &self.dev_id + } + + fn set_device_name(&self, name: String) { + self.inner().name = Some(name); + } + + fn device_name(&self) -> String { + self.inner() + .name + .clone() + .unwrap_or_else(|| VIRTIO_CONSOLE_BASENAME.to_string()) + } + + fn set_virtio_device_index(&self, index: VirtIODeviceIndex) { + self.inner().virtio_index = Some(index); + } + + fn virtio_device_index(&self) -> Option { + self.inner().virtio_index + } + + fn device_type_id(&self) -> u32 { + virtio_drivers::transport::DeviceType::Console as u32 + } + + fn vendor(&self) -> u32 { + VIRTIO_VENDOR_ID.into() + } + + fn irq(&self) -> Option { + self.inner().irq + } +} + +#[derive(Debug)] +#[cast_to([sync] VirtIODriver)] +#[cast_to([sync] Driver)] +struct VirtIOConsoleDriver { + inner: SpinLock, + devices: RwLock<[Option>; Self::MAX_DEVICES]>, + kobj_state: LockedKObjectState, +} + +impl VirtIOConsoleDriver { + const MAX_DEVICES: usize = 32; + + pub fn new() -> Arc { + let inner = InnerVirtIOConsoleDriver { + virtio_driver_common: VirtIODriverCommonData::default(), + driver_common: DriverCommonData::default(), + kobj_common: KObjectCommonData::default(), + id_bmp: bitmap::StaticBitmap::new(), + devname: [const { None }; Self::MAX_DEVICES], + }; + + let id_table = VirtioDeviceId::new( + virtio_drivers::transport::DeviceType::Console as u32, + VIRTIO_VENDOR_ID.into(), + ); + + let result = VirtIOConsoleDriver { + inner: SpinLock::new(inner), + kobj_state: LockedKObjectState::default(), + devices: RwLock::new([const { None }; Self::MAX_DEVICES]), + }; + + result.add_virtio_id(id_table); + Arc::new(result) + } + + fn inner(&self) -> SpinLockGuard { + self.inner.lock() + } + + fn do_install( + &self, + driver: Arc, + tty: Arc, + vc: Arc, + ) -> Result<(), SystemError> { + driver.standard_install(tty.clone())?; + vc.port().setup_internal_tty(Arc::downgrade(&tty)); + tty.set_port(vc.port()); + vc.devfs_setup()?; + + Ok(()) + } +} + +#[derive(Debug)] +struct InnerVirtIOConsoleDriver { + id_bmp: bitmap::StaticBitmap<{ VirtIOConsoleDriver::MAX_DEVICES }>, + devname: [Option; VirtIOConsoleDriver::MAX_DEVICES], + virtio_driver_common: VirtIODriverCommonData, + driver_common: DriverCommonData, + kobj_common: KObjectCommonData, +} + +impl InnerVirtIOConsoleDriver { + fn alloc_id(&mut self) -> Option { + let idx = self.id_bmp.first_false_index()?; + self.id_bmp.set(idx, true); + let name = Self::format_name(idx); + self.devname[idx] = Some(name.clone()); + Some(name) + } + + fn format_name(id: usize) -> DevName { + DevName::new(format!("vport{}", id), id) + } + + fn free_id(&mut self, id: usize) { + if id >= VirtIOConsoleDriver::MAX_DEVICES { + return; + } + self.id_bmp.set(id, false); + self.devname[id] = None; + } +} + +impl TtyOperation for VirtIOConsoleDriver { + fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { + Ok(()) + } + + fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result { + if nr > buf.len() { + return Err(SystemError::EINVAL); + } + let index = tty.index(); + if index >= VirtIOConsoleDriver::MAX_DEVICES { + return Err(SystemError::ENODEV); + } + + let dev = self.devices.read()[index] + .clone() + .ok_or(SystemError::ENODEV)?; + let mut cnt = 0; + let mut inner = dev.inner(); + for c in buf[0..nr].iter() { + if let Err(e) = inner.device_inner.send(*c) { + if cnt > 0 { + return Ok(cnt); + } + return Err(virtio_drivers_error_to_system_error(e)); + } else { + cnt += 1; + } + } + + Ok(cnt) + } + + fn flush_chars(&self, _tty: &TtyCoreData) { + // do nothing + } + + fn ioctl(&self, _tty: Arc, _cmd: u32, _arg: usize) -> Result<(), SystemError> { + Err(SystemError::ENOIOCTLCMD) + } + + fn close(&self, _tty: Arc) -> Result<(), SystemError> { + Ok(()) + } + + fn resize(&self, tty: Arc, winsize: WindowSize) -> Result<(), SystemError> { + *tty.core().window_size_write() = winsize; + Ok(()) + } + + fn install(&self, driver: Arc, tty: Arc) -> Result<(), SystemError> { + if tty.core().index() >= VirtIOConsoleDriver::MAX_DEVICES { + return Err(SystemError::ENODEV); + } + + let dev = self.devices.read()[tty.core().index()] + .clone() + .ok_or(SystemError::ENODEV)?; + let info = dev.inner().device_inner.info(); + let winsize = WindowSize::new(info.rows, info.columns, 1, 1); + + *tty.core().window_size_write() = winsize; + let vc_data = Arc::new(SpinLock::new(VirtualConsoleData::new(usize::MAX))); + let mut vc_data_guard = vc_data.lock_irqsave(); + vc_data_guard.set_driver_funcs(Arc::downgrade(&dummy_console()) as Weak); + vc_data_guard.init( + Some(tty.core().window_size().row.into()), + Some(tty.core().window_size().col.into()), + true, + ); + drop(vc_data_guard); + + let vc = VirtConsole::new(Some(vc_data)); + let vc_index = vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?; + self.do_install(driver, tty, vc.clone()).inspect_err(|_| { + vc_manager().free(vc_index); + })?; + + Ok(()) + } +} + +impl VirtIODriver for VirtIOConsoleDriver { + fn probe(&self, device: &Arc) -> Result<(), SystemError> { + log::debug!("VirtIOConsoleDriver::probe()"); + let _dev = device + .clone() + .arc_any() + .downcast::() + .map_err(|_| { + log::error!( + "VirtIOConsoleDriver::probe() failed: device is not a VirtIO console device. Device: '{:?}'", + device.name() + ); + SystemError::EINVAL + })?; + log::debug!("VirtIOConsoleDriver::probe() succeeded"); + Ok(()) + } + + fn virtio_id_table(&self) -> Vec { + self.inner().virtio_driver_common.id_table.clone() + } + + fn add_virtio_id(&self, id: VirtioDeviceId) { + self.inner().virtio_driver_common.id_table.push(id); + } +} + +impl Driver for VirtIOConsoleDriver { + fn id_table(&self) -> Option { + Some(IdTable::new(VIRTIO_CONSOLE_BASENAME.to_string(), None)) + } + + // todo: 添加错误时,资源释放的逻辑 + fn add_device(&self, device: Arc) { + log::debug!("virtio console: add_device"); + let virtio_con_dev = device.arc_any().downcast::().expect( + "VirtIOConsoleDriver::add_device() failed: device is not a VirtIOConsoleDevice", + ); + if virtio_con_dev.dev_name.initialized() { + panic!("VirtIOConsoleDriver::add_device() failed: dev_name has already initialized for device: '{:?}'", + virtio_con_dev.dev_id(), + ); + } + let mut inner = self.inner(); + let dev_name = inner.alloc_id(); + if dev_name.is_none() { + panic!("Failed to allocate ID for VirtIO console device: '{:?}', virtio console device limit exceeded.", virtio_con_dev.dev_id()) + } + + let dev_name = dev_name.unwrap(); + + virtio_con_dev.dev_name.init(dev_name); + + inner + .driver_common + .devices + .push(virtio_con_dev.clone() as Arc); + + // avoid deadlock in `init_tty_device` + drop(inner); + + let mut devices_fast_guard = self.devices.write(); + let index = virtio_con_dev.dev_name.get().id(); + if devices_fast_guard[index].is_none() { + devices_fast_guard[index] = Some(virtio_con_dev.clone()); + } else { + panic!("VirtIOConsoleDriver::add_device() failed: device slot already occupied at index: {}", index); + } + // avoid deadlock in `init_tty_device` + drop(devices_fast_guard); + + log::debug!("virtio console: add_device: to init tty device"); + let r = tty_hvc_driver().init_tty_device(Some(index)); + log::debug!( + "virtio console: add_device: init tty device done, index: {}, dev_name: {:?}", + index, + virtio_con_dev.dev_name.get(), + ); + if let Err(e) = r { + log::error!( + "Failed to init tty device for virtio console device, index: {}, dev_name: {:?}, err: {:?}", + index, + virtio_con_dev.dev_name.get(), + e, + ); + return; + } + } + + fn delete_device(&self, device: &Arc) { + let virtio_con_dev = device + .clone() + .arc_any() + .downcast::() + .expect( + "VirtIOConsoleDriver::delete_device() failed: device is not a VirtIOConsoleDevice", + ); + + let mut guard = self.inner(); + let mut devices_fast_guard = self.devices.write(); + let index = guard + .driver_common + .devices + .iter() + .position(|dev| Arc::ptr_eq(device, dev)) + .expect("VirtIOConsoleDriver::delete_device() failed: device not found"); + + guard.driver_common.devices.remove(index); + guard.free_id(virtio_con_dev.dev_name.get().id()); + + devices_fast_guard[index] = None; + } + + fn devices(&self) -> Vec> { + self.inner().driver_common.devices.clone() + } + + fn bus(&self) -> Option> { + Some(Arc::downgrade(&virtio_bus()) as Weak) + } + + fn set_bus(&self, _bus: Option>) { + // do nothing + } +} + +impl KObject for VirtIOConsoleDriver { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobj_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobj_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobj_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobj_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobj_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobj_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobj_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobj_common.kobj_type = ktype; + } + + fn name(&self) -> String { + VIRTIO_CONSOLE_BASENAME.to_string() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&self) -> RwLockReadGuard { + self.kobj_state.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.kobj_state.write() = state; + } +} + +#[unified_init(INITCALL_POSTCORE)] +fn virtio_console_driver_init() -> Result<(), SystemError> { + let driver = VirtIOConsoleDriver::new(); + virtio_driver_manager() + .register(driver.clone() as Arc) + .expect("Add virtio console driver failed"); + unsafe { + VIRTIO_CONSOLE_DRIVER = Some(driver.clone()); + } + let hvc_tty_driver = TtyDriver::new( + VirtIOConsoleDriver::MAX_DEVICES.try_into().unwrap(), + "hvc", + 0, + Major::HVC_MAJOR, + HVC_MINOR, + TtyDriverType::System, + *TTY_STD_TERMIOS, + driver.clone(), + None, + ); + + let hvc_tty_driver = TtyDriverManager::tty_register_driver(hvc_tty_driver)?; + compiler_fence(Ordering::SeqCst); + unsafe { + TTY_HVC_DRIVER = Some(hvc_tty_driver); + } + + compiler_fence(Ordering::SeqCst); + + return Ok(()); +} diff --git a/kernel/src/driver/disk/ahci/ahcidisk.rs b/kernel/src/driver/disk/ahci/ahcidisk.rs index 76bc05b3..b3c16ad9 100644 --- a/kernel/src/driver/disk/ahci/ahcidisk.rs +++ b/kernel/src/driver/disk/ahci/ahcidisk.rs @@ -1,15 +1,13 @@ use super::{_port, hba::HbaCmdTable}; use crate::arch::MMArch; -use crate::driver::base::block::block_device::{ - BlockDevName, BlockDevice, BlockId, GeneralBlockRange, -}; +use crate::driver::base::block::block_device::{BlockDevice, BlockId, GeneralBlockRange}; use crate::driver::base::block::disk_info::Partition; use crate::driver::base::block::manager::BlockDevMeta; use crate::driver::base::class::Class; use crate::driver::base::device::bus::Bus; use crate::driver::base::device::driver::Driver; -use crate::driver::base::device::{Device, DeviceType, IdTable}; +use crate::driver::base::device::{DevName, Device, DeviceType, IdTable}; use crate::driver::base::kobject::{KObjType, KObject, KObjectState}; use crate::driver::base::kset::KSet; use crate::driver::disk::ahci::HBA_PxIS_TFES; @@ -520,7 +518,7 @@ impl Device for LockedAhciDisk { } impl BlockDevice for LockedAhciDisk { - fn dev_name(&self) -> &BlockDevName { + fn dev_name(&self) -> &DevName { &self.blkdev_meta.devname } diff --git a/kernel/src/driver/disk/ahci/mod.rs b/kernel/src/driver/disk/ahci/mod.rs index 8af50581..2e610407 100644 --- a/kernel/src/driver/disk/ahci/mod.rs +++ b/kernel/src/driver/disk/ahci/mod.rs @@ -55,8 +55,11 @@ pub fn ahci_init() -> Result<(), SystemError> { let standard_device = device.as_standard_device().unwrap(); standard_device.bar_ioremap(); // 对于每一个ahci控制器分配一块空间 - let ahci_port_base_vaddr = - Box::leak(Box::new([0u8; (1 << 20) as usize])) as *mut u8 as usize; + // let ahci_port_base_vaddr = + // Box::leak(Box::new([0u8; (1 << 20) as usize])) as *mut u8 as usize; + let buffer = Box::leak(vec![0u8; (1 << 20) as usize].into_boxed_slice()); + let ahci_port_base_vaddr = buffer.as_mut_ptr() as usize; + let virtaddr = standard_device .bar() .ok_or(SystemError::EACCES)? diff --git a/kernel/src/driver/disk/ata.h b/kernel/src/driver/disk/ata.h deleted file mode 100644 index 7fb099b4..00000000 --- a/kernel/src/driver/disk/ata.h +++ /dev/null @@ -1,345 +0,0 @@ -#pragma once - -#include - -// ======== PIO端口定义 ======== -#define PORT_DISK0_DATA 0x1f0 // 数据 -#define PORT_DISK0_ERR_STATUS 0x1f1 // 错误状态 -#define PORT_DISK0_SECTOR_CNT 0x1f2 // 操作扇区数 -#define PORT_DISK0_LBA_7_0 0x1f3 // 扇区号 / LBA[7:0] -#define PORT_DISK0_LBA_15_8 0x1f4 // 柱面号[7:0] / LBA[15:8] -#define PORT_DISK0_LBA_23_16 0x1f5 // 柱面号[15:8] / LBA[23:16] -#define PORT_DISK0_DEVICE_CONFIGURE_REG 0x1f6 // 设备配置寄存器 -#define PORT_DISK0_CONTROLLER_STATUS_CMD 0x1f7 // 控制器状态端口 / 控制器命令端口 -#define PORT_DISK0_STATUS_CTRL_REG 0x3f6 // 状态寄存器 / 控制寄存器 - -#define PORT_DISK1_DATA 0x170 // 数据 -#define PORT_DISK1_ERR_STATUS 0x171 // 错误状态 -#define PORT_DISK1_SECTOR_CNT 0x172 // 操作扇区数 -#define PORT_DISK1_LBA_7_0 0x173 // 扇区号 / LBA[7:0] -#define PORT_DISK1_LBA_15_8 0x174 // 柱面号[7:0] / LBA[15:8] -#define PORT_DISK1_LBA_23_16 0x175 // 柱面号[15:8] / LBA[23:16] -#define PORT_DISK1_DEVICE_CONFIGURE_REG 0x176 // 设备配置寄存器 -#define PORT_DISK1_CONTROLLER_STATUS_CMD 0x177 // 控制器状态端口 / 控制器命令端口 -#define PORT_DISK1_STATUS_CTRL_REG 0x376 // 状态寄存器 / 控制寄存器 - -// ======= 状态寄存器的状态位 ========== -#define DISK_STATUS_BUSY (1 << 7) // 控制器忙 -#define DISK_STATUS_READY (1 << 6) // 驱动器准备就绪 -#define DISK_STATUS_SEEK (1 << 4) // 驱动器寻道 -#define DISK_STATUS_DATA_REQ (1 << 3) // 数据请求 -#define DISK_STATUS_DATA_ERROR (1 << 0) // 命令执行错误 - -/** - * @brief 执行0xec指令返回的512bytes的硬件设备识别信息 - * 位于ATA8-ACS中 Table-22 - */ -struct ata_identify_device_data -{ - // 0 General configuration bit-significant information - unsigned short General_Config; - - // 1 Obsolete - unsigned short Obsolete0; - - // 2 Specific configuration - unsigned short Specific_Coinfig; - - // 3 Obsolete - unsigned short Obsolete1; - - // 4-5 Retired - unsigned short Retired0[2]; - - // 6 Obsolete - unsigned short Obsolete2; - - // 7-8 Reserved for the CompactFlash Association - unsigned short CompactFlash[2]; - - // 9 Retired - unsigned short Retired1; - - // 10-19 Serial number (20 ASCII characters) - unsigned short Serial_Number[10]; - - // 20-21 Retired - unsigned short Retired2[2]; - - // 22 Obsolete - unsigned short Obsolete3; - - // 23-26 Firmware revision(8 ASCII characters) - unsigned short Firmware_Version[4]; - - // 27-46 Model number (40 ASCII characters) - unsigned short Model_Number[20]; - - // 47 15:8 80h - // 7:0 00h=Reserved - // 01h-FFh = Maximumnumber of logical sectors that shall be transferred per DRQ data block on READ/WRITE MULTIPLE commands - unsigned short Max_logical_transferred_per_DRQ; - - // 48 Trusted Computing feature set options - unsigned short Trusted_Computing_feature_set_options; - - // 49 Capabilities - unsigned short Capabilities0; - - // 50 Capabilities - unsigned short Capabilities1; - - // 51-52 Obsolete - unsigned short Obsolete4[2]; - - // 53 15:8 Free-fall Control Sensitivity - // 7:3 Reserved - // 2 the fields reported in word 88 are valid - // 1 the fields reported in words (70:64) are valid - unsigned short Report_88_70to64_valid; - - // 54-58 Obsolete - unsigned short Obsolete5[5]; - - // 59 15:9 Reserved - // 8 Multiple sector setting is valid - // 7:0 xxh current setting for number of logical sectors that shall be transferred per DRQ data block on READ/WRITE Multiple commands - unsigned short Mul_Sec_Setting_Valid; - - // 60-61 Total number of user addresssable logical sectors for 28bit CMD - unsigned short Addressable_Logical_Sectors_for_28[2]; - - // 62 Obsolete - unsigned short Obsolete6; - - // 63 15:11 Reserved - // 10:8=1 Multiword DMA mode 210 is selected - // 7:3 Reserved - // 2:0=1 Multiword DMA mode 210 and below are supported - unsigned short MultWord_DMA_Select; - - // 64 15:8 Reserved - // 7:0 PIO mdoes supported - unsigned short PIO_mode_supported; - - // 65 Minimum Multiword DMA transfer cycle time per word - unsigned short Min_MulWord_DMA_cycle_time_per_word; - - // 66 Manufacturer`s recommended Multiword DMA transfer cycle time - unsigned short Manufacture_Recommend_MulWord_DMA_cycle_time; - - // 67 Minimum PIO transfer cycle time without flow control - unsigned short Min_PIO_cycle_time_Flow_Control; - - // 68 Minimum PIO transfer cycle time with IORDY flow control - unsigned short Min_PIO_cycle_time_IOREDY_Flow_Control; - - // 69-70 Reserved - unsigned short Reserved1[2]; - - // 71-74 Reserved for the IDENTIFY PACKET DEVICE command - unsigned short Reserved2[4]; - - // 75 Queue depth - unsigned short Queue_depth; - - // 76 Serial ATA Capabilities - unsigned short SATA_Capabilities; - - // 77 Reserved for Serial ATA - unsigned short Reserved3; - - // 78 Serial ATA features Supported - unsigned short SATA_features_Supported; - - // 79 Serial ATA features enabled - unsigned short SATA_features_enabled; - - // 80 Major Version number - unsigned short Major_Version; - - // 81 Minor version number - unsigned short Minor_Version; - - // 82 Commands and feature sets supported - unsigned short Cmd_feature_sets_supported0; - - // 83 Commands and feature sets supported - unsigned short Cmd_feature_sets_supported1; - - // 84 Commands and feature sets supported - unsigned short Cmd_feature_sets_supported2; - - // 85 Commands and feature sets supported or enabled - unsigned short Cmd_feature_sets_supported3; - - // 86 Commands and feature sets supported or enabled - unsigned short Cmd_feature_sets_supported4; - - // 87 Commands and feature sets supported or enabled - unsigned short Cmd_feature_sets_supported5; - - // 88 15 Reserved - // 14:8=1 Ultra DMA mode 6543210 is selected - // 7 Reserved - // 6:0=1 Ultra DMA mode 6543210 and below are suported - unsigned short Ultra_DMA_modes; - - // 89 Time required for Normal Erase mode SECURITY ERASE UNIT command - unsigned short Time_required_Erase_CMD; - - // 90 Time required for an Enhanced Erase mode SECURITY ERASE UNIT command - unsigned short Time_required_Enhanced_CMD; - - // 91 Current APM level value - unsigned short Current_APM_level_Value; - - // 92 Master Password Identifier - unsigned short Master_Password_Identifier; - - // 93 Hardware resset result.The contents of bits (12:0) of this word shall change only during the execution of a hardware reset. - unsigned short HardWare_Reset_Result; - - // 94 Current AAM value - // 15:8 Vendor’s recommended AAM value - // 7:0 Current AAM value - unsigned short Current_AAM_value; - - // 95 Stream Minimum Request Size - unsigned short Stream_Min_Request_Size; - - // 96 Streaming Transger Time-DMA - unsigned short Streaming_Transger_time_DMA; - - // 97 Streaming Access Latency-DMA and PIO - unsigned short Streaming_Access_Latency_DMA_PIO; - - // 98-99 Streaming Performance Granularity (DWord) - unsigned short Streaming_Performance_Granularity[2]; - - // 100-103 Total Number of User Addressable Logical Sectors for 48-bit commands (QWord) - unsigned short Total_user_LBA_for_48_Address_Feature_set[4]; - - // 104 Streaming Transger Time-PIO - unsigned short Streaming_Transfer_Time_PIO; - - // 105 Reserved - unsigned short Reserved4; - - // 106 Physical Sector size/Logical Sector Size - unsigned short Physical_Logical_Sector_Size; - - // 107 Inter-seek delay for ISO-7779 acoustic testing in microseconds - unsigned short Inter_seek_delay; - - // 108-111 World wide name - unsigned short World_wide_name[4]; - - // 112-115 Reserved - unsigned short Reserved5[4]; - - // 116 Reserved for TLC - unsigned short Reserved6; - - // 117-118 Logical sector size (DWord) - unsigned short Words_per_Logical_Sector[2]; - - // 119 Commands and feature sets supported (Continued from words 84:82) - unsigned short CMD_feature_Supported; - - // 120 Commands and feature sets supported or enabled (Continued from words 87:85) - unsigned short CMD_feature_Supported_enabled; - - // 121-126 Reserved for expanded supported and enabled settings - unsigned short Reserved7[6]; - - // 127 Obsolete - unsigned short Obsolete7; - - // 128 Security status - unsigned short Security_Status; - - // 129-159 Vendor specific - unsigned short Vendor_Specific[31]; - - // 160 CFA power mode - unsigned short CFA_Power_mode; - - // 161-167 Reserved for the CompactFlash Association - unsigned short Reserved8[7]; - - // 168 Device Nominal Form Factor - unsigned short Dev_from_Factor; - - // 169-175 Reserved - unsigned short Reserved9[7]; - - // 176-205 Current media serial number (ATA string) - unsigned short Current_Media_Serial_Number[30]; - - // 206 SCT Command Transport - unsigned short SCT_Cmd_Transport; - - // 207-208 Reserved for CE-ATA - unsigned short Reserved10[2]; - - // 209 Alignment of logical blocks within a physical block - unsigned short Alignment_Logical_blocks_within_a_physical_block; - - // 210-211 Write-Read-Verify Sector Count Mode 3 (DWord) - unsigned short Write_Read_Verify_Sector_Count_Mode_3[2]; - - // 212-213 Write-Read-Verify Sector Count Mode 2 (DWord) - unsigned short Write_Read_Verify_Sector_Count_Mode_2[2]; - - // 214 NV Cache Capabilities - unsigned short NV_Cache_Capabilities; - - // 215-216 NV Cache Size in Logical Blocks (DWord) - unsigned short NV_Cache_Size[2]; - - // 217 Nominal media rotation rate - unsigned short Nominal_media_rotation_rate; - - // 218 Reserved - unsigned short Reserved11; - - // 219 NV Cache Options - unsigned short NV_Cache_Options; - - // 220 Write-Read-Verify feature set current mode - unsigned short Write_Read_Verify_feature_set_current_mode; - - // 221 Reserved - unsigned short Reserved12; - - // 222 Transport major version number. - // 0000h or ffffh = device does not report version - unsigned short Transport_Major_Version_Number; - - // 223 Transport Minor version number - unsigned short Transport_Minor_Version_Number; - - // 224-233 Reserved for CE-ATA - unsigned short Reserved13[10]; - - // 234 Minimum number of 512-byte data blocks per DOWNLOAD MICROCODE command for mode 03h - unsigned short Mini_blocks_per_CMD; - - // 235 Maximum number of 512-byte data blocks per DOWNLOAD MICROCODE command for mode 03h - unsigned short Max_blocks_per_CMD; - - // 236-254 Reserved - unsigned short Reserved14[19]; - - // 255 Integrity word - // 15:8 Checksum - // 7:0 Checksum Validity Indicator - unsigned short Integrity_word; -} __attribute__((packed)); - -/** - * @brief 初始化ATA磁盘驱动程序 - * - */ -void ata_init(); \ No newline at end of file diff --git a/kernel/src/driver/input/ps2_mouse/ps_mouse_device.rs b/kernel/src/driver/input/ps2_mouse/ps_mouse_device.rs index 78633ea9..1790e70b 100644 --- a/kernel/src/driver/input/ps2_mouse/ps_mouse_device.rs +++ b/kernel/src/driver/input/ps2_mouse/ps_mouse_device.rs @@ -31,7 +31,7 @@ use crate::{ devfs::{devfs_register, DevFS, DeviceINode}, kernfs::KernFSInode, vfs::{ - core::generate_inode_id, syscall::ModeType, utils::DName, FilePrivateData, FileSystem, + syscall::ModeType, utils::DName, vcore::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, }, }, @@ -198,6 +198,7 @@ impl Ps2MouseDevice { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::CharDevice, // 文件夹,block设备,char设备 mode: ModeType::from_bits_truncate(0o644), nlinks: 1, diff --git a/kernel/src/driver/irqchip/riscv_sifive_plic.rs b/kernel/src/driver/irqchip/riscv_sifive_plic.rs index 05bc52f0..c8639f03 100644 --- a/kernel/src/driver/irqchip/riscv_sifive_plic.rs +++ b/kernel/src/driver/irqchip/riscv_sifive_plic.rs @@ -649,7 +649,7 @@ pub(super) fn do_plic_irq(trap_frame: &mut TrapFrame) { if claim == 0 { break; } - debug!("plic: claim: {claim:?}"); + // debug!("plic: claim: {claim:?}"); let hwirq = HardwareIrqNumber::new(claim); if let Err(e) = GenericIrqHandler::handle_domain_irq(domain.clone(), hwirq, trap_frame) { diff --git a/kernel/src/driver/keyboard/ps2_keyboard.rs b/kernel/src/driver/keyboard/ps2_keyboard.rs index 94564e9f..35a65a65 100644 --- a/kernel/src/driver/keyboard/ps2_keyboard.rs +++ b/kernel/src/driver/keyboard/ps2_keyboard.rs @@ -22,7 +22,7 @@ use crate::{ filesystem::{ devfs::{devfs_register, DevFS, DeviceINode}, vfs::{ - core::generate_inode_id, file::FileMode, syscall::ModeType, FilePrivateData, + file::FileMode, syscall::ModeType, vcore::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, }, }, @@ -86,6 +86,7 @@ impl LockedPS2KeyBoardInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::CharDevice, // 文件夹,block设备,char设备 mode: ModeType::from_bits_truncate(0o666), nlinks: 1, @@ -155,6 +156,7 @@ impl IndexNode for LockedPS2KeyBoardInode { inode.metadata.atime = metadata.atime; inode.metadata.mtime = metadata.mtime; inode.metadata.ctime = metadata.ctime; + inode.metadata.btime = metadata.btime; inode.metadata.mode = metadata.mode; inode.metadata.uid = metadata.uid; inode.metadata.gid = metadata.gid; diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index 3b723b78..8fae3da2 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -1,6 +1,7 @@ pub mod acpi; pub mod base; pub mod block; +pub mod char; pub mod clocksource; pub mod disk; pub mod firmware; diff --git a/kernel/src/driver/net/e1000e/e1000e.rs b/kernel/src/driver/net/e1000e/e1000e.rs index 0383c8ac..cb08a611 100644 --- a/kernel/src/driver/net/e1000e/e1000e.rs +++ b/kernel/src/driver/net/e1000e/e1000e.rs @@ -587,11 +587,13 @@ impl Drop for E1000EDevice { pub fn e1000e_init() { match e1000e_probe() { - Ok(_code) => { - info!("Successfully init e1000e device!"); + Ok(code) => { + if code == 1 { + info!("Successfully init e1000e device!"); + } } - Err(_error) => { - info!("Error occurred!"); + Err(error) => { + info!("Failed to init e1000e device: {error:?}"); } } } @@ -602,6 +604,7 @@ pub fn e1000e_probe() -> Result { if result.is_empty() { return Ok(0); } + let mut initialized = false; for device in result { let standard_device = device.as_standard_device().unwrap(); if standard_device.common_header.vendor_id == 0x8086 { @@ -625,11 +628,16 @@ pub fn e1000e_probe() -> Result { .unwrap(), )?; e1000e_driver_init(e1000e); + initialized = true; } } } - return Ok(1); + if initialized { + Ok(1) + } else { + Ok(0) + } } // 用到的e1000e寄存器结构体 @@ -787,6 +795,7 @@ const E1000E_TXD_CMD_RS: u8 = 1 << 3; /// E1000E驱动初始化过程中可能的错误 #[allow(dead_code)] +#[derive(Debug)] pub enum E1000EPciError { // 获取到错误类型的BAR(IO BAR) // An IO BAR was provided rather than a memory BAR. diff --git a/kernel/src/driver/net/virtio_net.rs b/kernel/src/driver/net/virtio_net.rs index 307a3a05..2500a1e1 100644 --- a/kernel/src/driver/net/virtio_net.rs +++ b/kernel/src/driver/net/virtio_net.rs @@ -1,12 +1,11 @@ use core::{ any::Any, cell::UnsafeCell, - fmt::Debug, + fmt::{Debug, Formatter}, ops::{Deref, DerefMut}, }; use alloc::{ - collections::LinkedList, string::{String, ToString}, sync::{Arc, Weak}, vec::Vec, @@ -63,7 +62,6 @@ fn virtio_net_driver() -> Arc { } /// virtio net device -#[derive(Debug)] #[cast_to([sync] VirtIODevice)] #[cast_to([sync] Device)] pub struct VirtIONetDevice { @@ -72,6 +70,14 @@ pub struct VirtIONetDevice { locked_kobj_state: LockedKObjectState, } +impl Debug for VirtIONetDevice { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("VirtIONetDevice") + .field("dev_id", &self.dev_id.id()) + .finish() + } +} + unsafe impl Send for VirtIONetDevice {} unsafe impl Sync for VirtIONetDevice {} @@ -85,7 +91,7 @@ struct InnerVirtIONetDevice { impl Debug for InnerVirtIONetDevice { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("InnerVirtIOBlkDevice").finish() + f.debug_struct("InnerVirtIONetDevice").finish() } } @@ -108,7 +114,7 @@ impl VirtIONetDevice { let mac = wire::EthernetAddress::from_bytes(&driver_net.mac_address()); debug!("VirtIONetDevice mac: {:?}", mac); let device_inner = VirtIONicDeviceInner::new(driver_net); - + device_inner.inner.lock_irqsave().enable_interrupts(); let dev = Arc::new(Self { dev_id, inner: SpinLock::new(InnerVirtIONetDevice { @@ -824,12 +830,12 @@ impl VirtIODriver for VirtIONetDriver { return Ok(()); } - fn virtio_id_table(&self) -> LinkedList { + fn virtio_id_table(&self) -> Vec { self.inner().virtio_driver_common.id_table.clone() } fn add_virtio_id(&self, id: VirtioDeviceId) { - self.inner().virtio_driver_common.id_table.push_back(id); + self.inner().virtio_driver_common.id_table.push(id); } } diff --git a/kernel/src/driver/pci/pci.rs b/kernel/src/driver/pci/pci.rs index 82bb20c9..8be45ee9 100644 --- a/kernel/src/driver/pci/pci.rs +++ b/kernel/src/driver/pci/pci.rs @@ -1063,7 +1063,12 @@ pub fn pci_init() { let common_header = box_pci_device.common_header(); match box_pci_device.header_type() { HeaderType::Standard if common_header.status & 0x10 != 0 => { - info!("Found pci standard device with class code ={} subclass={} status={:#x} cap_pointer={:#x} vendor={:#x}, device id={:#x},bdf={}", common_header.class_code, common_header.subclass, common_header.status, box_pci_device.as_standard_device().unwrap().capabilities_pointer,common_header.vendor_id, common_header.device_id,common_header.bus_device_function); + info!( + "Found pci standard device with class code ={} subclass={}, bdf={}", + common_header.class_code, + common_header.subclass, + common_header.bus_device_function + ); } HeaderType::Standard => { info!( diff --git a/kernel/src/driver/scsi/mod.rs b/kernel/src/driver/scsi/mod.rs index 21a42cc8..3a01f1ff 100644 --- a/kernel/src/driver/scsi/mod.rs +++ b/kernel/src/driver/scsi/mod.rs @@ -7,7 +7,7 @@ use crate::{ libs::spinlock::{SpinLock, SpinLockGuard}, }; -use super::base::block::block_device::BlockDevName; +use super::base::device::DevName; static mut SCSI_MANAGER: Option = None; @@ -30,7 +30,7 @@ pub struct ScsiManager { struct InnerScsiManager { id_bmp: bitmap::StaticBitmap<{ ScsiManager::MAX_DEVICES }>, - devname: [Option; ScsiManager::MAX_DEVICES], + devname: [Option; ScsiManager::MAX_DEVICES], } impl ScsiManager { @@ -49,7 +49,7 @@ impl ScsiManager { self.inner.lock() } - pub fn alloc_id(&self) -> Option { + pub fn alloc_id(&self) -> Option { let mut inner = self.inner(); let idx = inner.id_bmp.first_false_index()?; inner.id_bmp.set(idx, true); @@ -59,9 +59,9 @@ impl ScsiManager { } /// Generate a new block device name like 'sda', 'sdb', etc. - fn format_name(id: usize) -> BlockDevName { + fn format_name(id: usize) -> DevName { let x = (b'a' + id as u8) as char; - BlockDevName::new(format!("sd{}", x), id) + DevName::new(format!("sd{}", x), id) } #[allow(dead_code)] diff --git a/kernel/src/driver/serial/serial8250/mod.rs b/kernel/src/driver/serial/serial8250/mod.rs index 257b4bc3..4fc220dd 100644 --- a/kernel/src/driver/serial/serial8250/mod.rs +++ b/kernel/src/driver/serial/serial8250/mod.rs @@ -43,6 +43,9 @@ use super::{uart_manager, UartDriver, UartManager, UartPort, TTY_SERIAL_DEFAULT_ #[cfg(target_arch = "x86_64")] mod serial8250_pio; +#[cfg(target_arch = "loongarch64")] +mod serial8250_la64; + static mut SERIAL8250_ISA_DEVICES: Option> = None; static mut SERIAL8250_ISA_DRIVER: Option> = None; @@ -75,8 +78,11 @@ impl Serial8250Manager { /// 初始化串口设备(在内存管理初始化之前) pub fn early_init(&self) -> Result<(), SystemError> { // todo: riscv64: 串口设备初始化 - #[cfg(not(target_arch = "riscv64"))] + #[cfg(target_arch = "x86_64")] serial8250_pio_port_early_init()?; + + #[cfg(target_arch = "loongarch64")] + serial8250_la64::early_la64_seria8250_init()?; return Ok(()); } @@ -127,7 +133,7 @@ impl Serial8250Manager { return Ok(()); } - #[cfg(target_arch = "riscv64")] + #[cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))] fn serial_tty_init(&self) -> Result<(), SystemError> { Ok(()) } @@ -564,4 +570,9 @@ pub fn send_to_default_serial8250_port(s: &[u8]) { { crate::arch::driver::sbi::console_putstr(s); } + + #[cfg(target_arch = "loongarch64")] + { + serial8250_la64::send_to_default_serial8250_la64_port(s); + } } diff --git a/kernel/src/driver/serial/serial8250/serial8250_la64.rs b/kernel/src/driver/serial/serial8250/serial8250_la64.rs new file mode 100644 index 00000000..ee11674d --- /dev/null +++ b/kernel/src/driver/serial/serial8250/serial8250_la64.rs @@ -0,0 +1,69 @@ +use system_error::SystemError; + +use crate::{ + arch::MMArch, + libs::spinlock::SpinLock, + mm::{MemoryManagementArch, PhysAddr, VirtAddr}, +}; + +const UART_PADDR_COM1: PhysAddr = PhysAddr::new(0x01FE001E0); + +static mut UART_PORT_COM1: Option> = None; + +struct Serial8250LA64Port { + base_address: VirtAddr, +} + +impl Serial8250LA64Port { + pub fn new(base_address: PhysAddr) -> Self { + Self { + base_address: unsafe { MMArch::phys_2_virt(base_address).unwrap() }, + } + } + + pub fn putchar(&mut self, c: u8) { + let ptr = self.base_address.as_ptr() as *mut u8; + loop { + unsafe { + if ptr.add(5).read_volatile() & (1 << 5) != 0 { + break; + } + } + } + unsafe { + ptr.add(0).write_volatile(c); + } + } + + pub fn getchar(&mut self) -> Option { + let ptr = self.base_address.as_ptr() as *mut u8; + unsafe { + if ptr.add(5).read_volatile() & 1 == 0 { + // The DR bit is 0, meaning no data + None + } else { + // The DR bit is 1, meaning data! + Some(ptr.add(0).read_volatile()) + } + } + } +} + +#[inline(never)] +pub(super) fn early_la64_seria8250_init() -> Result<(), SystemError> { + let port = Serial8250LA64Port::new(UART_PADDR_COM1); + unsafe { + UART_PORT_COM1 = Some(SpinLock::new(port)); + } + send_to_default_serial8250_la64_port(b"[DragonOS] loongarch64 debug uart port initialized!\n"); + Ok(()) +} + +pub(super) fn send_to_default_serial8250_la64_port(s: &[u8]) { + if let Some(com) = unsafe { UART_PORT_COM1.as_ref() } { + let mut cg = com.lock_irqsave(); + for c in s.iter() { + cg.putchar(*c); + } + } +} diff --git a/kernel/src/driver/tty/pty/unix98pty.rs b/kernel/src/driver/tty/pty/unix98pty.rs index c280f0b8..c8658335 100644 --- a/kernel/src/driver/tty/pty/unix98pty.rs +++ b/kernel/src/driver/tty/pty/unix98pty.rs @@ -10,6 +10,7 @@ use crate::{ }, filesystem::{ devpts::DevPtsFs, + epoll::EPollEventType, vfs::{ file::FileMode, syscall::ModeType, FilePrivateData, FileType, MountFS, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES, @@ -17,7 +18,6 @@ use crate::{ }, libs::spinlock::SpinLockGuard, mm::VirtAddr, - net::event_poll::EPollEventType, syscall::user_access::UserBufferWriter, }; diff --git a/kernel/src/driver/tty/termios.rs b/kernel/src/driver/tty/termios.rs index 0a0ca4bb..919ec84c 100644 --- a/kernel/src/driver/tty/termios.rs +++ b/kernel/src/driver/tty/termios.rs @@ -44,10 +44,8 @@ pub struct PosixTermios { pub c_oflag: u32, pub c_cflag: u32, pub c_lflag: u32, - pub c_cc: [u8; CONTORL_CHARACTER_NUM], pub c_line: u8, - pub c_ispeed: u32, - pub c_ospeed: u32, + pub c_cc: [u8; CONTORL_CHARACTER_NUM], } impl PosixTermios { @@ -59,8 +57,6 @@ impl PosixTermios { c_lflag: termios.local_mode.bits, c_cc: termios.control_characters, c_line: termios.line as u8, - c_ispeed: termios.input_speed, - c_ospeed: termios.output_speed, } } @@ -73,8 +69,24 @@ impl PosixTermios { local_mode: LocalMode::from_bits_truncate(self.c_lflag), control_characters: self.c_cc, line: LineDisciplineType::from_line(self.c_line), - input_speed: self.c_ispeed, - output_speed: self.c_ospeed, + input_speed: self.input_speed().unwrap_or(38400), + output_speed: self.output_speed().unwrap_or(38400), + } + } + + fn output_speed(&self) -> Option { + let flag = ControlMode::from_bits_truncate( + self.c_cflag & ControlMode::CBAUD.intersection(ControlMode::CBAUDEX).bits(), + ); // CBAUD + CBAUDEX + flag.baud_rate() + } + + fn input_speed(&self) -> Option { + let ibaud = (self.c_cflag & ControlMode::CIBAUD.bits()) >> 16; + if ibaud == 0 { + self.output_speed() + } else { + ControlMode::from_bits_truncate(ibaud).baud_rate() } } } @@ -352,6 +364,47 @@ bitflags! { } } +impl ControlMode { + /// 获取波特率 + pub fn baud_rate(&self) -> Option { + let flag = self.intersection(Self::CBAUD); + match flag { + Self::B0 => Some(0), + Self::B50 => Some(50), + Self::B75 => Some(75), + Self::B110 => Some(110), + Self::B134 => Some(134), + Self::B150 => Some(150), + Self::B200 => Some(200), + Self::B300 => Some(300), + Self::B600 => Some(600), + Self::B1200 => Some(1200), + Self::B1800 => Some(1800), + Self::B2400 => Some(2400), + Self::B4800 => Some(4800), + Self::B9600 => Some(9600), + Self::B19200 => Some(19200), + Self::B38400 => Some(38400), + Self::B57600 => Some(57600), + Self::B115200 => Some(115200), + Self::B230400 => Some(230400), + Self::B460800 => Some(460800), + Self::B500000 => Some(500000), + Self::B576000 => Some(576000), + Self::B921600 => Some(921600), + Self::B1000000 => Some(1000000), + Self::B1152000 => Some(1152000), + Self::B1500000 => Some(1500000), + Self::B2000000 => Some(2000000), + Self::B2500000 => Some(2500000), + Self::B3000000 => Some(3000000), + Self::B3500000 => Some(3500000), + Self::B4000000 => Some(4000000), + _ => None, + } + } +} + /// 对应termios中控制字符的索引 pub struct ControlCharIndex; #[allow(dead_code)] diff --git a/kernel/src/driver/tty/tty_core.rs b/kernel/src/driver/tty/tty_core.rs index 93f0e9c4..40c3a095 100644 --- a/kernel/src/driver/tty/tty_core.rs +++ b/kernel/src/driver/tty/tty_core.rs @@ -12,14 +12,14 @@ use system_error::SystemError; use crate::{ driver::{base::device::device_number::DeviceNumber, tty::pty::ptm_driver}, + filesystem::epoll::{EPollEventType, EPollItem}, libs::{ rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard}, spinlock::{SpinLock, SpinLockGuard}, wait_queue::EventWaitQueue, }, mm::VirtAddr, - net::event_poll::{EPollEventType, EPollItem}, - process::Pid, + process::{process_group::Pgid, session::Sid, ProcessControlBlock}, syscall::user_access::{UserBufferReader, UserBufferWriter}, }; @@ -50,6 +50,7 @@ impl Drop for TtyCore { } impl TtyCore { + #[inline(never)] pub fn new(driver: Arc, index: usize) -> Arc { let name = driver.tty_line_name(index); let device_number = driver @@ -76,7 +77,6 @@ impl TtyCore { device_number, privete_fields: SpinLock::new(None), }; - return Arc::new(Self { core, line_discipline: Arc::new(NTtyLinediscipline { @@ -280,16 +280,23 @@ impl TtyCore { #[derive(Debug, Default)] pub struct TtyContorlInfo { - /// 前台进程pid - pub session: Option, + /// 当前会话的SId + pub session: Option, /// 前台进程组id - pub pgid: Option, + pub pgid: Option, /// packet模式下使用,目前未用到 pub pktstatus: TtyPacketStatus, pub packet: bool, } +impl TtyContorlInfo { + pub fn set_info_by_pcb(&mut self, pcb: Arc) { + self.session = Some(pcb.sid()); + self.pgid = Some(pcb.pgid()); + } +} + #[derive(Debug, Default)] pub struct TtyFlowState { /// 表示流控是否被停止 @@ -490,6 +497,16 @@ impl TtyCoreData { self.epitems.lock().push_back(epitem) } + pub fn remove_epitem(&self, epitem: &Arc) -> Result<(), SystemError> { + let mut guard = self.epitems.lock(); + let len = guard.len(); + guard.retain(|x| !Arc::ptr_eq(x, epitem)); + if len != guard.len() { + return Ok(()); + } + Err(SystemError::ENOENT) + } + pub fn eptiems(&self) -> &SpinLock>> { &self.epitems } diff --git a/kernel/src/driver/tty/tty_device.rs b/kernel/src/driver/tty/tty_device.rs index 7b78ef4e..6f50bfc8 100644 --- a/kernel/src/driver/tty/tty_device.rs +++ b/kernel/src/driver/tty/tty_device.rs @@ -25,8 +25,12 @@ use crate::{ }, filesystem::{ devfs::{devfs_register, DevFS, DeviceINode}, + epoll::EPollItem, kernfs::KernFSInode, - vfs::{file::FileMode, syscall::ModeType, FilePrivateData, FileType, IndexNode, Metadata}, + vfs::{ + file::FileMode, syscall::ModeType, FilePrivateData, FileType, IndexNode, Metadata, + PollableInode, + }, }, init::initcall::INITCALL_DEVICE, libs::{ @@ -34,7 +38,6 @@ use crate::{ spinlock::SpinLockGuard, }, mm::VirtAddr, - net::event_poll::{EPollItem, KernelIoctlData}, process::ProcessManager, syscall::user_access::{UserBufferReader, UserBufferWriter}, }; @@ -130,6 +133,43 @@ impl TtyDevice { pub fn name_ref(&self) -> &str { &self.name } + + fn tty_core(private_data: &FilePrivateData) -> Result, SystemError> { + let (tty, _) = if let FilePrivateData::Tty(tty_priv) = private_data { + (tty_priv.tty.clone(), tty_priv.mode) + } else { + return Err(SystemError::EIO); + }; + Ok(tty) + } +} + +impl PollableInode for TtyDevice { + fn poll(&self, private_data: &FilePrivateData) -> Result { + let tty = TtyDevice::tty_core(private_data)?; + tty.ldisc().poll(tty) + } + + fn add_epitem( + &self, + epitem: Arc, + private_data: &FilePrivateData, + ) -> Result<(), SystemError> { + let tty = TtyDevice::tty_core(private_data)?; + let core = tty.core(); + core.add_epitem(epitem); + Ok(()) + } + + fn remove_epitem( + &self, + epitem: &Arc, + private_data: &FilePrivateData, + ) -> Result<(), SystemError> { + let tty = TtyDevice::tty_core(private_data)?; + let core = tty.core(); + core.remove_epitem(epitem) + } } impl IndexNode for TtyDevice { @@ -312,35 +352,6 @@ impl IndexNode for TtyDevice { Ok(()) } - fn kernel_ioctl( - &self, - arg: Arc, - data: &FilePrivateData, - ) -> Result { - let epitem = arg - .arc_any() - .downcast::() - .map_err(|_| SystemError::EFAULT)?; - - let _ = UserBufferReader::new( - &epitem as *const Arc, - core::mem::size_of::>(), - false, - )?; - - let (tty, _) = if let FilePrivateData::Tty(tty_priv) = data { - (tty_priv.tty(), tty_priv.mode) - } else { - return Err(SystemError::EIO); - }; - - let core = tty.core(); - - core.add_epitem(epitem.clone()); - - return Ok(0); - } - fn ioctl(&self, cmd: u32, arg: usize, data: &FilePrivateData) -> Result { let (tty, _) = if let FilePrivateData::Tty(tty_priv) = data { (tty_priv.tty(), tty_priv.mode) @@ -423,14 +434,8 @@ impl IndexNode for TtyDevice { Ok(0) } - fn poll(&self, private_data: &FilePrivateData) -> Result { - let (tty, _) = if let FilePrivateData::Tty(tty_priv) = private_data { - (tty_priv.tty.clone(), tty_priv.mode) - } else { - return Err(SystemError::EIO); - }; - - tty.ldisc().poll(tty) + fn as_pollable_inode(&self) -> Result<&dyn PollableInode, SystemError> { + Ok(self) } } diff --git a/kernel/src/driver/tty/tty_driver.rs b/kernel/src/driver/tty/tty_driver.rs index a586599f..6c0ffcf1 100644 --- a/kernel/src/driver/tty/tty_driver.rs +++ b/kernel/src/driver/tty/tty_driver.rs @@ -309,10 +309,16 @@ impl TtyDriver { } else { idx = self.ida.lock().alloc().ok_or(SystemError::EBUSY)?; } - + log::debug!("init_tty_device: create TtyCore"); let tty = TtyCore::new(self.self_ref(), idx); + log::debug!("init_tty_device: to driver_install_tty"); self.driver_install_tty(tty.clone())?; + log::debug!( + "init_tty_device: driver_install_tty done, index: {}, dev_name: {:?}", + idx, + tty.core().name(), + ); let core = tty.core(); @@ -321,18 +327,20 @@ impl TtyDriver { ports[core.index()].setup_internal_tty(Arc::downgrade(&tty)); tty.set_port(ports[core.index()].clone()); } - + log::debug!("init_tty_device: to ldisc_setup"); TtyLdiscManager::ldisc_setup(tty.clone(), tty.core().link())?; // 在devfs创建对应的文件 + log::debug!("init_tty_device: to new tty device"); let device = TtyDevice::new( core.name().clone(), IdTable::new(self.tty_line_name(idx), Some(*core.device_number())), super::tty_device::TtyType::Tty, ); - + log::debug!("init_tty_device: to devfs_register"); devfs_register(device.name_ref(), device.clone())?; + log::debug!("init_tty_device: to device_register"); device_register(device)?; Ok(tty) } @@ -473,8 +481,8 @@ pub trait TtyOperation: Sync + Send + Debug { fn flush_chars(&self, tty: &TtyCoreData); - fn put_char(&self, _tty: &TtyCoreData, _ch: u8) -> Result<(), SystemError> { - Err(SystemError::ENOSYS) + fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> { + self.write(tty, &[ch], 1).map(|_| ()) } fn start(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { diff --git a/kernel/src/driver/tty/tty_job_control.rs b/kernel/src/driver/tty/tty_job_control.rs index ef242838..9cff704f 100644 --- a/kernel/src/driver/tty/tty_job_control.rs +++ b/kernel/src/driver/tty/tty_job_control.rs @@ -4,11 +4,8 @@ use system_error::SystemError; use crate::{ arch::ipc::signal::{SigSet, Signal}, mm::VirtAddr, - process::{Pid, ProcessFlags, ProcessManager}, - syscall::{ - user_access::{UserBufferReader, UserBufferWriter}, - Syscall, - }, + process::{process_group::Pgid, Pid, ProcessFlags, ProcessManager}, + syscall::user_access::{UserBufferReader, UserBufferWriter}, }; use super::tty_core::{TtyCore, TtyIoctlCmd}; @@ -19,15 +16,13 @@ impl TtyJobCtrlManager { /// ### 设置当前进程的tty pub fn proc_set_tty(tty: Arc) { let core = tty.core(); - let mut ctrl = core.contorl_info_irqsave(); let pcb = ProcessManager::current_pcb(); - ctrl.session = Some(pcb.basic().sid()); - - assert!(pcb.sig_info_irqsave().tty().is_none()); + let mut ctrl = core.contorl_info_irqsave(); + ctrl.set_info_by_pcb(pcb.clone()); + drop(ctrl); let mut singal = pcb.sig_info_mut(); - drop(ctrl); singal.set_tty(Some(tty.clone())); } @@ -41,27 +36,27 @@ impl TtyJobCtrlManager { return Ok(()); } - let core = tty.core(); - let ctrl = core.contorl_info_irqsave(); + let pgid = pcb.pgid(); - // todo pgid - let pgid = pcb.pid(); + let ctrl = tty.core().contorl_info_irqsave(); let tty_pgid = ctrl.pgid; + drop(ctrl); if tty_pgid.is_some() && tty_pgid.unwrap() != pgid { if pcb .sig_info_irqsave() .sig_blocked() - .contains(SigSet::from_bits_truncate(1 << sig as u64)) + .contains(SigSet::from(sig)) || pcb.sig_struct_irqsave().handlers[sig as usize - 1].is_ignore() { // 忽略该信号 if sig == Signal::SIGTTIN { return Err(SystemError::EIO); } + } else if ProcessManager::is_current_pgrp_orphaned() { + return Err(SystemError::EIO); } else { - // 暂时使用kill而不是killpg - Syscall::kill(pgid, sig as i32)?; + crate::ipc::kill::kill_process_group(pgid, sig)?; ProcessManager::current_pcb() .flags() .insert(ProcessFlags::HAS_PENDING_SIGNAL); @@ -73,74 +68,146 @@ impl TtyJobCtrlManager { Ok(()) } - pub fn job_ctrl_ioctl(tty: Arc, cmd: u32, arg: usize) -> Result { + pub fn job_ctrl_ioctl( + real_tty: Arc, + cmd: u32, + arg: usize, + ) -> Result { match cmd { - TtyIoctlCmd::TIOCSPGRP => { - match Self::tty_check_change(tty.clone(), Signal::SIGTTOU) { - Ok(_) => {} - Err(e) => { - if e == SystemError::EIO { - return Err(SystemError::ENOTTY); - } - return Err(e); - } - }; - - let user_reader = UserBufferReader::new( - VirtAddr::new(arg).as_ptr::(), - core::mem::size_of::(), - true, - )?; - - let pgrp = user_reader.read_one_from_user::(0)?; - - let current = ProcessManager::current_pcb(); - - let mut ctrl = tty.core().contorl_info_irqsave(); - - if current.sig_info_irqsave().tty().is_none() - || !Arc::ptr_eq(¤t.sig_info_irqsave().tty().clone().unwrap(), &tty) - || ctrl.session.is_none() - || ctrl.session.unwrap() != current.basic().sid() - { - return Err(SystemError::ENOTTY); - } - - ctrl.pgid = Some(Pid::new(*pgrp as usize)); - - return Ok(0); - } - - TtyIoctlCmd::TIOCGPGRP => { - let current = ProcessManager::current_pcb(); - if current.sig_info_irqsave().tty().is_some() - && !Arc::ptr_eq(¤t.sig_info_irqsave().tty().unwrap(), &tty) - { - return Err(SystemError::ENOTTY); - } - - let mut user_writer = UserBufferWriter::new( - VirtAddr::new(arg).as_ptr::(), - core::mem::size_of::(), - true, - )?; - - user_writer.copy_one_to_user( - &(tty - .core() - .contorl_info_irqsave() - .pgid - .unwrap_or(Pid::new(0)) - .data() as i32), - 0, - )?; - - return Ok(0); - } - + TtyIoctlCmd::TIOCSPGRP => Self::tiocspgrp(real_tty, arg), + TtyIoctlCmd::TIOCGPGRP => Self::tiocgpgrp(real_tty, arg), + TtyIoctlCmd::TIOCGSID => Self::tiocgsid(real_tty, arg), + TtyIoctlCmd::TIOCSCTTY => Self::tiocsctty(real_tty), _ => { return Err(SystemError::ENOIOCTLCMD); } } } + + fn tiocsctty(real_tty: Arc) -> Result { + let current = ProcessManager::current_pcb(); + // log::debug!("job_ctrl_ioctl: TIOCSCTTY,current: {:?}", current.pid()); + if current.is_session_leader() + && real_tty.core().contorl_info_irqsave().session.unwrap() == current.sid() + { + return Ok(0); + } + + if !current.is_session_leader() || current.sig_info_irqsave().tty().is_some() { + return Err(SystemError::EPERM); + } + + //todo 权限检查? + // https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/tty/tty_jobctrl.c#tiocsctty + if let Some(sid) = real_tty.core().contorl_info_irqsave().session { + //todo 目前只有一个tty设备,所以选择复用1号进程的tty,因此修改1号进程的tty暂时被允许 + if sid != Pid::new(1) { + return Err(SystemError::EPERM); + } + } + + Self::proc_set_tty(real_tty); + Ok(0) + } + + fn tiocgpgrp(real_tty: Arc, arg: usize) -> Result { + // log::debug!("job_ctrl_ioctl: TIOCGPGRP"); + let current = ProcessManager::current_pcb(); + if current.sig_info_irqsave().tty().is_some() + && !Arc::ptr_eq(¤t.sig_info_irqsave().tty().unwrap(), &real_tty) + { + return Err(SystemError::ENOTTY); + } + + let mut user_writer = UserBufferWriter::new( + VirtAddr::new(arg).as_ptr::(), + core::mem::size_of::(), + true, + )?; + + user_writer.copy_one_to_user( + &(real_tty + .core() + .contorl_info_irqsave() + .pgid + .unwrap_or(Pid::new(1)) + .data() as i32), + 0, + )?; + + return Ok(0); + } + + fn tiocgsid(real_tty: Arc, arg: usize) -> Result { + // log::debug!("job_ctrl_ioctl: TIOCGSID"); + let current = ProcessManager::current_pcb(); + if current.sig_info_irqsave().tty().is_some() + && !Arc::ptr_eq(¤t.sig_info_irqsave().tty().unwrap(), &real_tty) + { + return Err(SystemError::ENOTTY); + } + + let guard = real_tty.core().contorl_info_irqsave(); + if guard.session.is_none() { + return Err(SystemError::ENOTTY); + } + let sid = guard.session.unwrap(); + drop(guard); + + let mut user_writer = UserBufferWriter::new( + VirtAddr::new(arg).as_ptr::(), + core::mem::size_of::(), + true, + )?; + user_writer.copy_one_to_user(&(sid.data() as i32), 0)?; + + return Ok(0); + } + + fn tiocspgrp(real_tty: Arc, arg: usize) -> Result { + // log::debug!("job_ctrl_ioctl: TIOCSPGRP"); + match Self::tty_check_change(real_tty.clone(), Signal::SIGTTOU) { + Ok(_) => {} + Err(e) => { + if e == SystemError::EIO { + return Err(SystemError::ENOTTY); + } + return Err(e); + } + }; + + let user_reader = UserBufferReader::new( + VirtAddr::new(arg).as_ptr::(), + core::mem::size_of::(), + true, + )?; + + let pgrp = user_reader.read_one_from_user::(0)?; + + let current = ProcessManager::current_pcb(); + + let mut ctrl = real_tty.core().contorl_info_irqsave(); + + if current.sig_info_irqsave().tty().is_none() + || !Arc::ptr_eq( + ¤t.sig_info_irqsave().tty().clone().unwrap(), + &real_tty, + ) + || ctrl.session.is_none() + || ctrl.session.unwrap() != current.sid() + { + return Err(SystemError::ENOTTY); + } + + let pg = ProcessManager::find_process_group(Pgid::from(*pgrp as usize)); + if pg.is_none() { + return Err(SystemError::ESRCH); + } else if !Arc::ptr_eq(&pg.unwrap().session().unwrap(), ¤t.session().unwrap()) { + return Err(SystemError::EPERM); + } + + ctrl.pgid = Some(Pid::from(*pgrp as usize)); + + return Ok(0); + } } diff --git a/kernel/src/driver/tty/tty_ldisc/mod.rs b/kernel/src/driver/tty/tty_ldisc/mod.rs index e46ec325..f00e41c2 100644 --- a/kernel/src/driver/tty/tty_ldisc/mod.rs +++ b/kernel/src/driver/tty/tty_ldisc/mod.rs @@ -99,6 +99,7 @@ impl TtyLdiscManager { /// ### 参数 /// - tty:需要设置的tty /// - o_tty: other tty 用于pty pair + #[inline(never)] pub fn ldisc_setup(tty: Arc, o_tty: Option>) -> Result<(), SystemError> { let ld = tty.ldisc(); diff --git a/kernel/src/driver/tty/tty_ldisc/ntty.rs b/kernel/src/driver/tty/tty_ldisc/ntty.rs index 363fe579..81353bcc 100644 --- a/kernel/src/driver/tty/tty_ldisc/ntty.rs +++ b/kernel/src/driver/tty/tty_ldisc/ntty.rs @@ -15,15 +15,14 @@ use crate::{ tty_driver::{TtyDriverFlag, TtyOperation}, tty_job_control::TtyJobCtrlManager, }, - filesystem::vfs::file::FileMode, + filesystem::{epoll::EPollEventType, vfs::file::FileMode}, libs::{ rwlock::RwLockReadGuard, spinlock::{SpinLock, SpinLockGuard}, }, mm::VirtAddr, - net::event_poll::EPollEventType, process::{ProcessFlags, ProcessManager}, - syscall::{user_access::UserBufferWriter, Syscall}, + syscall::user_access::UserBufferWriter, }; use super::TtyLineDiscipline; @@ -149,8 +148,8 @@ impl NTtyData { cursor_column: 0, canon_cursor_column: 0, echo_tail: 0, - read_buf: Box::new([0; NTTY_BUFSIZE]), - echo_buf: Box::new([0; NTTY_BUFSIZE]), + read_buf: vec![0; NTTY_BUFSIZE].into_boxed_slice().try_into().unwrap(), + echo_buf: vec![0; NTTY_BUFSIZE].into_boxed_slice().try_into().unwrap(), read_flags: StaticBitmap::new(), char_map: StaticBitmap::new(), tty: Weak::default(), @@ -390,7 +389,7 @@ impl NTtyData { continue; } - if ((c as usize) < self.char_map.size()) && self.char_map.get(c as usize).unwrap() { + if ((c as usize) < self.char_map.len()) && self.char_map.get(c as usize).unwrap() { // 特殊字符 self.receive_special_char(c, tty.clone(), lookahead_done); } else { @@ -790,7 +789,7 @@ impl NTtyData { let ctrl_info = tty.core().contorl_info_irqsave(); let pg = ctrl_info.pgid; if let Some(pg) = pg { - let _ = Syscall::kill(pg, signal as i32); + let _ = crate::ipc::kill::kill_process_group(pg, signal); } if !termios.local_mode.contains(LocalMode::NOFLSH) { diff --git a/kernel/src/driver/tty/tty_port.rs b/kernel/src/driver/tty/tty_port.rs index bab9ea7f..19d97116 100644 --- a/kernel/src/driver/tty/tty_port.rs +++ b/kernel/src/driver/tty/tty_port.rs @@ -5,8 +5,8 @@ use kdepends::thingbuf::mpsc; use system_error::SystemError; use crate::{ + filesystem::epoll::{event_poll::EventPoll, EPollEventType}, libs::spinlock::{SpinLock, SpinLockGuard}, - net::event_poll::EventPoll, }; use super::tty_core::TtyCore; @@ -80,17 +80,14 @@ pub trait TtyPort: Sync + Send + Debug { /// 作为客户端的tty ports接收数据 fn receive_buf(&self, buf: &[u8], _flags: &[u8], count: usize) -> Result { let tty = self.port_data().internal_tty().unwrap(); - let ld = tty.ldisc(); - let ret = ld.receive_buf2(tty.clone(), buf, None, count); - if let Err(SystemError::ENOSYS) = ret { return ld.receive_buf(tty, buf, None, count); } - - EventPoll::wakeup_epoll(tty.core().eptiems(), None)?; - + let event: usize = ld.poll(tty.clone())?; + let pollflag = EPollEventType::from_bits_truncate(event as u32); + EventPoll::wakeup_epoll(tty.core().eptiems(), pollflag)?; ret } } diff --git a/kernel/src/driver/tty/virtual_terminal/mod.rs b/kernel/src/driver/tty/virtual_terminal/mod.rs index 31abbfb6..5ec8d28e 100644 --- a/kernel/src/driver/tty/virtual_terminal/mod.rs +++ b/kernel/src/driver/tty/virtual_terminal/mod.rs @@ -58,6 +58,8 @@ lazy_static! { static ref VC_MANAGER: VirtConsoleManager = VirtConsoleManager::new(); } +kernel_cmdline_param_kv!(CONSOLE_PARAM, console, ""); + /// 获取虚拟终端管理器 #[inline] pub fn vc_manager() -> &'static VirtConsoleManager { @@ -228,12 +230,29 @@ impl VirtConsoleManager { } pub fn setup_default_vc(&self) { - // todo: 从内核启动参数中获取 - for name in Self::DEFAULT_VC_NAMES.iter() { - if let Some(vc) = self.lookup_vc_by_tty_name(name) { - log::info!("Set default vc with tty device: {}", name); + let mut console_value_str = CONSOLE_PARAM.value_str().unwrap_or("").trim(); + if !console_value_str.is_empty() { + // 删除前缀/dev/ + console_value_str = console_value_str + .strip_prefix("/dev/") + .unwrap_or(console_value_str); + if let Some(vc) = self.lookup_vc_by_tty_name(console_value_str) { + log::info!("Set vc by cmdline: {}", console_value_str); self.set_current_vc(vc); return; + } else { + panic!( + "virt console: set vc by cmdline failed, name: {}", + console_value_str + ); + } + } else { + for name in Self::DEFAULT_VC_NAMES.iter() { + if let Some(vc) = self.lookup_vc_by_tty_name(name) { + log::info!("Set default vc with tty device: {}", name); + self.set_current_vc(vc); + return; + } } } diff --git a/kernel/src/driver/video/mod.rs b/kernel/src/driver/video/mod.rs index 42c4249a..09fede63 100644 --- a/kernel/src/driver/video/mod.rs +++ b/kernel/src/driver/video/mod.rs @@ -155,7 +155,7 @@ impl VideoRefreshManager { } /// 在riscv64平台下暂时不支持 - #[cfg(target_arch = "riscv64")] + #[cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))] pub unsafe fn video_init() -> Result<(), SystemError> { return Err(SystemError::ENOSYS); } @@ -295,10 +295,3 @@ impl TimerFunction for VideoRefreshExecutor { return Ok(()); } } - -#[no_mangle] -pub unsafe extern "C" fn rs_video_init() -> i32 { - return VideoRefreshManager::video_init() - .map(|_| 0) - .unwrap_or_else(|e| e.to_posix_errno()); -} diff --git a/kernel/src/driver/virtio/mod.rs b/kernel/src/driver/virtio/mod.rs index d0a1db91..fca5212b 100644 --- a/kernel/src/driver/virtio/mod.rs +++ b/kernel/src/driver/virtio/mod.rs @@ -1,4 +1,4 @@ -use alloc::{collections::LinkedList, string::String, sync::Arc}; +use alloc::{string::String, sync::Arc, vec::Vec}; use system_error::SystemError; use crate::exception::{irqdesc::IrqReturn, IrqNumber}; @@ -51,7 +51,7 @@ pub trait VirtIODevice: Device { pub trait VirtIODriver: Driver { fn probe(&self, device: &Arc) -> Result<(), SystemError>; - fn virtio_id_table(&self) -> LinkedList; + fn virtio_id_table(&self) -> Vec; fn add_virtio_id(&self, id: VirtioDeviceId); } @@ -60,7 +60,7 @@ int_like!(VirtIODeviceIndex, usize); #[derive(Debug, Default)] pub struct VirtIODriverCommonData { - pub id_table: LinkedList, + pub id_table: Vec, } /// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/mod_devicetable.h#449 @@ -75,3 +75,19 @@ impl VirtioDeviceId { Self { device, vendor } } } + +pub fn virtio_drivers_error_to_system_error(error: virtio_drivers::Error) -> SystemError { + match error { + virtio_drivers::Error::QueueFull => SystemError::ENOBUFS, + virtio_drivers::Error::NotReady => SystemError::EAGAIN_OR_EWOULDBLOCK, + virtio_drivers::Error::WrongToken => SystemError::EINVAL, + virtio_drivers::Error::AlreadyUsed => SystemError::EBUSY, + virtio_drivers::Error::InvalidParam => SystemError::EINVAL, + virtio_drivers::Error::DmaError => SystemError::ENOMEM, + virtio_drivers::Error::IoError => SystemError::EIO, + virtio_drivers::Error::Unsupported => SystemError::ENOSYS, + virtio_drivers::Error::ConfigSpaceTooSmall => SystemError::EINVAL, + virtio_drivers::Error::ConfigSpaceMissing => SystemError::EINVAL, + virtio_drivers::Error::SocketDeviceError(_) => SystemError::EIO, + } +} diff --git a/kernel/src/driver/virtio/sysfs.rs b/kernel/src/driver/virtio/sysfs.rs index b528d5c0..2749155c 100644 --- a/kernel/src/driver/virtio/sysfs.rs +++ b/kernel/src/driver/virtio/sysfs.rs @@ -196,11 +196,14 @@ impl VirtIODeviceManager { dev.set_virtio_device_index(virtio_index); dev.set_device_name(format!("virtio{}", virtio_index.data())); + log::debug!("virtio_device_add: dev: {:?}", dev.name()); + // 添加设备到设备管理器 device_manager().add_device(dev.clone() as Arc)?; let r = device_manager() .add_groups(&(dev.clone() as Arc), &[&VirtIODeviceAttrGroup]); - + log::debug!("virtio_device_add: to setup irq"); self.setup_irq(&dev).ok(); + log::debug!("virtio_device_add: setup irq done"); return r; } diff --git a/kernel/src/driver/virtio/virtio.rs b/kernel/src/driver/virtio/virtio.rs index 4864f01b..414d11e2 100644 --- a/kernel/src/driver/virtio/virtio.rs +++ b/kernel/src/driver/virtio/virtio.rs @@ -4,6 +4,7 @@ use super::virtio_impl::HalImpl; use crate::driver::base::device::bus::Bus; use crate::driver::base::device::{Device, DeviceId}; use crate::driver::block::virtio_blk::virtio_blk; +use crate::driver::char::virtio_console::virtio_console; use crate::driver::net::virtio_net::virtio_net; use crate::driver::pci::pci::{ get_pci_device_structures_mut_by_vendor_id, PciDeviceStructureGeneralDevice, @@ -11,18 +12,24 @@ use crate::driver::pci::pci::{ }; use crate::driver::pci::subsys::pci_bus; use crate::driver::virtio::transport::VirtIOTransport; +use crate::init::initcall::INITCALL_DEVICE; use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; use log::{debug, error, warn}; +use system_error::SystemError; +use unified_init::macros::unified_init; use virtio_drivers::transport::{DeviceType, Transport}; ///@brief 寻找并加载所有virtio设备的驱动(目前只有virtio-net,但其他virtio设备也可添加) -pub fn virtio_probe() { +#[unified_init(INITCALL_DEVICE)] +fn virtio_probe() -> Result<(), SystemError> { #[cfg(not(target_arch = "riscv64"))] virtio_probe_pci(); virtio_probe_mmio(); + + Ok(()) } #[allow(dead_code)] @@ -63,6 +70,7 @@ pub(super) fn virtio_device_init( DeviceType::GPU => { warn!("Not support virtio_gpu device for now"); } + DeviceType::Console => virtio_console(transport, dev_id, dev_parent), DeviceType::Input => { warn!("Not support virtio_input device for now"); } diff --git a/kernel/src/exception/manage.rs b/kernel/src/exception/manage.rs index 4e84d8a6..30290de6 100644 --- a/kernel/src/exception/manage.rs +++ b/kernel/src/exception/manage.rs @@ -11,7 +11,7 @@ use crate::{ irqchip::IrqChipSetMaskResult, irqdesc::{irq_desc_manager, InnerIrqDesc, IrqAction}, }, - libs::{cpumask::CpuMask, spinlock::SpinLockGuard}, + libs::{cpumask::CpuMask, mutex::MutexGuard, spinlock::SpinLockGuard}, process::{kthread::KernelThreadMechanism, ProcessManager}, smp::cpu::ProcessorId, }; @@ -156,87 +156,98 @@ impl IrqManager { *action_guard.flags_mut() = flags; *action_guard.dev_id_mut() = dev_id; drop(action_guard); - debug!("to inner_setup_irq: {irq:?}"); + // debug!("to inner_setup_irq: {irq:?}"); return self.inner_setup_irq(irq, irqaction, desc); } + /// 处理线程错误 + #[inline(never)] + fn handle_thread_error( + &self, + e: SystemError, + mut action_guard: SpinLockGuard<'_, InnerIrqAction>, + ) -> SystemError { + if let Some(thread_pcb) = action_guard.thread() { + action_guard.set_thread(None); + KernelThreadMechanism::stop(&thread_pcb).ok(); + } + + if let Some(secondary) = action_guard.secondary() { + let mut secondary_guard = secondary.inner(); + if let Some(thread_pcb) = secondary_guard.thread() { + secondary_guard.set_thread(None); + KernelThreadMechanism::stop(&thread_pcb).ok(); + } + } + e + } + + /// 处理总线解锁错误 + #[inline(never)] + fn handle_bus_unlock_error( + &self, + e: SystemError, + desc: Arc, + req_mutex_guard: crate::libs::mutex::MutexGuard<'_, ()>, + action_guard: SpinLockGuard<'_, InnerIrqAction>, + ) -> SystemError { + desc.chip_bus_sync_unlock(); + drop(req_mutex_guard); + self.handle_thread_error(e, action_guard) + } + + /// 处理解锁错误 + #[inline(never)] + fn handle_unlock_error( + &self, + e: SystemError, + desc_guard: SpinLockGuard<'_, InnerIrqDesc>, + desc: Arc, + req_mutex_guard: crate::libs::mutex::MutexGuard<'_, ()>, + action_guard: SpinLockGuard<'_, InnerIrqAction>, + ) -> SystemError { + drop(desc_guard); + self.handle_bus_unlock_error(e, desc, req_mutex_guard, action_guard) + } + + /// 处理标志不匹配错误 + #[inline(never)] + fn __inner_setup_irq_handle_mismatch_error( + &self, + old_action_guard: SpinLockGuard<'_, InnerIrqAction>, + desc_guard: SpinLockGuard<'_, InnerIrqDesc>, + action_guard: SpinLockGuard<'_, InnerIrqAction>, + desc: Arc, + req_mutex_guard: crate::libs::mutex::MutexGuard<'_, ()>, + ) -> SystemError { + if !action_guard + .flags() + .contains(IrqHandleFlags::IRQF_PROBE_SHARED) + { + error!("Flags mismatch for irq {} (name: {}, flags: {:?}). old action name: {}, old flags: {:?}", + desc.irq_data().irq().data(), + action_guard.name(), + action_guard.flags(), + old_action_guard.name(), + old_action_guard.flags()); + } + self.handle_unlock_error( + SystemError::EBUSY, + desc_guard, + desc, + req_mutex_guard, + action_guard, + ) + } + /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/manage.c?r=&mo=59252&fi=2138#1497 #[inline(never)] - fn inner_setup_irq( + fn prepare_irq_setup<'a>( &self, + mut action_guard: SpinLockGuard<'a, InnerIrqAction>, irq: IrqNumber, - action: Arc, - desc: Arc, - ) -> Result<(), SystemError> { - // ==== 定义错误处理函数 ==== - let err_out_thread = - |e: SystemError, mut action_guard: SpinLockGuard<'_, InnerIrqAction>| -> SystemError { - if let Some(thread_pcb) = action_guard.thread() { - action_guard.set_thread(None); - KernelThreadMechanism::stop(&thread_pcb).ok(); - } - - if let Some(secondary) = action_guard.secondary() { - let mut secondary_guard = secondary.inner(); - if let Some(thread_pcb) = secondary_guard.thread() { - secondary_guard.set_thread(None); - KernelThreadMechanism::stop(&thread_pcb).ok(); - } - } - return e; - }; - - let err_out_bus_unlock = |e: SystemError, - desc: Arc, - req_mutex_guard: crate::libs::mutex::MutexGuard<'_, ()>, - action_guard: SpinLockGuard<'_, InnerIrqAction>| - -> SystemError { - desc.chip_bus_sync_unlock(); - drop(req_mutex_guard); - return err_out_thread(e, action_guard); - }; - - let err_out_unlock = |e: SystemError, - desc_guard: SpinLockGuard<'_, InnerIrqDesc>, - desc: Arc, - req_mutex_guard: crate::libs::mutex::MutexGuard<'_, ()>, - action_guard: SpinLockGuard<'_, InnerIrqAction>| - -> SystemError { - drop(desc_guard); - return err_out_bus_unlock(e, desc, req_mutex_guard, action_guard); - }; - - let err_out_mismatch = |old_action_guard: SpinLockGuard<'_, InnerIrqAction>, - desc_guard: SpinLockGuard<'_, InnerIrqDesc>, - action_guard: SpinLockGuard<'_, InnerIrqAction>, - desc: Arc, - req_mutex_guard: crate::libs::mutex::MutexGuard<'_, ()>| - -> SystemError { - if !action_guard - .flags() - .contains(IrqHandleFlags::IRQF_PROBE_SHARED) - { - error!("Flags mismatch for irq {} (name: {}, flags: {:?}). old action name: {}, old flags: {:?}", irq.data(), action_guard.name(), action_guard.flags(), old_action_guard.name(), old_action_guard.flags()); - } - return err_out_unlock( - SystemError::EBUSY, - desc_guard, - desc, - req_mutex_guard, - action_guard, - ); - }; - - // ===== 代码开始 ===== - - if Arc::ptr_eq( - &desc.irq_data().chip_info_read_irqsave().chip(), - &no_irq_chip(), - ) { - return Err(SystemError::ENOSYS); - } - - let mut action_guard = action.inner(); + desc: &Arc, + ) -> Result, SystemError> { if !action_guard.flags().trigger_type_specified() { // 如果没有指定触发类型,则使用默认的触发类型 action_guard @@ -263,7 +274,7 @@ impl IrqManager { if let Some(secondary) = action_guard.secondary() { let secondary_guard = secondary.inner(); if let Err(e) = self.setup_irq_thread(irq, secondary_guard.deref(), true) { - return Err(err_out_thread(e, action_guard)); + return Err(self.handle_thread_error(e, action_guard)); } } } @@ -286,6 +297,16 @@ impl IrqManager { *action_guard.flags_mut() &= !IrqHandleFlags::IRQF_ONESHOT; } + Ok(action_guard) + } + + #[inline(never)] + fn setup_irq_resources<'a>( + &self, + action_guard: SpinLockGuard<'a, InnerIrqAction>, + irq: IrqNumber, + desc: &'a Arc, + ) -> Result, SystemError> { // Protects against a concurrent __free_irq() call which might wait // for synchronize_hardirq() to complete without holding the optional // chip bus lock and desc->lock. Also protects against handing out @@ -301,14 +322,20 @@ impl IrqManager { // 如果当前中断线上还没有irqaction, 则先为中断线申请资源 if desc.actions().is_empty() { if let Err(e) = self.irq_request_resources(desc.clone()) { - error!( - "Failed to request resources for {} (irq {}) on irqchip {}, error {:?}", - action_guard.name(), - irq.data(), - desc.irq_data().chip_info_read_irqsave().chip().name(), - e - ); - return Err(err_out_bus_unlock( + #[inline(never)] + fn __tmp_log(name: &str, irq: &IrqNumber, desc: &Arc, e: &SystemError) { + error!( + "Failed to request resources for {} (irq {}) on irqchip {}, error {:?}", + name, + irq.data(), + desc.irq_data().chip_info_read_irqsave().chip().name(), + e + ); + } + + __tmp_log(action_guard.name(), &irq, desc, &e); + + return Err(self.handle_bus_unlock_error( e, desc.clone(), req_mutex_guard, @@ -317,7 +344,7 @@ impl IrqManager { } } - let mut desc_inner_guard: SpinLockGuard<'_, InnerIrqDesc> = desc.inner(); + let desc_inner_guard: SpinLockGuard<'_, InnerIrqDesc> = desc.inner(); // 标记当前irq是否是共享的 let mut irq_shared = false; @@ -330,17 +357,27 @@ impl IrqManager { .internal_state() .contains(IrqDescState::IRQS_NMI) { - error!( - "Invalid attempt to share NMI for {} (irq {}) on irqchip {}", - action_guard.name(), - irq.data(), - desc_inner_guard - .irq_data() - .chip_info_read_irqsave() - .chip() - .name() - ); - return Err(err_out_unlock( + #[inline(never)] + fn __tmp_log( + name: &str, + irq: &IrqNumber, + desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>, + ) { + error!( + "Invalid attempt to share NMI for {} (irq {}) on irqchip {}", + name, + irq.data(), + desc_inner_guard + .irq_data() + .chip_info_read_irqsave() + .chip() + .name() + ); + } + + __tmp_log(action_guard.name(), &irq, &desc_inner_guard); + + return Err(self.handle_unlock_error( SystemError::EINVAL, desc_inner_guard, desc.clone(), @@ -371,16 +408,16 @@ impl IrqManager { || ((old_guard.flags().bitxor(*action_guard.flags())) .contains(IrqHandleFlags::IRQF_ONESHOT)) { - debug!( - "Flags mismatch for irq {} (name: {}, flags: {:?}). old action name: {}, old flags: {:?}", - irq.data(), - action_guard.name(), - action_guard.flags(), - old_guard.name(), - old_guard.flags() - ); + // debug!( + // "Flags mismatch for irq {} (name: {}, flags: {:?}). old action name: {}, old flags: {:?}", + // irq.data(), + // action_guard.name(), + // action_guard.flags(), + // old_guard.name(), + // old_guard.flags() + // ); - return Err(err_out_mismatch( + return Err(self.__inner_setup_irq_handle_mismatch_error( old_guard, desc_inner_guard, action_guard, @@ -393,13 +430,13 @@ impl IrqManager { if *old_guard.flags() & IrqHandleFlags::IRQF_PERCPU != *action_guard.flags() & IrqHandleFlags::IRQF_PERCPU { - debug!( - "Per-cpu mismatch for irq {} (name: {}, flags: {:?})", - irq.data(), - action_guard.name(), - action_guard.flags() - ); - return Err(err_out_mismatch( + // debug!( + // "Per-cpu mismatch for irq {} (name: {}, flags: {:?})", + // irq.data(), + // action_guard.name(), + // action_guard.flags() + // ); + return Err(self.__inner_setup_irq_handle_mismatch_error( old_guard, desc_inner_guard, action_guard, @@ -430,12 +467,17 @@ impl IrqManager { // 因为我们不能确定这个中断实际上具有什么类型。 // 由于底层芯片实现可能会覆盖它们,所以类型标志并不可靠. - error!( + #[inline(never)] + fn __tmp_log(irq: &IrqNumber, name: &str) { + error!( "Requesting irq {} without a handler, and ONESHOT flags not set for irqaction: {}", - irq.data(), - action_guard.name() - ); - return Err(err_out_unlock( + irq.data(), + name, + ); + } + + __tmp_log(&irq, action_guard.name()); + return Err(self.handle_unlock_error( SystemError::EINVAL, desc_inner_guard, desc.clone(), @@ -444,89 +486,119 @@ impl IrqManager { )); } + return Ok(SetupIrqResourcesResp { + action_guard, + irq_shared, + desc_inner_guard, + req_mutex_guard, + }); + } + + #[inline(never)] + fn activate_irq_line<'a>( + &self, + irq: IrqNumber, + desc: &'a Arc, + action: Arc, + mut resp: SetupIrqResourcesResp<'a>, + ) -> Result<(), SystemError> { // 第一次在当前irqdesc上注册中断处理函数 - if !irq_shared { + if !resp.irq_shared { // 设置中断触发方式 - if action_guard.flags().trigger_type_specified() { - let trigger_type = action_guard.flags().trigger_type(); + if resp.action_guard.flags().trigger_type_specified() { + let trigger_type = resp.action_guard.flags().trigger_type(); if let Err(e) = - self.do_set_irq_trigger(desc.clone(), &mut desc_inner_guard, trigger_type) + self.do_set_irq_trigger(desc.clone(), &mut resp.desc_inner_guard, trigger_type) { - debug!( - "Failed to set trigger type for irq {} (name: {}, flags: {:?}), error {:?}", - irq.data(), - action_guard.name(), - action_guard.flags(), - e - ); - return Err(err_out_unlock( + // debug!( + // "Failed to set trigger type for irq {} (name: {}, flags: {:?}), error {:?}", + // irq.data(), + // action_guard.name(), + // action_guard.flags(), + // e + // ); + return Err(self.handle_unlock_error( e, - desc_inner_guard, + resp.desc_inner_guard, desc.clone(), - req_mutex_guard, - action_guard, + resp.req_mutex_guard, + resp.action_guard, )); } } - debug!("to irq_activate"); + // debug!("to irq_activate"); // 激活中断。这种激活必须独立于IRQ_NOAUTOEN进行*desc_inner_guard.internal_state_mut() |= IrqDescState::IRQS_NOREQUEST;uest. - if let Err(e) = self.irq_activate(&desc, &mut desc_inner_guard) { - debug!( - "Failed to activate irq {} (name: {}, flags: {:?}), error {:?}", - irq.data(), - action_guard.name(), - action_guard.flags(), - e - ); - return Err(err_out_unlock( + if let Err(e) = self.irq_activate(desc, &mut resp.desc_inner_guard) { + // debug!( + // "Failed to activate irq {} (name: {}, flags: {:?}), error {:?}", + // irq.data(), + // action_guard.name(), + // action_guard.flags(), + // e + // ); + return Err(self.handle_unlock_error( e, - desc_inner_guard, + resp.desc_inner_guard, desc.clone(), - req_mutex_guard, - action_guard, + resp.req_mutex_guard, + resp.action_guard, )); } - *desc_inner_guard.internal_state_mut() &= !(IrqDescState::IRQS_AUTODETECT + *resp.desc_inner_guard.internal_state_mut() &= !(IrqDescState::IRQS_AUTODETECT | IrqDescState::IRQS_SPURIOUS_DISABLED | IrqDescState::IRQS_ONESHOT | IrqDescState::IRQS_WAITING); - desc_inner_guard + resp.desc_inner_guard .common_data() .clear_status(IrqStatus::IRQD_IRQ_INPROGRESS); - if action_guard.flags().contains(IrqHandleFlags::IRQF_PERCPU) { - desc_inner_guard + if resp + .action_guard + .flags() + .contains(IrqHandleFlags::IRQF_PERCPU) + { + resp.desc_inner_guard .common_data() .insert_status(IrqStatus::IRQD_PER_CPU); - desc_inner_guard.line_status_set_per_cpu(); + resp.desc_inner_guard.line_status_set_per_cpu(); - if action_guard.flags().contains(IrqHandleFlags::IRQF_NO_DEBUG) { - desc_inner_guard.line_status_set_no_debug(); + if resp + .action_guard + .flags() + .contains(IrqHandleFlags::IRQF_NO_DEBUG) + { + resp.desc_inner_guard.line_status_set_no_debug(); } } - if action_guard.flags().contains(IrqHandleFlags::IRQF_ONESHOT) { - *desc_inner_guard.internal_state_mut() |= IrqDescState::IRQS_ONESHOT; + if resp + .action_guard + .flags() + .contains(IrqHandleFlags::IRQF_ONESHOT) + { + *resp.desc_inner_guard.internal_state_mut() |= IrqDescState::IRQS_ONESHOT; } // 如果有要求的话,则忽略IRQ的均衡。 - if action_guard + if resp + .action_guard .flags() .contains(IrqHandleFlags::IRQF_NOBALANCING) { todo!("IRQF_NO_BALANCING"); } - if !action_guard + if !resp + .action_guard .flags() .contains(IrqHandleFlags::IRQF_NO_AUTOEN) - && desc_inner_guard.can_autoenable() + && resp.desc_inner_guard.can_autoenable() { // 如果没有设置IRQF_NOAUTOEN,则自动使能中断 self.irq_startup( - &desc, - &mut desc_inner_guard, + desc, + &mut resp.desc_inner_guard, Self::IRQ_RESEND, Self::IRQ_START_COND, ) @@ -536,49 +608,89 @@ impl IrqManager { // 共享中断可能在它仍然被禁用时请求它,然后永远等待中断。 static mut WARNED: bool = false; - if action_guard.flags().contains(IrqHandleFlags::IRQF_SHARED) && unsafe { !WARNED } + if resp + .action_guard + .flags() + .contains(IrqHandleFlags::IRQF_SHARED) + && unsafe { !WARNED } { - warn!( - "Shared interrupt {} for {} requested but not auto enabled", - irq.data(), - action_guard.name() - ); + #[inline(never)] + fn __tmp_warn_shared_interrupt(irq: &IrqNumber, name: &str) { + warn!( + "Shared interrupt {} for {} requested but not auto enabled", + irq.data(), + name + ); + } + __tmp_warn_shared_interrupt(&irq, resp.action_guard.name()); unsafe { WARNED = true }; } - desc_inner_guard.set_depth(1); + resp.desc_inner_guard.set_depth(1); } - } else if action_guard.flags().trigger_type_specified() { - let new_trigger_type = action_guard.flags().trigger_type(); - let old_trigger_type = desc_inner_guard.common_data().trigger_type(); + } else if resp.action_guard.flags().trigger_type_specified() { + let new_trigger_type = resp.action_guard.flags().trigger_type(); + let old_trigger_type = resp.desc_inner_guard.common_data().trigger_type(); if new_trigger_type != old_trigger_type { - warn!("Irq {} uses trigger type: {old_trigger_type:?}, but requested trigger type: {new_trigger_type:?}.", irq.data()); + #[inline(never)] + fn ___tmp_log_irq_line_status_change( + old_trigger_type: IrqLineStatus, + new_trigger_type: IrqLineStatus, + irq: &IrqNumber, + ) { + warn!("Irq {} uses trigger type: {old_trigger_type:?}, but requested trigger type: {new_trigger_type:?}.", irq.data()); + } + + ___tmp_log_irq_line_status_change(old_trigger_type, new_trigger_type, &irq); } } // 在队列末尾添加新的irqaction - desc_inner_guard.add_action(action.clone()); + resp.desc_inner_guard.add_action(action.clone()); // 检查我们是否曾经通过虚构的中断处理程序禁用过irq。重新启用它并再给它一次机会。 - if irq_shared - && desc_inner_guard + if resp.irq_shared + && resp + .desc_inner_guard .internal_state() .contains(IrqDescState::IRQS_SPURIOUS_DISABLED) { - desc_inner_guard + resp.desc_inner_guard .internal_state_mut() .remove(IrqDescState::IRQS_SPURIOUS_DISABLED); - self.do_enable_irq(desc.clone(), &mut desc_inner_guard).ok(); + self.do_enable_irq(desc.clone(), &mut resp.desc_inner_guard) + .ok(); } - drop(desc_inner_guard); + drop(resp.desc_inner_guard); desc.chip_bus_sync_unlock(); - drop(req_mutex_guard); + drop(resp.req_mutex_guard); - drop(action_guard); - self.wake_up_and_wait_for_irq_thread_ready(&desc, Some(action.clone())); - self.wake_up_and_wait_for_irq_thread_ready(&desc, action.inner().secondary()); - return Ok(()); + drop(resp.action_guard); + self.wake_up_and_wait_for_irq_thread_ready(desc, Some(action.clone())); + self.wake_up_and_wait_for_irq_thread_ready(desc, action.inner().secondary()); + Ok(()) + } + + #[inline(never)] + fn inner_setup_irq( + &self, + irq: IrqNumber, + action: Arc, + desc: Arc, + ) -> Result<(), SystemError> { + if Arc::ptr_eq( + &desc.irq_data().chip_info_read_irqsave().chip(), + &no_irq_chip(), + ) { + return Err(SystemError::ENOSYS); + } + let action_guard = action.inner(); + + let action_guard = self.prepare_irq_setup(action_guard, irq, &desc)?; + let resp: SetupIrqResourcesResp<'_> = self.setup_irq_resources(action_guard, irq, &desc)?; + + self.activate_irq_line(irq, &desc, action.clone(), resp) } /// 唤醒中断线程并等待中断线程准备好 @@ -638,6 +750,7 @@ impl IrqManager { self.irq_startup(desc, desc_inner_guard, resend, Self::IRQ_START_FORCE) } + #[inline(never)] pub(super) fn irq_activate( &self, _desc: &Arc, @@ -1144,3 +1257,10 @@ impl IrqHandler for IrqNestedPrimaryHandler { return Ok(IrqReturn::NotHandled); } } + +struct SetupIrqResourcesResp<'a> { + action_guard: SpinLockGuard<'a, InnerIrqAction>, + irq_shared: bool, + desc_inner_guard: SpinLockGuard<'a, InnerIrqDesc>, + req_mutex_guard: MutexGuard<'a, ()>, +} diff --git a/kernel/src/exception/softirq.rs b/kernel/src/exception/softirq.rs index c67cc23b..3da151b3 100644 --- a/kernel/src/exception/softirq.rs +++ b/kernel/src/exception/softirq.rs @@ -28,11 +28,6 @@ const MAX_SOFTIRQ_RESTART: i32 = 20; static mut __CPU_PENDING: Option> = None; static mut __SORTIRQ_VECTORS: *mut Softirq = null_mut(); -#[no_mangle] -pub extern "C" fn rs_softirq_init() { - softirq_init().expect("softirq_init failed"); -} - #[inline(never)] pub fn softirq_init() -> Result<(), SystemError> { info!("Initializing softirq..."); diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index 92f602a2..bc19daf1 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -3,10 +3,10 @@ pub mod null_dev; pub mod zero_dev; use super::vfs::{ - core::{generate_inode_id, ROOT_INODE}, file::FileMode, syscall::ModeType, utils::DName, + vcore::{generate_inode_id, ROOT_INODE}, FilePrivateData, FileSystem, FileType, FsInfo, IndexNode, Magic, Metadata, SuperBlock, }; use crate::{ @@ -141,16 +141,21 @@ impl DevFS { .as_any_ref() .downcast_ref::() .unwrap(); - // 在 /dev/char 下创建设备节点 - dev_char_inode.add_dev(name, device.clone())?; // 特殊处理 tty 设备,挂载在 /dev 下 if name.starts_with("tty") && name.len() > 3 { dev_root_inode.add_dev(name, device.clone())?; - } - // ptmx设备 - if name == "ptmx" { + } else if name.starts_with("hvc") && name.len() > 3 { + // 特殊处理 hvc 设备,挂载在 /dev 下 dev_root_inode.add_dev(name, device.clone())?; + } else if name == "console" { + dev_root_inode.add_dev(name, device.clone())?; + } else if name == "ptmx" { + // ptmx设备 + dev_root_inode.add_dev(name, device.clone())?; + } else { + // 在 /dev/char 下创建设备节点 + dev_char_inode.add_dev(name, device.clone())?; } device.set_fs(dev_char_inode.0.lock().fs.clone()); } @@ -279,6 +284,7 @@ impl DevFSInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: dev_type_, // 文件夹 mode, nlinks: 1, @@ -370,6 +376,7 @@ impl LockedDevFSInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type, mode, nlinks: 1, @@ -526,6 +533,7 @@ impl IndexNode for LockedDevFSInode { inode.metadata.atime = metadata.atime; inode.metadata.mtime = metadata.mtime; inode.metadata.ctime = metadata.ctime; + inode.metadata.btime = metadata.btime; inode.metadata.mode = metadata.mode; inode.metadata.uid = metadata.uid; inode.metadata.gid = metadata.gid; diff --git a/kernel/src/filesystem/devfs/null_dev.rs b/kernel/src/filesystem/devfs/null_dev.rs index 0b050031..71f45aab 100644 --- a/kernel/src/filesystem/devfs/null_dev.rs +++ b/kernel/src/filesystem/devfs/null_dev.rs @@ -2,7 +2,7 @@ use crate::driver::base::device::device_number::DeviceNumber; use crate::filesystem::vfs::file::FileMode; use crate::filesystem::vfs::syscall::ModeType; use crate::filesystem::vfs::{ - core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, + vcore::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, }; use crate::libs::spinlock::SpinLockGuard; use crate::{libs::spinlock::SpinLock, time::PosixTimeSpec}; @@ -45,6 +45,7 @@ impl LockedNullInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::CharDevice, // 文件夹,block设备,char设备 mode: ModeType::from_bits_truncate(0o666), nlinks: 1, @@ -101,6 +102,7 @@ impl IndexNode for LockedNullInode { inode.metadata.atime = metadata.atime; inode.metadata.mtime = metadata.mtime; inode.metadata.ctime = metadata.ctime; + inode.metadata.btime = metadata.btime; inode.metadata.mode = metadata.mode; inode.metadata.uid = metadata.uid; inode.metadata.gid = metadata.gid; diff --git a/kernel/src/filesystem/devfs/zero_dev.rs b/kernel/src/filesystem/devfs/zero_dev.rs index 0a74b586..b19af347 100644 --- a/kernel/src/filesystem/devfs/zero_dev.rs +++ b/kernel/src/filesystem/devfs/zero_dev.rs @@ -2,7 +2,7 @@ use crate::driver::base::device::device_number::DeviceNumber; use crate::filesystem::vfs::file::FileMode; use crate::filesystem::vfs::syscall::ModeType; use crate::filesystem::vfs::{ - core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, + vcore::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, }; use crate::libs::spinlock::SpinLockGuard; use crate::{libs::spinlock::SpinLock, time::PosixTimeSpec}; @@ -45,6 +45,7 @@ impl LockedZeroInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::CharDevice, // 文件夹,block设备,char设备 mode: ModeType::from_bits_truncate(0o666), nlinks: 1, @@ -101,6 +102,7 @@ impl IndexNode for LockedZeroInode { inode.metadata.atime = metadata.atime; inode.metadata.mtime = metadata.mtime; inode.metadata.ctime = metadata.ctime; + inode.metadata.btime = metadata.btime; inode.metadata.mode = metadata.mode; inode.metadata.uid = metadata.uid; inode.metadata.gid = metadata.gid; diff --git a/kernel/src/filesystem/devpts/mod.rs b/kernel/src/filesystem/devpts/mod.rs index dae03024..62e6c387 100644 --- a/kernel/src/filesystem/devpts/mod.rs +++ b/kernel/src/filesystem/devpts/mod.rs @@ -22,14 +22,14 @@ use crate::{ tty_device::{PtyType, TtyDevice, TtyType}, }, }, - filesystem::vfs::{core::do_mount_mkdir, syscall::ModeType, FileType}, + filesystem::vfs::{syscall::ModeType, vcore::do_mount_mkdir, FileType}, init::initcall::INITCALL_FS, libs::spinlock::{SpinLock, SpinLockGuard}, time::PosixTimeSpec, }; use super::vfs::{ - core::generate_inode_id, FilePrivateData, FileSystem, FsInfo, IndexNode, Metadata, + vcore::generate_inode_id, FilePrivateData, FileSystem, FsInfo, IndexNode, Metadata, }; const DEV_PTYFS_MAX_NAMELEN: usize = 16; @@ -109,6 +109,7 @@ impl LockedDevPtsFSInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::Dir, mode: ModeType::from_bits_truncate(0o777), nlinks: 1, diff --git a/kernel/src/net/event_poll/mod.rs b/kernel/src/filesystem/epoll/event_poll.rs similarity index 68% rename from kernel/src/net/event_poll/mod.rs rename to kernel/src/filesystem/epoll/event_poll.rs index 2536d11b..e53e0591 100644 --- a/kernel/src/net/event_poll/mod.rs +++ b/kernel/src/filesystem/epoll/event_poll.rs @@ -1,25 +1,15 @@ use core::{ - any::Any, fmt::Debug, sync::atomic::{AtomicBool, Ordering}, }; -use alloc::{ - collections::LinkedList, - sync::{Arc, Weak}, - vec::Vec, -}; -use intertrait::CastFromSync; -use system_error::SystemError; - use crate::{ filesystem::vfs::{ file::{File, FileMode}, - FilePrivateData, IndexNode, Metadata, + FilePrivateData, }, libs::{ rbtree::RBTree, - rwlock::RwLock, spinlock::{SpinLock, SpinLockGuard}, wait_queue::WaitQueue, }, @@ -31,10 +21,14 @@ use crate::{ }, }; -pub mod syscall; +use alloc::{ + collections::LinkedList, + sync::{Arc, Weak}, + vec::Vec, +}; +use system_error::SystemError; -#[derive(Debug, Clone)] -pub struct LockedEventPoll(Arc>); +use super::{fs::EPollInode, EPollCtlOption, EPollEvent, EPollEventType, EPollItem}; /// 内核的Epoll对象结构体,当用户创建一个Epoll时,内核就会创建一个该类型对象 /// 它对应一个epfd @@ -51,147 +45,6 @@ pub struct EventPoll { self_ref: Option>>, } -/// EpollItem表示的是Epoll所真正管理的对象 -/// 每当用户向Epoll添加描述符时都会注册一个新的EpollItem,EpollItem携带了一些被监听的描述符的必要信息 -#[derive(Debug)] -pub struct EPollItem { - /// 对应的Epoll - epoll: Weak>, - /// 用户注册的事件 - event: RwLock, - /// 监听的描述符 - fd: i32, - /// 对应的文件 - file: Weak, -} - -impl EPollItem { - pub fn new( - epoll: Weak>, - events: EPollEvent, - fd: i32, - file: Weak, - ) -> Self { - Self { - epoll, - event: RwLock::new(events), - fd, - file, - } - } - - pub fn epoll(&self) -> Weak> { - self.epoll.clone() - } - - pub fn event(&self) -> &RwLock { - &self.event - } - - pub fn file(&self) -> Weak { - self.file.clone() - } - - pub fn fd(&self) -> i32 { - self.fd - } - - /// ## 通过epoll_item来执行绑定文件的poll方法,并获取到感兴趣的事件 - fn ep_item_poll(&self) -> EPollEventType { - let file = self.file.upgrade(); - if file.is_none() { - return EPollEventType::empty(); - } - if let Ok(events) = file.unwrap().poll() { - let events = events as u32 & self.event.read().events; - return EPollEventType::from_bits_truncate(events); - } - return EPollEventType::empty(); - } -} - -pub trait KernelIoctlData: Send + Sync + Any + Debug + CastFromSync {} - -impl KernelIoctlData for EPollItem {} - -/// ### Epoll文件的私有信息 -#[derive(Debug, Clone)] -pub struct EPollPrivateData { - epoll: LockedEventPoll, -} - -/// ### 该结构体将Epoll加入文件系统 -#[derive(Debug)] -pub struct EPollInode { - epoll: LockedEventPoll, -} - -impl EPollInode { - pub fn new(epoll: LockedEventPoll) -> Arc { - Arc::new(Self { epoll }) - } -} - -impl IndexNode for EPollInode { - fn read_at( - &self, - _offset: usize, - _len: usize, - _buf: &mut [u8], - _data: SpinLockGuard, - ) -> Result { - Err(SystemError::ENOSYS) - } - - fn write_at( - &self, - _offset: usize, - _len: usize, - _buf: &[u8], - _data: SpinLockGuard, - ) -> Result { - Err(SystemError::ENOSYS) - } - - fn poll(&self, _private_data: &FilePrivateData) -> Result { - // 需要实现epoll嵌套epoll时,需要实现这里 - todo!() - } - - fn fs(&self) -> Arc { - todo!() - } - - fn as_any_ref(&self) -> &dyn core::any::Any { - self - } - - fn list(&self) -> Result, SystemError> { - Err(SystemError::ENOSYS) - } - - fn metadata(&self) -> Result { - Ok(Metadata::default()) - } - - fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { - // 释放资源 - let mut epoll = self.epoll.0.lock_irqsave(); - - epoll.close()?; - - Ok(()) - } - - fn open( - &self, - _data: SpinLockGuard, - _mode: &FileMode, - ) -> Result<(), SystemError> { - Ok(()) - } -} - impl EventPoll { pub const EP_MAX_EVENTS: u32 = u32::MAX / (core::mem::size_of::() as u32); /// 用于获取inode中的epitem队列 @@ -207,7 +60,7 @@ impl EventPoll { } /// 关闭epoll时,执行的逻辑 - fn close(&mut self) -> Result<(), SystemError> { + pub(super) fn close(&mut self) -> Result<(), SystemError> { // 唤醒epoll上面等待的所有进程 self.shutdown.store(true, Ordering::SeqCst); self.ep_wake_all(); @@ -221,9 +74,8 @@ impl EventPoll { .get_file_by_fd(fd); if let Some(file) = file { - if let Some(self_ref) = self.self_ref.as_ref() { - file.remove_epoll(self_ref)?; - } + let epitm = self.ep_items.get(&fd).unwrap(); + file.remove_epitem(epitm)?; } self.ep_items.remove(&fd); @@ -352,7 +204,7 @@ impl EventPoll { } } - let ep_item = epoll_guard.ep_items.get(&dstfd); + let ep_item = epoll_guard.ep_items.get(&dstfd).cloned(); match op { EPollCtlOption::Add => { // 如果已经存在,则返回错误 @@ -369,12 +221,16 @@ impl EventPoll { Self::ep_insert(&mut epoll_guard, dst_file, epitem)?; } EPollCtlOption::Del => { - // 不存在则返回错误 - if ep_item.is_none() { - return Err(SystemError::ENOENT); + match ep_item { + Some(ref ep_item) => { + // 删除 + Self::ep_remove(&mut epoll_guard, dstfd, Some(dst_file), ep_item)?; + } + None => { + // 不存在则返回错误 + return Err(SystemError::ENOENT); + } } - // 删除 - Self::ep_remove(&mut epoll_guard, dstfd, Some(dst_file))?; } EPollCtlOption::Mod => { // 不存在则返回错误 @@ -487,7 +343,7 @@ impl EventPoll { } } else if timespec.is_none() { // 非阻塞情况 - timeout = true; + timeout = false; } // 判断epoll上有没有就绪事件 let mut available = epoll_guard.ep_events_available(); @@ -531,8 +387,10 @@ impl EventPoll { continue; } - // 如果有未处理的信号则返回错误 - if current_pcb.has_pending_signal_fast() { + // 如果有未处理且未被屏蔽的信号则返回错误 + if current_pcb.has_pending_signal_fast() + && current_pcb.has_pending_not_masked_signal() + { return Err(SystemError::ERESTARTSYS); } @@ -698,7 +556,7 @@ impl EventPoll { return Err(SystemError::ENOSYS); } - dst_file.add_epoll(epitem.clone())?; + dst_file.add_epitem(epitem.clone())?; Ok(()) } @@ -706,9 +564,10 @@ impl EventPoll { epoll: &mut SpinLockGuard, fd: i32, dst_file: Option>, + epitem: &Arc, ) -> Result<(), SystemError> { if let Some(dst_file) = dst_file { - dst_file.remove_epoll(epoll.self_ref.as_ref().unwrap())?; + dst_file.remove_epitem(epitem)?; } if let Some(epitem) = epoll.ep_items.remove(&fd) { @@ -780,171 +639,48 @@ impl EventPoll { /// ### epoll的回调,支持epoll的文件有事件到来时直接调用该方法即可 pub fn wakeup_epoll( epitems: &SpinLock>>, - pollflags: Option, + pollflags: EPollEventType, ) -> Result<(), SystemError> { - let mut epitems_guard = epitems.try_lock_irqsave()?; - // 一次只取一个,因为一次也只有一个进程能拿到对应文件的🔓 - if let Some(epitem) = epitems_guard.pop_front() { - let pollflags = pollflags.unwrap_or({ - if let Some(file) = epitem.file.upgrade() { - EPollEventType::from_bits_truncate(file.poll()? as u32) - } else { - EPollEventType::empty() - } - }); + let epitems_guard = epitems.try_lock_irqsave()?; + for epitem in epitems_guard.iter() { + // The upgrade is safe because EventPoll always exists when the epitem is in the list + let epoll = epitem.epoll().upgrade().unwrap(); + let mut epoll_guard = epoll.try_lock()?; + let binding = epitem.clone(); + let event_guard = binding.event().read(); + let ep_events = EPollEventType::from_bits_truncate(event_guard.events()); + // 检查事件合理性以及是否有感兴趣的事件 + if !(ep_events + .difference(EPollEventType::EP_PRIVATE_BITS) + .is_empty() + || pollflags.difference(ep_events).is_empty()) + { + // TODO: 未处理pm相关 - if let Some(epoll) = epitem.epoll().upgrade() { - let mut epoll_guard = epoll.try_lock()?; - let binding = epitem.clone(); - let event_guard = binding.event().read(); - let ep_events = EPollEventType::from_bits_truncate(event_guard.events()); - // 检查事件合理性以及是否有感兴趣的事件 - if !(ep_events - .difference(EPollEventType::EP_PRIVATE_BITS) - .is_empty() - || pollflags.difference(ep_events).is_empty()) - { - // TODO: 未处理pm相关 + // 首先将就绪的epitem加入等待队列 + epoll_guard.ep_add_ready(epitem.clone()); - // 首先将就绪的epitem加入等待队列 - epoll_guard.ep_add_ready(epitem.clone()); - - if epoll_guard.ep_has_waiter() { - if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE) - && !pollflags.contains(EPollEventType::POLLFREE) - { - // 避免惊群 - epoll_guard.ep_wake_one(); - } else { - epoll_guard.ep_wake_all(); - } + if epoll_guard.ep_has_waiter() { + if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE) + && !pollflags.contains(EPollEventType::POLLFREE) + { + // 避免惊群 + epoll_guard.ep_wake_one(); + } else { + epoll_guard.ep_wake_all(); } } - - epitems_guard.push_back(epitem); } } Ok(()) } } -/// 与C兼容的Epoll事件结构体 -#[derive(Copy, Clone, Default)] -#[repr(packed)] -#[repr(C)] -pub struct EPollEvent { - /// 表示触发的事件 - events: u32, - /// 内核态不使用该字段,该字段由用户态自由使用,在事件发生时内核将会原样返回 - data: u64, -} - -impl Debug for EPollEvent { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let events = self.events; - let u64 = self.data; - f.debug_struct("epoll_event") - .field("events", &events) - .field("data", &u64) - .finish() - } -} - -impl EPollEvent { - pub fn set_events(&mut self, events: u32) { - self.events = events; - } - - pub fn events(&self) -> u32 { - self.events - } -} - -/// ## epoll_ctl函数的参数 -#[derive(Debug, PartialEq)] -pub enum EPollCtlOption { - /// 注册新的文件描述符到epfd - Add, - /// 将对应的文件描述符从epfd中删除 - Del, - /// 修改已经注册的文件描述符的监听事件 - Mod, -} - -impl EPollCtlOption { - pub fn from_op_num(op: usize) -> Result { - match op { - 1 => Ok(Self::Add), - 2 => Ok(Self::Del), - 3 => Ok(Self::Mod), - _ => Err(SystemError::EINVAL), - } - } -} - -bitflags! { - #[allow(dead_code)] - pub struct EPollEventType: u32 { - /// 对应的描述符有新的数据可读时会触发 - const EPOLLIN = 0x00000001; - /// 对应的描述符有紧急数据可读时会触发 - const EPOLLPRI = 0x00000002; - /// 对应的描述符可以写入数据时会触发 - const EPOLLOUT = 0x00000004; - /// 对应的描述符发生错误时会触发 - const EPOLLERR = 0x00000008; - /// 对应的描述符被挂断(连接关闭)时会触发 - const EPOLLHUP = 0x00000010; - /// 对应的描述符不是一个有效的文件描述符时会触发 - const EPOLLNVAL = 0x00000020; - /// 普通数据可读,类似于`EPOLLIN` - const EPOLLRDNORM = 0x00000040; - /// 优先级带外数据可读 - const EPOLLRDBAND = 0x00000080; - /// 普通数据可写,类似于'EPOLLOUT' - const EPOLLWRNORM = 0x00000100; - /// 优先级带外数据可写 - const EPOLLWRBAND = 0x00000200; - /// 通过消息队列收到消息时会触 - const EPOLLMSG = 0x00000400; - /// 对应的描述符被挂断(连接关闭)的一端发送了 FIN 时会触发(读关闭) - const EPOLLRDHUP = 0x00002000; - - /// 以下为额外选项 - /// - /// 特定选项,用于异步 I/O,目前未实现 - const EPOLL_URING_WAKE = 1u32 << 27; - /// 设置epoll为独占模式 - const EPOLLEXCLUSIVE = 1u32 << 28; - /// 允许在系统挂起时唤醒 epoll,通常用于通过 eventfd 或 timerfd 唤醒 epoll,(通常与电源管理相关,未实现) - const EPOLLWAKEUP = 1u32 << 29; - /// 表示只监听一次事件,之后需要重新添加 - const EPOLLONESHOT = 1u32 << 30; - - /// 启用边缘触发模式(即只有下次触发事件时才会通过epoll_wait返回), - /// 对应为水平触发(默认),水平触发模式下若这次未处理完数据,那epoll还会将其加入自己的就绪队列 - const EPOLLET = 1u32 << 31; - - /// 以下为组合码 - const EPOLLINOUT_BITS = Self::EPOLLIN.bits | Self::EPOLLOUT.bits; - const EPOLLEXCLUSIVE_OK_BITS = - Self::EPOLLINOUT_BITS.bits - | Self::EPOLLERR.bits - | Self::EPOLLHUP.bits - | Self::EPOLLWAKEUP.bits - | Self::EPOLLET.bits - | Self::EPOLLEXCLUSIVE.bits; - - const EP_PRIVATE_BITS = - Self::EPOLLWAKEUP.bits - | Self::EPOLLONESHOT.bits - | Self::EPOLLET.bits - | Self::EPOLLEXCLUSIVE.bits; - - /// 表示epoll已经被释放,但是在目前的设计中未用到 - const POLLFREE = 0x4000; - - /// listen状态的socket可以接受连接 - const EPOLL_LISTEN_CAN_ACCEPT = Self::EPOLLIN.bits | Self::EPOLLRDNORM.bits; - } +#[derive(Debug, Clone)] +pub struct LockedEventPoll(pub(super) Arc>); + +/// ### Epoll文件的私有信息 +#[derive(Debug, Clone)] +pub struct EPollPrivateData { + pub(super) epoll: LockedEventPoll, } diff --git a/kernel/src/filesystem/epoll/fs.rs b/kernel/src/filesystem/epoll/fs.rs new file mode 100644 index 00000000..f19e3052 --- /dev/null +++ b/kernel/src/filesystem/epoll/fs.rs @@ -0,0 +1,77 @@ +use crate::{ + filesystem::vfs::{file::FileMode, FilePrivateData, IndexNode, Metadata}, + libs::spinlock::SpinLockGuard, +}; + +use alloc::sync::Arc; +use alloc::vec::Vec; +use system_error::SystemError; + +use super::event_poll::LockedEventPoll; + +/// ### 该结构体将Epoll加入文件系统 +#[derive(Debug)] +pub struct EPollInode { + pub epoll: LockedEventPoll, +} + +impl EPollInode { + pub fn new(epoll: LockedEventPoll) -> Arc { + Arc::new(Self { epoll }) + } +} + +impl IndexNode for EPollInode { + fn read_at( + &self, + _offset: usize, + _len: usize, + _buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn fs(&self) -> Arc { + todo!() + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn list(&self) -> Result, SystemError> { + Err(SystemError::ENOSYS) + } + + fn metadata(&self) -> Result { + Ok(Metadata::default()) + } + + fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { + // 释放资源 + let mut epoll = self.epoll.0.lock_irqsave(); + + epoll.close()?; + + Ok(()) + } + + fn open( + &self, + _data: SpinLockGuard, + _mode: &FileMode, + ) -> Result<(), SystemError> { + Ok(()) + } +} diff --git a/kernel/src/filesystem/epoll/mod.rs b/kernel/src/filesystem/epoll/mod.rs new file mode 100644 index 00000000..c581c847 --- /dev/null +++ b/kernel/src/filesystem/epoll/mod.rs @@ -0,0 +1,197 @@ +use super::vfs::file::File; +use crate::libs::{rwlock::RwLock, spinlock::SpinLock}; +use alloc::sync::Weak; +use core::fmt::Debug; +use event_poll::EventPoll; +use system_error::SystemError; + +pub mod event_poll; +pub mod fs; + +/// 与C兼容的Epoll事件结构体 +#[derive(Copy, Clone, Default)] +#[repr(packed)] +#[repr(C)] +pub struct EPollEvent { + /// 表示触发的事件 + events: u32, + /// 内核态不使用该字段,该字段由用户态自由使用,在事件发生时内核将会原样返回 + data: u64, +} + +impl Debug for EPollEvent { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let events = self.events; + let u64 = self.data; + f.debug_struct("epoll_event") + .field("events", &events) + .field("data", &u64) + .finish() + } +} + +impl EPollEvent { + pub fn set_events(&mut self, events: u32) { + self.events = events; + } + + pub fn events(&self) -> u32 { + self.events + } + + pub fn set_data(&mut self, data: u64) { + self.data = data; + } + + pub fn data(&self) -> u64 { + self.data + } +} + +/// EpollItem表示的是Epoll所真正管理的对象 +/// 每当用户向Epoll添加描述符时都会注册一个新的EpollItem,EpollItem携带了一些被监听的描述符的必要信息 +#[derive(Debug)] +pub struct EPollItem { + /// 对应的Epoll + epoll: Weak>, + /// 用户注册的事件 + event: RwLock, + /// 监听的描述符 + fd: i32, + /// 对应的文件 + file: Weak, +} + +impl EPollItem { + pub fn new( + epoll: Weak>, + events: EPollEvent, + fd: i32, + file: Weak, + ) -> Self { + Self { + epoll, + event: RwLock::new(events), + fd, + file, + } + } + + pub fn epoll(&self) -> Weak> { + self.epoll.clone() + } + + pub fn event(&self) -> &RwLock { + &self.event + } + + pub fn file(&self) -> Weak { + self.file.clone() + } + + pub fn fd(&self) -> i32 { + self.fd + } + + /// ## 通过epoll_item来执行绑定文件的poll方法,并获取到感兴趣的事件 + fn ep_item_poll(&self) -> EPollEventType { + let file = self.file.upgrade(); + if file.is_none() { + return EPollEventType::empty(); + } + if let Ok(events) = file.unwrap().poll() { + let events = events as u32 & self.event.read().events; + return EPollEventType::from_bits_truncate(events); + } + return EPollEventType::empty(); + } +} + +/// ## epoll_ctl函数的参数 +#[derive(Debug, PartialEq)] +pub enum EPollCtlOption { + /// 注册新的文件描述符到epfd + Add, + /// 将对应的文件描述符从epfd中删除 + Del, + /// 修改已经注册的文件描述符的监听事件 + Mod, +} + +impl EPollCtlOption { + pub fn from_op_num(op: usize) -> Result { + match op { + 1 => Ok(Self::Add), + 2 => Ok(Self::Del), + 3 => Ok(Self::Mod), + _ => Err(SystemError::EINVAL), + } + } +} + +bitflags! { + #[allow(dead_code)] + pub struct EPollEventType: u32 { + /// 对应的描述符有新的数据可读时会触发 + const EPOLLIN = 0x00000001; + /// 对应的描述符有紧急数据可读时会触发 + const EPOLLPRI = 0x00000002; + /// 对应的描述符可以写入数据时会触发 + const EPOLLOUT = 0x00000004; + /// 对应的描述符发生错误时会触发 + const EPOLLERR = 0x00000008; + /// 对应的描述符被挂断(连接关闭)时会触发 + const EPOLLHUP = 0x00000010; + /// 对应的描述符不是一个有效的文件描述符时会触发 + const EPOLLNVAL = 0x00000020; + /// 普通数据可读,类似于`EPOLLIN` + const EPOLLRDNORM = 0x00000040; + /// 优先级带外数据可读 + const EPOLLRDBAND = 0x00000080; + /// 普通数据可写,类似于'EPOLLOUT' + const EPOLLWRNORM = 0x00000100; + /// 优先级带外数据可写 + const EPOLLWRBAND = 0x00000200; + /// 通过消息队列收到消息时会触 + const EPOLLMSG = 0x00000400; + /// 对应的描述符被挂断(连接关闭)的一端发送了 FIN 时会触发(读关闭) + const EPOLLRDHUP = 0x00002000; + + /// 以下为额外选项 + /// + /// 特定选项,用于异步 I/O,目前未实现 + const EPOLL_URING_WAKE = 1u32 << 27; + /// 设置epoll为独占模式 + const EPOLLEXCLUSIVE = 1u32 << 28; + /// 允许在系统挂起时唤醒 epoll,通常用于通过 eventfd 或 timerfd 唤醒 epoll,(通常与电源管理相关,未实现) + const EPOLLWAKEUP = 1u32 << 29; + /// 表示只监听一次事件,之后需要重新添加 + const EPOLLONESHOT = 1u32 << 30; + + /// 启用边缘触发模式(即只有下次触发事件时才会通过epoll_wait返回), + /// 对应为水平触发(默认),水平触发模式下若这次未处理完数据,那epoll还会将其加入自己的就绪队列 + const EPOLLET = 1u32 << 31; + + /// 以下为组合码 + const EPOLLINOUT_BITS = Self::EPOLLIN.bits | Self::EPOLLOUT.bits; + const EPOLLEXCLUSIVE_OK_BITS = + Self::EPOLLINOUT_BITS.bits + | Self::EPOLLERR.bits + | Self::EPOLLHUP.bits + | Self::EPOLLWAKEUP.bits + | Self::EPOLLET.bits + | Self::EPOLLEXCLUSIVE.bits; + + const EP_PRIVATE_BITS = + Self::EPOLLWAKEUP.bits + | Self::EPOLLONESHOT.bits + | Self::EPOLLET.bits + | Self::EPOLLEXCLUSIVE.bits; + + /// 表示epoll已经被释放,但是在目前的设计中未用到 + const POLLFREE = 0x4000; + + /// listen状态的socket可以接受连接 + const EPOLL_LISTEN_CAN_ACCEPT = Self::EPOLLIN.bits | Self::EPOLLRDNORM.bits; + } +} diff --git a/kernel/src/filesystem/eventfd.rs b/kernel/src/filesystem/eventfd.rs index ecce149b..e318d226 100644 --- a/kernel/src/filesystem/eventfd.rs +++ b/kernel/src/filesystem/eventfd.rs @@ -1,16 +1,18 @@ +use super::vfs::PollableInode; use crate::filesystem::vfs::file::{File, FileMode}; use crate::filesystem::vfs::syscall::ModeType; -use crate::filesystem::vfs::{FilePrivateData, FileSystem, FileType, IndexNode, Metadata}; +use crate::filesystem::{ + epoll::{event_poll::EventPoll, EPollEventType, EPollItem}, + vfs::{FilePrivateData, FileSystem, FileType, IndexNode, Metadata}, +}; use crate::libs::spinlock::{SpinLock, SpinLockGuard}; use crate::libs::wait_queue::WaitQueue; -use crate::net::event_poll::{EPollEventType, EPollItem, EventPoll, KernelIoctlData}; use crate::process::{ProcessFlags, ProcessManager}; use crate::sched::SchedMode; use crate::syscall::Syscall; use alloc::collections::LinkedList; use alloc::string::String; use alloc::sync::Arc; -use alloc::sync::Weak; use alloc::vec::Vec; use core::any::Any; use ida::IdAllocator; @@ -63,21 +65,6 @@ impl EventFdInode { epitems: SpinLock::new(LinkedList::new()), } } - pub fn remove_epoll(&self, epoll: &Weak>) -> Result<(), SystemError> { - let is_remove = !self - .epitems - .lock_irqsave() - .extract_if(|x| x.epoll().ptr_eq(epoll)) - .collect::>() - .is_empty(); - - if is_remove { - return Ok(()); - } - - Err(SystemError::ENOENT) - } - fn readable(&self) -> bool { let count = self.eventfd.lock().count; return count > 0; @@ -99,6 +86,36 @@ impl EventFdInode { } } +impl PollableInode for EventFdInode { + fn poll(&self, _private_data: &FilePrivateData) -> Result { + let self_guard = self.eventfd.lock(); + self.do_poll(_private_data, &self_guard) + } + + fn add_epitem( + &self, + epitem: Arc, + _private_data: &FilePrivateData, + ) -> Result<(), SystemError> { + self.epitems.lock().push_back(epitem); + Ok(()) + } + + fn remove_epitem( + &self, + epitem: &Arc, + _private_data: &FilePrivateData, + ) -> Result<(), SystemError> { + let mut guard = self.epitems.lock(); + let len = guard.len(); + guard.retain(|x| !Arc::ptr_eq(x, epitem)); + if len != guard.len() { + return Ok(()); + } + Err(SystemError::ENOENT) + } +} + impl IndexNode for EventFdInode { fn open( &self, @@ -171,7 +188,7 @@ impl IndexNode for EventFdInode { drop(eventfd); // 唤醒epoll中等待的进程 - EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; + EventPoll::wakeup_epoll(&self.epitems, pollflag)?; return Ok(8); } @@ -225,19 +242,10 @@ impl IndexNode for EventFdInode { drop(eventfd); // 唤醒epoll中等待的进程 - EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; + EventPoll::wakeup_epoll(&self.epitems, pollflag)?; return Ok(8); } - /// # 检查 eventfd 的状态 - /// - /// - 如果 counter 的值大于 0 ,那么 fd 的状态就是可读的 - /// - 如果能无阻塞地写入一个至少为 1 的值,那么 fd 的状态就是可写的 - fn poll(&self, _private_data: &FilePrivateData) -> Result { - let self_guard = self.eventfd.lock(); - self.do_poll(_private_data, &self_guard) - } - fn metadata(&self) -> Result { let meta = Metadata { mode: ModeType::from_bits_truncate(0o755), @@ -250,27 +258,22 @@ impl IndexNode for EventFdInode { fn resize(&self, _len: usize) -> Result<(), SystemError> { Ok(()) } - fn kernel_ioctl( - &self, - arg: Arc, - _data: &FilePrivateData, - ) -> Result { - let epitem = arg - .arc_any() - .downcast::() - .map_err(|_| SystemError::EFAULT)?; - self.epitems.lock().push_back(epitem); - Ok(0) - } + fn fs(&self) -> Arc { panic!("EventFd does not have a filesystem") } + fn as_any_ref(&self) -> &dyn Any { self } + fn list(&self) -> Result, SystemError> { Err(SystemError::EINVAL) } + + fn as_pollable_inode(&self) -> Result<&dyn PollableInode, SystemError> { + Ok(self) + } } impl Syscall { diff --git a/kernel/src/filesystem/fat/fs.rs b/kernel/src/filesystem/fat/fs.rs index 88712c45..16682dc4 100644 --- a/kernel/src/filesystem/fat/fs.rs +++ b/kernel/src/filesystem/fat/fs.rs @@ -23,9 +23,9 @@ use crate::mm::VmFaultReason; use crate::{ driver::base::block::{block_device::LBA_SIZE, disk_info::Partition, SeekFrom}, filesystem::vfs::{ - core::generate_inode_id, file::{FileMode, FilePrivateData}, syscall::ModeType, + vcore::generate_inode_id, FileSystem, FileType, IndexNode, InodeId, Metadata, }, libs::{ @@ -227,6 +227,7 @@ impl LockedFATInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type, mode: ModeType::from_bits_truncate(0o777), nlinks: 1, @@ -250,6 +251,83 @@ impl LockedFATInode { return inode; } + + #[inline(never)] + fn rename_file_in_current_dir( + &self, + old_name: &str, + new_name: &str, + ) -> Result<(), SystemError> { + let mut guard = self.0.lock(); + let old_inode: Arc = guard.find(old_name)?; + // 对目标inode上锁,以防更改 + let old_inode_guard: SpinLockGuard = old_inode.0.lock(); + let fs = old_inode_guard.fs.upgrade().unwrap(); + // 从缓存删除 + let old_dir = match &guard.inode_type { + FATDirEntry::File(_) | FATDirEntry::VolId(_) => { + return Err(SystemError::ENOTDIR); + } + FATDirEntry::Dir(d) => d, + FATDirEntry::UnInit => { + error!("FATFS: param: Inode_type uninitialized."); + return Err(SystemError::EROFS); + } + }; + // 检查文件是否存在 + // old_dir.check_existence(old_name, Some(false), guard.fs.upgrade().unwrap())?; + + old_dir.rename(fs, old_name, new_name)?; + let _nod = guard.children.remove(&to_search_name(old_name)); + Ok(()) + } + + #[inline(never)] + fn move_to_another_dir( + &self, + old_name: &str, + new_name: &str, + target: &Arc, + ) -> Result<(), SystemError> { + let mut old_guard = self.0.lock(); + let other: &LockedFATInode = target + .downcast_ref::() + .ok_or(SystemError::EPERM)?; + + let new_guard = other.0.lock(); + let old_inode: Arc = old_guard.find(old_name)?; + // 对目标inode上锁,以防更改 + let old_inode_guard: SpinLockGuard = old_inode.0.lock(); + let fs = old_inode_guard.fs.upgrade().unwrap(); + + let old_dir = match &old_guard.inode_type { + FATDirEntry::File(_) | FATDirEntry::VolId(_) => { + return Err(SystemError::ENOTDIR); + } + FATDirEntry::Dir(d) => d, + FATDirEntry::UnInit => { + error!("FATFS: param: Inode_type uninitialized."); + return Err(SystemError::EROFS); + } + }; + let new_dir = match &new_guard.inode_type { + FATDirEntry::File(_) | FATDirEntry::VolId(_) => { + return Err(SystemError::ENOTDIR); + } + FATDirEntry::Dir(d) => d, + FATDirEntry::UnInit => { + error!("FATFA: param: Inode_type uninitialized."); + return Err(SystemError::EROFS); + } + }; + // 检查文件是否存在 + old_dir.check_existence(old_name, Some(false), old_guard.fs.upgrade().unwrap())?; + old_dir.rename_across(fs, new_dir, old_name, new_name)?; + // 从缓存删除 + let _nod = old_guard.children.remove(&to_search_name(old_name)); + + Ok(()) + } } /// FsInfo结构体(内存中的一份拷贝,当卸载卷或者sync的时候,把它写入磁盘) @@ -377,6 +455,7 @@ impl FATFileSystem { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::Dir, mode: ModeType::from_bits_truncate(0o777), nlinks: 1, @@ -1450,7 +1529,6 @@ impl IndexNode for LockedFATInode { let page_cache = self.0.lock().page_cache.clone(); if let Some(page_cache) = page_cache { let r = page_cache.lock_irqsave().read(offset, &mut buf[0..len]); - // self.0.lock_irqsave().update_metadata(); return r; } else { return self.read_direct(offset, len, buf, data); @@ -1761,64 +1839,9 @@ impl IndexNode for LockedFATInode { let new_id = target.metadata().unwrap().inode_id; // 若在同一父目录下 if old_id == new_id { - let mut guard = self.0.lock(); - let old_inode: Arc = guard.find(old_name)?; - // 对目标inode上锁,以防更改 - let old_inode_guard: SpinLockGuard = old_inode.0.lock(); - let fs = old_inode_guard.fs.upgrade().unwrap(); - // 从缓存删除 - let old_dir = match &guard.inode_type { - FATDirEntry::File(_) | FATDirEntry::VolId(_) => { - return Err(SystemError::ENOTDIR); - } - FATDirEntry::Dir(d) => d, - FATDirEntry::UnInit => { - error!("FATFS: param: Inode_type uninitialized."); - return Err(SystemError::EROFS); - } - }; - // 检查文件是否存在 - // old_dir.check_existence(old_name, Some(false), guard.fs.upgrade().unwrap())?; - - old_dir.rename(fs, old_name, new_name)?; - let _nod = guard.children.remove(&to_search_name(old_name)); + self.rename_file_in_current_dir(old_name, new_name)?; } else { - let mut old_guard = self.0.lock(); - let other: &LockedFATInode = target - .downcast_ref::() - .ok_or(SystemError::EPERM)?; - - let new_guard = other.0.lock(); - let old_inode: Arc = old_guard.find(old_name)?; - // 对目标inode上锁,以防更改 - let old_inode_guard: SpinLockGuard = old_inode.0.lock(); - let fs = old_inode_guard.fs.upgrade().unwrap(); - - let old_dir = match &old_guard.inode_type { - FATDirEntry::File(_) | FATDirEntry::VolId(_) => { - return Err(SystemError::ENOTDIR); - } - FATDirEntry::Dir(d) => d, - FATDirEntry::UnInit => { - error!("FATFS: param: Inode_type uninitialized."); - return Err(SystemError::EROFS); - } - }; - let new_dir = match &new_guard.inode_type { - FATDirEntry::File(_) | FATDirEntry::VolId(_) => { - return Err(SystemError::ENOTDIR); - } - FATDirEntry::Dir(d) => d, - FATDirEntry::UnInit => { - error!("FATFA: param: Inode_type uninitialized."); - return Err(SystemError::EROFS); - } - }; - // 检查文件是否存在 - old_dir.check_existence(old_name, Some(false), old_guard.fs.upgrade().unwrap())?; - old_dir.rename_across(fs, new_dir, old_name, new_name)?; - // 从缓存删除 - let _nod = old_guard.children.remove(&to_search_name(old_name)); + self.move_to_another_dir(old_name, new_name, target)?; } return Ok(()); diff --git a/kernel/src/filesystem/kernfs/callback.rs b/kernel/src/filesystem/kernfs/callback.rs index 563893c6..db1c96e6 100644 --- a/kernel/src/filesystem/kernfs/callback.rs +++ b/kernel/src/filesystem/kernfs/callback.rs @@ -1,3 +1,5 @@ +use super::KernFSInode; +use crate::tracepoint::{TracePipeSnapshot, TracePointInfo}; use crate::{ filesystem::{sysfs::SysFSKernPrivateData, vfs::PollStatus}, libs::spinlock::SpinLockGuard, @@ -6,8 +8,6 @@ use alloc::sync::Arc; use core::fmt::Debug; use system_error::SystemError; -use super::KernFSInode; - /// KernFS文件的回调接口 /// /// 当用户态程序打开、读取、写入、关闭文件时,kernfs会调用相应的回调函数。 @@ -86,24 +86,24 @@ impl<'a> KernCallbackData<'a> { #[derive(Debug)] pub enum KernInodePrivateData { SysFS(SysFSKernPrivateData), + DebugFS(Arc), + TracePipe(TracePipeSnapshot), } impl KernInodePrivateData { #[inline(always)] pub fn callback_read(&self, buf: &mut [u8], offset: usize) -> Result { - match self { - KernInodePrivateData::SysFS(private_data) => { - return private_data.callback_read(buf, offset); - } - } + return match self { + KernInodePrivateData::SysFS(private_data) => private_data.callback_read(buf, offset), + _ => Err(SystemError::ENOSYS), + }; } #[inline(always)] pub fn callback_write(&self, buf: &[u8], offset: usize) -> Result { - match self { - KernInodePrivateData::SysFS(private_data) => { - return private_data.callback_write(buf, offset); - } - } + return match self { + KernInodePrivateData::SysFS(private_data) => private_data.callback_write(buf, offset), + _ => Err(SystemError::ENOSYS), + }; } } diff --git a/kernel/src/filesystem/kernfs/mod.rs b/kernel/src/filesystem/kernfs/mod.rs index 91765e57..a8eeedd9 100644 --- a/kernel/src/filesystem/kernfs/mod.rs +++ b/kernel/src/filesystem/kernfs/mod.rs @@ -1,3 +1,4 @@ +use alloc::string::ToString; use core::{cmp::min, fmt::Debug, intrinsics::unlikely}; use alloc::{ @@ -22,7 +23,7 @@ use crate::{ use self::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData}; use super::vfs::{ - core::generate_inode_id, file::FileMode, syscall::ModeType, FilePrivateData, FileSystem, + file::FileMode, syscall::ModeType, vcore::generate_inode_id, FilePrivateData, FileSystem, FileType, FsInfo, IndexNode, InodeId, Magic, Metadata, SuperBlock, }; @@ -94,6 +95,7 @@ impl KernFS { atime: PosixTimeSpec::new(0, 0), mtime: PosixTimeSpec::new(0, 0), ctime: PosixTimeSpec::new(0, 0), + btime: PosixTimeSpec::new(0, 0), dev_id: 0, inode_id: generate_inode_id(), file_type: FileType::Dir, @@ -114,6 +116,7 @@ impl KernFS { callback: None, children: SpinLock::new(HashMap::new()), inode_type: KernInodeType::Dir, + lazy_list: SpinLock::new(HashMap::new()), }); return root_inode; @@ -137,6 +140,16 @@ pub struct KernFSInode { inode_type: KernInodeType, /// Inode名称 name: String, + /// lazy list + lazy_list: SpinLock KernFSInodeArgs>>, +} + +pub struct KernFSInodeArgs { + pub mode: ModeType, + pub inode_type: KernInodeType, + pub size: Option, + pub private_data: Option, + pub callback: Option<&'static dyn KernFSCallback>, } #[derive(Debug)] @@ -244,12 +257,25 @@ impl IndexNode for KernFSInode { } name => { // 在子目录项中查找 - return Ok(self - .children - .lock() - .get(name) - .ok_or(SystemError::ENOENT)? - .clone()); + let child = self.children.lock().get(name).cloned(); + if let Some(child) = child { + return Ok(child); + } + let lazy_list = self.lazy_list.lock(); + if let Some(provider) = lazy_list.get(name) { + // 如果存在lazy list,则调用提供者函数创建 + let args = provider(); + let inode = self.inner_create( + name.to_string(), + args.inode_type, + args.mode, + args.size.unwrap_or(4096), + args.private_data, + args.callback, + )?; + return Ok(inode); + } + Err(SystemError::ENOENT) } } } @@ -320,7 +346,7 @@ impl IndexNode for KernFSInode { offset: usize, len: usize, buf: &mut [u8], - _data: SpinLockGuard, + data: SpinLockGuard, ) -> Result { if self.inode_type == KernInodeType::SymLink { let inner = self.inner.read(); @@ -349,6 +375,8 @@ impl IndexNode for KernFSInode { warn!("kernfs: callback is none"); return Err(SystemError::ENOSYS); } + // release the private data lock before calling the callback + drop(data); let callback_data = KernCallbackData::new(self.self_ref.upgrade().unwrap(), self.private_data.lock()); @@ -364,7 +392,7 @@ impl IndexNode for KernFSInode { offset: usize, len: usize, buf: &[u8], - _data: SpinLockGuard, + data: SpinLockGuard, ) -> Result { if self.inode_type != KernInodeType::File { return Err(SystemError::EISDIR); @@ -374,6 +402,9 @@ impl IndexNode for KernFSInode { return Err(SystemError::ENOSYS); } + // release the private data lock before calling the callback + drop(data); + let callback_data = KernCallbackData::new(self.self_ref.upgrade().unwrap(), self.private_data.lock()); return self @@ -410,6 +441,7 @@ impl KernFSInode { callback, children: SpinLock::new(HashMap::new()), inode_type, + lazy_list: SpinLock::new(HashMap::new()), }); { @@ -499,6 +531,18 @@ impl KernFSInode { ); } + pub fn add_file_lazy( + &self, + name: String, + provider: fn() -> KernFSInodeArgs, + ) -> Result<(), SystemError> { + if unlikely(self.inode_type != KernInodeType::Dir) { + return Err(SystemError::ENOTDIR); + } + self.lazy_list.lock().insert(name, provider); + Ok(()) + } + fn inner_create( &self, name: String, @@ -525,6 +569,7 @@ impl KernFSInode { atime: PosixTimeSpec::new(0, 0), mtime: PosixTimeSpec::new(0, 0), ctime: PosixTimeSpec::new(0, 0), + btime: PosixTimeSpec::new(0, 0), dev_id: 0, inode_id: generate_inode_id(), file_type: file_type.into(), diff --git a/kernel/src/filesystem/mbr.rs b/kernel/src/filesystem/mbr.rs index 9cf6eedd..f44b801b 100644 --- a/kernel/src/filesystem/mbr.rs +++ b/kernel/src/filesystem/mbr.rs @@ -4,7 +4,6 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; -use log::debug; use system_error::SystemError; use crate::{ @@ -106,7 +105,7 @@ impl MbrDiskPartionTable { table.dpte[i].starting_lba = cursor.read_u32()?; table.dpte[i].total_sectors = cursor.read_u32()?; - debug!("dpte[{i}] = {:?}", table.dpte[i]); + // debug!("dpte[{i}] = {:?}", table.dpte[i]); } table.bs_trailsig = cursor.read_u16()?; // debug!("bs_trailsig = {}", unsafe { diff --git a/kernel/src/filesystem/mod.rs b/kernel/src/filesystem/mod.rs index 8bd94989..2b9e836b 100644 --- a/kernel/src/filesystem/mod.rs +++ b/kernel/src/filesystem/mod.rs @@ -1,5 +1,6 @@ pub mod devfs; pub mod devpts; +pub mod epoll; pub mod eventfd; pub mod fat; pub mod kernfs; diff --git a/kernel/src/filesystem/page_cache.rs b/kernel/src/filesystem/page_cache.rs index 7f595933..c5902a02 100644 --- a/kernel/src/filesystem/page_cache.rs +++ b/kernel/src/filesystem/page_cache.rs @@ -1,4 +1,7 @@ -use core::cmp::min; +use core::{ + cmp::min, + sync::atomic::{AtomicUsize, Ordering}, +}; use alloc::{ sync::{Arc, Weak}, @@ -21,22 +24,27 @@ use crate::{ }; use crate::{libs::align::page_align_up, mm::page::PageType}; +static PAGE_CACHE_ID: AtomicUsize = AtomicUsize::new(0); /// 页面缓存 #[derive(Debug)] pub struct PageCache { + id: usize, inner: SpinLock, inode: Lazy>, } #[derive(Debug)] pub struct InnerPageCache { + #[allow(unused)] + id: usize, pages: HashMap>, page_cache_ref: Weak, } impl InnerPageCache { - pub fn new(page_cache_ref: Weak) -> InnerPageCache { + pub fn new(page_cache_ref: Weak, id: usize) -> InnerPageCache { Self { + id, pages: HashMap::new(), page_cache_ref, } @@ -105,13 +113,14 @@ impl InnerPageCache { /// - `Ok(usize)` 成功读取的长度 /// - `Err(SystemError)` 失败返回错误码 pub fn read(&mut self, offset: usize, buf: &mut [u8]) -> Result { - let inode = self + let inode: Arc = self .page_cache_ref .upgrade() .unwrap() .inode .upgrade() .unwrap(); + let file_size = inode.metadata().unwrap().size; let len = if offset < file_size as usize { @@ -174,6 +183,7 @@ impl InnerPageCache { for (page_index, count) in not_exist { // TODO 这里使用buffer避免多次读取磁盘,将来引入异步IO直接写入页面,减少内存开销和拷贝 let mut page_buf = vec![0u8; MMArch::PAGE_SIZE * count]; + inode.read_sync(page_index * MMArch::PAGE_SIZE, page_buf.as_mut())?; self.create_pages(page_index, page_buf.as_mut())?; @@ -306,7 +316,7 @@ impl InnerPageCache { impl Drop for InnerPageCache { fn drop(&mut self) { - log::debug!("page cache drop"); + // log::debug!("page cache drop"); let mut page_manager = page_manager_lock_irqsave(); for page in self.pages.values() { page_manager.remove_page(&page.phys_address()); @@ -316,8 +326,10 @@ impl Drop for InnerPageCache { impl PageCache { pub fn new(inode: Option>) -> Arc { + let id = PAGE_CACHE_ID.fetch_add(1, Ordering::SeqCst); Arc::new_cyclic(|weak| Self { - inner: SpinLock::new(InnerPageCache::new(weak.clone())), + id, + inner: SpinLock::new(InnerPageCache::new(weak.clone(), id)), inode: { let v: Lazy> = Lazy::new(); if let Some(inode) = inode { @@ -328,6 +340,13 @@ impl PageCache { }) } + /// # 获取页缓存的ID + #[inline] + #[allow(unused)] + pub fn id(&self) -> usize { + self.id + } + pub fn inode(&self) -> Option> { self.inode.try_get().cloned() } @@ -341,6 +360,13 @@ impl PageCache { } pub fn lock_irqsave(&self) -> SpinLockGuard { + if self.inner.is_locked() { + log::error!("page cache already locked"); + } self.inner.lock_irqsave() } + + pub fn is_locked(&self) -> bool { + self.inner.is_locked() + } } diff --git a/kernel/src/filesystem/poll.rs b/kernel/src/filesystem/poll.rs index e5a96d9a..6e77e731 100644 --- a/kernel/src/filesystem/poll.rs +++ b/kernel/src/filesystem/poll.rs @@ -1,12 +1,18 @@ use core::ffi::c_int; use crate::{ - ipc::signal::{RestartBlock, RestartBlockData, RestartFn}, + arch::ipc::signal::SigSet, + filesystem::epoll::{event_poll::EventPoll, EPollCtlOption, EPollEvent, EPollEventType}, + ipc::signal::{ + restore_saved_sigmask_unless, set_user_sigmask, RestartBlock, RestartBlockData, RestartFn, + }, mm::VirtAddr, - net::event_poll::{EPollCtlOption, EPollEvent, EPollEventType, EventPoll}, process::ProcessManager, - syscall::{user_access::UserBufferWriter, Syscall}, - time::{Duration, Instant}, + syscall::{ + user_access::{UserBufferReader, UserBufferWriter}, + Syscall, + }, + time::{Duration, Instant, PosixTimeSpec}, }; use super::vfs::file::{File, FileMode}; @@ -32,11 +38,15 @@ impl<'a> PollAdapter<'a> { } fn add_pollfds(&self) -> Result<(), SystemError> { - for pollfd in self.poll_fds.iter() { + for (i, pollfd) in self.poll_fds.iter().enumerate() { + if pollfd.fd < 0 { + continue; + } let mut epoll_event = EPollEvent::default(); let poll_flags = PollFlags::from_bits_truncate(pollfd.events); let ep_events: EPollEventType = poll_flags.into(); epoll_event.set_events(ep_events.bits()); + epoll_event.set_data(i as u64); EventPoll::epoll_ctl_with_epfile( self.ep_file.clone(), @@ -54,9 +64,11 @@ impl<'a> PollAdapter<'a> { fn poll_all_fds(&mut self, timeout: Option) -> Result { let mut epoll_events = vec![EPollEvent::default(); self.poll_fds.len()]; let len = epoll_events.len() as i32; - let remain_timeout = timeout - .and_then(|t| t.duration_since(Instant::now())) - .map(|t| t.into()); + let remain_timeout = timeout.map(|t| { + t.duration_since(Instant::now()) + .unwrap_or(Duration::ZERO) + .into() + }); let events = EventPoll::epoll_wait_with_file( self.ep_file.clone(), &mut epoll_events, @@ -64,8 +76,13 @@ impl<'a> PollAdapter<'a> { remain_timeout, )?; - for (i, event) in epoll_events.iter().enumerate() { - self.poll_fds[i].revents = (event.events() & 0xffff) as u16; + for event in epoll_events.iter() { + let index = event.data() as usize; + if index >= self.poll_fds.len() { + log::warn!("poll_all_fds: Invalid index in epoll event: {}", index); + continue; + } + self.poll_fds[index].revents = (event.events() & 0xffff) as u16; } Ok(events) @@ -74,13 +91,14 @@ impl<'a> PollAdapter<'a> { impl Syscall { /// https://code.dragonos.org.cn/xref/linux-6.6.21/fs/select.c#1068 + #[inline(never)] pub fn poll(pollfd_ptr: usize, nfds: u32, timeout_ms: i32) -> Result { let pollfd_ptr = VirtAddr::new(pollfd_ptr); let len = nfds as usize * core::mem::size_of::(); let mut timeout: Option = None; if timeout_ms >= 0 { - timeout = poll_select_set_timeout(timeout_ms); + timeout = poll_select_set_timeout(timeout_ms as u64); } let mut poll_fds_writer = UserBufferWriter::new(pollfd_ptr.as_ptr::(), len, true)?; let mut r = do_sys_poll(poll_fds_writer.buffer(0)?, timeout); @@ -92,15 +110,58 @@ impl Syscall { return r; } -} -/// 计算超时的时刻 -fn poll_select_set_timeout(timeout_ms: i32) -> Option { - if timeout_ms == 0 { - return None; + /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/select.c#1101 + #[inline(never)] + pub fn ppoll( + pollfd_ptr: usize, + nfds: u32, + timespec_ptr: usize, + sigmask_ptr: usize, + ) -> Result { + let mut timeout_ts: Option = None; + let mut sigmask: Option = None; + let pollfd_ptr = VirtAddr::new(pollfd_ptr); + let pollfds_len = nfds as usize * core::mem::size_of::(); + let mut poll_fds_writer = + UserBufferWriter::new(pollfd_ptr.as_ptr::(), pollfds_len, true)?; + let poll_fds = poll_fds_writer.buffer(0)?; + if sigmask_ptr != 0 { + let sigmask_reader = + UserBufferReader::new(sigmask_ptr as *const SigSet, size_of::(), true)?; + sigmask = Some(*sigmask_reader.read_one_from_user(0)?); + } + + if timespec_ptr != 0 { + let tsreader = UserBufferReader::new( + timespec_ptr as *const PosixTimeSpec, + size_of::(), + true, + )?; + let ts: PosixTimeSpec = *tsreader.read_one_from_user(0)?; + let timeout_ms = ts.tv_sec * 1000 + ts.tv_nsec / 1_000_000; + + if timeout_ms >= 0 { + timeout_ts = + Some(poll_select_set_timeout(timeout_ms as u64).ok_or(SystemError::EINVAL)?); + } + } + + if let Some(mut sigmask) = sigmask { + set_user_sigmask(&mut sigmask); + } + // log::debug!( + // "ppoll: poll_fds: {:?}, nfds: {}, timeout_ts: {:?},sigmask: {:?}", + // poll_fds, + // nfds, + // timeout_ts, + // sigmask + // ); + + let r: Result = do_sys_poll(poll_fds, timeout_ts); + + return poll_select_finish(timeout_ts, timespec_ptr, PollTimeType::TimeSpec, r); } - - Some(Instant::now() + Duration::from_millis(timeout_ms as u64)) } fn do_sys_poll(poll_fds: &mut [PollFd], timeout: Option) -> Result { @@ -115,6 +176,71 @@ fn do_sys_poll(poll_fds: &mut [PollFd], timeout: Option) -> Result Option { + Some(Instant::now() + Duration::from_millis(timeout_ms)) +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/select.c#298 +fn poll_select_finish( + end_time: Option, + user_time_ptr: usize, + poll_time_type: PollTimeType, + mut result: Result, +) -> Result { + restore_saved_sigmask_unless(result == Err(SystemError::ERESTARTNOHAND)); + + if user_time_ptr == 0 { + return result; + } + + // todo: 处理sticky timeouts + + if end_time.is_none() { + return result; + } + + let end_time = end_time.unwrap(); + + // no update for zero timeout + if end_time.total_millis() <= 0 { + return result; + } + + let ts = Instant::now(); + let duration = end_time.saturating_sub(ts); + let rts: PosixTimeSpec = duration.into(); + + match poll_time_type { + PollTimeType::TimeSpec => { + let mut tswriter = UserBufferWriter::new( + user_time_ptr as *mut PosixTimeSpec, + size_of::(), + true, + )?; + if tswriter.copy_one_to_user(&rts, 0).is_err() { + return result; + } + } + _ => todo!(), + } + + if result == Err(SystemError::ERESTARTNOHAND) { + result = result.map_err(|_| SystemError::EINTR); + } + + return result; +} + +#[allow(unused)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum PollTimeType { + TimeVal, + OldTimeVal, + TimeSpec, + OldTimeSpec, +} + bitflags! { pub struct PollFlags: u16 { const POLLIN = 0x0001; diff --git a/kernel/src/filesystem/procfs/mod.rs b/kernel/src/filesystem/procfs/mod.rs index 3c131032..3e7fd479 100644 --- a/kernel/src/filesystem/procfs/mod.rs +++ b/kernel/src/filesystem/procfs/mod.rs @@ -15,7 +15,7 @@ use crate::{ arch::mm::LockedFrameAllocator, driver::base::device::device_number::DeviceNumber, filesystem::vfs::{ - core::{generate_inode_id, ROOT_INODE}, + vcore::{generate_inode_id, ROOT_INODE}, FileType, }, libs::{ @@ -50,6 +50,8 @@ pub enum ProcFileType { ProcMeminfo = 1, /// kmsg ProcKmsg = 2, + /// 可执行路径 + ProcExe = 3, //todo: 其他文件类型 ///默认文件类型 Default, @@ -61,6 +63,7 @@ impl From for ProcFileType { 0 => ProcFileType::ProcStatus, 1 => ProcFileType::ProcMeminfo, 2 => ProcFileType::ProcKmsg, + 3 => ProcFileType::ProcExe, _ => ProcFileType::Default, } } @@ -266,6 +269,28 @@ impl ProcFSInode { return Ok((data.len() * size_of::()) as i64); } + // 打开 exe 文件 + fn open_exe(&self, _pdata: &mut ProcfsFilePrivateData) -> Result { + // 这个文件是一个软链接,直接返回0即可 + return Ok(0); + } + + // 读取exe文件 + fn read_link(&self, buf: &mut [u8]) -> Result { + // 判断是否有记录pid信息,有的话就是当前进程的exe文件,没有则是当前进程的exe文件 + let pid = self.fdata.pid; + let pcb = if pid == Pid::from(0) { + ProcessManager::current_pcb() + } else { + ProcessManager::find(pid).ok_or(SystemError::ESRCH)? + }; + let exe = pcb.execute_path(); + let exe_bytes = exe.as_bytes(); + let len = exe_bytes.len().min(buf.len()); + buf[..len].copy_from_slice(&exe_bytes[..len]); + Ok(len) + } + /// proc文件系统读取函数 fn proc_read( &self, @@ -336,6 +361,7 @@ impl ProcFS { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::Dir, mode: ModeType::from_bits_truncate(0o555), nlinks: 1, @@ -419,6 +445,23 @@ impl ProcFS { } else { panic!("create version_signature error"); } + + let self_dir = inode + .create("self", FileType::Dir, ModeType::from_bits_truncate(0o555)) + .unwrap(); + + let binding = self_dir.create("exe", FileType::SymLink, ModeType::S_IRUGO); + if let Ok(exe) = binding { + let exe_file = exe + .as_any_ref() + .downcast_ref::() + .unwrap(); + exe_file.0.lock().fdata.pid = Pid::new(0); + exe_file.0.lock().fdata.ftype = ProcFileType::ProcExe; + } else { + panic!("create exe error"); + } + return result; } @@ -435,18 +478,32 @@ impl ProcFS { )?; // 创建相关文件 // status文件 - let binding: Arc = pid_dir.create( + let status_binding: Arc = pid_dir.create( "status", FileType::File, ModeType::from_bits_truncate(0o444), )?; - let status_file: &LockedProcFSInode = binding + let status_file: &LockedProcFSInode = status_binding .as_any_ref() .downcast_ref::() .unwrap(); status_file.0.lock().fdata.pid = pid; status_file.0.lock().fdata.ftype = ProcFileType::ProcStatus; + // exe文件 + let exe_binding: Arc = pid_dir.create_with_data( + "exe", + FileType::SymLink, + ModeType::from_bits_truncate(0o444), + 0, + )?; + let exe_file = exe_binding + .as_any_ref() + .downcast_ref::() + .unwrap(); + exe_file.0.lock().fdata.pid = pid; + exe_file.0.lock().fdata.ftype = ProcFileType::ProcExe; + //todo: 创建其他文件 return Ok(()); @@ -461,6 +518,7 @@ impl ProcFS { let pid_dir: Arc = proc.find(&pid.to_string())?; // 删除进程文件夹下文件 pid_dir.unlink("status")?; + pid_dir.unlink("exe")?; // 查看进程文件是否还存在 // let pf= pid_dir.find("status").expect("Cannot find status"); @@ -490,6 +548,7 @@ impl IndexNode for LockedProcFSInode { let file_size = match inode.fdata.ftype { ProcFileType::ProcStatus => inode.open_status(&mut private_data)?, ProcFileType::ProcMeminfo => inode.open_meminfo(&mut private_data)?, + ProcFileType::ProcExe => inode.open_exe(&mut private_data)?, ProcFileType::Default => inode.data.len() as i64, _ => { todo!() @@ -548,6 +607,7 @@ impl IndexNode for LockedProcFSInode { ProcFileType::ProcMeminfo => { return inode.proc_read(offset, len, buf, &mut private_data) } + ProcFileType::ProcExe => return inode.read_link(buf), ProcFileType::ProcKmsg => (), ProcFileType::Default => (), }; @@ -597,6 +657,7 @@ impl IndexNode for LockedProcFSInode { inode.metadata.atime = metadata.atime; inode.metadata.mtime = metadata.mtime; inode.metadata.ctime = metadata.ctime; + inode.metadata.btime = metadata.btime; inode.metadata.mode = metadata.mode; inode.metadata.uid = metadata.uid; inode.metadata.gid = metadata.gid; @@ -649,6 +710,7 @@ impl IndexNode for LockedProcFSInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type, mode, nlinks: 1, diff --git a/kernel/src/filesystem/ramfs/mod.rs b/kernel/src/filesystem/ramfs/mod.rs index 61dddf34..40ae7fe0 100644 --- a/kernel/src/filesystem/ramfs/mod.rs +++ b/kernel/src/filesystem/ramfs/mod.rs @@ -5,7 +5,7 @@ use crate::filesystem::vfs::{FileSystemMakerData, FSMAKER}; use crate::libs::rwlock::RwLock; use crate::{ driver::base::device::device_number::DeviceNumber, - filesystem::vfs::{core::generate_inode_id, FileType}, + filesystem::vfs::{vcore::generate_inode_id, FileType}, ipc::pipe::LockedPipeInode, libs::casting::DowncastArc, libs::spinlock::{SpinLock, SpinLockGuard}, @@ -86,6 +86,7 @@ impl RamFSInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::Dir, mode: ModeType::from_bits_truncate(0o777), nlinks: 1, @@ -281,6 +282,7 @@ impl IndexNode for LockedRamFSInode { inode.metadata.atime = metadata.atime; inode.metadata.mtime = metadata.mtime; inode.metadata.ctime = metadata.ctime; + inode.metadata.btime = metadata.btime; inode.metadata.mode = metadata.mode; inode.metadata.uid = metadata.uid; inode.metadata.gid = metadata.gid; @@ -332,6 +334,7 @@ impl IndexNode for LockedRamFSInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type, mode, nlinks: 1, @@ -594,6 +597,7 @@ impl IndexNode for LockedRamFSInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::Pipe, mode, nlinks: 1, diff --git a/kernel/src/filesystem/vfs/fcntl.rs b/kernel/src/filesystem/vfs/fcntl.rs index 0c7b42d5..5d4985df 100644 --- a/kernel/src/filesystem/vfs/fcntl.rs +++ b/kernel/src/filesystem/vfs/fcntl.rs @@ -101,6 +101,8 @@ bitflags! { /// 应用于整个子树。 /// AT_RECURSIVE: 0x8000 const AT_RECURSIVE = 0x8000; + + const AT_GETATTR_NOSEC = i32::MIN; } } diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 66e76be5..4dbbb071 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -1,28 +1,22 @@ use core::sync::atomic::{AtomicUsize, Ordering}; -use alloc::{ - string::String, - sync::{Arc, Weak}, - vec::Vec, -}; +use alloc::{string::String, sync::Arc, vec::Vec}; use log::error; use system_error::SystemError; -use super::{Dirent, FileType, IndexNode, InodeId, Metadata, SpecialNodeData}; -use crate::filesystem::eventfd::EventFdInode; -use crate::perf::PerfEventInode; +use super::{FileType, IndexNode, InodeId, Metadata, SpecialNodeData}; use crate::{ driver::{ base::{block::SeekFrom, device::DevicePrivateData}, tty::tty_device::TtyFilePrivateData, }, - filesystem::procfs::ProcfsFilePrivateData, - ipc::pipe::{LockedPipeInode, PipeFsPrivateData}, - libs::{rwlock::RwLock, spinlock::SpinLock}, - net::{ - event_poll::{EPollItem, EPollPrivateData, EventPoll}, - socket::SocketInode, + filesystem::{ + epoll::{event_poll::EPollPrivateData, EPollItem}, + procfs::ProcfsFilePrivateData, + vfs::FilldirContext, }, + ipc::pipe::PipeFsPrivateData, + libs::{rwlock::RwLock, spinlock::SpinLock}, process::{cred::Cred, ProcessManager}, }; @@ -352,60 +346,49 @@ impl File { return Ok(()); } - /// @biref 充填dirent结构体 - /// @return 返回dirent结构体的大小 - pub fn readdir(&self, dirent: &mut Dirent) -> Result { + /// # 读取目录项 + /// + /// ## 参数 + /// - ctx 填充目录项的上下文 + pub fn read_dir(&self, ctx: &mut FilldirContext) -> Result<(), SystemError> { let inode: &Arc = &self.inode; - let mut readdir_subdirs_name = self.readdir_subdirs_name.lock(); - let offset = self.offset.load(Ordering::SeqCst); - // 如果偏移量为0 - if offset == 0 { - // 通过list更新readdir_subdirs_name - *readdir_subdirs_name = inode.list()?; - readdir_subdirs_name.sort(); - } - // debug!("sub_entries={sub_entries:?}"); + let mut current_pos = self.offset.load(Ordering::SeqCst); - // 已经读到末尾 - if offset == readdir_subdirs_name.len() { - self.offset.store(0, Ordering::SeqCst); - return Ok(0); - } - let name = &readdir_subdirs_name[offset]; - let sub_inode: Arc = match inode.find(name) { - Ok(i) => i, - Err(e) => { - error!( - "Readdir error: Failed to find sub inode:{name:?}, file={self:?}, error={e:?}" - ); - return Err(e); + // POSIX 标准要求readdir应该返回. 和 .. + // 但是观察到在现有的子目录中已经包含,不做处理也能正常返回. 和 .. 这里先不做处理 + + // 迭代读取目录项 + let readdir_subdirs_name = inode.list()?; + + let subdirs_name_len = readdir_subdirs_name.len(); + while current_pos < subdirs_name_len { + let name = &readdir_subdirs_name[current_pos]; + let sub_inode: Arc = match inode.find(name) { + Ok(i) => i, + Err(e) => { + error!("Readdir error: Failed to find sub inode"); + return Err(e); + } + }; + + let inode_metadata = sub_inode.metadata().unwrap(); + let entry_ino = inode_metadata.inode_id.into() as u64; + let entry_d_type = inode_metadata.file_type.get_file_type_num() as u8; + match ctx.fill_dir(name, current_pos, entry_ino, entry_d_type) { + Ok(_) => { + self.offset.fetch_add(1, Ordering::SeqCst); + current_pos += 1; + } + Err(SystemError::EINVAL) => { + return Ok(()); + } + Err(e) => { + ctx.error = Some(e.clone()); + return Err(e); + } } - }; - - let name_bytes: &[u8] = name.as_bytes(); - - // 根据posix的规定,dirent中的d_name是一个不定长的数组,因此需要unsafe来拷贝数据 - unsafe { - let ptr = &mut dirent.d_name as *mut u8; - - let buf: &mut [u8] = - ::core::slice::from_raw_parts_mut::<'static, u8>(ptr, name_bytes.len() + 1); - buf[0..name_bytes.len()].copy_from_slice(name_bytes); - buf[name_bytes.len()] = 0; } - - self.offset.fetch_add(1, Ordering::SeqCst); - dirent.d_ino = sub_inode.metadata().unwrap().inode_id.into() as u64; - dirent.d_type = sub_inode.metadata().unwrap().file_type.get_file_type_num() as u8; - - // 计算dirent结构体的大小 - let size = (name_bytes.len() + ::core::mem::size_of::() - - ::core::mem::size_of_val(&dirent.d_name)) as u64; - - dirent.d_reclen = size as u16; - dirent.d_off += dirent.d_reclen as i64; - - return Ok(size); + return Ok(()); } pub fn inode(&self) -> Arc { @@ -492,63 +475,26 @@ impl File { return Ok(()); } - /// ## 向该文件添加一个EPollItem对象 - /// - /// 在文件状态发生变化时,需要向epoll通知 - pub fn add_epoll(&self, epitem: Arc) -> Result<(), SystemError> { - match self.file_type { - FileType::Socket => { - let inode = self.inode.downcast_ref::().unwrap(); - // let mut socket = inode.inner(); - - inode.epoll_items().add(epitem); - return Ok(()); - } - FileType::Pipe => { - let inode = self.inode.downcast_ref::().unwrap(); - return inode.add_epoll(epitem); - } - _ => { - let r = self.inode.kernel_ioctl(epitem, &self.private_data.lock()); - if r.is_err() { - return Err(SystemError::ENOSYS); - } - - Ok(()) - } - } + /// Add an EPollItem to the file + pub fn add_epitem(&self, epitem: Arc) -> Result<(), SystemError> { + let private_data = self.private_data.lock(); + self.inode + .as_pollable_inode()? + .add_epitem(epitem, &private_data) } - /// ## 删除一个绑定的epoll - pub fn remove_epoll(&self, epoll: &Weak>) -> Result<(), SystemError> { - match self.file_type { - FileType::Socket => self - .inode - .downcast_ref::() - .unwrap() - .epoll_items() - .remove(epoll), - FileType::Pipe => { - let inode = self.inode.downcast_ref::().unwrap(); - inode.remove_epoll(epoll) - } - _ => { - let inode = self.inode.downcast_ref::(); - if let Some(inode) = inode { - return inode.remove_epoll(epoll); - } - - let inode = self - .inode - .downcast_ref::() - .ok_or(SystemError::ENOSYS)?; - return inode.remove_epoll(epoll); - } - } + /// Remove epitems associated with the epoll + pub fn remove_epitem(&self, epitem: &Arc) -> Result<(), SystemError> { + let private_data = self.private_data.lock(); + self.inode + .as_pollable_inode()? + .remove_epitem(epitem, &private_data) } + /// Poll the file for events pub fn poll(&self) -> Result { - self.inode.poll(&self.private_data.lock()) + let private_data = self.private_data.lock(); + self.inode.as_pollable_inode()?.poll(&private_data) } } diff --git a/kernel/src/filesystem/vfs/iov.rs b/kernel/src/filesystem/vfs/iov.rs new file mode 100644 index 00000000..5943e495 --- /dev/null +++ b/kernel/src/filesystem/vfs/iov.rs @@ -0,0 +1,149 @@ +use alloc::vec::Vec; +use system_error::SystemError; + +use crate::syscall::user_access::{UserBufferReader, UserBufferWriter}; +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct IoVec { + /// 缓冲区的起始地址 + pub iov_base: *mut u8, + /// 缓冲区的长度 + pub iov_len: usize, +} + +/// 用于存储多个来自用户空间的IoVec +/// +/// 由于目前内核中的文件系统还不支持分散读写,所以暂时只支持将用户空间的IoVec聚合成一个缓冲区,然后进行操作。 +/// TODO:支持分散读写 +#[derive(Debug)] +pub struct IoVecs(Vec); + +impl IoVecs { + /// 获取IoVecs中所有缓冲区的总长度 + #[inline(never)] + pub fn total_len(&self) -> usize { + self.0.iter().map(|x| x.iov_len).sum() + } + + /// Constructs `IoVecs` from an array of `IoVec` in userspace. + /// + /// # Arguments + /// + /// * `iov` - Pointer to the array of `IoVec` in userspace + /// * `iovcnt` - Number of `IoVec` elements in the array + /// * `readv` - Whether this is for the `readv` syscall (currently unused) + /// + /// # Returns + /// + /// Returns `Ok(IoVecs)` on success, or `Err(SystemError)` if any error occurs. + /// + /// # Safety + /// + /// This function is unsafe because it operates on raw pointers from userspace. + /// The caller must ensure: + /// - The pointer `iov` is valid and points to at least `iovcnt` valid `IoVec` structures + /// - The userspace memory is not modified during this operation + #[inline(never)] + pub unsafe fn from_user( + iov: *const IoVec, + iovcnt: usize, + _readv: bool, + ) -> Result { + let iovs_reader = UserBufferReader::new(iov, iovcnt * core::mem::size_of::(), true)?; + + // 将用户空间的IoVec转换为引用(注意:这里的引用是静态的,因为用户空间的IoVec不会被释放) + let iovs = iovs_reader.buffer::(0)?; + + let mut slices: Vec = Vec::with_capacity(iovs.len()); + + for iov in iovs.iter() { + if iov.iov_len == 0 { + continue; + } + + let _ = UserBufferWriter::new(iov.iov_base, iov.iov_len, true)?; + slices.push(*iov); + } + + return Ok(Self(slices)); + } + + /// Aggregates data from all IoVecs into a single buffer. + /// + /// This function reads data from each IoVec in sequence and combines them into + /// a single contiguous buffer. + /// + /// # Returns + /// + /// Returns a [`Vec`] containing all the data from the IoVecs. + /// + /// # Examples + /// + /// ```rust + /// let iovecs = IoVecs::from_user(/* ... */)?; + /// let buffer = iovecs.gather(); + /// ``` + pub fn gather(&self) -> Vec { + let mut buf = Vec::new(); + for slice in self.0.iter() { + let buf_reader = UserBufferReader::new(slice.iov_base, slice.iov_len, true).unwrap(); + let slice = buf_reader.buffer::(0).unwrap(); + buf.extend_from_slice(slice); + } + return buf; + } + + /// Scatters the given data into the IoVecs. + /// + /// This function writes data sequentially to each IoVec, splitting the input data + /// across multiple buffers as needed. If the input data is smaller than the total + /// capacity of the IoVecs, only the required amount of data will be written. + /// If the input data is larger than the total capacity, the excess data will be ignored. + /// + /// # Arguments + /// + /// * `data` - The data to be scattered across the IoVecs + /// + /// # Examples + /// + /// ```rust + /// let iovecs = IoVecs::from_user(/* ... */)?; + /// iovecs.scatter(&[1, 2, 3, 4, 5]); + /// ``` + pub fn scatter(&self, data: &[u8]) { + let mut data: &[u8] = data; + for slice in self.0.iter() { + let len = core::cmp::min(slice.iov_len, data.len()); + if len == 0 { + continue; + } + + let mut buf_writer = + UserBufferWriter::new(slice.iov_base, slice.iov_len, true).unwrap(); + let slice = buf_writer.buffer::(0).unwrap(); + + slice[..len].copy_from_slice(&data[..len]); + data = &data[len..]; + } + } + + /// Creates a buffer with capacity equal to the total length of all IoVecs. + /// + /// # Arguments + /// + /// * `set_len` - If true, sets the length of the returned Vec to the total length of all IoVecs. + /// If false, the returned Vec will have length 0 but capacity equal to the total length. + /// + /// # Returns + /// + /// A new [`Vec`] with capacity (and potentially length) equal to the total length of all IoVecs. + pub fn new_buf(&self, set_len: bool) -> Vec { + let total_len = self.total_len(); + let mut buf: Vec = Vec::with_capacity(total_len); + + if set_len { + buf.resize(total_len, 0); + } + return buf; + } +} diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index 50f61619..36bb7846 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -1,13 +1,16 @@ -pub mod core; pub mod fcntl; pub mod file; +pub mod iov; pub mod mount; pub mod open; +pub mod stat; pub mod syscall; pub mod utils; +pub mod vcore; use ::core::{any::Any, fmt::Debug, sync::atomic::AtomicUsize}; use alloc::{string::String, sync::Arc, vec::Vec}; +use derive_builder::Builder; use intertrait::CastFromSync; use system_error::SystemError; @@ -15,6 +18,7 @@ use crate::{ driver::base::{ block::block_device::BlockDevice, char::CharDevice, device::device_number::DeviceNumber, }, + filesystem::epoll::EPollItem, ipc::pipe::LockedPipeInode, libs::{ casting::DowncastArc, @@ -24,8 +28,8 @@ use crate::{ time::PosixTimeSpec, }; -use self::{core::generate_inode_id, file::FileMode, syscall::ModeType, utils::DName}; -pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS}; +use self::{file::FileMode, syscall::ModeType, utils::DName, vcore::generate_inode_id}; +pub use self::{file::FilePrivateData, mount::MountFS, vcore::ROOT_INODE}; use super::page_cache::PageCache; @@ -58,6 +62,22 @@ pub enum FileType { Socket, } +impl From for ModeType { + fn from(val: FileType) -> Self { + match val { + FileType::File => ModeType::S_IFREG, + FileType::Dir => ModeType::S_IFDIR, + FileType::BlockDevice => ModeType::S_IFBLK, + FileType::CharDevice => ModeType::S_IFCHR, + FileType::SymLink => ModeType::S_IFLNK, + FileType::Socket => ModeType::S_IFSOCK, + FileType::Pipe => ModeType::S_IFIFO, + FileType::KvmDevice => ModeType::S_IFCHR, + FileType::FramebufferDevice => ModeType::S_IFCHR, + } + } +} + #[allow(dead_code)] #[derive(Debug, Clone)] pub enum SpecialNodeData { @@ -121,6 +141,24 @@ bitflags! { } } +/// The pollable inode trait +pub trait PollableInode: Any + Sync + Send + Debug + CastFromSync { + /// Return the poll status of the inode + fn poll(&self, private_data: &FilePrivateData) -> Result; + /// Add an epoll item to the inode + fn add_epitem( + &self, + epitem: Arc, + private_data: &FilePrivateData, + ) -> Result<(), SystemError>; + /// Remove epitems associated with the epoll + fn remove_epitem( + &self, + epitm: &Arc, + private_data: &FilePrivateData, + ) -> Result<(), SystemError>; +} + pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync { fn mmap(&self, _start: usize, _len: usize, _offset: usize) -> Result<(), SystemError> { return Err(SystemError::ENOSYS); @@ -236,14 +274,6 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync { return Err(SystemError::ENOSYS); } - /// @brief 获取当前inode的状态。 - /// - /// @return PollStatus结构体 - fn poll(&self, _private_data: &FilePrivateData) -> Result { - // 若文件系统没有实现此方法,则返回“不支持” - return Err(SystemError::ENOSYS); - } - /// @brief 获取inode的元数据 /// /// @return 成功:Ok(inode的元数据) @@ -411,14 +441,6 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync { return Err(SystemError::ENOSYS); } - fn kernel_ioctl( - &self, - _arg: Arc, - _data: &FilePrivateData, - ) -> Result { - return Err(SystemError::ENOSYS); - } - /// @brief 获取inode所在的文件系统的指针 fn fs(&self) -> Arc; @@ -625,6 +647,13 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync { ); None } + + /// Transform the inode to a pollable inode + /// + /// If the inode is not pollable, return an error + fn as_pollable_inode(&self) -> Result<&dyn PollableInode, SystemError> { + Err(SystemError::ENOSYS) + } } impl DowncastArc for dyn IndexNode { @@ -771,9 +800,11 @@ impl dyn IndexNode { /// IndexNode的元数据 /// /// 对应Posix2008中的sys/stat.h中的定义 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Builder)] +#[builder(no_std, setter(into))] pub struct Metadata { /// 当前inode所在的文件系统的设备号 + /// todo:更改为DeviceNumber结构体 pub dev_id: usize, /// inode号 @@ -793,12 +824,15 @@ pub struct Metadata { /// inode最后一次被访问的时间 pub atime: PosixTimeSpec, - /// inode最后一次修改的时间 + /// inode的文件数据最后一次修改的时间 pub mtime: PosixTimeSpec, - /// inode的创建时间 + /// inode的元数据、权限或文件内容最后一次发生改变的时间 pub ctime: PosixTimeSpec, + /// inode的创建时间 + pub btime: PosixTimeSpec, + /// 文件类型 pub file_type: FileType, @@ -829,6 +863,7 @@ impl Default for Metadata { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::File, mode: ModeType::empty(), nlinks: 1, @@ -965,6 +1000,7 @@ impl Metadata { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type, mode, nlinks: 1, @@ -1037,3 +1073,75 @@ macro_rules! producefs { } define_filesystem_maker_slice!(FSMAKER); + +/// # 批量填充Dirent时的上下文Add commentMore actions +/// linux语义是通过getdents_callback *类型来实现类似链表的迭代填充,这里考虑通过填充传入的缓冲区来实现 +pub struct FilldirContext<'a> { + buf: &'a mut [u8], + current_pos: usize, + remain_size: usize, + error: Option, +} + +impl<'a> FilldirContext<'a> { + pub fn new(user_buf: &'a mut [u8]) -> Self { + Self { + remain_size: user_buf.len(), + buf: user_buf, + current_pos: 0, + error: None, + } + } + + /// # 填充单个dirent结构体 + /// + /// ## 参数 + /// - name 目录项名称 + /// - offset 当前目录项偏移量 + /// - ino 目录项的inode的inode_id + /// - d_type 目录项的inode的file_type_num + fn fill_dir( + &mut self, + name: &str, + offset: usize, + ino: u64, + d_type: u8, + ) -> Result<(), SystemError> { + let name_len = name.as_bytes().len(); + let dirent_size = ::core::mem::size_of::() - ::core::mem::size_of::(); + let reclen = name_len + dirent_size + 1; + + // 将reclen向上对齐usize大小 + let align_up = |len: usize, align: usize| -> usize { (len + align - 1) & !(align - 1) }; + let align_up_reclen = align_up(reclen, ::core::mem::size_of::()); + + // 当前缓冲区空间已不足,返回EINVAL + if align_up_reclen > self.remain_size { + self.error = Some(SystemError::EINVAL); + return Err(SystemError::EINVAL); + } + + // 获取剩余缓冲区 + let current_dirent_slice = &mut self.buf[self.current_pos..]; + let dirent = unsafe { (current_dirent_slice.as_mut_ptr() as *mut Dirent).as_mut() } + .ok_or(SystemError::EFAULT)?; + + // 填充dirent + dirent.d_ino = ino; + dirent.d_type = d_type; + dirent.d_reclen = align_up_reclen as u16; + dirent.d_off = offset as i64; + unsafe { + let ptr = &mut dirent.d_name as *mut u8; + let buf: &mut [u8] = + ::core::slice::from_raw_parts_mut::<'static, u8>(ptr, name_len + 1); + buf[0..name_len].copy_from_slice(name.as_bytes()); + buf[name_len] = 0; + } + + self.current_pos += align_up_reclen; + self.remain_size -= align_up_reclen; + + return Ok(()); + } +} diff --git a/kernel/src/filesystem/vfs/mount.rs b/kernel/src/filesystem/vfs/mount.rs index 35d221d8..732153b9 100644 --- a/kernel/src/filesystem/vfs/mount.rs +++ b/kernel/src/filesystem/vfs/mount.rs @@ -25,7 +25,7 @@ use crate::{ use super::{ file::FileMode, syscall::ModeType, utils::DName, FilePrivateData, FileSystem, FileType, - IndexNode, InodeId, Magic, SuperBlock, + IndexNode, InodeId, Magic, PollableInode, SuperBlock, }; const MOUNTFS_BLOCK_SIZE: u64 = 512; @@ -435,15 +435,6 @@ impl IndexNode for MountFSInode { return self.inner_inode.ioctl(cmd, data, private_data); } - #[inline] - fn kernel_ioctl( - &self, - arg: Arc, - data: &FilePrivateData, - ) -> Result { - return self.inner_inode.kernel_ioctl(arg, data); - } - #[inline] fn list(&self) -> Result, SystemError> { return self.inner_inode.list(); @@ -528,11 +519,6 @@ impl IndexNode for MountFSInode { self.inner_inode.special_node() } - #[inline] - fn poll(&self, private_data: &FilePrivateData) -> Result { - self.inner_inode.poll(private_data) - } - /// 若不支持,则调用第二种情况来从父目录获取文件名 /// # Performance /// 应尽可能引入DName, @@ -553,6 +539,10 @@ impl IndexNode for MountFSInode { fn page_cache(&self) -> Option> { self.inner_inode.page_cache() } + + fn as_pollable_inode(&self) -> Result<&dyn PollableInode, SystemError> { + self.inner_inode.as_pollable_inode() + } } impl FileSystem for MountFS { @@ -759,3 +749,18 @@ impl Debug for MountList { f.debug_map().entries(MOUNT_LIST().0.read().iter()).finish() } } + +/// 判断给定的inode是否为其所在文件系统的根inode +/// +/// ## 返回值 +/// +/// - `true`: 是根inode +/// - `false`: 不是根inode或者传入的inode不是MountFSInode类型,或者调用inode的metadata方法时报错了。 +pub fn is_mountpoint_root(inode: &Arc) -> bool { + let mnt_inode = inode.as_any_ref().downcast_ref::(); + if let Some(mnt) = mnt_inode { + return mnt.is_mountpoint_root().unwrap_or(false); + } + + return false; +} diff --git a/kernel/src/filesystem/vfs/open.rs b/kernel/src/filesystem/vfs/open.rs index fd6893e7..64a2f7b6 100644 --- a/kernel/src/filesystem/vfs/open.rs +++ b/kernel/src/filesystem/vfs/open.rs @@ -41,6 +41,7 @@ pub(super) fn do_faccessat( let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; let path = path.to_str().map_err(|_| SystemError::EINVAL)?; + // log::debug!("do_faccessat path: {:?}", path); let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; @@ -148,7 +149,7 @@ pub fn ksys_fchown(fd: i32, uid: usize, gid: usize) -> Result Result { - //debug!("open path: {}, how: {:?}", path, how); + // log::debug!("openat2: dirfd: {}, path: {}, how: {:?}",dirfd, path, how); let path = path.trim(); let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; diff --git a/kernel/src/filesystem/vfs/stat.rs b/kernel/src/filesystem/vfs/stat.rs new file mode 100644 index 00000000..87167170 --- /dev/null +++ b/kernel/src/filesystem/vfs/stat.rs @@ -0,0 +1,491 @@ +use system_error::SystemError; + +use crate::{ + arch::filesystem::stat::PosixStat, + driver::base::device::device_number::DeviceNumber, + filesystem::vfs::{mount::is_mountpoint_root, vcore::do_file_lookup_at}, + process::ProcessManager, + syscall::user_access::UserBufferWriter, + time::PosixTimeSpec, +}; +use alloc::sync::Arc; + +use super::{ + fcntl::AtFlags, + syscall::{ModeType, PosixStatx, PosixStatxMask, StxAttributes}, + IndexNode, +}; + +#[derive(Clone)] +pub struct KStat { + pub result_mask: PosixStatxMask, // What fields the user got + pub mode: ModeType, // umode_t + pub nlink: u32, + pub blksize: u32, // Preferred I/O size + pub attributes: StxAttributes, + pub attributes_mask: StxAttributes, + pub ino: u64, + pub dev: DeviceNumber, // dev_t + pub rdev: DeviceNumber, // dev_t + pub uid: u32, // kuid_t + pub gid: u32, // kgid_t + pub size: usize, // loff_t + pub atime: PosixTimeSpec, // struct timespec64 + pub mtime: PosixTimeSpec, // struct timespec64 + pub ctime: PosixTimeSpec, // struct timespec64 + pub btime: PosixTimeSpec, // File creation time + pub blocks: u64, + pub mnt_id: u64, + pub dio_mem_align: u32, + pub dio_offset_align: u32, +} + +impl Default for KStat { + fn default() -> Self { + Self { + result_mask: PosixStatxMask::empty(), + mode: ModeType::empty(), + nlink: Default::default(), + blksize: Default::default(), + attributes: StxAttributes::empty(), + attributes_mask: StxAttributes::empty(), + ino: Default::default(), + dev: Default::default(), + rdev: Default::default(), + uid: Default::default(), + gid: Default::default(), + size: Default::default(), + atime: Default::default(), + mtime: Default::default(), + ctime: Default::default(), + btime: Default::default(), + blocks: Default::default(), + mnt_id: Default::default(), + dio_mem_align: Default::default(), + dio_offset_align: Default::default(), + } + } +} + +bitflags! { + /// https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/namei.h?fi=LOOKUP_FOLLOW#21 + pub struct LookUpFlags: u32 { + /// follow links at the end + const FOLLOW = 0x0001; + /// require a directory + const DIRECTORY = 0x0002; + /// force terminal automount + const AUTOMOUNT = 0x0004; + /// accept empty path [user_... only] + const EMPTY = 0x4000; + /// follow mounts in the starting point + const DOWN = 0x8000; + /// follow mounts in the end + const MOUNTPOINT = 0x0080; + /// tell ->d_revalidate() to trust no cache + const REVAL = 0x0020; + /// RCU pathwalk mode; semi-internal + const RCU = 0x0040; + /// ... in open + const OPEN = 0x0100; + /// ... in object creation + const CREATE = 0x0200; + /// ... in exclusive creation + const EXCL = 0x0400; + /// ... in destination of rename() + const RENAME_TARGET = 0x0800; + /// internal use only + const PARENT = 0x0010; + /// No symlink crossing + const NO_SYMLINKS = 0x010000; + /// No nd_jump_link() crossing + const NO_MAGICLINKS = 0x020000; + /// No mountpoint crossing + const NO_XDEV = 0x040000; + /// No escaping from starting point + const BENEATH = 0x080000; + /// Treat dirfd as fs root + const IN_ROOT = 0x100000; + /// Only do cached lookup + const CACHED = 0x200000; + /// LOOKUP_* flags which do scope-related checks based on the dirfd. + const IS_SCOPED = LookUpFlags::BENEATH.bits | LookUpFlags::IN_ROOT.bits; + } +} + +impl From for LookUpFlags { + fn from(value: AtFlags) -> Self { + let mut lookup_flags = LookUpFlags::empty(); + + if !value.contains(AtFlags::AT_SYMLINK_NOFOLLOW) { + lookup_flags |= LookUpFlags::FOLLOW; + } + + if !value.contains(AtFlags::AT_NO_AUTOMOUNT) { + lookup_flags |= LookUpFlags::AUTOMOUNT; + } + + if value.contains(AtFlags::AT_EMPTY_PATH) { + lookup_flags |= LookUpFlags::EMPTY; + } + + lookup_flags + } +} + +/// https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#232 +#[inline(never)] +pub fn vfs_statx( + dfd: i32, + filename: &str, + flags: AtFlags, + request_mask: PosixStatxMask, +) -> Result { + let lookup_flags: LookUpFlags = flags.into(); + + // Validate flags - only allowed flags are AT_SYMLINK_NOFOLLOW, AT_NO_AUTOMOUNT, AT_EMPTY_PATH, AT_STATX_SYNC_TYPE + if flags.intersects( + !(AtFlags::AT_SYMLINK_NOFOLLOW + | AtFlags::AT_NO_AUTOMOUNT + | AtFlags::AT_EMPTY_PATH + | AtFlags::AT_STATX_SYNC_TYPE), + ) { + return Err(SystemError::EINVAL); + } + let inode = do_file_lookup_at(dfd, filename, lookup_flags)?; + + let mut kstat = vfs_getattr(&inode, request_mask, flags)?; + if is_mountpoint_root(&inode) { + kstat + .attributes + .insert(StxAttributes::STATX_ATTR_MOUNT_ROOT); + } + kstat + .attributes_mask + .insert(StxAttributes::STATX_ATTR_MOUNT_ROOT); + + // todo: 添加 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#266 这里的逻辑 + + Ok(kstat) +} + +/// 获取文件的增强基本属性 +/// +/// # 参数 +/// - `path`: 目标文件路径 +/// - `stat`: 用于返回统计信息的结构体 +/// - `request_mask`: PosixStatxMask标志位,指示调用者需要哪些属性 +/// - `query_flags`: 查询模式(AT_STATX_SYNC_TYPE) +/// +/// # 描述 +/// 向文件系统请求文件的属性。调用者必须通过request_mask和query_flags指定需要的信息。 +/// +/// 如果文件是远程的: +/// - 可以通过传递AT_STATX_FORCE_SYNC强制文件系统从后端存储更新属性 +/// - 可以通过传递AT_STATX_DONT_SYNC禁止更新 +/// +/// request_mask中必须设置相应的位来指示调用者需要检索哪些属性。 +/// 未请求的属性也可能被返回,但其值可能是近似的,如果是远程文件, +/// 可能没有与服务器同步。 +/// +/// # 返回值 +/// 成功时返回0,失败时返回负的错误码 +/// +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#165 +#[inline(never)] +pub fn vfs_getattr( + inode: &Arc, + request_mask: PosixStatxMask, + mut at_flags: AtFlags, +) -> Result { + if at_flags.contains(AtFlags::AT_GETATTR_NOSEC) { + return Err(SystemError::EPERM); + } + + let mut kstat = KStat::default(); + kstat.result_mask |= PosixStatxMask::STATX_BASIC_STATS; + at_flags &= AtFlags::AT_STATX_SYNC_TYPE; + + let metadata = inode.metadata()?; + if metadata.atime.is_empty() { + kstat.result_mask.remove(PosixStatxMask::STATX_ATIME); + } + + // todo: 添加automount和dax属性 + + kstat.blksize = metadata.blk_size as u32; + if request_mask.contains(PosixStatxMask::STATX_MODE) + || request_mask.contains(PosixStatxMask::STATX_TYPE) + { + kstat.mode = metadata.mode; + } + if request_mask.contains(PosixStatxMask::STATX_NLINK) { + kstat.nlink = metadata.nlinks as u32; + } + if request_mask.contains(PosixStatxMask::STATX_UID) { + kstat.uid = metadata.uid as u32; + } + if request_mask.contains(PosixStatxMask::STATX_GID) { + kstat.gid = metadata.gid as u32; + } + if request_mask.contains(PosixStatxMask::STATX_ATIME) { + kstat.atime.tv_sec = metadata.atime.tv_sec; + kstat.atime.tv_nsec = metadata.atime.tv_nsec; + } + if request_mask.contains(PosixStatxMask::STATX_MTIME) { + kstat.mtime.tv_sec = metadata.mtime.tv_sec; + kstat.mtime.tv_nsec = metadata.mtime.tv_nsec; + } + if request_mask.contains(PosixStatxMask::STATX_CTIME) { + // ctime是文件上次修改状态的时间 + kstat.ctime.tv_sec = metadata.ctime.tv_sec; + kstat.ctime.tv_nsec = metadata.ctime.tv_nsec; + } + if request_mask.contains(PosixStatxMask::STATX_INO) { + kstat.ino = metadata.inode_id.into() as u64; + } + if request_mask.contains(PosixStatxMask::STATX_SIZE) { + kstat.size = metadata.size as usize; + } + if request_mask.contains(PosixStatxMask::STATX_BLOCKS) { + kstat.blocks = metadata.blocks as u64; + } + + if request_mask.contains(PosixStatxMask::STATX_BTIME) { + // btime是文件创建时间 + kstat.btime.tv_sec = metadata.btime.tv_sec; + kstat.btime.tv_nsec = metadata.btime.tv_nsec; + } + if request_mask.contains(PosixStatxMask::STATX_ALL) { + kstat.attributes = StxAttributes::STATX_ATTR_APPEND; + kstat.attributes_mask |= + StxAttributes::STATX_ATTR_AUTOMOUNT | StxAttributes::STATX_ATTR_DAX; + kstat.dev = DeviceNumber::from(metadata.dev_id as u32); + kstat.rdev = metadata.raw_dev; + } + + // 把文件类型加入mode里面 (todo: 在具体的文件系统里面去实现这个操作。这里只是权宜之计) + kstat.mode |= metadata.file_type.into(); + + return Ok(kstat); +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#274 +#[inline(never)] +pub fn vfs_fstatat(dfd: i32, filename: &str, flags: AtFlags) -> Result { + // log::debug!("vfs_fstatat: dfd={}, filename={}", dfd, filename); + let statx_flags = flags | AtFlags::AT_NO_AUTOMOUNT; + if dfd >= 0 && flags == AtFlags::AT_EMPTY_PATH { + return vfs_fstat(dfd); + } + + return vfs_statx( + dfd, + filename, + statx_flags, + PosixStatxMask::STATX_BASIC_STATS, + ); +} + +/// vfs_fstat - Get the basic attributes by file descriptor +/// +/// # Arguments +/// - fd: The file descriptor referring to the file of interest +/// +/// This function is a wrapper around vfs_getattr(). The main difference is +/// that it uses a file descriptor to determine the file location. +/// +/// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#190 +pub fn vfs_fstat(dfd: i32) -> Result { + // Get the file from the file descriptor + let pcb = ProcessManager::current_pcb(); + let fd_table = pcb.fd_table(); + let file = fd_table + .read() + .get_file_by_fd(dfd) + .ok_or(SystemError::EBADF)?; + let inode = file.inode(); + + // Get attributes using vfs_getattr with basic stats mask + vfs_getattr(&inode, PosixStatxMask::STATX_BASIC_STATS, AtFlags::empty()) +} + +pub(super) fn do_newfstatat( + dfd: i32, + filename: &str, + user_stat_buf_ptr: usize, + flags: u32, +) -> Result<(), SystemError> { + let kstat = vfs_fstatat(dfd, filename, AtFlags::from_bits_truncate(flags as i32))?; + + cp_new_stat(kstat, user_stat_buf_ptr) +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#393 +#[inline(never)] +pub(super) fn cp_new_stat(kstat: KStat, user_buf_ptr: usize) -> Result<(), SystemError> { + let posix_stat = PosixStat::try_from(kstat)?; + let mut ubuf_writer = + UserBufferWriter::new(user_buf_ptr as *mut PosixStat, size_of::(), true)?; + ubuf_writer + .copy_one_to_user(&posix_stat, 0) + .map_err(|_| SystemError::EFAULT) +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#660 +pub(super) fn do_statx( + dfd: i32, + filename: &str, + flags: u32, + mask: u32, + user_kstat_ptr: usize, +) -> Result<(), SystemError> { + let mask = PosixStatxMask::from_bits_truncate(mask); + if mask.contains(PosixStatxMask::STATX_RESERVED) { + return Err(SystemError::EINVAL); + } + + let flags = AtFlags::from_bits_truncate(flags as i32); + if flags.contains(AtFlags::AT_STATX_SYNC_TYPE) { + return Err(SystemError::EINVAL); + } + + let kstat = vfs_statx(dfd, filename, flags, mask)?; + cp_statx(kstat, user_kstat_ptr) +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#622 +#[inline(never)] +fn cp_statx(kstat: KStat, user_buf_ptr: usize) -> Result<(), SystemError> { + let mut userbuf = UserBufferWriter::new( + user_buf_ptr as *mut PosixStatx, + size_of::(), + true, + )?; + let mut statx: PosixStatx = PosixStatx::new(); + + // Copy fields from KStat to PosixStatx + statx.stx_mask = kstat.result_mask & !PosixStatxMask::STATX_CHANGE_COOKIE; + statx.stx_blksize = kstat.blksize; + statx.stx_attributes = kstat.attributes & !StxAttributes::STATX_ATTR_CHANGE_MONOTONIC; + statx.stx_nlink = kstat.nlink; + statx.stx_uid = kstat.uid; + statx.stx_gid = kstat.gid; + statx.stx_mode = kstat.mode; + statx.stx_inode = kstat.ino; + statx.stx_size = kstat.size as i64; + statx.stx_blocks = kstat.blocks; + statx.stx_attributes_mask = kstat.attributes_mask; + + // Copy time fields + statx.stx_atime = kstat.atime; + statx.stx_btime = kstat.btime; + statx.stx_ctime = kstat.ctime; + statx.stx_mtime = kstat.mtime; + + // Convert device numbers + statx.stx_rdev_major = kstat.rdev.major().data(); + statx.stx_rdev_minor = kstat.rdev.minor(); + statx.stx_dev_major = kstat.dev.major().data(); + statx.stx_dev_minor = kstat.dev.minor(); + + statx.stx_mnt_id = kstat.mnt_id; + statx.stx_dio_mem_align = kstat.dio_mem_align; + statx.stx_dio_offset_align = kstat.dio_offset_align; + + // Write to user space + userbuf.copy_one_to_user(&statx, 0)?; + Ok(()) +} + +/// 通用的PosixStat +#[allow(unused)] +#[repr(C)] +#[derive(Default, Clone, Copy)] +pub struct GenericPosixStat { + /// Device ID + pub st_dev: u64, + /// File serial number (inode) + pub st_ino: u64, + /// File mode + pub st_mode: u32, + /// Link count + pub st_nlink: u32, + /// User ID of the file's owner + pub st_uid: u32, + /// Group ID of the file's group + pub st_gid: u32, + /// Device number, if device + pub st_rdev: u64, + /// Padding + pub __pad1: u64, + /// Size of file, in bytes + pub st_size: i64, + /// Optimal block size for I/O + pub st_blksize: i32, + /// Padding + pub __pad2: i32, + /// Number 512-byte blocks allocated + pub st_blocks: i64, + /// Time of last access (seconds) + pub st_atime: i64, + /// Time of last access (nanoseconds) + pub st_atime_nsec: u64, + /// Time of last modification (seconds) + pub st_mtime: i64, + /// Time of last modification (nanoseconds) + pub st_mtime_nsec: u64, + /// Time of last status change (seconds) + pub st_ctime: i64, + /// Time of last status change (nanoseconds) + pub st_ctime_nsec: u64, + /// Unused + pub __unused4: u32, + /// Unused + pub __unused5: u32, +} + +/// 转换的代码参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#393 +impl TryFrom for GenericPosixStat { + type Error = SystemError; + + fn try_from(kstat: KStat) -> Result { + let mut tmp = GenericPosixStat::default(); + if core::mem::size_of_val(&tmp.st_dev) < 4 && !kstat.dev.old_valid_dev() { + return Err(SystemError::EOVERFLOW); + } + if core::mem::size_of_val(&tmp.st_rdev) < 4 && !kstat.rdev.old_valid_dev() { + return Err(SystemError::EOVERFLOW); + } + + tmp.st_dev = kstat.dev.new_encode_dev() as u64; + tmp.st_ino = kstat.ino; + + if core::mem::size_of_val(&tmp.st_ino) < core::mem::size_of_val(&kstat.ino) + && tmp.st_ino != kstat.ino + { + return Err(SystemError::EOVERFLOW); + } + + tmp.st_mode = kstat.mode.bits(); + tmp.st_nlink = kstat.nlink; + + // todo: 处理user namespace (https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#415) + tmp.st_uid = kstat.uid; + tmp.st_gid = kstat.gid; + + tmp.st_rdev = kstat.rdev.data() as u64; + tmp.st_size = kstat.size as i64; + + tmp.st_atime = kstat.atime.tv_sec; + tmp.st_mtime = kstat.mtime.tv_sec; + tmp.st_ctime = kstat.ctime.tv_sec; + tmp.st_atime_nsec = kstat.atime.tv_nsec as u64; + tmp.st_mtime_nsec = kstat.mtime.tv_nsec as u64; + tmp.st_ctime_nsec = kstat.ctime.tv_nsec as u64; + tmp.st_blocks = kstat.blocks as i64; + tmp.st_blksize = kstat.blksize as i32; + + Ok(tmp) + } +} diff --git a/kernel/src/filesystem/vfs/syscall/epoll_utils.rs b/kernel/src/filesystem/vfs/syscall/epoll_utils.rs new file mode 100644 index 00000000..65faf93c --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/epoll_utils.rs @@ -0,0 +1,49 @@ +use crate::filesystem::epoll::event_poll::EventPoll; +use crate::filesystem::epoll::EPollEvent; +use crate::mm::VirtAddr; +use crate::syscall::user_access::UserBufferWriter; +use crate::time::PosixTimeSpec; +use system_error::SystemError; + +/// System call handler for epoll_wait. +/// +/// # Arguments +/// * `epfd` - File descriptor of the epoll instance +/// * `events` - User space address to store the events +/// * `max_events` - Maximum number of events to return +/// * `timeout` - Timeout in milliseconds, 0 for no wait, negative for infinite wait +/// +/// # Returns +/// Returns the number of events ready or an error if the operation fails. +pub(super) fn do_epoll_wait( + epfd: i32, + events: VirtAddr, + max_events: i32, + timeout: i32, +) -> Result { + if max_events <= 0 || max_events as u32 > EventPoll::EP_MAX_EVENTS { + return Err(SystemError::EINVAL); + } + + let mut timespec = None; + if timeout == 0 { + timespec = Some(PosixTimeSpec::new(0, 0)); + } + + if timeout > 0 { + let sec: i64 = timeout as i64 / 1000; + let nsec: i64 = 1000000 * (timeout as i64 % 1000); + + timespec = Some(PosixTimeSpec::new(sec, nsec)) + } + + // 从用户传入的地址中拿到epoll_events + let mut epds_writer = UserBufferWriter::new( + events.as_ptr::(), + max_events as usize * core::mem::size_of::(), + true, + )?; + + let epoll_events = epds_writer.buffer::(0)?; + return EventPoll::epoll_wait(epfd, epoll_events, max_events, timespec); +} diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall/mod.rs similarity index 72% rename from kernel/src/filesystem/vfs/syscall.rs rename to kernel/src/filesystem/vfs/syscall/mod.rs index 5eb3e0c3..ad3a7a0e 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall/mod.rs @@ -1,5 +1,5 @@ use crate::filesystem::overlayfs::OverlayMountData; -use crate::filesystem::vfs::FileSystemMakerData; +use crate::filesystem::vfs::{FileSystemMakerData, FilldirContext}; use core::mem::size_of; use alloc::{string::String, sync::Arc, vec::Vec}; @@ -9,9 +9,9 @@ use crate::producefs; use crate::syscall::user_access::UserBufferReader; use crate::{ driver::base::{block::SeekFrom, device::device_number::DeviceNumber}, - filesystem::vfs::{core as Vcore, file::FileDescriptorVec}, + filesystem::vfs::{file::FileDescriptorVec, vcore as Vcore}, libs::rwlock::RwLockWriteGuard, - mm::{verify_area, VirtAddr}, + mm::VirtAddr, process::ProcessManager, syscall::{ user_access::{self, check_and_clone_cstr, UserBufferWriter}, @@ -20,19 +20,45 @@ use crate::{ time::{syscall::PosixTimeval, PosixTimeSpec}, }; -use super::core::do_symlinkat; +use super::stat::{do_newfstatat, do_statx, vfs_fstat}; +use super::vcore::do_symlinkat; use super::{ - core::{do_mkdir_at, do_remove_dir, do_unlink_at}, fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC}, file::{File, FileMode}, open::{ do_faccessat, do_fchmodat, do_fchownat, do_sys_open, do_utimensat, do_utimes, ksys_fchown, }, utils::{rsplit_path, user_path_at}, - Dirent, FileType, IndexNode, SuperBlock, FSMAKER, MAX_PATHLEN, ROOT_INODE, + vcore::{do_mkdir_at, do_remove_dir, do_unlink_at}, + FileType, IndexNode, SuperBlock, FSMAKER, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES, }; +mod open_utils; +mod sys_close; +#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] +mod sys_fstat; +mod sys_ioctl; +#[cfg(target_arch = "x86_64")] +mod sys_lstat; +#[cfg(target_arch = "x86_64")] +mod sys_open; +mod sys_read; +mod sys_readv; +#[cfg(target_arch = "x86_64")] +mod sys_stat; +mod sys_write; +mod sys_writev; + +mod epoll_utils; +#[cfg(target_arch = "x86_64")] +mod sys_epoll_create; +mod sys_epoll_create1; +mod sys_epoll_ctl; +mod sys_epoll_pwait; +#[cfg(target_arch = "x86_64")] +mod sys_epoll_wait; + pub const SEEK_SET: u32 = 0; pub const SEEK_CUR: u32 = 1; pub const SEEK_END: u32 = 2; @@ -87,126 +113,65 @@ bitflags! { } } -#[repr(C)] -#[derive(Clone, Copy)] -/// # 文件信息结构体 -pub struct PosixKstat { - /// 硬件设备ID - dev_id: u64, - /// inode号 - inode: u64, - /// 硬链接数 - nlink: u64, - /// 文件权限 - mode: ModeType, - /// 所有者用户ID - uid: i32, - /// 所有者组ID - gid: i32, - /// 设备ID - rdev: i64, - /// 文件大小 - size: i64, - /// 文件系统块大小 - blcok_size: i64, - /// 分配的512B块数 - blocks: u64, - /// 最后访问时间 - atime: PosixTimeSpec, - /// 最后修改时间 - mtime: PosixTimeSpec, - /// 最后状态变化时间 - ctime: PosixTimeSpec, - /// 用于填充结构体大小的空白数据 - pub _pad: [i8; 24], -} -impl PosixKstat { - fn new() -> Self { - Self { - inode: 0, - dev_id: 0, - mode: ModeType { bits: 0 }, - nlink: 0, - uid: 0, - gid: 0, - rdev: 0, - size: 0, - atime: PosixTimeSpec { - tv_sec: 0, - tv_nsec: 0, - }, - mtime: PosixTimeSpec { - tv_sec: 0, - tv_nsec: 0, - }, - ctime: PosixTimeSpec { - tv_sec: 0, - tv_nsec: 0, - }, - blcok_size: 0, - blocks: 0, - _pad: Default::default(), - } - } -} - #[repr(C)] #[derive(Clone, Copy)] /// # 文件信息结构体X pub struct PosixStatx { /* 0x00 */ - stx_mask: PosixStatxMask, + pub stx_mask: PosixStatxMask, /// 文件系统块大小 - stx_blksize: u32, + pub stx_blksize: u32, /// Flags conveying information about the file [uncond] - stx_attributes: StxAttributes, + pub stx_attributes: StxAttributes, /* 0x10 */ /// 硬链接数 - stx_nlink: u32, + pub stx_nlink: u32, /// 所有者用户ID - stx_uid: u32, + pub stx_uid: u32, /// 所有者组ID - stx_gid: u32, + pub stx_gid: u32, /// 文件权限 - stx_mode: ModeType, + pub stx_mode: ModeType, /* 0x20 */ /// inode号 - stx_inode: u64, + pub stx_inode: u64, /// 文件大小 - stx_size: i64, + pub stx_size: i64, /// 分配的512B块数 - stx_blocks: u64, + pub stx_blocks: u64, /// Mask to show what's supported in stx_attributes - stx_attributes_mask: StxAttributes, + pub stx_attributes_mask: StxAttributes, /* 0x40 */ /// 最后访问时间 - stx_atime: PosixTimeSpec, + pub stx_atime: PosixTimeSpec, /// 文件创建时间 - stx_btime: PosixTimeSpec, + pub stx_btime: PosixTimeSpec, /// 最后状态变化时间 - stx_ctime: PosixTimeSpec, + pub stx_ctime: PosixTimeSpec, /// 最后修改时间 - stx_mtime: PosixTimeSpec, + pub stx_mtime: PosixTimeSpec, /* 0x80 */ /// 主设备ID - stx_rdev_major: u32, + pub stx_rdev_major: u32, /// 次设备ID - stx_rdev_minor: u32, + pub stx_rdev_minor: u32, /// 主硬件设备ID - stx_dev_major: u32, + pub stx_dev_major: u32, /// 次硬件设备ID - stx_dev_minor: u32, + pub stx_dev_minor: u32, /* 0x90 */ - stx_mnt_id: u64, - stx_dio_mem_align: u32, - stx_dio_offset_align: u32, + pub stx_mnt_id: u64, + pub stx_dio_mem_align: u32, + pub stx_dio_offset_align: u32, } + impl PosixStatx { - fn new() -> Self { + #[inline(never)] + pub(super) fn new() -> Self { Self { stx_mask: PosixStatxMask::STATX_BASIC_STATS, stx_blksize: 0, @@ -300,6 +265,9 @@ bitflags! { /// Reserved for future struct statx expansion const STATX_RESERVED = 0x80000000; + + /// Want/got stx_change_attr + const STATX_CHANGE_COOKIE = 0x40000000; } } @@ -323,6 +291,8 @@ bitflags! { const STATX_ATTR_VERITY = 0x00100000; /// 文件当前处于 DAX 状态 CPU直接访问 const STATX_ATTR_DAX = 0x00200000; + /// version monotonically increases + const STATX_ATTR_CHANGE_MONOTONIC = 0x8000000000000000; } } @@ -474,33 +444,6 @@ bitflags! { } impl Syscall { - /// @brief 为当前进程打开一个文件 - /// - /// @param path 文件路径 - /// @param o_flags 打开文件的标志位 - /// - /// @return 文件描述符编号,或者是错误码 - pub fn open( - path: *const u8, - o_flags: u32, - mode: u32, - follow_symlink: bool, - ) -> Result { - let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))? - .into_string() - .map_err(|_| SystemError::EINVAL)?; - - let open_flags: FileMode = FileMode::from_bits(o_flags).ok_or(SystemError::EINVAL)?; - let mode = ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?; - return do_sys_open( - AtFlags::AT_FDCWD.bits(), - &path, - open_flags, - mode, - follow_symlink, - ); - } - pub fn openat( dirfd: i32, path: *const u8, @@ -517,82 +460,6 @@ impl Syscall { return do_sys_open(dirfd, &path, open_flags, mode, follow_symlink); } - /// @brief 关闭文件 - /// - /// @param fd 文件描述符编号 - /// - /// @return 成功返回0,失败返回错误码 - pub fn close(fd: usize) -> Result { - let binding = ProcessManager::current_pcb().fd_table(); - let mut fd_table_guard = binding.write(); - let _file = fd_table_guard.drop_fd(fd as i32)?; - drop(fd_table_guard); - Ok(0) - } - - /// @brief 发送命令到文件描述符对应的设备, - /// - /// @param fd 文件描述符编号 - /// @param cmd 设备相关的请求类型 - /// - /// @return Ok(usize) 成功返回0 - /// @return Err(SystemError) 读取失败,返回posix错误码 - pub fn ioctl(fd: usize, cmd: u32, data: usize) -> Result { - let binding = ProcessManager::current_pcb().fd_table(); - let fd_table_guard = binding.read(); - - let file = fd_table_guard - .get_file_by_fd(fd as i32) - .ok_or(SystemError::EBADF)?; - - // drop guard 以避免无法调度的问题 - drop(fd_table_guard); - let r = file.inode().ioctl(cmd, data, &file.private_data.lock()); - return r; - } - - /// @brief 根据文件描述符,读取文件数据。尝试读取的数据长度与buf的长度相同。 - /// - /// @param fd 文件描述符编号 - /// @param buf 输出缓冲区 - /// - /// @return Ok(usize) 成功读取的数据的字节数 - /// @return Err(SystemError) 读取失败,返回posix错误码 - pub fn read(fd: i32, buf: &mut [u8]) -> Result { - let binding = ProcessManager::current_pcb().fd_table(); - let fd_table_guard = binding.read(); - - let file = fd_table_guard.get_file_by_fd(fd); - if file.is_none() { - return Err(SystemError::EBADF); - } - // drop guard 以避免无法调度的问题 - drop(fd_table_guard); - let file = file.unwrap(); - - return file.read(buf.len(), buf); - } - - /// @brief 根据文件描述符,向文件写入数据。尝试写入的数据长度与buf的长度相同。 - /// - /// @param fd 文件描述符编号 - /// @param buf 输入缓冲区 - /// - /// @return Ok(usize) 成功写入的数据的字节数 - /// @return Err(SystemError) 写入失败,返回posix错误码 - pub fn write(fd: i32, buf: &[u8]) -> Result { - let binding = ProcessManager::current_pcb().fd_table(); - let fd_table_guard = binding.read(); - - let file = fd_table_guard - .get_file_by_fd(fd) - .ok_or(SystemError::EBADF)?; - - // drop guard 以避免无法调度的问题 - drop(fd_table_guard); - return file.write(buf.len(), buf); - } - /// @brief 调整文件操作指针的位置 /// /// @param fd 文件描述符编号 @@ -733,6 +600,7 @@ impl Syscall { let metadata = inode.metadata()?; if metadata.file_type == FileType::Dir { proc.basic_mut().set_cwd(new_path); + proc.fs_struct_mut().set_pwd(inode); return Ok(0); } else { return Err(SystemError::ENOTDIR); @@ -752,6 +620,7 @@ impl Syscall { } let path = inode.absolute_path()?; pcb.basic_mut().set_cwd(path); + pcb.fs_struct_mut().set_pwd(inode); return Ok(0); } @@ -777,18 +646,16 @@ impl Syscall { return Ok(VirtAddr::new(buf.as_ptr() as usize)); } - /// @brief 获取目录中的数据 + /// # 获取目录中的数据 /// - /// TODO: 这个函数的语义与Linux不一致,需要修改!!! + /// ## 参数 + /// - fd 文件描述符号 + /// - buf 输出缓冲区 /// - /// @param fd 文件描述符号 - /// @param buf 输出缓冲区 - /// - /// @return 成功返回读取的字节数,失败返回错误码 + /// ## 返回值 + /// - Ok(ctx.current_pos) 填充缓冲区当前指针位置 + /// - Err(ctx.error.unwrap()) 填充缓冲区时返回的错误 pub fn getdents(fd: i32, buf: &mut [u8]) -> Result { - let dirent = - unsafe { (buf.as_mut_ptr() as *mut Dirent).as_mut() }.ok_or(SystemError::EFAULT)?; - if fd < 0 || fd as usize > FileDescriptorVec::PROCESS_MAX_FD { return Err(SystemError::EBADF); } @@ -803,9 +670,22 @@ impl Syscall { // drop guard 以避免无法调度的问题 drop(fd_table_guard); - let res = file.readdir(dirent).map(|x| x as usize); - - return res; + let mut ctx = FilldirContext::new(buf); + match file.read_dir(&mut ctx) { + Ok(_) => { + if ctx.error.is_some() { + if ctx.error == Some(SystemError::EINVAL) { + return Ok(ctx.current_pos); + } else { + return Err(ctx.error.unwrap()); + } + } + return Ok(ctx.current_pos); + } + Err(e) => { + return Err(e); + } + } } /// @brief 创建文件夹 @@ -1300,86 +1180,9 @@ impl Syscall { return Err(SystemError::EBADF); } - fn do_fstat(fd: i32) -> Result { - let binding = ProcessManager::current_pcb().fd_table(); - let fd_table_guard = binding.read(); - let file = fd_table_guard - .get_file_by_fd(fd) - .ok_or(SystemError::EBADF)?; - // drop guard 以避免无法调度的问题 - drop(fd_table_guard); - - let mut kstat = PosixKstat::new(); - // 获取文件信息 - let metadata = file.metadata()?; - kstat.size = metadata.size; - kstat.dev_id = metadata.dev_id as u64; - kstat.inode = metadata.inode_id.into() as u64; - kstat.blcok_size = metadata.blk_size as i64; - kstat.blocks = metadata.blocks as u64; - - kstat.atime.tv_sec = metadata.atime.tv_sec; - kstat.atime.tv_nsec = metadata.atime.tv_nsec; - kstat.mtime.tv_sec = metadata.mtime.tv_sec; - kstat.mtime.tv_nsec = metadata.mtime.tv_nsec; - kstat.ctime.tv_sec = metadata.ctime.tv_sec; - kstat.ctime.tv_nsec = metadata.ctime.tv_nsec; - - kstat.nlink = metadata.nlinks as u64; - kstat.uid = metadata.uid as i32; - kstat.gid = metadata.gid as i32; - kstat.rdev = metadata.raw_dev.data() as i64; - kstat.mode = metadata.mode; - match file.file_type() { - FileType::File => kstat.mode.insert(ModeType::S_IFREG), - FileType::Dir => kstat.mode.insert(ModeType::S_IFDIR), - FileType::BlockDevice => kstat.mode.insert(ModeType::S_IFBLK), - FileType::CharDevice => kstat.mode.insert(ModeType::S_IFCHR), - FileType::SymLink => kstat.mode.insert(ModeType::S_IFLNK), - FileType::Socket => kstat.mode.insert(ModeType::S_IFSOCK), - FileType::Pipe => kstat.mode.insert(ModeType::S_IFIFO), - FileType::KvmDevice => kstat.mode.insert(ModeType::S_IFCHR), - FileType::FramebufferDevice => kstat.mode.insert(ModeType::S_IFCHR), - } - - return Ok(kstat); - } - - pub fn fstat(fd: i32, usr_kstat: *mut PosixKstat) -> Result { - let mut writer = UserBufferWriter::new(usr_kstat, size_of::(), true)?; - let kstat = Self::do_fstat(fd)?; - - writer.copy_one_to_user(&kstat, 0)?; - return Ok(0); - } - - pub fn stat(path: *const u8, user_kstat: *mut PosixKstat) -> Result { - let fd = Self::open( - path, - FileMode::O_RDONLY.bits(), - ModeType::empty().bits(), - true, - )?; - let r = Self::fstat(fd as i32, user_kstat); - Self::close(fd).ok(); - return r; - } - - pub fn lstat(path: *const u8, user_kstat: *mut PosixKstat) -> Result { - let fd = Self::open( - path, - FileMode::O_RDONLY.bits(), - ModeType::empty().bits(), - false, - )?; - let r = Self::fstat(fd as i32, user_kstat); - Self::close(fd).ok(); - return r; - } - pub fn statfs(path: *const u8, user_statfs: *mut PosixStatfs) -> Result { let mut writer = UserBufferWriter::new(user_statfs, size_of::(), true)?; - let fd = Self::open( + let fd = open_utils::do_open( path, FileMode::O_RDONLY.bits(), ModeType::empty().bits(), @@ -1410,112 +1213,49 @@ impl Syscall { return Ok(0); } - pub fn do_statx( - fd: i32, - path: *const u8, + #[inline(never)] + pub fn statx( + dfd: i32, + filename_ptr: usize, flags: u32, mask: u32, - usr_kstat: *mut PosixStatx, + user_kstat_ptr: usize, ) -> Result { - if usr_kstat.is_null() { + if user_kstat_ptr == 0 { return Err(SystemError::EFAULT); } - let mask = PosixStatxMask::from_bits_truncate(mask); + let filename = check_and_clone_cstr(filename_ptr as *const u8, Some(MAX_PATHLEN))?; + let filename_str = filename.to_str().map_err(|_| SystemError::EINVAL)?; - if mask.contains(PosixStatxMask::STATX_RESERVED) { - return Err(SystemError::ENAVAIL); + do_statx(dfd, filename_str, flags, mask, user_kstat_ptr).map(|_| 0) + } + + #[inline(never)] + pub fn newfstatat( + dfd: i32, + filename_ptr: usize, + user_stat_buf_ptr: usize, + flags: u32, + ) -> Result { + if user_stat_buf_ptr == 0 { + return Err(SystemError::EFAULT); } - let flags = FileMode::from_bits_truncate(flags); - let ofd = Self::open(path, flags.bits(), ModeType::empty().bits, true)?; + let filename = check_and_clone_cstr(filename_ptr as *const u8, Some(MAX_PATHLEN))?; + let filename_str = filename.to_str().map_err(|_| SystemError::EINVAL)?; - let binding = ProcessManager::current_pcb().fd_table(); - let fd_table_guard = binding.read(); - let file = fd_table_guard - .get_file_by_fd(ofd as i32) - .ok_or(SystemError::EBADF)?; - // drop guard 以避免无法调度的问题 - drop(fd_table_guard); - let mut writer = UserBufferWriter::new(usr_kstat, size_of::(), true)?; - let mut tmp: PosixStatx = PosixStatx::new(); - // 获取文件信息 - let metadata = file.metadata()?; + do_newfstatat(dfd, filename_str, user_stat_buf_ptr, flags).map(|_| 0) + } - tmp.stx_mask |= PosixStatxMask::STATX_BASIC_STATS; - tmp.stx_blksize = metadata.blk_size as u32; - if mask.contains(PosixStatxMask::STATX_MODE) || mask.contains(PosixStatxMask::STATX_TYPE) { - tmp.stx_mode = metadata.mode; + #[inline(never)] + pub fn newfstat(fd: i32, user_stat_buf_ptr: usize) -> Result { + if user_stat_buf_ptr == 0 { + return Err(SystemError::EFAULT); } - if mask.contains(PosixStatxMask::STATX_NLINK) { - tmp.stx_nlink = metadata.nlinks as u32; - } - if mask.contains(PosixStatxMask::STATX_UID) { - tmp.stx_uid = metadata.uid as u32; - } - if mask.contains(PosixStatxMask::STATX_GID) { - tmp.stx_gid = metadata.gid as u32; - } - if mask.contains(PosixStatxMask::STATX_ATIME) { - tmp.stx_atime.tv_sec = metadata.atime.tv_sec; - tmp.stx_atime.tv_nsec = metadata.atime.tv_nsec; - } - if mask.contains(PosixStatxMask::STATX_MTIME) { - tmp.stx_mtime.tv_sec = metadata.ctime.tv_sec; - tmp.stx_mtime.tv_nsec = metadata.ctime.tv_nsec; - } - if mask.contains(PosixStatxMask::STATX_CTIME) { - // ctime是文件上次修改状态的时间 - tmp.stx_ctime.tv_sec = metadata.mtime.tv_sec; - tmp.stx_ctime.tv_nsec = metadata.mtime.tv_nsec; - } - if mask.contains(PosixStatxMask::STATX_INO) { - tmp.stx_inode = metadata.inode_id.into() as u64; - } - if mask.contains(PosixStatxMask::STATX_SIZE) { - tmp.stx_size = metadata.size; - } - if mask.contains(PosixStatxMask::STATX_BLOCKS) { - tmp.stx_blocks = metadata.blocks as u64; - } - - if mask.contains(PosixStatxMask::STATX_BTIME) { - // btime是文件创建时间 - tmp.stx_btime.tv_sec = metadata.ctime.tv_sec; - tmp.stx_btime.tv_nsec = metadata.ctime.tv_nsec; - } - if mask.contains(PosixStatxMask::STATX_ALL) { - tmp.stx_attributes = StxAttributes::STATX_ATTR_APPEND; - tmp.stx_attributes_mask |= - StxAttributes::STATX_ATTR_AUTOMOUNT | StxAttributes::STATX_ATTR_DAX; - tmp.stx_dev_major = metadata.dev_id as u32; - tmp.stx_dev_minor = metadata.dev_id as u32; // - tmp.stx_rdev_major = metadata.raw_dev.data(); - tmp.stx_rdev_minor = metadata.raw_dev.data(); - } - if mask.contains(PosixStatxMask::STATX_MNT_ID) { - tmp.stx_mnt_id = 0; - } - if mask.contains(PosixStatxMask::STATX_DIOALIGN) { - tmp.stx_dio_mem_align = 0; - tmp.stx_dio_offset_align = 0; - } - - match file.file_type() { - FileType::File => tmp.stx_mode.insert(ModeType::S_IFREG), - FileType::Dir => tmp.stx_mode.insert(ModeType::S_IFDIR), - FileType::BlockDevice => tmp.stx_mode.insert(ModeType::S_IFBLK), - FileType::CharDevice => tmp.stx_mode.insert(ModeType::S_IFCHR), - FileType::SymLink => tmp.stx_mode.insert(ModeType::S_IFLNK), - FileType::Socket => tmp.stx_mode.insert(ModeType::S_IFSOCK), - FileType::Pipe => tmp.stx_mode.insert(ModeType::S_IFIFO), - FileType::KvmDevice => tmp.stx_mode.insert(ModeType::S_IFCHR), - FileType::FramebufferDevice => tmp.stx_mode.insert(ModeType::S_IFCHR), - } - - writer.copy_one_to_user(&tmp, 0)?; - Self::close(fd as usize).ok(); - return Ok(0); + let stat = vfs_fstat(fd)?; + // log::debug!("newfstat fd: {}, stat.size: {:?}",fd,stat.size); + super::stat::cp_new_stat(stat, user_stat_buf_ptr).map(|_| 0) } pub fn mknod( @@ -1546,28 +1286,6 @@ impl Syscall { return Ok(0); } - pub fn writev(fd: i32, iov: usize, count: usize) -> Result { - // IoVecs会进行用户态检验 - let iovecs = unsafe { IoVecs::from_user(iov as *const IoVec, count, false) }?; - - let data = iovecs.gather(); - - Self::write(fd, &data) - } - - pub fn readv(fd: i32, iov: usize, count: usize) -> Result { - // IoVecs会进行用户态检验 - let mut iovecs = unsafe { IoVecs::from_user(iov as *const IoVec, count, true) }?; - - let mut data = vec![0; iovecs.0.iter().map(|x| x.len()).sum()]; - - let len = Self::read(fd, &mut data)?; - - iovecs.scatter(&data[..len]); - - return Ok(len); - } - pub fn readlink_at( dirfd: i32, path: *const u8, @@ -1800,104 +1518,3 @@ impl Syscall { do_utimes(&pathname, times) } } - -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct IoVec { - /// 缓冲区的起始地址 - pub iov_base: *mut u8, - /// 缓冲区的长度 - pub iov_len: usize, -} - -/// 用于存储多个来自用户空间的IoVec -/// -/// 由于目前内核中的文件系统还不支持分散读写,所以暂时只支持将用户空间的IoVec聚合成一个缓冲区,然后进行操作。 -/// TODO:支持分散读写 -#[derive(Debug)] -pub struct IoVecs(Vec<&'static mut [u8]>); - -impl IoVecs { - /// 从用户空间的IoVec中构造IoVecs - /// - /// @param iov 用户空间的IoVec - /// @param iovcnt 用户空间的IoVec的数量 - /// @param readv 是否为readv系统调用 - /// - /// @return 构造成功返回IoVecs,否则返回错误码 - pub unsafe fn from_user( - iov: *const IoVec, - iovcnt: usize, - _readv: bool, - ) -> Result { - // 检查iov指针所在空间是否合法 - verify_area( - VirtAddr::new(iov as usize), - iovcnt * core::mem::size_of::(), - ) - .map_err(|_| SystemError::EFAULT)?; - - // 将用户空间的IoVec转换为引用(注意:这里的引用是静态的,因为用户空间的IoVec不会被释放) - let iovs: &[IoVec] = core::slice::from_raw_parts(iov, iovcnt); - - let mut slices: Vec<&mut [u8]> = Vec::with_capacity(iovs.len()); - - for iov in iovs.iter() { - if iov.iov_len == 0 { - continue; - } - - verify_area( - VirtAddr::new(iov.iov_base as usize), - iovcnt * core::mem::size_of::(), - ) - .map_err(|_| SystemError::EFAULT)?; - - slices.push(core::slice::from_raw_parts_mut(iov.iov_base, iov.iov_len)); - } - - return Ok(Self(slices)); - } - - /// @brief 将IoVecs中的数据聚合到一个缓冲区中 - /// - /// @return 返回聚合后的缓冲区 - pub fn gather(&self) -> Vec { - let mut buf = Vec::new(); - for slice in self.0.iter() { - buf.extend_from_slice(slice); - } - return buf; - } - - /// @brief 将给定的数据分散写入到IoVecs中 - pub fn scatter(&mut self, data: &[u8]) { - let mut data: &[u8] = data; - for slice in self.0.iter_mut() { - let len = core::cmp::min(slice.len(), data.len()); - if len == 0 { - continue; - } - - slice[..len].copy_from_slice(&data[..len]); - data = &data[len..]; - } - } - - /// @brief 创建与IoVecs等长的缓冲区 - /// - /// @param set_len 是否设置返回的Vec的len。 - /// 如果为true,则返回的Vec的len为所有IoVec的长度之和; - /// 否则返回的Vec的len为0,capacity为所有IoVec的长度之和. - /// - /// @return 返回创建的缓冲区 - pub fn new_buf(&self, set_len: bool) -> Vec { - let total_len: usize = self.0.iter().map(|slice| slice.len()).sum(); - let mut buf: Vec = Vec::with_capacity(total_len); - - if set_len { - buf.resize(total_len, 0); - } - return buf; - } -} diff --git a/kernel/src/filesystem/vfs/syscall/open_utils.rs b/kernel/src/filesystem/vfs/syscall/open_utils.rs new file mode 100644 index 00000000..b887ae47 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/open_utils.rs @@ -0,0 +1,39 @@ +use system_error::SystemError; + +use crate::{ + filesystem::vfs::{fcntl::AtFlags, file::FileMode, open::do_sys_open, MAX_PATHLEN}, + syscall::user_access::check_and_clone_cstr, +}; + +use super::ModeType; + +/// Performs the actual file opening operation. +/// +/// # Arguments +/// * `path` - Pointer to the path string +/// * `o_flags` - File opening flags +/// * `mode` - File mode/permissions +/// * `follow_symlink` - Whether to follow symbolic links +/// +/// # Returns +/// File descriptor on success, or error code on failure. +pub(super) fn do_open( + path: *const u8, + o_flags: u32, + mode: u32, + follow_symlink: bool, +) -> Result { + let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))? + .into_string() + .map_err(|_| SystemError::EINVAL)?; + + let open_flags: FileMode = FileMode::from_bits(o_flags).ok_or(SystemError::EINVAL)?; + let mode = ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?; + return do_sys_open( + AtFlags::AT_FDCWD.bits(), + &path, + open_flags, + mode, + follow_symlink, + ); +} diff --git a/kernel/src/filesystem/vfs/syscall/sys_close.rs b/kernel/src/filesystem/vfs/syscall/sys_close.rs new file mode 100644 index 00000000..d0a4d958 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_close.rs @@ -0,0 +1,54 @@ +//! System call handler for closing files. + +use alloc::string::ToString; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_CLOSE; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +/// Handler for the `close` system call. +pub struct SysCloseHandle; + +impl Syscall for SysCloseHandle { + /// Returns the number of arguments this syscall takes (1). + fn num_args(&self) -> usize { + 1 + } + + /// Handles the close syscall by extracting arguments and calling `do_close`. + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let fd = Self::fd(args); + do_close(fd) + } + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new("fd", Self::fd(args).to_string())] + } +} + +impl SysCloseHandle { + /// Extracts the file descriptor (fd) argument from syscall parameters. + fn fd(args: &[usize]) -> i32 { + args[0] as i32 + } +} + +syscall_table_macros::declare_syscall!(SYS_CLOSE, SysCloseHandle); + +/// Close a file descriptor +/// +/// # Arguments +/// - `fd`: The file descriptor to close +/// +/// # Returns +/// Returns Ok(0) on success, or Err(SystemError) on failure +pub(super) fn do_close(fd: i32) -> Result { + let binding = ProcessManager::current_pcb().fd_table(); + let mut fd_table_guard = binding.write(); + let _file = fd_table_guard.drop_fd(fd)?; + drop(fd_table_guard); + Ok(0) +} diff --git a/kernel/src/filesystem/vfs/syscall/sys_epoll_create.rs b/kernel/src/filesystem/vfs/syscall/sys_epoll_create.rs new file mode 100644 index 00000000..798fae96 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_epoll_create.rs @@ -0,0 +1,42 @@ +//! System call handler for epoll creation. + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_EPOLL_CREATE; +use crate::filesystem::epoll::event_poll::EventPoll; +use crate::filesystem::vfs::file::FileMode; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysEpollCreateHandle; + +impl Syscall for SysEpollCreateHandle { + fn num_args(&self) -> usize { + 1 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let max_size = Self::max_size(args); + if max_size < 0 { + return Err(SystemError::EINVAL); + } + + return EventPoll::create_epoll(FileMode::empty()); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "max_size", + format!("{:#x}", Self::max_size(args) as usize), + )] + } +} + +impl SysEpollCreateHandle { + fn max_size(args: &[usize]) -> i32 { + args[0] as i32 + } +} + +syscall_table_macros::declare_syscall!(SYS_EPOLL_CREATE, SysEpollCreateHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_epoll_create1.rs b/kernel/src/filesystem/vfs/syscall/sys_epoll_create1.rs new file mode 100644 index 00000000..24f7398c --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_epoll_create1.rs @@ -0,0 +1,36 @@ +//! System call handler for epoll_create1. + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_EPOLL_CREATE1; +use crate::filesystem::epoll::event_poll::EventPoll; +use crate::filesystem::vfs::file::FileMode; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysEpollCreate1Handle; + +impl Syscall for SysEpollCreate1Handle { + fn num_args(&self) -> usize { + 1 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + return EventPoll::create_epoll(Self::flags(args)); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "flags", + format!("{:#x}", Self::flags(args)), + )] + } +} + +impl SysEpollCreate1Handle { + fn flags(args: &[usize]) -> FileMode { + FileMode::from_bits_truncate(args[0] as u32) + } +} + +syscall_table_macros::declare_syscall!(SYS_EPOLL_CREATE1, SysEpollCreate1Handle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_epoll_ctl.rs b/kernel/src/filesystem/vfs/syscall/sys_epoll_ctl.rs new file mode 100644 index 00000000..fe8c5220 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_epoll_ctl.rs @@ -0,0 +1,75 @@ +//! System call handler for epoll_ctl. + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_EPOLL_CTL; +use crate::filesystem::epoll::event_poll::EventPoll; +use crate::filesystem::epoll::EPollCtlOption; +use crate::filesystem::epoll::EPollEvent; +use crate::mm::VirtAddr; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use crate::syscall::user_access::UserBufferReader; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysEpollCtlHandle; + +impl Syscall for SysEpollCtlHandle { + fn num_args(&self) -> usize { + 4 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let op = EPollCtlOption::from_op_num(Self::op(args))?; + let mut epds = EPollEvent::default(); + let event = Self::event(args); + let epfd = Self::epfd(args); + let fd = Self::fd(args); + + if op != EPollCtlOption::Del { + // 不为EpollCtlDel时不允许传入空指针 + if event.is_null() { + return Err(SystemError::EFAULT); + } + + // 还是一样的问题,C标准的epoll_event大小为12字节,而内核实现的epoll_event内存对齐后为16字节 + // 这样分别拷贝其实和整体拷贝差别不大,内核使用内存对其版本甚至可能提升性能 + let epds_reader = UserBufferReader::new( + event.as_ptr::(), + core::mem::size_of::(), + true, + )?; + + // 拷贝到内核 + epds_reader.copy_one_from_user(&mut epds, 0)?; + } + + return EventPoll::epoll_ctl_with_epfd(epfd, op, fd, epds, false); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("epfd", format!("{:#x}", Self::epfd(args) as usize)), + FormattedSyscallParam::new("op", format!("{:#x}", Self::op(args))), + FormattedSyscallParam::new("fd", format!("{:#x}", Self::fd(args) as usize)), + FormattedSyscallParam::new("event", format!("{:#x}", Self::event(args).data())), + ] + } +} + +impl SysEpollCtlHandle { + fn epfd(args: &[usize]) -> i32 { + args[0] as i32 + } + fn op(args: &[usize]) -> usize { + args[1] + } + fn fd(args: &[usize]) -> i32 { + args[2] as i32 + } + fn event(args: &[usize]) -> VirtAddr { + VirtAddr::new(args[3]) + } +} + +syscall_table_macros::declare_syscall!(SYS_EPOLL_CTL, SysEpollCtlHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_epoll_pwait.rs b/kernel/src/filesystem/vfs/syscall/sys_epoll_pwait.rs new file mode 100644 index 00000000..79c4bb33 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_epoll_pwait.rs @@ -0,0 +1,79 @@ +//! System call handler for epoll_pwait. + +use super::epoll_utils::do_epoll_wait; +use crate::arch::interrupt::TrapFrame; +use crate::arch::ipc::signal::SigSet; +use crate::arch::syscall::nr::SYS_EPOLL_PWAIT; +use crate::ipc::signal::restore_saved_sigmask; +use crate::ipc::signal::set_user_sigmask; +use crate::mm::VirtAddr; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use crate::syscall::user_access::UserBufferReader; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysEpollPwaitHandle; + +impl Syscall for SysEpollPwaitHandle { + fn num_args(&self) -> usize { + 5 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let epfd = Self::epfd(args); + let epoll_event = Self::epoll_event(args); + let max_events = Self::max_events(args); + let timespec = Self::timespec(args); + let sigmask_addr = Self::sigmask_addr(args); + + if sigmask_addr.is_null() { + return do_epoll_wait(epfd, epoll_event, max_events, timespec); + } + let sigmask_reader = + UserBufferReader::new(sigmask_addr, core::mem::size_of::(), true)?; + let mut sigmask = *sigmask_reader.read_one_from_user::(0)?; + + set_user_sigmask(&mut sigmask); + + let wait_ret = do_epoll_wait(epfd, epoll_event, max_events, timespec); + + if wait_ret.is_err() && *wait_ret.as_ref().unwrap_err() != SystemError::EINTR { + restore_saved_sigmask(); + } + wait_ret + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("epfd", format!("{:#x}", Self::epfd(args) as usize)), + FormattedSyscallParam::new("event", format!("{:#x}", Self::epoll_event(args).data())), + FormattedSyscallParam::new("max_events", format!("{:#x}", Self::max_events(args))), + FormattedSyscallParam::new("timespec", format!("{:#x}", Self::timespec(args))), + FormattedSyscallParam::new( + "sigmask_addr", + format!("{:#x}", Self::sigmask_addr(args) as usize), + ), + ] + } +} + +impl SysEpollPwaitHandle { + fn epfd(args: &[usize]) -> i32 { + args[0] as i32 + } + fn epoll_event(args: &[usize]) -> VirtAddr { + VirtAddr::new(args[1]) + } + fn max_events(args: &[usize]) -> i32 { + args[2] as i32 + } + fn timespec(args: &[usize]) -> i32 { + args[3] as i32 + } + fn sigmask_addr(args: &[usize]) -> *mut SigSet { + args[4] as *mut SigSet + } +} + +syscall_table_macros::declare_syscall!(SYS_EPOLL_PWAIT, SysEpollPwaitHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_epoll_wait.rs b/kernel/src/filesystem/vfs/syscall/sys_epoll_wait.rs new file mode 100644 index 00000000..efd0c1a9 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_epoll_wait.rs @@ -0,0 +1,53 @@ +//! System call handler for epoll_wait. + +use super::epoll_utils::do_epoll_wait; +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_EPOLL_WAIT; +use crate::mm::VirtAddr; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysEpollWaitHandle; + +impl Syscall for SysEpollWaitHandle { + fn num_args(&self) -> usize { + 4 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let epfd = Self::epfd(args); + let max_events = Self::max_events(args); + let timeout = Self::timeout(args); + let events = Self::events(args); + + do_epoll_wait(epfd, events, max_events, timeout) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("epfd", format!("{:#x}", Self::epfd(args) as usize)), + FormattedSyscallParam::new("events", format!("{:#x}", Self::events(args).data())), + FormattedSyscallParam::new("max_events", format!("{:#x}", Self::max_events(args))), + FormattedSyscallParam::new("timeout", format!("{:#x}", Self::timeout(args))), + ] + } +} + +impl SysEpollWaitHandle { + fn epfd(args: &[usize]) -> i32 { + args[0] as i32 + } + fn events(args: &[usize]) -> VirtAddr { + VirtAddr::new(args[1]) + } + fn max_events(args: &[usize]) -> i32 { + args[2] as i32 + } + fn timeout(args: &[usize]) -> i32 { + args[3] as i32 + } +} + +syscall_table_macros::declare_syscall!(SYS_EPOLL_WAIT, SysEpollWaitHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_fstat.rs b/kernel/src/filesystem/vfs/syscall/sys_fstat.rs new file mode 100644 index 00000000..28bd572e --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_fstat.rs @@ -0,0 +1,47 @@ +//! System call handler for opening files. + +use system_error::SystemError; + +use crate::arch::syscall::nr::SYS_FSTAT; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; + +use crate::arch::interrupt::TrapFrame; +use alloc::string::ToString; +use alloc::vec::Vec; +pub struct SysFstatHandle; + +impl Syscall for SysFstatHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 2 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let fd = Self::fd(args); + let usr_kstat = Self::usr_kstat(args); + crate::syscall::Syscall::newfstat(fd, usr_kstat) + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("fd", Self::fd(args).to_string()), + FormattedSyscallParam::new("statbuf", format!("{:#x}", Self::usr_kstat(args))), + ] + } +} + +impl SysFstatHandle { + /// Extracts the fd argument from syscall parameters. + fn fd(args: &[usize]) -> i32 { + args[0] as i32 + } + + /// Extracts the usr_kstat argument from syscall parameters. + fn usr_kstat(args: &[usize]) -> usize { + args[1] + } +} + +syscall_table_macros::declare_syscall!(SYS_FSTAT, SysFstatHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_ioctl.rs b/kernel/src/filesystem/vfs/syscall/sys_ioctl.rs new file mode 100644 index 00000000..0efeaf08 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_ioctl.rs @@ -0,0 +1,78 @@ +//! System call handler for ioctls. + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_IOCTL; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use system_error::SystemError; + +use alloc::string::ToString; +use alloc::vec::Vec; + +/// Handler for the `ioctl` system call. +pub struct SysIoctlHandle; + +impl Syscall for SysIoctlHandle { + /// Returns the number of arguments this syscall takes (3). + fn num_args(&self) -> usize { + 3 + } + + /// Sends a command to the device corresponding to the file descriptor. + /// + /// # Arguments + /// + /// * `fd` - File descriptor number + /// * `cmd` - Device-dependent request code + /// + /// # Returns + /// + /// * `Ok(usize)` - On success, returns 0 + /// * `Err(SystemError)` - On failure, returns a POSIX error code + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let fd = Self::fd(args); + let cmd = Self::cmd(args); + let data = Self::data(args); + + let binding = ProcessManager::current_pcb().fd_table(); + let fd_table_guard = binding.read(); + + let file = fd_table_guard + .get_file_by_fd(fd as i32) + .ok_or(SystemError::EBADF)?; + + // drop guard 以避免无法调度的问题 + drop(fd_table_guard); + let r = file.inode().ioctl(cmd, data, &file.private_data.lock()); + return r; + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("fd", Self::fd(args).to_string()), + FormattedSyscallParam::new("cmd", format!("{:#x}", Self::cmd(args))), + FormattedSyscallParam::new("data", format!("{:#x}", Self::data(args))), + ] + } +} + +impl SysIoctlHandle { + /// Extracts the file descriptor argument from syscall parameters. + fn fd(args: &[usize]) -> usize { + args[0] + } + + /// Extracts the command argument from syscall parameters. + fn cmd(args: &[usize]) -> u32 { + args[1] as u32 + } + + /// Extracts the data argument from syscall parameters. + fn data(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_IOCTL, SysIoctlHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_lstat.rs b/kernel/src/filesystem/vfs/syscall/sys_lstat.rs new file mode 100644 index 00000000..4e130312 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_lstat.rs @@ -0,0 +1,64 @@ +//! System call handler for opening files. + +use system_error::SystemError; + +use defer::defer; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_LSTAT; +use crate::filesystem::vfs::file::FileMode; +use crate::filesystem::vfs::syscall::sys_close::do_close; +use crate::filesystem::vfs::ModeType; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; + +pub struct SysLstatHandle; + +impl Syscall for SysLstatHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 2 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let path = Self::path(args); + let usr_kstat = Self::usr_kstat(args); + + let fd = super::open_utils::do_open( + path, + FileMode::O_RDONLY.bits(), + ModeType::empty().bits(), + false, + )?; + + defer!({ + do_close(fd as i32).ok(); + }); + crate::syscall::Syscall::newfstat(fd as i32, usr_kstat)?; + + return Ok(0); + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("path", format!("{:#x}", Self::path(args) as usize)), + FormattedSyscallParam::new("statbuf", format!("{:#x}", Self::usr_kstat(args))), + ] + } +} + +impl SysLstatHandle { + /// Extracts the path argument from syscall parameters. + fn path(args: &[usize]) -> *const u8 { + args[0] as *const u8 + } + + /// Extracts the usr_kstat argument from syscall parameters. + fn usr_kstat(args: &[usize]) -> usize { + args[1] + } +} + +syscall_table_macros::declare_syscall!(SYS_LSTAT, SysLstatHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_open.rs b/kernel/src/filesystem/vfs/syscall/sys_open.rs new file mode 100644 index 00000000..3c5ec612 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_open.rs @@ -0,0 +1,58 @@ +//! System call handler for opening files. + +use system_error::SystemError; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_OPEN; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; + +use alloc::string::ToString; +use alloc::vec::Vec; + +/// Handler for the `open` system call. +pub struct SysOpenHandle; + +impl Syscall for SysOpenHandle { + /// Returns the number of arguments this syscall takes (3). + fn num_args(&self) -> usize { + 3 + } + + /// Handles the open syscall by extracting arguments and calling `do_open`. + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let path = Self::path(args); + let flags = Self::flags(args); + let mode = Self::mode(args); + + super::open_utils::do_open(path, flags, mode, true) + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("path", format!("{:#x}", Self::path(args) as usize)), + FormattedSyscallParam::new("flags", Self::flags(args).to_string()), + FormattedSyscallParam::new("mode", Self::mode(args).to_string()), + ] + } +} + +impl SysOpenHandle { + /// Extracts the path argument from syscall parameters. + fn path(args: &[usize]) -> *const u8 { + args[0] as *const u8 + } + + /// Extracts the flags argument from syscall parameters. + fn flags(args: &[usize]) -> u32 { + args[1] as u32 + } + + /// Extracts the mode argument from syscall parameters. + fn mode(args: &[usize]) -> u32 { + args[2] as u32 + } +} + +syscall_table_macros::declare_syscall!(SYS_OPEN, SysOpenHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_read.rs b/kernel/src/filesystem/vfs/syscall/sys_read.rs new file mode 100644 index 00000000..2d57c77c --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_read.rs @@ -0,0 +1,105 @@ +use system_error::SystemError; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_READ; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use crate::syscall::user_access::UserBufferWriter; +use alloc::string::ToString; +use alloc::vec::Vec; + +/// System call handler for the `read` syscall +/// +/// This handler implements the `Syscall` trait to provide functionality for reading data from a file descriptor. +pub struct SysReadHandle; + +impl Syscall for SysReadHandle { + /// Returns the number of arguments expected by the `read` syscall + fn num_args(&self) -> usize { + 3 + } + + /// Handles the `read` system call + /// + /// Reads data from the specified file descriptor into a user buffer. + /// + /// # Arguments + /// * `args` - Array containing: + /// - args[0]: File descriptor (i32) + /// - args[1]: Pointer to user buffer (*mut u8) + /// - args[2]: Length of data to read (usize) + /// * `from_user` - Indicates if the call originates from user space + /// + /// # Returns + /// * `Ok(usize)` - Number of bytes successfully read + /// * `Err(SystemError)` - Error code if operation fails + fn handle(&self, args: &[usize], frame: &mut TrapFrame) -> Result { + let fd = Self::fd(args); + let buf_vaddr = Self::buf(args); + let len = Self::len(args); + + let mut user_buffer_writer = UserBufferWriter::new(buf_vaddr, len, frame.is_from_user())?; + + let user_buf = user_buffer_writer.buffer(0)?; + do_read(fd, user_buf) + } + + /// Formats the syscall parameters for display/debug purposes + /// + /// # Arguments + /// * `args` - The raw syscall arguments + /// + /// # Returns + /// Vector of formatted parameters with descriptive names + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("fd", Self::fd(args).to_string()), + FormattedSyscallParam::new("buf", format!("{:#x}", Self::buf(args) as usize)), + FormattedSyscallParam::new("len", Self::len(args).to_string()), + ] + } +} + +impl SysReadHandle { + /// Extracts the file descriptor from syscall arguments + fn fd(args: &[usize]) -> i32 { + args[0] as i32 + } + + /// Extracts the buffer pointer from syscall arguments + fn buf(args: &[usize]) -> *mut u8 { + args[1] as *mut u8 + } + + /// Extracts the buffer length from syscall arguments + fn len(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_READ, SysReadHandle); + +/// Internal implementation of the read operation +/// +/// # Arguments +/// * `fd` - File descriptor to read from +/// * `buf` - Buffer to store read data +/// +/// # Returns +/// * `Ok(usize)` - Number of bytes successfully read +/// * `Err(SystemError)` - Error code if operation fails +pub(super) fn do_read(fd: i32, buf: &mut [u8]) -> Result { + let binding = ProcessManager::current_pcb().fd_table(); + let fd_table_guard = binding.read(); + + let file = fd_table_guard.get_file_by_fd(fd); + if file.is_none() { + return Err(SystemError::EBADF); + } + // drop guard 以避免无法调度的问题 + drop(fd_table_guard); + let file = file.unwrap(); + + return file.read(buf.len(), buf); +} diff --git a/kernel/src/filesystem/vfs/syscall/sys_readv.rs b/kernel/src/filesystem/vfs/syscall/sys_readv.rs new file mode 100644 index 00000000..9a99d6f5 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_readv.rs @@ -0,0 +1,65 @@ +use system_error::SystemError; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_READV; +use crate::filesystem::vfs::iov::IoVec; +use crate::filesystem::vfs::iov::IoVecs; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::string::ToString; +use alloc::vec::Vec; + +use super::sys_read::do_read; + +/// System call handler for `readv` operation +/// +/// The `readv` system call reads data into multiple buffers from a file descriptor. +/// It is equivalent to multiple `read` calls but is more efficient. +pub struct SysReadVHandle; + +impl Syscall for SysReadVHandle { + fn num_args(&self) -> usize { + 3 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let fd = Self::fd(args); + let iov = Self::iov(args); + let count = Self::count(args); + + // IoVecs会进行用户态检验 + let iovecs = unsafe { IoVecs::from_user(iov, count, true) }?; + + let mut data = vec![0; iovecs.total_len()]; + + let len = do_read(fd, &mut data)?; + + iovecs.scatter(&data[..len]); + + return Ok(len); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("fd", Self::fd(args).to_string()), + FormattedSyscallParam::new("iov", format!("{:#x}", Self::iov(args) as usize)), + FormattedSyscallParam::new("count", Self::count(args).to_string()), + ] + } +} + +impl SysReadVHandle { + fn fd(args: &[usize]) -> i32 { + args[0] as i32 + } + + fn iov(args: &[usize]) -> *const IoVec { + args[1] as *const IoVec + } + + fn count(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_READV, SysReadVHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_stat.rs b/kernel/src/filesystem/vfs/syscall/sys_stat.rs new file mode 100644 index 00000000..a812e4cd --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_stat.rs @@ -0,0 +1,65 @@ +//! System call handler for opening files. + +use system_error::SystemError; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_STAT; +use crate::filesystem::vfs::file::FileMode; +use crate::filesystem::vfs::syscall::sys_close::do_close; +use crate::filesystem::vfs::ModeType; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use defer::defer; + +use alloc::vec::Vec; + +pub struct SysStatHandle; + +impl Syscall for SysStatHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 2 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let path = Self::path(args); + let usr_kstat = Self::usr_kstat(args); + + let fd = super::open_utils::do_open( + path, + FileMode::O_RDONLY.bits(), + ModeType::empty().bits(), + true, + )?; + + defer!({ + do_close(fd as i32).ok(); + }); + + crate::syscall::Syscall::newfstat(fd as i32, usr_kstat)?; + + return Ok(0); + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("path", format!("{:#x}", Self::path(args) as usize)), + FormattedSyscallParam::new("statbuf", format!("{:#x}", Self::usr_kstat(args))), + ] + } +} + +impl SysStatHandle { + /// Extracts the path argument from syscall parameters. + fn path(args: &[usize]) -> *const u8 { + args[0] as *const u8 + } + + /// Extracts the usr_kstat argument from syscall parameters. + fn usr_kstat(args: &[usize]) -> usize { + args[1] + } +} + +syscall_table_macros::declare_syscall!(SYS_STAT, SysStatHandle); diff --git a/kernel/src/filesystem/vfs/syscall/sys_write.rs b/kernel/src/filesystem/vfs/syscall/sys_write.rs new file mode 100644 index 00000000..c0c47e71 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_write.rs @@ -0,0 +1,104 @@ +use system_error::SystemError; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_WRITE; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use crate::syscall::user_access::UserBufferReader; +use alloc::string::ToString; +use alloc::vec::Vec; + +/// System call handler for the `write` syscall +/// +/// This handler implements the `Syscall` trait to provide functionality for writing data to a file descriptor. +pub struct SysWriteHandle; + +impl Syscall for SysWriteHandle { + /// Returns the number of arguments expected by the `write` syscall + fn num_args(&self) -> usize { + 3 + } + + /// Handles the `write` system call + /// + /// Writes data from a user buffer to the specified file descriptor. + /// + /// # Arguments + /// * `args` - Array containing: + /// - args[0]: File descriptor (i32) + /// - args[1]: Pointer to user buffer (*const u8) + /// - args[2]: Length of data to write (usize) + /// * `from_user` - Indicates if the call originates from user space + /// + /// # Returns + /// * `Ok(usize)` - Number of bytes successfully written + /// * `Err(SystemError)` - Error code if operation fails + fn handle(&self, args: &[usize], frame: &mut TrapFrame) -> Result { + let fd = Self::fd(args); + let buf_vaddr = Self::buf(args); + let len = Self::len(args); + + let user_buffer_reader = UserBufferReader::new(buf_vaddr, len, frame.is_from_user())?; + + let user_buf = user_buffer_reader.read_from_user(0)?; + + do_write(fd, user_buf) + } + + /// Formats the syscall parameters for display/debug purposes + /// + /// # Arguments + /// * `args` - The raw syscall arguments + /// + /// # Returns + /// Vector of formatted parameters with descriptive names + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("fd", Self::fd(args).to_string()), + FormattedSyscallParam::new("buf", format!("{:#x}", Self::buf(args) as usize)), + FormattedSyscallParam::new("len", Self::len(args).to_string()), + ] + } +} + +impl SysWriteHandle { + /// Extracts the file descriptor from syscall arguments + fn fd(args: &[usize]) -> i32 { + args[0] as i32 + } + + /// Extracts the buffer pointer from syscall arguments + fn buf(args: &[usize]) -> *const u8 { + args[1] as *const u8 + } + + /// Extracts the buffer length from syscall arguments + fn len(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_WRITE, SysWriteHandle); + +/// Internal implementation of the write operation +/// +/// # Arguments +/// * `fd` - File descriptor to write to +/// * `buf` - Buffer containing data to write +/// +/// # Returns +/// * `Ok(usize)` - Number of bytes successfully written +/// * `Err(SystemError)` - Error code if operation fails +pub(super) fn do_write(fd: i32, buf: &[u8]) -> Result { + let binding = ProcessManager::current_pcb().fd_table(); + let fd_table_guard = binding.read(); + + let file = fd_table_guard + .get_file_by_fd(fd) + .ok_or(SystemError::EBADF)?; + + // drop guard 以避免无法调度的问题 + drop(fd_table_guard); + return file.write(buf.len(), buf); +} diff --git a/kernel/src/filesystem/vfs/syscall/sys_writev.rs b/kernel/src/filesystem/vfs/syscall/sys_writev.rs new file mode 100644 index 00000000..beba0b32 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall/sys_writev.rs @@ -0,0 +1,85 @@ +use system_error::SystemError; + +use crate::arch::syscall::nr::SYS_WRITEV; +use crate::filesystem::vfs::iov::IoVec; +use crate::filesystem::vfs::iov::IoVecs; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; + +use alloc::string::ToString; +use alloc::vec::Vec; + +use super::sys_write::do_write; +use crate::arch::interrupt::TrapFrame; +/// System call handler for `writev` operation +/// +/// The `writev` system call writes data from multiple buffers to a file descriptor. +/// It is equivalent to multiple `write` calls but is more efficient. +pub struct SysWriteVHandle; + +impl Syscall for SysWriteVHandle { + /// Returns the number of arguments required by the `writev` system call + fn num_args(&self) -> usize { + 3 + } + + /// Handles the `writev` system call + /// + /// # Arguments + /// * `args` - System call arguments containing: + /// * `fd`: File descriptor to write to + /// * `iov`: Pointer to array of I/O vectors + /// * `count`: Number of elements in the I/O vector array + /// * `_from_user` - Flag indicating if the call originated from user space + /// + /// # Returns + /// * `Ok(usize)` - Number of bytes written + /// * `Err(SystemError)` - Error that occurred during operation + /// + /// # Safety + /// The caller must ensure the `iov` pointer is valid and points to properly initialized memory. + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let fd = Self::fd(args); + let iov = Self::iov(args); + let count = Self::count(args); + + // IoVecs会进行用户态检验 + let iovecs = unsafe { IoVecs::from_user(iov, count, false) }?; + let data = iovecs.gather(); + do_write(fd, &data) + } + + /// Formats the system call parameters for display/debug purposes + /// + /// # Arguments + /// * `args` - System call arguments to format + /// + /// # Returns + /// Vector of formatted parameters with their names and values + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("fd", Self::fd(args).to_string()), + FormattedSyscallParam::new("iov", format!("{:#x}", Self::iov(args) as usize)), + FormattedSyscallParam::new("count", Self::count(args).to_string()), + ] + } +} + +impl SysWriteVHandle { + /// Extracts the file descriptor from system call arguments + fn fd(args: &[usize]) -> i32 { + args[0] as i32 + } + + /// Extracts the I/O vector pointer from system call arguments + fn iov(args: &[usize]) -> *const IoVec { + args[1] as *const IoVec + } + + /// Extracts the I/O vector count from system call arguments + fn count(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_WRITEV, SysWriteVHandle); diff --git a/kernel/src/filesystem/vfs/core.rs b/kernel/src/filesystem/vfs/vcore.rs similarity index 91% rename from kernel/src/filesystem/vfs/core.rs rename to kernel/src/filesystem/vfs/vcore.rs index 85ea2c4f..b96796f0 100644 --- a/kernel/src/filesystem/vfs/core.rs +++ b/kernel/src/filesystem/vfs/vcore.rs @@ -5,6 +5,7 @@ use log::{error, info}; use system_error::SystemError; use crate::{ + define_event_trace, driver::base::block::{gendisk::GenDisk, manager::block_dev_manager}, filesystem::{ devfs::devfs_init, @@ -25,6 +26,7 @@ use super::{ fcntl::AtFlags, file::FileMode, mount::{init_mountlist, MOUNT_LIST}, + stat::LookUpFlags, syscall::UmountFlag, utils::{rsplit_path, user_path_at}, FilePrivateData, IndexNode, InodeId, VFS_MAX_FOLLOW_SYMLINK_TIMES, @@ -155,7 +157,7 @@ pub fn mount_root_fs() -> Result<(), SystemError> { let fatfs: Arc = fatfs.unwrap(); let r = migrate_virtual_filesystem(fatfs); if r.is_err() { - error!("Failed to migrate virtual filesystem to FAT32!"); + error!("Failed to migrate virtual filesyst em to FAT32!"); loop { spin_loop(); } @@ -165,12 +167,39 @@ pub fn mount_root_fs() -> Result<(), SystemError> { return Ok(()); } +define_event_trace!( + do_mkdir_at, + TP_system(vfs), + TP_PROTO(path:&str, mode: FileMode), + TP_STRUCT__entry { + fmode: FileMode, + path: [u8;64], + }, + TP_fast_assign { + fmode: mode, + path: { + let mut buf = [0u8; 64]; + let path = path.as_bytes(); + let len = path.len().min(63); + buf[..len].copy_from_slice(&path[..len]); + buf[len] = 0; // null-terminate + buf + }, + }, + TP_ident(__entry), + TP_printk({ + let path = core::str::from_utf8(&__entry.path).unwrap_or("invalid utf8"); + let mode = __entry.fmode; + format!("mkdir at {} with mode {:?}", path, mode) + }) +); /// @brief 创建文件/文件夹 pub fn do_mkdir_at( dirfd: i32, path: &str, mode: FileMode, ) -> Result, SystemError> { + trace_do_mkdir_at(path, mode); // debug!("Call do mkdir at"); let (mut current_inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path.trim())?; @@ -392,3 +421,13 @@ pub fn do_umount2( }; return do_umount(); } + +pub(super) fn do_file_lookup_at( + dfd: i32, + path: &str, + lookup_flags: LookUpFlags, +) -> Result, SystemError> { + let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dfd, path)?; + let follow_final = lookup_flags.contains(LookUpFlags::FOLLOW); + return inode.lookup_follow_symlink2(&path, VFS_MAX_FOLLOW_SYMLINK_TIMES, follow_final); +} diff --git a/kernel/src/include/DragonOS/stdint.h b/kernel/src/include/DragonOS/stdint.h deleted file mode 100644 index 63e3b2da..00000000 --- a/kernel/src/include/DragonOS/stdint.h +++ /dev/null @@ -1,316 +0,0 @@ -/* Copyright (C) 1997-2022 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* - * ISO C99: 7.18 Integer types - */ - -#ifndef _STDINT_H -#define _STDINT_H 1 - - - -# define __WORDSIZE 64 - -/* Convenience types. */ -typedef unsigned char __u_char; -typedef unsigned short int __u_short; -typedef unsigned int __u_int; -typedef unsigned long int __u_long; - -/* Fixed-size types, underlying types depend on word size and compiler. */ -typedef signed char __int8_t; -typedef unsigned char __uint8_t; -typedef signed short int __int16_t; -typedef unsigned short int __uint16_t; -typedef signed int __int32_t; -typedef unsigned int __uint32_t; -#if __WORDSIZE == 64 -typedef signed long int __int64_t; -typedef unsigned long int __uint64_t; -#else -__extension__ typedef signed long long int __int64_t; -__extension__ typedef unsigned long long int __uint64_t; -#endif - -/* Smallest types with at least a given width. */ -typedef __int8_t __int_least8_t; -typedef __uint8_t __uint_least8_t; -typedef __int16_t __int_least16_t; -typedef __uint16_t __uint_least16_t; -typedef __int32_t __int_least32_t; -typedef __uint32_t __uint_least32_t; -typedef __int64_t __int_least64_t; -typedef __uint64_t __uint_least64_t; - -typedef __uint8_t uint8_t; -typedef __uint16_t uint16_t; -typedef __uint32_t uint32_t; -typedef __uint64_t uint64_t; - -typedef __int8_t int8_t; -typedef __int16_t int16_t; -typedef __int32_t int32_t; -typedef __int64_t int64_t; - -/* Small types. */ - -/* Signed. */ -typedef __int_least8_t int_least8_t; -typedef __int_least16_t int_least16_t; -typedef __int_least32_t int_least32_t; -typedef __int_least64_t int_least64_t; - -/* Unsigned. */ -typedef __uint_least8_t uint_least8_t; -typedef __uint_least16_t uint_least16_t; -typedef __uint_least32_t uint_least32_t; -typedef __uint_least64_t uint_least64_t; - - -/* Fast types. */ - -/* Signed. */ -typedef signed char int_fast8_t; -#if __WORDSIZE == 64 -typedef long int int_fast16_t; -typedef long int int_fast32_t; -typedef long int int_fast64_t; -#else -typedef int int_fast16_t; -typedef int int_fast32_t; -__extension__ -typedef long long int int_fast64_t; -#endif - -/* Unsigned. */ -typedef unsigned char uint_fast8_t; -#if __WORDSIZE == 64 -typedef unsigned long int uint_fast16_t; -typedef unsigned long int uint_fast32_t; -typedef unsigned long int uint_fast64_t; -#else -typedef unsigned int uint_fast16_t; -typedef unsigned int uint_fast32_t; -__extension__ -typedef unsigned long long int uint_fast64_t; -#endif - - -/* Types for `void *' pointers. */ -#if __WORDSIZE == 64 -# ifndef __intptr_t_defined -typedef long int intptr_t; -# define __intptr_t_defined -# endif -typedef unsigned long int uintptr_t; -#else -# ifndef __intptr_t_defined -typedef int intptr_t; -# define __intptr_t_defined -# endif -typedef unsigned int uintptr_t; -#endif - -/* Largest integral types. */ -#if __WORDSIZE == 64 -typedef long int __intmax_t; -typedef unsigned long int __uintmax_t; -#else -__extension__ typedef long long int __intmax_t; -__extension__ typedef unsigned long long int __uintmax_t; -#endif - - -/* Largest integral types. */ -typedef __intmax_t intmax_t; -typedef __uintmax_t uintmax_t; - - -# if __WORDSIZE == 64 -# define __INT64_C(c) c ## L -# define __UINT64_C(c) c ## UL -# else -# define __INT64_C(c) c ## LL -# define __UINT64_C(c) c ## ULL -# endif - -/* Limits of integral types. */ - -/* Minimum of signed integral types. */ -# define INT8_MIN (-128) -# define INT16_MIN (-32767-1) -# define INT32_MIN (-2147483647-1) -# define INT64_MIN (-__INT64_C(9223372036854775807)-1) -/* Maximum of signed integral types. */ -# define INT8_MAX (127) -# define INT16_MAX (32767) -# define INT32_MAX (2147483647) -# define INT64_MAX (__INT64_C(9223372036854775807)) - -/* Maximum of unsigned integral types. */ -# define UINT8_MAX (255) -# define UINT16_MAX (65535) -# define UINT32_MAX (4294967295U) -# define UINT64_MAX (__UINT64_C(18446744073709551615)) - - -/* Minimum of signed integral types having a minimum size. */ -# define INT_LEAST8_MIN (-128) -# define INT_LEAST16_MIN (-32767-1) -# define INT_LEAST32_MIN (-2147483647-1) -# define INT_LEAST64_MIN (-__INT64_C(9223372036854775807)-1) -/* Maximum of signed integral types having a minimum size. */ -# define INT_LEAST8_MAX (127) -# define INT_LEAST16_MAX (32767) -# define INT_LEAST32_MAX (2147483647) -# define INT_LEAST64_MAX (__INT64_C(9223372036854775807)) - -/* Maximum of unsigned integral types having a minimum size. */ -# define UINT_LEAST8_MAX (255) -# define UINT_LEAST16_MAX (65535) -# define UINT_LEAST32_MAX (4294967295U) -# define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615)) - - -/* Minimum of fast signed integral types having a minimum size. */ -# define INT_FAST8_MIN (-128) -# if __WORDSIZE == 64 -# define INT_FAST16_MIN (-9223372036854775807L-1) -# define INT_FAST32_MIN (-9223372036854775807L-1) -# else -# define INT_FAST16_MIN (-2147483647-1) -# define INT_FAST32_MIN (-2147483647-1) -# endif -# define INT_FAST64_MIN (-__INT64_C(9223372036854775807)-1) -/* Maximum of fast signed integral types having a minimum size. */ -# define INT_FAST8_MAX (127) -# if __WORDSIZE == 64 -# define INT_FAST16_MAX (9223372036854775807L) -# define INT_FAST32_MAX (9223372036854775807L) -# else -# define INT_FAST16_MAX (2147483647) -# define INT_FAST32_MAX (2147483647) -# endif -# define INT_FAST64_MAX (__INT64_C(9223372036854775807)) - -/* Maximum of fast unsigned integral types having a minimum size. */ -# define UINT_FAST8_MAX (255) -# if __WORDSIZE == 64 -# define UINT_FAST16_MAX (18446744073709551615UL) -# define UINT_FAST32_MAX (18446744073709551615UL) -# else -# define UINT_FAST16_MAX (4294967295U) -# define UINT_FAST32_MAX (4294967295U) -# endif -# define UINT_FAST64_MAX (__UINT64_C(18446744073709551615)) - - -/* Values to test for integral types holding `void *' pointer. */ -# if __WORDSIZE == 64 -# define INTPTR_MIN (-9223372036854775807L-1) -# define INTPTR_MAX (9223372036854775807L) -# define UINTPTR_MAX (18446744073709551615UL) -# else -# define INTPTR_MIN (-2147483647-1) -# define INTPTR_MAX (2147483647) -# define UINTPTR_MAX (4294967295U) -# endif - - -/* Minimum for largest signed integral type. */ -# define INTMAX_MIN (-__INT64_C(9223372036854775807)-1) -/* Maximum for largest signed integral type. */ -# define INTMAX_MAX (__INT64_C(9223372036854775807)) - -/* Maximum for largest unsigned integral type. */ -# define UINTMAX_MAX (__UINT64_C(18446744073709551615)) - - -/* Limits of other integer types. */ - -/* Limits of `ptrdiff_t' type. */ -# if __WORDSIZE == 64 -# define PTRDIFF_MIN (-9223372036854775807L-1) -# define PTRDIFF_MAX (9223372036854775807L) -# else -# if __WORDSIZE32_PTRDIFF_LONG -# define PTRDIFF_MIN (-2147483647L-1) -# define PTRDIFF_MAX (2147483647L) -# else -# define PTRDIFF_MIN (-2147483647-1) -# define PTRDIFF_MAX (2147483647) -# endif -# endif - -/* Limits of `sig_atomic_t'. */ -# define SIG_ATOMIC_MIN (-2147483647-1) -# define SIG_ATOMIC_MAX (2147483647) - -/* Limit of `size_t' type. */ -# if __WORDSIZE == 64 -# define SIZE_MAX (18446744073709551615UL) -# else -# if __WORDSIZE32_SIZE_ULONG -# define SIZE_MAX (4294967295UL) -# else -# define SIZE_MAX (4294967295U) -# endif -# endif - -/* Limits of `wchar_t'. */ -# ifndef WCHAR_MIN -/* These constants might also be defined in . */ -# define WCHAR_MIN __WCHAR_MIN -# define WCHAR_MAX __WCHAR_MAX -# endif - -/* Limits of `wint_t'. */ -# define WINT_MIN (0u) -# define WINT_MAX (4294967295u) - -/* Signed. */ -# define INT8_C(c) c -# define INT16_C(c) c -# define INT32_C(c) c -# if __WORDSIZE == 64 -# define INT64_C(c) c ## L -# else -# define INT64_C(c) c ## LL -# endif - -/* Unsigned. */ -# define UINT8_C(c) c -# define UINT16_C(c) c -# define UINT32_C(c) c ## U -# if __WORDSIZE == 64 -# define UINT64_C(c) c ## UL -# else -# define UINT64_C(c) c ## ULL -# endif - -/* Maximal type. */ -# if __WORDSIZE == 64 -# define INTMAX_C(c) c ## L -# define UINTMAX_C(c) c ## UL -# else -# define INTMAX_C(c) c ## LL -# define UINTMAX_C(c) c ## ULL -# endif - - -#endif /* stdint.h */ \ No newline at end of file diff --git a/kernel/src/include/bindings/mod.rs b/kernel/src/include/bindings/mod.rs index 4ab2c21e..2aaff584 100644 --- a/kernel/src/include/bindings/mod.rs +++ b/kernel/src/include/bindings/mod.rs @@ -6,5 +6,4 @@ missing_docs, clippy::module_inception )] -pub mod bindings; pub mod linux_bpf; diff --git a/kernel/src/include/bindings/wrapper.h b/kernel/src/include/bindings/wrapper.h deleted file mode 100644 index f4f160d5..00000000 --- a/kernel/src/include/bindings/wrapper.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @file sched-wrapper.h - * @author longjin (longjin@RinGoTek.cn) - * @brief 这是为调度器相关接口创建rust绑定的wrapper - * @version 0.1 - * @date 2022-11-10 - * - * @copyright Copyright (c) 2022 - * - */ -#pragma once - diff --git a/kernel/src/init/boot.rs b/kernel/src/init/boot.rs index ec345fd2..d455d02a 100644 --- a/kernel/src/init/boot.rs +++ b/kernel/src/init/boot.rs @@ -102,7 +102,7 @@ impl BootParams { #[cfg(target_arch = "riscv64")] return Some(self.arch.arch_fdt()); - #[cfg(target_arch = "x86_64")] + #[cfg(any(target_arch = "x86_64", target_arch = "loongarch64"))] return None; } @@ -112,7 +112,7 @@ impl BootParams { #[cfg(target_arch = "riscv64")] return Some(self.arch.fdt_paddr); - #[cfg(target_arch = "x86_64")] + #[cfg(any(target_arch = "x86_64", target_arch = "loongarch64"))] return None; } } diff --git a/kernel/src/init/cmdline.rs b/kernel/src/init/cmdline.rs index a313be51..0676e1df 100644 --- a/kernel/src/init/cmdline.rs +++ b/kernel/src/init/cmdline.rs @@ -321,6 +321,7 @@ impl KernelCmdlineManager { continue; } + log::debug!("cmdline: argument: {:?} ", argument); let (node, option, value) = match self.split_arg(argument) { Some(v) => v, None => continue, diff --git a/kernel/src/init/init.rs b/kernel/src/init/init.rs index 0be5bce2..8907c88e 100644 --- a/kernel/src/init/init.rs +++ b/kernel/src/init/init.rs @@ -9,7 +9,7 @@ use crate::{ video::VideoRefreshManager, }, exception::{init::irq_init, softirq::softirq_init, InterruptArch}, - filesystem::vfs::core::vfs_init, + filesystem::vfs::vcore::vfs_init, init::init_intertrait, libs::{ futex::futex::Futex, @@ -23,7 +23,7 @@ use crate::{ process::{kthread::kthread_init, process_init, ProcessManager}, sched::SchedArch, smp::{early_smp_init, SMPArch}, - syscall::Syscall, + syscall::{syscall_init, Syscall}, time::{ clocksource::clocksource_boot_finish, timekeeping::timekeeping_init, timer::timer_init, }, @@ -69,6 +69,8 @@ fn do_start_kernel() { init_intertrait(); + syscall_init().expect("syscall init failed"); + vfs_init().expect("vfs init failed"); driver_init().expect("driver init failed"); @@ -93,16 +95,17 @@ fn do_start_kernel() { crate::bpf::init_bpf_system(); crate::debug::jump_label::static_keys_init(); - // #[cfg(all(target_arch = "x86_64", feature = "kvm"))] - // crate::virt::kvm::kvm_init(); #[cfg(all(target_arch = "x86_64", feature = "kvm"))] - crate::arch::vm::vmx::vmx_init().unwrap(); + if crate::arch::vm::vmx::vmx_init().is_err() { + log::warn!("vmx init failed, will not be enabled"); + } } /// 在内存管理初始化之前,执行的初始化 #[inline(never)] fn init_before_mem_init() { serial_early_init().expect("serial early init failed"); + let video_ok = unsafe { VideoRefreshManager::video_init().is_ok() }; scm_init(video_ok); diff --git a/kernel/src/init/initial_kthread.rs b/kernel/src/init/initial_kthread.rs index a79c59da..10a8fdc8 100644 --- a/kernel/src/init/initial_kthread.rs +++ b/kernel/src/init/initial_kthread.rs @@ -8,25 +8,24 @@ use system_error::SystemError; use crate::{ arch::{interrupt::TrapFrame, process::arch_switch_to_user}, - driver::{net::e1000e::e1000e::e1000e_init, virtio::virtio::virtio_probe}, - filesystem::vfs::core::mount_root_fs, + driver::net::e1000e::e1000e::e1000e_init, + filesystem::vfs::vcore::mount_root_fs, namespaces::NsProxy, net::net_core::net_init, process::{ - exec::ProcInitInfo, kthread::KernelThreadMechanism, stdio::stdio_init, ProcessFlags, - ProcessManager, + exec::ProcInitInfo, execve::do_execve, kthread::KernelThreadMechanism, stdio::stdio_init, + ProcessFlags, ProcessManager, }, smp::smp_init, - syscall::Syscall, }; use super::{cmdline::kenrel_cmdline_param_manager, initcall::do_initcalls}; const INIT_PROC_TRYLIST: [(&str, Option<&str>); 4] = [ ("/bin/dragonreach", None), + ("/bin/busybox", Some("init")), ("/bin/init", None), ("/bin/sh", None), - ("/bin/busybox", Some("init")), ]; pub fn initial_kernel_thread() -> i32 { @@ -45,7 +44,7 @@ fn kernel_init() -> Result<(), SystemError> { crate::driver::disk::ahci::ahci_init() .inspect_err(|e| log::error!("ahci_init failed: {:?}", e)) .ok(); - virtio_probe(); + mount_root_fs().expect("Failed to mount root fs"); e1000e_init(); net_init().unwrap_or_else(|err| { @@ -128,6 +127,7 @@ fn try_to_run_init_process( ext_args: &Option<&str>, trap_frame: &mut TrapFrame, ) -> Result<(), SystemError> { + log::debug!("Trying to run init process at {:?}", path); let mut args_to_insert = alloc::vec::Vec::new(); args_to_insert.push(CString::new(path).unwrap()); @@ -163,7 +163,7 @@ fn run_init_process( ProcessManager::current_pcb().set_nsproxy(NsProxy::new()); // 初始化init进程的namespace let path = proc_init_info.proc_name.to_str().unwrap(); - Syscall::do_execve( + do_execve( path.to_string(), proc_init_info.args.clone(), proc_init_info.envs.clone(), diff --git a/kernel/src/ipc/generic_signal.rs b/kernel/src/ipc/generic_signal.rs new file mode 100644 index 00000000..9aba1f24 --- /dev/null +++ b/kernel/src/ipc/generic_signal.rs @@ -0,0 +1,206 @@ +use num_traits::FromPrimitive; + +use crate::arch::ipc::signal::{SigSet, MAX_SIG_NUM}; + +/// 信号处理的栈的栈指针的最小对齐 +#[allow(dead_code)] +pub const GENERIC_STACK_ALIGN: u64 = 16; +/// 信号最大值 +#[allow(dead_code)] +pub const GENERIC_MAX_SIG_NUM: usize = 64; + +#[allow(dead_code)] +#[derive(Eq, PartialEq, FromPrimitive)] +#[repr(usize)] +#[allow(non_camel_case_types)] +#[atomic_enum] +pub enum GenericSignal { + INVALID = 0, + SIGHUP = 1, + SIGINT, + SIGQUIT, + SIGILL, + SIGTRAP, + /// SIGABRT和SIGIOT共用这个号码 + SIGABRT_OR_IOT, + SIGBUS, + SIGFPE, + SIGKILL, + SIGUSR1, + + SIGSEGV = 11, + SIGUSR2, + SIGPIPE, + SIGALRM, + SIGTERM, + SIGSTKFLT, + SIGCHLD, + SIGCONT, + SIGSTOP, + SIGTSTP, + + SIGTTIN = 21, + SIGTTOU, + SIGURG, + SIGXCPU, + SIGXFSZ, + SIGVTALRM, + SIGPROF, + SIGWINCH, + /// SIGIO和SIGPOLL共用这个号码 + SIGIO_OR_POLL, + SIGPWR, + + SIGSYS = 31, + + SIGRTMIN = 32, + SIGRTMAX = 64, +} + +impl GenericSignal { + /// 判断一个数字是否为可用的信号 + #[inline] + pub fn is_valid(&self) -> bool { + return (*self) as usize <= MAX_SIG_NUM; + } + + /// const convertor between `Signal` and `SigSet` + pub const fn into_sigset(self) -> SigSet { + SigSet::from_bits_truncate(1 << (self as usize - 1)) + } + + /// 判断一个信号是不是实时信号 + /// + /// ## 返回值 + /// + /// - `true` 这个信号是实时信号 + /// - `false` 这个信号不是实时信号 + #[inline] + pub fn is_rt_signal(&self) -> bool { + return (*self) as usize >= Self::SIGRTMIN.into(); + } +} + +impl From for usize { + fn from(val: GenericSignal) -> Self { + val as usize + } +} + +impl From for GenericSignal { + fn from(value: usize) -> Self { + ::from_usize(value).unwrap_or(GenericSignal::INVALID) + } +} + +impl From for GenericSignal { + fn from(value: i32) -> Self { + if value < 0 { + log::error!("Try to convert an invalid number to GenericSignal"); + return GenericSignal::INVALID; + } else { + return Self::from(value as usize); + } + } +} + +impl From for GenericSigSet { + fn from(val: GenericSignal) -> Self { + GenericSigSet { + bits: (1 << (val as usize - 1) as u64), + } + } +} + +/// SIGCHLD si_codes +#[derive(Debug, Clone, Copy, PartialEq, Eq, ToPrimitive)] +#[allow(dead_code)] +pub enum GenericSigChildCode { + /// child has exited + /// + /// CLD_EXITED + Exited = 1, + /// child was killed + /// + /// CLD_KILLED + Killed = 2, + /// child terminated abnormally + /// + /// CLD_DUMPED + Dumped = 3, + /// traced child has trapped + /// + /// CLD_TRAPPED + Trapped = 4, + /// child has stopped + /// + /// CLD_STOPPED + Stopped = 5, + /// stopped child has continued + /// + /// CLD_CONTINUED + Continued = 6, +} + +impl From for i32 { + fn from(value: GenericSigChildCode) -> Self { + value as i32 + } +} + +bitflags! { + /// 请注意,sigset 这个bitmap, 第0位表示sig=1的信号。也就是说,Signal-1才是sigset_t中对应的位 + #[derive(Default)] + pub struct GenericSigSet:u64 { + const SIGHUP = 1<<0; + const SIGINT = 1<<1; + const SIGQUIT = 1<<2; + const SIGILL = 1<<3; + const SIGTRAP = 1<<4; + /// SIGABRT和SIGIOT共用这个号码 + const SIGABRT_OR_IOT = 1<<5; + const SIGBUS = 1<<6; + const SIGFPE = 1<<7; + const SIGKILL = 1<<8; + const SIGUSR = 1<<9; + const SIGSEGV = 1<<10; + const SIGUSR2 = 1<<11; + const SIGPIPE = 1<<12; + const SIGALRM = 1<<13; + const SIGTERM = 1<<14; + const SIGSTKFLT= 1<<15; + const SIGCHLD = 1<<16; + const SIGCONT = 1<<17; + const SIGSTOP = 1<<18; + const SIGTSTP = 1<<19; + const SIGTTIN = 1<<20; + const SIGTTOU = 1<<21; + const SIGURG = 1<<22; + const SIGXCPU = 1<<23; + const SIGXFSZ = 1<<24; + const SIGVTALRM= 1<<25; + const SIGPROF = 1<<26; + const SIGWINCH = 1<<27; + /// SIGIO和SIGPOLL共用这个号码 + const SIGIO_OR_POLL = 1<<28; + const SIGPWR = 1<<29; + const SIGSYS = 1<<30; + const SIGRTMIN = 1<<31; + // TODO 写上实时信号 + const SIGRTMAX = 1 << (GENERIC_MAX_SIG_NUM-1); + } + + #[repr(C,align(8))] + #[derive(Default)] + pub struct GenericSigFlags:u32{ + const SA_NOCLDSTOP = 1; + const SA_NOCLDWAIT = 2; + const SA_SIGINFO = 4; + const SA_ONSTACK = 0x08000000; + const SA_RESTART = 0x10000000; + const SA_NODEFER = 0x40000000; + const SA_RESETHAND = 0x80000000; + const SA_RESTORER =0x04000000; + const SA_ALL = Self::SA_NOCLDSTOP.bits()|Self::SA_NOCLDWAIT.bits()|Self::SA_NODEFER.bits()|Self::SA_ONSTACK.bits()|Self::SA_RESETHAND.bits()|Self::SA_RESTART.bits()|Self::SA_SIGINFO.bits()|Self::SA_RESTORER.bits(); + } +} diff --git a/kernel/src/ipc/kill.rs b/kernel/src/ipc/kill.rs new file mode 100644 index 00000000..cc0065ce --- /dev/null +++ b/kernel/src/ipc/kill.rs @@ -0,0 +1,44 @@ +use crate::arch::ipc::signal::{SigCode, Signal}; +use crate::ipc::signal_types::{SigInfo, SigType}; +use crate::process::{process_group::Pgid, Pid, ProcessManager}; +use core::sync::atomic::compiler_fence; +use system_error::SystemError; + +/// ### 杀死一个进程 +pub fn kill_process(pid: Pid, sig: Signal) -> Result { + // 初始化signal info + let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid)); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + let ret = sig + .send_signal_info(Some(&mut info), pid) + .map(|x| x as usize); + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + ret +} + +/// ### 杀死一个进程组 +pub fn kill_process_group(pgid: Pgid, sig: Signal) -> Result { + let pg = ProcessManager::find_process_group(pgid).ok_or(SystemError::ESRCH)?; + let inner = pg.process_group_inner.lock(); + for pcb in inner.processes.values() { + kill_process(pcb.pid(), sig)?; // Call the new common function + } + Ok(0) +} + +/// ### 杀死所有进程 +/// - 该函数会杀死所有进程,除了当前进程和init进程 +pub fn kill_all(sig: Signal) -> Result { + let current_pid = ProcessManager::current_pcb().pid(); + let all_processes = ProcessManager::get_all_processes(); + + for pid_val in all_processes { + if pid_val == current_pid || pid_val.data() == 1 { + continue; + } + kill_process(pid_val, sig)?; // Call the new common function + } + Ok(0) +} diff --git a/kernel/src/ipc/mod.rs b/kernel/src/ipc/mod.rs index 8f794a65..8b1d5b32 100644 --- a/kernel/src/ipc/mod.rs +++ b/kernel/src/ipc/mod.rs @@ -1,3 +1,5 @@ +pub mod generic_signal; +pub mod kill; pub mod pipe; pub mod shm; pub mod signal; diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index b4a5bb79..34c1578a 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -2,15 +2,17 @@ use core::sync::atomic::compiler_fence; use crate::{ arch::ipc::signal::{SigCode, Signal}, - filesystem::vfs::{ - core::generate_inode_id, file::FileMode, syscall::ModeType, FilePrivateData, FileSystem, - FileType, IndexNode, Metadata, + filesystem::{ + epoll::{event_poll::EventPoll, EPollEventType, EPollItem}, + vfs::{ + file::FileMode, syscall::ModeType, vcore::generate_inode_id, FilePrivateData, + FileSystem, FileType, IndexNode, Metadata, PollableInode, + }, }, libs::{ spinlock::{SpinLock, SpinLockGuard}, wait_queue::WaitQueue, }, - net::event_poll::{EPollEventType, EPollItem, EventPoll}, process::{ProcessFlags, ProcessManager, ProcessState}, sched::SchedMode, time::PosixTimeSpec, @@ -19,7 +21,6 @@ use crate::{ use alloc::{ collections::LinkedList, sync::{Arc, Weak}, - vec::Vec, }; use system_error::SystemError; @@ -129,6 +130,7 @@ impl LockedPipeInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::Pipe, mode: ModeType::from_bits_truncate(0o666), nlinks: 1, @@ -165,24 +167,33 @@ impl LockedPipeInode { let inode = self.inner.lock(); return !inode.buf_full() || inode.reader == 0; } +} - pub fn add_epoll(&self, epitem: Arc) -> Result<(), SystemError> { +impl PollableInode for LockedPipeInode { + fn poll(&self, private_data: &FilePrivateData) -> Result { + self.inner.lock().poll(private_data) + } + + fn add_epitem( + &self, + epitem: Arc, + _private_data: &FilePrivateData, + ) -> Result<(), SystemError> { self.epitems.lock().push_back(epitem); Ok(()) } - pub fn remove_epoll(&self, epoll: &Weak>) -> Result<(), SystemError> { - let is_remove = !self - .epitems - .lock_irqsave() - .extract_if(|x| x.epoll().ptr_eq(epoll)) - .collect::>() - .is_empty(); - - if is_remove { + fn remove_epitem( + &self, + epitem: &Arc, + _private_data: &FilePrivateData, + ) -> Result<(), SystemError> { + let mut guard = self.epitems.lock(); + let len = guard.len(); + guard.retain(|x| !Arc::ptr_eq(x, epitem)); + if len != guard.len() { return Ok(()); } - Err(SystemError::ENOENT) } } @@ -279,7 +290,7 @@ impl IndexNode for LockedPipeInode { let pollflag = EPollEventType::from_bits_truncate(inner_guard.poll(&data)? as u32); drop(inner_guard); // 唤醒epoll中等待的进程 - EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; + EventPoll::wakeup_epoll(&self.epitems, pollflag)?; //返回读取的字节数 return Ok(num); @@ -468,7 +479,7 @@ impl IndexNode for LockedPipeInode { drop(inner_guard); // 唤醒epoll中等待的进程 - EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; + EventPoll::wakeup_epoll(&self.epitems, pollflag)?; // 返回写入的字节数 return Ok(len); @@ -496,7 +507,7 @@ impl IndexNode for LockedPipeInode { return Err(SystemError::ENOSYS); } - fn poll(&self, private_data: &FilePrivateData) -> Result { - return self.inner.lock().poll(private_data); + fn as_pollable_inode(&self) -> Result<&dyn PollableInode, SystemError> { + Ok(self) } } diff --git a/kernel/src/ipc/shm.rs b/kernel/src/ipc/shm.rs index e2c0187f..b04ae324 100644 --- a/kernel/src/ipc/shm.rs +++ b/kernel/src/ipc/shm.rs @@ -14,13 +14,13 @@ use crate::{ syscall::user_access::{UserBufferReader, UserBufferWriter}, time::PosixTimeSpec, }; +use core::fmt; use core::sync::atomic::{compiler_fence, Ordering}; use hashbrown::HashMap; use ida::IdAllocator; use log::info; use num::ToPrimitive; use system_error::SystemError; - pub static mut SHM_MANAGER: Option> = None; /// 用于创建新的私有IPC对象 @@ -104,6 +104,23 @@ impl From for ShmCtlCmd { } } +impl fmt::Display for ShmCtlCmd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ShmCtlCmd::IpcRmid => write!(f, "IPC_RMID"), + ShmCtlCmd::IpcSet => write!(f, "IPC_SET"), + ShmCtlCmd::IpcStat => write!(f, "IPC_STAT"), + ShmCtlCmd::IpcInfo => write!(f, "IPC_INFO"), + ShmCtlCmd::ShmLock => write!(f, "SHM_LOCK"), + ShmCtlCmd::ShmUnlock => write!(f, "SHM_UNLOCK"), + ShmCtlCmd::ShmStat => write!(f, "SHM_STAT"), + ShmCtlCmd::ShmInfo => write!(f, "SHM_INFO"), + ShmCtlCmd::ShmtStatAny => write!(f, "SHM_STAT_ANY"), + ShmCtlCmd::Default => write!(f, "DEFAULT (Invalid Cmd)"), + } + } +} + impl PartialEq for ShmCtlCmd { fn eq(&self, other: &ShmCtlCmd) -> bool { *self as usize == *other as usize diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 1f5ee768..ce84408b 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -419,6 +419,16 @@ pub fn restore_saved_sigmask() { } } +pub fn restore_saved_sigmask_unless(interrupted: bool) { + if interrupted { + if !ProcessManager::current_pcb().has_pending_signal_fast() { + log::warn!("restore_saved_sigmask_unless: interrupted, but has NO pending signal"); + } + } else { + restore_saved_sigmask(); + } +} + /// 刷新指定进程的sighand的sigaction,将满足条件的sigaction恢复为默认状态。 /// 除非某个信号被设置为忽略且 `force_default` 为 `false`,否则都不会将其恢复。 /// diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index befeda02..124c3e5d 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -78,7 +78,11 @@ impl SignalStruct { let mut r = Self { inner: Box::::default(), }; - let sig_ign = Sigaction::default(); + let mut sig_ign = Sigaction::default(); + // 收到忽略的信号,重启系统调用 + // todo: 看看linux哪些 + sig_ign.flags_mut().insert(SigFlags::SA_RESTART); + r.inner.handlers[Signal::SIGCHLD as usize - 1] = sig_ign; r.inner.handlers[Signal::SIGURG as usize - 1] = sig_ign; r.inner.handlers[Signal::SIGWINCH as usize - 1] = sig_ign; diff --git a/kernel/src/ipc/syscall.rs b/kernel/src/ipc/syscall.rs deleted file mode 100644 index 90d4ddc4..00000000 --- a/kernel/src/ipc/syscall.rs +++ /dev/null @@ -1,565 +0,0 @@ -use core::{ - ffi::{c_int, c_void}, - sync::atomic::compiler_fence, -}; - -use log::{error, warn}; -use system_error::SystemError; - -use crate::{ - arch::{ - ipc::signal::{SigCode, SigFlags, SigSet, Signal}, - MMArch, - }, - filesystem::vfs::{ - file::{File, FileMode}, - FilePrivateData, - }, - ipc::shm::{shm_manager_lock, IPC_PRIVATE}, - libs::{align::page_align_up, spinlock::SpinLock}, - mm::{ - allocator::page_frame::{PageFrameCount, PhysPageFrame, VirtPageFrame}, - page::{page_manager_lock_irqsave, EntryFlags, PageFlushAll}, - syscall::ProtFlags, - ucontext::{AddressSpace, VMA}, - VirtAddr, VmFlags, - }, - process::{Pid, ProcessManager}, - syscall::{ - user_access::{UserBufferReader, UserBufferWriter}, - Syscall, - }, -}; - -use super::{ - pipe::{LockedPipeInode, PipeFsPrivateData}, - shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey}, - signal::{set_sigprocmask, SigHow}, - signal_types::{ - SaHandlerType, SigInfo, SigType, Sigaction, SigactionType, UserSigaction, USER_SIG_DFL, - USER_SIG_ERR, USER_SIG_IGN, - }, -}; - -impl Syscall { - /// # 创建带参数的匿名管道 - /// - /// ## 参数 - /// - /// - `fd`: 用于返回文件描述符的数组 - /// - `flags`:设置管道的参数 - pub fn pipe2(fd: *mut i32, flags: FileMode) -> Result { - if !flags - .difference(FileMode::O_CLOEXEC | FileMode::O_NONBLOCK | FileMode::O_DIRECT) - .is_empty() - { - return Err(SystemError::EINVAL); - } - - let mut user_buffer = UserBufferWriter::new(fd, core::mem::size_of::<[c_int; 2]>(), true)?; - let fd = user_buffer.buffer::(0)?; - let pipe_ptr = LockedPipeInode::new(); - - let mut read_file = File::new( - pipe_ptr.clone(), - FileMode::O_RDONLY | (flags & FileMode::O_NONBLOCK), - )?; - read_file.private_data = SpinLock::new(FilePrivateData::Pipefs(PipeFsPrivateData::new( - FileMode::O_RDONLY, - ))); - - let mut write_file = File::new( - pipe_ptr.clone(), - FileMode::O_WRONLY | (flags & (FileMode::O_NONBLOCK | FileMode::O_DIRECT)), - )?; - write_file.private_data = SpinLock::new(FilePrivateData::Pipefs(PipeFsPrivateData::new( - FileMode::O_WRONLY | (flags & (FileMode::O_NONBLOCK | FileMode::O_DIRECT)), - ))); - - if flags.contains(FileMode::O_CLOEXEC) { - read_file.set_close_on_exec(true); - write_file.set_close_on_exec(true); - } - let fd_table_ptr = ProcessManager::current_pcb().fd_table(); - let mut fd_table_guard = fd_table_ptr.write(); - let read_fd = fd_table_guard.alloc_fd(read_file, None)?; - let write_fd = fd_table_guard.alloc_fd(write_file, None)?; - - drop(fd_table_guard); - - fd[0] = read_fd; - fd[1] = write_fd; - Ok(0) - } - - pub fn kill(pid: Pid, sig: c_int) -> Result { - let sig = Signal::from(sig); - if sig == Signal::INVALID { - // 传入的signal数值不合法 - warn!("Not a valid signal number"); - return Err(SystemError::EINVAL); - } - - // 初始化signal info - let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid)); - - compiler_fence(core::sync::atomic::Ordering::SeqCst); - - let retval = sig - .send_signal_info(Some(&mut info), pid) - .map(|x| x as usize); - - compiler_fence(core::sync::atomic::Ordering::SeqCst); - - return retval; - } - - /// 通用信号注册函数 - /// - /// ## 参数 - /// - /// - `sig` 信号的值 - /// - `act` 用户空间传入的 Sigaction 指针 - /// - `old_act` 用户空间传入的用来保存旧 Sigaction 的指针 - /// - `from_user` 用来标识这个函数调用是否来自用户空间 - /// - /// @return int 错误码 - #[no_mangle] - pub fn sigaction( - sig: c_int, - new_act: usize, - old_act: usize, - from_user: bool, - ) -> Result { - // 请注意:用户态传进来的user_sigaction结构体类型,请注意,这个结构体与内核实际的不一样 - let act: *mut UserSigaction = new_act as *mut UserSigaction; - let old_act = old_act as *mut UserSigaction; - let mut new_ka: Sigaction = Default::default(); - let mut old_sigaction: Sigaction = Default::default(); - // 如果传入的,新的sigaction不为空 - if !act.is_null() { - // 如果参数的范围不在用户空间,则返回错误 - let r = UserBufferWriter::new(act, core::mem::size_of::(), from_user); - if r.is_err() { - return Err(SystemError::EFAULT); - } - let mask: SigSet = unsafe { (*act).mask }; - let input_sighandler = unsafe { (*act).handler as u64 }; - match input_sighandler { - USER_SIG_DFL => { - new_ka = Sigaction::DEFAULT_SIGACTION; - *new_ka.flags_mut() = unsafe { (*act).flags }; - new_ka.set_restorer(None); - } - - USER_SIG_IGN => { - new_ka = Sigaction::DEFAULT_SIGACTION_IGNORE; - *new_ka.flags_mut() = unsafe { (*act).flags }; - - new_ka.set_restorer(None); - } - _ => { - // 从用户空间获得sigaction结构体 - // TODO mask是default还是用户空间传入 - new_ka = Sigaction::new( - SigactionType::SaHandler(SaHandlerType::Customized(unsafe { - VirtAddr::new((*act).handler as usize) - })), - unsafe { (*act).flags }, - SigSet::default(), - unsafe { Some(VirtAddr::new((*act).restorer as usize)) }, - ); - } - } - - // TODO 如果为空,赋默认值? - // debug!("new_ka={:?}", new_ka); - // 如果用户手动给了sa_restorer,那么就置位SA_FLAG_RESTORER,否则报错。(用户必须手动指定restorer) - if new_ka.restorer().is_some() { - new_ka.flags_mut().insert(SigFlags::SA_RESTORER); - } else if new_ka.action().is_customized() { - error!( - "pid:{:?}: in sys_sigaction: User must manually sprcify a sa_restorer for signal {}.", - ProcessManager::current_pcb().pid(), - sig - ); - return Err(SystemError::EINVAL); - } - *new_ka.mask_mut() = mask; - } - - let sig = Signal::from(sig); - // 如果给出的信号值不合法 - if sig == Signal::INVALID { - return Err(SystemError::EINVAL); - } - - let retval = super::signal::do_sigaction( - sig, - if act.is_null() { - None - } else { - Some(&mut new_ka) - }, - if old_act.is_null() { - None - } else { - Some(&mut old_sigaction) - }, - ); - - // - if (retval == Ok(())) && (!old_act.is_null()) { - let r = - UserBufferWriter::new(old_act, core::mem::size_of::(), from_user); - if r.is_err() { - return Err(SystemError::EFAULT); - } - - let sigaction_handler = match old_sigaction.action() { - SigactionType::SaHandler(handler) => { - if let SaHandlerType::Customized(hand) = handler { - hand - } else if handler.is_sig_ignore() { - VirtAddr::new(USER_SIG_IGN as usize) - } else if handler.is_sig_error() { - VirtAddr::new(USER_SIG_ERR as usize) - } else { - VirtAddr::new(USER_SIG_DFL as usize) - } - } - SigactionType::SaSigaction(_) => { - error!("unsupported type: SaSigaction"); - VirtAddr::new(USER_SIG_DFL as usize) - } - }; - - unsafe { - (*old_act).handler = sigaction_handler.data() as *mut c_void; - (*old_act).flags = old_sigaction.flags(); - (*old_act).mask = old_sigaction.mask(); - if old_sigaction.restorer().is_some() { - (*old_act).restorer = old_sigaction.restorer().unwrap().data() as *mut c_void; - } - } - } - return retval.map(|_| 0); - } - - /// # SYS_SHMGET系统调用函数,用于获取共享内存 - /// - /// ## 参数 - /// - /// - `key`: 共享内存键值 - /// - `size`: 共享内存大小(bytes) - /// - `shmflg`: 共享内存标志 - /// - /// ## 返回值 - /// - /// 成功:共享内存id - /// 失败:错误码 - pub fn shmget(key: ShmKey, size: usize, shmflg: ShmFlags) -> Result { - // 暂不支持巨页 - if shmflg.contains(ShmFlags::SHM_HUGETLB) { - error!("shmget: not support huge page"); - return Err(SystemError::ENOSYS); - } - - let mut shm_manager_guard = shm_manager_lock(); - match key { - // 创建共享内存段 - IPC_PRIVATE => shm_manager_guard.add(key, size, shmflg), - _ => { - // 查找key对应的共享内存段是否存在 - let id = shm_manager_guard.contains_key(&key); - if let Some(id) = id { - // 不能重复创建 - if shmflg.contains(ShmFlags::IPC_CREAT | ShmFlags::IPC_EXCL) { - return Err(SystemError::EEXIST); - } - - // key值存在,说明有对应共享内存,返回该共享内存id - return Ok(id.data()); - } else { - // key不存在且shm_flags不包含IPC_CREAT创建IPC对象标志,则返回错误码 - if !shmflg.contains(ShmFlags::IPC_CREAT) { - return Err(SystemError::ENOENT); - } - - // 存在创建IPC对象标志 - return shm_manager_guard.add(key, size, shmflg); - } - } - } - } - - /// # SYS_SHMAT系统调用函数,用于连接共享内存段 - /// - /// ## 参数 - /// - /// - `id`: 共享内存id - /// - `vaddr`: 连接共享内存的进程虚拟内存区域起始地址 - /// - `shmflg`: 共享内存标志 - /// - /// ## 返回值 - /// - /// 成功:映射到共享内存的虚拟内存区域起始地址 - /// 失败:错误码 - pub fn shmat(id: ShmId, vaddr: VirtAddr, shmflg: ShmFlags) -> Result { - let mut shm_manager_guard = shm_manager_lock(); - let current_address_space = AddressSpace::current()?; - let mut address_write_guard = current_address_space.write(); - - let kernel_shm = shm_manager_guard.get_mut(&id).ok_or(SystemError::EINVAL)?; - let size = page_align_up(kernel_shm.size()); - let mut phys = PhysPageFrame::new(kernel_shm.start_paddr()); - let count = PageFrameCount::from_bytes(size).unwrap(); - let r = match vaddr.data() { - // 找到空闲区域并映射到共享内存 - 0 => { - // 找到空闲区域 - let region = address_write_guard - .mappings - .find_free(vaddr, size) - .ok_or(SystemError::EINVAL)?; - let vm_flags = VmFlags::from(shmflg); - let destination = VirtPageFrame::new(region.start()); - let page_flags: EntryFlags = - EntryFlags::from_prot_flags(ProtFlags::from(vm_flags), true); - let flusher: PageFlushAll = PageFlushAll::new(); - - // 将共享内存映射到对应虚拟区域 - let vma = VMA::physmap( - phys, - destination, - count, - vm_flags, - page_flags, - &mut address_write_guard.user_mapper.utable, - flusher, - )?; - - // 将VMA加入到当前进程的VMA列表中 - address_write_guard.mappings.insert_vma(vma); - - region.start().data() - } - // 指定虚拟地址 - _ => { - // 获取对应vma - let vma = address_write_guard - .mappings - .contains(vaddr) - .ok_or(SystemError::EINVAL)?; - if vma.lock_irqsave().region().start() != vaddr { - return Err(SystemError::EINVAL); - } - - // 验证用户虚拟内存区域是否有效 - let _ = UserBufferReader::new(vaddr.data() as *const u8, size, true)?; - - // 必须在取消映射前获取到EntryFlags - let page_flags = address_write_guard - .user_mapper - .utable - .translate(vaddr) - .ok_or(SystemError::EINVAL)? - .1; - - // 取消原映射 - let flusher: PageFlushAll = PageFlushAll::new(); - vma.unmap(&mut address_write_guard.user_mapper.utable, flusher); - - // 将该虚拟内存区域映射到共享内存区域 - let mut page_manager_guard = page_manager_lock_irqsave(); - let mut virt = VirtPageFrame::new(vaddr); - for _ in 0..count.data() { - let r = unsafe { - address_write_guard.user_mapper.utable.map_phys( - virt.virt_address(), - phys.phys_address(), - page_flags, - ) - } - .expect("Failed to map zero, may be OOM error"); - r.flush(); - - // 将vma加入到对应Page的anon_vma - page_manager_guard - .get_unwrap(&phys.phys_address()) - .write_irqsave() - .insert_vma(vma.clone()); - - phys = phys.next(); - virt = virt.next(); - } - - // 更新vma的映射状态 - vma.lock_irqsave().set_mapped(true); - - vaddr.data() - } - }; - - // 更新最后一次连接时间 - kernel_shm.update_atim(); - - // 映射计数增加 - kernel_shm.increase_count(); - - Ok(r) - } - - /// # SYS_SHMDT系统调用函数,用于取消对共享内存的连接 - /// - /// ## 参数 - /// - /// - `vaddr`: 需要取消映射的虚拟内存区域起始地址 - /// - /// ## 返回值 - /// - /// 成功:0 - /// 失败:错误码 - pub fn shmdt(vaddr: VirtAddr) -> Result { - let current_address_space = AddressSpace::current()?; - let mut address_write_guard = current_address_space.write(); - - // 获取vma - let vma = address_write_guard - .mappings - .contains(vaddr) - .ok_or(SystemError::EINVAL)?; - - // 判断vaddr是否为起始地址 - if vma.lock_irqsave().region().start() != vaddr { - return Err(SystemError::EINVAL); - } - - // 取消映射 - let flusher: PageFlushAll = PageFlushAll::new(); - vma.unmap(&mut address_write_guard.user_mapper.utable, flusher); - - return Ok(0); - } - - /// # SYS_SHMCTL系统调用函数,用于管理共享内存段 - /// - /// ## 参数 - /// - /// - `id`: 共享内存id - /// - `cmd`: 操作码 - /// - `user_buf`: 用户缓冲区 - /// - `from_user`: buf_vaddr是否来自用户地址空间 - /// - /// ## 返回值 - /// - /// 成功:0 - /// 失败:错误码 - pub fn shmctl( - id: ShmId, - cmd: ShmCtlCmd, - user_buf: *const u8, - from_user: bool, - ) -> Result { - let mut shm_manager_guard = shm_manager_lock(); - - match cmd { - // 查看共享内存元信息 - ShmCtlCmd::IpcInfo => shm_manager_guard.ipc_info(user_buf, from_user), - // 查看共享内存使用信息 - ShmCtlCmd::ShmInfo => shm_manager_guard.shm_info(user_buf, from_user), - // 查看id对应的共享内存信息 - ShmCtlCmd::ShmStat | ShmCtlCmd::ShmtStatAny | ShmCtlCmd::IpcStat => { - shm_manager_guard.shm_stat(id, cmd, user_buf, from_user) - } - // 设置KernIpcPerm - ShmCtlCmd::IpcSet => shm_manager_guard.ipc_set(id, user_buf, from_user), - // 将共享内存段设置为可回收状态 - ShmCtlCmd::IpcRmid => shm_manager_guard.ipc_rmid(id), - // 锁住共享内存段,不允许内存置换 - ShmCtlCmd::ShmLock => shm_manager_guard.shm_lock(id), - // 解锁共享内存段,允许内存置换 - ShmCtlCmd::ShmUnlock => shm_manager_guard.shm_unlock(id), - // 无效操作码 - ShmCtlCmd::Default => Err(SystemError::EINVAL), - } - } - - /// # SYS_SIGPROCMASK系统调用函数,用于设置或查询当前进程的信号屏蔽字 - /// - /// ## 参数 - /// - /// - `how`: 指示如何修改信号屏蔽字 - /// - `nset`: 新的信号屏蔽字 - /// - `oset`: 旧的信号屏蔽字的指针,由于可以是NULL,所以用Option包装 - /// - `sigsetsize`: 信号集的大小 - /// - /// ## 返回值 - /// - /// 成功:0 - /// 失败:错误码 - /// - /// ## 说明 - /// 根据 https://man7.org/linux/man-pages/man2/sigprocmask.2.html ,传进来的oldset和newset都是指针类型,这里选择传入usize然后转换为u64的指针类型 - pub fn rt_sigprocmask( - how: i32, - newset: usize, - oldset: usize, - sigsetsize: usize, - ) -> Result { - // 对应oset传进来一个NULL的情况 - let oset = if oldset == 0 { None } else { Some(oldset) }; - let nset = if newset == 0 { None } else { Some(newset) }; - - if sigsetsize != size_of::() { - return Err(SystemError::EFAULT); - } - - let sighow = SigHow::try_from(how)?; - - let mut new_set = SigSet::default(); - if let Some(nset) = nset { - let reader = UserBufferReader::new( - VirtAddr::new(nset).as_ptr::(), - core::mem::size_of::(), - true, - )?; - - let nset = reader.read_one_from_user::(0)?; - new_set = SigSet::from_bits_truncate(*nset); - // debug!("Get Newset: {}", &new_set.bits()); - let to_remove: SigSet = - >::into(Signal::SIGKILL) | Signal::SIGSTOP.into(); - new_set.remove(to_remove); - } - - let oldset_to_return = set_sigprocmask(sighow, new_set)?; - if let Some(oldset) = oset { - // debug!("Get Oldset to return: {}", &oldset_to_return.bits()); - let mut writer = UserBufferWriter::new( - VirtAddr::new(oldset).as_ptr::(), - core::mem::size_of::(), - true, - )?; - writer.copy_one_to_user::(&oldset_to_return.bits(), 0)?; - } - - Ok(0) - } - - pub fn restart_syscall() -> Result { - let restart_block = ProcessManager::current_pcb().restart_block().take(); - if let Some(mut restart_block) = restart_block { - return restart_block.restart_fn.call(&mut restart_block.data); - } else { - // 不应该走到这里,因此kill掉当前进程及同组的进程 - let pid = Pid::new(0); - let sig = Signal::SIGKILL; - let mut info = SigInfo::new(sig, 0, SigCode::Kernel, SigType::Kill(pid)); - - sig.send_signal_info(Some(&mut info), pid) - .expect("Failed to kill "); - return Ok(0); - } - } -} diff --git a/kernel/src/ipc/syscall/mod.rs b/kernel/src/ipc/syscall/mod.rs new file mode 100644 index 00000000..75a79042 --- /dev/null +++ b/kernel/src/ipc/syscall/mod.rs @@ -0,0 +1,13 @@ +pub mod sys_kill; +pub mod sys_pipe2; +mod sys_restart; +mod sys_rt_sigprocmask; +mod sys_shmat; +mod sys_shmctl; +mod sys_shmdt; +mod sys_shmget; +mod sys_sigaction; +mod sys_sigpending; + +#[cfg(target_arch = "x86_64")] +pub mod sys_pipe; diff --git a/kernel/src/ipc/syscall/sys_kill.rs b/kernel/src/ipc/syscall/sys_kill.rs new file mode 100644 index 00000000..a71ae635 --- /dev/null +++ b/kernel/src/ipc/syscall/sys_kill.rs @@ -0,0 +1,91 @@ +use alloc::string::ToString; +use alloc::vec::Vec; +use core::ffi::c_int; + +use crate::arch::interrupt::TrapFrame; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use crate::{ + arch::{ipc::signal::Signal, syscall::nr::SYS_KILL}, + process::{process_group::Pgid, Pid, ProcessManager}, +}; +use log::warn; +use system_error::SystemError; + +use crate::ipc::kill::{kill_all, kill_process, kill_process_group}; + +/// ### pid转换器,将输入的id转换成对应的pid或pgid +/// - 如果id < -1,则为pgid +/// - 如果id == -1,则为所有进程 +/// - 如果id == 0,则为当前进程组 +/// - 如果id > 0,则为pid +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PidConverter { + All, + Pid(Pid), + Pgid(Pgid), +} + +impl PidConverter { + /// ### 为 `wait` 和 `kill` 调用使用 + pub fn from_id(id: i32) -> Self { + if id < -1 { + PidConverter::Pgid(Pgid::from(-id as usize)) + } else if id == -1 { + PidConverter::All + } else if id == 0 { + let pgid = ProcessManager::current_pcb().pgid(); + PidConverter::Pgid(pgid) + } else { + PidConverter::Pid(Pid::from(id as usize)) + } + } +} + +pub struct SysKillHandle; + +impl SysKillHandle { + #[inline(always)] + fn pid(args: &[usize]) -> i32 { + // 第一个参数是id + args[0] as i32 + } + #[inline(always)] + fn sig(args: &[usize]) -> c_int { + // 第二个参数是信号值 + args[1] as c_int + } +} + +impl Syscall for SysKillHandle { + fn num_args(&self) -> usize { + 2 + } + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let id = Self::pid(args); + let sig_c_int = Self::sig(args); + + let converter = PidConverter::from_id(id); + let sig = Signal::from(sig_c_int); + if sig == Signal::INVALID { + warn!("Not a valid signal number"); + return Err(SystemError::EINVAL); + } + + match converter { + PidConverter::Pid(pid) => kill_process(pid, sig), + PidConverter::Pgid(pgid) => kill_process_group(pgid, sig), + PidConverter::All => kill_all(sig), + } + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("pid", Self::pid(args).to_string()), + FormattedSyscallParam::new("sig", Self::sig(args).to_string()), + ] + } +} + +// 注册系统调用 +syscall_table_macros::declare_syscall!(SYS_KILL, SysKillHandle); diff --git a/kernel/src/ipc/syscall/sys_pipe.rs b/kernel/src/ipc/syscall/sys_pipe.rs new file mode 100644 index 00000000..edfde6bc --- /dev/null +++ b/kernel/src/ipc/syscall/sys_pipe.rs @@ -0,0 +1,45 @@ +use super::sys_pipe2::do_kernel_pipe2; +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_PIPE; +use crate::{ + filesystem::vfs::file::FileMode, + syscall::table::{FormattedSyscallParam, Syscall}, +}; +use alloc::vec::Vec; +use core::ffi::c_int; +use system_error::SystemError; + +pub struct SysPipeHandle; + +impl SysPipeHandle { + #[inline(always)] + fn pipefd(args: &[usize]) -> *mut i32 { + // 第一个参数是fd指针 + args[0] as *mut c_int + } +} + +impl Syscall for SysPipeHandle { + fn num_args(&self) -> usize { + 1 // pipefd + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let pipefd = Self::pipefd(args); + if pipefd.is_null() { + return Err(SystemError::EFAULT); + } else { + do_kernel_pipe2(pipefd, FileMode::empty()) + } + } + + fn entry_format(&self, args: &[usize]) -> Vec { + let fd_ptr = Self::pipefd(args); + vec![FormattedSyscallParam::new( + "fd_ptr", + format!("{}", fd_ptr as usize), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_PIPE, SysPipeHandle); diff --git a/kernel/src/ipc/syscall/sys_pipe2.rs b/kernel/src/ipc/syscall/sys_pipe2.rs new file mode 100644 index 00000000..d195b457 --- /dev/null +++ b/kernel/src/ipc/syscall/sys_pipe2.rs @@ -0,0 +1,102 @@ +use crate::arch::interrupt::TrapFrame; +use crate::{ + arch::syscall::nr::SYS_PIPE2, + filesystem::vfs::{ + file::{File, FileMode}, + FilePrivateData, + }, + ipc::pipe::{LockedPipeInode, PipeFsPrivateData}, + libs::spinlock::SpinLock, + process::ProcessManager, + syscall::{ + table::{FormattedSyscallParam, Syscall}, + user_access::UserBufferWriter, + }, +}; +use alloc::vec::Vec; +use core::ffi::c_int; +use system_error::SystemError; +pub struct SysPipe2Handle; + +// Extracted core logic for pipe2 +// pub(super) makes it visible to other modules in kernel/src/ipc/syscall/ +pub(super) fn do_kernel_pipe2(fd: *mut i32, flags: FileMode) -> Result { + if !flags + .difference(FileMode::O_CLOEXEC | FileMode::O_NONBLOCK | FileMode::O_DIRECT) + .is_empty() + { + return Err(SystemError::EINVAL); + } + + let mut user_buffer = UserBufferWriter::new(fd, core::mem::size_of::<[c_int; 2]>(), true)?; + let fd = user_buffer.buffer::(0)?; + let pipe_ptr = LockedPipeInode::new(); + + let mut read_file = File::new( + pipe_ptr.clone(), + FileMode::O_RDONLY | (flags & FileMode::O_NONBLOCK), + )?; + read_file.private_data = SpinLock::new(FilePrivateData::Pipefs(PipeFsPrivateData::new( + FileMode::O_RDONLY, + ))); + + let mut write_file = File::new( + pipe_ptr.clone(), + FileMode::O_WRONLY | (flags & (FileMode::O_NONBLOCK | FileMode::O_DIRECT)), + )?; + write_file.private_data = SpinLock::new(FilePrivateData::Pipefs(PipeFsPrivateData::new( + FileMode::O_WRONLY | (flags & (FileMode::O_NONBLOCK | FileMode::O_DIRECT)), + ))); + + if flags.contains(FileMode::O_CLOEXEC) { + read_file.set_close_on_exec(true); + write_file.set_close_on_exec(true); + } + let fd_table_ptr = ProcessManager::current_pcb().fd_table(); + let mut fd_table_guard = fd_table_ptr.write(); + let read_fd = fd_table_guard.alloc_fd(read_file, None)?; + let write_fd = fd_table_guard.alloc_fd(write_file, None)?; + + drop(fd_table_guard); + + fd[0] = read_fd; + fd[1] = write_fd; + Ok(0) +} + +impl SysPipe2Handle { + #[inline(always)] + fn pipefd(args: &[usize]) -> *mut i32 { + args[0] as *mut c_int + } + #[inline(always)] + fn flags(args: &[usize]) -> FileMode { + FileMode::from_bits_truncate(args[1] as u32) + } +} + +impl Syscall for SysPipe2Handle { + fn num_args(&self) -> usize { + 2 // fd_ptr, flags + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let fd_ptr = Self::pipefd(args); + if fd_ptr.is_null() { + return Err(SystemError::EFAULT); + } else { + let flags = FileMode::from_bits_truncate(args[1] as u32); + do_kernel_pipe2(fd_ptr, flags) + } + } + + fn entry_format(&self, args: &[usize]) -> Vec { + let fd_ptr = Self::pipefd(args); + vec![ + FormattedSyscallParam::new("fd_ptr", format!("{}", fd_ptr as usize)), // Format pointer as hex + FormattedSyscallParam::new("flags", format!("{}", Self::flags(args).bits())), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_PIPE2, SysPipe2Handle); diff --git a/kernel/src/ipc/syscall/sys_restart.rs b/kernel/src/ipc/syscall/sys_restart.rs new file mode 100644 index 00000000..c52c9d69 --- /dev/null +++ b/kernel/src/ipc/syscall/sys_restart.rs @@ -0,0 +1,49 @@ +use super::super::signal_types::{SigInfo, SigType}; +use crate::arch::interrupt::TrapFrame; +use crate::{ + alloc::vec::Vec, + arch::ipc::signal::{SigCode, Signal}, + arch::syscall::nr::SYS_RESTART_SYSCALL, + process::{Pid, ProcessManager}, + syscall::table::{FormattedSyscallParam, Syscall}, +}; +use syscall_table_macros::declare_syscall; +use system_error::SystemError; +pub struct SysRestartHandle; + +/// # SYS_RESTART_SYSCALL 系统调用函数,用于重启被信号中断的系统调用 +/// +/// ## 返回值 +/// +/// 根据被重启的系统调用决定 +pub(super) fn do_kernel_restart_syscall() -> Result { + let restart_block = ProcessManager::current_pcb().restart_block().take(); + if let Some(mut restart_block) = restart_block { + return restart_block.restart_fn.call(&mut restart_block.data); + } else { + // 不应该走到这里,因此kill掉当前进程及同组的进程 + let pid = Pid::new(0); + let sig = Signal::SIGKILL; + let mut info = SigInfo::new(sig, 0, SigCode::Kernel, SigType::Kill(pid)); + + sig.send_signal_info(Some(&mut info), pid) + .expect("Failed to kill "); + return Ok(0); + } +} + +impl Syscall for SysRestartHandle { + fn num_args(&self) -> usize { + 0 // restart_syscall 通常没有参数 + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + Vec::new() // 没有参数,返回空Vec + } + + fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { + do_kernel_restart_syscall() + } +} + +declare_syscall!(SYS_RESTART_SYSCALL, SysRestartHandle); diff --git a/kernel/src/ipc/syscall/sys_rt_sigprocmask.rs b/kernel/src/ipc/syscall/sys_rt_sigprocmask.rs new file mode 100644 index 00000000..267206b1 --- /dev/null +++ b/kernel/src/ipc/syscall/sys_rt_sigprocmask.rs @@ -0,0 +1,135 @@ +use crate::alloc::vec::Vec; +use crate::arch::interrupt::TrapFrame; +use crate::{ + arch::ipc::signal::{SigSet, Signal}, + arch::syscall::nr::SYS_RT_SIGPROCMASK, + ipc::signal::{set_sigprocmask, SigHow}, + mm::VirtAddr, + syscall::{ + table::{FormattedSyscallParam, Syscall}, + user_access::{UserBufferReader, UserBufferWriter}, + }, +}; +use core::mem::size_of; +use syscall_table_macros::declare_syscall; +use system_error::SystemError; // 添加 Vec +pub struct SysRtSigprocmaskHandle; + +/// # SYS_SIGPROCMASK系统调用函数,用于设置或查询当前进程的信号屏蔽字 +/// +/// ## 参数 +/// +/// - `how`: 指示如何修改信号屏蔽字 +/// - `nset`: 新的信号屏蔽字 +/// - `oset`: 旧的信号屏蔽字的指针,由于可以是NULL,所以用Option包装 +/// - `sigsetsize`: 信号集的大小 +/// +/// ## 返回值 +/// +/// 成功:0 +/// 失败:错误码 +/// +/// ## 说明 +/// 根据 https://man7.org/linux/man-pages/man2/sigprocmask.2.html ,传进来的oldset和newset都是指针类型,这里选择传入usize然后转换为u64的指针类型 +pub(super) fn do_kernel_rt_sigprocmask( + how: i32, + newset: usize, + oldset: usize, + sigsetsize: usize, +) -> Result { + // 对应oset传进来一个NULL的情况 + let oset = if oldset == 0 { None } else { Some(oldset) }; + let nset = if newset == 0 { None } else { Some(newset) }; + + if sigsetsize != size_of::() { + return Err(SystemError::EFAULT); + } + + let sighow = SigHow::try_from(how)?; + + let mut new_set = SigSet::default(); + if let Some(nset) = nset { + let reader = UserBufferReader::new( + VirtAddr::new(nset).as_ptr::(), + core::mem::size_of::(), + true, + )?; + + let nset = reader.read_one_from_user::(0)?; + new_set = SigSet::from_bits_truncate(*nset); + // debug!("Get Newset: {}", &new_set.bits()); + let to_remove: SigSet = + >::into(Signal::SIGKILL) | Signal::SIGSTOP.into(); + new_set.remove(to_remove); + } + + let oldset_to_return = set_sigprocmask(sighow, new_set)?; + if let Some(oldset) = oset { + // debug!("Get Oldset to return: {}", &oldset_to_return.bits()); + let mut writer = UserBufferWriter::new( + VirtAddr::new(oldset).as_ptr::(), + core::mem::size_of::(), + true, + )?; + writer.copy_one_to_user::(&oldset_to_return.bits(), 0)?; + } + + Ok(0) +} + +impl SysRtSigprocmaskHandle { + #[inline(always)] + fn how(args: &[usize]) -> i32 { + // 第一个参数是 how + args[0] as i32 + } + + #[inline(always)] + fn nset(args: &[usize]) -> usize { + // 第二个参数是新信号集的指针 + args[1] + } + + #[inline(always)] + fn oset(args: &[usize]) -> usize { + // 第三个参数是旧信号集的指针 + args[2] + } + + #[inline(always)] + fn sigsetsize(args: &[usize]) -> usize { + // 第四个参数是 sigset_t 的大小 + args[3] + } +} + +impl Syscall for SysRtSigprocmaskHandle { + fn num_args(&self) -> usize { + 4 + } + + fn entry_format(&self, args: &[usize]) -> Vec { + let how = Self::how(args); + let nset_ptr = Self::nset(args); + let oset_ptr = Self::oset(args); + let sigsetsize = Self::sigsetsize(args); + + vec![ + FormattedSyscallParam::new("how", format!("{:#x}", how)), + FormattedSyscallParam::new("nset", format!("{:#x}", nset_ptr)), + FormattedSyscallParam::new("oset", format!("{:#x}", oset_ptr)), + FormattedSyscallParam::new("sigsetsize", format!("{}", sigsetsize)), + ] + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let how = Self::how(args); + let nset = Self::nset(args); + let oset = Self::oset(args); + let sigsetsize = Self::sigsetsize(args); + + do_kernel_rt_sigprocmask(how, nset, oset, sigsetsize) + } +} + +declare_syscall!(SYS_RT_SIGPROCMASK, SysRtSigprocmaskHandle); diff --git a/kernel/src/ipc/syscall/sys_shmat.rs b/kernel/src/ipc/syscall/sys_shmat.rs new file mode 100644 index 00000000..f8a6ccca --- /dev/null +++ b/kernel/src/ipc/syscall/sys_shmat.rs @@ -0,0 +1,179 @@ +use crate::alloc::vec::Vec; +use crate::arch::interrupt::TrapFrame; +use crate::syscall::table::FormattedSyscallParam; +use crate::{ + arch::syscall::nr::SYS_SHMAT, + arch::MMArch, + ipc::shm::{shm_manager_lock, ShmFlags, ShmId}, + libs::align::page_align_up, + mm::{ + allocator::page_frame::{PageFrameCount, PhysPageFrame, VirtPageFrame}, + page::{page_manager_lock_irqsave, EntryFlags, PageFlushAll}, + syscall::ProtFlags, + ucontext::{AddressSpace, VMA}, + VirtAddr, VmFlags, + }, + syscall::{table::Syscall, user_access::UserBufferReader}, +}; +use syscall_table_macros::declare_syscall; +use system_error::SystemError; +pub struct SysShmatHandle; + +/// # SYS_SHMAT系统调用函数,用于连接共享内存段 +/// +/// ## 参数 +/// +/// - `id`: 共享内存id +/// - `vaddr`: 连接共享内存的进程虚拟内存区域起始地址 +/// - `shmflg`: 共享内存标志 +/// +/// ## 返回值 +/// +/// 成功:映射到共享内存的虚拟内存区域起始地址 +/// 失败:错误码 +pub(super) fn do_kernel_shmat( + id: ShmId, + vaddr: VirtAddr, + shmflg: ShmFlags, +) -> Result { + let mut shm_manager_guard = shm_manager_lock(); + let current_address_space = AddressSpace::current()?; + let mut address_write_guard = current_address_space.write(); + + let kernel_shm = shm_manager_guard.get_mut(&id).ok_or(SystemError::EINVAL)?; + let size = page_align_up(kernel_shm.size()); + let mut phys = PhysPageFrame::new(kernel_shm.start_paddr()); + let count = PageFrameCount::from_bytes(size).unwrap(); + let r = match vaddr.data() { + // 找到空闲区域并映射到共享内存 + 0 => { + // 找到空闲区域 + let region = address_write_guard + .mappings + .find_free(vaddr, size) + .ok_or(SystemError::EINVAL)?; + let vm_flags = VmFlags::from(shmflg); + let destination = VirtPageFrame::new(region.start()); + let page_flags: EntryFlags = + EntryFlags::from_prot_flags(ProtFlags::from(vm_flags), true); + let flusher: PageFlushAll = PageFlushAll::new(); + + // 将共享内存映射到对应虚拟区域 + let vma = VMA::physmap( + phys, + destination, + count, + vm_flags, + page_flags, + &mut address_write_guard.user_mapper.utable, + flusher, + )?; + + // 将VMA加入到当前进程的VMA列表中 + address_write_guard.mappings.insert_vma(vma); + + region.start().data() + } + // 指定虚拟地址 + _ => { + // 获取对应vma + let vma = address_write_guard + .mappings + .contains(vaddr) + .ok_or(SystemError::EINVAL)?; + if vma.lock_irqsave().region().start() != vaddr { + return Err(SystemError::EINVAL); + } + + // 验证用户虚拟内存区域是否有效 + let _ = UserBufferReader::new(vaddr.data() as *const u8, size, true)?; + + // 必须在取消映射前获取到EntryFlags + let page_flags = address_write_guard + .user_mapper + .utable + .translate(vaddr) + .ok_or(SystemError::EINVAL)? + .1; + + // 取消原映射 + let flusher: PageFlushAll = PageFlushAll::new(); + vma.unmap(&mut address_write_guard.user_mapper.utable, flusher); + + // 将该虚拟内存区域映射到共享内存区域 + let mut page_manager_guard = page_manager_lock_irqsave(); + let mut virt = VirtPageFrame::new(vaddr); + for _ in 0..count.data() { + let r = unsafe { + address_write_guard.user_mapper.utable.map_phys( + virt.virt_address(), + phys.phys_address(), + page_flags, + ) + } + .expect("Failed to map zero, may be OOM error"); + r.flush(); + + // 将vma加入到对应Page的anon_vma + page_manager_guard + .get_unwrap(&phys.phys_address()) + .write_irqsave() + .insert_vma(vma.clone()); + + phys = phys.next(); + virt = virt.next(); + } + + // 更新vma的映射状态 + vma.lock_irqsave().set_mapped(true); + + vaddr.data() + } + }; + + // 更新最后一次连接时间 + kernel_shm.update_atim(); + + // 映射计数增加 + kernel_shm.increase_count(); + + Ok(r) +} + +impl SysShmatHandle { + #[inline(always)] + fn id(args: &[usize]) -> ShmId { + ShmId::new(args[0]) // 更正 ShmIT 为 ShmId + } + + #[inline(always)] + fn vaddr(args: &[usize]) -> VirtAddr { + VirtAddr::new(args[1]) + } + #[inline(always)] + fn shmflg(args: &[usize]) -> ShmFlags { + ShmFlags::from_bits_truncate(args[2] as u32) + } +} + +impl Syscall for SysShmatHandle { + fn num_args(&self) -> usize { + 3 + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("id", format!("{}", Self::id(args).data())), + FormattedSyscallParam::new("vaddr", format!("{}", Self::vaddr(args).data())), + FormattedSyscallParam::new("shmflg", format!("{}", Self::shmflg(args).bits())), + ] + } + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let id = Self::id(args); + let vaddr = Self::vaddr(args); + let shmflg = Self::shmflg(args); + do_kernel_shmat(id, vaddr, shmflg) + } +} + +declare_syscall!(SYS_SHMAT, SysShmatHandle); diff --git a/kernel/src/ipc/syscall/sys_shmctl.rs b/kernel/src/ipc/syscall/sys_shmctl.rs new file mode 100644 index 00000000..7ac5ea68 --- /dev/null +++ b/kernel/src/ipc/syscall/sys_shmctl.rs @@ -0,0 +1,92 @@ +use crate::alloc::vec::Vec; +use crate::arch::interrupt::TrapFrame; +use crate::{ + arch::syscall::nr::SYS_SHMCTL, + ipc::shm::{shm_manager_lock, ShmCtlCmd, ShmId}, + syscall::table::{FormattedSyscallParam, Syscall}, +}; +use syscall_table_macros::declare_syscall; +use system_error::SystemError; +pub struct SysShmctlHandle; + +/// # SYS_SHMCTL系统调用函数,用于管理共享内存段 +/// +/// ## 参数 +/// +/// - `id`: 共享内存id +/// - `cmd`: 操作码 +/// - `user_buf`: 用户缓冲区 +/// - `from_user`: buf_vaddr是否来自用户地址空间 +/// +/// ## 返回值 +/// +/// 成功:0 +/// 失败:错误码 +pub(super) fn do_kernel_shmctl( + id: ShmId, + cmd: ShmCtlCmd, + user_buf: *const u8, + from_user: bool, +) -> Result { + let mut shm_manager_guard = shm_manager_lock(); + + match cmd { + // 查看共享内存元信息 + ShmCtlCmd::IpcInfo => shm_manager_guard.ipc_info(user_buf, from_user), + // 查看共享内存使用信息 + ShmCtlCmd::ShmInfo => shm_manager_guard.shm_info(user_buf, from_user), + // 查看id对应的共享内存信息 + ShmCtlCmd::ShmStat | ShmCtlCmd::ShmtStatAny | ShmCtlCmd::IpcStat => { + shm_manager_guard.shm_stat(id, cmd, user_buf, from_user) + } + // 设置KernIpcPerm + ShmCtlCmd::IpcSet => shm_manager_guard.ipc_set(id, user_buf, from_user), + // 将共享内存段设置为可回收状态 + ShmCtlCmd::IpcRmid => shm_manager_guard.ipc_rmid(id), + // 锁住共享内存段,不允许内存置换 + ShmCtlCmd::ShmLock => shm_manager_guard.shm_lock(id), + // 解锁共享内存段,允许内存置换 + ShmCtlCmd::ShmUnlock => shm_manager_guard.shm_unlock(id), + // 无效操作码 + ShmCtlCmd::Default => Err(SystemError::EINVAL), + } +} + +impl SysShmctlHandle { + #[inline(always)] + fn id(args: &[usize]) -> ShmId { + ShmId::new(args[0]) // Assuming ShmId::new takes usize or can infer from args[0] + } + + #[inline(always)] + fn cmd(args: &[usize]) -> ShmCtlCmd { + ShmCtlCmd::from(args[1]) + } + + #[inline(always)] + fn user_buf(args: &[usize]) -> *const u8 { + args[2] as *const u8 // Assuming args[2] is a pointer to user buffer + } +} + +impl Syscall for SysShmctlHandle { + fn num_args(&self) -> usize { + 3 + } + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("shmid", format!("{}", Self::id(args).data())), + FormattedSyscallParam::new("cmd", format!("{}", Self::cmd(args))), + FormattedSyscallParam::new("buf", format!("{:#x}", Self::user_buf(args) as usize)), + ] + } + + fn handle(&self, args: &[usize], frame: &mut TrapFrame) -> Result { + let id = Self::id(args); + let cmd = Self::cmd(args); + let user_buf = Self::user_buf(args); + do_kernel_shmctl(id, cmd, user_buf, frame.is_from_user()) + } +} + +declare_syscall!(SYS_SHMCTL, SysShmctlHandle); diff --git a/kernel/src/ipc/syscall/sys_shmdt.rs b/kernel/src/ipc/syscall/sys_shmdt.rs new file mode 100644 index 00000000..f67b4983 --- /dev/null +++ b/kernel/src/ipc/syscall/sys_shmdt.rs @@ -0,0 +1,67 @@ +use crate::arch::interrupt::TrapFrame; +use crate::mm::page::PageFlushAll; +use crate::syscall::table::FormattedSyscallParam; +use crate::{ + arch::syscall::nr::SYS_SHMDT, + arch::MMArch, + mm::{ucontext::AddressSpace, VirtAddr}, + syscall::table::Syscall, +}; +use alloc::vec::Vec; +use syscall_table_macros::declare_syscall; +use system_error::SystemError; +pub struct SysShmdtHandle; + +impl SysShmdtHandle { + #[inline(always)] + fn vaddr(args: &[usize]) -> VirtAddr { + VirtAddr::new(args[0]) + } +} + +impl Syscall for SysShmdtHandle { + fn num_args(&self) -> usize { + 1 + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "vaddr", + format!("{}", Self::vaddr(args).data()), + )] + } + /// # SYS_SHMDT系统调用函数,用于取消对共享内存的连接 + /// + /// ## 参数 + /// + /// - `vaddr`: 需要取消映射的虚拟内存区域起始地址 + /// + /// ## 返回值 + /// + /// 成功:0 + /// 失败:错误码 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let vaddr = Self::vaddr(args); + let current_address_space = AddressSpace::current()?; + let mut address_write_guard = current_address_space.write(); + + // 获取vma + let vma = address_write_guard + .mappings + .contains(vaddr) + .ok_or(SystemError::EINVAL)?; + + // 判断vaddr是否为起始地址 + if vma.lock_irqsave().region().start() != vaddr { + return Err(SystemError::EINVAL); + } + + // 取消映射 + let flusher: PageFlushAll = PageFlushAll::new(); + vma.unmap(&mut address_write_guard.user_mapper.utable, flusher); + + return Ok(0); + } +} + +declare_syscall!(SYS_SHMDT, SysShmdtHandle); diff --git a/kernel/src/ipc/syscall/sys_shmget.rs b/kernel/src/ipc/syscall/sys_shmget.rs new file mode 100644 index 00000000..0e2675eb --- /dev/null +++ b/kernel/src/ipc/syscall/sys_shmget.rs @@ -0,0 +1,110 @@ +use crate::alloc::vec::Vec; +use crate::arch::interrupt::TrapFrame; +use crate::syscall::table::FormattedSyscallParam; +use crate::{ + arch::syscall::nr::SYS_SHMGET, + ipc::shm::{shm_manager_lock, ShmFlags, ShmKey, IPC_PRIVATE}, + syscall::table::Syscall, +}; +use log::error; +use syscall_table_macros::declare_syscall; +use system_error::SystemError; +pub struct SysShmgetHandle; + +/// # SYS_SHMGET系统调用函数,用于获取共享内存 +/// +/// ## 参数 +/// +/// - `key`: 共享内存键值 +/// - `size`: 共享内存大小(bytes) +/// - `shmflg`: 共享内存标志 +/// +/// ## 返回值 +/// +/// 成功:共享内存id +/// 失败:错误码 +pub(super) fn do_kernel_shmget( + key: ShmKey, + size: usize, + shmflg: ShmFlags, +) -> Result { + // 暂不支持巨页 + if shmflg.contains(ShmFlags::SHM_HUGETLB) { + error!("shmget: not support huge page"); + return Err(SystemError::ENOSYS); + } + + let mut shm_manager_guard = shm_manager_lock(); + match key { + // 创建共享内存段 + IPC_PRIVATE => shm_manager_guard.add(key, size, shmflg), + _ => { + // 查找key对应的共享内存段是否存在 + let id = shm_manager_guard.contains_key(&key); + if let Some(id) = id { + // 不能重复创建 + if shmflg.contains(ShmFlags::IPC_CREAT | ShmFlags::IPC_EXCL) { + return Err(SystemError::EEXIST); + } + + // key值存在,说明有对应共享内存,返回该共享内存id + return Ok(id.data()); + } else { + // key不存在且shm_flags不包含IPC_CREAT创建IPC对象标志,则返回错误码 + if !shmflg.contains(ShmFlags::IPC_CREAT) { + return Err(SystemError::ENOENT); + } + + // 存在创建IPC对象标志 + return shm_manager_guard.add(key, size, shmflg); + } + } + } +} + +impl SysShmgetHandle { + #[inline(always)] + fn key(args: &[usize]) -> ShmKey { + // 第一个参数是共享内存的key + // In the old code: ShmKey::new(args[0]) + // ShmKey is likely a type alias for i32 or similar, args[0] is usize + ShmKey::new(args[0]) // Assuming ShmKey::new takes i32 + } + + #[inline(always)] + fn size(args: &[usize]) -> usize { + // 第二个参数是共享内存的大小 + args[1] + } + + #[inline(always)] + fn shmflg(args: &[usize]) -> ShmFlags { + // 第三个参数是共享内存的标志 + // In the old code: ShmFlags::from_bits_truncate(args[2] as u32) + ShmFlags::from_bits_truncate(args[2] as u32) + } +} + +impl Syscall for SysShmgetHandle { + fn num_args(&self) -> usize { + 3 // key, size, shmflg + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let key = Self::key(args); + let size = Self::size(args); + let shmflg = Self::shmflg(args); + do_kernel_shmget(key, size, shmflg) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("key", format!("{}", Self::key(args).data())), + // 使用 format! 宏将 usize 类型的 size 转换为 String + FormattedSyscallParam::new("size", format!("{}", Self::size(args))), + FormattedSyscallParam::new("shmflg", format!("{:#x}", Self::shmflg(args).bits())), + ] + } +} + +declare_syscall!(SYS_SHMGET, SysShmgetHandle); diff --git a/kernel/src/ipc/syscall/sys_sigaction.rs b/kernel/src/ipc/syscall/sys_sigaction.rs new file mode 100644 index 00000000..d67c2e4b --- /dev/null +++ b/kernel/src/ipc/syscall/sys_sigaction.rs @@ -0,0 +1,191 @@ +use super::super::signal_types::{ + SaHandlerType, Sigaction, SigactionType, UserSigaction, USER_SIG_DFL, USER_SIG_ERR, + USER_SIG_IGN, +}; +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_RT_SIGACTION; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use crate::{ + arch::ipc::signal::{SigFlags, SigSet, Signal}, + mm::VirtAddr, + process::ProcessManager, + syscall::user_access::UserBufferWriter, +}; +use alloc::vec::Vec; +use core::ffi::{c_int, c_void}; +use log::error; +use system_error::SystemError; +pub struct SysSigactionHandle; + +/// 通用信号注册函数 +/// +/// ## 参数 +/// +/// - `sig` 信号的值 +/// - `act` 用户空间传入的 Sigaction 指针 +/// - `old_act` 用户空间传入的用来保存旧 Sigaction 的指针 +/// - `from_user` 用来标识这个函数调用是否来自用户空间 +/// +/// @return int 错误码 +#[no_mangle] +pub(super) fn do_kernel_sigaction( + sig: c_int, + new_act: usize, + old_act: usize, + from_user: bool, +) -> Result { + // 请注意:用户态传进来的user_sigaction结构体类型,请注意,这个结构体与内核实际的不一样 + let act: *mut UserSigaction = new_act as *mut UserSigaction; + let old_act = old_act as *mut UserSigaction; + let mut new_ka: Sigaction = Default::default(); + let mut old_sigaction: Sigaction = Default::default(); + // 如果传入的,新的sigaction不为空 + if !act.is_null() { + // 如果参数的范围不在用户空间,则返回错误 + let r = UserBufferWriter::new(act, core::mem::size_of::(), from_user); + if r.is_err() { + return Err(SystemError::EFAULT); + } + let mask: SigSet = unsafe { (*act).mask }; + let input_sighandler = unsafe { (*act).handler as u64 }; + match input_sighandler { + USER_SIG_DFL => { + new_ka = Sigaction::DEFAULT_SIGACTION; + *new_ka.flags_mut() = unsafe { (*act).flags }; + new_ka.set_restorer(None); + } + + USER_SIG_IGN => { + new_ka = Sigaction::DEFAULT_SIGACTION_IGNORE; + *new_ka.flags_mut() = unsafe { (*act).flags }; + + new_ka.set_restorer(None); + } + _ => { + // 从用户空间获得sigaction结构体 + // TODO mask是default还是用户空间传入 + new_ka = Sigaction::new( + SigactionType::SaHandler(SaHandlerType::Customized(unsafe { + VirtAddr::new((*act).handler as usize) + })), + unsafe { (*act).flags }, + SigSet::default(), + unsafe { Some(VirtAddr::new((*act).restorer as usize)) }, + ); + } + } + + // TODO 如果为空,赋默认值? + // debug!("new_ka={:?}", new_ka); + // 如果用户手动给了sa_restorer,那么就置位SA_FLAG_RESTORER,否则报错。(用户必须手动指定restorer) + if new_ka.restorer().is_some() { + new_ka.flags_mut().insert(SigFlags::SA_RESTORER); + } else if new_ka.action().is_customized() { + error!( + "pid:{:?}: in sys_sigaction: User must manually sprcify a sa_restorer for signal {}.", + ProcessManager::current_pcb().pid(), + sig + ); + return Err(SystemError::EINVAL); + } + *new_ka.mask_mut() = mask; + } + + let sig = Signal::from(sig); + // 如果给出的信号值不合法 + if sig == Signal::INVALID { + return Err(SystemError::EINVAL); + } + + let retval = super::super::signal::do_sigaction( + sig, + if act.is_null() { + None + } else { + Some(&mut new_ka) + }, + if old_act.is_null() { + None + } else { + Some(&mut old_sigaction) + }, + ); + + // + if (retval == Ok(())) && (!old_act.is_null()) { + let r = UserBufferWriter::new(old_act, core::mem::size_of::(), from_user); + if r.is_err() { + return Err(SystemError::EFAULT); + } + + let sigaction_handler = match old_sigaction.action() { + SigactionType::SaHandler(handler) => { + if let SaHandlerType::Customized(hand) = handler { + hand + } else if handler.is_sig_ignore() { + VirtAddr::new(USER_SIG_IGN as usize) + } else if handler.is_sig_error() { + VirtAddr::new(USER_SIG_ERR as usize) + } else { + VirtAddr::new(USER_SIG_DFL as usize) + } + } + SigactionType::SaSigaction(_) => { + error!("unsupported type: SaSigaction"); + VirtAddr::new(USER_SIG_DFL as usize) + } + }; + + unsafe { + (*old_act).handler = sigaction_handler.data() as *mut c_void; + (*old_act).flags = old_sigaction.flags(); + (*old_act).mask = old_sigaction.mask(); + if old_sigaction.restorer().is_some() { + (*old_act).restorer = old_sigaction.restorer().unwrap().data() as *mut c_void; + } + } + } + return retval.map(|_| 0); +} + +impl SysSigactionHandle { + #[inline(always)] + fn sig(args: &[usize]) -> c_int { + // 第一个参数是信号值 + args[0] as c_int + } + #[inline(always)] + fn act(args: &[usize]) -> usize { + // 第二个参数是用户空间传入的 Sigaction 指针 + args[1] + } + #[inline(always)] + fn old_act(args: &[usize]) -> usize { + // 第三个参数是用户空间传入的用来保存旧 Sigaction 的指针 + args[2] + } +} + +impl Syscall for SysSigactionHandle { + fn num_args(&self) -> usize { + 3 + } + + #[no_mangle] + fn handle(&self, args: &[usize], frame: &mut TrapFrame) -> Result { + let sig = Self::sig(args); + let act = Self::act(args); + let old_act = Self::old_act(args); + + do_kernel_sigaction(sig, act, old_act, frame.is_from_user()) + } + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("sig", format!("{}", Self::sig(args))), + FormattedSyscallParam::new("act", format!("{:#x}", Self::act(args))), + FormattedSyscallParam::new("old_act", format!("{:#x}", Self::old_act(args))), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_RT_SIGACTION, SysSigactionHandle); diff --git a/kernel/src/ipc/syscall/sys_sigpending.rs b/kernel/src/ipc/syscall/sys_sigpending.rs new file mode 100644 index 00000000..8556786d --- /dev/null +++ b/kernel/src/ipc/syscall/sys_sigpending.rs @@ -0,0 +1,76 @@ +use crate::arch::interrupt::TrapFrame; +use crate::{ + alloc::vec::Vec, + arch::ipc::signal::SigSet, + arch::syscall::nr::SYS_RT_SIGPENDING, + process::ProcessManager, + syscall::{ + table::{FormattedSyscallParam, Syscall}, + user_access::UserBufferWriter, + }, +}; +use core::mem::size_of; +use syscall_table_macros::declare_syscall; +use system_error::SystemError; +pub struct SysSigpendingHandle; + +#[inline(never)] +pub(super) fn do_kernel_rt_sigpending( + user_sigset_ptr: usize, + sigsetsize: usize, +) -> Result { + if sigsetsize != size_of::() { + return Err(SystemError::EINVAL); + } + + let mut user_buffer_writer = + UserBufferWriter::new(user_sigset_ptr as *mut SigSet, size_of::(), true)?; + + let pcb = ProcessManager::current_pcb(); + let siginfo_guard = pcb.sig_info_irqsave(); + let pending_set = siginfo_guard.sig_pending().signal(); + let shared_pending_set = siginfo_guard.sig_shared_pending().signal(); + let blocked_set = *siginfo_guard.sig_blocked(); + drop(siginfo_guard); + + let mut result = pending_set.union(shared_pending_set); + result = result.difference(blocked_set); + + user_buffer_writer.copy_one_to_user(&result, 0)?; + + Ok(0) +} + +impl Syscall for SysSigpendingHandle { + fn num_args(&self) -> usize { + 2 // sigpending(sigset_t *set) + } + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("user_sigset_ptr", format!("{}", args[0])), + FormattedSyscallParam::new("sigsetsize", format!("{}", args[1])), + ] + } + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let user_sigset = SysSigpendingHandle::user_sigset_ptr(args); + let size = SysSigpendingHandle::sigsetsize(args); + + do_kernel_rt_sigpending(user_sigset, size) + } +} + +impl SysSigpendingHandle { + #[inline(always)] + fn user_sigset_ptr(args: &[usize]) -> usize { + // 第一个参数是用户空间信号集的指针 + args[0] + } + + #[inline(always)] + fn sigsetsize(args: &[usize]) -> usize { + // 第二个参数是 sigset_t 的大小 + args[1] + } +} + +declare_syscall!(SYS_RT_SIGPENDING, SysSigpendingHandle); diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 48237caf..b7d37046 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -1,12 +1,16 @@ #![no_main] // <1> +#![no_std] #![feature(alloc_error_handler)] +#![feature(asm_goto)] #![feature(new_zeroed_alloc)] #![feature(allocator_api)] #![feature(arbitrary_self_types)] #![feature(concat_idents)] #![feature(const_for)] +#![feature(const_size_of_val)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] +#![feature(c_variadic)] #![feature(c_void_variant)] #![feature(extract_if)] #![feature(fn_align)] @@ -17,12 +21,20 @@ #![feature(slice_ptr_get)] #![feature(sync_unsafe_cell)] #![feature(vec_into_raw_parts)] -#![feature(c_variadic)] -#![feature(asm_goto)] -#![cfg_attr(target_os = "none", no_std)] -#![allow(static_mut_refs, non_local_definitions, internal_features)] +#![feature(linkage)] +#![feature(panic_can_unwind)] +#![allow( + static_mut_refs, + non_local_definitions, + internal_features, + non_upper_case_globals +)] // clippy的配置 #![deny(clippy::all)] +// 取消下面的注释以启用clippy对栈帧大小的检查 +// #![deny(clippy::large_stack_frames)] +// #![deny(clippy::large_const_arrays)] + // DragonOS允许在函数中使用return语句(尤其是长函数时,我们推荐这么做) #![allow( clippy::macro_metavars_in_unsafe, @@ -63,6 +75,7 @@ mod sched; mod smp; mod syscall; mod time; +mod tracepoint; #[cfg(target_arch = "x86_64")] mod virt; diff --git a/kernel/src/libs/elf.rs b/kernel/src/libs/elf.rs index 7cbfdb91..7ccbe6a5 100644 --- a/kernel/src/libs/elf.rs +++ b/kernel/src/libs/elf.rs @@ -7,10 +7,10 @@ use core::{ use alloc::vec::Vec; use elf::{ - abi::{PT_GNU_PROPERTY, PT_INTERP}, + abi::{ET_DYN, ET_EXEC, PT_GNU_PROPERTY, PT_INTERP, PT_LOAD}, endian::AnyEndian, file::FileHeader, - segment::ProgramHeader, + segment::{ProgramHeader, SegmentTable}, }; use log::error; use system_error::SystemError; @@ -18,7 +18,6 @@ use system_error::SystemError; use crate::{ arch::{CurrentElfArch, MMArch}, driver::base::block::SeekFrom, - filesystem::vfs::file::File, libs::align::page_align_up, mm::{ allocator::page_frame::{PageFrameCount, VirtPageFrame}, @@ -28,7 +27,9 @@ use crate::{ }, process::{ abi::AtType, - exec::{BinaryLoader, BinaryLoaderResult, ExecError, ExecLoadMode, ExecParam}, + exec::{ + BinaryLoader, BinaryLoaderResult, ExecError, ExecLoadMode, ExecParam, ExecParamFlags, + }, ProcessFlags, ProcessManager, }, syscall::user_access::{clear_user, copy_to_user}, @@ -106,6 +107,19 @@ impl ElfLoader { return self.inner_probe_common(param, ehdr); } + #[cfg(target_arch = "loongarch64")] + pub fn probe_loongarch( + &self, + param: &ExecParam, + ehdr: &FileHeader, + ) -> Result<(), ExecError> { + // 判断架构是否匹配 + if ElfMachine::from(ehdr.e_machine) != ElfMachine::LoongArch { + return Err(ExecError::WrongArchitecture); + } + return self.inner_probe_common(param, ehdr); + } + /// 设置用户堆空间,映射[start, end)区间的虚拟地址,并把brk指针指向end /// /// ## 参数 @@ -121,8 +135,8 @@ impl ElfLoader { end: VirtAddr, prot_flags: ProtFlags, ) -> Result<(), ExecError> { - let start = self.elf_page_start(start); - let end = self.elf_page_align_up(end); + let start = Self::elf_page_start(start); + let end = Self::elf_page_align_up(end); // debug!("set_elf_brk: start={:?}, end={:?}", start, end); if end > start { let r = user_vm_guard.map_anonymous( @@ -145,15 +159,15 @@ impl ElfLoader { } /// 计算addr在ELF PAGE内的偏移 - fn elf_page_offset(&self, addr: VirtAddr) -> usize { + fn elf_page_offset(addr: VirtAddr) -> usize { addr.data() & (CurrentElfArch::ELF_PAGE_SIZE - 1) } - fn elf_page_start(&self, addr: VirtAddr) -> VirtAddr { + fn elf_page_start(addr: VirtAddr) -> VirtAddr { VirtAddr::new(addr.data() & (!(CurrentElfArch::ELF_PAGE_SIZE - 1))) } - fn elf_page_align_up(&self, addr: VirtAddr) -> VirtAddr { + fn elf_page_align_up(addr: VirtAddr) -> VirtAddr { VirtAddr::new( (addr.data() + CurrentElfArch::ELF_PAGE_SIZE - 1) & (!(CurrentElfArch::ELF_PAGE_SIZE - 1)), @@ -161,7 +175,7 @@ impl ElfLoader { } /// 根据ELF的p_flags生成对应的ProtFlags - fn make_prot(&self, p_flags: u32, _has_interpreter: bool, _is_interpreter: bool) -> ProtFlags { + fn make_prot(p_flags: u32, _has_interpreter: bool, _is_interpreter: bool) -> ProtFlags { let mut prot = ProtFlags::empty(); if p_flags & elf::abi::PF_R != 0 { prot |= ProtFlags::PROT_READ; @@ -198,7 +212,6 @@ impl ElfLoader { /// - `Ok((VirtAddr, bool))`:如果成功加载,则bool值为true,否则为false. VirtAddr为加载的地址 #[allow(clippy::too_many_arguments)] fn load_elf_segment( - &self, user_vm_guard: &mut RwLockWriteGuard<'_, InnerAddressSpace>, param: &mut ExecParam, phent: &ProgramHeader, @@ -210,11 +223,11 @@ impl ElfLoader { // debug!("load_elf_segment: addr_to_map={:?}", addr_to_map); // 映射位置的偏移量(页内偏移) - let beginning_page_offset = self.elf_page_offset(addr_to_map); - addr_to_map = self.elf_page_start(addr_to_map); + let beginning_page_offset = Self::elf_page_offset(addr_to_map); + addr_to_map = Self::elf_page_start(addr_to_map); // 计算要映射的内存的大小 let map_size = phent.p_filesz as usize + beginning_page_offset; - let map_size = self.elf_page_align_up(VirtAddr::new(map_size)).data(); + let map_size = Self::elf_page_align_up(VirtAddr::new(map_size)).data(); // 当前段在文件中的大小 let seg_in_file_size = phent.p_filesz as usize; // 当前段在文件中的偏移量 @@ -253,7 +266,9 @@ impl ElfLoader { // So we first map the 'big' image - and unmap the remainder at // the end. (which unmap is needed for ELF images with holes.) if total_size != 0 { - let total_size = self.elf_page_align_up(VirtAddr::new(total_size)).data(); + let total_size = Self::elf_page_align_up(VirtAddr::new(total_size)).data(); + + // log::debug!("total_size={}", total_size); map_addr = user_vm_guard .map_anonymous(addr_to_map, total_size, tmp_prot, *map_flags, false, true) @@ -269,7 +284,7 @@ impl ElfLoader { )?; // 加载文件到内存 - self.do_load_file( + Self::do_load_file( map_addr + beginning_page_offset, seg_in_file_size, file_offset, @@ -294,7 +309,7 @@ impl ElfLoader { // ); // 加载文件到内存 - self.do_load_file( + Self::do_load_file( map_addr + beginning_page_offset, seg_in_file_size, file_offset, @@ -313,6 +328,152 @@ impl ElfLoader { return Ok((map_addr, true)); } + /// 加载elf动态链接器 + /// + /// ## 参数 + /// + /// - `interp_elf_ex`:动态链接器 + /// - `load_bias`偏移量 + /// + /// ## TODO + /// + /// 添加一个Arch state抽象,描述架构相关的elf state(参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#592) + fn load_elf_interp( + interp_elf_ex: &mut ExecParam, + load_bias: usize, + ) -> Result { + // log::debug!("loading elf interp"); + let mut head_buf = [0u8; 512]; + interp_elf_ex + .file_mut() + .lseek(SeekFrom::SeekSet(0)) + .map_err(|_| ExecError::NotSupported)?; + let _bytes = interp_elf_ex + .file_mut() + .read(512, &mut head_buf) + .map_err(|_| ExecError::NotSupported)?; + let interp_hdr = + Self::parse_ehdr(head_buf.as_ref()).map_err(|_| ExecError::NotExecutable)?; + if interp_hdr.e_type != ET_EXEC && interp_hdr.e_type != ET_DYN { + return Err(ExecError::NotExecutable); + } + let mut phdr_buf = Vec::new(); + let phdr_table = Self::parse_segments(interp_elf_ex, &interp_hdr, &mut phdr_buf) + .map_err(|_| ExecError::ParseError)? + .ok_or(ExecError::ParseError)?; + //TODO 架构相关检查 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#610 + let mut total_size = Self::total_mapping_size(&phdr_table); + + if total_size == 0 { + return Err(ExecError::InvalidParemeter); + } + + let mut load_addr_set = false; + let mut load_addr: VirtAddr = VirtAddr::new(0); + let mut elf_bss: VirtAddr = VirtAddr::new(0); + let mut last_bss: VirtAddr = VirtAddr::new(0); + let mut bss_prot: Option = None; + for section in phdr_table { + if section.p_type == PT_LOAD { + // log::debug!("loading {:?}", section); + let mut elf_type = MapFlags::MAP_PRIVATE; + let elf_prot = Self::make_prot(section.p_flags, true, true); + let vaddr = TryInto::::try_into(section.p_vaddr).unwrap(); + let mut addr_to_map = load_addr + vaddr; + if interp_hdr.e_type == ET_EXEC || load_addr_set { + elf_type.insert(MapFlags::MAP_FIXED) + } else if load_bias != 0 && interp_hdr.e_type == ET_DYN { + addr_to_map = VirtAddr::new(0); + } + let map_addr = Self::load_elf_segment( + &mut interp_elf_ex.vm().clone().write(), + interp_elf_ex, + §ion, + addr_to_map, + &elf_prot, + &elf_type, + total_size, + ) + .map_err(|e| { + log::error!("Failed to load elf interpreter :{:?}", e); + return ExecError::InvalidParemeter; + })?; + if !map_addr.1 { + return Err(ExecError::BadAddress(Some(map_addr.0))); + } + let map_addr = map_addr.0; + total_size = 0; + if !load_addr_set && interp_hdr.e_type == ET_DYN { + load_addr = + VirtAddr::new(map_addr - Self::elf_page_start(VirtAddr::new(vaddr))); + load_addr_set = true; + } + let addr = load_addr + TryInto::::try_into(section.p_vaddr).unwrap(); + if addr >= MMArch::USER_END_VADDR + || section.p_filesz > section.p_memsz + || TryInto::::try_into(section.p_memsz).unwrap() + > MMArch::USER_END_VADDR.data() + || MMArch::USER_END_VADDR - TryInto::::try_into(section.p_memsz).unwrap() + < addr + { + return Err(ExecError::OutOfMemory); + } + + let addr = load_addr + + TryInto::::try_into(section.p_vaddr + section.p_filesz).unwrap(); + if addr > elf_bss { + elf_bss = addr; + } + + let addr = load_addr + + TryInto::::try_into(section.p_vaddr + section.p_memsz).unwrap(); + if addr > last_bss { + last_bss = addr; + bss_prot = Some(elf_prot); + } + } + } + Self::pad_zero(elf_bss).map_err(|_| return ExecError::BadAddress(Some(elf_bss)))?; + elf_bss = Self::elf_page_align_up(elf_bss); + last_bss = Self::elf_page_align_up(last_bss); + if last_bss > elf_bss { + if bss_prot.is_none() { + return Err(ExecError::InvalidParemeter); + } + let mut bss_prot = bss_prot.unwrap(); + if bss_prot.contains(ProtFlags::PROT_EXEC) { + bss_prot = ProtFlags::PROT_EXEC; + } else { + bss_prot = ProtFlags::PROT_NONE; + } + interp_elf_ex + .vm() + .clone() + .write() + .map_anonymous( + elf_bss, + last_bss - elf_bss, + bss_prot, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED_NOREPLACE, + false, + true, + ) + .map_err(|e| match e { + SystemError::EINVAL => ExecError::InvalidParemeter, + SystemError::ENOMEM => ExecError::OutOfMemory, + _ => return ExecError::InvalidParemeter, + })?; + } + load_addr += TryInto::::try_into(interp_hdr.e_entry).unwrap(); + if load_addr > MMArch::USER_END_VADDR { + return Err(ExecError::BadAddress(Some( + load_addr + TryInto::::try_into(interp_hdr.e_entry).unwrap(), + ))); + } + // log::debug!("sucessfully load elf interp"); + return Ok(BinaryLoaderResult::new(load_addr)); + } + /// 加载ELF文件到用户空间 /// /// ## 参数 @@ -322,7 +483,6 @@ impl ElfLoader { /// - `offset_in_file`:在文件内的偏移量 /// - `param`:执行参数 fn do_load_file( - &self, mut vaddr: VirtAddr, size: usize, offset_in_file: usize, @@ -354,8 +514,8 @@ impl ElfLoader { } /// 我们需要显式的把数据段之后剩余的内存页都清零。 - fn pad_zero(&self, elf_bss: VirtAddr) -> Result<(), SystemError> { - let nbyte = self.elf_page_offset(elf_bss); + fn pad_zero(elf_bss: VirtAddr) -> Result<(), SystemError> { + let nbyte = Self::elf_page_offset(elf_bss); if nbyte > 0 { let nbyte = CurrentElfArch::ELF_PAGE_SIZE - nbyte; unsafe { clear_user(elf_bss, nbyte).map_err(|_| SystemError::EFAULT) }?; @@ -363,6 +523,37 @@ impl ElfLoader { return Ok(()); } + /// 参考https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1158,获取要加载的total_size + fn total_mapping_size(ehdr_table: &SegmentTable<'_, AnyEndian>) -> usize { + let mut has_load = false; + let mut min_address = VirtAddr::new(usize::MAX); + let mut max_address = VirtAddr::new(0usize); + let loadable_sections = ehdr_table + .into_iter() + .filter(|seg| seg.p_type == elf::abi::PT_LOAD); + for seg_to_load in loadable_sections { + min_address = min( + min_address, + Self::elf_page_start(VirtAddr::new(seg_to_load.p_vaddr.try_into().unwrap())), + ); + max_address = max( + max_address, + VirtAddr::new( + (seg_to_load.p_vaddr + seg_to_load.p_memsz) + .try_into() + .unwrap(), + ), + ); + has_load = true; + } + let total_size = if has_load { + max_address - min_address + } else { + 0 + }; + return total_size; + } + /// 创建auxv /// /// ## 参数 @@ -512,7 +703,14 @@ impl BinaryLoader for ElfLoader { #[cfg(target_arch = "riscv64")] return self.probe_riscv(param, &ehdr); - #[cfg(not(any(target_arch = "x86_64", target_arch = "riscv64")))] + #[cfg(target_arch = "loongarch64")] + return self.probe_loongarch(param, &ehdr); + + #[cfg(not(any( + target_arch = "x86_64", + target_arch = "riscv64", + target_arch = "loongarch64" + )))] compile_error!("BinaryLoader: Unsupported architecture"); } @@ -542,7 +740,7 @@ impl BinaryLoader for ElfLoader { .map_err(|_| ExecError::ParseError)? .ok_or(ExecError::ParseError)?; let mut _gnu_property_data: Option = None; - let interpreter: Option = None; + let mut interpreter: Option = None; for seg in phdr_table { if seg.p_type == PT_GNU_PROPERTY { _gnu_property_data = Some(seg); @@ -558,22 +756,42 @@ impl BinaryLoader for ElfLoader { if seg.p_filesz > 4096 || seg.p_filesz < 2 { return Err(ExecError::NotExecutable); } - - let interpreter_ptr = unsafe { - core::slice::from_raw_parts( - seg.p_offset as *const u8, + let mut buffer = vec![0; seg.p_filesz.try_into().unwrap()]; + let r = param + .file_mut() + .pread( + seg.p_offset.try_into().unwrap(), seg.p_filesz.try_into().unwrap(), + buffer.as_mut_slice(), ) - }; - let _interpreter_path = core::str::from_utf8(interpreter_ptr).map_err(|e| { + .map_err(|e| { + log::error!("Failed to load interpreter :{:?}", e); + return ExecError::NotSupported; + })?; + if r != seg.p_filesz.try_into().unwrap() { + log::error!("Failed to load interpreter "); + return Err(ExecError::NotSupported); + } + let interpreter_path = core::str::from_utf8( + &buffer[0..TryInto::::try_into(seg.p_filesz).unwrap() - 1], + ) + .map_err(|e| { ExecError::Other(format!( "Failed to parse the path of dynamic linker with error {}", e )) })?; - - //TODO 加入对动态链接器的加载,参照 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#890 + // log::debug!("opening interpreter at :{}", interpreter_path); + interpreter = Some( + ExecParam::new(interpreter_path, param.vm().clone(), ExecParamFlags::EXEC) + .map_err(|e| { + log::error!("Failed to load interpreter {interpreter_path}: {:?}", e); + return ExecError::NotSupported; + })?, + ); } + //TODO 缺少一部分逻辑 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#931 + if interpreter.is_some() { /* Some simple consistency checks for the interpreter */ // 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#950 @@ -595,39 +813,14 @@ impl BinaryLoader for ElfLoader { // program header的虚拟地址 let mut phdr_vaddr: Option = None; let mut _reloc_func_desc = 0usize; - // 参考https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1158,获取要加载的total_size - let mut has_load = false; - let mut min_address = VirtAddr::new(usize::MAX); - let mut max_address = VirtAddr::new(0usize); + + let total_size = Self::total_mapping_size(&phdr_table); let loadable_sections = phdr_table .into_iter() .filter(|seg| seg.p_type == elf::abi::PT_LOAD); for seg_to_load in loadable_sections { - min_address = min( - min_address, - self.elf_page_start(VirtAddr::new(seg_to_load.p_vaddr.try_into().unwrap())), - ); - max_address = max( - max_address, - VirtAddr::new( - (seg_to_load.p_vaddr + seg_to_load.p_memsz) - .try_into() - .unwrap(), - ), - ); - has_load = true; - } - let total_size = if has_load { - max_address - min_address - } else { - 0 - }; - let loadable_sections = phdr_table - .into_iter() - .filter(|seg| seg.p_type == elf::abi::PT_LOAD); - for seg_to_load in loadable_sections { - // debug!("seg_to_load = {:?}", seg_to_load); + // log::debug!("seg_to_load = {:?}", seg_to_load); if unlikely(elf_brk > elf_bss) { // debug!( // "to set brk, elf_brk = {:?}, elf_bss = {:?}", @@ -640,7 +833,7 @@ impl BinaryLoader for ElfLoader { elf_brk + load_bias, bss_prot_flags, )?; - let nbyte = self.elf_page_offset(elf_bss); + let nbyte = Self::elf_page_offset(elf_bss); if nbyte > 0 { let nbyte = min(CurrentElfArch::ELF_PAGE_SIZE - nbyte, elf_brk - elf_bss); unsafe { @@ -652,7 +845,7 @@ impl BinaryLoader for ElfLoader { } // 生成ProtFlags. - let elf_prot_flags = self.make_prot(seg_to_load.p_flags, interpreter.is_some(), false); + let elf_prot_flags = Self::make_prot(seg_to_load.p_flags, interpreter.is_some(), false); let mut elf_map_flags = MapFlags::MAP_PRIVATE; @@ -681,37 +874,33 @@ impl BinaryLoader for ElfLoader { load_bias = 0; } } - load_bias = self - .elf_page_start(VirtAddr::new( - load_bias - TryInto::::try_into(seg_to_load.p_vaddr).unwrap(), - )) - .data(); + load_bias = Self::elf_page_start(VirtAddr::new( + load_bias - TryInto::::try_into(seg_to_load.p_vaddr).unwrap(), + )) + .data(); if total_size == 0 { return Err(ExecError::InvalidParemeter); } } // 加载这个段到用户空间 - // debug!("to load elf segment"); - let e = self - .load_elf_segment( - &mut user_vm, - param, - &seg_to_load, - vaddr + load_bias, - &elf_prot_flags, - &elf_map_flags, - total_size, - ) - .map_err(|e| { - error!("load_elf_segment failed: {:?}", e); - match e { - SystemError::EFAULT => ExecError::BadAddress(None), - SystemError::ENOMEM => ExecError::OutOfMemory, - _ => ExecError::Other(format!("load_elf_segment failed: {:?}", e)), - } - })?; + // log::debug!("bias: {load_bias}"); + let e = Self::load_elf_segment( + &mut user_vm, + param, + &seg_to_load, + vaddr + load_bias, + &elf_prot_flags, + &elf_map_flags, + total_size, + ) + .map_err(|e| match e { + SystemError::EFAULT => ExecError::BadAddress(None), + SystemError::ENOMEM => ExecError::OutOfMemory, + _ => ExecError::Other(format!("load_elf_segment failed: {:?}", e)), + })?; + // log::debug!("e.0={:?}", e.0); // 如果地址不对,那么就报错 if !e.1 { return Err(ExecError::BadAddress(Some(e.0))); @@ -722,12 +911,10 @@ impl BinaryLoader for ElfLoader { if elf_type == ElfType::DSO { // todo: 在这里增加对load_bias和reloc_func_desc的更新代码 load_bias += e.0.data() - - self - .elf_page_start(VirtAddr::new( - load_bias - + TryInto::::try_into(seg_to_load.p_vaddr).unwrap(), - )) - .data(); + - Self::elf_page_start(VirtAddr::new( + load_bias + TryInto::::try_into(seg_to_load.p_vaddr).unwrap(), + )) + .data(); _reloc_func_desc = load_bias; } } @@ -761,7 +948,7 @@ impl BinaryLoader for ElfLoader { // 如果程序段要加载的目标地址不在用户空间内,或者是其他不合法的情况,那么就报错 if !p_vaddr.check_user() || seg_to_load.p_filesz > seg_to_load.p_memsz - || self.elf_page_align_up(p_vaddr + seg_to_load.p_memsz as usize) + || Self::elf_page_align_up(p_vaddr + seg_to_load.p_memsz as usize) >= MMArch::USER_END_VADDR { // debug!("ERR: p_vaddr={p_vaddr:?}"); @@ -769,7 +956,7 @@ impl BinaryLoader for ElfLoader { } // end vaddr of this segment(code+data+bss) - let seg_end_vaddr_f = self.elf_page_align_up(VirtAddr::new( + let seg_end_vaddr_f = Self::elf_page_align_up(VirtAddr::new( (seg_to_load.p_vaddr + seg_to_load.p_filesz) as usize, )); @@ -807,7 +994,7 @@ impl BinaryLoader for ElfLoader { end_code = end_code.map(|v| v + load_bias); start_data = start_data.map(|v| v + load_bias); end_data = end_data.map(|v| v + load_bias); - + let mut interp_load_addr: Option = None; // debug!( // "to set brk: elf_bss: {:?}, elf_brk: {:?}, bss_prot_flags: {:?}", // elf_bss, @@ -816,16 +1003,27 @@ impl BinaryLoader for ElfLoader { // ); self.set_elf_brk(&mut user_vm, elf_bss, elf_brk, bss_prot_flags)?; - if likely(elf_bss != elf_brk) && unlikely(self.pad_zero(elf_bss).is_err()) { + if likely(elf_bss != elf_brk) && unlikely(Self::pad_zero(elf_bss).is_err()) { // debug!("elf_bss = {elf_bss:?}, elf_brk = {elf_brk:?}"); return Err(ExecError::BadAddress(Some(elf_bss))); } - if interpreter.is_some() { - // TODO 添加对动态加载器的处理 + drop(user_vm); + if let Some(mut interpreter) = interpreter { // 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1249 + let elf_entry = Self::load_elf_interp(&mut interpreter, load_bias)?.entry_point(); + interp_load_addr = Some(elf_entry); + _reloc_func_desc = elf_entry.data(); + //参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1269 + //TODO allow_write_access(interpreter); + ProcessManager::current_pcb() + .fd_table() + .write() + .alloc_fd(interpreter.file(), None) + .map(|fd| fd as usize) + .map_err(|_| ExecError::InvalidParemeter)?; } // debug!("to create auxv"); - + let mut user_vm = binding.write(); self.create_auxv(param, program_entrypoint, phdr_vaddr, &ehdr)?; // debug!("auxv create ok"); @@ -834,8 +1032,8 @@ impl BinaryLoader for ElfLoader { user_vm.start_data = start_data.unwrap_or(VirtAddr::new(0)); user_vm.end_data = end_data.unwrap_or(VirtAddr::new(0)); - let result = BinaryLoaderResult::new(program_entrypoint); - // debug!("elf load OK!!!"); + let result = BinaryLoaderResult::new(interp_load_addr.unwrap_or(program_entrypoint)); + // kdebug!("elf load OK!!!"); return Ok(result); } } diff --git a/kernel/src/libs/futex/futex.rs b/kernel/src/libs/futex/futex.rs index cc651ad2..59e3d431 100644 --- a/kernel/src/libs/futex/futex.rs +++ b/kernel/src/libs/futex/futex.rs @@ -677,7 +677,7 @@ impl RobustListHead { /// - head_uaddr:robust list head用户空间地址 /// - len:robust list head的长度 pub fn set_robust_list(head_uaddr: VirtAddr, len: usize) -> Result { - let robust_list_head_len = mem::size_of::<&RobustListHead>(); + let robust_list_head_len = mem::size_of::(); if unlikely(len != robust_list_head_len) { return Err(SystemError::EINVAL); } diff --git a/kernel/src/libs/lib_ui/textui.h b/kernel/src/libs/lib_ui/textui.h deleted file mode 100644 index 74dcfbfd..00000000 --- a/kernel/src/libs/lib_ui/textui.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -/** - * @brief 在默认窗口上输出一个字符 - * - * @param character 字符 - * @param FRcolor 前景色(RGB) - * @param BKcolor 背景色(RGB) - * @return int - */ -extern int rs_textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor); diff --git a/kernel/src/libs/lib_ui/textui.rs b/kernel/src/libs/lib_ui/textui.rs index 69558b6e..6714181b 100644 --- a/kernel/src/libs/lib_ui/textui.rs +++ b/kernel/src/libs/lib_ui/textui.rs @@ -1,8 +1,5 @@ use crate::{ - driver::{ - serial::serial8250::send_to_default_serial8250_port, tty::virtual_terminal::vc_manager, - video::video_refresh_manager, - }, + driver::{serial::serial8250::send_to_default_serial8250_port, video::video_refresh_manager}, libs::{ lib_ui::font::FONT_8x16, rwlock::RwLock, @@ -1017,69 +1014,6 @@ where } } -/// 在默认窗口上输出一个字符 -/// ## 参数 -/// - character 字符 -/// - FRcolor 前景色(RGB) -/// - BKcolor 背景色(RGB) -#[no_mangle] -pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 { - if let Some(current_vc) = vc_manager().current_vc() { - // tty已经初始化了之后才输出到屏幕 - let fr = (fr_color & 0x00ff0000) >> 16; - let fg = (fr_color & 0x0000ff00) >> 8; - let fb = fr_color & 0x000000ff; - let br = (bk_color & 0x00ff0000) >> 16; - let bg = (bk_color & 0x0000ff00) >> 8; - let bb = bk_color & 0x000000ff; - let buf = format!( - "\x1B[38;2;{fr};{fg};{fb};48;2;{br};{bg};{bb}m{}\x1B[0m", - character as char - ); - let port = current_vc.port(); - let tty = port.port_data().internal_tty(); - if let Some(tty) = tty { - return tty - .write_to_core(buf.as_bytes(), buf.len()) - .map(|_| 0) - .unwrap_or_else(|e| e.to_posix_errno()); - } - } - return textui_putchar( - character as char, - FontColor::from(fr_color), - FontColor::from(bk_color), - ) - .map(|_| 0) - .unwrap_or_else(|e| e.to_posix_errno()); -} - -pub fn textui_putchar( - character: char, - fr_color: FontColor, - bk_color: FontColor, -) -> Result<(), SystemError> { - if unsafe { TEXTUI_IS_INIT } { - return textui_framework() - .current_window - .lock_irqsave() - .textui_putchar_window( - character, - fr_color, - bk_color, - textui_is_enable_put_to_window(), - ); - } else { - //未初始化暴力输出 - return no_init_textui_putchar_window( - character, - fr_color, - bk_color, - textui_is_enable_put_to_window(), - ); - } -} - /// 向默认窗口输出一个字符串 pub fn textui_putstr( string: &str, diff --git a/kernel/src/libs/printk.c b/kernel/src/libs/printk.c deleted file mode 100644 index 9d45e3ac..00000000 --- a/kernel/src/libs/printk.c +++ /dev/null @@ -1,631 +0,0 @@ -// -// Created by longjin on 2022/1/22. -// -#include -#include - -#include -#include -#include - -#include -#include - -static spinlock_t __printk_lock = {1}; -/** - * @brief 将数字按照指定的要求转换成对应的字符串(2~36进制) - * - * @param str 要返回的字符串 - * @param num 要打印的数值 - * @param base 基数 - * @param field_width 区域宽度 - * @param precision 精度 - * @param flags 标志位 - */ -static char *write_num(char *str, ul num, int base, int field_width, int precision, int flags); - -static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags); - -static int skip_and_atoi(const char **s) -{ - /** - * @brief 获取连续的一段字符对应整数的值 - * @param:**s 指向 指向字符串的指针 的指针 - */ - int ans = 0; - while (is_digit(**s)) - { - ans = ans * 10 + (**s) - '0'; - ++(*s); - } - return ans; -} - -/** - * @brief 将字符串按照fmt和args中的内容进行格式化,当buf_size为-1时,字符串直接保存到buf中 - * 否则将字符串前buf_size-1个字符放入,大小为buf_size的buf数组中 - * - * @param buf 结果缓冲区 - * @param fmt 格式化字符串 - * @param args 内容 - * @param buf_size buf_size为-1时,不指定buf的大小,否则buf大小为buf_size - * @return 最终字符串的长度 - */ -static int __do_vsprintf(char *buf, const char *fmt, int buf_size, va_list args) -{ - - // 当需要输出的字符串的指针为空时,使用该字符填充目标字符串的指针 - static const char __end_zero_char = '\0'; - - char *str = NULL, *s = NULL, *end = NULL; - - str = buf; - - int flags; // 用来存储格式信息的bitmap - int field_width; //区域宽度 - int precision; //精度 - int qualifier; //数据显示的类型 - int len; - - if (buf_size != -1) - { - end = buf + buf_size; - } - //开始解析字符串 - for (; *fmt; ++fmt) - { - //内容不涉及到格式化,直接输出 - if (*fmt != '%') - { - *str = *fmt; - ++str; - continue; - } - - //开始格式化字符串 - - //清空标志位和field宽度 - field_width = flags = 0; - - bool flag_tmp = true; - bool flag_break = false; - - ++fmt; - while (flag_tmp) - { - switch (*fmt) - { - case '\0': - //结束解析 - flag_break = true; - flag_tmp = false; - break; - - case '-': - // 左对齐 - flags |= LEFT; - ++fmt; - break; - case '+': - //在正数前面显示加号 - flags |= PLUS; - ++fmt; - break; - case ' ': - flags |= SPACE; - ++fmt; - break; - case '#': - //在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X' - flags |= SPECIAL; - ++fmt; - break; - case '0': - //显示的数字之前填充‘0’来取代空格 - flags |= PAD_ZERO; - ++fmt; - break; - default: - flag_tmp = false; - break; - } - } - if (flag_break) - break; - - //获取区域宽度 - field_width = -1; - if (*fmt == '*') - { - field_width = va_arg(args, int); - ++fmt; - } - else if (is_digit(*fmt)) - { - field_width = skip_and_atoi(&fmt); - if (field_width < 0) - { - field_width = -field_width; - flags |= LEFT; - } - } - - //获取小数精度 - precision = -1; - if (*fmt == '.') - { - ++fmt; - if (*fmt == '*') - { - precision = va_arg(args, int); - ++fmt; - } - else if (is_digit(*fmt)) - { - precision = skip_and_atoi(&fmt); - } - } - - //获取要显示的数据的类型 - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z') - { - qualifier = *fmt; - ++fmt; - } - //为了支持lld - if (qualifier == 'l' && *fmt == 'l', *(fmt + 1) == 'd') - ++fmt; - - //转化成字符串 - long long *ip; - switch (*fmt) - { - //输出 % - case '%': - *str++ = '%'; - - break; - // 显示一个字符 - case 'c': - //靠右对齐 - if (!(flags & LEFT)) - { - while (--field_width > 0) - { - *str = ' '; - ++str; - } - } - - *str++ = (unsigned char)va_arg(args, int); - - while (--field_width > 0) - { - *str = ' '; - ++str; - } - - break; - - //显示一个字符串 - case 's': - s = va_arg(args, char *); - if (!s) - s = &__end_zero_char; - len = strlen(s); - if (precision < 0) - { - //未指定精度 - precision = len; - } - - else if (len > precision) - { - len = precision; - } - - //靠右对齐 - if (!(flags & LEFT)) - while (len < field_width--) - { - *str = ' '; - ++str; - } - - for (int i = 0; i < len; i++) - { - *str = *s; - ++s; - ++str; - } - - while (len < field_width--) - { - *str = ' '; - ++str; - } - - break; - //以八进制显示字符串 - case 'o': - flags |= SMALL; - case 'O': - flags |= SPECIAL; - if (qualifier == 'l') - str = write_num(str, va_arg(args, long long), 8, field_width, precision, flags); - else - str = write_num(str, va_arg(args, int), 8, field_width, precision, flags); - break; - - //打印指针指向的地址 - case 'p': - if (field_width == 0) - { - field_width = 2 * sizeof(void *); - flags |= PAD_ZERO; - } - - str = write_num(str, (unsigned long)va_arg(args, void *), 16, field_width, precision, flags); - - break; - - //打印十六进制 - case 'x': - flags |= SMALL; - case 'X': - // flags |= SPECIAL; - if (qualifier == 'l') - str = write_num(str, va_arg(args, ll), 16, field_width, precision, flags); - else - str = write_num(str, va_arg(args, int), 16, field_width, precision, flags); - break; - - //打印十进制有符号整数 - case 'i': - case 'd': - - flags |= SIGN; - if (qualifier == 'l') - str = write_num(str, va_arg(args, long long), 10, field_width, precision, flags); - else - str = write_num(str, va_arg(args, int), 10, field_width, precision, flags); - break; - - //打印十进制无符号整数 - case 'u': - if (qualifier == 'l') - str = write_num(str, va_arg(args, unsigned long long), 10, field_width, precision, flags); - else - str = write_num(str, va_arg(args, unsigned int), 10, field_width, precision, flags); - break; - - //输出有效字符数量到*ip对应的变量 - case 'n': - - if (qualifier == 'l') - ip = va_arg(args, long long *); - else - ip = (ll *)va_arg(args, int *); - - *ip = str - buf; - break; - case 'f': - // 默认精度为3 - // printk("1111\n"); - // va_arg(args, double); - // printk("222\n"); - - if (precision < 0) - precision = 3; - - str = write_float_point_num(str, va_arg(args, double), field_width, precision, flags); - - break; - - //对于不识别的控制符,直接输出 - default: - *str++ = '%'; - if (*fmt) - *str++ = *fmt; - else - --fmt; - break; - } - } - //实现vsnprintf 的功能 - if (buf_size > 0) - { - if (str < end) - { - *str = '\0'; - } - else - { - *(end-1) = '\0'; - } - return buf_size; - } - else - { - *str = '\0'; - } - - //返回缓冲区已有字符串的长度。 - return str - buf; -} - -/** - * 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中 - * @param buf 结果缓冲区 - * @param fmt 格式化字符串 - * @param args 内容 - * @return 最终字符串的长度 - */ -int vsprintf(char *buf, const char *fmt, va_list args) -{ - return __do_vsprintf(buf, fmt, -1, args); -} - -/** - * @brief 将字符串按照fmt和args中的内容进行格式化,截取字符串前buf_size-1,保存到buf中 - * - * @param buf 结果缓冲区,大小为buf_size - * @param fmt 格式化字符串 - * @param buf_size 缓冲区长度 - * @param args 内容 - * @return 最终字符串的长度 - */ -int vsnprintf(char *buf, const char *fmt, int buf_size, va_list args) -{ - return __do_vsprintf(buf, fmt, buf_size, args); -} - -static char *write_num(char *str, ul num, int base, int field_width, int precision, int flags) -{ - /** - * @brief 将数字按照指定的要求转换成对应的字符串 - * - * @param str 要返回的字符串 - * @param num 要打印的数值 - * @param base 基数 - * @param field_width 区域宽度 - * @param precision 精度 - * @param flags 标志位 - */ - - // 首先判断是否支持该进制 - if (base < 2 || base > 36) - return 0; - char pad, sign, tmp_num[100]; - - const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - // 显示小写字母 - if (flags & SMALL) - digits = "0123456789abcdefghijklmnopqrstuvwxyz"; - - if (flags & LEFT) - flags &= ~PAD_ZERO; - // 设置填充元素 - pad = (flags & PAD_ZERO) ? '0' : ' '; - - sign = 0; - - if (flags & SIGN) - { - int64_t signed_num = (int64_t)num; - if (signed_num < 0) - { - sign = '-'; - num = -signed_num; - } - else - num = signed_num; - } - else - { - // 设置符号 - sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0); - } - - // sign占用了一个宽度 - if (sign) - --field_width; - - if (flags & SPECIAL) - if (base == 16) // 0x占用2个位置 - field_width -= 2; - else if (base == 8) // O占用一个位置 - --field_width; - - int js_num = 0; // 临时数字字符串tmp_num的长度 - - if (num == 0) - tmp_num[js_num++] = '0'; - else - { - num = ABS(num); - //进制转换 - while (num > 0) - { - tmp_num[js_num++] = digits[num % base]; // 注意这里,输出的数字,是小端对齐的。低位存低位 - num /= base; - } - } - - if (js_num > precision) - precision = js_num; - - field_width -= precision; - - // 靠右对齐 - if (!(flags & (LEFT + PAD_ZERO))) - while (field_width-- > 0) - *str++ = ' '; - - if (sign) - *str++ = sign; - if (flags & SPECIAL) - if (base == 16) - { - *str++ = '0'; - *str++ = digits[33]; - } - else if (base == 8) - *str++ = digits[24]; //注意这里是英文字母O或者o - if (!(flags & LEFT)) - while (field_width-- > 0) - *str++ = pad; - while (js_num < precision) - { - --precision; - *str++ = '0'; - } - - while (js_num-- > 0) - *str++ = tmp_num[js_num]; - - while (field_width-- > 0) - *str++ = ' '; - - return str; -} - -static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags) -{ - /** - * @brief 将浮点数按照指定的要求转换成对应的字符串 - * - * @param str 要返回的字符串 - * @param num 要打印的数值 - * @param field_width 区域宽度 - * @param precision 精度 - * @param flags 标志位 - */ - - char pad, sign, tmp_num_z[100], tmp_num_d[350]; - - const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - // 显示小写字母 - if (flags & SMALL) - digits = "0123456789abcdefghijklmnopqrstuvwxyz"; - - // 设置填充元素 - pad = (flags & PAD_ZERO) ? '0' : ' '; - sign = 0; - if (flags & SIGN && num < 0) - { - sign = '-'; - num = -num; - } - else - { - // 设置符号 - sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0); - } - - // sign占用了一个宽度 - if (sign) - --field_width; - - int js_num_z = 0, js_num_d = 0; // 临时数字字符串tmp_num_z tmp_num_d的长度 - uint64_t num_z = (uint64_t)(num); // 获取整数部分 - uint64_t num_decimal = (uint64_t)(round(1.0 * (num - num_z) * pow(10, precision))); // 获取小数部分 - - if (num == 0 || num_z == 0) - tmp_num_z[js_num_z++] = '0'; - else - { - //存储整数部分 - while (num_z > 0) - { - tmp_num_z[js_num_z++] = digits[num_z % 10]; // 注意这里,输出的数字,是小端对齐的。低位存低位 - num_z /= 10; - } - } - - while (num_decimal > 0) - { - tmp_num_d[js_num_d++] = digits[num_decimal % 10]; - num_decimal /= 10; - } - - field_width -= (precision + 1 + js_num_z); - - // 靠右对齐 - if (!(flags & LEFT)) - while (field_width-- > 0) - *str++ = pad; - - if (sign) - *str++ = sign; - - // 输出整数部分 - while (js_num_z > 0) - { - *str++ = tmp_num_z[js_num_z - 1]; - --js_num_z; - } - *str++ = '.'; - - // 输出小数部分 - int total_dec_count = js_num_d; - for (int i = 0; i < precision && js_num_d-- > 0; ++i) - *str++ = tmp_num_d[js_num_d]; - - while (total_dec_count < precision) - { - ++total_dec_count; - *str++ = '0'; - } - - while (field_width-- > 0) - *str++ = ' '; - - return str; -} - -/** - * @brief 格式化打印字符串 - * - * @param FRcolor 前景色 - * @param BKcolor 背景色 - * @param ... 格式化字符串 - */ -int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...) -{ - uint64_t rflags; - io_mfence(); - spin_lock_irqsave(&__printk_lock, rflags); - io_mfence(); - va_list args; - va_start(args, fmt); - static char buf[4096]; // vsprintf()的缓冲区 - int len = vsprintf(buf, fmt, args); - - va_end(args); - unsigned char current; - - int i; // 总共输出的字符数 - for (i = 0; i < len; ++i) - { - current = *(buf + i); - // 输出 - rs_textui_putchar(current, FRcolor, BKcolor); - } - io_mfence(); - spin_unlock_irqrestore(&__printk_lock, rflags); - io_mfence(); - return i; -} - -int sprintk(char *buf, const char *fmt, ...) -{ - int count = 0; - va_list args; - - va_start(args, fmt); - count = vsprintf(buf, fmt, args); - va_end(args); - - return count; -} diff --git a/kernel/src/libs/rand.rs b/kernel/src/libs/rand.rs index 581a0465..d001c9ea 100644 --- a/kernel/src/libs/rand.rs +++ b/kernel/src/libs/rand.rs @@ -1,3 +1,5 @@ +use crate::arch::rand::rand; + bitflags! { pub struct GRandFlags: u8{ const GRND_NONBLOCK = 0x0001; @@ -5,3 +7,59 @@ bitflags! { const GRND_INSECURE = 0x0004; } } + +/// Generates an array of random bytes of size `N`. +/// +/// This function fills an array of size `N` with random bytes by repeatedly +/// generating random numbers and converting them to little-endian byte arrays. +/// The function ensures that the entire array is filled with random bytes, +/// even if the size of the array is not a multiple of the size of `usize`. +/// +/// # Type Parameters +/// +/// * `N`: The size of the array to be filled with random bytes. +/// +/// # Returns +/// +/// An array of size `N` filled with random bytes. +/// +/// # Example +/// +/// ```rust +/// let random_bytes = rand_bytes::<16>(); +/// assert_eq!(random_bytes.len(), 16); +/// ``` +pub fn rand_bytes() -> [u8; N] { + let mut bytes = [0u8; N]; + let mut remaining = N; + let mut index = 0; + + while remaining > 0 { + let random_num = rand(); + let random_bytes = random_num.to_le_bytes(); + + let to_copy = core::cmp::min(remaining, size_of::()); + bytes[index..index + to_copy].copy_from_slice(&random_bytes[..to_copy]); + + index += to_copy; + remaining -= to_copy; + } + + bytes +} + +// 软件实现的随机数生成器 +#[allow(dead_code)] +pub fn soft_rand() -> usize { + static mut SEED: u64 = 0xdead_beef_cafe_babe; + let mut buf = [0u8; size_of::()]; + for x in buf.iter_mut() { + unsafe { + // from musl + SEED = SEED.wrapping_mul(0x5851_f42d_4c95_7f2d); + *x = (SEED >> 33) as u8; + } + } + let x: usize = unsafe { core::mem::transmute(buf) }; + return x; +} diff --git a/kernel/src/libs/rwlock.rs b/kernel/src/libs/rwlock.rs index 2fabd5c2..10eac058 100644 --- a/kernel/src/libs/rwlock.rs +++ b/kernel/src/libs/rwlock.rs @@ -202,7 +202,6 @@ impl RwLock { return (self.lock.load(Ordering::Relaxed) & WRITER) / WRITER; } - #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] #[allow(dead_code)] #[inline] /// @brief 尝试获得WRITER守卫 @@ -216,7 +215,6 @@ impl RwLock { return r; } //当架构为arm时,有些代码需要作出调整compare_exchange=>compare_exchange_weak - #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] #[allow(dead_code)] #[inline] pub fn try_write_irqsave(&self) -> Option> { @@ -233,7 +231,6 @@ impl RwLock { return r; } - #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] #[allow(dead_code)] fn inner_try_write(&self) -> Option> { let res: bool = self diff --git a/kernel/src/mm/allocator/buddy.rs b/kernel/src/mm/allocator/buddy.rs index 50ee1a3b..721ee5b3 100644 --- a/kernel/src/mm/allocator/buddy.rs +++ b/kernel/src/mm/allocator/buddy.rs @@ -77,11 +77,12 @@ impl BuddyAllocator { // 定义一个变量记录buddy表的大小 (A::PAGE_SIZE - mem::size_of::>()) / mem::size_of::(); + #[inline(never)] pub unsafe fn new(mut bump_allocator: BumpAllocator) -> Option { let initial_free_pages = bump_allocator.usage().free(); let total_memory = bump_allocator.usage().total(); debug!("Free pages before init buddy: {:?}", initial_free_pages); - debug!("Buddy entries: {}", Self::BUDDY_ENTRIES); + // debug!("Buddy entries: {}", Self::BUDDY_ENTRIES); let mut free_area: [PhysAddr; MAX_ORDER - MIN_ORDER] = [PhysAddr::new(0); MAX_ORDER - MIN_ORDER]; @@ -105,12 +106,12 @@ impl BuddyAllocator { }; let mut total_pages_to_buddy = PageFrameCount::new(0); - let mut res_areas = [PhysMemoryArea::default(); 128]; + static mut RES_AREAS: [PhysMemoryArea; 128] = [PhysMemoryArea::DEFAULT; 128]; let mut offset_in_remain_area = bump_allocator - .remain_areas(&mut res_areas) + .remain_areas(&mut RES_AREAS) .expect("BuddyAllocator: failed to get remain areas from bump allocator"); - let remain_areas = &res_areas[0..]; + let remain_areas = &RES_AREAS[0..]; for area in remain_areas { let mut paddr = (area.area_base_aligned() + offset_in_remain_area).data(); @@ -120,7 +121,7 @@ impl BuddyAllocator { if remain_pages.data() == 0 { continue; } - debug!("area: {area:?}, paddr: {paddr:#x}, remain_pages: {remain_pages:?}"); + // debug!("area: {area:?}, paddr: {paddr:#x}, remain_pages: {remain_pages:?}"); total_pages_to_buddy += remain_pages; diff --git a/kernel/src/mm/allocator/kernel_allocator.rs b/kernel/src/mm/allocator/kernel_allocator.rs index b09a944f..226f7850 100644 --- a/kernel/src/mm/allocator/kernel_allocator.rs +++ b/kernel/src/mm/allocator/kernel_allocator.rs @@ -154,7 +154,7 @@ fn dealloc_debug_log(source: LogSource, layout: Layout, ptr: *mut u8) { ) } -/// 为内核slab分配器实现Allocator特性 +// 为内核slab分配器实现Allocator特性 // unsafe impl Allocator for KernelAllocator { // fn allocate(&self, layout: Layout) -> Result, AllocError> { // let memory = unsafe {self.local_alloc(layout)}; diff --git a/kernel/src/mm/allocator/slab.rs b/kernel/src/mm/allocator/slab.rs index 4ac38a31..b48306e9 100644 --- a/kernel/src/mm/allocator/slab.rs +++ b/kernel/src/mm/allocator/slab.rs @@ -35,6 +35,10 @@ impl SlabAllocator { Ok(nptr) => nptr.as_ptr(), Err(AllocationError::OutOfMemory) => { let boxed_page = ObjectPage::new(); + assert_eq!( + (boxed_page.as_ref() as *const ObjectPage as usize) & (MMArch::PAGE_SIZE - 1), + 0 + ); let leaked_page = Box::leak(boxed_page); self.zone .refill(layout, leaked_page) diff --git a/kernel/src/mm/c_adapter.rs b/kernel/src/mm/c_adapter.rs deleted file mode 100644 index 4f33b91b..00000000 --- a/kernel/src/mm/c_adapter.rs +++ /dev/null @@ -1,119 +0,0 @@ -//! 这是暴露给C的接口,用于在C语言中使用Rust的内存分配器。 - -use core::intrinsics::unlikely; - -use alloc::vec::Vec; -use hashbrown::HashMap; -use log::error; -use system_error::SystemError; - -use crate::libs::spinlock::SpinLock; - -use super::{mmio_buddy::mmio_pool, VirtAddr}; - -lazy_static! { - // 用于记录内核分配给C的空间信息 - static ref C_ALLOCATION_MAP: SpinLock> = SpinLock::new(HashMap::new()); -} - -#[no_mangle] -pub unsafe extern "C" fn kzalloc(size: usize, _gfp: u64) -> usize { - // debug!("kzalloc: size: {size}"); - return do_kmalloc(size, true); -} - -#[no_mangle] -pub unsafe extern "C" fn kmalloc(size: usize, _gfp: u64) -> usize { - // debug!("kmalloc: size: {size}"); - // 由于C代码不规范,因此都全部清空 - return do_kmalloc(size, true); -} - -fn do_kmalloc(size: usize, _zero: bool) -> usize { - let space: Vec = vec![0u8; size]; - - assert!(space.len() == size); - let (ptr, len, cap) = space.into_raw_parts(); - if !ptr.is_null() { - let vaddr = VirtAddr::new(ptr as usize); - let mut guard = C_ALLOCATION_MAP.lock(); - if unlikely(guard.contains_key(&vaddr)) { - drop(guard); - unsafe { - drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap)); - } - panic!( - "do_kmalloc: vaddr {:?} already exists in C Allocation Map, query size: {size}, zero: {_zero}", - vaddr - ); - } - // 插入到C Allocation Map中 - guard.insert(vaddr, (vaddr, len, cap)); - return vaddr.data(); - } else { - return SystemError::ENOMEM.to_posix_errno() as i64 as usize; - } -} - -#[no_mangle] -pub unsafe extern "C" fn kfree(vaddr: usize) -> usize { - let vaddr = VirtAddr::new(vaddr); - let mut guard = C_ALLOCATION_MAP.lock(); - let p = guard.remove(&vaddr); - drop(guard); - - if p.is_none() { - error!("kfree: vaddr {:?} not found in C Allocation Map", vaddr); - return SystemError::EINVAL.to_posix_errno() as i64 as usize; - } - let (vaddr, len, cap) = p.unwrap(); - drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap)); - return 0; -} - -/// @brief 创建一块mmio区域,并将vma绑定到initial_mm -/// -/// @param size mmio区域的大小(字节) -/// -/// @param vm_flags 要把vma设置成的标志 -/// -/// @param res_vaddr 返回值-分配得到的虚拟地址 -/// -/// @param res_length 返回值-分配的虚拟地址空间长度 -/// -/// @return int 错误码 -#[no_mangle] -unsafe extern "C" fn rs_mmio_create( - size: u32, - _vm_flags: u64, - res_vaddr: *mut u64, - res_length: *mut u64, -) -> i32 { - // debug!("mmio_create"); - let r = mmio_pool().create_mmio(size as usize); - if let Err(e) = r { - return e.to_posix_errno(); - } - let space_guard = r.unwrap(); - *res_vaddr = space_guard.vaddr().data() as u64; - *res_length = space_guard.size() as u64; - // 由于space_guard drop的时候会自动释放内存,所以这里要忽略它的释放 - core::mem::forget(space_guard); - return 0; -} - -/// @brief 取消mmio的映射并将地址空间归还到buddy中 -/// -/// @param vaddr 起始的虚拟地址 -/// -/// @param length 要归还的地址空间的长度 -/// -/// @return Ok(i32) 成功返回0 -/// -/// @return Err(i32) 失败返回错误码 -#[no_mangle] -pub unsafe extern "C" fn rs_mmio_release(vaddr: u64, length: u64) -> i32 { - return mmio_pool() - .release_mmio(VirtAddr::new(vaddr as usize), length as usize) - .unwrap_or_else(|err| err.to_posix_errno()); -} diff --git a/kernel/src/mm/fault.rs b/kernel/src/mm/fault.rs index 0fa8e6b0..1c9ee9a8 100644 --- a/kernel/src/mm/fault.rs +++ b/kernel/src/mm/fault.rs @@ -20,10 +20,7 @@ use crate::{ use crate::mm::MemoryManagementArch; -use super::{ - allocator::page_frame::FrameAllocator, - page::{FileMapInfo, Page, PageFlags, PageType}, -}; +use super::page::{Page, PageFlags}; bitflags! { pub struct FaultFlags: u64{ @@ -270,6 +267,7 @@ impl PageFaultHandler { /// /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 + #[inline(never)] pub unsafe fn do_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { if !pfm.flags().contains(FaultFlags::FAULT_FLAG_WRITE) { Self::do_read_fault(pfm) @@ -293,6 +291,7 @@ impl PageFaultHandler { /// /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 + #[inline(never)] pub unsafe fn do_cow_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { let mut ret = Self::filemap_fault(pfm); @@ -316,7 +315,6 @@ impl PageFaultHandler { } else { return VmFaultReason::VM_FAULT_OOM; } - ret = ret.union(Self::finish_fault(pfm)); ret @@ -353,6 +351,7 @@ impl PageFaultHandler { /// /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 + #[inline(never)] pub unsafe fn do_shared_fault(pfm: &mut PageFaultMessage) -> VmFaultReason { let mut ret = Self::filemap_fault(pfm); @@ -413,6 +412,7 @@ impl PageFaultHandler { /// /// ## 返回值 /// - VmFaultReason: 页面错误处理信息标志 + #[inline(never)] pub unsafe fn do_wp_page(pfm: &mut PageFaultMessage) -> VmFaultReason { let address = pfm.address_aligned_down(); let vma = pfm.vma.clone(); @@ -540,7 +540,7 @@ impl PageFaultHandler { let to_pte = min( from_pte + fault_around_page_number, min( - 1 << MMArch::PAGE_SHIFT, + MMArch::PAGE_ENTRY_NUM, pte_pgoff + (vma_pages_count - vm_pgoff), ), ); @@ -589,7 +589,7 @@ impl PageFaultHandler { .expect("file_page_offset is none")) << MMArch::PAGE_SHIFT); - for pgoff in start_pgoff..=end_pgoff { + for pgoff in start_pgoff..end_pgoff { if let Some(page) = page_cache.lock_irqsave().get_page(pgoff) { let page_guard = page.read_irqsave(); if page_guard.flags().contains(PageFlags::PG_UPTODATE) { @@ -621,10 +621,10 @@ impl PageFaultHandler { let file = vma_guard.vm_file().expect("no vm_file in vma"); let page_cache = file.inode().page_cache().unwrap(); let file_pgoff = pfm.file_pgoff.expect("no file_pgoff"); - let mapper = &mut pfm.mapper; let mut ret = VmFaultReason::empty(); - if let Some(page) = page_cache.lock_irqsave().get_page(file_pgoff) { + let page = page_cache.lock_irqsave().get_page(file_pgoff); + if let Some(page) = page { // TODO 异步从磁盘中预读页面进PageCache // 直接将PageCache中的页面作为要映射的页面 @@ -633,37 +633,17 @@ impl PageFaultHandler { // TODO 同步预读 //涉及磁盘IO,返回标志为VM_FAULT_MAJOR ret = VmFaultReason::VM_FAULT_MAJOR; - // let mut buf: Vec = vec![0; MMArch::PAGE_SIZE]; - - let allocator = mapper.allocator_mut(); - - // 分配一个物理页面作为加入PageCache的新页 - let new_cache_page = allocator.allocate_one().unwrap(); - // (MMArch::phys_2_virt(new_cache_page).unwrap().data() as *mut u8) - // .copy_from_nonoverlapping(buf.as_mut_ptr(), MMArch::PAGE_SIZE); + let mut buffer = vec![0u8; MMArch::PAGE_SIZE]; file.pread( file_pgoff * MMArch::PAGE_SIZE, MMArch::PAGE_SIZE, - core::slice::from_raw_parts_mut( - MMArch::phys_2_virt(new_cache_page).unwrap().data() as *mut u8, - MMArch::PAGE_SIZE, - ), + buffer.as_mut_slice(), ) .expect("failed to read file to create pagecache page"); + drop(buffer); - let page = page_manager_lock_irqsave() - .create_one_page( - PageType::File(FileMapInfo { - page_cache: page_cache.clone(), - index: file_pgoff, - }), - PageFlags::PG_LRU, - allocator, - ) - .expect("failed to create page"); - pfm.page = Some(page.clone()); - - page_cache.lock_irqsave().add_page(file_pgoff, &page); + let page = page_cache.lock_irqsave().get_page(file_pgoff); + pfm.page = page; } ret } diff --git a/kernel/src/mm/memblock.rs b/kernel/src/mm/memblock.rs index ae586146..07f487c2 100644 --- a/kernel/src/mm/memblock.rs +++ b/kernel/src/mm/memblock.rs @@ -40,6 +40,9 @@ impl MemBlockManager { pub const MIN_MEMBLOCK_ADDR: PhysAddr = PhysAddr::new(0); #[allow(dead_code)] pub const MAX_MEMBLOCK_ADDR: PhysAddr = PhysAddr::new(usize::MAX); + + /// 由于这个函数只在全局调用,因此不需要担心栈上溢出问题 + #[allow(clippy::large_stack_frames)] const fn new() -> Self { Self { inner: SpinLock::new(InnerMemBlockManager { diff --git a/kernel/src/mm/mm.h b/kernel/src/mm/mm.h deleted file mode 100644 index e20acc63..00000000 --- a/kernel/src/mm/mm.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -#include -#include - -#define PAGE_4K_SHIFT 12 -#define PAGE_2M_SHIFT 21 -#define PAGE_1G_SHIFT 30 -#define PAGE_GDT_SHIFT 39 - -// 不同大小的页的容量 -#define PAGE_4K_SIZE (1UL << PAGE_4K_SHIFT) -#define PAGE_2M_SIZE (1UL << PAGE_2M_SHIFT) -#define PAGE_1G_SIZE (1UL << PAGE_1G_SHIFT) - -// 屏蔽低于x的数值 -#define PAGE_4K_MASK (~(PAGE_4K_SIZE - 1)) -#define PAGE_2M_MASK (~(PAGE_2M_SIZE - 1)) - -// 将addr按照x的上边界对齐 -#define PAGE_4K_ALIGN(addr) \ - (((unsigned long)(addr) + PAGE_4K_SIZE - 1) & PAGE_4K_MASK) -#define PAGE_2M_ALIGN(addr) \ - (((unsigned long)(addr) + PAGE_2M_SIZE - 1) & PAGE_2M_MASK) - -// 虚拟地址与物理地址转换 -#define virt_2_phys(addr) ((unsigned long)(addr)-PAGE_OFFSET) -#define phys_2_virt(addr) \ - ((unsigned long *)((unsigned long)(addr) + PAGE_OFFSET)) - -// ===== 页面属性 ===== -// 页面在页表中已被映射 mapped=1 unmapped=0 -#define PAGE_PGT_MAPPED (1 << 0) - -// 内核初始化所占用的页 init-code=1 normal-code/data=0 -#define PAGE_KERNEL_INIT (1 << 1) - -// 1=设备MMIO映射的内存 0=物理内存 -#define PAGE_DEVICE (1 << 2) - -// 内核层页 kernel=1 memory=0 -#define PAGE_KERNEL (1 << 3) - -// 共享的页 shared=1 single-use=0 -#define PAGE_SHARED (1 << 4) - -// =========== 页表项权限 ======== - -// bit 63 Execution Disable: -#define PAGE_XD (1UL << 63) - -// bit 12 Page Attribute Table -#define PAGE_PAT (1UL << 12) -// 对于PTE而言,第7位是PAT -#define PAGE_4K_PAT (1UL << 7) - -// bit 8 Global Page:1,global;0,part -#define PAGE_GLOBAL (1UL << 8) - -// bit 7 Page Size:1,big page;0,small page; -#define PAGE_PS (1UL << 7) - -// bit 6 Dirty:1,dirty;0,clean; -#define PAGE_DIRTY (1UL << 6) - -// bit 5 Accessed:1,visited;0,unvisited; -#define PAGE_ACCESSED (1UL << 5) - -// bit 4 Page Level Cache Disable -#define PAGE_PCD (1UL << 4) - -// bit 3 Page Level Write Through -#define PAGE_PWT (1UL << 3) - -// bit 2 User Supervisor:1,user and supervisor;0,supervisor; -#define PAGE_U_S (1UL << 2) - -// bit 1 Read Write:1,read and write;0,read; -#define PAGE_R_W (1UL << 1) - -// bit 0 Present:1,present;0,no present; -#define PAGE_PRESENT (1UL << 0) - -// 1,0 -#define PAGE_KERNEL_PGT (PAGE_R_W | PAGE_PRESENT) - -// 1,0 -#define PAGE_KERNEL_DIR (PAGE_R_W | PAGE_PRESENT) - -// 1,0 (4级页表在3级页表中的页表项的属性) -#define PAGE_KERNEL_PDE (PAGE_R_W | PAGE_PRESENT) - -// 7,1,0 -#define PAGE_KERNEL_PAGE (PAGE_PS | PAGE_R_W | PAGE_PRESENT) - -#define PAGE_KERNEL_4K_PAGE (PAGE_R_W | PAGE_PRESENT) - -#define PAGE_USER_PGT (PAGE_U_S | PAGE_R_W | PAGE_PRESENT) - -// 2,1,0 -#define PAGE_USER_DIR (PAGE_U_S | PAGE_R_W | PAGE_PRESENT) - -// 1,0 (4级页表在3级页表中的页表项的属性) -#define PAGE_USER_PDE (PAGE_U_S | PAGE_R_W | PAGE_PRESENT) -// 7,2,1,0 -#define PAGE_USER_PAGE (PAGE_PS | PAGE_U_S | PAGE_R_W | PAGE_PRESENT) - -#define PAGE_USER_4K_PAGE (PAGE_U_S | PAGE_R_W | PAGE_PRESENT) - -// 导出内核程序的几个段的起止地址 -extern char _text; -extern char _etext; -extern char _data; -extern char _edata; -extern char _rodata; -extern char _erodata; -extern char _bss; -extern char _ebss; -extern char _end; - -/* - * vm_area_struct中的vm_flags的可选值 - * 对应的结构体请见mm-types.h - */ -#define VM_NONE 0 -#define VM_READ (1 << 0) -#define VM_WRITE (1 << 1) -#define VM_EXEC (1 << 2) -#define VM_SHARED (1 << 3) -#define VM_IO (1 << 4) // MMIO的内存区域 -#define VM_SOFTDIRTY (1 << 5) -#define VM_MAYSHARE (1 << 6) // 该vma可被共享 -#define VM_USER (1 << 7) // 该vma可被用户态访问 -#define VM_DONTCOPY (1 << 8) // 当fork的时候不拷贝该虚拟内存区域 - -/* VMA basic access permission flags */ -#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC) diff --git a/kernel/src/mm/mmio.h b/kernel/src/mm/mmio.h deleted file mode 100644 index 6042611b..00000000 --- a/kernel/src/mm/mmio.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -#include "mm.h" - -extern int rs_mmio_create(uint32_t size, uint64_t vm_flags, uint64_t* res_vaddr, uint64_t* res_length); -extern int rs_mmio_release(uint64_t vaddr, uint64_t length); diff --git a/kernel/src/mm/mmio_buddy.rs b/kernel/src/mm/mmio_buddy.rs index ce03c949..ad0cd727 100644 --- a/kernel/src/mm/mmio_buddy.rs +++ b/kernel/src/mm/mmio_buddy.rs @@ -5,9 +5,7 @@ use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT}; use crate::mm::{MMArch, MemoryManagementArch}; use crate::process::ProcessManager; -use alloc::{collections::LinkedList, vec::Vec}; -use core::mem; -use core::mem::MaybeUninit; +use alloc::vec::Vec; use core::sync::atomic::{AtomicBool, Ordering}; use log::{debug, error, info, warn}; use system_error::SystemError; @@ -43,25 +41,18 @@ pub enum MmioResult { pub struct MmioBuddyMemPool { pool_start_addr: VirtAddr, pool_size: usize, - free_regions: [SpinLock; MMIO_BUDDY_REGION_COUNT as usize], + free_regions: Vec>, } impl MmioBuddyMemPool { #[inline(never)] fn new() -> Self { - let mut free_regions: [MaybeUninit>; - MMIO_BUDDY_REGION_COUNT as usize] = unsafe { MaybeUninit::uninit().assume_init() }; - for i in 0..MMIO_BUDDY_REGION_COUNT { - free_regions[i as usize] = MaybeUninit::new(SpinLock::new(MmioFreeRegionList::new())); + let mut free_regions: Vec> = + Vec::with_capacity(MMIO_BUDDY_REGION_COUNT as usize); + + for _ in 0..MMIO_BUDDY_REGION_COUNT { + free_regions.push(SpinLock::new(MmioFreeRegionList::new())); } - let free_regions = unsafe { - mem::transmute::< - [core::mem::MaybeUninit< - crate::libs::spinlock::SpinLock, - >; MMIO_BUDDY_REGION_COUNT as usize], - [SpinLock; MMIO_BUDDY_REGION_COUNT as usize], - >(free_regions) - }; let pool = MmioBuddyMemPool { pool_start_addr: MMArch::MMIO_BASE, @@ -70,7 +61,6 @@ impl MmioBuddyMemPool { }; assert!(pool.pool_start_addr.data() % PAGE_1G_SIZE == 0); - debug!("MMIO buddy pool init: created"); let mut vaddr_base = MMArch::MMIO_BASE; let mut remain_size = MMArch::MMIO_SIZE; @@ -122,6 +112,7 @@ impl MmioBuddyMemPool { /// @return Ok(i32) 返回0 /// /// @return Err(SystemError) 返回错误码 + #[inline(never)] fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result { // 确保内存对齐,低位都要为0 if (vaddr.data() & ((1 << exp) - 1)) != 0 { @@ -178,13 +169,13 @@ impl MmioBuddyMemPool { } // 没有恰好符合要求的内存块 // 注意:exp对应的链表list_guard已上锁【注意避免死锁问题】 - if list_guard.num_free == 0 { + if list_guard.free_count() == 0 { // 找到最小符合申请范围的内存块 // 将大的内存块依次分成小块内存,直到能够满足exp大小,即将exp+1分成两块exp for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 { let pop_list: &mut SpinLockGuard = &mut self.free_regions[exp2index(e)].lock(); - if pop_list.num_free == 0 { + if pop_list.free_count() == 0 { continue; } @@ -232,7 +223,7 @@ impl MmioBuddyMemPool { break; } // 判断是否获得了exp大小的内存块 - if list_guard.num_free > 0 { + if list_guard.free_count() > 0 { match self.pop_block(list_guard) { Ok(ret) => return Ok(ret), Err(err) => return Err(err), @@ -283,7 +274,7 @@ impl MmioBuddyMemPool { } //判断是否获得了exp大小的内存块 - if list_guard.num_free > 0 { + if list_guard.free_count() > 0 { match self.pop_block(list_guard) { Ok(ret) => return Ok(ret), Err(err) => return Err(err), @@ -325,8 +316,7 @@ impl MmioBuddyMemPool { region: MmioBuddyAddrRegion, list_guard: &mut SpinLockGuard, ) { - list_guard.list.push_back(region); - list_guard.num_free += 1; + list_guard.list.push(region); } /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址 @@ -365,7 +355,6 @@ impl MmioBuddyMemPool { .extract_if(|x| x.vaddr == buddy_vaddr) .collect(); if element.len() == 1 { - list_guard.num_free -= 1; return Ok(element.pop().unwrap()); } @@ -386,8 +375,7 @@ impl MmioBuddyMemPool { list_guard: &mut SpinLockGuard, ) -> Result { if !list_guard.list.is_empty() { - list_guard.num_free -= 1; - return Ok(list_guard.list.pop_back().unwrap()); + return Ok(list_guard.list.pop().unwrap()); } return Err(MmioResult::ISEMPTY); } @@ -412,22 +400,22 @@ impl MmioBuddyMemPool { high_list_guard: &mut SpinLockGuard, ) -> Result { // 至少要两个内存块才能合并 - if list_guard.num_free <= 1 { + if list_guard.free_count() <= 1 { return Err(MmioResult::EINVAL); } loop { - if list_guard.num_free <= 1 { + if list_guard.free_count() <= 1 { break; } // 获取内存块 - let vaddr: VirtAddr = list_guard.list.back().unwrap().vaddr; + let vaddr: VirtAddr = list_guard.list.last().unwrap().vaddr; // 获取伙伴内存块 match self.pop_buddy_block(vaddr, exp, list_guard) { Err(err) => { return Err(err); } Ok(buddy_region) => { - let region: MmioBuddyAddrRegion = list_guard.list.pop_back().unwrap(); + let region: MmioBuddyAddrRegion = list_guard.list.pop().unwrap(); let copy_region = region.clone(); // 在两块内存都被取出之后才进行合并 match self.merge_blocks(region, buddy_region, exp, high_list_guard) { @@ -488,7 +476,6 @@ impl MmioBuddyMemPool { return Err(SystemError::EPERM); } // 计算前导0 - #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] let mut size_exp: u32 = 63 - size.leading_zeros(); // debug!("create_mmio: size_exp: {}", size_exp); // 记录最终申请的空间大小 @@ -594,17 +581,17 @@ impl MmioBuddyAddrRegion { /// @brief 空闲页数组结构体 #[derive(Debug, Default)] pub struct MmioFreeRegionList { - /// 存储mmio_buddy的地址链表 - list: LinkedList, - /// 空闲块的数量 - num_free: i64, + /// 存储mmio_buddy的地址数组 + list: Vec, } impl MmioFreeRegionList { #[allow(dead_code)] - fn new() -> Self { - return MmioFreeRegionList { - ..Default::default() - }; + const fn new() -> Self { + Self { list: Vec::new() } + } + + fn free_count(&self) -> usize { + return self.list.len(); } } diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index f5fac396..a088ed13 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -21,7 +21,6 @@ use self::{ }; pub mod allocator; -pub mod c_adapter; pub mod early_ioremap; pub mod fault; pub mod init; diff --git a/kernel/src/mm/no_init.rs b/kernel/src/mm/no_init.rs index fdb8d4d6..9c699326 100644 --- a/kernel/src/mm/no_init.rs +++ b/kernel/src/mm/no_init.rs @@ -51,7 +51,13 @@ pub struct EarlyIoRemapPages { impl EarlyIoRemapPages { /// 预留的用于在内存管理初始化之前,映射内存所使用的页表数量 pub const EARLY_REMAP_PAGES_NUM: usize = 256; - pub const fn new() -> Self { + + /// 创建一个新的EarlyIoRemapPages实例 + /// + /// # Safety + /// 由于该函数只在编译时被调用,因此 `#[allow(clippy::large_stack_frames)]` 是安全的。 + #[allow(clippy::large_stack_frames)] + const fn new() -> Self { Self { pages: [EarlyRemapPage { data: [0; MMArch::PAGE_SIZE], diff --git a/kernel/src/mm/page.rs b/kernel/src/mm/page.rs index 0b84aaba..9520f629 100644 --- a/kernel/src/mm/page.rs +++ b/kernel/src/mm/page.rs @@ -82,12 +82,16 @@ impl PageManager { } pub fn get(&mut self, paddr: &PhysAddr) -> Option> { - page_reclaimer_lock_irqsave().get(paddr); + if let Some(p) = page_reclaimer_lock_irqsave().get(paddr) { + return Some(p); + } self.phys2page.get(paddr).cloned() } pub fn get_unwrap(&mut self, paddr: &PhysAddr) -> Arc { - page_reclaimer_lock_irqsave().get(paddr); + if let Some(p) = page_reclaimer_lock_irqsave().get(paddr) { + return p; + } self.phys2page .get(paddr) .unwrap_or_else(|| panic!("Phys Page not found, {:?}", paddr)) @@ -348,8 +352,11 @@ impl PageReclaimer { let inode = page_cache.inode().clone().unwrap().upgrade().unwrap(); for vma in guard.vma_set() { - let address_space = vma.lock_irqsave().address_space().unwrap(); - let address_space = address_space.upgrade().unwrap(); + let address_space = vma.lock_irqsave().address_space().and_then(|x| x.upgrade()); + if address_space.is_none() { + continue; + } + let address_space = address_space.unwrap(); let mut guard = address_space.write(); let mapper = &mut guard.user_mapper.utable; let virt = vma.lock_irqsave().page_address(page_index).unwrap(); @@ -380,19 +387,21 @@ impl PageReclaimer { MMArch::PAGE_SIZE }; - inode - .write_direct( - page_index * MMArch::PAGE_SIZE, - len, - unsafe { - core::slice::from_raw_parts( - MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8, - len, - ) - }, - SpinLock::new(FilePrivateData::Unused).lock(), - ) - .unwrap(); + if len > 0 { + inode + .write_direct( + page_index * MMArch::PAGE_SIZE, + len, + unsafe { + core::slice::from_raw_parts( + MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8, + len, + ) + }, + SpinLock::new(FilePrivateData::Unused).lock(), + ) + .unwrap(); + } // 清除标记 guard.remove_flags(PageFlags::PG_DIRTY); @@ -927,6 +936,11 @@ impl PageEntry { let ppn = ((self.data & (!((1 << 10) - 1))) >> 10) & ((1 << 54) - 1); super::allocator::page_frame::PhysPageFrame::from_ppn(ppn).phys_address() } + + #[cfg(target_arch = "loongarch64")] + { + todo!("la64: PageEntry::address") + } }; if self.present() { @@ -1055,6 +1069,11 @@ impl EntryFlags { // riscv64指向下一级页表的页表项,不应设置R/W/X权限位 Self::from_data(Arch::ENTRY_FLAG_DEFAULT_TABLE) } + + #[cfg(target_arch = "loongarch64")] + { + Self::from_data(Arch::ENTRY_FLAG_DEFAULT_TABLE) + } }; #[cfg(target_arch = "x86_64")] @@ -1070,6 +1089,11 @@ impl EntryFlags { { r } + + #[cfg(target_arch = "loongarch64")] + { + todo!("loongarch64: new_page_table") + } }; } @@ -1147,6 +1171,11 @@ impl EntryFlags { .update_flags(Arch::ENTRY_FLAG_WRITEABLE, false); } } + + #[cfg(target_arch = "loongarch64")] + { + todo!("la64: set_write") + } } /// 当前页表项是否可写 @@ -1280,6 +1309,11 @@ impl EntryFlags { .set_execute(true) .set_page_global(true) } + + #[cfg(target_arch = "loongarch64")] + { + todo!("la64: mmio_flags()") + } } } diff --git a/kernel/src/mm/percpu.rs b/kernel/src/mm/percpu.rs index 58757727..7c2ee513 100644 --- a/kernel/src/mm/percpu.rs +++ b/kernel/src/mm/percpu.rs @@ -25,6 +25,9 @@ impl PerCpu { #[cfg(target_arch = "riscv64")] pub const MAX_CPU_NUM: u32 = 64; + #[cfg(target_arch = "loongarch64")] + pub const MAX_CPU_NUM: u32 = 128; + /// # 初始化PerCpu /// /// 该函数应该在内核初始化时调用一次。 diff --git a/kernel/src/mm/slab.h b/kernel/src/mm/slab.h deleted file mode 100644 index 19fb8b69..00000000 --- a/kernel/src/mm/slab.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "mm.h" - -/** - * @brief 通用内存分配函数 - * - * @param size 要分配的内存大小 - * @param gfp 内存的flag - * @return void* 分配得到的内存的指针 - */ -extern void *kmalloc(unsigned long size, gfp_t gfp); - -/** - * @brief 从kmalloc申请一块内存,并将这块内存清空 - * - * @param size 要分配的内存大小 - * @param gfp 内存的flag - * @return void* 分配得到的内存的指针 - */ -extern void *kzalloc(size_t size, gfp_t gfp); - -/** - * @brief 通用内存释放函数 - * - * @param address 要释放的内存地址 - * @return unsigned long - */ -extern unsigned long kfree(void *address); diff --git a/kernel/src/mm/syscall.rs b/kernel/src/mm/syscall.rs deleted file mode 100644 index 6c9646a3..00000000 --- a/kernel/src/mm/syscall.rs +++ /dev/null @@ -1,654 +0,0 @@ -use core::{intrinsics::unlikely, slice::from_raw_parts}; - -use alloc::sync::Arc; -use log::error; -use system_error::SystemError; - -use crate::{ - arch::MMArch, - driver::base::block::SeekFrom, - ipc::shm::ShmFlags, - libs::align::{check_aligned, page_align_up}, - mm::MemoryManagementArch, - syscall::Syscall, -}; - -use super::{ - allocator::page_frame::{PageFrameCount, VirtPageFrame}, - ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR}, - verify_area, MsFlags, VirtAddr, VmFlags, -}; - -bitflags! { - /// Memory protection flags - pub struct ProtFlags: u64 { - const PROT_NONE = 0x0; - const PROT_READ = 0x1; - const PROT_WRITE = 0x2; - const PROT_EXEC = 0x4; - } - - /// Memory mapping flags - pub struct MapFlags: u64 { - const MAP_NONE = 0x0; - /// share changes - const MAP_SHARED = 0x1; - /// changes are private - const MAP_PRIVATE = 0x2; - /// Interpret addr exactly - const MAP_FIXED = 0x10; - /// don't use a file - const MAP_ANONYMOUS = 0x20; - // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7 - /// stack-like segment - const MAP_GROWSDOWN = 0x100; - /// ETXTBSY - const MAP_DENYWRITE = 0x800; - /// Mark it as an executable - const MAP_EXECUTABLE = 0x1000; - /// Pages are locked - const MAP_LOCKED = 0x2000; - /// don't check for reservations - const MAP_NORESERVE = 0x4000; - /// populate (prefault) pagetables - const MAP_POPULATE = 0x8000; - /// do not block on IO - const MAP_NONBLOCK = 0x10000; - /// give out an address that is best suited for process/thread stacks - const MAP_STACK = 0x20000; - /// create a huge page mapping - const MAP_HUGETLB = 0x40000; - /// perform synchronous page faults for the mapping - const MAP_SYNC = 0x80000; - /// MAP_FIXED which doesn't unmap underlying mapping - const MAP_FIXED_NOREPLACE = 0x100000; - - /// For anonymous mmap, memory could be uninitialized - const MAP_UNINITIALIZED = 0x4000000; - } - - /// Memory mremapping flags - pub struct MremapFlags: u8 { - const MREMAP_MAYMOVE = 1; - const MREMAP_FIXED = 2; - const MREMAP_DONTUNMAP = 4; - } - - - pub struct MadvFlags: u64 { - /// 默认行为,系统会进行一定的预读和预写,适用于一般读取场景 - const MADV_NORMAL = 0; - /// 随机访问模式,系统会尽量最小化数据读取量,适用于随机访问的场景 - const MADV_RANDOM = 1; - /// 顺序访问模式,系统会进行积极的预读,访问后的页面可以尽快释放,适用于顺序读取场景 - const MADV_SEQUENTIAL = 2; - /// 通知系统预读某些页面,用于应用程序提前准备数据 - const MADV_WILLNEED = 3; - /// 通知系统应用程序不再需要某些页面,内核可以释放相关资源 - const MADV_DONTNEED = 4; - - /// 将指定范围的页面标记为延迟释放,真正的释放会延迟至内存压力发生时 - const MADV_FREE = 8; - /// 应用程序请求释放指定范围的页面和相关的后备存储 - const MADV_REMOVE = 9; - /// 在 fork 时排除指定区域 - const MADV_DONTFORK = 10; - /// 取消 MADV_DONTFORK 的效果,不再在 fork 时排除指定区域 - const MADV_DOFORK = 11; - /// 模拟内存硬件错误,触发内存错误处理器处理 - const MADV_HWPOISON = 100; - /// 尝试软下线指定的内存范围 - const MADV_SOFT_OFFLINE = 101; - - /// 应用程序建议内核尝试合并指定范围内内容相同的页面 - const MADV_MERGEABLE = 12; - /// 取消 MADV_MERGEABLE 的效果,不再合并页面 - const MADV_UNMERGEABLE = 13; - - /// 应用程序希望将指定范围以透明大页方式支持 - const MADV_HUGEPAGE = 14; - /// 将指定范围标记为不值得用透明大页支持 - const MADV_NOHUGEPAGE = 15; - - /// 应用程序请求在核心转储时排除指定范围内的页面 - const MADV_DONTDUMP = 16; - /// 取消 MADV_DONTDUMP 的效果,不再排除核心转储时的页面 - const MADV_DODUMP = 17; - - /// 在 fork 时将子进程的该区域内存填充为零 - const MADV_WIPEONFORK = 18; - /// 取消 `MADV_WIPEONFORK` 的效果,不再在 fork 时填充子进程的内存 - const MADV_KEEPONFORK = 19; - - /// 应用程序不会立刻使用这些内存,内核将页面设置为非活动状态以便在内存压力发生时轻松回收 - const MADV_COLD = 20; - /// 应用程序不会立刻使用这些内存,内核立即将这些页面换出 - const MADV_PAGEOUT = 21; - - /// 预先填充页面表,可读,通过触发读取故障 - const MADV_POPULATE_READ = 22; - /// 预先填充页面表,可写,通过触发写入故障 - const MADV_POPULATE_WRITE = 23; - - /// 与 `MADV_DONTNEED` 类似,会将被锁定的页面释放 - const MADV_DONTNEED_LOCKED = 24; - - /// 同步将页面合并为新的透明大页 - const MADV_COLLAPSE = 25; - - } -} - -impl From for VmFlags { - fn from(map_flags: MapFlags) -> Self { - let mut vm_flags = VmFlags::VM_NONE; - - if map_flags.contains(MapFlags::MAP_GROWSDOWN) { - vm_flags |= VmFlags::VM_GROWSDOWN; - } - - if map_flags.contains(MapFlags::MAP_LOCKED) { - vm_flags |= VmFlags::VM_LOCKED; - } - - if map_flags.contains(MapFlags::MAP_SYNC) { - vm_flags |= VmFlags::VM_SYNC; - } - - if map_flags.contains(MapFlags::MAP_SHARED) { - vm_flags |= VmFlags::VM_SHARED; - } - - vm_flags - } -} - -impl From for VmFlags { - fn from(prot_flags: ProtFlags) -> Self { - let mut vm_flags = VmFlags::VM_NONE; - - if prot_flags.contains(ProtFlags::PROT_READ) { - vm_flags |= VmFlags::VM_READ; - } - - if prot_flags.contains(ProtFlags::PROT_WRITE) { - vm_flags |= VmFlags::VM_WRITE; - } - - if prot_flags.contains(ProtFlags::PROT_EXEC) { - vm_flags |= VmFlags::VM_EXEC; - } - - vm_flags - } -} - -impl From for VmFlags { - fn from(shm_flags: ShmFlags) -> Self { - let mut vm_flags = VmFlags::VM_NONE; - - if shm_flags.contains(ShmFlags::SHM_RDONLY) { - vm_flags |= VmFlags::VM_READ; - } else { - vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE; - } - - if shm_flags.contains(ShmFlags::SHM_EXEC) { - vm_flags |= VmFlags::VM_EXEC; - } - - if shm_flags.contains(ShmFlags::SHM_HUGETLB) { - vm_flags |= VmFlags::VM_HUGETLB; - } - - vm_flags - } -} - -impl From for MapFlags { - fn from(value: VmFlags) -> Self { - let mut map_flags = MapFlags::MAP_NONE; - - if value.contains(VmFlags::VM_GROWSDOWN) { - map_flags |= MapFlags::MAP_GROWSDOWN; - } - - if value.contains(VmFlags::VM_LOCKED) { - map_flags |= MapFlags::MAP_LOCKED; - } - - if value.contains(VmFlags::VM_SYNC) { - map_flags |= MapFlags::MAP_SYNC; - } - - if value.contains(VmFlags::VM_MAYSHARE) { - map_flags |= MapFlags::MAP_SHARED; - } - - map_flags - } -} - -impl From for ProtFlags { - fn from(value: VmFlags) -> Self { - let mut prot_flags = ProtFlags::PROT_NONE; - - if value.contains(VmFlags::VM_READ) { - prot_flags |= ProtFlags::PROT_READ; - } - - if value.contains(VmFlags::VM_WRITE) { - prot_flags |= ProtFlags::PROT_WRITE; - } - - if value.contains(VmFlags::VM_EXEC) { - prot_flags |= ProtFlags::PROT_EXEC; - } - - prot_flags - } -} - -impl Syscall { - pub fn brk(new_addr: VirtAddr) -> Result { - // debug!("brk: new_addr={:?}", new_addr); - let address_space = AddressSpace::current()?; - let mut address_space = address_space.write(); - - if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR { - return Ok(address_space.brk); - } - if new_addr == address_space.brk { - return Ok(address_space.brk); - } - - unsafe { - address_space - .set_brk(VirtAddr::new(page_align_up(new_addr.data()))) - .ok(); - - return Ok(address_space.sbrk(0).unwrap()); - } - } - - pub fn sbrk(incr: isize) -> Result { - let address_space = AddressSpace::current()?; - assert!(address_space.read().user_mapper.utable.is_current()); - let mut address_space = address_space.write(); - let r = unsafe { address_space.sbrk(incr) }; - - return r; - } - - /// ## mmap系统调用 - /// - /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现 - /// - /// ## 参数 - /// - /// - `start_vaddr`:映射的起始地址 - /// - `len`:映射的长度 - /// - `prot`:保护标志 - /// - `flags`:映射标志 - /// - `fd`:文件描述符(暂时不支持) - /// - `offset`:文件偏移量 (暂时不支持) - /// - /// ## 返回值 - /// - /// 成功时返回映射的起始地址,失败时返回错误码 - pub fn mmap( - start_vaddr: VirtAddr, - len: usize, - prot_flags: usize, - map_flags: usize, - fd: i32, - offset: usize, - ) -> Result { - let map_flags = MapFlags::from_bits_truncate(map_flags as u64); - let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64); - - if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR) - && map_flags.contains(MapFlags::MAP_FIXED) - { - error!( - "mmap: MAP_FIXED is not supported for address below {}", - DEFAULT_MMAP_MIN_ADDR - ); - return Err(SystemError::EINVAL); - } - - // 暂时不支持巨页映射 - if map_flags.contains(MapFlags::MAP_HUGETLB) { - error!("mmap: not support huge page mapping"); - return Err(SystemError::ENOSYS); - } - let current_address_space = AddressSpace::current()?; - let start_page = if map_flags.contains(MapFlags::MAP_ANONYMOUS) { - // 匿名映射 - current_address_space.write().map_anonymous( - start_vaddr, - len, - prot_flags, - map_flags, - true, - false, - )? - } else { - // 文件映射 - current_address_space.write().file_mapping( - start_vaddr, - len, - prot_flags, - map_flags, - fd, - offset, - true, - false, - )? - }; - - return Ok(start_page.virt_address().data()); - } - - /// ## mremap系统调用 - /// - /// - /// ## 参数 - /// - /// - `old_vaddr`:原映射的起始地址 - /// - `old_len`:原映射的长度 - /// - `new_len`:重新映射的长度 - /// - `mremap_flags`:重映射标志 - /// - `new_vaddr`:重新映射的起始地址 - /// - /// ## 返回值 - /// - /// 成功时返回重映射的起始地址,失败时返回错误码 - pub fn mremap( - old_vaddr: VirtAddr, - old_len: usize, - new_len: usize, - mremap_flags: MremapFlags, - new_vaddr: VirtAddr, - ) -> Result { - // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址 - if mremap_flags.contains(MremapFlags::MREMAP_FIXED) - && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) - || new_vaddr == VirtAddr::new(0)) - { - return Err(SystemError::EINVAL); - } - - // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小 - if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) - && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len) - { - return Err(SystemError::EINVAL); - } - - // 旧内存地址必须对齐 - if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) { - return Err(SystemError::EINVAL); - } - - // 将old_len、new_len 对齐页面大小 - let old_len = page_align_up(old_len); - let new_len = page_align_up(new_len); - - // 不允许重映射内存区域大小为0 - if new_len == 0 { - return Err(SystemError::EINVAL); - } - - let current_address_space = AddressSpace::current()?; - let vma = current_address_space.read().mappings.contains(old_vaddr); - if vma.is_none() { - return Err(SystemError::EINVAL); - } - let vma = vma.unwrap(); - let vm_flags = *vma.lock_irqsave().vm_flags(); - - // 暂时不支持巨页映射 - if vm_flags.contains(VmFlags::VM_HUGETLB) { - error!("mmap: not support huge page mapping"); - return Err(SystemError::ENOSYS); - } - - // 缩小旧内存映射区域 - if old_len > new_len { - Self::munmap(old_vaddr + new_len, old_len - new_len)?; - return Ok(old_vaddr.data()); - } - - // 重映射到新内存区域 - let r = current_address_space.write().mremap( - old_vaddr, - old_len, - new_len, - mremap_flags, - new_vaddr, - vm_flags, - )?; - - if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) { - Self::munmap(old_vaddr, old_len)?; - } - - return Ok(r.data()); - } - - /// ## munmap系统调用 - /// - /// ## 参数 - /// - /// - `start_vaddr`:取消映射的起始地址(已经对齐到页) - /// - `len`:取消映射的字节数(已经对齐到页) - /// - /// ## 返回值 - /// - /// 成功时返回0,失败时返回错误码 - pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result { - assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); - assert!(check_aligned(len, MMArch::PAGE_SIZE)); - - if unlikely(verify_area(start_vaddr, len).is_err()) { - return Err(SystemError::EINVAL); - } - if unlikely(len == 0) { - return Err(SystemError::EINVAL); - } - - let current_address_space: Arc = AddressSpace::current()?; - let start_frame = VirtPageFrame::new(start_vaddr); - let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); - - current_address_space - .write() - .munmap(start_frame, page_count) - .map_err(|_| SystemError::EINVAL)?; - - return Ok(0); - } - - /// ## mprotect系统调用 - /// - /// ## 参数 - /// - /// - `start_vaddr`:起始地址(已经对齐到页) - /// - `len`:长度(已经对齐到页) - /// - `prot_flags`:保护标志 - pub fn mprotect( - start_vaddr: VirtAddr, - len: usize, - prot_flags: usize, - ) -> Result { - assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); - assert!(check_aligned(len, MMArch::PAGE_SIZE)); - - if unlikely(verify_area(start_vaddr, len).is_err()) { - return Err(SystemError::EINVAL); - } - if unlikely(len == 0) { - return Err(SystemError::EINVAL); - } - - let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?; - - let current_address_space: Arc = AddressSpace::current()?; - let start_frame = VirtPageFrame::new(start_vaddr); - let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); - - current_address_space - .write() - .mprotect(start_frame, page_count, prot_flags) - .map_err(|_| SystemError::EINVAL)?; - return Ok(0); - } - - /// ## madvise系统调用 - /// - /// ## 参数 - /// - /// - `start_vaddr`:起始地址(已经对齐到页) - /// - `len`:长度(已经对齐到页) - /// - `madv_flags`:建议标志 - pub fn madvise( - start_vaddr: VirtAddr, - len: usize, - madv_flags: usize, - ) -> Result { - if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) { - return Err(SystemError::EINVAL); - } - - if unlikely(verify_area(start_vaddr, len).is_err()) { - return Err(SystemError::EINVAL); - } - if unlikely(len == 0) { - return Err(SystemError::EINVAL); - } - - let madv_flags = MadvFlags::from_bits(madv_flags as u64).ok_or(SystemError::EINVAL)?; - - let current_address_space: Arc = AddressSpace::current()?; - let start_frame = VirtPageFrame::new(start_vaddr); - let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); - - current_address_space - .write() - .madvise(start_frame, page_count, madv_flags) - .map_err(|_| SystemError::EINVAL)?; - return Ok(0); - } - - /// ## msync系统调用 - /// - /// ## 参数 - /// - /// - `start`:起始地址(已经对齐到页) - /// - `len`:长度(已经对齐到页) - /// - `flags`:标志 - pub fn msync(start: VirtAddr, len: usize, flags: usize) -> Result { - if !start.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) { - return Err(SystemError::EINVAL); - } - - if unlikely(verify_area(start, len).is_err()) { - return Err(SystemError::EINVAL); - } - if unlikely(len == 0) { - return Err(SystemError::EINVAL); - } - - let mut start = start.data(); - let end = start + len; - let flags = MsFlags::from_bits_truncate(flags); - let mut unmapped_error = Ok(0); - - if !flags.intersects(MsFlags::MS_ASYNC | MsFlags::MS_INVALIDATE | MsFlags::MS_SYNC) { - return Err(SystemError::EINVAL); - } - - if flags.contains(MsFlags::MS_ASYNC | MsFlags::MS_SYNC) { - return Err(SystemError::EINVAL); - } - - if end < start { - return Err(SystemError::ENOMEM); - } - - if start == end { - return Ok(0); - } - - let current_address_space = AddressSpace::current()?; - let mut err = Err(SystemError::ENOMEM); - let mut next_vma = current_address_space - .read() - .mappings - .find_nearest(VirtAddr::new(start)); - loop { - if let Some(vma) = next_vma.clone() { - let guard = vma.lock_irqsave(); - let vm_start = guard.region().start().data(); - let vm_end = guard.region().end().data(); - if start < vm_start { - if flags == MsFlags::MS_ASYNC { - break; - } - start = vm_start; - if start >= vm_end { - break; - } - unmapped_error = Err(SystemError::ENOMEM); - } - let vm_flags = *guard.vm_flags(); - if flags.contains(MsFlags::MS_INVALIDATE) && vm_flags.contains(VmFlags::VM_LOCKED) { - err = Err(SystemError::EBUSY); - break; - } - let file = guard.vm_file(); - let fstart = (start - vm_start) - + (guard.file_page_offset().unwrap_or(0) << MMArch::PAGE_SHIFT); - let fend = fstart + (core::cmp::min(end, vm_end) - start) - 1; - let old_start = start; - start = vm_end; - // log::info!("flags: {:?}", flags); - // log::info!("vm_flags: {:?}", vm_flags); - // log::info!("file: {:?}", file); - if flags.contains(MsFlags::MS_SYNC) && vm_flags.contains(VmFlags::VM_SHARED) { - if let Some(file) = file { - let old_pos = file.lseek(SeekFrom::SeekCurrent(0)).unwrap(); - file.lseek(SeekFrom::SeekSet(fstart as i64)).unwrap(); - err = file.write(len, unsafe { - from_raw_parts(old_start as *mut u8, fend - fstart + 1) - }); - file.lseek(SeekFrom::SeekSet(old_pos as i64)).unwrap(); - if err.is_err() { - break; - } else if start >= end { - err = unmapped_error; - break; - } - next_vma = current_address_space - .read() - .mappings - .find_nearest(VirtAddr::new(start)); - } - } else { - if start >= end { - err = unmapped_error; - break; - } - next_vma = current_address_space - .read() - .mappings - .find_nearest(VirtAddr::new(vm_end)); - } - } else { - return Err(SystemError::ENOMEM); - } - } - return err; - } -} diff --git a/kernel/src/mm/syscall/mod.rs b/kernel/src/mm/syscall/mod.rs new file mode 100644 index 00000000..fd41edbe --- /dev/null +++ b/kernel/src/mm/syscall/mod.rs @@ -0,0 +1,245 @@ +use crate::{ + ipc::shm::ShmFlags, + libs::align::{check_aligned, page_align_up}, +}; + +use super::{allocator::page_frame::PageFrameCount, MsFlags, VmFlags}; + +mod sys_brk; +mod sys_madvise; +mod sys_mmap; +mod sys_mprotect; +mod sys_mremap; +mod sys_msync; +mod sys_munmap; +pub mod sys_sbrk; + +bitflags! { + /// Memory protection flags + pub struct ProtFlags: u64 { + const PROT_NONE = 0x0; + const PROT_READ = 0x1; + const PROT_WRITE = 0x2; + const PROT_EXEC = 0x4; + } + + /// Memory mapping flags + pub struct MapFlags: u64 { + const MAP_NONE = 0x0; + /// share changes + const MAP_SHARED = 0x1; + /// changes are private + const MAP_PRIVATE = 0x2; + /// Interpret addr exactly + const MAP_FIXED = 0x10; + /// don't use a file + const MAP_ANONYMOUS = 0x20; + // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7 + /// stack-like segment + const MAP_GROWSDOWN = 0x100; + /// ETXTBSY + const MAP_DENYWRITE = 0x800; + /// Mark it as an executable + const MAP_EXECUTABLE = 0x1000; + /// Pages are locked + const MAP_LOCKED = 0x2000; + /// don't check for reservations + const MAP_NORESERVE = 0x4000; + /// populate (prefault) pagetables + const MAP_POPULATE = 0x8000; + /// do not block on IO + const MAP_NONBLOCK = 0x10000; + /// give out an address that is best suited for process/thread stacks + const MAP_STACK = 0x20000; + /// create a huge page mapping + const MAP_HUGETLB = 0x40000; + /// perform synchronous page faults for the mapping + const MAP_SYNC = 0x80000; + /// MAP_FIXED which doesn't unmap underlying mapping + const MAP_FIXED_NOREPLACE = 0x100000; + + /// For anonymous mmap, memory could be uninitialized + const MAP_UNINITIALIZED = 0x4000000; + } + + /// Memory mremapping flags + pub struct MremapFlags: u8 { + const MREMAP_MAYMOVE = 1; + const MREMAP_FIXED = 2; + const MREMAP_DONTUNMAP = 4; + } + + + pub struct MadvFlags: u64 { + /// 默认行为,系统会进行一定的预读和预写,适用于一般读取场景 + const MADV_NORMAL = 0; + /// 随机访问模式,系统会尽量最小化数据读取量,适用于随机访问的场景 + const MADV_RANDOM = 1; + /// 顺序访问模式,系统会进行积极的预读,访问后的页面可以尽快释放,适用于顺序读取场景 + const MADV_SEQUENTIAL = 2; + /// 通知系统预读某些页面,用于应用程序提前准备数据 + const MADV_WILLNEED = 3; + /// 通知系统应用程序不再需要某些页面,内核可以释放相关资源 + const MADV_DONTNEED = 4; + + /// 将指定范围的页面标记为延迟释放,真正的释放会延迟至内存压力发生时 + const MADV_FREE = 8; + /// 应用程序请求释放指定范围的页面和相关的后备存储 + const MADV_REMOVE = 9; + /// 在 fork 时排除指定区域 + const MADV_DONTFORK = 10; + /// 取消 MADV_DONTFORK 的效果,不再在 fork 时排除指定区域 + const MADV_DOFORK = 11; + /// 模拟内存硬件错误,触发内存错误处理器处理 + const MADV_HWPOISON = 100; + /// 尝试软下线指定的内存范围 + const MADV_SOFT_OFFLINE = 101; + + /// 应用程序建议内核尝试合并指定范围内内容相同的页面 + const MADV_MERGEABLE = 12; + /// 取消 MADV_MERGEABLE 的效果,不再合并页面 + const MADV_UNMERGEABLE = 13; + + /// 应用程序希望将指定范围以透明大页方式支持 + const MADV_HUGEPAGE = 14; + /// 将指定范围标记为不值得用透明大页支持 + const MADV_NOHUGEPAGE = 15; + + /// 应用程序请求在核心转储时排除指定范围内的页面 + const MADV_DONTDUMP = 16; + /// 取消 MADV_DONTDUMP 的效果,不再排除核心转储时的页面 + const MADV_DODUMP = 17; + + /// 在 fork 时将子进程的该区域内存填充为零 + const MADV_WIPEONFORK = 18; + /// 取消 `MADV_WIPEONFORK` 的效果,不再在 fork 时填充子进程的内存 + const MADV_KEEPONFORK = 19; + + /// 应用程序不会立刻使用这些内存,内核将页面设置为非活动状态以便在内存压力发生时轻松回收 + const MADV_COLD = 20; + /// 应用程序不会立刻使用这些内存,内核立即将这些页面换出 + const MADV_PAGEOUT = 21; + + /// 预先填充页面表,可读,通过触发读取故障 + const MADV_POPULATE_READ = 22; + /// 预先填充页面表,可写,通过触发写入故障 + const MADV_POPULATE_WRITE = 23; + + /// 与 `MADV_DONTNEED` 类似,会将被锁定的页面释放 + const MADV_DONTNEED_LOCKED = 24; + + /// 同步将页面合并为新的透明大页 + const MADV_COLLAPSE = 25; + + } +} + +impl From for VmFlags { + fn from(map_flags: MapFlags) -> Self { + let mut vm_flags = VmFlags::VM_NONE; + + if map_flags.contains(MapFlags::MAP_GROWSDOWN) { + vm_flags |= VmFlags::VM_GROWSDOWN; + } + + if map_flags.contains(MapFlags::MAP_LOCKED) { + vm_flags |= VmFlags::VM_LOCKED; + } + + if map_flags.contains(MapFlags::MAP_SYNC) { + vm_flags |= VmFlags::VM_SYNC; + } + + if map_flags.contains(MapFlags::MAP_SHARED) { + vm_flags |= VmFlags::VM_SHARED; + } + + vm_flags + } +} + +impl From for VmFlags { + fn from(prot_flags: ProtFlags) -> Self { + let mut vm_flags = VmFlags::VM_NONE; + + if prot_flags.contains(ProtFlags::PROT_READ) { + vm_flags |= VmFlags::VM_READ; + } + + if prot_flags.contains(ProtFlags::PROT_WRITE) { + vm_flags |= VmFlags::VM_WRITE; + } + + if prot_flags.contains(ProtFlags::PROT_EXEC) { + vm_flags |= VmFlags::VM_EXEC; + } + + vm_flags + } +} + +impl From for VmFlags { + fn from(shm_flags: ShmFlags) -> Self { + let mut vm_flags = VmFlags::VM_NONE; + + if shm_flags.contains(ShmFlags::SHM_RDONLY) { + vm_flags |= VmFlags::VM_READ; + } else { + vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE; + } + + if shm_flags.contains(ShmFlags::SHM_EXEC) { + vm_flags |= VmFlags::VM_EXEC; + } + + if shm_flags.contains(ShmFlags::SHM_HUGETLB) { + vm_flags |= VmFlags::VM_HUGETLB; + } + + vm_flags + } +} + +impl From for MapFlags { + fn from(value: VmFlags) -> Self { + let mut map_flags = MapFlags::MAP_NONE; + + if value.contains(VmFlags::VM_GROWSDOWN) { + map_flags |= MapFlags::MAP_GROWSDOWN; + } + + if value.contains(VmFlags::VM_LOCKED) { + map_flags |= MapFlags::MAP_LOCKED; + } + + if value.contains(VmFlags::VM_SYNC) { + map_flags |= MapFlags::MAP_SYNC; + } + + if value.contains(VmFlags::VM_MAYSHARE) { + map_flags |= MapFlags::MAP_SHARED; + } + + map_flags + } +} + +impl From for ProtFlags { + fn from(value: VmFlags) -> Self { + let mut prot_flags = ProtFlags::PROT_NONE; + + if value.contains(VmFlags::VM_READ) { + prot_flags |= ProtFlags::PROT_READ; + } + + if value.contains(VmFlags::VM_WRITE) { + prot_flags |= ProtFlags::PROT_WRITE; + } + + if value.contains(VmFlags::VM_EXEC) { + prot_flags |= ProtFlags::PROT_EXEC; + } + + prot_flags + } +} diff --git a/kernel/src/mm/syscall/sys_brk.rs b/kernel/src/mm/syscall/sys_brk.rs new file mode 100644 index 00000000..ee3fe295 --- /dev/null +++ b/kernel/src/mm/syscall/sys_brk.rs @@ -0,0 +1,68 @@ +//! System call handler for the brk system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_BRK}; +use crate::mm::ucontext::AddressSpace; +use crate::mm::MemoryManagementArch; +use crate::mm::VirtAddr; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::vec::Vec; + +/// Handler for the brk system call, which sets the end of the data segment (heap). +pub struct SysBrkHandle; + +impl Syscall for SysBrkHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 1 + } + + /// Handles the brk system call. + /// + /// # Arguments + /// * `args` - The syscall arguments, where args[0] is the new end address of the heap. + /// + /// # Returns + /// * On success, returns the new program break (heap end) as usize. + /// * On failure, returns a SystemError. + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let addr = Self::addr(args); + let new_addr = VirtAddr::new(addr); + let address_space = AddressSpace::current()?; + let mut address_space = address_space.write(); + + if new_addr < address_space.brk_start || new_addr >= crate::arch::MMArch::USER_END_VADDR { + return Ok(address_space.brk.data()); + } + if new_addr == address_space.brk { + return Ok(address_space.brk.data()); + } + + unsafe { + address_space + .set_brk(VirtAddr::new(crate::libs::align::page_align_up( + new_addr.data(), + ))) + .ok(); + return Ok(address_space.sbrk(0).unwrap().data()); + } + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "addr", + format!("{:#x}", Self::addr(args)), + )] + } +} + +impl SysBrkHandle { + /// Extracts the address argument from syscall parameters. + fn addr(args: &[usize]) -> usize { + args[0] + } +} + +syscall_table_macros::declare_syscall!(SYS_BRK, SysBrkHandle); diff --git a/kernel/src/mm/syscall/sys_madvise.rs b/kernel/src/mm/syscall/sys_madvise.rs new file mode 100644 index 00000000..6f251e50 --- /dev/null +++ b/kernel/src/mm/syscall/sys_madvise.rs @@ -0,0 +1,84 @@ +//! System call handler for the madvise system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MADVISE, MMArch}; +use crate::mm::{ + syscall::{check_aligned, MadvFlags, PageFrameCount}, + ucontext::AddressSpace, + MemoryManagementArch, VirtPageFrame, {verify_area, VirtAddr}, +}; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::sync::Arc; +use alloc::vec::Vec; + +/// Handles the madvise system call, which gives advice about the use of memory. +pub struct SysMadviseHandle; + +impl Syscall for SysMadviseHandle { + fn num_args(&self) -> usize { + 3 + } + + /// ## madvise系统调用 + /// + /// ## 参数 + /// - `start_vaddr`:起始地址(已经对齐到页) + /// - `len`:长度(已经对齐到页) + /// - `madv_flags`:建议标志 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let start_vaddr = VirtAddr::new(Self::start_vaddr(args)); + let len = Self::len(args); + let madv_flags = + MadvFlags::from_bits(Self::madv_flags(args) as u64).ok_or(SystemError::EINVAL)?; + if Self::start_vaddr(args) & (MMArch::PAGE_SIZE - 1) != 0 { + return Err(SystemError::EINVAL); + } + + if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) { + return Err(SystemError::EINVAL); + } + if verify_area(start_vaddr, len).is_err() { + return Err(SystemError::EINVAL); + } + if len == 0 { + return Err(SystemError::EINVAL); + } + + let current_address_space: Arc = AddressSpace::current()?; + let start_frame = VirtPageFrame::new(start_vaddr); + let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); + + current_address_space + .write() + .madvise(start_frame, page_count, madv_flags) + .map_err(|_| SystemError::EINVAL)?; + return Ok(0); + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + FormattedSyscallParam::new("madv_flags", format!("{:#x}", Self::madv_flags(args))), + ] + } +} + +impl SysMadviseHandle { + /// Extracts the start_vaddr argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the len argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the madv_flags argument from syscall parameters. + fn madv_flags(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_MADVISE, SysMadviseHandle); diff --git a/kernel/src/mm/syscall/sys_mmap.rs b/kernel/src/mm/syscall/sys_mmap.rs new file mode 100644 index 00000000..54d84d1b --- /dev/null +++ b/kernel/src/mm/syscall/sys_mmap.rs @@ -0,0 +1,137 @@ +//! System call handler for the mmap system call. + +use super::ProtFlags; +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MMAP}; +use crate::mm::syscall::page_align_up; +use crate::mm::syscall::MapFlags; +use crate::mm::ucontext::DEFAULT_MMAP_MIN_ADDR; +use crate::mm::verify_area; +use crate::mm::AddressSpace; +use crate::mm::VirtAddr; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use log::error; +use system_error::SystemError; + +use alloc::vec::Vec; + +/// Handler for the mmap system call, which maps files or devices into memory. +pub struct SysMmapHandle; + +impl Syscall for SysMmapHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 6 + } + + /// ## mmap系统调用 + /// + /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现 + /// + /// ## 参数 + /// + /// - `start_vaddr`:映射的起始地址 + /// - `len`:映射的长度 + /// - `prot`:保护标志 + /// - `flags`:映射标志 + /// - `fd`:文件描述符(暂时不支持) + /// - `offset`:文件偏移量 (暂时不支持) + /// + /// ## 返回值 + /// + /// 成功时返回映射的起始地址,失败时返回错误码 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let start_vaddr = VirtAddr::new(Self::start_vaddr(args)); + let len = page_align_up(Self::len(args)); + let prot_flags = Self::prot(args); + let map_flags = Self::flags(args); + let fd = Self::fd(args); + let offset = Self::offset(args); + if verify_area(start_vaddr, len).is_err() { + return Err(SystemError::EFAULT); + } else { + let map_flags = MapFlags::from_bits_truncate(map_flags as u64); + let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64); + + if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR) + && map_flags.contains(MapFlags::MAP_FIXED) + { + error!( + "mmap: MAP_FIXED is not supported for address below {}", + DEFAULT_MMAP_MIN_ADDR + ); + return Err(SystemError::EINVAL); + } + + // 暂时不支持巨页映射 + if map_flags.contains(MapFlags::MAP_HUGETLB) { + error!("mmap: not support huge page mapping"); + return Err(SystemError::ENOSYS); + } + let current_address_space = AddressSpace::current()?; + let start_page = if map_flags.contains(MapFlags::MAP_ANONYMOUS) { + // 匿名映射 + current_address_space.write().map_anonymous( + start_vaddr, + len, + prot_flags, + map_flags, + true, + false, + )? + } else { + // 文件映射 + current_address_space.write().file_mapping( + start_vaddr, + len, + prot_flags, + map_flags, + fd, + offset, + true, + false, + )? + }; + return Ok(start_page.virt_address().data()); + } + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + FormattedSyscallParam::new("prot", format!("{:#x}", Self::prot(args))), + FormattedSyscallParam::new("flags", format!("{:#x}", Self::flags(args))), + FormattedSyscallParam::new("fd", format!("{}", Self::fd(args))), + FormattedSyscallParam::new("offset", format!("{:#x}", Self::offset(args))), + ] + } +} + +impl SysMmapHandle { + /// Extracts the start virtual address argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the length argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the protection flags argument from syscall parameters. + fn prot(args: &[usize]) -> usize { + args[2] + } + /// Extracts the mapping flags argument from syscall parameters. + fn flags(args: &[usize]) -> usize { + args[3] + } + /// Extracts the file descriptor argument from syscall parameters. + fn fd(args: &[usize]) -> i32 { + args[4] as i32 + } + /// Extracts the file offset argument from syscall parameters. + fn offset(args: &[usize]) -> usize { + args[5] + } +} +syscall_table_macros::declare_syscall!(SYS_MMAP, SysMmapHandle); diff --git a/kernel/src/mm/syscall/sys_mprotect.rs b/kernel/src/mm/syscall/sys_mprotect.rs new file mode 100644 index 00000000..9d919358 --- /dev/null +++ b/kernel/src/mm/syscall/sys_mprotect.rs @@ -0,0 +1,83 @@ +//! System call handler for the mprotect system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MPROTECT, MMArch}; +use crate::mm::{ + syscall::{check_aligned, PageFrameCount, ProtFlags}, + ucontext::AddressSpace, + MemoryManagementArch, VirtPageFrame, {verify_area, VirtAddr}, +}; + +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::sync::Arc; +use alloc::vec::Vec; + +/// Handles the mprotect system call. +pub struct SysMprotectHandle; + +impl Syscall for SysMprotectHandle { + fn num_args(&self) -> usize { + 3 + } + + /// ## mprotect系统调用 + /// + /// ## 参数 + /// + /// - `start_vaddr`:起始地址(已经对齐到页) + /// - `len`:长度(已经对齐到页) + /// - `prot_flags`:保护标志 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let start_vaddr = VirtAddr::new(Self::start_vaddr(args)); + let len = Self::len(args); + let prot_flags = + ProtFlags::from_bits(Self::prot_flags(args) as u64).ok_or(SystemError::EINVAL)?; + + assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); + assert!(check_aligned(len, MMArch::PAGE_SIZE)); + + if verify_area(start_vaddr, len).is_err() { + return Err(SystemError::EINVAL); + } + if len == 0 { + return Err(SystemError::EINVAL); + } + + let current_address_space: Arc = AddressSpace::current()?; + let start_frame = VirtPageFrame::new(start_vaddr); + let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); + + current_address_space + .write() + .mprotect(start_frame, page_count, prot_flags) + .map_err(|_| SystemError::EINVAL)?; + return Ok(0); + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + FormattedSyscallParam::new("prot_flags", format!("{:#x}", Self::prot_flags(args))), + ] + } +} + +impl SysMprotectHandle { + /// Extracts the start_vaddr argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the len argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the prot_flags argument from syscall parameters. + fn prot_flags(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_MPROTECT, SysMprotectHandle); diff --git a/kernel/src/mm/syscall/sys_mremap.rs b/kernel/src/mm/syscall/sys_mremap.rs new file mode 100644 index 00000000..71692af2 --- /dev/null +++ b/kernel/src/mm/syscall/sys_mremap.rs @@ -0,0 +1,145 @@ +//! System call handler for the mremap system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MREMAP}; +use crate::mm::syscall::page_align_up; +use crate::mm::syscall::sys_munmap::do_munmap; +use crate::mm::syscall::MremapFlags; +use crate::mm::ucontext::AddressSpace; +use crate::mm::MemoryManagementArch; +use crate::mm::{MMArch, VirtAddr, VmFlags}; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::vec::Vec; +/// Handles the mremap system call. +pub struct SysMremapHandle; + +impl Syscall for SysMremapHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 5 + } + + /// ## mremap系统调用 + /// + /// + /// ## 参数 + /// + /// - `old_vaddr`:原映射的起始地址 + /// - `old_len`:原映射的长度 + /// - `new_len`:重新映射的长度 + /// - `mremap_flags`:重映射标志 + /// - `new_vaddr`:重新映射的起始地址 + /// + /// ## 返回值 + /// + /// 成功时返回重映射的起始地址,失败时返回错误码 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let old_vaddr = VirtAddr::new(Self::old_vaddr(args)); + let old_len = Self::old_len(args); + let new_len = Self::new_len(args); + let mremap_flags = MremapFlags::from_bits_truncate(Self::mremap_flags(args) as u8); + let new_vaddr = VirtAddr::new(Self::new_vaddr(args)); + + // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址 + if mremap_flags.contains(MremapFlags::MREMAP_FIXED) + && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) + || new_vaddr == VirtAddr::new(0)) + { + return Err(SystemError::EINVAL); + } + + // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小 + if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) + && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len) + { + return Err(SystemError::EINVAL); + } + + // 旧内存地址必须对齐 + if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) { + return Err(SystemError::EINVAL); + } + + // 将old_len、new_len 对齐页面大小 + let old_len = page_align_up(old_len); + let new_len = page_align_up(new_len); + + // 不允许重映射内存区域大小为0 + if new_len == 0 { + return Err(SystemError::EINVAL); + } + + let current_address_space = AddressSpace::current()?; + let vma = current_address_space.read().mappings.contains(old_vaddr); + if vma.is_none() { + return Err(SystemError::EINVAL); + } + let vma = vma.unwrap(); + let vm_flags = *vma.lock_irqsave().vm_flags(); + + // 暂时不支持巨页映射 + if vm_flags.contains(VmFlags::VM_HUGETLB) { + log::error!("mmap: not support huge page mapping"); + return Err(SystemError::ENOSYS); + } + + // 缩小旧内存映射区域 + if old_len > new_len { + do_munmap(old_vaddr + new_len, old_len - new_len)?; + return Ok(old_vaddr.data()); + } + + // 重映射到新内存区域 + let r = current_address_space.write().mremap( + old_vaddr, + old_len, + new_len, + mremap_flags, + new_vaddr, + vm_flags, + )?; + + if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) { + do_munmap(old_vaddr, old_len)?; + } + + return Ok(r.data()); + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("old_vaddr", format!("{:#x}", Self::old_vaddr(args))), + FormattedSyscallParam::new("old_len", format!("{:#x}", Self::old_len(args))), + FormattedSyscallParam::new("new_len", format!("{:#x}", Self::new_len(args))), + FormattedSyscallParam::new("mremap_flags", format!("{:#x}", Self::mremap_flags(args))), + FormattedSyscallParam::new("new_vaddr", format!("{:#x}", Self::new_vaddr(args))), + ] + } +} + +impl SysMremapHandle { + /// Extracts the old_vaddr argument from syscall parameters. + fn old_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the old_len argument from syscall parameters. + fn old_len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the new_len argument from syscall parameters. + fn new_len(args: &[usize]) -> usize { + args[2] + } + /// Extracts the mremap_flags argument from syscall parameters. + fn mremap_flags(args: &[usize]) -> usize { + args[3] + } + /// Extracts the new_vaddr argument from syscall parameters. + fn new_vaddr(args: &[usize]) -> usize { + args[4] + } +} + +syscall_table_macros::declare_syscall!(SYS_MREMAP, SysMremapHandle); diff --git a/kernel/src/mm/syscall/sys_msync.rs b/kernel/src/mm/syscall/sys_msync.rs new file mode 100644 index 00000000..c4df4bd1 --- /dev/null +++ b/kernel/src/mm/syscall/sys_msync.rs @@ -0,0 +1,158 @@ +//! System call handler for the msync system call. + +use crate::{ + arch::{interrupt::TrapFrame, syscall::nr::SYS_MSYNC, MMArch}, + driver::base::block::SeekFrom, +}; + +use crate::mm::{ + syscall::{check_aligned, MsFlags, VmFlags}, + ucontext::AddressSpace, + unlikely, verify_area, MemoryManagementArch, VirtAddr, +}; + +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use system_error::SystemError; + +use alloc::vec::Vec; + +/// Handles the msync system call. +pub struct SysMsyncHandle; + +impl Syscall for SysMsyncHandle { + fn num_args(&self) -> usize { + 3 + } + /// ## msync系统调用 + /// + /// ## 参数 + /// + /// - `start`:起始地址(已经对齐到页) + /// - `len`:长度(已经对齐到页) + /// - `flags`:标志 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let start = VirtAddr::new(Self::start_vaddr(args)); + let len = Self::len(args); + let flags = MsFlags::from_bits_truncate(Self::flags(args)); + + if !start.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) { + return Err(SystemError::EINVAL); + } + if unlikely(verify_area(start, len).is_err()) { + return Err(SystemError::EINVAL); + } + if unlikely(len == 0) { + return Err(SystemError::EINVAL); + } + + let mut start = start.data(); + let end = start + len; + let mut unmapped_error = Ok(0); + + if !flags.intersects(MsFlags::MS_ASYNC | MsFlags::MS_INVALIDATE | MsFlags::MS_SYNC) { + return Err(SystemError::EINVAL); + } + if flags.contains(MsFlags::MS_ASYNC | MsFlags::MS_SYNC) { + return Err(SystemError::EINVAL); + } + if end < start { + return Err(SystemError::ENOMEM); + } + if start == end { + return Ok(0); + } + + let current_address_space = AddressSpace::current()?; + let mut err = Err(SystemError::ENOMEM); + let mut next_vma = current_address_space + .read() + .mappings + .find_nearest(VirtAddr::new(start)); + loop { + if let Some(vma) = next_vma.clone() { + let guard = vma.lock_irqsave(); + let vm_start = guard.region().start().data(); + let vm_end = guard.region().end().data(); + if start < vm_start { + if flags == MsFlags::MS_ASYNC { + break; + } + start = vm_start; + if start >= vm_end { + break; + } + unmapped_error = Err(SystemError::ENOMEM); + } + let vm_flags = *guard.vm_flags(); + if flags.contains(MsFlags::MS_INVALIDATE) && vm_flags.contains(VmFlags::VM_LOCKED) { + err = Err(SystemError::EBUSY); + break; + } + let file = guard.vm_file(); + let fstart = (start - vm_start) + + (guard.file_page_offset().unwrap_or(0) << MMArch::PAGE_SHIFT); + let fend = fstart + (core::cmp::min(end, vm_end) - start) - 1; + let old_start = start; + start = vm_end; + if flags.contains(MsFlags::MS_SYNC) && vm_flags.contains(VmFlags::VM_SHARED) { + if let Some(file) = file { + let old_pos = file.lseek(SeekFrom::SeekCurrent(0)).unwrap(); + file.lseek(SeekFrom::SeekSet(fstart as i64)).unwrap(); + err = file.write(len, unsafe { + core::slice::from_raw_parts(old_start as *mut u8, fend - fstart + 1) + }); + file.lseek(SeekFrom::SeekSet(old_pos as i64)).unwrap(); + if err.is_err() { + break; + } else if start >= end { + err = unmapped_error; + break; + } + next_vma = current_address_space + .read() + .mappings + .find_nearest(VirtAddr::new(start)); + } + } else { + if start >= end { + err = unmapped_error; + break; + } + next_vma = current_address_space + .read() + .mappings + .find_nearest(VirtAddr::new(vm_end)); + } + } else { + return Err(SystemError::ENOMEM); + } + } + return err; + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + FormattedSyscallParam::new("flags", format!("{:#x}", Self::flags(args))), + ] + } +} + +impl SysMsyncHandle { + /// Extracts the start_vaddr argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the len argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } + /// Extracts the flags argument from syscall parameters. + fn flags(args: &[usize]) -> usize { + args[2] + } +} + +syscall_table_macros::declare_syscall!(SYS_MSYNC, SysMsyncHandle); diff --git a/kernel/src/mm/syscall/sys_munmap.rs b/kernel/src/mm/syscall/sys_munmap.rs new file mode 100644 index 00000000..8bf31154 --- /dev/null +++ b/kernel/src/mm/syscall/sys_munmap.rs @@ -0,0 +1,89 @@ +//! System call handler for the munmap system call. + +use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MUNMAP}; +use crate::mm::syscall::check_aligned; +use crate::mm::syscall::page_align_up; +use crate::mm::syscall::PageFrameCount; +use crate::mm::ucontext::AddressSpace; +use crate::mm::unlikely; +use crate::mm::MemoryManagementArch; +use crate::mm::{verify_area, MMArch, VirtAddr, VirtPageFrame}; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use alloc::sync::Arc; +use alloc::vec::Vec; +use system_error::SystemError; + +/// ## munmap系统调用 +/// +/// ## 参数 +/// +/// - `start_vaddr`:取消映射的起始地址(已经对齐到页) +/// - `len`:取消映射的字节数(已经对齐到页) +/// +/// ## 返回值 +/// +/// 成功时返回0,失败时返回错误码 +pub struct SysMunmapHandle; + +impl Syscall for SysMunmapHandle { + /// Returns the number of arguments this syscall takes. + fn num_args(&self) -> usize { + 2 + } + + /// Handles the munmap system call. + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let addr = args[0]; + let len = page_align_up(args[1]); + if addr & (MMArch::PAGE_SIZE - 1) != 0 { + // The addr argument is not a multiple of the page size + return Err(SystemError::EINVAL); + } else { + do_munmap(VirtAddr::new(addr), len) + } + } + + /// Formats the syscall arguments for display/debugging purposes. + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))), + FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))), + ] + } +} + +impl SysMunmapHandle { + /// Extracts the start virtual address argument from syscall parameters. + fn start_vaddr(args: &[usize]) -> usize { + args[0] + } + /// Extracts the length argument from syscall parameters. + fn len(args: &[usize]) -> usize { + args[1] + } +} + +syscall_table_macros::declare_syscall!(SYS_MUNMAP, SysMunmapHandle); + +pub(super) fn do_munmap(start_vaddr: VirtAddr, len: usize) -> Result { + assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); + assert!(check_aligned(len, MMArch::PAGE_SIZE)); + + if unlikely(verify_area(start_vaddr, len).is_err()) { + return Err(SystemError::EINVAL); + } + if unlikely(len == 0) { + return Err(SystemError::EINVAL); + } + + let current_address_space: Arc = AddressSpace::current()?; + let start_frame = VirtPageFrame::new(start_vaddr); + let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); + + current_address_space + .write() + .munmap(start_frame, page_count) + .map_err(|_| SystemError::EINVAL)?; + + return Ok(0); +} diff --git a/kernel/src/mm/syscall/sys_sbrk.rs b/kernel/src/mm/syscall/sys_sbrk.rs new file mode 100644 index 00000000..241138cb --- /dev/null +++ b/kernel/src/mm/syscall/sys_sbrk.rs @@ -0,0 +1,64 @@ +//! System call handler for the sbrk system call. + +use crate::mm::ucontext::AddressSpace; +use system_error::SystemError; + +// /// Handler for the sbrk system call, which increments the program's data space (heap). +// pub struct SysSbrkHandle; + +// impl Syscall for SysSbrkHandle { +// /// Returns the number of arguments this syscall takes. +// fn num_args(&self) -> usize { +// 1 +// } + +// /// Handles the sbrk system call. +// /// +// /// # Arguments +// /// * `args` - The syscall arguments, where args[0] is the increment value (isize). +// /// +// /// # Returns +// /// * On success, returns the previous program break (heap end) as usize. +// /// * On failure, returns a SystemError. +// fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { +// let incr = Self::incr(args); +// let address_space = AddressSpace::current()?; +// assert!(address_space.read().user_mapper.utable.is_current()); +// let mut address_space = address_space.write(); +// let r = unsafe { address_space.sbrk(incr) }?; +// return Ok(r.data()); +// } + +// /// Formats the syscall arguments for display/debugging purposes. +// fn entry_format(&self, args: &[usize]) -> Vec { +// vec![FormattedSyscallParam::new( +// "incr", +// format!("{}", Self::incr(args)), +// )] +// } +// } + +// impl SysSbrkHandle { +// /// Extracts the increment argument from syscall parameters. +// fn incr(args: &[usize]) -> isize { +// args[0] as isize +// } +// } + +// syscall_table_macros::declare_syscall!(SYS_SBRK, SysSbrkHandle); + +/// Handles the sbrk system call. +/// +/// # Arguments +/// * `args` - The syscall arguments, where args[0] is the increment value (isize). +/// +/// # Returns +/// * On success, returns the previous program break (heap end) as usize. +/// * On failure, returns a SystemError. +pub fn sys_sbrk(incr: isize) -> Result { + let address_space = AddressSpace::current()?; + assert!(address_space.read().user_mapper.utable.is_current()); + let mut address_space = address_space.write(); + let r = unsafe { address_space.sbrk(incr) }?; + return Ok(r.data()); +} diff --git a/kernel/src/mm/ucontext.rs b/kernel/src/mm/ucontext.rs index 04d953b2..a4a24331 100644 --- a/kernel/src/mm/ucontext.rs +++ b/kernel/src/mm/ucontext.rs @@ -206,21 +206,51 @@ impl InnerAddressSpace { return Ok(new_addr_space); } + /// Check if the stack can be extended + pub fn can_extend_stack(&self, bytes: usize) -> bool { + let bytes = page_align_up(bytes); + let stack = self.user_stack.as_ref().unwrap(); + let new_size = stack.mapped_size + bytes; + if new_size > stack.max_limit { + // Don't exceed the maximum stack size + return false; + } + return true; + } + /// 拓展用户栈 /// ## 参数 /// /// - `bytes`: 拓展大小 - #[allow(dead_code)] pub fn extend_stack(&mut self, mut bytes: usize) -> Result<(), SystemError> { - // debug!("extend user stack"); + // log::debug!("extend user stack"); + + // Layout + // -------------- high->sp + // | stack pages| + // |------------| + // | stack pages| + // |------------| + // | not mapped | + // -------------- low + let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC; let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_GROWSDOWN; let stack = self.user_stack.as_mut().unwrap(); bytes = page_align_up(bytes); stack.mapped_size += bytes; - let len = stack.stack_bottom - stack.mapped_size; - self.map_anonymous(len, bytes, prot_flags, map_flags, false, false)?; + // map new stack pages + let extend_stack_start = stack.stack_bottom - stack.mapped_size; + + self.map_anonymous( + extend_stack_start, + bytes, + prot_flags, + map_flags, + false, + false, + )?; return Ok(()); } @@ -451,8 +481,7 @@ impl InnerAddressSpace { // 找到未使用的区域 let region = match addr { Some(vaddr) => { - self.mappings - .find_free_at(self.mmap_min, vaddr, page_count.bytes(), map_flags)? + self.find_free_at(self.mmap_min, vaddr, page_count.bytes(), map_flags)? } None => self .mappings @@ -799,6 +828,56 @@ impl InnerAddressSpace { return self.set_brk(new_brk); } + + pub fn find_free_at( + &mut self, + min_vaddr: VirtAddr, + vaddr: VirtAddr, + size: usize, + flags: MapFlags, + ) -> Result { + // 如果没有指定地址,那么就在当前进程的地址空间中寻找一个空闲的虚拟内存范围。 + if vaddr == VirtAddr::new(0) { + return self + .mappings + .find_free(min_vaddr, size) + .ok_or(SystemError::ENOMEM); + } + + // 如果指定了地址,那么就检查指定的地址是否可用。 + let requested = VirtRegion::new(vaddr, size); + + if requested.end() >= MMArch::USER_END_VADDR || !vaddr.check_aligned(MMArch::PAGE_SIZE) { + return Err(SystemError::EINVAL); + } + + let intersect_vma = self.mappings.conflicts(requested).next(); + if let Some(vma) = intersect_vma { + if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) { + // 如果指定了 MAP_FIXED_NOREPLACE 标志,由于所指定的地址无法成功建立映射,则放弃映射,不对地址做修正 + return Err(SystemError::EEXIST); + } + + if flags.contains(MapFlags::MAP_FIXED) { + // 对已有的VMA进行覆盖 + let intersect_region = vma.lock().region.intersect(&requested).unwrap(); + self.munmap( + VirtPageFrame::new(intersect_region.start), + PageFrameCount::from_bytes(intersect_region.size).unwrap(), + )?; + return Ok(requested); + } + + // 如果没有指定MAP_FIXED标志,那么就对地址做修正 + let requested = self + .mappings + .find_free(min_vaddr, size) + .ok_or(SystemError::ENOMEM)?; + return Ok(requested); + } + + return Ok(requested); + } } impl Drop for InnerAddressSpace { @@ -949,45 +1028,6 @@ impl UserMappings { return Some(region); } - pub fn find_free_at( - &self, - min_vaddr: VirtAddr, - vaddr: VirtAddr, - size: usize, - flags: MapFlags, - ) -> Result { - // 如果没有指定地址,那么就在当前进程的地址空间中寻找一个空闲的虚拟内存范围。 - if vaddr == VirtAddr::new(0) { - return self.find_free(min_vaddr, size).ok_or(SystemError::ENOMEM); - } - - // 如果指定了地址,那么就检查指定的地址是否可用。 - - let requested = VirtRegion::new(vaddr, size); - - if requested.end() >= MMArch::USER_END_VADDR || !vaddr.check_aligned(MMArch::PAGE_SIZE) { - return Err(SystemError::EINVAL); - } - - if let Some(_x) = self.conflicts(requested).next() { - if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) { - // 如果指定了 MAP_FIXED_NOREPLACE 标志,由于所指定的地址无法成功建立映射,则放弃映射,不对地址做修正 - return Err(SystemError::EEXIST); - } - - if flags.contains(MapFlags::MAP_FIXED) { - // todo: 支持MAP_FIXED标志对已有的VMA进行覆盖 - return Err(SystemError::ENOSYS); - } - - // 如果没有指定MAP_FIXED标志,那么就对地址做修正 - let requested = self.find_free(min_vaddr, size).ok_or(SystemError::ENOMEM)?; - return Ok(requested); - } - - return Ok(requested); - } - /// 在当前进程的地址空间中,保留一个指定大小的区域,使得该区域不在空洞中。 /// 该函数会修改vm_holes中的空洞信息。 /// @@ -1724,6 +1764,8 @@ pub struct UserStack { mapped_size: usize, /// 栈顶地址(这个值需要仔细确定!因为它可能不会实时与用户栈的真实栈顶保持一致!要小心!) current_sp: VirtAddr, + /// 用户自定义的栈大小限制 + max_limit: usize, } impl UserStack { @@ -1743,117 +1785,43 @@ impl UserStack { let stack_bottom = stack_bottom.unwrap_or(Self::DEFAULT_USER_STACK_BOTTOM); assert!(stack_bottom.check_aligned(MMArch::PAGE_SIZE)); - // 分配用户栈的保护页 - let guard_size = Self::GUARD_PAGES_NUM * MMArch::PAGE_SIZE; - let actual_stack_bottom = stack_bottom - guard_size; + // Layout + // -------------- high->sp + // | stack pages| + // |------------| + // | not mapped | + // -------------- low - let mut prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE; - let map_flags = MapFlags::MAP_PRIVATE - | MapFlags::MAP_ANONYMOUS - | MapFlags::MAP_FIXED_NOREPLACE - | MapFlags::MAP_GROWSDOWN; - // debug!( - // "map anonymous stack: {:?} {}", - // actual_stack_bottom, - // guard_size - // ); - vm.map_anonymous( - actual_stack_bottom, - guard_size, - prot_flags, - map_flags, - false, - false, - )?; - // test_buddy(); - // 设置保护页只读 - prot_flags.remove(ProtFlags::PROT_WRITE); - // debug!( - // "to mprotect stack guard pages: {:?} {}", - // actual_stack_bottom, - // guard_size - // ); - vm.mprotect( - VirtPageFrame::new(actual_stack_bottom), - PageFrameCount::new(Self::GUARD_PAGES_NUM), - prot_flags, - )?; - - // debug!( - // "mprotect stack guard pages done: {:?} {}", - // actual_stack_bottom, - // guard_size - // ); - - let mut user_stack = UserStack { - stack_bottom: actual_stack_bottom, - mapped_size: guard_size, - current_sp: actual_stack_bottom - guard_size, - }; - - // debug!("extend user stack: {:?} {}", stack_bottom, stack_size); - // 分配用户栈 - user_stack.initial_extend(vm, stack_size)?; - // debug!("user stack created: {:?} {}", stack_bottom, stack_size); - return Ok(user_stack); - } - - fn initial_extend( - &mut self, - vm: &mut InnerAddressSpace, - mut bytes: usize, - ) -> Result<(), SystemError> { let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC; let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_GROWSDOWN; - bytes = page_align_up(bytes); - self.mapped_size += bytes; + let stack_size = page_align_up(stack_size); + + // log::info!( + // "UserStack stack_range: {:#x} - {:#x}", + // stack_bottom.data() - stack_size, + // stack_bottom.data() + // ); vm.map_anonymous( - self.stack_bottom - self.mapped_size, - bytes, + stack_bottom - stack_size, + stack_size, prot_flags, map_flags, false, false, )?; - return Ok(()); - } + let max_limit = core::cmp::max(Self::DEFAULT_USER_STACK_SIZE, stack_size); - /// 扩展用户栈 - /// - /// ## 参数 - /// - /// - `vm` 用户地址空间结构体 - /// - `bytes` 要扩展的字节数 - /// - /// ## 返回值 - /// - /// - **Ok(())** 扩展成功 - /// - **Err(SystemError)** 扩展失败 - #[allow(dead_code)] - pub fn extend( - &mut self, - vm: &mut InnerAddressSpace, - mut bytes: usize, - ) -> Result<(), SystemError> { - let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC; - let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS; + let user_stack = UserStack { + stack_bottom, + mapped_size: stack_size, + current_sp: stack_bottom, + max_limit, + }; - bytes = page_align_up(bytes); - self.mapped_size += bytes; - - vm.map_anonymous( - self.stack_bottom - self.mapped_size, - bytes, - prot_flags, - map_flags, - false, - false, - )?; - - return Ok(()); + return Ok(user_stack); } /// 获取栈顶地址 @@ -1873,11 +1841,17 @@ impl UserStack { stack_bottom: self.stack_bottom, mapped_size: self.mapped_size, current_sp: self.current_sp, + max_limit: self.max_limit, }; } /// 获取当前用户栈的大小(不包括保护页) pub fn stack_size(&self) -> usize { - return self.mapped_size - Self::GUARD_PAGES_NUM * MMArch::PAGE_SIZE; + return self.mapped_size; + } + + /// 设置当前用户栈的最大大小 + pub fn set_max_limit(&mut self, max_limit: usize) { + self.max_limit = max_limit; } } diff --git a/kernel/src/namespaces/mnt_namespace.rs b/kernel/src/namespaces/mnt_namespace.rs index e5312d82..81954586 100644 --- a/kernel/src/namespaces/mnt_namespace.rs +++ b/kernel/src/namespaces/mnt_namespace.rs @@ -16,15 +16,17 @@ use super::ucount::Ucount::MntNamespaces; use super::{namespace::NsCommon, ucount::UCounts, user_namespace::UserNamespace}; use crate::container_of; use crate::filesystem::vfs::mount::MountFSInode; +use crate::filesystem::vfs::syscall::ModeType; use crate::filesystem::vfs::IndexNode; use crate::filesystem::vfs::InodeId; use crate::filesystem::vfs::MountFS; use crate::filesystem::vfs::ROOT_INODE; use crate::libs::rbtree::RBTree; +use crate::libs::rwlock::RwLock; use crate::libs::wait_queue::WaitQueue; use crate::process::fork::CloneFlags; +use crate::process::geteuid::do_geteuid; use crate::process::ProcessManager; -use crate::syscall::Syscall; #[allow(dead_code)] #[derive(Debug)] pub struct MntNamespace { @@ -60,13 +62,36 @@ struct MntNsOperations { clone_flags: CloneFlags, } -/// 使用该结构体的时候加spinlock -#[derive(Clone, Debug)] -pub struct FsStruct { - umask: u32, //文件权限掩码 - pub root: Arc, - pub pwd: Arc, +#[derive(Debug, Clone)] +struct PathContext { + root: Arc, + pwd: Arc, } + +impl PathContext { + pub fn new() -> Self { + Self { + root: ROOT_INODE(), + pwd: ROOT_INODE(), + } + } +} + +#[derive(Debug)] +pub struct FsStruct { + umask: ModeType, //文件权限掩码 + path_context: RwLock, +} + +impl Clone for FsStruct { + fn clone(&self) -> Self { + Self { + umask: self.umask, + path_context: RwLock::new(self.path_context.read().clone()), + } + } +} + impl Default for FsStruct { fn default() -> Self { Self::new() @@ -76,23 +101,33 @@ impl Default for FsStruct { impl FsStruct { pub fn new() -> Self { Self { - umask: 0o22, - root: ROOT_INODE(), - pwd: ROOT_INODE(), + umask: ModeType::S_IWUGO, + path_context: RwLock::new(PathContext::new()), } } - pub fn set_root(&mut self, inode: Arc) { - self.root = inode; + + pub fn set_root(&self, inode: Arc) { + self.path_context.write().root = inode; } - pub fn set_pwd(&mut self, inode: Arc) { - self.pwd = inode; + + pub fn set_pwd(&self, inode: Arc) { + self.path_context.write().pwd = inode; + } + + pub fn pwd(&self) -> Arc { + self.path_context.read().pwd.clone() + } + + pub fn root(&self) -> Arc { + self.path_context.read().root.clone() } } impl Namespace for MntNamespace { fn ns_common_to_ns(ns_common: Arc) -> Arc { let ns_common_ptr = Arc::as_ptr(&ns_common); - container_of!(ns_common_ptr, MntNamespace, ns_common) + // container_of!(ns_common_ptr, MntNamespace, ns_common) + panic!("not implemented") } } @@ -126,8 +161,10 @@ impl NsOperations for MntNsOperations { } nsproxy.mnt_namespace = mnt_ns; - nsset.fs.lock().set_pwd(ROOT_INODE()); - nsset.fs.lock().set_root(ROOT_INODE()); + let guard = nsset.fs.write(); + guard.set_pwd(ROOT_INODE()); + guard.set_root(ROOT_INODE()); + Ok(()) } fn owner(&self, ns_common: Arc) -> Arc { @@ -193,7 +230,7 @@ impl MntNamespace { ) -> Result>, SystemError> { Ok(self .ucounts - .inc_ucounts(user_ns, Syscall::geteuid()?, MntNamespaces)) + .inc_ucounts(user_ns, do_geteuid()?, MntNamespaces)) } pub fn dec_mnt_namespace(&self, uc: Arc) { diff --git a/kernel/src/namespaces/mod.rs b/kernel/src/namespaces/mod.rs index a9043a12..51ead2c6 100644 --- a/kernel/src/namespaces/mod.rs +++ b/kernel/src/namespaces/mod.rs @@ -5,7 +5,7 @@ use system_error::SystemError; use user_namespace::UserNamespace; use crate::{ - libs::spinlock::SpinLock, + libs::rwlock::RwLock, process::{fork::CloneFlags, ProcessControlBlock}, }; @@ -17,12 +17,12 @@ pub mod ucount; pub mod user_namespace; /// 管理 namespace,包含了所有namespace的信息 -#[derive(Clone)] pub struct NsSet { flags: u64, nsproxy: NsProxy, - pub fs: Arc>, + pub fs: RwLock>, } + #[derive(Debug, Clone)] pub struct NsProxy { pub pid_namespace: Arc, diff --git a/kernel/src/namespaces/namespace.rs b/kernel/src/namespaces/namespace.rs index 06b0e6ac..f4b77880 100644 --- a/kernel/src/namespaces/namespace.rs +++ b/kernel/src/namespaces/namespace.rs @@ -3,6 +3,7 @@ use core::fmt::Debug; use crate::filesystem::procfs::ProcFSInode; use crate::filesystem::vfs::{IndexNode, ROOT_INODE}; +use crate::libs::rwlock::RwLock; use crate::namespaces::user_namespace::UserNamespace; use crate::process::fork::CloneFlags; use crate::process::{Pid, ProcessControlBlock, ProcessManager}; @@ -101,7 +102,7 @@ pub fn prepare_nsset(flags: u64) -> Result { let current = ProcessManager::current_pcb(); Ok(NsSet { flags, - fs: current.fs_struct(), + fs: RwLock::new(current.fs_struct()), nsproxy: create_new_namespaces(flags, ¤t, USER_NS.clone())?, }) } @@ -110,10 +111,10 @@ pub fn commit_nsset(nsset: NsSet) { let flags = CloneFlags::from_bits_truncate(nsset.flags); let current = ProcessManager::current_pcb(); if flags.contains(CloneFlags::CLONE_NEWNS) { - let fs = current.fs_struct(); - let nsset_fs = nsset.fs.lock(); - fs.lock().set_pwd(nsset_fs.pwd.clone()); - fs.lock().set_root(nsset_fs.root.clone()); + let nsset_fs = nsset.fs.read(); + let fs = current.fs_struct_mut(); + fs.set_pwd(nsset_fs.pwd()); + fs.set_root(nsset_fs.root()); } switch_task_namespace(current, nsset.nsproxy); // 转移所有权 } diff --git a/kernel/src/namespaces/pid_namespace.rs b/kernel/src/namespaces/pid_namespace.rs index 7f1eb05b..f07a51bd 100644 --- a/kernel/src/namespaces/pid_namespace.rs +++ b/kernel/src/namespaces/pid_namespace.rs @@ -9,8 +9,8 @@ use crate::container_of; use crate::filesystem::vfs::{IndexNode, ROOT_INODE}; use crate::namespaces::namespace::NsOperations; use crate::process::fork::CloneFlags; +use crate::process::geteuid::do_geteuid; use crate::process::ProcessManager; -use crate::syscall::Syscall; use crate::{libs::rwlock::RwLock, process::Pid}; use alloc::boxed::Box; use alloc::string::String; @@ -264,7 +264,7 @@ impl PidNamespace { ) -> Result>, SystemError> { Ok(self .ucounts - .inc_ucounts(user_ns, Syscall::geteuid()?, PidNamespaces)) + .inc_ucounts(user_ns, do_geteuid()?, PidNamespaces)) } pub fn dec_pid_namespaces(&mut self, uc: Arc) { diff --git a/kernel/src/net/event_poll/syscall.rs b/kernel/src/net/event_poll/syscall.rs deleted file mode 100644 index a984bbd2..00000000 --- a/kernel/src/net/event_poll/syscall.rs +++ /dev/null @@ -1,108 +0,0 @@ -use system_error::SystemError; - -use crate::{ - arch::ipc::signal::SigSet, - filesystem::vfs::file::FileMode, - ipc::signal::{restore_saved_sigmask, set_user_sigmask}, - mm::VirtAddr, - syscall::{ - user_access::{UserBufferReader, UserBufferWriter}, - Syscall, - }, - time::PosixTimeSpec, -}; - -use super::{EPollCtlOption, EPollEvent, EventPoll}; - -impl Syscall { - pub fn epoll_create(max_size: i32) -> Result { - if max_size < 0 { - return Err(SystemError::EINVAL); - } - - return EventPoll::create_epoll(FileMode::empty()); - } - - pub fn epoll_create1(flag: usize) -> Result { - let flags = FileMode::from_bits_truncate(flag as u32); - - let ret = EventPoll::create_epoll(flags); - ret - } - - pub fn epoll_wait( - epfd: i32, - events: VirtAddr, - max_events: i32, - timeout: i32, - ) -> Result { - if max_events <= 0 || max_events as u32 > EventPoll::EP_MAX_EVENTS { - return Err(SystemError::EINVAL); - } - - let mut timespec = None; - if timeout == 0 { - timespec = Some(PosixTimeSpec::new(0, 0)); - } - - if timeout > 0 { - let sec: i64 = timeout as i64 / 1000; - let nsec: i64 = 1000000 * (timeout as i64 % 1000); - - timespec = Some(PosixTimeSpec::new(sec, nsec)) - } - - // 从用户传入的地址中拿到epoll_events - let mut epds_writer = UserBufferWriter::new( - events.as_ptr::(), - max_events as usize * core::mem::size_of::(), - true, - )?; - - let epoll_events = epds_writer.buffer::(0)?; - return EventPoll::epoll_wait(epfd, epoll_events, max_events, timespec); - } - - pub fn epoll_ctl(epfd: i32, op: usize, fd: i32, event: VirtAddr) -> Result { - let op = EPollCtlOption::from_op_num(op)?; - let mut epds = EPollEvent::default(); - if op != EPollCtlOption::Del { - // 不为EpollCtlDel时不允许传入空指针 - if event.is_null() { - return Err(SystemError::EFAULT); - } - - // 还是一样的问题,C标准的epoll_event大小为12字节,而内核实现的epoll_event内存对齐后为16字节 - // 这样分别拷贝其实和整体拷贝差别不大,内核使用内存对其版本甚至可能提升性能 - let epds_reader = UserBufferReader::new( - event.as_ptr::(), - core::mem::size_of::(), - true, - )?; - - // 拷贝到内核 - epds_reader.copy_one_from_user(&mut epds, 0)?; - } - - return EventPoll::epoll_ctl_with_epfd(epfd, op, fd, epds, false); - } - - /// ## 在epoll_wait时屏蔽某些信号 - pub fn epoll_pwait( - epfd: i32, - epoll_event: VirtAddr, - max_events: i32, - timespec: i32, - sigmask: &mut SigSet, - ) -> Result { - // 设置屏蔽的信号 - set_user_sigmask(sigmask); - - let wait_ret = Self::epoll_wait(epfd, epoll_event, max_events, timespec); - - if wait_ret.is_err() && *wait_ret.as_ref().unwrap_err() != SystemError::EINTR { - restore_saved_sigmask(); - } - wait_ret - } -} diff --git a/kernel/src/net/mod.rs b/kernel/src/net/mod.rs index 83a52c74..805761cc 100644 --- a/kernel/src/net/mod.rs +++ b/kernel/src/net/mod.rs @@ -8,7 +8,6 @@ use alloc::{collections::BTreeMap, sync::Arc}; use crate::{driver::net::Iface, libs::rwlock::RwLock}; -pub mod event_poll; pub mod net_core; pub mod posix; pub mod socket; diff --git a/kernel/src/net/posix.rs b/kernel/src/net/posix.rs index 937273de..b4d6c07d 100644 --- a/kernel/src/net/posix.rs +++ b/kernel/src/net/posix.rs @@ -364,7 +364,7 @@ pub struct MsgHdr { /// SockAddr结构体的大小 pub msg_namelen: u32, /// scatter/gather array - pub msg_iov: *mut crate::filesystem::vfs::syscall::IoVec, + pub msg_iov: *mut crate::filesystem::vfs::iov::IoVec, /// elements in msg_iov pub msg_iovlen: usize, /// 辅助数据 diff --git a/kernel/src/net/socket/common/epoll_items.rs b/kernel/src/net/socket/common/epoll_items.rs index 9d8ad47c..b81f7ec8 100644 --- a/kernel/src/net/socket/common/epoll_items.rs +++ b/kernel/src/net/socket/common/epoll_items.rs @@ -6,8 +6,8 @@ use alloc::{ use system_error::SystemError; use crate::{ + filesystem::epoll::{event_poll::EventPoll, EPollItem}, libs::spinlock::SpinLock, - net::event_poll::{EPollItem, EventPoll}, }; #[derive(Debug, Clone)] @@ -50,8 +50,8 @@ impl EPollItems { let mut result = Ok(()); guard.iter().for_each(|item| { if let Some(epoll) = item.epoll().upgrade() { - let _ = - EventPoll::ep_remove(&mut epoll.lock_irqsave(), item.fd(), None).map_err(|e| { + let _ = EventPoll::ep_remove(&mut epoll.lock_irqsave(), item.fd(), None, item) + .map_err(|e| { result = Err(e); }); } diff --git a/kernel/src/net/socket/inet/datagram/mod.rs b/kernel/src/net/socket/inet/datagram/mod.rs index 594457c5..cdd51a95 100644 --- a/kernel/src/net/socket/inet/datagram/mod.rs +++ b/kernel/src/net/socket/inet/datagram/mod.rs @@ -2,8 +2,8 @@ use inner::{UdpInner, UnboundUdp}; use smoltcp; use system_error::SystemError; +use crate::filesystem::epoll::EPollEventType; use crate::libs::wait_queue::WaitQueue; -use crate::net::event_poll::EPollEventType; use crate::net::socket::{Socket, PMSG}; use crate::{libs::rwlock::RwLock, net::socket::endpoint::Endpoint}; use alloc::sync::{Arc, Weak}; @@ -13,7 +13,7 @@ use super::InetSocket; pub mod inner; -type EP = EPollEventType; +type EP = crate::filesystem::epoll::EPollEventType; // Udp Socket 负责提供状态切换接口、执行状态切换 #[derive(Debug)] diff --git a/kernel/src/net/socket/inet/stream/inner.rs b/kernel/src/net/socket/inet/stream/inner.rs index bda841a4..9afbfa6e 100644 --- a/kernel/src/net/socket/inet/stream/inner.rs +++ b/kernel/src/net/socket/inet/stream/inner.rs @@ -1,7 +1,7 @@ use core::sync::atomic::AtomicUsize; +use crate::filesystem::epoll::EPollEventType; use crate::libs::rwlock::RwLock; -use crate::net::socket::EPollEventType; use crate::net::socket::{self, inet::Types}; use alloc::boxed::Box; use alloc::vec::Vec; diff --git a/kernel/src/net/socket/inet/stream/mod.rs b/kernel/src/net/socket/inet/stream/mod.rs index a9193ae5..6484d842 100644 --- a/kernel/src/net/socket/inet/stream/mod.rs +++ b/kernel/src/net/socket/inet/stream/mod.rs @@ -3,7 +3,6 @@ use core::sync::atomic::{AtomicBool, AtomicUsize}; use system_error::SystemError; use crate::libs::wait_queue::WaitQueue; -use crate::net::event_poll::EPollEventType; use crate::net::socket::common::shutdown::{ShutdownBit, ShutdownTemp}; use crate::net::socket::endpoint::Endpoint; use crate::net::socket::{Socket, SocketInode, PMSG, PSOL}; @@ -18,7 +17,7 @@ pub use option::Options as TcpOption; use super::{InetSocket, UNSPECIFIED_LOCAL_ENDPOINT_V4, UNSPECIFIED_LOCAL_ENDPOINT_V6}; -type EP = EPollEventType; +type EP = crate::filesystem::epoll::EPollEventType; #[derive(Debug)] pub struct TcpSocket { inner: RwLock>, diff --git a/kernel/src/net/socket/inode.rs b/kernel/src/net/socket/inode.rs index 8fabf5ea..bad85527 100644 --- a/kernel/src/net/socket/inode.rs +++ b/kernel/src/net/socket/inode.rs @@ -52,10 +52,6 @@ impl IndexNode for SocketInode { unimplemented!() } - fn poll(&self, _: &crate::filesystem::vfs::FilePrivateData) -> Result { - Ok(self.inner.poll()) - } - fn open( &self, _data: crate::libs::spinlock::SpinLockGuard, diff --git a/kernel/src/net/socket/mod.rs b/kernel/src/net/socket/mod.rs index 96d16c44..ed1796e8 100644 --- a/kernel/src/net/socket/mod.rs +++ b/kernel/src/net/socket/mod.rs @@ -12,7 +12,6 @@ mod utils; use crate::libs::wait_queue::WaitQueue; pub use base::Socket; -pub use crate::net::event_poll::EPollEventType; pub use common::{ // poll_unit::{EPollItems, WaitQueue}, EPollItems, diff --git a/kernel/src/net/socket/unix/seqpacket/mod.rs b/kernel/src/net/socket/unix/seqpacket/mod.rs index 3ad63086..4a47e55a 100644 --- a/kernel/src/net/socket/unix/seqpacket/mod.rs +++ b/kernel/src/net/socket/unix/seqpacket/mod.rs @@ -7,7 +7,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; use crate::{ libs::{rwlock::RwLock, wait_queue::WaitQueue}, - net::socket::{EPollEventType, Socket, SocketInode, PMSG}, + net::socket::{Socket, SocketInode, PMSG}, }; use crate::{ net::{ @@ -27,7 +27,7 @@ use super::{ INODE_MAP, }; -type EP = EPollEventType; +type EP = crate::filesystem::epoll::EPollEventType; #[derive(Debug)] pub struct SeqpacketSocket { inner: RwLock, diff --git a/kernel/src/net/socket/unix/stream/mod.rs b/kernel/src/net/socket/unix/stream/mod.rs index 4ce34fce..10b040d4 100644 --- a/kernel/src/net/socket/unix/stream/mod.rs +++ b/kernel/src/net/socket/unix/stream/mod.rs @@ -25,7 +25,7 @@ use crate::{ net::socket::{self, *}, }; -type EP = EPollEventType; +type EP = crate::filesystem::epoll::EPollEventType; pub mod inner; diff --git a/kernel/src/net/syscall.rs b/kernel/src/net/syscall.rs index 47e1e2d4..2d90eff9 100644 --- a/kernel/src/net/syscall.rs +++ b/kernel/src/net/syscall.rs @@ -3,14 +3,18 @@ use log::debug; use system_error::SystemError; use crate::{ - filesystem::vfs::file::{File, FileMode}, + filesystem::vfs::{ + file::{File, FileMode}, + iov::IoVecs, + }, + net::socket::AddressFamily, process::ProcessManager, syscall::Syscall, }; use super::{ posix::{MsgHdr, PosixArgsSocketType, SockAddr}, - socket::{self, endpoint::Endpoint, unix::Unix, AddressFamily}, + socket::{self, endpoint::Endpoint, unix::Unix}, }; /// Flags for socket, socketpair, accept4 @@ -322,9 +326,7 @@ impl Syscall { /// @return 成功返回接收的字节数,失败返回错误码 pub fn recvmsg(fd: usize, msg: &mut MsgHdr, flags: u32) -> Result { // 检查每个缓冲区地址是否合法,生成iovecs - let mut iovs = unsafe { - crate::filesystem::vfs::syscall::IoVecs::from_user(msg.msg_iov, msg.msg_iovlen, true)? - }; + let iovs = unsafe { IoVecs::from_user(msg.msg_iov, msg.msg_iovlen, true)? }; let socket: Arc = ProcessManager::current_pcb() .get_socket(fd as i32) diff --git a/kernel/src/perf/mod.rs b/kernel/src/perf/mod.rs index 99d2e25a..b5622780 100644 --- a/kernel/src/perf/mod.rs +++ b/kernel/src/perf/mod.rs @@ -2,11 +2,12 @@ mod bpf; mod kprobe; mod util; +use crate::filesystem::epoll::{event_poll::EventPoll, EPollEventType, EPollItem}; use crate::filesystem::page_cache::PageCache; use crate::filesystem::vfs::file::{File, FileMode}; use crate::filesystem::vfs::syscall::ModeType; use crate::filesystem::vfs::{ - FilePrivateData, FileSystem, FileType, FsInfo, IndexNode, Metadata, SuperBlock, + FilePrivateData, FileSystem, FileType, FsInfo, IndexNode, Metadata, PollableInode, SuperBlock, }; use crate::include::bindings::linux_bpf::{ perf_event_attr, perf_event_sample_format, perf_sw_ids, perf_type_id, @@ -15,7 +16,6 @@ use crate::libs::casting::DowncastArc; use crate::libs::spinlock::{SpinLock, SpinLockGuard}; use crate::mm::fault::{PageFaultHandler, PageFaultMessage}; use crate::mm::VmFaultReason; -use crate::net::event_poll::{EPollEventType, EPollItem, EventPoll, KernelIoctlData}; use crate::perf::bpf::BpfPerfEvent; use crate::perf::util::{PerfEventIoc, PerfEventOpenFlags, PerfProbeArgs}; use crate::process::ProcessManager; @@ -24,7 +24,7 @@ use crate::syscall::Syscall; use alloc::boxed::Box; use alloc::collections::LinkedList; use alloc::string::String; -use alloc::sync::{Arc, Weak}; +use alloc::sync::Arc; use alloc::vec::Vec; use core::any::Any; use core::ffi::c_void; @@ -67,21 +67,6 @@ impl PerfEventInode { epitems: SpinLock::new(LinkedList::new()), } } - pub fn remove_epoll( - &self, - epoll: &Weak>, - ) -> core::result::Result<(), SystemError> { - let is_remove = !self - .epitems - .lock_irqsave() - .extract_if(|x| x.epoll().ptr_eq(epoll)) - .collect::>() - .is_empty(); - if is_remove { - return Ok(()); - } - Err(SystemError::ENOENT) - } fn do_poll(&self) -> Result { let mut events = EPollEventType::empty(); if self.event.readable() { @@ -92,7 +77,7 @@ impl PerfEventInode { fn epoll_callback(&self) -> Result<()> { let pollflag = EPollEventType::from_bits_truncate(self.do_poll()? as u32); // 唤醒epoll中等待的进程 - EventPoll::wakeup_epoll(&self.epitems, Some(pollflag)) + EventPoll::wakeup_epoll(&self.epitems, pollflag) } } @@ -134,10 +119,6 @@ impl IndexNode for PerfEventInode { panic!("write_at not implemented for PerfEvent"); } - fn poll(&self, _private_data: &FilePrivateData) -> Result { - self.do_poll() - } - fn metadata(&self) -> Result { let meta = Metadata { mode: ModeType::from_bits_truncate(0o755), @@ -177,32 +158,51 @@ impl IndexNode for PerfEventInode { } } - fn kernel_ioctl( - &self, - arg: Arc, - _data: &FilePrivateData, - ) -> core::result::Result { - let epitem = arg - .arc_any() - .downcast::() - .map_err(|_| SystemError::EFAULT)?; - self.epitems.lock().push_back(epitem); - Ok(0) - } - fn fs(&self) -> Arc { // panic!("PerfEvent does not have a filesystem") Arc::new(PerfFakeFs) } + fn as_any_ref(&self) -> &dyn Any { self } + fn list(&self) -> Result> { Err(SystemError::ENOSYS) } + fn page_cache(&self) -> Option> { self.event.page_cache() } + + fn as_pollable_inode(&self) -> Result<&dyn PollableInode> { + Ok(self) + } +} + +impl PollableInode for PerfEventInode { + fn poll(&self, _private_data: &FilePrivateData) -> Result { + self.do_poll() + } + + fn add_epitem(&self, epitem: Arc, _private_data: &FilePrivateData) -> Result<()> { + self.epitems.lock().push_back(epitem); + Ok(()) + } + + fn remove_epitem( + &self, + epitem: &Arc, + _private_data: &FilePrivateData, + ) -> Result<()> { + let mut guard = self.epitems.lock(); + let len = guard.len(); + guard.retain(|x| !Arc::ptr_eq(x, epitem)); + if len != guard.len() { + return Ok(()); + } + Err(SystemError::ENOENT) + } } #[derive(Debug)] diff --git a/kernel/src/process/abi.rs b/kernel/src/process/abi.rs index cbaab9d0..a39f4ff3 100644 --- a/kernel/src/process/abi.rs +++ b/kernel/src/process/abi.rs @@ -38,7 +38,7 @@ pub enum AtType { /// Frequency at which times() increments. ClkTck, /// Secure mode boolean. - Secure, + Secure = 23, /// String identifying real platform, may differ from AT_PLATFORM. BasePlatform, /// Address of 16 random bytes. @@ -46,7 +46,7 @@ pub enum AtType { /// Extension of AT_HWCAP. HwCap2, /// Filename of program. - ExecFn, + ExecFn = 31, /// Minimal stack size for signal delivery. MinSigStackSize, } diff --git a/kernel/src/process/c_adapter.rs b/kernel/src/process/c_adapter.rs deleted file mode 100644 index a0669e3a..00000000 --- a/kernel/src/process/c_adapter.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::smp::core::smp_get_processor_id; - -use super::{process_init, ProcessManager, __PROCESS_MANAGEMENT_INIT_DONE}; - -#[no_mangle] -unsafe extern "C" fn rs_process_init() { - process_init(); -} - -/// 临时用于获取空闲进程的栈顶的函数,这个函数是为了旧的smp模块的初始化而写在这的 -#[no_mangle] -unsafe extern "C" fn rs_get_idle_stack_top(cpu_id: u32) -> usize { - return ProcessManager::idle_pcb()[cpu_id as usize] - .kernel_stack() - .stack_max_address() - .data(); -} - -#[no_mangle] -unsafe extern "C" fn rs_current_pcb_cpuid() -> u32 { - return smp_get_processor_id().data(); -} - -#[no_mangle] -unsafe extern "C" fn rs_current_pcb_pid() -> u32 { - if unsafe { __PROCESS_MANAGEMENT_INIT_DONE } { - return ProcessManager::current_pcb().pid().0 as u32; - } - return 0; -} - -#[no_mangle] -unsafe extern "C" fn rs_current_pcb_preempt_count() -> u32 { - if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } { - return 0; - } - return ProcessManager::current_pcb().preempt_count() as u32; -} - -#[no_mangle] -unsafe extern "C" fn rs_current_pcb_flags() -> u32 { - if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } { - return 0; - } - return ProcessManager::current_pcb().flags().bits() as u32; -} - -#[no_mangle] -#[cfg(target_arch = "x86_64")] -unsafe extern "C" fn rs_current_pcb_thread_rbp() -> u64 { - if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } { - return 0; - } - return ProcessManager::current_pcb().arch_info_irqsave().rbp() as u64; -} - -#[no_mangle] -#[cfg(target_arch = "riscv64")] -unsafe extern "C" fn rs_current_pcb_thread_rbp() -> u64 { - // 不应该实现这个函数 - unimplemented!("rs_current_pcb_thread_rbp") -} - -#[no_mangle] -unsafe extern "C" fn rs_preempt_disable() { - return ProcessManager::preempt_disable(); -} - -#[no_mangle] -unsafe extern "C" fn rs_preempt_enable() { - return ProcessManager::preempt_enable(); -} - -#[no_mangle] -unsafe extern "C" fn rs_process_do_exit(exit_code: usize) -> usize { - if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } { - return 0; - } - ProcessManager::exit(exit_code); -} diff --git a/kernel/src/process/exec.rs b/kernel/src/process/exec.rs index 12af4c33..5eaae376 100644 --- a/kernel/src/process/exec.rs +++ b/kernel/src/process/exec.rs @@ -5,10 +5,7 @@ use system_error::SystemError; use crate::{ driver::base::block::SeekFrom, - filesystem::vfs::{ - file::{File, FileMode}, - ROOT_INODE, - }, + filesystem::vfs::file::{File, FileMode}, libs::elf::ELF_LOADER, mm::{ ucontext::{AddressSpace, UserStack}, @@ -118,7 +115,8 @@ impl ExecParam { vm: Arc, flags: ExecParamFlags, ) -> Result { - let inode = ROOT_INODE().lookup(file_path)?; + let pwd = ProcessManager::current_pcb().pwd_inode(); + let inode = pwd.lookup(file_path)?; // 读取文件头部,用于判断文件类型 let file = File::new(inode, FileMode::O_RDONLY)?; @@ -159,6 +157,11 @@ impl ExecParam { pub fn file_mut(&mut self) -> &mut File { &mut self.file } + + /// 获取File的所有权,用于将动态链接器加入文件描述符表中 + pub fn file(self) -> File { + self.file + } } /// ## 加载二进制文件 @@ -201,6 +204,7 @@ pub struct ProcInitInfo { pub args: Vec, pub envs: Vec, pub auxv: BTreeMap, + pub rand_num: [u8; 16], } impl ProcInitInfo { @@ -210,6 +214,7 @@ impl ProcInitInfo { args: Vec::new(), envs: Vec::new(), auxv: BTreeMap::new(), + rand_num: [0u8; 16], } } @@ -220,7 +225,7 @@ impl ProcInitInfo { /// /// 返回值是一个元组,第一个元素是最终的用户栈顶地址,第二个元素是环境变量pointer数组的起始地址 pub unsafe fn push_at( - &self, + &mut self, ustack: &mut UserStack, ) -> Result<(VirtAddr, VirtAddr), SystemError> { // 先把程序的名称压入栈中 @@ -235,6 +240,7 @@ impl ProcInitInfo { ustack.sp() }) .collect::>(); + // 然后把参数压入栈中 let argps = self .args @@ -245,6 +251,20 @@ impl ProcInitInfo { }) .collect::>(); + // 压入随机数,把指针放入auxv + self.push_slice(ustack, &[self.rand_num])?; + self.auxv + .insert(super::abi::AtType::Random as u8, ustack.sp().data()); + + // 实现栈的16字节对齐 + // 用当前栈顶地址减去后续要压栈的长度,得到的压栈后的栈顶地址与0xF按位与操作得到对齐要填充的字节数 + let length_to_push = (self.auxv.len() + envps.len() + 1 + argps.len() + 1 + 1) + * core::mem::align_of::(); + self.push_slice( + ustack, + &vec![0u8; (ustack.sp().data() - length_to_push) & 0xF], + )?; + // 压入auxv self.push_slice(ustack, &[null::(), null::()])?; for (&k, &v) in self.auxv.iter() { @@ -258,7 +278,6 @@ impl ProcInitInfo { // 把参数指针压入栈中 self.push_slice(ustack, &[null::()])?; self.push_slice(ustack, argps.as_slice())?; - let argv_ptr = ustack.sp(); // 把argc压入栈中 diff --git a/kernel/src/process/execve.rs b/kernel/src/process/execve.rs new file mode 100644 index 00000000..7d2e4ac2 --- /dev/null +++ b/kernel/src/process/execve.rs @@ -0,0 +1,113 @@ +use crate::arch::CurrentIrqArch; +use crate::exception::InterruptArch; +use crate::process::exec::{load_binary_file, ExecParam, ExecParamFlags}; +use crate::process::ProcessManager; +use crate::syscall::Syscall; +use crate::{libs::rand::rand_bytes, mm::ucontext::AddressSpace}; + +use crate::arch::interrupt::TrapFrame; +use alloc::{ffi::CString, string::String, sync::Arc, vec::Vec}; +use system_error::SystemError; +pub fn do_execve( + path: String, + argv: Vec, + envp: Vec, + regs: &mut TrapFrame, +) -> Result<(), SystemError> { + let address_space = AddressSpace::new(true).expect("Failed to create new address space"); + // debug!("to load binary file"); + let mut param = ExecParam::new(path.as_str(), address_space.clone(), ExecParamFlags::EXEC)?; + let old_vm = do_execve_switch_user_vm(address_space.clone()); + + // 加载可执行文件 + let load_result = load_binary_file(&mut param).inspect_err(|_| { + if let Some(old_vm) = old_vm { + do_execve_switch_user_vm(old_vm); + } + })?; + + // debug!("load binary file done"); + // debug!("argv: {:?}, envp: {:?}", argv, envp); + param.init_info_mut().args = argv; + param.init_info_mut().envs = envp; + // // 生成16字节随机数 + param.init_info_mut().rand_num = rand_bytes::<16>(); + + // 把proc_init_info写到用户栈上 + let mut ustack_message = unsafe { + address_space + .write() + .user_stack_mut() + .expect("No user stack found") + .clone_info_only() + }; + let (user_sp, argv_ptr) = unsafe { + param + .init_info_mut() + .push_at( + // address_space + // .write() + // .user_stack_mut() + // .expect("No user stack found"), + &mut ustack_message, + ) + .expect("Failed to push proc_init_info to user stack") + }; + address_space.write().user_stack = Some(ustack_message); + + Syscall::arch_do_execve(regs, ¶m, &load_result, user_sp, argv_ptr) +} + +/// 切换用户虚拟内存空间 +/// +/// 该函数用于在执行系统调用 `execve` 时切换用户进程的虚拟内存空间。 +/// +/// # 参数 +/// - `new_vm`: 新的用户地址空间,类型为 `Arc`。 +/// +/// # 返回值 +/// - 返回旧的用户地址空间的引用,类型为 `Option>`。 +/// +/// # 错误处理 +/// 如果地址空间切换失败,函数会触发断言失败,并输出错误信息。 +fn do_execve_switch_user_vm(new_vm: Arc) -> Option> { + // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。 + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + let pcb = ProcessManager::current_pcb(); + // log::debug!( + // "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n", + // pcb.pid(), + // path, + // argv, + // envp + // ); + + let mut basic_info = pcb.basic_mut(); + // 暂存原本的用户地址空间的引用(因为如果在切换页表之前释放了它,可能会造成内存use after free) + let old_address_space = basic_info.user_vm(); + + // 在pcb中原来的用户地址空间 + unsafe { + basic_info.set_user_vm(None); + } + // 创建新的地址空间并设置为当前地址空间 + unsafe { + basic_info.set_user_vm(Some(new_vm.clone())); + } + + // to avoid deadlock + drop(basic_info); + + assert!( + AddressSpace::is_current(&new_vm), + "Failed to set address space" + ); + // debug!("Switch to new address space"); + + // 切换到新的用户地址空间 + unsafe { new_vm.read().user_mapper.utable.make_current() }; + + drop(irq_guard); + + old_address_space +} diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index 9cc1620d..4549e54b 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -1,26 +1,23 @@ -use core::intrinsics::likely; - use alloc::sync::Arc; -use log::warn; +use core::intrinsics::likely; use system_error::SystemError; use crate::{ arch::ipc::signal::{SigChildCode, Signal}, + ipc::syscall::sys_kill::PidConverter, sched::{schedule, SchedMode}, syscall::user_access::UserBufferWriter, time::{sleep::nanosleep, Duration}, }; use super::{ - abi::WaitOption, pid::PidType, resource::RUsage, Pid, ProcessControlBlock, ProcessManager, - ProcessState, + abi::WaitOption, resource::RUsage, Pid, ProcessControlBlock, ProcessManager, ProcessState, }; /// 内核wait4时的参数 #[derive(Debug)] pub struct KernelWaitOption<'a> { - pub pid_type: PidType, - pub pid: Pid, + pub pid_converter: PidConverter, pub options: WaitOption, pub ret_status: i32, pub ret_info: Option, @@ -37,10 +34,9 @@ pub struct WaitIdInfo { } impl KernelWaitOption<'_> { - pub fn new(pid_type: PidType, pid: Pid, options: WaitOption) -> Self { + pub fn new(pid_converter: PidConverter, options: WaitOption) -> Self { Self { - pid_type, - pid, + pid_converter, options, ret_status: 0, ret_info: None, @@ -51,36 +47,15 @@ impl KernelWaitOption<'_> { } pub fn kernel_wait4( - mut pid: i64, + pid: i32, wstatus_buf: Option>, options: WaitOption, rusage_buf: Option<&mut RUsage>, ) -> Result { - // i64::MIN is not defined - if pid == i64::MIN { - return Err(SystemError::ESRCH); - } - - // 判断pid类型 - let pidtype: PidType; - if pid == -1 { - pidtype = PidType::MAX; - } else if pid < 0 { - pidtype = PidType::PGID; - warn!("kernel_wait4: currently not support pgid, default to wait for pid\n"); - pid = -pid; - } else if pid == 0 { - pidtype = PidType::PGID; - warn!("kernel_wait4: currently not support pgid, default to wait for pid\n"); - pid = ProcessManager::current_pcb().pid().data() as i64; - } else { - pidtype = PidType::PID; - } - - let pid = Pid(pid as usize); + let converter = PidConverter::from_id(pid); // 构造参数 - let mut kwo = KernelWaitOption::new(pidtype, pid, options); + let mut kwo = KernelWaitOption::new(converter, options); kwo.options.insert(WaitOption::WEXITED); kwo.ret_rusage = rusage_buf; @@ -131,59 +106,78 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result { 'outer: loop { kwo.no_task_error = Some(SystemError::ECHILD); - let child_pcb = ProcessManager::find(kwo.pid).ok_or(SystemError::ECHILD); - - if kwo.pid_type != PidType::MAX && child_pcb.is_err() { - notask!('outer); - } - - if kwo.pid_type == PidType::PID { - let child_pcb = child_pcb.unwrap(); - // 获取weak引用,以便于在do_waitpid中能正常drop pcb - let child_weak = Arc::downgrade(&child_pcb); - let r = do_waitpid(child_pcb, kwo); - if let Some(r) = r { - retval = r; - break 'outer; - } else if let Err(SystemError::ESRCH) = child_weak.upgrade().unwrap().wait_queue.sleep() - { - // log::debug!("do_wait: child_pcb sleep failed"); - continue; - } - } else if kwo.pid_type == PidType::MAX { - // 等待任意子进程 - // todo: 这里有问题!应当让当前进程sleep到自身的child_wait等待队列上,这样才高效。(还没实现) - let current_pcb = ProcessManager::current_pcb(); - loop { - let rd_childen = current_pcb.children.read(); - if rd_childen.is_empty() { - break; + match kwo.pid_converter { + PidConverter::Pid(pid) => { + let child_pcb = ProcessManager::find(pid) + .ok_or(SystemError::ECHILD) + .unwrap(); + // 获取weak引用,以便于在do_waitpid中能正常drop pcb + let child_weak = Arc::downgrade(&child_pcb); + let r: Option> = do_waitpid(child_pcb, kwo); + if let Some(r) = r { + retval = r; + break 'outer; + } else if let Err(SystemError::ESRCH) = + child_weak.upgrade().unwrap().wait_queue.sleep() + { + // log::debug!("do_wait: child_pcb sleep failed"); + continue; } - for pid in rd_childen.iter() { - let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?; - let sched_guard = pcb.sched_info().inner_lock_read_irqsave(); - let state = sched_guard.state(); - if state.is_exited() { - kwo.ret_status = state.exit_code().unwrap() as i32; - kwo.no_task_error = None; - // 由于pcb的drop方法里面要获取父进程的children字段的写锁,所以这里不能直接drop pcb, - // 而是要先break到外层循环,以便释放父进程的children字段的锁,才能drop pcb。 - // 否则会死锁。 - tmp_child_pcb = Some(pcb.clone()); - unsafe { ProcessManager::release(*pid) }; - retval = Ok((*pid).into()); - break 'outer; + } + PidConverter::All => { + // 等待任意子进程 + // todo: 这里有问题!应当让当前进程sleep到自身的child_wait等待队列上,这样才高效。(还没实现) + let current_pcb = ProcessManager::current_pcb(); + loop { + let rd_childen = current_pcb.children.read(); + if rd_childen.is_empty() { + break; } + for pid in rd_childen.iter() { + let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?; + let sched_guard = pcb.sched_info().inner_lock_read_irqsave(); + let state = sched_guard.state(); + if state.is_exited() { + kwo.ret_status = state.exit_code().unwrap() as i32; + kwo.no_task_error = None; + // 由于pcb的drop方法里面要获取父进程的children字段的写锁,所以这里不能直接drop pcb, + // 而是要先break到外层循环,以便释放父进程的children字段的锁,才能drop pcb。 + // 否则会死锁。 + tmp_child_pcb = Some(pcb.clone()); + unsafe { ProcessManager::release(*pid) }; + retval = Ok((*pid).into()); + break 'outer; + } + } + drop(rd_childen); + nanosleep(Duration::from_millis(100).into())?; + } + } + PidConverter::Pgid(pgid) => { + let pg = ProcessManager::find_process_group(pgid).ok_or(SystemError::ESRCH)?; + loop { + let inner = pg.process_group_inner.lock(); + for (_, pcb) in inner.processes.iter() { + let sched_guard = pcb.sched_info().inner_lock_read_irqsave(); + let state = sched_guard.state(); + if state.is_exited() { + kwo.ret_status = state.exit_code().unwrap() as i32; + kwo.no_task_error = None; + // 由于pcb的drop方法里面要获取父进程的children字段的写锁,所以这里不能直接drop pcb, + // 而是要先break到外层循环,以便释放父进程的children字段的锁,才能drop pcb。 + // 否则会死锁。 + tmp_child_pcb = Some(pcb.clone()); + let pid = pcb.pid(); + unsafe { ProcessManager::release(pid) }; + retval = Ok((pid).into()); + break 'outer; + } + } + drop(inner); + nanosleep(Duration::from_millis(100).into())?; } - drop(rd_childen); - nanosleep(Duration::from_millis(100).into())?; } - } else { - // todo: 对于pgid的处理 - warn!("kernel_wait4: currently not support {:?}", kwo.pid_type); - return Err(SystemError::EINVAL); } - notask!('outer); } @@ -271,6 +265,7 @@ fn do_waitpid( kwo.ret_status = status as i32; + child_pcb.clear_pg_and_session_reference(); drop(child_pcb); // debug!("wait4: to release {pid:?}"); unsafe { ProcessManager::release(pid) }; diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index ca4e6015..c150af89 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -20,7 +20,7 @@ use crate::{ use super::{ kthread::{KernelThreadPcbPrivate, WorkerPrivate}, - KernelStack, Pid, ProcessControlBlock, ProcessManager, + KernelStack, Pgid, Pid, ProcessControlBlock, ProcessManager, Sid, }; const MAX_PID_NS_LEVEL: usize = 32; @@ -179,7 +179,6 @@ impl ProcessManager { ); e })?; - ProcessManager::add_pcb(pcb.clone()); // 向procfs注册进程 procfs_register_pid(pcb.pid()).unwrap_or_else(|e| { @@ -311,13 +310,21 @@ impl ProcessManager { current_pcb: &Arc, new_pcb: &Arc, ) -> Result<(), SystemError> { - // // 将信号的处理函数设置为default(除了那些被手动屏蔽的) - if clone_flags.contains(CloneFlags::CLONE_CLEAR_SIGHAND) { - flush_signal_handlers(new_pcb.clone(), false); + // todo SignalStruct结构需要更改,属于线程组逻辑 + if clone_flags.contains(CloneFlags::CLONE_SIGHAND) { + // log::debug!("copy_sighand: CLONE_SIGHAND"); + current_pcb + .sig_struct_irqsave() + .cnt + .fetch_add(1, Ordering::SeqCst); + return Ok(()); } - if clone_flags.contains(CloneFlags::CLONE_SIGHAND) { - new_pcb.sig_struct_irqsave().handlers = current_pcb.sig_struct_irqsave().handlers; + // log::debug!("Just copy sighand"); + new_pcb.sig_struct_irqsave().handlers = current_pcb.sig_struct_irqsave().handlers; + + if clone_flags.contains(CloneFlags::CLONE_CLEAR_SIGHAND) { + flush_signal_handlers(new_pcb.clone(), false); } return Ok(()); } @@ -343,6 +350,7 @@ impl ProcessManager { clone_args: KernelCloneArgs, current_trapframe: &TrapFrame, ) -> Result<(), SystemError> { + // log::debug!("fork: clone_flags: {:?}", clone_args.flags); let clone_flags = clone_args.flags; // 不允许与不同namespace的进程共享根目录 @@ -497,7 +505,8 @@ impl ProcessManager { } else { pcb.thread.write_irqsave().group_leader = Arc::downgrade(pcb); - let ptr = pcb.as_ref() as *const ProcessControlBlock as *mut ProcessControlBlock; + let ptr: *mut ProcessControlBlock = + pcb.as_ref() as *const ProcessControlBlock as *mut ProcessControlBlock; unsafe { (*ptr).tgid = pcb.pid; } @@ -533,8 +542,82 @@ impl ProcessManager { // todo: 增加线程组相关的逻辑。 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/fork.c#2437 + Self::copy_group(current_pcb, pcb).unwrap_or_else(|e| { + panic!( + "fork: Failed to set the process group for the new pcb, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", + current_pcb.pid(), pcb.pid(), e + ) + }); + + Self::copy_fs(&clone_flags, current_pcb, pcb).unwrap_or_else(|e| { + panic!( + "fork: Failed to copy fs from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", + current_pcb.pid(), pcb.pid(), e + ) + }); + sched_cgroup_fork(pcb); Ok(()) } + + /// 拷贝进程组信息 + /// + /// ## 参数 + /// + /// `parent_pcb` - 父进程 + /// `child_pcb` - 子进程 + /// ## 返回值 + /// + /// 无 + fn copy_group( + parent_pcb: &Arc, + child_pcb: &Arc, + ) -> Result<(), SystemError> { + if parent_pcb.process_group().is_none() && parent_pcb.pid() == Pid(0) { + return Ok(()); + } + let pg = parent_pcb.process_group().unwrap(); + + let mut pg_inner = pg.process_group_inner.lock(); + + let mut children_writelock = parent_pcb.children.write(); + + children_writelock.push(child_pcb.pid()); + + pg_inner + .processes + .insert(child_pcb.pid(), child_pcb.clone()); + + // 检查是否已经存在pgid和sid + let pgid = Pgid::new(child_pcb.pid().0); + let sid = Sid::new(pgid.into()); + + if ProcessManager::find_process_group(pgid).is_some() { + ProcessManager::remove_process_group(pgid); + } + if ProcessManager::find_session(sid).is_some() { + ProcessManager::remove_session(sid); + } + + child_pcb.set_process_group(&pg); + + Ok(()) + } + + fn copy_fs( + clone_flags: &CloneFlags, + parent_pcb: &Arc, + child_pcb: &Arc, + ) -> Result<(), SystemError> { + let fs = parent_pcb.fs_struct(); + let mut guard = child_pcb.fs_struct_mut(); + if clone_flags.contains(CloneFlags::CLONE_FS) { + *guard = fs.clone(); + } else { + let new_fs = (*fs).clone(); + *guard = Arc::new(new_fs); + } + Ok(()) + } } diff --git a/kernel/src/process/geteuid.rs b/kernel/src/process/geteuid.rs new file mode 100644 index 00000000..99fc3f2d --- /dev/null +++ b/kernel/src/process/geteuid.rs @@ -0,0 +1,8 @@ +use system_error::SystemError; + +use crate::process::ProcessManager; + +pub fn do_geteuid() -> Result { + let pcb = ProcessManager::current_pcb(); + return Ok(pcb.cred.lock().euid.data()); +} diff --git a/kernel/src/process/idle.rs b/kernel/src/process/idle.rs index 9849326f..ba282118 100644 --- a/kernel/src/process/idle.rs +++ b/kernel/src/process/idle.rs @@ -97,6 +97,11 @@ impl ProcessManager { } return VirtAddr::new(stack_ptr); } + + #[cfg(target_arch = "loongarch64")] + { + todo!("la64: stack_ptr() not implemented yet") + } } /// 获取idle进程数组的引用 diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index d7f80057..28406669 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -16,6 +16,8 @@ use alloc::{ use cred::INIT_CRED; use hashbrown::HashMap; use log::{debug, error, info, warn}; +use process_group::{Pgid, ProcessGroup, ALL_PROCESS_GROUP}; +use session::{Session, Sid, ALL_SESSION}; use system_error::SystemError; use crate::{ @@ -29,7 +31,7 @@ use crate::{ exception::InterruptArch, filesystem::{ procfs::procfs_unregister_pid, - vfs::{file::FileDescriptorVec, FileType}, + vfs::{file::FileDescriptorVec, FileType, IndexNode}, }, ipc::{ signal::RestartBlock, @@ -43,6 +45,7 @@ use crate::{ futex::{Futex, RobustListHead}, }, lock_free_flags::LockFreeFlags, + mutex::Mutex, rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, spinlock::{SpinLock, SpinLockGuard}, wait_queue::WaitQueue, @@ -64,22 +67,25 @@ use crate::{ cpu::{AtomicProcessorId, ProcessorId}, kick_cpu, }, - syscall::{user_access::clear_user, Syscall}, + syscall::user_access::clear_user, }; use timer::AlarmTimer; use self::{cred::Cred, kthread::WorkerPrivate}; pub mod abi; -pub mod c_adapter; pub mod cred; pub mod exec; +pub mod execve; pub mod exit; pub mod fork; +pub mod geteuid; pub mod idle; pub mod kthread; pub mod pid; +pub mod process_group; pub mod resource; +pub mod session; pub mod stdio; pub mod syscall; pub mod timer; @@ -132,6 +138,8 @@ impl ProcessManager { }; ALL_PROCESS.lock_irqsave().replace(HashMap::new()); + ALL_PROCESS_GROUP.lock_irqsave().replace(HashMap::new()); + ALL_SESSION.lock_irqsave().replace(HashMap::new()); Self::init_switch_result(); Self::arch_init(); debug!("process arch init done."); @@ -226,6 +234,15 @@ impl ProcessManager { .insert(pcb.pid(), pcb.clone()); } + /// ### 获取所有进程的pid + pub fn get_all_processes() -> Vec { + let mut pids = Vec::new(); + for (pid, _) in ALL_PROCESS.lock_irqsave().as_ref().unwrap().iter() { + pids.push(*pid); + } + pids + } + /// 唤醒一个进程 pub fn wakeup(pcb: &Arc) -> Result<(), SystemError> { let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; @@ -371,7 +388,7 @@ impl ProcessManager { return; } let parent_pcb = r.unwrap(); - let r = Syscall::kill(parent_pcb.pid(), Signal::SIGCHLD as i32); + let r = crate::ipc::kill::kill_process(parent_pcb.pid(), Signal::SIGCHLD); if r.is_err() { warn!( "failed to send kill signal to {:?}'s parent pcb {:?}", @@ -389,6 +406,11 @@ impl ProcessManager { /// ## 参数 /// /// - `exit_code` : 进程的退出码 + /// + /// ## 注意 + /// 对于正常退出的进程,状态码应该先左移八位,以便用户态读取的时候正常返回退出码;而对于被信号终止的进程,状态码则是最低七位,无需进行移位操作。 + /// + /// 因此注意,传入的`exit_code`应该是已经完成了移位操作的 pub fn exit(exit_code: usize) -> ! { // 关中断 let _irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; @@ -449,6 +471,7 @@ impl ProcessManager { } pcb.sig_info_mut().set_tty(None); + pcb.clear_pg_and_session_reference(); drop(pcb); ProcessManager::exit_notify(); } @@ -464,6 +487,7 @@ impl ProcessManager { pub unsafe fn release(pid: Pid) { let pcb = ProcessManager::find(pid); if pcb.is_some() { + // log::debug!("release pid {}", pid); // let pcb = pcb.unwrap(); // 判断该pcb是否在全局没有任何引用 // TODO: 当前,pcb的Arc指针存在泄露问题,引用计数不正确,打算在接下来实现debug专用的Arc,方便调试,然后解决这个bug。 @@ -701,7 +725,7 @@ pub struct ProcessControlBlock { thread: RwLock, /// 进程文件系统的状态 - fs: Arc>, + fs: RwLock>, ///闹钟定时器 alarm_timer: SpinLock>, @@ -717,6 +741,12 @@ pub struct ProcessControlBlock { self_ref: Weak, restart_block: SpinLock>, + + /// 进程组 + process_group: Mutex>, + + /// 进程的可执行文件路径 + executable_path: RwLock, } impl ProcessControlBlock { @@ -768,55 +798,58 @@ impl ProcessControlBlock { (Self::generate_pid(), ppid, cwd, cred, tty) }; - let basic_info = ProcessBasicInfo::new(Pid(0), ppid, Pid(0), name, cwd, None); + let basic_info = ProcessBasicInfo::new(ppid, name.clone(), cwd, None); let preempt_count = AtomicUsize::new(0); let flags = unsafe { LockFreeFlags::new(ProcessFlags::empty()) }; let sched_info = ProcessSchedulerInfo::new(None); - let arch_info = SpinLock::new(ArchPCBInfo::new(&kstack)); let ppcb: Weak = ProcessManager::find(ppid) .map(|p| Arc::downgrade(&p)) .unwrap_or_default(); - let mut pcb = Self { - pid, - tgid: pid, - thread_pid: Arc::new(RwLock::new(PidStrcut::new())), - basic: basic_info, - preempt_count, - flags, - kernel_stack: RwLock::new(kstack), - syscall_stack: RwLock::new(KernelStack::new().unwrap()), - worker_private: SpinLock::new(None), - sched_info, - arch_info, - sig_info: RwLock::new(ProcessSignalInfo::default()), - sig_struct: SpinLock::new(SignalStruct::new()), - exit_signal: AtomicSignal::new(Signal::SIGCHLD), - parent_pcb: RwLock::new(ppcb.clone()), - real_parent_pcb: RwLock::new(ppcb), - children: RwLock::new(Vec::new()), - wait_queue: WaitQueue::default(), - thread: RwLock::new(ThreadInfo::new()), - fs: Arc::new(SpinLock::new(FsStruct::new())), - alarm_timer: SpinLock::new(None), - robust_list: RwLock::new(None), - nsproxy: Arc::new(RwLock::new(NsProxy::new())), - cred: SpinLock::new(cred), - self_ref: Weak::new(), - restart_block: SpinLock::new(None), - }; - - pcb.sig_info.write().set_tty(tty); - - // 初始化系统调用栈 - #[cfg(target_arch = "x86_64")] - pcb.arch_info - .lock() - .init_syscall_stack(&pcb.syscall_stack.read()); + // 使用 Arc::new_cyclic 避免在栈上创建巨大的结构体 let pcb = Arc::new_cyclic(|weak| { - pcb.self_ref = weak.clone(); + let arch_info = SpinLock::new(ArchPCBInfo::new(&kstack)); + let pcb = Self { + pid, + tgid: pid, + thread_pid: Arc::new(RwLock::new(PidStrcut::new())), + basic: basic_info, + preempt_count, + flags, + kernel_stack: RwLock::new(kstack), + syscall_stack: RwLock::new(KernelStack::new().unwrap()), + worker_private: SpinLock::new(None), + sched_info, + arch_info, + sig_info: RwLock::new(ProcessSignalInfo::default()), + sig_struct: SpinLock::new(SignalStruct::new()), + exit_signal: AtomicSignal::new(Signal::SIGCHLD), + parent_pcb: RwLock::new(ppcb.clone()), + real_parent_pcb: RwLock::new(ppcb), + children: RwLock::new(Vec::new()), + wait_queue: WaitQueue::default(), + thread: RwLock::new(ThreadInfo::new()), + fs: RwLock::new(Arc::new(FsStruct::new())), + alarm_timer: SpinLock::new(None), + robust_list: RwLock::new(None), + nsproxy: Arc::new(RwLock::new(NsProxy::new())), + cred: SpinLock::new(cred), + self_ref: weak.clone(), + restart_block: SpinLock::new(None), + process_group: Mutex::new(Weak::new()), + executable_path: RwLock::new(name), + }; + + pcb.sig_info.write().set_tty(tty); + + // 初始化系统调用栈 + #[cfg(target_arch = "x86_64")] + pcb.arch_info + .lock() + .init_syscall_stack(&pcb.syscall_stack.read()); + pcb }); @@ -847,6 +880,25 @@ impl ProcessControlBlock { } } + if pcb.pid() > Pid(0) && !is_idle { + let process_group = ProcessGroup::new(pcb.clone()); + *pcb.process_group.lock() = Arc::downgrade(&process_group); + ProcessManager::add_process_group(process_group.clone()); + + let session = Session::new(process_group.clone()); + process_group.process_group_inner.lock().session = Arc::downgrade(&session); + session.session_inner.lock().leader = Some(pcb.clone()); + ProcessManager::add_session(session); + + ProcessManager::add_pcb(pcb.clone()); + } + // log::debug!( + // "A new process is created, pid: {:?}, pgid: {:?}, sid: {:?}", + // pcb.pid(), + // pcb.process_group().unwrap().pgid(), + // pcb.session().unwrap().sid() + // ); + return pcb; } @@ -880,6 +932,12 @@ impl ProcessControlBlock { self.preempt_count.store(count, Ordering::SeqCst); } + #[inline(always)] + pub fn contain_child(&self, pid: &Pid) -> bool { + let children = self.children.read(); + return children.contains(pid); + } + #[inline(always)] pub fn flags(&self) -> &mut ProcessFlags { return self.flags.get_mut(); @@ -962,8 +1020,16 @@ impl ProcessControlBlock { } #[inline(always)] - pub fn fs_struct(&self) -> Arc> { - self.fs.clone() + pub fn fs_struct(&self) -> Arc { + self.fs.read().clone() + } + + pub fn fs_struct_mut(&self) -> RwLockWriteGuard> { + self.fs.write() + } + + pub fn pwd_inode(&self) -> Arc { + self.fs.read().pwd() } /// 获取文件描述符表的Arc指针 @@ -977,6 +1043,14 @@ impl ProcessControlBlock { self.cred.lock().clone() } + pub fn set_execute_path(&self, path: String) { + *self.executable_path.write() = path; + } + + pub fn execute_path(&self) -> String { + self.executable_path.read().clone() + } + /// 根据文件描述符序号,获取socket对象的Arc指针 /// /// ## 参数 @@ -1071,6 +1145,24 @@ impl ProcessControlBlock { self.flags.get().contains(ProcessFlags::HAS_PENDING_SIGNAL) } + /// 检查当前进程是否有未被阻塞的待处理信号。 + /// + /// 注:该函数较慢,因此需要与 has_pending_signal_fast 一起使用。 + pub fn has_pending_not_masked_signal(&self) -> bool { + let sig_info = self.sig_info_irqsave(); + let blocked: SigSet = *sig_info.sig_blocked(); + let mut pending: SigSet = sig_info.sig_pending().signal(); + drop(sig_info); + pending.remove(blocked); + // log::debug!( + // "pending and not masked:{:?}, masked: {:?}", + // pending, + // blocked + // ); + let has_not_masked = !pending.is_empty(); + return has_not_masked; + } + pub fn sig_struct(&self) -> SpinLockGuard { self.sig_struct.lock_irqsave() } @@ -1135,6 +1227,17 @@ impl ProcessControlBlock { *self.restart_block.lock() = restart_block; return Err(SystemError::ERESTART_RESTARTBLOCK); } + + pub fn parent_pcb(&self) -> Option> { + self.parent_pcb.read().upgrade() + } + + pub fn is_exited(&self) -> bool { + self.sched_info + .inner_lock_read_irqsave() + .state() + .is_exited() + } } impl Drop for ProcessControlBlock { @@ -1150,6 +1253,7 @@ impl Drop for ProcessControlBlock { .retain(|pid| *pid != self.pid()); } + // log::debug!("Drop pid: {:?}", self.pid()); drop(irq_guard); } } @@ -1192,12 +1296,8 @@ impl ThreadInfo { /// 这个结构体保存进程的基本信息,主要是那些不会随着进程的运行而经常改变的信息。 #[derive(Debug)] pub struct ProcessBasicInfo { - /// 当前进程的进程组id - pgid: Pid, /// 当前进程的父进程的pid ppid: Pid, - /// 当前进程所属会话id - sid: Pid, /// 进程的名字 name: String, @@ -1214,18 +1314,14 @@ pub struct ProcessBasicInfo { impl ProcessBasicInfo { #[inline(never)] pub fn new( - pgid: Pid, ppid: Pid, - sid: Pid, name: String, cwd: String, user_vm: Option>, ) -> RwLock { let fd_table = Arc::new(RwLock::new(FileDescriptorVec::new())); return RwLock::new(Self { - pgid, ppid, - sid, name, cwd, user_vm, @@ -1233,18 +1329,10 @@ impl ProcessBasicInfo { }); } - pub fn pgid(&self) -> Pid { - return self.pgid; - } - pub fn ppid(&self) -> Pid { return self.ppid; } - pub fn sid(&self) -> Pid { - return self.sid; - } - pub fn name(&self) -> &str { return &self.name; } @@ -1494,8 +1582,8 @@ pub struct KernelStack { } impl KernelStack { - pub const SIZE: usize = 0x4000; - pub const ALIGN: usize = 0x4000; + pub const SIZE: usize = 0x8000; + pub const ALIGN: usize = 0x8000; pub fn new() -> Result { return Ok(Self { diff --git a/kernel/src/process/preempt.h b/kernel/src/process/preempt.h deleted file mode 100644 index 5987b6a8..00000000 --- a/kernel/src/process/preempt.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -extern void rs_preempt_disable(); -extern void rs_preempt_enable(); diff --git a/kernel/src/process/process.h b/kernel/src/process/process.h deleted file mode 100644 index 9695316d..00000000 --- a/kernel/src/process/process.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file process.h - * @author longjin - * @brief 进程 - * @date 2022-01-29 - * - * @copyright Copyright (c) 2022 - * - */ - -#pragma once -#include "ptrace.h" -#include -#include - -/** - * @brief 进程退出时执行的函数 - * - * @param code 返回码 - * @return ul - */ -extern ul rs_process_do_exit(ul code); - -extern int rs_current_cpu_id(); - -extern unsigned long head_stack_start; // 导出内核层栈基地址(定义在head.S) -extern ul _stack_start; -extern void ret_from_intr(void); // 导出从中断返回的函数(定义在entry.S) - -extern uint32_t rs_current_pcb_cpuid(); -extern uint32_t rs_current_pcb_pid(); -extern uint32_t rs_current_pcb_preempt_count(); -extern uint32_t rs_current_pcb_flags(); -extern uint64_t rs_current_pcb_thread_rbp(); - -#define PF_NEED_SCHED (1UL << 1) diff --git a/kernel/src/process/process_group.rs b/kernel/src/process/process_group.rs new file mode 100644 index 00000000..313285b0 --- /dev/null +++ b/kernel/src/process/process_group.rs @@ -0,0 +1,368 @@ +use super::{ + session::{Session, Sid}, + Pid, ProcessControlBlock, ProcessManager, +}; +use crate::libs::spinlock::SpinLock; +use alloc::{ + collections::BTreeMap, + sync::{Arc, Weak}, +}; +use hashbrown::HashMap; +use system_error::SystemError; + +/// 进程组ID +pub type Pgid = Pid; + +/// 系统中所有进程组 +pub static ALL_PROCESS_GROUP: SpinLock>>> = + SpinLock::new(None); + +pub struct ProcessGroup { + /// 进程组pgid + pub pgid: Pgid, + pub process_group_inner: SpinLock, +} + +pub struct PGInner { + pub processes: BTreeMap>, + pub leader: Option>, + pub session: Weak, +} + +impl PGInner { + pub fn remove_process(&mut self, pid: &Pid) { + if let Some(process) = self.processes.remove(pid) { + if let Some(leader) = &self.leader { + if Arc::ptr_eq(leader, &process) { + self.leader = None; + } + } + } + } + pub fn is_empty(&self) -> bool { + self.processes.is_empty() + } +} + +impl ProcessGroup { + pub fn new(pcb: Arc) -> Arc { + let pid = pcb.pid(); + let mut processes = BTreeMap::new(); + processes.insert(pid, pcb.clone()); + let inner = PGInner { + processes, + leader: Some(pcb), + session: Weak::new(), + }; + // log::debug!("New ProcessGroup {:?}", pid); + + Arc::new(Self { + pgid: pid, + process_group_inner: SpinLock::new(inner), + }) + } + + pub fn contains(&self, pid: Pid) -> bool { + self.process_group_inner.lock().processes.contains_key(&pid) + } + + pub fn pgid(&self) -> Pgid { + self.pgid + } + + pub fn leader(&self) -> Option> { + self.process_group_inner.lock().leader.clone() + } + + pub fn session(&self) -> Option> { + // log::debug!("Before lock"); + let guard = self.process_group_inner.lock(); + // log::debug!("Locking"); + let session = guard.session.upgrade(); + drop(guard); + // log::debug!("After lock"); + return session; + } + + pub fn broadcast(&self) { + unimplemented!("broadcast not supported yet"); + } + + pub fn sid(&self) -> Sid { + if let Some(session) = self.session() { + return session.sid(); + } + Sid::from(0) + } +} + +impl Drop for ProcessGroup { + fn drop(&mut self) { + let mut inner = self.process_group_inner.lock(); + + if let Some(leader) = inner.leader.take() { + // 组长进程仍然在进程列表中,不应该直接销毁 + if inner.processes.contains_key(&leader.pid()) { + inner.leader = Some(leader); + } + } + + inner.processes.clear(); + + if let Some(session) = inner.session.upgrade() { + let mut session_inner = session.session_inner.lock(); + session_inner.process_groups.remove(&self.pgid); + + if session_inner.should_destory() { + ProcessManager::remove_session(session.sid()); + } + } + // log::debug!("Dropping pg {:?}", self.pgid.clone()); + } +} + +impl ProcessManager { + /// 根据pgid获取进程组 + /// + /// ## 参数 + /// + /// - `pgid` : 进程组的pgid + /// + /// ## 返回值 + /// + /// 如果找到了对应的进程组,那么返回该进程组,否则返回None + pub fn find_process_group(pgid: Pgid) -> Option> { + return ALL_PROCESS_GROUP + .lock_irqsave() + .as_ref()? + .get(&pgid) + .cloned(); + } + + /// 向系统中添加一个进程组 + /// + /// ## 参数 + /// + /// - `pg` : Arc + /// + /// ## 返回值 + /// + /// 无 + pub fn add_process_group(pg: Arc) { + ALL_PROCESS_GROUP + .lock_irqsave() + .as_mut() + .unwrap() + .insert(pg.pgid(), pg.clone()); + // log::debug!("New ProcessGroup added, pgid: {:?}", pg.pgid()); + } + + /// 删除一个进程组 + pub fn remove_process_group(pgid: Pgid) { + // log::debug!("Removing pg {:?}", pgid.clone()); + let mut all_groups = ALL_PROCESS_GROUP.lock_irqsave(); + if let Some(pg) = all_groups.as_mut().unwrap().remove(&pgid) { + // log::debug!("count: {:?}", Arc::strong_count(&pg)); + if Arc::strong_count(&pg) <= 2 { + // 这里 Arc 计数小于等于 2,意味着它只有在 all_groups 里有一个引用,移除后会自动释放 + drop(pg); + } + } + } + + // 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/exit.c#345 + pub fn is_current_pgrp_orphaned() -> bool { + let current_pcb = ProcessManager::current_pcb(); + let sid = current_pcb.sid(); + let process_group = current_pcb.process_group(); + if let Some(pg) = process_group { + for process in pg.process_group_inner.lock().processes.values() { + if let Some(real_parent) = process.real_parent_pcb.read().clone().upgrade() { + //todo 添加判断: 1.是否被忽略 2.是否已经退出(线程组是否为空) + if real_parent.pid == Pid(1) || process.is_exited() { + log::debug!("is_current_pgrp_orphaned: real_parent is init or exited"); + continue; + } + let real_parent_pg = real_parent.process_group().unwrap(); + if real_parent_pg.pgid() != pg.pgid() && real_parent_pg.sid() == sid { + return false; + } + } + } + } + true + } +} + +impl ProcessControlBlock { + #[inline(always)] + pub fn pgid(&self) -> Pgid { + if let Some(process_group) = self.process_group.lock().upgrade() { + process_group.pgid() + } else { + Pgid::from(0) + } + } + + #[inline(always)] + pub fn process_group(&self) -> Option> { + self.process_group.lock().upgrade() + } + + pub fn set_process_group(&self, pg: &Arc) { + if let Some(pcb) = self.self_ref.upgrade() { + *pcb.process_group.lock() = Arc::downgrade(pg); + // log::debug!("pid: {:?} set pgid: {:?}", self.pid(), pg.pgid()); + } + } + + pub fn is_process_group_leader(&self) -> bool { + if let Some(pcb) = self.self_ref.upgrade() { + let pg = self.process_group().unwrap(); + if let Some(leader) = pg.leader() { + return Arc::ptr_eq(&pcb, &leader); + } + } + + return false; + } + + /// 将进程加入到指定pgid的进程组中(无论该进程组是否已经存在) + /// + /// 如果进程组已经存在,则将进程加入到该进程组中 + /// 如果进程组不存在,则创建一个新的进程组,并将进程加入到该进程组中 + /// + /// ## 参数 + /// `pgid` : 目标进程组的pgid + /// + /// ## 返回值 + /// 无 + pub fn join_other_group(&self, pgid: Pgid) -> Result<(), SystemError> { + // if let Some(pcb) = self.self_ref.upgrade() { + if self.pgid() == pgid { + return Ok(()); + } + if self.is_session_leader() { + // 会话领导者不能加入其他进程组 + return Err(SystemError::EPERM); + } + if let Some(pg) = ProcessManager::find_process_group(pgid) { + let session = self.session().unwrap(); + if !session.contains_process_group(&pg) { + // 进程组和进程应该属于同一个会话 + return Err(SystemError::EPERM); + } + self.join_specified_group(&pg)?; + } else { + if pgid != self.pid() { + // 进程组不存在,只能加入自己的进程组 + return Err(SystemError::EPERM); + } + self.join_new_group()?; + } + // } + + Ok(()) + } + + /// 将进程加入到新创建的进程组中 + fn join_new_group(&self) -> Result<(), SystemError> { + let session = self.session().unwrap(); + let mut self_pg_mut = self.process_group.lock(); + + if let Some(old_pg) = self_pg_mut.upgrade() { + let mut old_pg_inner = old_pg.process_group_inner.lock(); + let mut session_inner = session.session_inner.lock(); + old_pg_inner.remove_process(&self.pid); + *self_pg_mut = Weak::new(); + + if old_pg_inner.is_empty() { + ProcessManager::remove_process_group(old_pg.pgid()); + assert!(session_inner.process_groups.contains_key(&old_pg.pgid())); + session_inner.process_groups.remove(&old_pg.pgid()); + } + } + + let pcb = self.self_ref.upgrade().unwrap(); + let new_pg = ProcessGroup::new(pcb); + let mut new_pg_inner = new_pg.process_group_inner.lock(); + let mut session_inner = session.session_inner.lock(); + + *self_pg_mut = Arc::downgrade(&new_pg); + ProcessManager::add_process_group(new_pg.clone()); + + new_pg_inner.session = Arc::downgrade(&session); + session_inner + .process_groups + .insert(new_pg.pgid, new_pg.clone()); + + Ok(()) + } + + /// 将进程加入到指定的进程组中 + fn join_specified_group(&self, group: &Arc) -> Result<(), SystemError> { + let mut self_group = self.process_group.lock(); + + let mut group_inner = if let Some(old_pg) = self_group.upgrade() { + let (mut old_pg_inner, group_inner) = match old_pg.pgid().cmp(&group.pgid()) { + core::cmp::Ordering::Equal => return Ok(()), + core::cmp::Ordering::Less => ( + old_pg.process_group_inner.lock(), + group.process_group_inner.lock(), + ), + core::cmp::Ordering::Greater => { + let group_inner = group.process_group_inner.lock(); + let old_pg_inner = old_pg.process_group_inner.lock(); + (old_pg_inner, group_inner) + } + }; + old_pg_inner.remove_process(&self.pid); + *self_group = Weak::new(); + + if old_pg_inner.is_empty() { + ProcessManager::remove_process_group(old_pg.pgid()); + } + group_inner + } else { + group.process_group_inner.lock() + }; + + let pcb = self.self_ref.upgrade().unwrap(); + group_inner.processes.insert(self.pid, pcb); + *self_group = Arc::downgrade(group); + Ok(()) + } + + /// ### 清除自身的进程组以及会话引用(如果有的话),这个方法只能在进程退出时调用 + pub fn clear_pg_and_session_reference(&self) { + if let Some(pg) = self.process_group() { + let mut pg_inner = pg.process_group_inner.lock(); + pg_inner.remove_process(&self.pid()); + + if pg_inner.is_empty() { + // 如果进程组没有任何进程了,就删除该进程组 + ProcessManager::remove_process_group(pg.pgid()); + // log::debug!("clear_pg_reference: {:?}", pg.pgid()); + + if let Some(session) = pg_inner.session.upgrade() { + let mut session_inner = session.session_inner.lock(); + session_inner.remove_process_group(&pg.pgid()); + if session_inner.is_empty() { + // 如果会话没有任何进程组了,就删除该会话 + ProcessManager::remove_session(session.sid()); + // log::debug!("clear_pg_reference: {:?}", session.sid()); + } + } + } + } + + if let Some(session) = self.session() { + let mut session_inner = session.session_inner.lock(); + if let Some(leader) = &session_inner.leader { + if Arc::ptr_eq(leader, &self.self_ref.upgrade().unwrap()) { + session_inner.leader = None; + } + } + } + } +} diff --git a/kernel/src/process/ptrace.h b/kernel/src/process/ptrace.h deleted file mode 100644 index 7e26e4d6..00000000 --- a/kernel/src/process/ptrace.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __PTRACE_H__ - -#define __PTRACE_H__ - -struct pt_regs -{ - unsigned long r15; - unsigned long r14; - unsigned long r13; - unsigned long r12; - unsigned long r11; - unsigned long r10; - unsigned long r9; - unsigned long r8; - unsigned long rbx; - unsigned long rcx; - unsigned long rdx; - unsigned long rsi; - unsigned long rdi; - unsigned long rbp; - unsigned long ds; - unsigned long es; - unsigned long rax; - unsigned long func; - unsigned long errcode; - unsigned long rip; - unsigned long cs; - unsigned long rflags; - unsigned long rsp; - unsigned long ss; -}; - -/** - * @brief 判断pt_regs是否来自用户态 - * - * @param regs - * @return __always_inline - */ -static inline int user_mode(struct pt_regs *regs) -{ - return !!(regs->cs & 3); -} - -#endif diff --git a/kernel/src/process/session.rs b/kernel/src/process/session.rs new file mode 100644 index 00000000..3aeeb6b0 --- /dev/null +++ b/kernel/src/process/session.rs @@ -0,0 +1,218 @@ +use super::{ + process_group::{Pgid, ProcessGroup}, + Pid, ProcessControlBlock, ProcessManager, +}; +use crate::libs::spinlock::SpinLock; +use alloc::{ + collections::BTreeMap, + sync::{Arc, Weak}, +}; +use hashbrown::HashMap; +use system_error::SystemError; + +/// 会话SID +pub type Sid = Pid; + +/// 系统中所有会话 +pub static ALL_SESSION: SpinLock>>> = SpinLock::new(None); + +pub struct Session { + pub sid: Sid, + pub session_inner: SpinLock, +} + +pub struct SessionInner { + pub process_groups: BTreeMap>, + pub leader: Option>, +} + +impl SessionInner { + pub fn is_empty(&self) -> bool { + self.process_groups.is_empty() + } + pub fn remove_process_group(&mut self, pgid: &Pgid) { + self.process_groups.remove(pgid); + } + pub fn remove_process(&mut self, pcb: &Arc) { + if let Some(leader) = &self.leader { + if Arc::ptr_eq(leader, pcb) { + self.leader = None; + } + } + } + pub fn should_destory(&self) -> bool { + self.process_groups.is_empty() + } +} + +impl Session { + pub fn new(group: Arc) -> Arc { + let sid = group.pgid; + let mut process_groups = BTreeMap::new(); + process_groups.insert(group.pgid, group.clone()); + let inner = SessionInner { + process_groups, + leader: None, + }; + // log::debug!("New Session {:?}", sid); + Arc::new(Self { + sid, + session_inner: SpinLock::new(inner), + }) + } + + pub fn sid(&self) -> Sid { + self.sid + } + + pub fn leader(&self) -> Option> { + self.session_inner.lock().leader.clone() + } + + // pub fn contains_process_group(&self, pgid: Pgid) -> bool { + // self.session_inner.lock().process_groups.contains_key(&pgid) + // } + + pub fn contains_process_group(&self, process_group: &Arc) -> bool { + self.session_inner + .lock() + .process_groups + .contains_key(&process_group.pgid) + } +} + +impl Drop for Session { + fn drop(&mut self) { + let mut session_inner = self.session_inner.lock(); + session_inner.process_groups.clear(); + session_inner.leader = None; + // log::debug!("Dropping session: {:?}", self.sid()); + } +} + +impl ProcessManager { + /// 根据sid获取会话 + /// + /// ## 参数 + /// + /// - `sid` : 会话的sid + /// + /// ## 返回值 + /// + /// 如果找到了对应的会话,那么返回该会话,否则返回None + pub fn find_session(sid: Sid) -> Option> { + return ALL_SESSION.lock_irqsave().as_ref()?.get(&sid).cloned(); + } + + /// 向系统中添加一个会话 + /// + /// ## 参数 + /// + /// - `session` : Arc + /// + /// ## 返回值 + /// + /// 无 + pub fn add_session(session: Arc) { + ALL_SESSION + .lock_irqsave() + .as_mut() + .unwrap() + .insert(session.sid(), session.clone()); + // log::debug!("New Session added, sid: {:?}", session.sid()); + } + + pub fn remove_session(sid: Sid) { + // log::debug!("Removing session: {:?}", sid.clone()); + let mut all_sessions = ALL_SESSION.lock_irqsave(); + if let Some(session) = all_sessions.as_mut().unwrap().remove(&sid) { + if Arc::strong_count(&session) <= 2 { + // 这里 Arc 计数为 1,意味着它只有在 all_groups 里有一个引用,移除后会自动释放 + drop(session); + } + } + } +} + +impl ProcessControlBlock { + pub fn session(&self) -> Option> { + let pg = self.process_group()?; + pg.session() + } + + pub fn is_session_leader(&self) -> bool { + if let Some(pcb) = self.self_ref.upgrade() { + let session = pcb.session().unwrap(); + if let Some(leader) = session.leader() { + return Arc::ptr_eq(&pcb, &leader); + } + } + + return false; + } + + /// 将进程移动到新会话中 + /// 如果进程已经是会话领导者,则返回当前会话 + /// 如果不是,则主动创建一个新会话,并将进程移动到新会话中,返回新会话 + /// + /// ## 返回值 + /// + /// 新会话 + pub fn go_to_new_session(&self) -> Result, SystemError> { + if self.is_session_leader() { + return Ok(self.session().unwrap()); + } + + if self.is_process_group_leader() { + return Err(SystemError::EPERM); + } + + let session = self.session().unwrap(); + + let mut self_group = self.process_group.lock(); + if ProcessManager::find_session(self.pid()).is_some() { + return Err(SystemError::EPERM); + } + if ProcessManager::find_process_group(self.pid).is_some() { + return Err(SystemError::EPERM); + } + if let Some(old_pg) = self_group.upgrade() { + let mut old_pg_inner = old_pg.process_group_inner.lock(); + let mut session_inner = session.session_inner.lock(); + old_pg_inner.remove_process(&self.pid); + *self_group = Weak::new(); + + if old_pg_inner.is_empty() { + ProcessManager::remove_process_group(old_pg.pgid()); + assert!(session_inner.process_groups.contains_key(&old_pg.pgid())); + session_inner.process_groups.remove(&old_pg.pgid()); + if session_inner.is_empty() { + ProcessManager::remove_session(session.sid()); + } + } + } + + let pcb = self.self_ref.upgrade().unwrap(); + let new_pg = ProcessGroup::new(pcb.clone()); + *self_group = Arc::downgrade(&new_pg); + ProcessManager::add_process_group(new_pg.clone()); + + let new_session = Session::new(new_pg.clone()); + let mut new_pg_inner = new_pg.process_group_inner.lock(); + new_pg_inner.session = Arc::downgrade(&new_session); + new_session.session_inner.lock().leader = Some(pcb.clone()); + ProcessManager::add_session(new_session.clone()); + + let mut session_inner = session.session_inner.lock(); + session_inner.remove_process(&pcb); + + Ok(new_session) + } + + pub fn sid(&self) -> Sid { + if let Some(session) = self.session() { + return session.sid(); + } + return Sid::new(1); + } +} diff --git a/kernel/src/process/syscall.rs b/kernel/src/process/syscall.rs deleted file mode 100644 index ddcb9620..00000000 --- a/kernel/src/process/syscall.rs +++ /dev/null @@ -1,613 +0,0 @@ -use core::ffi::c_void; - -use alloc::{ - ffi::CString, - string::{String, ToString}, - sync::Arc, - vec::Vec, -}; -use log::error; -use system_error::SystemError; - -use super::{ - abi::WaitOption, - cred::{Kgid, Kuid}, - exec::{load_binary_file, ExecParam, ExecParamFlags}, - exit::kernel_wait4, - fork::{CloneFlags, KernelCloneArgs}, - resource::{RLimit64, RLimitID, RUsage, RUsageWho}, - KernelStack, Pid, ProcessManager, -}; -use crate::{ - arch::{interrupt::TrapFrame, CurrentIrqArch, MMArch}, - exception::InterruptArch, - filesystem::{ - procfs::procfs_register_pid, - vfs::{file::FileDescriptorVec, MAX_PATHLEN}, - }, - mm::{ - ucontext::{AddressSpace, UserStack}, - verify_area, MemoryManagementArch, VirtAddr, - }, - process::ProcessControlBlock, - sched::completion::Completion, - syscall::{ - user_access::{check_and_clone_cstr, check_and_clone_cstr_array, UserBufferWriter}, - Syscall, - }, -}; - -//参考资料:https://code.dragonos.org.cn/xref/linux-6.1.9/include/uapi/linux/utsname.h#17 -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct PosixOldUtsName { - pub sysname: [u8; 65], - pub nodename: [u8; 65], - pub release: [u8; 65], - pub version: [u8; 65], - pub machine: [u8; 65], -} - -impl PosixOldUtsName { - pub fn new() -> Self { - const SYS_NAME: &[u8] = b"DragonOS"; - const NODENAME: &[u8] = b"DragonOS"; - const RELEASE: &[u8] = env!("CARGO_PKG_VERSION").as_bytes(); - const VERSION: &[u8] = env!("CARGO_PKG_VERSION").as_bytes(); - - #[cfg(target_arch = "x86_64")] - const MACHINE: &[u8] = b"x86_64"; - - #[cfg(target_arch = "aarch64")] - const MACHINE: &[u8] = b"aarch64"; - - #[cfg(target_arch = "riscv64")] - const MACHINE: &[u8] = b"riscv64"; - - let mut r = Self { - sysname: [0; 65], - nodename: [0; 65], - release: [0; 65], - version: [0; 65], - machine: [0; 65], - }; - - r.sysname[0..SYS_NAME.len()].copy_from_slice(SYS_NAME); - r.nodename[0..NODENAME.len()].copy_from_slice(NODENAME); - r.release[0..RELEASE.len()].copy_from_slice(RELEASE); - r.version[0..VERSION.len()].copy_from_slice(VERSION); - r.machine[0..MACHINE.len()].copy_from_slice(MACHINE); - - return r; - } -} - -impl Syscall { - pub fn fork(frame: &TrapFrame) -> Result { - ProcessManager::fork(frame, CloneFlags::empty()).map(|pid| pid.into()) - } - - pub fn vfork(frame: &TrapFrame) -> Result { - // 由于Linux vfork需要保证子进程先运行(除非子进程调用execve或者exit), - // 而我们目前没有实现这个特性,所以暂时使用fork代替vfork(linux文档表示这样也是也可以的) - Self::fork(frame) - - // 下面是以前的实现,除非我们实现了子进程先运行的特性,否则不要使用,不然会导致父进程数据损坏 - // ProcessManager::fork( - // frame, - // CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL, - // ) - // .map(|pid| pid.into()) - } - - pub fn execve( - path: *const u8, - argv: *const *const u8, - envp: *const *const u8, - frame: &mut TrapFrame, - ) -> Result<(), SystemError> { - // debug!( - // "execve path: {:?}, argv: {:?}, envp: {:?}\n", - // path, - // argv, - // envp - // ); - // debug!( - // "before execve: strong count: {}", - // Arc::strong_count(&ProcessManager::current_pcb()) - // ); - - if path.is_null() { - return Err(SystemError::EINVAL); - } - - let x = || { - let path: CString = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; - let argv: Vec = check_and_clone_cstr_array(argv)?; - let envp: Vec = check_and_clone_cstr_array(envp)?; - Ok((path, argv, envp)) - }; - let (path, argv, envp) = x().inspect_err(|e: &SystemError| { - error!("Failed to execve: {:?}", e); - })?; - - let path = path.into_string().map_err(|_| SystemError::EINVAL)?; - ProcessManager::current_pcb() - .basic_mut() - .set_name(ProcessControlBlock::generate_name(&path, &argv)); - - Self::do_execve(path, argv, envp, frame)?; - - // 关闭设置了O_CLOEXEC的文件描述符 - let fd_table = ProcessManager::current_pcb().fd_table(); - fd_table.write().close_on_exec(); - // debug!( - // "after execve: strong count: {}", - // Arc::strong_count(&ProcessManager::current_pcb()) - // ); - - return Ok(()); - } - - pub fn do_execve( - path: String, - argv: Vec, - envp: Vec, - regs: &mut TrapFrame, - ) -> Result<(), SystemError> { - let address_space = AddressSpace::new(true).expect("Failed to create new address space"); - // debug!("to load binary file"); - let mut param = ExecParam::new(path.as_str(), address_space.clone(), ExecParamFlags::EXEC)?; - let old_vm = do_execve_switch_user_vm(address_space.clone()); - - // 加载可执行文件 - let load_result = load_binary_file(&mut param).inspect_err(|_| { - if let Some(old_vm) = old_vm { - do_execve_switch_user_vm(old_vm); - } - })?; - - // debug!("load binary file done"); - // debug!("argv: {:?}, envp: {:?}", argv, envp); - param.init_info_mut().args = argv; - param.init_info_mut().envs = envp; - - // 把proc_init_info写到用户栈上 - let mut ustack_message = unsafe { - address_space - .write() - .user_stack_mut() - .expect("No user stack found") - .clone_info_only() - }; - let (user_sp, argv_ptr) = unsafe { - param - .init_info() - .push_at( - // address_space - // .write() - // .user_stack_mut() - // .expect("No user stack found"), - &mut ustack_message, - ) - .expect("Failed to push proc_init_info to user stack") - }; - address_space.write().user_stack = Some(ustack_message); - - Self::arch_do_execve(regs, ¶m, &load_result, user_sp, argv_ptr) - } - - pub fn wait4( - pid: i64, - wstatus: *mut i32, - options: i32, - rusage: *mut c_void, - ) -> Result { - let options = WaitOption::from_bits(options as u32).ok_or(SystemError::EINVAL)?; - - let wstatus_buf = if wstatus.is_null() { - None - } else { - Some(UserBufferWriter::new( - wstatus, - core::mem::size_of::(), - true, - )?) - }; - - let mut tmp_rusage = if rusage.is_null() { - None - } else { - Some(RUsage::default()) - }; - - let r = kernel_wait4(pid, wstatus_buf, options, tmp_rusage.as_mut())?; - - if !rusage.is_null() { - let mut rusage_buf = UserBufferWriter::new::( - rusage as *mut RUsage, - core::mem::size_of::(), - true, - )?; - rusage_buf.copy_one_to_user(&tmp_rusage.unwrap(), 0)?; - } - return Ok(r); - } - - /// # 退出进程 - /// - /// ## 参数 - /// - /// - status: 退出状态 - pub fn exit(status: usize) -> ! { - ProcessManager::exit(status); - } - - /// @brief 获取当前进程的pid - pub fn getpid() -> Result { - let current_pcb = ProcessManager::current_pcb(); - // if let Some(pid_ns) = ¤t_pcb.get_nsproxy().read().pid_namespace { - // // 获取该进程在命名空间中的 PID - // return Ok(current_pcb.pid_strcut().read().numbers[pid_ns.level].nr); - // // 返回命名空间中的 PID - // } - // 默认返回 tgid - Ok(current_pcb.tgid()) - } - - /// @brief 获取指定进程的pgid - /// - /// @param pid 指定一个进程号 - /// - /// @return 成功,指定进程的进程组id - /// @return 错误,不存在该进程 - pub fn getpgid(mut pid: Pid) -> Result { - if pid == Pid(0) { - let current_pcb = ProcessManager::current_pcb(); - pid = current_pcb.pid(); - } - let target_proc = ProcessManager::find(pid).ok_or(SystemError::ESRCH)?; - return Ok(target_proc.basic().pgid()); - } - /// @brief 获取当前进程的父进程id - /// - /// 若为initproc则ppid设置为0 - pub fn getppid() -> Result { - let current_pcb = ProcessManager::current_pcb(); - return Ok(current_pcb.basic().ppid()); - } - - pub fn clone( - current_trapframe: &TrapFrame, - clone_args: KernelCloneArgs, - ) -> Result { - let flags = clone_args.flags; - - let vfork = Arc::new(Completion::new()); - - if flags.contains(CloneFlags::CLONE_PIDFD) - && flags.contains(CloneFlags::CLONE_PARENT_SETTID) - { - return Err(SystemError::EINVAL); - } - - let current_pcb = ProcessManager::current_pcb(); - let new_kstack = KernelStack::new()?; - let name = current_pcb.basic().name().to_string(); - let pcb = ProcessControlBlock::new(name, new_kstack); - // 克隆pcb - ProcessManager::copy_process(¤t_pcb, &pcb, clone_args, current_trapframe)?; - ProcessManager::add_pcb(pcb.clone()); - - // 向procfs注册进程 - procfs_register_pid(pcb.pid()).unwrap_or_else(|e| { - panic!( - "fork: Failed to register pid to procfs, pid: [{:?}]. Error: {:?}", - pcb.pid(), - e - ) - }); - - if flags.contains(CloneFlags::CLONE_VFORK) { - pcb.thread.write_irqsave().vfork_done = Some(vfork.clone()); - } - - if pcb.thread.read_irqsave().set_child_tid.is_some() { - let addr = pcb.thread.read_irqsave().set_child_tid.unwrap(); - let mut writer = - UserBufferWriter::new(addr.as_ptr::(), core::mem::size_of::(), true)?; - writer.copy_one_to_user(&(pcb.pid().data() as i32), 0)?; - } - - ProcessManager::wakeup(&pcb).unwrap_or_else(|e| { - panic!( - "fork: Failed to wakeup new process, pid: [{:?}]. Error: {:?}", - pcb.pid(), - e - ) - }); - - if flags.contains(CloneFlags::CLONE_VFORK) { - // 等待子进程结束或者exec; - vfork.wait_for_completion_interruptible()?; - } - - return Ok(pcb.pid().0); - } - - /// 设置线程地址 - pub fn set_tid_address(ptr: usize) -> Result { - verify_area(VirtAddr::new(ptr), core::mem::size_of::()) - .map_err(|_| SystemError::EFAULT)?; - - let pcb = ProcessManager::current_pcb(); - pcb.thread.write_irqsave().clear_child_tid = Some(VirtAddr::new(ptr)); - Ok(pcb.pid.0) - } - - pub fn gettid() -> Result { - let pcb = ProcessManager::current_pcb(); - Ok(pcb.pid) - } - - pub fn getuid() -> Result { - let pcb = ProcessManager::current_pcb(); - return Ok(pcb.cred.lock().uid.data()); - } - - pub fn getgid() -> Result { - let pcb = ProcessManager::current_pcb(); - return Ok(pcb.cred.lock().gid.data()); - } - - pub fn geteuid() -> Result { - let pcb = ProcessManager::current_pcb(); - return Ok(pcb.cred.lock().euid.data()); - } - - pub fn getegid() -> Result { - let pcb = ProcessManager::current_pcb(); - return Ok(pcb.cred.lock().egid.data()); - } - - pub fn setuid(uid: usize) -> Result { - let pcb = ProcessManager::current_pcb(); - let mut guard = pcb.cred.lock(); - - if guard.uid.data() == 0 { - guard.setuid(uid); - guard.seteuid(uid); - guard.setsuid(uid); - } else if uid == guard.uid.data() || uid == guard.suid.data() { - guard.seteuid(uid); - } else { - return Err(SystemError::EPERM); - } - - return Ok(0); - } - - pub fn setgid(gid: usize) -> Result { - let pcb = ProcessManager::current_pcb(); - let mut guard = pcb.cred.lock(); - - if guard.egid.data() == 0 { - guard.setgid(gid); - guard.setegid(gid); - guard.setsgid(gid); - guard.setfsgid(gid); - } else if guard.gid.data() == gid || guard.sgid.data() == gid { - guard.setegid(gid); - guard.setfsgid(gid); - } else { - return Err(SystemError::EPERM); - } - - return Ok(0); - } - - pub fn seteuid(euid: usize) -> Result { - let pcb = ProcessManager::current_pcb(); - let mut guard = pcb.cred.lock(); - - if euid == usize::MAX || (euid == guard.euid.data() && euid == guard.fsuid.data()) { - return Ok(0); - } - - if euid != usize::MAX { - guard.seteuid(euid); - } - - let euid = guard.euid.data(); - guard.setfsuid(euid); - - return Ok(0); - } - - pub fn setegid(egid: usize) -> Result { - let pcb = ProcessManager::current_pcb(); - let mut guard = pcb.cred.lock(); - - if egid == usize::MAX || (egid == guard.egid.data() && egid == guard.fsgid.data()) { - return Ok(0); - } - - if egid != usize::MAX { - guard.setegid(egid); - } - - let egid = guard.egid.data(); - guard.setfsgid(egid); - - return Ok(0); - } - - pub fn setfsuid(fsuid: usize) -> Result { - let fsuid = Kuid::new(fsuid); - - let pcb = ProcessManager::current_pcb(); - let mut guard = pcb.cred.lock(); - let old_fsuid = guard.fsuid; - - if fsuid == guard.uid || fsuid == guard.euid || fsuid == guard.suid { - guard.setfsuid(fsuid.data()); - } - - Ok(old_fsuid.data()) - } - - pub fn setfsgid(fsgid: usize) -> Result { - let fsgid = Kgid::new(fsgid); - - let pcb = ProcessManager::current_pcb(); - let mut guard = pcb.cred.lock(); - let old_fsgid = guard.fsgid; - - if fsgid == guard.gid || fsgid == guard.egid || fsgid == guard.sgid { - guard.setfsgid(fsgid.data()); - } - - Ok(old_fsgid.data()) - } - - pub fn get_rusage(who: i32, rusage: *mut RUsage) -> Result { - let who = RUsageWho::try_from(who)?; - let mut writer = UserBufferWriter::new(rusage, core::mem::size_of::(), true)?; - let pcb = ProcessManager::current_pcb(); - let rusage = pcb.get_rusage(who).ok_or(SystemError::EINVAL)?; - - let ubuf = writer.buffer::(0).unwrap(); - ubuf.copy_from_slice(&[rusage]); - - return Ok(0); - } - - /// # 设置资源限制 - /// - /// TODO: 目前暂时不支持设置资源限制,只提供读取默认值的功能 - /// - /// ## 参数 - /// - /// - pid: 进程号 - /// - resource: 资源类型 - /// - new_limit: 新的资源限制 - /// - old_limit: 旧的资源限制 - /// - /// ## 返回值 - /// - /// - 成功,0 - /// - 如果old_limit不为NULL,则返回旧的资源限制到old_limit - /// - pub fn prlimit64( - _pid: Pid, - resource: usize, - _new_limit: *const RLimit64, - old_limit: *mut RLimit64, - ) -> Result { - let resource = RLimitID::try_from(resource)?; - let mut writer = None; - - if !old_limit.is_null() { - writer = Some(UserBufferWriter::new( - old_limit, - core::mem::size_of::(), - true, - )?); - } - - match resource { - RLimitID::Stack => { - if let Some(mut writer) = writer { - let mut rlimit = writer.buffer::(0).unwrap()[0]; - rlimit.rlim_cur = UserStack::DEFAULT_USER_STACK_SIZE as u64; - rlimit.rlim_max = UserStack::DEFAULT_USER_STACK_SIZE as u64; - } - return Ok(0); - } - - RLimitID::Nofile => { - if let Some(mut writer) = writer { - let mut rlimit = writer.buffer::(0).unwrap()[0]; - rlimit.rlim_cur = FileDescriptorVec::PROCESS_MAX_FD as u64; - rlimit.rlim_max = FileDescriptorVec::PROCESS_MAX_FD as u64; - } - return Ok(0); - } - - RLimitID::As | RLimitID::Rss => { - if let Some(mut writer) = writer { - let mut rlimit = writer.buffer::(0).unwrap()[0]; - rlimit.rlim_cur = MMArch::USER_END_VADDR.data() as u64; - rlimit.rlim_max = MMArch::USER_END_VADDR.data() as u64; - } - return Ok(0); - } - - _ => { - return Err(SystemError::ENOSYS); - } - } - } - - pub fn uname(name: *mut PosixOldUtsName) -> Result { - let mut writer = - UserBufferWriter::new(name, core::mem::size_of::(), true)?; - writer.copy_one_to_user(&PosixOldUtsName::new(), 0)?; - - return Ok(0); - } -} - -/// 切换用户虚拟内存空间 -/// -/// 该函数用于在执行系统调用 `execve` 时切换用户进程的虚拟内存空间。 -/// -/// # 参数 -/// - `new_vm`: 新的用户地址空间,类型为 `Arc`。 -/// -/// # 返回值 -/// - 返回旧的用户地址空间的引用,类型为 `Option>`。 -/// -/// # 错误处理 -/// 如果地址空间切换失败,函数会触发断言失败,并输出错误信息。 -fn do_execve_switch_user_vm(new_vm: Arc) -> Option> { - // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。 - let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - let pcb = ProcessManager::current_pcb(); - // log::debug!( - // "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n", - // pcb.pid(), - // path, - // argv, - // envp - // ); - - let mut basic_info = pcb.basic_mut(); - // 暂存原本的用户地址空间的引用(因为如果在切换页表之前释放了它,可能会造成内存use after free) - let old_address_space = basic_info.user_vm(); - - // 在pcb中原来的用户地址空间 - unsafe { - basic_info.set_user_vm(None); - } - // 创建新的地址空间并设置为当前地址空间 - unsafe { - basic_info.set_user_vm(Some(new_vm.clone())); - } - - // to avoid deadlock - drop(basic_info); - - assert!( - AddressSpace::is_current(&new_vm), - "Failed to set address space" - ); - // debug!("Switch to new address space"); - - // 切换到新的用户地址空间 - unsafe { new_vm.read().user_mapper.utable.make_current() }; - - drop(irq_guard); - - old_address_space -} diff --git a/kernel/src/process/syscall/mod.rs b/kernel/src/process/syscall/mod.rs new file mode 100644 index 00000000..7d3dd9ce --- /dev/null +++ b/kernel/src/process/syscall/mod.rs @@ -0,0 +1,81 @@ +mod sys_clone; +mod sys_execve; +mod sys_exit; +mod sys_exit_group; +mod sys_get_rusage; +mod sys_getegid; +mod sys_geteuid; +mod sys_getgid; +mod sys_getpgid; +mod sys_getpid; +mod sys_getppid; +mod sys_getsid; +mod sys_gettid; +mod sys_getuid; +mod sys_prlimit64; +mod sys_set_tid_address; +mod sys_setfsgid; +mod sys_setfsuid; +mod sys_setgid; +mod sys_setpgid; +mod sys_setresgid; +mod sys_setresuid; +mod sys_setsid; +mod sys_setuid; +mod sys_uname; +mod sys_wait4; + +#[cfg(target_arch = "x86_64")] +mod sys_fork; +#[cfg(target_arch = "x86_64")] +mod sys_getrlimit; +#[cfg(target_arch = "x86_64")] +mod sys_vfork; + +//参考资料:https://code.dragonos.org.cn/xref/linux-6.1.9/include/uapi/linux/utsname.h#17 +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct PosixOldUtsName { + pub sysname: [u8; 65], + pub nodename: [u8; 65], + pub release: [u8; 65], + pub version: [u8; 65], + pub machine: [u8; 65], +} + +impl PosixOldUtsName { + pub fn new() -> Self { + const SYS_NAME: &[u8] = b"Linux"; + const NODENAME: &[u8] = b"DragonOS"; + const RELEASE: &[u8] = b"5.19.0"; + const VERSION: &[u8] = b"5.19.0"; + + #[cfg(target_arch = "x86_64")] + const MACHINE: &[u8] = b"x86_64"; + + #[cfg(target_arch = "aarch64")] + const MACHINE: &[u8] = b"aarch64"; + + #[cfg(target_arch = "riscv64")] + const MACHINE: &[u8] = b"riscv64"; + + #[cfg(target_arch = "loongarch64")] + const MACHINE: &[u8] = b"longarch64"; + + let mut r = Self { + sysname: [0; 65], + nodename: [0; 65], + release: [0; 65], + version: [0; 65], + machine: [0; 65], + }; + + r.sysname[0..SYS_NAME.len()].copy_from_slice(SYS_NAME); + r.nodename[0..NODENAME.len()].copy_from_slice(NODENAME); + r.release[0..RELEASE.len()].copy_from_slice(RELEASE); + r.version[0..VERSION.len()].copy_from_slice(VERSION); + r.machine[0..MACHINE.len()].copy_from_slice(MACHINE); + + return r; + } +} diff --git a/kernel/src/process/syscall/sys_clone.rs b/kernel/src/process/syscall/sys_clone.rs new file mode 100644 index 00000000..67bf1077 --- /dev/null +++ b/kernel/src/process/syscall/sys_clone.rs @@ -0,0 +1,128 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_CLONE; +use crate::filesystem::procfs::procfs_register_pid; +use crate::mm::{verify_area, VirtAddr}; +use crate::process::fork::{CloneFlags, KernelCloneArgs}; +use crate::process::{KernelStack, ProcessControlBlock, ProcessManager}; +use crate::sched::completion::Completion; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use crate::syscall::user_access::UserBufferWriter; +use alloc::vec::Vec; +use alloc::{string::ToString, sync::Arc}; +use system_error::SystemError; + +pub struct SysClone; + +impl SysClone { + fn parent_tid(args: &[usize]) -> VirtAddr { + VirtAddr::new(args[2]) + } + + fn child_tid(args: &[usize]) -> VirtAddr { + VirtAddr::new(args[3]) + } + + fn flags(args: &[usize]) -> CloneFlags { + CloneFlags::from_bits_truncate(args[0] as u64) + } + + fn stack(args: &[usize]) -> usize { + args[1] + } + + fn tls(args: &[usize]) -> usize { + args[4] + } +} + +impl Syscall for SysClone { + fn num_args(&self) -> usize { + 5 + } + + fn handle(&self, args: &[usize], frame: &mut TrapFrame) -> Result { + let parent_tid = Self::parent_tid(args); + let child_tid = Self::child_tid(args); + + // 地址校验 + verify_area(parent_tid, core::mem::size_of::())?; + verify_area(child_tid, core::mem::size_of::())?; + + let flags = Self::flags(args); + let stack = Self::stack(args); + let tls = Self::tls(args); + + let mut clone_args = KernelCloneArgs::new(); + clone_args.flags = flags; + clone_args.stack = stack; + clone_args.parent_tid = parent_tid; + clone_args.child_tid = child_tid; + clone_args.tls = tls; + + let vfork = Arc::new(Completion::new()); + + if flags.contains(CloneFlags::CLONE_PIDFD) + && flags.contains(CloneFlags::CLONE_PARENT_SETTID) + { + return Err(SystemError::EINVAL); + } + + let current_pcb = ProcessManager::current_pcb(); + let new_kstack = KernelStack::new()?; + let name = current_pcb.basic().name().to_string(); + + let pcb = ProcessControlBlock::new(name, new_kstack); + // 克隆pcb + ProcessManager::copy_process(¤t_pcb, &pcb, clone_args, frame)?; + + // 向procfs注册进程 + procfs_register_pid(pcb.pid()).unwrap_or_else(|e| { + panic!( + "fork: Failed to register pid to procfs, pid: [{:?}]. Error: {:?}", + pcb.pid(), + e + ) + }); + + if flags.contains(CloneFlags::CLONE_VFORK) { + pcb.thread.write_irqsave().vfork_done = Some(vfork.clone()); + } + + if pcb.thread.read_irqsave().set_child_tid.is_some() { + let addr = pcb.thread.read_irqsave().set_child_tid.unwrap(); + let mut writer = + UserBufferWriter::new(addr.as_ptr::(), core::mem::size_of::(), true)?; + writer.copy_one_to_user(&(pcb.pid().data() as i32), 0)?; + } + + ProcessManager::wakeup(&pcb).unwrap_or_else(|e| { + panic!( + "fork: Failed to wakeup new process, pid: [{:?}]. Error: {:?}", + pcb.pid(), + e + ) + }); + + if flags.contains(CloneFlags::CLONE_VFORK) { + // 等待子进程结束或者exec; + vfork.wait_for_completion_interruptible()?; + } + + return Ok(pcb.pid().0); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new( + "parent_tid", + format!("{:#x}", Self::parent_tid(args).data()), + ), + FormattedSyscallParam::new("child_tid", format!("{:#x}", Self::child_tid(args).data())), + FormattedSyscallParam::new("flags", format!("{:#x}", Self::flags(args))), + FormattedSyscallParam::new("stack", format!("{:#x}", Self::stack(args))), + FormattedSyscallParam::new("tls", format!("{:#x}", Self::tls(args))), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_CLONE, SysClone); diff --git a/kernel/src/process/syscall/sys_execve.rs b/kernel/src/process/syscall/sys_execve.rs new file mode 100644 index 00000000..3a4f470a --- /dev/null +++ b/kernel/src/process/syscall/sys_execve.rs @@ -0,0 +1,98 @@ +use log::error; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_EXECVE; +use crate::filesystem::vfs::MAX_PATHLEN; +use crate::mm::page::PAGE_4K_SIZE; +use crate::mm::{verify_area, VirtAddr}; +use crate::process::execve::do_execve; +use crate::process::{ProcessControlBlock, ProcessManager}; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use crate::syscall::user_access::{check_and_clone_cstr, check_and_clone_cstr_array}; +use alloc::{ffi::CString, vec::Vec}; +use system_error::SystemError; + +pub struct SysExecve; + +impl SysExecve { + fn path_ptr(args: &[usize]) -> usize { + args[0] + } + + fn argv_ptr(args: &[usize]) -> usize { + args[1] + } + + fn env_ptr(args: &[usize]) -> usize { + args[2] + } +} + +impl Syscall for SysExecve { + fn num_args(&self) -> usize { + 3 + } + + fn handle(&self, args: &[usize], frame: &mut TrapFrame) -> Result { + let path_ptr = Self::path_ptr(args); + let argv_ptr = Self::argv_ptr(args); + let env_ptr = Self::env_ptr(args); + + let virt_path_ptr = VirtAddr::new(path_ptr); + let virt_argv_ptr = VirtAddr::new(argv_ptr); + let virt_env_ptr = VirtAddr::new(env_ptr); + + // 权限校验 + if frame.is_from_user() + && (verify_area(virt_path_ptr, MAX_PATHLEN).is_err() + || verify_area(virt_argv_ptr, PAGE_4K_SIZE).is_err()) + || verify_area(virt_env_ptr, PAGE_4K_SIZE).is_err() + { + Err(SystemError::EFAULT) + } else { + let path = path_ptr as *const u8; + let argv = argv_ptr as *const *const u8; + let envp = env_ptr as *const *const u8; + + if path.is_null() { + return Err(SystemError::EINVAL); + } + + let x = || { + let path: CString = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; + let argv: Vec = check_and_clone_cstr_array(argv)?; + let envp: Vec = check_and_clone_cstr_array(envp)?; + Ok((path, argv, envp)) + }; + let (path, argv, envp) = x().inspect_err(|e: &SystemError| { + error!("Failed to execve: {:?}", e); + })?; + + let path = path.into_string().map_err(|_| SystemError::EINVAL)?; + ProcessManager::current_pcb() + .basic_mut() + .set_name(ProcessControlBlock::generate_name(&path, &argv)); + + do_execve(path.clone(), argv, envp, frame)?; + + let pcb = ProcessManager::current_pcb(); + // 关闭设置了O_CLOEXEC的文件描述符 + let fd_table = pcb.fd_table(); + fd_table.write().close_on_exec(); + + pcb.set_execute_path(path); + + return Ok(0); + } + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("path", format!("{:#x}", Self::path_ptr(args))), + FormattedSyscallParam::new("argv", format!("{:#x}", Self::argv_ptr(args))), + FormattedSyscallParam::new("env", format!("{:#x}", Self::env_ptr(args))), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_EXECVE, SysExecve); diff --git a/kernel/src/process/syscall/sys_exit.rs b/kernel/src/process/syscall/sys_exit.rs new file mode 100644 index 00000000..796126fe --- /dev/null +++ b/kernel/src/process/syscall/sys_exit.rs @@ -0,0 +1,34 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_EXIT; +use crate::process::ProcessManager; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysExit; + +impl SysExit { + fn exit_code(args: &[usize]) -> usize { + args[0] + } +} + +impl Syscall for SysExit { + fn num_args(&self) -> usize { + 1 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let exit_code = Self::exit_code(args); + ProcessManager::exit((exit_code & 0xff) << 8); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "exit_code", + format!("{:#x}", Self::exit_code(args)), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_EXIT, SysExit); diff --git a/kernel/src/process/syscall/sys_exit_group.rs b/kernel/src/process/syscall/sys_exit_group.rs new file mode 100644 index 00000000..557f4e5b --- /dev/null +++ b/kernel/src/process/syscall/sys_exit_group.rs @@ -0,0 +1,34 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_EXIT_GROUP; +use crate::process::ProcessManager; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysExitGroup; + +impl SysExitGroup { + fn exit_code(args: &[usize]) -> usize { + args[0] + } +} + +impl Syscall for SysExitGroup { + fn num_args(&self) -> usize { + 1 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let exit_code = Self::exit_code(args); + ProcessManager::exit((exit_code & 0xff) << 8); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "exit_code", + format!("{:#x}", Self::exit_code(args)), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_EXIT_GROUP, SysExitGroup); diff --git a/kernel/src/process/syscall/sys_fork.rs b/kernel/src/process/syscall/sys_fork.rs new file mode 100644 index 00000000..8a2aea69 --- /dev/null +++ b/kernel/src/process/syscall/sys_fork.rs @@ -0,0 +1,26 @@ +use crate::arch::interrupt::TrapFrame; +//use crate::arch::syscall::nr::SYS_FORK; +use crate::process::fork::CloneFlags; +use crate::process::ProcessManager; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysFork; + +impl Syscall for SysFork { + fn num_args(&self) -> usize { + 0 + } + + fn handle(&self, _args: &[usize], frame: &mut TrapFrame) -> Result { + log::debug!("fork"); + ProcessManager::fork(frame, CloneFlags::empty()).map(|pid| pid.into()) + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +//syscall_table_macros::declare_syscall!(SYS_FORK, SysFork); diff --git a/kernel/src/process/syscall/sys_get_rusage.rs b/kernel/src/process/syscall/sys_get_rusage.rs new file mode 100644 index 00000000..ba7a77e7 --- /dev/null +++ b/kernel/src/process/syscall/sys_get_rusage.rs @@ -0,0 +1,52 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETRUSAGE; +use crate::process::resource::RUsageWho; +use crate::process::{resource::RUsage, ProcessManager}; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use crate::syscall::user_access::UserBufferWriter; +use alloc::vec::Vec; +use core::ffi::c_int; +use system_error::SystemError; + +pub struct SysGetRusage; + +impl SysGetRusage { + fn who(args: &[usize]) -> c_int { + args[0] as c_int + } + + fn rusage(args: &[usize]) -> *mut RUsage { + args[1] as *mut RUsage + } +} + +impl Syscall for SysGetRusage { + fn num_args(&self) -> usize { + 2 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let who = Self::who(args); + let rusage = Self::rusage(args); + + let who = RUsageWho::try_from(who)?; + let mut writer = UserBufferWriter::new(rusage, core::mem::size_of::(), true)?; + let pcb = ProcessManager::current_pcb(); + let rusage = pcb.get_rusage(who).ok_or(SystemError::EINVAL)?; + + let ubuf = writer.buffer::(0).unwrap(); + ubuf.copy_from_slice(&[rusage]); + + return Ok(0); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("who", format!("{:#x}", Self::who(args))), + FormattedSyscallParam::new("rusage", format!("{:#x}", Self::rusage(args) as usize)), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETRUSAGE, SysGetRusage); diff --git a/kernel/src/process/syscall/sys_getegid.rs b/kernel/src/process/syscall/sys_getegid.rs new file mode 100644 index 00000000..ae044793 --- /dev/null +++ b/kernel/src/process/syscall/sys_getegid.rs @@ -0,0 +1,26 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETEGID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysGetEgid; + +impl Syscall for SysGetEgid { + fn num_args(&self) -> usize { + 0 + } + + fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { + let pcb = ProcessManager::current_pcb(); + return Ok(pcb.cred.lock().egid.data()); + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETEGID, SysGetEgid); diff --git a/kernel/src/process/syscall/sys_geteuid.rs b/kernel/src/process/syscall/sys_geteuid.rs new file mode 100644 index 00000000..7c328408 --- /dev/null +++ b/kernel/src/process/syscall/sys_geteuid.rs @@ -0,0 +1,25 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETEUID; +use crate::process::geteuid::do_geteuid; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysGetEuid; + +impl Syscall for SysGetEuid { + fn num_args(&self) -> usize { + 0 + } + + fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { + do_geteuid() + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETEUID, SysGetEuid); diff --git a/kernel/src/process/syscall/sys_getgid.rs b/kernel/src/process/syscall/sys_getgid.rs new file mode 100644 index 00000000..e00e1a5c --- /dev/null +++ b/kernel/src/process/syscall/sys_getgid.rs @@ -0,0 +1,25 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETGID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysGetGid; + +impl Syscall for SysGetGid { + fn num_args(&self) -> usize { + 0 + } + + fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { + let pcb = ProcessManager::current_pcb(); + return Ok(pcb.cred.lock().gid.data()); + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETGID, SysGetGid); diff --git a/kernel/src/process/syscall/sys_getpgid.rs b/kernel/src/process/syscall/sys_getpgid.rs new file mode 100644 index 00000000..331e01f0 --- /dev/null +++ b/kernel/src/process/syscall/sys_getpgid.rs @@ -0,0 +1,49 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETPGID; +use crate::process::Pid; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysGetPgid; + +impl SysGetPgid { + fn pid(args: &[usize]) -> Pid { + Pid::new(args[0]) + } +} + +impl Syscall for SysGetPgid { + fn num_args(&self) -> usize { + 1 + } + + /// # 函数的功能 + /// 获取指定进程的pgid + /// + /// ## 参数 + /// - pid: 指定一个进程号 + /// + /// ## 返回值 + /// - 成功,指定进程的进程组id + /// - 错误,不存在该进程 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let pid = Self::pid(args); + if pid == Pid(0) { + let current_pcb = ProcessManager::current_pcb(); + return Ok(current_pcb.pgid().into()); + } + let target_proc = ProcessManager::find(pid).ok_or(SystemError::ESRCH)?; + return Ok(target_proc.pgid().into()); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "pid", + format!("{:#x}", Self::pid(args).0), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETPGID, SysGetPgid); diff --git a/kernel/src/process/syscall/sys_getpid.rs b/kernel/src/process/syscall/sys_getpid.rs new file mode 100644 index 00000000..72d2ff1b --- /dev/null +++ b/kernel/src/process/syscall/sys_getpid.rs @@ -0,0 +1,33 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETPID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysGetPid; + +impl Syscall for SysGetPid { + fn num_args(&self) -> usize { + 0 + } + + /// # 函数的功能 + /// 获取当前进程的pid + fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { + let current_pcb = ProcessManager::current_pcb(); + // if let Some(pid_ns) = ¤t_pcb.get_nsproxy().read().pid_namespace { + // // 获取该进程在命名空间中的 PID + // return Ok(current_pcb.pid_strcut().read().numbers[pid_ns.level].nr); + // // 返回命名空间中的 PID + // } + // 默认返回 tgid + return Ok(current_pcb.tgid().into()); + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETPID, SysGetPid); diff --git a/kernel/src/process/syscall/sys_getppid.rs b/kernel/src/process/syscall/sys_getppid.rs new file mode 100644 index 00000000..f4ef8bd3 --- /dev/null +++ b/kernel/src/process/syscall/sys_getppid.rs @@ -0,0 +1,27 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETPPID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysGetPpid; + +impl Syscall for SysGetPpid { + fn num_args(&self) -> usize { + 0 + } + + /// # 函数的功能 + /// 获取当前进程的父进程id + fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { + let current_pcb = ProcessManager::current_pcb(); + return Ok(current_pcb.basic().ppid().into()); + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETPPID, SysGetPpid); diff --git a/kernel/src/process/syscall/sys_getrlimit.rs b/kernel/src/process/syscall/sys_getrlimit.rs new file mode 100644 index 00000000..815d22fa --- /dev/null +++ b/kernel/src/process/syscall/sys_getrlimit.rs @@ -0,0 +1,50 @@ +use system_error::SystemError; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETRLIMIT; +use crate::process::resource::RLimit64; +use crate::process::syscall::sys_prlimit64::do_prlimit64; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; + +use alloc::vec::Vec; + +pub struct SysGetRlimit; + +impl SysGetRlimit { + fn resource(args: &[usize]) -> usize { + args[0] + } + + fn rlimit(args: &[usize]) -> *mut RLimit64 { + args[1] as *mut RLimit64 + } +} + +impl Syscall for SysGetRlimit { + fn num_args(&self) -> usize { + 2 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let resource = Self::resource(args); + let rlimit = Self::rlimit(args); + + do_prlimit64( + ProcessManager::current_pcb().pid(), + resource, + core::ptr::null::(), + rlimit, + ) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("resource", format!("{:#x}", Self::resource(args))), + FormattedSyscallParam::new("rlimit", format!("{:#x}", Self::rlimit(args) as usize)), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETRLIMIT, SysGetRlimit); diff --git a/kernel/src/process/syscall/sys_getsid.rs b/kernel/src/process/syscall/sys_getsid.rs new file mode 100644 index 00000000..2bdb710f --- /dev/null +++ b/kernel/src/process/syscall/sys_getsid.rs @@ -0,0 +1,54 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETSID; +use crate::process::Pid; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::sync::Arc; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysGetsid; + +impl SysGetsid { + fn pid(args: &[usize]) -> Pid { + Pid::new(args[0]) + } +} + +impl Syscall for SysGetsid { + fn num_args(&self) -> usize { + 1 + } + + /// # 函数的功能 + /// 获取指定进程的会话id + /// + /// 若pid为0,则返回当前进程的会话id + /// + /// 若pid不为0,则返回指定进程的会话id + /// + /// ## 参数 + /// - pid: 指定一个进程号 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let pid = Self::pid(args); + let session = ProcessManager::current_pcb().session().unwrap(); + let sid = session.sid().into(); + if pid == Pid(0) { + return Ok(sid); + } + let pcb = ProcessManager::find(pid).ok_or(SystemError::ESRCH)?; + if !Arc::ptr_eq(&session, &pcb.session().unwrap()) { + return Err(SystemError::EPERM); + } + return Ok(sid); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "pid", + format!("{:#x}", Self::pid(args).0), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETSID, SysGetsid); diff --git a/kernel/src/process/syscall/sys_gettid.rs b/kernel/src/process/syscall/sys_gettid.rs new file mode 100644 index 00000000..5e825668 --- /dev/null +++ b/kernel/src/process/syscall/sys_gettid.rs @@ -0,0 +1,25 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETTID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysGetTid; + +impl Syscall for SysGetTid { + fn num_args(&self) -> usize { + 0 + } + + fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { + let pcb = ProcessManager::current_pcb(); + return Ok(pcb.pid.into()); + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETTID, SysGetTid); diff --git a/kernel/src/process/syscall/sys_getuid.rs b/kernel/src/process/syscall/sys_getuid.rs new file mode 100644 index 00000000..19fa7edb --- /dev/null +++ b/kernel/src/process/syscall/sys_getuid.rs @@ -0,0 +1,26 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_GETUID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysGetUid; + +impl Syscall for SysGetUid { + fn num_args(&self) -> usize { + 0 + } + + fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { + let pcb = ProcessManager::current_pcb(); + return Ok(pcb.cred.lock().uid.data()); + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +syscall_table_macros::declare_syscall!(SYS_GETUID, SysGetUid); diff --git a/kernel/src/process/syscall/sys_prlimit64.rs b/kernel/src/process/syscall/sys_prlimit64.rs new file mode 100644 index 00000000..bdac7ad9 --- /dev/null +++ b/kernel/src/process/syscall/sys_prlimit64.rs @@ -0,0 +1,135 @@ +use crate::arch::syscall::nr::SYS_PRLIMIT64; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use crate::{ + arch::MMArch, + filesystem::vfs::file::FileDescriptorVec, + mm::{ucontext::UserStack, MemoryManagementArch}, + process::{ + resource::{RLimit64, RLimitID}, + Pid, + }, + syscall::user_access::UserBufferWriter, +}; +use alloc::vec::Vec; +use system_error::SystemError; + +use crate::arch::interrupt::TrapFrame; +pub struct SysPrlimit64; + +impl SysPrlimit64 { + fn pid(args: &[usize]) -> Pid { + Pid::new(args[0]) + } + + fn resource(args: &[usize]) -> usize { + args[1] + } + + fn new_limit(args: &[usize]) -> *const RLimit64 { + args[2] as *const RLimit64 + } + + fn old_limit(args: &[usize]) -> *mut RLimit64 { + args[3] as *mut RLimit64 + } +} + +impl Syscall for SysPrlimit64 { + fn num_args(&self) -> usize { + 4 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let pid = Self::pid(args); + let resource = Self::resource(args); + let new_limit = Self::new_limit(args); + let old_limit = Self::old_limit(args); + + do_prlimit64(pid, resource, new_limit, old_limit) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("pid", format!("{:#x}", Self::pid(args).data())), + FormattedSyscallParam::new("resource", format!("{:#x}", Self::resource(args))), + FormattedSyscallParam::new( + "new_limit", + format!("{:#x}", Self::new_limit(args) as usize), + ), + FormattedSyscallParam::new( + "old_limit", + format!("{:#x}", Self::old_limit(args) as usize), + ), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_PRLIMIT64, SysPrlimit64); + +/// # 设置资源限制 +/// +/// TODO: 目前暂时不支持设置资源限制,只提供读取默认值的功能 +/// +/// ## 参数 +/// +/// - pid: 进程号 +/// - resource: 资源类型 +/// - new_limit: 新的资源限制 +/// - old_limit: 旧的资源限制 +/// +/// ## 返回值 +/// +/// - 成功,0 +/// - 如果old_limit不为NULL,则返回旧的资源限制到old_limit +/// +pub(super) fn do_prlimit64( + _pid: Pid, + resource: usize, + _new_limit: *const RLimit64, + old_limit: *mut RLimit64, +) -> Result { + let resource = RLimitID::try_from(resource)?; + let mut writer = None; + + if !old_limit.is_null() { + writer = Some(UserBufferWriter::new( + old_limit, + core::mem::size_of::(), + true, + )?); + } + + match resource { + RLimitID::Stack => { + if let Some(mut writer) = writer { + let mut rlimit = writer.buffer::(0).unwrap()[0]; + rlimit.rlim_cur = UserStack::DEFAULT_USER_STACK_SIZE as u64; + rlimit.rlim_max = UserStack::DEFAULT_USER_STACK_SIZE as u64; + } + return Ok(0); + } + + RLimitID::Nofile => { + if let Some(mut writer) = writer { + let mut rlimit = writer.buffer::(0).unwrap()[0]; + rlimit.rlim_cur = FileDescriptorVec::PROCESS_MAX_FD as u64; + rlimit.rlim_max = FileDescriptorVec::PROCESS_MAX_FD as u64; + } + return Ok(0); + } + + RLimitID::As | RLimitID::Rss => { + if let Some(mut writer) = writer { + let mut rlimit = writer.buffer::(0).unwrap()[0]; + rlimit.rlim_cur = MMArch::USER_END_VADDR.data() as u64; + rlimit.rlim_max = MMArch::USER_END_VADDR.data() as u64; + } + return Ok(0); + } + + _ => { + return Err(SystemError::ENOSYS); + } + } +} diff --git a/kernel/src/process/syscall/sys_set_tid_address.rs b/kernel/src/process/syscall/sys_set_tid_address.rs new file mode 100644 index 00000000..ba02b45e --- /dev/null +++ b/kernel/src/process/syscall/sys_set_tid_address.rs @@ -0,0 +1,43 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SET_TID_ADDRESS; +use crate::mm::verify_area; +use crate::mm::VirtAddr; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysSetTidAddress; + +impl SysSetTidAddress { + fn ptr(args: &[usize]) -> usize { + args[0] + } +} + +impl Syscall for SysSetTidAddress { + fn num_args(&self) -> usize { + 1 + } + + /// # 函数的功能 + /// 设置线程地址 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let ptr = Self::ptr(args); + verify_area(VirtAddr::new(ptr), core::mem::size_of::()) + .map_err(|_| SystemError::EFAULT)?; + + let pcb = ProcessManager::current_pcb(); + pcb.thread.write_irqsave().clear_child_tid = Some(VirtAddr::new(ptr)); + Ok(pcb.pid.0) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "ptr", + format!("{:#x}", Self::ptr(args)), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_SET_TID_ADDRESS, SysSetTidAddress); diff --git a/kernel/src/process/syscall/sys_setfsgid.rs b/kernel/src/process/syscall/sys_setfsgid.rs new file mode 100644 index 00000000..7c63d2b5 --- /dev/null +++ b/kernel/src/process/syscall/sys_setfsgid.rs @@ -0,0 +1,46 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SETFSGID; +use crate::process::cred::Kgid; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysSetFsgid; + +impl SysSetFsgid { + fn fsgid(args: &[usize]) -> usize { + args[0] + } +} + +impl Syscall for SysSetFsgid { + fn num_args(&self) -> usize { + 1 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let fsgid = Self::fsgid(args); + let fsgid = Kgid::new(fsgid); + + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + let old_fsgid = guard.fsgid; + + if fsgid == guard.gid || fsgid == guard.egid || fsgid == guard.sgid { + guard.setfsgid(fsgid.data()); + } + + Ok(old_fsgid.data()) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "fsgid", + format!("{:#x}", Self::fsgid(args)), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_SETFSGID, SysSetFsgid); diff --git a/kernel/src/process/syscall/sys_setfsuid.rs b/kernel/src/process/syscall/sys_setfsuid.rs new file mode 100644 index 00000000..1823831c --- /dev/null +++ b/kernel/src/process/syscall/sys_setfsuid.rs @@ -0,0 +1,45 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SETFSUID; +use crate::process::cred::Kuid; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysSetFsuid; + +impl SysSetFsuid { + fn fsuid(args: &[usize]) -> usize { + args[0] + } +} + +impl Syscall for SysSetFsuid { + fn num_args(&self) -> usize { + 1 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let fsuid = Self::fsuid(args); + let fsuid = Kuid::new(fsuid); + + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + let old_fsuid = guard.fsuid; + + if fsuid == guard.uid || fsuid == guard.euid || fsuid == guard.suid { + guard.setfsuid(fsuid.data()); + } + + Ok(old_fsuid.data()) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "fsuid", + format!("{:#x}", Self::fsuid(args)), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_SETFSUID, SysSetFsuid); diff --git a/kernel/src/process/syscall/sys_setgid.rs b/kernel/src/process/syscall/sys_setgid.rs new file mode 100644 index 00000000..a482c48c --- /dev/null +++ b/kernel/src/process/syscall/sys_setgid.rs @@ -0,0 +1,50 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SETGID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysSetGid; + +impl SysSetGid { + fn gid(args: &[usize]) -> usize { + args[0] + } +} + +impl Syscall for SysSetGid { + fn num_args(&self) -> usize { + 1 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let gid = Self::gid(args); + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + + if guard.egid.data() == 0 { + guard.setgid(gid); + guard.setegid(gid); + guard.setsgid(gid); + guard.setfsgid(gid); + } else if guard.gid.data() == gid || guard.sgid.data() == gid { + guard.setegid(gid); + guard.setfsgid(gid); + } else { + return Err(SystemError::EPERM); + } + + return Ok(0); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "gid", + format!("{:#x}", Self::gid(args)), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_SETGID, SysSetGid); diff --git a/kernel/src/process/syscall/sys_setpgid.rs b/kernel/src/process/syscall/sys_setpgid.rs new file mode 100644 index 00000000..1185a032 --- /dev/null +++ b/kernel/src/process/syscall/sys_setpgid.rs @@ -0,0 +1,69 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SETPGID; +use crate::process::Pgid; +use crate::process::Pid; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysSetPgid; + +impl SysSetPgid { + fn pid(args: &[usize]) -> Pid { + Pid::new(args[0]) + } + + fn pgid(args: &[usize]) -> Pgid { + Pgid::new(args[1]) + } +} + +impl Syscall for SysSetPgid { + fn num_args(&self) -> usize { + 2 + } + + /// # 函数的功能 + /// 设置指定进程的pgid + /// + /// ## 参数 + /// - pid: 指定进程号 + /// - pgid: 新的进程组号 + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let pid = Self::pid(args); + let pgid = Self::pgid(args); + + let current_pcb = ProcessManager::current_pcb(); + let pid = if pid == Pid(0) { + current_pcb.pid() + } else { + pid + }; + let pgid = if pgid == Pgid::from(0) { + Pgid::from(pid.into()) + } else { + pgid + }; + if pid != current_pcb.pid() && !current_pcb.contain_child(&pid) { + return Err(SystemError::ESRCH); + } + + if pgid.into() != pid.into() && ProcessManager::find_process_group(pgid).is_none() { + return Err(SystemError::EPERM); + } + let pcb = ProcessManager::find(pid).ok_or(SystemError::ESRCH)?; + pcb.join_other_group(pgid)?; + + return Ok(0); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("pid", format!("{:#x}", Self::pid(args).0)), + FormattedSyscallParam::new("pgid", format!("{:#x}", Self::pgid(args).0)), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_SETPGID, SysSetPgid); diff --git a/kernel/src/process/syscall/sys_setresgid.rs b/kernel/src/process/syscall/sys_setresgid.rs new file mode 100644 index 00000000..aa1eac6e --- /dev/null +++ b/kernel/src/process/syscall/sys_setresgid.rs @@ -0,0 +1,48 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SETRESGID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysSetResGid; + +impl SysSetResGid { + fn egid(args: &[usize]) -> usize { + args[1] + } +} + +impl Syscall for SysSetResGid { + fn num_args(&self) -> usize { + 2 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let egid = Self::egid(args); + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + + if egid == usize::MAX || (egid == guard.egid.data() && egid == guard.fsgid.data()) { + return Ok(0); + } + + if egid != usize::MAX { + guard.setegid(egid); + } + + let egid = guard.egid.data(); + guard.setfsgid(egid); + + return Ok(0); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "egid", + format!("{:#x}", Self::egid(args)), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_SETRESGID, SysSetResGid); diff --git a/kernel/src/process/syscall/sys_setresuid.rs b/kernel/src/process/syscall/sys_setresuid.rs new file mode 100644 index 00000000..2041933b --- /dev/null +++ b/kernel/src/process/syscall/sys_setresuid.rs @@ -0,0 +1,48 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SETRESUID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysSetResUid; + +impl SysSetResUid { + fn euid(args: &[usize]) -> usize { + args[1] + } +} + +impl Syscall for SysSetResUid { + fn num_args(&self) -> usize { + 2 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let euid = Self::euid(args); + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + + if euid == usize::MAX || (euid == guard.euid.data() && euid == guard.fsuid.data()) { + return Ok(0); + } + + if euid != usize::MAX { + guard.seteuid(euid); + } + + let euid = guard.euid.data(); + guard.setfsuid(euid); + + return Ok(0); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "euid", + format!("{:#x}", Self::euid(args)), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_SETRESUID, SysSetResUid); diff --git a/kernel/src/process/syscall/sys_setsid.rs b/kernel/src/process/syscall/sys_setsid.rs new file mode 100644 index 00000000..5f6fb82e --- /dev/null +++ b/kernel/src/process/syscall/sys_setsid.rs @@ -0,0 +1,30 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SETSID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysSetsid; + +impl Syscall for SysSetsid { + fn num_args(&self) -> usize { + 0 + } + + /// # 函数的功能 + /// 创建新的会话 + fn handle(&self, _args: &[usize], _frame: &mut TrapFrame) -> Result { + let pcb = ProcessManager::current_pcb(); + let session = pcb.go_to_new_session()?; + let mut guard = pcb.sig_info_mut(); + guard.set_tty(None); + Ok(session.sid().into()) + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +syscall_table_macros::declare_syscall!(SYS_SETSID, SysSetsid); diff --git a/kernel/src/process/syscall/sys_setuid.rs b/kernel/src/process/syscall/sys_setuid.rs new file mode 100644 index 00000000..4c392bd8 --- /dev/null +++ b/kernel/src/process/syscall/sys_setuid.rs @@ -0,0 +1,47 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SETUID; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysSetUid; + +impl SysSetUid { + fn uid(args: &[usize]) -> usize { + args[0] + } +} + +impl Syscall for SysSetUid { + fn num_args(&self) -> usize { + 1 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let uid = Self::uid(args); + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + + if guard.uid.data() == 0 { + guard.setuid(uid); + guard.seteuid(uid); + guard.setsuid(uid); + } else if uid == guard.uid.data() || uid == guard.suid.data() { + guard.seteuid(uid); + } else { + return Err(SystemError::EPERM); + } + + return Ok(0); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "uid", + format!("{:#x}", Self::uid(args)), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_SETUID, SysSetUid); diff --git a/kernel/src/process/syscall/sys_uname.rs b/kernel/src/process/syscall/sys_uname.rs new file mode 100644 index 00000000..5ed44fc9 --- /dev/null +++ b/kernel/src/process/syscall/sys_uname.rs @@ -0,0 +1,38 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_UNAME; +use crate::process::syscall::PosixOldUtsName; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use crate::syscall::user_access::UserBufferWriter; +use alloc::vec::Vec; +use system_error::SystemError; +pub struct SysUname; + +impl SysUname { + fn name(args: &[usize]) -> *mut PosixOldUtsName { + args[0] as *mut PosixOldUtsName + } +} + +impl Syscall for SysUname { + fn num_args(&self) -> usize { + 1 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let name = Self::name(args); + let mut writer = + UserBufferWriter::new(name, core::mem::size_of::(), true)?; + writer.copy_one_to_user(&PosixOldUtsName::new(), 0)?; + + return Ok(0); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![FormattedSyscallParam::new( + "name", + format!("{:#x}", Self::name(args) as usize), + )] + } +} + +syscall_table_macros::declare_syscall!(SYS_UNAME, SysUname); diff --git a/kernel/src/process/syscall/sys_vfork.rs b/kernel/src/process/syscall/sys_vfork.rs new file mode 100644 index 00000000..b7b1dd00 --- /dev/null +++ b/kernel/src/process/syscall/sys_vfork.rs @@ -0,0 +1,35 @@ +use crate::arch::interrupt::TrapFrame; +//use crate::arch::syscall::nr::SYS_VFORK; +use crate::process::fork::CloneFlags; +use crate::process::ProcessManager; +use crate::syscall::table::{FormattedSyscallParam, Syscall}; +use alloc::vec::Vec; +use system_error::SystemError; + +pub struct SysVfork; + +impl Syscall for SysVfork { + fn num_args(&self) -> usize { + 0 + } + + fn handle(&self, _args: &[usize], frame: &mut TrapFrame) -> Result { + // 由于Linux vfork需要保证子进程先运行(除非子进程调用execve或者exit), + // 而我们目前没有实现这个特性,所以暂时使用fork代替vfork(linux文档表示这样也是也可以的) + log::debug!("vfork"); + ProcessManager::fork(frame, CloneFlags::empty()).map(|pid| pid.into()) + + // 下面是以前的实现,除非我们实现了子进程先运行的特性,否则不要使用,不然会导致父进程数据损坏 + // ProcessManager::fork( + // frame, + // CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL, + // ) + // .map(|pid| pid.into()) + } + + fn entry_format(&self, _args: &[usize]) -> Vec { + vec![] + } +} + +//syscall_table_macros::declare_syscall!(SYS_VFORK, SysVfork); diff --git a/kernel/src/process/syscall/sys_wait4.rs b/kernel/src/process/syscall/sys_wait4.rs new file mode 100644 index 00000000..705910ea --- /dev/null +++ b/kernel/src/process/syscall/sys_wait4.rs @@ -0,0 +1,88 @@ +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_WAIT4; +use crate::process::abi::WaitOption; +use crate::process::exit::kernel_wait4; +use crate::process::resource::RUsage; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; +use crate::syscall::user_access::UserBufferWriter; +use alloc::vec::Vec; +use core::ffi::c_int; +use core::ffi::c_void; +use system_error::SystemError; + +pub struct SysWait4; + +impl SysWait4 { + fn pid(args: &[usize]) -> i32 { + args[0] as i32 + } + + fn wstatus(args: &[usize]) -> *mut i32 { + args[1] as *mut i32 + } + + fn options(args: &[usize]) -> c_int { + args[2] as c_int + } + + fn rusage(args: &[usize]) -> *mut c_void { + args[3] as *mut c_void + } +} + +impl Syscall for SysWait4 { + fn num_args(&self) -> usize { + 4 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let pid = Self::pid(args); + let wstatus = Self::wstatus(args); + let options = Self::options(args); + let rusage = Self::rusage(args); + // 权限校验 + // todo: 引入rusage之后,更正以下权限校验代码中,rusage的大小 + + let options = WaitOption::from_bits(options as u32).ok_or(SystemError::EINVAL)?; + + let wstatus_buf = if wstatus.is_null() { + None + } else { + Some(UserBufferWriter::new( + wstatus, + core::mem::size_of::(), + true, + )?) + }; + + let mut tmp_rusage = if rusage.is_null() { + None + } else { + Some(RUsage::default()) + }; + + let r = kernel_wait4(pid, wstatus_buf, options, tmp_rusage.as_mut())?; + + if !rusage.is_null() { + let mut rusage_buf = UserBufferWriter::new::( + rusage as *mut RUsage, + core::mem::size_of::(), + true, + )?; + rusage_buf.copy_one_to_user(&tmp_rusage.unwrap(), 0)?; + } + return Ok(r); + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("pid", format!("{:#x}", Self::pid(args))), + FormattedSyscallParam::new("wstatus", format!("{:#x}", Self::wstatus(args) as usize)), + FormattedSyscallParam::new("options", format!("{:#x}", Self::options(args))), + FormattedSyscallParam::new("rusage", format!("{:#x}", Self::rusage(args) as usize)), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_WAIT4, SysWait4); diff --git a/kernel/src/sched/clock.rs b/kernel/src/sched/clock.rs index c1eed405..8f75c968 100644 --- a/kernel/src/sched/clock.rs +++ b/kernel/src/sched/clock.rs @@ -16,7 +16,7 @@ impl SchedClock { return CurrentTimeArch::cycles2ns(CurrentTimeArch::get_cycles()) as u64; } - #[cfg(target_arch = "riscv64")] + #[cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))] { return CurrentTimeArch::cycles2ns(CurrentTimeArch::get_cycles()) as u64; } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 95feb754..741191ad 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -1,20 +1,16 @@ +use crate::process::fork::CloneFlags; use core::{ - ffi::{c_int, c_void}, + ffi::c_int, sync::atomic::{AtomicBool, Ordering}, }; use crate::{ - arch::{ipc::signal::SigSet, syscall::nr::*}, - filesystem::vfs::syscall::{PosixStatfs, PosixStatx}, - ipc::shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey}, + arch::syscall::nr::*, + filesystem::vfs::syscall::PosixStatfs, libs::{futex::constant::FutexFlag, rand::GRandFlags}, - mm::{page::PAGE_4K_SIZE, syscall::MremapFlags}, + mm::page::PAGE_4K_SIZE, net::posix::{MsgHdr, SockAddr}, - process::{ - fork::KernelCloneArgs, - resource::{RLimit64, RUsage}, - ProcessFlags, ProcessManager, - }, + process::{ProcessFlags, ProcessManager}, sched::{schedule, SchedMode}, syscall::user_access::check_and_clone_cstr, }; @@ -22,18 +18,15 @@ use crate::{ use log::{info, warn}; use num_traits::FromPrimitive; use system_error::SystemError; +use table::{syscall_table, syscall_table_init}; use crate::{ - arch::{interrupt::TrapFrame, MMArch}, + arch::interrupt::TrapFrame, filesystem::vfs::{ fcntl::{AtFlags, FcntlCommand}, - file::FileMode, - syscall::{ModeType, PosixKstat, UtimensFlags}, - MAX_PATHLEN, + syscall::{ModeType, UtimensFlags}, }, - libs::align::page_align_up, - mm::{verify_area, MemoryManagementArch, VirtAddr}, - process::{fork::CloneFlags, syscall::PosixOldUtsName, Pid}, + mm::{verify_area, VirtAddr}, time::{ syscall::{PosixTimeZone, PosixTimeval}, PosixTimeSpec, @@ -46,6 +39,7 @@ use self::{ }; pub mod misc; +pub mod table; pub mod user_access; // 与linux不一致的调用,在linux基础上累加 @@ -76,16 +70,15 @@ impl Syscall { /// 系统调用分发器,用于分发系统调用。 /// /// 与[handle]不同,这个函数会捕获系统调用处理函数的panic,返回错误码。 - #[cfg(feature = "backtrace")] + #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] pub fn catch_handle( syscall_num: usize, args: &[usize], frame: &mut TrapFrame, ) -> Result { - let res = unwinding::panic::catch_unwind(|| Self::handle(syscall_num, args, frame)); - res.unwrap_or_else(|_| loop { - core::hint::spin_loop(); - }) + use crate::debug::panic::kernel_catch_unwind; + let res = kernel_catch_unwind(|| Self::handle(syscall_num, args, frame))?; + res } /// @brief 系统调用分发器,用于分发系统调用。 /// @@ -97,18 +90,23 @@ impl Syscall { args: &[usize], frame: &mut TrapFrame, ) -> Result { + // 首先尝试从syscall_table获取处理函数 + if let Some(handler) = syscall_table().get(syscall_num) { + // 使用以下代码可以打印系统调用号和参数,方便调试 + // log::debug!( + // "Syscall {} called with args {}", + // handler.name, + // handler.args_string(args) + // ); + + return handler.inner_handle.handle(args, frame); + } + + // 如果找不到,fallback到原有逻辑 let r = match syscall_num { SYS_PUT_STRING => { Self::put_string(args[0] as *const u8, args[1] as u32, args[2] as u32) } - #[cfg(target_arch = "x86_64")] - SYS_OPEN => { - let path = args[0] as *const u8; - let flags = args[1] as u32; - let mode = args[2] as u32; - - Self::open(path, flags, mode, true) - } #[cfg(target_arch = "x86_64")] SYS_RENAME => { @@ -123,6 +121,11 @@ impl Syscall { ) } + #[cfg(target_arch = "x86_64")] + SYS_FORK => ProcessManager::fork(frame, CloneFlags::empty()).map(|pid| pid.into()), + #[cfg(target_arch = "x86_64")] + SYS_VFORK => ProcessManager::fork(frame, CloneFlags::empty()).map(|pid| pid.into()), + #[cfg(target_arch = "x86_64")] SYS_RENAMEAT => { let oldfd = args[0] as i32; @@ -149,32 +152,6 @@ impl Syscall { Self::openat(dirfd, path, flags, mode, true) } - SYS_CLOSE => { - let fd = args[0]; - Self::close(fd) - } - SYS_READ => { - let fd = args[0] as i32; - let buf_vaddr = args[1]; - let len = args[2]; - let from_user = frame.is_from_user(); - let mut user_buffer_writer = - UserBufferWriter::new(buf_vaddr as *mut u8, len, from_user)?; - - let user_buf = user_buffer_writer.buffer(0)?; - Self::read(fd, user_buf) - } - SYS_WRITE => { - let fd = args[0] as i32; - let buf_vaddr = args[1]; - let len = args[2]; - let from_user = frame.is_from_user(); - let user_buffer_reader = - UserBufferReader::new(buf_vaddr as *const u8, len, from_user)?; - - let user_buf = user_buffer_reader.read_from_user(0)?; - Self::write(fd, user_buf) - } SYS_LSEEK => { let fd = args[0] as i32; @@ -209,26 +186,9 @@ impl Syscall { Self::pwrite(fd, buf, len, offset) } - SYS_IOCTL => { - let fd = args[0]; - let cmd = args[1]; - let data = args[2]; - Self::ioctl(fd, cmd as u32, data) - } - - #[cfg(target_arch = "x86_64")] - SYS_FORK => Self::fork(frame), - #[cfg(target_arch = "x86_64")] - SYS_VFORK => Self::vfork(frame), - - SYS_BRK => { - let new_brk = VirtAddr::new(args[0]); - Self::brk(new_brk).map(|vaddr| vaddr.data()) - } - SYS_SBRK => { - let increment = args[0] as isize; - Self::sbrk(increment).map(|vaddr: VirtAddr| vaddr.data()) + let incr = args[0] as isize; + crate::mm::syscall::sys_sbrk::sys_sbrk(incr) } SYS_REBOOT => { @@ -271,44 +231,6 @@ impl Syscall { res } - SYS_EXECVE => { - let path_ptr = args[0]; - let argv_ptr = args[1]; - let env_ptr = args[2]; - let virt_path_ptr = VirtAddr::new(path_ptr); - let virt_argv_ptr = VirtAddr::new(argv_ptr); - let virt_env_ptr = VirtAddr::new(env_ptr); - // 权限校验 - if frame.is_from_user() - && (verify_area(virt_path_ptr, MAX_PATHLEN).is_err() - || verify_area(virt_argv_ptr, PAGE_4K_SIZE).is_err()) - || verify_area(virt_env_ptr, PAGE_4K_SIZE).is_err() - { - Err(SystemError::EFAULT) - } else { - Self::execve( - path_ptr as *const u8, - argv_ptr as *const *const u8, - env_ptr as *const *const u8, - frame, - ) - .map(|_| 0) - } - } - SYS_WAIT4 => { - let pid = args[0] as i32; - let wstatus = args[1] as *mut i32; - let options = args[2] as c_int; - let rusage = args[3] as *mut c_void; - // 权限校验 - // todo: 引入rusage之后,更正以下权限校验代码中,rusage的大小 - Self::wait4(pid.into(), wstatus, options, rusage) - } - - SYS_EXIT => { - let exit_code = args[0]; - Self::exit(exit_code) - } #[cfg(target_arch = "x86_64")] SYS_MKDIR => { let path = args[0] as *const u8; @@ -340,27 +262,6 @@ impl Syscall { } SYS_CLOCK => Self::clock(), - #[cfg(target_arch = "x86_64")] - SYS_PIPE => { - let pipefd: *mut i32 = args[0] as *mut c_int; - if pipefd.is_null() { - Err(SystemError::EFAULT) - } else { - Self::pipe2(pipefd, FileMode::empty()) - } - } - - SYS_PIPE2 => { - let pipefd: *mut i32 = args[0] as *mut c_int; - let arg1 = args[1]; - if pipefd.is_null() { - Err(SystemError::EFAULT) - } else { - let flags = FileMode::from_bits_truncate(arg1 as u32); - Self::pipe2(pipefd, flags) - } - } - SYS_UNLINKAT => { let dirfd = args[0] as i32; let path = args[1] as *const u8; @@ -409,21 +310,6 @@ impl Syscall { let path = args[0] as *const u8; Self::unlink(path) } - SYS_KILL => { - let pid = Pid::new(args[0]); - let sig = args[1] as c_int; - // debug!("KILL SYSCALL RECEIVED"); - Self::kill(pid, sig) - } - - SYS_RT_SIGACTION => { - let sig = args[0] as c_int; - let act = args[1]; - let old_act = args[2]; - Self::sigaction(sig, act, old_act, frame.is_from_user()) - } - - SYS_GETPID => Self::getpid().map(|pid| pid.into()), SYS_SCHED => { warn!("syscall sched"); @@ -605,51 +491,6 @@ impl Syscall { let timezone_ptr = args[1] as *mut PosixTimeZone; Self::gettimeofday(timeval, timezone_ptr) } - SYS_MMAP => { - let len = page_align_up(args[1]); - let virt_addr = VirtAddr::new(args[0]); - if verify_area(virt_addr, len).is_err() { - Err(SystemError::EFAULT) - } else { - Self::mmap( - VirtAddr::new(args[0]), - len, - args[2], - args[3], - args[4] as i32, - args[5], - ) - } - } - SYS_MREMAP => { - let old_vaddr = VirtAddr::new(args[0]); - let old_len = args[1]; - let new_len = args[2]; - let mremap_flags = MremapFlags::from_bits_truncate(args[3] as u8); - let new_vaddr = VirtAddr::new(args[4]); - - Self::mremap(old_vaddr, old_len, new_len, mremap_flags, new_vaddr) - } - SYS_MUNMAP => { - let addr = args[0]; - let len = page_align_up(args[1]); - if addr & (MMArch::PAGE_SIZE - 1) != 0 { - // The addr argument is not a multiple of the page size - Err(SystemError::EINVAL) - } else { - Self::munmap(VirtAddr::new(addr), len) - } - } - SYS_MPROTECT => { - let addr = args[0]; - let len = page_align_up(args[1]); - if addr & (MMArch::PAGE_SIZE - 1) != 0 { - // The addr argument is not a multiple of the page size - Err(SystemError::EINVAL) - } else { - Self::mprotect(VirtAddr::new(addr), len, args[2]) - } - } SYS_GETCWD => { let buf = args[0] as *mut u8; @@ -667,21 +508,6 @@ impl Syscall { } } - SYS_GETPGID => Self::getpgid(Pid::new(args[0])).map(|pid| pid.into()), - - SYS_GETPPID => Self::getppid().map(|pid| pid.into()), - SYS_FSTAT => { - let fd = args[0] as i32; - let kstat: *mut PosixKstat = args[1] as *mut PosixKstat; - let vaddr = VirtAddr::new(kstat as usize); - // FIXME 由于c中的verify_area与rust中的verify_area重名,所以在引入时加了前缀区分 - // TODO 应该将用了c版本的verify_area都改为rust的verify_area - match verify_area(vaddr, core::mem::size_of::()) { - Ok(_) => Self::fstat(fd, kstat), - Err(e) => Err(e), - } - } - SYS_FCNTL => { let fd = args[0] as i32; let cmd: Option = @@ -718,23 +544,6 @@ impl Syscall { ) } - SYS_CLONE => { - let parent_tid = VirtAddr::new(args[2]); - let child_tid = VirtAddr::new(args[3]); - - // 地址校验 - verify_area(parent_tid, core::mem::size_of::())?; - verify_area(child_tid, core::mem::size_of::())?; - - let mut clone_args = KernelCloneArgs::new(); - clone_args.flags = CloneFlags::from_bits_truncate(args[0] as u64); - clone_args.stack = args[1]; - clone_args.parent_tid = parent_tid; - clone_args.child_tid = child_tid; - clone_args.tls = args[4]; - Self::clone(frame, clone_args) - } - SYS_FUTEX => { let uaddr = VirtAddr::new(args[0]); let operation = FutexFlag::from_bits(args[1] as u32).ok_or(SystemError::ENOSYS)?; @@ -777,25 +586,6 @@ impl Syscall { return ret; } - SYS_READV => Self::readv(args[0] as i32, args[1], args[2]), - SYS_WRITEV => Self::writev(args[0] as i32, args[1], args[2]), - - SYS_SET_TID_ADDRESS => Self::set_tid_address(args[0]), - - #[cfg(target_arch = "x86_64")] - SYS_LSTAT => { - let path = args[0] as *const u8; - let kstat = args[1] as *mut PosixKstat; - Self::lstat(path, kstat) - } - - #[cfg(target_arch = "x86_64")] - SYS_STAT => { - let path = args[0] as *const u8; - let kstat = args[1] as *mut PosixKstat; - Self::stat(path, kstat) - } - SYS_STATFS => { let path = args[0] as *const u8; let statfs = args[1] as *mut PosixStatfs; @@ -808,58 +598,14 @@ impl Syscall { Self::fstatfs(fd, statfs) } - SYS_STATX => { - let fd = args[0] as i32; - let path = args[1] as *const u8; - let flags = args[2] as u32; - let mask = args[3] as u32; - let kstat = args[4] as *mut PosixStatx; - - Self::do_statx(fd, path, flags, mask, kstat) - } - - #[cfg(target_arch = "x86_64")] - SYS_EPOLL_CREATE => Self::epoll_create(args[0] as i32), - SYS_EPOLL_CREATE1 => Self::epoll_create1(args[0]), - - SYS_EPOLL_CTL => Self::epoll_ctl( + SYS_STATX => Self::statx( args[0] as i32, args[1], - args[2] as i32, - VirtAddr::new(args[3]), + args[2] as u32, + args[3] as u32, + args[4], ), - #[cfg(target_arch = "x86_64")] - SYS_EPOLL_WAIT => Self::epoll_wait( - args[0] as i32, - VirtAddr::new(args[1]), - args[2] as i32, - args[3] as i32, - ), - - SYS_EPOLL_PWAIT => { - let epfd = args[0] as i32; - let epoll_event = VirtAddr::new(args[1]); - let max_events = args[2] as i32; - let timespec = args[3] as i32; - let sigmask_addr = args[4] as *mut SigSet; - - if sigmask_addr.is_null() { - return Self::epoll_wait(epfd, epoll_event, max_events, timespec); - } - let sigmask_reader = - UserBufferReader::new(sigmask_addr, core::mem::size_of::(), true)?; - let mut sigmask = *sigmask_reader.read_one_from_user::(0)?; - - Self::epoll_pwait( - args[0] as i32, - VirtAddr::new(args[1]), - args[2] as i32, - args[3] as i32, - &mut sigmask, - ) - } - // 目前为了适配musl-libc,以下系统调用先这样写着 SYS_GETRANDOM => { let flags = GRandFlags::from_bits(args[2] as u8).ok_or(SystemError::EINVAL)?; @@ -884,18 +630,7 @@ impl Syscall { Self::poll(fds, nfds, timeout) } - SYS_SETPGID => { - warn!("SYS_SETPGID has not yet been implemented"); - Ok(0) - } - - SYS_RT_SIGPROCMASK => { - let how = args[0] as i32; - let nset = args[1]; - let oset = args[2]; - let sigsetsize = args[3]; - Self::rt_sigprocmask(how, nset, oset, sigsetsize) - } + SYS_PPOLL => Self::ppoll(args[0], args[1] as u32, args[2], args[3]), SYS_TKILL => { warn!("SYS_TKILL has not yet been implemented"); @@ -907,23 +642,6 @@ impl Syscall { Ok(0) } - SYS_EXIT_GROUP => { - warn!("SYS_EXIT_GROUP has not yet been implemented"); - Ok(0) - } - - SYS_MADVISE => { - let addr = args[0]; - let len = page_align_up(args[1]); - if addr & (MMArch::PAGE_SIZE - 1) != 0 { - Err(SystemError::EINVAL) - } else { - Self::madvise(VirtAddr::new(addr), len, args[2]) - } - } - - SYS_GETTID => Self::gettid().map(|tid| tid.into()), - SYS_SYSLOG => { let syslog_action_type = args[0]; let buf_vaddr = args[1]; @@ -936,29 +654,6 @@ impl Syscall { Self::do_syslog(syslog_action_type, user_buf, len) } - SYS_GETUID => Self::getuid(), - SYS_GETGID => Self::getgid(), - SYS_SETUID => Self::setuid(args[0]), - SYS_SETGID => Self::setgid(args[0]), - - SYS_GETEUID => Self::geteuid(), - SYS_GETEGID => Self::getegid(), - SYS_SETRESUID => Self::seteuid(args[1]), - SYS_SETRESGID => Self::setegid(args[1]), - - SYS_SETFSUID => Self::setfsuid(args[0]), - SYS_SETFSGID => Self::setfsgid(args[0]), - - SYS_SETSID => { - warn!("SYS_SETSID has not yet been implemented"); - Ok(0) - } - - SYS_GETRUSAGE => { - let who = args[0] as c_int; - let rusage = args[1] as *mut RUsage; - Self::get_rusage(who, rusage) - } #[cfg(target_arch = "x86_64")] SYS_READLINK => { let path = args[0] as *const u8; @@ -975,16 +670,6 @@ impl Syscall { Self::readlink_at(dirfd, path, buf, bufsiz) } - SYS_PRLIMIT64 => { - let pid = args[0]; - let pid = Pid::new(pid); - let resource = args[1]; - let new_limit = args[2] as *const RLimit64; - let old_limit = args[3] as *mut RLimit64; - - Self::prlimit64(pid, resource, new_limit, old_limit) - } - #[cfg(target_arch = "x86_64")] SYS_ACCESS => { let pathname = args[0] as *const u8; @@ -1059,7 +744,7 @@ impl Syscall { SYS_RSEQ => { warn!("SYS_RSEQ has not yet been implemented"); - Ok(0) + Err(SystemError::ENOSYS) } #[cfg(target_arch = "x86_64")] @@ -1094,19 +779,6 @@ impl Syscall { Self::getaffinity(pid, set) } - #[cfg(target_arch = "x86_64")] - SYS_GETRLIMIT => { - let resource = args[0]; - let rlimit = args[1] as *mut RLimit64; - - Self::prlimit64( - ProcessManager::current_pcb().pid(), - resource, - core::ptr::null::(), - rlimit, - ) - } - SYS_FADVISE64 => { // todo: 这个系统调用还没有实现 @@ -1129,17 +801,10 @@ impl Syscall { return Ok(0); } - SYS_NEWFSTATAT => { - // todo: 这个系统调用还没有实现 - - Err(SystemError::ENOSYS) - } + #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] + SYS_NEWFSTATAT => Self::newfstatat(args[0] as i32, args[1], args[2], args[3] as u32), // SYS_SCHED_YIELD => Self::sched_yield(), - SYS_UNAME => { - let name = args[0] as *mut PosixOldUtsName; - Self::uname(name) - } SYS_PRCTL => { // todo: 这个系统调用还没有实现 @@ -1152,38 +817,6 @@ impl Syscall { Self::alarm(second) } - SYS_SHMGET => { - let key = ShmKey::new(args[0]); - let size = args[1]; - let shmflg = ShmFlags::from_bits_truncate(args[2] as u32); - - Self::shmget(key, size, shmflg) - } - SYS_SHMAT => { - let id = ShmId::new(args[0]); - let vaddr = VirtAddr::new(args[1]); - let shmflg = ShmFlags::from_bits_truncate(args[2] as u32); - - Self::shmat(id, vaddr, shmflg) - } - SYS_SHMDT => { - let vaddr = VirtAddr::new(args[0]); - Self::shmdt(vaddr) - } - SYS_SHMCTL => { - let id = ShmId::new(args[0]); - let cmd = ShmCtlCmd::from(args[1]); - let user_buf = args[2] as *const u8; - let from_user = frame.is_from_user(); - - Self::shmctl(id, cmd, user_buf, from_user) - } - SYS_MSYNC => { - let start = page_align_up(args[0]); - let len = page_align_up(args[1]); - let flags = args[2]; - Self::msync(VirtAddr::new(start), len, flags) - } SYS_UTIMENSAT => Self::sys_utimensat( args[0] as i32, args[1] as *const u8, @@ -1227,8 +860,13 @@ impl Syscall { let flags = args[4] as u32; Self::sys_perf_event_open(attr, pid, cpu, group_fd, flags) } + #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] SYS_SETRLIMIT => Ok(0), - SYS_RESTART_SYSCALL => Self::restart_syscall(), + + SYS_RT_SIGTIMEDWAIT => { + log::warn!("SYS_RT_SIGTIMEDWAIT has not yet been implemented"); + Ok(0) + } _ => panic!("Unsupported syscall ID: {}", syscall_num), }; @@ -1261,3 +899,9 @@ impl Syscall { return Ok(s.len()); } } + +#[inline(never)] +pub fn syscall_init() -> Result<(), SystemError> { + syscall_table_init()?; + Ok(()) +} diff --git a/kernel/src/syscall/table.rs b/kernel/src/syscall/table.rs new file mode 100644 index 00000000..4c3b6891 --- /dev/null +++ b/kernel/src/syscall/table.rs @@ -0,0 +1,130 @@ +#![allow(unused)] + +use alloc::string::String; +use alloc::string::ToString; +use alloc::vec::Vec; +use core::cell::OnceCell; +use core::fmt::Display; + +use crate::arch::interrupt::TrapFrame; +use crate::libs::once::Once; +use crate::syscall::SystemError; + +/// 定义Syscall trait +pub trait Syscall: Send + Sync + 'static { + /// 系统调用参数数量 + fn num_args(&self) -> usize; + fn handle(&self, args: &[usize], frame: &mut TrapFrame) -> Result; + + /// Formats the system call parameters for display/debug purposes + /// + /// # Arguments + /// * `args` - System call arguments to format + /// + /// # Returns + /// Vector of formatted parameters with their names and values + fn entry_format(&self, args: &[usize]) -> Vec; +} + +pub struct FormattedSyscallParam { + pub name: &'static str, + pub value: String, +} + +impl FormattedSyscallParam { + pub fn new(name: &'static str, value: String) -> Self { + Self { name, value } + } +} + +impl Display for FormattedSyscallParam { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}: {}", self.name, self.value) + } +} + +/// 系统调用处理句柄 +#[repr(C)] +pub struct SyscallHandle { + pub nr: usize, + pub inner_handle: &'static dyn Syscall, + pub name: &'static str, +} + +impl SyscallHandle { + #[inline(never)] + pub fn args_string(&self, args: &[usize]) -> String { + let args_slice = self.inner_handle.entry_format(args); + args_slice + .iter() + .map(|p| format!("{}", p)) + .collect::>() + .join(", ") + } +} + +/// 系统调用表类型 +#[repr(C)] +pub struct SyscallTable { + entries: [Option<&'static SyscallHandle>; Self::ENTRIES], +} + +impl SyscallTable { + pub const ENTRIES: usize = 512; + /// 获取系统调用处理函数 + pub fn get(&self, nr: usize) -> Option<&'static SyscallHandle> { + *self.entries.get(nr)? + } +} + +// 声明外部链接的syscall_table符号 +extern "C" { + fn _syscall_table(); + fn _esyscall_table(); +} + +/// 全局系统调用表实例 +#[used] +#[link_section = ".data"] +static mut SYS_CALL_TABLE: SyscallTable = SyscallTable { + entries: [None; SyscallTable::ENTRIES], +}; + +#[inline] +pub(super) fn syscall_table() -> &'static SyscallTable { + unsafe { &SYS_CALL_TABLE } +} + +/// 初始化系统调用表 +#[inline(never)] +pub(super) fn syscall_table_init() -> Result<(), SystemError> { + static INIT: Once = Once::new(); + INIT.call_once(|| { + log::debug!("Initializing syscall table..."); + + // 初始化系统调用表 + unsafe { + let start = _syscall_table as usize; + let end = _esyscall_table as usize; + let size = end - start; + let count = size / core::mem::size_of::(); + + if size % core::mem::size_of::() != 0 { + panic!("Invalid syscall table size: {}", size); + } + + let handles = + core::slice::from_raw_parts(_syscall_table as *const SyscallHandle, count); + for handle in handles { + if handle.nr < SyscallTable::ENTRIES { + SYS_CALL_TABLE.entries[handle.nr] = Some(handle); + } else { + panic!("Invalid syscall number: {}", handle.nr); + } + } + + log::debug!("Syscall table (count: {count}) initialized successfully.") + } + }); + Ok(()) +} diff --git a/kernel/src/time/jiffies.rs b/kernel/src/time/jiffies.rs index 4025295f..c3a9ecde 100644 --- a/kernel/src/time/jiffies.rs +++ b/kernel/src/time/jiffies.rs @@ -110,8 +110,3 @@ pub fn jiffies_init() { } }; } - -#[no_mangle] -pub extern "C" fn rs_jiffies_init() { - jiffies_init(); -} diff --git a/kernel/src/time/mod.rs b/kernel/src/time/mod.rs index 12947310..30c0d0a0 100644 --- a/kernel/src/time/mod.rs +++ b/kernel/src/time/mod.rs @@ -65,6 +65,10 @@ impl PosixTimeSpec { }; } + pub fn is_empty(&self) -> bool { + self.tv_nsec == 0 && self.tv_sec == 0 + } + /// 获取当前时间 #[inline(always)] pub fn now() -> Self { @@ -86,7 +90,7 @@ impl PosixTimeSpec { } } - #[cfg(target_arch = "riscv64")] + #[cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))] { return PosixTimeSpec::new(0, 0); } @@ -288,6 +292,23 @@ impl Instant { let micros_diff = self.micros - earlier.micros; Some(Duration::from_micros(micros_diff as u64)) } + + /// Saturating subtraction. Computes `self - other`, returning [`Instant::ZERO`] if the result would be negative. + /// + /// # Arguments + /// + /// * `other` - The `Instant` to subtract from `self`. + /// + /// # Returns + /// + /// The duration between `self` and `other`, or [`Instant::ZERO`] if `other` is later than `self`. + pub fn saturating_sub(self, other: Instant) -> Duration { + if self.micros >= other.micros { + Duration::from_micros((self.micros - other.micros) as u64) + } else { + Duration::ZERO + } + } } impl fmt::Display for Instant { diff --git a/kernel/src/time/timer.rs b/kernel/src/time/timer.rs index 35a3a13b..ca5a2412 100644 --- a/kernel/src/time/timer.rs +++ b/kernel/src/time/timer.rs @@ -386,10 +386,3 @@ pub fn update_timer_jiffies(add_jiffies: u64) -> u64 { pub fn clock() -> u64 { return TIMER_JIFFIES.load(Ordering::SeqCst); } - -// ====== 以下为给C提供的接口 ====== - -#[no_mangle] -pub extern "C" fn rs_timer_init() { - timer_init(); -} diff --git a/kernel/src/tracepoint/basic_macro.rs b/kernel/src/tracepoint/basic_macro.rs new file mode 100644 index 00000000..1663aad1 --- /dev/null +++ b/kernel/src/tracepoint/basic_macro.rs @@ -0,0 +1,175 @@ +/// Define a tracepoint with the given parameters. +/// +/// This macro generates a tracepoint with the specified name, arguments, entry structure, assignment logic, identifier, and print format. +/// # Parameters +/// - `name`: The name of the tracepoint. +/// - `TP_system`: The subsystem or system to which the tracepoint belongs. +/// - `TP_PROTO`: The prototype of the tracepoint function. +/// - `TP_STRUCT__entry`: The structure of the tracepoint entry. +/// - `TP_fast_assign`: The assignment logic for the tracepoint entry. +/// - `TP_ident`: The identifier for the tracepoint entry. +/// - `TP_printk`: The print format for the tracepoint. +/// +/// # Example +/// ```rust +/// define_event_trace!( +/// TEST2, +/// TP_PROTO(a: u32, b: u32), +/// TP_STRUCT__entry{ +/// a: u32, +/// b: u32, +/// }, +/// TP_fast_assign{ +/// a:a, +/// b:{ +/// // do something with b +/// b +/// } +/// }, +/// TP_ident(__entry), +/// TP_printk({ +/// // do something with __entry +/// format!("Hello from tracepoint! a={}, b={}", __entry.a, __entry.b) +/// }) +/// ); +/// ``` +#[macro_export] +macro_rules! define_event_trace{ + ( + $name:ident, + TP_system($system:ident), + TP_PROTO($($arg:ident:$arg_type:ty),*), + TP_STRUCT__entry{$($entry:ident:$entry_type:ty,)*}, + TP_fast_assign{$($assign:ident:$value:expr,)*}, + TP_ident($tp_ident:ident), + TP_printk($fmt_expr: expr) + ) => { + paste::paste!{ + static_keys::define_static_key_false!([<__ $name _KEY>]); + #[allow(non_upper_case_globals)] + #[used] + static [<__ $name>]: $crate::tracepoint::TracePoint = $crate::tracepoint::TracePoint::new(&[<__ $name _KEY>],stringify!($name), stringify!($system),[], []); + + #[inline(always)] + #[allow(non_snake_case)] + pub fn []( $($arg:$arg_type),* ){ + if static_keys::static_branch_unlikely!([<__ $name _KEY>]){ + let mut f = |trace_func: &$crate::tracepoint::TracePointFunc |{ + let func = trace_func.func; + let data = trace_func.data.as_ref(); + let func = unsafe{core::mem::transmute::(func)}; + func(data $(,$arg)*); + }; + let trace_point = &[<__ $name>]; + trace_point.callback_list(&mut f); + } + } + #[allow(unused,non_snake_case)] + pub fn [](func: fn(& (dyn core::any::Any+Send+Sync), $($arg_type),*), data: alloc::boxed::Box){ + let func = unsafe{core::mem::transmute::(func)}; + [<__ $name>].register(func,data); + } + #[allow(unused,non_snake_case)] + pub fn [](func: fn(& (dyn core::any::Any+Send+Sync), $($arg_type),*)){ + let func = unsafe{core::mem::transmute::(func)}; + [<__ $name>].unregister(func); + } + + + #[derive(Debug)] + #[repr(C)] + #[allow(non_snake_case,non_camel_case_types)] + struct [<__ $name _TracePointMeta>]{ + trace_point: &'static $crate::tracepoint::TracePoint, + print_func: fn(&mut (dyn core::any::Any+Send+Sync), $($arg_type),*), + } + + #[allow(non_upper_case_globals)] + #[link_section = ".tracepoint"] + #[used] + static [<__ $name _meta>]: [<__ $name _TracePointMeta>] = [<__ $name _TracePointMeta>]{ + trace_point:& [<__ $name>], + print_func:[], + }; + + #[allow(unused,non_snake_case)] + pub fn [](_data:&mut (dyn core::any::Any+Send+Sync), $($arg:$arg_type),* ){ + #[repr(C)] + struct Entry { + $($entry: $entry_type,)* + } + #[repr(C)] + struct FullEntry { + common: $crate::tracepoint::TraceEntry, + entry: Entry, + } + + let entry = Entry { + $($assign: $value,)* + }; + + let process = $crate::process::ProcessManager::current_pcb(); + let pid = process.pid().data() as _; + + let common = $crate::tracepoint::TraceEntry { + type_: [<__ $name>].id() as _, + flags: [<__ $name>].flags(), + preempt_count: 0, + pid, + }; + + let full_entry = FullEntry { + common, + entry, + }; + + let event_buf = unsafe { + core::slice::from_raw_parts( + &full_entry as *const FullEntry as *const u8, + core::mem::size_of::(), + ) + }; + $crate::debug::tracing::trace_cmdline_push(pid as u32); + $crate::debug::tracing::trace_pipe_push_raw_record(event_buf); + } + + #[allow(unused,non_snake_case)] + pub fn [](buf_ptr: *const u8) -> alloc::string::String { + #[repr(C)] + struct Entry { + $($entry: $entry_type,)* + } + let $tp_ident = unsafe { + &*(buf_ptr as *const Entry) + }; + let fmt = format!("{}", $fmt_expr); + fmt + } + + #[allow(unused,non_snake_case)] + pub fn []()-> alloc::string::String { + let mut fmt = format!("format: +\tfield: u16 common_type; offset: 0; size: 2; signed: 0; +\tfield: u8 common_flags; offset: 2; size: 1; signed: 0; +\tfield: u8 common_preempt_count; offset: 3; size: 1; signed: 0; +\tfield: i32 common_pid; offset: 4; size: 4; signed: 1; + +"); + fn is_signed() -> bool { + match core::any::type_name::() { + "i8" | "i16" | "i32" | "i64" | "i128" | "isize" => true, + _ => false, + } + } + let mut offset = 8; + $( + fmt.push_str(&format!("\tfield: {} {} offset: {}; size: {}; signed: {};\n", + stringify!($entry_type), stringify!($entry), offset, core::mem::size_of::<$entry_type>(), if is_signed::<$entry_type>() { 1 } else { 0 })); + offset += core::mem::size_of::<$entry_type>(); + )* + fmt.push_str(&format!("\nprint fmt: \"{}\"", stringify!($fmt_expr))); + fmt + } + } + }; +} diff --git a/kernel/src/tracepoint/mod.rs b/kernel/src/tracepoint/mod.rs new file mode 100644 index 00000000..b963d43d --- /dev/null +++ b/kernel/src/tracepoint/mod.rs @@ -0,0 +1,293 @@ +#![allow(clippy::new_without_default)] + +mod basic_macro; +mod point; +mod trace_pipe; + +use alloc::{ + boxed::Box, + collections::BTreeMap, + string::{String, ToString}, + sync::Arc, + vec::Vec, +}; +use core::{ + ops::{Deref, DerefMut}, + sync::atomic::AtomicUsize, +}; +pub use point::{CommonTracePointMeta, TraceEntry, TracePoint, TracePointFunc}; +use system_error::SystemError; +pub use trace_pipe::{ + TraceCmdLineCache, TraceEntryParser, TracePipeOps, TracePipeRaw, TracePipeSnapshot, +}; + +use crate::libs::spinlock::{SpinLock, SpinLockGuard}; + +#[derive(Debug)] +pub struct TracePointMap(BTreeMap); + +impl TracePointMap { + /// Create a new TracePointMap + fn new() -> Self { + Self(BTreeMap::new()) + } +} + +impl Deref for TracePointMap { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for TracePointMap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[derive(Debug)] +pub struct TracingEventsManager { + subsystems: SpinLock>>, + map: SpinLock, +} + +impl TracingEventsManager { + fn new(map: TracePointMap) -> Self { + Self { + subsystems: SpinLock::new(BTreeMap::new()), + map: SpinLock::new(map), + } + } + + /// Get the tracepoint map + pub fn tracepoint_map(&self) -> SpinLockGuard { + self.map.lock() + } + + /// Create a subsystem by name + /// + /// If the subsystem already exists, return the existing subsystem. + fn create_subsystem(&self, subsystem_name: &str) -> Arc { + if self.subsystems.lock().contains_key(subsystem_name) { + return self + .get_subsystem(subsystem_name) + .expect("Subsystem should exist"); + } + let subsystem = Arc::new(EventsSubsystem::new()); + self.subsystems + .lock() + .insert(subsystem_name.to_string(), subsystem.clone()); + subsystem + } + + /// Get the subsystem by name + pub fn get_subsystem(&self, subsystem_name: &str) -> Option> { + self.subsystems.lock().get(subsystem_name).cloned() + } + + #[allow(unused)] + /// Remove the subsystem by name + pub fn remove_subsystem(&self, subsystem_name: &str) -> Option> { + self.subsystems.lock().remove(subsystem_name) + } + + /// Get all subsystems + pub fn subsystem_names(&self) -> Vec { + let res = self + .subsystems + .lock() + .keys() + .cloned() + .collect::>(); + res + } +} + +#[derive(Debug)] +pub struct EventsSubsystem { + events: SpinLock>>, +} + +impl EventsSubsystem { + fn new() -> Self { + Self { + events: SpinLock::new(BTreeMap::new()), + } + } + + /// Create an event by name + fn create_event(&self, event_name: &str, event_info: TracePointInfo) { + self.events + .lock() + .insert(event_name.to_string(), Arc::new(event_info)); + } + + /// Get the event by name + pub fn get_event(&self, event_name: &str) -> Option> { + self.events.lock().get(event_name).cloned() + } + + /// Get all events in the subsystem + pub fn event_names(&self) -> Vec { + let res = self.events.lock().keys().cloned().collect::>(); + res + } +} +#[derive(Debug)] +pub struct TracePointInfo { + enable: TracePointEnableFile, + tracepoint: &'static TracePoint, + format: TracePointFormatFile, + id: TracePointIdFile, + // filter:, + // trigger:, +} + +impl TracePointInfo { + fn new(tracepoint: &'static TracePoint) -> Self { + let enable = TracePointEnableFile::new(tracepoint); + let format = TracePointFormatFile::new(tracepoint); + let id = TracePointIdFile::new(tracepoint); + Self { + enable, + tracepoint, + format, + id, + } + } + + /// Get the tracepoint + pub fn tracepoint(&self) -> &'static TracePoint { + self.tracepoint + } + + /// Get the enable file + pub fn enable_file(&self) -> &TracePointEnableFile { + &self.enable + } + + /// Get the format file + pub fn format_file(&self) -> &TracePointFormatFile { + &self.format + } + + /// Get the ID file + pub fn id_file(&self) -> &TracePointIdFile { + &self.id + } +} + +/// TracePointFormatFile provides a way to get the format of the tracepoint. +#[derive(Debug, Clone)] +pub struct TracePointFormatFile { + tracepoint: &'static TracePoint, +} + +impl TracePointFormatFile { + fn new(tracepoint: &'static TracePoint) -> Self { + Self { tracepoint } + } + + /// Read the tracepoint format + /// + /// Returns the format string of the tracepoint. + pub fn read(&self) -> String { + self.tracepoint.print_fmt() + } +} + +#[derive(Debug, Clone)] +pub struct TracePointEnableFile { + tracepoint: &'static TracePoint, +} + +impl TracePointEnableFile { + fn new(tracepoint: &'static TracePoint) -> Self { + Self { tracepoint } + } + + /// Read the tracepoint status + /// + /// Returns true if the tracepoint is enabled, false otherwise. + pub fn read(&self) -> &'static str { + if self.tracepoint.is_enabled() { + "1\n" + } else { + "0\n" + } + } + /// Enable or disable the tracepoint + pub fn write(&self, enable: char) { + match enable { + '1' => self.tracepoint.enable(), + '0' => self.tracepoint.disable(), + _ => { + log::warn!("Invalid value for tracepoint enable: {}", enable); + } + } + } +} + +#[derive(Debug, Clone)] +pub struct TracePointIdFile { + tracepoint: &'static TracePoint, +} + +impl TracePointIdFile { + fn new(tracepoint: &'static TracePoint) -> Self { + Self { tracepoint } + } + + /// Read the tracepoint ID + /// + /// Returns the ID of the tracepoint. + pub fn read(&self) -> String { + format!("{}\n", self.tracepoint.id()) + } +} + +extern "C" { + fn _tracepoint(); + fn _etracepoint(); +} + +/// Initialize the tracing events +pub fn global_init_events() -> Result { + static TRACE_POINT_ID: AtomicUsize = AtomicUsize::new(0); + let events_manager = TracingEventsManager::new(TracePointMap::new()); + let tracepoint_data_start = _tracepoint as usize as *mut CommonTracePointMeta; + let tracepoint_data_end = _etracepoint as usize as *mut CommonTracePointMeta; + log::info!( + "tracepoint_data_start: {:#x}, tracepoint_data_end: {:#x}", + tracepoint_data_start as usize, + tracepoint_data_end as usize + ); + let tracepoint_data_len = (tracepoint_data_end as usize - tracepoint_data_start as usize) + / size_of::(); + let tracepoint_data = + unsafe { core::slice::from_raw_parts_mut(tracepoint_data_start, tracepoint_data_len) }; + + log::info!("tracepoint_data_len: {}", tracepoint_data_len); + + let mut tracepoint_map = events_manager.tracepoint_map(); + for tracepoint_meta in tracepoint_data { + let tracepoint = tracepoint_meta.trace_point; + let id = TRACE_POINT_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + tracepoint.set_id(id as u32); + tracepoint.register(tracepoint_meta.print_func, Box::new(())); + tracepoint_map.insert(id as u32, tracepoint); + log::info!( + "tracepoint registered: {}:{}", + tracepoint.system(), + tracepoint.name(), + ); + let subsys_name = tracepoint.system(); + let subsys = events_manager.create_subsystem(subsys_name); + let event_info = TracePointInfo::new(tracepoint); + subsys.create_event(tracepoint.name(), event_info); + } + drop(tracepoint_map); // Release the lock on the tracepoint map + Ok(events_manager) +} diff --git a/kernel/src/tracepoint/point.rs b/kernel/src/tracepoint/point.rs new file mode 100644 index 00000000..00275908 --- /dev/null +++ b/kernel/src/tracepoint/point.rs @@ -0,0 +1,179 @@ +use crate::libs::spinlock::SpinLock; +use alloc::{boxed::Box, collections::BTreeMap, format, string::String}; +use core::{any::Any, sync::atomic::AtomicU32}; +use static_keys::StaticFalseKey; + +#[derive(Debug)] +#[repr(C)] +pub struct TraceEntry { + pub type_: u16, + pub flags: u8, + pub preempt_count: u8, + pub pid: i32, +} + +impl TraceEntry { + pub fn trace_print_lat_fmt(&self) -> String { + // todo!("Implement IRQs off logic"); + let irqs_off = '.'; + let resched = '.'; + let hardsoft_irq = '.'; + let mut preempt_low = '.'; + if self.preempt_count & 0xf != 0 { + preempt_low = ((b'0') + (self.preempt_count & 0xf)) as char; + } + let mut preempt_high = '.'; + if self.preempt_count >> 4 != 0 { + preempt_high = ((b'0') + (self.preempt_count >> 4)) as char; + } + format!( + "{}{}{}{}{}", + irqs_off, resched, hardsoft_irq, preempt_low, preempt_high + ) + } +} + +pub struct TracePoint { + name: &'static str, + system: &'static str, + key: &'static StaticFalseKey, + id: AtomicU32, + inner: SpinLock, + trace_entry_fmt_func: fn(*const u8) -> String, + trace_print_func: fn() -> String, + flags: u8, +} + +struct TracePointInner { + callback: BTreeMap, +} + +impl core::fmt::Debug for TracePoint { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("TracePoint") + .field("name", &self.name) + .field("system", &self.system) + .field("id", &self.id()) + .field("flags", &self.flags) + .finish() + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct CommonTracePointMeta { + pub trace_point: &'static TracePoint, + pub print_func: fn(), +} + +#[derive(Debug)] +pub struct TracePointFunc { + pub func: fn(), + pub data: Box, +} + +impl TracePoint { + pub const fn new( + key: &'static StaticFalseKey, + name: &'static str, + system: &'static str, + fmt_func: fn(*const u8) -> String, + trace_print_func: fn() -> String, + ) -> Self { + Self { + name, + system, + key, + id: AtomicU32::new(0), + flags: 0, + trace_entry_fmt_func: fmt_func, + trace_print_func, + inner: SpinLock::new(TracePointInner { + callback: BTreeMap::new(), + }), + } + } + + /// Returns the name of the tracepoint. + pub fn name(&self) -> &'static str { + self.name + } + + /// Returns the system of the tracepoint. + pub fn system(&self) -> &'static str { + self.system + } + + /// Sets the ID of the tracepoint. + pub(crate) fn set_id(&self, id: u32) { + self.id.store(id, core::sync::atomic::Ordering::Relaxed); + } + + /// Returns the ID of the tracepoint. + pub fn id(&self) -> u32 { + self.id.load(core::sync::atomic::Ordering::Relaxed) + } + + /// Returns the flags of the tracepoint. + pub fn flags(&self) -> u8 { + self.flags + } + + /// Returns the format function for the tracepoint. + pub(crate) fn fmt_func(&self) -> fn(*const u8) -> String { + self.trace_entry_fmt_func + } + + /// Returns a string representation of the format function for the tracepoint. + /// + /// You can use `cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_openat/format` in linux + /// to see the format of the tracepoint. + pub fn print_fmt(&self) -> String { + let post_str = (self.trace_print_func)(); + format!("name: {}\nID: {}\n{}\n", self.name(), self.id(), post_str) + } + + /// Register a callback function to the tracepoint + pub fn register(&self, func: fn(), data: Box) { + let trace_point_func = TracePointFunc { func, data }; + let ptr = func as usize; + self.inner + .lock() + .callback + .entry(ptr) + .or_insert(trace_point_func); + } + + /// Unregister a callback function from the tracepoint + pub fn unregister(&self, func: fn()) { + let func_ptr = func as usize; + self.inner.lock().callback.remove(&func_ptr); + } + + /// Iterate over all registered callback functions + pub fn callback_list(&self, f: &dyn Fn(&TracePointFunc)) { + let inner = self.inner.lock(); + for trace_func in inner.callback.values() { + f(trace_func); + } + } + + /// Enable the tracepoint + pub fn enable(&self) { + unsafe { + self.key.enable(); + } + } + + /// Disable the tracepoint + pub fn disable(&self) { + unsafe { + self.key.disable(); + } + } + + /// Check if the tracepoint is enabled + pub fn is_enabled(&self) -> bool { + self.key.is_enabled() + } +} diff --git a/kernel/src/tracepoint/trace_pipe.rs b/kernel/src/tracepoint/trace_pipe.rs new file mode 100644 index 00000000..a92a6565 --- /dev/null +++ b/kernel/src/tracepoint/trace_pipe.rs @@ -0,0 +1,221 @@ +use crate::tracepoint::{TraceEntry, TracePointMap}; +use alloc::{format, string::String, vec::Vec}; + +pub trait TracePipeOps { + /// Returns the first event in the trace pipe buffer without removing it. + fn peek(&self) -> Option<&Vec>; + + /// Remove and return the first event in the trace pipe buffer. + fn pop(&mut self) -> Option>; + + /// Whether the trace pipe buffer is empty. + fn is_empty(&self) -> bool; +} + +/// A raw trace pipe buffer that stores trace events as byte vectors. +pub struct TracePipeRaw { + max_record: usize, + event_buf: Vec>, +} + +impl TracePipeRaw { + pub const fn new(max_record: usize) -> Self { + Self { + max_record, + event_buf: Vec::new(), + } + } + + /// Set the maximum number of records to keep in the trace pipe buffer. + /// + /// If the current number of records exceeds this limit, the oldest records will be removed. + pub fn set_max_record(&mut self, max_record: usize) { + self.max_record = max_record; + if self.event_buf.len() > max_record { + self.event_buf.truncate(max_record); // Keep only the latest records + } + } + + /// Push a new event into the trace pipe buffer. + pub fn push_event(&mut self, event: Vec) { + if self.event_buf.len() >= self.max_record { + self.event_buf.remove(0); // Remove the oldest record + } + self.event_buf.push(event); + } + + /// The number of events currently in the trace pipe buffer. + pub fn event_count(&self) -> usize { + self.event_buf.len() + } + + /// Clear the trace pipe buffer. + pub fn clear(&mut self) { + self.event_buf.clear(); + } + + /// Create a snapshot of the current state of the trace pipe buffer. + pub fn snapshot(&self) -> TracePipeSnapshot { + TracePipeSnapshot::new(self.event_buf.clone()) + } +} + +impl TracePipeOps for TracePipeRaw { + fn peek(&self) -> Option<&Vec> { + self.event_buf.first() + } + + fn pop(&mut self) -> Option> { + if self.event_buf.is_empty() { + None + } else { + Some(self.event_buf.remove(0)) + } + } + + fn is_empty(&self) -> bool { + self.event_buf.is_empty() + } +} + +#[derive(Debug)] +pub struct TracePipeSnapshot(Vec>); + +impl TracePipeSnapshot { + pub fn new(event_buf: Vec>) -> Self { + Self(event_buf) + } + + /// The formatted string representation to be used as a header for the trace pipe output. + pub fn default_fmt_str(&self) -> String { + let show = "# +# +# _-----=> irqs-off/BH-disabled +# / _----=> need-resched +# | / _---=> hardirq/softirq +# || / _--=> preempt-depth +# ||| / _-=> migrate-disable +# |||| / delay +# TASK-PID CPU# ||||| TIMESTAMP FUNCTION +# | | | ||||| | | +"; + format!( + "# tracer: nop\n#\n# entries-in-buffer/entries-written: {}/{} #P:32\n{}", + self.0.len(), + self.0.len(), + show + ) + } +} + +impl TracePipeOps for TracePipeSnapshot { + fn peek(&self) -> Option<&Vec> { + self.0.first() + } + + fn pop(&mut self) -> Option> { + if self.0.is_empty() { + None + } else { + Some(self.0.remove(0)) + } + } + + fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +/// A cache for storing command line arguments for each trace point. +/// +/// See https://www.kernel.org/doc/Documentation/trace/ftrace.txt +pub struct TraceCmdLineCache { + cmdline: Vec<(u32, [u8; 16])>, + max_record: usize, +} + +impl TraceCmdLineCache { + pub const fn new(max_record: usize) -> Self { + Self { + cmdline: Vec::new(), + max_record, + } + } + + /// Insert a command line argument for a trace point. + /// + /// If the command line exceeds 16 bytes, it will be truncated. + /// If the cache exceeds the maximum record limit, the oldest entry will be removed. + pub fn insert(&mut self, id: u32, cmdline: String) { + if self.cmdline.len() >= self.max_record { + // Remove the oldest entry if we exceed the max record limit + self.cmdline.remove(0); + } + let mut cmdline_bytes = [0u8; 16]; + if cmdline.len() > 16 { + // Truncate to fit the fixed size + cmdline_bytes.copy_from_slice(&cmdline.as_bytes()[..16]); + } else { + // Copy the command line bytes into the fixed size array + cmdline_bytes[..cmdline.len()].copy_from_slice(cmdline.as_bytes()); + } + self.cmdline.push((id, cmdline_bytes)); + } + + /// Get the command line argument for a trace point. + pub fn get(&self, id: u32) -> Option<&str> { + self.cmdline.iter().find_map(|(key, value)| { + if *key == id { + Some(core::str::from_utf8(value).unwrap().trim_end_matches('\0')) + } else { + None + } + }) + } + + /// Set the maximum length for command line arguments. + pub fn set_max_record(&mut self, max_len: usize) { + self.max_record = max_len; + if self.cmdline.len() > max_len { + self.cmdline.truncate(max_len); // Keep only the latest records + } + } +} + +pub struct TraceEntryParser; + +impl TraceEntryParser { + /// Parse the trace entry and return a formatted string. + pub fn parse( + tracepoint_map: &TracePointMap, + cmdline_cache: &TraceCmdLineCache, + entry: &[u8], + ) -> String { + let trace_entry = unsafe { &*(entry.as_ptr() as *const TraceEntry) }; + let id = trace_entry.type_ as u32; + let tracepoint = tracepoint_map.get(&id).expect("TracePoint not found"); + let fmt_func = tracepoint.fmt_func(); + let offset = core::mem::size_of::(); + let str = fmt_func(unsafe { entry.as_ptr().add(offset) }); + + let time = crate::time::Instant::now().total_micros() * 1000; // Convert to nanoseconds + let cpu_id = crate::arch::cpu::current_cpu_id().data(); + + let pname = cmdline_cache.get(trace_entry.pid as u32).unwrap_or("<...>"); + + let secs = time / 1_000_000_000; + let usec_rem = time % 1_000_000_000 / 1000; + + format!( + "{:>16}-{:<7} [{:03}] {} {:5}.{:06}: {}({})\n", + pname, + trace_entry.pid, + cpu_id, + trace_entry.trace_print_lat_fmt(), + secs, + usec_rem, + tracepoint.name(), + str + ) + } +} diff --git a/kernel/src/virt/vm/kvm_dev.rs b/kernel/src/virt/vm/kvm_dev.rs index cab74f37..b64f0d6a 100644 --- a/kernel/src/virt/vm/kvm_dev.rs +++ b/kernel/src/virt/vm/kvm_dev.rs @@ -13,9 +13,9 @@ use crate::{ filesystem::{ devfs::{devfs_register, DevFS, DeviceINode}, vfs::{ - core::generate_inode_id, file::{File, FileMode}, syscall::ModeType, + vcore::generate_inode_id, FileType, IndexNode, Metadata, }, }, @@ -61,6 +61,7 @@ impl LockedKvmInode { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::KvmDevice, // 文件夹,block设备,char设备 mode: ModeType::S_IALLUGO, nlinks: 1, @@ -202,6 +203,7 @@ impl KvmInstance { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::KvmDevice, mode: ModeType::S_IALLUGO, nlinks: 1, @@ -332,6 +334,7 @@ impl KvmVcpuDev { atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), file_type: FileType::KvmDevice, // 文件夹,block设备,char设备 mode: ModeType::S_IALLUGO, nlinks: 1, diff --git a/tools/.gitignore b/tools/.gitignore index 832dff97..0634b300 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -5,5 +5,6 @@ arch/i386/efi/grub/* arch/x86_64/efi/grub/* *.tar.gz +*.tar.xz build/* target/ \ No newline at end of file diff --git a/tools/BUILD_CONTAINER_VERSION b/tools/BUILD_CONTAINER_VERSION index 8a9f2d79..f5a8e286 100644 --- a/tools/BUILD_CONTAINER_VERSION +++ b/tools/BUILD_CONTAINER_VERSION @@ -1 +1 @@ -v1.8 \ No newline at end of file +v1.12 \ No newline at end of file diff --git a/tools/bootstrap.sh b/tools/bootstrap.sh old mode 100644 new mode 100755 index ff6a5d96..e14535fee --- a/tools/bootstrap.sh +++ b/tools/bootstrap.sh @@ -43,7 +43,7 @@ congratulations() echo "| 请[关闭]当前终端, 并[重新打开]一个终端 |" echo "| 然后通过以下命令运行: |" echo "| |" - echo "| make run |" + echo "| make run-nographic |" echo "| |" echo "|------------------------------------------|" } @@ -232,8 +232,7 @@ rustInstall() { fi echo "正在安装DragonOS所需的rust组件...首次安装需要一些时间来更新索引,请耐心等待..." - cargo install cargo-binutils - cargo install bpf-linker + rustup toolchain install $RUST_VERSION-x86_64-unknown-linux-gnu rustup toolchain install $RUST_VERSION_OLD-x86_64-unknown-linux-gnu rustup component add rust-src --toolchain $RUST_VERSION-x86_64-unknown-linux-gnu @@ -242,18 +241,21 @@ rustInstall() { rustup target add x86_64-unknown-none --toolchain $RUST_VERSION_OLD-x86_64-unknown-linux-gnu rustup target add x86_64-unknown-linux-musl --toolchain $RUST_VERSION-x86_64-unknown-linux-gnu rustup target add x86_64-unknown-linux-musl --toolchain $RUST_VERSION_OLD-x86_64-unknown-linux-gnu + rustup target add riscv64gc-unknown-none-elf --toolchain $RUST_VERSION-x86_64-unknown-linux-gnu + rustup target add riscv64gc-unknown-none-elf --toolchain $RUST_VERSION_OLD-x86_64-unknown-linux-gnu + rustup target add riscv64imac-unknown-none-elf --toolchain $RUST_VERSION-x86_64-unknown-linux-gnu + rustup target add riscv64imac-unknown-none-elf --toolchain $RUST_VERSION_OLD-x86_64-unknown-linux-gnu + rustup target add riscv64gc-unknown-linux-musl --toolchain $RUST_VERSION-x86_64-unknown-linux-gnu + rustup target add riscv64gc-unknown-linux-musl --toolchain $RUST_VERSION_OLD-x86_64-unknown-linux-gnu + rustup target add loongarch64-unknown-none --toolchain $RUST_VERSION-x86_64-unknown-linux-gnu + rustup target add loongarch64-unknown-none --toolchain $RUST_VERSION_OLD-x86_64-unknown-linux-gnu - rustup toolchain install $RUST_VERSION-riscv64gc-unknown-linux-gnu --force-non-host - rustup toolchain install $RUST_VERSION_OLD-riscv64gc-unknown-linux-gnu --force-non-host - rustup target add riscv64gc-unknown-none-elf --toolchain $RUST_VERSION-riscv64gc-unknown-linux-gnu - rustup target add riscv64imac-unknown-none-elf --toolchain $RUST_VERSION-riscv64gc-unknown-linux-gnu - rustup target add riscv64gc-unknown-none-elf --toolchain $RUST_VERSION_OLD-riscv64gc-unknown-linux-gnu - rustup target add riscv64imac-unknown-none-elf --toolchain $RUST_VERSION_OLD-riscv64gc-unknown-linux-gnu - rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu rustup component add rust-src rustup component add llvm-tools-preview rustup default $RUST_VERSION + cargo install cargo-binutils + cargo install bpf-linker echo "Rust已经成功的在您的计算机上安装!请运行 source ~/.cargo/env 以使rust在当前窗口生效!" fi @@ -267,6 +269,8 @@ install_python_pkg() } + + ############# 脚本开始 ############## # 读取参数及选项,使用 -help 参数查看详细选项 while true; do @@ -334,12 +338,12 @@ rustInstall install_python_pkg # 安装dadk -cargo install dadk || exit 1 +cargo install --git https://git.mirrors.dragonos.org.cn/DragonOS-Community/DADK.git --tag v0.4.0 || exit 1 bashpath=$(cd `dirname $0`; pwd) # 编译安装musl交叉编译工具链 -$SHELL ${bashpath}/install_musl_gcc.sh || (echo "musl交叉编译工具链安装失败" && exit 1) +$SHELL ${bashpath}/install_cross_gcc.sh || (echo "musl交叉编译工具链安装失败" && exit 1) # 编译安装grub $SHELL ${bashpath}/grub_auto_install.sh || (echo "grub安装失败" && exit 1) diff --git a/tools/build_gcc_toolchain.sh b/tools/build_gcc_toolchain.sh old mode 100644 new mode 100755 diff --git a/tools/build_in_docker.sh b/tools/build_in_docker.sh old mode 100644 new mode 100755 index 206f1797..db679c94 --- a/tools/build_in_docker.sh +++ b/tools/build_in_docker.sh @@ -1,6 +1,6 @@ docker rm -f dragonos-build || echo "No existed container" cpu_count=$(cat /proc/cpuinfo |grep "processor"|wc -l) -docker run --rm --privileged=true --cap-add SYS_ADMIN --cap-add MKNOD -v $(pwd):/data -v /dev:/dev -v dragonos-build-cargo:/root/.cargo/registry --name dragonos-build -i dragonos/dragonos-dev:v1.8 bash << EOF +docker run --rm --privileged=true --cap-add SYS_ADMIN --cap-add MKNOD -v $(pwd):/data -v /dev:/dev -v dragonos-build-cargo:/root/.cargo/registry --name dragonos-build -i dragonos/dragonos-dev:v1.12 bash << EOF source ~/.cargo/env source ~/.bashrc cd /data diff --git a/tools/change_rust_src.sh b/tools/change_rust_src.sh old mode 100644 new mode 100755 diff --git a/tools/check_arch.sh b/tools/check_arch.sh old mode 100644 new mode 100755 diff --git a/tools/configure_network.sh b/tools/configure_network.sh old mode 100644 new mode 100755 diff --git a/tools/doc_translator.py b/tools/doc_translator.py new file mode 100644 index 00000000..176d1946 --- /dev/null +++ b/tools/doc_translator.py @@ -0,0 +1,472 @@ +#!/usr/bin/env python3 +""" +DragonOS文档自动翻译工具 +Usage: +在DragonOS源码根目录下运行此脚本。 + +需要先进入docs目录,执行命令安装依赖包。 +pip install -r requirements.txt + +接着先声明以下变量: +export OPENAI_API_KEY=your_api_key +export OPENAI_MODEL=your_model_name (推荐qwen3的4b以上的) +export OPENAI_BASE_URL=your_openai_base_url +export MAX_WORKERS=your_max_workers (推荐2-20) + +然后运行: +python3 tools/doc_translator.py +""" + +import os +import re +import hashlib +import json +from pathlib import Path +import sys +import threading +from typing import List, Dict, Tuple +import openai +import datetime +import time + +from tqdm import tqdm + +# 配置 + + +def get_env_var(name, required=False, default=None): + """从环境变量获取配置""" + value = os.getenv(name, default) + if required and not value: + raise ValueError(f"环境变量 {name} 未设置") + return value + + +CONFIG = { + "source_dir": "docs", # 源文档目录 + "target_languages": { + "en": "English", + }, + "dirs_exclude": ["_build", "locales"], # 排除的目录 + "model": get_env_var("OPENAI_MODEL", default="qwen3:4b"), # 模型名称 + # API地址 + "base_url": get_env_var("OPENAI_BASE_URL", default="http://localhost:11434/v1"), + "chunk_size": 1000, # 分块大小(tokens) + "cache_file": "docs/.translation_cache.json", # 翻译缓存文件 + "max_workers": int(get_env_var("MAX_WORKERS", default="1")), # 并行工作数 + # 元数据模板 + "meta_templates": { + ".rst": ( + ".. note:: AI Translation Notice\n\n" + " This document was automatically translated by `{model}` model, for reference only.\n\n" + " - Source document: {original_path}\n\n" + " - Translation time: {timestamp}\n\n" + " - Translation model: `{model}`\n\n" + "\n Please report issues via `Community Channel `_\n\n" + ), + ".md": ( + ":::{note}\n" + "**AI Translation Notice**\n\n" + "This document was automatically translated by `{model}` model, for reference only.\n\n" + "- Source document: {original_path}\n\n" + "- Translation time: {timestamp}\n\n" + "- Translation model: `{model}`\n\n" + "Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues)\n\n" + ":::\n\n" + ) + } +} + + +class LabelManager: + """管理文档标签和引用""" + + def __init__(self, lang: str): + self.label_map = {} + self.prefix = "_translated_label_" + self.lang = lang + + def register_label(self, original_label: str) -> str: + """注册新标签并返回映射后的标签""" + if original_label not in self.label_map: + new_label = f"{self.prefix}_{original_label}_{self.lang}" + self.label_map[original_label] = new_label + return self.label_map[original_label] + + def get_all_labels(self) -> Dict[str, str]: + """获取所有标签映射""" + return self.label_map + + +class DocumentTranslator: + def __init__(self): + self._cache_lock = threading.Lock() + self._cache = self._load_cache() + self.fail_count = 0 + try: + self.client = openai.OpenAI( + base_url=CONFIG["base_url"], + # 这是故意把key的获取写在这里的。防止哪个二货直接print CONFIG导致key泄露。 + api_key=get_env_var("OPENAI_API_KEY", default="ollama"), + ) + except Exception as e: + raise RuntimeError(f"OpenAI客户端初始化失败: {str(e)}") + + def _load_cache(self) -> Dict: + """加载翻译缓存""" + if os.path.exists(CONFIG["cache_file"]): + with open(CONFIG["cache_file"], "r", encoding="utf-8") as f: + try: + return json.load(f) + except json.JSONDecodeError: + pass + return {} + + def _save_cache(self): + """保存翻译缓存""" + with self._cache_lock: + with open(CONFIG["cache_file"], "w", encoding="utf-8") as f: + json.dump(self._cache, f, ensure_ascii=False, indent=2) + + def _get_cache_key(self, filepath: str, lang: str) -> str: + """生成缓存键(包含语言代码)""" + rel_path = os.path.relpath(filepath, CONFIG["source_dir"]) + return f"{lang}:{rel_path}" + + def _split_into_chunks(self, text: str) -> List[str]: + """将文本分块""" + # 按段落分割 + paragraphs = re.split(r"\n\s*\n", text) + chunks = [] + current_chunk = [] + current_size = 0 + for para in paragraphs: + para_size = len(para.split()) + if current_size + para_size > CONFIG["chunk_size"] and current_chunk: + chunks.append("\n\n".join(current_chunk)) + current_chunk = [] + current_size = 0 + current_chunk.append(para) + current_size += para_size + + if current_chunk: + chunks.append("\n\n".join(current_chunk)) + + return chunks + + def _process_rst_labels(self, text: str, label_manager: LabelManager) -> str: + """处理reStructuredText标签""" + def replace_label(match): + original_label = match.group(1) + new_label = label_manager.register_label(original_label) + return f'.. {new_label}:' + + # 处理标签定义 + text = re.sub(r'\.\.\s+_([^:]+):', replace_label, text) + # 处理标签引用 + text = re.sub(r'(? str: + """处理Markdown标签""" + # 处理显式标签定义 {#label} + text = re.sub(r'\{#([^}]+)\}', + lambda m: f'{{#{label_manager.register_label(m.group(1))}}}', + text) + + # 处理显式标签定义 (label)= + text = re.sub(r'\(([^)]+)\)=', + lambda m: f'({label_manager.register_label(m.group(1))})=', + text) + + # 处理标签引用 [text](#label) + text = re.sub(r'\[([^\]]+)\]\(#([^)]+)\)', + lambda m: f'[{m.group(1)}](#{label_manager.register_label(m.group(2))})', + text) + + # 处理裸标签引用 #label + text = re.sub(r'(? str: + # 处理标签 + + label_manager = LabelManager(lang) + text = self._process_rst_labels(text, label_manager) + text = self._process_md_labels(text, label_manager) + return text + + def _preserve_special_format(self, text: str) -> Tuple[str, Dict]: + """保留特殊格式""" + preserved = {} + + # 排除不需要翻译的块 + exclude_blocks = re.findall( + r'\.\. Note: __EXCLUDE_IN_TRANSLATED_START.*?\.\. Note: __EXCLUDE_IN_TRANSLATED_END', + text, re.DOTALL) + for block in exclude_blocks: + text = text.replace(block, '') + + # 处理多行代码块 + code_blocks = re.findall(r"```.*?\n.*?```", text, re.DOTALL) + for i, block in enumerate(code_blocks): + placeholder = f"__CODE_BLOCK_{i}__" + preserved[placeholder] = block + text = text.replace(block, placeholder) + # 处理内联代码块 + inline_code = re.findall(r"`[^`]+`", text) + for i, code in enumerate(inline_code): + placeholder = f"__INLINE_CODE_{i}__" + preserved[placeholder] = code + text = text.replace(code, placeholder) + + return text, preserved + + def _restore_special_format(self, text: str, preserved: Dict) -> str: + """恢复特殊格式""" + # 先恢复内联代码块 + for placeholder, content in preserved.items(): + if placeholder.startswith("__INLINE_CODE_"): + text = text.replace(placeholder, content) + + # 然后恢复多行代码块 + for placeholder, content in preserved.items(): + if placeholder.startswith("__CODE_BLOCK_"): + text = text.replace(placeholder, content) + + return text + + def _remove_thinking(self, text: str) -> str: + """Remove tags from text""" + return re.sub(r'.*?', '', text, flags=re.DOTALL) + + def _translate_chunk(self, args: Tuple[str, str]) -> str: + """翻译单个文本块(内部方法,用于并行处理)""" + chunk, lang = args + retry = 3 + while retry > 0: + try: + lang_name = CONFIG["target_languages"].get(lang, "English") + prompt = f"你是一个专业的文档翻译助手,请将以下中文技术文档准确翻译成{lang_name},保持技术术语的正确性和格式不变。" + + # disable qwen3's thinking mode + if "qwen3" in CONFIG["model"].lower(): + prompt += "\n/no_think\n" + chunk += "\n/no_think\n" + + response = self.client.chat.completions.create( + extra_body={"enable_thinking": False}, + model=CONFIG["model"], + messages=[ + {"role": "system", "content": prompt}, + {"role": "user", "content": chunk} + ], + temperature=0.3, + ) + content = response.choices[0].message.content + return self._remove_thinking(content) + except Exception as e: + retry -= 1 + if retry == 0: + print("翻译失败: {e},放弃重试。") + return None + + print(f"翻译出错: {e}, retrying... ({retry})") + time.sleep(2) + + def translate_text(self, text: str, lang: str) -> str: + """使用openai接口翻译文本 + Args: + text: 要翻译的文本 + lang: 目标语言代码 + """ + chunks = self._split_into_chunks(text) + translated_chunks = [] + + for chunk in chunks: + translated_chunk = self._translate_chunk((chunk, lang)) + if translated_chunk: + translated_chunks.append(translated_chunk) + + return "\n\n".join(translated_chunks) + + def process_file(self, filepath: str, lang: str = "en"): + """处理单个文件 + Args: + filepath: 源文件路径 + lang: 目标语言代码 (默认'en') + """ + rel_path = os.path.relpath(filepath, CONFIG["source_dir"]) + target_path = os.path.join( + CONFIG["source_dir"], "locales", lang, rel_path) + + # 检查文件是否已存在且未修改 + cache_key = self._get_cache_key(filepath, lang) + file_hash = hashlib.md5(open(filepath, "rb").read()).hexdigest() + target_file_exists = os.path.exists(target_path) + with self._cache_lock: + if cache_key in self._cache and self._cache[cache_key]["hash"] == file_hash and target_file_exists: + print(f"文件未修改,跳过: {rel_path} (语言: {lang})") + return + + print(f"正在处理: {rel_path}") + + # 读取文件内容 + with open(filepath, "r", encoding="utf-8") as f: + content = f.read() + + # 保留特殊格式 + content, preserved = self._preserve_special_format(content) + + content = self._generate_unique_label_for_lang(content, lang) + + # 分块翻译 + translated_content = self.translate_text( + content, lang) + if not translated_content: + print(f"翻译失败!{filepath}") + self.fail_count += 1 + return + + # 恢复特殊格式 + translated_content = self._restore_special_format( + translated_content, preserved) + + # 创建目标目录 + os.makedirs(os.path.dirname(target_path), exist_ok=True) + + # 写入翻译结果 + with open(target_path, "w", encoding="utf-8") as f: + # 添加翻译元数据 + file_ext = os.path.splitext(filepath)[1] + template = CONFIG["meta_templates"].get(file_ext, "") + + if template: + timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + original_path = os.path.relpath(filepath, CONFIG["source_dir"]) + meta_content = template.format( + note="{note}", + model=CONFIG["model"], + timestamp=timestamp, + original_name=os.path.basename(filepath), + original_path=original_path + ) + translated_content = meta_content + translated_content + + f.write(translated_content) + f.write("\n") + + # 更新缓存 + with self._cache_lock: + self._cache[cache_key] = { + "hash": file_hash, + } + + self._save_cache() + + print(f"文件 {rel_path} 已成功翻译为 {lang} 并保存到 {target_path}") + + def add_language_root_title(self, lang): + """为每个语言的文档添加标题""" + lang_root_doc_path = os.path.join( + CONFIG["source_dir"], "locales", lang, "index.rst") + + if not os.path.exists(lang_root_doc_path): + raise FileNotFoundError(f"未找到 {lang} 的标题文件: {lang_root_doc_path}") + print(f"正在为 {CONFIG['target_languages'][lang]} 添加标题...") + + # Read existing content first + with open(lang_root_doc_path, "r", encoding="utf-8") as f: + content = f.read() + + lang_v = CONFIG["target_languages"][lang] + if content.startswith(lang_v): + print(f"{lang_v} 的标题已存在,跳过...") + return + + # Then write new content (this clears the file) + with open(lang_root_doc_path, "w", encoding="utf-8") as f: + f.write( + f"{lang_v}\n==========================================\n{content}") + + print(f"标题已添加到 {lang_root_doc_path}") + + def run(self): + """运行翻译流程""" + + print("Collecting all files...") + all_files = [] + for root, dirs, files in os.walk(CONFIG["source_dir"], topdown=True): + # 只在根目录应用排除逻辑 + if root == CONFIG["source_dir"]: + dirs[:] = [d for d in dirs if d not in CONFIG["dirs_exclude"]] + for file in files: + if file.endswith((".rst", ".md")): + all_files.append(os.path.join(root, file)) + total_files = len(all_files) + print( + f"Total {total_files} files to translate in {len(CONFIG['target_languages'])} languages.") + total_tasks = total_files * len(CONFIG["target_languages"]) + + # 外层进度条:语言 + lang_pbar = tqdm(CONFIG["target_languages"].items(), + desc="Overall progress", + unit="lang", + position=0) + + for lang_k, lang_v in lang_pbar: + lang_pbar.set_description(f"Translating to {lang_v}") + + # 并行处理文件 + from concurrent.futures import ThreadPoolExecutor, as_completed + + # 包装处理函数便于调试之类的 + + def process_file_wrapper(file_path): + self.process_file(file_path, lang_k) + return file_path + + # 创建线程池 + with ThreadPoolExecutor(max_workers=CONFIG["max_workers"]) as executor: + # 提交所有文件处理任务 + futures = [executor.submit( + process_file_wrapper, path) for path in all_files] + + # 创建进度条 + file_pbar = tqdm(total=len(all_files), + desc=f"Files in {lang_v}", + unit="file", + position=1, + leave=False) + + # 更新进度条 + for future in as_completed(futures): + file_pbar.update(1) + future.result() # 获取结果(如果有异常会在这里抛出) + + file_pbar.close() + self.add_language_root_title(lang_k) + + lang_pbar.close() + print( + f"\n翻译完成! Succ: {total_tasks-self.fail_count}, Fail: {self.fail_count}") + + + +if __name__ == "__main__": + print("Starting translation process...") + print("WORKERS: ", CONFIG["max_workers"]) + print("LANGUAGES: ", CONFIG["target_languages"]) + print("SOURCE_DIR: ", CONFIG["source_dir"]) + print("MODEL: ", CONFIG["model"]) + + translator = DocumentTranslator() + translator.run() + + if translator.fail_count > 0: + sys.exit(1) diff --git a/tools/docker-entrypoint.sh b/tools/docker-entrypoint.sh old mode 100644 new mode 100755 diff --git a/tools/dump_kernel.sh b/tools/dump_kernel.sh old mode 100644 new mode 100755 diff --git a/tools/grub_auto_install.sh b/tools/grub_auto_install.sh old mode 100644 new mode 100755 diff --git a/tools/init_rust_toolchain.sh b/tools/init_rust_toolchain.sh old mode 100644 new mode 100755 diff --git a/tools/install_musl_gcc.sh b/tools/install_cross_gcc.sh old mode 100644 new mode 100755 similarity index 75% rename from tools/install_musl_gcc.sh rename to tools/install_cross_gcc.sh index 1809f3e7..7e98fa47 --- a/tools/install_musl_gcc.sh +++ b/tools/install_cross_gcc.sh @@ -1,3 +1,5 @@ +#! /bin/bash + ######################################################################### # 这个脚本用于安装musl交叉编译工具链 # 该脚本会自动下载musl交叉编译工具链,并将其添加到PATH中 @@ -12,8 +14,13 @@ MUSL_GCC_VERSION="9.4.0" MUSL_GCC_X86_64_TAR= MUSL_GCC_RISCV64_TAR= +LA64_GCC_VERSION="loongarch64-cross-14.2.0" +LA64_GCC_TAR="${LA64_GCC_VERSION}.tar.xz" + MUSL_GCC_X86_64_DOWNLOAD_URL="" MUSL_GCC_RISCV64_DOWNLOAD_URL="" +LA64_GCC_DOWNLOAD_URL="https://mirrors.dragonos.org.cn/pub/third_party/toolchain/gcc/${LA64_GCC_TAR}" + if [ $USE_GITHUB -eq 1 ]; then echo "Download from github" @@ -21,7 +28,6 @@ if [ $USE_GITHUB -eq 1 ]; then MUSL_GCC_RISCV64_TAR=riscv64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}.tar.xz MUSL_GCC_X86_64_DOWNLOAD_URL="https://github.com/DragonOS-Community/musl-cross-make/releases/download/${MUSL_GCC_VERSION}-${MUSL_GCC_DATE}/${MUSL_GCC_X86_64_TAR}" MUSL_GCC_RISCV64_DOWNLOAD_URL="https://github.com/DragonOS-Community/musl-cross-make/releases/download/${MUSL_GCC_VERSION}-${MUSL_GCC_DATE}/${MUSL_GCC_RISCV64_TAR}" - https://github.com/DragonOS-Community/musl-cross-make/releases/download/9.4.0-231114/riscv64-linux-musl-cross-gcc-9.4.0.tar.xz else echo "Download from mirrors.dragonos.org.cn" MUSL_GCC_X86_64_TAR="x86_64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}-${MUSL_GCC_DATE}.tar.xz" @@ -50,6 +56,7 @@ get_shell_rc_file() trap_handler(){ rm -f $MUSL_GCC_X86_64_TAR rm -f $MUSL_GCC_RISCV64_TAR + rm -f $LA64_GCC_TAR } trap trap_handler EXIT @@ -59,6 +66,20 @@ trap trap_handler SIGINT SHELL_RC=$(get_shell_rc_file) source $SHELL_RC +install_loongarch64_gcc() +{ + echo "正在安装 loongarch64-unknown-linux-gnu 工具链" + + wget ${LA64_GCC_DOWNLOAD_URL} || exit 1 + echo "正在解压 loongarch64-unknown-linux-gnu 工具链" + tar xf $LA64_GCC_TAR -C $INSTALL_POS || exit 1 + echo "正在将 loongarch64-unknown-linux-gnu 工具链添加到 PATH 环境变量中" + echo "export PATH=\$PATH:$INSTALL_POS/${LA64_GCC_VERSION}/bin" >> $SHELL_RC + + echo "loongarch64-unknown-linux-gnu 工具链已成功安装!请运行 source $SHELL_RC 以使更改生效!" + rm -rf $LA64_GCC_TAR || exit 1 +} + # 下载musl交叉编译工具链 # 如果x86_64-linux-musl-gcc或x86_64-linux-musl-g++不存在,则下载 @@ -68,7 +89,7 @@ if [ ! -n "$(which x86_64-linux-musl-gcc)" ] || [ ! -n "$(which x86_64-linux-mus echo "下载完成" echo "开始解压x86_64-linux-musl-gcc" tar xvf $MUSL_GCC_X86_64_TAR -C $INSTALL_POS || exit 1 - echo "PATH=\$PATH:$INSTALL_POS/x86_64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}/bin" >> $SHELL_RC + echo "export PATH=\$PATH:$INSTALL_POS/x86_64-linux-musl-cross-gcc-${MUSL_GCC_VERSION}/bin" >> $SHELL_RC echo "安装完成" echo "开始清理x86_64-linux-musl-gcc的下载缓存" rm -rf $MUSL_GCC_X86_64_TAR || exit 1 @@ -93,6 +114,13 @@ else echo "riscv64-linux-musl-gcc已经安装" fi +if [ ! -n "$(which loongarch64-unknown-linux-gnu-gcc)" ] || [ ! -n "$(which loongarch64-unknown-linux-gnu-g++)" ]; then + install_loongarch64_gcc || exit 1 +else + echo "loongarch64-unknown-linux-gnu-gcc已经安装" +fi + + source $SHELL_RC echo "musl交叉编译工具链安装完成,请运行 source $SHELL_RC 以使musl交叉编译工具链在当前窗口生效!" diff --git a/tools/qemu/.gitignore b/tools/qemu/.gitignore new file mode 100644 index 00000000..f91f5825 --- /dev/null +++ b/tools/qemu/.gitignore @@ -0,0 +1,3 @@ +/source_packages +/build_dir +*.log \ No newline at end of file diff --git a/tools/qemu/build-qemu-la64-for-ubuntu.sh b/tools/qemu/build-qemu-la64-for-ubuntu.sh new file mode 100755 index 00000000..25fe9534 --- /dev/null +++ b/tools/qemu/build-qemu-la64-for-ubuntu.sh @@ -0,0 +1,155 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +# 默认参数 +QEMU_VERSION="9.2.1" +TARGET_LIST="loongarch64-softmmu" +USE_MIRROR=0 +DEST_DIR="${HOME}/opt/qemu-${QEMU_VERSION}" +SOURCE_PACKAGES_DIR="$SCRIPT_DIR/source_packages" +BUILD_DIR="$SCRIPT_DIR/build_dir" + +SUDO=sudo +FORCE=0 + +# 检查是否为root用户 +if [ "$(id -u)" -eq 0 ]; then + SUDO="" +fi + +# 参数解析 +while [[ $# -gt 0 ]]; do + case "$1" in + --version) + QEMU_VERSION="$2" + shift 2 + DEST_DIR="${HOME}/opt/qemu-${QEMU_VERSION}" # 更新默认路径 + ;; + --target-list) + TARGET_LIST="$2" + shift 2 + ;; + --use-mirror) + USE_MIRROR=1 + shift + ;; + --dest-dir) + DEST_DIR="$2" + shift 2 + ;; + -f|--force) + FORCE=1 + shift + ;; + *) + echo "未知参数: $1" + exit 1 + ;; + esac +done + +# 检查是否已存在qemu-system-loongarch64 +QEMU_BINARY="${DEST_DIR}/bin/qemu-system-loongarch64" +if [ -f "$QEMU_BINARY" ] && [ "$FORCE" -eq 0 ]; then + echo "检测到已存在 qemu-system-loongarch64 在 ${QEMU_BINARY}" + echo "如需强制重新构建,请使用 -f 或 --force 参数" + exit 1 +fi + +# 依赖检查函数 +check_dependency() { + if ! dpkg -l | grep -q "^ii $1 "; then + echo "安装依赖: $1" + ${SUDO} apt-get install -y "$1" + fi +} + +# 镜像源设置 +if [[ $USE_MIRROR -eq 1 ]]; then + echo "使用国内镜像源..." + # APT镜像 + ${SUDO} sed -i \ + 's|//.*archive.ubuntu.com|//mirrors.ustc.edu.cn|g' \ + /etc/apt/sources.list + + # PyPI镜像 + PIP_MIRROR="https://pypi.mirrors.ustc.edu.cn/simple" +else + PIP_MIRROR="https://pypi.org/simple" +fi + +# 更新源 +${SUDO} apt-get update + +# 安装基础依赖 +check_dependency build-essential +check_dependency ninja-build +check_dependency meson +check_dependency pkg-config +check_dependency libglib2.0-dev +check_dependency libslirp-dev +check_dependency wget +check_dependency git + +# Python环境配置 +if ! command -v python3 &> /dev/null; then + ${SUDO} apt-get install -y python3 python3-pip +elif ! command -v pip3 &> /dev/null; then + ${SUDO} apt-get install -y python3-pip +fi + +if ! pip3 show tomli &> /dev/null; then + pip3 install --user -i $PIP_MIRROR tomli +fi + +# 创建目录结构 +mkdir -p "$DEST_DIR" +mkdir -p $SOURCE_PACKAGES_DIR +mkdir -p $BUILD_DIR + +# 下载源码包 +QEMU_TAR="qemu-${QEMU_VERSION}.tar.xz" +QEMU_SRC_DIR="$SOURCE_PACKAGES_DIR/qemu-${QEMU_VERSION}" + +if [ ! -f "$SOURCE_PACKAGES_DIR/${QEMU_TAR}" ]; then + echo "正在下载QEMU源码包..." + wget "https://download.qemu.org/${QEMU_TAR}" -O "$SOURCE_PACKAGES_DIR/${QEMU_TAR}" +fi + +# 解压源码 +if [ ! -d "${QEMU_SRC_DIR}" ]; then + echo "解压QEMU源码..." + tar xf "$SOURCE_PACKAGES_DIR/${QEMU_TAR}" -C $SOURCE_PACKAGES_DIR +fi + +# 配置构建目录 +BUILD_DIR="$BUILD_DIR/qemu-${QEMU_VERSION}_${TARGET_LIST//,/}" +mkdir -p "${BUILD_DIR}" + +pushd $(pwd) + +cd "${BUILD_DIR}" + +# 运行配置 +echo "配置编译参数..." +"${QEMU_SRC_DIR}/configure" \ + --prefix="$DEST_DIR" \ + --enable-slirp \ + --target-list="$TARGET_LIST" \ + --enable-kvm + +# 编译和安装 +echo "开始编译(使用$(nproc)线程)..." +make -j "$(nproc)" +make install + +popd +# 清理 +rm -rf "./${BUILD_DIR}" +rm -rf "${QEMU_SRC_DIR}" + +echo -e "\n编译完成!安装路径: ${DEST_DIR}" +echo -e "运行以下命令使用QEMU:" +echo -e " 或者将其添加到你的shell配置文件中(例如~/.bashrc或~/.zshrc):" +echo "export PATH=\"${DEST_DIR}/bin:\$PATH\"" diff --git a/tools/run-qemu.sh b/tools/run-qemu.sh old mode 100644 new mode 100755 index 7b48644c..ec0f122b --- a/tools/run-qemu.sh +++ b/tools/run-qemu.sh @@ -6,6 +6,16 @@ check_dependencies() exit 1 fi + if [ -z "$(which ${QEMU})" ]; then + if [ "$ARCH" == "loongarch64" ]; then + echo -e "\nPlease install qemu-system-loongarch64 first!" + echo -e "\nYou can install it by running: (if you are using ubuntu)" + echo -e " ${ROOT_PATH}/tools/qemu/build-qemu-la64-for-ubuntu.sh" + echo -e "" + exit 1 + fi + fi + # Check if brctl is installed if [ -z "$(which brctl)" ]; then echo "Please install bridge-utils first!" @@ -26,7 +36,6 @@ check_dependencies() } -check_dependencies # 进行启动前检查 flag_can_run=1 @@ -38,6 +47,8 @@ allflags= # 设置ARCH环境变量,如果没有设置,就默认为x86_64 export ARCH=${ARCH:=x86_64} echo "ARCH=${ARCH}" + + #ARCH="i386" # 请根据自己的需要,在-d 后方加入所需的 trace 事件 @@ -67,7 +78,7 @@ RISCV64_UBOOT_PATH="arch/riscv64/u-boot-${UBOOT_VERSION}-riscv64" DISK_NAME="disk-image-${ARCH}.img" -QEMU=qemu-system-${ARCH} +QEMU=$(which qemu-system-${ARCH}) QEMU_DISK_IMAGE="../bin/${DISK_NAME}" QEMU_MEMORY="512M" QEMU_MEMORY_BACKEND="dragonos-qemu-shm.ram" @@ -82,11 +93,21 @@ QEMU_SERIAL_LOG_FILE="../serial_opt.txt" QEMU_SERIAL="-serial file:${QEMU_SERIAL_LOG_FILE}" QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none" QEMU_ACCELARATE="" -QEMU_ARGUMENT="" +QEMU_ARGUMENT=" -no-reboot " QEMU_DEVICES="" + + +check_dependencies + +# 设置无图形界面模式 +QEMU_NOGRAPHIC=false + +KERNEL_CMDLINE=" " + BIOS_TYPE="" #这个变量为true则使用virtio磁盘 -VIRTIO_BLK_DEVICE=false +VIRTIO_BLK_DEVICE=true + # 如果qemu_accel不为空 if [ -n "${qemu_accel}" ]; then QEMU_ACCELARATE=" -machine accel=${qemu_accel} " @@ -105,23 +126,25 @@ if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then QEMU_DEVICES_DISK="-device virtio-blk-pci,drive=disk -device pci-bridge,chassis_nr=1,id=pci.1 -device pcie-root-port " fi -else +elif [ ${ARCH} == "riscv64" ]; then QEMU_MACHINE=" -machine virt,memory-backend=${QEMU_MEMORY_BACKEND} -cpu sifive-u54 " QEMU_DEVICES_DISK="-device virtio-blk-device,drive=disk " - +elif [ ${ARCH} == "loongarch64" ]; then + QEMU_MACHINE=" -machine virt" + QEMU_DEVICES_DISK="-device virtio-blk-pci,drive=disk -device pci-bridge,chassis_nr=1,id=pci.1 -device pcie-root-port " +else + echo "Unsupported architecture: ${ARCH}" + exit 1 fi if [ ${ARCH} == "riscv64" ]; then # 如果是riscv64架构,就不需要图形界面 - QEMU_ARGUMENT+=" --nographic " - # 从控制台显示 - QEMU_MONITOR="" - QEMU_SERIAL="" + QEMU_NOGRAPHIC=true fi while true;do case "$1" in - --bios) + --bios) case "$2" in uefi) #uefi启动新增ovmf.fd固件 BIOS_TYPE=uefi @@ -138,17 +161,54 @@ while true;do window) ;; nographic) - QEMU_SERIAL=" -serial chardev:mux -monitor chardev:mux -chardev stdio,id=mux,mux=on,signal=off,logfile=${QEMU_SERIAL_LOG_FILE} " - QEMU_MONITOR="" - QEMU_ARGUMENT+=" --nographic " - QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf " + QEMU_NOGRAPHIC=true ;; esac;shift 2;; *) break - esac + esac done +setup_kernel_init_program() { + if [ ${ARCH} == "x86_64" ]; then + KERNEL_CMDLINE+=" init=/bin/busybox init " + # KERNEL_CMDLINE+=" init=/bin/dragonreach " + elif [ ${ARCH} == "riscv64" ]; then + KERNEL_CMDLINE+=" init=/bin/riscv_rust_init " + fi +} + +# 设置内核init程序 +setup_kernel_init_program + + +if [ ${QEMU_NOGRAPHIC} == true ]; then + QEMU_SERIAL=" -serial chardev:mux -monitor chardev:mux -chardev stdio,id=mux,mux=on,signal=off,logfile=${QEMU_SERIAL_LOG_FILE} " + + # 添加 virtio console 设备 + if [ ${ARCH} == "x86_64" ]; then + QEMU_DEVICES+=" -device virtio-serial -device virtconsole,chardev=mux " + elif [ ${ARCH} == "loongarch64" ]; then + QEMU_DEVICES+=" -device virtio-serial -device virtconsole,chardev=mux " + elif [ ${ARCH} == "riscv64" ]; then + QEMU_DEVICES+=" -device virtio-serial-device -device virtconsole,chardev=mux " + fi + + KERNEL_CMDLINE=" console=/dev/hvc0 ${KERNEL_CMDLINE}" + QEMU_MONITOR="" + QEMU_ARGUMENT+=" --nographic " + + KERNEL_CMDLINE=$(echo "${KERNEL_CMDLINE}" | sed 's/^[ \t]*//;s/[ \t]*$//') + + if [ ${ARCH} == "x86_64" ]; then + QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf -append \"${KERNEL_CMDLINE}\" " + elif [ ${ARCH} == "loongarch64" ]; then + QEMU_ARGUMENT+=" -kernel ../bin/kernel/kernel.elf -append \"${KERNEL_CMDLINE}\" " + elif [ ${ARCH} == "riscv64" ]; then + QEMU_ARGUMENT+=" -append \"${KERNEL_CMDLINE}\" " + fi +fi + # ps: 下面这条使用tap的方式,无法dhcp获取到ip,暂时不知道为什么 # QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 " @@ -156,12 +216,15 @@ QEMU_DEVICES+="${QEMU_DEVICES_DISK} " QEMU_DEVICES+=" -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -device virtio-net-pci,vectors=5,netdev=hostnet0,id=net0 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 " # E1000E # QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -net nic,model=e1000e,netdev=hostnet0,id=net0 -netdev user,id=hostnet1,hostfwd=tcp::12581-:12581 -device virtio-net-pci,vectors=5,netdev=hostnet1,id=net1 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 " + + QEMU_ARGUMENT+="-d ${QEMU_DISK_IMAGE} -m ${QEMU_MEMORY} -smp ${QEMU_SMP} -boot order=d ${QEMU_MONITOR} -d ${qemu_trace_std} " QEMU_ARGUMENT+="-s ${QEMU_MACHINE} ${QEMU_CPU_FEATURES} ${QEMU_RTC_CLOCK} ${QEMU_SERIAL} -drive ${QEMU_DRIVE} ${QEMU_DEVICES} " QEMU_ARGUMENT+=" ${QEMU_SHM_OBJECT} " QEMU_ARGUMENT+=" ${QEMU_ACCELARATE} " +QEMU_ARGUMENT+=" -D ../qemu.log " # 安装riscv64的uboot @@ -196,23 +259,25 @@ sudo rm -rf ${QEMU_MEMORY_BACKEND_PATH_PREFIX}/${QEMU_MEMORY_BACKEND} if [ ${BIOS_TYPE} == uefi ] ;then if [ ${ARCH} == x86_64 ] ;then - sudo ${QEMU} -bios arch/x86_64/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} -bios arch/x86_64/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT}" elif [ ${ARCH} == i386 ] ;then - sudo ${QEMU} -bios arch/i386/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} -bios arch/i386/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT}" elif [ ${ARCH} == riscv64 ] ;then install_riscv_uboot - sudo ${QEMU} -kernel ${RISCV64_UBOOT_PATH}/u-boot.bin ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} -kernel ${RISCV64_UBOOT_PATH}/u-boot.bin ${QEMU_ARGUMENT}" else echo "不支持的架构: ${ARCH}" fi else # 如果是i386架构或者x86_64架构,就直接启动 if [ ${ARCH} == x86_64 ] || [ ${ARCH} == i386 ] ;then - sudo ${QEMU} ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} ${QEMU_ARGUMENT}" elif [ ${ARCH} == riscv64 ] ;then # 如果是riscv64架构,就与efi启动一样 install_riscv_uboot - sudo ${QEMU} -kernel ${RISCV64_UBOOT_PATH}/u-boot.bin ${QEMU_ARGUMENT} + sh -c "sudo ${QEMU} -kernel ${RISCV64_UBOOT_PATH}/u-boot.bin ${QEMU_ARGUMENT}" + elif [ ${ARCH} == loongarch64 ] ;then + sh -c "sudo ${QEMU} ${QEMU_ARGUMENT}" else echo "不支持的架构: ${ARCH}" fi diff --git a/tools/write_disk_image.sh b/tools/write_disk_image.sh old mode 100644 new mode 100755 index 24017c9a..c9522f58 --- a/tools/write_disk_image.sh +++ b/tools/write_disk_image.sh @@ -79,6 +79,9 @@ $DADK -w $root_folder rootfs mount || exit 1 LOOP_DEVICE=$($DADK -w $root_folder rootfs show-loop-device || exit 1) echo $LOOP_DEVICE echo ${mount_folder} + +FS_TYPE=$(findmnt -n -o FSTYPE ${mount_folder} || df -T ${mount_folder} | tail -1 | awk '{print $2}') +echo "FS_TYPE: $FS_TYPE" # mkdir -p ${GRUB_INSTALL_PATH} # 检测grub文件夹是否存在 @@ -99,7 +102,12 @@ mkdir -p ${mount_folder}/bin mkdir -p ${mount_folder}/dev mkdir -p ${mount_folder}/proc mkdir -p ${mount_folder}/usr -cp -r ${root_folder}/bin/sysroot/* ${mount_folder}/ + +if [ "$FS_TYPE" = "vfat" ] || [ "$FS_TYPE" = "fat32" ]; then + cp -rL ${root_folder}/bin/sysroot/* ${mount_folder}/ +else + cp -r ${root_folder}/bin/sysroot/* ${mount_folder}/ +fi # 设置 grub 相关数据 if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then diff --git a/user/Makefile b/user/Makefile index c21d6179..1f720d74 100644 --- a/user/Makefile +++ b/user/Makefile @@ -2,7 +2,7 @@ user_sub_dirs = apps DADK_VERSION=$(shell dadk -V | awk 'END {print $$2}') # 最小的DADK版本 -MIN_DADK_VERSION = 0.2.0 +MIN_DADK_VERSION = 0.4.0 DADK_CACHE_DIR = $(ROOT_PATH)/bin/dadk_cache ECHO: @@ -17,10 +17,10 @@ ifeq ("$(DADK_VERSION)", "") @echo "\nYou can install dadk by running the following command:" @echo "\n\tcargo install dadk" @echo "\nOr you can install dadk from source by running the following command:" - @echo "\n\tcargo install --git https://git.mirrors.dragonos.org.cn/DragonOS-Community/DADK.git --tag v$(MIN_DADK_VERSION)" + @echo "\n\tcargo install --git https://git.mirrors.dragonos.org.cn/DragonOS-Community/DADK.git --tag v$(MIN_DADK_VERSION)" --locked @echo "\n" @echo "Auto installing dadk..." - cargo install dadk + cargo install --git https://git.mirrors.dragonos.org.cn/DragonOS-Community/DADK.git --tag v$(MIN_DADK_VERSION)" --locked else # 如果DADK版本过低,则自动更新 @echo "dadk version $(DADK_VERSION) installed" @@ -28,7 +28,7 @@ else ifneq ($(shell printf '%s\n%s' "$(DADK_VERSION)" "$(MIN_DADK_VERSION)" | sort -V | head -n1), $(MIN_DADK_VERSION)) @echo "dadk version is too low, please update to $(MIN_DADK_VERSION) or higher version" @echo "Updating dadk..." - cargo install --git https://git.mirrors.dragonos.org.cn/DragonOS-Community/DADK.git --tag v$(MIN_DADK_VERSION) || (echo "dadk update failed" && exit 1) + cargo install --git https://git.mirrors.dragonos.org.cn/DragonOS-Community/DADK.git --tag v$(MIN_DADK_VERSION) --locked || (echo "dadk update failed" && exit 1) @echo "dadk updated" endif endif diff --git a/user/apps/busybox/.gitignore b/user/apps/busybox/.gitignore new file mode 100644 index 00000000..879a99e1 --- /dev/null +++ b/user/apps/busybox/.gitignore @@ -0,0 +1,3 @@ +build/ +busybox-1.35.0.tar.bz2 +busybox-1.35.0.tar.bz2.md5sum \ No newline at end of file diff --git a/user/apps/busybox/Makefile b/user/apps/busybox/Makefile new file mode 100644 index 00000000..6e150bc8 --- /dev/null +++ b/user/apps/busybox/Makefile @@ -0,0 +1,72 @@ +ARCH ?= x86_64 +busybox_version := 1.35.0 +busybox_tarball := busybox-$(busybox_version).tar.bz2 +busybox_tarball_path := $(busybox_tarball) +build_dir := build/$(ARCH) +busybox_dir := $(build_dir)/busybox-$(busybox_version) +prefix := $(ARCH)-linux-musl- +bin := build/$(ARCH)/busybox + +# 特殊架构处理 +ifeq ($(ARCH), mipsel) + prefix := mipsel-linux-musln32- +endif + +cc := $(prefix)gcc +strip := $(prefix)strip + +# 下载 busybox 的 md5sum 文件 +$(busybox_tarball_path).md5sum: + wget https://mirrors.dragonos.org.cn/pub/third_party/busybox/$(busybox_tarball).md5sum + +# 下载源码 +$(busybox_tarball_path): $(busybox_tarball_path).md5sum + @if [ ! -f $@ ] || ! md5sum -c $(busybox_tarball_path).md5sum; then \ + echo "Downloading $@..."; \ + wget https://mirrors.dragonos.org.cn/pub/third_party/busybox/$(busybox_tarball); \ + fi + +# 解压源码包 +$(busybox_dir): $(busybox_tarball_path) + mkdir -p $(build_dir) + tar -xjf $< -C $(build_dir) + +# 配置和编译 +$(bin): $(busybox_dir) + @# 应用必要补丁和配置调整 + cd $(busybox_dir) && \ + make defconfig && \ + sed -i '/CONFIG_STATIC/s/.*/CONFIG_STATIC=y/' .config && \ + sed -i '/CONFIG_PIE/d' .config && \ + echo "CONFIG_CROSS_COMPILER_PREFIX=\"$(prefix)\"" >> .config && \ + echo "CONFIG_FEATURE_STATIC=y" >> .config && \ + echo "CONFIG_STATIC_LIBGCC=y" >> .config && \ + echo "CONFIG_ASH=y" >> .config && \ + echo "CONFIG_ASH_READ_PROFILE=y" >> .config + + + @# 执行编译 + cd $(busybox_dir) && \ + KCONFIG_NOTIMESTAMP=1 make CC="$(cc)" CFLAGS_EXTRA="-static -Os" LDFLAGS="--static" -j$(nproc) + + @# 处理编译输出 + mkdir -p $(dir $(bin)) + cp $(busybox_dir)/busybox $(bin) + $(strip) $(bin) + +.PHONY: all clean menuconfig + +all: $(bin) + +install: all + mv $(bin) $(DADK_CURRENT_BUILD_DIR)/busybox + +# 交互式配置菜单 +menuconfig: $(busybox_dir) + cd $(busybox_dir) && make menuconfig + +clean: + rm -rf build/ + +distclean: clean + rm -f $(busybox_tarball_path) $(busybox_tarball_path).md5sum diff --git a/user/apps/clear/Makefile b/user/apps/clear/Makefile index 0d140353..261eba3d 100644 --- a/user/apps/clear/Makefile +++ b/user/apps/clear/Makefile @@ -10,7 +10,7 @@ else endif ifeq ($(ARCH), x86_64) - export RUST_TARGET=x86_64-unknown-linux-musl + export RUST_TARGET=x86_64-unknown-linux-gnu else ifeq ($(ARCH), riscv64) export RUST_TARGET=riscv64gc-unknown-linux-gnu else diff --git a/user/apps/riscv_init/Makefile b/user/apps/riscv_init/Makefile index a75ff55d..8df0859b 100644 --- a/user/apps/riscv_init/Makefile +++ b/user/apps/riscv_init/Makefile @@ -6,15 +6,18 @@ endif CC=$(CROSS_COMPILE)gcc + .PHONY: all -all: main.c - $(CC) -static -o init main.c +all: $(riscv_rust_init) + $(MAKE) -C riscv_rust_init ARCH=$(ARCH) install .PHONY: install clean install: all - mv init $(DADK_CURRENT_BUILD_DIR)/init + $(MAKE) -C riscv_rust_init ARCH=$(ARCH) install + clean: rm init *.o + $(MAKE) -C riscv_rust_init ARCH=$(ARCH) clean fmt: diff --git a/user/apps/riscv_init/main.c b/user/apps/riscv_init/main.c deleted file mode 100644 index aab66227..00000000 --- a/user/apps/riscv_init/main.c +++ /dev/null @@ -1,9 +0,0 @@ -#include - -int main() { - while(1){ - printf("\033[43;37mHello, World!\033[0m\n"); - sleep(1); - } - return 0; -} \ No newline at end of file diff --git a/user/apps/riscv_init/riscv_rust_init/.cargo/config.toml b/user/apps/riscv_init/riscv_rust_init/.cargo/config.toml new file mode 100644 index 00000000..d5865724 --- /dev/null +++ b/user/apps/riscv_init/riscv_rust_init/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.riscv64gc-unknown-linux-musl] +linker = "riscv64-linux-gnu-gcc" diff --git a/user/apps/riscv_init/riscv_rust_init/.gitignore b/user/apps/riscv_init/riscv_rust_init/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/user/apps/riscv_init/riscv_rust_init/.gitignore @@ -0,0 +1 @@ +/target diff --git a/user/apps/riscv_init/riscv_rust_init/Cargo.toml b/user/apps/riscv_init/riscv_rust_init/Cargo.toml new file mode 100644 index 00000000..ab9f2534 --- /dev/null +++ b/user/apps/riscv_init/riscv_rust_init/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "riscv_rust_init" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/user/apps/riscv_init/riscv_rust_init/Makefile b/user/apps/riscv_init/riscv_rust_init/Makefile new file mode 100644 index 00000000..7efb0f91 --- /dev/null +++ b/user/apps/riscv_init/riscv_rust_init/Makefile @@ -0,0 +1,50 @@ +# The toolchain we use. +# You can get it by running DragonOS' `tools/bootstrap.sh` +TOOLCHAIN="+nightly-2024-11-05-x86_64-unknown-linux-gnu" + +ifeq ($(ARCH), riscv64) +RUSTFLAGS+="-C target-feature=+crt-static" +endif + +ifdef DADK_CURRENT_BUILD_DIR +# 如果是在dadk中编译,那么安装到dadk的安装目录中 + INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR) +else +# 如果是在本地编译,那么安装到当前目录下的install目录中 + INSTALL_DIR = ./install +endif + + +ifeq ($(ARCH), x86_64) + export RUST_TARGET=x86_64-unknown-linux-musl +else ifeq ($(ARCH), riscv64) + export RUST_TARGET=riscv64gc-unknown-linux-musl +else +# 默认为x86_64,用于本地编译 + export RUST_TARGET=x86_64-unknown-linux-musl +endif + +build: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) + +run-dragonreach: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --bin DragonReach + +clean: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean + +build-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release + +clean-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release + +fmt: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt + +fmt-check: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check + +.PHONY: install +install: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force \ No newline at end of file diff --git a/user/apps/riscv_init/riscv_rust_init/src/main.rs b/user/apps/riscv_init/riscv_rust_init/src/main.rs new file mode 100644 index 00000000..c6ed5c4e --- /dev/null +++ b/user/apps/riscv_init/riscv_rust_init/src/main.rs @@ -0,0 +1,4 @@ +fn main() { + println!("rs: Hello, world!"); + loop {} +} diff --git a/user/apps/syscall_ebpf/syscall_ebpf-ebpf/rust-toolchain.toml b/user/apps/syscall_ebpf/syscall_ebpf-ebpf/rust-toolchain.toml index f70d2254..5d44daf0 100644 --- a/user/apps/syscall_ebpf/syscall_ebpf-ebpf/rust-toolchain.toml +++ b/user/apps/syscall_ebpf/syscall_ebpf-ebpf/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly" +channel = "nightly-2024-11-05" components = ["rust-src"] diff --git a/user/apps/test-processgroup/.gitignore b/user/apps/test-processgroup/.gitignore new file mode 100644 index 00000000..2180c4c4 --- /dev/null +++ b/user/apps/test-processgroup/.gitignore @@ -0,0 +1 @@ +test-processgroup \ No newline at end of file diff --git a/user/apps/test-processgroup/Makefile b/user/apps/test-processgroup/Makefile new file mode 100644 index 00000000..56880551 --- /dev/null +++ b/user/apps/test-processgroup/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)gcc + + +all: main.c + $(CC) -static -o test-processgroup main.c + +.PHONY: install clean +install: all + mv test-processgroup $(DADK_CURRENT_BUILD_DIR)/test-processgroup + +clean: + rm test-processgroup *.o + +fmt: diff --git a/user/apps/test-processgroup/main.c b/user/apps/test-processgroup/main.c new file mode 100644 index 00000000..ef4e9aad --- /dev/null +++ b/user/apps/test-processgroup/main.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +#define TEST_ASSERT(left, right, success_msg, fail_msg) \ + do { \ + if ((left) == (right)) { \ + printf("[PASS] %s\n", success_msg); \ + } else { \ + printf("[FAIL] %s: Expected 0x%lx, but got 0x%lx\n", \ + fail_msg, \ + (unsigned long)(right), \ + (unsigned long)(left)); \ + } \ + } while (0) + + + +// 打印进程信息 +void print_ids(const char *name) { + printf("[%s] PID=%d, PPID=%d, PGID=%d, SID=%d\n", + name, + getpid(), + getppid(), + getpgid(0), // 获取当前进程的 PGID + getsid(0)); // 获取当前进程的 SID +} + +int main() { + printf("===== 测试进程组 =====\n"); + print_ids("Parent"); + + // 创建第一个子进程 + pid_t child1 = fork(); + if (child1 == 0) { + // 子进程1:设置自己的进程组 + printf("\n[Child1] 子进程启动...\n"); + print_ids("Child1 (before setpgid)"); + + if (setpgid(0, 0) == -1) { // 将自己的 PGID 设置为自己的 PID + perror("setpgid failed"); + exit(EXIT_FAILURE); + } + + print_ids("Child1 (after setpgid)"); + + // Assert: PGID 应该等于 PID + // assert(getpgid(0) == getpid()); + TEST_ASSERT(getpgid(0), getpid(), "Successfully set child1 as processgroup leader", "Child1 PGID check failed"); + + sleep(2); // 保持运行,便于观察 + exit(EXIT_SUCCESS); + } + + // 创建第二个子进程 + pid_t child2 = fork(); + if (child2 == 0) { + // 子进程2:加入第一个子进程的进程组 + printf("\n[Child2] 子进程启动...\n"); + print_ids("Child2 (before setpgid)"); + + if (setpgid(0, child1) == -1) { // 将自己的 PGID 设置为 child1 的 PID + perror("setpgid failed"); + exit(EXIT_FAILURE); + } + + print_ids("Child2 (after setpgid)"); + + // Assert: PGID 应该等于 child1 的 PID + // assert(getpgid(0) == child1); + TEST_ASSERT(getpgid(0),child1,"Child2 PGID is equal to Child1","Child2 PGID check failed"); + + sleep(2); // 保持运行,便于观察 + exit(EXIT_SUCCESS); + } + + // 父进程:等待子进程结束 + waitpid(child1, NULL, 0); + waitpid(child2, NULL, 0); + + printf("\n[Parent] 所有子进程结束后...\n"); + print_ids("Parent"); + + return 0; +} \ No newline at end of file diff --git a/user/apps/test-session/.gitignore b/user/apps/test-session/.gitignore new file mode 100644 index 00000000..def31541 --- /dev/null +++ b/user/apps/test-session/.gitignore @@ -0,0 +1 @@ +test-session \ No newline at end of file diff --git a/user/apps/test-session/Makefile b/user/apps/test-session/Makefile new file mode 100644 index 00000000..1ebf48f8 --- /dev/null +++ b/user/apps/test-session/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)gcc + + +all: main.c + $(CC) -static -o test-session main.c + +.PHONY: install clean +install: all + mv test-session $(DADK_CURRENT_BUILD_DIR)/test-session + +clean: + rm test-session *.o + +fmt: diff --git a/user/apps/test-session/main.c b/user/apps/test-session/main.c new file mode 100644 index 00000000..c33046e4 --- /dev/null +++ b/user/apps/test-session/main.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include + +#define TEST_ASSERT(left, right, success_msg, fail_msg) \ + do { \ + if ((left) == (right)) { \ + printf("[PASS] %s\n", success_msg); \ + } else { \ + printf("[FAIL] %s: Expected 0x%lx, but got 0x%lx\n", \ + fail_msg, \ + (unsigned long)(right), \ + (unsigned long)(left)); \ + } \ + } while (0) + +#define TEST_CONDITION(condition, success_msg, fail_msg) \ + do { \ + if (condition) { \ + printf("[PASS] %s\n", success_msg); \ + } else { \ + printf("[FAIL] %s\n", fail_msg); \ + } \ + } while (0) + +// 打印进程信息 +void print_ids(const char *name) { + printf("[%s] PID=%d, PPID=%d, PGID=%d, SID=%d\n", + name, + getpid(), + getppid(), + getpgid(0), // 获取当前进程的 PGID + getsid(0)); // 获取当前进程的 SID +} + +int main() { + printf("===== 测试 getsid =====\n"); + print_ids("Parent"); + + pid_t child = fork(); + if (child == 0) { + // 子进程 + printf("\n[Child] 子进程启动...\n"); + print_ids("Child (before setsid)"); + + // 创建新会话 + pid_t newsid = setsid(); + if (newsid == -1) { + perror("setsid failed"); + exit(EXIT_FAILURE); + } + + printf("[Child] 创建新会话成功,新 SID = %d\n", newsid); + print_ids("Child (after setsid)"); + + TEST_ASSERT(newsid, getpid(), "New sid equal to child pid", "failed to set new sid"); + TEST_ASSERT(getsid(0), getpid(), "Child sid equal to child pid", "failed to set new sid"); + TEST_ASSERT(getpgid(0), getpid(), "Child pgid equal to child pid", "failed to set new sid"); + + exit(EXIT_SUCCESS); + } else if (child > 0) { + // 父进程 + waitpid(child, NULL, 0); // 等待子进程结束 + printf("\n[Parent] 子进程结束后...\n"); + print_ids("Parent"); + + TEST_CONDITION(getsid(0)!=child, "Parent sid unchanged", "Parent sid changed"); + TEST_CONDITION(getpgid(0)!=child, "Parent pgid unchanged", "Parent pgid changed"); + } else { + perror("fork failed"); + exit(EXIT_FAILURE); + } + + return 0; +} \ No newline at end of file diff --git a/user/apps/test_ebpf/Cargo.lock b/user/apps/test_ebpf/Cargo.lock deleted file mode 100644 index ae4fdb0a..00000000 --- a/user/apps/test_ebpf/Cargo.lock +++ /dev/null @@ -1,652 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "allocator-api2" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" -dependencies = [ - "anstyle", - "windows-sys 0.59.0", -] - -[[package]] -name = "assert_matches" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" - -[[package]] -name = "aya" -version = "0.1.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/tiny-aya.git?rev=0689f13#0689f13a7be0d822b3194227c6bee4cb5b0c9bfa" -dependencies = [ - "assert_matches", - "aya-obj", - "bitflags", - "bytes", - "lazy_static", - "libc", - "log", - "object", - "thiserror", - "tokio", -] - -[[package]] -name = "aya-log" -version = "0.2.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/tiny-aya.git?rev=0689f13#0689f13a7be0d822b3194227c6bee4cb5b0c9bfa" -dependencies = [ - "aya", - "aya-log-common", - "bytes", - "log", - "thiserror", - "tokio", -] - -[[package]] -name = "aya-log-common" -version = "0.1.14" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "num_enum", -] - -[[package]] -name = "aya-obj" -version = "0.1.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "bytes", - "core-error", - "hashbrown 0.14.5", - "log", - "object", - "thiserror", -] - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", -] - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bytes" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "core-error" -version = "0.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efcdb2972eb64230b4c50646d8498ff73f5128d196a90c7236eec4cbe8619b8f" -dependencies = [ - "version_check", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "env_filter" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "foldhash" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "indexmap" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" -dependencies = [ - "equivalent", - "hashbrown 0.15.2", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.166" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" -dependencies = [ - "hermit-abi", - "libc", - "wasi", - "windows-sys 0.52.0", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "object" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "crc32fast", - "hashbrown 0.15.2", - "indexmap", - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "syn" -version = "2.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "test_ebpf" -version = "0.1.0" -dependencies = [ - "aya", - "aya-log", - "env_logger", - "log", - "tokio", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.41.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" -dependencies = [ - "backtrace", - "libc", - "mio", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/user/apps/test_ebpf/syscall_ebpf/Cargo.lock b/user/apps/test_ebpf/syscall_ebpf/Cargo.lock deleted file mode 100644 index 231c2cdb..00000000 --- a/user/apps/test_ebpf/syscall_ebpf/Cargo.lock +++ /dev/null @@ -1,575 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "allocator-api2" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" - -[[package]] -name = "anstream" -version = "0.6.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" - -[[package]] -name = "anstyle-parse" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "anyhow" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" - -[[package]] -name = "assert_matches" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" - -[[package]] -name = "aya" -version = "0.1.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/tiny-aya.git?rev=0689f13#0689f13a7be0d822b3194227c6bee4cb5b0c9bfa" -dependencies = [ - "assert_matches", - "aya-obj", - "bitflags", - "bytes", - "lazy_static", - "libc", - "log", - "object", - "thiserror", - "tokio", -] - -[[package]] -name = "aya-obj" -version = "0.1.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "bytes", - "core-error", - "hashbrown 0.14.5", - "log", - "object", - "thiserror", -] - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", -] - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bytes" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.5.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" - -[[package]] -name = "colorchoice" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" - -[[package]] -name = "core-error" -version = "0.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efcdb2972eb64230b4c50646d8498ff73f5128d196a90c7236eec4cbe8619b8f" -dependencies = [ - "version_check", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "foldhash" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - -[[package]] -name = "hashbrown" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" -dependencies = [ - "foldhash", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "indexmap" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" -dependencies = [ - "equivalent", - "hashbrown 0.15.0", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.161" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" -dependencies = [ - "hermit-abi", - "libc", - "wasi", - "windows-sys", -] - -[[package]] -name = "object" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "crc32fast", - "hashbrown 0.15.0", - "indexmap", - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "proc-macro2" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "2.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syscall_ebpf-common" -version = "0.1.0" -dependencies = [ - "aya", -] - -[[package]] -name = "thiserror" -version = "1.0.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" -dependencies = [ - "backtrace", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys", -] - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "xtask" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/user/apps/test_ebpf/syscall_ebpf/syscall_ebpf-ebpf/Cargo.lock b/user/apps/test_ebpf/syscall_ebpf/syscall_ebpf-ebpf/Cargo.lock deleted file mode 100644 index 79cc2cc7..00000000 --- a/user/apps/test_ebpf/syscall_ebpf/syscall_ebpf-ebpf/Cargo.lock +++ /dev/null @@ -1,179 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aya-ebpf" -version = "0.1.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "aya-ebpf-bindings", - "aya-ebpf-cty", - "aya-ebpf-macros", - "rustversion", -] - -[[package]] -name = "aya-ebpf-bindings" -version = "0.1.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "aya-ebpf-cty", -] - -[[package]] -name = "aya-ebpf-cty" -version = "0.2.1" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" - -[[package]] -name = "aya-ebpf-macros" -version = "0.1.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "aya-log-common" -version = "0.1.14" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "num_enum", -] - -[[package]] -name = "aya-log-ebpf" -version = "0.1.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "aya-ebpf", - "aya-log-common", - "aya-log-ebpf-macros", -] - -[[package]] -name = "aya-log-ebpf-macros" -version = "0.1.0" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "aya-log-common", - "aya-log-parser", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "aya-log-parser" -version = "0.1.13" -source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/aya.git?rev=3d57d35#3d57d358e40591acf23dfde740697fbfff026410" -dependencies = [ - "aya-log-common", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustversion" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" - -[[package]] -name = "syn" -version = "2.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syscall_ebpf-common" -version = "0.1.0" - -[[package]] -name = "syscall_ebpf-ebpf" -version = "0.1.0" -dependencies = [ - "aya-ebpf", - "aya-log-ebpf", - "syscall_ebpf-common", -] - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" diff --git a/user/apps/test_epoll/.gitignore b/user/apps/test_epoll/.gitignore new file mode 100644 index 00000000..2702e1c0 --- /dev/null +++ b/user/apps/test_epoll/.gitignore @@ -0,0 +1 @@ +test_epoll diff --git a/user/apps/test_epoll/Makefile b/user/apps/test_epoll/Makefile new file mode 100644 index 00000000..8071b10a --- /dev/null +++ b/user/apps/test_epoll/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)gcc + +.PHONY: all +all: main.c + $(CC) -static -o test_epoll main.c + +.PHONY: install clean +install: all + mv test_epoll $(DADK_CURRENT_BUILD_DIR)/test_epoll + +clean: + rm test_epoll *.o + +fmt: diff --git a/user/apps/test_epoll/main.c b/user/apps/test_epoll/main.c new file mode 100644 index 00000000..f1cfd72e --- /dev/null +++ b/user/apps/test_epoll/main.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_EVENTS 10 + +static int efd; // eventfd 描述符 +static int efd2; // eventfd 描述符 + +// 工作线程:等待2秒后向 eventfd 写入事件通知 +void *worker_thread(void *arg) { + uint64_t u = 1; + printf("工作线程:等待2秒后发送事件通知...\n"); + sleep(2); // 模拟耗时任务 + printf("工作线程:发送事件通知...\n"); + if (write(efd, &u, sizeof(u)) != sizeof(u)) { + perror("工作线程写入 eventfd 出错"); + exit(EXIT_FAILURE); + } + printf("工作线程:事件通知已发送\n"); + return NULL; +} + +int main() { + int epoll_fd; + struct epoll_event ev, events[MAX_EVENTS]; + int nfds; + pthread_t tid; + + // 创建 eventfd,对象初始计数为 0 + efd = eventfd(0, 0); + if (efd == -1) { + perror("创建 eventfd 失败"); + exit(EXIT_FAILURE); + } else { + printf("创建 eventfd 成功,描述符 = %d\n", efd); + } + + efd2 = dup(efd); // 复制 eventfd 描述符 + if (efd2 == -1) { + perror("复制 eventfd 失败"); + close(efd); + exit(EXIT_FAILURE); + } else { + printf("复制 eventfd 成功,描述符 = %d\n", efd2); + } + + // 创建 epoll 实例 + epoll_fd = epoll_create1(0); + if (epoll_fd == -1) { + perror("创建 epoll 实例失败"); + close(efd); + exit(EXIT_FAILURE); + } + + // 将 eventfd 添加到 epoll 监听队列,关注可读事件 + ev.events = EPOLLIN; + ev.data.fd = efd; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, efd, &ev) == -1) { + perror("epoll_ctl 添加 eventfd 失败"); + close(efd); + close(epoll_fd); + exit(EXIT_FAILURE); + } + + // 将复制的 eventfd 添加到 epoll 监听队列,关注可读事件 + ev.data.fd = efd2; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, efd2, &ev) == -1) { + perror("epoll_ctl 添加复制的 eventfd 失败"); + close(efd); + close(efd2); + close(epoll_fd); + exit(EXIT_FAILURE); + } + + // 创建工作线程,模拟事件发生 + if (pthread_create(&tid, NULL, worker_thread, NULL) != 0) { + perror("创建工作线程失败"); + close(efd); + close(efd2); + close(epoll_fd); + exit(EXIT_FAILURE); + } + + printf("主线程:使用 epoll_wait 等待事件...\n"); + + // 阻塞等待事件发生 + nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); + if (nfds == -1) { + perror("epoll_wait 失败"); + exit(EXIT_FAILURE); + } else { + printf("主线程:epoll_wait 返回,事件数量 = %d\n", nfds); + } + + if (nfds != 2) { + printf("主线程:事件数量不匹配,预期 2,实际 %d\n", nfds); + exit(EXIT_FAILURE); + } + + // 由于dup复制了 eventfd 描述符,所以 只需要处理一个就行 + nfds -= 1; + // 处理就绪事件 + for (int i = 0; i < nfds; i++) { + if (events[i].data.fd == efd || events[i].data.fd == efd2) { + uint64_t count; + int fd = events[i].data.fd; + printf("主线程:事件发生在 fd = %d\n", fd); + if (read(fd, &count, sizeof(count)) != sizeof(count)) { + perror("从 eventfd 读取失败"); + exit(EXIT_FAILURE); + } + printf("主线程:接收到 eventfd 事件,计数值 = %lu\n", count); + } + } + + // 等待工作线程结束 + pthread_join(tid, NULL); + + int r = close(epoll_fd); + if (r == -1) { + perror("关闭 epoll 实例失败"); + exit(EXIT_FAILURE); + } else { + printf("关闭 epoll 实例成功\n"); + } + close(efd); + close(efd2); // 关闭复制的 eventfd 描述符 + printf("test_epoll ok\n"); + return 0; +} \ No newline at end of file diff --git a/user/apps/test_fstat/Makefile b/user/apps/test_fstat/Makefile index 6fd5da61..3ccc94bc 100644 --- a/user/apps/test_fstat/Makefile +++ b/user/apps/test_fstat/Makefile @@ -1,5 +1,5 @@ ifeq ($(ARCH), x86_64) - CROSS_COMPILE=x86_64-linux-musl- + CROSS_COMPILE=x86_64-linux-gnu- else ifeq ($(ARCH), riscv64) CROSS_COMPILE=riscv64-linux-musl- endif @@ -8,7 +8,7 @@ CC=$(CROSS_COMPILE)gcc .PHONY: all all: main.c - $(CC) -static -o test_fstat main.c + $(CC) -o test_fstat main.c .PHONY: install clean install: all diff --git a/user/apps/test_newfstatat/.gitignore b/user/apps/test_newfstatat/.gitignore new file mode 100644 index 00000000..47c6d617 --- /dev/null +++ b/user/apps/test_newfstatat/.gitignore @@ -0,0 +1 @@ +test_newfstatat diff --git a/user/apps/test_newfstatat/Makefile b/user/apps/test_newfstatat/Makefile new file mode 100644 index 00000000..49682068 --- /dev/null +++ b/user/apps/test_newfstatat/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-gnu- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)gcc + +.PHONY: all +all: main.c + $(CC) -o test_newfstatat main.c + +.PHONY: install clean +install: all + mv test_newfstatat $(DADK_CURRENT_BUILD_DIR)/test_newfstatat + +clean: + rm test_newfstatat *.o + +fmt: diff --git a/user/apps/test_newfstatat/main.c b/user/apps/test_newfstatat/main.c new file mode 100644 index 00000000..3411fd88 --- /dev/null +++ b/user/apps/test_newfstatat/main.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include + + + +#define TEST_DIR "test_dir" +#define TEST_FILE "test_file" + +void create_test_files() { + mkdir(TEST_DIR, 0755); + int fd = open(TEST_FILE, O_CREAT | O_RDWR, 0644); + if (fd >= 0) close(fd); +} + +void cleanup_test_files() { + unlink(TEST_FILE); + rmdir(TEST_DIR); +} + +void run_test(const char *name, int (*test_func)(), int expected) { + printf("Testing %s... ", name); + int result = test_func(); + if (result == expected) { + printf("[PASS]\n"); + } else { + printf("[FAILED] (expected %d, got %d)\n", expected, result); + } +} + +int test_normal_file() { + struct stat st; + return syscall(__NR_newfstatat, AT_FDCWD, TEST_FILE, &st, 0); +} + +int test_directory() { + struct stat st; + return syscall(__NR_newfstatat, AT_FDCWD, TEST_DIR, &st, 0); +} + +int test_invalid_fd() { + struct stat st; + return syscall(__NR_newfstatat, -1, TEST_FILE, &st, 0); +} + +int test_nonexistent_path() { + struct stat st; + return syscall(__NR_newfstatat, AT_FDCWD, "nonexistent_file", &st, 0); +} + +int main() { + create_test_files(); + + run_test("normal file stat", test_normal_file, 0); + run_test("directory stat", test_directory, 0); + run_test("invalid file descriptor", test_invalid_fd, -1); + run_test("nonexistent path", test_nonexistent_path, -1); + + cleanup_test_files(); + return 0; +} diff --git a/user/apps/test_poll/.gitignore b/user/apps/test_poll/.gitignore index 96903813..36fe7a1d 100644 --- a/user/apps/test_poll/.gitignore +++ b/user/apps/test_poll/.gitignore @@ -1 +1,3 @@ test_poll +test_ppoll +*.o \ No newline at end of file diff --git a/user/apps/test_poll/Makefile b/user/apps/test_poll/Makefile index 6604e069..437f0ef2 100644 --- a/user/apps/test_poll/Makefile +++ b/user/apps/test_poll/Makefile @@ -8,14 +8,17 @@ BIN_NAME=test_poll CC=$(CROSS_COMPILE)gcc .PHONY: all -all: main.c +all: main.c ppoll.c $(CC) -static -o $(BIN_NAME) main.c + $(CC) -static -o test_ppoll ppoll.c .PHONY: install clean install: all mv $(BIN_NAME) $(DADK_CURRENT_BUILD_DIR)/$(BIN_NAME) + mv test_ppoll $(DADK_CURRENT_BUILD_DIR)/test_ppoll clean: rm $(BIN_NAME) *.o + rm test_ppoll fmt: diff --git a/user/apps/test_poll/ppoll.c b/user/apps/test_poll/ppoll.c new file mode 100644 index 00000000..0300bdd1 --- /dev/null +++ b/user/apps/test_poll/ppoll.c @@ -0,0 +1,148 @@ +#include +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RED "\x1B[31m" +#define GREEN "\x1B[32m" +#define RESET "\x1B[0m" + +// 测试用例1:基本功能测试(管道I/O) +void test_basic_functionality() { + int pipefd[2]; + struct pollfd fds[1]; + struct timespec timeout = {5, 0}; // 5秒超时 + + printf("=== Test 1: Basic functionality test ===\n"); + + // 创建管道 + if (pipe(pipefd) == -1) { + perror("pipe creation failed"); + exit(EXIT_FAILURE); + } + + // 设置监听读端管道 + fds[0].fd = pipefd[0]; + fds[0].events = POLLIN; + + printf("Test scenario 1: Wait with no data (should timeout)\n"); + int ret = ppoll(fds, 1, &timeout, NULL); + if (ret == 0) { + printf(GREEN "Test passed: Correct timeout\n" RESET); + } else { + printf(RED "Test failed: Return value %d\n" RESET, ret); + } + + // 向管道写入数据 + const char *msg = "test data"; + write(pipefd[1], msg, strlen(msg)); + + printf( + "\nTest scenario 2: Should return immediately when data is available\n"); + timeout.tv_sec = 5; + ret = ppoll(fds, 1, &timeout, NULL); + if (ret > 0 && (fds[0].revents & POLLIN)) { + printf(GREEN "Test passed: Data detected\n" RESET); + } else { + printf(RED "Test failed: Return value %d, revents %d\n" RESET, ret, + fds[0].revents); + } + + close(pipefd[0]); + close(pipefd[1]); +} + +// 测试用例2:信号屏蔽测试 +void test_signal_handling() { + printf("\n=== Test 2: Signal handling test ===\n"); + sigset_t mask, orig_mask; + struct timespec timeout = {5, 0}; + struct pollfd fds[1]; + + fds[0].fd = -1; + fds[0].events = 0; + + // 设置信号屏蔽 + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + // 阻塞SIGUSR1,并保存原来的信号掩码 + if (sigprocmask(SIG_BLOCK, &mask, &orig_mask)) { + perror("sigprocmask"); + exit(EXIT_FAILURE); + } + + printf("Test scenario: Signal should not interrupt when masked\n"); + pid_t pid = fork(); + if (pid == 0) { // 子进程 + sleep(2); // 等待父进程进入ppoll + kill(getppid(), SIGUSR1); + exit(0); + } + + int ret = ppoll(fds, 1, &timeout, &mask); + + if (ret == 0) { + printf(GREEN "Test passed: Completed full 5 second wait\n" RESET); + } else { + printf(RED "Test failed: Premature return %d\n" RESET, errno); + } + + waitpid(pid, NULL, 0); + + // 检查并消费挂起的SIGUSR1信号 + sigset_t pending; + sigpending(&pending); + if (sigismember(&pending, SIGUSR1)) { + int sig; + sigwait(&mask, &sig); // 主动消费信号 + + printf("Consumed pending SIGUSR1 signal\n"); + } + // 恢复原来的信号掩码 + sigprocmask(SIG_SETMASK, &orig_mask, NULL); +} + +// 测试用例3:精确超时测试 +void test_timeout_accuracy() { + printf("\n=== Test 3: Timeout accuracy test ===\n"); + struct timespec start, end, timeout = {0, 500000000}; + struct pollfd fds[1]; + fds[0].fd = -1; + fds[0].events = 0; + + clock_gettime(CLOCK_MONOTONIC, &start); + int ret = ppoll(fds, 1, &timeout, NULL); + clock_gettime(CLOCK_MONOTONIC, &end); + + long elapsed = (end.tv_sec - start.tv_sec) * 1000000 + + (end.tv_nsec - start.tv_nsec) / 1000; + + printf("Expected timeout: 500ms, Actual elapsed: %.3fms\n", elapsed / 1000.0); + if (labs(elapsed - 500000) < 50000) { // 允许±50ms误差 + printf(GREEN "Test passed: Timeout within acceptable range\n" RESET); + } else { + printf(RED "Test failed: Timeout deviation too large\n" RESET); + } +} + +int main() { + // 设置非阻塞标准输入 + fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); + + test_basic_functionality(); + test_signal_handling(); + test_timeout_accuracy(); + + return 0; +} diff --git a/user/apps/test_stack/.gitignore b/user/apps/test_stack/.gitignore new file mode 100644 index 00000000..a1c1e2e6 --- /dev/null +++ b/user/apps/test_stack/.gitignore @@ -0,0 +1 @@ +test_stack \ No newline at end of file diff --git a/user/apps/test_stack/Makefile b/user/apps/test_stack/Makefile new file mode 100644 index 00000000..349124d1 --- /dev/null +++ b/user/apps/test_stack/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)gcc + +.PHONY: all +all: main.c + $(CC) -static -o test_stack main.c + +.PHONY: install clean +install: all + mv test_stack $(DADK_CURRENT_BUILD_DIR)/test_stack + +clean: + rm test_stack *.o + +fmt: diff --git a/user/apps/test_stack/main.c b/user/apps/test_stack/main.c new file mode 100644 index 00000000..8bbb6323 --- /dev/null +++ b/user/apps/test_stack/main.c @@ -0,0 +1,13 @@ +#include + +void overflow(int depth) { + char buffer[1024 * 1024]; // 占用一些栈空间 + printf("Recursion depth: %d\n", depth); + overflow(depth + 1); // 递归调用 +} + +int main() { + overflow(1); + printf("This line will not be printed due to stack overflow.\n"); + return 0; +} diff --git a/user/dadk/config/busybox_1_35_0.toml b/user/dadk/config/busybox_1_35_0.toml new file mode 100644 index 00000000..39253931 --- /dev/null +++ b/user/dadk/config/busybox_1_35_0.toml @@ -0,0 +1,36 @@ +# 用户程序名称 +name = "busybox" +# 版本号 +version = "1.35.0" +# 用户程序描述信息 +description = "" +# (可选)是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果 +build-once = false +# (可选) 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装 +install-once = false +# 目标架构 +# 可选值:"x86_64", "aarch64", "riscv64" +target-arch = ["x86_64"] +# 任务源 +[task-source] +# 构建类型 +# 可选值:"build-from_source", "install-from-prebuilt" +type = "build-from-source" +# 构建来源 +# "build_from_source" 可选值:"git", "local", "archive" +# "install_from_prebuilt" 可选值:"local", "archive" +source = "local" +# 路径或URL +source-path = "user/apps/busybox" +# 构建相关信息 +[build] +# (可选)构建命令 +build-command = "make install" +# 安装相关信息 +[install] +# (可选)安装到DragonOS的路径 +in-dragonos-path = "/bin" +# 清除相关信息 +[clean] +# (可选)清除命令 +clean-command = "make distclean" diff --git a/user/dadk/config/core_utils-9.4.0.toml b/user/dadk/config/core_utils-9.4.0.toml index eaf93230..8860f901 100644 --- a/user/dadk/config/core_utils-9.4.0.toml +++ b/user/dadk/config/core_utils-9.4.0.toml @@ -22,6 +22,10 @@ type = "build-from-source" source = "archive" # 路径或URL source-path = "https://mirrors.dragonos.org.cn/pub/third_party/gnu/coreutils/coreutils-9.4.tar.xz" + +# 把压缩包中的哪个目录作为根目录(可选),仅当 source = "archive" 时生效 +archive-rootdir = "coreutils-9.4" + # 构建相关信息 [build] # (可选)构建命令 diff --git a/user/dadk/config/dragon_reach-0.1.0.toml b/user/dadk/config/dragon_reach-0.1.0.toml index fcefd08e..59fd0b31 100644 --- a/user/dadk/config/dragon_reach-0.1.0.toml +++ b/user/dadk/config/dragon_reach-0.1.0.toml @@ -47,3 +47,4 @@ clean-command = "make clean" # 环境变量 # 注意:因为没有环境变量,所以这里不包含[[envs]]部分 + diff --git a/user/dadk/config/glibc_bin_ubuntu2404.toml b/user/dadk/config/glibc_bin_ubuntu2404.toml new file mode 100644 index 00000000..f455b198 --- /dev/null +++ b/user/dadk/config/glibc_bin_ubuntu2404.toml @@ -0,0 +1,40 @@ +# 用户程序名称 +name = "glibc_bin_ubuntu2404" +# 版本号 +version = "2.39" +# 用户程序描述信息 +description = "GNU C Library for Ubuntu 24.04" +# (可选)默认: false 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果 +build-once = false +# (可选) 默认: false 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装 +install-once = false +# 目标架构 +# 可选值:"x86_64", "aarch64", "riscv64", "loongarch64" +target-arch = ["x86_64"] +# 任务源 +[task-source] +# 构建类型 +# 可选值:"build-from-source", "install-from-prebuilt" +type = "install-from-prebuilt" +# 构建来源 +# "build_from_source" 可选值:"git", "local", "archive" +# "install_from_prebuilt" 可选值:"local", "archive" +source = "archive" +# 路径或URL +source-path = "https://mirrors.dragonos.org.cn/pub/third_party/gnu/glibc-bin/glibc-ubuntu2404-x86_64-202505111756-8f3207567bf10f4d09027b2cd84b7807.tar.xz" +archive-rootdir = "sysroot/" + +[build] + +# 安装相关信息 +[install] +# (可选)安装到DragonOS的路径 +in-dragonos-path = "/" +# 清除相关信息 +[clean] +# (可选)清除命令 +clean-command = "" +# (可选)依赖项 +# 注意:如果没有依赖项,忽略此项,不允许只留一个[[depends]] +# (可选)环境变量 +# 注意:如果没有环境变量,忽略此项,不允许只留一个[[envs]] diff --git a/user/dadk/config/musl_1_2_4.toml b/user/dadk/config/musl_1_2_4.toml index bad7c371..ec2026f4 100644 --- a/user/dadk/config/musl_1_2_4.toml +++ b/user/dadk/config/musl_1_2_4.toml @@ -22,10 +22,13 @@ type = "build-from-source" source = "archive" # 路径或URL source-path = "https://mirrors.dragonos.org.cn/pub/third_party/musl/musl-1.2.4.tar.gz" +# 把压缩包中的哪个目录作为根目录(可选),仅当 source = "archive" 时生效 +archive-rootdir = "musl-1.2.4" + # 构建相关信息 [build] # (可选)构建命令 -build-command = "touch config.mak && DESTDIR=$DADK_CURRENT_BUILD_DIR make install -j $(nproc)" +build-command = "touch config.mak && DESTDIR=$DADK_CURRENT_BUILD_DIR make install -j $(nproc) && rm -rf $DADK_CURRENT_BUILD_DIR/lib && rm -rf $DADK_CURRENT_BUILD_DIR/lib64" # 安装相关信息 [install] # (可选)安装到DragonOS的路径 diff --git a/user/dadk/config/riscv_init-0.1.0.toml b/user/dadk/config/riscv_init-0.1.0.toml index 385c655a..636099bf 100644 --- a/user/dadk/config/riscv_init-0.1.0.toml +++ b/user/dadk/config/riscv_init-0.1.0.toml @@ -29,7 +29,7 @@ build-command = "make install" # 安装相关信息 [install] # (可选)安装到DragonOS的路径 -in-dragonos-path = "/bin" +in-dragonos-path = "/" # 清除相关信息 [clean] # (可选)清除命令 diff --git a/user/dadk/config/test_epoll.toml b/user/dadk/config/test_epoll.toml new file mode 100644 index 00000000..405bd8e6 --- /dev/null +++ b/user/dadk/config/test_epoll.toml @@ -0,0 +1,46 @@ +# 用户程序名称 +name = "test_epoll" +# 版本号 +version = "0.1.0" +# 用户程序描述信息 +description = "test_epoll" +# (可选)默认: false 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果 +build-once = false +# (可选) 默认: false 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装 +install-once = false +# 目标架构 +# 可选值:"x86_64", "aarch64", "riscv64" +target-arch = ["x86_64"] +# 任务源 +[task-source] +# 构建类型 +# 可选值:"build-from_source", "install-from-prebuilt" +type = "build-from-source" +# 构建来源 +# "build_from_source" 可选值:"git", "local", "archive" +# "install_from_prebuilt" 可选值:"local", "archive" +source = "local" +# 路径或URL +source-path = "user/apps/test_epoll" +# 构建相关信息 +[build] +# (可选)构建命令 +build-command = "make install" +# 安装相关信息 +[install] +# (可选)安装到DragonOS的路径 +in-dragonos-path = "/bin" +# 清除相关信息 +[clean] +# (可选)清除命令 +clean-command = "make clean" +# (可选)依赖项 +# 注意:如果没有依赖项,忽略此项,不允许只留一个[[depends]] +# [[depends]] +# name = "depend1" +# version = "0.1.1" +# (可选)环境变量 +# 注意:如果没有环境变量,忽略此项,不允许只留一个[[envs]] +# [[envs]] +# key = "PATH" +# value = "/usr/bin" diff --git a/user/dadk/config/test_newfstatat-0.1.0.toml b/user/dadk/config/test_newfstatat-0.1.0.toml new file mode 100644 index 00000000..37e68910 --- /dev/null +++ b/user/dadk/config/test_newfstatat-0.1.0.toml @@ -0,0 +1,36 @@ +# 用户程序名称 +name = "test_newfstatat" +# 版本号 +version = "0.1.0" +# 用户程序描述信息 +description = "一个用来测试 newfstatat 能够正常运行的app" +# (可选)默认: false 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果 +build-once = false +# (可选) 默认: false 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装 +install-once = false +# 目标架构 +# 可选值:"x86_64", "aarch64", "riscv64", "loongarch64" +target-arch = ["x86_64", "riscv64"] +# 任务源 +[task-source] +# 构建类型 +# 可选值:"build-from_source", "install-from-prebuilt" +type = "build-from-source" +# 构建来源 +# "build_from_source" 可选值:"git", "local", "archive" +# "install_from_prebuilt" 可选值:"local", "archive" +source = "local" +# 路径或URL +source-path = "user/apps/test_newfstatat" +# 构建相关信息 +[build] +# (可选)构建命令 +build-command = "make install" +# 安装相关信息 +[install] +# (可选)安装到DragonOS的路径 +in-dragonos-path = "/bin" +# 清除相关信息 +[clean] +# (可选)清除命令 +clean-command = "make clean" diff --git a/user/dadk/config/test_processgroup_0_1_0.toml b/user/dadk/config/test_processgroup_0_1_0.toml new file mode 100644 index 00000000..619174da --- /dev/null +++ b/user/dadk/config/test_processgroup_0_1_0.toml @@ -0,0 +1,47 @@ +# 用户程序名称 +name = "test-processgroup" + +# 版本号 +version = "0.1.0" + +# 用户程序描述信息 +description = "测试进程组的系统调用" + +# 是否只构建一次 +build-once = false + +# 是否只安装一次 +install-once = false + +# 目标架构 +target-arch = ["x86_64"] + +# 任务源 +[task-source] +# 构建类型 +type = "build-from-source" +# 构建来源 +source = "local" +# 路径或URL +source-path = "user/apps/test-processgroup" + +# 构建相关信息 +[build] +# 构建命令 +build-command = "make install -j $(nproc)" + +# 安装相关信息 +[install] +# 安装到DragonOS的路径 +in-dragonos-path = "/bin" + +# 清除相关信息 +[clean] +# 清除命令 +clean-command = "make clean" + +# 依赖项 +# 注意:因为没有依赖项,所以这里不包含[[depends]]部分 + +# 环境变量 +# 注意:因为没有环境变量,所以这里不包含[[envs]]部分 diff --git a/user/dadk/config/test_session_0_1_0.toml b/user/dadk/config/test_session_0_1_0.toml new file mode 100644 index 00000000..57e8a335 --- /dev/null +++ b/user/dadk/config/test_session_0_1_0.toml @@ -0,0 +1,47 @@ +# 用户程序名称 +name = "test-session" + +# 版本号 +version = "0.1.0" + +# 用户程序描述信息 +description = "测试会话的系统调用" + +# 是否只构建一次 +build-once = false + +# 是否只安装一次 +install-once = false + +# 目标架构 +target-arch = ["x86_64"] + +# 任务源 +[task-source] +# 构建类型 +type = "build-from-source" +# 构建来源 +source = "local" +# 路径或URL +source-path = "user/apps/test-session" + +# 构建相关信息 +[build] +# 构建命令 +build-command = "make install -j $(nproc)" + +# 安装相关信息 +[install] +# 安装到DragonOS的路径 +in-dragonos-path = "/bin" + +# 清除相关信息 +[clean] +# 清除命令 +clean-command = "make clean" + +# 依赖项 +# 注意:因为没有依赖项,所以这里不包含[[depends]]部分 + +# 环境变量 +# 注意:因为没有环境变量,所以这里不包含[[envs]]部分 diff --git a/user/dadk/config/test_stack_0_1_0.toml b/user/dadk/config/test_stack_0_1_0.toml new file mode 100644 index 00000000..90ee57ed --- /dev/null +++ b/user/dadk/config/test_stack_0_1_0.toml @@ -0,0 +1,32 @@ +# 用户程序名称 +name = "test_stack" +# 版本号 +version = "0.1.0" +# 用户程序描述信息 +description = "test_stack" +# 目标架构 +target-arch = ["x86_64"] + +# 任务源 +[task-source] +# 构建类型 +type = "build-from-source" +# 构建来源 +source = "local" +# 路径或URL +source-path = "user/apps/test_stack" + +# 构建相关信息 +[build] +# (可选)构建命令 +build-command = "make install" + +# 安装相关信息 +[install] +# (可选)安装到DragonOS的路径 +in-dragonos-path = "/bin" + +# 清除相关信息 +[clean] +# (可选)清除命令 +clean-command = "make clean" \ No newline at end of file diff --git a/user/sysconfig/etc/init.d/rcS b/user/sysconfig/etc/init.d/rcS new file mode 100755 index 00000000..e72af21c --- /dev/null +++ b/user/sysconfig/etc/init.d/rcS @@ -0,0 +1,3 @@ +#!/bin/sh +echo "[rcS] Running system init script..." +/bin/about.elf \ No newline at end of file diff --git a/user/sysconfig/etc/inittab b/user/sysconfig/etc/inittab new file mode 100644 index 00000000..bdd68925 --- /dev/null +++ b/user/sysconfig/etc/inittab @@ -0,0 +1,27 @@ +# /etc/inittab +::sysinit:busybox sh /etc/init.d/rcS # 系统初始化脚本 + +::askfirst:-/bin/busybox sh --login + + +# /etc/inittab - 根据源码弄出来的默认inittab +# https://code.dragonos.org.cn/xref/busybox-1.35.0/init/init.c#679 + +# # 系统初始化脚本 +# ::sysinit:/etc/init.d/rcS + +# # askfirst shell +# ::askfirst:-/bin/sh +# tty2::askfirst:-/bin/sh +# tty3::askfirst:-/bin/sh +# tty4::askfirst:-/bin/sh + +# # Ctrl-Alt-Del 重启 +# ::ctrlaltdel:/sbin/reboot + +# # 系统关闭或重启前的动作 +# ::shutdown:/bin/umount -a -r +# ::shutdown:/sbin/swapoff -a + +# # 收到 QUIT 信号时重启 init +# ::restart:/sbin/init diff --git a/user/sysconfig/etc/profile b/user/sysconfig/etc/profile new file mode 100644 index 00000000..0c937bd4 --- /dev/null +++ b/user/sysconfig/etc/profile @@ -0,0 +1,3 @@ +#!/bin/sh +export PATH=/bin:/usr/bin:/usr/local/bin +trap ' ' INT \ No newline at end of file diff --git a/user/sysconfig/etc/reach/system/shell.service b/user/sysconfig/etc/reach/system/shell.service index 75bd9a40..94adc314 100644 --- a/user/sysconfig/etc/reach/system/shell.service +++ b/user/sysconfig/etc/reach/system/shell.service @@ -6,3 +6,5 @@ Type=simple ExecStart=/bin/NovaShell Restart=always ExecStartPre=-/bin/about.elf +Environment=PATH=/bin:/usr/bin:/usr/local/bin +Environment=LD_LIBRARY_PATH=/usr/lib:/usr/lib64:/usr/local/lib