Skip to content

Instantly share code, notes, and snippets.

@Risca
Last active December 15, 2021 04:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Risca/5c52f5cd17c4e6e91785d7ba9ef8adc5 to your computer and use it in GitHub Desktop.
Save Risca/5c52f5cd17c4e6e91785d7ba9ef8adc5 to your computer and use it in GitHub Desktop.
This adds support to qemu for bifferboard
Index: host-qemu-5.2.0/default-configs/devices/i386-softmmu.mak
===================================================================
--- host-qemu-5.2.0.orig/default-configs/devices/i386-softmmu.mak
+++ host-qemu-5.2.0/default-configs/devices/i386-softmmu.mak
@@ -27,5 +27,6 @@
#
CONFIG_ISAPC=y
CONFIG_I440FX=y
+CONFIG_RDC3210=y
CONFIG_Q35=y
CONFIG_MICROVM=y
Index: host-qemu-5.2.0/hw/block/pflash_cfi02.c
===================================================================
--- host-qemu-5.2.0.orig/hw/block/pflash_cfi02.c
+++ host-qemu-5.2.0/hw/block/pflash_cfi02.c
@@ -97,7 +97,7 @@ struct PFlashCFI02 {
uint16_t ident3;
uint16_t unlock_addr0;
uint16_t unlock_addr1;
- uint8_t cfi_table[0x4d];
+ uint8_t cfi_table[0x50];
QEMUTimer timer;
/* The device replicates the flash memory across its memory space. Emulate
* that by having a container (.mem) filled with an array of aliases
@@ -315,12 +315,14 @@ static uint64_t pflash_read(void *opaque
pflash_register_memory(pfl, 1);
}
offset &= pfl->chip_len - 1;
- boff = offset & 0xFF;
- if (pfl->width == 2) {
+ boff = offset;
+ if (width == 2) {
boff = boff >> 1;
- } else if (pfl->width == 4) {
+ } else if (width == 4) {
boff = boff >> 2;
}
+ /* Only the least-significant 11 bits are used in most cases. */
+ boff &= 0x7FF;
switch (pfl->cmd) {
default:
/* This should never happen : reset state & treat it as a read*/
@@ -350,10 +352,18 @@ static uint64_t pflash_read(void *opaque
ret = boff & 0x01 ? pfl->ident1 : pfl->ident0;
break;
case 0x02:
- ret = 0x00; /* Pretend all sectors are unprotected */
+ // TODO: check if offset == sector address instead of this
+ if (width == pfl->width) {
+ ret = 0x00; /* Pretend all sectors are unprotected */
+ }
+ else {
+ ret = pfl->ident1 & ((1 << (width * 8)) - 1);
+ }
break;
case 0x0E:
case 0x0F:
+ case 0x100:
+ case 0x200:
ret = boff & 0x01 ? pfl->ident3 : pfl->ident2;
if (ret != (uint8_t)-1) {
break;
@@ -831,6 +841,7 @@ static void pflash_cfi02_realize(DeviceS
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
timer_init_ns(&pfl->timer, QEMU_CLOCK_VIRTUAL, pflash_timer, pfl);
+ pfl->bypass = 0;
pfl->wcycle = 0;
pfl->cmd = 0;
pfl->status = 0;
@@ -926,7 +937,9 @@ static void pflash_cfi02_realize(DeviceS
pfl->cfi_table[0x0b + pri_ofs] = 0x00;
/* Page mode not supported. */
pfl->cfi_table[0x0c + pri_ofs] = 0x00;
- assert(0x0c + pri_ofs < ARRAY_SIZE(pfl->cfi_table));
+ /* Top/bottom boot sector */
+ pfl->cfi_table[0x0f + pri_ofs] = 0x02;
+ assert(0x0f + pri_ofs < ARRAY_SIZE(pfl->cfi_table));
}
static Property pflash_cfi02_properties[] = {
Index: host-qemu-5.2.0/hw/i386/Kconfig
===================================================================
--- host-qemu-5.2.0.orig/hw/i386/Kconfig
+++ host-qemu-5.2.0/hw/i386/Kconfig
@@ -119,6 +119,12 @@ config AMD_IOMMU
bool
select X86_IOMMU
+config RDC3210
+ bool
+ imply R6040_PCI
+ select I440FX
+ select PFLASH_CFI02
+
config VMPORT
bool
Index: host-qemu-5.2.0/hw/i386/meson.build
===================================================================
--- host-qemu-5.2.0.orig/hw/i386/meson.build
+++ host-qemu-5.2.0/hw/i386/meson.build
@@ -13,6 +13,7 @@ i386_ss.add(when: 'CONFIG_AMD_IOMMU', if
i386_ss.add(when: 'CONFIG_I440FX', if_true: files('pc_piix.c'))
i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('microvm.c', 'acpi-microvm.c'))
i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c'))
+i386_ss.add(when: 'CONFIG_RDC3210', if_true: files('rdc3210.c'))
i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c'))
i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c'))
i386_ss.add(when: 'CONFIG_VTD', if_true: files('intel_iommu.c'))
Index: host-qemu-5.2.0/hw/i386/rdc3210.c
===================================================================
--- /dev/null
+++ host-qemu-5.2.0/hw/i386/rdc3210.c
@@ -0,0 +1,411 @@
+/*
+ * QEMU RDC3210 PC System Emulator
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include CONFIG_DEVICES
+
+#include "qemu/units.h"
+#include "hw/loader.h"
+#include "hw/i386/x86.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/apic.h"
+#include "hw/pci-host/i440fx.h"
+#include "hw/southbridge/piix.h"
+#include "hw/display/ramfb.h"
+#include "hw/firmware/smbios.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/usb.h"
+#include "hw/ide/pci.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "net/net.h"
+#include "sysemu/kvm.h"
+#include "sysemu/block-backend.h"
+#include "hw/kvm/clock.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "sysemu/arch_init.h"
+#include "hw/i2c/smbus_eeprom.h"
+#include "hw/xen/xen-x86.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "e820_memory_layout.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/pc-hotplug.h"
+#include "cpu.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "sysemu/xen.h"
+#include "migration/global_state.h"
+#include "migration/misc.h"
+#include "sysemu/numa.h"
+#include "hw/hyperv/vmbus-bridge.h"
+#include "hw/mem/nvdimm.h"
+#include "hw/i386/acpi-build.h"
+
+#define MAX_IDE_BUS 2
+
+#define FLASH_EN29LV640_BASE (0xff800000)
+#define FLASH_EN29LV640_SIZE (0x800000)
+static void bifferboard_flash_init(MemoryRegion *rom_memory)
+{
+ DriveInfo *dinfo;
+ BlockBackend *blk;
+ DeviceState *dev;
+
+ dev = qdev_new(TYPE_PFLASH_CFI02);
+
+ dinfo = drive_get(IF_PFLASH, 0, 0);
+ blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
+ if (blk) {
+ char devpath[100];
+ hwaddr addr = (hwaddr)(FLASH_EN29LV640_BASE + FLASH_EN29LV640_SIZE - 64*1024);
+
+ snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr);
+ add_boot_device_path(-1, NULL, devpath);
+
+ /* Set blk as backing file */
+ qdev_prop_set_drive(dev, "drive", blk);
+ }
+ else {
+ warn_report("No firmware backing file set! Set one with '%s'",
+ "-drive file=firmware.img,if=pflash,format=raw");
+ /* Try to load biffboot from "-bios" command line */
+ x86_bios_rom_init(rom_memory, false);
+ }
+
+ // Last 64K is organized as 8 * 8K
+ qdev_prop_set_uint32(dev, "num-blocks0", (FLASH_EN29LV640_SIZE - 0x10000) / 0x10000);
+ qdev_prop_set_uint32(dev, "sector-length0", 0x10000);
+ qdev_prop_set_uint32(dev, "num-blocks1", 8);
+ qdev_prop_set_uint32(dev, "sector-length1", 0x2000);
+ qdev_prop_set_uint8(dev, "width", 2); // 16 bit
+ qdev_prop_set_uint8(dev, "mappings", 1);
+ qdev_prop_set_uint8(dev, "big-endian", 0);
+ qdev_prop_set_uint16(dev, "id0", 0x007F);
+ qdev_prop_set_uint16(dev, "id1", 0x22CB);
+ qdev_prop_set_uint16(dev, "id2", 0x001C);
+ qdev_prop_set_uint16(dev, "id3", 0x0000);
+ qdev_prop_set_uint16(dev, "unlock-addr0", 0x0555);
+ qdev_prop_set_uint16(dev, "unlock-addr1", 0x02aa);
+ qdev_prop_set_string(dev, "name", "en29lv640.0");
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_EN29LV640_BASE);
+}
+
+static void rdc_memory_init(PCMachineState *pcms,
+ MemoryRegion *system_memory,
+ MemoryRegion *rom_memory,
+ MemoryRegion **ram_memory)
+{
+ MemoryRegion *ram_below_4g, *ram_above_4g;
+ MachineState *machine = MACHINE(pcms);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
+ X86MachineState *x86ms = X86_MACHINE(pcms);
+
+ assert(machine->ram_size == x86ms->below_4g_mem_size +
+ x86ms->above_4g_mem_size);
+
+ /*
+ * Split single memory region and use aliases to address portions of it,
+ * done for backwards compatibility with older qemus.
+ */
+ *ram_memory = machine->ram;
+ ram_below_4g = g_malloc(sizeof(*ram_below_4g));
+ memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", machine->ram,
+ 0, x86ms->below_4g_mem_size);
+ memory_region_add_subregion(system_memory, 0, ram_below_4g);
+ e820_add_entry(0, x86ms->below_4g_mem_size, E820_RAM);
+ if (x86ms->above_4g_mem_size > 0) {
+ ram_above_4g = g_malloc(sizeof(*ram_above_4g));
+ memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g",
+ machine->ram,
+ x86ms->below_4g_mem_size,
+ x86ms->above_4g_mem_size);
+ memory_region_add_subregion(system_memory, 0x100000000ULL,
+ ram_above_4g);
+ e820_add_entry(0x100000000ULL, x86ms->above_4g_mem_size, E820_RAM);
+ }
+
+ if (!pcmc->has_reserved_memory &&
+ (machine->ram_slots ||
+ (machine->maxram_size > machine->ram_size))) {
+
+ error_report("\"-memory 'slots|maxmem'\" is not supported by: %s",
+ mc->name);
+ exit(EXIT_FAILURE);
+ }
+
+ /* always allocate the device memory information */
+ machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
+
+ /* initialize device memory address space */
+ if (pcmc->has_reserved_memory &&
+ (machine->ram_size < machine->maxram_size)) {
+ ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
+
+ if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
+ error_report("unsupported amount of memory slots: %"PRIu64,
+ machine->ram_slots);
+ exit(EXIT_FAILURE);
+ }
+
+ if (QEMU_ALIGN_UP(machine->maxram_size,
+ TARGET_PAGE_SIZE) != machine->maxram_size) {
+ error_report("maximum memory size must by aligned to multiple of "
+ "%d bytes", TARGET_PAGE_SIZE);
+ exit(EXIT_FAILURE);
+ }
+
+ machine->device_memory->base =
+ ROUND_UP(0x100000000ULL + x86ms->above_4g_mem_size, 1 * GiB);
+
+ if (pcmc->enforce_aligned_dimm) {
+ /* size device region assuming 1G page max alignment per slot */
+ device_mem_size += (1 * GiB) * machine->ram_slots;
+ }
+
+ if ((machine->device_memory->base + device_mem_size) <
+ device_mem_size) {
+ error_report("unsupported amount of maximum memory: " RAM_ADDR_FMT,
+ machine->maxram_size);
+ exit(EXIT_FAILURE);
+ }
+
+ memory_region_init(&machine->device_memory->mr, OBJECT(pcms),
+ "device-memory", device_mem_size);
+ memory_region_add_subregion(system_memory, machine->device_memory->base,
+ &machine->device_memory->mr);
+ }
+
+ bifferboard_flash_init(rom_memory);
+ pc_system_flash_cleanup_unused(pcms);
+
+ /* Init default IOAPIC address space */
+ x86ms->ioapic_as = &address_space_memory;
+
+ /* Init ACPI memory hotplug IO base address */
+ pcms->memhp_io_base = ACPI_MEMORY_HOTPLUG_BASE;
+}
+
+/* PC hardware initialisation */
+static void pc_init1(MachineState *machine,
+ const char *host_type, const char *pci_type)
+{
+ PCMachineState *pcms = PC_MACHINE(machine);
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
+ X86MachineState *x86ms = X86_MACHINE(machine);
+ MemoryRegion *system_memory = get_system_memory();
+ MemoryRegion *system_io = get_system_io();
+ PCIBus *pci_bus;
+ PIIX3State *piix3;
+ ISABus *isa_bus;
+ PCII440FXState *i440fx_state;
+ int piix3_devfn = -1;
+ GSIState *gsi_state;
+ ISADevice *rtc_state;
+ MemoryRegion *ram_memory;
+ MemoryRegion *pci_memory;
+ MemoryRegion *rom_memory;
+ ram_addr_t lowmem;
+
+ /*
+ * Calculate ram split, for memory below and above 4G. It's a bit
+ * complicated for backward compatibility reasons ...
+ *
+ * - Traditional split is 3.5G (lowmem = 0xe0000000). This is the
+ * default value for max_ram_below_4g now.
+ *
+ * - Then, to gigabyte align the memory, we move the split to 3G
+ * (lowmem = 0xc0000000). But only in case we have to split in
+ * the first place, i.e. ram_size is larger than (traditional)
+ * lowmem. And for new machine types (gigabyte_align = true)
+ * only, for live migration compatibility reasons.
+ *
+ * - Next the max-ram-below-4g option was added, which allowed to
+ * reduce lowmem to a smaller value, to allow a larger PCI I/O
+ * window below 4G. qemu doesn't enforce gigabyte alignment here,
+ * but prints a warning.
+ *
+ * - Finally max-ram-below-4g got updated to also allow raising lowmem,
+ * so legacy non-PAE guests can get as much memory as possible in
+ * the 32bit address space below 4G.
+ *
+ * - Note that Xen has its own ram setup code in xen_ram_init(),
+ * called via xen_hvm_init_pc().
+ *
+ * Examples:
+ * qemu -M pc-1.7 -m 4G (old default) -> 3584M low, 512M high
+ * qemu -M pc -m 4G (new default) -> 3072M low, 1024M high
+ * qemu -M pc,max-ram-below-4g=2G -m 4G -> 2048M low, 2048M high
+ * qemu -M pc,max-ram-below-4g=4G -m 3968M -> 3968M low (=4G-128M)
+ */
+ if (!pcms->max_ram_below_4g) {
+ pcms->max_ram_below_4g = 0xe0000000; /* default: 3.5G */
+ }
+ lowmem = pcms->max_ram_below_4g;
+ if (machine->ram_size >= pcms->max_ram_below_4g) {
+ if (pcmc->gigabyte_align) {
+ if (lowmem > 0xc0000000) {
+ lowmem = 0xc0000000;
+ }
+ if (lowmem & (1 * GiB - 1)) {
+ warn_report("Large machine and max_ram_below_4g "
+ "(%" PRIu64 ") not a multiple of 1G; "
+ "possible bad performance.",
+ pcms->max_ram_below_4g);
+ }
+ }
+ }
+
+ if (machine->ram_size >= lowmem) {
+ x86ms->above_4g_mem_size = machine->ram_size - lowmem;
+ x86ms->below_4g_mem_size = lowmem;
+ } else {
+ x86ms->above_4g_mem_size = 0;
+ x86ms->below_4g_mem_size = machine->ram_size;
+ }
+
+ x86_cpus_init(x86ms, pcmc->default_cpu_version);
+
+ if (pcmc->kvmclock_enabled) {
+ kvmclock_create(pcmc->kvmclock_create_always);
+ }
+
+ pci_memory = g_new(MemoryRegion, 1);
+ memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
+ rom_memory = pci_memory;
+
+ pc_guest_info_init(pcms);
+
+ if (pcmc->smbios_defaults) {
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ /* These values are guest ABI, do not change */
+ smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
+ mc->name, pcmc->smbios_legacy_mode,
+ pcmc->smbios_uuid_encoded,
+ SMBIOS_ENTRY_POINT_21);
+ }
+
+ /* allocate ram and load rom/bios */
+ rdc_memory_init(pcms, system_memory, rom_memory, &ram_memory);
+
+ gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled);
+
+ pci_bus = i440fx_init(host_type,
+ pci_type,
+ &i440fx_state,
+ system_memory, system_io, machine->ram_size,
+ x86ms->below_4g_mem_size,
+ x86ms->above_4g_mem_size,
+ pci_memory, ram_memory);
+ pcms->bus = pci_bus;
+
+ piix3 = piix3_create(pci_bus, &isa_bus);
+ piix3->pic = x86ms->gsi;
+ piix3_devfn = piix3->dev.devfn;
+
+ isa_bus_irqs(isa_bus, x86ms->gsi);
+
+ pc_i8259_create(isa_bus, gsi_state->i8259_irq);
+
+ ioapic_init_gsi(gsi_state, "i440fx");
+
+ if (tcg_enabled()) {
+ x86_register_ferr_irq(x86ms->gsi[13]);
+ }
+
+ assert(pcms->vmport != ON_OFF_AUTO__MAX);
+ if (pcms->vmport == ON_OFF_AUTO_AUTO) {
+ pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
+ }
+
+ /* init basic PC hardware */
+ pc_basic_device_init(pcms, isa_bus, x86ms->gsi, &rtc_state, true,
+ 0x4);
+
+ pc_nic_init(pcmc, isa_bus, pci_bus);
+
+ if (pcmc->pci_enabled) {
+ PCIDevice *dev;
+ BusState *idebus[MAX_IDE_BUS];
+
+ dev = pci_create_simple(pci_bus, piix3_devfn + 1,
+ xen_enabled() ? "piix3-ide-xen" : "piix3-ide");
+ pci_ide_create_devs(dev);
+ idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
+ idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
+ pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
+ }
+
+ if (pcmc->pci_enabled && machine_usb(machine)) {
+ pci_create_simple(pci_bus, piix3_devfn + 2, "pci-ohci");
+ }
+
+ if (pcmc->pci_enabled && x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) {
+ DeviceState *piix4_pm;
+ qemu_irq smi_irq;
+
+ smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
+ /* TODO: Populate SPD eeprom data. */
+ pcms->smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+ x86ms->gsi[9], smi_irq,
+ x86_machine_is_smm_enabled(x86ms),
+ &piix4_pm);
+ smbus_eeprom_init(pcms->smbus, 8, NULL, 0);
+
+ object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
+ TYPE_HOTPLUG_HANDLER,
+ (Object **)&x86ms->acpi_dev,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
+ object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
+ OBJECT(piix4_pm), &error_abort);
+ }
+}
+
+static void rdc3210_machine_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ pcmc->default_nic_model = "e1000";
+ m->family = "pc_piix";
+ m->desc = "RDC3210";
+ m->default_machine_opts = "firmware=bios-256k.bin";
+ m->default_display = NULL;
+ machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
+ machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
+ m->alias = "rdc3210";
+ m->is_default = false;
+ pcmc->default_cpu_version = 1;
+}
+
+static void pc_init_rdc3210(MachineState *machine) \
+{
+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE,
+ TYPE_I440FX_PCI_DEVICE);
+}
+
+DEFINE_PC_MACHINE(rdc3210, "rdc-3210", pc_init_rdc3210,
+ rdc3210_machine_options);
Index: host-qemu-5.2.0/hw/net/Kconfig
===================================================================
--- host-qemu-5.2.0.orig/hw/net/Kconfig
+++ host-qemu-5.2.0/hw/net/Kconfig
@@ -49,6 +49,11 @@ config RTL8139_PCI
default y if PCI_DEVICES
depends on PCI
+config R6040_PCI
+ bool
+ default y if PCI_DEVICES
+ depends on PCI
+
config VMXNET3_PCI
bool
default y if PCI_DEVICES
Index: host-qemu-5.2.0/hw/net/meson.build
===================================================================
--- host-qemu-5.2.0.orig/hw/net/meson.build
+++ host-qemu-5.2.0/hw/net/meson.build
@@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_E1000_PCI',
softmmu_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
softmmu_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: files('e1000e.c', 'e1000e_core.c', 'e1000x_common.c'))
softmmu_ss.add(when: 'CONFIG_RTL8139_PCI', if_true: files('rtl8139.c'))
+softmmu_ss.add(when: 'CONFIG_R6040_PCI', if_true: files('r6040.c'))
softmmu_ss.add(when: 'CONFIG_TULIP', if_true: files('tulip.c'))
softmmu_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
softmmu_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('vmxnet3.c'))
Index: host-qemu-5.2.0/hw/net/r6040.c
===================================================================
--- /dev/null
+++ host-qemu-5.2.0/hw/net/r6040.c
@@ -0,0 +1,685 @@
+/*
+ * Emulation of r6040 ethernet controller found in a number of SoCs.
+ * Copyright (c) 2011 Mark Kelly, mark@bifferos.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * This has been written using the R8610[1] and ip101a[2] datasheets.
+ *
+ * ICs with the embedded controller include R8610, R3210, AMRISC20000
+ * and Vortex86SX
+ *
+ * The emulation seems good enough to fool Linux 2.6.37.6. It is
+ * not perfect, but has proven useful.
+ *
+ * [1] http://www.sima.com.tw/download/R8610_D06_20051003.pdf
+ * [2] http://www.icplus.com.tw/pp-IP101A.html
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/pci/pci.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "qemu/timer.h"
+
+/* #define DEBUG_R6040 1 */
+
+
+#if defined DEBUG_R6040
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stderr, "R6040: " fmt, ## __VA_ARGS__); } while (0)
+#else
+static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)
+{
+ return 0;
+}
+#endif
+
+#define TYPE_R6040 "r6040"
+
+OBJECT_DECLARE_SIMPLE_TYPE(R6040State, R6040)
+
+/* Cast in order of appearance. _W suffix means it's used to index the
+ register word array (regs_w)
+ */
+
+#define MPSCCR_W (0x88 / 2)
+
+#define MAC0_W (0x68 / 2)
+#define MAC1_W (0x6a / 2)
+#define MAC2_W (0x6c / 2)
+
+
+#define RX_START_LOW_W (0x34 / 2)
+#define RX_START_HIGH_W (0x38 / 2)
+#define TX_PKT_COUNT_W (0x5a / 2)
+#define RX_PKT_COUNT_W (0x50 / 2)
+
+
+#define MCR0_W (0x00 / 2)
+#define MCR1_W (0x04 / 2)
+#define BIT_MRST (1 << 0)
+
+#define MTPR_W (0x14 / 2)
+#define MRBSR_W (0x18 / 2)
+#define MISR_W (0x3c / 2)
+#define MIER_W (0x40 / 2)
+
+#define MMDIO_W (0x20 / 2)
+#define MDIO_READ_W (0x24 / 2)
+#define MDIO_WRITE_W (0x28 / 2)
+
+#define MRCNT_W (0x50 / 2)
+#define MTCNT_W (0x5c / 2)
+
+
+#define MDIO_WRITE 0x4000
+#define MDIO_READ 0x2000
+
+
+typedef struct R6040State {
+ PCIDevice dev;
+ NICState *nic;
+ NICConf conf;
+
+ /* PHY related register sets */
+ uint16_t mid0[3];
+ uint16_t phy_regs[32];
+ uint32_t phy_op_in_progress;
+
+ /* Primary IO address space */
+ union {
+ uint8_t regs_b[0x100]; /* Byte access */
+ uint16_t regs_w[0x100/2]; /* word access */
+ uint32_t regs_l[0x100/4]; /* DWORD access */
+ };
+ QEMUTimer *timer;
+
+ MemoryRegion bar_io;
+ MemoryRegion bar_mem;
+} R6040State;
+
+
+/* some inlines to help access above structure */
+static inline uint32_t TX_START(R6040State *s)
+{
+ uint32_t tmp = s->regs_w[0x2c/2];
+ return tmp | (s->regs_w[0x30/2] << 16);
+}
+
+static inline void TX_START_SET(R6040State *s, uint32_t start)
+{
+ s->regs_w[0x2c/2] = start & 0xffff;
+ s->regs_w[0x30/2] = (start >> 16) & 0xffff;
+}
+
+static inline uint32_t RX_START(R6040State *s)
+{
+ uint32_t tmp = s->regs_w[0x34/2];
+ return tmp | (s->regs_w[0x38/2] << 16);
+}
+
+static inline void RX_START_SET(R6040State *s, uint32_t start)
+{
+ s->regs_w[0x34/2] = start & 0xffff;
+ s->regs_w[0x38/2] = (start >> 16) & 0xffff;
+}
+
+
+static void r6040_update_irq(R6040State *s)
+{
+ PCIDevice *d = PCI_DEVICE(s);
+ uint16_t isr = s->regs_w[MISR_W] & s->regs_w[MIER_W];
+
+ pci_set_irq(d, (isr != 0));
+}
+
+
+/* Mark auto-neg complete, NIC up. */
+static void PhysicalLinkUp(void *opaque)
+{
+ R6040State *s = opaque;
+ s->phy_regs[1] |= (1 << 2);
+ timer_del(s->timer);
+ timer_free(s->timer);
+}
+
+
+/* Transmit and receive descriptors are doubled up
+ One is a subset of the other anyhow
+ */
+typedef struct Descriptor {
+ uint16_t dst;
+ uint16_t dlen;
+ uint32_t dbp;
+ uint32_t dnx;
+ uint16_t hidx;
+ uint16_t reserved_1;
+ uint16_t reserved_2;
+} Descriptor;
+
+
+/* Some debugging functions */
+
+#ifdef DEBUG_R6040
+static void addr_dump16(const char *name, uint16_t val)
+{
+ DPRINTF("%s: 0x%04x ", name, val);
+}
+
+static void addr_dump32(const char *name, uint32_t val)
+{
+ DPRINTF("%s: 0x%x ", name, val);
+}
+
+static void hex_dump(const uint8_t *data, uint32_t len)
+{
+ uint8_t i;
+ DPRINTF("hex: ");
+ for (i = 0; i < len; i++) {
+ fprintf(stderr, "%02x ", *data);
+ if (i && !(i % 0x20)) {
+ fprintf(stderr, "\n");
+ }
+ data++;
+ }
+ fprintf(stderr, "\n");
+}
+
+static void desc_dump(Descriptor *d, uint32_t addr)
+{
+ DPRINTF("\nDumping: 0x%x\n", addr);
+ addr_dump16("DST", d->dst);
+ addr_dump16("DLEN", d->dlen);
+ addr_dump32("DBP", (unsigned long)d->dbp);
+ addr_dump32("DNX", (unsigned long)d->dnx);
+ addr_dump16("HIDX", d->hidx);
+ printf("\n");
+}
+
+static void dump_phys_mem(uint32_t addr, int len)
+{
+ uint8_t buffer[1024];
+ cpu_physical_memory_read(addr, buffer, len);
+ hex_dump(buffer, len);
+}
+
+static void dump_pci(uint8_t *pci_conf)
+{
+ uint32_t *p = (uint32_t *)pci_conf;
+ int i = 0;
+ for (i = 0; i < 0x40; i += 4) {
+ DPRINTF("Addr: 0x%08x, Data: 0x%08x\n", i, *p);
+ p++;
+ }
+}
+#endif
+
+
+static const VMStateDescription vmstate_r6040 = {
+ .name = "r6040",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .minimum_version_id_old = 2,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, R6040State),
+ VMSTATE_BUFFER(regs_b, R6040State),
+ VMSTATE_UINT16_ARRAY(mid0, R6040State, 3),
+ VMSTATE_UINT16_ARRAY(phy_regs, R6040State, 32),
+ VMSTATE_UINT32(phy_op_in_progress, R6040State),
+ VMSTATE_MACADDR(conf.macaddr, R6040State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+static int TryToSendOnePacket(void *opaque)
+{
+ R6040State *s = opaque;
+ Descriptor d;
+ uint8_t pkt_buffer[2000];
+ uint32_t tocopy;
+
+ cpu_physical_memory_read(TX_START(s), (uint8_t *)&d, sizeof(d));
+
+ if (d.dst & 0x8000) { /* MAC owns it? */
+ tocopy = d.dlen;
+ if (tocopy > sizeof(pkt_buffer)) {
+ tocopy = sizeof(pkt_buffer);
+ }
+ /* copy the packet to send it */
+ cpu_physical_memory_read(d.dbp, pkt_buffer, tocopy);
+
+ qemu_send_packet(qemu_get_queue(s->nic), pkt_buffer, tocopy);
+ s->regs_w[TX_PKT_COUNT_W]++;
+
+ /* relinquish ownership, we're done with it */
+ d.dst &= ~0x8000;
+
+ /* Copy the new version of the descriptor back */
+ cpu_physical_memory_write(TX_START(s), (uint8_t *)&d, sizeof(d));
+
+ /* Advance to the next buffer if packet processed */
+ TX_START_SET(s, d.dnx);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void r6040_transmit(void *opaque)
+{
+ R6040State *s = opaque;
+ int count = 0;
+
+ while (TryToSendOnePacket(s)) {
+ ++count;
+ }
+
+ if (count) {
+ s->regs_w[MISR_W] |= 0x10;
+ r6040_update_irq(s);
+ }
+}
+
+
+/* Whether to allow callback returning 1 for yes, can receive */
+static bool r6040_can_receive(NetClientState *nc)
+{
+ R6040State *s = qemu_get_nic_opaque(nc);
+ return s->regs_w[0] & 0x0002;
+}
+
+
+static int ReceiveOnePacket(void *opaque, const uint8_t *buf, size_t len)
+{
+ R6040State *s = opaque;
+ uint32_t tocopy = len+4; /* include checksum */
+ Descriptor d;
+
+ cpu_physical_memory_read(RX_START(s), (uint8_t *)&d, sizeof(Descriptor));
+ /*desc_dump(&d, 0);*/
+
+ if (d.dst & 0x8000) { /* MAC owned? */
+
+ uint16_t max_buffer = s->regs_w[MRBSR_W] & 0x07fc;
+ if (tocopy > max_buffer) {
+ tocopy = max_buffer;
+ }
+
+ cpu_physical_memory_write(d.dbp, buf, tocopy-4);
+
+ /* indicate received OK */
+ d.dst |= (1 << 14);
+ d.dlen = tocopy;
+ /* relinquish ownership */
+ d.dst &= ~0x8000;
+
+ /* Copy the descriptor back */
+ cpu_physical_memory_write(RX_START(s), (uint8_t *)&d,
+ sizeof(Descriptor));
+
+ s->regs_w[RX_PKT_COUNT_W]++;
+
+ s->regs_w[MISR_W] |= 1; /* received pkt interrupt */
+
+ r6040_update_irq(s);
+
+ RX_START_SET(s, d.dnx); /* advance */
+
+ return 0;
+ }
+ return -1;
+}
+
+
+/* called on incoming packets */
+static ssize_t r6040_receive(NetClientState *nc, const uint8_t *buf,
+ size_t len)
+{
+ R6040State *s = qemu_get_nic_opaque(nc);
+ DPRINTF("Received incoming packet of len %ld\n", len);
+
+ if (0 == ReceiveOnePacket(s, buf, len)) {
+ return len; /* copied OK */
+ }
+
+ return 0;
+}
+
+
+static inline int BIT_SET(uint16_t old, uint16_t new, uint16_t bit)
+{
+ uint16_t before = (old & (1 << bit));
+ uint16_t after = (new & (1 << bit));
+ if (!before && after) {
+ return 1;
+ }
+ return 0;
+}
+
+
+static void r6040_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+ R6040State *s = opaque;
+ uint16_t old;
+ addr &= 0xff; /* get relative to base address */
+ addr /= 2; /* Get the offset into the word-array */
+ old = s->regs_w[addr]; /* store the old value for future use */
+
+ switch (addr) {
+ case MCR0_W: /* 0x00 */
+ if (BIT_SET(old, val, 12)) {
+ r6040_transmit(opaque);
+ }
+ break;
+ case MCR1_W: /* 0x04 */
+ if (val & BIT_MRST) { /* reset request incoming */
+ /* reset requested, complete it immediately, set this value to
+ default */
+ val = 0x0010;
+ }
+ break;
+ case MTPR_W: /* TX command reg, 0x14 */
+ if (val & 1) {
+ r6040_transmit(opaque);
+ val &= ~1;
+ }
+ break;
+ case MMDIO_W: /* MDIO control, 0x20 */
+ {
+ int phy_exists = ((val & 0x1f00) == 0x100) ? 1 : 0;
+ uint16_t *phy = s->phy_regs;
+ phy += (val & 0x1f);
+
+ if (val & (1 << 13)) { /* read data */
+ if (phy_exists) {
+ s->regs_w[MDIO_READ_W] = *phy;
+ } else {
+ s->regs_w[MDIO_READ_W] = 0xffff;
+ }
+ } else if (val & (1 << 14)) { /* write data */
+ if (phy_exists) {
+ *phy = s->regs_w[MDIO_WRITE_W];
+ }
+ }
+
+ /* Whether you request to read or write, both bits go high while
+ the operation is in progress, e.g. tell it to read, and the
+ write-in-progress flag also goes high */
+ val |= 0x6000; /* signal operation has started */
+ s->phy_op_in_progress = 1;
+
+ break;
+ }
+ case MISR_W: /* interrupt status reg (read to clear), 0x3c */
+ return;
+
+ case MIER_W: /* interrupt enable register, 0x40 */
+ s->regs_w[MIER_W] = val;
+ r6040_update_irq(s);
+ return;
+
+ case MRCNT_W: /* 0x50 */
+ case MTCNT_W: /* 0x5c */
+ return; /* Can't write to pkt count registers, skip */
+
+ }
+ s->regs_w[addr] = val & 0xFFFF;
+}
+
+
+static uint32_t r6040_ioport_readw(void *opaque, uint32_t addr)
+{
+ R6040State *s = opaque;
+ addr &= 0xff; /* get relative to base address */
+ addr /= 2; /* Get the offset into the word-array */
+ uint32_t tmp = s->regs_w[addr]; /* get the value */
+
+ switch (addr) {
+
+ case MMDIO_W: /* MDIO control, 0x20 */
+ {
+ /* Clear any in-progress MDIO activity for the next read
+ This simulates the polling of the MDIO operation status,
+ so the driver code always has to read the register twice
+ before it thinks the operation is complete. */
+ if (s->phy_op_in_progress) {
+ s->regs_w[addr] &= ~0x6000;
+ s->phy_op_in_progress = 0;
+ }
+ break;
+ }
+ case MISR_W: /* interrupt status reg (read to clear) 0x3c */
+ s->regs_w[addr] = 0;
+ break;
+ case MIER_W: /* interrupt enable reg 0x40 */
+ break;
+ case MRCNT_W: /* 0x50 */
+ case MTCNT_W: /* 0x5c */
+ s->regs_w[addr] = 0; /* read to clear */
+ break;
+ default:
+ break;
+ }
+ return tmp;
+}
+
+
+/* byte and long access are routed via the word operation handlers */
+static void r6040_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ R6040State *s = opaque;
+ addr &= 0xFF;
+ val &= 0xFF;
+ uint16_t old = s->regs_w[addr/2]; /* get the current value */
+ if (addr & 1) {
+ old &= 0xff;
+ old |= (val << 8);
+ } else {
+ old &= 0xff00;
+ old |= val;
+ }
+
+ r6040_ioport_writew(opaque, addr, old); /* call the word-based version */
+}
+
+static void r6040_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+ /* Set the low value */
+ r6040_ioport_writew(opaque, addr, val & 0xffff);
+ /* Set the high value */
+ r6040_ioport_writew(opaque, addr+2, (val >> 16) & 0xffff);
+}
+
+static uint32_t r6040_ioport_readb(void *opaque, uint32_t addr)
+{
+ uint32_t tmp = r6040_ioport_readw(opaque, addr & ~1);
+ if (addr & 1) {
+ return (tmp & 0xff00) >> 8;
+ }
+ return tmp & 0xff;
+}
+
+static uint32_t r6040_ioport_readl(void *opaque, uint32_t addr)
+{
+ uint32_t tmp = r6040_ioport_readw(opaque, addr);
+ return tmp | (r6040_ioport_readw(opaque, addr+2) << 16);
+}
+
+static void r6040_ioport_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ switch (size) {
+ case 1:
+ r6040_ioport_writeb(opaque, addr, val);
+ break;
+ case 2:
+ r6040_ioport_writew(opaque, addr, val);
+ break;
+ case 4:
+ r6040_ioport_writel(opaque, addr, val);
+ break;
+ }
+}
+
+static uint64_t r6040_ioport_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ switch (size) {
+ case 1:
+ return r6040_ioport_readb(opaque, addr);
+ case 2:
+ return r6040_ioport_readw(opaque, addr);
+ case 4:
+ return r6040_ioport_readl(opaque, addr);
+ }
+
+ return -1;
+}
+
+static const MemoryRegionOps rtl8139_io_ops = {
+ .read = r6040_ioport_read,
+ .write = r6040_ioport_write,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+
+static NetClientInfo net_r6040_info = {
+ .type = NET_CLIENT_DRIVER_NIC,
+ .size = sizeof(NICState),
+ .can_receive = r6040_can_receive,
+ .receive = r6040_receive,
+};
+
+
+static void r6040_realize(PCIDevice *dev, Error **errp)
+{
+ R6040State *s = R6040(dev);
+ uint8_t *pci_conf;
+
+ /* MAC PHYS status change register. Linux driver expects something
+ sensible as default and if not will try to set it */
+ s->regs_w[MPSCCR_W] = 0x9f07;
+
+ /* Default value for maximum packet size */
+ s->regs_w[MRBSR_W] = 0x600;
+
+ /* set the MAC, linux driver reads this when it loads, it is
+ normally set by the BIOS, but obviously Qemu BIOS isn't going
+ to do that */
+ s->regs_w[MAC0_W] = 0x5452;
+ s->regs_w[MAC1_W] = 0x1200;
+ s->regs_w[MAC2_W] = 0x5734;
+
+ /* Tell Qemu the same thing */
+ s->conf.macaddr.a[0] = s->regs_w[MAC0_W] & 0xff;
+ s->conf.macaddr.a[1] = (s->regs_w[MAC0_W] >> 8) & 0xff;
+ s->conf.macaddr.a[2] = s->regs_w[MAC1_W] & 0xff;
+ s->conf.macaddr.a[3] = (s->regs_w[MAC1_W] >> 8) & 0xff;
+ s->conf.macaddr.a[4] = s->regs_w[MAC2_W] & 0xff;
+ s->conf.macaddr.a[5] = (s->regs_w[MAC2_W] >> 8) & 0xff;
+
+ /* no commands running */
+ s->phy_op_in_progress = 0;
+
+ /* PHY auto-neg in progress */
+ s->phy_regs[1] = 0x786d & ~(1 << 2);
+ s->phy_regs[2] = 0x0243;
+ s->phy_regs[3] = 0x0c54;
+
+ pci_conf = (uint8_t *)s->dev.config;
+
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */
+ pci_conf[PCI_INTERRUPT_LINE] = 0xa; /* interrupt line */
+ pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */
+
+ memory_region_init_io(&s->bar_io, OBJECT(s), &rtl8139_io_ops, s,
+ "r6040", 0x100);
+ memory_region_init_alias(&s->bar_mem, OBJECT(s), "r6040-mem", &s->bar_io,
+ 0, 0x100);
+
+ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
+ pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
+
+ s->nic = qemu_new_nic(&net_r6040_info, &s->conf,
+ object_get_typename(OBJECT(dev)), DEVICE(dev)->id, s);
+
+ qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+ /* Simulate a delay of a couple of seconds for the link to come up.
+ Not required for Linux but very handy for developing BIOS code.
+ */
+ s->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, PhysicalLinkUp, s);
+ timer_mod(s->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1500);
+}
+
+static Property r6040_properties[] = {
+ DEFINE_NIC_PROPERTIES(R6040State, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void r6040_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->realize = r6040_realize;
+ k->exit = NULL;
+ k->romfile = NULL;
+ k->vendor_id = PCI_VENDOR_ID_RDC;
+ k->device_id = PCI_DEVICE_ID_RDC_R6040;
+ k->revision = 0;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->reset = NULL;
+ dc->vmsd = &vmstate_r6040;
+ device_class_set_props(dc, r6040_properties);
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+}
+
+
+static const TypeInfo r6040_info = {
+ .name = TYPE_R6040,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(R6040State),
+ .class_init = r6040_class_init,
+ .instance_init = NULL,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+
+static void r6040_register_types(void)
+{
+ type_register_static(&r6040_info);
+}
+
+
+type_init(r6040_register_types)
Index: host-qemu-5.2.0/hw/pci-host/i440fx.c
===================================================================
--- host-qemu-5.2.0.orig/hw/pci-host/i440fx.c
+++ host-qemu-5.2.0/hw/pci-host/i440fx.c
@@ -309,6 +309,11 @@ PCIBus *i440fx_init(const char *host_typ
}
d->config[I440FX_COREBOOT_RAM_SIZE] = ram_size;
+ d->config[0x90] = 0x00;
+ d->config[0x91] = 0x10;
+ d->config[0x92] = 0x32;
+ d->config[0x93] = 0x00;
+
i440fx_update_memory_mappings(f);
return b;
@@ -329,8 +334,10 @@ static void i440fx_class_init(ObjectClas
k->realize = i440fx_realize;
k->config_write = i440fx_write_config;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82441;
+// k->vendor_id = PCI_VENDOR_ID_INTEL;
+// k->device_id = PCI_DEVICE_ID_INTEL_82441;
+ k->vendor_id = PCI_VENDOR_ID_RDC;
+ k->device_id = PCI_DEVICE_ID_RDC_R6020;
k->revision = 0x02;
k->class_id = PCI_CLASS_BRIDGE_HOST;
dc->desc = "Host bridge";
Index: host-qemu-5.2.0/include/hw/pci/pci_ids.h
===================================================================
--- host-qemu-5.2.0.orig/include/hw/pci/pci_ids.h
+++ host-qemu-5.2.0/include/hw/pci/pci_ids.h
@@ -258,6 +258,11 @@
#define PCI_DEVICE_ID_INTEL_P35_MCH 0x29c0
+#define PCI_VENDOR_ID_RDC 0x17f3
+#define PCI_DEVICE_ID_RDC_R6020 0x6020
+#define PCI_DEVICE_ID_RDC_R6030 0x6030
+#define PCI_DEVICE_ID_RDC_R6040 0x6040
+
#define PCI_VENDOR_ID_XEN 0x5853
#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
Index: host-qemu-5.2.0/target/i386/cpu.h
===================================================================
--- host-qemu-5.2.0.orig/target/i386/cpu.h
+++ host-qemu-5.2.0/target/i386/cpu.h
@@ -135,7 +135,10 @@ typedef enum X86Seg {
#define AC_MASK 0x00040000
#define VIF_MASK 0x00080000
#define VIP_MASK 0x00100000
-#define ID_MASK 0x00200000
+//
+// Prevent EFLAGS ID toggle, so linux doesn't think we have CPU ID.
+//#define ID_MASK 0x00200000
+#define ID_MASK 0x00000000
/* hidden flags - used internally by qemu to represent additional cpu
states. Only the INHIBIT_IRQ, SMM and SVMI are not redundant. We
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment