Интегрированная графика Intel

Здесь должна появиться статья о програмировании интегрированной графики intel. Пока буду выкладывать наработки... Пока что это неподтвержденные высеры...

Все описанное ниже относится к 945GM на других девайсах это может не работать.

Начнем с того, что интегрированное графическое устройство является 2м устройством на нулевой шине PCI.

Intel GPU программируются через MMIO - Memory Mapped Input/Output. Контроллер памяти GPU следит за некоторыми областями памяти и управляет GPU в соответствии с данными в этих областях.

Блок MMIO указывается через PCI. Регистр PCI отвечающий за смещение этого блока в памяти называется MMADR. Он расположен на нулевой шине 2 устройстве 0 функции по смещению 10h. Это 32 битный регистр задающий 32 битный адрес блока MMIO.

Размер этого блока 512 Кб, то есть смещения полей относительно MMADR 00000h-7FFFFh. Он расположен по адресу реально не существующему, то есть если у вас 1 Гб оперативы то MMIO блок будет расположен по адресу 40000000h или выше.

32 битный адрес видеопамяти (GMADR) также указывается через PCI и расположен по смещению 14h. Он тоже имеет значение 40000000h или выше.

Исходя из написанного выше надо полагать, что эта штука не поддерживает x64.

Собственно кодинг

У меня нетбук с экраном 1024x600 поэтому все написанное ниже будет писаться для этого режима. Все это я запускаю чистом защищенном режиме с изначально установленным текстовым видеорежимом 40x25.

Для начала пробуем найти сей девайс. Он 2й на нулевой шине PCI. Имеет VendorID 8086h (Intel) и DeviceID 27AEh (945GM).

Биты Описание
0 - 1 Всегда в нуле
2 - 7 Смещение регистра в конфигурационном пространстве
8 - 10 Функция
11 - 15 Устройство
16 - 23 Шина
24 - 30 Зарезервировано
31 Разрешить(1)/запретить(0) обращение в конфигурационное пространство через порт CONFIG_DATA (0CFCh)

Порт адреса

Смотрим на таблицу выше и пытаемся считать DeviceID (смещение 00h) и VendorID (смещение 04h) позволяющие однозначно опознать устройство.

mov eax, 80001000h
mov dx, 0CF8h
out dx, eax
mov dx, 0CFCh
in eax, dx

После выполнения этого кода в eax окажется 27AE8086h, если 2е устройство на 0й шине - 945GM.

Далее стоит попробовать выключить/включить монитор. Смотрим в документации PP_CONTROL - Panel Power Control Register.

Биты Описание
0 Выключить(0)/включить(1) панель
1 Не выключать(0)/выключать(1) панель когда с ICH (I/O controller hub) приходит reset
2 - 15 Зарезервировано
16 - 31 ABCD - отключить защиту от записи в регистры нужные для переключения режима; иные значения игнорируются

Регистр PP_CONTROL

Нам нужно использовать установить в 0 0й бит чтобы выключить панель а потом в 1 чтобы включить ее:

; выключаем панель (PP_CONTROL bit0 = 0)
and dword [ds:56280000h+00061204h], 0FFFFFFFEh
; ждем полсекунды пока отключится
call sleep
; включаем панель (PP_CONTROL bit0 = 1)
or dword [ds:56280000h+00061204h], 00000001h
; ждем полсекунды пока включится
call sleep

Рассмотрим используемый адрес 56280000h+00061204h: 56280000h - это смещение считанное из PCI регистра MMADR а 00061204h - смещение регистра PP_CONTROL в блоке MMIO.

Результатом работы этого кода будет кратковременное отключение монитора (у меня sleep - задержка на 0.5 секунды).

Теперь попробуем переключить режим.

У девайса есть 2 канала (pipeA и pipeB) для двойной буферизации. В VGA режиме установленном при старте активен только pipeB я пока не стал этого менять (юзать двойную буферизацию). Соответственно все остальное тоже уже настроено на использование pipeB, поэтому тут остается только сменить разрешение на этом пайпе.

Для начала естественно надо выключить сам pipeB (pipeA и так отключен), отключить VGA режим, прописать в определенных регистрах разрешение, включить не VGA режим и включить пайп. Следующий код устанавливает разрешение 1024x600x32.

; отключаем pipeB (PIPEBCONF bit31 = 0)
and dword [ds:56280000h+00071008h], 7FFFFFFFh
; отключаем VGA (VGACNTRL bit31 = 1)
or dword [ds:56280000h+00071400h], 80000000h
; меняем разрешение
; 1024x600 - PIPESRC_B
mov dword [ds:56280000h+0006101Ch], 03ff0257h
; 1024x600 - DSPBSIZE
mov dword [ds:56280000h+00071190h], 025703ffh
; количество байт на строку DSPBSTRIDE 400h(1024 пиксела)*4h(4 байта на пиксел)=1000h
mov dword [ds:56280000h+00071188h], 00001000h
; включаем не VGA (DSPBCTRL bit31 = 1)
or dword [ds:56280000h+00071180h], 80000000h
; включаем pipeB (PIPEBCONF bit31 = 1)
or dword [ds:56280000h+00071008h], 80000000h

Теперь можно что нибудь вывести на экран.

To be continued...

Upd: На это подзабил пока, куплю Sandy Bridge - начну снова.

Кодес (intel_tests в Kernel.asm)

Hosted by uCoz