我可以用Java读/写一个linux块设备java.nio.以下代码有效:
Path fp = FileSystems.getDefault().getPath("/dev", "sdb");
FileChannel fc = null;
try {
fc = FileChannel.open(fp, EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE));
} catch (Exception e) {
System.out.println("Error opening file: " + e.getMessage());
}
ByteBuffer buf = ByteBuffer.allocate(50);
try {
if(fc != null)
fc.write(buf);
} catch (Exception e) {
System.out.println("Error writing to file: " + e.getMessage());
}
Run Code Online (Sandbox Code Playgroud)
但是,内存映射不起作用.以下代码失败:
MappedByteBuffer mbb = null;
try {
mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 100);
} catch (IOException e) {
System.out.println("Error mapping file: " + e.getMessage());
} …Run Code Online (Sandbox Code Playgroud) 我们知道:http://en.wikipedia.org/wiki/IOMMU#Advantages
IOMMU可以支持外围存储器分页.使用PCI-SIG PCIe地址转换服务(ATS)页面请求接口(PRI)扩展的外设可以检测并发出对内存管理器服务的需求.

但是当我们使用CUDA> = 5.0的nVidia GPU时,我们可以使用RDMA GPUDirect,并且知道:
http://docs.nvidia.com/cuda/gpudirect-rdma/index.html#how-gpudirect-rdma-works
传统上,使用CPU的MMU作为内存映射I/O(MMIO)地址,将BAR窗口等资源映射到用户或内核地址空间.但是,由于当前的操作系统没有足够的机制来在驱动程序之间交换MMIO区域,因此NVIDIA内核驱动程序会导出函数以执行必要的地址转换和映射.
http://docs.nvidia.com/cuda/gpudirect-rdma/index.html#supported-systems
从PCI设备的角度来看,GPUDirect的RDMA当前依赖于所有物理地址是相同的.这使它与IOMMU不兼容,因此必须禁用它们才能使RDUD for GPUDirect正常工作.
如果我们将CPU-RAM分配并映射到UVA,如下所示:
#include <iostream>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
int main() {
// Can Host map memory
cudaSetDeviceFlags(cudaDeviceMapHost);
// Allocate memory
unsigned char *host_src_ptr = NULL;
cudaHostAlloc(&host_src_ptr, 1024*1024, cudaHostAllocMapped);
std::cout << "host_src_ptr = " << (size_t)host_src_ptr << std::endl;
// Get UVA-pointer
unsigned int *uva_src_ptr = NULL;
cudaHostGetDevicePointer(&uva_src_ptr, host_src_ptr, 0);
std::cout << "uva_src_ptr = " << (size_t)uva_src_ptr << std::endl;
int b; …Run Code Online (Sandbox Code Playgroud) 我有以下asm代码:
org $1000 ;Table Origin is at $1000
fcb $02,$04,$06,$08 ; values of table from $1001 - $1004
fcb $0a,$0c,$0e,$10 ; values of table from $1005 - $1009
org $400 ; Program Start
lds #$4000 ; Set Stack Pointer at value (#) $4000
ldy #$1000 ; Set Index Y at $1000
ldaa #$04 ; Load Accumulator a with value $04
loop staa $20,y ; Store value of Accumulator a at y = $1000 {DOESNT WORK}
staa $21,y ; Store value …Run Code Online (Sandbox Code Playgroud) 我正在用Java做内存映射的IO。FileChannel类允许您将ByteBuffer映射到文件的特定部分。我这样做是用只读方式打开的文件。
我遇到的问题是,当我尝试对生成的ByteBuffer调用.array()方法时遇到异常。也许是因为.array()返回byte []数组,而我真的想要一个最终的字节数组吗?
有没有办法解决?
我正在使用基于x86的内核来操作32位内存映射寄存器.仅当CPU对该寄存器产生32位宽的读写操作时,我的硬件才能正常工作.寄存器在32位地址上对齐,并且不能以字节粒度进行寻址.
我该怎么做才能保证我的C(或C99)编译器在所有情况下都只能生成完整的32位宽读写?
例如,如果我执行这样的读 - 修改 - 写操作:
volatile uint32_t* p_reg = 0xCAFE0000;
*p_reg |= 0x01;
Run Code Online (Sandbox Code Playgroud)
我不希望编译器明智地知道只有底部字节发生变化并产生8位宽的读/写.由于机器代码在x86上的8位操作通常更密集,我害怕不必要的优化.一般情况下禁用优化不是一种选择.
-----编辑-------
一篇有趣且非常相关的论文:http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf
什么是串行副本?它与深拷贝和浅拷贝不同吗?
根据Duff设备下的wiki条目,它传统上实现为:
do { //count > 0 assumed
*to = *from++; //Note that the 'to' pointer is NOT incremented
} while(--count > 0);
Run Code Online (Sandbox Code Playgroud)
然后它做了一个说明,说
请注意,
to由于Duff正在复制到单个内存映射输出寄存器,因此不会增加.
我真的不明白这个说明.
如果to指针没有递增,那么循环的重点是什么?为什么然后它被实现为:
*to = from[count-1]; //does it not do the same thing?
Run Code Online (Sandbox Code Playgroud)
我怀疑它与串行副本的定义有关.
我们如何分配内存以to使循环产生一些差异?
我正在从事一个嵌入式项目,该项目涉及内存映射 FPGA 寄存器上的 I/O。需要标记指向这些内存区域的指针,volatile以便编译器不会通过在 CPU 寄存器中缓存值来“优化”对 FPGA 的读取和写入。
在少数情况下,我们希望将一系列 FPGA 寄存器复制到缓冲区中以供进一步使用。由于寄存器映射到连续地址,这memcpy似乎是合适的,但是将我们的volatile指针作为源参数传递会给出关于丢弃volatile限定符的警告。
丢弃volatile指针的-ness 以抑制此警告是否安全(和理智)?除非编译器做了一些神奇的事情,否则我无法想象调用memcpy将无法执行实际复制的场景。另一种方法是仅使用for循环并逐字节复制,但memcpy实现可以(并且确实)根据副本的大小、对齐方式等优化副本。
我正在使用 OpenCL 进行一些图像处理,并希望使用它将 RGBA 图像直接写入帧缓冲区。工作流程如下图所示:
1) 将帧缓冲区映射到用户空间。
2) 使用 clCreateBuffer 创建 OpenCL 缓冲区,标志为“CL_MEM_ALLOC_HOST_PTR”
3)使用clEnqueueMapBuffer将结果映射到framebuffer。
然而,这不起作用。屏幕上什么也没有。然后我发现帧缓冲区映射的虚拟地址与映射OpenCL的虚拟地址不同。有没有人做过从 GPU 到帧缓冲区的数据零复制移动?我应该使用什么方法来实现此目的有任何帮助吗?
一些关键代码:
if ((fd_fb = open("/dev/fb0", O_RDWR, 0)) < 0) {
printf("Unable to open /dev/fb0\n");
return -1;
}
fb0 = (unsigned char *)mmap(0, fb0_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
...
cmDevSrc4 = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof(cl_uchar) * imagesize * 4, NULL, &status);
...
fb0 = (unsigned char*)clEnqueueMapBuffer(cqCommandQueue, cmDevSrc4, CL_TRUE, CL_MAP_READ, 0, sizeof(cl_uchar) * imagesize * 4, 0, NULL, NULL, &ciErr);
Run Code Online (Sandbox Code Playgroud) 我想读取一些Cortex-A53寄存器的值,例如
不幸的是,我缺乏一点嵌入式/组装经验。文档显示
访问 ID_AA64ISAR0_EL1: MRS 、 ID_AA64ISAR0_EL1 ;将ID_AA64ISAR0_EL1读入Xt ID_AA64ISAR0_EL1[31:0]可以通过内部存储器映射接口和外部调试接口访问,偏移量0xD30。
我决定在我的目标上使用 devmem2(因为 busybox 不包含 devmem 小程序)。以下读取寄存器的过程是否正确?
devmem2 0xD30
Run Code Online (Sandbox Code Playgroud)
我不确定的部分是使用“偏移量”作为直接物理地址。如果它是实际地址,为什么要调用“offset”而不是“address”。如果是偏移量,基地址是多少?我 99% 确定这不是正确的过程,但我如何知道要添加偏移量的基地址?我搜索了Armv8技术参考手册和A53 MPCore文档没有结果。详细解释了寄存器内容,但似乎假设您使用标签 ID_AA64ISAR0_EL1 从 ASM 读取它们。
更新:
我找到了这个:
配置基地址寄存器,EL1 CBAR_EL1 的特性包括: 用途 保存内存映射 GIC CPU 接口寄存器的物理基地址。
但它只是重复了我的问题,如何读取另一个寄存器?
更新 2: 第一个更新似乎仅与 GIC 相关,与我试图读取的配置寄存器无关(我认为我误解了信息)。
对于手头的具体问题(检查加密扩展可用性),人们可以简单地 cat /proc/cpuinfo 并查找 aes/sha 等。
更新3:
我现在正在调查http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0176c/ar01s04s01.html,以及 SoC 特定的基地址,因此可以在SoC 的参考手册。
更新4:
感谢这个很好的答案,我似乎能够通过我的内核模块读取数据:
[ 4943.461948] ID_AA64ISA_EL1 : 0x11120
[ 4943.465775] ID_ISAR5_EL1 : 0x11121
Run Code Online (Sandbox Code Playgroud)
PS: 这篇文章非常有见地,再次感谢!
更新5: 根据要求源代码:
/******************************************************************************
*
* Copyright …Run Code Online (Sandbox Code Playgroud)