Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
039d984
fix(loongarch): use uncached window for mmio
a6d9a6m Jun 23, 2026
6bbfaca
fix(loongarch): clone mmio metadata without remapping
a6d9a6m Jun 23, 2026
2ee1c63
fix(loongarch): walk all levels in tlb refill
a6d9a6m Jun 23, 2026
bacb2f3
fix(loongarch): keep kernel root in high half pgd
a6d9a6m Jun 23, 2026
c6600f1
fix(loongarch): let ertn restore user privilege
a6d9a6m Jun 23, 2026
3dbba9d
fix(loongarch): skip disabled dir4 in tlb refill
a6d9a6m Jun 23, 2026
4d5292a
test(loongarch): run musl tests from mounted image
a6d9a6m Jun 23, 2026
6af87ac
fix(ext4): prevent directory checksum stack overflow
a6d9a6m Jun 23, 2026
db5054d
test: use external oscomp images directly
a6d9a6m Jun 23, 2026
42f0f67
fix(loongarch): support ls7a rtc
a6d9a6m Jun 24, 2026
f5eb9cb
Merge remote-tracking branch 'origin/main' into loongarch-main-dev
a6d9a6m Jun 24, 2026
824f80c
fix(loongarch): poll network on timer ticks
a6d9a6m Jun 24, 2026
ecc729d
fix(loongarch): use hardware time for milliseconds
a6d9a6m Jun 24, 2026
caf3186
fix(loongarch): use raw boot trap frame storage
a6d9a6m Jun 24, 2026
f27de72
fix(loongarch): save user fpu context across traps
a6d9a6m Jun 24, 2026
cb1e195
fix(loongarch): restore fpu using target prmd
a6d9a6m Jun 24, 2026
78cccad
fix(net): defer timer network polling to worker
a6d9a6m Jun 24, 2026
01b8254
fix(ext4): shift extents on insert
a6d9a6m Jun 24, 2026
39e4046
fix(ext4): bound bitmap bit access
a6d9a6m Jun 24, 2026
70f1e9f
fix(ext4): bound direntry slice copies
a6d9a6m Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ VFAT_IMG := $(OS_DIR)/vfat.img
MKFS_VFAT ?= mkfs.vfat
ASSEMBLE_DISK := scripts/assemble_partitioned_disk.sh
COMMA := ,
TESTIMG_RV ?= sdcard-rv.img
TESTIMG_LA ?= sdcard-la.img
# Local test images can be large (LTP in particular), so keep them outside this
# worktree and attach them directly as writable QEMU block devices. Override with
# `make run-la TESTIMG_LA=/path/to/sdcard-la.img` when needed.
LOCAL_TESTIMG_DIR ?= ../CCYOS
TESTIMG_RV ?= $(firstword $(wildcard $(LOCAL_TESTIMG_DIR)/sdcard-rv.img sdcard-rv.img))
TESTIMG_LA ?= $(firstword $(wildcard $(LOCAL_TESTIMG_DIR)/sdcard-la.img sdcard-la.img))
RV_TEST_DRIVE := -drive file=$(TESTIMG_RV)$(COMMA)if=none$(COMMA)format=raw$(COMMA)id=test0 -device virtio-blk-device$(COMMA)drive=test0$(COMMA)bus=virtio-mmio-bus.0
LA_TEST_DRIVE := -drive file=$(TESTIMG_LA)$(COMMA)if=none$(COMMA)format=raw$(COMMA)id=test0 -device virtio-blk-pci$(COMMA)drive=test0

Expand Down Expand Up @@ -143,7 +147,11 @@ disk-la.img: kernel-la $(VFAT_IMG) $(ASSEMBLE_DISK)
# 官方测试盘放 bus.0,注册出来才是 vda=disk、vdb=sdcard。
# 设备型号对齐 os/qemu-run.sh(riscv: virtio-mmio)与 os/qemu-loongarch-run.sh(loongarch: pci)。
# ------------------------------------------------------------
run-rv: kernel-rv disk.img $(TESTIMG_RV)
run-rv: kernel-rv disk.img
@if [ -z "$(TESTIMG_RV)" ]; then \
echo "Error: no RISC-V test image found. Set TESTIMG_RV=/path/to/sdcard-rv.img" >&2; \
exit 1; \
fi
@echo "[Run] 运行 RISC-V QEMU(内核盘:vda1 rootfs,vda2 VFAT;测试盘:vdb)"
qemu-system-riscv64 -machine virt -kernel kernel-rv -m $(RV_MEM) -nographic \
-smp $(RV_SMP) -bios default -no-reboot -rtc base=utc \
Expand All @@ -152,7 +160,11 @@ run-rv: kernel-rv disk.img $(TESTIMG_RV)
$(RV_TEST_DRIVE) \
-device virtio-net-device,netdev=net -netdev user,id=net

run-la: kernel-la disk-la.img $(TESTIMG_LA)
run-la: kernel-la disk-la.img
@if [ -z "$(TESTIMG_LA)" ]; then \
echo "Error: no LoongArch test image found. Set TESTIMG_LA=/path/to/sdcard-la.img" >&2; \
exit 1; \
fi
@echo "[Run] 运行 LoongArch QEMU(内核盘:vda1 rootfs,vda2 VFAT;测试盘:vdb)"
qemu-system-loongarch64 -machine virt -kernel kernel-la -m $(LA_MEM) -nographic \
-smp $(LA_SMP) -no-reboot -rtc base=utc \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ cd os && make test
- 第一分区:ext4 rootfs,内容来自对应的 `os/fs-*.img`。
- 第二分区:64 MiB FAT32/VFAT 空分区,用于 OSComp `basic/mount` 与 `basic/umount` 测试。

官方测试镜像 `sdcard-rv.img` / `sdcard-la.img` 不写入 rootfs;本地运行时它们需要位于仓库根目录。`make run-rv` / `make run-la` 会将我们的 MBR 分区盘作为第一个 VirtIO 块设备 `vda`,将官方测试镜像作为第二个块设备 `vdb`。内核从 `vda1` 启动 rootfs,`rcS` 会把 `vdb` 这个裸 ext4 测试镜像挂到 `/tests` 后执行白名单 musl 测试。
官方测试镜像 `sdcard-rv.img` / `sdcard-la.img` 不写入 rootfs,也不需要复制到本仓库。`make run-rv` / `make run-la` 默认优先使用相邻 `../CCYOS/` 目录下的测试镜像,也可通过 `TESTIMG_RV=/path/to/sdcard-rv.img` 或 `TESTIMG_LA=/path/to/sdcard-la.img` 指定任意本地路径。运行时我们的 MBR 分区盘作为第一个 VirtIO 块设备 `vda`,官方测试镜像作为第二个块设备 `vdb`。内核从 `vda1` 启动 rootfs,`rcS` 会把 `vdb` 这个裸 ext4 测试镜像挂到 `/tests` 后原地执行白名单 musl 测试。

内核默认会从发现到的块设备(整盘和分区)中探测 ext4 rootfs,优先尝试分区设备,并选择含 `/bin/sh` 或 `/bin/ash` 的设备挂载为 `/`,因此评测运行形态会从我们的 `vda1` 启动。`oscomp` feature 已弃用并保留为空兼容项,不再改变启动行为。

Expand Down
2 changes: 1 addition & 1 deletion README_gitlab.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
- 第一分区:ext4 rootfs。
- 第二分区:64 MiB FAT32/VFAT 空分区,用于 `basic/mount`、`basic/umount`。

我们的 MBR 分区盘作为第一个块设备 `vda`,内核从 `vda1` 启动 rootfs。官方测试镜像 `sdcard-rv.img` / `sdcard-la.img` 作为第二个块设备 `vdb` 提供测试内容,镜像根目录包含 `musl/` 与 `glibc/`。启动脚本会把 `vdb` 这个裸 ext4 测试镜像挂载到 `/tests`,再自动运行白名单 musl 测试。
我们的 MBR 分区盘作为第一个块设备 `vda`,内核从 `vda1` 启动 rootfs。官方测试镜像 `sdcard-rv.img` / `sdcard-la.img` 作为第二个块设备 `vdb` 提供测试内容,镜像根目录包含 `musl/` 与 `glibc/`。本地运行时测试镜像可放在仓库外,并通过 `TESTIMG_RV` / `TESTIMG_LA` 指定路径;启动脚本会把 `vdb` 这个裸 ext4 测试镜像挂载到 `/tests`,再原地运行白名单 musl 测试。

内核默认会从发现到的整盘与分区块设备中探测 ext4 rootfs,优先尝试分区设备,选择含 `/bin/sh` 或 `/bin/ash` 的分区作为 `/`。`oscomp` feature 已弃用并保留为空兼容项,不再改变启动行为。

Expand Down
52 changes: 3 additions & 49 deletions data/loongarch_musl/etc/init.d/rcS
Original file line number Diff line number Diff line change
Expand Up @@ -95,56 +95,15 @@ mount_official_test_image_if_present() {
return 1
}

stage_musl_group_to_tmpfs() {
src="/tests/musl"
dst="/tmp/musl"
script="$1"

[ -d "$src" ] || return 1
[ -n "$script" ] || return 1

[ -d "$dst" ] || mkdir "$dst" || return 1

echo "[Tests] staging $script into tmpfs at $dst"

case "$script" in
basic_testcode.sh)
items="basic basic_testcode.sh busybox"
;;
busybox_testcode.sh)
items="busybox busybox_cmd.txt busybox_testcode.sh"
;;
lua_testcode.sh)
items="lua lua_testcode.sh test.sh date.lua file_io.lua max_min.lua random.lua remove.lua round_num.lua sin30.lua sort.lua strings.lua"
;;
iperf_testcode.sh)
items="busybox iperf3 iperf_testcode.sh"
;;
*)
return 1
;;
esac

for item in $items; do
[ -e "$src/$item" ] || continue
[ -e "$dst/$item" ] && continue
cp -R "$src/$item" "$dst/" || return 1
done

[ -f "$dst/$script" ] || return 1
echo "[Tests] staged $script into tmpfs"
return 0
}

run_musl_tests_if_present() {
# 官方测试镜像挂载到 /tests 后,当前自动入口只跑 musl 分组;
# glibc 分组保留在测试镜像中,后续需要时直接调整本脚本。
mount_official_test_image_if_present || true
[ -d /tests ] || return 1
[ -d /tests/musl ] || return 1

ran=0
echo "[Tests] detected whitelisted musl test scripts; running in rcS"
export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/tmp/musl:/tests/musl"
export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/tests/musl"
export HOME="/"

for name in \
Expand All @@ -153,12 +112,7 @@ run_musl_tests_if_present() {
lua_testcode.sh \
iperf_testcode.sh
do
if stage_musl_group_to_tmpfs "$name"; then
f="/tmp/musl/$name"
else
echo "[Tests] tmpfs staging failed for $name; running directly from /tests"
f="/tests/musl/$name"
fi
f="/tests/musl/$name"
[ -f "$f" ] || continue

dir="${f%/*}"
Expand Down
97 changes: 0 additions & 97 deletions docs/os-myself/big-bug-record.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,100 +74,3 @@ BusyBox applet 的链接森林只是在运行时需要,不应该作为 Git 仓
2. 减少 `mount`/`umount` 测试里的 VFAT 初始化成本。
3. 对目录项查找和路径解析加缓存,减少 exec 高频路径的重复 ext4 访问。
4. 如果评测机总时间更长,可以保留当前按组懒 staging;如果只追 basic 分数,可以进一步只运行 basic 组,避免后续组影响关机和输出。

## 2026-06-23 iperf TCP 吞吐从几 KB/s 提升到数百 Mbit/s

### 现象

最初 iperf 组能启动,但 TCP 分数几乎没有贡献:

- `BASIC_TCP` 只发送 4KiB,sender 约 16Kbit/s,receiver 为 0。
- `REVERSE_TCP` sender 也只有 4KiB,receiver 为 0。
- `PARALLEL_TCP` 第二条以后连接报 `Connection refused`。
- UDP 能跑通,说明基本 socket、loopback 地址和 iperf 控制连接不是完全坏掉;问题集中在 TCP 数据面和监听队列语义。

### 关键发现

第一层瓶颈是监听语义。iperf3 `-P 5` 会为同一个 server port 建多条 TCP data stream。smoltcp 的 TCP socket 没有 Linux 那种单 socket backlog 队列模型,监听端需要准备多个 TCP socket 才能同时接住多个 SYN。原实现只有一个 listener handle,所以第一条连接建立后,后续 stream 容易被拒绝。

第二层瓶颈是 loopback MTU 和 adapter RX buffer 不一致。loopback 设备暴露 `mtu=65535`,smoltcp 因此会发接近 64KiB 的 TCP/IP 包;但 `NetDeviceAdapter` 原来只有 2048 字节接收缓冲。结果大 TCP frame 在 adapter 层直接被丢掉,表现为客户端以为发出了少量数据,服务端几乎收不到。

第三层是 syscall 和轮询节奏。iperf3 会传大 buffer;如果每次 syscall 都按用户长度一次性分配/copy,会增加内核堆压力,也让 loopback 队列 drain 不及时。写入后不主动 poll,会把推进 TCP 状态机的工作推迟到后续调度点,吞吐很差。

### 处理步骤

这轮 TCP 相关修复按小步提交推进:

- `da0d56c tests: stage busybox for iperf script`:iperf 脚本里会调用 BusyBox 工具,staging 只复制 `iperf3` 不够,先保证测试脚本自身能稳定运行。
- `56c01e8 net: enlarge socket buffers for iperf`:TCP/UDP buffer 扩到 256KiB,避免 iperf 数据面频繁因为小 buffer 进入 WouldBlock。
- `de092e8 net: chunk socket syscall buffers`:`send/recv` 单次内核复制限制到 64KiB,控制临时分配和 copy 成本。
- `e63c8a5 net: drain loopback after socket writes`:socket write/sendto 成功后 bounded poll,尽快把 loopback Tx frame 回灌到 Rx 并推进 smoltcp 状态机。
- `eb9d8ce net: support parallel tcp listeners`:为监听 socket 维护一组 spare TCP listener,accept 时把已建立连接交给新 fd,并补充新的 listener,解决 `PARALLEL_TCP` 连接拒绝。
- `491634c net: reduce iperf socket log noise`:把热路径 socket/TCP 连接日志从 info 降到 debug,避免串口日志本身拖慢性能。
- `aae6897 net: size adapter rx buffer for mtu`:adapter RX buffer 改为按 `device.mtu() + Ethernet header` 分配,修复 64KiB loopback TCP frame 被 2048B buffer 丢弃的问题。
- `474b6ea net: cap tcp buffers below unstable window`:验证 UDP 改动时复现 smoltcp `SeqNumber` subtraction underflow,最终把 TCP buffer 从 256KiB 收到 128KiB-1,避开不稳定的大窗口组合。

### 决策和取舍

没有直接 patch smoltcp。这里的问题主要是我们给 smoltcp 的设备能力、buffer 和 listen 模型不一致,先修本内核适配层更稳,也更容易解释。

TCP buffer 起初选 256KiB,是为了减少 WouldBlock 并提高窗口;这一版峰值很好,`BASIC_TCP`/`REVERSE_TCP` 能到约 490Mbit/s,`PARALLEL_TCP` 能到约 709Mbit/s。但后续在完整 iperf-only 复测中,`PARALLEL_TCP` 五条连接建立后触发 smoltcp sequence number underflow panic。64KiB 以内能稳定,但单流 TCP 只剩约 70Mbit/s。最终选 `128KiB-1`:仍然明显高于原始 4KiB/0 receiver,且完整 iperf 组稳定通过。

listener pool 做了上限,不直接相信 iperf 传入的巨大 backlog。当前逻辑把用户 backlog clamp 到 128,实际 spare listener pool clamp 到 16,足够覆盖 iperf `-P 5`,同时避免一次 listen 分配过多 TCP buffer。

保留 loopback 的大 MTU,而不是降回 1500。降 MTU 能减少单帧内存,但 TCP throughput 会被更多包处理开销限制。真正的问题是 adapter 宣告大 MTU 却没有同等大小的 RX buffer,因此修 buffer 更符合设备模型。

### 验证

临时把 RISC-V `rcS` 改成只跑 `iperf_testcode.sh`,构建 release 内核,用临时分区盘 `/tmp/ccyos-disk-udpq-tcp128k.img` 跑官方 RISC-V musl iperf 组。

最终采用 128KiB-1 TCP buffer 后,最新一次验证中 TCP 三项都通过:

- `BASIC_TCP`:sender 71.7MiB / 300Mbit/s,receiver 71.4MiB / 299Mbit/s。
- `PARALLEL_TCP`:5 stream 全部连接成功,SUM sender 102MiB / 424Mbit/s,receiver 102MiB / 418Mbit/s。
- `REVERSE_TCP`:sender 72.2MiB / 302Mbit/s,receiver 72.0MiB / 302Mbit/s。

这说明最初 “4KiB / receiver 0” 和 “parallel connection refused” 两个 TCP 主问题已经解决。TCP 的峰值为了稳定性放弃了 256KiB buffer 下的最高数字,但所有 TCP 子项稳定通过,且吞吐仍是原始结果的数量级提升。

## 2026-06-23 iperf UDP 单流和反向模式高丢包

### 现象

TCP 主问题解决后,UDP 仍然拖分:

- `BASIC_UDP` receiver 约 46Mbit/s,丢包约 58%-61%。
- `REVERSE_UDP` receiver 约 48Mbit/s,同样有大量丢包。
- `PARALLEL_UDP` 反而能到约 137Mbit/s 且 0% loss。

这个现象说明链路、loopback MTU 和基本 UDP socket 不是完全坏掉;单 fd 收包路径比多 stream 分摊路径更容易溢出。

### 关键发现

本内核对 UDP 做了 per-port smoltcp socket 加 per-fd 队列的分发。smoltcp 共享 socket 收到包以后,`udp_dispatch_drain_locked()` 会复制到目标 `SocketFile` 的 `udp_rx_queue`,用户态再从这个队列 `recvfrom()`。

原来的 `UDP_RXQ_CAP = 64` 太小。iperf UDP 使用极高目标带宽发包,发送端在短时间内产生的 datagram 比接收线程 drain 得更快;队列满后 `udp_push()` 直接返回 false,后续 datagram 被丢掉。`PARALLEL_UDP` 因为 5 条 stream 分散到多个 fd 队列,每个队列压力小,所以表现比单流好。

试过把 UDP 队列固定预分配到 512。这个版本把 `BASIC_UDP` 提到 77.8Mbit/s 且 0% loss,但 `PARALLEL_UDP` 随后触发 `memory allocation of 1064960 bytes failed`。原因是每个 UDP 队列项包含最大 2048 字节 payload 缓冲,512 项接近 1MiB;所有 UDP socket 一创建就预分配,会把 parallel 场景的内存压力放大。

### 处理步骤

- `f4905d9 net: grow udp receive queues lazily`:UDP per-fd 队列初始仍为 64,只有队列满时才尝试翻倍扩容,最大 512。
- 如果扩容失败或已达上限,队列丢弃最旧 datagram 再放入新 datagram。这样在内存紧张时仍然有 UDP 丢包,但不会因为固定大队列把内核堆打爆,也更偏向保留较新的 iperf 数据。

### 决策和取舍

没有把所有 UDP socket 都预分配 512 项。固定大队列能改善单流 loss,但并行时内存占用不可控;lazy growth 只让真正承压的 socket 付出内存成本。

没有把 UDP 队列做成无限增长。iperf `-u -b 1000G` 本质上会制造远超内核处理能力的 burst;无限增长只是把丢包变成内存耗尽。512 是这次本地验证中能消掉单流丢包、又不会让 parallel UDP 分配失败的上限。

丢弃策略从“队列满就丢新包”变成“扩不动时丢旧包”。这对 UDP 是可接受取舍:UDP 本来不保证可靠性,保留较新的 datagram 对 iperf 的实时统计和反向模式更有价值。

### 验证

临时把 RISC-V `rcS` 改成只跑 `iperf_testcode.sh`,构建 release 内核并用临时分区盘 `/tmp/ccyos-disk-udpq-tcp128k.img` 跑官方 RISC-V musl iperf 组。最新一次完整 iperf-only 验证全部通过:

- `BASIC_UDP`:sender 25.9MiB / 109Mbit/s,receiver 25.9MiB / 108Mbit/s,0% loss。
- `PARALLEL_UDP`:SUM sender 36.6MiB / 154Mbit/s,receiver 36.5MiB / 153Mbit/s,0% loss。
- `REVERSE_UDP`:sender 19.9MiB / 82.7Mbit/s,receiver 19.8MiB / 82.8Mbit/s,0% loss。

这说明 UDP 的主要问题是 per-fd 接收队列容量和内存策略,而不是 UDP 校验、地址绑定或 loopback 设备本身。
14 changes: 11 additions & 3 deletions os/qemu-loongarch-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ arch="${ARCH:-loongarch}"
fs="fs-${arch}.img"
disk="disk-la.img"
vfat="vfat.img"
test_img="../sdcard-la.img"
test_img="${TESTIMG_LA:-}"
if [ -z "$test_img" ]; then
for candidate in "../../CCYOS/sdcard-la.img" "../sdcard-la.img"; do
if [ -f "$candidate" ]; then
test_img="$candidate"
break
fi
done
fi

QEMU_ARGS=(
-machine virt
Expand Down Expand Up @@ -53,12 +61,12 @@ else
QEMU_ARGS+=(-drive file="$disk",if=none,format=raw,id=x0)
QEMU_ARGS+=(-device virtio-blk-pci,drive=x0)

if [ -f "$test_img" ]; then
if [ -n "$test_img" ] && [ -f "$test_img" ]; then
echo "Attaching official test image ${test_img} as vdb"
QEMU_ARGS+=(-drive file="$test_img",if=none,format=raw,id=test0)
QEMU_ARGS+=(-device virtio-blk-pci,drive=test0)
else
echo "Warning: official test image ${test_img} not found; skipping vdb attachment" >&2
echo "Warning: official test image not found; set TESTIMG_LA=/path/to/sdcard-la.img to attach one" >&2
fi
fi

Expand Down
14 changes: 11 additions & 3 deletions os/qemu-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@ arch="${ARCH:-riscv}"
fs="fs-${arch}.img"
disk="disk.img"
vfat="vfat.img"
test_img="../sdcard-rv.img"
test_img="${TESTIMG_RV:-}"
if [ -z "$test_img" ]; then
for candidate in "../../CCYOS/sdcard-rv.img" "../sdcard-rv.img"; do
if [ -f "$candidate" ]; then
test_img="$candidate"
break
fi
done
fi

# 1. 转换为纯二进制
rust-objcopy --strip-all "$ELF_FILE" -O binary "$BIN_FILE"
Expand Down Expand Up @@ -63,12 +71,12 @@ else
QEMU_ARGS="$QEMU_ARGS -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.1"

# 官方测试盘是额外裸 ext4 盘,固定注册为 /dev/vdb 后由 rcS 挂载到 /tests。
if [ -f "$test_img" ]; then
if [ -n "$test_img" ] && [ -f "$test_img" ]; then
echo "Attaching official test image ${test_img} as vdb"
QEMU_ARGS="$QEMU_ARGS -drive file=$test_img,if=none,format=raw,id=test0"
QEMU_ARGS="$QEMU_ARGS -device virtio-blk-device,drive=test0,bus=virtio-mmio-bus.0"
else
echo "Warning: official test image ${test_img} not found; skipping vdb attachment" >&2
echo "Warning: official test image not found; set TESTIMG_RV=/path/to/sdcard-rv.img to attach one" >&2
fi
fi

Expand Down
14 changes: 14 additions & 0 deletions os/src/arch/loongarch/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ mod page_table;
mod page_table_entry;

use crate::arch::address::{PA, VA};
use crate::mm::address::{PageNum, Ppn, UsizeConvert};
use core::sync::atomic::{AtomicUsize, Ordering};
pub use page_table::{PageTableInner, TlbBatchContext};
pub use page_table_entry::PageTableEntry;

Expand All @@ -39,6 +41,18 @@ pub const VADDR_START: usize = 0x9000_0000_0000_0000;
/// 用于从虚拟地址提取物理地址,保留低 48 位。
pub const PADDR_MASK: usize = 0x0000_FFFF_FFFF_FFFF;

static KERNEL_ROOT_PPN: AtomicUsize = AtomicUsize::new(0);

/// Register the final kernel page-table root used for the high-half address space.
pub fn set_kernel_root_ppn(ppn: Ppn) {
KERNEL_ROOT_PPN.store(ppn.as_usize(), Ordering::Release);
}

pub(crate) fn kernel_root_paddr() -> Option<usize> {
let ppn = KERNEL_ROOT_PPN.load(Ordering::Acquire);
(ppn != 0).then(|| Ppn::from_usize(ppn).start_addr().as_usize())
}

/// 虚拟地址转物理地址
///
/// # 参数
Expand Down
Loading
Loading