47 mmap 的实现

本文介绍了mmap函数的内存映射优势,通过实例展示其工作流程,涉及get_unmapped_area、mmap_region和mm_populate等关键步骤。

前言

mmap 函数经常是和 普通的 bio 进行一个参照对比 

mmap 相比于 bio 减少了一次 系统空间 到 用户空间 的拷贝操作 

普通的 bio 的流程可以参见这里 从磁盘读取数据到内存的调试

这里 我们来看一下 mmap 

测试用例 

测试用例如下, 仅仅是一个 mmap 的一个简单的使用

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>

#define LEN (10*4096)

int main(void) {
    int fd, loop;
    char *vadr;

    if ((fd = open("/dev/mapnopage", O_RDWR)) < 0) {
        return 0;
    }
    vadr = mmap(0, LEN, PROT_READ, MAP_PRIVATE | MAP_LOCKED, fd, 0);

    for (loop = 0; loop < 2; loop++) {
        printf("[%-10s----%lx]\n", vadr + 4096 * loop, vadr + 4096 * loop);
    }

}

get_unmapped_area 

从上下文可知 file 为 代码中读取的 "mapnopage" 

do_mmap 主要有几个阶段, get_unmapped_area 为 获取可用的 mmap 的虚拟内存

mmap_region 为处理真正的映射处理, 初始化 vma->vm_ops 

mm_populate 为迭代用户需要的 n 个页面, 然后 产生缺页中断, 然后 基于 vma->vm_ops 来处理缺页中断, 填充页面 

如果用户有传入一个合法的 虚拟地址, 直接返回目标的地址 

否则从 heap 自顶向下获取可用的 虚拟内存区间 

然后就是 找可用的 mmap 映射区, 从 mmap_base 开始向下找, 可用的 vma 映射区 

mmap_region 

这部分就是 根据可用的 mmap 映射区, 新建 vma, 然后添加到 用户进程中 

然后基于 file->f_op->mmap 来处理 vma, 更新 vma->vm_ops 为 对应的文件系统的 vm_ops, 比如这里 "/dev/mapnopage" 对应的 vm_ops 更新为 shmem_vm_ops 

mm_populate

循环需要处理的 n 个页面, 主动触发获取 物理页 

然后 shmem_fault 会从 pagecache 中获取给定的文件, 给定的偏移 的 page 信息 

然后 定时同步到 持久化设备 

 以上处理的堆栈信息 

在 pagecache 中尝试查询 

### Xilinx RFSoC ZU47DR 数据手册与规格 Xilinx RFSoC ZU47DR 是赛灵思推出的高性能系统级芯片(SoC),集成了 ARM 处理器、FPGA 逻辑资源以及高精度高速模数/数模转换器。该芯片适用于雷达、通信、测试测量设备等高端应用领域,具备极高的灵活性和性能[^3]。 #### 主要技术规格 - **ADC 性能**: - 最高采样率:5 GSPS - 分辨率:14 位 - 输入带宽:支持射频直采(RF Direct Sampling)[^4] - **DAC 性能**: - 最高采样率:9.8 GSPS - 分辨率:14 位 - 输出频率范围广,适合宽带信号合成[^4] - **ARM 处理器子系统**: - 集成四核 ARM Cortex-A53,主频最高可达 1.3 GHz - 支持多种操作系统,如 Linux、FreeRTOS 等 - 包含丰富的外设接口,包括千兆以太网、USB 3.0、SD 卡控制器等[^3] - **FPGA 资源**: - 可编程逻辑资源丰富,适用于高速数字信号处理算法实现 - 支持 PL 端高速接口,如 QSFP+、PCIe Gen3 x8 等[^1] - **内存支持**: - PS 端支持高达 4GB DDR4 SDRAM,速率可达 2400MT/s - PL 端可扩展 DDR4 内存,用于高速缓存或数据缓冲[^5] - **外部接口**: - PCIe Gen3 x8 接口,支持 PC 直接访问 FPGA 和 ADC/DAC 数据流 - 多路 GPIO、RS422、RS485、UART 等通用通信接口[^1] #### 开发资源与工具链 为了加速开发流程,Xilinx 提供了完整的开发环境和文档支持: - **Vivado Design Suite**:用于 FPGA 逻辑设计、综合、布局布线及仿真。 - **SDK / Vitis**:支持嵌入式软件开发,包括裸机程序和基于 Linux 的应用。 - **PetaLinux 工具**:用于构建定制化的嵌入式 Linux 系统。 - **参考设计与评估板**:例如基于 ZU47DR 的信号处理板卡,提供完整硬件平台用于验证和原型开发[^5] 此外,官方还提供了详细的《Xilinx RFSoC ZU47DR 使用指南》[^4],涵盖芯片配置、时钟管理、电源设计、射频接口调试等内容。 #### 应用场景 - **通信系统**:5G 基带处理、毫米波通信前端 - **雷达系统**:MIMO 雷达、数字波束成形(Digital Beamforming) - **测试与测量设备**:高速示波器、频谱分析仪、信号发生器 - **工业控制与传感器融合**:多通道高精度采集系统 ### 示例代码:初始化 RFSoC ZU47DR 的 ADC 通道 以下是一个简化版的 C++ 示例代码片段,展示如何在 PetaLinux 环境中通过寄存器访问方式初始化 ADC 通道(需根据具体硬件设计修改地址和值): ```cpp #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #define ADC_BASE_ADDR 0x43C00000 #define ADC_REG_SIZE 0x1000 int main() { int dev_mem = open("/dev/mem", O_RDWR | O_SYNC); if (dev_mem < 0) { perror("Failed to open /dev/mem"); return -1; } volatile void* adc_regs = mmap(NULL, ADC_REG_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem, ADC_BASE_ADDR); if (adc_regs == MAP_FAILED) { perror("mmap failed"); close(dev_mem); return -1; } // Write to control register to enable ADC channel 0 *(volatile uint32_t*)((char*)adc_regs + 0x00) = 0x01; munmap((void*)adc_regs, ADC_REG_SIZE); close(dev_mem); return 0; } ``` 此代码展示了如何通过 `/dev/mem` 映射物理地址空间并访问 ADC 控制寄存器,适用于低层硬件驱动开发或调试阶段使用。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值