mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 17:03:23 +00:00
Update OSDK guide
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
16298008fc
commit
cab5cf9574
@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
# Asterinas OSDK
|
# Asterinas OSDK
|
||||||
|
|
||||||
* [OSDK User Guide]()
|
* [OSDK User Guide](osdk/guide/README.md)
|
||||||
* [Why OSDK]()
|
* [Why OSDK](osdk/guide/why.md)
|
||||||
* [Creating an OS Project]()
|
* [Creating an OS Project](osdk/guide/create-project.md)
|
||||||
* [Testing or Running an OS Project]()
|
* [Testing or Running an OS Project](osdk/guide/run-project.md)
|
||||||
* [Working in a Workspace]()
|
* [Working in a Workspace](osdk/guide/work-in-workspace.md)
|
||||||
* [OSDK User Reference]()
|
* [OSDK User Reference]()
|
||||||
* [Commands]()
|
* [Commands]()
|
||||||
* [cargo osdk new]()
|
* [cargo osdk new]()
|
||||||
|
@ -1 +1,46 @@
|
|||||||
# OSDK User Guide
|
# OSDK User Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
OSDK (short for Operating System Development Kit) is designed to simplify the development of Rust operating systems. It aims to streamline the process by leveraging [the framekernel architecture](../../kernel/the-framekernel-architecture.md).
|
||||||
|
|
||||||
|
OSDK provides a command-line tool `cargo-osdk`, which facilitates project management for those developed on the framekernel architecture. `cargo-osdk` can be used as a subcommand of Cargo. Much like Cargo for Rust projects, `cargo-osdk` enables building, running, and testing projects conveniently.
|
||||||
|
|
||||||
|
## Install OSDK
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
Currently, OSDK only works on x86_64 ubuntu system. We will add support for more operating systems in the future.
|
||||||
|
|
||||||
|
To run a kernel developed by OSDK with QEMU, the following tools need to be installed:
|
||||||
|
- Rust >= 1.75.0
|
||||||
|
- cargo-binutils
|
||||||
|
- gcc
|
||||||
|
- qemu-system-x86_64
|
||||||
|
- grub-mkrescue
|
||||||
|
- ovmf
|
||||||
|
- xorriso
|
||||||
|
|
||||||
|
About how to install Rust, you can refer to the [official site](https://www.rust-lang.org/tools/install).
|
||||||
|
|
||||||
|
`cargo-binutils` can be installed after Rust is installed by
|
||||||
|
```bash
|
||||||
|
cargo install cargo-binutils
|
||||||
|
```
|
||||||
|
|
||||||
|
Other tools can be installed by
|
||||||
|
```bash
|
||||||
|
apt install build-essential grub2-common qemu-system-x86 ovmf xorriso
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
|
`cargo-osdk` is published on [crates.io](https://crates.io/), and can be installed by
|
||||||
|
```bash
|
||||||
|
cargo install cargo-osdk
|
||||||
|
```
|
||||||
|
|
||||||
|
### Upgrate
|
||||||
|
If `cargo-osdk` is already installed, the tool can be upgraded by
|
||||||
|
```bash
|
||||||
|
cargo install --force cargo-osdk
|
||||||
|
```
|
||||||
|
@ -1 +1,130 @@
|
|||||||
# Creating an OS Project
|
# Creating an OS Project
|
||||||
|
|
||||||
|
OSDK can be used to create a new kernel project or a new library project. A kernel project defines the entry point of the kernel and can be run with QEMU. A library project can provide certain OS functionalities and be imported by other OSes.
|
||||||
|
|
||||||
|
## Creating a new kernel project
|
||||||
|
|
||||||
|
Creating a new kernel project is simple. You only need to execute the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk new --kernel myos
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating a new library project
|
||||||
|
|
||||||
|
Creating a new library project requires just one command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk new mylib
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generated files
|
||||||
|
|
||||||
|
Next, we will introduce the contents of the generated project in detail. If you don't wish to delve into the details, you can skip the following sections.
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
|
The generated directory for both the kernel project and library project contains the following contents:
|
||||||
|
|
||||||
|
```text
|
||||||
|
myos/
|
||||||
|
src/
|
||||||
|
lib.rs
|
||||||
|
Cargo.toml
|
||||||
|
OSDK.toml
|
||||||
|
rust-toolchain.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
### `src/lib.rs`
|
||||||
|
|
||||||
|
#### Kernel project
|
||||||
|
|
||||||
|
The `src/lib.rs` file contains the code for a simple kernel. The function marked with the `#[aster_main]` macro is considered the kernel entry point by OSDK. The kernel will print `Hello world from the guest kernel!` to the console and then abort.
|
||||||
|
|
||||||
|
There is also a code snippet that demonstrates how to write kernel mode unit tests. It follows a similar code pattern as user mode unit tests. The test module is marked with the `#[cfg(ktest)]` macro, and each test case is marked with `#[ktest]`.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate ktest;
|
||||||
|
|
||||||
|
use aster_frame::prelude::*;
|
||||||
|
|
||||||
|
#[aster_main]
|
||||||
|
fn kernel_main() -> ! {
|
||||||
|
println!("Hello world from guest kernel!");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ktest)]
|
||||||
|
mod tests {
|
||||||
|
#[ktest]
|
||||||
|
fn it_works() {
|
||||||
|
let memory_regions = aster_frame::boot::memory_regions();
|
||||||
|
assert!(!memory_regions.is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Library project
|
||||||
|
|
||||||
|
The `src/lib.rs` of library project only contains a simple kernel mode unit test.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate ktest;
|
||||||
|
extern crate aster_frame;
|
||||||
|
|
||||||
|
#[cfg(ktest)]
|
||||||
|
mod tests {
|
||||||
|
#[ktest]
|
||||||
|
fn it_works() {
|
||||||
|
let memory_regions = aster_frame::boot::memory_regions();
|
||||||
|
assert!(!memory_regions.is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Cargo.toml`
|
||||||
|
|
||||||
|
The `Cargo.toml` file is the Rust project manifest. In addition to the contents of a normal Rust project, OSDK will add the dependencies of the Asterinas framework to the file. The dependency version may change over time.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies.aster_frame]
|
||||||
|
git = "https://github.com/asterinas/asterinas"
|
||||||
|
branch = "main"
|
||||||
|
|
||||||
|
[dependencies.ktest]
|
||||||
|
git = "https://github.com/asterinas/asterinas"
|
||||||
|
branch = "main"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `OSDK.toml`
|
||||||
|
|
||||||
|
The `OSDK.toml` file is a manifest that defines the exact behavior of OSDK. By default, it contains the following contents. It includes settings on how to start QEMU to run a kernel. The meaning of each key can be found in the [manifest documentation](../reference/manifest.md). Please avoid changing the default settings unless you know what you are doing.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[boot]
|
||||||
|
ovmf = "/usr/share/OVMF"
|
||||||
|
[qemu]
|
||||||
|
machine = "q35"
|
||||||
|
args = [
|
||||||
|
"--no-reboot",
|
||||||
|
"-m 2G",
|
||||||
|
"-nographic",
|
||||||
|
"-serial chardev:mux",
|
||||||
|
"-monitor chardev:mux",
|
||||||
|
"-chardev stdio,id=mux,mux=on,signal=off",
|
||||||
|
"-display none",
|
||||||
|
"-device isa-debug-exit,iobase=0xf4,iosize=0x04",
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### `rust-toolchain.toml`
|
||||||
|
|
||||||
|
The Rust toolchain for the kernel. It aligns with the toolchain of the Asterinas framework.
|
||||||
|
@ -1 +1,54 @@
|
|||||||
# Testing or Running an OS Project
|
# Testing or Running an OS Project
|
||||||
|
|
||||||
|
OSDK allows for convenient building, running, and testing of an OS project. The following example shows the typical workflow.
|
||||||
|
|
||||||
|
Suppose you have created a new kernel project named `myos` and you are in the project directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk new --kernel myos && cd myos
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build the project
|
||||||
|
|
||||||
|
To build the project and its dependencies, simply type:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run the project
|
||||||
|
|
||||||
|
To launch the kernel with QEMU, use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk run
|
||||||
|
```
|
||||||
|
|
||||||
|
OSDK will boot the kernel and initialize OS resources like the console for output, and then hand over control to the kernel entry point to execute the kernel code.
|
||||||
|
|
||||||
|
**Note**: Only kernel projects (the projects that defines the function marked with `#[aster_main]`) can be run; library projects cannot.
|
||||||
|
|
||||||
|
|
||||||
|
## Test the project
|
||||||
|
|
||||||
|
To run the kernel mode tests, use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk test
|
||||||
|
```
|
||||||
|
|
||||||
|
OSDK will run all the kernel mode tests in the crate.
|
||||||
|
|
||||||
|
If you want to run a specific test with a given name, for example, if the test is named `foo`, use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk test foo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
Both `build`, `run`, and `test` commands accept options to control their behavior, such as how to compile and launch the kernel. The following documentations provide details on all the available options:
|
||||||
|
|
||||||
|
- [build options](../reference/commands/build.md)
|
||||||
|
- [run options](../reference/commands/run.md)
|
||||||
|
- [test options](../reference/commands/test.md)
|
||||||
|
@ -1 +1,13 @@
|
|||||||
# Why OSDK
|
# Why OSDK
|
||||||
|
|
||||||
|
OSDK is designed to elevate the development experience for Rust OS developers to the ease and convenience typically associated with Rust application development. Imagine crafting operating systems with the same simplicity as applications! This is important to Asterinas as we believe that the project's success is intricately tied to the productivity and happiness of its developers. So OSDK is here to upgrade your dev experience.
|
||||||
|
|
||||||
|
To be honest, writing OS kernels is hard. Even when you're using Rust, which is a total game-changer for OS devs, the challenge stands tall. There is a bunch of reasons.
|
||||||
|
|
||||||
|
First, it is hard to write a new kernel from scratch. Everything that has been taken for granted by application developers are gone: no stack, no heap, no threads, not even the standard I/O. It's just you and the no_std world of Rust. You have to implement these basic programming primitives by getting your hands dirty with the most low-level, error-prone, nitty-gritty of computer architecture. It's a journey of learning, doing, and a whole lot of finger-crossing to make sure everything clicks into place. This means a high entry bar for new OS creators.
|
||||||
|
|
||||||
|
Second, it is hard to reuse OS-related libraries/crates across projects. Think about it: most applications share a common groundwork, like libc, Rust's std library, or an SDK. This isn't the case with kernels -- they lack this shared starting point, forcing each one to craft its own set of tools from the ground up. Take device drivers, for example. They often need DMA-capable buffers for chatting with hardware, but since every kernel has its own DMA API flavor, a driver for one kernel is pretty much a no-go for another. This means that for each new kernel out there, developers find themselves having to 'reinvent the wheel' for many core components that are standard in other kernels.
|
||||||
|
|
||||||
|
Third, it is hard to do unit tests for OS functionalities. Unit testing plays a crucial role in ensuring code quality, but when you're dealing with a monolithic kernel like Linux, it's like a spaghetti bowl of intertwined parts. Trying to isolate one part for testing? Forget about it. You'd have to boot the whole kernel just to test a slice of it. Loadable kernel modules are no exception: you can't test them without plugging them into a live kernel. This monolithic approach to unit testing is slow and unproductive as it performs the job of unit tests at a price of integration tests. Regardless of the kernel architecture, Rust's built-in unit testing facility is not suited for kernel development, leaving each kernel to hack together their own testing frameworks.
|
||||||
|
|
||||||
|
Last, it is hard to avoid writing unsafe Rust in a Rust kernel. Rust brings safety... well, at least for Rust applications, where you can pretty much stay in the wonderland of safe Rust all the way through. But for a Rust kernel, one cannot help but use unsafe Rust. This is because, among other reasons, low-level operations (e.g., managing page tables, doing context switching, handling interrupts, and interacting with devices) have to be expressed with unsafe Rust features (like executing assembly code or dereferencing raw pointers). The misuse of unsafe Rust could lead to various safety and security issues, as reported by [RustSec Advisory Database](https://rustsec.org). Despite having [a whole book](https://doc.rust-lang.org/nomicon/) to document "the Dark Arts of Unsafe Rust", unsafe Rust is still tricky to use correctly, even among reasoned Rust developers.
|
||||||
|
@ -1 +1,100 @@
|
|||||||
# Working in a Workspace
|
# Working in a Workspace
|
||||||
|
|
||||||
|
Typically, an operating system may consist of multiple crates, and these crates may be organized in a workspace. OSDK also supports managing projects in a workspace. Below is an example that demonstrates how to create, build, run, and test projects in a workspace.
|
||||||
|
|
||||||
|
## Creating a new workspace
|
||||||
|
|
||||||
|
Create a new workspace by executing the following commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir myworkspace && cd myworkspace
|
||||||
|
touch Cargo.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, add the following content to `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[workspace]
|
||||||
|
members = []
|
||||||
|
resolver = "2"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating a kernel project and a library project
|
||||||
|
|
||||||
|
The two projects can be created using the following commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk new --kernel myos
|
||||||
|
cargo osdk new mymodule
|
||||||
|
```
|
||||||
|
|
||||||
|
The generated directory structure will be as follows:
|
||||||
|
|
||||||
|
```text
|
||||||
|
myworkspace/
|
||||||
|
Cargo.toml
|
||||||
|
OSDK.toml
|
||||||
|
rust-toolchain.toml
|
||||||
|
myos/
|
||||||
|
src/
|
||||||
|
lib.rs
|
||||||
|
Cargo.toml
|
||||||
|
mymodule/
|
||||||
|
src/
|
||||||
|
lib.rs
|
||||||
|
Cargo.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
In addition to the two projects, OSDK will also generate `OSDK.toml` and `rust-toolchain.toml` at the root of the workspace.
|
||||||
|
|
||||||
|
Next, add the following function to `mymodule/src/lib.rs`. This function will calculate the available memory after booting:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub fn available_memory() -> usize {
|
||||||
|
let regions = aster_frame::boot::memory_regions();
|
||||||
|
regions.iter().map(|region| region.len()).sum()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, add a dependency on `mymodule` to `myos/Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
mymodule = { path = "../mymodule" }
|
||||||
|
```
|
||||||
|
|
||||||
|
In `myos/src/lib.rs`, modify the main function as follows. This function will call the function from `mymodule`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[aster_main]
|
||||||
|
fn kernel_main() -> ! {
|
||||||
|
let avail_mem_as_mb = mymodule::available_memory() / 0x1_000_000;
|
||||||
|
println!("The available memory is {} MB", avail_mem_as_mb);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building and Running the kernel
|
||||||
|
|
||||||
|
Build and run the project using the following commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk build
|
||||||
|
cargo osdk run
|
||||||
|
```
|
||||||
|
|
||||||
|
If everything goes well, you will see the output from the guest kernel.
|
||||||
|
|
||||||
|
## Running unit test
|
||||||
|
|
||||||
|
You can run test cases from all crates by using the following command in the workspace folder:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo osdk test
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to run test cases from a specific crate, navigate to the crate's folder and run `cargo osdk test`. For example, if you want to test `myos`, use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd myos && cargo osdk test
|
||||||
|
```
|
||||||
|
Reference in New Issue
Block a user