diff --git a/deps/hypervisor/bfdriver/src/common.c b/deps/hypervisor/bfdriver/src/common.c index 2e0ccdf7f..0181fdcbf 100644 --- a/deps/hypervisor/bfdriver/src/common.c +++ b/deps/hypervisor/bfdriver/src/common.c @@ -43,10 +43,18 @@ int g_enable_winpv = 0; int g_disable_xen_pfd = 0; int g_enable_xue = 0; +#define PCI_PT_CLASS_LIST_SIZE 14 +uint64_t pci_pt_class_list[PCI_PT_CLASS_LIST_SIZE]; +uint64_t pci_pt_class_count = 0; + #define NO_PCI_PT_LIST_SIZE 256 uint64_t no_pci_pt_list[NO_PCI_PT_LIST_SIZE]; uint64_t no_pci_pt_count = 0; +#define PCI_PT_LIST_SIZE 256 +uint64_t pci_pt_list[PCI_PT_LIST_SIZE]; +uint64_t pci_pt_count = 0; + #ifdef USE_XUE struct xue g_xue; struct xue_ops g_xue_ops; @@ -525,6 +533,16 @@ common_load_vmm(void) goto failure; } + for (i = 0; i < pci_pt_class_count; i++) { + ret = platform_call_vmm_on_core(0, + BF_REQUEST_PCI_PT_CLASS, + pci_pt_class_list[i], + 0); + if (ret != BF_SUCCESS) { + goto failure; + } + } + for (i = 0; i < no_pci_pt_count; i++) { ret = platform_call_vmm_on_core(0, BF_REQUEST_NO_PCI_PT, @@ -535,6 +553,16 @@ common_load_vmm(void) } } + for (i = 0; i < pci_pt_class_count; i++) { + ret = platform_call_vmm_on_core(0, + BF_REQUEST_PCI_PT, + pci_pt_list[i], + 0); + if (ret != BF_SUCCESS) { + goto failure; + } + } + ret = private_add_modules_mdl(); if (ret != BF_SUCCESS) { goto failure; diff --git a/deps/hypervisor/bfdriver/src/platform/efi/entry.c b/deps/hypervisor/bfdriver/src/platform/efi/entry.c index 17eef8d24..ebad55573 100644 --- a/deps/hypervisor/bfdriver/src/platform/efi/entry.c +++ b/deps/hypervisor/bfdriver/src/platform/efi/entry.c @@ -55,17 +55,32 @@ struct pmodule_t pmodules[MAX_NUM_MODULES] = {{0}}; static const CHAR16 *opt_disable_xen_pfd = L"--disable-xen-pfd"; static const CHAR16 *opt_enable_winpv = L"--enable-winpv"; static const CHAR16 *opt_disable_winpv = L"--disable-winpv"; +static const CHAR16 *opt_pci_pt_class = L"--pci-pt-class"; static const CHAR16 *opt_no_pci_pt = L"--no-pci-pt"; +static const CHAR16 *opt_pci_pt = L"--pci-pt"; static const CHAR16 *opt_enable_xue = L"--enable-xue"; +#define PCI_PT_CLASS_LIST_SIZE 14 +extern uint64_t pci_pt_class_list[PCI_PT_CLASS_LIST_SIZE]; +extern uint64_t pci_pt_class_count; + #define NO_PCI_PT_LIST_SIZE 256 extern uint64_t no_pci_pt_list[NO_PCI_PT_LIST_SIZE]; extern uint64_t no_pci_pt_count; +#define PCI_PT_LIST_SIZE 256 +extern uint64_t pci_pt_list[PCI_PT_LIST_SIZE]; +extern uint64_t pci_pt_count; + #ifndef EFI_BOOT_NEXT #define EFI_BOOT_NEXT L"\\EFI\\boot\\bootx64.efi" #endif +#define EFI_CONFIG_FILE_MAX_SIZE (EFI_PAGE_SIZE >> 2) +#ifndef EFI_CONFIG_FILE_PATH +#define EFI_CONFIG_FILE_PATH L"\\EFI\\boot\\bareflank.cfg" +#endif + void unmap_vmm_from_root_domain(void); static int64_t @@ -251,77 +266,264 @@ load_start_vm(EFI_HANDLE ParentImage) return EFI_ABORTED; } -void parse_cmdline(EFI_HANDLE image) +static uint64_t bdf_str_to_uint(const CHAR16 *bdf_str) { - INTN argc, i; - CHAR16 **argv; + UINTN bdf_len = StrLen(bdf_str); - argc = GetShellArgcArgv(image, &argv); + if (bdf_len != 7) { + BFALERT("Invalid BDF string size: %u\n", bdf_len); + BFALERT(" usage: --no-pci-pt BB:DD.F\n"); + return -1ULL; + } + + CHAR8 bus_str[16]; + CHAR8 dev_str[16]; + CHAR8 fun_str[16]; + + ZeroMem(bus_str, 16); + ZeroMem(dev_str, 16); + ZeroMem(fun_str, 16); + + CopyMem(bus_str, bdf_str, 4); + CopyMem(dev_str, (char *)bdf_str + 6, 4); + CopyMem(fun_str, (char *)bdf_str + 12, 2); + + UINTN bus = xtoi((CHAR16 *)bus_str); + UINTN dev = xtoi((CHAR16 *)dev_str); + UINTN fun = xtoi((CHAR16 *)fun_str); - for (i = 0; i < argc; i++) { - if (!StrnCmp(opt_enable_xue, argv[i], StrLen(opt_enable_xue))) { - Print(L"Enabling Xue USB Debugger\n"); + if (bus > 255 || dev > 31 || fun > 7) { + BFALERT("BDF out of range: bus=%lx, dev=%lx, fun=%lx\n", + bus, dev, fun); + return -1ULL; + } + + return (bus << 16) | (dev << 11) | (fun << 8); +} + +void parse_cmdline(INTN argc, CHAR16 **argv) +{ + INTN i; + + if (argc <= 1) { + return; + } + + for (i = 1; i < argc; i++) { + if (!StrnCmp(opt_enable_xue, argv[i], StrLen(opt_enable_xue) + 1)) { + BFINFO("Enabling Xue USB Debugger\n"); g_enable_xue = 1; + continue; } - if (!StrnCmp(opt_enable_winpv, argv[i], StrLen(opt_enable_winpv))) { - Print(L"Enabling Windows PV\n"); + if (!StrnCmp(opt_enable_winpv, argv[i], StrLen(opt_enable_winpv) + 1)) { + BFINFO("Enabling Windows PV\n"); g_enable_winpv = 1; + continue; } - if (!StrnCmp(opt_disable_winpv, argv[i], StrLen(opt_disable_winpv))) { - Print(L"Disabling Windows PV\n"); + if (!StrnCmp(opt_disable_winpv, argv[i], StrLen(opt_disable_winpv) + 1)) { + BFINFO("Disabling Windows PV\n"); g_enable_winpv = 0; + continue; } - if (!StrnCmp(opt_disable_xen_pfd, argv[i], StrLen(opt_disable_xen_pfd))) { - Print(L"Disabling Xen Platform PCI device\n"); + if (!StrnCmp(opt_disable_xen_pfd, argv[i], StrLen(opt_disable_xen_pfd) + 1)) { + BFINFO("Disabling Xen Platform PCI device\n"); g_disable_xen_pfd = 1; + continue; } - if (!StrnCmp(opt_no_pci_pt, argv[i], StrLen(opt_no_pci_pt))) { + if (!StrnCmp(opt_pci_pt_class, argv[i], StrLen(opt_pci_pt_class) + 1)) { if (i >= argc - 1) { + BFALERT("Missing class value\n"); + BFALERT(" usage: --pci-pt-class n\n"); continue; } - CHAR16 *bdf_str = argv[i + 1]; - UINTN bdf_len = StrLen(bdf_str); + CHAR16 *class_str = argv[i + 1]; + UINTN class_len = StrLen(class_str); - if (bdf_len != 7) { - Print(L"Invalid BDF string size: %u\n", bdf_len); - Print(L" usage: --no-pci-pt BB:DD.F\n"); + if (class_len != 1 && class_len != 2) { + BFALERT("Invalid class string size: %u\n", class_len); + BFALERT(" usage: --pci-pt-class n\n"); continue; } - CHAR8 bus_str[16]; - CHAR8 dev_str[16]; - CHAR8 fun_str[16]; + UINTN pci_class = Atoi((CHAR16 *) argv[i+1]); + pci_pt_class_list[pci_pt_class_count] = pci_class; + pci_pt_class_count++; - ZeroMem(bus_str, 16); - ZeroMem(dev_str, 16); - ZeroMem(fun_str, 16); + BFINFO("Enabling passthrough for PCI class %ld\n", pci_class); - CopyMem(bus_str, bdf_str, 4); - CopyMem(dev_str, (char *)bdf_str + 6, 4); - CopyMem(fun_str, (char *)bdf_str + 12, 2); + i++; + continue; + } - UINTN bus = xtoi((CHAR16 *)bus_str); - UINTN dev = xtoi((CHAR16 *)dev_str); - UINTN fun = xtoi((CHAR16 *)fun_str); + if (!StrnCmp(opt_no_pci_pt, argv[i], StrLen(opt_no_pci_pt) + 1)) { + if (i >= argc - 1) { + continue; + } - if (bus > 255 || dev > 31 || fun > 7) { - Print(L"BDF out of range: bus=%lx, dev=%lx, fun=%lx\n", - bus, dev, fun); + uint64_t bdf = bdf_str_to_uint(argv[i + 1]); + if (bdf == -1ULL) { continue; } - no_pci_pt_list[no_pci_pt_count] = - (bus << 16) | (dev << 11) | (fun << 8); + no_pci_pt_list[no_pci_pt_count] = bdf; no_pci_pt_count++; - Print(L"Disabling passthrough for %02x:%02x.%02x\n", bus, dev, fun); + BFINFO("Disabling passthrough for %02x:%02x.%02x\n", + (bdf & 0x00FF0000) >> 16, + (bdf & 0x0000F800) >> 11, + (bdf & 0x00000700) >> 8); + + i++; + continue; + } + + if (!StrnCmp(opt_pci_pt, argv[i], StrLen(opt_pci_pt) + 1)) { + if (i >= argc - 1) { + continue; + } + + uint64_t bdf = bdf_str_to_uint(argv[i + 1]); + if (bdf == -1ULL) { + continue; + } + + pci_pt_list[pci_pt_count] = bdf; + pci_pt_count++; + + BFINFO("Enabling passthrough for %02x:%02x.%02x\n", + (bdf & 0x00FF0000) >> 16, + (bdf & 0x0000F800) >> 11, + (bdf & 0x00000700) >> 8); + + i++; + continue; + } + + BFALERT("Ignoring unknown argument: "); + Print(L"%s\n", argv[i]); + } +} + +static UINTN read_file(EFI_LOADED_IMAGE *image, const CHAR16 *path, void **buffer) +{ + UINTN size = 0; + EFI_HANDLE dev_hdl; + SIMPLE_READ_FILE read_hdl; + char *buf_tmp = NULL; + const unsigned buf_size = 512; + UINTN file_buf_size = 0; + UINTN read_size = buf_size; + + EFI_DEVICE_PATH *fd_path = FileDevicePath(image->DeviceHandle, (CHAR16 *) path); + EFI_STATUS status = OpenSimpleReadFile(FALSE, NULL, 0, &fd_path, &dev_hdl, &read_hdl); + gBS->FreePool(fd_path); + + if (EFI_ERROR(status)) { + return 0; + } + + while(read_size == buf_size) { + read_size = buf_size; + file_buf_size = size + buf_size; + buf_tmp = ReallocatePool(buf_tmp, size, file_buf_size); + status = ReadSimpleReadFile(read_hdl, size, &read_size, buf_tmp + size); + + size += read_size; + + if (EFI_ERROR(status)) { + BFALERT("OpenSimpleReadFile: failed to read chunk (%r)\n", status); + } + } + + buf_tmp = ReallocatePool(buf_tmp, file_buf_size, size); + *buffer = buf_tmp; + + return size; +} + +/** + * Reads an ascii config file and builds a unicode cmdline string. + * Lines starting with `#` are ignored and whitespaces are removed. + * Returns the number of arguments argc and sets argv to an array of arguments + * with argv[0] set to arg0. + */ +static INTN get_args_from_cfg(EFI_HANDLE hdl, CHAR16 *arg0, CHAR16 **argv[]) +{ + EFI_LOADED_IMAGE* image; + INTN argc = 0; + UINTN size_ascii = 0; + char *buf_ascii = NULL; + char *buf_unicode = NULL; + char **buf_argv = NULL; + UINTN i = 0; + UINTN j = 0; + BOOLEAN in_comment = FALSE; + BOOLEAN in_whitespace = TRUE; /* or start */ + + gBS->HandleProtocol(hdl, &LoadedImageProtocol, (void**)&image); + + size_ascii = read_file(image, EFI_CONFIG_FILE_PATH, (void**) &buf_ascii); + if (size_ascii > EFI_CONFIG_FILE_MAX_SIZE) { + BFDEBUG("get_args_from_cfg: config file size of %d bytes is too large\n", size_ascii); + return 0; + } + + /* Build unicode cmdline argc argv: */ + + buf_unicode = AllocatePool(size_ascii << 1); + buf_argv = AllocatePool(size_ascii >> 1); + buf_argv[argc++] = (char *) arg0; + + for (; i < size_ascii; i++) { + switch(buf_ascii[i]) { + case '\n': /* 10 */ + if (in_comment) { + in_comment = FALSE; + } + /* fall through */ + case '\t': /* 9 */ + /* fall through */ + case ' ': /* 32 */ + in_whitespace = TRUE; + continue; + case '!' ... '~': /* 33 ... 126: main ascii chars */ + if (buf_ascii[i] == '#') { + in_comment = TRUE; + continue; + } + break; + default: + continue; } + + if (in_comment) { + continue; + } + + if (in_whitespace) { + in_whitespace = FALSE; + buf_unicode[j++] = '\0'; + buf_unicode[j++] = '\0'; + buf_argv[argc++] = &buf_unicode[j]; + } + + buf_unicode[j++] = buf_ascii[i]; + buf_unicode[j++] = '\0'; } + + buf_unicode[j++] = '\0'; + buf_unicode[j++] = '\0'; + + *argv = (CHAR16 **) buf_argv; + + gBS->FreePool(buf_ascii); + + return argc; } /* -------------------------------------------------------------------------- */ @@ -331,6 +533,9 @@ void parse_cmdline(EFI_HANDLE image) EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { + INTN argc; + CHAR16 **argv; + InitializeLib(image, systab); if (common_init() != BF_SUCCESS) { @@ -338,7 +543,18 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) } g_enable_winpv = 1; - parse_cmdline(image); + + argc = GetShellArgcArgv(image, &argv); + if (argc <= 1) { + /* Read config file */ + argc = get_args_from_cfg(image, argv[0], &argv); + if (argc > 1) { + Print(L"[BAREFLANK INFO]: Reading config file from %s\n", EFI_CONFIG_FILE_PATH); + } else { + BFDEBUG("No cmdline and no config file!\n"); + } + } + parse_cmdline(argc, argv); #ifdef USE_XUE if (g_enable_xue) { diff --git a/deps/hypervisor/bfintrinsics/include/intrinsics.h b/deps/hypervisor/bfintrinsics/include/intrinsics.h index d5e1282f3..f75063253 100644 --- a/deps/hypervisor/bfintrinsics/include/intrinsics.h +++ b/deps/hypervisor/bfintrinsics/include/intrinsics.h @@ -31,7 +31,9 @@ inline bool g_uefi_boot = false; inline bool g_enable_winpv = false; inline bool g_disable_xen_pfd = false; inline bool g_enable_xue = false; +inline std::unordered_set g_pci_pt_class; inline std::unordered_set g_no_pci_pt; +inline std::unordered_set g_pci_pt; #ifdef BF_X64 #include diff --git a/deps/hypervisor/bfsdk/include/bfdebug.h b/deps/hypervisor/bfsdk/include/bfdebug.h index f9589a3a7..e4c05d35a 100644 --- a/deps/hypervisor/bfsdk/include/bfdebug.h +++ b/deps/hypervisor/bfsdk/include/bfdebug.h @@ -1244,10 +1244,11 @@ bfdebug_exception(const std::exception &e) #if defined(KERNEL) && defined(EFI) #include "efi.h" #include "efilib.h" -#define BFINFO(...) Print(L__VA_ARGS__) -#define BFDEBUG(...) Print(L"[BAREFLANK DEBUG]: " __VA_ARGS__) -#define BFALERT(...) Print(L"[BAREFLANK ALERT]: " __VA_ARGS__) -#define BFERROR(...) Print(L"[BAREFLANK ERROR]: " __VA_ARGS__) + +#define BFINFO(...) APrint((const CHAR8 *) __VA_ARGS__) +#define BFDEBUG(...) APrint((const CHAR8 *) "[BAREFLANK DEBUG]: " __VA_ARGS__) +#define BFALERT(...) APrint((const CHAR8 *) "[BAREFLANK ALERT]: " __VA_ARGS__) +#define BFERROR(...) APrint((const CHAR8 *) "[BAREFLANK ERROR]: " __VA_ARGS__) #endif /** @endcond */ diff --git a/deps/hypervisor/bfsdk/include/bfsupport.h b/deps/hypervisor/bfsdk/include/bfsupport.h index 5fea143e4..6f4ae41c4 100644 --- a/deps/hypervisor/bfsdk/include/bfsupport.h +++ b/deps/hypervisor/bfsdk/include/bfsupport.h @@ -181,6 +181,8 @@ struct crt_info_t { #define BF_REQUEST_UEFI_BOOT 8 #define BF_REQUEST_WINPV 9 #define BF_REQUEST_NO_PCI_PT 10 +#define BF_REQUEST_PCI_PT_CLASS 11 +#define BF_REQUEST_PCI_PT 12 #define BF_REQUEST_END 0xFFFF /* @endcond */ diff --git a/deps/hypervisor/bfvmm/src/entry/entry.cpp b/deps/hypervisor/bfvmm/src/entry/entry.cpp index 7ab79a2be..c7d626456 100644 --- a/deps/hypervisor/bfvmm/src/entry/entry.cpp +++ b/deps/hypervisor/bfvmm/src/entry/entry.cpp @@ -129,6 +129,13 @@ private_winpv(bool enable_winpv, bool disable_xen_pfd) noexcept return ENTRY_SUCCESS; } +extern "C" int64_t +private_pci_pt_class(uint8_t pci_class) noexcept +{ + g_pci_pt_class.emplace((uint32_t)pci_class); + return ENTRY_SUCCESS; +} + extern "C" int64_t private_no_pci_pt(uint64_t bdf) noexcept { @@ -136,6 +143,13 @@ private_no_pci_pt(uint64_t bdf) noexcept return ENTRY_SUCCESS; } +extern "C" int64_t +private_pci_pt(uint64_t bdf) noexcept +{ + g_pci_pt.emplace((1UL << 31) | (uint32_t)bdf); + return ENTRY_SUCCESS; +} + extern "C" int64_t private_init_vmm(uint64_t arg) noexcept { @@ -218,6 +232,12 @@ bfmain(uintptr_t request, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) case BF_REQUEST_NO_PCI_PT: return private_no_pci_pt(arg1); + case BF_REQUEST_PCI_PT_CLASS: + return private_pci_pt_class(arg1); + + case BF_REQUEST_PCI_PT: + return private_pci_pt(arg1); + default: break; } diff --git a/vmm/src/pci.cpp b/vmm/src/pci.cpp index 74efaf0e4..cd16b49c1 100644 --- a/vmm/src/pci.cpp +++ b/vmm/src/pci.cpp @@ -174,7 +174,9 @@ static void probe_bus(uint32_t b, struct pci_dev *bridge) for (auto next = secondary; next <= subordinate; next++) { probe_bus(next, pdev); } - } else if (pdev->is_netdev()) { + } else if (pdev->is_netdev() && + g_pci_pt_class.count(pci_cc_network) || + g_pci_pt.count(addr)) { if (g_no_pci_pt.count(addr)) { printv("pci: %s: passthrough disabled via boot option\n", pdev->bdf_str());