qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC 9/9] pc: introduce light weight PC board pc-lite


From: Chao Peng
Subject: [Qemu-devel] [RFC 9/9] pc: introduce light weight PC board pc-lite
Date: Fri, 17 Jun 2016 04:14:17 -0400

The new board gets rid of most legacy devices and mainly support modern
PCI devices. BIOS is skipped and an ELF format kernel must be specified.
QEMU will boot this kernel directly.

Add "-machine pc-lite -kernel $ELF_KERNEL -append $KERNEL_CMD" to use it.

Signed-off-by: Chao Peng <address@hidden>
---
 hw/i386/Makefile.objs |   2 +-
 hw/i386/pc.c          |  91 ++++++++++++++++------
 hw/i386/pc_lite.c     | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/i386/pc_piix.c     |   2 +
 hw/i386/pc_q35.c      |   2 +
 include/hw/i386/pc.h  |   8 ++
 6 files changed, 284 insertions(+), 26 deletions(-)
 create mode 100644 hw/i386/pc_lite.c

diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 7d29ec0..af3f53d 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -1,6 +1,6 @@
 obj-$(CONFIG_KVM) += kvm/
 obj-y += multiboot.o
-obj-y += pc.o pc_piix.o pc_q35.o pc_lite_acpi.o
+obj-y += pc.o pc_piix.o pc_q35.o pc_lite_acpi.o pc_lite.o
 obj-y += pc_sysfw.o
 obj-y += intel_iommu.o
 obj-$(CONFIG_XEN) += ../xenpv/ xen/
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 64ce65c..0533951 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -962,8 +962,43 @@ static long get_file_size(FILE *f)
     return size;
 }
 
-static void load_linux(PCMachineState *pcms,
-                       FWCfgState *fw_cfg)
+static void load_linux_efi(PCMachineState *pcms)
+{
+    unsigned char class;
+    MachineState *machine = MACHINE(pcms);
+    FILE *file = fopen(machine->kernel_filename, "rb");
+
+    if (!file) {
+        goto err;
+    }
+
+    if (fseek(file, EI_CLASS, 0) || fread(&class, 1, 1, file) != 1) {
+        fclose(file);
+        goto err;
+    }
+    fclose(file);
+
+    if (load_elf(machine->kernel_filename, NULL, NULL, &boot_info.entry,
+                   NULL, NULL, 0, EM_X86_64, 0, 0) < 0) {
+        goto err;
+    }
+
+    if (class == ELFCLASS64) {
+        boot_info.long_mode = true;
+    } else if (class != ELFCLASS32) {
+        goto err;
+    }
+
+    boot_info.protected_mode = true;
+    return;
+
+err:
+    fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    machine->kernel_filename);
+    exit(1);
+}
+
+static void load_linux_bzimage(PCMachineState *pcms, FWCfgState *fw_cfg)
 {
     uint16_t protocol;
     int setup_size, kernel_size, initrd_size = 0, cmdline_size;
@@ -1404,7 +1439,7 @@ void xen_load_linux(PCMachineState *pcms)
     fw_cfg = fw_cfg_init_io(FW_CFG_IO_BASE);
     rom_set_fw(fw_cfg);
 
-    load_linux(pcms, fw_cfg);
+    load_linux_bzimage(pcms, fw_cfg);
     for (i = 0; i < nb_option_roms; i++) {
         assert(!strcmp(option_rom[i].name, "linuxboot.bin") ||
                !strcmp(option_rom[i].name, "multiboot.bin"));
@@ -1421,7 +1456,7 @@ void pc_memory_init(PCMachineState *pcms,
     int linux_boot, i;
     MemoryRegion *ram, *option_rom_mr;
     MemoryRegion *ram_below_4g, *ram_above_4g;
-    FWCfgState *fw_cfg;
+    FWCfgState *fw_cfg = NULL;
     MachineState *machine = MACHINE(pcms);
     PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
 
@@ -1503,36 +1538,42 @@ void pc_memory_init(PCMachineState *pcms,
                                     &pcms->hotplug_memory.mr);
     }
 
-    /* Initialize PC system firmware */
-    pc_system_firmware_init(rom_memory, !pcmc->pci_enabled);
+    if (pcmc->type != PC_MACHINE_TYPE_LITE) {
+        /* Initialize PC system firmware */
+        pc_system_firmware_init(rom_memory, !pcmc->pci_enabled);
 
-    option_rom_mr = g_malloc(sizeof(*option_rom_mr));
-    memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
-                           &error_fatal);
-    vmstate_register_ram_global(option_rom_mr);
-    memory_region_add_subregion_overlap(rom_memory,
-                                        PC_ROM_MIN_VGA,
-                                        option_rom_mr,
-                                        1);
+        option_rom_mr = g_malloc(sizeof(*option_rom_mr));
+        memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
+                               &error_fatal);
+        vmstate_register_ram_global(option_rom_mr);
+        memory_region_add_subregion_overlap(rom_memory,
+                                            PC_ROM_MIN_VGA,
+                                            option_rom_mr,
+                                            1);
 
-    fw_cfg = bochs_bios_init(&address_space_memory, pcms);
+        fw_cfg = bochs_bios_init(&address_space_memory, pcms);
 
-    rom_set_fw(fw_cfg);
+        rom_set_fw(fw_cfg);
 
-    if (pcmc->has_reserved_memory && pcms->hotplug_memory.base) {
-        uint64_t *val = g_malloc(sizeof(*val));
-        PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
-        uint64_t res_mem_end = pcms->hotplug_memory.base;
+        if (pcmc->has_reserved_memory && pcms->hotplug_memory.base) {
+            uint64_t *val = g_malloc(sizeof(*val));
+            PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
+            uint64_t res_mem_end = pcms->hotplug_memory.base;
 
-        if (!pcmc->broken_reserved_end) {
-            res_mem_end += memory_region_size(&pcms->hotplug_memory.mr);
+            if (!pcmc->broken_reserved_end) {
+                res_mem_end += memory_region_size(&pcms->hotplug_memory.mr);
+            }
+            *val = cpu_to_le64(ROUND_UP(res_mem_end, 0x1ULL << 30));
+            fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, 
sizeof(*val));
         }
-        *val = cpu_to_le64(ROUND_UP(res_mem_end, 0x1ULL << 30));
-        fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
     }
 
     if (linux_boot) {
-        load_linux(pcms, fw_cfg);
+        if (pcmc->type == PC_MACHINE_TYPE_LITE) {
+            load_linux_efi(pcms);
+        } else {
+            load_linux_bzimage(pcms, fw_cfg);
+        }
     }
 
     for (i = 0; i < nb_option_roms; i++) {
diff --git a/hw/i386/pc_lite.c b/hw/i386/pc_lite.c
new file mode 100644
index 0000000..3756848
--- /dev/null
+++ b/hw/i386/pc_lite.c
@@ -0,0 +1,205 @@
+/*
+ * Light weight PC chipset
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2009, 2010
+ *               Isaku Yamahata <yamahata at valinux co jp>
+ *               VA Linux Systems Japan K.K.
+ * Copyright (C) 2012 Jason Baron <address@hidden>
+ * Copyright (C) 2016 Chao Peng <address@hidden>
+ *
+ * This is based on pc_q35.c, but heavily modified.
+ *
+ * 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 "hw/hw.h"
+#include "hw/loader.h"
+#include "sysemu/arch_init.h"
+#include "hw/boards.h"
+#include "hw/xen/xen.h"
+#include "sysemu/kvm.h"
+#include "hw/kvm/clock.h"
+#include "hw/pci-host/q35.h"
+#include "exec/address-spaces.h"
+#include "hw/i386/ich9.h"
+#include "hw/smbios/smbios.h"
+#include "hw/ide/pci.h"
+#include "qemu/error-report.h"
+#include "migration/migration.h"
+
+static void pc_lite_gsi_handler(void *opaque, int n, int level)
+{
+    GSIState *s = opaque;
+
+    qemu_set_irq(s->ioapic_irq[n], level);
+}
+
+static void pc_lite_init(MachineState *machine)
+{
+    PCMachineState *pcms = PC_MACHINE(machine);
+    PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
+    PCIBus *host_bus;
+    MemoryRegion *pci_memory;
+    MemoryRegion *rom_memory;
+    MemoryRegion *ram_memory;
+    GSIState *gsi_state;
+    qemu_irq *gsi;
+    ram_addr_t lowmem;
+    DeviceState *pm;
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+
+    /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
+     * and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
+     * also known as MMCFG).
+     * If it doesn't, we need to split it in chunks below and above 4G.
+     * In any case, try to make sure that guest addresses aligned at
+     * 1G boundaries get mapped to host addresses aligned at 1G boundaries.
+     */
+    if (machine->ram_size >= 0xb0000000) {
+        lowmem = 0x80000000;
+    } else {
+        lowmem = 0xb0000000;
+    }
+
+    /* Handle the machine opt max-ram-below-4g.  It is basically doing
+     * min(qemu limit, user limit).
+     */
+    if (lowmem > pcms->max_ram_below_4g) {
+        lowmem = pcms->max_ram_below_4g;
+        if (machine->ram_size - lowmem > lowmem &&
+            lowmem & ((1ULL << 30) - 1)) {
+            error_report("Warning: 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) {
+        pcms->above_4g_mem_size = machine->ram_size - lowmem;
+        pcms->below_4g_mem_size = lowmem;
+    } else {
+        pcms->above_4g_mem_size = 0;
+        pcms->below_4g_mem_size = machine->ram_size;
+    }
+
+    if (xen_enabled()) {
+        xen_hvm_init(pcms, &ram_memory);
+    }
+
+    pc_cpus_init(pcms);
+
+    kvmclock_create();
+
+    /* pci enabled */
+    if (pcmc->pci_enabled) {
+        pci_memory = g_new(MemoryRegion, 1);
+        memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
+        rom_memory = pci_memory;
+    } else {
+        pci_memory = NULL;
+        rom_memory = get_system_memory();
+    }
+
+    pc_guest_info_init(pcms);
+
+    if (pcmc->smbios_defaults) {
+        /* These values are guest ABI, do not change */
+        smbios_set_defaults("QEMU", "Light weight PC)",
+                            mc->name, pcmc->smbios_legacy_mode,
+                            pcmc->smbios_uuid_encoded,
+                            SMBIOS_ENTRY_POINT_21);
+    }
+
+    /* allocate ram and load rom/bios */
+    if (!xen_enabled()) {
+        pc_memory_init(pcms, get_system_memory(),
+                       rom_memory, &ram_memory);
+    }
+
+    /* irq lines */
+    gsi_state = g_malloc0(sizeof(*gsi_state));
+    if (kvm_irqchip_in_kernel()) {
+        kvm_pc_setup_irq_routing(pcmc->pci_enabled);
+    }
+    gsi = qemu_allocate_irqs(pc_lite_gsi_handler, gsi_state, GSI_NUM_PINS);
+
+    if (pcmc->pci_enabled) {
+        host_bus = pci_lite_init(get_system_memory(), get_system_io(),
+                                     pci_memory);
+        pcms->bus = host_bus;
+
+        if (acpi_enabled) {
+            pm = pm_lite_init(host_bus, -1, gsi[9]);
+
+            object_property_add_link(OBJECT(machine),
+                                     PC_MACHINE_ACPI_DEVICE_PROP,
+                                     TYPE_HOTPLUG_HANDLER,
+                                     (Object **)&pcms->acpi_dev,
+                                     object_property_allow_set_link,
+                                     OBJ_PROP_LINK_UNREF_ON_RELEASE,
+                                     &error_abort);
+            object_property_set_link(OBJECT(machine), OBJECT(pm),
+                                     PC_MACHINE_ACPI_DEVICE_PROP, 
&error_abort);
+        }
+    }
+
+    if (pcmc->pci_enabled) {
+        ioapic_init_gsi(gsi_state, "pcilite");
+    }
+
+    pc_register_ferr_irq(gsi[13]);
+
+    if (pcms->acpi_nvdimm_state.is_enabled) {
+        nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, get_system_io(),
+                               pcms->fw_cfg, OBJECT(pcms));
+    }
+}
+
+#define DEFINE_LITE_MACHINE(suffix, name, compatfn, optionfn) \
+    static void pc_init_##suffix(MachineState *machine) \
+    { \
+        void (*compat)(MachineState *m) = (compatfn); \
+        if (compat) { \
+            compat(machine); \
+        } \
+        pc_lite_init(machine); \
+    } \
+    DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
+
+
+static void pc_lite_machine_options(MachineClass *m)
+{
+    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+    m->family = "pc_lite";
+    m->desc = "Light weight PC";
+    m->hot_add_cpu = pc_hot_add_cpu;
+    m->units_per_default_bus = 1;
+    m->no_floppy = 1;
+    pcmc->type = PC_MACHINE_TYPE_LITE;
+}
+
+static void pc_lite_2_7_machine_options(MachineClass *m)
+{
+    pc_lite_machine_options(m);
+    m->alias = "pc-lite";
+}
+
+DEFINE_LITE_MACHINE(v2_7, "pc-lite-2.7", NULL,
+                    pc_lite_2_7_machine_options);
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 53bc968..9d25abc 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -425,11 +425,13 @@ static void pc_xen_hvm_init(MachineState *machine)
 
 static void pc_i440fx_machine_options(MachineClass *m)
 {
+    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
     m->family = "pc_piix";
     m->desc = "Standard PC (i440FX + PIIX, 1996)";
     m->hot_add_cpu = pc_hot_add_cpu;
     m->default_machine_opts = "firmware=bios-256k.bin";
     m->default_display = "std";
+    pcmc->type = PC_MACHINE_TYPE_PIIX;
 }
 
 static void pc_i440fx_2_7_machine_options(MachineClass *m)
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index e4b541f..af2c201 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -274,6 +274,7 @@ static void pc_q35_init(MachineState *machine)
 
 static void pc_q35_machine_options(MachineClass *m)
 {
+    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
     m->family = "pc_q35";
     m->desc = "Standard PC (Q35 + ICH9, 2009)";
     m->hot_add_cpu = pc_hot_add_cpu;
@@ -281,6 +282,7 @@ static void pc_q35_machine_options(MachineClass *m)
     m->default_machine_opts = "firmware=bios-256k.bin";
     m->default_display = "std";
     m->no_floppy = 1;
+    pcmc->type = PC_MACHINE_TYPE_Q35;
 }
 
 static void pc_q35_2_7_machine_options(MachineClass *m)
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index ad7533b..ef0e3df 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -33,6 +33,12 @@
 #define kvm_ioapic_in_kernel()   0
 #endif
 
+typedef enum {
+    PC_MACHINE_TYPE_PIIX    = 0,
+    PC_MACHINE_TYPE_Q35     = 1,
+    PC_MACHINE_TYPE_LITE    = 2,
+} PCMachineType;
+
 /**
  * PCMachineState:
  * @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling
@@ -136,6 +142,8 @@ struct PCMachineClass {
 
     /* TSC rate migration: */
     bool save_tsc_khz;
+
+    PCMachineType type;
 };
 
 #define TYPE_PC_MACHINE "generic-pc-machine"
-- 
1.8.3.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]