Files
VBoxGuest/core/irq.inc
Alexey Mikhailov 0f400bc0e0 #1 init в репу
2026-01-06 15:43:37 +03:00

458 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
; =============================================================================
; VirtualBox IRQ Handler
; =============================================================================
VMMDEV_MMIO_EVENTS = 0x00
VMMDEV_MMIO_EVENT_CLEAR = 0x04
; Глобальные переменные для IRQ обработки
align 4
vbox_pending_events dd 0
vbox_service_running dd 1 ; 1 = running, 0 = should exit
vbox_service_event dd 0
vbox_service_event_code dd 0
vbox_service_thread_handle dd ?
; =============================================================================
; ПРОЦЕДУРА: vbox_install_irq_handler
; Установка IRQ обработчика при инициализации драйвера
; =============================================================================
proc vbox_install_irq_handler stdcall, irq_line
DEBUGF 1, "[irq] Installing IRQ handler for line %d\n", [irq_line]
; Устанавливаем обработчик прерывания
invoke AttachIntHandler, [irq_line], vbox_irq_handler, 0
test eax, eax
jz .error
DEBUGF 1, "[irq] IRQ handler installed successfully\n"
xor eax, eax
ret
.error:
DEBUGF 2, "[irq] ERROR: Failed to install IRQ handler, eax=0x%x\n", eax
mov eax, VERR_INTERNAL_ERROR
ret
endp
; =============================================================================
; ПРОЦЕДУРА: vbox_irq_handler
; Top half IRQ обработчика - минимум работы в IRQ контексте
; =============================================================================
proc vbox_irq_handler
push ebx esi edi
; 1. Проверяем, наш ли это IRQ
mov eax, [vbox_device.mmio]
test eax, eax
jz .not_ours
; 2. Читаем флаги событий из MMIO
mov eax, [eax + VMMDEV_MEMORY.event_flags]
test eax, eax
jz .not_ours
DEBUGF 2, "[irq] IRQ received, flags=0x%x\n", eax
mov ebx, eax
; 3. Фильтруем интересующие нас события
and eax, VMMDEV_EVENT_DISPLAY_CHANGE or VMMDEV_EVENT_HGCM or VMMDEV_EVENT_MOUSE_POSITION_CHANGED
; test eax, eax
; jz .no_relevant_events
; 4. Атомарно добавляем события в pending
lock or [vbox_pending_events], eax
; 5. ACK события (безопасно для IRQ контекста)
; push eax
; stdcall vmmdev_ack_events, eax
; pop eax
mov eax, [vbox_device.mmio]
mov [eax + VMMDEV_MEMORY.event_ack], ebx
; mov [edx + 0x18], ebx ; ACK ALL EVENTS
DEBUGF 2, "[irq] Acknowledged events: 0x%x\n", eax
; ; 6. Если есть HGCM событие (clipboard), будим service thread
; test eax, VMMDEV_EVENT_HGCM
; jz .no_hgcm_wakeup
; ; Проверяем, создан ли service thread
; cmp dword [vbox_service_event], 0
; je .no_hgcm_wakeup
; ; Будим service thread через event
; mov eax, [vbox_service_event]
; mov ebx, [vbox_service_event_code]
; invoke RaiseEvent
DEBUGF 2, "[irq] Woke up service thread for HGCM\n"
; .no_hgcm_wakeup:
; ; 7. Для display change можно обработать быстрее в IRQ
; ; Быстрая обработка display change в IRQ контексте
; test eax, VMMDEV_EVENT_DISPLAY_CHANGE
; jz .no_display_irq
; ; Display change требует немедленной реакции
; ; Устанавливаем флаг для быстрой обработки
; DEBUGF 2, "[irq] Display change detected, scheduling immediate update\n"
; ; Можно также сразу обработать display change,
; ; если операция быстрая и безопасная в IRQ контексте
; push eax
; call display_change_irq ; быстрая версия display_change
; pop eax
; .no_display_irq:
; ; 8. Если есть mouse events, также можно обработать быстро
; test eax, VMMDEV_EVENT_MOUSE_POSITION_CHANGED
; jz .no_mouse_irq
; ; Быстрая обработка мыши в IRQ контексте
; DEBUGF 2, "[irq] Mouse position changed\n"
; ; Здесь можно обновить кэшированные координаты мыши
; ; или установить флаг для обработки в service thread
; .no_mouse_irq:
; pop edi esi ebx
; mov eax, 1 ; IRQ обработан
; ret
; .no_relevant_events:
; DEBUGF 2, "[irq] No relevant events (filtered)\n"
; ; Все равно ACK события, чтобы не залипали
; stdcall vmmdev_ack_events, ebx
pop edi esi ebx
mov eax, 1 ; IRQ обработан
ret
.not_ours:
pop edi esi ebx
xor eax, eax ; не наш IRQ
ret
endp
; =============================================================================
; ПРОЦЕДУРА: display_change_irq
; Быстрая обработка изменения дисплея в IRQ контексте
; =============================================================================
proc display_change_irq
; Минимальная обработка в IRQ контексте
; Основная обработка будет в service thread
; Просто устанавливаем флаг для полной обработки
; или сразу читаем новое разрешение
push eax ebx
; Быстрое чтение нового разрешения из MMIO
mov eax, [vbox_device.mmio]
test eax, eax
jz .no_mmio
; Здесь можно прочитать новые параметры дисплея
; но основную работу оставляем для service thread
.no_mmio:
pop ebx eax
ret
endp
; =============================================================================
; ПРОЦЕДУРА: vbox_uninstall_irq_handler
; Удаление IRQ обработчика при выгрузке драйвера
; =============================================================================
proc vbox_uninstall_irq_handler
DEBUGF 2, "[irq] Uninstalling IRQ handler\n"
; В KolibriOS нет стандартного способа удалить обработчик
; Просто отмечаем, что обработчик больше не активен
mov dword [vbox_service_running], 0
xor eax, eax
ret
endp
; =============================================================================
; ПРОЦЕДУРА: vbox_service_init
; Инициализация service thread
; =============================================================================
proc vbox_service_init
DEBUGF 2, "[service] Initializing service thread\n"
; 1. Создаём event для синхронизации
xor esi, esi
xor ecx, ecx
invoke CreateEvent
test eax, eax
jz .event_create_failed
mov [vbox_service_event], eax
mov [vbox_service_event_code], edx
DEBUGF 2, "[service] Event created: handle=0x%x, code=0x%x\n", eax, edx
; 2. Создаём service thread
push ebx ecx edx esi edi
movi ebx, 1 ; priority = 1 (низкий)
mov ecx, vbox_service_thread ; entry point
xor edx, edx ; parameter = NULL
invoke CreateThread
pop edi esi edx ecx ebx
cmp eax, -1
je .thread_create_failed
mov [vbox_service_thread_handle], eax
DEBUGF 2, "[service] Service thread created, handle=0x%x\n", eax
; 3. Устанавливаем флаг запуска
mov dword [vbox_service_running], 1
mov dword [vbox_pending_events], 0
xor eax, eax
ret
.event_create_failed:
DEBUGF 1, "[service] ERROR: Failed to create event\n"
or eax, -1
ret
.thread_create_failed:
DEBUGF 1, "[service] ERROR: Failed to create service thread\n"
; Освобождаем event
mov eax, [vbox_service_event]
test eax, eax
jz @f
invoke DestroyEvent
@@:
mov dword [vbox_service_event], 0
or eax, -1
ret
endp
; =============================================================================
; ПРОЦЕДУРА: vbox_service_cleanup
; Очистка ресурсов service thread
; =============================================================================
proc vbox_service_cleanup
DEBUGF 2, "[service] Cleaning up service thread\n"
; 1. Устанавливаем флаг завершения
mov dword [vbox_service_running], 0
; 2. Будим thread для завершения (если спит)
mov eax, [vbox_service_event]
test eax, eax
jz .no_event
mov ebx, [vbox_service_event_code]
invoke RaiseEvent
; 3. Ждем завершения thread (краткий таймаут)
push esi
movi esi, 50 ; 50ms timeout
invoke Sleep
pop esi
.no_event:
; 4. Освобождаем event
mov eax, [vbox_service_event]
test eax, eax
jz @f
invoke DestroyEvent
@@:
mov dword [vbox_service_event], 0
mov dword [vbox_service_event_code], 0
mov dword [vbox_service_thread_handle], 0
ret
endp
; =============================================================================
; ПРОЦЕДУРА: vbox_service_thread
; Основной service thread (bottom half обработки)
; =============================================================================
proc vbox_service_thread
DEBUGF 2, "[service] Service thread started\n"
.service_loop:
; 1. Ждем события или timeout
mov eax, [vbox_service_event]
mov ebx, [vbox_service_event_code]
; invoke WaitEventTimeout, eax, ebx, 1000 ; timeout 1000ms
invoke WaitEvent, eax, ebx
; 2. Проверяем, не пора ли завершать thread
cmp dword [vbox_service_running], 0
je .exit_thread
; 3. Обрабатываем pending events
call vbox_process_pending_events
; 4. Продолжаем цикл
jmp .service_loop
.exit_thread:
DEBUGF 2, "[service] Service thread exiting\n"
or eax, -1
int 0x40
endp
; =============================================================================
; ПРОЦЕДУРА: vbox_process_pending_events
; Обработка всех pending events
; =============================================================================
proc vbox_process_pending_events
push ebx esi edi
.process_loop:
; 1. Атомарно читаем и сбрасываем pending events
cli
mov eax, [vbox_pending_events]
mov dword [vbox_pending_events], 0
sti
; 2. Если нет событий - выходим
test eax, eax
jz .done
DEBUGF 2, "[service] Processing events: 0x%x\n", eax
; 3. Сохраняем события для обработки
push eax
; =====================================================================
; Обработка DISPLAY_CHANGE (полная версия)
; =====================================================================
test eax, VMMDEV_EVENT_DISPLAY_CHANGE
jz .no_display_change
DEBUGF 2, "[service] Handling display change (full)\n"
call display_change
.no_display_change:
; =====================================================================
; Обработка HGCM (clipboard)
; =====================================================================
test eax, VMMDEV_EVENT_HGCM
jz .no_hgcm_event
; Проверяем, что clipboard инициализирован
cmp dword [clipboard_state.connected], 1
jne .hgcm_not_ready
DEBUGF 2, "[service] Handling HGCM clipboard event\n"
; Включаем прерывания на время обработки
sti
call clipboard_handle_event
; Выключаем обратно для атомарных операций
cli
jmp .no_hgcm_event
.hgcm_not_ready:
DEBUGF 2, "[service] HGCM event ignored (clipboard not ready)\n"
.no_hgcm_event:
; =====================================================================
; Обработка MOUSE events
; =====================================================================
test eax, VMMDEV_EVENT_MOUSE_POSITION_CHANGED
jz .no_mouse_event
DEBUGF 2, "[service] Handling mouse position change\n"
call mouse_position_changed
.no_mouse_event:
; 4. Восстанавливаем оригинальные события
pop eax
; 5. Проверяем, не появились ли новые события пока мы обрабатывали
; (это безопасно, т.к. мы уже обработали текущие)
jmp .process_loop
.done:
pop edi esi ebx
ret
endp
; =============================================================================
; ПРОЦЕДУРА: mouse_position_changed
; Обработка изменения позиции мыши
; =============================================================================
proc mouse_position_changed
push eax ebx ecx edx
; Читаем новые координаты мыши из MMIO
mov eax, [vbox_device.mmio]
test eax, eax
jz .no_mmio
; Здесь можно обновить состояние мыши в системе
.no_mmio:
pop edx ecx ebx eax
ret
endp
; =============================================================================
; ПРОЦЕДУРА: vbox_check_events
; Ручная проверка событий (для polling режима)
; =============================================================================
proc vbox_check_events
; Проверяем pending events вручную
mov eax, [vbox_pending_events]
test eax, eax
jz .no_events
; Если есть service thread, он обработает
cmp dword [vbox_service_thread_handle], 0
jne .thread_will_handle
; Иначе обрабатываем сами
call vbox_process_pending_events
.thread_will_handle:
.no_events:
ret
endp
; =============================================================================
; ПРОЦЕДУРА: vbox_clear_pending_events
; Очистка pending events
; =============================================================================
proc vbox_clear_pending_events
mov dword [vbox_pending_events], 0
ret
endp
; =============================================================================
; ПРОЦЕДУРА: vbox_get_pending_events
; Получение текущих pending events
; Возврат: EAX = pending events flags
; =============================================================================
proc vbox_get_pending_events
mov eax, [vbox_pending_events]
ret
endp