Format OSDK documentation

This commit is contained in:
Jianfeng Jiang
2024-03-01 03:23:47 +00:00
committed by Tate, Hongliang Tian
parent 7fef686136
commit a51b3c7076
18 changed files with 397 additions and 162 deletions

View File

@ -2,16 +2,27 @@
## 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 (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.
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.
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:
To run a kernel developed by OSDK with QEMU,
the following tools need to be installed:
- Rust >= 1.75.0
- cargo-binutils
- gcc
@ -20,9 +31,11 @@ To run a kernel developed by OSDK with QEMU, the following tools need to be inst
- ovmf
- xorriso
About how to install Rust, you can refer to the [official site](https://www.rust-lang.org/tools/install).
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
`cargo-binutils` can be installed
after Rust is installed by
```bash
cargo install cargo-binutils
```
@ -34,13 +47,15 @@ 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
`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
If `cargo-osdk` is already installed,
the tool can be upgraded by
```bash
cargo install --force cargo-osdk
```

View File

@ -1,10 +1,16 @@
# 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.
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:
Creating a new kernel project is simple.
You only need to execute the following command:
```bash
cargo osdk new --kernel myos
@ -20,11 +26,16 @@ 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.
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:
The generated directory
for both the kernel project and library project
contains the following contents:
```text
myos/
@ -39,60 +50,38 @@ myos/
#### 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.
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]`.
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());
}
}
{{#include ../../../../osdk/src/commands/new/kernel.template}}
```
#### Library project
The `src/lib.rs` of library project only contains a simple kernel mode unit test.
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());
}
}
{{#include ../../../../osdk/src/commands/new/lib.template}}
```
### `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.
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]
@ -106,7 +95,14 @@ 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.
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]
@ -127,4 +123,5 @@ args = [
### `rust-toolchain.toml`
The Rust toolchain for the kernel. It aligns with the toolchain of the Asterinas framework.
The Rust toolchain for the kernel.
It aligns with the toolchain of the Asterinas framework.

View File

@ -1,8 +1,11 @@
# 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.
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:
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
@ -10,7 +13,8 @@ cargo osdk new --kernel myos && cd myos
## Build the project
To build the project and its dependencies, simply type:
To build the project and its dependencies,
simply type:
```bash
cargo osdk build
@ -18,15 +22,22 @@ cargo osdk build
## Run the project
To launch the kernel with QEMU, use the following command:
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.
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.
**Note**: Only kernel projects (the projects
that defines the function marked with `#[aster_main]`)
can be run;
library projects cannot.
## Test the project
@ -37,9 +48,11 @@ To run the kernel mode tests, use the following command:
cargo osdk test
```
OSDK will run all the kernel mode tests in the crate.
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:
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
@ -47,7 +60,11 @@ 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:
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)

View File

@ -1,13 +1,86 @@
# 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.
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.
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.
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.
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.
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.
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,6 +1,10 @@
# 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.
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
@ -45,9 +49,13 @@ myworkspace/
Cargo.toml
```
In addition to the two projects, OSDK will also generate `OSDK.toml` and `rust-toolchain.toml` at the root of the workspace.
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:
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 {
@ -63,15 +71,15 @@ Then, add a dependency on `mymodule` to `myos/Cargo.toml`:
mymodule = { path = "../mymodule" }
```
In `myos/src/lib.rs`, modify the main function as follows. This function will call the function from `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;
fn kernel_main() {
let avail_mem_as_mb = mymodule::available_memory() / 1_000_000;
println!("The available memory is {} MB", avail_mem_as_mb);
abort();
}
```
## Building and Running the kernel
@ -83,17 +91,23 @@ cargo osdk build
cargo osdk run
```
If everything goes well, you will see the output from the guest kernel.
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:
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:
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