
Raio-x de latência para hardware não documentado
Uma ferramenta exploratória para temporização de MMIO — meça o tempo de qualquer endereço físico e disseque o hardware a partir da latência.

Surpreendentemente útil para engenharia reversa de hardware, impressão digital de hipervisores, atividade de dispositivos por canal lateral, caracterização de registradores, calibração de gatilhos maliciosos e criação de instruções de máquina absurdamente longas.
O primeiro megabyte de memória física é um exemplo fácil para começar, mesmo que sua estrutura já seja bem conhecida.

As fronteiras de latência nos permitem dividir o espaço de endereçamento sem depender de layouts reportados.
sudo ./mmiotic --start-address 0x0 --end-address 0x100000 --stride 4 --count 20 --quiet-mmap0x9FFFF a ~380 cy, depois o buraco de vídeo de 128 KB, que se divide em dois em 0xB0000. A mudança na variância em 0x20000 pode indicar um page walk diferente para a página nula.A0000–AFFFF: lento e instável (996 cy, stdev 327), roteado para a Radeon ligada mas ociosa. B0000–BFFFF: rápido e rígido (780 cy, stdev 3.2, lê ffffffff), reivindicado por ninguém. Dados de aparência semelhante, mas uma diferença de 100x na variância.C0000–FFFFF: /proc/iomem diz "System ROM", mas o scan mostra latência de DRAM, não velocidade de flash — a BIOS é espelhada na DRAM.Faça um scan do espaço de configuração do root complex (00:00.0, 4 KB) em busca de outliers de latência contra um piso plano de ~675 ciclos:

A latência do mailbox é significativamente maior do que os dados ao redor, e os picos duplicados e as variâncias equivalentes nos permitem associar registradores funcionalmente semelhantes.
sudo ./mmiotic --start-address 0xf8000000 --end-address 0xf8001000 --stride 4 --count 2000xe4 (1218 cy, valor 80e3110b) e 0xa4 (1199 cy, valor deadbeef). e4 é um doorbell documentado; a4 não é documentado.e4 é público.deadbeef é lido como um sentinela de não inicializado/erro — mesmo mailbox, a4 não implementado ou alimentado com entrada inválida.Latências cuidadosamente selecionadas às vezes podem ser usadas em cenários incomuns de exploração (MCHAMMER, smiiiiiiiiiiiiiiii):

Aqui, uma Radeon ociosa e sem driver transforma uma leitura alinhada de 4 bytes em uma parada de ~100.000 ciclos.
sudo ./mmiotic --start-address 0x90e00000 --end-address 0x90e00100 --stride 4 --count 50 — varra o início do BAR da GPU (0x90e00000, 256 KB). 0x90e00008 custa 110.152 cy; 0x90e00018, 16 bytes adiante, volta a ser rápido a 1.523 — por registrador, não por página.sudo ./mmiotic --start-address 0x90e00000 --end-address 0x90e40000 --stride 4 --count 1 --binary — --binary sonda em ordem de inversão de bits, então toda a janela de 256 KB é coberta uniformemente após 1.012 sondas, mapeando um bloco contíguo de 48 KB onde todo registrador é lento.Idealmente, ler um endereço físico seria uma operação relativamente segura, mas mmiotic é especialmente bom em encontrar acidentalmente as exceções:

Por exemplo, na plataforma acima, uma leitura de 1 byte de 0xdc5003b0 — offset 0x3b0 de um BAR de registradores de iGPU Zen 4 sem driver (Região 5, 0xdc500000, 512 KB) — reinicia o sistema de forma confiável.
sudo ./mmiotic --address 0xdc5003b0 --size 1 --count 1. Sem saída; a máquina reinicia.0x3ac e 0x3b4 em ambos os lados leem 00000000 a ~3.200 cy e são inofensivos.0x3a0–0x3fc encontra 7 dwords venenosas intercaladas com 17 seguras.sudo busybox devmem 0xdc5003b0 32 e sudo dd if=/dev/mem bs=1 count=1 skip=$((0xdc5003b0)) derrubam a máquina se você preferir pular o intermediário.[!WARNING] Algumas plataformas serão reiniciadas quando regiões de endereço específicas forem sondadas pelo
mmiotic. Tenha cuidado onde você usa isso.
| Opção | Nomes |
|---|---|
-b/-d/-f/-r | PCI --bus/--device/--function/--register — decodificados com base no ECAM |
-o, --offset <n> | offset a partir da base MMIO (ignora a decodificação B/D/F) |
-A, --address <n> | um endereço físico; define a base da região implicitamente |
-a/-z | --start-address/--end-address — uma faixa física; implica --scan |
A base e o tamanho do ECAM são detectados automaticamente a partir do ACPI MCFG (/sys/firmware/acpi/tables/MCFG). Substitua com -M, --mmio-base / -Z, --mmio-size.
| Opção | Efeito |
|---|---|
-S, --scan | percorre todos os endereços na região alvo |
-t, --stride <n> | passo entre endereços (padrão: 4) |
-n, --limit <n> | parar após este número de endereços |
--binary | sonda em ordem de inversão de bits — após k sondas a faixa tem cobertura uniforme com granularidade de ~range/k (veja o aviso acima) |
-x, --limited | faixa de registradores limitada (0x00–0xff vs 0x000–0xfff) |
-e, --skip | pula funções que leem 0xffffffff no offset 0 (dispositivos ausentes) |
-I, --iomem | escaneia todas as regiões de nível superior não–System-RAM em /proc/iomem |
-R, --ioregion <name> | escaneia regiões de /proc/iomem cujo rótulo corresponde a <name>, em qualquer profundidade |
--find-target/--find-longest transformam a varredura em busca:
| Opção | Efeito |
|---|---|
-F, --find-target <s> | encontra um endereço cujo tempo de acesso atinja s segundos e então aumenta a largura (4b não alinhado → 8/16/32/64/512b) para elevá-lo ainda mais |
-G, --find-longest | mesma busca, mas esgota todos os candidatos em vez de parar no primeiro resultado |
-B, --fallbacks <n> | candidatos levados para a fase de escalada (padrão: 10) |