From 0c394d4d71bbe6734b79c158900a9d375d61c5f4 Mon Sep 17 00:00:00 2001 From: Neil Ramaswamy <33679306+neilramaswamy@users.noreply.github.com> Date: Fri, 5 Aug 2022 15:42:14 -0700 Subject: [PATCH 1/2] readme wording changes --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5bb0945..6a2873f 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ As described in [BCM2835-ARM-Peripherals](https://www.raspberrypi.org/app/upload * *ARM Virtual Address*: The address used in the [virtual address space](https://en.wikipedia.org/wiki/Virtual_address_space) of a Linux process. * *ARM Physical Address*: The address used when accessing physical memory. Since peripherals on BCM2835 are [memory-mapped](https://en.wikipedia.org/wiki/Memory-mapped_I/O), this address is used to access peripherals directly. -* *Bus Address*: This is the address used by the DMA engine. +* *Bus Address*: This is the address used by the DMA engine. A bus address is an address as seen by hardware peripherals. The *physical addresses* of the peripherals range from *0x3F000000* to *0x3FFFFFFF* and are mapped onto *bus address* range *0x7F000000* to *0x7FFFFFFF*. We can convert between them like this: @@ -30,7 +30,7 @@ The *DMA control blocks* on BCM2835 are organized as a *linked list*, with the * ## Mapping Peripherals into Virtual Memory -The first thing is to get access to the peripherals. As memtioned above, peripherals can be accessed by user programs with their *physical address*. In order to configure the DMA channel, we need to bring the DMA controller registers into *virtual memory*. +The first thing is to get access to the peripherals. As mentioned above, peripherals can be accessed by user programs with their *physical address*. In order to configure the DMA channel, we need to bring the DMA controller registers into *virtual memory*. The way we access these memory-mapped peripherals is to `mmap` them from the `/dev/mem` device, which is an image of main memory. I wrapped this procedure in a function, note that I omitted error handling code here for clarity. @@ -68,7 +68,7 @@ volatile dma_channel_hdr = (DMAChannelHeader *)(dma_base_ptr + DMA_CHANNEL * 0x1 The next step is to allocate our control blocks and a buffer to store DMA results. What's special about this is that since DMA accesses uses *bus address*, we need to find a way to know the *bus address* of our allocated memory region. -As bus addresses can be calculated from physical addresses, a straightforward way to get physical addresses out of virtual addresses may be using Linux's [`pagemap`](https://www.kernel.org/doc/Documentation/vm/pagemap.txt) interface. However, this seems to be reliable because we can't guarantee the memory we have is cache coherent, which is [**crucial to proper DMA**](https://en.wikipedia.org/wiki/Direct_memory_access#Cache_coherency). Also, the exact physical address backing a certain virtual address may be **subject to change**. Thus, **I do not recommend using** `pagemap`. +As bus addresses can be calculated from physical addresses, a straightforward way to get physical addresses out of virtual addresses may be using Linux's [`pagemap`](https://www.kernel.org/doc/Documentation/vm/pagemap.txt) interface. However, this seems to be unreliable because we can't guarantee the memory we have is cache coherent, which is [**crucial to proper DMA**](https://en.wikipedia.org/wiki/Direct_memory_access#Cache_coherency). Also, the exact physical address backing a certain virtual address may be **subject to change**. Thus, **I do not recommend using** `pagemap`. What comes to the rescue here is the [mailbox property interface](https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface). As it's developed for communication between the ARM and the GPU, which I guess also suffers from cache coherency problems, it provides ways to [allocate](https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface#allocate-memory) contiguous memory on the **coherent** portion of L2 cache & RAM and [lock](https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface#lock-memory) it on a fixed bus address. It looks perfectly suitable for DMA, so it's becoming a standard way for projects adopting DMA. We are gonna use it, too. From 38b74acfed3259a8303818825355bd59ce0e5457 Mon Sep 17 00:00:00 2001 From: Neil Ramaswamy Date: Thu, 18 Aug 2022 17:03:18 -0700 Subject: [PATCH 2/2] Clarify physical/virtual/bus address meaning --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6a2873f..645304a 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,13 @@ I tested my code on my Raspberry Pi 3 B+, but it seems that the only difference ## A little Background -As described in [BCM2835-ARM-Peripherals](https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf) (the "*datasheet*"), There are three types of addresses in Raspberry Pi: +As described in [BCM2835-ARM-Peripherals](https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf) (the "*datasheet*"), there are three types of memory addresses: -* *ARM Virtual Address*: The address used in the [virtual address space](https://en.wikipedia.org/wiki/Virtual_address_space) of a Linux process. * *ARM Physical Address*: The address used when accessing physical memory. Since peripherals on BCM2835 are [memory-mapped](https://en.wikipedia.org/wiki/Memory-mapped_I/O), this address is used to access peripherals directly. -* *Bus Address*: This is the address used by the DMA engine. A bus address is an address as seen by hardware peripherals. +* *ARM Virtual Address*: The address used in the [virtual address space](https://en.wikipedia.org/wiki/Virtual_address_space) of a Linux process. +* *Bus Address*: The address that hardware peripherals use to access memory. This is the address used by the DMA engine. Note that bus address `A` does not necessarily map to physical address `A`; in fact, in our case it doesn't. Linus Torvalds elaborates more on this idea [here](https://tldp.org/LDP/khg/HyperNews/get/devices/addrxlate.html). -The *physical addresses* of the peripherals range from *0x3F000000* to *0x3FFFFFFF* and are mapped onto *bus address* range *0x7F000000* to *0x7FFFFFFF*. We can convert between them like this: +The *physical addresses* of the peripherals range from *0x20000000* to *0x20FFFFFF* and are mapped onto *bus address* range *0x7E000000* to *0x7FFFFFFF*. We can convert between them like this: ``` c #define BUS_TO_PHYS(x) ((x) & ~0xC0000000