summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <pmooney@pfmooney.com>2018-09-11 15:32:29 +0000
committerPatrick Mooney <pmooney@pfmooney.com>2018-10-04 18:58:47 +0000
commit4c14c4cff5adaaa79d7099e153c3ace3a0d65148 (patch)
tree9bbd6c76f695d66fd84448c3dd6b0c495815e61f
parent1f946b3740393b0dc458e4d386c40f40dd9b8465 (diff)
downloadillumos-joyent-4c14c4cff5adaaa79d7099e153c3ace3a0d65148.tar.gz
OS-7238 bhyve zones should add hostbridge device
Reviewed by: Mike Gerdts <mike.gerdts@joyent.com> Reviewed by: Jorge Schrauwen <jorge@blackdot.be> Reviewed by: Hans Rosenfeld <hans.rosenfeld@joyent.com> Approved by: Hans Rosenfeld <hans.rosenfeld@joyent.com>
-rw-r--r--usr/src/cmd/bhyve/pci_hostbridge.c164
-rw-r--r--usr/src/lib/brand/bhyve/zone/boot.c40
2 files changed, 203 insertions, 1 deletions
diff --git a/usr/src/cmd/bhyve/pci_hostbridge.c b/usr/src/cmd/bhyve/pci_hostbridge.c
index 559496a9fe..b926c7817e 100644
--- a/usr/src/cmd/bhyve/pci_hostbridge.c
+++ b/usr/src/cmd/bhyve/pci_hostbridge.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2011 NetApp, Inc.
+ * Copyright (c) 2018 Joyent, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,10 +30,17 @@
*/
#include <sys/cdefs.h>
+#ifndef __FreeBSD__
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#endif
__FBSDID("$FreeBSD$");
#include "pci_emul.h"
+#ifdef __FreeBSD__
static int
pci_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
{
@@ -58,6 +66,162 @@ pci_amd_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
return (0);
}
+#else
+static void
+pci_hostbridge_setup(struct pci_devinst *pi, uint16_t vendor, uint16_t device)
+{
+ /* config space */
+ pci_set_cfgdata16(pi, PCIR_VENDOR, vendor);
+ pci_set_cfgdata16(pi, PCIR_DEVICE, device);
+ pci_set_cfgdata8(pi, PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL);
+ pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE);
+ pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_HOST);
+
+ pci_emul_add_pciecap(pi, PCIEM_TYPE_ROOT_PORT);
+}
+
+
+static int
+pci_hostbridge_parse_pci_val(const char *in, uint16_t *val)
+{
+ long num;
+ char *endp = NULL;
+
+ errno = 0;
+ num = strtol(in, &endp, 0);
+ if (errno != 0 || endp == NULL || *endp != '\0') {
+ fprintf(stderr, "pci_hostbridge: invalid num '%s'", in);
+ return (-1);
+ } else if (num < 1 || num > UINT16_MAX) {
+ fprintf(stderr, "pci_hostbridge: 0x%04lx out of range", num);
+ return (-1);
+ }
+ *val = num;
+ return (0);
+}
+
+static struct pci_hostbridge_model {
+ const char *phm_model;
+ uint16_t phm_vendor;
+ uint16_t phm_device;
+} pci_hb_models[] = {
+ { "amd", 0x1022, 0x7432 }, /* AMD/made-up */
+ { "netapp", 0x1275, 0x1275 }, /* NetApp/NetApp */
+ { "i440fx", 0x8086, 0x1237 }, /* Intel/82441 */
+ { "q35", 0x8086, 0x29b0 }, /* Intel/Q35 HB */
+};
+
+#define NUM_HB_MODELS (sizeof (pci_hb_models) / sizeof (pci_hb_models[0]))
+
+static int
+pci_hostbridge_parse_args(char *opts, uint16_t *vendorp, uint16_t *devicep)
+{
+ const char *model = NULL;
+ char *next;
+ uint16_t vendor = 0, device = 0;
+ int err = 0;
+
+ for (; opts != NULL && *opts != '\0'; opts = next) {
+ char *val, *cp;
+
+ if ((cp = strchr(opts, ',')) != NULL) {
+ *cp = '\0';
+ next = cp + 1;
+ } else {
+ next = NULL;
+ }
+
+ if ((cp = strchr(opts, '=')) == NULL) {
+ fprintf(stderr,
+ "pci_hostbridge: expected value for param"
+ " (%s=VAL)", opts);
+ err = -1;
+ continue;
+ }
+
+ /* <param>=<value> handling */
+ val = cp + 1;
+ *cp = '\0';
+ if (strcmp(opts, "model") == 0) {
+ model = val;
+ } else if (strcmp(opts, "vendor") == 0) {
+ if (pci_hostbridge_parse_pci_val(val, &vendor) != 0) {
+ err = -1;
+ continue;
+ }
+ } else if (strcmp(opts, "device") == 0) {
+ if (pci_hostbridge_parse_pci_val(val, &device) != 0) {
+ err = -1;
+ continue;
+ }
+ } else {
+ fprintf(stderr,
+ "pci_hostbridge: unrecognized option '%s'", opts);
+ err = -1;
+ continue;
+ }
+ }
+ if (err != 0) {
+ return (err);
+ }
+
+ if (model != NULL && (vendor != 0 || device != 0)) {
+ fprintf(stderr, "pci_hostbridge: cannot specify model "
+ "and vendor/device");
+ return (-1);
+ } else if ((vendor != 0 && device == 0) ||
+ (vendor == 0 && device != 0)) {
+ fprintf(stderr, "pci_hostbridge: must specify both vendor and"
+ "device for custom hostbridge");
+ return (-1);
+ }
+ if (model != NULL) {
+ uint_t i;
+
+ for (i = 0; i < NUM_HB_MODELS; i++) {
+ if (strcmp(model, pci_hb_models[i].phm_model) != 0)
+ continue;
+
+ /* found a model match */
+ *vendorp = pci_hb_models[i].phm_vendor;
+ *devicep = pci_hb_models[i].phm_device;
+ return (0);
+ }
+ fprintf(stderr, "pci_hostbridge: invalid model '%s'", model);
+ return (-1);
+ }
+
+ /* custom hostbridge ID was specified */
+ *vendorp = vendor;
+ *devicep = device;
+ return (0);
+}
+
+static int
+pci_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
+{
+ uint16_t vendor, device;
+
+ if (opts == NULL) {
+ /* Fall back to NetApp default if no options are specified */
+ vendor = 0x1275;
+ device = 0x1275;
+ } else if (pci_hostbridge_parse_args(opts, &vendor, &device) != 0) {
+ return (-1);
+ }
+
+ pci_hostbridge_setup(pi, vendor, device);
+ return (0);
+}
+
+static int
+pci_amd_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
+{
+ pci_hostbridge_setup(pi, 0x1022, 0x7432);
+ return (0);
+}
+
+#endif /* __FreeBSD__ */
struct pci_devemu pci_de_amd_hostbridge = {
.pe_emu = "amd_hostbridge",
diff --git a/usr/src/lib/brand/bhyve/zone/boot.c b/usr/src/lib/brand/bhyve/zone/boot.c
index 1adea7b26f..58160a88cc 100644
--- a/usr/src/lib/brand/bhyve/zone/boot.c
+++ b/usr/src/lib/brand/bhyve/zone/boot.c
@@ -42,7 +42,7 @@
#define DEFAULT_BOOTROM_CSM "/usr/share/bhyve/uefi-csm-rom.bin"
typedef enum {
- PCI_SLOT_HOSTBRIDGE = 0, /* Not used here, but reserved */
+ PCI_SLOT_HOSTBRIDGE = 0,
PCI_SLOT_CD = 3, /* Windows ahci allows slots 3 - 6 */
PCI_SLOT_BOOT_DISK,
PCI_SLOT_OTHER_DISKS,
@@ -449,6 +449,43 @@ add_lpc(int *argc, char **argv)
}
static int
+add_hostbridge(int *argc, char **argv)
+{
+ char conf[MAXPATHLEN];
+ char *model = NULL;
+ boolean_t raw_config = B_FALSE;
+
+ if ((model = get_zcfg_var("attr", "hostbridge", NULL)) != NULL) {
+ /* Easy bypass for doing testing */
+ if (strcmp("none", model) == 0) {
+ return (0);
+ }
+
+ if (strchr(model, '=') != NULL) {
+ /*
+ * If the attribute contains '=', assume the creator
+ * wants total control over the config. Do not prepend
+ * the value with 'model='.
+ */
+ raw_config = B_TRUE;
+ }
+ }
+
+ /* Default to Natoma if nothing else is specified */
+ if (model == NULL) {
+ model = "i440fx";
+ }
+
+ (void) snprintf(conf, sizeof (conf), "%d,hostbridge,%s%s",
+ PCI_SLOT_HOSTBRIDGE, raw_config ? "" : "model=", model);
+ if (add_arg(argc, argv, "-s") != 0 ||
+ add_arg(argc, argv, conf) != 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+static int
add_bhyve_extra_opts(int *argc, char **argv)
{
char *val;
@@ -624,6 +661,7 @@ main(int argc, char **argv)
if (add_smbios(&zhargc, (char **)&zhargv) != 0 ||
add_lpc(&zhargc, (char **)&zhargv) != 0 ||
+ add_hostbridge(&zhargc, (char **)&zhargv) != 0 ||
add_cpu(&zhargc, (char **)&zhargv) != 0 ||
add_ram(&zhargc, (char **)&zhargv) != 0 ||
add_devices(&zhargc, (char **)&zhargv) != 0 ||