0x822a5b87的博客

到码头整点薯条吃

uCore并发

引言

线程定义

简单地说,线程是进程的组成部分,进程可包含1 – n个线程,属于同一个进程的线程共享进程的资源, 比如 地址空间、打开的文件等。基本的线程由线程ID、执行状态、当前指令指针 (PC)、寄存器集合和栈组成。 线程是可以被操作系统或用户态调度器独立调度(Scheduling)和分派(Dispatch)的基本单位。进程是线程的资源容器, 线程成为了程序的基本执行实体。

同步互斥

阅读全文 »

进程间通信

基于文件的管道

// os/src/fs/pipe.rs

pub struct Pipe {
    readable: bool,
    writable: bool,
    buffer: Arc<Mutex<PipeRingBuffer>>,
}

通过 buffer 字段还可以找到该管道端所在的管道自身。后续我们将为它实现 File Trait ,之后它便可以通过文件描述符来访问。

// os/src/fs/pipe.rs

const RING_BUFFER_SIZE: usize = 32;

#[derive(Copy, Clone, PartialEq)]
enum RingBufferStatus {
    FULL,
    EMPTY,
    NORMAL,
}

pub struct PipeRingBuffer {
    arr: [u8; RING_BUFFER_SIZE],
    head: usize,
    tail: usize,
    status: RingBufferStatus,
    write_end: Option<Weak<Pipe>>,
}
阅读全文 »

文件系统

layout

整体逻辑

graph BT
    %% 核心模块:easy-fs(文件系统核心逻辑)
    subgraph easy-fs ["easy-fs(文件系统核心算法)"]
        direction BT
        subgraph BD ["抽象层:BlockDevice(块设备接口)"]
            direction TB
            read_block("read_block")
            write_block("write_block")
        end

        subgraph BC ["缓存层:BlockCache(块缓存)"]
            direction TB
            read("read")
            modify("modify")
            bc_other("其他缓存操作...")
        end

        subgraph LAY ["布局层:存储结构定义"]
            direction TB
            SB("SuperBlock(超级块)")
            BM("Bitmap(位图)")
            DI("DiskInode(磁盘索引节点)")
            DE("DirEntry(目录项)")
            DB("DataBlock(数据块)")
        end

        subgraph BMGR ["管理层:文件系统实例/接口"]
            direction TB
            EFS("EasyFileSystem(文件系统实例)")
            INODE("Inode(文件/目录操作接口)")
        end

        %% easy-fs 内部链路(修正方向)
        BD -->|读写物理块| BC
        BC -->|缓存读写| LAY
        LAY -->|基于布局实现| BMGR
    end

    %% 辅助工具:easy-fs 配套工具(宿主机侧)
    subgraph easy-fs-tools ["easy-fs-tools(宿主机工具)"]
        direction TB
        pack("easy_fs_pack(打包工具)")
        fuse("easy-fs-fuse(FUSE调试工具)")
    end
    easy-fs -->|依赖核心逻辑| pack
    pack -->|生成镜像| fs_img["fs.img(raw格式镜像)"]
    easy-fs -->|适配FUSE接口| fuse
    fuse -->|挂载调试| fs_img

    %% QEMU(虚拟硬件层)
    subgraph qemu ["QEMU(虚拟硬件)"]
        direction TB
        drive("-drive file=fs.img(后端存储)")
        virtio_dev("-device virtio-blk-device(虚拟块设备)")
    end
    fs_img -->|作为后端存储| drive
    drive -->|绑定到虚拟设备| virtio_dev

    %% os 内核(驱动+文件系统调用)
    subgraph os ["os(内核层)"]
        direction TB
        subgraph VIRTIO ["驱动层:VirtIOBlock"]
            direction TB
            virtio_bd("实现 BlockDevice 接口")
            virtio_ops("virtio-blk 读写操作")
        end
        subgraph FS_CALL ["应用层:文件系统调用"]
            direction TB
            fs_open("open/read/write")
            fs_exec("执行ELF文件")
        end
    end
    %% 内核链路
    qemu -->|暴露虚拟硬件| virtio_dev
    virtio_dev -->|内核枚举设备| VIRTIO
    VIRTIO -->|适配接口| easy-fs
    easy-fs -->|提供文件操作| FS_CALL

文件与文件描述符

阅读全文 »

uCore:进程及进程管理

我们将开发一个用户 终端 (Terminal) 或 命令行 (Command Line Application, 俗称 Shell ) , 形成用户与操作系统进行交互的命令行界面 (Command Line Interface)。

为此,我们要对任务建立新的抽象: 进程 ,并实现若干基于 进程 的强大系统调用。

flowchart LR
    subgraph init["初始化阶段:无用户任务"]
        direction LR
        registers_0("registers.cx: idle运行状态"):::pink
        current_0("current: None"):::purple
        idle_task_cx_0("idle_task_cx: zero.ctx(占位)"):::green
    end

    subgraph stage_1["阶段1:fetch_task"]
        direction LR
        registers_1("registers.cx: task.cx(用户任务状态)"):::pink
        current_1("current: Some(task)"):::purple
        idle_task_cx_1("idle_task_cx: 原registers.cx(idle休眠状态)"):::green
    end

    subgraph stage_2["阶段2:suspend"]
        direction LR
        registers_2("registers.cx: idle运行状态(从idle_task_cx_1加载)"):::pink
        current_2("current: None"):::purple
        idle_task_cx_2("idle_task_cx: 原registers_1(用户任务挂起状态)"):::green
    end

    subgraph stage_3["阶段3:exit→用户任务退出"]
        direction LR
        registers_3("registers.cx: idle运行状态(从idle_task_cx_1加载)"):::pink
        current_3("current: None"):::purple
        idle_task_cx_3("idle_task_cx: 原idle_task_cx_1(无变化)"):::green
    end

    subgraph TaskManager["TaskManager:就绪队列"]
        t_task("task.cx: 用户任务挂起状态(仅suspend后存在)"):::coral
    end

    %% 流转逻辑(补充关键动作标注)
    init -->|init| stage_1
    stage_1 -->|suspend| stage_2
    stage_1 -->|exit| stage_3

    %% 状态转移细节
    current_1 -->|take_current后add_task,共享task所有权| TaskManager
    registers_1 -->|__switch保存用户任务状态到task.cx| t_task
    idle_task_cx_1 -->|__switch加载idle状态到寄存器| registers_2
    idle_task_cx_1 -->|__switch加载idle状态到寄存器| registers_3

    %% 样式定义(沿用你的设计)
    classDef pink fill:#FFCCCC,stroke:#333, color: #fff, font-weight:bold;
    classDef green fill: #696,color: #fff,font-weight: bold;
    classDef purple fill:#969,stroke:#333, font-weight: bold;
    classDef error fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5;
    classDef coral fill:#f9f,stroke:#333,stroke-width:4px;
    classDef animate stroke-dasharray: 9,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;

与进程有关的重要系统调用

重要系统调用

阅读全文 »

在这个章节,我们会实现虚拟内存机制。

物理空间和虚拟空间

虚拟空间连续,物理空间不一定连续!

flowchart LR
    %% 样式定义(避开关键字,用合法语法)
    classDef structStyle fill:#f0f8ff,stroke:#2c3e50,stroke-width:2px,rounded:10px
    classDef vaStyle fill:#fdf2f8,stroke:#9b59b6,stroke-width:2px,rounded:10px
    classDef vpnStyle fill:#fef7fb,stroke:#9b59b6,stroke-width:1px,rounded:8px,padding:10px
    classDef paStyle fill:#e8f4f8,stroke:#3498db,stroke-width:2px,rounded:10px
    classDef ppnStyle fill:#f0f8ff,stroke:#3498db,stroke-width:1px,rounded:8px,padding:10px
    classDef fieldStyle font-weight:bold,color:#2c3e50
    classDef connStyle stroke:#7f8c8d,stroke-width:1.5px,arrowheadStyle:fill:#7f8c8d

    %% 上层:结构体(连续字段)
    subgraph Struct["📦 TimeVal 结构体(连续虚拟内存视图)"]
        direction TB
        sec["sec
usize (8字节)"]:::fieldStyle usec["usec
usize (8字节)"]:::fieldStyle end class Struct structStyle %% 中层:虚拟地址 VA(连续,跨2个虚拟页) subgraph VA["🌐 虚拟地址 VA(连续)"] direction LR subgraph VPN0["VPN0(虚拟页0)"] %% 修正:sec 位于 VPN0 末尾,VA = 页起始 + (4KB-8) = 0x40200000 + 0xFF8 = 0x40200FF8 va_sec["0x40200FF8
[页内偏移: 0xFF8 = 4KB-8]"] end subgraph VPN1["VPN1(虚拟页1)"] %% 修正:usec 位于 VPN1 起始,页内偏移 0x000 va_usec["0x40201000
[页内偏移: 0x000]"] end note_va["页大小:4KB (0x1000)
VPN0范围:0x40200000~0x40200FFF
VPN1范围:0x40201000~0x40201FFF"] class note_va vaStyle end class VA vaStyle %% 下层:物理地址 PA(离散) subgraph PA["💾 物理地址 PA(离散)"] subgraph PPN0["PPN0(物理页0)"] %% 物理页0起始 + 偏移0xFF8 = 0x8000 + 0xFF8 = 0x8FF8 pa_sec["0x8FF8
[页内偏移: 0xFF8]"] end subgraph PPN1["PPN1(物理页1)"] %% 物理页1起始 + 偏移0x000 = 0x4000 + 0x000 = 0x4000 pa_usec["0x4000
[页内偏移: 0x000]"] end note_pa["物理页独立分配,地址不连续
PPN0范围:0x8000~0x8FFF
PPN1范围:0x4000~0x4FFF"] class note_pa paStyle end class PA paStyle %% 映射关系(字段 → VA → PA) sec -.->|字段对应VA| va_sec:::connStyle usec -.->|字段对应VA| VPN1:::connStyle va_sec -.->|页表翻译(VPN0→PPN0)| pa_sec:::connStyle va_usec -.->|页表翻译(VPN1→PPN1)| pa_usec:::connStyle %% 核心结论标注(突出问题) conclusion["⚠️ 核心问题:
结构体VA连续(跨页边界),但映射的PA离散
内核需拆为2段写入:
1. PPN0的0x8FF8~0x8FFF(6字节?不,8字节刚好)
2. PPN1的0x4000~0x4007"]:::structStyle PA -.->|体现| conclusion:::connStyle

管理SV39多级页表

阅读全文 »

多道程序与分时多任务

内存调度模型

flowchart LR
    %% 按类型定义专属样式(遵循通俗约定:函数=蓝、结构体=绿、寄存器=紫、栈=浅红、内存=黄、管理组件=深蓝)
    classDef func fill:#4299e1, stroke:#2563eb, stroke-width:2px, color:#fff, font-weight:bold, rounded:8px, font-size:14px;
    classDef struct fill:#4ade80, stroke:#16a34a, stroke-width:2px, color:#1e293b, font-weight:bold, rounded:8px, font-size:14px;
    classDef reg fill:#a855f7, stroke:#7e22ce, stroke-width:2px, color:#fff, font-weight:bold, rounded:6px, font-size:13px;
    classDef stack fill:#fecaca, stroke:#dc2626, stroke-width:2px, color:#7f1d1d, font-weight:600, rounded:8px, font-size:13px;
    classDef memory fill:#fde047, stroke:#ca8a04, stroke-width:2px, color:#78350f, font-weight:600, rounded:8px, font-size:13px;
    classDef manager fill:#1e40af, stroke:#1e3a8a, stroke-width:2px, color:#fff, font-weight:bold, rounded:10px, font-size:14px;
    classDef transition stroke:#64748b, stroke-width:1.5px, stroke-linecap:round, font-size:12px, font-family:Arial;
    classDef subgraphTitle fill:#1e293b, font-weight:bold, font-size:14px, font-family:Arial;

    %% 栈(USER_STACK/KERNEL_STACK)
    subgraph USER_STACK["USER_STACK"]
        direction LR
        US1("..."):::stack
        US0("UserStack 0"):::stack
    end
    subgraph KERNEL_STACK["KERNEL_STACK"]
        direction LR
        KS1("..."):::stack
        KS0("KernelStack 0"):::stack
    end

    %% 内存/二进制代码
    subgraph Memory["Memory"]
       direction LR
        M1("..."):::memory
        M0("Task 0 Code"):::memory
    end

    %% 任务相关(结构体:TaskControlBlock/TaskStatus/TaskContext/TrapContext)
    subgraph tasks["tasks"]
       subgraph TaskControlBlock1["TaskControlBlock1"]
        TaskContext1("..."):::struct
        TaskStatus1("..."):::struct
       end
       subgraph TaskControlBlock0["TaskControlBlock0"]
        subgraph TaskContext0["TaskContext0"]
            ra0("ra"):::reg 
            sp0("sp"):::reg
            s0("s0 ~ s11"):::reg
        end
        TaskStatus0("TaskStatus 0"):::struct
       end
    end
    subgraph TrapContextList["TrapContextList"]
        OtherTrapContext("..."):::struct
        subgraph TrapContext["TrapContext"]
            x0("x0~x31"):::reg
            ssstatus0("sstatus"):::reg
            sepc0("sepc"):::reg
        end
    end

    %% 管理组件(TaskManager/TASK_MANAGER)
    TaskManager("TaskManager"):::manager
    TASK_MANAGER("TASK_MANAGER"):::manager

    %% 函数(main/__restore)
    main("main"):::func
    __restore("__restore"):::func

    %% 原有连接关系(保持不变,统一应用transition样式)
    TaskManager -->|延迟加载全局唯一实例| TASK_MANAGER:::transition
    main -->|1. load_apps 加载应用代码| Memory:::transition
    main -->|2. run_first_task触发初始化| TASK_MANAGER:::transition
    TASK_MANAGER -.->|初始化| tasks:::transition
    sp0 -.->|__restore使用sp作为参数恢复上下文| __restore:::transition
    sepc0 -.-> M0:::transition
    x0 -.->|sp| US0:::transition
    KS0 -.->|存储了TrapContext| TrapContext:::transition
    ra0 --> __restore:::transition
    sp0 --> KS0:::transition

    %% 优化子图标题样式(统一居中、加粗)
    style USER_STACK fill:#fef2f2, stroke:#fecaca, stroke-width:1px, padding:10px;
    style KERNEL_STACK fill:#fef2f2, stroke:#fecaca, stroke-width:1px, padding:10px;
    style Memory fill:#fffbeb, stroke:#fde047, stroke-width:1px, padding:10px;
    style tasks fill:#ecfccb, stroke:#4ade80, stroke-width:1px, padding:10px;
    style TrapContextList fill:#ecfccb, stroke:#4ade80, stroke-width:1px, padding:10px;

实现

应用加载

阅读全文 »

批处理系统

综述

在本章节中,我们实现一个简单的批处理系统,内核在启动之后,将多个程序打包输入并按顺序执行,而本章节我们会实现以下几个重要逻辑:

  1. 通过加载器在启动时动态的加载代码到并执行;
  2. 实现错误处理,保证在单个程序出错时不影响其他的程序。这个位置我们会引入一些新的概念,例如 privilege。同时我们也可以看到操作系统和普通的应用程序的区别,例如:操作系统有自己的内核栈,这个栈是完全独立于任何程序的。
  3. 操作系统通过trap机制来处理 interruptionexception 事件。
---
title: Compiling rCore-test
---
flowchart TB

subgraph desc
    direction TB
    build_system("构建系统"):::purple
    dir("文件夹"):::green
    products("源文件/构建产物"):::animate
end


subgraph 构建过程
    direction LR
    makefile("Makefile"):::purple
    build("build.py"):::purple

    target("target/riscv64gc-unknown-none-elf/release"):::green
    build_dir("build"):::green

    source_code("*.rs"):::animate
    bin("*.bin"):::animate
    elf("*.elf"):::animate
    object("*.object"):::animate


    source_code -->|输入| build -->|编译| object -.->|输出到文件夹| target
    object -->|输入| makefile -->|rust-objcopy| bin -.->|输出到文件夹| target
    object -->|输入| makefile -->|cp| elf -.->|输出到文件夹| target

    bin -->|cp| build_dir
    elf -->|cp| build_dir
end

desc --> 构建过程

classDef pink 0,fill:#FFCCCC,stroke:#333, color: #fff, font-weight:bold;
classDef green fill: #695,color: #fff,font-weight: bold;
classDef purple fill:#968,stroke:#333, font-weight: bold;
classDef error fill:#bbf,stroke:#f65,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
classDef coral fill:#f8f,stroke:#333,stroke-width:4px;
classDef animate stroke-dasharray: 8,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
阅读全文 »

项目的全部代码在这里:ardi

整体逻辑图解

我们的项目包含以下文件,各模块功能如下:

  1. *.rs 文件:Rust 源代码文件,定义了程序的核心执行逻辑;
  2. linker.ld:链接脚本(Linker Script),用于告知链接器如何合并目标文件、编排内存布局,最终生成符合要求的二进制文件;
  3. entry.asm:启动引导文件(汇编编写),负责初始化基础执行环境,引导 CPU 定位并跳转到 Rust 程序的入口地址;
  4. rustsbi-qemu.bin :SBI(Supervisor Binary Interface)固件文件,作为内核与硬件的隔离层 / 抽象层,为内核提供硬件相关的基础服务(详见 什么是 SBI);
  5. Makefile : 构建脚本,通过声明编译目标(target)、依赖关系及执行命令,简化程序的编译、运行、加载等流程管理。
flowchart LR

rustsbi(rustsbi-qemu.bin):::coral
linker("linker.ld"):::green
entry("entry.asm"):::green
rust("*.rs"):::green
qemu("qemu"):::error

cargo("cargo"):::error

linker --> cargo
entry --> cargo
rust --> cargo

cargo --> elf -->|rust-objcopy| binary

subgraph elf
    direction TB
    os_comment("elf格式的二进制文件") -.-> os("os"):::pink
end

subgraph binary
    direction TB
    os_bin_comment("二进制文件") -.-> os_bin("os.bin"):::pink
end

binary --> rustsbi --> qemu

classDef pink 0,fill:#FFCCCC,stroke:#333, color: #fff, font-weight:bold;
classDef green fill: #695,color: #fff,font-weight: bold;
classDef purple fill:#968,stroke:#333, font-weight: bold;
classDef error fill:#bbf,stroke:#f65,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
classDef coral fill:#f8f,stroke:#333,stroke-width:4px;
classDef animate stroke-dasharray: 8,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
阅读全文 »

前言

最近在学习 RISCV 的过程中,碰见了一个比较奇特的BUG,在下面的代码中,我们出现了一个神秘的未定义行为(Undefined Behavior):

#include <stdio.h>

void main()
{
    char a;
    unsigned int b;
    unsigned long c;

    a = 0x88;
    b = ~a;
    c = ~a;

    printf("a=0x%x, ~a=0x%x, b=0x%x, c=0x%lx\n", a, ~a, b, c);
}

本来是一段很简单的用于测试C语言下的隐式转换规则的代码,结果很神奇的是在两个不同的平台下出现了截然不同的输出!

x86/x86_64

阅读全文 »

最近由于学习 risc-v,需要使用到 gdb 来调试 elf 文件,本来想使用大学期间比较熟悉的 gdbinit 或者 peda。折腾了接近两天时间,修复了各种问题,最后还是失败了。直接切换到 pwndbg 解决全部问题。

pwndbg

回想这两天痛苦的查文档,翻github的issue却从来没有想过时代在变化,大学期间的明星项目peda已经断更五年多了。

0%