From: Corey Minyard cminyard@mvista.com
An IPMI device is being added to the qemu code, and it has an SMBIOS entry to describe the interface characteristics. So add the SMBIOS entry to the BIOS so it can handle this.
Signed-off-by: Corey Minyard cminyard@mvista.com --- Makefile | 2 +- src/ipmi.c | 16 ++++++++++++++++ src/ipmi.h | 27 +++++++++++++++++++++++++++ src/paravirt.c | 18 ++++++++++++++++++ src/paravirt.h | 9 +++++++++ src/post.c | 2 ++ src/smbios.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/smbios.h | 12 ++++++++++++ src/util.h | 5 +++++ 9 files changed, 144 insertions(+), 1 deletions(-) create mode 100644 src/ipmi.c create mode 100644 src/ipmi.h
diff --git a/Makefile b/Makefile index dfdec5c..1b6eb96 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SRCBOTH=misc.c stacks.c pmm.c output.c util.c block.c floppy.c ata.c mouse.c \ pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \ usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \ virtio-ring.c virtio-pci.c virtio-blk.c virtio-scsi.c apm.c ahci.c \ - usb-uas.c lsi-scsi.c + usb-uas.c lsi-scsi.c ipmi.c SRC16=$(SRCBOTH) system.c disk.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ diff --git a/src/ipmi.c b/src/ipmi.c new file mode 100644 index 0000000..7521a8b --- /dev/null +++ b/src/ipmi.c @@ -0,0 +1,16 @@ +// IPMI setup information +// +// Copyright (C) 2012 Corey Minyard cminyard@mvista.com +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "ipmi.h" +#include "paravirt.h" + +struct ipmi_info ipmi_info; + +void +ipmi_setup(void) +{ + qemu_cfg_load_ipmi(&ipmi_info); +} diff --git a/src/ipmi.h b/src/ipmi.h new file mode 100644 index 0000000..b0cf61e --- /dev/null +++ b/src/ipmi.h @@ -0,0 +1,27 @@ +// IPMI setup information +// +// Copyright (C) 2012 Corey Minyard cminyard@mvista.com +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#ifndef __IPMI_H +#define __IPMI_H + +#include "config.h" // CONFIG_COREBOOT +#include "types.h" + +struct ipmi_info { + u64 base_addr; + u8 interface; + u8 reg_space; + u8 reg_spacing; + u8 slave_addr; + u8 irq; + u8 version; +}; + +extern struct ipmi_info ipmi_info; + +void ipmi_setup(void); + +#endif diff --git a/src/paravirt.c b/src/paravirt.c index 2a98d53..4986cfb 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -148,6 +148,24 @@ void* qemu_cfg_e820_load_next(void *addr) return addr; }
+void qemu_cfg_load_ipmi(struct ipmi_info *info) +{ + qemu_cfg_read_entry(&info->interface, QEMU_CFG_IPMI_INTERFACE, sizeof(u8)); + qemu_cfg_read_entry(&info->base_addr, QEMU_CFG_IPMI_BASE_ADDR, sizeof(u64)); + + if ((info->interface == 0) || (info->base_addr == 0)) + return; + + info->base_addr = le64_to_cpu(info->base_addr); + qemu_cfg_read_entry(&info->reg_spacing, QEMU_CFG_IPMI_REG_SPACING, + sizeof(u8)); + qemu_cfg_read_entry(&info->reg_space, QEMU_CFG_IPMI_REG_SPACE, sizeof(u8)); + qemu_cfg_read_entry(&info->version, QEMU_CFG_IPMI_VERSION, sizeof(u8)); + qemu_cfg_read_entry(&info->slave_addr, QEMU_CFG_IPMI_SLAVE_ADDR, + sizeof(u8)); + qemu_cfg_read_entry(&info->irq, QEMU_CFG_IPMI_IRQ, sizeof(u8)); +} + struct smbios_header { u16 length; u8 type; diff --git a/src/paravirt.h b/src/paravirt.h index a284c41..b14e41b 100644 --- a/src/paravirt.h +++ b/src/paravirt.h @@ -3,6 +3,7 @@
#include "config.h" // CONFIG_COREBOOT #include "util.h" +#include "ipmi.h" // struct ipmi_info
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It * should be used to determine that a VM is running under KVM. @@ -35,6 +36,13 @@ static inline int kvm_para_available(void) #define QEMU_CFG_BOOT_MENU 0x0e #define QEMU_CFG_MAX_CPUS 0x0f #define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_IPMI_INTERFACE 0x30 +#define QEMU_CFG_IPMI_BASE_ADDR 0x31 +#define QEMU_CFG_IPMI_REG_SPACE 0x32 +#define QEMU_CFG_IPMI_REG_SPACING 0x33 +#define QEMU_CFG_IPMI_SLAVE_ADDR 0x34 +#define QEMU_CFG_IPMI_IRQ 0x35 +#define QEMU_CFG_IPMI_VERSION 0x36 #define QEMU_CFG_ARCH_LOCAL 0x8000 #define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0) #define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1) @@ -64,6 +72,7 @@ struct e820_reservation { }; u32 qemu_cfg_e820_entries(void); void* qemu_cfg_e820_load_next(void *addr); +void qemu_cfg_load_ipmi(struct ipmi_info *info); void qemu_cfg_romfile_setup(void);
#endif diff --git a/src/post.c b/src/post.c index 0f31b4c..69834b6 100644 --- a/src/post.c +++ b/src/post.c @@ -28,6 +28,7 @@ #include "virtio-blk.h" // virtio_blk_setup #include "virtio-scsi.h" // virtio_scsi_setup #include "lsi-scsi.h" // lsi_scsi_setup +#include "ipmi.h" // ipmi_setup
/**************************************************************** @@ -255,6 +256,7 @@ maininit(void) pnp_setup(); kbd_setup(); mouse_setup(); + ipmi_setup(); init_bios_tables();
// Run vga option rom diff --git a/src/smbios.c b/src/smbios.c index fc84aad..9576c02 100644 --- a/src/smbios.c +++ b/src/smbios.c @@ -422,6 +422,58 @@ smbios_init_type_32(void *start) return start+2; }
+/* Type 38 -- System Boot Information */ +static void * +smbios_init_type_38(void *start, struct ipmi_info *info) +{ + struct smbios_type_38 *p = (struct smbios_type_38 *)start; + + p->header.type = 38; + p->header.length = sizeof(struct smbios_type_38); + p->header.handle = 0x2100; + + p->interface_type = info->interface; + + p->base_addr = info->base_addr & ~1ULL; + /* Bit 0 goes into a special place */ + p->base_addr_mod_and_irq_info = (info->base_addr & 1) << 4; + + switch (info->reg_spacing) { + case 4: + p->base_addr_mod_and_irq_info |= (1 << 6); + break; + case 16: + p->base_addr_mod_and_irq_info |= (2 << 6); + break; + case 1: + default: + /* zero is the right value */ + break; + } + + if (info->reg_space) + p->base_addr |= 1; /* I/O space */ + + if (info->version) + p->ipmi_version = info->version; + else + p->ipmi_version = 0x15; + + if (info->slave_addr) + p->i2c_slave_addr = info->slave_addr; + else + p->i2c_slave_addr = 0x20; + + p->nv_storage_dev_addr = 0; + + p->interrupt_number = info->irq; + + start += sizeof(struct smbios_type_38); + *((u16 *)start) = 0; + + return start+2; +} + /* Type 127 -- End of Table */ static void * smbios_init_type_127(void *start) @@ -510,6 +562,8 @@ smbios_init(void) }
add_struct(32, p); + if (ipmi_info.interface) + add_struct(38, p, &ipmi_info); /* Add any remaining provided entries before the end marker */ for (i = 0; i < 256; i++) qemu_cfg_smbios_load_external(i, &p, &nr_structs, &max_struct_size, diff --git a/src/smbios.h b/src/smbios.h index 9d54e80..1935335 100644 --- a/src/smbios.h +++ b/src/smbios.h @@ -160,6 +160,18 @@ struct smbios_type_32 { u8 boot_status; } PACKED;
+/* SMBIOS type 38 - IPMI Information */ +struct smbios_type_38 { + struct smbios_structure_header header; + u8 interface_type; + u8 ipmi_version; + u8 i2c_slave_addr; + u8 nv_storage_dev_addr; + u64 base_addr; + u8 base_addr_mod_and_irq_info; + u8 interrupt_number; +} PACKED; + /* SMBIOS type 127 -- End-of-table */ struct smbios_type_127 { struct smbios_structure_header header; diff --git a/src/util.h b/src/util.h index ef8ec7c..415f518 100644 --- a/src/util.h +++ b/src/util.h @@ -134,6 +134,11 @@ static inline u32 le32_to_cpu(u32 x) return x; }
+static inline u64 le64_to_cpu(u64 x) +{ + return x; +} + static inline u32 getesp(void) { u32 esp; asm("movl %%esp, %0" : "=rm"(esp));
On Mon, Jul 30, 2012 at 09:57:47PM -0500, minyard@acm.org wrote:
From: Corey Minyard cminyard@mvista.com
An IPMI device is being added to the qemu code, and it has an SMBIOS entry to describe the interface characteristics. So add the SMBIOS entry to the BIOS so it can handle this.
Signed-off-by: Corey Minyard cminyard@mvista.com
Makefile | 2 +- src/ipmi.c | 16 ++++++++++++++++ src/ipmi.h | 27 +++++++++++++++++++++++++++ src/paravirt.c | 18 ++++++++++++++++++ src/paravirt.h | 9 +++++++++ src/post.c | 2 ++ src/smbios.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/smbios.h | 12 ++++++++++++ src/util.h | 5 +++++ 9 files changed, 144 insertions(+), 1 deletions(-) create mode 100644 src/ipmi.c create mode 100644 src/ipmi.h
diff --git a/Makefile b/Makefile index dfdec5c..1b6eb96 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SRCBOTH=misc.c stacks.c pmm.c output.c util.c block.c floppy.c ata.c mouse.c \ pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \ usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \ virtio-ring.c virtio-pci.c virtio-blk.c virtio-scsi.c apm.c ahci.c \
- usb-uas.c lsi-scsi.c
- usb-uas.c lsi-scsi.c ipmi.c
SRC16=$(SRCBOTH) system.c disk.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ diff --git a/src/ipmi.c b/src/ipmi.c new file mode 100644 index 0000000..7521a8b --- /dev/null +++ b/src/ipmi.c @@ -0,0 +1,16 @@ +// IPMI setup information +// +// Copyright (C) 2012 Corey Minyard cminyard@mvista.com +// +// This file may be distributed under the terms of the GNU LGPLv3 license.
+#include "ipmi.h" +#include "paravirt.h"
+struct ipmi_info ipmi_info;
+void +ipmi_setup(void) +{
- qemu_cfg_load_ipmi(&ipmi_info);
+} diff --git a/src/ipmi.h b/src/ipmi.h new file mode 100644 index 0000000..b0cf61e --- /dev/null +++ b/src/ipmi.h @@ -0,0 +1,27 @@ +// IPMI setup information +// +// Copyright (C) 2012 Corey Minyard cminyard@mvista.com +// +// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __IPMI_H +#define __IPMI_H
+#include "config.h" // CONFIG_COREBOOT +#include "types.h"
+struct ipmi_info {
- u64 base_addr;
- u8 interface;
- u8 reg_space;
- u8 reg_spacing;
- u8 slave_addr;
- u8 irq;
- u8 version;
+};
+extern struct ipmi_info ipmi_info;
+void ipmi_setup(void);
+#endif diff --git a/src/paravirt.c b/src/paravirt.c index 2a98d53..4986cfb 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -148,6 +148,24 @@ void* qemu_cfg_e820_load_next(void *addr) return addr; }
+void qemu_cfg_load_ipmi(struct ipmi_info *info) +{
- qemu_cfg_read_entry(&info->interface, QEMU_CFG_IPMI_INTERFACE, sizeof(u8));
- qemu_cfg_read_entry(&info->base_addr, QEMU_CFG_IPMI_BASE_ADDR, sizeof(u64));
- if ((info->interface == 0) || (info->base_addr == 0))
return;
- info->base_addr = le64_to_cpu(info->base_addr);
- qemu_cfg_read_entry(&info->reg_spacing, QEMU_CFG_IPMI_REG_SPACING,
sizeof(u8));
- qemu_cfg_read_entry(&info->reg_space, QEMU_CFG_IPMI_REG_SPACE, sizeof(u8));
- qemu_cfg_read_entry(&info->version, QEMU_CFG_IPMI_VERSION, sizeof(u8));
- qemu_cfg_read_entry(&info->slave_addr, QEMU_CFG_IPMI_SLAVE_ADDR,
sizeof(u8));
- qemu_cfg_read_entry(&info->irq, QEMU_CFG_IPMI_IRQ, sizeof(u8));
+}
struct smbios_header { u16 length; u8 type; diff --git a/src/paravirt.h b/src/paravirt.h index a284c41..b14e41b 100644 --- a/src/paravirt.h +++ b/src/paravirt.h @@ -3,6 +3,7 @@
#include "config.h" // CONFIG_COREBOOT #include "util.h" +#include "ipmi.h" // struct ipmi_info
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
- should be used to determine that a VM is running under KVM.
@@ -35,6 +36,13 @@ static inline int kvm_para_available(void) #define QEMU_CFG_BOOT_MENU 0x0e #define QEMU_CFG_MAX_CPUS 0x0f #define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_IPMI_INTERFACE 0x30 +#define QEMU_CFG_IPMI_BASE_ADDR 0x31 +#define QEMU_CFG_IPMI_REG_SPACE 0x32 +#define QEMU_CFG_IPMI_REG_SPACING 0x33 +#define QEMU_CFG_IPMI_SLAVE_ADDR 0x34 +#define QEMU_CFG_IPMI_IRQ 0x35 +#define QEMU_CFG_IPMI_VERSION 0x36
Better to add _one_ fw_cfg entry that contains all of the info. But I am sure Kevin will want this to be passed through file interface anyway.
#define QEMU_CFG_ARCH_LOCAL 0x8000 #define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0) #define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1) @@ -64,6 +72,7 @@ struct e820_reservation { }; u32 qemu_cfg_e820_entries(void); void* qemu_cfg_e820_load_next(void *addr); +void qemu_cfg_load_ipmi(struct ipmi_info *info); void qemu_cfg_romfile_setup(void);
#endif diff --git a/src/post.c b/src/post.c index 0f31b4c..69834b6 100644 --- a/src/post.c +++ b/src/post.c @@ -28,6 +28,7 @@ #include "virtio-blk.h" // virtio_blk_setup #include "virtio-scsi.h" // virtio_scsi_setup #include "lsi-scsi.h" // lsi_scsi_setup +#include "ipmi.h" // ipmi_setup
/**************************************************************** @@ -255,6 +256,7 @@ maininit(void) pnp_setup(); kbd_setup(); mouse_setup();
ipmi_setup(); init_bios_tables();
// Run vga option rom
diff --git a/src/smbios.c b/src/smbios.c index fc84aad..9576c02 100644 --- a/src/smbios.c +++ b/src/smbios.c @@ -422,6 +422,58 @@ smbios_init_type_32(void *start) return start+2; }
+/* Type 38 -- System Boot Information */ +static void * +smbios_init_type_38(void *start, struct ipmi_info *info) +{
- struct smbios_type_38 *p = (struct smbios_type_38 *)start;
- p->header.type = 38;
- p->header.length = sizeof(struct smbios_type_38);
- p->header.handle = 0x2100;
- p->interface_type = info->interface;
- p->base_addr = info->base_addr & ~1ULL;
- /* Bit 0 goes into a special place */
- p->base_addr_mod_and_irq_info = (info->base_addr & 1) << 4;
- switch (info->reg_spacing) {
- case 4:
p->base_addr_mod_and_irq_info |= (1 << 6);
break;
- case 16:
p->base_addr_mod_and_irq_info |= (2 << 6);
break;
- case 1:
- default:
/* zero is the right value */
break;
- }
- if (info->reg_space)
p->base_addr |= 1; /* I/O space */
- if (info->version)
p->ipmi_version = info->version;
- else
p->ipmi_version = 0x15;
- if (info->slave_addr)
p->i2c_slave_addr = info->slave_addr;
- else
p->i2c_slave_addr = 0x20;
- p->nv_storage_dev_addr = 0;
- p->interrupt_number = info->irq;
- start += sizeof(struct smbios_type_38);
- *((u16 *)start) = 0;
- return start+2;
+}
/* Type 127 -- End of Table */ static void * smbios_init_type_127(void *start) @@ -510,6 +562,8 @@ smbios_init(void) }
add_struct(32, p);
- if (ipmi_info.interface)
/* Add any remaining provided entries before the end marker */ for (i = 0; i < 256; i++) qemu_cfg_smbios_load_external(i, &p, &nr_structs, &max_struct_size,add_struct(38, p, &ipmi_info);
diff --git a/src/smbios.h b/src/smbios.h index 9d54e80..1935335 100644 --- a/src/smbios.h +++ b/src/smbios.h @@ -160,6 +160,18 @@ struct smbios_type_32 { u8 boot_status; } PACKED;
+/* SMBIOS type 38 - IPMI Information */ +struct smbios_type_38 {
- struct smbios_structure_header header;
- u8 interface_type;
- u8 ipmi_version;
- u8 i2c_slave_addr;
- u8 nv_storage_dev_addr;
- u64 base_addr;
- u8 base_addr_mod_and_irq_info;
- u8 interrupt_number;
+} PACKED;
/* SMBIOS type 127 -- End-of-table */ struct smbios_type_127 { struct smbios_structure_header header; diff --git a/src/util.h b/src/util.h index ef8ec7c..415f518 100644 --- a/src/util.h +++ b/src/util.h @@ -134,6 +134,11 @@ static inline u32 le32_to_cpu(u32 x) return x; }
+static inline u64 le64_to_cpu(u64 x) +{
- return x;
+}
static inline u32 getesp(void) { u32 esp; asm("movl %%esp, %0" : "=rm"(esp)); -- 1.7.4.1
SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios
-- Gleb.
On 07/31/2012 02:10 AM, Gleb Natapov wrote:
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
- should be used to determine that a VM is running under KVM.
@@ -35,6 +36,13 @@ static inline int kvm_para_available(void) #define QEMU_CFG_BOOT_MENU 0x0e #define QEMU_CFG_MAX_CPUS 0x0f #define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_IPMI_INTERFACE 0x30 +#define QEMU_CFG_IPMI_BASE_ADDR 0x31 +#define QEMU_CFG_IPMI_REG_SPACE 0x32 +#define QEMU_CFG_IPMI_REG_SPACING 0x33 +#define QEMU_CFG_IPMI_SLAVE_ADDR 0x34 +#define QEMU_CFG_IPMI_IRQ 0x35 +#define QEMU_CFG_IPMI_VERSION 0x36 Better to add _one_ fw_cfg entry that contains all of the info. But I am sure Kevin will want this to be passed through file interface anyway.
I considered that, but that seems like a more brittle interface. New fields may need to be added in the future. I'll look at the file interface, but I would think it would be best to have something that could be added to.
Thanks,
-corey
On Tue, Jul 31, 2012 at 08:33:53AM -0500, Corey Minyard wrote:
On 07/31/2012 02:10 AM, Gleb Natapov wrote:
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
- should be used to determine that a VM is running under KVM.
@@ -35,6 +36,13 @@ static inline int kvm_para_available(void) #define QEMU_CFG_BOOT_MENU 0x0e #define QEMU_CFG_MAX_CPUS 0x0f #define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_IPMI_INTERFACE 0x30 +#define QEMU_CFG_IPMI_BASE_ADDR 0x31 +#define QEMU_CFG_IPMI_REG_SPACE 0x32 +#define QEMU_CFG_IPMI_REG_SPACING 0x33 +#define QEMU_CFG_IPMI_SLAVE_ADDR 0x34 +#define QEMU_CFG_IPMI_IRQ 0x35 +#define QEMU_CFG_IPMI_VERSION 0x36 Better to add _one_ fw_cfg entry that contains all of the info. But I am sure Kevin will want this to be passed through file interface anyway.
I considered that, but that seems like a more brittle interface. New fields may need to be added in the future. I'll look at the file interface, but I would think it would be best to have something that could be added to.
If you think it will have to be extended version it or include feature bitmap.
-- Gleb.
Il 31/07/2012 15:33, Corey Minyard ha scritto:
I considered that, but that seems like a more brittle interface. New fields may need to be added in the future. I'll look at the file interface, but I would think it would be best to have something that could be added to.
Just format it as a sequence of SMBIOS structs. For now you only support one entry with header.type = 38, in the future it could be extended to visit each header in turn.
Paolo
On 07/31/2012 11:34 AM, Paolo Bonzini wrote:
Il 31/07/2012 15:33, Corey Minyard ha scritto:
I considered that, but that seems like a more brittle interface. New fields may need to be added in the future. I'll look at the file interface, but I would think it would be best to have something that could be added to.
Just format it as a sequence of SMBIOS structs. For now you only support one entry with header.type = 38, in the future it could be extended to visit each header in turn.
I think something generic is more appropriate, this will probably eventually support other arches and the IPMI SMBIOS structure is a big hack. The file interface was easy to use, anyway, and I'm ready to resubmit try two.
Thanks,
-corey