forked from KolibriOS/kolibrios
Compare commits
2 Commits
iconv_upda
...
VBoxGuest
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab59015ded | ||
|
|
1493edddb6 |
2
drivers/vboxguest/common/common.inc
Normal file
2
drivers/vboxguest/common/common.inc
Normal file
@@ -0,0 +1,2 @@
|
||||
include 'errors.inc'
|
||||
include 'utils.inc'
|
||||
82
drivers/vboxguest/common/errors.inc
Normal file
82
drivers/vboxguest/common/errors.inc
Normal file
@@ -0,0 +1,82 @@
|
||||
; =============================================================================
|
||||
; VBoxGuest Driver for KolibriOS - Dual-level Error Handling
|
||||
; VMMDev transport errors + HGCM service errors
|
||||
; На базе версии v1_04
|
||||
; =============================================================================
|
||||
|
||||
; =============================================================================
|
||||
; VMMDev Error Codes (Generic VERR_*)
|
||||
; These appear in vmmdev_request_header.rc
|
||||
; =============================================================================
|
||||
|
||||
; Success codes (positive or zero)
|
||||
VINF_SUCCESS equ 0
|
||||
VINF_HGCM_ASYNC_EXECUTE equ 2903 ; Запрос выполняется асинхронно
|
||||
VBOX_HGCM_REQ_DONE equ 0x00000001 ; Флаг завершения в поле flags
|
||||
HGCM_TIMEOUT_DEFAULT equ 500000 ; Базовый таймаут
|
||||
|
||||
; err.h
|
||||
VINF_NOT_SUPPORTED equ 37
|
||||
VERR_ACCESS_DENIED equ -38
|
||||
VERR_INTERRUPTED equ -39
|
||||
VINF_INTERRUPTED equ 39
|
||||
|
||||
; =============================================================================
|
||||
; Error Codes
|
||||
; =============================================================================
|
||||
VERR_TIMEOUT equ -78
|
||||
VERR_NOT_READY equ -25
|
||||
|
||||
VERR_GENERAL_FAILURE equ -1
|
||||
VERR_INVALID_PARAMETER equ -2
|
||||
VERR_INVALID_MAGIC equ -3
|
||||
VERR_INVALID_POINTER equ -6
|
||||
VERR_NO_MEMORY equ -8
|
||||
VERR_NOT_IMPLEMENTED equ -12
|
||||
VERR_INVALID_FLAGS equ -13 ; 0xFFFFFFF3
|
||||
VERR_INVALID_FUNCTION equ -36
|
||||
VERR_NOT_SUPPORTED equ -37
|
||||
VERR_TOO_MUCH_DATA equ -42
|
||||
VERR_NOT_FOUND equ -78
|
||||
VERR_INVALID_STATE equ -79
|
||||
VERR_OUT_OF_RESOURCES equ -80
|
||||
VERR_ALREADY_EXISTS equ -105
|
||||
VERR_TRY_AGAIN equ -116
|
||||
VERR_INTERNAL_ERROR equ -225
|
||||
|
||||
; VERR_WRONG_TYPE-22409
|
||||
; VERR_WRONG_PARAMETER_TYPE-22416
|
||||
|
||||
VERR_NO_DATA equ -125 ; Нэт доступных данных
|
||||
|
||||
|
||||
; =============================================================================
|
||||
; HGCM Error Codes (Range -2900..-2909)
|
||||
; These appear in VMMDevHGCMRequestHeader.result
|
||||
; =============================================================================
|
||||
|
||||
VERR_HGCM_SERVICE_NOT_FOUND equ -2900
|
||||
VERR_HGCM_CLIENT_REJECTED equ -2901
|
||||
VERR_HGCM_INVALID_CMD_ADDRESS equ -2902
|
||||
VERR_HGCM_INTERNAL equ -2904
|
||||
VERR_HGCM_INVALID_CLIENT_ID equ -2905
|
||||
VERR_HGCM_PROTOCOL_ERROR equ -2906
|
||||
VERR_HGCM_TOO_MANY_CLIENTS equ -2908
|
||||
VERR_HGCM_TOO_MANY_PARMS equ -2909
|
||||
|
||||
; =============================================================================
|
||||
; Clipboard-specific Error Codes
|
||||
; =============================================================================
|
||||
|
||||
VERR_SHCLPB_NO_DATA equ -7153
|
||||
VERR_SHCLPB_FORMAT_NOT_SUPPORTED equ -7154
|
||||
|
||||
; =============================================================================
|
||||
; Error Code Ranges
|
||||
; =============================================================================
|
||||
|
||||
VMMDEV_ERROR_RANGE_START equ -1000
|
||||
VMMDEV_ERROR_RANGE_END equ 0
|
||||
HGCM_ERROR_RANGE_START equ -2910
|
||||
HGCM_ERROR_RANGE_END equ -2900
|
||||
|
||||
133
drivers/vboxguest/common/utils.inc
Normal file
133
drivers/vboxguest/common/utils.inc
Normal file
@@ -0,0 +1,133 @@
|
||||
; =============================================================================
|
||||
; VBoxGuest Driver for KolibriOS - Common Utilities
|
||||
; Файл: common/utils.inc
|
||||
; =============================================================================
|
||||
|
||||
; sf_utf8_to_cp866 — Конвертировать UTF-8 строку в CP866 (кириллица)
|
||||
proc sf_utf8_to_cp866 uses ebx ecx edx esi edi, src:dword, dst:dword, src_len:dword
|
||||
mov esi, [src]
|
||||
mov edi, [dst]
|
||||
mov ecx, [src_len]
|
||||
xor edx, edx
|
||||
|
||||
.u8_loop:
|
||||
test ecx, ecx
|
||||
jle .u8_done
|
||||
|
||||
movzx eax, byte [esi]
|
||||
|
||||
cmp al, 0x80
|
||||
jb .u8_ascii
|
||||
|
||||
cmp al, 0xC0
|
||||
jb .u8_skip1
|
||||
cmp al, 0xE0
|
||||
jb .u8_two_byte
|
||||
|
||||
cmp al, 0xF0
|
||||
jb .u8_skip3
|
||||
|
||||
mov byte [edi], '?'
|
||||
inc edi
|
||||
inc edx
|
||||
add esi, 4
|
||||
sub ecx, 4
|
||||
jmp .u8_loop
|
||||
|
||||
.u8_skip3:
|
||||
mov byte [edi], '?'
|
||||
inc edi
|
||||
inc edx
|
||||
add esi, 3
|
||||
sub ecx, 3
|
||||
jmp .u8_loop
|
||||
|
||||
.u8_ascii:
|
||||
mov [edi], al
|
||||
inc esi
|
||||
inc edi
|
||||
inc edx
|
||||
dec ecx
|
||||
jmp .u8_loop
|
||||
|
||||
.u8_two_byte:
|
||||
cmp ecx, 2
|
||||
jb .u8_done
|
||||
|
||||
movzx eax, byte [esi]
|
||||
movzx ebx, byte [esi + 1]
|
||||
and eax, 0x1F
|
||||
shl eax, 6
|
||||
and ebx, 0x3F
|
||||
or eax, ebx
|
||||
|
||||
cmp eax, 0x0401
|
||||
je .u8_yo_upper
|
||||
cmp eax, 0x0451
|
||||
je .u8_yo_lower
|
||||
|
||||
cmp eax, 0x0410
|
||||
jb .u8_not_cyrillic
|
||||
cmp eax, 0x041F
|
||||
jbe .u8_upper1
|
||||
|
||||
cmp eax, 0x042F
|
||||
jbe .u8_upper2
|
||||
|
||||
cmp eax, 0x043F
|
||||
jbe .u8_lower1
|
||||
|
||||
cmp eax, 0x044F
|
||||
jbe .u8_lower2
|
||||
|
||||
jmp .u8_not_cyrillic
|
||||
|
||||
.u8_upper1:
|
||||
sub eax, 0x0410
|
||||
add eax, 0x80
|
||||
jmp .u8_store2
|
||||
|
||||
.u8_upper2:
|
||||
sub eax, 0x0420
|
||||
add eax, 0x90
|
||||
jmp .u8_store2
|
||||
|
||||
.u8_lower1:
|
||||
sub eax, 0x0430
|
||||
add eax, 0xA0
|
||||
jmp .u8_store2
|
||||
|
||||
.u8_lower2:
|
||||
sub eax, 0x0440
|
||||
add eax, 0xE0
|
||||
jmp .u8_store2
|
||||
|
||||
.u8_yo_upper:
|
||||
mov eax, 0xF0
|
||||
jmp .u8_store2
|
||||
|
||||
.u8_yo_lower:
|
||||
mov eax, 0xF1
|
||||
jmp .u8_store2
|
||||
|
||||
.u8_not_cyrillic:
|
||||
mov eax, '?'
|
||||
|
||||
.u8_store2:
|
||||
mov [edi], al
|
||||
add esi, 2
|
||||
sub ecx, 2
|
||||
inc edi
|
||||
inc edx
|
||||
jmp .u8_loop
|
||||
|
||||
.u8_skip1:
|
||||
inc esi
|
||||
dec ecx
|
||||
jmp .u8_loop
|
||||
|
||||
.u8_done:
|
||||
mov byte [edi], 0
|
||||
mov eax, edx
|
||||
ret
|
||||
endp
|
||||
41
drivers/vboxguest/config.inc
Normal file
41
drivers/vboxguest/config.inc
Normal file
@@ -0,0 +1,41 @@
|
||||
; =============================================================================
|
||||
; VBoxGuest Конфигурация
|
||||
; =============================================================================
|
||||
|
||||
; =============================================================================
|
||||
; Автозапуск сервисов
|
||||
; =============================================================================
|
||||
AUTOSTART_MOUSE = 1 ; Абсолютная мыщъх
|
||||
AUTOSTART_HEARTBEAT = 1 ; Heartbeat
|
||||
AUTOSTART_DISPLAY = 1 ; Разрешение экрана
|
||||
AUTOSTART_TIMESYNC = 0 ; Синхронизация времени
|
||||
AUTOSTART_SHARED_FOLDERS = 1 ; Общие папки
|
||||
AUTOSTART_CLIPBOARD = 1 ; Буфер обмена
|
||||
AUTOSTART_GUEST_PROPS = 1 ; Guest Properties
|
||||
AUTOSTART_SEAMLESS = 0 ; Seamless mode
|
||||
|
||||
; =============================================================================
|
||||
; Настройки сервисов
|
||||
; =============================================================================
|
||||
SHFL_MAX_FOLDERS = 10 ; Максимум общих папок
|
||||
|
||||
; =============================================================================
|
||||
; Отладка
|
||||
; =============================================================================
|
||||
; Уровни отладки:
|
||||
; __DEBUG_LEVEL__ = 1 -> Полное логирование (очень много вывода)
|
||||
; __DEBUG_LEVEL__ = 2 -> Только ошибки
|
||||
|
||||
__DEBUG__ = 1 ; Включена
|
||||
__DEBUG_LEVEL__ = 2 ;
|
||||
|
||||
__DEBUG_IRQ__ = 0 ; Логирование прерываний
|
||||
__DEBUG_HGCM__ = 0 ; Логирование HGCM
|
||||
__DEBUG_SF__ = 0 ; SharedFolder
|
||||
__DEBUG_CB__ = 0 ; ClipBoard
|
||||
__DEBUG_EVENTS__ = 0 ; Логирование событий
|
||||
__DEBUG_MOUSE__ = 0 ; Логирование мыщъх
|
||||
__DEBUG_SEAMLESS__ = 0
|
||||
__DEBUG_HB__ = 0 ; Heartbeat мониторинг гостя
|
||||
__DEBUG_DISPLAY__ = 0 ; Display разрешение экрана
|
||||
__DEBUG_DISPATCHER__ = 0 ; Логирование диспетчера
|
||||
13
drivers/vboxguest/core/core.inc
Normal file
13
drivers/vboxguest/core/core.inc
Normal file
@@ -0,0 +1,13 @@
|
||||
; =============================================================================
|
||||
; Модуль : Core Aggregator
|
||||
; Назначение : Подключение всех модулей ядра драйвера
|
||||
; Файл : core/core.inc
|
||||
; =============================================================================
|
||||
|
||||
include 'core/state.inc'
|
||||
include 'core/pci.inc'
|
||||
include 'core/mmio.inc'
|
||||
include 'core/ports.inc'
|
||||
include 'core/irq.inc'
|
||||
include 'core/timer.inc'
|
||||
include 'core/dispatcher/dispatcher.inc'
|
||||
345
drivers/vboxguest/core/dispatcher/dispatcher.inc
Normal file
345
drivers/vboxguest/core/dispatcher/dispatcher.inc
Normal file
@@ -0,0 +1,345 @@
|
||||
; =============================================================================
|
||||
; Модуль : Service Dispatcher
|
||||
; Файл : core/dispatcher.inc
|
||||
; Назначение : Функции диспетчера сервисов
|
||||
; =============================================================================
|
||||
|
||||
include 'dispatcher_macros.inc'
|
||||
|
||||
; =============================================================================
|
||||
; Данные диспетчера
|
||||
; =============================================================================
|
||||
align 4
|
||||
dispatcher_active_events dd 0 ; OR всех event_mask включенных сервисов
|
||||
dispatcher_active_caps dd 0 ; OR всех caps_mask включенных сервисов
|
||||
|
||||
|
||||
; dispatcher_find_by_id — Найти сервис по ID
|
||||
;
|
||||
; Вход : svc_id — числовой идентификатор сервиса
|
||||
; Выход: eax = SERVICE_ENTRY* или 0 если не найден
|
||||
proc dispatcher_find_by_id stdcall uses ecx esi, svc_id:dword
|
||||
mov ecx, [services_count]
|
||||
test ecx, ecx
|
||||
jz .not_found
|
||||
|
||||
mov esi, services_table
|
||||
mov eax, [svc_id]
|
||||
|
||||
.loop:
|
||||
cmp [esi + SERVICE_ENTRY.id], eax
|
||||
je .found
|
||||
|
||||
add esi, sizeof.SERVICE_ENTRY
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.not_found:
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.found:
|
||||
mov eax, esi
|
||||
ret
|
||||
endp
|
||||
|
||||
; Включить сервис по ID
|
||||
proc dispatcher_enable_by_id stdcall, svc_id:dword
|
||||
stdcall dispatcher_find_by_id, [svc_id]
|
||||
test eax, eax
|
||||
jz .not_found
|
||||
|
||||
stdcall dispatcher_enable_entry, eax
|
||||
ret
|
||||
|
||||
.not_found:
|
||||
mov eax, -1
|
||||
ret
|
||||
endp
|
||||
|
||||
; Выключить сервис по ID
|
||||
proc dispatcher_disable_by_id stdcall, svc_id:dword
|
||||
stdcall dispatcher_find_by_id, [svc_id]
|
||||
test eax, eax
|
||||
jz .not_found
|
||||
|
||||
stdcall dispatcher_disable_entry, eax
|
||||
ret
|
||||
|
||||
.not_found:
|
||||
mov eax, -1
|
||||
ret
|
||||
endp
|
||||
|
||||
; Включить сервис по указателю на SERVICE_ENTRY
|
||||
proc dispatcher_enable_entry stdcall uses ebx esi, entry_ptr:dword
|
||||
mov esi, [entry_ptr]
|
||||
|
||||
; Уже включен?
|
||||
cmp dword [esi + SERVICE_ENTRY.enabled], 1
|
||||
je .already_enabled
|
||||
|
||||
; Вызвать fn_enable если есть
|
||||
mov eax, [esi + SERVICE_ENTRY.fn_enable]
|
||||
test eax, eax
|
||||
jz .no_enable_fn
|
||||
|
||||
push esi
|
||||
call eax
|
||||
pop esi
|
||||
|
||||
test eax, eax
|
||||
jnz .enable_failed
|
||||
|
||||
.no_enable_fn:
|
||||
; Включить
|
||||
mov dword [esi + SERVICE_ENTRY.enabled], 1
|
||||
|
||||
; Добавить маски
|
||||
mov eax, [esi + SERVICE_ENTRY.event_mask]
|
||||
or [dispatcher_active_events], eax
|
||||
|
||||
mov eax, [esi + SERVICE_ENTRY.caps_mask]
|
||||
or [dispatcher_active_caps], eax
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] Enabled service ID=%d\n", [esi + SERVICE_ENTRY.id]
|
||||
|
||||
.already_enabled:
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.enable_failed:
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] Enable failed: 0x%x\n", eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; Выключить сервис по указателю
|
||||
proc dispatcher_disable_entry stdcall uses ebx esi, entry_ptr:dword
|
||||
mov esi, [entry_ptr]
|
||||
|
||||
; Уже выключен?
|
||||
cmp dword [esi + SERVICE_ENTRY.enabled], 0
|
||||
je .already_disabled
|
||||
|
||||
; Вызвать fn_disable если есть
|
||||
mov eax, [esi + SERVICE_ENTRY.fn_disable]
|
||||
test eax, eax
|
||||
jz .no_disable_fn
|
||||
|
||||
push esi
|
||||
call eax
|
||||
pop esi
|
||||
|
||||
.no_disable_fn:
|
||||
; Выключить
|
||||
mov dword [esi + SERVICE_ENTRY.enabled], 0
|
||||
|
||||
; Пересчитать активные маски
|
||||
call dispatcher_recalc_masks
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] Disabled service ID=%d\n", [esi + SERVICE_ENTRY.id]
|
||||
|
||||
.already_disabled:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; dispatcher_disable_all — Выключить все сервисы
|
||||
proc dispatcher_disable_all uses ecx esi
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] Disabling all services\n"
|
||||
|
||||
mov ecx, [services_count]
|
||||
test ecx, ecx
|
||||
jz .done
|
||||
|
||||
mov esi, services_table
|
||||
|
||||
.loop:
|
||||
stdcall dispatcher_disable_entry, esi
|
||||
add esi, sizeof.SERVICE_ENTRY
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Инициализация всех сервисов
|
||||
proc dispatcher_init_all uses ebx ecx esi
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] Initializing %d services...\n", [services_count]
|
||||
|
||||
mov ecx, [services_count]
|
||||
test ecx, ecx
|
||||
jz .done
|
||||
|
||||
mov esi, services_table
|
||||
|
||||
.loop:
|
||||
mov eax, [esi + SERVICE_ENTRY.fn_init]
|
||||
test eax, eax
|
||||
jz .next
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] Init service ID=%d, name=%s\n", [esi + SERVICE_ENTRY.id], [esi + SERVICE_ENTRY.name_ptr]
|
||||
push ecx esi
|
||||
call eax
|
||||
pop esi ecx
|
||||
|
||||
test eax, eax
|
||||
jnz .init_failed
|
||||
|
||||
.next:
|
||||
add esi, sizeof.SERVICE_ENTRY
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.done:
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] All services initialized\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.init_failed:
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] Service ID=%d init failed: 0x%x\n", [esi + SERVICE_ENTRY.id], eax
|
||||
jmp .next
|
||||
endp
|
||||
|
||||
; Включить сервисы с autostart=1
|
||||
proc dispatcher_enable_autostart uses ecx esi
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] Enabling autostart services...\n"
|
||||
|
||||
mov ecx, [services_count]
|
||||
test ecx, ecx
|
||||
jz .done
|
||||
|
||||
mov esi, services_table
|
||||
|
||||
.loop:
|
||||
cmp dword [esi + SERVICE_ENTRY.autostart], 1
|
||||
jne .next
|
||||
|
||||
push ecx esi
|
||||
stdcall dispatcher_enable_entry, esi
|
||||
pop esi ecx
|
||||
|
||||
.next:
|
||||
add esi, sizeof.SERVICE_ENTRY
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.done:
|
||||
DEBUGF 2, "[VBoxGuest] [Dispatcher] Autostart done, events=0x%x, caps=0x%x\n", \
|
||||
[dispatcher_active_events], [dispatcher_active_caps]
|
||||
ret
|
||||
endp
|
||||
|
||||
; Пересчитать активные маски
|
||||
proc dispatcher_recalc_masks uses ebx ecx edx esi
|
||||
xor edx, edx ; events
|
||||
xor ebx, ebx ; caps
|
||||
|
||||
mov ecx, [services_count]
|
||||
test ecx, ecx
|
||||
jz .done
|
||||
|
||||
mov esi, services_table
|
||||
|
||||
.loop:
|
||||
cmp dword [esi + SERVICE_ENTRY.enabled], 1
|
||||
jne .next
|
||||
|
||||
or edx, [esi + SERVICE_ENTRY.event_mask]
|
||||
or ebx, [esi + SERVICE_ENTRY.caps_mask]
|
||||
|
||||
.next:
|
||||
add esi, sizeof.SERVICE_ENTRY
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.done:
|
||||
mov [dispatcher_active_events], edx
|
||||
mov [dispatcher_active_caps], ebx
|
||||
ret
|
||||
endp
|
||||
|
||||
; Разослать события включенным сервисам
|
||||
proc dispatcher_dispatch stdcall uses ebx ecx edx esi, event_mask:dword
|
||||
mov edx, [event_mask]
|
||||
test edx, edx
|
||||
jz .done
|
||||
|
||||
mov ecx, [services_count]
|
||||
test ecx, ecx
|
||||
jz .done
|
||||
|
||||
mov esi, services_table
|
||||
|
||||
.loop:
|
||||
; Включен?
|
||||
cmp dword [esi + SERVICE_ENTRY.enabled], 0
|
||||
je .next
|
||||
|
||||
; Есть совпадение событий?
|
||||
mov eax, [esi + SERVICE_ENTRY.event_mask]
|
||||
test eax, edx
|
||||
jz .next
|
||||
|
||||
; Есть обработчик?
|
||||
mov eax, [esi + SERVICE_ENTRY.fn_on_event]
|
||||
test eax, eax
|
||||
jz .next
|
||||
|
||||
; Вызвать fn_on_event(event_mask)
|
||||
push ecx edx esi
|
||||
mov eax, edx
|
||||
call [esi + SERVICE_ENTRY.fn_on_event]
|
||||
pop esi edx ecx
|
||||
|
||||
.next:
|
||||
add esi, sizeof.SERVICE_ENTRY
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Вызвать fn_on_tick у включенных сервисов
|
||||
proc dispatcher_tick_all uses eax ecx esi
|
||||
mov ecx, [services_count]
|
||||
test ecx, ecx
|
||||
jz .done
|
||||
|
||||
mov esi, services_table
|
||||
|
||||
.loop:
|
||||
cmp dword [esi + SERVICE_ENTRY.enabled], 0
|
||||
je .next
|
||||
|
||||
mov eax, [esi + SERVICE_ENTRY.fn_on_tick]
|
||||
test eax, eax
|
||||
jz .next
|
||||
|
||||
push ecx esi
|
||||
call eax
|
||||
pop esi ecx
|
||||
|
||||
.next:
|
||||
add esi, sizeof.SERVICE_ENTRY
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
; Получить активную маску событий
|
||||
proc dispatcher_get_active_events
|
||||
mov eax, [dispatcher_active_events]
|
||||
ret
|
||||
endp
|
||||
|
||||
; Получить активную маску capabilities
|
||||
proc dispatcher_get_active_caps
|
||||
mov eax, [dispatcher_active_caps]
|
||||
ret
|
||||
endp
|
||||
114
drivers/vboxguest/core/dispatcher/dispatcher_macros.inc
Normal file
114
drivers/vboxguest/core/dispatcher/dispatcher_macros.inc
Normal file
@@ -0,0 +1,114 @@
|
||||
; =============================================================================
|
||||
; Модуль : Dispatcher Macros
|
||||
; Файл : core/dispatcher_macros.inc
|
||||
; Назначение : Макросы для авторегистрации сервисов VBoxGuest
|
||||
; =============================================================================
|
||||
|
||||
; Структура SERVICE_ENTRY (52 байта = 13 DWORD)
|
||||
struct SERVICE_ENTRY
|
||||
id dd ? ; +0: Уникальный ID (auto-increment)
|
||||
name_ptr dd ? ; +4: Указатель на строку имени
|
||||
event_mask dd ? ; +8: Маска событий VMMDev
|
||||
caps_mask dd ? ; +12: Маска guest capabilities
|
||||
enabled dd ? ; +16: 0=выключен, 1=включен
|
||||
autostart dd ? ; +20: 1=запуск с драйвером, 0=через vboxctrl
|
||||
fn_init dd ? ; +24: Инициализация (или 0)
|
||||
fn_enable dd ? ; +28: Включение (или 0)
|
||||
fn_disable dd ? ; +32: Выключение (или 0)
|
||||
fn_on_event dd ? ; +36: Обработчик IRQ (или 0)
|
||||
fn_on_tick dd ? ; +40: Обработчик тика (или 0)
|
||||
hgcm_wakeup_event dd ? ; +44: Event handle для пробуждения HGCM-треда из IRQ
|
||||
hgcm_wakeup_event_id dd ? ; +48: Event euid для пробуждения HGCM-треда из IRQ
|
||||
ends
|
||||
|
||||
; Алиас для кода использующего SERVICE_ENTRY_SIZE
|
||||
SERVICE_ENTRY_SIZE = sizeof.SERVICE_ENTRY
|
||||
|
||||
; =============================================================================
|
||||
; Инициализация списка сервисов (пустой)
|
||||
; =============================================================================
|
||||
__SERVICES_LIST__ equ
|
||||
|
||||
; =============================================================================
|
||||
; REGISTER_SERVICE - Регистрация сервиса
|
||||
; ID назначается автоматически (1, 2, 3, ...)
|
||||
; =============================================================================
|
||||
; Это позволяет корректно работать с IRP/forward
|
||||
; =============================================================================
|
||||
macro REGISTER_SERVICE svc_name, event_mask, caps_mask, fn_init, fn_enable, fn_disable, fn_on_event, fn_on_tick, autostart
|
||||
{
|
||||
; Добавляем в список с | как разделителем
|
||||
; Формат: name|evmask|capmask|init|enable|disable|onevent|ontick|autostart
|
||||
match any, __SERVICES_LIST__ \{
|
||||
__SERVICES_LIST__ equ __SERVICES_LIST__,svc_name|event_mask|caps_mask|fn_init|fn_enable|fn_disable|fn_on_event|fn_on_tick|autostart
|
||||
\}
|
||||
match , __SERVICES_LIST__ \{
|
||||
__SERVICES_LIST__ equ svc_name|event_mask|caps_mask|fn_init|fn_enable|fn_disable|fn_on_event|fn_on_tick|autostart
|
||||
\}
|
||||
}
|
||||
|
||||
; =============================================================================
|
||||
; BUILD_SERVICE_TABLE - Генерация таблицы сервисов
|
||||
; Создаёт:
|
||||
; services_table - массив SERVICE_ENTRY
|
||||
; services_table_end - метка конца
|
||||
; services_count - количество сервисов (dd)
|
||||
; SVC_ID_xxx - константы ID для каждого сервиса
|
||||
; =============================================================================
|
||||
macro BUILD_SERVICE_TABLE
|
||||
{
|
||||
align 4
|
||||
services_table:
|
||||
|
||||
; Проверка: есть ли сервисы?
|
||||
match , __SERVICES_LIST__ \{
|
||||
display 'WARNING: No services registered!', 13, 10
|
||||
\}
|
||||
|
||||
; Генерация записей
|
||||
match list, __SERVICES_LIST__ \{
|
||||
__BUILD_ENTRIES__ list
|
||||
\}
|
||||
|
||||
services_table_end:
|
||||
services_count dd __BUILD_ID__
|
||||
}
|
||||
|
||||
; =============================================================================
|
||||
; Вспомогательный макрос для построения записей
|
||||
; =============================================================================
|
||||
|
||||
__BUILD_ID__ = 0
|
||||
|
||||
macro __BUILD_ENTRIES__ [entry]
|
||||
{
|
||||
forward
|
||||
__BUILD_ID__ = __BUILD_ID__ + 1
|
||||
; Парсим entry с разделителем |
|
||||
; Формат: name|evmask|capmask|init|enable|disable|onevent|ontick|autostart
|
||||
match _name|_evmask|_capmask|_init|_enable|_disable|_onevent|_ontick|_auto, entry \{
|
||||
dd __BUILD_ID__ ; id
|
||||
dd _name ; name_ptr
|
||||
dd _evmask ; event_mask
|
||||
dd _capmask ; caps_mask
|
||||
dd 0 ; enabled = 0
|
||||
dd _auto ; autostart
|
||||
dd _init ; fn_init
|
||||
dd _enable ; fn_enable
|
||||
dd _disable ; fn_disable
|
||||
dd _onevent ; fn_on_event
|
||||
dd _ontick ; fn_on_tick
|
||||
dd 0 ; hgcm_wakeup_event (заполняется сервисом в runtime)
|
||||
dd 0 ; hgcm_wakeup_event_id
|
||||
\}
|
||||
}
|
||||
|
||||
; =============================================================================
|
||||
; Макрос для получения ID по имени переменной (опционально)
|
||||
; Использование: SVC_ID svc_name_var
|
||||
; =============================================================================
|
||||
macro SVC_ID name
|
||||
{
|
||||
; Поиск ID в рантайме через dispatcher_find_by_name
|
||||
; Или использовать константу если известна
|
||||
}
|
||||
109
drivers/vboxguest/core/irq.inc
Normal file
109
drivers/vboxguest/core/irq.inc
Normal file
@@ -0,0 +1,109 @@
|
||||
; =============================================================================
|
||||
; Модуль : IRQ Handler
|
||||
; Назначение : Обработчик прерываний VMMDev
|
||||
; Файл : core/irq.inc
|
||||
; =============================================================================
|
||||
|
||||
align 4
|
||||
vbox_irq_count dd 0
|
||||
|
||||
; vbox_irq_handler — Top-half обработчик IRQ
|
||||
proc vbox_irq_handler stdcall
|
||||
push ebx edx
|
||||
|
||||
movzx edx, word [vbox_device.port]
|
||||
add dx, VMMDEV_PORT_OFF_REQUEST_FAST
|
||||
in eax, dx
|
||||
|
||||
test eax, eax
|
||||
jz .not_ours
|
||||
|
||||
mov ebx, eax
|
||||
|
||||
; ACK все события сразу
|
||||
out dx, eax
|
||||
|
||||
DEBUGF __DEBUG_IRQ__, "[VBoxGuest] [Dispatch] [IRQ] events=0x%x, service event=0x%x\n", ebx, [dispatcher_active_events]
|
||||
|
||||
; Немедленно разбудить HGCM-треды (Linux: wake_up() из IRQ)
|
||||
test ebx, VMMDEV_EVENT_HGCM
|
||||
jz .no_hgcm_wake
|
||||
call hgcm_irq_dispatch
|
||||
.no_hgcm_wake:
|
||||
|
||||
; Вызвать fn_on_event у всех подходящих сервисов прямо сейчас
|
||||
stdcall dispatcher_dispatch, ebx
|
||||
|
||||
lock inc dword [vbox_irq_count]
|
||||
|
||||
.acked:
|
||||
pop edx ebx
|
||||
mov eax, 1
|
||||
ret
|
||||
|
||||
.not_ours:
|
||||
pop edx ebx
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; hgcm_irq_dispatch — Разбудить все HGCM-треды из IRQ контекста
|
||||
proc hgcm_irq_dispatch
|
||||
push eax ebx ecx edx esi edi
|
||||
|
||||
mov ecx, [services_count]
|
||||
test ecx, ecx
|
||||
jz .done
|
||||
|
||||
mov edi, services_table
|
||||
|
||||
.loop:
|
||||
cmp dword [edi + SERVICE_ENTRY.enabled], 0
|
||||
je .next
|
||||
|
||||
cmp dword [edi + SERVICE_ENTRY.hgcm_wakeup_event], 0
|
||||
je .next
|
||||
|
||||
mov eax, [edi + SERVICE_ENTRY.hgcm_wakeup_event]
|
||||
mov ebx, [edi + SERVICE_ENTRY.hgcm_wakeup_event_id]
|
||||
xor edx, edx
|
||||
xor esi, esi
|
||||
invoke RaiseEvent
|
||||
|
||||
.next:
|
||||
add edi, sizeof.SERVICE_ENTRY
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.done:
|
||||
pop edi esi edx ecx ebx eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; vmmdev_irq_install — Установить обработчик IRQ
|
||||
proc vmmdev_irq_install
|
||||
mov eax, [vbox_device.irq]
|
||||
test eax, eax
|
||||
jz .no_irq
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [IRQ] Attaching to IRQ %d\n", eax
|
||||
|
||||
invoke AttachIntHandler, eax, vbox_irq_handler, 0
|
||||
test eax, eax
|
||||
jz .failed
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [IRQ] Handler attached successfully\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.no_irq:
|
||||
DEBUGF 2, "[VBoxGuest] [IRQ] No IRQ line\n"
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
|
||||
.failed:
|
||||
DEBUGF 2, "[VBoxGuest] [IRQ] Attach failed\n"
|
||||
mov eax, VERR_INTERNAL_ERROR
|
||||
ret
|
||||
endp
|
||||
|
||||
74
drivers/vboxguest/core/mmio.inc
Normal file
74
drivers/vboxguest/core/mmio.inc
Normal file
@@ -0,0 +1,74 @@
|
||||
; =============================================================================
|
||||
; Модуль : Memory Mapped I/O Operations
|
||||
; Назначение : Работа с MMIO областью VMMDev
|
||||
; =============================================================================
|
||||
proc mmio_map_vmmdev
|
||||
; Маппинг физической памяти в виртуальное адресное пространство
|
||||
invoke MapIoMem, [vbox_device.mmio_phys], VMMDEV_MEMORY_SIZE, PG_NOCACHE + PG_SW
|
||||
test eax, eax
|
||||
jz .map_failed
|
||||
|
||||
; Сохраняем виртуальный адрес
|
||||
mov [vbox_device.mmio_virt], eax
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] Mapped to virtual address: 0x%x\n", eax
|
||||
|
||||
; Проверяем версию VMMDev
|
||||
call mmio_check_version
|
||||
test eax, eax
|
||||
jnz .version_check_failed
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] Mapping completed successfully\n"
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.map_failed:
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] ERROR: MapIoMem failed\n"
|
||||
mov eax, VERR_NO_MEMORY
|
||||
ret
|
||||
|
||||
.version_check_failed:
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] ERROR: VMMDev version check failed\n"
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
; mmio_check_version — Проверка версии VMMDev структуры в MMIO
|
||||
proc mmio_check_version
|
||||
mov edi, [vbox_device.mmio_virt]
|
||||
|
||||
; Отладочный вывод структуры VMMDev
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] VMMDev structure at 0x%x:\n", edi
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] size: 0x%x\n", [edi + VMMDEV_MEMORY.size]
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] version: 0x%x\n", [edi + VMMDEV_MEMORY.version]
|
||||
|
||||
; Проверяем минимальный размер структуры
|
||||
mov eax, [edi + VMMDEV_MEMORY.size]
|
||||
cmp eax, sizeof.VMMDEV_MEMORY
|
||||
jb .invalid_size
|
||||
|
||||
; Проверяем версию VMMDev
|
||||
mov eax, [edi + VMMDEV_MEMORY.version]
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] Detected VMMDev version: 0x%x (required: 0x%x)\n", \
|
||||
eax, VMMDEV_MEMORY_VERSION
|
||||
|
||||
; Проверяем совместимость версии (должна быть >= требуемой)
|
||||
cmp eax, VMMDEV_MEMORY_VERSION
|
||||
jae .version_ok
|
||||
|
||||
; Устаревшая версия - выводим предупреждение, но продолжаем
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] WARNING: Old VMMDev version: 0x%x (expected >= 0x%x)\n", \
|
||||
eax, VMMDEV_MEMORY_VERSION
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] Some features may be unavailable\n"
|
||||
|
||||
.version_ok:
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] VMMDev version check passed\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.invalid_size:
|
||||
DEBUGF 2, "[VBoxGuest] [MMIO] ERROR: Invalid VMMDev structure size: %d (expected >= %d)\n", \
|
||||
eax, sizeof.VMMDEV_MEMORY
|
||||
mov eax, -1
|
||||
ret
|
||||
endp
|
||||
117
drivers/vboxguest/core/pci.inc
Normal file
117
drivers/vboxguest/core/pci.inc
Normal file
@@ -0,0 +1,117 @@
|
||||
; =============================================================================
|
||||
; Модуль : PCI Device Detection
|
||||
; Назначение : Обнаружение и идентификация PCI устройства VirtualBox
|
||||
; Файл : core/pci.inc
|
||||
; =============================================================================
|
||||
|
||||
align 4
|
||||
pci_device dd ? ; Указатель на структуру PCI устройства VBox
|
||||
|
||||
; vmmdev_probe — Поиск PCI устройства VirtualBox в системе
|
||||
proc vmmdev_probe
|
||||
call pci_find_vmmdev
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
call pci_init_vmmdev_irq
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
call pci_init_vmmdev_bar
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
xor eax, eax
|
||||
ret
|
||||
.fail:
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] Initialization failed\n"
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
endp
|
||||
|
||||
proc pci_find_vmmdev
|
||||
; Получаем список PCI устройств
|
||||
invoke GetPCIList
|
||||
mov ebx, eax ; EBX = начало списка (якорь)
|
||||
|
||||
.search_loop:
|
||||
mov eax, [eax + PCIDEV.fd]
|
||||
cmp eax, ebx
|
||||
je .not_found
|
||||
|
||||
; Сравниваем Vendor/Device ID
|
||||
mov edx, [eax + PCIDEV.vendor_device_id]
|
||||
cmp edx, (VBOX_DEVICE_ID shl 16) + VBOX_VENDOR_ID
|
||||
jne .search_loop
|
||||
|
||||
.found:
|
||||
mov [pci_device], eax
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] VBox device found\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.not_found:
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] VBox device NOT found\n"
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
endp
|
||||
|
||||
; pci_init_vmmdev_irq — Чтение IRQ линии из PCI конфигурации
|
||||
proc pci_init_vmmdev_irq
|
||||
mov ebx, [pci_device]
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] pci_device=0x%x\n", [pci_device]
|
||||
test ebx, ebx
|
||||
jz .no_device
|
||||
|
||||
; Читаем IRQ линию из PCI конфигурации
|
||||
invoke PciRead32, dword [ebx + PCIDEV.bus], dword [ebx + PCIDEV.devfn], PCI_header00.interrupt_line
|
||||
movzx eax, al ; IRQ линия - младший байт
|
||||
|
||||
; Проверяем валидность IRQ (должна быть 0-15)
|
||||
cmp eax, 16
|
||||
jae .invalid_irq
|
||||
|
||||
; Сохраняем IRQ в структуре устройства
|
||||
mov [vbox_device.irq], eax
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] IRQ line: %d\n", eax
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.no_device:
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] ERROR: No PCI device for IRQ init\n"
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
|
||||
.invalid_irq:
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] ERROR: Invalid IRQ line: %d\n", eax
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
; pci_init_vmmdev_bar — Чтение BAR0 (I/O) и BAR1 (MMIO) из PCI конфигурации
|
||||
proc pci_init_vmmdev_bar
|
||||
mov ebx, [pci_device]
|
||||
test ebx, ebx
|
||||
jz .no_device
|
||||
|
||||
; Читаем BAR0 (I/O port)
|
||||
invoke PciRead32, dword [ebx + PCIDEV.bus], dword [ebx + PCIDEV.devfn], PCI_header00.base_addr_0
|
||||
and eax, not 0xF
|
||||
mov [vbox_device.port], ax
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] BAR0 (I/O Port): 0x%x\n", eax
|
||||
|
||||
; Читаем BAR1 (MMIO)
|
||||
invoke PciRead32, dword [ebx + PCIDEV.bus], dword [ebx + PCIDEV.devfn], PCI_header00.base_addr_1
|
||||
and eax, not 0xF
|
||||
mov [vbox_device.mmio_phys], eax
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] BAR1 (MMIO): phys=0x%x\n", eax
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.no_device:
|
||||
DEBUGF 2, "[VBoxGuest] [PCI] ERROR: No PCI device for BAR init\n"
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
|
||||
endp
|
||||
54
drivers/vboxguest/core/ports.inc
Normal file
54
drivers/vboxguest/core/ports.inc
Normal file
@@ -0,0 +1,54 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev I/O Ports
|
||||
; Назначение : Операции через I/O порты VMMDev (fast request/events)
|
||||
; Файл : core/ports.inc
|
||||
; =============================================================================
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; vmmdev_send_request — отправка физического адреса VMMDev-запроса в I/O порт
|
||||
;
|
||||
; Вход : phys_addr — физ. адрес VMMDev-пакета
|
||||
; Выход: —
|
||||
; -----------------------------------------------------------------------------
|
||||
proc vmmdev_send_request uses edx, phys_addr:dword
|
||||
mov eax, [phys_addr]
|
||||
|
||||
mov dx, [vbox_device.port]
|
||||
out dx, eax
|
||||
|
||||
; Спин-ожидание (~1ms): даёт хосту время на обработку запроса
|
||||
mov ecx, 1000000
|
||||
.wait:
|
||||
xor eax, eax
|
||||
loop .wait
|
||||
|
||||
ret
|
||||
endp
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; ports_init — проверка, что порт задан
|
||||
;
|
||||
; Выход: eax = 0 успех / VERR_INVALID_PARAMETER
|
||||
; -----------------------------------------------------------------------------
|
||||
proc ports_init
|
||||
movzx eax, word [vbox_device.port]
|
||||
test eax, eax
|
||||
jz .bad
|
||||
xor eax, eax
|
||||
ret
|
||||
.bad:
|
||||
mov eax, VERR_INVALID_PARAMETER
|
||||
ret
|
||||
endp
|
||||
|
||||
; ports_read_fast_events — прочитать pending mask через FAST порт
|
||||
;
|
||||
; Выход: eax = маска событий
|
||||
proc ports_read_fast_events uses edx
|
||||
mov dx, [vbox_device.port]
|
||||
add dx, VMMDEV_PORT_OFF_REQUEST_FAST
|
||||
in eax, dx
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
70
drivers/vboxguest/core/state.inc
Normal file
70
drivers/vboxguest/core/state.inc
Normal file
@@ -0,0 +1,70 @@
|
||||
; =============================================================================
|
||||
; Модуль : Driver Internal Structures
|
||||
; Назначение : Глобальная структура состояния драйвера VBoxGuest
|
||||
; Файл : core/state.inc
|
||||
; =============================================================================
|
||||
struct VBOX_DEVICE
|
||||
port dw ?
|
||||
pad1 dw ?
|
||||
mmio_virt dd ?
|
||||
mmio_phys dd ?
|
||||
|
||||
irq dd ?
|
||||
last_events dd ? ; последняя маска событий, прочитанная в IRQ
|
||||
event_filter dd ?
|
||||
caps dd ?
|
||||
|
||||
flags dd ?
|
||||
; бит0: device_present
|
||||
; бит1: mmio_mapped
|
||||
; бит2: irq_attached
|
||||
; бит3: timer_running
|
||||
|
||||
|
||||
; HGCM
|
||||
hgcm_timeout dd ?
|
||||
|
||||
; HGCM packets
|
||||
hgcm_connect_virt dd ?
|
||||
hgcm_connect_phys dd ?
|
||||
hgcm_disconnect_virt dd ?
|
||||
hgcm_disconnect_phys dd ?
|
||||
hgcm_call_virt dd ?
|
||||
hgcm_call_phys dd ?
|
||||
|
||||
; Pre-allocated packets
|
||||
display_virt dd ?
|
||||
display_phys dd ?
|
||||
events_virt dd ?
|
||||
events_phys dd ?
|
||||
filter_virt dd ?
|
||||
filter_phys dd ?
|
||||
caps_virt dd ?
|
||||
caps_phys dd ?
|
||||
guestinfo_virt dd ?
|
||||
guestinfo_phys dd ?
|
||||
guestinfo2_virt dd ?
|
||||
guestinfo2_phys dd ?
|
||||
|
||||
mouse_virt dd ?
|
||||
mouse_phys dd ?
|
||||
|
||||
hypervisor_info_virt dd ?
|
||||
hypervisor_info_phys dd ?
|
||||
dnd_call_virt dd ?
|
||||
dnd_call_phys dd ?
|
||||
host_version_virt dd ?
|
||||
host_version_phys dd ?
|
||||
|
||||
heartbeat_config_virt dd ?
|
||||
heartbeat_config_phys dd ?
|
||||
heartbeat_virt dd ?
|
||||
heartbeat_phys dd ?
|
||||
|
||||
; Pagelist HGCM call buffer (динамически выделяется)
|
||||
hgcm_call_pl_virt dd ?
|
||||
hgcm_call_pl_phys dd ?
|
||||
|
||||
; Единый блок памяти для VMMDev пакетов
|
||||
vmmdev_packets_page dd ?
|
||||
ends
|
||||
57
drivers/vboxguest/core/timer.inc
Normal file
57
drivers/vboxguest/core/timer.inc
Normal file
@@ -0,0 +1,57 @@
|
||||
; =============================================================================
|
||||
; Модуль : Timer
|
||||
; Назначение : Периодический вызов fn_on_tick сервисов
|
||||
; Файл : core/timer.inc
|
||||
; =============================================================================
|
||||
|
||||
align 4
|
||||
vbox_timer_handle dd 0
|
||||
|
||||
TIMER_DELAY_START equ 10 ; 100ms до первого вызова
|
||||
TIMER_INTERVAL equ 10 ; 100ms между вызовами
|
||||
|
||||
; timer_init — Запуск таймера
|
||||
proc timer_init
|
||||
DEBUGF 2, "[VBoxGuest] [Timer] Initializing...\n"
|
||||
|
||||
mov eax, [vbox_timer_handle]
|
||||
test eax, eax
|
||||
jnz .ok
|
||||
|
||||
invoke TimerHS, TIMER_DELAY_START, TIMER_INTERVAL, timer_cb, 0
|
||||
test eax, eax
|
||||
jz .err
|
||||
|
||||
mov [vbox_timer_handle], eax
|
||||
DEBUGF 2, "[VBoxGuest] [Timer] Started, handle=0x%x, interval=%dms\n", \
|
||||
eax, TIMER_INTERVAL * 10
|
||||
|
||||
.ok:
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.err:
|
||||
DEBUGF 2, "[VBoxGuest] [Timer] ERROR: Failed to start\n"
|
||||
mov eax, VERR_INTERNAL_ERROR
|
||||
ret
|
||||
endp
|
||||
|
||||
; timer_stop — Остановка таймера
|
||||
proc timer_stop
|
||||
mov eax, [vbox_timer_handle]
|
||||
test eax, eax
|
||||
jz .done
|
||||
|
||||
invoke CancelTimerHS, eax
|
||||
mov dword [vbox_timer_handle], 0
|
||||
DEBUGF 2, "[VBoxGuest] [Timer] Stopped\n"
|
||||
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Callback таймера — вызывает fn_on_tick у всех включенных сервисов
|
||||
proc timer_cb stdcall, userdata:dword
|
||||
stdcall dispatcher_tick_all
|
||||
ret
|
||||
endp
|
||||
80
drivers/vboxguest/data/clipboard/constants.inc
Normal file
80
drivers/vboxguest/data/clipboard/constants.inc
Normal file
@@ -0,0 +1,80 @@
|
||||
; =============================================================================
|
||||
; Clipboard Constants — из VBox 7.2.6 исходников
|
||||
;
|
||||
; Источники:
|
||||
; include/VBox/HostServices/VBoxClipboardSvc.h
|
||||
; include/VBox/GuestHost/SharedClipboard.h
|
||||
; =============================================================================
|
||||
|
||||
; =============================================================================
|
||||
; Guest function numbers (VBOX_SHCL_GUEST_FN_*)
|
||||
; Гость вызывает эти функции через HGCM
|
||||
; =============================================================================
|
||||
VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT equ 1 ; Ждать сообщение от хоста (blocking, deprecated но работает)
|
||||
VBOX_SHCL_GUEST_FN_REPORT_FORMATS equ 2 ; Сообщить хосту о доступных форматах
|
||||
VBOX_SHCL_GUEST_FN_DATA_READ equ 3 ; Прочитать данные с хоста
|
||||
VBOX_SHCL_GUEST_FN_DATA_WRITE equ 4 ; Записать данные на хост
|
||||
VBOX_SHCL_GUEST_FN_CONNECT equ 5 ; (deprecated в 7.x)
|
||||
VBOX_SHCL_GUEST_FN_REPORT_FEATURES equ 6 ; Сообщить о поддерживаемых фичах
|
||||
VBOX_SHCL_GUEST_FN_QUERY_FEATURES equ 7 ; Запросить фичи хоста
|
||||
VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT equ 8 ; Peek без блокировки
|
||||
VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT equ 9 ; Peek с блокировкой
|
||||
VBOX_SHCL_GUEST_FN_MSG_GET equ 10 ; Получить сообщение (новый протокол)
|
||||
VBOX_SHCL_GUEST_FN_MSG_CANCEL equ 26 ; Отменить ожидание
|
||||
|
||||
; Количества параметров
|
||||
VBOX_SHCL_CPARMS_MSG_OLD_GET_WAIT equ 2
|
||||
VBOX_SHCL_CPARMS_REPORT_FORMATS equ 1
|
||||
VBOX_SHCL_CPARMS_DATA_READ equ 3
|
||||
VBOX_SHCL_CPARMS_DATA_WRITE_OLD equ 2 ; Без CONTEXT_ID (старый протокол)
|
||||
VBOX_SHCL_CPARMS_DATA_WRITE equ 3 ; С CONTEXT_ID (новый протокол)
|
||||
|
||||
; =============================================================================
|
||||
; Host message types (VBOX_SHCL_HOST_MSG_*)
|
||||
; Приходят в parm[0] от MSG_OLD_GET_WAIT
|
||||
;
|
||||
; КРИТИЧНО! В старом коде были НЕПРАВИЛЬНЫЕ значения:
|
||||
; было: FORMATS_REPORT=1, READ_DATA=2, WRITE_DATA=3
|
||||
; надо: QUIT=1, READ_DATA=2, FORMATS_REPORT=3
|
||||
; =============================================================================
|
||||
VBOX_SHCL_HOST_MSG_QUIT equ 1 ; Хост закрывает клипборд
|
||||
VBOX_SHCL_HOST_MSG_READ_DATA equ 2 ; Хост хочет прочитать данные гостя
|
||||
VBOX_SHCL_HOST_MSG_FORMATS_REPORT equ 3 ; Хост сообщает о новых форматах
|
||||
VBOX_SHCL_HOST_MSG_CANCELED equ 4 ; Отмена
|
||||
|
||||
; =============================================================================
|
||||
; Format flags (VBOX_SHCL_FMT_*) — БИТОВЫЕ МАСКИ
|
||||
;
|
||||
; КРИТИЧНО! В старом коде были НЕПРАВИЛЬНЫЕ значения:
|
||||
; было: FMT_TEXT=1, FMT_UNICODETEXT=13
|
||||
; надо: FMT_UNICODETEXT=1 (bit 0), FMT_BITMAP=2 (bit 1), FMT_HTML=4 (bit 2)
|
||||
; FMT_TEXT не существует в VBox! Только UNICODETEXT (UTF-16LE)
|
||||
; =============================================================================
|
||||
VBOX_SHCL_FMT_NONE equ 0x0000
|
||||
VBOX_SHCL_FMT_UNICODETEXT equ 0x0001 ; bit 0 — UTF-16LE текст
|
||||
VBOX_SHCL_FMT_BITMAP equ 0x0002 ; bit 1 — DIB bitmap
|
||||
VBOX_SHCL_FMT_HTML equ 0x0004 ; bit 2 — HTML
|
||||
VBOX_SHCL_FMT_URI_LIST equ 0x0008 ; bit 3 — URI list (drag-n-drop)
|
||||
VBOX_SHCL_FMT_VALID_MASK equ 0x000F
|
||||
|
||||
; Буфер
|
||||
VBOX_SHCL_MAX_CHUNK_SIZE equ 0x10000 ; 64KB
|
||||
|
||||
; Событие VMMDev для clipboard
|
||||
CLIPBOARD_EVENT_MASK equ VMMDEV_EVENT_HGCM ; bit 1 = 0x02
|
||||
CLIPBOARD_CAPS_MASK equ 0 ; VMMDEV_GUEST_SUPPORTS_SHCL ; bit 7 = 0x80
|
||||
|
||||
; =============================================================================
|
||||
; Состояния listener'а
|
||||
; =============================================================================
|
||||
CLIP_LISTEN_IDLE equ 0 ; Не слушаем
|
||||
CLIP_LISTEN_SUBMITTED equ 1 ; Запрос отправлен в VMMDev, ждём ответ
|
||||
|
||||
; Максимум ошибок подряд до отключения
|
||||
CLIP_MAX_ERRORS equ 5
|
||||
|
||||
; Флаги KolibriOS события (для CreateEvent)
|
||||
CLIP_MANUAL_DESTROY equ 0x80000000 ; Событие не уничтожается после WaitEvent
|
||||
|
||||
; VBOXGUEST_GUEST_CAPS_OR_MASK equ ( VBOXGUEST_GUEST_CAPS_OR_MASK or CLIPBOARD_CAPS_MASK )
|
||||
; VBOXGUEST_EVENTS_OR_MASK equ ( VBOXGUEST_EVENTS_OR_MASK or CLIPBOARD_EVENT_MASK )
|
||||
73
drivers/vboxguest/data/clipboard/structs.inc
Normal file
73
drivers/vboxguest/data/clipboard/structs.inc
Normal file
@@ -0,0 +1,73 @@
|
||||
; =============================================================================
|
||||
; Clipboard (HGCM service: Shared Clipboard / SHCL)
|
||||
; =============================================================================
|
||||
struct SHCL_MSG_GET
|
||||
header HGCM_CALL
|
||||
msg_type HGCM_PARM
|
||||
formats HGCM_PARM
|
||||
ends
|
||||
|
||||
struct SHCL_FORMATS_REPORT
|
||||
header HGCM_CALL
|
||||
formats HGCM_PARM
|
||||
ends
|
||||
|
||||
struct SHCL_DATA_READ
|
||||
header HGCM_CALL
|
||||
format HGCM_PARM
|
||||
buffer HGCM_PARM
|
||||
size HGCM_PARM
|
||||
ends
|
||||
|
||||
struct SHCL_DATA_WRITE
|
||||
header HGCM_CALL
|
||||
format HGCM_PARM
|
||||
buffer HGCM_PARM
|
||||
ends
|
||||
|
||||
|
||||
|
||||
; =============================================================================
|
||||
; Clipboard Structures
|
||||
;
|
||||
; ПРИМЕЧАНИЕ: Старые структуры SHCL_MSG_GET, SHCL_FORMATS_REPORT,
|
||||
; SHCL_DATA_READ, SHCL_DATA_WRITE УДАЛЕНЫ — они не нужны.
|
||||
;
|
||||
; Новый код использует плоский массив HGCM_PARM + hgcm_call32_pagelist,
|
||||
; как в guest_props. Структуры с встроенным HGCM_CALL заголовком
|
||||
; были нужны только для ручного формирования пакетов через
|
||||
; hgcm_send_request, что больше не используется.
|
||||
; =============================================================================
|
||||
|
||||
; struct CLIPBOARD_STATE
|
||||
; client_id dd ? ; HGCM client ID
|
||||
; connected dd ? ; 0 = not connected, 1 = connected
|
||||
; formats_host dd ? ; Форматы доступные на хосте (битовая маска VBOX_SHCL_FMT_*)
|
||||
; formats_guest dd ? ; Форматы доступные у гостя
|
||||
; listen_state dd ?
|
||||
; error_count dd ?
|
||||
; ends
|
||||
|
||||
struct CLIPBOARD_STATE
|
||||
client_id dd ? ; HGCM client ID
|
||||
connected dd ? ; 0/1
|
||||
listen_state dd ? ; IDLE/SUBMITTED
|
||||
error_count dd ? ; Счетчик ошибок
|
||||
formats_host dd ? ; Форматы от хоста
|
||||
formats_guest dd ? ; Наши форматы
|
||||
has_data dd ? ; Есть данные для чтения
|
||||
data_size dd ? ; Размер данных
|
||||
|
||||
; Динамически выделяемые буферы
|
||||
data_buf_ptr dd ? ; -> clip_data_buf (KernelAlloc 64K)
|
||||
listen_pkt_virt dd ? ; -> clip_listen_pkt (KernelAlloc 4096, DMA)
|
||||
listen_pkt_phys dd ? ; физ. адрес listen_pkt
|
||||
parms_ptr dd ? ; -> clip_parms (KernelAlloc)
|
||||
debug_buf_ptr dd ? ; -> clip_debug_buf (KernelAlloc)
|
||||
|
||||
; Поток слушателя (thread-based listener)
|
||||
hgcm_event dd ? ; event handle (из CreateEvent)
|
||||
hgcm_event_id dd ? ; event euid (из CreateEvent)
|
||||
thread_id dd ? ; thread ID (из CreateThread)
|
||||
thread_stop dd ? ; 1 = попросить поток завершиться
|
||||
ends
|
||||
135
drivers/vboxguest/data/core/constants.inc
Normal file
135
drivers/vboxguest/data/core/constants.inc
Normal file
@@ -0,0 +1,135 @@
|
||||
; =============================================================================
|
||||
; Модуль : VBoxGuest Core Constants
|
||||
; Файл : data/core/constants.inc
|
||||
; Назначение : VMMDev константы и определения (PCI, версия, маски событий)
|
||||
; =============================================================================
|
||||
|
||||
; PCI
|
||||
VBOX_VENDOR_ID equ 0x80EE
|
||||
VBOX_DEVICE_ID equ 0xCAFE
|
||||
|
||||
; VMMDev протокол v1_04
|
||||
VMMDEV_VERSION_MAJOR equ 1
|
||||
VMMDEV_VERSION_MINOR equ 4
|
||||
VMMDEV_VERSION equ (VMMDEV_VERSION_MAJOR shl 16) or VMMDEV_VERSION_MINOR
|
||||
|
||||
VMMDEV_REQUEST_HEADER_VERSION equ 0x00010001
|
||||
VMMDEV_HF_FAST_IRQ_ACK equ 0x00000001
|
||||
VMMDEV_MEMORY_VERSION equ 1
|
||||
VMMDEV_MEMORY_SIZE equ 0x00400000
|
||||
|
||||
VMMDEV_PORT_OFF_REQUEST equ 0
|
||||
VMMDEV_PORT_OFF_REQUEST_FAST equ 8
|
||||
|
||||
VMMDEV_MAX_HGCM_PARMS equ 32
|
||||
VMMDEV_MAX_HGCM_DATA_SIZE equ 128 ; MB
|
||||
|
||||
; VMMDev Request Types
|
||||
VMMDEV_REQ_GET_HOST_VERSION equ 4
|
||||
VMMDEV_REQ_ACKNOWLEDGE_EVENTS equ 41
|
||||
VMMDEV_REQ_CTL_GUEST_FILTER_MASK equ 42
|
||||
VMMDEV_REQ_REPORT_GUEST_INFO equ 50
|
||||
VMMDEV_REQ_GET_DISPLAY_CHANGE_2 equ 54
|
||||
VMMDEV_REPORT_GUEST_CAPS equ 55
|
||||
VMMDEV_SET_GUEST_CAPS equ 56
|
||||
VMMDEV_REQ_REPORT_GUEST_INFO2 equ 58
|
||||
VMMDEV_HGCM_CONNECT equ 60
|
||||
VMMDEV_HGCM_DISCONNECT equ 61
|
||||
VMMDEV_HGCM_CALL32 equ 62
|
||||
VMMDEV_HGCM_CALL64 equ 63
|
||||
|
||||
VBOXGSTINFO2_F_REQUESTOR_INFO equ 0x00000001
|
||||
|
||||
; Guest capabilities
|
||||
VMMDEV_GUEST_SUPPORTS_SEAMLESS equ 0x00000001
|
||||
VMMDEV_GUEST_SUPPORTS_GHW_MAPPING equ 0x00000002
|
||||
VMMDEV_GUEST_SUPPORTS_GRAPHICS equ 0x00000004
|
||||
VMMDEV_GUEST_SUPPORTS_VRDP equ 0x00000010
|
||||
VMMDEV_GUEST_SUPPORTS_HGCM equ 0x00000020
|
||||
VMMDEV_GUEST_SUPPORTS_ACPI equ 0x00000040
|
||||
VMMDEV_GUEST_SUPPORTS_SHCL equ 0x00000080
|
||||
VMMDEV_GUEST_SUPPORTS_VRDP_RESIZE equ 0x00000100
|
||||
VMMDEV_GUEST_SUPPORTS_DRAG_AND_DROP equ 0x00000200
|
||||
VMMDEV_GUEST_SUPPORTS_CR3_MONITORING equ 0x00000400
|
||||
VMMDEV_GUEST_SUPPORTS_TIMER_NS equ 0x00000800
|
||||
VMMDEV_GUEST_SUPPORTS_GUEST_HEARTBEAT equ 0x00001000
|
||||
VMMDEV_GUEST_SUPPORTS_HOST_DISPLAY_TOPOLOGY equ 0x00002000
|
||||
VMMDEV_GUEST_SUPPORTS_REQUESTOR equ 0x00004000
|
||||
VMMDEV_GUEST_SUPPORTS_VBVA equ 0x00008000
|
||||
VMMDEV_GUEST_SUPPORTS_SET_GUEST_CAPABILITIES equ 0x00010000
|
||||
VMMDEV_GUEST_SUPPORTS_MOUSE equ 0x00020000
|
||||
VMMDEV_GUEST_SUPPORTS_SHARED_FOLDERS equ 0x00040000
|
||||
VMMDEV_GUEST_SUPPORTS_VIDEO_ACCEL equ 0x00080000
|
||||
VMMDEV_GUEST_SUPPORTS_AUDIO equ 0x00100000
|
||||
VMMDEV_GUEST_SUPPORTS_TSC_EMULATION equ 0x00200000
|
||||
|
||||
; VMMDev события (биты)
|
||||
VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED equ 0x00000001 ; bit 0
|
||||
VMMDEV_EVENT_HGCM equ 0x00000002 ; bit 1
|
||||
VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST equ 0x00000004 ; bit 2
|
||||
VMMDEV_EVENT_JUDGE_CREDENTIALS equ 0x00000008 ; bit 3
|
||||
VMMDEV_EVENT_RESTORED equ 0x00000010 ; bit 4
|
||||
VMMDEV_EVENT_SEAMLESS_MODE_CHANGE equ 0x00000020 ; bit 5
|
||||
VMMDEV_EVENT_BALLOON_CHANGE_REQUEST equ 0x00000040 ; bit 6
|
||||
VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE equ 0x00000080 ; bit 7
|
||||
VMMDEV_EVENT_VRDP equ 0x00000100 ; bit 8
|
||||
VMMDEV_EVENT_MOUSE_POSITION_CHANGED equ 0x00000200 ; bit 9
|
||||
VMMDEV_EVENT_CPU_HOTPLUG equ 0x00000400 ; bit 10
|
||||
VMMDEV_EVENT_VALID_EVENT_MASK equ 0x000007FF ; bits 0-10
|
||||
VMMDEV_EVENT_GUEST_HEARTBEAT equ 0x00040000
|
||||
VMMDEV_EVENT_GUEST_HEARTBEAT_TIMEOUT equ 0x00080000
|
||||
VMMDEV_EVENT_HGCM_ASYNC_CALL equ 0x00100000
|
||||
|
||||
; Накопительные маски событий и capabilities (сервисы добавляют через OR)
|
||||
VBOXGUEST_EVENTS_OR_MASK equ 0
|
||||
VBOXGUEST_EVENTS_NOT_MASK equ 0
|
||||
VBOXGUEST_GUEST_CAPS_OR_MASK equ 0
|
||||
VBOXGUEST_GUEST_CAPS_NOT_MASK equ 0
|
||||
|
||||
; Маска «шумных» событий — НЕ логировать
|
||||
DISPATCHER_NOISY_EVENTS equ (VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED or VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
|
||||
|
||||
; OS Type
|
||||
VBOXOSTYPE_KOLIBRIOS equ 0x00090000
|
||||
|
||||
; HGCM размеры пакетов
|
||||
HGCM_CALL_HEADER_SIZE equ 32
|
||||
HGCM_CALL_BASE_SIZE equ 44
|
||||
HGCM_PARAM_SIZE equ 12
|
||||
|
||||
; Host Features
|
||||
VMMDEV_HVF_MMIO equ 0x00000002
|
||||
|
||||
; Memory Balloon
|
||||
VMMDEV_MEMORY_BALLOON_CHUNK_SIZE equ 0x00100000
|
||||
VMMDEV_MEMORY_BALLOON_CHUNK_PAGES equ 0x100
|
||||
|
||||
; Guest Facility Types
|
||||
VBoxGuestFacilityType_VBoxGuestDriver equ 0
|
||||
VBoxGuestFacilityType_VBoxService equ 1
|
||||
VBoxGuestFacilityType_VBoxTrayClient equ 2
|
||||
VBoxGuestFacilityType_Seamless equ 3
|
||||
VBoxGuestFacilityType_Graphics equ 4
|
||||
|
||||
; Guest Facility Status
|
||||
VBoxGuestFacilityStatus_Inactive equ 0
|
||||
VBoxGuestFacilityStatus_Active equ 1
|
||||
|
||||
; Requestor flags
|
||||
VMMDEV_REQUESTOR_USR_NOT_GIVEN equ 0x00000000
|
||||
VMMDEV_REQUESTOR_USR_DRV equ 0x00000001
|
||||
VMMDEV_REQUESTOR_USR_DRV_OTHER equ 0x00000002
|
||||
VMMDEV_REQUESTOR_USR_ROOT equ 0x00000003
|
||||
VMMDEV_REQUESTOR_USR_USER equ 0x00000006
|
||||
VMMDEV_REQUESTOR_KERNEL equ 0x00000000
|
||||
VMMDEV_REQUESTOR_USERMODE equ 0x00000008
|
||||
VMMDEV_REQUESTOR_CON_DONT_KNOW equ 0x00000000
|
||||
VMMDEV_REQUESTOR_CON_NO equ 0x00000010
|
||||
VMMDEV_REQUESTOR_CON_YES equ 0x00000020
|
||||
VMMDEV_REQUESTOR_GRP_VBOX equ 0x00000080
|
||||
VMMDEV_REQUESTOR_TRUST_NOT_GIVEN equ 0x00000000
|
||||
VMMDEV_REQUESTOR_VBOXGUEST equ (VMMDEV_REQUESTOR_USR_DRV or VMMDEV_REQUESTOR_GRP_VBOX)
|
||||
|
||||
; MMIO смещения
|
||||
VMMDEV_MEMORY_HAVE_EVENTS_V1_04 equ 0x14
|
||||
VMMDEV_MEMORY_HAVE_EVENTS_V1_03 equ 0x0C
|
||||
297
drivers/vboxguest/data/core/structs.inc
Normal file
297
drivers/vboxguest/data/core/structs.inc
Normal file
@@ -0,0 +1,297 @@
|
||||
; =============================================================================
|
||||
; VBoxGuest : Data / VMMDev структуры
|
||||
; Назначение: ABI структуры протокола VMMDev (точное соответствие заголовкам VBox)
|
||||
; Файл : data/core/structs.inc
|
||||
; =============================================================================
|
||||
|
||||
; =============================================================================
|
||||
; Базовый заголовок запросов VMMDev (VMMDevRequestHeader)
|
||||
; =============================================================================
|
||||
struct VMMDEV_HEADER
|
||||
size dd ? ; 0 - размер пакета
|
||||
version dd ? ; 4 - версия, = VMMDEV_REQUEST_HEADER_VERSION
|
||||
request_type dd ? ; 8 - тип запроса
|
||||
rc dd ? ; 12 - код возврата
|
||||
reserved1 dd ? ; 16 - ВАЖНО! Это поле ДОЛЖНО быть, значение 0
|
||||
f_requestor dd ? ; 20 - флаги requestor
|
||||
ends ; Размер = 24 БАЙТА
|
||||
|
||||
; =============================================================================
|
||||
; Структура VMMDevMemory v1_04
|
||||
; =============================================================================
|
||||
struct VMMDEV_MEMORY
|
||||
size dd ? ; 0x00 размер области (в байтах)
|
||||
version dd ? ; 0x04 версия структуры (u32Version)
|
||||
have_events dd ?
|
||||
; vb_va_memory VB_VA_MEMORY
|
||||
ends
|
||||
|
||||
; VBVA memory layout => typedef struct VBVAMEMORY
|
||||
struct VB_VA_MEMORY
|
||||
; fu32_mode_flags dd ?
|
||||
; off32_data dd ?
|
||||
; off32_free dd ?
|
||||
; au8_ring_buffer dd ? ; VMMDEV_VBVA_RING_BUFFER_SIZE
|
||||
; VMMDEVVBVARECORD aRecords[VMMDEV_VBVA_MAX_RECORDS];
|
||||
; index_record_first dd ?
|
||||
; index_record_free dd ?
|
||||
; fu32_supported_orders dd?
|
||||
; reserved1 dd ? ; 0x0C: Зарезервировано
|
||||
; host_features dd ? ; 0x10: Возможности хоста
|
||||
; guest_features dd ? ; 0x14: Возможности гостя
|
||||
; mouse_features dd ? ; 0x18: Возможности мыши
|
||||
; mouse_pos_x dd ? ; 0x1C: Позиция мыши X
|
||||
; mouse_pos_y dd ? ; 0x20: Позиция мыши Y
|
||||
ends
|
||||
; =============================================================================
|
||||
; Запрос: Version Request
|
||||
; =============================================================================
|
||||
struct VMMDEV_GET_HOST_VERSION
|
||||
header VMMDEV_HEADER
|
||||
major dw ?
|
||||
minor dw ?
|
||||
build dd ?
|
||||
revision dd ?
|
||||
features dd ?
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: ReportGuestInfo (VMMDevReq_ReportGuestInfo = 50)
|
||||
; =============================================================================
|
||||
struct VMMDEV_REPORT_GUEST_INFO
|
||||
header VMMDEV_HEADER
|
||||
interface_version dd ? ; VMMDEV_VERSION (0x00010004)
|
||||
os_type dd ? ; VBOXOSTYPE_*
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: ReportGuestInfo2 (VMMDevReq_ReportGuestInfo2 = 58)
|
||||
; Используется в vgdrvReportGuestInfo
|
||||
; =============================================================================
|
||||
struct VMMDEV_GUEST_INFO2
|
||||
additions_major dw ? ; VBOX_VERSION_MAJOR
|
||||
additions_minor dw ? ; VBOX_VERSION_MINOR
|
||||
additions_build dd ? ; VBOX_VERSION_BUILD
|
||||
additions_revision dd ? ; VBOX_SVN_REV
|
||||
additions_features dd ? ; VBOXGSTINFO2_F_REQUESTOR_INFO
|
||||
szName rb 128 ; VBOX_VERSION_STRING
|
||||
ends
|
||||
|
||||
struct VMMDEV_REPORT_GUEST_INFO2
|
||||
header VMMDEV_HEADER
|
||||
guest_info VMMDEV_GUEST_INFO2
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: GetHypervisorInfo (VMMDevReq_GetHypervisorInfo = 2)
|
||||
; =============================================================================
|
||||
struct VMMDEV_REQ_HYPERVISOR_INFO
|
||||
header VMMDEV_HEADER
|
||||
hypervisorStart dd ? ; GCPhys32
|
||||
hypervisorSize dd ?
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: SetHypervisorInfo (VMMDevReq_SetHypervisorInfo = 3)
|
||||
; =============================================================================
|
||||
struct VMMDEV_SET_HYPERVISOR_INFO
|
||||
header VMMDEV_HEADER
|
||||
hypervisorStart dd ? ; GCPhys32
|
||||
hypervisorSize dd ?
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: AcknowledgeEvents (VMMDevReq_AcknowledgeEvents = 41)
|
||||
; В коде: VMMDevEvents
|
||||
; =============================================================================
|
||||
struct VMMDEV_EVENTS
|
||||
header VMMDEV_HEADER
|
||||
events dd ? ; IN/OUT: маска событий
|
||||
ends
|
||||
|
||||
; Алиас для совместимости
|
||||
struct VMMDEV_ACKNOWLEDGE_EVENTS
|
||||
header VMMDEV_HEADER
|
||||
events dd ?
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: CtlGuestFilterMask (VMMDevReq_CtlGuestFilterMask = 42)
|
||||
; guestEventFilter = (guestEventFilter | u32OrMask) & ~u32NotMask
|
||||
; =============================================================================
|
||||
struct VMMDEV_CTL_GUEST_FILTER_MASK
|
||||
header VMMDEV_HEADER
|
||||
or_mask dd ? ; маска OR
|
||||
not_mask dd ? ; маска NOT
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: SetGuestCapabilities (VMMDevReq_SetGuestCapabilities = 55)
|
||||
; guestCaps = (guestCaps | u32OrMask) & ~u32NotMask
|
||||
; VMMDevReqGuestCapabilities2 = VMMDevReq_SetGuestCapabilities
|
||||
; =============================================================================
|
||||
struct VMMDEV_SET_GUEST_CAPABILITIES2
|
||||
header VMMDEV_HEADER
|
||||
or_mask dd ? ; маска OR
|
||||
not_mask dd ? ; маска NOT
|
||||
ends
|
||||
|
||||
; Алиас для совместимости
|
||||
struct VMMDEV_GUEST_CAPS2
|
||||
header VMMDEV_HEADER
|
||||
or_mask dd ?
|
||||
not_mask dd ?
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: GetDisplayChangeRequest2 (VMMDevReq_GetDisplayChangeRequest2 = 54)
|
||||
; =============================================================================
|
||||
struct VMMDEV_GET_DISPLAY_CHANGE_REQUEST2
|
||||
header VMMDEV_HEADER
|
||||
x_res dd ?
|
||||
y_res dd ?
|
||||
bpp dd ?
|
||||
event_ack dd ? ; BOOL: 0/1 (false/true)
|
||||
display dd ? ; индекс дисплея (0 для основного)
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: ReportGuestStatus (VMMDevReq_ReportGuestStatus = 61)
|
||||
; =============================================================================
|
||||
struct VBOXGUEST_STATUS
|
||||
facility dd ? ; VBoxGuestFacilityType_*
|
||||
status dd ? ; VBoxGuestFacilityStatus_*
|
||||
flags dd ?
|
||||
ends
|
||||
|
||||
struct VMMDEV_REPORT_GUEST_STATUS
|
||||
header VMMDEV_HEADER
|
||||
guestStatus VBOXGUEST_STATUS
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Memory Ballooning Structures
|
||||
; =============================================================================
|
||||
|
||||
; Запрос: GetMemBalloonChangeRequest
|
||||
struct VMMDEV_GET_MEM_BALLOON_CHANGE_REQUEST
|
||||
header VMMDEV_HEADER
|
||||
eventAck dd ?
|
||||
cBalloonChunks dd ?
|
||||
cPhysMemChunks dd ?
|
||||
ends
|
||||
|
||||
; Запрос: ChangeMemBalloon
|
||||
struct VMMDEV_CHANGE_MEM_BALLOON
|
||||
header VMMDEV_HEADER
|
||||
cPages dd ?
|
||||
fInflate dd ? ; true = inflate, false = deflate
|
||||
aPhysPage rd VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
|
||||
ends
|
||||
|
||||
|
||||
|
||||
; =============================================================================
|
||||
; Вспомогательные структуры
|
||||
; =============================================================================
|
||||
|
||||
; SHFLSTRING - строка с длиной (UTF-8 или UTF-16)
|
||||
struct SHFLSTRING
|
||||
size dw ? ; Размер буфера в байтах
|
||||
length dw ? ; Длина строки в байтах (без null terminator)
|
||||
string rb 0 ; Начало строки (переменный размер)
|
||||
ends
|
||||
|
||||
; SHFLFSOBJINFO - информация о файле/директории (92 байта)
|
||||
; Источник: include/iprt/types.h — RTFSOBJINFO
|
||||
struct SHFLFSOBJINFO
|
||||
size_low dd ? ; +0: cbObject low (int64_t)
|
||||
size_high dd ? ; +4: cbObject high
|
||||
allocated_low dd ? ; +8: cbAllocated low (int64_t)
|
||||
allocated_high dd ? ; +12: cbAllocated high
|
||||
access_time_low dd ? ; +16: AccessTime low (RTTIMESPEC, nanoseconds)
|
||||
access_time_high dd ? ; +20: AccessTime high
|
||||
modification_time_low dd ? ; +24: ModificationTime low
|
||||
modification_time_high dd ? ; +28: ModificationTime high
|
||||
change_time_low dd ? ; +32: ChangeTime low
|
||||
change_time_high dd ? ; +36: ChangeTime high
|
||||
birth_time_low dd ? ; +40: BirthTime low
|
||||
birth_time_high dd ? ; +44: BirthTime high
|
||||
fMode dd ? ; +48: RTFMODE (тип+права: 0x4000=dir, 0x8000=file)
|
||||
attr_reserved rb 40 ; +52: остаток RTFSOBJATTR (enmAdditional + union)
|
||||
ends ; = 48 + 4 + 40 = 92 байт
|
||||
|
||||
; SHFLMAPPING - информация о mapping (для QUERY_MAPPINGS)
|
||||
struct SHFLMAPPING
|
||||
flags dd ? ; Флаги
|
||||
root dd ? ; Root handle
|
||||
; После этого идет SHFLSTRING с именем
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Internal Driver Structures
|
||||
; =============================================================================
|
||||
|
||||
struct VBOXGUEST_WAIT
|
||||
Event dd ? ; RTSEMEVENTMULTI handle
|
||||
ListNode_next dd ? ; RTListNode::pNext
|
||||
ListNode_prev dd ? ; RTListNode::pPrev
|
||||
fReqEvents dd ? ; запрашиваемые события
|
||||
fResEvents dd ? ; полученные события
|
||||
pSession dd ? ; сессия
|
||||
pHGCMReq dd ? ; HGCM запрос (если есть)
|
||||
fPendingWakeUp dd ? ; флаг отложенного пробуждения
|
||||
fFreeMe dd ? ; флаг для освобождения
|
||||
ends
|
||||
|
||||
struct VBOXGUEST_SESSION
|
||||
Process dd ? ; RTPROCESS
|
||||
R0Process dd ? ; RTR0PROCESS
|
||||
pDevExt dd ? ; устройство
|
||||
fRequestor dd ? ; VMMDEV_REQUESTOR_*
|
||||
fUserSession dd ? ; bool
|
||||
SessionSpinlock dd ? ; спинлок для синхронизации сессии
|
||||
ListNode_next dd ? ; RTListNode::pNext
|
||||
ListNode_prev dd ? ; RTListNode::pPrev
|
||||
fEventFilter dd ? ; маска фильтра событий
|
||||
fMouseStatus dd ? ; статус мыши
|
||||
fCapabilities dd ? ; возможности
|
||||
fAcquiredGuestCaps dd ? ; приобретенные возможности
|
||||
aHGCMClientIds rd 32 ; HGCM client IDs
|
||||
fPendingCancelWaitEvents dd ? ; bool
|
||||
u32MousePosChangedSeq dd ? ; последовательность изменения позиции мыши
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Memory Ballooning Internal Structures
|
||||
; =============================================================================
|
||||
|
||||
struct VBOXGUEST_MEMBALLOON
|
||||
hMtx dd ? ; мьютекс
|
||||
cChunks dd ? ; текущее количество чанков
|
||||
cMaxChunks dd ? ; максимальное количество чанков
|
||||
fUseKernelAPI dd ? ; использовать ли API ядра
|
||||
paMemObj dd ? ; указатель на массив объектов памяти
|
||||
pOwner dd ? ; владелец (сессия)
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Bit Usage Tracker Structure
|
||||
; =============================================================================
|
||||
struct VBOXGUEST_BITUSAGE_TRACKER
|
||||
acPerBitUsage rd 32 ; счетчики использования битов (0..31)
|
||||
fMask dd ? ; итоговая маска
|
||||
ends
|
||||
|
||||
struct DISPLAY_STATE
|
||||
width dd ?
|
||||
height dd ?
|
||||
bpp dd ?
|
||||
lfb dd ?
|
||||
pitch dd ?
|
||||
refresh_rate dd ?
|
||||
active dd ?
|
||||
pending_change dd ?
|
||||
x dd ?
|
||||
y dd ?
|
||||
ends
|
||||
26
drivers/vboxguest/data/data.inc
Normal file
26
drivers/vboxguest/data/data.inc
Normal file
@@ -0,0 +1,26 @@
|
||||
; =============================================================================
|
||||
; VBoxGuest : Data / VMMDev константы структуры
|
||||
; Назначение: Агрегатор все констант и структур
|
||||
; Файл : data/data.inc
|
||||
; =============================================================================
|
||||
include 'core\constants.inc'
|
||||
include 'core\structs.inc'
|
||||
|
||||
include 'hgcm\constants.inc'
|
||||
include 'hgcm\structs.inc'
|
||||
include 'heartbeat\constants.inc'
|
||||
include 'heartbeat\structs.inc'
|
||||
include 'mouse\constants.inc'
|
||||
include 'mouse\structs.inc'
|
||||
include 'display\constants.inc'
|
||||
include 'display\structs.inc'
|
||||
include 'timesync\constants.inc'
|
||||
include 'timesync\structs.inc'
|
||||
include 'guest_props\constants.inc'
|
||||
include 'guest_props\structs.inc'
|
||||
include 'shared_folders\constants.inc'
|
||||
include 'shared_folders\structs.inc'
|
||||
include 'clipboard\constants.inc'
|
||||
include 'clipboard\structs.inc'
|
||||
include 'seamless\constants.inc'
|
||||
include 'seamless\structs.inc'
|
||||
33
drivers/vboxguest/data/display/constants.inc
Normal file
33
drivers/vboxguest/data/display/constants.inc
Normal file
@@ -0,0 +1,33 @@
|
||||
; =============================================================================
|
||||
; Модуль : Display Service Constants
|
||||
; Файл : data/display/constants.inc
|
||||
; Назначение : Параметры автоизменения разрешения экрана VMMDev Display Change
|
||||
; =============================================================================
|
||||
|
||||
; Display resolution limits
|
||||
DISP_W_MIN equ 640
|
||||
DISP_H_MIN equ 480
|
||||
DISP_W_MAX equ 3840
|
||||
DISP_H_MAX equ 2160
|
||||
|
||||
; BGA (Bochs Graphics Adapter) register ports
|
||||
VBE_DISPI_IOPORT_INDEX equ 0x01CE
|
||||
VBE_DISPI_IOPORT_DATA equ 0x01CF
|
||||
|
||||
; BGA register indices
|
||||
VBE_DISPI_INDEX_XRES equ 0x01
|
||||
VBE_DISPI_INDEX_YRES equ 0x02
|
||||
VBE_DISPI_INDEX_BPP equ 0x03
|
||||
VBE_DISPI_INDEX_ENABLE equ 0x04
|
||||
|
||||
; BGA enable flags
|
||||
VBE_DISPI_DISABLED equ 0x00
|
||||
VBE_DISPI_ENABLED equ 0x01
|
||||
VBE_DISPI_LFB_ENABLED equ 0x40
|
||||
|
||||
; Event mask for display service
|
||||
DISPLAY_EVENT_MASK equ VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
|
||||
|
||||
; Accumulate global masks
|
||||
VBOXGUEST_GUEST_CAPS_OR_MASK equ ( VBOXGUEST_GUEST_CAPS_OR_MASK or VMMDEV_GUEST_SUPPORTS_GRAPHICS )
|
||||
VBOXGUEST_EVENTS_OR_MASK equ ( VBOXGUEST_EVENTS_OR_MASK or DISPLAY_EVENT_MASK )
|
||||
17
drivers/vboxguest/data/display/structs.inc
Normal file
17
drivers/vboxguest/data/display/structs.inc
Normal file
@@ -0,0 +1,17 @@
|
||||
; =============================================================================
|
||||
; Display Service Structures
|
||||
; =============================================================================
|
||||
; VMMDEV_GET_DISPLAY_CHANGE_REQUEST2 and DISPLAY_STATE are defined in
|
||||
; data/core/structs.inc
|
||||
|
||||
|
||||
struct DISPLAY
|
||||
x dd ?
|
||||
y dd ?
|
||||
width dd ?
|
||||
height dd ?
|
||||
bits_per_pixel dd ?
|
||||
vrefresh dd ?
|
||||
pitch dd ?
|
||||
lfb dd ?
|
||||
ends
|
||||
39
drivers/vboxguest/data/guest_props/constants.inc
Normal file
39
drivers/vboxguest/data/guest_props/constants.inc
Normal file
@@ -0,0 +1,39 @@
|
||||
; =============================================================================
|
||||
; Модуль : Guest Properties Constants
|
||||
; Файл : data/guest_props/constants.inc
|
||||
; Назначение : HGCM сервис "VBoxGuestPropSvc" функции и константы
|
||||
; =============================================================================
|
||||
|
||||
; HGCM function numbers (guest side)
|
||||
GUEST_PROP_FN_GET_PROP equ 1 ; Получить свойство
|
||||
GUEST_PROP_FN_SET_PROP equ 2 ; Установить свойство (с флагами)
|
||||
GUEST_PROP_FN_DEL_PROP equ 4 ; ?? 3 ; Удалить свойство
|
||||
GUEST_PROP_FN_SET_PROP_VALUE equ 3 ; ?? 4 ; Установить значение (без флагов)
|
||||
GUEST_PROP_FN_ENUM_PROPS equ 5 ; Перечислить свойства
|
||||
GUEST_PROP_FN_GET_NOTIFICATION equ 6 ; Ожидать уведомления об изменении
|
||||
|
||||
; GUEST_PROP_FN_HOST_SET_PROP_VALUE equ 4 ; недоступно гостю
|
||||
|
||||
; Максимальные размеры
|
||||
GUEST_PROP_MAX_NAME_LEN equ 256
|
||||
GUEST_PROP_MAX_VALUE_LEN equ 1024
|
||||
GUEST_PROP_MAX_FLAGS_LEN equ 128
|
||||
GUEST_PROP_ENUM_BUF_SIZE equ 4096
|
||||
|
||||
; Количество HGCM параметров для разных операций
|
||||
GUEST_PROP_GET_PARM_COUNT equ 4 ; name, value, timestamp, flags
|
||||
GUEST_PROP_SET_PARM_COUNT equ 3 ; name, value, flags
|
||||
GUEST_PROP_SET_VALUE_PARM_COUNT equ 2 ; name, value
|
||||
GUEST_PROP_DEL_PARM_COUNT equ 1 ; name
|
||||
GUEST_PROP_ENUM_PARM_COUNT equ 3 ; patterns, buffer, size
|
||||
|
||||
; Стандартные свойства для установки при инициализации
|
||||
; /VirtualBox/GuestInfo/OS/Product = "KolibriOS"
|
||||
; /VirtualBox/GuestInfo/OS/Release = "1.0"
|
||||
; /VirtualBox/GuestAdd/VersionExt = "1.0.0"
|
||||
; /VirtualBox/GuestAdd/Revision = "1"
|
||||
|
||||
; Маска событий: Guest Properties не используют VMMDev события напрямую
|
||||
GUEST_PROP_EVENT_MASK equ 0
|
||||
; Capabilities: не требует отдельных guest caps
|
||||
GUEST_PROP_CAPS_MASK equ 0
|
||||
16
drivers/vboxguest/data/guest_props/structs.inc
Normal file
16
drivers/vboxguest/data/guest_props/structs.inc
Normal file
@@ -0,0 +1,16 @@
|
||||
; =============================================================================
|
||||
; Guest Properties Structures
|
||||
; =============================================================================
|
||||
|
||||
struct GUEST_PROP_STATE
|
||||
client_id dd ? ; HGCM client ID
|
||||
connected dd ? ; 0/1
|
||||
|
||||
; Динамически выделяемые буферы
|
||||
enum_buf_ptr dd ? ; gp_enum_buf (KernelAlloc 4096)
|
||||
name_buf_ptr dd ? ; gp_name_buf (часть small_bufs)
|
||||
value_buf_ptr dd ? ; gp_value_buf
|
||||
flags_buf_ptr dd ? ; gp_flags_buf
|
||||
parms_ptr dd ? ; gp_parms
|
||||
small_bufs_ptr dd ? ; единый блок (KernelAlloc 4096)
|
||||
ends
|
||||
11
drivers/vboxguest/data/heartbeat/constants.inc
Normal file
11
drivers/vboxguest/data/heartbeat/constants.inc
Normal file
@@ -0,0 +1,11 @@
|
||||
; =============================================================================
|
||||
; Модуль : Heartbeat Service Constants
|
||||
; Файл : data/heartbeat/constants.inc
|
||||
; Назначение : VMMDev heartbeat мониторинг гостя (запросы и события)
|
||||
; =============================================================================
|
||||
|
||||
VMMDEV_REQ_GUEST_HEARTBEAT equ 217 ; VMMDevReq_GuestHeartbeat, Отправка heartbeat
|
||||
VMMDEV_REQ_HEARTBEAT_CONFIGURE equ 218 ; VMMDevReq_HeartbeatConfigure, Настройка heartbeat
|
||||
|
||||
VBOXGUEST_EVENTS_OR_MASK equ ( VBOXGUEST_EVENTS_OR_MASK or VMMDEV_EVENT_GUEST_HEARTBEAT or VMMDEV_EVENT_GUEST_HEARTBEAT_TIMEOUT)
|
||||
VBOXGUEST_GUEST_CAPS_OR_MASK equ ( VBOXGUEST_GUEST_CAPS_OR_MASK or VMMDEV_GUEST_SUPPORTS_GUEST_HEARTBEAT )
|
||||
20
drivers/vboxguest/data/heartbeat/structs.inc
Normal file
20
drivers/vboxguest/data/heartbeat/structs.inc
Normal file
@@ -0,0 +1,20 @@
|
||||
; =============================================================================
|
||||
; Запрос: HeartbeatConfigure (VMMDevReq_HeartbeatConfigure = 60)
|
||||
; Структура VMMDevReqHeartbeat
|
||||
; cNsInterval - /* OUT: интервал в наносекундах */
|
||||
; f_enabled - флаг включения
|
||||
; =============================================================================
|
||||
struct VMMDEV_HEARTBEAT_CONFIGURE
|
||||
header VMMDEV_HEADER
|
||||
c_ns_interval dd ? ; Интервал в наносекундах (младшая часть)
|
||||
c_ns_interval_high dd ? ; Интервал в наносекундах (старшая часть)
|
||||
f_enabled dd ? ; bool(byte) + выравнивание, 1 = включить, 0 = выключить
|
||||
ends ; 24 + 12 байт
|
||||
; AssertCompileSize(VMMDevReqHeartbeat, 24+12);
|
||||
|
||||
; =============================================================================
|
||||
; Запрос: GuestHeartbeat (VMMDevReq_GuestHeartbeat = 61)
|
||||
; =============================================================================
|
||||
struct VMMDEV_GUEST_HEARTBEAT
|
||||
header VMMDEV_HEADER
|
||||
ends ; 24 bytes
|
||||
107
drivers/vboxguest/data/hgcm/constants.inc
Normal file
107
drivers/vboxguest/data/hgcm/constants.inc
Normal file
@@ -0,0 +1,107 @@
|
||||
; =============================================================================
|
||||
; Модуль : HGCM Protocol Constants
|
||||
; Файл : data/hgcm/constants.inc
|
||||
; Назначение : HGCM (Host Guest Communication Manager) протокол константы и параметры
|
||||
; =============================================================================
|
||||
|
||||
|
||||
; =============================================================================
|
||||
; HGCM Protocol Constants
|
||||
; =============================================================================
|
||||
VBOX_HGCM_REQ_DONE equ 0x00000001
|
||||
VBOX_HGCM_REQ_CANCELLED equ 0x00000002
|
||||
|
||||
HGCM_SERVICE_NAME_MAX equ 128
|
||||
HGCM_TIMEOUT_ITERS equ 500000 ; Количество итераций внешнего цикла ожидания
|
||||
HGCM_ASYNC_DELAY_ITERS equ 1000 ; Количество pause инструкций во вложенном цикле
|
||||
|
||||
HGCM_LOC_TYPE_PREDEFINED equ 2
|
||||
|
||||
; =============================================================================
|
||||
; HGCM Parameter Types (VMMDevHGCMParmType)
|
||||
; Источник: include/VBox/VMMDev.h из исходного кода VirtualBox
|
||||
; =============================================================================
|
||||
VMMDEV_HGCM_PARM_TYPE_INVALID equ 0
|
||||
VMMDEV_HGCM_PARM_TYPE_32BIT equ 1
|
||||
HGCM_PARM_TYPE_32BIT equ VMMDEV_HGCM_PARM_TYPE_32BIT
|
||||
VMMDEV_HGCM_PARM_TYPE_64BIT equ 2
|
||||
; VMMDEV_HGCM_PARM_TYPE_PHYSADDR equ 3 ; устарел
|
||||
VMMDEV_HGCM_PARM_TYPE_LINADDR equ 4 ; In and Out
|
||||
HGCM_PARM_TYPE_LINADDR equ VMMDEV_HGCM_PARM_TYPE_LINADDR
|
||||
VMMDEV_HGCM_PARM_TYPE_LINADDR_IN equ 5 ; Host <- Guest
|
||||
HGCM_PARM_TYPE_LINADDR_IN equ VMMDEV_HGCM_PARM_TYPE_LINADDR_IN
|
||||
VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT equ 6 ; Host -> Guest
|
||||
HGCM_PARM_TYPE_LINADDR_OUT equ VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT
|
||||
VMMDEV_HGCM_PARM_TYPE_LINADDR_LOCKED equ 7 ; Для VBoxGuest, а не хоста
|
||||
VMMDEV_HGCM_PARM_TYPE_LINADDR_LOCKED_IN equ 8 ; Для VBoxGuest, а не хоста
|
||||
VMMDEV_HGCM_PARM_TYPE_LINADDR_LOCKED_OUT equ 9 ; Для VBoxGuest, а не хоста
|
||||
VMMDEV_HGCM_PARM_TYPE_PAGELIST equ 10
|
||||
VMMDEV_HGCM_PARM_TYPE_EMBEDDED equ 11
|
||||
VMMDEV_HGCM_PARM_TYPE_CONTIGUOUS_PAGELIST equ 12
|
||||
VMMDEV_HGCM_PARM_TYPE_NO_BOUNCE_PAGELIST equ 13
|
||||
VMMDEV_HGCM_PARM_TYPE_SIZE_HACK equ 0x7fffffff
|
||||
|
||||
; =============================================================================
|
||||
; Флаги для EMBEDDED параметров (Embedded.fFlags)
|
||||
; =============================================================================
|
||||
VMMDEV_HGCM_EMBEDDED_FLAG_IN equ 1 ; Данные от гостя к хосту
|
||||
VMMDEV_HGCM_EMBEDDED_FLAG_OUT equ 2 ; Данные от хоста к гостю
|
||||
VMMDEV_HGCM_EMBEDDED_FLAG_BOTH equ 3 ; (IN | OUT)
|
||||
|
||||
; =============================================================================
|
||||
; Дополнительные константы для проверки возможностей хоста (Host Features)
|
||||
; =============================================================================
|
||||
VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS equ 0x00000002 ; Битовый флаг 1
|
||||
|
||||
; =============================================================================
|
||||
; (Опционально) Для обратной совместимости с вашим текущим кодом
|
||||
; =============================================================================
|
||||
; Короткие алиасы для использования в коде:
|
||||
HGCM_PARM_TYPE_64BIT equ VMMDEV_HGCM_PARM_TYPE_64BIT
|
||||
HGCM_PARM_TYPE_LINADDR_INOUT equ VMMDEV_HGCM_PARM_TYPE_LINADDR ; = 4 (bidirectional)
|
||||
HGCM_PARM_TYPE_EMBEDDED equ VMMDEV_HGCM_PARM_TYPE_EMBEDDED
|
||||
HGCM_EMBED_FLAG_IN equ VMMDEV_HGCM_EMBEDDED_FLAG_IN
|
||||
HGCM_EMBED_FLAG_OUT equ VMMDEV_HGCM_EMBEDDED_FLAG_OUT
|
||||
HGCM_EMBED_FLAG_BOTH equ VMMDEV_HGCM_EMBEDDED_FLAG_BOTH
|
||||
|
||||
; Максимальный размер данных для embedded
|
||||
HGCM_MAX_EMBEDDED_DATA equ 4096
|
||||
|
||||
; Максимальный хвост PageList (для pagelist call buffer)
|
||||
HGCM_MAX_PAGELIST_TAIL equ 8192
|
||||
|
||||
; =============================================================================
|
||||
; Константы PageList
|
||||
; =============================================================================
|
||||
HGCM_PARM_TYPE_PAGELIST equ 10
|
||||
|
||||
; Флаги направления PageList
|
||||
HGCM_PL_FLAG_IN equ 1 ; guest -> host
|
||||
HGCM_PL_FLAG_OUT equ 2 ; host -> guest
|
||||
HGCM_PL_FLAG_BOTH equ 3
|
||||
|
||||
; Размеры страниц
|
||||
PAGE_SIZE equ 4096
|
||||
PAGE_OFFSET_MASK equ 0x0FFF
|
||||
PAGE_BASE_MASK equ 0xFFFFF000
|
||||
|
||||
; Смещения внутри HGCMPageListInfo
|
||||
HGCM_PLI_FLAGS equ 0 ; dd flags
|
||||
HGCM_PLI_OFF_FIRST_PAGE equ 4 ; dw offFirstPage
|
||||
HGCM_PLI_CPAGES equ 6 ; dw cPages
|
||||
HGCM_PLI_APAGES equ 8 ; начало массива dq[] aPages
|
||||
|
||||
; =============================================================================
|
||||
; Макрос FILL_HGCM_HEADER - Заполнить стандартный заголовок HGCM пакета
|
||||
; Параметры:
|
||||
; reg - регистр с указателем на структуру HGCM_HEADER
|
||||
; size - размер пакета в байтах
|
||||
; =============================================================================
|
||||
macro FILL_HGCM_HEADER reg, size {
|
||||
mov dword [reg + HGCM_HEADER.header.size], size
|
||||
mov dword [reg + HGCM_HEADER.header.version], VMMDEV_REQUEST_HEADER_VERSION
|
||||
mov dword [reg + HGCM_HEADER.header.request_type], VMMDEV_REQ_HGCM_CALL32
|
||||
mov dword [reg + HGCM_HEADER.header.rc], VERR_GENERAL_FAILURE
|
||||
mov dword [reg + HGCM_HEADER.header.reserved1], 0
|
||||
mov dword [reg + HGCM_HEADER.header.requestor], VMMDEV_REQUESTOR_KERNEL
|
||||
}
|
||||
70
drivers/vboxguest/data/hgcm/structs.inc
Normal file
70
drivers/vboxguest/data/hgcm/structs.inc
Normal file
@@ -0,0 +1,70 @@
|
||||
; =============================================================================
|
||||
; VBoxGuest Driver for KolibriOS - Structures HGCM
|
||||
; =============================================================================
|
||||
|
||||
; =============================================================================
|
||||
; HGCM Structures
|
||||
; =============================================================================
|
||||
|
||||
struct HGCM_HEADER
|
||||
header VMMDEV_HEADER
|
||||
flags dd ?
|
||||
result dd ?
|
||||
ends ; 32 байта
|
||||
|
||||
struct HGCM_CONNECT
|
||||
header HGCM_HEADER
|
||||
location_type dd ?
|
||||
service_name rb HGCM_SERVICE_NAME_MAX ; имя сервиса
|
||||
client_id dd ?
|
||||
ends
|
||||
|
||||
struct HGCM_DISCONNECT
|
||||
header HGCM_HEADER
|
||||
client_id dd ?
|
||||
ends
|
||||
|
||||
struct HGCM_CALL
|
||||
header HGCM_HEADER ; 32
|
||||
client_id dd ? ; +4 = 36 // ID клиента
|
||||
function dd ? ; +4 = 40 // Номер функции (1=MSG_OLD_GET_WAIT и т.д.)
|
||||
param_count dd ? ; +4 = 44 // Количество параметров
|
||||
; params[0] начинаются с offset 44
|
||||
; Далее идут параметры: struct vmmdev_hgcm_function_parameter params[parm_count];
|
||||
ends
|
||||
|
||||
struct HGCM_PARM
|
||||
type dd ? ; тип параметра (VMMDevHGCMParmType)
|
||||
u rb 8 ; union { uint32_t value32; RTGCPTR pointer; }
|
||||
ends
|
||||
|
||||
HGCM_PARM.u.value32 equ HGCM_PARM.u
|
||||
HGCM_PARM.u.value_or_size equ HGCM_PARM.u
|
||||
|
||||
HGCM_PARM.u.value64_lo equ HGCM_PARM.u
|
||||
HGCM_PARM.u.value64_hi equ HGCM_PARM.u+4
|
||||
|
||||
HGCM_PARM.u.LinAddr.size equ HGCM_PARM.u
|
||||
HGCM_PARM.u.LinAddr.offset equ HGCM_PARM.u+4
|
||||
|
||||
HGCM_PARM.value_or_size equ HGCM_PARM.u
|
||||
HGCM_PARM.offset_or_addr equ HGCM_PARM.u+4
|
||||
|
||||
|
||||
|
||||
; sizeof(vmmdev_request_header) = 24
|
||||
; sizeof(vmmdev_hgcmreq_header) = 32 // header(24) + flags(4) + result(4)
|
||||
; sizeof(vmmdev_hgcm_call) = 44 // header(32) + client_id(4) + function(4) + parm_count(4)
|
||||
; sizeof(vmmdev_hgcm_function_parameter) = 12
|
||||
; sizeof(vmmdev_hgcm_pagelist) = 16 + (cPages * 8)
|
||||
|
||||
; struct vmmdev_hgcm_pagelist {
|
||||
; u32 flags; // Direction flags (1,2,3)
|
||||
; u16 offFirstPage; // Смещение в первой странице
|
||||
; u16 cPages; // Количество страниц
|
||||
; u64 pages[1]; // Массив физических адресов страниц (RTGCPHYS64)
|
||||
; };
|
||||
|
||||
; Размер буфера для PageList HGCM вызовов
|
||||
; = sizeof.HGCM_CALL(44) + 32*sizeof.HGCM_PARM(12) + 8192 = 8620 → 3 страницы
|
||||
HGCM_PL_BUF_SIZE equ sizeof.HGCM_CALL + (VMMDEV_MAX_HGCM_PARMS * sizeof.HGCM_PARM) + HGCM_MAX_PAGELIST_TAIL
|
||||
40
drivers/vboxguest/data/mouse/constants.inc
Normal file
40
drivers/vboxguest/data/mouse/constants.inc
Normal file
@@ -0,0 +1,40 @@
|
||||
; =============================================================================
|
||||
; Модуль : Mouse Service Constants
|
||||
; Файл : data/mouse/constants.inc
|
||||
; Назначение : VMMDev запросы мыши (абсолютные координаты, кнопки, скролл)
|
||||
; =============================================================================
|
||||
VMMDEV_REQ_GET_MOUSE_STATUS equ 1
|
||||
VMMDEV_REQ_SET_MOUSE_STATUS equ 2
|
||||
VMMDEV_REQ_SET_POINTER_SHAPE equ 3
|
||||
VMMDEV_REQ_GET_MOUSE_STATUS_EX equ 223 ; Extended: + buttons, scroll
|
||||
|
||||
; VMMDEV_REQ_GET_POINTER_SHAPE equ 58
|
||||
|
||||
; Новые (v1_04):
|
||||
VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE equ 0x00000001
|
||||
VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR equ 0x00000002
|
||||
VMMDEV_MOUSE_GUEST_HAS_ABSOLUTE equ 0x00000004
|
||||
VMMDEV_MOUSE_NEW_PROTOCOL equ 0x00000010
|
||||
VMMDEV_MOUSE_NOTIFY_GUEST equ 0x00000080
|
||||
VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE equ 0x00000100
|
||||
VMMDEV_MOUSE_HOST_HAS_ABSOLUTE equ 0x00000200
|
||||
VMMDEV_MOUSE_HOST_NEW_PROTOCOL equ 0x00000400
|
||||
|
||||
; Full state protocol (VBox 6.1+): кнопки + скролл в одном запросе
|
||||
VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL equ 0x00000080
|
||||
VMMDEV_MOUSE_HOST_SUPPORTS_FULL_STATE_PROTOCOL equ 0x00000100
|
||||
|
||||
; Mouse button masks
|
||||
VMMDEV_MOUSE_BUTTON_LEFT equ 0x01
|
||||
VMMDEV_MOUSE_BUTTON_RIGHT equ 0x02
|
||||
VMMDEV_MOUSE_BUTTON_MIDDLE equ 0x04
|
||||
VMMDEV_MOUSE_BUTTON_X1 equ 0x08
|
||||
VMMDEV_MOUSE_BUTTON_X2 equ 0x10
|
||||
|
||||
VBOX_MOUSE_GUEST_FEATURES equ VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE
|
||||
VBOX_MOUSE_GUEST_FEATURES_EXT equ (VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE or VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL)
|
||||
|
||||
MOUSE_EVENT_MASK equ ( VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED or VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
|
||||
|
||||
VBOXGUEST_GUEST_CAPS_OR_MASK equ ( VBOXGUEST_GUEST_CAPS_OR_MASK or VMMDEV_GUEST_SUPPORTS_MOUSE )
|
||||
VBOXGUEST_EVENTS_OR_MASK equ ( VBOXGUEST_EVENTS_OR_MASK or MOUSE_EVENT_MASK )
|
||||
43
drivers/vboxguest/data/mouse/structs.inc
Normal file
43
drivers/vboxguest/data/mouse/structs.inc
Normal file
@@ -0,0 +1,43 @@
|
||||
; =============================================================================
|
||||
; Запрос: GetMouseStatus (VMMDevReq_GetMouseStatus = 1)
|
||||
; Запрос: SetMouseStatus (VMMDevReq_SetMouseStatus = 2)
|
||||
; =============================================================================
|
||||
struct VMMDEV_REQ_MOUSE_STATUS
|
||||
header VMMDEV_HEADER
|
||||
mouse_features dd ? ; VMMDEV_MOUSE_* features
|
||||
pointer_x_pos dd ? ; X position
|
||||
pointer_y_pos dd ? ; Y position
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Mouse pointer shape (для изменения курсора)
|
||||
; =============================================================================
|
||||
struct VMMDEV_REQ_POINTER_SHAPE
|
||||
header VMMDEV_HEADER
|
||||
flags dd ? ; VMMDEV_POINTER_* flags
|
||||
x_hot dd ? ; X hotspot
|
||||
y_hot dd ? ; Y hotspot
|
||||
width dd ? ; Width in pixels
|
||||
height dd ? ; Height in pixels
|
||||
; За которыми следуют данные маски
|
||||
ends
|
||||
; =============================================================================
|
||||
; Extended mouse status (VMMDevReq_GetMouseStatusEx = 223)
|
||||
; Включает кнопки и скролл. Требует VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL.
|
||||
; =============================================================================
|
||||
struct VMMDEV_REQ_MOUSE_STATUS_EX
|
||||
core VMMDEV_REQ_MOUSE_STATUS
|
||||
scroll_dz dd ? ; vertical scroll delta
|
||||
scroll_dw dd ? ; horizontal scroll delta
|
||||
buttons dd ? ; VMMDEV_MOUSE_BUTTON_* mask
|
||||
ends
|
||||
|
||||
;struct VMMDEV_REQ_MOUSE_POINTER
|
||||
; header VMMDEV_HEADER
|
||||
; f_flags dd ?
|
||||
; x_hot dd ?
|
||||
; y_hot dd ?
|
||||
; width dd ?
|
||||
; height dd ?
|
||||
; data rb 0 ; AND-mask + XOR-mask (variable)
|
||||
;ends
|
||||
26
drivers/vboxguest/data/seamless/constants.inc
Normal file
26
drivers/vboxguest/data/seamless/constants.inc
Normal file
@@ -0,0 +1,26 @@
|
||||
; =============================================================================
|
||||
; Seamless Constants — VBox 7.2.6
|
||||
; Источник: include/VBox/VMMDevCoreTypes.h, include/VBox/VMMDev.h
|
||||
; =============================================================================
|
||||
|
||||
; VMMDevReq_GetSeamlessChangeRequest
|
||||
VMMDEV_REQ_GET_SEAMLESS_CHANGE equ 73
|
||||
|
||||
; VMMDevSeamlessMode enum
|
||||
VMMDEV_SEAMLESS_DISABLED equ 0 ; Обычный режим, весь десктоп
|
||||
VMMDEV_SEAMLESS_VISIBLE_REGION equ 1 ; Только top-level окна
|
||||
VMMDEV_SEAMLESS_HOST_WINDOW equ 2 ; Каждое окно гостя = окно хоста
|
||||
|
||||
; VMMDevReq_VideoSetVisibleRegion
|
||||
VMMDEV_REQ_VIDEO_SET_VISIBLE_REGION equ 72
|
||||
|
||||
; Event: хост просит переключить seamless mode
|
||||
; VMMDEV_EVENT_SEAMLESS_MODE_CHANGE = 0x00000020 (bit 5) — уже в core/constants.inc
|
||||
|
||||
SEAMLESS_EVENT_MASK equ VMMDEV_EVENT_SEAMLESS_MODE_CHANGE
|
||||
|
||||
; Caps: гость поддерживает seamless
|
||||
; VMMDEV_GUEST_SUPPORTS_SEAMLESS = 0x00000001 — уже в core/constants.inc
|
||||
|
||||
; Накопительная маска
|
||||
VBOXGUEST_EVENTS_OR_MASK equ ( VBOXGUEST_EVENTS_OR_MASK or SEAMLESS_EVENT_MASK )
|
||||
29
drivers/vboxguest/data/seamless/structs.inc
Normal file
29
drivers/vboxguest/data/seamless/structs.inc
Normal file
@@ -0,0 +1,29 @@
|
||||
; =============================================================================
|
||||
; Seamless Structures — VBox 7.2.6
|
||||
; Источник: include/VBox/VMMDev.h
|
||||
; =============================================================================
|
||||
|
||||
; VMMDevSeamlessChangeRequest (VMMDevReq_GetSeamlessChangeRequest = 73)
|
||||
; size = 24 (header) + 8 = 32
|
||||
struct VMMDEV_SEAMLESS_CHANGE_REQUEST
|
||||
header VMMDEV_HEADER
|
||||
mode dd ? ; OUT: VMMDevSeamlessMode (0=disabled, 1=visible, 2=host_window)
|
||||
eventAck dd ? ; IN: VMMDEV_EVENT_SEAMLESS_MODE_CHANGE для ACK
|
||||
ends
|
||||
|
||||
; RTRECT — прямоугольник (для VideoSetVisibleRegion)
|
||||
struct RTRECT
|
||||
xLeft dd ?
|
||||
yTop dd ?
|
||||
xRight dd ?
|
||||
yBottom dd ?
|
||||
ends
|
||||
|
||||
; VMMDevVideoSetVisibleRegion (VMMDevReq_VideoSetVisibleRegion = 72)
|
||||
; Переменная длина: header(24) + cRect(4) + Rect[cRect] (16 каждый)
|
||||
; Для KolibriOS — один прямоугольник (весь экран)
|
||||
struct VMMDEV_VIDEO_SET_VISIBLE_REGION
|
||||
header VMMDEV_HEADER
|
||||
cRect dd ? ; Количество прямоугольников
|
||||
rect0 RTRECT ; Первый (и единственный) прямоугольник
|
||||
ends
|
||||
113
drivers/vboxguest/data/shared_folders/constants.inc
Normal file
113
drivers/vboxguest/data/shared_folders/constants.inc
Normal file
@@ -0,0 +1,113 @@
|
||||
; =============================================================================
|
||||
; SharedFolder Constants (VirtualBox HGCM)
|
||||
; =============================================================================
|
||||
|
||||
; =========================================
|
||||
; Функции службы Shared Folders (SHFL_FN_*)
|
||||
; =========================================
|
||||
SHFL_FN_QUERY_MAPPINGS equ 1 ; Запросить список подключенных папок
|
||||
SHFL_FN_QUERY_MAP_NAME equ 2 ; Запросить имя подключения по индексу
|
||||
SHFL_FN_CREATE equ 3 ; Создать файл/каталог
|
||||
SHFL_FN_CLOSE equ 4 ; Закрыть дескриптор
|
||||
SHFL_FN_READ equ 5 ; Чтение из файла
|
||||
SHFL_FN_WRITE equ 6 ; Запись в файл
|
||||
SHFL_FN_LOCK equ 7 ; Блокировка файла
|
||||
SHFL_FN_LIST equ 8 ; Получить содержимое каталога
|
||||
SHFL_FN_INFORMATION equ 9 ; Получить/установить информацию о файле
|
||||
SHFL_FN_UNUSED_10 equ 10 ; (Зарезервировано)
|
||||
SHFL_FN_REMOVE equ 11 ; Удалить файл/каталог
|
||||
SHFL_FN_MAP_FOLDER_OLD equ 12 ; Устаревшее подключение папки (не использовать)
|
||||
SHFL_FN_UNMAP_FOLDER equ 13 ; Отключить папку
|
||||
SHFL_FN_RENAME equ 14 ; Переименовать/переместить
|
||||
SHFL_FN_FLUSH equ 15 ; Сбросить кэш файла на диск
|
||||
SHFL_FN_SET_UTF8 equ 16 ; Включить режим UTF-8 (0 параметров)
|
||||
SHFL_FN_MAP_FOLDER equ 17 ; Подключить папку
|
||||
SHFL_FN_READLINK equ 18 ; Прочитать символьную ссылку
|
||||
SHFL_FN_SYMLINK equ 19 ; Создать символьную ссылку
|
||||
SHFL_FN_SET_SYMLINKS equ 20 ; Разрешить/запретить симлинки (0 параметров)
|
||||
SHFL_FN_SET_FILE_SIZE equ 24 ; Установить размер файла (усечь/расширить)
|
||||
|
||||
; Флаги для SHFL_FN_REMOVE
|
||||
SHFL_REMOVE_FILE equ 0x01 ; Удалить файл
|
||||
SHFL_REMOVE_DIR equ 0x02 ; Удалить каталог
|
||||
SHFL_REMOVE_SYMLINK equ 0x04 ; Удалить символьную ссылку
|
||||
|
||||
; Флаги для SHFL_FN_RENAME
|
||||
SHFL_RENAME_FILE equ 0x01 ; Переименовать файл
|
||||
SHFL_RENAME_DIR equ 0x02 ; Переименовать каталог
|
||||
SHFL_RENAME_REPLACE_IF_EXISTS equ 0x04 ; Заменить если существует
|
||||
|
||||
; Флаги для операции LIST (используются в SHFL_LIST_PARMS.Flags)
|
||||
; ==============================================================
|
||||
SHFL_LIST_NONE equ 0x00000000 ; Базовый листинг
|
||||
SHFL_LIST_RETURN_ONE equ 0x00000001 ; Вернуть только первую запись
|
||||
SHFL_LIST_RESTART equ 0x00000002 ; Начать перебор заново
|
||||
SHFL_LIST_SIZE_RETURNED equ 0x00000004 ; В SizeReturned реальный размер данных
|
||||
|
||||
; Лимиты
|
||||
; ======
|
||||
SHFL_MAX_MAPPINGS equ 10 ; Максимальное число подключенных папок
|
||||
SHFL_MAX_NAME_LEN equ 256 ; Макс. длина имени в символах
|
||||
SHFL_MAX_PATH_LEN equ 4096 ; Макс. длина пути в байтах (включая UTF-8)
|
||||
|
||||
; Флаги создания/открытия файлов - SHFL_CF_*
|
||||
; ======================================================================
|
||||
; SHFL_CF_* — CreateFlags для SHFL_FN_CREATE (из shflsvc.h)
|
||||
; ======================================================================
|
||||
SHFL_CF_NONE equ 0x00000000
|
||||
|
||||
; Бит 0: Lookup only
|
||||
SHFL_CF_LOOKUP equ 0x00000001
|
||||
|
||||
; Бит 1: Open target directory
|
||||
SHFL_CF_OPEN_TARGET_DIRECTORY equ 0x00000002
|
||||
|
||||
; Бит 2: Object is a directory
|
||||
SHFL_CF_DIRECTORY equ 0x00000004
|
||||
|
||||
; Биты 4..7: Action if file EXISTS
|
||||
SHFL_CF_ACT_MASK_IF_EXISTS equ 0x000000F0
|
||||
SHFL_CF_ACT_OPEN_IF_EXISTS equ 0x00000000 ; Open existing
|
||||
SHFL_CF_ACT_FAIL_IF_EXISTS equ 0x00000010 ; Fail if exists
|
||||
SHFL_CF_ACT_REPLACE_IF_EXISTS equ 0x00000020 ; Replace (truncate)
|
||||
SHFL_CF_ACT_OVERWRITE_IF_EXISTS equ 0x00000030 ; Overwrite
|
||||
|
||||
; Биты 8..11: Action if file is NEW
|
||||
SHFL_CF_ACT_MASK_IF_NEW equ 0x00000F00
|
||||
SHFL_CF_ACT_CREATE_IF_NEW equ 0x00000000 ; Create new file
|
||||
SHFL_CF_ACT_FAIL_IF_NEW equ 0x00000100 ; Fail if doesn't exist
|
||||
|
||||
; Биты 12..13: Access mode (read/write)
|
||||
SHFL_CF_ACCESS_MASK_RW equ 0x00003000
|
||||
SHFL_CF_ACCESS_NONE equ 0x00000000
|
||||
SHFL_CF_ACCESS_READ equ 0x00001000
|
||||
SHFL_CF_ACCESS_WRITE equ 0x00002000
|
||||
SHFL_CF_ACCESS_READWRITE equ 0x00003000
|
||||
|
||||
; Биты 14..15: Deny mode (sharing)
|
||||
SHFL_CF_ACCESS_MASK_DENY equ 0x0000C000
|
||||
SHFL_CF_ACCESS_DENYNONE equ 0x00000000
|
||||
SHFL_CF_ACCESS_DENYREAD equ 0x00004000
|
||||
SHFL_CF_ACCESS_DENYWRITE equ 0x00008000
|
||||
SHFL_CF_ACCESS_DENYALL equ 0x0000C000
|
||||
|
||||
; Биты 16..17: Attribute access
|
||||
SHFL_CF_ACCESS_MASK_ATTR equ 0x00030000
|
||||
SHFL_CF_ACCESS_ATTR_NONE equ 0x00000000
|
||||
SHFL_CF_ACCESS_ATTR_READ equ 0x00010000
|
||||
SHFL_CF_ACCESS_ATTR_WRITE equ 0x00020000
|
||||
SHFL_CF_ACCESS_ATTR_READWRITE equ 0x00030000
|
||||
|
||||
; Бит 18: Append mode
|
||||
SHFL_CF_ACCESS_APPEND equ 0x00040000
|
||||
|
||||
; ======================================================================
|
||||
; SHFLCREATERESULT — результат CREATE
|
||||
; ======================================================================
|
||||
SHFL_NO_RESULT equ 0
|
||||
SHFL_PATH_NOT_FOUND equ 1
|
||||
SHFL_FILE_NOT_FOUND equ 2
|
||||
SHFL_FILE_EXISTS equ 3
|
||||
SHFL_FILE_CREATED equ 4
|
||||
SHFL_FILE_REPLACED equ 5
|
||||
|
||||
304
drivers/vboxguest/data/shared_folders/structs.inc
Normal file
304
drivers/vboxguest/data/shared_folders/structs.inc
Normal file
@@ -0,0 +1,304 @@
|
||||
; =============================================================================
|
||||
; VirtualBox SharedFolder Structures
|
||||
; =============================================================================
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Глобальное состояние SharedFolder драйвера
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SF_STATE
|
||||
connected dd ? ; 1 = HGCM подключен к сервису
|
||||
client_id dd ? ; HGCM client ID
|
||||
|
||||
; Динамически выделяемые init-буферы
|
||||
packet_ptr dd ? ; sf_packet (KernelAlloc 4096)
|
||||
mappings_ptr dd ? ; sf_mappings (часть small_bufs)
|
||||
namebuf_ptr dd ? ; sf_namebuf
|
||||
cp866_buf_ptr dd ? ; sf_cp866_buf
|
||||
listbuf_ptr dd ? ; sf_listbuf (KernelAlloc 4096)
|
||||
createparms_ptr dd ? ; sf_createparms
|
||||
dir_path_ptr dd ? ; sf_dir_path
|
||||
small_bufs_ptr dd ? ; единый блок мелких буферов (KernelAlloc 4096)
|
||||
|
||||
; Динамически выделяемые FS-буферы
|
||||
fs_packet_ptr dd ? ; vboxsf_fs_packet (KernelAlloc 4096)
|
||||
fs_listbuf_ptr dd ? ; vboxsf_fs_listbuf (KernelAlloc 4096)
|
||||
fs_iobuf_ptr dd ? ; vboxsf_fs_iobuf (KernelAlloc 65536)
|
||||
fs_cparms_ptr dd ? ; vboxsf_fs_cparms (KernelAlloc 4096)
|
||||
fs_pathbuf_ptr dd ? ; vboxsf_fs_pathbuf
|
||||
fs_pathbuf2_ptr dd ? ; vboxsf_fs_pathbuf2
|
||||
fs_tmpname_ptr dd ? ; vboxsf_fs_tmpname
|
||||
fs_small_bufs_ptr dd ? ; единый блок мелких FS-буферов (KernelAlloc 4096)
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Информация об одной shared folder (выделяется через KernelAlloc)
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SF_FOLDER
|
||||
root_handle dd ? ; SHFL root handle (от MAP_FOLDER)
|
||||
active dd ? ; 1 = folder активен и подключен
|
||||
name rb 256 ; Имя mapping (UTF-8, null-terminated)
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Данные для виртуального диска /vbox/
|
||||
; -----------------------------------------------------------------------------
|
||||
struct VBOXSF_DISK
|
||||
folders rd SHFL_MAX_FOLDERS ; Указатели на SF_FOLDER
|
||||
count dd ? ; Количество папок
|
||||
disk_handle dd ? ; Handle от DiskAdd
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Структура DISKMEDIAINFO для querymedia callback
|
||||
; =============================================================================
|
||||
struct DISKMEDIAINFO
|
||||
flags dd ? ; флаги медиа
|
||||
sectorsize dd ? ; размер сектора
|
||||
capacity dq ? ; емкость в секторах (64-bit)
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; Смещения внутренних структур ядра KolibriOS
|
||||
; (нужны для create_partition callback)
|
||||
; =============================================================================
|
||||
KPARTITION_OFS_DISK = 16 ; PARTITION.Disk -> DISK*
|
||||
KPARTITION_OFS_FSUSERFUNCTIONS = 20 ; PARTITION.FSUserFunctions -> UserFuncs*
|
||||
KDISK_OFS_USERDATA = 16 ; DISK.UserData -> void*
|
||||
|
||||
; =============================================================================
|
||||
; BDFE (Block Data File Entry) — формат записи в директории KolibriOS
|
||||
; =============================================================================
|
||||
BDFE_SIZE = 304 ; Размер одной BDFE записи (CP866)
|
||||
BDFE_HEADER_SIZE = 32 ; Размер заголовка ответа ReadFolder
|
||||
|
||||
; Структура заголовка ReadFolder ответа
|
||||
struct BDFE_HEADER
|
||||
version dd ? ; Версия формата (1)
|
||||
entries_placed dd ? ; Количество возвращенных записей
|
||||
total_entries dd ? ; Общее количество записей
|
||||
reserved rd 5 ; Зарезервировано (20 байт)
|
||||
ends
|
||||
|
||||
; Смещения полей BDFE
|
||||
BDFE_OFS_ATTR = 0 ; dword: атрибуты
|
||||
BDFE_OFS_ENCODING = 4 ; byte: кодировка (0=CP866, 1=UTF-16, 2=UTF-8)
|
||||
BDFE_OFS_CTIME = 8 ; dword: время создания
|
||||
BDFE_OFS_CDATE = 12 ; dword: дата создания
|
||||
BDFE_OFS_ATIME = 16 ; dword: время доступа
|
||||
BDFE_OFS_ADATE = 20 ; dword: дата доступа
|
||||
BDFE_OFS_MTIME = 24 ; dword: время модификации
|
||||
BDFE_OFS_MDATE = 28 ; dword: дата модификации
|
||||
BDFE_OFS_SIZE_LO = 32 ; dword: размер файла (младшие 32 бита)
|
||||
BDFE_OFS_SIZE_HI = 36 ; dword: размер файла (старшие 32 бита)
|
||||
BDFE_OFS_NAME = 40 ; 264 байта: имя файла (null-terminated)
|
||||
|
||||
; Атрибуты файлов
|
||||
FA_READONLY = 0x01
|
||||
FA_HIDDEN = 0x02
|
||||
FA_SYSTEM = 0x04
|
||||
FA_LABEL = 0x08
|
||||
FA_FOLDER = 0x10
|
||||
FA_ARCHIVED = 0x20
|
||||
|
||||
; Коды ошибок KolibriOS (syscall 70)
|
||||
ERROR_SUCCESS = 0
|
||||
ERROR_DISK_FULL = 1
|
||||
ERROR_UNSUPPORTED = 2
|
||||
ERROR_UNKNOWN_FS = 3
|
||||
ERROR_FILE_NOT_FOUND = 5
|
||||
ERROR_END_OF_FILE = 6
|
||||
ERROR_MEMORY = 7
|
||||
ERROR_ACCESS_DENIED = 10
|
||||
ERROR_DEVICE = 11
|
||||
|
||||
; =============================================================================
|
||||
; Смещения внутри SHFLFSOBJINFO (92 байта)
|
||||
; Используются для конвертации в BDFE при ReadFolder/GetFileInfo
|
||||
; =============================================================================
|
||||
SHFLOBJINFO_OFS_SIZE_LO = 0 ; int64 cbObject (low)
|
||||
SHFLOBJINFO_OFS_SIZE_HI = 4 ; int64 cbObject (high)
|
||||
SHFLOBJINFO_OFS_ALLOC_LO = 8 ; int64 cbAllocated (low)
|
||||
SHFLOBJINFO_OFS_ALLOC_HI = 12 ; int64 cbAllocated (high)
|
||||
SHFLOBJINFO_OFS_BTIME_LO = 16 ; int64 BirthTime (low, nanosec)
|
||||
SHFLOBJINFO_OFS_BTIME_HI = 20 ; int64 BirthTime (high)
|
||||
SHFLOBJINFO_OFS_CTIME_LO = 24 ; int64 ChangeTime (low)
|
||||
SHFLOBJINFO_OFS_CTIME_HI = 28 ; int64 ChangeTime (high)
|
||||
SHFLOBJINFO_OFS_MTIME_LO = 32 ; int64 ModificationTime (low)
|
||||
SHFLOBJINFO_OFS_MTIME_HI = 36 ; int64 ModificationTime (high)
|
||||
SHFLOBJINFO_OFS_ATIME_LO = 40 ; int64 AccessTime (low)
|
||||
SHFLOBJINFO_OFS_ATIME_HI = 44 ; int64 AccessTime (high)
|
||||
SHFLOBJINFO_OFS_FMODE = 48 ; uint32 Attr (RTFMODE)
|
||||
|
||||
; Биты fMode (RTFMODE)
|
||||
S_IFDIR = 0x4000
|
||||
S_IFREG = 0x8000
|
||||
|
||||
; =============================================================================
|
||||
; HGCM пакеты для SharedFolder операций
|
||||
; =============================================================================
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_QUERY_MAPPINGS - Получить список доступных mappings
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_QUERY_MAPPINGS
|
||||
header HGCM_CALL
|
||||
flags HGCM_PARM ; IN: флаги (обычно 0)
|
||||
count HGCM_PARM ; OUT: количество mappings
|
||||
buffer HGCM_PARM ; OUT: буфер для данных (SHFLMAPPING[])
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_QUERY_MAP_NAME - Получить имя mapping по индексу
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_QUERY_MAP_NAME
|
||||
header HGCM_CALL
|
||||
index HGCM_PARM ; IN: индекс mapping (0..count-1)
|
||||
name HGCM_PARM ; OUT: имя mapping (SHFLSTRING)
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_MAP_FOLDER - Подключить mapping
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_MAP_FOLDER
|
||||
header HGCM_CALL
|
||||
path HGCM_PARM ; IN
|
||||
root HGCM_PARM ; OUT
|
||||
delimiter HGCM_PARM ; IN
|
||||
flags HGCM_PARM ; IN
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_UNMAP_FOLDER - Отключить mapping
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_UNMAP_FOLDER
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; IN: root handle
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_CREATE - Открыть/создать файл
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_CREATE
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; IN: root handle
|
||||
path HGCM_PARM ; IN: путь к файлу (SHFLSTRING)
|
||||
parms HGCM_PARM ; IN/OUT: параметры (SHFLCREATEPARMS)
|
||||
ends
|
||||
|
||||
; Параметры создания файла (108 байт)
|
||||
struct SHFLCREATEPARMS
|
||||
handle_lo dd ? ; +0: OUT: SHFLHANDLE low (uint64_t)
|
||||
handle_hi dd ? ; +4: OUT: SHFLHANDLE high
|
||||
result dd ? ; +8: OUT: SHFLCREATERESULT
|
||||
flags dd ? ; +12: IN: SHFL_CF_* CreateFlags
|
||||
info rb 92 ; +16: IN/OUT: SHFLFSOBJINFO
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFLDIRINFO - одна запись в результате SHFL_FN_LIST (переменный размер)
|
||||
; Фиксированная часть = 126 байт:
|
||||
; SHFLFSOBJINFO (92) + cucShortName (2) + uszShortName (28) + SHFLSTRING hdr (4)
|
||||
; За ней идут байты имени файла (переменная длина).
|
||||
; -----------------------------------------------------------------------------
|
||||
SHFLDIRINFO_FIXED_SIZE = 126
|
||||
|
||||
SHFLDIRINFO_OFS_INFO = 0 ; SHFLFSOBJINFO (92 bytes)
|
||||
SHFLDIRINFO_OFS_SIZE_LO = 0 ; cbObject low
|
||||
SHFLDIRINFO_OFS_SIZE_HI = 4 ; cbObject high
|
||||
SHFLDIRINFO_OFS_FMODE = 48 ; fMode (RTFMODE)
|
||||
SHFLDIRINFO_OFS_CUC_SHORT_NAME = 92 ; cucShortName (uint16)
|
||||
SHFLDIRINFO_OFS_USZ_SHORT_NAME = 94 ; uszShortName (14 x uint16 = 28 bytes)
|
||||
SHFLDIRINFO_OFS_NAME_SIZE = 122 ; SHFLSTRING.u16Size
|
||||
SHFLDIRINFO_OFS_NAME_LENGTH = 124 ; SHFLSTRING.u16Length
|
||||
SHFLDIRINFO_OFS_NAME_STRING = 126 ; SHFLSTRING.string (данные имени)
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_CLOSE - Закрыть файл
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_CLOSE
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; IN: root handle
|
||||
handle HGCM_PARM ; IN: file handle
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_READ - Читать из файла
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_READ
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; IN: root handle
|
||||
handle HGCM_PARM ; IN: file handle
|
||||
offset_low HGCM_PARM ; IN: offset low (64-bit)
|
||||
offset_high HGCM_PARM ; IN: offset high (64-bit)
|
||||
size HGCM_PARM ; IN/OUT: размер для чтения
|
||||
buffer HGCM_PARM ; OUT: буфер для данных
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_WRITE - Писать в файл
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_WRITE
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; IN: root handle
|
||||
handle HGCM_PARM ; IN: file handle
|
||||
offset_low HGCM_PARM ; IN: offset low (64-bit)
|
||||
offset_high HGCM_PARM ; IN: offset high (64-bit)
|
||||
size HGCM_PARM ; IN/OUT: размер для записи
|
||||
buffer HGCM_PARM ; IN: буфер с данными
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_LIST - Получить список файлов в директории
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_LIST
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; parm[0] IN: root handle (32bit)
|
||||
handle HGCM_PARM ; parm[1] IN: dir handle (64bit!)
|
||||
flags HGCM_PARM ; parm[2] IN: SHFL_LIST_* (32bit)
|
||||
cb HGCM_PARM ; parm[3] IN/OUT: размер буфера (32bit)
|
||||
path HGCM_PARM ; parm[4] IN: search pattern (опционально)
|
||||
buffer HGCM_PARM ; parm[5] OUT: SHFLDIRINFO[]
|
||||
resume_pt HGCM_PARM ; parm[6] IN/OUT: точка продолжения (32bit)
|
||||
file_count HGCM_PARM ; parm[7] OUT: количество файлов (32bit)
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_INFORMATION - Получить информацию о файле
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_INFORMATION
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; IN: root handle
|
||||
handle HGCM_PARM ; IN: file handle
|
||||
flags HGCM_PARM ; IN: флаги
|
||||
info HGCM_PARM ; OUT: информация (SHFLFSOBJINFO)
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_REMOVE - Удалить файл
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_REMOVE
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; IN: root handle
|
||||
path HGCM_PARM ; IN: путь к файлу (SHFLSTRING)
|
||||
flags HGCM_PARM ; IN: флаги
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_RENAME - Переименовать файл
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_RENAME
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; IN: root handle
|
||||
src HGCM_PARM ; IN: исходный путь (SHFLSTRING)
|
||||
dst HGCM_PARM ; IN: новый путь (SHFLSTRING)
|
||||
flags HGCM_PARM ; IN: флаги
|
||||
ends
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; SHFL_FN_FLUSH - Flush буферов файла
|
||||
; -----------------------------------------------------------------------------
|
||||
struct SHFL_FLUSH
|
||||
header HGCM_CALL
|
||||
root HGCM_PARM ; IN: root handle
|
||||
handle HGCM_PARM ; IN: file handle
|
||||
ends
|
||||
16
drivers/vboxguest/data/timesync/constants.inc
Normal file
16
drivers/vboxguest/data/timesync/constants.inc
Normal file
@@ -0,0 +1,16 @@
|
||||
; =============================================================================
|
||||
; Time Sync Constants
|
||||
; =============================================================================
|
||||
VMMDEV_REQ_GET_HOST_TIME equ 10 ; VMMDevReq_GetHostTime
|
||||
|
||||
; Интервал синхронизации: 6000 тиков * 10ms = 60 сек
|
||||
TIMESYNC_INTERVAL_TICKS equ 6000
|
||||
|
||||
; Максимальное допустимое расхождение (100ms в наносекундах / 100)
|
||||
TIMESYNC_MAX_DRIFT_NS100 equ 1000000
|
||||
|
||||
; Флаг: нет событий VMMDev, чисто по таймеру
|
||||
TIMESYNC_EVENT_MASK equ 0
|
||||
|
||||
; Накопительные маски (timesync не требует событий и caps)
|
||||
VBOXGUEST_EVENTS_OR_MASK equ ( VBOXGUEST_EVENTS_OR_MASK or TIMESYNC_EVENT_MASK )
|
||||
12
drivers/vboxguest/data/timesync/structs.inc
Normal file
12
drivers/vboxguest/data/timesync/structs.inc
Normal file
@@ -0,0 +1,12 @@
|
||||
; =============================================================================
|
||||
; Time Sync Structures
|
||||
; =============================================================================
|
||||
|
||||
; VMMDevReq_GetHostTime (request type 10)
|
||||
; Возвращает время хоста в формате 100-наносекундных интервалов с 01.01.1601
|
||||
; (Windows FILETIME формат, он же RTTIMESPEC в VBox)
|
||||
struct VMMDEV_GET_HOST_TIME
|
||||
header VMMDEV_HEADER
|
||||
time_low dd ? ; Младшие 32 бита (100ns units since 1601)
|
||||
time_high dd ? ; Старшие 32 бита
|
||||
ends
|
||||
63
drivers/vboxguest/hgcm/async.inc
Normal file
63
drivers/vboxguest/hgcm/async.inc
Normal file
@@ -0,0 +1,63 @@
|
||||
; =============================================================================
|
||||
; Модуль : HGCM Async
|
||||
; Назначение : Ожидание завершения async HGCM запросов
|
||||
; Файл : hgcm/async.inc
|
||||
; Версия : 1.0
|
||||
; Дата : 2025.01.15
|
||||
; =============================================================================
|
||||
|
||||
; hgcm_wait_async
|
||||
proc hgcm_wait_async uses ebx ecx edx esi, request_ptr:dword
|
||||
mov esi, [request_ptr]
|
||||
test esi, esi
|
||||
jz .bad
|
||||
|
||||
mov ecx, HGCM_TIMEOUT_ITERS
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Waiting for async completion (timeout=%d iterations)\n", HGCM_TIMEOUT_ITERS
|
||||
|
||||
.wait_loop:
|
||||
mfence
|
||||
mov eax, [esi + HGCM_HEADER.flags]
|
||||
|
||||
test eax, VBOX_HGCM_REQ_DONE
|
||||
jnz .completed
|
||||
|
||||
test eax, VBOX_HGCM_REQ_CANCELLED
|
||||
jnz .cancelled
|
||||
|
||||
dec ecx
|
||||
jz .timeout
|
||||
|
||||
; короткая задержка
|
||||
push ecx
|
||||
mov ecx, 1000
|
||||
.delay:
|
||||
pause
|
||||
loop .delay
|
||||
pop ecx
|
||||
|
||||
jmp .wait_loop
|
||||
|
||||
.completed:
|
||||
mfence
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Async request completed\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.cancelled:
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Async request cancelled\n"
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
|
||||
.timeout:
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] *** ASYNC TIMEOUT ***\n"
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Current flags: 0x%x\n", [esi + HGCM_HEADER.flags]
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Request RC: 0x%x\n", [esi + HGCM_HEADER.header.rc]
|
||||
mov eax, VERR_TIMEOUT
|
||||
ret
|
||||
|
||||
.bad:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
endp
|
||||
395
drivers/vboxguest/hgcm/call.inc
Normal file
395
drivers/vboxguest/hgcm/call.inc
Normal file
@@ -0,0 +1,395 @@
|
||||
; =============================================================================
|
||||
; Модуль : HGCM Call32 с поддержкой PageList параметров
|
||||
; Назначение : HGCM вызовы (CALL32) поверх hgcm_send_request
|
||||
; Автоматическая конвертация LINADDR -> PAGE_LIST (type=10)
|
||||
; Файл : hgcm/call.inc
|
||||
; =============================================================================
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; hgcm_call32_pagelist — вызов HGCM_CALL32 с auto-pagelist
|
||||
;
|
||||
; Вход : client_id, function, parms_ptr, parm_count
|
||||
; Выход: eax = 0 успех / VERR_*
|
||||
;
|
||||
; LINADDR_IN/OUT/INOUT автоматически конвертируются в PAGE_LIST (type=10).
|
||||
; 32BIT/64BIT передаются как есть.
|
||||
; После вызова: данные OUT/INOUT уже в памяти гостя (хост писал напрямую
|
||||
; в физ. страницы). Обновляется поле size в оригинальных параметрах.
|
||||
; -----------------------------------------------------------------------------
|
||||
proc hgcm_call32_pagelist uses ebx ecx edx esi edi, client_id:dword, function:dword, parms:dword, parm_count:dword
|
||||
locals
|
||||
packet_base dd ?
|
||||
data_tail dd ? ; текущее смещение хвоста (для PageListInfo)
|
||||
param_idx dd ?
|
||||
; Временные переменные для конвертации одного параметра
|
||||
conv_cbdata dd ? ; размер буфера
|
||||
conv_vaddr dd ? ; виртуальный адрес буфера
|
||||
conv_flags dd ? ; флаги направления
|
||||
conv_off_first dd ? ; смещение в первой странице
|
||||
conv_cpages dd ? ; количество страниц
|
||||
conv_page_virt dd ? ; текущий virt addr страницы (для цикла)
|
||||
endl
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] CALL32: client=0x%x fn=%d cnt=%d\n", \
|
||||
[client_id], [function], [parm_count]
|
||||
|
||||
; --- Проверка: буфер не занят (защита от реентрантности) ---
|
||||
; lock bts dword [hgcm_pl_busy], 0
|
||||
; jc .busy
|
||||
|
||||
; --- Проверки ---
|
||||
mov eax, [parm_count]
|
||||
cmp eax, VMMDEV_MAX_HGCM_PARMS
|
||||
jbe .count_ok
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] ERROR: parm_count %d > max %d\n", eax, VMMDEV_MAX_HGCM_PARMS
|
||||
; mov dword [hgcm_pl_busy], 0
|
||||
mov eax, VERR_INVALID_PARAMETER
|
||||
ret
|
||||
.count_ok:
|
||||
|
||||
mov edi, [vbox_device.hgcm_call_pl_virt]
|
||||
test edi, edi
|
||||
jz .bad
|
||||
mov [packet_base], edi
|
||||
|
||||
; =================================================================
|
||||
; 1. Заголовок HGCM_CALL
|
||||
; =================================================================
|
||||
mov eax, [parm_count]
|
||||
imul eax, sizeof.HGCM_PARM
|
||||
add eax, sizeof.HGCM_CALL
|
||||
|
||||
hgcm_prepare_header edi, eax, VMMDEV_HGCM_CALL32
|
||||
|
||||
mov eax, [client_id]
|
||||
mov [edi + HGCM_CALL.client_id], eax
|
||||
mov eax, [function]
|
||||
mov [edi + HGCM_CALL.function], eax
|
||||
mov eax, [parm_count]
|
||||
mov [edi + HGCM_CALL.param_count], eax
|
||||
|
||||
; =================================================================
|
||||
; 2. Копируем параметры из parms[] в пакет
|
||||
; =================================================================
|
||||
mov ecx, [parm_count]
|
||||
test ecx, ecx
|
||||
jz .send_no_params
|
||||
|
||||
push ecx
|
||||
mov esi, [parms]
|
||||
lea edi, [edi + sizeof.HGCM_CALL]
|
||||
imul ecx, sizeof.HGCM_PARM
|
||||
rep movsb
|
||||
pop ecx
|
||||
|
||||
; =================================================================
|
||||
; 3. data_tail = начало области для PageListInfo
|
||||
; =================================================================
|
||||
mov eax, [parm_count]
|
||||
imul eax, sizeof.HGCM_PARM
|
||||
add eax, sizeof.HGCM_CALL
|
||||
mov [data_tail], eax
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] PageList tail starts at offset %d\n", eax
|
||||
|
||||
; =================================================================
|
||||
; 4. Конвертация LINADDR -> PAGE_LIST
|
||||
; =================================================================
|
||||
mov dword [param_idx], 0
|
||||
|
||||
.convert_loop:
|
||||
mov ecx, [param_idx]
|
||||
cmp ecx, [parm_count]
|
||||
jae .convert_done
|
||||
|
||||
; esi -> текущий параметр в пакете
|
||||
mov esi, [packet_base]
|
||||
add esi, sizeof.HGCM_CALL
|
||||
mov eax, ecx
|
||||
imul eax, sizeof.HGCM_PARM
|
||||
add esi, eax
|
||||
|
||||
mov eax, [esi + HGCM_PARM.type]
|
||||
|
||||
cmp eax, HGCM_PARM_TYPE_LINADDR_IN
|
||||
je .conv_in
|
||||
cmp eax, HGCM_PARM_TYPE_LINADDR_OUT
|
||||
je .conv_out
|
||||
cmp eax, HGCM_PARM_TYPE_LINADDR_INOUT
|
||||
je .conv_inout
|
||||
cmp eax, HGCM_PARM_TYPE_LINADDR
|
||||
je .conv_inout
|
||||
|
||||
; Не LINADDR — пропускаем
|
||||
jmp .next_param
|
||||
|
||||
.conv_in:
|
||||
mov dword [conv_flags], HGCM_PL_FLAG_IN
|
||||
jmp .do_convert
|
||||
.conv_out:
|
||||
mov dword [conv_flags], HGCM_PL_FLAG_OUT
|
||||
jmp .do_convert
|
||||
.conv_inout:
|
||||
mov dword [conv_flags], HGCM_PL_FLAG_BOTH
|
||||
|
||||
; ---- Конвертация одного параметра в PAGE_LIST ----
|
||||
; esi = указатель на HGCM_PARM в пакете (сохраняется)
|
||||
.do_convert:
|
||||
; Сохраняем cbData и vaddr в локальные переменные
|
||||
mov eax, dword [esi + HGCM_PARM.u.LinAddr.size]
|
||||
mov [conv_cbdata], eax
|
||||
mov eax, dword [esi + HGCM_PARM.u.LinAddr.offset]
|
||||
mov [conv_vaddr], eax
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] parm[%d]: LINADDR->PL vaddr=0x%x cb=%d fl=%d\n", \
|
||||
[param_idx], [conv_vaddr], [conv_cbdata], [conv_flags]
|
||||
|
||||
; --- cbData == 0 -> пустой PageList ---
|
||||
cmp dword [conv_cbdata], 0
|
||||
je .empty_pagelist
|
||||
|
||||
; --- offFirstPage = vaddr & 0xFFF ---
|
||||
mov eax, [conv_vaddr]
|
||||
and eax, PAGE_OFFSET_MASK
|
||||
mov [conv_off_first], eax
|
||||
|
||||
; --- cPages = (offFirstPage + cbData + 4095) >> 12 ---
|
||||
mov eax, [conv_off_first]
|
||||
add eax, [conv_cbdata]
|
||||
add eax, PAGE_SIZE - 1
|
||||
shr eax, 12
|
||||
mov [conv_cpages], eax
|
||||
|
||||
; --- Проверка: хватает ли места в хвосте? ---
|
||||
; Нужно: HGCM_PLI_APAGES (=8) + conv_cpages * 8
|
||||
mov eax, [conv_cpages]
|
||||
shl eax, 3 ; * 8 (размер одного RTGCPHYS64)
|
||||
add eax, HGCM_PLI_APAGES ; + 8 (заголовок PageListInfo)
|
||||
add eax, [data_tail]
|
||||
cmp eax, HGCM_PL_BUF_SIZE
|
||||
ja .buffer_overflow
|
||||
|
||||
; --- Заполняем заголовок HGCMPageListInfo ---
|
||||
; edi -> PageListInfo в хвосте пакета
|
||||
mov edi, [packet_base]
|
||||
add edi, [data_tail]
|
||||
|
||||
; flags (direction)
|
||||
mov eax, [conv_flags]
|
||||
mov dword [edi + HGCM_PLI_FLAGS], eax
|
||||
|
||||
; offFirstPage (word) — смещение данных внутри первой страницы
|
||||
mov eax, [conv_off_first]
|
||||
mov word [edi + HGCM_PLI_OFF_FIRST_PAGE], ax
|
||||
|
||||
; cPages (word)
|
||||
mov eax, [conv_cpages]
|
||||
mov word [edi + HGCM_PLI_CPAGES], ax
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] PLI at +%d: fl=%d offFirst=%d cPages=%d\n", \
|
||||
[data_tail], [conv_flags], [conv_off_first], [conv_cpages]
|
||||
|
||||
; --- Заполняем массив aPages[] физическими адресами ---
|
||||
; Подготовка: стартовый виртуальный адрес страницы
|
||||
mov eax, [conv_vaddr]
|
||||
and eax, PAGE_BASE_MASK
|
||||
mov [conv_page_virt], eax ; virt base первой страницы
|
||||
|
||||
xor ecx, ecx ; ecx = индекс страницы
|
||||
|
||||
.page_loop:
|
||||
cmp ecx, [conv_cpages]
|
||||
jae .pages_done
|
||||
|
||||
; Получаем физический адрес текущей страницы
|
||||
; GetPhysAddr: eax(вход) = virt addr, eax(выход) = phys addr
|
||||
; Сохраняем всё, что может быть затёрто invoke
|
||||
push ecx esi edi
|
||||
mov eax, [conv_page_virt]
|
||||
invoke GetPhysAddr
|
||||
mov ebx, eax ; ebx = phys addr
|
||||
pop edi esi ecx
|
||||
|
||||
; Записываем aPages[ecx] как RTGCPHYS64 (8 байт, little-endian)
|
||||
mov dword [edi + HGCM_PLI_APAGES + ecx*8], ebx ; low 32 bits
|
||||
mov dword [edi + HGCM_PLI_APAGES + ecx*8 + 4], 0 ; high 32 bits = 0
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] aPages[%d]: virt=0x%x phys=0x%x\n", \
|
||||
ecx, [conv_page_virt], ebx
|
||||
|
||||
; Следующая страница
|
||||
add dword [conv_page_virt], PAGE_SIZE
|
||||
inc ecx
|
||||
jmp .page_loop
|
||||
|
||||
.pages_done:
|
||||
; --- Перезаписываем параметр в пакете как PAGE_LIST ---
|
||||
; type = 10 (PAGE_LIST)
|
||||
mov dword [esi + HGCM_PARM.type], HGCM_PARM_TYPE_PAGELIST
|
||||
|
||||
; u[0..3] = cbData
|
||||
mov eax, [conv_cbdata]
|
||||
mov dword [esi + HGCM_PARM.u], eax
|
||||
|
||||
; u[4..7] = смещение к PageListInfo от начала пакета
|
||||
mov eax, [data_tail]
|
||||
mov dword [esi + HGCM_PARM.u + 4], eax
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] => type=10 cb=%d offPLI=%d\n", \
|
||||
[conv_cbdata], [data_tail]
|
||||
|
||||
; Сдвигаем data_tail: += HGCM_PLI_APAGES + cPages * 8
|
||||
mov eax, [conv_cpages]
|
||||
shl eax, 3 ; * 8
|
||||
add eax, HGCM_PLI_APAGES ; + 8 (заголовок)
|
||||
add [data_tail], eax
|
||||
|
||||
jmp .next_param
|
||||
|
||||
; --- Пустой PageList (cbData == 0) ---
|
||||
; ВАЖНО: VMMDev проверяет cPages > 0 даже при cbData=0!
|
||||
; Ставим cPages=1 с фиктивной страницей, чтобы пройти валидацию.
|
||||
; cbData=0 гарантирует что данные не передаются.
|
||||
.empty_pagelist:
|
||||
; Проверка места: 16 байт (8 заголовок + 8 одна фиктивная страница)
|
||||
mov eax, [data_tail]
|
||||
add eax, HGCM_PLI_APAGES + 8 ; 8 + 8 = 16
|
||||
cmp eax, HGCM_PL_BUF_SIZE
|
||||
ja .buffer_overflow
|
||||
|
||||
; Заполняем PageListInfo с 1 фиктивной страницей
|
||||
mov edi, [packet_base]
|
||||
add edi, [data_tail]
|
||||
mov eax, [conv_flags]
|
||||
mov dword [edi + HGCM_PLI_FLAGS], eax
|
||||
mov word [edi + HGCM_PLI_OFF_FIRST_PAGE], 0
|
||||
mov word [edi + HGCM_PLI_CPAGES], 1 ; cPages=1 (не 0!)
|
||||
mov dword [edi + HGCM_PLI_APAGES], 0 ; dummy phys lo
|
||||
mov dword [edi + HGCM_PLI_APAGES + 4], 0 ; dummy phys hi
|
||||
|
||||
; Записываем параметр
|
||||
mov dword [esi + HGCM_PARM.type], HGCM_PARM_TYPE_PAGELIST
|
||||
mov dword [esi + HGCM_PARM.u], 0 ; cbData = 0
|
||||
mov eax, [data_tail]
|
||||
mov dword [esi + HGCM_PARM.u + 4], eax ; offset к PLI
|
||||
|
||||
; data_tail += 16 (8 заголовок + 8 одна страница)
|
||||
add dword [data_tail], HGCM_PLI_APAGES + 8
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] parm[%d]: empty pagelist (cPages=1 dummy)\n", [param_idx]
|
||||
jmp .next_param
|
||||
|
||||
.buffer_overflow:
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] ERROR: PageList overflow at param %d\n", [param_idx]
|
||||
; mov dword [hgcm_pl_busy], 0
|
||||
mov eax, VERR_TOO_MUCH_DATA
|
||||
ret
|
||||
|
||||
.next_param:
|
||||
inc dword [param_idx]
|
||||
jmp .convert_loop
|
||||
|
||||
; =================================================================
|
||||
; 5. Обновляем размер пакета и отправляем
|
||||
; =================================================================
|
||||
.convert_done:
|
||||
mov edi, [packet_base]
|
||||
mov eax, [data_tail]
|
||||
mov [edi + VMMDEV_HEADER.size], eax
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] Final packet size: %d bytes\n", eax
|
||||
|
||||
; Отправляем
|
||||
stdcall hgcm_send_request, [packet_base]
|
||||
|
||||
; Debug post-send
|
||||
push eax
|
||||
mov esi, [packet_base]
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] POST: rc=0x%x result=0x%x\n", \
|
||||
[esi + HGCM_HEADER.header.rc], [esi + HGCM_HEADER.result]
|
||||
pop eax
|
||||
|
||||
test eax, eax
|
||||
jnz .send_failed
|
||||
|
||||
; =================================================================
|
||||
; 6. Copyback — только размеры и скалярные параметры
|
||||
; Данные OUT/INOUT уже на месте в памяти гостя.
|
||||
; =================================================================
|
||||
mov dword [param_idx], 0
|
||||
|
||||
.cb_loop:
|
||||
mov ecx, [param_idx]
|
||||
cmp ecx, [parm_count]
|
||||
jae .cb_done
|
||||
|
||||
; esi -> параметр в пакете
|
||||
mov esi, [packet_base]
|
||||
add esi, sizeof.HGCM_CALL
|
||||
mov eax, ecx
|
||||
imul eax, sizeof.HGCM_PARM
|
||||
add esi, eax
|
||||
|
||||
; edi -> оригинальный параметр в parms[]
|
||||
mov edi, [parms]
|
||||
add edi, eax
|
||||
|
||||
mov eax, [esi + HGCM_PARM.type]
|
||||
|
||||
cmp eax, HGCM_PARM_TYPE_PAGELIST
|
||||
je .cb_pagelist
|
||||
cmp eax, HGCM_PARM_TYPE_32BIT
|
||||
je .cb_32bit
|
||||
cmp eax, HGCM_PARM_TYPE_64BIT
|
||||
je .cb_64bit
|
||||
jmp .cb_next
|
||||
|
||||
.cb_32bit:
|
||||
; 32-bit значение — копируем обратно
|
||||
mov eax, dword [esi + HGCM_PARM.u]
|
||||
mov dword [edi + HGCM_PARM.u], eax
|
||||
jmp .cb_next
|
||||
|
||||
.cb_64bit:
|
||||
; 64-bit значение — копируем обратно
|
||||
mov eax, dword [esi + HGCM_PARM.u]
|
||||
mov dword [edi + HGCM_PARM.u], eax
|
||||
mov eax, dword [esi + HGCM_PARM.u + 4]
|
||||
mov dword [edi + HGCM_PARM.u + 4], eax
|
||||
jmp .cb_next
|
||||
|
||||
.cb_pagelist:
|
||||
; Для PAGE_LIST: хост мог обновить cbData (u[0..3]).
|
||||
; Копируем обновлённый размер в оригинальный параметр (LinAddr.size).
|
||||
; Адрес буфера (LinAddr.offset) не меняется.
|
||||
mov eax, dword [esi + HGCM_PARM.u]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.size], eax
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] cb[%d]: size=%d\n", ecx, eax
|
||||
jmp .cb_next
|
||||
|
||||
.cb_next:
|
||||
inc dword [param_idx]
|
||||
jmp .cb_loop
|
||||
|
||||
.cb_done:
|
||||
xor eax, eax
|
||||
.send_failed:
|
||||
; mov dword [hgcm_pl_busy], 0
|
||||
ret
|
||||
|
||||
.bad:
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] [PageList] ERROR: hgcm_call_pl_virt is NULL!\n"
|
||||
; mov dword [hgcm_pl_busy], 0
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
|
||||
.busy:
|
||||
DEBUGF 2, "[VBoxGuest] [HGCM] [PageList] BUSY — reentrancy blocked\n"
|
||||
mov eax, VERR_TRY_AGAIN
|
||||
ret
|
||||
|
||||
.send_no_params:
|
||||
; Без параметров — размер и отправка как в .convert_done
|
||||
jmp .convert_done
|
||||
|
||||
endp
|
||||
5
drivers/vboxguest/hgcm/core.inc
Normal file
5
drivers/vboxguest/hgcm/core.inc
Normal file
@@ -0,0 +1,5 @@
|
||||
; HGCM подсистема
|
||||
include 'hgcm/async.inc'
|
||||
include 'hgcm/params.inc'
|
||||
include 'hgcm/hgcm.inc'
|
||||
include 'hgcm/call.inc'
|
||||
276
drivers/vboxguest/hgcm/hgcm.inc
Normal file
276
drivers/vboxguest/hgcm/hgcm.inc
Normal file
@@ -0,0 +1,276 @@
|
||||
; =============================================================================
|
||||
; Модуль : HGCM Core
|
||||
; Назначение : HGCM: init packets + connect/disconnect + общий send_request
|
||||
; Файл : hgcm/hgcm.inc
|
||||
; =============================================================================
|
||||
; -----------------------------------------------------------------------------
|
||||
; Макрос: hgcm_prepare_header
|
||||
; Назначение: заполнить VMMDevRequestHeader внутри HGCM request
|
||||
; -----------------------------------------------------------------------------
|
||||
macro hgcm_prepare_header req_ptr, req_size, req_type
|
||||
{
|
||||
mov dword [req_ptr + HGCM_HEADER.header.size], req_size
|
||||
mov dword [req_ptr + HGCM_HEADER.header.version], VMMDEV_REQUEST_HEADER_VERSION
|
||||
mov dword [req_ptr + HGCM_HEADER.header.request_type], req_type
|
||||
mov dword [req_ptr + HGCM_HEADER.header.rc], VERR_GENERAL_FAILURE ; 0 ;VERR_NOT_READY
|
||||
mov dword [req_ptr + HGCM_HEADER.header.reserved1], 0
|
||||
mov dword [req_ptr + HGCM_HEADER.header.f_requestor], VMMDEV_REQUESTOR_VBOXGUEST
|
||||
|
||||
mov dword [req_ptr + HGCM_HEADER.flags], 0
|
||||
mov dword [req_ptr + HGCM_HEADER.result], 0
|
||||
}
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; hgcm_init_packets — выделить и привязать буферы HGCM (KernelAlloc)
|
||||
;
|
||||
; Выделяем:
|
||||
; 1 страница (4096) для connect + disconnect (помещаются вместе)
|
||||
; 1 страница (4096) для hgcm_call_s (embedded)
|
||||
; N страниц для hgcm_call_pl_s (pagelist)
|
||||
; -----------------------------------------------------------------------------
|
||||
proc hgcm_init_packets uses ebx
|
||||
|
||||
; --- Страница для connect + disconnect ---
|
||||
invoke KernelAlloc, PAGE_SIZE
|
||||
test eax, eax
|
||||
jz .alloc_fail
|
||||
|
||||
; connect = начало страницы
|
||||
mov [vbox_device.hgcm_connect_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.hgcm_connect_phys], eax
|
||||
|
||||
; disconnect = connect_virt + sizeof.HGCM_CONNECT (выровнено на 4)
|
||||
mov eax, [vbox_device.hgcm_connect_virt]
|
||||
add eax, ((sizeof.HGCM_CONNECT + 3) and (not 3))
|
||||
mov [vbox_device.hgcm_disconnect_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.hgcm_disconnect_phys], eax
|
||||
|
||||
; --- Страница для embedded call ---
|
||||
invoke KernelAlloc, PAGE_SIZE
|
||||
test eax, eax
|
||||
jz .alloc_fail_free1
|
||||
|
||||
mov [vbox_device.hgcm_call_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.hgcm_call_phys], eax
|
||||
|
||||
; --- Буфер для pagelist call
|
||||
invoke KernelAlloc, HGCM_PL_BUF_SIZE
|
||||
test eax, eax
|
||||
jz .alloc_fail_free2
|
||||
|
||||
mov [vbox_device.hgcm_call_pl_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.hgcm_call_pl_phys], eax
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [HGCM] Packets allocated: connect=0x%x call=0x%x pl=0x%x\n", \
|
||||
[vbox_device.hgcm_connect_virt], [vbox_device.hgcm_call_virt], [vbox_device.hgcm_call_pl_virt]
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.alloc_fail_free2:
|
||||
invoke KernelFree, [vbox_device.hgcm_call_virt]
|
||||
.alloc_fail_free1:
|
||||
invoke KernelFree, [vbox_device.hgcm_connect_virt]
|
||||
.alloc_fail:
|
||||
DEBUGF 2, "[VBoxGuest] [HGCM] ERROR: KernelAlloc failed for HGCM packets\n"
|
||||
mov eax, VERR_NO_MEMORY
|
||||
ret
|
||||
endp
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; hgcm_free_packets — освободить буферы HGCM
|
||||
; -----------------------------------------------------------------------------
|
||||
proc hgcm_free_packets
|
||||
; Pagelist call buffer
|
||||
cmp dword [vbox_device.hgcm_call_pl_virt], 0
|
||||
je @f
|
||||
invoke KernelFree, [vbox_device.hgcm_call_pl_virt]
|
||||
mov dword [vbox_device.hgcm_call_pl_virt], 0
|
||||
@@:
|
||||
; Embedded call buffer
|
||||
cmp dword [vbox_device.hgcm_call_virt], 0
|
||||
je @f
|
||||
invoke KernelFree, [vbox_device.hgcm_call_virt]
|
||||
mov dword [vbox_device.hgcm_call_virt], 0
|
||||
@@:
|
||||
; Connect+disconnect page
|
||||
cmp dword [vbox_device.hgcm_connect_virt], 0
|
||||
je @f
|
||||
invoke KernelFree, [vbox_device.hgcm_connect_virt]
|
||||
mov dword [vbox_device.hgcm_connect_virt], 0
|
||||
mov dword [vbox_device.hgcm_disconnect_virt], 0
|
||||
@@:
|
||||
ret
|
||||
endp
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; hgcm_init инициализация HGCM подсистемы
|
||||
; -----------------------------------------------------------------------------
|
||||
proc hgcm_init
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Initializing HGCM subsystem\n"
|
||||
|
||||
; Инициализируем пакеты
|
||||
call hgcm_init_packets
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Initialization complete\n"
|
||||
ret
|
||||
endp
|
||||
|
||||
; hgcm_send_request — отправить HGCM request через VMMDev + обработать ASYNC
|
||||
proc hgcm_send_request uses ebx ecx edx esi edi, request_ptr:dword
|
||||
mov esi, [request_ptr]
|
||||
test esi, esi
|
||||
jz .bad_ptr
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Sending request type=0x%x\n", [esi + HGCM_HEADER.header.request_type]
|
||||
|
||||
; phys адрес запроса
|
||||
mov eax, esi
|
||||
invoke GetPhysAddr
|
||||
test eax, eax
|
||||
jz .phys_failed
|
||||
mov edx, eax
|
||||
|
||||
; отправка VMMDev (submit-only, хост обновляет пакет через MMIO)
|
||||
stdcall vmmdev_send_request, edx
|
||||
|
||||
; транспортный rc
|
||||
mov eax, [esi + HGCM_HEADER.header.rc]
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Transport RC: 0x%x\n", eax
|
||||
|
||||
cmp eax, VINF_HGCM_ASYNC_EXECUTE
|
||||
je .async
|
||||
|
||||
; если rc < 0 — ошибка транспорта
|
||||
test eax, eax
|
||||
js .transport_error
|
||||
|
||||
; sync ok -> проверяем service result
|
||||
jmp .check_service
|
||||
|
||||
.async:
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Request is async, waiting...\n"
|
||||
stdcall hgcm_wait_async, esi
|
||||
test eax, eax
|
||||
jnz .async_failed
|
||||
|
||||
; после async: транспортный rc
|
||||
mov eax, [esi + HGCM_HEADER.header.rc]
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Post-async transport RC: 0x%x\n", eax
|
||||
test eax, eax
|
||||
js .transport_error_after_async
|
||||
|
||||
.check_service:
|
||||
; результат сервиса
|
||||
mov eax, [esi + HGCM_HEADER.result]
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Service result: 0x%x\n", eax
|
||||
test eax, eax
|
||||
js .service_error
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
|
||||
.phys_failed:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
|
||||
.transport_error:
|
||||
ret
|
||||
|
||||
.transport_error_after_async:
|
||||
ret
|
||||
|
||||
.service_error:
|
||||
ret
|
||||
|
||||
.async_failed:
|
||||
ret
|
||||
endp
|
||||
|
||||
; hgcm_connect — подключение к HGCM сервису
|
||||
proc hgcm_connect uses ebx ecx edx esi edi, service_name:dword
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Connecting to service: %s\n", [service_name]
|
||||
|
||||
mov edi, [vbox_device.hgcm_connect_virt]
|
||||
test edi, edi
|
||||
jz .failed
|
||||
|
||||
; header
|
||||
hgcm_prepare_header edi, sizeof.HGCM_CONNECT, VMMDEV_HGCM_CONNECT
|
||||
|
||||
; location
|
||||
mov dword [edi + HGCM_CONNECT.location_type], HGCM_LOC_TYPE_PREDEFINED
|
||||
|
||||
; очистить service_name буфер
|
||||
push edi
|
||||
lea edi, [edi + HGCM_CONNECT.service_name]
|
||||
xor eax, eax
|
||||
mov ecx, HGCM_SERVICE_NAME_MAX / 4
|
||||
rep stosd
|
||||
pop edi
|
||||
|
||||
; копировать ASCII имя сервиса
|
||||
mov esi, [service_name]
|
||||
push edi
|
||||
lea edi, [edi + HGCM_CONNECT.service_name]
|
||||
mov ecx, HGCM_SERVICE_NAME_MAX - 1
|
||||
.copy_name:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .name_done
|
||||
stosb
|
||||
loop .copy_name
|
||||
.name_done:
|
||||
xor al, al
|
||||
stosb
|
||||
pop edi
|
||||
|
||||
; client_id = 0
|
||||
mov dword [edi + HGCM_CONNECT.client_id], 0
|
||||
|
||||
; отправить
|
||||
stdcall hgcm_send_request, [vbox_device.hgcm_connect_virt]
|
||||
test eax, eax
|
||||
jnz .failed
|
||||
|
||||
mov eax, [edi + HGCM_CONNECT.client_id]
|
||||
test eax, eax
|
||||
jz .failed
|
||||
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Connected, client_id=0x%x\n", eax
|
||||
ret
|
||||
|
||||
.failed:
|
||||
DEBUGF 2, "[VBoxGuest] [HGCM] Connect failed\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; hgcm_disconnect — отключение клиента HGCM
|
||||
proc hgcm_disconnect uses edi, client_id:dword
|
||||
DEBUGF __DEBUG_HGCM__, "[VBoxGuest] [HGCM] Disconnecting client: 0x%x\n", [client_id]
|
||||
|
||||
mov edi, [vbox_device.hgcm_disconnect_virt]
|
||||
test edi, edi
|
||||
jz .bad
|
||||
|
||||
hgcm_prepare_header edi, sizeof.HGCM_DISCONNECT, VMMDEV_HGCM_DISCONNECT
|
||||
|
||||
mov eax, [client_id]
|
||||
mov [edi + HGCM_DISCONNECT.client_id], eax
|
||||
|
||||
stdcall hgcm_send_request, [vbox_device.hgcm_disconnect_virt]
|
||||
ret
|
||||
|
||||
.bad:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
endp
|
||||
78
drivers/vboxguest/hgcm/params.inc
Normal file
78
drivers/vboxguest/hgcm/params.inc
Normal file
@@ -0,0 +1,78 @@
|
||||
; =============================================================================
|
||||
; Модуль : HGCM Params
|
||||
; Назначение : Формирование параметров HGCM_PARM
|
||||
; Файл : hgcm/params.inc
|
||||
; Версия : 1.1
|
||||
; Дата : 2025.01.15
|
||||
; =============================================================================
|
||||
|
||||
; hgcm_param_32 — заполнить 32-битный параметр
|
||||
;
|
||||
; Вход : p — указатель на HGCM_PARM, value — значение
|
||||
proc hgcm_param_32 uses edi, p:dword, value:dword
|
||||
mov edi, [p]
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_32BIT
|
||||
mov eax, [value]
|
||||
mov dword [edi + HGCM_PARM.u.value32], eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; hgcm_param_64 — заполнить 64-битный параметр
|
||||
;
|
||||
; Вход : p — указатель на HGCM_PARM, lo/hi — младшая/старшая часть
|
||||
; -----------------------------------------------------------------------------
|
||||
proc hgcm_param_64 uses edi, p:dword, lo:dword, hi:dword
|
||||
mov edi, [p]
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_64BIT
|
||||
mov eax, [lo]
|
||||
mov dword [edi + HGCM_PARM.u.value64_lo], eax
|
||||
mov eax, [hi]
|
||||
mov dword [edi + HGCM_PARM.u.value64_hi], eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; hgcm_param_linaddr_in — линейный буфер IN (гость → хост)
|
||||
;
|
||||
; Вход : p — указатель на HGCM_PARM, addr — адрес буфера, size — размер
|
||||
; -----------------------------------------------------------------------------
|
||||
proc hgcm_param_linaddr_in uses edi, p:dword, addr:dword, size:dword
|
||||
mov edi, [p]
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_LINADDR_IN
|
||||
mov eax, [size]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.size], eax
|
||||
mov eax, [addr]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.offset], eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; hgcm_param_linaddr_out — линейный буфер OUT (хост → гость)
|
||||
;
|
||||
; Вход : p — указатель на HGCM_PARM, addr — адрес буфера, size — размер
|
||||
; -----------------------------------------------------------------------------
|
||||
proc hgcm_param_linaddr_out uses edi, p:dword, addr:dword, size:dword
|
||||
mov edi, [p]
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_LINADDR_OUT
|
||||
mov eax, [size]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.size], eax
|
||||
mov eax, [addr]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.offset], eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; hgcm_param_linaddr_inout — линейный буфер INOUT (двунаправленный)
|
||||
;
|
||||
; Вход : p — указатель на HGCM_PARM, addr — адрес буфера, size — размер
|
||||
; -----------------------------------------------------------------------------
|
||||
proc hgcm_param_linaddr_inout uses edi, p:dword, addr:dword, size:dword
|
||||
mov edi, [p]
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_LINADDR_INOUT
|
||||
mov eax, [size]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.size], eax
|
||||
mov eax, [addr]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.offset], eax
|
||||
ret
|
||||
endp
|
||||
220
drivers/vboxguest/services/clipboard/clipboard.inc
Normal file
220
drivers/vboxguest/services/clipboard/clipboard.inc
Normal file
@@ -0,0 +1,220 @@
|
||||
; =============================================================================
|
||||
; Модуль : VBox Shared Clipboard Service
|
||||
; Файл : services/clipboard/clipboard.inc
|
||||
;
|
||||
; Архитектура : Async state machine + IOCTL ABI
|
||||
; clipboard_init — HGCM connect + аллокация listener пакета
|
||||
; clipboard_enable — отправка первого MSG_OLD_GET_WAIT (async)
|
||||
; clipboard_on_tick — проверка завершения async запроса + resubmit
|
||||
;
|
||||
; Данные хоста и гостя передаются через IOCTL (приложение):
|
||||
; CLIP_STATUS (10) — статус (formats, host_new)
|
||||
; CLIP_READ (11) — чтение данных хоста (HGCM DATA_READ)
|
||||
; CLIP_WRITE (12) — запись данных гостя (буферизация + HGCM REPORT_FORMATS)
|
||||
;
|
||||
; Источник протокола: VBox 7.2.6
|
||||
; include/VBox/HostServices/VBoxClipboardSvc.h
|
||||
; =============================================================================
|
||||
|
||||
svc_clipboard_name db "CLIPBOARD", 0
|
||||
|
||||
align 4
|
||||
sz_clipboard_hgcm_service db 'VBoxSharedClipboard', 0
|
||||
|
||||
align 4
|
||||
clip_state CLIPBOARD_STATE
|
||||
|
||||
; clipboard_init — Подключиться к HGCM + выделить listener пакет
|
||||
proc clipboard_init uses ebx
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Initializing...\n"
|
||||
|
||||
mov eax, [vbox_device.hgcm_connect_virt]
|
||||
test eax, eax
|
||||
jz .hgcm_not_ready
|
||||
|
||||
cmp dword [clip_state.connected], 1
|
||||
je .already_connected
|
||||
|
||||
; --- Подключиться к HGCM ---
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Connecting to '%s'...\n", sz_clipboard_hgcm_service
|
||||
stdcall hgcm_connect, sz_clipboard_hgcm_service
|
||||
test eax, eax
|
||||
jz .connect_failed
|
||||
|
||||
mov [clip_state.client_id], eax
|
||||
mov dword [clip_state.connected], 1
|
||||
mov dword [clip_state.listen_state], CLIP_LISTEN_IDLE
|
||||
mov dword [clip_state.error_count], 0
|
||||
mov dword [clip_state.formats_host], 0
|
||||
mov dword [clip_state.formats_guest], 0
|
||||
mov dword [clip_state.has_data], 0
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Connected, client_id=%d\n", eax
|
||||
|
||||
; --- Выделить listener пакет (или переиспользовать существующий) ---
|
||||
; При fire-and-forget disconnect пакет не освобождается (хост может
|
||||
; ещё DMA-писать DONE flag), поэтому переиспользуем при re-enable.
|
||||
cmp dword [clip_state.listen_pkt_virt], 0
|
||||
jne .pkt_ready
|
||||
|
||||
invoke KernelAlloc, 4096
|
||||
test eax, eax
|
||||
jz .alloc_failed
|
||||
|
||||
mov [clip_state.listen_pkt_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [clip_state.listen_pkt_phys], eax
|
||||
.pkt_ready:
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Listener pkt: virt=0x%x, phys=0x%x\n", \
|
||||
[clip_state.listen_pkt_virt], [clip_state.listen_pkt_phys]
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Initialized OK\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.alloc_failed:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] KernelAlloc failed for listener pkt\n"
|
||||
stdcall hgcm_disconnect, [clip_state.client_id]
|
||||
mov dword [clip_state.connected], 0
|
||||
mov eax, VERR_NO_MEMORY
|
||||
ret
|
||||
|
||||
.connect_failed:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] HGCM connect failed\n"
|
||||
mov eax, VERR_HGCM_SERVICE_NOT_FOUND
|
||||
ret
|
||||
.hgcm_not_ready:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] HGCM not ready\n"
|
||||
mov eax, VERR_NOT_READY
|
||||
ret
|
||||
.already_connected:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Already connected\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; clipboard_enable — Отправить первый MSG_OLD_GET_WAIT
|
||||
proc clipboard_enable
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Enabling (async listener)...\n"
|
||||
|
||||
cmp dword [clip_state.connected], 0
|
||||
jne .connected
|
||||
|
||||
; После disable HGCM отключен — переподключиться
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Not connected, re-initializing...\n"
|
||||
call clipboard_init
|
||||
test eax, eax
|
||||
jnz .init_failed
|
||||
|
||||
.connected:
|
||||
; Отправить первый listener запрос
|
||||
call clipboard_listener_submit
|
||||
test eax, eax
|
||||
jnz .submit_failed
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Enabled OK\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.init_failed:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Enable: re-init failed (0x%x)\n", eax
|
||||
ret
|
||||
|
||||
.submit_failed:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Enable: first submit failed (0x%x)\n", eax
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; clipboard_on_event — Вызывается из IRQ (dispatcher_dispatch)
|
||||
; ПРИМЕЧАНИЕ: IRQ обработка полностью делегирована on_tick,
|
||||
; поэтому здесь просто возвращаем (событие уже обработано в tick)
|
||||
proc clipboard_on_event
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; clipboard_on_tick — Вызывается из таймера каждые 100ms
|
||||
proc clipboard_on_tick
|
||||
cmp dword [clip_state.connected], 0
|
||||
je .done
|
||||
|
||||
cmp dword [clip_state.error_count], CLIP_MAX_ERRORS
|
||||
jae .done
|
||||
|
||||
mov eax, [clip_state.listen_state]
|
||||
|
||||
cmp eax, CLIP_LISTEN_SUBMITTED
|
||||
je .check
|
||||
|
||||
; IDLE — отправить новый запрос
|
||||
call clipboard_listener_submit
|
||||
jmp .done
|
||||
|
||||
.check:
|
||||
call clipboard_listener_check
|
||||
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; clipboard_disable — Остановить listener, disconnect HGCM
|
||||
proc clipboard_disable uses edi
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Disabling...\n"
|
||||
|
||||
cmp dword [clip_state.connected], 0
|
||||
je .done
|
||||
|
||||
; Если listener pending — disconnect fire-and-forget (без busy-wait).
|
||||
; При shutdown VBox не может быстро обработать disconnect из-за pending
|
||||
; MSG_OLD_GET_WAIT, и hgcm_send_request зависает в hgcm_wait_async
|
||||
; на ~30-60 сек (HGCM_TIMEOUT_MS = 500000 итераций busy-loop).
|
||||
cmp dword [clip_state.listen_state], CLIP_LISTEN_SUBMITTED
|
||||
je .fast_disconnect
|
||||
|
||||
; Нет pending запроса — обычный disconnect (sync, быстрый)
|
||||
stdcall hgcm_disconnect, [clip_state.client_id]
|
||||
jmp .cleanup
|
||||
|
||||
.fast_disconnect:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Listener pending — fire-and-forget disconnect\n"
|
||||
|
||||
mov edi, [vbox_device.hgcm_disconnect_virt]
|
||||
test edi, edi
|
||||
jz .cleanup
|
||||
|
||||
hgcm_prepare_header edi, sizeof.HGCM_DISCONNECT, VMMDEV_HGCM_DISCONNECT
|
||||
mov eax, [clip_state.client_id]
|
||||
mov [edi + HGCM_DISCONNECT.client_id], eax
|
||||
|
||||
; Отправить через VMMDev напрямую (non-blocking out dx, eax)
|
||||
; НЕ вызываем hgcm_send_request чтобы избежать hgcm_wait_async
|
||||
stdcall vmmdev_send_request, [vbox_device.hgcm_disconnect_phys]
|
||||
|
||||
.cleanup:
|
||||
; НЕ освобождаем listener пакет — хост может ещё DMA-писать DONE flag
|
||||
; в эту страницу. Пакет будет переиспользован при следующем enable.
|
||||
|
||||
; Освободить буфер guest→host данных
|
||||
cmp dword [clip_guest_buf_ptr], 0
|
||||
je .no_guest_buf
|
||||
invoke KernelFree, [clip_guest_buf_ptr]
|
||||
mov dword [clip_guest_buf_ptr], 0
|
||||
mov dword [clip_guest_buf_size], 0
|
||||
.no_guest_buf:
|
||||
|
||||
mov dword [clip_state.connected], 0
|
||||
mov dword [clip_state.client_id], 0
|
||||
mov dword [clip_state.listen_state], CLIP_LISTEN_IDLE
|
||||
mov dword [clip_host_new], 0
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Disabled\n"
|
||||
.done:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
include 'clipboard_listener.inc'
|
||||
|
||||
REGISTER_SERVICE svc_clipboard_name, CLIPBOARD_EVENT_MASK, CLIPBOARD_CAPS_MASK, \
|
||||
clipboard_init, clipboard_enable, clipboard_disable, clipboard_on_event, clipboard_on_tick, AUTOSTART_CLIPBOARD
|
||||
614
drivers/vboxguest/services/clipboard/clipboard_listener.inc
Normal file
614
drivers/vboxguest/services/clipboard/clipboard_listener.inc
Normal file
@@ -0,0 +1,614 @@
|
||||
; =============================================================================
|
||||
; Clipboard Listener + IOCTL handlers
|
||||
;
|
||||
; Файл: services/clipboard/clipboard_listener.inc
|
||||
;
|
||||
; Listener: async MSG_OLD_GET_WAIT для получения сообщений от хоста
|
||||
; IOCTL: clip_ioctl_status, clip_ioctl_read, clip_ioctl_write
|
||||
; =============================================================================
|
||||
|
||||
; Размер пакета: HGCM_CALL(44) + 2 * HGCM_PARM(12) = 68
|
||||
CLIP_LISTEN_PKT_SIZE = sizeof.HGCM_CALL + (VBOX_SHCL_CPARMS_MSG_OLD_GET_WAIT * sizeof.HGCM_PARM)
|
||||
|
||||
; Смещения параметров от начала пакета
|
||||
CLIP_LISTEN_PARM0 = sizeof.HGCM_CALL ; offset 44: msg_type
|
||||
CLIP_LISTEN_PARM1 = sizeof.HGCM_CALL + sizeof.HGCM_PARM ; offset 56: formats
|
||||
|
||||
; Начальный размер буфера для HGCM DATA_READ (retry с большим если не хватит)
|
||||
CLIP_INITIAL_BUF_SIZE = 65536 ; 64KB
|
||||
|
||||
; Максимум символов для debug вывода
|
||||
CLIP_DEBUG_MAX_CHARS = 200
|
||||
|
||||
; Статический буфер для cp866-вывода (UTF-16LE → cp866)
|
||||
align 4
|
||||
clip_ascii_buf rb CLIP_DEBUG_MAX_CHARS + 4
|
||||
|
||||
; Host clipboard state (set by async listener, read by IOCTL)
|
||||
align 4
|
||||
clip_host_new dd 0 ; 1 = host clipboard changed since last CLIP_READ
|
||||
|
||||
; Guest → host buffered data (set by CLIP_WRITE, sent on host READ_DATA)
|
||||
align 4
|
||||
clip_guest_buf_ptr dd 0 ; KernelAlloc'd buffer, or 0
|
||||
clip_guest_buf_size dd 0 ; data size in bytes
|
||||
clip_guest_buf_fmt dd 0 ; VBOX_SHCL_FMT_*
|
||||
|
||||
; clipboard_listener_submit — Отправить MSG_OLD_GET_WAIT (async)
|
||||
proc clipboard_listener_submit uses ebx edx edi
|
||||
mov edi, [clip_state.listen_pkt_virt]
|
||||
test edi, edi
|
||||
jz .bad_ptr
|
||||
|
||||
; --- Заполнить HGCM_CALL заголовок ---
|
||||
hgcm_prepare_header edi, CLIP_LISTEN_PKT_SIZE, VMMDEV_HGCM_CALL32
|
||||
|
||||
mov eax, [clip_state.client_id]
|
||||
mov [edi + HGCM_CALL.client_id], eax
|
||||
mov dword [edi + HGCM_CALL.function], VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT
|
||||
mov dword [edi + HGCM_CALL.param_count], VBOX_SHCL_CPARMS_MSG_OLD_GET_WAIT
|
||||
|
||||
; --- parm[0]: msg_type (32BIT, OUT) ---
|
||||
mov dword [edi + CLIP_LISTEN_PARM0 + HGCM_PARM.type], HGCM_PARM_TYPE_32BIT
|
||||
mov dword [edi + CLIP_LISTEN_PARM0 + HGCM_PARM.u.value32], 0
|
||||
mov dword [edi + CLIP_LISTEN_PARM0 + HGCM_PARM.u.value32 + 4], 0
|
||||
|
||||
; --- parm[1]: formats (32BIT, OUT) ---
|
||||
mov dword [edi + CLIP_LISTEN_PARM1 + HGCM_PARM.type], HGCM_PARM_TYPE_32BIT
|
||||
mov dword [edi + CLIP_LISTEN_PARM1 + HGCM_PARM.u.value32], 0
|
||||
mov dword [edi + CLIP_LISTEN_PARM1 + HGCM_PARM.u.value32 + 4], 0
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Submitting MSG_OLD_GET_WAIT (async)...\n"
|
||||
|
||||
stdcall vmmdev_send_request, [clip_state.listen_pkt_phys]
|
||||
|
||||
mov eax, [edi + HGCM_HEADER.header.rc]
|
||||
|
||||
cmp eax, VINF_HGCM_ASYNC_EXECUTE
|
||||
je .async_ok
|
||||
|
||||
test eax, eax
|
||||
js .error
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] MSG_OLD_GET_WAIT completed sync (rc=0x%x)\n", eax
|
||||
mov dword [clip_state.listen_state], CLIP_LISTEN_SUBMITTED
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.async_ok:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] MSG_OLD_GET_WAIT submitted (async)\n"
|
||||
mov dword [clip_state.listen_state], CLIP_LISTEN_SUBMITTED
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] MSG_OLD_GET_WAIT submit failed: rc=0x%x\n", eax
|
||||
mov dword [clip_state.listen_state], CLIP_LISTEN_IDLE
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Listener packet not allocated!\n"
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
endp
|
||||
|
||||
; clipboard_listener_check — Проверить завершение async запроса
|
||||
proc clipboard_listener_check uses ebx edx edi
|
||||
mov edi, [clip_state.listen_pkt_virt]
|
||||
|
||||
mfence
|
||||
|
||||
mov eax, [edi + HGCM_HEADER.flags]
|
||||
test eax, VBOX_HGCM_REQ_DONE
|
||||
jz .not_done
|
||||
|
||||
mfence
|
||||
|
||||
mov eax, [edi + HGCM_HEADER.header.rc]
|
||||
test eax, eax
|
||||
js .transport_error
|
||||
|
||||
mov eax, [edi + HGCM_HEADER.result]
|
||||
test eax, eax
|
||||
js .service_error
|
||||
|
||||
mov eax, dword [edi + CLIP_LISTEN_PARM0 + HGCM_PARM.u.value32]
|
||||
mov edx, dword [edi + CLIP_LISTEN_PARM1 + HGCM_PARM.u.value32]
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Got message: type=%d, formats=0x%x\n", eax, edx
|
||||
|
||||
push eax edx
|
||||
stdcall clipboard_listener_dispatch, eax, edx
|
||||
pop edx eax
|
||||
|
||||
mov dword [clip_state.listen_state], CLIP_LISTEN_IDLE
|
||||
mov dword [clip_state.error_count], 0
|
||||
mov eax, 1
|
||||
ret
|
||||
|
||||
.transport_error:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Listener transport error: rc=0x%x\n", eax
|
||||
jmp .handle_error
|
||||
|
||||
.service_error:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Listener service error: result=0x%x\n", eax
|
||||
|
||||
.handle_error:
|
||||
mov dword [clip_state.listen_state], CLIP_LISTEN_IDLE
|
||||
inc dword [clip_state.error_count]
|
||||
mov eax, 1
|
||||
ret
|
||||
|
||||
.not_done:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; clipboard_listener_dispatch — Обработать сообщение хоста
|
||||
proc clipboard_listener_dispatch stdcall, msg_type:dword, formats:dword
|
||||
|
||||
mov eax, [msg_type]
|
||||
|
||||
cmp eax, VBOX_SHCL_HOST_MSG_FORMATS_REPORT
|
||||
je .formats_report
|
||||
|
||||
cmp eax, VBOX_SHCL_HOST_MSG_READ_DATA
|
||||
je .read_data
|
||||
|
||||
cmp eax, VBOX_SHCL_HOST_MSG_QUIT
|
||||
je .quit
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Unknown msg_type=%d\n", eax
|
||||
ret
|
||||
|
||||
.formats_report:
|
||||
; Хост сообщает что у него новые данные в клипборде
|
||||
mov eax, [formats]
|
||||
mov [clip_state.formats_host], eax
|
||||
mov dword [clip_host_new], 1
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Host formats: 0x%x (flagged for app)\n", eax
|
||||
ret
|
||||
|
||||
.read_data:
|
||||
; Хост хочет прочитать данные гостя — отправляем буферизованные
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Host requests READ_DATA (formats=0x%x, buf=%d bytes)\n", \
|
||||
[formats], [clip_guest_buf_size]
|
||||
|
||||
cmp dword [clip_guest_buf_ptr], 0
|
||||
je .no_guest_data
|
||||
|
||||
stdcall clipboard_respond_read_data
|
||||
ret
|
||||
|
||||
.no_guest_data:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] READ_DATA: no guest data buffered!\n"
|
||||
ret
|
||||
|
||||
.quit:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Host sent QUIT\n"
|
||||
mov dword [clip_state.connected], 0
|
||||
ret
|
||||
endp
|
||||
|
||||
; clipboard_respond_read_data — Отправить буферизованные данные хосту
|
||||
proc clipboard_respond_read_data stdcall uses ebx ecx edx esi edi
|
||||
locals
|
||||
parms rb sizeof.HGCM_PARM * 2
|
||||
endl
|
||||
|
||||
; parm[0]: format (32BIT, IN)
|
||||
lea edi, [parms]
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_32BIT
|
||||
mov eax, [clip_guest_buf_fmt]
|
||||
mov dword [edi + HGCM_PARM.u.value32], eax
|
||||
mov dword [edi + HGCM_PARM.u.value32 + 4], 0
|
||||
|
||||
; parm[1]: data (LINADDR_IN)
|
||||
add edi, sizeof.HGCM_PARM
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_LINADDR_IN
|
||||
mov eax, [clip_guest_buf_size]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.size], eax
|
||||
mov eax, [clip_guest_buf_ptr]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.offset], eax
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Sending %d bytes to host (fmt=0x%x)\n", \
|
||||
[clip_guest_buf_size], [clip_guest_buf_fmt]
|
||||
|
||||
lea eax, [parms]
|
||||
stdcall hgcm_call32_pagelist, [clip_state.client_id], \
|
||||
VBOX_SHCL_GUEST_FN_DATA_WRITE, eax, VBOX_SHCL_CPARMS_DATA_WRITE_OLD
|
||||
|
||||
test eax, eax
|
||||
jnz .error
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Guest data sent to host OK\n"
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] DATA_WRITE FAILED: 0x%x\n", eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; clipboard_report_formats — Сообщить хосту о форматах гостевого clipboard
|
||||
proc clipboard_report_formats stdcall uses ebx ecx edx esi edi, formats:dword
|
||||
locals
|
||||
parms rb sizeof.HGCM_PARM
|
||||
endl
|
||||
lea edi, [parms]
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_32BIT
|
||||
mov eax, [formats]
|
||||
mov dword [edi + HGCM_PARM.u.value32], eax
|
||||
mov dword [edi + HGCM_PARM.u.value32 + 4], 0
|
||||
|
||||
lea eax, [parms]
|
||||
stdcall hgcm_call32_pagelist, [clip_state.client_id], \
|
||||
VBOX_SHCL_GUEST_FN_REPORT_FORMATS, eax, VBOX_SHCL_CPARMS_REPORT_FORMATS
|
||||
|
||||
test eax, eax
|
||||
jnz .error
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Reported formats 0x%x to host\n", [formats]
|
||||
ret
|
||||
.error:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Report formats FAILED: 0x%x\n", eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; clip_ioctl_status — IOCTL 10: Статус clipboard
|
||||
proc clip_ioctl_status stdcall uses ebx, ioctl_ptr:dword
|
||||
mov ebx, [ioctl_ptr]
|
||||
cmp [ebx + IOCTL.out_size], 12
|
||||
jb .fail
|
||||
|
||||
mov eax, [ebx + IOCTL.output]
|
||||
|
||||
mov ecx, [clip_state.connected]
|
||||
mov [eax], ecx
|
||||
|
||||
mov ecx, [clip_state.formats_host]
|
||||
mov [eax + 4], ecx
|
||||
|
||||
mov ecx, [clip_host_new]
|
||||
mov [eax + 8], ecx
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.fail:
|
||||
or eax, -1
|
||||
ret
|
||||
endp
|
||||
|
||||
; clip_ioctl_read — IOCTL 11: Прочитать clipboard хоста
|
||||
proc clip_ioctl_read stdcall uses ebx ecx edx esi edi, ioctl_ptr:dword
|
||||
locals
|
||||
parms rb sizeof.HGCM_PARM * 3
|
||||
kern_buf dd ?
|
||||
kern_size dd ?
|
||||
req_format dd ?
|
||||
endl
|
||||
mov ebx, [ioctl_ptr]
|
||||
|
||||
; Validate input/output
|
||||
cmp [ebx + IOCTL.inp_size], 4
|
||||
jb .fail
|
||||
cmp [ebx + IOCTL.out_size], 4
|
||||
jb .fail
|
||||
cmp dword [clip_state.connected], 0
|
||||
je .fail
|
||||
|
||||
; Сбросить host_new СРАЗУ — чтобы при ошибке HGCM приложение
|
||||
; не повторяло CLIP_READ бесконечно (retry storm).
|
||||
; Новое изменение хоста снова выставит host_new=1 через listener.
|
||||
mov dword [clip_host_new], 0
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] CLIP_READ: out_size=%d\n", [ebx + IOCTL.out_size]
|
||||
|
||||
; Get requested format
|
||||
mov eax, [ebx + IOCTL.input]
|
||||
mov eax, [eax]
|
||||
mov [req_format], eax
|
||||
|
||||
; Calculate kernel buffer size: max(out_size - 4, CLIP_INITIAL_BUF_SIZE)
|
||||
mov ecx, [ebx + IOCTL.out_size]
|
||||
sub ecx, 4
|
||||
cmp ecx, CLIP_INITIAL_BUF_SIZE
|
||||
jae .size_ok
|
||||
mov ecx, CLIP_INITIAL_BUF_SIZE
|
||||
.size_ok:
|
||||
; Round up to page
|
||||
add ecx, (PAGE_SIZE - 1)
|
||||
and ecx, PAGE_BASE_MASK
|
||||
mov [kern_size], ecx
|
||||
|
||||
; Allocate kernel buffer
|
||||
invoke KernelAlloc, ecx
|
||||
test eax, eax
|
||||
jz .no_mem
|
||||
mov [kern_buf], eax
|
||||
|
||||
.do_read:
|
||||
; --- Заполнить HGCM DATA_READ параметры ---
|
||||
lea edi, [parms]
|
||||
|
||||
; parm[0]: format (32BIT, IN)
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_32BIT
|
||||
mov eax, [req_format]
|
||||
mov dword [edi + HGCM_PARM.u.value32], eax
|
||||
mov dword [edi + HGCM_PARM.u.value32 + 4], 0
|
||||
|
||||
; parm[1]: buffer (LINADDR_OUT)
|
||||
add edi, sizeof.HGCM_PARM
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_LINADDR_OUT
|
||||
mov eax, [kern_size]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.size], eax
|
||||
mov eax, [kern_buf]
|
||||
mov dword [edi + HGCM_PARM.u.LinAddr.offset], eax
|
||||
|
||||
; parm[2]: size (32BIT, OUT)
|
||||
add edi, sizeof.HGCM_PARM
|
||||
mov dword [edi + HGCM_PARM.type], HGCM_PARM_TYPE_32BIT
|
||||
mov dword [edi + HGCM_PARM.u.value32], 0
|
||||
mov dword [edi + HGCM_PARM.u.value32 + 4], 0
|
||||
|
||||
; --- Вызвать HGCM DATA_READ ---
|
||||
lea eax, [parms]
|
||||
stdcall hgcm_call32_pagelist, [clip_state.client_id], \
|
||||
VBOX_SHCL_GUEST_FN_DATA_READ, eax, VBOX_SHCL_CPARMS_DATA_READ
|
||||
|
||||
; Прочитать actual_size из parm[2]
|
||||
lea edi, [parms]
|
||||
mov ecx, dword [edi + 2 * sizeof.HGCM_PARM + HGCM_PARM.u.value32]
|
||||
|
||||
; Проверить результат HGCM
|
||||
test eax, eax
|
||||
jnz .check_overflow
|
||||
|
||||
; Успех — данные прочитаны
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] CLIP_READ: OK, %d bytes (fmt=0x%x)\n", ecx, [req_format]
|
||||
|
||||
; Записать actual_size в output[0]
|
||||
mov ebx, [ioctl_ptr]
|
||||
mov edi, [ebx + IOCTL.output]
|
||||
mov [edi], ecx
|
||||
|
||||
; Хватает ли места в output для данных?
|
||||
mov eax, [ebx + IOCTL.out_size]
|
||||
sub eax, 4
|
||||
cmp eax, ecx
|
||||
jb .app_overflow
|
||||
|
||||
; Скопировать данные из kern_buf в output + 4
|
||||
push ecx
|
||||
mov esi, [kern_buf]
|
||||
add edi, 4
|
||||
cld
|
||||
rep movsb
|
||||
pop ecx
|
||||
|
||||
; Debug: вывести текст если это UNICODETEXT
|
||||
cmp dword [req_format], VBOX_SHCL_FMT_UNICODETEXT
|
||||
jne .read_ok
|
||||
cmp ecx, 4
|
||||
jb .read_ok
|
||||
stdcall clipboard_utf16_to_debug, [kern_buf], ecx
|
||||
|
||||
.read_ok:
|
||||
invoke KernelFree, [kern_buf]
|
||||
xor eax, eax ; success
|
||||
ret
|
||||
|
||||
.app_overflow:
|
||||
; Буфер приложения мал — actual_size записан, данных нет
|
||||
invoke KernelFree, [kern_buf]
|
||||
mov eax, 1 ; buffer overflow
|
||||
ret
|
||||
|
||||
.check_overflow:
|
||||
; HGCM вернул ошибку — если actual_size > kern_size, это overflow
|
||||
; Попробовать с большим буфером
|
||||
cmp ecx, [kern_size]
|
||||
jbe .hgcm_error ; не overflow, реальная ошибка
|
||||
|
||||
; actual_size > kern_size — нужен буфер побольше
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] CLIP_READ: overflow, need %d bytes\n", ecx
|
||||
|
||||
invoke KernelFree, [kern_buf]
|
||||
|
||||
; Выделить буфер нужного размера (round up to page)
|
||||
add ecx, (PAGE_SIZE - 1)
|
||||
and ecx, PAGE_BASE_MASK
|
||||
mov [kern_size], ecx
|
||||
invoke KernelAlloc, ecx
|
||||
test eax, eax
|
||||
jz .no_mem
|
||||
mov [kern_buf], eax
|
||||
|
||||
jmp .do_read ; retry
|
||||
|
||||
.hgcm_error:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] CLIP_READ: HGCM error 0x%x\n", eax
|
||||
; Записать actual_size если возможно
|
||||
mov ebx, [ioctl_ptr]
|
||||
cmp [ebx + IOCTL.out_size], 4
|
||||
jb .hgcm_err_ret
|
||||
mov edi, [ebx + IOCTL.output]
|
||||
mov [edi], ecx
|
||||
.hgcm_err_ret:
|
||||
invoke KernelFree, [kern_buf]
|
||||
or eax, -1
|
||||
ret
|
||||
|
||||
.no_mem:
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] CLIP_READ: KernelAlloc failed\n"
|
||||
or eax, -1
|
||||
ret
|
||||
|
||||
.fail:
|
||||
or eax, -1
|
||||
ret
|
||||
endp
|
||||
|
||||
; clip_ioctl_write — IOCTL 12: Записать данные в clipboard хоста
|
||||
proc clip_ioctl_write stdcall uses ebx ecx edx esi edi, ioctl_ptr:dword
|
||||
mov ebx, [ioctl_ptr]
|
||||
|
||||
cmp [ebx + IOCTL.inp_size], 8 ; минимум: dd format + хотя бы 4 байта данных
|
||||
jb .fail
|
||||
cmp dword [clip_state.connected], 0
|
||||
je .fail
|
||||
|
||||
; Прочитать format и data size
|
||||
mov esi, [ebx + IOCTL.input]
|
||||
mov ecx, [esi] ; format
|
||||
mov edx, [ebx + IOCTL.inp_size]
|
||||
sub edx, 4 ; data_size = inp_size - 4
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] CLIP_WRITE: %d bytes, fmt=0x%x\n", edx, ecx
|
||||
|
||||
; Освободить предыдущий буфер
|
||||
cmp dword [clip_guest_buf_ptr], 0
|
||||
je .no_old
|
||||
push ecx edx esi
|
||||
invoke KernelFree, [clip_guest_buf_ptr]
|
||||
mov dword [clip_guest_buf_ptr], 0
|
||||
pop esi edx ecx
|
||||
.no_old:
|
||||
|
||||
; Выделить новый буфер (round up to page, min 4096)
|
||||
push ecx edx esi
|
||||
mov eax, edx
|
||||
add eax, (PAGE_SIZE - 1)
|
||||
and eax, PAGE_BASE_MASK
|
||||
cmp eax, PAGE_SIZE
|
||||
jae .alloc_go
|
||||
mov eax, PAGE_SIZE
|
||||
.alloc_go:
|
||||
invoke KernelAlloc, eax
|
||||
test eax, eax
|
||||
jz .no_mem
|
||||
mov [clip_guest_buf_ptr], eax
|
||||
pop esi edx ecx
|
||||
|
||||
mov [clip_guest_buf_size], edx
|
||||
mov [clip_guest_buf_fmt], ecx
|
||||
|
||||
; Скопировать данные из input + 4 в ядерный буфер
|
||||
add esi, 4 ; skip format field
|
||||
mov edi, [clip_guest_buf_ptr]
|
||||
mov ecx, edx
|
||||
cld
|
||||
rep movsb
|
||||
|
||||
; Сообщить хосту что у гостя есть данные
|
||||
stdcall clipboard_report_formats, [clip_guest_buf_fmt]
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.no_mem:
|
||||
pop esi edx ecx
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] CLIP_WRITE: KernelAlloc failed\n"
|
||||
or eax, -1
|
||||
ret
|
||||
|
||||
.fail:
|
||||
or eax, -1
|
||||
ret
|
||||
endp
|
||||
|
||||
; clipboard_utf16_to_debug — Конвертировать UTF-16LE -> cp866 и вывести
|
||||
proc clipboard_utf16_to_debug stdcall uses ebx ecx edx esi edi, buf_ptr:dword, buf_size:dword
|
||||
|
||||
mov esi, [buf_ptr]
|
||||
mov edi, clip_ascii_buf
|
||||
mov ecx, [buf_size]
|
||||
shr ecx, 1 ; количество UTF-16 символов (size / 2)
|
||||
|
||||
; Ограничить до CLIP_DEBUG_MAX_CHARS - 1
|
||||
cmp ecx, CLIP_DEBUG_MAX_CHARS - 1
|
||||
jbe .len_ok
|
||||
mov ecx, CLIP_DEBUG_MAX_CHARS - 1
|
||||
.len_ok:
|
||||
|
||||
test ecx, ecx
|
||||
jz .done_empty
|
||||
|
||||
.loop:
|
||||
lodsw ; ax = UTF-16LE char (si += 2)
|
||||
|
||||
; Null terminator?
|
||||
test ax, ax
|
||||
jz .done
|
||||
|
||||
; --- ASCII range (< 0x80) ---
|
||||
cmp ax, 0x80
|
||||
jb .ascii
|
||||
|
||||
; --- Cyrillic: U+0410..U+044F → cp866 ---
|
||||
cmp ax, 0x0410
|
||||
jb .check_yo
|
||||
cmp ax, 0x0440
|
||||
jb .cyr_80 ; U+0410..U+043F → cp866 0x80..0xAF
|
||||
cmp ax, 0x0450
|
||||
jb .cyr_e0 ; U+0440..U+044F → cp866 0xE0..0xEF
|
||||
jmp .check_yo
|
||||
|
||||
.cyr_80:
|
||||
sub ax, 0x0410
|
||||
add al, 0x80
|
||||
jmp .store
|
||||
|
||||
.cyr_e0:
|
||||
sub ax, 0x0440
|
||||
add al, 0xE0
|
||||
jmp .store
|
||||
|
||||
.check_yo:
|
||||
cmp ax, 0x0401 ; Ё → cp866 0xF0
|
||||
je .yo_upper
|
||||
cmp ax, 0x0451 ; ё → cp866 0xF1
|
||||
je .yo_lower
|
||||
|
||||
; Unknown non-ASCII → '?'
|
||||
mov al, '?'
|
||||
jmp .store
|
||||
|
||||
.yo_upper:
|
||||
mov al, 0xF0
|
||||
jmp .store
|
||||
|
||||
.yo_lower:
|
||||
mov al, 0xF1
|
||||
jmp .store
|
||||
|
||||
.ascii:
|
||||
; Контрольные символы (< 0x20) кроме \n, \r, \t → пропускаем
|
||||
cmp al, 0x20
|
||||
jae .store
|
||||
cmp al, 0x0A
|
||||
je .store
|
||||
cmp al, 0x0D
|
||||
je .store
|
||||
cmp al, 0x09
|
||||
je .store
|
||||
jmp .skip
|
||||
|
||||
.store:
|
||||
stosb
|
||||
.skip:
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.done:
|
||||
xor al, al
|
||||
stosb
|
||||
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Text: '%s'\n", clip_ascii_buf
|
||||
ret
|
||||
|
||||
.done_empty:
|
||||
mov byte [clip_ascii_buf], 0
|
||||
DEBUGF __DEBUG_CB__, "[VBoxGuest] [Clipboard] Text: (empty)\n"
|
||||
ret
|
||||
endp
|
||||
206
drivers/vboxguest/services/display/display.inc
Normal file
206
drivers/vboxguest/services/display/display.inc
Normal file
@@ -0,0 +1,206 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Display Service (Auto-resize)
|
||||
; Назначение : Автоматическое изменение разрешения экрана при resize окна VBox
|
||||
; Файл : services/display/display.inc
|
||||
;
|
||||
; Логика задержки (паттерн heartbeat):
|
||||
; Event → запомнить время, поставить флаг pending
|
||||
; Tick → если pending и прошло 2 секунды → display_change
|
||||
; Каждое новое событие сбрасывает таймер (debounce)
|
||||
; =============================================================================
|
||||
|
||||
svc_display_name db "DISPLAY", 0
|
||||
|
||||
; --- Display Data ---
|
||||
align 4
|
||||
vbox_display_enabled dd 0
|
||||
kos_display_ptr dd 0
|
||||
|
||||
; Отложенное обновление (debounce)
|
||||
vbox_display_pending dd 0 ; 1 = есть отложенный запрос
|
||||
vbox_display_event_time dd 0 ; timer_ticks момента последнего события
|
||||
DISPLAY_DELAY_TICKS equ 50 ; 500ms (50 * 10ms)
|
||||
|
||||
; Статический буфер для запроса GetDisplayChangeRequest2
|
||||
align 4
|
||||
vmmdev_display_change_s VMMDEV_GET_DISPLAY_CHANGE_REQUEST2 \
|
||||
<sizeof.VMMDEV_GET_DISPLAY_CHANGE_REQUEST2, \
|
||||
VMMDEV_REQUEST_HEADER_VERSION, \
|
||||
VMMDEV_REQ_GET_DISPLAY_CHANGE_2, \
|
||||
0, 0, VMMDEV_REQUESTOR_KERNEL>, \
|
||||
0, 0, 0, 1, 0 ; x_res, y_res, bpp, event_ack=1, display=0
|
||||
|
||||
; --- BGA Macros ---
|
||||
|
||||
macro bga_write index_val, data_val {
|
||||
mov eax, index_val
|
||||
mov dx, VBE_DISPI_IOPORT_INDEX
|
||||
out dx, ax
|
||||
mov eax, data_val
|
||||
mov dx, VBE_DISPI_IOPORT_DATA
|
||||
out dx, ax
|
||||
}
|
||||
|
||||
macro bga_set_mode w, h, bpp {
|
||||
bga_write VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED
|
||||
bga_write VBE_DISPI_INDEX_XRES, w
|
||||
bga_write VBE_DISPI_INDEX_YRES, h
|
||||
bga_write VBE_DISPI_INDEX_BPP, bpp
|
||||
bga_write VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED or VBE_DISPI_LFB_ENABLED
|
||||
}
|
||||
|
||||
; vmmdev_display_init — Инициализация подсистемы дисплея
|
||||
proc vmmdev_display_init
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Initializing...\n"
|
||||
|
||||
; Получить указатель на DISPLAY структуру ядра KolibriOS
|
||||
invoke GetDisplay
|
||||
mov [kos_display_ptr], eax
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] KOS display struct: 0x%x\n", eax
|
||||
|
||||
; Получить физический адрес буфера запроса
|
||||
mov eax, vmmdev_display_change_s
|
||||
mov [vbox_device.display_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.display_phys], eax
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Buffer: virt=0x%x, phys=0x%x\n", \
|
||||
vmmdev_display_change_s, eax
|
||||
|
||||
mov dword [vbox_display_enabled], 1
|
||||
|
||||
; Сразу обработать текущее разрешение (без задержки)
|
||||
call display_change
|
||||
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Initialized OK\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; display_handle_event — Обработка события (из IRQ)
|
||||
proc display_handle_event
|
||||
test eax, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
|
||||
jz .done
|
||||
cmp dword [vbox_display_enabled], 0
|
||||
je .done
|
||||
|
||||
; Запомнить время события (сбросить таймер при повторных)
|
||||
invoke GetTimerTicks
|
||||
mov [vbox_display_event_time], eax
|
||||
|
||||
; Поставить флаг
|
||||
mov dword [vbox_display_pending], 1
|
||||
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Event queued, will apply in 2s\n"
|
||||
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; display_tick — Вызывается периодически из timer tick
|
||||
proc display_tick
|
||||
cmp dword [vbox_display_pending], 0
|
||||
je .done
|
||||
|
||||
invoke GetTimerTicks
|
||||
sub eax, [vbox_display_event_time]
|
||||
cmp eax, DISPLAY_DELAY_TICKS
|
||||
jb .done
|
||||
|
||||
; Сбросить флаг ДО обработки (новое событие во время display_change
|
||||
; не потеряется — оно поставит pending заново)
|
||||
mov dword [vbox_display_pending], 0
|
||||
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Delay elapsed, applying...\n"
|
||||
call display_change
|
||||
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; display_change — Запросить и применить новое разрешение
|
||||
proc display_change uses ebx ecx edx esi edi
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] display_change\n"
|
||||
|
||||
mov ebx, [vbox_device.display_virt]
|
||||
test ebx, ebx
|
||||
jz .skip
|
||||
|
||||
mov dword [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.header.rc], 0
|
||||
mov dword [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.event_ack], 1
|
||||
mov dword [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.display], 0
|
||||
|
||||
mov eax, [vbox_device.display_phys]
|
||||
stdcall vmmdev_send_request, eax
|
||||
|
||||
mov ebx, [vbox_device.display_virt]
|
||||
mov edi, [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.x_res]
|
||||
mov esi, [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.y_res]
|
||||
mov ecx, [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.bpp]
|
||||
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Requested: %dx%d %dbpp\n", edi, esi, ecx
|
||||
|
||||
; Валидация
|
||||
cmp edi, DISP_W_MIN
|
||||
jb .skip
|
||||
cmp esi, DISP_H_MIN
|
||||
jb .skip
|
||||
cmp edi, DISP_W_MAX
|
||||
ja .skip
|
||||
cmp esi, DISP_H_MAX
|
||||
ja .skip
|
||||
|
||||
cmp ecx, 32
|
||||
je .valid
|
||||
cmp ecx, 24
|
||||
je .valid
|
||||
cmp ecx, 16
|
||||
je .valid
|
||||
cmp ecx, 8
|
||||
jne .skip
|
||||
|
||||
.valid:
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Setting %dx%d %dbpp\n", edi, esi, ecx
|
||||
|
||||
; BGA под cli (как в v5)
|
||||
cli
|
||||
bga_set_mode edi, esi, ecx
|
||||
sti
|
||||
|
||||
; Обновить DISPLAY структуру ядра
|
||||
mov eax, [kos_display_ptr]
|
||||
mov [eax + DISPLAY.width], edi
|
||||
mov [eax + DISPLAY.height], esi
|
||||
mov [eax + DISPLAY.bits_per_pixel], ecx
|
||||
|
||||
; pitch = (bpp / 8) * width
|
||||
push ebx
|
||||
mov ebx, ecx
|
||||
shr ecx, 3
|
||||
imul ecx, edi
|
||||
mov [eax + DISPLAY.pitch], ecx
|
||||
pop ebx
|
||||
|
||||
; SetScreen(width-1, height-1)
|
||||
mov eax, edi
|
||||
mov edx, esi
|
||||
dec eax
|
||||
dec edx
|
||||
invoke SetScreen
|
||||
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Resolution set successfully\n"
|
||||
|
||||
.skip:
|
||||
ret
|
||||
endp
|
||||
|
||||
; display_disable — Отключить подсистему дисплея
|
||||
proc display_disable
|
||||
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Disabling...\n"
|
||||
mov dword [vbox_display_enabled], 0
|
||||
mov dword [vbox_display_pending], 0
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
REGISTER_SERVICE svc_display_name, DISPLAY_EVENT_MASK, VMMDEV_GUEST_SUPPORTS_GRAPHICS, \
|
||||
vmmdev_display_init, 0, display_disable, display_handle_event, display_tick, AUTOSTART_DISPLAY
|
||||
263
drivers/vboxguest/services/guest_props/guest_props.inc
Normal file
263
drivers/vboxguest/services/guest_props/guest_props.inc
Normal file
@@ -0,0 +1,263 @@
|
||||
; =============================================================================
|
||||
; Модуль : VBox Guest Properties Service
|
||||
; Назначение : Обмен ключ-значение свойствами между хостом и гостем
|
||||
; Файл : services/guest_props/guest_props.inc
|
||||
; Протокол : HGCM (VBoxGuestPropSvc)
|
||||
;
|
||||
; Функционал:
|
||||
; - Подключение к HGCM сервису VBoxGuestPropSvc
|
||||
; - Установка начальных свойств гостевой ОС
|
||||
; - GET_PROP / SET_PROP_VALUE / DEL_PROP / ENUM_PROPS
|
||||
;
|
||||
; Стандартные свойства (устанавливаются при инициализации):
|
||||
; /VirtualBox/GuestInfo/OS/Product = "KolibriOS"
|
||||
; /VirtualBox/GuestInfo/OS/Release = "1.0"
|
||||
; /VirtualBox/GuestAdd/VersionExt = "1.0.0"
|
||||
; /VirtualBox/GuestAdd/Revision = "1"
|
||||
;
|
||||
; Аналог в Linux: VBoxService --property
|
||||
; =============================================================================
|
||||
|
||||
svc_guestprop_name db "GUEST_PROPS", 0
|
||||
|
||||
; HGCM service name on host
|
||||
align 4
|
||||
sz_guestprop_hgcm_service db 'VBoxGuestPropSvc', 0
|
||||
|
||||
; --- Guest Properties Data ---
|
||||
align 4
|
||||
gp_state GUEST_PROP_STATE
|
||||
|
||||
; Буферы выделяются динамически в guestprop_init, указатели в gp_state
|
||||
|
||||
; --- Строки стандартных свойств ---
|
||||
align 4
|
||||
gp_key_os_product db '/VirtualBox/GuestInfo/OS/Product', 0
|
||||
gp_val_os_product db 'KolibriOS', 0
|
||||
|
||||
gp_key_os_release db '/VirtualBox/GuestInfo/OS/Release', 0
|
||||
gp_val_os_release db '1.0', 0
|
||||
|
||||
gp_key_version db '/VirtualBox/GuestAdd/VersionExt', 0
|
||||
gp_val_version db '1.0.0', 0
|
||||
|
||||
gp_key_revision db '/VirtualBox/GuestAdd/Revision', 0
|
||||
gp_val_revision db '1', 0
|
||||
|
||||
; guestprop_init — Инициализация сервиса Guest Properties
|
||||
proc guestprop_init uses ebx ecx edx esi edi
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Initializing...\n"
|
||||
|
||||
; Проверка что HGCM готов
|
||||
mov eax, [vbox_device.hgcm_connect_virt]
|
||||
test eax, eax
|
||||
jz .hgcm_not_ready
|
||||
|
||||
; Уже подключены?
|
||||
cmp dword [gp_state.connected], 1
|
||||
je .already_connected
|
||||
|
||||
; --- Выделить буферы ---
|
||||
invoke KernelAlloc, 4096 ; gp_enum_buf (page-aligned для HGCM)
|
||||
test eax, eax
|
||||
jz .alloc_fail
|
||||
mov [gp_state.enum_buf_ptr], eax
|
||||
|
||||
invoke KernelAlloc, 4096 ; small_bufs: parms+name+value+flags
|
||||
test eax, eax
|
||||
jz .alloc_fail_free1
|
||||
mov [gp_state.small_bufs_ptr], eax
|
||||
|
||||
; Вычислить указатели внутри small_bufs
|
||||
lea ecx, [eax + 0]
|
||||
mov [gp_state.parms_ptr], ecx ; +0: 48 байт (sizeof.HGCM_PARM * 4)
|
||||
lea ecx, [eax + 48]
|
||||
mov [gp_state.name_buf_ptr], ecx ; +48: 256 байт
|
||||
lea ecx, [eax + 304]
|
||||
mov [gp_state.value_buf_ptr], ecx ; +304: 1024 байт
|
||||
lea ecx, [eax + 1328]
|
||||
mov [gp_state.flags_buf_ptr], ecx ; +1328: 128 байт
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Buffers allocated\n"
|
||||
|
||||
; Подключиться к HGCM сервису
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Connecting to '%s'...\n", sz_guestprop_hgcm_service
|
||||
stdcall hgcm_connect, sz_guestprop_hgcm_service
|
||||
test eax, eax
|
||||
jz .connect_failed
|
||||
|
||||
mov [gp_state.client_id], eax
|
||||
mov dword [gp_state.connected], 1
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Connected, client_id=%d\n", eax
|
||||
|
||||
; Установить начальные свойства
|
||||
call guestprop_set_initial_props
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Initialized OK\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.connect_failed:
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] HGCM connect failed\n"
|
||||
call guestprop_free_bufs
|
||||
mov eax, VERR_HGCM_SERVICE_NOT_FOUND
|
||||
ret
|
||||
|
||||
.alloc_fail_free1:
|
||||
invoke KernelFree, [gp_state.enum_buf_ptr]
|
||||
mov dword [gp_state.enum_buf_ptr], 0
|
||||
.alloc_fail:
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] KernelAlloc failed\n"
|
||||
mov eax, VERR_NO_MEMORY
|
||||
ret
|
||||
|
||||
.hgcm_not_ready:
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] HGCM not ready\n"
|
||||
mov eax, VERR_NOT_READY
|
||||
ret
|
||||
|
||||
.already_connected:
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Already connected\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; guestprop_set_initial_props — Установить стандартные свойства ОС
|
||||
proc guestprop_set_initial_props uses eax
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Setting initial properties...\n"
|
||||
|
||||
stdcall guestprop_set, gp_key_os_product, gp_val_os_product
|
||||
stdcall guestprop_set, gp_key_os_release, gp_val_os_release
|
||||
stdcall guestprop_set, gp_key_version, gp_val_version
|
||||
stdcall guestprop_set, gp_key_revision, gp_val_revision
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Initial properties set\n"
|
||||
ret
|
||||
endp
|
||||
|
||||
; guestprop_set — Установить свойство (SET_PROP_VALUE, fn=4)
|
||||
proc guestprop_set stdcall uses ebx ecx edx esi edi, name_ptr:dword, value_ptr:dword
|
||||
cmp dword [gp_state.connected], 0
|
||||
je .not_connected
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] SET '%s' = '%s'\n", [name_ptr], [value_ptr]
|
||||
|
||||
mov edi, [gp_state.parms_ptr]
|
||||
|
||||
; parm[0] = name (linaddr IN)
|
||||
stdcall hgcm_strlen, [name_ptr]
|
||||
inc eax ; +null
|
||||
stdcall hgcm_param_linaddr_in, edi, [name_ptr], eax
|
||||
add edi, sizeof.HGCM_PARM
|
||||
|
||||
; parm[1] = value (linaddr IN)
|
||||
stdcall hgcm_strlen, [value_ptr]
|
||||
inc eax ; +null
|
||||
stdcall hgcm_param_linaddr_in, edi, [value_ptr], eax
|
||||
|
||||
; Вызвать HGCM
|
||||
stdcall hgcm_call32_pagelist, [gp_state.client_id], GUEST_PROP_FN_SET_PROP_VALUE, [gp_state.parms_ptr], GUEST_PROP_SET_VALUE_PARM_COUNT
|
||||
test eax, eax
|
||||
jnz .failed
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] SET OK\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.not_connected:
|
||||
mov eax, VERR_NOT_READY
|
||||
ret
|
||||
.failed:
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] SET failed: 0x%x\n", eax
|
||||
ret
|
||||
|
||||
; strlen(esi) → eax
|
||||
endp
|
||||
|
||||
; guestprop_set_with_flags — Установить свойство с флагами (SET_PROP, fn=2)
|
||||
proc guestprop_set_with_flags stdcall uses ebx ecx edx esi edi, name_ptr:dword, value_ptr:dword, flags_ptr:dword
|
||||
cmp dword [gp_state.connected], 0
|
||||
je .not_connected
|
||||
|
||||
mov edi, [gp_state.parms_ptr]
|
||||
|
||||
; parm[0] = name
|
||||
stdcall hgcm_strlen, [name_ptr]
|
||||
inc eax
|
||||
stdcall hgcm_param_linaddr_in, edi, [name_ptr], eax
|
||||
add edi, sizeof.HGCM_PARM
|
||||
|
||||
; parm[1] = value
|
||||
stdcall hgcm_strlen, [value_ptr]
|
||||
inc eax
|
||||
stdcall hgcm_param_linaddr_in, edi, [value_ptr], eax
|
||||
add edi, sizeof.HGCM_PARM
|
||||
|
||||
; parm[2] = flags
|
||||
stdcall hgcm_strlen, [flags_ptr]
|
||||
inc eax
|
||||
stdcall hgcm_param_linaddr_in, edi, [flags_ptr], eax
|
||||
|
||||
stdcall hgcm_call32_pagelist, [gp_state.client_id], GUEST_PROP_FN_SET_PROP, [gp_state.parms_ptr], GUEST_PROP_SET_PARM_COUNT
|
||||
ret
|
||||
|
||||
.not_connected:
|
||||
mov eax, VERR_NOT_READY
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
proc hgcm_strlen uses esi, str_ptr:dword
|
||||
mov esi, [str_ptr]
|
||||
xor eax, eax
|
||||
@@: cmp byte [esi], 0
|
||||
je @f
|
||||
inc esi
|
||||
inc eax
|
||||
jmp @b
|
||||
@@: ret
|
||||
endp
|
||||
|
||||
; guestprop_disable — Отключение сервиса
|
||||
proc guestprop_disable uses edi
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Disabling...\n"
|
||||
|
||||
cmp dword [gp_state.connected], 0
|
||||
je .done
|
||||
|
||||
stdcall hgcm_disconnect, [gp_state.client_id]
|
||||
|
||||
mov dword [gp_state.connected], 0
|
||||
mov dword [gp_state.client_id], 0
|
||||
|
||||
; Освободить буферы
|
||||
call guestprop_free_bufs
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [GuestProp] Disabled\n"
|
||||
.done:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; guestprop_free_bufs — Освободить буферы Guest Properties
|
||||
proc guestprop_free_bufs
|
||||
cmp dword [gp_state.enum_buf_ptr], 0
|
||||
je @f
|
||||
invoke KernelFree, [gp_state.enum_buf_ptr]
|
||||
mov dword [gp_state.enum_buf_ptr], 0
|
||||
@@:
|
||||
cmp dword [gp_state.small_bufs_ptr], 0
|
||||
je @f
|
||||
invoke KernelFree, [gp_state.small_bufs_ptr]
|
||||
mov dword [gp_state.small_bufs_ptr], 0
|
||||
; Обнулить указатели-потомки
|
||||
mov dword [gp_state.parms_ptr], 0
|
||||
mov dword [gp_state.name_buf_ptr], 0
|
||||
mov dword [gp_state.value_buf_ptr], 0
|
||||
mov dword [gp_state.flags_buf_ptr], 0
|
||||
@@:
|
||||
ret
|
||||
endp
|
||||
|
||||
REGISTER_SERVICE svc_guestprop_name, GUEST_PROP_EVENT_MASK, GUEST_PROP_CAPS_MASK, \
|
||||
guestprop_init, 0, guestprop_disable, 0, 0, AUTOSTART_GUEST_PROPS
|
||||
243
drivers/vboxguest/services/heartbeat/heartbeat.inc
Normal file
243
drivers/vboxguest/services/heartbeat/heartbeat.inc
Normal file
@@ -0,0 +1,243 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Heartbeat Service
|
||||
; Назначение : Периодическая отправка heartbeat сигналов хосту для мониторинга
|
||||
; Файл : vmmdev/heartbeat.inc
|
||||
; Протокол : Прямые VMMDev запросы (БЕЗ HGCM)
|
||||
; =============================================================================
|
||||
|
||||
svc_heartbeat_name db "HEARTBEAT", 0
|
||||
|
||||
; --- Heartbeat Data ---
|
||||
align 4
|
||||
|
||||
vbox_hb_last_send_time dd 0 ; timer_ticks последней отправки
|
||||
vbox_hb_tick_interval dd 100
|
||||
vbox_hb_enabled dd 0
|
||||
|
||||
; Статические буферы для запросов
|
||||
align 4
|
||||
vmmdev_heartbeat_configure_s VMMDEV_HEARTBEAT_CONFIGURE \
|
||||
<sizeof.VMMDEV_HEARTBEAT_CONFIGURE, \
|
||||
VMMDEV_REQUEST_HEADER_VERSION, \
|
||||
VMMDEV_REQ_HEARTBEAT_CONFIGURE, \
|
||||
0, 0, 0>, \
|
||||
0, 0, 0; интервал и enabled заполняются при вызове
|
||||
|
||||
align 4
|
||||
vmmdev_heartbeat_s VMMDEV_GUEST_HEARTBEAT \
|
||||
<sizeof.VMMDEV_GUEST_HEARTBEAT, \
|
||||
VMMDEV_REQUEST_HEADER_VERSION, \
|
||||
VMMDEV_REQ_GUEST_HEARTBEAT, \
|
||||
0, 0, 0>
|
||||
|
||||
; vmmdev_heartbeat_init — Инициализация heartbeat подсистемы
|
||||
proc vmmdev_heartbeat_init
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Initializing...\n"
|
||||
|
||||
; Получить физические адреса буферов
|
||||
mov eax, vmmdev_heartbeat_configure_s
|
||||
mov [vbox_device.heartbeat_config_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.heartbeat_config_phys], eax
|
||||
DEBUGF __DEBUG_HB__, "[VBoxGuest] [Heartbeat] Config packet: virt=0x%x, phys=0x%x\n", \
|
||||
vmmdev_heartbeat_configure_s, eax
|
||||
|
||||
mov eax, vmmdev_heartbeat_s
|
||||
mov [vbox_device.heartbeat_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.heartbeat_phys], eax
|
||||
DEBUGF __DEBUG_HB__, "[VBoxGuest] [Heartbeat] Send packet : virt=0x%x, phys=0x%x\n", \
|
||||
vmmdev_heartbeat_s, eax
|
||||
|
||||
; Запросить конфигурацию у хоста
|
||||
call vmmdev_heartbeat_configure
|
||||
test eax, eax
|
||||
jnz .failed
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Initialized successfully\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.failed:
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Initialization failed: rc=0x%x\n", eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; vmmdev_heartbeat_configure — Запросить настройки heartbeat у хоста и включить мониторинг
|
||||
proc vmmdev_heartbeat_configure uses ebx edi
|
||||
DEBUGF __DEBUG_HB__, "[VBoxGuest] [Heartbeat] Configuring...\n"
|
||||
|
||||
mov edi, [vbox_device.heartbeat_config_virt]
|
||||
test edi, edi
|
||||
jz .bad_ptr
|
||||
|
||||
; Заполнить запрос (header уже инициализирован статически)
|
||||
; Обнулить rc перед отправкой
|
||||
mov dword [edi + VMMDEV_HEARTBEAT_CONFIGURE.header.rc], 0
|
||||
|
||||
; Запросить у хоста интервал (0 = использовать дефолтный)
|
||||
mov dword [edi + VMMDEV_HEARTBEAT_CONFIGURE.c_ns_interval], 0
|
||||
mov dword [edi + VMMDEV_HEARTBEAT_CONFIGURE.c_ns_interval_high], 0
|
||||
|
||||
; Включить heartbeat
|
||||
mov dword [edi + VMMDEV_HEARTBEAT_CONFIGURE.f_enabled], 1
|
||||
|
||||
; Отправить запрос
|
||||
mov ebx, [vbox_device.heartbeat_config_phys]
|
||||
stdcall vmmdev_send_request, ebx
|
||||
|
||||
; Проверить результат
|
||||
mov eax, [edi + VMMDEV_HEARTBEAT_CONFIGURE.header.rc]
|
||||
test eax, eax
|
||||
js .error
|
||||
|
||||
; Получить интервал от хоста (если вернул)
|
||||
mov eax, [edi + VMMDEV_HEARTBEAT_CONFIGURE.c_ns_interval]
|
||||
mov edx, [edi + VMMDEV_HEARTBEAT_CONFIGURE.c_ns_interval_high]
|
||||
|
||||
; Конвертировать наносекунды в тики
|
||||
; Предположим timer tick = 10ms = 10,000,000 ns
|
||||
; Делим ns на 10,000,000 чтобы получить тики
|
||||
test eax, eax
|
||||
jz .use_default
|
||||
test edx, edx
|
||||
jnz .use_default ; Если интервал > 4.2 секунды, используем дефолт
|
||||
|
||||
; eax = наносекунды, конвертируем в тики (10ms)
|
||||
; ticks = ns / 10,000,000
|
||||
; правильное деление: 10,000,000 / 10,000 = 1000 (тики в 10ms)
|
||||
mov ebx, 10000
|
||||
xor edx, edx
|
||||
div ebx ; eax = eax / 10000 (микросекунды)
|
||||
mov ebx, 1000
|
||||
xor edx, edx
|
||||
div ebx ; eax = eax / 1000 (тики 10ms)
|
||||
test eax, eax
|
||||
jz .use_default
|
||||
|
||||
mov [vbox_hb_tick_interval], eax
|
||||
DEBUGF __DEBUG_HB__, "[VBoxGuest] [Heartbeat] Interval set to %d ticks\n", eax
|
||||
jmp .enabled
|
||||
|
||||
.use_default:
|
||||
DEBUGF __DEBUG_HB__, "[VBoxGuest] [Heartbeat] Using default interval: %d ticks\n", \
|
||||
[vbox_hb_tick_interval]
|
||||
|
||||
.enabled:
|
||||
; Включить heartbeat
|
||||
mov dword [vbox_hb_enabled], 1
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Enabled\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Configure failed: rc=0x%x\n", eax
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Configure: bad pointer\n"
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
endp
|
||||
|
||||
; vmmdev_heartbeat_send — Отправить heartbeat хосту
|
||||
proc vmmdev_heartbeat_send uses ebx edi
|
||||
mov edi, [vbox_device.heartbeat_virt]
|
||||
mov ebx, [vbox_device.heartbeat_phys]
|
||||
test edi, edi
|
||||
jz .bad_ptr
|
||||
test ebx, ebx
|
||||
jz .bad_ptr
|
||||
|
||||
; Обнулить rc перед отправкой
|
||||
mov dword [edi + VMMDEV_GUEST_HEARTBEAT.header.rc], 0
|
||||
|
||||
; DEBUGF __DEBUG_HB__, "[VBoxGuest] [Heartbeat] Sending...\n"
|
||||
|
||||
; Отправить запрос
|
||||
stdcall vmmdev_send_request, ebx
|
||||
|
||||
; Проверить результат
|
||||
mov eax, [edi + VMMDEV_GUEST_HEARTBEAT.header.rc]
|
||||
test eax, eax
|
||||
js .error
|
||||
|
||||
; DEBUGF __DEBUG_HB__, "[VBoxGuest] [Heartbeat] Sent successfully\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Send failed: rc=0x%x\n", eax
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Send: bad pointer virt=0x%x phys=0x%x\n", edi, ebx
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
endp
|
||||
|
||||
proc vmmdev_heartbeat_tick
|
||||
cmp dword [vbox_hb_enabled], 0
|
||||
je .done
|
||||
|
||||
invoke GetTimerTicks ; eax = timer_ticks
|
||||
sub eax, [vbox_hb_last_send_time]
|
||||
cmp eax, [vbox_hb_tick_interval]
|
||||
jb .done
|
||||
|
||||
invoke GetTimerTicks ; eax = текущее время для обновления last_send_time
|
||||
mov [vbox_hb_last_send_time], eax
|
||||
|
||||
call vmmdev_heartbeat_send
|
||||
test eax, eax
|
||||
jz .done
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Tick: send error 0x%x\n", eax
|
||||
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; vmmdev_heartbeat_disable — Отключить heartbeat (при выгрузке драйвера)
|
||||
proc vmmdev_heartbeat_disable uses ebx edi
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Disabling...\n"
|
||||
|
||||
; Выключить локальный флаг
|
||||
mov dword [vbox_hb_enabled], 0
|
||||
|
||||
mov edi, [vbox_device.heartbeat_config_virt]
|
||||
test edi, edi
|
||||
jz .bad_ptr
|
||||
|
||||
; Обнулить rc
|
||||
mov dword [edi + VMMDEV_HEARTBEAT_CONFIGURE.header.rc], 0
|
||||
|
||||
; Отключить на хосте
|
||||
mov dword [edi + VMMDEV_HEARTBEAT_CONFIGURE.f_enabled], 0
|
||||
mov dword [edi + VMMDEV_HEARTBEAT_CONFIGURE.c_ns_interval], 0
|
||||
mov dword [edi + VMMDEV_HEARTBEAT_CONFIGURE.c_ns_interval_high], 0
|
||||
|
||||
; Отправить запрос
|
||||
mov ebx, [vbox_device.heartbeat_config_phys]
|
||||
stdcall vmmdev_send_request, ebx
|
||||
|
||||
mov eax, [edi + VMMDEV_HEARTBEAT_CONFIGURE.header.rc]
|
||||
test eax, eax
|
||||
js .error
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Disabled\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [Heartbeat] Disable failed: rc=0x%x\n", eax
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
endp
|
||||
|
||||
REGISTER_SERVICE svc_heartbeat_name, 0, 0, \
|
||||
vmmdev_heartbeat_init, 0, vmmdev_heartbeat_disable, 0, vmmdev_heartbeat_tick, AUTOSTART_HEARTBEAT
|
||||
382
drivers/vboxguest/services/mouse/mouse.inc
Normal file
382
drivers/vboxguest/services/mouse/mouse.inc
Normal file
@@ -0,0 +1,382 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Mouse Service (Absolute Pointer)
|
||||
; Назначение : Поддержка абсолютных координат мыши VirtualBox
|
||||
; Файл : services/mouse/mouse.inc
|
||||
;
|
||||
; Использует расширенный протокол GetMouseStatusEx (type=223) если хост
|
||||
; поддерживает FULL_STATE_PROTOCOL — кнопки и скролл приходят от VMMDev.
|
||||
; Если хост не поддерживает — fallback на стандартный протокол + PS/2.
|
||||
; =============================================================================
|
||||
|
||||
svc_mouse_name db "MOUSE", 0
|
||||
|
||||
; --- Mouse Data ---
|
||||
align 4
|
||||
vbox_mouse_enabled dd 0
|
||||
vbox_mouse_x dd 0
|
||||
vbox_mouse_y dd 0
|
||||
vbox_mouse_buttons dd 0
|
||||
vbox_mouse_dz dd 0 ; vertical scroll delta
|
||||
vbox_mouse_dw dd 0 ; horizontal scroll delta
|
||||
vbox_mouse_host_features dd 0
|
||||
vbox_mouse_use_ext dd 0 ; 1 = extended protocol (buttons+scroll from VMMDev)
|
||||
|
||||
; Статический буфер для запроса (48 байт: 36 standard + 12 extended fields)
|
||||
align 4
|
||||
vmmdev_mouse_status_s VMMDEV_REQ_MOUSE_STATUS \
|
||||
<sizeof.VMMDEV_REQ_MOUSE_STATUS, \
|
||||
VMMDEV_REQUEST_HEADER_VERSION, \
|
||||
VMMDEV_REQ_SET_MOUSE_STATUS, \
|
||||
0, 0, VMMDEV_REQUESTOR_KERNEL>, \
|
||||
VBOX_MOUSE_GUEST_FEATURES, 0, 0
|
||||
; Extended fields (immediately after VMMDEV_REQ_MOUSE_STATUS in memory)
|
||||
; VMMDev заполнит их при GET_MOUSE_STATUS_EX (type=223)
|
||||
vmmdev_mouse_ext_dz dd 0 ; offset +36: vertical scroll
|
||||
vmmdev_mouse_ext_dw dd 0 ; offset +40: horizontal scroll
|
||||
vmmdev_mouse_ext_buttons dd 0 ; offset +44: button state
|
||||
|
||||
SIZEOF_MOUSE_STATUS_EX = sizeof.VMMDEV_REQ_MOUSE_STATUS + 12
|
||||
MOUSE_EXT_OFS_DZ = sizeof.VMMDEV_REQ_MOUSE_STATUS
|
||||
MOUSE_EXT_OFS_DW = sizeof.VMMDEV_REQ_MOUSE_STATUS + 4
|
||||
MOUSE_EXT_OFS_BUTTONS = sizeof.VMMDEV_REQ_MOUSE_STATUS + 8
|
||||
|
||||
; vmmdev_mouse_init — Инициализация подсистемы мыши
|
||||
proc vmmdev_mouse_init
|
||||
; Guard against double initialization (fn_init = fn_enable in REGISTER_SERVICE)
|
||||
cmp dword [vbox_mouse_enabled], 1
|
||||
je .already_initialized
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Initializing...\n"
|
||||
|
||||
; Получить физический адрес буфера
|
||||
mov eax, vmmdev_mouse_status_s
|
||||
mov [vbox_device.mouse_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.mouse_phys], eax
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Buffer: virt=0x%x, phys=0x%x, ext_size=%d\n", \
|
||||
vmmdev_mouse_status_s, eax, SIZEOF_MOUSE_STATUS_EX
|
||||
|
||||
; Запросить текущий статус (стандартный GET, т.к. use_ext=0)
|
||||
call mouse_query_status
|
||||
test eax, eax
|
||||
jnz .failed
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Host features: 0x%x\n", [vbox_mouse_host_features]
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Host position: X=%d, Y=%d\n", [vbox_mouse_x], [vbox_mouse_y]
|
||||
|
||||
; Проверить поддержку расширенного протокола
|
||||
test dword [vbox_mouse_host_features], VMMDEV_MOUSE_HOST_SUPPORTS_FULL_STATE_PROTOCOL
|
||||
jz .no_ext
|
||||
|
||||
; === Расширенный протокол ===
|
||||
mov dword [vbox_mouse_use_ext], 1
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Host supports FULL_STATE_PROTOCOL — using extended mode\n"
|
||||
|
||||
call mouse_send_status
|
||||
test eax, eax
|
||||
jnz .failed
|
||||
|
||||
; Отключить PS/2 IRQ12 — VMMDev сам сообщает кнопки+скролл.
|
||||
; Если PS/2 остаётся активным, SetMouseData(buttons=0) от VMMDev
|
||||
; сбрасывает нажатые кнопки из PS/2 на каждом движении (glitch при drag).
|
||||
stdcall i8042_mouse_control, 0
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] PS/2 IRQ12 disabled (buttons from VMMDev)\n"
|
||||
|
||||
jmp .ok
|
||||
|
||||
.no_ext:
|
||||
; === Стандартный протокол (fallback) ===
|
||||
mov dword [vbox_mouse_use_ext], 0
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] WARNING: Host does NOT support FULL_STATE_PROTOCOL\n"
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Fallback: standard protocol, PS/2 stays enabled for buttons\n"
|
||||
|
||||
call mouse_send_status
|
||||
test eax, eax
|
||||
jnz .failed
|
||||
|
||||
.ok:
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Initialized OK (ext=%d)\n", [vbox_mouse_use_ext]
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.already_initialized:
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Already initialized (skip reinit)\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.failed:
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Init failed: 0x%x\n", eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; mouse_query_status — Запросить статус у хоста
|
||||
proc mouse_query_status
|
||||
push ebx edi
|
||||
|
||||
mov edi, [vbox_device.mouse_virt]
|
||||
test edi, edi
|
||||
jz .bad_ptr
|
||||
|
||||
; Очистить rc
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.rc], 0
|
||||
|
||||
; Выбрать тип запроса
|
||||
cmp dword [vbox_mouse_use_ext], 0
|
||||
je .setup_standard
|
||||
|
||||
; === Extended GET (type=223, size=48) ===
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.size], SIZEOF_MOUSE_STATUS_EX
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.request_type], VMMDEV_REQ_GET_MOUSE_STATUS_EX
|
||||
jmp .send
|
||||
|
||||
.setup_standard:
|
||||
; === Standard GET (type=1, size=36) ===
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.size], sizeof.VMMDEV_REQ_MOUSE_STATUS
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.request_type], VMMDEV_REQ_GET_MOUSE_STATUS
|
||||
|
||||
.send:
|
||||
mov ebx, [vbox_device.mouse_phys]
|
||||
stdcall vmmdev_send_request, ebx
|
||||
|
||||
mov eax, [edi + VMMDEV_REQ_MOUSE_STATUS.header.rc]
|
||||
test eax, eax
|
||||
js .error
|
||||
|
||||
; === Сохранить общие данные ===
|
||||
mov eax, [edi + VMMDEV_REQ_MOUSE_STATUS.mouse_features]
|
||||
mov [vbox_mouse_host_features], eax
|
||||
|
||||
mov eax, [edi + VMMDEV_REQ_MOUSE_STATUS.pointer_x_pos]
|
||||
mov [vbox_mouse_x], eax
|
||||
|
||||
mov eax, [edi + VMMDEV_REQ_MOUSE_STATUS.pointer_y_pos]
|
||||
mov [vbox_mouse_y], eax
|
||||
|
||||
; === Если extended — сохранить кнопки и скролл ===
|
||||
cmp dword [vbox_mouse_use_ext], 0
|
||||
je .no_ext
|
||||
|
||||
mov eax, [edi + MOUSE_EXT_OFS_BUTTONS]
|
||||
and eax, 0x1F ; биты 0-4: left, right, middle, X1, X2
|
||||
mov [vbox_mouse_buttons], eax
|
||||
|
||||
mov eax, [edi + MOUSE_EXT_OFS_DZ]
|
||||
mov [vbox_mouse_dz], eax
|
||||
|
||||
mov eax, [edi + MOUSE_EXT_OFS_DW]
|
||||
mov [vbox_mouse_dw], eax
|
||||
|
||||
.no_ext:
|
||||
DEBUGF __DEBUG_MOUSE__, "[VBoxGuest] [Mouse] VMMDev: feat=0x%x, X=%d, Y=%d, btn=0x%x, dz=%d\n", \
|
||||
[vbox_mouse_host_features], [vbox_mouse_x], [vbox_mouse_y], \
|
||||
[vbox_mouse_buttons], [vbox_mouse_dz]
|
||||
|
||||
; Восстановить header для SET запросов
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.size], sizeof.VMMDEV_REQ_MOUSE_STATUS
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.request_type], VMMDEV_REQ_SET_MOUSE_STATUS
|
||||
|
||||
xor eax, eax
|
||||
pop edi ebx
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Query failed: rc=0x%x\n", eax
|
||||
; Восстановить header даже при ошибке
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.size], sizeof.VMMDEV_REQ_MOUSE_STATUS
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.request_type], VMMDEV_REQ_SET_MOUSE_STATUS
|
||||
pop edi ebx
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
pop edi ebx
|
||||
ret
|
||||
endp
|
||||
|
||||
; mouse_send_status — Отправить guest capabilities хосту
|
||||
proc mouse_send_status
|
||||
push ebx edi
|
||||
|
||||
mov edi, [vbox_device.mouse_virt]
|
||||
mov ebx, [vbox_device.mouse_phys]
|
||||
test edi, edi
|
||||
jz .bad_ptr
|
||||
test ebx, ebx
|
||||
jz .bad_ptr
|
||||
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.rc], 0
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.pointer_x_pos], 0
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.pointer_y_pos], 0
|
||||
|
||||
; Выбрать guest features
|
||||
cmp dword [vbox_mouse_use_ext], 0
|
||||
je .std_feats
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.mouse_features], VBOX_MOUSE_GUEST_FEATURES_EXT
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Sending guest features: 0x%x (extended)\n", VBOX_MOUSE_GUEST_FEATURES_EXT
|
||||
jmp .send
|
||||
.std_feats:
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.mouse_features], VBOX_MOUSE_GUEST_FEATURES
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Sending guest features: 0x%x (standard)\n", VBOX_MOUSE_GUEST_FEATURES
|
||||
.send:
|
||||
stdcall vmmdev_send_request, ebx
|
||||
|
||||
mov eax, [edi + VMMDEV_REQ_MOUSE_STATUS.header.rc]
|
||||
test eax, eax
|
||||
js .error
|
||||
|
||||
mov dword [vbox_mouse_enabled], 1
|
||||
xor eax, eax
|
||||
pop edi ebx
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Send status failed: 0x%x\n", eax
|
||||
pop edi ebx
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
pop edi ebx
|
||||
ret
|
||||
endp
|
||||
|
||||
; mouse_handle_event — Обработка событий мыши (вызывается из IRQ)
|
||||
proc mouse_handle_event
|
||||
push eax
|
||||
|
||||
DEBUGF __DEBUG_MOUSE__, "[VBoxGuest] [Mouse] Event: mask=0x%x\n", eax
|
||||
|
||||
; Любое из двух событий — нужен свежий статус
|
||||
call mouse_query_status
|
||||
test eax, eax
|
||||
jnz .query_fail
|
||||
|
||||
pop eax
|
||||
push eax
|
||||
|
||||
; Для position changed — обновить координаты в системе
|
||||
test eax, VMMDEV_EVENT_MOUSE_POSITION_CHANGED
|
||||
jz .done
|
||||
|
||||
call mouse_update_system_position
|
||||
jmp .done
|
||||
|
||||
.query_fail:
|
||||
DEBUGF __DEBUG_MOUSE__, "[VBoxGuest] [Mouse] Query failed in event handler: 0x%x\n", eax
|
||||
|
||||
.done:
|
||||
pop eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; mouse_update_system_position — Отправить позицию + кнопки + скролл в KolibriOS
|
||||
proc mouse_update_system_position
|
||||
push eax ebx ecx edx
|
||||
|
||||
; VirtualBox: 0-65535, KolibriOS: 0-32767
|
||||
mov ecx, [vbox_mouse_x]
|
||||
shr ecx, 1 ; X / 2
|
||||
|
||||
mov edx, [vbox_mouse_y]
|
||||
shr edx, 1 ; Y / 2
|
||||
|
||||
; Флаги: bit31=X_abs, bit30=Y_abs + кнопки (bits 0-4)
|
||||
mov eax, 0xC0000000
|
||||
or eax, [vbox_mouse_buttons]
|
||||
|
||||
DEBUGF __DEBUG_MOUSE__, "[VBoxGuest] [Mouse] SetMouseData: flags=0x%x, X=%d, Y=%d, btn=0x%x, dz=%d, dw=%d\n", \
|
||||
eax, ecx, edx, [vbox_mouse_buttons], [vbox_mouse_dz], [vbox_mouse_dw]
|
||||
|
||||
invoke SetMouseData, eax, ecx, edx, [vbox_mouse_dz], [vbox_mouse_dw]
|
||||
|
||||
; Сбросить дельты скролла (это дельты, не состояние)
|
||||
mov dword [vbox_mouse_dz], 0
|
||||
mov dword [vbox_mouse_dw], 0
|
||||
|
||||
pop edx ecx ebx eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; mouse_disable — Отключить мышь
|
||||
proc mouse_disable
|
||||
push ebx edi
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Mouse] Disabling...\n"
|
||||
|
||||
mov dword [vbox_mouse_enabled], 0
|
||||
|
||||
mov edi, [vbox_device.mouse_virt]
|
||||
test edi, edi
|
||||
jz .done
|
||||
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.header.rc], 0
|
||||
mov dword [edi + VMMDEV_REQ_MOUSE_STATUS.mouse_features], 0
|
||||
|
||||
mov ebx, [vbox_device.mouse_phys]
|
||||
stdcall vmmdev_send_request, ebx
|
||||
|
||||
; Восстановить PS/2 при выключении
|
||||
stdcall i8042_mouse_control, 1
|
||||
|
||||
.done:
|
||||
xor eax, eax
|
||||
pop edi ebx
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
; i8042_mouse_control — Включить/выключить IRQ12 PS/2 мыши
|
||||
proc i8042_mouse_control stdcall, enable:dword
|
||||
call .wait_input
|
||||
mov al, 0x20
|
||||
out 0x64, al
|
||||
|
||||
call .wait_output
|
||||
in al, 0x60
|
||||
|
||||
and al, not 0x02
|
||||
cmp [enable], 0
|
||||
je @f
|
||||
or al, 0x02
|
||||
@@:
|
||||
mov ah, al
|
||||
|
||||
call .wait_input
|
||||
mov al, 0x60
|
||||
out 0x64, al
|
||||
|
||||
call .wait_input
|
||||
mov al, ah
|
||||
out 0x60, al
|
||||
ret
|
||||
|
||||
.wait_input:
|
||||
push ecx
|
||||
mov ecx, 0xFFFF
|
||||
@@:
|
||||
in al, 0x64
|
||||
test al, 0x02
|
||||
jz @f
|
||||
dec ecx
|
||||
jnz @b
|
||||
@@:
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
.wait_output:
|
||||
push ecx
|
||||
mov ecx, 0xFFFF
|
||||
@@:
|
||||
in al, 0x64
|
||||
test al, 0x01
|
||||
jnz @f
|
||||
dec ecx
|
||||
jnz @b
|
||||
@@:
|
||||
pop ecx
|
||||
ret
|
||||
endp
|
||||
|
||||
REGISTER_SERVICE svc_mouse_name, MOUSE_EVENT_MASK, VMMDEV_GUEST_SUPPORTS_MOUSE, \
|
||||
vmmdev_mouse_init, vmmdev_mouse_init, mouse_disable, mouse_handle_event, 0, AUTOSTART_MOUSE
|
||||
265
drivers/vboxguest/services/seamless/seamless.inc
Normal file
265
drivers/vboxguest/services/seamless/seamless.inc
Normal file
@@ -0,0 +1,265 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Seamless Mode Service
|
||||
; Назначение : Получение запросов на seamless mode от хоста
|
||||
; Файл : services/seamless/seamless.inc
|
||||
; Протокол : VMMDevReq_GetSeamlessChangeRequest (73)
|
||||
;
|
||||
; Seamless mode = «бесшовные окна»: окна гостя рисуются как окна хоста,
|
||||
; без рамки VM. Хост периодически спрашивает гостя: «какие области экрана
|
||||
; заняты окнами?» (visible region).
|
||||
;
|
||||
; Для KolibriOS полный seamless пока невозможен (нет API получения
|
||||
; регионов окон), но мы:
|
||||
; 1. Сообщаем хосту VMMDEV_GUEST_SUPPORTS_SEAMLESS → кнопка
|
||||
; «View → Seamless Mode» в VBox GUI станет активной
|
||||
; 2. Получаем события SEAMLESS_MODE_CHANGE через IRQ
|
||||
; 3. Запрашиваем текущий режим через GetSeamlessChangeRequest
|
||||
; 4. При включении seamless → отправляем visible region = весь экран
|
||||
; (один прямоугольник 0,0 → width,height)
|
||||
;
|
||||
; Архитектура (как display):
|
||||
; IRQ event → seamless_handle_event → pending=1, timestamp
|
||||
; Timer tick → seamless_tick → если pending и debounce прошёл → обработать
|
||||
; =============================================================================
|
||||
|
||||
svc_seamless_name db "SEAMLESS", 0
|
||||
|
||||
; --- Data ---
|
||||
align 4
|
||||
vbox_seamless_enabled dd 0
|
||||
vbox_seamless_current_mode dd 0 ; VMMDEV_SEAMLESS_*
|
||||
vbox_seamless_pending dd 0
|
||||
vbox_seamless_event_time dd 0
|
||||
|
||||
; Debounce: 500ms (50 тиков * 10ms)
|
||||
SEAMLESS_DELAY_TICKS equ 50
|
||||
|
||||
; --- Пакет GetSeamlessChangeRequest ---
|
||||
align 4
|
||||
vmmdev_seamless_change_s VMMDEV_SEAMLESS_CHANGE_REQUEST \
|
||||
<sizeof.VMMDEV_SEAMLESS_CHANGE_REQUEST, \
|
||||
VMMDEV_REQUEST_HEADER_VERSION, \
|
||||
VMMDEV_REQ_GET_SEAMLESS_CHANGE, \
|
||||
0, 0, 0>, \
|
||||
0, \
|
||||
VMMDEV_EVENT_SEAMLESS_MODE_CHANGE ; eventAck
|
||||
|
||||
align 4
|
||||
seamless_change_virt dd 0
|
||||
seamless_change_phys dd 0
|
||||
|
||||
; --- Пакет VideoSetVisibleRegion (1 прямоугольник) ---
|
||||
align 4
|
||||
vmmdev_visible_region_s VMMDEV_VIDEO_SET_VISIBLE_REGION \
|
||||
<sizeof.VMMDEV_VIDEO_SET_VISIBLE_REGION, \
|
||||
VMMDEV_REQUEST_HEADER_VERSION, \
|
||||
VMMDEV_REQ_VIDEO_SET_VISIBLE_REGION, \
|
||||
0, 0, 0>, \
|
||||
1, \
|
||||
<0, 0, 0, 0> ; rect0: заполняется при вызове
|
||||
|
||||
align 4
|
||||
visible_region_virt dd 0
|
||||
visible_region_phys dd 0
|
||||
|
||||
; seamless_init — Инициализация
|
||||
proc seamless_init uses ebx
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Initializing...\n"
|
||||
|
||||
; --- Физические адреса пакетов ---
|
||||
mov eax, vmmdev_seamless_change_s
|
||||
mov [seamless_change_virt], eax
|
||||
invoke GetPhysAddr
|
||||
test eax, eax
|
||||
jz .phys_failed
|
||||
mov [seamless_change_phys], eax
|
||||
|
||||
mov eax, vmmdev_visible_region_s
|
||||
mov [visible_region_virt], eax
|
||||
invoke GetPhysAddr
|
||||
test eax, eax
|
||||
jz .phys_failed
|
||||
mov [visible_region_phys], eax
|
||||
|
||||
DEBUGF __DEBUG_SEAMLESS__, "[VBoxGuest] [Seamless] SeamlessChange pkt: virt=0x%x phys=0x%x\n", \
|
||||
[seamless_change_virt], [seamless_change_phys]
|
||||
DEBUGF __DEBUG_SEAMLESS__, "[VBoxGuest] [Seamless] VisibleRegion pkt: virt=0x%x phys=0x%x\n", \
|
||||
[visible_region_virt], [visible_region_phys]
|
||||
|
||||
mov dword [vbox_seamless_enabled], 1
|
||||
mov dword [vbox_seamless_current_mode], VMMDEV_SEAMLESS_DISABLED
|
||||
|
||||
; Сразу запросить текущий режим (может быть уже включен)
|
||||
call seamless_query_mode
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Initialized OK (mode=%d)\n", \
|
||||
[vbox_seamless_current_mode]
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.phys_failed:
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] GetPhysAddr failed\n"
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
endp
|
||||
|
||||
; seamless_handle_event — Из IRQ контекста
|
||||
proc seamless_handle_event
|
||||
test eax, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE
|
||||
jz .done
|
||||
cmp dword [vbox_seamless_enabled], 0
|
||||
je .done
|
||||
|
||||
invoke GetTimerTicks
|
||||
mov [vbox_seamless_event_time], eax
|
||||
mov dword [vbox_seamless_pending], 1
|
||||
|
||||
DEBUGF __DEBUG_SEAMLESS__, "[VBoxGuest] [Seamless] Event queued\n"
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; seamless_tick — Из таймера, debounce
|
||||
proc seamless_tick
|
||||
cmp dword [vbox_seamless_pending], 0
|
||||
je .done
|
||||
|
||||
invoke GetTimerTicks
|
||||
sub eax, [vbox_seamless_event_time]
|
||||
cmp eax, SEAMLESS_DELAY_TICKS
|
||||
jb .done
|
||||
|
||||
mov dword [vbox_seamless_pending], 0
|
||||
|
||||
DEBUGF __DEBUG_SEAMLESS__, "[VBoxGuest] [Seamless] Processing mode change...\n"
|
||||
call seamless_query_mode
|
||||
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; seamless_query_mode — Запросить текущий seamless mode у хоста (req 73)
|
||||
proc seamless_query_mode uses ebx edi
|
||||
mov edi, [seamless_change_virt]
|
||||
test edi, edi
|
||||
jz .bad_ptr
|
||||
|
||||
; Заполнить запрос
|
||||
mov dword [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.header.rc], 0
|
||||
mov dword [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.mode], 0
|
||||
mov dword [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.eventAck], \
|
||||
VMMDEV_EVENT_SEAMLESS_MODE_CHANGE
|
||||
|
||||
; Отправить
|
||||
stdcall vmmdev_send_request, [seamless_change_phys]
|
||||
|
||||
; Проверить rc
|
||||
mov eax, [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.header.rc]
|
||||
test eax, eax
|
||||
jnz .error
|
||||
|
||||
; Прочитать режим
|
||||
mov eax, [edi + VMMDEV_SEAMLESS_CHANGE_REQUEST.mode]
|
||||
mov ebx, [vbox_seamless_current_mode]
|
||||
mov [vbox_seamless_current_mode], eax
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Mode: %d → %d\n", ebx, eax
|
||||
|
||||
; Обработать смену режима
|
||||
cmp eax, VMMDEV_SEAMLESS_DISABLED
|
||||
je .mode_disabled
|
||||
|
||||
cmp eax, VMMDEV_SEAMLESS_VISIBLE_REGION
|
||||
je .mode_visible_region
|
||||
|
||||
cmp eax, VMMDEV_SEAMLESS_HOST_WINDOW
|
||||
je .mode_host_window
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Unknown mode: %d\n", eax
|
||||
ret
|
||||
|
||||
.mode_disabled:
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Seamless DISABLED\n"
|
||||
ret
|
||||
|
||||
.mode_visible_region:
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Seamless ENABLED (visible region)\n"
|
||||
; Отправить видимую область = весь экран
|
||||
call seamless_send_fullscreen_region
|
||||
ret
|
||||
|
||||
.mode_host_window:
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Seamless ENABLED (host window)\n"
|
||||
call seamless_send_fullscreen_region
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Bad pointer\n"
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] GetSeamlessChange failed: rc=0x%x\n", eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; seamless_send_fullscreen_region — Отправить visible region = весь экран
|
||||
proc seamless_send_fullscreen_region uses ebx edi
|
||||
mov edi, [visible_region_virt]
|
||||
test edi, edi
|
||||
jz .bad_ptr
|
||||
|
||||
; Получить текущее разрешение из KOS
|
||||
invoke GetDisplay
|
||||
test eax, eax
|
||||
jz .no_display
|
||||
|
||||
mov ebx, eax
|
||||
mov ecx, [ebx + DISPLAY.width]
|
||||
mov edx, [ebx + DISPLAY.height]
|
||||
|
||||
DEBUGF 1, "[VBoxGuest] [Seamless] Sending region: 0,0 → %d,%d\n", ecx, edx
|
||||
|
||||
; Заполнить заголовок
|
||||
mov dword [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.header.rc], 0
|
||||
|
||||
; Заполнить прямоугольник
|
||||
mov dword [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.cRect], 1
|
||||
mov dword [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.rect0.xLeft], 0
|
||||
mov dword [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.rect0.yTop], 0
|
||||
mov [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.rect0.xRight], ecx
|
||||
mov [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.rect0.yBottom], edx
|
||||
|
||||
; Отправить
|
||||
stdcall vmmdev_send_request, [visible_region_phys]
|
||||
|
||||
mov eax, [edi + VMMDEV_VIDEO_SET_VISIBLE_REGION.header.rc]
|
||||
test eax, eax
|
||||
jnz .error
|
||||
|
||||
DEBUGF 1, "[VBoxGuest] [Seamless] Region sent OK\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Bad pointer\n"
|
||||
ret
|
||||
.no_display:
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] No display\n"
|
||||
ret
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] SetVisibleRegion failed: rc=0x%x\n", eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; seamless_disable — Выключить seamless
|
||||
proc seamless_disable
|
||||
DEBUGF 2, "[VBoxGuest] [Seamless] Disabling...\n"
|
||||
mov dword [vbox_seamless_enabled], 0
|
||||
mov dword [vbox_seamless_pending], 0
|
||||
mov dword [vbox_seamless_current_mode], VMMDEV_SEAMLESS_DISABLED
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
REGISTER_SERVICE svc_seamless_name, SEAMLESS_EVENT_MASK, VMMDEV_GUEST_SUPPORTS_SEAMLESS, \
|
||||
seamless_init, 0, seamless_disable, seamless_handle_event, seamless_tick, AUTOSTART_SEAMLESS
|
||||
11
drivers/vboxguest/services/services.inc
Normal file
11
drivers/vboxguest/services/services.inc
Normal file
@@ -0,0 +1,11 @@
|
||||
; =============================================================================
|
||||
; Services Aggregator
|
||||
; =============================================================================
|
||||
include 'services/mouse/mouse.inc'
|
||||
include 'services/heartbeat/heartbeat.inc'
|
||||
include 'services/guest_props/guest_props.inc'
|
||||
include 'services/display/display.inc'
|
||||
include 'services/shared_folders/shared_folders.inc'
|
||||
include 'services/clipboard/clipboard.inc'
|
||||
include 'services/seamless/seamless.inc'
|
||||
include 'services/timesync/timesync.inc'
|
||||
1119
drivers/vboxguest/services/shared_folders/shared_folders.inc
Normal file
1119
drivers/vboxguest/services/shared_folders/shared_folders.inc
Normal file
File diff suppressed because it is too large
Load Diff
3153
drivers/vboxguest/services/shared_folders/vboxsf.inc
Normal file
3153
drivers/vboxguest/services/shared_folders/vboxsf.inc
Normal file
File diff suppressed because it is too large
Load Diff
444
drivers/vboxguest/services/timesync/timesync.inc
Normal file
444
drivers/vboxguest/services/timesync/timesync.inc
Normal file
@@ -0,0 +1,444 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Time Sync Service
|
||||
; Назначение : Синхронизация часов гостевой ОС с хостом VirtualBox
|
||||
; Файл : services/timesync/timesync.inc
|
||||
;
|
||||
; VBox возвращает 64-bit миллисекунды с Unix epoch (1970-01-01).
|
||||
; Драйвер пишет время напрямую в CMOS RTC (порты 0x70/0x71).
|
||||
; int 0x40 нельзя из kernel-mode: обработчик syscall предполагает ring 3
|
||||
; (переключение стеков user→kernel), из ring 0 это разрушает стек.
|
||||
; =============================================================================
|
||||
|
||||
svc_timesync_name db "TIMESYNC", 0
|
||||
|
||||
; --- Data ---
|
||||
align 4
|
||||
vbox_timesync_enabled dd 0
|
||||
vbox_timesync_last_tick dd 0
|
||||
|
||||
align 4
|
||||
vmmdev_get_host_time_s VMMDEV_GET_HOST_TIME \
|
||||
<sizeof.VMMDEV_GET_HOST_TIME, \
|
||||
VMMDEV_REQUEST_HEADER_VERSION, \
|
||||
VMMDEV_REQ_GET_HOST_TIME, \
|
||||
0, 0, 0>, \
|
||||
0, 0
|
||||
|
||||
align 4
|
||||
timesync_time_virt dd 0
|
||||
timesync_time_phys dd 0
|
||||
|
||||
; CMOS port constants
|
||||
CMOS_ADDR equ 0x70
|
||||
CMOS_DATA equ 0x71
|
||||
|
||||
; timesync_init — Инициализация
|
||||
proc timesync_init
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Initializing...\n"
|
||||
|
||||
mov eax, vmmdev_get_host_time_s
|
||||
mov [timesync_time_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [timesync_time_phys], eax
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Buffer: virt=0x%x, phys=0x%x\n", \
|
||||
[timesync_time_virt], [timesync_time_phys]
|
||||
|
||||
mov dword [vbox_timesync_enabled], 1
|
||||
call timesync_do_sync
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Initialized OK\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; timesync_tick — Проверка интервала и синхронизация
|
||||
proc timesync_tick
|
||||
cmp dword [vbox_timesync_enabled], 0
|
||||
je .done
|
||||
invoke GetTimerTicks
|
||||
sub eax, [vbox_timesync_last_tick]
|
||||
cmp eax, TIMESYNC_INTERVAL_TICKS
|
||||
jb .done
|
||||
invoke GetTimerTicks
|
||||
mov [vbox_timesync_last_tick], eax
|
||||
call timesync_do_sync
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
; timesync_do_sync — Получить время хоста и записать в CMOS RTC
|
||||
proc timesync_do_sync uses ebx ecx edx esi edi
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Syncing...\n"
|
||||
|
||||
mov edi, [timesync_time_virt]
|
||||
test edi, edi
|
||||
jz .bad_ptr
|
||||
|
||||
mov dword [edi + VMMDEV_GET_HOST_TIME.header.rc], 0
|
||||
mov dword [edi + VMMDEV_GET_HOST_TIME.time_low], 0
|
||||
mov dword [edi + VMMDEV_GET_HOST_TIME.time_high], 0
|
||||
|
||||
stdcall vmmdev_send_request, [timesync_time_phys]
|
||||
|
||||
mov eax, [edi + VMMDEV_GET_HOST_TIME.header.rc]
|
||||
test eax, eax
|
||||
js .error
|
||||
|
||||
; 64-bit миллисекунды с epoch
|
||||
mov eax, [edi + VMMDEV_GET_HOST_TIME.time_low]
|
||||
mov edx, [edi + VMMDEV_GET_HOST_TIME.time_high]
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Host ms: hi=0x%x lo=0x%x\n", edx, eax
|
||||
|
||||
mov ecx, eax
|
||||
or ecx, edx
|
||||
jz .bad_time
|
||||
|
||||
; edx:eax / 1000 → eax = unix seconds
|
||||
mov ecx, 1000
|
||||
div ecx
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Unix timestamp: %d\n", eax
|
||||
call timesync_set_cmos
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Sync complete\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.bad_ptr:
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Bad pointer\n"
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] GetHostTime failed: rc=0x%x\n", eax
|
||||
ret
|
||||
.bad_time:
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Zero time returned\n"
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
endp
|
||||
|
||||
; timesync_set_cmos — Вычисляет дату/время и записывает в CMOS RTC
|
||||
proc timesync_set_cmos uses ebx ecx edx esi edi
|
||||
locals
|
||||
ts_sec dd ?
|
||||
ts_min dd ?
|
||||
ts_hour dd ?
|
||||
ts_day dd ?
|
||||
ts_month dd ?
|
||||
ts_year dd ?
|
||||
ts_dow dd ?
|
||||
endl
|
||||
|
||||
; ── Разложить на дни и время дня ──
|
||||
xor edx, edx
|
||||
mov ecx, 86400
|
||||
div ecx
|
||||
; eax = total_days, edx = time_of_day_seconds
|
||||
mov esi, eax ; total_days
|
||||
|
||||
; Время суток
|
||||
mov eax, edx
|
||||
xor edx, edx
|
||||
mov ecx, 3600
|
||||
div ecx
|
||||
mov [ts_hour], eax
|
||||
|
||||
mov eax, edx
|
||||
xor edx, edx
|
||||
mov ecx, 60
|
||||
div ecx
|
||||
mov [ts_min], eax
|
||||
mov [ts_sec], edx
|
||||
|
||||
; ── День недели: (days + 3) % 7 + 1 ──
|
||||
lea eax, [esi + 3]
|
||||
xor edx, edx
|
||||
mov ecx, 7
|
||||
div ecx
|
||||
inc edx
|
||||
mov [ts_dow], edx
|
||||
|
||||
; ── civil_from_days (Howard Hinnant) ──
|
||||
; eax = days → дата
|
||||
mov eax, esi
|
||||
call .civil_from_days
|
||||
mov [ts_day], eax
|
||||
mov [ts_month], ebx
|
||||
mov [ts_year], ecx
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Date: %d-%d-%d %d:%d:%d DoW=%d\n", \
|
||||
[ts_year], [ts_month], [ts_day], [ts_hour], [ts_min], [ts_sec], [ts_dow]
|
||||
|
||||
; ── Ждать окончания обновления RTC ──
|
||||
call .cmos_wait
|
||||
|
||||
; ── Запретить обновления (SET bit в Status B) ──
|
||||
mov al, 0x0B
|
||||
out CMOS_ADDR, al
|
||||
in al, CMOS_DATA
|
||||
or al, 0x80
|
||||
push eax
|
||||
mov al, 0x0B
|
||||
out CMOS_ADDR, al
|
||||
pop eax
|
||||
out CMOS_DATA, al
|
||||
|
||||
; ── Записать все поля (BCD) ──
|
||||
mov eax, [ts_sec]
|
||||
call .to_bcd
|
||||
mov ah, al
|
||||
mov al, 0x00 ; seconds register
|
||||
call .cmos_wr
|
||||
|
||||
mov eax, [ts_min]
|
||||
call .to_bcd
|
||||
mov ah, al
|
||||
mov al, 0x02 ; minutes register
|
||||
call .cmos_wr
|
||||
|
||||
mov eax, [ts_hour]
|
||||
call .to_bcd
|
||||
mov ah, al
|
||||
mov al, 0x04 ; hours register
|
||||
call .cmos_wr
|
||||
|
||||
mov eax, [ts_dow]
|
||||
mov ah, al
|
||||
mov al, 0x06 ; weekday register
|
||||
call .cmos_wr
|
||||
|
||||
mov eax, [ts_day]
|
||||
call .to_bcd
|
||||
mov ah, al
|
||||
mov al, 0x07 ; day register
|
||||
call .cmos_wr
|
||||
|
||||
mov eax, [ts_month]
|
||||
call .to_bcd
|
||||
mov ah, al
|
||||
mov al, 0x08 ; month register
|
||||
call .cmos_wr
|
||||
|
||||
; YY = year mod 100
|
||||
mov eax, [ts_year]
|
||||
xor edx, edx
|
||||
mov ecx, 100
|
||||
div ecx
|
||||
push eax ; century
|
||||
mov eax, edx
|
||||
call .to_bcd
|
||||
mov ah, al
|
||||
mov al, 0x09 ; year register
|
||||
call .cmos_wr
|
||||
|
||||
; Century
|
||||
pop eax
|
||||
call .to_bcd
|
||||
mov ah, al
|
||||
mov al, 0x32 ; century register
|
||||
call .cmos_wr
|
||||
|
||||
; ── Разрешить обновления ──
|
||||
mov al, 0x0B
|
||||
out CMOS_ADDR, al
|
||||
in al, CMOS_DATA
|
||||
and al, 0x7F
|
||||
push eax
|
||||
mov al, 0x0B
|
||||
out CMOS_ADDR, al
|
||||
pop eax
|
||||
out CMOS_DATA, al
|
||||
|
||||
ret
|
||||
|
||||
; ── Helpers ──
|
||||
|
||||
.cmos_wr:
|
||||
; al = register, ah = value
|
||||
out CMOS_ADDR, al
|
||||
mov al, ah
|
||||
out CMOS_DATA, al
|
||||
ret
|
||||
|
||||
.cmos_wait:
|
||||
push eax ecx
|
||||
mov ecx, 10000
|
||||
@@:
|
||||
mov al, 0x0A
|
||||
out CMOS_ADDR, al
|
||||
in al, CMOS_DATA
|
||||
test al, 0x80
|
||||
jz @f
|
||||
pause
|
||||
loop @b
|
||||
@@:
|
||||
pop ecx eax
|
||||
ret
|
||||
|
||||
.to_bcd:
|
||||
; eax (0-99) → eax BCD
|
||||
push ecx edx
|
||||
and eax, 0xFF
|
||||
xor edx, edx
|
||||
mov ecx, 10
|
||||
div ecx
|
||||
shl eax, 4
|
||||
or eax, edx
|
||||
pop edx ecx
|
||||
ret
|
||||
|
||||
; .civil_from_days — Howard Hinnant algorithm
|
||||
.civil_from_days:
|
||||
; z = days + 719468
|
||||
add eax, 719468
|
||||
|
||||
; era = z / 146097
|
||||
xor edx, edx
|
||||
mov ecx, 146097
|
||||
div ecx
|
||||
mov esi, eax ; era
|
||||
; doe = z - era * 146097 (но z уже потерян → используем edx = remainder)
|
||||
mov ecx, edx ; ecx = doe
|
||||
|
||||
; yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365
|
||||
mov eax, ecx
|
||||
xor edx, edx
|
||||
mov edi, 1460
|
||||
div edi
|
||||
mov edi, eax ; doe/1460
|
||||
|
||||
mov eax, ecx
|
||||
xor edx, edx
|
||||
push ecx
|
||||
mov ecx, 36524
|
||||
div ecx
|
||||
pop ecx
|
||||
sub edi, eax ; doe/1460 - doe/36524 (note: we subtract then add later)
|
||||
; Actually: val = doe - doe/1460 + doe/36524 - doe/146096
|
||||
; Let me redo properly:
|
||||
|
||||
; A = doe/1460
|
||||
push ecx
|
||||
mov eax, ecx
|
||||
xor edx, edx
|
||||
mov ecx, 1460
|
||||
div ecx
|
||||
pop ecx
|
||||
push eax ; [esp] = A
|
||||
|
||||
; B = doe/36524
|
||||
push ecx
|
||||
mov eax, ecx
|
||||
xor edx, edx
|
||||
mov ecx, 36524
|
||||
div ecx
|
||||
pop ecx
|
||||
push eax ; [esp]=B, [esp+4]=A
|
||||
|
||||
; C = doe/146096
|
||||
push ecx
|
||||
mov eax, ecx
|
||||
xor edx, edx
|
||||
mov ecx, 146096
|
||||
div ecx
|
||||
pop ecx
|
||||
; eax = C
|
||||
|
||||
pop ebx ; B
|
||||
pop edi ; A
|
||||
|
||||
; val = doe - A + B - C
|
||||
mov edx, ecx ; doe
|
||||
sub edx, edi
|
||||
add edx, ebx
|
||||
sub edx, eax
|
||||
|
||||
; yoe = val / 365
|
||||
mov eax, edx
|
||||
xor edx, edx
|
||||
push ecx
|
||||
mov ecx, 365
|
||||
div ecx
|
||||
pop ecx
|
||||
; eax = yoe, ecx still = doe
|
||||
mov edi, eax ; edi = yoe
|
||||
|
||||
; year = yoe + era * 400
|
||||
mov eax, esi ; era
|
||||
imul eax, 400
|
||||
add eax, edi
|
||||
push eax ; [esp] = year
|
||||
|
||||
; doy = doe - (365*yoe + yoe/4 - yoe/100)
|
||||
mov eax, edi
|
||||
imul eax, 365
|
||||
mov esi, eax ; 365*yoe
|
||||
|
||||
mov eax, edi
|
||||
shr eax, 2
|
||||
add esi, eax ; + yoe/4
|
||||
|
||||
mov eax, edi
|
||||
xor edx, edx
|
||||
push ecx
|
||||
mov ecx, 100
|
||||
div ecx
|
||||
pop ecx
|
||||
sub esi, eax ; - yoe/100
|
||||
|
||||
sub ecx, esi ; ecx = doy
|
||||
|
||||
; mp = (5*doy + 2) / 153
|
||||
imul eax, ecx, 5
|
||||
add eax, 2
|
||||
xor edx, edx
|
||||
push ecx
|
||||
mov ecx, 153
|
||||
div ecx
|
||||
pop ecx
|
||||
mov edi, eax ; mp
|
||||
|
||||
; day = doy - (153*mp + 2)/5 + 1
|
||||
imul eax, edi, 153
|
||||
add eax, 2
|
||||
xor edx, edx
|
||||
push ecx
|
||||
mov ecx, 5
|
||||
div ecx
|
||||
pop ecx
|
||||
sub ecx, eax
|
||||
inc ecx ; ecx = day
|
||||
|
||||
; month = mp < 10 ? mp + 3 : mp - 9
|
||||
cmp edi, 10
|
||||
jae .mp_ge10
|
||||
add edi, 3
|
||||
jmp .month_done2
|
||||
.mp_ge10:
|
||||
sub edi, 9
|
||||
.month_done2:
|
||||
; edi = month, ecx = day
|
||||
|
||||
; if month <= 2 → year++
|
||||
pop eax ; year
|
||||
cmp edi, 2
|
||||
ja .year_ok2
|
||||
inc eax
|
||||
.year_ok2:
|
||||
; Формируем результат: eax=day, ebx=month, ecx=year
|
||||
mov ebx, edi ; month
|
||||
xchg eax, ecx ; eax=day, ecx=year
|
||||
ret
|
||||
endp
|
||||
|
||||
; timesync_disable — Выключить timesync
|
||||
proc timesync_disable
|
||||
DEBUGF 2, "[VBoxGuest] [TimeSync] Disabling...\n"
|
||||
mov dword [vbox_timesync_enabled], 0
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
REGISTER_SERVICE svc_timesync_name, TIMESYNC_EVENT_MASK, 0, \
|
||||
timesync_init, 0, timesync_disable, 0, timesync_tick, AUTOSTART_TIMESYNC
|
||||
70
drivers/vboxguest/sys/init.inc
Normal file
70
drivers/vboxguest/sys/init.inc
Normal file
@@ -0,0 +1,70 @@
|
||||
; =============================================================================
|
||||
; Модуль : Инициализация драйвера VBoxGuest
|
||||
; Назначение : Инициализация всех подсистем драйвера, подключение к VMMDev,
|
||||
; настройка сервисов, установка обработчиков
|
||||
; Файл : sys/init.inc
|
||||
; =============================================================================
|
||||
|
||||
; Полная инициализация драйвера VBoxGuest
|
||||
proc sys_init
|
||||
|
||||
call vmmdev_probe
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
call mmio_map_vmmdev
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
call ports_init ; чекалка
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
call vmmdev_init_packets
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
call vmmdev_check_version ; получить версию хоста (для guest_info2)
|
||||
|
||||
call vmmdev_init_protocol ; guest_info + caps + event_filter
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
call hgcm_init ; подготовка пакетов/таймаутов
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
call timer_init
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
call vmmdev_irq_install
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
call dispatcher_init_all
|
||||
call dispatcher_enable_autostart
|
||||
|
||||
call dispatcher_get_active_events
|
||||
call vmmdev_update_event_filter
|
||||
test eax, eax
|
||||
jnz .fail_event_filter
|
||||
|
||||
call dispatcher_get_active_caps
|
||||
call vmmdev_update_capabilities
|
||||
test eax, eax
|
||||
jnz .fail_caps
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.fail_event_filter:
|
||||
DEBUGF 2, "[VBoxGuest] [Init] Event filter setup failed: 0x%x\n", eax
|
||||
ret
|
||||
|
||||
.fail_caps:
|
||||
DEBUGF 2, "[VBoxGuest] [Init] Guest capabilities setup failed: 0x%x\n", eax
|
||||
ret
|
||||
.fail:
|
||||
ret
|
||||
endp
|
||||
183
drivers/vboxguest/sys/ioctl.inc
Normal file
183
drivers/vboxguest/sys/ioctl.inc
Normal file
@@ -0,0 +1,183 @@
|
||||
; =============================================================================
|
||||
; Модуль : IOCTL интерфейс драйвера VBoxGuest
|
||||
; Назначение : Обработка команд от приложений (service_proc, ioctl_get_services)
|
||||
; Файл : sys/ioctl.inc
|
||||
; =============================================================================
|
||||
|
||||
; IOCTL ABI v1
|
||||
API_VERSION equ 1
|
||||
|
||||
; General
|
||||
VBOX_IOCTL_GET_VERSION equ 0
|
||||
VBOX_IOCTL_GET_SERVICES equ 1
|
||||
VBOX_IOCTL_SVC_ENABLE equ 2
|
||||
VBOX_IOCTL_SVC_DISABLE equ 3
|
||||
|
||||
; Clipboard
|
||||
VBOX_IOCTL_CLIP_STATUS equ 10
|
||||
VBOX_IOCTL_CLIP_READ equ 11
|
||||
VBOX_IOCTL_CLIP_WRITE equ 12
|
||||
|
||||
; SERVICE_INFO size for GET_SERVICES (dd id + rb name[16] + dd enabled = 24)
|
||||
SVC_INFO_SIZE equ 24
|
||||
SVC_INFO_NAME_LEN equ 16
|
||||
|
||||
; =============================================================================
|
||||
; Service Procedure — IOCTL dispatch
|
||||
; =============================================================================
|
||||
proc service_proc stdcall, ioctl:dword
|
||||
mov ebx, [ioctl]
|
||||
mov eax, [ebx + IOCTL.io_code]
|
||||
|
||||
cmp eax, VBOX_IOCTL_GET_VERSION
|
||||
je .get_version
|
||||
cmp eax, VBOX_IOCTL_GET_SERVICES
|
||||
je .get_services
|
||||
cmp eax, VBOX_IOCTL_SVC_ENABLE
|
||||
je .svc_enable
|
||||
cmp eax, VBOX_IOCTL_SVC_DISABLE
|
||||
je .svc_disable
|
||||
cmp eax, VBOX_IOCTL_CLIP_STATUS
|
||||
je .clip_status
|
||||
cmp eax, VBOX_IOCTL_CLIP_READ
|
||||
je .clip_read
|
||||
cmp eax, VBOX_IOCTL_CLIP_WRITE
|
||||
je .clip_write
|
||||
|
||||
jmp .fail
|
||||
|
||||
; --- GET_VERSION (0) ---
|
||||
.get_version:
|
||||
cmp [ebx + IOCTL.out_size], 4
|
||||
jb .fail
|
||||
mov eax, [ebx + IOCTL.output]
|
||||
mov dword [eax], API_VERSION
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
; --- GET_SERVICES (1) ---
|
||||
.get_services:
|
||||
stdcall ioctl_get_services, ebx
|
||||
ret
|
||||
|
||||
; --- SVC_ENABLE (2) ---
|
||||
.svc_enable:
|
||||
cmp [ebx + IOCTL.inp_size], 4
|
||||
jb .fail
|
||||
mov eax, [ebx + IOCTL.input]
|
||||
mov eax, [eax]
|
||||
stdcall dispatcher_enable_by_id, eax
|
||||
push eax
|
||||
call dispatcher_get_active_events
|
||||
call vmmdev_update_event_filter
|
||||
call dispatcher_get_active_caps
|
||||
call vmmdev_update_capabilities
|
||||
pop eax
|
||||
ret
|
||||
|
||||
; --- SVC_DISABLE (3) ---
|
||||
.svc_disable:
|
||||
cmp [ebx + IOCTL.inp_size], 4
|
||||
jb .fail
|
||||
mov eax, [ebx + IOCTL.input]
|
||||
mov eax, [eax]
|
||||
stdcall dispatcher_disable_by_id, eax
|
||||
push eax
|
||||
call dispatcher_get_active_events
|
||||
call vmmdev_update_event_filter
|
||||
call dispatcher_get_active_caps
|
||||
call vmmdev_update_capabilities
|
||||
pop eax
|
||||
ret
|
||||
|
||||
; --- CLIP_STATUS (10) ---
|
||||
.clip_status:
|
||||
stdcall clip_ioctl_status, ebx
|
||||
ret
|
||||
|
||||
; --- CLIP_READ (11) ---
|
||||
.clip_read:
|
||||
stdcall clip_ioctl_read, ebx
|
||||
ret
|
||||
|
||||
; --- CLIP_WRITE (12) ---
|
||||
.clip_write:
|
||||
stdcall clip_ioctl_write, ebx
|
||||
ret
|
||||
|
||||
.fail:
|
||||
or eax, -1
|
||||
ret
|
||||
endp
|
||||
|
||||
; =============================================================================
|
||||
; ioctl_get_services — Заполнить список сервисов
|
||||
; =============================================================================
|
||||
proc ioctl_get_services stdcall uses ebx ecx edx esi edi, ioctl_ptr:dword
|
||||
mov ebx, [ioctl_ptr]
|
||||
cmp [ebx + IOCTL.out_size], 4
|
||||
jb .fail
|
||||
|
||||
mov edi, [ebx + IOCTL.output]
|
||||
mov ecx, [services_count]
|
||||
mov [edi], ecx ; dd count
|
||||
add edi, 4
|
||||
|
||||
test ecx, ecx
|
||||
jz .done
|
||||
|
||||
; Доступное место = out_size - 4
|
||||
mov edx, [ebx + IOCTL.out_size]
|
||||
sub edx, 4
|
||||
|
||||
mov esi, services_table
|
||||
|
||||
.loop:
|
||||
cmp edx, SVC_INFO_SIZE
|
||||
jb .done
|
||||
|
||||
; dd id
|
||||
mov eax, [esi + SERVICE_ENTRY.id]
|
||||
mov [edi], eax
|
||||
add edi, 4
|
||||
|
||||
; rb name[16] — null-padded
|
||||
push ecx esi edi
|
||||
mov ecx, SVC_INFO_NAME_LEN
|
||||
; Заполнить нулями
|
||||
push edi
|
||||
xor al, al
|
||||
rep stosb
|
||||
pop edi
|
||||
; Скопировать имя
|
||||
mov esi, [esi + SERVICE_ENTRY.name_ptr]
|
||||
mov ecx, SVC_INFO_NAME_LEN - 1
|
||||
.copy_name:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .name_done
|
||||
stosb
|
||||
dec ecx
|
||||
jnz .copy_name
|
||||
.name_done:
|
||||
pop edi esi ecx
|
||||
add edi, SVC_INFO_NAME_LEN
|
||||
|
||||
; dd enabled
|
||||
mov eax, [esi + SERVICE_ENTRY.enabled]
|
||||
mov [edi], eax
|
||||
add edi, 4
|
||||
|
||||
sub edx, SVC_INFO_SIZE
|
||||
add esi, sizeof.SERVICE_ENTRY
|
||||
dec ecx
|
||||
jnz .loop
|
||||
|
||||
.done:
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.fail:
|
||||
or eax, -1
|
||||
ret
|
||||
endp
|
||||
47
drivers/vboxguest/sys/shutdown.inc
Normal file
47
drivers/vboxguest/sys/shutdown.inc
Normal file
@@ -0,0 +1,47 @@
|
||||
; =============================================================================
|
||||
; Модуль : Корректное завершение работы драйвера VBoxGuest
|
||||
; Назначение : Деинициализация всех подсистем при выгрузке драйвера (DRV_EXIT)
|
||||
; Файл : sys/shutdown.inc
|
||||
; Порядок : По образцу Linux vbg_core_exit для избежания зависаний
|
||||
; =============================================================================
|
||||
|
||||
; Полная деинициализация драйвера VBoxGuest (вызывается при DRV_EXIT)
|
||||
proc sys_shutdown
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] Shutdown started\n"
|
||||
|
||||
; 1. Остановить все сервисы (отправить уведомления хосту)
|
||||
call dispatcher_disable_all
|
||||
DEBUGF 2, "[VBoxGuest] All services disabled\n"
|
||||
|
||||
; 2. Остановить таймер (ПЕРЕД IRQ detach, иначе tick вызовется во время cleanup)
|
||||
call timer_stop
|
||||
DEBUGF 2, "[VBoxGuest] Timer stopped\n"
|
||||
|
||||
; 3. Убрать IRQ handler ОБЯЗАТЕЛЬНО до освобождения буферов
|
||||
; ISR не должна писать в освобождаемую память
|
||||
; call vbox_irq_detach
|
||||
; DEBUGF 2, "[VBoxGuest] IRQ handler detached\n"
|
||||
|
||||
; 4. Сбросить маски события и возможностей на хосте (маска = 0)
|
||||
xor eax, eax
|
||||
mov [dispatcher_active_events], eax
|
||||
call vmmdev_update_event_filter
|
||||
DEBUGF 2, "[VBoxGuest] Event filter cleared\n"
|
||||
|
||||
mov [dispatcher_active_caps], eax
|
||||
call vmmdev_update_capabilities
|
||||
DEBUGF 2, "[VBoxGuest] Capabilities cleared\n"
|
||||
|
||||
; 5. Освободить пакеты (ПОСЛЕ IRQ detach — ISR больше не пишет в них)
|
||||
call hgcm_free_packets
|
||||
DEBUGF 2, "[VBoxGuest] HGCM packets freed\n"
|
||||
|
||||
call vmmdev_free_packets
|
||||
DEBUGF 2, "[VBoxGuest] VMMDev packets freed\n"
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] Shutdown complete\n"
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
1102
drivers/vboxguest/vboxctrl/vboxctrl.asm
Normal file
1102
drivers/vboxguest/vboxctrl/vboxctrl.asm
Normal file
File diff suppressed because it is too large
Load Diff
92
drivers/vboxguest/vboxguest.asm
Normal file
92
drivers/vboxguest/vboxguest.asm
Normal file
@@ -0,0 +1,92 @@
|
||||
; =============================================================================
|
||||
; Программа : VirtualBox Guest Driver для KolibriOS
|
||||
; Модуль : Main driver entry
|
||||
; Назначение : Full-featured driver
|
||||
; Файл : vboxguest.asm
|
||||
; Автор : lex_coder(lex_coder@mail.ru), Алексей Михайлов
|
||||
; При моральной поддержке сообщества KolibriOS
|
||||
;
|
||||
; cp /usbhd0/1/vboxguest/vboxguest /sys/Drivers/vboxguest.sys
|
||||
; loaddrv vboxguest
|
||||
;
|
||||
; =============================================================================
|
||||
format PE DLL native 0.05
|
||||
entry START
|
||||
|
||||
section '.flat' code readable writable executable
|
||||
|
||||
include '/usbhd0/1/ksrc_n/DRIVERS/proc32.inc'
|
||||
include '/usbhd0/1/ksrc_n/DRIVERS/struct.inc'
|
||||
include '/usbhd0/1/ksrc_n/DRIVERS/macros.inc'
|
||||
include '/usbhd0/1/ksrc_n/DRIVERS/peimport.inc'
|
||||
include '/usbhd0/1/ksrc_n/DRIVERS/fdo.inc'
|
||||
include '/usbhd0/1/ksrc_n/DRIVERS/pci.inc'
|
||||
|
||||
include 'config.inc'
|
||||
include 'common/common.inc'
|
||||
include 'data/data.inc'
|
||||
include 'core/core.inc'
|
||||
include 'vmmdev/vmmdev.inc'
|
||||
include 'hgcm/core.inc'
|
||||
include 'sys/init.inc'
|
||||
include 'sys/shutdown.inc'
|
||||
include 'sys/ioctl.inc'
|
||||
include 'services/services.inc'
|
||||
|
||||
BUILD_SERVICE_TABLE
|
||||
|
||||
; =============================================================================
|
||||
; Driver Entry Point
|
||||
; =============================================================================
|
||||
proc START c, state:dword, cmdline:dword
|
||||
push ebx esi edi
|
||||
cmp [state], DRV_ENTRY
|
||||
je .entry
|
||||
cmp [state], DRV_EXIT
|
||||
je .exit
|
||||
|
||||
pop edi esi ebx
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.entry:
|
||||
DEBUGF 2, "[VBoxGuest] VBoxGuest Driver v2.0\n"
|
||||
|
||||
call sys_init ;
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
; Регистрация сервиса (IOCTL интерфейс для приложений)
|
||||
invoke RegService, service_name, service_proc
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] IOCTL service '%s' registered (API v%d)\n", service_name, API_VERSION
|
||||
DEBUGF 2, "[VBoxGuest] Initialization complete!\n"
|
||||
pop edi esi ebx
|
||||
ret
|
||||
|
||||
.fail:
|
||||
DEBUGF 2, "[VBoxGuest] Initialization FAILED\n"
|
||||
|
||||
.exit:
|
||||
DEBUGF 2, "[VBoxGuest] DRV_EXIT: Shutting down driver\n"
|
||||
call sys_shutdown
|
||||
pop edi esi ebx
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
; =============================================================================
|
||||
; Data Section
|
||||
; =============================================================================
|
||||
align 4
|
||||
service_name db 'VBOXGUEST', 0
|
||||
|
||||
align 4
|
||||
vbox_device VBOX_DEVICE
|
||||
|
||||
include_debug_strings
|
||||
|
||||
align 4
|
||||
data fixups
|
||||
end data
|
||||
27
drivers/vboxguest/vmmdev/capabilities.inc
Normal file
27
drivers/vboxguest/vmmdev/capabilities.inc
Normal file
@@ -0,0 +1,27 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Guest Capabilities
|
||||
; Назначение : Настройка возможностей гостя (REQ 56)
|
||||
; Файл : vmmdev/capabilities.inc
|
||||
; =============================================================================
|
||||
|
||||
; vmmdev_update_capabilities — Обновить caps по runtime-маске из dispatcher
|
||||
proc vmmdev_update_capabilities
|
||||
mov edi, [vbox_device.caps_virt]
|
||||
test edi, edi
|
||||
jz .bad
|
||||
|
||||
; Обновить or_mask в пакете
|
||||
mov [edi + VMMDEV_SET_GUEST_CAPABILITIES2.or_mask], eax
|
||||
mov dword [edi + VMMDEV_SET_GUEST_CAPABILITIES2.header.rc], 0
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Caps] Updating capabilities: or_mask=0x%x\n", eax
|
||||
|
||||
mov ebx, [vbox_device.caps_phys]
|
||||
stdcall vmmdev_send_request, ebx
|
||||
|
||||
mov eax, [edi + VMMDEV_SET_GUEST_CAPABILITIES2.header.rc]
|
||||
ret
|
||||
.bad:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
endp
|
||||
25
drivers/vboxguest/vmmdev/core.inc
Normal file
25
drivers/vboxguest/vmmdev/core.inc
Normal file
@@ -0,0 +1,25 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Core
|
||||
; Назначение : Базовые операции VMMDev: send_request, init протокола
|
||||
; Файл : vmmdev/core.inc
|
||||
; =============================================================================
|
||||
|
||||
; Базовая настройка протокола VMMDev
|
||||
proc vmmdev_init_protocol
|
||||
|
||||
; GuestInfo
|
||||
call guest_info_report
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
; GuestInfo2 (non-fatal — не все версии VBox поддерживают)
|
||||
call guest_info_2_report
|
||||
test eax, eax
|
||||
jz @f
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] GuestInfo2 failed (rc=0x%x), continuing...\n", eax
|
||||
@@:
|
||||
|
||||
xor eax, eax
|
||||
.fail:
|
||||
ret
|
||||
endp
|
||||
28
drivers/vboxguest/vmmdev/event_filter.inc
Normal file
28
drivers/vboxguest/vmmdev/event_filter.inc
Normal file
@@ -0,0 +1,28 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Event Filter
|
||||
; Назначение : Фильтр событий VMMDev (REQ 42)
|
||||
; Файл : vmmdev/event_filter.inc
|
||||
; =============================================================================
|
||||
|
||||
; vmmdev_update_event_filter — Обновить фильтр по маске из dispatcher
|
||||
proc vmmdev_update_event_filter
|
||||
mov edi, [vbox_device.filter_virt]
|
||||
test edi, edi
|
||||
jz .bad
|
||||
|
||||
; Обновить or_mask в пакете
|
||||
mov [edi + VMMDEV_CTL_GUEST_FILTER_MASK.or_mask], eax
|
||||
mov dword [edi + VMMDEV_CTL_GUEST_FILTER_MASK.header.rc], 0
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [Filter] Updating event filter: or_mask=0x%x\n", eax
|
||||
|
||||
mov ebx, [vbox_device.filter_phys]
|
||||
stdcall vmmdev_send_request, ebx
|
||||
|
||||
mov eax, [edi + VMMDEV_CTL_GUEST_FILTER_MASK.header.rc]
|
||||
ret
|
||||
|
||||
.bad:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
endp
|
||||
77
drivers/vboxguest/vmmdev/guest_info.inc
Normal file
77
drivers/vboxguest/vmmdev/guest_info.inc
Normal file
@@ -0,0 +1,77 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Guest Info
|
||||
; Назначение : ReportGuestInfo / ReportGuestInfo2
|
||||
; Файл : vmmdev/guest_info.inc
|
||||
; =============================================================================
|
||||
|
||||
; Отправка ReportGuestInfo (REQ 50)
|
||||
proc guest_info_report uses ebx esi
|
||||
mov esi, [vbox_device.guestinfo_virt]
|
||||
mov ebx, [vbox_device.guestinfo_phys]
|
||||
test esi, esi
|
||||
jz .bad
|
||||
test ebx, ebx
|
||||
jz .bad
|
||||
|
||||
stdcall vmmdev_send_request, ebx
|
||||
mov eax, [esi + VMMDEV_HEADER.rc]
|
||||
test eax, eax
|
||||
jnz .error
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] Guest info sent (interface 0x%x)\n", VMMDEV_VERSION
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] send_guest_info failed, rc=0x%x\n", eax
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
|
||||
.bad:
|
||||
mov eax, VERR_INVALID_PARAMETER
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
; Отправка ReportGuestInfo2 (REQ 58), версия заполняется из host_version
|
||||
proc guest_info_2_report uses ebx esi edi
|
||||
mov esi, [vbox_device.guestinfo2_virt]
|
||||
mov ebx, [vbox_device.guestinfo2_phys]
|
||||
test esi, esi
|
||||
jz .bad
|
||||
test ebx, ebx
|
||||
jz .bad
|
||||
|
||||
; Заполнить версию GA из полученной версии хоста
|
||||
mov edi, [vbox_device.host_version_virt]
|
||||
test edi, edi
|
||||
jz .send ; нет данных — отправляем как есть (нули)
|
||||
|
||||
movzx eax, word [edi + VMMDEV_GET_HOST_VERSION.major]
|
||||
mov word [esi + VMMDEV_REPORT_GUEST_INFO2.guest_info.additions_major], ax
|
||||
movzx eax, word [edi + VMMDEV_GET_HOST_VERSION.minor]
|
||||
mov word [esi + VMMDEV_REPORT_GUEST_INFO2.guest_info.additions_minor], ax
|
||||
mov eax, [edi + VMMDEV_GET_HOST_VERSION.build]
|
||||
mov dword [esi + VMMDEV_REPORT_GUEST_INFO2.guest_info.additions_build], eax
|
||||
mov eax, [edi + VMMDEV_GET_HOST_VERSION.revision]
|
||||
mov dword [esi + VMMDEV_REPORT_GUEST_INFO2.guest_info.additions_revision], eax
|
||||
|
||||
.send:
|
||||
stdcall vmmdev_send_request, ebx
|
||||
mov eax, [esi + VMMDEV_HEADER.rc]
|
||||
test eax, eax
|
||||
jnz .error
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] Guest info 2 sent (interface 0x%x)\n", VMMDEV_VERSION
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] send_guest_info_2 failed, rc=0x%x\n", eax
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
|
||||
.bad:
|
||||
mov eax, VERR_INVALID_PARAMETER
|
||||
ret
|
||||
endp
|
||||
51
drivers/vboxguest/vmmdev/hypervisor.inc
Normal file
51
drivers/vboxguest/vmmdev/hypervisor.inc
Normal file
@@ -0,0 +1,51 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Host/Hypervisor Info
|
||||
; Назначение : Получение информации о хосте (REQ 4: GetHostVersion)
|
||||
; Файл : vmmdev/hypervisor.inc
|
||||
; =============================================================================
|
||||
|
||||
; Отправить REQ 4 GetHostVersion, eax = header.rc
|
||||
proc vmmdev_get_host_version uses ebx edi
|
||||
mov edi, [vbox_device.host_version_virt]
|
||||
mov ebx, [vbox_device.host_version_phys]
|
||||
test edi, edi
|
||||
jz .bad
|
||||
test ebx, ebx
|
||||
jz .bad
|
||||
|
||||
stdcall vmmdev_send_request, ebx
|
||||
mov eax, [edi + VMMDEV_HEADER.rc]
|
||||
ret
|
||||
|
||||
.bad:
|
||||
mov eax, VERR_INVALID_POINTER
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
proc vmmdev_check_version uses ebx
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] Checking host version (GetHostVersion)...\n"
|
||||
|
||||
stdcall vmmdev_get_host_version
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] GetHostVersion rc=0x%x\n", eax
|
||||
test eax, eax
|
||||
jnz .error
|
||||
|
||||
mov eax, [vbox_device.host_version_virt]
|
||||
movzx ebx, [eax + VMMDEV_GET_HOST_VERSION.major]
|
||||
movzx ecx, [eax + VMMDEV_GET_HOST_VERSION.minor]
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] Host version: %d.%d.%d r%d features=0x%x\n", \
|
||||
ebx, ecx, \
|
||||
[eax + VMMDEV_GET_HOST_VERSION.build], \
|
||||
[eax + VMMDEV_GET_HOST_VERSION.revision], \
|
||||
[eax + VMMDEV_GET_HOST_VERSION.features]
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.error:
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] ERROR: GetHostVersion failed, rc=0x%x\n", eax
|
||||
mov eax, VERR_GENERAL_FAILURE
|
||||
ret
|
||||
endp
|
||||
169
drivers/vboxguest/vmmdev/packets.inc
Normal file
169
drivers/vboxguest/vmmdev/packets.inc
Normal file
@@ -0,0 +1,169 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Packets
|
||||
; Назначение : Выделение и инициализация пакетов VMMDev (одна страница 4KB)
|
||||
; Файл : vmmdev/packets.inc
|
||||
; =============================================================================
|
||||
|
||||
VMMDEV_PKT_OFS_HOST_VERSION = 0 ; sizeof.VMMDEV_GET_HOST_VERSION
|
||||
VMMDEV_PKT_OFS_GUEST_INFO = 64 ; sizeof.VMMDEV_REPORT_GUEST_INFO
|
||||
VMMDEV_PKT_OFS_GUEST_INFO2 = 128 ; sizeof.VMMDEV_REPORT_GUEST_INFO2 (~168)
|
||||
VMMDEV_PKT_OFS_CAPS = 320 ; sizeof.VMMDEV_SET_GUEST_CAPABILITIES2
|
||||
VMMDEV_PKT_OFS_FILTER = 384 ; sizeof.VMMDEV_CTL_GUEST_FILTER_MASK
|
||||
VMMDEV_PKT_OFS_ACK_EVENTS = 448 ; sizeof.VMMDEV_ACKNOWLEDGE_EVENTS
|
||||
|
||||
; Строка версии (read-only, для копирования в пакет)
|
||||
vmmdev_version_string db '1.0.0_KolibriOS', 0
|
||||
VMMDEV_VERSION_STRING_LEN = $ - vmmdev_version_string
|
||||
|
||||
; =============================================================================
|
||||
; vmmdev_init_packets — Выделить страницу и инициализировать все VMMDev пакеты
|
||||
; =============================================================================
|
||||
proc vmmdev_init_packets uses ebx ecx edx esi edi
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] Init packets (dynamic)\n"
|
||||
|
||||
; --- Выделить страницу ---
|
||||
invoke KernelAlloc, 4096
|
||||
test eax, eax
|
||||
jz .alloc_fail
|
||||
|
||||
mov [vbox_device.vmmdev_packets_page], eax
|
||||
|
||||
; Обнулить страницу
|
||||
mov edi, eax
|
||||
xor eax, eax
|
||||
mov ecx, 4096 / 4
|
||||
rep stosd
|
||||
|
||||
mov ebx, [vbox_device.vmmdev_packets_page]
|
||||
|
||||
; =================================================================
|
||||
; 1) HOST_VERSION (offset 0)
|
||||
; =================================================================
|
||||
lea edi, [ebx + VMMDEV_PKT_OFS_HOST_VERSION]
|
||||
mov dword [edi + VMMDEV_HEADER.size], sizeof.VMMDEV_GET_HOST_VERSION
|
||||
mov dword [edi + VMMDEV_HEADER.version], VMMDEV_REQUEST_HEADER_VERSION
|
||||
mov dword [edi + VMMDEV_HEADER.request_type], VMMDEV_REQ_GET_HOST_VERSION
|
||||
|
||||
mov [vbox_device.host_version_virt], edi
|
||||
mov eax, edi
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.host_version_phys], eax
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] HostVersion packet: virt=0x%x, phys=0x%x\n", \
|
||||
[vbox_device.host_version_virt], eax
|
||||
|
||||
; =================================================================
|
||||
; 2) REPORT_GUEST_INFO (offset 64)
|
||||
; =================================================================
|
||||
lea edi, [ebx + VMMDEV_PKT_OFS_GUEST_INFO]
|
||||
mov dword [edi + VMMDEV_HEADER.size], sizeof.VMMDEV_REPORT_GUEST_INFO
|
||||
mov dword [edi + VMMDEV_HEADER.version], VMMDEV_REQUEST_HEADER_VERSION
|
||||
mov dword [edi + VMMDEV_HEADER.request_type], VMMDEV_REQ_REPORT_GUEST_INFO
|
||||
mov dword [edi + VMMDEV_REPORT_GUEST_INFO.interface_version], VMMDEV_VERSION
|
||||
mov dword [edi + VMMDEV_REPORT_GUEST_INFO.os_type], VBOXOSTYPE_KOLIBRIOS
|
||||
|
||||
mov [vbox_device.guestinfo_virt], edi
|
||||
mov eax, edi
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.guestinfo_phys], eax
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] GuestInfo packet : virt=0x%x, phys=0x%x\n", \
|
||||
[vbox_device.guestinfo_virt], eax
|
||||
|
||||
; =================================================================
|
||||
; 3) REPORT_GUEST_INFO2 (offset 128)
|
||||
; =================================================================
|
||||
lea edi, [ebx + VMMDEV_PKT_OFS_GUEST_INFO2]
|
||||
mov dword [edi + VMMDEV_HEADER.size], sizeof.VMMDEV_REPORT_GUEST_INFO2
|
||||
mov dword [edi + VMMDEV_HEADER.version], VMMDEV_REQUEST_HEADER_VERSION
|
||||
mov dword [edi + VMMDEV_HEADER.request_type], VMMDEV_REQ_REPORT_GUEST_INFO2
|
||||
; rc, reserved1, f_requestor уже 0 (обнулено)
|
||||
; payload: версия заполняется из host_version в guest_info_2_report()
|
||||
mov dword [edi + VMMDEV_REPORT_GUEST_INFO2.guest_info + VMMDEV_GUEST_INFO2.additions_features], VBOXGSTINFO2_F_REQUESTOR_INFO
|
||||
; szName[128] — копируем строку версии
|
||||
push edi ecx
|
||||
lea edi, [edi + VMMDEV_REPORT_GUEST_INFO2.guest_info + VMMDEV_GUEST_INFO2.szName]
|
||||
mov esi, vmmdev_version_string
|
||||
mov ecx, VMMDEV_VERSION_STRING_LEN
|
||||
rep movsb
|
||||
pop ecx edi
|
||||
|
||||
lea eax, [ebx + VMMDEV_PKT_OFS_GUEST_INFO2]
|
||||
mov [vbox_device.guestinfo2_virt], eax
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.guestinfo2_phys], eax
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] GuestInfo2 packet : virt=0x%x, phys=0x%x\n", \
|
||||
[vbox_device.guestinfo2_virt], eax
|
||||
|
||||
; =================================================================
|
||||
; 4) SET_GUEST_CAPABILITIES2 (offset 320)
|
||||
; =================================================================
|
||||
lea edi, [ebx + VMMDEV_PKT_OFS_CAPS]
|
||||
mov dword [edi + VMMDEV_HEADER.size], sizeof.VMMDEV_SET_GUEST_CAPABILITIES2
|
||||
mov dword [edi + VMMDEV_HEADER.version], VMMDEV_REQUEST_HEADER_VERSION
|
||||
mov dword [edi + VMMDEV_HEADER.request_type], VMMDEV_SET_GUEST_CAPS
|
||||
mov dword [edi + VMMDEV_SET_GUEST_CAPABILITIES2.or_mask], VBOXGUEST_GUEST_CAPS_OR_MASK
|
||||
mov dword [edi + VMMDEV_SET_GUEST_CAPABILITIES2.not_mask], VBOXGUEST_GUEST_CAPS_NOT_MASK
|
||||
|
||||
mov [vbox_device.caps_virt], edi
|
||||
mov eax, edi
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.caps_phys], eax
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] Caps packet : virt=0x%x, phys=0x%x\n", \
|
||||
[vbox_device.caps_virt], eax
|
||||
|
||||
; =================================================================
|
||||
; 5) CTL_GUEST_FILTER_MASK (offset 384)
|
||||
; =================================================================
|
||||
lea edi, [ebx + VMMDEV_PKT_OFS_FILTER]
|
||||
mov dword [edi + VMMDEV_HEADER.size], sizeof.VMMDEV_CTL_GUEST_FILTER_MASK
|
||||
mov dword [edi + VMMDEV_HEADER.version], VMMDEV_REQUEST_HEADER_VERSION
|
||||
mov dword [edi + VMMDEV_HEADER.request_type], VMMDEV_REQ_CTL_GUEST_FILTER_MASK
|
||||
mov dword [edi + VMMDEV_CTL_GUEST_FILTER_MASK.or_mask], VBOXGUEST_EVENTS_OR_MASK
|
||||
mov dword [edi + VMMDEV_CTL_GUEST_FILTER_MASK.not_mask], VBOXGUEST_EVENTS_NOT_MASK
|
||||
|
||||
mov [vbox_device.filter_virt], edi
|
||||
mov eax, edi
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.filter_phys], eax
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] Filter packet : virt=0x%x, phys=0x%x\n", \
|
||||
[vbox_device.filter_virt], eax
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] Filter: OR=0x%x, NOT=0x%x\n", \
|
||||
[edi + VMMDEV_CTL_GUEST_FILTER_MASK.or_mask], \
|
||||
[edi + VMMDEV_CTL_GUEST_FILTER_MASK.not_mask]
|
||||
|
||||
; =================================================================
|
||||
; 6) ACKNOWLEDGE_EVENTS (offset 448)
|
||||
; =================================================================
|
||||
lea edi, [ebx + VMMDEV_PKT_OFS_ACK_EVENTS]
|
||||
mov dword [edi + VMMDEV_HEADER.size], sizeof.VMMDEV_ACKNOWLEDGE_EVENTS
|
||||
mov dword [edi + VMMDEV_HEADER.version], VMMDEV_REQUEST_HEADER_VERSION
|
||||
mov dword [edi + VMMDEV_HEADER.request_type], VMMDEV_REQ_ACKNOWLEDGE_EVENTS
|
||||
|
||||
mov [vbox_device.events_virt], edi
|
||||
mov eax, edi
|
||||
invoke GetPhysAddr
|
||||
mov [vbox_device.events_phys], eax
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] ACK packet : virt=0x%x, phys=0x%x\n", \
|
||||
[vbox_device.events_virt], eax
|
||||
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] Init packets success\n"
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.alloc_fail:
|
||||
DEBUGF 2, "[VBoxGuest] [VMMDev] ERROR: KernelAlloc failed for VMMDev packets\n"
|
||||
mov eax, VERR_NO_MEMORY
|
||||
ret
|
||||
endp
|
||||
|
||||
; =============================================================================
|
||||
; vmmdev_free_packets — Освободить страницу VMMDev пакетов
|
||||
; =============================================================================
|
||||
proc vmmdev_free_packets
|
||||
cmp dword [vbox_device.vmmdev_packets_page], 0
|
||||
je @f
|
||||
invoke KernelFree, [vbox_device.vmmdev_packets_page]
|
||||
mov dword [vbox_device.vmmdev_packets_page], 0
|
||||
@@:
|
||||
ret
|
||||
endp
|
||||
12
drivers/vboxguest/vmmdev/vmmdev.inc
Normal file
12
drivers/vboxguest/vmmdev/vmmdev.inc
Normal file
@@ -0,0 +1,12 @@
|
||||
; =============================================================================
|
||||
; Модуль : VMMDev Aggregator
|
||||
; Назначение : Подключение модулей протокола VMMDev
|
||||
; Файл : vmmdev/vmmdev.inc
|
||||
; =============================================================================
|
||||
|
||||
include 'vmmdev/packets.inc'
|
||||
include 'vmmdev/core.inc'
|
||||
include 'vmmdev/guest_info.inc'
|
||||
include 'vmmdev/capabilities.inc'
|
||||
include 'vmmdev/event_filter.inc'
|
||||
include 'vmmdev/hypervisor.inc'
|
||||
Reference in New Issue
Block a user