From 9db39666e7658a99011d92655a024b1126cf5fa8 Mon Sep 17 00:00:00 2001 From: Fengqixian <570311238@qq.com> Date: Tue, 9 Aug 2022 13:40:47 +0800 Subject: [PATCH 1/7] Translation tutorial 3 --- 03_hacky_hello_world/README.CN.md | 371 ++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 03_hacky_hello_world/README.CN.md diff --git a/03_hacky_hello_world/README.CN.md b/03_hacky_hello_world/README.CN.md new file mode 100644 index 000000000..2c6dfd8b3 --- /dev/null +++ b/03_hacky_hello_world/README.CN.md @@ -0,0 +1,371 @@ +# 教程 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 + +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 "] + 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 +@@ -85,17 +85,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) + + + +@@ -190,3 +193,27 @@ + $(call color_header, "Launching nm") + @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt + ++ ++ ++##-------------------------------------------------------------------------------------------------- ++## Testing targets ++##-------------------------------------------------------------------------------------------------- ++.PHONY: test test_boot ++ ++ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. ++ ++test_boot test: ++ $(call color_header, "$(QEMU_MISSING_STRING)") ++ ++else # QEMU is supported. ++ ++##------------------------------------------------------------------------------ ++## Run boot test ++##------------------------------------------------------------------------------ ++test_boot: $(KERNEL_BIN) ++ $(call color_header, "Boot 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 ++ ++//! 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,32 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2018-2022 Andre Richter ++ ++//! System console. ++ ++use crate::bsp; ++ ++//-------------------------------------------------------------------------------------------------- ++// 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; ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// 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 +@@ -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] + #![no_std] + + mod bsp; ++mod console; + mod cpu; + mod panic_wait; ++mod print; + + /// Early init code. + /// +@@ -120,5 +124,7 @@ + /// + /// - Only a single core must be active and running this function. + unsafe fn kernel_init() -> ! { +- panic!() ++ println!("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,14 +4,61 @@ + + //! A panic handler that infinitely waits. + +-use crate::cpu; ++use crate::{cpu, println}; + use core::panic::PanicInfo; + + //-------------------------------------------------------------------------------------------------- + // Private Code + //-------------------------------------------------------------------------------------------------- + ++/// Stop immediately if called a second time. ++/// ++/// # Note ++/// ++/// Using atomics here relieves us from needing to use `unsafe` for the static variable. ++/// ++/// On `AArch64`, which is the only implemented architecture at the time of writing this, ++/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store ++/// instructions. They are therefore safe to use even with MMU + caching deactivated. ++/// ++/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load ++/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store ++fn panic_prevent_reenter() { ++ use core::sync::atomic::{AtomicBool, Ordering}; ++ ++ #[cfg(not(target_arch = "aarch64"))] ++ compile_error!("Add the target_arch to above's check if the following code is safe to use"); ++ ++ static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); ++ ++ if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { ++ PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); ++ ++ return; ++ } ++ ++ cpu::wait_forever() ++} ++ + #[panic_handler] +-fn panic(_info: &PanicInfo) -> ! { ++fn panic(info: &PanicInfo) -> ! { ++ // Protect against panic infinite loops if any of the following code panics itself. ++ panic_prevent_reenter(); ++ ++ let (location, line, column) = match info.location() { ++ Some(loc) => (loc.file(), loc.line(), loc.column()), ++ _ => ("???", 0, 0), ++ }; ++ ++ println!( ++ "Kernel panic!\n\n\ ++ Panic location:\n File '{}', line {}, column {}\n\n\ ++ {}", ++ location, ++ line, ++ column, ++ info.message().unwrap_or(&format_args!("")), ++ ); ++ + 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 ++ ++//! Printing. ++ ++use crate::console; ++use core::fmt; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++#[doc(hidden)] ++pub fn _print(args: fmt::Arguments) { ++ use console::interface::Write; ++ ++ console::console().write_fmt(args).unwrap(); ++} ++ ++/// Prints without a newline. ++/// ++/// Carbon copy from ++#[macro_export] ++macro_rules! print { ++ ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); ++} ++ ++/// Prints with a newline. ++/// ++/// Carbon copy from ++#[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' + +``` From 1d49c9dc0109ba7f97523e8b9fafd56144714991 Mon Sep 17 00:00:00 2001 From: James Zow Date: Wed, 17 Aug 2022 20:38:05 +0800 Subject: [PATCH 2/7] Update README.CN.md --- 03_hacky_hello_world/README.CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_hacky_hello_world/README.CN.md b/03_hacky_hello_world/README.CN.md index 2c6dfd8b3..4c6917581 100644 --- a/03_hacky_hello_world/README.CN.md +++ b/03_hacky_hello_world/README.CN.md @@ -4,7 +4,7 @@ - 全面介绍`println!()` 宏以便尽早启用"printf debugging"。 - 为了保持教程长度合理,打印函数目前 "滥用" 了 QEMU 属性,该属性允许我们在没有正确设置的情况下使用树莓派的`UART`。 -- 使用真正的硬件`UART 在以下教程中逐步启用。 +- 在接下来的教程中将逐步使用真实硬件的`UART`。 ## 值得注意的补充 From 85fa50a18e1b889c74707daf68f5b6e0c9425474 Mon Sep 17 00:00:00 2001 From: James Zow Date: Sun, 11 Sep 2022 19:12:44 +0800 Subject: [PATCH 3/7] Update README.CN.md --- 03_hacky_hello_world/README.CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_hacky_hello_world/README.CN.md b/03_hacky_hello_world/README.CN.md index 4c6917581..2b3e5cc23 100644 --- a/03_hacky_hello_world/README.CN.md +++ b/03_hacky_hello_world/README.CN.md @@ -2,7 +2,7 @@ ## tl;dr -- 全面介绍`println!()` 宏以便尽早启用"printf debugging"。 +- 介绍全局的`println!()`宏以便尽早启用"printf debugging"。 - 为了保持教程长度合理,打印函数目前 "滥用" 了 QEMU 属性,该属性允许我们在没有正确设置的情况下使用树莓派的`UART`。 - 在接下来的教程中将逐步使用真实硬件的`UART`。 From 1275cfa1df2b5bd940008530b18995ba110231fb Mon Sep 17 00:00:00 2001 From: James Zow Date: Tue, 13 Sep 2022 19:17:06 +0800 Subject: [PATCH 4/7] Update README.CN.md --- 03_hacky_hello_world/README.CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_hacky_hello_world/README.CN.md b/03_hacky_hello_world/README.CN.md index 2b3e5cc23..796d6b5e2 100644 --- a/03_hacky_hello_world/README.CN.md +++ b/03_hacky_hello_world/README.CN.md @@ -31,7 +31,7 @@ Panic location: Stopping here. ``` -## 与上面不同 +## 相比之前的变化(diff) ```diff diff -uNr 02_runtime_init/Cargo.toml 03_hacky_hello_world/Cargo.toml From 6c4d1fcb04400f4c413981d027b844e0739df007 Mon Sep 17 00:00:00 2001 From: James Zow Date: Tue, 13 Sep 2022 19:21:27 +0800 Subject: [PATCH 5/7] Update README.CN.md --- 03_hacky_hello_world/README.CN.md | 338 +----------------------------- 1 file changed, 1 insertion(+), 337 deletions(-) diff --git a/03_hacky_hello_world/README.CN.md b/03_hacky_hello_world/README.CN.md index 796d6b5e2..28ec0a5df 100644 --- a/03_hacky_hello_world/README.CN.md +++ b/03_hacky_hello_world/README.CN.md @@ -32,340 +32,4 @@ Stopping here. ``` ## 相比之前的变化(diff) -```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 "] - 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 -@@ -85,17 +85,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) - - - -@@ -190,3 +193,27 @@ - $(call color_header, "Launching nm") - @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt - -+ -+ -+##-------------------------------------------------------------------------------------------------- -+## Testing targets -+##-------------------------------------------------------------------------------------------------- -+.PHONY: test test_boot -+ -+ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. -+ -+test_boot test: -+ $(call color_header, "$(QEMU_MISSING_STRING)") -+ -+else # QEMU is supported. -+ -+##------------------------------------------------------------------------------ -+## Run boot test -+##------------------------------------------------------------------------------ -+test_boot: $(KERNEL_BIN) -+ $(call color_header, "Boot 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 -+ -+//! 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,32 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! System console. -+ -+use crate::bsp; -+ -+//-------------------------------------------------------------------------------------------------- -+// 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; -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// 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 -@@ -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] - #![no_std] - - mod bsp; -+mod console; - mod cpu; - mod panic_wait; -+mod print; - - /// Early init code. - /// -@@ -120,5 +124,7 @@ - /// - /// - Only a single core must be active and running this function. - unsafe fn kernel_init() -> ! { -- panic!() -+ println!("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,14 +4,61 @@ - - //! A panic handler that infinitely waits. - --use crate::cpu; -+use crate::{cpu, println}; - use core::panic::PanicInfo; - - //-------------------------------------------------------------------------------------------------- - // Private Code - //-------------------------------------------------------------------------------------------------- - -+/// Stop immediately if called a second time. -+/// -+/// # Note -+/// -+/// Using atomics here relieves us from needing to use `unsafe` for the static variable. -+/// -+/// On `AArch64`, which is the only implemented architecture at the time of writing this, -+/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store -+/// instructions. They are therefore safe to use even with MMU + caching deactivated. -+/// -+/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load -+/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store -+fn panic_prevent_reenter() { -+ use core::sync::atomic::{AtomicBool, Ordering}; -+ -+ #[cfg(not(target_arch = "aarch64"))] -+ compile_error!("Add the target_arch to above's check if the following code is safe to use"); -+ -+ static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); -+ -+ if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { -+ PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); -+ -+ return; -+ } -+ -+ cpu::wait_forever() -+} -+ - #[panic_handler] --fn panic(_info: &PanicInfo) -> ! { -+fn panic(info: &PanicInfo) -> ! { -+ // Protect against panic infinite loops if any of the following code panics itself. -+ panic_prevent_reenter(); -+ -+ let (location, line, column) = match info.location() { -+ Some(loc) => (loc.file(), loc.line(), loc.column()), -+ _ => ("???", 0, 0), -+ }; -+ -+ println!( -+ "Kernel panic!\n\n\ -+ Panic location:\n File '{}', line {}, column {}\n\n\ -+ {}", -+ location, -+ line, -+ column, -+ info.message().unwrap_or(&format_args!("")), -+ ); -+ - 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 -+ -+//! Printing. -+ -+use crate::console; -+use core::fmt; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+#[doc(hidden)] -+pub fn _print(args: fmt::Arguments) { -+ use console::interface::Write; -+ -+ console::console().write_fmt(args).unwrap(); -+} -+ -+/// Prints without a newline. -+/// -+/// Carbon copy from -+#[macro_export] -+macro_rules! print { -+ ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); -+} -+ -+/// Prints with a newline. -+/// -+/// Carbon copy from -+#[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. From ebb662c8feb11846e90cb836fb99495e4d073497 Mon Sep 17 00:00:00 2001 From: James Zow Date: Fri, 16 Sep 2022 21:46:46 +0800 Subject: [PATCH 6/7] Translate Chapter 4 Safe Globals --- 04_safe_globals/README.CN.md | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 04_safe_globals/README.CN.md diff --git a/04_safe_globals/README.CN.md b/04_safe_globals/README.CN.md new file mode 100644 index 000000000..14ec5175b --- /dev/null +++ b/04_safe_globals/README.CN.md @@ -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),这是最新的。 From b90cb10b02774ac8482956d89310653f0f2d6777 Mon Sep 17 00:00:00 2001 From: James Zow Date: Mon, 19 Sep 2022 16:14:17 +0800 Subject: [PATCH 7/7] remove Chapter 4 Translation, modify the diff in Chapter 2 and Chapter 3 --- 02_runtime_init/README.CN.md | 2 +- 03_hacky_hello_world/README.CN.md | 2 +- 04_safe_globals/README.CN.md | 50 ------------------------------- 3 files changed, 2 insertions(+), 52 deletions(-) delete mode 100644 04_safe_globals/README.CN.md diff --git a/02_runtime_init/README.CN.md b/02_runtime_init/README.CN.md index 46c524672..f8d64f6f3 100644 --- a/02_runtime_init/README.CN.md +++ b/02_runtime_init/README.CN.md @@ -19,5 +19,5 @@ [bss]: https://en.wikipedia.org/wiki/.bss ## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。 -Please check [the english version](README.md#diff-to-previous), which is kept up-to-date. diff --git a/03_hacky_hello_world/README.CN.md b/03_hacky_hello_world/README.CN.md index 28ec0a5df..ac08fae53 100644 --- a/03_hacky_hello_world/README.CN.md +++ b/03_hacky_hello_world/README.CN.md @@ -32,4 +32,4 @@ Stopping here. ``` ## 相比之前的变化(diff) -Please check [the english version](README.md#diff-to-previous), which is kept up-to-date. +请检查[英文版本](README.md#diff-to-previous),这是最新的。 diff --git a/04_safe_globals/README.CN.md b/04_safe_globals/README.CN.md deleted file mode 100644 index 14ec5175b..000000000 --- a/04_safe_globals/README.CN.md +++ /dev/null @@ -1,50 +0,0 @@ -# 教程 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),这是最新的。