Device driver in virtual memory system - driver

Assume that there is a device using memory-mapped I/O i.e. there is a specific range of physical memory assigned to this device
If virtual memory system is not used, then it is quite straightforward to manipulate the device through read/write operations done with corresponding physical addresses
What if there is virtual memory system ?
Device driver needs to be aware of that specific range of physical memory assigned to that device, but how does it access that address range if it should use virtual addresses instead of physical ?

In case of memory mapped IO devices, any physical address shared by that device can be mapped to the kernel virtual memory using the ioremap() API [1].
Hence in your case, we can map the physical address 0x1234 using ioremap() to obtain its kernel virtual address and start writing data to this address.
[1] http://lxr.gwbnsh.net.cn/linux/arch/cris/mm/ioremap.c

It's been a long time since I've done it, but my recollection is that when you map a block of physical memory, the address in your user space corresponds to that physical memory. Writing to your user-space address is a write to the physical memory.

Related

Purpose of logical address?

What is the purpose of logical address? Why should CPU generate logical address? it can directly access relocatable register base address and limit to exe a process. Why should MMU make a mapping between logical and physical address?
Why?
Because this gives the Operating System a way to securely manage memory.
Why is secure memory management necessary?
Imagine if there was no logical addressing. All processes were given direct access to physical addresses. A multi-process OS runs several different programs simultaneously. Imagine you are editing an important letter in MS Word while listening to music on YouTube on a very recently released browser. The browser is buggy and writes bogus values to a range of physical addresses that were being used by the Word program to store the edits of your letter. All of that information is corrupt!
Highly undesirable situation.
How can the OS prevent this?
Maintain a mapping of physical addresses allocated to each process and make sure one process cannot access the memory allocated to another process!
Clearly, having actual physical addresses exposed to programs is not a good idea. Since memory is then handled totally by the OS, we need an abstraction that we can provide to processes with a simple API that would make it seem that the process was dealing with physical memory, but all allocations would actually be handled by the OS.
Here comes virtual memory!
The need of logical address is to securely manage our physical memory.
Logical address is used to reference to access the physical memory location.
A logical address is generated so that a user program never directly access the physical memory and the process donot occupies memory which is acquired by another process thus corrupting that process.
A logical address gives us a surety that a new process will not occupy memory space occupied by any other process.
In execution time binding, the MMU makes a mapping from logical address to physical address because in this type of binding:
logical address is specifically referred to as virtual address
The address actually has no meaning because it is there to illusion the user that it has a large memory for its processes. The address actually bear meaning when mapping occurs and they get some real addresses which are present in physical memory.
Also I would like to mention that the base register and limit register are loaded by executing privileged instructions and privileged instructions are executed in kernel mode and only operating system has access to kernel mode and therefore CPU cannot directly access the registers.
So first the CPU will generate the logical address then the MMU of Operating system will take over and do the mapping.
The binding of instruction and data of a process to memory is done at compile time, load time or at execution time. Logical address comes into picture, only if the process moved during its execution time from one memory segment to another. logical address is the address of a process, before any relocation happens(memory address = 10). Once relocation happened for a process(moved to memory address = 100), just to redirect the cpu to correct memory location=> memory management unit(MMU), maintains the difference between relocated address and original address(100-10 = 90) in relocation register(base register acts as relocation register here) . once CPU have to access data in memory address 10, MMU add 90(value in relocation register) to the address, and fetch data from memory address 100.

PCI Device Mapped Region for low physical memory

I have been reading about how the PCI subsystem gets configured from Bootup, BIOS involvement and mapping of device addresses i.e the BAR's into system Memory.
From the diagram above I am assuming that the address space is physical 4GB RAM with 4GB physical addresses. So, As can be seen above 3GB the device memory is mapped. What happens to this memory on 2GB physical RAM addresses.
If suppose my assumption is wrong and the above map shows virtual address for a 32 bit system. Then how is the device memory mapped to physical addresses for DMA. Is the mapping permanent (non swappable and changeable).
Please help me understand this concept.
If I understand your question, nothing different happens on a 2GB system. There will simply be a "hole" in the physical address space between 2GB and 3GB; that is, there simply won't be a hardware device decoding the addresses here. But otherwise there is no significant difference with respect to PCI devices: they will still be assigned space in the region above 3GB.
It's important to note that the map you show above (physical address space) doesn't necessarily stop at 4GB (since about 1995). Most modern x86 processors have more than 32 address bits. This is why you now often get systems with more than 4GB RAM. And there may be additional holes in the address space above 4GB too.
Actually using the RAM above 4GB requires either the processor's 64-bit mode or PAE (Physical Address Extension) which offers a way to address more than 4GB of physical space in 32-bit mode. [There is also PSE-36 {Page Size Extension} but that's much less commonly used.]
The map you're showing above is specific to physical address space. The x86 virtual address space, (when the processor is operating in 32-bit mode) is 4GB in size, but it does not have all the reserved areas in your diagram. Indeed, the layout of the virtual address space is totally dependent on and determined by the operating system. The usual way that it's configured in linux reserves the part of the virtual address space below the 3GB line for user-mode, and the area above 3GB for kernel-mode. However, this configuration can be changed via the kernel config.
Mapping of the physical address space into virtual address space is managed by the operating system kernel on a page by page basis. A virtual page may be directed either to system RAM or to a PCI device. And note that the page size can vary too, depending on how the processor and page tables are configured.

Linux memory manager infringes on PCI memory

My board has a Cavium Octeon NPU, running Linux kernel 2.6.34.10 that acts as a PCIe Root Complex. It is connected to PCIe switch, as are some other peripheral devices (Endpoints), among which there is Marvell's 9143 PCI-to_SATA controller based SSD.
When PCIe is initially enumerated, PCI driver on Octeon adds up the sizes of all the prefetchable memory resources and programs the PLIMIT and PBASE registers on the upstream switch port accordingly. In my case that address range is 0x80000000 - 0xEFFFFFFF.
After that, I would expect that address range to be inaccessible to kernel memory manager allocating for DMA buffers etc. And yet, I see the kernel, at some point starts sending SCSI requests to the SSD device, where scatter-gather list elements fall within this address range. I confirmed this, by looking at PCI analyzer trace. Naturally, when SSD controller receives such an address, it tries to access it (DMA read or write), and fails, because upstream switch port refuses to forward this request upstream to Root Complex, because it is programmed to think that this address would be downstream from it. (Interestingly enough, it mostly happens when I manipulate large files, I see that kernel allocated buffer addresses grow downward, until they dip below 0xEFFFFFFF)
Hence, the question: shouldn't PCI enumeration/rescan code, tell the kernel - these are PCI devices register addresses and therefore are off-limit for DMA buffer allocation? Or is it responsibility of each individual device driver to reserve its prefetchable memory? Marvell driver I use reserves regular memory BAR, but not the prefetcheable one. Is that a problem?
Thanks in advance and apologies for lengthy description.

Is is necessary to map the memory allocated to the device by the OS to a virtual memory space?

example while writing a driver we do the following
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
We get the info about the memory allocated to the device.
So is it necessary that I use this memory using virtual address
virt_base = ioremap(res->start, resource_size(res));
Can't we use the physical address itself to address the memory?
If we can, so are there any specific advantages of using virtual memory or this is how kernel wants us to do...
Yes, it is absolutely necessary. (On x86) Once paging is enabled in the CPU, all addresses visible to the OS (so you, the driver developer) are virtual addresses. In other words, any address you read from or write to will be interpreted by the CPU as a virtual address. It will then go through the page table hierarchy to finally arrive at a physical address to put on the bus.
You can't use physical addresses - they will not be mapped, or mapped to something other than what you want. This is why ioremap must exist and be used.

Confused over memory mapping

I've recently started getting into low level stuff and looking into bootloaders and operating systems etc...
As I understand it, for ARM processors at least, peripherals are initialized by the bootloader and then they are mapped into the physical memory space. From here, code can access the peripherals by simply writing values to the memory space mapped to the peripherals registers. Later if the chip has a MMU, it can be used to further remap into virtual memory spaces. Am I right?
What I don't understand are (assuming what I have said above is correct):
How does the bootloader initialize the peripherals if they haven't been mapped to an address space yet?
With virtual memory mapping, there are tables that tell the MMU where to map what. But what determines where peripherals are mapped in physical memory?
When a device boots, the MMU is turned off and you will be typically running in supervisor mode. This means that any addresses provide are physical addresses.
Each ARM SOC (system on Chip) will have a memory map. The correspondece of addresses to devices is determined by which physical data and address line are connect to which parts of the processor. All this information can be found in a Technical reference manual. For OMAP4 chips this can be found here.
There are several ways to connect off-chip device. One is using the GPMC. Here you will need to sepcify the address in the GPMC that you want to use on the chip.
When the MMU is then turned on, these addresses may change depending on how the MMU is programmed. Typically direct access to hardware will also only be available in kernel mode.
Though this is an old question, thought of answering this as it might help some others like me trying to get sufficient answers from stackoverflow.
you explanation is almost correct but want to give little explanation on this one:
peripherals are initialized by the bootloader and then they are mapped into the physical memory space
Onchip peripherals already have a predefined physical address space. For other external IO mapped peripherals (like PCIe), we need to config a physical addr space, but their physical address space range is still predefined. They cannot be configured at random address space.
Now to your questions, here are my answers..
How does the bootloader initialize the peripherals if they haven't been mapped to an address space yet?
As I mentioned above, all (on-chip)peripherals have physical address space predefined (usually will be listed in Memory map chapter of processor RM). So, boot loaders (assuming MMU is off) can directly access them.
With virtual memory mapping, there are tables that tell the MMU where to map what. But what determines where peripherals are mapped in physical memory?
With VMM, there are page tables (created and stored in physical DRAM by kernel) that tells MMU to map virtual addr to physical addr. In linux kernel with 1G kernel virt space (say kernel virtual addrs from 0xc0000000-0xffffffff), on-chip peripherals will need to have a VM space from within the above kernel VM space (so that kernel & only kernel can access it); and page tables will be setup to map that peripheral virt addr to its actual physical addr (the ones defined in RM)
You can't remap peripherals in ARM processor, all peripheral devices correspond to fixed positions in memory map. Even registers are mapped to internal RAM memory that has permanent fixed positions. The only things you can remap are memory devices like SRAM, FLASH, etc. via FSMC or similar core feature. You can however remap a memory mapped add-on custom peripheral that is not part of the core itself, lets say a hard disk controller for instance, but what is inside ARM core its fixed.
A good start is to take a look at processor datasheets at company sites like Philips and ST, or ARM architecture itself at www.arm.com.

Resources