Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

IPC 服务架构

Proka Kernel 采用微内核架构,所有系统操作通过 IPC(进程间通信)消息传递完成。

架构概览

┌─────────────────────────────────────────────────────────────┐
│                        用户空间                              │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────────────┐ │
│  │ 用户程序 │  │ 用户程序 │  │ 文件服务 │  │   设备服务      │ │
│  │         │  │         │  │ (fs:/)  │  │    (dev:/)      │ │
│  └────┬────┘  └────┬────┘  └────┬────┘  └───────┬─────────┘ │
└───────┼────────────┼────────────┼───────────────┼───────────┘
        │ syscall    │            │ IPC 消息      │ IPC 消息
        └─────┬──────┴────────────┴───────┬───────┘
              │                           │
              v                           v
┌─────────────────────────────────────────────────────────────┐
│                         内核空间                             │
│  ┌──────────────────────────────────────────────────────┐   │
│  │              IPC 调度器 (service::dispatch)           │   │
│  └──────────────────────────────────────────────────────┘   │
│                           │                                 │
│         ┌─────────────────┼─────────────────┐              │
│         v                 v                 v              │
│  ┌────────────┐    ┌────────────┐    ┌────────────┐        │
│  │ proc:/     │    │ mem:/      │    │ console:/  │        │
│  │ 进程服务   │    │ 内存服务   │    │ 控制台服务 │        │
│  │ (内核态)   │    │ (内核态)   │    │ (内核态)   │        │
│  └────────────┘    └────────────┘    └────────────┘        │
│                                                             │
│  注: fs:/ 和 dev:/ 可迁移到用户态成为用户空间服务            │
└─────────────────────────────────────────────────────────────┘

微内核设计原则

内核态 vs 用户态服务

服务名称当前位置可迁移至用户态
ProcessServiceproc:/内核态⚠️ 部分功能(需要调度器支持)
MemoryServicemem:/内核态⚠️ 部分功能(需要页表操作)
ConsoleServiceconsole:/内核态✅ 可迁移
FilesystemServicefs:/未实现✅ 用户态设计
DeviceServicedev:/未实现✅ 用户态设计

为什么某些服务保留在内核态?

  1. MemoryService: 需要直接操作页表,修改地址空间映射
  2. ProcessService: 需要操作调度器数据结构

迁移路径

阶段 1 (当前): 所有服务在内核态
    ↓
阶段 2: Console/FS/Device 迁移到用户态
    ↓
阶段 3: 仅保留最小内核 (IPC + 调度 + 基础内存)

命名服务注册

服务名称格式

服务通过 URI 风格的名称注册:

<type>://
服务名ServiceId说明
proc:/0进程管理服务
mem:/1内存管理服务
console:/2控制台服务
fs:/3文件系统服务
dev:/4设备管理服务

注册内核态服务

内核服务在 service::init() 中自动注册:

#![allow(unused)]
fn main() {
// kernel/src/service/mod.rs
pub fn init() {
    register_kernel_service_locked(&mut registry, Box::new(ProcessService::new()));
    register_kernel_service_locked(&mut registry, Box::new(MemoryService::new()));
    register_kernel_service_locked(&mut registry, Box::new(ConsoleService::new()));
}
}

注册用户态服务

用户态服务进程启动后注册自己:

// 用户态服务进程
fn main() {
    // 创建消息队列
    ipc::create_queue(my_tid);
    
    // 注册服务名
    service::register_user_service("fs:/", my_tid).unwrap();
    
    // 服务循环
    loop {
        let msg = ipc::recv(None, None).unwrap();
        handle_request(msg);
    }
}

服务发现

通过名称查找服务:

#![allow(unused)]
fn main() {
// 查找服务
let service_id = service::lookup_service("fs:/");  // 返回 ServiceId

// 或通过 IPC 模块查找
let tid = ipc::lookup_service("fs:/");  // 返回 TID

// 检查是否为内核服务
if ipc::is_kernel_service(tid) {
    // 使用 service::dispatch 路由到内核服务
} else {
    // 直接发送 IPC 消息到用户态服务
}
}

IPC 调用约定

寄存器传递

寄存器用途
RAX固定为 0(IPC_CALL)
RDI服务 ID
RSI载荷指针
RDX保留 (0)
R10消息类型
R8载荷指针 (备用)
R9载荷大小
RAX返回值

返回值

  • 成功: 返回值在 RAX 中
  • 失败: RAX 最高位为 1,低 63 位为错误码
if (result >> 63) {
    // 错误: error_code = result & 0x7FFFFFFFFFFFFFFF
} else {
    // 成功: retval = result
}

服务定义

服务 ID

#![allow(unused)]
fn main() {
pub enum ServiceId {
    Process = 0,   // 进程管理
    Memory = 1,    // 内存管理
    Console = 2,   // 控制台 I/O
    FileSystem = 3, // 文件系统
    Device = 4,    // 设备管理
}
}

消息格式

#![allow(unused)]
fn main() {
pub struct IpcRequestHeader {
    pub service: u16,      // 目标服务 ID
    pub msg_type: u16,     // 消息类型
    pub flags: u32,        // 标志 (保留)
    pub payload_size: u64, // 载荷大小
}

pub struct IpcResponseHeader {
    pub status: i64,       // 状态码 (0=成功)
    pub retval: u64,       // 返回值
    pub payload_size: u64, // 响应载荷大小
}
}

ProcessService

服务名: proc:/, 服务 ID: 0

消息类型

类型说明
Exit0退出当前进程
GetPid1获取当前进程 ID
Spawn2创建新进程 (未实现)
Wait3等待子进程 (未实现)

Exit

// 载荷: 4 字节退出码 (小端序)
uint8_t payload[4] = { code & 0xFF, (code >> 8) & 0xFF, ... };
ipc_call(SERVICE_PROCESS, PROCESS_EXIT, payload, 4);

GetPid

uint64_t pid = ipc_call(SERVICE_PROCESS, PROCESS_GETPID, NULL, 0);

MemoryService

服务名: mem:/, 服务 ID: 1

消息类型

类型说明
Mmap0映射内存
Munmap1取消映射
Brk2调整堆边界

Mmap

// 载荷: 32 字节
// [0-7]   addr (u64)
// [8-15]  size (u64)
// [16-23] prot (u64)
// [24-31] flags (u64)

void *mem = (void *)ipc_call(SERVICE_MEMORY, MEMORY_MMAP, payload, 32);

保护标志:

  • PROT_READ = 0x1
  • PROT_WRITE = 0x2
  • PROT_EXEC = 0x4

映射标志:

  • MAP_PRIVATE = 0x02
  • MAP_ANONYMOUS = 0x20

Munmap

// 载荷: 16 字节
// [0-7]  addr (u64)
// [8-15] size (u64)

ipc_call(SERVICE_MEMORY, MEMORY_MUNMAP, payload, 16);

Brk

// 载荷: 8 字节
// [0-7] new_brk (u64)

uint64_t brk = ipc_call(SERVICE_MEMORY, MEMORY_BRK, payload, 8);

ConsoleService

服务名: console:/, 服务 ID: 2

消息类型

类型说明
Putc0输出字符
Getc1输入字符 (未实现)
Write2输出字符串
Read3读取字符串 (未实现)

Putc

uint8_t payload[1] = { (uint8_t)c };
ipc_call(SERVICE_CONSOLE, CONSOLE_PUTC, payload, 1);

Write

ipc_call(SERVICE_CONSOLE, CONSOLE_WRITE, str, strlen(str));

错误码

#![allow(unused)]
fn main() {
pub mod error {
    pub const EINVAL: i64 = 22;      // 无效参数
    pub const ENOSYS: i64 = 38;      // 功能未实现
    pub const ESRCH: i64 = 3;        // 进程不存在
    pub const ENOMEM: i64 = 12;      // 内存不足
    pub const ESRV: i64 = 100;       // 无效服务
    pub const ESRVUNAVAIL: i64 = 101; // 服务不可用
}
}

示例

#include "ipc_test.c"

void _start(void) {
    // 输出字符串
    console_write("Hello, World!\n");
    
    // 获取 PID
    uint64_t pid = proc_getpid();
    
    // 分配内存
    void *mem = mem_alloc(4096);
    
    // 退出
    proc_exit(0);
}

相关文件

文件功能
syscall/mod.rsIPC 调用入口
service/mod.rs服务注册和分发
service/types.rsIPC 类型定义
service/process.rs进程服务
service/memory.rs内存服务
service/console.rs控制台服务
ipc/mod.rsIPC 消息传递、服务注册