Skip to content

Commit 3b6ba1f

Browse files
committed
dma lab
1 parent 795d759 commit 3b6ba1f

File tree

1 file changed

+69
-8
lines changed

1 file changed

+69
-8
lines changed

_labs/dma.md

+69-8
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,83 @@ toc: true
44
title: "Lab 8: DMA"
55
short_title: DMA
66
number: 8
7-
under_construction: true
7+
under_construction: false
88
---
99

1010
In this lab you will create a specialized driver for a DMA engine, allowing for offloading of sprite drawing.
1111

1212
## Objectives
13-
* Learn about, and use, a AXI master device.
13+
* Learn about, and use, an AXI master device.
1414
* Learn about DMA engines, and their mode of operation.
1515

1616
## Preliminary
1717

18-
* Read about [DMA](https://en.wikipedia.org/wiki/Direct_memory_access) on Wikipedia.
19-
* Read about the [AMD AXI CDMA]({% link media/docs/pg034-axi-cdma.pdf %}). Read over the:
20-
* Introduction & Features (Page 1)
21-
* Overview & Block diagram (Page 5-7)
18+
### DMA
19+
Read about [DMA](https://en.wikipedia.org/wiki/Direct_memory_access) on Wikipedia.
2220

23-
*
24-
* Register Space (Page )
21+
### AMD AXI CDMA
22+
Read about the [AMD AXI CDMA]({% link media/docs/pg034-axi-cdma.pdf %}). Read over the:
23+
* Introduction & Features (Page 1)
24+
* Overview & Block diagram (Page 5-7)
25+
* Scatter Gather Mode (Page 34)
26+
* Scatter Gather Transfer Descriptor Definition (Page 36-41)
27+
* Register Space. Focus on registers applicable to the Scatter Gather mode (Page 13-31). Pay particular attention to *Table 3-1* as well as the note on the alignment of transfer descriptors. We won't be using interrupts in this lab, so you can ignore the interrupt output of the DMA.
2528

29+
### DMA.H
30+
Look over the functions in [dma.h](https://github.com/byu-cpe/ecen427_student/blob/main/userspace/drivers/dma/dma.h). The goal of this lab is to implement these functions in a *dma.c* file. This driver will be used to offload sprite drawing from the CPU to the DMA engine.
31+
32+
Unfortunately a sprite is not a simple contiguous block of memory, since each line of the sprite is in a different location in the pixel buffer memory. This means that we can't use a simple single-source, single-destination DMA transfer. Instead, we will use the Scatter Gather mode of the AXI CDMA to copy the sprite to the pixel buffer. Each line of the sprite will be handled by one transfer descriptor, and the CDMA will chain these together to copy the entire sprite without CPU intervention.
33+
34+
In order to accomplish this, we need a couple extra things:
35+
1. We need to know the **physical** address of the pixel buffer.
36+
1. We need some memory to store the transfer descriptors. This memory must be contiguous, and must be accesible by the DMA. The DMA does not work with virtual addresses, so we need to know the **physical** address of this memory as well, and need the ability to fill it.
37+
38+
### Graphics Buffer Address
39+
In order to get the physical address of the pixel buffer, you can use the `ECEN427_IOC_FRAME_BUFFER_ADDR` ioctl command on the HDMI driver. See the [ecen427_ioctl.h](https://github.com/byu-cpe/ecen427_student/blob/main/kernel/hdmi_ctrl/ecen427_ioctl.h) file. This will provide you with a 32-bit physical address of the pixel buffer. You can then use offsets from this address to determine the source and destination address for each transfer descriptor.
40+
41+
### DMA Descriptor Memory
42+
Another kernel driver is provided to you that will give you some access to a block of physical memory that you can use for your transer descriptor array. You will need to know a couple things about this memory:
43+
1. You need to know the physical address. You need to provide the physical address of your first and last transfer descriptor to the DMA engine. In addition, within each transfer descriptor, you need to provide the physical address of the next transfer descriptor. You can obtain this address via ioctl:
44+
45+
fd_dma_desc = open(SYSTEM_DMA_DESC_FILE, O_RDWR);
46+
ioctl(fd_dma_desc, DMA_DESC_IOC_BUFFER_ADDR, &dma_desc_array_phys_addr);
47+
48+
49+
1. You need to be able to write data to this buffer. You should populate your transfer descriptors in a temporary array, then use `write()` to copy the data to the kernel buffer:
50+
51+
lseek(dma_desc_id, 0, SEEK_SET);
52+
write(fd_dma_desc, dma_desc_array, num_descriptors * sizeof(...));
53+
54+
### Security
55+
The approach we are taking in this lab is not secure. We are providing a user space driver with access to a DMA engine that allows for reading and writing arbitrary physical memory locations. _**This is a massive security vulnerability**_. By reading arbitrary physical memory, a user could steal sensitive information from the system, including passwords, encryption keys, etc. In a typical system, only the kernel would have access to the DMA engine. However, for simplicity of development and debugging, we are doing this lab in user space.
56+
57+
58+
## Implementation
59+
60+
1. Implement a user space driver for copying sprites using the AXI CDMA. Implement the functions listed in [dma.h](https://github.com/byu-cpe/ecen427_student/blob/main/userspace/drivers/dma/dma.h) in a *dma.c* file.
61+
62+
1. Use the [dma_test](https://github.com/byu-cpe/ecen427_student/tree/main/userspace/apps/dma_test) application to verify that your driver is working correctly. This application will draw a sprite in the top-left corner of the screen, and then copy it to the three other corners using the DMA engine.
63+
64+
1. Use the [dma_benchmarking](https://github.com/byu-cpe/ecen427_student/tree/main/userspace/apps/dma_benchmarking) application to test how fast the DMA is compared to using the CPU to draw sprites. This application should report that the DMA takes about 0.7s to draw 100 sprites. Your board may be slightly faster or slower, but it should be about the same. The CPU runtime will depend on your implementation of the sprite drawing function, but will probably be a bit slower than the DMA.
65+
66+
## Submission
67+
Follow the instructions on the [Submission]({% link _other/submission.md %}) page.
68+
69+
## Suggestions
70+
71+
You might try approaching this lab in the following order:
72+
1. Create a *dma_init()* function that provides you access to the DMA registers via *mmap* (similar to your other user space drviers). You probably want to create helper functions for reading and writing to the registers.
73+
1. Implement the *dma_is_busy()* function by reading the appropriate register bit. Verify the the DMA engine is not busy.
74+
1. Get the physical address of the pixel buffer (using ioctl) and print the address to the console.
75+
1. Get the physical address of the DMA descriptor memory (using ioctl) and print the address to the console.
76+
1. Create a struct to represent a transfer descriptor, and create an array of these structs. Make sure the struct is sized such that you are following the alignment requirements of the DMA engine.
77+
1. First try to copy a single line of the sprite using the DMA engine:
78+
* To do this you only need to use a single transfer descriptor.
79+
* Calculate the source and destination addresses for the copy operation. Print these addresses and make sure they make sense relative to the pixel buffer (you want to be careful writing to arbitrary memory locations as you can easily crash the system).
80+
* Initialize the transfer descriptor with the source and destination addresses, and the length of the transfer.
81+
* Copy the transfer descriptor to the DMA descriptor memory.
82+
* Set the registers in the DMA engine. You will need to enable scatter gather mode, and set both the current and tail descriptor pointers to the physical address of your transfer descriptor.
83+
1. If you can get a single line to copy, try to copy the entire sprite:
84+
* Expand your previous code to initialize an array of transfer descriptors, with source and destination addresses for each line of the sprite.
85+
* Chain the transfer descriptors together by setting the next descriptor address in each descriptor.
86+
* Make sure the tail register is set to the last descriptor in the chain.

0 commit comments

Comments
 (0)