Update OSDK guide

This commit is contained in:
Jianfeng Jiang
2024-02-27 09:30:26 +00:00
committed by Tate, Hongliang Tian
parent 16298008fc
commit cab5cf9574
6 changed files with 343 additions and 5 deletions

View File

@ -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]()

View File

@ -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
```

View File

@ -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.

View File

@ -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)

View File

@ -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.

View File

@ -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
```