Maurice's Notes
Blog
Low Level Computing
Low Level Computing
  • Operating Systems
    • General Operating Systems
      • OS Structure
      • Main Memory
        • Basic Hardware
        • Address Binding
        • Memory Address Register
      • Booting
        • MBR (Master Boot Record)
        • Global Descriptor Table
      • Direct Memory Access (DMA)
        • DMA
      • Processes
        • Basics
        • Process Scheduling
    • Linux Operating System
      • Linker Scripts
      • Position Independent Code/Executable
      • Relocation
      • Understanding PLT and GOT
    • Windows Operating System
      • Page 1
    • Real-Time Embedded Systems
      • Real-Time Scheduling
        • Cyclic Executive
  • Computer Architecture
    • Architecture Fundamentals
      • Introduction
      • Cache Basics
      • Cache Memory
      • A Few CPU Formulas
    • RISC Architectures
      • ARM
        • ARM Design Philosophy
        • RISC Review
        • Exceptions, Interrupts, & Vector Table
        • ARM Pipelines
        • ARM Registers
        • ARM Branch Instructions
        • ARM CSPR (Instructions)
        • ARM Data Processing Instructions
        • Load/Store Instructions
        • Profiling Cycle Counter
        • Compiler Optimizations
      • RISCV
    • CISC Architectures
    • Cache Coherency
      • Basic Introduction
      • Memory Sequential Consistency
  • Exploits
    • Walkthrough: Return-to-Libc
    • Access Physical Memory
  • Compilers & Runtime Systems
    • Introduction
      • Programming Language Basics
      • Static Scope
    • Syntax Translation
      • Syntax Defined
      • Parsing
    • Algorithms
      • FIRST FOLLOW (Top-Down) Parsing
      • Building a Recursive Descent Parser
      • Construction: Regular Expression -> NFA
Powered by GitBook
On this page
  • Introduction
  • DMA Output
  • DMA Input
  • Multiple Buffers

Was this helpful?

  1. Operating Systems
  2. General Operating Systems
  3. Direct Memory Access (DMA)

DMA

Introduction

One of the primary motives for DMA is parallelism, allowing I/O devices to transfer data over a but without interrupting the processor.

DMA Output

To understand DMA output, consider an example using DMA to write data to a disk block. The operating system creates a buffer, places data into the buffer, creates a write request (in memory) and passes a pointer to the write request to the I/O device.

Once the device receives the pointer, the processor can continue to executing other processes.

The DMA hardware will user the bus to access the write request and obtain the buffer address to transfer data from buffer to disk. Once an entire block is complete, the disk interrupts the processor.

DMA Input

Similarly, to receive data from a disk block using DMA, the OS creates a buffer to hold the data and issues a read request (in memory), and passes a pointer the request to the I/O device. The processor is used to initiate this request; once the device has the pointer to the request, the processor is free to move on.

The DMA hardware uses the bus to access the request, locate the buffer, and transfers a block from the disk device to the buffer. Once complete, the disk interrupts the processor.

In both cases, only one interrupt occurs per block transferred.

Multiple Buffers

The previous examples of DMA Input/Output are indeed overly simplistic; in actuality, an operating system will allocate multiple request blocks (and buffers) and link them together as a liked list. The address of the list is shared.

Consider what may happen in the context of networking. A linked list is passed by the operating system to the the networking device. Each node in the list contains a pointer to a buffer and a status bit; the network device uses a request node to locate the buffer and uses DMA to copy the packet into the buffer. After generating an interrupt, it moves on to the next request.

Ring Buffer

Most devices use a ring buffer, whereby the last node points to the first. This prevents the devices from reaching the end of the list.

The code snippets included below are merely examples to illustrate the described functionality.

// example node structure

typedef struct _node {
    unsigned int status: 1;
    void *buffer;
    struct node* next;
} request_t;

When receiving input, the operating system initializes each node in the list, setting the status to EMPTY (as an example), and points to a buffer. After filling a buffer, the DMA hardware changes the status to FULL and interrupts.

// Example initialization

#define bitcheck(byte,nbit) ((byte) &   (1<<(nbit)))
#define BUFFER 512
#define EMPTY 0
#define FULL 1

void initialize_ring_buffer(request_t *head)
{
    request_t *current = head;
    while (current->next != NULL) {
        current->buffer = malloc(BUFFER);
        if (!current->buffer) {
            perror("Failed to allocate Buffer");
            return 1;
        }
        
        current->status = EMPTY;
        current = current->next;
    }
}

PreviousDirect Memory Access (DMA)NextProcesses

Last updated 7 months ago

Was this helpful?