Interfaces no QEMU: UART e conceitos de MMIO

TL;DR


1. UART no QEMU virt

A máquina virt expõe uma UART em um endereço MMIO fixo:

1
UART0 base: 0x10000000

Escrever um byte nesse endereço imprime um caractere.

Escrita mínima na UART

1
2
3
4
5
6
7
// src/uart.c (veja o arquivo completo em src/)
#define UART0_BASE 0x10000000u
static volatile u8 *const uart0 = (volatile u8 *)UART0_BASE;

void uart_putc(char c) {
  *uart0 = (u8)c;
}

2. Um exemplo de UART executável

1
2
3
4
5
6
7
8
// src/hello_uart.c
#include "types.h"
#include "uart.h"

int main(void) {
  uart_puts("UART is alive!\n");
  return 0;
}

Compile e rode:

1
2
3
4
5
riscv64-unknown-elf-gcc -O0 -g -ffreestanding -nostdlib \
  -march=rv32im -mabi=ilp32 -T src/link.ld \
  src/start.s src/uart.c src/hello_uart.c -o build/hello_uart.elf

qemu-system-riscv32 -M virt -nographic -bios none -kernel build/hello_uart.elf

3. Visão conceitual: JTAG, SPI, I2C

São interfaces de hardware comuns, mas neste livro nós apenas descrevemos:

Como rodamos tudo no QEMU, não precisamos de fiação física, adaptadores ou placas.


Exercícios

  1. Altere a string da UART e verifique a saída.
  2. Adicione uma função que imprima um valor em hexadecimal com uart_puthex32.
  3. Pesquise o mapa de memória do QEMU virt e liste mais um dispositivo MMIO.

Resumo