Применение KolibriOS. Часть 2: Экзоверсия ядра для разработчиков железа
Хочется сказать спасибо art_zh за потраченное время на подготовку материала для данной статьи.
Наверное, немногие наши читатели помнят те давние-давние времена, «когда компьютеры были большими» и практически не использовались для делопроизводства и развлечений. Основными сферами применения этих дорогущих монстров были зубодробительные вычисления, автоматизированные системы сбора данных, проектирования и управления сложными технологическими процессами.
Прошли десятилетия, компьютеры стали гораздо дешевле и быстрее, но старые задачи не стали проще. Постоянно возрастают требования к эффективности обработки широкополосных потоков данных, к быстроте и надежности схем управления, к простоте и наглядности пользовательского интерфейса.
Один из наших разработчиков — art_zh, инженер-электронщик из Англии, пришел в проект после долгих и безуспешных поисков оптимальной ОС для системы «быстрого» технического зрения на х86-платформе. Конкретная задача требовала обработки широкополосного видеопотока (500 SXGA-кадров, 660 миллионов пикселей в секунду), – из этой лавины данных нужно было выделить несколько характерных зон, найти среднюю яркость в каждой зоне и следить за изменением этой яркости в течение 10-12 часов. Периодически отображая полноформатную картинку на экране.
Задача осложнялась нестандартностью применяемого железа. Фреймграббер и DMA-контроллер были реализованы на экспериментальной PCI-express карте с мотором Virtex-5 от Xilinx. Суровый Verilog-код требовал тщательной отладки всех пакетных транзакций протоколу TLP-PCIe. Эту тему мы более подробно обсудим в одной из следующих публикаций этого цикла, здесь ограничимся констатацией того, что среда Windows для такой отладки представляется совершенно непригодной, а в Линуксе цикл модификация кода — компиляция драйвера – перезагрузка – анализ printk-сообщений занимал неприемлемо долгое время.
Итак, нужна была быстрая, графическая, 32-разрядная операционная система с экзоядром, прозрачным для доступа из приложения к аппаратным ресурсам самого низкого уровня – конфигурационному пространству PCI, регистрам PCIe Root Complex, адресам MMIO (отображаемого на память ввода вывода) и т.п.
КолибриОС привлекала своей быстротой и минимальной латентностью, простым и удобным графическим интерфейсом, очень компактным и открытым кодом ядра. Проблема была с ограниченным набором функций для работы с аппаратной частью ПК.
В стандартном ядре Колибри приложению был открыт доступ только к ограниченному диапазону портов ввода-вывода, системным сообщениям о некоторых аппаратных прерываниях и очень кривой PCI-сервис. Чтобы максимально ускорить работу программ с компьютерным железом, надо было прорубить экзодыру в монолитном ядре.
Так появилась Колибри-А, экзоверсия КолибриОС для платформ на базе AMD Fusion. Поскольку любое экзоядро несет в себе опасность фатального повреждения данных и оборудования ПК из-за некорректного доступа к критическим системным ресурсам, а также учитывая, что подавляющее большинство пользователей нашей системы –
Первым делом приложению напрямую был открыт доступ к
- Вводу/выводу во все порты (в основной ветке ядра приложение до сих пор должно «заказывать» нужный диапазон портов ввода/вывода через уродливое менуэтовское наследие – т.н. «сороковые функции»).
Этого оказалось мало. Сейчас уже трудно найти устройство, общающееся с процессором исключительно через порты. Был добавлен удобный - Доступ к MMIO (отображаемому на память пространству ввода/вывода) с помощью сисфункции 62:12. Сервис работает подобно линуксовской функции ioremap(), но реализован проще и гибче. Приложение указывает номер BAR-регистра в конфигурационном пространстве выбранного устройства и выбирает диапазон MMIO, к которому будет обращаться, а ядро отображает выбранный диапазон на линейное пространство приложения.
Но и это еще не все. Приложение должно иметь полный доступ к конфигурационному пространству выбранного устройства. PCI-сервис ядра КолибриОС был реализован через медленные и неудобные порты CF8/CFC. В А-версию был добавлен быстрый доступ к - Конфигурационному пространству PCI (включая расширенный конфигспейс PCI Express) с отображением на виртуальное адресное пространство приложения начиная с адреса 0xF0000000. Пример чтения заголовка PCI-устройства 1:18:2
mov eax, (1 shl 20) + (18 shl 15) + (2 shl 12)
or eax, 0xF0000000
mov [device_vendor], [eax]
Нужно заметить, что отображение конфигспейса на память реализовано только для платформ на базе AMD-процессоров (кстати, именно это подчекивает название «Колибри-А»). Для интелов экзосервис пока не разработан: art_zh работает только с AMD-железом, а все остальные разработчики, к сожалению, особого интереса к экзоядру не проявляют.
Ну хорошо, конфигспейс открыт. Теперь мы можем идентифицировать устройства, разрешать прерывания, следить за состоянием PCI-линии и обращаться к любым внутренним ресурсам, контролируя потоки данных и организуя прямой доступ в память… Хотя тут вот есть неувязочка: устройство ведь знает только физические адреса DMA-области, а приложение живет в своем линейном пространстве. Для этого - Выделена статическая область DMA. Используя специальную сисфункцию 62:12-DA, приложение может запросить ее линейный адрес и работать с ней напрямую:
mcall 62,11,0x0500 ; init MMIO/DMA: bus=5, device=0, fn=0
mov [dma],eax ; store phys.addr of the DMA buffer:
mcall 62,0+12,4096,0 ; map MMIO access to BAR0-space
mov [mio],eax ; store MMIO linear address
mcall 62,0xDA0C,4096,0 ; 0x0da0c = create user DMA channel
mov [mem],eax ; store DMA buffer: linear @
mov eax, [dma]
or eax, DMA_FLAGS
mov dword[mio+4], eax ; program device-specific DMA-register
; ....
mov ecx, [mem]
mov eax, [index]
mov edx, dword[ecx+eax*4] ; load the fresh data from DMA-buffer
Вот теперь с устройством можно полноценно работать прямо из пользовательского приложения. Получился гибкий и универсальный инструмент, который art_zh уже 5 лет использует в повседневной работе для разработки нового железа и отладки низкоуровнего кода очень разных встраиваемых х86-устройств.
К сожалению, разработав такой инструмент, автор переключился на другие задачи и нечасто публикует новые версии своего кода (оставаясь в проекте в роли «продвинутого юзера» и вечного брюзги на форуме). Но несмотря на длительные перерывы, работа потихоньку продолжается. Кроме вышеперечисленных, на сегодняшний день в Колибри-А имеются и другие экзофишки: - Организация MSI-прерываний может быть организована через доступное юзеру адресное пространство LAPIC.
- Физическая память также может быть прочитана из приложения. Этот сервис очень полезен при отладке ядра.
- Бездисковая загрузка ОС опробована через CoreBoot (с помощью Xvilka) и через BIOS Extension ROM – из бортовой памяти PCIe-устройств.
- Открыто пространство GPU – пока только для установки аппаратных курсоров и реверс-инжиниринга ресурсов графического процессора AMD/ATI. Но кто знает, возможно когда-нибудь в Колибри будут программы и на GPU-ассемблере...
(продолжение следует)