Подтвердить что ты не робот

Как получить доступ к физическим адресам из пользовательского пространства в Linux?

В системе на базе ARM, работающей под управлением Linux, у меня есть устройство, в котором память отображается на физический адрес. Из программы пространства пользователя, где все адреса являются виртуальными, как я могу читать контент с этого адреса?

4b9b3361

Ответ 1

Вы можете сопоставить файл устройства в пользовательской памяти процесса с помощью системного вызова mmap(2). Обычно файлы устройств представляют собой сопоставления физической памяти с файловой системой. В противном случае вам необходимо написать модуль ядра, который создает такой файл, или предоставляет способ сопоставить необходимую память с пользовательским процессом.

Другой способ - переназначение частей /dev/mem в пользовательскую память.

Изменить: Пример mmaping/dev/mem (эта программа должна иметь доступ к /dev/mem, например, иметь права root):

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Usage: %s <phys_addr> <offset>\n", argv[0]);
        return 0;
    }

    off_t offset = strtoul(argv[1], NULL, 0);
    size_t len = strtoul(argv[2], NULL, 0);

    // Truncate offset to a multiple of the page size, or mmap will fail.
    size_t pagesize = sysconf(_SC_PAGE_SIZE);
    off_t page_base = (offset / pagesize) * pagesize;
    off_t page_offset = offset - page_base;

    int fd = open("/dev/mem", O_SYNC);
    unsigned char *mem = mmap(NULL, page_offset + len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, page_base);
    if (mem == MAP_FAILED) {
        perror("Can't map memory");
        return -1;
    }

    size_t i;
    for (i = 0; i < len; ++i)
        printf("%02x ", (int)mem[page_offset + i]);

    return 0;
}

Ответ 2

busybox devmem

busybox devmem - это крошечная утилита CLI, которая называется mmaps /dev/mem.

Вы можете получить его в Ubuntu с помощью: sudo apt-get install busybox

Использование: чтение 4 байтов с физического адреса 0x12345678:

sudo busybox devmem 0x12345678

Напишите 0x9abcdef0 по этому адресу:

sudo busybox devmem 0x12345678 w 0x9abcdef0

Источник: https://github.com/mirror/busybox/blob/1_27_2/miscutils/devmem.c#L85

mmap MAP_SHARED

При mmapping /dev/mem вы, вероятно, захотите использовать:

open("/dev/mem", O_RDWR | O_SYNC);
mmap(..., PROT_READ | PROT_WRITE, MAP_SHARED, ...)

MAP_SHARED заставляет записи немедленно отправляться в физическую память, что облегчает наблюдение и имеет больше смысла для MAP_SHARED аппаратного регистра.

CONFIG_STRICT_DEVMEM и nopat

Чтобы использовать /dev/mem для просмотра и изменения обычной оперативной памяти в ядре v4.9, вы должны:

  • отключить CONFIG_STRICT_DEVMEM (устанавливается по умолчанию в Ubuntu 17.04)
  • передать nopat командной строки ядра nopat для x86

Порты ввода-вывода по-прежнему работают без них.

См. Также: mmap из /dev/mem завершается с ошибочным аргументом для адреса virt_to_phys, но адрес выровнен по странице

Сброс кеша

Если вы попытаетесь выполнить запись в ОЗУ, а не в регистр, память может быть кэширована ЦП. Как очистить кэш ЦП для области адресного пространства в Linux? и я не вижу очень переносимого/простого способа очистить его или пометить регион как недоступный для кэширования:

Так, может быть, /dev/mem нельзя надежно использовать для передачи буферов памяти на устройства?

К сожалению, в QEMU этого не наблюдается, поскольку QEMU не моделирует кэши.

Как это проверить

Теперь самое интересное. Вот несколько классных настроек:

  • Пользовательская память
    • выделение volatile переменную процесса на UserLand
    • получить физический адрес с помощью /proc/<pid>/maps + /proc/<pid>/pagemap
    • измените значение по физическому адресу с помощью devmem и наблюдайте за devmem пользовательского процесса
  • Ядро памяти
    • выделить память ядра с помощью kmalloc
    • получить физический адрес с помощью virt_to_phys и передать его обратно пользователю
    • изменить физический адрес с помощью devmem
    • запросить значение из модуля ядра
  • IO mem и устройство виртуальной платформы QEMU
    • создать платформенное устройство с известными физическими адресами регистра
    • используйте devmem для записи в реестр
    • смотреть, как printf выходит из виртуального устройства в ответ

Ответ 3

Я хочу читать и записывать данные на FPGA, выступая в качестве физической памяти. Начальный адрес: 0xFFFDF0000 Конечный адрес: 0xFFFDF007F

так что я должен ввести для "Смещение"? потому что я получаю ошибку шины при указании физического адреса в качестве значения смещения. пожалуйста помоги

Спасибо