Compare commits

..

10 Commits

Author SHA1 Message Date
Philipp Oppermann
d21a78dc0b Switch back to official nightly 2020-03-22 17:30:00 +01:00
Philipp Oppermann
0186f65ece Use cooked-waker crate for creating wakers 2020-03-22 17:24:58 +01:00
Philipp Oppermann
2772abc8eb Implement proper wakeups using RawWaker 2020-03-22 16:54:47 +01:00
Philipp Oppermann
51f90236a5 Base dummy waker on RawWaker to avoid allocations
The Wake trait is based on Arc, which leads to deallocation on wakes. Since interrupts should not (de)allocate, this can lead to a deadlock.
2020-03-22 16:11:25 +01:00
Philipp Oppermann
90abd5c8c5 Add a keyboard task that prints keypresses 2020-03-22 12:45:24 +01:00
Philipp Oppermann
a6273614e4 Add waker support to ScancodeStream 2020-03-22 12:16:17 +01:00
Philipp Oppermann
3a2a468a0b Add a ScancodeStream based on the SCANCODE_QUEUE 2020-03-22 12:12:11 +01:00
Philipp Oppermann
05f6abd261 Fill the scancode queue on keyboard interrupts 2020-03-22 12:11:09 +01:00
Philipp Oppermann
255982a8b7 Implement scancode queue 2020-03-20 13:03:41 +01:00
Philipp Oppermann
f885f17b70 Implement a simple poll-loop executor 2020-03-19 16:46:37 +01:00
25 changed files with 627 additions and 370 deletions

5
.cargo/config Normal file
View File

@@ -0,0 +1,5 @@
[build]
target = "x86_64-blog_os.json"
[target.'cfg(target_os = "none")']
runner = "bootimage runner"

View File

@@ -1,9 +0,0 @@
[unstable]
build-std = ["core", "compiler_builtins", "alloc"]
build-std-features = ["compiler-builtins-mem"]
[build]
target = "x86_64-blog_os.json"
[target.'cfg(target_os = "none")']
runner = "bootimage runner"

96
.github/workflows/build-code.yml vendored Normal file
View File

@@ -0,0 +1,96 @@
name: Build Code
on:
push:
branches:
- '*'
- '!staging.tmp'
tags:
- '*'
schedule:
- cron: '40 3 * * *' # every day at 3:40
pull_request:
jobs:
test:
name: "Test"
strategy:
matrix:
platform: [
ubuntu-latest,
macos-latest,
windows-latest
]
runs-on: ${{ matrix.platform }}
timeout-minutes: 15
steps:
- name: "Checkout Repository"
uses: actions/checkout@v1
- name: Install Rustup
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly
echo ::add-path::$HOME/.cargo/bin
if: runner.os == 'macOS'
- name: "Print Rust Version"
run: |
rustc -Vv
cargo -Vv
- name: "Install Rustup Components"
run: rustup component add rust-src llvm-tools-preview
- name: "Install cargo-xbuild"
run: cargo install cargo-xbuild --debug
- name: "Install bootimage"
run: cargo install bootimage --debug
- name: "Run cargo xbuild"
run: cargo xbuild
- name: "Create Bootimage"
run: cargo bootimage
# install QEMU
- name: Install QEMU (Linux)
run: sudo apt update && sudo apt install qemu-system-x86
if: runner.os == 'Linux'
- name: Install QEMU (macOS)
run: brew install qemu
if: runner.os == 'macOS'
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
- name: Install Scoop (Windows)
run: |
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
echo ::add-path::$HOME\scoop\shims
if: runner.os == 'Windows'
shell: pwsh
- name: Install QEMU (Windows)
run: scoop install qemu
if: runner.os == 'Windows'
shell: pwsh
- name: "Print QEMU Version"
run: qemu-system-x86_64 --version
- name: "Run cargo xtest"
run: cargo xtest
check_formatting:
name: "Check Formatting"
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- uses: actions/checkout@v1
- name: "Use the latest Rust nightly with rustfmt"
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
profile: minimal
components: rustfmt
override: true
- run: cargo fmt -- --check

View File

@@ -1,130 +0,0 @@
name: Code
on:
push:
branches:
- '*'
- '!staging.tmp'
tags:
- '*'
schedule:
- cron: '40 3 * * *' # every day at 3:40
pull_request:
workflow_dispatch:
jobs:
check:
name: Check
strategy:
fail-fast: false
matrix:
platform: [
ubuntu-latest,
macos-latest,
windows-latest
]
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Install Rust Toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
- name: Install `rust-src` Rustup Component
run: rustup component add rust-src
- name: Run `cargo check`
uses: actions-rs/cargo@v1
with:
command: check
test:
name: Test
strategy:
fail-fast: false
matrix:
platform: [
ubuntu-latest,
macos-latest,
windows-latest
]
runs-on: ${{ matrix.platform }}
steps:
- name: Install Rust Toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
- name: Install bootimage
run: cargo install bootimage --debug
- name: Checkout Repository
uses: actions/checkout@v2
- name: Install Rustup Components
run: rustup component add rust-src llvm-tools-preview
- name: Run `cargo bootimage`
uses: actions-rs/cargo@v1
with:
command: bootimage
# install QEMU
- name: Install QEMU (Linux)
run: sudo apt update && sudo apt install qemu-system-x86
if: runner.os == 'Linux'
- name: Install QEMU (macOS)
run: brew install qemu
if: runner.os == 'macOS'
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
- name: Install QEMU (Windows)
run: |
choco install qemu --version 2021.5.5
echo "$Env:Programfiles\qemu" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
if: runner.os == 'Windows'
shell: pwsh
- name: "Print QEMU Version"
run: qemu-system-x86_64 --version
- name: Run `cargo test`
uses: actions-rs/cargo@v1
with:
command: test
check_formatting:
name: Check Formatting
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Install Rust Toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
components: rustfmt
override: true
- name: Run `cargo fmt`
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Install Rust Toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
components: clippy, rust-src
override: true
- name: Run `cargo clippy`
uses: actions-rs/cargo@v1
with:
command: clippy

234
Cargo.lock generated
View File

@@ -1,106 +1,210 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "autocfg"
version = "1.5.0"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "bit_field"
version = "0.10.2"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
checksum = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
[[package]]
name = "bitflags"
version = "1.3.2"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blog_os"
version = "0.1.0"
dependencies = [
"bootloader",
"conquer-once",
"cooked-waker",
"crossbeam-queue",
"futures-util",
"lazy_static",
"linked_list_allocator",
"pc-keyboard",
"pic8259",
"spin 0.5.2",
"pic8259_simple",
"spin",
"uart_16550",
"volatile 0.2.7",
"volatile",
"x86_64",
]
[[package]]
name = "bootloader"
version = "0.9.32"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ea119c3ed05625c179e09d17d0914570a3753ca09c890a73d98f6b72aea00d2"
checksum = "152a28c753e229e037e910b4cd4cd16a90c53dd9a67fd751fa304b4b4a03970c"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "conquer-once"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f7644600a548ecad74e4a918392af1798f7dd045be610be3203b9e129b4f98f"
dependencies = [
"conquer-util",
]
[[package]]
name = "conquer-util"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "654fb2472cc369d311c547103a1fa81d467bef370ae7a0680f65939895b1182a"
[[package]]
name = "cooked-waker"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0032e8be0680b63daf14b0fd7fd57f85fd6897951e110b041d32e839a831914"
dependencies = [
"cooked-waker-derive",
"stowaway",
]
[[package]]
name = "cooked-waker-derive"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74ded02b04a8ff53ea7328cd71297cde598bee70d165ad92512bdb7e20be9d74"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "cpuio"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa"
[[package]]
name = "crossbeam-queue"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg",
"cfg-if",
]
[[package]]
name = "futures-core"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
[[package]]
name = "futures-task"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
[[package]]
name = "futures-util"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
dependencies = [
"futures-core",
"futures-task",
"pin-utils",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
dependencies = [
"spin 0.9.8",
"spin",
]
[[package]]
name = "linked_list_allocator"
version = "0.9.1"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a"
checksum = "18c618c431dfe4419afbe22852f6aceffbc17bd82ba0a18b982def291000824c"
dependencies = [
"spinning_top",
]
[[package]]
name = "lock_api"
version = "0.4.13"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "pc-keyboard"
version = "0.7.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed089a1fbffe3337a1a345501c981f1eb1e47e69de5a40e852433e12953c3174"
checksum = "c48392db76c4e9a69e0b3be356c5f97ebb7b14413c5e4fd0af4755dbf86e2fce"
[[package]]
name = "pic8259"
version = "0.10.4"
name = "pic8259_simple"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb844b5b01db1e0b17938685738f113bfc903846f18932b378bc0eabfa40e194"
checksum = "dc64b2fd10828da8521b6cdabe0679385d7d2a3a6d4c336b819d1fa31ba35c72"
dependencies = [
"x86_64",
"cpuio",
]
[[package]]
name = "rustversion"
version = "1.0.22"
name = "pin-utils"
version = "0.1.0-alpha.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
[[package]]
name = "proc-macro2"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "spin"
@@ -108,52 +212,60 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "spinning_top"
version = "0.2.5"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
checksum = "32d801a3a53bcf5071f85fef8d5cab9e5f638fc5580a37e6eb7aba4b37438d24"
dependencies = [
"lock_api",
]
[[package]]
name = "uart_16550"
version = "0.2.19"
name = "stowaway"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "614ff2a87880d4bd4374722268598a970bbad05ced8bf630439417347254ab2e"
checksum = "32b13d61e782863c0eaeeaf7e8e580dc956a625851fd2fb73e5e92db9601c891"
[[package]]
name = "syn"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
dependencies = [
"bitflags 1.3.2",
"rustversion",
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "uart_16550"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d44b0f30cb82b0fbc15b78ade1064226529ad52028bc8cb8accb98ff6f3d7131"
dependencies = [
"bitflags",
"x86_64",
]
[[package]]
name = "volatile"
version = "0.2.7"
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6b06ad3ed06fef1713569d547cdbdb439eafed76341820fb0e0344f29a41945"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "volatile"
version = "0.4.6"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793"
checksum = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29"
[[package]]
name = "x86_64"
version = "0.14.13"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c101112411baafbb4bf8d33e4c4a80ab5b02d74d2612331c61e8192fc9710491"
checksum = "4206b60c9f99766329b66962aa8ddc01df6c7edd02edc046b7a69d5df9fcdbcf"
dependencies = [
"bit_field",
"bitflags 2.9.2",
"rustversion",
"volatile 0.4.6",
"bitflags",
]

View File

@@ -2,7 +2,7 @@
name = "blog_os"
version = "0.1.0"
authors = ["Philipp Oppermann <dev@phil-opp.com>"]
edition = "2024"
edition = "2018"
[[test]]
name = "should_panic"
@@ -13,32 +13,37 @@ name = "stack_overflow"
harness = false
[dependencies]
bootloader = { version = "0.9", features = ["map_physical_memory"] }
bootloader = { version = "0.8.8", features = ["map_physical_memory"]}
volatile = "0.2.6"
spin = "0.5.2"
x86_64 = "0.14.2"
x86_64 = "0.9.6"
uart_16550 = "0.2.0"
pic8259 = "0.10.1"
pc-keyboard = "0.7.0"
linked_list_allocator = "0.9.0"
pic8259_simple = "0.1.1"
pc-keyboard = "0.5.0"
linked_list_allocator = "0.8.0"
cooked-waker = "1.0.2"
[dependencies.lazy_static]
version = "1.0"
features = ["spin_no_std"]
[[bin]]
name = "blog_os"
test = true
bench = false
[dependencies.crossbeam-queue]
version = "0.2.1"
default-features = false
features = ["alloc"]
[dependencies.conquer-once]
version = "0.2.0"
default-features = false
[dependencies.futures-util]
version = "0.3.4"
default-features = false
features = ["alloc"]
[package.metadata.bootimage]
test-args = [
"-device",
"isa-debug-exit,iobase=0xf4,iosize=0x04",
"-serial",
"stdio",
"-display",
"none",
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio",
"-display", "none"
]
test-success-exit-code = 33 # (0x10 << 1) | 1
test-success-exit-code = 33 # (0x10 << 1) | 1

View File

@@ -1,32 +1,28 @@
# Blog OS (Allocator Designs)
# Blog OS (Heap Allocation)
[![Build Status](https://github.com/phil-opp/blog_os/workflows/Code/badge.svg?branch=post-11)](https://github.com/phil-opp/blog_os/actions?query=workflow%3A%22Code%22+branch%3Apost-11)
[![Build Status](https://github.com/phil-opp/blog_os/workflows/Build%20Code/badge.svg?branch=post-10)](https://github.com/phil-opp/blog_os/actions?query=workflow%3A%22Build+Code%22+branch%3Apost-10)
This repository contains the source code for the [Allocator Designs][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series.
This repository contains the source code for the [Heap Allocation][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series.
[post]: https://os.phil-opp.com/allocator-designs/
[post]: https://os.phil-opp.com/heap-allocation/
**Check out the [master branch](https://github.com/phil-opp/blog_os) for more information.**
## Building
This project requires a nightly version of Rust because it uses some unstable features. At least nightly _2020-07-15_ is required for building. You might need to run `rustup update nightly --force` to update to the latest nightly even if some components such as `rustfmt` are missing it.
You can build the project by running:
You need a nightly Rust compiler. First you need to install the `cargo-xbuild` and `bootimage` tools:
```
cargo build
cargo install cargo-xbuild bootimage
```
To create a bootable disk image from the compiled kernel, you need to install the [`bootimage`] tool:
[`bootimage`]: https://github.com/rust-osdev/bootimage
Then you can build the project by running:
```
cargo install bootimage
cargo xbuild
```
After installing, you can create the bootable disk image by running:
To create a bootable disk image, run:
```
cargo bootimage
@@ -43,10 +39,10 @@ You can run the disk image in [QEMU] through:
[QEMU]: https://www.qemu.org/
```
cargo run
cargo xrun
```
[QEMU] and the [`bootimage`] tool need to be installed for this.
Of course [QEMU] needs to be installed for this.
You can also write the image to an USB stick for booting it on a real machine. On Linux, the command for this is:

View File

@@ -2,10 +2,10 @@ use alloc::alloc::{GlobalAlloc, Layout};
use core::ptr::null_mut;
use fixed_size_block::FixedSizeBlockAllocator;
use x86_64::{
VirtAddr,
structures::paging::{
FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB, mapper::MapToError,
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
},
VirtAddr,
};
pub mod bump;
@@ -35,7 +35,7 @@ pub fn init_heap(
.allocate_frame()
.ok_or(MapToError::FrameAllocationFailed)?;
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
mapper.map_to(page, frame, flags, frame_allocator)?.flush();
}
unsafe {

View File

@@ -1,4 +1,4 @@
use super::{Locked, align_up};
use super::{align_up, Locked};
use alloc::alloc::{GlobalAlloc, Layout};
use core::ptr;

View File

@@ -31,9 +31,8 @@ pub struct FixedSizeBlockAllocator {
impl FixedSizeBlockAllocator {
/// Creates an empty FixedSizeBlockAllocator.
pub const fn new() -> Self {
const EMPTY: Option<&'static mut ListNode> = None;
FixedSizeBlockAllocator {
list_heads: [EMPTY; BLOCK_SIZES.len()],
list_heads: [None; BLOCK_SIZES.len()],
fallback_allocator: linked_list_allocator::Heap::empty(),
}
}
@@ -44,9 +43,7 @@ impl FixedSizeBlockAllocator {
/// heap bounds are valid and that the heap is unused. This method must be
/// called only once.
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
unsafe {
self.fallback_allocator.init(heap_start, heap_size);
}
self.fallback_allocator.init(heap_start, heap_size);
}
/// Allocates using the fallback allocator.
@@ -93,16 +90,12 @@ unsafe impl GlobalAlloc for Locked<FixedSizeBlockAllocator> {
assert!(mem::size_of::<ListNode>() <= BLOCK_SIZES[index]);
assert!(mem::align_of::<ListNode>() <= BLOCK_SIZES[index]);
let new_node_ptr = ptr as *mut ListNode;
unsafe {
new_node_ptr.write(new_node);
allocator.list_heads[index] = Some(&mut *new_node_ptr);
}
new_node_ptr.write(new_node);
allocator.list_heads[index] = Some(&mut *new_node_ptr);
}
None => {
let ptr = NonNull::new(ptr).unwrap();
unsafe {
allocator.fallback_allocator.deallocate(ptr, layout);
}
allocator.fallback_allocator.deallocate(ptr, layout);
}
}
}

View File

@@ -1,4 +1,4 @@
use super::{Locked, align_up};
use super::{align_up, Locked};
use alloc::alloc::{GlobalAlloc, Layout};
use core::{mem, ptr};
@@ -39,25 +39,21 @@ impl LinkedListAllocator {
/// heap bounds are valid and that the heap is unused. This method must be
/// called only once.
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
unsafe {
self.add_free_region(heap_start, heap_size);
}
self.add_free_region(heap_start, heap_size);
}
/// Adds the given memory region to the front of the list.
unsafe fn add_free_region(&mut self, addr: usize, size: usize) {
// ensure that the freed region is capable of holding ListNode
assert_eq!(align_up(addr, mem::align_of::<ListNode>()), addr);
assert!(align_up(addr, mem::align_of::<ListNode>()) == addr);
assert!(size >= mem::size_of::<ListNode>());
// create a new list node and append it at the start of the list
let mut node = ListNode::new(size);
node.next = self.head.next.take();
let node_ptr = addr as *mut ListNode;
unsafe {
node_ptr.write(node);
self.head.next = Some(&mut *node_ptr);
}
node_ptr.write(node);
self.head.next = Some(&mut *node_ptr)
}
/// Looks for a free region with the given size and alignment and removes
@@ -132,9 +128,7 @@ unsafe impl GlobalAlloc for Locked<LinkedListAllocator> {
let alloc_end = alloc_start.checked_add(size).expect("overflow");
let excess_size = region.end_addr() - alloc_end;
if excess_size > 0 {
unsafe {
allocator.add_free_region(alloc_end, excess_size);
}
allocator.add_free_region(alloc_end, excess_size);
}
alloc_start as *mut u8
} else {
@@ -146,6 +140,6 @@ unsafe impl GlobalAlloc for Locked<LinkedListAllocator> {
// perform layout adjustments
let (size, _) = LinkedListAllocator::size_align(layout);
unsafe { self.lock().add_free_region(ptr as usize, size) }
self.lock().add_free_region(ptr as usize, size)
}
}

View File

@@ -1,7 +1,7 @@
use lazy_static::lazy_static;
use x86_64::VirtAddr;
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
use x86_64::structures::tss::TaskStateSegment;
use x86_64::VirtAddr;
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
@@ -9,10 +9,10 @@ lazy_static! {
static ref TSS: TaskStateSegment = {
let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = {
const STACK_SIZE: usize = 4096 * 5;
const STACK_SIZE: usize = 4096;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(&raw const STACK);
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
@@ -41,12 +41,12 @@ struct Selectors {
}
pub fn init() {
use x86_64::instructions::segmentation::{CS, Segment};
use x86_64::instructions::segmentation::set_cs;
use x86_64::instructions::tables::load_tss;
GDT.0.load();
unsafe {
CS::set_reg(GDT.1.code_selector);
set_cs(GDT.1.code_selector);
load_tss(GDT.1.tss_selector);
}
}

View File

@@ -1,6 +1,6 @@
use crate::{gdt, hlt_loop, print, println};
use lazy_static::lazy_static;
use pic8259::ChainedPics;
use pic8259_simple::ChainedPics;
use spin;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
@@ -47,12 +47,12 @@ pub fn init_idt() {
IDT.load();
}
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) {
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
}
extern "x86-interrupt" fn page_fault_handler(
stack_frame: InterruptStackFrame,
stack_frame: &mut InterruptStackFrame,
error_code: PageFaultErrorCode,
) {
use x86_64::registers::control::Cr2;
@@ -65,13 +65,13 @@ extern "x86-interrupt" fn page_fault_handler(
}
extern "x86-interrupt" fn double_fault_handler(
stack_frame: InterruptStackFrame,
stack_frame: &mut InterruptStackFrame,
_error_code: u64,
) -> ! {
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
}
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
print!(".");
unsafe {
PICS.lock()
@@ -79,32 +79,12 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr
}
}
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
use pc_keyboard::{DecodedKey, HandleControl, Keyboard, ScancodeSet1, layouts};
use spin::Mutex;
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
use x86_64::instructions::port::Port;
lazy_static! {
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
Mutex::new(Keyboard::new(
ScancodeSet1::new(),
layouts::Us104Key,
HandleControl::Ignore
));
}
let mut keyboard = KEYBOARD.lock();
let mut port = Port::new(0x60);
let scancode: u8 = unsafe { port.read() };
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
if let Some(key) = keyboard.process_keyevent(key_event) {
match key {
DecodedKey::Unicode(character) => print!("{}", character),
DecodedKey::RawKey(key) => print!("{:?}", key),
}
}
}
crate::task::keyboard::add_scancode(scancode);
unsafe {
PICS.lock()
@@ -112,8 +92,13 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac
}
}
#[cfg(test)]
use crate::{serial_print, serial_println};
#[test_case]
fn test_breakpoint_exception() {
serial_print!("test_breakpoint_exception...");
// invoke a breakpoint exception
x86_64::instructions::interrupts::int3();
serial_println!("[ok]");
}

View File

@@ -2,10 +2,15 @@
#![cfg_attr(test, no_main)]
#![feature(custom_test_frameworks)]
#![feature(abi_x86_interrupt)]
#![feature(alloc_error_handler)]
#![feature(const_fn)]
#![feature(alloc_layout_extra)]
#![feature(const_in_array_repeat_expressions)]
#![test_runner(crate::test_runner)]
#![reexport_test_harness_main = "test_main"]
extern crate alloc;
use core::panic::PanicInfo;
pub mod allocator;
@@ -13,6 +18,7 @@ pub mod gdt;
pub mod interrupts;
pub mod memory;
pub mod serial;
pub mod task;
pub mod vga_buffer;
pub fn init() {
@@ -21,25 +27,11 @@ pub fn init() {
unsafe { interrupts::PICS.lock().initialize() };
x86_64::instructions::interrupts::enable();
}
pub trait Testable {
fn run(&self) -> ();
}
impl<T> Testable for T
where
T: Fn(),
{
fn run(&self) {
serial_print!("{}...\t", core::any::type_name::<T>());
self();
serial_println!("[ok]");
}
}
pub fn test_runner(tests: &[&dyn Testable]) {
pub fn test_runner(tests: &[&dyn Fn()]) {
serial_println!("Running {} tests", tests.len());
for test in tests {
test.run();
test();
}
exit_qemu(QemuExitCode::Success);
}
@@ -74,7 +66,7 @@ pub fn hlt_loop() -> ! {
}
#[cfg(test)]
use bootloader::{BootInfo, entry_point};
use bootloader::{entry_point, BootInfo};
#[cfg(test)]
entry_point!(test_kernel_main);
@@ -92,3 +84,8 @@ fn test_kernel_main(_boot_info: &'static BootInfo) -> ! {
fn panic(info: &PanicInfo) -> ! {
test_panic_handler(info)
}
#[alloc_error_handler]
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
panic!("allocation error: {:?}", layout)
}

View File

@@ -6,9 +6,8 @@
extern crate alloc;
use alloc::{boxed::Box, rc::Rc, vec, vec::Vec};
use blog_os::println;
use bootloader::{BootInfo, entry_point};
use bootloader::{entry_point, BootInfo};
use core::panic::PanicInfo;
entry_point!(kernel_main);
@@ -16,6 +15,7 @@ entry_point!(kernel_main);
fn kernel_main(boot_info: &'static BootInfo) -> ! {
use blog_os::allocator;
use blog_os::memory::{self, BootInfoFrameAllocator};
use blog_os::task::{keyboard, simple_executor::SimpleExecutor, Task};
use x86_64::VirtAddr;
println!("Hello World{}", "!");
@@ -27,29 +27,10 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed");
// allocate a number on the heap
let heap_value = Box::new(41);
println!("heap_value at {:p}", heap_value);
// create a dynamically sized vector
let mut vec = Vec::new();
for i in 0..500 {
vec.push(i);
}
println!("vec at {:p}", vec.as_slice());
// create a reference counted vector -> will be freed when count reaches 0
let reference_counted = Rc::new(vec![1, 2, 3]);
let cloned_reference = reference_counted.clone();
println!(
"current reference count is {}",
Rc::strong_count(&cloned_reference)
);
core::mem::drop(reference_counted);
println!(
"reference count is {} now",
Rc::strong_count(&cloned_reference)
);
let mut executor = SimpleExecutor::new();
executor.spawn(Task::new(example_task()));
executor.spawn(Task::new(keyboard::print_keypresses()));
executor.run();
#[cfg(test)]
test_main();
@@ -58,6 +39,15 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
blog_os::hlt_loop();
}
async fn async_number() -> u32 {
42
}
async fn example_task() {
let number = async_number().await;
println!("async number: {}", number);
}
/// This function is called on panic.
#[cfg(not(test))]
#[panic_handler]
@@ -71,8 +61,3 @@ fn panic(info: &PanicInfo) -> ! {
fn panic(info: &PanicInfo) -> ! {
blog_os::test_panic_handler(info)
}
#[test_case]
fn trivial_assertion() {
assert_eq!(1, 1);
}

View File

@@ -1,7 +1,10 @@
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
use x86_64::{
structures::paging::{
FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB,
UnusedPhysFrame,
},
PhysAddr, VirtAddr,
structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB},
};
/// Initialize a new OffsetPageTable.
@@ -11,10 +14,8 @@ use x86_64::{
/// `physical_memory_offset`. Also, this function must be only called once
/// to avoid aliasing `&mut` references (which is undefined behavior).
pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> {
unsafe {
let level_4_table = active_level_4_table(physical_memory_offset);
OffsetPageTable::new(level_4_table, physical_memory_offset)
}
let level_4_table = active_level_4_table(physical_memory_offset);
OffsetPageTable::new(level_4_table, physical_memory_offset)
}
/// Returns a mutable reference to the active level 4 table.
@@ -32,14 +33,31 @@ unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut
let virt = physical_memory_offset + phys.as_u64();
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
unsafe { &mut *page_table_ptr }
&mut *page_table_ptr // unsafe
}
/// Creates an example mapping for the given page to frame `0xb8000`.
pub fn create_example_mapping(
page: Page,
mapper: &mut OffsetPageTable,
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
) {
use x86_64::structures::paging::PageTableFlags as Flags;
let frame = PhysFrame::containing_address(PhysAddr::new(0xb8000));
// FIXME: ONLY FOR TEMPORARY TESTING
let unused_frame = unsafe { UnusedPhysFrame::new(frame) };
let flags = Flags::PRESENT | Flags::WRITABLE;
let map_to_result = mapper.map_to(page, unused_frame, flags, frame_allocator);
map_to_result.expect("map_to failed").flush();
}
/// A FrameAllocator that always returns `None`.
pub struct EmptyFrameAllocator;
unsafe impl FrameAllocator<Size4KiB> for EmptyFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame> {
fn allocate_frame(&mut self) -> Option<UnusedPhysFrame> {
None
}
}
@@ -64,7 +82,7 @@ impl BootInfoFrameAllocator {
}
/// Returns an iterator over the usable frames specified in the memory map.
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
fn usable_frames(&self) -> impl Iterator<Item = UnusedPhysFrame> {
// get usable regions from memory map
let regions = self.memory_map.iter();
let usable_regions = regions.filter(|r| r.region_type == MemoryRegionType::Usable);
@@ -73,12 +91,14 @@ impl BootInfoFrameAllocator {
// transform to an iterator of frame start addresses
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
// create `PhysFrame` types from the start addresses
frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)))
let frames = frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)));
// we know that the frames are really unused
frames.map(|f| unsafe { UnusedPhysFrame::new(f) })
}
}
unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame> {
fn allocate_frame(&mut self) -> Option<UnusedPhysFrame> {
let frame = self.usable_frames().nth(self.next);
self.next += 1;
frame

79
src/task/keyboard.rs Normal file
View File

@@ -0,0 +1,79 @@
use crate::print;
use crate::println;
use conquer_once::spin::OnceCell;
use core::{
pin::Pin,
task::{Context, Poll},
};
use crossbeam_queue::ArrayQueue;
use futures_util::stream::StreamExt;
use futures_util::{stream::Stream, task::AtomicWaker};
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
static SCANCODE_QUEUE: OnceCell<ArrayQueue<u8>> = OnceCell::uninit();
static WAKER: AtomicWaker = AtomicWaker::new();
/// Called by the keyboard interrupt handler
///
/// Must not block or allocate.
pub(crate) fn add_scancode(scancode: u8) {
if let Ok(queue) = SCANCODE_QUEUE.try_get() {
if let Err(_) = queue.push(scancode) {
println!("WARNING: scancode queue full; dropping keyboard input");
} else {
WAKER.wake();
}
} else {
println!("WARNING: scancode queue uninitialized");
}
}
pub struct ScancodeStream {
_private: (),
}
impl ScancodeStream {
pub fn new() -> Self {
SCANCODE_QUEUE
.try_init_once(|| ArrayQueue::new(100))
.expect("ScancodeStream::new should only be called once");
ScancodeStream { _private: () }
}
}
impl Stream for ScancodeStream {
type Item = u8;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<u8>> {
let queue = SCANCODE_QUEUE
.try_get()
.expect("scancode queue not initialized");
// fast path
if let Ok(scancode) = queue.pop() {
return Poll::Ready(Some(scancode));
}
WAKER.register(&cx.waker());
match queue.pop() {
Ok(scancode) => Poll::Ready(Some(scancode)),
Err(crossbeam_queue::PopError) => Poll::Pending,
}
}
}
pub async fn print_keypresses() {
let mut scancodes = ScancodeStream::new();
let mut keyboard = Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore);
while let Some(scancode) = scancodes.next().await {
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
if let Some(key) = keyboard.process_keyevent(key_event) {
match key {
DecodedKey::Unicode(character) => print!("{}", character),
DecodedKey::RawKey(key) => print!("{:?}", key),
}
}
}
}
}

26
src/task/mod.rs Normal file
View File

@@ -0,0 +1,26 @@
use alloc::boxed::Box;
use core::task::{Context, Poll};
use core::{future::Future, pin::Pin};
pub mod keyboard;
pub mod simple_executor;
pub struct Task {
future: Pin<Box<dyn Future<Output = ()>>>,
}
impl Task {
pub fn new(future: impl Future<Output = ()> + 'static) -> Task {
Task {
future: Box::pin(future),
}
}
fn poll(&mut self, context: &mut Context) -> Poll<()> {
self.future.as_mut().poll(context)
}
fn id(&self) -> usize {
&*self.future as *const _ as *const () as usize
}
}

View File

@@ -0,0 +1,86 @@
use super::Task;
use alloc::{
collections::{BTreeMap, VecDeque},
sync::Arc,
};
use cooked_waker::IntoWaker;
use core::task::{Context, Poll};
use crossbeam_queue::ArrayQueue;
pub struct SimpleExecutor {
task_queue: VecDeque<Task>,
waiting_tasks: BTreeMap<usize, Task>,
wake_queue: Arc<ArrayQueue<usize>>,
}
impl SimpleExecutor {
pub fn new() -> SimpleExecutor {
SimpleExecutor {
task_queue: VecDeque::new(),
waiting_tasks: BTreeMap::new(),
wake_queue: Arc::new(ArrayQueue::new(100)),
}
}
pub fn spawn(&mut self, task: Task) {
self.task_queue.push_back(task)
}
pub fn run(&mut self) {
loop {
self.handle_wakeups();
self.run_ready_tasks();
}
}
fn handle_wakeups(&mut self) {
while let Ok(task_id) = self.wake_queue.pop() {
if let Some(task) = self.waiting_tasks.remove(&task_id) {
self.task_queue.push_back(task);
}
}
}
fn run_ready_tasks(&mut self) {
while let Some(mut task) = self.task_queue.pop_front() {
let waker = TaskWaker {
task_id: task.id(),
wake_queue: self.wake_queue.clone(),
}
.into_waker();
let mut context = Context::from_waker(&waker);
match task.poll(&mut context) {
Poll::Ready(()) => {} // task done
Poll::Pending => {
if self.waiting_tasks.insert(task.id(), task).is_some() {
panic!("Same task inserted into waiting_tasks twice");
}
}
}
}
}
}
#[derive(Debug, Clone, IntoWaker)]
struct TaskWaker {
task_id: usize,
wake_queue: Arc<ArrayQueue<usize>>,
}
impl TaskWaker {
fn wake_task(&self) {
self.wake_queue.push(self.task_id).expect("wake queue full");
}
}
impl cooked_waker::WakeRef for TaskWaker {
fn wake_by_ref(&self) {
self.wake_task();
}
}
impl cooked_waker::Wake for TaskWaker {
fn wake(self) {
self.wake_task();
}
}

View File

@@ -3,6 +3,9 @@ use lazy_static::lazy_static;
use spin::Mutex;
use volatile::Volatile;
#[cfg(test)]
use crate::{serial_print, serial_println};
lazy_static! {
/// A global `Writer` instance that can be used for printing to the VGA text buffer.
///
@@ -177,14 +180,18 @@ pub fn _print(args: fmt::Arguments) {
#[test_case]
fn test_println_simple() {
serial_print!("test_println... ");
println!("test_println_simple output");
serial_println!("[ok]");
}
#[test_case]
fn test_println_many() {
serial_print!("test_println_many... ");
for _ in 0..200 {
println!("test_println_many output");
}
serial_println!("[ok]");
}
#[test_case]
@@ -192,6 +199,8 @@ fn test_println_output() {
use core::fmt::Write;
use x86_64::instructions::interrupts;
serial_print!("test_println_output... ");
let s = "Some test string that fits on a single line";
interrupts::without_interrupts(|| {
let mut writer = WRITER.lock();
@@ -201,4 +210,6 @@ fn test_println_output() {
assert_eq!(char::from(screen_char.ascii_character), c);
}
});
serial_println!("[ok]");
}

View File

@@ -4,10 +4,10 @@
#![test_runner(blog_os::test_runner)]
#![reexport_test_harness_main = "test_main"]
use blog_os::println;
use blog_os::{println, serial_print, serial_println};
use core::panic::PanicInfo;
#[unsafe(no_mangle)] // don't mangle the name of this function
#[no_mangle] // don't mangle the name of this function
pub extern "C" fn _start() -> ! {
test_main();
@@ -21,5 +21,7 @@ fn panic(info: &PanicInfo) -> ! {
#[test_case]
fn test_println() {
serial_print!("test_println... ");
println!("test_println output");
serial_println!("[ok]");
}

View File

@@ -7,8 +7,8 @@
extern crate alloc;
use alloc::{boxed::Box, vec::Vec};
use blog_os::allocator::HEAP_SIZE;
use bootloader::{BootInfo, entry_point};
use blog_os::{allocator::HEAP_SIZE, serial_print, serial_println};
use bootloader::{entry_point, BootInfo};
use core::panic::PanicInfo;
entry_point!(main);
@@ -30,38 +30,44 @@ fn main(boot_info: &'static BootInfo) -> ! {
#[test_case]
fn simple_allocation() {
let heap_value_1 = Box::new(41);
let heap_value_2 = Box::new(13);
assert_eq!(*heap_value_1, 41);
assert_eq!(*heap_value_2, 13);
serial_print!("simple_allocation... ");
let heap_value = Box::new(41);
assert_eq!(*heap_value, 41);
serial_println!("[ok]");
}
#[test_case]
fn large_vec() {
serial_print!("large_vec... ");
let n = 1000;
let mut vec = Vec::new();
for i in 0..n {
vec.push(i);
}
assert_eq!(vec.iter().sum::<u64>(), (n - 1) * n / 2);
serial_println!("[ok]");
}
#[test_case]
fn many_boxes() {
serial_print!("many_boxes... ");
for i in 0..HEAP_SIZE {
let x = Box::new(i);
assert_eq!(*x, i);
}
serial_println!("[ok]");
}
#[test_case]
fn many_boxes_long_lived() {
serial_print!("many_boxes_long_lived... ");
let long_lived = Box::new(1); // new
for i in 0..HEAP_SIZE {
let x = Box::new(i);
assert_eq!(*x, i);
}
assert_eq!(*long_lived, 1); // new
serial_println!("[ok]");
}
#[panic_handler]

View File

@@ -1,10 +1,10 @@
#![no_std]
#![no_main]
use blog_os::{QemuExitCode, exit_qemu, serial_print, serial_println};
use blog_os::{exit_qemu, serial_print, serial_println, QemuExitCode};
use core::panic::PanicInfo;
#[unsafe(no_mangle)]
#[no_mangle]
pub extern "C" fn _start() -> ! {
should_fail();
serial_println!("[test did not panic]");
@@ -13,7 +13,7 @@ pub extern "C" fn _start() -> ! {
}
fn should_fail() {
serial_print!("should_panic::should_fail...\t");
serial_print!("should_fail... ");
assert_eq!(0, 1);
}

View File

@@ -2,14 +2,14 @@
#![no_main]
#![feature(abi_x86_interrupt)]
use blog_os::{QemuExitCode, exit_qemu, serial_print, serial_println};
use blog_os::{exit_qemu, serial_print, serial_println, QemuExitCode};
use core::panic::PanicInfo;
use lazy_static::lazy_static;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
#[unsafe(no_mangle)]
#[no_mangle]
pub extern "C" fn _start() -> ! {
serial_print!("stack_overflow::stack_overflow...\t");
serial_print!("stack_overflow... ");
blog_os::gdt::init();
init_test_idt();
@@ -23,7 +23,6 @@ pub extern "C" fn _start() -> ! {
#[allow(unconditional_recursion)]
fn stack_overflow() {
stack_overflow(); // for each recursion, the return address is pushed
volatile::Volatile::new(0).read(); // prevent tail recursion optimizations
}
lazy_static! {
@@ -44,7 +43,7 @@ pub fn init_test_idt() {
}
extern "x86-interrupt" fn test_double_fault_handler(
_stack_frame: InterruptStackFrame,
_stack_frame: &mut InterruptStackFrame,
_error_code: u64,
) -> ! {
serial_println!("[ok]");

View File

@@ -1,16 +1,15 @@
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": 32,
"target-c-int-width": "32",
"os": "none",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "-mmx,-sse,+soft-float",
"rustc-abi": "x86-softfloat"
"features": "-mmx,-sse,+soft-float"
}