Files
kolibrios/drivers/vboxguest/services/clipboard/clipboard.inc
2026-03-04 21:16:17 +03:00

221 lines
7.7 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
; =============================================================================
; Модуль : 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