Compare commits
No commits in common. "master" and "0.0.3" have entirely different histories.
|
@ -0,0 +1,15 @@
|
|||
**Reproduction**: [describe how you are able to reproduce ("trigger") this bug/issue.]
|
||||
|
||||
**Expected behavior**: [describe the behavior you would expect the repro to yield.]
|
||||
|
||||
**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.]
|
||||
|
||||
**Blocking/related**: [issues or PRs blocking or being related to this issue.]
|
||||
|
||||
**Misc**: [optional: for other relevant information that should be known or cannot be described in the other fields.]
|
||||
|
||||
------
|
||||
|
||||
_If the above does not fit the nature of the issue feel free to modify it._
|
|
@ -1,4 +1,7 @@
|
|||
/build/
|
||||
/prefix/
|
||||
.config
|
||||
**/my_*
|
||||
Cargo.lock
|
||||
build
|
||||
target
|
||||
initfs/bin
|
||||
filesystem/bin
|
||||
filesystem/ref
|
||||
filesystem/sbin
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
image: "ubuntu:22.04"
|
||||
|
||||
variables:
|
||||
GIT_STRATEGY: "clone"
|
||||
GIT_SUBMODULE_STRATEGY: "recursive"
|
||||
|
||||
before_script:
|
||||
# Disable the wget progress bar
|
||||
- echo 'show-progress = off' >> ~/.wgetrc
|
||||
- |
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq &&
|
||||
apt-get install -qq \
|
||||
bison \
|
||||
build-essential \
|
||||
curl \
|
||||
flex \
|
||||
fuse3 \
|
||||
git \
|
||||
libfuse-dev \
|
||||
nasm \
|
||||
pkg-config \
|
||||
texinfo \
|
||||
wget \
|
||||
zstd &&
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none
|
||||
|
||||
img:
|
||||
script:
|
||||
- |
|
||||
source "$HOME/.cargo/env" &&
|
||||
curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash &&
|
||||
cargo binstall --no-confirm --version 0.1.1 cargo-config &&
|
||||
cargo binstall --no-confirm --version 1.16.0 just &&
|
||||
cargo binstall --no-confirm --version 0.26.0 cbindgen &&
|
||||
cargo build --manifest-path installer/Cargo.toml --release &&
|
||||
make ci-img IMG_TAG=$CI_COMMIT_REF_NAME REPO_BINARY=1
|
||||
artifacts:
|
||||
paths:
|
||||
- build/img/
|
||||
expire_in: 1 week
|
|
@ -1,92 +0,0 @@
|
|||
<!-- Thank you for taking the time to submit an issue! By following these comments and filling out the sections below, you can help the developers get the necessary information to fix your issue. Please provide a single issue per report. You can also preview this report before submitting it. Feel free to modify/remove sections to fit the nature of your issue. -->
|
||||
|
||||
<!-- Please search to check that your issue has not been created already. By preventing duplicate issues, you can help keep the repository organized. If your current issue has already been created and is still unresolved, you can contribute by commenting there. -->
|
||||
<!-- Replace the empty checkbox [ ] below with a checked one [x] if you have already searched for your issue. -->
|
||||
- [ ] I agree that I have searched opened and closed issues to prevent duplicates.
|
||||
|
||||
--------------------
|
||||
|
||||
|
||||
|
||||
## Description
|
||||
<!-- Briefly summarize/describe the issue that you are experiencing below. -->
|
||||
Replace me
|
||||
|
||||
|
||||
|
||||
## Environment info
|
||||
<!-- To understand where your issue originates, please include some relevant information about your environment. -->
|
||||
|
||||
<!-- If you are using a pre-built release of Redox, please specify the release version below. -->
|
||||
- Redox OS Release:
|
||||
0.0.0 Remove me
|
||||
|
||||
<!-- If you have built Redox OS yourself, please provide the following information: -->
|
||||
- Operating system:
|
||||
Replace me
|
||||
- `uname -a`:
|
||||
`Replace me`
|
||||
- `rustc -V`:
|
||||
`Replace me`
|
||||
- `git rev-parse HEAD`:
|
||||
`Replace me`
|
||||
<!-- Depending on your issue, additional information about your environment (network config, package versions, dependencies, etc.) can also help. You can list that below. -->
|
||||
- Replace me:
|
||||
Replace me
|
||||
|
||||
|
||||
|
||||
## Steps to reproduce
|
||||
<!-- If possible, please list the steps to reproduce ("trigger") your issue below. Being detailed definitely helps speed up bug fixes. -->
|
||||
1. Replace me
|
||||
2. Replace me
|
||||
3. ...
|
||||
|
||||
|
||||
|
||||
## Behavior
|
||||
<!-- It may seem obvious to know what to expect, but isolating the behavior from everything else simplifies the development process. Remember to provide a single issue in this report. You can use the References section below to link your issues together. -->
|
||||
|
||||
<!-- Describe the behavior you expect your steps should yield (i.e., correct behavior). -->
|
||||
- **Expected behavior**:
|
||||
Replace me
|
||||
|
||||
<!-- Describe the behavior you observed when running your steps (i.e., buggy behavior). -->
|
||||
- **Actual behavior**:
|
||||
Replace me
|
||||
|
||||
<!-- **Logs?** Posting a log can help developers find your particular issue more easily. Please wrap your code in code blocks using triple back-ticks ``` to increase readability. -->
|
||||
```
|
||||
Replace me
|
||||
```
|
||||
|
||||
<!-- **Solution?** Have a solution in mind? Propose your solution below. -->
|
||||
- **Proposed solution**:
|
||||
Replace me
|
||||
|
||||
<!-- **Screenshots?** Make it easier to get your point across with screenshots. You can drag & drop or paste your images below. -->
|
||||
|
||||
|
||||
|
||||
## Optional references
|
||||
<!-- If you have found issues or pull requests that are related to or blocking this issue, please link them below. See https://help.github.com/articles/autolinked-references-and-urls/ for more options. You can also link related code snippets by providing the permalink. See https://help.github.com/articles/creating-a-permanent-link-to-a-code-snippet/ for more information. -->
|
||||
|
||||
Related to:
|
||||
- #0000 Remove me
|
||||
- Replace me
|
||||
- ...
|
||||
|
||||
Blocked by:
|
||||
- #0000 Remove me
|
||||
- ...
|
||||
|
||||
|
||||
|
||||
## Optional extras
|
||||
<!-- If you have other relevant information not found in other sections, you can include it below. -->
|
||||
Replace me
|
||||
|
||||
<!-- **Code?** Awesome! You can also create a pull request with a reference to this issue. -->
|
||||
<!-- **Files?** Attach your relevant files by dragging & dropping or pasting them below. -->
|
||||
|
||||
<!-- You also can preview your report before submitting it. Thanks for contributing to Redox! -->
|
|
@ -1,21 +1,57 @@
|
|||
[submodule "cookbook"]
|
||||
path = cookbook
|
||||
url = https://gitlab.redox-os.org/redox-os/cookbook.git
|
||||
branch = master
|
||||
[submodule "installer"]
|
||||
path = installer
|
||||
url = https://gitlab.redox-os.org/redox-os/installer.git
|
||||
branch = master
|
||||
[submodule "rust"]
|
||||
path = rust
|
||||
url = https://gitlab.redox-os.org/redox-os/rust.git
|
||||
branch = redox-2023-09-07
|
||||
update = none
|
||||
[submodule "redoxfs"]
|
||||
path = redoxfs
|
||||
url = https://gitlab.redox-os.org/redox-os/redoxfs.git
|
||||
branch = master
|
||||
[submodule "relibc"]
|
||||
path = relibc
|
||||
url = https://gitlab.redox-os.org/redox-os/relibc.git
|
||||
branch = master
|
||||
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 "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 "libstd_real/openlibm"]
|
||||
path = libstd/openlibm
|
||||
url = https://github.com/redox-os/openlibm.git
|
||||
[submodule "programs/binutils"]
|
||||
path = programs/binutils
|
||||
url = https://github.com/redox-os/binutils.git
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
sudo: required
|
||||
language: rust
|
||||
rust:
|
||||
- nightly
|
||||
cache: cargo
|
||||
os:
|
||||
- linux
|
||||
dist: trusty
|
||||
before_install:
|
||||
- if [ `uname` = "Linux" ]; then sudo apt-get install -qq nasm pkg-config fuse libfuse-dev;
|
||||
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; fi
|
||||
script:
|
||||
- export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
- make clean && make update && make build/harddrive.bin.gz build/livedisk.bin.gz build/livedisk.iso -j 2
|
||||
notifications:
|
||||
email: false
|
||||
webhooks: http://37.139.9.28:54863/travis
|
||||
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
|
||||
on:
|
||||
repo: redox-os/redox
|
||||
tags: true
|
220
CONTRIBUTING.md
220
CONTRIBUTING.md
|
@ -1,141 +1,163 @@
|
|||
# Contributing to Redox
|
||||
|
||||
**Thank you for your interest in 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.
|
||||
|
||||
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
|
||||
|
||||
## Code Of Conduct
|
||||
* [Communication](#communication)
|
||||
* [Chat](#chat)
|
||||
* [Reddit](#reddit)
|
||||
* [Direct Contributing](#direct-contributing)
|
||||
* [Low-Hanging Fruit - Easy Targets for Newbies](#easy-targets)
|
||||
* [GitHub Issues](#gh-issues)
|
||||
* [Pull Requests](#prs)
|
||||
* [Creating a Pull Request](#creating-a-pr)
|
||||
* [Best Practices/Guidelines](#best-practices)
|
||||
* [General](#general)
|
||||
* [Kernel](#kernel)
|
||||
* [Testing Practices](#testing-practices)
|
||||
* [Style Guidelines](#style-guidelines)
|
||||
* [Rust](#rust-style-guidelines)
|
||||
* [Git](#git-style-guidelines)
|
||||
* [Other Ways to Contribute](#other)
|
||||
* [Graphic Design](#graphic-design)
|
||||
|
||||
We follow the [Rust Code Of Conduct](https://www.rust-lang.org/policies/code-of-conduct).
|
||||
## <a name="extern-links"> Other External Links </a>
|
||||
|
||||
## License
|
||||
* [redox-os.org](http://redox-os.org)
|
||||
* [rust-os-comparison](https://github.com/flosse/rust-os-comparison)
|
||||
* [rust-lang.org](http://rust-lang.org)
|
||||
|
||||
In general, your contributions to Redox are governed by the [MIT License](https://en.wikipedia.org/wiki/MIT_License). Each project repository has a `LICENSE` file that provides the license terms for that project.
|
||||
## <a name="communication"> Communication </a>
|
||||
|
||||
Please review the LICENSE for the project you are contributing to.
|
||||
### <a name="chat"> Chat </a>
|
||||
|
||||
On [this](https://doc.redox-os.org/book/ch01-02-philosophy.html) page we explain why we use the MIT license.
|
||||
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.
|
||||
|
||||
## Chat
|
||||
### <a name="reddit"> Reddit </a>
|
||||
|
||||
Join us on [Matrix Chat](https://doc.redox-os.org/book/ch13-01-chat.html) to discuss issues or ask questions.
|
||||
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.
|
||||
|
||||
## Important Places to Contribute
|
||||
## <a name="direct-contributing"> Direct Contributing </a>
|
||||
|
||||
(Before starting to contribute you **must** read the [FAQ](https://www.redox-os.org/faq/) and the [Redox Book](https://doc.redox-os.org/book/))
|
||||
### <a name="easy-targets"> Low-Hanging Fruit - Easy Targets for Newbies </a>
|
||||
|
||||
You can contribute to the Redox documentation and code on these repositories:
|
||||
* If you're not fluent in Rust:
|
||||
|
||||
(The order is based on difficulty, easy things first)
|
||||
* 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)
|
||||
|
||||
- [Website](https://gitlab.redox-os.org/redox-os/website)
|
||||
- [Book](https://gitlab.redox-os.org/redox-os/book) - High-level documentation
|
||||
- [Build System Configuration](https://gitlab.redox-os.org/redox-os/redox) - Our main repository
|
||||
- [Cookbook](https://gitlab.redox-os.org/redox-os/cookbook) - Ports system
|
||||
- [Orbital](https://gitlab.redox-os.org/redox-os/orbital) - Display server and window manager
|
||||
- [Package Manager](https://gitlab.redox-os.org/redox-os/pkgutils)
|
||||
- [relibc](https://gitlab.redox-os.org/redox-os/relibc) - Redox C Library
|
||||
- [Drivers](https://gitlab.redox-os.org/redox-os/drivers) - Device daemons
|
||||
- [Kernel](https://gitlab.redox-os.org/redox-os/kernel)
|
||||
* If you are fluent in Rust, but not OS Development:
|
||||
|
||||
### Skill Levels
|
||||
* Apps development
|
||||
* Shell ([Ion](https://github.com/redox-os/ion)) development
|
||||
* Package manager ([Magnet](https://github.com/redox-os/magnet)) development
|
||||
* Other high-level code tasks
|
||||
|
||||
If you aren't fluent in Rust:
|
||||
* If you are fluent in Rust, and have experience with OS Dev:
|
||||
|
||||
- Write documentation
|
||||
- Use and test Redox, fill issues for bugs or needed features (please verify the repository issues before)
|
||||
- Web development on the website (we don't accept JavaScript code)
|
||||
- Write unit tests (may require minimal knowledge of Rust)
|
||||
* 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
|
||||
|
||||
If you are fluent in Rust, but not operating system Development:
|
||||
### <a name="gh-issues"> GitHub Issues </a>
|
||||
|
||||
- Improve the Orbital display server and window manager.
|
||||
- Port programs written in Rust to Redox (in most cases you need to port crates, be aware of missing functions on relibc, porting without these functions will make patches dirty)
|
||||
- Improve the program compatibility in relibc
|
||||
- Improve the package manager
|
||||
- Improve the [Ion](https://gitlab.redox-os.org/redox-os/ion) shell
|
||||
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.
|
||||
|
||||
If you are fluent in Rust, and have experience with operating system development:
|
||||
### <a name="prs"> Pull Requests </a>
|
||||
|
||||
- Familiarize yourself with the repository and code
|
||||
- Grep for `TODO`, `FIXME`, `BUG`, `UNOPTIMIZED`, `REWRITEME`, `DOCME`, and `PRETTYFYME` and fix the code you find
|
||||
- Update old code to remove warnings
|
||||
- Improve and optimize code, especially in the kernel
|
||||
- Write device drivers
|
||||
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)
|
||||
|
||||
For those who want to contribute to the Redox GUI, our GUI strategy has recently changed.
|
||||
### <a name="creating-a-pr"> Creating a Pull Request </a>
|
||||
|
||||
- We are improving the [Orbital](https://gitlab.redox-os.org/redox-os/orbital) display server and window manager, you can read more about it on [this](https://gitlab.redox-os.org/redox-os/redox/-/issues/1430) tracking issue.
|
||||
- Redox is in the process of adopting other Rust-written GUI toolkits, such as [Iced](https://iced.rs) and [Slint](https://slint-ui.com/). Please check out those projects if this is your area of interest.
|
||||
- OrbTk is in maintenance mode, and its developers have moved to other projects such as the ones below. There is currently no Redox-specific GUI development underway.
|
||||
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!)
|
||||
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`)
|
||||
6. Make changes
|
||||
7. Commit (`git add . --all; git commit -m "my commit"`)
|
||||
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`)
|
||||
(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.)
|
||||
11. Repeat step 9 to make sure the rebase still builds and starts
|
||||
12. Push to your fork (`git push origin my-branch`)
|
||||
13. Create a pull request
|
||||
14. Describe your changes
|
||||
15. Submit!
|
||||
|
||||
## Tracking Issues Index
|
||||
## <a name="best-practices"> Best Practices and Guidelines </a>
|
||||
|
||||
We use an index to track the development priorities, you can find them on [this](https://gitlab.redox-os.org/redox-os/redox/-/issues/1384) page.
|
||||
### <a name="general"> General </a>
|
||||
|
||||
## Build System
|
||||
* **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.**
|
||||
|
||||
You can find the Redox build system organization and commands on [this](https://doc.redox-os.org/book/ch08-06-build-system-reference.html) page.
|
||||
##### On the more technical side:
|
||||
* Test, test, and test!
|
||||
* Follow the style conventions
|
||||
* 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 passing references to the data over owned data. (Don't take `String`, take `&str`. Don't take `Vec<T>` 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`.
|
||||
* 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.
|
||||
|
||||
## Developer FAQ
|
||||
### <a name="kernel"> Kernel </a>
|
||||
|
||||
You can see the most common questions and problems on [this](https://doc.redox-os.org/book/ch09-07-developer-faq.html) page.
|
||||
* 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.
|
||||
|
||||
## Porting Software
|
||||
### <a name="testing-practices"> Testing Practices </a>
|
||||
|
||||
You can read how to use the Cookbook recipe system to port applications on [this](https://doc.redox-os.org/book/ch09-03-porting-applications.html) page.
|
||||
* 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.
|
||||
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.
|
||||
|
||||
## Libraries and APIs
|
||||
* To run the ZFS tests:
|
||||
* Create the zfs.img only once. If one has not been created, run `make filesystem/apps/zfs/zfs.img` before booting into Redox.
|
||||
* Run `open zfs.img` to open the created ZFS image.
|
||||
* Run `file /home/LICENSE.md` twice to ensure ARC isn't broken.
|
||||
|
||||
You can read [this](https://doc.redox-os.org/book/ch09-06-libraries-apis.html) page to learn about the libraries and APIs used in Redox.
|
||||
## <a name="style-guidelines"> Style Guidelines </a>
|
||||
|
||||
## Development Tips
|
||||
### <a name="rust-style-guidelines"> Rust </a>
|
||||
|
||||
You can find important tips on [this](https://doc.redox-os.org/book/ch09-02-coding-and-building.html#development-tips) section.
|
||||
Since Rust is a relatively small and new language compared to others like C, there's really only one standard. Just follow the official Rust standards for formatting, and maybe run `rustfmt` on your changes, until we setup the CI system to do it automatically.
|
||||
|
||||
## References
|
||||
### <a name="git-style-guidelines"> Git </a>
|
||||
|
||||
We maintain a list of wikis, articles and videos to learn Rust, OS development and computer science on [this](https://doc.redox-os.org/book/ch09-08-references.html) page.
|
||||
* 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.
|
||||
|
||||
If you are skilled there's a possibility that they could improve your knowledge in some way.
|
||||
## <a name="other"> Other Ways to Contribute </a>
|
||||
|
||||
## Best Practices and Guidelines
|
||||
### <a name="graphic-design"> Graphic Design </a>
|
||||
|
||||
You can read the best practices and guidelines on [this](https://doc.redox-os.org/book/ch11-00-best-practices.html) chapter.
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
### Rust
|
||||
|
||||
Since **Rust** is a relatively small and new language compared to others like C and C++, there's really only one standard. Just follow the official Rust standards for formatting, and maybe run `rustfmt` on your changes, until we setup the CI system to do it automatically.
|
||||
|
||||
### Git
|
||||
|
||||
Please follow our [Git style](https://doc.redox-os.org/book/ch12-04-creating-proper-pull-requests.html) for pull requests.
|
||||
|
||||
## GitLab
|
||||
|
||||
### Issues
|
||||
|
||||
To know how to create issues on the Redox GitLab, read [this](https://doc.redox-os.org/book/ch12-05-filing-issues.html) page.
|
||||
|
||||
### Pull Requests
|
||||
|
||||
Please follow [our process](https://doc.redox-os.org/book/ch12-04-creating-proper-pull-requests.html) for creating proper pull requests.
|
||||
|
||||
## Other Ways to Contribute
|
||||
|
||||
If you aren't good on coding, but you still want to help keep the project going, you can contribute and 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.
|
||||
|
||||
- [Redox backgrounds](https://gitlab.redox-os.org/redox-os/backgrounds) - You can send your wallpapers on this repository.
|
||||
- [Redox assets](https://gitlab.redox-os.org/redox-os/assets) - You can send your logos, icons and themes on this repository.
|
||||
|
||||
If you have questions about the graphic design, ask us on the [Chat](https://doc.redox-os.org/book/ch13-01-chat.html).
|
||||
|
||||
### Donate to Redox
|
||||
|
||||
If you are interested in donating to the Redox OS Nonprofit, you can find instructions [here](https://www.redox-os.org/donate/).
|
||||
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.
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
[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/redox-os/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"
|
327
HARDWARE.md
327
HARDWARE.md
|
@ -1,327 +0,0 @@
|
|||
# Hardware Compatibility
|
||||
|
||||
This document tracks the current hardware compatibility of Redox.
|
||||
|
||||
- [Status](#status)
|
||||
- [General](#general)
|
||||
- [Template](#template)
|
||||
- [x86-64](#x86-64)
|
||||
- [System76](#system76)
|
||||
- [Dell](#dell)
|
||||
- [HP](#hp)
|
||||
- [ASUS](#asus)
|
||||
- [Lenovo](#lenovo)
|
||||
- [Toshiba](#toshiba)
|
||||
- [Custom](#custom)
|
||||
- [i686](#i686)
|
||||
- [Dell](#dell-1)
|
||||
- [ASUS](#asus-1)
|
||||
- [Lenovo](#lenovo-1)
|
||||
- [Toshiba](#toshiba-1)
|
||||
- [Panasonic](#panasonic)
|
||||
- [Custom](#custom-1)
|
||||
- [ARM64](#arm64)
|
||||
- [Custom](#custom-2)
|
||||
|
||||
## Status
|
||||
|
||||
- Broken - The system can't boot.
|
||||
- Booting - The system boots with some issues.
|
||||
- Recommended - The system start with all features working.
|
||||
|
||||
## General
|
||||
|
||||
This section cover things to consider.
|
||||
|
||||
- ACPI support is incomplete (some things are hardcoded on the kernel)
|
||||
- USB support is incomplete (desktops are generally not recommended)
|
||||
- Wi-Fi is not supported
|
||||
- GPU drivers aren't supported (only VESA and GOP)
|
||||
- Automatic operating system discovery on boot loader is not implemented (remember this before installing Redox)
|
||||
|
||||
## Template
|
||||
|
||||
You will use this template to insert your computer.
|
||||
|
||||
- **Computer model**
|
||||
|
||||
```
|
||||
Status - (Broken, Booting or Recommended)
|
||||
Redox version - 0.0.0
|
||||
Variant - (server-minimal, desktop-minimal, server, desktop, demo, dev or customized)
|
||||
Image date - day-month-year
|
||||
|
||||
- Additional details goes here as items
|
||||
```
|
||||
|
||||
## x86-64
|
||||
|
||||
Computers using a 64 bits Intel/AMD CPU.
|
||||
|
||||
### System76
|
||||
|
||||
- **System76 Galago Pro (galp5)**
|
||||
|
||||
```
|
||||
Status - Recommended
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using UEFI
|
||||
- Boots to desktop
|
||||
```
|
||||
|
||||
- **System76 Lemur Pro (lemp9)**
|
||||
|
||||
```
|
||||
Status - Recommended
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using UEFI
|
||||
- Boots to desktop
|
||||
```
|
||||
|
||||
- **System76 Oryx Pro (oryp10)**
|
||||
|
||||
```
|
||||
Status - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using UEFI
|
||||
- Boots to desktop
|
||||
- No touchpad support, though it should be working
|
||||
```
|
||||
|
||||
- **System76 Pangolin (pang12)**
|
||||
|
||||
```
|
||||
Status - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using UEFI
|
||||
- Boots to desktop
|
||||
- No touchpad support, requires I2C HID
|
||||
```
|
||||
|
||||
### Dell
|
||||
|
||||
- **Dell XPS 13 (9350)**
|
||||
|
||||
```
|
||||
Status - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using both BIOS and UEFI
|
||||
- Boots to desktop
|
||||
- NVMe driver livelocks
|
||||
```
|
||||
|
||||
### HP
|
||||
|
||||
- **HP Dev One**
|
||||
|
||||
```
|
||||
Status - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using UEFI
|
||||
- Boots to desktop
|
||||
- No touchpad support, requires I2C HID
|
||||
```
|
||||
|
||||
### ASUS
|
||||
|
||||
- **ASUS X554L**
|
||||
|
||||
```
|
||||
Status - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using BIOS
|
||||
- Boots to desktop
|
||||
- No audio, HDA driver cannot find output pins
|
||||
```
|
||||
|
||||
- **ASUS ROG g55vw**
|
||||
|
||||
```
|
||||
Satus - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2023
|
||||
|
||||
- Booted using BIOS
|
||||
- Boots to desktop
|
||||
- UEFI panic in SETUP
|
||||
```
|
||||
|
||||
### Lenovo
|
||||
|
||||
- **Lenovo IdeaPad Y510P**
|
||||
|
||||
```
|
||||
Status - Recommended
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using both BIOS and UEFI
|
||||
- Boots to desktop
|
||||
```
|
||||
|
||||
- **Lenovo G570**
|
||||
|
||||
```
|
||||
Status - Broken
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using BIOS
|
||||
- Correct video mode not offered, this is a firmware issue
|
||||
- Bootloader panics in alloc_zeroed_page_aligned
|
||||
```
|
||||
|
||||
### Toshiba
|
||||
|
||||
- **Toshiba Satellite L500**
|
||||
|
||||
```
|
||||
Status - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using BIOS
|
||||
- Correct video mode not offered, this is a firmware issue
|
||||
- Boots to desktop
|
||||
- No ethernet driver
|
||||
```
|
||||
|
||||
### Custom
|
||||
|
||||
If you have a customized computer, put it here.
|
||||
|
||||
|
||||
|
||||
## i686
|
||||
|
||||
Computers with a 32 bits Intel/AMD CPU.
|
||||
|
||||
### Dell
|
||||
|
||||
- **Dell XPS 13 (9350)**
|
||||
|
||||
```
|
||||
Status - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using BIOS
|
||||
- Boots to desktop
|
||||
- NVMe driver livelocks
|
||||
```
|
||||
|
||||
### ASUS
|
||||
|
||||
- **ASUS Eee PC 900**
|
||||
|
||||
```
|
||||
Status - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using BIOS
|
||||
- Correct video mode not offered, this is a firmware issue
|
||||
- Boots to desktop
|
||||
- No ethernet driver
|
||||
```
|
||||
|
||||
### Lenovo
|
||||
|
||||
- **Lenovo IdeaPad Y510P**
|
||||
|
||||
```
|
||||
Status - Broken
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using BIOS
|
||||
- Panics on phys_to_virt overflow, probably having invalid mappings for 32-bit
|
||||
```
|
||||
|
||||
### Toshiba
|
||||
|
||||
- **Toshiba Satellite L500**
|
||||
|
||||
```
|
||||
Status - Broken
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using BIOS
|
||||
- Correct video mode not offered, this is a firmware issue
|
||||
- Panics on phys_to_virt overflow, probably having invalid mappings for 32-bit
|
||||
```
|
||||
|
||||
### Panasonic
|
||||
|
||||
- **Panasonic Toughbook CF-18**
|
||||
|
||||
```
|
||||
Status - Broken
|
||||
Redox version - 0.8.0
|
||||
Variant - desktop
|
||||
Image date - 11-11-2022
|
||||
|
||||
- Booted using BIOS
|
||||
- Hangs after PIT initialization
|
||||
```
|
||||
|
||||
### Custom
|
||||
|
||||
If you have a customized computer, put it here.
|
||||
|
||||
|
||||
|
||||
## ARM64
|
||||
|
||||
Computers using a 64 bits ARM CPU.
|
||||
|
||||
### Raspberry Pi
|
||||
|
||||
- **Raspberry Pi 3 Model B+**
|
||||
|
||||
```
|
||||
Status - Booting
|
||||
Redox version - 0.8.0
|
||||
Variant - server
|
||||
Image date - None
|
||||
|
||||
- Booted using Uboot
|
||||
- Boots to UART serial console
|
||||
- a bcm2835-sdhci/mmc driver
|
||||
- pl011 UART
|
||||
```
|
||||
|
||||
### Custom
|
||||
|
||||
If you have a customized ARM board, put it here.
|
||||
|
681
Makefile
681
Makefile
|
@ -1,100 +1,601 @@
|
|||
# Configuration and variables
|
||||
include mk/config.mk
|
||||
ARCH?=x86_64
|
||||
|
||||
# Dependencies
|
||||
include mk/depends.mk
|
||||
# Kernel variables
|
||||
KTARGET=$(ARCH)-unknown-none
|
||||
KBUILD=build/kernel
|
||||
KRUSTC=./krustc.sh
|
||||
KRUSTCFLAGS=--target $(KTARGET).json -C opt-level=2 -C debuginfo=0 -C soft-float
|
||||
KRUSTDOC=./krustdoc.sh
|
||||
KCARGO=RUSTC="$(KRUSTC)" RUSTDOC="$(KRUSTDOC)" cargo
|
||||
KCARGOFLAGS=--target $(KTARGET).json --release -- -C soft-float
|
||||
|
||||
all: $(BUILD)/harddrive.img
|
||||
# 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 --
|
||||
|
||||
live:
|
||||
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
||||
-$(FUMOUNT) /tmp/redox_installer/ || true
|
||||
rm -f $(BUILD)/livedisk.iso
|
||||
$(MAKE) $(BUILD)/livedisk.iso
|
||||
# Default targets
|
||||
.PHONY: all live iso clean doc ref test update qemu bochs drivers schemes binutils coreutils extrautils netutils userutils wireshark FORCE
|
||||
|
||||
popsicle: $(BUILD)/livedisk.iso
|
||||
popsicle-gtk $(BUILD)/livedisk.iso
|
||||
all: build/harddrive.bin
|
||||
|
||||
image:
|
||||
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
||||
-$(FUMOUNT) /tmp/redox_installer/ || true
|
||||
rm -f $(BUILD)/harddrive.img $(BUILD)/livedisk.iso
|
||||
$(MAKE) all
|
||||
live: build/livedisk.bin
|
||||
|
||||
rebuild:
|
||||
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
||||
-$(FUMOUNT) /tmp/redox_installer/ || true
|
||||
rm -rf $(BUILD)
|
||||
$(MAKE) all
|
||||
iso: build/livedisk.iso
|
||||
|
||||
clean: $(CONTAINER_TAG)
|
||||
ifeq ($(PODMAN_BUILD),1)
|
||||
$(PODMAN_RUN) $(MAKE) $@
|
||||
else
|
||||
cd cookbook && ./clean.sh
|
||||
-rm -rf cookbook/repo
|
||||
cargo clean --manifest-path cookbook/pkgutils/Cargo.toml
|
||||
cargo clean --manifest-path installer/Cargo.toml
|
||||
cargo clean --manifest-path redoxfs/Cargo.toml
|
||||
cargo clean --manifest-path relibc/Cargo.toml
|
||||
endif
|
||||
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
||||
-$(FUMOUNT) /tmp/redox_installer/ || true
|
||||
rm -rf $(BUILD)
|
||||
|
||||
distclean: $(CONTAINER_TAG)
|
||||
ifeq ($(PODMAN_BUILD),1)
|
||||
$(PODMAN_RUN) $(MAKE) $@
|
||||
else
|
||||
$(MAKE) clean
|
||||
cd cookbook && ./unfetch.sh
|
||||
endif
|
||||
|
||||
pull:
|
||||
git pull
|
||||
git submodule sync --recursive
|
||||
git submodule update --recursive --init
|
||||
|
||||
fetch: $(BUILD)/fetch.tag
|
||||
|
||||
repo: $(BUILD)/repo.tag
|
||||
|
||||
# Podman build recipes and vars
|
||||
include mk/podman.mk
|
||||
|
||||
# Disk Imaging and Cookbook tools
|
||||
include mk/fstools.mk
|
||||
|
||||
# Cross compiler recipes
|
||||
include mk/prefix.mk
|
||||
|
||||
# Repository maintenance
|
||||
include mk/repo.mk
|
||||
|
||||
# Disk images
|
||||
include mk/disk.mk
|
||||
|
||||
# Emulation recipes
|
||||
include mk/qemu.mk
|
||||
include mk/virtualbox.mk
|
||||
|
||||
# CI
|
||||
include mk/ci.mk
|
||||
|
||||
env: prefix FORCE $(CONTAINER_TAG)
|
||||
ifeq ($(PODMAN_BUILD),1)
|
||||
$(PODMAN_RUN) $(MAKE) $@
|
||||
else
|
||||
export PATH="$(PREFIX_PATH):$$PATH" && \
|
||||
bash
|
||||
endif
|
||||
|
||||
gdb: FORCE
|
||||
gdb cookbook/recipes/core/kernel/target/$(TARGET)/build/kernel.sym --eval-command="target remote localhost:1234"
|
||||
|
||||
# An empty target
|
||||
FORCE:
|
||||
|
||||
# Wireshark
|
||||
clean:
|
||||
cargo clean
|
||||
cargo clean --manifest-path 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/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
|
||||
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 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 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/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 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/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
|
||||
|
||||
# Emulation
|
||||
QEMU=SDL_VIDEO_X11_DGAMOUSE=0 qemu-system-$(ARCH)
|
||||
QEMUFLAGS=-serial mon:stdio -d cpu_reset -d guest_errors
|
||||
ifeq ($(ARCH),arm)
|
||||
LD=$(ARCH)-none-eabi-ld
|
||||
QEMUFLAGS+=-cpu arm1176 -machine integratorcp
|
||||
QEMUFLAGS+=-nographic
|
||||
|
||||
%.list: %
|
||||
$(ARCH)-none-eabi-objdump -C -D $< > $@
|
||||
|
||||
build/harddrive.bin: $(KBUILD)/kernel
|
||||
cp $< $@
|
||||
|
||||
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
|
||||
|
||||
UNAME := $(shell uname)
|
||||
ifeq ($(UNAME),Darwin)
|
||||
CC=$(ARCH)-elf-gcc
|
||||
CXX=$(ARCH)-elf-g++
|
||||
ECHO=/bin/echo
|
||||
FUMOUNT=sudo umount
|
||||
LD=$(ARCH)-elf-ld
|
||||
LDFLAGS=--gc-sections
|
||||
KRUSTCFLAGS+=-C linker=$(CC)
|
||||
KCARGOFLAGS+=-C linker=$(CC)
|
||||
RUSTCFLAGS+=-C linker=$(CC)
|
||||
CARGOFLAGS+=-C linker=$(CC)
|
||||
VB_AUDIO=coreaudio
|
||||
VBM="/Applications/VirtualBox.app/Contents/MacOS/VBoxManage"
|
||||
else
|
||||
CC=gcc
|
||||
CXX=g++
|
||||
ECHO=echo
|
||||
FUMOUNT=fusermount -u
|
||||
LD=ld
|
||||
LDFLAGS=--gc-sections
|
||||
ifneq ($(kvm),no)
|
||||
QEMUFLAGS+=-enable-kvm -cpu host
|
||||
endif
|
||||
VB_AUDIO="pulse"
|
||||
VBM=VBoxManage
|
||||
endif
|
||||
|
||||
%.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
|
||||
mkisofs -o $@ -b isolinux/isolinux.bin -c isolinux/boot.cat \
|
||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||
build/iso/
|
||||
|
||||
qemu: build/harddrive.bin
|
||||
$(QEMU) $(QEMUFLAGS) -drive file=$<,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
|
||||
$(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
|
||||
$(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
|
||||
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)/librustc_unicode.rlib: rust/src/librustc_unicode/lib.rs $(KBUILD)/libcore.rlib
|
||||
$(KRUSTC) $(KRUSTCFLAGS) -o $@ $<
|
||||
|
||||
$(KBUILD)/libcollections.rlib: rust/src/libcollections/lib.rs $(KBUILD)/libcore.rlib $(KBUILD)/liballoc.rlib $(KBUILD)/librustc_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)/libcore.rlib: rust/src/libcore/lib.rs
|
||||
mkdir -p $(BUILD)
|
||||
$(RUSTC) $(RUSTCFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD)/liballoc.rlib: rust/src/liballoc/lib.rs $(BUILD)/libcore.rlib
|
||||
$(RUSTC) $(RUSTCFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD)/libcollections.rlib: rust/src/libcollections/lib.rs $(BUILD)/libcore.rlib $(BUILD)/liballoc.rlib $(BUILD)/librustc_unicode.rlib
|
||||
$(RUSTC) $(RUSTCFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD)/librand.rlib: rust/src/librand/lib.rs $(BUILD)/libcore.rlib
|
||||
$(RUSTC) $(RUSTCFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD)/librustc_unicode.rlib: rust/src/librustc_unicode/lib.rs $(BUILD)/libcore.rlib
|
||||
$(RUSTC) $(RUSTCFLAGS) -o $@ $<
|
||||
|
||||
libstd/openlibm/libopenlibm.a:
|
||||
CROSSCC=$(CC) CFLAGS=-fno-stack-protector make -C libstd/openlibm libopenlibm.a
|
||||
|
||||
$(BUILD)/libopenlibm.a: libstd/openlibm/libopenlibm.a
|
||||
mkdir -p $(BUILD)
|
||||
cp $< $@
|
||||
|
||||
$(BUILD)/libstd.rlib: libstd/Cargo.toml rust/src/libstd/** $(BUILD)/libcore.rlib $(BUILD)/liballoc.rlib $(BUILD)/librustc_unicode.rlib $(BUILD)/libcollections.rlib $(BUILD)/librand.rlib $(BUILD)/libopenlibm.a
|
||||
$(CARGO) rustc --verbose --manifest-path $< $(CARGOFLAGS) -o $@
|
||||
cp libstd/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/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/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 $@
|
||||
|
||||
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
|
||||
|
||||
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/tcpd \
|
||||
filesystem/sbin/udpd
|
||||
|
||||
build/filesystem.bin: \
|
||||
drivers \
|
||||
coreutils \
|
||||
extrautils \
|
||||
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/
|
||||
echo exit | cargo run --manifest-path schemes/redoxfs/Cargo.toml --bin redoxfs-utility $@ 128
|
||||
mkdir -p build/filesystem/
|
||||
cargo build --manifest-path schemes/redoxfs/Cargo.toml --bin redoxfs-fuse --release
|
||||
schemes/redoxfs/target/release/redoxfs-fuse $@ build/filesystem/ &
|
||||
sleep 2
|
||||
pgrep redoxfs-fuse
|
||||
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 --bin redoxfs-fuse --release
|
||||
schemes/redoxfs/target/release/redoxfs-fuse build/harddrive.bin build/filesystem/ &
|
||||
sleep 2
|
||||
pgrep redoxfs-fuse
|
||||
|
||||
unmount: FORCE
|
||||
sync
|
||||
-$(FUMOUNT) build/filesystem/
|
||||
rm -rf build/filesystem/
|
||||
|
||||
wireshark: FORCE
|
||||
wireshark $(BUILD)/network.pcap
|
||||
wireshark build/network.pcap
|
||||
|
|
191
README.md
191
README.md
|
@ -1,73 +1,150 @@
|
|||
<p align="center">
|
||||
<img alt="Redox" width="346" src="https://gitlab.redox-os.org/redox-os/assets/raw/master/logos/redox/logo.png">
|
||||
<img alt="Redox" height="120" src="https://github.com/redox-os/assets/raw/master/logo.png">
|
||||
</p>
|
||||
|
||||
[Redox](https://www.redox-os.org) is an operating system written in Rust, a language with focus on safety, efficiency and high performance. Redox, following the microkernel design, aims to be reliable, secure, usable, correct and free. Redox is inspired by previous operating systems, such as seL4, MINIX, Plan 9, Linux and BSD.
|
||||
**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 components (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.
|
||||
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.
|
||||
|
||||
[](https://gitlab.redox-os.org/redox-os/redox/tags)
|
||||
[](./LICENSE)
|
||||
The website can be found at https://www.redox-os.org.
|
||||
|
||||
## Guide
|
||||
Please make sure you use the **latest nightly** of `rustc` before building (for more troubleshooting, see ["Help! Redox won't compile!"](#compile-help)).
|
||||
|
||||
This is the main repository of the Redox GitLab where the build system files are stored, this README is used to guide new developers.
|
||||
[](https://travis-ci.org/redox-os/redox)
|
||||
[](./LICENSE.md)
|
||||
|
||||
You can find the most important pages below:
|
||||
## Contents
|
||||
|
||||
- [Book](https://doc.redox-os.org/book/)
|
||||
- [Contribute](CONTRIBUTING.md)
|
||||
- [Hardware Compatibility](HARDWARE.md)
|
||||
- [Trying Out Redox](https://doc.redox-os.org/book/ch02-04-trying-out-redox.html)
|
||||
- [Building Redox](https://doc.redox-os.org/book/ch02-05-building-redox.html)
|
||||
- [Build System Documentation](https://doc.redox-os.org/book/ch08-06-build-system-reference.html)
|
||||
- [Developer FAQ](https://doc.redox-os.org/book/ch09-07-developer-faq.html)
|
||||
- [Chat/Discussions/Help](https://doc.redox-os.org/book/ch13-01-chat.html)
|
||||
* [What it looks like](#what-it-looks-like)
|
||||
* [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)
|
||||
|
||||
## Ecosystem
|
||||
## <a name="what-it-looks-like"> What it looks like </a>
|
||||
|
||||
These are the most important repositories available on the Redox GitLab:
|
||||
<img alt="Redox" height="150" src="https://github.com/redox-os/assets/raw/master/screenshots/Desktop.png">
|
||||
<img alt="Redox" height="150" src="https://github.com/redox-os/assets/raw/master/screenshots/Fancy_opacity.png">
|
||||
<img alt="Redox" height="150" src="https://github.com/redox-os/assets/raw/master/screenshots/File_manager.png">
|
||||
|
||||
| Name (lexicographic order) | Maintainer
|
||||
|--------------------------------------------------------------------------------------|---------------------------
|
||||
| [acid (kernel integration tests)](https://gitlab.redox-os.org/redox-os/acid) | **@jackpot51**
|
||||
| [binutils](https://gitlab.redox-os.org/redox-os/binutils) | **@jackpot51**
|
||||
| [cookbook](https://gitlab.redox-os.org/redox-os/cookbook) | **@jackpot51** **@hatred_45** **@ids1024**
|
||||
| [coreutils](https://gitlab.redox-os.org/redox-os/coreutils) | **@jackpot51**
|
||||
| [extrautils](https://gitlab.redox-os.org/redox-os/extrautils) | **@jackpot51**
|
||||
| [games](https://gitlab.redox-os.org/redox-os/games) | **@fabiao**
|
||||
| [Ion (shell)](https://gitlab.redox-os.org/redox-os/ion) | **@jackpot51**
|
||||
| [ipcd](https://gitlab.redox-os.org/redox-os/ipcd) | **@jackpot51**
|
||||
| [kernel](https://gitlab.redox-os.org/redox-os/kernel) | **@jackpot51**
|
||||
| [libextra](https://gitlab.redox-os.org/redox-os/libextra) | **@jackpot51**
|
||||
| [libpager](https://gitlab.redox-os.org/redox-os/libpager) | **@jackpot51**
|
||||
| [netstack](https://gitlab.redox-os.org/redox-os/netstack) | **@jackpot51**
|
||||
| [netutils](https://gitlab.redox-os.org/redox-os/netutils) | **@jackpot51**
|
||||
| [orbclient (Orbital client)](https://gitlab.redox-os.org/redox-os/orbclient) | **@jackpot51** **@FloVanGH**
|
||||
| [orbdata](https://gitlab.redox-os.org/redox-os/orbdata) | **@jackpot51**
|
||||
| [orbgame (Orbital 2D game engine)](https://gitlab.redox-os.org/redox-os/orbgame) | **@FloVanGH**
|
||||
| [Orbital (windowing and compositing system)](https://gitlab.redox-os.org/redox-os/orbital) | **@jackpot51**
|
||||
| [orbtk (Orbital toolkit)](https://gitlab.redox-os.org/redox-os/orbtk) | **@FloVanGH**
|
||||
| [orbutils (Orbital utilities)](https://gitlab.redox-os.org/redox-os/orbutils) | **@jackpot51**
|
||||
| [pkgutils (current package manager)](https://gitlab.redox-os.org/redox-os/pkgutils) | **@jackpot51**
|
||||
| [ralloc](https://gitlab.redox-os.org/redox-os/ralloc) | **@jackpot51**
|
||||
| [RANSID (Rust ANSI driver)](https://gitlab.redox-os.org/redox-os/ransid) | **@jackpot51**
|
||||
| [redoxfs (default filesystem)](https://gitlab.redox-os.org/redox-os/redoxfs) | **@jackpot51**
|
||||
| [relibc (C Library in Rust)](https://gitlab.redox-os.org/redox-os/relibc) | **@jackpot51**
|
||||
| [small (stack String and other collections)](https://gitlab.redox-os.org/redox-os/small) | **@jackpot51**
|
||||
| [syscall](https://gitlab.redox-os.org/redox-os/syscall) | **@jackpot51**
|
||||
| [Sodium (Vim-inspired text editor)](https://gitlab.redox-os.org/redox-os/sodium) | **@jackpot51**
|
||||
| [The Redox book](https://gitlab.redox-os.org/redox-os/book) | **@hatred_45**
|
||||
| [userutils](https://gitlab.redox-os.org/redox-os/userutils) | **@jackpot51**
|
||||
<img alt="Redox" height="150" src="https://github.com/redox-os/assets/raw/master/screenshots/Sodium_v1.png">
|
||||
<img alt="Redox" height="150" src="https://github.com/redox-os/assets/raw/master/screenshots/Boot.png">
|
||||
<img alt="Redox" height="150" src="https://github.com/redox-os/assets/raw/master/screenshots/start.png">
|
||||
|
||||
## What it looks like
|
||||
## <a name="ecosystem"> Ecosystem </a>
|
||||
|
||||
<img alt="Redox" height="150" src="https://gitlab.redox-os.org/redox-os/assets/raw/master/screenshots/Senza%20titolo.jpeg">
|
||||
<img alt="Redox" height="150" src="https://gitlab.redox-os.org/redox-os/assets/raw/master/screenshots/redox running.jpeg">
|
||||
<img alt="Redox" height="150" src="https://gitlab.redox-os.org/redox-os/assets/raw/master/screenshots/IMG_1460.PNG">
|
||||
The ecosystem and software Redox OS provides is listed below.
|
||||
|
||||
<img alt="Redox" height="150" src="https://gitlab.redox-os.org/redox-os/assets/raw/master/screenshots/Sodium_v2.PNG">
|
||||
<img alt="Redox" height="150" src="https://gitlab.redox-os.org/redox-os/assets/raw/master/screenshots/Boot.png">
|
||||
<img alt="Redox" height="150" src="https://gitlab.redox-os.org/redox-os/assets/raw/master/screenshots/IMG_1459.PNG">
|
||||
| Name (lexiographic 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))
|
||||
| [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)
|
||||
| [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)
|
||||
| [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)
|
||||
| [netutils](https://github.com/redox-os/netutils) | [**@jackpot51**](https://github.com/jackpot51)
|
||||
| [orbclient](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)
|
||||
| [pkgutils (current package manager)](https://github.com/redox-os/pkgutils) | [**@jackpot51**](https://github.com/jackpot51)
|
||||
| [playbot (internal REPL bot)](https://github.com/redox-os/platbot) | [**@ticki**](https://github.com/ticki)
|
||||
| [ralloc](https://github.com/redox-os/ralloc) | [**@ticki**](https://github.com/ticki)
|
||||
| [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)
|
||||
| [userutils](https://github.com/redox-os/userutils) | [**@jackpot51**](https://github.com/jackpot51)
|
||||
|
||||
See [Redox in Action](https://www.redox-os.org/screens/) for photos and videos.
|
||||
## <a name="compile-help"> Help! Redox won't compile! </a>
|
||||
|
||||
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`).
|
||||
|
||||
and then rebuild!
|
||||
|
||||
## <a name="contributing"> Contributing to Redox </a>
|
||||
|
||||
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.
|
||||
|
||||
## <a name="cloning-building-running"> Cloning, Building, and Running </a>
|
||||
|
||||
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!
|
||||
|
||||
### <a name="quick-setup" /> Quick Setup </a>
|
||||
|
||||
```bash
|
||||
$ 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
|
||||
|
||||
# Build Redox
|
||||
$ 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
|
||||
```
|
||||
|
||||
#### 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.
|
||||
|
||||
### <a name="manual-setup"> Manual Setup </a>
|
||||
|
||||
To manually clone, build and run Redox using a Linux host, run the following commands (with exceptions, be sure to read the comments):
|
||||
```bash
|
||||
$ cd path/to/your/projects/folder/
|
||||
|
||||
# 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
|
||||
|
||||
$ cd redox/
|
||||
|
||||
# Install/update dependencies
|
||||
$ bash bootstrap.sh -d
|
||||
|
||||
# Install rustup.rs
|
||||
$ curl https://sh.rustup.rs -sSf | sh
|
||||
|
||||
# Set override toolchain to nightly build
|
||||
$ rustup override set nightly
|
||||
|
||||
# For successive builds start here. If this is your first build, just continue
|
||||
|
||||
# Update git submodules
|
||||
$ git submodule update --recursive --init
|
||||
|
||||
# Build Redox
|
||||
$ 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
|
||||
```
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "arch_arm"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "*"
|
||||
hole_list_allocator = { path = "../../crates/hole_list_allocator"}
|
||||
spin = "*"
|
|
@ -0,0 +1,9 @@
|
|||
#[derive(Debug)]
|
||||
pub struct Context;
|
||||
|
||||
impl Context {
|
||||
pub fn new() -> Self {
|
||||
Context
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/// 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
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
//! 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() {
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
//! 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;
|
|
@ -0,0 +1,60 @@
|
|||
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*)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//! 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 {}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
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 {}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
[package]
|
||||
name = "arch_test"
|
||||
version = "0.1.0"
|
|
@ -0,0 +1,43 @@
|
|||
//! 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();
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//! 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;
|
|
@ -0,0 +1,11 @@
|
|||
/// 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();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
pub fn monotonic() -> (u64, u64) {
|
||||
(0, 0)
|
||||
}
|
||||
|
||||
pub fn realtime() -> (u64, u64) {
|
||||
(0, 0)
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
[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
|
|
@ -0,0 +1,77 @@
|
|||
#[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,
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
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<Dmar> {
|
||||
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<Self::Item> {
|
||||
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::<DmarDrhd>() {
|
||||
DmarEntry::Drhd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarDrhd) })
|
||||
} else {
|
||||
DmarEntry::InvalidDrhd(entry_len)
|
||||
},
|
||||
1 => if entry_len >= mem::size_of::<DmarRmrr>() {
|
||||
DmarEntry::Rmrr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRmrr) })
|
||||
} else {
|
||||
DmarEntry::InvalidRmrr(entry_len)
|
||||
},
|
||||
2 => if entry_len >= mem::size_of::<DmarAtsr>() {
|
||||
DmarEntry::Atsr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAtsr) })
|
||||
} else {
|
||||
DmarEntry::InvalidAtsr(entry_len)
|
||||
},
|
||||
3 => if entry_len == mem::size_of::<DmarRhsa>() {
|
||||
DmarEntry::Rhsa(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRhsa) })
|
||||
} else {
|
||||
DmarEntry::InvalidRhsa(entry_len)
|
||||
},
|
||||
4 => if entry_len >= mem::size_of::<DmarAndd>() {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
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<Madt> {
|
||||
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<Self::Item> {
|
||||
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::<MadtLocalApic>() + 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::<MadtIoApic>() + 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::<MadtIntSrcOverride>() + 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
//! # 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::madt::{Madt, MadtEntry};
|
||||
use self::rsdt::Rsdt;
|
||||
use self::sdt::Sdt;
|
||||
use self::xsdt::Xsdt;
|
||||
|
||||
pub mod dmar;
|
||||
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(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<Acpi> {
|
||||
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<RSDP> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
use core::mem;
|
||||
|
||||
use super::sdt::Sdt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Rsdt(&'static Sdt);
|
||||
|
||||
impl Rsdt {
|
||||
pub fn new(sdt: &'static Sdt) -> Option<Rsdt> {
|
||||
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<Self::Item> {
|
||||
if self.i < self.sdt.data_len()/mem::size_of::<u32>() {
|
||||
let item = unsafe { *(self.sdt.data_address() as *const u32).offset(self.i as isize) };
|
||||
self.i += 1;
|
||||
Some(item as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
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::<Sdt>()
|
||||
}
|
||||
|
||||
/// 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::<Sdt>();
|
||||
if total_size >= header_size {
|
||||
total_size - header_size
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
use core::mem;
|
||||
|
||||
use super::sdt::Sdt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Xsdt(&'static Sdt);
|
||||
|
||||
impl Xsdt {
|
||||
pub fn new(sdt: &'static Sdt) -> Option<Xsdt> {
|
||||
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<Self::Item> {
|
||||
if self.i < self.sdt.data_len()/mem::size_of::<u64>() {
|
||||
let item = unsafe { *(self.sdt.data_address() as *const u64).offset(self.i as isize) };
|
||||
self.i += 1;
|
||||
Some(item as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
use core::fmt::{self, Write};
|
||||
use spin::Mutex;
|
||||
|
||||
use device::serial::COM1;
|
||||
|
||||
pub static CONSOLE: Mutex<Console> = 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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
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::<usize>();
|
||||
*(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::<usize>();
|
||||
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");
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
extern crate raw_cpuid;
|
||||
|
||||
use core::fmt::{Result, Write};
|
||||
|
||||
use self::raw_cpuid::CpuId;
|
||||
|
||||
pub fn cpu_info<W: Write>(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(())
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
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();
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
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<u8>,
|
||||
data: Pio<u8>,
|
||||
}
|
||||
|
||||
impl Rtc {
|
||||
/// Create new empty RTC
|
||||
pub fn new() -> Self {
|
||||
return Rtc {
|
||||
addr: Pio::<u8>::new(0x70),
|
||||
data: Pio::<u8>::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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
use core::fmt::{self, Write};
|
||||
use spin::Mutex;
|
||||
|
||||
use io::{Io, Pio, ReadOnly};
|
||||
|
||||
pub static COM1: Mutex<SerialPort> = Mutex::new(SerialPort::new(0x3F8));
|
||||
pub static COM2: Mutex<SerialPort> = 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<u8>,
|
||||
/// Interrupt enable
|
||||
int_en: Pio<u8>,
|
||||
/// FIFO control
|
||||
fifo_ctrl: Pio<u8>,
|
||||
/// Line control
|
||||
line_ctrl: Pio<u8>,
|
||||
/// Modem control
|
||||
modem_ctrl: Pio<u8>,
|
||||
/// Line status
|
||||
line_sts: ReadOnly<Pio<u8>>,
|
||||
/// Modem status
|
||||
modem_sts: ReadOnly<Pio<u8>>,
|
||||
}
|
||||
|
||||
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 write_translate(&mut self, data: u8) {
|
||||
match data {
|
||||
8 | 0x7F => {
|
||||
self.write(8);
|
||||
self.write(b' ');
|
||||
self.write(8);
|
||||
},
|
||||
b'\r' => {
|
||||
self.write(b'\n');
|
||||
},
|
||||
_ => {
|
||||
self.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() {
|
||||
self.write_translate(byte);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/// 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
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
//! 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::<GdtEntry>() - 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::<GdtEntry>() - 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::<TaskStateSegment>() 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
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::<IdtEntry>() - 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::<IdtEntry>() - 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
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);
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
use device::local_apic::LOCAL_APIC;
|
||||
|
||||
interrupt!(ipi, {
|
||||
LOCAL_APIC.eoi();
|
||||
});
|
|
@ -0,0 +1,115 @@
|
|||
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();
|
||||
});
|
|
@ -0,0 +1,85 @@
|
|||
//! 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::<usize>()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#[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
|
||||
}
|
|
@ -0,0 +1,320 @@
|
|||
//! 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;
|
||||
|
||||
/// Time
|
||||
pub mod time;
|
|
@ -0,0 +1,63 @@
|
|||
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*)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
//! # 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<Frame> {
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
//! # 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<Self::Item> {
|
||||
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<Option<AreaFrameAllocator>> = 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<Frame> {
|
||||
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<Frame> {
|
||||
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<Frame> {
|
||||
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<Frame>;
|
||||
fn deallocate_frames(&mut self, frame: Frame, size: usize);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//! # 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<Frame> {
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
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<Table<Level4>>,
|
||||
}
|
||||
|
||||
impl Mapper {
|
||||
/// Create a new page table
|
||||
pub unsafe fn new() -> Mapper {
|
||||
Mapper {
|
||||
p4: Unique::new(table::P4),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn p4(&self) -> &Table<Level4> {
|
||||
unsafe { self.p4.get() }
|
||||
}
|
||||
|
||||
pub fn p4_mut(&mut self) -> &mut Table<Level4> {
|
||||
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<Frame> {
|
||||
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<EntryFlags> {
|
||||
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<PhysicalAddress> {
|
||||
let offset = virtual_address.get() % PAGE_SIZE;
|
||||
self.translate_page(Page::containing_address(virtual_address))
|
||||
.map(|frame| PhysicalAddress::new(frame.start_address().get() + offset))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,419 @@
|
|||
//! # 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::<usize>();
|
||||
|
||||
::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<F>(&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<Page> {
|
||||
if self.start <= self.end {
|
||||
let page = self.start;
|
||||
self.start.number += 1;
|
||||
Some(page)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//! # 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<Level4> = 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<L: TableLevel> {
|
||||
entries: [Entry; ENTRY_COUNT],
|
||||
level: PhantomData<L>,
|
||||
}
|
||||
|
||||
impl<L> Table<L> where L: TableLevel {
|
||||
pub fn zero(&mut self) {
|
||||
for entry in self.entries.iter_mut() {
|
||||
entry.set_unused();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L> Table<L> where L: HierarchicalLevel {
|
||||
pub fn next_table(&self, index: usize) -> Option<&Table<L::NextLevel>> {
|
||||
self.next_table_address(index).map(|address| unsafe { &*(address as *const _) })
|
||||
}
|
||||
|
||||
pub fn next_table_mut(&mut self, index: usize) -> Option<&mut Table<L::NextLevel>> {
|
||||
self.next_table_address(index).map(|address| unsafe { &mut *(address as *mut _) })
|
||||
}
|
||||
|
||||
pub fn next_table_create(&mut self, index: usize) -> &mut Table<L::NextLevel> {
|
||||
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<usize> {
|
||||
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<L> Index<usize> for Table<L> where L: TableLevel {
|
||||
type Output = Entry;
|
||||
|
||||
fn index(&self, index: usize) -> &Entry {
|
||||
&self.entries[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl<L> IndexMut<usize> for Table<L> where L: TableLevel {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Entry {
|
||||
&mut self.entries[index]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//! 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<Level1> {
|
||||
unsafe { &mut *(self.map(frame, flags, active_table).get() as *mut Table<Level1>) }
|
||||
}
|
||||
|
||||
/// Unmaps the temporary page in the active table.
|
||||
pub fn unmap(&mut self, active_table: &mut ActivePageTable) {
|
||||
active_table.unmap(self.page)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//! 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(); }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/// 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!();
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
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)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"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": ["-m32", "-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
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
ata0-master: type=disk, path="build/harddrive.bin", mode=flat
|
||||
boot: disk
|
||||
com1: enabled=1, mode=file, dev=build/serial.log
|
||||
megs: 1024
|
||||
|
||||
magic_break: enabled=1
|
||||
display_library: x, options="gui_debug"
|
||||
|
||||
log: -
|
||||
debug: action=ignore
|
||||
info: action=report
|
||||
error: action=report
|
||||
panic: action=ask
|
||||
debugger_log: -
|
|
@ -0,0 +1,17 @@
|
|||
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
|
|
@ -0,0 +1,188 @@
|
|||
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
|
|
@ -0,0 +1,18 @@
|
|||
SECTION .text
|
||||
USE16
|
||||
|
||||
align 512, db 0
|
||||
|
||||
config:
|
||||
.xres: dw 1024
|
||||
.yres: dw 768
|
||||
|
||||
times 512 - ($ - config) db 0
|
||||
|
||||
save_config:
|
||||
mov eax, (config - boot) / 512
|
||||
mov bx, config
|
||||
mov cx, 1
|
||||
xor dx, dx
|
||||
call store
|
||||
ret
|
|
@ -0,0 +1,46 @@
|
|||
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
|
|
@ -0,0 +1,8 @@
|
|||
struc GDTEntry
|
||||
.limitl resw 1
|
||||
.basel resw 1
|
||||
.basem resb 1
|
||||
.attribute resb 1
|
||||
.flags__limith resb 1
|
||||
.baseh resb 1
|
||||
endstruc
|
|
@ -0,0 +1,21 @@
|
|||
%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"
|
|
@ -0,0 +1,78 @@
|
|||
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
|
|
@ -0,0 +1,19 @@
|
|||
%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
|
|
@ -0,0 +1,32 @@
|
|||
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
|
|
@ -0,0 +1,65 @@
|
|||
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
|
|
@ -0,0 +1,110 @@
|
|||
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
|
|
@ -0,0 +1,148 @@
|
|||
%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:
|
|
@ -0,0 +1,179 @@
|
|||
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
|
|
@ -0,0 +1,54 @@
|
|||
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
|
|
@ -0,0 +1,207 @@
|
|||
%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
|
|
@ -0,0 +1,90 @@
|
|||
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
|
File diff suppressed because it is too large
Load Diff
98
build.sh
98
build.sh
|
@ -1,98 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
###########################################################################
|
||||
# #
|
||||
# Build the system, with a specified processor type and filesystem config #
|
||||
# #
|
||||
###########################################################################
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "build.sh: Invoke make for a particular architecture and configuration."
|
||||
echo "Usage:"
|
||||
echo "./build.sh [-X | -A | -6 | -a ARCH] [-c CONFIG] [-f FILESYSTEM_CONFIG] TARGET..."
|
||||
echo " -X Equivalent to -a x86_64."
|
||||
echo " -A Equivalent to -a aarch64."
|
||||
echo " -6 Equivalent to -a i686."
|
||||
echo " -a ARCH: Processor Architecture. Normally one of x86_64, aarch64 or"
|
||||
echo " i686. ARCH is not checked, so you can add a new architecture."
|
||||
echo " Defaults to the directory containing the FILESYSTEM_CONFIG file,"
|
||||
echo " or x86_64 if no FILESYSTEM_CONFIG is specified."
|
||||
echo " -c CONFIG: The name of the config, e.g. desktop, server or demo."
|
||||
echo " Determines the name of the image, build/ARCH/CONFIG/harddrive.img"
|
||||
echo " e.g. build/x86_64/desktop/harddrive.img"
|
||||
echo " Determines the name of FILESYSTEM_CONFIG if none is specified."
|
||||
echo " Defaults to the basename of FILESYSTEM_CONFIG, or 'desktop'"
|
||||
echo " if FILESYSTEM_CONFIG is not specified."
|
||||
echo " -f FILESYSTEM_CONFIG:"
|
||||
echo " The config file to use. It can be in any location."
|
||||
echo " However, if the file is not in a directory named x86_64, aarch64"
|
||||
echo " or i686, you must specify the architecture."
|
||||
echo " If -f is not specified, FILESYSTEM_CONFIG is set to"
|
||||
echo " config/ARCH/CONFIG.toml"
|
||||
echo " If you specify both CONFIG and FILESYSTEM_CONFIG, it is not"
|
||||
echo " necessary that they match, but it is recommended."
|
||||
echo " Examples: ./build.sh -c demo live - make build/x86_64/demo/livedisk.iso"
|
||||
echo " ./build.sh -6 qemu - make build/i686/desktop/harddrive.img and"
|
||||
echo " and run it in qemu"
|
||||
echo " NOTE: If you do not change ARCH or CONFIG very often, edit mk/config.mk"
|
||||
echo " and set ARCH and FILESYSTEM_CONFIG. You only need to use this"
|
||||
echo " script when you want to override them."
|
||||
}
|
||||
|
||||
if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
|
||||
usage
|
||||
exit
|
||||
fi
|
||||
|
||||
defaultarch="x86_64"
|
||||
defaultname="desktop"
|
||||
ARCH=""
|
||||
CONFIG_NAME=""
|
||||
FILESYSTEM_CONFIG=""
|
||||
|
||||
while getopts ":c:f:a:dhXA6" opt
|
||||
do
|
||||
case "$opt" in
|
||||
a) ARCH="$OPTARG";;
|
||||
c) CONFIG_NAME="$OPTARG";;
|
||||
f) FILESYSTEM_CONFIG="$OPTARG";;
|
||||
X) ARCH="x86_64";;
|
||||
A) ARCH="aarch64";;
|
||||
6) ARCH="i686";;
|
||||
h) usage;;
|
||||
\?) echo "Unknown option -$OPTARG, try -h for help"; exit;;
|
||||
:) echo "-$OPTARG requires a value"; exit;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND -1))
|
||||
|
||||
if [ -z "$ARCH" ] && [ -n "$FILESYSTEM_CONFIG" ]; then
|
||||
dirname=`dirname "$FILESYSTEM_CONFIG"`
|
||||
ARCH=`basename $dirname`
|
||||
case "$ARCH" in
|
||||
x86_64) : ;;
|
||||
aarch64) : ;;
|
||||
i686) : ;;
|
||||
\?) ARCH=""; echo "Unknown Architecture, please specify x86_64, aarch64 or i686";;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ -z "$config_name" ] && [ -n "$FILESYSTEM_CONFIG" ]; then
|
||||
CONFIG_NAME=`basename "$FILESYSTEM_CONFIG" .toml`
|
||||
fi
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
ARCH="$defaultarch"
|
||||
fi
|
||||
|
||||
if [ -z "$CONFIG_NAME" ]; then
|
||||
CONFIG_NAME="$defaultname"
|
||||
fi
|
||||
|
||||
if [ -z "$FILESYSTEM_CONFIG" ]; then
|
||||
FILESYSTEM_CONFIG="config/$ARCH/$CONFIG_NAME.toml"
|
||||
fi
|
||||
|
||||
export ARCH CONFIG_NAME FILESYSTEM_CONFIG
|
||||
make $@
|
|
@ -1,3 +0,0 @@
|
|||
# Configuration for using acid
|
||||
|
||||
include = ["../acid.toml"]
|
|
@ -1,213 +0,0 @@
|
|||
# This is the CI configuration file
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Do not prompt if settings are not defined
|
||||
prompt = false
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
acid = {}
|
||||
atk = {}
|
||||
audiod = {}
|
||||
autoconf = {}
|
||||
automake = {}
|
||||
bash = {}
|
||||
binutils = {}
|
||||
bootloader = {}
|
||||
bootstrap = {}
|
||||
ca-certificates = {}
|
||||
cairo = {}
|
||||
cairodemo = {}
|
||||
#calculator = {}
|
||||
cargo = {}
|
||||
cleye = {}
|
||||
#cmatrix = {} # needs ncursesw now
|
||||
contain = {}
|
||||
coreutils = {}
|
||||
cosmic-edit = {}
|
||||
cosmic-icons = {}
|
||||
cosmic-text = {}
|
||||
cpal = {}
|
||||
curl = {}
|
||||
dash = {}
|
||||
diffutils = {}
|
||||
dosbox = {}
|
||||
drivers = {}
|
||||
drivers-initfs = {}
|
||||
duktape = {}
|
||||
eduke32 = {}
|
||||
escalated = {}
|
||||
exampled = {}
|
||||
expat = {}
|
||||
extrautils = {}
|
||||
#fal
|
||||
#fd = {} # ctrlc-3.1.1
|
||||
#ffmpeg6 = {} # undefined references
|
||||
findutils = {}
|
||||
fontconfig = {}
|
||||
#freeciv = {}
|
||||
freedoom = {}
|
||||
#freeglut = {}
|
||||
freepats = {}
|
||||
freetype2 = {}
|
||||
#friar = {} # mio patch
|
||||
fribidi = {}
|
||||
#game-2048 = {} # rustc-serialize
|
||||
#gawk = {} # langinfo.h
|
||||
gcc13 = {}
|
||||
gdbserver = {}
|
||||
#gdk-pixbuf = {} # shared-mime-info
|
||||
gears = {}
|
||||
generaluser-gs = {}
|
||||
gettext = {}
|
||||
gigalomania = {}
|
||||
git = {}
|
||||
glib = {}
|
||||
glium = {}
|
||||
glutin = {}
|
||||
gnu-binutils = {}
|
||||
gnu-grep = {}
|
||||
gnu-make = {}
|
||||
#gstreamer = {} # conflict with thread local errno
|
||||
harfbuzz = {}
|
||||
#hematite = {} # needs crate patches for redox-unix
|
||||
init = {}
|
||||
initfs = {}
|
||||
installer = {}
|
||||
installer-gui = {}
|
||||
intel-one-mono = {}
|
||||
ion = {}
|
||||
ipcd = {}
|
||||
jansson = {}
|
||||
kernel = {}
|
||||
keyboard-sfx = {}
|
||||
lci = {}
|
||||
libc-bench = {}
|
||||
libffi = {}
|
||||
libgmp = {}
|
||||
libiconv = {}
|
||||
libjpeg = {}
|
||||
libogg = {}
|
||||
liborbital = {}
|
||||
libpng = {}
|
||||
libsodium = {}
|
||||
libvorbis = {}
|
||||
libxml2 = {}
|
||||
llvm = {}
|
||||
logd = {}
|
||||
lua54 = {}
|
||||
#mdp = {} # ncursesw
|
||||
mesa = {}
|
||||
mesa-glu = {}
|
||||
mgba = {}
|
||||
#miniserve = {} # actix
|
||||
nano = {}
|
||||
nasm = {}
|
||||
#ncdu = {} # fails to link with ncurses
|
||||
ncurses = {}
|
||||
#ncursesw = {} # mkstemp configure hang
|
||||
netdb = {}
|
||||
netstack = {}
|
||||
netsurf = {}
|
||||
netutils = {}
|
||||
neverball = {}
|
||||
#newlib = {} # obsolete
|
||||
#newlibtest = {} # obsolete
|
||||
nghttp2 = {}
|
||||
openjazz = {}
|
||||
openssl1 = {}
|
||||
openttd = {}
|
||||
openttd-opengfx = {}
|
||||
openttd-openmsx = {}
|
||||
openttd-opensfx = {}
|
||||
orbclient = {}
|
||||
orbdata = {}
|
||||
orbital = {}
|
||||
orbterm = {}
|
||||
orbutils = {}
|
||||
#orbutils-background = {} # needs recipe update
|
||||
#orbutils-launcher = {} # needs recipe update
|
||||
#orbutils-orblogin = {} # needs recipe update
|
||||
osdemo = {}
|
||||
#pango = {} # undefined references to std::__throw_system_error(int)
|
||||
#pastel = {} # needs crate patches for redox-unix
|
||||
patch = {}
|
||||
#pathfinder = {} # servo-fontconfig
|
||||
#pciids = {}
|
||||
pcre = {}
|
||||
perg = {}
|
||||
periodictable = {}
|
||||
#perl = {} # ctermid, tempnam, ttyname
|
||||
pixelcannon = {}
|
||||
pixman = {}
|
||||
#pkgar = {} # uses virtual Cargo.toml, needs recipe update
|
||||
pkg-config = {}
|
||||
pkgutils = {}
|
||||
pop-icon-theme = {}
|
||||
#powerline = {} # dirs
|
||||
prboom = {}
|
||||
procedural-wallpapers-rs = {}
|
||||
ptyd = {}
|
||||
#python = {} # getaddrinfo
|
||||
#qemu = {}
|
||||
ramfs = {}
|
||||
randd = {}
|
||||
readline = {}
|
||||
redoxerd = {}
|
||||
redox-fatfs = {}
|
||||
redoxfs = {}
|
||||
redox-games = {}
|
||||
redox-ssh = {}
|
||||
relibc = {}
|
||||
#relibc-tests = {} # madvise link error
|
||||
resist = {}
|
||||
#retroarch = {} # OS_TLSIndex not declared
|
||||
ripgrep = {}
|
||||
rodioplay = {}
|
||||
rs-nes = {}
|
||||
rust = {}
|
||||
rust64 = {}
|
||||
rust-cairo = {}
|
||||
rust-cairo-demo = {}
|
||||
rustual-boy = {}
|
||||
schismtracker = {}
|
||||
scummvm = {}
|
||||
sdl-gfx = {}
|
||||
#sdl-player = {} # wctype_t
|
||||
sdl1 = {}
|
||||
sdl1-image = {}
|
||||
sdl1-mixer = {}
|
||||
sdl1-ttf = {}
|
||||
sdl2 = {}
|
||||
sdl2-gears = {}
|
||||
sdl2-image = {}
|
||||
sdl2-mixer = {}
|
||||
sdl2-ttf = {}
|
||||
sed = {}
|
||||
#servo = {} # some more crates to port
|
||||
#shared-mime-info = {} # intltool-update out of date
|
||||
shellharden = {}
|
||||
shellstorm = {}
|
||||
smith = {}
|
||||
sodium = {}
|
||||
sopwith = {}
|
||||
#ssh = {}
|
||||
strace = {}
|
||||
syobonaction = {}
|
||||
terminfo = {}
|
||||
#termplay = {} # backtrace cannot find link.h
|
||||
timidity = {}
|
||||
ttf-hack = {}
|
||||
userutils = {}
|
||||
uutils = {}
|
||||
vice = {}
|
||||
vim = {}
|
||||
vttest = {}
|
||||
vvvvvv = {}
|
||||
#webrender = {} # unwind
|
||||
#wesnoth = {}
|
||||
#winit = {} # tzset
|
||||
xz = {}
|
||||
zerod = {}
|
||||
zlib = {}
|
|
@ -1,14 +0,0 @@
|
|||
# Default desktop configuration
|
||||
|
||||
include = ["../desktop-minimal.toml"]
|
||||
|
||||
# Override the default settings here
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
# filesystem_size = 1024
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
# example = {}
|
|
@ -1,10 +0,0 @@
|
|||
# Minimal configuration
|
||||
|
||||
include = ["../../server-minimal.toml"]
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
filesystem_size = 256
|
||||
# EFI partition size in MiB
|
||||
efi_partition_size = 128
|
|
@ -1,3 +0,0 @@
|
|||
# Configuration for using resist
|
||||
|
||||
include = ["../resist.toml"]
|
|
@ -1,14 +0,0 @@
|
|||
# Minimal configuration
|
||||
|
||||
include = ["../server-minimal.toml"]
|
||||
|
||||
# Override the default settings here
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
# filesystem_size = 1024
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
# example = {}
|
|
@ -1,26 +0,0 @@
|
|||
# Configuration for using acid
|
||||
|
||||
include = ["base.toml"]
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
filesystem_size = 256
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
acid = {}
|
||||
coreutils = {}
|
||||
ion = {}
|
||||
|
||||
[[files]]
|
||||
path = "/usr/lib/init.d/10_acid"
|
||||
data = """
|
||||
export RUST_BACKTRACE full
|
||||
acid
|
||||
acid create_test
|
||||
acid switch
|
||||
acid tls
|
||||
acid thread
|
||||
shutdown
|
||||
"""
|
168
config/base.toml
168
config/base.toml
|
@ -1,168 +0,0 @@
|
|||
# Base configuration: This configuration is meant to be included by
|
||||
# other configurations rather than use directly. It is the greatest
|
||||
# common divisor of all other configurations and misses several
|
||||
# parts necessary to create a bootable system.
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Do not prompt if settings are not defined
|
||||
prompt = false
|
||||
|
||||
[packages]
|
||||
bootloader = {}
|
||||
bootstrap = {}
|
||||
escalated = {}
|
||||
initfs = {}
|
||||
ipcd = {}
|
||||
kernel = {}
|
||||
ptyd = {}
|
||||
uutils = {}
|
||||
|
||||
## Configuration files
|
||||
[[files]]
|
||||
path = "/usr/lib/init.d/00_base"
|
||||
data = """
|
||||
# clear and recreate tmpdir with 0o1777 permission
|
||||
rm -r /tmp
|
||||
mkdir -m a=rwxt /tmp
|
||||
|
||||
ipcd
|
||||
ptyd
|
||||
escalated
|
||||
"""
|
||||
|
||||
[[files]]
|
||||
path = "/etc/hostname"
|
||||
data = """
|
||||
redox
|
||||
"""
|
||||
|
||||
# https://www.freedesktop.org/software/systemd/man/latest/os-release.html
|
||||
[[files]]
|
||||
path = "/usr/lib/os-release"
|
||||
data = """
|
||||
PRETTY_NAME="Redox OS 0.8.0"
|
||||
NAME="Redox OS"
|
||||
VERSION_ID="0.8.0"
|
||||
VERSION="0.8.0"
|
||||
ID="redox-os"
|
||||
|
||||
HOME_URL="https://redox-os.org/"
|
||||
DOCUMENTATION_URL="https://redox-os.org/docs/"
|
||||
SUPPORT_URL="https://redox-os.org/community/"
|
||||
"""
|
||||
# FIXME maybe add VARIANT= and VARIANT_ID= keys depending on the chosen configuration?
|
||||
|
||||
[[files]]
|
||||
path = "/etc/os-release"
|
||||
data = "../usr/lib/os-release"
|
||||
symlink = true
|
||||
|
||||
## Symlinks for usrmerge
|
||||
[[files]]
|
||||
path = "/usr"
|
||||
data = ""
|
||||
directory = true
|
||||
mode = 0o755
|
||||
|
||||
[[files]]
|
||||
path = "/usr/bin"
|
||||
data = ""
|
||||
directory = true
|
||||
mode = 0o755
|
||||
|
||||
[[files]]
|
||||
path = "/bin"
|
||||
data = "usr/bin"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/usr/include"
|
||||
data = ""
|
||||
directory = true
|
||||
mode = 0o755
|
||||
|
||||
[[files]]
|
||||
path = "/include"
|
||||
data = "usr/include"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/usr/lib"
|
||||
data = ""
|
||||
directory = true
|
||||
mode = 0o755
|
||||
|
||||
[[files]]
|
||||
path = "/lib"
|
||||
data = "usr/lib"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/usr/share"
|
||||
data = ""
|
||||
directory = true
|
||||
mode = 0o755
|
||||
|
||||
[[files]]
|
||||
path = "/share"
|
||||
data = "usr/share"
|
||||
symlink = true
|
||||
|
||||
## Device file symlinks
|
||||
[[files]]
|
||||
path = "/dev/null"
|
||||
data = "null:"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/dev/random"
|
||||
data = "rand:"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/dev/urandom"
|
||||
data = "rand:"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/dev/zero"
|
||||
data = "zero:"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/dev/tty"
|
||||
data = "libc:tty"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/dev/stdin"
|
||||
data = "libc:stdin"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/dev/stdout"
|
||||
data = "libc:stdout"
|
||||
symlink = true
|
||||
|
||||
[[files]]
|
||||
path = "/dev/stderr"
|
||||
data = "libc:stderr"
|
||||
symlink = true
|
||||
|
||||
# User settings
|
||||
[users.root]
|
||||
password = "password"
|
||||
uid = 0
|
||||
gid = 0
|
||||
name = "root"
|
||||
home = "/root"
|
||||
|
||||
[users.user]
|
||||
# Password is unset
|
||||
password = ""
|
||||
|
||||
# Group settings
|
||||
[groups.sudo]
|
||||
gid = 1
|
||||
members = ["user"]
|
|
@ -1,30 +0,0 @@
|
|||
# Default desktop configuration
|
||||
|
||||
include = ["server-minimal.toml"]
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
filesystem_size = 128
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
drivers = {}
|
||||
orbdata = {}
|
||||
orbital = {}
|
||||
orbterm = {}
|
||||
orbutils-background = {}
|
||||
orbutils-launcher = {}
|
||||
orbutils-orblogin = {}
|
||||
|
||||
[[files]]
|
||||
path = "/usr/lib/init.d/00_drivers"
|
||||
data = """
|
||||
pcid /etc/pcid.d/
|
||||
"""
|
||||
|
||||
[[files]]
|
||||
path = "/usr/lib/init.d/20_orbital"
|
||||
data = """
|
||||
orbital orblogin launcher
|
||||
"""
|
|
@ -1,33 +0,0 @@
|
|||
# Default desktop configuration
|
||||
|
||||
include = ["server.toml"]
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
filesystem_size = 512
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
audiod = {}
|
||||
installer-gui = {}
|
||||
netsurf = {}
|
||||
orbdata = {}
|
||||
orbital = {}
|
||||
orbterm = {}
|
||||
orbutils = {}
|
||||
|
||||
[[files]]
|
||||
path = "/usr/lib/init.d/20_orbital"
|
||||
data = """
|
||||
audiod
|
||||
orbital orblogin launcher
|
||||
"""
|
||||
|
||||
# Override console config to not switch to VT 2
|
||||
[[files]]
|
||||
path = "/usr/lib/init.d/30_console"
|
||||
data = """
|
||||
getty 2
|
||||
getty debug: -J
|
||||
"""
|
|
@ -1,27 +0,0 @@
|
|||
# Configuration for development, includes cargo and rustc
|
||||
|
||||
include = ["desktop.toml"]
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
filesystem_size = 2048
|
||||
# Do not prompt if settings are not defined
|
||||
prompt = false
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
cargo = {}
|
||||
crates-io-index = {}
|
||||
gcc13 = {}
|
||||
gnu-binutils = {}
|
||||
gnu-make = {}
|
||||
rust = {}
|
||||
|
||||
[[files]]
|
||||
path = "/home/user/example.rs"
|
||||
data = """
|
||||
fn main() {
|
||||
println!("Hello, Redox!");
|
||||
}
|
||||
"""
|
|
@ -1,3 +0,0 @@
|
|||
# Configuration for using acid
|
||||
|
||||
include = ["../acid.toml"]
|
|
@ -1,47 +0,0 @@
|
|||
# This is the CI configuration file
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Do not prompt if settings are not defined
|
||||
prompt = false
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
audiod = {}
|
||||
bootloader = {}
|
||||
bootstrap = {}
|
||||
ca-certificates = {}
|
||||
contain = {}
|
||||
coreutils = {}
|
||||
dash = {}
|
||||
diffutils = {}
|
||||
drivers = {}
|
||||
escalated = {}
|
||||
extrautils = {}
|
||||
findutils = {}
|
||||
initfs = {}
|
||||
installer = {}
|
||||
installer-gui = {}
|
||||
ion = {}
|
||||
ipcd = {}
|
||||
kernel = {}
|
||||
nano = {}
|
||||
netdb = {}
|
||||
netstack = {}
|
||||
netsurf = {}
|
||||
netutils = {}
|
||||
orbdata = {}
|
||||
orbital = {}
|
||||
orbterm = {}
|
||||
orbutils = {}
|
||||
pkgutils = {}
|
||||
ptyd = {}
|
||||
redoxfs = {}
|
||||
relibc = {}
|
||||
resist = {}
|
||||
smith = {}
|
||||
userutils = {}
|
||||
uutils = {}
|
||||
vim = {}
|
||||
|
||||
#TODO: Add more packages
|
|
@ -1,70 +0,0 @@
|
|||
##############################################################################
|
||||
# Redox Demo Configuration #
|
||||
# #
|
||||
# This file defines the setup of the Redox Demo system. #
|
||||
# #
|
||||
# The "[packages]" section specifies what packages are installed in the #
|
||||
# filesystem prior to booting the system. During build, these packages must #
|
||||
# have a recipe defined in the config folder (see the Redox Book, #
|
||||
# Chapter 5.1). The first group of packages is mandatory for the system to #
|
||||
# function, although some items can be removed for special builds, #
|
||||
# e.g. The Orbital GUI is not required for a headless server. #
|
||||
# #
|
||||
# Items in the "Developer Tools" and "Games" section are optional. You can #
|
||||
# add your own programs here. #
|
||||
# #
|
||||
# The "[users]" section creates user id's and passwords. Each user will have #
|
||||
# a home directory at boot. #
|
||||
# #
|
||||
# The "[[files]]" section contains files needed by the system. If you need #
|
||||
# create a file, e.g. a config file for a program you are adding, you can do #
|
||||
# it here. #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
include = ["../desktop.toml"]
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
filesystem_size = 512
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
# Games
|
||||
dosbox = {}
|
||||
freedoom = {}
|
||||
prboom = {}
|
||||
redox-games = {}
|
||||
|
||||
# Demos
|
||||
pixelcannon = {}
|
||||
|
||||
# MIDI
|
||||
freepats = {}
|
||||
|
||||
[[files]]
|
||||
path = "/home/user/Welcome.txt"
|
||||
data = """
|
||||
##############################################################################
|
||||
# #
|
||||
# Welcome to 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 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. #
|
||||
# #
|
||||
# The website can be found at https://www.redox-os.org. #
|
||||
# #
|
||||
# For things to try on Redox, please see #
|
||||
# https://doc.redox-os.org/book/ch02-06-trying-out-redox.html #
|
||||
# #
|
||||
##############################################################################
|
||||
"""
|
|
@ -1,14 +0,0 @@
|
|||
# Default desktop configuration
|
||||
|
||||
include = ["../desktop-minimal.toml"]
|
||||
|
||||
# Override the default settings here
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
# filesystem_size = 1024
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
# example = {}
|
|
@ -1,14 +0,0 @@
|
|||
# Default desktop configuration
|
||||
|
||||
include = ["../desktop.toml"]
|
||||
|
||||
# Override the default settings here
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
# filesystem_size = 1024
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
# example = {}
|
|
@ -1,14 +0,0 @@
|
|||
# Configuration for development, includes cargo and rustc
|
||||
|
||||
include = ["../dev.toml"]
|
||||
|
||||
# Override the default settings here
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
# filesystem_size = 1024
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
# example = {}
|
|
@ -1,40 +0,0 @@
|
|||
# Jeremy's configuration
|
||||
|
||||
include = ["../desktop.toml"]
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
filesystem_size = 4000
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
# apps
|
||||
cosmic-text = {}
|
||||
pixelcannon = {}
|
||||
sodium = {}
|
||||
|
||||
# cli
|
||||
acid = {}
|
||||
cleye = {}
|
||||
ripgrep = {}
|
||||
|
||||
# demos
|
||||
cpal = {}
|
||||
orbclient = {}
|
||||
rodioplay = {}
|
||||
winit = {}
|
||||
|
||||
# games
|
||||
dosbox = {}
|
||||
eduke32 = {}
|
||||
freedoom = {}
|
||||
prboom = {}
|
||||
redox-games = {}
|
||||
|
||||
# stuff
|
||||
freepats = {}
|
||||
generaluser-gs = {}
|
||||
jeremy = {}
|
||||
keyboard-sfx = {}
|
||||
ttf-hack = {}
|
|
@ -1,3 +0,0 @@
|
|||
# Configuration for using resist
|
||||
|
||||
include = ["../resist.toml"]
|
|
@ -1,14 +0,0 @@
|
|||
# Minimal configuration
|
||||
|
||||
include = ["../server-minimal.toml"]
|
||||
|
||||
# Override the default settings here
|
||||
|
||||
# General settings
|
||||
[general]
|
||||
# Filesystem size in MiB
|
||||
# filesystem_size = 1024
|
||||
|
||||
# Package settings
|
||||
[packages]
|
||||
# example = {}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue