forked from KolibriOS/kolibrios
244 lines
7.8 KiB
HTML
244 lines
7.8 KiB
HTML
; =============================================================================
|
||
; Модуль : 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
|