summaryrefslogtreecommitdiffstats
path: root/qemu/roms/seabios/src
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/seabios/src')
-rw-r--r--qemu/roms/seabios/src/Kconfig59
-rw-r--r--qemu/roms/seabios/src/biosvar.h8
-rw-r--r--qemu/roms/seabios/src/block.c248
-rw-r--r--qemu/roms/seabios/src/block.h16
-rw-r--r--qemu/roms/seabios/src/bmp.c2
-rw-r--r--qemu/roms/seabios/src/boot.c22
-rw-r--r--qemu/roms/seabios/src/cdrom.c23
-rw-r--r--qemu/roms/seabios/src/clock.c57
-rw-r--r--qemu/roms/seabios/src/config.h3
-rw-r--r--qemu/roms/seabios/src/disk.c5
-rw-r--r--qemu/roms/seabios/src/e820map.c (renamed from qemu/roms/seabios/src/memmap.c)18
-rw-r--r--qemu/roms/seabios/src/e820map.h26
-rw-r--r--qemu/roms/seabios/src/fw/biostables.c66
-rw-r--r--qemu/roms/seabios/src/fw/coreboot.c17
-rw-r--r--qemu/roms/seabios/src/fw/csm.c23
-rw-r--r--qemu/roms/seabios/src/fw/dev-q35.h3
-rw-r--r--qemu/roms/seabios/src/fw/multiboot.c111
-rw-r--r--qemu/roms/seabios/src/fw/paravirt.c93
-rw-r--r--qemu/roms/seabios/src/fw/paravirt.h26
-rw-r--r--qemu/roms/seabios/src/fw/pciinit.c24
-rw-r--r--qemu/roms/seabios/src/fw/shadow.c12
-rw-r--r--qemu/roms/seabios/src/fw/smbios.c2
-rw-r--r--qemu/roms/seabios/src/fw/smm.c8
-rw-r--r--qemu/roms/seabios/src/fw/smp.c3
-rw-r--r--qemu/roms/seabios/src/fw/xen.c9
-rw-r--r--qemu/roms/seabios/src/hw/ahci.c36
-rw-r--r--qemu/roms/seabios/src/hw/ahci.h4
-rw-r--r--qemu/roms/seabios/src/hw/ata.c42
-rw-r--r--qemu/roms/seabios/src/hw/ata.h6
-rw-r--r--qemu/roms/seabios/src/hw/blockcmd.c139
-rw-r--r--qemu/roms/seabios/src/hw/blockcmd.h4
-rw-r--r--qemu/roms/seabios/src/hw/esp-scsi.c33
-rw-r--r--qemu/roms/seabios/src/hw/esp-scsi.h2
-rw-r--r--qemu/roms/seabios/src/hw/floppy.c2
-rw-r--r--qemu/roms/seabios/src/hw/lsi-scsi.c32
-rw-r--r--qemu/roms/seabios/src/hw/lsi-scsi.h2
-rw-r--r--qemu/roms/seabios/src/hw/megasas.c26
-rw-r--r--qemu/roms/seabios/src/hw/megasas.h2
-rw-r--r--qemu/roms/seabios/src/hw/pci.c11
-rw-r--r--qemu/roms/seabios/src/hw/pci.h2
-rw-r--r--qemu/roms/seabios/src/hw/pci_ids.h8
-rw-r--r--qemu/roms/seabios/src/hw/pic.c14
-rw-r--r--qemu/roms/seabios/src/hw/pic.h4
-rw-r--r--qemu/roms/seabios/src/hw/ps2port.c53
-rw-r--r--qemu/roms/seabios/src/hw/ps2port.h3
-rw-r--r--qemu/roms/seabios/src/hw/pvscsi.c64
-rw-r--r--qemu/roms/seabios/src/hw/pvscsi.h2
-rw-r--r--qemu/roms/seabios/src/hw/ramdisk.c17
-rw-r--r--qemu/roms/seabios/src/hw/rtc.c7
-rw-r--r--qemu/roms/seabios/src/hw/sdcard.c415
-rw-r--r--qemu/roms/seabios/src/hw/timer.c25
-rw-r--r--qemu/roms/seabios/src/hw/tpm_drivers.c291
-rw-r--r--qemu/roms/seabios/src/hw/tpm_drivers.h90
-rw-r--r--qemu/roms/seabios/src/hw/usb-hid.h8
-rw-r--r--qemu/roms/seabios/src/hw/usb-msc.c14
-rw-r--r--qemu/roms/seabios/src/hw/usb-msc.h2
-rw-r--r--qemu/roms/seabios/src/hw/usb-uas.c6
-rw-r--r--qemu/roms/seabios/src/hw/usb-uas.h2
-rw-r--r--qemu/roms/seabios/src/hw/usb-xhci.c46
-rw-r--r--qemu/roms/seabios/src/hw/usb.c9
-rw-r--r--qemu/roms/seabios/src/hw/virtio-blk.c126
-rw-r--r--qemu/roms/seabios/src/hw/virtio-blk.h2
-rw-r--r--qemu/roms/seabios/src/hw/virtio-pci.c228
-rw-r--r--qemu/roms/seabios/src/hw/virtio-pci.h260
-rw-r--r--qemu/roms/seabios/src/hw/virtio-ring.c65
-rw-r--r--qemu/roms/seabios/src/hw/virtio-ring.h45
-rw-r--r--qemu/roms/seabios/src/hw/virtio-scsi.c98
-rw-r--r--qemu/roms/seabios/src/hw/virtio-scsi.h2
-rw-r--r--qemu/roms/seabios/src/list.h10
-rw-r--r--qemu/roms/seabios/src/malloc.c296
-rw-r--r--qemu/roms/seabios/src/malloc.h13
-rw-r--r--qemu/roms/seabios/src/memmap.h38
-rw-r--r--qemu/roms/seabios/src/misc.c2
-rw-r--r--qemu/roms/seabios/src/mouse.c3
-rw-r--r--qemu/roms/seabios/src/optionroms.c39
-rw-r--r--qemu/roms/seabios/src/output.c1
-rw-r--r--qemu/roms/seabios/src/pmm.c16
-rw-r--r--qemu/roms/seabios/src/post.c60
-rw-r--r--qemu/roms/seabios/src/resume.c3
-rw-r--r--qemu/roms/seabios/src/romlayout.S103
-rw-r--r--qemu/roms/seabios/src/sha1.c147
-rw-r--r--qemu/roms/seabios/src/sha1.h8
-rw-r--r--qemu/roms/seabios/src/stacks.c382
-rw-r--r--qemu/roms/seabios/src/stacks.h27
-rw-r--r--qemu/roms/seabios/src/std/acpi.h20
-rw-r--r--qemu/roms/seabios/src/std/bda.h2
-rw-r--r--qemu/roms/seabios/src/std/multiboot.h260
-rw-r--r--qemu/roms/seabios/src/std/smbios.h4
-rw-r--r--qemu/roms/seabios/src/string.c2
-rw-r--r--qemu/roms/seabios/src/string.h8
-rw-r--r--qemu/roms/seabios/src/system.c2
-rw-r--r--qemu/roms/seabios/src/tcgbios.c1480
-rw-r--r--qemu/roms/seabios/src/tcgbios.h375
-rw-r--r--qemu/roms/seabios/src/types.h2
-rw-r--r--qemu/roms/seabios/src/util.h16
-rw-r--r--qemu/roms/seabios/src/version.c5
-rw-r--r--qemu/roms/seabios/src/vgahooks.c2
-rw-r--r--qemu/roms/seabios/src/x86.h27
98 files changed, 5090 insertions, 1396 deletions
diff --git a/qemu/roms/seabios/src/Kconfig b/qemu/roms/seabios/src/Kconfig
index 45ca59cf3..95bf087b8 100644
--- a/qemu/roms/seabios/src/Kconfig
+++ b/qemu/roms/seabios/src/Kconfig
@@ -20,7 +20,7 @@ choice
Configure for an emulated machine (QEMU, Xen, KVM, or Bochs).
config CSM
- bool "Build as Compatibilty Support Module for EFI BIOS"
+ bool "Build as Compatibility Support Module for EFI BIOS"
help
Configure to be used by EFI firmware as Compatibility Support
module (CSM) to provide legacy BIOS services.
@@ -96,12 +96,13 @@ endchoice
the CBFS filesystem is at a non-standard location (eg,
0xffe00000 if CBFS ends 2Meg below the end of flash).
- config FLASH_FLOPPY
- depends on COREBOOT_FLASH
- bool "Floppy images in CBFS"
+ config MULTIBOOT
+ depends on COREBOOT
+ bool "multiboot support"
default y
help
- Support floppy images in coreboot flash.
+ Add multiboot header in bios.bin.raw and accept files supplied
+ as multiboot modules.
config ENTRY_EXTRASTACK
bool "Use internal stack for 16bit interrupt entry points"
default y
@@ -160,7 +161,7 @@ menu "Hardware support"
help
Support for AHCI disk code.
config SDCARD
- depends on DRIVES && QEMU_HARDWARE
+ depends on DRIVES
bool "SD controllers"
default y
help
@@ -208,11 +209,18 @@ menu "Hardware support"
help
Support boot from LSI MegaRAID SAS scsi storage.
config FLOPPY
- depends on DRIVES
+ depends on DRIVES && HARDWARE_IRQ
bool "Floppy controller"
default y
help
Support floppy drive access.
+ config FLASH_FLOPPY
+ depends on DRIVES
+ bool "Floppy images from CBFS or fw_cfg"
+ default y
+ help
+ Support floppy images stored in coreboot flash or from
+ QEMU fw_cfg.
config PS2PORT
depends on KEYBOARD || MOUSE
@@ -291,6 +299,26 @@ menu "Hardware support"
default y
help
Support parallel ports. This also enables int 17 parallel port calls.
+ config RTC_TIMER
+ bool "Real Time Clock (RTC) scheduling"
+ depends on HARDWARE_IRQ
+ default y
+ help
+ Support MC146818 Real Time Clock chip timer
+ interrupts. This also enables int 1583 and int 1586 calls.
+
+ Disabling this support does not disable access to the RTC
+ cmos registers.
+
+ config HARDWARE_IRQ
+ bool "Hardware interrupts"
+ default y
+ help
+ Program and support hardware interrupts using the i8259
+ programmable interrupt controller (PIC). This option must
+ be enabled in order to support most boot loaders. Only
+ disable this option if running on peculiar hardware known
+ not to support irq routing.
config USE_SMM
depends on QEMU
@@ -309,10 +337,16 @@ menu "Hardware support"
help
Initialize the Memory Type Range Registers (on emulators).
config PMTIMER
- bool "Use ACPI timer"
+ bool "Support ACPI timer"
default y
help
- Use the ACPI timer instead of the TSC for timekeeping (on qemu).
+ Detect and use the ACPI timer for timekeeping.
+ config TSC_TIMER
+ bool "Support CPU timestamp counter as timer"
+ default y
+ help
+ Support for using the CPU timestamp counter as an internal
+ timing source.
endmenu
menu "BIOS interfaces"
@@ -421,6 +455,13 @@ menu "BIOS interfaces"
modified by programs. However, some old DOS high memory
managers may require the UMB region to be read-only.
+ config TCGBIOS
+ depends on S3_RESUME
+ bool "TPM support and TCG BIOS extensions"
+ default y
+ help
+ Provide TPM support along with TCG BIOS extensions
+
endmenu
menu "BIOS Tables"
diff --git a/qemu/roms/seabios/src/biosvar.h b/qemu/roms/seabios/src/biosvar.h
index 58bcbcedb..f61fb6a50 100644
--- a/qemu/roms/seabios/src/biosvar.h
+++ b/qemu/roms/seabios/src/biosvar.h
@@ -8,11 +8,12 @@
#include "config.h" // SEG_BDA
#include "farptr.h" // GET_FARVAR
+#include "memmap.h" // SYMBOL
#include "std/bda.h" // struct bios_data_area_s
/****************************************************************
- * Interupt vector table
+ * Interrupt vector table
****************************************************************/
#define GET_IVT(vector) \
@@ -112,13 +113,12 @@ static inline u16 get_global_seg(void) {
* "Low" memory variables
****************************************************************/
-extern u8 _zonelow_seg, zonelow_base[];
-#define SEG_LOW ((u32)&_zonelow_seg)
+#define SEG_LOW SYMBOL(_zonelow_seg)
#if MODESEGMENT
#define GET_LOW(var) GET_FARVAR(SEG_LOW, (var))
#define SET_LOW(var, val) SET_FARVAR(SEG_LOW, (var), (val))
-#define LOWFLAT2LOW(var) ((typeof(var))((void*)(var) - (u32)zonelow_base))
+#define LOWFLAT2LOW(var) ((typeof(var))((void*)(var) - SYMBOL(zonelow_base)))
#else
#define GET_LOW(var) (var)
#define SET_LOW(var, val) do { (var) = (val); } while (0)
diff --git a/qemu/roms/seabios/src/block.c b/qemu/roms/seabios/src/block.c
index 3f7ecb1d7..1762e2a33 100644
--- a/qemu/roms/seabios/src/block.c
+++ b/qemu/roms/seabios/src/block.c
@@ -10,9 +10,16 @@
#include "hw/ata.h" // process_ata_op
#include "hw/ahci.h" // process_ahci_op
#include "hw/blockcmd.h" // cdb_*
+#include "hw/esp-scsi.h" // esp_scsi_process_op
+#include "hw/lsi-scsi.h" // lsi_scsi_process_op
+#include "hw/megasas.h" // megasas_process_op
#include "hw/pci.h" // pci_bdf_to_bus
+#include "hw/pvscsi.h" // pvscsi_process_op
#include "hw/rtc.h" // rtc_read
+#include "hw/usb-msc.h" // usb_process_op
+#include "hw/usb-uas.h" // uas_process_op
#include "hw/virtio-blk.h" // process_virtio_blk_op
+#include "hw/virtio-scsi.h" // virtio_scsi_process_op
#include "malloc.h" // malloc_low
#include "output.h" // dprintf
#include "stacks.h" // stack_hop
@@ -67,10 +74,8 @@ get_translation(struct drive_s *drive)
u8 type = drive->type;
if (CONFIG_QEMU && type == DTYPE_ATA) {
// Emulators pass in the translation info via nvram.
- u8 ataid = drive->cntl_id;
- u8 channel = ataid / 2;
- u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + channel/2);
- translation >>= 2 * (ataid % 4);
+ u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + drive->cntl_id/4);
+ translation >>= 2 * (drive->cntl_id % 4);
translation &= 0x03;
return translation;
}
@@ -282,11 +287,21 @@ map_floppy_drive(struct drive_s *drive)
* Extended Disk Drive (EDD) get drive parameters
****************************************************************/
+// flags for bus_iface field in fill_generic_edd()
+#define EDD_ISA 0x01
+#define EDD_PCI 0x02
+#define EDD_BUS_MASK 0x0f
+#define EDD_ATA 0x10
+#define EDD_SCSI 0x20
+#define EDD_IFACE_MASK 0xf0
+
+// Fill in EDD info
static int
-fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf
- , u32 dpte_so, char *iface_type
- , int bdf, u8 channel, u16 iobase, u64 device_path)
+fill_generic_edd(struct segoff_s edd, struct drive_s *drive_gf
+ , u32 dpte_so, u8 bus_iface, u32 iface_path, u32 device_path)
{
+ u16 seg = edd.seg;
+ struct int13dpt_s *param_far = (void*)(edd.offset+0);
u16 size = GET_FARVAR(seg, param_far->size);
u16 t13 = size == 74;
@@ -335,7 +350,7 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf
SET_FARVAR(seg, param_far->size, 30);
SET_FARVAR(seg, param_far->dpte.segoff, dpte_so);
- if (size < 66 || !iface_type)
+ if (size < 66 || !bus_iface)
return DISK_RET_SUCCESS;
// EDD 3.x
@@ -344,32 +359,22 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf
SET_FARVAR(seg, param_far->reserved1, 0);
SET_FARVAR(seg, param_far->reserved2, 0);
- int i;
- for (i=0; i<sizeof(param_far->iface_type); i++)
- SET_FARVAR(seg, param_far->iface_type[i], GET_GLOBAL(iface_type[i]));
-
- if (bdf != -1) {
- SET_FARVAR(seg, param_far->host_bus[0], 'P');
- SET_FARVAR(seg, param_far->host_bus[1], 'C');
- SET_FARVAR(seg, param_far->host_bus[2], 'I');
- SET_FARVAR(seg, param_far->host_bus[3], ' ');
-
- u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
- | (pci_bdf_to_fn(bdf) << 16));
- if (t13)
- path |= channel << 24;
-
- SET_FARVAR(seg, param_far->iface_path, path);
- } else {
- // ISA
- SET_FARVAR(seg, param_far->host_bus[0], 'I');
- SET_FARVAR(seg, param_far->host_bus[1], 'S');
- SET_FARVAR(seg, param_far->host_bus[2], 'A');
- SET_FARVAR(seg, param_far->host_bus[3], ' ');
-
- SET_FARVAR(seg, param_far->iface_path, iobase);
+ const char *host_bus = "ISA ";
+ if ((bus_iface & EDD_BUS_MASK) == EDD_PCI) {
+ host_bus = "PCI ";
+ if (!t13)
+ // Phoenix v3 spec (pre t13) did not define the PCI channel field
+ iface_path &= 0x00ffffff;
}
-
+ memcpy_far(seg, param_far->host_bus, SEG_BIOS, host_bus
+ , sizeof(param_far->host_bus));
+ SET_FARVAR(seg, param_far->iface_path, iface_path);
+
+ const char *iface_type = "ATA ";
+ if ((bus_iface & EDD_IFACE_MASK) == EDD_SCSI)
+ iface_type = "SCSI ";
+ memcpy_far(seg, param_far->iface_type, SEG_BIOS, iface_type
+ , sizeof(param_far->iface_type));
if (t13) {
SET_FARVAR(seg, param_far->t13.device_path[0], device_path);
SET_FARVAR(seg, param_far->t13.device_path[1], 0);
@@ -386,10 +391,19 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf
return DISK_RET_SUCCESS;
}
+// Build an EDD "iface_path" field for a PCI device
+static u32
+edd_pci_path(u16 bdf, u8 channel)
+{
+ return (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
+ | (pci_bdf_to_fn(bdf) << 16) | ((u32)channel << 24));
+}
+
struct dpte_s DefaultDPTE VARLOW;
+// EDD info for ATA and ATAPI drives
static int
-fill_ata_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf)
+fill_ata_edd(struct segoff_s edd, struct drive_s *drive_gf)
{
if (!CONFIG_ATA)
return DISK_RET_EPARAM;
@@ -440,109 +454,141 @@ fill_ata_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf)
u8 sum = checksum_far(SEG_LOW, &DefaultDPTE, 15);
SET_LOW(DefaultDPTE.checksum, -sum);
+ u32 bustype = EDD_ISA, ifpath = iobase1;
+ if (bdf >= 0) {
+ bustype = EDD_PCI;
+ ifpath = edd_pci_path(bdf, channel);
+ }
return fill_generic_edd(
- seg, param_far, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff
- , "ATA ", bdf, channel, iobase1, slave);
+ edd, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff
+ , bustype | EDD_ATA, ifpath, slave);
}
+// Fill Extended Disk Drive (EDD) "Get drive parameters" info for a drive
int noinline
-fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf)
+fill_edd(struct segoff_s edd, struct drive_s *drive_gf)
{
switch (GET_GLOBALFLAT(drive_gf->type)) {
case DTYPE_ATA:
case DTYPE_ATA_ATAPI:
- return fill_ata_edd(seg, param_far, drive_gf);
+ return fill_ata_edd(edd, drive_gf);
case DTYPE_VIRTIO_BLK:
case DTYPE_VIRTIO_SCSI:
return fill_generic_edd(
- seg, param_far, drive_gf, 0xffffffff
- , "SCSI ", GET_GLOBALFLAT(drive_gf->cntl_id), 0, 0, 0);
+ edd, drive_gf, 0xffffffff, EDD_PCI | EDD_SCSI
+ , edd_pci_path(GET_GLOBALFLAT(drive_gf->cntl_id), 0), 0);
default:
- return fill_generic_edd(seg, param_far, drive_gf, 0, NULL, 0, 0, 0, 0);
+ return fill_generic_edd(edd, drive_gf, 0, 0, 0, 0);
}
}
/****************************************************************
- * 16bit calling interface
+ * Disk driver dispatch
****************************************************************/
-int VISIBLE32FLAT
-process_atapi_op(struct disk_op_s *op)
+// Fallback handler for command requests not implemented by drivers
+int
+default_process_op(struct disk_op_s *op)
{
switch (op->command) {
- case CMD_WRITE:
case CMD_FORMAT:
- return DISK_RET_EWRITEPROTECT;
+ case CMD_RESET:
+ case CMD_ISREADY:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ // Return success if the driver doesn't implement these commands
+ return DISK_RET_SUCCESS;
default:
- return scsi_process_op(op);
+ return DISK_RET_EPARAM;
}
}
-// Execute a disk_op request.
-int
-process_op(struct disk_op_s *op)
+// Command dispatch for disk drivers that run in both 16bit and 32bit mode
+static int
+process_op_both(struct disk_op_s *op)
{
- ASSERT16();
- int ret, origcount = op->count;
- if (origcount * GET_GLOBALFLAT(op->drive_gf->blksize) > 64*1024) {
- op->count = 0;
- return DISK_RET_EBOUNDARY;
- }
- u8 type = GET_GLOBALFLAT(op->drive_gf->type);
- switch (type) {
- case DTYPE_FLOPPY:
- ret = process_floppy_op(op);
- break;
- case DTYPE_ATA:
- ret = process_ata_op(op);
- break;
- case DTYPE_RAMDISK:
- ret = process_ramdisk_op(op);
- break;
- case DTYPE_CDEMU:
- ret = process_cdemu_op(op);
- break;
- case DTYPE_VIRTIO_BLK:
- ret = process_virtio_blk_op(op);
- break;
- case DTYPE_AHCI: ;
- extern void _cfunc32flat_process_ahci_op(void);
- ret = call32(_cfunc32flat_process_ahci_op
- , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
- break;
+ switch (GET_GLOBALFLAT(op->drive_gf->type)) {
case DTYPE_ATA_ATAPI:
- ret = process_atapi_op(op);
- break;
- case DTYPE_AHCI_ATAPI: ;
- extern void _cfunc32flat_process_atapi_op(void);
- ret = call32(_cfunc32flat_process_atapi_op
- , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
- break;
- case DTYPE_SDCARD: ;
- extern void _cfunc32flat_process_sdcard_op(void);
- ret = call32(_cfunc32flat_process_sdcard_op
- , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
- break;
+ return ata_atapi_process_op(op);
case DTYPE_USB:
+ return usb_process_op(op);
case DTYPE_UAS:
- case DTYPE_VIRTIO_SCSI:
+ return uas_process_op(op);
case DTYPE_LSI_SCSI:
+ return lsi_scsi_process_op(op);
case DTYPE_ESP_SCSI:
+ return esp_scsi_process_op(op);
case DTYPE_MEGASAS:
- ret = scsi_process_op(op);
- break;
+ return megasas_process_op(op);
+ default:
+ if (!MODESEGMENT)
+ return DISK_RET_EPARAM;
+ // In 16bit mode and driver not found - try in 32bit mode
+ return call32(process_op_32, MAKE_FLATPTR(GET_SEG(SS), op)
+ , DISK_RET_EPARAM);
+ }
+}
+
+// Command dispatch for disk drivers that only run in 32bit mode
+int VISIBLE32FLAT
+process_op_32(struct disk_op_s *op)
+{
+ ASSERT32FLAT();
+ switch (op->drive_gf->type) {
+ case DTYPE_VIRTIO_BLK:
+ return virtio_blk_process_op(op);
+ case DTYPE_AHCI:
+ return ahci_process_op(op);
+ case DTYPE_AHCI_ATAPI:
+ return ahci_atapi_process_op(op);
+ case DTYPE_SDCARD:
+ return sdcard_process_op(op);
case DTYPE_USB_32:
+ return usb_process_op(op);
case DTYPE_UAS_32:
- case DTYPE_PVSCSI: ;
- extern void _cfunc32flat_scsi_process_op(void);
- ret = call32(_cfunc32flat_scsi_process_op
- , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
- break;
+ return uas_process_op(op);
+ case DTYPE_VIRTIO_SCSI:
+ return virtio_scsi_process_op(op);
+ case DTYPE_PVSCSI:
+ return pvscsi_process_op(op);
default:
- ret = DISK_RET_EPARAM;
- break;
+ return process_op_both(op);
}
+}
+
+// Command dispatch for disk drivers that only run in 16bit mode
+static int
+process_op_16(struct disk_op_s *op)
+{
+ ASSERT16();
+ switch (GET_GLOBALFLAT(op->drive_gf->type)) {
+ case DTYPE_FLOPPY:
+ return floppy_process_op(op);
+ case DTYPE_ATA:
+ return ata_process_op(op);
+ case DTYPE_RAMDISK:
+ return ramdisk_process_op(op);
+ case DTYPE_CDEMU:
+ return cdemu_process_op(op);
+ default:
+ return process_op_both(op);
+ }
+}
+
+// Execute a disk_op_s request.
+int
+process_op(struct disk_op_s *op)
+{
+ int ret, origcount = op->count;
+ if (origcount * GET_GLOBALFLAT(op->drive_gf->blksize) > 64*1024) {
+ op->count = 0;
+ return DISK_RET_EBOUNDARY;
+ }
+ if (MODESEGMENT)
+ ret = process_op_16(op);
+ else
+ ret = process_op_32(op);
if (ret && op->count == origcount)
// If the count hasn't changed on error, assume no data transferred.
op->count = 0;
@@ -578,5 +624,5 @@ send_disk_op(struct disk_op_s *op)
if (! CONFIG_DRIVES)
return -1;
- return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
+ return stack_hop(__send_disk_op, op, GET_SEG(SS));
}
diff --git a/qemu/roms/seabios/src/block.h b/qemu/roms/seabios/src/block.h
index 8182288d4..2ff359fb2 100644
--- a/qemu/roms/seabios/src/block.h
+++ b/qemu/roms/seabios/src/block.h
@@ -9,11 +9,19 @@
****************************************************************/
struct disk_op_s {
- u64 lba;
void *buf_fl;
struct drive_s *drive_gf;
- u16 count;
u8 command;
+ u16 count;
+ union {
+ // Commands: READ, WRITE, VERIFY, SEEK, FORMAT
+ u64 lba;
+ // Commands: SCSI
+ struct {
+ u16 blocksize;
+ void *cdbcmd;
+ };
+ };
};
#define CMD_RESET 0x00
@@ -23,6 +31,7 @@ struct disk_op_s {
#define CMD_FORMAT 0x05
#define CMD_SEEK 0x07
#define CMD_ISREADY 0x10
+#define CMD_SCSI 0x20
/****************************************************************
@@ -101,7 +110,8 @@ void map_floppy_drive(struct drive_s *drive);
void map_hd_drive(struct drive_s *drive);
void map_cd_drive(struct drive_s *drive);
struct int13dpt_s;
-int fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf);
+int fill_edd(struct segoff_s edd, struct drive_s *drive_gf);
+int default_process_op(struct disk_op_s *op);
int process_op(struct disk_op_s *op);
int send_disk_op(struct disk_op_s *op);
int create_bounce_buf(void);
diff --git a/qemu/roms/seabios/src/bmp.c b/qemu/roms/seabios/src/bmp.c
index d8e76b789..96a2b3f22 100644
--- a/qemu/roms/seabios/src/bmp.c
+++ b/qemu/roms/seabios/src/bmp.c
@@ -1,6 +1,6 @@
/*
* Basic BMP data process and Raw picture data handle functions.
-* Could be used to adjust pixel data format, get infomation, etc.
+* Could be used to adjust pixel data format, get information, etc.
*
* Copyright (C) 2011 Wayne Xia <xiawenc@cn.ibm.com>
*
diff --git a/qemu/roms/seabios/src/boot.c b/qemu/roms/seabios/src/boot.c
index f23e9e154..e0f73a385 100644
--- a/qemu/roms/seabios/src/boot.c
+++ b/qemu/roms/seabios/src/boot.c
@@ -19,6 +19,7 @@
#include "std/disk.h" // struct mbr_s
#include "string.h" // memset
#include "util.h" // irqtimer_calc
+#include "tcgbios.h" // tpm_*
/****************************************************************
@@ -111,9 +112,9 @@ build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci)
if (pci->parent) {
p = build_pci_path(p, max, "pci-bridge", pci->parent);
} else {
- if (pci->rootbus)
- p += snprintf(p, max, "/pci-root@%x", pci->rootbus);
p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN);
+ if (pci->rootbus)
+ p += snprintf(p, buf+max-p, ",%x", pci->rootbus);
}
int dev = pci_bdf_to_dev(pci->bdf), fn = pci_bdf_to_fn(pci->bdf);
@@ -459,8 +460,8 @@ interactive_bootmenu(void)
;
char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL);
- int menukey = romfile_loadint("etc/boot-menu-key", 0x86);
- printf("%s", bootmsg ?: "\nPress F12 for boot menu.\n\n");
+ int menukey = romfile_loadint("etc/boot-menu-key", 1);
+ printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n\n");
free(bootmsg);
u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT);
@@ -486,9 +487,15 @@ interactive_bootmenu(void)
, strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
}
- // Get key press
+ // Get key press. If the menu key is ESC, do not restart boot unless
+ // 1.5 seconds have passed. Otherwise users (trained by years of
+ // repeatedly hitting keys to enter the BIOS) will end up hitting ESC
+ // multiple times and immediately booting the primary boot device.
+ int esc_accepted_time = irqtimer_calc(menukey == 1 ? 1500 : 0);
for (;;) {
scan_code = get_keystroke(1000);
+ if (scan_code == 1 && !irqtimer_check(esc_accepted_time))
+ continue;
if (scan_code >= 1 && scan_code <= maxmenu+1)
break;
}
@@ -622,6 +629,8 @@ boot_disk(u8 bootdrv, int checksig)
}
}
+ tpm_add_bcv(bootdrv, MAKE_FLATPTR(bootseg, 0), 512);
+
/* Canonicalize bootseg:bootip */
u16 bootip = (bootseg & 0x0fff) << 4;
bootseg &= 0xf000;
@@ -645,6 +654,9 @@ boot_cdrom(struct drive_s *drive_g)
u8 bootdrv = CDEmu.emulated_drive;
u16 bootseg = CDEmu.load_segment;
+
+ tpm_add_cdrom(bootdrv, MAKE_FLATPTR(bootseg, 0), 512);
+
/* Canonicalize bootseg:bootip */
u16 bootip = (bootseg & 0x0fff) << 4;
bootseg &= 0xf000;
diff --git a/qemu/roms/seabios/src/cdrom.c b/qemu/roms/seabios/src/cdrom.c
index 92f34f42b..a4f31adde 100644
--- a/qemu/roms/seabios/src/cdrom.c
+++ b/qemu/roms/seabios/src/cdrom.c
@@ -15,9 +15,7 @@
#include "std/disk.h" // DISK_RET_SUCCESS
#include "string.h" // memset
#include "util.h" // cdrom_prepboot
-
-// Locks for removable devices
-u8 CDRom_locks[BUILD_MAX_EXTDRIVE] VARLOW;
+#include "tcgbios.h" // tpm_*
/****************************************************************
@@ -88,7 +86,7 @@ cdemu_read(struct disk_op_s *op)
}
int
-process_cdemu_op(struct disk_op_s *op)
+cdemu_process_op(struct disk_op_s *op)
{
if (!CONFIG_CDROM_EMU)
return 0;
@@ -99,13 +97,8 @@ process_cdemu_op(struct disk_op_s *op)
case CMD_WRITE:
case CMD_FORMAT:
return DISK_RET_EWRITEPROTECT;
- case CMD_VERIFY:
- case CMD_RESET:
- case CMD_SEEK:
- case CMD_ISREADY:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -122,7 +115,6 @@ cdrom_prepboot(void)
struct drive_s *drive = malloc_fseg(sizeof(*drive));
if (!drive) {
warn_noalloc();
- free(drive);
return;
}
cdemu_drive_gf = drive;
@@ -158,7 +150,7 @@ cdrom_boot(struct drive_s *drive)
dop.lba = 0x11;
dop.count = 1;
dop.buf_fl = buffer;
- ret = scsi_process_op(&dop);
+ ret = process_op(&dop);
if (ret)
return 3;
@@ -174,7 +166,7 @@ cdrom_boot(struct drive_s *drive)
// And we read the Boot Catalog
dop.lba = lba;
dop.count = 1;
- ret = scsi_process_op(&dop);
+ ret = process_op(&dop);
if (ret)
return 7;
@@ -192,6 +184,9 @@ cdrom_boot(struct drive_s *drive)
if (buffer[0x20] != 0x88)
return 11; // Bootable
+ /* measure 2048 bytes (one sector) */
+ tpm_add_cdrom_catalog(MAKE_FLATPTR(GET_SEG(SS), buffer), sizeof(buffer));
+
// Fill in el-torito cdrom emulation fields.
emulated_drive_gf = drive;
u8 media = buffer[0x21];
@@ -220,7 +215,7 @@ cdrom_boot(struct drive_s *drive)
if (count > 64*1024/CDROM_SECTOR_SIZE)
count = 64*1024/CDROM_SECTOR_SIZE;
dop.count = count;
- ret = scsi_process_op(&dop);
+ ret = process_op(&dop);
if (ret)
return 12;
nbsectors -= count;
diff --git a/qemu/roms/seabios/src/clock.c b/qemu/roms/seabios/src/clock.c
index 9ab0ac026..e83e0f338 100644
--- a/qemu/roms/seabios/src/clock.c
+++ b/qemu/roms/seabios/src/clock.c
@@ -8,6 +8,7 @@
#include "biosvar.h" // SET_BDA
#include "bregs.h" // struct bregs
#include "hw/pic.h" // pic_eoi1
+#include "hw/ps2port.h" // ps2_check_event
#include "hw/rtc.h" // rtc_read
#include "hw/usb-hid.h" // usb_check_event
#include "output.h" // debug_enter
@@ -55,7 +56,8 @@ clock_setup(void)
}
enable_hwirq(0, FUNC16(entry_08));
- enable_hwirq(8, FUNC16(entry_70));
+ if (CONFIG_RTC_TIMER)
+ enable_hwirq(8, FUNC16(entry_70));
}
@@ -239,6 +241,16 @@ handle_1a07(struct bregs *regs)
set_success(regs);
}
+static void
+handle_1abb(struct bregs *regs)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ dprintf(DEBUG_tcg, "16: Calling tpm_interrupt_handler\n");
+ call32(tpm_interrupt_handler32, MAKE_FLATPTR(GET_SEG(SS), regs), 0);
+}
+
// Unsupported
static void
handle_1aXX(struct bregs *regs)
@@ -260,17 +272,15 @@ handle_1a(struct bregs *regs)
case 0x05: handle_1a05(regs); break;
case 0x06: handle_1a06(regs); break;
case 0x07: handle_1a07(regs); break;
+ case 0xbb: handle_1abb(regs); break;
default: handle_1aXX(regs); break;
}
}
-// INT 08h System Timer ISR Entry Point
-void VISIBLE16
-handle_08(void)
+// Update main tick counter
+static void
+clock_update(void)
{
- debug_isr(DEBUG_ISR_08);
-
- // Update counter
u32 counter = GET_BDA(timer_counter);
counter++;
// compare to one days worth of timer ticks at 18.2 hz
@@ -284,6 +294,15 @@ handle_08(void)
// Check for internal events.
floppy_tick();
usb_check_event();
+ ps2_check_event();
+}
+
+// INT 08h System Timer ISR Entry Point
+void VISIBLE16
+handle_08(void)
+{
+ debug_isr(DEBUG_ISR_08);
+ clock_update();
// chain to user timer tick INT #0x1c
struct bregs br;
@@ -294,6 +313,20 @@ handle_08(void)
pic_eoi1();
}
+u32 last_timer_check VARLOW;
+
+// Simulate timer irq on machines without hardware irqs
+void
+clock_poll_irq(void)
+{
+ if (CONFIG_HARDWARE_IRQ)
+ return;
+ if (!timer_check(GET_LOW(last_timer_check)))
+ return;
+ SET_LOW(last_timer_check, timer_calc(ticks_to_ms(1)));
+ clock_update();
+}
+
/****************************************************************
* IRQ based timer
@@ -359,6 +392,10 @@ clear_usertimer(void)
void
handle_1586(struct bregs *regs)
{
+ if (!CONFIG_RTC_TIMER) {
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+ return;
+ }
// Use the rtc to wait for the specified time.
u8 statusflag = 0;
u32 count = (regs->cx << 16) | regs->dx;
@@ -402,6 +439,10 @@ handle_1583XX(struct bregs *regs)
void
handle_1583(struct bregs *regs)
{
+ if (!CONFIG_RTC_TIMER) {
+ handle_1583XX(regs);
+ return;
+ }
switch (regs->al) {
case 0x00: handle_158300(regs); break;
case 0x01: handle_158301(regs); break;
@@ -415,6 +456,8 @@ handle_1583(struct bregs *regs)
void VISIBLE16
handle_70(void)
{
+ if (!CONFIG_RTC_TIMER)
+ return;
debug_isr(DEBUG_ISR_70);
// Check which modes are enabled and have occurred.
diff --git a/qemu/roms/seabios/src/config.h b/qemu/roms/seabios/src/config.h
index 6da067d0b..6c47f161c 100644
--- a/qemu/roms/seabios/src/config.h
+++ b/qemu/roms/seabios/src/config.h
@@ -22,6 +22,8 @@
#define BUILD_MAX_EXTDRIVE 16
// Number of bytes the smbios may be and still live in the f-segment
#define BUILD_MAX_SMBIOS_FSEG 600
+// Maximum number of bytes the mptable may be and still be copied to f-segment
+#define BUILD_MAX_MPTABLE_FSEG 600
#define BUILD_MODEL_ID 0xFC
#define BUILD_SUBMODEL_ID 0x00
@@ -104,5 +106,6 @@
#define DEBUG_unimplemented 2
#define DEBUG_invalid 3
#define DEBUG_thread 2
+#define DEBUG_tcg 20
#endif // config.h
diff --git a/qemu/roms/seabios/src/disk.c b/qemu/roms/seabios/src/disk.c
index 0e0af24b3..3854d0024 100644
--- a/qemu/roms/seabios/src/disk.c
+++ b/qemu/roms/seabios/src/disk.c
@@ -407,6 +407,9 @@ disk_1344(struct bregs *regs, struct drive_s *drive_gf)
extended_access(regs, drive_gf, CMD_VERIFY);
}
+// Locks for removable devices
+u8 CDRom_locks[BUILD_MAX_EXTDRIVE] VARLOW;
+
// lock
static void
disk_134500(struct bregs *regs, struct drive_s *drive_gf)
@@ -519,7 +522,7 @@ disk_1347(struct bregs *regs, struct drive_s *drive_gf)
static void
disk_1348(struct bregs *regs, struct drive_s *drive_gf)
{
- int ret = fill_edd(regs->ds, (void*)(regs->si+0), drive_gf);
+ int ret = fill_edd(SEGOFF(regs->ds, regs->si), drive_gf);
disk_ret(regs, ret);
}
diff --git a/qemu/roms/seabios/src/memmap.c b/qemu/roms/seabios/src/e820map.c
index e03f8d0bf..39445cf63 100644
--- a/qemu/roms/seabios/src/memmap.c
+++ b/qemu/roms/seabios/src/e820map.c
@@ -5,7 +5,7 @@
// This file may be distributed under the terms of the GNU LGPLv3 license.
#include "config.h" // BUILD_MAX_E820
-#include "memmap.h" // struct e820entry
+#include "e820map.h" // struct e820entry
#include "output.h" // dprintf
#include "string.h" // memmove
@@ -54,7 +54,6 @@ e820_type_name(u32 type)
case E820_ACPI: return "ACPI";
case E820_NVS: return "NVS";
case E820_UNUSABLE: return "UNUSABLE";
- case E820_HOLE: return "HOLE";
default: return "UNKNOWN";
}
}
@@ -73,12 +72,14 @@ dump_map(void)
}
}
+#define E820_HOLE ((u32)-1) // Used internally to remove entries
+
// Add a new entry to the list. This scans for overlaps and keeps the
// list sorted.
void
-add_e820(u64 start, u64 size, u32 type)
+e820_add(u64 start, u64 size, u32 type)
{
- dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
+ dprintf(8, "Add to e820 map: %08llx %08llx %d\n", start, size, type);
if (! size)
// Huh? Nothing to do.
@@ -136,9 +137,16 @@ add_e820(u64 start, u64 size, u32 type)
//dump_map();
}
+// Remove any definitions in a memory range (make a memory hole).
+void
+e820_remove(u64 start, u64 size)
+{
+ e820_add(start, size, E820_HOLE);
+}
+
// Report on final memory locations.
void
-memmap_prepboot(void)
+e820_prepboot(void)
{
dump_map();
}
diff --git a/qemu/roms/seabios/src/e820map.h b/qemu/roms/seabios/src/e820map.h
new file mode 100644
index 000000000..de8b52300
--- /dev/null
+++ b/qemu/roms/seabios/src/e820map.h
@@ -0,0 +1,26 @@
+#ifndef __E820MAP_H
+#define __E820MAP_H
+
+#include "types.h" // u64
+
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_UNUSABLE 5
+
+struct e820entry {
+ u64 start;
+ u64 size;
+ u32 type;
+};
+
+void e820_add(u64 start, u64 size, u32 type);
+void e820_remove(u64 start, u64 size);
+void e820_prepboot(void);
+
+// e820 map storage
+extern struct e820entry e820_list[];
+extern int e820_count;
+
+#endif // e820map.h
diff --git a/qemu/roms/seabios/src/fw/biostables.c b/qemu/roms/seabios/src/fw/biostables.c
index 50a891be8..9fb9ff9df 100644
--- a/qemu/roms/seabios/src/fw/biostables.c
+++ b/qemu/roms/seabios/src/fw/biostables.c
@@ -6,14 +6,15 @@
#include "byteorder.h" // le32_to_cpu
#include "config.h" // CONFIG_*
+#include "hw/pci.h" // pci_config_writeb
#include "malloc.h" // malloc_fseg
+#include "memmap.h" // SYMBOL
#include "output.h" // dprintf
-#include "hw/pci.h" // pci_config_writeb
+#include "romfile.h" // romfile_find
#include "std/acpi.h" // struct rsdp_descriptor
#include "std/mptable.h" // MPTABLE_SIGNATURE
#include "std/pirtable.h" // struct pir_header
#include "std/smbios.h" // struct smbios_entry_point
-#include "romfile.h"
#include "string.h" // memcpy
#include "util.h" // copy_table
#include "x86.h" // outb
@@ -54,6 +55,11 @@ copy_mptable(void *pos)
return;
u32 length = p->length * 16;
u16 mpclength = ((struct mptable_config_s *)p->physaddr)->length;
+ if (length + mpclength > BUILD_MAX_MPTABLE_FSEG) {
+ dprintf(1, "Skipping MPTABLE copy due to large size (%d bytes)\n"
+ , length + mpclength);
+ return;
+ }
// Allocate final memory location. (In theory the config
// structure can go in high memory, but Linux kernels before
// v2.6.30 crash with that.)
@@ -117,9 +123,8 @@ copy_acpi_rsdp(void *pos)
void *find_acpi_rsdp(void)
{
- extern u8 zonefseg_start[], zonefseg_end[];
- unsigned long start = (unsigned long)zonefseg_start;
- unsigned long end = (unsigned long)zonefseg_end;
+ unsigned long start = SYMBOL(zonefseg_start);
+ unsigned long end = SYMBOL(zonefseg_end);
unsigned long pos;
for (pos = ALIGN(start, 0x10); pos <= ALIGN_DOWN(end, 0x10); pos += 0x10)
@@ -271,7 +276,7 @@ copy_smbios(void *pos)
if (SMBiosAddr)
return;
struct smbios_entry_point *p = pos;
- if (memcmp(p->anchor_string, "_SM_", 4))
+ if (p->signature != SMBIOS_SIGNATURE)
return;
if (checksum(pos, 0x10) != 0)
return;
@@ -301,17 +306,42 @@ display_uuid(void)
if (memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0)
return;
- printf("Machine UUID"
- " %02x%02x%02x%02x"
- "-%02x%02x"
- "-%02x%02x"
- "-%02x%02x"
- "-%02x%02x%02x%02x%02x%02x\n"
- , uuid[ 0], uuid[ 1], uuid[ 2], uuid[ 3]
- , uuid[ 4], uuid[ 5]
- , uuid[ 6], uuid[ 7]
- , uuid[ 8], uuid[ 9]
- , uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
+ /*
+ * According to SMBIOS v2.6 the first three fields are encoded in
+ * little-endian format. Versions prior to v2.6 did not specify
+ * the encoding, but we follow dmidecode and assume big-endian
+ * encoding.
+ */
+ if (SMBiosAddr->smbios_major_version > 2 ||
+ (SMBiosAddr->smbios_major_version == 2 &&
+ SMBiosAddr->smbios_minor_version >= 6)) {
+ printf("Machine UUID"
+ " %02x%02x%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x%02x%02x%02x%02x\n"
+ , uuid[ 3], uuid[ 2], uuid[ 1], uuid[ 0]
+ , uuid[ 5], uuid[ 4]
+ , uuid[ 7], uuid[ 6]
+ , uuid[ 8], uuid[ 9]
+ , uuid[10], uuid[11], uuid[12]
+ , uuid[13], uuid[14], uuid[15]);
+ } else {
+ printf("Machine UUID"
+ " %02x%02x%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x%02x%02x%02x%02x\n"
+ , uuid[ 0], uuid[ 1], uuid[ 2], uuid[ 3]
+ , uuid[ 4], uuid[ 5]
+ , uuid[ 6], uuid[ 7]
+ , uuid[ 8], uuid[ 9]
+ , uuid[10], uuid[11], uuid[12]
+ , uuid[13], uuid[14], uuid[15]);
+ }
+
return;
}
}
@@ -447,7 +477,7 @@ void
smbios_setup(void)
{
if (smbios_romfile_setup())
- return;
+ return;
smbios_legacy_setup();
}
diff --git a/qemu/roms/seabios/src/fw/coreboot.c b/qemu/roms/seabios/src/fw/coreboot.c
index 8fd84493b..4fe12928c 100644
--- a/qemu/roms/seabios/src/fw/coreboot.c
+++ b/qemu/roms/seabios/src/fw/coreboot.c
@@ -7,10 +7,10 @@
#include "block.h" // MAXDESCSIZE
#include "byteorder.h" // be32_to_cpu
#include "config.h" // CONFIG_*
+#include "e820map.h" // e820_add
#include "hw/pci.h" // pci_probe_devices
#include "lzmadecode.h" // LzmaDecode
#include "malloc.h" // free
-#include "memmap.h" // add_e820
#include "output.h" // dprintf
#include "paravirt.h" // PlatformRunningOn
#include "romfile.h" // romfile_findprefix
@@ -184,12 +184,12 @@ coreboot_preinit(void)
u32 type = m->type;
if (type == CB_MEM_TABLE)
type = E820_RESERVED;
- add_e820(m->start, m->size, type);
+ e820_add(m->start, m->size, type);
}
// Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
// confuses grub. So, override it.
- add_e820(0, 16*1024, E820_RAM);
+ e820_add(0, 16*1024, E820_RAM);
struct cb_cbmem_ref *cbref = find_cb_subtable(cbh, CB_TAG_CBMEM_CONSOLE);
if (cbref) {
@@ -210,7 +210,7 @@ coreboot_preinit(void)
fail:
// No table found.. Use 16Megs as a dummy value.
dprintf(1, "Unable to find coreboot table!\n");
- add_e820(0, 16*1024*1024, E820_RAM);
+ e820_add(0, 16*1024*1024, E820_RAM);
return;
}
@@ -421,6 +421,13 @@ coreboot_cbfs_init(void)
return;
struct cbfs_header *hdr = *(void **)(CONFIG_CBFS_LOCATION - 4);
+ if ((u32)hdr & 0x03) {
+ dprintf(1, "Invalid CBFS pointer %p\n", hdr);
+ return;
+ }
+ if (CONFIG_CBFS_LOCATION && (u32)hdr > CONFIG_CBFS_LOCATION)
+ // Looks like the pointer is relative to CONFIG_CBFS_LOCATION
+ hdr = (void*)hdr + CONFIG_CBFS_LOCATION;
if (hdr->magic != cpu_to_be32(CBFS_HEADER_MAGIC)) {
dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
, hdr, hdr->magic, cpu_to_be32(CBFS_HEADER_MAGIC));
@@ -503,7 +510,7 @@ cbfs_run_payload(struct cbfs_file *fhdr)
break;
case PAYLOAD_SEGMENT_ENTRY: {
dprintf(1, "Calling addr %p\n", dest);
- void (*func)() = dest;
+ void (*func)(void) = dest;
func();
return;
}
diff --git a/qemu/roms/seabios/src/fw/csm.c b/qemu/roms/seabios/src/fw/csm.c
index 7cdb398f2..7cadd12e5 100644
--- a/qemu/roms/seabios/src/fw/csm.c
+++ b/qemu/roms/seabios/src/fw/csm.c
@@ -4,20 +4,21 @@
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "bregs.h"
+#include "bregs.h" // struct bregs
#include "config.h" // CONFIG_*
+#include "e820map.h" // e820_add
#include "farptr.h" // MAKE_FLATPTR
-#include "hw/pci.h"
-#include "hw/pic.h"
-#include "malloc.h" // csm_malloc_preinit
-#include "memmap.h"
+#include "hw/pci.h" // pci_probe_devices
+#include "hw/pic.h" // pic_irqmask_read
+#include "malloc.h" // malloc_csm_preinit
+#include "memmap.h" // SYMBOL
#include "output.h" // dprintf
+#include "paravirt.h" // qemu_preinit
#include "stacks.h" // wait_threads
#include "std/acpi.h" // RSDP_SIGNATURE
#include "std/bda.h" // struct bios_data_area_s
#include "std/optionrom.h" // struct rom_header
#include "util.h" // copy_smbios
-#include "paravirt.h" // qemu_preinit
#define UINT8 u8
#define UINT16 u16
@@ -47,12 +48,11 @@ static void
csm_return(struct bregs *regs)
{
u32 rommax = rom_get_max();
- extern u8 final_readonly_start[];
dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
csm_compat_table.UmaAddress = rommax;
- csm_compat_table.UmaSize = (u32)final_readonly_start - rommax;
+ csm_compat_table.UmaSize = SYMBOL(final_readonly_start) - rommax;
PICMask = pic_irqmask_read();
__csm_return(regs);
@@ -95,7 +95,7 @@ handle_csm_0000(struct bregs *regs)
dprintf(3, "LoPmmMemory %08x\n", csm_init_table->LowPmmMemory);
dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes);
- csm_malloc_preinit(csm_init_table->LowPmmMemory,
+ malloc_csm_preinit(csm_init_table->LowPmmMemory,
csm_init_table->LowPmmMemorySizeInBytes,
csm_init_table->HiPmmMemory,
csm_init_table->HiPmmMemorySizeInBytes);
@@ -147,11 +147,11 @@ handle_csm_0002(struct bregs *regs)
struct e820entry *p = (void *)csm_compat_table.E820Pointer;
int i;
for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++)
- add_e820(p[i].start, p[i].size, p[i].type);
+ e820_add(p[i].start, p[i].size, p[i].type);
if (csm_init_table->HiPmmMemorySizeInBytes > BUILD_MAX_HIGHTABLE) {
u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes;
- add_e820(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
+ e820_add(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
}
// For PCIBIOS 1ab10e
@@ -183,6 +183,7 @@ handle_csm_0002(struct bregs *regs)
struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
bda->hdcount = 0;
+ thread_setup();
mathcp_setup();
timer_setup();
clock_setup();
diff --git a/qemu/roms/seabios/src/fw/dev-q35.h b/qemu/roms/seabios/src/fw/dev-q35.h
index c6f8bd9e7..201825deb 100644
--- a/qemu/roms/seabios/src/fw/dev-q35.h
+++ b/qemu/roms/seabios/src/fw/dev-q35.h
@@ -27,6 +27,9 @@
#define ICH9_LPC_GEN_PMCON_1_SMI_LOCK (1 << 4)
#define ICH9_LPC_PORT_ELCR1 0x4d0
#define ICH9_LPC_PORT_ELCR2 0x4d1
+#define ICH9_LPC_RCBA 0xf0
+#define ICH9_LPC_RCBA_ADDR 0xfed1c000
+#define ICH9_LPC_RCBA_EN 0x1
#define PCI_DEVICE_ID_INTEL_ICH9_SMBUS 0x2930
#define ICH9_SMB_SMB_BASE 0x20
#define ICH9_SMB_HOSTC 0x40
diff --git a/qemu/roms/seabios/src/fw/multiboot.c b/qemu/roms/seabios/src/fw/multiboot.c
new file mode 100644
index 000000000..d9df06764
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/multiboot.c
@@ -0,0 +1,111 @@
+// Multiboot interface support.
+//
+// Copyright (C) 2015 Vladimir Serbinenko <phcoder@gmail.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_add
+#include "std/multiboot.h" // MULTIBOOT_*
+#include "string.h" // memset
+#include "util.h" // multiboot_init
+
+struct mbfs_romfile_s {
+ struct romfile_s file;
+ void *data;
+};
+
+static int
+extract_filename(char *dest, char *src, size_t lim)
+{
+ char *ptr;
+ for (ptr = src; *ptr; ptr++) {
+ if (!(ptr == src || ptr[-1] == ' ' || ptr[-1] == '\t'))
+ continue;
+ /* memcmp stops early if it encounters \0 as it doesn't match name=. */
+ if (memcmp(ptr, "name=", 5) == 0) {
+ int i;
+ char *optr = dest;
+ for (i = 0, ptr += 5; *ptr && *ptr != ' ' && i < lim; i++) {
+ *optr++ = *ptr++;
+ }
+ *optr++ = '\0';
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// Copy a file to memory
+static int
+mbfs_copyfile(struct romfile_s *file, void *dst, u32 maxlen)
+{
+ struct mbfs_romfile_s *cfile;
+ cfile = container_of(file, struct mbfs_romfile_s, file);
+ u32 size = cfile->file.size;
+ void *src = cfile->data;
+
+ // Not compressed.
+ dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst);
+ if (size > maxlen) {
+ warn_noalloc();
+ return -1;
+ }
+ iomemcpy(dst, src, size);
+ return size;
+}
+
+u32 __VISIBLE entry_elf_eax, entry_elf_ebx;
+
+void
+multiboot_init(void)
+{
+ struct multiboot_info *mbi;
+ if (!CONFIG_MULTIBOOT)
+ return;
+ dprintf(1, "multiboot: eax=%x, ebx=%x\n", entry_elf_eax, entry_elf_ebx);
+ if (entry_elf_eax != MULTIBOOT_BOOTLOADER_MAGIC)
+ return;
+ mbi = (void *)entry_elf_ebx;
+ dprintf(1, "mbptr=%p\n", mbi);
+ dprintf(1, "flags=0x%x, mods=0x%x, mods_c=%d\n", mbi->flags, mbi->mods_addr,
+ mbi->mods_count);
+ if (!(mbi->flags & MULTIBOOT_INFO_MODS))
+ return;
+ int i;
+ struct multiboot_mod_list *mod = (void *)mbi->mods_addr;
+ for (i = 0; i < mbi->mods_count; i++) {
+ struct mbfs_romfile_s *cfile;
+ u8 *copy;
+ u32 len;
+ if (!mod[i].cmdline)
+ continue;
+ len = mod[i].mod_end - mod[i].mod_start;
+ cfile = malloc_tmp(sizeof(*cfile));
+ if (!cfile) {
+ warn_noalloc();
+ return;
+ }
+ memset(cfile, 0, sizeof(*cfile));
+ dprintf(1, "module %s, size 0x%x\n", (char *)mod[i].cmdline, len);
+ if (!extract_filename(cfile->file.name, (char *)mod[i].cmdline,
+ sizeof(cfile->file.name))) {
+ free(cfile);
+ continue;
+ }
+ dprintf(1, "assigned file name <%s>\n", cfile->file.name);
+ cfile->file.size = len;
+ copy = malloc_tmp(len);
+ if (!copy) {
+ warn_noalloc();
+ free(cfile);
+ return;
+ }
+ memcpy(copy, (void *)mod[i].mod_start, len);
+ cfile->file.copy = mbfs_copyfile;
+ cfile->data = copy;
+ romfile_add(&cfile->file);
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/paravirt.c b/qemu/roms/seabios/src/fw/paravirt.c
index db22ae8fc..3fae13a83 100644
--- a/qemu/roms/seabios/src/fw/paravirt.c
+++ b/qemu/roms/seabios/src/fw/paravirt.c
@@ -10,11 +10,11 @@
#include "byteorder.h" // be32_to_cpu
#include "config.h" // CONFIG_QEMU
+#include "e820map.h" // e820_add
#include "hw/pci.h" // create_pirtable
#include "hw/pci_regs.h" // PCI_DEVICE_ID
#include "hw/rtc.h" // CMOS_*
#include "malloc.h" // malloc_tmp
-#include "memmap.h" // add_e820
#include "output.h" // dprintf
#include "paravirt.h" // qemu_cfg_preinit
#include "romfile.h" // romfile_loadint
@@ -23,6 +23,7 @@
#include "util.h" // pci_setup
#include "x86.h" // cpuid
#include "xen.h" // xen_biostable_setup
+#include "stacks.h" // yield
// Amount of continuous ram under 4Gig
u32 RamSize;
@@ -30,6 +31,13 @@ u32 RamSize;
u64 RamSizeOver4G;
// Type of emulator platform.
int PlatformRunningOn VARFSEG;
+// cfg_dma enabled
+int cfg_dma_enabled = 0;
+
+inline int qemu_cfg_dma_enabled(void)
+{
+ return cfg_dma_enabled;
+}
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
* should be used to determine that a VM is running under KVM.
@@ -114,10 +122,10 @@ qemu_preinit(void)
| (rtc_read(CMOS_MEM_EXTMEM_HIGH) << 18))
+ 1 * 1024 * 1024);
RamSize = rs;
- add_e820(0, rs, E820_RAM);
+ e820_add(0, rs, E820_RAM);
/* reserve 256KB BIOS area at the end of 4 GB */
- add_e820(0xfffc0000, 256*1024, E820_RESERVED);
+ e820_add(0xfffc0000, 256*1024, E820_RESERVED);
dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize);
}
@@ -199,23 +207,63 @@ qemu_cfg_select(u16 f)
}
static void
+qemu_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+ QemuCfgDmaAccess access;
+
+ access.address = cpu_to_be64((u64)(u32)address);
+ access.length = cpu_to_be32(length);
+ access.control = cpu_to_be32(control);
+
+ barrier();
+
+ outl(cpu_to_be32((u32)&access), PORT_QEMU_CFG_DMA_ADDR_LOW);
+
+ while(be32_to_cpu(access.control) & ~QEMU_CFG_DMA_CTL_ERROR) {
+ yield();
+ }
+}
+
+static void
qemu_cfg_read(void *buf, int len)
{
- insb(PORT_QEMU_CFG_DATA, buf, len);
+ if (len == 0) {
+ return;
+ }
+
+ if (qemu_cfg_dma_enabled()) {
+ qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_READ);
+ } else {
+ insb(PORT_QEMU_CFG_DATA, buf, len);
+ }
}
static void
qemu_cfg_skip(int len)
{
- while (len--)
- inb(PORT_QEMU_CFG_DATA);
+ if (len == 0) {
+ return;
+ }
+
+ if (qemu_cfg_dma_enabled()) {
+ qemu_cfg_dma_transfer(0, len, QEMU_CFG_DMA_CTL_SKIP);
+ } else {
+ while (len--)
+ inb(PORT_QEMU_CFG_DATA);
+ }
}
static void
qemu_cfg_read_entry(void *buf, int e, int len)
{
- qemu_cfg_select(e);
- qemu_cfg_read(buf, len);
+ if (qemu_cfg_dma_enabled()) {
+ u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT
+ | QEMU_CFG_DMA_CTL_READ;
+ qemu_cfg_dma_transfer(buf, len, control);
+ } else {
+ qemu_cfg_select(e);
+ qemu_cfg_read(buf, len);
+ }
}
struct qemu_romfile_s {
@@ -230,9 +278,14 @@ qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
return -1;
struct qemu_romfile_s *qfile;
qfile = container_of(file, struct qemu_romfile_s, file);
- qemu_cfg_select(qfile->select);
- qemu_cfg_skip(qfile->skip);
- qemu_cfg_read(dst, file->size);
+ if (qfile->skip == 0) {
+ /* Do it in one transfer */
+ qemu_cfg_read_entry(dst, qfile->select, file->size);
+ } else {
+ qemu_cfg_select(qfile->select);
+ qemu_cfg_skip(qfile->skip);
+ qemu_cfg_read(dst, file->size);
+ }
return file->size;
}
@@ -302,7 +355,7 @@ qemu_cfg_e820(void)
}
/* fall through */
case E820_RESERVED:
- add_e820(table[i].address, table[i].length, table[i].type);
+ e820_add(table[i].address, table[i].length, table[i].type);
break;
default:
/*
@@ -324,13 +377,13 @@ qemu_cfg_e820(void)
int i;
for (i = 0; i < count32; i++) {
qemu_cfg_read(&entry, sizeof(entry));
- add_e820(entry.address, entry.length, entry.type);
+ e820_add(entry.address, entry.length, entry.type);
}
} else if (runningOnKVM()) {
// Backwards compatibility - provide hard coded range.
// 4 pages before the bios, 3 pages for vmx tss pages, the
// other page for EPT real mode pagetable
- add_e820(0xfffbc000, 4*4096, E820_RESERVED);
+ e820_add(0xfffbc000, 4*4096, E820_RESERVED);
}
// Check for memory over 4Gig in cmos
@@ -338,7 +391,7 @@ qemu_cfg_e820(void)
| ((u32)rtc_read(CMOS_MEM_HIGHMEM_MID) << 24)
| ((u64)rtc_read(CMOS_MEM_HIGHMEM_HIGH) << 32));
RamSizeOver4G = high;
- add_e820(0x100000000ull, high, E820_RAM);
+ e820_add(0x100000000ull, high, E820_RAM);
dprintf(1, "RamSizeOver4G: 0x%016llx [cmos]\n", RamSizeOver4G);
}
@@ -422,8 +475,18 @@ void qemu_cfg_init(void)
for (i = 0; i < 4; i++)
if (inb(PORT_QEMU_CFG_DATA) != sig[i])
return;
+
dprintf(1, "Found QEMU fw_cfg\n");
+ // Detect DMA interface.
+ u32 id;
+ qemu_cfg_read_entry(&id, QEMU_CFG_ID, sizeof(id));
+
+ if (id & QEMU_CFG_VERSION_DMA) {
+ dprintf(1, "QEMU fw_cfg DMA interface supported\n");
+ cfg_dma_enabled = 1;
+ }
+
// Populate romfiles for legacy fw_cfg entries
qemu_cfg_legacy();
diff --git a/qemu/roms/seabios/src/fw/paravirt.h b/qemu/roms/seabios/src/fw/paravirt.h
index 95ffb92ad..ed8e5f1f8 100644
--- a/qemu/roms/seabios/src/fw/paravirt.h
+++ b/qemu/roms/seabios/src/fw/paravirt.h
@@ -9,6 +9,12 @@
#define PF_XEN (1<<1)
#define PF_KVM (1<<2)
+typedef struct QemuCfgDmaAccess {
+ u32 control;
+ u32 length;
+ u64 address;
+} PACKED QemuCfgDmaAccess;
+
extern u32 RamSize;
extern u64 RamSizeOver4G;
extern int PlatformRunningOn;
@@ -25,11 +31,23 @@ static inline int runningOnKVM(void) {
}
// Common paravirt ports.
-#define PORT_SMI_CMD 0x00b2
-#define PORT_SMI_STATUS 0x00b3
-#define PORT_QEMU_CFG_CTL 0x0510
-#define PORT_QEMU_CFG_DATA 0x0511
+#define PORT_SMI_CMD 0x00b2
+#define PORT_SMI_STATUS 0x00b3
+#define PORT_QEMU_CFG_CTL 0x0510
+#define PORT_QEMU_CFG_DATA 0x0511
+#define PORT_QEMU_CFG_DMA_ADDR_HIGH 0x0514
+#define PORT_QEMU_CFG_DMA_ADDR_LOW 0x0518
+
+// QEMU_CFG_DMA_CONTROL bits
+#define QEMU_CFG_DMA_CTL_ERROR 0x01
+#define QEMU_CFG_DMA_CTL_READ 0x02
+#define QEMU_CFG_DMA_CTL_SKIP 0x04
+#define QEMU_CFG_DMA_CTL_SELECT 0x08
+
+// QEMU_CFG_DMA ID bit
+#define QEMU_CFG_VERSION_DMA 2
+int qemu_cfg_dma_enabled(void);
void qemu_preinit(void);
void qemu_platform_setup(void);
void qemu_cfg_init(void);
diff --git a/qemu/roms/seabios/src/fw/pciinit.c b/qemu/roms/seabios/src/fw/pciinit.c
index 46ae7090e..c31c2fa0c 100644
--- a/qemu/roms/seabios/src/fw/pciinit.c
+++ b/qemu/roms/seabios/src/fw/pciinit.c
@@ -9,13 +9,13 @@
#include "config.h" // CONFIG_*
#include "dev-q35.h" // Q35_HOST_BRIDGE_PCIEXBAR_ADDR
#include "dev-piix.h" // PIIX_*
+#include "e820map.h" // e820_add
#include "hw/ata.h" // PORT_ATA1_CMD_BASE
#include "hw/pci.h" // pci_config_readl
#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
#include "hw/pci_regs.h" // PCI_COMMAND
#include "list.h" // struct hlist_node
#include "malloc.h" // free
-#include "memmap.h" // add_e820
#include "output.h" // dprintf
#include "paravirt.h" // RamSize
#include "romfile.h" // romfile_loadint
@@ -183,6 +183,11 @@ static void mch_isa_bridge_setup(struct pci_device *dev, void *arg)
/* acpi enable, SCI: IRQ9 000b = irq9*/
pci_config_writeb(bdf, ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_ACPI_EN);
+ /* set root complex register block BAR */
+ pci_config_writel(bdf, ICH9_LPC_RCBA,
+ ICH9_LPC_RCBA_ADDR | ICH9_LPC_RCBA_EN);
+ e820_add(ICH9_LPC_RCBA_ADDR, 16*1024, E820_RESERVED);
+
acpi_pm1a_cnt = acpi_pm_base + 0x04;
pmtimer_setup(acpi_pm_base + 0x08);
}
@@ -316,6 +321,10 @@ static void pci_bios_init_device(struct pci_device *pci)
/* enable memory mappings */
pci_config_maskw(bdf, PCI_COMMAND, 0,
PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SERR);
+ /* enable SERR# for forwarding */
+ if (pci->header_type & PCI_HEADER_TYPE_BRIDGE)
+ pci_config_maskw(bdf, PCI_BRIDGE_CONTROL, 0,
+ PCI_BRIDGE_CTL_SERR);
}
static void pci_bios_init_devices(void)
@@ -391,7 +400,7 @@ static void mch_mem_addr_setup(struct pci_device *dev, void *arg)
pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, 0);
pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR + 4, upper);
pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower);
- add_e820(addr, size, E820_RESERVED);
+ e820_add(addr, size, E820_RESERVED);
/* setup pci i/o window (above mmconfig) */
pcimem_start = addr + size;
@@ -636,9 +645,8 @@ pci_region_create_entry(struct pci_bus *bus, struct pci_device *dev,
return entry;
}
-static int pci_bus_hotplug_support(struct pci_bus *bus)
+static int pci_bus_hotplug_support(struct pci_bus *bus, u8 pcie_cap)
{
- u8 pcie_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_EXP);
u8 shpc_cap;
if (pcie_cap) {
@@ -662,7 +670,7 @@ static int pci_bus_hotplug_support(struct pci_bus *bus)
return downstream_port && slot_implemented;
}
- shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC);
+ shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC, 0);
return !!shpc_cap;
}
@@ -718,7 +726,8 @@ static int pci_bios_check_devices(struct pci_bus *busses)
*/
parent = &busses[0];
int type;
- int hotplug_support = pci_bus_hotplug_support(s);
+ u8 pcie_cap = pci_find_capability(s->bus_dev, PCI_CAP_ID_EXP, 0);
+ int hotplug_support = pci_bus_hotplug_support(s, pcie_cap);
for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
u64 align = (type == PCI_REGION_TYPE_IO) ?
PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
@@ -727,7 +736,8 @@ static int pci_bios_check_devices(struct pci_bus *busses)
if (pci_region_align(&s->r[type]) > align)
align = pci_region_align(&s->r[type]);
u64 sum = pci_region_sum(&s->r[type]);
- if (!sum && hotplug_support)
+ int resource_optional = pcie_cap && (type == PCI_REGION_TYPE_IO);
+ if (!sum && hotplug_support && !resource_optional)
sum = align; /* reserve min size for hot-plug */
u64 size = ALIGN(sum, align);
int is64 = pci_bios_bridge_region_is64(&s->r[type],
diff --git a/qemu/roms/seabios/src/fw/shadow.c b/qemu/roms/seabios/src/fw/shadow.c
index 4f00006bf..ee87d36e0 100644
--- a/qemu/roms/seabios/src/fw/shadow.c
+++ b/qemu/roms/seabios/src/fw/shadow.c
@@ -53,9 +53,8 @@ __make_bios_writable_intel(u16 bdf, u32 pam0)
return;
// Copy bios.
- extern u8 code32flat_start[], code32flat_end[];
- memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
- , code32flat_end - code32flat_start);
+ memcpy(VSYMBOL(code32flat_start), VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET
+ , SYMBOL(code32flat_end) - SYMBOL(code32flat_start));
}
static void
@@ -65,7 +64,7 @@ make_bios_writable_intel(u16 bdf, u32 pam0)
if (!(reg & 0x10)) {
// QEMU doesn't fully implement the piix shadow capabilities -
// if ram isn't backing the bios segment when shadowing is
- // disabled, the code itself wont be in memory. So, run the
+ // disabled, the code itself won't be in memory. So, run the
// code from the high-memory flash location.
u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
void (*func)(u16 bdf, u32 pam0) = (void*)pos;
@@ -165,7 +164,6 @@ qemu_prep_reset(void)
// QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
// reset, so do that manually before invoking a hard reset.
make_bios_writable();
- extern u8 code32flat_start[], code32flat_end[];
- memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
- , code32flat_end - code32flat_start);
+ memcpy(VSYMBOL(code32flat_start), VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET
+ , SYMBOL(code32flat_end) - SYMBOL(code32flat_start));
}
diff --git a/qemu/roms/seabios/src/fw/smbios.c b/qemu/roms/seabios/src/fw/smbios.c
index dba054133..f3b5ad9dd 100644
--- a/qemu/roms/seabios/src/fw/smbios.c
+++ b/qemu/roms/seabios/src/fw/smbios.c
@@ -37,7 +37,7 @@ smbios_entry_point_setup(u16 max_structure_size,
struct smbios_entry_point ep;
memset(&ep, 0, sizeof(ep));
- memcpy(ep.anchor_string, "_SM_", 4);
+ ep.signature = SMBIOS_SIGNATURE;
ep.length = 0x1f;
ep.smbios_major_version = 2;
ep.smbios_minor_version = 4;
diff --git a/qemu/roms/seabios/src/fw/smm.c b/qemu/roms/seabios/src/fw/smm.c
index 6cb484e7e..8f042ee4d 100644
--- a/qemu/roms/seabios/src/fw/smm.c
+++ b/qemu/roms/seabios/src/fw/smm.c
@@ -64,11 +64,11 @@ handle_smi(u16 cs)
return;
u8 cmd = inb(PORT_SMI_CMD);
struct smm_layout *smm = MAKE_FLATPTR(cs, 0);
+ u32 rev = smm->cpu.i32.smm_rev & SMM_REV_MASK;
dprintf(DEBUG_HDL_smi, "handle_smi cmd=%x smbase=%p\n", cmd, smm);
if (smm == (void*)BUILD_SMM_INIT_ADDR) {
// relocate SMBASE to 0xa0000
- u32 rev = smm->cpu.i32.smm_rev & SMM_REV_MASK;
if (rev == SMM_REV_I32) {
smm->cpu.i32.smm_base = BUILD_SMM_ADDR;
} else if (rev == SMM_REV_I64) {
@@ -92,7 +92,7 @@ handle_smi(u16 cs)
}
if (CONFIG_CALL32_SMM && cmd == CALL32SMM_CMDID) {
- if (smm->cpu.i32.smm_rev == SMM_REV_I32) {
+ if (rev == SMM_REV_I32) {
u32 regs[8];
memcpy(regs, &smm->cpu.i32.eax, sizeof(regs));
if (smm->cpu.i32.ecx == CALL32SMM_ENTERID) {
@@ -107,7 +107,7 @@ handle_smi(u16 cs)
memcpy(&smm->cpu.i32.eax, regs, sizeof(regs));
smm->cpu.i32.eip = regs[3];
}
- } else if (smm->cpu.i64.smm_rev == SMM_REV_I64) {
+ } else if (rev == SMM_REV_I64) {
u64 regs[8];
memcpy(regs, &smm->cpu.i64.rdi, sizeof(regs));
if ((u32)smm->cpu.i64.rcx == CALL32SMM_ENTERID) {
@@ -184,7 +184,7 @@ static void piix4_apmc_smm_setup(int isabdf, int i440_bdf)
/* enable SMI generation */
value = inl(acpi_pm_base + PIIX_PMIO_GLBCTL);
- outl(acpi_pm_base + PIIX_PMIO_GLBCTL, value | PIIX_PMIO_GLBCTL_SMI_EN);
+ outl(value | PIIX_PMIO_GLBCTL_SMI_EN, acpi_pm_base + PIIX_PMIO_GLBCTL);
smm_relocate_and_restore();
diff --git a/qemu/roms/seabios/src/fw/smp.c b/qemu/roms/seabios/src/fw/smp.c
index a466ea6e9..579acdbd0 100644
--- a/qemu/roms/seabios/src/fw/smp.c
+++ b/qemu/roms/seabios/src/fw/smp.c
@@ -52,9 +52,6 @@ handle_smp(void)
if (!CONFIG_QEMU)
return;
- // Enable CPU caching
- setcr0(getcr0() & ~(CR0_CD|CR0_NW));
-
// Detect apic_id
u32 eax, ebx, ecx, cpuid_features;
cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
diff --git a/qemu/roms/seabios/src/fw/xen.c b/qemu/roms/seabios/src/fw/xen.c
index dd8e8afd4..3f19ef2dc 100644
--- a/qemu/roms/seabios/src/fw/xen.c
+++ b/qemu/roms/seabios/src/fw/xen.c
@@ -4,16 +4,17 @@
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "config.h"
+#include "config.h" // CONFIG_XEN
+#include "e820map.h" // e820_add
#include "hw/serialio.h" // DebugOutputPort
#include "malloc.h" // memalign_high
-#include "memmap.h" // add_e820
+#include "memmap.h" // PAGE_SIZE
#include "output.h" // dprintf
#include "paravirt.h" // PlatformRunningOn
#include "string.h" // memcpy
#include "util.h" // copy_acpi_rsdp
#include "x86.h" // cpuid
-#include "xen.h"
+#include "xen.h" // xen_extraversion_t
#define INFO_PHYSICAL_ADDRESS 0x00001000
@@ -142,6 +143,6 @@ void xen_ramsize_preinit(void)
for (i = 0; i < info->e820_nr; i++) {
struct e820entry *e = &e820[i];
- add_e820(e->start, e->size, e->type);
+ e820_add(e->start, e->size, e->type);
}
}
diff --git a/qemu/roms/seabios/src/hw/ahci.c b/qemu/roms/seabios/src/hw/ahci.c
index 3193d81a6..83b747cb2 100644
--- a/qemu/roms/seabios/src/hw/ahci.c
+++ b/qemu/roms/seabios/src/hw/ahci.c
@@ -213,7 +213,7 @@ static int ahci_command(struct ahci_port_s *port_gf, int iswrite, int isatapi,
#define CDROM_CDB_SIZE 12
-int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+int ahci_atapi_process_op(struct disk_op_s *op)
{
if (! CONFIG_AHCI)
return 0;
@@ -221,15 +221,14 @@ int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
struct ahci_port_s *port_gf = container_of(
op->drive_gf, struct ahci_port_s, drive);
struct ahci_cmd_s *cmd = port_gf->cmd;
- u8 *atapi = cdbcmd;
- int i, rc;
+ if (op->command == CMD_WRITE || op->command == CMD_FORMAT)
+ return DISK_RET_EWRITEPROTECT;
+ int blocksize = scsi_fill_cmd(op, cmd->atapi, CDROM_CDB_SIZE);
+ if (blocksize < 0)
+ return default_process_op(op);
sata_prep_atapi(&cmd->fis, blocksize);
- for (i = 0; i < CDROM_CDB_SIZE; i++) {
- cmd->atapi[i] = atapi[i];
- }
- rc = ahci_command(port_gf, 0, 1, op->buf_fl,
- op->count * blocksize);
+ int rc = ahci_command(port_gf, 0, 1, op->buf_fl, op->count * blocksize);
if (rc < 0)
return DISK_RET_EBADTRACK;
return DISK_RET_SUCCESS;
@@ -296,8 +295,8 @@ ahci_disk_readwrite(struct disk_op_s *op, int iswrite)
}
// command demuxer
-int VISIBLE32FLAT
-process_ahci_op(struct disk_op_s *op)
+int
+ahci_process_op(struct disk_op_s *op)
{
if (!CONFIG_AHCI)
return 0;
@@ -306,15 +305,8 @@ process_ahci_op(struct disk_op_s *op)
return ahci_disk_readwrite(op, 0);
case CMD_WRITE:
return ahci_disk_readwrite(op, 1);
- case CMD_FORMAT:
- case CMD_RESET:
- case CMD_ISREADY:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
default:
- dprintf(1, "AHCI: unknown disk command %d\n", op->command);
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -405,6 +397,14 @@ static struct ahci_port_s* ahci_port_realloc(struct ahci_port_s *port)
port->list = memalign_high(1024, 1024);
port->fis = memalign_high(256, 256);
port->cmd = memalign_high(256, 256);
+ if (!port->list || !port->fis || !port->cmd) {
+ warn_noalloc();
+ free(port->list);
+ free(port->fis);
+ free(port->cmd);
+ free(port);
+ return NULL;
+ }
ahci_port_writel(port->ctrl, port->pnr, PORT_LST_ADDR, (u32)port->list);
ahci_port_writel(port->ctrl, port->pnr, PORT_FIS_ADDR, (u32)port->fis);
diff --git a/qemu/roms/seabios/src/hw/ahci.h b/qemu/roms/seabios/src/hw/ahci.h
index c8c755a3f..fa11d6619 100644
--- a/qemu/roms/seabios/src/hw/ahci.h
+++ b/qemu/roms/seabios/src/hw/ahci.h
@@ -83,8 +83,8 @@ struct ahci_port_s {
};
void ahci_setup(void);
-int process_ahci_op(struct disk_op_s *op);
-int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int ahci_process_op(struct disk_op_s *op);
+int ahci_atapi_process_op(struct disk_op_s *op);
#define AHCI_IRQ_ON_SG (1 << 31)
#define AHCI_CMD_ATAPI (1 << 5)
diff --git a/qemu/roms/seabios/src/hw/ata.c b/qemu/roms/seabios/src/hw/ata.c
index d805706dd..fbbbbc1bb 100644
--- a/qemu/roms/seabios/src/hw/ata.c
+++ b/qemu/roms/seabios/src/hw/ata.c
@@ -552,7 +552,7 @@ ata_readwrite(struct disk_op_s *op, int iswrite)
// 16bit command demuxer for ATA harddrives.
int
-process_ata_op(struct disk_op_s *op)
+ata_process_op(struct disk_op_s *op)
{
if (!CONFIG_ATA)
return 0;
@@ -569,12 +569,8 @@ process_ata_op(struct disk_op_s *op)
return DISK_RET_SUCCESS;
case CMD_ISREADY:
return isready(adrive_gf);
- case CMD_FORMAT:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -587,11 +583,18 @@ process_ata_op(struct disk_op_s *op)
// Low-level atapi command transmit function.
int
-atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+ata_atapi_process_op(struct disk_op_s *op)
{
if (! CONFIG_ATA)
return 0;
+ if (op->command == CMD_WRITE || op->command == CMD_FORMAT)
+ return DISK_RET_EWRITEPROTECT;
+ u8 cdbcmd[CDROM_CDB_SIZE];
+ int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd));
+ if (blocksize < 0)
+ return default_process_op(op);
+
struct atadrive_s *adrive_gf = container_of(
op->drive_gf, struct atadrive_s, drive);
struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
@@ -715,7 +718,7 @@ init_atadrive(struct atadrive_s *dummy, u16 *buffer)
memset(adrive, 0, sizeof(*adrive));
adrive->chan_gf = dummy->chan_gf;
adrive->slave = dummy->slave;
- adrive->drive.cntl_id = adrive->chan_gf->chanid * 2 + dummy->slave;
+ adrive->drive.cntl_id = adrive->chan_gf->ataid * 2 + dummy->slave;
adrive->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
return adrive;
}
@@ -740,7 +743,7 @@ init_drive_atapi(struct atadrive_s *dummy, u16 *buffer)
char model[MAXMODEL+1];
char *desc = znprintf(MAXDESCSIZE
, "DVD/CD [ata%d-%d: %s ATAPI-%d %s]"
- , adrive->chan_gf->chanid, adrive->slave
+ , adrive->chan_gf->ataid, adrive->slave
, ata_extract_model(model, MAXMODEL, buffer)
, ata_extract_version(buffer)
, (iscd ? "DVD/CD" : "Device"));
@@ -792,7 +795,7 @@ init_drive_ata(struct atadrive_s *dummy, u16 *buffer)
char model[MAXMODEL+1];
char *desc = znprintf(MAXDESCSIZE
, "ata%d-%d: %s ATA-%d Hard-Disk (%u %ciBytes)"
- , adrive->chan_gf->chanid, adrive->slave
+ , adrive->chan_gf->ataid, adrive->slave
, ata_extract_model(model, MAXMODEL, buffer)
, ata_extract_version(buffer)
, (u32)adjsize, adjprefix);
@@ -866,7 +869,7 @@ ata_detect(void *data)
u8 sc = inb(iobase1+ATA_CB_SC);
u8 sn = inb(iobase1+ATA_CB_SN);
dprintf(6, "ata_detect ata%d-%d: sc=%x sn=%x dh=%x\n"
- , chan_gf->chanid, slave, sc, sn, dh);
+ , chan_gf->ataid, slave, sc, sn, dh);
if (sc != 0x55 || sn != 0xaa || dh != newdh)
continue;
@@ -913,16 +916,17 @@ ata_detect(void *data)
// Initialize an ata controller and detect its drives.
static void
-init_controller(struct pci_device *pci, int irq
+init_controller(struct pci_device *pci, int chanid, int irq
, u32 port1, u32 port2, u32 master)
{
- static int chanid = 0;
+ static int ataid = 0;
struct ata_channel_s *chan_gf = malloc_fseg(sizeof(*chan_gf));
if (!chan_gf) {
warn_noalloc();
return;
}
- chan_gf->chanid = chanid++;
+ chan_gf->ataid = ataid++;
+ chan_gf->chanid = chanid;
chan_gf->irq = irq;
chan_gf->pci_bdf = pci ? pci->bdf : -1;
chan_gf->pci_tmp = pci;
@@ -930,7 +934,7 @@ init_controller(struct pci_device *pci, int irq
chan_gf->iobase2 = port2;
chan_gf->iomaster = master;
dprintf(1, "ATA controller %d at %x/%x/%x (irq %d dev %x)\n"
- , chanid, port1, port2, master, irq, chan_gf->pci_bdf);
+ , ataid, port1, port2, master, irq, chan_gf->pci_bdf);
run_thread(ata_detect, chan_gf);
}
@@ -966,7 +970,7 @@ init_pciata(struct pci_device *pci, u8 prog_if)
port2 = PORT_ATA1_CTRL_BASE;
irq = IRQ_ATA1;
}
- init_controller(pci, irq, port1, port2, master);
+ init_controller(pci, 0, irq, port1, port2, master);
if (prog_if & 4) {
port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2)
@@ -979,7 +983,7 @@ init_pciata(struct pci_device *pci, u8 prog_if)
port2 = PORT_ATA2_CTRL_BASE;
irq = IRQ_ATA2;
}
- init_controller(pci, irq, port1, port2, master ? master + 8 : 0);
+ init_controller(pci, 1, irq, port1, port2, master ? master + 8 : 0);
}
static void
@@ -1011,9 +1015,9 @@ ata_scan(void)
if (CONFIG_QEMU && hlist_empty(&PCIDevices)) {
// No PCI devices found - probably a QEMU "-M isapc" machine.
// Try using ISA ports for ATA controllers.
- init_controller(NULL, IRQ_ATA1
+ init_controller(NULL, 0, IRQ_ATA1
, PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0);
- init_controller(NULL, IRQ_ATA2
+ init_controller(NULL, 1, IRQ_ATA2
, PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0);
return;
}
diff --git a/qemu/roms/seabios/src/hw/ata.h b/qemu/roms/seabios/src/hw/ata.h
index c73892bbe..cd14e59e9 100644
--- a/qemu/roms/seabios/src/hw/ata.h
+++ b/qemu/roms/seabios/src/hw/ata.h
@@ -11,6 +11,7 @@ struct ata_channel_s {
u16 iomaster;
u8 irq;
u8 chanid;
+ u8 ataid;
int pci_bdf;
struct pci_device *pci_tmp;
};
@@ -24,10 +25,9 @@ struct atadrive_s {
// ata.c
char *ata_extract_model(char *model, u32 size, u16 *buffer);
int ata_extract_version(u16 *buffer);
-int cdrom_read(struct disk_op_s *op);
-int atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int ata_process_op(struct disk_op_s *op);
+int ata_atapi_process_op(struct disk_op_s *op);
void ata_setup(void);
-int process_ata_op(struct disk_op_s *op);
#define PORT_ATA2_CMD_BASE 0x0170
#define PORT_ATA1_CMD_BASE 0x01f0
diff --git a/qemu/roms/seabios/src/hw/blockcmd.c b/qemu/roms/seabios/src/hw/blockcmd.c
index 78c0e65f4..0725b46db 100644
--- a/qemu/roms/seabios/src/hw/blockcmd.c
+++ b/qemu/roms/seabios/src/hw/blockcmd.c
@@ -5,67 +5,14 @@
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "ahci.h" // atapi_cmd_data
-#include "ata.h" // atapi_cmd_data
#include "biosvar.h" // GET_GLOBALFLAT
#include "block.h" // struct disk_op_s
#include "blockcmd.h" // struct cdb_request_sense
#include "byteorder.h" // be32_to_cpu
-#include "esp-scsi.h" // esp_scsi_cmd_data
-#include "lsi-scsi.h" // lsi_scsi_cmd_data
-#include "megasas.h" // megasas_cmd_data
-#include "pvscsi.h" // pvscsi_cmd_data
#include "output.h" // dprintf
#include "std/disk.h" // DISK_RET_EPARAM
#include "string.h" // memset
-#include "usb-msc.h" // usb_cmd_data
-#include "usb-uas.h" // usb_cmd_data
#include "util.h" // timer_calc
-#include "virtio-scsi.h" // virtio_scsi_cmd_data
-
-// Route command to low-level handler.
-static int
-cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- u8 type = GET_GLOBALFLAT(op->drive_gf->type);
- switch (type) {
- case DTYPE_ATA_ATAPI:
- return atapi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_USB:
- return usb_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_UAS:
- return uas_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_VIRTIO_SCSI:
- return virtio_scsi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_LSI_SCSI:
- return lsi_scsi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_ESP_SCSI:
- return esp_scsi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_MEGASAS:
- return megasas_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_USB_32:
- if (!MODESEGMENT)
- return usb_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_UAS_32:
- if (!MODESEGMENT)
- return uas_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_PVSCSI:
- if (!MODESEGMENT)
- return pvscsi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_AHCI_ATAPI:
- if (!MODESEGMENT)
- return ahci_cmd_data(op, cdbcmd, blocksize);
- default:
- return DISK_RET_EPARAM;
- }
-}
-
-// Determine if the command is a request to pull data from the device
-int
-cdb_is_read(u8 *cdbcmd, u16 blocksize)
-{
- return blocksize && cdbcmd[0] != CDB_CMD_WRITE_10;
-}
/****************************************************************
@@ -79,9 +26,12 @@ cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
memset(&cmd, 0, sizeof(cmd));
cmd.command = CDB_CMD_INQUIRY;
cmd.length = sizeof(*data);
+ op->command = CMD_SCSI;
op->count = 1;
op->buf_fl = data;
- return cdb_cmd_data(op, &cmd, sizeof(*data));
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
}
// Request SENSE
@@ -92,9 +42,12 @@ cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
memset(&cmd, 0, sizeof(cmd));
cmd.command = CDB_CMD_REQUEST_SENSE;
cmd.length = sizeof(*data);
+ op->command = CMD_SCSI;
op->count = 1;
op->buf_fl = data;
- return cdb_cmd_data(op, &cmd, sizeof(*data));
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
}
// Test unit ready
@@ -104,9 +57,12 @@ cdb_test_unit_ready(struct disk_op_s *op)
struct cdb_request_sense cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.command = CDB_CMD_TEST_UNIT_READY;
+ op->command = CMD_SCSI;
op->count = 0;
op->buf_fl = NULL;
- return cdb_cmd_data(op, &cmd, 0);
+ op->cdbcmd = &cmd;
+ op->blocksize = 0;
+ return process_op(op);
}
// Request capacity
@@ -116,9 +72,12 @@ cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data)
struct cdb_read_capacity cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.command = CDB_CMD_READ_CAPACITY;
+ op->command = CMD_SCSI;
op->count = 1;
op->buf_fl = data;
- return cdb_cmd_data(op, &cmd, sizeof(*data));
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
}
// Mode sense, geometry page.
@@ -131,33 +90,12 @@ cdb_mode_sense_geom(struct disk_op_s *op, struct cdbres_mode_sense_geom *data)
cmd.flags = 8; /* DBD */
cmd.page = MODE_PAGE_HD_GEOMETRY;
cmd.count = cpu_to_be16(sizeof(*data));
+ op->command = CMD_SCSI;
op->count = 1;
op->buf_fl = data;
- return cdb_cmd_data(op, &cmd, sizeof(*data));
-}
-
-// Read sectors.
-static int
-cdb_read(struct disk_op_s *op)
-{
- struct cdb_rwdata_10 cmd;
- memset(&cmd, 0, sizeof(cmd));
- cmd.command = CDB_CMD_READ_10;
- cmd.lba = cpu_to_be32(op->lba);
- cmd.count = cpu_to_be16(op->count);
- return cdb_cmd_data(op, &cmd, GET_GLOBALFLAT(op->drive_gf->blksize));
-}
-
-// Write sectors.
-static int
-cdb_write(struct disk_op_s *op)
-{
- struct cdb_rwdata_10 cmd;
- memset(&cmd, 0, sizeof(cmd));
- cmd.command = CDB_CMD_WRITE_10;
- cmd.lba = cpu_to_be32(op->lba);
- cmd.count = cpu_to_be16(op->count);
- return cdb_cmd_data(op, &cmd, GET_GLOBALFLAT(op->drive_gf->blksize));
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
}
@@ -165,25 +103,36 @@ cdb_write(struct disk_op_s *op)
* Main SCSI commands
****************************************************************/
-int VISIBLE32FLAT
-scsi_process_op(struct disk_op_s *op)
+// Create a scsi command request from a disk_op_s request
+int
+scsi_fill_cmd(struct disk_op_s *op, void *cdbcmd, int maxcdb)
{
switch (op->command) {
case CMD_READ:
- return cdb_read(op);
- case CMD_WRITE:
- return cdb_write(op);
- case CMD_FORMAT:
- case CMD_RESET:
- case CMD_ISREADY:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
+ case CMD_WRITE: ;
+ struct cdb_rwdata_10 *cmd = cdbcmd;
+ memset(cmd, 0, maxcdb);
+ cmd->command = (op->command == CMD_READ ? CDB_CMD_READ_10
+ : CDB_CMD_WRITE_10);
+ cmd->lba = cpu_to_be32(op->lba);
+ cmd->count = cpu_to_be16(op->count);
+ return GET_GLOBALFLAT(op->drive_gf->blksize);
+ case CMD_SCSI:
+ memcpy(cdbcmd, op->cdbcmd, maxcdb);
+ return op->blocksize;
default:
- return DISK_RET_EPARAM;
+ return -1;
}
}
+// Determine if the command is a request to pull data from the device
+int
+scsi_is_read(struct disk_op_s *op)
+{
+ return op->command == CMD_READ || (op->command == CMD_SCSI && op->blocksize);
+}
+
+// Check if a SCSI device is ready to receive commands
int
scsi_is_ready(struct disk_op_s *op)
{
@@ -219,7 +168,7 @@ scsi_is_ready(struct disk_op_s *op)
if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
/* IN PROGRESS OF BECOMING READY */
- printf("Waiting for device to detect medium... ");
+ dprintf(1, "Waiting for device to detect medium... ");
/* Allow 30 seconds more */
end = timer_calc(30000);
in_progress = 1;
diff --git a/qemu/roms/seabios/src/hw/blockcmd.h b/qemu/roms/seabios/src/hw/blockcmd.h
index df12a6d42..b543f85eb 100644
--- a/qemu/roms/seabios/src/hw/blockcmd.h
+++ b/qemu/roms/seabios/src/hw/blockcmd.h
@@ -100,9 +100,9 @@ struct cdbres_mode_sense_geom {
} PACKED;
// blockcmd.c
-int cdb_is_read(u8 *cdbcmd, u16 blocksize);
struct disk_op_s;
-int scsi_process_op(struct disk_op_s *op);
+int scsi_fill_cmd(struct disk_op_s *op, void *cdbcmd, int maxcdb);
+int scsi_is_read(struct disk_op_s *op);
int scsi_is_ready(struct disk_op_s *op);
struct drive_s;
int scsi_drive_setup(struct drive_s *drive, const char *s, int prio);
diff --git a/qemu/roms/seabios/src/hw/esp-scsi.c b/qemu/roms/seabios/src/hw/esp-scsi.c
index 33cc44986..d4e47e3c5 100644
--- a/qemu/roms/seabios/src/hw/esp-scsi.c
+++ b/qemu/roms/seabios/src/hw/esp-scsi.c
@@ -76,10 +76,19 @@ esp_scsi_dma(u32 iobase, u32 buf, u32 len, int read)
outb(read ? 0x83 : 0x03, iobase + ESP_DMA_CMD);
}
-static int
-esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op,
- u8 *cdbcmd, u16 target, u16 lun, u16 blocksize)
+int
+esp_scsi_process_op(struct disk_op_s *op)
{
+ if (!CONFIG_ESP_SCSI)
+ return DISK_RET_EBADTRACK;
+ struct esp_lun_s *llun_gf =
+ container_of(op->drive_gf, struct esp_lun_s, drive);
+ u16 target = GET_GLOBALFLAT(llun_gf->target);
+ u16 lun = GET_GLOBALFLAT(llun_gf->lun);
+ u8 cdbcmd[16];
+ int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd));
+ if (blocksize < 0)
+ return default_process_op(op);
u32 iobase = GET_GLOBALFLAT(llun_gf->iobase);
int i, state;
u8 status;
@@ -113,8 +122,7 @@ esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op,
if (op->count && blocksize) {
/* Data phase. */
u32 count = (u32)op->count * blocksize;
- esp_scsi_dma(iobase, (u32)op->buf_fl, count,
- cdb_is_read(cdbcmd, blocksize));
+ esp_scsi_dma(iobase, (u32)op->buf_fl, count, scsi_is_read(op));
outb(ESP_CMD_TI | ESP_CMD_DMA, iobase + ESP_CMD);
continue;
}
@@ -144,21 +152,6 @@ esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op,
return DISK_RET_EBADTRACK;
}
-int
-esp_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- if (!CONFIG_ESP_SCSI)
- return DISK_RET_EBADTRACK;
-
- struct esp_lun_s *llun_gf =
- container_of(op->drive_gf, struct esp_lun_s, drive);
-
- return esp_scsi_cmd(llun_gf, op, cdbcmd,
- GET_GLOBALFLAT(llun_gf->target),
- GET_GLOBALFLAT(llun_gf->lun),
- blocksize);
-}
-
static int
esp_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
{
diff --git a/qemu/roms/seabios/src/hw/esp-scsi.h b/qemu/roms/seabios/src/hw/esp-scsi.h
index dc555f395..0616d14b1 100644
--- a/qemu/roms/seabios/src/hw/esp-scsi.h
+++ b/qemu/roms/seabios/src/hw/esp-scsi.h
@@ -2,7 +2,7 @@
#define __ESP_SCSI_H
struct disk_op_s;
-int esp_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int esp_scsi_process_op(struct disk_op_s *op);
void esp_scsi_setup(void);
#endif /* __ESP_SCSI_H */
diff --git a/qemu/roms/seabios/src/hw/floppy.c b/qemu/roms/seabios/src/hw/floppy.c
index d60362a34..a14f7e093 100644
--- a/qemu/roms/seabios/src/hw/floppy.c
+++ b/qemu/roms/seabios/src/hw/floppy.c
@@ -613,7 +613,7 @@ floppy_format(struct disk_op_s *op)
}
int
-process_floppy_op(struct disk_op_s *op)
+floppy_process_op(struct disk_op_s *op)
{
if (!CONFIG_FLOPPY)
return 0;
diff --git a/qemu/roms/seabios/src/hw/lsi-scsi.c b/qemu/roms/seabios/src/hw/lsi-scsi.c
index b1d6bbf4b..ad3352886 100644
--- a/qemu/roms/seabios/src/hw/lsi-scsi.c
+++ b/qemu/roms/seabios/src/hw/lsi-scsi.c
@@ -50,12 +50,21 @@ struct lsi_lun_s {
u8 lun;
};
-static int
-lsi_scsi_cmd(struct lsi_lun_s *llun_gf, struct disk_op_s *op,
- void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+int
+lsi_scsi_process_op(struct disk_op_s *op)
{
+ if (!CONFIG_LSI_SCSI)
+ return DISK_RET_EBADTRACK;
+ struct lsi_lun_s *llun_gf =
+ container_of(op->drive_gf, struct lsi_lun_s, drive);
+ u16 target = GET_GLOBALFLAT(llun_gf->target);
+ u16 lun = GET_GLOBALFLAT(llun_gf->lun);
+ u8 cdbcmd[16];
+ int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd));
+ if (blocksize < 0)
+ return default_process_op(op);
u32 iobase = GET_GLOBALFLAT(llun_gf->iobase);
- u32 dma = ((cdb_is_read(cdbcmd, blocksize) ? 0x01000000 : 0x00000000) |
+ u32 dma = ((scsi_is_read(op) ? 0x01000000 : 0x00000000) |
(op->count * blocksize));
u8 msgout[] = {
0x80 | lun, // select lun
@@ -122,21 +131,6 @@ fail:
return DISK_RET_EBADTRACK;
}
-int
-lsi_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- if (!CONFIG_LSI_SCSI)
- return DISK_RET_EBADTRACK;
-
- struct lsi_lun_s *llun_gf =
- container_of(op->drive_gf, struct lsi_lun_s, drive);
-
- return lsi_scsi_cmd(llun_gf, op, cdbcmd,
- GET_GLOBALFLAT(llun_gf->target),
- GET_GLOBALFLAT(llun_gf->lun),
- blocksize);
-}
-
static int
lsi_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
{
diff --git a/qemu/roms/seabios/src/hw/lsi-scsi.h b/qemu/roms/seabios/src/hw/lsi-scsi.h
index 9c5a9b212..6baf4a162 100644
--- a/qemu/roms/seabios/src/hw/lsi-scsi.h
+++ b/qemu/roms/seabios/src/hw/lsi-scsi.h
@@ -2,7 +2,7 @@
#define __LSI_SCSI_H
struct disk_op_s;
-int lsi_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int lsi_scsi_process_op(struct disk_op_s *op);
void lsi_scsi_setup(void);
#endif /* __LSI_SCSI_H */
diff --git a/qemu/roms/seabios/src/hw/megasas.c b/qemu/roms/seabios/src/hw/megasas.c
index b2a65e48b..cb1a2a653 100644
--- a/qemu/roms/seabios/src/hw/megasas.c
+++ b/qemu/roms/seabios/src/hw/megasas.c
@@ -157,18 +157,20 @@ static int megasas_fire_cmd(u16 pci_id, u32 ioaddr,
}
int
-megasas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+megasas_process_op(struct disk_op_s *op)
{
+ if (!CONFIG_MEGASAS)
+ return DISK_RET_EBADTRACK;
+ u8 cdb[16];
+ int blocksize = scsi_fill_cmd(op, cdb, sizeof(cdb));
+ if (blocksize < 0)
+ return default_process_op(op);
struct megasas_lun_s *mlun_gf =
container_of(op->drive_gf, struct megasas_lun_s, drive);
- u8 *cdb = cdbcmd;
struct megasas_cmd_frame *frame = GET_GLOBALFLAT(mlun_gf->frame);
u16 pci_id = GET_GLOBALFLAT(mlun_gf->pci_id);
int i;
- if (!CONFIG_MEGASAS)
- return DISK_RET_EBADTRACK;
-
memset_fl(frame, 0, sizeof(*frame));
SET_LOWFLAT(frame->cmd, MFI_CMD_LD_SCSI_IO);
SET_LOWFLAT(frame->cmd_status, 0xFF);
@@ -241,7 +243,10 @@ static void megasas_scan_target(struct pci_device *pci, u32 iobase)
{
struct mfi_ld_list_s ld_list;
struct megasas_cmd_frame *frame = memalign_tmp(256, sizeof(*frame));
- int i;
+ if (!frame) {
+ warn_noalloc();
+ return;
+ }
memset(&ld_list, 0, sizeof(ld_list));
memset_fl(frame, 0, sizeof(*frame));
@@ -258,6 +263,7 @@ static void megasas_scan_target(struct pci_device *pci, u32 iobase)
if (megasas_fire_cmd(pci->device, iobase, frame) == 0) {
dprintf(2, "%d LD found\n", ld_list.count);
+ int i;
for (i = 0; i < ld_list.count; i++) {
dprintf(2, "LD %d:%d state 0x%x\n",
ld_list.lds[i].target, ld_list.lds[i].lun,
@@ -295,9 +301,9 @@ static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr)
pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
- outl(ioaddr + MFI_DB, mfi_flags);
+ outl(mfi_flags, ioaddr + MFI_DB);
} else {
- outl(ioaddr + MFI_IDB, mfi_flags);
+ outl(mfi_flags, ioaddr + MFI_IDB);
}
break;
case MFI_STATE_OPERATIONAL:
@@ -306,7 +312,7 @@ static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr)
pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
- outl(ioaddr + MFI_DB, mfi_flags);
+ outl(mfi_flags, ioaddr + MFI_DB);
if (pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
int j = 0;
@@ -321,7 +327,7 @@ static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr)
}
}
} else {
- outw(ioaddr + MFI_IDB, mfi_flags);
+ outl(mfi_flags, ioaddr + MFI_IDB);
}
break;
case MFI_STATE_READY:
diff --git a/qemu/roms/seabios/src/hw/megasas.h b/qemu/roms/seabios/src/hw/megasas.h
index 124042e1c..ed0e4f096 100644
--- a/qemu/roms/seabios/src/hw/megasas.h
+++ b/qemu/roms/seabios/src/hw/megasas.h
@@ -2,7 +2,7 @@
#define __MEGASAS_H
struct disk_op_s;
-int megasas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int megasas_process_op(struct disk_op_s *op);
void megasas_setup(void);
#endif /* __MEGASAS_H */
diff --git a/qemu/roms/seabios/src/hw/pci.c b/qemu/roms/seabios/src/hw/pci.c
index 0379b558e..a241d0675 100644
--- a/qemu/roms/seabios/src/hw/pci.c
+++ b/qemu/roms/seabios/src/hw/pci.c
@@ -221,16 +221,21 @@ pci_find_init_device(const struct pci_device_id *ids, void *arg)
return NULL;
}
-u8 pci_find_capability(struct pci_device *pci, u8 cap_id)
+u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap)
{
int i;
- u8 cap;
u16 status = pci_config_readw(pci->bdf, PCI_STATUS);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
- cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST);
+ if (cap == 0) {
+ /* find first */
+ cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST);
+ } else {
+ /* find next */
+ cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT);
+ }
for (i = 0; cap && i <= 0xff; i++) {
if (pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_ID) == cap_id)
return cap;
diff --git a/qemu/roms/seabios/src/hw/pci.h b/qemu/roms/seabios/src/hw/pci.h
index 0aaa84c1a..fc5e7b9bf 100644
--- a/qemu/roms/seabios/src/hw/pci.h
+++ b/qemu/roms/seabios/src/hw/pci.h
@@ -123,7 +123,7 @@ int pci_init_device(const struct pci_device_id *ids
, struct pci_device *pci, void *arg);
struct pci_device *pci_find_init_device(const struct pci_device_id *ids
, void *arg);
-u8 pci_find_capability(struct pci_device *pci, u8 cap_id);
+u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap);
int pci_bridge_has_region(struct pci_device *pci,
enum pci_region_type region_type);
void pci_reboot(void);
diff --git a/qemu/roms/seabios/src/hw/pci_ids.h b/qemu/roms/seabios/src/hw/pci_ids.h
index 1cd4f7269..cdf9b3cbc 100644
--- a/qemu/roms/seabios/src/hw/pci_ids.h
+++ b/qemu/roms/seabios/src/hw/pci_ids.h
@@ -2616,8 +2616,12 @@
#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
-#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001
-#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004
+/* virtio 0.9.5 ids (legacy/transitional devices) */
+#define PCI_DEVICE_ID_VIRTIO_BLK_09 0x1001
+#define PCI_DEVICE_ID_VIRTIO_SCSI_09 0x1004
+/* virtio 1.0 ids (modern devices) */
+#define PCI_DEVICE_ID_VIRTIO_BLK_10 0x1042
+#define PCI_DEVICE_ID_VIRTIO_SCSI_10 0x1048
#define PCI_VENDOR_ID_VMWARE 0x15ad
#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0
diff --git a/qemu/roms/seabios/src/hw/pic.c b/qemu/roms/seabios/src/hw/pic.c
index 6ff696765..d8b9764c7 100644
--- a/qemu/roms/seabios/src/hw/pic.c
+++ b/qemu/roms/seabios/src/hw/pic.c
@@ -13,12 +13,16 @@
u16
pic_irqmask_read(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return 0;
return inb(PORT_PIC1_DATA) | (inb(PORT_PIC2_DATA) << 8);
}
void
pic_irqmask_write(u16 mask)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
outb(mask, PORT_PIC1_DATA);
outb(mask >> 8, PORT_PIC2_DATA);
}
@@ -26,6 +30,8 @@ pic_irqmask_write(u16 mask)
void
pic_irqmask_mask(u16 off, u16 on)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
u8 pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8;
outb((inb(PORT_PIC1_DATA) & ~pic1off) | pic1on, PORT_PIC1_DATA);
outb((inb(PORT_PIC2_DATA) & ~pic2off) | pic2on, PORT_PIC2_DATA);
@@ -34,6 +40,8 @@ pic_irqmask_mask(u16 off, u16 on)
void
pic_reset(u8 irq0, u8 irq8)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
// Send ICW1 (select OCW1 + will send ICW4)
outb(0x11, PORT_PIC1_CMD);
outb(0x11, PORT_PIC2_CMD);
@@ -60,6 +68,8 @@ pic_setup(void)
void
enable_hwirq(int hwirq, struct segoff_s func)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
pic_irqmask_mask(1 << hwirq, 0);
int vector;
if (hwirq < 8)
@@ -72,6 +82,8 @@ enable_hwirq(int hwirq, struct segoff_s func)
static u8
pic_isr1_read(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return 0;
// 0x0b == select OCW1 + read ISR
outb(0x0b, PORT_PIC1_CMD);
return inb(PORT_PIC1_CMD);
@@ -80,6 +92,8 @@ pic_isr1_read(void)
static u8
pic_isr2_read(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return 0;
// 0x0b == select OCW1 + read ISR
outb(0x0b, PORT_PIC2_CMD);
return inb(PORT_PIC2_CMD);
diff --git a/qemu/roms/seabios/src/hw/pic.h b/qemu/roms/seabios/src/hw/pic.h
index 6947b6e81..f2d9f6130 100644
--- a/qemu/roms/seabios/src/hw/pic.h
+++ b/qemu/roms/seabios/src/hw/pic.h
@@ -34,6 +34,8 @@
static inline void
pic_eoi1(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
// Send eoi (select OCW2 + eoi)
outb(0x20, PORT_PIC1_CMD);
}
@@ -41,6 +43,8 @@ pic_eoi1(void)
static inline void
pic_eoi2(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
// Send eoi (select OCW2 + eoi)
outb(0x20, PORT_PIC2_CMD);
pic_eoi1();
diff --git a/qemu/roms/seabios/src/hw/ps2port.c b/qemu/roms/seabios/src/hw/ps2port.c
index 04995c881..d5504f71e 100644
--- a/qemu/roms/seabios/src/hw/ps2port.c
+++ b/qemu/roms/seabios/src/hw/ps2port.c
@@ -210,7 +210,7 @@ ps2_sendbyte(int aux, u8 command, int timeout)
return 0;
}
-u8 Ps2ctr VARLOW;
+u8 Ps2ctr VARLOW = I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
static int
__ps2_command(int aux, int command, u8 *param)
@@ -232,6 +232,7 @@ __ps2_command(int aux, int command, u8 *param)
yield();
// Enable port command is being sent to.
+ SET_LOW(Ps2ctr, newctr);
if (aux)
newctr &= ~I8042_CTR_AUXDIS;
else
@@ -240,8 +241,8 @@ __ps2_command(int aux, int command, u8 *param)
if (ret)
goto fail;
- if (command == ATKBD_CMD_RESET_BAT) {
- // Reset is special wrt timeouts and bytes received.
+ if ((u8)command == (u8)ATKBD_CMD_RESET_BAT) {
+ // Reset is special wrt timeouts.
// Send command.
ret = ps2_sendbyte(aux, command, 1000);
@@ -253,11 +254,12 @@ __ps2_command(int aux, int command, u8 *param)
if (ret < 0)
goto fail;
param[0] = ret;
- ret = ps2_recvbyte(aux, 0, 100);
- if (ret < 0)
- // Some devices only respond with one byte on reset.
- ret = 0;
- param[1] = ret;
+ if (receive > 1) {
+ ret = ps2_recvbyte(aux, 0, 500);
+ if (ret < 0)
+ goto fail;
+ param[1] = ret;
+ }
} else if (command == ATKBD_CMD_GETID) {
// Getid is special wrt bytes received.
@@ -308,6 +310,7 @@ __ps2_command(int aux, int command, u8 *param)
fail:
// Restore interrupts and keyboard/mouse.
+ SET_LOW(Ps2ctr, ps2ctr);
ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
if (ret2)
return ret2;
@@ -343,7 +346,8 @@ ps2_mouse_command(int command, u8 *param)
if (command == PSMOUSE_CMD_ENABLE || command == PSMOUSE_CMD_DISABLE) {
u8 ps2ctr = GET_LOW(Ps2ctr);
if (command == PSMOUSE_CMD_ENABLE)
- ps2ctr = (ps2ctr | I8042_CTR_AUXINT) & ~I8042_CTR_AUXDIS;
+ ps2ctr = ((ps2ctr | (CONFIG_HARDWARE_IRQ ? I8042_CTR_AUXINT : 0))
+ & ~I8042_CTR_AUXDIS);
else
ps2ctr = (ps2ctr | I8042_CTR_AUXDIS) & ~I8042_CTR_AUXINT;
SET_LOW(Ps2ctr, ps2ctr);
@@ -414,6 +418,31 @@ done:
pic_eoi1();
}
+// Check for ps2 activity on machines without hardware irqs
+void
+ps2_check_event(void)
+{
+ if (! CONFIG_PS2PORT || CONFIG_HARDWARE_IRQ)
+ return;
+ u8 ps2ctr = GET_LOW(Ps2ctr);
+ if ((ps2ctr & (I8042_CTR_KBDDIS|I8042_CTR_AUXDIS))
+ == (I8042_CTR_KBDDIS|I8042_CTR_AUXDIS))
+ return;
+ for (;;) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (!(status & I8042_STR_OBF))
+ break;
+ u8 data = inb(PORT_PS2_DATA);
+ if (status & I8042_STR_AUXDATA) {
+ if (!(ps2ctr & I8042_CTR_AUXDIS))
+ process_mouse(data);
+ } else {
+ if (!(ps2ctr & I8042_CTR_KBDDIS))
+ process_key(data);
+ }
+ }
+}
+
/****************************************************************
* Setup
@@ -446,9 +475,6 @@ ps2_keyboard_setup(void *data)
return;
}
- // Disable keyboard and mouse events.
- SET_LOW(Ps2ctr, I8042_CTR_KBDDIS | I8042_CTR_AUXDIS);
-
/* ------------------- keyboard side ------------------------*/
/* reset keyboard and self test (keyboard side) */
@@ -482,7 +508,8 @@ ps2_keyboard_setup(void *data)
return;
// Keyboard Mode: disable mouse, scan code convert, enable kbd IRQ
- SET_LOW(Ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT);
+ Ps2ctr = (I8042_CTR_AUXDIS | I8042_CTR_XLATE
+ | (CONFIG_HARDWARE_IRQ ? I8042_CTR_KBDINT : 0));
/* Enable keyboard */
ret = ps2_kbd_command(ATKBD_CMD_ENABLE, NULL);
diff --git a/qemu/roms/seabios/src/hw/ps2port.h b/qemu/roms/seabios/src/hw/ps2port.h
index e5d9014b7..1338406ac 100644
--- a/qemu/roms/seabios/src/hw/ps2port.h
+++ b/qemu/roms/seabios/src/hw/ps2port.h
@@ -26,7 +26,7 @@
#define ATKBD_CMD_GETID 0x02f2
#define ATKBD_CMD_ENABLE 0x00f4
#define ATKBD_CMD_RESET_DIS 0x00f5
-#define ATKBD_CMD_RESET_BAT 0x02ff
+#define ATKBD_CMD_RESET_BAT 0x01ff
// Mouse commands
#define PSMOUSE_CMD_SETSCALE11 0x00e6
@@ -61,6 +61,7 @@
void i8042_reboot(void);
int ps2_kbd_command(int command, u8 *param);
int ps2_mouse_command(int command, u8 *param);
+void ps2_check_event(void);
void ps2port_setup(void);
#endif // ps2port.h
diff --git a/qemu/roms/seabios/src/hw/pvscsi.c b/qemu/roms/seabios/src/hw/pvscsi.c
index 601a551db..fa20efef7 100644
--- a/qemu/roms/seabios/src/hw/pvscsi.c
+++ b/qemu/roms/seabios/src/hw/pvscsi.c
@@ -11,6 +11,7 @@
#include "blockcmd.h" // scsi_drive_setup
#include "config.h" // CONFIG_*
#include "malloc.h" // free
+#include "memmap.h" // PAGE_SHIFT, virt_to_phys
#include "output.h" // dprintf
#include "pci.h" // foreachpci
#include "pci_ids.h" // PCI_DEVICE_ID_VMWARE_PVSCSI
@@ -19,7 +20,6 @@
#include "std/disk.h" // DISK_RET_SUCCESS
#include "string.h" // memset
#include "util.h" // usleep
-#include "virtio-ring.h" // PAGE_SHIFT, virt_to_phys
#include "x86.h" // writel
#define MASK(n) ((1 << (n)) - 1)
@@ -197,29 +197,6 @@ pvscsi_init_rings(void *iobase, struct pvscsi_ring_dsc_s **ring_dsc)
*ring_dsc = dsc;
}
-static void pvscsi_fill_req(struct PVSCSIRingsState *s,
- struct PVSCSIRingReqDesc *req,
- u16 target, u16 lun, void *cdbcmd, u16 blocksize,
- struct disk_op_s *op)
-{
- req->bus = 0;
- req->target = target;
- memset(req->lun, 0, sizeof(req->lun));
- req->lun[1] = lun;
- req->senseLen = 0;
- req->senseAddr = 0;
- req->cdbLen = 16;
- req->vcpuHint = 0;
- memcpy(req->cdb, cdbcmd, 16);
- req->tag = SIMPLE_QUEUE_TAG;
- req->flags = cdb_is_read(cdbcmd, blocksize) ?
- PVSCSI_FLAG_CMD_DIR_TOHOST : PVSCSI_FLAG_CMD_DIR_TODEVICE;
-
- req->dataLen = op->count * blocksize;
- req->dataAddr = (u32)op->buf_fl;
- s->reqProdIdx = s->reqProdIdx + 1;
-}
-
static u32
pvscsi_get_rsp(struct PVSCSIRingsState *s,
struct PVSCSIRingCmpDesc *rsp)
@@ -229,10 +206,13 @@ pvscsi_get_rsp(struct PVSCSIRingsState *s,
return status;
}
-static int
-pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op,
- void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+int
+pvscsi_process_op(struct disk_op_s *op)
{
+ if (!CONFIG_PVSCSI)
+ return DISK_RET_EBADTRACK;
+ struct pvscsi_lun_s *plun =
+ container_of(op->drive_gf, struct pvscsi_lun_s, drive);
struct pvscsi_ring_dsc_s *ring_dsc = plun->ring_dsc;
struct PVSCSIRingsState *s = ring_dsc->ring_state;
u32 req_entries = s->reqNumEntriesLog2;
@@ -248,7 +228,23 @@ pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op,
}
req = ring_dsc->ring_reqs + (s->reqProdIdx & MASK(req_entries));
- pvscsi_fill_req(s, req, target, lun, cdbcmd, blocksize, op);
+ int blocksize = scsi_fill_cmd(op, req->cdb, 16);
+ if (blocksize < 0)
+ return default_process_op(op);
+ req->bus = 0;
+ req->target = plun->target;
+ memset(req->lun, 0, sizeof(req->lun));
+ req->lun[1] = plun->lun;
+ req->senseLen = 0;
+ req->senseAddr = 0;
+ req->cdbLen = 16;
+ req->vcpuHint = 0;
+ req->tag = SIMPLE_QUEUE_TAG;
+ req->flags = scsi_is_read(op) ?
+ PVSCSI_FLAG_CMD_DIR_TOHOST : PVSCSI_FLAG_CMD_DIR_TODEVICE;
+ req->dataLen = op->count * blocksize;
+ req->dataAddr = (u32)op->buf_fl;
+ s->reqProdIdx = s->reqProdIdx + 1;
pvscsi_kick_rw_io(plun->iobase);
pvscsi_wait_intr_cmpl(plun->iobase);
@@ -259,18 +255,6 @@ pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op,
return status == 0 ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
}
-int
-pvscsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- if (!CONFIG_PVSCSI)
- return DISK_RET_EBADTRACK;
-
- struct pvscsi_lun_s *plun =
- container_of(op->drive_gf, struct pvscsi_lun_s, drive);
-
- return pvscsi_cmd(plun, op, cdbcmd, plun->target, plun->lun, blocksize);
-}
-
static int
pvscsi_add_lun(struct pci_device *pci, void *iobase,
struct pvscsi_ring_dsc_s *ring_dsc, u8 target, u8 lun)
diff --git a/qemu/roms/seabios/src/hw/pvscsi.h b/qemu/roms/seabios/src/hw/pvscsi.h
index fde9f0b98..5af7dcb0e 100644
--- a/qemu/roms/seabios/src/hw/pvscsi.h
+++ b/qemu/roms/seabios/src/hw/pvscsi.h
@@ -2,7 +2,7 @@
#define _PVSCSI_H_
struct disk_op_s;
-int pvscsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int pvscsi_process_op(struct disk_op_s *op);
void pvscsi_setup(void);
#endif /* _PVSCSI_H_ */
diff --git a/qemu/roms/seabios/src/hw/ramdisk.c b/qemu/roms/seabios/src/hw/ramdisk.c
index 1177bc00a..adec1d1b3 100644
--- a/qemu/roms/seabios/src/hw/ramdisk.c
+++ b/qemu/roms/seabios/src/hw/ramdisk.c
@@ -7,8 +7,9 @@
#include "biosvar.h" // GET_GLOBALFLAT
#include "block.h" // struct drive_s
#include "bregs.h" // struct bregs
-#include "malloc.h" // malloc_fseg
-#include "memmap.h" // add_e820
+#include "e820map.h" // e820_add
+#include "malloc.h" // memalign_tmphigh
+#include "memmap.h" // PAGE_SIZE
#include "output.h" // dprintf
#include "romfile.h" // romfile_findprefix
#include "stacks.h" // call16_int
@@ -41,7 +42,7 @@ ramdisk_setup(void)
warn_noalloc();
return;
}
- add_e820((u32)pos, size, E820_RESERVED);
+ e820_add((u32)pos, size, E820_RESERVED);
// Copy image into ram.
int ret = file->copy(file, pos, size);
@@ -53,7 +54,7 @@ ramdisk_setup(void)
if (!drive)
return;
drive->type = DTYPE_RAMDISK;
- dprintf(1, "Mapping CBFS floppy %s to addr %p\n", filename, pos);
+ dprintf(1, "Mapping floppy %s to addr %p\n", filename, pos);
char *desc = znprintf(MAXDESCSIZE, "Ramdisk [%s]", &filename[10]);
boot_add_floppy(drive, desc, bootprio_find_named_rom(filename, 0));
}
@@ -91,7 +92,7 @@ ramdisk_copy(struct disk_op_s *op, int iswrite)
}
int
-process_ramdisk_op(struct disk_op_s *op)
+ramdisk_process_op(struct disk_op_s *op)
{
if (!CONFIG_FLASH_FLOPPY)
return 0;
@@ -101,11 +102,7 @@ process_ramdisk_op(struct disk_op_s *op)
return ramdisk_copy(op, 0);
case CMD_WRITE:
return ramdisk_copy(op, 1);
- case CMD_VERIFY:
- case CMD_FORMAT:
- case CMD_RESET:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
diff --git a/qemu/roms/seabios/src/hw/rtc.c b/qemu/roms/seabios/src/hw/rtc.c
index 628d5429f..9649a5a79 100644
--- a/qemu/roms/seabios/src/hw/rtc.c
+++ b/qemu/roms/seabios/src/hw/rtc.c
@@ -30,6 +30,7 @@ rtc_write(u8 index, u8 val)
void
rtc_mask(u8 index, u8 off, u8 on)
{
+ index |= NMI_DISABLE_BIT;
outb(index, PORT_CMOS_INDEX);
u8 val = inb(PORT_CMOS_DATA);
outb((val & ~off) | on, PORT_CMOS_DATA);
@@ -62,6 +63,8 @@ rtc_updating(void)
void
rtc_setup(void)
{
+ if (!CONFIG_RTC_TIMER)
+ return;
rtc_write(CMOS_STATUS_A, 0x26); // 32,768Khz src, 976.5625us updates
rtc_mask(CMOS_STATUS_B, ~RTC_B_DSE, RTC_B_24HR);
rtc_read(CMOS_STATUS_C);
@@ -73,6 +76,8 @@ int RTCusers VARLOW;
void
rtc_use(void)
{
+ if (!CONFIG_RTC_TIMER)
+ return;
int count = GET_LOW(RTCusers);
SET_LOW(RTCusers, count+1);
if (count)
@@ -84,6 +89,8 @@ rtc_use(void)
void
rtc_release(void)
{
+ if (!CONFIG_RTC_TIMER)
+ return;
int count = GET_LOW(RTCusers);
SET_LOW(RTCusers, count-1);
if (count != 1)
diff --git a/qemu/roms/seabios/src/hw/sdcard.c b/qemu/roms/seabios/src/hw/sdcard.c
index 6ff93c856..e01e1bb02 100644
--- a/qemu/roms/seabios/src/hw/sdcard.c
+++ b/qemu/roms/seabios/src/hw/sdcard.c
@@ -5,12 +5,12 @@
// This file may be distributed under the terms of the GNU LGPLv3 license.
#include "block.h" // struct drive_s
-#include "fw/paravirt.h" // runningOnQEMU
#include "malloc.h" // malloc_fseg
#include "output.h" // znprintf
#include "pci.h" // pci_config_readl
#include "pci_ids.h" // PCI_CLASS_SYSTEM_SDHCI
#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "romfile.h" // romfile_findprefix
#include "stacks.h" // wait_preempt
#include "std/disk.h" // DISK_RET_SUCCESS
#include "string.h" // memset
@@ -42,8 +42,8 @@ struct sdhci_s {
u16 irq_signal;
u16 error_signal;
u16 auto_cmd12;
- u8 pad_3E[2];
- u64 cap;
+ u16 host_control2;
+ u32 cap_lo, cap_hi;
u64 max_current;
u16 force_auto_cmd12;
u16 force_error;
@@ -56,25 +56,38 @@ struct sdhci_s {
} PACKED;
// SDHCI commands
-#define SC_ALL_SEND_CID ((2<<8) | 0x21)
-#define SC_SEND_RELATIVE_ADDR ((3<<8) | 0x22)
-#define SC_SELECT_DESELECT_CARD ((7<<8) | 0x23)
-#define SC_READ_SINGLE ((17<<8) | 0x22)
-#define SC_READ_MULTIPLE ((18<<8) | 0x22)
-#define SC_WRITE_SINGLE ((24<<8) | 0x22)
-#define SC_WRITE_MULTIPLE ((25<<8) | 0x22)
-#define SC_APP_CMD ((55<<8) | 0x22)
-#define SC_APP_SEND_OP_COND ((41<<8) | 0x22)
+#define SCB_R0 0x00 // No response
+#define SCB_R48 0x1a // Response R1 (no data), R5, R6, R7
+#define SCB_R48d 0x3a // Response R1 (with data)
+#define SCB_R48b 0x1b // Response R1b, R5b
+#define SCB_R48o 0x02 // Response R3, R4
+#define SCB_R136 0x09 // Response R2
+#define SC_GO_IDLE_STATE ((0<<8) | SCB_R0)
+#define SC_SEND_OP_COND ((1<<8) | SCB_R48o)
+#define SC_ALL_SEND_CID ((2<<8) | SCB_R136)
+#define SC_SEND_RELATIVE_ADDR ((3<<8) | SCB_R48)
+#define SC_SELECT_DESELECT_CARD ((7<<8) | SCB_R48b)
+#define SC_SEND_IF_COND ((8<<8) | SCB_R48)
+#define SC_SEND_EXT_CSD ((8<<8) | SCB_R48d)
+#define SC_SEND_CSD ((9<<8) | SCB_R136)
+#define SC_READ_SINGLE ((17<<8) | SCB_R48d)
+#define SC_READ_MULTIPLE ((18<<8) | SCB_R48d)
+#define SC_WRITE_SINGLE ((24<<8) | SCB_R48d)
+#define SC_WRITE_MULTIPLE ((25<<8) | SCB_R48d)
+#define SC_APP_CMD ((55<<8) | SCB_R48)
+#define SC_APP_SEND_OP_COND ((41<<8) | SCB_R48o)
// SDHCI irqs
#define SI_CMD_COMPLETE (1<<0)
#define SI_TRANS_DONE (1<<1)
#define SI_WRITE_READY (1<<4)
#define SI_READ_READY (1<<5)
+#define SI_ERROR (1<<15)
// SDHCI present_state flags
-#define SP_CMD_INHIBIT (1<<0)
-#define SP_DAT_INHIBIT (1<<1)
+#define SP_CMD_INHIBIT (1<<0)
+#define SP_DAT_INHIBIT (1<<1)
+#define SP_CARD_INSERTED (1<<16)
// SDHCI transfer_mode flags
#define ST_BLOCKCOUNT (1<<1)
@@ -82,12 +95,43 @@ struct sdhci_s {
#define ST_READ (1<<4)
#define ST_MULTIPLE (1<<5)
+// SDHCI capabilities flags
+#define SD_CAPLO_V33 (1<<24)
+#define SD_CAPLO_V30 (1<<25)
+#define SD_CAPLO_V18 (1<<26)
+#define SD_CAPLO_BASECLOCK_SHIFT 8
+#define SD_CAPLO_BASECLOCK_MASK 0xff
+
+// SDHCI clock control flags
+#define SCC_INTERNAL_ENABLE (1<<0)
+#define SCC_STABLE (1<<1)
+#define SCC_CLOCK_ENABLE (1<<2)
+#define SCC_SDCLK_MASK 0xff
+#define SCC_SDCLK_SHIFT 8
+#define SCC_SDCLK_HI_MASK 0x300
+#define SCC_SDCLK_HI_RSHIFT 2
+
+// SDHCI power control flags
+#define SPC_POWER_ON (1<<0)
+#define SPC_V18 0x0a
+#define SPC_V30 0x0c
+#define SPC_V33 0x0e
+
+// SDHCI software reset flags
+#define SRF_ALL 0x01
+#define SRF_CMD 0x02
+#define SRF_DATA 0x04
+
// SDHCI result flags
-#define SR_OCR_CCS (1<<30)
+#define SR_OCR_CCS (1<<30)
+#define SR_OCR_NOTBUSY (1<<31)
// SDHCI timeouts
-#define SDHCI_PIO_TIMEOUT 1000 // XXX - these are just made up
-#define SDHCI_TRANSFER_TIMEOUT 10000
+#define SDHCI_POWER_OFF_TIME 1
+#define SDHCI_POWER_ON_TIME 1
+#define SDHCI_CLOCK_ON_TIME 1 // 74 clock cycles
+#define SDHCI_POWERUP_TIMEOUT 1000
+#define SDHCI_PIO_TIMEOUT 1000 // XXX - this is just made up
// Internal 'struct drive_s' storage for a detected card
struct sddrive_s {
@@ -97,18 +141,18 @@ struct sddrive_s {
};
// SD card types
-#define SF_MMC 0
-#define SF_SDSC 1
-#define SF_SDHC 2
+#define SF_MMC (1<<0)
+#define SF_HIGHCAPACITY (1<<1)
-// Repeatedly read a u16 register until the specific value is found
+// Repeatedly read a u16 register until any bit in a given mask is set
static int
-waitw(u16 *reg, u16 mask, u16 value, u32 end)
+sdcard_waitw(u16 *reg, u16 mask)
{
+ u32 end = timer_calc(SDHCI_PIO_TIMEOUT);
for (;;) {
u16 v = readw(reg);
- if ((v & mask) == value)
- return 0;
+ if (v & mask)
+ return v;
if (timer_check(end)) {
warn_timeout();
return -1;
@@ -117,24 +161,49 @@ waitw(u16 *reg, u16 mask, u16 value, u32 end)
}
}
+// Send an sdhci reset
+static int
+sdcard_reset(struct sdhci_s *regs, int flags)
+{
+ writeb(&regs->software_reset, flags);
+ u32 end = timer_calc(SDHCI_PIO_TIMEOUT);
+ while (readb(&regs->software_reset))
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ return 0;
+}
+
// Send a command to the card.
static int
sdcard_pio(struct sdhci_s *regs, int cmd, u32 *param)
{
- u32 end = timer_calc(SDHCI_PIO_TIMEOUT);
- u16 busyf = SP_CMD_INHIBIT | ((cmd & 0x03) == 0x03 ? SP_DAT_INHIBIT : 0);
- int ret = waitw((u16*)&regs->present_state, busyf, 0, end);
- if (ret)
- return ret;
+ u32 state = readl(&regs->present_state);
+ dprintf(9, "sdcard_pio cmd %x %x %x\n", cmd, *param, state);
+ if ((state & SP_CMD_INHIBIT)
+ || ((cmd & 0x03) == 0x03 && state & SP_DAT_INHIBIT)) {
+ dprintf(1, "sdcard_pio not ready %x\n", state);
+ return -1;
+ }
// Send command
writel(&regs->arg, *param);
writew(&regs->cmd, cmd);
- ret = waitw(&regs->irq_status, SI_CMD_COMPLETE, SI_CMD_COMPLETE, end);
- if (ret)
+ int ret = sdcard_waitw(&regs->irq_status, SI_ERROR|SI_CMD_COMPLETE);
+ if (ret < 0)
return ret;
+ if (ret & SI_ERROR) {
+ u16 err = readw(&regs->error_irq_status);
+ dprintf(3, "sdcard_pio command stop (code=%x)\n", err);
+ sdcard_reset(regs, SRF_CMD|SRF_DATA);
+ writew(&regs->error_irq_status, err);
+ return -1;
+ }
writew(&regs->irq_status, SI_CMD_COMPLETE);
// Read response
memcpy(param, regs->response, sizeof(regs->response));
+ dprintf(9, "sdcard cmd %x response %x %x %x %x\n"
+ , cmd, param[0], param[1], param[2], param[3]);
return 0;
}
@@ -155,24 +224,23 @@ sdcard_pio_transfer(struct sddrive_s *drive, int cmd, u32 addr
, void *data, int count)
{
// Send command
- writel(&drive->regs->block_size, DISK_SECTOR_SIZE);
- writew(&drive->regs->block_count, count); // XXX - SC_SET_BLOCK_COUNT?
+ writew(&drive->regs->block_size, DISK_SECTOR_SIZE);
+ writew(&drive->regs->block_count, count);
int isread = cmd != SC_WRITE_SINGLE && cmd != SC_WRITE_MULTIPLE;
u16 tmode = ((count > 1 ? ST_MULTIPLE|ST_AUTO_CMD12|ST_BLOCKCOUNT : 0)
| (isread ? ST_READ : 0));
writew(&drive->regs->transfer_mode, tmode);
- if (drive->card_type < SF_SDHC)
+ if (!(drive->card_type & SF_HIGHCAPACITY))
addr *= DISK_SECTOR_SIZE;
u32 param[4] = { addr };
int ret = sdcard_pio(drive->regs, cmd, param);
if (ret)
return ret;
// Read/write data
- u32 end = timer_calc(SDHCI_TRANSFER_TIMEOUT);
u16 cbit = isread ? SI_READ_READY : SI_WRITE_READY;
while (count--) {
- ret = waitw(&drive->regs->irq_status, cbit, cbit, end);
- if (ret)
+ ret = sdcard_waitw(&drive->regs->irq_status, cbit);
+ if (ret < 0)
return ret;
writew(&drive->regs->irq_status, cbit);
int i;
@@ -185,9 +253,8 @@ sdcard_pio_transfer(struct sddrive_s *drive, int cmd, u32 addr
}
}
// Complete command
- // XXX - SC_STOP_TRANSMISSION?
- ret = waitw(&drive->regs->irq_status, SI_TRANS_DONE, SI_TRANS_DONE, end);
- if (ret)
+ ret = sdcard_waitw(&drive->regs->irq_status, SI_TRANS_DONE);
+ if (ret < 0)
return ret;
writew(&drive->regs->irq_status, SI_TRANS_DONE);
return 0;
@@ -208,8 +275,8 @@ sdcard_readwrite(struct disk_op_s *op, int iswrite)
return DISK_RET_SUCCESS;
}
-int VISIBLE32FLAT
-process_sdcard_op(struct disk_op_s *op)
+int
+sdcard_process_op(struct disk_op_s *op)
{
if (!CONFIG_SDCARD)
return 0;
@@ -218,14 +285,8 @@ process_sdcard_op(struct disk_op_s *op)
return sdcard_readwrite(op, 0);
case CMD_WRITE:
return sdcard_readwrite(op, 1);
- case CMD_FORMAT:
- case CMD_RESET:
- case CMD_ISREADY:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -234,75 +295,253 @@ process_sdcard_op(struct disk_op_s *op)
* Setup
****************************************************************/
+static int
+sdcard_set_power(struct sdhci_s *regs)
+{
+ u32 cap = readl(&regs->cap_lo);
+ u32 volt, vbits;
+ if (cap & SD_CAPLO_V33) {
+ volt = 1<<20;
+ vbits = SPC_V33;
+ } else if (cap & SD_CAPLO_V30) {
+ volt = 1<<18;
+ vbits = SPC_V30;
+ } else if (cap & SD_CAPLO_V18) {
+ volt = 1<<7;
+ vbits = SPC_V18;
+ } else {
+ dprintf(1, "SD controller unsupported volt range (%x)\n", cap);
+ return -1;
+ }
+ writeb(&regs->power_control, 0);
+ msleep(SDHCI_POWER_OFF_TIME);
+ writeb(&regs->power_control, vbits | SPC_POWER_ON);
+ msleep(SDHCI_POWER_ON_TIME);
+ return volt;
+}
+
+static int
+sdcard_set_frequency(struct sdhci_s *regs, u32 khz)
+{
+ u16 ver = readw(&regs->controller_version);
+ u32 cap = readl(&regs->cap_lo);
+ u32 base_freq = (cap >> SD_CAPLO_BASECLOCK_SHIFT) & SD_CAPLO_BASECLOCK_MASK;
+ if (!base_freq) {
+ dprintf(1, "Unknown base frequency for SD controller\n");
+ return -1;
+ }
+ // Set new frequency
+ u32 divisor = DIV_ROUND_UP(base_freq * 1000, khz);
+ u16 creg;
+ if ((ver & 0xff) <= 0x01) {
+ divisor = divisor > 1 ? 1 << __fls(divisor-1) : 0;
+ creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT;
+ } else {
+ divisor = DIV_ROUND_UP(divisor, 2);
+ creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT;
+ creg |= (divisor & SCC_SDCLK_HI_MASK) >> SCC_SDCLK_HI_RSHIFT;
+ }
+ dprintf(3, "sdcard_set_frequency %d %d %x\n", base_freq, khz, creg);
+ writew(&regs->clock_control, 0);
+ writew(&regs->clock_control, creg | SCC_INTERNAL_ENABLE);
+ // Wait for frequency to become active
+ int ret = sdcard_waitw(&regs->clock_control, SCC_STABLE);
+ if (ret < 0)
+ return ret;
+ // Enable SD clock
+ writew(&regs->clock_control, creg | SCC_INTERNAL_ENABLE | SCC_CLOCK_ENABLE);
+ return 0;
+}
+
+// Obtain the disk size of an SD card
+static int
+sdcard_get_capacity(struct sddrive_s *drive, u8 *csd)
+{
+ // Original MMC/SD card capacity formula
+ u16 C_SIZE = (csd[6] >> 6) | (csd[7] << 2) | ((csd[8] & 0x03) << 10);
+ u8 C_SIZE_MULT = (csd[4] >> 7) | ((csd[5] & 0x03) << 1);
+ u8 READ_BL_LEN = csd[9] & 0x0f;
+ u32 count = (C_SIZE+1) << (C_SIZE_MULT + 2 + READ_BL_LEN - 9);
+ // Check for newer encoding formats.
+ u8 CSD_STRUCTURE = csd[14] >> 6;
+ if ((drive->card_type & SF_MMC) && CSD_STRUCTURE >= 2) {
+ // Get capacity from EXT_CSD register
+ u8 ext_csd[512];
+ int ret = sdcard_pio_transfer(drive, SC_SEND_EXT_CSD, 0, ext_csd, 1);
+ if (ret)
+ return ret;
+ count = *(u32*)&ext_csd[212];
+ } else if (!(drive->card_type & SF_MMC) && CSD_STRUCTURE >= 1) {
+ // High capacity SD card
+ u32 C_SIZE2 = csd[5] | (csd[6] << 8) | ((csd[7] & 0x3f) << 16);
+ count = (C_SIZE2+1) << (19-9);
+ }
+ // Fill drive struct and return
+ drive->drive.blksize = DISK_SECTOR_SIZE;
+ drive->drive.sectors = count;
+ return 0;
+}
+
// Initialize an SD card
static int
-sdcard_card_setup(struct sdhci_s *regs)
+sdcard_card_setup(struct sddrive_s *drive, int volt, int prio)
{
- // XXX - works on QEMU; probably wont on real hardware!
- u32 param[4] = { 0x01 };
- int ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param);
+ struct sdhci_s *regs = drive->regs;
+ // Set controller to initialization clock rate
+ int ret = sdcard_set_frequency(regs, 400);
+ if (ret)
+ return ret;
+ msleep(SDHCI_CLOCK_ON_TIME);
+ // Reset card
+ u32 param[4] = { };
+ ret = sdcard_pio(regs, SC_GO_IDLE_STATE, param);
if (ret)
return ret;
- int card_type = (param[0] & SR_OCR_CCS) ? SF_SDHC : SF_SDSC;
+ // Let card know SDHC/SDXC is supported and confirm voltage
+ u32 hcs = 0, vrange = (volt >= (1<<15) ? 0x100 : 0x200) | 0xaa;
+ param[0] = vrange;
+ ret = sdcard_pio(regs, SC_SEND_IF_COND, param);
+ if (!ret && param[0] == vrange)
+ hcs = (1<<30);
+ // Verify SD card (instead of MMC or SDIO)
+ param[0] = 0x00;
+ ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param);
+ if (ret) {
+ // Check for MMC card
+ param[0] = 0x00;
+ ret = sdcard_pio(regs, SC_SEND_OP_COND, param);
+ if (ret)
+ return ret;
+ drive->card_type |= SF_MMC;
+ hcs = (1<<30);
+ }
+ // Init card
+ u32 end = timer_calc(SDHCI_POWERUP_TIMEOUT);
+ for (;;) {
+ param[0] = hcs | volt; // high-capacity support and voltage level
+ if (drive->card_type & SF_MMC)
+ ret = sdcard_pio(regs, SC_SEND_OP_COND, param);
+ else
+ ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param);
+ if (ret)
+ return ret;
+ if (param[0] & SR_OCR_NOTBUSY)
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ msleep(5); // Avoid flooding log when debugging
+ }
+ drive->card_type |= (param[0] & SR_OCR_CCS) ? SF_HIGHCAPACITY : 0;
+ // Select card (get cid, set rca, get csd, select card)
param[0] = 0x00;
ret = sdcard_pio(regs, SC_ALL_SEND_CID, param);
if (ret)
return ret;
- param[0] = 0x01 << 16;
+ u8 cid[16];
+ memcpy(cid, param, sizeof(cid));
+ param[0] = drive->card_type & SF_MMC ? 0x0001 << 16 : 0x00;
ret = sdcard_pio(regs, SC_SEND_RELATIVE_ADDR, param);
if (ret)
return ret;
- u16 rca = param[0] >> 16;
+ u16 rca = drive->card_type & SF_MMC ? 0x0001 : param[0] >> 16;
+ param[0] = rca << 16;
+ ret = sdcard_pio(regs, SC_SEND_CSD, param);
+ if (ret)
+ return ret;
+ u8 csd[16];
+ memcpy(csd, param, sizeof(csd));
param[0] = rca << 16;
ret = sdcard_pio(regs, SC_SELECT_DESELECT_CARD, param);
if (ret)
return ret;
- return card_type;
+ // Set controller to data transfer clock rate
+ ret = sdcard_set_frequency(regs, 25000);
+ if (ret)
+ return ret;
+ // Register drive
+ ret = sdcard_get_capacity(drive, csd);
+ if (ret)
+ return ret;
+ char pnm[7] = {};
+ int i;
+ for (i=0; i < (drive->card_type & SF_MMC ? 6 : 5); i++)
+ pnm[i] = cid[11-i];
+ char *desc = znprintf(MAXDESCSIZE, "%s %s %dMiB"
+ , drive->card_type & SF_MMC ? "MMC drive" : "SD card"
+ , pnm, (u32)(drive->drive.sectors >> 11));
+ dprintf(1, "Found sdcard at %p: %s\n", regs, desc);
+ boot_add_hd(&drive->drive, desc, prio);
+ return 0;
}
// Setup and configure an SD card controller
static void
-sdcard_controller_setup(void *data)
+sdcard_controller_setup(struct sdhci_s *regs, int prio)
{
- struct pci_device *pci = data;
- u16 bdf = pci->bdf;
- wait_preempt(); // Avoid pci_config_readl when preempting
- struct sdhci_s *regs = (void*)pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
- pci_config_maskw(bdf, PCI_COMMAND, 0,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-
// Initialize controller
- if (!runningOnQEMU())
- // XXX - this init logic will probably only work on qemu!
+ u32 present_state = readl(&regs->present_state);
+ if (!(present_state & SP_CARD_INSERTED))
+ // No card present
return;
+ dprintf(3, "sdhci@%p ver=%x cap=%x %x\n", regs
+ , readw(&regs->controller_version)
+ , readl(&regs->cap_lo), readl(&regs->cap_hi));
+ sdcard_reset(regs, SRF_ALL);
writew(&regs->irq_signal, 0);
- writew(&regs->irq_enable, 0xffff);
+ writew(&regs->irq_enable, 0x01ff);
+ writew(&regs->irq_status, readw(&regs->irq_status));
writew(&regs->error_signal, 0);
- writeb(&regs->power_control, 0x0f);
- writew(&regs->clock_control, 0x0005);
-
- // Initialize card
- int card_type = sdcard_card_setup(regs);
- if (card_type < 0)
+ writew(&regs->error_irq_enable, 0x01ff);
+ writew(&regs->error_irq_status, readw(&regs->error_irq_status));
+ writeb(&regs->timeout_control, 0x0e); // Set to max timeout
+ int volt = sdcard_set_power(regs);
+ if (volt < 0)
return;
- // Register drive
+ // Initialize card
struct sddrive_s *drive = malloc_fseg(sizeof(*drive));
if (!drive) {
warn_noalloc();
- return;
+ goto fail;
}
memset(drive, 0, sizeof(*drive));
drive->drive.type = DTYPE_SDCARD;
- drive->drive.blksize = DISK_SECTOR_SIZE;
- drive->drive.sectors = (u64)-1; // XXX
drive->regs = regs;
- drive->card_type = card_type;
+ int ret = sdcard_card_setup(drive, volt, prio);
+ if (ret) {
+ free(drive);
+ goto fail;
+ }
+ return;
+fail:
+ writeb(&regs->power_control, 0);
+ writew(&regs->clock_control, 0);
+}
- dprintf(1, "Found SD Card at %02x:%02x.%x\n"
- , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
- char *desc = znprintf(MAXDESCSIZE, "SD Card"); // XXX
- boot_add_hd(&drive->drive, desc, bootprio_find_pci_device(pci));
+static void
+sdcard_pci_setup(void *data)
+{
+ struct pci_device *pci = data;
+ wait_preempt(); // Avoid pci_config_readl when preempting
+ // XXX - bars dependent on slot index register in pci config space
+ u32 regs = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0);
+ regs &= PCI_BASE_ADDRESS_MEM_MASK;
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ int prio = bootprio_find_pci_device(pci);
+ sdcard_controller_setup((void*)regs, prio);
+}
+
+static void
+sdcard_romfile_setup(void *data)
+{
+ struct romfile_s *file = data;
+ int prio = bootprio_find_named_rom(file->name, 0);
+ u32 addr = romfile_loadint(file->name, 0);
+ dprintf(1, "Starting sdcard controller check at addr %x\n", addr);
+ sdcard_controller_setup((void*)addr, prio);
}
void
@@ -311,11 +550,19 @@ sdcard_setup(void)
if (!CONFIG_SDCARD)
return;
+ struct romfile_s *file = NULL;
+ for (;;) {
+ file = romfile_findprefix("etc/sdcard", file);
+ if (!file)
+ break;
+ run_thread(sdcard_romfile_setup, file);
+ }
+
struct pci_device *pci;
foreachpci(pci) {
if (pci->class != PCI_CLASS_SYSTEM_SDHCI || pci->prog_if >= 2)
// Not an SDHCI controller following SDHCI spec
continue;
- run_thread(sdcard_controller_setup, pci);
+ run_thread(sdcard_pci_setup, pci);
}
}
diff --git a/qemu/roms/seabios/src/hw/timer.c b/qemu/roms/seabios/src/hw/timer.c
index 5edc9fdbb..03d22b2f5 100644
--- a/qemu/roms/seabios/src/hw/timer.c
+++ b/qemu/roms/seabios/src/hw/timer.c
@@ -49,8 +49,8 @@
#define PMTIMER_HZ 3579545 // Underlying Hz of the PM Timer
#define PMTIMER_TO_PIT 3 // Ratio of pmtimer rate to pit rate
-u32 TimerKHz VARFSEG;
-u16 TimerPort VARFSEG;
+u32 TimerKHz VARFSEG = DIV_ROUND_UP(PMTIMER_HZ, 1000 * PMTIMER_TO_PIT);
+u16 TimerPort VARFSEG = PORT_PIT_COUNTER0;
u8 ShiftTSC VARFSEG;
@@ -92,6 +92,7 @@ tsctimer_setup(void)
t = (t + 1) >> 1;
}
TimerKHz = DIV_ROUND_UP((u32)t, 1000 * PMTIMER_TO_PIT);
+ TimerPort = 0;
dprintf(1, "CPU Mhz=%u\n", (TimerKHz << ShiftTSC) / 1000);
}
@@ -100,24 +101,16 @@ tsctimer_setup(void)
void
timer_setup(void)
{
- if (CONFIG_PMTIMER && TimerPort) {
- dprintf(3, "pmtimer already configured; will not calibrate TSC\n");
+ if (!CONFIG_TSC_TIMER || (CONFIG_PMTIMER && TimerPort != PORT_PIT_COUNTER0))
return;
- }
+ // Check if CPU has a timestamp counter
u32 eax, ebx, ecx, edx, cpuid_features = 0;
cpuid(0, &eax, &ebx, &ecx, &edx);
if (eax > 0)
cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
-
- if (!(cpuid_features & CPUID_TSC)) {
- TimerPort = PORT_PIT_COUNTER0;
- TimerKHz = DIV_ROUND_UP(PMTIMER_HZ, 1000 * PMTIMER_TO_PIT);
- dprintf(3, "386/486 class CPU. Using TSC emulation\n");
- return;
- }
-
- tsctimer_setup();
+ if (cpuid_features & CPUID_TSC)
+ tsctimer_setup();
}
void
@@ -154,7 +147,7 @@ static u32
timer_read(void)
{
u16 port = GET_GLOBAL(TimerPort);
- if (!port)
+ if (CONFIG_TSC_TIMER && !port)
// Read from CPU TSC
return rdtscll() >> GET_GLOBAL(ShiftTSC);
if (CONFIG_PMTIMER && port != PORT_PIT_COUNTER0)
@@ -249,6 +242,8 @@ ticks_from_ms(u32 ms)
void
pit_setup(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
// timer0: binary count, 16bit count, mode 2
outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE);
// maximum count of 0000H = 18.2Hz
diff --git a/qemu/roms/seabios/src/hw/tpm_drivers.c b/qemu/roms/seabios/src/hw/tpm_drivers.c
new file mode 100644
index 000000000..444eac39b
--- /dev/null
+++ b/qemu/roms/seabios/src/hw/tpm_drivers.c
@@ -0,0 +1,291 @@
+// Implementation of a TPM driver for the TPM TIS interface
+//
+// Copyright (C) 2006-2011 IBM Corporation
+//
+// Authors:
+// Stefan Berger <stefanb@linux.vnet.ibm.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_TPM_TIS_SHA1THRESHOLD
+#include "string.h" // memcpy
+#include "util.h" // msleep
+#include "x86.h" // readl
+#include "hw/tpm_drivers.h" // struct tpm_driver
+#include "tcgbios.h" // TCG_*
+
+static const u32 tis_default_timeouts[4] = {
+ TIS_DEFAULT_TIMEOUT_A,
+ TIS_DEFAULT_TIMEOUT_B,
+ TIS_DEFAULT_TIMEOUT_C,
+ TIS_DEFAULT_TIMEOUT_D,
+};
+
+static const u32 tpm_default_durations[3] = {
+ TPM_DEFAULT_DURATION_SHORT,
+ TPM_DEFAULT_DURATION_MEDIUM,
+ TPM_DEFAULT_DURATION_LONG,
+};
+
+/* determined values */
+static u32 tpm_default_dur[3];
+static u32 tpm_default_to[4];
+
+
+/* if device is not there, return '0', '1' otherwise */
+static u32 tis_probe(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID));
+
+ if ((didvid != 0) && (didvid != 0xffffffff))
+ rc = 1;
+
+ return rc;
+}
+
+static u32 tis_init(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 1;
+
+ writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0);
+
+ if (tpm_drivers[TIS_DRIVER_IDX].durations == NULL) {
+ u32 *durations = tpm_default_dur;
+ memcpy(durations, tpm_default_durations,
+ sizeof(tpm_default_durations));
+ tpm_drivers[TIS_DRIVER_IDX].durations = durations;
+ }
+
+ if (tpm_drivers[TIS_DRIVER_IDX].timeouts == NULL) {
+ u32 *timeouts = tpm_default_to;
+ memcpy(timeouts, tis_default_timeouts,
+ sizeof(tis_default_timeouts));
+ tpm_drivers[TIS_DRIVER_IDX].timeouts = timeouts;
+ }
+
+ return 1;
+}
+
+
+static void set_timeouts(u32 timeouts[4], u32 durations[3])
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ u32 *tos = tpm_drivers[TIS_DRIVER_IDX].timeouts;
+ u32 *dus = tpm_drivers[TIS_DRIVER_IDX].durations;
+
+ if (tos && tos != tis_default_timeouts && timeouts)
+ memcpy(tos, timeouts, 4 * sizeof(u32));
+ if (dus && dus != tpm_default_durations && durations)
+ memcpy(dus, durations, 3 * sizeof(u32));
+}
+
+
+static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 1;
+
+ while (time > 0) {
+ u8 sts = readb(TIS_REG(locty, TIS_REG_STS));
+ if ((sts & mask) == expect) {
+ rc = 0;
+ break;
+ }
+ msleep(1);
+ time--;
+ }
+ return rc;
+}
+
+static u32 tis_activate(u8 locty)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 acc;
+ int l;
+ u32 timeout_a = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_A];
+
+ if (!(readb(TIS_REG(locty, TIS_REG_ACCESS)) &
+ TIS_ACCESS_ACTIVE_LOCALITY)) {
+ /* release locality in use top-downwards */
+ for (l = 4; l >= 0; l--)
+ writeb(TIS_REG(l, TIS_REG_ACCESS),
+ TIS_ACCESS_ACTIVE_LOCALITY);
+ }
+
+ /* request access to locality */
+ writeb(TIS_REG(locty, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
+
+ acc = readb(TIS_REG(locty, TIS_REG_ACCESS));
+ if ((acc & TIS_ACCESS_ACTIVE_LOCALITY)) {
+ writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+ rc = tis_wait_sts(locty, timeout_a,
+ TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
+ }
+
+ return rc;
+}
+
+static u32 tis_find_active_locality(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u8 locty;
+
+ for (locty = 0; locty <= 4; locty++) {
+ if ((readb(TIS_REG(locty, TIS_REG_ACCESS)) &
+ TIS_ACCESS_ACTIVE_LOCALITY))
+ return locty;
+ }
+
+ tis_activate(0);
+
+ return 0;
+}
+
+static u32 tis_ready(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 locty = tis_find_active_locality();
+ u32 timeout_b = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_B];
+
+ writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+ rc = tis_wait_sts(locty, timeout_b,
+ TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
+
+ return rc;
+}
+
+static u32 tis_senddata(const u8 *const data, u32 len)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u32 offset = 0;
+ u32 end = 0;
+ u16 burst = 0;
+ u32 ctr = 0;
+ u8 locty = tis_find_active_locality();
+ u32 timeout_d = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_D];
+
+ do {
+ while (burst == 0 && ctr < timeout_d) {
+ burst = readl(TIS_REG(locty, TIS_REG_STS)) >> 8;
+ if (burst == 0) {
+ msleep(1);
+ ctr++;
+ }
+ }
+
+ if (burst == 0) {
+ rc = TCG_RESPONSE_TIMEOUT;
+ break;
+ }
+
+ while (1) {
+ writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), data[offset++]);
+ burst--;
+
+ if (burst == 0 || offset == len)
+ break;
+ }
+
+ if (offset == len)
+ end = 1;
+ } while (end == 0);
+
+ return rc;
+}
+
+static u32 tis_readresp(u8 *buffer, u32 *len)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u32 offset = 0;
+ u32 sts;
+ u8 locty = tis_find_active_locality();
+
+ while (offset < *len) {
+ buffer[offset] = readb(TIS_REG(locty, TIS_REG_DATA_FIFO));
+ offset++;
+ sts = readb(TIS_REG(locty, TIS_REG_STS));
+ /* data left ? */
+ if ((sts & TIS_STS_DATA_AVAILABLE) == 0)
+ break;
+ }
+
+ *len = offset;
+
+ return rc;
+}
+
+
+static u32 tis_waitdatavalid(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 locty = tis_find_active_locality();
+ u32 timeout_c = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C];
+
+ if (tis_wait_sts(locty, timeout_c, TIS_STS_VALID, TIS_STS_VALID) != 0)
+ rc = TCG_NO_RESPONSE;
+
+ return rc;
+}
+
+static u32 tis_waitrespready(enum tpmDurationType to_t)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 locty = tis_find_active_locality();
+ u32 timeout = tpm_drivers[TIS_DRIVER_IDX].durations[to_t];
+
+ writeb(TIS_REG(locty ,TIS_REG_STS), TIS_STS_TPM_GO);
+
+ if (tis_wait_sts(locty, timeout,
+ TIS_STS_DATA_AVAILABLE, TIS_STS_DATA_AVAILABLE) != 0)
+ rc = TCG_NO_RESPONSE;
+
+ return rc;
+}
+
+
+struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
+ [TIS_DRIVER_IDX] =
+ {
+ .timeouts = NULL,
+ .durations = NULL,
+ .set_timeouts = set_timeouts,
+ .probe = tis_probe,
+ .init = tis_init,
+ .activate = tis_activate,
+ .ready = tis_ready,
+ .senddata = tis_senddata,
+ .readresp = tis_readresp,
+ .waitdatavalid = tis_waitdatavalid,
+ .waitrespready = tis_waitrespready,
+ .sha1threshold = 100 * 1024,
+ },
+};
diff --git a/qemu/roms/seabios/src/hw/tpm_drivers.h b/qemu/roms/seabios/src/hw/tpm_drivers.h
new file mode 100644
index 000000000..34bb12d1c
--- /dev/null
+++ b/qemu/roms/seabios/src/hw/tpm_drivers.h
@@ -0,0 +1,90 @@
+#ifndef TPM_DRIVERS_H
+#define TPM_DRIVERS_H
+
+#include "types.h" // u32
+
+
+enum tpmDurationType {
+ TPM_DURATION_TYPE_SHORT = 0,
+ TPM_DURATION_TYPE_MEDIUM,
+ TPM_DURATION_TYPE_LONG,
+};
+
+/* low level driver implementation */
+struct tpm_driver {
+ u32 *timeouts;
+ u32 *durations;
+ void (*set_timeouts)(u32 timeouts[4], u32 durations[3]);
+ u32 (*probe)(void);
+ u32 (*init)(void);
+ u32 (*activate)(u8 locty);
+ u32 (*ready)(void);
+ u32 (*senddata)(const u8 *const data, u32 len);
+ u32 (*readresp)(u8 *buffer, u32 *len);
+ u32 (*waitdatavalid)(void);
+ u32 (*waitrespready)(enum tpmDurationType to_t);
+ /* the TPM will be used for buffers of sizes below the sha1threshold
+ for calculating the hash */
+ u32 sha1threshold;
+};
+
+extern struct tpm_driver tpm_drivers[];
+
+
+#define TIS_DRIVER_IDX 0
+#define TPM_NUM_DRIVERS 1
+
+#define TPM_INVALID_DRIVER -1
+
+/* TIS driver */
+/* address of locality 0 (TIS) */
+#define TPM_TIS_BASE_ADDRESS 0xfed40000
+
+#define TIS_REG(LOCTY, REG) \
+ (void *)(TPM_TIS_BASE_ADDRESS + (LOCTY << 12) + REG)
+
+/* hardware registers */
+#define TIS_REG_ACCESS 0x0
+#define TIS_REG_INT_ENABLE 0x8
+#define TIS_REG_INT_VECTOR 0xc
+#define TIS_REG_INT_STATUS 0x10
+#define TIS_REG_INTF_CAPABILITY 0x14
+#define TIS_REG_STS 0x18
+#define TIS_REG_DATA_FIFO 0x24
+#define TIS_REG_DID_VID 0xf00
+#define TIS_REG_RID 0xf04
+
+#define TIS_STS_VALID (1 << 7) /* 0x80 */
+#define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */
+#define TIS_STS_TPM_GO (1 << 5) /* 0x20 */
+#define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */
+#define TIS_STS_EXPECT (1 << 3) /* 0x08 */
+#define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */
+
+#define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */
+#define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */
+#define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */
+#define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */
+#define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */
+#define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */
+#define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */
+
+#define SCALER 10
+
+#define TIS_DEFAULT_TIMEOUT_A (750 * SCALER)
+#define TIS_DEFAULT_TIMEOUT_B (2000 * SCALER)
+#define TIS_DEFAULT_TIMEOUT_C (750 * SCALER)
+#define TIS_DEFAULT_TIMEOUT_D (750 * SCALER)
+
+enum tisTimeoutType {
+ TIS_TIMEOUT_TYPE_A = 0,
+ TIS_TIMEOUT_TYPE_B,
+ TIS_TIMEOUT_TYPE_C,
+ TIS_TIMEOUT_TYPE_D,
+};
+
+#define TPM_DEFAULT_DURATION_SHORT (2000 * SCALER)
+#define TPM_DEFAULT_DURATION_MEDIUM (20000 * SCALER)
+#define TPM_DEFAULT_DURATION_LONG (60000 * SCALER)
+
+#endif /* TPM_DRIVERS_H */
diff --git a/qemu/roms/seabios/src/hw/usb-hid.h b/qemu/roms/seabios/src/hw/usb-hid.h
index ef34e7963..fd7b8f8be 100644
--- a/qemu/roms/seabios/src/hw/usb-hid.h
+++ b/qemu/roms/seabios/src/hw/usb-hid.h
@@ -4,10 +4,10 @@
// usb-hid.c
struct usbdevice_s;
int usb_hid_setup(struct usbdevice_s *usbdev);
-inline int usb_kbd_active(void);
-inline int usb_kbd_command(int command, u8 *param);
-inline int usb_mouse_active(void);
-inline int usb_mouse_command(int command, u8 *param);
+int usb_kbd_active(void);
+int usb_kbd_command(int command, u8 *param);
+int usb_mouse_active(void);
+int usb_mouse_command(int command, u8 *param);
void usb_check_event(void);
diff --git a/qemu/roms/seabios/src/hw/usb-msc.c b/qemu/roms/seabios/src/hw/usb-msc.c
index d90319f51..a234f13be 100644
--- a/qemu/roms/seabios/src/hw/usb-msc.c
+++ b/qemu/roms/seabios/src/hw/usb-msc.c
@@ -63,25 +63,27 @@ usb_msc_send(struct usbdrive_s *udrive_gf, int dir, void *buf, u32 bytes)
// Low-level usb command transmit function.
int
-usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+usb_process_op(struct disk_op_s *op)
{
if (!CONFIG_USB_MSC)
return 0;
- dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
- , op->drive_gf, 0, op->count, blocksize, op->buf_fl);
+ dprintf(16, "usb_cmd_data id=%p write=%d count=%d buf=%p\n"
+ , op->drive_gf, 0, op->count, op->buf_fl);
struct usbdrive_s *udrive_gf = container_of(
op->drive_gf, struct usbdrive_s, drive);
// Setup command block wrapper.
- u32 bytes = blocksize * op->count;
struct cbw_s cbw;
memset(&cbw, 0, sizeof(cbw));
- memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE);
+ int blocksize = scsi_fill_cmd(op, cbw.CBWCB, USB_CDB_SIZE);
+ if (blocksize < 0)
+ return default_process_op(op);
+ u32 bytes = blocksize * op->count;
cbw.dCBWSignature = CBW_SIGNATURE;
cbw.dCBWTag = 999; // XXX
cbw.dCBWDataTransferLength = bytes;
- cbw.bmCBWFlags = cdb_is_read(cdbcmd, blocksize) ? USB_DIR_IN : USB_DIR_OUT;
+ cbw.bmCBWFlags = scsi_is_read(op) ? USB_DIR_IN : USB_DIR_OUT;
cbw.bCBWLUN = GET_GLOBALFLAT(udrive_gf->lun);
cbw.bCBWCBLength = USB_CDB_SIZE;
diff --git a/qemu/roms/seabios/src/hw/usb-msc.h b/qemu/roms/seabios/src/hw/usb-msc.h
index c40d75556..ff3c38038 100644
--- a/qemu/roms/seabios/src/hw/usb-msc.h
+++ b/qemu/roms/seabios/src/hw/usb-msc.h
@@ -3,7 +3,7 @@
// usb-msc.c
struct disk_op_s;
-int usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int usb_process_op(struct disk_op_s *op);
struct usbdevice_s;
int usb_msc_setup(struct usbdevice_s *usbdev);
diff --git a/qemu/roms/seabios/src/hw/usb-uas.c b/qemu/roms/seabios/src/hw/usb-uas.c
index 6ef8d0912..10e38454a 100644
--- a/qemu/roms/seabios/src/hw/usb-uas.c
+++ b/qemu/roms/seabios/src/hw/usb-uas.c
@@ -91,7 +91,7 @@ struct uasdrive_s {
};
int
-uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+uas_process_op(struct disk_op_s *op)
{
if (!CONFIG_USB_UAS)
return DISK_RET_EBADTRACK;
@@ -104,7 +104,9 @@ uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
ui.hdr.id = UAS_UI_COMMAND;
ui.hdr.tag = 0xdead;
ui.command.lun[1] = GET_GLOBALFLAT(drive_gf->lun);
- memcpy(ui.command.cdb, cdbcmd, sizeof(ui.command.cdb));
+ int blocksize = scsi_fill_cmd(op, ui.command.cdb, sizeof(ui.command.cdb));
+ if (blocksize < 0)
+ return default_process_op(op);
int ret = usb_send_bulk(GET_GLOBALFLAT(drive_gf->command),
USB_DIR_OUT, MAKE_FLATPTR(GET_SEG(SS), &ui),
sizeof(ui.hdr) + sizeof(ui.command));
diff --git a/qemu/roms/seabios/src/hw/usb-uas.h b/qemu/roms/seabios/src/hw/usb-uas.h
index ad91c5f60..8b2f810e9 100644
--- a/qemu/roms/seabios/src/hw/usb-uas.h
+++ b/qemu/roms/seabios/src/hw/usb-uas.h
@@ -2,7 +2,7 @@
#define __USB_UAS_H
struct disk_op_s;
-int uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int uas_process_op(struct disk_op_s *op);
struct usbdevice_s;
int usb_uas_setup(struct usbdevice_s *usbdev);
diff --git a/qemu/roms/seabios/src/hw/usb-xhci.c b/qemu/roms/seabios/src/hw/usb-xhci.c
index fd58334dc..654febaad 100644
--- a/qemu/roms/seabios/src/hw/usb-xhci.c
+++ b/qemu/roms/seabios/src/hw/usb-xhci.c
@@ -350,26 +350,41 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port)
{
struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb);
u32 portsc = readl(&xhci->pr[port].portsc);
- int rc;
+ if (!(portsc & XHCI_PORTSC_CCS))
+ // Device no longer connected?!
+ return -1;
switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) {
case PLS_U0:
- rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
+ // A USB3 port - controller automatically performs reset
break;
case PLS_POLLING:
+ // A USB2 port - perform device reset
xhci_print_port_state(3, __func__, port, portsc);
- portsc |= XHCI_PORTSC_PR;
- writel(&xhci->pr[port].portsc, portsc);
- if (wait_bit(&xhci->pr[port].portsc, XHCI_PORTSC_PED, XHCI_PORTSC_PED, 100) != 0)
- return -1;
- portsc = readl(&xhci->pr[port].portsc);
- rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
+ writel(&xhci->pr[port].portsc, portsc | XHCI_PORTSC_PR);
break;
default:
- rc = -1;
- break;
+ return -1;
}
+ // Wait for device to complete reset and be enabled
+ u32 end = timer_calc(100);
+ for (;;) {
+ portsc = readl(&xhci->pr[port].portsc);
+ if (!(portsc & XHCI_PORTSC_CCS))
+ // Device disconnected during reset
+ return -1;
+ if (portsc & XHCI_PORTSC_PED)
+ // Reset complete
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+
+ int rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
xhci_print_port_state(1, "XHCI", port, portsc);
return rc;
}
@@ -465,7 +480,7 @@ configure_xhci(void *data)
xhci->evts->cs = 1;
reg = readl(&xhci->caps->hcsparams2);
- u32 spb = reg >> 27;
+ u32 spb = (reg >> 21 & 0x1f) << 5 | reg >> 27;
if (spb) {
dprintf(3, "%s: setup %d scratch pad buffers\n", __func__, spb);
u64 *spba = memalign_high(64, sizeof(*spba) * spb);
@@ -921,8 +936,14 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
pipe->epid = epid;
pipe->reqs.cs = 1;
- if (eptype == USB_ENDPOINT_XFER_INT)
+ if (eptype == USB_ENDPOINT_XFER_INT) {
pipe->buf = malloc_high(pipe->pipe.maxpacket);
+ if (!pipe->buf) {
+ warn_noalloc();
+ free(pipe);
+ return NULL;
+ }
+ }
// Allocate input context and initialize endpoint info.
struct xhci_inctx *in = xhci_alloc_inctx(usbdev, epid);
@@ -988,6 +1009,7 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
return &pipe->pipe;
fail:
+ free(pipe->buf);
free(pipe);
free(in);
return NULL;
diff --git a/qemu/roms/seabios/src/hw/usb.c b/qemu/roms/seabios/src/hw/usb.c
index 1b4ea8bed..e46092c63 100644
--- a/qemu/roms/seabios/src/hw/usb.c
+++ b/qemu/roms/seabios/src/hw/usb.c
@@ -79,9 +79,8 @@ usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
case USB_TYPE_EHCI:
return ehci_poll_intr(pipe_fl, data);
case USB_TYPE_XHCI: ;
- extern void _cfunc32flat_xhci_poll_intr(void);
- return call32_params(_cfunc32flat_xhci_poll_intr, (u32)pipe_fl
- , (u32)MAKE_FLATPTR(GET_SEG(SS), (u32)data), 0, -1);
+ return call32_params(xhci_poll_intr, pipe_fl
+ , MAKE_FLATPTR(GET_SEG(SS), data), 0, -1);
}
}
@@ -249,8 +248,10 @@ get_device_config(struct usb_pipe *pipe)
return NULL;
void *config = malloc_tmphigh(cfg.wTotalLength);
- if (!config)
+ if (!config) {
+ warn_noalloc();
return NULL;
+ }
req.wLength = cfg.wTotalLength;
ret = usb_send_default_control(pipe, &req, config);
if (ret) {
diff --git a/qemu/roms/seabios/src/hw/virtio-blk.c b/qemu/roms/seabios/src/hw/virtio-blk.c
index e2dbd3c94..20a79ebba 100644
--- a/qemu/roms/seabios/src/hw/virtio-blk.c
+++ b/qemu/roms/seabios/src/hw/virtio-blk.c
@@ -25,7 +25,7 @@
struct virtiodrive_s {
struct drive_s drive;
struct vring_virtqueue *vq;
- u16 ioaddr;
+ struct vp_device vp;
};
static int
@@ -33,7 +33,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
{
struct virtiodrive_s *vdrive_gf =
container_of(op->drive_gf, struct virtiodrive_s, drive);
- struct vring_virtqueue *vq = GET_GLOBALFLAT(vdrive_gf->vq);
+ struct vring_virtqueue *vq = vdrive_gf->vq;
struct virtio_blk_outhdr hdr = {
.type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN,
.ioprio = 0,
@@ -42,15 +42,15 @@ virtio_blk_op(struct disk_op_s *op, int write)
u8 status = VIRTIO_BLK_S_UNSUPP;
struct vring_list sg[] = {
{
- .addr = MAKE_FLATPTR(GET_SEG(SS), &hdr),
+ .addr = (void*)(&hdr),
.length = sizeof(hdr),
},
{
.addr = op->buf_fl,
- .length = GET_GLOBALFLAT(vdrive_gf->drive.blksize) * op->count,
+ .length = vdrive_gf->drive.blksize * op->count,
},
{
- .addr = MAKE_FLATPTR(GET_SEG(SS), &status),
+ .addr = (void*)(&status),
.length = sizeof(status),
},
};
@@ -60,7 +60,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
vring_add_buf(vq, sg, 2, 1, 0, 0);
else
vring_add_buf(vq, sg, 1, 2, 0, 0);
- vring_kick(GET_GLOBALFLAT(vdrive_gf->ioaddr), vq, 1);
+ vring_kick(&vdrive_gf->vp, vq, 1);
/* Wait for reply */
while (!vring_more_used(vq))
@@ -72,13 +72,13 @@ virtio_blk_op(struct disk_op_s *op, int write)
/* Clear interrupt status register. Avoid leaving interrupts stuck if
* VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
*/
- vp_get_isr(GET_GLOBALFLAT(vdrive_gf->ioaddr));
+ vp_get_isr(&vdrive_gf->vp);
return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
}
int
-process_virtio_blk_op(struct disk_op_s *op)
+virtio_blk_process_op(struct disk_op_s *op)
{
if (! CONFIG_VIRTIO_BLK)
return 0;
@@ -87,14 +87,8 @@ process_virtio_blk_op(struct disk_op_s *op)
return virtio_blk_op(op, 0);
case CMD_WRITE:
return virtio_blk_op(op, 1);
- case CMD_FORMAT:
- case CMD_RESET:
- case CMD_ISREADY:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -102,6 +96,7 @@ static void
init_virtio_blk(struct pci_device *pci)
{
u16 bdf = pci->bdf;
+ u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER;
dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf),
pci_bdf_to_dev(bdf));
struct virtiodrive_s *vdrive = malloc_fseg(sizeof(*vdrive));
@@ -113,47 +108,93 @@ init_virtio_blk(struct pci_device *pci)
vdrive->drive.type = DTYPE_VIRTIO_BLK;
vdrive->drive.cntl_id = bdf;
- u16 ioaddr = vp_init_simple(bdf);
- vdrive->ioaddr = ioaddr;
- if (vp_find_vq(ioaddr, 0, &vdrive->vq) < 0 ) {
+ vp_init_simple(&vdrive->vp, pci);
+ if (vp_find_vq(&vdrive->vp, 0, &vdrive->vq) < 0 ) {
dprintf(1, "fail to find vq for virtio-blk %x:%x\n",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
goto fail;
}
- struct virtio_blk_config cfg;
- vp_get(ioaddr, 0, &cfg, sizeof(cfg));
-
- u32 f = vp_get_features(ioaddr);
- vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
- cfg.blk_size : DISK_SECTOR_SIZE;
-
- vdrive->drive.sectors = cfg.capacity;
- dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
- pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
- vdrive->drive.blksize, (u32)vdrive->drive.sectors);
-
- if (vdrive->drive.blksize != DISK_SECTOR_SIZE) {
- dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
+ if (vdrive->vp.use_modern) {
+ struct vp_device *vp = &vdrive->vp;
+ u64 features = vp_get_features(vp);
+ u64 version1 = 1ull << VIRTIO_F_VERSION_1;
+ u64 blk_size = 1ull << VIRTIO_BLK_F_BLK_SIZE;
+ if (!(features & version1)) {
+ dprintf(1, "modern device without virtio_1 feature bit: %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+
+ features = features & (version1 | blk_size);
+ vp_set_features(vp, features);
+ status |= VIRTIO_CONFIG_S_FEATURES_OK;
+ vp_set_status(vp, status);
+ if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) {
+ dprintf(1, "device didn't accept features: %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+
+ vdrive->drive.sectors =
+ vp_read(&vp->device, struct virtio_blk_config, capacity);
+ if (features & blk_size) {
+ vdrive->drive.blksize =
+ vp_read(&vp->device, struct virtio_blk_config, blk_size);
+ } else {
+ vdrive->drive.blksize = DISK_SECTOR_SIZE;
+ }
+ if (vdrive->drive.blksize != DISK_SECTOR_SIZE) {
+ dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive->drive.blksize);
+ goto fail;
+ }
+ dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
- vdrive->drive.blksize);
- goto fail;
+ vdrive->drive.blksize, (u32)vdrive->drive.sectors);
+
+ vdrive->drive.pchs.cylinder =
+ vp_read(&vp->device, struct virtio_blk_config, cylinders);
+ vdrive->drive.pchs.head =
+ vp_read(&vp->device, struct virtio_blk_config, heads);
+ vdrive->drive.pchs.sector =
+ vp_read(&vp->device, struct virtio_blk_config, sectors);
+ } else {
+ struct virtio_blk_config cfg;
+ vp_get_legacy(&vdrive->vp, 0, &cfg, sizeof(cfg));
+
+ u64 f = vp_get_features(&vdrive->vp);
+ vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
+ cfg.blk_size : DISK_SECTOR_SIZE;
+
+ vdrive->drive.sectors = cfg.capacity;
+ dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive->drive.blksize, (u32)vdrive->drive.sectors);
+
+ if (vdrive->drive.blksize != DISK_SECTOR_SIZE) {
+ dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive->drive.blksize);
+ goto fail;
+ }
+ vdrive->drive.pchs.cylinder = cfg.cylinders;
+ vdrive->drive.pchs.head = cfg.heads;
+ vdrive->drive.pchs.sector = cfg.sectors;
}
- vdrive->drive.pchs.cylinder = cfg.cylinders;
- vdrive->drive.pchs.head = cfg.heads;
- vdrive->drive.pchs.sector = cfg.sectors;
char *desc = znprintf(MAXDESCSIZE, "Virtio disk PCI:%x:%x",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
boot_add_hd(&vdrive->drive, desc, bootprio_find_pci_device(pci));
- vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
- VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
+ status |= VIRTIO_CONFIG_S_DRIVER_OK;
+ vp_set_status(&vdrive->vp, status);
return;
fail:
- vp_reset(ioaddr);
+ vp_reset(&vdrive->vp);
free(vdrive->vq);
free(vdrive);
}
@@ -169,8 +210,9 @@ virtio_blk_setup(void)
struct pci_device *pci;
foreachpci(pci) {
- if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET
- || pci->device != PCI_DEVICE_ID_VIRTIO_BLK)
+ if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET ||
+ (pci->device != PCI_DEVICE_ID_VIRTIO_BLK_09 &&
+ pci->device != PCI_DEVICE_ID_VIRTIO_BLK_10))
continue;
init_virtio_blk(pci);
}
diff --git a/qemu/roms/seabios/src/hw/virtio-blk.h b/qemu/roms/seabios/src/hw/virtio-blk.h
index b233c744b..157bed627 100644
--- a/qemu/roms/seabios/src/hw/virtio-blk.h
+++ b/qemu/roms/seabios/src/hw/virtio-blk.h
@@ -37,7 +37,7 @@ struct virtio_blk_outhdr {
#define VIRTIO_BLK_S_UNSUPP 2
struct disk_op_s;
-int process_virtio_blk_op(struct disk_op_s *op);
+int virtio_blk_process_op(struct disk_op_s *op);
void virtio_blk_setup(void);
#endif /* _VIRTIO_BLK_H */
diff --git a/qemu/roms/seabios/src/hw/virtio-pci.c b/qemu/roms/seabios/src/hw/virtio-pci.c
index b9b3ab1e3..6df519489 100644
--- a/qemu/roms/seabios/src/hw/virtio-pci.c
+++ b/qemu/roms/seabios/src/hw/virtio-pci.c
@@ -24,47 +24,153 @@
#include "virtio-pci.h"
#include "virtio-ring.h"
-int vp_find_vq(unsigned int ioaddr, int queue_index,
+u64 vp_get_features(struct vp_device *vp)
+{
+ u32 f0, f1;
+
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, device_feature_select, 0);
+ f0 = vp_read(&vp->common, virtio_pci_common_cfg, device_feature);
+ vp_write(&vp->common, virtio_pci_common_cfg, device_feature_select, 1);
+ f1 = vp_read(&vp->common, virtio_pci_common_cfg, device_feature);
+ } else {
+ f0 = vp_read(&vp->legacy, virtio_pci_legacy, host_features);
+ f1 = 0;
+ }
+ return ((u64)f1 << 32) | f0;
+}
+
+void vp_set_features(struct vp_device *vp, u64 features)
+{
+ u32 f0, f1;
+
+ f0 = features;
+ f1 = features >> 32;
+
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, guest_feature_select, 0);
+ vp_write(&vp->common, virtio_pci_common_cfg, guest_feature, f0);
+ vp_write(&vp->common, virtio_pci_common_cfg, guest_feature_select, 1);
+ vp_write(&vp->common, virtio_pci_common_cfg, guest_feature, f1);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, guest_features, f0);
+ }
+}
+
+u8 vp_get_status(struct vp_device *vp)
+{
+ if (vp->use_modern) {
+ return vp_read(&vp->common, virtio_pci_common_cfg, device_status);
+ } else {
+ return vp_read(&vp->legacy, virtio_pci_legacy, status);
+ }
+}
+
+void vp_set_status(struct vp_device *vp, u8 status)
+{
+ if (status == 0) /* reset */
+ return;
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, device_status, status);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, status, status);
+ }
+}
+
+u8 vp_get_isr(struct vp_device *vp)
+{
+ if (vp->use_modern) {
+ return vp_read(&vp->isr, virtio_pci_isr, isr);
+ } else {
+ return vp_read(&vp->legacy, virtio_pci_legacy, isr);
+ }
+}
+
+void vp_reset(struct vp_device *vp)
+{
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, device_status, 0);
+ vp_read(&vp->isr, virtio_pci_isr, isr);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, status, 0);
+ vp_read(&vp->legacy, virtio_pci_legacy, isr);
+ }
+}
+
+void vp_notify(struct vp_device *vp, struct vring_virtqueue *vq)
+{
+ if (vp->use_modern) {
+ u32 addr = vp->notify.addr +
+ vq->queue_notify_off *
+ vp->notify_off_multiplier;
+ if (vp->notify.is_io) {
+ outw(vq->queue_index, addr);
+ } else {
+ writew((void*)addr, vq->queue_index);
+ }
+ dprintf(9, "vp notify %x (%d) -- 0x%x\n",
+ addr, 2, vq->queue_index);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, queue_notify, vq->queue_index);
+ }
+}
+
+int vp_find_vq(struct vp_device *vp, int queue_index,
struct vring_virtqueue **p_vq)
{
u16 num;
ASSERT32FLAT();
- struct vring_virtqueue *vq = *p_vq = memalign_low(PAGE_SIZE, sizeof(*vq));
+ struct vring_virtqueue *vq = *p_vq = memalign_high(PAGE_SIZE, sizeof(*vq));
if (!vq) {
warn_noalloc();
goto fail;
}
memset(vq, 0, sizeof(*vq));
- /* select the queue */
- outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+ /* select the queue */
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_select, queue_index);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, queue_sel, queue_index);
+ }
/* check if the queue is available */
-
- num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
+ if (vp->use_modern) {
+ num = vp_read(&vp->common, virtio_pci_common_cfg, queue_size);
+ if (num > MAX_QUEUE_NUM) {
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_size,
+ MAX_QUEUE_NUM);
+ num = vp_read(&vp->common, virtio_pci_common_cfg, queue_size);
+ }
+ } else {
+ num = vp_read(&vp->legacy, virtio_pci_legacy, queue_num);
+ }
if (!num) {
dprintf(1, "ERROR: queue size is 0\n");
goto fail;
}
-
if (num > MAX_QUEUE_NUM) {
dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
goto fail;
}
/* check if the queue is already active */
-
- if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
- dprintf(1, "ERROR: queue already active\n");
- goto fail;
+ if (vp->use_modern) {
+ if (vp_read(&vp->common, virtio_pci_common_cfg, queue_enable)) {
+ dprintf(1, "ERROR: queue already active\n");
+ goto fail;
+ }
+ } else {
+ if (vp_read(&vp->legacy, virtio_pci_legacy, queue_pfn)) {
+ dprintf(1, "ERROR: queue already active\n");
+ goto fail;
+ }
}
-
vq->queue_index = queue_index;
/* initialize the queue */
-
struct vring * vr = &vq->vring;
vring_init(vr, num, (unsigned char*)&vq->queue);
@@ -73,9 +179,23 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
* NOTE: vr->desc is initialized by vring_init()
*/
- outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
- ioaddr + VIRTIO_PCI_QUEUE_PFN);
-
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_desc_lo,
+ (unsigned long)virt_to_phys(vr->desc));
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_desc_hi, 0);
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_avail_lo,
+ (unsigned long)virt_to_phys(vr->avail));
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_avail_hi, 0);
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_used_lo,
+ (unsigned long)virt_to_phys(vr->used));
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_used_hi, 0);
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_enable, 1);
+ vq->queue_notify_off = vp_read(&vp->common, virtio_pci_common_cfg,
+ queue_notify_off);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, queue_pfn,
+ (unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT);
+ }
return num;
fail:
@@ -84,14 +204,76 @@ fail:
return -1;
}
-u16 vp_init_simple(u16 bdf)
+void vp_init_simple(struct vp_device *vp, struct pci_device *pci)
{
- u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
- PCI_BASE_ADDRESS_IO_MASK;
+ u8 cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, 0);
+ struct vp_cap *vp_cap;
+ u32 addr, offset, mul;
+ u8 type;
+
+ memset(vp, 0, sizeof(*vp));
+ while (cap != 0) {
+ type = pci_config_readb(pci->bdf, cap +
+ offsetof(struct virtio_pci_cap, cfg_type));
+ switch (type) {
+ case VIRTIO_PCI_CAP_COMMON_CFG:
+ vp_cap = &vp->common;
+ break;
+ case VIRTIO_PCI_CAP_NOTIFY_CFG:
+ vp_cap = &vp->notify;
+ mul = offsetof(struct virtio_pci_notify_cap, notify_off_multiplier);
+ vp->notify_off_multiplier = pci_config_readl(pci->bdf, cap + mul);
+ break;
+ case VIRTIO_PCI_CAP_ISR_CFG:
+ vp_cap = &vp->isr;
+ break;
+ case VIRTIO_PCI_CAP_DEVICE_CFG:
+ vp_cap = &vp->device;
+ break;
+ default:
+ vp_cap = NULL;
+ break;
+ }
+ if (vp_cap && !vp_cap->cap) {
+ vp_cap->cap = cap;
+ vp_cap->bar = pci_config_readb(pci->bdf, cap +
+ offsetof(struct virtio_pci_cap, bar));
+ offset = pci_config_readl(pci->bdf, cap +
+ offsetof(struct virtio_pci_cap, offset));
+ addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0 + 4 * vp_cap->bar);
+ if (addr & PCI_BASE_ADDRESS_SPACE_IO) {
+ vp_cap->is_io = 1;
+ addr &= PCI_BASE_ADDRESS_IO_MASK;
+ } else {
+ vp_cap->is_io = 0;
+ addr &= PCI_BASE_ADDRESS_MEM_MASK;
+ }
+ vp_cap->addr = addr + offset;
+ dprintf(3, "pci dev %x:%x virtio cap at 0x%x type %d "
+ "bar %d at 0x%08x off +0x%04x [%s]\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ vp_cap->cap, type, vp_cap->bar, addr, offset,
+ vp_cap->is_io ? "io" : "mmio");
+ }
+
+ cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, cap);
+ }
+
+ if (vp->common.cap && vp->notify.cap && vp->isr.cap && vp->device.cap) {
+ dprintf(1, "pci dev %x:%x using modern (1.0) virtio mode\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf));
+ vp->use_modern = 1;
+ } else {
+ dprintf(1, "pci dev %x:%x using legacy (0.9.5) virtio mode\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf));
+ vp->legacy.bar = 0;
+ vp->legacy.addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) &
+ PCI_BASE_ADDRESS_IO_MASK;
+ vp->legacy.is_io = 1;
+ }
- vp_reset(ioaddr);
- pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
- vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ vp_reset(vp);
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+ vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER );
- return ioaddr;
}
diff --git a/qemu/roms/seabios/src/hw/virtio-pci.h b/qemu/roms/seabios/src/hw/virtio-pci.h
index bc04b039e..b11c3555e 100644
--- a/qemu/roms/seabios/src/hw/virtio-pci.h
+++ b/qemu/roms/seabios/src/hw/virtio-pci.h
@@ -2,104 +2,210 @@
#define _VIRTIO_PCI_H
#include "x86.h" // inl
-
-/* A 32-bit r/o bitmask of the features supported by the host */
-#define VIRTIO_PCI_HOST_FEATURES 0
-
-/* A 32-bit r/w bitmask of features activated by the guest */
-#define VIRTIO_PCI_GUEST_FEATURES 4
-
-/* A 32-bit r/w PFN for the currently selected queue */
-#define VIRTIO_PCI_QUEUE_PFN 8
-
-/* A 16-bit r/o queue size for the currently selected queue */
-#define VIRTIO_PCI_QUEUE_NUM 12
-
-/* A 16-bit r/w queue selector */
-#define VIRTIO_PCI_QUEUE_SEL 14
-
-/* A 16-bit r/w queue notifier */
-#define VIRTIO_PCI_QUEUE_NOTIFY 16
-
-/* An 8-bit device status register. */
-#define VIRTIO_PCI_STATUS 18
-
-/* An 8-bit r/o interrupt status register. Reading the value will return the
- * current contents of the ISR and will also clear it. This is effectively
- * a read-and-acknowledge. */
-#define VIRTIO_PCI_ISR 19
+#include "biosvar.h" // GET_LOWFLAT
/* The bit of the ISR which indicates a device configuration change. */
#define VIRTIO_PCI_ISR_CONFIG 0x2
-/* The remaining space is defined by each driver as the per-driver
- * configuration space */
-#define VIRTIO_PCI_CONFIG 20
-
/* Virtio ABI version, this must match exactly */
#define VIRTIO_PCI_ABI_VERSION 0
-static inline u32 vp_get_features(unsigned int ioaddr)
-{
- return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
-}
-
-static inline void vp_set_features(unsigned int ioaddr, u32 features)
+/* --- virtio 0.9.5 (legacy) struct --------------------------------- */
+
+typedef struct virtio_pci_legacy {
+ u32 host_features;
+ u32 guest_features;
+ u32 queue_pfn;
+ u16 queue_num;
+ u16 queue_sel;
+ u16 queue_notify;
+ u8 status;
+ u8 isr;
+ u8 device[];
+} virtio_pci_legacy;
+
+/* --- virtio 1.0 (modern) structs ---------------------------------- */
+
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG 1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
+/* ISR access */
+#define VIRTIO_PCI_CAP_ISR_CFG 3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG 4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG 5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+ u8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
+ u8 cap_next; /* Generic PCI field: next ptr. */
+ u8 cap_len; /* Generic PCI field: capability length */
+ u8 cfg_type; /* Identifies the structure. */
+ u8 bar; /* Where to find it. */
+ u8 padding[3]; /* Pad to full dword. */
+ u32 offset; /* Offset within bar. */
+ u32 length; /* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+ struct virtio_pci_cap cap;
+ u32 notify_off_multiplier; /* Multiplier for queue_notify_off. */
+};
+
+typedef struct virtio_pci_common_cfg {
+ /* About the whole device. */
+ u32 device_feature_select; /* read-write */
+ u32 device_feature; /* read-only */
+ u32 guest_feature_select; /* read-write */
+ u32 guest_feature; /* read-write */
+ u16 msix_config; /* read-write */
+ u16 num_queues; /* read-only */
+ u8 device_status; /* read-write */
+ u8 config_generation; /* read-only */
+
+ /* About a specific virtqueue. */
+ u16 queue_select; /* read-write */
+ u16 queue_size; /* read-write, power of 2. */
+ u16 queue_msix_vector; /* read-write */
+ u16 queue_enable; /* read-write */
+ u16 queue_notify_off; /* read-only */
+ u32 queue_desc_lo; /* read-write */
+ u32 queue_desc_hi; /* read-write */
+ u32 queue_avail_lo; /* read-write */
+ u32 queue_avail_hi; /* read-write */
+ u32 queue_used_lo; /* read-write */
+ u32 queue_used_hi; /* read-write */
+} virtio_pci_common_cfg;
+
+typedef struct virtio_pci_isr {
+ u8 isr;
+} virtio_pci_isr;
+
+/* --- driver structs ----------------------------------------------- */
+
+struct vp_cap {
+ u32 addr;
+ u8 cap;
+ u8 bar;
+ u8 is_io;
+};
+
+struct vp_device {
+ struct vp_cap common, notify, isr, device, legacy;
+ u32 notify_off_multiplier;
+ u8 use_modern;
+};
+
+static inline u64 _vp_read(struct vp_cap *cap, u32 offset, u8 size)
{
- outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+ u32 addr = cap->addr + offset;
+ u64 var;
+
+ if (cap->is_io) {
+ switch (size) {
+ case 8:
+ var = inl(addr);
+ var |= (u64)inl(addr+4) << 32;
+ break;
+ case 4:
+ var = inl(addr);
+ break;
+ case 2:
+ var = inw(addr);
+ break;
+ case 1:
+ var = inb(addr);
+ break;
+ default:
+ var = 0;
+ }
+ } else {
+ switch (size) {
+ case 8:
+ var = readl((void*)addr);
+ var |= (u64)readl((void*)(addr+4)) << 32;
+ break;
+ case 4:
+ var = readl((void*)addr);
+ break;
+ case 2:
+ var = readw((void*)addr);
+ break;
+ case 1:
+ var = readb((void*)addr);
+ break;
+ default:
+ var = 0;
+ }
+ }
+ dprintf(9, "vp read %x (%d) -> 0x%llx\n", addr, size, var);
+ return var;
}
-static inline void vp_get(unsigned int ioaddr, unsigned offset,
- void *buf, unsigned len)
+static inline void _vp_write(struct vp_cap *cap, u32 offset, u8 size, u64 var)
{
- u8 *ptr = buf;
- unsigned i;
-
- for (i = 0; i < len; i++)
- ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
+ u32 addr = cap->addr + offset;
+
+ dprintf(9, "vp write %x (%d) <- 0x%llx\n", addr, size, var);
+ if (cap->is_io) {
+ switch (size) {
+ case 4:
+ outl(var, addr);
+ break;
+ case 2:
+ outw(var, addr);
+ break;
+ case 1:
+ outb(var, addr);
+ break;
+ }
+ } else {
+ switch (size) {
+ case 4:
+ writel((void*)addr, var);
+ break;
+ case 2:
+ writew((void*)addr, var);
+ break;
+ case 1:
+ writeb((void*)addr, var);
+ break;
+ }
+ }
}
-static inline u8 vp_get_status(unsigned int ioaddr)
-{
- return inb(ioaddr + VIRTIO_PCI_STATUS);
-}
+#define vp_read(_cap, _struct, _field) \
+ _vp_read(_cap, offsetof(_struct, _field), \
+ sizeof(((_struct *)0)->_field))
-static inline void vp_set_status(unsigned int ioaddr, u8 status)
-{
- if (status == 0) /* reset */
- return;
- outb(status, ioaddr + VIRTIO_PCI_STATUS);
-}
+#define vp_write(_cap, _struct, _field, _var) \
+ _vp_write(_cap, offsetof(_struct, _field), \
+ sizeof(((_struct *)0)->_field), _var)
-static inline u8 vp_get_isr(unsigned int ioaddr)
-{
- return inb(ioaddr + VIRTIO_PCI_ISR);
-}
+u64 vp_get_features(struct vp_device *vp);
+void vp_set_features(struct vp_device *vp, u64 features);
-static inline void vp_reset(unsigned int ioaddr)
+static inline void vp_get_legacy(struct vp_device *vp, unsigned offset,
+ void *buf, unsigned len)
{
- outb(0, ioaddr + VIRTIO_PCI_STATUS);
- (void)inb(ioaddr + VIRTIO_PCI_ISR);
-}
+ u8 *ptr = buf;
+ unsigned i;
-static inline void vp_notify(unsigned int ioaddr, int queue_index)
-{
- outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+ for (i = 0; i < len; i++)
+ ptr[i] = vp_read(&vp->legacy, virtio_pci_legacy, device[i]);
}
-static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
-{
- /* select the queue */
-
- outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
-
- /* deactivate the queue */
-
- outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
-}
+u8 vp_get_status(struct vp_device *vp);
+void vp_set_status(struct vp_device *vp, u8 status);
+u8 vp_get_isr(struct vp_device *vp);
+void vp_reset(struct vp_device *vp);
+struct pci_device;
struct vring_virtqueue;
-u16 vp_init_simple(u16 bdf);
-int vp_find_vq(unsigned int ioaddr, int queue_index,
+void vp_init_simple(struct vp_device *vp, struct pci_device *pci);
+void vp_notify(struct vp_device *vp, struct vring_virtqueue *vq);
+int vp_find_vq(struct vp_device *vp, int queue_index,
struct vring_virtqueue **p_vq);
#endif /* _VIRTIO_PCI_H_ */
diff --git a/qemu/roms/seabios/src/hw/virtio-ring.c b/qemu/roms/seabios/src/hw/virtio-ring.c
index 97e0b3487..7205a0acd 100644
--- a/qemu/roms/seabios/src/hw/virtio-ring.c
+++ b/qemu/roms/seabios/src/hw/virtio-ring.c
@@ -35,8 +35,8 @@
int vring_more_used(struct vring_virtqueue *vq)
{
- struct vring_used *used = GET_LOWFLAT(vq->vring.used);
- int more = GET_LOWFLAT(vq->last_used_idx) != GET_LOWFLAT(used->idx);
+ struct vring_used *used = vq->vring.used;
+ int more = vq->last_used_idx != used->idx;
/* Make sure ring reads are done after idx read above. */
smp_rmb();
return more;
@@ -57,13 +57,13 @@ void vring_detach(struct vring_virtqueue *vq, unsigned int head)
/* find end of given descriptor */
i = head;
- while (GET_LOWFLAT(desc[i].flags) & VRING_DESC_F_NEXT)
- i = GET_LOWFLAT(desc[i].next);
+ while (desc[i].flags & VRING_DESC_F_NEXT)
+ i = desc[i].next;
/* link it with free list and point to it */
- SET_LOWFLAT(desc[i].next, GET_LOWFLAT(vq->free_head));
- SET_LOWFLAT(vq->free_head, head);
+ desc[i].next = vq->free_head;
+ vq->free_head = head;
}
/*
@@ -77,22 +77,22 @@ int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
{
struct vring *vr = &vq->vring;
struct vring_used_elem *elem;
- struct vring_used *used = GET_LOWFLAT(vq->vring.used);
+ struct vring_used *used = vq->vring.used;
u32 id;
int ret;
// BUG_ON(!vring_more_used(vq));
- elem = &used->ring[GET_LOWFLAT(vq->last_used_idx) % GET_LOWFLAT(vr->num)];
- id = GET_LOWFLAT(elem->id);
+ elem = &used->ring[vq->last_used_idx % vr->num];
+ id = elem->id;
if (len != NULL)
- *len = GET_LOWFLAT(elem->len);
+ *len = elem->len;
- ret = GET_LOWFLAT(vq->vdata[id]);
+ ret = vq->vdata[id];
vring_detach(vq, id);
- SET_LOWFLAT(vq->last_used_idx, GET_LOWFLAT(vq->last_used_idx) + 1);
+ vq->last_used_idx = vq->last_used_idx + 1;
return ret;
}
@@ -104,46 +104,45 @@ void vring_add_buf(struct vring_virtqueue *vq,
{
struct vring *vr = &vq->vring;
int i, av, head, prev;
- struct vring_desc *desc = GET_LOWFLAT(vr->desc);
- struct vring_avail *avail = GET_LOWFLAT(vr->avail);
+ struct vring_desc *desc = vr->desc;
+ struct vring_avail *avail = vr->avail;
BUG_ON(out + in == 0);
prev = 0;
- head = GET_LOWFLAT(vq->free_head);
- for (i = head; out; i = GET_LOWFLAT(desc[i].next), out--) {
- SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT);
- SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr));
- SET_LOWFLAT(desc[i].len, list->length);
+ head = vq->free_head;
+ for (i = head; out; i = desc[i].next, out--) {
+ desc[i].flags = VRING_DESC_F_NEXT;
+ desc[i].addr = (u64)virt_to_phys(list->addr);
+ desc[i].len = list->length;
prev = i;
list++;
}
- for ( ; in; i = GET_LOWFLAT(desc[i].next), in--) {
- SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE);
- SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr));
- SET_LOWFLAT(desc[i].len, list->length);
+ for ( ; in; i = desc[i].next, in--) {
+ desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
+ desc[i].addr = (u64)virt_to_phys(list->addr);
+ desc[i].len = list->length;
prev = i;
list++;
}
- SET_LOWFLAT(desc[prev].flags,
- GET_LOWFLAT(desc[prev].flags) & ~VRING_DESC_F_NEXT);
+ desc[prev].flags = desc[prev].flags & ~VRING_DESC_F_NEXT;
- SET_LOWFLAT(vq->free_head, i);
+ vq->free_head = i;
- SET_LOWFLAT(vq->vdata[head], index);
+ vq->vdata[head] = index;
- av = (GET_LOWFLAT(avail->idx) + num_added) % GET_LOWFLAT(vr->num);
- SET_LOWFLAT(avail->ring[av], head);
+ av = (avail->idx + num_added) % vr->num;
+ avail->ring[av] = head;
}
-void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
+void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added)
{
struct vring *vr = &vq->vring;
- struct vring_avail *avail = GET_LOWFLAT(vr->avail);
+ struct vring_avail *avail = vr->avail;
/* Make sure idx update is done after ring write. */
smp_wmb();
- SET_LOWFLAT(avail->idx, GET_LOWFLAT(avail->idx) + num_added);
+ avail->idx = avail->idx + num_added;
- vp_notify(ioaddr, GET_LOWFLAT(vq->queue_index));
+ vp_notify(vp, vq);
}
diff --git a/qemu/roms/seabios/src/hw/virtio-ring.h b/qemu/roms/seabios/src/hw/virtio-ring.h
index b7a7aafb2..7665fd54b 100644
--- a/qemu/roms/seabios/src/hw/virtio-ring.h
+++ b/qemu/roms/seabios/src/hw/virtio-ring.h
@@ -4,15 +4,6 @@
#include "types.h" // u64
#include "memmap.h" // PAGE_SIZE
-#define PAGE_SHIFT 12
-#define PAGE_MASK (PAGE_SIZE-1)
-
-#define virt_to_phys(v) (unsigned long)(v)
-#define phys_to_virt(p) (void*)(p)
-/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-
/* Status byte for guest to report progress, and synchronize features. */
/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
@@ -20,9 +11,14 @@
#define VIRTIO_CONFIG_S_DRIVER 2
/* Driver has used its parts of the config, and is happy */
#define VIRTIO_CONFIG_S_DRIVER_OK 4
+/* Driver has finished configuring features */
+#define VIRTIO_CONFIG_S_FEATURES_OK 8
/* We've given up on this device. */
#define VIRTIO_CONFIG_S_FAILED 0x80
+/* v1.0 compliant. */
+#define VIRTIO_F_VERSION_1 32
+
#define MAX_QUEUE_NUM (128)
#define VRING_DESC_F_NEXT 1
@@ -68,10 +64,9 @@ struct vring {
};
#define vring_size(num) \
- (((((sizeof(struct vring_desc) * num) + \
- (sizeof(struct vring_avail) + sizeof(u16) * num)) \
- + PAGE_MASK) & ~PAGE_MASK) + \
- (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
+ (ALIGN(sizeof(struct vring_desc) * num + sizeof(struct vring_avail) \
+ + sizeof(u16) * num, PAGE_SIZE) \
+ + sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num)
typedef unsigned char virtio_queue_t[vring_size(MAX_QUEUE_NUM)];
@@ -83,6 +78,7 @@ struct vring_virtqueue {
u16 vdata[MAX_QUEUE_NUM];
/* PCI */
int queue_index;
+ int queue_notify_off;
};
struct vring_list {
@@ -90,42 +86,35 @@ struct vring_list {
unsigned int length;
};
-static inline void vring_init(struct vring *vr,
- unsigned int num, unsigned char *queue)
+static inline void
+vring_init(struct vring *vr, unsigned int num, unsigned char *queue)
{
- unsigned int i;
- unsigned long pa;
-
ASSERT32FLAT();
vr->num = num;
/* physical address of desc must be page aligned */
-
- pa = virt_to_phys(queue);
- pa = (pa + PAGE_MASK) & ~PAGE_MASK;
- vr->desc = phys_to_virt(pa);
+ vr->desc = (void*)ALIGN((u32)queue, PAGE_SIZE);
vr->avail = (struct vring_avail *)&vr->desc[num];
/* disable interrupts */
vr->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
/* physical address of used must be page aligned */
+ vr->used = (void*)ALIGN((u32)&vr->avail->ring[num], PAGE_SIZE);
- pa = virt_to_phys(&vr->avail->ring[num]);
- pa = (pa + PAGE_MASK) & ~PAGE_MASK;
- vr->used = phys_to_virt(pa);
-
+ int i;
for (i = 0; i < num - 1; i++)
- vr->desc[i].next = i + 1;
+ vr->desc[i].next = i + 1;
vr->desc[i].next = 0;
}
+struct vp_device;
int vring_more_used(struct vring_virtqueue *vq);
void vring_detach(struct vring_virtqueue *vq, unsigned int head);
int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len);
void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
unsigned int out, unsigned int in,
int index, int num_added);
-void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
+void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added);
#endif /* _VIRTIO_RING_H_ */
diff --git a/qemu/roms/seabios/src/hw/virtio-scsi.c b/qemu/roms/seabios/src/hw/virtio-scsi.c
index 8f966875b..80afd04ca 100644
--- a/qemu/roms/seabios/src/hw/virtio-scsi.c
+++ b/qemu/roms/seabios/src/hw/virtio-scsi.c
@@ -27,35 +27,42 @@ struct virtio_lun_s {
struct drive_s drive;
struct pci_device *pci;
struct vring_virtqueue *vq;
- u16 ioaddr;
+ struct vp_device *vp;
u16 target;
u16 lun;
};
-static int
-virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
- void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+int
+virtio_scsi_process_op(struct disk_op_s *op)
{
+ if (! CONFIG_VIRTIO_SCSI)
+ return 0;
+ struct virtio_lun_s *vlun =
+ container_of(op->drive_gf, struct virtio_lun_s, drive);
+ struct vp_device *vp = vlun->vp;
+ struct vring_virtqueue *vq = vlun->vq;
struct virtio_scsi_req_cmd req;
struct virtio_scsi_resp_cmd resp;
struct vring_list sg[3];
memset(&req, 0, sizeof(req));
+ int blocksize = scsi_fill_cmd(op, req.cdb, 16);
+ if (blocksize < 0)
+ return default_process_op(op);
req.lun[0] = 1;
- req.lun[1] = target;
- req.lun[2] = (lun >> 8) | 0x40;
- req.lun[3] = (lun & 0xff);
- memcpy(req.cdb, cdbcmd, 16);
+ req.lun[1] = vlun->target;
+ req.lun[2] = (vlun->lun >> 8) | 0x40;
+ req.lun[3] = (vlun->lun & 0xff);
u32 len = op->count * blocksize;
- int datain = cdb_is_read(cdbcmd, blocksize);
+ int datain = scsi_is_read(op);
int in_num = (datain ? 2 : 1);
int out_num = (len ? 3 : 2) - in_num;
- sg[0].addr = MAKE_FLATPTR(GET_SEG(SS), &req);
+ sg[0].addr = (void*)(&req);
sg[0].length = sizeof(req);
- sg[out_num].addr = MAKE_FLATPTR(GET_SEG(SS), &resp);
+ sg[out_num].addr = (void*)(&resp);
sg[out_num].length = sizeof(resp);
if (len) {
@@ -66,7 +73,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
/* Add to virtqueue and kick host */
vring_add_buf(vq, sg, out_num, in_num, 0, 0);
- vring_kick(ioaddr, vq, 1);
+ vring_kick(vp, vq, 1);
/* Wait for reply */
while (!vring_more_used(vq))
@@ -78,7 +85,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
/* Clear interrupt status register. Avoid leaving interrupts stuck if
* VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
*/
- vp_get_isr(ioaddr);
+ vp_get_isr(vp);
if (resp.response == VIRTIO_SCSI_S_OK && resp.status == 0) {
return DISK_RET_SUCCESS;
@@ -86,21 +93,8 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
return DISK_RET_EBADTRACK;
}
-int
-virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- struct virtio_lun_s *vlun_gf =
- container_of(op->drive_gf, struct virtio_lun_s, drive);
-
- return virtio_scsi_cmd(GET_GLOBALFLAT(vlun_gf->ioaddr),
- GET_GLOBALFLAT(vlun_gf->vq), op, cdbcmd,
- GET_GLOBALFLAT(vlun_gf->target),
- GET_GLOBALFLAT(vlun_gf->lun),
- blocksize);
-}
-
static int
-virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr,
+virtio_scsi_add_lun(struct pci_device *pci, struct vp_device *vp,
struct vring_virtqueue *vq, u16 target, u16 lun)
{
struct virtio_lun_s *vlun = malloc_fseg(sizeof(*vlun));
@@ -112,7 +106,7 @@ virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr,
vlun->drive.type = DTYPE_VIRTIO_SCSI;
vlun->drive.cntl_id = pci->bdf;
vlun->pci = pci;
- vlun->ioaddr = ioaddr;
+ vlun->vp = vp;
vlun->vq = vq;
vlun->target = target;
vlun->lun = lun;
@@ -129,11 +123,11 @@ fail:
}
static int
-virtio_scsi_scan_target(struct pci_device *pci, u16 ioaddr,
+virtio_scsi_scan_target(struct pci_device *pci, struct vp_device *vp,
struct vring_virtqueue *vq, u16 target)
{
/* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */
- int ret = virtio_scsi_add_lun(pci, ioaddr, vq, target, 0);
+ int ret = virtio_scsi_add_lun(pci, vp, vq, target, 0);
return ret < 0 ? 0 : 1;
}
@@ -144,19 +138,45 @@ init_virtio_scsi(struct pci_device *pci)
dprintf(1, "found virtio-scsi at %x:%x\n", pci_bdf_to_bus(bdf),
pci_bdf_to_dev(bdf));
struct vring_virtqueue *vq = NULL;
- u16 ioaddr = vp_init_simple(bdf);
- if (vp_find_vq(ioaddr, 2, &vq) < 0 ) {
+ struct vp_device *vp = malloc_high(sizeof(*vp));
+ if (!vp) {
+ warn_noalloc();
+ return;
+ }
+ vp_init_simple(vp, pci);
+ u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER;
+
+ if (vp->use_modern) {
+ u64 features = vp_get_features(vp);
+ u64 version1 = 1ull << VIRTIO_F_VERSION_1;
+ if (!(features & version1)) {
+ dprintf(1, "modern device without virtio_1 feature bit: %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+
+ vp_set_features(vp, version1);
+ status |= VIRTIO_CONFIG_S_FEATURES_OK;
+ vp_set_status(vp, status);
+ if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) {
+ dprintf(1, "device didn't accept features: %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+ }
+
+ if (vp_find_vq(vp, 2, &vq) < 0 ) {
dprintf(1, "fail to find vq for virtio-scsi %x:%x\n",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
goto fail;
}
- vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
- VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
+ status |= VIRTIO_CONFIG_S_DRIVER_OK;
+ vp_set_status(vp, status);
int i, tot;
for (tot = 0, i = 0; i < 256; i++)
- tot += virtio_scsi_scan_target(pci, ioaddr, vq, i);
+ tot += virtio_scsi_scan_target(pci, vp, vq, i);
if (!tot)
goto fail;
@@ -164,7 +184,8 @@ init_virtio_scsi(struct pci_device *pci)
return;
fail:
- vp_reset(ioaddr);
+ vp_reset(vp);
+ free(vp);
free(vq);
}
@@ -179,8 +200,9 @@ virtio_scsi_setup(void)
struct pci_device *pci;
foreachpci(pci) {
- if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET
- || pci->device != PCI_DEVICE_ID_VIRTIO_SCSI)
+ if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET ||
+ (pci->device != PCI_DEVICE_ID_VIRTIO_SCSI_09 &&
+ pci->device != PCI_DEVICE_ID_VIRTIO_SCSI_10))
continue;
init_virtio_scsi(pci);
}
diff --git a/qemu/roms/seabios/src/hw/virtio-scsi.h b/qemu/roms/seabios/src/hw/virtio-scsi.h
index 96c3701d2..7532cc98e 100644
--- a/qemu/roms/seabios/src/hw/virtio-scsi.h
+++ b/qemu/roms/seabios/src/hw/virtio-scsi.h
@@ -41,7 +41,7 @@ struct virtio_scsi_resp_cmd {
#define VIRTIO_SCSI_S_OK 0
struct disk_op_s;
-int virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int virtio_scsi_process_op(struct disk_op_s *op);
void virtio_scsi_setup(void);
#endif /* _VIRTIO_SCSI_H */
diff --git a/qemu/roms/seabios/src/list.h b/qemu/roms/seabios/src/list.h
index de656b9d6..94512e306 100644
--- a/qemu/roms/seabios/src/list.h
+++ b/qemu/roms/seabios/src/list.h
@@ -61,6 +61,16 @@ hlist_add_after(struct hlist_node *n, struct hlist_node *prev)
hlist_add(n, &prev->next);
}
+static inline void
+hlist_replace(struct hlist_node *old, struct hlist_node *new)
+{
+ new->next = old->next;
+ if (new->next)
+ new->next->pprev = &new->next;
+ new->pprev = old->pprev;
+ *new->pprev = new;
+}
+
#define hlist_for_each_entry(pos, head, member) \
for (pos = container_of((head)->first, typeof(*pos), member) \
; pos != container_of(NULL, typeof(*pos), member) \
diff --git a/qemu/roms/seabios/src/malloc.c b/qemu/roms/seabios/src/malloc.c
index c4cb17149..3733855ca 100644
--- a/qemu/roms/seabios/src/malloc.c
+++ b/qemu/roms/seabios/src/malloc.c
@@ -6,9 +6,10 @@
#include "biosvar.h" // GET_BDA
#include "config.h" // BUILD_BIOS_ADDR
+#include "e820map.h" // struct e820entry
#include "list.h" // hlist_node
#include "malloc.h" // _malloc
-#include "memmap.h" // struct e820entry
+#include "memmap.h" // PAGE_SIZE
#include "output.h" // dprintf
#include "stacks.h" // wait_preempt
#include "std/optionrom.h" // OPTION_ROM_ALIGN
@@ -17,7 +18,7 @@
// Information on a reserved area.
struct allocinfo_s {
struct hlist_node node;
- void *data, *dataend, *allocend;
+ u32 range_start, range_end, alloc_size;
};
// Information on a tracked memory allocation.
@@ -46,98 +47,106 @@ static struct zone_s *Zones[] VARVERIFY32INIT = {
****************************************************************/
// Find and reserve space from a given zone
-static void *
-allocSpace(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill)
+static u32
+alloc_new(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill)
{
struct allocinfo_s *info;
hlist_for_each_entry(info, &zone->head, node) {
- void *dataend = info->dataend;
- void *allocend = info->allocend;
- void *newallocend = (void*)ALIGN_DOWN((u32)allocend - size, align);
- if (newallocend >= dataend && newallocend <= allocend) {
+ u32 alloc_end = info->range_start + info->alloc_size;
+ u32 range_end = info->range_end;
+ u32 new_range_end = ALIGN_DOWN(range_end - size, align);
+ if (new_range_end >= alloc_end && new_range_end <= range_end) {
// Found space - now reserve it.
- if (!fill)
- fill = newallocend;
- fill->data = newallocend;
- fill->dataend = newallocend + size;
- fill->allocend = allocend;
+ fill->range_start = new_range_end;
+ fill->range_end = range_end;
+ fill->alloc_size = size;
- info->allocend = newallocend;
+ info->range_end = new_range_end;
hlist_add_before(&fill->node, &info->node);
- return newallocend;
+ return new_range_end;
}
}
- return NULL;
+ return 0;
}
-// Release space allocated with allocSpace()
-static void
-freeSpace(struct allocinfo_s *info)
+// Reserve space for a 'struct allocdetail_s' and fill
+static struct allocdetail_s *
+alloc_new_detail(struct allocdetail_s *temp)
{
- struct allocinfo_s *next = container_of_or_null(
- info->node.next, struct allocinfo_s, node);
- if (next && next->allocend == info->data)
- next->allocend = info->allocend;
- hlist_del(&info->node);
+ u32 detail_addr = alloc_new(&ZoneTmpHigh, sizeof(struct allocdetail_s)
+ , MALLOC_MIN_ALIGN, &temp->detailinfo);
+ if (!detail_addr) {
+ detail_addr = alloc_new(&ZoneTmpLow, sizeof(struct allocdetail_s)
+ , MALLOC_MIN_ALIGN, &temp->detailinfo);
+ if (!detail_addr) {
+ warn_noalloc();
+ return NULL;
+ }
+ }
+ struct allocdetail_s *detail = memremap(detail_addr, sizeof(*detail));
+
+ // Fill final 'detail' allocation from data in 'temp'
+ memcpy(detail, temp, sizeof(*detail));
+ hlist_replace(&temp->detailinfo.node, &detail->detailinfo.node);
+ hlist_replace(&temp->datainfo.node, &detail->datainfo.node);
+ return detail;
}
// Add new memory to a zone
static void
-addSpace(struct zone_s *zone, void *start, void *end)
+alloc_add(struct zone_s *zone, u32 start, u32 end)
{
// Find position to add space
struct allocinfo_s *info;
struct hlist_node **pprev;
hlist_for_each_entry_pprev(info, pprev, &zone->head, node) {
- if (info->data < start)
+ if (info->range_start < start)
break;
}
// Add space using temporary allocation info.
struct allocdetail_s tempdetail;
- tempdetail.datainfo.data = tempdetail.datainfo.dataend = start;
- tempdetail.datainfo.allocend = end;
+ tempdetail.handle = MALLOC_DEFAULT_HANDLE;
+ tempdetail.datainfo.range_start = start;
+ tempdetail.datainfo.range_end = end;
+ tempdetail.datainfo.alloc_size = 0;
hlist_add(&tempdetail.datainfo.node, pprev);
// Allocate final allocation info.
- struct allocdetail_s *detail = allocSpace(
- &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
- if (!detail) {
- detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
- , MALLOC_MIN_ALIGN, NULL);
- if (!detail) {
- hlist_del(&tempdetail.datainfo.node);
- warn_noalloc();
- return;
- }
- }
+ struct allocdetail_s *detail = alloc_new_detail(&tempdetail);
+ if (!detail)
+ hlist_del(&tempdetail.datainfo.node);
+}
- // Replace temp alloc space with final alloc space
- pprev = tempdetail.datainfo.node.pprev;
- hlist_del(&tempdetail.datainfo.node);
- memcpy(&detail->datainfo, &tempdetail.datainfo, sizeof(detail->datainfo));
- detail->handle = MALLOC_DEFAULT_HANDLE;
- hlist_add(&detail->datainfo.node, pprev);
+// Release space allocated with alloc_new()
+static void
+alloc_free(struct allocinfo_s *info)
+{
+ struct allocinfo_s *next = container_of_or_null(
+ info->node.next, struct allocinfo_s, node);
+ if (next && next->range_end == info->range_start)
+ next->range_end = info->range_end;
+ hlist_del(&info->node);
}
-// Search all zones for an allocation obtained from allocSpace()
+// Search all zones for an allocation obtained from alloc_new()
static struct allocinfo_s *
-findAlloc(void *data)
+alloc_find(u32 data)
{
int i;
for (i=0; i<ARRAY_SIZE(Zones); i++) {
struct allocinfo_s *info;
hlist_for_each_entry(info, &Zones[i]->head, node) {
- if (info->data == data)
+ if (info->range_start == data)
return info;
}
}
return NULL;
}
-// Return the last sentinal node of a zone
+// Find the lowest memory range added by alloc_add()
static struct allocinfo_s *
-findLast(struct zone_s *zone)
+alloc_find_lowest(struct zone_s *zone)
{
struct allocinfo_s *info, *last = NULL;
hlist_for_each_entry(info, &zone->head, node) {
@@ -171,25 +180,25 @@ relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size)
}
// Support expanding the ZoneLow dynamically.
-static void *
+static u32
zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill)
{
// Make sure to not move ebda while an optionrom is running.
if (unlikely(wait_preempt())) {
- void *data = allocSpace(&ZoneLow, size, align, fill);
+ u32 data = alloc_new(&ZoneLow, size, align, fill);
if (data)
return data;
}
- struct allocinfo_s *info = findLast(&ZoneLow);
+ struct allocinfo_s *info = alloc_find_lowest(&ZoneLow);
if (!info)
- return NULL;
- u32 oldpos = (u32)info->allocend;
+ return 0;
+ u32 oldpos = info->range_end;
u32 newpos = ALIGN_DOWN(oldpos - size, align);
- u32 bottom = (u32)info->dataend;
+ u32 bottom = info->range_start + info->alloc_size;
if (newpos >= bottom && newpos <= oldpos)
// Space already present.
- return allocSpace(&ZoneLow, size, align, fill);
+ return alloc_new(&ZoneLow, size, align, fill);
u16 ebda_seg = get_ebda_seg();
u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0);
u8 ebda_size = GET_EBDA(ebda_seg, size);
@@ -201,21 +210,20 @@ zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill)
u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024);
if (newebda < BUILD_EBDA_MINIMUM)
// Not enough space.
- return NULL;
+ return 0;
// Move ebda
int ret = relocate_ebda(newebda, ebda_pos, ebda_size);
if (ret)
- return NULL;
+ return 0;
// Update zone
- if (ebda_end == bottom) {
- info->data = (void*)newbottom;
- info->dataend = (void*)newbottom;
- } else
- addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end);
+ if (ebda_end == bottom)
+ info->range_start = newbottom;
+ else
+ alloc_add(&ZoneLow, newbottom, ebda_end);
- return allocSpace(&ZoneLow, size, align, fill);
+ return alloc_new(&ZoneLow, size, align, fill);
}
@@ -223,56 +231,69 @@ zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill)
* tracked memory allocations
****************************************************************/
-// Allocate memory from the given zone and track it as a PMM allocation
-void * __malloc
-_malloc(struct zone_s *zone, u32 size, u32 align)
+// Allocate physical memory from the given zone and track it as a PMM allocation
+u32
+malloc_palloc(struct zone_s *zone, u32 size, u32 align)
{
ASSERT32FLAT();
if (!size)
- return NULL;
-
- // Find and reserve space for bookkeeping.
- struct allocdetail_s *detail = allocSpace(
- &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
- if (!detail) {
- detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
- , MALLOC_MIN_ALIGN, NULL);
- if (!detail)
- return NULL;
- }
- detail->handle = MALLOC_DEFAULT_HANDLE;
+ return 0;
// Find and reserve space for main allocation
- void *data = allocSpace(zone, size, align, &detail->datainfo);
+ struct allocdetail_s tempdetail;
+ tempdetail.handle = MALLOC_DEFAULT_HANDLE;
+ u32 data = alloc_new(zone, size, align, &tempdetail.datainfo);
if (!CONFIG_MALLOC_UPPERMEMORY && !data && zone == &ZoneLow)
- data = zonelow_expand(size, align, &detail->datainfo);
- if (!data) {
- freeSpace(&detail->detailinfo);
- return NULL;
+ data = zonelow_expand(size, align, &tempdetail.datainfo);
+ if (!data)
+ return 0;
+
+ // Find and reserve space for bookkeeping.
+ struct allocdetail_s *detail = alloc_new_detail(&tempdetail);
+ if (!detail) {
+ alloc_free(&tempdetail.datainfo);
+ return 0;
}
- dprintf(8, "_malloc zone=%p size=%d align=%x ret=%p (detail=%p)\n"
+ dprintf(8, "phys_alloc zone=%p size=%d align=%x ret=%x (detail=%p)\n"
, zone, size, align, data, detail);
return data;
}
-// Free a data block allocated with _malloc
+// Allocate virtual memory from the given zone
+void * __malloc
+_malloc(struct zone_s *zone, u32 size, u32 align)
+{
+ return memremap(malloc_palloc(zone, size, align), size);
+}
+
+// Free a data block allocated with phys_alloc
int
-_free(void *data)
+malloc_pfree(u32 data)
{
ASSERT32FLAT();
- struct allocinfo_s *info = findAlloc(data);
- if (!info || data == (void*)info || data == info->dataend)
+ struct allocinfo_s *info = alloc_find(data);
+ if (!info || data == virt_to_phys(info) || !info->alloc_size)
return -1;
struct allocdetail_s *detail = container_of(
info, struct allocdetail_s, datainfo);
- dprintf(8, "_free %p (detail=%p)\n", data, detail);
- freeSpace(info);
- freeSpace(&detail->detailinfo);
+ dprintf(8, "phys_free %x (detail=%p)\n", data, detail);
+ alloc_free(info);
+ alloc_free(&detail->detailinfo);
return 0;
}
+void
+free(void *data)
+{
+ if (!data)
+ return;
+ int ret = malloc_pfree(virt_to_phys(data));
+ if (ret)
+ warn_internalerror();
+}
+
// Find the amount of free space in a given zone.
u32
malloc_getspace(struct zone_s *zone)
@@ -282,7 +303,7 @@ malloc_getspace(struct zone_s *zone)
u32 maxspace = 0;
struct allocinfo_s *info;
hlist_for_each_entry(info, &zone->head, node) {
- u32 space = info->allocend - info->dataend;
+ u32 space = info->range_end - info->range_start - info->alloc_size;
if (space > maxspace)
maxspace = space;
}
@@ -298,34 +319,34 @@ malloc_getspace(struct zone_s *zone)
// Set a handle associated with an allocation.
void
-malloc_sethandle(void *data, u32 handle)
+malloc_sethandle(u32 data, u32 handle)
{
ASSERT32FLAT();
- struct allocinfo_s *info = findAlloc(data);
- if (!info || data == (void*)info || data == info->dataend)
+ struct allocinfo_s *info = alloc_find(data);
+ if (!info || data == virt_to_phys(info) || !info->alloc_size)
return;
struct allocdetail_s *detail = container_of(
info, struct allocdetail_s, datainfo);
detail->handle = handle;
}
-// Find the data block allocated with _malloc with a given handle.
-void *
+// Find the data block allocated with phys_alloc with a given handle.
+u32
malloc_findhandle(u32 handle)
{
int i;
for (i=0; i<ARRAY_SIZE(Zones); i++) {
struct allocinfo_s *info;
hlist_for_each_entry(info, &Zones[i]->head, node) {
- if (info->data != (void*)info)
+ if (info->range_start != virt_to_phys(info))
continue;
struct allocdetail_s *detail = container_of(
info, struct allocdetail_s, detailinfo);
if (detail->handle == handle)
- return detail->datainfo.data;
+ return detail->datainfo.range_start;
}
}
- return NULL;
+ return 0;
}
@@ -343,10 +364,9 @@ u32
rom_get_max(void)
{
if (CONFIG_MALLOC_UPPERMEMORY)
- return ALIGN_DOWN((u32)RomBase->allocend - OPROM_HEADER_RESERVE
+ return ALIGN_DOWN(RomBase->range_end - OPROM_HEADER_RESERVE
, OPTION_ROM_ALIGN);
- extern u8 final_readonly_start[];
- return (u32)final_readonly_start;
+ return SYMBOL(final_readonly_start);
}
// Return the end of the last deployed option rom.
@@ -364,9 +384,9 @@ rom_reserve(u32 size)
if (newend > rom_get_max())
return NULL;
if (CONFIG_MALLOC_UPPERMEMORY) {
- if (newend < (u32)zonelow_base)
- newend = (u32)zonelow_base;
- RomBase->data = RomBase->dataend = (void*)newend + OPROM_HEADER_RESERVE;
+ if (newend < SYMBOL(zonelow_base))
+ newend = SYMBOL(zonelow_base);
+ RomBase->range_start = newend + OPROM_HEADER_RESERVE;
}
return (void*)RomEnd;
}
@@ -396,10 +416,10 @@ malloc_preinit(void)
dprintf(3, "malloc preinit\n");
// Don't declare any memory between 0xa0000 and 0x100000
- add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE);
+ e820_remove(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END);
// Mark known areas as reserved.
- add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
+ e820_add(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
// Populate temp high ram
u32 highram = 0;
@@ -419,31 +439,30 @@ malloc_preinit(void)
e = newe;
}
}
- addSpace(&ZoneTmpHigh, (void*)s, (void*)e);
+ alloc_add(&ZoneTmpHigh, s, e);
}
// Populate regions
- addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM);
+ alloc_add(&ZoneTmpLow, BUILD_STACK_ADDR, BUILD_EBDA_MINIMUM);
if (highram) {
- addSpace(&ZoneHigh, (void*)highram
- , (void*)highram + BUILD_MAX_HIGHTABLE);
- add_e820(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED);
+ alloc_add(&ZoneHigh, highram, highram + BUILD_MAX_HIGHTABLE);
+ e820_add(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED);
}
}
void
-csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size)
+malloc_csm_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size)
{
ASSERT32FLAT();
if (hi_pmm_size > BUILD_MAX_HIGHTABLE) {
- void *hi_pmm_end = (void *)hi_pmm + hi_pmm_size;
- addSpace(&ZoneTmpHigh, (void *)hi_pmm, hi_pmm_end - BUILD_MAX_HIGHTABLE);
- addSpace(&ZoneHigh, hi_pmm_end - BUILD_MAX_HIGHTABLE, hi_pmm_end);
+ u32 hi_pmm_end = hi_pmm + hi_pmm_size;
+ alloc_add(&ZoneTmpHigh, hi_pmm, hi_pmm_end - BUILD_MAX_HIGHTABLE);
+ alloc_add(&ZoneHigh, hi_pmm_end - BUILD_MAX_HIGHTABLE, hi_pmm_end);
} else {
- addSpace(&ZoneTmpHigh, (void *)hi_pmm, (void *)hi_pmm + hi_pmm_size);
+ alloc_add(&ZoneTmpHigh, hi_pmm, hi_pmm + hi_pmm_size);
}
- addSpace(&ZoneTmpLow, (void *)low_pmm, (void *)low_pmm + low_pmm_size);
+ alloc_add(&ZoneTmpLow, low_pmm, low_pmm + low_pmm_size);
}
u32 LegacyRamSize VARFSEG;
@@ -484,21 +503,21 @@ malloc_init(void)
}
// Initialize low-memory region
- extern u8 varlow_start[], varlow_end[], final_varlow_start[];
- memmove(final_varlow_start, varlow_start, varlow_end - varlow_start);
+ memmove(VSYMBOL(final_varlow_start), VSYMBOL(varlow_start)
+ , SYMBOL(varlow_end) - SYMBOL(varlow_start));
if (CONFIG_MALLOC_UPPERMEMORY) {
- addSpace(&ZoneLow, zonelow_base + OPROM_HEADER_RESERVE
- , final_varlow_start);
- RomBase = findLast(&ZoneLow);
+ alloc_add(&ZoneLow, SYMBOL(zonelow_base) + OPROM_HEADER_RESERVE
+ , SYMBOL(final_varlow_start));
+ RomBase = alloc_find_lowest(&ZoneLow);
} else {
- addSpace(&ZoneLow, (void*)ALIGN_DOWN((u32)final_varlow_start, 1024)
- , final_varlow_start);
+ alloc_add(&ZoneLow, ALIGN_DOWN(SYMBOL(final_varlow_start), 1024)
+ , SYMBOL(final_varlow_start));
}
// Add space available in f-segment to ZoneFSeg
- extern u8 zonefseg_start[], zonefseg_end[];
- memset(zonefseg_start, 0, zonefseg_end - zonefseg_start);
- addSpace(&ZoneFSeg, zonefseg_start, zonefseg_end);
+ memset(VSYMBOL(zonefseg_start), 0
+ , SYMBOL(zonefseg_end) - SYMBOL(zonefseg_start));
+ alloc_add(&ZoneFSeg, SYMBOL(zonefseg_start), SYMBOL(zonefseg_end));
calcRamSize();
}
@@ -521,19 +540,20 @@ malloc_prepboot(void)
// Reserve more low-mem if needed.
u32 endlow = GET_BDA(mem_size_kb)*1024;
- add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
+ e820_add(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
// Clear unused f-seg ram.
- struct allocinfo_s *info = findLast(&ZoneFSeg);
- memset(info->dataend, 0, info->allocend - info->dataend);
+ struct allocinfo_s *info = alloc_find_lowest(&ZoneFSeg);
+ u32 size = info->range_end - info->range_start;
+ memset(memremap(info->range_start, size), 0, size);
dprintf(1, "Space available for UMB: %x-%x, %x-%x\n"
- , RomEnd, base, (u32)info->dataend, (u32)info->allocend);
+ , RomEnd, base, info->range_start, info->range_end);
// Give back unused high ram.
- info = findLast(&ZoneHigh);
+ info = alloc_find_lowest(&ZoneHigh);
if (info) {
- u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE);
- add_e820((u32)info->dataend, giveback, E820_RAM);
+ u32 giveback = ALIGN_DOWN(info->range_end-info->range_start, PAGE_SIZE);
+ e820_add(info->range_start, giveback, E820_RAM);
dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
}
diff --git a/qemu/roms/seabios/src/malloc.h b/qemu/roms/seabios/src/malloc.h
index 2bcb5bf6d..960a7f800 100644
--- a/qemu/roms/seabios/src/malloc.h
+++ b/qemu/roms/seabios/src/malloc.h
@@ -9,17 +9,19 @@ u32 rom_get_max(void);
u32 rom_get_last(void);
struct rom_header *rom_reserve(u32 size);
int rom_confirm(u32 size);
-void csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm,
+void malloc_csm_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm,
u32 hi_pmm_size);
void malloc_preinit(void);
extern u32 LegacyRamSize;
void malloc_init(void);
void malloc_prepboot(void);
+u32 malloc_palloc(struct zone_s *zone, u32 size, u32 align);
void *_malloc(struct zone_s *zone, u32 size, u32 align);
-int _free(void *data);
+int malloc_pfree(u32 data);
+void free(void *data);
u32 malloc_getspace(struct zone_s *zone);
-void malloc_sethandle(void *data, u32 handle);
-void *malloc_findhandle(u32 handle);
+void malloc_sethandle(u32 data, u32 handle);
+u32 malloc_findhandle(u32 handle);
#define MALLOC_DEFAULT_HANDLE 0xFFFFFFFF
// Minimum alignment of malloc'd memory
@@ -64,8 +66,5 @@ static inline void *memalign_tmp(u32 align, u32 size) {
return ret;
return memalign_tmplow(align, size);
}
-static inline void free(void *data) {
- _free(data);
-}
#endif // malloc.h
diff --git a/qemu/roms/seabios/src/memmap.h b/qemu/roms/seabios/src/memmap.h
index 7bda56e2b..22bd4bcb8 100644
--- a/qemu/roms/seabios/src/memmap.h
+++ b/qemu/roms/seabios/src/memmap.h
@@ -1,29 +1,21 @@
-#ifndef __E820MAP_H
-#define __E820MAP_H
+#ifndef __MEMMAP_H
+#define __MEMMAP_H
-#include "types.h" // u64
-
-#define E820_RAM 1
-#define E820_RESERVED 2
-#define E820_ACPI 3
-#define E820_NVS 4
-#define E820_UNUSABLE 5
-#define E820_HOLE ((u32)-1) // Useful for removing entries
-
-struct e820entry {
- u64 start;
- u64 size;
- u32 type;
-};
-
-void add_e820(u64 start, u64 size, u32 type);
-void memmap_prepboot(void);
+#include "types.h" // u32
// A typical OS page size
#define PAGE_SIZE 4096
+#define PAGE_SHIFT 12
+
+static inline u32 virt_to_phys(void *v) {
+ return (u32)v;
+}
+static inline void *memremap(u32 addr, u32 len) {
+ return (void*)addr;
+}
-// e820 map storage
-extern struct e820entry e820_list[];
-extern int e820_count;
+// Return the value of a linker script symbol (see scripts/layoutrom.py)
+#define SYMBOL(SYM) ({ extern char SYM; (u32)&SYM; })
+#define VSYMBOL(SYM) ((void*)SYMBOL(SYM))
-#endif // e820map.h
+#endif // memmap.h
diff --git a/qemu/roms/seabios/src/misc.c b/qemu/roms/seabios/src/misc.c
index 8caaf31d8..f02237c36 100644
--- a/qemu/roms/seabios/src/misc.c
+++ b/qemu/roms/seabios/src/misc.c
@@ -56,7 +56,7 @@ void VISIBLE16
handle_10(struct bregs *regs)
{
debug_enter(regs, DEBUG_HDL_10);
- // dont do anything, since the VGA BIOS handles int10h requests
+ // don't do anything, since the VGA BIOS handles int10h requests
}
// NMI handler
diff --git a/qemu/roms/seabios/src/mouse.c b/qemu/roms/seabios/src/mouse.c
index 6d1f5b77e..b7ad7c62a 100644
--- a/qemu/roms/seabios/src/mouse.c
+++ b/qemu/roms/seabios/src/mouse.c
@@ -280,8 +280,7 @@ invoke_mouse_handler(void)
if (!CONFIG_MOUSE)
return;
if (need_hop_back()) {
- extern void _cfunc16_invoke_mouse_handler(void);
- stack_hop_back(0, 0, _cfunc16_invoke_mouse_handler);
+ stack_hop_back(invoke_mouse_handler, 0, 0);
return;
}
ASSERT16();
diff --git a/qemu/roms/seabios/src/optionroms.c b/qemu/roms/seabios/src/optionroms.c
index 93d9d2fe6..c81eff2d2 100644
--- a/qemu/roms/seabios/src/optionroms.c
+++ b/qemu/roms/seabios/src/optionroms.c
@@ -19,6 +19,9 @@
#include "std/pnpbios.h" // PNP_SIGNATURE
#include "string.h" // memset
#include "util.h" // get_pnp_offset
+#include "tcgbios.h" // tpm_*
+
+static int EnforceChecksum, S3ResumeVga, RunPCIroms;
/****************************************************************
@@ -60,8 +63,6 @@ call_bcv(u16 seg, u16 ip)
__callrom(MAKE_FLATPTR(seg, 0), ip, 0);
}
-static int EnforceChecksum;
-
// Verify that an option rom looks valid
static int
is_valid_rom(struct rom_header *rom)
@@ -132,6 +133,8 @@ init_optionrom(struct rom_header *rom, u16 bdf, int isvga)
if (newrom != rom)
memmove(newrom, rom, rom->size * 512);
+ tpm_option_rom(newrom, rom->size * 512);
+
if (isvga || get_pnp_rom(newrom))
// Only init vga and PnP roms here.
callrom(newrom, bdf);
@@ -180,19 +183,6 @@ deploy_romfile(struct romfile_s *file)
return rom;
}
-// Check if an option rom is at a hardcoded location or in CBFS.
-static struct rom_header *
-lookup_hardcode(struct pci_device *pci)
-{
- char fname[17];
- snprintf(fname, sizeof(fname), "pci%04x,%04x.rom"
- , pci->vendor, pci->device);
- struct romfile_s *file = romfile_find(fname);
- if (file)
- return deploy_romfile(file);
- return NULL;
-}
-
// Run all roms in a given CBFS directory.
static void
run_file_roms(const char *prefix, int isvga, u64 *sources)
@@ -321,21 +311,28 @@ fail:
}
// Attempt to map and initialize the option rom on a given PCI device.
-static int
+static void
init_pcirom(struct pci_device *pci, int isvga, u64 *sources)
{
u16 bdf = pci->bdf;
dprintf(4, "Attempting to init PCI bdf %02x:%02x.%x (vd %04x:%04x)\n"
, pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)
, pci->vendor, pci->device);
- struct rom_header *rom = lookup_hardcode(pci);
- if (! rom)
+
+ char fname[17];
+ snprintf(fname, sizeof(fname), "pci%04x,%04x.rom"
+ , pci->vendor, pci->device);
+ struct romfile_s *file = romfile_find(fname);
+ struct rom_header *rom = NULL;
+ if (file)
+ rom = deploy_romfile(file);
+ else if (RunPCIroms > 1 || (RunPCIroms == 1 && isvga))
rom = map_pcirom(pci);
if (! rom)
// No ROM present.
- return -1;
+ return;
setRomSource(sources, rom, RS_PCIROM | (u32)pci);
- return init_optionrom(rom, bdf, isvga);
+ init_optionrom(rom, bdf, isvga);
}
@@ -416,7 +413,6 @@ optionrom_setup(void)
* VGA init
****************************************************************/
-static int S3ResumeVga;
int ScreenAndDebug;
struct rom_header *VgaROM;
@@ -432,6 +428,7 @@ vgarom_setup(void)
// Load some config settings that impact VGA.
EnforceChecksum = romfile_loadint("etc/optionroms-checksum", 1);
S3ResumeVga = romfile_loadint("etc/s3-resume-vga-init", CONFIG_QEMU);
+ RunPCIroms = romfile_loadint("etc/pci-optionrom-exec", 2);
ScreenAndDebug = romfile_loadint("etc/screen-and-debug", 1);
if (CONFIG_OPTIONROMS_DEPLOYED) {
diff --git a/qemu/roms/seabios/src/output.c b/qemu/roms/seabios/src/output.c
index 45397b3f6..8a883889c 100644
--- a/qemu/roms/seabios/src/output.c
+++ b/qemu/roms/seabios/src/output.c
@@ -30,6 +30,7 @@ void
debug_banner(void)
{
dprintf(1, "SeaBIOS (version %s)\n", VERSION);
+ dprintf(1, "BUILD: %s\n", BUILDINFO);
}
// Write a character to debug port(s).
diff --git a/qemu/roms/seabios/src/pmm.c b/qemu/roms/seabios/src/pmm.c
index 304faab2c..640341472 100644
--- a/qemu/roms/seabios/src/pmm.c
+++ b/qemu/roms/seabios/src/pmm.c
@@ -65,26 +65,26 @@ handle_pmm00(u16 *args)
if (align < MALLOC_MIN_ALIGN)
align = MALLOC_MIN_ALIGN;
}
- void *data;
+ u32 data;
switch (flags & 3) {
default:
case 0:
return 0;
case 1:
- data = _malloc(lowzone, size, align);
+ data = malloc_palloc(lowzone, size, align);
break;
case 2:
- data = _malloc(highzone, size, align);
+ data = malloc_palloc(highzone, size, align);
break;
case 3: {
- data = _malloc(lowzone, size, align);
+ data = malloc_palloc(lowzone, size, align);
if (!data)
- data = _malloc(highzone, size, align);
+ data = malloc_palloc(highzone, size, align);
}
}
if (data && handle != MALLOC_DEFAULT_HANDLE)
malloc_sethandle(data, handle);
- return (u32)data;
+ return data;
}
// PMM - find
@@ -95,7 +95,7 @@ handle_pmm01(u16 *args)
dprintf(3, "pmm01: handle=%x\n", handle);
if (handle == MALLOC_DEFAULT_HANDLE)
return 0;
- return (u32)malloc_findhandle(handle);
+ return malloc_findhandle(handle);
}
// PMM - deallocate
@@ -104,7 +104,7 @@ handle_pmm02(u16 *args)
{
u32 buffer = *(u32*)&args[1];
dprintf(3, "pmm02: buffer=%x\n", buffer);
- int ret = _free((void*)buffer);
+ int ret = malloc_pfree(buffer);
if (ret)
// Error
return 1;
diff --git a/qemu/roms/seabios/src/post.c b/qemu/roms/seabios/src/post.c
index 9ea5620c9..49c22b875 100644
--- a/qemu/roms/seabios/src/post.c
+++ b/qemu/roms/seabios/src/post.c
@@ -8,6 +8,7 @@
#include "biosvar.h" // SET_BDA
#include "bregs.h" // struct bregs
#include "config.h" // CONFIG_*
+#include "e820map.h" // e820_add
#include "fw/paravirt.h" // qemu_cfg_preinit
#include "fw/xen.h" // xen_preinit
#include "hw/ahci.h" // ahci_setup
@@ -24,10 +25,11 @@
#include "hw/virtio-blk.h" // virtio_blk_setup
#include "hw/virtio-scsi.h" // virtio_scsi_setup
#include "malloc.h" // malloc_init
-#include "memmap.h" // add_e820
+#include "memmap.h" // SYMBOL
#include "output.h" // dprintf
#include "string.h" // memset
#include "util.h" // kbd_init
+#include "tcgbios.h" // tpm_*
/****************************************************************
@@ -88,9 +90,8 @@ bda_init(void)
int esize = EBDA_SIZE_START;
u16 ebda_seg = EBDA_SEGMENT_START;
- extern u8 final_varlow_start[];
if (!CONFIG_MALLOC_UPPERMEMORY)
- ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN((u32)final_varlow_start, 1024)
+ ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN(SYMBOL(final_varlow_start), 1024)
- EBDA_SIZE_START*1024);
SET_BDA(ebda_seg, ebda_seg);
@@ -101,10 +102,10 @@ bda_init(void)
memset(ebda, 0, sizeof(*ebda));
ebda->size = esize;
- add_e820((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED);
+ e820_add((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED);
// Init extra stack
- StackPos = (void*)(&ExtraStack[BUILD_EXTRA_STACK_SIZE] - zonelow_base);
+ StackPos = &ExtraStack[BUILD_EXTRA_STACK_SIZE] - SYMBOL(zonelow_base);
}
void
@@ -116,13 +117,13 @@ interface_init(void)
// Setup romfile items.
qemu_cfg_init();
coreboot_cbfs_init();
+ multiboot_init();
// Setup ivt/bda/ebda
ivt_init();
bda_init();
// Other interfaces
- thread_init();
boot_init();
bios32_init();
pmm_init();
@@ -157,26 +158,32 @@ device_hardware_setup(void)
static void
platform_hardware_setup(void)
{
- // Enable CPU caching
- setcr0(getcr0() & ~(CR0_CD|CR0_NW));
-
// Make sure legacy DMA isn't running.
dma_setup();
// Init base pc hardware.
pic_setup();
+ thread_setup();
mathcp_setup();
- timer_setup();
- clock_setup();
// Platform specific setup
qemu_platform_setup();
coreboot_platform_setup();
+
+ // Setup timers and periodic clock interrupt
+ timer_setup();
+ clock_setup();
+
+ // Initialize TPM
+ tpm_setup();
}
void
prepareboot(void)
{
+ // Change TPM phys. presence state befor leaving BIOS
+ tpm_prepboot();
+
// Run BCVs
bcv_prepboot();
@@ -184,7 +191,7 @@ prepareboot(void)
cdrom_prepboot();
pmm_prepboot();
malloc_prepboot();
- memmap_prepboot();
+ e820_prepboot();
HaveRunPost = 2;
@@ -269,30 +276,27 @@ reloc_preinit(void *f, void *arg)
void (*func)(void *) __noreturn = f;
if (!CONFIG_RELOCATE_INIT)
func(arg);
- // Symbols populated by the build.
- extern u8 code32flat_start[];
- extern u8 _reloc_min_align;
- extern u32 _reloc_abs_start[], _reloc_abs_end[];
- extern u32 _reloc_rel_start[], _reloc_rel_end[];
- extern u32 _reloc_init_start[], _reloc_init_end[];
- extern u8 code32init_start[], code32init_end[];
// Allocate space for init code.
- u32 initsize = code32init_end - code32init_start;
- u32 codealign = (u32)&_reloc_min_align;
+ u32 initsize = SYMBOL(code32init_end) - SYMBOL(code32init_start);
+ u32 codealign = SYMBOL(_reloc_min_align);
void *codedest = memalign_tmp(codealign, initsize);
+ void *codesrc = VSYMBOL(code32init_start);
if (!codedest)
panic("No space for init relocation.\n");
// Copy code and update relocs (init absolute, init relative, and runtime)
dprintf(1, "Relocating init from %p to %p (size %d)\n"
- , code32init_start, codedest, initsize);
- s32 delta = codedest - (void*)code32init_start;
- memcpy(codedest, code32init_start, initsize);
- updateRelocs(codedest, _reloc_abs_start, _reloc_abs_end, delta);
- updateRelocs(codedest, _reloc_rel_start, _reloc_rel_end, -delta);
- updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta);
- if (f >= (void*)code32init_start && f < (void*)code32init_end)
+ , codesrc, codedest, initsize);
+ s32 delta = codedest - codesrc;
+ memcpy(codedest, codesrc, initsize);
+ updateRelocs(codedest, VSYMBOL(_reloc_abs_start), VSYMBOL(_reloc_abs_end)
+ , delta);
+ updateRelocs(codedest, VSYMBOL(_reloc_rel_start), VSYMBOL(_reloc_rel_end)
+ , -delta);
+ updateRelocs(VSYMBOL(code32flat_start), VSYMBOL(_reloc_init_start)
+ , VSYMBOL(_reloc_init_end), delta);
+ if (f >= codesrc && f < VSYMBOL(code32init_end))
func = f + delta;
// Call function in relocated code.
diff --git a/qemu/roms/seabios/src/resume.c b/qemu/roms/seabios/src/resume.c
index 19031747c..a5465d877 100644
--- a/qemu/roms/seabios/src/resume.c
+++ b/qemu/roms/seabios/src/resume.c
@@ -16,6 +16,7 @@
#include "std/bda.h" // struct bios_data_area_s
#include "string.h" // memset
#include "util.h" // dma_setup
+#include "tcgbios.h" // tpm_s3_resume
// Handler for post calls that look like a resume.
void VISIBLE16
@@ -99,6 +100,8 @@ s3_resume(void)
pci_resume();
+ /* resume TPM before we may measure option roms */
+ tpm_s3_resume();
s3_resume_vga();
make_bios_readonly();
diff --git a/qemu/roms/seabios/src/romlayout.S b/qemu/roms/seabios/src/romlayout.S
index 93b6874e7..53cc0f5e3 100644
--- a/qemu/roms/seabios/src/romlayout.S
+++ b/qemu/roms/seabios/src/romlayout.S
@@ -22,18 +22,14 @@
// %edx = return location (in 32bit mode)
// Clobbers: ecx, flags, segment registers, cr0, idt/gdt
DECLFUNC transition32
-transition32_nmi_off:
- // transition32 when NMI and A20 are already initialized
- movl %eax, %ecx
- jmp 1f
+ .global transition32_nmi_off
transition32:
- movl %eax, %ecx
-
// Disable irqs (and clear direction flag)
cli
cld
// Disable nmi
+ movl %eax, %ecx
movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax
outb %al, $PORT_CMOS_INDEX
inb $PORT_CMOS_DATA, %al
@@ -42,29 +38,31 @@ transition32:
inb $PORT_A20, %al
orb $A20_ENABLE_BIT, %al
outb %al, $PORT_A20
+ movl %ecx, %eax
+transition32_nmi_off:
// Set segment descriptors
-1: lidtw %cs:pmode_IDT_info
+ lidtw %cs:pmode_IDT_info
lgdtw %cs:rombios32_gdt_48
// Enable protected mode
- movl %cr0, %eax
- orl $CR0_PE, %eax
- movl %eax, %cr0
+ movl %cr0, %ecx
+ andl $~(CR0_PG|CR0_CD|CR0_NW), %ecx
+ orl $CR0_PE, %ecx
+ movl %ecx, %cr0
// start 32bit protected mode code
- ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 2f)
+ ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f)
.code32
// init data segments
-2: movl $SEG32_MODE32_DS, %eax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw %ax, %fs
- movw %ax, %gs
+1: movl $SEG32_MODE32_DS, %ecx
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+ movw %cx, %fs
+ movw %cx, %gs
- movl %ecx, %eax
jmpl *%edx
.code16
@@ -75,61 +73,47 @@ transition32:
.global transition16big
.code32
transition16:
- movl %eax, %ecx
-
- // restore data segment limits to 0xffff
- movl $SEG32_MODE16_DS, %eax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw %ax, %fs
- movw %ax, %gs
-
-#if CONFIG_DISABLE_A20
- // disable a20
- inb $PORT_A20, %al
- andb $~A20_ENABLE_BIT, %al
- outb %al, $PORT_A20
-#endif
+ // Reset data segment limits
+ movl $SEG32_MODE16_DS, %ecx
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+ movw %cx, %fs
+ movw %cx, %gs
// Jump to 16bit mode
ljmpw $SEG32_MODE16_CS, $1f
transition16big:
- movl %eax, %ecx
-
- movl $SEG32_MODE16BIG_DS, %eax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw %ax, %fs
- movw %ax, %gs
+ movl $SEG32_MODE16BIG_DS, %ecx
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+ movw %cx, %fs
+ movw %cx, %gs
ljmpw $SEG32_MODE16BIG_CS, $1f
.code16
-1:
// Disable protected mode
- movl %cr0, %eax
- andl $~CR0_PE, %eax
- movl %eax, %cr0
+1: movl %cr0, %ecx
+ andl $~CR0_PE, %ecx
+ movl %ecx, %cr0
// far jump to flush CPU queue after transition to real mode
ljmpw $SEG_BIOS, $2f
-2:
// restore IDT to normal real-mode defaults
- lidtw %cs:rmode_IDT_info
+2: lidtw %cs:rmode_IDT_info
// Clear segment registers
- xorw %ax, %ax
- movw %ax, %fs
- movw %ax, %gs
- movw %ax, %es
- movw %ax, %ds
- movw %ax, %ss // Assume stack is in segment 0
+ xorw %cx, %cx
+ movw %cx, %fs
+ movw %cx, %gs
+ movw %cx, %es
+ movw %cx, %ds
+ movw %cx, %ss // Assume stack is in segment 0
- movl %ecx, %eax
jmpl *%edx
@@ -264,7 +248,7 @@ entry_pmm:
movl $_cfunc32flat_handle_pmm, %eax // Setup: call32(handle_pmm, args, -1)
leal PUSHBREGS_size+12(%esp, %ecx), %edx // %edx points to start of args
movl $-1, %ecx
- calll call32
+ calll __call32
movw %ax, BREGS_eax(%esp) // Modify %ax:%dx to return %eax
shrl $16, %eax
movw %ax, BREGS_edx(%esp)
@@ -374,6 +358,8 @@ entry_bios32:
entry_elf:
cli
cld
+ movl %eax, entry_elf_eax
+ movl %ebx, entry_elf_ebx
lidtl (BUILD_BIOS_ADDR + pmode_IDT_info)
lgdtl (BUILD_BIOS_ADDR + rombios32_gdt_48)
movl $SEG32_MODE32_DS, %eax
@@ -562,7 +548,10 @@ entry_post:
ENTRY_INTO32 _cfunc32flat_handle_post // Normal entry point
ORG 0xe2c3
- IRQ_ENTRY 02
+ .global entry_02
+entry_02:
+ ENTRY handle_02 // NMI handler does not switch onto extra stack
+ iretw
ORG 0xe3fe
.global entry_13_official
diff --git a/qemu/roms/seabios/src/sha1.c b/qemu/roms/seabios/src/sha1.c
new file mode 100644
index 000000000..2ecb3cb89
--- /dev/null
+++ b/qemu/roms/seabios/src/sha1.c
@@ -0,0 +1,147 @@
+// Support for Calculation of SHA1 in SW
+//
+// Copyright (C) 2006-2011 IBM Corporation
+//
+// Authors:
+// Stefan Berger <stefanb@linux.vnet.ibm.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+//
+// See: http://www.itl.nist.gov/fipspubs/fip180-1.htm
+// RFC3174, Wikipedia's SHA1 alogrithm description
+//
+
+#include "config.h"
+#include "byteorder.h" // cpu_to_*, __swab64
+#include "sha1.h" // sha1
+#include "string.h" // memcpy
+#include "x86.h" // rol
+
+typedef struct _sha1_ctx {
+ u32 h[5];
+} sha1_ctx;
+
+
+static void
+sha1_block(u32 *w, sha1_ctx *ctx)
+{
+ u32 i;
+ u32 a,b,c,d,e,f;
+ u32 tmp;
+ u32 idx;
+
+ static const u32 sha_ko[4] = {
+ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
+
+ /* change endianness of given data */
+ for (i = 0; i < 16; i++)
+ w[i] = be32_to_cpu(w[i]);
+
+ for (i = 16; i <= 79; i++) {
+ tmp = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16];
+ w[i] = rol(tmp,1);
+ }
+
+ a = ctx->h[0];
+ b = ctx->h[1];
+ c = ctx->h[2];
+ d = ctx->h[3];
+ e = ctx->h[4];
+
+ for (i = 0; i <= 79; i++) {
+ if (i <= 19) {
+ f = (b & c) | ((b ^ 0xffffffff) & d);
+ idx = 0;
+ } else if (i <= 39) {
+ f = b ^ c ^ d;
+ idx = 1;
+ } else if (i <= 59) {
+ f = (b & c) | (b & d) | (c & d);
+ idx = 2;
+ } else {
+ f = b ^ c ^ d;
+ idx = 3;
+ }
+
+ tmp = rol(a, 5) +
+ f +
+ e +
+ sha_ko[idx] +
+ w[i];
+ e = d;
+ d = c;
+ c = rol(b, 30);
+ b = a;
+ a = tmp;
+ }
+
+ ctx->h[0] += a;
+ ctx->h[1] += b;
+ ctx->h[2] += c;
+ ctx->h[3] += d;
+ ctx->h[4] += e;
+}
+
+
+static void
+sha1_do(sha1_ctx *ctx, const u8 *data32, u32 length)
+{
+ u32 offset;
+ u16 num;
+ u32 bits = 0;
+ u32 w[80];
+ u64 tmp;
+
+ /* treat data in 64-byte chunks */
+ for (offset = 0; length - offset >= 64; offset += 64) {
+ memcpy(w, data32 + offset, 64);
+ sha1_block((u32 *)w, ctx);
+ bits += (64 * 8);
+ }
+
+ /* last block with less than 64 bytes */
+ num = length - offset;
+ bits += (num << 3);
+
+ memcpy(w, data32 + offset, num);
+ ((u8 *)w)[num] = 0x80;
+ if (64 - (num + 1) > 0)
+ memset( &((u8 *)w)[num + 1], 0x0, 64 - (num + 1));
+
+ if (num >= 56) {
+ /* cannot append number of bits here */
+ sha1_block((u32 *)w, ctx);
+ memset(w, 0x0, 60);
+ }
+
+ /* write number of bits to end of block */
+ tmp = __swab64(bits);
+ memcpy(&w[14], &tmp, 8);
+
+ sha1_block(w, ctx);
+
+ /* need to switch result's endianness */
+ for (num = 0; num < 5; num++)
+ ctx->h[num] = cpu_to_be32(ctx->h[num]);
+}
+
+
+u32
+sha1(const u8 *data, u32 length, u8 *hash)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ sha1_ctx ctx = {
+ .h[0] = 0x67452301,
+ .h[1] = 0xefcdab89,
+ .h[2] = 0x98badcfe,
+ .h[3] = 0x10325476,
+ .h[4] = 0xc3d2e1f0,
+ };
+
+ sha1_do(&ctx, data, length);
+ memcpy(hash, &ctx.h[0], 20);
+
+ return 0;
+}
diff --git a/qemu/roms/seabios/src/sha1.h b/qemu/roms/seabios/src/sha1.h
new file mode 100644
index 000000000..07aabf34f
--- /dev/null
+++ b/qemu/roms/seabios/src/sha1.h
@@ -0,0 +1,8 @@
+#ifndef __SHA1_H
+#define __SHA1_H
+
+#include "types.h" // u32
+
+u32 sha1(const u8 *data, u32 length, u8 *hash);
+
+#endif // sha1.h
diff --git a/qemu/roms/seabios/src/stacks.c b/qemu/roms/seabios/src/stacks.c
index 1dbdfe9bb..ef6a70775 100644
--- a/qemu/roms/seabios/src/stacks.c
+++ b/qemu/roms/seabios/src/stacks.c
@@ -1,6 +1,6 @@
// Code for manipulating stack locations.
//
-// Copyright (C) 2009-2014 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2009-2015 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -13,6 +13,7 @@
#include "output.h" // dprintf
#include "romfile.h" // romfile_loadint
#include "stacks.h" // struct mutex_s
+#include "string.h" // memset
#include "util.h" // useRTC
#define MAIN_STACK_MAX (1024*1024)
@@ -27,40 +28,108 @@ struct {
u8 cmosindex;
u8 a20;
u16 ss, fs, gs;
+ u32 cr0;
struct descloc_s gdt;
-} Call32Data VARLOW;
+} Call16Data VARLOW;
-#define C32_SLOPPY 1
-#define C32_SMM 2
+#define C16_BIG 1
+#define C16_SMM 2
int HaveSmmCall32 VARFSEG;
-// Backup state in preparation for call32_smm()
-static void
-call32_smm_prep(void)
-{
+// Backup state in preparation for call32
+static int
+call32_prep(u8 method)
+{
+ if (!CONFIG_CALL32_SMM || method != C16_SMM) {
+ // Backup cr0
+ u32 cr0 = cr0_read();
+ if (cr0 & CR0_PE)
+ // Called in 16bit protected mode?!
+ return -1;
+ SET_LOW(Call16Data.cr0, cr0);
+
+ // Backup fs/gs and gdt
+ SET_LOW(Call16Data.fs, GET_SEG(FS));
+ SET_LOW(Call16Data.gs, GET_SEG(GS));
+ struct descloc_s gdt;
+ sgdt(&gdt);
+ SET_LOW(Call16Data.gdt.length, gdt.length);
+ SET_LOW(Call16Data.gdt.addr, gdt.addr);
+
+ // Enable a20 and backup its previous state
+ SET_LOW(Call16Data.a20, set_a20(1));
+ }
+
+ // Backup ss
+ SET_LOW(Call16Data.ss, GET_SEG(SS));
+
// Backup cmos index register and disable nmi
u8 cmosindex = inb(PORT_CMOS_INDEX);
outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
inb(PORT_CMOS_DATA);
- SET_LOW(Call32Data.cmosindex, cmosindex);
-
- // Backup ss
- SET_LOW(Call32Data.ss, GET_SEG(SS));
+ SET_LOW(Call16Data.cmosindex, cmosindex);
- SET_LOW(Call32Data.method, C32_SMM);
+ SET_LOW(Call16Data.method, method);
+ return 0;
}
-// Restore state backed up during call32_smm()
-static void
-call32_smm_post(void)
+// Restore state backed up during call32
+static u8
+call32_post(void)
{
- SET_LOW(Call32Data.method, 0);
- SET_LOW(Call32Data.ss, 0);
+ u8 method = GET_LOW(Call16Data.method);
+ SET_LOW(Call16Data.method, 0);
+ SET_LOW(Call16Data.ss, 0);
+
+ if (!CONFIG_CALL32_SMM || method != C16_SMM) {
+ // Restore a20
+ set_a20(GET_LOW(Call16Data.a20));
+
+ // Restore gdt and fs/gs
+ struct descloc_s gdt;
+ gdt.length = GET_LOW(Call16Data.gdt.length);
+ gdt.addr = GET_LOW(Call16Data.gdt.addr);
+ lgdt(&gdt);
+ SET_SEG(FS, GET_LOW(Call16Data.fs));
+ SET_SEG(GS, GET_LOW(Call16Data.gs));
+
+ // Restore cr0
+ u32 cr0_caching = GET_LOW(Call16Data.cr0) & (CR0_CD|CR0_NW);
+ if (cr0_caching)
+ cr0_mask(CR0_CD|CR0_NW, cr0_caching);
+ }
// Restore cmos index register
- outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX);
+ outb(GET_LOW(Call16Data.cmosindex), PORT_CMOS_INDEX);
inb(PORT_CMOS_DATA);
+ return method;
+}
+
+// Force next call16() to restore to a pristine cpu environment state
+static void
+call16_override(int big)
+{
+ ASSERT32FLAT();
+ if (getesp() > BUILD_STACK_ADDR)
+ panic("call16_override with invalid stack\n");
+ memset(&Call16Data, 0, sizeof(Call16Data));
+ if (big) {
+ Call16Data.method = C16_BIG;
+ Call16Data.a20 = 1;
+ } else {
+ Call16Data.a20 = !CONFIG_DISABLE_A20;
+ }
+}
+
+// 16bit handler code called from call16() / call16_smm()
+u32 VISIBLE16
+call16_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx))
+{
+ u8 method = call32_post();
+ u32 ret = func(eax, edx);
+ call32_prep(method);
+ return ret;
}
#define ASM32_SWITCH16 " .pushsection .text.32fseg." UNIQSEC "\n .code16\n"
@@ -74,7 +143,7 @@ call32_smm(void *func, u32 eax)
{
ASSERT16();
dprintf(9, "call32_smm %p %x\n", func, eax);
- call32_smm_prep();
+ call32_prep(C16_SMM);
u32 bkup_esp;
asm volatile(
// Backup esp / set esp to flat stack location
@@ -109,24 +178,12 @@ call32_smm(void *func, u32 eax)
: "=&r" (bkup_esp), "+r" (eax)
: "r" (func)
: "eax", "ecx", "edx", "ebx", "cc", "memory");
- call32_smm_post();
+ call32_post();
dprintf(9, "call32_smm done %p %x\n", func, eax);
return eax;
}
-// 16bit handler code called from call16_smm()
-u32 VISIBLE16
-call16_smm_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx))
-{
- if (!CONFIG_CALL32_SMM)
- return eax;
- call32_smm_post();
- u32 ret = func(eax, edx);
- call32_smm_prep();
- return ret;
-}
-
static u32
call16_smm(u32 eax, u32 edx, void *func)
{
@@ -135,7 +192,7 @@ call16_smm(u32 eax, u32 edx, void *func)
return eax;
func -= BUILD_BIOS_ADDR;
dprintf(9, "call16_smm %p %x %x\n", func, eax, edx);
- u32 stackoffset = Call32Data.ss << 4;
+ u32 stackoffset = Call16Data.ss << 4;
asm volatile(
// Restore esp
" subl %0, %%esp\n"
@@ -151,7 +208,7 @@ call16_smm(u32 eax, u32 edx, void *func)
ASM32_SWITCH16
"1:movl %1, %%eax\n"
" movl %3, %%ecx\n"
- " calll _cfunc16_call16_smm_helper\n"
+ " calll _cfunc16_call16_helper\n"
" movl %%eax, %1\n"
" movl $" __stringify(CALL32SMM_CMDID) ", %%eax\n"
@@ -170,61 +227,18 @@ call16_smm(u32 eax, u32 edx, void *func)
return eax;
}
-// Backup state in preparation for call32_sloppy()
-static void
-call32_sloppy_prep(void)
-{
- // Backup cmos index register and disable nmi
- u8 cmosindex = inb(PORT_CMOS_INDEX);
- outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
- inb(PORT_CMOS_DATA);
- SET_LOW(Call32Data.cmosindex, cmosindex);
-
- // Enable a20 and backup it's previous state
- SET_LOW(Call32Data.a20, set_a20(1));
-
- // Backup ss/fs/gs and gdt
- SET_LOW(Call32Data.ss, GET_SEG(SS));
- SET_LOW(Call32Data.fs, GET_SEG(FS));
- SET_LOW(Call32Data.gs, GET_SEG(GS));
- struct descloc_s gdt;
- sgdt(&gdt);
- SET_LOW(Call32Data.gdt.length, gdt.length);
- SET_LOW(Call32Data.gdt.addr, gdt.addr);
-
- SET_LOW(Call32Data.method, C32_SLOPPY);
-}
-
-// Restore state backed up during call32_sloppy()
-static void
-call32_sloppy_post(void)
-{
- SET_LOW(Call32Data.method, 0);
- SET_LOW(Call32Data.ss, 0);
-
- // Restore gdt and fs/gs
- struct descloc_s gdt;
- gdt.length = GET_LOW(Call32Data.gdt.length);
- gdt.addr = GET_LOW(Call32Data.gdt.addr);
- lgdt(&gdt);
- SET_SEG(FS, GET_LOW(Call32Data.fs));
- SET_SEG(GS, GET_LOW(Call32Data.gs));
-
- // Restore a20
- set_a20(GET_LOW(Call32Data.a20));
-
- // Restore cmos index register
- outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX);
- inb(PORT_CMOS_DATA);
-}
-
-// Call a C function in 32bit mode. This clobbers the 16bit segment
-// selector registers.
-static u32
-call32_sloppy(void *func, u32 eax)
+// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function.
+u32 VISIBLE16
+__call32(void *func, u32 eax, u32 errret)
{
ASSERT16();
- call32_sloppy_prep();
+ if (CONFIG_CALL32_SMM && GET_GLOBAL(HaveSmmCall32))
+ return call32_smm(func, eax);
+ // Jump direclty to 32bit mode - this clobbers the 16bit segment
+ // selector registers.
+ int ret = call32_prep(C16_BIG);
+ if (ret)
+ return errret;
u32 bkup_ss, bkup_esp;
asm volatile(
// Backup ss/esp / set esp to flat stack location
@@ -236,7 +250,7 @@ call32_sloppy(void *func, u32 eax)
// Transition to 32bit mode, call func, return to 16bit
" movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n"
- " jmp transition32\n"
+ " jmp transition32_nmi_off\n"
ASM16_SWITCH32
"1:calll *%3\n"
" movl $2f, %%edx\n"
@@ -250,136 +264,52 @@ call32_sloppy(void *func, u32 eax)
: "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax)
: "r" (func)
: "ecx", "edx", "cc", "memory");
- call32_sloppy_post();
+ call32_post();
return eax;
}
-// 16bit handler code called from call16_sloppy()
-u32 VISIBLE16
-call16_sloppy_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx))
-{
- call32_sloppy_post();
- u32 ret = func(eax, edx);
- call32_sloppy_prep();
- return ret;
-}
-
-// Jump back to 16bit mode while in 32bit mode from call32_sloppy()
+// Call a 16bit SeaBIOS function, restoring the mode from last call32().
static u32
-call16_sloppy(u32 eax, u32 edx, void *func)
+call16(u32 eax, u32 edx, void *func)
{
ASSERT32FLAT();
if (getesp() > MAIN_STACK_MAX)
- panic("call16_sloppy with invalid stack\n");
+ panic("call16 with invalid stack\n");
+ if (CONFIG_CALL32_SMM && Call16Data.method == C16_SMM)
+ return call16_smm(eax, edx, func);
+
+ extern void transition16big(void);
+ extern void transition16(void);
+ void *thunk = transition16;
+ if (Call16Data.method == C16_BIG || in_post())
+ thunk = transition16big;
func -= BUILD_BIOS_ADDR;
- u32 stackseg = Call32Data.ss;
+ u32 stackseg = Call16Data.ss;
asm volatile(
// Transition to 16bit mode
" movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
- " jmp transition16big\n"
+ " jmp *%%ecx\n"
// Setup ss/esp and call func
ASM32_SWITCH16
- "1:movl %3, %%ecx\n"
- " shll $4, %3\n"
+ "1:movl %2, %%ecx\n"
+ " shll $4, %2\n"
" movw %%cx, %%ss\n"
- " subl %3, %%esp\n"
+ " subl %2, %%esp\n"
" movw %%cx, %%ds\n"
- " movl %2, %%edx\n"
- " movl %1, %%ecx\n"
- " calll _cfunc16_call16_sloppy_helper\n"
+ " movl %4, %%edx\n"
+ " movl %3, %%ecx\n"
+ " calll _cfunc16_call16_helper\n"
// Return to 32bit and restore esp
" movl $2f, %%edx\n"
- " jmp transition32\n"
- ASM32_BACK32
- "2:addl %3, %%esp\n"
- : "+a" (eax)
- : "r" (func), "r" (edx), "r" (stackseg)
- : "edx", "ecx", "cc", "memory");
- return eax;
-}
-
-// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function.
-u32 VISIBLE16
-call32(void *func, u32 eax, u32 errret)
-{
- ASSERT16();
- if (CONFIG_CALL32_SMM && GET_GLOBAL(HaveSmmCall32))
- return call32_smm(func, eax);
- u32 cr0 = getcr0();
- if (cr0 & CR0_PE)
- // Called in 16bit protected mode?!
- return errret;
- return call32_sloppy(func, eax);
-}
-
-// Call a 16bit SeaBIOS function from a 32bit SeaBIOS function.
-static u32
-call16(u32 eax, u32 edx, void *func)
-{
- ASSERT32FLAT();
- if (getesp() > BUILD_STACK_ADDR)
- panic("call16 with invalid stack\n");
- func -= BUILD_BIOS_ADDR;
- asm volatile(
- // Transition to 16bit mode
- " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
- " jmp transition16\n"
- // Call func
- ASM32_SWITCH16
- "1:movl %2, %%edx\n"
- " calll *%1\n"
- // Return to 32bit
- " movl $2f, %%edx\n"
- " jmp transition32\n"
- ASM32_BACK32
- "2:\n"
- : "+a" (eax)
- : "r" (func), "r" (edx)
- : "edx", "ecx", "cc", "memory");
- return eax;
-}
-
-// Call a 16bit SeaBIOS function in "big real" mode.
-static u32
-call16big(u32 eax, u32 edx, void *func)
-{
- ASSERT32FLAT();
- if (getesp() > BUILD_STACK_ADDR)
- panic("call16big with invalid stack\n");
- func -= BUILD_BIOS_ADDR;
- asm volatile(
- // Transition to 16bit mode
- " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
- " jmp transition16big\n"
- // Call func
- ASM32_SWITCH16
- "1:movl %2, %%edx\n"
- " calll *%1\n"
- // Return to 32bit
- " movl $2f, %%edx\n"
- " jmp transition32\n"
+ " jmp transition32_nmi_off\n"
ASM32_BACK32
- "2:\n"
- : "+a" (eax)
+ "2:addl %2, %%esp\n"
+ : "+a" (eax), "+c"(thunk), "+r"(stackseg)
: "r" (func), "r" (edx)
- : "edx", "ecx", "cc", "memory");
+ : "edx", "cc", "memory");
return eax;
}
-// Call a 16bit SeaBIOS function, restoring the mode from last call32().
-static u32
-call16_back(u32 eax, u32 edx, void *func)
-{
- ASSERT32FLAT();
- if (CONFIG_CALL32_SMM && Call32Data.method == C32_SMM)
- return call16_smm(eax, edx, func);
- if (Call32Data.method == C32_SLOPPY)
- return call16_sloppy(eax, edx, func);
- if (in_post())
- return call16big(eax, edx, func);
- return call16(eax, edx, func);
-}
-
/****************************************************************
* Extra 16bit stack
@@ -398,7 +328,7 @@ on_extra_stack(void)
// Switch to the extra stack and call a function.
u32
-stack_hop(u32 eax, u32 edx, void *func)
+__stack_hop(u32 eax, u32 edx, void *func)
{
if (on_extra_stack())
return ((u32 (*)(u32, u32))func)(eax, edx);
@@ -431,10 +361,10 @@ stack_hop(u32 eax, u32 edx, void *func)
// Switch back to original caller's stack and call a function.
u32
-stack_hop_back(u32 eax, u32 edx, void *func)
+__stack_hop_back(u32 eax, u32 edx, void *func)
{
if (!MODESEGMENT)
- return call16_back(eax, edx, func);
+ return call16(eax, edx, func);
if (!MODE16 || !on_extra_stack())
return ((u32 (*)(u32, u32))func)(eax, edx);
ASSERT16();
@@ -474,8 +404,7 @@ void VISIBLE16
_farcall16(struct bregs *callregs, u16 callregseg)
{
if (need_hop_back()) {
- extern void _cfunc16__farcall16(void);
- stack_hop_back((u32)callregs, callregseg, _cfunc16__farcall16);
+ stack_hop_back(_farcall16, callregs, callregseg);
return;
}
ASSERT16();
@@ -486,18 +415,20 @@ _farcall16(struct bregs *callregs, u16 callregseg)
: "ebx", "ecx", "esi", "edi", "cc", "memory");
}
+// Invoke external 16bit code.
void
farcall16(struct bregs *callregs)
{
- extern void _cfunc16__farcall16(void);
- call16((u32)callregs, 0, _cfunc16__farcall16);
+ call16_override(0);
+ _farcall16(callregs, 0);
}
+// Invoke external 16bit code in "big real" mode.
void
farcall16big(struct bregs *callregs)
{
- extern void _cfunc16__farcall16(void);
- call16big((u32)callregs, 0, _cfunc16__farcall16);
+ call16_override(1);
+ _farcall16(callregs, 0);
}
// Invoke a 16bit software interrupt.
@@ -507,7 +438,7 @@ __call16_int(struct bregs *callregs, u16 offset)
callregs->code.offset = offset;
if (!MODESEGMENT) {
callregs->code.seg = SEG_BIOS;
- _farcall16((void*)callregs - Call32Data.ss * 16, Call32Data.ss);
+ _farcall16((void*)callregs - Call16Data.ss * 16, Call16Data.ss);
return;
}
callregs->code.seg = GET_SEG(CS);
@@ -520,7 +451,7 @@ reset(void)
{
extern void reset_vector(void) __noreturn;
if (!MODE16)
- call16_back(0, 0, reset_vector);
+ call16(0, 0, reset_vector);
reset_vector();
}
@@ -558,12 +489,13 @@ getCurThread(void)
return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE);
}
-static int ThreadControl;
+static u8 CanInterrupt, ThreadControl;
// Initialize the support for internal threads.
void
-thread_init(void)
+thread_setup(void)
{
+ CanInterrupt = 1;
if (! CONFIG_THREADS)
return;
ThreadControl = romfile_loadint("etc/threads", 1);
@@ -573,7 +505,7 @@ thread_init(void)
int
threads_during_optionroms(void)
{
- return CONFIG_THREADS && ThreadControl == 2 && in_post();
+ return CONFIG_THREADS && CONFIG_RTC_TIMER && ThreadControl == 2 && in_post();
}
// Switch to next thread stack.
@@ -660,11 +592,17 @@ fail:
void VISIBLE16
check_irqs(void)
{
+ if (!MODESEGMENT && !CanInterrupt) {
+ // Can't enable interrupts (PIC and/or IVT not yet setup)
+ cpu_relax();
+ return;
+ }
if (need_hop_back()) {
- extern void _cfunc16_check_irqs(void);
- stack_hop_back(0, 0, _cfunc16_check_irqs);
+ stack_hop_back(check_irqs, 0, 0);
return;
}
+ if (MODE16)
+ clock_poll_irq();
asm volatile("sti ; nop ; rep ; nop ; cli ; cld" : : :"memory");
}
@@ -689,8 +627,7 @@ void VISIBLE16
wait_irq(void)
{
if (need_hop_back()) {
- extern void _cfunc16_wait_irq(void);
- stack_hop_back(0, 0, _cfunc16_wait_irq);
+ stack_hop_back(wait_irq, 0, 0);
return;
}
asm volatile("sti ; hlt ; cli ; cld": : :"memory");
@@ -700,8 +637,9 @@ wait_irq(void)
void
yield_toirq(void)
{
- if (!MODESEGMENT && have_threads()) {
- // Threads still active - do a yield instead.
+ if (!CONFIG_HARDWARE_IRQ
+ || (!MODESEGMENT && (have_threads() || !CanInterrupt))) {
+ // Threads still active or irqs not available - do a yield instead.
yield();
return;
}
@@ -794,9 +732,8 @@ yield_preempt(void)
void
check_preempt(void)
{
- extern void _cfunc32flat_yield_preempt(void);
if (CONFIG_THREADS && GET_GLOBAL(CanPreempt) && have_threads())
- call32(_cfunc32flat_yield_preempt, 0, 0);
+ call32(yield_preempt, 0, 0);
}
@@ -817,11 +754,10 @@ call32_params_helper(struct call32_params_s *params)
}
u32
-call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret)
+__call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret)
{
ASSERT16();
struct call32_params_s params = {func, eax, edx, ecx};
- extern void _cfunc32flat_call32_params_helper(void);
- return call32(_cfunc32flat_call32_params_helper
- , (u32)MAKE_FLATPTR(GET_SEG(SS), &params), errret);
+ return call32(call32_params_helper, MAKE_FLATPTR(GET_SEG(SS), &params)
+ , errret);
}
diff --git a/qemu/roms/seabios/src/stacks.h b/qemu/roms/seabios/src/stacks.h
index 82c4c3c85..c71bdc8e3 100644
--- a/qemu/roms/seabios/src/stacks.h
+++ b/qemu/roms/seabios/src/stacks.h
@@ -10,17 +10,27 @@
// stacks.c
extern int HaveSmmCall32;
-u32 call32(void *func, u32 eax, u32 errret);
+u32 __call32(void *func, u32 eax, u32 errret);
+#define call32(func, eax, errret) ({ \
+ extern void _cfunc32flat_ ##func (void); \
+ __call32( _cfunc32flat_ ##func , (u32)(eax), (errret)); \
+ })
extern u8 ExtraStack[], *StackPos;
-u32 stack_hop(u32 eax, u32 edx, void *func);
-u32 stack_hop_back(u32 eax, u32 edx, void *func);
+u32 __stack_hop(u32 eax, u32 edx, void *func);
+#define stack_hop(func, eax, edx) \
+ __stack_hop((u32)(eax), (u32)(edx), (func))
+u32 __stack_hop_back(u32 eax, u32 edx, void *func);
+#define stack_hop_back(func, eax, edx) ({ \
+ extern void _cfunc16_ ##func (void); \
+ __stack_hop_back((u32)(eax), (u32)(edx), _cfunc16_ ##func ); \
+ })
int on_extra_stack(void);
struct bregs;
void farcall16(struct bregs *callregs);
void farcall16big(struct bregs *callregs);
void __call16_int(struct bregs *callregs, u16 offset);
#define call16_int(nr, callregs) do { \
- extern void irq_trampoline_ ##nr (); \
+ extern void irq_trampoline_ ##nr (void); \
__call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \
} while (0)
void reset(void);
@@ -28,7 +38,7 @@ extern struct thread_info MainThread;
struct thread_info *getCurThread(void);
void yield(void);
void yield_toirq(void);
-void thread_init(void);
+void thread_setup(void);
int threads_during_optionroms(void);
void run_thread(void (*func)(void*), void *data);
void wait_threads(void);
@@ -39,7 +49,12 @@ void start_preempt(void);
void finish_preempt(void);
int wait_preempt(void);
void check_preempt(void);
-u32 call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret);
+u32 __call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret);
+#define call32_params(func, eax, edx, ecx, errret) ({ \
+ extern void _cfunc32flat_ ##func (void); \
+ __call32_params( _cfunc32flat_ ##func , (u32)(eax), (u32)(edx) \
+ , (u32)(ecx), (errret)); \
+ })
// Inline functions
diff --git a/qemu/roms/seabios/src/std/acpi.h b/qemu/roms/seabios/src/std/acpi.h
index e0d9516ba..b672bbee4 100644
--- a/qemu/roms/seabios/src/std/acpi.h
+++ b/qemu/roms/seabios/src/std/acpi.h
@@ -294,4 +294,24 @@ struct acpi_table_mcfg {
struct acpi_mcfg_allocation allocation[0];
} PACKED;
+
+struct rsdt_descriptor {
+ ACPI_TABLE_HEADER_DEF
+ u32 entry[1];
+} PACKED;
+
+#define TCPA_SIGNATURE 0x41504354
+struct tcpa_descriptor_rev2
+{
+ ACPI_TABLE_HEADER_DEF
+ u16 platform_class;
+ u32 log_area_minimum_length;
+ u64 log_area_start_address;
+} PACKED;
+
+/* TCPA ACPI definitions */
+#define TCPA_ACPI_CLASS_CLIENT 0
+#define TCPA_ACPI_CLASS_SERVER 1
+
+
#endif // acpi.h
diff --git a/qemu/roms/seabios/src/std/bda.h b/qemu/roms/seabios/src/std/bda.h
index c321266e2..4ad6605d4 100644
--- a/qemu/roms/seabios/src/std/bda.h
+++ b/qemu/roms/seabios/src/std/bda.h
@@ -7,7 +7,7 @@
/****************************************************************
- * Interupt vector table
+ * Interrupt vector table
****************************************************************/
struct rmode_IVT {
diff --git a/qemu/roms/seabios/src/std/multiboot.h b/qemu/roms/seabios/src/std/multiboot.h
new file mode 100644
index 000000000..6c9512703
--- /dev/null
+++ b/qemu/roms/seabios/src/std/multiboot.h
@@ -0,0 +1,260 @@
+/* multiboot.h - Multiboot header file. */
+/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * 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 ANY
+ * DEVELOPER OR DISTRIBUTOR 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.
+ */
+
+#ifndef MULTIBOOT_HEADER
+#define MULTIBOOT_HEADER 1
+
+/* How many bytes from the start of the file we search for the header. */
+#define MULTIBOOT_SEARCH 8192
+#define MULTIBOOT_HEADER_ALIGN 4
+
+/* The magic field should contain this. */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/* This should be in %eax. */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+/* Alignment of multiboot modules. */
+#define MULTIBOOT_MOD_ALIGN 0x00001000
+
+/* Alignment of the multiboot info structure. */
+#define MULTIBOOT_INFO_ALIGN 0x00000004
+
+/* Flags set in the 'flags' member of the multiboot header. */
+
+/* Align all boot modules on i386 page (4KB) boundaries. */
+#define MULTIBOOT_PAGE_ALIGN 0x00000001
+
+/* Must pass memory information to OS. */
+#define MULTIBOOT_MEMORY_INFO 0x00000002
+
+/* Must pass video information to OS. */
+#define MULTIBOOT_VIDEO_MODE 0x00000004
+
+/* This flag indicates the use of the address fields in the header. */
+#define MULTIBOOT_AOUT_KLUDGE 0x00010000
+
+/* Flags to be set in the 'flags' member of the multiboot info structure. */
+
+/* is there basic lower/upper memory information? */
+#define MULTIBOOT_INFO_MEMORY 0x00000001
+/* is there a boot device set? */
+#define MULTIBOOT_INFO_BOOTDEV 0x00000002
+/* is the command-line defined? */
+#define MULTIBOOT_INFO_CMDLINE 0x00000004
+/* are there modules to do something with? */
+#define MULTIBOOT_INFO_MODS 0x00000008
+
+/* These next two are mutually exclusive */
+
+/* is there a symbol table loaded? */
+#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
+/* is there an ELF section header table? */
+#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
+
+/* is there a full memory map? */
+#define MULTIBOOT_INFO_MEM_MAP 0x00000040
+
+/* Is there drive info? */
+#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
+
+/* Is there a config table? */
+#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
+
+/* Is there a boot loader name? */
+#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
+
+/* Is there a APM table? */
+#define MULTIBOOT_INFO_APM_TABLE 0x00000400
+
+/* Is there video information? */
+#define MULTIBOOT_INFO_VBE_INFO 0x00000800
+#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000
+
+#ifndef ASM_FILE
+
+typedef unsigned char multiboot_uint8_t;
+typedef unsigned short multiboot_uint16_t;
+typedef unsigned int multiboot_uint32_t;
+typedef unsigned long long multiboot_uint64_t;
+
+struct multiboot_header
+{
+ /* Must be MULTIBOOT_MAGIC - see above. */
+ multiboot_uint32_t magic;
+
+ /* Feature flags. */
+ multiboot_uint32_t flags;
+
+ /* The above fields plus this one must equal 0 mod 2^32. */
+ multiboot_uint32_t checksum;
+
+ /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
+ multiboot_uint32_t header_addr;
+ multiboot_uint32_t load_addr;
+ multiboot_uint32_t load_end_addr;
+ multiboot_uint32_t bss_end_addr;
+ multiboot_uint32_t entry_addr;
+
+ /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
+ multiboot_uint32_t mode_type;
+ multiboot_uint32_t width;
+ multiboot_uint32_t height;
+ multiboot_uint32_t depth;
+};
+
+/* The symbol table for a.out. */
+struct multiboot_aout_symbol_table
+{
+ multiboot_uint32_t tabsize;
+ multiboot_uint32_t strsize;
+ multiboot_uint32_t addr;
+ multiboot_uint32_t reserved;
+};
+typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
+
+/* The section header table for ELF. */
+struct multiboot_elf_section_header_table
+{
+ multiboot_uint32_t num;
+ multiboot_uint32_t size;
+ multiboot_uint32_t addr;
+ multiboot_uint32_t shndx;
+};
+typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
+
+struct multiboot_info
+{
+ /* Multiboot info version number */
+ multiboot_uint32_t flags;
+
+ /* Available memory from BIOS */
+ multiboot_uint32_t mem_lower;
+ multiboot_uint32_t mem_upper;
+
+ /* "root" partition */
+ multiboot_uint32_t boot_device;
+
+ /* Kernel command line */
+ multiboot_uint32_t cmdline;
+
+ /* Boot-Module list */
+ multiboot_uint32_t mods_count;
+ multiboot_uint32_t mods_addr;
+
+ union
+ {
+ multiboot_aout_symbol_table_t aout_sym;
+ multiboot_elf_section_header_table_t elf_sec;
+ } u;
+
+ /* Memory Mapping buffer */
+ multiboot_uint32_t mmap_length;
+ multiboot_uint32_t mmap_addr;
+
+ /* Drive Info buffer */
+ multiboot_uint32_t drives_length;
+ multiboot_uint32_t drives_addr;
+
+ /* ROM configuration table */
+ multiboot_uint32_t config_table;
+
+ /* Boot Loader Name */
+ multiboot_uint32_t boot_loader_name;
+
+ /* APM table */
+ multiboot_uint32_t apm_table;
+
+ /* Video */
+ multiboot_uint32_t vbe_control_info;
+ multiboot_uint32_t vbe_mode_info;
+ multiboot_uint16_t vbe_mode;
+ multiboot_uint16_t vbe_interface_seg;
+ multiboot_uint16_t vbe_interface_off;
+ multiboot_uint16_t vbe_interface_len;
+
+ multiboot_uint64_t framebuffer_addr;
+ multiboot_uint32_t framebuffer_pitch;
+ multiboot_uint32_t framebuffer_width;
+ multiboot_uint32_t framebuffer_height;
+ multiboot_uint8_t framebuffer_bpp;
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
+#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
+ multiboot_uint8_t framebuffer_type;
+ union
+ {
+ struct
+ {
+ multiboot_uint32_t framebuffer_palette_addr;
+ multiboot_uint16_t framebuffer_palette_num_colors;
+ };
+ struct
+ {
+ multiboot_uint8_t framebuffer_red_field_position;
+ multiboot_uint8_t framebuffer_red_mask_size;
+ multiboot_uint8_t framebuffer_green_field_position;
+ multiboot_uint8_t framebuffer_green_mask_size;
+ multiboot_uint8_t framebuffer_blue_field_position;
+ multiboot_uint8_t framebuffer_blue_mask_size;
+ };
+ };
+};
+typedef struct multiboot_info multiboot_info_t;
+
+struct multiboot_color
+{
+ multiboot_uint8_t red;
+ multiboot_uint8_t green;
+ multiboot_uint8_t blue;
+};
+
+struct multiboot_mmap_entry
+{
+ multiboot_uint32_t size;
+ multiboot_uint64_t addr;
+ multiboot_uint64_t len;
+#define MULTIBOOT_MEMORY_AVAILABLE 1
+#define MULTIBOOT_MEMORY_RESERVED 2
+#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
+#define MULTIBOOT_MEMORY_NVS 4
+#define MULTIBOOT_MEMORY_BADRAM 5
+ multiboot_uint32_t type;
+} __attribute__((packed));
+typedef struct multiboot_mmap_entry multiboot_memory_map_t;
+
+struct multiboot_mod_list
+{
+ /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
+ multiboot_uint32_t mod_start;
+ multiboot_uint32_t mod_end;
+
+ /* Module command line */
+ multiboot_uint32_t cmdline;
+
+ /* padding to take it to 16 bytes (must be zero) */
+ multiboot_uint32_t pad;
+};
+typedef struct multiboot_mod_list multiboot_module_t;
+
+#endif /* ! ASM_FILE */
+
+#endif /* ! MULTIBOOT_HEADER */
diff --git a/qemu/roms/seabios/src/std/smbios.h b/qemu/roms/seabios/src/std/smbios.h
index 05137167a..4ccf2ea34 100644
--- a/qemu/roms/seabios/src/std/smbios.h
+++ b/qemu/roms/seabios/src/std/smbios.h
@@ -3,11 +3,13 @@
#include "types.h" // u32
+#define SMBIOS_SIGNATURE 0x5f4d535f // "_SM_"
+
/* SMBIOS entry point -- must be written to a 16-bit aligned address
between 0xf0000 and 0xfffff.
*/
struct smbios_entry_point {
- char anchor_string[4];
+ u32 signature;
u8 checksum;
u8 length;
u8 smbios_major_version;
diff --git a/qemu/roms/seabios/src/string.c b/qemu/roms/seabios/src/string.c
index 2e4e43746..adb8198f8 100644
--- a/qemu/roms/seabios/src/string.c
+++ b/qemu/roms/seabios/src/string.c
@@ -227,7 +227,7 @@ strtcpy(char *dest, const char *src, size_t len)
return dest;
}
-// locate first occurance of character c in the string s
+// locate first occurrence of character c in the string s
char *
strchr(const char *s, int c)
{
diff --git a/qemu/roms/seabios/src/string.h b/qemu/roms/seabios/src/string.h
index a557d6a44..d069989db 100644
--- a/qemu/roms/seabios/src/string.h
+++ b/qemu/roms/seabios/src/string.h
@@ -11,12 +11,12 @@ size_t strlen(const char *s);
int memcmp_far(u16 s1seg, const void *s1, u16 s2seg, const void *s2, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2);
-inline void memset_far(u16 d_seg, void *d_far, u8 c, size_t len);
-inline void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len);
+void memset_far(u16 d_seg, void *d_far, u8 c, size_t len);
+void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len);
void *memset(void *s, int c, size_t n);
void memset_fl(void *ptr, u8 val, size_t size);
-inline void memcpy_far(u16 d_seg, void *d_far
- , u16 s_seg, const void *s_far, size_t len);
+void memcpy_far(u16 d_seg, void *d_far
+ , u16 s_seg, const void *s_far, size_t len);
void memcpy_fl(void *d_fl, const void *s_fl, size_t len);
void *memcpy(void *d1, const void *s1, size_t len);
#if MODESEGMENT == 0
diff --git a/qemu/roms/seabios/src/system.c b/qemu/roms/seabios/src/system.c
index 60a6fce58..438e60e2c 100644
--- a/qemu/roms/seabios/src/system.c
+++ b/qemu/roms/seabios/src/system.c
@@ -7,9 +7,9 @@
#include "biosvar.h" // GET_GLOBAL
#include "bregs.h" // struct bregs
+#include "e820map.h" // E820_RAM
#include "hw/pic.h" // pic_reset
#include "malloc.h" // LegacyRamSize
-#include "memmap.h" // E820_RAM
#include "output.h" // debug_enter
#include "string.h" // memcpy_far
#include "util.h" // handle_1553
diff --git a/qemu/roms/seabios/src/tcgbios.c b/qemu/roms/seabios/src/tcgbios.c
new file mode 100644
index 000000000..09954825c
--- /dev/null
+++ b/qemu/roms/seabios/src/tcgbios.c
@@ -0,0 +1,1480 @@
+// Implementation of the TCG BIOS extension according to the specification
+// described in specs found at
+// http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
+//
+// Copyright (C) 2006-2011, 2014, 2015 IBM Corporation
+//
+// Authors:
+// Stefan Berger <stefanb@linux.vnet.ibm.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+#include "config.h"
+
+#include "types.h"
+#include "byteorder.h" // cpu_to_*
+#include "hw/tpm_drivers.h" // tpm_drivers[]
+#include "farptr.h" // MAKE_FLATPTR
+#include "string.h" // checksum
+#include "tcgbios.h"// tpm_*, prototypes
+#include "util.h" // printf, get_keystroke
+#include "output.h" // dprintf
+#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
+#include "bregs.h" // struct bregs
+#include "sha1.h" // sha1
+#include "fw/paravirt.h" // runningOnXen
+#include "std/smbios.h"
+
+static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
+static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
+
+static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 };
+static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
+static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 };
+static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
+
+static const u8 CommandFlag_FALSE[1] = { 0x00 };
+static const u8 CommandFlag_TRUE[1] = { 0x01 };
+
+static const u8 GetCapability_Permanent_Flags[] = {
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x08
+};
+
+static const u8 GetCapability_OwnerAuth[] = {
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x11
+};
+
+static const u8 GetCapability_Timeouts[] = {
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x15
+};
+
+static const u8 GetCapability_Durations[] = {
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x20
+};
+
+static u8 evt_separator[] = {0xff,0xff,0xff,0xff};
+
+
+#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr)
+
+/* local function prototypes */
+
+static u32 tpm_calling_int19h(void);
+static u32 tpm_add_event_separators(void);
+static u32 tpm_start_option_rom_scan(void);
+static u32 tpm_smbios_measure(void);
+
+/* helper functions */
+
+static inline void *input_buf32(struct bregs *regs)
+{
+ return MAKE_FLATPTR(regs->es, regs->di);
+}
+
+static inline void *output_buf32(struct bregs *regs)
+{
+ return MAKE_FLATPTR(regs->ds, regs->si);
+}
+
+
+typedef struct {
+ u8 tpm_probed:1;
+ u8 tpm_found:1;
+ u8 tpm_working:1;
+ u8 if_shutdown:1;
+ u8 tpm_driver_to_use:4;
+} tpm_state_t;
+
+
+static tpm_state_t tpm_state = {
+ .tpm_driver_to_use = TPM_INVALID_DRIVER,
+};
+
+
+/********************************************************
+ Extensions for TCG-enabled BIOS
+ *******************************************************/
+
+
+static u32
+is_tpm_present(void)
+{
+ u32 rc = 0;
+ unsigned int i;
+
+ for (i = 0; i < TPM_NUM_DRIVERS; i++) {
+ struct tpm_driver *td = &tpm_drivers[i];
+ if (td->probe() != 0) {
+ td->init();
+ tpm_state.tpm_driver_to_use = i;
+ rc = 1;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static void
+probe_tpm(void)
+{
+ if (!tpm_state.tpm_probed) {
+ tpm_state.tpm_probed = 1;
+ tpm_state.tpm_found = (is_tpm_present() != 0);
+ tpm_state.tpm_working = tpm_state.tpm_found;
+ }
+}
+
+static int
+has_working_tpm(void)
+{
+ probe_tpm();
+
+ return tpm_state.tpm_working;
+}
+
+static struct tcpa_descriptor_rev2 *
+find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
+{
+ u32 ctr = 0;
+ struct tcpa_descriptor_rev2 *tcpa = NULL;
+ struct rsdt_descriptor *rsdt;
+ u32 length;
+ u16 off;
+
+ rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
+ if (!rsdt)
+ return NULL;
+
+ length = rsdt->length;
+ off = offsetof(struct rsdt_descriptor, entry);
+
+ while ((off + sizeof(rsdt->entry[0])) <= length) {
+ /* try all pointers to structures */
+ tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
+
+ /* valid TCPA ACPI table ? */
+ if (tcpa->signature == TCPA_SIGNATURE &&
+ checksum((u8 *)tcpa, tcpa->length) == 0)
+ break;
+
+ tcpa = NULL;
+ off += sizeof(rsdt->entry[0]);
+ ctr++;
+ }
+
+ return tcpa;
+}
+
+
+static struct tcpa_descriptor_rev2 *
+find_tcpa_table(void)
+{
+ struct tcpa_descriptor_rev2 *tcpa = NULL;
+ struct rsdp_descriptor *rsdp = RsdpAddr;
+
+ if (rsdp)
+ tcpa = find_tcpa_by_rsdp(rsdp);
+ else
+ tpm_state.if_shutdown = 1;
+
+ if (!rsdp)
+ dprintf(DEBUG_tcg,
+ "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
+ else if (!tcpa)
+ dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
+
+ return tcpa;
+}
+
+
+static u8 *
+get_lasa_base_ptr(u32 *log_area_minimum_length)
+{
+ u8 *log_area_start_address = 0;
+ struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
+
+ if (tcpa) {
+ log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
+ if (log_area_minimum_length)
+ *log_area_minimum_length = tcpa->log_area_minimum_length;
+ }
+
+ return log_area_start_address;
+}
+
+
+/* clear the ACPI log */
+static void
+reset_acpi_log(void)
+{
+ u32 log_area_minimum_length;
+ u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length);
+
+ if (log_area_start_address)
+ memset(log_area_start_address, 0x0, log_area_minimum_length);
+}
+
+
+/*
+ initialize the TCPA ACPI subsystem; find the ACPI tables and determine
+ where the TCPA table is.
+ */
+static void
+tpm_acpi_init(void)
+{
+ tpm_state.if_shutdown = 0;
+ tpm_state.tpm_probed = 0;
+ tpm_state.tpm_found = 0;
+ tpm_state.tpm_working = 0;
+
+ if (!has_working_tpm()) {
+ tpm_state.if_shutdown = 1;
+ return;
+ }
+
+ reset_acpi_log();
+}
+
+
+static u32
+transmit(u8 locty, const struct iovec iovec[],
+ u8 *respbuffer, u32 *respbufferlen,
+ enum tpmDurationType to_t)
+{
+ u32 rc = 0;
+ u32 irc;
+ struct tpm_driver *td;
+ unsigned int i;
+
+ if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
+ return TCG_FATAL_COM_ERROR;
+
+ td = &tpm_drivers[tpm_state.tpm_driver_to_use];
+
+ irc = td->activate(locty);
+ if (irc != 0) {
+ /* tpm could not be activated */
+ return TCG_FATAL_COM_ERROR;
+ }
+
+ for (i = 0; iovec[i].length; i++) {
+ irc = td->senddata(iovec[i].data,
+ iovec[i].length);
+ if (irc != 0)
+ return TCG_FATAL_COM_ERROR;
+ }
+
+ irc = td->waitdatavalid();
+ if (irc != 0)
+ return TCG_FATAL_COM_ERROR;
+
+ irc = td->waitrespready(to_t);
+ if (irc != 0)
+ return TCG_FATAL_COM_ERROR;
+
+ irc = td->readresp(respbuffer,
+ respbufferlen);
+ if (irc != 0)
+ return TCG_FATAL_COM_ERROR;
+
+ td->ready();
+
+ return rc;
+}
+
+
+/*
+ * Send a TPM command with the given ordinal. Append the given buffer
+ * containing all data in network byte order to the command (this is
+ * the custom part per command) and expect a response of the given size.
+ * If a buffer is provided, the response will be copied into it.
+ */
+static u32
+build_and_send_cmd_od(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
+ u8 *resbuffer, u32 return_size, u32 *returnCode,
+ const u8 *otherdata, u32 otherdata_size,
+ enum tpmDurationType to_t)
+{
+#define MAX_APPEND_SIZE sizeof(GetCapability_Timeouts)
+#define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags)
+ u32 rc;
+ u8 ibuffer[TPM_REQ_HEADER_SIZE + MAX_APPEND_SIZE];
+ u8 obuffer[MAX_RESPONSE_SIZE];
+ struct tpm_req_header *trqh = (struct tpm_req_header *)ibuffer;
+ struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
+ struct iovec iovec[3];
+ u32 obuffer_len = sizeof(obuffer);
+ u32 idx = 1;
+
+ if (append_size > MAX_APPEND_SIZE ||
+ return_size > MAX_RESPONSE_SIZE) {
+ dprintf(DEBUG_tcg, "TCGBIOS: size of requested buffers too big.");
+ return TCG_FIRMWARE_ERROR;
+ }
+
+ iovec[0].data = trqh;
+ iovec[0].length = TPM_REQ_HEADER_SIZE + append_size;
+
+ if (otherdata) {
+ iovec[1].data = (void *)otherdata;
+ iovec[1].length = otherdata_size;
+ idx = 2;
+ }
+
+ iovec[idx].data = NULL;
+ iovec[idx].length = 0;
+
+ memset(ibuffer, 0x0, sizeof(ibuffer));
+ memset(obuffer, 0x0, sizeof(obuffer));
+
+ trqh->tag = cpu_to_be16(TPM_TAG_RQU_CMD);
+ trqh->totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size +
+ otherdata_size);
+ trqh->ordinal = cpu_to_be32(ordinal);
+
+ if (append_size)
+ memcpy((char *)trqh + sizeof(*trqh),
+ append, append_size);
+
+ rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
+ if (rc)
+ return rc;
+
+ *returnCode = be32_to_cpu(trsh->errcode);
+
+ if (resbuffer)
+ memcpy(resbuffer, trsh, return_size);
+
+ return 0;
+}
+
+
+static u32
+build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
+ u8 *resbuffer, u32 return_size, u32 *returnCode,
+ enum tpmDurationType to_t)
+{
+ return build_and_send_cmd_od(locty, ordinal, append, append_size,
+ resbuffer, return_size, returnCode,
+ NULL, 0, to_t);
+}
+
+
+static u32
+determine_timeouts(void)
+{
+ u32 rc;
+ u32 returnCode;
+ struct tpm_res_getcap_timeouts timeouts;
+ struct tpm_res_getcap_durations durations;
+ struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
+ u32 i;
+
+ rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
+ GetCapability_Timeouts,
+ sizeof(GetCapability_Timeouts),
+ (u8 *)&timeouts, sizeof(timeouts),
+ &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
+ " = 0x%08x\n", returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
+ GetCapability_Durations,
+ sizeof(GetCapability_Durations),
+ (u8 *)&durations, sizeof(durations),
+ &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
+ " = 0x%08x\n", returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ for (i = 0; i < 3; i++)
+ durations.durations[i] = be32_to_cpu(durations.durations[i]);
+
+ for (i = 0; i < 4; i++)
+ timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
+ timeouts.timeouts[0],
+ timeouts.timeouts[1],
+ timeouts.timeouts[2],
+ timeouts.timeouts[3]);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
+ durations.durations[0],
+ durations.durations[1],
+ durations.durations[2]);
+
+
+ td->set_timeouts(timeouts.timeouts, durations.durations);
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+tpm_startup(void)
+{
+ u32 rc;
+ u32 returnCode;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
+ rc = build_and_send_cmd(0, TPM_ORD_Startup,
+ Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
+ returnCode);
+
+ if (CONFIG_COREBOOT) {
+ /* with other firmware on the system the TPM may already have been
+ * initialized
+ */
+ if (returnCode == TPM_INVALID_POSTINIT)
+ returnCode = 0;
+ }
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
+
+ dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
+ returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
+ returnCode);
+
+ if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
+ goto err_exit;
+
+ rc = determine_timeouts();
+ if (rc)
+ goto err_exit;
+
+ rc = tpm_smbios_measure();
+ if (rc)
+ goto err_exit;
+
+ rc = tpm_start_option_rom_scan();
+ if (rc)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
+
+
+void
+tpm_setup(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ tpm_acpi_init();
+ if (runningOnXen())
+ return;
+
+ tpm_startup();
+}
+
+
+void
+tpm_prepboot(void)
+{
+ u32 rc;
+ u32 returnCode;
+
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ if (!has_working_tpm())
+ return;
+
+ rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
+ PhysicalPresence_CMD_ENABLE,
+ sizeof(PhysicalPresence_CMD_ENABLE),
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
+ PhysicalPresence_NOT_PRESENT_LOCK,
+ sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = tpm_calling_int19h();
+ if (rc)
+ goto err_exit;
+
+ rc = tpm_add_event_separators();
+ if (rc)
+ goto err_exit;
+
+ return;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+}
+
+static int
+is_valid_pcpes(struct pcpes *pcpes)
+{
+ return (pcpes->eventtype != 0);
+}
+
+
+static u8 *
+get_lasa_last_ptr(u16 *entry_count, u8 **log_area_start_address_next)
+{
+ struct pcpes *pcpes;
+ u32 log_area_minimum_length = 0;
+ u8 *log_area_start_address_base =
+ get_lasa_base_ptr(&log_area_minimum_length);
+ u8 *log_area_start_address_last = NULL;
+ u8 *end = log_area_start_address_base + log_area_minimum_length;
+ u32 size;
+
+ if (entry_count)
+ *entry_count = 0;
+
+ if (!log_area_start_address_base)
+ return NULL;
+
+ while (log_area_start_address_base < end) {
+ pcpes = (struct pcpes *)log_area_start_address_base;
+ if (!is_valid_pcpes(pcpes))
+ break;
+ if (entry_count)
+ (*entry_count)++;
+ size = pcpes->eventdatasize + offsetof(struct pcpes, event);
+ log_area_start_address_last = log_area_start_address_base;
+ log_area_start_address_base += size;
+ }
+
+ if (log_area_start_address_next)
+ *log_area_start_address_next = log_area_start_address_base;
+
+ return log_area_start_address_last;
+}
+
+
+static u32
+tpm_sha1_calc(const u8 *data, u32 length, u8 *hash)
+{
+ u32 rc;
+ u32 returnCode;
+ struct tpm_res_sha1start start;
+ struct tpm_res_sha1complete complete;
+ u32 blocks = length / 64;
+ u32 rest = length & 0x3f;
+ u32 numbytes, numbytes_no;
+ u32 offset = 0;
+
+ rc = build_and_send_cmd(0, TPM_ORD_SHA1Start,
+ NULL, 0,
+ (u8 *)&start, sizeof(start),
+ &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ while (blocks > 0) {
+
+ numbytes = be32_to_cpu(start.max_num_bytes);
+ if (numbytes > blocks * 64)
+ numbytes = blocks * 64;
+
+ numbytes_no = cpu_to_be32(numbytes);
+
+ rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Update,
+ (u8 *)&numbytes_no, sizeof(numbytes_no),
+ NULL, 0, &returnCode,
+ &data[offset], numbytes,
+ TPM_DURATION_TYPE_SHORT);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ offset += numbytes;
+ blocks -= (numbytes / 64);
+ }
+
+ numbytes_no = cpu_to_be32(rest);
+
+ rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Complete,
+ (u8 *)&numbytes_no, sizeof(numbytes_no),
+ (u8 *)&complete, sizeof(complete),
+ &returnCode,
+ &data[offset], rest, TPM_DURATION_TYPE_SHORT);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ memcpy(hash, complete.hash, sizeof(complete.hash));
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM SHA1 malfunctioning.\n");
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+sha1_calc(const u8 *data, u32 length, u8 *hash)
+{
+ if (length < tpm_drivers[tpm_state.tpm_driver_to_use].sha1threshold)
+ return tpm_sha1_calc(data, length, hash);
+
+ return sha1(data, length, hash);
+}
+
+
+/*
+ * Extend the ACPI log with the given entry by copying the
+ * entry data into the log.
+ * Input
+ * Pointer to the structure to be copied into the log
+ *
+ * Output:
+ * lower 16 bits of return code contain entry number
+ * if entry number is '0', then upper 16 bits contain error code.
+ */
+static u32
+tpm_extend_acpi_log(void *entry_ptr, u16 *entry_count)
+{
+ u32 log_area_minimum_length, size;
+ u8 *log_area_start_address_base =
+ get_lasa_base_ptr(&log_area_minimum_length);
+ u8 *log_area_start_address_next = NULL;
+ struct pcpes *pcpes = (struct pcpes *)entry_ptr;
+
+ get_lasa_last_ptr(entry_count, &log_area_start_address_next);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: LASA_BASE = %p, LASA_NEXT = %p\n",
+ log_area_start_address_base, log_area_start_address_next);
+
+ if (log_area_start_address_next == NULL || log_area_minimum_length == 0)
+ return TCG_PC_LOGOVERFLOW;
+
+ size = pcpes->eventdatasize + offsetof(struct pcpes, event);
+
+ if ((log_area_start_address_next + size - log_area_start_address_base) >
+ log_area_minimum_length) {
+ dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
+ return TCG_PC_LOGOVERFLOW;
+ }
+
+ memcpy(log_area_start_address_next, entry_ptr, size);
+
+ (*entry_count)++;
+
+ return 0;
+}
+
+
+static u32
+is_preboot_if_shutdown(void)
+{
+ return tpm_state.if_shutdown;
+}
+
+
+static u32
+shutdown_preboot_interface(void)
+{
+ u32 rc = 0;
+
+ if (!is_preboot_if_shutdown()) {
+ tpm_state.if_shutdown = 1;
+ } else {
+ rc = TCG_INTERFACE_SHUTDOWN;
+ }
+
+ return rc;
+}
+
+
+static void
+tpm_shutdown(void)
+{
+ reset_acpi_log();
+ shutdown_preboot_interface();
+}
+
+
+static u32
+pass_through_to_tpm(struct pttti *pttti, struct pttto *pttto)
+{
+ u32 rc = 0;
+ u32 resbuflen = 0;
+ struct tpm_req_header *trh;
+ u8 locty = 0;
+ struct iovec iovec[2];
+ const u32 *tmp;
+
+ if (is_preboot_if_shutdown()) {
+ rc = TCG_INTERFACE_SHUTDOWN;
+ goto err_exit;
+ }
+
+ trh = (struct tpm_req_header *)pttti->tpmopin;
+
+ if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE ||
+ pttti->opblength < sizeof(struct pttto) ||
+ be32_to_cpu(trh->totlen) + sizeof(struct pttti) > pttti->ipblength ) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
+
+ iovec[0].data = pttti->tpmopin;
+ tmp = (const u32 *)&((u8 *)iovec[0].data)[2];
+ iovec[0].length = cpu_to_be32(*tmp);
+
+ iovec[1].data = NULL;
+ iovec[1].length = 0;
+
+ rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen,
+ TPM_DURATION_TYPE_LONG /* worst case */);
+ if (rc)
+ goto err_exit;
+
+ pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
+ pttto->reserved = 0;
+
+err_exit:
+ if (rc != 0) {
+ pttto->opblength = 4;
+ pttto->reserved = 0;
+ }
+
+ return rc;
+}
+
+
+static u32
+tpm_extend(u8 *hash, u32 pcrindex)
+{
+ u32 rc;
+ struct pttto_extend pttto;
+ struct pttti_extend pttti = {
+ .pttti = {
+ .ipblength = sizeof(struct pttti_extend),
+ .opblength = sizeof(struct pttto_extend),
+ },
+ .req = {
+ .tag = cpu_to_be16(0xc1),
+ .totlen = cpu_to_be32(sizeof(pttti.req)),
+ .ordinal = cpu_to_be32(TPM_ORD_Extend),
+ .pcrindex = cpu_to_be32(pcrindex),
+ },
+ };
+
+ memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest));
+
+ rc = pass_through_to_tpm(&pttti.pttti, &pttto.pttto);
+
+ if (rc == 0) {
+ if (pttto.pttto.opblength < TPM_RSP_HEADER_SIZE ||
+ pttto.pttto.opblength !=
+ sizeof(struct pttto) + be32_to_cpu(pttto.rsp.totlen) ||
+ be16_to_cpu(pttto.rsp.tag) != 0xc4) {
+ rc = TCG_FATAL_COM_ERROR;
+ }
+ }
+
+ if (rc)
+ tpm_shutdown();
+
+ return rc;
+}
+
+
+static u32
+hash_all(const struct hai *hai, u8 *hash)
+{
+ if (is_preboot_if_shutdown() != 0)
+ return TCG_INTERFACE_SHUTDOWN;
+
+ if (hai->ipblength != sizeof(struct hai) ||
+ hai->hashdataptr == 0 ||
+ hai->hashdatalen == 0 ||
+ hai->algorithmid != TPM_ALG_SHA)
+ return TCG_INVALID_INPUT_PARA;
+
+ return sha1_calc((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
+}
+
+
+static u32
+hash_log_event(const struct hlei *hlei, struct hleo *hleo)
+{
+ u32 rc = 0;
+ u16 size;
+ struct pcpes *pcpes;
+ u16 entry_count;
+
+ if (is_preboot_if_shutdown() != 0) {
+ rc = TCG_INTERFACE_SHUTDOWN;
+ goto err_exit;
+ }
+
+ size = hlei->ipblength;
+ if (size != sizeof(*hlei)) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ pcpes = (struct pcpes *)hlei->logdataptr;
+
+ if (pcpes->pcrindex >= 24 ||
+ pcpes->pcrindex != hlei->pcrindex ||
+ pcpes->eventtype != hlei->logeventtype) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ if ((hlei->hashdataptr != 0) && (hlei->hashdatalen != 0)) {
+ rc = sha1_calc((const u8 *)hlei->hashdataptr,
+ hlei->hashdatalen, pcpes->digest);
+ if (rc)
+ return rc;
+ }
+
+ rc = tpm_extend_acpi_log((void *)hlei->logdataptr, &entry_count);
+ if (rc)
+ goto err_exit;
+
+ /* updating the log was fine */
+ hleo->opblength = sizeof(struct hleo);
+ hleo->reserved = 0;
+ hleo->eventnumber = entry_count;
+
+err_exit:
+ if (rc != 0) {
+ hleo->opblength = 2;
+ hleo->reserved = 0;
+ }
+
+ return rc;
+}
+
+
+static u32
+hash_log_extend_event(const struct hleei_short *hleei_s, struct hleeo *hleeo)
+{
+ u32 rc = 0;
+ struct hleo hleo;
+ struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
+ const void *logdataptr;
+ u32 logdatalen;
+ struct pcpes *pcpes;
+
+ /* short or long version? */
+ switch (hleei_s->ipblength) {
+ case sizeof(struct hleei_short):
+ /* short */
+ logdataptr = hleei_s->logdataptr;
+ logdatalen = hleei_s->logdatalen;
+ break;
+
+ case sizeof(struct hleei_long):
+ /* long */
+ logdataptr = hleei_l->logdataptr;
+ logdatalen = hleei_l->logdatalen;
+ break;
+
+ default:
+ /* bad input block */
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ pcpes = (struct pcpes *)logdataptr;
+
+ struct hlei hlei = {
+ .ipblength = sizeof(hlei),
+ .hashdataptr = hleei_s->hashdataptr,
+ .hashdatalen = hleei_s->hashdatalen,
+ .pcrindex = hleei_s->pcrindex,
+ .logeventtype= pcpes->eventtype,
+ .logdataptr = logdataptr,
+ .logdatalen = logdatalen,
+ };
+
+ rc = hash_log_event(&hlei, &hleo);
+ if (rc)
+ goto err_exit;
+
+ hleeo->opblength = sizeof(struct hleeo);
+ hleeo->reserved = 0;
+ hleeo->eventnumber = hleo.eventnumber;
+
+ rc = tpm_extend(pcpes->digest, hleei_s->pcrindex);
+
+err_exit:
+ if (rc != 0) {
+ hleeo->opblength = 4;
+ hleeo->reserved = 0;
+ }
+
+ return rc;
+
+}
+
+
+static u32
+tss(struct ti *ti, struct to *to)
+{
+ u32 rc = 0;
+
+ if (is_preboot_if_shutdown() == 0) {
+ rc = TCG_PC_UNSUPPORTED;
+ } else {
+ rc = TCG_INTERFACE_SHUTDOWN;
+ }
+
+ to->opblength = sizeof(struct to);
+ to->reserved = 0;
+
+ return rc;
+}
+
+
+static u32
+compact_hash_log_extend_event(u8 *buffer,
+ u32 info,
+ u32 length,
+ u32 pcrindex,
+ u32 *edx_ptr)
+{
+ u32 rc = 0;
+ struct hleeo hleeo;
+ struct pcpes pcpes = {
+ .pcrindex = pcrindex,
+ .eventtype = EV_COMPACT_HASH,
+ .eventdatasize = sizeof(info),
+ .event = info,
+ };
+ struct hleei_short hleei = {
+ .ipblength = sizeof(hleei),
+ .hashdataptr = buffer,
+ .hashdatalen = length,
+ .pcrindex = pcrindex,
+ .logdataptr = &pcpes,
+ .logdatalen = sizeof(pcpes),
+ };
+
+ rc = hash_log_extend_event(&hleei, &hleeo);
+ if (rc == 0)
+ *edx_ptr = hleeo.eventnumber;
+
+ return rc;
+}
+
+
+void VISIBLE32FLAT
+tpm_interrupt_handler32(struct bregs *regs)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ set_cf(regs, 0);
+
+ if (!has_working_tpm()) {
+ regs->eax = TCG_GENERAL_ERROR;
+ return;
+ }
+
+ switch ((enum irq_ids)regs->al) {
+ case TCG_StatusCheck:
+ if (is_tpm_present() == 0) {
+ /* no TPM available */
+ regs->eax = TCG_PC_TPM_NOT_PRESENT;
+ } else {
+ regs->eax = 0;
+ regs->ebx = TCG_MAGIC;
+ regs->ch = TCG_VERSION_MAJOR;
+ regs->cl = TCG_VERSION_MINOR;
+ regs->edx = 0x0;
+ regs->esi = (u32)get_lasa_base_ptr(NULL);
+ regs->edi =
+ (u32)get_lasa_last_ptr(NULL, NULL);
+ }
+ break;
+
+ case TCG_HashLogExtendEvent:
+ regs->eax =
+ hash_log_extend_event(
+ (struct hleei_short *)input_buf32(regs),
+ (struct hleeo *)output_buf32(regs));
+ break;
+
+ case TCG_PassThroughToTPM:
+ regs->eax =
+ pass_through_to_tpm((struct pttti *)input_buf32(regs),
+ (struct pttto *)output_buf32(regs));
+ break;
+
+ case TCG_ShutdownPreBootInterface:
+ regs->eax = shutdown_preboot_interface();
+ break;
+
+ case TCG_HashLogEvent:
+ regs->eax = hash_log_event((struct hlei*)input_buf32(regs),
+ (struct hleo*)output_buf32(regs));
+ break;
+
+ case TCG_HashAll:
+ regs->eax =
+ hash_all((struct hai*)input_buf32(regs),
+ (u8 *)output_buf32(regs));
+ break;
+
+ case TCG_TSS:
+ regs->eax = tss((struct ti*)input_buf32(regs),
+ (struct to*)output_buf32(regs));
+ break;
+
+ case TCG_CompactHashLogExtendEvent:
+ regs->eax =
+ compact_hash_log_extend_event((u8 *)input_buf32(regs),
+ regs->esi,
+ regs->ecx,
+ regs->edx,
+ &regs->edx);
+ break;
+
+ default:
+ set_cf(regs, 1);
+ }
+
+ return;
+}
+
+/*
+ * Add a measurement to the log; the data at data_seg:data/length are
+ * appended to the TCG_PCClientPCREventStruct
+ *
+ * Input parameters:
+ * pcrIndex : which PCR to extend
+ * event_type : type of event; specs section on 'Event Types'
+ * info : pointer to info (e.g., string) to be added to log as-is
+ * info_length: length of the info
+ * data : pointer to the data (i.e., string) to be added to the log
+ * data_length: length of the data
+ */
+static u32
+tpm_add_measurement_to_log(u32 pcrIndex, u32 event_type,
+ const char *info, u32 info_length,
+ const u8 *data, u32 data_length)
+{
+ u32 rc = 0;
+ struct hleeo hleeo;
+ u8 _pcpes[offsetof(struct pcpes, event) + 400];
+ struct pcpes *pcpes = (struct pcpes *)_pcpes;
+
+ if (info_length < sizeof(_pcpes) - offsetof(struct pcpes, event)) {
+
+ pcpes->pcrindex = pcrIndex;
+ pcpes->eventtype = event_type;
+ memset(&pcpes->digest, 0x0, sizeof(pcpes->digest));
+ pcpes->eventdatasize = info_length;
+ memcpy(&pcpes->event, info, info_length);
+
+ struct hleei_short hleei = {
+ .ipblength = sizeof(hleei),
+ .hashdataptr = data,
+ .hashdatalen = data_length,
+ .pcrindex = pcrIndex,
+ .logdataptr = _pcpes,
+ .logdatalen = info_length + offsetof(struct pcpes, event),
+ };
+
+ rc = hash_log_extend_event(&hleei, &hleeo);
+ } else {
+ rc = TCG_GENERAL_ERROR;
+ }
+
+ return rc;
+}
+
+
+/*
+ * Add a measurement to the list of measurements
+ * pcrIndex : PCR to be extended
+ * event_type : type of event; specs section on 'Event Types'
+ * data : additional parameter; used as parameter for
+ * 'action index'
+ */
+static u32
+tpm_add_measurement(u32 pcrIndex,
+ u16 event_type,
+ const char *string)
+{
+ u32 rc;
+ u32 len;
+
+ switch (event_type) {
+ case EV_SEPARATOR:
+ len = sizeof(evt_separator);
+ rc = tpm_add_measurement_to_log(pcrIndex, event_type,
+ (char *)NULL, 0,
+ (u8 *)evt_separator, len);
+ break;
+
+ case EV_ACTION:
+ rc = tpm_add_measurement_to_log(pcrIndex, event_type,
+ string, strlen(string),
+ (u8 *)string, strlen(string));
+ break;
+
+ default:
+ rc = TCG_INVALID_INPUT_PARA;
+ }
+
+ return rc;
+}
+
+
+static u32
+tpm_calling_int19h(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ return tpm_add_measurement(4, EV_ACTION,
+ "Calling INT 19h");
+}
+
+/*
+ * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
+ */
+u32
+tpm_add_event_separators(void)
+{
+ u32 rc;
+ u32 pcrIndex = 0;
+
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ while (pcrIndex <= 7) {
+ rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL);
+ if (rc)
+ break;
+ pcrIndex ++;
+ }
+
+ return rc;
+}
+
+
+/*
+ * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to
+ * the list of measurements.
+ */
+static u32
+tpm_add_bootdevice(u32 bootcd, u32 bootdrv)
+{
+ const char *string;
+
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ switch (bootcd) {
+ case 0:
+ switch (bootdrv) {
+ case 0:
+ string = "Booting BCV device 00h (Floppy)";
+ break;
+
+ case 0x80:
+ string = "Booting BCV device 80h (HDD)";
+ break;
+
+ default:
+ string = "Booting unknown device";
+ break;
+ }
+
+ break;
+
+ default:
+ string = "Booting from CD ROM device";
+ }
+
+ return tpm_add_measurement_to_log(4, EV_ACTION,
+ string, strlen(string),
+ (u8 *)string, strlen(string));
+}
+
+
+/*
+ * Add measurement to the log about option rom scan
+ */
+u32
+tpm_start_option_rom_scan(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ return tpm_add_measurement(2, EV_ACTION,
+ "Start Option ROM Scan");
+}
+
+
+/*
+ * Add measurement to the log about an option rom
+ */
+u32
+tpm_option_rom(const void *addr, u32 len)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc;
+ struct pcctes_romex pcctes = {
+ .eventid = 7,
+ .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
+ };
+
+ rc = sha1((const u8 *)addr, len, pcctes.digest);
+ if (rc)
+ return rc;
+
+ return tpm_add_measurement_to_log(2,
+ EV_EVENT_TAG,
+ (const char *)&pcctes, sizeof(pcctes),
+ (u8 *)&pcctes, sizeof(pcctes));
+}
+
+
+u32
+tpm_smbios_measure(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc;
+ struct pcctes pcctes = {
+ .eventid = 1,
+ .eventdatasize = SHA1_BUFSIZE,
+ };
+ struct smbios_entry_point *sep = SMBiosAddr;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
+
+ if (!sep)
+ return 0;
+
+ rc = sha1((const u8 *)sep->structure_table_address,
+ sep->structure_table_length, pcctes.digest);
+ if (rc)
+ return rc;
+
+ return tpm_add_measurement_to_log(1,
+ EV_EVENT_TAG,
+ (const char *)&pcctes, sizeof(pcctes),
+ (u8 *)&pcctes, sizeof(pcctes));
+}
+
+
+/*
+ * Add a measurement related to Initial Program Loader to the log.
+ * Creates two log entries.
+ *
+ * Input parameter:
+ * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito
+ * addr : address where the IP data are located
+ * length : IP data length in bytes
+ */
+static u32
+tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length)
+{
+ u32 rc;
+ const char *string;
+
+ switch (bootcd) {
+ case IPL_EL_TORITO_1:
+ /* specs: see section 'El Torito' */
+ string = "EL TORITO IPL";
+ rc = tpm_add_measurement_to_log(4, EV_IPL,
+ string, strlen(string),
+ addr, length);
+ break;
+
+ case IPL_EL_TORITO_2:
+ /* specs: see section 'El Torito' */
+ string = "BOOT CATALOG";
+ rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
+ string, strlen(string),
+ addr, length);
+ break;
+
+ default:
+ /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
+ /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
+ string = "MBR";
+ rc = tpm_add_measurement_to_log(4, EV_IPL,
+ string, strlen(string),
+ addr, 0x1b8);
+
+ if (rc)
+ break;
+
+ /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
+ string = "MBR PARTITION_TABLE";
+ rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
+ string, strlen(string),
+ addr + 0x1b8, 0x48);
+ }
+
+ return rc;
+}
+
+u32
+tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc = tpm_add_bootdevice(0, bootdrv);
+ if (rc)
+ return rc;
+
+ return tpm_ipl(IPL_BCV, addr, length);
+}
+
+u32
+tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc = tpm_add_bootdevice(1, bootdrv);
+ if (rc)
+ return rc;
+
+ return tpm_ipl(IPL_EL_TORITO_1, addr, length);
+}
+
+u32
+tpm_add_cdrom_catalog(const u8 *addr, u32 length)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc = tpm_add_bootdevice(1, 0);
+ if (rc)
+ return rc;
+
+ return tpm_ipl(IPL_EL_TORITO_2, addr, length);
+}
+
+void
+tpm_s3_resume(void)
+{
+ u32 rc;
+ u32 returnCode;
+
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ if (!has_working_tpm())
+ return;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
+
+ rc = build_and_send_cmd(0, TPM_ORD_Startup,
+ Startup_ST_STATE, sizeof(Startup_ST_STATE),
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
+ returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ return;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+}
diff --git a/qemu/roms/seabios/src/tcgbios.h b/qemu/roms/seabios/src/tcgbios.h
new file mode 100644
index 000000000..4b7eaabef
--- /dev/null
+++ b/qemu/roms/seabios/src/tcgbios.h
@@ -0,0 +1,375 @@
+#ifndef TCGBIOS_H
+#define TCGBIOS_H
+
+#include "types.h"
+
+/* Define for section 12.3 */
+#define TCG_PC_OK 0x0
+#define TCG_PC_TPMERROR 0x1
+#define TCG_PC_LOGOVERFLOW 0x2
+#define TCG_PC_UNSUPPORTED 0x3
+
+#define TPM_ALG_SHA 0x4
+
+#define TCG_MAGIC 0x41504354L
+#define TCG_VERSION_MAJOR 1
+#define TCG_VERSION_MINOR 2
+
+#define TPM_OK 0x0
+#define TPM_RET_BASE 0x1
+#define TCG_GENERAL_ERROR (TPM_RET_BASE + 0x0)
+#define TCG_TPM_IS_LOCKED (TPM_RET_BASE + 0x1)
+#define TCG_NO_RESPONSE (TPM_RET_BASE + 0x2)
+#define TCG_INVALID_RESPONSE (TPM_RET_BASE + 0x3)
+#define TCG_INVALID_ACCESS_REQUEST (TPM_RET_BASE + 0x4)
+#define TCG_FIRMWARE_ERROR (TPM_RET_BASE + 0x5)
+#define TCG_INTEGRITY_CHECK_FAILED (TPM_RET_BASE + 0x6)
+#define TCG_INVALID_DEVICE_ID (TPM_RET_BASE + 0x7)
+#define TCG_INVALID_VENDOR_ID (TPM_RET_BASE + 0x8)
+#define TCG_UNABLE_TO_OPEN (TPM_RET_BASE + 0x9)
+#define TCG_UNABLE_TO_CLOSE (TPM_RET_BASE + 0xa)
+#define TCG_RESPONSE_TIMEOUT (TPM_RET_BASE + 0xb)
+#define TCG_INVALID_COM_REQUEST (TPM_RET_BASE + 0xc)
+#define TCG_INVALID_ADR_REQUEST (TPM_RET_BASE + 0xd)
+#define TCG_WRITE_BYTE_ERROR (TPM_RET_BASE + 0xe)
+#define TCG_READ_BYTE_ERROR (TPM_RET_BASE + 0xf)
+#define TCG_BLOCK_WRITE_TIMEOUT (TPM_RET_BASE + 0x10)
+#define TCG_CHAR_WRITE_TIMEOUT (TPM_RET_BASE + 0x11)
+#define TCG_CHAR_READ_TIMEOUT (TPM_RET_BASE + 0x12)
+#define TCG_BLOCK_READ_TIMEOUT (TPM_RET_BASE + 0x13)
+#define TCG_TRANSFER_ABORT (TPM_RET_BASE + 0x14)
+#define TCG_INVALID_DRV_FUNCTION (TPM_RET_BASE + 0x15)
+#define TCG_OUTPUT_BUFFER_TOO_SHORT (TPM_RET_BASE + 0x16)
+#define TCG_FATAL_COM_ERROR (TPM_RET_BASE + 0x17)
+#define TCG_INVALID_INPUT_PARA (TPM_RET_BASE + 0x18)
+#define TCG_TCG_COMMAND_ERROR (TPM_RET_BASE + 0x19)
+#define TCG_INTERFACE_SHUTDOWN (TPM_RET_BASE + 0x20)
+//define TCG_PC_UNSUPPORTED (TPM_RET_BASE + 0x21)
+#define TCG_PC_TPM_NOT_PRESENT (TPM_RET_BASE + 0x22)
+#define TCG_PC_TPM_DEACTIVATED (TPM_RET_BASE + 0x23)
+
+
+#define TPM_ORD_SelfTestFull 0x00000050
+#define TPM_ORD_ForceClear 0x0000005d
+#define TPM_ORD_GetCapability 0x00000065
+#define TPM_ORD_PhysicalEnable 0x0000006f
+#define TPM_ORD_PhysicalDisable 0x00000070
+#define TPM_ORD_SetOwnerInstall 0x00000071
+#define TPM_ORD_PhysicalSetDeactivated 0x00000072
+#define TPM_ORD_Startup 0x00000099
+#define TPM_ORD_PhysicalPresence 0x4000000a
+#define TPM_ORD_Extend 0x00000014
+#define TPM_ORD_SHA1Start 0x000000a0
+#define TPM_ORD_SHA1Update 0x000000a1
+#define TPM_ORD_SHA1Complete 0x000000a2
+#define TSC_ORD_ResetEstablishmentBit 0x4000000b
+
+
+#define TPM_ST_CLEAR 0x1
+#define TPM_ST_STATE 0x2
+#define TPM_ST_DEACTIVATED 0x3
+
+
+/* TPM command error codes */
+#define TPM_INVALID_POSTINIT 0x26
+#define TPM_BAD_LOCALITY 0x3d
+
+/* TPM command tags */
+#define TPM_TAG_RQU_CMD 0x00c1
+
+/* interrupt identifiers (al register) */
+enum irq_ids {
+ TCG_StatusCheck = 0,
+ TCG_HashLogExtendEvent = 1,
+ TCG_PassThroughToTPM = 2,
+ TCG_ShutdownPreBootInterface = 3,
+ TCG_HashLogEvent = 4,
+ TCG_HashAll = 5,
+ TCG_TSS = 6,
+ TCG_CompactHashLogExtendEvent = 7,
+};
+
+/* event types: 10.4.1 / table 11 */
+#define EV_POST_CODE 1
+#define EV_SEPARATOR 4
+#define EV_ACTION 5
+#define EV_EVENT_TAG 6
+#define EV_COMPACT_HASH 12
+#define EV_IPL 13
+#define EV_IPL_PARTITION_DATA 14
+
+
+#define STATUS_FLAG_SHUTDOWN (1 << 0)
+
+#define SHA1_BUFSIZE 20
+
+
+struct iovec
+{
+ size_t length;
+ void *data;
+};
+
+
+/* Input and Output blocks for the TCG BIOS commands */
+
+struct hleei_short
+{
+ u16 ipblength;
+ u16 reserved;
+ const void *hashdataptr;
+ u32 hashdatalen;
+ u32 pcrindex;
+ const void *logdataptr;
+ u32 logdatalen;
+} PACKED;
+
+
+struct hleei_long
+{
+ u16 ipblength;
+ u16 reserved;
+ void *hashdataptr;
+ u32 hashdatalen;
+ u32 pcrindex;
+ u32 reserved2;
+ void *logdataptr;
+ u32 logdatalen;
+} PACKED;
+
+
+struct hleeo
+{
+ u16 opblength;
+ u16 reserved;
+ u32 eventnumber;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+struct pttti
+{
+ u16 ipblength;
+ u16 reserved;
+ u16 opblength;
+ u16 reserved2;
+ u8 tpmopin[0];
+} PACKED;
+
+
+struct pttto
+{
+ u16 opblength;
+ u16 reserved;
+ u8 tpmopout[0];
+};
+
+
+struct hlei
+{
+ u16 ipblength;
+ u16 reserved;
+ const void *hashdataptr;
+ u32 hashdatalen;
+ u32 pcrindex;
+ u32 logeventtype;
+ const void *logdataptr;
+ u32 logdatalen;
+} PACKED;
+
+
+struct hleo
+{
+ u16 opblength;
+ u16 reserved;
+ u32 eventnumber;
+} PACKED;
+
+
+struct hai
+{
+ u16 ipblength;
+ u16 reserved;
+ const void *hashdataptr;
+ u32 hashdatalen;
+ u32 algorithmid;
+} PACKED;
+
+
+struct ti
+{
+ u16 ipblength;
+ u16 reserved;
+ u16 opblength;
+ u16 reserved2;
+ u8 tssoperandin[0];
+} PACKED;
+
+
+struct to
+{
+ u16 opblength;
+ u16 reserved;
+ u8 tssoperandout[0];
+} PACKED;
+
+
+struct pcpes
+{
+ u32 pcrindex;
+ u32 eventtype;
+ u8 digest[SHA1_BUFSIZE];
+ u32 eventdatasize;
+ u32 event;
+} PACKED;
+
+struct pcctes
+{
+ u32 eventid;
+ u32 eventdatasize;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+struct pcctes_romex
+{
+ u32 eventid;
+ u32 eventdatasize;
+ u16 reserved;
+ u16 pfa;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+#define TPM_REQ_HEADER \
+ u16 tag; \
+ u32 totlen; \
+ u32 ordinal;
+
+#define TPM_REQ_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32))
+
+#define TPM_RSP_HEADER \
+ u16 tag; \
+ u32 totlen; \
+ u32 errcode;
+
+#define TPM_RSP_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32))
+
+struct tpm_req_header {
+ TPM_REQ_HEADER;
+} PACKED;
+
+
+struct tpm_rsp_header {
+ TPM_RSP_HEADER;
+} PACKED;
+
+
+struct tpm_req_extend {
+ TPM_REQ_HEADER
+ u32 pcrindex;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+struct tpm_rsp_extend {
+ TPM_RSP_HEADER
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+struct tpm_req_getcap_perm_flags {
+ TPM_REQ_HEADER
+ u32 capArea;
+ u32 subCapSize;
+ u32 subCap;
+} PACKED;
+
+
+struct tpm_permanent_flags {
+ u16 tag;
+ u8 flags[20];
+} PACKED;
+
+
+enum permFlagsIndex {
+ PERM_FLAG_IDX_DISABLE = 0,
+ PERM_FLAG_IDX_OWNERSHIP,
+ PERM_FLAG_IDX_DEACTIVATED,
+ PERM_FLAG_IDX_READPUBEK,
+ PERM_FLAG_IDX_DISABLEOWNERCLEAR,
+ PERM_FLAG_IDX_ALLOW_MAINTENANCE,
+ PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK,
+ PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE,
+};
+
+
+struct tpm_res_getcap_perm_flags {
+ TPM_RSP_HEADER
+ u32 size;
+ struct tpm_permanent_flags perm_flags;
+} PACKED;
+
+
+struct tpm_res_getcap_ownerauth {
+ TPM_RSP_HEADER
+ u32 size;
+ u8 flag;
+} PACKED;
+
+
+struct tpm_res_getcap_timeouts {
+ TPM_RSP_HEADER
+ u32 size;
+ u32 timeouts[4];
+} PACKED;
+
+
+struct tpm_res_getcap_durations {
+ TPM_RSP_HEADER
+ u32 size;
+ u32 durations[3];
+} PACKED;
+
+
+struct tpm_res_sha1start {
+ TPM_RSP_HEADER
+ u32 max_num_bytes;
+} PACKED;
+
+
+struct tpm_res_sha1complete {
+ TPM_RSP_HEADER
+ u8 hash[20];
+} PACKED;
+
+struct pttti_extend {
+ struct pttti pttti;
+ struct tpm_req_extend req;
+} PACKED;
+
+
+struct pttto_extend {
+ struct pttto pttto;
+ struct tpm_rsp_extend rsp;
+} PACKED;
+
+
+enum ipltype {
+ IPL_BCV = 0,
+ IPL_EL_TORITO_1,
+ IPL_EL_TORITO_2
+};
+
+
+struct bregs;
+void tpm_interrupt_handler32(struct bregs *regs);
+
+void tpm_setup(void);
+void tpm_prepboot(void);
+void tpm_s3_resume(void);
+u32 tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length);
+u32 tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length);
+u32 tpm_add_cdrom_catalog(const u8 *addr, u32 length);
+u32 tpm_option_rom(const void *addr, u32 len);
+
+#endif /* TCGBIOS_H */
diff --git a/qemu/roms/seabios/src/types.h b/qemu/roms/seabios/src/types.h
index 097372cdb..19d9f6c14 100644
--- a/qemu/roms/seabios/src/types.h
+++ b/qemu/roms/seabios/src/types.h
@@ -70,7 +70,7 @@ extern void __force_link_error__only_in_16bit(void) __noreturn;
# define VARFSEG __section(".discard.varfseg." UNIQSEC) __VISIBLE __weak
// Designate a variable at a specific address in the f-segment.
# define VARFSEGFIXED(addr) __section(".discard.varfixed." UNIQSEC) __VISIBLE __weak
-// Verify a variable is only accessable via 32bit "init" functions
+// Verify a variable is only accessible via 32bit "init" functions
# define VARVERIFY32INIT __section(".discard.varinit." UNIQSEC)
// Designate top-level assembler as 16bit only.
# define ASM16(code) __ASM(code)
diff --git a/qemu/roms/seabios/src/util.h b/qemu/roms/seabios/src/util.h
index 09bb8a9f3..cba3359d5 100644
--- a/qemu/roms/seabios/src/util.h
+++ b/qemu/roms/seabios/src/util.h
@@ -43,17 +43,17 @@ void enable_bootsplash(void);
void disable_bootsplash(void);
// cdrom.c
-extern u8 CDRom_locks[];
extern struct eltorito_s CDEmu;
extern struct drive_s *cdemu_drive_gf;
struct disk_op_s;
-int process_cdemu_op(struct disk_op_s *op);
+int cdemu_process_op(struct disk_op_s *op);
void cdrom_prepboot(void);
int cdrom_boot(struct drive_s *drive_g);
// clock.c
void clock_setup(void);
void handle_1583(struct bregs *regs);
+void clock_poll_irq(void);
u32 irqtimer_calc_ticks(u32 count);
u32 irqtimer_calc(u32 msecs);
int irqtimer_check(u32 end);
@@ -75,6 +75,7 @@ u32 find_resume_vector(void);
void acpi_reboot(void);
void find_acpi_features(void);
extern struct smbios_entry_point *SMBiosAddr;
+struct smbios_entry_point *get_smbios_entry_point();
void copy_smbios(void *pos);
void display_uuid(void);
void copy_table(void *pos);
@@ -104,6 +105,9 @@ void mptable_setup(void);
// fw/mtrr.c
void mtrr_setup(void);
+// fw/multiboot.c
+void multiboot_init(void);
+
// fw/pciinit.c
extern const u8 pci_irqs[4];
void pci_setup(void);
@@ -139,15 +143,15 @@ extern struct floppy_ext_dbt_s diskette_param_table2;
void floppy_setup(void);
struct drive_s *init_floppy(int floppyid, int ftype);
int find_floppy_type(u32 size);
-int process_floppy_op(struct disk_op_s *op);
+int floppy_process_op(struct disk_op_s *op);
void floppy_tick(void);
// hw/ramdisk.c
void ramdisk_setup(void);
-int process_ramdisk_op(struct disk_op_s *op);
+int ramdisk_process_op(struct disk_op_s *op);
// hw/sdcard.c
-int process_sdcard_op(struct disk_op_s *op);
+int sdcard_process_op(struct disk_op_s *op);
void sdcard_setup(void);
// hw/timer.c
@@ -232,6 +236,6 @@ void vgahook_setup(struct pci_device *pci);
// version (auto generated file out/version.c)
-extern const char VERSION[];
+extern const char VERSION[], BUILDINFO[];
#endif // util.h
diff --git a/qemu/roms/seabios/src/version.c b/qemu/roms/seabios/src/version.c
new file mode 100644
index 000000000..a8a58cf09
--- /dev/null
+++ b/qemu/roms/seabios/src/version.c
@@ -0,0 +1,5 @@
+// Place build generated version into a C variable
+#include "autoversion.h"
+
+char VERSION[] = BUILD_VERSION;
+char BUILDINFO[] = BUILD_TOOLS;
diff --git a/qemu/roms/seabios/src/vgahooks.c b/qemu/roms/seabios/src/vgahooks.c
index 6a4acfeaf..48efb086c 100644
--- a/qemu/roms/seabios/src/vgahooks.c
+++ b/qemu/roms/seabios/src/vgahooks.c
@@ -124,7 +124,7 @@ getAMDRamSpeed(void)
/* int 0x15 - 5f18
- ECX = unknown/dont care
+ ECX = unknown/don't care
EBX[3..0] Frame Buffer Size 2^N MiB
EBX[7..4] Memory speed:
0: SDR 66Mhz
diff --git a/qemu/roms/seabios/src/x86.h b/qemu/roms/seabios/src/x86.h
index 7798b1c17..53378e9ed 100644
--- a/qemu/roms/seabios/src/x86.h
+++ b/qemu/roms/seabios/src/x86.h
@@ -75,14 +75,22 @@ static inline void __cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
: "0" (index));
}
-static inline u32 getcr0(void) {
+static inline u32 cr0_read(void) {
u32 cr0;
asm("movl %%cr0, %0" : "=r"(cr0));
return cr0;
}
-static inline void setcr0(u32 cr0) {
+static inline void cr0_write(u32 cr0) {
asm("movl %0, %%cr0" : : "r"(cr0));
}
+static inline void cr0_mask(u32 off, u32 on) {
+ cr0_write((cr0_read() & ~off) | on);
+}
+static inline u16 cr0_vm86_read(void) {
+ u16 cr0;
+ asm("smsww %0" : "=r"(cr0));
+ return cr0;
+}
static inline u64 rdmsr(u32 index)
{
@@ -124,6 +132,13 @@ static inline u32 getesp(void) {
return esp;
}
+static inline u32 rol(u32 val, u16 rol) {
+ u32 res;
+ asm volatile("roll %%cl, %%eax"
+ : "=a" (res) : "a" (val), "c" (rol));
+ return res;
+}
+
static inline void outb(u8 value, u16 port) {
__asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
}
@@ -175,6 +190,14 @@ static inline void outsl(u16 port, u32 *data, u32 count) {
: "+c"(count), "+S"(data) : "d"(port) : "memory");
}
+/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */
+static inline void smp_rmb(void) {
+ barrier();
+}
+static inline void smp_wmb(void) {
+ barrier();
+}
+
static inline void writel(void *addr, u32 val) {
barrier();
*(volatile u32 *)addr = val;