PMON 2K0300 地址空间分布完整分析
一、地址空间总览
PMON 运行在 LoongArch 架构上,使用 64 位虚拟地址,高 16 位决定访问属性:
┌─────────────────────────────────────────────────────────────────────────────┐
│ LoongArch 64 位地址空间布局 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 0x0000_0000_0000_0000 ┌─────────────────────────────────────────────────┐ │
│ │ 用户态地址空间 (KUSEG) │ │
│ │ USRTEXT: 0x00400000 (用户代码起始) │ │
│ │ USRSTACK: 0x80000000 (用户栈顶) │ │
│ 0x7FFF_FFFF_FFFF_FFFF ├─────────────────────────────────────────────────┤ │
│ │ 非缓存内存 (UNCACHED) │ │
│ 0x8000_0000_0000_0000 │ PHYS_TO_UNCACHED(x) = x | 0x8000... │ │
│ │ 用于设备寄存器、DMA 缓冲区 │ │
│ 0x8FFF_FFFF_FFFF_FFFF ├─────────────────────────────────────────────────┤ │
│ │ 缓存内存 (CACHED) │ │
│ 0x9000_0000_0000_0000 │ PHYS_TO_CACHED(x) = x | 0x9000... │ │
│ │ 用于普通内存访问 │ │
│ 0x9FFF_FFFF_FFFF_FFFF ├─────────────────────────────────────────────────┤ │
│ │ 保留/其他 │ │
│ 0xFFFF_FFFF_FFFF_FFFF └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
二、地址空间核心宏定义 (cpu.h)
// cpu.h 中的地址空间定义
#define KUSEG_ADDR 0x0 // 用户段
#define CACHED_MEMORY_ADDR 0x9000000000000000ULL // 缓存内存基址
#define UNCACHED_MEMORY_ADDR 0x8000000000000000ULL // 非缓存内存基址
#define MAX_MEM_ADDR PHYS_TO_UNCACHED(0x1e000000) // 最大内存地址
#define RESERVED_ADDR PHYS_TO_UNCACHED(0x1fc80000) // 保留地址
// 地址转换宏
#define IS_CACHED_ADDR(x) (!!(((x) & 0xff00000000000000ULL) == CACHED_MEMORY_ADDR))
#ifndef _LOCORE
#define PHYS_TO_CACHED(x) ((unsigned long long)(x) | CACHED_MEMORY_ADDR)
#define PHYS_TO_UNCACHED(x) ((unsigned long long)(x) | UNCACHED_MEMORY_ADDR)
#define CACHED_TO_UNCACHED(x) (PHYS_TO_UNCACHED(VA_TO_PHYS(x)))
#define UNCACHED_TO_CACHED(x) (PHYS_TO_CACHED(VA_TO_PHYS(x)))
#define VA_TO_PHYS(x) ((unsigned long long)(x) & 0xffffffffffffULL)
#else
// 汇编版本
#define PHYS_TO_CACHED(x) ((x) | CACHED_MEMORY_ADDR)
#define PHYS_TO_UNCACHED(x) ((x) | UNCACHED_MEMORY_ADDR)
#define VA_TO_PHYS(x) ((x) & 0xffffffffffff)
#endif
三、物理地址空间分布 (bonito.h, ls2k300.h)
3.1 物理地址总览
| 地址范围 | 大小 | 用途 |
|----------|------|------|
| 0x0000_0000 - 0x0FFF_FFFF | 256MB | 系统内存(低端) |
| 0x1000_0000 - 0x1BFF_FFFF | 192MB | 系统内存(高端) |
| 0x1C00_0000 - 0x1CFF_FFFF | 16MB | SPI Flash (PMON 固件) |
| 0x1D00_0000 - 0x1DFF_FFFF | 16MB | 保留 |
| 0x1E00_0000 - 0x1EFF_FFFF | 16MB | LIO 内存窗口 |
| 0x1F00_0000 - 0x1FDF_FFFF | 14MB | 设备寄存器 |
| 0x1FE0_0000 - 0x1FEF_FFFF | 1MB | SoC 内部寄存器 |
| 0x1FF0_0000 - 0x1FFF_FFFF | 1MB | 外设寄存器 |
3.2 Flash 内部布局
// bonito.h
#define BONITO_FLASH_BASE PHYS_TO_UNCACHED(0x1c000000)
#define BONITO_FLASH_SIZE 0x100000
// NVRAM 环境变量区域
#define NVRAM_OFFS 0x000ff000 // 环境变量偏移
#define NVRAM_SECSIZE 500 // 环境变量大小
// DTB 设备树区域
#define DTB_SIZE 0x4000 // 16KB (2K300 为 0x5000)
#define DTB_OFFS (NVRAM_OFFS - DTB_SIZE)
// 内存信息存储
#define DIMM_INFO_IN_FLASH_OFFS (PHYS_TO_UNCACHED(0x1c000000) + DTB_OFFS - 0x1000)
#define SMBIOS_INFO_IN_SDRAM_OFFS PHYS_TO_UNCACHED(0xfffc000)
Flash 详细布局:
0x1C00_0000 ┌─────────────────────────────────────────────┐
│ PMON 代码 (.text, .rodata, .data) │
│ (从 _start 到 _edata) │
│ │
│ ~ 800KB - 1MB │
│ │
0x1C0F_E000 ├─────────────────────────────────────────────┤ ← DTB_OFFS
│ DTB 设备树 (16KB/20KB) │
0x1C0F_F000 ├─────────────────────────────────────────────┤ ← NVRAM_OFFS
│ NVRAM 环境变量 (500 字节) │
0x1C0F_F500 ├─────────────────────────────────────────────┤
│ 保留 │
0x1C0F_FFFF └─────────────────────────────────────────────┘
四、外设寄存器地址映射
4.1 2K300 外设寄存器 (ls2k300.h)
// 芯片配置寄存器
#define LS2K300_GENERAL_CFG0 0x16000100 // 芯片配置0
#define LS2K300_GENERAL_CFG1 0x16000104 // 芯片配置1
#define LS2K300_GENERAL_CFG2 0x16000108 // 芯片配置2
#define LS2K300_GENERAL_CFG3 0x1600010c // 缓存一致性配置
#define LS2K300_GENERAL_CFG4 0x16000110 // SPI PAD 配置
#define LS2K300_GENERAL_CFG5 0x16000114 // 芯片配置5
#define LS2K300_SAMPLE_CFG0 0x16000120 // 采样配置0
#define LS2K300_CHIP_HPT_LO 0x16000130 // HPET 低32位
#define LS2K300_CHIP_HPT_HI 0x16000134 // HPET 高32位
// GPIO 寄存器
#define LS2K300_GPIO_MULTI_CFG 0x16000490 // GPIO 复用配置
#define LS2K300_GPIO_BASE 0x16104000 // GPIO 基址
#define LS2K300_GPIO_BIT_OEN 0x16104000 // GPIO 输出使能
#define LS2K300_GPIO_BIT_O 0x16104010 // GPIO 输出值
#define LS2K300_GPIO_BIT_I 0x16104020 // GPIO 输入值
// USB 控制器
#define LS2K300_OHCI_BASE 0x16040000 // OHCI USB 1.1
#define LS2K300_EHCI_BASE 0x16080000 // EHCI USB 2.0
// 显示控制器
#define LS2K300_DC_BASE 0x16090000 // DC 基址
// SPI 控制器
#define LS2K300_SPI0_BASE 0x16010000 // SPI0
#define LS2K300_SPI1_BASE 0x16018000 // SPI1
#define LS2K300_SPI2_BASE 0x1610c000 // SPI2
#define LS2K300_SPI3_BASE 0x1610e000 // SPI3
// UART 控制器
#define LS2K300_UART0_REG_BASE 0x16100000 // UART0
#define LS2K300_UART1_REG_BASE 0x16100400 // UART1
#define LS2K300_UART2_REG_BASE 0x16100800 // UART2 (调试串口)
#define LS2K300_UART3_REG_BASE 0x16100c00 // UART3
#define LS2K300_UART4_REG_BASE 0x16101000 // UART4
#define LS2K300_UART5_REG_BASE 0x16101400 // UART5
#define LS2K300_UART6_REG_BASE 0x16101800 // UART6
#define LS2K300_UART7_REG_BASE 0x16101c00 // UART7
#define LS2K300_UART8_REG_BASE 0x16102000 // UART8
#define LS2K300_UART9_REG_BASE 0x16102400 // UART9
// I2C 控制器
#define LS2K300_I2C0_REG_BASE 0x16108000 // I2C0
#define LS2K300_I2C1_REG_BASE 0x16109000 // I2C1
// SDIO 控制器
#define LS2K300_SDIO0_BASE 0x16140000 // SDIO0
#define LS2K300_SDIO1_BASE 0x16148000 // SDIO1
// 定时器
#define LS2K300_HPET0_BASE 0x16120000 // HPET0
#define LS2K300_HPET0_PERIOD 0x16120004 // HPET0 周期
#define LS2K300_HPET0_CONF 0x16120010 // HPET0 配置
#define LS2K300_HPET0_MAIN 0x161200f0 // HPET0 主计数器
// RTC
#define LS2K300_RTC_REG_BASE 0x16128000 // RTC 基址
#define LS2K300_TOY_READ0_REG 0x1612802c // TOY 读寄存器0
#define LS2K300_TOY_READ1_REG 0x16128030 // TOY 读寄存器1
#define LS2K300_RTC_CTRL_REG 0x16128040 // RTC 控制寄存器
// DMA
#define LS2K300_DMA_ORDER0 0x1612c000 // DMA 通道0
// PLL 控制
#define CBUS_PLL_NODE 0x16000400 // Node PLL
#define CBUS_PLL_DDR 0x16000408 // DDR PLL
#define CBUS_PLL_PIX 0x16000410 // PIX PLL
// 看门狗
#define LS2K300_WDT_BASE 0x16124000 // 看门狗基址
#define LS2K300_RST_CNT_REG 0x16124000 // 复位控制
4.2 PCI 地址空间 (bonito.h)
// PCI 配置空间
#define BONITO_PCICFG0_BASE_VA 0xfe00000000 // PCI 配置空间0
#define BONITO_PCICFG1_BASE_VA 0xfe10000000 // PCI 配置空间1
// PCI 内存空间
#define BONITO_PCILO_BASE_VA 0x10000000 // PCI 低端内存
#define BONITO_PCILO_SIZE 0x0c000000 // 192MB
#define BONITO_PCILO_TOP 0x1BFFFFFF
// PCI I/O 空间
#define BONITO_PCIIO_BASE 0x1fd00000 // PCI I/O 基址
#define BONITO_PCIIO_BASE_VA 0x1fd00000 // PCI I/O 虚拟地址
#define BONITO_PCIIO_SIZE 0x00010000 // 64KB
// LIO 内存窗口
#define LIO_MEM_BASE0 0x1a000000 // LIO 内存0
#define LIO_MEM_BASE1 0x1b000000 // LIO 内存1
#define LIO_MEM_SIZE 0x01000000 // 16MB
// LPC 内存
#define LPC_MEM_BASE 0x1df00000 // LPC 内存基址
#define LPC_MEM_SIZE 0x01000000 // 16MB
// SPI Flash 内存映射
#define SPI_MEM_BASE 0x18000000 // SPI 内存基址
#define SPI_MEM_SIZE 0x02000000 // 32MB
五、虚拟内存映射 (vmparam.h, vm_kern.h)
5.1 用户/内核地址划分
// vmparam.h
#define USRTEXT 0x00400000 // 用户代码起始
#define USRSTACK 0x80000000 // 用户栈顶
#define VM_MAXUSER_ADDRESS 0x80000000 // 用户空间上限
#define KERNBASE 0x80000000 // 内核虚拟起始
#define VM_MIN_KERNEL_ADDRESS 0xC0000000 // 内核最小地址
#define VM_MAX_KERNEL_ADDRESS 0xFFFFC000 // 内核最大地址
// 内核特殊区域
#define UADDR 0xffffc000 // u-area 地址
#define KERNELSTACK (UADDR + UPAGES*NBPG) // 内核栈顶
5.2 内核映射区 (vm_kern.h)
// 内核虚拟内存映射区
extern vm_map_t buffer_map; // 文件系统缓冲区映射
extern vm_map_t exec_map; // exec 参数/环境映射
extern vm_map_t kernel_map; // 内核核心映射
extern vm_map_t kmem_map; // malloc 内存映射
extern vm_map_t mb_map; // mbuf 集群映射
extern vm_map_t phys_map; // 物理内存映射
5.3 内核映射区用途
| 映射区 | 用途 | 典型大小 |
|--------|------|----------|
| kernel_map | 内核代码、数据、页表 | 整个内核地址空间 |
| kmem_map | malloc() 动态分配 | VM_KMEM_SIZE |
| mb_map | 网络 mbuf 集群 | NMBCLUSTERS * MCLBYTES |
| buffer_map | 文件系统缓冲区 | nbuf * MAXBSIZE |
| phys_map | 设备 I/O 映射 | USRIOSIZE * PAGE_SIZE |
六、PMON 运行时地址空间布局
6.1 PMON 代码段定位 (start.S)
// start.S 中的栈定义
stack = start + LOCK_CACHE_SIZE /* 栈在锁定缓存末尾 */
// 锁定缓存配置
#define LOCK_CACHE_BASE 0x90000000 // 256KB 锁定缓存
#define LOCK_CACHE_SIZE 0x40000 // 256KB
6.2 PMON 运行时地址分布
Scache (0x90000000 - 0x9003FFFF, 256KB)
┌─────────────────────────────────────────────────────────────────────────────┐
│ 0x90000000 ┌─────────────────────────────────────────────────────────────┐ │
│ │ .text (PMON 代码段) │ │
│ │ 入口: _start → cache_main → init_loongarch → dbginit → main│ │
│ │ ~ 100-150KB │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ .rodata (只读数据) │ │
│ │ - 字符串常量 │ │
│ │ - 命令表 │ │
│ │ - 设备表 │ │
│ │ ~ 10-20KB │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ .data (初始化数据) │ │
│ │ - 全局变量 (已初始化) │ │
│ │ - 设备结构 │ │
│ │ ~ 10-20KB │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ .bss (未初始化数据) │ │
│ │ - 全局变量 (未初始化) │ │
│ │ - 缓冲区 │ │
│ │ ~ 10-20KB │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ 空闲区域 / 栈 (向下增长) │ │
│ 0x9003FFFF └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
6.3 kmem 静态内存池 (kern_misc.c)
// vminit() - 从内存顶部预留内存池
void vminit()
{
memorysize = (memorysize - VM_KMEM_SIZE) & ~PGOFSET;
if (IS_CACHED_ADDR((u_int64_t)&kmem)) {
kmem = (u_char *)PHYS_TO_CACHED(memorysize);
} else {
kmem = (u_char *)PHYS_TO_UNCACHED(memorysize);
}
}
// kmem_malloc - 从静态池分配
vm_offset_t kmem_malloc(vm_map_t map, vm_size_t size)
{
size = (size + PGOFSET) & ~PGOFSET;
// 预留 16MB 给上层 PMON 代码
if (kmem_offs + size > VM_KMEM_SIZE - 0x01000000) {
return 0;
}
p = (vm_offset_t) &kmem[kmem_offs];
kmem_offs += size;
return p;
}
kmem 内存池布局:
高地址 ┌─────────────────────────────────┐
│ 保留区域 (16MB) │ ← 给上层 PMON 代码
├─────────────────────────────────┤
│ kmem 动态分配区 │ ← kmem_malloc 分配
│ (kmem_offs 递增) │
├─────────────────────────────────┤
│ VM_KMEM_SIZE │
│ 内核内存池 │
低地址 └─────────────────────────────────┘
七、异常向量地址
// cpu.h
#define TLB_MISS_EXC_VEC CACHED_MEMORY_ADDR // TLB 缺失
#define XTLB_MISS_EXC_VEC PHYS_TO_CACHED(0x80) // XTLB 缺失
#define CACHE_ERR_EXC_VEC CACHED_MEMORY_ADDR // 缓存错误
#define GEN_EXC_VEC PHYS_TO_CACHED(0xfe00000) // 通用异常向量
// start.S 中设置
#define GEN_EXC_VEC 0xfe00000
#define TLB_EXC_VEC 0x1c001000
八、内存探测结果 (tgt_machdep.c)
void get_memorysize(unsigned long long tgt_memsz)
{
raw_memsz = tgt_memsz >> 9;
mem_size = raw_memsz & 0xff;
mem_size = mem_size << 29; // 转换为字节
mem_size = mem_size - 0x1000000; // 减去 16MB 保留
mem_size = mem_size >> 20; // 转换为 MB
// 低端内存 (前 240MB)
memorysize = mem_size > 240 ? 240 << 20 : mem_size << 20;
// 高端内存 (超过 240MB 的部分)
memorysize_high = mem_size > 240 ?
(((unsigned long long)mem_size) - 240) << 20 : 0;
memorysize_total = ((memorysize + memorysize_high) >> 20) + 16;
}
1GB 内存布局示例:
物理地址 虚拟地址 (缓存)
0x0000_0000 ┌──────────────┐ 0x9000_0000_0000_0000
│ 保留 16MB │
0x0100_0000 ├──────────────┤
│ 低端内存 │
│ (240MB) │
0x1000_0000 ├──────────────┤
│ 高端内存 │
│ (784MB) │
0x3FFF_FFFF └──────────────┘ 0x9000_0000_3FFF_FFFF
九、地址空间分布总图
┌─────────────────────────────────────────────────────────────────────────────┐
│ PMON 完整地址空间分布 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 物理地址空间 (Physical Address) │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 0x0000_0000 - 0x0FFF_FFFF: 系统内存 (低端) │ │
│ │ 0x1000_0000 - 0x1BFF_FFFF: 系统内存 (高端) │ │
│ │ 0x1C00_0000 - 0x1CFF_FFFF: SPI Flash (PMON 固件) │ │
│ │ 0x1E00_0000 - 0x1EFF_FFFF: LIO 内存窗口 │ │
│ │ 0x1FD0_0000 - 0x1FD0_FFFF: PCI I/O 空间 │ │
│ │ 0x1FE0_0000 - 0x1FEF_FFFF: SoC 内部寄存器 │ │
│ │ 0x1FF0_0000 - 0x1FFF_FFFF: 外设寄存器 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ (VA_TO_PHYS / PHYS_TO_CACHED) │
│ 虚拟地址空间 (Virtual Address) │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 0x0000_0000_0000_0000 ──────────────────────────────────────────── │ │
│ │ 用户态 (KUSEG) │ │
│ │ USRTEXT: 0x00400000 │ │
│ │ USRSTACK: 0x80000000 │ │
│ │ 0x7FFF_FFFF_FFFF_FFFF ──────────────────────────────────────────── │ │
│ │ 非缓存 (UNCACHED) │ │
│ │ 设备寄存器: 0x8000_0000_1600_0000 │ │
│ │ 0x8000_0000_1C00_0000: Flash (非缓存访问) │ │
│ │ 0x8FFF_FFFF_FFFF_FFFF ──────────────────────────────────────────── │ │
│ │ 缓存 (CACHED) │ │
│ │ 0x9000_0000_0000_0000: Scache 锁定 (256KB) │ │
│ │ 0x9000_0000_0000_0000: PMON 代码运行地址 │ │
│ │ 0x9000_0000_1000_0000: 系统内存 (缓存访问) │ │
│ │ 0x9FFF_FFFF_FFFF_FFFF ──────────────────────────────────────────── │ │
│ │ 内核地址空间 │ │
│ │ KERNBASE: 0x80000000 │ │
│ │ VM_MIN_KERNEL: 0xC0000000 │ │
│ │ UADDR: 0xFFFFC000 (u-area) │ │
│ │ 0xFFFF_FFFF_FFFF_FFFF ──────────────────────────────────────────── │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
十、地址空间关键常量汇总
| 常量 | 值 | 说明 |
|------|-----|------|
| CACHED_MEMORY_ADDR | 0x9000_0000_0000_0000 | 缓存内存基址 |
| UNCACHED_MEMORY_ADDR | 0x8000_0000_0000_0000 | 非缓存内存基址 |
| USRTEXT | 0x0040_0000 | 用户代码起始 |
| USRSTACK | 0x8000_0000 | 用户栈顶 |
| KERNBASE | 0x8000_0000 | 内核虚拟起始 |
| UADDR | 0xFFFF_C000 | u-area 地址 |
| LOCK_CACHE_BASE | 0x9000_0000 | Scache 锁定基址 |
| LOCK_CACHE_SIZE | 0x4_0000 (256KB) | Scache 锁定大小 |
| BONITO_FLASH_BASE | 0x1C00_0000 | Flash 基址 (物理) |
| BONITO_PCIIO_BASE | 0x1FD0_0000 | PCI I/O 基址 |
| NVRAM_OFFS | 0x000F_F000 | NVRAM 在 Flash 中的偏移 |
| DTB_OFFS | NVRAM_OFFS - DTB_SIZE | DTB 在 Flash 中的偏移 |
| VM_KMEM_SIZE | 编译时确定 | 内核内存池大小 |
| NMBCLUSTERS | 1024/2048 | mbuf 集群数量 |
十一、总结
PMON 的地址空间分布具有以下特点:
- 64 位地址空间:利用 LoongArch 的高位区分缓存/非缓存访问
- 物理/虚拟地址转换:通过
PHYS_TO_CACHED 和 PHYS_TO_UNCACHED 宏统一管理
- Scache 锁定:启动时在 0x90000000 锁定 256KB 缓存用于加速
- Flash 布局:PMON 代码、DTB、NVRAM 在 Flash 中紧凑排列
- 设备寄存器映射:所有外设寄存器通过非缓存地址访问
- 内核映射区:多种专用映射区 (mbuf、buffer、kmem 等) 隔离不同用途
- 用户/内核隔离:用户空间 (0x00400000-0x80000000) 与内核空间分离