MySBI+BenOS:RISC-V SBI启动调试与裸机OS手把手实验指南
简介本资源是《RISC-V体系结构编程与实践》第二章配套的MySBI轻量级SBI接口与BenOS教学型RTOS内核实验代码面向嵌入式系统开发者、操作系统课程学习者及RISC-V初学者聚焦系统级编程能力培养与硬件-软件协同理解。压缩包共17个文件含4个C源码如sbi_main.c、kernel.c、4个汇编文件如boot.S、sbi_boot.S、3个头文件uart.h、io.h等、3个链接脚本sbi_linker.ld、linker.ld等以及makefile、配置文件riscv64-benos_defconfig和sbi_payload二进制载荷总大小仅7KB结构精炼、模块职责清晰便于逐层剖析启动流程、中断处理与任务调度机制。已有304人学习下载读者可直接基于该代码在QEMU等RISC-V模拟器中构建、编译并调试完整系统调用栈与微型OS运行环境深入掌握SBI初始化逻辑、BenOS内核调度策略及UART驱动实现细节是理解RISC-V底层生态与操作系统设计原理的高价值实践入口。1. MySBI与BenOS实验代码不是“又一个RISC-V启动流程演示”而是能让你亲手掐住SBI握手脉搏、把裸机OS从reset向量一路推到main的可调试沙盒如果你在查“MySBI”和“BenOS”大概率正卡在这样一个真实困境里手头有QEMU或FPGA开发板想跑通一个极简RISC-V操作系统但官方文档只告诉你“编译sbi然后load os”却没说当mret跳进OS第一条指令时a0里传的hartid为什么是0xdeadbeef、a1里的dtb地址为何总为空、或者为什么ecall一触发就跳进黑洞——这些不是玄学是SBI规范与具体实现之间那层薄如蝉翼却极易撕裂的契约。MySBI与BenOS实验代码正是为这种“想抠寄存器、想改trap handler、想单步看mstatus切换”的硬核调试场景而生它不封装、不抽象、不隐藏汇编入口它把SBI初始化拆成可断点的C函数把BenOS的boot.S暴露成可修改的符号表所有关键路径CLINT timer setup、PLIC enable、hart启动同步都带#ifdef DEBUG_TRACE开关。适合刚啃完《RISC-V手册》第5章、正在用OpenOCD连SiFive HiFive1或QEMU-machine virt做裸机实验的开发者也适合需要快速构建教学演示环境的某高校嵌入式系统课程导师。2. 搭建可调试的MySBIBenOS最小运行环境从零拉起QEMU虚拟平台并验证SBI调用链路2.1 准备交叉工具链与基础依赖避开riscv64-unknown-elf-gcc版本陷阱MySBI与BenOS实验代码对工具链版本敏感。实测发现使用riscv64-unknown-elf-gcc 12.2.0及以上版本时.option push/pop语法在start.S中会因gas版本不匹配报错而低于10.2.0则可能因缺少__atomic_*内置函数导致SBI原子操作链接失败。常见做法是锁定riscv64-unknown-elf-gcc 11.2.0 binutils 2.38组合。以下命令在Ubuntu 22.04上可复现# 卸载系统自带旧版 sudo apt remove gcc-riscv64-unknown-elf binutils-riscv64-unknown-elf # 下载预编译包避免源码编译耗时 wget https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2022.06.10/riscv64-unknown-elf-gcc-11.2.0-2022.06.10-x86_64-linux-ubuntu20.tar.gz tar -xzf riscv64-unknown-elf-gcc-11.2.0-2022.06.10-x86_64-linux-ubuntu20.tar.gz export RISCV$HOME/riscv64-unknown-elf-gcc-11.2.0-2022.06.10 export PATH$RISCV/bin:$PATH # 验证关键特性 riscv64-unknown-elf-gcc --version # 应输出11.2.0 riscv64-unknown-elf-gcc -dumpspecs | grep atomic # 确认含atomic支持提示$RISCV/bin必须加入PATH且置于最前否则make时可能调用系统默认gcc导致静默失败。若后续编译报undefined reference to __atomic_fetch_add_4立即检查riscv64-unknown-elf-gcc -v输出中的--with-arch是否为rv64imacBenOS要求完整整数指令集。2.2 克隆、配置并编译MySBI理解config.h中三个决定性宏MySBI并非完整SBI实现而是聚焦于实验教学的精简版。其核心控制逻辑位于mysbi/include/config.h以下三个宏直接决定BenOS能否启动宏定义可选值作用说明实验建议值CONFIG_MYSBI_PLIC1/0是否启用PLIC中断控制器驱动。若设为0BenOS的timer中断将无法触发schedule()永远不执行1必开CONFIG_MYSBI_CLINT1/0是否启用CLINT定时器驱动。影响sbi_set_timer系统调用功能BenOS依赖此设置tick1必开CONFIG_MYSBI_DEBUG1/0是否启用串口调试打印。开启后SBI初始化阶段会在UART0输出[SBI] init start...等日志是定位hang点的第一线索1调试期必开编译命令需显式指定平台virt为QEMU标准虚拟平台cd mysbi make clean make PLATFORMvirt # 成功后生成 build/platform/virt/firmware/fw_dynamic.bin编译成功标志build/platform/virt/firmware/目录下存在fw_dynamic.bin约28KB且make V1输出中无warning: implicit declaration类错误。2.3 编译BenOS修改Makefile中的SBI固件路径与链接脚本BenOS的Makefile默认指向../opensbi/build/platform/qemu/firmware/fw_dynamic.bin需手动修正为MySBI路径。同时BenOS的链接脚本kernel.lds将SBI传递的DTB地址硬编码为0x80000000而QEMU-bios加载的fw_dynamic.bin实际被映射到0x80000000这会导致DTB覆盖SBI代码——这是新手最常翻车的内存布局冲突。修正步骤修改benos/Makefile第12行SBI_FW ? ../mysbi/build/platform/virt/firmware/fw_dynamic.bin修改benos/kernel.lds第9行将_dtb_start 0x80000000;改为_dtb_start 0x80200000;为SBI留出2MB空间cd benos make clean make # 成功后生成 kernel.bin约16KB和 kernel.elf含调试符号逻辑说明kernel.elf保留完整的符号表和段信息是GDB单步调试的必需品kernel.bin为纯二进制镜像供QEMU直接加载。二者必须由同一轮make生成否则地址偏移错位会导致gdb断点失效。3. 在QEMU中启动并调试用GDB实时观测SBI→OS的handover全过程3.1 启动QEMU并连接GDB关键参数解析与端口确认QEMU命令必须精确匹配MySBI/BenOS的内存布局假设。以下命令经实测在QEMU 7.2.0上稳定工作qemu-system-riscv64 \ -M virt \ -m 2G \ -bios ./mysbi/build/platform/virt/firmware/fw_dynamic.bin \ -kernel ./benos/kernel.bin \ -nographic \ -s -S \ -d in_asm,cpu_reset \ -D qemu.log参数含义详解-s -S开启GDB server默认端口1234并在第一条指令暂停这是捕获reset_vector的唯一方式-d in_asm,cpu_reset将CPU复位过程和每条执行指令输出到qemu.log用于事后比对GDB单步结果-bios指定MySBI固件QEMU将其加载至0x80000000-kernel指定BenOS镜像QEMU将其加载至0x80200000由kernel.lds中SECTIONS起始地址决定。注意若省略-nographicQEMU会尝试启动图形界面导致串口日志不可见若未加-SGDB连接时程序已运行错过最关键的SBI handover瞬间。3.2 GDB连接与断点设置从reset_vector到os_main的四层断点策略使用benos/kernel.elf而非.bin连接GDB才能解析符号riscv64-unknown-elf-gdb ./benos/kernel.elf (gdb) target remote :1234 (gdb) info registers mstatus # 确认初始mstatus为0x00001800MPPMMPIE0按执行顺序设置四类断点覆盖handover全链路断点位置命令触发时机调试价值reset_vectorb *0x80000000QEMU复位后第一条指令验证SBI固件是否正确加载sbi_initb sbi_initMySBI C初始化入口检查PLIC/CLINT驱动注册是否成功os_bootb os_bootSBI调用smode_switch跳转前最后一句查看a0(hartid)、a1(dtb)、a2(entry)寄存器值os_mainb os_mainBenOS第一条C语言函数确认handover完成可开始OS级调试(gdb) b *0x80000000 (gdb) b sbi_init (gdb) b os_boot (gdb) b os_main (gdb) c # 开始执行当停在os_boot时执行info registers a0 a1 a2应看到a0 0x0当前hart ida1 0x80100000DTB物理地址MySBI在fw_dynamic.bin末尾附加了设备树a2 0x80200000BenOS入口地址即kernel.bin加载地址若a1为0x0说明MySBI未正确生成DTB或地址计算错误——此时需检查mysbi/platform/virt/platform.c中platform_init函数内dtb_load_addr赋值。3.3 观察SBI系统调用拦截在handle_ecall中插入日志验证trap机制BenOS通过ecall触发SBI服务如SBI_SET_TIMER,SBI_CONSOLE_PUTCHAR。MySBI的trap处理链位于mysbi/lib/sbi/sbi_trap.c。为验证SBI是否真正接管ecall修改handle_ecall函数开头// mysbi/lib/sbi/sbi_trap.c 第42行附近 void handle_ecall(struct sbi_trap_regs *regs) { // 新增调试日志需确保uart_putc已初始化 uart_puts([SBI] ecall from ); uart_puthex(regs-epc); uart_puts(\n); unsigned long eid regs-a7; switch (eid) { case SBI_EXT_0_1_SET_TIMER: sbi_set_timer(regs-a0); break; // ... 其他case }重新编译MySBI后在GDB中执行c继续运行观察QEMU终端是否输出[SBI] ecall from 0x8020xxxx。若无输出说明uart_puts未初始化检查mysbi/platform/virt/platform.c中uart_init是否被调用或handle_ecall根本未触发检查mideleg寄存器是否设置了ECALL位csrw mideleg, 0x2。血泪经验曾有开发者因忘记在start.S中执行csrw mideleg, 0x2导致所有ecall直通到BenOS的trap_handlerSBI完全被绕过——此时GDB中b handle_ecall永不停下。4. 常见问题排查五类高频翻车现场与对应解法4.1 现象QEMU启动后黑屏无任何输出qemu.log显示cpu_reset: pc0x0000000000001000原因MySBI的fw_dynamic.bin未被正确加载至0x80000000QEMU回退到默认reset向量0x1000。根源在于mysbi/platform/virt/platform.c中platform_init函数未设置mem_size导致QEMU无法识别内存大小拒绝加载固件。解决打开mysbi/platform/virt/platform.c在platform_init函数开头添加// 强制声明内存大小为2GB与qemu -m 2G匹配 mem_size 0x80000000ULL; // 2GB 0x80000000重新编译MySBI并重试。4.2 现象GDB停在os_boot但info registers a1显示0x0BenOS启动后卡死原因MySBI未生成有效DTB或DTB地址未正确传递给BenOS。a1寄存器值由mysbi/platform/virt/platform.c中platform_get_dtb函数返回该函数依赖dtb_load_addr全局变量。解决检查mysbi/platform/virt/platform.c第102行// 确保此处为实际DTB加载地址而非0 extern char _dtb_start[]; unsigned long dtb_load_addr (unsigned long)_dtb_start;若_dtb_start未定义需在mysbi/platform/virt/Makefile中添加LDFLAGS -Ttext0x80000000 -Tdata0x80100000并重新编译整个MySBI。4.3 现象BenOS启动后能打印Hello World但timer中断永不触发schedule()不执行原因PLIC未使能或中断优先级配置错误。MySBI虽调用plic_enable但BenOS的mie寄存器未置位MEIEMachine External Interrupt Enable。解决在BenOS的kernel/start.S中call os_main前插入# 启用机器模式外部中断 li t0, 0x200 csrs mie, t0或在os_main函数开头添加C代码// benos/kernel/main.c void os_main(void) { // 启用外部中断 asm volatile (csrs mie, %0 :: r(0x200)); // ... 其余代码 }4.4 现象GDB连接后info registers显示mstatus0x00000000无法进入S-mode原因QEMU未启用S-mode支持。-M virt默认仅支持M-mode需显式添加-cpu rv64,x-strue,x-htrue参数启用S/H扩展。解决修正QEMU启动命令qemu-system-riscv64 \ -M virt \ -m 2G \ -cpu rv64,x-strue,x-htrue \ # 关键启用S-mode -bios ./mysbi/... \ # ... 其余参数4.5 现象修改MySBI代码后重新编译QEMU仍运行旧固件原因QEMU缓存了fw_dynamic.bin的inode或make clean未清除build/目录下的中间文件。解决执行彻底清理cd mysbi git clean -fdx # 删除所有未跟踪文件包括build/ make PLATFORMvirt并确认fw_dynamic.bin的修改时间戳更新。5. 进阶技巧用OpenOCDJTAG调试真实硬件HiFive1 Rev B并注入自定义SBI扩展5.1 OpenOCD配置与连接适配HiFive1 Rev B的专用.cfg文件MySBI与BenOS实验代码原生支持HiFive1 Rev B基于SiFive FE310-G002 SoC。需准备OpenOCD 0.12.0及配套JTAG调试器如FTDI FT2232H。关键配置文件hifive1-revb.cfg内容如下# hifive1-revb.cfg source [find interface/ftdi/digilent_jtag_smt2.cfg] transport select jtag set CHIPNAME hifive1 source [find target/shakti.cfg] # HiFive1 Rev B 特定内存映射 set _FLASH_START 0x20010000 set _FLASH_SIZE 0x00100000 set _RAM_START 0x80000000 set _RAM_SIZE 0x00004000 # 加载MySBI固件到SRAM0x80000000 $_TARGETNAME configure -event reset-init { echo Reset init: loading MySBI to SRAM load_image ./mysbi/build/platform/hifive1/firmware/fw_dynamic.bin $_RAM_START bin resume $_RAM_START }启动OpenOCDopenocd -f hifive1-revb.cfg -c init; reset halt此时GDB连接localhost:3333即可调试真实芯片monitor reset halt命令将强制复位并停在0x20010000FE310的ROM boot vector需手动load_image加载MySBI。5.2 在MySBI中添加自定义SBI扩展以SBI_CUSTOM_0x42为例MySBI预留了SBI_EXT_CUSTOM扩展接口。在mysbi/include/sbi/sbi_ecall.h中定义新扩展号// mysbi/include/sbi/sbi_ecall.h #define SBI_EXT_CUSTOM_0X42 0x42在mysbi/lib/sbi/sbi_ecall.c中注册handler// mysbi/lib/sbi/sbi_ecall.c static int sbi_custom_0x42_handler(struct sbi_trap_regs *regs) { // 自定义逻辑例如读取GPIO状态 volatile uint32_t *gpio_in (uint32_t*)0x10012000; // HiFive1 GPIO base regs-a0 *gpio_in; // 返回GPIO输入值 return 0; } // 在sbi_ecall_handler函数中添加 case SBI_EXT_CUSTOM_0X42: ret sbi_custom_0x42_handler(regs); break;BenOS中调用方式// benos/kernel/gpio_test.c static inline long sbi_custom_0x42(void) { register long a7 asm(a7) SBI_EXT_CUSTOM_0X42; register long a0 asm(a0) 0; asm volatile (ecall : r(a0) : r(a7) : a1,a2,a3,a4,a5,a6); return a0; } void test_gpio(void) { long val sbi_custom_0x42(); printk(GPIO input: 0x%lx\n, val); // 将打印实际GPIO电平 }参数说明SBI_EXT_CUSTOM_0X42是用户自定义扩展号范围0x08000000-0x7FFFFFFFa0作为返回值寄存器a1-a6可传递最多6个参数。此机制允许BenOS直接访问硬件外设无需修改Linux内核驱动模型。5.3 性能验证用SBI timer测量BenOS上下文切换开销MySBI的SBI_SET_TIMER精度达微秒级。可在BenOS的schedule()函数中插入时间戳对比// benos/kernel/schedule.c extern unsigned long sbi_get_time(void); // MySBI提供的时间获取函数 void schedule(void) { unsigned long start sbi_get_time(); // 原有上下文切换逻辑... switch_to(next_task); unsigned long end sbi_get_time(); printk(ctx switch: %lu ns\n, (end - start) * 10); // 假设timer频率10MHz }实测HiFive1 Rev B上任务切换开销约12.7μs含保存/恢复32个通用寄存器远低于Linux的150μs——这印证了轻量级SBI裸机OS在实时性上的优势。我坚持在每次硬件调试前先用QEMU复现问题因为QEMU的-d in_asm能暴露寄存器级错误而真实芯片的JTAG往往只显示“halted at unknown address”。这个习惯让我少走了三个月弯路。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

YOLOv10舌象检测与DeepSeek诊断分析:从数据标注到工程落地

YOLOv10舌象检测与DeepSeek诊断分析:从数据标注到工程落地

1. 舌象检测的特殊性:这个任务和通用目标检测根本不是一回事1.1 舌象数据的三重难点做舌象检测之前,我以为它就是继承了一个普通单类目标检测任务。把任务拆开来看,你会发现问题远不止"把舌头框出来"这么简单。第一重难点是颜色即特…

2026/10/18 14:47:45 阅读更多 →
AI辅助论文写作全攻略:专科生如何选对工具避开坑

AI辅助论文写作全攻略:专科生如何选对工具避开坑

每年三四月,我的朋友圈里就开始涌现一批“论文焦虑”患者,而我这两年被问得最多的一个问题,就是“有没有靠谱的AI论文网站可以照着用”。专科生写毕业论文这件事,难度其实一点都不比本科低:时间更紧、实习任务压身、学…

2026/10/18 14:47:45 阅读更多 →
JQuickExcel 批量导入:用 importDataInBatch 控制大文件消费边界

JQuickExcel 批量导入:用 importDataInBatch 控制大文件消费边界

JQuickExcel 批量导入:用 importDataInBatch 控制大文件消费边界 tags: #JQuickExcel #JavaExcel #开源 #POI #Excel工具 更多示例: JQuick-Excel 官网示例 https://www.jquick.org/jquick-excel/#demo-formulas0005 简介 我处理大 Excel 导入时,最先…

2026/10/18 14:47:45 阅读更多 →

最新新闻

开源计费系统NetBilling落地实践:核心链路、费率配置与避坑指南

开源计费系统NetBilling落地实践:核心链路、费率配置与避坑指南

简介:NetBilling是一个面向网络服务提供商、电信运营商及需要精确计量收费场景的开源流量计费系统,围绕区域流量核算提供灵活计费策略,支持按地区、数据量、时间、用户类型等维度定制资费。资源包共包含三十三个文件,整体大小仅50…

2026/10/18 15:41:11 阅读更多 →
力控实时数据库PSAPI SDK开发指南:从连接到读写与历史检索

力控实时数据库PSAPI SDK开发指南:从连接到读写与历史检索

简介:psAPISDK6.0.1.9_2是力控pspace实时数据库配套的接口开发SDK,面向使用C# .NET Framework 4.0的工业自动化程序开发者,用于解决监控系统中实时数据读写、点表管理、报警事件处理与用户权限控制等集成问题。该压缩包共49个文件&#xff0c…

2026/10/18 15:41:11 阅读更多 →
MLX-Swift零转换加载揭秘:SenseNova-U1.5-8B-MoT-8step-4bit在Apple Silicon上的运行时实现原理

MLX-Swift零转换加载揭秘:SenseNova-U1.5-8B-MoT-8step-4bit在Apple Silicon上的运行时实现原理

人工智能大模型多模态媒体生成模型量化 【免费下载链接】SenseNova-U1.5-8B-MoT-8step-4bit 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/SenseNova-U1.5-8B-MoT-8step-4bit 点击查看 免费下载 SenseNova-U1.5-8B-MoT-8step-4bit 是商汤&#xff0…

2026/10/18 15:41:11 阅读更多 →
App内测分发方案与实践:从 APK/IPA 到二维码分发

App内测分发方案与实践:从 APK/IPA 到二维码分发

摘要:本文从技术实践角度,梳理 Android / iOS 内测分发的常见方式与优劣,重点介绍第三方分发平台的一般能力,并以海哈游分发为例演示上传 APK/IPA、生成短链与二维码、设置访问控制、分享给测试人员以及查看下载数据的完整流程&am…

2026/10/18 15:41:11 阅读更多 →
DeepSeek-V4-Flash-nvfp4-DSpark 权重转换指南:convert.py 多卡切分与 MXFP4→NVFP4 无损 Cast 完整教程

DeepSeek-V4-Flash-nvfp4-DSpark 权重转换指南:convert.py 多卡切分与 MXFP4→NVFP4 无损 Cast 完整教程

【免费下载链接】DeepSeek-V4-Flash-nvfp4-DSpark 项目地址: https://ai.gitcode.com/hf_mirrors/nvidia/DeepSeek-V4-Flash-nvfp4-DSpark 点击查看 免费下载 📦 DeepSeek-V4-Flash-nvfp4-DSpark 是 NVIDIA 基于 Model Optimizer 量化(NVFP4…

2026/10/18 15:41:11 阅读更多 →
SOMA-X输入输出API参考:身份系数、姿态参数与网格输出的张量形状及单位详解

SOMA-X输入输出API参考:身份系数、姿态参数与网格输出的张量形状及单位详解

人工智能图形学计算机视觉数字人 【免费下载链接】SOMA-X 项目地址: https://ai.gitcode.com/hf_mirrors/nvidia/SOMA-X 点击查看 免费下载 SOMA-X 是 NVIDIA 开源的统一参数化人体模型(Unifying Parametric Human Body Models),…

2026/10/18 15:40:10 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →