diff --git a/sys/dev/smbios/smbios_subr.c b/sys/dev/smbios/smbios_subr.c --- a/sys/dev/smbios/smbios_subr.c +++ b/sys/dev/smbios/smbios_subr.c @@ -39,11 +39,13 @@ #include -static const struct { - const char *vm_bname; +struct name_guest { + const char *name; int vm_guest; -} vm_bnames[] = { - { "QEMU", VM_GUEST_VM }, /* QEMU */ +}; + +static const struct name_guest vm_bnames[] = { + { "QEMU", VM_GUEST_QEMU }, /* QEMU */ { "Plex86", VM_GUEST_VM }, /* Plex86 */ { "Bochs", VM_GUEST_VM }, /* Bochs */ { "Xen", VM_GUEST_XEN }, /* Xen */ @@ -51,23 +53,72 @@ { "Seabios", VM_GUEST_KVM }, /* KVM */ }; -static const struct { - const char *vm_pname; - int vm_guest; -} vm_pnames[] = { +static const struct name_guest vm_pnames[] = { { "VMware Virtual Platform", VM_GUEST_VMWARE }, { "Virtual Machine", VM_GUEST_VM }, /* Microsoft VirtualPC */ - { "QEMU Virtual Machine", VM_GUEST_VM }, { "VirtualBox", VM_GUEST_VBOX }, - { "Parallels Virtual Platform", VM_GUEST_PARALLELS }, { "KVM", VM_GUEST_KVM }, }; +static const struct name_guest vm_pname_prefixes[] = { + { "QEMU", VM_GUEST_QEMU }, + { "Parallels", VM_GUEST_PARALLELS }, +}; + +static const struct name_guest vm_mnames[] = { + { "QEMU", VM_GUEST_QEMU }, +}; + + +typedef bool match_func(const char *_provided, const char *_known); + +static bool +name_match(const char *provided, const char *known) +{ + return (strcmp(provided, known) == 0); +} + +static bool +prefix_match(const char *provided, const char *known) +{ + return (strncmp(provided, known, strlen(known)) == 0); +} + +static int +match_in_map(const char *const name, const struct name_guest *const map, + const size_t map_len, match_func *const match) +{ + for (size_t i = 0; i < map_len; ++i) + if (match(name, map[i].name)) + return (map[i].vm_guest); + return (VM_GUEST_NO); +} + +static int +name_to_guest(const char *const name, const struct name_guest *const map, + const size_t map_size) +{ + return (match_in_map(name, map, map_size, name_match)); +} + +#define NAME_TO_GUEST(name, map) \ + (name_to_guest((name), (map), nitems(map))) + +static int +prefix_to_guest(const char *const name, const struct name_guest *const map, + const size_t map_len) +{ + return (match_in_map(name, map, map_len, prefix_match)); +} + +#define PREFIX_TO_GUEST(name, map) \ + (prefix_to_guest((name), (map), nitems(map))) + void identify_hypervisor_smbios(void) { - char *p; - int i; + char *p = NULL; + int cand; /* * Some platforms, e.g., amd64, have other ways of detecting what kind @@ -77,36 +128,44 @@ if (vm_guest != VM_GUEST_NO && vm_guest != VM_GUEST_VM) return; - /* - * XXX: Some of these entries may not be needed since they were - * added to FreeBSD before the checks above. - */ - p = kern_getenv("smbios.bios.vendor"); + p = kern_getenv("smbios.system.maker"); if (p != NULL) { - for (i = 0; i < nitems(vm_bnames); i++) - if (strcmp(p, vm_bnames[i].vm_bname) == 0) { - vm_guest = vm_bnames[i].vm_guest; - /* If we have a specific match, return */ - if (vm_guest != VM_GUEST_VM) { - freeenv(p); - return; - } - /* - * We are done with bnames, but there might be - * a more specific match in the pnames - */ - break; - } + cand = NAME_TO_GUEST(p, vm_mnames); + if (cand != VM_GUEST_NO) + goto found; + freeenv(p); + p = NULL; } + p = kern_getenv("smbios.system.product"); if (p != NULL) { - for (i = 0; i < nitems(vm_pnames); i++) - if (strcmp(p, vm_pnames[i].vm_pname) == 0) { - vm_guest = vm_pnames[i].vm_guest; - freeenv(p); - return; - } + cand = NAME_TO_GUEST(p, vm_pnames); + if (cand != VM_GUEST_NO) + goto found; + + cand = PREFIX_TO_GUEST(p, vm_pname_prefixes); + if (cand != VM_GUEST_NO) + goto found; + freeenv(p); + p = NULL; } + + p = kern_getenv("smbios.bios.vendor"); + if (p != NULL) { + cand = NAME_TO_GUEST(p, vm_bnames); + if (cand != VM_GUEST_NO) + goto found; + + freeenv(p); + p = NULL; + } + + return; + +found: + MPASS(cand != VM_GUEST_NO); + vm_guest = cand; + freeenv(p); } diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c --- a/sys/kern/subr_param.c +++ b/sys/kern/subr_param.c @@ -158,6 +158,7 @@ [VM_GUEST_VBOX] = "vbox", [VM_GUEST_PARALLELS] = "parallels", [VM_GUEST_NVMM] = "nvmm", + [VM_GUEST_QEMU] = "qemu", }; _Static_assert(nitems(vm_guest_sysctl_names) == VM_GUEST_LAST, "new vm guest type not added to vm_guest_sysctl_names"); diff --git a/sys/sys/systm.h b/sys/sys/systm.h --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -79,7 +79,8 @@ */ enum VM_GUEST { VM_GUEST_NO = 0, VM_GUEST_VM, VM_GUEST_XEN, VM_GUEST_HV, VM_GUEST_VMWARE, VM_GUEST_KVM, VM_GUEST_BHYVE, VM_GUEST_VBOX, - VM_GUEST_PARALLELS, VM_GUEST_NVMM, VM_GUEST_LAST }; + VM_GUEST_PARALLELS, VM_GUEST_NVMM, VM_GUEST_QEMU, + VM_GUEST_LAST }; #endif /* KERNEL */