Задача:
Системный сервис Колибри предоставляет пользователю широкий набор функций для работы с оборудованием (доступ к портам ввода-вывода, конфигурационному пространству 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К-выравнивания линейного адреса не производится:
User-accessible MMIO
-
- Attachments
-
-
pci32.7z (3.72 KiB)Downloaded 449 times
-
Last edited by art_zh on Mon Dec 28, 2009 2:01 pm, edited 1 time in total.Евангелие от Иоанна: стих 1[/size]Code: Select all
; В начале было Слово: B32: mov ax, os_stack ; Selector for os
art_zh
Выдели память user_alloc (68.12), проверь линейный адрес и мапь туда MMIO страницы с флагами PG_SHARED|PG_UW и не забываем про кеширование PG_NOCACHE.
Обратный процесс - вызов user_free (68.13).
Update.
Размер mmio часто больше одной страницы. Таку что лучше мапить страницы commit_pages и освобождать unmap_pages.
Выдели память user_alloc (68.12), проверь линейный адрес и мапь туда MMIO страницы с флагами PG_SHARED|PG_UW и не забываем про кеширование PG_NOCACHE.
Обратный процесс - вызов user_free (68.13).
Update.
Размер mmio часто больше одной страницы. Таку что лучше мапить страницы commit_pages и освобождать unmap_pages.
...и наслаждайся глюками, которые возникнут, когда при внезапном завершении программы менеджер памяти попытается такие страницы освободить.Serge wrote:Выдели память user_alloc (68.12), проверь линейный адрес и мапь туда MMIO страницы с флагами PG_SHARED|PG_UW
Ушёл к умным, знающим и культурным людям.
Serge
Спасибо, учту. PG_NOCACHE - зевнул, это точно
Только тем, что реальные физические страницы не потеряются, а останутся на своем месте, по тем же BIOS-адресам.
Спасибо, учту. PG_NOCACHE - зевнул, это точно
А чем эти глюки принципиально будут отличаться от обычной незакрытой кучи?diamond wrote:...и наслаждайся глюками, которые возникнут, когда при внезапном завершении программы менеджер памяти попытается такие страницы освободить.Serge wrote:Выдели память user_alloc (68.12), проверь линейный адрес и мапь туда MMIO страницы с флагами PG_SHARED|PG_UW
Только тем, что реальные физические страницы не потеряются, а останутся на своем месте, по тем же BIOS-адресам.
Евангелие от Иоанна: стих 1[/size]
Code: Select all
; В начале было Слово:
B32: mov ax, os_stack ; Selector for os
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!
Ушёл к умным, знающим и культурным людям.
В данном конкретном случае - ничего страшного не случится. Поскольку физические адреса MMIO находятся в самой верхней зоне адресного пространства, просто будет поставлен бит где-то в самом конце таблицы sys_pgmap, куда менеджер памяти никогда не заглядывает.diamond wrote:Вопрос на засыпку: что будет, если free_page (начало кода которой приведено выше) попытается освободить страницу, находящуюся за пределами физической памяти (на которую рассчитан битовый массив 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
и сразу же - на выход, без каких-бы то ни было катастрофических последствий.
Евангелие от Иоанна: стих 1[/size]
Code: Select all
; В начале было Слово:
B32: mov ax, os_stack ; Selector for os
Ответ неверный. Рекомендую подумать ещё раз, учитывая (уже приведённый) факт, что массив sys_pgmap рассчитан на покрытие физической памяти.art_zh wrote:В данном конкретном случае - ничего страшного не случится. Поскольку физические адреса MMIO находятся в самой верхней зоне адресного пространства, просто будет поставлен бит где-то в самом конце таблицы sys_pgmap
Ушёл к умным, знающим и культурным людям.
diamond
user_free расшареные страницы не трогает. В остальных случаях terminate вызывает destroy_app_space, та destroy_page_table
Или есть другой способ "разобрать" адресное пространство ?
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
Пардон, не заметил флага PG_SHARED. Тогда вопрос снимается.
Я написал план, пофиг на ваше мнение, выполняйте. (c) главнокомандующий
diamond, заметь, я такого не говорил и не писал (ни тут, ни в вике).
А то, что я написал в вике - обобщения с форума.
diamond, заметь, я такого не говорил и не писал (ни тут, ни в вике).
А то, что я написал в вике - обобщения с форума.
Все так и сделал Система грузится нормально вплоть до установки видеорежима.... Потом вышибает на перезагрузку.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.
Отключил АТI- драйвер - все загрузилось без проблем.
Похоже, ATIKMS где-то перехватывает сервис PCI?
Евангелие от Иоанна: стих 1[/size]
Code: Select all
; В начале было Слово:
B32: mov ax, os_stack ; Selector for os
art_zh
Не перехватывает, но активно юзает.
pci_api
pci_read8
pci_read16
pci_read32
pci_write8
pci_write16
pci_write32
А до изменений нормально грузилось ?
Не перехватывает, но активно юзает.
pci_api
pci_read8
pci_read16
pci_read32
pci_write8
pci_write16
pci_write32
А до изменений нормально грузилось ?
Serge
Оказалось, что я зацепил pci_write копипастом, fixed.
Еще там была пара багов с перераскладкой регистров при системном вызове, разобрался с помощью diamond'а.
Сейчас вроде все нормально; для тестирования слегка переделал утилиту pcidev.asm, теперь она видит выделенные юзеру каналы MMIO, распознает и маппит RAM-блоки, после чего пробует прочитать первую страницу из бортовой памяти.
После 1 января выложу файлы здесь.
На svn залью когда дадут аккаунт.
Очень надеюсь, что новый сервис будет кому-нибудь так же полезен, как и мне. (а для меня это просто подарок к Новому году!)
Спасибо, с наступающим!
Оказалось, что я зацепил pci_write копипастом, fixed.
Еще там была пара багов с перераскладкой регистров при системном вызове, разобрался с помощью diamond'а.
Сейчас вроде все нормально; для тестирования слегка переделал утилиту pcidev.asm, теперь она видит выделенные юзеру каналы MMIO, распознает и маппит RAM-блоки, после чего пробует прочитать первую страницу из бортовой памяти.
После 1 января выложу файлы здесь.
На svn залью когда дадут аккаунт.
Очень надеюсь, что новый сервис будет кому-нибудь так же полезен, как и мне. (а для меня это просто подарок к Новому году!)
Спасибо, с наступающим!
Евангелие от Иоанна: стих 1[/size]
Code: Select all
; В начале было Слово:
B32: mov ax, os_stack ; Selector for os
Вначале нужно добавить поддержку PCI потом думать о том как его в user mode тянуть. Сейчас PCI это костыль таких размеров что многие думают что PCI есть, но на самом деле, его нет...
Она не только маппит блок необходимой длины на юзерспейс, но еще и избавляет от нудных манипуляций с BAR-регистрами и физическими адресами. Единственное, что надо держать в памяти: длина блока задается в байтах, а смещение в физической памяти - в целых страницах (1стр = 4к байт).
Это так и задумано, иначе у юзера будет соблазн выставить не выравненный по началу страницы оффсет, что обязательно приведет либо к потере данных при маппинге, либо к сдвигу реальных линейных адресов относительно запрашиваемых приложением.
Last edited by art_zh on Sat Jan 02, 2010 3:18 pm, edited 1 time in total.
Евангелие от Иоанна: стих 1[/size]
Code: Select all
; В начале было Слово:
B32: mov ax, os_stack ; Selector for os
Who is online
Users browsing this forum: No registered users and 1 guest