Is masking physical address of DMA allocated memory valid? - linux

I'm currently programming a Linux Kernel driver, which needs to tell a FPGA a base address in RAM to write to.
The memory is allocated in the kernel driver with dma_alloc_coherent.
This will generate a 32 bit physical address and a kernel virtual address, the physical address is being passed to the FPGA.
The FPGA is a Cyclone V with embedded ARM Cortex-A9, on which an embedded Linux with the driver is running.
The problem now is, that the FPGA fabric only generates a 27 bit wide bus to address the sdram, while the physical address, that is being generated by the dma call has 32 bits, e.g. th physical address has been 0x2f220000, which exceeds 27 bit span.
I want to know, if it is okay to mask the most significant 5 bits and tell the FPGA the address 0x7220000 and still have the correct behaviour (In doc it is stated, that the physical address shall be casted to buswidth, that would mean masking, because I can't use 27 bit in processor).
Also is it okay to access the DMA memory with a simple memcpy command, that copies from the kernel virtual address to a buffer?
Thanks in advance.

The answer truly depends on the physical memory layout of your device. If the address bus of the FPGA complements the missing bits so that the actual address resolves to the correct memory, then masking is, probably, okay. If not, then it is possible that the memory that the Linux kernel returned to you is simply in accessible to the FPGA. If that's the case, you will have to find a way to ask Linux to only give you buffers from memory that is accessible.

Related

Virtual Address Space

I have started to learn about Virtual Address Space (VAS) and I have few questions:
How much of VAS is created for each process depending on the architecture (32-bit and 64-bit)?
Is VAS for each process created on hard disk? If so, what happens if there is not enough space?
What is the difference between VAS and Virtual Memory (VM)?
Virtual address versus physical address
During the execution of your program, the variables (integers, arrays, strings, etc.) are stored somewhere in the main memory of your computer (RAM). Some programming languages (like C or C++) allow you to obtain the memory address at which a given variable is stored (with the & operator), and to manipulate that address (add to it, subtract from it, print it, etc.).
Here is a C program that prints the memory address of a variable:
#include <stdio.h>
int main(void) {
int variable = 1234;
void *address = &variable;
printf("Memory address of variable: %p\n", address);
return 0;
}
Output:
Memory address of variable: 0x7ffc9e9662a4
Now, if you compile and execute this program on a typical desktop computer, with a typical operating system (like GNU/Linux or Windows), the memory address that is printed by this program is not the hardware address at which the data 1234 is actually located in the memory chip. This may be surprising, but there is a level of indirection between the addresses used by your program and the hardware addresses.
Virtual address space on 64-bit computers
On a 64-bit computer, a memory address manipulated by your program is an integer between 0 and 18446744073709551615 inclusive. Such an address is called a virtual memory address. The range of those addresses is called the virtual address space of the process. You can ask the operating system to map a range of virtual memory addresses to the physical memory of your computer, so that when you try to read or write bytes at thoses addresses, your program doesn't crash for accessing unmapped virtual memory addresses.
Typically, on x86-64 computers, only 248 virtual memory addresses can be successfully mapped to physical memory, because 256 TiB of usable virtual address space is considered sufficient. In the future, processor manufacturers may raise or remove this limit if there is a need for it.
Virtual address space on 32-bit computers
On 32-bit computers, there are 232 virtual memory addresses. On those computers, a memory address manipulated by your program is an integer between 0 and 4294967295 inclusive.
On x86 32-bit computers, there is usually no restriction on the range of virtual memory addresses that can be mapped to physical memory addresses.
Mapping a range of virtual memory addresses
On GNU/Linux, you can request a mapping by calling the function mmap(). On Windows, you can request a mapping by calling the function VirtualAlloc(). Those functions take the size of the mapping as argument, and return the first virtual address that is now backed by actual physical memory. Those functions can fail to create a new mapping if the physical memory is already completely used by other processes. And again, if you try to access (read or write) the content of a virtual memory address that is outside an area mapped by mmap() or VirtualAlloc(), the operating system will terminate your program (by sending a segmentation fault signal).
On GNU/Linux, a process can examine the mappings created in its virtual address space just by reading the file /proc/self/maps. You can learn a lot by reading the output of the command cat /proc/self/maps.
Hard disk drive
On a typical computer, the main memory is a semiconductor memory, and the hard disk drive is only a secondary storage device.
On a typical operating system, a range of virtual memory addresses can only be mapped to the main memory (which is usually a semiconductor memory device). Such a range cannot be directly mapped to a secondary storage device (usually a hard disk drive) without using the main memory as intermediary.
On an n-bit machine, the VAS is 2n bytes large. So, on a 32-bit machine, the VAS 232 = 4 GiB large.
Virtual memory is not created on disk. In fact, the existence of a disk is not needed for implementing virtual memory. Most implementations of virtual memory are paged. So, when a 4 GiB VAS is created, only the pages that are needed are mapped into that VAS. For example, suppose a process only uses 16 pages of memory on a 32-bit system with 4k-sized pages. Despite having a 4 GiB VAS, only 16 * 4k = 216 bytes of memory are mapped into the VAS. The rest of the memory is unmapped. If the CPU tries to access this unmapped memory, a segmentation fault will occur. If a process wants to map memory at this address, then (in a POSIX-complaint OS) it can request the mapping from the OS using mmap(2). This will make a lot more sense once you learn about page tables.
Virtual memory is a concept. A virtual address space is an entity that stems from the concept of virtual memory. These terms go hand in hand, but refer to different things.
I will list a couple of caveats.
Caveat 1.1
I am not not aware of any 64-bit processor that truly supports a 64-bit VAS. The addresses themselves are 64 bits wide, but a certain number of upper bits are ignored. AMD's first implementation of x86_64 only supported 48-bit addresses. The upper 16 bits of an address were effectively ignored. In such a system, the addresses are 64 bits wide, but the real size of the VAS is limited to 248 bytes. Subsequent architectures supported 56-bit addresses.
Caveat 1.2
If a processor supports PAE, then the VAS on an n-bit machine may be larger than 2n bytes. This is how 32-bit processors can support VASs larger than 4 GiB.
Caveat 2.1
Not really a caveat, but this is related to your question. You asked what happens when there isn't enough space on disk to create a VAS. As I mentioned in the main answer, the VAS is not created on disk. However, any computer only has a finite amount of physical memory. What happens when a process requests a page be mapped, but there is no physical memory available? There are there several ways to handle this:
Swapping is done by temporarily moving a page that is mapped in virtual memory to disk. The entire contents of the page are copied to disk. Then, the process that requested the page has the physical page mapped into their memory. Eventually, the old page may be requested. If this occurs, then the OS copies the page from disk and remaps it into the corresponding VAS. This is what Linux and most modern operating systems do.
The process is simply told there is no memory available, for example, through an error number like ENOMEM.
The process is blocked until memory is available. I haven't seen this in practice.
Swapping implies the use of a disk, but virtual memory does not imply the use of swapping, hence a disk is not necessary for virtual memory.
Virtual Address Space - wikipedia
When a new application on a 32-bit OS is executed, the process has a 4 GiB VAS: each one of the memory addresses (from 0 to 232 − 1) in that space can have a single byte as a value. Initially, none of them have values.
For n-bit OS, these n-address lines allow address space upto 2n addresses, i.e., 0 to 2n - 1. This would mean 16 EiB for 64-bit OS. (Though in actual implementations, less space is used as this much space is unnecessary.)
CPU Cache - wikipedia
Most general purpose CPUs implement some form of virtual memory. To summarize, either each program running on the machine sees its own simplified address space, which contains code and data for that program only, or all programs run in a common virtual address space. A program executes by calculating, comparing, reading and writing to addresses of its virtual address space, rather than addresses of physical address space, making programs simpler and thus easier to write.
For example, in C++, program memory is divided in stack, heap, data, code. I'm not sure if analogy is correct (may be), but it somewhat presents an insight if you're aware.
Virtual memory - wikipedia
In computing, virtual memory is a memory management technique that provides an "idealized abstraction of the storage resources that are actually available on a given machine"3 which "creates the illusion to users of a very large (main) memory".[4]
The computer's operating system, using a combination of hardware and software, maps memory addresses used by a program, called virtual addresses, into physical addresses in computer memory. Main storage, as seen by a process or task, appears as a contiguous address space or collection of contiguous segments. The operating system manages virtual address spaces and the assignment of real memory to virtual memory.
Address translation hardware in the CPU, often referred to as a memory management unit (MMU), automatically translates virtual addresses to physical addresses. Software within the operating system may extend these capabilities to provide a virtual address space that can exceed the capacity of real memory and thus reference more memory than is physically present in the computer.
If you know about computer architecture (which I'm sure you do from the question), it'd be clarified by now.
Still, for anyone in general, I'm giving a bit of explanation.
Assume addresses as pointers in C++. If you don't know C++, closest analogy would be array/list indices in any language. Now the addresses point to the memory locations, just like pointers point to the variable. The actual data is stored in the variable. To get the variable data using pointer/index, you provide address location from where the data is to be extracted. Now in physical memory, there won't be a thing like a variable. There is memory and it's location address through which it is accessed.
The real memory is physical memory, which is the hard disks. It is accessed with physical addresses, which would be unique for each byte.
Accessing physical memory directly with physical addresses would be cumbersome. Thus the addresses are simplified by the OS to virtual addresses. These addresses may or may not be unique (these aren't physical addresses, remember). Thus, multiple virtual addresses may point to same location.
The virtual memory is not actually existent, rather it's just a concept of physical memory simplified using virtual addresses to give the user an illusionous space say where next memory location is stored at next address (virtual address to be precise).
Since multiple virtual addresses can be mapped, by using MMU, to same physical address, and thus to point to same phyical memory location, the virtual memory size can be made to exceed the physical memory size (virtually). But effectively, the memory size would still be same as physical.
Thus, to access a memory data, Virtual Addresses are specified by user/program to OS, which are converted to Physical Addresses by memory management unit (mmu) and then applied to the address lines of the computer architecture (electronics spotted!!), which yields the data at the corresponding physical location. And this concept is called Virtual Memory.
-Himanshu

Using a large buffer for DMA on a linux x86_64 system

I am writing a device driver for a Fibre Channel card that will move large amounts of data. The card can act as PCI master and will DMA the data into system memory. This is on an x86_64 linux system running kernel 3.0.35.
I first tried allocating the buffers using kmalloc(), but found that I could not allocate buffers large enough. However, as a learning exercise, I continued with the development using small buffers allocated with kmalloc(). I got the driver to work in this case. I allocated small buffers with kmalloc() (and the GFP_DMA flag), passed the address returned by kmalloc to dma_map_single(), and returned the address returned to the registers on the card.
I am now trying to modify the driver to use large buffers - on the order of 200MB. I have reserved a block of memory at boot time using the mem= kernel parameter. I map the reserved memory using ioremap(). I have mmap-ed the memory to user space and I have verified that the user application can write to the mmap-ed region and that the driver can read the data using the virtual address returned by ioremap(). But I have not been able to get the board to DMA data to my buffers.
I have tried to map the region that I allocated with dma_map_single(). I first passed the virtual address returned from ioremap(). I thought this was the correct address because the DMA-API-HOWTO file says:
"the driver can give a virtual address X to
an interface like dma_map_single(), which sets up any required IOMMU
mapping and returns the DMA address Z. The driver then tells the device to
do DMA to Z, and the IOMMU maps it to the buffer at address Y in system
RAM."
But I got no data from the card. I have also tried passing dma_map_single() the physical address of the region, but that didn't work. I have tried writing the address returned by dma_map_single() to the cards registers, and I have tried writing the physical address to the registers. Neither of those efforts worked, either.
Is there a step that I'm missing? Is my procedure in this case completely wrong? Can a card even perform DMAs to a memory region like the one I have reserved on an x86_64?
There is a possibility that I could upgrade the system to a 3.12.28 kernel. I understand that that kernel supports CMA. Would CMA work in this case?
Any help is appreciated.

How can kmalloc return a physical address greater than the size of the physical address?

I am allocating a block of memory with kmalloc in a device driver in Linux. The address that I get is 0xffff880000180000. I am using an IvyBridge processor with a 46-bit physical address space. That means that the CPU doesn't have more than 46 addressing pins, so it can't access any address above 0x00003fffffffffff. The address I'm getting is obviously greater than that, as it has bit 47 set.
Assuming that kmalloc returns a physical pointer (that is, a pointer where the virtual, linear and physical addresses are the same), how can I be getting such an address, if it's not accessible by the CPU?
This question is related to "Why am I getting a high address when I use kmalloc with GFP_DMA in Linux?". However, it is not identical. This question is about the physical addresses kmalloc returns in general, whereas the linked question is about use of GFP_DMA and its relationship to the returned address.
It's clearly not a physical address but a linear or virtual address, and is in 'canonical form' where the value of bit 47 is 'sign extended' up to bit 63.

x86 paging in linux kernel with mmu

In x86 arch, linux kernel 2.6.x, 32bit system
I understand that virtual address 0xC0000000 ~ 0xFFFFFFFF
is reserved for kernel.
and this virtual address can be translated to physical address by
subtracting 0xC0000000.
however, I think even the result is same, MMU will translate
the kernel virtual address(such as 0xC0851000) to physical address by walking through page table.
such as
CR3 -> page directory -> page table -> PFN.
am I correct or wrong?, please correct me if I'm wrong.
I need to develop hardware based kernel monitor in x86, linux 32bit system.
so I need to know this problem
please help.
For kernel logical addresses, you are correct. Kernel virtual addresses, like memory allocated by vmalloc, do not necessarily have a one-to-one mapping to physical addresses that characterize the logical address space, however.
Just bear in mind that kernel logical addresses aren't always translated to physical by subtracting an offset (that's true in x86 but not, say, AVR32).
"and this virtual address can be translated to physical address by
subtracting 0xC0000000"
since page tables for the kernel virtual addresses are configured that way, people have come up with a shortcut you mentioned.

why do we need zone_highmem on x86?

In linux kernel, mem_map is the array which holds all "struct page" descriptors. Those pages includes the 128MiB memory in lowmem for dynamically mapping highmem.
Since the lowmem size is 1GiB, so the mem_map array has only 1GiB/4KiB=256KiB entries. If each entry size is 32 byte, then the mem_map memory size = 8MiB. But if we could use mem_map to map all 4GiB physical memory(if we have so much physical memory available on x86-32), then the mem_map array would occupy 32MiB, that is not a lot of kernel memory(or am i wrong?).
So my question is: why do we need to use that 128MiB in low for indirect highmem mapping in the first place? Or put another way, why not to map all those max 4GiB physical memory(if available) in the kernel space directly?
Note: if my understanding of the kernel source above is wrong, please correct. Thanks!
Look Here: http://www.xml.com/ldd/chapter/book/ch13.html
Kernel low memory is the 'real' memory map, addressed with 32-bit pointers on x86.
Kernel high memory is the 'virtual' memory map, addressed with virtual structures on x86.
You don't want to map it all into the kernel address space, because you can't always address all of it, and you need most of your memory for virtual memory segments (virtual, page-mapped process space.)
At least, that's how I read it. Wow, that's a complicated question you asked.
To throw more confusion, chapter 13 talks about some PCI devices not being able to address the 32-bit space, which was the genesis of my previous comment:
On x86, some kernel memory usage is limited to the first Gigabyte of memory bacause of DMA addressing concerns. I'm not 100% familiar with the topic, but there's a comapatibility mode for DMA on the PCI bus. That may be what you are looking at.
3.6 GB is not the ceiling when using physical address extension, which is commonly needed on most modern x86 boards, especially with memory hotplug.
Or put another way, why not to map all those max 4GiB physical
memory(if available) in the kernel space directly?
One reason is userspace: every usespace process have its own virtual address space. Suppose you have 4Gb of RAM on x86. So if we suggest that kernel owns 1Gb of memory (~800 directly mapped + ~200 vmalloc) all other ~3Gb should be dynamically distributed between processes spinning in user space. So how can you map your 4Gbs directly when you have a several address spaces?
why do we need zone_highmem on x86?
The reason is the same. Kernel reserves only ~800Mb for low mem. All other memory will be allocated and connected with particular virtual address only on demand. For example if you will execute a binary a new virtual address space will be created and some pages will be allocated for storing your binary code and data (heap ,stack ...). So the key attribute of high mem is to serve dynamic memory allocation requests, you never know in advance what will be triggered by userspace...

Resources