diff options
author | Patrick Mooney <pmooney@pfmooney.com> | 2018-09-11 15:32:29 +0000 |
---|---|---|
committer | Patrick Mooney <pmooney@pfmooney.com> | 2018-10-04 18:58:47 +0000 |
commit | 4c14c4cff5adaaa79d7099e153c3ace3a0d65148 (patch) | |
tree | 9bbd6c76f695d66fd84448c3dd6b0c495815e61f | |
parent | 1f946b3740393b0dc458e4d386c40f40dd9b8465 (diff) | |
download | illumos-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.c | 164 | ||||
-rw-r--r-- | usr/src/lib/brand/bhyve/zone/boot.c | 40 |
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 || |