diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE index 204f577..00b7db7 100644 --- a/.github/ISSUE_TEMPLATE +++ b/.github/ISSUE_TEMPLATE @@ -4,7 +4,8 @@ **Actual behavior**: [describe the actual behavior, which is presented through the repro.]. -**Build information**: [output of `rustc -V`, `git rev-parse HEAD`, `qemu-i386 -version`, `uname -a`, etc.] +**Build information**: [only when using a self build version: output of `rustc -V`, `git rev-parse HEAD` `qemu-i386 -version`, `uname -a`, etc.] +**Redox release**: [only when using a prebuild version: redox version] **Blocking/related**: [issues or PRs blocking or being related to this issue.] diff --git a/.gitignore b/.gitignore index a8b6ee3..378eac2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1 @@ -Cargo.lock build -target -initfs/bin -filesystem/bin -filesystem/ref -filesystem/sbin diff --git a/.gitmodules b/.gitmodules index 7c83399..ffbef5c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,60 +1,21 @@ -[submodule "rust"] - path = rust - url = https://github.com/redox-os/rust.git -[submodule "ion"] - path = programs/ion - url = https://github.com/redox-os/ion.git -[submodule "programs/coreutils"] - path = programs/coreutils - url = https://github.com/redox-os/coreutils.git -[submodule "schemes/redoxfs"] - path = schemes/redoxfs - url = https://github.com/redox-os/redoxfs -[submodule "programs/extrautils"] - path = programs/extrautils - url = https://github.com/redox-os/extrautils.git -[submodule "programs/smith"] - path = programs/smith - url = https://github.com/IGI-111/Smith.git -[submodule "programs/userutils"] - path = programs/userutils - url = https://github.com/redox-os/userutils.git -[submodule "programs/netutils"] - path = programs/netutils - url = https://github.com/redox-os/netutils.git -[submodule "schemes/orbital"] - path = schemes/orbital - url = https://github.com/redox-os/orbital.git -[submodule "programs/orbutils"] - path = programs/orbutils - url = https://github.com/redox-os/orbutils.git -[submodule "filesystem/ui"] - path = filesystem/ui - url = https://github.com/redox-os/orbdata.git -[submodule "programs/acid"] - path = programs/acid - url = https://github.com/redox-os/acid.git -[submodule "programs/tar"] - path = programs/tar - url = https://github.com/redox-os/tar-rs.git -[submodule "programs/pkgutils"] - path = programs/pkgutils - url = https://github.com/redox-os/pkgutils.git +[submodule "bootloader"] + path = bootloader + url = https://github.com/redox-os/bootloader.git +[submodule "cookbook"] + path = cookbook + url = https://github.com/redox-os/cookbook.git [submodule "installer"] path = installer url = https://github.com/redox-os/installer.git -[submodule "syscall"] - path = syscall - url = https://github.com/redox-os/syscall.git -[submodule "crates/docgen"] - path = crates/docgen - url = https://github.com/redox-os/docgen.git -[submodule "programs/binutils"] - path = programs/binutils - url = https://github.com/redox-os/binutils.git -[submodule "libc-artifacts"] - path = libc-artifacts - url = https://github.com/redox-os/libc-artifacts.git -[submodule "programs/games"] - path = programs/games - url = https://github.com/redox-os/games.git +[submodule "isolinux"] + path = isolinux + url = https://github.com/redox-os/isolinux.git +[submodule "kernel"] + path = kernel + url = https://github.com/redox-os/kernel.git +[submodule "rust"] + path = rust + url = https://github.com/redox-os/rust.git +[submodule "redoxfs"] + path = redoxfs + url = https://github.com/redox-os/redoxfs.git diff --git a/.travis.yml b/.travis.yml index 22670b6..c438058 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,23 +5,30 @@ rust: cache: cargo os: - linux +#- osx +#matrix: +# allow_failures: +# - os: osx dist: trusty before_install: -- if [ `uname` = "Linux" ]; then - sudo apt-get install -qq nasm pkg-config fuse libfuse-dev genisoimage syslinux && +- if [ "$TRAVIS_OS_NAME" == "linux" ]; then + sudo apt-key adv -q --batch --yes --keyserver keyserver.ubuntu.com --recv-keys AA12E97F0881517F && + sudo add-apt-repository 'deb https://static.redox-os.org/toolchain/apt ./' && + sudo apt-get update -qq && + sudo apt-get purge -qq binutils-doc && + sudo apt-get install -qq nasm pkg-config fuse libfuse-dev genisoimage syslinux x86-64-unknown-redox-gcc && sudo modprobe fuse && sudo chmod 666 /dev/fuse && sudo chown root:$USER /etc/fuse.conf; fi -- if [ `uname` = "Darwin" ]; then brew update && - brew install nasm gcc49 pkg-config Caskroom/cask/osxfuse && - brew tap glendc/gcc_cross_compilers && - brew install glendc/gcc_cross_compilers/x64-elf-binutils glendc/gcc_cross_compilers/x64-elf-gcc; +- if [ "$TRAVIS_OS_NAME" == "osx" ]; then + brew update && + brew install nasm pkg-config Caskroom/cask/osxfuse && + travis_wait 30 brew install redox-os/gcc_cross_compilers/x86_64-elf-gcc; fi +- cd cookbook && ./setup.sh && cd .. script: -- make clean && - make update && - make build/harddrive.bin.gz build/livedisk.bin.gz build/livedisk.iso -j 2 +- make clean && make travis notifications: email: false webhooks: http://37.139.9.28:54863/travis @@ -29,11 +36,10 @@ deploy: provider: releases api_key: secure: E5w3mgFbW4fAFNJn0FGcvwGKK33d+StC4izDX7dsGPxX/gwAsMnZqabDWpsrj8n/jFI5NdPzuyz4Ojkip4AXrEs0DWfX96d9CSWvJmWIirwwKhALnxZ5cqnHnBXY3wpk9k8MKpdODzKs3ZjM3pPug2jjjp2EHdrEV6iyc8LlnLAJutbtPpNJv0rJrx/TfCZRx70YWKQyx2Lfx5P6Vj+5yoYsKk+SHmKZlIQfj2E1cfC8+/w+fzc9CRTNhM9XFBisKnu9qql3nNhEW8VUNQ9FnltGpunmcTnCmsKzHPfs8Zv6kM/6y3wuoqxwPnIwRu+zsntkjM/eT7Zy3DtTBqJDjq+L5jov50QWOxzjUuFYMv0lAMeMC0PIGn0ECpFs546M+Wqvd7HKgabac0UhilEBPbinOdW+6aOOhbo+Fe2I2ec0XIGxlQpccQeWQUsjjOQ+6QuvnpPE+CbvQaVyrx27rVAkqD44cOP8xqOq2Es651J+Dt0O1OIhLdPB3FxOLCDpEIHU5Ojci1QbUxZgGKjShpo44nNqcTv7v71JrfzFSVG2pF9a35Mpo6bFEkzyQprOyrwH2fcnN+4jyxdJXzdNsgraXsQopWAB5cL/8i7SXMwHy9ivpFaX/zgoHQqpc1a4VjrmTtPA08rLORIllw9CplfvJNsmNmCi2aSeTXR06Xk= - file: - - build/harddrive.bin.gz - - build/livedisk.bin.gz - - build/livedisk.iso + file_glob: true + file: build/travis/* on: repo: redox-os/redox tags: true + condition: $TRAVIS_OS_NAME = linux skip_cleanup: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a73625f..4c27589 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,17 +1,18 @@ # Contributing to Redox -Thank you for your interest in contributing to Redox! This document is a guide to help newcomers contribute! -There are many ways to help us out and we appreciate all of them. +Thank you for your interest in contributing to Redox! This document will outline the basics of where to start if you wish to contribute to the project. There are many ways to help us out and and we appreciate all of them. We look forward to your contribution! ## Index * [Communication](#communication) * [Chat](#chat) - * [Reddit](#reddit) -* [Direct Contributing](#direct-contributing) - * [Low-Hanging Fruit - Easy Targets for Newbies](#easy-targets) - * [GitHub Issues](#gh-issues) + * [GitHub Issues](#issues) * [Pull Requests](#prs) + * [Discourse](#discourse) + * [Reddit](#reddit) + * [News](#news) +* [Code Contributions](#code-contributions) + * [Low-Hanging Fruit - Easy Targets for Newbies](#easy-targets) * [Creating a Pull Request](#creating-a-pr) * [Best Practices/Guidelines](#best-practices) * [General](#general) @@ -22,10 +23,11 @@ There are many ways to help us out and we appreciate all of them. * [Git](#git-style-guidelines) * [Other Ways to Contribute](#other) * [Graphic Design](#graphic-design) + * [Patreon](#patreon) ## Other External Links -* [redox-os.org](http://redox-os.org) +* [redox-os.org](https://redox-os.org) * [rust-os-comparison](https://github.com/flosse/rust-os-comparison) * [rust-lang.org](http://rust-lang.org) @@ -33,70 +35,77 @@ There are many ways to help us out and we appreciate all of them. ### Chat -The quickest and most open way to communicate with the Redox team is on our chat server. Currently, the only way to join it is by sending an email to [info@redox-os.org](mailto:info@redox-os.org), which might take a little while, since it's not automated. We're currently working on an easier way to do this, but this is the most convenient way right now. +The quickest and most open way to communicate with the Redox team is on our chat server. Currently, you can only get an invite by sending an email request to [info@redox-os.org](mailto:info@redox-os.org), which might take a little while, since it's not automated. Simply say you'd like to join the chat. We're working on an better way to do this, but this is the best way right now. + +### GitHub Issues + +A bit more formal way of communication with fellow Redox devs, but a little less quick and convenient like the chat. Submit an issue when you run into problems compiling, testing, or just would like to discuss a certain topic, be it features, code style, code inconsistencies, minor changes and fixes, etc. + +### Pull Requests + +It's fine to just submit a small pull request without first making an issue or asking in the chat, but if it's a significant change that will require a lot of planning and reviewing. Also see [Creating a Pull Request](#creating-a-pr) and [Git Style Guidelines](#git-style-guidelines). + +### Discourse + +We have a discourse forum at [discourse.redox-os.org](https://discourse.redox-os.org). This is the best way to discuss more general topics that aren't about specific things that need to be addressed one way or another. You can sign up like any other website. ### Reddit -You can find Redox on Reddit in [/r/rust/](https://www.reddit.com/r/rust) and [/r/redox/](https://www.reddit.com/r/redox). The weekly update news is posted on the former. +You can also find Redox on Reddit in [/r/rust/](https://www.reddit.com/r/rust) and [/r/redox/](https://www.reddit.com/r/redox). Redox news and discussion is posted on the latter, and Rust news and discussion, as well as some Redox posts, is on the former. -## Direct Contributing +### News + +News and updates for Redox are posted at [redox-os.org/news](https://redox-os.org/news). It's more one-way than the other things on this list, but it should provide a good summary of what's been going on with the project lately. It's usually updated weekly, but with some exceptions. A mailing list may be included eventually, but it's not set up right now. + +## Code Contributions ### Low-Hanging Fruit - Easy Targets for Newbies -* If you're not fluent in Rust: +#### If you're not fluent in Rust: * Writing documentation * Using/testing Redox, filing issues for bugs and needed features * Web development ([Redox website, separate repo](https://github.com/redox-os/website)) * Writing unit tests (may require minimal knowledge of rust) -* If you are fluent in Rust, but not OS Development: +#### If you are fluent in Rust, but not OS Development: * Apps development * Shell ([Ion](https://github.com/redox-os/ion)) development - * Package manager ([Magnet](https://github.com/redox-os/magnet)) development + * Package management ([pkgutils](https://github.com/redox-os/pkgutils)) development * Other high-level code tasks -* If you are fluent in Rust, and have experience with OS Dev: +#### If you are fluent in Rust, and have experience with OS Dev: * Familiarize yourself with the repository and codebase * Grep for `TODO`, `FIXME`, `BUG`, `UNOPTIMIZED`, `REWRITEME`, `DOCME`, and `PRETTYFYME` and fix the code you find. * Improve and optimize code, especially in the kernel -### GitHub Issues - -A bit more formal way of communication with fellow Redox devs, but a little less quick and convenient like the chat (unless of course you aren't in it yet, which if you're going to be involved in this project really at all, it is recommended that you request to join). These are for more specific topics. - -### Pull Requests - -It's completely okay to just submit a small pull request without first making an issue or something, but if it's a significant change that will require a lot of planning and reviewing, it's best you start with writing an issue first. Also see [git guidelines](#git-style-guidelines) - ### Creating a Pull Request 1. Fork the repository 2. Clone the original repository to your local PC using one of the following commands based on the protocol you are using: * HTTPS:`git clone https://github.com/redox-os/redox.git --origin upstream --recursive` * SSH:`git clone git@github.com:redox-os/redox.git --origin upstream --recursive` - * Then rebase: `git rebase upstream master` - Use HTTPS if you don't know which one to use. (Recommended: learn about SSH if you don't want to have to log in every time you push/pull!) + * Then rebase: `git rebase upstream master` + If you use HTTPS, you will have to log in each time when pushing to your fork. (Recommended: learn about git SSH support, it logs in automatically using SSH keys) 3. Add your fork with * HTTPS:`git remote add origin https://github.com/your-username/redox.git` * SSH:`git remote add origin git@github.com:your-username/redox.git` 4. Alternatively, if you already have a fork and copy of the repo, you can simply check to make sure you're up-to-date - * Fetch the upstream:`git fetch upstream master` - * Rebase with local commits:`git rebase upstream/master` - * Update the submodules:`git submodule update --init` -5. Optionally create a separate branch (recommended if you're making multiple changes simultaneously) (`git checkout -b my-branch`) + * Pull the upstream:`git pull upstream --rebase` + * Update the submodules:`git submodule update --recursive --init` +5. Create a separate branch (recommended if you're making multiple changes simultaneously) (`git checkout -b my-branch`) 6. Make changes -7. Commit (`git add . --all; git commit -m "my commit"`) +7. Commit (`git add ; git commit`) and write your commit message 8. Optionally run [rustfmt](https://github.com/rust-lang-nursery/rustfmt) on the files you changed and commit again if it did anything (check with `git diff` first) -9. Test your changes with `make qemu` or `make virtualbox` (you might have to use `make qemu kvm=no`, formerly `make qemu_no_kvm`) +9. Test your changes by cleaning (`make clean; git clean -Xfd`) and building with `make qemu` (you might have to use `make qemu kvm=no`) or `make virtualbox`. (see [Best Practices and Guidelines](#best-practices)) -10. Pull from upstream (`git fetch upstream; git rebase upstream/master`) (Note: try not to use `git pull`, it is equivalent to doing `git fetch upstream; git merge master upstream/master`, which is not usually preferred for local/fork repositories, although it is fine in some cases.) +10. Pull from upstream (`git pull upstream --rebase`) (Note: Make sure to include `--rebase`, as it will apply your changes on top of the changes you just pulled, allowing for a much cleaner merge) 11. Repeat step 9 to make sure the rebase still builds and starts -12. Push to your fork (`git push origin my-branch`) +12. Push to your fork (`git push origin `), `` being the branch you created earlier 13. Create a pull request -14. Describe your changes +14. If your changes are minor, you can just describe them in a paragraph or less. If they're major, please fill out the provided form. 15. Submit! ## Best Practices and Guidelines @@ -105,36 +114,36 @@ It's completely okay to just submit a small pull request without first making an * **Remember to do a `git rebase -i upstream/master` before you send your patch!** * **Make sure your code is readable, commented, and well-documented.** -* **Don't hesitate to ask for help!** -* **Before implementing something, discuss it! Open an issue, or join the chat.** +* **Don't hesitate to ask for help, comments or suggestions!** +* **Before implementing something, discuss it! Open an issue, or ask in the chat.** ##### On the more technical side: * Test, test, and test! -* Follow the style conventions +* Follow the style conventions (See [rust style guidelines](#rust-style-guidelines)) * Use `std::mem::replace` and `std::mem::swap` when you can. * `libredox` should be 1-to-1 with the official `libstd`. -* Use `.into()` and `.to_owned()` over `.to_string()`. +* Prefer `.into()` and `.to_owned()` over `.to_string()`. * Prefer passing references to the data over owned data. (Don't take `String`, take `&str`. Don't take `Vec` take `&[T]`). * Use generics, traits, and other abstractions Rust provides. * Avoid using lossy conversions (for example: don't do `my_u32 as u16 == my_u16`, prefer `my_u32 == my_u16 as my_u32`). * Prefer in place (`box` keyword) when doing heap allocations. * Prefer platform independently sized integer over pointer sized integer (`u32` over `usize`, for example). * Follow the usual idioms of programming, such as "composition over inheritance", "let your program be divided in smaller pieces", and "resource acquisition is initialization". -* When `unsafe` is unnecessary, don't use it. 10 lines longer safe code is better than more compact unsafe code! -* Be sure to mark parts that need work with `TODO`, `FIXME`, `BUG`, `UNOPTIMIZED`, `REWRITEME`, `DOCME`, and `PRETTYFYME`. +* When `unsafe` is unnecessary, don't use it. **Longer safe code is better than shorter unsafe code!** +* Be sure to mark parts that need work with `TODO`, `FIXME`, `BUG`, `UNOPTIMIZED`, `REWRITEME`, `DOCME`, and `PRETTYFYME`. Always elaborate on these messages, too. Nothing is more annoying than seeing a `TODO` and not knowing how to actually fix it. * Use the compiler hint attributes, such as `#[inline]`, `#[cold]`, etc. when it makes sense to do so. -* Check the [chat](#chat), [the Website](http://redox-os.org), and [the Rust subreddit](https://www.reddit.com/r/rust) frequently. +* Check the [chat](#chat), [the website](http://redox-os.org/news), and [the Rust subreddit](https://www.reddit.com/r/rust) frequently. ### Kernel -* When trying to access a slice, **always** use the `common::GetSlice` trait and the `.get_slice()` method to get a slice without causing the kernel to panic. - The problem with slicing in regular Rust, e.g. `foo[a..b]`, is that if someone tries to access with a range that is out of bounds of an array/string/slice, it will cause a panic at runtime, as a safety measure. Same thing when accessing an element. +* When trying to access a slice, **always** use the `common::GetSlice` trait and the `.get_slice()` method to get a slice without causing the kernel to panic. + The problem with slicing in regular Rust, e.g. `foo[a..b]`, is that if someone tries to access with a range that is out of bounds of an array/string/slice, it will cause a panic at runtime, as a safety measure. Same thing when accessing an element. Always use `foo.get(n)` instead of `foo[n]` and try to cover for the possibility of `Option::None`. Doing the regular way may work fine for applications, but never in the kernel. No possible panics should ever exist in kernel space, because then the whole OS would just stop working. ### Testing Practices -* It's always better to test boot (`make qemu` or `make virtualbox`) every time you make a change, because it is important to see how the OS boots and works after it compiles. - Even though Rust is a safety-oriented language, something as unstable as an in-dev operating system will have problems in many cases and may completely break on even the slightest critical change. +* It's always better to test boot (`make qemu` or `make virtualbox`) every time you make a change, because it is important to see how the OS boots and works after it compiles. + Even though Rust is a safety-oriented language, something as unstable and low-level as an in-dev operating system will almost certainly have problems in many cases and may completely break on even the slightest critical change. Also, make sure you check how the unmodified version runs on your machine before making any changes. Else, you won't have anything to compare to, and it will generally just lead to confusion. TLDR: Rebuild and test boot often. * To run the ZFS tests: @@ -150,14 +159,33 @@ Since Rust is a relatively small and new language compared to others like C, the ### Git -* Commit messages should describe their changes in present tense, e.g. "`Add stuff to file.ext`" instead of "`added stuff to file.ext`". -* Try to remove useless duplicate/merge commits from PRs as these clutter up history, and may make it hard to read. -* Usually, when syncing your local copy with the master branch, you will want to rebase instead of merge. This is because it will create duplicate commits that don't actually do anything when merged into the master branch. -* When you start to make changes, you will want to create a separate branch, and keep the `master` branch of your fork identical to the main repository, so that you can compare your changes with the main branch and test out a more stable build if you need to. * You should have a fork of the repository on GitHub and a local copy on your computer. The local copy should have two remotes; `upstream` and `origin`, `upstream` should be set to the main repository and `origin` should be your fork. +* When you start to make changes, you will want to create a separate branch, and keep the `master` branch of your fork identical to the main repository, so that you can compare your changes with the main branch and test out a more stable build if you need to. +* Usually, when syncing your local copy with the master branch, you'll want to rebase instead of merge. This is because it will create duplicate commits that don't actually do anything when merged into the master branch. You can do this in one command with `git pull upstream --rebase`. This will pull from the upstream, then roll back to the current state of the upstream, and "replay" your changes on top of it. Make sure you commit before doing this, though. Git won't be able to rebase if you don't. +* Prefer to omit the `-m` when using `git commit`. This opens your editor and should help get you in the habit of writing longer commit messages. +* Commit messages should describe their changes in present tense, e.g. "`Add stuff to file.ext`" instead of "`added stuff to file.ext`". This makes sense as sometimes when you revert back, then run through commits one-by-one, you want to see what a commit will do, instead of just what the person did when they made the commit. It's also just being consistent. +* Try to remove useless duplicate/merge commits from PRs as these don't do anything except clutter up history and make it harder to read. ## Other Ways to Contribute -### Graphic Design +If you're not big on coding, but you still want to help keep the project going, you can still contribute/support in a variety of ways! We'll try to find a way to use anything you have to offer. + +### Design + +If you're a good designer, whether it's 2D graphics, 3D graphics, interfaces, web design, you can help. We need logos, UI design, UI skins, app icons, desktop backgrounds, etc. More information to come on this in the future, for now just join [the chat](#chat) and ask about graphic design. + +### Patreon + +Our BDFL, [jackpot51](https://github.com/jackpot51), has a [Patreon campaign](https://www.patreon.com/redox_os)! All money recieved will go towards Redox OS development. If you donate, you will be listed in the Redox credits as one of the people that made Redox OS possible. You'll also get other rewards the more you donate. However, please don't donate if you can't afford it. + + -If you're a good designer, you can help with logos, UI design, app icons, other graphics (e.g. stock desktop backgrounds), etc. More information to come on this, for now just join [the chat](#chat) and ask about graphic design. diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 5c3c138..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "kernel" -version = "0.1.0" - -[lib] -name = "kernel" -path = "kernel/lib.rs" -crate-type = ["staticlib"] - -[dependencies] -bitflags = "*" -spin = "*" -redox_syscall = { path = "syscall/" } - -[dependencies.goblin] -git = "https://github.com/m4b/goblin.git" -default-features = false -features = ["elf32", "elf64"] - -[dev-dependencies] -arch_test = { path = "arch/test" } - -[target.'cfg(target_arch = "arm")'.dependencies] -arch_arm = { path = "arch/arm" } - -[target.'cfg(target_arch = "x86_64")'.dependencies] -arch_x86_64 = { path = "arch/x86_64" } - -[features] -default = [] -live = [] - -[profile.dev] -panic = "unwind" - -[profile.release] -panic = "abort" diff --git a/Makefile b/Makefile index 1329ee8..1ccb277 100644 --- a/Makefile +++ b/Makefile @@ -1,31 +1,5 @@ -ARCH?=x86_64 - -ROOT=$(PWD) -export RUST_TARGET_PATH=$(ROOT)/targets - -#TODO: Use libssp -export CFLAGS=-fno-stack-protector -U_FORTIFY_SOURCE - -# Kernel variables -KTARGET=$(ARCH)-unknown-none -KBUILD=build/kernel -KRUSTC=./krustc.sh -KRUSTCFLAGS=--target $(KTARGET) -C opt-level=2 -C debuginfo=0 -C soft-float -KRUSTDOC=./krustdoc.sh -KCARGO=RUSTC="$(KRUSTC)" RUSTDOC="$(KRUSTDOC)" cargo -KCARGOFLAGS=--target $(KTARGET) --release -- -C soft-float - -# Userspace variables -TARGET=$(ARCH)-unknown-redox -BUILD=build/userspace -RUSTC=./rustc.sh -RUSTCFLAGS=--target $(TARGET).json -C opt-level=2 -C debuginfo=0 -RUSTDOC=./rustdoc.sh -CARGO=RUSTC="$(RUSTC)" RUSTDOC="$(RUSTDOC)" cargo -CARGOFLAGS=--target $(TARGET).json --release -- - -# Default targets -.PHONY: all live iso clean doc ref test update pull qemu bochs drivers schemes binutils coreutils extrautils netutils userutils wireshark FORCE +# Configuration and variables +include mk/config.mk all: build/harddrive.bin @@ -33,130 +7,15 @@ live: build/livedisk.bin iso: build/livedisk.iso -FORCE: - clean: - cargo clean - cargo clean --manifest-path rust/src/libstd/Cargo.toml - cargo clean --manifest-path drivers/ahcid/Cargo.toml - cargo clean --manifest-path drivers/e1000d/Cargo.toml - cargo clean --manifest-path drivers/ps2d/Cargo.toml - cargo clean --manifest-path drivers/pcid/Cargo.toml - cargo clean --manifest-path drivers/rtl8168d/Cargo.toml - cargo clean --manifest-path drivers/vesad/Cargo.toml - cargo clean --manifest-path programs/acid/Cargo.toml - cargo clean --manifest-path programs/contain/Cargo.toml - cargo clean --manifest-path programs/init/Cargo.toml - cargo clean --manifest-path programs/ion/Cargo.toml - cargo clean --manifest-path programs/binutils/Cargo.toml - cargo clean --manifest-path programs/coreutils/Cargo.toml - cargo clean --manifest-path programs/extrautils/Cargo.toml - cargo clean --manifest-path programs/games/Cargo.toml - cargo clean --manifest-path programs/netutils/Cargo.toml - cargo clean --manifest-path programs/orbutils/Cargo.toml - cargo clean --manifest-path programs/pkgutils/Cargo.toml - cargo clean --manifest-path programs/userutils/Cargo.toml - cargo clean --manifest-path programs/smith/Cargo.toml - cargo clean --manifest-path programs/tar/Cargo.toml - cargo clean --manifest-path schemes/ethernetd/Cargo.toml - cargo clean --manifest-path schemes/example/Cargo.toml - cargo clean --manifest-path schemes/ipd/Cargo.toml - cargo clean --manifest-path schemes/orbital/Cargo.toml - cargo clean --manifest-path schemes/ptyd/Cargo.toml - cargo clean --manifest-path schemes/randd/Cargo.toml - cargo clean --manifest-path schemes/redoxfs/Cargo.toml - cargo clean --manifest-path schemes/tcpd/Cargo.toml - cargo clean --manifest-path schemes/udpd/Cargo.toml - -$(FUMOUNT) build/filesystem/ - rm -rf initfs/bin - rm -rf filesystem/bin filesystem/sbin filesystem/ui/bin + cd cookbook && ./clean.sh + cargo clean --manifest-path cookbook/pkgutils/Cargo.toml + cargo clean --manifest-path installer/Cargo.toml + cargo clean --manifest-path kernel/Cargo.toml + cargo clean --manifest-path redoxfs/Cargo.toml + -$(FUMOUNT) build/filesystem/ || true rm -rf build -doc: \ - doc-kernel \ - doc-std - -#FORCE to let cargo decide if docs need updating -doc-kernel: $(KBUILD)/libkernel.a FORCE - $(KCARGO) doc --target $(KTARGET).json - -doc-std: $(BUILD)/libstd.rlib FORCE - $(CARGO) doc --target $(TARGET).json --manifest-path rust/src/libstd/Cargo.toml - -ref: FORCE - rm -rf filesystem/ref/ - mkdir -p filesystem/ref/ - cargo run --manifest-path crates/docgen/Cargo.toml -- programs/binutils/src/bin/ filesystem/ref/ - cargo run --manifest-path crates/docgen/Cargo.toml -- programs/coreutils/src/bin/ filesystem/ref/ - cargo run --manifest-path crates/docgen/Cargo.toml -- programs/extrautils/src/bin/ filesystem/ref/ - cargo run --manifest-path crates/docgen/Cargo.toml -- programs/netutils/src/ filesystem/ref/ - -test: - cargo test - cargo test --manifest-path rust/src/libstd/Cargo.toml - cargo test --manifest-path drivers/ahcid/Cargo.toml - cargo test --manifest-path drivers/e1000d/Cargo.toml - cargo test --manifest-path drivers/ps2d/Cargo.toml - cargo test --manifest-path drivers/pcid/Cargo.toml - cargo test --manifest-path drivers/rtl8168d/Cargo.toml - cargo test --manifest-path drivers/vesad/Cargo.toml - cargo test --manifest-path programs/acid/Cargo.toml - cargo test --manifest-path programs/contain/Cargo.toml - cargo test --manifest-path programs/init/Cargo.toml - cargo test --manifest-path programs/ion/Cargo.toml - cargo test --manifest-path programs/binutils/Cargo.toml - cargo test --manifest-path programs/coreutils/Cargo.toml - cargo test --manifest-path programs/extrautils/Cargo.toml - cargo test --manifest-path programs/games/Cargo.toml - cargo test --manifest-path programs/netutils/Cargo.toml - cargo test --manifest-path programs/orbutils/Cargo.toml - cargo test --manifest-path programs/pkgutils/Cargo.toml - cargo test --manifest-path programs/userutils/Cargo.toml - cargo test --manifest-path programs/smith/Cargo.toml - cargo test --manifest-path programs/tar/Cargo.toml - cargo test --manifest-path schemes/ethernetd/Cargo.toml - cargo test --manifest-path schemes/example/Cargo.toml - cargo test --manifest-path schemes/ipd/Cargo.toml - cargo test --manifest-path schemes/orbital/Cargo.toml - cargo test --manifest-path schemes/ptyd/Cargo.toml - cargo test --manifest-path schemes/randd/Cargo.toml - cargo test --manifest-path schemes/redoxfs/Cargo.toml - cargo test --manifest-path schemes/tcpd/Cargo.toml - cargo test --manifest-path schemes/udpd/Cargo.toml - -update: - cargo update - cargo update --manifest-path rust/src/libstd/Cargo.toml - cargo update --manifest-path drivers/ahcid/Cargo.toml - cargo update --manifest-path drivers/e1000d/Cargo.toml - cargo update --manifest-path drivers/ps2d/Cargo.toml - cargo update --manifest-path drivers/pcid/Cargo.toml - cargo update --manifest-path drivers/rtl8168d/Cargo.toml - cargo update --manifest-path drivers/vesad/Cargo.toml - cargo update --manifest-path programs/acid/Cargo.toml - cargo update --manifest-path programs/contain/Cargo.toml - cargo update --manifest-path programs/init/Cargo.toml - cargo update --manifest-path programs/ion/Cargo.toml - cargo update --manifest-path programs/binutils/Cargo.toml - cargo update --manifest-path programs/coreutils/Cargo.toml - cargo update --manifest-path programs/extrautils/Cargo.toml - cargo update --manifest-path programs/games/Cargo.toml - cargo update --manifest-path programs/netutils/Cargo.toml - cargo update --manifest-path programs/orbutils/Cargo.toml - cargo update --manifest-path programs/pkgutils/Cargo.toml - cargo update --manifest-path programs/userutils/Cargo.toml - cargo update --manifest-path programs/smith/Cargo.toml - cargo update --manifest-path programs/tar/Cargo.toml - cargo update --manifest-path schemes/ethernetd/Cargo.toml - cargo update --manifest-path schemes/example/Cargo.toml - cargo update --manifest-path schemes/ipd/Cargo.toml - cargo update --manifest-path schemes/orbital/Cargo.toml - cargo update --manifest-path schemes/ptyd/Cargo.toml - cargo update --manifest-path schemes/randd/Cargo.toml - cargo update --manifest-path schemes/redoxfs/Cargo.toml - cargo update --manifest-path schemes/tcpd/Cargo.toml - cargo update --manifest-path schemes/udpd/Cargo.toml - pull: git pull --rebase --recurse-submodules git submodule sync @@ -165,472 +24,49 @@ pull: make clean make update -# Emulation -QEMU=SDL_VIDEO_X11_DGAMOUSE=0 qemu-system-$(ARCH) -QEMUFLAGS=-serial mon:stdio -d cpu_reset -d guest_errors -ifeq ($(ARCH),arm) - QEMUFLAGS+=-cpu arm1176 -machine integratorcp - QEMUFLAGS+=-nographic +update: + cd cookbook; \ + ./update.sh "$$(cargo run --manifest-path ../installer/Cargo.toml -- --list-packages ../initfs.toml ../filesystem.toml)" + cargo update --manifest-path cookbook/pkgutils/Cargo.toml + cargo update --manifest-path installer/Cargo.toml + cargo update --manifest-path kernel/Cargo.toml + cargo update --manifest-path redoxfs/Cargo.toml - export CC=$(ARCH)-none-eabi-gcc - export CXX=$(ARCH)-none-eabi-g++ - export LD=$(ARCH)-none-eabi-ld +fetch: + cd cookbook; \ + ./fetch.sh "$$(cargo run --manifest-path ../installer/Cargo.toml -- --list-packages ../initfs.toml ../filesystem.toml)" - KRUSTCFLAGS+=-C linker=$(CC) - KCARGOFLAGS+=-C linker=$(CC) - RUSTCFLAGS+=-C linker=$(CC) - CARGOFLAGS+=-C linker=$(CC) +# Emulation recipes +include mk/qemu.mk +include mk/bochs.mk +include mk/virtualbox.mk -%.list: % - $(ARCH)-none-eabi-objdump -C -D $< > $@ +# Kernel recipes +include mk/kernel.mk -build/harddrive.bin: $(KBUILD)/kernel - cp $< $@ +# Filesystem recipes +include mk/initfs.mk +include mk/filesystem.mk -qemu: build/harddrive.bin - $(QEMU) $(QEMUFLAGS) -kernel $< -else - QEMUFLAGS+=-smp 4 -m 1024 - ifeq ($(iommu),yes) - QEMUFLAGS+=-machine q35,iommu=on - else - QEMUFLAGS+=-machine q35 - endif - ifeq ($(net),no) - QEMUFLAGS+=-net none - else - QEMUFLAGS+=-net nic,model=e1000 -net user -net dump,file=build/network.pcap - ifeq ($(net),redir) - QEMUFLAGS+=-redir tcp:8080::8080 - endif - endif - ifeq ($(vga),no) - QEMUFLAGS+=-nographic -vga none - endif - #,int,pcall - #-device intel-iommu +# Disk images +include mk/disk.mk - UNAME := $(shell uname) - ifeq ($(UNAME),Darwin) - export CC=$(ARCH)-elf-gcc - export CXX=$(ARCH)-elf-g++ - ECHO=/bin/echo - FUMOUNT=sudo umount - export LD=$(ARCH)-elf-ld - export LDFLAGS=--gc-sections - VB_AUDIO=coreaudio - VBM="/Applications/VirtualBox.app/Contents/MacOS/VBoxManage" - else - export CC=gcc - export CXX=g++ - ECHO=echo - FUMOUNT=fusermount -u - export LD=ld - export LDFLAGS=--gc-sections - ifneq ($(kvm),no) - QEMUFLAGS+=-enable-kvm -cpu host - endif - VB_AUDIO="pulse" - VBM=VBoxManage - endif +# Travis target +travis: FORCE + INSTALLER_FLAGS= make build/harddrive.bin.gz build/livedisk.iso + rm -rf build/travis + mkdir build/travis + mv build/harddrive.bin.gz build/travis/redox_$(TRAVIS_TAG).bin.gz + mv build/livedisk.iso build/travis/redox_$(TRAVIS_TAG).iso + cd build/travis && sha256sum -b redox_$(TRAVIS_TAG).bin.gz redox_$(TRAVIS_TAG).iso > SHA256SUM - KRUSTCFLAGS+=-C linker=$(CC) - KCARGOFLAGS+=-C linker=$(CC) - RUSTCFLAGS+=-C linker=$(CC) - CARGOFLAGS+=-C linker=$(CC) +# An empty target +FORCE: +# A method of creating a listing for any binary %.list: % objdump -C -M intel -D $< > $@ -build/harddrive.bin: $(KBUILD)/kernel bootloader/$(ARCH)/** build/filesystem.bin - nasm -f bin -o $@ -D ARCH_$(ARCH) -ibootloader/$(ARCH)/ bootloader/$(ARCH)/harddrive.asm - -build/livedisk.bin: $(KBUILD)/kernel_live bootloader/$(ARCH)/** - nasm -f bin -o $@ -D ARCH_$(ARCH) -ibootloader/$(ARCH)/ bootloader/$(ARCH)/livedisk.asm - -build/%.bin.gz: build/%.bin - gzip -k -f $< - -build/livedisk.iso: build/livedisk.bin.gz - rm -rf build/iso/ - mkdir -p build/iso/ - cp -RL isolinux build/iso/ - cp $< build/iso/livedisk.gz - genisoimage -o $@ -b isolinux/isolinux.bin -c isolinux/boot.cat \ - -no-emul-boot -boot-load-size 4 -boot-info-table \ - build/iso/ - isohybrid $@ - -qemu: build/harddrive.bin - $(QEMU) $(QEMUFLAGS) -drive file=$<,format=raw - -qemu_extra: build/harddrive.bin - if [ ! -e build/extra.bin ]; then dd if=/dev/zero of=build/extra.bin bs=1M count=1024; fi - $(QEMU) $(QEMUFLAGS) -drive file=$<,format=raw -drive file=build/extra.bin,format=raw - -qemu_no_build: - $(QEMU) $(QEMUFLAGS) -drive file=build/harddrive.bin,format=raw - -qemu_live: build/livedisk.bin - $(QEMU) $(QEMUFLAGS) -device usb-ehci,id=flash_bus -drive id=flash_drive,file=$<,format=raw,if=none -device usb-storage,drive=flash_drive,bus=flash_bus.0 - -qemu_live_no_build: - $(QEMU) $(QEMUFLAGS) -device usb-ehci,id=flash_bus -drive id=flash_drive,file=build/livedisk.bin,format=raw,if=none -device usb-storage,drive=flash_drive,bus=flash_bus.0 - -qemu_iso: build/livedisk.iso - $(QEMU) $(QEMUFLAGS) -boot d -cdrom $< - -qemu_iso_no_build: - $(QEMU) $(QEMUFLAGS) -boot d -cdrom build/livedisk.iso - -endif - -bochs: build/harddrive.bin - bochs -f bochs.$(ARCH) - -virtualbox: build/harddrive.bin - echo "Delete VM" - -$(VBM) unregistervm Redox --delete; \ - if [ $$? -ne 0 ]; \ - then \ - if [ -d "$$HOME/VirtualBox VMs/Redox" ]; \ - then \ - echo "Redox directory exists, deleting..."; \ - $(RM) -rf "$$HOME/VirtualBox VMs/Redox"; \ - fi \ - fi - echo "Delete Disk" - -$(RM) harddrive.vdi - echo "Create VM" - $(VBM) createvm --name Redox --register - echo "Set Configuration" - $(VBM) modifyvm Redox --memory 1024 - $(VBM) modifyvm Redox --vram 16 - if [ "$(net)" != "no" ]; \ - then \ - $(VBM) modifyvm Redox --nic1 nat; \ - $(VBM) modifyvm Redox --nictype1 82540EM; \ - $(VBM) modifyvm Redox --cableconnected1 on; \ - $(VBM) modifyvm Redox --nictrace1 on; \ - $(VBM) modifyvm Redox --nictracefile1 build/network.pcap; \ - fi - $(VBM) modifyvm Redox --uart1 0x3F8 4 - $(VBM) modifyvm Redox --uartmode1 file build/serial.log - $(VBM) modifyvm Redox --usb off # on - $(VBM) modifyvm Redox --keyboard ps2 - $(VBM) modifyvm Redox --mouse ps2 - $(VBM) modifyvm Redox --audio $(VB_AUDIO) - $(VBM) modifyvm Redox --audiocontroller ac97 - $(VBM) modifyvm Redox --nestedpaging off - echo "Create Disk" - $(VBM) convertfromraw $< build/harddrive.vdi - echo "Attach Disk" - $(VBM) storagectl Redox --name ATA --add sata --controller IntelAHCI --bootable on --portcount 1 - $(VBM) storageattach Redox --storagectl ATA --port 0 --device 0 --type hdd --medium build/harddrive.vdi - echo "Run VM" - $(VBM) startvm Redox - -# Kernel recipes -$(KBUILD)/libcore.rlib: rust/src/libcore/lib.rs - mkdir -p $(KBUILD) - $(KRUSTC) $(KRUSTCFLAGS) -o $@ $< - -$(KBUILD)/librand.rlib: rust/src/librand/lib.rs $(KBUILD)/libcore.rlib - $(KRUSTC) $(KRUSTCFLAGS) -o $@ $< - -$(KBUILD)/liballoc.rlib: rust/src/liballoc/lib.rs $(KBUILD)/libcore.rlib - $(KRUSTC) $(KRUSTCFLAGS) -o $@ $< - -$(KBUILD)/libstd_unicode.rlib: rust/src/libstd_unicode/lib.rs $(KBUILD)/libcore.rlib - $(KRUSTC) $(KRUSTCFLAGS) -o $@ $< - -$(KBUILD)/libcollections.rlib: rust/src/libcollections/lib.rs $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/libstd_unicode.rlib - $(KRUSTC) $(KRUSTCFLAGS) -o $@ $< - -$(KBUILD)/libkernel.a: kernel/** $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/libcollections.rlib $(BUILD)/initfs.rs - $(KCARGO) rustc $(KCARGOFLAGS) -C lto -o $@ - -$(KBUILD)/libkernel_live.a: kernel/** $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/libcollections.rlib $(BUILD)/initfs.rs build/filesystem.bin - $(KCARGO) rustc --lib $(KCARGOFLAGS) --cfg 'feature="live"' -C lto --emit obj=$@ - -$(KBUILD)/kernel: $(KBUILD)/libkernel.a - $(LD) $(LDFLAGS) -z max-page-size=0x1000 -T arch/$(ARCH)/src/linker.ld -o $@ $< - -$(KBUILD)/kernel_live: $(KBUILD)/libkernel_live.a - $(LD) $(LDFLAGS) -z max-page-size=0x1000 -T arch/$(ARCH)/src/linker.ld -o $@ $< - -# Userspace recipes -$(BUILD)/libstd.rlib: rust/src/libstd/Cargo.toml rust/src/libstd/** - mkdir -p $(BUILD) - $(CARGO) rustc --verbose --manifest-path $< $(CARGOFLAGS) -L native=libc-artifacts/lib -o $@ - cp rust/src/target/$(TARGET)/release/deps/*.rlib $(BUILD) - -initfs/bin/%: drivers/%/Cargo.toml drivers/%/src/** $(BUILD)/libstd.rlib - mkdir -p initfs/bin - $(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ - strip $@ - -initfs/bin/%: programs/%/Cargo.toml programs/%/src/** $(BUILD)/libstd.rlib - mkdir -p initfs/bin - $(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ - #strip $@ - -initfs/bin/%: schemes/%/Cargo.toml schemes/%/src/** $(BUILD)/libstd.rlib - mkdir -p initfs/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -$(BUILD)/initfs.rs: \ - initfs/bin/init \ - initfs/bin/ahcid \ - initfs/bin/bgad \ - initfs/bin/pcid \ - initfs/bin/ps2d \ - initfs/bin/redoxfs \ - initfs/bin/vesad \ - initfs/etc/** - echo 'use collections::BTreeMap;' > $@ - echo 'pub fn gen() -> BTreeMap<&'"'"'static [u8], (&'"'"'static [u8], bool)> {' >> $@ - echo ' let mut files: BTreeMap<&'"'"'static [u8], (&'"'"'static [u8], bool)> = BTreeMap::new();' >> $@ - for folder in `find initfs -type d | sort`; do \ - name=$$(echo $$folder | sed 's/initfs//' | cut -d '/' -f2-) ; \ - $(ECHO) -n ' files.insert(b"'$$name'", (b"' >> $@ ; \ - ls -1 $$folder | sort | awk 'NR > 1 {printf("\\n")} {printf("%s", $$0)}' >> $@ ; \ - echo '", true));' >> $@ ; \ - done - find initfs -type f -o -type l | cut -d '/' -f2- | sort | awk '{printf(" files.insert(b\"%s\", (include_bytes!(\"../../initfs/%s\"), false));\n", $$0, $$0)}' >> $@ - echo ' files' >> $@ - echo '}' >> $@ - -filesystem/sbin/%: drivers/%/Cargo.toml drivers/%/src/** $(BUILD)/libstd.rlib - mkdir -p filesystem/sbin - $(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/bin/%: programs/%/Cargo.toml programs/%/src/** $(BUILD)/libstd.rlib - mkdir -p filesystem/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/bin/sh: filesystem/bin/ion - cp $< $@ - -filesystem/bin/%: programs/binutils/Cargo.toml programs/binutils/src/bin/%.rs $(BUILD)/libstd.rlib - mkdir -p filesystem/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/bin/%: programs/coreutils/Cargo.toml programs/coreutils/src/bin/%.rs $(BUILD)/libstd.rlib - mkdir -p filesystem/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/bin/%: programs/extrautils/Cargo.toml programs/extrautils/src/bin/%.rs $(BUILD)/libstd.rlib - mkdir -p filesystem/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/bin/%: programs/games/Cargo.toml programs/games/src/%/**.rs $(BUILD)/libstd.rlib - mkdir -p filesystem/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/bin/%: programs/netutils/Cargo.toml programs/netutils/src/%/**.rs $(BUILD)/libstd.rlib - mkdir -p filesystem/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/ui/bin/%: programs/orbutils/Cargo.toml programs/orbutils/src/%/**.rs $(BUILD)/libstd.rlib - mkdir -p filesystem/ui/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/bin/%: programs/pkgutils/Cargo.toml programs/pkgutils/src/%/**.rs $(BUILD)/libstd.rlib - mkdir -p filesystem/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/bin/%: programs/userutils/Cargo.toml programs/userutils/src/bin/%.rs $(BUILD)/libstd.rlib - mkdir -p filesystem/bin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/sbin/%: schemes/%/Cargo.toml schemes/%/src/** $(BUILD)/libstd.rlib - mkdir -p filesystem/sbin - $(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ - strip $@ - -filesystem/sbin/redoxfs-mkfs: schemes/redoxfs/Cargo.toml schemes/redoxfs/src/** $(BUILD)/libstd.rlib - mkdir -p filesystem/bin - $(CARGO) rustc --manifest-path $< --bin redoxfs-mkfs $(CARGOFLAGS) -o $@ - strip $@ - -drivers: \ - filesystem/sbin/pcid \ - filesystem/sbin/e1000d \ - filesystem/sbin/rtl8168d - -binutils: \ - filesystem/bin/hex \ - filesystem/bin/hexdump \ - filesystem/bin/strings - -coreutils: \ - filesystem/bin/basename \ - filesystem/bin/cat \ - filesystem/bin/chmod \ - filesystem/bin/clear \ - filesystem/bin/cp \ - filesystem/bin/cut \ - filesystem/bin/date \ - filesystem/bin/dd \ - filesystem/bin/df \ - filesystem/bin/du \ - filesystem/bin/echo \ - filesystem/bin/env \ - filesystem/bin/false \ - filesystem/bin/free \ - filesystem/bin/head \ - filesystem/bin/kill \ - filesystem/bin/ls \ - filesystem/bin/mkdir \ - filesystem/bin/mv \ - filesystem/bin/printenv \ - filesystem/bin/ps \ - filesystem/bin/pwd \ - filesystem/bin/realpath \ - filesystem/bin/reset \ - filesystem/bin/rmdir \ - filesystem/bin/rm \ - filesystem/bin/seq \ - filesystem/bin/sleep \ - filesystem/bin/sort \ - filesystem/bin/tail \ - filesystem/bin/tee \ - filesystem/bin/time \ - filesystem/bin/touch \ - filesystem/bin/true \ - filesystem/bin/wc \ - filesystem/bin/yes - #filesystem/bin/shutdown filesystem/bin/test - -extrautils: \ - filesystem/bin/calc \ - filesystem/bin/cksum \ - filesystem/bin/cur \ - filesystem/bin/grep \ - filesystem/bin/less \ - filesystem/bin/man \ - filesystem/bin/mdless \ - filesystem/bin/mtxt \ - filesystem/bin/rem \ - #filesystem/bin/dmesg filesystem/bin/info filesystem/bin/watch - -games: \ - filesystem/bin/ice \ - filesystem/bin/minesweeper \ - filesystem/bin/reblox \ - filesystem/bin/rusthello \ - filesystem/bin/snake - -netutils: \ - filesystem/bin/dhcpd \ - filesystem/bin/dns \ - filesystem/bin/httpd \ - filesystem/bin/irc \ - filesystem/bin/nc \ - filesystem/bin/ntp \ - filesystem/bin/wget - -orbutils: \ - filesystem/ui/bin/browser \ - filesystem/ui/bin/calculator \ - filesystem/ui/bin/character_map \ - filesystem/ui/bin/editor \ - filesystem/ui/bin/file_manager \ - filesystem/ui/bin/launcher \ - filesystem/ui/bin/orblogin \ - filesystem/ui/bin/terminal \ - filesystem/ui/bin/viewer - -pkgutils: \ - filesystem/bin/pkg - -userutils: \ - filesystem/bin/getty \ - filesystem/bin/id \ - filesystem/bin/login \ - filesystem/bin/passwd \ - filesystem/bin/su \ - filesystem/bin/sudo - -schemes: \ - filesystem/sbin/ethernetd \ - filesystem/sbin/ipd \ - filesystem/sbin/orbital \ - filesystem/sbin/ptyd \ - filesystem/sbin/randd \ - filesystem/sbin/redoxfs \ - filesystem/sbin/redoxfs-mkfs \ - filesystem/sbin/tcpd \ - filesystem/sbin/udpd - -build/filesystem.bin: \ - drivers \ - coreutils \ - extrautils \ - games \ - netutils \ - orbutils \ - pkgutils \ - userutils \ - schemes \ - filesystem/bin/acid \ - filesystem/bin/contain \ - filesystem/bin/ion \ - filesystem/bin/sh \ - filesystem/bin/smith \ - filesystem/bin/tar - -$(FUMOUNT) build/filesystem/ - rm -rf $@ build/filesystem/ - dd if=/dev/zero of=$@ bs=1M count=128 - cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs-mkfs $@ - mkdir -p build/filesystem/ - cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs - schemes/redoxfs/target/release/redoxfs $@ build/filesystem/ - sleep 2 - pgrep redoxfs - cp -RL filesystem/* build/filesystem/ - chown -R 0:0 build/filesystem - chown -R 1000:1000 build/filesystem/home/user - chmod -R uog+rX build/filesystem - chmod -R u+w build/filesystem - chmod -R og-w build/filesystem - chmod -R 755 build/filesystem/bin - chmod -R u+rwX build/filesystem/root - chmod -R og-rwx build/filesystem/root - chmod -R u+rwX build/filesystem/home/user - chmod -R og-rwx build/filesystem/home/user - chmod +s build/filesystem/bin/passwd - chmod +s build/filesystem/bin/su - chmod +s build/filesystem/bin/sudo - mkdir build/filesystem/tmp - chmod 1777 build/filesystem/tmp - sync - -$(FUMOUNT) build/filesystem/ - rm -rf build/filesystem/ - -mount: FORCE - mkdir -p build/filesystem/ - cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs - schemes/redoxfs/target/release/redoxfs build/harddrive.bin build/filesystem/ - sleep 2 - pgrep redoxfs - -unmount: FORCE - sync - -$(FUMOUNT) build/filesystem/ - rm -rf build/filesystem/ - +# Wireshark wireshark: FORCE wireshark build/network.pcap diff --git a/README.md b/README.md index 82c53ca..8c0b53f 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,40 @@

-Redox +Redox

**Redox** is an operating system written in Rust, a language with focus on safety and high performance. Redox, following the microkernel design, aims to be secure, usable, and free. Redox is inspired by previous kernels and operating systems, such as SeL4, Minix, Plan 9, and BSD. -Redox _is not_ just a kernel, it's a full-featured Operating System, providing packages (memory allocator, file system, display manager, core utilities, etc.) that together makes up a functional and convenient operating system. You can loosly think of it as the GNU or BSD ecosystem, but in a memory safe language and with modern technology. See [this list](#ecosystem) for overview of the ecosystem. +Redox _is not_ just a kernel, it's a **full-featured Operating System**, providing packages (memory allocator, file system, display manager, core utilities, etc.) that together make up a functional and convenient operating system. You can loosely think of it as the GNU or BSD ecosystem, but in a memory safe language and with modern technology. See [this list](#ecosystem) for overview of the ecosystem. The website can be found at https://www.redox-os.org. Please make sure you use the **latest nightly** of `rustc` before building (for more troubleshooting, see ["Help! Redox won't compile!"](#compile-help)). [![Travis Build Status](https://travis-ci.org/redox-os/redox.svg?branch=master)](https://travis-ci.org/redox-os/redox) +[![Downloads](https://img.shields.io/github/downloads/redox-os/redox/total.svg)](https://github.com/redox-os/redox/releases) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.md) -![Rust Version](https://img.shields.io/badge/rust-1.15.0--nightly%20(71c06a56a%202016--12--18)-lightgrey.svg) +![Rust Version](https://img.shields.io/badge/rust-nightly%202017--07--26-lightgrey.svg) ## Contents -* [What it looks like](#what-it-looks-like) +* [What it looks like](#screenshots) * [Ecosystem](#ecosystem) * [Help! Redox won't compile](#compile-help) * [Contributing to Redox](#contributing) * [Cloning, Building and running](#cloning-building-running) * [Quick Setup](#quick-setup) * [Manual Setup](#manual-setup) + * [Setup Using Docker](#setup-using-docker) -## What it looks like +## What it looks like Redox -Redox -Redox +Redox +Redox Redox Redox -Redox +Redox ## Ecosystem @@ -40,48 +42,49 @@ The ecosystem and software Redox OS provides is listed below. | Name (lexicographic order) | Maintainer |-----------------------------------------------------------------------------|--------------------------- -| [Ion (shell)](https://github.com/redox-os/ion) | [**@skylerberg**](https://github.com/skylerberg) & [**@jackpot51**](https://github.com/jackpot51) -| [RANSID](https://github.com/redox-os/ransid) | [**@jackpot51**](https://github.com/jackpot51) -| [Sodium (editor)](https://github.com/redox-os/sodium) | [**@ticki**](https://github.com/ticki) -| [Standard library](https://github.com/redox-os/libstd) | [**@jackpot51**](https://github.com/jackpot51) -| [TFS (filesystem)](https://github.com/ticki/tfs) | [**@ticki**](https://github.com/ticki) -| [The Redox book](https://github.com/redox-os/book) | [**@ticki**](https://github.com/ticki) -| [The old kernel](https://github.com/redox-os/old) | abandoned -| [ZFS](https://github.com/redox-os/zfs) | abandoned, superseded by TFS -| [acid tests](https://github.com/redox-os/acid) | [**@jackpot51**](https://github.com/jackpot51) (co.: [**@ticki**](https://github.com/ticki), [**@nilset](https://github.com/nilset)) +| [acid (kernel integration tests)](https://github.com/redox-os/acid) | [**@jackpot51**](https://github.com/jackpot51) (co.: [**@ticki**](https://github.com/ticki), [**@nilset](https://github.com/nilset)) | [binutils](https://github.com/redox-os/binutils) | [**@ticki**](https://github.com/ticki) -| [bots (other internal bots)](https://github.com/redox-os/bots) | [**@ticki**](https://github.com/ticki) +| [bots (custom Mattermost bots)](https://github.com/redox-os/bots) | [**@ticki**](https://github.com/ticki) | [cookbook](https://github.com/redox-os/cookbook) | [**@jackpot51**](https://github.com/jackpot51) | [coreutils](https://github.com/redox-os/coreutils) | [**@ticki**](https://github.com/ticki) (co.: [**@stratact**](https://github.com/stratact)) | [extrautils](https://github.com/redox-os/extrautils) | [**@ticki**](https://github.com/ticki) | [games](https://github.com/redox-os/games) | [**@ticki**](https://github.com/ticki) +| [Ion (shell)](https://github.com/redox-os/ion) | [**@skylerberg**](https://github.com/skylerberg) & [**@jackpot51**](https://github.com/jackpot51) | [kernel](https://github.com/redox-os/kernel) | [**@jackpot51**](https://github.com/jackpot51) | [libextra](https://github.com/redox-os/libextra) | [**@ticki**](https://github.com/ticki) | [libpager](https://github.com/redox-os/libpager) | [**@ticki**](https://github.com/ticki) -| [magnet (future package manager)](https://github.com/redox-os/magnet) | [**@ticki**](https://github.com/ticki) +| [libstd (Redox standard library)](https://github.com/redox-os/libstd) | [**@jackpot51**](https://github.com/jackpot51) | [netutils](https://github.com/redox-os/netutils) | [**@jackpot51**](https://github.com/jackpot51) -| [orbclient](https://github.com/redox-os/orbclient) | [**@jackpot51**](https://github.com/jackpot51) +| [orbclient (Orbital client)](https://github.com/redox-os/orbclient) | [**@jackpot51**](https://github.com/jackpot51) | [orbdata](https://github.com/redox-os/orbdata) | [**@jackpot51**](https://github.com/jackpot51) -| [orbital](https://github.com/redox-os/orbital) | [**@jackpot51**](https://github.com/jackpot51) -| [orbtk](https://github.com/redox-os/orbtk) | [**@stratact**](https://github.com/stratact) -| [orbutils](https://github.com/redox-os/orbutils) | [**@jackpot51**](https://github.com/jackpot51) +| [Orbital (windowing and compositing system)](https://github.com/redox-os/orbital) | [**@jackpot51**](https://github.com/jackpot51) +| [orbtk (Orbital toolkit)](https://github.com/redox-os/orbtk) | [**@stratact**](https://github.com/stratact) +| [orbutils (Orbital utilities)](https://github.com/redox-os/orbutils) | [**@jackpot51**](https://github.com/jackpot51) | [pkgutils (current package manager)](https://github.com/redox-os/pkgutils) | [**@jackpot51**](https://github.com/jackpot51) | [playbot (internal REPL bot)](https://github.com/redox-os/playbot) | [**@ticki**](https://github.com/ticki) | [ralloc](https://github.com/redox-os/ralloc) | [**@ticki**](https://github.com/ticki) +| [RANSID (Rust ANSI driver)](https://github.com/redox-os/ransid) | [**@jackpot51**](https://github.com/jackpot51) | [redoxfs (old filesystem)](https://github.com/redox-os/redoxfs) | [**@jackpot51**](https://github.com/jackpot51) | [syscall](https://github.com/redox-os/syscall) | [**@jackpot51**](https://github.com/jackpot51) +| [Sodium (Vim-inspired text editor)](https://github.com/redox-os/sodium) | [**@ticki**](https://github.com/ticki) | [userutils](https://github.com/redox-os/userutils) | [**@jackpot51**](https://github.com/jackpot51) +| [TFS (ticki filesystem)](https://github.com/ticki/tfs) | [**@ticki**](https://github.com/ticki) +| [The Redox book](https://github.com/redox-os/book) | [**@ticki**](https://github.com/ticki) +| [The old kernel](https://github.com/redox-os/old) | **abandoned** +| [ZFS](https://github.com/redox-os/zfs) | **abandoned, superseded by [TFS](https://github.com/ticki/tfs)** ## Help! Redox won't compile! Sometimes things go wrong when compiling. Try the following before opening an issue: -1. Run `make clean`. -2. Run `git clean -X -f -d`. -3. Make sure you have **the latest version of Rust nightly!** ([rustup.rs](https://www.rustup.rs) is recommended for managing Rust versions). -4. Update **GNU Make**, **NASM** and **QEMU/VirtualBox**. -5. Pull the upstream master branch (`git remote add upstream git@github.com:redox-os/redox.git; git pull upstream master`). -6. Update submodules (`git submodule update --recursive --init`). +1. Make sure you have a redox toolchain (`x86_64-unknown-redox-gcc`). + * You can install from .deb packages(`https://static.redox-os.org/toolchain/apt/`) or build [redox-os/libc](https://github.com/redox-os/libc) manually. +1. Run `rustup update` +1. Run `make clean pull`. +1. Make sure you have **the latest version of Rust nightly!** ([rustup.rs](https://www.rustup.rs) is recommended for managing Rust versions. If you already have it, run `rustup`). +1. Update **GNU Make**, **NASM** and **QEMU/VirtualBox**. +1. Pull the upstream master branch (`git remote add upstream git@github.com:redox-os/redox.git; git pull upstream master`). +1. Update submodules (`git submodule update --recursive --init`). and then rebuild! @@ -89,9 +92,9 @@ and then rebuild! If you're interested in this project, and you'd like to help us out, [here](CONTRIBUTING.md) is a list of ways you can do just that. -## Cloning, Building, and Running +## Cloning, Building and Running -Redox is big (even compressed)! So cloning Redox takes a lot of bandwidth, and (depending on your data plan) can be costly, so clone at your own risk! +Redox is big, even compressed. Downloading the full history may take a lot of bandwidth, and can even be costly on some data plans. Clone at your own risk! ### Quick Setup @@ -101,6 +104,9 @@ $ cd path/to/your/projects/folder/ # Run bootstrap setup $ curl -sf https://raw.githubusercontent.com/redox-os/redox/master/bootstrap.sh -o bootstrap.sh && bash -e bootstrap.sh +#Change to project directory +$ cd redox + # Build Redox $ make all @@ -112,11 +118,11 @@ $ make qemu kvm=no #### QEMU with KVM -To use QEMU with KVM (kernel-based virtual Machine), which is faster than without KVM, you need a CPU with Intel® Virtualization Technology (Intel® VT) or AMD Virtualization™ (AMD-V™) support. Most systems have this disabled in the BIOS by default, so you may need to reboot and enable the feature in the BIOS. +To use QEMU with KVM (kernel-based virtual Machine), which is faster than without KVM, you need a CPU with Intel® Virtualization Technology (Intel® VT) or AMD Virtualization™ (AMD-V™) support. Most systems have this disabled by default, so you may need to reboot, go into the BIOS, and enable it. ### Manual Setup -To manually clone, build and run Redox using a Linux host, run the following commands (with exceptions, be sure to read the comments): +To manually clone, build and run Redox using a Unix-based host, run the following commands (with exceptions, be sure to read the comments): ```bash $ cd path/to/your/projects/folder/ @@ -128,7 +134,7 @@ $ git clone git@github.com:redox-os/redox.git --origin upstream --recursive $ cd redox/ # Install/update dependencies -$ bash bootstrap.sh -d +$ ./bootstrap.sh -d # Install rustup.rs $ curl https://sh.rustup.rs -sSf | sh @@ -146,6 +152,22 @@ $ make all # Launch using QEMU $ make qemu + # Launch using QEMU without using KVM (Kernel Virtual Machine). Try if QEMU gives an error. $ make qemu kvm=no + +# Launch using QEMU without using KVM (Kernel Virtual Machine) nor Graphics +make qemu kvm=no vga=no ``` + +### Setup using Docker +We also provide docker image. After cloning this repository, please follow README under the `docker` directory. + +### Updating the codebase using the Makefile +To update the codebase run: + +``` +make pull; make fetch +``` + +`make pull` pulls and updates the submodules, and `make fetch` updates the sources for cookbook recipes. diff --git a/arch/arm/Cargo.toml b/arch/arm/Cargo.toml deleted file mode 100644 index deadc75..0000000 --- a/arch/arm/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "arch_arm" -version = "0.1.0" - -[dependencies] -bitflags = "*" -hole_list_allocator = { path = "../../crates/hole_list_allocator"} -spin = "*" diff --git a/arch/arm/src/context.rs b/arch/arm/src/context.rs deleted file mode 100644 index db711c3..0000000 --- a/arch/arm/src/context.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[derive(Debug)] -pub struct Context; - -impl Context { - pub fn new() -> Self { - Context - } -} - diff --git a/arch/arm/src/externs.rs b/arch/arm/src/externs.rs deleted file mode 100644 index 3b87427..0000000 --- a/arch/arm/src/externs.rs +++ /dev/null @@ -1,70 +0,0 @@ -/// Memcpy -/// -/// Copy N bytes of memory from one location to another. -#[no_mangle] -pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8, - n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - - dest -} - -/// Memmove -/// -/// Copy N bytes of memory from src to dest. The memory areas may overlap. -#[no_mangle] -pub unsafe extern fn memmove(dest: *mut u8, src: *const u8, - n: usize) -> *mut u8 { - if src < dest as *const u8 { - let mut i = n; - while i != 0 { - i -= 1; - *dest.offset(i as isize) = *src.offset(i as isize); - } - } else { - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - } - - dest -} - -/// Memset -/// -/// Fill a block of memory with a specified value. -#[no_mangle] -pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *s.offset(i as isize) = c as u8; - i += 1; - } - - s -} - -/// Memcmp -/// -/// Compare two blocks of memory. -#[no_mangle] -pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - - while i < n { - let a = *s1.offset(i as isize); - let b = *s2.offset(i as isize); - if a != b { - return a as i32 - b as i32 - } - i += 1; - } - - 0 -} diff --git a/arch/arm/src/interrupt.rs b/arch/arm/src/interrupt.rs deleted file mode 100644 index 6d7d460..0000000 --- a/arch/arm/src/interrupt.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Interrupt instructions - -/// Clear interrupts -#[inline(always)] -pub unsafe fn disable() { -} - -/// Set interrupts -#[inline(always)] -pub unsafe fn enable() { -} - -/// Set interrupts and halt -#[inline(always)] -pub unsafe fn enable_and_halt() { - halt(); -} - -/// Halt instruction -#[inline(always)] -pub unsafe fn halt() { - //asm!("wfi" : : : : "volatile"); - asm!("nop" : : : : "volatile"); -} - -/// Get a stack trace -//TODO: Check for stack being mapped before dereferencing -#[inline(never)] -pub unsafe fn stack_trace() { -} diff --git a/arch/arm/src/lib.rs b/arch/arm/src/lib.rs deleted file mode 100644 index 77b0e9c..0000000 --- a/arch/arm/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Architecture support for ARM - -#![feature(asm)] -#![feature(lang_items)] -#![feature(naked_functions)] -#![no_std] - -extern crate hole_list_allocator as allocator; -#[macro_use] -extern crate bitflags; -extern crate spin; - -/// Print to console -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ({}); -} - -/// Print with new line to console -#[macro_export] -macro_rules! println { - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -} - -/// Context switching -pub mod context; - -/// Memset, memcpy, etc. -pub mod externs; - -/// Interrupt handling -pub mod interrupt; - -/// Panic support -pub mod panic; - -/// Initialization function -pub mod start; diff --git a/arch/arm/src/linker.ld b/arch/arm/src/linker.ld deleted file mode 100644 index 71fd23e..0000000 --- a/arch/arm/src/linker.ld +++ /dev/null @@ -1,60 +0,0 @@ -ENTRY(kstart) -OUTPUT_ARCH(arm) -OUTPUT_FORMAT(elf32-littlearm) - -KERNEL_OFFSET = 0; - -SECTIONS { - . = KERNEL_OFFSET; - - .text : AT(ADDR(.text) - KERNEL_OFFSET) { - __text_start = .; - *(.text*) - . = ALIGN(4096); - __text_end = .; - } - - .rodata : AT(ADDR(.rodata) - KERNEL_OFFSET) { - __rodata_start = .; - *(.rodata*) - . = ALIGN(4096); - __rodata_end = .; - } - - .data : AT(ADDR(.data) - KERNEL_OFFSET) { - __data_start = .; - *(.data*) - . = ALIGN(4096); - __data_end = .; - } - - .tdata : AT(ADDR(.tdata) - KERNEL_OFFSET) { - __tdata_start = .; - *(.tdata*) - . = ALIGN(4096); - __tdata_end = .; - __tbss_start = .; - *(.tbss*) - . += 8; - . = ALIGN(4096); - __tbss_end = .; - } - - .bss : AT(ADDR(.bss) - KERNEL_OFFSET) { - __bss_start = .; - *(.bss*) - . = ALIGN(4096); - __bss_end = .; - } - - __end = .; - - /DISCARD/ : { - *(.comment*) - *(.debug*) - *(.eh_frame*) - *(.gcc_except_table*) - *(.note*) - *(.rel.eh_frame*) - } -} diff --git a/arch/arm/src/panic.rs b/arch/arm/src/panic.rs deleted file mode 100644 index 2acb38e..0000000 --- a/arch/arm/src/panic.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Intrinsics for panic handling - -use interrupt; - -#[cfg(not(test))] -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -#[cfg(not(test))] -/// Required to handle panics -#[lang = "panic_fmt"] -extern "C" fn panic_fmt(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! { - println!("PANIC: {}", fmt); - println!("FILE: {}", file); - println!("LINE: {}", line); - - unsafe { interrupt::stack_trace(); } - - println!("HALT"); - loop { - unsafe { interrupt::halt(); } - } -} - -#[allow(non_snake_case)] -#[no_mangle] -/// Required to handle panics -pub extern "C" fn _Unwind_Resume() -> ! { - loop { - unsafe { interrupt::halt(); } - } -} - -/// Required for linker -#[no_mangle] -pub extern "C" fn __aeabi_unwind_cpp_pr0() { - loop {} -} diff --git a/arch/arm/src/start.rs b/arch/arm/src/start.rs deleted file mode 100644 index b9abbe6..0000000 --- a/arch/arm/src/start.rs +++ /dev/null @@ -1,27 +0,0 @@ -const SERIAL_BASE: *mut u8 = 0x16000000 as *mut u8; -const SERIAL_FLAG_REGISTER: *const u8 = 0x16000018 as *const u8; -const SERIAL_BUFFER_FULL: u8 = (1 << 5); - -unsafe fn putc (c: u8) -{ - /* Wait until the serial buffer is empty */ - while *SERIAL_FLAG_REGISTER & SERIAL_BUFFER_FULL == SERIAL_BUFFER_FULL {} - - /* Put our character, c, into the serial buffer */ - *SERIAL_BASE = c; -} - -unsafe fn puts(string: &str) -{ - for b in string.bytes() { - putc(b); - } -} - -#[no_mangle] -#[naked] -pub unsafe extern fn kstart() -> ! { - asm!("mov sp, 0x18000" : : : : "volatile"); - puts("TEST\r\n"); - loop {} -} diff --git a/arch/test/Cargo.toml b/arch/test/Cargo.toml deleted file mode 100644 index 1900c7d..0000000 --- a/arch/test/Cargo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[package] -name = "arch_test" -version = "0.1.0" diff --git a/arch/test/src/interrupt.rs b/arch/test/src/interrupt.rs deleted file mode 100644 index 9e49020..0000000 --- a/arch/test/src/interrupt.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Interrupt instructions - -static mut INTERRUPTS_ENABLED: bool = false; - -/// Clear interrupts -#[inline(always)] -pub unsafe fn disable() { - println!("CLEAR INTERRUPTS"); - INTERRUPTS_ENABLED = false; -} - -/// Set interrupts -#[inline(always)] -pub unsafe fn enable() { - println!("SET INTERRUPTS"); - INTERRUPTS_ENABLED = true; -} - -/// Halt instruction -#[inline(always)] -pub unsafe fn halt() { - assert!(INTERRUPTS_ENABLED); - ::std::thread::yield_now(); -} - -/// Pause instruction -#[inline(always)] -pub unsafe fn pause() { - -} - -/// Set interrupts and nop -#[inline(always)] -pub unsafe fn enable_and_nop() { - enable(); -} - -/// Set interrupts and halt -#[inline(always)] -pub unsafe fn enable_and_halt() { - enable(); - halt(); -} diff --git a/arch/test/src/lib.rs b/arch/test/src/lib.rs deleted file mode 100644 index 8a155cd..0000000 --- a/arch/test/src/lib.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Architecture support for testing - -pub use std::io; - -/// Print to console -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ({ - use $crate::io::Write; - let _ = write!($crate::io::stdout(), $($arg)*); - }); -} - -/// Print with new line to console -#[macro_export] -macro_rules! println { - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -} - -/// Create an interrupt function that can safely run rust code -#[macro_export] -macro_rules! interrupt { - ($name:ident, $func:block) => { - pub unsafe extern fn $name () { - unsafe fn inner() { - $func - } - - // Call inner rust function - inner(); - } - }; -} - -/// Interrupt instructions -pub mod interrupt; - -/// Initialization and main function -pub mod main; - -/// Time functions -pub mod time; diff --git a/arch/test/src/main.rs b/arch/test/src/main.rs deleted file mode 100644 index 3f93ffb..0000000 --- a/arch/test/src/main.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// This function is where the kernel sets up IRQ handlers -/// It is increcibly unsafe, and should be minimal in nature - -extern { - fn kmain() -> !; -} - -#[no_mangle] -pub unsafe extern fn kstart() -> ! { - kmain(); -} diff --git a/arch/test/src/time.rs b/arch/test/src/time.rs deleted file mode 100644 index 6f7889d..0000000 --- a/arch/test/src/time.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub fn monotonic() -> (u64, u64) { - (0, 0) -} - -pub fn realtime() -> (u64, u64) { - (0, 0) -} diff --git a/arch/x86_64/Cargo.toml b/arch/x86_64/Cargo.toml deleted file mode 100644 index 695a907..0000000 --- a/arch/x86_64/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "arch_x86_64" -version = "0.1.0" - -[dependencies] -bitflags = "*" -hole_list_allocator = { path = "../../crates/hole_list_allocator/" } -io = { path = "../../crates/io/" } -raw-cpuid = { git = "https://github.com/gz/rust-cpuid" } -spin = "*" -redox_syscall = { path = "../../syscall/" } - -[dependencies.x86] -version = "0.7" -default-features = false diff --git a/arch/x86_64/src/acpi/dmar/drhd.rs b/arch/x86_64/src/acpi/dmar/drhd.rs deleted file mode 100644 index 494917e..0000000 --- a/arch/x86_64/src/acpi/dmar/drhd.rs +++ /dev/null @@ -1,77 +0,0 @@ -#[repr(packed)] -pub struct DrhdFault { - pub sts: u32, - pub ctrl: u32, - pub data: u32, - pub addr: [u32; 2], - _rsv: [u64; 2], - pub log: u64, -} - -#[repr(packed)] -pub struct DrhdProtectedMemory { - pub en: u32, - pub low_base: u32, - pub low_limit: u32, - pub high_base: u64, - pub high_limit: u64, -} - -#[repr(packed)] -pub struct DrhdInvalidation { - pub queue_head: u64, - pub queue_tail: u64, - pub queue_addr: u64, - _rsv: u32, - pub cmpl_sts: u32, - pub cmpl_ctrl: u32, - pub cmpl_data: u32, - pub cmpl_addr: [u32; 2], -} - -#[repr(packed)] -pub struct DrhdPageRequest { - pub queue_head: u64, - pub queue_tail: u64, - pub queue_addr: u64, - _rsv: u32, - pub sts: u32, - pub ctrl: u32, - pub data: u32, - pub addr: [u32; 2], -} - -#[repr(packed)] -pub struct DrhdMtrrVariable { - pub base: u64, - pub mask: u64, -} - -#[repr(packed)] -pub struct DrhdMtrr { - pub cap: u64, - pub def_type: u64, - pub fixed: [u64; 11], - pub variable: [DrhdMtrrVariable; 10], -} - -#[repr(packed)] -pub struct Drhd { - pub version: u32, - _rsv: u32, - pub cap: u64, - pub ext_cap: u64, - pub gl_cmd: u32, - pub gl_sts: u32, - pub root_table: u64, - pub ctx_cmd: u64, - _rsv1: u32, - pub fault: DrhdFault, - _rsv2: u32, - pub pm: DrhdProtectedMemory, - pub invl: DrhdInvalidation, - _rsv3: u64, - pub intr_table: u64, - pub page_req: DrhdPageRequest, - pub mtrr: DrhdMtrr, -} diff --git a/arch/x86_64/src/acpi/dmar/mod.rs b/arch/x86_64/src/acpi/dmar/mod.rs deleted file mode 100644 index d13184f..0000000 --- a/arch/x86_64/src/acpi/dmar/mod.rs +++ /dev/null @@ -1,182 +0,0 @@ -use core::mem; - -use super::sdt::Sdt; -use self::drhd::Drhd; -use memory::Frame; -use paging::{entry, ActivePageTable, PhysicalAddress}; - -pub mod drhd; - -/// The DMA Remapping Table -#[derive(Debug)] -pub struct Dmar { - sdt: &'static Sdt, - pub addr_width: u8, - pub flags: u8, - _rsv: [u8; 10], -} - -impl Dmar { - pub fn new(sdt: &'static Sdt) -> Option { - if &sdt.signature == b"DMAR" && sdt.data_len() >= 12 { //Not valid if no local address and flags - let addr_width = unsafe { *(sdt.data_address() as *const u8) }; - let flags = unsafe { *(sdt.data_address() as *const u8).offset(1) }; - let rsv: [u8; 10] = unsafe { *((sdt.data_address() as *const u8).offset(2) as *const [u8; 10]) }; - - Some(Dmar { - sdt: sdt, - addr_width: addr_width, - flags: flags, - _rsv: rsv, - }) - } else { - None - } - } - - pub fn iter(&self) -> DmarIter { - DmarIter { - sdt: self.sdt, - i: 12 // Skip address width and flags - } - } -} - -/// - -/// DMAR DMA Remapping Hardware Unit Definition -// TODO: Implement iterator on DmarDrhd scope -#[derive(Debug)] -#[repr(packed)] -pub struct DmarDrhd { - kind: u16, - length: u16, - flags: u8, - _rsv: u8, - segment: u16, - base: u64, -} - -impl DmarDrhd { - pub fn get(&self, active_table: &mut ActivePageTable) -> &'static mut Drhd { - active_table.identity_map(Frame::containing_address(PhysicalAddress::new(self.base as usize)), entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE); - unsafe { &mut *(self.base as *mut Drhd) } - } -} - -/// DMAR Reserved Memory Region Reporting -// TODO: Implement iterator on DmarRmrr scope -#[derive(Debug)] -#[repr(packed)] -pub struct DmarRmrr { - kind: u16, - length: u16, - _rsv: u16, - segment: u16, - base: u64, - limit: u64, -} - -/// DMAR Root Port ATS Capability Reporting -// TODO: Implement iterator on DmarAtsr scope -#[derive(Debug)] -#[repr(packed)] -pub struct DmarAtsr { - kind: u16, - length: u16, - flags: u8, - _rsv: u8, - segment: u16, -} - -/// DMAR Remapping Hardware Static Affinity -#[derive(Debug)] -#[repr(packed)] -pub struct DmarRhsa { - kind: u16, - length: u16, - _rsv: u32, - base: u64, - domain: u32, -} - -/// DMAR ACPI Name-space Device Declaration -// TODO: Implement iterator on DmarAndd object name -#[derive(Debug)] -#[repr(packed)] -pub struct DmarAndd { - kind: u16, - length: u16, - _rsv: [u8; 3], - acpi_dev: u8, -} - -/// DMAR Entries -#[derive(Debug)] -pub enum DmarEntry { - Drhd(&'static DmarDrhd), - InvalidDrhd(usize), - Rmrr(&'static DmarRmrr), - InvalidRmrr(usize), - Atsr(&'static DmarAtsr), - InvalidAtsr(usize), - Rhsa(&'static DmarRhsa), - InvalidRhsa(usize), - Andd(&'static DmarAndd), - InvalidAndd(usize), - Unknown(u16) -} - -pub struct DmarIter { - sdt: &'static Sdt, - i: usize -} - -impl Iterator for DmarIter { - type Item = DmarEntry; - fn next(&mut self) -> Option { - if self.i + 4 <= self.sdt.data_len() { - let entry_type = unsafe { *((self.sdt.data_address() as *const u8).offset(self.i as isize) as *const u16) }; - let entry_len = unsafe { *((self.sdt.data_address() as *const u8).offset(self.i as isize + 2) as *const u16) } as usize; - - if self.i + entry_len <= self.sdt.data_len() { - let item = match entry_type { - 0 => if entry_len >= mem::size_of::() { - DmarEntry::Drhd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarDrhd) }) - } else { - DmarEntry::InvalidDrhd(entry_len) - }, - 1 => if entry_len >= mem::size_of::() { - DmarEntry::Rmrr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRmrr) }) - } else { - DmarEntry::InvalidRmrr(entry_len) - }, - 2 => if entry_len >= mem::size_of::() { - DmarEntry::Atsr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAtsr) }) - } else { - DmarEntry::InvalidAtsr(entry_len) - }, - 3 => if entry_len == mem::size_of::() { - DmarEntry::Rhsa(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRhsa) }) - } else { - DmarEntry::InvalidRhsa(entry_len) - }, - 4 => if entry_len >= mem::size_of::() { - DmarEntry::Andd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAndd) }) - } else { - DmarEntry::InvalidAndd(entry_len) - }, - _ => DmarEntry::Unknown(entry_type) - }; - - self.i += entry_len; - - Some(item) - } else { - None - } - } else { - None - } - } -} diff --git a/arch/x86_64/src/acpi/fadt.rs b/arch/x86_64/src/acpi/fadt.rs deleted file mode 100644 index d40d5a1..0000000 --- a/arch/x86_64/src/acpi/fadt.rs +++ /dev/null @@ -1,96 +0,0 @@ -use core::{mem, ptr}; - -use super::sdt::Sdt; - -#[repr(packed)] -#[derive(Debug)] -pub struct Fadt { - pub header: Sdt, - pub firmware_ctrl: u32, - pub dsdt: u32, - - // field used in ACPI 1.0; no longer in use, for compatibility only - reserved: u8, - - pub preferred_power_managament: u8, - pub sci_interrupt: u16, - pub smi_command_port: u32, - pub acpi_enable: u8, - pub acpi_disable: u8, - pub s4_bios_req: u8, - pub pstate_control: u8, - pub pm1a_event_block: u32, - pub pm1b_event_block: u32, - pub pm1a_control_block: u32, - pub pm1b_control_block: u32, - pub pm2_control_block: u32, - pub pm_timer_block: u32, - pub gpe0_block: u32, - pub gpe1_block: u32, - pub pm1_event_length: u8, - pub pm1_control_length: u8, - pub pm2_control_length: u8, - pub pm_timer_length: u8, - pub gpe0_ength: u8, - pub gpe1_length: u8, - pub gpe1_base: u8, - pub c_state_control: u8, - pub worst_c2_latency: u16, - pub worst_c3_latency: u16, - pub flush_size: u16, - pub flush_stride: u16, - pub duty_offset: u8, - pub duty_width: u8, - pub day_alarm: u8, - pub month_alarm: u8, - pub century: u8, - - // reserved in ACPI 1.0; used since ACPI 2.0+ - pub boot_architecture_flags: u16, - - reserved2: u8, - pub flags: u32, -} - -/* ACPI 2 structure -#[repr(packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct GenericAddressStructure { - address_space: u8, - bit_width: u8, - bit_offset: u8, - access_size: u8, - address: u64, -} - -{ - // 12 byte structure; see below for details - pub reset_reg: GenericAddressStructure, - - pub reset_value: u8, - reserved3: [u8; 3], - - // 64bit pointers - Available on ACPI 2.0+ - pub x_firmware_control: u64, - pub x_dsdt: u64, - - pub x_pm1a_event_block: GenericAddressStructure, - pub x_pm1b_event_block: GenericAddressStructure, - pub x_pm1a_control_block: GenericAddressStructure, - pub x_pm1b_control_block: GenericAddressStructure, - pub x_pm2_control_block: GenericAddressStructure, - pub x_pm_timer_block: GenericAddressStructure, - pub x_gpe0_block: GenericAddressStructure, - pub x_gpe1_block: GenericAddressStructure, -} -*/ - -impl Fadt { - pub fn new(sdt: &'static Sdt) -> Option { - if &sdt.signature == b"FACP" && sdt.length as usize >= mem::size_of::() { - Some(unsafe { ptr::read((sdt as *const Sdt) as *const Fadt) }) - } else { - None - } - } -} diff --git a/arch/x86_64/src/acpi/madt.rs b/arch/x86_64/src/acpi/madt.rs deleted file mode 100644 index dac16dc..0000000 --- a/arch/x86_64/src/acpi/madt.rs +++ /dev/null @@ -1,133 +0,0 @@ -use core::mem; - -use super::sdt::Sdt; - -/// The Multiple APIC Descriptor Table -#[derive(Debug)] -pub struct Madt { - sdt: &'static Sdt, - pub local_address: u32, - pub flags: u32 -} - -impl Madt { - pub fn new(sdt: &'static Sdt) -> Option { - if &sdt.signature == b"APIC" && sdt.data_len() >= 8 { //Not valid if no local address and flags - let local_address = unsafe { *(sdt.data_address() as *const u32) }; - let flags = unsafe { *(sdt.data_address() as *const u32).offset(1) }; - - Some(Madt { - sdt: sdt, - local_address: local_address, - flags: flags - }) - } else { - None - } - } - - pub fn iter(&self) -> MadtIter { - MadtIter { - sdt: self.sdt, - i: 8 // Skip local controller address and flags - } - } -} - -/// - -/// MADT Local APIC -#[derive(Debug)] -#[repr(packed)] -pub struct MadtLocalApic { - /// Processor ID - pub processor: u8, - /// Local APIC ID - pub id: u8, - /// Flags. 1 means that the processor is enabled - pub flags: u32 -} - -/// MADT I/O APIC -#[derive(Debug)] -#[repr(packed)] -pub struct MadtIoApic { - /// I/O APIC ID - pub id: u8, - /// reserved - reserved: u8, - /// I/O APIC address - pub address: u32, - /// Global system interrupt base - pub gsi_base: u32 -} - -/// MADT Interrupt Source Override -#[derive(Debug)] -#[repr(packed)] -pub struct MadtIntSrcOverride { - /// Bus Source - pub bus_source: u8, - /// IRQ Source - pub irq_source: u8, - /// Global system interrupt base - pub gsi_base: u32, - /// Flags - pub flags: u16 -} - -/// MADT Entries -#[derive(Debug)] -pub enum MadtEntry { - LocalApic(&'static MadtLocalApic), - InvalidLocalApic(usize), - IoApic(&'static MadtIoApic), - InvalidIoApic(usize), - IntSrcOverride(&'static MadtIntSrcOverride), - InvalidIntSrcOverride(usize), - Unknown(u8) -} - -pub struct MadtIter { - sdt: &'static Sdt, - i: usize -} - -impl Iterator for MadtIter { - type Item = MadtEntry; - fn next(&mut self) -> Option { - if self.i + 1 < self.sdt.data_len() { - let entry_type = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize) }; - let entry_len = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize + 1) } as usize; - - if self.i + entry_len <= self.sdt.data_len() { - let item = match entry_type { - 0 => if entry_len == mem::size_of::() + 2 { - MadtEntry::LocalApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtLocalApic) }) - } else { - MadtEntry::InvalidLocalApic(entry_len) - }, - 1 => if entry_len == mem::size_of::() + 2 { - MadtEntry::IoApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIoApic) }) - } else { - MadtEntry::InvalidIoApic(entry_len) - }, - 2 => if entry_len == mem::size_of::() + 2 { - MadtEntry::IntSrcOverride(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIntSrcOverride) }) - } else { - MadtEntry::InvalidIntSrcOverride(entry_len) - }, - _ => MadtEntry::Unknown(entry_type) - }; - - self.i += entry_len; - - Some(item) - } else { - None - } - } else { - None - } - } -} diff --git a/arch/x86_64/src/acpi/mod.rs b/arch/x86_64/src/acpi/mod.rs deleted file mode 100644 index 87f4416..0000000 --- a/arch/x86_64/src/acpi/mod.rs +++ /dev/null @@ -1,284 +0,0 @@ -//! # ACPI -//! Code to parse the ACPI tables - -use core::intrinsics::{atomic_load, atomic_store}; -use core::sync::atomic::Ordering; - -use device::local_apic::LOCAL_APIC; -use interrupt; -use memory::{allocate_frames, Frame}; -use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; -use start::{kstart_ap, CPU_COUNT, AP_READY}; - -use self::dmar::{Dmar, DmarEntry}; -use self::fadt::Fadt; -use self::madt::{Madt, MadtEntry}; -use self::rsdt::Rsdt; -use self::sdt::Sdt; -use self::xsdt::Xsdt; - -pub mod dmar; -pub mod fadt; -pub mod madt; -pub mod rsdt; -pub mod sdt; -pub mod xsdt; - -const TRAMPOLINE: usize = 0x7E00; -const AP_STARTUP: usize = TRAMPOLINE + 512; - -pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { - print!(" "); - for &c in sdt.signature.iter() { - print!("{}", c as char); - } - - if let Some(fadt) = Fadt::new(sdt) { - println!(": {:#?}", fadt); - } else if let Some(madt) = Madt::new(sdt) { - println!(": {:>08X}: {}", madt.local_address, madt.flags); - - let mut local_apic = unsafe { &mut LOCAL_APIC }; - - let me = local_apic.id() as u8; - - if local_apic.x2 { - println!(" X2APIC {}", me); - } else { - println!(" XAPIC {}: {:>08X}", me, local_apic.address); - } - - let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE)); - let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE)); - - // Map trampoline - active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE); - active_table.flush(trampoline_page); - - for madt_entry in madt.iter() { - println!(" {:?}", madt_entry); - match madt_entry { - MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me { - println!(" This is my local APIC"); - } else { - if ap_local_apic.flags & 1 == 1 { - // Increase CPU ID - CPU_COUNT.fetch_add(1, Ordering::SeqCst); - - // Allocate a stack - let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET; - let stack_end = stack_start + 64 * 4096; - - let ap_ready = TRAMPOLINE as *mut u64; - let ap_cpu_id = unsafe { ap_ready.offset(1) }; - let ap_page_table = unsafe { ap_ready.offset(2) }; - let ap_stack_start = unsafe { ap_ready.offset(3) }; - let ap_stack_end = unsafe { ap_ready.offset(4) }; - let ap_code = unsafe { ap_ready.offset(5) }; - - // Set the ap_ready to 0, volatile - unsafe { atomic_store(ap_ready, 0) }; - unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) }; - unsafe { atomic_store(ap_page_table, active_table.address() as u64) }; - unsafe { atomic_store(ap_stack_start, stack_start as u64) }; - unsafe { atomic_store(ap_stack_end, stack_end as u64) }; - unsafe { atomic_store(ap_code, kstart_ap as u64) }; - AP_READY.store(false, Ordering::SeqCst); - - print!(" AP {}:", ap_local_apic.id); - - // Send INIT IPI - { - let mut icr = 0x4500; - if local_apic.x2 { - icr |= (ap_local_apic.id as u64) << 32; - } else { - icr |= (ap_local_apic.id as u64) << 56; - } - print!(" IPI..."); - local_apic.set_icr(icr); - } - - // Send START IPI - { - //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there - let ap_segment = (AP_STARTUP >> 12) & 0xFF; - let mut icr = 0x4600 | ap_segment as u64; - - if local_apic.x2 { - icr |= (ap_local_apic.id as u64) << 32; - } else { - icr |= (ap_local_apic.id as u64) << 56; - } - - print!(" SIPI..."); - local_apic.set_icr(icr); - } - - // Wait for trampoline ready - print!(" Wait..."); - while unsafe { atomic_load(ap_ready) } == 0 { - interrupt::pause(); - } - print!(" Trampoline..."); - while ! AP_READY.load(Ordering::SeqCst) { - interrupt::pause(); - } - println!(" Ready"); - - active_table.flush_all(); - } else { - println!(" CPU Disabled"); - } - }, - _ => () - } - } - - // Unmap trampoline - active_table.unmap(trampoline_page); - active_table.flush(trampoline_page); - } else if let Some(dmar) = Dmar::new(sdt) { - println!(": {}: {}", dmar.addr_width, dmar.flags); - - for dmar_entry in dmar.iter() { - println!(" {:?}", dmar_entry); - match dmar_entry { - DmarEntry::Drhd(dmar_drhd) => { - let drhd = dmar_drhd.get(active_table); - - println!("VER: {:X}", drhd.version); - println!("CAP: {:X}", drhd.cap); - println!("EXT_CAP: {:X}", drhd.ext_cap); - println!("GCMD: {:X}", drhd.gl_cmd); - println!("GSTS: {:X}", drhd.gl_sts); - println!("RT: {:X}", drhd.root_table); - }, - _ => () - } - } - } else { - println!(": Unknown"); - } -} - -/// Parse the ACPI tables to gather CPU, interrupt, and timer information -pub unsafe fn init(active_table: &mut ActivePageTable) -> Option { - let start_addr = 0xE0000; - let end_addr = 0xFFFFF; - - // Map all of the ACPI RSDP space - { - let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr)); - let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get())); - active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE); - active_table.flush(page); - } - } - - // Search for RSDP - if let Some(rsdp) = RSDP::search(start_addr, end_addr) { - let get_sdt = |sdt_address: usize, active_table: &mut ActivePageTable| -> (&'static Sdt, bool) { - let mapped = if active_table.translate_page(Page::containing_address(VirtualAddress::new(sdt_address))).is_none() { - let sdt_frame = Frame::containing_address(PhysicalAddress::new(sdt_address)); - let sdt_page = Page::containing_address(VirtualAddress::new(sdt_address)); - active_table.map_to(sdt_page, sdt_frame, entry::PRESENT | entry::NO_EXECUTE); - active_table.flush(sdt_page); - true - } else { - false - }; - (&*(sdt_address as *const Sdt), mapped) - }; - - let drop_sdt = |sdt: &'static Sdt, mapped: bool, active_table: &mut ActivePageTable| { - let sdt_address = sdt as *const Sdt as usize; - drop(sdt); - if mapped { - let sdt_page = Page::containing_address(VirtualAddress::new(sdt_address)); - active_table.unmap(sdt_page); - active_table.flush(sdt_page); - } - }; - - let (rxsdt, rxmapped) = get_sdt(rsdp.sdt_address(), active_table); - - for &c in rxsdt.signature.iter() { - print!("{}", c as char); - } - println!(":"); - if let Some(rsdt) = Rsdt::new(rxsdt) { - for sdt_address in rsdt.iter() { - let (sdt, mapped) = get_sdt(sdt_address, active_table); - init_sdt(sdt, active_table); - drop_sdt(sdt, mapped, active_table); - } - } else if let Some(xsdt) = Xsdt::new(rxsdt) { - for sdt_address in xsdt.iter() { - let (sdt, mapped) = get_sdt(sdt_address, active_table); - init_sdt(sdt, active_table); - drop_sdt(sdt, mapped, active_table); - } - } else { - println!("UNKNOWN RSDT OR XSDT SIGNATURE"); - } - - drop_sdt(rxsdt, rxmapped, active_table); - } else { - println!("NO RSDP FOUND"); - } - - // Unmap all of the ACPI RSDP space - { - let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr)); - let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get())); - active_table.unmap(page); - active_table.flush(page); - } - } - - None -} - -pub struct Acpi; - -/// RSDP -#[derive(Copy, Clone, Debug)] -#[repr(packed)] -pub struct RSDP { - signature: [u8; 8], - checksum: u8, - oemid: [u8; 6], - revision: u8, - rsdt_address: u32, - length: u32, - xsdt_address: u64, - extended_checksum: u8, - reserved: [u8; 3] -} - -impl RSDP { - /// Search for the RSDP - pub fn search(start_addr: usize, end_addr: usize) -> Option { - for i in 0 .. (end_addr + 1 - start_addr)/16 { - let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) }; - if &rsdp.signature == b"RSD PTR " { - return Some(*rsdp); - } - } - None - } - - /// Get the RSDT or XSDT address - pub fn sdt_address(&self) -> usize { - if self.revision >= 2 { - self.xsdt_address as usize - } else { - self.rsdt_address as usize - } - } -} diff --git a/arch/x86_64/src/acpi/rsdt.rs b/arch/x86_64/src/acpi/rsdt.rs deleted file mode 100644 index fa391c0..0000000 --- a/arch/x86_64/src/acpi/rsdt.rs +++ /dev/null @@ -1,41 +0,0 @@ -use core::mem; - -use super::sdt::Sdt; - -#[derive(Debug)] -pub struct Rsdt(&'static Sdt); - -impl Rsdt { - pub fn new(sdt: &'static Sdt) -> Option { - if &sdt.signature == b"RSDT" { - Some(Rsdt(sdt)) - } else { - None - } - } - - pub fn iter(&self) -> RsdtIter { - RsdtIter { - sdt: self.0, - i: 0 - } - } -} - -pub struct RsdtIter { - sdt: &'static Sdt, - i: usize -} - -impl Iterator for RsdtIter { - type Item = usize; - fn next(&mut self) -> Option { - if self.i < self.sdt.data_len()/mem::size_of::() { - let item = unsafe { *(self.sdt.data_address() as *const u32).offset(self.i as isize) }; - self.i += 1; - Some(item as usize) - } else { - None - } - } -} diff --git a/arch/x86_64/src/acpi/sdt.rs b/arch/x86_64/src/acpi/sdt.rs deleted file mode 100644 index 0d8cedd..0000000 --- a/arch/x86_64/src/acpi/sdt.rs +++ /dev/null @@ -1,33 +0,0 @@ -use core::mem; - -#[derive(Copy, Clone, Debug)] -#[repr(packed)] -pub struct Sdt { - pub signature: [u8; 4], - pub length: u32, - pub revision: u8, - pub checksum: u8, - pub oem_id: [u8; 6], - pub oem_table_id: [u8; 8], - pub oem_revision: u32, - pub creator_id: u32, - pub creator_revision: u32 -} - -impl Sdt { - /// Get the address of this tables data - pub fn data_address(&'static self) -> usize { - self as *const _ as usize + mem::size_of::() - } - - /// Get the length of this tables data - pub fn data_len(&'static self) -> usize { - let total_size = self.length as usize; - let header_size = mem::size_of::(); - if total_size >= header_size { - total_size - header_size - } else { - 0 - } - } -} diff --git a/arch/x86_64/src/acpi/xsdt.rs b/arch/x86_64/src/acpi/xsdt.rs deleted file mode 100644 index 5ec6036..0000000 --- a/arch/x86_64/src/acpi/xsdt.rs +++ /dev/null @@ -1,41 +0,0 @@ -use core::mem; - -use super::sdt::Sdt; - -#[derive(Debug)] -pub struct Xsdt(&'static Sdt); - -impl Xsdt { - pub fn new(sdt: &'static Sdt) -> Option { - if &sdt.signature == b"XSDT" { - Some(Xsdt(sdt)) - } else { - None - } - } - - pub fn iter(&self) -> XsdtIter { - XsdtIter { - sdt: self.0, - i: 0 - } - } -} - -pub struct XsdtIter { - sdt: &'static Sdt, - i: usize -} - -impl Iterator for XsdtIter { - type Item = usize; - fn next(&mut self) -> Option { - if self.i < self.sdt.data_len()/mem::size_of::() { - let item = unsafe { *(self.sdt.data_address() as *const u64).offset(self.i as isize) }; - self.i += 1; - Some(item as usize) - } else { - None - } - } -} diff --git a/arch/x86_64/src/console.rs b/arch/x86_64/src/console.rs deleted file mode 100644 index 92f28d8..0000000 --- a/arch/x86_64/src/console.rs +++ /dev/null @@ -1,14 +0,0 @@ -use core::fmt::{self, Write}; -use spin::Mutex; - -use device::serial::COM1; - -pub static CONSOLE: Mutex = Mutex::new(Console); - -pub struct Console; - -impl Write for Console { - fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - COM1.lock().write_str(s) - } -} diff --git a/arch/x86_64/src/context.rs b/arch/x86_64/src/context.rs deleted file mode 100644 index 2a8242d..0000000 --- a/arch/x86_64/src/context.rs +++ /dev/null @@ -1,184 +0,0 @@ -use core::mem; -use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; - -/// This must be used by the kernel to ensure that context switches are done atomically -/// Compare and exchange this to true when beginning a context switch on any CPU -/// The Context::switch_to function will set it back to false, allowing other CPU's to switch -/// This must be done, as no locks can be held on the stack during switch -pub static CONTEXT_SWITCH_LOCK: AtomicBool = ATOMIC_BOOL_INIT; - -#[derive(Clone, Debug)] -pub struct Context { - /// FX valid? - loadable: bool, - /// FX location - fx: usize, - /// Page table pointer - cr3: usize, - /// RFLAGS register - rflags: usize, - /// RBX register - rbx: usize, - /// R12 register - r12: usize, - /// R13 register - r13: usize, - /// R14 register - r14: usize, - /// R15 register - r15: usize, - /// Base pointer - rbp: usize, - /// Stack pointer - rsp: usize -} - -impl Context { - pub fn new() -> Context { - Context { - loadable: false, - fx: 0, - cr3: 0, - rflags: 0, - rbx: 0, - r12: 0, - r13: 0, - r14: 0, - r15: 0, - rbp: 0, - rsp: 0 - } - } - - pub fn get_page_table(&self) -> usize { - self.cr3 - } - - pub fn set_fx(&mut self, address: usize) { - self.fx = address; - } - - pub fn set_page_table(&mut self, address: usize) { - self.cr3 = address; - } - - pub fn set_stack(&mut self, address: usize) { - self.rsp = address; - } - - pub unsafe fn signal_stack(&mut self, handler: extern fn(usize), sig: u8) { - self.push_stack(sig as usize); - self.push_stack(handler as usize); - self.push_stack(signal_handler_wrapper as usize); - } - - pub unsafe fn push_stack(&mut self, value: usize) { - self.rsp -= mem::size_of::(); - *(self.rsp as *mut usize) = value; - } - - pub unsafe fn pop_stack(&mut self) -> usize { - let value = *(self.rsp as *const usize); - self.rsp += mem::size_of::(); - value - } - - /// Switch to the next context by restoring its stack and registers - #[cold] - #[inline(never)] - #[naked] - pub unsafe fn switch_to(&mut self, next: &mut Context) { - asm!("fxsave [$0]" : : "r"(self.fx) : "memory" : "intel", "volatile"); - self.loadable = true; - if next.loadable { - asm!("fxrstor [$0]" : : "r"(next.fx) : "memory" : "intel", "volatile"); - }else{ - asm!("fninit" : : : "memory" : "intel", "volatile"); - } - - asm!("mov $0, cr3" : "=r"(self.cr3) : : "memory" : "intel", "volatile"); - if next.cr3 != self.cr3 { - asm!("mov cr3, $0" : : "r"(next.cr3) : "memory" : "intel", "volatile"); - } - - asm!("pushfq ; pop $0" : "=r"(self.rflags) : : "memory" : "intel", "volatile"); - asm!("push $0 ; popfq" : : "r"(next.rflags) : "memory" : "intel", "volatile"); - - asm!("mov $0, rbx" : "=r"(self.rbx) : : "memory" : "intel", "volatile"); - asm!("mov rbx, $0" : : "r"(next.rbx) : "memory" : "intel", "volatile"); - - asm!("mov $0, r12" : "=r"(self.r12) : : "memory" : "intel", "volatile"); - asm!("mov r12, $0" : : "r"(next.r12) : "memory" : "intel", "volatile"); - - asm!("mov $0, r13" : "=r"(self.r13) : : "memory" : "intel", "volatile"); - asm!("mov r13, $0" : : "r"(next.r13) : "memory" : "intel", "volatile"); - - asm!("mov $0, r14" : "=r"(self.r14) : : "memory" : "intel", "volatile"); - asm!("mov r14, $0" : : "r"(next.r14) : "memory" : "intel", "volatile"); - - asm!("mov $0, r15" : "=r"(self.r15) : : "memory" : "intel", "volatile"); - asm!("mov r15, $0" : : "r"(next.r15) : "memory" : "intel", "volatile"); - - asm!("mov $0, rsp" : "=r"(self.rsp) : : "memory" : "intel", "volatile"); - asm!("mov rsp, $0" : : "r"(next.rsp) : "memory" : "intel", "volatile"); - - asm!("mov $0, rbp" : "=r"(self.rbp) : : "memory" : "intel", "volatile"); - asm!("mov rbp, $0" : : "r"(next.rbp) : "memory" : "intel", "volatile"); - } -} - -#[repr(packed)] -pub struct SignalHandlerStack { - r11: usize, - r10: usize, - r9: usize, - r8: usize, - rsi: usize, - rdi: usize, - rdx: usize, - rcx: usize, - rax: usize, - handler: extern fn(usize), - sig: usize, - rip: usize, -} - -#[naked] -unsafe extern fn signal_handler_wrapper() { - #[inline(never)] - unsafe fn inner(stack: &SignalHandlerStack) { - (stack.handler)(stack.sig); - } - - // Push scratch registers - asm!("push rax - push rcx - push rdx - push rdi - push rsi - push r8 - push r9 - push r10 - push r11" - : : : : "intel", "volatile"); - - // Get reference to stack variables - let rsp: usize; - asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); - - // Call inner rust function - inner(&*(rsp as *const SignalHandlerStack)); - - // Pop scratch registers, error code, and return - asm!("pop r11 - pop r10 - pop r9 - pop r8 - pop rsi - pop rdi - pop rdx - pop rcx - pop rax - add rsp, 16" - : : : : "intel", "volatile"); -} diff --git a/arch/x86_64/src/device/cpu.rs b/arch/x86_64/src/device/cpu.rs deleted file mode 100644 index e48547b..0000000 --- a/arch/x86_64/src/device/cpu.rs +++ /dev/null @@ -1,126 +0,0 @@ -extern crate raw_cpuid; - -use core::fmt::{Result, Write}; - -use self::raw_cpuid::CpuId; - -pub fn cpu_info(w: &mut W) -> Result { - let cpuid = CpuId::new(); - - if let Some(info) = cpuid.get_vendor_info() { - write!(w, "Vendor: {}\n", info.as_string())?; - } - - if let Some(info) = cpuid.get_extended_function_info() { - if let Some(brand) = info.processor_brand_string() { - write!(w, "Model: {}\n", brand)?; - } - } - - if let Some(info) = cpuid.get_processor_frequency_info() { - write!(w, "CPU Base MHz: {}\n", info.processor_base_frequency())?; - write!(w, "CPU Max MHz: {}\n", info.processor_max_frequency())?; - write!(w, "Bus MHz: {}\n", info.bus_frequency())?; - } - - write!(w, "Features:")?; - - if let Some(info) = cpuid.get_feature_info() { - if info.has_fpu() { write!(w, " fpu")? }; - if info.has_vme() { write!(w, " vme")? }; - if info.has_de() { write!(w, " de")? }; - if info.has_pse() { write!(w, " pse")? }; - if info.has_tsc() { write!(w, " tsc")? }; - if info.has_msr() { write!(w, " msr")? }; - if info.has_pae() { write!(w, " pae")? }; - if info.has_mce() { write!(w, " mce")? }; - - if info.has_cmpxchg8b() { write!(w, " cx8")? }; - if info.has_apic() { write!(w, " apic")? }; - if info.has_sysenter_sysexit() { write!(w, " sep")? }; - if info.has_mtrr() { write!(w, " mtrr")? }; - if info.has_pge() { write!(w, " pge")? }; - if info.has_mca() { write!(w, " mca")? }; - if info.has_cmov() { write!(w, " cmov")? }; - if info.has_pat() { write!(w, " pat")? }; - - if info.has_pse36() { write!(w, " pse36")? }; - if info.has_psn() { write!(w, " psn")? }; - if info.has_clflush() { write!(w, " clflush")? }; - if info.has_ds() { write!(w, " ds")? }; - if info.has_acpi() { write!(w, " acpi")? }; - if info.has_mmx() { write!(w, " mmx")? }; - if info.has_fxsave_fxstor() { write!(w, " fxsr")? }; - if info.has_sse() { write!(w, " sse")? }; - - if info.has_sse2() { write!(w, " sse2")? }; - if info.has_ss() { write!(w, " ss")? }; - if info.has_htt() { write!(w, " ht")? }; - if info.has_tm() { write!(w, " tm")? }; - if info.has_pbe() { write!(w, " pbe")? }; - - if info.has_sse3() { write!(w, " sse3")? }; - if info.has_pclmulqdq() { write!(w, " pclmulqdq")? }; - if info.has_ds_area() { write!(w, " dtes64")? }; - if info.has_monitor_mwait() { write!(w, " monitor")? }; - if info.has_cpl() { write!(w, " ds_cpl")? }; - if info.has_vmx() { write!(w, " vmx")? }; - if info.has_smx() { write!(w, " smx")? }; - if info.has_eist() { write!(w, " est")? }; - - if info.has_tm2() { write!(w, " tm2")? }; - if info.has_ssse3() { write!(w, " ssse3")? }; - if info.has_cnxtid() { write!(w, " cnxtid")? }; - if info.has_fma() { write!(w, " fma")? }; - if info.has_cmpxchg16b() { write!(w, " cx16")? }; - if info.has_pdcm() { write!(w, " pdcm")? }; - if info.has_pcid() { write!(w, " pcid")? }; - if info.has_dca() { write!(w, " dca")? }; - - if info.has_sse41() { write!(w, " sse4_1")? }; - if info.has_sse42() { write!(w, " sse4_2")? }; - if info.has_x2apic() { write!(w, " x2apic")? }; - if info.has_movbe() { write!(w, " movbe")? }; - if info.has_popcnt() { write!(w, " popcnt")? }; - if info.has_tsc_deadline() { write!(w, " tsc_deadline_timer")? }; - if info.has_aesni() { write!(w, " aes")? }; - if info.has_xsave() { write!(w, " xsave")? }; - - if info.has_oxsave() { write!(w, " xsaveopt")? }; - if info.has_avx() { write!(w, " avx")? }; - if info.has_f16c() { write!(w, " f16c")? }; - if info.has_rdrand() { write!(w, " rdrand")? }; - } - - if let Some(info) = cpuid.get_extended_function_info() { - if info.has_64bit_mode() { write!(w, " lm")? }; - if info.has_rdtscp() { write!(w, " rdtscp")? }; - if info.has_1gib_pages() { write!(w, " pdpe1gb")? }; - if info.has_execute_disable() { write!(w, " nx")? }; - if info.has_syscall_sysret() { write!(w, " syscall")? }; - if info.has_prefetchw() { write!(w, " prefetchw")? }; - if info.has_lzcnt() { write!(w, " lzcnt")? }; - if info.has_lahf_sahf() { write!(w, " lahf_lm")? }; - if info.has_invariant_tsc() { write!(w, " constant_tsc")? }; - } - - if let Some(info) = cpuid.get_extended_feature_info() { - if info.has_fsgsbase() { write!(w, " fsgsbase")? }; - if info.has_tsc_adjust_msr() { write!(w, " tsc_adjust")? }; - if info.has_bmi1() { write!(w, " bmi1")? }; - if info.has_hle() { write!(w, " hle")? }; - if info.has_avx2() { write!(w, " avx2")? }; - if info.has_smep() { write!(w, " smep")? }; - if info.has_bmi2() { write!(w, " bmi2")? }; - if info.has_rep_movsb_stosb() { write!(w, " erms")? }; - if info.has_invpcid() { write!(w, " invpcid")? }; - if info.has_rtm() { write!(w, " rtm")? }; - if info.has_qm() { write!(w, " qm")? }; - if info.has_fpu_cs_ds_deprecated() { write!(w, " fpu_seg")? }; - if info.has_mpx() { write!(w, " mpx")? }; - } - - write!(w, "\n")?; - - Ok(()) -} diff --git a/arch/x86_64/src/device/local_apic.rs b/arch/x86_64/src/device/local_apic.rs deleted file mode 100644 index d352c2c..0000000 --- a/arch/x86_64/src/device/local_apic.rs +++ /dev/null @@ -1,114 +0,0 @@ -use core::intrinsics::{volatile_load, volatile_store}; -use x86::cpuid::CpuId; -use x86::msr::*; - -use memory::Frame; -use paging::{entry, ActivePageTable, PhysicalAddress, Page, VirtualAddress}; - -pub static mut LOCAL_APIC: LocalApic = LocalApic { - address: 0, - x2: false -}; - -pub unsafe fn init(active_table: &mut ActivePageTable) { - LOCAL_APIC.init(active_table); -} - -pub unsafe fn init_ap() { - LOCAL_APIC.init_ap(); -} - -/// Local APIC -pub struct LocalApic { - pub address: usize, - pub x2: bool -} - -impl LocalApic { - unsafe fn init(&mut self, active_table: &mut ActivePageTable) { - self.address = (rdmsr(IA32_APIC_BASE) as usize & 0xFFFF0000) + ::KERNEL_OFFSET; - self.x2 = CpuId::new().get_feature_info().unwrap().has_x2apic(); - - if ! self.x2 { - let page = Page::containing_address(VirtualAddress::new(self.address)); - let frame = Frame::containing_address(PhysicalAddress::new(self.address - ::KERNEL_OFFSET)); - active_table.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE); - } - - self.init_ap(); - } - - unsafe fn init_ap(&mut self) { - if self.x2 { - wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10); - wrmsr(IA32_X2APIC_SIVR, 0x100); - } else { - self.write(0xF0, 0x100); - } - } - - unsafe fn read(&self, reg: u32) -> u32 { - volatile_load((self.address + reg as usize) as *const u32) - } - - unsafe fn write(&mut self, reg: u32, value: u32) { - volatile_store((self.address + reg as usize) as *mut u32, value); - } - - pub fn id(&self) -> u32 { - if self.x2 { - unsafe { rdmsr(IA32_X2APIC_APICID) as u32 } - } else { - unsafe { self.read(0x20) } - } - } - - pub fn version(&self) -> u32 { - if self.x2 { - unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 } - } else { - unsafe { self.read(0x30) } - } - } - - pub fn icr(&self) -> u64 { - if self.x2 { - unsafe { rdmsr(IA32_X2APIC_ICR) } - } else { - unsafe { - (self.read(0x310) as u64) << 32 | self.read(0x300) as u64 - } - } - } - - pub fn set_icr(&mut self, value: u64) { - if self.x2 { - unsafe { wrmsr(IA32_X2APIC_ICR, value); } - } else { - unsafe { - while self.read(0x300) & 1 << 12 == 1 << 12 {} - self.write(0x310, (value >> 32) as u32); - self.write(0x300, value as u32); - while self.read(0x300) & 1 << 12 == 1 << 12 {} - } - } - } - - pub fn ipi(&mut self, apic_id: usize) { - let mut icr = 0x4040; - if self.x2 { - icr |= (apic_id as u64) << 32; - } else { - icr |= (apic_id as u64) << 56; - } - self.set_icr(icr); - } - - pub unsafe fn eoi(&mut self) { - if self.x2 { - wrmsr(IA32_X2APIC_EOI, 0); - } else { - self.write(0xB0, 0); - } - } -} diff --git a/arch/x86_64/src/device/mod.rs b/arch/x86_64/src/device/mod.rs deleted file mode 100644 index d4d56e6..0000000 --- a/arch/x86_64/src/device/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -use paging::ActivePageTable; - -pub mod cpu; -pub mod local_apic; -pub mod rtc; -pub mod serial; - -pub unsafe fn init(active_table: &mut ActivePageTable){ - local_apic::init(active_table); - rtc::init(); - serial::init(); -} - -pub unsafe fn init_ap() { - local_apic::init_ap(); -} diff --git a/arch/x86_64/src/device/rtc.rs b/arch/x86_64/src/device/rtc.rs deleted file mode 100644 index ef6de05..0000000 --- a/arch/x86_64/src/device/rtc.rs +++ /dev/null @@ -1,109 +0,0 @@ -use io::{Io, Pio}; -use time; - -pub fn init() { - let mut rtc = Rtc::new(); - time::START.lock().0 = rtc.time(); -} - -fn cvt_bcd(value: usize) -> usize { - (value & 0xF) + ((value / 16) * 10) -} - -/// RTC -pub struct Rtc { - addr: Pio, - data: Pio, -} - -impl Rtc { - /// Create new empty RTC - pub fn new() -> Self { - return Rtc { - addr: Pio::::new(0x70), - data: Pio::::new(0x71), - }; - } - - /// Read - unsafe fn read(&mut self, reg: u8) -> u8 { - self.addr.write(reg); - return self.data.read(); - } - - /// Wait - unsafe fn wait(&mut self) { - while self.read(0xA) & 0x80 != 0x80 {} - while self.read(0xA) & 0x80 == 0x80 {} - } - - /// Get time - pub fn time(&mut self) -> u64 { - let mut second; - let mut minute; - let mut hour; - let mut day; - let mut month; - let mut year; - let register_b; - unsafe { - self.wait(); - second = self.read(0) as usize; - minute = self.read(2) as usize; - hour = self.read(4) as usize; - day = self.read(7) as usize; - month = self.read(8) as usize; - year = self.read(9) as usize; - register_b = self.read(0xB); - } - - if register_b & 4 != 4 { - second = cvt_bcd(second); - minute = cvt_bcd(minute); - hour = cvt_bcd(hour & 0x7F) | (hour & 0x80); - day = cvt_bcd(day); - month = cvt_bcd(month); - year = cvt_bcd(year); - } - - if register_b & 2 != 2 || hour & 0x80 == 0x80 { - hour = ((hour & 0x7F) + 12) % 24; - } - - // TODO: Century Register - year += 2000; - - // Unix time from clock - let mut secs: u64 = (year as u64 - 1970) * 31536000; - - let mut leap_days = (year as u64 - 1972) / 4 + 1; - if year % 4 == 0 { - if month <= 2 { - leap_days -= 1; - } - } - secs += leap_days * 86400; - - match month { - 2 => secs += 2678400, - 3 => secs += 5097600, - 4 => secs += 7776000, - 5 => secs += 10368000, - 6 => secs += 13046400, - 7 => secs += 15638400, - 8 => secs += 18316800, - 9 => secs += 20995200, - 10 => secs += 23587200, - 11 => secs += 26265600, - 12 => secs += 28857600, - _ => (), - } - - secs += (day as u64 - 1) * 86400; - secs += hour as u64 * 3600; - secs += minute as u64 * 60; - secs += second as u64; - - secs - } -} diff --git a/arch/x86_64/src/device/serial.rs b/arch/x86_64/src/device/serial.rs deleted file mode 100644 index 521c04e..0000000 --- a/arch/x86_64/src/device/serial.rs +++ /dev/null @@ -1,115 +0,0 @@ -use core::fmt::{self, Write}; -use spin::Mutex; - -use io::{Io, Pio, ReadOnly}; - -pub static COM1: Mutex = Mutex::new(SerialPort::new(0x3F8)); -pub static COM2: Mutex = Mutex::new(SerialPort::new(0x2F8)); - -pub unsafe fn init() { - COM1.lock().init(); - COM2.lock().init(); -} - -bitflags! { - /// Interrupt enable flags - flags IntEnFlags: u8 { - const RECEIVED = 1, - const SENT = 1 << 1, - const ERRORED = 1 << 2, - const STATUS_CHANGE = 1 << 3, - // 4 to 7 are unused - } -} - -bitflags! { - /// Line status flags - flags LineStsFlags: u8 { - const INPUT_FULL = 1, - // 1 to 4 unknown - const OUTPUT_EMPTY = 1 << 5, - // 6 and 7 unknown - } -} - -#[allow(dead_code)] -pub struct SerialPort { - /// Data register, read to receive, write to send - data: Pio, - /// Interrupt enable - int_en: Pio, - /// FIFO control - fifo_ctrl: Pio, - /// Line control - line_ctrl: Pio, - /// Modem control - modem_ctrl: Pio, - /// Line status - line_sts: ReadOnly>, - /// Modem status - modem_sts: ReadOnly>, -} - -impl SerialPort { - const fn new(base: u16) -> SerialPort { - SerialPort { - data: Pio::new(base), - int_en: Pio::new(base + 1), - fifo_ctrl: Pio::new(base + 2), - line_ctrl: Pio::new(base + 3), - modem_ctrl: Pio::new(base + 4), - line_sts: ReadOnly::new(Pio::new(base + 5)), - modem_sts: ReadOnly::new(Pio::new(base + 6)) - } - } - - fn line_sts(&self) -> LineStsFlags { - LineStsFlags::from_bits_truncate(self.line_sts.read()) - } - - fn write(&mut self, data: u8) { - while ! self.line_sts().contains(OUTPUT_EMPTY) {} - self.data.write(data) - } - - fn init(&mut self) { - //TODO: Cleanup - self.int_en.write(0x00); - self.line_ctrl.write(0x80); - self.data.write(0x03); - self.int_en.write(0x00); - self.line_ctrl.write(0x03); - self.fifo_ctrl.write(0xC7); - self.modem_ctrl.write(0x0B); - self.int_en.write(0x01); - } - - pub fn on_receive(&mut self) { - let data = self.data.read(); - - extern { - fn debug_input(byte: u8); - } - - unsafe { debug_input(data) }; - } -} - -impl Write for SerialPort { - fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - for byte in s.bytes() { - match byte { - 8 | 0x7F => { - self.write(8); - self.write(b' '); - self.write(8); - }, - _ => { - self.write(byte); - } - } - } - - Ok(()) - } -} diff --git a/arch/x86_64/src/externs.rs b/arch/x86_64/src/externs.rs deleted file mode 100644 index d92f8c4..0000000 --- a/arch/x86_64/src/externs.rs +++ /dev/null @@ -1,70 +0,0 @@ -/// Memcpy -/// -/// Copy N bytes of memory from one location to another. -#[no_mangle] -pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8, - n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *((dest as usize + i) as *mut u8) = *((src as usize + i) as *const u8); - i += 1; - } - - dest -} - -/// Memmove -/// -/// Copy N bytes of memory from src to dest. The memory areas may overlap. -#[no_mangle] -pub unsafe extern fn memmove(dest: *mut u8, src: *const u8, - n: usize) -> *mut u8 { - if src < dest as *const u8 { - let mut i = n; - while i != 0 { - i -= 1; - *((dest as usize + i) as *mut u8) = *((src as usize + i) as *const u8); - } - } else { - let mut i = 0; - while i < n { - *((dest as usize + i) as *mut u8) = *((src as usize + i) as *const u8); - i += 1; - } - } - - dest -} - -/// Memset -/// -/// Fill a block of memory with a specified value. -#[no_mangle] -pub unsafe extern fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *((dest as usize + i) as *mut u8) = c as u8; - i += 1; - } - - dest -} - -/// Memcmp -/// -/// Compare two blocks of memory. -#[no_mangle] -pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - - while i < n { - let a = *((s1 as usize + i) as *const u8); - let b = *((s2 as usize + i) as *const u8); - if a != b { - return a as i32 - b as i32 - } - i += 1; - } - - 0 -} diff --git a/arch/x86_64/src/gdt.rs b/arch/x86_64/src/gdt.rs deleted file mode 100644 index 96e1b99..0000000 --- a/arch/x86_64/src/gdt.rs +++ /dev/null @@ -1,177 +0,0 @@ -//! Global descriptor table - -use core::mem; -use x86::dtables::{self, DescriptorTablePointer}; -use x86::segmentation::{self, SegmentSelector}; -use x86::task::{self, TaskStateSegment}; - -pub const GDT_NULL: usize = 0; -pub const GDT_KERNEL_CODE: usize = 1; -pub const GDT_KERNEL_DATA: usize = 2; -pub const GDT_KERNEL_TLS: usize = 3; -pub const GDT_USER_CODE: usize = 4; -pub const GDT_USER_DATA: usize = 5; -pub const GDT_USER_TLS: usize = 6; -pub const GDT_TSS: usize = 7; -pub const GDT_TSS_HIGH: usize = 8; - -pub const GDT_A_PRESENT: u8 = 1 << 7; -pub const GDT_A_RING_0: u8 = 0 << 5; -pub const GDT_A_RING_1: u8 = 1 << 5; -pub const GDT_A_RING_2: u8 = 2 << 5; -pub const GDT_A_RING_3: u8 = 3 << 5; -pub const GDT_A_SYSTEM: u8 = 1 << 4; -pub const GDT_A_EXECUTABLE: u8 = 1 << 3; -pub const GDT_A_CONFORMING: u8 = 1 << 2; -pub const GDT_A_PRIVILEGE: u8 = 1 << 1; -pub const GDT_A_DIRTY: u8 = 1; - -pub const GDT_A_TSS_AVAIL: u8 = 0x9; -pub const GDT_A_TSS_BUSY: u8 = 0xB; - -pub const GDT_F_PAGE_SIZE: u8 = 1 << 7; -pub const GDT_F_PROTECTED_MODE: u8 = 1 << 6; -pub const GDT_F_LONG_MODE: u8 = 1 << 5; - -static mut INIT_GDTR: DescriptorTablePointer = DescriptorTablePointer { - limit: 0, - base: 0 -}; - -static mut INIT_GDT: [GdtEntry; 4] = [ - // Null - GdtEntry::new(0, 0, 0, 0), - // Kernel code - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_LONG_MODE), - // Kernel data - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE), - // Kernel TLS - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE) -]; - -#[thread_local] -pub static mut GDTR: DescriptorTablePointer = DescriptorTablePointer { - limit: 0, - base: 0 -}; - -#[thread_local] -pub static mut GDT: [GdtEntry; 9] = [ - // Null - GdtEntry::new(0, 0, 0, 0), - // Kernel code - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_LONG_MODE), - // Kernel data - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE), - // Kernel TLS - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE), - // User code - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_LONG_MODE), - // User data - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE), - // User TLS - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE), - // TSS - GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_TSS_AVAIL, 0), - // TSS must be 16 bytes long, twice the normal size - GdtEntry::new(0, 0, 0, 0), -]; - -#[thread_local] -pub static mut TSS: TaskStateSegment = TaskStateSegment { - reserved: 0, - rsp: [0; 3], - reserved2: 0, - ist: [0; 7], - reserved3: 0, - reserved4: 0, - iomap_base: 0xFFFF -}; - -/// Initialize GDT -pub unsafe fn init(tcb_offset: usize, stack_offset: usize) { - // Setup the initial GDT with TLS, so we can setup the TLS GDT (a little confusing) - // This means that each CPU will have its own GDT, but we only need to define it once as a thread local - INIT_GDTR.limit = (INIT_GDT.len() * mem::size_of::() - 1) as u16; - INIT_GDTR.base = INIT_GDT.as_ptr() as u64; - - // Set the TLS segment to the offset of the Thread Control Block - INIT_GDT[GDT_KERNEL_TLS].set_offset(tcb_offset as u32); - - // Load the initial GDT, before we have access to thread locals - dtables::lgdt(&INIT_GDTR); - - // Load the segment descriptors - segmentation::load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16)); - segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16)); - segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16)); - segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_TLS as u16)); - segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_DATA as u16)); - segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16)); - - // Now that we have access to thread locals, setup the AP's individual GDT - GDTR.limit = (GDT.len() * mem::size_of::() - 1) as u16; - GDTR.base = GDT.as_ptr() as u64; - - // Set the TLS segment to the offset of the Thread Control Block - GDT[GDT_KERNEL_TLS].set_offset(tcb_offset as u32); - - // Set the User TLS segment to the offset of the user TCB - GDT[GDT_USER_TLS].set_offset(::USER_TCB_OFFSET as u32); - - // We can now access our TSS, which is a thread local - GDT[GDT_TSS].set_offset(&TSS as *const _ as u32); - GDT[GDT_TSS].set_limit(mem::size_of::() as u32); - - // Set the stack pointer when coming back from userspace - TSS.rsp[0] = stack_offset as u64; - - // Load the new GDT, which is correctly located in thread local storage - dtables::lgdt(&GDTR); - - // Reload the segment descriptors - segmentation::load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16)); - segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16)); - segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16)); - segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_TLS as u16)); - segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_DATA as u16)); - segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16)); - - // Load the task register - task::load_ltr(SegmentSelector::new(GDT_TSS as u16)); -} - -#[derive(Copy, Clone, Debug)] -#[repr(packed)] -pub struct GdtEntry { - pub limitl: u16, - pub offsetl: u16, - pub offsetm: u8, - pub access: u8, - pub flags_limith: u8, - pub offseth: u8 -} - -impl GdtEntry { - pub const fn new(offset: u32, limit: u32, access: u8, flags: u8) -> Self { - GdtEntry { - limitl: limit as u16, - offsetl: offset as u16, - offsetm: (offset >> 16) as u8, - access: access, - flags_limith: flags & 0xF0 | ((limit >> 16) as u8) & 0x0F, - offseth: (offset >> 24) as u8 - } - } - - pub fn set_offset(&mut self, offset: u32) { - self.offsetl = offset as u16; - self.offsetm = (offset >> 16) as u8; - self.offseth = (offset >> 24) as u8; - } - - pub fn set_limit(&mut self, limit: u32) { - self.limitl = limit as u16; - self.flags_limith = self.flags_limith & 0xF0 | ((limit >> 16) as u8) & 0x0F; - } -} diff --git a/arch/x86_64/src/idt.rs b/arch/x86_64/src/idt.rs deleted file mode 100644 index 0d0d95e..0000000 --- a/arch/x86_64/src/idt.rs +++ /dev/null @@ -1,142 +0,0 @@ -use core::mem; -use x86::dtables::{self, DescriptorTablePointer}; - -use interrupt::*; - -pub static mut IDTR: DescriptorTablePointer = DescriptorTablePointer { - limit: 0, - base: 0 -}; - -pub static mut IDT: [IdtEntry; 256] = [IdtEntry::new(); 256]; - -pub unsafe fn init() { - IDTR.limit = (IDT.len() * mem::size_of::() - 1) as u16; - IDTR.base = IDT.as_ptr() as u64; - - // Set up exceptions - IDT[0].set_func(exception::divide_by_zero); - IDT[1].set_func(exception::debug); - IDT[2].set_func(exception::non_maskable); - IDT[3].set_func(exception::breakpoint); - IDT[4].set_func(exception::overflow); - IDT[5].set_func(exception::bound_range); - IDT[6].set_func(exception::invalid_opcode); - IDT[7].set_func(exception::device_not_available); - IDT[8].set_func(exception::double_fault); - // 9 no longer available - IDT[10].set_func(exception::invalid_tss); - IDT[11].set_func(exception::segment_not_present); - IDT[12].set_func(exception::stack_segment); - IDT[13].set_func(exception::protection); - IDT[14].set_func(exception::page); - // 15 reserved - IDT[16].set_func(exception::fpu); - IDT[17].set_func(exception::alignment_check); - IDT[18].set_func(exception::machine_check); - IDT[19].set_func(exception::simd); - IDT[20].set_func(exception::virtualization); - // 21 through 29 reserved - IDT[30].set_func(exception::security); - // 31 reserved - - // Set up IRQs - IDT[32].set_func(irq::pit); - IDT[33].set_func(irq::keyboard); - IDT[34].set_func(irq::cascade); - IDT[35].set_func(irq::com2); - IDT[36].set_func(irq::com1); - IDT[37].set_func(irq::lpt2); - IDT[38].set_func(irq::floppy); - IDT[39].set_func(irq::lpt1); - IDT[40].set_func(irq::rtc); - IDT[41].set_func(irq::pci1); - IDT[42].set_func(irq::pci2); - IDT[43].set_func(irq::pci3); - IDT[44].set_func(irq::mouse); - IDT[45].set_func(irq::fpu); - IDT[46].set_func(irq::ata1); - IDT[47].set_func(irq::ata2); - - // Set IPI handler (null) - IDT[0x40].set_func(ipi::ipi); - - // Set syscall function - IDT[0x80].set_func(syscall::syscall); - IDT[0x80].set_flags(IDT_PRESENT | IDT_RING_3 | IDT_INTERRUPT); - - dtables::lidt(&IDTR); -} - -bitflags! { - pub flags IdtFlags: u8 { - const IDT_PRESENT = 1 << 7, - const IDT_RING_0 = 0 << 5, - const IDT_RING_1 = 1 << 5, - const IDT_RING_2 = 2 << 5, - const IDT_RING_3 = 3 << 5, - const IDT_SS = 1 << 4, - const IDT_INTERRUPT = 0xE, - const IDT_TRAP = 0xF, - } -} - -#[repr(packed)] -pub struct IdtDescriptor { - size: u16, - offset: u64 -} - -impl IdtDescriptor { - pub fn set_slice(&mut self, slice: &'static [IdtEntry]) { - self.size = (slice.len() * mem::size_of::() - 1) as u16; - self.offset = slice.as_ptr() as u64; - } - - pub unsafe fn load(&self) { - asm!("lidt [rax]" : : "{rax}"(self as *const _ as usize) : : "intel", "volatile"); - } -} - -#[derive(Copy, Clone, Debug)] -#[repr(packed)] -pub struct IdtEntry { - offsetl: u16, - selector: u16, - zero: u8, - attribute: u8, - offsetm: u16, - offseth: u32, - zero2: u32 -} - -impl IdtEntry { - pub const fn new() -> IdtEntry { - IdtEntry { - offsetl: 0, - selector: 0, - zero: 0, - attribute: 0, - offsetm: 0, - offseth: 0, - zero2: 0 - } - } - - pub fn set_flags(&mut self, flags: IdtFlags) { - self.attribute = flags.bits; - } - - pub fn set_offset(&mut self, selector: u16, base: usize) { - self.selector = selector; - self.offsetl = base as u16; - self.offsetm = (base >> 16) as u16; - self.offseth = (base >> 32) as u32; - } - - // A function to set the offset more easily - pub fn set_func(&mut self, func: unsafe extern fn()) { - self.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT); - self.set_offset(8, func as usize); - } -} diff --git a/arch/x86_64/src/interrupt/exception.rs b/arch/x86_64/src/interrupt/exception.rs deleted file mode 100644 index 3822779..0000000 --- a/arch/x86_64/src/interrupt/exception.rs +++ /dev/null @@ -1,123 +0,0 @@ -use interrupt::stack_trace; -use syscall::flag::*; - -extern { - fn ksignal(signal: usize); -} - -interrupt_stack!(divide_by_zero, stack, { - println!("Divide by zero fault at {:>02X}:{:>016X}", stack.cs, stack.rip); - stack_trace(); - ksignal(SIGFPE); -}); - -interrupt_stack!(debug, stack, { - println!("Debug trap at {:>02X}:{:>016X}", stack.cs, stack.rip); - ksignal(SIGTRAP); -}); - -interrupt_stack!(non_maskable, stack, { - println!("Non-maskable interrupt at {:>02X}:{:>016X}", stack.cs, stack.rip); -}); - -interrupt_stack!(breakpoint, stack, { - println!("Breakpoint trap at {:>02X}:{:>016X}", stack.cs, stack.rip); - ksignal(SIGTRAP); -}); - -interrupt_stack!(overflow, stack, { - println!("Overflow trap at {:>02X}:{:>016X}", stack.cs, stack.rip); - ksignal(SIGFPE); -}); - -interrupt_stack!(bound_range, stack, { - println!("Bound range exceeded fault at {:>02X}:{:>016X}", stack.cs, stack.rip); - stack_trace(); - ksignal(SIGSEGV); -}); - -interrupt_stack!(invalid_opcode, stack, { - println!("Invalid opcode fault at {:>02X}:{:>016X}", stack.cs, stack.rip); - stack_trace(); - ksignal(SIGILL); -}); - -interrupt_stack!(device_not_available, stack, { - println!("Device not available fault at {:>02X}:{:>016X}", stack.cs, stack.rip); - stack_trace(); - ksignal(SIGILL); -}); - -interrupt_error!(double_fault, stack, { - println!("Double fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); - stack_trace(); - ksignal(SIGSEGV); -}); - -interrupt_error!(invalid_tss, stack, { - println!("Invalid TSS fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); - stack_trace(); - ksignal(SIGSEGV); -}); - -interrupt_error!(segment_not_present, stack, { - println!("Segment not present fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); - stack_trace(); - ksignal(SIGSEGV); -}); - -interrupt_error!(stack_segment, stack, { - println!("Stack segment fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); - stack_trace(); - ksignal(SIGSEGV); -}); - -interrupt_error!(protection, stack, { - println!("Protection fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); - stack_trace(); - ksignal(SIGSEGV); -}); - -interrupt_error!(page, stack, { - let cr2: usize; - asm!("mov rax, cr2" : "={rax}"(cr2) : : : "intel", "volatile"); - println!("Page fault: {:>02X}:{:>016X} at {:>02X}:{:>016X}", stack.code, cr2, stack.cs, stack.rip); - stack_trace(); - ksignal(SIGSEGV); -}); - -interrupt_stack!(fpu, stack, { - println!("FPU floating point fault at {:>02X}:{:>016X}", stack.cs, stack.rip); - stack_trace(); - ksignal(SIGFPE); -}); - -interrupt_error!(alignment_check, stack, { - println!("Alignment check fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); - stack_trace(); - ksignal(SIGBUS); -}); - -interrupt_stack!(machine_check, stack, { - println!("Machine check fault at {:>02X}:{:>016X}", stack.cs, stack.rip); - stack_trace(); - ksignal(SIGBUS); -}); - -interrupt_stack!(simd, stack, { - println!("SIMD floating point fault at {:>02X}:{:>016X}", stack.cs, stack.rip); - stack_trace(); - ksignal(SIGFPE); -}); - -interrupt_stack!(virtualization, stack, { - println!("Virtualization fault at {:>02X}:{:>016X}", stack.cs, stack.rip); - stack_trace(); - ksignal(SIGBUS); -}); - -interrupt_error!(security, stack, { - println!("Security exception: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip); - stack_trace(); - ksignal(SIGBUS); -}); diff --git a/arch/x86_64/src/interrupt/ipi.rs b/arch/x86_64/src/interrupt/ipi.rs deleted file mode 100644 index 325d9d8..0000000 --- a/arch/x86_64/src/interrupt/ipi.rs +++ /dev/null @@ -1,5 +0,0 @@ -use device::local_apic::LOCAL_APIC; - -interrupt!(ipi, { - LOCAL_APIC.eoi(); -}); diff --git a/arch/x86_64/src/interrupt/irq.rs b/arch/x86_64/src/interrupt/irq.rs deleted file mode 100644 index c6a8733..0000000 --- a/arch/x86_64/src/interrupt/irq.rs +++ /dev/null @@ -1,115 +0,0 @@ -use x86::io; - -use device::serial::{COM1, COM2}; -use time; - -extern { - fn irq_trigger(irq: u8); -} - -#[inline(always)] -unsafe fn master_ack() { - io::outb(0x20, 0x20); -} - -#[inline(always)] -unsafe fn slave_ack() { - io::outb(0xA0, 0x20); - master_ack(); -} - -pub unsafe fn acknowledge(irq: usize) { - if irq >= 8 { - slave_ack(); - } else { - master_ack(); - } -} - -interrupt!(pit, { - // Saves CPU time by not sending IRQ event irq_trigger(0); - - { - const PIT_RATE: u64 = 2250286; - - let mut offset = time::OFFSET.lock(); - let sum = offset.1 + PIT_RATE; - offset.1 = sum % 1000000000; - offset.0 += sum / 1000000000; - } - - master_ack(); -}); - -interrupt!(keyboard, { - irq_trigger(1); -}); - -interrupt!(cascade, { - irq_trigger(2); - master_ack(); -}); - -interrupt!(com2, { - irq_trigger(3); - COM2.lock().on_receive(); - master_ack(); -}); - -interrupt!(com1, { - irq_trigger(4); - COM1.lock().on_receive(); - master_ack(); -}); - -interrupt!(lpt2, { - irq_trigger(5); - master_ack(); -}); - -interrupt!(floppy, { - irq_trigger(6); - master_ack(); -}); - -interrupt!(lpt1, { - irq_trigger(7); - master_ack(); -}); - -interrupt!(rtc, { - irq_trigger(8); - slave_ack(); -}); - -interrupt!(pci1, { - irq_trigger(9); - slave_ack(); -}); - -interrupt!(pci2, { - irq_trigger(10); -}); - -interrupt!(pci3, { - irq_trigger(11); -}); - -interrupt!(mouse, { - irq_trigger(12); -}); - -interrupt!(fpu, { - irq_trigger(13); - slave_ack(); -}); - -interrupt!(ata1, { - irq_trigger(14); - slave_ack(); -}); - -interrupt!(ata2, { - irq_trigger(15); - slave_ack(); -}); diff --git a/arch/x86_64/src/interrupt/mod.rs b/arch/x86_64/src/interrupt/mod.rs deleted file mode 100644 index 3cc5caa..0000000 --- a/arch/x86_64/src/interrupt/mod.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Interrupt instructions - -use core::mem; - -use paging::{ActivePageTable, VirtualAddress}; - -pub mod exception; -pub mod ipi; -pub mod irq; -pub mod syscall; - -/// Clear interrupts -#[inline(always)] -pub unsafe fn disable() { - asm!("cli" : : : : "intel", "volatile"); -} - -/// Set interrupts -#[inline(always)] -pub unsafe fn enable() { - asm!("sti" : : : : "intel", "volatile"); -} - -/// Set interrupts and halt -/// This will atomically wait for the next interrupt -/// Performing enable followed by halt is not guaranteed to be atomic, use this instead! -#[inline(always)] -pub unsafe fn enable_and_halt() { - asm!("sti - hlt" - : : : : "intel", "volatile"); -} - -/// Set interrupts and nop -/// This will enable interrupts and allow the IF flag to be processed -/// Simply enabling interrupts does not gurantee that they will trigger, use this instead! -#[inline(always)] -pub unsafe fn enable_and_nop() { - asm!("sti - nop" - : : : : "intel", "volatile"); -} - -/// Halt instruction -#[inline(always)] -pub unsafe fn halt() { - asm!("hlt" : : : : "intel", "volatile"); -} - -/// Pause instruction -/// Safe because it is similar to a NOP, and has no memory effects -#[inline(always)] -pub fn pause() { - unsafe { asm!("pause" : : : : "intel", "volatile"); } -} - -/// Get a stack trace -//TODO: Check for stack being mapped before dereferencing -#[inline(never)] -pub unsafe fn stack_trace() { - let mut rbp: usize; - asm!("" : "={rbp}"(rbp) : : : "intel", "volatile"); - - println!("TRACE: {:>016X}", rbp); - //Maximum 64 frames - let active_table = ActivePageTable::new(); - for _frame in 0..64 { - if let Some(rip_rbp) = rbp.checked_add(mem::size_of::()) { - if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rip_rbp)).is_some() { - let rip = *(rip_rbp as *const usize); - if rip == 0 { - println!(" {:>016X}: EMPTY RETURN", rbp); - break; - } - println!(" {:>016X}: {:>016X}", rbp, rip); - rbp = *(rbp as *const usize); - } else { - println!(" {:>016X}: GUARD PAGE", rbp); - break; - } - } else { - println!(" {:>016X}: RBP OVERFLOW", rbp); - } - } -} diff --git a/arch/x86_64/src/interrupt/syscall.rs b/arch/x86_64/src/interrupt/syscall.rs deleted file mode 100644 index d1527da..0000000 --- a/arch/x86_64/src/interrupt/syscall.rs +++ /dev/null @@ -1,61 +0,0 @@ -#[naked] -pub unsafe extern fn syscall() { - #[inline(never)] - unsafe fn inner() { - extern { - fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize; - } - - let mut a; - { - let b; - let c; - let d; - let e; - let f; - let stack; - asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f), "={rbp}"(stack) - : : : "intel", "volatile"); - - a = syscall(a, b, c, d, e, f, stack); - } - - asm!("" : : "{rax}"(a) : : "intel", "volatile"); - } - - // Push scratch registers, minus rax for the return value - asm!("push rcx - push rdx - push rdi - push rsi - push r8 - push r9 - push r10 - push r11 - push fs - mov r11, 0x18 - mov fs, r11" - : : : : "intel", "volatile"); - - inner(); - - // Interrupt return - asm!("pop fs - pop r11 - pop r10 - pop r9 - pop r8 - pop rsi - pop rdi - pop rdx - pop rcx - iretq" - : : : : "intel", "volatile"); -} - -#[naked] -pub unsafe extern fn clone_ret() -> usize { - asm!("pop rbp" - : : : : "intel", "volatile"); - 0 -} diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs deleted file mode 100644 index dc30d69..0000000 --- a/arch/x86_64/src/lib.rs +++ /dev/null @@ -1,323 +0,0 @@ -//! Architecture support for x86_64 - -#![feature(asm)] -#![feature(concat_idents)] -#![feature(const_fn)] -#![feature(core_intrinsics)] -#![feature(drop_types_in_const)] -#![feature(lang_items)] -#![feature(naked_functions)] -#![feature(thread_local)] -#![feature(unique)] -#![no_std] - -extern crate hole_list_allocator as allocator; - -#[macro_use] -extern crate bitflags; -extern crate io; -extern crate spin; -extern crate syscall; -pub extern crate x86; - -// Because the memory map is so important to not be aliased, it is defined here, in one place -// The lower 256 PML4 entries are reserved for userspace -// Each PML4 entry references up to 512 GB of memory -// The top (511) PML4 is reserved for recursive mapping -// The second from the top (510) PML4 is reserved for the kernel - /// The size of a single PML4 - pub const PML4_SIZE: usize = 0x0000_0080_0000_0000; - - /// Offset of recursive paging - pub const RECURSIVE_PAGE_OFFSET: usize = (-(PML4_SIZE as isize)) as usize; - - /// Offset of kernel - pub const KERNEL_OFFSET: usize = RECURSIVE_PAGE_OFFSET - PML4_SIZE; - - /// Offset to kernel heap - pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET + PML4_SIZE/2; - /// Size of kernel heap - pub const KERNEL_HEAP_SIZE: usize = 256 * 1024 * 1024; // 256 MB - - /// Offset to kernel percpu variables - //TODO: Use 64-bit fs offset to enable this pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE; - pub const KERNEL_PERCPU_OFFSET: usize = 0xC000_0000; - /// Size of kernel percpu variables - pub const KERNEL_PERCPU_SIZE: usize = 64 * 1024; // 64 KB - - /// Offset to user image - pub const USER_OFFSET: usize = 0; - - /// Offset to user TCB - pub const USER_TCB_OFFSET: usize = 0xB000_0000; - - /// Offset to user arguments - pub const USER_ARG_OFFSET: usize = USER_OFFSET + PML4_SIZE/2; - - /// Offset to user heap - pub const USER_HEAP_OFFSET: usize = USER_OFFSET + PML4_SIZE; - - /// Offset to user grants - pub const USER_GRANT_OFFSET: usize = USER_HEAP_OFFSET + PML4_SIZE; - - /// Offset to user stack - pub const USER_STACK_OFFSET: usize = USER_GRANT_OFFSET + PML4_SIZE; - /// Size of user stack - pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB - - /// Offset to user TLS - pub const USER_TLS_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; - - /// Offset to user temporary image (used when cloning) - pub const USER_TMP_OFFSET: usize = USER_TLS_OFFSET + PML4_SIZE; - - /// Offset to user temporary heap (used when cloning) - pub const USER_TMP_HEAP_OFFSET: usize = USER_TMP_OFFSET + PML4_SIZE; - - /// Offset to user temporary page for grants - pub const USER_TMP_GRANT_OFFSET: usize = USER_TMP_HEAP_OFFSET + PML4_SIZE; - - /// Offset to user temporary stack (used when cloning) - pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_GRANT_OFFSET + PML4_SIZE; - - /// Offset to user temporary tls (used when cloning) - pub const USER_TMP_TLS_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE; - - -/// Print to console -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ({ - use core::fmt::Write; - let _ = write!($crate::console::CONSOLE.lock(), $($arg)*); - }); -} - -/// Print with new line to console -#[macro_export] -macro_rules! println { - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -} - -/// Create an interrupt function that can safely run rust code -#[macro_export] -macro_rules! interrupt { - ($name:ident, $func:block) => { - #[naked] - pub unsafe extern fn $name () { - #[inline(never)] - unsafe fn inner() { - $func - } - - // Push scratch registers - asm!("push rax - push rcx - push rdx - push rdi - push rsi - push r8 - push r9 - push r10 - push r11 - push fs - mov rax, 0x18 - mov fs, ax" - : : : : "intel", "volatile"); - - // Call inner rust function - inner(); - - // Pop scratch registers and return - asm!("pop fs - pop r11 - pop r10 - pop r9 - pop r8 - pop rsi - pop rdi - pop rdx - pop rcx - pop rax - iretq" - : : : : "intel", "volatile"); - } - }; -} - -#[repr(packed)] -pub struct InterruptStack { - fs: usize, - r11: usize, - r10: usize, - r9: usize, - r8: usize, - rsi: usize, - rdi: usize, - rdx: usize, - rcx: usize, - rax: usize, - rip: usize, - cs: usize, - rflags: usize, -} - -#[macro_export] -macro_rules! interrupt_stack { - ($name:ident, $stack: ident, $func:block) => { - #[naked] - pub unsafe extern fn $name () { - #[inline(never)] - unsafe fn inner($stack: &$crate::InterruptStack) { - $func - } - - // Push scratch registers - asm!("push rax - push rcx - push rdx - push rdi - push rsi - push r8 - push r9 - push r10 - push r11 - push fs - mov rax, 0x18 - mov fs, ax" - : : : : "intel", "volatile"); - - // Get reference to stack variables - let rsp: usize; - asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); - - // Call inner rust function - inner(&*(rsp as *const $crate::InterruptStack)); - - // Pop scratch registers and return - asm!("pop fs - pop r11 - pop r10 - pop r9 - pop r8 - pop rsi - pop rdi - pop rdx - pop rcx - pop rax - iretq" - : : : : "intel", "volatile"); - } - }; -} - -#[repr(packed)] -pub struct InterruptErrorStack { - fs: usize, - r11: usize, - r10: usize, - r9: usize, - r8: usize, - rsi: usize, - rdi: usize, - rdx: usize, - rcx: usize, - rax: usize, - code: usize, - rip: usize, - cs: usize, - rflags: usize, -} - -#[macro_export] -macro_rules! interrupt_error { - ($name:ident, $stack:ident, $func:block) => { - #[naked] - pub unsafe extern fn $name () { - #[inline(never)] - unsafe fn inner($stack: &$crate::InterruptErrorStack) { - $func - } - - // Push scratch registers - asm!("push rax - push rcx - push rdx - push rdi - push rsi - push r8 - push r9 - push r10 - push r11 - push fs - mov rax, 0x18 - mov fs, ax" - : : : : "intel", "volatile"); - - // Get reference to stack variables - let rsp: usize; - asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); - - // Call inner rust function - inner(&*(rsp as *const $crate::InterruptErrorStack)); - - // Pop scratch registers, error code, and return - asm!("pop fs - pop r11 - pop r10 - pop r9 - pop r8 - pop rsi - pop rdi - pop rdx - pop rcx - pop rax - add rsp, 8 - iretq" - : : : : "intel", "volatile"); - } - }; -} - -/// ACPI table parsing -pub mod acpi; - -/// Console handling -pub mod console; - -/// Context switching -pub mod context; - -/// Devices -pub mod device; - -/// Memcpy, memmove, etc. -pub mod externs; - -/// Global descriptor table -pub mod gdt; - -/// Interrupt descriptor table -pub mod idt; - -/// Interrupt instructions -pub mod interrupt; - -/// Memory management -pub mod memory; - -/// Paging -pub mod paging; - -/// Panic -pub mod panic; - -/// Initialization and start function -pub mod start; - -/// Shutdown function -pub mod stop; - -/// Time -pub mod time; diff --git a/arch/x86_64/src/linker.ld b/arch/x86_64/src/linker.ld deleted file mode 100644 index 546adaa..0000000 --- a/arch/x86_64/src/linker.ld +++ /dev/null @@ -1,63 +0,0 @@ -ENTRY(kstart) -OUTPUT_FORMAT(elf64-x86-64) - -KERNEL_OFFSET = 0xffffff0000100000; -/* KERNEL_OFFSET = 0x100000; */ - -SECTIONS { - . = KERNEL_OFFSET; - - . += SIZEOF_HEADERS; - . = ALIGN(4096); - - .text : AT(ADDR(.text) - KERNEL_OFFSET) { - __text_start = .; - *(.text*) - . = ALIGN(4096); - __text_end = .; - } - - .rodata : AT(ADDR(.rodata) - KERNEL_OFFSET) { - __rodata_start = .; - *(.rodata*) - . = ALIGN(4096); - __rodata_end = .; - } - - .data : AT(ADDR(.data) - KERNEL_OFFSET) { - __data_start = .; - *(.data*) - . = ALIGN(4096); - __data_end = .; - } - - .tdata : AT(ADDR(.tdata) - KERNEL_OFFSET) { - __tdata_start = .; - *(.tdata*) - . = ALIGN(4096); - __tdata_end = .; - __tbss_start = .; - *(.tbss*) - . += 8; - . = ALIGN(4096); - __tbss_end = .; - } - - .bss : AT(ADDR(.bss) - KERNEL_OFFSET) { - __bss_start = .; - *(.bss*) - . = ALIGN(4096); - __bss_end = .; - } - - __end = .; - - /DISCARD/ : { - *(.comment*) - *(.debug*) - *(.eh_frame*) - *(.gcc_except_table*) - *(.note*) - *(.rel.eh_frame*) - } -} diff --git a/arch/x86_64/src/memory/area_frame_allocator.rs b/arch/x86_64/src/memory/area_frame_allocator.rs deleted file mode 100644 index e25f22a..0000000 --- a/arch/x86_64/src/memory/area_frame_allocator.rs +++ /dev/null @@ -1,127 +0,0 @@ -//! # Area frame allocator -//! Some code was borrowed from [Phil Opp's Blog](http://os.phil-opp.com/allocating-frames.html) - -use paging::PhysicalAddress; - -use super::{Frame, FrameAllocator, MemoryArea, MemoryAreaIter}; - - -pub struct AreaFrameAllocator { - next_free_frame: Frame, - current_area: Option<&'static MemoryArea>, - areas: MemoryAreaIter, - kernel_start: Frame, - kernel_end: Frame -} - -impl AreaFrameAllocator { - pub fn new(kernel_start: usize, kernel_end: usize, memory_areas: MemoryAreaIter) -> AreaFrameAllocator { - let mut allocator = AreaFrameAllocator { - next_free_frame: Frame::containing_address(PhysicalAddress::new(0)), - current_area: None, - areas: memory_areas, - kernel_start: Frame::containing_address(PhysicalAddress::new(kernel_start)), - kernel_end: Frame::containing_address(PhysicalAddress::new(kernel_end)) - }; - allocator.choose_next_area(); - allocator - } - - fn choose_next_area(&mut self) { - self.current_area = self.areas.clone().filter(|area| { - let address = area.base_addr + area.length - 1; - Frame::containing_address(PhysicalAddress::new(address as usize)) >= self.next_free_frame - }).min_by_key(|area| area.base_addr); - - if let Some(area) = self.current_area { - let start_frame = Frame::containing_address(PhysicalAddress::new(area.base_addr as usize)); - if self.next_free_frame < start_frame { - self.next_free_frame = start_frame; - } - } - } -} - -impl FrameAllocator for AreaFrameAllocator { - fn free_frames(&self) -> usize { - let mut count = 0; - - for area in self.areas.clone() { - let start_frame = Frame::containing_address(PhysicalAddress::new(area.base_addr as usize)); - let end_frame = Frame::containing_address(PhysicalAddress::new((area.base_addr + area.length - 1) as usize)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - if frame >= self.kernel_start && frame <= self.kernel_end { - // Inside of kernel range - } else if frame >= self.next_free_frame { - // Frame is in free range - count += 1; - } else { - // Inside of used range - } - } - } - - count - } - - fn used_frames(&self) -> usize { - let mut count = 0; - - for area in self.areas.clone() { - let start_frame = Frame::containing_address(PhysicalAddress::new(area.base_addr as usize)); - let end_frame = Frame::containing_address(PhysicalAddress::new((area.base_addr + area.length - 1) as usize)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - if frame >= self.kernel_start && frame <= self.kernel_end { - // Inside of kernel range - count += 1 - } else if frame >= self.next_free_frame { - // Frame is in free range - } else { - count += 1; - } - } - } - - count - } - - fn allocate_frames(&mut self, count: usize) -> Option { - if count == 0 { - None - } else if let Some(area) = self.current_area { - // "Clone" the frame to return it if it's free. Frame doesn't - // implement Clone, but we can construct an identical frame. - let start_frame = Frame{ number: self.next_free_frame.number }; - let end_frame = Frame { number: self.next_free_frame.number + (count - 1) }; - - // the last frame of the current area - let current_area_last_frame = { - let address = area.base_addr + area.length - 1; - Frame::containing_address(PhysicalAddress::new(address as usize)) - }; - - if end_frame > current_area_last_frame { - // all frames of current area are used, switch to next area - self.choose_next_area(); - } else if (start_frame >= self.kernel_start && start_frame <= self.kernel_end) - || (end_frame >= self.kernel_start && end_frame <= self.kernel_end) { - // `frame` is used by the kernel - self.next_free_frame = Frame { - number: self.kernel_end.number + 1 - }; - } else { - // frame is unused, increment `next_free_frame` and return it - self.next_free_frame.number += count; - return Some(start_frame); - } - // `frame` was not valid, try it again with the updated `next_free_frame` - self.allocate_frames(count) - } else { - None // no free frames left - } - } - - fn deallocate_frames(&mut self, frame: Frame, count: usize) { - //panic!("AreaFrameAllocator::deallocate_frame: not supported: {:?}", frame); - } -} diff --git a/arch/x86_64/src/memory/mod.rs b/arch/x86_64/src/memory/mod.rs deleted file mode 100644 index 17b2200..0000000 --- a/arch/x86_64/src/memory/mod.rs +++ /dev/null @@ -1,189 +0,0 @@ -//! # Memory management -//! Some code was borrowed from [Phil Opp's Blog](http://os.phil-opp.com/allocating-frames.html) - -pub use paging::{PAGE_SIZE, PhysicalAddress}; - -use self::area_frame_allocator::AreaFrameAllocator; - -use spin::Mutex; - -pub mod area_frame_allocator; - -/// The current memory map. It's size is maxed out to 512 entries, due to it being -/// from 0x500 to 0x5000 (800 is the absolute total) -static mut MEMORY_MAP: [MemoryArea; 512] = [MemoryArea { base_addr: 0, length: 0, _type: 0, acpi: 0 }; 512]; - -/// Memory does not exist -pub const MEMORY_AREA_NULL: u32 = 0; - -/// Memory is free to use -pub const MEMORY_AREA_FREE: u32 = 1; - -/// Memory is reserved -pub const MEMORY_AREA_RESERVED: u32 = 2; - -/// Memory is used by ACPI, and can be reclaimed -pub const MEMORY_AREA_ACPI: u32 = 3; - -/// A memory map area -#[derive(Copy, Clone, Debug, Default)] -#[repr(packed)] -pub struct MemoryArea { - pub base_addr: u64, - pub length: u64, - pub _type: u32, - pub acpi: u32 -} - -#[derive(Clone)] -pub struct MemoryAreaIter { - _type: u32, - i: usize -} - -impl MemoryAreaIter { - fn new(_type: u32) -> Self { - MemoryAreaIter { - _type: _type, - i: 0 - } - } -} - -impl Iterator for MemoryAreaIter { - type Item = &'static MemoryArea; - fn next(&mut self) -> Option { - while self.i < unsafe { MEMORY_MAP.len() } { - let entry = unsafe { &MEMORY_MAP[self.i] }; - self.i += 1; - if entry._type == self._type { - return Some(entry); - } - } - None - } -} - -static ALLOCATOR: Mutex> = Mutex::new(None); - -/// Init memory module -/// Must be called once, and only once, -pub unsafe fn init(kernel_start: usize, kernel_end: usize) { - // Copy memory map from bootloader location - for (i, mut entry) in MEMORY_MAP.iter_mut().enumerate() { - *entry = *(0x500 as *const MemoryArea).offset(i as isize); - if entry._type != MEMORY_AREA_NULL { - println!("{:?}", entry); - } - } - - *ALLOCATOR.lock() = Some(AreaFrameAllocator::new(kernel_start, kernel_end, MemoryAreaIter::new(MEMORY_AREA_FREE))); -} - -/// Allocate a frame -pub fn allocate_frame() -> Option { - allocate_frames(1) -} - -/// Deallocate a frame -pub fn deallocate_frame(frame: Frame) { - deallocate_frames(frame, 1) -} - -/// Get the number of frames available -pub fn free_frames() -> usize { - if let Some(ref allocator) = *ALLOCATOR.lock() { - allocator.free_frames() - } else { - panic!("frame allocator not initialized"); - } -} - -/// Get the number of frames used -pub fn used_frames() -> usize { - if let Some(ref allocator) = *ALLOCATOR.lock() { - allocator.used_frames() - } else { - panic!("frame allocator not initialized"); - } -} - -/// Allocate a range of frames -pub fn allocate_frames(count: usize) -> Option { - if let Some(ref mut allocator) = *ALLOCATOR.lock() { - allocator.allocate_frames(count) - } else { - panic!("frame allocator not initialized"); - } -} - -/// Deallocate a range of frames frame -pub fn deallocate_frames(frame: Frame, count: usize) { - if let Some(ref mut allocator) = *ALLOCATOR.lock() { - allocator.deallocate_frames(frame, count) - } else { - panic!("frame allocator not initialized"); - } -} - -/// A frame, allocated by the frame allocator. -/// Do not add more derives, or make anything `pub`! -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Frame { - number: usize -} - -impl Frame { - /// Get the address of this frame - pub fn start_address(&self) -> PhysicalAddress { - PhysicalAddress::new(self.number * PAGE_SIZE) - } - - //TODO: Set private - pub fn clone(&self) -> Frame { - Frame { - number: self.number - } - } - - /// Create a frame containing `address` - pub fn containing_address(address: PhysicalAddress) -> Frame { - Frame { - number: address.get() / PAGE_SIZE - } - } - - //TODO: Set private - pub fn range_inclusive(start: Frame, end: Frame) -> FrameIter { - FrameIter { - start: start, - end: end, - } - } -} - -pub struct FrameIter { - start: Frame, - end: Frame, -} - -impl Iterator for FrameIter { - type Item = Frame; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let frame = self.start.clone(); - self.start.number += 1; - Some(frame) - } else { - None - } - } -} - -pub trait FrameAllocator { - fn free_frames(&self) -> usize; - fn used_frames(&self) -> usize; - fn allocate_frames(&mut self, size: usize) -> Option; - fn deallocate_frames(&mut self, frame: Frame, size: usize); -} diff --git a/arch/x86_64/src/paging/entry.rs b/arch/x86_64/src/paging/entry.rs deleted file mode 100644 index aecf647..0000000 --- a/arch/x86_64/src/paging/entry.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! # Page table entry -//! Some code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html) - -use memory::Frame; - -use super::PhysicalAddress; - -/// A page table entry -pub struct Entry(u64); - -bitflags! { - pub flags EntryFlags: u64 { - const PRESENT = 1 << 0, - const WRITABLE = 1 << 1, - const USER_ACCESSIBLE = 1 << 2, - const WRITE_THROUGH = 1 << 3, - const NO_CACHE = 1 << 4, - const ACCESSED = 1 << 5, - const DIRTY = 1 << 6, - const HUGE_PAGE = 1 << 7, - const GLOBAL = 1 << 8, - const NO_EXECUTE = 1 << 63, - } -} - -pub const ADDRESS_MASK: usize = 0x000f_ffff_ffff_f000; - -impl Entry { - /// Is the entry unused? - pub fn is_unused(&self) -> bool { - self.0 == 0 - } - - /// Make the entry unused - pub fn set_unused(&mut self) { - self.0 = 0; - } - - /// Get the address this page references - pub fn address(&self) -> PhysicalAddress { - PhysicalAddress::new(self.0 as usize & ADDRESS_MASK) - } - - /// Get the current entry flags - pub fn flags(&self) -> EntryFlags { - EntryFlags::from_bits_truncate(self.0) - } - - /// Get the associated frame, if available - pub fn pointed_frame(&self) -> Option { - if self.flags().contains(PRESENT) { - Some(Frame::containing_address(self.address())) - } else { - None - } - } - - pub fn set(&mut self, frame: Frame, flags: EntryFlags) { - debug_assert!(frame.start_address().get() & !ADDRESS_MASK == 0); - self.0 = (frame.start_address().get() as u64) | flags.bits(); - } -} diff --git a/arch/x86_64/src/paging/mapper.rs b/arch/x86_64/src/paging/mapper.rs deleted file mode 100644 index cb4eccd..0000000 --- a/arch/x86_64/src/paging/mapper.rs +++ /dev/null @@ -1,109 +0,0 @@ -use core::ptr::Unique; - -use memory::{allocate_frame, deallocate_frame, Frame}; - -use super::{Page, PAGE_SIZE, PhysicalAddress, VirtualAddress}; -use super::entry::{self, EntryFlags}; -use super::table::{self, Table, Level4}; - -pub struct Mapper { - p4: Unique>, -} - -impl Mapper { - /// Create a new page table - pub unsafe fn new() -> Mapper { - Mapper { - p4: Unique::new(table::P4), - } - } - - pub fn p4(&self) -> &Table { - unsafe { self.p4.get() } - } - - pub fn p4_mut(&mut self) -> &mut Table { - unsafe { self.p4.get_mut() } - } - - /// Map a page to a frame - pub fn map_to(&mut self, page: Page, frame: Frame, flags: EntryFlags) { - let mut p3 = self.p4_mut().next_table_create(page.p4_index()); - let mut p2 = p3.next_table_create(page.p3_index()); - let mut p1 = p2.next_table_create(page.p2_index()); - - assert!(p1[page.p1_index()].is_unused(), - "{:X}: Set to {:X}: {:?}, requesting {:X}: {:?}", - page.start_address().get(), - p1[page.p1_index()].address().get(), p1[page.p1_index()].flags(), - frame.start_address().get(), flags); - p1[page.p1_index()].set(frame, flags | entry::PRESENT); - } - - /// Map a page to the next free frame - pub fn map(&mut self, page: Page, flags: EntryFlags) { - let frame = allocate_frame().expect("out of frames"); - self.map_to(page, frame, flags) - } - - /// Update flags for a page - pub fn remap(&mut self, page: Page, flags: EntryFlags) { - let mut p3 = self.p4_mut().next_table_mut(page.p4_index()).expect("failed to remap: no p3"); - let mut p2 = p3.next_table_mut(page.p3_index()).expect("failed to remap: no p2"); - let mut p1 = p2.next_table_mut(page.p2_index()).expect("failed to remap: no p1"); - let frame = p1[page.p1_index()].pointed_frame().expect("failed to remap: not mapped"); - p1[page.p1_index()].set(frame, flags | entry::PRESENT); - } - - /// Identity map a frame - pub fn identity_map(&mut self, frame: Frame, flags: EntryFlags) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get())); - self.map_to(page, frame, flags) - } - - /// Unmap a page - pub fn unmap(&mut self, page: Page) { - let p1 = self.p4_mut() - .next_table_mut(page.p4_index()) - .and_then(|p3| p3.next_table_mut(page.p3_index())) - .and_then(|p2| p2.next_table_mut(page.p2_index())) - .expect("mapping code does not support huge pages"); - let frame = p1[page.p1_index()].pointed_frame().unwrap(); - p1[page.p1_index()].set_unused(); - // TODO free p(1,2,3) table if empty - deallocate_frame(frame); - } - - /// Unmap a page, return frame without free - pub fn unmap_return(&mut self, page: Page) -> Frame { - let p1 = self.p4_mut() - .next_table_mut(page.p4_index()) - .and_then(|p3| p3.next_table_mut(page.p3_index())) - .and_then(|p2| p2.next_table_mut(page.p2_index())) - .expect("mapping code does not support huge pages"); - let frame = p1[page.p1_index()].pointed_frame().unwrap(); - p1[page.p1_index()].set_unused(); - frame - } - - pub fn translate_page(&self, page: Page) -> Option { - self.p4().next_table(page.p4_index()) - .and_then(|p3| p3.next_table(page.p3_index())) - .and_then(|p2| p2.next_table(page.p2_index())) - .and_then(|p1| p1[page.p1_index()].pointed_frame()) - } - - pub fn translate_page_flags(&self, page: Page) -> Option { - self.p4().next_table(page.p4_index()) - .and_then(|p3| p3.next_table(page.p3_index())) - .and_then(|p2| p2.next_table(page.p2_index())) - .and_then(|p1| Some(p1[page.p1_index()].flags())) - } - - /// Translate a virtual address to a physical one - pub fn translate(&self, virtual_address: VirtualAddress) -> Option { - let offset = virtual_address.get() % PAGE_SIZE; - self.translate_page(Page::containing_address(virtual_address)) - .map(|frame| PhysicalAddress::new(frame.start_address().get() + offset)) - } -} diff --git a/arch/x86_64/src/paging/mod.rs b/arch/x86_64/src/paging/mod.rs deleted file mode 100644 index 2221438..0000000 --- a/arch/x86_64/src/paging/mod.rs +++ /dev/null @@ -1,419 +0,0 @@ -//! # Paging -//! Some code was borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html) - -use core::mem; -use core::ops::{Deref, DerefMut}; -use x86::{msr, tlb}; - -use memory::{allocate_frame, Frame}; - -use self::entry::{EntryFlags, PRESENT, GLOBAL, WRITABLE, NO_EXECUTE}; -use self::mapper::Mapper; -use self::temporary_page::TemporaryPage; - -pub mod entry; -pub mod mapper; -pub mod table; -pub mod temporary_page; - -/// Number of entries per page table -pub const ENTRY_COUNT: usize = 512; - -/// Size of pages -pub const PAGE_SIZE: usize = 4096; - -/// Setup page attribute table -unsafe fn init_pat() { - let uncacheable = 0; - let write_combining = 1; - let write_through = 4; - //let write_protected = 5; - let write_back = 6; - let uncached = 7; - - let pat0 = write_back; - let pat1 = write_through; - let pat2 = uncached; - let pat3 = uncacheable; - - let pat4 = write_combining; - let pat5 = pat1; - let pat6 = pat2; - let pat7 = pat3; - - msr::wrmsr(msr::IA32_PAT, pat7 << 56 | pat6 << 48 | pat5 << 40 | pat4 << 32 - | pat3 << 24 | pat2 << 16 | pat1 << 8 | pat0); -} - -/// Copy tdata, clear tbss, set TCB self pointer -unsafe fn init_tcb(cpu_id: usize) -> usize { - extern { - /// The starting byte of the thread data segment - static mut __tdata_start: u8; - /// The ending byte of the thread data segment - static mut __tdata_end: u8; - /// The starting byte of the thread BSS segment - static mut __tbss_start: u8; - /// The ending byte of the thread BSS segment - static mut __tbss_end: u8; - } - - let tcb_offset; - { - let size = & __tbss_end as *const _ as usize - & __tdata_start as *const _ as usize; - let tbss_offset = & __tbss_start as *const _ as usize - & __tdata_start as *const _ as usize; - - let start = ::KERNEL_PERCPU_OFFSET + ::KERNEL_PERCPU_SIZE * cpu_id; - let end = start + size; - tcb_offset = end - mem::size_of::(); - - ::externs::memcpy(start as *mut u8, & __tdata_start as *const u8, tbss_offset); - ::externs::memset((start + tbss_offset) as *mut u8, 0, size - tbss_offset); - - *(tcb_offset as *mut usize) = end; - } - tcb_offset -} - -/// Initialize paging -/// -/// Returns page table and thread control block offset -pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (ActivePageTable, usize) { - extern { - /// The starting byte of the text (code) data segment. - static mut __text_start: u8; - /// The ending byte of the text (code) data segment. - static mut __text_end: u8; - /// The starting byte of the _.rodata_ (read-only data) segment. - static mut __rodata_start: u8; - /// The ending byte of the _.rodata_ (read-only data) segment. - static mut __rodata_end: u8; - /// The starting byte of the _.data_ segment. - static mut __data_start: u8; - /// The ending byte of the _.data_ segment. - static mut __data_end: u8; - /// The starting byte of the thread data segment - static mut __tdata_start: u8; - /// The ending byte of the thread data segment - static mut __tdata_end: u8; - /// The starting byte of the thread BSS segment - static mut __tbss_start: u8; - /// The ending byte of the thread BSS segment - static mut __tbss_end: u8; - /// The starting byte of the _.bss_ (uninitialized data) segment. - static mut __bss_start: u8; - /// The ending byte of the _.bss_ (uninitialized data) segment. - static mut __bss_end: u8; - } - - init_pat(); - - let mut active_table = ActivePageTable::new(); - - let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(0x8_0000_0000))); - - let mut new_table = { - let frame = allocate_frame().expect("no more frames in paging::init new_table"); - InactivePageTable::new(frame, &mut active_table, &mut temporary_page) - }; - - active_table.with(&mut new_table, &mut temporary_page, |mapper| { - { - // Map tdata and tbss - { - let size = & __tbss_end as *const _ as usize - & __tdata_start as *const _ as usize; - - let start = ::KERNEL_PERCPU_OFFSET + ::KERNEL_PERCPU_SIZE * cpu_id; - let end = start + size; - - let start_page = Page::containing_address(VirtualAddress::new(start)); - let end_page = Page::containing_address(VirtualAddress::new(end - 1)); - for page in Page::range_inclusive(start_page, end_page) { - mapper.map(page, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - } - } - - let mut remap = |start: usize, end: usize, flags: EntryFlags| { - if end > start { - let start_frame = Frame::containing_address(PhysicalAddress::new(start)); - let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); - mapper.map_to(page, frame, flags); - } - } - }; - - // Remap stack writable, no execute - remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - - // Remap a section with `flags` - let mut remap_section = |start: &u8, end: &u8, flags: EntryFlags| { - remap(start as *const _ as usize - ::KERNEL_OFFSET, end as *const _ as usize - ::KERNEL_OFFSET, flags); - }; - // Remap text read-only - remap_section(& __text_start, & __text_end, PRESENT | GLOBAL); - // Remap rodata read-only, no execute - remap_section(& __rodata_start, & __rodata_end, PRESENT | GLOBAL | NO_EXECUTE); - // Remap data writable, no execute - remap_section(& __data_start, & __data_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - // Remap tdata master writable, no execute - remap_section(& __tdata_start, & __tdata_end, PRESENT | GLOBAL | NO_EXECUTE); - // Remap bss writable, no execute - remap_section(& __bss_start, & __bss_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - } - }); - - active_table.switch(new_table); - - (active_table, init_tcb(cpu_id)) -} - -pub unsafe fn init_ap(cpu_id: usize, bsp_table: usize, stack_start: usize, stack_end: usize) -> usize { - extern { - /// The starting byte of the thread data segment - static mut __tdata_start: u8; - /// The ending byte of the thread data segment - static mut __tdata_end: u8; - /// The starting byte of the thread BSS segment - static mut __tbss_start: u8; - /// The ending byte of the thread BSS segment - static mut __tbss_end: u8; - } - - init_pat(); - - let mut active_table = ActivePageTable::new(); - - let mut new_table = InactivePageTable::from_address(bsp_table); - - let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(0x8_0000_0000))); - - active_table.with(&mut new_table, &mut temporary_page, |mapper| { - // Map tdata and tbss - { - let size = & __tbss_end as *const _ as usize - & __tdata_start as *const _ as usize; - - let start = ::KERNEL_PERCPU_OFFSET + ::KERNEL_PERCPU_SIZE * cpu_id; - let end = start + size; - - let start_page = Page::containing_address(VirtualAddress::new(start)); - let end_page = Page::containing_address(VirtualAddress::new(end - 1)); - for page in Page::range_inclusive(start_page, end_page) { - mapper.map(page, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - } - } - - let mut remap = |start: usize, end: usize, flags: EntryFlags| { - if end > start { - let start_frame = Frame::containing_address(PhysicalAddress::new(start)); - let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); - mapper.map_to(page, frame, flags); - } - } - }; - - // Remap stack writable, no execute - remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - }); - - active_table.switch(new_table); - - init_tcb(cpu_id) -} - -pub struct ActivePageTable { - mapper: Mapper, -} - -impl Deref for ActivePageTable { - type Target = Mapper; - - fn deref(&self) -> &Mapper { - &self.mapper - } -} - -impl DerefMut for ActivePageTable { - fn deref_mut(&mut self) -> &mut Mapper { - &mut self.mapper - } -} - -impl ActivePageTable { - pub unsafe fn new() -> ActivePageTable { - ActivePageTable { - mapper: Mapper::new(), - } - } - - pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { - use x86::controlregs; - - let old_table = InactivePageTable { - p4_frame: Frame::containing_address( - PhysicalAddress::new(unsafe { controlregs::cr3() } as usize) - ), - }; - unsafe { - controlregs::cr3_write(new_table.p4_frame.start_address().get() as u64); - } - old_table - } - - pub fn flush(&mut self, page: Page) { - unsafe { tlb::flush(page.start_address().get()); } - } - - pub fn flush_all(&mut self) { - unsafe { tlb::flush_all(); } - } - - pub fn with(&mut self, table: &mut InactivePageTable, temporary_page: &mut temporary_page::TemporaryPage, f: F) - where F: FnOnce(&mut Mapper) - { - use x86::controlregs; - - { - let backup = Frame::containing_address(PhysicalAddress::new(unsafe { controlregs::cr3() as usize })); - - // map temporary_page to current p4 table - let p4_table = temporary_page.map_table_frame(backup.clone(), PRESENT | WRITABLE | NO_EXECUTE, self); - - // overwrite recursive mapping - self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE | NO_EXECUTE); - self.flush_all(); - - // execute f in the new context - f(self); - - // restore recursive mapping to original p4 table - p4_table[511].set(backup, PRESENT | WRITABLE | NO_EXECUTE); - self.flush_all(); - } - - temporary_page.unmap(self); - } - - pub unsafe fn address(&self) -> usize { - use x86::controlregs; - controlregs::cr3() as usize - } -} - -pub struct InactivePageTable { - p4_frame: Frame, -} - -impl InactivePageTable { - pub fn new(frame: Frame, active_table: &mut ActivePageTable, temporary_page: &mut TemporaryPage) -> InactivePageTable { - { - let table = temporary_page.map_table_frame(frame.clone(), PRESENT | WRITABLE | NO_EXECUTE, active_table); - // now we are able to zero the table - table.zero(); - // set up recursive mapping for the table - table[511].set(frame.clone(), PRESENT | WRITABLE | NO_EXECUTE); - } - temporary_page.unmap(active_table); - - InactivePageTable { p4_frame: frame } - } - - pub unsafe fn from_address(cr3: usize) -> InactivePageTable { - InactivePageTable { p4_frame: Frame::containing_address(PhysicalAddress::new(cr3)) } - } - - pub unsafe fn address(&self) -> usize { - self.p4_frame.start_address().get() - } -} - -/// A physical address. -#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct PhysicalAddress(usize); - -impl PhysicalAddress { - pub fn new(address: usize) -> Self { - PhysicalAddress(address) - } - - pub fn get(&self) -> usize { - self.0 - } -} - -/// A virtual address. -#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct VirtualAddress(usize); - -impl VirtualAddress { - pub fn new(address: usize) -> Self { - VirtualAddress(address) - } - - pub fn get(&self) -> usize { - self.0 - } -} - -/// Page -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Page { - number: usize -} - -impl Page { - pub fn start_address(&self) -> VirtualAddress { - VirtualAddress::new(self.number * PAGE_SIZE) - } - - pub fn p4_index(&self) -> usize { - (self.number >> 27) & 0o777 - } - - pub fn p3_index(&self) -> usize { - (self.number >> 18) & 0o777 - } - - pub fn p2_index(&self) -> usize { - (self.number >> 9) & 0o777 - } - - pub fn p1_index(&self) -> usize { - (self.number >> 0) & 0o777 - } - - pub fn containing_address(address: VirtualAddress) -> Page { - //TODO assert!(address.get() < 0x0000_8000_0000_0000 || address.get() >= 0xffff_8000_0000_0000, - // "invalid address: 0x{:x}", address.get()); - Page { number: address.get() / PAGE_SIZE } - } - - pub fn range_inclusive(start: Page, end: Page) -> PageIter { - PageIter { - start: start, - end: end, - } - } -} - -pub struct PageIter { - start: Page, - end: Page, -} - -impl Iterator for PageIter { - type Item = Page; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let page = self.start; - self.start.number += 1; - Some(page) - } else { - None - } - } -} diff --git a/arch/x86_64/src/paging/table.rs b/arch/x86_64/src/paging/table.rs deleted file mode 100644 index f2fa466..0000000 --- a/arch/x86_64/src/paging/table.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! # Page table -//! Code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html) - -use core::marker::PhantomData; -use core::ops::{Index, IndexMut}; - -use memory::allocate_frame; - -use super::entry::*; -use super::ENTRY_COUNT; - -pub const P4: *mut Table = 0xffff_ffff_ffff_f000 as *mut _; - -pub trait TableLevel {} - -pub enum Level4 {} -pub enum Level3 {} -pub enum Level2 {} -pub enum Level1 {} - -impl TableLevel for Level4 {} -impl TableLevel for Level3 {} -impl TableLevel for Level2 {} -impl TableLevel for Level1 {} - -pub trait HierarchicalLevel: TableLevel { - type NextLevel: TableLevel; -} - -impl HierarchicalLevel for Level4 { - type NextLevel = Level3; -} - -impl HierarchicalLevel for Level3 { - type NextLevel = Level2; -} - -impl HierarchicalLevel for Level2 { - type NextLevel = Level1; -} - -pub struct Table { - entries: [Entry; ENTRY_COUNT], - level: PhantomData, -} - -impl Table where L: TableLevel { - pub fn zero(&mut self) { - for entry in self.entries.iter_mut() { - entry.set_unused(); - } - } -} - -impl Table where L: HierarchicalLevel { - pub fn next_table(&self, index: usize) -> Option<&Table> { - self.next_table_address(index).map(|address| unsafe { &*(address as *const _) }) - } - - pub fn next_table_mut(&mut self, index: usize) -> Option<&mut Table> { - self.next_table_address(index).map(|address| unsafe { &mut *(address as *mut _) }) - } - - pub fn next_table_create(&mut self, index: usize) -> &mut Table { - if self.next_table(index).is_none() { - assert!(!self[index].flags().contains(HUGE_PAGE), - "mapping code does not support huge pages"); - let frame = allocate_frame().expect("no frames available"); - self[index].set(frame, PRESENT | WRITABLE | USER_ACCESSIBLE /* Allow users to go down the page table, implement permissions at the page level */); - self.next_table_mut(index).unwrap().zero(); - } - self.next_table_mut(index).unwrap() - } - - fn next_table_address(&self, index: usize) -> Option { - let entry_flags = self[index].flags(); - if entry_flags.contains(PRESENT) && !entry_flags.contains(HUGE_PAGE) { - let table_address = self as *const _ as usize; - Some((table_address << 9) | (index << 12)) - } else { - None - } - } -} - -impl Index for Table where L: TableLevel { - type Output = Entry; - - fn index(&self, index: usize) -> &Entry { - &self.entries[index] - } -} - -impl IndexMut for Table where L: TableLevel { - fn index_mut(&mut self, index: usize) -> &mut Entry { - &mut self.entries[index] - } -} diff --git a/arch/x86_64/src/paging/temporary_page.rs b/arch/x86_64/src/paging/temporary_page.rs deleted file mode 100644 index 4afa6c5..0000000 --- a/arch/x86_64/src/paging/temporary_page.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Temporarily map a page -//! From [Phil Opp's Blog](http://os.phil-opp.com/remap-the-kernel.html) - -use memory::Frame; - -use super::{ActivePageTable, Page, VirtualAddress}; -use super::entry::EntryFlags; -use super::table::{Table, Level1}; - -pub struct TemporaryPage { - page: Page, -} - -impl TemporaryPage { - pub fn new(page: Page) -> TemporaryPage { - TemporaryPage { - page: page, - } - } - - pub fn start_address (&self) -> VirtualAddress { - self.page.start_address() - } - - /// Maps the temporary page to the given frame in the active table. - /// Returns the start address of the temporary page. - pub fn map(&mut self, frame: Frame, flags: EntryFlags, active_table: &mut ActivePageTable) -> VirtualAddress { - assert!(active_table.translate_page(self.page).is_none(), "temporary page is already mapped"); - active_table.map_to(self.page, frame, flags); - self.page.start_address() - } - - /// Maps the temporary page to the given page table frame in the active - /// table. Returns a reference to the now mapped table. - pub fn map_table_frame(&mut self, frame: Frame, flags: EntryFlags, active_table: &mut ActivePageTable) -> &mut Table { - unsafe { &mut *(self.map(frame, flags, active_table).get() as *mut Table) } - } - - /// Unmaps the temporary page in the active table. - pub fn unmap(&mut self, active_table: &mut ActivePageTable) { - active_table.unmap(self.page) - } -} diff --git a/arch/x86_64/src/panic.rs b/arch/x86_64/src/panic.rs deleted file mode 100644 index 27d361d..0000000 --- a/arch/x86_64/src/panic.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Intrinsics for panic handling - -use interrupt; - -#[cfg(not(test))] -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -#[cfg(not(test))] -/// Required to handle panics -#[lang = "panic_fmt"] -extern "C" fn panic_fmt(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! { - println!("PANIC: {}", fmt); - println!("FILE: {}", file); - println!("LINE: {}", line); - - unsafe { interrupt::stack_trace(); } - - println!("HALT"); - loop { - unsafe { interrupt::halt(); } - } -} - -#[allow(non_snake_case)] -#[no_mangle] -/// Required to handle panics -pub extern "C" fn _Unwind_Resume() -> ! { - loop { - unsafe { interrupt::halt(); } - } -} diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs deleted file mode 100644 index c39edf4..0000000 --- a/arch/x86_64/src/start.rs +++ /dev/null @@ -1,183 +0,0 @@ -/// This function is where the kernel sets up IRQ handlers -/// It is increcibly unsafe, and should be minimal in nature -/// It must create the IDT with the correct entries, those entries are -/// defined in other files inside of the `arch` module - -use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - -use acpi; -use allocator; -use device; -use externs::memset; -use gdt; -use idt; -use interrupt; -use memory; -use paging::{self, entry, Page, VirtualAddress}; - -/// Test of zero values in BSS. -static BSS_TEST_ZERO: usize = 0; -/// Test of non-zero values in data. -static DATA_TEST_NONZERO: usize = 0xFFFFFFFFFFFFFFFF; -/// Test of zero values in thread BSS -#[thread_local] -static mut TBSS_TEST_ZERO: usize = 0; -/// Test of non-zero values in thread data. -#[thread_local] -static mut TDATA_TEST_NONZERO: usize = 0xFFFFFFFFFFFFFFFF; - -pub static CPU_COUNT: AtomicUsize = ATOMIC_USIZE_INIT; -pub static AP_READY: AtomicBool = ATOMIC_BOOL_INIT; -static BSP_READY: AtomicBool = ATOMIC_BOOL_INIT; - -extern { - /// Kernel main function - fn kmain(cpus: usize) -> !; - /// Kernel main for APs - fn kmain_ap(id: usize) -> !; -} - -/// The entry to Rust, all things must be initialized -#[no_mangle] -pub unsafe extern fn kstart() -> ! { - { - extern { - /// The starting byte of the _.bss_ (uninitialized data) segment. - static mut __bss_start: u8; - /// The ending byte of the _.bss_ (uninitialized data) segment. - static mut __bss_end: u8; - /// The end of the kernel - static mut __end: u8; - } - - // Zero BSS, this initializes statics that are set to 0 - { - let start_ptr = &mut __bss_start as *mut u8; - let end_ptr = & __bss_end as *const u8 as usize; - - if start_ptr as usize <= end_ptr { - let size = end_ptr - start_ptr as usize; - memset(start_ptr, 0, size); - } - - assert_eq!(BSS_TEST_ZERO, 0); - assert_eq!(DATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF); - } - - // Initialize memory management - memory::init(0, &__end as *const u8 as usize - ::KERNEL_OFFSET); - - // TODO: allocate a stack - let stack_start = 0x00080000 + ::KERNEL_OFFSET; - let stack_end = 0x0009F000 + ::KERNEL_OFFSET; - - // Initialize paging - let (mut active_table, tcb_offset) = paging::init(0, stack_start, stack_end); - - // Set up GDT - gdt::init(tcb_offset, stack_end); - - // Set up IDT - idt::init(); - - // Test tdata and tbss - { - assert_eq!(TBSS_TEST_ZERO, 0); - TBSS_TEST_ZERO += 1; - assert_eq!(TBSS_TEST_ZERO, 1); - assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF); - TDATA_TEST_NONZERO -= 1; - assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE); - } - - // Reset AP variables - CPU_COUNT.store(1, Ordering::SeqCst); - AP_READY.store(false, Ordering::SeqCst); - BSP_READY.store(false, Ordering::SeqCst); - - // Setup kernel heap - { - // Map heap pages - let heap_start_page = Page::containing_address(VirtualAddress::new(::KERNEL_HEAP_OFFSET)); - let heap_end_page = Page::containing_address(VirtualAddress::new(::KERNEL_HEAP_OFFSET + ::KERNEL_HEAP_SIZE-1)); - for page in Page::range_inclusive(heap_start_page, heap_end_page) { - active_table.map(page, entry::PRESENT | entry::GLOBAL | entry::WRITABLE | entry::NO_EXECUTE); - } - - // Init the allocator - allocator::init(::KERNEL_HEAP_OFFSET, ::KERNEL_HEAP_SIZE); - } - - // Initialize devices - device::init(&mut active_table); - - // Read ACPI tables, starts APs - acpi::init(&mut active_table); - - BSP_READY.store(true, Ordering::SeqCst); - } - - kmain(CPU_COUNT.load(Ordering::SeqCst)); -} - -/// Entry to rust for an AP -pub unsafe extern fn kstart_ap(cpu_id: usize, bsp_table: usize, stack_start: usize, stack_end: usize) -> ! { - { - assert_eq!(BSS_TEST_ZERO, 0); - assert_eq!(DATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF); - - // Initialize paging - let tcb_offset = paging::init_ap(cpu_id, bsp_table, stack_start, stack_end); - - // Set up GDT for AP - gdt::init(tcb_offset, stack_end); - - // Set up IDT for AP - idt::init(); - - // Test tdata and tbss - { - assert_eq!(TBSS_TEST_ZERO, 0); - TBSS_TEST_ZERO += 1; - assert_eq!(TBSS_TEST_ZERO, 1); - assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF); - TDATA_TEST_NONZERO -= 1; - assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE); - } - - // Initialize devices (for AP) - device::init_ap(); - - AP_READY.store(true, Ordering::SeqCst); - } - - while ! BSP_READY.load(Ordering::SeqCst) { - interrupt::pause(); - } - - kmain_ap(cpu_id); -} - -pub unsafe fn usermode(ip: usize, sp: usize) -> ! { - // Go to usermode - asm!("mov ds, ax - mov es, ax - mov fs, bx - mov gs, ax - push rax - push rcx - push rdx - push rsi - push rdi - iretq" - : // No output because it never returns - : "{rax}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment - "{rbx}"(gdt::GDT_USER_TLS << 3 | 3), // TLS segment - "{rcx}"(sp), // Stack pointer - "{rdx}"(3 << 12 | 1 << 9), // Flags - Set IOPL and interrupt enable flag - "{rsi}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment - "{rdi}"(ip) // IP - : // No clobers because it never returns - : "intel", "volatile"); - unreachable!(); -} diff --git a/arch/x86_64/src/stop.rs b/arch/x86_64/src/stop.rs deleted file mode 100644 index 5af92ae..0000000 --- a/arch/x86_64/src/stop.rs +++ /dev/null @@ -1,23 +0,0 @@ -use io::{Io, Pio}; - -#[no_mangle] -pub unsafe extern fn kstop() -> ! { - // (phony) ACPI shutdown (http://forum.osdev.org/viewtopic.php?t=16990) - // Works for qemu and bochs. - for &port in [0x604, 0xB004].iter() { - println!("Shutdown with outw(0x{:X}, 0x{:X})", port, 0x2000); - Pio::::new(port).write(0x2000); - } - - // Magic shutdown code for bochs and qemu (older versions). - for c in "Shutdown".bytes() { - println!("Shutdown with outb(0x{:X}, '{}')", 0x8900, c as char); - Pio::::new(0x8900).write(c); - } - - // Magic code for VMWare. Also a hard lock. - println!("Shutdown with cli hlt"); - asm!("cli; hlt" : : : : "intel", "volatile"); - - unreachable!(); -} diff --git a/arch/x86_64/src/time.rs b/arch/x86_64/src/time.rs deleted file mode 100644 index 7af3ef7..0000000 --- a/arch/x86_64/src/time.rs +++ /dev/null @@ -1,15 +0,0 @@ -use spin::Mutex; - -pub static START: Mutex<(u64, u64)> = Mutex::new((0, 0)); -pub static OFFSET: Mutex<(u64, u64)> = Mutex::new((0, 0)); - -pub fn monotonic() -> (u64, u64) { - *OFFSET.lock() -} - -pub fn realtime() -> (u64, u64) { - let offset = monotonic(); - let start = *START.lock(); - let sum = start.1 + offset.1; - (start.0 + offset.0 + sum / 1000000000, sum % 1000000000) -} diff --git a/arm-unknown-redox.json b/arm-unknown-redox.json deleted file mode 100644 index 6089ab1..0000000 --- a/arm-unknown-redox.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "llvm-target": "arm-unknown-redox", - "target-endian": "little", - "target-pointer-width": "32", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "arch": "arm", - "os": "redox", - "env": "", - "vendor": "unknown", - "target-family": "redox", - "pre-link-args": ["-nostdlib", "-static"], - "features": "+soft-float", - "dynamic-linking": false, - "executables": true, - "relocation-model": "static", - "code-model": "default", - "disable-redzone": true, - "eliminate-frame-pointer": false, - "exe-suffix": "", - "has-rpath": false, - "no-compiler-rt": true, - "no-default-libraries": true, - "position-independent-executables": false, - "has-elf-tls": true, - "panic-strategy": "abort" -} diff --git a/bootloader b/bootloader new file mode 160000 index 0000000..59fd6fb --- /dev/null +++ b/bootloader @@ -0,0 +1 @@ +Subproject commit 59fd6fbcfe9adc7e5d0c0df58fe4e2e07df5f31b diff --git a/bootloader/arm/start.s b/bootloader/arm/start.s deleted file mode 100644 index 8495600..0000000 --- a/bootloader/arm/start.s +++ /dev/null @@ -1,17 +0,0 @@ -interrupt_vector_table: - b . @ Reset - b . - b . @ SWI instruction - b . - b . - b . - b . - b . - -.comm stack, 0x10000 @ Reserve 64k stack in the BSS -_start: - .globl _start - ldr sp, =stack+0x10000 @ Set up the stack - bl kstart @ Jump to the main function -1: - b 1b @ Halt diff --git a/bootloader/x86_64/bootsector.asm b/bootloader/x86_64/bootsector.asm deleted file mode 100644 index b66184e..0000000 --- a/bootloader/x86_64/bootsector.asm +++ /dev/null @@ -1,188 +0,0 @@ -ORG 0x7C00 -SECTION .text -USE16 - -boot: ; dl comes with disk - ; initialize segment registers - xor ax, ax - mov ds, ax - mov es, ax - mov ss, ax - - ; initialize stack - mov sp, 0x7C00 - - ; initialize CS - push ax - push word .set_cs - retf - -.set_cs: - - ; save disk number - mov [disk], dl - - mov si, name - call print - call print_line - - mov bx, (startup_start - boot) / 512 - call print_num - call print_line - - mov bx, startup_start - call print_num - call print_line - - mov eax, (startup_start - boot) / 512 - mov bx, startup_start - mov cx, (startup_end - startup_start) / 512 - xor dx, dx - call load - - mov si, finished - call print - call print_line - - jmp startup - -; load some sectors from disk to a buffer in memory -; buffer has to be below 1MiB -; IN -; ax: start sector -; bx: offset of buffer -; cx: number of sectors (512 Bytes each) -; dx: segment of buffer -; CLOBBER -; ax, bx, cx, dx, si -; TODO rewrite to (eventually) move larger parts at once -; if that is done increase buffer_size_sectors in startup-common to that (max 0x80000 - startup_end) -load: - cmp cx, 127 - jbe .good_size - - pusha - mov cx, 127 - call load - popa - add ax, 127 - add dx, 127 * 512 / 16 - sub cx, 127 - - jmp load -.good_size: - mov [DAPACK.addr], eax - mov [DAPACK.buf], bx - mov [DAPACK.count], cx - mov [DAPACK.seg], dx - - call print_dapack - - mov dl, [disk] - mov si, DAPACK - mov ah, 0x42 - int 0x13 - jc error - ret - - ; store some sectors to disk from a buffer in memory - ; buffer has to be below 1MiB - ; IN - ; ax: start sector - ; bx: offset of buffer - ; cx: number of sectors (512 Bytes each) - ; dx: segment of buffer - ; CLOBBER - ; ax, bx, cx, dx, si - ; TODO rewrite to (eventually) move larger parts at once - ; if that is done increase buffer_size_sectors in startup-common to that (max 0x80000 - startup_end) - store: - cmp cx, 127 - jbe .good_size - - pusha - mov cx, 127 - call store - popa - add ax, 127 - add dx, 127 * 512 / 16 - sub cx, 127 - - jmp store - .good_size: - mov [DAPACK.addr], eax - mov [DAPACK.buf], bx - mov [DAPACK.count], cx - mov [DAPACK.seg], dx - - call print_dapack - - mov dl, [disk] - mov si, DAPACK - mov ah, 0x43 - int 0x13 - jc error - ret - -print_dapack: - mov bx, [DAPACK.addr + 2] - call print_num - - mov bx, [DAPACK.addr] - call print_num - - mov al, '#' - call print_char - - mov bx, [DAPACK.count] - call print_num - - mov al, ' ' - call print_char - - mov bx, [DAPACK.seg] - call print_num - - mov al, ':' - call print_char - - mov bx, [DAPACK.buf] - call print_num - - jmp print_line - -error: - mov bh, 0 - mov bl, ah - call print_num - - mov al, ' ' - call print_char - - mov si, errored - call print - call print_line -.halt: - cli - hlt - jmp .halt - -%include "print16.asm" - -name: db "Redox Loader - Stage One",0 -errored: db "Could not read disk",0 -finished: db "Redox Loader - Stage Two",0 - -disk: db 0 - -DAPACK: - db 0x10 - db 0 -.count: dw 0 ; int 13 resets this to # of blocks actually read/written -.buf: dw 0 ; memory buffer destination address (0:7c00) -.seg: dw 0 ; in memory page zero -.addr: dq 0 ; put the lba to read in this spot - -times 510-($-$$) db 0 -db 0x55 -db 0xaa diff --git a/bootloader/x86_64/config.asm b/bootloader/x86_64/config.asm deleted file mode 100644 index 8e3b220..0000000 --- a/bootloader/x86_64/config.asm +++ /dev/null @@ -1,18 +0,0 @@ -SECTION .text -USE16 - -align 512, db 0 - -config: - .xres: dw 0 - .yres: dw 0 - -times 512 - ($ - config) db 0 - -save_config: - mov eax, (config - boot) / 512 - mov bx, config - mov cx, 1 - xor dx, dx - call store - ret diff --git a/bootloader/x86_64/descriptor_flags.inc b/bootloader/x86_64/descriptor_flags.inc deleted file mode 100644 index 210c98d..0000000 --- a/bootloader/x86_64/descriptor_flags.inc +++ /dev/null @@ -1,46 +0,0 @@ -attrib: - .present equ 1 << 7 - .ring1 equ 1 << 5 - .ring2 equ 1 << 6 - .ring3 equ 1 << 5 | 1 << 6 - .user equ 1 << 4 -;user - .code equ 1 << 3 -; code - .conforming equ 1 << 2 - .readable equ 1 << 1 -; data - .expand_down equ 1 << 2 - .writable equ 1 << 1 - .accessed equ 1 << 0 -;system -; legacy - .tssAvailabe16 equ 0x1 - .ldt equ 0x2 - .tssBusy16 equ 0x3 - .call16 equ 0x4 - .task equ 0x5 - .interrupt16 equ 0x6 - .trap16 equ 0x7 - .tssAvailabe32 equ 0x9 - .tssBusy32 equ 0xB - .call32 equ 0xC - .interrupt32 equ 0xE - .trap32 equ 0xF -; long mode - .ldt32 equ 0x2 - .tssAvailabe64 equ 0x9 - .tssBusy64 equ 0xB - .call64 equ 0xC - .interrupt64 equ 0xE - .trap64 equ 0xF - -flags: - .granularity equ 1 << 7 - .available equ 1 << 4 -;user - .default_operand_size equ 1 << 6 -; code - .long_mode equ 1 << 5 -; data - .reserved equ 1 << 5 diff --git a/bootloader/x86_64/gdt_entry.inc b/bootloader/x86_64/gdt_entry.inc deleted file mode 100644 index 861a78b..0000000 --- a/bootloader/x86_64/gdt_entry.inc +++ /dev/null @@ -1,8 +0,0 @@ -struc GDTEntry - .limitl resw 1 - .basel resw 1 - .basem resb 1 - .attribute resb 1 - .flags__limith resb 1 - .baseh resb 1 -endstruc diff --git a/bootloader/x86_64/harddrive.asm b/bootloader/x86_64/harddrive.asm deleted file mode 100644 index 052dfe8..0000000 --- a/bootloader/x86_64/harddrive.asm +++ /dev/null @@ -1,21 +0,0 @@ -%include "bootsector.asm" - -startup_start: -%ifdef ARCH_i386 - %include "startup-i386.asm" -%endif - -%ifdef ARCH_x86_64 - %include "startup-x86_64.asm" -%endif -align 512, db 0 -startup_end: - -kernel_file: - incbin "build/kernel/kernel" - align 512, db 0 -.end: -.length equ kernel_file.end - kernel_file -.length_sectors equ .length / 512 - -incbin "build/filesystem.bin" diff --git a/bootloader/x86_64/initialize.asm b/bootloader/x86_64/initialize.asm deleted file mode 100644 index e723d37..0000000 --- a/bootloader/x86_64/initialize.asm +++ /dev/null @@ -1,78 +0,0 @@ -SECTION .text -USE16 - -initialize: -.fpu: ;enable fpu - mov eax, cr0 - and al, 11110011b - or al, 00100010b - mov cr0, eax - mov eax, cr4 - or eax, 0x200 - mov cr4, eax - fninit - ret - -.sse: ;enable sse - mov eax, cr4 - or ax, 0000011000000000b - mov cr4, eax - ret - -;PIT Frequency -;If using nanoseconds, to minimize drift, one should find a frequency as close to an integer nanosecond value in wavelength -;Divider Hz Nanoseconds Properties -;2685 444.38795779019242706393 2250286.00003631746492922946 Best For Context Switching -;5370 222.19397889509621353196 4500572.00007263492985856020 -;21029 56.73981961418358774390 17624306.99991199998882825455 -;23714 50.31549576902532962244 19874592.99994831745375667118 -;26399 45.19798729749864262535 22124878.99998463491868476373 -;29084 41.02536331545408701233 24375165.00002095238361424615 -;31769 37.55804925136663623868 26625451.00005726984854313455 -;34454 34.63115071302799868423 28875737.00009358731347639618 -;50113 23.80982313305263437963 41999471.99993295237244784676 -;52798 22.59899364874932131267 44249757.99996926983737931766 -;55483 21.50535599492937776736 46500044.00000558730230583335 Lowest Drift -;58168 20.51268165772704350616 48750330.00004190476724037528 -;60853 19.60760630809765610021 51000616.00007822223218031738 - -.pit: - ;initialize the PIT - mov ax, 2685 ;this is the divider for the PIT - out 0x40, al - rol ax, 8 - out 0x40, al - ;DISABLED ;enable rtc interrupt - ;mov al, 0xB - ;out 0x70, al - ;rol ax, 8 - ;in al, 0x71 - ;rol ax, 8 - ;out 0x70, al - ;rol ax, 8 - ;or al, 0x40 - ;out 0x71, al - ret - -.pic: ;sets up IRQs at int 20-2F - mov al, 0x11 - out 0x20, al - out 0xA0, al - mov al, 0x20 ;IRQ0 vector - out 0x21, al - mov al, 0x28 ;IRQ8 vector - out 0xA1, al - mov al, 4 - out 0x21, al - mov al, 2 - out 0xA1, al - mov al, 1 - out 0x21, al - out 0xA1, al - xor al, al ;no IRQ masks - out 0x21, al - out 0xA1, al - mov al, 0x20 ;reset PIC's - out 0xA0, al - out 0x20, al - ret diff --git a/bootloader/x86_64/livedisk.asm b/bootloader/x86_64/livedisk.asm deleted file mode 100644 index e1cd643..0000000 --- a/bootloader/x86_64/livedisk.asm +++ /dev/null @@ -1,19 +0,0 @@ -%include "bootsector.asm" - -startup_start: -%ifdef ARCH_i386 - %include "startup-i386.asm" -%endif - -%ifdef ARCH_x86_64 - %include "startup-x86_64.asm" -%endif -align 512, db 0 -startup_end: - -kernel_file: - incbin "build/kernel/kernel_live" - align 512, db 0 -.end: -.length equ kernel_file.end - kernel_file -.length_sectors equ .length / 512 diff --git a/bootloader/x86_64/memory_map.asm b/bootloader/x86_64/memory_map.asm deleted file mode 100644 index a5cdc70..0000000 --- a/bootloader/x86_64/memory_map.asm +++ /dev/null @@ -1,32 +0,0 @@ -SECTION .text -USE16 -;Generate a memory map at 0x500 to 0x5000 (available memory not used for kernel or bootloader) -memory_map: -.start equ 0x0500 -.end equ 0x5000 -.length equ .end - .start - - xor eax, eax - mov di, .start - mov ecx, .length / 4 ; moving 4 Bytes at once - cld - rep stosd - - mov di, .start - mov edx, 0x534D4150 - xor ebx, ebx -.lp: - mov eax, 0xE820 - mov ecx, 24 - - int 0x15 - jc .done ; Error or finished - - cmp ebx, 0 - je .done ; Finished - - add di, 24 - cmp di, .end - jb .lp ; Still have buffer space -.done: - ret diff --git a/bootloader/x86_64/print16.asm b/bootloader/x86_64/print16.asm deleted file mode 100644 index dada0fd..0000000 --- a/bootloader/x86_64/print16.asm +++ /dev/null @@ -1,65 +0,0 @@ -SECTION .text -USE16 -; provide function for printing in x86 real mode - -; print a string and a newline -; IN -; si: points at zero-terminated String -; CLOBBER -; ax -print_line: - mov al, 13 - call print_char - mov al, 10 - jmp print_char - -; print a string -; IN -; si: points at zero-terminated String -; CLOBBER -; ax -print: - cld -.loop: - lodsb - test al, al - jz .done - call print_char - jmp .loop -.done: - ret - -; print a character -; IN -; al: character to print -; CLOBBER -; ah -print_char: - mov ah, 0x0e - int 0x10 - ret - -; print a number in hex -; IN -; bx: the number -; CLOBBER -; cx, ax -print_num: - mov cx, 4 -.lp: - mov al, bh - shr al, 4 - - cmp al, 0xA - jb .below_0xA - - add al, 'A' - 0xA - '0' -.below_0xA: - add al, '0' - - call print_char - - shl bx, 4 - loop .lp - - ret diff --git a/bootloader/x86_64/startup-common.asm b/bootloader/x86_64/startup-common.asm deleted file mode 100644 index 9677bbc..0000000 --- a/bootloader/x86_64/startup-common.asm +++ /dev/null @@ -1,110 +0,0 @@ -SECTION .text -USE16 - -startup: - ; enable A20-Line via IO-Port 92, might not work on all motherboards - in al, 0x92 - or al, 2 - out 0x92, al - -; loading kernel to 1MiB -; move part of kernel to startup_end via bootsector#load and then copy it up -; repeat until all of the kernel is loaded - -; buffersize in multiple of sectors (512 Bytes) -; min 1 -; max (0x70000 - startup_end) / 512 -buffer_size_sectors equ 127 -; buffer size in Bytes -buffer_size_bytes equ buffer_size_sectors * 512 - -kernel_base equ 0x100000 - - ; how often do we need to call load and move memory - mov ecx, kernel_file.length_sectors / buffer_size_sectors - - mov eax, (kernel_file - boot) / 512 - mov edi, kernel_base - cld -.lp: - ; saving counter - push cx - - ; populating buffer - mov cx, buffer_size_sectors - mov bx, kernel_file - mov dx, 0x0 - - push edi - push eax - call load - - ; moving buffer - call unreal - pop eax - pop edi - - mov esi, kernel_file - mov ecx, buffer_size_bytes / 4 - a32 rep movsd - - ; preparing next iteration - add eax, buffer_size_sectors - - pop cx - loop .lp - - ; load the part of the kernel that does not fill the buffer completely - mov cx, kernel_file.length_sectors % buffer_size_sectors - test cx, cx - jz finished_loading ; if cx = 0 => skip - - mov bx, kernel_file - mov dx, 0x0 - call load - - ; moving remnants of kernel - call unreal - - mov esi, kernel_file - mov ecx, (kernel_file.length_sectors % buffer_size_bytes) / 4 - a32 rep movsd -finished_loading: - call memory_map - - call vesa - - mov si, init_fpu_msg - call printrm - call initialize.fpu - - mov si, init_sse_msg - call printrm - call initialize.sse - - mov si, init_pit_msg - call printrm - call initialize.pit - - mov si, init_pic_msg - call printrm - call initialize.pic - - mov si, startup_arch_msg - call printrm - - jmp startup_arch - -%include "config.asm" -%include "descriptor_flags.inc" -%include "gdt_entry.inc" -%include "unreal.asm" -%include "memory_map.asm" -%include "vesa.asm" -%include "initialize.asm" - -init_fpu_msg: db "Init FPU",13,10,0 -init_sse_msg: db "Init SSE",13,10,0 -init_pit_msg: db "Init PIT",13,10,0 -init_pic_msg: db "Init PIC",13,10,0 -startup_arch_msg: db "Startup Arch",13,10,0 diff --git a/bootloader/x86_64/startup-i386.asm b/bootloader/x86_64/startup-i386.asm deleted file mode 100644 index c38a09e..0000000 --- a/bootloader/x86_64/startup-i386.asm +++ /dev/null @@ -1,148 +0,0 @@ -%include "startup-common.asm" - -startup_arch: - ; load protected mode GDT and IDT - cli - lgdt [gdtr] - lidt [idtr] - ; set protected mode bit of cr0 - mov eax, cr0 - or eax, 1 - mov cr0, eax - - ; far jump to load CS with 32 bit segment - jmp gdt.kernel_code:protected_mode - -USE32 -protected_mode: - ; load all the other segments with 32 bit data segments - mov eax, gdt.kernel_data - mov ds, eax - mov es, eax - mov fs, eax - mov gs, eax - mov ss, eax - - mov esp, 0x800000 - 128 - - mov eax, gdt.tss - ltr ax - - ;rust init - mov eax, [kernel_base + 0x18] - mov [interrupts.handler], eax - mov eax, gdtr - mov ebx, idtr - mov ecx, tss - int 255 -.lp: - sti - hlt - jmp .lp - -gdtr: - dw gdt.end + 1 ; size - dd gdt ; offset - -gdt: -.null equ $ - gdt - dq 0 - -.kernel_code equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code | attrib.readable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.kernel_data equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.user_code equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.code | attrib.readable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.user_data equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.user_tls equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.tss equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw (tss.end - tss) & 0xFFFF - at GDTEntry.basel, dw (tss-$$+0x7C00) & 0xFFFF - at GDTEntry.basem, db ((tss-$$+0x7C00) >> 16) & 0xFF - at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.tssAvailabe32 - at GDTEntry.flags__limith, db ((tss.end - tss) >> 16) & 0xF - at GDTEntry.baseh, db ((tss-$$+0x7C00) >> 24) & 0xFF - iend -.end equ $ - gdt - -struc TSS - .prev_tss resd 1 ;The previous TSS - if we used hardware task switching this would form a linked list. - .esp0 resd 1 ;The stack pointer to load when we change to kernel mode. - .ss0 resd 1 ;The stack segment to load when we change to kernel mode. - .esp1 resd 1 ;everything below here is unused now.. - .ss1 resd 1 - .esp2 resd 1 - .ss2 resd 1 - .cr3 resd 1 - .eip resd 1 - .eflags resd 1 - .eax resd 1 - .ecx resd 1 - .edx resd 1 - .ebx resd 1 - .esp resd 1 - .ebp resd 1 - .esi resd 1 - .edi resd 1 - .es resd 1 - .cs resd 1 - .ss resd 1 - .ds resd 1 - .fs resd 1 - .gs resd 1 - .ldt resd 1 - .trap resw 1 - .iomap_base resw 1 -endstruc - -tss: - istruc TSS - at TSS.esp0, dd 0x800000 - 128 - at TSS.ss0, dd gdt.kernel_data - at TSS.iomap_base, dw 0xFFFF - iend -.end: diff --git a/bootloader/x86_64/startup-x86_64.asm b/bootloader/x86_64/startup-x86_64.asm deleted file mode 100644 index 6059331..0000000 --- a/bootloader/x86_64/startup-x86_64.asm +++ /dev/null @@ -1,179 +0,0 @@ -trampoline: - .ready: dq 0 - .cpu_id: dq 0 - .page_table: dq 0 - .stack_start: dq 0 - .stack_end: dq 0 - .code: dq 0 - - times 512 - ($ - trampoline) db 0 - -startup_ap: - cli - - xor ax, ax - mov ds, ax - mov es, ax - mov ss, ax - - ; initialize stack - mov sp, 0x7C00 - - call initialize.fpu - call initialize.sse - - ;cr3 holds pointer to PML4 - mov edi, 0x70000 - mov cr3, edi - - ;enable FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension - mov eax, cr4 - or eax, 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4 - mov cr4, eax - - ; load protected mode GDT - lgdt [gdtr] - - mov ecx, 0xC0000080 ; Read from the EFER MSR. - rdmsr - or eax, 1 << 11 | 1 << 8 ; Set the Long-Mode-Enable and NXE bit. - wrmsr - - ;enabling paging and protection simultaneously - mov ebx, cr0 - or ebx, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode - mov cr0, ebx - - ; far jump to enable Long Mode and load CS with 64 bit segment - jmp gdt.kernel_code:long_mode_ap - -%include "startup-common.asm" - -startup_arch: - cli - ; setting up Page Tables - ; Identity Mapping first GB - mov ax, 0x7000 - mov es, ax - - xor edi, edi - xor eax, eax - mov ecx, 6 * 4096 / 4 ;PML4, PDP, 4 PD / moves 4 Bytes at once - cld - rep stosd - - xor edi, edi - ;Link first PML4 and second to last PML4 to PDP - mov DWORD [es:edi], 0x71000 | 1 << 1 | 1 - mov DWORD [es:edi + 510*8], 0x71000 | 1 << 1 | 1 - add edi, 0x1000 - ;Link last PML4 to PML4 - mov DWORD [es:edi - 8], 0x70000 | 1 << 1 | 1 - ;Link first four PDP to PD - mov DWORD [es:edi], 0x72000 | 1 << 1 | 1 - mov DWORD [es:edi + 8], 0x73000 | 1 << 1 | 1 - mov DWORD [es:edi + 16], 0x74000 | 1 << 1 | 1 - mov DWORD [es:edi + 24], 0x75000 | 1 << 1 | 1 - add edi, 0x1000 - ;Link all PD's (512 per PDP, 2MB each)y - mov ebx, 1 << 7 | 1 << 1 | 1 - mov ecx, 4*512 -.setpd: - mov [es:edi], ebx - add ebx, 0x200000 - add edi, 8 - loop .setpd - - xor ax, ax - mov es, ax - - ;cr3 holds pointer to PML4 - mov edi, 0x70000 - mov cr3, edi - - ;enable FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension - mov eax, cr4 - or eax, 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4 - mov cr4, eax - - ; load protected mode GDT - lgdt [gdtr] - - mov ecx, 0xC0000080 ; Read from the EFER MSR. - rdmsr - or eax, 1 << 11 | 1 << 8 ; Set the Long-Mode-Enable and NXE bit. - wrmsr - - ;enabling paging and protection simultaneously - mov ebx, cr0 - or ebx, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode - mov cr0, ebx - - ; far jump to enable Long Mode and load CS with 64 bit segment - jmp gdt.kernel_code:long_mode - -USE64 -long_mode: - ; load all the other segments with 64 bit data segments - mov rax, gdt.kernel_data - mov ds, rax - mov es, rax - mov fs, rax - mov gs, rax - mov ss, rax - - mov rsp, 0xFFFFFF000009F000 - - ;rust init - mov rax, [kernel_base + 0x18] - jmp rax - -long_mode_ap: - mov rax, gdt.kernel_data - mov ds, rax - mov es, rax - mov fs, rax - mov gs, rax - mov ss, rax - - mov rdi, [trampoline.cpu_id] - mov rsi, [trampoline.page_table] - mov rdx, [trampoline.stack_start] - mov rcx, [trampoline.stack_end] - - lea rsp, [rcx - 256] - - mov rax, [trampoline.code] - mov qword [trampoline.ready], 1 - jmp rax - -gdtr: - dw gdt.end + 1 ; size - dq gdt ; offset - -gdt: -.null equ $ - gdt - dq 0 - -.kernel_code equ $ - gdt -istruc GDTEntry - at GDTEntry.limitl, dw 0 - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code - at GDTEntry.flags__limith, db flags.long_mode - at GDTEntry.baseh, db 0 -iend - -.kernel_data equ $ - gdt -istruc GDTEntry - at GDTEntry.limitl, dw 0 - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 -; AMD System Programming Manual states that the writeable bit is ignored in long mode, but ss can not be set to this descriptor without it - at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0 - at GDTEntry.baseh, db 0 -iend - -.end equ $ - gdt diff --git a/bootloader/x86_64/unreal.asm b/bootloader/x86_64/unreal.asm deleted file mode 100644 index 691a892..0000000 --- a/bootloader/x86_64/unreal.asm +++ /dev/null @@ -1,54 +0,0 @@ -SECTION .text -USE16 - -; switch to unreal mode; ds and es can address up to 4GiB -unreal: - cli - - lgdt [unreal_gdtr] - - push es - push ds - - mov eax, cr0 ; switch to pmode by - or al,1 ; set pmode bit - mov cr0, eax - - jmp $+2 - -; http://wiki.osdev.org/Babystep7 -; When this register given a "selector", a "segment descriptor cache register" -; is filled with the descriptor values, including the size (or limit). After -; the switch back to real mode, these values are not modified, regardless of -; what value is in the 16-bit segment register. So the 64k limit is no longer -; valid and 32-bit offsets can be used with the real-mode addressing rules - mov bx, unreal_gdt.data - mov es, bx - mov ds, bx - - and al,0xFE ; back to realmode - mov cr0, eax ; by toggling bit again - - pop ds - pop es - sti - ret - - -unreal_gdtr: - dw unreal_gdt.end + 1 ; size - dd unreal_gdt ; offset - -unreal_gdt: -.null equ $ - unreal_gdt - dq 0 -.data equ $ - unreal_gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0x0 - at GDTEntry.basem, db 0x0 - at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0x0 - iend -.end equ $ - unreal_gdt diff --git a/bootloader/x86_64/vesa.asm b/bootloader/x86_64/vesa.asm deleted file mode 100644 index b649e4b..0000000 --- a/bootloader/x86_64/vesa.asm +++ /dev/null @@ -1,207 +0,0 @@ -%include "vesa.inc" -SECTION .text -USE16 -vesa: -.getcardinfo: - mov ax, 0x4F00 - mov di, VBECardInfo - int 0x10 - cmp ax, 0x4F - je .findmode - mov eax, 1 - ret - .resetlist: - ;if needed, reset mins/maxes/stuff - xor cx, cx - mov [.minx], cx - mov [.miny], cx - mov [config.xres], cx - mov [config.yres], cx -.findmode: - mov si, [VBECardInfo.videomodeptr] - mov ax, [VBECardInfo.videomodeptr+2] - mov fs, ax - sub si, 2 -.searchmodes: - add si, 2 - mov cx, [fs:si] - cmp cx, 0xFFFF - jne .getmodeinfo - cmp word [.goodmode], 0 - je .resetlist - jmp .findmode -.getmodeinfo: - push esi - mov [.currentmode], cx - mov ax, 0x4F01 - mov di, VBEModeInfo - int 0x10 - pop esi - cmp ax, 0x4F - je .foundmode - mov eax, 1 - ret -.foundmode: - ;check minimum values, really not minimums from an OS perspective but ugly for users - cmp byte [VBEModeInfo.bitsperpixel], 32 - jb .searchmodes -.testx: - mov cx, [VBEModeInfo.xresolution] - cmp word [config.xres], 0 - je .notrequiredx - cmp cx, [config.xres] - je .testy - jmp .searchmodes -.notrequiredx: - cmp cx, [.minx] - jb .searchmodes -.testy: - mov cx, [VBEModeInfo.yresolution] - cmp word [config.yres], 0 - je .notrequiredy - cmp cx, [config.yres] - jne .searchmodes ;as if there weren't enough warnings, USE WITH CAUTION - cmp word [config.xres], 0 - jnz .setmode - jmp .testgood -.notrequiredy: - cmp cx, [.miny] - jb .searchmodes -.testgood: - mov cx, [.currentmode] - mov [.goodmode], cx - push esi - ; call decshowrm - ; mov al, ':' - ; call charrm - mov cx, [VBEModeInfo.xresolution] - call decshowrm - mov al, 'x' - call charrm - mov cx, [VBEModeInfo.yresolution] - call decshowrm - mov al, '@' - call charrm - xor ch, ch - mov cl, [VBEModeInfo.bitsperpixel] - call decshowrm - mov si, .modeok - call printrm - xor ax, ax - int 0x16 - pop esi - cmp al, 'y' - je .setmode - cmp al, 's' - je .savemode - jmp .searchmodes -.savemode: - mov cx, [VBEModeInfo.xresolution] - mov [config.xres], cx - mov cx, [VBEModeInfo.yresolution] - mov [config.yres], cx - call save_config -.setmode: - mov bx, [.currentmode] - cmp bx, 0 - je .nomode - or bx, 0x4000 - mov ax, 0x4F02 - int 0x10 -.nomode: - cmp ax, 0x4F - je .returngood - mov eax, 1 - ret -.returngood: - xor eax, eax - ret - -.minx dw 640 -.miny dw 480 - -.modeok db ": Is this OK? (s)ave/(y)es/(n)o",10,13,0 - -.goodmode dw 0 -.currentmode dw 0 -;useful functions - -decshowrm: - mov si, .number -.clear: - mov al, "0" - mov [si], al - inc si - cmp si, .numberend - jb .clear - dec si - call convertrm - mov si, .number -.lp: - lodsb - cmp si, .numberend - jae .end - cmp al, "0" - jbe .lp -.end: - dec si - call printrm - ret - -.number times 7 db 0 -.numberend db 0 - -convertrm: - dec si - mov bx, si ;place to convert into must be in si, number to convert must be in cx -.cnvrt: - mov si, bx - sub si, 4 -.ten4: inc si - cmp cx, 10000 - jb .ten3 - sub cx, 10000 - inc byte [si] - jmp .cnvrt -.ten3: inc si - cmp cx, 1000 - jb .ten2 - sub cx, 1000 - inc byte [si] - jmp .cnvrt -.ten2: inc si - cmp cx, 100 - jb .ten1 - sub cx, 100 - inc byte [si] - jmp .cnvrt -.ten1: inc si - cmp cx, 10 - jb .ten0 - sub cx, 10 - inc byte [si] - jmp .cnvrt -.ten0: inc si - cmp cx, 1 - jb .return - sub cx, 1 - inc byte [si] - jmp .cnvrt -.return: - ret - -printrm: - mov al, [si] - test al, al - jz .return - call charrm - inc si - jmp printrm -.return: - ret - -charrm: ;char must be in al - mov bx, 7 - mov ah, 0xE - int 10h - ret diff --git a/bootloader/x86_64/vesa.inc b/bootloader/x86_64/vesa.inc deleted file mode 100644 index 7f85476..0000000 --- a/bootloader/x86_64/vesa.inc +++ /dev/null @@ -1,90 +0,0 @@ -ABSOLUTE 0x5000 -VBECardInfo: - .signature resb 4 - .version resw 1 - .oemstring resd 1 - .capabilities resd 1 - .videomodeptr resd 1 - .totalmemory resw 1 - .oemsoftwarerev resw 1 - .oemvendornameptr resd 1 - .oemproductnameptr resd 1 - .oemproductrevptr resd 1 - .reserved resb 222 - .oemdata resb 256 - -ABSOLUTE 0x5200 -VBEModeInfo: - .attributes resw 1 - .winA resb 1 - .winB resb 1 - .granularity resw 1 - .winsize resw 1 - .segmentA resw 1 - .segmentB resw 1 - .winfuncptr resd 1 - .bytesperscanline resw 1 - .xresolution resw 1 - .yresolution resw 1 - .xcharsize resb 1 - .ycharsize resb 1 - .numberofplanes resb 1 - .bitsperpixel resb 1 - .numberofbanks resb 1 - .memorymodel resb 1 - .banksize resb 1 - .numberofimagepages resb 1 - .unused resb 1 - .redmasksize resb 1 - .redfieldposition resb 1 - .greenmasksize resb 1 - .greenfieldposition resb 1 - .bluemasksize resb 1 - .bluefieldposition resb 1 - .rsvdmasksize resb 1 - .rsvdfieldposition resb 1 - .directcolormodeinfo resb 1 - .physbaseptr resd 1 - .offscreenmemoryoffset resd 1 - .offscreenmemsize resw 1 - .reserved resb 206 - -VBE.ModeAttributes: - .available equ 1 << 0 - .bios equ 1 << 2 - .color equ 1 << 3 - .graphics equ 1 << 4 - .vgacompatible equ 1 << 5 - .notbankable equ 1 << 6 - .linearframebuffer equ 1 << 7 - -ABSOLUTE 0x5400 -VBEEDID: - .header resb 8 - .manufacturer resw 1 - .productid resw 1 - .serial resd 1 - .manufactureweek resb 1 - .manufactureyear resb 1 - .version resb 1 - .revision resb 1 - .input resb 1 - .horizontalsize resb 1 - .verticalsize resb 1 - .gamma resb 1 - .displaytype resb 1 - .chromaticity resb 10 - .timingI resb 1 - .timingII resb 1 - .timingreserved resb 1 - .standardtiming: resw 8 ;format: db (horizontal-248)/8, aspectratio | verticalfrequency - 60 - .aspect.16.10 equ 0 ;mul horizontal by 10, shr 4 to get vertical resolution - .aspect.4.3 equ 1 << 6 ;mul horizontal by 3, shr 2 to get vertical resolution - .aspect.5.4 equ 2 << 6 ;shl horizontal by 2, div by 5 to get vertical resolution - .aspect.16.9 equ 3 << 6 ;mul horizontal by 9, shr by 4 to get vertical resolution - .descriptorblock1 resb 18 - .descriptorblock2 resb 18 - .descriptorblock3 resb 18 - .descriptorblock4 resb 18 - .extensionflag resb 1 - .checksum resb 1 \ No newline at end of file diff --git a/bootstrap.sh b/bootstrap.sh old mode 100644 new mode 100755 index 7e1c9a8..3f892e4 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -4,7 +4,7 @@ # This function is simply a banner to introduce the script ########################################################## banner() -{ +{ echo "|------------------------------------------|" echo "|----- Welcome to the redox bootstrap -----|" echo "|------------------------------------------|" @@ -26,7 +26,7 @@ install_macos_pkg() BIN_NAME=$PKG_NAME fi - BIN_LOCATION=$(which $BIN_NAME) + BIN_LOCATION=$(which $BIN_NAME || true) if [ -z "$BIN_LOCATION" ]; then echo "$PKG_MANAGER install $PKG_NAME" $PKG_MANAGER install "$PKG_NAME" @@ -53,7 +53,7 @@ install_brew_cask_pkg() ############################################################################### # This function checks which of the supported package managers # is available on the OSX Host. -# If a support package manager is found, it delegates the installing work to +# If a supported package manager is found, it delegates the installing work to # the relevant function. # Otherwise this function will exit this script with an error. ############################################################################### @@ -66,7 +66,7 @@ osx() elif [ ! -z "$(which port)" ]; then osx_macports $@ else - echo "Please install either Hombrew or MacPorts, if you wish to use this script" + echo "Please install either Homebrew or MacPorts, if you wish to use this script" echo "Re-run this script once you installed one of those package managers" echo "Will not install, now exiting..." exit 1 @@ -93,6 +93,8 @@ osx_macports() install_macports_pkg "virtualbox" fi + install_macports_pkg "coreutils" + install_macports_pkg "findutils" install_macports_pkg "gcc49" "gcc-4.9" install_macports_pkg "nasm" install_macports_pkg "pkgconfig" @@ -101,7 +103,7 @@ osx_macports() } ############################################################################### -# This function takes care of installing all dependencies using Hombrew +# This function takes care of installing all dependencies using Homebrew # for building redox on Mac OSX # @params: $1 the emulator to install, virtualbox or qemu ############################################################################### @@ -110,10 +112,6 @@ osx_homebrew() echo "Homebrew detected! Now updating..." brew update - echo "Tapping required taps..." - brew tap homebrew/versions - brew tap glendc/gcc_cross_compilers - echo "Installing missing packages..." install_brew_pkg "git" @@ -124,13 +122,14 @@ osx_homebrew() install_brew_pkg "virtualbox" fi + install_brew_pkg "coreutils" + install_brew_pkg "findutils" install_brew_pkg "gcc49" "gcc-4.9" install_brew_pkg "nasm" install_brew_pkg "pkg-config" install_brew_cask_pkg "osxfuse" - install_brew_pkg "glendc/gcc_cross_compilers/x64-elf-binutils" "x86_64-elf-gcc" - install_brew_pkg "glendc/gcc_cross_compilers/x64-elf-gcc" "x86_64-elf-gcc" + install_brew_pkg "redox-os/gcc_cross_compilers/x86_64-elf-gcc" } ############################################################################### @@ -155,7 +154,7 @@ archLinux() fi if [ "$1" == "qemu" ]; then - if [ -z "$(which qemu-system-i386)" ]; then + if [ -z "$(which qemu-system-x86_64)" ]; then echo "Installing QEMU..." sudo pacman -S qemu else @@ -164,14 +163,14 @@ archLinux() fi echo "Installing fuse..." - sudo pacman -S fuse + sudo pacman -S --needed fuse } ############################################################################### # This function takes care of installing all dependencies for building redox on # debian based linux # @params: $1 the emulator to install, virtualbox or qemu -# $2 the package manager to use +# $2 the package manager to use ############################################################################### ubuntu() { @@ -179,9 +178,9 @@ ubuntu() echo "Updating system..." sudo "$2" update echo "Installing required packages..." - sudo "$2" install build-essential libc6-dev-i386 nasm curl file git libfuse-dev + sudo "$2" install build-essential libc6-dev-i386 nasm curl file git libfuse-dev fuse pkg-config if [ "$1" == "qemu" ]; then - if [ -z "$(which qemu-system-i386)" ]; then + if [ -z "$(which qemu-system-x86_64)" ]; then echo "Installing QEMU..." sudo "$2" install qemu-system-x86 qemu-kvm else @@ -210,7 +209,7 @@ fedora() sudo dnf install git-all fi if [ "$1" == "qemu" ]; then - if [ -z "$(which qemu-system-i386)" ]; then + if [ -z "$(which qemu-system-x86_64)" ]; then echo "Installing QEMU..." sudo dnf install qemu-system-x86 qemu-kvm else @@ -241,13 +240,13 @@ fedora() ############################################################################### suse() { - echo "Detected a suse" + echo "Detected SUSE Linux" if [ -z "$(which git)" ]; then echo "Installing git..." zypper install git fi if [ "$1" == "qemu" ]; then - if [ -z "$(which qemu-system-i386)" ]; then + if [ -z "$(which qemu-system-x86_64)" ]; then echo "Installing QEMU..." sudo zypper install qemu-x86 qemu-kvm else @@ -263,7 +262,7 @@ suse() fi fi echo "Installing necessary build tools..." - sudo zypper install gcc gcc-c++ glibc-devel-32bit nasm make libfuse + sudo zypper install gcc gcc-c++ glibc-devel-32bit nasm make fuse-devel } ############################################################################## @@ -282,12 +281,14 @@ gentoo() echo "Installing git..." sudo emerge dev-vcs/git fi - echo "Installing fuse..." - sudo emerge sys-fs/fuse + if [ -z "$(which fusermount)" ]; then + echo "Installing fuse..." + sudo emerge sys-fs/fuse + fi if [ "$2" == "qemu" ]; then - if [ -z "$(which qemu-system-i386)" ]; then + if [ -z "$(which qemu-system-x86_64)" ]; then echo "Please install QEMU and re-run this script" - echo "Step1. Add QEMU_SOFTMMU_TARGETS=\"i386\" to /etc/portage/make.conf" + echo "Step1. Add QEMU_SOFTMMU_TARGETS=\"x86_64\" to /etc/portage/make.conf" echo "Step2. Execute \"sudo emerge app-emulation/qemu\"" else echo "QEMU already installed!" @@ -303,18 +304,9 @@ gentoo() solus() { echo "Detected SolusOS" - if [ -z "$(which nasm)" ]; then - echo "Installing nasm..." - sudo eopkg it nasm - fi - if [ -z "$(which git)" ]; then - echo "Installing git..." - sudo eopkg it git - fi - echo "Installing fuse..." - sudo eopkg it fuse-devel + if [ "$1" == "qemu" ]; then - if [ -z "$(which qemu-system-i386)" ]; then + if [ -z "$(which qemu-system-x86_64)" ]; then sudo eopkg it qemu else echo "QEMU already installed!" @@ -328,6 +320,10 @@ solus() echo "Virtualbox already installed!" fi fi + + echo "Installing necessary build tools..." + #if guards are not necessary with eopkg since it does nothing if latest version is already installed + sudo eopkg it fuse-devel git gcc g++ libgcc-32bit libstdc++-32bit nasm make } ###################################################################### @@ -348,16 +344,16 @@ usage() echo " -e [emulator] Install specific emulator, virtualbox or qemu" echo " -p [package Choose an Ubuntu package manager, apt-fast or" echo " manager] aptitude" - echo " -d Only install the dependencies, skip boot step" + echo " -d Only install the dependencies, skip boot step" echo "EXAMPLES:" echo - echo "./bootstrap.sh -b buddy -e qemu" + echo "./bootstrap.sh -e qemu" exit } #################################################################################### # This function takes care of everything associated to rust, and the version manager -# That controls it, it can install rustup and uninstall multirust as well as making +# That controls it, it can install rustup and uninstall multirust as well as making # sure that the correct version of rustc is selected by rustup #################################################################################### rustInstall() { @@ -370,7 +366,7 @@ rustInstall() { printf "Uninstall multirust (y/N):" read multirust if echo "$multirust" | grep -iq "^y" ;then - sudo /usr/local/lib/rustlib/uninstall.sh + sudo /usr/local/lib/rustlib/uninstall.sh else echo "Please manually uninstall multirust and any other versions of rust, then re-run bootstrap." exit @@ -378,10 +374,10 @@ rustInstall() { else echo "Old multirust not installed, you are good to go." fi - # If rustup is not installed we should offer to install it for them + # If rustup is not installed we should offer to install it for them if [ -z "$(which rustup)" ]; then echo "You do not have rustup installed." - echo "We HIGHLY reccomend using rustup." + echo "We HIGHLY recommend using rustup." echo "Would you like to install it now?" echo "*WARNING* this involves a 'curl | sh' style command" printf "(y/N): " @@ -389,22 +385,22 @@ rustInstall() { if echo "$rustup" | grep -iq "^y" ;then #install rustup curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly - # You have to add the rustup variables to the $PATH + # You have to add the rustup variables to the $PATH echo "export PATH=\"\$HOME/.cargo/bin:\$PATH\"" >> ~/.bashrc # source the variables so that we can execute rustup commands in the current shell - source ~/.cargo/env + source ~/.cargo/env rustup default nightly else echo "Rustup will not be installed!" fi - fi - # + fi + # if [ -z "$(which rustc)" ]; then echo "Rust is not installed" echo "Please either run the script again, accepting rustup install" - echo "or install rustc nightly manually (not reccomended) via:" + echo "or install rustc nightly manually (not recommended) via:" echo "\#curl -sSf https://static.rust-lang.org/rustup.sh | sh -s -- --channel=nightly" - exit + exit fi # If the system has rustup installed then update rustc to the latest nightly if hash 2>/dev/null rustup; then @@ -415,8 +411,8 @@ rustInstall() { if echo "$(rustc --version)" | grep -viq "nightly" ;then echo "It appears that you have rust installed, but it" echo "is not the nightly version, please either install" - echo "the nightly manually (not reccomended) or run this" - echo "script again, accepting the multirust install" + echo "the nightly manually (not recommended) or run this" + echo "script again, accepting the rustup install" echo else echo "Your rust install looks good!" @@ -425,7 +421,7 @@ rustInstall() { } #################################################################### -# This function gets the current build status from travis and prints +# This function gets the current build status from travis and prints # a message to the user #################################################################### statusCheck() { @@ -435,14 +431,14 @@ statusCheck() { if echo "$i" | grep -iq "0" ;then echo echo "********************************************" - echo "Travis reports that the last build succeded!" + echo "Travis reports that the last build succeeded!" echo "Looks like you are good to go!" echo "********************************************" elif echo "$i" | grep -iq "null" ;then echo - echo "******************************************************************" + echo "******************************************************************" echo "The Travis build did not finish, this is an error with its config." - echo "I cannot reliably determine whether the build is succeding or not." + echo "I cannot reliably determine whether the build is succeeding or not." echo "Consider checking for and maybe opening an issue on github" echo "******************************************************************" else @@ -463,7 +459,7 @@ statusCheck() { boot() { echo "Cloning github repo..." - git clone https://github.com/redox-os/redox.git --origin upstream --recursive + git clone https://github.com/redox-os/redox.git --origin upstream --recursive rustInstall echo "Cleaning up..." rm bootstrap.sh @@ -511,7 +507,7 @@ banner if [ "Darwin" == "$(uname -s)" ]; then osx "$emulator" else - # Here we will user package managers to determine which operating system the user is using + # Here we will user package managers to determine which operating system the user is using # Arch linux if hash 2>/dev/null pacman; then archLinux "$emulator" diff --git a/cookbook b/cookbook new file mode 160000 index 0000000..5f961f8 --- /dev/null +++ b/cookbook @@ -0,0 +1 @@ +Subproject commit 5f961f888b8cc32266f63713073ad13c1983e3e0 diff --git a/crates/dma/Cargo.toml b/crates/dma/Cargo.toml deleted file mode 100644 index 24c1b8e..0000000 --- a/crates/dma/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "dma" -version = "0.1.0" - -[dependencies] -redox_syscall = { path = "../../syscall/" } diff --git a/crates/dma/src/lib.rs b/crates/dma/src/lib.rs deleted file mode 100644 index 557b60a..0000000 --- a/crates/dma/src/lib.rs +++ /dev/null @@ -1,78 +0,0 @@ -extern crate syscall; - -use std::{mem, ptr}; -use std::ops::{Deref, DerefMut}; - -use syscall::Result; - -struct PhysBox { - address: usize, - size: usize -} - -impl PhysBox { - fn new(size: usize) -> Result { - let address = unsafe { syscall::physalloc(size)? }; - Ok(PhysBox { - address: address, - size: size - }) - } -} - -impl Drop for PhysBox { - fn drop(&mut self) { - let _ = unsafe { syscall::physfree(self.address, self.size) }; - } -} - -pub struct Dma { - phys: PhysBox, - virt: *mut T -} - -impl Dma { - pub fn new(value: T) -> Result> { - let phys = PhysBox::new(mem::size_of::())?; - let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; - unsafe { ptr::write(virt, value); } - Ok(Dma { - phys: phys, - virt: virt - }) - } - - pub fn zeroed() -> Result> { - let phys = PhysBox::new(mem::size_of::())?; - let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; - unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); } - Ok(Dma { - phys: phys, - virt: virt - }) - } - - pub fn physical(&self) -> usize { - self.phys.address - } -} - -impl Deref for Dma { - type Target = T; - fn deref(&self) -> &T { - unsafe { &*self.virt } - } -} - -impl DerefMut for Dma { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.virt } - } -} - -impl Drop for Dma { - fn drop(&mut self) { - unsafe { drop(ptr::read(self.virt)); } - let _ = unsafe { syscall::physunmap(self.virt as usize) }; - } -} diff --git a/crates/docgen b/crates/docgen deleted file mode 160000 index 2e1bcf2..0000000 --- a/crates/docgen +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2e1bcf2ab5a03d176e7c66ae79c31ffccdcda77a diff --git a/crates/event/Cargo.toml b/crates/event/Cargo.toml deleted file mode 100644 index d382ece..0000000 --- a/crates/event/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "event" -version = "0.1.0" - -[dependencies] -redox_syscall = { path = "../../syscall/" } diff --git a/crates/event/src/lib.rs b/crates/event/src/lib.rs deleted file mode 100644 index a3662a0..0000000 --- a/crates/event/src/lib.rs +++ /dev/null @@ -1,83 +0,0 @@ -extern crate syscall; - -use std::collections::BTreeMap; -use std::fs::File; -use std::io::{Read, Error, Result}; -use std::os::unix::io::RawFd; - -pub struct EventQueue { - /// The file to read events from - file: File, - /// A map of registered file descriptors to their handler callbacks - callbacks: BTreeMap Result>>> -} - -impl EventQueue { - /// Create a new event queue - pub fn new() -> Result> { - Ok(EventQueue { - file: File::open("event:")?, - callbacks: BTreeMap::new() - }) - } - - /// Add a file to the event queue, calling a callback when an event occurs - /// - /// The callback is given a mutable reference to the file and the event data - /// (typically the length of data available for read) - /// - /// The callback returns Ok(None) if it wishes to continue the event loop, - /// or Ok(Some(R)) to break the event loop and return the value. - /// Err can be used to allow the callback to return an I/O error, and break the - /// event loop - pub fn add Result> + 'static>(&mut self, fd: RawFd, callback: F) -> Result<()> { - syscall::fevent(fd, syscall::EVENT_READ).map_err(|x| Error::from_raw_os_error(x.errno))?; - - self.callbacks.insert(fd, Box::new(callback)); - - Ok(()) - } - - /// Remove a file from the event queue, returning its callback if found - pub fn remove(&mut self, fd: RawFd) -> Result Result>>>> { - if let Some(callback) = self.callbacks.remove(&fd) { - syscall::fevent(fd, 0).map_err(|x| Error::from_raw_os_error(x.errno))?; - - Ok(Some(callback)) - } else { - Ok(None) - } - } - - /// Send an event to a descriptor callback - pub fn trigger(&mut self, fd: RawFd, count: usize) -> Result> { - if let Some(callback) = self.callbacks.get_mut(&fd) { - callback(count) - } else { - Ok(None) - } - } - - /// Send an event to all descriptor callbacks, useful for cleaning out buffers after init - pub fn trigger_all(&mut self, count: usize) -> Result> { - let mut rets = Vec::new(); - for (_fd, callback) in self.callbacks.iter_mut() { - if let Some(ret) = callback(count)? { - rets.push(ret); - } - } - Ok(rets) - } - - /// Process the event queue until a callback returns Some(R) - pub fn run(&mut self) -> Result { - loop { - let mut event = syscall::Event::default(); - if self.file.read(&mut event)? > 0 { - if let Some(ret) = self.trigger(event.id, event.data)? { - return Ok(ret); - } - } - } - } -} diff --git a/crates/hole_list_allocator/Cargo.toml b/crates/hole_list_allocator/Cargo.toml deleted file mode 100644 index 5ef3a50..0000000 --- a/crates/hole_list_allocator/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -authors = ["Philipp Oppermann "] -name = "hole_list_allocator" -version = "0.1.0" - -[dependencies] -linked_list_allocator = { git = "https://github.com/phil-opp/linked-list-allocator.git" } -spin = "*" diff --git a/crates/hole_list_allocator/src/lib.rs b/crates/hole_list_allocator/src/lib.rs deleted file mode 100644 index df90843..0000000 --- a/crates/hole_list_allocator/src/lib.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![feature(allocator)] -#![feature(const_fn)] - -#![allocator] -#![no_std] - -use spin::Mutex; -use linked_list_allocator::Heap; - -extern crate spin; -extern crate linked_list_allocator; - -static HEAP: Mutex> = Mutex::new(None); - -pub unsafe fn init(offset: usize, size: usize) { - *HEAP.lock() = Some(Heap::new(offset, size)); -} - -#[no_mangle] -pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 { - if let Some(ref mut heap) = *HEAP.lock() { - heap.allocate_first_fit(size, align).expect("out of memory") - } else { - panic!("__rust_allocate: heap not initialized"); - } -} - -#[no_mangle] -pub extern fn __rust_deallocate(ptr: *mut u8, size: usize, align: usize) { - if let Some(ref mut heap) = *HEAP.lock() { - unsafe { heap.deallocate(ptr, size, align) }; - } else { - panic!("__rust_deallocate: heap not initialized"); - } -} - -#[no_mangle] -pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { - size -} - -#[no_mangle] -pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, size: usize, - _new_size: usize, _align: usize) -> usize -{ - size -} - -#[no_mangle] -pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize, - align: usize) -> *mut u8 { - use core::{ptr, cmp}; - - // from: https://github.com/rust-lang/rust/blob/ - // c66d2380a810c9a2b3dbb4f93a830b101ee49cc2/ - // src/liballoc_system/lib.rs#L98-L101 - - let new_ptr = __rust_allocate(new_size, align); - unsafe { ptr::copy(ptr, new_ptr, cmp::min(size, new_size)) }; - __rust_deallocate(ptr, size, align); - new_ptr -} diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml deleted file mode 100644 index b0ee40b..0000000 --- a/crates/io/Cargo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[package] -name = "io" -version = "0.1.0" diff --git a/crates/io/src/io.rs b/crates/io/src/io.rs deleted file mode 100644 index fb866b5..0000000 --- a/crates/io/src/io.rs +++ /dev/null @@ -1,67 +0,0 @@ -use core::cmp::PartialEq; -use core::ops::{BitAnd, BitOr, Not}; - -pub trait Io { - type Value: Copy + PartialEq + BitAnd + BitOr + Not; - - fn read(&self) -> Self::Value; - fn write(&mut self, value: Self::Value); - - #[inline(always)] - fn readf(&self, flags: Self::Value) -> bool { - (self.read() & flags) as Self::Value == flags - } - - #[inline(always)] - fn writef(&mut self, flags: Self::Value, value: bool) { - let tmp: Self::Value = match value { - true => self.read() | flags, - false => self.read() & !flags, - }; - self.write(tmp); - } -} - -pub struct ReadOnly { - inner: I -} - -impl ReadOnly { - pub const fn new(inner: I) -> ReadOnly { - ReadOnly { - inner: inner - } - } - - #[inline(always)] - pub fn read(&self) -> I::Value { - self.inner.read() - } - - #[inline(always)] - pub fn readf(&self, flags: I::Value) -> bool { - self.inner.readf(flags) - } -} - -pub struct WriteOnly { - inner: I -} - -impl WriteOnly { - pub const fn new(inner: I) -> WriteOnly { - WriteOnly { - inner: inner - } - } - - #[inline(always)] - pub fn write(&mut self, value: I::Value) { - self.inner.write(value) - } - - #[inline(always)] - pub fn writef(&mut self, flags: I::Value, value: bool) { - self.inner.writef(flags, value) - } -} diff --git a/crates/io/src/lib.rs b/crates/io/src/lib.rs deleted file mode 100644 index 22f8eb7..0000000 --- a/crates/io/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! I/O functions - -#![feature(asm)] -#![feature(const_fn)] -#![feature(core_intrinsics)] -#![no_std] - -pub use self::io::*; -pub use self::mmio::*; -pub use self::pio::*; - -mod io; -mod mmio; -mod pio; diff --git a/crates/io/src/mmio.rs b/crates/io/src/mmio.rs deleted file mode 100644 index 1a1d199..0000000 --- a/crates/io/src/mmio.rs +++ /dev/null @@ -1,31 +0,0 @@ -use core::intrinsics::{volatile_load, volatile_store}; -use core::mem::uninitialized; -use core::ops::{BitAnd, BitOr, Not}; - -use super::io::Io; - -#[repr(packed)] -pub struct Mmio { - value: T, -} - -impl Mmio { - /// Create a new Mmio without initializing - pub fn new() -> Self { - Mmio { - value: unsafe { uninitialized() } - } - } -} - -impl Io for Mmio where T: Copy + PartialEq + BitAnd + BitOr + Not { - type Value = T; - - fn read(&self) -> T { - unsafe { volatile_load(&self.value) } - } - - fn write(&mut self, value: T) { - unsafe { volatile_store(&mut self.value, value) }; - } -} diff --git a/crates/io/src/pio.rs b/crates/io/src/pio.rs deleted file mode 100644 index 91ae310..0000000 --- a/crates/io/src/pio.rs +++ /dev/null @@ -1,89 +0,0 @@ -use core::marker::PhantomData; - -use super::io::Io; - -/// Generic PIO -#[derive(Copy, Clone)] -pub struct Pio { - port: u16, - value: PhantomData, -} - -impl Pio { - /// Create a PIO from a given port - pub const fn new(port: u16) -> Self { - Pio:: { - port: port, - value: PhantomData, - } - } -} - -/// Read/Write for byte PIO -impl Io for Pio { - type Value = u8; - - /// Read - #[inline(always)] - fn read(&self) -> u8 { - let value: u8; - unsafe { - asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - value - } - - /// Write - #[inline(always)] - fn write(&mut self, value: u8) { - unsafe { - asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - } -} - -/// Read/Write for word PIO -impl Io for Pio { - type Value = u16; - - /// Read - #[inline(always)] - fn read(&self) -> u16 { - let value: u16; - unsafe { - asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - value - } - - /// Write - #[inline(always)] - fn write(&mut self, value: u16) { - unsafe { - asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - } -} - -/// Read/Write for doubleword PIO -impl Io for Pio { - type Value = u32; - - /// Read - #[inline(always)] - fn read(&self) -> u32 { - let value: u32; - unsafe { - asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - value - } - - /// Write - #[inline(always)] - fn write(&mut self, value: u32) { - unsafe { - asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - } -} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100755 index 0000000..b59fae3 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,43 @@ +FROM ubuntu:17.04 + +ENV USER user +ARG LOCAL_UID=local +ARG LOCAL_GID=local +ENV BUILD_UID=${LOCAL_UID:-9001} +ENV BUILD_GID=${LOCAL_GID:-9001} + +RUN apt-get update \ + && apt-get install -y dirmngr git gosu gcc fuse nasm qemu-utils pkg-config \ + libfuse-dev make curl wget file sudo apt-transport-https autoconf flex \ + bison texinfo \ + && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys AA12E97F0881517F \ + && echo "deb https://static.redox-os.org/toolchain/apt/ /" >> /etc/apt/sources.list.d/redox.list \ + && apt-get update -o Dir::Etc::sourcelist="redox.list" \ + && apt-get install -y x86-64-unknown-redox-newlib x86-64-unknown-redox-binutils x86-64-unknown-redox-gcc \ + && groupadd -g $BUILD_GID user \ + && useradd --shell /bin/bash -u $BUILD_UID -g $BUILD_GID -o -c "" -m $USER \ + && echo "$USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/user-no-sudo-password + +COPY entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +USER $USER +ENV HOME /home/$USER +ENV PATH $HOME/.cargo/bin:$PATH +ENV SRC_PATH $HOME/src +WORKDIR $HOME +RUN curl https://sh.rustup.rs > sh.rustup.rs \ + && sh sh.rustup.rs -y \ + && rustup update \ + && rustup component add rust-src \ + && rustup default nightly \ + && curl -O https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.gz \ + && tar -xvpf automake-1.15.1.tar.gz; cd automake-1.15.1; ./configure; make; sudo make install; cd .. \ + && cargo install xargo \ + && cargo install cargo-config \ + && mkdir -p $SRC_PATH + +WORKDIR $SRC_PATH +USER root + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..93cc9d7 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,29 @@ +### Building Redox using Docker images with the toolchain + +*All you need is git, make, qemu, fuse and docker. The method requires a non-privileged user able to run the `docker` command, which is usually achieved by adding the user to the `docker` group.* + +```shell +git clone https://github.com/redox-os/redox.git ; cd redox #1 +docker build --build-arg LOCAL_UID="$(id -u)" --build-arg LOCAL_GID="$(id -g)" \ + -t redox docker/ #2 +git pull --rebase --recurse-submodules && git submodule sync \ + && git submodule update --recursive --init #3 +docker run --cap-add MKNOD --cap-add SYS_ADMIN \ + -e LOCAL_UID="$(id -u)" -e LOCAL_GID="$(id -g)" \ + --device /dev/fuse -v "$(pwd):/home/user/src" --rm redox make fetch all #4 +make qemu #5 +``` +To unpack: +1. Creates a local copy of the repository. +2. Creates a new image in the local image repository named `redox` with Redox toolchain installed. You only need to rebuild the image if you want to update the toolchain. +3. Updates all the submodules in the repository. +4. Builds Redox using the `redox` image. The arguments allow the container to use `fuse` and ensure the resulting files are owned by the current user. +5. Runs Redox. + +On selinux systems, replace #4 with: +``` +docker run --cap-add MKNOD --cap-add SYS_ADMIN \ + -e LOCAL_UID="$(id -u)" -e LOCAL_GID="$(id -g)" \ + --device /dev/fuse -v "$(pwd):/home/user/src" --security-opt label=disable \ + --rm redox make fetch all +``` diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 0000000..d47300e --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +# Use -e LOCAL_UID="$(id -u)" -e LOCAL_GID="$(id -g)" +# on the docker run command line if the container build user is different +# from the run user + +CONT_UID=`id -u user` +CONT_GID=`id -g user` +RUN_UID=${LOCAL_UID:-$CONT_UID} +RUN_GID=${LOCAL_GID:-$CONT_GID} + +if [ $RUN_UID != $CONT_UID ] || [ $RUN_GID != $CONT_GID ]; then + echo -e "\033[01;38;5;155mChanging user id:group to ${RUN_UID}:${RUN_GID}. Please wait...\033[0m" + groupmod -g $RUN_GID user + usermod -u $RUN_UID -g $RUN_GID user +fi + +exec gosu user:user "$@" diff --git a/drivers/ahcid/Cargo.toml b/drivers/ahcid/Cargo.toml deleted file mode 100644 index f718331..0000000 --- a/drivers/ahcid/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "ahcid" -version = "0.1.0" - -[dependencies] -bitflags = "*" -dma = { path = "../../crates/dma/" } -io = { path = "../../crates/io/" } -spin = "*" -redox_syscall = { path = "../../syscall/" } diff --git a/drivers/ahcid/src/ahci/disk.rs b/drivers/ahcid/src/ahci/disk.rs deleted file mode 100644 index f28d5e8..0000000 --- a/drivers/ahcid/src/ahci/disk.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::ptr; - -use dma::Dma; -use syscall::error::Result; - -use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; - -pub struct Disk { - id: usize, - port: &'static mut HbaPort, - size: u64, - clb: Dma<[HbaCmdHeader; 32]>, - ctbas: [Dma; 32], - fb: Dma<[u8; 256]>, - buf: Dma<[u8; 256 * 512]> -} - -impl Disk { - pub fn new(id: usize, port: &'static mut HbaPort) -> Result { - let mut clb = Dma::zeroed()?; - let mut ctbas = [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - ]; - let mut fb = Dma::zeroed()?; - let buf = Dma::zeroed()?; - - port.init(&mut clb, &mut ctbas, &mut fb); - - let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) }; - - Ok(Disk { - id: id, - port: port, - size: size, - clb: clb, - ctbas: ctbas, - fb: fb, - buf: buf - }) - } - - pub fn id(&self) -> usize { - self.id - } - - pub fn size(&self) -> u64 { - self.size - } - - pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { - let sectors = buffer.len()/512; - - let mut sector: usize = 0; - while sectors - sector >= 255 { - if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } - - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); } - - sector += 255; - } - if sector < sectors { - if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } - - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); } - - sector += sectors - sector; - } - - Ok(sector * 512) - } - - pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result { - let sectors = buffer.len()/512; - - let mut sector: usize = 0; - while sectors - sector >= 255 { - unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); } - - if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } - - sector += 255; - } - if sector < sectors { - unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); } - - if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } - - sector += sectors - sector; - } - - Ok(sector * 512) - } -} diff --git a/drivers/ahcid/src/ahci/fis.rs b/drivers/ahcid/src/ahci/fis.rs deleted file mode 100644 index 7dbe33c..0000000 --- a/drivers/ahcid/src/ahci/fis.rs +++ /dev/null @@ -1,155 +0,0 @@ -use io::Mmio; - -#[repr(u8)] -pub enum FisType { - /// Register FIS - host to device - RegH2D = 0x27, - /// Register FIS - device to host - RegD2H = 0x34, - /// DMA activate FIS - device to host - DmaAct = 0x39, - /// DMA setup FIS - bidirectional - DmaSetup = 0x41, - /// Data FIS - bidirectional - Data = 0x46, - /// BIST activate FIS - bidirectional - Bist = 0x58, - /// PIO setup FIS - device to host - PioSetup = 0x5F, - /// Set device bits FIS - device to host - DevBits = 0xA1 -} - -#[repr(packed)] -pub struct FisRegH2D { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_REG_H2D - - pub pm: Mmio, // Port multiplier, 1: Command, 0: Control - - pub command: Mmio, // Command register - pub featurel: Mmio, // Feature register, 7:0 - - // DWORD 1 - pub lba0: Mmio, // LBA low register, 7:0 - pub lba1: Mmio, // LBA mid register, 15:8 - pub lba2: Mmio, // LBA high register, 23:16 - pub device: Mmio, // Device register - - // DWORD 2 - pub lba3: Mmio, // LBA register, 31:24 - pub lba4: Mmio, // LBA register, 39:32 - pub lba5: Mmio, // LBA register, 47:40 - pub featureh: Mmio, // Feature register, 15:8 - - // DWORD 3 - pub countl: Mmio, // Count register, 7:0 - pub counth: Mmio, // Count register, 15:8 - pub icc: Mmio, // Isochronous command completion - pub control: Mmio, // Control register - - // DWORD 4 - pub rsv1: [Mmio; 4], // Reserved -} - -#[repr(packed)] -pub struct FisRegD2H { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_REG_D2H - - pub pm: Mmio, // Port multiplier, Interrupt bit: 2 - - pub status: Mmio, // Status register - pub error: Mmio, // Error register - - // DWORD 1 - pub lba0: Mmio, // LBA low register, 7:0 - pub lba1: Mmio, // LBA mid register, 15:8 - pub lba2: Mmio, // LBA high register, 23:16 - pub device: Mmio, // Device register - - // DWORD 2 - pub lba3: Mmio, // LBA register, 31:24 - pub lba4: Mmio, // LBA register, 39:32 - pub lba5: Mmio, // LBA register, 47:40 - pub rsv2: Mmio, // Reserved - - // DWORD 3 - pub countl: Mmio, // Count register, 7:0 - pub counth: Mmio, // Count register, 15:8 - pub rsv3: [Mmio; 2], // Reserved - - // DWORD 4 - pub rsv4: [Mmio; 4], // Reserved -} - -#[repr(packed)] -pub struct FisData { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_DATA - - pub pm: Mmio, // Port multiplier - - pub rsv1: [Mmio; 2], // Reserved - - // DWORD 1 ~ N - pub data: [Mmio; 252], // Payload -} - -#[repr(packed)] -pub struct FisPioSetup { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_PIO_SETUP - - pub pm: Mmio, // Port multiplier, direction: 4 - device to host, interrupt: 2 - - pub status: Mmio, // Status register - pub error: Mmio, // Error register - - // DWORD 1 - pub lba0: Mmio, // LBA low register, 7:0 - pub lba1: Mmio, // LBA mid register, 15:8 - pub lba2: Mmio, // LBA high register, 23:16 - pub device: Mmio, // Device register - - // DWORD 2 - pub lba3: Mmio, // LBA register, 31:24 - pub lba4: Mmio, // LBA register, 39:32 - pub lba5: Mmio, // LBA register, 47:40 - pub rsv2: Mmio, // Reserved - - // DWORD 3 - pub countl: Mmio, // Count register, 7:0 - pub counth: Mmio, // Count register, 15:8 - pub rsv3: Mmio, // Reserved - pub e_status: Mmio, // New value of status register - - // DWORD 4 - pub tc: Mmio, // Transfer count - pub rsv4: [Mmio; 2], // Reserved -} - -#[repr(packed)] -pub struct FisDmaSetup { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_DMA_SETUP - - pub pm: Mmio, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1 - - pub rsv1: [Mmio; 2], // Reserved - - // DWORD 1&2 - pub dma_buffer_id: Mmio, /* DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */ - - // DWORD 3 - pub rsv3: Mmio, // More reserved - - // DWORD 4 - pub dma_buffer_offset: Mmio, // Byte offset into buffer. First 2 bits must be 0 - - // DWORD 5 - pub transfer_count: Mmio, // Number of bytes to transfer. Bit 0 must be 0 - - // DWORD 6 - pub rsv6: Mmio, // Reserved -} diff --git a/drivers/ahcid/src/ahci/hba.rs b/drivers/ahcid/src/ahci/hba.rs deleted file mode 100644 index 1981847..0000000 --- a/drivers/ahcid/src/ahci/hba.rs +++ /dev/null @@ -1,417 +0,0 @@ -use std::mem::size_of; -use std::ops::DerefMut; -use std::{ptr, u32}; - -use dma::Dma; -use io::{Io, Mmio}; -use syscall::error::{Error, Result, EIO}; - -use super::fis::{FisType, FisRegH2D}; - -const ATA_CMD_READ_DMA_EXT: u8 = 0x25; -const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; -const ATA_CMD_IDENTIFY: u8 = 0xEC; -const ATA_DEV_BUSY: u8 = 0x80; -const ATA_DEV_DRQ: u8 = 0x08; - -const HBA_PORT_CMD_CR: u32 = 1 << 15; -const HBA_PORT_CMD_FR: u32 = 1 << 14; -const HBA_PORT_CMD_FRE: u32 = 1 << 4; -const HBA_PORT_CMD_ST: u32 = 1; -const HBA_PORT_IS_ERR: u32 = 1 << 30 | 1 << 29 | 1 << 28 | 1 << 27; -const HBA_SSTS_PRESENT: u32 = 0x3; -const HBA_SIG_ATA: u32 = 0x00000101; -const HBA_SIG_ATAPI: u32 = 0xEB140101; -const HBA_SIG_PM: u32 = 0x96690101; -const HBA_SIG_SEMB: u32 = 0xC33C0101; - -fn pause() { - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } -} - -#[derive(Debug)] -pub enum HbaPortType { - None, - Unknown(u32), - SATA, - SATAPI, - PM, - SEMB, -} - -#[repr(packed)] -pub struct HbaPort { - pub clb: [Mmio; 2], // 0x00, command list base address, 1K-byte aligned - pub fb: [Mmio; 2], // 0x08, FIS base address, 256-byte aligned - pub is: Mmio, // 0x10, interrupt status - pub ie: Mmio, // 0x14, interrupt enable - pub cmd: Mmio, // 0x18, command and status - pub _rsv0: Mmio, // 0x1C, Reserved - pub tfd: Mmio, // 0x20, task file data - pub sig: Mmio, // 0x24, signature - pub ssts: Mmio, // 0x28, SATA status (SCR0:SStatus) - pub sctl: Mmio, // 0x2C, SATA control (SCR2:SControl) - pub serr: Mmio, // 0x30, SATA error (SCR1:SError) - pub sact: Mmio, // 0x34, SATA active (SCR3:SActive) - pub ci: Mmio, // 0x38, command issue - pub sntf: Mmio, // 0x3C, SATA notification (SCR4:SNotification) - pub fbs: Mmio, // 0x40, FIS-based switch control - pub _rsv1: [Mmio; 11], // 0x44 ~ 0x6F, Reserved - pub vendor: [Mmio; 4], // 0x70 ~ 0x7F, vendor specific -} - -impl HbaPort { - pub fn probe(&self) -> HbaPortType { - if self.ssts.readf(HBA_SSTS_PRESENT) { - let sig = self.sig.read(); - match sig { - HBA_SIG_ATA => HbaPortType::SATA, - HBA_SIG_ATAPI => HbaPortType::SATAPI, - HBA_SIG_PM => HbaPortType::PM, - HBA_SIG_SEMB => HbaPortType::SEMB, - _ => HbaPortType::Unknown(sig), - } - } else { - HbaPortType::None - } - } - - pub fn start(&mut self) { - while self.cmd.readf(HBA_PORT_CMD_CR) { - pause(); - } - - self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true); - } - - pub fn stop(&mut self) { - self.cmd.writef(HBA_PORT_CMD_ST, false); - - while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { - pause(); - } - - self.cmd.writef(HBA_PORT_CMD_FRE, false); - } - - pub fn slot(&self) -> Option { - let slots = self.sact.read() | self.ci.read(); - for i in 0..32 { - if slots & 1 << i == 0 { - return Some(i); - } - } - None - } - - pub fn init(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], fb: &mut Dma<[u8; 256]>) { - self.stop(); - - for i in 0..32 { - let cmdheader = &mut clb[i]; - cmdheader.ctba.write(ctbas[i].physical() as u64); - cmdheader.prdtl.write(0); - } - - self.clb[0].write(clb.physical() as u32); - self.clb[1].write((clb.physical() >> 32) as u32); - self.fb[0].write(fb.physical() as u32); - self.fb[1].write((fb.physical() >> 32) as u32); - let is = self.is.read(); - self.is.write(is); - self.ie.write(0); - let serr = self.serr.read(); - self.serr.write(serr); - - // Disable power management - let sctl = self.sctl.read() ; - self.sctl.write(sctl | 7 << 8); - - // Power on and spin up device - self.cmd.writef(1 << 2 | 1 << 1, true); - - print!("{}", format!(" - AHCI init {:X}\n", self.cmd.read())); - } - - pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { - self.is.write(u32::MAX); - - let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); - - if let Some(slot) = self.slot() { - let cmdheader = &mut clb[slot as usize]; - cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); - cmdheader.prdtl.write(1); - - { - let cmdtbl = &mut ctbas[slot as usize]; - ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()); - - let prdt_entry = &mut cmdtbl.prdt_entry[0]; - prdt_entry.dba.write(dest.physical() as u64); - prdt_entry.dbc.write(512 | 1); - } - - { - let cmdfis = &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D); - - cmdfis.fis_type.write(FisType::RegH2D as u8); - cmdfis.pm.write(1 << 7); - cmdfis.command.write(ATA_CMD_IDENTIFY); - cmdfis.device.write(0); - cmdfis.countl.write(1); - cmdfis.counth.write(0); - } - - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - pause(); - } - - self.ci.writef(1 << slot, true); - - self.start(); - - while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { - pause(); - } - - self.stop(); - - if self.is.read() & HBA_PORT_IS_ERR != 0 { - print!("{}", format!("ERROR IS {:X} TFD {:X} SERR {:X}\n", self.is.read(), self.tfd.read(), self.serr.read())); - return None; - } - - let mut serial = String::new(); - for word in 10..20 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - serial.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - serial.push(b); - } - } - - let mut firmware = String::new(); - for word in 23..27 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - firmware.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - firmware.push(b); - } - } - - let mut model = String::new(); - for word in 27..47 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - model.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - model.push(b); - } - } - - let mut sectors = (dest[100] as u64) | - ((dest[101] as u64) << 16) | - ((dest[102] as u64) << 32) | - ((dest[103] as u64) << 48); - - let lba_bits = if sectors == 0 { - sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); - 28 - } else { - 48 - }; - - print!("{}", format!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB\n", - serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048)); - - Some(sectors * 512) - } else { - None - } - } - - pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { - if write { - //print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); - } - - assert!(sectors > 0 && sectors < 256); - - self.is.write(u32::MAX); - - if let Some(slot) = self.slot() { - if write { - //print!("{}", format!("SLOT {}\n", slot)); - } - - let cmdheader = &mut clb[slot as usize]; - - cmdheader.cfl.write(((size_of::() / size_of::()) as u8) | if write { 1 << 7 | 1 << 6 } else { 0 }); - - cmdheader.prdtl.write(1); - - { - let cmdtbl = &mut ctbas[slot as usize]; - unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()) }; - - let prdt_entry = &mut cmdtbl.prdt_entry[0]; - prdt_entry.dba.write(buf.physical() as u64); - prdt_entry.dbc.write(((sectors * 512) as u32) | 1); - } - - { - let cmdfis = unsafe { &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D) }; - - cmdfis.fis_type.write(FisType::RegH2D as u8); - cmdfis.pm.write(1 << 7); - if write { - cmdfis.command.write(ATA_CMD_WRITE_DMA_EXT); - } else { - cmdfis.command.write(ATA_CMD_READ_DMA_EXT); - } - - cmdfis.lba0.write(block as u8); - cmdfis.lba1.write((block >> 8) as u8); - cmdfis.lba2.write((block >> 16) as u8); - - cmdfis.device.write(1 << 6); - - cmdfis.lba3.write((block >> 24) as u8); - cmdfis.lba4.write((block >> 32) as u8); - cmdfis.lba5.write((block >> 40) as u8); - - cmdfis.countl.write(sectors as u8); - cmdfis.counth.write((sectors >> 8) as u8); - } - - if write { - //print!("WAIT ATA_DEV_BUSY | ATA_DEV_DRQ\n"); - } - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - pause(); - } - - if write { - //print!("{}", format!("WRITE CI {:X} in {:X}\n", 1 << slot, self.ci.read())); - } - self.ci.writef(1 << slot, true); - - self.start(); - - if write { - //print!("{}", format!("WAIT CI {:X} in {:X}\n", 1 << slot, self.ci.read())); - } - while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { - pause(); - if write { - //print!("{}", format!("WAIT CI {:X} TFD {:X} IS {:X} CMD {:X} SERR {:X}\n", self.ci.read(), self.tfd.read(), self.is.read(), self.cmd.read(), self.serr.read())); - } - } - - self.stop(); - - if self.is.read() & HBA_PORT_IS_ERR != 0 { - print!("{}", format!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}\n", - self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(), - self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(), - self.ci.read(), self.sntf.read(), self.fbs.read())); - self.is.write(u32::MAX); - return Err(Error::new(EIO)); - } - - if write { - //print!("{}", format!("SUCCESS {}\n", sectors)); - } - Ok(sectors * 512) - } else { - print!("No Command Slots\n"); - Err(Error::new(EIO)) - } - } -} - -#[repr(packed)] -pub struct HbaMem { - pub cap: Mmio, // 0x00, Host capability - pub ghc: Mmio, // 0x04, Global host control - pub is: Mmio, // 0x08, Interrupt status - pub pi: Mmio, // 0x0C, Port implemented - pub vs: Mmio, // 0x10, Version - pub ccc_ctl: Mmio, // 0x14, Command completion coalescing control - pub ccc_pts: Mmio, // 0x18, Command completion coalescing ports - pub em_loc: Mmio, // 0x1C, Enclosure management location - pub em_ctl: Mmio, // 0x20, Enclosure management control - pub cap2: Mmio, // 0x24, Host capabilities extended - pub bohc: Mmio, // 0x28, BIOS/OS handoff control and status - pub _rsv: [Mmio; 116], // 0x2C - 0x9F, Reserved - pub vendor: [Mmio; 96], // 0xA0 - 0xFF, Vendor specific registers - pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers -} - -impl HbaMem { - pub fn init(&mut self) { - /* - self.ghc.writef(1, true); - while self.ghc.readf(1) { - pause(); - } - */ - self.ghc.write(1 << 31 | 1 << 1); - - print!("{}", format!(" - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", - self.cap.read(), self.ghc.read(), self.is.read(), self.pi.read(), - self.vs.read(), self.cap2.read(), self.bohc.read())); - } -} - -#[repr(packed)] -pub struct HbaPrdtEntry { - dba: Mmio, // Data base address - _rsv0: Mmio, // Reserved - dbc: Mmio, // Byte count, 4M max, interrupt = 1 -} - -#[repr(packed)] -pub struct HbaCmdTable { - // 0x00 - cfis: [Mmio; 64], // Command FIS - - // 0x40 - acmd: [Mmio; 16], // ATAPI command, 12 or 16 bytes - - // 0x50 - _rsv: [Mmio; 48], // Reserved - - // 0x80 - prdt_entry: [HbaPrdtEntry; 65536], // Physical region descriptor table entries, 0 ~ 65535 -} - -#[repr(packed)] -pub struct HbaCmdHeader { - // DW0 - cfl: Mmio, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */ - pm: Mmio, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier - - prdtl: Mmio, // Physical region descriptor table length in entries - - // DW1 - prdbc: Mmio, // Physical region descriptor byte count transferred - - // DW2, 3 - ctba: Mmio, // Command table descriptor base address - - // DW4 - 7 - _rsv1: [Mmio; 4], // Reserved -} diff --git a/drivers/ahcid/src/ahci/mod.rs b/drivers/ahcid/src/ahci/mod.rs deleted file mode 100644 index fec9e00..0000000 --- a/drivers/ahcid/src/ahci/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -use io::Io; - -use self::disk::Disk; -use self::hba::{HbaMem, HbaPortType}; - -pub mod disk; -pub mod fis; -pub mod hba; - -pub fn disks(base: usize, name: &str) -> Vec { - unsafe { &mut *(base as *mut HbaMem) }.init(); - let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); - let ret: Vec = (0..32) - .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) - .filter_map(|i| { - let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; - let port_type = port.probe(); - print!("{}", format!("{}-{}: {:?}\n", name, i, port_type)); - match port_type { - HbaPortType::SATA => { - match Disk::new(i, port) { - Ok(disk) => Some(disk), - Err(err) => { - print!("{}", format!("{}: {}\n", i, err)); - None - } - } - } - _ => None, - } - }) - .collect(); - - ret -} diff --git a/drivers/ahcid/src/main.rs b/drivers/ahcid/src/main.rs deleted file mode 100644 index 1cd417c..0000000 --- a/drivers/ahcid/src/main.rs +++ /dev/null @@ -1,77 +0,0 @@ -#![feature(asm)] - -#[macro_use] -extern crate bitflags; -extern crate dma; -extern crate io; -extern crate spin; -extern crate syscall; - -use std::{env, usize}; -use std::fs::File; -use std::io::{Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd}; -use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme}; - -use scheme::DiskScheme; - -pub mod ahci; -pub mod scheme; - -fn main() { - let mut args = env::args().skip(1); - - let mut name = args.next().expect("ahcid: no name provided"); - name.push_str("_ahci"); - - let bar_str = args.next().expect("ahcid: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address"); - - let irq_str = args.next().expect("ahcid: no irq provided"); - let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); - - print!("{}", format!(" + AHCI {} on: {:X} IRQ: {}\n", name, bar, irq)); - - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; - { - let socket_fd = syscall::open(":disk", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ahcid: failed to create disk scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd) }; - syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme"); - - let mut irq_file = File::open(&format!("irq:{}", irq)).expect("ahcid: failed to open irq file"); - let irq_fd = irq_file.as_raw_fd(); - syscall::fevent(irq_fd, EVENT_READ).expect("ahcid: failed to fevent irq file"); - - let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); - - let scheme = DiskScheme::new(ahci::disks(address, &name)); - loop { - let mut event = Event::default(); - if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { - break; - } - if event.id == socket_fd { - loop { - let mut packet = Packet::default(); - if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 { - break; - } - scheme.handle(&mut packet); - socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); - } - } else if event.id == irq_fd { - let mut irq = [0; 8]; - if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { - //TODO : Test for IRQ - //irq_file.write(&irq).expect("ahcid: failed to write irq file"); - } - } else { - println!("Unknown event {}", event.id); - } - } - } - unsafe { let _ = syscall::physunmap(address); } - } -} diff --git a/drivers/ahcid/src/scheme.rs b/drivers/ahcid/src/scheme.rs deleted file mode 100644 index 96a7c20..0000000 --- a/drivers/ahcid/src/scheme.rs +++ /dev/null @@ -1,110 +0,0 @@ -use std::collections::BTreeMap; -use std::{cmp, str}; -use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; -use spin::Mutex; -use syscall::{Error, EACCES, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET}; - -use ahci::disk::Disk; - -pub struct DiskScheme { - disks: Box<[Arc>]>, - handles: Mutex>, usize)>>, - next_id: AtomicUsize -} - -impl DiskScheme { - pub fn new(disks: Vec) -> DiskScheme { - let mut disk_arcs = vec![]; - for disk in disks { - disk_arcs.push(Arc::new(Mutex::new(disk))); - } - - DiskScheme { - disks: disk_arcs.into_boxed_slice(), - handles: Mutex::new(BTreeMap::new()), - next_id: AtomicUsize::new(0) - } - } -} - -impl Scheme for DiskScheme { - fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { - if uid == 0 { - let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; - - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(i) { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, (disk.clone(), 0)); - Ok(id) - } else { - Err(Error::new(ENOENT)) - } - } else { - Err(Error::new(EACCES)) - } - } - - fn dup(&self, id: usize, _buf: &[u8]) -> Result { - let mut handles = self.handles.lock(); - let new_handle = { - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - handle.clone() - }; - - let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); - handles.insert(new_id, new_handle); - Ok(new_id) - } - - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles = self.handles.lock(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - stat.st_mode = MODE_FILE; - stat.st_size = handle.0.lock().size(); - Ok(0) - } - - fn read(&self, id: usize, buf: &mut [u8]) -> Result { - let mut handles = self.handles.lock(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let mut disk = handle.0.lock(); - let count = disk.read((handle.1 as u64)/512, buf)?; - handle.1 += count; - Ok(count) - } - - fn write(&self, id: usize, buf: &[u8]) -> Result { - let mut handles = self.handles.lock(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let mut disk = handle.0.lock(); - let count = disk.write((handle.1 as u64)/512, buf)?; - handle.1 += count; - Ok(count) - } - - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - let mut handles = self.handles.lock(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let len = handle.0.lock().size() as usize; - handle.1 = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(handle.1) - } - - fn close(&self, id: usize) -> Result { - let mut handles = self.handles.lock(); - handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) - } -} diff --git a/drivers/bgad/Cargo.toml b/drivers/bgad/Cargo.toml deleted file mode 100644 index cc9ce26..0000000 --- a/drivers/bgad/Cargo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[package] -name = "rtl8168d" -version = "0.1.0" diff --git a/drivers/bgad/src/main.rs b/drivers/bgad/src/main.rs deleted file mode 100644 index 48d75d7..0000000 --- a/drivers/bgad/src/main.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::env; - -fn main() { - let mut args = env::args().skip(1); - - let mut name = args.next().expect("bgad: no name provided"); - name.push_str("_bga"); - - let bar_str = args.next().expect("bgad: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("bgad: failed to parse address"); - - print!("{}", format!(" + BGA {} on: {:X}\n", name, bar)); -} diff --git a/drivers/e1000d/Cargo.toml b/drivers/e1000d/Cargo.toml deleted file mode 100644 index ec8c45e..0000000 --- a/drivers/e1000d/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "e1000d" -version = "0.1.0" - -[dependencies] -bitflags = "*" -dma = { path = "../../crates/dma/" } -event = { path = "../../crates/event/" } -io = { path = "../../crates/io/" } -netutils = { path = "../../programs/netutils/" } -redox_syscall = { path = "../../syscall/" } diff --git a/drivers/e1000d/src/device.rs b/drivers/e1000d/src/device.rs deleted file mode 100644 index fe2df01..0000000 --- a/drivers/e1000d/src/device.rs +++ /dev/null @@ -1,346 +0,0 @@ -use std::{cmp, mem, ptr, slice}; - -use dma::Dma; -use netutils::setcfg; -use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; -use syscall::flag::O_NONBLOCK; -use syscall::scheme::Scheme; - -const CTRL: u32 = 0x00; -const CTRL_LRST: u32 = 1 << 3; -const CTRL_ASDE: u32 = 1 << 5; -const CTRL_SLU: u32 = 1 << 6; -const CTRL_ILOS: u32 = 1 << 7; -const CTRL_VME: u32 = 1 << 30; -const CTRL_PHY_RST: u32 = 1 << 31; - -const STATUS: u32 = 0x08; - -const FCAL: u32 = 0x28; -const FCAH: u32 = 0x2C; -const FCT: u32 = 0x30; -const FCTTV: u32 = 0x170; - -const ICR: u32 = 0xC0; - -const IMS: u32 = 0xD0; -const IMS_TXDW: u32 = 1; -const IMS_TXQE: u32 = 1 << 1; -const IMS_LSC: u32 = 1 << 2; -const IMS_RXSEQ: u32 = 1 << 3; -const IMS_RXDMT: u32 = 1 << 4; -const IMS_RX: u32 = 1 << 6; -const IMS_RXT: u32 = 1 << 7; - -const RCTL: u32 = 0x100; -const RCTL_EN: u32 = 1 << 1; -const RCTL_UPE: u32 = 1 << 3; -const RCTL_MPE: u32 = 1 << 4; -const RCTL_LPE: u32 = 1 << 5; -const RCTL_LBM: u32 = 1 << 6 | 1 << 7; -const RCTL_BAM: u32 = 1 << 15; -const RCTL_BSIZE1: u32 = 1 << 16; -const RCTL_BSIZE2: u32 = 1 << 17; -const RCTL_BSEX: u32 = 1 << 25; -const RCTL_SECRC: u32 = 1 << 26; - -const RDBAL: u32 = 0x2800; -const RDBAH: u32 = 0x2804; -const RDLEN: u32 = 0x2808; -const RDH: u32 = 0x2810; -const RDT: u32 = 0x2818; - -const RAL0: u32 = 0x5400; -const RAH0: u32 = 0x5404; - -#[derive(Debug)] -#[repr(packed)] -struct Rd { - buffer: u64, - length: u16, - checksum: u16, - status: u8, - error: u8, - special: u16, -} -const RD_DD: u8 = 1; -const RD_EOP: u8 = 1 << 1; - -const TCTL: u32 = 0x400; -const TCTL_EN: u32 = 1 << 1; -const TCTL_PSP: u32 = 1 << 3; - -const TDBAL: u32 = 0x3800; -const TDBAH: u32 = 0x3804; -const TDLEN: u32 = 0x3808; -const TDH: u32 = 0x3810; -const TDT: u32 = 0x3818; - -#[derive(Debug)] -#[repr(packed)] -struct Td { - buffer: u64, - length: u16, - cso: u8, - command: u8, - status: u8, - css: u8, - special: u16, -} -const TD_CMD_EOP: u8 = 1; -const TD_CMD_IFCS: u8 = 1 << 1; -const TD_CMD_RS: u8 = 1 << 3; -const TD_DD: u8 = 1; - -pub struct Intel8254x { - base: usize, - receive_buffer: [Dma<[u8; 16384]>; 16], - receive_ring: Dma<[Rd; 16]>, - transmit_buffer: [Dma<[u8; 16384]>; 16], - transmit_ring: Dma<[Td; 16]> -} - -impl Scheme for Intel8254x { - fn open(&self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - if uid == 0 { - Ok(flags) - } else { - Err(Error::new(EACCES)) - } - } - - fn dup(&self, id: usize, _buf: &[u8]) -> Result { - Ok(id) - } - - fn read(&self, id: usize, buf: &mut [u8]) -> Result { - let head = unsafe { self.read(RDH) }; - let mut tail = unsafe { self.read(RDT) }; - - tail += 1; - if tail >= self.receive_ring.len() as u32 { - tail = 0; - } - - if tail != head { - let rd = unsafe { &mut * (self.receive_ring.as_ptr().offset(tail as isize) as *mut Rd) }; - if rd.status & RD_DD == RD_DD { - rd.status = 0; - - let data = &self.receive_buffer[tail as usize][.. rd.length as usize]; - - let mut i = 0; - while i < buf.len() && i < data.len() { - buf[i] = data[i]; - i += 1; - } - - unsafe { self.write(RDT, tail) }; - - return Ok(i); - } - } - - if id & O_NONBLOCK == O_NONBLOCK { - Ok(0) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } - - fn write(&self, _id: usize, buf: &[u8]) -> Result { - loop { - let head = unsafe { self.read(TDH) }; - let mut tail = unsafe { self.read(TDT) }; - let old_tail = tail; - - tail += 1; - if tail >= self.transmit_ring.len() as u32 { - tail = 0; - } - - if tail != head { - let td = unsafe { &mut * (self.transmit_ring.as_ptr().offset(old_tail as isize) as *mut Td) }; - - td.cso = 0; - td.command = TD_CMD_EOP | TD_CMD_IFCS | TD_CMD_RS; - td.status = 0; - td.css = 0; - td.special = 0; - - td.length = (cmp::min(buf.len(), 0x3FFF)) as u16; - - let mut data = unsafe { slice::from_raw_parts_mut(self.transmit_buffer[old_tail as usize].as_ptr() as *mut u8, td.length as usize) }; - - let mut i = 0; - while i < buf.len() && i < data.len() { - data[i] = buf[i]; - i += 1; - } - - unsafe { self.write(TDT, tail) }; - - while td.status == 0 { - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } - } - - return Ok(i); - } - - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } - } - } - - fn fevent(&self, _id: usize, _flags: usize) -> Result { - Ok(0) - } - - fn fsync(&self, _id: usize) -> Result { - Ok(0) - } - - fn close(&self, _id: usize) -> Result { - Ok(0) - } -} - -impl Intel8254x { - pub unsafe fn new(base: usize) -> Result { - let mut module = Intel8254x { - base: base, - receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], - receive_ring: Dma::zeroed()?, - transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], - transmit_ring: Dma::zeroed()? - }; - - module.init(); - - Ok(module) - } - - pub unsafe fn irq(&self) -> bool { - let icr = self.read(ICR); - icr != 0 - } - - pub fn next_read(&self) -> usize { - let head = unsafe { self.read(RDH) }; - let mut tail = unsafe { self.read(RDT) }; - - tail += 1; - if tail >= self.receive_ring.len() as u32 { - tail = 0; - } - - if tail != head { - let rd = unsafe { &* (self.receive_ring.as_ptr().offset(tail as isize) as *const Rd) }; - if rd.status & RD_DD == RD_DD { - return rd.length as usize; - } - } - - 0 - } - - pub unsafe fn read(&self, register: u32) -> u32 { - ptr::read_volatile((self.base + register as usize) as *mut u32) - } - - pub unsafe fn write(&self, register: u32, data: u32) -> u32 { - ptr::write_volatile((self.base + register as usize) as *mut u32, data); - ptr::read_volatile((self.base + register as usize) as *mut u32) - } - - pub unsafe fn flag(&self, register: u32, flag: u32, value: bool) { - if value { - self.write(register, self.read(register) | flag); - } else { - self.write(register, self.read(register) & (0xFFFFFFFF - flag)); - } - } - - pub unsafe fn init(&mut self) { - // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal - self.flag(CTRL, CTRL_ASDE | CTRL_SLU, true); - self.flag(CTRL, CTRL_LRST, false); - self.flag(CTRL, CTRL_PHY_RST, false); - self.flag(CTRL, CTRL_ILOS, false); - - // No flow control - self.write(FCAH, 0); - self.write(FCAL, 0); - self.write(FCT, 0); - self.write(FCTTV, 0); - - // Do not use VLANs - self.flag(CTRL, CTRL_VME, false); - - // TODO: Clear statistical counters - - let mac_low = self.read(RAL0); - let mac_high = self.read(RAH0); - let mac = [mac_low as u8, - (mac_low >> 8) as u8, - (mac_low >> 16) as u8, - (mac_low >> 24) as u8, - mac_high as u8, - (mac_high >> 8) as u8]; - print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - - // - // MTA => 0; - // - - // Receive Buffer - for i in 0..self.receive_ring.len() { - self.receive_ring[i].buffer = self.receive_buffer[i].physical() as u64; - } - - self.write(RDBAH, (self.receive_ring.physical() >> 32) as u32); - self.write(RDBAL, self.receive_ring.physical() as u32); - self.write(RDLEN, (self.receive_ring.len() * mem::size_of::()) as u32); - self.write(RDH, 0); - self.write(RDT, self.receive_ring.len() as u32 - 1); - - // Transmit Buffer - for i in 0..self.transmit_ring.len() { - self.transmit_ring[i].buffer = self.transmit_buffer[i].physical() as u64; - } - - self.write(TDBAH, (self.transmit_ring.physical() >> 32) as u32); - self.write(TDBAL, self.transmit_ring.physical() as u32); - self.write(TDLEN, (self.transmit_ring.len() * mem::size_of::()) as u32); - self.write(TDH, 0); - self.write(TDT, 0); - - self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ); // | IMS_LSC | IMS_TXQE | IMS_TXDW - - self.flag(RCTL, RCTL_EN, true); - self.flag(RCTL, RCTL_UPE, true); - // self.flag(RCTL, RCTL_MPE, true); - self.flag(RCTL, RCTL_LPE, true); - self.flag(RCTL, RCTL_LBM, false); - // RCTL.RDMTS = Minimum threshold size ??? - // RCTL.MO = Multicast offset - self.flag(RCTL, RCTL_BAM, true); - self.flag(RCTL, RCTL_BSIZE1, true); - self.flag(RCTL, RCTL_BSIZE2, false); - self.flag(RCTL, RCTL_BSEX, true); - self.flag(RCTL, RCTL_SECRC, true); - - self.flag(TCTL, TCTL_EN, true); - self.flag(TCTL, TCTL_PSP, true); - // TCTL.CT = Collition threshold - // TCTL.COLD = Collision distance - // TIPG Packet Gap - // TODO ... - } -} diff --git a/drivers/e1000d/src/main.rs b/drivers/e1000d/src/main.rs deleted file mode 100644 index b690029..0000000 --- a/drivers/e1000d/src/main.rs +++ /dev/null @@ -1,136 +0,0 @@ -#![feature(asm)] - -extern crate dma; -extern crate event; -extern crate netutils; -extern crate syscall; - -use std::cell::RefCell; -use std::env; -use std::fs::File; -use std::io::{Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd}; -use std::sync::Arc; - -use event::EventQueue; -use syscall::{Packet, Scheme, MAP_WRITE}; -use syscall::error::EWOULDBLOCK; - -pub mod device; - -fn main() { - let mut args = env::args().skip(1); - - let mut name = args.next().expect("e1000d: no name provided"); - name.push_str("_e1000"); - - let bar_str = args.next().expect("e1000d: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address"); - - let irq_str = args.next().expect("e1000d: no irq provided"); - let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); - - print!("{}", format!(" + E1000 {} on: {:X}, IRQ: {}\n", name, bar, irq)); - - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("e1000d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); - - let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; - { - let device = Arc::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }); - - let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); - - let todo = Arc::new(RefCell::new(Vec::::new())); - - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - if unsafe { device_irq.irq() } { - irq_file.write(&mut irq)?; - - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - device_irq.handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_irq.borrow_mut().write(&mut todo[i])?; - todo.remove(i); - } - } - - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }).expect("e1000d: failed to catch events on IRQ file"); - - let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_count: usize| -> Result> { - loop { - let mut packet = Packet::default(); - if socket_packet.borrow_mut().read(&mut packet)? == 0 { - break; - } - - let a = packet.a; - device.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; - } - } - - let next_read = device.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - - Ok(None) - }).expect("e1000d: failed to catch events on IRQ file"); - - for event_count in event_queue.trigger_all(0).expect("e1000d: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("e1000d: failed to write event"); - } - - loop { - let event_count = event_queue.run().expect("e1000d: failed to handle events"); - - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("e1000d: failed to write event"); - } - } - unsafe { let _ = syscall::physunmap(address); } - } -} diff --git a/drivers/pcid/Cargo.toml b/drivers/pcid/Cargo.toml deleted file mode 100644 index f09b85a..0000000 --- a/drivers/pcid/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "pcid" -version = "0.1.0" - -[dependencies] -redox_syscall = { path = "../../syscall/" } -rustc-serialize = "0.3" -toml = "0.2" diff --git a/drivers/pcid/src/config.rs b/drivers/pcid/src/config.rs deleted file mode 100644 index 3bc4dba..0000000 --- a/drivers/pcid/src/config.rs +++ /dev/null @@ -1,14 +0,0 @@ -#[derive(Debug, Default, RustcDecodable)] -pub struct Config { - pub drivers: Vec -} - -#[derive(Debug, Default, RustcDecodable)] -pub struct DriverConfig { - pub name: Option, - pub class: Option, - pub subclass: Option, - pub vendor: Option, - pub device: Option, - pub command: Option> -} diff --git a/drivers/pcid/src/main.rs b/drivers/pcid/src/main.rs deleted file mode 100644 index 8202d6f..0000000 --- a/drivers/pcid/src/main.rs +++ /dev/null @@ -1,160 +0,0 @@ -#![feature(asm)] - -extern crate rustc_serialize; -extern crate syscall; -extern crate toml; - -use std::env; -use std::fs::File; -use std::io::Read; -use std::process::Command; -use syscall::iopl; - -use config::Config; -use pci::{Pci, PciBar, PciClass}; - -mod config; -mod pci; - -fn main() { - let mut config = Config::default(); - - let mut args = env::args().skip(1); - if let Some(config_path) = args.next() { - if let Ok(mut config_file) = File::open(&config_path) { - let mut config_data = String::new(); - if let Ok(_) = config_file.read_to_string(&mut config_data) { - config = toml::decode_str(&config_data).unwrap_or(Config::default()); - } - } - } - - unsafe { iopl(3).unwrap() }; - - print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n"); - - let pci = Pci::new(); - for bus in pci.buses() { - for dev in bus.devs() { - for func in dev.funcs() { - if let Some(header) = func.header() { - let pci_class = PciClass::from(header.class); - - let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - bus.num, dev.num, func.num, - header.vendor_id, header.device_id, - header.class, header.subclass, header.interface, header.revision, - pci_class); - - match pci_class { - PciClass::Storage => match header.subclass { - 0x01 => { - string.push_str(" IDE"); - }, - 0x06 => { - string.push_str(" SATA"); - }, - _ => () - }, - PciClass::SerialBus => match header.subclass { - 0x03 => match header.interface { - 0x00 => { - string.push_str(" UHCI"); - }, - 0x10 => { - string.push_str(" OHCI"); - }, - 0x20 => { - string.push_str(" EHCI"); - }, - 0x30 => { - string.push_str(" XHCI"); - }, - _ => () - }, - _ => () - }, - _ => () - } - - for i in 0..header.bars.len() { - match PciBar::from(header.bars[i]) { - PciBar::None => (), - PciBar::Memory(address) => string.push_str(&format!(" {}={:>08X}", i, address)), - PciBar::Port(address) => string.push_str(&format!(" {}={:>04X}", i, address)) - } - } - - string.push('\n'); - - print!("{}", string); - - for driver in config.drivers.iter() { - if let Some(class) = driver.class { - if class != header.class { continue; } - } - - if let Some(subclass) = driver.subclass { - if subclass != header.subclass { continue; } - } - - if let Some(vendor) = driver.vendor { - if vendor != header.vendor_id { continue; } - } - - if let Some(device) = driver.device { - if device != header.device_id { continue; } - } - - if let Some(ref args) = driver.command { - // Enable bus mastering - unsafe { - let cmd = pci.read(bus.num, dev.num, func.num, 0x04); - pci.write(bus.num, dev.num, func.num, 0x04, cmd | 4); - } - - let mut args = args.iter(); - if let Some(program) = args.next() { - let mut command = Command::new(program); - for arg in args { - let bar_arg = |i| -> String { - match PciBar::from(header.bars[i]) { - PciBar::None => String::new(), - PciBar::Memory(address) => format!("{:>08X}", address), - PciBar::Port(address) => format!("{:>04X}", address) - } - }; - let arg = match arg.as_str() { - "$BUS" => format!("{:>02X}", bus.num), - "$DEV" => format!("{:>02X}", dev.num), - "$FUNC" => format!("{:>02X}", func.num), - "$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus.num, dev.num, func.num), - "$BAR0" => bar_arg(0), - "$BAR1" => bar_arg(1), - "$BAR2" => bar_arg(2), - "$BAR3" => bar_arg(3), - "$BAR4" => bar_arg(4), - "$BAR5" => bar_arg(5), - "$IRQ" => format!("{}", header.interrupt_line), - _ => arg.clone() - }; - command.arg(&arg); - } - - println!("PCID SPAWN {:?}", command); - - match command.spawn() { - Ok(mut child) => match child.wait() { - Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), - Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err) - }, - Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) - } - } - } - } - } - } - } - } -} diff --git a/drivers/pcid/src/pci/bar.rs b/drivers/pcid/src/pci/bar.rs deleted file mode 100644 index 190fa05..0000000 --- a/drivers/pcid/src/pci/bar.rs +++ /dev/null @@ -1,18 +0,0 @@ -#[derive(Debug)] -pub enum PciBar { - None, - Memory(u32), - Port(u16) -} - -impl From for PciBar { - fn from(bar: u32) -> Self { - if bar & 0xFFFFFFFC == 0 { - PciBar::None - } else if bar & 1 == 0 { - PciBar::Memory(bar & 0xFFFFFFF0) - } else { - PciBar::Port((bar & 0xFFFC) as u16) - } - } -} diff --git a/drivers/pcid/src/pci/bus.rs b/drivers/pcid/src/pci/bus.rs deleted file mode 100644 index 120fa45..0000000 --- a/drivers/pcid/src/pci/bus.rs +++ /dev/null @@ -1,46 +0,0 @@ -use super::{Pci, PciDev}; - -pub struct PciBus<'pci> { - pub pci: &'pci Pci, - pub num: u8 -} - -impl<'pci> PciBus<'pci> { - pub fn devs(&'pci self) -> PciBusIter<'pci> { - PciBusIter::new(self) - } - - pub unsafe fn read(&self, dev: u8, func: u8, offset: u8) -> u32 { - self.pci.read(self.num, dev, func, offset) - } -} - -pub struct PciBusIter<'pci> { - bus: &'pci PciBus<'pci>, - num: u32 -} - -impl<'pci> PciBusIter<'pci> { - pub fn new(bus: &'pci PciBus<'pci>) -> Self { - PciBusIter { - bus: bus, - num: 0 - } - } -} - -impl<'pci> Iterator for PciBusIter<'pci> { - type Item = PciDev<'pci>; - fn next(&mut self) -> Option { - if self.num < 32 { - let dev = PciDev { - bus: self.bus, - num: self.num as u8 - }; - self.num += 1; - Some(dev) - } else { - None - } - } -} diff --git a/drivers/pcid/src/pci/class.rs b/drivers/pcid/src/pci/class.rs deleted file mode 100644 index 21f7f69..0000000 --- a/drivers/pcid/src/pci/class.rs +++ /dev/null @@ -1,50 +0,0 @@ -#[derive(Debug)] -pub enum PciClass { - Legacy, - Storage, - Network, - Display, - Multimedia, - Memory, - Bridge, - SimpleComms, - Peripheral, - Input, - Docking, - Processor, - SerialBus, - Wireless, - IntelligentIo, - SatelliteComms, - Cryptography, - SignalProc, - Reserved(u8), - Unknown -} - -impl From for PciClass { - fn from(class: u8) -> PciClass { - match class { - 0x00 => PciClass::Legacy, - 0x01 => PciClass::Storage, - 0x02 => PciClass::Network, - 0x03 => PciClass::Display, - 0x04 => PciClass::Multimedia, - 0x05 => PciClass::Memory, - 0x06 => PciClass::Bridge, - 0x07 => PciClass::SimpleComms, - 0x08 => PciClass::Peripheral, - 0x09 => PciClass::Input, - 0x0A => PciClass::Docking, - 0x0B => PciClass::Processor, - 0x0C => PciClass::SerialBus, - 0x0D => PciClass::Wireless, - 0x0E => PciClass::IntelligentIo, - 0x0F => PciClass::SatelliteComms, - 0x10 => PciClass::Cryptography, - 0x11 => PciClass::SignalProc, - 0xFF => PciClass::Unknown, - reserved => PciClass::Reserved(reserved) - } - } -} diff --git a/drivers/pcid/src/pci/dev.rs b/drivers/pcid/src/pci/dev.rs deleted file mode 100644 index 0508888..0000000 --- a/drivers/pcid/src/pci/dev.rs +++ /dev/null @@ -1,46 +0,0 @@ -use super::{PciBus, PciFunc}; - -pub struct PciDev<'pci> { - pub bus: &'pci PciBus<'pci>, - pub num: u8 -} - -impl<'pci> PciDev<'pci> { - pub fn funcs(&'pci self) -> PciDevIter<'pci> { - PciDevIter::new(self) - } - - pub unsafe fn read(&self, func: u8, offset: u8) -> u32 { - self.bus.read(self.num, func, offset) - } -} - -pub struct PciDevIter<'pci> { - dev: &'pci PciDev<'pci>, - num: u32 -} - -impl<'pci> PciDevIter<'pci> { - pub fn new(dev: &'pci PciDev<'pci>) -> Self { - PciDevIter { - dev: dev, - num: 0 - } - } -} - -impl<'pci> Iterator for PciDevIter<'pci> { - type Item = PciFunc<'pci>; - fn next(&mut self) -> Option { - if self.num < 8 { - let func = PciFunc { - dev: self.dev, - num: self.num as u8 - }; - self.num += 1; - Some(func) - } else { - None - } - } -} diff --git a/drivers/pcid/src/pci/func.rs b/drivers/pcid/src/pci/func.rs deleted file mode 100644 index 578e5c6..0000000 --- a/drivers/pcid/src/pci/func.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::ops::DerefMut; - -use super::{PciDev, PciHeader}; - -pub struct PciFunc<'pci> { - pub dev: &'pci PciDev<'pci>, - pub num: u8 -} - -impl<'pci> PciFunc<'pci> { - pub fn header(&self) -> Option { - if unsafe { self.read(0) } != 0xFFFFFFFF { - let mut header = PciHeader::default(); - { - let dwords = header.deref_mut(); - dwords.iter_mut().fold(0usize, |offset, dword| { - *dword = unsafe { self.read(offset as u8) }; - offset + 4 - }); - } - Some(header) - } else { - None - } - } - - pub unsafe fn read(&self, offset: u8) -> u32 { - self.dev.read(self.num, offset) - } -} diff --git a/drivers/pcid/src/pci/header.rs b/drivers/pcid/src/pci/header.rs deleted file mode 100644 index 2cc335e..0000000 --- a/drivers/pcid/src/pci/header.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::ops::{Deref, DerefMut}; -use std::{slice, mem}; - -#[derive(Debug, Default)] -#[repr(packed)] -pub struct PciHeader { - pub vendor_id: u16, - pub device_id: u16, - pub command: u16, - pub status: u16, - pub revision: u8, - pub interface: u8, - pub subclass: u8, - pub class: u8, - pub cache_line_size: u8, - pub latency_timer: u8, - pub header_type: u8, - pub bist: u8, - pub bars: [u32; 6], - pub cardbus_cis_ptr: u32, - pub subsystem_vendor_id: u16, - pub subsystem_id: u16, - pub expansion_rom_bar: u32, - pub capabilities: u8, - pub reserved: [u8; 7], - pub interrupt_line: u8, - pub interrupt_pin: u8, - pub min_grant: u8, - pub max_latency: u8 -} - -impl Deref for PciHeader { - type Target = [u32]; - fn deref(&self) -> &[u32] { - unsafe { slice::from_raw_parts(self as *const PciHeader as *const u32, mem::size_of::()/4) as &[u32] } - } -} - -impl DerefMut for PciHeader { - fn deref_mut(&mut self) -> &mut [u32] { - unsafe { slice::from_raw_parts_mut(self as *mut PciHeader as *mut u32, mem::size_of::()/4) as &mut [u32] } - } -} diff --git a/drivers/pcid/src/pci/mod.rs b/drivers/pcid/src/pci/mod.rs deleted file mode 100644 index d2a8e89..0000000 --- a/drivers/pcid/src/pci/mod.rs +++ /dev/null @@ -1,78 +0,0 @@ -pub use self::bar::PciBar; -pub use self::bus::{PciBus, PciBusIter}; -pub use self::class::PciClass; -pub use self::dev::{PciDev, PciDevIter}; -pub use self::func::PciFunc; -pub use self::header::PciHeader; - -mod bar; -mod bus; -mod class; -mod dev; -mod func; -mod header; - -pub struct Pci; - -impl Pci { - pub fn new() -> Self { - Pci - } - - pub fn buses<'pci>(&'pci self) -> PciIter<'pci> { - PciIter::new(self) - } - - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { - let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); - let value: u32; - asm!("mov dx, 0xCF8 - out dx, eax - mov dx, 0xCFC - in eax, dx" - : "={eax}"(value) : "{eax}"(address) : "dx" : "intel", "volatile"); - value - } - - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { - let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); - asm!("mov dx, 0xCF8 - out dx, eax" - : : "{eax}"(address) : "dx" : "intel", "volatile"); - asm!("mov dx, 0xCFC - out dx, eax" - : : "{eax}"(value) : "dx" : "intel", "volatile"); - } -} - -pub struct PciIter<'pci> { - pci: &'pci Pci, - num: u32 -} - -impl<'pci> PciIter<'pci> { - pub fn new(pci: &'pci Pci) -> Self { - PciIter { - pci: pci, - num: 0 - } - } -} - -impl<'pci> Iterator for PciIter<'pci> { - type Item = PciBus<'pci>; - fn next(&mut self) -> Option { - if self.num < 256 { - let bus = PciBus { - pci: self.pci, - num: self.num as u8 - }; - self.num += 1; - Some(bus) - } else { - None - } - } -} diff --git a/drivers/ps2d/Cargo.toml b/drivers/ps2d/Cargo.toml deleted file mode 100644 index 98ebbf2..0000000 --- a/drivers/ps2d/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "ps2d" -version = "0.1.0" - -[dependencies] -bitflags = "*" -event = { path = "../../crates/event/" } -io = { path = "../../crates/io/" } -orbclient = "0.1" -redox_syscall = { path = "../../syscall/" } diff --git a/drivers/ps2d/src/controller.rs b/drivers/ps2d/src/controller.rs deleted file mode 100644 index e68d4f1..0000000 --- a/drivers/ps2d/src/controller.rs +++ /dev/null @@ -1,233 +0,0 @@ -use io::{Io, Pio, ReadOnly, WriteOnly}; - -bitflags! { - flags StatusFlags: u8 { - const OUTPUT_FULL = 1, - const INPUT_FULL = 1 << 1, - const SYSTEM = 1 << 2, - const COMMAND = 1 << 3, - // Chipset specific - const KEYBOARD_LOCK = 1 << 4, - // Chipset specific - const SECOND_OUTPUT_FULL = 1 << 5, - const TIME_OUT = 1 << 6, - const PARITY = 1 << 7 - } -} - -bitflags! { - flags ConfigFlags: u8 { - const FIRST_INTERRUPT = 1, - const SECOND_INTERRUPT = 1 << 1, - const POST_PASSED = 1 << 2, - // 1 << 3 should be zero - const CONFIG_RESERVED_3 = 1 << 3, - const FIRST_DISABLED = 1 << 4, - const SECOND_DISABLED = 1 << 5, - const FIRST_TRANSLATE = 1 << 6, - // 1 << 7 should be zero - const CONFIG_RESERVED_7 = 1 << 7, - } -} - -#[repr(u8)] -#[allow(dead_code)] -enum Command { - ReadConfig = 0x20, - WriteConfig = 0x60, - DisableSecond = 0xA7, - EnableSecond = 0xA8, - TestSecond = 0xA9, - TestController = 0xAA, - TestFirst = 0xAB, - Diagnostic = 0xAC, - DisableFirst = 0xAD, - EnableFirst = 0xAE, - WriteSecond = 0xD4 -} - -#[repr(u8)] -#[allow(dead_code)] -enum KeyboardCommand { - EnableReporting = 0xF4, - SetDefaults = 0xF6, - Reset = 0xFF -} - -#[repr(u8)] -enum KeyboardCommandData { - ScancodeSet = 0xF0 -} - -#[repr(u8)] -#[allow(dead_code)] -enum MouseCommand { - GetDeviceId = 0xF2, - EnableReporting = 0xF4, - SetDefaults = 0xF6, - Reset = 0xFF -} - -#[repr(u8)] -enum MouseCommandData { - SetSampleRate = 0xF3, -} - -pub struct Ps2 { - data: Pio, - status: ReadOnly>, - command: WriteOnly> -} - -impl Ps2 { - pub fn new() -> Self { - Ps2 { - data: Pio::new(0x60), - status: ReadOnly::new(Pio::new(0x64)), - command: WriteOnly::new(Pio::new(0x64)), - } - } - - fn status(&mut self) -> StatusFlags { - StatusFlags::from_bits_truncate(self.status.read()) - } - - fn wait_write(&mut self) { - while self.status().contains(INPUT_FULL) {} - } - - fn wait_read(&mut self) { - while ! self.status().contains(OUTPUT_FULL) {} - } - - fn flush_read(&mut self) { - while self.status().contains(OUTPUT_FULL) { - print!("FLUSH: {:X}\n", self.data.read()); - } - } - - fn command(&mut self, command: Command) { - self.wait_write(); - self.command.write(command as u8); - } - - fn read(&mut self) -> u8 { - self.wait_read(); - self.data.read() - } - - fn write(&mut self, data: u8) { - self.wait_write(); - self.data.write(data); - } - - fn config(&mut self) -> ConfigFlags { - self.command(Command::ReadConfig); - ConfigFlags::from_bits_truncate(self.read()) - } - - fn set_config(&mut self, config: ConfigFlags) { - self.command(Command::WriteConfig); - self.write(config.bits()); - } - - fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 { - self.write(command as u8); - self.read() - } - - fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> u8 { - self.write(command as u8); - assert_eq!(self.read(), 0xFA); - self.write(data as u8); - self.read() - } - - fn mouse_command(&mut self, command: MouseCommand) -> u8 { - self.command(Command::WriteSecond); - self.write(command as u8); - self.read() - } - - fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> u8 { - self.command(Command::WriteSecond); - self.write(command as u8); - assert_eq!(self.read(), 0xFA); - self.command(Command::WriteSecond); - self.write(data as u8); - self.read() - } - - pub fn init(&mut self) -> bool { - // Disable devices - self.command(Command::DisableFirst); - self.command(Command::DisableSecond); - - // Clear remaining data - self.flush_read(); - - // Disable clocks, disable interrupts, and disable translate - { - let mut config = self.config(); - config.insert(FIRST_DISABLED); - config.insert(SECOND_DISABLED); - config.remove(FIRST_TRANSLATE); - config.remove(FIRST_INTERRUPT); - config.remove(SECOND_INTERRUPT); - self.set_config(config); - } - - // Perform the self test - self.command(Command::TestController); - assert_eq!(self.read(), 0x55); - - // Enable devices - self.command(Command::EnableFirst); - self.command(Command::EnableSecond); - - // Reset keyboard - assert_eq!(self.keyboard_command(KeyboardCommand::Reset), 0xFA); - assert_eq!(self.read(), 0xAA); - self.flush_read(); - - // Set scancode set to 2 - assert_eq!(self.keyboard_command_data(KeyboardCommandData::ScancodeSet, 2), 0xFA); - - // Reset mouse and set up scroll - // TODO: Check for ack - assert_eq!(self.mouse_command(MouseCommand::Reset), 0xFA); - assert_eq!(self.read(), 0xAA); - assert_eq!(self.read(), 0x00); - self.flush_read(); - - // Enable extra packet on mouse - assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA); - assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 100), 0xFA); - assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 80), 0xFA); - assert_eq!(self.mouse_command(MouseCommand::GetDeviceId), 0xFA); - let mouse_id = self.read(); - let mouse_extra = mouse_id == 3; - - // Set sample rate to maximum - assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA); - - // Enable data reporting - assert_eq!(self.keyboard_command(KeyboardCommand::EnableReporting), 0xFA); - assert_eq!(self.mouse_command(MouseCommand::EnableReporting), 0xFA); - - // Enable clocks and interrupts - { - let mut config = self.config(); - config.remove(FIRST_DISABLED); - config.remove(SECOND_DISABLED); - config.insert(FIRST_TRANSLATE); - config.insert(FIRST_INTERRUPT); - config.insert(SECOND_INTERRUPT); - self.set_config(config); - } - - self.flush_read(); - - mouse_extra - } -} diff --git a/drivers/ps2d/src/keymap.rs b/drivers/ps2d/src/keymap.rs deleted file mode 100644 index 5697e52..0000000 --- a/drivers/ps2d/src/keymap.rs +++ /dev/null @@ -1,148 +0,0 @@ -pub mod english { - static ENGLISH: [[char; 2]; 58] = [ - ['\0', '\0'], - ['\x1B', '\x1B'], - ['1', '!'], - ['2', '@'], - ['3', '#'], - ['4', '$'], - ['5', '%'], - ['6', '^'], - ['7', '&'], - ['8', '*'], - ['9', '('], - ['0', ')'], - ['-', '_'], - ['=', '+'], - ['\x7F', '\x7F'], - ['\t', '\t'], - ['q', 'Q'], - ['w', 'W'], - ['e', 'E'], - ['r', 'R'], - ['t', 'T'], - ['y', 'Y'], - ['u', 'U'], - ['i', 'I'], - ['o', 'O'], - ['p', 'P'], - ['[', '{'], - [']', '}'], - ['\n', '\n'], - ['\0', '\0'], - ['a', 'A'], - ['s', 'S'], - ['d', 'D'], - ['f', 'F'], - ['g', 'G'], - ['h', 'H'], - ['j', 'J'], - ['k', 'K'], - ['l', 'L'], - [';', ':'], - ['\'', '"'], - ['`', '~'], - ['\0', '\0'], - ['\\', '|'], - ['z', 'Z'], - ['x', 'X'], - ['c', 'C'], - ['v', 'V'], - ['b', 'B'], - ['n', 'N'], - ['m', 'M'], - [',', '<'], - ['.', '>'], - ['/', '?'], - ['\0', '\0'], - ['\0', '\0'], - ['\0', '\0'], - [' ', ' '] - ]; - - pub fn get_char(scancode: u8, shift: bool) -> char { - if let Some(c) = ENGLISH.get(scancode as usize) { - if shift { - c[1] - } else { - c[0] - } - } else { - '\0' - } - } -} -pub mod dvorak { - static DVORAK: [[char; 2]; 58] = [ - ['\0', '\0'], - ['\x1B', '\x1B'], - ['1', '!'], - ['2', '@'], - ['3', '#'], - ['4', '$'], - ['5', '%'], - ['6', '^'], - ['7', '&'], - ['8', '*'], - ['9', '('], - ['0', ')'], - ['[', '{'], - [']', '}'], - ['\x7F', '\x7F'], - ['\t', '\t'], - ['\'', '"'], - [',', '<'], - ['.', '>'], - ['p', 'P'], - ['y', 'Y'], - ['f', 'F'], - ['g', 'G'], - ['c', 'C'], - ['r', 'R'], - ['l', 'L'], - ['/', '?'], - ['=', '+'], - ['\n', '\n'], - ['\0', '\0'], - ['a', 'A'], - ['o', 'O'], - ['e', 'E'], - ['u', 'U'], - ['i', 'I'], - ['d', 'D'], - ['h', 'H'], - ['t', 'T'], - ['n', 'N'], - ['s', 'S'], - ['-', '_'], - ['`', '~'], - ['\0', '\0'], - ['\\', '|'], - [';', ':'], - ['q', 'Q'], - ['j', 'J'], - ['k', 'K'], - ['x', 'X'], - ['b', 'B'], - ['m', 'M'], - ['w', 'W'], - ['v', 'V'], - ['z', 'Z'], - ['\0', '\0'], - ['\0', '\0'], - ['\0', '\0'], - [' ', ' '] - ]; - - pub fn get_char(scancode: u8, shift: bool) -> char { - if let Some(c) = DVORAK.get(scancode as usize) { - if shift { - c[1] - } else { - c[0] - } - } else { - '\0' - } - } -} diff --git a/drivers/ps2d/src/main.rs b/drivers/ps2d/src/main.rs deleted file mode 100644 index 7c67bd3..0000000 --- a/drivers/ps2d/src/main.rs +++ /dev/null @@ -1,193 +0,0 @@ -#![feature(asm)] - -#[macro_use] -extern crate bitflags; -extern crate event; -extern crate io; -extern crate orbclient; -extern crate syscall; - -use std::env; -use std::fs::File; -use std::io::{Read, Write, Result}; -use std::os::unix::io::AsRawFd; -use std::mem; - -use event::EventQueue; -use orbclient::{KeyEvent, MouseEvent}; -use syscall::iopl; - -mod controller; -mod keymap; - -bitflags! { - flags MousePacketFlags: u8 { - const LEFT_BUTTON = 1, - const RIGHT_BUTTON = 1 << 1, - const MIDDLE_BUTTON = 1 << 2, - const ALWAYS_ON = 1 << 3, - const X_SIGN = 1 << 4, - const Y_SIGN = 1 << 5, - const X_OVERFLOW = 1 << 6, - const Y_OVERFLOW = 1 << 7 - } -} - -struct Ps2d<'a> { - input: File, - lshift: bool, - rshift: bool, - packets: [u8; 4], - packet_i: usize, - extra_packet: bool, - //Keymap function - get_char: &'a Fn(u8,bool) -> char -} - -impl<'a> Ps2d<'a> { - fn new(input: File, extra_packet: bool, keymap: &'a Fn(u8,bool) -> char) -> Self { - Ps2d { - input: input, - lshift: false, - rshift: false, - packets: [0; 4], - packet_i: 0, - extra_packet: extra_packet, - get_char: keymap - } - } - - fn handle(&mut self, keyboard: bool, data: u8) { - if keyboard { - let (scancode, pressed) = if data >= 0x80 { - (data - 0x80, false) - } else { - (data, true) - }; - - if scancode == 0x2A { - self.lshift = pressed; - } else if scancode == 0x36 { - self.rshift = pressed; - } - - self.input.write(&KeyEvent { - character: (self.get_char)(scancode, self.lshift || self.rshift), - scancode: scancode, - pressed: pressed - }.to_event()).expect("ps2d: failed to write key event"); - } else { - self.packets[self.packet_i] = data; - self.packet_i += 1; - - let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); - if ! flags.contains(ALWAYS_ON) { - println!("MOUSE MISALIGN {:X}", self.packets[0]); - - self.packets = [0; 4]; - self.packet_i = 0; - } else if self.packet_i >= self.packets.len() || (!self.extra_packet && self.packet_i >= 3) { - if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { - let mut dx = self.packets[1] as i32; - if flags.contains(X_SIGN) { - dx -= 0x100; - } - - let mut dy = -(self.packets[2] as i32); - if flags.contains(Y_SIGN) { - dy += 0x100; - } - - let _extra = if self.extra_packet { - self.packets[3] - } else { - 0 - }; - - self.input.write(&MouseEvent { - x: dx, - y: dy, - left_button: flags.contains(LEFT_BUTTON), - middle_button: flags.contains(MIDDLE_BUTTON), - right_button: flags.contains(RIGHT_BUTTON) - }.to_event()).expect("ps2d: failed to write mouse event"); - } else { - println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); - } - - self.packets = [0; 4]; - self.packet_i = 0; - } - } - } -} - -fn main() { - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - unsafe { - iopl(3).expect("ps2d: failed to get I/O permission"); - asm!("cli" : : : : "intel", "volatile"); - } - - let input = File::open("display:input").expect("ps2d: failed to open display:input"); - - let extra_packet = controller::Ps2::new().init(); - let keymap = match env::args().skip(1).next() { - Some(k) => match k.to_lowercase().as_ref() { - "dvorak" => (keymap::dvorak::get_char), - "english" => (keymap::english::get_char), - &_ => (keymap::english::get_char) - }, - None => (keymap::english::get_char) - }; - let mut ps2d = Ps2d::new(input, extra_packet,&keymap); - - let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue"); - - let mut key_irq = File::open("irq:1").expect("ps2d: failed to open irq:1"); - - event_queue.add(key_irq.as_raw_fd(), move |_count: usize| -> Result> { - let mut irq = [0; 8]; - if key_irq.read(&mut irq)? >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - key_irq.write(&irq)?; - - Ok(Some((true, data))) - } else { - Ok(None) - } - }).expect("ps2d: failed to poll irq:1"); - - let mut mouse_irq = File::open("irq:12").expect("ps2d: failed to open irq:12"); - - event_queue.add(mouse_irq.as_raw_fd(), move |_count: usize| -> Result> { - let mut irq = [0; 8]; - if mouse_irq.read(&mut irq)? >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - mouse_irq.write(&irq)?; - - Ok(Some((false, data))) - } else { - Ok(None) - } - }).expect("ps2d: failed to poll irq:12"); - - for (keyboard, data) in event_queue.trigger_all(0).expect("ps2d: failed to trigger events") { - ps2d.handle(keyboard, data); - } - - loop { - let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events"); - ps2d.handle(keyboard, data); - } - } -} diff --git a/drivers/rtl8168d/Cargo.toml b/drivers/rtl8168d/Cargo.toml deleted file mode 100644 index e72a130..0000000 --- a/drivers/rtl8168d/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "rtl8168d" -version = "0.1.0" - -[dependencies] -bitflags = "*" -dma = { path = "../../crates/dma/" } -event = { path = "../../crates/event/" } -io = { path = "../../crates/io/" } -netutils = { path = "../../programs/netutils/" } -redox_syscall = { path = "../../syscall/" } diff --git a/drivers/rtl8168d/src/device.rs b/drivers/rtl8168d/src/device.rs deleted file mode 100644 index 7ed7d59..0000000 --- a/drivers/rtl8168d/src/device.rs +++ /dev/null @@ -1,300 +0,0 @@ -use std::mem; - -use dma::Dma; -use io::{Mmio, Io, ReadOnly}; -use netutils::setcfg; -use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; -use syscall::flag::O_NONBLOCK; -use syscall::scheme::SchemeMut; - -#[repr(packed)] -struct Regs { - mac: [Mmio; 2], - _mar: [Mmio; 2], - _dtccr: [Mmio; 2], - _rsv0: [Mmio; 2], - tnpds: [Mmio; 2], - thpds: [Mmio; 2], - _rsv1: [Mmio; 7], - cmd: Mmio, - tppoll: Mmio, - _rsv2: [Mmio; 3], - imr: Mmio, - isr: Mmio, - tcr: Mmio, - rcr: Mmio, - _tctr: Mmio, - _rsv3: Mmio, - cmd_9346: Mmio, - _config: [Mmio; 6], - _rsv4: Mmio, - timer_int: Mmio, - _rsv5: Mmio, - _phys_ar: Mmio, - _rsv6: [Mmio; 2], - phys_sts: ReadOnly>, - _rsv7: [Mmio; 23], - _wakeup: [Mmio; 16], - _crc: [Mmio; 5], - _rsv8: [Mmio; 12], - rms: Mmio, - _rsv9: Mmio, - _c_plus_cr: Mmio, - _rsv10: Mmio, - rdsar: [Mmio; 2], - mtps: Mmio, - _rsv11: [Mmio; 19], -} - -const OWN: u32 = 1 << 31; -const EOR: u32 = 1 << 30; -const FS: u32 = 1 << 29; -const LS: u32 = 1 << 28; - -#[repr(packed)] -struct Rd { - ctrl: Mmio, - _vlan: Mmio, - buffer: Mmio -} - -#[repr(packed)] -struct Td { - ctrl: Mmio, - _vlan: Mmio, - buffer: Mmio -} - -pub struct Rtl8168 { - regs: &'static mut Regs, - receive_buffer: [Dma<[Mmio; 0x1FF8]>; 16], - receive_ring: Dma<[Rd; 16]>, - transmit_buffer: [Dma<[Mmio; 7552]>; 16], - transmit_ring: Dma<[Td; 16]>, - transmit_buffer_h: [Dma<[Mmio; 7552]>; 1], - transmit_ring_h: Dma<[Td; 1]> -} - -impl SchemeMut for Rtl8168 { - fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - if uid == 0 { - Ok(flags) - } else { - Err(Error::new(EACCES)) - } - } - - fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { - Ok(id) - } - - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { - for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() { - if ! rd.ctrl.readf(OWN) { - let rd_len = rd.ctrl.read() & 0x3FFF; - - let data = &self.receive_buffer[rd_i as usize]; - - let mut i = 0; - while i < buf.len() && i < rd_len as usize { - buf[i] = data[i].read(); - i += 1; - } - - let eor = rd.ctrl.read() & EOR; - rd.ctrl.write(OWN | eor | data.len() as u32); - - return Ok(i); - } - } - - if id & O_NONBLOCK == O_NONBLOCK { - Ok(0) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } - - fn write(&mut self, _id: usize, buf: &[u8]) -> Result { - loop { - for (td_i, td) in self.transmit_ring.iter_mut().enumerate() { - if ! td.ctrl.readf(OWN) { - - let mut data = &mut self.transmit_buffer[td_i as usize]; - - let mut i = 0; - while i < buf.len() && i < data.len() { - data[i].write(buf[i]); - i += 1; - } - - let eor = td.ctrl.read() & EOR; - td.ctrl.write(OWN | eor | FS | LS | i as u32); - - self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet - - while self.regs.tppoll.readf(1 << 6) { - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } - } - - return Ok(i); - } - } - - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } - } - } - - fn fevent(&mut self, _id: usize, _flags: usize) -> Result { - Ok(0) - } - - fn fsync(&mut self, _id: usize) -> Result { - Ok(0) - } - - fn close(&mut self, _id: usize) -> Result { - Ok(0) - } -} - -impl Rtl8168 { - pub unsafe fn new(base: usize) -> Result { - assert_eq!(mem::size_of::(), 256); - - let regs = &mut *(base as *mut Regs); - assert_eq!(®s.tnpds as *const _ as usize - base, 0x20); - assert_eq!(®s.cmd as *const _ as usize - base, 0x37); - assert_eq!(®s.tcr as *const _ as usize - base, 0x40); - assert_eq!(®s.rcr as *const _ as usize - base, 0x44); - assert_eq!(®s.cmd_9346 as *const _ as usize - base, 0x50); - assert_eq!(®s.phys_sts as *const _ as usize - base, 0x6C); - assert_eq!(®s.rms as *const _ as usize - base, 0xDA); - assert_eq!(®s.rdsar as *const _ as usize - base, 0xE4); - assert_eq!(®s.mtps as *const _ as usize - base, 0xEC); - - let mut module = Rtl8168 { - regs: regs, - receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], - receive_ring: Dma::zeroed()?, - transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], - transmit_ring: Dma::zeroed()?, - transmit_buffer_h: [Dma::zeroed()?], - transmit_ring_h: Dma::zeroed()? - }; - - module.init(); - - Ok(module) - } - - pub unsafe fn irq(&mut self) -> u16 { - // Read and then clear the ISR - let isr = self.regs.isr.read(); - self.regs.isr.write(isr); - let imr = self.regs.imr.read(); - isr & imr - } - - pub fn next_read(&self) -> usize { - for rd in self.receive_ring.iter() { - if ! rd.ctrl.readf(OWN) { - return rd.ctrl.read() as usize & 0x3FFF; - } - } - 0 - } - - pub unsafe fn init(&mut self) { - let mac_low = self.regs.mac[0].read(); - let mac_high = self.regs.mac[1].read(); - let mac = [mac_low as u8, - (mac_low >> 8) as u8, - (mac_low >> 16) as u8, - (mac_low >> 24) as u8, - mac_high as u8, - (mac_high >> 8) as u8]; - print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - - // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value - self.regs.cmd.writef(1 << 4, true); - while self.regs.cmd.readf(1 << 4) {} - - // Set up rx buffers - for i in 0..self.receive_ring.len() { - let rd = &mut self.receive_ring[i]; - let data = &mut self.receive_buffer[i]; - rd.buffer.write(data.physical() as u64); - rd.ctrl.write(OWN | data.len() as u32); - } - if let Some(mut rd) = self.receive_ring.last_mut() { - rd.ctrl.writef(EOR, true); - } - - // Set up normal priority tx buffers - for i in 0..self.transmit_ring.len() { - self.transmit_ring[i].buffer.write(self.transmit_buffer[i].physical() as u64); - } - if let Some(mut td) = self.transmit_ring.last_mut() { - td.ctrl.writef(EOR, true); - } - - // Set up high priority tx buffers - for i in 0..self.transmit_ring_h.len() { - self.transmit_ring_h[i].buffer.write(self.transmit_buffer_h[i].physical() as u64); - } - if let Some(mut td) = self.transmit_ring_h.last_mut() { - td.ctrl.writef(EOR, true); - } - - // Unlock config - self.regs.cmd_9346.write(1 << 7 | 1 << 6); - - // Enable rx (bit 3) and tx (bit 2) - self.regs.cmd.writef(1 << 3 | 1 << 2, true); - - // Max RX packet size - self.regs.rms.write(0x1FF8); - - // Max TX packet size - self.regs.mtps.write(0x3B); - - // Set tx low priority buffer address - self.regs.tnpds[0].write(self.transmit_ring.physical() as u32); - self.regs.tnpds[1].write((self.transmit_ring.physical() >> 32) as u32); - - // Set tx high priority buffer address - self.regs.thpds[0].write(self.transmit_ring_h.physical() as u32); - self.regs.thpds[1].write((self.transmit_ring_h.physical() >> 32) as u32); - - // Set rx buffer address - self.regs.rdsar[0].write(self.receive_ring.physical() as u32); - self.regs.rdsar[1].write((self.receive_ring.physical() >> 32) as u32); - - // Disable timer interrupt - self.regs.timer_int.write(0); - - //Clear ISR - let isr = self.regs.isr.read(); - self.regs.isr.write(isr); - - // Interrupt on tx error (bit 3), tx ok (bit 2), rx error(bit 1), and rx ok (bit 0) - self.regs.imr.write(1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1); - - // Set TX config - self.regs.tcr.write(0b11 << 24 | 0b111 << 8); - - // Set RX config - Accept broadcast (bit 3), multicast (bit 2), and unicast (bit 1) - self.regs.rcr.write(0xE70E); - - // Lock config - self.regs.cmd_9346.write(0); - } -} diff --git a/drivers/rtl8168d/src/main.rs b/drivers/rtl8168d/src/main.rs deleted file mode 100644 index 46a1b86..0000000 --- a/drivers/rtl8168d/src/main.rs +++ /dev/null @@ -1,141 +0,0 @@ -#![feature(asm)] - -extern crate dma; -extern crate event; -extern crate io; -extern crate netutils; -extern crate syscall; - -use std::cell::RefCell; -use std::env; -use std::fs::File; -use std::io::{Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd}; -use std::sync::Arc; - -use event::EventQueue; -use syscall::{Packet, SchemeMut, MAP_WRITE}; -use syscall::error::EWOULDBLOCK; - -pub mod device; - -fn main() { - let mut args = env::args().skip(1); - - let mut name = args.next().expect("rtl8168d: no name provided"); - name.push_str("_rtl8168"); - - let bar_str = args.next().expect("rtl8168d: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address"); - - let irq_str = args.next().expect("rtl8168d: no irq provided"); - let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); - - print!("{}", format!(" + RTL8168 {} on: {:X}, IRQ: {}\n", name, bar, irq)); - - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("rtl8168d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); - - let mut irq_file = File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open IRQ file"); - - let address = unsafe { syscall::physmap(bar, 256, MAP_WRITE).expect("rtl8168d: failed to map address") }; - { - let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") })); - - let mut event_queue = EventQueue::::new().expect("rtl8168d: failed to create event queue"); - - let todo = Arc::new(RefCell::new(Vec::::new())); - - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - - let isr = unsafe { device_irq.borrow_mut().irq() }; - if isr != 0 { - irq_file.write(&mut irq)?; - - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - device_irq.borrow_mut().handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_irq.borrow_mut().write(&mut todo[i])?; - todo.remove(i); - } - } - - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }).expect("rtl8168d: failed to catch events on IRQ file"); - - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_count: usize| -> Result> { - loop { - let mut packet = Packet::default(); - if socket_packet.borrow_mut().read(&mut packet)? == 0 { - break; - } - - let a = packet.a; - device.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; - } - } - - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - - Ok(None) - }).expect("rtl8168d: failed to catch events on IRQ file"); - - for event_count in event_queue.trigger_all(0).expect("rtl8168d: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("rtl8168d: failed to write event"); - } - - loop { - let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); - - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("rtl8168d: failed to write event"); - } - } - unsafe { let _ = syscall::physunmap(address); } - } -} diff --git a/drivers/vesad/Cargo.toml b/drivers/vesad/Cargo.toml deleted file mode 100644 index 9041edb..0000000 --- a/drivers/vesad/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "vesad" -version = "0.1.0" - -[dependencies] -orbclient = "0.1" -ransid = "0.2" -rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true } -redox_syscall = { path = "../../syscall" } - -[features] -default = [] diff --git a/drivers/vesad/src/display.rs b/drivers/vesad/src/display.rs deleted file mode 100644 index 829d6ba..0000000 --- a/drivers/vesad/src/display.rs +++ /dev/null @@ -1,246 +0,0 @@ -#[cfg(feature="rusttype")] -extern crate rusttype; - -use alloc::heap; -use std::{cmp, slice}; - -use primitive::{fast_set32, fast_set64, fast_copy, fast_copy64}; - -#[cfg(feature="rusttype")] -use self::rusttype::{Font, FontCollection, Scale, point}; - -#[cfg(not(feature="rusttype"))] -static FONT: &'static [u8] = include_bytes!("../../../res/fonts/unifont.font"); - -#[cfg(feature="rusttype")] -static FONT: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono.ttf"); -#[cfg(feature="rusttype")] -static FONT_BOLD: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf"); -#[cfg(feature="rusttype")] -static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf"); -#[cfg(feature="rusttype")] -static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf"); - -/// A display -pub struct Display { - pub width: usize, - pub height: usize, - pub onscreen: &'static mut [u32], - pub offscreen: &'static mut [u32], - #[cfg(feature="rusttype")] - pub font: Font<'static>, - #[cfg(feature="rusttype")] - pub font_bold: Font<'static>, - #[cfg(feature="rusttype")] - pub font_bold_italic: Font<'static>, - #[cfg(feature="rusttype")] - pub font_italic: Font<'static> -} - -impl Display { - #[cfg(not(feature="rusttype"))] - pub fn new(width: usize, height: usize, onscreen: usize) -> Display { - let size = width * height; - let offscreen = unsafe { heap::allocate(size * 4, 4096) }; - unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; - Display { - width: width, - height: height, - onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, - offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } - } - } - - #[cfg(feature="rusttype")] - pub fn new(width: usize, height: usize, onscreen: usize) -> Display { - let size = width * height; - let offscreen = unsafe { heap::allocate(size * 4, 4096) }; - unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; - Display { - width: width, - height: height, - onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, - offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }, - font: FontCollection::from_bytes(FONT).into_font().unwrap(), - font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(), - font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(), - font_italic: FontCollection::from_bytes(FONT_ITALIC).into_font().unwrap() - } - } - - /// Draw a rectangle - pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) { - let start_y = cmp::min(self.height - 1, y); - let end_y = cmp::min(self.height, y + h); - - let start_x = cmp::min(self.width - 1, x); - let len = cmp::min(self.width, x + w) - start_x; - - let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - - let stride = self.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - unsafe { - fast_set32(offscreen_ptr as *mut u32, color, len); - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Invert a rectangle - pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(self.height - 1, y); - let end_y = cmp::min(self.height, y + h); - - let start_x = cmp::min(self.width - 1, x); - let len = cmp::min(self.width, x + w) - start_x; - - let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - - let stride = self.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - let mut row_ptr = offscreen_ptr; - let mut cols = len; - while cols > 0 { - unsafe { - let color = *(row_ptr as *mut u32); - *(row_ptr as *mut u32) = !color; - } - row_ptr += 4; - cols -= 1; - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Draw a character - #[cfg(not(feature="rusttype"))] - pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { - if x + 8 <= self.width && y + 16 <= self.height { - let mut dst = self.offscreen.as_mut_ptr() as usize + (y * self.width + x) * 4; - - let font_i = 16 * (character as usize); - if font_i + 16 <= FONT.len() { - for row in 0..16 { - let row_data = FONT[font_i + row]; - for col in 0..8 { - if (row_data >> (7 - col)) & 1 == 1 { - unsafe { *((dst + col * 4) as *mut u32) = color; } - } - } - dst += self.width * 4; - } - } - } - } - - /// Draw a character - #[cfg(feature="rusttype")] - pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, bold: bool, italic: bool) { - let width = self.width; - let height = self.height; - let offscreen = self.offscreen.as_mut_ptr() as usize; - - let font = if bold && italic { - &self.font_bold_italic - } else if bold { - &self.font_bold - } else if italic { - &self.font_italic - } else { - &self.font - }; - - if let Some(glyph) = font.glyph(character){ - let scale = Scale::uniform(16.0); - let v_metrics = font.v_metrics(scale); - let point = point(0.0, v_metrics.ascent); - let glyph = glyph.scaled(scale).positioned(point); - if let Some(bb) = glyph.pixel_bounding_box() { - glyph.draw(|off_x, off_y, v| { - let off_x = x + (off_x as i32 + bb.min.x) as usize; - let off_y = y + (off_y as i32 + bb.min.y) as usize; - // There's still a possibility that the glyph clips the boundaries of the bitmap - if off_x < width && off_y < height { - if v > 0.0 { - let f_a = (v * 255.0) as u32; - let f_r = (((color >> 16) & 0xFF) * f_a)/255; - let f_g = (((color >> 8) & 0xFF) * f_a)/255; - let f_b = ((color & 0xFF) * f_a)/255; - - let offscreen_ptr = (offscreen + (off_y * width + off_x) * 4) as *mut u32; - - let bg = unsafe { *offscreen_ptr }; - - let b_a = 255 - f_a; - let b_r = (((bg >> 16) & 0xFF) * b_a)/255; - let b_g = (((bg >> 8) & 0xFF) * b_a)/255; - let b_b = ((bg & 0xFF) * b_a)/255; - - let c = ((f_r + b_r) << 16) | ((f_g + b_g) << 8) | (f_b + b_b); - - unsafe { *offscreen_ptr = c; } - } - } - }); - } - } - } - - /// Scroll display - pub fn scroll(&mut self, rows: usize, color: u32) { - let data = (color as u64) << 32 | color as u64; - - let width = self.width/2; - let height = self.height; - if rows > 0 && rows < height { - let off1 = rows * width; - let off2 = height * width - off1; - unsafe { - let data_ptr = self.offscreen.as_mut_ptr() as *mut u64; - fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2); - fast_set64(data_ptr.offset(off2 as isize), data, off1); - } - } - } - - /// Copy from offscreen to onscreen - pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(self.height - 1, y); - let end_y = cmp::min(self.height, y + h); - - let start_x = cmp::min(self.width - 1, x); - let len = (cmp::min(self.width, x + w) - start_x) * 4; - - let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize; - - let stride = self.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - onscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - unsafe { - fast_copy(onscreen_ptr as *mut u8, offscreen_ptr as *const u8, len); - } - offscreen_ptr += stride; - onscreen_ptr += stride; - rows -= 1; - } - } -} diff --git a/drivers/vesad/src/main.rs b/drivers/vesad/src/main.rs deleted file mode 100644 index 7f4347a..0000000 --- a/drivers/vesad/src/main.rs +++ /dev/null @@ -1,109 +0,0 @@ -#![feature(alloc)] -#![feature(asm)] -#![feature(heap_api)] - -extern crate alloc; -extern crate orbclient; -extern crate syscall; - -use std::{env, mem}; -use std::fs::File; -use std::io::{Read, Write}; -use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; - -use mode_info::VBEModeInfo; -use primitive::fast_set64; -use scheme::DisplayScheme; - -pub mod display; -pub mod mode_info; -pub mod primitive; -pub mod scheme; -pub mod screen; - -fn main() { - let mut spec = Vec::new(); - - for arg in env::args().skip(1) { - if arg == "T" { - spec.push(false); - } else if arg == "G" { - spec.push(true); - } else { - println!("vesad: unknown screen type: {}", arg); - } - } - - let width; - let height; - let physbaseptr; - - { - let mode_info = unsafe { &*(physmap(0x5200, 4096, 0).expect("vesad: failed to map VBE info") as *const VBEModeInfo) }; - - width = mode_info.xresolution as usize; - height = mode_info.yresolution as usize; - physbaseptr = mode_info.physbaseptr as usize; - - unsafe { let _ = physunmap(mode_info as *const _ as usize); } - } - - if physbaseptr > 0 { - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); - - let size = width * height; - - let onscreen = unsafe { physmap(physbaseptr, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; - unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; - - let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); - - let mut blocked = Vec::new(); - loop { - let mut packet = Packet::default(); - socket.read(&mut packet).expect("vesad: failed to read display scheme"); - - // If it is a read packet, and there is no data, block it. Otherwise, handle packet - if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.will_block(packet.b) { - blocked.push(packet); - } else { - scheme.handle(&mut packet); - socket.write(&packet).expect("vesad: failed to write display scheme"); - } - - // If there are blocked readers, and data is available, handle them - { - let mut i = 0; - while i < blocked.len() { - if ! scheme.will_block(blocked[i].b) { - let mut packet = blocked.remove(i); - scheme.handle(&mut packet); - socket.write(&packet).expect("vesad: failed to write display scheme"); - } else { - i += 1; - } - } - } - - for (screen_id, screen) in scheme.screens.iter() { - if ! screen.will_block() { - let event_packet = Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *screen_id, - c: EVENT_READ, - d: mem::size_of::() - }; - - socket.write(&event_packet).expect("vesad: failed to write display event"); - } - } - } - } - } -} diff --git a/drivers/vesad/src/mode_info.rs b/drivers/vesad/src/mode_info.rs deleted file mode 100644 index 7d59af6..0000000 --- a/drivers/vesad/src/mode_info.rs +++ /dev/null @@ -1,37 +0,0 @@ -/// The info of the VBE mode -#[derive(Copy, Clone, Default, Debug)] -#[repr(packed)] -pub struct VBEModeInfo { - attributes: u16, - win_a: u8, - win_b: u8, - granularity: u16, - winsize: u16, - segment_a: u16, - segment_b: u16, - winfuncptr: u32, - bytesperscanline: u16, - pub xresolution: u16, - pub yresolution: u16, - xcharsize: u8, - ycharsize: u8, - numberofplanes: u8, - bitsperpixel: u8, - numberofbanks: u8, - memorymodel: u8, - banksize: u8, - numberofimagepages: u8, - unused: u8, - redmasksize: u8, - redfieldposition: u8, - greenmasksize: u8, - greenfieldposition: u8, - bluemasksize: u8, - bluefieldposition: u8, - rsvdmasksize: u8, - rsvdfieldposition: u8, - directcolormodeinfo: u8, - pub physbaseptr: u32, - offscreenmemoryoffset: u32, - offscreenmemsize: u16, -} diff --git a/drivers/vesad/src/primitive.rs b/drivers/vesad/src/primitive.rs deleted file mode 100644 index 16c2536..0000000 --- a/drivers/vesad/src/primitive.rs +++ /dev/null @@ -1,47 +0,0 @@ -#[cfg(target_arch = "x86_64")] -#[inline(always)] -#[cold] -pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) { - asm!("cld - rep movsb" - : - : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) - : "cc", "memory", "rdi", "rsi", "rcx" - : "intel", "volatile"); -} - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -#[cold] -pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) { - asm!("cld - rep movsq" - : - : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) - : "cc", "memory", "rdi", "rsi", "rcx" - : "intel", "volatile"); -} - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -#[cold] -pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) { - asm!("cld - rep stosd" - : - : "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len) - : "cc", "memory", "rdi", "rcx" - : "intel", "volatile"); -} - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -#[cold] -pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) { - asm!("cld - rep stosq" - : - : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len) - : "cc", "memory", "rdi", "rcx" - : "intel", "volatile"); -} diff --git a/drivers/vesad/src/scheme.rs b/drivers/vesad/src/scheme.rs deleted file mode 100644 index e376bf7..0000000 --- a/drivers/vesad/src/scheme.rs +++ /dev/null @@ -1,190 +0,0 @@ -use std::collections::BTreeMap; -use std::{mem, slice, str}; - -use orbclient::{Event, EventOption}; -use syscall::{Result, Error, EACCES, EBADF, ENOENT, SchemeMut}; - -use display::Display; -use screen::{Screen, GraphicScreen, TextScreen}; - -pub struct DisplayScheme { - active: usize, - pub screens: BTreeMap> -} - -impl DisplayScheme { - pub fn new(width: usize, height: usize, onscreen: usize, spec: &[bool]) -> DisplayScheme { - let mut screens: BTreeMap> = BTreeMap::new(); - - let mut screen_i = 1; - for &screen_type in spec.iter() { - if screen_type { - screens.insert(screen_i, Box::new(GraphicScreen::new(Display::new(width, height, onscreen)))); - } else { - screens.insert(screen_i, Box::new(TextScreen::new(Display::new(width, height, onscreen)))); - } - screen_i += 1; - } - - DisplayScheme { - active: 1, - screens: screens - } - } - - pub fn will_block(&self, id: usize) -> bool { - if let Some(screen) = self.screens.get(&id) { - screen.will_block() - } else { - false - } - } -} - -impl SchemeMut for DisplayScheme { - fn open(&mut self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { - if path == b"input" { - if uid == 0 { - Ok(0) - } else { - Err(Error::new(EACCES)) - } - } else { - let path_str = str::from_utf8(path).unwrap_or("").trim_matches('/'); - let mut parts = path_str.split('/'); - let id = parts.next().unwrap_or("").parse::().unwrap_or(0); - if self.screens.contains_key(&id) { - for cmd in parts { - if cmd == "activate" { - self.active = id; - } - } - Ok(id) - } else { - Err(Error::new(ENOENT)) - } - } - } - - fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { - Ok(id) - } - - fn fevent(&mut self, id: usize, flags: usize) -> Result { - if let Some(mut screen) = self.screens.get_mut(&id) { - screen.event(flags).and(Ok(id)) - } else { - Err(Error::new(EBADF)) - } - } - - fn fmap(&mut self, id: usize, offset: usize, size: usize) -> Result { - if let Some(screen) = self.screens.get(&id) { - screen.map(offset, size) - } else { - Err(Error::new(EBADF)) - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let path_str = if id == 0 { - format!("display:input") - } else if let Some(screen) = self.screens.get(&id) { - format!("display:{}/{}/{}", id, screen.width(), screen.height()) - } else { - return Err(Error::new(EBADF)); - }; - - let path = path_str.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } - - fn fsync(&mut self, id: usize) -> Result { - if let Some(mut screen) = self.screens.get_mut(&id) { - if id == self.active { - screen.sync(); - } - Ok(0) - } else { - Err(Error::new(EBADF)) - } - } - - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { - if let Some(mut screen) = self.screens.get_mut(&id) { - screen.read(buf) - } else { - Err(Error::new(EBADF)) - } - } - - fn write(&mut self, id: usize, buf: &[u8]) -> Result { - if id == 0 { - if buf.len() == 1 && buf[0] >= 0xF4 { - let new_active = (buf[0] - 0xF4) as usize + 1; - if let Some(mut screen) = self.screens.get_mut(&new_active) { - self.active = new_active; - screen.redraw(); - } - Ok(1) - } else { - let events = unsafe { slice::from_raw_parts(buf.as_ptr() as *const Event, buf.len()/mem::size_of::()) }; - - for event in events.iter() { - let new_active_opt = if let EventOption::Key(key_event) = event.to_option() { - match key_event.scancode { - f @ 0x3B ... 0x44 => { // F1 through F10 - Some((f - 0x3A) as usize) - }, - 0x57 => { // F11 - Some(11) - }, - 0x58 => { // F12 - Some(12) - }, - _ => None - } - } else { - None - }; - - if let Some(new_active) = new_active_opt { - if let Some(mut screen) = self.screens.get_mut(&new_active) { - self.active = new_active; - screen.redraw(); - } - } else { - if let Some(mut screen) = self.screens.get_mut(&self.active) { - screen.input(event); - } - } - } - - Ok(events.len() * mem::size_of::()) - } - } else if let Some(mut screen) = self.screens.get_mut(&id) { - screen.write(buf, id == self.active) - } else { - Err(Error::new(EBADF)) - } - } - - fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result { - if let Some(mut screen) = self.screens.get_mut(&id) { - screen.seek(pos, whence) - } else { - Err(Error::new(EBADF)) - } - } - - fn close(&mut self, _id: usize) -> Result { - Ok(0) - } -} diff --git a/drivers/vesad/src/screen/graphic.rs b/drivers/vesad/src/screen/graphic.rs deleted file mode 100644 index b911922..0000000 --- a/drivers/vesad/src/screen/graphic.rs +++ /dev/null @@ -1,126 +0,0 @@ -use std::collections::VecDeque; -use std::{cmp, mem, slice}; - -use orbclient::{Event, EventOption}; -use syscall::error::*; -use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; - -use display::Display; -use primitive::fast_copy; -use screen::Screen; - -pub struct GraphicScreen { - pub display: Display, - pub seek: usize, - pub mouse_x: i32, - pub mouse_y: i32, - pub input: VecDeque, - pub requested: usize -} - -impl GraphicScreen { - pub fn new(display: Display) -> GraphicScreen { - GraphicScreen { - display: display, - seek: 0, - mouse_x: 0, - mouse_y: 0, - input: VecDeque::new(), - requested: 0 - } - } -} - -impl Screen for GraphicScreen { - fn width(&self) -> usize { - self.display.width - } - - fn height(&self) -> usize { - self.display.height - } - - fn event(&mut self, flags: usize) -> Result { - self.requested = flags; - Ok(0) - } - - fn map(&self, offset: usize, size: usize) -> Result { - if offset + size <= self.display.offscreen.len() * 4 { - Ok(self.display.offscreen.as_ptr() as usize + offset) - } else { - Err(Error::new(EINVAL)) - } - } - - fn input(&mut self, event: &Event) { - if let EventOption::Mouse(mut mouse_event) = event.to_option() { - let x = cmp::max(0, cmp::min(self.display.width as i32, self.mouse_x + mouse_event.x)); - let y = cmp::max(0, cmp::min(self.display.height as i32, self.mouse_y + mouse_event.y)); - - mouse_event.x = x; - self.mouse_x = x; - mouse_event.y = y; - self.mouse_y = y; - - self.input.push_back(mouse_event.to_event()); - } else { - self.input.push_back(*event); - } - } - - fn read(&mut self, buf: &mut [u8]) -> Result { - let mut i = 0; - - let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::()) }; - - while i < event_buf.len() && ! self.input.is_empty() { - event_buf[i] = self.input.pop_front().unwrap(); - i += 1; - } - - Ok(i * mem::size_of::()) - } - - fn will_block(&self) -> bool { - self.input.is_empty() - } - - fn write(&mut self, buf: &[u8], sync: bool) -> Result { - let size = cmp::max(0, cmp::min(self.display.offscreen.len() as isize - self.seek as isize, (buf.len()/4) as isize)) as usize; - - if size > 0 { - unsafe { - fast_copy(self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4); - if sync { - fast_copy(self.display.onscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4); - } - } - } - - Ok(size * 4) - } - - fn seek(&mut self, pos: usize, whence: usize) -> Result { - let size = self.display.offscreen.len(); - - self.seek = match whence { - SEEK_SET => cmp::min(size, (pos/4)), - SEEK_CUR => cmp::max(0, cmp::min(size as isize, self.seek as isize + (pos/4) as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(size as isize, size as isize + (pos/4) as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(self.seek * 4) - } - - fn sync(&mut self) { - self.redraw(); - } - - fn redraw(&mut self) { - let width = self.display.width; - let height = self.display.height; - self.display.sync(0, 0, width, height); - } -} diff --git a/drivers/vesad/src/screen/mod.rs b/drivers/vesad/src/screen/mod.rs deleted file mode 100644 index 9909694..0000000 --- a/drivers/vesad/src/screen/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -pub use self::graphic::GraphicScreen; -pub use self::text::TextScreen; - -use orbclient::Event; -use syscall::Result; - -mod graphic; -mod text; - -pub trait Screen { - fn width(&self) -> usize; - - fn height(&self) -> usize; - - fn event(&mut self, flags: usize) -> Result; - - fn map(&self, offset: usize, size: usize) -> Result; - - fn input(&mut self, event: &Event); - - fn read(&mut self, buf: &mut [u8]) -> Result; - - fn will_block(&self) -> bool; - - fn write(&mut self, buf: &[u8], sync: bool) -> Result; - - fn seek(&mut self, pos: usize, whence: usize) -> Result; - - fn sync(&mut self); - - fn redraw(&mut self); -} diff --git a/drivers/vesad/src/screen/text.rs b/drivers/vesad/src/screen/text.rs deleted file mode 100644 index ccc259d..0000000 --- a/drivers/vesad/src/screen/text.rs +++ /dev/null @@ -1,233 +0,0 @@ -extern crate ransid; - -use std::collections::{BTreeSet, VecDeque}; - -use orbclient::{Event, EventOption}; -use syscall::error::*; - -use display::Display; -use screen::Screen; - -pub struct TextScreen { - pub console: ransid::Console, - pub display: Display, - pub changed: BTreeSet, - pub ctrl: bool, - pub input: VecDeque, - pub end_of_input: bool, - pub cooked: VecDeque, - pub requested: usize -} - -impl TextScreen { - pub fn new(display: Display) -> TextScreen { - TextScreen { - console: ransid::Console::new(display.width/8, display.height/16), - display: display, - changed: BTreeSet::new(), - ctrl: false, - input: VecDeque::new(), - end_of_input: false, - cooked: VecDeque::new(), - requested: 0 - } - } -} - -impl Screen for TextScreen { - fn width(&self) -> usize { - self.console.w - } - - fn height(&self) -> usize { - self.console.h - } - - fn event(&mut self, flags: usize) -> Result { - self.requested = flags; - Ok(0) - } - - fn map(&self, offset: usize, size: usize) -> Result { - Err(Error::new(EBADF)) - } - - fn input(&mut self, event: &Event) { - let mut buf = vec![]; - - match event.to_option() { - EventOption::Key(key_event) => { - if key_event.scancode == 0x1D { - self.ctrl = key_event.pressed; - } else if key_event.pressed { - match key_event.scancode { - 0x0E => { // Backspace - buf.extend_from_slice(b"\x7F"); - }, - 0x47 => { // Home - buf.extend_from_slice(b"\x1B[H"); - }, - 0x48 => { // Up - buf.extend_from_slice(b"\x1B[A"); - }, - 0x49 => { // Page up - buf.extend_from_slice(b"\x1B[5~"); - }, - 0x4B => { // Left - buf.extend_from_slice(b"\x1B[D"); - }, - 0x4D => { // Right - buf.extend_from_slice(b"\x1B[C"); - }, - 0x4F => { // End - buf.extend_from_slice(b"\x1B[F"); - }, - 0x50 => { // Down - buf.extend_from_slice(b"\x1B[B"); - }, - 0x51 => { // Page down - buf.extend_from_slice(b"\x1B[6~"); - }, - 0x52 => { // Insert - buf.extend_from_slice(b"\x1B[2~"); - }, - 0x53 => { // Delete - buf.extend_from_slice(b"\x1B[3~"); - }, - _ => { - let c = match key_event.character { - c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char, - c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char, - c => c - }; - - if c != '\0' { - buf.extend_from_slice(&[c as u8]); - } - } - } - } - }, - _ => () //TODO: Mouse in terminal - } - - if self.console.raw_mode { - for &b in buf.iter() { - self.input.push_back(b); - } - } else { - for &b in buf.iter() { - match b { - b'\x03' => { - self.end_of_input = true; - let _ = self.write(b"^C\n", true); - }, - b'\x08' | b'\x7F' => { - if let Some(_c) = self.cooked.pop_back() { - let _ = self.write(b"\x08", true); - } - }, - b'\x1B' => { - let _ = self.write(b"^[", true); - }, - b'\n' | b'\r' => { - self.cooked.push_back(b); - while let Some(c) = self.cooked.pop_front() { - self.input.push_back(c); - } - let _ = self.write(b"\n", true); - }, - _ => { - self.cooked.push_back(b); - let _ = self.write(&[b], true); - } - } - } - } - } - - fn read(&mut self, buf: &mut [u8]) -> Result { - let mut i = 0; - - while i < buf.len() && ! self.input.is_empty() { - buf[i] = self.input.pop_front().unwrap(); - i += 1; - } - - if i == 0 { - self.end_of_input = false; - } - - Ok(i) - } - - fn will_block(&self) -> bool { - self.input.is_empty() && ! self.end_of_input - } - - fn write(&mut self, buf: &[u8], sync: bool) -> Result { - if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { - let x = self.console.x; - let y = self.console.y; - self.display.invert(x * 8, y * 16, 8, 16); - self.changed.insert(y); - } - - { - let display = &mut self.display; - let changed = &mut self.changed; - self.console.write(buf, |event| { - match event { - ransid::Event::Char { x, y, c, color, bold, .. } => { - display.char(x * 8, y * 16, c, color.data, bold, false); - changed.insert(y); - }, - ransid::Event::Rect { x, y, w, h, color } => { - display.rect(x * 8, y * 16, w * 8, h * 16, color.data); - for y2 in y..y + h { - changed.insert(y2); - } - }, - ransid::Event::Scroll { rows, color } => { - display.scroll(rows * 16, color.data); - for y in 0..display.height/16 { - changed.insert(y); - } - } - } - }); - } - - if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { - let x = self.console.x; - let y = self.console.y; - self.display.invert(x * 8, y * 16, 8, 16); - self.changed.insert(y); - } - - if ! self.console.raw_mode && sync { - self.sync(); - } - - Ok(buf.len()) - } - - fn seek(&mut self, _pos: usize, _whence: usize) -> Result { - Ok(0) - } - - fn sync(&mut self) { - let width = self.display.width; - for change in self.changed.iter() { - self.display.sync(0, change * 16, width, 16); - } - self.changed.clear(); - } - - fn redraw(&mut self) { - let width = self.display.width; - let height = self.display.height; - self.display.sync(0, 0, width, height); - self.changed.clear(); - } -} diff --git a/filesystem.toml b/filesystem.toml new file mode 100644 index 0000000..8344c12 --- /dev/null +++ b/filesystem.toml @@ -0,0 +1,171 @@ +# This is the default configuration file + +# General settings +[general] +# Do not prompt if settings are not defined +prompt = false +sysroot = "build/filesystem" + +# Package settings +[packages] +#acid = {} +#binutils = {} +#ca-certificates = {} +#cargo = {} +#contain = {} +coreutils = {} +#curl = {} +#dash = {} +drivers = {} +extrautils = {} +findutils = {} +#games = {} +#gawk = {} +#gcc = {} +#git = {} +#gnu-binutils = {} +#gnu-make = {} +#installer = {} +ion = {} +#lua = {} +#nasm = {} +netstack = {} +netutils = {} +#newlib = {} +orbdata = {} +orbital = {} +orbterm = {} +orbutils = {} +#pastel = {} +#pixelcannon = {} +pkgutils = {} +ptyd = {} +#python = {} +randd = {} +#redoxfs = {} +#rust = {} +#rustual-boy = {} +#sed = {} +smith = {} +#sodium = {} +userutils = {} +uutils = {} + +# User settings +[users.root] +# Password is set to "password" +password = "$argon2i$m=4096,t=10,p=1$Tnc4UVV0N00$ML9LIOujd3nmAfkAwEcSTMPqakWUF0OUiLWrIy0nGLk" +uid = 0 +gid = 0 +name = "root" +home = "/root" + +[users.user] +# Password is unset +password = "" + +[[files]] +path = "/etc/init.d/00_base" +data = """ +pcid /etc/pcid/filesystem.toml +randd +ptyd +""" + +[[files]] +path = "/etc/init.d/10_net" +data = """ +ethernetd +ipd +icmpd +tcpd +udpd +dhcpd -b +""" + +[[files]] +path = "/etc/init.d/20_orbital" +data = """ +orbital display:3/activate orblogin launcher +""" + +[[files]] +path = "/etc/init.d/30_console" +data = """ +getty display:2 +getty debug: -J +""" + +[[files]] +path = "/etc/net/dns" +data = """ +208.67.222.222 +""" + +[[files]] +path = "/etc/net/ip" +data = """ +10.0.2.15 +""" + +[[files]] +path = "/etc/net/ip_router" +data = """ +10.0.2.2 +""" + +[[files]] +path = "/etc/net/ip_subnet" +data = """ +255.255.255.0 +""" + +[[files]] +path = "/etc/net/mac" +data = """ +54-52-00-ab-cd-ef +""" + +[[files]] +path = "/etc/pkg.d/50_redox" +data = "https://static.redox-os.org/pkg" + +[[files]] +path = "/etc/group" +data = """ +root;0;root +user;1000;user +sudo;1;user +""" + +[[files]] +path = "/etc/hostname" +data = """ +redox +""" + +[[files]] +path = "/etc/issue" +data = """ +########## Redox OS ########## +# Login with the following: # +# `user` # +# `root`:`password` # +############################## + +""" + +[[files]] +path = "/etc/motd" +data = """ +Welcome to Redox OS! + +""" + +[[files]] +path = "/home/user/.ionrc" +data = "" + +[[files]] +path = "/root/.ionrc" +data = "" diff --git a/filesystem/etc/group b/filesystem/etc/group deleted file mode 100644 index 62fcd49..0000000 --- a/filesystem/etc/group +++ /dev/null @@ -1 +0,0 @@ -sudo;1;user diff --git a/filesystem/etc/init.rc b/filesystem/etc/init.rc deleted file mode 100644 index ca4b860..0000000 --- a/filesystem/etc/init.rc +++ /dev/null @@ -1,12 +0,0 @@ -/sbin/randd -/sbin/ptyd -/sbin/pcid /etc/pcid.toml -/sbin/ethernetd -/sbin/ipd -/sbin/tcpd -/sbin/udpd -dhcpd -b -getty display:2 -getty display:3 -/sbin/orbital display:4/activate /ui/bin/orblogin /ui/bin/launcher -getty debug: -J diff --git a/filesystem/etc/issue b/filesystem/etc/issue deleted file mode 100644 index 6a963d8..0000000 --- a/filesystem/etc/issue +++ /dev/null @@ -1,6 +0,0 @@ -########## Redox OS ########## -# Login with the following: # -# `user` # -# `root`:`password` # -############################## - diff --git a/filesystem/etc/motd b/filesystem/etc/motd deleted file mode 100644 index 5cd097a..0000000 --- a/filesystem/etc/motd +++ /dev/null @@ -1,2 +0,0 @@ -Welcome to Redox OS! - diff --git a/filesystem/etc/net/dns b/filesystem/etc/net/dns deleted file mode 100644 index 85e3287..0000000 --- a/filesystem/etc/net/dns +++ /dev/null @@ -1 +0,0 @@ -208.67.222.222 diff --git a/filesystem/etc/net/ip b/filesystem/etc/net/ip deleted file mode 100644 index b86c8a7..0000000 --- a/filesystem/etc/net/ip +++ /dev/null @@ -1 +0,0 @@ -10.0.2.15 diff --git a/filesystem/etc/net/ip_router b/filesystem/etc/net/ip_router deleted file mode 100644 index 2e66646..0000000 --- a/filesystem/etc/net/ip_router +++ /dev/null @@ -1 +0,0 @@ -10.0.2.2 diff --git a/filesystem/etc/net/ip_subnet b/filesystem/etc/net/ip_subnet deleted file mode 100644 index d30f9e9..0000000 --- a/filesystem/etc/net/ip_subnet +++ /dev/null @@ -1 +0,0 @@ -255.255.255.0 diff --git a/filesystem/etc/net/mac b/filesystem/etc/net/mac deleted file mode 100644 index f02dd3e..0000000 --- a/filesystem/etc/net/mac +++ /dev/null @@ -1 +0,0 @@ -00.00.00.00.00.00 diff --git a/filesystem/etc/orbital.conf b/filesystem/etc/orbital.conf deleted file mode 100644 index 8d46aba..0000000 --- a/filesystem/etc/orbital.conf +++ /dev/null @@ -1,2 +0,0 @@ -background=/ui/background.png -cursor=/ui/cursor.png diff --git a/filesystem/etc/passwd b/filesystem/etc/passwd deleted file mode 100644 index 7baaf91..0000000 --- a/filesystem/etc/passwd +++ /dev/null @@ -1,2 +0,0 @@ -root;$argon2i$m=4096,t=10,p=1$Tnc4UVV0N00$ML9LIOujd3nmAfkAwEcSTMPqakWUF0OUiLWrIy0nGLk;0;0;root;/root;/bin/ion -user;;1000;1000;user;/home/user;/bin/ion diff --git a/filesystem/etc/pcid.toml b/filesystem/etc/pcid.toml deleted file mode 100644 index da177da..0000000 --- a/filesystem/etc/pcid.toml +++ /dev/null @@ -1,13 +0,0 @@ -[[drivers]] -name = "E1000 NIC" -class = 2 -vendor = 32902 -device = 4110 -command = ["/sbin/e1000d", "$NAME", "$BAR0", "$IRQ"] - -[[drivers]] -name = "RTL8168 NIC" -class = 2 -vendor = 4332 -device = 33128 -command = ["/sbin/rtl8168d", "$NAME", "$BAR2", "$IRQ"] diff --git a/filesystem/home/user/LICENSE b/filesystem/home/user/LICENSE deleted file mode 120000 index 5853aae..0000000 --- a/filesystem/home/user/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../LICENSE \ No newline at end of file diff --git a/filesystem/home/user/README.md b/filesystem/home/user/README.md deleted file mode 120000 index 8a33348..0000000 --- a/filesystem/home/user/README.md +++ /dev/null @@ -1 +0,0 @@ -../../../README.md \ No newline at end of file diff --git a/filesystem/root/LICENSE b/filesystem/root/LICENSE deleted file mode 120000 index 30cff74..0000000 --- a/filesystem/root/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/filesystem/root/README.md b/filesystem/root/README.md deleted file mode 120000 index fe84005..0000000 --- a/filesystem/root/README.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md \ No newline at end of file diff --git a/filesystem/ui b/filesystem/ui deleted file mode 160000 index e8c057a..0000000 --- a/filesystem/ui +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e8c057a343c2f55c38a134ac9db65f3c7f5c8eb2 diff --git a/initfs.toml b/initfs.toml new file mode 100644 index 0000000..1f23e58 --- /dev/null +++ b/initfs.toml @@ -0,0 +1,27 @@ +# This is the default configuration file + +# General settings +[general] +# Do not prompt if settings are not defined +prompt = false +sysroot = "build/initfs" + +# Package settings +[packages] +drivers = {} +init = {} +redoxfs = {} + +[[files]] +path="/etc/init.rc" +data=""" +export PATH /bin +export TMPDIR /tmp +vesad T T G +stdio display:1 +ps2d +pcid /etc/pcid/initfs.toml +redoxfs disk:0 file +cd file: +run.d /etc/init.d +""" diff --git a/initfs/etc/init.rc b/initfs/etc/init.rc deleted file mode 100644 index 1bfc59d..0000000 --- a/initfs/etc/init.rc +++ /dev/null @@ -1,9 +0,0 @@ -export PATH initfs:/bin -vesad T T T G -stdio display:1 -ps2d -pcid /etc/pcid.toml -redoxfs disk:0 file -cd file: -export PATH file:/bin -run /etc/init.rc diff --git a/initfs/etc/pcid.toml b/initfs/etc/pcid.toml deleted file mode 100644 index 65813a7..0000000 --- a/initfs/etc/pcid.toml +++ /dev/null @@ -1,19 +0,0 @@ -[[drivers]] -name = "AHCI storage" -class = 1 -subclass = 6 -command = ["ahcid", "$NAME", "$BAR5", "$IRQ"] - -[[drivers]] -name = "Bochs Graphics Array" -class = 3 -vendor = 4660 -device = 4369 -command = ["bgad", "$NAME", "$BAR0"] - -[[drivers]] -name = "Bochs Graphics Array" -class = 3 -vendor = 33006 -device = 48879 -command = ["bgad", "$NAME", "$BAR0"] diff --git a/installer b/installer new file mode 160000 index 0000000..a76c8df --- /dev/null +++ b/installer @@ -0,0 +1 @@ +Subproject commit a76c8df8675ac5a173f40aef129fbc075867a48f diff --git a/isolinux b/isolinux new file mode 160000 index 0000000..3cf79d3 --- /dev/null +++ b/isolinux @@ -0,0 +1 @@ +Subproject commit 3cf79d335400af8fc3a87a13f0ae12777a766b3b diff --git a/isolinux/COPYING b/isolinux/COPYING deleted file mode 100644 index 60549be..0000000 --- a/isolinux/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/isolinux/isolinux.bin b/isolinux/isolinux.bin deleted file mode 100644 index e099c90..0000000 Binary files a/isolinux/isolinux.bin and /dev/null differ diff --git a/isolinux/isolinux.cfg b/isolinux/isolinux.cfg deleted file mode 100644 index 20e6848..0000000 --- a/isolinux/isolinux.cfg +++ /dev/null @@ -1,6 +0,0 @@ -prompt 0 -default 1 - -label 1 - kernel /isolinux/memdisk - append initrd=/livedisk.gz diff --git a/isolinux/ldlinux.c32 b/isolinux/ldlinux.c32 deleted file mode 100644 index e433013..0000000 Binary files a/isolinux/ldlinux.c32 and /dev/null differ diff --git a/isolinux/memdisk b/isolinux/memdisk deleted file mode 100644 index 1a9b2e5..0000000 Binary files a/isolinux/memdisk and /dev/null differ diff --git a/kernel b/kernel new file mode 160000 index 0000000..5c5e5da --- /dev/null +++ b/kernel @@ -0,0 +1 @@ +Subproject commit 5c5e5da7c2503dc68cd254259fe7992ce29df8d6 diff --git a/kernel/README.md b/kernel/README.md deleted file mode 100644 index e9c8a98..0000000 --- a/kernel/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# kernel - -A collaborative effort to rewrite the kernel with focus on correctness and code -quality. - -## Why? - -The kernel code was getting increasingly messy to the point where only the -original writer would be able to find and fix bugs. Fortunately, the kernel of -Redox is relatively small and such a project is estimated to take only a few -months. - -## What? - -The aims of the new kernel should be clear in their order: - -1. **Correctness**: Above anything else, the kernel should be correct. No hacks, -despite how the tiny cool shortcuts might seem, it gives severe backslash later -on. Keep it correct and well-written. - -2. **Readability and documentation**: The code quality should be high, with that -follows a detailed documentation, including both API docs (on every item!) and -careful comments for anything non-trivial. - -3. **Performance**: If you can, go for it. - -## Guidelines - -### A rotten house is built on a rotten fundament. - -Don't fool yourself. You are likely not getting back to the ugly code. Write it -the right way **first time**, and make sure you only move on when it's -**done right**. - -### Comments - -Do not hesitate to put comments all over the place. - -### Documentation - -Every public item should contain API documentation. - -### Debug assertions - -Abusing debug assertions is a wonderful way to catch bugs, and it is very much -encouraged. - -### Statical checking - -Rust provides a lot of type-system features which can be used to create -wonderful safe abstractions, and you should use them whenever you get the chance. - -Unsafety should be avoided, and if it is triggered only under some addition -**insert an assertion**. Despite this being a kernel, we prefer kernel panics -over security vulnerabilities. - -If the condition is (or should be) unreachable, but if not upheld, leading to -UB, put an assertion in the start of the function. - -### Be gentle - -Don't just write as much code as you can as quick as possible. Take your time -and be careful. - -### Commits - -Use descriptive commits. One way to force yourself to do that is to not pass the -`-m` flag, which will make your editor pop up, so that you can conviniently -write long commit messages. diff --git a/kernel/common/int_like.rs b/kernel/common/int_like.rs deleted file mode 100644 index 10f8423..0000000 --- a/kernel/common/int_like.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Helpers used to define types that are backed by integers (typically `usize`), -//! without compromising safety. -//! -//! # Example -//! -//! ``` -//! /// Define an opaque type `Pid` backed by a `usize`. -//! int_like!(Pid, usize); -//! -//! const ZERO: Pid = Pid::from(0); -//! ``` -//! -//! # Example -//! -//! ``` -//! /// Define opaque types `Pid` and `AtomicPid`, backed respectively by a `usize` -//! /// and a `AtomicUsize`. -//! -//! int_like!(Pid, AtomicPid, usize, AtomicUsize); -//! -//! const ZERO: Pid = Pid::from(0); -//! let ATOMIC_PID: AtomicPid = AtomicPid::default(); -//! ``` - -#[macro_export] -macro_rules! int_like { - ($new_type_name:ident, $backing_type: ident) => { - #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] - pub struct $new_type_name($backing_type); - - impl $new_type_name { - pub const fn into(self) -> $backing_type { - self.0 - } - pub const fn from(x: $backing_type) -> Self { - $new_type_name(x) - } - } - }; - - ($new_type_name:ident, $new_atomic_type_name: ident, $backing_type:ident, $backing_atomic_type:ident) => { - int_like!($new_type_name, $backing_type); - - /// A mutable holder for T that can safely be shared among threads. - /// Runtime equivalent to using `AtomicUsize`, just type-safer. - pub struct $new_atomic_type_name { - container: $backing_atomic_type, - } - - impl $new_atomic_type_name { - pub const fn new(x: $new_type_name) -> Self { - $new_atomic_type_name { - container: $backing_atomic_type::new(x.into()) - } - } - pub const fn default() -> Self { - Self::new($new_type_name::from(0)) - } - pub fn load(&self, order: ::core::sync::atomic::Ordering) -> $new_type_name { - $new_type_name::from(self.container.load(order)) - } - pub fn store(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) { - self.container.store(val.into(), order) - } - #[allow(dead_code)] - pub fn swap(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) -> $new_type_name { - $new_type_name::from(self.container.swap(val.into(), order)) - } - #[allow(dead_code)] - pub fn compare_and_swap(&self, current: $new_type_name, new: $new_type_name, order: ::core::sync::atomic::Ordering) -> $new_type_name { - $new_type_name::from(self.container.compare_and_swap(current.into(), new.into(), order)) - } - #[allow(dead_code)] - pub fn compare_exchange(&self, current: $new_type_name, new: $new_type_name, success: ::core::sync::atomic::Ordering, failure: ::core::sync::atomic::Ordering) -> ::core::result::Result<$new_type_name, $new_type_name> { - match self.container.compare_exchange(current.into(), new.into(), success, failure) { - Ok(result) => Ok($new_type_name::from(result)), - Err(result) => Err($new_type_name::from(result)) - } - } - #[allow(dead_code)] - pub fn compare_exchange_weak(&self, current: $new_type_name, new: $new_type_name, success: ::core::sync::atomic::Ordering, failure: ::core::sync::atomic::Ordering) -> ::core::result::Result<$new_type_name, $new_type_name> { - match self.container.compare_exchange_weak(current.into(), new.into(), success, failure) { - Ok(result) => Ok($new_type_name::from(result)), - Err(result) => Err($new_type_name::from(result)) - } - } - } - } -} - -#[cfg(test)] -fn test() { - use core::mem::size_of; - use ::core::sync::atomic::AtomicUsize; - - // Generate type `usize_like`. - int_like!(UsizeLike, usize); - const ZERO: UsizeLike = UsizeLike::from(0); - assert_eq!(size_of::(), size_of::()); - - - // Generate types `usize_like` and `AtomicUsize`. - int_like!(UsizeLike2, AtomicUsizeLike, usize, AtomicUsize); - assert_eq!(size_of::(), size_of::()); - assert_eq!(size_of::(), size_of::()); -} - - diff --git a/kernel/common/mod.rs b/kernel/common/mod.rs deleted file mode 100644 index 29f6412..0000000 --- a/kernel/common/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[macro_use] -pub mod int_like; diff --git a/kernel/context/context.rs b/kernel/context/context.rs deleted file mode 100644 index 607653c..0000000 --- a/kernel/context/context.rs +++ /dev/null @@ -1,252 +0,0 @@ -use alloc::arc::Arc; -use alloc::boxed::Box; -use collections::{BTreeMap, Vec, VecDeque}; -use spin::Mutex; - -use arch; -use context::file::File; -use context::memory::{Grant, Memory, SharedMemory, Tls}; -use scheme::{SchemeNamespace, FileHandle}; -use syscall::data::Event; -use sync::{WaitMap, WaitQueue}; - -/// Unique identifier for a context (i.e. `pid`). -use ::core::sync::atomic::AtomicUsize; -int_like!(ContextId, AtomicContextId, usize, AtomicUsize); - -/// The status of a context - used for scheduling -/// See syscall::process::waitpid and the sync module for examples of usage -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Status { - Runnable, - Blocked, - Exited(usize) -} - -/// A context, which identifies either a process or a thread -#[derive(Debug)] -pub struct Context { - /// The ID of this context - pub id: ContextId, - /// The ID of the parent context - pub ppid: ContextId, - /// The real user id - pub ruid: u32, - /// The real group id - pub rgid: u32, - /// The real namespace id - pub rns: SchemeNamespace, - /// The effective user id - pub euid: u32, - /// The effective group id - pub egid: u32, - /// The effective namespace id - pub ens: SchemeNamespace, - /// Status of context - pub status: Status, - /// Context running or not - pub running: bool, - /// CPU ID, if locked - pub cpu_id: Option, - /// Context is halting parent - pub vfork: bool, - /// Context is being waited on - pub waitpid: Arc>, - /// Context should handle pending signals - pub pending: VecDeque, - /// Context should wake up at specified time - pub wake: Option<(u64, u64)>, - /// The architecture specific context - pub arch: arch::context::Context, - /// Kernel FX - used to store SIMD and FPU registers on context switch - pub kfx: Option>, - /// Kernel stack - pub kstack: Option>, - /// Executable image - pub image: Vec, - /// User heap - pub heap: Option, - /// User stack - pub stack: Option, - /// User Thread local storage - pub tls: Option, - /// User grants - pub grants: Arc>>, - /// The name of the context - pub name: Arc>>, - /// The current working directory - pub cwd: Arc>>, - /// Kernel events - pub events: Arc>, - /// The process environment - pub env: Arc, Arc>>>>>, - /// The open files in the scheme - pub files: Arc>>> -} - -impl Context { - pub fn new(id: ContextId) -> Context { - Context { - id: id, - ppid: ContextId::from(0), - ruid: 0, - rgid: 0, - rns: SchemeNamespace::from(0), - euid: 0, - egid: 0, - ens: SchemeNamespace::from(0), - status: Status::Blocked, - running: false, - cpu_id: None, - vfork: false, - waitpid: Arc::new(WaitMap::new()), - pending: VecDeque::new(), - wake: None, - arch: arch::context::Context::new(), - kfx: None, - kstack: None, - image: Vec::new(), - heap: None, - stack: None, - tls: None, - grants: Arc::new(Mutex::new(Vec::new())), - name: Arc::new(Mutex::new(Vec::new())), - cwd: Arc::new(Mutex::new(Vec::new())), - events: Arc::new(WaitQueue::new()), - env: Arc::new(Mutex::new(BTreeMap::new())), - files: Arc::new(Mutex::new(Vec::new())) - } - } - - /// Make a relative path absolute - /// Given a cwd of "scheme:/path" - /// This function will turn "foo" into "scheme:/path/foo" - /// "/foo" will turn into "scheme:/foo" - /// "bar:/foo" will be used directly, as it is already absolute - pub fn canonicalize(&self, path: &[u8]) -> Vec { - if path.iter().position(|&b| b == b':').is_none() { - let cwd = self.cwd.lock(); - if path == b"." { - cwd.clone() - } else if path == b".." { - cwd[..cwd[..cwd.len() - 1] - .iter().rposition(|&b| b == b'/' || b == b':') - .map_or(cwd.len(), |i| i + 1)] - .to_vec() - } else if path.starts_with(b"./") { - let mut canon = cwd.clone(); - if ! canon.ends_with(b"/") { - canon.push(b'/'); - } - canon.extend_from_slice(&path[2..]); - canon - } else if path.starts_with(b"../") { - let mut canon = cwd[..cwd[..cwd.len() - 1] - .iter().rposition(|&b| b == b'/' || b == b':') - .map_or(cwd.len(), |i| i + 1)] - .to_vec(); - canon.extend_from_slice(&path[3..]); - canon - } else if path.starts_with(b"/") { - let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec(); - canon.extend_from_slice(&path); - canon - } else { - let mut canon = cwd.clone(); - if ! canon.ends_with(b"/") { - canon.push(b'/'); - } - canon.extend_from_slice(&path); - canon - } - } else { - path.to_vec() - } - } - - /// Block the context, and return true if it was runnable before being blocked - pub fn block(&mut self) -> bool { - if self.status == Status::Runnable { - self.status = Status::Blocked; - true - } else { - false - } - } - - /// Unblock context, and return true if it was blocked before being marked runnable - pub fn unblock(&mut self) -> bool { - if self.status == Status::Blocked { - self.status = Status::Runnable; - if let Some(cpu_id) = self.cpu_id { - if cpu_id != ::cpu_id() { - // Send IPI if not on current CPU - // TODO: Make this more architecture independent - unsafe { arch::device::local_apic::LOCAL_APIC.ipi(cpu_id) }; - } - } - true - } else { - false - } - } - - /// Add a file to the lowest available slot. - /// Return the file descriptor number or None if no slot was found - pub fn add_file(&self, file: File) -> Option { - let mut files = self.files.lock(); - for (i, mut file_option) in files.iter_mut().enumerate() { - if file_option.is_none() { - *file_option = Some(file); - return Some(FileHandle::from(i)); - } - } - let len = files.len(); - if len < super::CONTEXT_MAX_FILES { - files.push(Some(file)); - Some(FileHandle::from(len)) - } else { - None - } - } - - /// Get a file - pub fn get_file(&self, i: FileHandle) -> Option { - let files = self.files.lock(); - if i.into() < files.len() { - files[i.into()] - } else { - None - } - } - - /// Insert a file with a specific handle number. This is used by dup2 - /// Return the file descriptor number or None if the slot was not empty, or i was invalid - pub fn insert_file(&self, i: FileHandle, file: File) -> Option { - let mut files = self.files.lock(); - if i.into() < super::CONTEXT_MAX_FILES { - while i.into() >= files.len() { - files.push(None); - } - if files[i.into()].is_none() { - files[i.into()] = Some(file); - Some(i) - } else { - None - } - } else { - None - } - } - - /// Remove a file - // TODO: adjust files vector to smaller size if possible - pub fn remove_file(&self, i: FileHandle) -> Option { - let mut files = self.files.lock(); - if i.into() < files.len() { - files[i.into()].take() - } else { - None - } - } -} diff --git a/kernel/context/event.rs b/kernel/context/event.rs deleted file mode 100644 index c6c9431..0000000 --- a/kernel/context/event.rs +++ /dev/null @@ -1,112 +0,0 @@ -use alloc::arc::{Arc, Weak}; -use collections::BTreeMap; -use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; - -use context; -use scheme::{FileHandle, SchemeId}; -use sync::WaitQueue; -use syscall::data::Event; - -type EventList = Weak>; - -#[derive(PartialEq, Eq, PartialOrd, Ord)] -pub struct RegKey { - scheme_id: SchemeId, - event_id: usize, -} - -#[derive(PartialEq, Eq, PartialOrd, Ord)] -pub struct ProcessKey { - context_id: context::context::ContextId, - fd: FileHandle, -} - -type Registry = BTreeMap>; - -static REGISTRY: Once> = Once::new(); - -/// Initialize registry, called if needed -fn init_registry() -> RwLock { - RwLock::new(Registry::new()) -} - -/// Get the global schemes list, const -fn registry() -> RwLockReadGuard<'static, Registry> { - REGISTRY.call_once(init_registry).read() -} - -/// Get the global schemes list, mutable -pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> { - REGISTRY.call_once(init_registry).write() -} - -pub fn register(fd: FileHandle, scheme_id: SchemeId, event_id: usize) -> bool { - let (context_id, events) = { - let contexts = context::contexts(); - let context_lock = contexts.current().expect("event::register: No context"); - let context = context_lock.read(); - (context.id, Arc::downgrade(&context.events)) - }; - - let mut registry = registry_mut(); - let entry = registry.entry(RegKey { - scheme_id: scheme_id, - event_id: event_id - }).or_insert_with(|| { - BTreeMap::new() - }); - let process_key = ProcessKey { - context_id: context_id, - fd: fd - }; - if entry.contains_key(&process_key) { - false - } else { - entry.insert(process_key, events); - true - } -} - -pub fn unregister(fd: FileHandle, scheme_id: SchemeId, event_id: usize) { - let mut registry = registry_mut(); - - let mut remove = false; - let key = RegKey { - scheme_id: scheme_id, - event_id: event_id - }; - if let Some(entry) = registry.get_mut(&key) { - let process_key = ProcessKey { - context_id: context::context_id(), - fd: fd, - }; - entry.remove(&process_key); - - if entry.is_empty() { - remove = true; - } - } - - if remove { - registry.remove(&key); - } -} - -pub fn trigger(scheme_id: SchemeId, event_id: usize, flags: usize, data: usize) { - let registry = registry(); - let key = RegKey { - scheme_id: scheme_id, - event_id: event_id - }; - if let Some(event_lists) = registry.get(&key) { - for entry in event_lists.iter() { - if let Some(event_list) = entry.1.upgrade() { - event_list.send(Event { - id: (entry.0).fd.into(), - flags: flags, - data: data - }); - } - } - } -} diff --git a/kernel/context/file.rs b/kernel/context/file.rs deleted file mode 100644 index 26e0863..0000000 --- a/kernel/context/file.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! File struct - -use scheme::SchemeId; - -/// A file -//TODO: Close on exec -#[derive(Copy, Clone, Debug)] -pub struct File { - /// The scheme that this file refers to - pub scheme: SchemeId, - /// The number the scheme uses to refer to this file - pub number: usize, - /// If events are on, this is the event ID - pub event: Option, -} diff --git a/kernel/context/list.rs b/kernel/context/list.rs deleted file mode 100644 index 11c25c2..0000000 --- a/kernel/context/list.rs +++ /dev/null @@ -1,91 +0,0 @@ -use alloc::arc::Arc; -use alloc::boxed::Box; -use collections::BTreeMap; -use core::mem; -use core::sync::atomic::Ordering; -use spin::RwLock; - -use arch; -use syscall::error::{Result, Error, EAGAIN}; -use super::context::{Context, ContextId}; - -/// Context list type -pub struct ContextList { - map: BTreeMap>>, - next_id: usize -} - -impl ContextList { - /// Create a new context list. - pub fn new() -> Self { - ContextList { - map: BTreeMap::new(), - next_id: 1 - } - } - - /// Get the nth context. - pub fn get(&self, id: ContextId) -> Option<&Arc>> { - self.map.get(&id) - } - - /// Get the current context. - pub fn current(&self) -> Option<&Arc>> { - self.map.get(&super::CONTEXT_ID.load(Ordering::SeqCst)) - } - - pub fn iter(&self) -> ::collections::btree_map::Iter>> { - self.map.iter() - } - - /// Create a new context. - pub fn new_context(&mut self) -> Result<&Arc>> { - if self.next_id >= super::CONTEXT_MAX_CONTEXTS { - self.next_id = 1; - } - - while self.map.contains_key(&ContextId::from(self.next_id)) { - self.next_id += 1; - } - - if self.next_id >= super::CONTEXT_MAX_CONTEXTS { - return Err(Error::new(EAGAIN)); - } - - let id = ContextId::from(self.next_id); - self.next_id += 1; - - assert!(self.map.insert(id, Arc::new(RwLock::new(Context::new(id)))).is_none()); - - Ok(self.map.get(&id).expect("Failed to insert new context. ID is out of bounds.")) - } - - /// Spawn a context from a function. - pub fn spawn(&mut self, func: extern fn()) -> Result<&Arc>> { - let context_lock = self.new_context()?; - { - let mut context = context_lock.write(); - let mut fx = unsafe { Box::from_raw(::alloc::heap::allocate(512, 16) as *mut [u8; 512]) }; - for b in fx.iter_mut() { - *b = 0; - } - let mut stack = vec![0; 65536].into_boxed_slice(); - let offset = stack.len() - mem::size_of::(); - unsafe { - let offset = stack.len() - mem::size_of::(); - let func_ptr = stack.as_mut_ptr().offset(offset as isize); - *(func_ptr as *mut usize) = func as usize; - } - context.arch.set_page_table(unsafe { arch::paging::ActivePageTable::new().address() }); - context.arch.set_fx(fx.as_ptr() as usize); - context.arch.set_stack(stack.as_ptr() as usize + offset); - context.kfx = Some(fx); - context.kstack = Some(stack); - } - Ok(context_lock) - } - - pub fn remove(&mut self, id: ContextId) -> Option>> { - self.map.remove(&id) - } -} diff --git a/kernel/context/memory.rs b/kernel/context/memory.rs deleted file mode 100644 index 73f808c..0000000 --- a/kernel/context/memory.rs +++ /dev/null @@ -1,362 +0,0 @@ -use alloc::arc::{Arc, Weak}; -use collections::VecDeque; -use core::intrinsics; -use spin::Mutex; - -use arch::memory::Frame; -use arch::paging::{ActivePageTable, InactivePageTable, Page, PageIter, PhysicalAddress, VirtualAddress}; -use arch::paging::entry::{self, EntryFlags}; -use arch::paging::temporary_page::TemporaryPage; - -#[derive(Debug)] -pub struct Grant { - start: VirtualAddress, - size: usize, - flags: EntryFlags, - mapped: bool -} - -impl Grant { - pub fn physmap(from: PhysicalAddress, to: VirtualAddress, size: usize, flags: EntryFlags) -> Grant { - let mut active_table = unsafe { ActivePageTable::new() }; - - let mut flush_all = false; - - let start_page = Page::containing_address(to); - let end_page = Page::containing_address(VirtualAddress::new(to.get() + size - 1)); - for page in Page::range_inclusive(start_page, end_page) { - let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get() - to.get() + from.get())); - active_table.map_to(page, frame, flags); - flush_all = true; - } - - if flush_all { - active_table.flush_all(); - } - - Grant { - start: to, - size: size, - flags: flags, - mapped: true - } - } - - pub fn map_inactive(from: VirtualAddress, to: VirtualAddress, size: usize, flags: EntryFlags, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) -> Grant { - let mut active_table = unsafe { ActivePageTable::new() }; - - let mut frames = VecDeque::new(); - - let start_page = Page::containing_address(from); - let end_page = Page::containing_address(VirtualAddress::new(from.get() + size - 1)); - for page in Page::range_inclusive(start_page, end_page) { - let frame = active_table.translate_page(page).expect("grant references unmapped memory"); - frames.push_back(frame); - } - - active_table.with(new_table, temporary_page, |mapper| { - let start_page = Page::containing_address(to); - let end_page = Page::containing_address(VirtualAddress::new(to.get() + size - 1)); - for page in Page::range_inclusive(start_page, end_page) { - let frame = frames.pop_front().expect("grant did not find enough frames"); - mapper.map_to(page, frame, flags); - } - }); - - Grant { - start: to, - size: size, - flags: flags, - mapped: true - } - } - - pub fn start_address(&self) -> VirtualAddress { - self.start - } - - pub fn size(&self) -> usize { - self.size - } - - pub fn flags(&self) -> EntryFlags { - self.flags - } - - pub fn unmap(mut self) { - assert!(self.mapped); - - let mut active_table = unsafe { ActivePageTable::new() }; - - let mut flush_all = false; - - let start_page = Page::containing_address(self.start); - let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1)); - for page in Page::range_inclusive(start_page, end_page) { - active_table.unmap_return(page); - flush_all = true; - } - - if flush_all { - active_table.flush_all(); - } - - self.mapped = false; - } - - pub fn unmap_inactive(mut self, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) { - assert!(self.mapped); - - let mut active_table = unsafe { ActivePageTable::new() }; - - active_table.with(new_table, temporary_page, |mapper| { - let start_page = Page::containing_address(self.start); - let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1)); - for page in Page::range_inclusive(start_page, end_page) { - mapper.unmap_return(page); - } - }); - - self.mapped = false; - } -} - -impl Drop for Grant { - fn drop(&mut self) { - assert!(!self.mapped); - } -} - -#[derive(Clone, Debug)] -pub enum SharedMemory { - Owned(Arc>), - Borrowed(Weak>) -} - -impl SharedMemory { - pub fn with(&self, f: F) -> T where F: FnOnce(&mut Memory) -> T { - match *self { - SharedMemory::Owned(ref memory_lock) => { - let mut memory = memory_lock.lock(); - f(&mut *memory) - }, - SharedMemory::Borrowed(ref memory_weak) => { - let memory_lock = memory_weak.upgrade().expect("SharedMemory::Borrowed no longer valid"); - let mut memory = memory_lock.lock(); - f(&mut *memory) - } - } - } - - pub fn borrow(&self) -> SharedMemory { - match *self { - SharedMemory::Owned(ref memory_lock) => SharedMemory::Borrowed(Arc::downgrade(memory_lock)), - SharedMemory::Borrowed(ref memory_lock) => SharedMemory::Borrowed(memory_lock.clone()) - } - } -} - -#[derive(Debug)] -pub struct Memory { - start: VirtualAddress, - size: usize, - flags: EntryFlags -} - -impl Memory { - pub fn new(start: VirtualAddress, size: usize, flags: EntryFlags, flush: bool, clear: bool) -> Self { - let mut memory = Memory { - start: start, - size: size, - flags: flags - }; - - memory.map(flush, clear); - - memory - } - - pub fn to_shared(self) -> SharedMemory { - SharedMemory::Owned(Arc::new(Mutex::new(self))) - } - - pub fn start_address(&self) -> VirtualAddress { - self.start - } - - pub fn size(&self) -> usize { - self.size - } - - pub fn flags(&self) -> EntryFlags { - self.flags - } - - pub fn pages(&self) -> PageIter { - let start_page = Page::containing_address(self.start); - let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1)); - Page::range_inclusive(start_page, end_page) - } - - fn map(&mut self, flush: bool, clear: bool) { - let mut active_table = unsafe { ActivePageTable::new() }; - - let mut flush_all = false; - - //TODO: Clear pages? - for page in self.pages() { - active_table.map(page, self.flags); - - if flush { - //active_table.flush(page); - flush_all = true; - } - } - - if flush_all { - active_table.flush_all(); - } - - if clear { - assert!(flush && self.flags.contains(entry::WRITABLE)); - unsafe { - intrinsics::write_bytes(self.start_address().get() as *mut u8, 0, self.size); - } - } - } - - fn unmap(&mut self, flush: bool) { - let mut active_table = unsafe { ActivePageTable::new() }; - - let mut flush_all = false; - - for page in self.pages() { - active_table.unmap(page); - - if flush { - //active_table.flush(page); - flush_all = true; - } - } - - if flush_all { - active_table.flush_all(); - } - } - - /// A complicated operation to move a piece of memory to a new page table - /// It also allows for changing the address at the same time - pub fn move_to(&mut self, new_start: VirtualAddress, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage, flush: bool) { - let mut active_table = unsafe { ActivePageTable::new() }; - - let mut flush_all = false; - - for page in self.pages() { - let frame = active_table.unmap_return(page); - - active_table.with(new_table, temporary_page, |mapper| { - let new_page = Page::containing_address(VirtualAddress::new(page.start_address().get() - self.start.get() + new_start.get())); - mapper.map_to(new_page, frame, self.flags); - }); - - if flush { - //active_table.flush(page); - flush_all = true; - } - } - - if flush_all { - active_table.flush_all(); - } - - self.start = new_start; - } - - pub fn remap(&mut self, new_flags: EntryFlags, flush: bool) { - let mut active_table = unsafe { ActivePageTable::new() }; - - let mut flush_all = false; - - for page in self.pages() { - active_table.remap(page, new_flags); - - if flush { - //active_table.flush(page); - flush_all = true; - } - } - - if flush_all { - active_table.flush_all(); - } - - self.flags = new_flags; - } - - pub fn resize(&mut self, new_size: usize, flush: bool, clear: bool) { - let mut active_table = unsafe { ActivePageTable::new() }; - - //TODO: Calculate page changes to minimize operations - if new_size > self.size { - let mut flush_all = false; - - let start_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size)); - let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + new_size - 1)); - for page in Page::range_inclusive(start_page, end_page) { - if active_table.translate_page(page).is_none() { - active_table.map(page, self.flags); - - if flush { - //active_table.flush(page); - flush_all = true; - } - } - } - - if flush_all { - active_table.flush_all(); - } - - if clear { - assert!(flush); - unsafe { - intrinsics::write_bytes((self.start.get() + self.size) as *mut u8, 0, new_size - self.size); - } - } - } else if new_size < self.size { - let mut flush_all = false; - - let start_page = Page::containing_address(VirtualAddress::new(self.start.get() + new_size)); - let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1)); - for page in Page::range_inclusive(start_page, end_page) { - if active_table.translate_page(page).is_some() { - active_table.unmap(page); - - if flush { - //active_table.flush(page); - flush_all = true; - } - } - } - - if flush_all { - active_table.flush_all(); - } - } - - self.size = new_size; - } -} - -impl Drop for Memory { - fn drop(&mut self) { - self.unmap(true); - } -} - -#[derive(Debug)] -pub struct Tls { - pub master: VirtualAddress, - pub file_size: usize, - pub mem: Memory -} diff --git a/kernel/context/mod.rs b/kernel/context/mod.rs deleted file mode 100644 index 2b1214c..0000000 --- a/kernel/context/mod.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! Context management -use alloc::boxed::Box; -use core::sync::atomic::Ordering; -use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; - -pub use self::context::{Context, Status}; -pub use self::list::ContextList; -pub use self::switch::switch; -pub use context::context::ContextId; - -/// Context struct -mod context; - -/// Context list -mod list; - -/// Context switch function -mod switch; - -/// Event handling -pub mod event; - -/// File struct - defines a scheme and a file number -pub mod file; - -/// Memory struct - contains a set of pages for a context -pub mod memory; - -/// Limit on number of contexts -pub const CONTEXT_MAX_CONTEXTS: usize = usize::max_value() - 1; - -/// Maximum context files -pub const CONTEXT_MAX_FILES: usize = 65536; - -/// Contexts list -static CONTEXTS: Once> = Once::new(); - -#[thread_local] -static CONTEXT_ID: context::AtomicContextId = context::AtomicContextId::default(); - -pub fn init() { - let mut contexts = contexts_mut(); - let context_lock = contexts.new_context().expect("could not initialize first context"); - let mut context = context_lock.write(); - let mut fx = unsafe { Box::from_raw(::alloc::heap::allocate(512, 16) as *mut [u8; 512]) }; - for b in fx.iter_mut() { - *b = 0; - } - - context.arch.set_fx(fx.as_ptr() as usize); - context.kfx = Some(fx); - context.status = Status::Runnable; - context.running = true; - context.cpu_id = Some(::cpu_id()); - CONTEXT_ID.store(context.id, Ordering::SeqCst); -} - -/// Initialize contexts, called if needed -fn init_contexts() -> RwLock { - RwLock::new(ContextList::new()) -} - -/// Get the global schemes list, const -pub fn contexts() -> RwLockReadGuard<'static, ContextList> { - CONTEXTS.call_once(init_contexts).read() -} - -/// Get the global schemes list, mutable -pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> { - CONTEXTS.call_once(init_contexts).write() -} - -pub fn context_id() -> context::ContextId { - CONTEXT_ID.load(Ordering::SeqCst) -} diff --git a/kernel/context/switch.rs b/kernel/context/switch.rs deleted file mode 100644 index bbdc8ad..0000000 --- a/kernel/context/switch.rs +++ /dev/null @@ -1,115 +0,0 @@ -use core::sync::atomic::Ordering; - -use arch; -use context::{contexts, Context, Status, CONTEXT_ID}; -use syscall; - -/// Switch to the next context -/// -/// # Safety -/// -/// Do not call this while holding locks! -pub unsafe fn switch() -> bool { - use core::ops::DerefMut; - - // Set the global lock to avoid the unsafe operations below from causing issues - while arch::context::CONTEXT_SWITCH_LOCK.compare_and_swap(false, true, Ordering::SeqCst) { - arch::interrupt::pause(); - } - - let cpu_id = ::cpu_id(); - - let from_ptr; - let mut to_ptr = 0 as *mut Context; - let mut to_sig = None; - { - let contexts = contexts(); - { - let context_lock = contexts.current().expect("context::switch: not inside of context"); - let mut context = context_lock.write(); - from_ptr = context.deref_mut() as *mut Context; - } - - let check_context = |context: &mut Context| -> bool { - if context.cpu_id == None && cpu_id == 0 { - context.cpu_id = Some(cpu_id); - // println!("{}: take {} {}", cpu_id, context.id, ::core::str::from_utf8_unchecked(&context.name.lock())); - } - - if context.status == Status::Blocked && ! context.pending.is_empty() { - context.unblock(); - } - - if context.status == Status::Blocked && context.wake.is_some() { - let wake = context.wake.expect("context::switch: wake not set"); - - let current = arch::time::monotonic(); - if current.0 > wake.0 || (current.0 == wake.0 && current.1 >= wake.1) { - context.unblock(); - } - } - - if context.cpu_id == Some(cpu_id) { - if context.status == Status::Runnable && ! context.running { - return true; - } - } - - false - }; - - for (pid, context_lock) in contexts.iter() { - if *pid > (*from_ptr).id { - let mut context = context_lock.write(); - if check_context(&mut context) { - to_ptr = context.deref_mut() as *mut Context; - to_sig = context.pending.pop_front(); - break; - } - } - } - - if to_ptr as usize == 0 { - for (pid, context_lock) in contexts.iter() { - if *pid < (*from_ptr).id { - let mut context = context_lock.write(); - if check_context(&mut context) { - to_ptr = context.deref_mut() as *mut Context; - to_sig = context.pending.pop_front(); - break; - } - } - } - } - }; - - if to_ptr as usize == 0 { - // Unset global lock if no context found - arch::context::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst); - return false; - } - - (&mut *from_ptr).running = false; - (&mut *to_ptr).running = true; - if let Some(ref stack) = (*to_ptr).kstack { - arch::gdt::TSS.rsp[0] = (stack.as_ptr() as usize + stack.len() - 256) as u64; - } - CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst); - - // Unset global lock before switch, as arch is only usable by the current CPU at this time - arch::context::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst); - - if let Some(sig) = to_sig { - println!("Handle {}", sig); - (&mut *to_ptr).arch.signal_stack(signal_handler, sig); - } - - (&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch); - - true -} - -extern fn signal_handler(signal: usize) { - println!("Signal handler: {}", signal); - syscall::exit(signal); -} diff --git a/kernel/elf.rs b/kernel/elf.rs deleted file mode 100644 index bf484fe..0000000 --- a/kernel/elf.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! ELF executables - -use collections::String; - -use core::str; - -#[cfg(target_arch = "x86")] -pub use goblin::elf32::{header, program_header}; - -#[cfg(target_arch = "x86_64")] -pub use goblin::elf64::{header, program_header}; - -/// An ELF executable -pub struct Elf<'a> { - pub data: &'a [u8], - header: &'a header::Header -} - -impl<'a> Elf<'a> { - /// Create a ELF executable from data - pub fn from(data: &'a [u8]) -> Result, String> { - if data.len() < header::SIZEOF_EHDR { - Err(format!("Elf: Not enough data: {} < {}", data.len(), header::SIZEOF_EHDR)) - } else if &data[..header::SELFMAG] != header::ELFMAG { - Err(format!("Elf: Invalid magic: {:?} != {:?}", &data[..4], header::ELFMAG)) - } else if data.get(header::EI_CLASS) != Some(&header::ELFCLASS) { - Err(format!("Elf: Invalid architecture: {:?} != {:?}", data.get(header::EI_CLASS), header::ELFCLASS)) - } else { - Ok(Elf { - data: data, - header: unsafe { &*(data.as_ptr() as usize as *const header::Header) } - }) - } - } - - pub fn segments(&'a self) -> ElfSegments<'a> { - ElfSegments { - data: self.data, - header: self.header, - i: 0 - } - } - - /// Get the entry field of the header - pub fn entry(&self) -> usize { - self.header.e_entry as usize - } -} - -pub struct ElfSegments<'a> { - data: &'a [u8], - header: &'a header::Header, - i: usize -} - -impl<'a> Iterator for ElfSegments<'a> { - type Item = &'a program_header::ProgramHeader; - fn next(&mut self) -> Option { - if self.i < self.header.e_phnum as usize { - let item = unsafe { - &* (( - self.data.as_ptr() as usize - + self.header.e_phoff as usize - + self.i * self.header.e_phentsize as usize - ) as *const program_header::ProgramHeader) - }; - self.i += 1; - Some(item) - } else { - None - } - } -} diff --git a/kernel/lib.rs b/kernel/lib.rs deleted file mode 100644 index 5502278..0000000 --- a/kernel/lib.rs +++ /dev/null @@ -1,180 +0,0 @@ -//! # The Redox OS Kernel, version 2 -//! -//! The Redox OS Kernel is a hybrid kernel that supports X86_64 systems and -//! provides Unix-like syscalls for primarily Rust applications - -#![deny(warnings)] -#![feature(alloc)] -#![feature(asm)] -#![feature(collections)] -#![feature(const_fn)] -#![feature(core_intrinsics)] -#![feature(drop_types_in_const)] -#![feature(heap_api)] -#![feature(integer_atomics)] -#![feature(never_type)] -#![feature(thread_local)] -#![no_std] - -use arch::interrupt; - -/// Architecture specific items (test) -#[cfg(test)] -#[macro_use] -extern crate arch_test as arch; - -/// Architecture specific items (ARM) -#[cfg(all(not(test), target_arch = "arm"))] -#[macro_use] -extern crate arch_arm as arch; - -/// Architecture specific items (x86_64) -#[cfg(all(not(test), target_arch = "x86_64"))] -#[macro_use] -extern crate arch_x86_64 as arch; - -extern crate alloc; -#[macro_use] -extern crate collections; - -#[macro_use] -extern crate bitflags; -extern crate goblin; -extern crate spin; - -use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; -use scheme::FileHandle; - -#[macro_use] -/// Shared data structures -pub mod common; - -/// Context management -pub mod context; - -/// ELF file parsing -pub mod elf; - -/// Schemes, filesystem handlers -pub mod scheme; - -/// Synchronization primitives -pub mod sync; - -/// Syscall handlers -pub mod syscall; - -/// Tests -#[cfg(test)] -pub mod tests; - -/// A unique number that identifies the current CPU - used for scheduling -#[thread_local] -static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT; - -/// Get the current CPU's scheduling ID -#[inline(always)] -pub fn cpu_id() -> usize { - CPU_ID.load(Ordering::Relaxed) -} - -/// The count of all CPUs that can have work scheduled -static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT; - -/// Get the number of CPUs currently active -#[inline(always)] -pub fn cpu_count() -> usize { - CPU_COUNT.load(Ordering::Relaxed) -} - -/// Initialize userspace by running the initfs:bin/init process -/// This function will also set the CWD to initfs:bin and open debug: as stdio -pub extern fn userspace_init() { - assert_eq!(syscall::chdir(b"initfs:"), Ok(0)); - - assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0)); - assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1)); - assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2)); - - syscall::exec(b"/bin/init", &[]).expect("failed to execute init"); - - panic!("init returned"); -} - -/// Allow exception handlers to send signal to arch-independant kernel -#[no_mangle] -pub extern fn ksignal(signal: usize) { - println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id()); - { - let contexts = context::contexts(); - if let Some(context_lock) = contexts.current() { - let context = context_lock.read(); - println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }); - } - } - syscall::exit(signal & 0x7F); -} - -/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this -#[no_mangle] -pub extern fn kmain(cpus: usize) { - CPU_ID.store(0, Ordering::SeqCst); - CPU_COUNT.store(cpus, Ordering::SeqCst); - - context::init(); - - let pid = syscall::getpid(); - println!("BSP: {:?} {}", pid, cpus); - - match context::contexts_mut().spawn(userspace_init) { - Ok(context_lock) => { - let mut context = context_lock.write(); - context.status = context::Status::Runnable; - }, - Err(err) => { - panic!("failed to spawn userspace_init: {:?}", err); - } - } - - loop { - unsafe { - interrupt::disable(); - if context::switch() { - interrupt::enable_and_nop(); - } else { - // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired. - interrupt::enable_and_halt(); - } - } - } -} - -/// This is the main kernel entry point for secondary CPUs -#[no_mangle] -pub extern fn kmain_ap(_id: usize) { - // Disable APs for now - loop { - unsafe { interrupt::enable_and_halt(); } - } - - /* - CPU_ID.store(id, Ordering::SeqCst); - - context::init(); - - let pid = syscall::getpid(); - println!("AP {}: {:?}", id, pid); - - loop { - unsafe { - interrupt::disable(); - if context::switch() { - interrupt::enable_and_nop(); - } else { - // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired. - interrupt::enable_and_halt(); - } - } - } -*/ -} diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs deleted file mode 100644 index 4d929a8..0000000 --- a/kernel/scheme/debug.rs +++ /dev/null @@ -1,75 +0,0 @@ -use core::str; -use core::sync::atomic::Ordering; -use spin::Once; - -use context; -use scheme::*; -use sync::WaitQueue; -use syscall::flag::EVENT_READ; -use syscall::scheme::Scheme; - -pub static DEBUG_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT; - -/// Input queue -static INPUT: Once> = Once::new(); - -/// Initialize input queue, called if needed -fn init_input() -> WaitQueue { - WaitQueue::new() -} - -/// Add to the input queue -#[no_mangle] -pub extern fn debug_input(b: u8) { - let len = INPUT.call_once(init_input).send(b); - - context::event::trigger(DEBUG_SCHEME_ID.load(Ordering::SeqCst), 0, EVENT_READ, len); -} - -pub struct DebugScheme; - -impl DebugScheme { - pub fn new(scheme_id: SchemeId) -> DebugScheme { - DEBUG_SCHEME_ID.store(scheme_id, Ordering::SeqCst); - DebugScheme - } -} - -impl Scheme for DebugScheme { - fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - Ok(0) - } - - fn dup(&self, _file: usize, _buf: &[u8]) -> Result { - Ok(0) - } - - /// Read the file `number` into the `buffer` - /// - /// Returns the number of bytes read - fn read(&self, _file: usize, buf: &mut [u8]) -> Result { - Ok(INPUT.call_once(init_input).receive_into(buf, true)) - } - - /// Write the `buffer` to the `file` - /// - /// Returns the number of bytes written - fn write(&self, _file: usize, buffer: &[u8]) -> Result { - //TODO: Write bytes, do not convert to str - print!("{}", unsafe { str::from_utf8_unchecked(buffer) }); - Ok(buffer.len()) - } - - fn fevent(&self, _file: usize, _flags: usize) -> Result { - Ok(0) - } - - fn fsync(&self, _file: usize) -> Result { - Ok(0) - } - - /// Close the file `number` - fn close(&self, _file: usize) -> Result { - Ok(0) - } -} diff --git a/kernel/scheme/env.rs b/kernel/scheme/env.rs deleted file mode 100644 index 3c88b1e..0000000 --- a/kernel/scheme/env.rs +++ /dev/null @@ -1,193 +0,0 @@ -use alloc::arc::Arc; -use collections::{BTreeMap, Vec}; -use core::{cmp, str}; -use core::sync::atomic::{AtomicUsize, Ordering}; -use spin::{Mutex, RwLock}; - -use context; -use syscall::data::Stat; -use syscall::error::*; -use syscall::flag::{MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END}; -use syscall::scheme::Scheme; - -#[derive(Clone)] -struct Handle { - data: Arc>>, - mode: u16, - seek: usize -} - -pub struct EnvScheme { - next_id: AtomicUsize, - handles: RwLock> -} - -impl EnvScheme { - pub fn new() -> EnvScheme { - EnvScheme { - next_id: AtomicUsize::new(0), - handles: RwLock::new(BTreeMap::new()) - } - } -} - -impl Scheme for EnvScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - let path = str::from_utf8(path).map_err(|_err| Error::new(ENOENT))?.trim_matches('/'); - - let env_lock = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.env.clone() - }; - - if path.is_empty() { - let mut list = Vec::new(); - { - let env = env_lock.lock(); - for entry in env.iter() { - if ! list.is_empty() { - list.push(b'\n'); - } - list.extend_from_slice(&entry.0); - list.push(b'='); - list.extend_from_slice(&entry.1.lock()); - } - } - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - data: Arc::new(Mutex::new(list)), - mode: MODE_FILE, - seek: 0 - }); - - Ok(id) - } else { - let data = { - let mut env = env_lock.lock(); - if env.contains_key(path.as_bytes()) { - env[path.as_bytes()].clone() - } else /*if flags & O_CREAT == O_CREAT*/ { - let name = path.as_bytes().to_vec().into_boxed_slice(); - let data = Arc::new(Mutex::new(Vec::new())); - env.insert(name, data.clone()); - data - } - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - data: data, - mode: MODE_FILE, - seek: 0 - }); - - Ok(id) - } - } - - fn dup(&self, id: usize, _buf: &[u8]) -> Result { - let new_handle = { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - handle.clone() - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, new_handle); - - Ok(id) - } - - fn read(&self, id: usize, buffer: &mut [u8]) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let data = handle.data.lock(); - - let mut i = 0; - while i < buffer.len() && handle.seek < data.len() { - buffer[i] = data[handle.seek]; - i += 1; - handle.seek += 1; - } - - Ok(i) - } - - fn write(&self, id: usize, buffer: &[u8]) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let mut data = handle.data.lock(); - - let mut i = 0; - while i < buffer.len() && handle.seek < data.len() { - data[handle.seek] = buffer[i]; - i += 1; - handle.seek += 1; - } - - while i < buffer.len() { - data.push(buffer[i]); - i += 1; - handle.seek += 1; - } - - Ok(i) - } - - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let len = handle.data.lock().len(); - handle.seek = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.seek as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(handle.seek) - } - - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - stat.st_mode = handle.mode; - stat.st_size = handle.data.lock().len() as u64; - - Ok(0) - } - - fn fsync(&self, id: usize) -> Result { - let handles = self.handles.read(); - let _handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - Ok(0) - } - - fn ftruncate(&self, id: usize, len: usize) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut data = handle.data.lock(); - if len < data.len() { - data.truncate(len) - } else { - while len > data.len() { - data.push(0); - } - } - - Ok(0) - } - - fn close(&self, id: usize) -> Result { - self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) - } -} diff --git a/kernel/scheme/event.rs b/kernel/scheme/event.rs deleted file mode 100644 index 2266141..0000000 --- a/kernel/scheme/event.rs +++ /dev/null @@ -1,74 +0,0 @@ -use alloc::arc::{Arc, Weak}; -use collections::BTreeMap; -use core::{mem, slice}; -use core::sync::atomic::{AtomicUsize, Ordering}; -use spin::RwLock; - -use context; -use sync::WaitQueue; -use syscall::data::Event; -use syscall::error::*; -use syscall::scheme::Scheme; - -pub struct EventScheme { - next_id: AtomicUsize, - handles: RwLock>>> -} - -impl EventScheme { - pub fn new() -> EventScheme { - EventScheme { - next_id: AtomicUsize::new(0), - handles: RwLock::new(BTreeMap::new()) - } - } -} - -impl Scheme for EventScheme { - fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - let handle = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.events.clone() - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Arc::downgrade(&handle)); - - Ok(id) - } - - fn dup(&self, id: usize, _buf: &[u8]) -> Result { - let handle = { - let handles = self.handles.read(); - let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; - handle_weak.upgrade().ok_or(Error::new(EBADF))? - }; - - let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(new_id, Arc::downgrade(&handle)); - Ok(new_id) - } - - fn read(&self, id: usize, buf: &mut [u8]) -> Result { - let handle = { - let handles = self.handles.read(); - let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; - handle_weak.upgrade().ok_or(Error::new(EBADF))? - }; - - let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::()) }; - Ok(handle.receive_into(event_buf, true) * mem::size_of::()) - } - - fn fsync(&self, id: usize) -> Result { - let handles = self.handles.read(); - let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; - handle_weak.upgrade().ok_or(Error::new(EBADF)).and(Ok(0)) - } - - fn close(&self, id: usize) -> Result { - self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) - } -} diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs deleted file mode 100644 index 6355928..0000000 --- a/kernel/scheme/initfs.rs +++ /dev/null @@ -1,154 +0,0 @@ -use collections::BTreeMap; -use core::{cmp, str}; -use core::sync::atomic::{AtomicUsize, Ordering}; -use spin::RwLock; - -use syscall::data::Stat; -use syscall::error::*; -use syscall::flag::{MODE_DIR, MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END}; -use syscall::scheme::Scheme; - -#[cfg(test)] -mod gen { - use collections::BTreeMap; - pub fn gen() -> BTreeMap<&'static [u8], (&'static [u8], bool)> { BTreeMap::new() } -} - -#[cfg(not(test))] -#[path="../../build/userspace/initfs.rs"] -mod gen; - -struct Handle { - path: &'static [u8], - data: &'static [u8], - mode: u16, - seek: usize -} - -pub struct InitFsScheme { - next_id: AtomicUsize, - files: BTreeMap<&'static [u8], (&'static [u8], bool)>, - handles: RwLock> -} - -impl InitFsScheme { - pub fn new() -> InitFsScheme { - InitFsScheme { - next_id: AtomicUsize::new(0), - files: gen::gen(), - handles: RwLock::new(BTreeMap::new()) - } - } -} - -impl Scheme for InitFsScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - let path_utf8 = str::from_utf8(path).map_err(|_err| Error::new(ENOENT))?; - let path_trimmed = path_utf8.trim_matches('/'); - - //Have to iterate to get the path without allocation - for entry in self.files.iter() { - if entry.0 == &path_trimmed.as_bytes() { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - path: entry.0, - data: (entry.1).0, - mode: if (entry.1).1 { MODE_DIR | 0o755 } else { MODE_FILE | 0o744 }, - seek: 0 - }); - - return Ok(id); - } - } - - Err(Error::new(ENOENT)) - } - - fn dup(&self, id: usize, _buf: &[u8]) -> Result { - let (path, data, mode, seek) = { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - (handle.path, handle.data, handle.mode, handle.seek) - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - path: path, - data: data, - mode: mode, - seek: seek - }); - - Ok(id) - } - - fn read(&self, id: usize, buffer: &mut [u8]) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - while i < buffer.len() && handle.seek < handle.data.len() { - buffer[i] = handle.data[handle.seek]; - i += 1; - handle.seek += 1; - } - - Ok(i) - } - - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - handle.seek = match whence { - SEEK_SET => cmp::min(handle.data.len(), pos), - SEEK_CUR => cmp::max(0, cmp::min(handle.data.len() as isize, handle.seek as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(handle.data.len() as isize, handle.data.len() as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(handle.seek) - } - - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - //TODO: Copy scheme part in kernel - let mut i = 0; - let scheme_path = b"initfs:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - - let mut j = 0; - while i < buf.len() && j < handle.path.len() { - buf[i] = handle.path[j]; - i += 1; - j += 1; - } - - Ok(i) - } - - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - stat.st_mode = handle.mode; - stat.st_uid = 0; - stat.st_gid = 0; - stat.st_size = handle.data.len() as u64; - - Ok(0) - } - - fn fsync(&self, _id: usize) -> Result { - Ok(0) - } - - fn close(&self, id: usize) -> Result { - self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) - } -} diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs deleted file mode 100644 index 4817df0..0000000 --- a/kernel/scheme/irq.rs +++ /dev/null @@ -1,101 +0,0 @@ -use core::{mem, str}; -use core::sync::atomic::Ordering; -use spin::Mutex; - -use arch::interrupt::irq::acknowledge; -use context; -use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId}; -use syscall::error::*; -use syscall::flag::EVENT_READ; -use syscall::scheme::Scheme; - -pub static IRQ_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT; - -/// IRQ queues -static ACKS: Mutex<[usize; 16]> = Mutex::new([0; 16]); -static COUNTS: Mutex<[usize; 16]> = Mutex::new([0; 16]); - -/// Add to the input queue -#[no_mangle] -pub extern fn irq_trigger(irq: u8) { - COUNTS.lock()[irq as usize] += 1; - context::event::trigger(IRQ_SCHEME_ID.load(Ordering::SeqCst), irq as usize, EVENT_READ, mem::size_of::()); -} - -pub struct IrqScheme; - -impl IrqScheme { - pub fn new(scheme_id: SchemeId) -> IrqScheme { - IRQ_SCHEME_ID.store(scheme_id, Ordering::SeqCst); - IrqScheme - } -} - -impl Scheme for IrqScheme { - fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { - if uid == 0 { - let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; - - let id = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if id < COUNTS.lock().len() { - Ok(id) - } else { - Err(Error::new(ENOENT)) - } - } else { - Err(Error::new(EACCES)) - } - } - - fn dup(&self, file: usize, _buf: &[u8]) -> Result { - Ok(file) - } - - fn read(&self, file: usize, buffer: &mut [u8]) -> Result { - // Ensures that the length of the buffer is larger than the size of a usize - if buffer.len() >= mem::size_of::() { - let ack = ACKS.lock()[file]; - let current = COUNTS.lock()[file]; - if ack != current { - // Safe if the length of the buffer is larger than the size of a usize - assert!(buffer.len() >= mem::size_of::()); - unsafe { *(buffer.as_mut_ptr() as *mut usize) = current; } - Ok(mem::size_of::()) - } else { - Ok(0) - } - } else { - Err(Error::new(EINVAL)) - } - } - - fn write(&self, file: usize, buffer: &[u8]) -> Result { - if buffer.len() >= mem::size_of::() { - assert!(buffer.len() >= mem::size_of::()); - let ack = unsafe { *(buffer.as_ptr() as *const usize) }; - let current = COUNTS.lock()[file]; - if ack == current { - ACKS.lock()[file] = ack; - unsafe { acknowledge(file); } - Ok(mem::size_of::()) - } else { - Ok(0) - } - } else { - Err(Error::new(EINVAL)) - } - } - - fn fevent(&self, file: usize, _flags: usize) -> Result { - Ok(file) - } - - fn fsync(&self, _file: usize) -> Result { - Ok(0) - } - - fn close(&self, _file: usize) -> Result { - Ok(0) - } -} diff --git a/kernel/scheme/live.rs b/kernel/scheme/live.rs deleted file mode 100644 index e9ac3b8..0000000 --- a/kernel/scheme/live.rs +++ /dev/null @@ -1,160 +0,0 @@ -/// Disk scheme replacement when making live disk - -use alloc::arc::Arc; -use collections::{BTreeMap, Vec}; -use core::cmp; -use core::sync::atomic::{AtomicUsize, Ordering}; -use spin::RwLock; - -use syscall::data::Stat; -use syscall::error::*; -use syscall::flag::{MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END}; -use syscall::scheme::Scheme; - -static FILESYSTEM: &'static [u8] = include_bytes!("../../build/filesystem.bin"); - -struct Handle { - path: &'static [u8], - data: Arc>>, - mode: u16, - seek: usize -} - -pub struct DiskScheme { - next_id: AtomicUsize, - data: Arc>>, - handles: RwLock> -} - -impl DiskScheme { - pub fn new() -> DiskScheme { - DiskScheme { - next_id: AtomicUsize::new(0), - data: Arc::new(RwLock::new(FILESYSTEM.to_vec())), - handles: RwLock::new(BTreeMap::new()) - } - } -} - -impl Scheme for DiskScheme { - fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - path: b"0", - data: self.data.clone(), - mode: MODE_FILE | 0o744, - seek: 0 - }); - - Ok(id) - } - - fn dup(&self, id: usize, _buf: &[u8]) -> Result { - let (path, data, mode, seek) = { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - (handle.path, handle.data.clone(), handle.mode, handle.seek) - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - path: path, - data: data, - mode: mode, - seek: seek - }); - - Ok(id) - } - - fn read(&self, id: usize, buffer: &mut [u8]) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let data = handle.data.read(); - - let mut i = 0; - while i < buffer.len() && handle.seek < data.len() { - buffer[i] = data[handle.seek]; - i += 1; - handle.seek += 1; - } - - Ok(i) - } - - fn write(&self, id: usize, buffer: &[u8]) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let mut data = handle.data.write(); - - let mut i = 0; - while i < buffer.len() && handle.seek < data.len() { - data[handle.seek] = buffer[i]; - i += 1; - handle.seek += 1; - } - - Ok(i) - } - - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let data = handle.data.read(); - - handle.seek = match whence { - SEEK_SET => cmp::min(data.len(), pos), - SEEK_CUR => cmp::max(0, cmp::min(data.len() as isize, handle.seek as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(data.len() as isize, data.len() as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(handle.seek) - } - - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - //TODO: Copy scheme part in kernel - let mut i = 0; - let scheme_path = b"disk:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - - let mut j = 0; - while i < buf.len() && j < handle.path.len() { - buf[i] = handle.path[j]; - i += 1; - j += 1; - } - - Ok(i) - } - - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - let data = handle.data.read(); - - stat.st_mode = handle.mode; - stat.st_uid = 0; - stat.st_gid = 0; - stat.st_size = data.len() as u64; - - Ok(0) - } - - fn fsync(&self, id: usize) -> Result { - let handles = self.handles.read(); - let _handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - Ok(0) - } - - fn close(&self, id: usize) -> Result { - self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) - } -} diff --git a/kernel/scheme/memory.rs b/kernel/scheme/memory.rs deleted file mode 100644 index 9db0c48..0000000 --- a/kernel/scheme/memory.rs +++ /dev/null @@ -1,30 +0,0 @@ -use arch::memory::{free_frames, used_frames}; - -use syscall::data::StatVfs; -use syscall::error::*; -use syscall::scheme::Scheme; - -pub struct MemoryScheme; - -impl Scheme for MemoryScheme { - fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - Ok(0) - } - - fn fstatvfs(&self, _file: usize, stat: &mut StatVfs) -> Result { - let used = used_frames() as u64; - let free = free_frames() as u64; - - stat.f_bsize = 4096; - stat.f_blocks = used + free; - stat.f_bfree = free; - stat.f_bavail = stat.f_bfree; - - Ok(0) - } - - /// Close the file `number` - fn close(&self, _file: usize) -> Result { - Ok(0) - } -} diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs deleted file mode 100644 index 3f0c5a7..0000000 --- a/kernel/scheme/mod.rs +++ /dev/null @@ -1,246 +0,0 @@ -//! # Schemes -//! A scheme is a primitive for handling filesystem syscalls in Redox. -//! Schemes accept paths from the kernel for `open`, and file descriptors that they generate -//! are then passed for operations like `close`, `read`, `write`, etc. -//! -//! The kernel validates paths and file descriptors before they are passed to schemes, -//! also stripping the scheme identifier of paths if necessary. - -use alloc::arc::Arc; -use alloc::boxed::Box; -use collections::BTreeMap; -use core::sync::atomic::AtomicUsize; -use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; - -use syscall::error::*; -use syscall::scheme::Scheme; - -use self::debug::DebugScheme; -use self::event::EventScheme; -use self::env::EnvScheme; -use self::initfs::InitFsScheme; -use self::irq::IrqScheme; -use self::memory::MemoryScheme; -use self::null::NullScheme; -use self::pipe::PipeScheme; -use self::root::RootScheme; -use self::sys::SysScheme; -use self::zero::ZeroScheme; - -/// `debug:` - provides access to serial console -pub mod debug; - -/// `event:` - allows reading of `Event`s which are registered using `fevent` -pub mod event; - -/// `env:` - access and modify environmental variables -pub mod env; - -/// `initfs:` - a readonly filesystem used for initializing the system -pub mod initfs; - -/// `irq:` - allows userspace handling of IRQs -pub mod irq; - -/// When compiled with "live" feature - `disk:` - embedded filesystem for live disk -#[cfg(feature="live")] -pub mod live; - -/// `memory:` - a scheme for accessing physical memory -pub mod memory; - -/// `null:` - a scheme that will discard all writes, and read no bytes -pub mod null; - -/// `pipe:` - used internally by the kernel to implement `pipe` -pub mod pipe; - -/// `:` - allows the creation of userspace schemes, tightly dependent on `user` -pub mod root; - -/// `sys:` - system information, such as the context list and scheme list -pub mod sys; - -/// A wrapper around userspace schemes, tightly dependent on `root` -pub mod user; - -/// `zero:` - a scheme that will discard all writes, and always fill read buffers with zero -pub mod zero; - -/// Limit on number of schemes -pub const SCHEME_MAX_SCHEMES: usize = 65536; - -/// Unique identifier for a scheme namespace. -int_like!(SchemeNamespace, AtomicSchemeNamespace, usize, AtomicUsize); - -/// Unique identifier for a scheme. -int_like!(SchemeId, AtomicSchemeId, usize, AtomicUsize); - -pub const ATOMIC_SCHEMEID_INIT: AtomicSchemeId = AtomicSchemeId::default(); - -/// Unique identifier for a file descriptor. -int_like!(FileHandle, AtomicFileHandle, usize, AtomicUsize); - -/// Scheme list type -pub struct SchemeList { - map: BTreeMap>>, - names: BTreeMap, SchemeId>>, - next_ns: usize, - next_id: usize -} - -impl SchemeList { - /// Create a new scheme list. - pub fn new() -> Self { - let mut list = SchemeList { - map: BTreeMap::new(), - names: BTreeMap::new(), - next_ns: 0, - next_id: 1 - }; - list.new_root(); - list - } - - /// Initialize a new namespace - fn new_ns(&mut self) -> SchemeNamespace { - let ns = SchemeNamespace(self.next_ns); - self.next_ns += 1; - self.names.insert(ns, BTreeMap::new()); - - self.insert(ns, Box::new(*b""), |scheme_id| Arc::new(Box::new(RootScheme::new(ns, scheme_id)))).unwrap(); - self.insert(ns, Box::new(*b"event"), |_| Arc::new(Box::new(EventScheme::new()))).unwrap(); - self.insert(ns, Box::new(*b"env"), |_| Arc::new(Box::new(EnvScheme::new()))).unwrap(); - self.insert(ns, Box::new(*b"null"), |_| Arc::new(Box::new(NullScheme))).unwrap(); - self.insert(ns, Box::new(*b"sys"), |_| Arc::new(Box::new(SysScheme::new()))).unwrap(); - self.insert(ns, Box::new(*b"zero"), |_| Arc::new(Box::new(ZeroScheme))).unwrap(); - - ns - } - - /// Initialize the root namespace - #[cfg(not(feature="live"))] - fn new_root(&mut self) { - // Do common namespace initialization - let ns = self.new_ns(); - - // Debug, Initfs and IRQ are only available in the root namespace. Pipe is special - self.insert(ns, Box::new(*b"debug"), |scheme_id| Arc::new(Box::new(DebugScheme::new(scheme_id)))).unwrap(); - self.insert(ns, Box::new(*b"initfs"), |_| Arc::new(Box::new(InitFsScheme::new()))).unwrap(); - self.insert(ns, Box::new(*b"irq"), |scheme_id| Arc::new(Box::new(IrqScheme::new(scheme_id)))).unwrap(); - self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme))).unwrap(); - self.insert(ns, Box::new(*b"pipe"), |scheme_id| Arc::new(Box::new(PipeScheme::new(scheme_id)))).unwrap(); - } - - /// Initialize the root namespace - with live disk - #[cfg(feature="live")] - fn new_root(&mut self) { - // Do common namespace initialization - let ns = self.new_ns(); - - // Debug, Disk, Initfs and IRQ are only available in the root namespace. Pipe is special - self.insert(ns, Box::new(*b"debug"), |scheme_id| Arc::new(Box::new(DebugScheme::new(scheme_id)))).unwrap(); - self.insert(ns, Box::new(*b"disk"), |_| Arc::new(Box::new(self::live::DiskScheme::new()))).unwrap(); - self.insert(ns, Box::new(*b"initfs"), |_| Arc::new(Box::new(InitFsScheme::new()))).unwrap(); - self.insert(ns, Box::new(*b"irq"), |scheme_id| Arc::new(Box::new(IrqScheme::new(scheme_id)))).unwrap(); - self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme))).unwrap(); - self.insert(ns, Box::new(*b"pipe"), |scheme_id| Arc::new(Box::new(PipeScheme::new(scheme_id)))).unwrap(); - } - - pub fn make_ns(&mut self, from: SchemeNamespace, names: &[&[u8]]) -> Result { - // Create an empty namespace - let to = self.new_ns(); - - // Copy requested scheme IDs - for name in names.iter() { - let id = if let Some((id, _scheme)) = self.get_name(from, name) { - id - } else { - return Err(Error::new(ENODEV)); - }; - - if let Some(ref mut names) = self.names.get_mut(&to) { - assert!(names.insert(name.to_vec().into_boxed_slice(), id).is_none()); - } else { - panic!("scheme namespace not found"); - } - } - - Ok(to) - } - - pub fn iter(&self) -> ::collections::btree_map::Iter>> { - self.map.iter() - } - - pub fn iter_name(&self, ns: SchemeNamespace) -> ::collections::btree_map::Iter, SchemeId> { - self.names[&ns].iter() - } - - /// Get the nth scheme. - pub fn get(&self, id: SchemeId) -> Option<&Arc>> { - self.map.get(&id) - } - - pub fn get_name(&self, ns: SchemeNamespace, name: &[u8]) -> Option<(SchemeId, &Arc>)> { - if let Some(&id) = self.names[&ns].get(name) { - self.get(id).map(|scheme| (id, scheme)) - } else { - None - } - } - - /// Create a new scheme. - pub fn insert(&mut self, ns: SchemeNamespace, name: Box<[u8]>, scheme_fn: F) -> Result - where F: Fn(SchemeId) -> Arc> - { - if self.names[&ns].contains_key(&name) { - return Err(Error::new(EEXIST)); - } - - if self.next_id >= SCHEME_MAX_SCHEMES { - self.next_id = 1; - } - - while self.map.contains_key(&SchemeId(self.next_id)) { - self.next_id += 1; - } - - /* Allow scheme list to grow if required - if self.next_id >= SCHEME_MAX_SCHEMES { - return Err(Error::new(EAGAIN)); - } - */ - - let id = SchemeId(self.next_id); - self.next_id += 1; - - let scheme = scheme_fn(id); - - assert!(self.map.insert(id, scheme).is_none()); - if let Some(ref mut names) = self.names.get_mut(&ns) { - assert!(names.insert(name, id).is_none()); - } else { - panic!("scheme namespace not found"); - } - Ok(id) - } -} - -/// Schemes list -static SCHEMES: Once> = Once::new(); - -/// Initialize schemes, called if needed -fn init_schemes() -> RwLock { - RwLock::new(SchemeList::new()) -} - -/// Get the global schemes list, const -pub fn schemes() -> RwLockReadGuard<'static, SchemeList> { - SCHEMES.call_once(init_schemes).read() -} - -/// Get the global schemes list, mutable -pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> { - SCHEMES.call_once(init_schemes).write() -} diff --git a/kernel/scheme/null.rs b/kernel/scheme/null.rs deleted file mode 100644 index 690c16c..0000000 --- a/kernel/scheme/null.rs +++ /dev/null @@ -1,37 +0,0 @@ -use syscall::error::*; -use syscall::scheme::Scheme; - -pub struct NullScheme; - -impl Scheme for NullScheme { - fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - Ok(0) - } - - fn dup(&self, _file: usize, _buf: &[u8]) -> Result { - Ok(0) - } - - /// Read the file `number` into the `buffer` - /// - /// Returns the number of bytes read - fn read(&self, _file: usize, _buf: &mut [u8]) -> Result { - Ok(0) - } - - /// Write the `buffer` to the `file` - /// - /// Returns the number of bytes written - fn write(&self, _file: usize, buffer: &[u8]) -> Result { - Ok(buffer.len()) - } - - fn fsync(&self, _file: usize) -> Result { - Ok(0) - } - - /// Close the file `number` - fn close(&self, _file: usize) -> Result { - Ok(0) - } -} diff --git a/kernel/scheme/pipe.rs b/kernel/scheme/pipe.rs deleted file mode 100644 index 5e64350..0000000 --- a/kernel/scheme/pipe.rs +++ /dev/null @@ -1,272 +0,0 @@ -use alloc::arc::{Arc, Weak}; -use collections::{BTreeMap, VecDeque}; -use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; -use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId}; - -use sync::WaitCondition; -use syscall::error::{Error, Result, EAGAIN, EBADF, EINVAL, EPIPE}; -use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE, O_CLOEXEC, O_NONBLOCK}; -use syscall::scheme::Scheme; - -/// Pipes list -pub static PIPE_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT; -static PIPE_NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT; -static PIPES: Once>, BTreeMap>)>> = Once::new(); - -/// Initialize pipes, called if needed -fn init_pipes() -> RwLock<(BTreeMap>, BTreeMap>)> { - RwLock::new((BTreeMap::new(), BTreeMap::new())) -} - -/// Get the global pipes list, const -fn pipes() -> RwLockReadGuard<'static, (BTreeMap>, BTreeMap>)> { - PIPES.call_once(init_pipes).read() -} - -/// Get the global schemes list, mutable -fn pipes_mut() -> RwLockWriteGuard<'static, (BTreeMap>, BTreeMap>)> { - PIPES.call_once(init_pipes).write() -} - -pub fn pipe(flags: usize) -> (usize, usize) { - let mut pipes = pipes_mut(); - let read_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst); - let write_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst); - let read = PipeRead::new(flags); - let write = PipeWrite::new(flags, &read); - pipes.0.insert(read_id, Arc::new(read)); - pipes.1.insert(write_id, Arc::new(write)); - (read_id, write_id) -} - -pub struct PipeScheme; - -impl PipeScheme { - pub fn new(scheme_id: SchemeId) -> PipeScheme { - PIPE_SCHEME_ID.store(scheme_id, Ordering::SeqCst); - PipeScheme - } -} - -impl Scheme for PipeScheme { - fn dup(&self, id: usize, buf: &[u8]) -> Result { - let mut pipes = pipes_mut(); - - let read_option = if let Some(pipe) = pipes.0.get(&id) { - Some(pipe.dup(buf)?) - } else { - None - }; - if let Some(pipe) = read_option { - let pipe_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst); - pipes.0.insert(pipe_id, Arc::new(pipe)); - return Ok(pipe_id); - } - - let write_option = if let Some(pipe) = pipes.1.get(&id) { - Some(pipe.dup(buf)?) - } else { - None - }; - if let Some(pipe) = write_option { - let pipe_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst); - pipes.1.insert(pipe_id, Arc::new(pipe)); - return Ok(pipe_id); - } - - Err(Error::new(EBADF)) - } - - fn read(&self, id: usize, buf: &mut [u8]) -> Result { - // Clone to prevent deadlocks - let pipe = { - let pipes = pipes(); - pipes.0.get(&id).map(|pipe| pipe.clone()).ok_or(Error::new(EBADF))? - }; - - pipe.read(buf) - } - - fn write(&self, id: usize, buf: &[u8]) -> Result { - // Clone to prevent deadlocks - let pipe = { - let pipes = pipes(); - pipes.1.get(&id).map(|pipe| pipe.clone()).ok_or(Error::new(EBADF))? - }; - - pipe.write(buf) - } - - fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result { - let pipes = pipes(); - - if let Some(pipe) = pipes.0.get(&id) { - return pipe.fcntl(cmd, arg); - } - - if let Some(pipe) = pipes.1.get(&id) { - return pipe.fcntl(cmd, arg); - } - - Err(Error::new(EBADF)) - } - - fn fsync(&self, _id: usize) -> Result { - Ok(0) - } - - fn close(&self, id: usize) -> Result { - let mut pipes = pipes_mut(); - - drop(pipes.0.remove(&id)); - drop(pipes.1.remove(&id)); - - Ok(0) - } -} - -/// Read side of a pipe -pub struct PipeRead { - flags: AtomicUsize, - condition: Arc, - vec: Arc>> -} - -impl PipeRead { - pub fn new(flags: usize) -> Self { - PipeRead { - flags: AtomicUsize::new(flags), - condition: Arc::new(WaitCondition::new()), - vec: Arc::new(Mutex::new(VecDeque::new())), - } - } - - fn dup(&self, buf: &[u8]) -> Result { - if buf == b"exec" && self.flags.load(Ordering::SeqCst) & O_CLOEXEC == O_CLOEXEC { - Err(Error::new(EBADF)) - } else { - let mut flags = self.flags.load(Ordering::SeqCst); - if buf.is_empty() { - flags &= ! O_CLOEXEC; - } - Ok(PipeRead { - flags: AtomicUsize::new(flags), - condition: self.condition.clone(), - vec: self.vec.clone() - }) - } - } - - fn fcntl(&self, cmd: usize, arg: usize) -> Result { - match cmd { - F_GETFL => Ok(self.flags.load(Ordering::SeqCst)), - F_SETFL => { - self.flags.store(arg & ! O_ACCMODE, Ordering::SeqCst); - Ok(0) - }, - _ => Err(Error::new(EINVAL)) - } - } - - fn read(&self, buf: &mut [u8]) -> Result { - loop { - { - let mut vec = self.vec.lock(); - - let mut i = 0; - while i < buf.len() { - if let Some(b) = vec.pop_front() { - buf[i] = b; - i += 1; - } else { - break; - } - } - - if i > 0 { - return Ok(i); - } - } - - if Arc::weak_count(&self.vec) == 0 { - return Ok(0); - } else if self.flags.load(Ordering::SeqCst) & O_NONBLOCK == O_NONBLOCK { - return Err(Error::new(EAGAIN)); - } else { - self.condition.wait(); - } - } - } -} - -/// Read side of a pipe -pub struct PipeWrite { - flags: AtomicUsize, - condition: Arc, - vec: Option>>> -} - -impl PipeWrite { - pub fn new(flags: usize, read: &PipeRead) -> Self { - PipeWrite { - flags: AtomicUsize::new(flags), - condition: read.condition.clone(), - vec: Some(Arc::downgrade(&read.vec)), - } - } - - fn dup(&self, buf: &[u8]) -> Result { - if buf == b"exec" && self.flags.load(Ordering::SeqCst) & O_CLOEXEC == O_CLOEXEC { - Err(Error::new(EBADF)) - } else { - let mut flags = self.flags.load(Ordering::SeqCst); - if buf.is_empty() { - flags &= ! O_CLOEXEC; - } - Ok(PipeWrite { - flags: AtomicUsize::new(flags), - condition: self.condition.clone(), - vec: self.vec.clone() - }) - } - } - - fn fcntl(&self, cmd: usize, arg: usize) -> Result { - match cmd { - F_GETFL => Ok(self.flags.load(Ordering::SeqCst)), - F_SETFL => { - self.flags.store(arg & ! O_ACCMODE, Ordering::SeqCst); - Ok(0) - }, - _ => Err(Error::new(EINVAL)) - } - } - - fn write(&self, buf: &[u8]) -> Result { - if let Some(ref vec_weak) = self.vec { - if let Some(vec_lock) = vec_weak.upgrade() { - let mut vec = vec_lock.lock(); - - for &b in buf.iter() { - vec.push_back(b); - } - - self.condition.notify(); - - Ok(buf.len()) - } else { - Err(Error::new(EPIPE)) - } - } else { - panic!("PipeWrite dropped before write"); - } - } -} - -impl Drop for PipeWrite { - fn drop(&mut self) { - drop(self.vec.take()); - self.condition.notify(); - } -} diff --git a/kernel/scheme/root.rs b/kernel/scheme/root.rs deleted file mode 100644 index 1860998..0000000 --- a/kernel/scheme/root.rs +++ /dev/null @@ -1,116 +0,0 @@ -use alloc::arc::Arc; -use alloc::boxed::Box; -use collections::BTreeMap; -use core::sync::atomic::{AtomicUsize, Ordering}; -use spin::RwLock; - -use context; -use syscall::error::*; -use syscall::scheme::Scheme; -use scheme::{self, SchemeNamespace, SchemeId}; -use scheme::user::{UserInner, UserScheme}; - -pub struct RootScheme { - scheme_ns: SchemeNamespace, - scheme_id: SchemeId, - next_id: AtomicUsize, - handles: RwLock>> -} - -impl RootScheme { - pub fn new(scheme_ns: SchemeNamespace, scheme_id: SchemeId) -> RootScheme { - RootScheme { - scheme_ns: scheme_ns, - scheme_id: scheme_id, - next_id: AtomicUsize::new(0), - handles: RwLock::new(BTreeMap::new()) - } - } -} - -impl Scheme for RootScheme { - fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - if uid == 0 { - let context = { - let contexts = context::contexts(); - let context = contexts.current().ok_or(Error::new(ESRCH))?; - Arc::downgrade(&context) - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - - let inner = { - let mut schemes = scheme::schemes_mut(); - let inner = Arc::new(UserInner::new(self.scheme_id, id, flags, context)); - schemes.insert(self.scheme_ns, path.to_vec().into_boxed_slice(), |scheme_id| { - inner.scheme_id.store(scheme_id, Ordering::SeqCst); - Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner)))) - })?; - inner - }; - - self.handles.write().insert(id, inner); - - Ok(id) - } else { - Err(Error::new(EACCES)) - } - } - - fn dup(&self, file: usize, _buf: &[u8]) -> Result { - let mut handles = self.handles.write(); - let inner = { - let inner = handles.get(&file).ok_or(Error::new(EBADF))?; - inner.clone() - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - handles.insert(id, inner); - - Ok(id) - } - - fn read(&self, file: usize, buf: &mut [u8]) -> Result { - let inner = { - let handles = self.handles.read(); - let inner = handles.get(&file).ok_or(Error::new(EBADF))?; - inner.clone() - }; - - inner.read(buf) - } - - fn write(&self, file: usize, buf: &[u8]) -> Result { - let inner = { - let handles = self.handles.read(); - let inner = handles.get(&file).ok_or(Error::new(EBADF))?; - inner.clone() - }; - - inner.write(buf) - } - - fn fevent(&self, file: usize, flags: usize) -> Result { - let inner = { - let handles = self.handles.read(); - let inner = handles.get(&file).ok_or(Error::new(EBADF))?; - inner.clone() - }; - - inner.fevent(flags) - } - - fn fsync(&self, file: usize) -> Result { - let inner = { - let handles = self.handles.read(); - let inner = handles.get(&file).ok_or(Error::new(EBADF))?; - inner.clone() - }; - - inner.fsync() - } - - fn close(&self, file: usize) -> Result { - self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) - } -} diff --git a/kernel/scheme/sys/context.rs b/kernel/scheme/sys/context.rs deleted file mode 100644 index a28820d..0000000 --- a/kernel/scheme/sys/context.rs +++ /dev/null @@ -1,106 +0,0 @@ -use collections::{String, Vec}; -use core::str; - -use context; -use syscall::error::Result; - -pub fn resource() -> Result> { - let mut string = format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n", - "PID", - "PPID", - "RUID", - "RGID", - "RNS", - "EUID", - "EGID", - "ENS", - "STAT", - "CPU", - "MEM", - "NAME"); - { - let contexts = context::contexts(); - for (_id, context_lock) in contexts.iter() { - let context = context_lock.read(); - - let mut stat_string = String::new(); - if context.stack.is_some() { - stat_string.push('U'); - } else { - stat_string.push('K'); - } - match context.status { - context::Status::Runnable => { - stat_string.push('R'); - }, - context::Status::Blocked => if context.wake.is_some() { - stat_string.push('S'); - } else { - stat_string.push('B'); - }, - context::Status::Exited(_status) => { - stat_string.push('Z'); - } - } - if context.running { - stat_string.push('+'); - } - - let cpu_string = if let Some(cpu_id) = context.cpu_id { - format!("{}", cpu_id) - } else { - format!("?") - }; - - let mut memory = 0; - if let Some(ref kfx) = context.kstack { - memory += kfx.len(); - } - if let Some(ref kstack) = context.kstack { - memory += kstack.len(); - } - for shared_mem in context.image.iter() { - shared_mem.with(|mem| { - memory += mem.size(); - }); - } - if let Some(ref heap) = context.heap { - heap.with(|heap| { - memory += heap.size(); - }); - } - if let Some(ref stack) = context.stack { - memory += stack.size(); - } - - let memory_string = if memory >= 1024 * 1024 * 1024 { - format!("{} GB", memory / 1024 / 1024 / 1024) - } else if memory >= 1024 * 1024 { - format!("{} MB", memory / 1024 / 1024) - } else if memory >= 1024 { - format!("{} KB", memory / 1024) - } else { - format!("{} B", memory) - }; - - let name_bytes = context.name.lock(); - let name = str::from_utf8(&name_bytes).unwrap_or(""); - - string.push_str(&format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n", - context.id.into(), - context.ppid.into(), - context.ruid, - context.rgid, - context.rns.into(), - context.euid, - context.egid, - context.ens.into(), - stat_string, - cpu_string, - memory_string, - name)); - } - } - - Ok(string.into_bytes()) -} diff --git a/kernel/scheme/sys/cpu.rs b/kernel/scheme/sys/cpu.rs deleted file mode 100644 index 70c1694..0000000 --- a/kernel/scheme/sys/cpu.rs +++ /dev/null @@ -1,13 +0,0 @@ -use collections::Vec; - -use arch::device::cpu::cpu_info; -use syscall::error::{Error, EIO, Result}; - -pub fn resource() -> Result> { - let mut string = format!("CPUs: {}\n", ::cpu_count()); - - match cpu_info(&mut string) { - Ok(()) => Ok(string.into_bytes()), - Err(_) => Err(Error::new(EIO)) - } -} diff --git a/kernel/scheme/sys/exe.rs b/kernel/scheme/sys/exe.rs deleted file mode 100644 index 84eb266..0000000 --- a/kernel/scheme/sys/exe.rs +++ /dev/null @@ -1,16 +0,0 @@ -use collections::Vec; - -use context; -use syscall::error::{Error, ESRCH, Result}; - -pub fn resource() -> Result> { - let mut name = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let name = context.name.lock(); - name.clone() - }; - name.push(b'\n'); - Ok(name) -} diff --git a/kernel/scheme/sys/mod.rs b/kernel/scheme/sys/mod.rs deleted file mode 100644 index ce5fd23..0000000 --- a/kernel/scheme/sys/mod.rs +++ /dev/null @@ -1,183 +0,0 @@ -use alloc::boxed::Box; -use collections::{BTreeMap, Vec}; -use core::{cmp, str}; -use core::sync::atomic::{AtomicUsize, Ordering}; -use spin::RwLock; - -use syscall::data::Stat; -use syscall::error::{Error, EBADF, EINVAL, ENOENT, Result}; -use syscall::flag::{MODE_DIR, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET}; -use syscall::scheme::Scheme; - -mod context; -mod cpu; -mod exe; -mod scheme; -//mod interrupt; -//mod log; -//mod test; - -struct Handle { - path: &'static [u8], - data: Vec, - mode: u16, - seek: usize -} - -type SysFn = Fn() -> Result> + Send + Sync; - -/// System information scheme -pub struct SysScheme { - next_id: AtomicUsize, - files: BTreeMap<&'static [u8], Box>, - handles: RwLock> -} - -impl SysScheme { - pub fn new() -> SysScheme { - let mut files: BTreeMap<&'static [u8], Box> = BTreeMap::new(); - - files.insert(b"context", Box::new(move || context::resource())); - files.insert(b"cpu", Box::new(move || cpu::resource())); - files.insert(b"exe", Box::new(move || exe::resource())); - files.insert(b"scheme", Box::new(move || scheme::resource())); - //files.insert(b"interrupt", Box::new(move || interrupt::resource())); - //files.insert(b"log", Box::new(move || log::resource())); - //files.insert(b"test", Box::new(move || test::resource())); - - SysScheme { - next_id: AtomicUsize::new(0), - files: files, - handles: RwLock::new(BTreeMap::new()) - } - } -} - -impl Scheme for SysScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - let path_utf8 = str::from_utf8(path).map_err(|_err| Error::new(ENOENT))?; - let path_trimmed = path_utf8.trim_matches('/'); - - if path_trimmed.is_empty() { - let mut data = Vec::new(); - for entry in self.files.iter() { - if ! data.is_empty() { - data.push(b'\n'); - } - data.extend_from_slice(entry.0); - } - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - path: b"", - data: data, - mode: MODE_DIR | 0o444, - seek: 0 - }); - return Ok(id) - } else { - //Have to iterate to get the path without allocation - for entry in self.files.iter() { - if entry.0 == &path_trimmed.as_bytes() { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - path: entry.0, - data: entry.1()?, - mode: MODE_FILE | 0o444, - seek: 0 - }); - return Ok(id) - } - } - } - - Err(Error::new(ENOENT)) - } - - fn dup(&self, id: usize, _buf: &[u8]) -> Result { - let (path, data, mode, seek) = { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - (handle.path, handle.data.clone(), handle.mode, handle.seek) - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - path: path, - data: data, - mode: mode, - seek: seek - }); - - Ok(id) - } - - fn read(&self, id: usize, buffer: &mut [u8]) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - while i < buffer.len() && handle.seek < handle.data.len() { - buffer[i] = handle.data[handle.seek]; - i += 1; - handle.seek += 1; - } - - Ok(i) - } - - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - handle.seek = match whence { - SEEK_SET => cmp::min(handle.data.len(), pos), - SEEK_CUR => cmp::max(0, cmp::min(handle.data.len() as isize, handle.seek as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(handle.data.len() as isize, handle.data.len() as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(handle.seek) - } - - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - let scheme_path = b"sys:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - - let mut j = 0; - while i < buf.len() && j < handle.path.len() { - buf[i] = handle.path[j]; - i += 1; - j += 1; - } - - Ok(i) - } - - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - stat.st_mode = handle.mode; - stat.st_uid = 0; - stat.st_gid = 0; - stat.st_size = handle.data.len() as u64; - - Ok(0) - } - - fn fsync(&self, _id: usize) -> Result { - Ok(0) - } - - fn close(&self, id: usize) -> Result { - self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) - } -} diff --git a/kernel/scheme/sys/scheme.rs b/kernel/scheme/sys/scheme.rs deleted file mode 100644 index b0f0c7d..0000000 --- a/kernel/scheme/sys/scheme.rs +++ /dev/null @@ -1,24 +0,0 @@ -use collections::Vec; - -use context; -use scheme; -use syscall::error::{Error, ESRCH, Result}; - -pub fn resource() -> Result> { - let scheme_ns = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.ens - }; - - let mut data = Vec::new(); - - let schemes = scheme::schemes(); - for (name, _scheme_lock) in schemes.iter_name(scheme_ns) { - data.extend_from_slice(name); - data.push(b'\n'); - } - - Ok(data) -} diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs deleted file mode 100644 index 589a8c9..0000000 --- a/kernel/scheme/user.rs +++ /dev/null @@ -1,354 +0,0 @@ -use alloc::arc::{Arc, Weak}; -use collections::BTreeMap; -use core::sync::atomic::{AtomicU64, Ordering}; -use core::{mem, slice, usize}; -use spin::{Mutex, RwLock}; - -use arch; -use arch::paging::{InactivePageTable, Page, VirtualAddress, entry}; -use arch::paging::temporary_page::TemporaryPage; -use context::{self, Context}; -use context::memory::Grant; -use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId}; -use sync::{WaitQueue, WaitMap}; -use syscall::data::{Packet, Stat, StatVfs}; -use syscall::error::*; -use syscall::flag::{EVENT_READ, O_NONBLOCK}; -use syscall::number::*; -use syscall::scheme::Scheme; - -pub struct UserInner { - root_id: SchemeId, - handle_id: usize, - flags: usize, - pub scheme_id: AtomicSchemeId, - next_id: AtomicU64, - context: Weak>, - todo: WaitQueue, - fmap: Mutex>, usize)>>, - done: WaitMap -} - -impl UserInner { - pub fn new(root_id: SchemeId, handle_id: usize, flags: usize, context: Weak>) -> UserInner { - UserInner { - root_id: root_id, - handle_id: handle_id, - flags: flags, - scheme_id: ATOMIC_SCHEMEID_INIT, - next_id: AtomicU64::new(1), - context: context, - todo: WaitQueue::new(), - fmap: Mutex::new(BTreeMap::new()), - done: WaitMap::new() - } - } - - pub fn call(&self, a: usize, b: usize, c: usize, d: usize) -> Result { - let (pid, uid, gid) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.id, context.euid, context.egid) - }; - - self.call_inner(Packet { - id: self.next_id.fetch_add(1, Ordering::SeqCst), - pid: pid.into(), - uid: uid, - gid: gid, - a: a, - b: b, - c: c, - d: d - }) - } - - fn call_inner(&self, packet: Packet) -> Result { - let id = packet.id; - - let len = self.todo.send(packet); - context::event::trigger(self.root_id, self.handle_id, EVENT_READ, mem::size_of::() * len); - - Error::demux(self.done.receive(&id)) - } - - pub fn capture(&self, buf: &[u8]) -> Result { - UserInner::capture_inner(&self.context, buf.as_ptr() as usize, buf.len(), false) - } - - pub fn capture_mut(&self, buf: &mut [u8]) -> Result { - UserInner::capture_inner(&self.context, buf.as_mut_ptr() as usize, buf.len(), true) - } - - fn capture_inner(context_weak: &Weak>, address: usize, size: usize, writable: bool) -> Result { - if size == 0 { - Ok(0) - } else { - let context_lock = context_weak.upgrade().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - - let mut grants = context.grants.lock(); - - let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; - let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); - - let from_address = (address/4096) * 4096; - let offset = address - from_address; - let full_size = ((offset + size + 4095)/4096) * 4096; - let mut to_address = arch::USER_GRANT_OFFSET; - - let mut flags = entry::PRESENT | entry::NO_EXECUTE | entry::USER_ACCESSIBLE; - if writable { - flags |= entry::WRITABLE; - } - - for i in 0 .. grants.len() { - let start = grants[i].start_address().get(); - if to_address + full_size < start { - grants.insert(i, Grant::map_inactive( - VirtualAddress::new(from_address), - VirtualAddress::new(to_address), - full_size, - flags, - &mut new_table, - &mut temporary_page - )); - - return Ok(to_address + offset); - } else { - let pages = (grants[i].size() + 4095) / 4096; - let end = start + pages * 4096; - to_address = end; - } - } - - grants.push(Grant::map_inactive( - VirtualAddress::new(from_address), - VirtualAddress::new(to_address), - full_size, - flags, - &mut new_table, - &mut temporary_page - )); - - Ok(to_address + offset) - } - } - - pub fn release(&self, address: usize) -> Result<()> { - if address == 0 { - Ok(()) - } else { - let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - - let mut grants = context.grants.lock(); - - let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; - let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); - - for i in 0 .. grants.len() { - let start = grants[i].start_address().get(); - let end = start + grants[i].size(); - if address >= start && address < end { - grants.remove(i).unmap_inactive(&mut new_table, &mut temporary_page); - - return Ok(()); - } - } - - Err(Error::new(EFAULT)) - } - } - - pub fn read(&self, buf: &mut [u8]) -> Result { - let packet_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Packet, buf.len()/mem::size_of::()) }; - Ok(self.todo.receive_into(packet_buf, self.flags & O_NONBLOCK != O_NONBLOCK) * mem::size_of::()) - } - - pub fn write(&self, buf: &[u8]) -> Result { - let packet_size = mem::size_of::(); - let len = buf.len()/packet_size; - let mut i = 0; - while i < len { - let mut packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) }; - if packet.id == 0 { - match packet.a { - SYS_FEVENT => context::event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, packet.c, packet.d), - _ => println!("Unknown scheme -> kernel message {}", packet.a) - } - } else { - if let Some((context_weak, size)) = self.fmap.lock().remove(&packet.id) { - if let Ok(address) = Error::demux(packet.a) { - packet.a = Error::mux(UserInner::capture_inner(&context_weak, address, size, true)); - } - } - - self.done.send(packet.id, packet.a); - } - i += 1; - } - - Ok(i * packet_size) - } - - pub fn fevent(&self, _flags: usize) -> Result { - Ok(self.handle_id) - } - - pub fn fsync(&self) -> Result { - Ok(0) - } -} - -/// UserInner has to be wrapped -pub struct UserScheme { - inner: Weak -} - -impl UserScheme { - pub fn new(inner: Weak) -> UserScheme { - UserScheme { - inner: inner - } - } -} - -impl Scheme for UserScheme { - fn open(&self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture(path)?; - let result = inner.call(SYS_OPEN, address, path.len(), flags); - let _ = inner.release(address); - result - } - - fn chmod(&self, path: &[u8], mode: u16, _uid: u32, _gid: u32) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture(path)?; - let result = inner.call(SYS_CHMOD, address, path.len(), mode as usize); - let _ = inner.release(address); - result - } - - fn rmdir(&self, path: &[u8], _uid: u32, _gid: u32) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture(path)?; - let result = inner.call(SYS_RMDIR, address, path.len(), 0); - let _ = inner.release(address); - result - } - - fn unlink(&self, path: &[u8], _uid: u32, _gid: u32) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture(path)?; - let result = inner.call(SYS_UNLINK, address, path.len(), 0); - let _ = inner.release(address); - result - } - - fn dup(&self, file: usize, buf: &[u8]) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture(buf)?; - let result = inner.call(SYS_DUP, file, address, buf.len()); - let _ = inner.release(address); - result - } - - fn read(&self, file: usize, buf: &mut [u8]) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture_mut(buf)?; - let result = inner.call(SYS_READ, file, address, buf.len()); - let _ = inner.release(address); - result - } - - fn write(&self, file: usize, buf: &[u8]) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture(buf)?; - let result = inner.call(SYS_WRITE, file, address, buf.len()); - let _ = inner.release(address); - result - } - - fn seek(&self, file: usize, position: usize, whence: usize) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - inner.call(SYS_LSEEK, file, position, whence) - } - - fn fcntl(&self, file: usize, cmd: usize, arg: usize) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - inner.call(SYS_FCNTL, file, cmd, arg) - } - - fn fevent(&self, file: usize, flags: usize) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - inner.call(SYS_FEVENT, file, flags, 0) - } - - fn fmap(&self, file: usize, offset: usize, size: usize) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - - let (pid, uid, gid, context_lock) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.id, context.euid, context.egid, Arc::downgrade(&context_lock)) - }; - - let id = inner.next_id.fetch_add(1, Ordering::SeqCst); - - inner.fmap.lock().insert(id, (context_lock, size)); - - inner.call_inner(Packet { - id: id, - pid: pid.into(), - uid: uid, - gid: gid, - a: SYS_FMAP, - b: file, - c: offset, - d: size - }) - } - - fn fpath(&self, file: usize, buf: &mut [u8]) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture_mut(buf)?; - let result = inner.call(SYS_FPATH, file, address, buf.len()); - let _ = inner.release(address); - result - } - - fn fstat(&self, file: usize, stat: &mut Stat) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture_mut(stat)?; - let result = inner.call(SYS_FSTAT, file, address, mem::size_of::()); - let _ = inner.release(address); - result - } - - fn fstatvfs(&self, file: usize, stat: &mut StatVfs) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - let address = inner.capture_mut(stat)?; - let result = inner.call(SYS_FSTATVFS, file, address, mem::size_of::()); - let _ = inner.release(address); - result - } - - fn fsync(&self, file: usize) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - inner.call(SYS_FSYNC, file, 0, 0) - } - - fn ftruncate(&self, file: usize, len: usize) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - inner.call(SYS_FTRUNCATE, file, len, 0) - } - - fn close(&self, file: usize) -> Result { - let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - inner.call(SYS_CLOSE, file, 0, 0) - } -} diff --git a/kernel/scheme/zero.rs b/kernel/scheme/zero.rs deleted file mode 100644 index 90175cb..0000000 --- a/kernel/scheme/zero.rs +++ /dev/null @@ -1,42 +0,0 @@ -use syscall::error::*; -use syscall::scheme::Scheme; - -pub struct ZeroScheme; - -impl Scheme for ZeroScheme { - fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - Ok(0) - } - - fn dup(&self, _file: usize, _buf: &[u8]) -> Result { - Ok(0) - } - - /// Read the file `number` into the `buffer` - /// - /// Returns the number of bytes read - fn read(&self, _file: usize, buf: &mut [u8]) -> Result { - let mut i = 0; - while i < buf.len() { - buf[i] = 0; - i += 1; - } - Ok(i) - } - - /// Write the `buffer` to the `file` - /// - /// Returns the number of bytes written - fn write(&self, _file: usize, buffer: &[u8]) -> Result { - Ok(buffer.len()) - } - - fn fsync(&self, _file: usize) -> Result { - Ok(0) - } - - /// Close the file `number` - fn close(&self, _file: usize) -> Result { - Ok(0) - } -} diff --git a/kernel/sync/mod.rs b/kernel/sync/mod.rs deleted file mode 100644 index 833925b..0000000 --- a/kernel/sync/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use self::wait_condition::WaitCondition; -pub use self::wait_queue::WaitQueue; -pub use self::wait_map::WaitMap; - -pub mod wait_condition; -pub mod wait_queue; -pub mod wait_map; diff --git a/kernel/sync/wait_condition.rs b/kernel/sync/wait_condition.rs deleted file mode 100644 index cb17026..0000000 --- a/kernel/sync/wait_condition.rs +++ /dev/null @@ -1,48 +0,0 @@ -use alloc::arc::Arc; -use collections::Vec; -use spin::{Mutex, RwLock}; - -use context::{self, Context}; - -#[derive(Debug)] -pub struct WaitCondition { - contexts: Mutex>>> -} - -impl WaitCondition { - pub fn new() -> WaitCondition { - WaitCondition { - contexts: Mutex::new(Vec::with_capacity(16)) - } - } - - pub fn notify(&self) -> usize { - let mut contexts = self.contexts.lock(); - let len = contexts.len(); - while let Some(context_lock) = contexts.pop() { - context_lock.write().unblock(); - } - len - } - - pub fn wait(&self) { - { - let context_lock = { - let contexts = context::contexts(); - let context_lock = contexts.current().expect("WaitCondition::wait: no context"); - context_lock.clone() - }; - - context_lock.write().block(); - - self.contexts.lock().push(context_lock); - } - unsafe { context::switch(); } - } -} - -impl Drop for WaitCondition { - fn drop(&mut self){ - self.notify(); - } -} diff --git a/kernel/sync/wait_map.rs b/kernel/sync/wait_map.rs deleted file mode 100644 index c0198a1..0000000 --- a/kernel/sync/wait_map.rs +++ /dev/null @@ -1,62 +0,0 @@ -use collections::BTreeMap; -use core::mem; -use spin::Mutex; - -use sync::WaitCondition; - -#[derive(Debug)] -pub struct WaitMap { - inner: Mutex>, - condition: WaitCondition -} - -impl WaitMap where K: Clone + Ord { - pub fn new() -> WaitMap { - WaitMap { - inner: Mutex::new(BTreeMap::new()), - condition: WaitCondition::new() - } - } - - pub fn receive_nonblock(&self, key: &K) -> Option { - self.inner.lock().remove(key) - } - - pub fn receive(&self, key: &K) -> V { - loop { - if let Some(value) = self.receive_nonblock(key) { - return value; - } - self.condition.wait(); - } - } - - pub fn receive_any_nonblock(&self) -> Option<(K, V)> { - let mut inner = self.inner.lock(); - if let Some(key) = inner.keys().next().map(|key| key.clone()) { - inner.remove(&key).map(|value| (key, value)) - } else { - None - } - } - - pub fn receive_any(&self) -> (K, V) { - loop { - if let Some(entry) = self.receive_any_nonblock() { - return entry; - } - self.condition.wait(); - } - } - - pub fn receive_all(&self) -> BTreeMap { - let mut ret = BTreeMap::new(); - mem::swap(&mut ret, &mut *self.inner.lock()); - ret - } - - pub fn send(&self, key: K, value: V) { - self.inner.lock().insert(key, value); - self.condition.notify(); - } -} diff --git a/kernel/sync/wait_queue.rs b/kernel/sync/wait_queue.rs deleted file mode 100644 index fdf81b5..0000000 --- a/kernel/sync/wait_queue.rs +++ /dev/null @@ -1,82 +0,0 @@ -use collections::vec_deque::VecDeque; -use spin::Mutex; - -use sync::WaitCondition; - -#[derive(Debug)] -pub struct WaitQueue { - pub inner: Mutex>, - pub condition: WaitCondition, -} - -impl WaitQueue { - pub fn new() -> WaitQueue { - WaitQueue { - inner: Mutex::new(VecDeque::new()), - condition: WaitCondition::new() - } - } - - pub fn clone(&self) -> WaitQueue where T: Clone { - WaitQueue { - inner: Mutex::new(self.inner.lock().clone()), - condition: WaitCondition::new() - } - } - - pub fn is_empty(&self) -> bool { - self.inner.lock().is_empty() - } - - pub fn receive(&self) -> T { - loop { - if let Some(value) = self.inner.lock().pop_front() { - return value; - } - self.condition.wait(); - } - } - - pub fn receive_into(&self, buf: &mut [T], block: bool) -> usize { - let mut i = 0; - - if i < buf.len() && block { - buf[i] = self.receive(); - i += 1; - } - - { - let mut inner = self.inner.lock(); - while i < buf.len() { - if let Some(value) = inner.pop_front() { - buf[i] = value; - i += 1; - } else { - break; - } - } - } - - i - } - - pub fn send(&self, value: T) -> usize { - let len = { - let mut inner = self.inner.lock(); - inner.push_back(value); - inner.len() - }; - self.condition.notify(); - len - } - - pub fn send_from(&self, buf: &[T]) -> usize where T: Copy { - let len = { - let mut inner = self.inner.lock(); - inner.extend(buf.iter()); - inner.len() - }; - self.condition.notify(); - len - } -} diff --git a/kernel/syscall/driver.rs b/kernel/syscall/driver.rs deleted file mode 100644 index 9c3f3cd..0000000 --- a/kernel/syscall/driver.rs +++ /dev/null @@ -1,130 +0,0 @@ -use arch; -use arch::memory::{allocate_frames, deallocate_frames, Frame}; -use arch::paging::{entry, ActivePageTable, PhysicalAddress, VirtualAddress}; -use context; -use context::memory::Grant; -use syscall::error::{Error, EFAULT, ENOMEM, EPERM, ESRCH, Result}; -use syscall::flag::{MAP_WRITE, MAP_WRITE_COMBINE}; - -fn enforce_root() -> Result<()> { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - if context.euid == 0 { - Ok(()) - } else { - Err(Error::new(EPERM)) - } -} - -pub fn iopl(_level: usize, _stack_base: usize) -> Result { - enforce_root()?; - - //TODO - Ok(0) -} - -pub fn physalloc(size: usize) -> Result { - enforce_root()?; - - allocate_frames((size + 4095)/4096).ok_or(Error::new(ENOMEM)).map(|frame| frame.start_address().get()) -} - -pub fn physfree(physical_address: usize, size: usize) -> Result { - enforce_root()?; - - deallocate_frames(Frame::containing_address(PhysicalAddress::new(physical_address)), (size + 4095)/4096); - //TODO: Check that no double free occured - Ok(0) -} - -//TODO: verify exlusive access to physical memory -pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result { - enforce_root()?; - - if size == 0 { - Ok(0) - } else { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - - let mut grants = context.grants.lock(); - - let from_address = (physical_address/4096) * 4096; - let offset = physical_address - from_address; - let full_size = ((offset + size + 4095)/4096) * 4096; - let mut to_address = arch::USER_GRANT_OFFSET; - - let mut entry_flags = entry::PRESENT | entry::NO_EXECUTE | entry::USER_ACCESSIBLE; - if flags & MAP_WRITE == MAP_WRITE { - entry_flags |= entry::WRITABLE; - } - if flags & MAP_WRITE_COMBINE == MAP_WRITE_COMBINE { - entry_flags |= entry::HUGE_PAGE; - } - - for i in 0 .. grants.len() { - let start = grants[i].start_address().get(); - if to_address + full_size < start { - grants.insert(i, Grant::physmap( - PhysicalAddress::new(from_address), - VirtualAddress::new(to_address), - full_size, - entry_flags - )); - - return Ok(to_address + offset); - } else { - let pages = (grants[i].size() + 4095) / 4096; - let end = start + pages * 4096; - to_address = end; - } - } - - grants.push(Grant::physmap( - PhysicalAddress::new(from_address), - VirtualAddress::new(to_address), - full_size, - entry_flags - )); - - Ok(to_address + offset) - } -} - -pub fn physunmap(virtual_address: usize) -> Result { - enforce_root()?; - - if virtual_address == 0 { - Ok(0) - } else { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - - let mut grants = context.grants.lock(); - - for i in 0 .. grants.len() { - let start = grants[i].start_address().get(); - let end = start + grants[i].size(); - if virtual_address >= start && virtual_address < end { - grants.remove(i).unmap(); - - return Ok(0); - } - } - - Err(Error::new(EFAULT)) - } -} - -pub fn virttophys(virtual_address: usize) -> Result { - enforce_root()?; - - let active_table = unsafe { ActivePageTable::new() }; - match active_table.translate(VirtualAddress::new(virtual_address)) { - Some(physical_address) => Ok(physical_address.get()), - None => Err(Error::new(EFAULT)) - } -} diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs deleted file mode 100644 index bd02c52..0000000 --- a/kernel/syscall/fs.rs +++ /dev/null @@ -1,356 +0,0 @@ -//! Filesystem syscalls -use core::sync::atomic::Ordering; - -use context; -use scheme::{self, FileHandle}; -use syscall; -use syscall::data::{Packet, Stat}; -use syscall::error::*; -use syscall::flag::{MODE_DIR, MODE_FILE}; - -pub fn file_op(a: usize, fd: FileHandle, c: usize, d: usize) -> Result { - let (file, pid, uid, gid) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let file = context.get_file(fd).ok_or(Error::new(EBADF))?; - (file, context.id, context.euid, context.egid) - }; - - let scheme = { - let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; - scheme.clone() - }; - - let mut packet = Packet { - id: 0, - pid: pid.into(), - uid: uid, - gid: gid, - a: a, - b: file.number, - c: c, - d: d - }; - - scheme.handle(&mut packet); - - Error::demux(packet.a) -} - -pub fn file_op_slice(a: usize, fd: FileHandle, slice: &[u8]) -> Result { - file_op(a, fd, slice.as_ptr() as usize, slice.len()) -} - -pub fn file_op_mut_slice(a: usize, fd: FileHandle, slice: &mut [u8]) -> Result { - file_op(a, fd, slice.as_mut_ptr() as usize, slice.len()) -} - -/// Change the current working directory -pub fn chdir(path: &[u8]) -> Result { - let fd = open(path, syscall::flag::O_RDONLY | syscall::flag::O_DIRECTORY)?; - let mut stat = Stat::default(); - let stat_res = file_op_mut_slice(syscall::number::SYS_FSTAT, fd, &mut stat); - let _ = close(fd); - stat_res?; - if stat.st_mode & (MODE_FILE | MODE_DIR) == MODE_DIR { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let canonical = context.canonicalize(path); - *context.cwd.lock() = canonical; - Ok(0) - } else { - Err(Error::new(ENOTDIR)) - } -} - -/// Get the current working directory -pub fn getcwd(buf: &mut [u8]) -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let cwd = context.cwd.lock(); - let mut i = 0; - while i < buf.len() && i < cwd.len() { - buf[i] = cwd[i]; - i += 1; - } - Ok(i) -} - -/// Open syscall -pub fn open(path: &[u8], flags: usize) -> Result { - let (path_canon, uid, gid, scheme_ns) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.canonicalize(path), context.euid, context.egid, context.ens) - }; - - //println!("open {}", unsafe { ::core::str::from_utf8_unchecked(&path_canon) }); - - let mut parts = path_canon.splitn(2, |&b| b == b':'); - let scheme_name_opt = parts.next(); - let reference_opt = parts.next(); - - let (scheme_id, file_id) = { - let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?; - let (scheme_id, scheme) = { - let schemes = scheme::schemes(); - let (scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?; - (scheme_id, scheme.clone()) - }; - let file_id = scheme.open(reference_opt.unwrap_or(b""), flags, uid, gid)?; - (scheme_id, file_id) - }; - - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.add_file(::context::file::File { - scheme: scheme_id, - number: file_id, - event: None, - }).ok_or(Error::new(EMFILE)) -} - -pub fn pipe2(fds: &mut [usize], flags: usize) -> Result { - if fds.len() >= 2 { - let scheme_id = ::scheme::pipe::PIPE_SCHEME_ID.load(Ordering::SeqCst); - let (read_id, write_id) = ::scheme::pipe::pipe(flags); - - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - - let read_fd = context.add_file(::context::file::File { - scheme: scheme_id, - number: read_id, - event: None, - }).ok_or(Error::new(EMFILE))?; - - let write_fd = context.add_file(::context::file::File { - scheme: scheme_id, - number: write_id, - event: None, - }).ok_or(Error::new(EMFILE))?; - - fds[0] = read_fd.into(); - fds[1] = write_fd.into(); - - Ok(0) - } else { - Err(Error::new(EFAULT)) - } -} - -/// chmod syscall -pub fn chmod(path: &[u8], mode: u16) -> Result { - let (path_canon, uid, gid, scheme_ns) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.canonicalize(path), context.euid, context.egid, context.ens) - }; - - let mut parts = path_canon.splitn(2, |&b| b == b':'); - let scheme_name_opt = parts.next(); - let reference_opt = parts.next(); - - let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?; - let scheme = { - let schemes = scheme::schemes(); - let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?; - scheme.clone() - }; - scheme.chmod(reference_opt.unwrap_or(b""), mode, uid, gid) -} - -/// rmdir syscall -pub fn rmdir(path: &[u8]) -> Result { - let (path_canon, uid, gid, scheme_ns) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.canonicalize(path), context.euid, context.egid, context.ens) - }; - - let mut parts = path_canon.splitn(2, |&b| b == b':'); - let scheme_name_opt = parts.next(); - let reference_opt = parts.next(); - - let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?; - let scheme = { - let schemes = scheme::schemes(); - let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?; - scheme.clone() - }; - scheme.rmdir(reference_opt.unwrap_or(b""), uid, gid) -} - -/// Unlink syscall -pub fn unlink(path: &[u8]) -> Result { - let (path_canon, uid, gid, scheme_ns) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.canonicalize(path), context.euid, context.egid, context.ens) - }; - - let mut parts = path_canon.splitn(2, |&b| b == b':'); - let scheme_name_opt = parts.next(); - let reference_opt = parts.next(); - - let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?; - let scheme = { - let schemes = scheme::schemes(); - let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?; - scheme.clone() - }; - scheme.unlink(reference_opt.unwrap_or(b""), uid, gid) -} - -/// Close syscall -pub fn close(fd: FileHandle) -> Result { - let file = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let file = context.remove_file(fd).ok_or(Error::new(EBADF))?; - file - }; - - if let Some(event_id) = file.event { - context::event::unregister(fd, file.scheme, event_id); - } - - let scheme = { - let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; - scheme.clone() - }; - scheme.close(file.number) -} - -/// Duplicate file descriptor -pub fn dup(fd: FileHandle, buf: &[u8]) -> Result { - let file = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let file = context.get_file(fd).ok_or(Error::new(EBADF))?; - file - }; - - let new_id = { - let scheme = { - let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; - scheme.clone() - }; - scheme.dup(file.number, buf)? - }; - - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.add_file(::context::file::File { - scheme: file.scheme, - number: new_id, - event: None, - }).ok_or(Error::new(EMFILE)) -} - -/// Duplicate file descriptor, replacing another -pub fn dup2(fd: FileHandle, new_fd: FileHandle, buf: &[u8]) -> Result { - if fd == new_fd { - Ok(new_fd) - } else { - let _ = close(new_fd)?; - - let file = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let file = context.get_file(fd).ok_or(Error::new(EBADF))?; - file - }; - - let new_id = { - let scheme = { - let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; - scheme.clone() - }; - scheme.dup(file.number, buf)? - }; - - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.insert_file(new_fd, ::context::file::File { - scheme: file.scheme, - number: new_id, - event: None, - }).ok_or(Error::new(EBADF)) - } -} - -/// Register events for file -pub fn fevent(fd: FileHandle, flags: usize) -> Result { - let file = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let mut files = context.files.lock(); - let mut file = files.get_mut(fd.into()).ok_or(Error::new(EBADF))?.ok_or(Error::new(EBADF))?; - if let Some(event_id) = file.event.take() { - println!("{:?}: {:?}:{}: events already registered: {}", fd, file.scheme, file.number, event_id); - context::event::unregister(fd, file.scheme, event_id); - } - file.clone() - }; - - let scheme = { - let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; - scheme.clone() - }; - let event_id = scheme.fevent(file.number, flags)?; - { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let mut files = context.files.lock(); - let mut file = files.get_mut(fd.into()).ok_or(Error::new(EBADF))?.ok_or(Error::new(EBADF))?; - file.event = Some(event_id); - } - context::event::register(fd, file.scheme, event_id); - Ok(0) -} - -pub fn funmap(virtual_address: usize) -> Result { - if virtual_address == 0 { - Ok(0) - } else { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - - let mut grants = context.grants.lock(); - - for i in 0 .. grants.len() { - let start = grants[i].start_address().get(); - let end = start + grants[i].size(); - if virtual_address >= start && virtual_address < end { - grants.remove(i).unmap(); - - return Ok(0); - } - } - - Err(Error::new(EFAULT)) - } -} diff --git a/kernel/syscall/futex.rs b/kernel/syscall/futex.rs deleted file mode 100644 index 4b9c30c..0000000 --- a/kernel/syscall/futex.rs +++ /dev/null @@ -1,110 +0,0 @@ -use alloc::arc::Arc; -use collections::VecDeque; -use core::intrinsics; -use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; - -use context::{self, Context}; -use syscall::error::{Error, Result, ESRCH, EAGAIN, EINVAL}; -use syscall::flag::{FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; -use syscall::validate::validate_slice_mut; - -type FutexList = VecDeque<(usize, Arc>)>; - -/// Fast userspace mutex list -static FUTEXES: Once> = Once::new(); - -/// Initialize futexes, called if needed -fn init_futexes() -> RwLock { - RwLock::new(VecDeque::new()) -} - -/// Get the global futexes list, const -pub fn futexes() -> RwLockReadGuard<'static, FutexList> { - FUTEXES.call_once(init_futexes).read() -} - -/// Get the global futexes list, mutable -pub fn futexes_mut() -> RwLockWriteGuard<'static, FutexList> { - FUTEXES.call_once(init_futexes).write() -} - -pub fn futex(addr: &mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32) -> Result { - match op { - FUTEX_WAIT => { - { - let mut futexes = futexes_mut(); - - let context_lock = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - context_lock.clone() - }; - - if unsafe { intrinsics::atomic_load(addr) != val } { - return Err(Error::new(EAGAIN)); - } - - context_lock.write().block(); - - futexes.push_back((addr as *mut i32 as usize, context_lock)); - } - - unsafe { context::switch(); } - - Ok(0) - }, - FUTEX_WAKE => { - let mut woken = 0; - - { - let mut futexes = futexes_mut(); - - let mut i = 0; - while i < futexes.len() && (woken as i32) < val { - if futexes[i].0 == addr as *mut i32 as usize { - if let Some(futex) = futexes.swap_remove_back(i) { - futex.1.write().unblock(); - woken += 1; - } - } else { - i += 1; - } - } - } - - Ok(woken) - }, - FUTEX_REQUEUE => { - let addr2_safe = validate_slice_mut(addr2, 1).map(|addr2_safe| &mut addr2_safe[0])?; - - let mut woken = 0; - let mut requeued = 0; - - { - let mut futexes = futexes_mut(); - - let mut i = 0; - while i < futexes.len() && (woken as i32) < val { - if futexes[i].0 == addr as *mut i32 as usize { - if let Some(futex) = futexes.swap_remove_back(i) { - futex.1.write().unblock(); - woken += 1; - } - } else { - i += 1; - } - } - while i < futexes.len() && requeued < val2 { - if futexes[i].0 == addr as *mut i32 as usize { - futexes[i].0 = addr2_safe as *mut i32 as usize; - requeued += 1; - } - i += 1; - } - } - - Ok(woken) - }, - _ => Err(Error::new(EINVAL)) - } -} diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs deleted file mode 100644 index d303007..0000000 --- a/kernel/syscall/mod.rs +++ /dev/null @@ -1,121 +0,0 @@ -///! Syscall handlers - -extern crate syscall; - -pub use self::syscall::{data, error, flag, number, scheme}; - -pub use self::driver::*; -pub use self::fs::*; -pub use self::futex::futex; -pub use self::privilege::*; -pub use self::process::*; -pub use self::time::*; -pub use self::validate::*; - -use self::data::TimeSpec; -use self::error::{Error, Result, ENOSYS}; -use self::number::*; - -use context::ContextId; -use scheme::{FileHandle, SchemeNamespace}; - -/// Driver syscalls -pub mod driver; - -/// Filesystem syscalls -pub mod fs; - -/// Fast userspace mutex -pub mod futex; - -/// Privilege syscalls -pub mod privilege; - -/// Process syscalls -pub mod process; - -/// Time syscalls -pub mod time; - -/// Validate input -pub mod validate; - -#[no_mangle] -pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize { - #[inline(always)] - fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> Result { - match a & SYS_CLASS { - SYS_CLASS_FILE => { - let fd = FileHandle::from(b); - match a & SYS_ARG { - SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?), - SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?), - _ => match a { - SYS_CLOSE => close(fd), - SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into), - SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into), - SYS_FEVENT => fevent(fd, c), - SYS_FUNMAP => funmap(b), - _ => file_op(a, fd, c, d) - } - } - }, - SYS_CLASS_PATH => match a { - SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into), - SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16), - SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?), - SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?), - _ => unreachable!() - }, - _ => match a { - SYS_YIELD => sched_yield(), - SYS_NANOSLEEP => nanosleep(validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?, validate_slice_mut(c as *mut TimeSpec, 1).ok().map(|rem| &mut rem[0])), - SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?), - SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32), - SYS_BRK => brk(b), - SYS_GETPID => getpid().map(ContextId::into), - SYS_CLONE => clone(b, stack).map(ContextId::into), - SYS_EXIT => exit((b & 0xFF) << 8), - SYS_KILL => kill(ContextId::from(b), c), - SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into), - SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?), - SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?), - SYS_IOPL => iopl(b, stack), - SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?), - SYS_GETEGID => getegid(), - SYS_GETENS => getens(), - SYS_GETEUID => geteuid(), - SYS_GETGID => getgid(), - SYS_GETNS => getns(), - SYS_GETUID => getuid(), - SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?), - SYS_SETREUID => setreuid(b as u32, c as u32), - SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)), - SYS_SETREGID => setregid(b as u32, c as u32), - SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c), - SYS_PHYSALLOC => physalloc(b), - SYS_PHYSFREE => physfree(b, c), - SYS_PHYSMAP => physmap(b, c, d), - SYS_PHYSUNMAP => physunmap(b), - SYS_VIRTTOPHYS => virttophys(b), - _ => Err(Error::new(ENOSYS)) - } - } - } - - let result = inner(a, b, c, d, e, f, stack); - - /* - if let Err(ref err) = result { - let contexts = ::context::contexts(); - if let Some(context_lock) = contexts.current() { - let context = context_lock.read(); - print!("{}: {}: ", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into()); - } - - println!("{:X}, {:X}, {:X}, {:X}: {}", a, b, c, d, err); - } - */ - - Error::mux(result) -} diff --git a/kernel/syscall/privilege.rs b/kernel/syscall/privilege.rs deleted file mode 100644 index e718196..0000000 --- a/kernel/syscall/privilege.rs +++ /dev/null @@ -1,147 +0,0 @@ -use collections::Vec; - -use context; -use scheme::{self, SchemeNamespace}; -use syscall::error::*; -use syscall::validate::validate_slice; - -pub fn getegid() -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - Ok(context.egid as usize) -} - -pub fn getens() -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - Ok(context.ens.into()) -} - -pub fn geteuid() -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - Ok(context.euid as usize) -} - -pub fn getgid() -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - Ok(context.rgid as usize) -} - -pub fn getns() -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - Ok(context.rns.into()) -} - -pub fn getuid() -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - Ok(context.ruid as usize) -} - -pub fn mkns(name_ptrs: &[[usize; 2]]) -> Result { - let mut names = Vec::new(); - for name_ptr in name_ptrs { - names.push(validate_slice(name_ptr[0] as *const u8, name_ptr[1])?); - } - - let (uid, from) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.euid, context.ens) - }; - - if uid == 0 { - let to = scheme::schemes_mut().make_ns(from, &names)?; - Ok(to.into()) - } else { - Err(Error::new(EACCES)) - } -} - -pub fn setregid(rgid: u32, egid: u32) -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let mut context = context_lock.write(); - - if (context.euid == 0 - || rgid as i32 == -1 - || rgid == context.egid - || rgid == context.rgid) - && (context.euid == 0 - || egid as i32 == -1 - || egid == context.egid - || egid == context.rgid) - { - if rgid as i32 != -1 { - context.rgid = rgid; - } - if egid as i32 != -1 { - context.egid = egid; - } - Ok(0) - } else { - Err(Error::new(EPERM)) - } -} - -pub fn setrens(rns: SchemeNamespace, ens: SchemeNamespace) -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let mut context = context_lock.write(); - - if (context.euid == 0 - || rns.into() as isize == -1 - || rns == context.ens - || rns == context.rns) - && (context.euid == 0 - || ens.into() as isize == -1 - || ens == context.ens - || ens == context.rns) - { - if rns.into() as isize != -1 { - context.rns = rns; - } - if ens.into() as isize != -1 { - context.ens = ens; - } - Ok(0) - } else { - Err(Error::new(EPERM)) - } -} - -pub fn setreuid(ruid: u32, euid: u32) -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let mut context = context_lock.write(); - - if (context.euid == 0 - || ruid as i32 == -1 - || ruid == context.euid - || ruid == context.ruid) - && (context.euid == 0 - || euid as i32 == -1 - || euid == context.euid - || euid == context.ruid) - { - if ruid as i32 != -1 { - context.ruid = ruid; - } - if euid as i32 != -1 { - context.euid = euid; - } - Ok(0) - } else { - Err(Error::new(EPERM)) - } -} diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs deleted file mode 100644 index 8ffadf5..0000000 --- a/kernel/syscall/process.rs +++ /dev/null @@ -1,973 +0,0 @@ -///! Process syscalls -use alloc::arc::Arc; -use alloc::boxed::Box; -use collections::{BTreeMap, Vec}; -use core::{intrinsics, mem, str}; -use core::ops::DerefMut; -use spin::Mutex; - -use arch; -use arch::memory::allocate_frame; -use arch::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, entry}; -use arch::paging::temporary_page::TemporaryPage; -use arch::start::usermode; -use context; -use context::ContextId; -use elf::{self, program_header}; -use scheme::{self, FileHandle}; -use syscall; -use syscall::data::Stat; -use syscall::error::*; -use syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, WNOHANG}; -use syscall::validate::{validate_slice, validate_slice_mut}; - -pub fn brk(address: usize) -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - - //println!("{}: {}: BRK {:X}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }, - // context.id.into(), address); - - let current = if let Some(ref heap_shared) = context.heap { - heap_shared.with(|heap| { - heap.start_address().get() + heap.size() - }) - } else { - panic!("user heap not initialized"); - }; - - if address == 0 { - //println!("Brk query {:X}", current); - Ok(current) - } else if address >= arch::USER_HEAP_OFFSET { - //TODO: out of memory errors - if let Some(ref heap_shared) = context.heap { - heap_shared.with(|heap| { - heap.resize(address - arch::USER_HEAP_OFFSET, true, true); - }); - } else { - panic!("user heap not initialized"); - } - - //println!("Brk resize {:X}", address); - Ok(address) - } else { - //println!("Brk no mem"); - Err(Error::new(ENOMEM)) - } -} - -pub fn clone(flags: usize, stack_base: usize) -> Result { - let ppid; - let pid; - { - let ruid; - let rgid; - let rns; - let euid; - let egid; - let ens; - let mut cpu_id = None; - let arch; - let vfork; - let mut kfx_option = None; - let mut kstack_option = None; - let mut offset = 0; - let mut image = vec![]; - let mut heap_option = None; - let mut stack_option = None; - let mut tls_option = None; - let grants; - let name; - let cwd; - let env; - let files; - - // Copy from old process - { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - - ppid = context.id; - ruid = context.ruid; - rgid = context.rgid; - rns = context.rns; - euid = context.euid; - egid = context.egid; - ens = context.ens; - - if flags & CLONE_VM == CLONE_VM { - cpu_id = context.cpu_id; - } - - arch = context.arch.clone(); - - if let Some(ref fx) = context.kfx { - let mut new_fx = unsafe { Box::from_raw(::alloc::heap::allocate(512, 16) as *mut [u8; 512]) }; - for (new_b, b) in new_fx.iter_mut().zip(fx.iter()) { - *new_b = *b; - } - kfx_option = Some(new_fx); - } - - if let Some(ref stack) = context.kstack { - offset = stack_base - stack.as_ptr() as usize - mem::size_of::(); // Add clone ret - let mut new_stack = stack.clone(); - - unsafe { - let func_ptr = new_stack.as_mut_ptr().offset(offset as isize); - *(func_ptr as *mut usize) = arch::interrupt::syscall::clone_ret as usize; - } - - kstack_option = Some(new_stack); - } - - if flags & CLONE_VM == CLONE_VM { - for memory_shared in context.image.iter() { - image.push(memory_shared.clone()); - } - - if let Some(ref heap_shared) = context.heap { - heap_option = Some(heap_shared.clone()); - } - } else { - for memory_shared in context.image.iter() { - memory_shared.with(|memory| { - let mut new_memory = context::memory::Memory::new( - VirtualAddress::new(memory.start_address().get() + arch::USER_TMP_OFFSET), - memory.size(), - entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE, - true, - false - ); - - unsafe { - intrinsics::copy(memory.start_address().get() as *const u8, - new_memory.start_address().get() as *mut u8, - memory.size()); - } - - new_memory.remap(memory.flags(), true); - image.push(new_memory.to_shared()); - }); - } - - if let Some(ref heap_shared) = context.heap { - heap_shared.with(|heap| { - let mut new_heap = context::memory::Memory::new( - VirtualAddress::new(arch::USER_TMP_HEAP_OFFSET), - heap.size(), - entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE, - true, - false - ); - - unsafe { - intrinsics::copy(heap.start_address().get() as *const u8, - new_heap.start_address().get() as *mut u8, - heap.size()); - } - - new_heap.remap(heap.flags(), true); - heap_option = Some(new_heap.to_shared()); - }); - } - } - - if let Some(ref stack) = context.stack { - let mut new_stack = context::memory::Memory::new( - VirtualAddress::new(arch::USER_TMP_STACK_OFFSET), - stack.size(), - entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE, - true, - false - ); - - unsafe { - intrinsics::copy(stack.start_address().get() as *const u8, - new_stack.start_address().get() as *mut u8, - stack.size()); - } - - new_stack.remap(stack.flags(), true); - stack_option = Some(new_stack); - } - - if let Some(ref tls) = context.tls { - let mut new_tls = context::memory::Tls { - master: tls.master, - file_size: tls.file_size, - mem: context::memory::Memory::new( - VirtualAddress::new(arch::USER_TMP_TLS_OFFSET), - tls.mem.size(), - entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE, - true, - true - ) - }; - - unsafe { - intrinsics::copy(tls.master.get() as *const u8, - new_tls.mem.start_address().get() as *mut u8, - tls.file_size); - } - - new_tls.mem.remap(tls.mem.flags(), true); - tls_option = Some(new_tls); - } - - if flags & CLONE_VM == CLONE_VM { - grants = context.grants.clone(); - } else { - grants = Arc::new(Mutex::new(Vec::new())); - } - - if flags & CLONE_VM == CLONE_VM { - name = context.name.clone(); - } else { - name = Arc::new(Mutex::new(context.name.lock().clone())); - } - - if flags & CLONE_FS == CLONE_FS { - cwd = context.cwd.clone(); - } else { - cwd = Arc::new(Mutex::new(context.cwd.lock().clone())); - } - - if flags & CLONE_VM == CLONE_VM { - env = context.env.clone(); - } else { - let mut new_env = BTreeMap::new(); - for item in context.env.lock().iter() { - new_env.insert(item.0.clone(), Arc::new(Mutex::new(item.1.lock().clone()))); - } - env = Arc::new(Mutex::new(new_env)); - } - - if flags & CLONE_FILES == CLONE_FILES { - files = context.files.clone(); - } else { - files = Arc::new(Mutex::new(context.files.lock().clone())); - } - } - - // If not cloning files, dup to get a new number from scheme - // This has to be done outside the context lock to prevent deadlocks - if flags & CLONE_FILES == 0 { - for (_fd, mut file_option) in files.lock().iter_mut().enumerate() { - let new_file_option = if let Some(file) = *file_option { - let result = { - let scheme = { - let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; - scheme.clone() - }; - let result = scheme.dup(file.number, b"clone"); - result - }; - match result { - Ok(new_number) => { - Some(context::file::File { - scheme: file.scheme, - number: new_number, - event: None, - }) - }, - Err(_err) => { - None - } - } - } else { - None - }; - - *file_option = new_file_option; - } - } - - // If vfork, block the current process - // This has to be done after the operations that may require context switches - if flags & CLONE_VFORK == CLONE_VFORK { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let mut context = context_lock.write(); - context.block(); - vfork = true; - } else { - vfork = false; - } - - // Set up new process - { - let mut contexts = context::contexts_mut(); - let context_lock = contexts.new_context()?; - let mut context = context_lock.write(); - - pid = context.id; - - context.ppid = ppid; - context.ruid = ruid; - context.rgid = rgid; - context.rns = rns; - context.euid = euid; - context.egid = egid; - context.ens = ens; - - context.cpu_id = cpu_id; - - context.status = context::Status::Runnable; - - context.vfork = vfork; - - context.arch = arch; - - let mut active_table = unsafe { ActivePageTable::new() }; - - let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(0x8_0000_0000))); - - let mut new_table = { - let frame = allocate_frame().expect("no more frames in syscall::clone new_table"); - InactivePageTable::new(frame, &mut active_table, &mut temporary_page) - }; - - context.arch.set_page_table(unsafe { new_table.address() }); - - // Copy kernel mapping - { - let frame = active_table.p4()[510].pointed_frame().expect("kernel table not mapped"); - let flags = active_table.p4()[510].flags(); - active_table.with(&mut new_table, &mut temporary_page, |mapper| { - mapper.p4_mut()[510].set(frame, flags); - }); - } - - if let Some(fx) = kfx_option.take() { - context.arch.set_fx(fx.as_ptr() as usize); - context.kfx = Some(fx); - } - - // Set kernel stack - if let Some(stack) = kstack_option.take() { - context.arch.set_stack(stack.as_ptr() as usize + offset); - context.kstack = Some(stack); - } - - // Setup heap - if flags & CLONE_VM == CLONE_VM { - // Copy user image mapping, if found - if ! image.is_empty() { - let frame = active_table.p4()[0].pointed_frame().expect("user image not mapped"); - let flags = active_table.p4()[0].flags(); - active_table.with(&mut new_table, &mut temporary_page, |mapper| { - mapper.p4_mut()[0].set(frame, flags); - }); - } - context.image = image; - - // Copy user heap mapping, if found - if let Some(heap_shared) = heap_option { - let frame = active_table.p4()[1].pointed_frame().expect("user heap not mapped"); - let flags = active_table.p4()[1].flags(); - active_table.with(&mut new_table, &mut temporary_page, |mapper| { - mapper.p4_mut()[1].set(frame, flags); - }); - context.heap = Some(heap_shared); - } - - // Copy grant mapping - if ! grants.lock().is_empty() { - let frame = active_table.p4()[2].pointed_frame().expect("user grants not mapped"); - let flags = active_table.p4()[2].flags(); - active_table.with(&mut new_table, &mut temporary_page, |mapper| { - mapper.p4_mut()[2].set(frame, flags); - }); - } - context.grants = grants; - } else { - // Copy percpu mapping - for cpu_id in 0..::cpu_count() { - extern { - /// The starting byte of the thread data segment - static mut __tdata_start: u8; - /// The ending byte of the thread BSS segment - static mut __tbss_end: u8; - } - - let size = unsafe { & __tbss_end as *const _ as usize - & __tdata_start as *const _ as usize }; - - let start = arch::KERNEL_PERCPU_OFFSET + arch::KERNEL_PERCPU_SIZE * cpu_id; - let end = start + size; - - let start_page = Page::containing_address(VirtualAddress::new(start)); - let end_page = Page::containing_address(VirtualAddress::new(end - 1)); - for page in Page::range_inclusive(start_page, end_page) { - let frame = active_table.translate_page(page).expect("kernel percpu not mapped"); - active_table.with(&mut new_table, &mut temporary_page, |mapper| { - mapper.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE); - }); - } - } - - // Move copy of image - for memory_shared in image.iter_mut() { - memory_shared.with(|memory| { - let start = VirtualAddress::new(memory.start_address().get() - arch::USER_TMP_OFFSET + arch::USER_OFFSET); - memory.move_to(start, &mut new_table, &mut temporary_page, true); - }); - } - context.image = image; - - // Move copy of heap - if let Some(heap_shared) = heap_option { - heap_shared.with(|heap| { - heap.move_to(VirtualAddress::new(arch::USER_HEAP_OFFSET), &mut new_table, &mut temporary_page, true); - }); - context.heap = Some(heap_shared); - } - } - - // Setup user stack - if let Some(mut stack) = stack_option { - stack.move_to(VirtualAddress::new(arch::USER_STACK_OFFSET), &mut new_table, &mut temporary_page, true); - context.stack = Some(stack); - } - - // Setup user TLS - if let Some(mut tls) = tls_option { - tls.mem.move_to(VirtualAddress::new(arch::USER_TLS_OFFSET), &mut new_table, &mut temporary_page, true); - context.tls = Some(tls); - } - - context.name = name; - - context.cwd = cwd; - - context.env = env; - - context.files = files; - } - } - - unsafe { context::switch(); } - - Ok(pid) -} - -fn empty(context: &mut context::Context, reaping: bool) { - if reaping { - // Memory should already be unmapped - assert!(context.image.is_empty()); - assert!(context.heap.is_none()); - assert!(context.stack.is_none()); - assert!(context.tls.is_none()); - } else { - // Unmap previous image, heap, grants, stack, and tls - context.image.clear(); - drop(context.heap.take()); - drop(context.stack.take()); - drop(context.tls.take()); - } - - // FIXME: Looks like a race condition. - // Is it possible for Arc::strong_count to return 1 to two contexts that exit at the - // same time, or return 2 to both, thus either double freeing or leaking the grants? - if Arc::strong_count(&context.grants) == 1 { - let mut grants = context.grants.lock(); - for grant in grants.drain(..) { - if reaping { - println!("{}: {}: Grant should not exist: {:?}", context.id.into(), unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }, grant); - - let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; - let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); - - grant.unmap_inactive(&mut new_table, &mut temporary_page); - } else { - grant.unmap(); - } - } - } -} - -pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { - let entry; - let mut sp = arch::USER_STACK_OFFSET + arch::USER_STACK_SIZE - 256; - - { - let mut args = Vec::new(); - for arg_ptr in arg_ptrs { - let arg = validate_slice(arg_ptr[0] as *const u8, arg_ptr[1])?; - args.push(arg.to_vec()); // Must be moved into kernel space before exec unmaps all memory - } - - let (uid, gid, canonical) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.euid, context.egid, context.canonicalize(path)) - }; - - let file = syscall::open(&canonical, syscall::flag::O_RDONLY)?; - let mut stat = Stat::default(); - syscall::file_op_mut_slice(syscall::number::SYS_FSTAT, file, &mut stat)?; - - let mut perm = stat.st_mode & 0o7; - if stat.st_uid == uid { - perm |= (stat.st_mode >> 6) & 0o7; - } - if stat.st_gid == gid { - perm |= (stat.st_mode >> 3) & 0o7; - } - if uid == 0 { - perm |= 0o7; - } - - if perm & 0o1 != 0o1 { - let _ = syscall::close(file); - return Err(Error::new(EACCES)); - } - - //TODO: Only read elf header, not entire file. Then read required segments - let mut data = vec![0; stat.st_size as usize]; - syscall::file_op_mut_slice(syscall::number::SYS_READ, file, &mut data)?; - let _ = syscall::close(file); - - match elf::Elf::from(&data) { - Ok(elf) => { - entry = elf.entry(); - - drop(path); // Drop so that usage is not allowed after unmapping context - drop(arg_ptrs); // Drop so that usage is not allowed after unmapping context - - let contexts = context::contexts(); - let (vfork, ppid, files) = { - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let mut context = context_lock.write(); - - // Set name - context.name = Arc::new(Mutex::new(canonical)); - - empty(&mut context, false); - - if stat.st_mode & syscall::flag::MODE_SETUID == syscall::flag::MODE_SETUID { - context.euid = stat.st_uid; - } - - if stat.st_mode & syscall::flag::MODE_SETGID == syscall::flag::MODE_SETGID { - context.egid = stat.st_gid; - } - - // Map and copy new segments - let mut tls_option = None; - for segment in elf.segments() { - if segment.p_type == program_header::PT_LOAD { - let mut memory = context::memory::Memory::new( - VirtualAddress::new(segment.p_vaddr as usize), - segment.p_memsz as usize, - entry::NO_EXECUTE | entry::WRITABLE, - true, - true - ); - - unsafe { - // Copy file data - intrinsics::copy((elf.data.as_ptr() as usize + segment.p_offset as usize) as *const u8, - segment.p_vaddr as *mut u8, - segment.p_filesz as usize); - } - - let mut flags = entry::NO_EXECUTE | entry::USER_ACCESSIBLE; - - if segment.p_flags & program_header::PF_R == program_header::PF_R { - flags.insert(entry::PRESENT); - } - - // W ^ X. If it is executable, do not allow it to be writable, even if requested - if segment.p_flags & program_header::PF_X == program_header::PF_X { - flags.remove(entry::NO_EXECUTE); - } else if segment.p_flags & program_header::PF_W == program_header::PF_W { - flags.insert(entry::WRITABLE); - } - - memory.remap(flags, true); - - context.image.push(memory.to_shared()); - } else if segment.p_type == program_header::PT_TLS { - let memory = context::memory::Memory::new( - VirtualAddress::new(arch::USER_TCB_OFFSET), - 4096, - entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE, - true, - true - ); - - unsafe { *(arch::USER_TCB_OFFSET as *mut usize) = arch::USER_TLS_OFFSET + segment.p_memsz as usize; } - - context.image.push(memory.to_shared()); - - tls_option = Some(( - VirtualAddress::new(segment.p_vaddr as usize), - segment.p_filesz as usize, - segment.p_memsz as usize - )); - } - } - - // Map heap - context.heap = Some(context::memory::Memory::new( - VirtualAddress::new(arch::USER_HEAP_OFFSET), - 0, - entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE, - true, - true - ).to_shared()); - - // Map stack - context.stack = Some(context::memory::Memory::new( - VirtualAddress::new(arch::USER_STACK_OFFSET), - arch::USER_STACK_SIZE, - entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE, - true, - true - )); - - // Map TLS - if let Some((master, file_size, size)) = tls_option { - let tls = context::memory::Tls { - master: master, - file_size: file_size, - mem: context::memory::Memory::new( - VirtualAddress::new(arch::USER_TLS_OFFSET), - size, - entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE, - true, - true - ) - }; - - unsafe { - // Copy file data - intrinsics::copy(master.get() as *const u8, - tls.mem.start_address().get() as *mut u8, - file_size); - } - - context.tls = Some(tls); - } - - // Push arguments - let mut arg_size = 0; - for arg in args.iter().rev() { - sp -= mem::size_of::(); - unsafe { *(sp as *mut usize) = arch::USER_ARG_OFFSET + arg_size; } - sp -= mem::size_of::(); - unsafe { *(sp as *mut usize) = arg.len(); } - - arg_size += arg.len(); - } - - sp -= mem::size_of::(); - unsafe { *(sp as *mut usize) = args.len(); } - - if arg_size > 0 { - let mut memory = context::memory::Memory::new( - VirtualAddress::new(arch::USER_ARG_OFFSET), - arg_size, - entry::NO_EXECUTE | entry::WRITABLE, - true, - true - ); - - let mut arg_offset = 0; - for arg in args.iter().rev() { - unsafe { - intrinsics::copy(arg.as_ptr(), - (arch::USER_ARG_OFFSET + arg_offset) as *mut u8, - arg.len()); - } - - arg_offset += arg.len(); - } - - memory.remap(entry::NO_EXECUTE | entry::USER_ACCESSIBLE, true); - - context.image.push(memory.to_shared()); - } - - let files = Arc::new(Mutex::new(context.files.lock().clone())); - context.files = files.clone(); - - let vfork = context.vfork; - context.vfork = false; - (vfork, context.ppid, files) - }; - - // Duplicate current files using b"exec", close previous - for (fd, mut file_option) in files.lock().iter_mut().enumerate() { - let new_file_option = if let Some(file) = *file_option { - // Duplicate - let result = { - let scheme_option = { - let schemes = scheme::schemes(); - schemes.get(file.scheme).map(|scheme| scheme.clone()) - }; - if let Some(scheme) = scheme_option { - let result = scheme.dup(file.number, b"exec"); - result - } else { - Err(Error::new(EBADF)) - } - }; - - // Close - { - if let Some(event_id) = file.event { - context::event::unregister(FileHandle::from(fd), file.scheme, event_id); - } - - let scheme_option = { - let schemes = scheme::schemes(); - schemes.get(file.scheme).map(|scheme| scheme.clone()) - }; - if let Some(scheme) = scheme_option { - let _ = scheme.close(file.number); - } - } - - // Return new descriptor - match result { - Ok(new_number) => { - Some(context::file::File { - scheme: file.scheme, - number: new_number, - event: None, - }) - }, - Err(_err) => { - None - } - } - } else { - None - }; - - *file_option = new_file_option; - } - - if vfork { - if let Some(context_lock) = contexts.get(ppid) { - let mut context = context_lock.write(); - if ! context.unblock() { - println!("{:?} not blocked for exec vfork unblock", ppid); - } - } else { - println!("{:?} not found for exec vfork unblock", ppid); - } - } - }, - Err(err) => { - println!("failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, err); - return Err(Error::new(ENOEXEC)); - } - } - } - - // Go to usermode - unsafe { usermode(entry, sp); } -} - -pub fn exit(status: usize) -> ! { - { - let context_lock = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exit failed to find context"); - context_lock.clone() - }; - - let mut close_files = Vec::new(); - let (pid, ppid) = { - let mut context = context_lock.write(); - // FIXME: Looks like a race condition. - // Is it possible for Arc::strong_count to return 1 to two contexts that exit at the - // same time, or return 2 to both, thus either double closing or leaking the files? - if Arc::strong_count(&context.files) == 1 { - mem::swap(context.files.lock().deref_mut(), &mut close_files); - } - context.files = Arc::new(Mutex::new(Vec::new())); - (context.id, context.ppid) - }; - - /// Files must be closed while context is valid so that messages can be passed - for (fd, file_option) in close_files.drain(..).enumerate() { - if let Some(file) = file_option { - if let Some(event_id) = file.event { - context::event::unregister(FileHandle::from(fd), file.scheme, event_id); - } - - let scheme_option = { - let schemes = scheme::schemes(); - schemes.get(file.scheme).map(|scheme| scheme.clone()) - }; - if let Some(scheme) = scheme_option { - let _ = scheme.close(file.number); - } - } - } - - /// Transfer child processes to parent - { - let contexts = context::contexts(); - for (_id, context_lock) in contexts.iter() { - let mut context = context_lock.write(); - if context.ppid == pid { - context.ppid = ppid; - context.vfork = false; - } - } - } - - let (vfork, children) = { - let mut context = context_lock.write(); - - empty(&mut context, false); - - let vfork = context.vfork; - context.vfork = false; - - context.status = context::Status::Exited(status); - - let children = context.waitpid.receive_all(); - - (vfork, children) - }; - - { - let contexts = context::contexts(); - if let Some(parent_lock) = contexts.get(ppid) { - let waitpid = { - let mut parent = parent_lock.write(); - if vfork { - if ! parent.unblock() { - println!("{:?} not blocked for exit vfork unblock", ppid); - } - } - parent.waitpid.clone() - }; - - for (c_pid, c_status) in children { - waitpid.send(c_pid, c_status); - } - waitpid.send(pid, status); - } else { - println!("{:?} not found for exit vfork unblock", ppid); - } - } - } - - unsafe { context::switch(); } - - unreachable!(); -} - -pub fn getpid() -> Result { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - Ok(context.id) -} - -pub fn kill(pid: ContextId, sig: usize) -> Result { - let (ruid, euid) = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - (context.ruid, context.euid) - }; - - if sig > 0 && sig <= 0x7F { - let contexts = context::contexts(); - let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?; - let mut context = context_lock.write(); - if euid == 0 - || euid == context.ruid - || ruid == context.ruid - { - context.pending.push_back(sig as u8); - Ok(0) - } else { - Err(Error::new(EPERM)) - } - } else { - Err(Error::new(EINVAL)) - } -} - -fn reap(pid: ContextId) -> Result { - // Spin until not running - let mut running = false; - while running { - { - let contexts = context::contexts(); - let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - running = context.running; - } - - arch::interrupt::pause(); - } - - let mut contexts = context::contexts_mut(); - let context_lock = contexts.remove(pid).ok_or(Error::new(ESRCH))?; - { - let mut context = context_lock.write(); - empty(&mut context, true); - } - drop(context_lock); - - Ok(pid) -} - -pub fn waitpid(pid: ContextId, status_ptr: usize, flags: usize) -> Result { - let waitpid = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.waitpid.clone() - }; - - let mut tmp = [0]; - let status_slice = if status_ptr != 0 { - validate_slice_mut(status_ptr as *mut usize, 1)? - } else { - &mut tmp - }; - - if pid.into() == 0 { - if flags & WNOHANG == WNOHANG { - if let Some((w_pid, status)) = waitpid.receive_any_nonblock() { - status_slice[0] = status; - reap(w_pid) - } else { - Ok(ContextId::from(0)) - } - } else { - let (w_pid, status) = waitpid.receive_any(); - status_slice[0] = status; - reap(w_pid) - } - } else { - if flags & WNOHANG == WNOHANG { - if let Some(status) = waitpid.receive_nonblock(&pid) { - status_slice[0] = status; - reap(pid) - } else { - Ok(ContextId::from(0)) - } - } else { - let status = waitpid.receive(&pid); - status_slice[0] = status; - reap(pid) - } - } -} diff --git a/kernel/syscall/time.rs b/kernel/syscall/time.rs deleted file mode 100644 index 448f311..0000000 --- a/kernel/syscall/time.rs +++ /dev/null @@ -1,53 +0,0 @@ -use arch; -use context; -use syscall::data::TimeSpec; -use syscall::error::*; -use syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC}; - -pub fn clock_gettime(clock: usize, time: &mut TimeSpec) -> Result { - match clock { - CLOCK_REALTIME => { - let arch_time = arch::time::realtime(); - time.tv_sec = arch_time.0 as i64; - time.tv_nsec = arch_time.1 as i32; - Ok(0) - }, - CLOCK_MONOTONIC => { - let arch_time = arch::time::monotonic(); - time.tv_sec = arch_time.0 as i64; - time.tv_nsec = arch_time.1 as i32; - Ok(0) - }, - _ => Err(Error::new(EINVAL)) - } -} - -pub fn nanosleep(req: &TimeSpec, rem_opt: Option<&mut TimeSpec>) -> Result { - let start = arch::time::monotonic(); - let sum = start.1 + req.tv_nsec as u64; - let end = (start.0 + req.tv_sec as u64 + sum / 1000000000, sum % 1000000000); - - { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let mut context = context_lock.write(); - - context.wake = Some(end); - context.block(); - } - - unsafe { context::switch(); } - - if let Some(mut rem) = rem_opt { - //TODO let current = arch::time::monotonic(); - rem.tv_sec = 0; - rem.tv_nsec = 0; - } - - Ok(0) -} - -pub fn sched_yield() -> Result { - unsafe { context::switch(); } - Ok(0) -} diff --git a/kernel/syscall/validate.rs b/kernel/syscall/validate.rs deleted file mode 100644 index 0f5b03b..0000000 --- a/kernel/syscall/validate.rs +++ /dev/null @@ -1,44 +0,0 @@ -use core::{mem, slice}; - -use arch::paging::{ActivePageTable, Page, VirtualAddress, entry}; -use syscall::error::*; - -fn validate(address: usize, size: usize, flags: entry::EntryFlags) -> Result<()> { - let active_table = unsafe { ActivePageTable::new() }; - - let start_page = Page::containing_address(VirtualAddress::new(address)); - let end_page = Page::containing_address(VirtualAddress::new(address + size - 1)); - for page in Page::range_inclusive(start_page, end_page) { - if let Some(page_flags) = active_table.translate_page_flags(page) { - if ! page_flags.contains(flags) { - //println!("{:X}: Not {:?}", page.start_address().get(), flags); - return Err(Error::new(EFAULT)); - } - } else { - //println!("{:X}: Not found", page.start_address().get()); - return Err(Error::new(EFAULT)); - } - } - - Ok(()) -} - -/// Convert a pointer and length to slice, if valid -pub fn validate_slice(ptr: *const T, len: usize) -> Result<&'static [T]> { - if len == 0 { - Ok(&[]) - } else { - validate(ptr as usize, len * mem::size_of::(), entry::PRESENT /* TODO | entry::USER_ACCESSIBLE */)?; - Ok(unsafe { slice::from_raw_parts(ptr, len) }) - } -} - -/// Convert a pointer and length to slice, if valid -pub fn validate_slice_mut(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { - if len == 0 { - Ok(&mut []) - } else { - validate(ptr as usize, len * mem::size_of::(), entry::PRESENT | entry::WRITABLE /* TODO | entry::USER_ACCESSIBLE */)?; - Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) - } -} diff --git a/kernel/tests/mod.rs b/kernel/tests/mod.rs deleted file mode 100644 index 0ad27af..0000000 --- a/kernel/tests/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -use syscall::{self, Error}; - -/// Test stdio -#[test] -fn stdio() { - // Test opening stdin - assert_eq!(syscall::open(b"debug:", 0), Ok(0)); - - // Test opening stdout - assert_eq!(syscall::open(b"debug:", 0), Ok(1)); - - // Test opening stderr - assert_eq!(syscall::open(b"debug:", 0), Ok(2)); - - // Test writing stdout - let stdout_str = b"STDOUT"; - assert_eq!(syscall::write(1, stdout_str), Ok(stdout_str.len())); - - // Test writing stderr - let stderr_str = b"STDERR"; - assert_eq!(syscall::write(2, stderr_str), Ok(stderr_str.len())); -} - -/// Test that invalid reads/writes cause errors -#[test] -fn invalid_path() { - assert_eq!(syscall::read(999, &mut []), Err(Error::new(EBADF))); - assert_eq!(syscall::write(999, &[]), Err(Error::new(EBADF))); -} diff --git a/krustc.sh b/krustc.sh deleted file mode 100755 index cc510e8..0000000 --- a/krustc.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -have_o=false -for arg in "$@"; do - if [[ "$arg" = "-o" ]]; then - have_o=true - break - fi -done - -args=() -for arg in "$@"; do - if [[ $have_o = true && "$arg" =~ ^extra-filename= ]]; then - unset args[${#args[@]}-1] - elif [[ $have_o = true && "$arg" =~ ^--emit= ]]; then - args+=("--emit=link") - else - args+=("$arg") - fi -done - -RUST_BACKTRACE=1 exec rustc -L build/kernel "${args[@]}" diff --git a/krustdoc.sh b/krustdoc.sh deleted file mode 100755 index 8365834..0000000 --- a/krustdoc.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -RUST_BACKTRACE=1 rustdoc -L build/kernel $* diff --git a/libc-artifacts b/libc-artifacts deleted file mode 160000 index b0e2a74..0000000 --- a/libc-artifacts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b0e2a74a505d0bc6ffea05d81fe239b1beb5c246 diff --git a/mk/bochs.mk b/mk/bochs.mk new file mode 100644 index 0000000..964dba5 --- /dev/null +++ b/mk/bochs.mk @@ -0,0 +1,2 @@ +bochs: build/harddrive.bin + bochs -f bochs.$(ARCH) diff --git a/mk/config.mk b/mk/config.mk new file mode 100644 index 0000000..2bcb528 --- /dev/null +++ b/mk/config.mk @@ -0,0 +1,38 @@ +# Configuration +ARCH?=x86_64 +INSTALLER_FLAGS?=--cookbook=cookbook + +# Per host variables +UNAME := $(shell uname) +ifeq ($(UNAME),Darwin) + ECHO=/bin/echo + FUMOUNT=sudo umount + export LD=$(ARCH)-elf-ld + export NPROC=sysctl -n hw.ncpu + export STRIP=$(ARCH)-elf-strip + VB_AUDIO=coreaudio + VBM="/Applications/VirtualBox.app/Contents/MacOS/VBoxManage" +else + ECHO=echo + FUMOUNT=fusermount -u + export LD=ld + export NPROC=nproc + export STRIP=strip + VB_AUDIO="pulse" + VBM=VBoxManage +endif + +# Automatic variables +ROOT=$(PWD) +export INITFS_FOLDER=$(ROOT)/build/initfs +export RUST_TARGET_PATH=$(ROOT)/kernel/targets +export XARGO_HOME=$(ROOT)/build/xargo +export XARGO_RUST_SRC=$(ROOT)/rust/src + +# Kernel variables +KTARGET=$(ARCH)-unknown-none +KBUILD=build/kernel + +# Userspace variables +export TARGET=$(ARCH)-unknown-redox +BUILD=build/userspace diff --git a/mk/disk.mk b/mk/disk.mk new file mode 100644 index 0000000..f78bbab --- /dev/null +++ b/mk/disk.mk @@ -0,0 +1,18 @@ +build/harddrive.bin: build/kernel build/filesystem.bin bootloader/$(ARCH)/** + nasm -f bin -o $@ -D ARCH_$(ARCH) -D FILESYSTEM=build/filesystem.bin -ibootloader/$(ARCH)/ bootloader/$(ARCH)/disk.asm + +build/livedisk.bin: build/kernel_live bootloader/$(ARCH)/** + nasm -f bin -o $@ -D ARCH_$(ARCH) -D KERNEL=$< -ibootloader/$(ARCH)/ bootloader/$(ARCH)/disk.asm + +build/%.bin.gz: build/%.bin + gzip -k -f $< + +build/livedisk.iso: build/livedisk.bin.gz + rm -rf build/iso/ + mkdir -p build/iso/ + cp -RL isolinux build/iso/ + cp $< build/iso/livedisk.gz + genisoimage -o $@ -b isolinux/isolinux.bin -c isolinux/boot.cat \ + -no-emul-boot -boot-load-size 4 -boot-info-table \ + build/iso/ + isohybrid $@ diff --git a/mk/filesystem.mk b/mk/filesystem.mk new file mode 100644 index 0000000..9918a76 --- /dev/null +++ b/mk/filesystem.mk @@ -0,0 +1,43 @@ +build/filesystem.bin: filesystem.toml build/kernel + -$(FUMOUNT) build/filesystem/ || true + rm -rf $@ $@.partial build/filesystem/ + dd if=/dev/zero of=$@.partial bs=1048576 count=512 + cargo run --manifest-path redoxfs/Cargo.toml --quiet --release --bin redoxfs-mkfs $@.partial + mkdir -p build/filesystem/ + cargo build --manifest-path redoxfs/Cargo.toml --quiet --release --bin redoxfs + cargo run --manifest-path redoxfs/Cargo.toml --quiet --release --bin redoxfs -- $@.partial build/filesystem/ + sleep 2 + pgrep redoxfs + cp build/kernel build/filesystem/kernel + cargo run --manifest-path installer/Cargo.toml -- $(INSTALLER_FLAGS) $< + chown -R 0:0 build/filesystem + chown -R 1000:1000 build/filesystem/home/user + chmod -R uog+rX build/filesystem + chmod -R u+w build/filesystem + chmod -R og-w build/filesystem + chmod -R 755 build/filesystem/bin + chmod -R u+rwX build/filesystem/root + chmod -R og-rwx build/filesystem/root + chmod -R u+rwX build/filesystem/home/user + chmod -R og-rwx build/filesystem/home/user + chmod +s build/filesystem/bin/passwd + chmod +s build/filesystem/bin/su + chmod +s build/filesystem/bin/sudo + mkdir build/filesystem/tmp + chmod 1777 build/filesystem/tmp + sync + -$(FUMOUNT) build/filesystem/ || true + rm -rf build/filesystem/ + mv $@.partial $@ + +mount: FORCE + mkdir -p build/filesystem/ + cargo build --manifest-path redoxfs/Cargo.toml --quiet --release --bin redoxfs + cargo run --manifest-path redoxfs/Cargo.toml --quiet --release --bin redoxfs -- build/harddrive.bin build/filesystem/ + sleep 2 + pgrep redoxfs + +unmount: FORCE + sync + -$(FUMOUNT) build/filesystem/ || true + rm -rf build/filesystem/ diff --git a/mk/initfs.mk b/mk/initfs.mk new file mode 100644 index 0000000..dc25325 --- /dev/null +++ b/mk/initfs.mk @@ -0,0 +1,5 @@ +build/initfs.tag: initfs.toml + cd kernel && xargo clean + rm -rf build/initfs + cargo run --manifest-path installer/Cargo.toml -- $(INSTALLER_FLAGS) $< + touch $@ diff --git a/mk/kernel.mk b/mk/kernel.mk new file mode 100644 index 0000000..32491e3 --- /dev/null +++ b/mk/kernel.mk @@ -0,0 +1,16 @@ +build/libkernel.a: kernel/Cargo.toml kernel/src/* kernel/src/*/* kernel/src/*/*/* build/initfs.tag +# Temporary fix for https://github.com/redox-os/redox/issues/963 allowing to build on macOS +ifeq ($(UNAME),Darwin) + cd kernel && CC=$(ARCH)-elf-gcc AR=$(ARCH)-elf-ar CFLAGS=-ffreestanding xargo rustc --lib --target $(KTARGET) --release -- -C soft-float --emit link=../$@ +else + cd kernel && xargo rustc --lib --target $(KTARGET) --release -- -C soft-float --emit link=../$@ +endif + +build/libkernel_live.a: kernel/Cargo.toml kernel/src/* kernel/src/*/* kernel/src/*/*/* build/initfs.tag build/filesystem.bin + cd kernel && FILESYSTEM="$(PWD)/build/filesystem.bin" xargo rustc --lib --features live --target $(KTARGET) --release -- -C soft-float --emit link=../$@ + +build/kernel: build/libkernel.a kernel/linkers/$(ARCH).ld + $(LD) --gc-sections -z max-page-size=0x1000 -T kernel/linkers/$(ARCH).ld -o $@ $< + +build/kernel_live: build/libkernel_live.a kernel/linkers/$(ARCH).ld + $(LD) --gc-sections -z max-page-size=0x1000 -T kernel/linkers/$(ARCH).ld -o $@ $< diff --git a/mk/qemu.mk b/mk/qemu.mk new file mode 100644 index 0000000..bfc69a5 --- /dev/null +++ b/mk/qemu.mk @@ -0,0 +1,75 @@ +QEMU=SDL_VIDEO_X11_DGAMOUSE=0 qemu-system-$(ARCH) +QEMUFLAGS=-serial mon:stdio -d cpu_reset -d guest_errors +QEMUFLAGS+=-smp 4 -m 2048 +ifeq ($(iommu),yes) + QEMUFLAGS+=-machine q35,iommu=on +else + QEMUFLAGS+=-machine q35 +endif +ifneq ($(audio),no) + QEMUFLAGS+=-device ich9-intel-hda -device hda-duplex +endif +ifeq ($(net),no) + QEMUFLAGS+=-net none +else + QEMUFLAGS+=-net nic,model=e1000 -net user -net dump,file=build/network.pcap + ifeq ($(net),redir) + QEMUFLAGS+=-redir tcp:8023::8023 -redir tcp:8080::8080 + endif +endif +ifeq ($(vga),no) + QEMUFLAGS+=-nographic -vga none +endif +ifneq ($(usb),no) + QEMUFLAGS+=-device nec-usb-xhci,id=xhci -device usb-tablet,bus=xhci.0 +endif +ifeq ($(UNAME),Linux) + ifneq ($(kvm),no) + QEMUFLAGS+=-enable-kvm -cpu host + endif +endif +#,int,pcall +#-device intel-iommu + +build/extra.qcow2: + qemu-img create -f qcow2 $@ 256M + +qemu: build/harddrive.bin build/extra.qcow2 + $(QEMU) $(QEMUFLAGS) \ + -drive file=build/harddrive.bin,format=raw \ + -drive file=build/extra.qcow2 + +qemu_no_build: build/extra.qcow2 + $(QEMU) $(QEMUFLAGS) \ + -drive file=build/harddrive.bin,format=raw \ + -drive file=build/extra.qcow2 + +qemu_nvme: build/harddrive.bin build/extra.qcow2 + $(QEMU) $(QEMUFLAGS) \ + -drive file=build/harddrive.bin,format=raw -drive file=build/extra.qcow2,if=none,id=drv0 -device nvme,drive=drv0,serial=NVME_SERIAL \ + -drive file=build/extra.qcow2 + +qemu_nvme_no_build: build/extra.qcow2 + $(QEMU) $(QEMUFLAGS) \ + -drive file=build/harddrive.bin,format=raw -drive file=build/extra.qcow2,if=none,id=drv0 -device nvme,drive=drv0,serial=NVME_SERIAL \ + -drive file=build/extra.qcow2 + +qemu_live: build/livedisk.bin build/extra.qcow2 + $(QEMU) $(QEMUFLAGS) \ + -device usb-ehci,id=flash_bus -drive id=flash_drive,file=build/livedisk.bin,format=raw,if=none -device usb-storage,drive=flash_drive,bus=flash_bus.0 \ + -drive file=build/extra.qcow2 + +qemu_live_no_build: build/extra.qcow2 + $(QEMU) $(QEMUFLAGS) \ + -device usb-ehci,id=flash_bus -drive id=flash_drive,file=build/livedisk.bin,format=raw,if=none -device usb-storage,drive=flash_drive,bus=flash_bus.0 \ + -drive file=build/extra.qcow2 + +qemu_iso: build/livedisk.iso build/extra.qcow2 + $(QEMU) $(QEMUFLAGS) \ + -boot d -cdrom build/livedisk.iso \ + -drive file=build/extra.qcow2 + +qemu_iso_no_build: build/extra.qcow2 + $(QEMU) $(QEMUFLAGS) \ + -boot d -cdrom build/livedisk.iso \ + -drive file=build/extra.qcow2 diff --git a/mk/virtualbox.mk b/mk/virtualbox.mk new file mode 100644 index 0000000..b764b2f --- /dev/null +++ b/mk/virtualbox.mk @@ -0,0 +1,42 @@ +BUILDDIR = $(abspath $(dir $(firstword $(MAKEFILE_LIST))))/build +virtualbox: build/harddrive.bin + echo "Delete VM" + -$(VBM) unregistervm Redox --delete; \ + if [ $$? -ne 0 ]; \ + then \ + if [ -d "$$HOME/VirtualBox VMs/Redox" ]; \ + then \ + echo "Redox directory exists, deleting..."; \ + $(RM) -rf "$$HOME/VirtualBox VMs/Redox"; \ + fi \ + fi + echo "Delete Disk" + -$(RM) harddrive.vdi + echo "Create VM" + $(VBM) createvm --name Redox --register + echo "Set Configuration" + $(VBM) modifyvm Redox --memory 2048 + $(VBM) modifyvm Redox --vram 32 + if [ "$(net)" != "no" ]; \ + then \ + $(VBM) modifyvm Redox --nic1 nat; \ + $(VBM) modifyvm Redox --nictype1 82540EM; \ + $(VBM) modifyvm Redox --cableconnected1 on; \ + $(VBM) modifyvm Redox --nictrace1 on; \ + $(VBM) modifyvm Redox --nictracefile1 "$(BUILDDIR)/redox_network.pcap"; \ + fi + $(VBM) modifyvm Redox --uart1 0x3F8 4 + $(VBM) modifyvm Redox --uartmode1 file "$(BUILDDIR)/redox_serial.log" + $(VBM) modifyvm Redox --usb off # on + $(VBM) modifyvm Redox --keyboard ps2 + $(VBM) modifyvm Redox --mouse ps2 + $(VBM) modifyvm Redox --audio $(VB_AUDIO) + $(VBM) modifyvm Redox --audiocontroller hda + $(VBM) modifyvm Redox --nestedpaging on + echo "Create Disk" + $(VBM) convertfromraw $< build/harddrive.vdi + echo "Attach Disk" + $(VBM) storagectl Redox --name ATA --add sata --controller IntelAHCI --bootable on --portcount 1 + $(VBM) storageattach Redox --storagectl ATA --port 0 --device 0 --type hdd --medium build/harddrive.vdi + echo "Run VM" + $(VBM) startvm Redox diff --git a/paper/redox.tex b/paper/redox.tex deleted file mode 100644 index c458d68..0000000 --- a/paper/redox.tex +++ /dev/null @@ -1,84 +0,0 @@ -\documentclass[11pt]{article} -\usepackage[T1]{fontenc} -\usepackage{amsmath, amsfonts, amssymb, amsthm, url, lmodern, color, graphicx} - -\title{Redox and system calls -- a multi-level kernel space} -\author{Redox OS developers} -\date{\today} - -\begin{document} - \maketitle - - %%% DISCLAIMER %%% - - \begin{titlepage} - \centering \huge\bfseries The following document is an incomplete draft. - \end{titlepage} - - %%% START OF DOCUMENT %%% - - \maketitle - - \begin{abstract} - In this paper, we review Redox's core system call interface. Redox has - multiple levels of kernel space, and the top one consists of a very - minimal system call interface, which we go over here. - \end{abstract} - - \section{Introduction} - TODO - - \section{Executing system calls} - We allow multiplied system calls, a generalized version of concept of - multicalls in the \emph{kqueue} system call. - - Depending on the platform, system calls might be sent through interrupts or - \texttt{sysenter}. What we are really interested in, though, is the state - when we leave user space. - - \begin{description} - \item [\texttt{rax}/\texttt{eax}] stores the pointer to the array of system calls. - \item [\texttt{rbx}/\texttt{ebx}] stores the number of system calls in - this bundle. - \end{description} - - \section{The interface} - Each entry in this system call bundle buffer needs an ABI representation. - We represent the interface for the \emph{core system calls}. - - The representation is as follows: - - \begin{description} - \item [The system call ID] this is an unsigned 16-bit integer - representing which system call is used. - \item [First argument] this 64-bit integer is used as defined by the - system call. - \item [Second argument] this 64-bit integer is used as defined by the - system call. - \end{description} - - The return value of the system call is placed in the respective element. - - \subsection{Access management} - The memory access management is a set of system calls taken pointer and - size, respectively. - - It contains of four calls: - - \begin{description} - \item [Make memory readable]. - \item [Make memory unreadable]. - \item [Make memory writable]. - \item [Make memory unwritable]. - \item [Make memory executable]. - \item [Make memory unexecutable]. - \end{description} - - \subsection{Access management} - - %%% BIBLIOGRAPHY %%% - - \begin{thebibliography}{9} - TODO - \end{thebibliography} -\end{document} diff --git a/programs/acid b/programs/acid deleted file mode 160000 index 2b029b4..0000000 --- a/programs/acid +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2b029b432b32070b94c443dfdd064a9dc5e25ab0 diff --git a/programs/binutils b/programs/binutils deleted file mode 160000 index 5599724..0000000 --- a/programs/binutils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5599724eab8b28705f6b2b66145fdcb7e4ce2d4d diff --git a/programs/contain/Cargo.toml b/programs/contain/Cargo.toml deleted file mode 100644 index ad46eb0..0000000 --- a/programs/contain/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "contain" -version = "0.1.0" - -[dependencies] -redox_syscall = { path = "../../syscall" } diff --git a/programs/contain/src/chroot.rs b/programs/contain/src/chroot.rs deleted file mode 100644 index edce9ea..0000000 --- a/programs/contain/src/chroot.rs +++ /dev/null @@ -1,172 +0,0 @@ -use syscall; -use syscall::data::{Stat, StatVfs}; -use syscall::error::{Error, EBADF, EINVAL, EPERM, Result}; -use syscall::scheme::Scheme; - -use std::str; -use std::path::PathBuf; - -pub struct ChrootScheme { - root: PathBuf -} - -impl ChrootScheme { - pub fn new(root: PathBuf) -> ChrootScheme { - ChrootScheme { - root: root - } - } - - fn translate(&self, path: &[u8]) -> Result { - let path = str::from_utf8(path).or(Err(Error::new(EINVAL)))?; - let mut translated = self.root.clone(); - translated.push(path.trim_left_matches('/')); - if translated.starts_with(&self.root) { - translated.into_os_string().into_string().or(Err(Error::new(EINVAL))) - } else { - println!("escaped chroot"); - Err(Error::new(EPERM)) - } - } -} - -impl Scheme for ChrootScheme { - fn open(&self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result { - if uid != 0 { - syscall::setreuid(0, uid as usize)?; - } - if gid != 0 { - syscall::setregid(0, gid as usize)?; - } - let res = syscall::open(&self.translate(path)?, flags); - if uid != 0 { - syscall::setreuid(0, 0).unwrap(); - } - if gid != 0 { - syscall::setregid(0, 0).unwrap(); - } - res - } - - fn chmod(&self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result { - if uid != 0 { - syscall::setreuid(0, uid as usize)?; - } - if gid != 0 { - syscall::setregid(0, gid as usize)?; - } - let res = syscall::chmod(&self.translate(path)?, mode as usize); - if uid != 0 { - syscall::setreuid(0, 0).unwrap(); - } - if gid != 0 { - syscall::setregid(0, 0).unwrap(); - } - res - } - - fn rmdir(&self, path: &[u8], uid: u32, gid: u32) -> Result { - if uid != 0 { - syscall::setreuid(0, uid as usize)?; - } - if gid != 0 { - syscall::setregid(0, gid as usize)?; - } - let res = syscall::rmdir(&self.translate(path)?); - if uid != 0 { - syscall::setreuid(0, 0).unwrap(); - } - if gid != 0 { - syscall::setregid(0, 0).unwrap(); - } - res - } - - fn unlink(&self, path: &[u8], uid: u32, gid: u32) -> Result { - if uid != 0 { - syscall::setreuid(0, uid as usize)?; - } - if gid != 0 { - syscall::setregid(0, gid as usize)?; - } - let res = syscall::unlink(&self.translate(path)?); - if uid != 0 { - syscall::setreuid(0, 0).unwrap(); - } - if gid != 0 { - syscall::setregid(0, 0).unwrap(); - } - res - } - - /* Resource operations */ - fn dup(&self, old_id: usize, buf: &[u8]) -> Result { - syscall::dup(old_id, buf) - } - - fn read(&self, id: usize, buf: &mut [u8]) -> Result { - syscall::read(id, buf) - } - - fn write(&self, id: usize, buf: &[u8]) -> Result { - syscall::write(id, buf) - } - - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - syscall::lseek(id, pos as isize, whence) - } - - fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result { - syscall::fcntl(id, cmd, arg) - } - - fn fevent(&self, _id: usize, _flags: usize) -> Result { - //TODO - Err(Error::new(EBADF)) - } - - fn fmap(&self, _id: usize, _offset: usize, _size: usize) -> Result { - //TODO - Err(Error::new(EBADF)) - } - - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let count = syscall::fpath(id, buf)?; - - let translated = { - let path = str::from_utf8(&buf[.. count]).or(Err(Error::new(EINVAL)))?; - let translated = path.to_string().replace(self.root.to_str().ok_or(Error::new(EINVAL))?, ""); - format!("file:{}", translated.trim_left_matches('/')) - }; - - let path = translated.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } - - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - syscall::fstat(id, stat) - } - - fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result { - syscall::fstatvfs(id, stat) - } - - fn fsync(&self, id: usize) -> Result { - syscall::fsync(id) - } - - fn ftruncate(&self, id: usize, len: usize) -> Result { - syscall::ftruncate(id, len) - } - - fn close(&self, id: usize) -> Result { - syscall::close(id) - } -} diff --git a/programs/contain/src/main.rs b/programs/contain/src/main.rs deleted file mode 100644 index 2e60062..0000000 --- a/programs/contain/src/main.rs +++ /dev/null @@ -1,146 +0,0 @@ -extern crate syscall; - -use syscall::scheme::Scheme; - -use std::{env, fs,thread}; -use std::io::{stderr, Write}; -use std::os::unix::process::CommandExt; -use std::path::Path; -use std::process::{self, Command}; - -use self::chroot::ChrootScheme; - -mod chroot; - -fn usage() -> ! { - write!(stderr(), "contain [create|enter] root cmd args..\n").unwrap(); - process::exit(1); -} - -fn create(root: &Path) { - let root = Path::new(root); - - println!("{}", root.display()); - fs::create_dir(root).unwrap(); - - let mut bin = root.to_path_buf(); - bin.push("bin"); - println!("{}", bin.display()); - fs::create_dir(&bin).unwrap(); - - for entry in fs::read_dir("/bin").unwrap() { - let entry = entry.unwrap(); - let mut dest = bin.clone(); - dest.push(entry.file_name()); - println!("{} -> {}", entry.path().display(), dest.display()); - fs::copy(entry.path(), dest).unwrap(); - } - - let mut etc = root.to_path_buf(); - etc.push("etc"); - println!("{}", etc.display()); - fs::create_dir(&etc).unwrap(); - - let mut net = etc.clone(); - net.push("net"); - println!("{}", net.display()); - fs::create_dir(&net).unwrap(); - - for entry in fs::read_dir("/etc/net").unwrap() { - let entry = entry.unwrap(); - let mut dest = net.clone(); - dest.push(entry.file_name()); - println!("{} -> {}", entry.path().display(), dest.display()); - fs::copy(entry.path(), dest).unwrap(); - } -} - -fn enter(root: &Path, cmd: &str, args: &[String]) { - let names = [ - "rand", - "tcp", - "udp" - ]; - - let mut name_ptrs = Vec::new(); - for name in names.iter() { - name_ptrs.push([name.as_ptr() as usize, name.len()]); - } - - let new_ns = syscall::mkns(&name_ptrs).unwrap(); - - let root_canon = fs::canonicalize(root).unwrap(); - let root_thread = thread::spawn(move || { - syscall::setrens(-1isize as usize, new_ns).unwrap(); - let scheme_fd = syscall::open(":file", syscall::O_CREAT | syscall::O_RDWR | syscall::O_CLOEXEC).unwrap(); - syscall::setrens(-1isize as usize, syscall::getns().unwrap()).unwrap(); - - let chroot_scheme = ChrootScheme::new(root_canon); - loop { - let mut packet = syscall::Packet::default(); - if syscall::read(scheme_fd, &mut packet).unwrap() == 0 { - break; - } - chroot_scheme.handle(&mut packet); - syscall::write(scheme_fd, &packet).unwrap(); - } - - let _ = syscall::close(scheme_fd); - }); - - let pid = unsafe { syscall::clone(0).unwrap() }; - if pid == 0 { - syscall::setrens(new_ns, new_ns).unwrap(); - - println!("Container {}: enter: {}", new_ns, cmd); - - let mut command = Command::new(&cmd); - for arg in args { - command.arg(&arg); - } - command.current_dir("/"); - - let err = command.exec(); - - panic!("contain: failed to launch {}: {}", cmd, err); - } else { - let mut status = 0; - syscall::waitpid(pid, &mut status, 0).unwrap(); - - loop { - let mut c_status = 0; - let c_pid = syscall::waitpid(0, &mut c_status, syscall::WNOHANG).unwrap(); - if c_pid == 0 { - break; - } else { - println!("Container zombie {}: {:X}", c_pid, c_status); - } - } - - println!("Container {}: exit: {:X}", new_ns, status); - } -} - -pub fn main() { - let mut args = env::args().skip(1); - - if let Some(op) = args.next() { - match op.as_str() { - "create" => if let Some(root) = args.next() { - create(Path::new(&root)); - } else { - usage(); - }, - "enter" => if let Some(root) = args.next() { - let cmd = args.next().unwrap_or("sh".to_string()); - let args: Vec = args.collect(); - enter(Path::new(&root), &cmd, &args); - } else { - usage(); - }, - _ => usage() - } - } else { - usage(); - } -} diff --git a/programs/coreutils b/programs/coreutils deleted file mode 160000 index 30dae30..0000000 --- a/programs/coreutils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 30dae30ee0c4d4628f08b04db9d7f986cc975763 diff --git a/programs/extrautils b/programs/extrautils deleted file mode 160000 index 4a5ee6e..0000000 --- a/programs/extrautils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4a5ee6e845bc3dd2180b505a303da6ee1e5021d1 diff --git a/programs/games b/programs/games deleted file mode 160000 index 15374e8..0000000 --- a/programs/games +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 15374e8a8ae5db6982e7d265ad088f790e38a3b8 diff --git a/programs/init/Cargo.toml b/programs/init/Cargo.toml deleted file mode 100644 index b045ad6..0000000 --- a/programs/init/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "init" -version = "0.1.0" - -[dependencies] -redox_syscall = { path = "../../syscall" } diff --git a/programs/init/src/main.rs b/programs/init/src/main.rs deleted file mode 100644 index 1b010ce..0000000 --- a/programs/init/src/main.rs +++ /dev/null @@ -1,97 +0,0 @@ -extern crate syscall; - -use std::env; -use std::fs::File; -use std::io::{BufRead, BufReader, Result}; -use std::process::Command; - -pub fn run(file: &str) -> Result<()> { - let file = File::open(file)?; - let reader = BufReader::new(file); - - for line_result in reader.lines() { - let line = line_result?; - let line = line.trim(); - if ! line.is_empty() && ! line.starts_with('#') { - let mut args = line.split(' '); - if let Some(cmd) = args.next() { - match cmd { - "cd" => if let Some(dir) = args.next() { - if let Err(err) = env::set_current_dir(dir) { - println!("init: failed to cd to '{}': {}", dir, err); - } - } else { - println!("init: failed to cd: no argument"); - }, - "echo" => { - if let Some(arg) = args.next() { - print!("{}", arg); - } - for arg in args { - print!(" {}", arg); - } - print!("\n"); - }, - "export" => if let Some(var) = args.next() { - let mut value = String::new(); - if let Some(arg) = args.next() { - value.push_str(&arg); - } - for arg in args { - value.push(' '); - value.push_str(&arg); - } - env::set_var(var, value); - } else { - println!("init: failed to export: no argument"); - }, - "run" => if let Some(new_file) = args.next() { - if let Err(err) = run(&new_file) { - println!("init: failed to run '{}': {}", new_file, err); - } - } else { - println!("init: failed to run: no argument"); - }, - "stdio" => if let Some(stdio) = args.next() { - let _ = syscall::close(2); - let _ = syscall::close(1); - let _ = syscall::close(0); - - let _ = syscall::open(&stdio, syscall::flag::O_RDWR); - let _ = syscall::open(&stdio, syscall::flag::O_RDWR); - let _ = syscall::open(&stdio, syscall::flag::O_RDWR); - } else { - println!("init: failed to set stdio: no argument"); - }, - _ => { - let mut command = Command::new(cmd); - for arg in args { - command.arg(arg); - } - - match command.spawn() { - Ok(mut child) => match child.wait() { - Ok(_status) => (), //println!("init: waited for {}: {:?}", line, status.code()), - Err(err) => println!("init: failed to wait for '{}': {}", line, err) - }, - Err(err) => println!("init: failed to execute '{}': {}", line, err) - } - } - } - } - } - } - - Ok(()) -} - -pub fn main() { - if let Err(err) = run("initfs:etc/init.rc") { - println!("init: failed to run initfs:etc/init.rc: {}", err); - } - - loop { - let mut status = 0; - syscall::waitpid(0, &mut status, 0).unwrap(); - } -} diff --git a/programs/ion b/programs/ion deleted file mode 160000 index ffd29c8..0000000 --- a/programs/ion +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ffd29c8e5c655f047bf22f5250b422161864cdfa diff --git a/programs/netutils b/programs/netutils deleted file mode 160000 index 88a9230..0000000 --- a/programs/netutils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 88a923087a3a9cbbad0bf8faea9cb56332269c57 diff --git a/programs/orbutils b/programs/orbutils deleted file mode 160000 index 196fc91..0000000 --- a/programs/orbutils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 196fc91bb03e5cfa1bb46fb8e59a720caf995ef8 diff --git a/programs/pkgutils b/programs/pkgutils deleted file mode 160000 index a196bd3..0000000 --- a/programs/pkgutils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a196bd36ff9f95025b95f5e68c4671cc64c14b09 diff --git a/programs/smith b/programs/smith deleted file mode 160000 index 59f4a27..0000000 --- a/programs/smith +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 59f4a27981eb39292abb01220e10b1c7a0afbf5e diff --git a/programs/tar b/programs/tar deleted file mode 160000 index efb5b05..0000000 --- a/programs/tar +++ /dev/null @@ -1 +0,0 @@ -Subproject commit efb5b052480b2822a4401358c6ee6be3c33b969c diff --git a/programs/userutils b/programs/userutils deleted file mode 160000 index 901caaf..0000000 --- a/programs/userutils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 901caafce3d3d9cb9c772f4a8415e9f78a3a0da3 diff --git a/redoxfs b/redoxfs new file mode 160000 index 0000000..801cbd9 --- /dev/null +++ b/redoxfs @@ -0,0 +1 @@ +Subproject commit 801cbd9072086b97ddff8605230bab5ee2b2b6d9 diff --git a/res/fonts/DejaVuSansMono-Bold.ttf b/res/fonts/DejaVuSansMono-Bold.ttf deleted file mode 100644 index 8184ced..0000000 Binary files a/res/fonts/DejaVuSansMono-Bold.ttf and /dev/null differ diff --git a/res/fonts/DejaVuSansMono-BoldOblique.ttf b/res/fonts/DejaVuSansMono-BoldOblique.ttf deleted file mode 100644 index 754dca7..0000000 Binary files a/res/fonts/DejaVuSansMono-BoldOblique.ttf and /dev/null differ diff --git a/res/fonts/DejaVuSansMono-LICENSE b/res/fonts/DejaVuSansMono-LICENSE deleted file mode 100644 index df52c17..0000000 --- a/res/fonts/DejaVuSansMono-LICENSE +++ /dev/null @@ -1,187 +0,0 @@ -Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. -Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) - - -Bitstream Vera Fonts Copyright ------------------------------- - -Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is -a trademark of Bitstream, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of the fonts accompanying this license ("Fonts") and associated -documentation files (the "Font Software"), to reproduce and distribute the -Font Software, including without limitation the rights to use, copy, merge, -publish, distribute, and/or sell copies of the Font Software, and to permit -persons to whom the Font Software is furnished to do so, subject to the -following conditions: - -The above copyright and trademark notices and this permission notice shall -be included in all copies of one or more of the Font Software typefaces. - -The Font Software may be modified, altered, or added to, and in particular -the designs of glyphs or characters in the Fonts may be modified and -additional glyphs or characters may be added to the Fonts, only if the fonts -are renamed to names not containing either the words "Bitstream" or the word -"Vera". - -This License becomes null and void to the extent applicable to Fonts or Font -Software that has been modified and is distributed under the "Bitstream -Vera" names. - -The Font Software may be sold as part of a larger software package but no -copy of one or more of the Font Software typefaces may be sold by itself. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, -TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME -FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING -ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF -THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE -FONT SOFTWARE. - -Except as contained in this notice, the names of Gnome, the Gnome -Foundation, and Bitstream Inc., shall not be used in advertising or -otherwise to promote the sale, use or other dealings in this Font Software -without prior written authorization from the Gnome Foundation or Bitstream -Inc., respectively. For further information, contact: fonts at gnome dot -org. - -Arev Fonts Copyright ------------------------------- - -Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the fonts accompanying this license ("Fonts") and -associated documentation files (the "Font Software"), to reproduce -and distribute the modifications to the Bitstream Vera Font Software, -including without limitation the rights to use, copy, merge, publish, -distribute, and/or sell copies of the Font Software, and to permit -persons to whom the Font Software is furnished to do so, subject to -the following conditions: - -The above copyright and trademark notices and this permission notice -shall be included in all copies of one or more of the Font Software -typefaces. - -The Font Software may be modified, altered, or added to, and in -particular the designs of glyphs or characters in the Fonts may be -modified and additional glyphs or characters may be added to the -Fonts, only if the fonts are renamed to names not containing either -the words "Tavmjong Bah" or the word "Arev". - -This License becomes null and void to the extent applicable to Fonts -or Font Software that has been modified and is distributed under the -"Tavmjong Bah Arev" names. - -The Font Software may be sold as part of a larger software package but -no copy of one or more of the Font Software typefaces may be sold by -itself. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL -TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. - -Except as contained in this notice, the name of Tavmjong Bah shall not -be used in advertising or otherwise to promote the sale, use or other -dealings in this Font Software without prior written authorization -from Tavmjong Bah. For further information, contact: tavmjong @ free -. fr. - -TeX Gyre DJV Math ------------------ -Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. - -Math extensions done by B. Jackowski, P. Strzelczyk and P. Pianowski -(on behalf of TeX users groups) are in public domain. - -Letters imported from Euler Fraktur from AMSfonts are (c) American -Mathematical Society (see below). -Bitstream Vera Fonts Copyright -Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera -is a trademark of Bitstream, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of the fonts accompanying this license (“Fonts”) and associated -documentation -files (the “Font Software”), to reproduce and distribute the Font Software, -including without limitation the rights to use, copy, merge, publish, -distribute, -and/or sell copies of the Font Software, and to permit persons to whom -the Font Software is furnished to do so, subject to the following -conditions: - -The above copyright and trademark notices and this permission notice -shall be -included in all copies of one or more of the Font Software typefaces. - -The Font Software may be modified, altered, or added to, and in particular -the designs of glyphs or characters in the Fonts may be modified and -additional -glyphs or characters may be added to the Fonts, only if the fonts are -renamed -to names not containing either the words “Bitstream” or the word “Vera”. - -This License becomes null and void to the extent applicable to Fonts or -Font Software -that has been modified and is distributed under the “Bitstream Vera” -names. - -The Font Software may be sold as part of a larger software package but -no copy -of one or more of the Font Software typefaces may be sold by itself. - -THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, -TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME -FOUNDATION -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, -SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN -ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR -INABILITY TO USE -THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. -Except as contained in this notice, the names of GNOME, the GNOME -Foundation, -and Bitstream Inc., shall not be used in advertising or otherwise to promote -the sale, use or other dealings in this Font Software without prior written -authorization from the GNOME Foundation or Bitstream Inc., respectively. -For further information, contact: fonts at gnome dot org. - -AMSFonts (v. 2.2) copyright - -The PostScript Type 1 implementation of the AMSFonts produced by and -previously distributed by Blue Sky Research and Y&Y, Inc. are now freely -available for general use. This has been accomplished through the -cooperation -of a consortium of scientific publishers with Blue Sky Research and Y&Y. -Members of this consortium include: - -Elsevier Science IBM Corporation Society for Industrial and Applied -Mathematics (SIAM) Springer-Verlag American Mathematical Society (AMS) - -In order to assure the authenticity of these fonts, copyright will be -held by -the American Mathematical Society. This is not meant to restrict in any way -the legitimate use of the fonts, such as (but not limited to) electronic -distribution of documents containing these fonts, inclusion of these fonts -into other public domain or commercial font collections or computer -applications, use of the outline data to create derivative fonts and/or -faces, etc. However, the AMS does require that the AMS copyright notice be -removed from any derivative versions of the fonts which have been altered in -any way. In addition, to ensure the fidelity of TeX documents using Computer -Modern fonts, Professor Donald Knuth, creator of the Computer Modern faces, -has requested that any alterations which yield different font metrics be -given a different name. - -$Id$ diff --git a/res/fonts/DejaVuSansMono-Oblique.ttf b/res/fonts/DejaVuSansMono-Oblique.ttf deleted file mode 100644 index 4c858d4..0000000 Binary files a/res/fonts/DejaVuSansMono-Oblique.ttf and /dev/null differ diff --git a/res/fonts/DejaVuSansMono.ttf b/res/fonts/DejaVuSansMono.ttf deleted file mode 100644 index f578602..0000000 Binary files a/res/fonts/DejaVuSansMono.ttf and /dev/null differ diff --git a/res/fonts/unifont-license.txt b/res/fonts/unifont-license.txt deleted file mode 100644 index 6b540a8..0000000 --- a/res/fonts/unifont-license.txt +++ /dev/null @@ -1,371 +0,0 @@ -LICENSE -------- -The source code for everything except the compiled fonts in this current -release is licensed as follows: - - License for this current distribution of program source - files (i.e., everything except the fonts) is released under - the terms of the GNU General Public License version 2, - or (at your option) a later version. - - See the section below for a copy of the GNU General Public License - version 2. - -The license for the compiled fonts is covered by the above GPL terms -with the GNU font embedding exception, as follows: - - As a special exception, if you create a document which uses this font, - and embed this font or unaltered portions of this font into the document, - this font does not by itself cause the resulting document to be covered - by the GNU General Public License. This exception does not however - invalidate any other reasons why the document might be covered by the - GNU General Public License. If you modify this font, you may extend - this exception to your version of the font, but you are not obligated - to do so. If you do not wish to do so, delete this exception statement - from your version. - -See "http://www.gnu.org/licenses/gpl-faq.html#FontException" for more details. - - -GPL VERSION 2 -------------- - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/res/fonts/unifont.font b/res/fonts/unifont.font deleted file mode 100644 index aee9d93..0000000 Binary files a/res/fonts/unifont.font and /dev/null differ diff --git a/res/fonts/unifont.rs b/res/fonts/unifont.rs deleted file mode 100644 index 9297f33..0000000 --- a/res/fonts/unifont.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::fs::File; -use std::io::{BufRead, BufReader, Read, Write}; - -fn main() { - let mut input = File::open("unifont.hex").unwrap(); - let mut output = File::create("unifont.font").unwrap(); - let mut count = 0; - for line_res in BufReader::new(input).lines() { - let line = line_res.unwrap(); - - let mut parts = line.split(":"); - let num = u32::from_str_radix(parts.next().unwrap(), 16).unwrap(); - assert_eq!(num, count); - - let mut data = [0; 16]; - let data_part = parts.next().unwrap(); - for i in 0..data.len() { - data[i] = u8::from_str_radix(&data_part[i * 2 .. i * 2 + 2], 16).unwrap(); - } - println!("{:>04X}:{:?}", num, data); - - output.write(&data).unwrap(); - - count += 1; - } -} diff --git a/rust b/rust index 57950fa..1e60a47 160000 --- a/rust +++ b/rust @@ -1 +1 @@ -Subproject commit 57950faeb68754451f94062c11e3fcf830392025 +Subproject commit 1e60a477a3f28ec5dc6e93e2714320d829bd7942 diff --git a/rustc.sh b/rustc.sh deleted file mode 100755 index ecd5588..0000000 --- a/rustc.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -have_o=false -for arg in "$@"; do - if [[ "$arg" = "-o" ]]; then - have_o=true - break - fi -done - -args=() -for arg in "$@"; do - if [[ $have_o = true && "$arg" =~ ^extra-filename= ]]; then - unset args[${#args[@]}-1] - elif [[ $have_o = true && "$arg" =~ ^--emit= ]]; then - args+=("--emit=link") - else - args+=("$arg") - fi -done - -RUST_BACKTRACE=1 exec rustc -L build/userspace "${args[@]}" diff --git a/rustdoc.sh b/rustdoc.sh deleted file mode 100755 index f60c41b..0000000 --- a/rustdoc.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -RUST_BACKTRACE=1 rustdoc -L build/userspace $* diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index 6776cef..0000000 --- a/rustfmt.toml +++ /dev/null @@ -1,5 +0,0 @@ -max_width = 200 -ideal_width = 100 -fn_call_width = 80 -wrap_match_arms = false -write_mode = "Overwrite" diff --git a/schemes/ethernetd/Cargo.toml b/schemes/ethernetd/Cargo.toml deleted file mode 100644 index 6e10ca0..0000000 --- a/schemes/ethernetd/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "ethernetd" -version = "0.1.0" - -[dependencies] -event = { path = "../../crates/event/" } -netutils = { path = "../../programs/netutils/" } -redox_syscall = { path = "../../syscall/" } diff --git a/schemes/ethernetd/src/main.rs b/schemes/ethernetd/src/main.rs deleted file mode 100644 index 66357b6..0000000 --- a/schemes/ethernetd/src/main.rs +++ /dev/null @@ -1,94 +0,0 @@ -extern crate event; -extern crate netutils; -extern crate syscall; - -use event::EventQueue; -use std::cell::RefCell; -use std::fs::File; -use std::io::{Result, Read, Write}; -use std::os::unix::io::FromRawFd; -use std::rc::Rc; - -use syscall::{Packet, SchemeMut, EWOULDBLOCK}; - -use scheme::EthernetScheme; - -mod scheme; - -fn main() { - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let network_fd = syscall::open("network:", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ethernetd: failed to open network"); - let network = unsafe { File::from_raw_fd(network_fd) }; - - let socket_fd = syscall::open(":ethernet", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ethernetd: failed to create ethernet scheme"); - let socket = Rc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); - - let scheme = Rc::new(RefCell::new(EthernetScheme::new(network))); - - let todo = Rc::new(RefCell::new(Vec::::new())); - - let mut event_queue = EventQueue::<()>::new().expect("ethernetd: failed to create event queue"); - - let socket_net = socket.clone(); - let scheme_net = scheme.clone(); - let todo_net = todo.clone(); - event_queue.add(network_fd, move |_count: usize| -> Result> { - if scheme_net.borrow_mut().input()? > 0 { - let mut todo = todo_net.borrow_mut(); - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - scheme_net.borrow_mut().handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_net.borrow_mut().write(&mut todo[i])?; - todo.remove(i); - } - } - - for (id, handle) in scheme_net.borrow_mut().handles.iter() { - if let Some(frame) = handle.frames.get(0) { - socket_net.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: syscall::flag::EVENT_READ, - d: frame.data.len() - })?; - } - } - } - Ok(None) - }).expect("ethernetd: failed to listen for network events"); - - event_queue.add(socket_fd, move |_count: usize| -> Result> { - loop { - let mut packet = Packet::default(); - if socket.borrow_mut().read(&mut packet)? == 0 { - break; - } - - let a = packet.a; - scheme.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket.borrow_mut().write(&mut packet)?; - } - } - - Ok(None) - }).expect("ethernetd: failed to listen for scheme events"); - - event_queue.trigger_all(0).expect("ethernetd: failed to trigger events"); - - event_queue.run().expect("ethernetd: failed to run event loop"); - } -} diff --git a/schemes/ethernetd/src/scheme.rs b/schemes/ethernetd/src/scheme.rs deleted file mode 100644 index 7b1b3bd..0000000 --- a/schemes/ethernetd/src/scheme.rs +++ /dev/null @@ -1,164 +0,0 @@ -use std::collections::{BTreeMap, VecDeque}; -use std::fs::File; -use std::io::{self, Read, Write}; -use std::os::unix::io::AsRawFd; -use std::{cmp, str, u16}; - -use netutils::{getcfg, MacAddr, EthernetII}; -use syscall; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EWOULDBLOCK}; -use syscall::flag::O_NONBLOCK; -use syscall::scheme::SchemeMut; - -#[derive(Clone)] -pub struct Handle { - /// The flags this handle was opened with - flags: usize, - /// The Host's MAC address - pub host_addr: MacAddr, - /// The ethernet type - pub ethertype: u16, - /// The data - pub frames: VecDeque, -} - -pub struct EthernetScheme { - network: File, - next_id: usize, - pub handles: BTreeMap -} - -impl EthernetScheme { - pub fn new(network: File) -> EthernetScheme { - EthernetScheme { - network: network, - next_id: 1, - handles: BTreeMap::new(), - } - } - - //TODO: Minimize allocation - //TODO: Reduce iteration cost (use BTreeMap of ethertype to handle?) - pub fn input(&mut self) -> io::Result { - let mut total = 0; - loop { - let mut bytes = [0; 65536]; - let count = self.network.read(&mut bytes)?; - if count == 0 { - break; - } - if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) { - for (_id, handle) in self.handles.iter_mut() { - if frame.header.ethertype.get() == handle.ethertype { - handle.frames.push_back(frame.clone()); - } - } - total += count; - } - } - Ok(total) - } -} - -impl SchemeMut for EthernetScheme { - fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - if uid == 0 { - let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?); - let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL)))); - - let ethertype = u16::from_str_radix(path, 16).unwrap_or(0); - - let next_id = self.next_id; - self.next_id += 1; - - self.handles.insert(next_id, Handle { - flags: flags, - host_addr: mac_addr, - ethertype: ethertype, - frames: VecDeque::new() - }); - - Ok(next_id) - } else { - Err(Error::new(EACCES)) - } - } - - fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { - let next_id = self.next_id; - self.next_id += 1; - - let handle = { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - handle.clone() - }; - - self.handles.insert(next_id, handle); - - Ok(next_id) - } - - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { - let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - if let Some(frame) = handle.frames.pop_front() { - let data = frame.to_bytes(); - for (b, d) in buf.iter_mut().zip(data.iter()) { - *b = *d; - } - - Ok(cmp::min(buf.len(), data.len())) - } else if handle.flags & O_NONBLOCK == O_NONBLOCK { - Ok(0) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } - - fn write(&mut self, id: usize, buf: &[u8]) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - if let Some(mut frame) = EthernetII::from_bytes(buf) { - frame.header.src = handle.host_addr; - frame.header.ethertype.set(handle.ethertype); - self.network.write(&frame.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))) - } else { - Err(Error::new(EINVAL)) - } - } - - fn fevent(&mut self, id: usize, _flags: usize) -> Result { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - Ok(id) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let path_string = format!("ethernet:{:X}", handle.ethertype); - let path = path_string.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } - - fn fsync(&mut self, id: usize) -> Result { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - syscall::fsync(self.network.as_raw_fd()) - } - - fn close(&mut self, id: usize) -> Result { - let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?; - - drop(handle); - - Ok(0) - } -} diff --git a/schemes/example/Cargo.toml b/schemes/example/Cargo.toml deleted file mode 100644 index dcd504b..0000000 --- a/schemes/example/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "example" -version = "0.1.0" - -[dependencies] -redox_syscall = { path = "../../syscall/" } diff --git a/schemes/example/src/main.rs b/schemes/example/src/main.rs deleted file mode 100644 index 1ba8d59..0000000 --- a/schemes/example/src/main.rs +++ /dev/null @@ -1,39 +0,0 @@ -extern crate syscall; - -use std::fs::File; -use std::io::{Read, Write}; -use std::str; - -use syscall::{Packet, Result, Scheme}; - -struct ExampleScheme; - -impl Scheme for ExampleScheme { - fn open(&self, path: &[u8], _flags: usize, uid: u32, gid: u32) -> Result { - println!("{} from {}:{}", unsafe { str::from_utf8_unchecked(path) }, uid, gid); - Ok(0) - } - - fn dup(&self, file: usize, _buf: &[u8]) -> Result { - Ok(file) - } - - fn close(&self, _file: usize) -> Result { - Ok(0) - } -} - -fn main(){ - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let mut socket = File::create(":example").expect("example: failed to create example scheme"); - let scheme = ExampleScheme; - loop { - let mut packet = Packet::default(); - socket.read(&mut packet).expect("example: failed to read events from example scheme"); - println!("{:?}", packet); - scheme.handle(&mut packet); - socket.write(&packet).expect("example: failed to write responses to example scheme"); - } - } -} diff --git a/schemes/ipd/Cargo.toml b/schemes/ipd/Cargo.toml deleted file mode 100644 index 23d2f3d..0000000 --- a/schemes/ipd/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "ipd" -version = "0.1.0" - -[dependencies] -event = { path = "../../crates/event/" } -netutils = { path = "../../programs/netutils/" } -redox_syscall = { path = "../../syscall/" } diff --git a/schemes/ipd/src/interface/ethernet.rs b/schemes/ipd/src/interface/ethernet.rs deleted file mode 100644 index d914a78..0000000 --- a/schemes/ipd/src/interface/ethernet.rs +++ /dev/null @@ -1,155 +0,0 @@ -use netutils::{getcfg, n16, Ipv4Addr, MacAddr, Ipv4, EthernetII, EthernetIIHeader, Arp}; -use std::collections::BTreeMap; -use std::fs::File; -use std::io::{Result, Read, Write}; -use std::os::unix::io::FromRawFd; - -use interface::Interface; - -pub struct EthernetInterface { - mac: MacAddr, - ip: Ipv4Addr, - router: Ipv4Addr, - subnet: Ipv4Addr, - arp_file: File, - ip_file: File, - arp: BTreeMap, - rarp: BTreeMap, -} - -impl EthernetInterface { - pub fn new(arp_fd: usize, ip_fd: usize) -> Self { - EthernetInterface { - mac: MacAddr::from_str(&getcfg("mac").unwrap()), - ip: Ipv4Addr::from_str(&getcfg("ip").unwrap()), - router: Ipv4Addr::from_str(&getcfg("ip_router").unwrap()), - subnet: Ipv4Addr::from_str(&getcfg("ip_subnet").unwrap()), - arp_file: unsafe { File::from_raw_fd(arp_fd) }, - ip_file: unsafe { File::from_raw_fd(ip_fd) }, - arp: BTreeMap::new(), - rarp: BTreeMap::new(), - } - } -} - -impl Interface for EthernetInterface { - fn ip(&self) -> Ipv4Addr { - self.ip - } - - fn routable(&self, dst: Ipv4Addr) -> bool { - dst != Ipv4Addr::LOOPBACK - } - - fn arp_event(&mut self) -> Result<()> { - loop { - let mut bytes = [0; 65536]; - let count = self.arp_file.read(&mut bytes)?; - if count == 0 { - break; - } - if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) { - if let Some(packet) = Arp::from_bytes(&frame.data) { - if packet.header.oper.get() == 1 { - if packet.header.dst_ip == self.ip { - if packet.header.src_ip != Ipv4Addr::BROADCAST && frame.header.src != MacAddr::BROADCAST { - self.arp.insert(packet.header.src_ip, frame.header.src); - self.rarp.insert(frame.header.src, packet.header.src_ip); - } - - let mut response = Arp { - header: packet.header, - data: packet.data.clone(), - }; - response.header.oper.set(2); - response.header.dst_mac = packet.header.src_mac; - response.header.dst_ip = packet.header.src_ip; - response.header.src_mac = self.mac; - response.header.src_ip = self.ip; - - let mut response_frame = EthernetII { - header: frame.header, - data: response.to_bytes() - }; - - response_frame.header.dst = response_frame.header.src; - response_frame.header.src = self.mac; - - self.arp_file.write(&response_frame.to_bytes())?; - } - } - } - } - } - - Ok(()) - } - - fn recv(&mut self) -> Result> { - let mut ips = Vec::new(); - - loop { - let mut bytes = [0; 65536]; - let count = self.ip_file.read(&mut bytes)?; - if count == 0 { - break; - } - if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) { - if let Some(ip) = Ipv4::from_bytes(&frame.data) { - if ip.header.dst == self.ip || ip.header.dst == Ipv4Addr::BROADCAST { - //TODO: Handle ping here - - if ip.header.src != Ipv4Addr::BROADCAST && frame.header.src != MacAddr::BROADCAST { - self.arp.insert(ip.header.src, frame.header.src); - self.rarp.insert(frame.header.src, ip.header.src); - } - - ips.push(ip); - } - } - } - } - - Ok(ips) - } - - fn send(&mut self, ip: Ipv4) -> Result { - let mut dst = MacAddr::BROADCAST; - if ip.header.dst != Ipv4Addr::BROADCAST { - let mut needs_routing = false; - - for octet in 0..4 { - let me = self.ip.bytes[octet]; - let mask = self.subnet.bytes[octet]; - let them = ip.header.dst.bytes[octet]; - if me & mask != them & mask { - needs_routing = true; - break; - } - } - - let route_addr = if needs_routing { - self.router - } else { - ip.header.dst - }; - - if let Some(mac) = self.arp.get(&route_addr) { - dst = *mac; - } else { - println!("ipd: need to arp {}", route_addr.to_string()); - } - } - - let frame = EthernetII { - header: EthernetIIHeader { - dst: dst, - src: self.mac, - ethertype: n16::new(0x800), - }, - data: ip.to_bytes() - }; - - self.ip_file.write(&frame.to_bytes()) - } -} diff --git a/schemes/ipd/src/interface/loopback.rs b/schemes/ipd/src/interface/loopback.rs deleted file mode 100644 index a957ef8..0000000 --- a/schemes/ipd/src/interface/loopback.rs +++ /dev/null @@ -1,50 +0,0 @@ -use netutils::{Ipv4Addr, Ipv4}; -use std::io::Result; - -use interface::Interface; - -pub struct LoopbackInterface { - packets: Vec -} - -impl LoopbackInterface { - pub fn new() -> Self { - LoopbackInterface { - packets: Vec::new() - } - } -} - -impl Interface for LoopbackInterface { - fn ip(&self) -> Ipv4Addr { - Ipv4Addr::LOOPBACK - } - - fn routable(&self, dst: Ipv4Addr) -> bool { - dst == Ipv4Addr::LOOPBACK - } - - fn recv(&mut self) -> Result> { - let mut ips = Vec::new(); - - for ip in self.packets.drain(..) { - ips.push(ip); - } - - Ok(ips) - } - - fn send(&mut self, ip: Ipv4) -> Result { - self.packets.push(ip); - - Ok(0) - } - - fn arp_event(&mut self) -> Result<()> { - Ok(()) - } - - fn has_loopback_data(&self) -> bool { - ! self.packets.is_empty() - } -} diff --git a/schemes/ipd/src/interface/mod.rs b/schemes/ipd/src/interface/mod.rs deleted file mode 100644 index 2fa89d9..0000000 --- a/schemes/ipd/src/interface/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -use netutils::{Ipv4, Ipv4Addr}; -use std::io::Result; - -pub use self::ethernet::EthernetInterface; -pub use self::loopback::LoopbackInterface; - -mod ethernet; -mod loopback; - -pub trait Interface { - fn ip(&self) -> Ipv4Addr; - fn routable(&self, dst: Ipv4Addr) -> bool; - fn recv(&mut self) -> Result>; - fn send(&mut self, ip: Ipv4) -> Result; - - fn arp_event(&mut self) -> Result<()>; - - fn has_loopback_data(&self) -> bool { false } -} diff --git a/schemes/ipd/src/main.rs b/schemes/ipd/src/main.rs deleted file mode 100644 index 52ae0cb..0000000 --- a/schemes/ipd/src/main.rs +++ /dev/null @@ -1,318 +0,0 @@ -extern crate event; -extern crate netutils; -extern crate syscall; - -use event::EventQueue; -use netutils::{Ipv4Addr, Ipv4, Tcp}; -use std::cell::RefCell; -use std::collections::{BTreeMap, VecDeque}; -use std::fs::File; -use std::io::{self, Read, Write}; -use std::os::unix::io::FromRawFd; -use std::rc::Rc; -use std::{slice, str}; -use syscall::data::Packet; -use syscall::error::{Error, Result, EACCES, EADDRNOTAVAIL, EBADF, EIO, EINVAL, ENOENT, EWOULDBLOCK}; -use syscall::flag::{EVENT_READ, O_NONBLOCK}; -use syscall::scheme::SchemeMut; - -use interface::{Interface, EthernetInterface, LoopbackInterface}; - -mod interface; - -struct Handle { - proto: u8, - flags: usize, - events: usize, - data: VecDeque>, - todo: VecDeque, -} - -struct Ipd { - scheme_file: File, - interfaces: Vec>, - next_id: usize, - handles: BTreeMap, -} - -impl Ipd { - fn new(scheme_file: File) -> Self { - Ipd { - scheme_file: scheme_file, - interfaces: Vec::new(), - next_id: 1, - handles: BTreeMap::new(), - } - } - - fn scheme_event(&mut self) -> io::Result<()> { - loop { - let mut packet = Packet::default(); - if self.scheme_file.read(&mut packet)? == 0 { - break; - } - - let a = packet.a; - self.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - if let Some(mut handle) = self.handles.get_mut(&packet.b) { - handle.todo.push_back(packet); - } - } else { - self.scheme_file.write(&packet)?; - } - } - - Ok(()) - } - - fn ip_event(&mut self, if_id: usize) -> io::Result<()> { - if let Some(mut interface) = self.interfaces.get_mut(if_id) { - for ip in interface.recv()? { - for (id, handle) in self.handles.iter_mut() { - if ip.header.proto == handle.proto { - handle.data.push_back(ip.to_bytes()); - - while ! handle.todo.is_empty() && ! handle.data.is_empty() { - let mut packet = handle.todo.pop_front().unwrap(); - let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }; - let data = handle.data.pop_front().unwrap(); - - let mut i = 0; - while i < buf.len() && i < data.len() { - buf[i] = data[i]; - i += 1; - } - packet.a = i; - - self.scheme_file.write(&packet)?; - } - - if handle.events & EVENT_READ == EVENT_READ { - if let Some(data) = handle.data.get(0) { - self.scheme_file.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: EVENT_READ, - d: data.len() - })?; - } - } - } - } - } - } - - Ok(()) - } - - fn loopback_event(&mut self, loopback_id: usize) -> io::Result<()> { - let handle_loopback = if let Some(interface) = self.interfaces.get(loopback_id) { - interface.has_loopback_data() - } else { - false - }; - - if handle_loopback { - self.ip_event(loopback_id)?; - } - - Ok(()) - } -} - -impl SchemeMut for Ipd { - fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - if uid == 0 { - let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?; - - let proto = u8::from_str_radix(path, 16).or(Err(Error::new(ENOENT)))?; - - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, Handle { - proto: proto, - flags: flags, - events: 0, - data: VecDeque::new(), - todo: VecDeque::new(), - }); - - Ok(id) - } else { - Err(Error::new(EACCES)) - } - } - - fn dup(&mut self, file: usize, _buf: &[u8]) -> Result { - let handle = { - let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; - Handle { - proto: handle.proto, - flags: handle.flags, - events: 0, - data: handle.data.clone(), - todo: VecDeque::new(), - } - }; - - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, handle); - - Ok(id) - } - - fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - if let Some(data) = handle.data.pop_front() { - let mut i = 0; - while i < buf.len() && i < data.len() { - buf[i] = data[i]; - i += 1; - } - - Ok(i) - } else if handle.flags & O_NONBLOCK == O_NONBLOCK { - Ok(0) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } - - fn write(&mut self, file: usize, buf: &[u8]) -> Result { - let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; - - if let Some(mut ip) = Ipv4::from_bytes(buf) { - for mut interface in self.interfaces.iter_mut() { - let if_ip = interface.ip(); - if ip.header.src == if_ip || (ip.header.src == Ipv4Addr::NULL && interface.routable(ip.header.dst)) { - ip.header.src = if_ip; - ip.header.proto = handle.proto; - - if let Some(mut tcp) = Tcp::from_bytes(&ip.data) { - tcp.checksum(&ip.header.src, &ip.header.dst); - ip.data = tcp.to_bytes(); - } - - ip.checksum(); - - interface.send(ip).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; - - return Ok(buf.len()); - } - } - - Err(Error::new(EADDRNOTAVAIL)) - } else { - Err(Error::new(EINVAL)) - } - } - - fn fevent(&mut self, file: usize, flags: usize) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - handle.events = flags; - - Ok(file) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let path_string = format!("ip:{:X}", handle.proto); - let path = path_string.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } - - fn fsync(&mut self, file: usize) -> Result { - let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; - - Ok(0) - } - - fn close(&mut self, file: usize) -> Result { - let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?; - - drop(handle); - - Ok(0) - } -} - -fn main() { - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let scheme_fd = syscall::open(":ip", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ipd: failed to create :ip"); - let scheme_file = unsafe { File::from_raw_fd(scheme_fd) }; - - let ipd = Rc::new(RefCell::new(Ipd::new(scheme_file))); - - let mut event_queue = EventQueue::<()>::new().expect("ipd: failed to create event queue"); - - //TODO: Multiple interfaces - { - let arp_fd = syscall::open("ethernet:806", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ipd: failed to open ethernet:806"); - let ip_fd = syscall::open("ethernet:800", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ipd: failed to open ethernet:800"); - let if_id = { - let mut ipd = ipd.borrow_mut(); - let if_id = ipd.interfaces.len(); - ipd.interfaces.push(Box::new(EthernetInterface::new(arp_fd, ip_fd))); - if_id - }; - - let arp_ipd = ipd.clone(); - event_queue.add(arp_fd, move |_count: usize| -> io::Result> { - if let Some(mut interface) = arp_ipd.borrow_mut().interfaces.get_mut(if_id) { - interface.arp_event()?; - } - - Ok(None) - }).expect("ipd: failed to listen to events on ethernet:806"); - - let ip_ipd = ipd.clone(); - event_queue.add(ip_fd, move |_count: usize| -> io::Result> { - ip_ipd.borrow_mut().ip_event(if_id)?; - - Ok(None) - }).expect("ipd: failed to listen to events on ethernet:800"); - } - - let loopback_id = { - let mut ipd = ipd.borrow_mut(); - let if_id = ipd.interfaces.len(); - ipd.interfaces.push(Box::new(LoopbackInterface::new())); - if_id - }; - - event_queue.add(scheme_fd, move |_count: usize| -> io::Result> { - let mut ipd = ipd.borrow_mut(); - - ipd.loopback_event(loopback_id)?; - ipd.scheme_event()?; - ipd.loopback_event(loopback_id)?; - - Ok(None) - }).expect("ipd: failed to listen to events on :ip"); - - // Make sure that all descriptors are at EOF - event_queue.trigger_all(0).expect("ipd: failed to trigger event queue"); - - event_queue.run().expect("ipd: failed to run event queue"); - } -} diff --git a/schemes/orbital b/schemes/orbital deleted file mode 160000 index 3dd11a7..0000000 --- a/schemes/orbital +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3dd11a7cfa8282204ad55356c39d04278267fceb diff --git a/schemes/ptyd/Cargo.toml b/schemes/ptyd/Cargo.toml deleted file mode 100644 index c8001df..0000000 --- a/schemes/ptyd/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "ptyd" -version = "0.1.0" - -[dependencies] -redox_syscall = { path = "../../syscall/" } diff --git a/schemes/ptyd/src/main.rs b/schemes/ptyd/src/main.rs deleted file mode 100644 index 28f058d..0000000 --- a/schemes/ptyd/src/main.rs +++ /dev/null @@ -1,380 +0,0 @@ -#![feature(rc_counts)] - -extern crate syscall; - -use std::cell::RefCell; -use std::collections::{BTreeMap, VecDeque}; -use std::fs::File; -use std::io::{Read, Write}; -use std::rc::{Rc, Weak}; -use std::str; - -use syscall::data::Packet; -use syscall::error::{Error, Result, EBADF, EINVAL, ENOENT, EPIPE, EWOULDBLOCK}; -use syscall::flag::O_NONBLOCK; -use syscall::scheme::SchemeMut; - -pub struct PtyScheme { - next_id: usize, - ptys: (BTreeMap, BTreeMap) -} - -impl PtyScheme { - fn new() -> Self { - PtyScheme { - next_id: 0, - ptys: (BTreeMap::new(), BTreeMap::new()) - } - } -} - -impl SchemeMut for PtyScheme { - fn open(&mut self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { - let path = str::from_utf8(path).or(Err(Error::new(EINVAL)))?.trim_matches('/'); - - if path.is_empty() { - let id = self.next_id; - self.next_id += 1; - - self.ptys.0.insert(id, PtyMaster::new(id, flags)); - - Ok(id) - } else { - let master_id = path.parse::().or(Err(Error::new(EINVAL)))?; - let master = self.ptys.0.get(&master_id).map(|pipe| pipe.clone()).ok_or(Error::new(ENOENT))?; - - let id = self.next_id; - self.next_id += 1; - - self.ptys.1.insert(id, PtySlave::new(&master, flags)); - - Ok(id) - } - } - - fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { - /* TODO CLOEXEC - Master cannot be cloned - let master_opt = self.ptys.0.get(&id).map(|pipe| pipe.clone()); - if let Some(pipe) = master_opt { - let pipe_id = self.next_id; - self.next_id += 1; - self.ptys.0.insert(pipe_id, pipe); - return Ok(pipe_id); - } - */ - - let slave_opt = self.ptys.1.get(&id).map(|pipe| pipe.clone()); - if let Some(pipe) = slave_opt { - let pipe_id = self.next_id; - self.next_id += 1; - self.ptys.1.insert(pipe_id, pipe); - return Ok(pipe_id); - } - - Err(Error::new(EBADF)) - } - - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { - let master_opt = self.ptys.0.get(&id).map(|pipe| pipe.clone()); - if let Some(pipe) = master_opt { - return pipe.read(buf); - } - - let slave_opt = self.ptys.1.get(&id).map(|pipe| pipe.clone()); - if let Some(pipe) = slave_opt { - return pipe.read(buf); - } - - Err(Error::new(EBADF)) - } - - fn write(&mut self, id: usize, buf: &[u8]) -> Result { - let master_opt = self.ptys.0.get(&id).map(|pipe| pipe.clone()); - if let Some(pipe) = master_opt { - return pipe.write(buf); - } - - let slave_opt = self.ptys.1.get(&id).map(|pipe| pipe.clone()); - if let Some(pipe) = slave_opt { - return pipe.write(buf); - } - - Err(Error::new(EBADF)) - } - - fn fevent(&mut self, id: usize, _flags: usize) -> Result { - if self.ptys.0.contains_key(&id) || self.ptys.1.contains_key(&id) { - Ok(id) - } else { - Err(Error::new(EBADF)) - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let master_opt = self.ptys.0.get(&id).map(|pipe| pipe.clone()); - if let Some(pipe) = master_opt { - return pipe.path(buf); - } - - let slave_opt = self.ptys.1.get(&id).map(|pipe| pipe.clone()); - if let Some(pipe) = slave_opt { - return pipe.path(buf); - } - - Err(Error::new(EBADF)) - } - - fn fsync(&mut self, id: usize) -> Result { - let slave_opt = self.ptys.1.get(&id).map(|pipe| pipe.clone()); - if let Some(pipe) = slave_opt { - return pipe.sync(); - } - - Ok(0) - } - - fn close(&mut self, id: usize) -> Result { - drop(self.ptys.0.remove(&id)); - drop(self.ptys.1.remove(&id)); - - Ok(0) - } -} - -/// Read side of a pipe -#[derive(Clone)] -pub struct PtyMaster { - id: usize, - flags: usize, - read: Rc>>>, - write: Rc>>, -} - -impl PtyMaster { - pub fn new(id: usize, flags: usize) -> Self { - PtyMaster { - id: id, - flags: flags, - read: Rc::new(RefCell::new(VecDeque::new())), - write: Rc::new(RefCell::new(VecDeque::new())), - } - } - - fn path(&self, buf: &mut [u8]) -> Result { - let path_str = format!("pty:{}", self.id); - let path = path_str.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } - - fn read(&self, buf: &mut [u8]) -> Result { - let mut read = self.read.borrow_mut(); - - if let Some(packet) = read.pop_front() { - let mut i = 0; - - while i < buf.len() && i < packet.len() { - buf[i] = packet[i]; - i += 1; - } - - Ok(i) - } else if self.flags & O_NONBLOCK == O_NONBLOCK || Rc::weak_count(&self.read) == 0 { - Ok(0) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } - - fn write(&self, buf: &[u8]) -> Result { - let mut write = self.write.borrow_mut(); - - let mut i = 0; - while i < buf.len() { - write.push_back(buf[i]); - i += 1; - } - - Ok(i) - } -} - -/// Read side of a pipe -#[derive(Clone)] -pub struct PtySlave { - master_id: usize, - flags: usize, - read: Weak>>, - write: Weak>>>, -} - -impl PtySlave { - pub fn new(master: &PtyMaster, flags: usize) -> Self { - PtySlave { - master_id: master.id, - flags: flags, - read: Rc::downgrade(&master.write), - write: Rc::downgrade(&master.read), - } - } - - fn path(&self, buf: &mut [u8]) -> Result { - let path_str = format!("pty:{}", self.master_id); - let path = path_str.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } - - fn read(&self, buf: &mut [u8]) -> Result { - if let Some(read_lock) = self.read.upgrade() { - let mut read = read_lock.borrow_mut(); - - let mut i = 0; - - while i < buf.len() && ! read.is_empty() { - buf[i] = read.pop_front().unwrap(); - i += 1; - } - - if i > 0 || self.flags & O_NONBLOCK == O_NONBLOCK { - Ok(i) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } else { - Ok(0) - } - } - - fn write(&self, buf: &[u8]) -> Result { - if let Some(write_lock) = self.write.upgrade() { - let mut vec = Vec::new(); - vec.push(0); - vec.extend_from_slice(buf); - - let mut write = write_lock.borrow_mut(); - write.push_back(vec); - - Ok(buf.len()) - } else { - Err(Error::new(EPIPE)) - } - } - - fn sync(&self) -> Result { - if let Some(write_lock) = self.write.upgrade() { - let mut vec = Vec::new(); - vec.push(1); - - let mut write = write_lock.borrow_mut(); - write.push_back(vec); - - Ok(0) - } else { - Err(Error::new(EPIPE)) - } - } -} - -fn main(){ - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let mut socket = File::create(":pty").expect("pty: failed to create pty scheme"); - let mut scheme = PtyScheme::new(); - let mut todo = Vec::new(); - loop { - let mut packet = Packet::default(); - socket.read(&mut packet).expect("pty: failed to read events from pty scheme"); - - let a = packet.a; - scheme.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.push(packet); - } else { - socket.write(&packet).expect("pty: failed to write responses to pty scheme"); - } - - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - scheme.handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - let packet = todo.remove(i); - socket.write(&packet).expect("pty: failed to write responses to pty scheme"); - } - } - - for (id, master) in scheme.ptys.0.iter() { - let read = master.read.borrow(); - if let Some(data) = read.front() { - socket.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: syscall::flag::EVENT_READ, - d: data.len() - }).expect("pty: failed to write event"); - } else if Rc::weak_count(&master.read) == 0 { - socket.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: syscall::flag::EVENT_READ, - d: 0 - }).expect("pty: failed to write event"); - } - } - - for (id, slave) in scheme.ptys.1.iter() { - if let Some(read_lock) = slave.read.upgrade() { - let read = read_lock.borrow(); - if ! read.is_empty() { - socket.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: syscall::flag::EVENT_READ, - d: read.len() - }).expect("pty: failed to write event"); - } - } else { - socket.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: syscall::flag::EVENT_READ, - d: 0 - }).expect("pty: failed to write event"); - } - } - } - } -} diff --git a/schemes/randd/Cargo.toml b/schemes/randd/Cargo.toml deleted file mode 100644 index 5ecdeff..0000000 --- a/schemes/randd/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "randd" -version = "0.1.0" - -[dependencies] -raw-cpuid = "2.*" -redox_syscall = { path = "../../syscall/" } diff --git a/schemes/randd/src/main.rs b/schemes/randd/src/main.rs deleted file mode 100644 index 116c664..0000000 --- a/schemes/randd/src/main.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![feature(asm)] -#![feature(rand)] - -extern crate syscall; -extern crate raw_cpuid; -extern crate rand; - -use std::fs::File; -use std::io::{Read, Write}; - -use rand::chacha::ChaChaRng; -use rand::Rng; - -use raw_cpuid::CpuId; - -use syscall::{Packet, Result, SchemeMut}; - -//TODO: Use a CSPRNG, allow write of entropy -struct RandScheme { - prng: ChaChaRng -} - -impl SchemeMut for RandScheme { - fn open(&mut self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - Ok(0) - } - - fn dup(&mut self, file: usize, _buf: &[u8]) -> Result { - Ok(file) - } - - fn read(&mut self, _file: usize, buf: &mut [u8]) -> Result { - let mut i = 0; - for chunk in buf.chunks_mut(8) { - let mut rand = self.prng.next_u64(); - for b in chunk.iter_mut() { - *b = rand as u8; - rand = rand >> 8; - i += 1; - } - } - Ok(i) - } - - fn close(&mut self, _file: usize) -> Result { - Ok(0) - } -} - -fn main(){ - let has_rdrand = CpuId::new().get_feature_info().unwrap().has_rdrand(); - - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let mut socket = File::create(":rand").expect("rand: failed to create rand scheme"); - - let mut rng = ChaChaRng::new_unseeded(); - - if has_rdrand { - println!("rand: seeding with rdrand"); - let rand: u64; - unsafe { - asm!("rdrand rax" - : "={rax}"(rand) - : - : - : "intel", "volatile"); - } - rng.set_counter(0, rand); - } else { - println!("rand: unseeded"); - } - - let mut scheme = RandScheme{prng: rng}; - loop { - let mut packet = Packet::default(); - socket.read(&mut packet).expect("rand: failed to read events from rand scheme"); - scheme.handle(&mut packet); - socket.write(&packet).expect("rand: failed to write responses to rand scheme"); - } - } -} diff --git a/schemes/redoxfs b/schemes/redoxfs deleted file mode 160000 index 5ab8c05..0000000 --- a/schemes/redoxfs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5ab8c050d86d73bc8d6b57f6a4a5ac2435fb5876 diff --git a/schemes/tcpd/Cargo.toml b/schemes/tcpd/Cargo.toml deleted file mode 100644 index a9c4202..0000000 --- a/schemes/tcpd/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "tcpd" -version = "0.1.0" - -[dependencies] -event = { path = "../../crates/event/" } -netutils = { path = "../../programs/netutils/" } -rand = { git = "https://github.com/rust-lang-nursery/rand.git" } -redox_syscall = { path = "../../syscall/" } diff --git a/schemes/tcpd/src/main.rs b/schemes/tcpd/src/main.rs deleted file mode 100644 index 64661ce..0000000 --- a/schemes/tcpd/src/main.rs +++ /dev/null @@ -1,695 +0,0 @@ -extern crate event; -extern crate netutils; -extern crate rand; -extern crate syscall; - -use rand::{Rng, OsRng}; -use std::collections::{BTreeMap, VecDeque}; -use std::cell::RefCell; -use std::fs::File; -use std::io::{self, Read, Write}; -use std::{mem, slice, str}; -use std::os::unix::io::FromRawFd; -use std::rc::Rc; - -use event::EventQueue; -use netutils::{n16, n32, Ipv4, Ipv4Addr, Ipv4Header, Tcp, TcpHeader, Checksum, TCP_FIN, TCP_SYN, TCP_RST, TCP_PSH, TCP_ACK}; -use syscall::data::Packet; -use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EIO, EINVAL, EISCONN, EMSGSIZE, ENOTCONN, EWOULDBLOCK}; -use syscall::flag::{EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_CREAT, O_RDWR, O_NONBLOCK}; -use syscall::scheme::SchemeMut; - -fn parse_socket(socket: &str) -> (Ipv4Addr, u16) { - let mut socket_parts = socket.split(":"); - let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or("")); - let port = socket_parts.next().unwrap_or("").parse::().unwrap_or(0); - (host, port) -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum State { - Listen, - SynSent, - SynReceived, - Established, - FinWait1, - FinWait2, - CloseWait, - Closing, - LastAck, - TimeWait, - Closed -} - -struct Handle { - local: (Ipv4Addr, u16), - remote: (Ipv4Addr, u16), - flags: usize, - events: usize, - state: State, - seq: u32, - ack: u32, - data: VecDeque<(Ipv4, Tcp)>, - todo_dup: VecDeque, - todo_read: VecDeque, - todo_write: VecDeque, -} - -impl Handle { - fn is_connected(&self) -> bool { - self.remote.0 != Ipv4Addr::NULL && self.remote.1 != 0 - } - - fn read_closed(&self) -> bool { - self.state == State::CloseWait || self.state == State::LastAck || self.state == State::TimeWait || self.state == State::Closed - } - - fn matches(&self, ip: &Ipv4, tcp: &Tcp) -> bool { - // Local address not set or IP dst matches or is broadcast - (self.local.0 == Ipv4Addr::NULL || ip.header.dst == self.local.0 || ip.header.dst == Ipv4Addr::BROADCAST) - // Local port matches UDP dst - && tcp.header.dst.get() == self.local.1 - // Remote address not set or is broadcast, or IP src matches - && (self.remote.0 == Ipv4Addr::NULL || self.remote.0 == Ipv4Addr::BROADCAST || ip.header.src == self.remote.0) - // Remote port not set or UDP src matches - && (self.remote.1 == 0 || tcp.header.src.get() == self.remote.1) - } - - fn create_tcp(&self, flags: u16, data: Vec) -> Tcp { - Tcp { - header: TcpHeader { - src: n16::new(self.local.1), - dst: n16::new(self.remote.1), - sequence: n32::new(self.seq), - ack_num: n32::new(self.ack), - flags: n16::new(((mem::size_of::() << 10) & 0xF000) as u16 | (flags & 0xFFF)), - window_size: n16::new(8192), - checksum: Checksum { data: 0 }, - urgent_pointer: n16::new(0), - }, - options: Vec::new(), - data: data - } - } - - fn create_ip(&self, id: u16, data: Vec) -> Ipv4 { - Ipv4 { - header: Ipv4Header { - ver_hlen: 0x45, - services: 0, - len: n16::new((data.len() + mem::size_of::()) as u16), - id: n16::new(id), - flags_fragment: n16::new(0), - ttl: 127, - proto: 0x06, - checksum: Checksum { data: 0 }, - src: self.local.0, - dst: self.remote.0 - }, - options: Vec::new(), - data: data - } - } -} - -struct Tcpd { - scheme_file: File, - tcp_file: File, - ports: BTreeMap, - next_id: usize, - handles: BTreeMap, - rng: OsRng, -} - -impl Tcpd { - fn new(scheme_file: File, tcp_file: File) -> Self { - Tcpd { - scheme_file: scheme_file, - tcp_file: tcp_file, - ports: BTreeMap::new(), - next_id: 1, - handles: BTreeMap::new(), - rng: OsRng::new().expect("tcpd: failed to open RNG") - } - } - - fn scheme_event(&mut self) -> io::Result<()> { - loop { - let mut packet = Packet::default(); - if self.scheme_file.read(&mut packet)? == 0 { - break; - } - - let a = packet.a; - self.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - if let Some(mut handle) = self.handles.get_mut(&packet.b) { - match a { - syscall::number::SYS_DUP => { - packet.a = a; - handle.todo_dup.push_back(packet); - }, - syscall::number::SYS_READ => { - packet.a = a; - handle.todo_read.push_back(packet); - }, - syscall::number::SYS_WRITE => { - packet.a = a; - handle.todo_write.push_back(packet); - }, - _ => { - self.scheme_file.write(&packet)?; - } - } - } - } else { - self.scheme_file.write(&packet)?; - } - } - - Ok(()) - } - - fn tcp_event(&mut self) -> io::Result<()> { - loop { - let mut bytes = [0; 65536]; - let count = self.tcp_file.read(&mut bytes)?; - if count == 0 { - break; - } - if let Some(ip) = Ipv4::from_bytes(&bytes[.. count]) { - if let Some(tcp) = Tcp::from_bytes(&ip.data) { - let mut closing = Vec::new(); - let mut found_connection = false; - for (id, handle) in self.handles.iter_mut() { - if handle.state != State::Listen && handle.matches(&ip, &tcp) { - found_connection = true; - - match handle.state { - State::SynReceived => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.state = State::Established; - }, - State::SynSent => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN | TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.state = State::Established; - handle.ack = tcp.header.sequence.get() + 1; - - let tcp = handle.create_tcp(TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; - }, - State::Established => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.ack = tcp.header.sequence.get(); - - if ! tcp.data.is_empty() { - handle.data.push_back((ip.clone(), tcp.clone())); - handle.ack += tcp.data.len() as u32; - - let tcp = handle.create_tcp(TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; - } else if tcp.header.flags.get() & TCP_FIN == TCP_FIN { - handle.state = State::CloseWait; - - handle.ack += 1; - - let tcp = handle.create_tcp(TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; - } - }, - //TODO: Time wait - State::FinWait1 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.ack = tcp.header.sequence.get() + 1; - - if tcp.header.flags.get() & TCP_FIN == TCP_FIN { - handle.state = State::TimeWait; - - let tcp = handle.create_tcp(TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; - - closing.push(*id); - } else { - handle.state = State::FinWait2; - } - }, - State::FinWait2 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK | TCP_FIN) == TCP_ACK | TCP_FIN && tcp.header.ack_num.get() == handle.seq { - handle.ack = tcp.header.sequence.get() + 1; - - handle.state = State::TimeWait; - - let tcp = handle.create_tcp(TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; - - closing.push(*id); - }, - State::LastAck => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq { - handle.state = State::Closed; - closing.push(*id); - }, - _ => () - } - - while ! handle.todo_read.is_empty() && (! handle.data.is_empty() || handle.read_closed()) { - let mut packet = handle.todo_read.pop_front().unwrap(); - let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }; - if let Some((_ip, tcp)) = handle.data.pop_front() { - let mut i = 0; - while i < buf.len() && i < tcp.data.len() { - buf[i] = tcp.data[i]; - i += 1; - } - packet.a = i; - } else { - packet.a = 0; - } - - self.scheme_file.write(&packet)?; - } - - if ! handle.todo_write.is_empty() && handle.state == State::Established { - let mut packet = handle.todo_write.pop_front().unwrap(); - let buf = unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }; - - let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - let result = self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))); - if result.is_ok() { - handle.seq += buf.len() as u32; - } - packet.a = Error::mux(result.and(Ok(buf.len()))); - - self.scheme_file.write(&packet)?; - } - - if handle.events & EVENT_READ == EVENT_READ { - if let Some(&(ref _ip, ref tcp)) = handle.data.get(0) { - self.scheme_file.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: EVENT_READ, - d: tcp.data.len() - })?; - } - } - } - } - - for file in closing { - let handle = self.handles.remove(&file).unwrap(); - - let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; - *port == 0 - } else { - false - }; - - if remove { - self.ports.remove(&handle.local.1); - } - } - - if ! found_connection && tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN { - let mut new_handles = Vec::new(); - - for (_id, handle) in self.handles.iter_mut() { - if handle.state == State::Listen && handle.matches(&ip, &tcp) { - handle.data.push_back((ip.clone(), tcp.clone())); - - while ! handle.todo_dup.is_empty() && ! handle.data.is_empty() { - let mut packet = handle.todo_dup.pop_front().unwrap(); - let (ip, tcp) = handle.data.pop_front().unwrap(); - - let mut new_handle = Handle { - local: handle.local, - remote: (ip.header.src, tcp.header.src.get()), - flags: handle.flags, - events: 0, - state: State::SynReceived, - seq: self.rng.gen(), - ack: tcp.header.sequence.get() + 1, - data: VecDeque::new(), - todo_dup: VecDeque::new(), - todo_read: VecDeque::new(), - todo_write: VecDeque::new(), - }; - - let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new()); - let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes())?; - - new_handle.seq += 1; - - handle.data.retain(|&(ref ip, ref tcp)| { - if new_handle.matches(ip, tcp) { - false - } else { - true - } - }); - - if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; - } - - let id = self.next_id; - self.next_id += 1; - - packet.a = id; - - new_handles.push((packet, new_handle)); - } - } - } - - for (packet, new_handle) in new_handles { - self.handles.insert(packet.a, new_handle); - self.scheme_file.write(&packet)?; - } - } - } - } - } - - Ok(()) - } -} - -impl SchemeMut for Tcpd { - fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?; - - let mut parts = path.split("/"); - let remote = parse_socket(parts.next().unwrap_or("")); - let mut local = parse_socket(parts.next().unwrap_or("")); - - if local.1 == 0 { - local.1 = self.rng.gen_range(32768, 65535); - } - - if local.1 <= 1024 && uid != 0 { - return Err(Error::new(EACCES)); - } - - if self.ports.contains_key(&local.1) { - return Err(Error::new(EADDRINUSE)); - } - - let mut handle = Handle { - local: local, - remote: remote, - flags: flags, - events: 0, - state: State::Listen, - seq: 0, - ack: 0, - data: VecDeque::new(), - todo_dup: VecDeque::new(), - todo_read: VecDeque::new(), - todo_write: VecDeque::new(), - }; - - if handle.is_connected() { - handle.seq = self.rng.gen(); - handle.ack = 0; - handle.state = State::SynSent; - - let tcp = handle.create_tcp(TCP_SYN, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; - - handle.seq += 1; - } - - self.ports.insert(local.1, 1); - - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, handle); - - Ok(id) - } - - fn dup(&mut self, file: usize, buf: &[u8]) -> Result { - let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; - - let handle = { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - let mut new_handle = Handle { - local: handle.local, - remote: handle.remote, - flags: handle.flags, - events: 0, - state: handle.state, - seq: handle.seq, - ack: handle.ack, - data: VecDeque::new(), - todo_dup: VecDeque::new(), - todo_read: VecDeque::new(), - todo_write: VecDeque::new(), - }; - - if path == "listen" { - if handle.is_connected() { - return Err(Error::new(EISCONN)); - } else if let Some((ip, tcp)) = handle.data.pop_front() { - new_handle.remote = (ip.header.src, tcp.header.src.get()); - - new_handle.seq = self.rng.gen(); - new_handle.ack = tcp.header.sequence.get() + 1; - new_handle.state = State::SynReceived; - - let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new()); - let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len()))?; - - new_handle.seq += 1; - } else { - return Err(Error::new(EWOULDBLOCK)); - } - - handle.data.retain(|&(ref ip, ref tcp)| { - if new_handle.matches(ip, tcp) { - false - } else { - true - } - }); - } else if path.is_empty() { - new_handle.data = handle.data.clone(); - } else if handle.is_connected() { - return Err(Error::new(EISCONN)); - } else { - new_handle.remote = parse_socket(path); - - if new_handle.is_connected() { - new_handle.seq = self.rng.gen(); - new_handle.ack = 0; - new_handle.state = State::SynSent; - - handle.data.retain(|&(ref ip, ref tcp)| { - if new_handle.matches(ip, tcp) { - new_handle.data.push_back((ip.clone(), tcp.clone())); - false - } else { - true - } - }); - - let tcp = new_handle.create_tcp(TCP_SYN, Vec::new()); - let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len()))?; - } else { - return Err(Error::new(EINVAL)); - } - } - - new_handle - }; - - if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; - } - - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, handle); - - Ok(id) - } - - fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - if ! handle.is_connected() { - Err(Error::new(ENOTCONN)) - } else if let Some((_ip, tcp)) = handle.data.pop_front() { - let mut i = 0; - while i < buf.len() && i < tcp.data.len() { - buf[i] = tcp.data[i]; - i += 1; - } - - Ok(i) - } else if handle.flags & O_NONBLOCK == O_NONBLOCK || handle.read_closed() { - Ok(0) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } - - fn write(&mut self, file: usize, buf: &[u8]) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - if ! handle.is_connected() { - Err(Error::new(ENOTCONN)) - } else if buf.len() >= 65507 { - Err(Error::new(EMSGSIZE)) - } else { - match handle.state { - State::Established => { - let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; - handle.seq += buf.len() as u32; - Ok(buf.len()) - }, - _ => { - Err(Error::new(EWOULDBLOCK)) - } - } - } - } - - fn fcntl(&mut self, file: usize, cmd: usize, arg: usize) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - match cmd { - F_GETFL => Ok(handle.flags), - F_SETFL => { - handle.flags = arg & ! O_ACCMODE; - Ok(0) - }, - _ => Err(Error::new(EINVAL)) - } - } - - fn fevent(&mut self, file: usize, flags: usize) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - handle.events = flags; - - Ok(file) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let path_string = format!("tcp:{}:{}/{}:{}", handle.remote.0.to_string(), handle.remote.1, handle.local.0.to_string(), handle.local.1); - let path = path_string.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } - - fn fsync(&mut self, file: usize) -> Result { - let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; - - Ok(0) - } - - fn close(&mut self, file: usize) -> Result { - let closed = { - let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; - - handle.data.clear(); - - match handle.state { - State::SynReceived | State::Established => { - handle.state = State::FinWait1; - - let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; - - handle.seq += 1; - - false - }, - State::CloseWait => { - handle.state = State::LastAck; - - let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new()); - let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes()); - self.tcp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; - - handle.seq += 1; - - false - }, - _ => true - } - }; - - if closed { - let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?; - - let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; - *port == 0 - } else { - false - }; - - if remove { - self.ports.remove(&handle.local.1); - } - } - - Ok(0) - } -} - -fn main() { - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let scheme_fd = syscall::open(":tcp", O_RDWR | O_CREAT | O_NONBLOCK).expect("tcpd: failed to create :tcp"); - let scheme_file = unsafe { File::from_raw_fd(scheme_fd) }; - - let tcp_fd = syscall::open("ip:6", O_RDWR | O_NONBLOCK).expect("tcpd: failed to open ip:6"); - let tcp_file = unsafe { File::from_raw_fd(tcp_fd) }; - - let tcpd = Rc::new(RefCell::new(Tcpd::new(scheme_file, tcp_file))); - - let mut event_queue = EventQueue::<()>::new().expect("tcpd: failed to create event queue"); - - let tcp_tcpd = tcpd.clone(); - event_queue.add(tcp_fd, move |_count: usize| -> io::Result> { - tcp_tcpd.borrow_mut().tcp_event()?; - Ok(None) - }).expect("tcpd: failed to listen to events on ip:6"); - - event_queue.add(scheme_fd, move |_count: usize| -> io::Result> { - tcpd.borrow_mut().scheme_event()?; - Ok(None) - }).expect("tcpd: failed to listen to events on :tcp"); - - event_queue.trigger_all(0).expect("tcpd: failed to trigger event queue"); - - event_queue.run().expect("tcpd: failed to run event queue"); - } -} diff --git a/schemes/udpd/Cargo.toml b/schemes/udpd/Cargo.toml deleted file mode 100644 index a62ffb0..0000000 --- a/schemes/udpd/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "udpd" -version = "0.1.0" - -[dependencies] -event = { path = "../../crates/event/" } -netutils = { path = "../../programs/netutils/" } -rand = { git = "https://github.com/rust-lang-nursery/rand.git" } -redox_syscall = { path = "../../syscall/" } diff --git a/schemes/udpd/src/main.rs b/schemes/udpd/src/main.rs deleted file mode 100644 index bd51751..0000000 --- a/schemes/udpd/src/main.rs +++ /dev/null @@ -1,482 +0,0 @@ -extern crate event; -extern crate netutils; -extern crate rand; -extern crate syscall; - -use rand::{Rng, OsRng}; -use std::collections::{BTreeMap, VecDeque}; -use std::cell::RefCell; -use std::fs::File; -use std::io::{self, Read, Write}; -use std::{mem, slice, str}; -use std::ops::{Deref, DerefMut}; -use std::os::unix::io::FromRawFd; -use std::rc::Rc; - -use event::EventQueue; -use netutils::{n16, Ipv4, Ipv4Addr, Ipv4Header, Checksum}; -use netutils::udp::{Udp, UdpHeader}; -use syscall::data::{Packet, TimeSpec}; -use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EIO, EINVAL, EMSGSIZE, ENOTCONN, EWOULDBLOCK}; -use syscall::flag::{EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_CREAT, O_RDWR, O_NONBLOCK}; -use syscall::scheme::SchemeMut; - -fn parse_socket(socket: &str) -> (Ipv4Addr, u16) { - let mut socket_parts = socket.split(":"); - let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or("")); - let port = socket_parts.next().unwrap_or("").parse::().unwrap_or(0); - (host, port) -} - -struct UdpHandle { - local: (Ipv4Addr, u16), - remote: (Ipv4Addr, u16), - flags: usize, - events: usize, - read_timeout: Option, - write_timeout: Option, - ttl: u8, - data: VecDeque>, - todo: VecDeque, -} - -#[derive(Copy, Clone)] -enum SettingKind { - Ttl, - ReadTimeout, - WriteTimeout -} - -enum Handle { - Udp(UdpHandle), - Setting(usize, SettingKind), -} - -struct Udpd { - scheme_file: File, - udp_file: File, - ports: BTreeMap, - next_id: usize, - handles: BTreeMap, - rng: OsRng, -} - -impl Udpd { - fn new(scheme_file: File, udp_file: File) -> Self { - Udpd { - scheme_file: scheme_file, - udp_file: udp_file, - ports: BTreeMap::new(), - next_id: 1, - handles: BTreeMap::new(), - rng: OsRng::new().expect("udpd: failed to open RNG") - } - } - - fn scheme_event(&mut self) -> io::Result<()> { - loop { - let mut packet = Packet::default(); - if self.scheme_file.read(&mut packet)? == 0 { - break; - } - - let a = packet.a; - self.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - if let Some(mut handle) = self.handles.get_mut(&packet.b) { - if let Handle::Udp(ref mut handle) = *handle { - handle.todo.push_back(packet); - } - } - } else { - self.scheme_file.write(&packet)?; - } - } - - Ok(()) - } - - fn udp_event(&mut self) -> io::Result<()> { - loop { - let mut bytes = [0; 65536]; - let count = self.udp_file.read(&mut bytes)?; - if count == 0 { - break; - } - if let Some(ip) = Ipv4::from_bytes(&bytes[.. count]) { - if let Some(udp) = Udp::from_bytes(&ip.data) { - for (id, handle) in self.handles.iter_mut() { - if let Handle::Udp(ref mut handle) = *handle { - // Local address not set or IP dst matches or is broadcast - if (handle.local.0 == Ipv4Addr::NULL || ip.header.dst == handle.local.0 || ip.header.dst == Ipv4Addr::BROADCAST) - // Local port matches UDP dst - && udp.header.dst.get() == handle.local.1 - // Remote address not set or is broadcast, or IP src matches - && (handle.remote.0 == Ipv4Addr::NULL || handle.remote.0 == Ipv4Addr::BROADCAST || ip.header.src == handle.remote.0) - // Remote port not set or UDP src matches - && (handle.remote.1 == 0 || udp.header.src.get() == handle.remote.1) - { - handle.data.push_back(udp.data.clone()); - - while ! handle.todo.is_empty() && ! handle.data.is_empty() { - let mut packet = handle.todo.pop_front().unwrap(); - let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }; - let data = handle.data.pop_front().unwrap(); - - let mut i = 0; - while i < buf.len() && i < data.len() { - buf[i] = data[i]; - i += 1; - } - packet.a = i; - - self.scheme_file.write(&packet)?; - } - - if handle.events & EVENT_READ == EVENT_READ { - if let Some(data) = handle.data.get(0) { - self.scheme_file.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: EVENT_READ, - d: data.len() - })?; - } - } - } - } - } - } - } - } - - Ok(()) - } -} - -impl SchemeMut for Udpd { - fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?; - - let mut parts = path.split("/"); - let remote = parse_socket(parts.next().unwrap_or("")); - let mut local = parse_socket(parts.next().unwrap_or("")); - - if local.1 == 0 { - local.1 = self.rng.gen_range(32768, 65535); - } - - if local.1 <= 1024 && uid != 0 { - return Err(Error::new(EACCES)); - } - - if self.ports.contains_key(&local.1) { - return Err(Error::new(EADDRINUSE)); - } - - self.ports.insert(local.1, 1); - - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, Handle::Udp(UdpHandle { - local: local, - remote: remote, - flags: flags, - events: 0, - ttl: 64, - read_timeout: None, - write_timeout: None, - data: VecDeque::new(), - todo: VecDeque::new(), - })); - - Ok(id) - } - - fn dup(&mut self, file: usize, buf: &[u8]) -> Result { - let handle = match *self.handles.get(&file).ok_or(Error::new(EBADF))? { - Handle::Udp(ref handle) => { - let mut handle = UdpHandle { - local: handle.local, - remote: handle.remote, - flags: handle.flags, - events: 0, - ttl: handle.ttl, - read_timeout: handle.read_timeout, - write_timeout: handle.write_timeout, - data: handle.data.clone(), - todo: VecDeque::new(), - }; - - let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; - - if path == "ttl" { - Handle::Setting(file, SettingKind::Ttl) - } else if path == "read_timeout" { - Handle::Setting(file, SettingKind::ReadTimeout) - } else if path == "write_timeout" { - Handle::Setting(file, SettingKind::WriteTimeout) - } else { - if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 { - handle.remote = parse_socket(path); - } - - if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; - } - - Handle::Udp(handle) - } - }, - Handle::Setting(file, kind) => { - Handle::Setting(file, kind) - } - }; - - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, handle); - - Ok(id) - } - - fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { - let (file, kind) = match *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { - Handle::Udp(ref mut handle) => { - if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 { - return Err(Error::new(ENOTCONN)); - } else if let Some(data) = handle.data.pop_front() { - let mut i = 0; - while i < buf.len() && i < data.len() { - buf[i] = data[i]; - i += 1; - } - - return Ok(i); - } else if handle.flags & O_NONBLOCK == O_NONBLOCK { - return Ok(0); - } else { - return Err(Error::new(EWOULDBLOCK)); - } - }, - Handle::Setting(file, kind) => { - (file, kind) - } - }; - - if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { - let read_timeout = |timeout: &Option, buf: &mut [u8]| -> Result { - if let Some(ref timespec) = *timeout { - timespec.deref().read(buf).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))) - } else { - Ok(0) - } - }; - - match kind { - SettingKind::Ttl => { - if let Some(mut ttl) = buf.get_mut(0) { - *ttl = handle.ttl; - Ok(1) - } else { - Ok(0) - } - }, - SettingKind::ReadTimeout => { - read_timeout(&handle.read_timeout, buf) - }, - SettingKind::WriteTimeout => { - read_timeout(&handle.write_timeout, buf) - } - } - } else { - Err(Error::new(EBADF)) - } - } - - fn write(&mut self, file: usize, buf: &[u8]) -> Result { - let (file, kind) = match *self.handles.get(&file).ok_or(Error::new(EBADF))? { - Handle::Udp(ref handle) => { - if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 { - return Err(Error::new(ENOTCONN)); - } else if buf.len() >= 65507 { - return Err(Error::new(EMSGSIZE)); - } else { - let udp_data = buf.to_vec(); - - let udp = Udp { - header: UdpHeader { - src: n16::new(handle.local.1), - dst: n16::new(handle.remote.1), - len: n16::new((udp_data.len() + mem::size_of::()) as u16), - checksum: Checksum { data: 0 } - }, - data: udp_data - }; - - let ip_data = udp.to_bytes(); - - let ip = Ipv4 { - header: Ipv4Header { - ver_hlen: 0x45, - services: 0, - len: n16::new((ip_data.len() + mem::size_of::()) as u16), - id: n16::new(self.rng.gen()), - flags_fragment: n16::new(0), - ttl: handle.ttl, - proto: 0x11, - checksum: Checksum { data: 0 }, - src: handle.local.0, - dst: handle.remote.0 - }, - options: Vec::new(), - data: ip_data - }; - - return self.udp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len())); - } - }, - Handle::Setting(file, kind) => { - (file, kind) - } - }; - - if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { - let write_timeout = |timeout: &mut Option, buf: &[u8]| -> Result { - if buf.len() >= mem::size_of::() { - let mut timespec = TimeSpec::default(); - let count = timespec.deref_mut().write(buf).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; - *timeout = Some(timespec); - Ok(count) - } else { - *timeout = None; - Ok(0) - } - }; - - match kind { - SettingKind::Ttl => { - if let Some(ttl) = buf.get(0) { - handle.ttl = *ttl; - Ok(1) - } else { - Ok(0) - } - }, - SettingKind::ReadTimeout => { - write_timeout(&mut handle.read_timeout, buf) - }, - SettingKind::WriteTimeout => { - write_timeout(&mut handle.write_timeout, buf) - } - } - } else { - Err(Error::new(EBADF)) - } - } - - fn fcntl(&mut self, file: usize, cmd: usize, arg: usize) -> Result { - if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { - match cmd { - F_GETFL => Ok(handle.flags), - F_SETFL => { - handle.flags = arg & ! O_ACCMODE; - Ok(0) - }, - _ => Err(Error::new(EINVAL)) - } - } else { - Err(Error::new(EBADF)) - } - } - - fn fevent(&mut self, file: usize, flags: usize) -> Result { - if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { - handle.events = flags; - Ok(file) - } else { - Err(Error::new(EBADF)) - } - } - - fn fpath(&mut self, file: usize, buf: &mut [u8]) -> Result { - if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { - let path_string = format!("udp:{}:{}/{}:{}", handle.remote.0.to_string(), handle.remote.1, handle.local.0.to_string(), handle.local.1); - let path = path_string.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } else { - Err(Error::new(EBADF)) - } - } - - fn fsync(&mut self, file: usize) -> Result { - let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; - - Ok(0) - } - - fn close(&mut self, file: usize) -> Result { - let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?; - - if let Handle::Udp(ref handle) = handle { - let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) { - *port = *port + 1; - *port == 0 - } else { - false - }; - - if remove { - drop(self.ports.remove(&handle.local.1)); - } - } - - drop(handle); - - Ok(0) - } -} - -fn main() { - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let scheme_fd = syscall::open(":udp", O_RDWR | O_CREAT | O_NONBLOCK).expect("udpd: failed to create :udp"); - let scheme_file = unsafe { File::from_raw_fd(scheme_fd) }; - - let udp_fd = syscall::open("ip:11", O_RDWR | O_NONBLOCK).expect("udpd: failed to open ip:11"); - let udp_file = unsafe { File::from_raw_fd(udp_fd) }; - - let udpd = Rc::new(RefCell::new(Udpd::new(scheme_file, udp_file))); - - let mut event_queue = EventQueue::<()>::new().expect("udpd: failed to create event queue"); - - let udp_udpd = udpd.clone(); - event_queue.add(udp_fd, move |_count: usize| -> io::Result> { - udp_udpd.borrow_mut().udp_event()?; - Ok(None) - }).expect("udpd: failed to listen to events on ip:11"); - - event_queue.add(scheme_fd, move |_count: usize| -> io::Result> { - udpd.borrow_mut().scheme_event()?; - Ok(None) - }).expect("udpd: failed to listen to events on :udp"); - - event_queue.trigger_all(0).expect("udpd: failed to trigger event queue"); - - event_queue.run().expect("udpd: failed to run event queue"); - } -} diff --git a/syscall b/syscall deleted file mode 160000 index 1193791..0000000 --- a/syscall +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1193791d642795840d7f22967249bad8bdef1a32 diff --git a/targets/arm-unknown-none.json b/targets/arm-unknown-none.json deleted file mode 100644 index 292fa64..0000000 --- a/targets/arm-unknown-none.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "llvm-target": "arm-unknown-none", - "target-endian": "little", - "target-pointer-width": "32", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "arch": "arm", - "os": "none", - "env": "", - "vendor": "unknown", - "target-family": "redox", - "pre-link-args": ["-nostdlib", "-static"], - "features": "+soft-float", - "dynamic-linking": false, - "executables": false, - "relocation-model": "static", - "code-model": "kernel", - "disable-redzone": true, - "eliminate-frame-pointer": false, - "exe-suffix": "", - "has-rpath": false, - "no-compiler-rt": true, - "no-default-libraries": true, - "position-independent-executables": false, - "has-elf-tls": true -} diff --git a/targets/x86_64-unknown-none.json b/targets/x86_64-unknown-none.json deleted file mode 100644 index 10ff541..0000000 --- a/targets/x86_64-unknown-none.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "llvm-target": "x86_64-unknown-none", - "target-endian": "little", - "target-pointer-width": "64", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "arch": "x86_64", - "os": "none", - "env": "", - "vendor": "unknown", - "target-family": "redox", - "pre-link-args": ["-m64", "-nostdlib", "-static"], - "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float", - "dynamic-linking": false, - "executables": false, - "relocation-model": "pic", - "code-model": "kernel", - "disable-redzone": true, - "eliminate-frame-pointer": false, - "exe-suffix": "", - "has-rpath": false, - "no-compiler-rt": true, - "no-default-libraries": true, - "position-independent-executables": false, - "has-elf-tls": true -} diff --git a/x86_64-unknown-redox.json b/x86_64-unknown-redox.json deleted file mode 100644 index 362ef9c..0000000 --- a/x86_64-unknown-redox.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "llvm-target": "x86_64-unknown-redox", - "target-endian": "little", - "target-pointer-width": "64", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "arch": "x86_64", - "os": "redox", - "env": "", - "vendor": "unknown", - "target-family": "redox", - "pre-link-args": ["-m64", "-Wl,--as-needed", "-Wl,-z,noexecstack", "-nostartfiles", "-nostdlib", "-static"], - "late-link-args": ["libc-artifacts/lib/crt0.o", "libc-artifacts/lib/libm.a", "libc-artifacts/lib/libc.a", "libc-artifacts/lib/libgcc.a"], - "features": "", - "dynamic-linking": false, - "executables": true, - "relocation-model": "static", - "code-model": "default", - "disable-redzone": true, - "eliminate-frame-pointer": false, - "exe-suffix": "", - "has-rpath": false, - "no-compiler-rt": true, - "no-default-libraries": true, - "position-independent-executables": false, - "lib-allocation-crate": "alloc_system", - "exe-allocation-crate": "alloc_system", - "has-elf-tls": true, - "panic-strategy": "abort" -}