Как регистры SOC отображаются в памяти операционной системы Linux?

Добрый день! У меня возникли вопросы по поводу отображения регистров SOC в адресное пространство памяти Linux. В частности, имея описание модуля WDT для SOM Rockchip RK3568: 

```dts
watchdog@fe600000 {
    compatible = "snps,dw-wdt";
    reg = <0x00 0xfe600000 0x00 0x100>;
    clocks = <0x1f 0x116 0x1f 0x115>;
    clock-names = "tclk\0pclk";
    interrupts = <0x00 0x95 0x04>;
    status = "okay";
    phandle = <0x1c9>;
};
```

Мне интересно, как можно узнать адреса этих регистров после инициализации устройств и загрузки операционной системы? 

Кроме того, если существует процесс, который записывает данные в определённую область памяти, как можно определить, являются ли эти адреса регистрами SOM? Есть ли способ получить возможный адрес в пространстве SOM и сопоставить его с доступными модулями, используя документацию datasheet?
  • 21 ноября 2024 г. 6:03
Ответы на вопрос 2
Добрый день!

Регистры SOC (System-On-Chip) отображаются в адресном пространстве памяти операционной системы Linux, и это достигается с помощью механизма, называемого "памятью устройства" (memory-mapped I/O). Ваша структура устройства в Device Tree Source (DTS), которую вы привели, содержит информацию о регистре, в том числе его адреса.

### Определение адресов регистров

После загрузки операционной системы и инициализации устройств, адреса регистров можно обнаружить в нескольких местах:

1. **Device Tree**: Ваша запись в DTS описывает адреса регистров WDT (watchdog timer) как `reg = <0x00 0xfe600000 0x00 0x100>;`. Это значит, что регистры для WDT находятся по адресу `0xfe600000`, а их размер – `0x100` байт.

2. **Linux Kernel**: Когда устройство инициализируется, информация из Device Tree загружается в ядро Linux, и драйвер устройства получает доступ к этим адресам. Обычно адреса регистров отображаются в виртуальной памяти с использованием функции `ioremap()`.

3. **Драйверы устройства**: В драйверах, написанных для вашего устройства, вы можете найти код, который использует `ioremap()` для сопоставления физических адресов с виртуальными адресами, доступными в драйвере. Например:
   ```c
   void __iomem *wdt_base;
   wdt_base = ioremap(0xfe600000, 0x100);
   ```

### Определение, являются ли адреса регистрами SOC

Чтобы убедиться, что определенный адрес в памяти принадлежит регистрам SOC, вы можете использовать следующие шаги:

1. **Сравнение с картой адресов**: Составьте карту адресов на основе документации SOC. Каждое устройство в системе будет иметь назначенный диапазон адресов. Сверьтесь с ним, чтобы определить принадлежность.

2. **Доступ к `/proc/iomem`**: Файл `/proc/iomem` в Linux содержит информацию об используемых адресах памяти и их назначениях. Вы можете просмотреть этот файл для проверки, какие устройства отображены на различных адресах. Например:
   ```bash
   cat /proc/iomem | grep fe600000
   ```

3. **Используйте утилиты**: Существуют утилиты, такие как `devmem`, которые позволяют читать и записывать в произвольные адреса физической памяти. Это полезно, но следует проявлять осторожность, так как некорректные операции могут привести к нестабильности системы.

Рекомендуется ознакомиться с документацией вашего конкретного SOC (в данном случае Rockchip RK3568), чтобы найти детальные описания адресов и регистров. Это позволит точно определить, какие адреса являются регистрами и как они формируют адресное пространство памяти в вашей системе.
Как узнать, какой адрес этих регистров уже после инициализации устройств и загрузки ОС?

Физический адрес -- как и написано в dts: 0xfe600000. Виртуальный адрес -- какой-то сравнительно случайный, выделенный вызовом ioremap() или какой-нибудь его обёрткой. Если драйверу нужен доступ к регистрам -- драйвер просто вызывает ioremap() сам и получает адрес. Если доступ нужен в юзерспейсе -- можно (при наличии разрешений) сделать mmap() файлу /dev/mem по смещению равному физическому адресу устройства.

Или обратная задача: есть процесс, который пишет в некоторую область памяти, как узнать, возможно, это какие-то регистры SOM

Сделать cat /proc/<pid>/maps и посмотреть, что отображено в эту область виртуальных адресов.

Но обычно люди не отображают регистры устройств напрямую в пользовательскую память, максимум -- отображают файл обрабатываемый драйвером устройства, а драйвер уже может выступить дополнительным слоем абстракции и подставить в отображение часть адресного пространства устройства, если такое им поддерживается. В этом случае для понимания что куда отображается без чтения исходников драйвера не обойтись.
Похожие вопросы