ReadDOS_head_Mapping

void CReadDOS_headDlg::OnBtnRead() 
{
	/*
	CFile f;
	CFileException e; 
	// 打开文件
	char buffPath[256];
	this->GetDlgItemText(IDC_FILE_PATH,buffPath,sizeof(buffPath));
	int openRet;
	if (!(openRet=f.Open(buffPath, CFile::modeRead, &e)))
	{
	TCHAR szError[1024];
	e.GetErrorMessage(szError, 1024);
	AfxMessageBox(szError);
	return;
	}
	*/

	// 打开文件
	char buffPath[256];
	this->GetDlgItemText(IDC_FILE_PATH,buffPath,sizeof(buffPath));
	HANDLE hFile = ::CreateFile(buffPath,  
      GENERIC_READ ,//| GENERIC_WRITE,  
      0,  
      NULL,  
      OPEN_ALWAYS,  
      FILE_ATTRIBUTE_NORMAL,  
      NULL);  
   // Create a file-mapping object for the file.  
   HANDLE hFileMapping = ::CreateFileMapping(hFile,  
      NULL,  
      PAGE_WRITECOPY,  
      0, 0,  
      NULL);  
    LPVOID lpBase=::MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0, 0, 0);  
	if(lpBase==NULL)
	{
	//printf("MapViewOfFile Failed\n");
		MessageBox("MapViewOfFile Failed");
		return ; 
	}

	IMAGE_DOS_HEADER *pheader;
	/*
	char FileBuff[5*1024];
	memset((void*)FileBuff,0,sizeof(FileBuff));
	f.Read((void*)FileBuff, sizeof(FileBuff));
	pheader=(IMAGE_DOS_HEADER *)FileBuff;
	*/
	pheader=(IMAGE_DOS_HEADER *)lpBase;


    
	char buffOutput[512];
	sprintf(buffOutput, \
	" \
	WORD e_magic:%d\r\n \
	WORD e_cblp:%d\r\n \
	WORD e_cp:%d\r\n \
	WORD e_crlc:%d\r\n \
	WORD e_cparhdr:%d\r\n \
	WORD e_minalloc:%d\r\n \
	WORD e_maxalloc:%d\r\n \
	WORD e_ss:%d\r\n \
	WORD e_sp:%d\r\n \
	WORD e_csum:%d\r\n \
	WORD e_ip:%d\r\n \
	WORD e_cs:%d\r\n \
	WORD e_lfarlc:%d\r\n \
	WORD e_ovno:%d\r\n \
	WORD e_oemid:%d\r\n \
	WORD e_oeminfo:%d\r\n \
	LONG e_lfanew:%d",
	pheader->e_magic,   
	pheader->e_cblp,    
	pheader->e_cp,      
	pheader->e_crlc,    
	pheader->e_cparhdr, 
	pheader->e_minalloc,
	pheader->e_maxalloc,
	pheader->e_ss,      
	pheader->e_sp,      
	pheader->e_csum,    
	pheader->e_ip,      
	pheader->e_cs,      
	pheader->e_lfarlc,  
	pheader->e_ovno,    
	pheader->e_oemid,   
	pheader->e_oeminfo, 
	pheader->e_lfanew);
	this->SetDlgItemText(IDC_DOS_HEADER,buffOutput);
	{
		//IDC_IMAGE_TYPE
		char buff[256];
		unsigned long ret=ImageFileType(pheader);
		switch(ret)
		{
		case IMAGE_DOS_SIGNATURE://MZ
			//cout<<"IMAGE_DOS_SIGNATURE"<<endl;
			sprintf(buff,"IMAGE_DOS_SIGNATURE");
			break;
		case IMAGE_OS2_SIGNATURE://NE
			//cout<<"IMAGE_OS2_SIGNATURE"<<endl;
			sprintf(buff,"IMAGE_OS2_SIGNATURE");
			break;
		case IMAGE_OS2_SIGNATURE_LE:
			//cout<<"IMAGE_OS2_SIGNATURE_LE"<<endl;
			sprintf(buff,"IMAGE_OS2_SIGNATURE_LE");
			break;
		case IMAGE_NT_SIGNATURE:
			//cout<<"IMAGE_NT_SIGNATURE"<<endl;
			sprintf(buff,"IMAGE_NT_SIGNATURE");
			break;
		default:
			sprintf(buff,"default:%x",ret);
			break;
		}
		this->SetDlgItemText(IDC_IMAGE_TYPE,buff);
	}
	
	//f.Close();
   ::UnmapViewOfFile(lpBase);  
   ::CloseHandle(hFileMapping);  
   ::CloseHandle(hFile);  
}

<think>我们正在解决用户关于`dma_mapping_error`的问题,并且用户提到了`of_dma_configure`。因此,我们需要将两者联系起来分析。用户的问题:查找关于`dma_mapping_error`的解决方案或原因分析,并且与`of_dma_configure`相关。首先,我们需要明确`dma_mapping_error`的作用:它是一个宏或函数,用于检查DMA映射操作(如`dma_map_single`,`dma_map_page`等)是否失败。如果失败,返回非0值。常见原因:1.DMA映射失败可能是因为DMA地址空间不足(例如,DMA掩码设置不当,导致请求的物理地址无法映射到DMA地址空间)。2.设备未正确配置DMA(例如,未调用`of_dma_configure`或未设置DMA掩码)。3.设备树中缺少必要的DMA属性,导致DMA配置不正确。由于用户提到了`of_dma_configure`,因此我们需要强调该函数在DMA配置中的重要性。根据引用[1],`of_dma_configure`会从设备树中读取`dma-coherent`等属性,并设置设备的DMA相关字段(如`dma_coherent`,`dma_mask`等)。如果这一步缺失或配置错误,后续的DMA映射操作可能会失败。因此,我们可以将原因和解决方法分为几个部分:一、`dma_mapping_error`的常见原因二、与`of_dma_configure`相关的配置问题三、解决方法另外,我们还可以给出代码示例,展示如何正确使用`of_dma_configure`以及如何检查DMA映射错误。最后,生成相关问题。注意:用户要求使用中文回答,并且按照指定的格式(包括引用和LaTeX)。</think>### `dma_mapping_error` 原因分析及解决方案(与`of_dma_configure`关联) #### 一、`dma_mapping_error` 的核心作用 在Linux DMA子系统中,`dma_mapping_error()` 用于**检测DMA映射操作是否失败**: ```c dma_addr_t dma_handle = dma_map_single(dev, cpu_ptr, size, dir); if (dma_mapping_error(dev, dma_handle)) { dev_err(dev, "DMA映射失败!"); // 错误处理 } ``` 当返回非零值时,表明`dma_map_single()`、`dma_map_page()`等映射操作失败[^1]。 --- ### 二、根本原因分析(关联`of_dma_configure`) #### 1. **DMA掩码未正确配置**(最常见) `of_dma_configure()` 未调用或调用错误 → 设备DMA掩码未初始化: ```c // 错误示例:未调用of_dma_configure dma_addr_t handle = dma_map_single(dev, buf, size, DMA_TO_DEVICE); if (dma_mapping_error(dev, handle)) // 因dev->dma_mask未设置而失败 ``` > 引用[1]:`of_dma_configure()` 负责设置`dev->dma_mask`和`dev->coherent_dma_mask`[^1]。 #### 2. **物理地址超出DMA范围** 设备树`dma-ranges`定义的范围过小: ```dts // 设备树示例:仅允许0x0-0x10000000的DMA访问 my_device { compatible = "vendor,device"; dma-ranges = <0 0 0x0 0x10000000>; }; ``` 若尝试映射`0x20000000`的物理地址 → 触发`dma_mapping_error`[^2]。 #### 3. **IOMMU配置错误** ```c // 未正确处理IOMMU映射 dma_addr_t handle = iommu_map(domain, iova, paddr, size, prot); if (dma_mapping_error(dev, handle)) // IOMMU映射失败 ``` #### 4. **内存区域不支持DMA** ```c void *buf = vmalloc(SIZE); // vmalloc内存默认不可DMA映射 dma_addr_t handle = dma_map_single(dev, buf, size, dir); // 必然失败 ``` --- ### 三、解决方案(结合`of_dma_configure`) #### 1. **正确初始化DMA配置** ```c static int driver_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; // 关键:先调用of_dma_configure of_dma_configure(dev, dev->of_node, true); // 第三个参数force=true // 显式设置DMA掩码(32位示例) if (!dev->coherent_dma_mask) dev->coherent_dma_mask = DMA_BIT_MASK(32); // 后续DMA操作 dma_addr_t handle = dma_map_single(dev, buf, size, dir); if (dma_mapping_error(dev, handle)) { dev_err(dev, "DMA映射失败, 地址掩码:0x%llx", dev->coherent_dma_mask); } } ``` #### 2. **检查设备树配置** ```dts my_device { compatible = "vendor,device"; // 必需属性 dma-coherent; // 声明硬件一致性 dma-ranges = <0 0 0x0 0x40000000>; // 扩展DMA地址范围 }; ``` #### 3. **使用DMA兼容的内存** ```c // 正确:分配DMA友好内存 void *buf = kmalloc(SIZE, GFP_DMA); // GFP_DMA确保低端内存 dma_addr_t handle = dma_map_single(dev, buf, size, dir); // 替代方案:dma_alloc_coherent dma_addr_t dma_handle; void *cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL); ``` #### 4. **IOMMU异常处理** ```c if (dev->iommu_group) { // 检查IOMMU状态 dma_addr_t handle = iommu_map(domain, iova, paddr, size, prot); if (dma_mapping_error(dev, handle)) { dev_err(dev, "IOMMU映射失败,检查domain配置"); } } ``` --- ### 四、调试技巧 1. **动态检测**:启用`CONFIG_DMA_API_DEBUG` ```bash echo 1 > /sys/kernel/debug/dma-api/dump # 查看DMA映射泄漏 ``` 2. **地址范围检查**: ```c dev_info(dev, "DMA掩码: 0x%llx, 物理地址: 0x%lx", *dev->dma_mask, virt_to_phys(buf)); ``` 3. **内核日志过滤**: ```bash dmesg | grep -i "dma mapping error" # 定位错误上下文 ``` --- ### 五、根本原因总结 | **错误原因** | **关联函数** | **解决方案** | |----------------------------|-----------------------|-----------------------------| | DMA掩码未初始化 | `of_dma_configure()`缺失 | 在probe()首部调用该函数 | | 物理地址超出`dma-ranges` | 设备树配置错误 | 扩展设备树中的地址范围 | | IOMMU映射失败 | `iommu_map()` | 验证IOMMU domain和映射权限 | | 非DMA安全内存 | `vmalloc()`/`kmap()` | 使用`kmalloc(GFP_DMA)`或`dma_alloc_coherent` | > 引用[1]:未正确调用`of_dma_configure`是DMA映射失败的**最常见根本原因**[^1]。 --- **相关问题** 1. 如何验证设备树中的`dma-ranges`是否生效? 2. `dma_map_single()`和`dma_alloc_coherent()`的性能差异如何? 3. ARM64架构下IOMMU与DMA的交互机制是怎样的? 4. 如何检测Linux内核中的DMA地址映射泄漏? [^1]: `of_dma_configure()`负责初始化设备DMA掩码,缺失将导致映射失败 [^2]: 设备树`dma-ranges`定义设备可访问的物理地址范围
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值