0%

After the 3rd stage of the 2024 autumn winter open source operating system training camp, I would like to share my experience and summary with you.

There are three system structures to compare:

  • Unikernel
    • Single-Privilege Physical-Address-Space Combination-of-Kernel-and-UserApps
  • Macrokernel Mode
    • Multi-Privilege Paging-Address-Space Isolation-between-Kernel-and-UserApps
  • Hypervisor (Virtual) Mode
    • Isolation-between-Host-and-Guest

The critical key to the Component-based design is the Feature. This can be configured in the Cargo.toml file and in the Makefile environment variable, which can decide which content to compile and link. It feels like a advanced #if - #endif switch option.

Unikernel

We use 3 stages to express the system advancing from bare-metal program to a component-based system.

  • Bare-metal program
    • Hardfirm + Bootloader
    • Initialize the special registers
    • Initialize MMU (for Paging)
    • Initialize Stack
    • Initialize Interrupt Vector
    • Initialize Peripherals / Devices
    • Transfer to main program
  • Layer / Hierarchy
    • Hardfirm + Bootloader (Layer)
    • Hardware Initialization(Layer): the special registers 、MMU(for Paging)、STACK、Interrupt Vector
    • Peripherals (Layer)
    • Transfer to main program (Layer)
  • Component-based
    • Hardfirm + Bootloader
    • Hardware Initialization (HAL)
    • Runtime Environment (RTE)
    • Transfer to main program
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void Reset_Handler(void) {
__asm__ volatile(
".code 32 \n"
"CPSID if \n"// Mask interrupts
/* Put any cores other than 0 to sleep */
"MRC p15, 0, R0, c0, c0, 5 \n" /* Read MPIDR */
"ANDS R0, R0, #3 \n"
"goToSleep: \n"
"ITT NE \n" /* Needed when in Thumb mode for following WFINE instruction */
"WFINE \n"
"BNE goToSleep \n"
/* Reset SCTLR Settings */
"MRC p15, 0, R0, c1, c0, 0 \n" /* Read CP15 System Control register */
"BIC R0, R0, #(0x1 << 12) \n" /* Clear I bit 12 to disable I Cache */
"BIC R0, R0, #(0x1 << 2) \n" /* Clear C bit 2 to disable D Cache */
"BIC R0, R0, #0x1 \n" /* Clear M bit 0 to disable MMU */
"BIC R0, R0, #(0x1 << 11) \n" /* Clear Z bit 11 to disable branch prediction */
"BIC R0, R0, #(0x1 << 13) \n" /* Clear V bit 13 to disable hivecs */
"BIC R0, R0, #(0x1 << 29) \n" /* Clear AFE bit 29 to enable the full range of access permissions */
"ORR R0, R0, #(0x1 << 30) \n" /* Set TE bit to take exceptions in Thumb mode */
"MCR p15, 0, R0, c1, c0, 0 \n" /* Write value back to CP15 System Control register */
"ISB \n"
/* Configure ACTLR */
"MRC p15, 0, r0, c1, c0, 1 \n" /* Read CP15 Auxiliary Control Register */
"ORR r0, r0, #(1 << 1) \n" /* Enable L2 prefetch hint (UNK/WI since r4p1) */
"MCR p15, 0, r0, c1, c0, 1 \n" /* Write CP15 Auxiliary Control Register */
/* Set Vector Base Address Register (VBAR) to point to this application's vector table */
"LDR R0, =Vectors \n"
"MCR p15, 0, R0, c12, c0, 0 \n"
"ISB \n"
...
"CPSIE if \n"// Unmask interrupts
"BL __libc_init_array \n"
"BL main \n"
...)
}

The above code selected from the HAL Code of STM32MP13, as the initialization and reset handler code, which will help initialize STACK, Interrupt-Vector and critical registers, and end up transferring to main program.
The code is followed similar logic as the rCore, and can help us have a better understanding of the MCU, MPU and CPU.


Like rCore, We need to provide implementation for the memory interfaces about heap operations, to avoid memory leaks and memory fragmentation.
This can help us manage memory more efficiently, and provide convenience for future expansion.

There are 2 kinds of Memory Allocation Functions: One is based on Page (palloc), and the other is based on Byte (balloc), where the “ByteAlloc” is based on “PageAlloc”.

If we take “PageAlloc” based on “ByteAlloc”, it will be difficult to align.

Algorithm for Memory Allocation

  • TLSF, Two-Level Segregated Fit
  • Buddy
  • Slab
  • Bump

How to enable paging mechanism:

  1. Early in the kernel startup, use the ruled identity mapping part of memory
    • 0xffff_ffc0_8000_0000 ~ 0xffff_ffc0_C000_FFFF $\rightarrow$ 0x8000_0000~0xC000_0000
    • Note that some address-related registers, such as SP, need to be changed to linear addresses
  2. Then if paging feature specified, rebuild the complete paging reflect.

Task switching:
Swaps the task currently being executed with a task in the ready queue.
For Single-core CPU, the form of multitasking can only be concurrent, but not parallel.

State of Task

  • Running
    • The number is equal to the number of processor cores
    • SWITCH-TO: Ready or Blocked or Exited
  • Ready
    • Is ready to be scheduled at any time
    • SWITCH-TO: Running
  • Blocked
    • Waiting for an event or resource satisfying a condition
    • SWITCH-TO: Ready
  • Exited
    • The task is finished and waiting to be recycled

Task switching: Firsty, save the context of the current task. Then, restore the context of the new task. Finally, trandfer to switch tasks.
Note that the interrupt enable state of the processor switching the task, should be off during the switching process (CLI).
If neccessary, the Spinlock and Mutex are required to be used to avoid race conditions (SMP?).


There are usual preemption conditions: One is the time slice of the task is exhausted, and the other is the interrupt source, such as the clock (Timer). The privilege level may be used to determine the nested or re-entry of the traps.

Algorithm of Scheduling

  • Collaborative scheduling algorithm (FIFO, fair)
  • Preemptive scheduling algorithm (Privileged)
    • ROUND_ROBIN
    • CFS (Completely Fair Scheduler)

The DEVICEs are usually in the kinds of net, block, display and so on.

How to discover and initialize devices

  • (axruntime at startup) discovers the device and initializes it with the appropriate driver
  • axdriver Indicates the process of discovering and initializing devices
    • 2-stage cyclic detection discovers the device
      • Level 1: traverses all virtio_mmio address ranges, determined by the platform physical memory layout, and performs transition page mapping
      • Level 2: Enumerate devices with the for_each_drivers macro, and then probe each virtio device probe_mmio
  • probe discovers devices based on the bus, matches drivers one by one, and initializes them
    • Bus connecting with devices
      • PCI
      • MMIO

A File System is a mechanism used in an operating system to manage files and data on computer storage devices such as hard disks, SSDS, flash memory, etc.
(In Linux, every device will also exist as one or more files)

File System

  • RAMFS: A memory-based virtual file system
    • For temporary data storage that is fast but easy to lose.
  • DEVFS: Device file system
    • For managing and accessing hardware devices, simplifying the development and access of device drivers.
  • ProcFS: process file system
    • Provides system process and status information for system monitoring and management.
  • SysFS: System file system
    • Exports kernel objects and properties for viewing and managing hardware devices and drivers.

Macro kernel

More than before:

  • Privilege Level
  • Address space

So we need

  • Map user/kernel space (address space)
    • Usual method
      • The high end of the page table is used as kernel space
      • The low end is used as user application space, because user programs mostly start from low addresses
    • Kernel space is shared and user space is used independently
  • Add system call (cross-privilege + address space)

The user applications toggle between two privilege levels:

  • Task Context : User Level, execute application logic
  • Trap Context : Kernel Level, handle system calls and exceptions

Address space Area mapping Back-end Backend maps specific areas in a space

  • Linear
    • case The target physical address space area already exists, and the mapping relationship is directly established
    • It can be used for MMIO area mapping and special shared address area mapping
    • Corresponding physical page frames must be consecutive
  • Alloc (Lazy)
    • case Use missing page exception (亡羊补牢)
    • Mapped by page, the corresponding physical page frames are usually discontinuous

To compatible with Linux applications, we should implement the compatible system calls, file systems and other system resources. This asks us to follow the POSIX standard.

POSIX allows developers to write applications using a standard set of apis without worrying about differences in the underlying operating system.

Except Windows, many modern operating systems, such as Linux, macOS (based on Unix), and many embedded systems (RtOS ?) , are partially or fully POSIX compliant. This allows applications developed on these systems to run seamlessly on different platforms.

When loading the ELF-formatted application, the VirtAddr and MemSiz are used to place the segment in the target virtual memory location. Beware that some segments like .bss are all zeros, so the actual data is not stored in the ELF file, but rather dynamically allocated space is requested.

The important support to do is to implemwnt hosted-standing environment main function.
We should provide:

  • Parameter information (argc and argv): parameter number, parameter string pointer array
  • Environment information (envv): environment variable string pointer array

Hypervisor

Each virtual machine has its own independent virtual machine hardware, based on the physical computer. Each virtual machine runs its own operating system, and the operating system believes that it is alone in the execution environment, and cannot distinguish whether the environment is a physical machine or a virtual machine. (ideal state)

This is similar to virtualization software, like VMware ?

Is the virtual 8086 mode on x86 the same or similar principle?

The difference between a Hypervisor and an Emulator is whether the architecture of the virtual running environment is the same as that of the physical running environment that supports it.

It Seems to have something to do with emulation KVM acceleration.

Layers of resource objects supported by the Hypervisor:

  • VM: manages the address space.
  • vCPU: indicates the virtualization of computing resources and the flow of execution on VMS
  • vMem: Memory virtualization based on the physical space layout of VMS
  • vDevice: indicates device virtualization, including direct mapping and emulation
  • vUtilities: interrupts virtualization and bus device operation

Usually use below items to implement a Hypervisor:

  • run_guest is responsible for entering Guest environment
  • guest_exit is responsible for exiting Guest environment

rCore第二阶段总结报告

第二阶段回顾

​ 本以为第一阶段后将是一马平川,却不曾想第二阶段竟是噩梦的开始。本以为第二阶段也和第一阶段一样,只需断断续续抽出一周的零碎时间即可轻易完成,但只有亲身尝试过才会知道这种想法多么的错误,最后几乎是推掉了所有的学业任务,把一整周都投入在了rCore上才勉勉强强卡ddl写完了所有lab。

​ 第零章和到第二章可以说是第二阶段的环境配置和任务理解阶段,由于上一阶段仅仅是在mac电脑上轻松写代码,故在一开始的环境配置上还是耗费了小两天,在此过程中第一次接触到了windows的wsl,然后一步一步在实验指导书的指导下搭建了 vscode + wsl + ubuntu20.02 这样的开发环境,在阅读前面几章的文档内容后也对所学的知识、实验的相关方向有了大致的了解,并能够初步运行起来自己的rust-os。在第一章的学习过程中,我理解了应用程序的执行环境,对 应用程序、函数调用、标准库、系统调用、操作系统、指令集和硬件平台 这些概念又有了新的认识,有种学习汇编语言的感觉,另外也接触到了 裸机编程、目标三元组 这些比较新的东西。但也仅停留在有印象的层面,没能深入理解其中奥秘;第二章的内容比较全面,我了解到了应用程序执行过程和操作系统的特权级切换机制,了解了编写risc-v的链接脚本来控制内存布局、内嵌汇编、异常处理、上下文切换的实现,这些操作在代码中的实现,更是让我操作系统的课上所学映入了现实,第二章的批处理调度系统,也是一个很好的帮助我入门并理解整体的代码架构的案例。

​ 后面几章就没有那么多时间细细咀嚼了,通常都是扫两眼知识然后直奔作业,除了文件系统外,其他由于都在课上学过,因此在gpt的帮助下没有被卡住太久的时间。也很感谢用心设计该实验教程的学长/学姐,不仅让我们快速入门了os,还让我们快速了解了如何系统开发一个os的各个功能。

​ 在lab1实验就卡了很久——不会仔细品读知识中所蕴含的代码实现细节,也不会投机取巧地去看看测试用例和作业所给的提示,而仅仅是闭门造车,最终卡了许久才在群聊天记录中找到了问题的关键所在,也就是时间的记录问题,当然在写的过程中也遇到诸如生命周期等等问题,让语言基础不太牢固的我举步维艰。

​ lab2是虚拟存储多级页表实验,虽然在课上老听说页表的神奇和重要性,但从没有像本次实验这样深刻地接触过操作系统中的页表,最初做的时候由于考虑的太多又无法实现便导致一度停滞不前,后来在发呆的时候又仔细重新阅读了一下题目的要求,发现需要实现的东西都还挺简单的,而且测试用例也给的非常宽松因此很快的做完了,并没有想象中那么复杂。

​ lab3是有关进程的简单创建和调度,实现上并不困难,主要难度还是在于代码结构发生了较大变化,比如本来 task_manager 做的事情现在换成了 process 在做。

​ lab4是最痛苦的一次实验,在把ch5的代码移植过来后发现仅需要过三个测试文件即可便觉得它很简单,但真正想要得心应手地写出来需要对文件系统和代码实现有详细的理解,最终还是在听了ddl前的讲解才恍然大悟:linkat和create略像前一章所提到的fork和spawn,否则将根本无从下手然后白白浪费时间并放弃之前的一切努力。在给 inode 加上 inode_id 相关的方法后很快完成了这次实验。

​ lab5的内容相对比较熟悉,也是课上自认为十分简单的死锁检测问题,但代码框架阅读起来难度较大,最终将前面的 sys_get_time 搬过来后跟着题目的提示实现了资源分配图和死锁检测系统调用的实现

第二阶段收获

​ 这次的第二阶段学习就像一场不断挑战极限的马拉松,让我既感到疲惫不堪,又充满了意想不到的收获。在本阶段的学习中,我获得了关于操作系统核心机制的更深入理解,体验到了真实操作系统开发的复杂性和细致入微的编程要求,特别是在进程管理、内存管理、以及文件系统的设计上有了全新的认识。

​ 首先,通过批处理调度系统的实现,我理解了特权级切换、上下文保存与恢复等机制。这种直接操控硬件资源的编程体验帮助我更好地理解了操作系统在管理硬件与应用间的角色。其次,在实现文件系统的过程中,我也是初次了解了文件路径解析、inode 管理和文件描述符等底层概念,这不仅让我理解了文件系统的设计精髓,也磨炼了抽象和模块化编程的能力。

​ 同时,在死锁检测的实验中,资源分配图的设计让我更深刻地理解了进程间的依赖关系和并发控制策略,学习知识的最好方式绝对是动手实践。

​ 总的来说,这一阶段的收获不止是技术上的进步,更让我体会到了系统开发的全局性思维和精确性要求。这不仅提升了我的编程能力,也让我更有信心面对后续操作系统开发中的复杂问题。

rCore第一阶段总结报告

参加训练营的契机

​ 本人是大三信息安全专业学生,起因是在学期初老师在班级群中转发了本次训练营的相关推送,正好本学期在修操作系统专业课,再加上在过去的两年实际上没有学过过硬的技术,就希望能通过本次训练营收获到许多实际项目开发相关的东西,希望能做到技多不压身。

第一阶段回顾

​ 本阶段的主要任务是根据 rust语言官方圣经 来学习rust语法,并在简单的知识训练、算法实现中掌握基本的编程逻辑和rust语言的独特思维。在学习过程中最大的感受就是,这是一门非常“麻烦”(或者说拗口)、非常底层但却非常“安全”的语言。

​ 在进一步地阅读文档和代码实操的过程中,我也深深地体会到了rust语言的魅力,很多在其他语言中不需要关注的问题,都是rust使用者的家常便饭,例如所有权与借用、生命周期、模式匹配、并发和线程、内存管理、特征泛型、智能指针、宏等等全新的概念,在学习的过程中,也能十分自然地和以往所写过的语言进行对比,也能十分自然地联想到自己所学的专业知识,整个学习过程是痛苦而充满趣味和成就感的。

​ 最终也是断断续续地在国庆后完成了110分的编程题目,虽然很多地方都有囫囵吞枣、只求大概的不好处理,但还算是初步打开了rust语言的大门。

阶段目标与晋级条件

  • 从零开始构建操作系统的各个模块,不断完善操作系统核心功能

  • 完成5道rCore操作系统大实验编程题,深入领会OS重要概念,掌握必备技能

  • 排行榜积分达到500分,方可进入项目阶段学习,参与团队合作完成关键任务

阶段个人总结

从本阶段开始本人感到明显的学习吃力,各种新概念在教学过程中如泉涌般浮现在脑海,难以在短时间内完全消化完毕。 故专门抽出一整个周末以及课余时间反复研读与理解教学文档,深入洞悉各种新概念的内涵,在彻底理解相关知识点后再结合视频直播中老师的讲解理解每一行代码的实现逻辑(5W1H原则:‌Why(何因)‌、‌What(何事)‌、‌Where(何地)‌、‌When(何时)‌、‌Who(何物)‌、‌How(何法))。在确保完全弄懂文档知识点与代码的实现逻辑之后,方才着手完成每个实验的习题。

通过本阶段的学习,我也认识到学习操作系统相较于其他编程实践项目需要投入更多的精力,对于陌生的技术栈需要花更多的心思去理解其技术细节与应用方式,不能向以前一样盲目自信而心不在焉地学习。同时这几次实验也建立起我实战大型编程项目的经验,为以后参与更多更繁杂的编程项目打下基础。

阶段目标与晋级条件

  • Rust编程语言为学习操作系统设计与实现打下坚实基础

  • 通过完成100道Rustling编程题,强化训练Rust编程技能

  • 该阶段排行榜达到满分可晋级,进入专业阶段学习

阶段个人总结

Rust 语言是参加本训练营必须掌握的一门语言,因为本训练营的所有项目均基于本语言编写。由于本人已学习过 Rust 编程语言,故本阶段无太大压力,跟着晋级要求完成 rustlings习题后即达成目标。

而重点是后续专业阶段 rCore 操作系统的学习与代码理解,因操作系统相关知识早已忘记(虽然曾跟着网络教程阅读过 Linux 内核源码,但年代久远早已忘记细节),故需要一定时间重拾相关知识,并跟着实验在旧知识基础上提升自己的理解水平。

附:本人学习 Rust 语言的主要参考视频教程

记得恢复package.json

主要内容

组件化内核实验路线

  • 第一周 组件化内核基础和Unikernel模式(以下4部分压缩合并到3次课)
    内核组件化基本概念、思路和框架 (U.1)
    内存管理 - 分页、地址空间(U.3)和动态内存分配(U.2)
    任务调度 - 任务与运行队列(U.4)、协作式调度(U.5) 、 抢占式调度(U.6)
    块设备驱动(U.7)和文件系统(U.8)
  • 第二周 宏内核扩展(其中第3次课由郑友捷老师讲,内容待定)
    从Unikernel到宏内核的扩展 (M.1)
    用户地址空间管理和页面异常(M.2)
    进程和Linux应用支持(M.3)
  • 第三周 Hypervisor扩展
    从Unikernel到宏内核的扩展 (H.1)
    Guest地址空间管理(H.2)
    VMExit各类情况处理与设备管理 (H.3)
    alt text
    alt text
    alt text

    ArceOS框架

    除了运行需要的基本工具外,其他所有东西都可以以组件的形式添加到内核中,通过rust提供的feature,能够自行选择需要的组件,实现内核最小化运行。
    axfeat是一个空的feature,用来汇聚所有的feature。
    alt text
    alt text

作业

alt text

在println!宏定义处添加颜色输出控制信息。

alt text

hashbrown有在no_std模式下使用的hashmap,在axstd文件夹下进行修改。
Cargo.toml中添加依赖hashbrown = "0.15"
axstd/src/lib.rs 将原来的 alloc::collections删除
添加 mod collections
在src下创建文件夹collections,在mod.rs中添加如下代码,

1
2
3
#[cfg(feature = "alloc")]
#[doc(hidden)]
pub use hashbrown::HashMap as HashMap;

需要为hashmap添加全局分配器,所以要引入alloc,否则会报出如下错误

1
error: no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait

第一阶段 - rust基础与算法

由于我有rust基础,没有遇到什么困难,但还是第一次完整地做一次rustlings,有一定收获

第二阶段 - 专业阶段

实验环境配置

rcore开发的环境配置比较繁琐,而我恰好比较熟悉nix,因此我用nix定义的一个完美兼容rcore的开发环境。由于不需要 rustup , 必须在 os/Makefile 中禁用 rust 环境的检测. flake.nix 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
{
description = "rCore dev flake";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
oldnixpkgs.url = "github:NixOS/nixpkgs/7cf5ccf1cdb2ba5f08f0ac29fc3d04b0b59a07e4";
flake-utils.url = "github:numtide/flake-utils";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
};

outputs = {
nixpkgs,
oldnixpkgs,
flake-utils,
rust-overlay,
...
}:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {
inherit system;
overlays = [(import rust-overlay)];
};
oldpkgs = import oldnixpkgs {
inherit system;
};
in {
devShells.default = pkgs.mkShell {
packages = with pkgs;
[
(rust-bin.nightly."2024-05-02".minimal.override {
extensions = [
"rust-src"
"llvm-tools"
"rustfmt"
"rust-analyzer"
"rust-docs"
"clippy"
];
targets = ["riscv64gc-unknown-none-elf"];
})
cargo-binutils
python3
gdb
tmux
]
++ [oldpkgs.qemu];

# 进入环境后显示rust和qemu版本
shellHook = ''
rustc --version
cargo --version
qemu-system-riscv64 --version
qemu-riscv64 --version
'';
};
});
}

这份 flake.nix 也已经分享到官方问答论坛

第一/二章

阅读这两章需要先了解riscv,特别是特权级相关设计。

主要参考:

第三章:多道程序与分时多任务

学习了系统调用,陷入等知识,上下文切换过程中通用寄存器和CSR的使用加深了我对riscv特权级设计的理解。

本章练习较为简单。

第四章:地址空间

SV39的设计又引入了若干相关的寄存器,如satp, pmp csr。查阅riscv manul以加深理解。

本章练习中,为了处理请求映射已经被映射的页的错误,我使用了Result错误传递,无法想象如果不使用Result?语法糖我的代码会多么丑陋。然而很奇怪,整个rcore中极少使用Result

第五章:进程及进程管理

本章内容比较轻松,完善了TCB的设计并实现fork()exec()系统调用。

本章练习也比较简单。

第六章:文件系统

easy-fs is NOT easy!层层抽象几乎让我晕头转向!

尽管如此,easy-fs囊括了superblock、索引节点、blockcache等现代文件系统中的基础概念,似乎不能再精简了。

link和unlink操作主要是查找inode并创建/删除目录项。在inode_block里创建与删除目录项无非是一些线性序列的操作,但由于没有封装成&[DirEntry],需要手动操作,比较费劲。将来有空我会尝试改进一下。

第七章:进程间通信

本章内容较少,但进程间通信是个大话题,还需拓展学习。

第八章:并发

学习了多线程的同步与互斥。

练习:学习了死锁检测算法

第一阶段

好几年前就被 Rust 的性能和并发功能吸引,无奈日常没有运用,只能学而时习之。不过 Rusting 还是没有什么难度的,多看看文档,轻松拿下不是问题。

第二阶段

第二阶段就需要了解操作系统原理了,各类教科书都停留在原理阶段,学完了也不知道自己学会了没有。
lab1 比较简单,原理是需要了解特权级和系统调用,实践上懂得在哪里记录数据和返回即可。
lab2 难度提升不小,原理上需要了解页表机制,多级页表极其抽象,算是一个难点。实践上要注意内核态拿到的是用户态的虚拟地址,要注意转换而不是直接访问。
lab3 难度不大,原理上就是进程那些事,不算难。实践上因为基础代码都已经提供了,依样画葫芦很容易就能通过。
lab4 感觉也是不算难的,原理上就是各种数据结构的管理。实践上因为现在的文件系统比较简易,很多可以不过多考虑直接取巧实现。最大的问题是我的机子性能太差,跑全部测试必定超时,我误以为是自己代码问题。
lab5 感觉是个巨坑,原理上实验说明写的模模糊糊,完全看不懂。实践上也是感觉测例不完善,虽然顺利通过了,但是没把握实现是正确的。

紧赶慢赶,终于是在交上了最后的实验,带着许多想法,写下了这篇总结。同样作为清朝老兵,我又回来了。

一阶段:Rust 110 道算法题

在第一阶段,主要通过编写 110 道算法题,掌握 Rust 编程的基本和高级特性。Rust 语言强调安全性和高效性,
这在算法编程中尤其重要,是的,单个语法题目还是比较轻松的,查阅资料什么的也都可以直接解决。当真正开始算法部分的
题目的时候,才开始慢慢体会到rust的折磨——借用检查器(Borrow Checker)、所有权(Ownership)以及生命周期(Lifetime)等概念
统统在处理复杂数据结构时痛击我,Rust 的强类型系统帮助我减少了运行时错误,经常是我的逻辑天衣无缝,但还是borrowed error。
没事,慢慢折磨吧,折磨多了就会了。。。

实际上,作为清朝老兵,一阶段倒是没花多少时间,翻出以前的仓库,看看填填也就过去了,但是当时熬夜做rustlings的日子仍然是我挥之不去的记忆。酸爽!

二阶段:实现 rCore 简单内核

是的,一拳打爆rcore。第二阶段则是操作系统开发,说白了就是补全各种系统调用。我也慢慢感受到书上说的种种在我看起来毫不起眼的东西,真正实现起来是真的困难,(这里点名虚拟内存和文件系统,东西是真的很多),每个ch都是一脸懵到嘎嘎乱写,然后对着panic疯狂调,期间甚至一度动摇额我的计算机世界观——计算机是真的有玄学啊。不过还好,总是能在某些神奇的地方调调代码就神奇地通过了测试,也是给我留下了不少的未解之谜。

在二阶段确实收获了不少,我现在对于一些较大的工程项目已经没有感觉了,也确实是慢慢熟悉rust了,好玩,爱玩!期待后面的考核。

祝训练营越办越好!希望能在虚拟内存和文件管理那多讲一点,确实很抽象。

最后,感觉你读完我的碎碎念,不管怎样,还是磕磕绊绊弄完了这两个阶段,也算是给上半年自己中间跑路一个交代吧,行文至此,拜拜。