diff --git a/include/kernel.h b/include/kernel.h index c800a894..7ef5b901 100755 --- a/include/kernel.h +++ b/include/kernel.h @@ -34,6 +34,7 @@ extern "C" { #include "kernel/vbe.h" #include "kernel/vdisk.h" #include "kernel/virtio.h" +#include "kernel/vmtools.h" #include "kernel/vsound.h" #ifdef __cplusplus } diff --git a/include/kernel/pci.h b/include/kernel/pci.h index 560a14c3..f8ad58ac 100755 --- a/include/kernel/pci.h +++ b/include/kernel/pci.h @@ -27,7 +27,7 @@ struct pci_config_space_public { u8 MaxLatency; }; -void init_pci(void *adder_Base); +void pci_init(); void pci_classcode_print(const struct pci_config_space_public *pci_config_space_puclic); int pci_get_device(int vendor_id, int device_id, int subsystem_id, u8 *bus, u8 *slot, u8 *func); u32 read_bar_n(u8 bus, u8 device, u8 function, u8 bar_n); diff --git a/include/kernel/ps2.h b/include/kernel/ps2.h index aad60924..f3b01c3b 100755 --- a/include/kernel/ps2.h +++ b/include/kernel/ps2.h @@ -25,3 +25,17 @@ int getch(); extern struct MOUSE_DEC mdec; void mouse_ready(struct MOUSE_DEC *mdec); + +typedef struct PointerEvent { + usize device_id; // 设备 ID 不可用默认为 0 + usize pointer_id; // 指针 ID 不可用默认为 0 + u32 buttons; // 指针的按钮按下状态,每一位代表一个按钮 + u32 x; // 指针指向的 x 位置 + u32 y; // 指针指向的 y 位置 + float xratio; // 指针指向的 x 位置的比例 + float yratio; // 指针指向的 y 位置的比例 + u32 width; // 指针接触范围的宽度 + u32 height; // 指针接触范围的高度 + f32 pressure; // 压力 (0 - 1) 不可用默认为 0.5 + f32 twist; // 指针设备的朝向 (0 - 2 * PI) 不可用默认为 0 +} PointerEvent; diff --git a/include/kernel/vmtools.h b/include/kernel/vmtools.h new file mode 100644 index 00000000..3b87f301 --- /dev/null +++ b/include/kernel/vmtools.h @@ -0,0 +1,36 @@ +#pragma once +#include + +#define vmware_send(cmd, arg) \ + ({ \ + const u32 _cmd_ = (cmd); \ + const u32 _arg_ = (arg); \ + struct { \ + u32 eax, ebx, ecx, edx, esi, edi; \ + } _564D5868_ = {0x564D5868, _arg_, _cmd_, 0x5658, 0, 0}; \ + asm volatile("in %%dx, %%eax\n\t" \ + : "+a"(_564D5868_.eax), "+b"(_564D5868_.ebx), "+c"(_564D5868_.ecx), \ + "+d"(_564D5868_.edx), "+S"(_564D5868_.esi), "+D"(_564D5868_.edi)); \ + _564D5868_; \ + }) + +#define vm_is_vmware (vmware_send(0x0A, 0).ebx == 0x564D5868) + +enum hypervisor_id { + HYPERVISOR_UNKNOWN, + HYPERVISOR_KVM, + HYPERVISOR_KVM_HV, + HYPERVISOR_QEMU, + HYPERVISOR_VMWARE, + HYPERVISOR_VBOX, + HYPERVISOR_HYPERV, +}; + +extern enum hypervisor_id hypervisor_id; + +// 注意非 vmwware 的虚拟机也有可能提供 vmware backdoor +extern bool vmware_backdoor_available; + +void detect_hypervisor(); + +void vmtools_init(); diff --git a/src/kernel/drivers/general/pci.c b/src/kernel/drivers/general/pci.c index 5bb39b99..ec052ab1 100755 --- a/src/kernel/drivers/general/pci.c +++ b/src/kernel/drivers/general/pci.c @@ -124,10 +124,12 @@ void pci_config(u32 bus, u32 f, u32 equipment, u32 adder) { // TODO 重构循环体到新函数 -void init_pci(void *addr_base) { - pci_addr_base = addr_base; +void pci_init() { + pci_addr_base = page_alloc(1 * 1024 * 1024); + kassert(pci_addr_base != null, "Out of memory"); + u32 i, bus, equipment, func, addr, *i1; - u8 *pci_dat = (void *)addr_base, *pci_dat1; + u8 *pci_dat = (void *)pci_addr_base, *pci_dat1; for (bus = 0; bus < 256; bus++) { //查询总线 for (equipment = 0; equipment < 32; equipment++) { //查询设备 for (func = 0; func < 8; func++) { //查询功能 diff --git a/src/kernel/drivers/general/vmtools.c b/src/kernel/drivers/general/vmtools.c new file mode 100644 index 00000000..b006f9b0 --- /dev/null +++ b/src/kernel/drivers/general/vmtools.c @@ -0,0 +1,87 @@ +#include + +bool vmware_backdoor_available = false; + +enum hypervisor_id hypervisor_id = HYPERVISOR_UNKNOWN; + +static void detect_hypervisor_id() { + static const struct { + const void *key; + enum hypervisor_id value; + } hypervisor_ids[] = { + {"KVMKVMKVM\0\0\0", HYPERVISOR_KVM }, + {"Linux KVM Hv", HYPERVISOR_KVM_HV}, + {"TCGTCGTCGTCG", HYPERVISOR_QEMU }, + {"VMwareVMware", HYPERVISOR_VMWARE}, + {"VBoxVBoxVBox", HYPERVISOR_VBOX }, + {"Microsoft Hv", HYPERVISOR_HYPERV}, + }; + for (usize i = 0; i < lengthof(hypervisor_ids); i++) { + if (memeq(cpuids.hypervisor_id, hypervisor_ids[i].key, 12)) { + hypervisor_id = hypervisor_ids[i].value; + return; + } + } +} + +void detect_hypervisor() { + detect_hypervisor_id(); + vmware_backdoor_available = vm_is_vmware; +} + +static inthandler_f inthandler2c; + +static void *ps2_mouse_handler = null; + +static void vmware_mouse_init() { + // 取消鼠标捕获 + vmware_send(41, 0x45414552); + vmware_send(40, 0); + vmware_send(39, 1); + vmware_send(41, 0x53424152); + ps2_mouse_handler = inthandler_set(0x2c, inthandler2c); +} + +static void vmware_mouse_deinit() { + vmware_send(41, 0xF5); + inthandler_set(0x2c, ps2_mouse_handler); +} + +void vmtools_init() { + if (vmware_backdoor_available) { + vmware_mouse_init(); // + } +} + +static PointerEvent event; + +static FASTCALL void inthandler2c(i32 id, regs32 *regs) { + asm_in8(PORT_KEYDAT); + + val status = vmware_send(40, 0); + + if (status.eax == 0xFFFF0000) { + klogw("VMware mouse data error"); + vmware_mouse_deinit(); + vmware_mouse_init(); + return; + } + + if ((status.eax & 0xFFFF) < 4) return; + + val data = vmware_send(39, 4); + + val flags = (data.eax & 0xFFFF0000) >> 16; /* Not important */ + val buttons = data.eax & 0xFFFF; /* 0x10 = Right, 0x20 = Left, 0x08 = Middle */ + val x = data.ebx; /* Both X and Y are scaled from 0 to 0xFFFF */ + val y = data.ecx; /* You should map these somewhere to the actual resolution. */ + val z = (i8)data.edx; /* Z is a single signed byte indicating scroll direction. */ + klogd("mouse x: %d, y: %d, z: %d", x, y, z); + + event.buttons = 0; + if (buttons & 0x20) event.buttons |= MASK(0); + if (buttons & 0x08) event.buttons |= MASK(1); + if (buttons & 0x10) event.buttons |= MASK(2); + event.xratio = (f32)x / 0xFFFF; + event.yratio = (f32)y / 0xFFFF; +} diff --git a/src/kernel/drivers/input/keyboard.c b/src/kernel/drivers/input/keyboard.c index 965094ed..bb6ce962 100755 --- a/src/kernel/drivers/input/keyboard.c +++ b/src/kernel/drivers/input/keyboard.c @@ -34,11 +34,11 @@ static inthandler_f inthandler21; // 初始化键盘控制电路 void keyboard_init() { inthandler_set(0x21, inthandler21); + irq_enable(1); ps2_wait(); asm_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); ps2_wait(); asm_out8(PORT_KEYDAT, KBC_MODE); - irq_enable(1); } int getch() { diff --git a/src/kernel/drivers/input/mouse.c b/src/kernel/drivers/input/mouse.c index f7b36c40..af17f9a9 100755 --- a/src/kernel/drivers/input/mouse.c +++ b/src/kernel/drivers/input/mouse.c @@ -41,6 +41,7 @@ static void mouse_reset() { void mouse_init() { inthandler_set(0x2c, inthandler2c); + irq_enable(12); ps2_wait(); asm_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); ps2_wait(); @@ -52,7 +53,7 @@ void mouse_init() { mouse_write(0xf3); mouse_write(80); mouse_write(0xf2); - klogd("mouseId=%d\n", mouse_read()); + klogd("mouseId=%d", mouse_read()); /* 顺利的话,键盘控制器会返回ACK(0xfa) */ } @@ -66,6 +67,8 @@ void mouse_ready(struct MOUSE_DEC *mdec) { mdec->sleep = 0; } +void update_mouse() {} + int mouse_decode(struct MOUSE_DEC *mdec, u8 dat) { if (mdec->phase == 1) { if (dat == 0xfa) { // ACK @@ -109,5 +112,5 @@ int mouse_decode(struct MOUSE_DEC *mdec, u8 dat) { static FASTCALL void inthandler2c(i32 id, regs32 *regs) { byte data = asm_in8(PORT_KEYDAT); - klogd("mouse data=%02x\n", data); + klogd("mouse data=%02x", data); } diff --git a/src/kernel/init/init.c b/src/kernel/init/init.c index d8409983..40144460 100755 --- a/src/kernel/init/init.c +++ b/src/kernel/init/init.c @@ -10,30 +10,8 @@ void abort() { } } -#define vmware_send(cmd, arg) \ - ({ \ - __SIZE_TYPE__ eax = 0x564D5868; \ - __SIZE_TYPE__ ebx = (arg); \ - __SIZE_TYPE__ ecx = (cmd); \ - __SIZE_TYPE__ edx = 0x5658; \ - asm volatile("in %%dx, %%eax\n\t" : "+a"(eax), "+b"(ebx), "+c"(ecx), "+d"(edx)); \ - ebx; \ - }) - -#define vm_is_vmware() \ - ({ \ - __SIZE_TYPE__ eax = 0x564D5868; \ - __SIZE_TYPE__ ebx = 0; \ - __SIZE_TYPE__ ecx = 0x0A; \ - __SIZE_TYPE__ edx = 0x5658; \ - asm volatile("in %%dx, %%eax\n\t" : "+a"(eax), "+b"(ebx), "+c"(ecx), "+d"(edx)); \ - ebx == 0x564D5868; \ - }) - void serial_init(); -bool vmware_backdoor_available = false; - void sysinit() { klogi("kernel is starting"); @@ -67,39 +45,19 @@ void sysinit() { //+ ========== vm ========== - if (memeq(cpuids.hypervisor_id, "KVMKVMKVM", 9)) { - klogi("You are running on KVM."); // - } - - if (memeq(cpuids.hypervisor_id, "Linux KVM Hv", 12)) { - klogi("You are running on KVM (Hyper-V emulation)."); // - } - - if (memeq(cpuids.hypervisor_id, "TCGTCGTCGTCG", 12)) { - klogi("You are running on QEMU."); // - } - - if (memeq(cpuids.hypervisor_id, "VMwareVMware", 12)) { - klogi("You are running on VMware."); // - } + detect_hypervisor(); - if (memeq(cpuids.hypervisor_id, "VBoxVBoxVBox", 12)) { - klogi("You are running on VBox."); // + switch (hypervisor_id) { + case HYPERVISOR_KVM: klogi("You are running on KVM."); break; + case HYPERVISOR_KVM_HV: klogi("You are running on KVM (Hyper-V emulation)."); break; + case HYPERVISOR_QEMU: klogi("You are running on QEMU."); break; + case HYPERVISOR_VMWARE: klogi("You are running on VMware."); break; + case HYPERVISOR_VBOX: klogi("You are running on VBox."); break; + case HYPERVISOR_HYPERV: klogi("You are running on Hyper-V."); break; + default: break; } - if (memeq(cpuids.hypervisor_id, "Microsoft Hv", 9)) { - klogi("You are running on Hyper-V."); // - } - - if (vm_is_vmware()) { - klogi("VMware Backdoor available."); // - } - - // 取消鼠标捕获 - vmware_send(41, 0x45414552); - vmware_send(40, 0); - vmware_send(39, 1); - vmware_send(41, 0x53424152); + if (vmware_backdoor_available) klogi("VMware Backdoor available."); //+ ========== VT-x / AMD-V ========== @@ -132,7 +90,7 @@ void sysinit() { init_tty(); screen_clear(); - init_pci(page_alloc(1 * 1024 * 1024)); + pci_init(); virtio_init(); virtio_gpu_init(); @@ -158,4 +116,6 @@ void sysinit() { keyboard_init(); mouse_init(); + + vmtools_init(); } diff --git a/src/loader/driver/pci.c b/src/loader/driver/pci.c index 2f903619..6e02d972 100755 --- a/src/loader/driver/pci.c +++ b/src/loader/driver/pci.c @@ -75,7 +75,7 @@ void pci_config(u32 bus, u32 f, u32 equipment, u32 adder) { // cmd = cmd | 0x01; asm_out32(PCI_COMMAND_PORT, cmd); } -void init_pci(u32 adder_Base) { +void pci_init(u32 adder_Base) { u32 i, BUS, Equipment, F, ADDER, *i1; u8 *PCI_DATA = (u8 *)adder_Base, *PCI_DATA1; for (BUS = 0; BUS < 256; BUS++) { // 查询总线