Linux SuperH (SH) 架构技术指南:Store Queue 存储队列、寄存器组、新板卡移植与 Machine/总线接口

发布时间:2026/9/13 18:15:16
Linux SuperH (SH) 架构技术指南:Store Queue 存储队列、寄存器组、新板卡移植与 Machine/总线接口 Linux SuperH (SH) 架构技术指南Store Queue 存储队列、寄存器组、新板卡移植与 Machine/总线接口【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本文基于 Linux 内核仓库中的 SuperH Interfaces Guide 及其 toctree 关联的 DeviceTree 启动说明、新板卡移植指南、寄存器组使用说明并结合 SH-4 Store Queue 管理模块、Dreamcast AICA RTC 驱动、SH-X3 ILSEL 中断管理 与 Maple 总线核心驱动 的实际源码进行展开。读完本文后你将掌握 SH-4 存储队列Store Queue的 remap/flush 完整 API 及底层实现机制、SH-3/SH-4 寄存器组SR.RB banking在内核中的具体用途、向 Linux SH 移植新板卡的完整步骤目录结构、Kconfig、defconfig 与构建命令以及 Dreamcast Maple 总线、AICA RTC 等机器特定接口的实现细节。1. 文档体系与总体结构Documentation/arch/sh/index.rst 是 Linux SHSuperH架构文档的入口作者为 Paul Mundt。其结构由四个部分组成toctree 子文档booting.rstDeviceTree 启动、new-machine.rst新板卡移植、register-banks.rst寄存器组、features.rst功能特性列表Memory Management / SH-4 / Store Queue API通过kernel-doc直接导出 arch/sh/kernel/cpu/sh4/sq.c 的函数文档Machine Specific Interfaces导出 mach-dreamcast 的 AICA RTC 与 mach-x3proto 的 ILSEL 管理 两个机器级接口的文档Busses / Maple导出 drivers/sh/maple/maple.c 的 Maple 总线 API 文档。值得注意的一点是 features.rst 的内容仅有一行kernel-feat:: features sh它并不包含正文而是由 Sphinx 构建系统在执行kernel-feat扩展时扫描 SH 架构 Kconfig 后动态生成全部特性清单。这意味着 SH 架构支持的功能全集CPU 型号、板卡选项、MMU/无 MMU 等应始终以构建生成的文档为准这也是判断某个 SH 配置项是否存在的可靠途径。2. SH 平台启动流程DeviceTree 约定booting.rst 明确了 SH 平台的现代启动契约支持 Device-tree 的 SH 引导程序bootloader必须将 device tree blob 的物理地址放在 r4 寄存器中。由此衍生出三条关键约束兼容引导程序将 DTB 物理地址放入 r4是标准路径内核以CONFIG_SH_DEVICE_TREE启用设备树解析老式引导程序不保证任何初始寄存器状态因此要与旧 bootloader 互操作的内核必须内建 DTBbuiltin DTB或者选择一个不使用设备树的 legacy 板卡选项文档同时指出非设备树的 legacy 板卡支持正在被逐步淘汰设备树是方向。从当前源码树看这一演进已经落地arch/sh/configs/ 下提供了ap325rxa_defconfig、dreamcast_defconfig、ecovec24_defconfig、edosk7705_defconfig、edosk7760_defconfig、apsh4a3a_defconfig、apsh4ad0a_defconfig等一整套 defconfig而 arch/sh/Makefile 中默认KBUILD_DEFCONFIG : shx3_defconfig即默认构建目标就是设备树驱动的 SH-X3 平台。3. 寄存器组Register BanksSR.RB 的内核级用法register-banks.rst 专门讲解内核中对 SH 寄存器组的使用规则这是阅读 SH 架构汇编代码异常入口、中断框架的前置知识。3.1 硬件背景只有 r0–r7 被分组SH-3 与 SH-4 家族传统上带有一个部分寄存器组由状态寄存器SR.RB位选择当前活跃组且只有r0–r7是 banked 的。其他 CPU 家族要么有更完整的分组能力要么完全没有。在 SR.RB banking 模式下若SR.RB指向目标组banked 寄存器直接映射为 r0–r7访问处于另一组上下文时仍可用ldc/stc指令以r0_bank–r7_bank名称访问对方组的寄存器编写使用这些 banked 寄存器的代码时必须时刻留意当前 SR.RB 取值用户态无法触碰 bank1 的值因此内核可以把 bank1 的寄存器当作高质量的私有暂存寄存器使用。3.2 内核对 bank1 各寄存器的实际分配文档列出了内核当前占用的寄存器这些约定在内核 SH 架构代码异常向量、do_IRQ()等中是硬约束Bank1 寄存器别名用途r0_bank,r1_bankk0, k1异常处理时的暂存寄存器scratch registersr2_bank—跟踪 EXPEVT/INTEVT 码供do_IRQ()等按中断异常向量跳转表偏移做 IRQ 映射r6_bank—全局中断掩码SR.IMASK 中断处理路径用它设置中断优先级对应local_irq_enable()一类操作r7_bankcurrent保存当前任务指针current理解这张表的价值在于当你在 SH 汇编路径中看到一个无名的 banked 寄存器读写可以先按上述分配对号入座避免误判为通用寄存器而破坏其隐式语义。4. SH-4 Store Queue内存管理与高性能 DMA 映射4.1 什么是 Store QueueStore QueueSQ是 SH-4 CPU 集成的写缓冲/预取结构主机侧对 SQ 映射区间的普通存储访问会被缓冲在 SQ 中再异步写入目标物理地址通常是帧缓冲、外设 DMA 缓冲区从而让 CPU 不必等待慢速总线事务。Linux SH 为此提供了 arch/sh/kernel/cpu/sh4/sq.c 中SH-4 integrated Store Queues 通用管理 API该模块以module_init(sq_api_init)形式注册启动时打印sq: Registering store queue API.。4.2 核心 API 三个函数sq_remap(phys, size, name, prot)—— 把物理地址经 SQ 映射返回可用的 SQ 虚拟地址。其内核文档注释与实现要点参数phys物理地址、size长度、name发起映射的用户名启动时及通过 sysfs 记录、prot保护位实现sq.c#L143-L197中有多层防护拒绝size 0以及phys size - 1回绕end phys返回-EINVAL拒绝把普通内存拉进 SQphys virt_to_phys(high_memory)直接返回-EINVAL防止普通内存被当作 SQ 目标重映射物理地址按页对齐phys PAGE_MASK长度向上页对齐用bitmap_find_free_region(sq_bitmap, 0x04000000 PAGE_SHIFT, get_order(size))在 SQ 地址空间0x0400_0000 页粒度位图中分配页得到map-sq_addr P4SEG_STORE_QUE (page PAGE_SHIFT)成功时打印sqremap: name [N pages] va 0x... pa 0x...便于调试。映射建立__sq_remapsq.c#L101-L130分两种情况有 MMUCONFIG_MMU调用__get_vm_area_caller()在 SQ 地址范围内申请VM_IOREMAP虚拟区再用ioremap_page_range()把该 VA 段映射到目标物理地址无 MMU直接把每个队列的 QACR 寄存器写入物理地址的对应高位((addr 26) 2) 0x1c分别落到SQ_QACR0/SQ_QACR1。sq_flush_range(start, len)—— 线性地冲刷start到start len的 SQ 内容。实现sq.c#L57-L67非常有代表性void sq_flush_range(unsigned long start, unsigned int len) { unsigned long *sq (unsigned long *)start; /* Flush the queues */ for (len 5; len--; sq 8) prefetchw(sq); /* Wait for completion */ store_queue_barrier(); }它以 32 字节len 5、sq 8为粒度发起prefetchw然后通过store_queue_barrier()等待完成——该屏障宏sq.c#L42-L47先读P4SEG_STORE_QUE状态寄存器再写 0 到其 0 与 8 两个控制寄存器从而强制排空队列。sq_unmap(vaddr)—— 释放先前由sq_remap()建立的映射按sq_addr在映射链表上查找找不到会打印bad store queue address释放位图区间MMU 情况下调用remove_vm_area()拆掉 VMA最后从链表移除并释放sq_mapping对象。文档注释说明它同时释放了内核页表中的 PTE 并丢弃 UTLB 翻译。三个函数均通过EXPORT_SYMBOL导出供模块态使用。4.3 用户态/sysfs 接口per-CPU 的mapping属性sq.c#L247-L370 实现了刻意复杂的 sysfs 接口源码注释自嘲为 Needlessly complex sysfs interface通过subsys_interface挂在cpu_subsys上为每个 CPU在/sys/devices/system/cpu/cpuN/sq/下创建一个mapping属性文件权限 0644见__ATTR(mapping, 0644, ...)读mapping_show逐行输出sq_addr 起始-结束 [物理地址]: 名字即当前全部 SQ 映射的清单写mapping_store格式为base lensscanf(buf, %lx %lx, ...)。len非零时以名字Userspace、PAGE_SHARED权限调用sq_remap(base, len, ...)len为 0 则调用sq_unmap(base)。这为调试 SQ 驱动提供了不改代码即可创建/拆除映射的手段。4.4 初始化与资源边界sq_api_init()sq.c#L372-L399创建store_queue_cacheslab 缓存、按0x04000000 PAGE_SHIFT个页分配位图并注册 subsys 接口模块作者署名为 Paul Mundt 与 M. R. Brown。从位图尺寸可以确认SQ 可分配的地址空间总预算为64 MiB0x0400_0000。5. 机器特定接口Machine Specific Interfaces5.1 mach-dreamcastAICA RTC 的时间服务index.rst 用:internal:方式导出 arch/sh/boards/mach-dreamcast/rtc.c 的 kernel-doc对应 Dreamcast 主板上 AICA 芯片的 RTC。实现要点源码注释与代码直接给出纪元修正AICA RTC 的 Epoch 是 1950-01-01因此读取时要减去 20 年秒、写入时加上 20 年换算到 Unix Epoch代码用TWENTY_YEARS ((20 * 365LU 5) * 86400)含 5 个闰年日32 位秒计数器由两个 16 位寄存器组成AICA_RTC_SECS_H 0xa0710000、AICA_RTC_SECS_L 0xa0710004抗撕裂读aica_rtc_gettimeofday()连续读两遍高低位组合值do { ... } while (val1 ! val2)直到两次读取一致防止在 0xFFFF - 0x0000 跨越瞬间读到撕裂值aica_rtc_settimeofday()写后同样回读校验一致性通过rtc_class_opsread_time/set_time注册到通用 RTC 框架aica_time_init()用platform_device_register_data(NULL, rtc-generic, -1, ...)注册rtc-generic平台设备由arch_initcall启动。这是机器相关硬件 通用内核框架的教科书式组合板级代码只提供硬件操作函数时间子系统rtc_time64_to_tm等全部复用通用实现。5.2 mach-x3protoILSEL 中断源选择管理arch/sh/boards/mach-x3proto/ilsel.c 为 SH-X3 原型板提供 ILSELInterrupt Level Select辅助例程SH-X3 的 15 级中断源选择寄存器布局源码注释给出ILSEL0 - 0xb8100004 [ Levels 1 - 4 ] ILSEL1 - 0xb8100006 [ Levels 5 - 8 ] ILSEL2 - 0xb8100008 [ Levels 9 - 12 ] ILSEL3 - 0xb810000a [ Levels 13 - 15 ]每个 16 位寄存器内 4 个 4-bit 字段各选一个中断源。三个导出 API 的内核文档EXPORT_SYMBOL_GPLilsel_enable(set)把给定非别名ILSEL 源set ILSEL_KEY挂到当前可用的最高中断级别上调用方应注意按降序中断级别组织调用点。别名 FPGA 与外部板 IRQ 必须用ilsel_enable_fixed()否则返回-EINVAL。实现上用find_first_zero_bittest_and_set_bit的自旋式抢位分配ilsel_level_map返回值是可直接用作 IRQ 号的 bit 位置ilsel_enable_fixed(set, level)把 ILSEL 源固定在指定级别1–15用于级别预留以及只存在于特殊 ILSEL# 上的别名源若该级别已被占用返回-EBUSYilsel_disable(irq)清掉对应 4-bit 字段并释放级别位。源码注释特别解释了一个设计IRQ 号与中断级别是反向编号的因此ilsel_level_map按从最高级别往下组织 bit 位保证 bit 位置与 IRQ 号 1:1 对应ilsel_enable*()的返回值可以直接用于后续的禁用路径记账。地址/移位换算由mk_ilsel_addr()/mk_ilsel_shift()完成ILSEL_BASE ((ILSEL_LEVELS - bit - 1) 1) ~0x1。6. 移植新板卡到 Linux SHnew-machine 指南精读new-machine.rst作者 Paul Mundt给出了在 2.5/2.6 系列内核上添加新板卡的完整流程并顺带交代了相对 2.4 的重大结构变化。下面按目录结构 → 必备代码 → 构建系统接线 → defconfig的顺序完整继承其要点。6.1 新的目录结构2.4 时代大部分板级代码直接放在arch/sh/kernel/板级头文件堆在include/asm-sh/新内核按板型、伴晶companion chip类型、CPU 类型拆分板级代码arch/sh/boards/board/板级头文件include/asm-sh/board/伴晶代码arch/sh/cchips/chip/subchip/例如hd6446x/hd64461其头文件同样按include/asm-sh/chip/组织CPU 家族抽象arch/sh/kernel/cpu/sh2|sh3|sh4/放各家族的通用文件arch/sh/mm/同样按 CPU 家族拆分让每个家族拥有自己的 cache/tlb 函数头文件位于include/asm-sh/cpu-sh2|sh3|sh4/。文档同时提醒CPU 子类型subtype并不被抽象仍需由 CPU 家族代码自行处理。6.2 每个板卡必须提供的代码每个板卡至少需要提供get_system_type()与platform_setup()两个定义。文档给出的虚拟板卡 vapor示例/* * arch/sh/boards/vapor/setup.c - Setup code for imaginary board */ #include linux/init.h const char *get_system_type(void) { return FooTech Vaporboard; } int __init platform_setup(void) { /* * If our hardware actually existed, we would do real * setup here. Though its also sane to leave this empty * if theres no real init work that has to be done for * this board. */ /* Start-up imaginary PCI ... */ /* And whatever else ... */ return 0; }6.3 machvec机器的能力向量板卡还需通过 machvecmachine vector接入内核。machvec 函数分为几类I/O 内存函数inb 等与 PCI/主存函数readb 等I/O 映射函数ioport_map、ioport_unmap等heartbeat 函数PCI 与 IRQ 初始化例程一致性分配器consistent allocator用于需要从板级特殊 SRAM 中分配 DMA 句柄的板卡。原文提醒machvec 的函数随时间增删务必以include/asm-sh/machvec.h的当前状态为准。需要说明的是从当前源码树核实include/asm-sh/machvec.h已不存在即 machvec 机制已从当前树中移除SH 平台的能力描述已迁移到设备树与 platform 设备体系。因此本节内容应作为理解历史板级代码以及阅读老补丁集的背景知识新板卡移植的实际接入点请参考第 2 节的 DeviceTree 约定与 arch/sh/Kconfig 中的板卡选项。其余移植步骤文档描述如下若板级定义很精简绝大多数板卡如此一个板级头文件即可。新建include/asm-sh/vapor.h声明以机器名为前缀的板级 IO 函数原型如vapor_inb。这些原型由__IO_PREFIX宏自动生成#define __IO_PREFIX vapor #include asm/io_generic.h文档还要求仍在用旧式io.h的板卡应整体删除旧文件、切换到新模式。在板级setup.c中加入机器向量定义最低限度为struct sh_machine_vector mv_vapor __initmv { .mv_name vapor, }; ALIAS_MV(vapor)最后添加arch/sh/boards/vapor/io.c实现板级 IO 函数数量值得的话。文档还指出内核会在启动时自动为未定义指针包上通用例程因为 machvec 函数指针在树中被无条件引用不同板卡差距悬殊——有的 machvec 极其稀疏如 dreamcast 与 sh03有的几乎要定义全部如 rts7751r2d。对于板族board family更合适的做法是在arch/sh/boards/下建公共目录、再按家族成员建子目录Solution Engine 与 hp6xx 就是这种模式。6.4 接入构建系统Kconfig 项在 arch/sh/Kconfig 的 System type 菜单下添加config SH_VAPOR bool Vapor help select Vapor if configuring for a FooTech Vaporboard.machdir 接线所有板卡都需要machdir-y条目arch/sh/Makefile条目名必须是arch/sh/boards下的目录名若位于子目录需逐级列出父目录。示例machdir-$(CONFIG_SH_VAPOR) vapor若include/asm-sh/下的目录名与板目录不同名常见于同族多板需要用incdir-y叠加显式追加原文建议参考 Solution Engine 与 hp6xx 的既有写法。mach-types在 arch/sh/tools/mach-types 文件末尾追加一行即可在通用代码中使用隐式板型判断/* Make sure were on the FooTech Vaporboard */ if (!mach_is_vapor()) return -ENODEV;注意mach_is_boardname()会被隐式强制小写即使 mach-types 条目本身是大写。defconfig为新板卡提供 defconfig假设为arch/sh/configs/vapor_defconfig别人拿到该板卡时可直接参考。一旦 defconfig 就位它自动成为构建目标并出现在make help输出中形如Architecture specific targets (sh): zImage Compressed kernel image (arch/sh/boot/zImage) adx_defconfig Build for adx cqreek_defconfig Build for cqreek dreamcast_defconfig Build for dreamcast ... vapor_defconfig Build for vapor 随后即可执行$ make ARCHsh CROSS_COMPILEsh4-linux- vapor_defconfig vmlinux该命令会拷贝该板卡的 defconfig、跑oldconfig对创建以来的新选项逐一询问随即进入新板卡内核的正常构建流程。当前树中可直接参考的真实示例包括 arch/sh/configs/dreamcast_defconfig、arch/sh/configs/ecovec24_defconfig、arch/sh/configs/edosk7760_defconfig 等。7. 总线MapleDreamcast 外设总线index.rst 的 Busses / Maple 一节通过kernel-doc导出 drivers/sh/maple/maple.c。Maple 是 Dreamcast 主机的外设总线该驱动是模块MODULE_AUTHOR为 Adrian McMenamin描述 Maple bus driver for Dreamcast。从源码可确认的核心 API 与机制maple_driver_register(drv)/maple_driver_unregister(drv)把maple_driver挂到私有maple_bus_type总线上driver_register()之后函数 ID 匹配的设备会被自动 probe——即典型的内核总线模型bus_type device driver 三方匹配maple_add_packet(mdev, function, command, length, data)向某设备的 Maple 队列追加一条指令。32 位字计数长度function以cpu_to_be32()大端化写入发送缓冲首字Maple 线序为大端随后加锁挂入maple_waitq等待发送maple_getcond_callback(dev, callback, interval, function)为周期查询类设备如控制器摇杆状态注册回调interval以 jiffies 为单位function为大端函数码DMA 与 VBLANK 触发maple_dma_reset()揭示了 Maple 系统寄存器的位定义源码注释位 31–16 为超时20ns 单位、位 12 硬触发置 0 则持续响应 VBLANK、位 9–8 速率00 2 Mbps01 1 Mbps、位 3–0 为 VBLANK 到 DMA 启动的延迟1.3ms 单位最大 11。驱动把MAPLE_TRIGTYPE置 1 使用 VBLANK 硬件触发并把发送缓冲物理地址写入MAPLE_DMAADDR后使能设备释放maple_release_device()释放mapleq队列与其 recvbuf体现 Maple 设备基础单元 从属设备的端口树模型subdevice_map[MAPLE_PORTS]、baseunits[MAPLE_PORTS]等结构。8. 小结如何使用这套文档与代码查 API 文档SH 架构的机器级/总线级 API 文档不单独成文而是内嵌在源码的 kernel-doc 注释中由 index.rst 以kernel-doc::指令聚合导出。想查某个 SH 特定函数如sq_remap、ilsel_enable、maple_add_packet直接读对应源码文件中的 doc 注释即可构建后的 Sphinx 文档会将其整理进 SuperH Interfaces Guide移植板卡以第 2 节 DeviceTree 启动约定为前提按第 6 节的目录、Kconfig、machdir-y/incdir-y、mach-types、defconfig 五步接线最后用make ARCHsh CROSS_COMPILE... board_defconfig vmlinux验证构建深入机制Store Queue 的 64MiB 地址空间位图分配、per-CPU sysfs 接口第 4 节SR.RB bank1 的四项内核占用第 3 节AICA RTC 的 1950 纪元与抗撕裂读写第 5.1 节Maple 的 VBLANK 触发 DMA 位定义第 7 节都给出了可直接核对的源码位置便于进一步追读。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询