Page 1 of 3

User-accessible MMIO

Posted: Fri Dec 25, 2009 3:27 am
by art_zh
Задача:
Системный сервис Колибри предоставляет пользователю широкий набор функций для работы с оборудованием (доступ к портам ввода-вывода, конфигурационному пространству PCI и даже перехват некоторых векторов прерываний). Предлагаю дополнить этот сервис каналом доступа к "бортовой" памяти устройств (MMIO, Memory-Mapped I/O).

Зачем это надо:
[*] для прямого тестирования железа, без заморочек с драйверами и IOCTL;
[*] для резкого ускорения разработки и значительного упрощения отладки новых драйверов КолибриОС;
[*] при наличии такого канала КОС становится идеальной средой разработки и наладки новой контрольно-измерительной аппаратуры.

Pro et Contra
Доступ к "бортовой" памяти устройств PCI, ATA и USB способен пробить заметную дыру в системной безопасности. К тому же подавляющему большинству пользователей он совершенно не нужен. Поэтому userMMIO-сервис имеет смысл отключить по умолчанию в бинарниках и исходных кодах, и (в отличие от сервиса PCI и i/o ports) включать его только после перекомпиляции ядра с "разрешительным" глобальным параметром.

Вторым ограничением является жесткая привязка сервиса uMMIO только к одному PCI-устройству, явно указываемому в системной переменной debug_pci_device в формате bbbbbbbb dddddfff (bus-device-function). Так можно быть уверенным, что программа, предназначенная для работы с одним устройством, не вломится случайно в адресное пространство другого.

API
Новый сервис предлагаю включить в логически связанный с ним сервис PCI-API в виде подфункий 11 (проверить канал MMIO), 12 (отобразить MMIO-страницу на пользовательский линейный адрес) и 13 (unmap MMIO page) функции 62.

Сразу хочу предупредить: приведенная ниже версия маппинга - очень сырая и дырявая. Прежде чем запрашивать маппинг физических блоков MMIO, юзер должен выделить в статической памяти или в куче своего процесса место для одной полной логической страницы, но ни разу не обращаться по этому адресу с чтением/записью до вызова fn 62:11. Иначе система успеет выделить этой странице реальный блок физической памяти, который будет безвозвратно потерян!

За один вызов маппится ровно одна страница, проверка 4К-выравнивания линейного адреса не производится:

Re: User-accessible MMIO

Posted: Fri Dec 25, 2009 6:27 am
by Serge
art_zh

Выдели память user_alloc (68.12), проверь линейный адрес и мапь туда MMIO страницы с флагами PG_SHARED|PG_UW и не забываем про кеширование PG_NOCACHE.

Обратный процесс - вызов user_free (68.13).

Update.

Размер mmio часто больше одной страницы. Таку что лучше мапить страницы commit_pages и освобождать unmap_pages.

Re: User-accessible MMIO

Posted: Fri Dec 25, 2009 11:46 am
by diamond
Serge wrote:Выдели память user_alloc (68.12), проверь линейный адрес и мапь туда MMIO страницы с флагами PG_SHARED|PG_UW
...и наслаждайся глюками, которые возникнут, когда при внезапном завершении программы менеджер памяти попытается такие страницы освободить.

Re: User-accessible MMIO

Posted: Fri Dec 25, 2009 12:02 pm
by art_zh
Serge
Спасибо, учту. PG_NOCACHE - зевнул, это точно
diamond wrote:
Serge wrote:Выдели память user_alloc (68.12), проверь линейный адрес и мапь туда MMIO страницы с флагами PG_SHARED|PG_UW
...и наслаждайся глюками, которые возникнут, когда при внезапном завершении программы менеджер памяти попытается такие страницы освободить.
А чем эти глюки принципиально будут отличаться от обычной незакрытой кучи?
Только тем, что реальные физические страницы не потеряются, а останутся на своем месте, по тем же BIOS-адресам.

Re: User-accessible MMIO

Posted: Fri Dec 25, 2009 12:12 pm
by diamond
art_zh wrote:А чем эти глюки принципиально будут отличаться от обычной незакрытой кучи?

Code: Select all

proc free_page
;arg:  eax  page address
           pushfd
           cli
           shr eax, 12                        ;page index
           bts dword [sys_pgmap], eax         ;that's all!
Вопрос на засыпку: что будет, если free_page (начало кода которой приведено выше) попытается освободить страницу, находящуюся за пределами физической памяти (на которую рассчитан битовый массив sys_pgmap)?

Re: User-accessible MMIO

Posted: Fri Dec 25, 2009 2:17 pm
by art_zh
diamond wrote:Вопрос на засыпку: что будет, если free_page (начало кода которой приведено выше) попытается освободить страницу, находящуюся за пределами физической памяти (на которую рассчитан битовый массив sys_pgmap)?
В данном конкретном случае - ничего страшного не случится. Поскольку физические адреса MMIO находятся в самой верхней зоне адресного пространства, просто будет поставлен бит где-то в самом конце таблицы sys_pgmap, куда менеджер памяти никогда не заглядывает.
Неплохо было бы при инициализации забить всю верхнюю зону этой таблицы единицами, тогда и на счетчике свободных страниц это никак не отразится

Code: Select all

; ( proc free_page)
.....
           bts dword [sys_pgmap], eax         ;that's all!
           cmc
           adc [pg_data.pages_free], 0
далее идет
cmp [page_start], eax
и сразу же - на выход, без каких-бы то ни было катастрофических последствий.

Re: User-accessible MMIO

Posted: Fri Dec 25, 2009 2:49 pm
by diamond
art_zh wrote:В данном конкретном случае - ничего страшного не случится. Поскольку физические адреса MMIO находятся в самой верхней зоне адресного пространства, просто будет поставлен бит где-то в самом конце таблицы sys_pgmap
Ответ неверный. Рекомендую подумать ещё раз, учитывая (уже приведённый) факт, что массив sys_pgmap рассчитан на покрытие физической памяти.

Re: User-accessible MMIO

Posted: Fri Dec 25, 2009 4:42 pm
by Serge
diamond

user_free расшареные страницы не трогает. В остальных случаях terminate вызывает destroy_app_space, та destroy_page_table

Code: Select all

proc destroy_page_table stdcall, pg_tab:dword

       push esi

       mov esi, [pg_tab]
       mov ecx, 1024
.free:
       mov eax, [esi]
       test eax, 1
       jz .next
           test eax, 1 shl 9
           jnz .next                      ;skip shared pages
       call free_page
.next:
       add esi, 4
       dec ecx
       jnz .free
       pop esi
       ret
endp
Или есть другой способ "разобрать" адресное пространство ?

Re: User-accessible MMIO

Posted: Fri Dec 25, 2009 5:03 pm
by diamond
Пардон, не заметил флага PG_SHARED. Тогда вопрос снимается.

Re: User-accessible MMIO

Posted: Fri Dec 25, 2009 5:33 pm
by maximYCH
Я написал план, пофиг на ваше мнение, выполняйте. (c) главнокомандующий
diamond, заметь, я такого не говорил и не писал (ни тут, ни в вике).
А то, что я написал в вике - обобщения с форума.

Re: User-accessible MMIO

Posted: Mon Dec 28, 2009 1:15 pm
by art_zh
Serge wrote:art_zh

Выдели память user_alloc (68.12), проверь линейный адрес и мапь туда MMIO страницы с флагами PG_SHARED|PG_UW и не забываем про кеширование PG_NOCACHE.

Обратный процесс - вызов user_free (68.13).

Update.

Размер mmio часто больше одной страницы. Таку что лучше мапить страницы commit_pages и освобождать unmap_pages.
Все так и сделал
pci32.7z (3.72 KiB)
Downloaded 429 times
Система грузится нормально :roll: вплоть до установки видеорежима.... Потом вышибает на перезагрузку.

Отключил АТI- драйвер - все загрузилось без проблем.
Похоже, ATIKMS где-то перехватывает сервис PCI?

Re: User-accessible MMIO

Posted: Mon Dec 28, 2009 6:22 pm
by Serge
art_zh

Не перехватывает, но активно юзает.
pci_api
pci_read8
pci_read16
pci_read32
pci_write8
pci_write16
pci_write32

А до изменений нормально грузилось ?

Re: User-accessible MMIO

Posted: Wed Dec 30, 2009 3:28 pm
by art_zh
Serge
Оказалось, что я зацепил pci_write копипастом, fixed.
Еще там была пара багов с перераскладкой регистров при системном вызове, разобрался с помощью diamond'а.
Сейчас вроде все нормально; для тестирования слегка переделал утилиту pcidev.asm, теперь она видит выделенные юзеру каналы MMIO, распознает и маппит RAM-блоки, после чего пробует прочитать первую страницу из бортовой памяти.

После 1 января выложу файлы здесь.
На svn залью когда дадут аккаунт.

Очень надеюсь, что новый сервис будет кому-нибудь так же полезен, как и мне. (а для меня это просто подарок к Новому году!)
Спасибо, с наступающим!

Re: User-accessible MMIO

Posted: Wed Dec 30, 2009 7:33 pm
by Ghost
Вначале нужно добавить поддержку PCI потом думать о том как его в user mode тянуть. Сейчас PCI это костыль таких размеров что многие думают что PCI есть, но на самом деле, его нет...

Re: User-accessible MMIO

Posted: Thu Dec 31, 2009 1:50 pm
by art_zh
pci32.7z (9.05 KiB)
новый PCI API и утилита PciDev.asm
Downloaded 423 times
Самая важная - функция 62:12.
Она не только маппит блок необходимой длины на юзерспейс, но еще и избавляет от нудных манипуляций с BAR-регистрами и физическими адресами. Единственное, что надо держать в памяти: длина блока задается в байтах, а смещение в физической памяти - в целых страницах (1стр = 4к байт).
Это так и задумано, иначе у юзера будет соблазн выставить не выравненный по началу страницы оффсет, что обязательно приведет либо к потере данных при маппинге, либо к сдвигу реальных линейных адресов относительно запрашиваемых приложением.