Merge branch 'rust-embedded:master' into master

pull/196/head
°~zanez 8 months ago committed by GitHub
commit 43d9997956
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -13,7 +13,7 @@ max_line_length = 100
[Dockerfile]
indent_size = 4
[Makefile]
[{Makefile,*.mk}]
indent_style = tab
indent_size = 8

@ -3,7 +3,7 @@
# SPDX-License-Identifier: MIT OR Apache-2.0
#
# Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
# Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
require_relative '../utils/devtool/copyright'
@ -23,9 +23,9 @@ def copyright_check(staged_files)
copyright_check_files(staged_files)
end
##--------------------------------------------------------------------------------------------------
## -------------------------------------------------------------------------------------------------
## Execution starts here
##--------------------------------------------------------------------------------------------------
## -------------------------------------------------------------------------------------------------
staged_files = `git --no-pager diff --name-only --cached --diff-filter=d`.split(/\n/)
root_dir = `git rev-parse --show-toplevel`.strip

@ -10,4 +10,5 @@ Related Issue: <Insert link here if applicable>
- Not needed if it is just a README change or similar.
- [ ] Ran `./contributor_setup.sh` followed by `./devtool ready_for_publish`
- You'll need `Ruby` with `Bundler` and `NPM` installed locally.
- If no Rust-related files were changed, `./devtool ready_for_publish_no_rust` can be used instead (faster).
- This step is optional, but much appreciated if done.

@ -1,40 +1,40 @@
name: BSP-RPi3
on:
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
jobs:
build:
name: Build kernels
runs-on: ubuntu-20.04
build:
name: Build kernels
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.x
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Make
run: |
BSP=rpi3 bundle exec ruby utils/devtool.rb make
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils rustfilt
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Run
run: |
BSP=rpi3 bundle exec ruby utils/devtool.rb make

@ -1,40 +1,40 @@
name: BSP-RPi4
on:
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
jobs:
build:
name: Build kernels
runs-on: ubuntu-20.04
build:
name: Build kernels
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.x
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Make
run: |
BSP=rpi4 bundle exec ruby utils/devtool.rb make
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils rustfilt
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Run
run: |
BSP=rpi4 bundle exec ruby utils/devtool.rb make

@ -1,46 +1,46 @@
name: Various Sanity Checks
on:
push:
branches:
- master
pull_request:
branches:
- master
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
name: Various Sanity Checks
runs-on: ubuntu-20.04
build:
name: Various Sanity Checks
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v1
with:
node-version: "12"
- name: Set up Ruby 2.x
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
rustup component add clippy
- name: Set up Bundler
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Set up Prettier
run: |
npm install prettier
- name: Setup misspell
run: |
curl -L -o ./install-misspell.sh https://git.io/misspell
sh ./install-misspell.sh -b .vendor
- name: Run checks
run: |
BSP=rpi3 bundle exec ruby utils/devtool.rb clippy
BSP=rpi4 bundle exec ruby utils/devtool.rb clippy
bundle exec ruby utils/devtool.rb copyright
bundle exec ruby utils/devtool.rb fmt_check
bundle exec ruby utils/devtool.rb misspell
bundle exec ruby utils/devtool.rb rubocop
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v1
with:
node-version: "16"
- name: Set up Ruby
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
rustup component add clippy
- name: Set up Bundler
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Set up Prettier
run: |
npm install prettier
- name: Setup misspell
run: |
curl -L -o ./install-misspell.sh https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh
sh ./install-misspell.sh -b .vendor
- name: Run checks
run: |
BSP=rpi3 bundle exec ruby utils/devtool.rb clippy
BSP=rpi4 bundle exec ruby utils/devtool.rb clippy
bundle exec ruby utils/devtool.rb copyright
bundle exec ruby utils/devtool.rb fmt_check
bundle exec ruby utils/devtool.rb misspell
bundle exec ruby utils/devtool.rb rubocop

@ -1,40 +1,40 @@
name: Integration-Tests
on:
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
jobs:
build:
name: Run integration tests
runs-on: ubuntu-20.04
build:
name: Run integration tests
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.x
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Make all
run: |
bundle exec ruby utils/devtool.rb test_integration
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils rustfilt
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Run
run: |
bundle exec ruby utils/devtool.rb test_integration

@ -1,40 +1,41 @@
name: Unit-Tests
name: Boot-and-Unit-Tests
on:
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
jobs:
build:
name: Run unit tests
runs-on: ubuntu-20.04
build:
name: Run boot and unit tests
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.x
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Make all
run: |
bundle exec ruby utils/devtool.rb test_unit
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils rustfilt
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Run
run: |
bundle exec ruby utils/devtool.rb test_boot
bundle exec ruby utils/devtool.rb test_unit

@ -1,40 +1,40 @@
name: Xtra-Tests
on:
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
push:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
pull_request:
branches:
- master
paths-ignore:
- "utils/**"
- "doc/**"
- "docker/**"
schedule:
- cron: "0 5 * * *"
jobs:
build:
name: Run xtra tests
runs-on: ubuntu-20.04
build:
name: Run xtra tests
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.x
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Make all
run: |
bundle exec ruby utils/devtool.rb test_xtra
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
- name: Set up Rust nightly
run: |
cargo install cargo-binutils
- name: Set up Ruby
run: |
gem install bundler
bundle config set without 'uart'
bundle install --retry 3
- name: Run
run: |
bundle exec ruby utils/devtool.rb make_xtra

3
.gitignore vendored

@ -3,7 +3,8 @@
**/kernel8.img
node_modules
.bundle
.vendor
Gemfile.lock
package-lock.json
package*.json

@ -1 +1,35 @@
{}
{
"printWidth": 100,
"tabWidth": 4,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "always",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve",
"endOfLine": "auto",
"overrides": [
{
"files": "*.rs",
"options": {
"printWidth": 100,
"tabWidth": 4,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "always",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve",
"endOfLine": "auto"
}
}
]
}

@ -10,23 +10,23 @@
# See https://github.com/rubocop-hq/rubocop/blob/master/manual/configuration.md
Layout/IndentationWidth:
Width: 4
IgnoredPatterns: ['^\s*module']
Width: 4
AllowedPatterns: ['^\s*module']
Layout/LineLength:
Max: 100
Max: 100
Lint/UnusedMethodArgument:
AutoCorrect: False
AutoCorrect: False
Metrics/AbcSize:
Max: 25
Max: 25
Metrics/ClassLength:
Enabled: false
Enabled: false
Metrics/MethodLength:
Max: 20
Max: 20
AllCops:
NewCops: enable
NewCops: enable

@ -1 +1 @@
2.7
3.0.2

@ -5,5 +5,3 @@ format_code_in_doc_comments = true
normalize_comments = true
wrap_comments = true
comment_width = 100
report_fixme = "Always"
report_todo = "Always"

@ -1,4 +1,10 @@
{
"editor.formatOnSave": true,
"editor.rulers": [100]
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
}

@ -1,9 +1,10 @@
{
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.overrideCommand": ["make", "check"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.extraArgs": ["--bins"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
}

@ -20,4 +20,4 @@ path = "src/main.rs"
## Dependencies
##--------------------------------------------------------------------------------------------------
[dependencies]
[dependencies]

@ -1,9 +1,10 @@
## SPDX-License-Identifier: MIT OR Apache-2.0
##
## Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
## Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
include ../common/format.mk
include ../common/docker.mk
include ../common/format.mk
include ../common/operating_system.mk
##--------------------------------------------------------------------------------------------------
## Optional, user-provided configuration values
@ -51,14 +52,14 @@ export LD_SCRIPT_PATH
##--------------------------------------------------------------------------------------------------
## Targets and Prerequisites
##--------------------------------------------------------------------------------------------------
KERNEL_LINKER_SCRIPT = link.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_MANIFEST = Cargo.toml
KERNEL_LINKER_SCRIPT = kernel.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_ELF = target/$(TARGET)/release/kernel
# This parses cargo's dep-info file.
# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG)
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)
@ -81,7 +82,6 @@ COMPILER_ARGS = --target=$(TARGET) \
RUSTC_CMD = cargo rustc $(COMPILER_ARGS)
DOC_CMD = cargo doc $(COMPILER_ARGS)
CLIPPY_CMD = cargo clippy $(COMPILER_ARGS)
CHECK_CMD = cargo check $(COMPILER_ARGS)
OBJCOPY_CMD = rust-objcopy \
--strip-all \
-O binary
@ -131,7 +131,7 @@ $(KERNEL_BIN): $(KERNEL_ELF)
$(call color_progress_prefix, "Name")
@echo $(KERNEL_BIN)
$(call color_progress_prefix, "Size")
@printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1`
$(call disk_usage_KiB, $(KERNEL_BIN))
##------------------------------------------------------------------------------
## Generate the documentation
@ -190,8 +190,3 @@ nm: $(KERNEL_ELF)
$(call color_header, "Launching nm")
@$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
##------------------------------------------------------------------------------
## Helper target for rust-analyzer
##------------------------------------------------------------------------------
check:
@RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json

@ -14,7 +14,7 @@
- `nm`: 检查符号。
- 代码按照 `kernel` `arch``BSP` (板级支持包)的形式组织。
- 条件编译会根据用户提供的参数编译各自的 `arch``BSP` 的内容。
- 自定义 `link.ld` 链接脚本.
- 自定义 `kernel.ld` 链接脚本.
- 载入地址为 `0x80_000`
- 目前仅有 `.text` 小节section
- `main.rs`: 重要的 [inner attributes]:

@ -9,37 +9,37 @@
## Compilar
* El archivo `Makefile` permite ejecutar:
* `doc`: Genera la documentación.
* `qemu`: Ejecutar el kernel en QEMU.
* `clippy`: Analiza el código y sugiere mejoras.
* `clean`: Elimina todos los archivos generados durante la compilación, etc.
* `readelf`: Inspecciona el archivo `ELF` de salida.
* `objdump`: Inspecciona el ensamblador.
* `objdump`: Inspecciona el ensamblador.
* `nm`: Inspecciona los símbolos.
## Código a revisar
* El script para enlazado específico para la `BSP` llamado `link.ld`.
* El script para enlazado específico para la `BSP` llamado `kernel.ld`.
* Carga la dirección en `0x8_0000`.
* Solo la sección `.text`.
* `main.rs`: [Atributos internos](https://doc.rust-lang.org/reference/attributes.html) importantes:
* `#![no_std]`, `#![no_main]`.
* `boot.s`: La función de ensamblador `_start()` que inicia `wfe` (Wait For Event / Esperar Hasta Un Evento), detiene todos los núcleos del procesador que están ejecutando `_start()`.
* `boot.s`: La función de ensamblador `_start()` que inicia `wfe` (Wait For Event / Esperar Hasta Un Evento), detiene todos los núcleos del procesador que están ejecutando `_start()`.
* Tenemos que definir una función que funcione como `#[panic_handler]` (manejador de pánico) para que el compilador no nos cause problemas.
* Hazla `unimplemented!()` porque se eliminará ya que no está siendo usada.
## Pruébalo

@ -18,7 +18,7 @@
## Code to look at
- `BSP`-specific `link.ld` linker script.
- `BSP`-specific `kernel.ld` linker script.
- Load address at `0x8_0000`
- Only `.text` section.
- `main.rs`: Important [inner attributes]:

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//! Architectural boot code.
//!
@ -11,5 +11,7 @@
//!
//! crate::cpu::boot::arch_boot
use core::arch::global_asm;
// Assembly counterpart to this file.
core::arch::global_asm!(include_str!("boot.s"));
global_asm!(include_str!("boot.s"));

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//--------------------------------------------------------------------------------------------------
// Public Code

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Conditional reexporting of Board Support Packages.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Top-level BSP file for the Raspberry Pi 3 and 4.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2020-2023 Andre Richter <andre.o.richter@gmail.com>
//! Processor code.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//! Boot code.

@ -1,9 +1,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
// Rust embedded logo for `make doc`.
#![doc(html_logo_url = "https://git.io/JeGIp")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png"
)]
//! The `kernel` binary.
//!

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! A panic handler that infinitely waits.

@ -1,9 +1,10 @@
{
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.overrideCommand": ["make", "check"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.extraArgs": ["--bins"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
}

@ -3,10 +3,10 @@
version = 3
[[package]]
name = "cortex-a"
version = "7.2.0"
name = "aarch64-cpu"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad"
checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225"
dependencies = [
"tock-registers",
]
@ -15,11 +15,11 @@ dependencies = [
name = "mingo"
version = "0.2.0"
dependencies = [
"cortex-a",
"aarch64-cpu",
]
[[package]]
name = "tock-registers"
version = "0.7.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e"
checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c"

@ -24,4 +24,4 @@ path = "src/main.rs"
# Platform specific dependencies
[target.'cfg(target_arch = "aarch64")'.dependencies]
cortex-a = { version = "7.x.x" }
aarch64-cpu = { version = "9.x.x" }

@ -1,9 +1,10 @@
## SPDX-License-Identifier: MIT OR Apache-2.0
##
## Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
## Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
include ../common/format.mk
include ../common/docker.mk
include ../common/format.mk
include ../common/operating_system.mk
##--------------------------------------------------------------------------------------------------
## Optional, user-provided configuration values
@ -51,14 +52,14 @@ export LD_SCRIPT_PATH
##--------------------------------------------------------------------------------------------------
## Targets and Prerequisites
##--------------------------------------------------------------------------------------------------
KERNEL_LINKER_SCRIPT = link.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_MANIFEST = Cargo.toml
KERNEL_LINKER_SCRIPT = kernel.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_ELF = target/$(TARGET)/release/kernel
# This parses cargo's dep-info file.
# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG)
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)
@ -81,7 +82,6 @@ COMPILER_ARGS = --target=$(TARGET) \
RUSTC_CMD = cargo rustc $(COMPILER_ARGS)
DOC_CMD = cargo doc $(COMPILER_ARGS)
CLIPPY_CMD = cargo clippy $(COMPILER_ARGS)
CHECK_CMD = cargo check $(COMPILER_ARGS)
OBJCOPY_CMD = rust-objcopy \
--strip-all \
-O binary
@ -131,7 +131,7 @@ $(KERNEL_BIN): $(KERNEL_ELF)
$(call color_progress_prefix, "Name")
@echo $(KERNEL_BIN)
$(call color_progress_prefix, "Size")
@printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1`
$(call disk_usage_KiB, $(KERNEL_BIN))
##------------------------------------------------------------------------------
## Generate the documentation
@ -182,7 +182,6 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \
--section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt
##------------------------------------------------------------------------------
@ -192,8 +191,3 @@ nm: $(KERNEL_ELF)
$(call color_header, "Launching nm")
@$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
##------------------------------------------------------------------------------
## Helper target for rust-analyzer
##------------------------------------------------------------------------------
check:
@RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json

@ -2,319 +2,29 @@
## tl;dr
我们拓展了`boot.S`在第一次启动的时候调用Rust代码。在Rust的代码中先清零了[bss] section然后通过调用`panic()`挂起CPU。再次运行`make qemu`看看新增加的代码是怎么运行的。
- 我们拓展了`boot.S`在第一次启动的时候调用Rust代码。
在跳转到rust代码前对运行时进行了一些初始化工作。
- Rust通过调用`panic()`挂起CPU。
- 再次运行`make qemu`看看新增加的代码是怎么运行的。
## 值得注意的变化
- 链接脚本linker script中有了更多的section。
- `.rodata`, `.data`
- `.bss`
- `_start()`:
- 当核心不是`core0`第0号核心的时候挂起该CPU核心。
- `core0`会调用Rust的函数`runtime_init()`。
- `runtime_init.rs`内的`runtime_init()`
- 清零了`.bss` section.
- 它调用了`kernel_init()`, 这个函数又调用了`panic!()`, panic函数最终把`core0`和其他核心一样挂起了。
- 链接脚本linker script中的变化:
- 新程序段sections: `.rodata`, `.got`, `.data`, `.bss`.
- 使用一个独立的位置(`.text._start_arguments`)来保存`_start()`引导函数所使用的参数。
- `_start()` in `_arch/__arch_name__/cpu/boot.s`:
1. 当核心不是`core0`第0号核心的时候挂起该CPU核心。
1. 通过清零`.bss`程序段来初始化`DRAM`.
1. 初始化堆栈指针(`stack pointer`.
1. 跳转到`arch/__arch_name__/cpu/boot.rs`文件中定义的`_start_rust()`函数
- `_start_rust()`:
1. 它调用了`kernel_init()`, 这个函数又调用了`panic!()`, panic函数最终把`core0`和其他核心一样挂起了。
- 目前依赖 [aarch64-cpu] 程序库, 这个库零成本的包装了处理 CPU 资源时的“不安全”部分。
- 详细请参考 `_arch/__arch_name__/cpu.rs`.
[bss]: https://en.wikipedia.org/wiki/.bss
[aarch64-cpu]: https://github.com/rust-embedded/aarch64-cpu
## 相比之前的变化diff
```diff
请检查[英文版本](README.md#diff-to-previous),这是最新的。
diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml
--- 01_wait_forever/Cargo.toml
+++ 02_runtime_init/Cargo.toml
@@ -4,6 +4,9 @@
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
edition = "2018"
+[profile.release]
+lto = true
+
# The features section is used to select the target board.
[features]
default = []
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.S 02_runtime_init/src/_arch/aarch64/cpu/boot.S
--- 01_wait_forever/src/_arch/aarch64/cpu/boot.S
+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.S
@@ -7,5 +7,15 @@
.global _start
_start:
-1: wfe // Wait for event
- b 1b // In case an event happened, jump back to 1
+ mrs x1, mpidr_el1 // Read Multiprocessor Affinity Register
+ and x1, x1, #3 // Clear all bits except [1:0], which hold core id
+ cbz x1, 2f // Jump to label 2 if we are core 0
+1: wfe // Wait for event
+ b 1b // In case an event happened, jump back to 1
+2: // If we are here, we are core0
+ ldr x1, =_start // Load address of function "_start()"
+ mov sp, x1 // Set start of stack to before our code, aka first
+ // address before "_start()"
+ bl runtime_init // Jump to the "runtime_init()" kernel function
+ b 1b // We should never reach here. But just in case,
+ // park this core aswell
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aarch64/cpu.rs
--- 01_wait_forever/src/_arch/aarch64/cpu.rs
+++ 02_runtime_init/src/_arch/aarch64/cpu.rs
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! Architectural processor code.
+//!
+//! # Orientation
+//!
+//! Since arch modules are imported into generic modules using the path attribute, the path of this
+//! file is:
+//!
+//! crate::cpu::arch_cpu
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Pause execution on the core.
+#[inline(always)]
+pub fn wait_forever() -> ! {
+ unsafe {
+ loop {
+ #[rustfmt::skip]
+ asm!(
+ "wfe",
+ options(nomem, nostack, preserves_flags)
+ );
+ }
+ }
+}
diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld
--- 01_wait_forever/src/bsp/raspberrypi/link.ld
+++ 02_runtime_init/src/bsp/raspberrypi/link.ld
@@ -13,5 +13,27 @@
*(.text._start) *(.text*)
}
+ .rodata :
+ {
+ *(.rodata*)
+ }
+
+ .data :
+ {
+ *(.data*)
+ }
+
+ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
+ .bss ALIGN(8):
+ {
+ __bss_start = .;
+ *(.bss*);
+ . = ALIGN(8);
+
+ /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
+ . += 8;
+ __bss_end_inclusive = . - 8;
+ }
+
/DISCARD/ : { *(.comment*) }
}
diff -uNr 01_wait_forever/src/bsp/raspberrypi/memory.rs 02_runtime_init/src/bsp/raspberrypi/memory.rs
--- 01_wait_forever/src/bsp/raspberrypi/memory.rs
+++ 02_runtime_init/src/bsp/raspberrypi/memory.rs
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! BSP Memory Management.
+
+use core::{cell::UnsafeCell, ops::RangeInclusive};
+
+//--------------------------------------------------------------------------------------------------
+// Private Definitions
+//--------------------------------------------------------------------------------------------------
+
+// Symbols from the linker script.
+extern "Rust" {
+ static __bss_start: UnsafeCell<u64>;
+ static __bss_end_inclusive: UnsafeCell<u64>;
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Return the inclusive range spanning the .bss section.
+///
+/// # Safety
+///
+/// - Values are provided by the linker script and must be trusted as-is.
+/// - The linker-provided addresses must be u64 aligned.
+pub fn bss_range_inclusive() -> RangeInclusive<*mut u64> {
+ let range;
+ unsafe {
+ range = RangeInclusive::new(__bss_start.get(), __bss_end_inclusive.get());
+ }
+ assert!(!range.is_empty());
+
+ range
+}
diff -uNr 01_wait_forever/src/bsp/raspberrypi.rs 02_runtime_init/src/bsp/raspberrypi.rs
--- 01_wait_forever/src/bsp/raspberrypi.rs
+++ 02_runtime_init/src/bsp/raspberrypi.rs
@@ -4,4 +4,4 @@
//! Top-level BSP file for the Raspberry Pi 3 and 4.
-// Coming soon.
+pub mod memory;
diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs
--- 01_wait_forever/src/cpu.rs
+++ 02_runtime_init/src/cpu.rs
@@ -4,4 +4,13 @@
//! Processor code.
+#[cfg(target_arch = "aarch64")]
+#[path = "_arch/aarch64/cpu.rs"]
+mod arch_cpu;
+
mod boot;
+
+//--------------------------------------------------------------------------------------------------
+// Architectural Public Reexports
+//--------------------------------------------------------------------------------------------------
+pub use arch_cpu::wait_forever;
diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
--- 01_wait_forever/src/main.rs
+++ 02_runtime_init/src/main.rs
@@ -102,6 +102,7 @@
//!
//! 1. The kernel's entry point is the function [`cpu::boot::arch_boot::_start()`].
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.rs`.
+//! 2. Once finished with architectural setup, the arch code calls [`runtime_init::runtime_init()`].
//!
//! [`cpu::boot::arch_boot::_start()`]: cpu/boot/arch_boot/fn._start.html
@@ -112,6 +113,15 @@
mod bsp;
mod cpu;
+mod memory;
mod panic_wait;
+mod runtime_init;
-// Kernel code coming next tutorial.
+/// Early init code.
+///
+/// # Safety
+///
+/// - Only a single core must be active and running this function.
+unsafe fn kernel_init() -> ! {
+ panic!()
+}
diff -uNr 01_wait_forever/src/memory.rs 02_runtime_init/src/memory.rs
--- 01_wait_forever/src/memory.rs
+++ 02_runtime_init/src/memory.rs
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! Memory Management.
+
+use core::ops::RangeInclusive;
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Zero out an inclusive memory range.
+///
+/// # Safety
+///
+/// - `range.start` and `range.end` must be valid.
+/// - `range.start` and `range.end` must be `T` aligned.
+pub unsafe fn zero_volatile<T>(range: RangeInclusive<*mut T>)
+where
+ T: From<u8>,
+{
+ let mut ptr = *range.start();
+ let end_inclusive = *range.end();
+
+ while ptr <= end_inclusive {
+ core::ptr::write_volatile(ptr, T::from(0));
+ ptr = ptr.offset(1);
+ }
+}
diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs
--- 01_wait_forever/src/panic_wait.rs
+++ 02_runtime_init/src/panic_wait.rs
@@ -4,9 +4,10 @@
//! A panic handler that infinitely waits.
+use crate::cpu;
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
- unimplemented!()
+ cpu::wait_forever()
}
diff -uNr 01_wait_forever/src/runtime_init.rs 02_runtime_init/src/runtime_init.rs
--- 01_wait_forever/src/runtime_init.rs
+++ 02_runtime_init/src/runtime_init.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! Rust runtime initialization code.
+
+use crate::{bsp, memory};
+
+//--------------------------------------------------------------------------------------------------
+// Private Code
+//--------------------------------------------------------------------------------------------------
+
+/// Zero out the .bss section.
+///
+/// # Safety
+///
+/// - Must only be called pre `kernel_init()`.
+#[inline(always)]
+unsafe fn zero_bss() {
+ memory::zero_volatile(bsp::memory::bss_range_inclusive());
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
+/// init code.
+///
+/// # Safety
+///
+/// - Only a single core must be active and running this function.
+#[no_mangle]
+pub unsafe fn runtime_init() -> ! {
+ zero_bss();
+
+ crate::kernel_init()
+}
```

@ -8,341 +8,30 @@
## Adiciones importantes
* Adiciones importantes al script `link.ld`:
* Adiciones importantes al script `kernel.ld`:
* Nuevas secciones: `.rodata`, `.got`, `.data`, `.bss`.
* Un lugar totalmente dedicado a enlazar argumentos de tiempo de arranque (boot-time) que necesitan estar listos cuando se llame a `_start()`.
* `_start()` en `_arch/__arch_name__/cpu/boot.s`:
1. Para todos los núcleos expecto el núcleo 0.
2. Inicializa la [`DRAM`](https://es.wikipedia.org/wiki/DRAM) poniendo a cero la sección [`.bss`](https://en.wikipedia.org/wiki/.bss).
3. Configura el `stack pointer` (puntero a la memoria [pila](https://es.wikipedia.org/wiki/Pila_(inform%C3%A1tica))).
4. Salta hacia la función `_start_rust()`, definida en `arch/__arch_name__/cpu/boot.rs`.
* `_start_rust()`:
* Llama a `kernel_init()`, que llama a `panic!()`, que al final también pone al núcleo 0 en pausa.
* La librería ahora usa el crate [cortex-a](https://github.com/rust-embedded/cortex-a), que nos da abstracciones sin coste y envuelve las partes que hacen uso de un `unsafe` (partes con código que no es seguro y podría causar errores) cuando se trabaja directamente con los recursos del procesador.
* La librería ahora usa el crate [aarch64-cpu](https://github.com/rust-embedded/aarch64-cpu), que nos da abstracciones sin coste y envuelve las partes que hacen uso de un `unsafe` (partes con código que no es seguro y podría causar errores) cuando se trabaja directamente con los recursos del procesador.
* Lo puedes ver en acción en `_arch/__arch_name__/cpu.rs`.
## Diferencia con el archivo anterior
```diff
diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml
--- 01_wait_forever/Cargo.toml
+++ 02_runtime_init/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "mingo"
-version = "0.1.0"
+version = "0.2.0"
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
edition = "2021"
@@ -21,3 +21,7 @@
##--------------------------------------------------------------------------------------------------
[dependencies]
+
+# Platform specific dependencies
+[target.'cfg(target_arch = "aarch64")'.dependencies]
+cortex-a = { version = "7.x.x" }
diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile
--- 01_wait_forever/Makefile
+++ 02_runtime_init/Makefile
@@ -153,6 +153,8 @@
$(call colorecho, "\nLaunching objdump")
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \
+ --section .rodata \
+ --section .got \
$(KERNEL_ELF) | rustfilt
##------------------------------------------------------------------------------
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
--- 01_wait_forever/src/_arch/aarch64/cpu/boot.rs
+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
@@ -13,3 +13,15 @@
// Assembly counterpart to this file.
core::arch::global_asm!(include_str!("boot.s"));
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// The Rust entry of the `kernel` binary.
+///
+/// The function is called from the assembly `_start` function.
+#[no_mangle]
+pub unsafe fn _start_rust() -> ! {
+ crate::kernel_init()
+}
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch/aarch64/cpu/boot.s
--- 01_wait_forever/src/_arch/aarch64/cpu/boot.s
+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.s
@@ -3,6 +3,24 @@
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
//--------------------------------------------------------------------------------------------------
+// Definitions
+//--------------------------------------------------------------------------------------------------
+
+// Load the address of a symbol into a register, PC-relative.
+//
+// The symbol must lie within +/- 4 GiB of the Program Counter.
+//
+// # Resources
+//
+// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html
+.macro ADR_REL register, symbol
+ adrp \register, \symbol
+ add \register, \register, #:lo12:\symbol
+.endm
+
+.equ _core_id_mask, 0b11
+
+//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
.section .text._start
@@ -11,6 +29,34 @@
// fn _start()
//------------------------------------------------------------------------------
_start:
+ // Only proceed on the boot core. Park it otherwise.
+ mrs x1, MPIDR_EL1
+ and x1, x1, _core_id_mask
+ ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
+ cmp x1, x2
+ b.ne .L_parking_loop
+
+ // If execution reaches here, it is the boot core.
+
+ // Initialize DRAM.
+ ADR_REL x0, __bss_start
+ ADR_REL x1, __bss_end_exclusive
+
+.L_bss_init_loop:
+ cmp x0, x1
+ b.eq .L_prepare_rust
+ stp xzr, xzr, [x0], #16
+ b .L_bss_init_loop
+
+ // Prepare the jump to Rust code.
+.L_prepare_rust:
+ // Set the stack pointer.
+ ADR_REL x0, __boot_core_stack_end_exclusive
+ mov sp, x0
+
+ // Jump to Rust code.
+ b _start_rust
+
// Infinitely wait for events (aka "park the core").
.L_parking_loop:
wfe
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aarch64/cpu.rs
--- 01_wait_forever/src/_arch/aarch64/cpu.rs
+++ 02_runtime_init/src/_arch/aarch64/cpu.rs
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! Architectural processor code.
+//!
+//! # Orientation
+//!
+//! Since arch modules are imported into generic modules using the path attribute, the path of this
+//! file is:
+//!
+//! crate::cpu::arch_cpu
+
+use cortex_a::asm;
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Pause execution on the core.
+#[inline(always)]
+pub fn wait_forever() -> ! {
+ loop {
+ asm::wfe()
+ }
+}
diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/raspberrypi/cpu.rs
--- 01_wait_forever/src/bsp/raspberrypi/cpu.rs
+++ 02_runtime_init/src/bsp/raspberrypi/cpu.rs
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! BSP Processor code.
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
+//--------------------------------------------------------------------------------------------------
+
+/// Used by `arch` code to find the early boot core.
+#[no_mangle]
+#[link_section = ".text._start_arguments"]
+pub static BOOT_CORE_ID: u64 = 0;
diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld
--- 01_wait_forever/src/bsp/raspberrypi/link.ld
+++ 02_runtime_init/src/bsp/raspberrypi/link.ld
@@ -3,6 +3,8 @@
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
*/
+__rpi_phys_dram_start_addr = 0;
+
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
__rpi_phys_binary_load_addr = 0x80000;
@@ -13,21 +15,58 @@
* 4 == R
* 5 == RX
* 6 == RW
+ *
+ * Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses.
+ * It doesn't mean all of them need actually be loaded.
*/
PHDRS
{
- segment_code PT_LOAD FLAGS(5);
+ segment_boot_core_stack PT_LOAD FLAGS(6);
+ segment_code PT_LOAD FLAGS(5);
+ segment_data PT_LOAD FLAGS(6);
}
SECTIONS
{
- . = __rpi_phys_binary_load_addr;
+ . = __rpi_phys_dram_start_addr;
+
+ /***********************************************************************************************
+ * Boot Core Stack
+ ***********************************************************************************************/
+ .boot_core_stack (NOLOAD) :
+ {
+ /* ^ */
+ /* | stack */
+ . += __rpi_phys_binary_load_addr; /* | growth */
+ /* | direction */
+ __boot_core_stack_end_exclusive = .; /* | */
+ } :segment_boot_core_stack
/***********************************************************************************************
- * Code
+ * Code + RO Data + Global Offset Table
***********************************************************************************************/
.text :
{
KEEP(*(.text._start))
+ *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */
+ *(.text._start_rust) /* The Rust entry point */
+ *(.text*) /* Everything else */
} :segment_code
+
+ .rodata : ALIGN(8) { *(.rodata*) } :segment_code
+ .got : ALIGN(8) { *(.got) } :segment_code
+
+ /***********************************************************************************************
+ * Data + BSS
+ ***********************************************************************************************/
+ .data : { *(.data*) } :segment_data
+
+ /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
+ .bss (NOLOAD) : ALIGN(16)
+ {
+ __bss_start = .;
+ *(.bss*);
+ . = ALIGN(16);
+ __bss_end_exclusive = .;
+ } :segment_data
}
diff -uNr 01_wait_forever/src/bsp/raspberrypi.rs 02_runtime_init/src/bsp/raspberrypi.rs
--- 01_wait_forever/src/bsp/raspberrypi.rs
+++ 02_runtime_init/src/bsp/raspberrypi.rs
@@ -4,4 +4,4 @@
//! Top-level BSP file for the Raspberry Pi 3 and 4.
-// Coming soon.
+pub mod cpu;
diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs
--- 01_wait_forever/src/cpu.rs
+++ 02_runtime_init/src/cpu.rs
@@ -4,4 +4,13 @@
//! Processor code.
+#[cfg(target_arch = "aarch64")]
+#[path = "_arch/aarch64/cpu.rs"]
+mod arch_cpu;
+
mod boot;
+
+//--------------------------------------------------------------------------------------------------
+// Architectural Public Reexports
+//--------------------------------------------------------------------------------------------------
+pub use arch_cpu::wait_forever;
diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
--- 01_wait_forever/src/main.rs
+++ 02_runtime_init/src/main.rs
@@ -102,6 +102,7 @@
//!
//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`.
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
+//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
#![no_main]
#![no_std]
@@ -110,4 +111,11 @@
mod cpu;
mod panic_wait;
-// Kernel code coming next tutorial.
+/// Early init code.
+///
+/// # Safety
+///
+/// - Only a single core must be active and running this function.
+unsafe fn kernel_init() -> ! {
+ panic!()
+}
diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs
--- 01_wait_forever/src/panic_wait.rs
+++ 02_runtime_init/src/panic_wait.rs
@@ -4,9 +4,10 @@
//! A panic handler that infinitely waits.
+use crate::cpu;
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
- unimplemented!()
+ cpu::wait_forever()
}
```
Please check [the english version](README.md#diff-to-previous), which is kept up-to-date.

@ -19,12 +19,12 @@
1. Jumps to the `_start_rust()` function, defined in `arch/__arch_name__/cpu/boot.rs`.
- `_start_rust()`:
- Calls `kernel_init()`, which calls `panic!()`, which eventually halts core0 as well.
- The library now uses the [cortex-a] crate, which provides zero-overhead abstractions and wraps
- The library now uses the [aarch64-cpu] crate, which provides zero-overhead abstractions and wraps
`unsafe` parts when dealing with the CPU's resources.
- See it in action in `_arch/__arch_name__/cpu.rs`.
[bss]: https://en.wikipedia.org/wiki/.bss
[cortex-a]: https://github.com/rust-embedded/cortex-a
[aarch64-cpu]: https://github.com/rust-embedded/aarch64-cpu
## Diff to previous
```diff
@ -47,28 +47,31 @@ diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml
+
+# Platform specific dependencies
+[target.'cfg(target_arch = "aarch64")'.dependencies]
+cortex-a = { version = "7.x.x" }
+aarch64-cpu = { version = "9.x.x" }
diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile
--- 01_wait_forever/Makefile
+++ 02_runtime_init/Makefile
@@ -181,6 +181,8 @@
@@ -181,6 +181,7 @@
$(call color_header, "Launching objdump")
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \
+ --section .rodata \
+ --section .got \
$(KERNEL_ELF) | rustfilt
##------------------------------------------------------------------------------
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
--- 01_wait_forever/src/_arch/aarch64/cpu/boot.rs
+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
@@ -13,3 +13,15 @@
@@ -14,4 +14,19 @@
use core::arch::global_asm;
// Assembly counterpart to this file.
core::arch::global_asm!(include_str!("boot.s"));
-global_asm!(include_str!("boot.s"));
+global_asm!(
+ include_str!("boot.s"),
+ CONST_CORE_ID_MASK = const 0b11
+);
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
@ -85,8 +88,8 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arc
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch/aarch64/cpu/boot.s
--- 01_wait_forever/src/_arch/aarch64/cpu/boot.s
+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.s
@@ -3,6 +3,24 @@
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
@@ -3,6 +3,22 @@
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//--------------------------------------------------------------------------------------------------
+// Definitions
@ -104,21 +107,19 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch
+ add \register, \register, #:lo12:\symbol
+.endm
+
+.equ _core_id_mask, 0b11
+
+//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
.section .text._start
@@ -11,6 +29,34 @@
@@ -11,6 +27,34 @@
// fn _start()
//------------------------------------------------------------------------------
_start:
+ // Only proceed on the boot core. Park it otherwise.
+ mrs x1, MPIDR_EL1
+ and x1, x1, _core_id_mask
+ ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
+ cmp x1, x2
+ mrs x0, MPIDR_EL1
+ and x0, x0, {CONST_CORE_ID_MASK}
+ ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
+ cmp x0, x1
+ b.ne .L_parking_loop
+
+ // If execution reaches here, it is the boot core.
@ -152,7 +153,7 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aar
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
+
+//! Architectural processor code.
+//!
@ -163,7 +164,7 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aar
+//!
+//! crate::cpu::arch_cpu
+
+use cortex_a::asm;
+use aarch64_cpu::asm;
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
@ -183,7 +184,7 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/ras
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
+
+//! BSP Processor code.
+
@ -196,11 +197,11 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/ras
+#[link_section = ".text._start_arguments"]
+pub static BOOT_CORE_ID: u64 = 0;
diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld
--- 01_wait_forever/src/bsp/raspberrypi/link.ld
+++ 02_runtime_init/src/bsp/raspberrypi/link.ld
diff -uNr 01_wait_forever/src/bsp/raspberrypi/kernel.ld 02_runtime_init/src/bsp/raspberrypi/kernel.ld
--- 01_wait_forever/src/bsp/raspberrypi/kernel.ld
+++ 02_runtime_init/src/bsp/raspberrypi/kernel.ld
@@ -3,6 +3,8 @@
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
* Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
*/
+__rpi_phys_dram_start_addr = 0;
@ -208,7 +209,7 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/ra
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
__rpi_phys_binary_load_addr = 0x80000;
@@ -13,21 +15,58 @@
@@ -13,21 +15,65 @@
* 4 == R
* 5 == RX
* 6 == RW
@ -254,7 +255,6 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/ra
} :segment_code
+
+ .rodata : ALIGN(8) { *(.rodata*) } :segment_code
+ .got : ALIGN(8) { *(.got) } :segment_code
+
+ /***********************************************************************************************
+ * Data + BSS
@ -269,6 +269,14 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/ra
+ . = ALIGN(16);
+ __bss_end_exclusive = .;
+ } :segment_data
+
+ /***********************************************************************************************
+ * Misc
+ ***********************************************************************************************/
+ .got : { *(.got*) }
+ ASSERT(SIZEOF(.got) == 0, "Relocation support not expected")
+
+ /DISCARD/ : { *(.comment*) }
}
diff -uNr 01_wait_forever/src/bsp/raspberrypi.rs 02_runtime_init/src/bsp/raspberrypi.rs
@ -302,15 +310,17 @@ diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs
diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
--- 01_wait_forever/src/main.rs
+++ 02_runtime_init/src/main.rs
@@ -102,6 +102,7 @@
@@ -104,7 +104,9 @@
//!
//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`.
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
+//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
+#![feature(asm_const)]
#![no_main]
#![no_std]
@@ -110,4 +111,11 @@
@@ -112,4 +114,11 @@
mod cpu;
mod panic_wait;

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Architectural processor code.
//!
@ -11,7 +11,7 @@
//!
//! crate::cpu::arch_cpu
use cortex_a::asm;
use aarch64_cpu::asm;
//--------------------------------------------------------------------------------------------------
// Public Code

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//! Architectural boot code.
//!
@ -11,8 +11,13 @@
//!
//! crate::cpu::boot::arch_boot
use core::arch::global_asm;
// Assembly counterpart to this file.
core::arch::global_asm!(include_str!("boot.s"));
global_asm!(
include_str!("boot.s"),
CONST_CORE_ID_MASK = const 0b11
);
//--------------------------------------------------------------------------------------------------
// Public Code

@ -18,8 +18,6 @@
add \register, \register, #:lo12:\symbol
.endm
.equ _core_id_mask, 0b11
//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
@ -30,10 +28,10 @@
//------------------------------------------------------------------------------
_start:
// Only proceed on the boot core. Park it otherwise.
mrs x1, MPIDR_EL1
and x1, x1, _core_id_mask
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
cmp x1, x2
mrs x0, MPIDR_EL1
and x0, x0, {CONST_CORE_ID_MASK}
ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
cmp x0, x1
b.ne .L_parking_loop
// If execution reaches here, it is the boot core.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Conditional reexporting of Board Support Packages.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Top-level BSP file for the Raspberry Pi 3 and 4.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! BSP Processor code.

@ -3,9 +3,6 @@
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
*/
PAGE_SIZE = 64K;
PAGE_MASK = PAGE_SIZE - 1;
__rpi_phys_dram_start_addr = 0;
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
@ -45,12 +42,9 @@ SECTIONS
__boot_core_stack_end_exclusive = .; /* | */
} :segment_boot_core_stack
ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned")
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
__code_start = .;
.text :
{
KEEP(*(.text._start))
@ -60,10 +54,6 @@ SECTIONS
} :segment_code
.rodata : ALIGN(8) { *(.rodata*) } :segment_code
.got : ALIGN(8) { *(.got) } :segment_code
. = ALIGN(PAGE_SIZE);
__code_end_exclusive = .;
/***********************************************************************************************
* Data + BSS
@ -78,4 +68,12 @@ SECTIONS
. = ALIGN(16);
__bss_end_exclusive = .;
} :segment_data
/***********************************************************************************************
* Misc
***********************************************************************************************/
.got : { *(.got*) }
ASSERT(SIZEOF(.got) == 0, "Relocation support not expected")
/DISCARD/ : { *(.comment*) }
}

@ -1,72 +0,0 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0
*
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
*/
__rpi_phys_dram_start_addr = 0;
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
__rpi_phys_binary_load_addr = 0x80000;
ENTRY(__rpi_phys_binary_load_addr)
/* Flags:
* 4 == R
* 5 == RX
* 6 == RW
*
* Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses.
* It doesn't mean all of them need actually be loaded.
*/
PHDRS
{
segment_boot_core_stack PT_LOAD FLAGS(6);
segment_code PT_LOAD FLAGS(5);
segment_data PT_LOAD FLAGS(6);
}
SECTIONS
{
. = __rpi_phys_dram_start_addr;
/***********************************************************************************************
* Boot Core Stack
***********************************************************************************************/
.boot_core_stack (NOLOAD) :
{
/* ^ */
/* | stack */
. += __rpi_phys_binary_load_addr; /* | growth */
/* | direction */
__boot_core_stack_end_exclusive = .; /* | */
} :segment_boot_core_stack
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
.text :
{
KEEP(*(.text._start))
*(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */
*(.text._start_rust) /* The Rust entry point */
*(.text*) /* Everything else */
} :segment_code
.rodata : ALIGN(8) { *(.rodata*) } :segment_code
.got : ALIGN(8) { *(.got) } :segment_code
/***********************************************************************************************
* Data + BSS
***********************************************************************************************/
.data : { *(.data*) } :segment_data
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
.bss (NOLOAD) : ALIGN(16)
{
__bss_start = .;
*(.bss*);
. = ALIGN(16);
__bss_end_exclusive = .;
} :segment_data
}

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2020-2023 Andre Richter <andre.o.richter@gmail.com>
//! Processor code.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//! Boot code.

@ -1,9 +1,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
// Rust embedded logo for `make doc`.
#![doc(html_logo_url = "https://git.io/JeGIp")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png"
)]
//! The `kernel` binary.
//!
@ -104,6 +106,7 @@
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
#![feature(asm_const)]
#![no_main]
#![no_std]

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! A panic handler that infinitely waits.

@ -1,9 +1,10 @@
{
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.overrideCommand": ["make", "check"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.extraArgs": ["--bins"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
}

@ -3,10 +3,10 @@
version = 3
[[package]]
name = "cortex-a"
version = "7.2.0"
name = "aarch64-cpu"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad"
checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225"
dependencies = [
"tock-registers",
]
@ -15,11 +15,11 @@ dependencies = [
name = "mingo"
version = "0.3.0"
dependencies = [
"cortex-a",
"aarch64-cpu",
]
[[package]]
name = "tock-registers"
version = "0.7.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e"
checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c"

@ -24,4 +24,4 @@ path = "src/main.rs"
# Platform specific dependencies
[target.'cfg(target_arch = "aarch64")'.dependencies]
cortex-a = { version = "7.x.x" }
aarch64-cpu = { version = "9.x.x" }

@ -1,9 +1,10 @@
## SPDX-License-Identifier: MIT OR Apache-2.0
##
## Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
## Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
include ../common/format.mk
include ../common/docker.mk
include ../common/format.mk
include ../common/operating_system.mk
##--------------------------------------------------------------------------------------------------
## Optional, user-provided configuration values
@ -51,14 +52,14 @@ export LD_SCRIPT_PATH
##--------------------------------------------------------------------------------------------------
## Targets and Prerequisites
##--------------------------------------------------------------------------------------------------
KERNEL_LINKER_SCRIPT = link.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_MANIFEST = Cargo.toml
KERNEL_LINKER_SCRIPT = kernel.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_ELF = target/$(TARGET)/release/kernel
# This parses cargo's dep-info file.
# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG)
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)
@ -81,7 +82,6 @@ COMPILER_ARGS = --target=$(TARGET) \
RUSTC_CMD = cargo rustc $(COMPILER_ARGS)
DOC_CMD = cargo doc $(COMPILER_ARGS)
CLIPPY_CMD = cargo clippy $(COMPILER_ARGS)
CHECK_CMD = cargo check $(COMPILER_ARGS)
OBJCOPY_CMD = rust-objcopy \
--strip-all \
-O binary
@ -134,7 +134,7 @@ $(KERNEL_BIN): $(KERNEL_ELF)
$(call color_progress_prefix, "Name")
@echo $(KERNEL_BIN)
$(call color_progress_prefix, "Size")
@printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1`
$(call disk_usage_KiB, $(KERNEL_BIN))
##------------------------------------------------------------------------------
## Generate the documentation
@ -185,7 +185,6 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \
--section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt
##------------------------------------------------------------------------------
@ -195,12 +194,6 @@ nm: $(KERNEL_ELF)
$(call color_header, "Launching nm")
@$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
##------------------------------------------------------------------------------
## Helper target for rust-analyzer
##------------------------------------------------------------------------------
check:
@RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json
##--------------------------------------------------------------------------------------------------

@ -0,0 +1,35 @@
# 教程 03 - Hacky Hello World
## tl;dr
- 介绍全局的`println!()`宏以便尽早启用"printf debugging"。
- 为了保持教程长度合理,打印函数目前 "滥用" 了 QEMU 属性,该属性允许我们在没有正确设置的情况下使用树莓派的`UART`。
- 在接下来的教程中将逐步使用真实硬件的`UART`。
## 值得注意的补充
- `src/console.rs`为控制台命令和通过`console::console()`对内核控制台的全局访问引入了接口`Traits`。
- `src/bsp/raspberrypi/console.rs` 实现QEMU仿真UART的接口。
- 紧急处理程序使用新的`println!()`以显示用户错误消息。
- 有一个新的Makefile目录`make test`,用于自动测试。它在`QEMU`中引导编译后的内核,并检查内核生成的预期输出字符串。
- 在本教程中,它检查字符串`Stopping here`,该字符串由`panic!()`在`main.rs`的末尾。
## 测试一下
QEMU不再以汇编模式运行。从现在起它将显示`console`的输出。
```console
$ make qemu
[...]
Hello from Rust!
Kernel panic!
Panic location:
File 'src/main.rs', line 126, column 5
Stopping here.
```
## 相比之前的变化diff
请检查[英文版本](README.md#diff-to-previous),这是最新的。

@ -31,292 +31,15 @@ Kernel panic: Stopping here.
* *Hacky:* Solución torpe o poco elegante para un problema.
* *Debugging:* Proceso para identificar y corregir errores de programación.
* *printf debugging:* Usado para describir el trabajo de depuración (*debugging*) poniendo comandos que dan una salida en consola, como el de "printf", en diferentes lugares del programa; observando la información y tratando de deducir qué está mal en el programa basándose en la información que nos dan nuestros comandos.
* *Traits:* Un *trait* le hace saber al compilador de Rust acerca de una funcionalidad que tiene un tipo de dato particular y que puede compartir con otros tipos de datos.
> NOTA: Los *traits* son similares a una característica que se le conoce comúnmente como *interfaces* en otros lenguajes, aunque con algunas diferencias.
Si deseas aprender más acerca de esto, por favor lee este capítulo del libro de Rust: [Traits: Defining Shared Behavior - The Rust Programming Language](https://doc.rust-lang.org/book/ch10-02-traits.html)
## Diferencias con el archivo anterior
```diff
diff -uNr 02_runtime_init/Cargo.toml 03_hacky_hello_world/Cargo.toml
--- 02_runtime_init/Cargo.toml
+++ 03_hacky_hello_world/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "mingo"
-version = "0.2.0"
+version = "0.3.0"
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
edition = "2021"
diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile
--- 02_runtime_init/Makefile
+++ 03_hacky_hello_world/Makefile
@@ -24,7 +24,7 @@
KERNEL_BIN = kernel8.img
QEMU_BINARY = qemu-system-aarch64
QEMU_MACHINE_TYPE = raspi3
- QEMU_RELEASE_ARGS = -d in_asm -display none
+ QEMU_RELEASE_ARGS = -serial stdio -display none
OBJDUMP_BINARY = aarch64-none-elf-objdump
NM_BINARY = aarch64-none-elf-nm
READELF_BINARY = aarch64-none-elf-readelf
@@ -35,7 +35,7 @@
KERNEL_BIN = kernel8.img
QEMU_BINARY = qemu-system-aarch64
QEMU_MACHINE_TYPE =
- QEMU_RELEASE_ARGS = -d in_asm -display none
+ QEMU_RELEASE_ARGS = -serial stdio -display none
OBJDUMP_BINARY = aarch64-none-elf-objdump
NM_BINARY = aarch64-none-elf-nm
READELF_BINARY = aarch64-none-elf-readelf
@@ -71,17 +71,20 @@
--strip-all \
-O binary
-EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
+EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
+EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb
##------------------------------------------------------------------------------
## Dockerization
##------------------------------------------------------------------------------
-DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial
-DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i
+DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial
+DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i
+DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common
# DOCKER_IMAGE defined in include file (see top of this file).
DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE)
DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE)
+DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE)
@@ -169,3 +172,28 @@
##------------------------------------------------------------------------------
check:
@RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json
+
+
+
+##--------------------------------------------------------------------------------------------------
+## Testing targets
+##--------------------------------------------------------------------------------------------------
+.PHONY: test test_boot
+
+ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board.
+
+test_boot test :
+ $(call colorecho, "\n$(QEMU_MISSING_STRING)")
+
+else # QEMU is supported.
+
+##------------------------------------------------------------------------------
+## Run boot test
+##------------------------------------------------------------------------------
+test_boot: $(KERNEL_BIN)
+ $(call colorecho, "\nBoot test - $(BSP)")
+ @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
+
+test: test_boot
+
+endif
diff -uNr 02_runtime_init/src/bsp/raspberrypi/console.rs 03_hacky_hello_world/src/bsp/raspberrypi/console.rs
--- 02_runtime_init/src/bsp/raspberrypi/console.rs
+++ 03_hacky_hello_world/src/bsp/raspberrypi/console.rs
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! BSP console facilities.
+
+use crate::console;
+use core::fmt;
+
+//--------------------------------------------------------------------------------------------------
+// Private Definitions
+//--------------------------------------------------------------------------------------------------
+
+/// A mystical, magical device for generating QEMU output out of the void.
+struct QEMUOutput;
+
+//--------------------------------------------------------------------------------------------------
+// Private Code
+//--------------------------------------------------------------------------------------------------
+
+/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
+/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
+/// we get `write_fmt()` automatically.
+///
+/// See [`src/print.rs`].
+///
+/// [`src/print.rs`]: ../../print/index.html
+impl fmt::Write for QEMUOutput {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ for c in s.chars() {
+ unsafe {
+ core::ptr::write_volatile(0x3F20_1000 as *mut u8, c as u8);
+ }
+ }
+
+ Ok(())
+ }
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Return a reference to the console.
+pub fn console() -> impl console::interface::Write {
+ QEMUOutput {}
+}
diff -uNr 02_runtime_init/src/bsp/raspberrypi.rs 03_hacky_hello_world/src/bsp/raspberrypi.rs
--- 02_runtime_init/src/bsp/raspberrypi.rs
+++ 03_hacky_hello_world/src/bsp/raspberrypi.rs
@@ -4,4 +4,5 @@
//! Top-level BSP file for the Raspberry Pi 3 and 4.
+pub mod console;
pub mod cpu;
diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs
--- 02_runtime_init/src/console.rs
+++ 03_hacky_hello_world/src/console.rs
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! System console.
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
+//--------------------------------------------------------------------------------------------------
+
+/// Console interfaces.
+pub mod interface {
+ /// Console write functions.
+ ///
+ /// `core::fmt::Write` is exactly what we need for now. Re-export it here because
+ /// implementing `console::Write` gives a better hint to the reader about the
+ /// intention.
+ pub use core::fmt::Write;
+}
diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs
--- 02_runtime_init/src/main.rs
+++ 03_hacky_hello_world/src/main.rs
@@ -104,12 +104,16 @@
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
+#![feature(format_args_nl)]
+#![feature(panic_info_message)]
#![no_main]
#![no_std]
mod bsp;
+mod console;
mod cpu;
mod panic_wait;
+mod print;
/// Early init code.
///
@@ -117,5 +121,7 @@
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
- panic!()
+ println!("[0] Hello from Rust!");
+
+ panic!("Stopping here.")
}
diff -uNr 02_runtime_init/src/panic_wait.rs 03_hacky_hello_world/src/panic_wait.rs
--- 02_runtime_init/src/panic_wait.rs
+++ 03_hacky_hello_world/src/panic_wait.rs
@@ -4,10 +4,16 @@
//! A panic handler that infinitely waits.
-use crate::cpu;
+use crate::{cpu, println};
use core::panic::PanicInfo;
#[panic_handler]
-fn panic(_info: &PanicInfo) -> ! {
+fn panic(info: &PanicInfo) -> ! {
+ if let Some(args) = info.message() {
+ println!("\nKernel panic: {}", args);
+ } else {
+ println!("\nKernel panic!");
+ }
+
cpu::wait_forever()
}
diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs
--- 02_runtime_init/src/print.rs
+++ 03_hacky_hello_world/src/print.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! Printing.
+
+use crate::{bsp, console};
+use core::fmt;
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+#[doc(hidden)]
+pub fn _print(args: fmt::Arguments) {
+ use console::interface::Write;
+
+ bsp::console::console().write_fmt(args).unwrap();
+}
+
+/// Prints without a newline.
+///
+/// Carbon copy from <https://doc.rust-lang.org/src/std/macros.rs.html>
+#[macro_export]
+macro_rules! print {
+ ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*)));
+}
+
+/// Prints with a newline.
+///
+/// Carbon copy from <https://doc.rust-lang.org/src/std/macros.rs.html>
+#[macro_export]
+macro_rules! println {
+ () => ($crate::print!("\n"));
+ ($($arg:tt)*) => ({
+ $crate::print::_print(format_args_nl!($($arg)*));
+ })
+}
diff -uNr 02_runtime_init/tests/boot_test_string.rb 03_hacky_hello_world/tests/boot_test_string.rb
--- 02_runtime_init/tests/boot_test_string.rb
+++ 03_hacky_hello_world/tests/boot_test_string.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+EXPECTED_PRINT = 'Stopping here'
```
Please check [the english version](README.md#diff-to-previous), which is kept up-to-date.

@ -2,16 +2,17 @@
## tl;dr
- Introducing global `print!()` macros to enable "printf debugging" at the earliest.
- Introducing global `println!()` macros to enable "printf debugging" at the earliest.
- To keep tutorial length reasonable, printing functions for now "abuse" a QEMU property that lets
us use the Raspberry's `UART` without setting it up properly.
- Using the real hardware `UART` is enabled step-by-step in following tutorials.
## Notable additions
- `src/console.rs` introduces interface `Traits` for console commands.
- `src/console.rs` introduces interface `Traits` for console commands and global access to the
kernel's console through `console::console()`.
- `src/bsp/raspberrypi/console.rs` implements the interface for QEMU's emulated UART.
- The panic handler makes use of the new `print!()` to display user error messages.
- The panic handler makes use of the new `println!()` to display user error messages.
- There is a new Makefile target, `make test`, intended for automated testing. It boots the compiled
kernel in `QEMU`, and checks for an expected output string produced by the kernel.
- In this tutorial, it checks for the string `Stopping here`, which is emitted by the `panic!()`
@ -52,7 +53,7 @@ diff -uNr 02_runtime_init/Cargo.toml 03_hacky_hello_world/Cargo.toml
diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile
--- 02_runtime_init/Makefile
+++ 03_hacky_hello_world/Makefile
@@ -24,7 +24,7 @@
@@ -25,7 +25,7 @@
KERNEL_BIN = kernel8.img
QEMU_BINARY = qemu-system-aarch64
QEMU_MACHINE_TYPE = raspi3
@ -61,7 +62,7 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile
OBJDUMP_BINARY = aarch64-none-elf-objdump
NM_BINARY = aarch64-none-elf-nm
READELF_BINARY = aarch64-none-elf-readelf
@@ -35,7 +35,7 @@
@@ -36,7 +36,7 @@
KERNEL_BIN = kernel8.img
QEMU_BINARY = qemu-system-aarch64
QEMU_MACHINE_TYPE =
@ -94,11 +95,10 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile
@@ -197,3 +200,28 @@
##------------------------------------------------------------------------------
check:
@RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json
+
@@ -191,3 +194,27 @@
$(call color_header, "Launching nm")
@$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
+
+
+##--------------------------------------------------------------------------------------------------
@ -130,7 +130,7 @@ diff -uNr 02_runtime_init/src/bsp/raspberrypi/console.rs 03_hacky_hello_world/sr
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
+
+//! BSP console facilities.
+
@ -189,13 +189,15 @@ diff -uNr 02_runtime_init/src/bsp/raspberrypi.rs 03_hacky_hello_world/src/bsp/ra
diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs
--- 02_runtime_init/src/console.rs
+++ 03_hacky_hello_world/src/console.rs
@@ -0,0 +1,19 @@
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
+
+//! System console.
+
+use crate::bsp;
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
+//--------------------------------------------------------------------------------------------------
@ -209,14 +211,25 @@ diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs
+ /// intention.
+ pub use core::fmt::Write;
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Return a reference to the console.
+///
+/// This is the global console used by all printing macros.
+pub fn console() -> impl interface::Write {
+ bsp::console::console()
+}
diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs
--- 02_runtime_init/src/main.rs
+++ 03_hacky_hello_world/src/main.rs
@@ -104,12 +104,16 @@
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
@@ -107,12 +107,16 @@
//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
#![feature(asm_const)]
+#![feature(format_args_nl)]
+#![feature(panic_info_message)]
#![no_main]
@ -230,7 +243,7 @@ diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs
/// Early init code.
///
@@ -117,5 +121,7 @@
@@ -120,5 +124,7 @@
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
@ -314,11 +327,11 @@ diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
+// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
+
+//! Printing.
+
+use crate::{bsp, console};
+use crate::console;
+use core::fmt;
+
+//--------------------------------------------------------------------------------------------------
@ -329,7 +342,7 @@ diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs
+pub fn _print(args: fmt::Arguments) {
+ use console::interface::Write;
+
+ bsp::console::console().write_fmt(args).unwrap();
+ console::console().write_fmt(args).unwrap();
+}
+
+/// Prints without a newline.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Architectural processor code.
//!
@ -11,7 +11,7 @@
//!
//! crate::cpu::arch_cpu
use cortex_a::asm;
use aarch64_cpu::asm;
//--------------------------------------------------------------------------------------------------
// Public Code

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//! Architectural boot code.
//!
@ -11,8 +11,13 @@
//!
//! crate::cpu::boot::arch_boot
use core::arch::global_asm;
// Assembly counterpart to this file.
core::arch::global_asm!(include_str!("boot.s"));
global_asm!(
include_str!("boot.s"),
CONST_CORE_ID_MASK = const 0b11
);
//--------------------------------------------------------------------------------------------------
// Public Code

@ -18,8 +18,6 @@
add \register, \register, #:lo12:\symbol
.endm
.equ _core_id_mask, 0b11
//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
@ -30,10 +28,10 @@
//------------------------------------------------------------------------------
_start:
// Only proceed on the boot core. Park it otherwise.
mrs x1, MPIDR_EL1
and x1, x1, _core_id_mask
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
cmp x1, x2
mrs x0, MPIDR_EL1
and x0, x0, {CONST_CORE_ID_MASK}
ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
cmp x0, x1
b.ne .L_parking_loop
// If execution reaches here, it is the boot core.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Conditional reexporting of Board Support Packages.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Top-level BSP file for the Raspberry Pi 3 and 4.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! BSP console facilities.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! BSP Processor code.

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0
*
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
*/
__rpi_phys_dram_start_addr = 0;
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
__rpi_phys_binary_load_addr = 0x80000;
ENTRY(__rpi_phys_binary_load_addr)
/* Flags:
* 4 == R
* 5 == RX
* 6 == RW
*
* Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses.
* It doesn't mean all of them need actually be loaded.
*/
PHDRS
{
segment_boot_core_stack PT_LOAD FLAGS(6);
segment_code PT_LOAD FLAGS(5);
segment_data PT_LOAD FLAGS(6);
}
SECTIONS
{
. = __rpi_phys_dram_start_addr;
/***********************************************************************************************
* Boot Core Stack
***********************************************************************************************/
.boot_core_stack (NOLOAD) :
{
/* ^ */
/* | stack */
. += __rpi_phys_binary_load_addr; /* | growth */
/* | direction */
__boot_core_stack_end_exclusive = .; /* | */
} :segment_boot_core_stack
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
.text :
{
KEEP(*(.text._start))
*(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */
*(.text._start_rust) /* The Rust entry point */
*(.text*) /* Everything else */
} :segment_code
.rodata : ALIGN(8) { *(.rodata*) } :segment_code
/***********************************************************************************************
* Data + BSS
***********************************************************************************************/
.data : { *(.data*) } :segment_data
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
.bss (NOLOAD) : ALIGN(16)
{
__bss_start = .;
*(.bss*);
. = ALIGN(16);
__bss_end_exclusive = .;
} :segment_data
/***********************************************************************************************
* Misc
***********************************************************************************************/
.got : { *(.got*) }
ASSERT(SIZEOF(.got) == 0, "Relocation support not expected")
/DISCARD/ : { *(.comment*) }
}

@ -1,72 +0,0 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0
*
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
*/
__rpi_phys_dram_start_addr = 0;
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
__rpi_phys_binary_load_addr = 0x80000;
ENTRY(__rpi_phys_binary_load_addr)
/* Flags:
* 4 == R
* 5 == RX
* 6 == RW
*
* Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses.
* It doesn't mean all of them need actually be loaded.
*/
PHDRS
{
segment_boot_core_stack PT_LOAD FLAGS(6);
segment_code PT_LOAD FLAGS(5);
segment_data PT_LOAD FLAGS(6);
}
SECTIONS
{
. = __rpi_phys_dram_start_addr;
/***********************************************************************************************
* Boot Core Stack
***********************************************************************************************/
.boot_core_stack (NOLOAD) :
{
/* ^ */
/* | stack */
. += __rpi_phys_binary_load_addr; /* | growth */
/* | direction */
__boot_core_stack_end_exclusive = .; /* | */
} :segment_boot_core_stack
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
.text :
{
KEEP(*(.text._start))
*(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */
*(.text._start_rust) /* The Rust entry point */
*(.text*) /* Everything else */
} :segment_code
.rodata : ALIGN(8) { *(.rodata*) } :segment_code
.got : ALIGN(8) { *(.got) } :segment_code
/***********************************************************************************************
* Data + BSS
***********************************************************************************************/
.data : { *(.data*) } :segment_data
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
.bss (NOLOAD) : ALIGN(16)
{
__bss_start = .;
*(.bss*);
. = ALIGN(16);
__bss_end_exclusive = .;
} :segment_data
}

@ -1,9 +1,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! System console.
use crate::bsp;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
@ -17,3 +19,14 @@ pub mod interface {
/// intention.
pub use core::fmt::Write;
}
//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
/// Return a reference to the console.
///
/// This is the global console used by all printing macros.
pub fn console() -> impl interface::Write {
bsp::console::console()
}

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2020-2023 Andre Richter <andre.o.richter@gmail.com>
//! Processor code.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//! Boot code.

@ -1,9 +1,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
// Rust embedded logo for `make doc`.
#![doc(html_logo_url = "https://git.io/JeGIp")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png"
)]
//! The `kernel` binary.
//!
@ -104,6 +106,7 @@
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
#![feature(asm_const)]
#![feature(format_args_nl)]
#![feature(panic_info_message)]
#![no_main]

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! A panic handler that infinitely waits.

@ -1,10 +1,10 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Printing.
use crate::{bsp, console};
use crate::console;
use core::fmt;
//--------------------------------------------------------------------------------------------------
@ -15,7 +15,7 @@ use core::fmt;
pub fn _print(args: fmt::Arguments) {
use console::interface::Write;
bsp::console::console().write_fmt(args).unwrap();
console::console().write_fmt(args).unwrap();
}
/// Prints without a newline.

@ -1,9 +1,10 @@
{
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.overrideCommand": ["make", "check"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.extraArgs": ["--bins"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
}

@ -3,10 +3,10 @@
version = 3
[[package]]
name = "cortex-a"
version = "7.2.0"
name = "aarch64-cpu"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad"
checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225"
dependencies = [
"tock-registers",
]
@ -15,11 +15,11 @@ dependencies = [
name = "mingo"
version = "0.4.0"
dependencies = [
"cortex-a",
"aarch64-cpu",
]
[[package]]
name = "tock-registers"
version = "0.7.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e"
checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c"

@ -24,4 +24,4 @@ path = "src/main.rs"
# Platform specific dependencies
[target.'cfg(target_arch = "aarch64")'.dependencies]
cortex-a = { version = "7.x.x" }
aarch64-cpu = { version = "9.x.x" }

@ -1,9 +1,10 @@
## SPDX-License-Identifier: MIT OR Apache-2.0
##
## Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
## Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
include ../common/format.mk
include ../common/docker.mk
include ../common/format.mk
include ../common/operating_system.mk
##--------------------------------------------------------------------------------------------------
## Optional, user-provided configuration values
@ -51,14 +52,14 @@ export LD_SCRIPT_PATH
##--------------------------------------------------------------------------------------------------
## Targets and Prerequisites
##--------------------------------------------------------------------------------------------------
KERNEL_LINKER_SCRIPT = link.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_MANIFEST = Cargo.toml
KERNEL_LINKER_SCRIPT = kernel.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_ELF = target/$(TARGET)/release/kernel
# This parses cargo's dep-info file.
# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG)
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)
@ -81,7 +82,6 @@ COMPILER_ARGS = --target=$(TARGET) \
RUSTC_CMD = cargo rustc $(COMPILER_ARGS)
DOC_CMD = cargo doc $(COMPILER_ARGS)
CLIPPY_CMD = cargo clippy $(COMPILER_ARGS)
CHECK_CMD = cargo check $(COMPILER_ARGS)
OBJCOPY_CMD = rust-objcopy \
--strip-all \
-O binary
@ -134,7 +134,7 @@ $(KERNEL_BIN): $(KERNEL_ELF)
$(call color_progress_prefix, "Name")
@echo $(KERNEL_BIN)
$(call color_progress_prefix, "Size")
@printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1`
$(call disk_usage_KiB, $(KERNEL_BIN))
##------------------------------------------------------------------------------
## Generate the documentation
@ -185,7 +185,6 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \
--section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt
##------------------------------------------------------------------------------
@ -195,12 +194,6 @@ nm: $(KERNEL_ELF)
$(call color_header, "Launching nm")
@$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
##------------------------------------------------------------------------------
## Helper target for rust-analyzer
##------------------------------------------------------------------------------
check:
@RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json
##--------------------------------------------------------------------------------------------------

@ -0,0 +1,50 @@
# 教程 04 - 全局安全
## tl;dr
- 引入了假的锁。
- 这是第一次展示原始操作系统同步,并支持安全访问全局数据结构。
## Rust中的全局可变
当我们引入全局可用的`print!`宏在 [教程03],我门有一点作弊。 调用
`core::fmt`的`write_fmt()`函数,接受`&mut self`的方法之所以有效,
是因为在每次调用时都会创建一个新的`QEMUOutput`实例。
如果我们想保留一些状态,例如关于写入字符数的统计数据,
我们需要创建`QEMUOutput`的一个全局实例 (在Rust中使用`static`关键字).
然而`static QEMU_OUTPUT`不允许调用具有`&mut self`的函数。
为此,我们需要`static mut`,但是调用改变`static mut`状态的函数是不安全的。
这个是Rust编译器对此的推理它无法再阻止核心/线程同时改变数据(它是全局的,所以每个人都可以从任何地方引用它,检查程序借用在这里帮不上忙)。
这个问题的解决方案是将全局封装到原始同步中。在我们的例子中,是一个*MUTual EXclusion*原语的变体。
`Mutex`是`synchronization.rs`中引入的一个特性,并由同一文件中的`NullLock`实现。
为了使代码更易于教学,它省略了用于防止并发访问的实际体系结构特定逻辑,因为只要内核仅在单个内核上执行并禁用中断,我们就不需要它。
`NullLock`侧重于展示Rust内部可变性的核心概念。请务必阅读它。
我们还建议您阅读这篇关于[Rust的引用类型的精确心智模型]文章
如果要将`NullLock`与一些真实的互斥实现进行比较,可以查看
[spin crate]或者[parking lot crate]。
[教程03]: ../03_hacky_hello_world
[内部可变性]: https://doc.rust-lang.org/std/cell/index.html
[Rust的引用类型的精确心智模型]: https://docs.rs/dtolnay/0.0.6/dtolnay/macro._02__reference_types.html
[spin crate]: https://github.com/mvdnes/spin-rs
[parking lot crate]: https://github.com/Amanieu/parking_lot
## 测试
```console
$ make qemu
[...]
[0] Hello from Rust!
[1] Chars written: 22
[2] Stopping here.
```
## 相比之前的变化diff
请检查[英文版本](README.md#diff-to-previous),这是最新的。

@ -148,7 +148,7 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr
}
Ok(())
@@ -41,7 +80,37 @@
@@ -41,7 +80,39 @@
// Public Code
//--------------------------------------------------------------------------------------------------
@ -164,9 +164,9 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr
/// Return a reference to the console.
-pub fn console() -> impl console::interface::Write {
- QEMUOutput {}
+pub fn console() -> &'static impl console::interface::All {
+pub fn console() -> &'static dyn console::interface::All {
+ &QEMU_OUTPUT
+}
}
+
+//------------------------------------------------------------------------------
+// OS Interface Code
@ -177,7 +177,7 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr
+/// serialize access.
+impl console::interface::Write for QEMUOutput {
+ fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
+ // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
+ // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase
+ // readability.
+ self.inner.lock(|inner| fmt::Write::write_fmt(inner, args))
+ }
@ -187,12 +187,14 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr
+ fn chars_written(&self) -> usize {
+ self.inner.lock(|inner| inner.chars_written)
+ }
}
+}
+
+impl console::interface::All for QEMUOutput {}
diff -uNr 03_hacky_hello_world/src/console.rs 04_safe_globals/src/console.rs
--- 03_hacky_hello_world/src/console.rs
+++ 04_safe_globals/src/console.rs
@@ -10,10 +10,22 @@
@@ -12,12 +12,24 @@
/// Console interfaces.
pub mod interface {
@ -218,21 +220,31 @@ diff -uNr 03_hacky_hello_world/src/console.rs 04_safe_globals/src/console.rs
+ }
+
+ /// Trait alias for a full-fledged console.
+ pub trait All = Write + Statistics;
+ pub trait All: Write + Statistics {}
}
//--------------------------------------------------------------------------------------------------
@@ -27,6 +39,6 @@
/// Return a reference to the console.
///
/// This is the global console used by all printing macros.
-pub fn console() -> impl interface::Write {
+pub fn console() -> &'static dyn interface::All {
bsp::console::console()
}
diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs
--- 03_hacky_hello_world/src/main.rs
+++ 04_safe_globals/src/main.rs
@@ -106,6 +106,7 @@
@@ -109,6 +109,7 @@
#![feature(asm_const)]
#![feature(format_args_nl)]
#![feature(panic_info_message)]
+#![feature(trait_alias)]
#![no_main]
#![no_std]
@@ -114,6 +115,7 @@
@@ -117,6 +118,7 @@
mod cpu;
mod panic_wait;
mod print;
@ -240,32 +252,42 @@ diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs
/// Early init code.
///
@@ -121,7 +123,15 @@
@@ -124,7 +126,12 @@
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
- println!("Hello from Rust!");
+ use console::interface::Statistics;
+ use console::console;
- panic!("Stopping here.")
+ println!("[0] Hello from Rust!");
+
+ println!(
+ "[1] Chars written: {}",
+ bsp::console::console().chars_written()
+ );
+ println!("[1] Chars written: {}", console().chars_written());
+
+ println!("[2] Stopping here.");
+ cpu::wait_forever()
}
diff -uNr 03_hacky_hello_world/src/print.rs 04_safe_globals/src/print.rs
--- 03_hacky_hello_world/src/print.rs
+++ 04_safe_globals/src/print.rs
@@ -13,8 +13,6 @@
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
- use console::interface::Write;
-
console::console().write_fmt(args).unwrap();
}
diff -uNr 03_hacky_hello_world/src/synchronization.rs 04_safe_globals/src/synchronization.rs
--- 03_hacky_hello_world/src/synchronization.rs
+++ 04_safe_globals/src/synchronization.rs
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
+// Copyright (c) 2020-2023 Andre Richter <andre.o.richter@gmail.com>
+
+//! Synchronization primitives.
+//!
@ -291,7 +313,7 @@ diff -uNr 03_hacky_hello_world/src/synchronization.rs 04_safe_globals/src/synchr
+ type Data;
+
+ /// Locks the mutex and grants the closure temporary mutable access to the wrapped data.
+ fn lock<R>(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
+ fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R;
+ }
+}
+
@ -332,7 +354,7 @@ diff -uNr 03_hacky_hello_world/src/synchronization.rs 04_safe_globals/src/synchr
+impl<T> interface::Mutex for NullLock<T> {
+ type Data = T;
+
+ fn lock<R>(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R {
+ fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R {
+ // In a real lock, there would be code encapsulating this line that ensures that this
+ // mutable reference will ever only be given out once at a time.
+ let data = unsafe { &mut *self.data.get() };

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Architectural processor code.
//!
@ -11,7 +11,7 @@
//!
//! crate::cpu::arch_cpu
use cortex_a::asm;
use aarch64_cpu::asm;
//--------------------------------------------------------------------------------------------------
// Public Code

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//! Architectural boot code.
//!
@ -11,8 +11,13 @@
//!
//! crate::cpu::boot::arch_boot
use core::arch::global_asm;
// Assembly counterpart to this file.
core::arch::global_asm!(include_str!("boot.s"));
global_asm!(
include_str!("boot.s"),
CONST_CORE_ID_MASK = const 0b11
);
//--------------------------------------------------------------------------------------------------
// Public Code

@ -18,8 +18,6 @@
add \register, \register, #:lo12:\symbol
.endm
.equ _core_id_mask, 0b11
//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
@ -30,10 +28,10 @@
//------------------------------------------------------------------------------
_start:
// Only proceed on the boot core. Park it otherwise.
mrs x1, MPIDR_EL1
and x1, x1, _core_id_mask
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
cmp x1, x2
mrs x0, MPIDR_EL1
and x0, x0, {CONST_CORE_ID_MASK}
ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
cmp x0, x1
b.ne .L_parking_loop
// If execution reaches here, it is the boot core.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Conditional reexporting of Board Support Packages.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Top-level BSP file for the Raspberry Pi 3 and 4.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! BSP console facilities.
@ -90,7 +90,7 @@ impl QEMUOutput {
}
/// Return a reference to the console.
pub fn console() -> &'static impl console::interface::All {
pub fn console() -> &'static dyn console::interface::All {
&QEMU_OUTPUT
}
@ -103,7 +103,7 @@ use synchronization::interface::Mutex;
/// serialize access.
impl console::interface::Write for QEMUOutput {
fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
// Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
// Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase
// readability.
self.inner.lock(|inner| fmt::Write::write_fmt(inner, args))
}
@ -114,3 +114,5 @@ impl console::interface::Statistics for QEMUOutput {
self.inner.lock(|inner| inner.chars_written)
}
}
impl console::interface::All for QEMUOutput {}

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! BSP Processor code.

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0
*
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
*/
__rpi_phys_dram_start_addr = 0;
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
__rpi_phys_binary_load_addr = 0x80000;
ENTRY(__rpi_phys_binary_load_addr)
/* Flags:
* 4 == R
* 5 == RX
* 6 == RW
*
* Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses.
* It doesn't mean all of them need actually be loaded.
*/
PHDRS
{
segment_boot_core_stack PT_LOAD FLAGS(6);
segment_code PT_LOAD FLAGS(5);
segment_data PT_LOAD FLAGS(6);
}
SECTIONS
{
. = __rpi_phys_dram_start_addr;
/***********************************************************************************************
* Boot Core Stack
***********************************************************************************************/
.boot_core_stack (NOLOAD) :
{
/* ^ */
/* | stack */
. += __rpi_phys_binary_load_addr; /* | growth */
/* | direction */
__boot_core_stack_end_exclusive = .; /* | */
} :segment_boot_core_stack
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
.text :
{
KEEP(*(.text._start))
*(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */
*(.text._start_rust) /* The Rust entry point */
*(.text*) /* Everything else */
} :segment_code
.rodata : ALIGN(8) { *(.rodata*) } :segment_code
/***********************************************************************************************
* Data + BSS
***********************************************************************************************/
.data : { *(.data*) } :segment_data
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
.bss (NOLOAD) : ALIGN(16)
{
__bss_start = .;
*(.bss*);
. = ALIGN(16);
__bss_end_exclusive = .;
} :segment_data
/***********************************************************************************************
* Misc
***********************************************************************************************/
.got : { *(.got*) }
ASSERT(SIZEOF(.got) == 0, "Relocation support not expected")
/DISCARD/ : { *(.comment*) }
}

@ -1,72 +0,0 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0
*
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
*/
__rpi_phys_dram_start_addr = 0;
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
__rpi_phys_binary_load_addr = 0x80000;
ENTRY(__rpi_phys_binary_load_addr)
/* Flags:
* 4 == R
* 5 == RX
* 6 == RW
*
* Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses.
* It doesn't mean all of them need actually be loaded.
*/
PHDRS
{
segment_boot_core_stack PT_LOAD FLAGS(6);
segment_code PT_LOAD FLAGS(5);
segment_data PT_LOAD FLAGS(6);
}
SECTIONS
{
. = __rpi_phys_dram_start_addr;
/***********************************************************************************************
* Boot Core Stack
***********************************************************************************************/
.boot_core_stack (NOLOAD) :
{
/* ^ */
/* | stack */
. += __rpi_phys_binary_load_addr; /* | growth */
/* | direction */
__boot_core_stack_end_exclusive = .; /* | */
} :segment_boot_core_stack
/***********************************************************************************************
* Code + RO Data + Global Offset Table
***********************************************************************************************/
.text :
{
KEEP(*(.text._start))
*(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */
*(.text._start_rust) /* The Rust entry point */
*(.text*) /* Everything else */
} :segment_code
.rodata : ALIGN(8) { *(.rodata*) } :segment_code
.got : ALIGN(8) { *(.got) } :segment_code
/***********************************************************************************************
* Data + BSS
***********************************************************************************************/
.data : { *(.data*) } :segment_data
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
.bss (NOLOAD) : ALIGN(16)
{
__bss_start = .;
*(.bss*);
. = ALIGN(16);
__bss_end_exclusive = .;
} :segment_data
}

@ -1,9 +1,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! System console.
use crate::bsp;
//--------------------------------------------------------------------------------------------------
// Public Definitions
//--------------------------------------------------------------------------------------------------
@ -27,5 +29,16 @@ pub mod interface {
}
/// Trait alias for a full-fledged console.
pub trait All = Write + Statistics;
pub trait All: Write + Statistics {}
}
//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
/// Return a reference to the console.
///
/// This is the global console used by all printing macros.
pub fn console() -> &'static dyn interface::All {
bsp::console::console()
}

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2020-2023 Andre Richter <andre.o.richter@gmail.com>
//! Processor code.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2021-2023 Andre Richter <andre.o.richter@gmail.com>
//! Boot code.

@ -1,9 +1,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
// Rust embedded logo for `make doc`.
#![doc(html_logo_url = "https://git.io/JeGIp")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png"
)]
//! The `kernel` binary.
//!
@ -104,6 +106,7 @@
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
#![feature(asm_const)]
#![feature(format_args_nl)]
#![feature(panic_info_message)]
#![feature(trait_alias)]
@ -123,14 +126,11 @@ mod synchronization;
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
use console::interface::Statistics;
use console::console;
println!("[0] Hello from Rust!");
println!(
"[1] Chars written: {}",
bsp::console::console().chars_written()
);
println!("[1] Chars written: {}", console().chars_written());
println!("[2] Stopping here.");
cpu::wait_forever()

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! A panic handler that infinitely waits.

@ -1,10 +1,10 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Printing.
use crate::{bsp, console};
use crate::console;
use core::fmt;
//--------------------------------------------------------------------------------------------------
@ -13,9 +13,7 @@ use core::fmt;
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
use console::interface::Write;
bsp::console::console().write_fmt(args).unwrap();
console::console().write_fmt(args).unwrap();
}
/// Prints without a newline.

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2020-2023 Andre Richter <andre.o.richter@gmail.com>
//! Synchronization primitives.
//!
@ -26,7 +26,7 @@ pub mod interface {
type Data;
/// Locks the mutex and grants the closure temporary mutable access to the wrapped data.
fn lock<R>(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R;
}
}
@ -67,7 +67,7 @@ impl<T> NullLock<T> {
impl<T> interface::Mutex for NullLock<T> {
type Data = T;
fn lock<R>(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R {
fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R {
// In a real lock, there would be code encapsulating this line that ensures that this
// mutable reference will ever only be given out once at a time.
let data = unsafe { &mut *self.data.get() };

@ -1,9 +1,10 @@
{
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.overrideCommand": ["make", "check"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
"editor.formatOnSave": true,
"editor.rulers": [100],
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
"rust-analyzer.cargo.features": ["bsp_rpi3"],
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.extraArgs": ["--bins"],
"rust-analyzer.lens.debug": false,
"rust-analyzer.lens.run": false
}

@ -3,10 +3,10 @@
version = 3
[[package]]
name = "cortex-a"
version = "7.2.0"
name = "aarch64-cpu"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad"
checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225"
dependencies = [
"tock-registers",
]
@ -15,12 +15,12 @@ dependencies = [
name = "mingo"
version = "0.5.0"
dependencies = [
"cortex-a",
"aarch64-cpu",
"tock-registers",
]
[[package]]
name = "tock-registers"
version = "0.7.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e"
checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c"

@ -23,8 +23,8 @@ path = "src/main.rs"
[dependencies]
# Optional dependencies
tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true }
tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true }
# Platform specific dependencies
[target.'cfg(target_arch = "aarch64")'.dependencies]
cortex-a = { version = "7.x.x" }
aarch64-cpu = { version = "9.x.x" }

@ -1,9 +1,10 @@
## SPDX-License-Identifier: MIT OR Apache-2.0
##
## Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
## Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
include ../common/format.mk
include ../common/docker.mk
include ../common/format.mk
include ../common/operating_system.mk
##--------------------------------------------------------------------------------------------------
## Optional, user-provided configuration values
@ -54,14 +55,14 @@ export LD_SCRIPT_PATH
##--------------------------------------------------------------------------------------------------
## Targets and Prerequisites
##--------------------------------------------------------------------------------------------------
KERNEL_LINKER_SCRIPT = link.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_MANIFEST = Cargo.toml
KERNEL_LINKER_SCRIPT = kernel.ld
LAST_BUILD_CONFIG = target/$(BSP).build_config
KERNEL_ELF = target/$(TARGET)/release/kernel
# This parses cargo's dep-info file.
# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG)
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)
@ -84,7 +85,6 @@ COMPILER_ARGS = --target=$(TARGET) \
RUSTC_CMD = cargo rustc $(COMPILER_ARGS)
DOC_CMD = cargo doc $(COMPILER_ARGS)
CLIPPY_CMD = cargo clippy $(COMPILER_ARGS)
CHECK_CMD = cargo check $(COMPILER_ARGS)
OBJCOPY_CMD = rust-objcopy \
--strip-all \
-O binary
@ -146,11 +146,11 @@ $(KERNEL_BIN): $(KERNEL_ELF)
$(call color_progress_prefix, "Name")
@echo $(KERNEL_BIN)
$(call color_progress_prefix, "Size")
@printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1`
$(call disk_usage_KiB, $(KERNEL_BIN))
##------------------------------------------------------------------------------
## Generate the documentation
##------------------------------------------------------------------------------
##-----------------------------------------------------------------------------
doc:
$(call color_header, "Generating docs")
@$(DOC_CMD) --document-private-items --open
@ -204,7 +204,6 @@ objdump: $(KERNEL_ELF)
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \
--section .rodata \
--section .got \
$(KERNEL_ELF) | rustfilt
##------------------------------------------------------------------------------
@ -214,12 +213,6 @@ nm: $(KERNEL_ELF)
$(call color_header, "Launching nm")
@$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
##------------------------------------------------------------------------------
## Helper target for rust-analyzer
##------------------------------------------------------------------------------
check:
@RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json
##--------------------------------------------------------------------------------------------------

@ -0,0 +1,138 @@
# 教程 05 - 驱动程序: GPIO和UART
## tl;dr
- 添加了用于真实`UART`和`GPIO`控制器的驱动程序。
- **我们将首次能够在真实硬件上运行代码** (请向下滚动查看说明)。
## 简介
在上一篇教程中,我们启用了全局安全变量,为添加第一个真实设备驱动程序奠定了基础。
我们放弃了神奇的QEMU控制台并引入了一个`驱动程序管理器`,允许`BSP`将设备驱动程序注册到`内核`中。
## 驱动程序管理器
第一步是向内核添加一个`driver subsystem`。相应的代码将位于`src/driver.rs`中。
该子系统引入了`interface::DeviceDriver`,这是每个设备驱动程序都需要实现的通用特征,并为内核所知。
在同一文件中实例化的全局`DRIVER_MANAGER`实例(类型为`DriverManager`)作为一个中央实体,可以被调用来管理内核中的所有设备驱动程序。
例如,通过使用全局可访问的`crate::driver::driver_manager().register_driver(...)`,任何代码都可以注册一个实现了`interface::DeviceDriver`特征的具有静态生命周期的对象。
在内核初始化期间,调用`crate::driver::driver_manager().init_drivers(...)`将使驱动程序管理器遍历所有已注册的驱动程序,
并启动它们的初始化,并执行可选的`post-init callback`,该回调可以与驱动程序一起注册。
例如,此机制用于在`UART`驱动程序初始化后将其切换为主系统控制台的驱动程序。
## BSP驱动程序实现
在`src/bsp/raspberrypi/driver.rs`中,函数`init()`负责注册`UART`和`GPIO`驱动程序。
因此,在内核初始化期间,按照以下来自`main.rs`的代码,正确的顺序是:
i首先初始化BSP驱动程序子系统然后ii调用`driver_manager()`。
```rust
unsafe fn kernel_init() -> ! {
// Initialize the BSP driver subsystem.
if let Err(x) = bsp::driver::init() {
panic!("Error initializing BSP driver subsystem: {}", x);
}
// Initialize all device drivers.
driver::driver_manager().init_drivers();
// println! is usable from here on.
```
驱动程序本身存储在`src/bsp/device_driver`中,并且可以在不同的`BSP`之间重复使用
在这些教程中添加的第一个驱动程序是`PL011Uart`驱动程序:它实现了`console::interface::*`特征,并且从现在开始用作主系统控制台。
第二个驱动程序是`GPIO`驱动程序,它根据需要将`RPii's`的`UART`映射(即将来自`SoC`内部的信号路由到实际的硬件引脚)。
请注意,`GPIO`驱动程序区分**RPi 3**和**RPi 4**。它们的硬件不同,因此我们必须在软件中进行适配。
现在,`BSP`还包含了一个内存映射表,位于`src/bsp/raspberrypi/memory.rs`中。它提供了树莓派的`MMIO`地址,
`BSP`使用这些地址来实例化相应的设备驱动程序,以便驱动程序代码知道在内存中找到设备的寄存器的位置。
## SD卡启动
由于我们现在有了真实的`UART`输出,我们可以在真实的硬件上运行代码。
由于前面提到的`GPIO`驱动程序的差异,构建过程在**RPi 3**和**RPi 4**之间有所区别。
默认情况下,所有的`Makefile`目标都将为**RPi 3**构建。
为了**RPi 4**构建,需要在每个目标前加上`BSP=rpi4`。例如:
```console
$ BSP=rpi4 make
$ BSP=rpi4 make doc
```
不幸的是QEMU目前还不支持**RPi 4**,因此`BSP=rpi4 make qemu`无法工作。
**准备SD卡的一些步骤在RPi3和RPi4之间有所不同请在以下操作中小心。**
### 通用步骤
1. 创建一个名为`boot`的`FAT32`分区。
2. 在SD卡上生成一个名为`config.txt`的文件,并将以下内容写入其中:
```txt
arm_64bit=1
init_uart_clock=48000000
```
### RPi 3
3. 从[Raspberry Pi firmware repo](https://github.com/raspberrypi/firmware/tree/master/boot)中将以下文件复制到SD卡上
- [bootcode.bin](https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin)
- [fixup.dat](https://github.com/raspberrypi/firmware/raw/master/boot/fixup.dat)
- [start.elf](https://github.com/raspberrypi/firmware/raw/master/boot/start.elf)
4. 运行`make`命令。
### RPi 4
3. 从[Raspberry Pi firmware repo](https://github.com/raspberrypi/firmware/tree/master/boot)中将以下文件复制到SD卡上
- [fixup4.dat](https://github.com/raspberrypi/firmware/raw/master/boot/fixup4.dat)
- [start4.elf](https://github.com/raspberrypi/firmware/raw/master/boot/start4.elf)
- [bcm2711-rpi-4-b.dtb](https://github.com/raspberrypi/firmware/raw/master/boot/bcm2711-rpi-4-b.dtb)
4. 运行`BSP=rpi4 make`命令。
_**注意**: 如果在您的RPi4上无法正常工作请尝试将`start4.elf`重命名为`start.elf` (不带4)
并复制到SD卡上。_
### 再次通用步骤
5. 将`kernel8.img`复制到SD卡上并将SD卡插入RPi。
6. 运行`miniterm` target在主机上打开UART设备
```console
$ make miniterm
```
> ❗ **注意**: `Miniterm`假设默认的串行设备名称为`/dev/ttyUSB0`。Depending on your
> 根据您的主机操作系统,设备名称可能会有所不同。例如,在`macOS`上,它可能是
> `/dev/tty.usbserial-0001`之类的。在这种情况下,请明确提供设备名称:
```console
$ DEV_SERIAL=/dev/tty.usbserial-0001 make miniterm
```
7. 将USB串口连接到主机PC。
- 请参考[top-level README](../README.md#-usb-serial-output)中的接线图。
- **注意**: TX发送线连接到RX接收引脚。
- 确保您**没有**连接USB串口的电源引脚只连接RX/TX和GND引脚。
8. 将RPi连接到USB电源线并观察输出。
```console
Miniterm 1.0
[MT] ⏳ Waiting for /dev/ttyUSB0
[MT] ✅ Serial connected
[0] mingo version 0.5.0
[1] Booting on: Raspberry Pi 3
[2] Drivers loaded:
1. BCM PL011 UART
2. BCM GPIO
[3] Chars written: 117
[4] Echoing input now
```
8. 通过按下<kbd>ctrl-c</kbd>退出。
## 相比之前的变化diff
请检查[英文版本](README.md#diff-to-previous),这是最新的。

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
//! Architectural processor code.
//!
@ -11,7 +11,7 @@
//!
//! crate::cpu::arch_cpu
use cortex_a::asm;
use aarch64_cpu::asm;
//--------------------------------------------------------------------------------------------------
// Public Code

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save