Я совершенно не понимаю, как Linux управляет общей памятью ввода-вывода для взаимодействия с устройствами, которые ее используют.
Если я правильно понял, ядро Linux начинает с отображения по адресу 0x100000 (чтобы избежать первых мегабайт устаревших данных оперативной памяти и сохранить их в смежных ячейках памяти), а затем после входа в защищенный режим:
- на 32-битных системах есть такое отображение
ZONE_NORMAL должен быть ниже 896 МБ, поэтому отображение между линейным 1 ГБ ядра и физическими 896 МБ всегда возможно. Давайте просто проигнорируем ZONE_DMA на данный момент (я читал, что это только для устаревших систем, так как PCI теперь может использовать передачи DMA везде в памяти)
- на 64-битных системах линейное адресное пространство ядра должно начинаться с PAGE_OFFSET= 0xffff810000000000 и далее
В обоих случаях, если адрес в пространстве ядра больше PAGE_OFFSET, он должен ссылаться на отображение ioremap (чтобы разрешить его с помощью разбиения на страницы), если он меньше PAGE_OFFSET, он может быть разрешен простым NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET. Это правильно?
Бонусный вопрос: когда ядро запущено и работает, и уборка завершена, оно все еще физически находится от 0x100000 и далее (в пределах первого ГБ)? Даже на 64-битных системах?
решение1
На ПК диапазоны ввода-вывода, отображаемые аппаратной памятью, назначаются BIOS физическим адресам памяти между 3GiB и 4 GiB. Когда драйвер запрашивает доступ к памяти, ядро отображает его где-то в виртуальном адресном пространстве ядра.
Ни один из ваших двух других вопросов, похоже, не имеет никакого отношения к общей памяти, но:
В обоих случаях, если адрес в пространстве ядра больше PAGE_OFFSET, он должен ссылаться на отображение ioremap (чтобы разрешить его с помощью разбиения на страницы), если он меньше PAGE_OFFSET, он может быть разрешен простым NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET. Это правильно?
Умственно, да. Аппаратное обеспечение использует таблицы страниц в обоих случаях.
решение2
Подумайте, как ваш вопрос выглядит, как работает ioremap..
vaddr = ioremap(paddr_io_mapped_device , size);
vaddr возвращает виртуальный адрес в пространстве ядра. Ядро создает записи таблицы страниц для диапазона виртуальных адресов (vaddr, size) и сопоставляет его с физическим адресом paddr_io_shared_device. Таким образом, если вы обращаетесь к диапазону виртуальных адресов, это будет так же хорошо, как и обращение к физическому адресу внутри устройства io_mapped.
Важно, что возвращенный vaddr - этоне кэшируется. Каждый раз, когда вы читаете/записываете диапазон адресов, он будет считываться/записываться с устройства io_mapped, а не из кэша.