summaryrefslogtreecommitdiffstats
path: root/qemu/roms/seabios/src/hw
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/seabios/src/hw')
-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
43 files changed, 1614 insertions, 635 deletions
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 */