You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用分页后如何正确访问物理地址0x1028的帧缓冲区

问题分析与解决方案

启用分页后无法访问帧缓冲区的核心原因是:虚拟地址与物理地址不再直接一一映射。你的代码存在两个关键问题:

  1. 分页后虚拟地址0x1028虽在当前映射的前4MB范围内,但即使能读取到帧缓冲区的物理地址,该物理地址对应的虚拟地址未被映射,导致后续操作失效;
  2. 帧缓冲区通常是连续的多页内存,若其物理地址超出前4MB范围,当前分页设置完全未覆盖该区域。

以下是具体修复步骤:

步骤1:提前保存帧缓冲区物理地址

在启用分页前读取并保存帧缓冲区的物理地址,避免分页后依赖未映射的虚拟地址读取:

// 全局/静态变量保存帧缓冲区物理地址
static dword_t framebuffer_phys = 0;

void main() {
    // 分页初始化前读取物理地址0x1028中的帧缓冲区地址
    if (!framebuffer_phys) {
        framebuffer_phys = *(dword_t *)0x1028;
    }

    // 初始化分页
    init_paging();

    // 后续处理帧缓冲区映射...
}

步骤2:映射帧缓冲区物理页到虚拟地址

使用你已实现的map_page函数,将帧缓冲区的所有物理页映射到虚拟地址空间的可用区域(例如内核常用的0xC0000000起始地址):

void main() {
    // (接上一步代码)

    // 计算帧缓冲区需要映射的页数(以1920*1080*4字节为例)
    size_t fb_size = 1920 * 1080 * sizeof(dword_t);
    size_t page_count = (fb_size + PAGE_SIZES - 1) / PAGE_SIZES; // 向上取整

    // 选择虚拟地址起始点
    void *virtual_base = (void *)0xC0000000;
    void *phys_base = (void *)framebuffer_phys;

    // 逐页映射,MMIO设备建议禁用缓存(添加0x10|0x20标志)
    for (size_t i = 0; i < page_count; i++) {
        map_page(phys_base, virtual_base, 0x3 | 0x10 | 0x20);
        phys_base += PAGE_SIZES;
        virtual_base += PAGE_SIZES;
    }

    // 使用映射后的虚拟地址操作帧缓冲区
    dword_t *framebuffer = (dword_t *)0xC0000000;
    framebuffer[10 * 1920 + 10] = 0xFFFFFF; // 绘制(10,10)白色像素
}

额外检查点

  1. MMIO缓存设置:帧缓冲区属于内存映射IO设备,禁用缓存(PCD=0x10、PWT=0x20)可避免缓存一致性问题,确保像素绘制立即生效;
  2. 页表权限:你的页表项使用0x3(Supervisor、Read/Write、Present),内核态运行时权限足够;
  3. 地址对齐:页目录和页表的__attribute__((aligned(4096)))属性正确,符合x86分页要求。

内容的提问来源于stack exchange,提问作者Magic Magician

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 21:09:50