[SeaBIOS] [PATCH 05/14] lsi-scsi: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

The lsi-scsi controller code will now explicitly set PCI_COMMAND_IO
instead of assuming it has already been enabled.

Signed-off-by: Kevin O'Connor 
---
 src/hw/lsi-scsi.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/hw/lsi-scsi.c b/src/hw/lsi-scsi.c
index ad33528..2629b5f 100644
--- a/src/hw/lsi-scsi.c
+++ b/src/hw/lsi-scsi.c
@@ -172,15 +172,14 @@ lsi_scsi_scan_target(struct pci_device *pci, u32 iobase, 
u8 target)
 static void
 init_lsi_scsi(struct pci_device *pci)
 {
-u16 bdf = pci->bdf;
-u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
-& PCI_BASE_ADDRESS_IO_MASK;
-
-pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+u32 iobase = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
+if (!iobase)
+return;
+pci_enable_busmaster(pci);
 
 dprintf(1, "found lsi53c895a at %02x:%02x.%x, io @ %x\n",
-pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
-pci_bdf_to_fn(bdf), iobase);
+pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+pci_bdf_to_fn(pci->bdf), iobase);
 
 // reset
 outb(LSI_ISTAT0_SRST, iobase + LSI_REG_ISTAT0);
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 01/14] pci: Add helper functions for internal driver BAR handling

2016-02-02 Thread Kevin O'Connor
Add functions to verify and obtain PCI BARs (Base Address Registers).
These new functions check that the requested BAR is of the right type
and appears valid.

Signed-off-by: Kevin O'Connor 
---
 src/hw/pci.c | 58 ++
 src/hw/pci.h |  3 +++
 2 files changed, 61 insertions(+)

diff --git a/src/hw/pci.c b/src/hw/pci.c
index a241d06..86b7d54 100644
--- a/src/hw/pci.c
+++ b/src/hw/pci.c
@@ -10,6 +10,7 @@
 #include "pci.h" // pci_config_writel
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "romfile.h" // romfile_loadint
+#include "stacks.h" // wait_preempt
 #include "string.h" // memset
 #include "util.h" // udelay
 #include "x86.h" // outl
@@ -271,6 +272,63 @@ int pci_bridge_has_region(struct pci_device *pci,
 return pci_config_readb(pci->bdf, base) != 0;
 }
 
+// Enable PCI bus-mastering (ie, DMA) support on a pci device
+void
+pci_enable_busmaster(struct pci_device *pci)
+{
+ASSERT32FLAT();
+wait_preempt();
+pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+}
+
+// Verify an IO bar and return it to the caller
+u16
+pci_enable_iobar(struct pci_device *pci, u32 addr)
+{
+ASSERT32FLAT();
+wait_preempt();
+u32 bar = pci_config_readl(pci->bdf, addr);
+if (!(bar & PCI_BASE_ADDRESS_SPACE_IO)) {
+warn_internalerror();
+return 0;
+}
+bar &= PCI_BASE_ADDRESS_IO_MASK;
+if (bar == 0 || bar > 0x) {
+warn_internalerror();
+return 0;
+}
+pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO);
+return bar;
+}
+
+// Verify a memory bar and return it to the caller
+void *
+pci_enable_membar(struct pci_device *pci, u32 addr)
+{
+ASSERT32FLAT();
+wait_preempt();
+u32 bar = pci_config_readl(pci->bdf, addr);
+if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+warn_internalerror();
+return NULL;
+}
+if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+u32 high = pci_config_readl(pci->bdf, addr+4);
+if (high) {
+dprintf(1, "Can not map memory bar over 4Gig\n");
+return NULL;
+}
+}
+bar &= PCI_BASE_ADDRESS_MEM_MASK;
+if (bar + 4*1024*1024 < 20*1024*1024) {
+// Bar doesn't look valid (it is in last 4M or first 16M)
+warn_internalerror();
+return NULL;
+}
+pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+return (void*)bar;
+}
+
 void
 pci_reboot(void)
 {
diff --git a/src/hw/pci.h b/src/hw/pci.h
index fc5e7b9..8e39753 100644
--- a/src/hw/pci.h
+++ b/src/hw/pci.h
@@ -126,6 +126,9 @@ struct pci_device *pci_find_init_device(const struct 
pci_device_id *ids
 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_enable_busmaster(struct pci_device *pci);
+u16 pci_enable_iobar(struct pci_device *pci, u32 addr);
+void *pci_enable_membar(struct pci_device *pci, u32 addr);
 void pci_reboot(void);
 
 #endif
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 06/14] megasas: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

After this change, the megasas driver will no longer enable
PCI_COMMAND_MEMORY accesses, as the megasas driver doesn't actually
map any BARs as memory.

Signed-off-by: Kevin O'Connor 
---
 src/hw/megasas.c | 18 --
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/src/hw/megasas.c b/src/hw/megasas.c
index cb1a2a6..31426e7 100644
--- a/src/hw/megasas.c
+++ b/src/hw/megasas.c
@@ -359,20 +359,18 @@ static int megasas_transition_to_ready(struct pci_device 
*pci, u32 ioaddr)
 static void
 init_megasas(struct pci_device *pci)
 {
-u16 bdf = pci->bdf;
-u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_2)
-& PCI_BASE_ADDRESS_IO_MASK;
-
+u32 bar = PCI_BASE_ADDRESS_2;
+if (!(pci_config_readl(pci->bdf, bar) & PCI_BASE_ADDRESS_IO_MASK))
+bar = PCI_BASE_ADDRESS_0;
+u32 iobase = pci_enable_iobar(pci, bar);
 if (!iobase)
-iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
-& PCI_BASE_ADDRESS_IO_MASK;
+return;
+pci_enable_busmaster(pci);
 
 dprintf(1, "found MegaRAID SAS at %02x:%02x.%x, io @ %x\n",
-pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
-pci_bdf_to_fn(bdf), iobase);
+pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+pci_bdf_to_fn(pci->bdf), iobase);
 
-pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
 // reset
 if (megasas_transition_to_ready(pci, iobase) == 0)
 megasas_scan_target(pci, iobase);
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 03/14] ata: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

The ATA controller code will now explicitly set PCI_COMMAND_IO instead
of assuming it has already been enabled.

Signed-off-by: Kevin O'Connor 
---
 src/hw/ata.c | 25 -
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/src/hw/ata.c b/src/hw/ata.c
index fc1..7aaf2f1 100644
--- a/src/hw/ata.c
+++ b/src/hw/ata.c
@@ -946,24 +946,23 @@ static void
 init_pciata(struct pci_device *pci, u8 prog_if)
 {
 pci->have_driver = 1;
-u16 bdf = pci->bdf;
-u8 pciirq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+u8 pciirq = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
 int master = 0;
 if (CONFIG_ATA_DMA && prog_if & 0x80) {
 // Check for bus-mastering.
-u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_4);
+u32 bar = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_4);
 if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
-master = bar & PCI_BASE_ADDRESS_IO_MASK;
-pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+master = pci_enable_iobar(pci, PCI_BASE_ADDRESS_4);
+pci_enable_busmaster(pci);
 }
 }
 
 u32 port1, port2, irq;
 if (prog_if & 1) {
-port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_0)
- & PCI_BASE_ADDRESS_IO_MASK);
-port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_1)
- & PCI_BASE_ADDRESS_IO_MASK);
+port1 = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
+port2 = pci_enable_iobar(pci, PCI_BASE_ADDRESS_1);
+if (!port1 || !port2)
+return;
 irq = pciirq;
 } else {
 port1 = PORT_ATA1_CMD_BASE;
@@ -973,10 +972,10 @@ init_pciata(struct pci_device *pci, u8 prog_if)
 init_controller(pci, 0, irq, port1, port2, master);
 
 if (prog_if & 4) {
-port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2)
- & PCI_BASE_ADDRESS_IO_MASK);
-port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_3)
- & PCI_BASE_ADDRESS_IO_MASK);
+port1 = pci_enable_iobar(pci, PCI_BASE_ADDRESS_2);
+port2 = pci_enable_iobar(pci, PCI_BASE_ADDRESS_3);
+if (!port1 || !port2)
+return;
 irq = pciirq;
 } else {
 port1 = PORT_ATA2_CMD_BASE;
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 12/14] xhci: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

The xhci controller code will now explicitly set PCI_COMMAND_MEMORY
instead of assuming it has already been enabled.

Signed-off-by: Kevin O'Connor 
---
 src/hw/usb-xhci.c | 27 ++-
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c
index ad541ab..af09592 100644
--- a/src/hw/usb-xhci.c
+++ b/src/hw/usb-xhci.c
@@ -230,7 +230,6 @@ struct usb_xhci_s {
 struct usb_s usb;
 
 /* devinfo */
-u32  baseaddr;
 u32  xcap;
 u32  ports;
 u32  slots;
@@ -527,20 +526,21 @@ fail:
 static void
 xhci_controller_setup(struct pci_device *pci)
 {
+void *baseaddr = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+if (!baseaddr)
+return;
+
 struct usb_xhci_s *xhci = malloc_high(sizeof(*xhci));
 if (!xhci) {
 warn_noalloc();
 return;
 }
 memset(xhci, 0, sizeof(*xhci));
-
-xhci->baseaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
-& PCI_BASE_ADDRESS_MEM_MASK;
-xhci->caps  = (void*)(xhci->baseaddr);
-xhci->op= (void*)(xhci->baseaddr + readb(&xhci->caps->caplength));
-xhci->pr= (void*)(xhci->baseaddr + readb(&xhci->caps->caplength) + 
0x400);
-xhci->db= (void*)(xhci->baseaddr + readl(&xhci->caps->dboff));
-xhci->ir= (void*)(xhci->baseaddr + readl(&xhci->caps->rtsoff) + 0x20);
+xhci->caps  = baseaddr;
+xhci->op= baseaddr + readb(&xhci->caps->caplength);
+xhci->pr= baseaddr + readb(&xhci->caps->caplength) + 0x400;
+xhci->db= baseaddr + readl(&xhci->caps->dboff);
+xhci->ir= baseaddr + readl(&xhci->caps->rtsoff) + 0x20;
 
 u32 hcs1 = readl(&xhci->caps->hcsparams1);
 u32 hcc  = readl(&xhci->caps->hccparams);
@@ -559,9 +559,10 @@ xhci_controller_setup(struct pci_device *pci)
 , xhci->ports, xhci->slots, xhci->context64 ? 64 : 32);
 
 if (xhci->xcap) {
-u32 off, addr = xhci->baseaddr + xhci->xcap;
+u32 off;
+void *addr = baseaddr + xhci->xcap;
 do {
-struct xhci_xcap *xcap = (void*)addr;
+struct xhci_xcap *xcap = addr;
 u32 ports, name, cap = readl(&xcap->cap);
 switch (cap & 0xff) {
 case 0x02:
@@ -580,7 +581,7 @@ xhci_controller_setup(struct pci_device *pci)
 , ports >> 16);
 break;
 default:
-dprintf(1, "XHCIextcap 0x%x @ %x\n", cap & 0xff, addr);
+dprintf(1, "XHCIextcap 0x%x @ %p\n", cap & 0xff, addr);
 break;
 }
 off = (cap >> 8) & 0xff;
@@ -596,7 +597,7 @@ xhci_controller_setup(struct pci_device *pci)
 return;
 }
 
-pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+pci_enable_busmaster(pci);
 
 run_thread(configure_xhci, xhci);
 }
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 10/14] ohci: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

Signed-off-by: Kevin O'Connor 
---
 src/hw/usb-ohci.c | 17 -
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c
index 0c0bf60..3d55d48 100644
--- a/src/hw/usb-ohci.c
+++ b/src/hw/usb-ohci.c
@@ -268,6 +268,10 @@ free:
 static void
 ohci_controller_setup(struct pci_device *pci)
 {
+struct ohci_regs *regs = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+if (!regs)
+return;
+
 struct usb_ohci_s *cntl = malloc_tmphigh(sizeof(*cntl));
 if (!cntl) {
 warn_noalloc();
@@ -276,18 +280,13 @@ ohci_controller_setup(struct pci_device *pci)
 memset(cntl, 0, sizeof(*cntl));
 cntl->usb.pci = pci;
 cntl->usb.type = USB_TYPE_OHCI;
-
-u16 bdf = pci->bdf;
-u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
-cntl->regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
+cntl->regs = regs;
 
 dprintf(1, "OHCI init on dev %02x:%02x.%x (regs=%p)\n"
-, pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
-, pci_bdf_to_fn(bdf), cntl->regs);
+, pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)
+, pci_bdf_to_fn(pci->bdf), cntl->regs);
 
-// Enable bus mastering and memory access.
-pci_config_maskw(bdf, PCI_COMMAND
- , 0, PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY);
+pci_enable_busmaster(pci);
 
 // XXX - check for and disable SMM control?
 
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 09/14] ehci: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

The ehci controller code will now explicitly set PCI_COMMAND_MEMORY
instead of assuming it has already been enabled.

Signed-off-by: Kevin O'Connor 
---
 src/hw/usb-ehci.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c
index a519455..57ce5a8 100644
--- a/src/hw/usb-ehci.c
+++ b/src/hw/usb-ehci.c
@@ -295,9 +295,9 @@ fail:
 static void
 ehci_controller_setup(struct pci_device *pci)
 {
-u16 bdf = pci->bdf;
-u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
-struct ehci_caps *caps = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
+struct ehci_caps *caps = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+if (!caps)
+return;
 u32 hcc_params = readl(&caps->hccparams);
 
 struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl));
@@ -316,10 +316,10 @@ ehci_controller_setup(struct pci_device *pci)
 PendingEHCI++;
 
 dprintf(1, "EHCI init on dev %02x:%02x.%x (regs=%p)\n"
-, pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
-, pci_bdf_to_fn(bdf), cntl->regs);
+, pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)
+, pci_bdf_to_fn(pci->bdf), cntl->regs);
 
-pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+pci_enable_busmaster(pci);
 
 // XXX - check for and disable SMM control?
 
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 04/14] esp-scsi: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

The esp-scsi controller code will now explicitly set PCI_COMMAND_IO
instead of assuming it has already been enabled.

Signed-off-by: Kevin O'Connor 
---
 src/hw/esp-scsi.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/hw/esp-scsi.c b/src/hw/esp-scsi.c
index d4e47e3..cf2cc11 100644
--- a/src/hw/esp-scsi.c
+++ b/src/hw/esp-scsi.c
@@ -192,15 +192,14 @@ esp_scsi_scan_target(struct pci_device *pci, u32 iobase, 
u8 target)
 static void
 init_esp_scsi(struct pci_device *pci)
 {
-u16 bdf = pci->bdf;
-u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
-& PCI_BASE_ADDRESS_IO_MASK;
+u32 iobase = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
+if (!iobase)
+return;
+pci_enable_busmaster(pci);
 
 dprintf(1, "found esp at %02x:%02x.%x, io @ %x\n",
-pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
-pci_bdf_to_fn(bdf), iobase);
-
-pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+pci_bdf_to_fn(pci->bdf), iobase);
 
 // reset
 outb(ESP_CMD_RESET, iobase + ESP_CMD);
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 08/14] sdcard: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

After this change, the sdcard driver will no longer enable
PCI_COMMAND_IO or PCI_COMMAND_MASTER accesses, as the sdcard driver
doesn't actually use IO BARs or implement DMA.

Signed-off-by: Kevin O'Connor 
---
 src/hw/sdcard.c | 14 ++
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/src/hw/sdcard.c b/src/hw/sdcard.c
index db3bbe1..1524b51 100644
--- a/src/hw/sdcard.c
+++ b/src/hw/sdcard.c
@@ -7,11 +7,11 @@
 #include "block.h" // struct drive_s
 #include "malloc.h" // malloc_fseg
 #include "output.h" // znprintf
-#include "pci.h" // pci_config_readl
+#include "pci.h" // foreachpci
 #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 "stacks.h" // yield
 #include "std/disk.h" // DISK_RET_SUCCESS
 #include "string.h" // memset
 #include "util.h" // boot_add_hd
@@ -525,14 +525,12 @@ 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);
+struct sdhci_s *regs = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+if (!regs)
+return;
 int prio = bootprio_find_pci_device(pci);
-sdcard_controller_setup((void*)regs, prio);
+sdcard_controller_setup(regs, prio);
 }
 
 static void
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 14/14] pci: Consistently set pci->have_drivers for devices with internal drivers

2016-02-02 Thread Kevin O'Connor
Set the pci->have_drivers flag for any device that calls
pci_enable_x() to ensure that the flag is consistently set on any
device with an internal driver.  Setting this flag prevents an option
rom on the device from being executed.

Signed-off-by: Kevin O'Connor 
---
 src/hw/ata.c| 1 -
 src/hw/pci.c| 3 +++
 src/hw/sdcard.c | 1 +
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/hw/ata.c b/src/hw/ata.c
index 7aaf2f1..12dab96 100644
--- a/src/hw/ata.c
+++ b/src/hw/ata.c
@@ -945,7 +945,6 @@ init_controller(struct pci_device *pci, int chanid, int irq
 static void
 init_pciata(struct pci_device *pci, u8 prog_if)
 {
-pci->have_driver = 1;
 u8 pciirq = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
 int master = 0;
 if (CONFIG_ATA_DMA && prog_if & 0x80) {
diff --git a/src/hw/pci.c b/src/hw/pci.c
index 86b7d54..76c293c 100644
--- a/src/hw/pci.c
+++ b/src/hw/pci.c
@@ -279,6 +279,7 @@ pci_enable_busmaster(struct pci_device *pci)
 ASSERT32FLAT();
 wait_preempt();
 pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+pci->have_driver = 1;
 }
 
 // Verify an IO bar and return it to the caller
@@ -298,6 +299,7 @@ pci_enable_iobar(struct pci_device *pci, u32 addr)
 return 0;
 }
 pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO);
+pci->have_driver = 1;
 return bar;
 }
 
@@ -326,6 +328,7 @@ pci_enable_membar(struct pci_device *pci, u32 addr)
 return NULL;
 }
 pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+pci->have_driver = 1;
 return (void*)bar;
 }
 
diff --git a/src/hw/sdcard.c b/src/hw/sdcard.c
index 1524b51..68a5e56 100644
--- a/src/hw/sdcard.c
+++ b/src/hw/sdcard.c
@@ -562,6 +562,7 @@ sdcard_setup(void)
 if (pci->class != PCI_CLASS_SYSTEM_SDHCI || pci->prog_if >= 2)
 // Not an SDHCI controller following SDHCI spec
 continue;
+pci->have_driver = 1; // Note driver present prior to starting thread
 run_thread(sdcard_pci_setup, pci);
 }
 }
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 13/14] virtio: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

This patch also converts cap->addr from a 'u32' to a union storing a
'u32' or a 'void*'.  This makes it more clear when the address is a
virtual memory address.

The virtio controller code will now explicitly set PCI_COMMAND_MEMORY
and/or PCI_COMMAND_IO instead of assuming it has already been enabled.

Signed-off-by: Kevin O'Connor 
---
 src/hw/virtio-pci.c | 36 
 src/hw/virtio-pci.h | 32 ++--
 2 files changed, 38 insertions(+), 30 deletions(-)

diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c
index 6df5194..f1e30a2 100644
--- a/src/hw/virtio-pci.c
+++ b/src/hw/virtio-pci.c
@@ -100,16 +100,14 @@ void vp_reset(struct vp_device *vp)
 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;
+u32 offset = vq->queue_notify_off * vp->notify_off_multiplier;
 if (vp->notify.is_io) {
-outw(vq->queue_index, addr);
+outw(vq->queue_index, vp->notify.ioaddr + offset);
 } else {
-writew((void*)addr, vq->queue_index);
+writew(vp->notify.memaddr + offset, vq->queue_index);
 }
 dprintf(9, "vp notify %x (%d) -- 0x%x\n",
-addr, 2, vq->queue_index);
+vp->notify.ioaddr, 2, vq->queue_index);
 } else {
 vp_write(&vp->legacy, virtio_pci_legacy, queue_notify, 
vq->queue_index);
 }
@@ -208,7 +206,7 @@ void vp_init_simple(struct vp_device *vp, struct pci_device 
*pci)
 {
 u8 cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, 0);
 struct vp_cap *vp_cap;
-u32 addr, offset, mul;
+u32 offset, mul;
 u8 type;
 
 memset(vp, 0, sizeof(*vp));
@@ -240,19 +238,24 @@ void vp_init_simple(struct vp_device *vp, struct 
pci_device *pci)
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) {
+u32 bar = PCI_BASE_ADDRESS_0 + 4 * vp_cap->bar;
+if (pci_config_readl(pci->bdf, bar) & PCI_BASE_ADDRESS_SPACE_IO) {
 vp_cap->is_io = 1;
-addr &= PCI_BASE_ADDRESS_IO_MASK;
+u32 addr = pci_enable_iobar(pci, bar);
+if (!addr)
+return;
+vp_cap->ioaddr = addr + offset;
 } else {
 vp_cap->is_io = 0;
-addr &= PCI_BASE_ADDRESS_MEM_MASK;
+void *addr = pci_enable_membar(pci, bar);
+if (!addr)
+return;
+vp_cap->memaddr = addr + offset;
 }
-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->cap, type, vp_cap->bar, vp_cap->ioaddr, offset,
 vp_cap->is_io ? "io" : "mmio");
 }
 
@@ -267,13 +270,14 @@ void vp_init_simple(struct vp_device *vp, struct 
pci_device *pci)
 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.ioaddr = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
+if (!vp->legacy.ioaddr)
+return;
 vp->legacy.is_io = 1;
 }
 
 vp_reset(vp);
-pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+pci_enable_busmaster(pci);
 vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE |
   VIRTIO_CONFIG_S_DRIVER );
 }
diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h
index b11c355..ff8454e 100644
--- a/src/hw/virtio-pci.h
+++ b/src/hw/virtio-pci.h
@@ -86,7 +86,10 @@ typedef struct virtio_pci_isr {
 /* --- driver structs --- */
 
 struct vp_cap {
-u32 addr;
+union {
+void *memaddr;
+u32 ioaddr;
+};
 u8 cap;
 u8 bar;
 u8 is_io;
@@ -100,10 +103,10 @@ struct vp_device {
 
 static inline u64 _vp_read(struct vp_cap *cap, u32 offset, u8 size)
 {
-u32 addr = cap->addr + offset;
 u64 var;
 
 if (cap->is_io) {
+u32 addr = cap->ioaddr + offset;
 switch (size) {
 case 8:
 var = inl(addr);
@@ -122,34 +125,34 @@ static inline u64 _vp_read(struct vp_cap *cap, u32 
offset, u8 size)
  

[SeaBIOS] [PATCH 07/14] pvscsi: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

The pvscsi controller code will now explicitly set PCI_COMMAND_MEMORY
instead of assuming it has already been enabled.

Signed-off-by: Kevin O'Connor 
---
 src/hw/pvscsi.c | 17 -
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/src/hw/pvscsi.c b/src/hw/pvscsi.c
index fa20efe..101a9c5 100644
--- a/src/hw/pvscsi.c
+++ b/src/hw/pvscsi.c
@@ -298,21 +298,20 @@ pvscsi_scan_target(struct pci_device *pci, void *iobase,
 static void
 init_pvscsi(struct pci_device *pci)
 {
-struct pvscsi_ring_dsc_s *ring_dsc = NULL;
-int i;
-u16 bdf = pci->bdf;
-void *iobase = (void*)(pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
-   & PCI_BASE_ADDRESS_MEM_MASK);
-
-pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+void *iobase = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+if (!iobase)
+return;
+pci_enable_busmaster(pci);
 
 dprintf(1, "found pvscsi at %02x:%02x.%x, io @ %p\n",
-pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
-pci_bdf_to_fn(bdf), iobase);
+pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+pci_bdf_to_fn(pci->bdf), iobase);
 
 pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
 
+struct pvscsi_ring_dsc_s *ring_dsc = NULL;
 pvscsi_init_rings(iobase, &ring_dsc);
+int i;
 for (i = 0; i < 7; i++)
 pvscsi_scan_target(pci, iobase, ring_dsc, i);
 
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 11/14] uhci: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

The uhci controller code will now explicitly set PCI_COMMAND_IO
instead of assuming it has already been enabled.

Signed-off-by: Kevin O'Connor 
---
 src/hw/usb-uhci.c | 16 +---
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/src/hw/usb-uhci.c b/src/hw/usb-uhci.c
index 7a11510..3b949e4 100644
--- a/src/hw/usb-uhci.c
+++ b/src/hw/usb-uhci.c
@@ -244,7 +244,10 @@ fail:
 static void
 uhci_controller_setup(struct pci_device *pci)
 {
-u16 bdf = pci->bdf;
+u16 iobase = pci_enable_iobar(pci, PCI_BASE_ADDRESS_4);
+if (!iobase)
+return;
+
 struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl));
 if (!cntl) {
 warn_noalloc();
@@ -253,16 +256,15 @@ uhci_controller_setup(struct pci_device *pci)
 memset(cntl, 0, sizeof(*cntl));
 cntl->usb.pci = pci;
 cntl->usb.type = USB_TYPE_UHCI;
-cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4)
-& PCI_BASE_ADDRESS_IO_MASK);
+cntl->iobase = iobase;
 
 dprintf(1, "UHCI init on dev %02x:%02x.%x (io=%x)\n"
-, pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
-, pci_bdf_to_fn(bdf), cntl->iobase);
+, pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)
+, pci_bdf_to_fn(pci->bdf), cntl->iobase);
 
-pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+pci_enable_busmaster(pci);
 
-reset_uhci(cntl, bdf);
+reset_uhci(cntl, pci->bdf);
 
 run_thread(configure_uhci, cntl);
 }
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 02/14] ahci: Convert to new PCI BAR helper functions

2016-02-02 Thread Kevin O'Connor
Use the pci_enable_x() functions.

This patch also converts cntl->iobase from a 'u32' to a 'void*' so
that it is clear that the address is a virtual memory address.

After this change, the AHCI driver will no longer enable
PCI_COMMAND_IO io accesses, as the AHCI driver doesn't actually
attempt IO accesses to the device.

Signed-off-by: Kevin O'Connor 
---
 src/hw/ahci.c | 35 ---
 src/hw/ahci.h |  3 +--
 2 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/src/hw/ahci.c b/src/hw/ahci.c
index 83b747c..5401cca 100644
--- a/src/hw/ahci.c
+++ b/src/hw/ahci.c
@@ -71,14 +71,12 @@ static void sata_prep_atapi(struct sata_cmd_fis *fis, u16 
blocksize)
 // ahci register access helpers
 static u32 ahci_ctrl_readl(struct ahci_ctrl_s *ctrl, u32 reg)
 {
-u32 addr = ctrl->iobase + reg;
-return readl((void*)addr);
+return readl(ctrl->iobase + reg);
 }
 
 static void ahci_ctrl_writel(struct ahci_ctrl_s *ctrl, u32 reg, u32 val)
 {
-u32 addr = ctrl->iobase + reg;
-writel((void*)addr, val);
+writel(ctrl->iobase + reg, val);
 }
 
 static u32 ahci_port_to_ctrl(u32 pnr, u32 port_reg)
@@ -567,31 +565,30 @@ ahci_port_detect(void *data)
 static void
 ahci_controller_setup(struct pci_device *pci)
 {
-struct ahci_ctrl_s *ctrl = malloc_fseg(sizeof(*ctrl));
 struct ahci_port_s *port;
-u16 bdf = pci->bdf;
 u32 val, pnr, max;
 
-if (!ctrl) {
-warn_noalloc();
+if (create_bounce_buf() < 0)
 return;
-}
 
-if (create_bounce_buf() < 0) {
+void *iobase = pci_enable_membar(pci, PCI_BASE_ADDRESS_5);
+if (!iobase)
+return;
+
+struct ahci_ctrl_s *ctrl = malloc_fseg(sizeof(*ctrl));
+if (!ctrl) {
 warn_noalloc();
-free(ctrl);
 return;
 }
 
 ctrl->pci_tmp = pci;
-ctrl->pci_bdf = bdf;
-ctrl->iobase = pci_config_readl(bdf, PCI_BASE_ADDRESS_5);
-ctrl->irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
-dprintf(1, "AHCI controller at %02x.%x, iobase %x, irq %d\n",
-bdf >> 3, bdf & 7, ctrl->iobase, ctrl->irq);
-
-pci_config_maskw(bdf, PCI_COMMAND, 0,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ctrl->iobase = iobase;
+ctrl->irq = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
+dprintf(1, "AHCI controller at %02x:%02x.%x, iobase %p, irq %d\n"
+, pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)
+, pci_bdf_to_fn(pci->bdf), ctrl->iobase, ctrl->irq);
+
+pci_enable_busmaster(pci);
 
 val = ahci_ctrl_readl(ctrl, HOST_CTL);
 ahci_ctrl_writel(ctrl, HOST_CTL, val | HOST_CTL_AHCI_EN);
diff --git a/src/hw/ahci.h b/src/hw/ahci.h
index fa11d66..5c4f6e1 100644
--- a/src/hw/ahci.h
+++ b/src/hw/ahci.h
@@ -30,9 +30,8 @@ struct sata_cmd_fis {
 
 struct ahci_ctrl_s {
 struct pci_device *pci_tmp;
-u16 pci_bdf;
 u8  irq;
-u32 iobase;
+void *iobase;
 u32 caps;
 u32 ports;
 };
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 00/14] Clean up PCI BAR handling

2016-02-02 Thread Kevin O'Connor
This series adds some helper functions for working with PCI BARs (Base
Address Registers), and it then updates all the drivers to use these
helper functions.  The new helper functions perform sanity checks on
the BARs and make sure the appropriate pci command register flags are
enabled.  The existing driver code was inconsistent with these checks.

At the end of this series, the pci->have_driver flag is also
consistently set on any PCI device that there is a SeaBIOS driver for.
This will make sure SeaBIOS does not attempt to load an option rom for
a device that SeaBIOS already has a native driver for.

This series is also available at:

  https://github.com/KevinOConnor/seabios/tree/testing

-Kevin


Kevin O'Connor (14):
  pci: Add helper functions for internal driver BAR handling
  ahci: Convert to new PCI BAR helper functions
  ata: Convert to new PCI BAR helper functions
  esp-scsi: Convert to new PCI BAR helper functions
  lsi-scsi: Convert to new PCI BAR helper functions
  megasas: Convert to new PCI BAR helper functions
  pvscsi: Convert to new PCI BAR helper functions
  sdcard: Convert to new PCI BAR helper functions
  ehci: Convert to new PCI BAR helper functions
  ohci: Convert to new PCI BAR helper functions
  uhci: Convert to new PCI BAR helper functions
  xhci: Convert to new PCI BAR helper functions
  virtio: Convert to new PCI BAR helper functions
  pci: Consistently set pci->have_drivers for devices with internal
drivers

 src/hw/ahci.c   | 35 ++
 src/hw/ahci.h   |  3 +--
 src/hw/ata.c| 26 +++
 src/hw/esp-scsi.c   | 13 ++--
 src/hw/lsi-scsi.c   | 13 ++--
 src/hw/megasas.c| 18 +++-
 src/hw/pci.c| 61 +
 src/hw/pci.h|  3 +++
 src/hw/pvscsi.c | 17 +++
 src/hw/sdcard.c | 15 ++---
 src/hw/usb-ehci.c   | 12 +--
 src/hw/usb-ohci.c   | 17 +++
 src/hw/usb-uhci.c   | 16 --
 src/hw/usb-xhci.c   | 27 
 src/hw/virtio-pci.c | 36 +--
 src/hw/virtio-pci.h | 32 
 16 files changed, 203 insertions(+), 141 deletions(-)

-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


Re: [SeaBIOS] [Qemu-devel] [iGVT-g] [vfio-users] [PATCH v3 00/11] igd passthrough chipset tweaks

2016-02-02 Thread Alex Williamson
On Tue, 2016-02-02 at 11:31 -0500, Kevin O'Connor wrote:
> On Tue, Feb 02, 2016 at 09:56:20AM +0100, Gerd Hoffmann wrote:
> >   Hi,
> > 
> > > > I'd have qemu copy the data on 0xfc write then, so things continue to
> > > > work without updating seabios.  So, the firmware has to allocate space,
> > > > reserve it etc.,  and programming the 0xfc register.  Qemu has to make
> > > > sure the opregion appears at the address written by the firmware, by
> > > > whatever method it prefers.
> > > 
> > > Yup. It's Qemu's responsibility to expose opregion content. 
> > > 
> > > btw, prefer to do copying here. It's pointless to allow write from guest
> > > side. One write example is SWSCI mailbox, thru which gfx driver can
> > > trigger some SCI event to communicate with BIOS (specifically ACPI
> > > methods here), mostly for some monitor operations. However it's 
> > > not a right thing for guest to trigger host SCI and thus kick host 
> > > ACPI methods.
> > 
> > Thanks.
> > 
> > So, question again how we do that best.  Option one being the mmap way,
> > i.e. basically what the patches posted by alex are doing.  Option two
> > being the fw_cfg way, i.e. place a opregion copy in fw_cfg and have
> > seabios not only set 0xfc, but also store the opregion there by copying
> > from fw_cfg.
> 
> What about option 2a - SeaBIOS copies from fw_cfg to memory and then
> programs 0xfc.  QEMU can detect the write to 0xfc and choose to map
> that ram (thus completely ignoring the contents that were just copied
> in) or it can choose not to map that ram (thus guest uses the contents
> just copied in).
> 
> The advantage of this approach is that it is a bit simpler in the
> firmware (no size probing is needed as the size comes from fw_cfg) and
> it allows for future flexibility as the choice of mapping can be
> deferred.
> 
> Totally untested seabios code below as example.
> 
> As an aside, if this type of "program a pci register" with a memory
> address becomes common, we could enhance the acpi-style "linker
> script" system to automate this..
> 
> -Kevin
> 
> 
> static void intel_igd_opregion_setup(struct pci_device *dev, void *arg)
> {
> struct romfile_s *file = romfile_find("etc/igd-opregion");
> if (!file)
> return;
> void *data = memalign_high(PAGE_SIZE, file->size);
> if (!data) {
> warn_noalloc();
> return;
> }
> int ret = file->copy(file, data, file->size);
> if (ret < 0) {
> free(data);
> return;
> }
> pci_config_writel(dev->bdf, 0xFC, (u32)data);
> }

I posted a v2 of the last QEMU patch and the SeaBIOS patch that takes
this approach with an option in QEMU for the direct map.  Thanks,

Alex


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios

[SeaBIOS] [RFC PATCH v2] fw/pci: Add support for mapping Intel IGD OpRegion via QEMU

2016-02-02 Thread Alex Williamson
When assigning Intel IGD graphics via QEMU/vfio, the OpRegion for the
device may be exposed as a fw_cfg file.  Allocate space for this, copy
the contents and write the ASL Storage register (0xFC) to point to
this buffer.  NB, it's possible for QEMU to use the write to the ASL
Storage register to map access to the host OpRegion overlapping the
allocated buffer, but we shouldn't care if it does.

References:
kernel vfio opregion support:
https://lkml.org/lkml/2016/2/1/884
QEMU vfio opregion support (revised v2 of 7/7 adds fw_cfg):
https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg00202.html
Gerd's IGD assignment series:
https://lists.gnu.org/archive/html/qemu-devel/2016-01/msg00244.html

Signed-off-by: Alex Williamson 
---
 src/fw/pciinit.c |   30 ++
 1 file changed, 30 insertions(+)

diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
index c31c2fa..92170d5 100644
--- a/src/fw/pciinit.c
+++ b/src/fw/pciinit.c
@@ -257,6 +257,32 @@ static void ich9_smbus_setup(struct pci_device *dev, void 
*arg)
 pci_config_writeb(bdf, ICH9_SMB_HOSTC, ICH9_SMB_HOSTC_HST_EN);
 }
 
+static void intel_igd_opregion_setup(struct pci_device *dev, void *arg)
+{
+struct romfile_s *file = romfile_find("etc/igd-opregion");
+void *opregion;
+u16 bdf = dev->bdf;
+
+if (!file || !file->size)
+return;
+
+opregion = memalign_high(PAGE_SIZE, file->size);
+if (!opregion) {
+warn_noalloc();
+return;
+}
+
+if (file->copy(file, opregion, file->size) < 0) {
+free(opregion);
+return;
+}
+
+pci_config_writel(bdf, 0xFC, cpu_to_le32((u32)opregion));
+
+dprintf(1, "Intel IGD OpRegion enabled on %02x:%02x.%x\n",
+pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
+}
+
 static const struct pci_device_id pci_device_tbl[] = {
 /* PIIX3/PIIX4 PCI to ISA bridge */
 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
@@ -290,6 +316,10 @@ static const struct pci_device_id pci_device_tbl[] = {
 PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_setup),
 PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_setup),
 
+/* Intel IGD OpRegion setup */
+PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA,
+ intel_igd_opregion_setup),
+
 PCI_DEVICE_END,
 };
 


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 2/2] usb: Eliminate USB controller setup thread

2016-02-02 Thread Kevin O'Connor
There are no longer any sleep or yield calls during the usb controller
device scans, so there is no need to run these device scans in a
separate thread.

Signed-off-by: Kevin O'Connor 
---
 src/hw/usb-ehci.c |  1 -
 src/hw/usb-ohci.c |  1 -
 src/hw/usb-uhci.c |  1 -
 src/hw/usb-xhci.c |  1 -
 src/hw/usb.c  | 16 +---
 5 files changed, 5 insertions(+), 15 deletions(-)

diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c
index 010746c..6cc22a5 100644
--- a/src/hw/usb-ehci.c
+++ b/src/hw/usb-ehci.c
@@ -295,7 +295,6 @@ fail:
 static void
 ehci_controller_setup(struct pci_device *pci)
 {
-wait_preempt();  // Avoid pci_config_readl when preempting
 u16 bdf = pci->bdf;
 u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
 struct ehci_caps *caps = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c
index 7ed964f..0c0bf60 100644
--- a/src/hw/usb-ohci.c
+++ b/src/hw/usb-ohci.c
@@ -277,7 +277,6 @@ ohci_controller_setup(struct pci_device *pci)
 cntl->usb.pci = pci;
 cntl->usb.type = USB_TYPE_OHCI;
 
-wait_preempt();  // Avoid pci_config_readl when preempting
 u16 bdf = pci->bdf;
 u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
 cntl->regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
diff --git a/src/hw/usb-uhci.c b/src/hw/usb-uhci.c
index 6d8aa47..7a11510 100644
--- a/src/hw/usb-uhci.c
+++ b/src/hw/usb-uhci.c
@@ -250,7 +250,6 @@ uhci_controller_setup(struct pci_device *pci)
 warn_noalloc();
 return;
 }
-wait_preempt();  // Avoid pci_config_readl when preempting
 memset(cntl, 0, sizeof(*cntl));
 cntl->usb.pci = pci;
 cntl->usb.type = USB_TYPE_UHCI;
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c
index 089cae7..ad541ab 100644
--- a/src/hw/usb-xhci.c
+++ b/src/hw/usb-xhci.c
@@ -534,7 +534,6 @@ xhci_controller_setup(struct pci_device *pci)
 }
 memset(xhci, 0, sizeof(*xhci));
 
-wait_preempt();  // Avoid pci_config_readl when preempting
 xhci->baseaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
 & PCI_BASE_ADDRESS_MEM_MASK;
 xhci->caps  = (void*)(xhci->baseaddr);
diff --git a/src/hw/usb.c b/src/hw/usb.c
index 2bffd25..20731d1 100644
--- a/src/hw/usb.c
+++ b/src/hw/usb.c
@@ -485,21 +485,15 @@ usb_enumerate(struct usbhub_s *hub)
 }
 
 void
-__usb_setup(void *data)
-{
-dprintf(3, "init usb\n");
-xhci_setup();
-ehci_setup();
-uhci_setup();
-ohci_setup();
-}
-
-void
 usb_setup(void)
 {
 ASSERT32FLAT();
 if (! CONFIG_USB)
 return;
+dprintf(3, "init usb\n");
 usb_time_sigatt = romfile_loadint("etc/usb-time-sigatt", USB_TIME_SIGATT);
-run_thread(__usb_setup, NULL);
+xhci_setup();
+ehci_setup();
+uhci_setup();
+ohci_setup();
 }
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH 1/2] ehci: Only delay UHCI/OHCI port scan until after EHCI setup completes

2016-02-02 Thread Kevin O'Connor
EHCI controller setup needs to occur prior to checking any UHCI or
OHCI ports to ensure a high speed device is not mistakenly configured
on a full speed "companion" controller.  However, only the UHCI/OHCI
port scan needs to be delayed, not the full UHCI/OHCI controller init.

This change moves back the ehci controller setup check until port
scan in UHCI/OHCI.

Signed-off-by: Kevin O'Connor 
---
 src/hw/usb-ehci.c | 8 ++--
 src/hw/usb-ehci.h | 1 +
 src/hw/usb-ohci.c | 3 +++
 src/hw/usb-uhci.c | 4 
 4 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c
index 41f8579..010746c 100644
--- a/src/hw/usb-ehci.c
+++ b/src/hw/usb-ehci.c
@@ -337,9 +337,13 @@ ehci_setup(void)
 if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_EHCI)
 ehci_controller_setup(pci);
 }
+}
 
-// Wait for all EHCI controllers to initialize.  This forces OHCI/UHCI
-// setup to always be after any EHCI ports are routed to EHCI.
+// Wait for all EHCI controllers to initialize.  This forces OHCI/UHCI
+// setup to always be after any EHCI ports are routed to EHCI.
+void
+ehci_wait_controllers(void)
+{
 while (PendingEHCI)
 yield();
 }
diff --git a/src/hw/usb-ehci.h b/src/hw/usb-ehci.h
index 88f7b6a..0442188 100644
--- a/src/hw/usb-ehci.h
+++ b/src/hw/usb-ehci.h
@@ -3,6 +3,7 @@
 
 // usb-ehci.c
 void ehci_setup(void);
+void ehci_wait_controllers(void);
 struct usbdevice_s;
 struct usb_endpoint_descriptor;
 struct usb_pipe;
diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c
index 42f8a06..7ed964f 100644
--- a/src/hw/usb-ohci.c
+++ b/src/hw/usb-ohci.c
@@ -14,6 +14,7 @@
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "string.h" // memset
 #include "usb.h" // struct usb_s
+#include "usb-ehci.h" // ehci_wait_controllers
 #include "usb-ohci.h" // struct ohci_hcca
 #include "util.h" // msleep
 #include "x86.h" // readl
@@ -96,6 +97,8 @@ static int
 check_ohci_ports(struct usb_ohci_s *cntl)
 {
 ASSERT32FLAT();
+// Wait for ehci init - in case this is a "companion controller"
+ehci_wait_controllers();
 // Turn on power for all devices on roothub.
 u32 rha = readl(&cntl->regs->roothub_a);
 rha &= ~(RH_A_PSM | RH_A_OCPM);
diff --git a/src/hw/usb-uhci.c b/src/hw/usb-uhci.c
index 69c33ee..6d8aa47 100644
--- a/src/hw/usb-uhci.c
+++ b/src/hw/usb-uhci.c
@@ -13,6 +13,7 @@
 #include "pci_regs.h" // PCI_BASE_ADDRESS_4
 #include "string.h" // memset
 #include "usb.h" // struct usb_s
+#include "usb-ehci.h" // ehci_wait_controllers
 #include "usb-uhci.h" // USBLEGSUP
 #include "util.h" // msleep
 #include "x86.h" // outw
@@ -94,6 +95,9 @@ static int
 check_uhci_ports(struct usb_uhci_s *cntl)
 {
 ASSERT32FLAT();
+// Wait for ehci init - in case this is a "companion controller"
+ehci_wait_controllers();
+
 struct usbhub_s hub;
 memset(&hub, 0, sizeof(hub));
 hub.cntl = &cntl->usb;
-- 
2.5.0


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH v3 05/11] tpm: Implement tpm20_set_timeouts

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

The TIS timeouts for TPM 2 are different than for TPM 1.2.
Also the timeouts indicating a failed TPM 2 command are different.
Further, the  command durations and timeouts cannot be read from the device.

We take the command timeout values for short, medium, and long running
commands from table 15 of the following specification:

TCG PC Client Platform TPM Profile (PTP) Specification

http://www.trustedcomputinggroup.org/resources/pc_client_platform_tpm_profile_ptp_specification

The values should work for all physical TPMs.

The tricky thing with virtualized environments is that the values
may need to be longer for a system where a vTPM cannot get sufficient
cycles. So a future patch _may_ need to multiply those values here
with some factor.

Signed-off-by: Stefan Berger 
---
 src/hw/tpm_drivers.h | 17 +
 src/tcgbios.c| 20 
 2 files changed, 37 insertions(+)

diff --git a/src/hw/tpm_drivers.h b/src/hw/tpm_drivers.h
index 52c7a15..56fd9e8 100644
--- a/src/hw/tpm_drivers.h
+++ b/src/hw/tpm_drivers.h
@@ -66,6 +66,14 @@ void tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]);
 #define TIS_DEFAULT_TIMEOUT_C   75 /* us */
 #define TIS_DEFAULT_TIMEOUT_D   75 /* us */
 
+/*
+ * Default TIS 2 timeouts given in TPM Profile (TPT) Spec
+ */
+#define TIS2_DEFAULT_TIMEOUT_A  75 /* us */
+#define TIS2_DEFAULT_TIMEOUT_B 200 /* us */
+#define TIS2_DEFAULT_TIMEOUT_C  20 /* us */
+#define TIS2_DEFAULT_TIMEOUT_D   3 /* us */
+
 enum tisTimeoutType {
 TIS_TIMEOUT_TYPE_A = 0,
 TIS_TIMEOUT_TYPE_B,
@@ -81,4 +89,13 @@ enum tisTimeoutType {
 #define TPM_DEFAULT_DURATION_MEDIUM2000 /* us */
 #define TPM_DEFAULT_DURATION_LONG  6000 /* us */
 
+/*
+ * TPM 2 command durations; we set them to the timeout values
+ * given in TPM Profile (PTP) Specification; exceeding those
+ * timeout values indicates a faulty TPM.
+ */
+#define TPM2_DEFAULT_DURATION_SHORT   75 /* us */
+#define TPM2_DEFAULT_DURATION_MEDIUM 200 /* us */
+#define TPM2_DEFAULT_DURATION_LONG   200 /* us */
+
 #endif /* TPM_DRIVERS_H */
diff --git a/src/tcgbios.c b/src/tcgbios.c
index 0b40a8f..463b7bb 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -322,6 +322,24 @@ tpm12_determine_timeouts(void)
 return 0;
 }
 
+static void
+tpm20_set_timeouts(void)
+{
+u32 durations[3] = {
+TPM2_DEFAULT_DURATION_SHORT,
+TPM2_DEFAULT_DURATION_MEDIUM,
+TPM2_DEFAULT_DURATION_LONG,
+};
+u32 timeouts[4] = {
+TIS2_DEFAULT_TIMEOUT_A,
+TIS2_DEFAULT_TIMEOUT_B,
+TIS2_DEFAULT_TIMEOUT_C,
+TIS2_DEFAULT_TIMEOUT_D,
+};
+
+tpmhw_set_timeouts(timeouts, durations);
+}
+
 static int
 tpm12_extend(u32 pcrindex, const u8 *digest)
 {
@@ -557,6 +575,8 @@ err_exit:
 static int
 tpm20_startup(void)
 {
+tpm20_set_timeouts();
+
 int ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup,
  Startup_SU_CLEAR,
  sizeof(Startup_SU_CLEAR),
-- 
2.4.3


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH v3 07/11] tpm: Implement tpm20_extend

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

Implement the tpm20_extend function. We use it with only SHA1.

Signed-off-by: Stefan Berger 
---
 src/std/tcg.h | 17 +
 src/tcgbios.c | 34 --
 2 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/src/std/tcg.h b/src/std/tcg.h
index e0d6f30..d45c7f6 100644
--- a/src/std/tcg.h
+++ b/src/std/tcg.h
@@ -375,6 +375,8 @@ struct tpm_res_sha1complete {
 #define TPM2_RS_PW  0x4009
 #define TPM2_RH_PLATFORM0x400c
 
+#define TPM2_ALG_SHA1   0x0004
+
 /* TPM 2 command tags */
 #define TPM2_ST_NO_SESSIONS 0x8001
 #define TPM2_ST_SESSIONS0x8002
@@ -385,6 +387,7 @@ struct tpm_res_sha1complete {
 #define TPM2_CC_Startup 0x144
 #define TPM2_CC_StirRandom  0x146
 #define TPM2_CC_GetRandom   0x17b
+#define TPM2_CC_PCR_Extend  0x182
 
 /* TPM 2 error codes */
 #define TPM2_RC_INITIALIZE  0x100
@@ -426,4 +429,18 @@ struct tpm2_req_hierarchychangeauth {
 struct tpm2b_20 newAuth;
 } PACKED;
 
+struct tpm2_digest_value {
+u32 count; /* 1 entry only */
+u16 hashalg; /* TPM2_ALG_SHA1 */
+u8 sha1[SHA1_BUFSIZE];
+} PACKED;
+
+struct tpm2_req_extend {
+struct tpm_req_header hdr;
+u32 pcrindex;
+u32 authblocksize;
+struct tpm2_authblock authblock;
+struct tpm2_digest_value digest;
+} PACKED;
+
 #endif // tcg.h
diff --git a/src/tcgbios.c b/src/tcgbios.c
index a99d58d..435e2eb 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -361,6 +361,37 @@ tpm12_extend(u32 pcrindex, const u8 *digest)
 return 0;
 }
 
+static int tpm20_extend(u32 pcrindex, const u8 *digest)
+{
+struct tpm2_req_extend tre = {
+.hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+.hdr.totlen  = cpu_to_be32(sizeof(tre)),
+.hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),
+.pcrindex= cpu_to_be32(pcrindex),
+.authblocksize = cpu_to_be32(sizeof(tre.authblock)),
+.authblock = {
+.handle = cpu_to_be32(TPM2_RS_PW),
+.noncesize = cpu_to_be16(0),
+.contsession = TPM2_YES,
+.pwdsize = cpu_to_be16(0),
+},
+.digest = {
+.count = cpu_to_be32(1),
+.hashalg = cpu_to_be16(TPM2_ALG_SHA1),
+},
+};
+memcpy(tre.digest.sha1, digest, sizeof(tre.digest.sha1));
+
+struct tpm_rsp_header rsp;
+u32 resp_length = sizeof(rsp);
+int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_SHORT);
+if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+return -1;
+
+return 0;
+}
+
 static int
 tpm_extend(u32 pcrindex, const u8 *digest)
 {
@@ -371,8 +402,7 @@ tpm_extend(u32 pcrindex, const u8 *digest)
 case TPM_VERSION_1_2:
 return tpm12_extend(pcrindex, digest);
 case TPM_VERSION_2:
-// FIXME: missing code
-return -1;
+return tpm20_extend(pcrindex, digest);
 }
 return -1;
 }
-- 
2.4.3


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH v3 03/11] tpm: Prepare code for TPM 2 functions

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

This patch prepares the tcgbios.c file for extension with TPM 2
specific code by:

 o prefixing all TPM 1.2 specific functions with tpm12_
 o where necessary, introduce switch statements in tpm_ - prefixed functions;
   here we branch into TPM versions specific code
 o introduce tpm_ - prefixed functions where necessary; mostly in those
   cases where tpm12_ functions are too large and where the tpm_ function
   then only holds the switch statement
 o leave FIXMEs where we need to write TPM 2 specific code; subsequent patches
   will replace those FIXMEs

Signed-off-by: Stefan Berger 
---
 src/tcgbios.c | 297 --
 1 file changed, 185 insertions(+), 112 deletions(-)

diff --git a/src/tcgbios.c b/src/tcgbios.c
index 799a8bf..6be1966 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -171,7 +171,13 @@ tpm_is_working(void)
 int
 tpm_can_show_menu(void)
 {
-return tpm_is_working() && TPM_has_physical_presence;
+switch (TPM_version) {
+case TPM_VERSION_1_2:
+return tpm_is_working() && TPM_has_physical_presence;
+case TPM_VERSION_2:
+return tpm_is_working();
+}
+return 0;
 }
 
 /*
@@ -180,8 +186,8 @@ tpm_can_show_menu(void)
  * the custom part per command) and expect a response of the given size.
  */
 static int
-build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
-   enum tpmDurationType to_t)
+tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append,
+   u32 append_size, enum tpmDurationType to_t)
 {
 struct {
 struct tpm_req_header trqh;
@@ -213,19 +219,26 @@ build_and_send_cmd(u8 locty, u32 ordinal, const u8 
*append, u32 append_size,
 static void
 tpm_set_failure(void)
 {
-/*
- * We will try to deactivate the TPM now - ignoring all errors
- * Physical presence is asserted.
- */
+   switch (TPM_version) {
+   case TPM_VERSION_1_2:
+/*
+ * We will try to deactivate the TPM now - ignoring all errors
+ * Physical presence is asserted.
+ */
 
-build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
-   NULL, 0, TPM_DURATION_TYPE_SHORT);
+tpm_build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
+   NULL, 0, TPM_DURATION_TYPE_SHORT);
+break;
+case TPM_VERSION_2:
+// FIXME: missing code
+break;
+}
 
 TPM_working = 0;
 }
 
 static int
-tpm_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
+tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 
rsize)
 {
 struct tpm_req_getcap trgc = {
 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
@@ -249,17 +262,17 @@ tpm_get_capability(u32 cap, u32 subcap, struct 
tpm_rsp_header *rsp, u32 rsize)
 }
 
 static int
-determine_timeouts(void)
+tpm12_determine_timeouts(void)
 {
 struct tpm_res_getcap_timeouts timeouts;
-int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
- , &timeouts.hdr, sizeof(timeouts));
+int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
+   , &timeouts.hdr, sizeof(timeouts));
 if (ret)
 return ret;
 
 struct tpm_res_getcap_durations durations;
-ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
- , &durations.hdr, sizeof(durations));
+ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
+   , &durations.hdr, sizeof(durations));
 if (ret)
 return ret;
 
@@ -287,11 +300,8 @@ determine_timeouts(void)
 }
 
 static int
-tpm_extend(u32 pcrindex, const u8 *digest)
+tpm12_extend(u32 pcrindex, const u8 *digest)
 {
-if (pcrindex >= 24)
-return -1;
-
 struct tpm_req_extend tre = {
 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
 .hdr.totlen  = cpu_to_be32(sizeof(tre)),
@@ -311,6 +321,22 @@ tpm_extend(u32 pcrindex, const u8 *digest)
 }
 
 static int
+tpm_extend(u32 pcrindex, const u8 *digest)
+{
+if (pcrindex >= 24)
+return -1;
+
+switch (TPM_version) {
+case TPM_VERSION_1_2:
+return tpm12_extend(pcrindex, digest);
+case TPM_VERSION_2:
+// FIXME: missing code
+return -1;
+}
+return -1;
+}
+
+static int
 tpm_log_extend_event(struct pcpes *pcpes, const void *event)
 {
 int ret = tpm_extend(pcpes->pcrindex, pcpes->digest);
@@ -410,13 +436,13 @@ tpm_smbios_measure(void)
 }
 
 static int
-read_permanent_flags(char *buf, int buf_len)
+tpm12_read_permanent_flags(char *buf, int buf_len)
 {
 memset(buf, 0, buf_len);
 
 struct tpm_res_getcap_perm_flags pf;
-int ret = tpm_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
- , &pf.hdr, sizeof(pf));
+int ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
+ 

[SeaBIOS] [PATCH v3 06/11] tpm: Implement tpm20_prepboot

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

Implement tpm20_preboot.

Here we set the platform password to a random password that prevents
higher layers (OS) to get this password. This avoids bad things like users
clearing the TPM, erasing EK (primary key) certificates, changing the
primary key etc.

The clearing of the TPM will still be possible through the TPM 2 menu.

Signed-off-by: Stefan Berger 
---
 src/std/tcg.h |  44 +++
 src/tcgbios.c | 111 --
 2 files changed, 153 insertions(+), 2 deletions(-)

diff --git a/src/std/tcg.h b/src/std/tcg.h
index db1155d..e0d6f30 100644
--- a/src/std/tcg.h
+++ b/src/std/tcg.h
@@ -372,14 +372,58 @@ struct tpm_res_sha1complete {
 #define TPM2_SU_CLEAR   0x
 #define TPM2_SU_STATE   0x0001
 
+#define TPM2_RS_PW  0x4009
+#define TPM2_RH_PLATFORM0x400c
+
 /* TPM 2 command tags */
 #define TPM2_ST_NO_SESSIONS 0x8001
+#define TPM2_ST_SESSIONS0x8002
 
 /* TPM 2 commands */
+#define TPM2_CC_HierarchyChangeAuth 0x129
 #define TPM2_CC_SelfTest0x143
 #define TPM2_CC_Startup 0x144
+#define TPM2_CC_StirRandom  0x146
+#define TPM2_CC_GetRandom   0x17b
 
 /* TPM 2 error codes */
 #define TPM2_RC_INITIALIZE  0x100
 
+/* TPM 2 data structures */
+
+struct tpm2b_stir {
+u16 size;
+u64 stir;
+} PACKED;
+
+struct tpm2_req_getrandom {
+struct tpm_req_header hdr;
+u16 bytesRequested;
+} PACKED;
+
+struct tpm2b_20 {
+u16 size;
+u8 buffer[20];
+} PACKED;
+
+struct tpm2_res_getrandom {
+struct tpm_rsp_header hdr;
+struct tpm2b_20 rnd;
+} PACKED;
+
+struct tpm2_authblock {
+u32 handle;
+u16 noncesize;  /* always 0 */
+u8 contsession; /* always TPM2_YES */
+u16 pwdsize;/* always 0 */
+} PACKED;
+
+struct tpm2_req_hierarchychangeauth {
+struct tpm_req_header hdr;
+u32 authhandle;
+u32 authblocksize;
+struct tpm2_authblock authblock;
+struct tpm2b_20 newAuth;
+} PACKED;
+
 #endif // tcg.h
diff --git a/src/tcgbios.c b/src/tcgbios.c
index 463b7bb..a99d58d 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -204,7 +204,7 @@ tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 
*append,
 {
 struct {
 struct tpm_req_header trqh;
-u8 cmd[6];
+u8 cmd[10];
 } PACKED req = {
 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
@@ -657,6 +657,113 @@ tpm_setup(void)
 tpm_add_action(2, "Start Option ROM Scan");
 }
 
+static int
+tpm20_stirrandom(void)
+{
+struct tpm2b_stir stir = {
+.size = cpu_to_be16(sizeof(stir.stir)),
+.stir = rdtscll(),
+};
+/* set more bits to stir with */
+stir.stir += swab64(rdtscll());
+
+int ret = tpm_build_and_send_cmd(0, TPM2_CC_StirRandom,
+ (u8 *)&stir, sizeof(stir),
+ TPM_DURATION_TYPE_SHORT);
+
+dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_StirRandom 
= 0x%08x\n",
+ret);
+
+return ret;
+}
+
+static int
+tpm20_getrandom(u8 *buf, u16 buf_len)
+{
+struct tpm2_res_getrandom rsp;
+
+if (buf_len > sizeof(rsp.rnd.buffer))
+return -1;
+
+struct tpm2_req_getrandom trgr = {
+.hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+.hdr.totlen = cpu_to_be32(sizeof(trgr)),
+.hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),
+.bytesRequested = cpu_to_be16(buf_len),
+};
+u32 resp_length = sizeof(rsp);
+
+int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_MEDIUM);
+if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
+ret = -1;
+else
+memcpy(buf, rsp.rnd.buffer, buf_len);
+
+dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetRandom = 
0x%08x\n",
+ret);
+
+return ret;
+}
+
+static int
+tpm20_hierarchychangeauth(u8 auth[20])
+{
+struct tpm2_req_hierarchychangeauth trhca = {
+.hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+.hdr.totlen = cpu_to_be32(sizeof(trhca)),
+.hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),
+.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+.authblocksize = cpu_to_be32(sizeof(trhca.authblock)),
+.authblock = {
+.handle = cpu_to_be32(TPM2_RS_PW),
+.noncesize = cpu_to_be16(0),
+.contsession = TPM2_YES,
+.pwdsize = cpu_to_be16(0),
+},
+.newAuth = {
+.size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),
+},
+};
+memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));
+
+struct tpm_rsp_header rsp;
+u32 resp_length = sizeof(rsp);
+int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_MEDIUM);
+if (r

[SeaBIOS] [PATCH v3 01/11] tpm: Extend TPM TIS with TPM 2 support.

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

Extend the probing of the interface with TPM 2 specifics.

Use the new interface ID register of the TIS to check whether
a TPM 1.2 or a TPM 2 is underneath.

We select the TIS if possible and lock it so we can issue commands
during S3 for example and prevent the OS from changing to CRB type
of interface.

The register is described in table 13 here:

http://www.trustedcomputinggroup.org/resources/pc_client_platform_tpm_profile_ptp_specification

Signed-off-by: Stefan Berger 
---
 src/hw/tpm_drivers.c | 38 ++
 src/hw/tpm_drivers.h |  9 -
 src/tcgbios.c| 12 +---
 3 files changed, 51 insertions(+), 8 deletions(-)

diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c
index 08fd101..a137e62 100644
--- a/src/hw/tpm_drivers.c
+++ b/src/hw/tpm_drivers.c
@@ -23,6 +23,7 @@ struct tpm_driver {
 u32 *durations;
 void (*set_timeouts)(u32 timeouts[4], u32 durations[3]);
 u32 (*probe)(void);
+TPMVersion (*get_tpm_version)(void);
 u32 (*init)(void);
 u32 (*activate)(u8 locty);
 u32 (*ready)(void);
@@ -56,7 +57,6 @@ static const u32 tpm_default_durations[3] = {
 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)
 {
@@ -69,9 +69,39 @@ static u32 tis_probe(void)
 if ((didvid != 0) && (didvid != 0x))
 rc = 1;
 
+/* TPM 2 has an interface register */
+u32 ifaceid = readl(TIS_REG(0, TIS_REG_IFACE_ID));
+
+if ((ifaceid & 0xf) != 0xf) {
+if ((ifaceid & 0xf) == 1) {
+/* CRB is active; no TIS */
+return 0;
+}
+if ((ifaceid & (1 << 13)) == 0) {
+/* TIS cannot be selected */
+return 0;
+}
+/* write of 0 to bits 17-18 selects TIS */
+writel(TIS_REG(0, TIS_REG_IFACE_ID), 0);
+/* since we only support TIS, we lock it */
+writel(TIS_REG(0, TIS_REG_IFACE_ID), (1 << 19));
+}
+
 return rc;
 }
 
+static TPMVersion tis_get_tpm_version(void)
+{
+/* TPM 2 has an interface register */
+u32 ifaceid = readl(TIS_REG(0, TIS_REG_IFACE_ID));
+
+if ((ifaceid & 0xf) == 0) {
+/* TPM 2 */
+return TPM_VERSION_2;
+}
+return TPM_VERSION_1_2;
+}
+
 static u32 tis_init(void)
 {
 if (!CONFIG_TCGBIOS)
@@ -323,7 +353,7 @@ struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
 
 static u8 TPMHW_driver_to_use = TPM_INVALID_DRIVER;
 
-int
+TPMVersion
 tpmhw_probe(void)
 {
 unsigned int i;
@@ -332,10 +362,10 @@ tpmhw_probe(void)
 if (td->probe() != 0) {
 td->init();
 TPMHW_driver_to_use = i;
-return 0;
+return tis_get_tpm_version();
 }
 }
-return -1;
+return TPM_VERSION_NONE;
 }
 
 int
diff --git a/src/hw/tpm_drivers.h b/src/hw/tpm_drivers.h
index 15a60af..52c7a15 100644
--- a/src/hw/tpm_drivers.h
+++ b/src/hw/tpm_drivers.h
@@ -10,7 +10,13 @@ enum tpmDurationType {
 TPM_DURATION_TYPE_LONG,
 };
 
-int tpmhw_probe(void);
+typedef u8 TPMVersion;
+
+#define TPM_VERSION_NONE 0
+#define TPM_VERSION_1_2  1
+#define TPM_VERSION_22
+
+TPMVersion tpmhw_probe(void);
 int tpmhw_is_present(void);
 struct tpm_req_header;
 int tpmhw_transmit(u8 locty, struct tpm_req_header *req,
@@ -33,6 +39,7 @@ void tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]);
 #define TIS_REG_INTF_CAPABILITY0x14
 #define TIS_REG_STS0x18
 #define TIS_REG_DATA_FIFO  0x24
+#define TIS_REG_IFACE_ID   0x30
 #define TIS_REG_DID_VID0xf00
 #define TIS_REG_RID0xf04
 
diff --git a/src/tcgbios.c b/src/tcgbios.c
index 7077426..0559083 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -62,6 +62,8 @@ struct {
 
 static int TPM_has_physical_presence;
 
+static TPMVersion TPM_version;
+
 static struct tcpa_descriptor_rev2 *
 find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
 {
@@ -498,11 +500,15 @@ tpm_setup(void)
 if (!CONFIG_TCGBIOS)
 return;
 
-int ret = tpmhw_probe();
-if (ret)
+TPM_version = tpmhw_probe();
+if (TPM_version == TPM_VERSION_NONE)
 return;
 
-ret = tpm_tcpa_probe();
+dprintf(DEBUG_tcg,
+"TCGBIOS: Detected a TPM %s.\n",
+ (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");
+
+int ret = tpm_tcpa_probe();
 if (ret)
 return;
 
-- 
2.4.3


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH v3 00/11] Add TPM 2 support

2016-02-02 Thread Stefan Berger
This series of patches adds TPM 2 support to SeaBIOS in the way previously
proposed.

v2->v3:
  - Converted TPM_VERSION_* from enum's to #define's and removed unnecessary
cases with TPM_VERSION_NONE in switch statements.
  - Convert the log_entry internal representation to TPM 2 native format.
  - Added patch that looks at command tags in the TPM_Passthrough API
call and return error code in case of TPM version mismatch.

v1->v2:
  - Addressed most of Kevin's comments.
  - Added patch for writing logs in TPM 2 format

   Stefan

Stefan Berger (11):
  tpm: Extend TPM TIS with TPM 2 support.
  tpm: Factor out tpm_extend
  tpm: Prepare code for TPM 2 functions
  tpm: Implement tpm20_startup and tpm20_s3_resume
  tpm: Implement tpm20_set_timeouts
  tpm: Implement tpm20_prepboot
  tpm: Implement tpm20_extend
  tpm: Implement tpm20_menu
  tpm: Implement TPM 2's tpm_set_failure part
  tpm: Write logs in TPM 2 format
  Filter TPM commands in passthrough API

 src/hw/tpm_drivers.c |  38 ++-
 src/hw/tpm_drivers.h |  26 +-
 src/std/tcg.h| 147 +
 src/tcgbios.c| 900 ++-
 4 files changed, 961 insertions(+), 150 deletions(-)

-- 
2.4.3


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH v3 04/11] tpm: Implement tpm20_startup and tpm20_s3_resume

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

Implement tpm20_startup and tpm20_s3_resume and their dependencies.

We follow this specification:

TCG PC Client Specific Platform Firmware Profile for TPM 2.0 Systems Revision 
1.0 Version 21

It can be found on this page:

http://www.trustedcomputinggroup.org/resources/specifications_in_public_review

Power on: Figure 7 & 7.3.2 item 4.
S3: Figure 9 & 7.3.2 item 4.

Signed-off-by: Stefan Berger 
---
 src/std/tcg.h | 20 +
 src/tcgbios.c | 91 +++
 2 files changed, 105 insertions(+), 6 deletions(-)

diff --git a/src/std/tcg.h b/src/std/tcg.h
index 91692e9..db1155d 100644
--- a/src/std/tcg.h
+++ b/src/std/tcg.h
@@ -362,4 +362,24 @@ struct tpm_res_sha1complete {
 #define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8
 #define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9
 
+/*
+ * TPM 2
+ */
+
+#define TPM2_NO 0
+#define TPM2_YES1
+
+#define TPM2_SU_CLEAR   0x
+#define TPM2_SU_STATE   0x0001
+
+/* TPM 2 command tags */
+#define TPM2_ST_NO_SESSIONS 0x8001
+
+/* TPM 2 commands */
+#define TPM2_CC_SelfTest0x143
+#define TPM2_CC_Startup 0x144
+
+/* TPM 2 error codes */
+#define TPM2_RC_INITIALIZE  0x100
+
 #endif // tcg.h
diff --git a/src/tcgbios.c b/src/tcgbios.c
index 6be1966..0b40a8f 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -25,6 +25,10 @@
 #include "util.h" // printf, get_keystroke
 #include "stacks.h" // wait_threads, reset
 
+/
+ * TPM 1.2 commands
+ /
+
 static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
 static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
 
@@ -36,8 +40,17 @@ static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 
0x00, 0x14 };
 static const u8 CommandFlag_FALSE[1] = { 0x00 };
 static const u8 CommandFlag_TRUE[1]  = { 0x01 };
 
-typedef u8 tpm_ppi_code;
+/
+ * TPM 2 commands
+ /
+
+static const u8 Startup_SU_CLEAR[] = { 0x00, TPM2_SU_CLEAR};
+static const u8 Startup_SU_STATE[] = { 0x00, TPM2_SU_STATE};
 
+static const u8 TPM2_SelfTest_YES[] =  { TPM2_YES }; /* full test */
+
+
+typedef u8 tpm_ppi_code;
 
 /
  * ACPI TCPA table interface
@@ -191,12 +204,22 @@ tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 
*append,
 {
 struct {
 struct tpm_req_header trqh;
-u8 cmd[2];
+u8 cmd[6];
 } PACKED req = {
 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
 .trqh.ordinal = cpu_to_be32(ordinal),
 };
+
+switch (TPM_version) {
+case TPM_VERSION_1_2:
+req.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
+break;
+case TPM_VERSION_2:
+req.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
+break;
+}
+
 u8 obuffer[64];
 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
 u32 obuffer_len = sizeof(obuffer);
@@ -532,14 +555,53 @@ err_exit:
 }
 
 static int
+tpm20_startup(void)
+{
+int ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup,
+ Startup_SU_CLEAR,
+ sizeof(Startup_SU_CLEAR),
+ TPM_DURATION_TYPE_SHORT);
+
+dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending 
TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",
+ret);
+
+if (CONFIG_COREBOOT && ret == TPM2_RC_INITIALIZE)
+/* with other firmware on the system the TPM may already have been
+ * initialized
+ */
+ret = 0;
+
+if (ret)
+goto err_exit;
+
+ret = tpm_build_and_send_cmd(0, TPM2_CC_SelfTest,
+ TPM2_SelfTest_YES,
+ sizeof(TPM2_SelfTest_YES),
+ TPM_DURATION_TYPE_LONG);
+
+dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest = 
0x%08x\n",
+ret);
+
+if (ret)
+goto err_exit;
+
+return 0;
+
+err_exit:
+dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+tpm_set_failure();
+return -1;
+}
+
+static int
 tpm_startup(void)
 {
 switch (TPM_version) {
 case TPM_VERSION_1_2:
 return tpm12_startup();
 case TPM_VERSION_2:
-// FIXME: missing code
-return -1;
+return tpm20_startup();
 }
 return -1;
 }
@@ -694,8 +756,25 @@ tpm_s3_resume(void)
  TPM_DURATION_TYPE_SHORT);
 break;
 case TPM_VERSION_2:
-// FIXME: missing code
-ret = -1;
+ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup,
+  

[SeaBIOS] [PATCH v3 09/11] tpm: Implement TPM 2's tpm_set_failure part

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

Implement TPM 2's tpm_set_failure part.

We follow this specification:

TCG PC Client Specific Platform Firmware Profile for TPM 2.0 Systems Revision 
1.0 Version 21

It can be found on this page:

http://www.trustedcomputinggroup.org/resources/specifications_in_public_review

Make the TPM unavailable for OS-present applications following 6.2 item 2.d.i .

Signed-off-by: Stefan Berger 
---
 src/std/tcg.h | 12 
 src/tcgbios.c | 35 ++-
 2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/src/std/tcg.h b/src/std/tcg.h
index dd860e6..8466b14 100644
--- a/src/std/tcg.h
+++ b/src/std/tcg.h
@@ -372,7 +372,9 @@ struct tpm_res_sha1complete {
 #define TPM2_SU_CLEAR   0x
 #define TPM2_SU_STATE   0x0001
 
+#define TPM2_RH_OWNER   0x4001
 #define TPM2_RS_PW  0x4009
+#define TPM2_RH_ENDORSEMENT 0x400b
 #define TPM2_RH_PLATFORM0x400c
 
 #define TPM2_ALG_SHA1   0x0004
@@ -382,6 +384,7 @@ struct tpm_res_sha1complete {
 #define TPM2_ST_SESSIONS0x8002
 
 /* TPM 2 commands */
+#define TPM2_CC_HierarchyControl0x121
 #define TPM2_CC_Clear   0x126
 #define TPM2_CC_ClearControl0x127
 #define TPM2_CC_HierarchyChangeAuth 0x129
@@ -460,4 +463,13 @@ struct tpm2_req_clear {
 struct tpm2_authblock authblock;
 } PACKED;
 
+struct tpm2_req_hierarchycontrol {
+struct tpm_req_header hdr;
+u32 authhandle;
+u32 authblocksize;
+struct tpm2_authblock authblock;
+u32 enable;
+u8 state;
+} PACKED;
+
 #endif // tcg.h
diff --git a/src/tcgbios.c b/src/tcgbios.c
index cd2b228..da457a4 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -239,6 +239,38 @@ tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 
*append,
 return ret;
 }
 
+static int
+tpm20_hierarchycontrol(u32 hierarchy, u8 state)
+{
+/* we will try to deactivate the TPM now - ignoring all errors */
+struct tpm2_req_hierarchycontrol trh = {
+.hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+.hdr.totlen = cpu_to_be32(sizeof(trh)),
+.hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl),
+.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+.authblocksize = cpu_to_be32(sizeof(trh.authblock)),
+.authblock = {
+.handle = cpu_to_be32(TPM2_RS_PW),
+.noncesize = cpu_to_be16(0),
+.contsession = TPM2_YES,
+.pwdsize = cpu_to_be16(0),
+},
+.enable = cpu_to_be32(hierarchy),
+.state = state,
+};
+struct tpm_rsp_header rsp;
+u32 resp_length = sizeof(rsp);
+int ret = tpmhw_transmit(0, &trh.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_MEDIUM);
+if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+ret = -1;
+
+dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending 
TPM2_CC_HierarchyControl = 0x%08x\n",
+ret);
+
+return ret;
+}
+
 static void
 tpm_set_failure(void)
 {
@@ -253,7 +285,8 @@ tpm_set_failure(void)
NULL, 0, TPM_DURATION_TYPE_SHORT);
 break;
 case TPM_VERSION_2:
-// FIXME: missing code
+tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO);
+tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO);
 break;
 }
 
-- 
2.4.3


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH v3 10/11] tpm: Write logs in TPM 2 format

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

Introduce a log_entry 'object' that we use to hold the data to be logged in
one log entry. Pass this object around rather than the TPM 1.2 specific 'pcpes'
structure.

Write this log_entry in the format that is appropriate for the version of the
host's TPM. For TPM 1.2 write it in the 'pcpes' structure's format, for TPM 2
in the new TPM 2 format.

By using this method we can keep the API interface on systems with a TPM 2 even
though applications pass in the 'pcpes' structures directly. The log will still 
be
written in the appropriate format.

The TPM 2 log contains a TPM 1.2 type of entry of event type EV_NO_ACTION and
entry of type TCG_EfiSpeIdEventStruct as the first entry. This is described
in the EFI specification (section 5.3):

TCG EFI Protocol Specification for TPM Family 2.0

http://www.trustedcomputinggroup.org/resources/tcg_efi_protocol_specification


Signed-off-by: Stefan Berger 
---
 src/std/tcg.h |  35 
 src/tcgbios.c | 174 +-
 2 files changed, 182 insertions(+), 27 deletions(-)

diff --git a/src/std/tcg.h b/src/std/tcg.h
index 8466b14..1e8b250 100644
--- a/src/std/tcg.h
+++ b/src/std/tcg.h
@@ -89,6 +89,7 @@ enum irq_ids {
 
 /* event types: 10.4.1 / table 11 */
 #define EV_POST_CODE 1
+#define EV_NO_ACTION 3
 #define EV_SEPARATOR 4
 #define EV_ACTION5
 #define EV_EVENT_TAG 6
@@ -472,4 +473,38 @@ struct tpm2_req_hierarchycontrol {
 u8 state;
 } PACKED;
 
+/* TPM 2 log entry */
+
+struct tpml_digest_values_sha1 {
+u16 hashtype;
+u8 sha1[SHA1_BUFSIZE];
+};
+
+struct tcg_pcr_event2_sha1 {
+u32 pcrindex;
+u32 eventtype;
+u32 count; /* number of digests */
+struct tpml_digest_values_sha1 digests[1];
+u32 eventsize;
+u8 event[0];
+} PACKED;
+
+struct TCG_EfiSpecIdEventStruct {
+u8 signature[16];
+u32 platformClass;
+u8 specVersionMinor;
+u8 specVersionMajor;
+u8 specErrata;
+u8 uintnSize;
+u32 numberOfAlgorithms;
+struct TCG_EfiSpecIdEventAlgorithmSize {
+u16 algorithmId;
+u16 digestSize;
+} digestSizes[1];
+u8 vendorInfoSize;
+u8 vendorInfo[0];
+};
+
+#define TPM_TCPA_ACPI_CLASS_CLIENT 0
+
 #endif // tcg.h
diff --git a/src/tcgbios.c b/src/tcgbios.c
index da457a4..9456a45 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -130,6 +130,58 @@ tpm_tcpa_probe(void)
 return 0;
 }
 
+/
+ * Log entry 'object'
+ /
+
+struct log_entry {
+/* embedded TPM 2 type of log entry header */
+struct tcg_pcr_event2_sha1 entry;
+const void *event; /* TPM 1.2 & 2 */
+};
+
+static u32
+log_entry_write_size(struct log_entry *le, TPMVersion tpm_version)
+{
+switch (tpm_version) {
+case TPM_VERSION_1_2:
+ return sizeof(struct pcpes) + le->entry.eventsize;
+case TPM_VERSION_2:
+ return sizeof(le->entry) + le->entry.eventsize;
+}
+return 0;
+}
+
+static void
+log_entry_write(struct log_entry *le, void *dest, TPMVersion tpm_version)
+{
+struct pcpes *pcpes;
+
+switch (tpm_version) {
+case TPM_VERSION_1_2:
+pcpes = dest;
+pcpes->pcrindex = le->entry.pcrindex;
+pcpes->eventtype = le->entry.eventtype;
+memcpy(pcpes->digest, le->entry.digests[0].sha1,
+   sizeof(pcpes->digest));
+pcpes->eventdatasize = le->entry.eventsize;
+
+dest += sizeof(*pcpes);
+
+break;
+case TPM_VERSION_2:
+/* fill in missing parts in TPM 2 log entry */
+le->entry.count = 1;
+le->entry.digests[0].hashtype = TPM2_ALG_SHA1;
+memcpy(dest, &le->entry, sizeof(le->entry));
+
+dest += sizeof(le->entry);
+
+break;
+}
+memcpy(dest, le->event, le->entry.eventsize);
+}
+
 /*
  * Extend the ACPI log with the given entry by copying the
  * entry data into the log.
@@ -141,7 +193,7 @@ tpm_tcpa_probe(void)
  *  Returns an error code in case of faiure, 0 in case of success
  */
 static int
-tpm_log_event(struct pcpes *pcpes, const void *event)
+tpm_log_event(struct log_entry *le, TPMVersion tpm_version)
 {
 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
@@ -149,7 +201,7 @@ tpm_log_event(struct pcpes *pcpes, const void *event)
 if (tpm_state.log_area_next_entry == NULL)
 return -1;
 
-u32 size = sizeof(*pcpes) + pcpes->eventdatasize;
+u32 size = log_entry_write_size(le, tpm_version);
 
 if ((tpm_state.log_area_next_entry + size - 
tpm_state.log_area_start_address) >
  tpm_state.log_area_minimum_length) {
@@ -157,9 +209,7 @@ tpm_log_event(struct pcpes *pcpes, const void *event)
 return -1;
 }
 
-memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes));
-memcpy(tpm_st

[SeaBIOS] [PATCH v3 08/11] tpm: Implement tpm20_menu

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

In the TPM 2 menu we currently only allow to run the TPM2_Clear operation.
For this we follow the TCG Physical Presence Interface Specification
to be found here:

http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification

Table 3 shows the 'Clear' operation and the sequence of commands to send.

Signed-off-by: Stefan Berger 
---
 src/std/tcg.h |  17 +
 src/tcgbios.c | 117 +-
 2 files changed, 133 insertions(+), 1 deletion(-)

diff --git a/src/std/tcg.h b/src/std/tcg.h
index d45c7f6..dd860e6 100644
--- a/src/std/tcg.h
+++ b/src/std/tcg.h
@@ -382,6 +382,8 @@ struct tpm_res_sha1complete {
 #define TPM2_ST_SESSIONS0x8002
 
 /* TPM 2 commands */
+#define TPM2_CC_Clear   0x126
+#define TPM2_CC_ClearControl0x127
 #define TPM2_CC_HierarchyChangeAuth 0x129
 #define TPM2_CC_SelfTest0x143
 #define TPM2_CC_Startup 0x144
@@ -443,4 +445,19 @@ struct tpm2_req_extend {
 struct tpm2_digest_value digest;
 } PACKED;
 
+struct tpm2_req_clearcontrol {
+struct tpm_req_header hdr;
+u32 authhandle;
+u32 authblocksize;
+struct tpm2_authblock authblock;
+u8 disable;
+} PACKED;
+
+struct tpm2_req_clear {
+struct tpm_req_header hdr;
+u32 authhandle;
+u32 authblocksize;
+struct tpm2_authblock authblock;
+} PACKED;
+
 #endif // tcg.h
diff --git a/src/tcgbios.c b/src/tcgbios.c
index 435e2eb..cd2b228 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -1441,6 +1441,87 @@ tpm12_process_cfg(tpm_ppi_code msgCode, int verbose)
 }
 
 static int
+tpm20_clearcontrol(u8 disable, int verbose)
+{
+struct tpm2_req_clearcontrol trc = {
+.hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+.hdr.totlen  = cpu_to_be32(sizeof(trc)),
+.hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl),
+.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+.authblocksize = cpu_to_be32(sizeof(trc.authblock)),
+.authblock = {
+.handle = cpu_to_be32(TPM2_RS_PW),
+.noncesize = cpu_to_be16(0),
+.contsession = TPM2_YES,
+.pwdsize = cpu_to_be16(0),
+},
+.disable = disable,
+};
+struct tpm_rsp_header rsp;
+u32 resp_length = sizeof(rsp);
+int ret = tpmhw_transmit(0, &trc.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_SHORT);
+if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+ret = -1;
+
+dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending 
TPM2_CC_ClearControl = 0x%08x\n",
+ret);
+
+return ret;
+}
+
+static int
+tpm20_clear(void)
+{
+struct tpm2_req_clear trq = {
+.hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+.hdr.totlen  = cpu_to_be32(sizeof(trq)),
+.hdr.ordinal = cpu_to_be32(TPM2_CC_Clear),
+.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+.authblocksize = cpu_to_be32(sizeof(trq.authblock)),
+.authblock = {
+.handle = cpu_to_be32(TPM2_RS_PW),
+.noncesize = cpu_to_be16(0),
+.contsession = TPM2_YES,
+.pwdsize = cpu_to_be16(0),
+},
+};
+struct tpm_rsp_header rsp;
+u32 resp_length = sizeof(rsp);
+int ret = tpmhw_transmit(0, &trq.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_MEDIUM);
+if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+ret = -1;
+
+dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Clear = 
0x%08x\n",
+ret);
+
+return ret;
+}
+
+static int
+tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
+{
+int ret = 0;
+
+switch (msgCode) {
+case TPM_PPI_OP_NOOP: /* no-op */
+break;
+
+case TPM_PPI_OP_CLEAR:
+ret = tpm20_clearcontrol(0, verbose);
+if (!ret)
+ ret = tpm20_clear();
+break;
+}
+
+if (ret)
+printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
+
+return ret;
+}
+
+static int
 tpm12_get_tpm_state(void)
 {
 int state = 0;
@@ -1614,6 +1695,40 @@ tpm12_menu(void)
 }
 }
 
+static void
+tpm20_menu(void)
+{
+int scan_code;
+tpm_ppi_code msgCode;
+
+for (;;) {
+printf("1. Clear TPM\n");
+
+printf("\nIf no change is desired or if this menu was reached by "
+   "mistake, press ESC to\n"
+   "reboot the machine.\n");
+
+msgCode = TPM_PPI_OP_NOOP;
+
+while ((scan_code = get_keystroke(1000)) == ~0)
+;
+
+switch (scan_code) {
+case 1:
+// ESC
+reset();
+break;
+case 2:
+msgCode = TPM_PPI_OP_CLEAR;
+break;
+default:
+continue;
+}
+
+tpm20_process_cfg(msgCode, 0);
+}
+}
+
 void
 tpm_menu(void)
 {
@@ -1629,7 +1744,7 @@ tpm_menu(void)
 tpm12_menu();
 break;
 cas

[SeaBIOS] [PATCH v3 11/11] Filter TPM commands in passthrough API

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

Filter TPM commands in the passthrough API call by matching the
type of tag in the header with the version of the underlying TPM.
Return an error code if the tag indicates that the command is
for the wrong TPM version.

Fix a size check on the way.

Signed-off-by: Stefan Berger 
---
 src/std/tcg.h |  2 ++
 src/tcgbios.c | 19 ++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/src/std/tcg.h b/src/std/tcg.h
index 1e8b250..f692142 100644
--- a/src/std/tcg.h
+++ b/src/std/tcg.h
@@ -74,6 +74,8 @@
 
 /* TPM command tags */
 #define TPM_TAG_RQU_CMD  0x00c1
+#define TPM_TAG_RQU_AUTH1_CMD0x00c2
+#define TPM_TAG_RQU_AUTH2_CMD0x00c3
 
 /* interrupt identifiers (al register) */
 enum irq_ids {
diff --git a/src/tcgbios.c b/src/tcgbios.c
index 9456a45..34f727b 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -1173,13 +1173,30 @@ pass_through_to_tpm_int(struct pttti *pttti, struct 
pttto *pttto)
 u32 rc = 0;
 struct tpm_req_header *trh = (void*)pttti->tpmopin;
 
-if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
+if (pttti->ipblength < sizeof(struct pttti) + sizeof(*trh)
 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
 || pttti->opblength < sizeof(struct pttto)) {
 rc = TCG_INVALID_INPUT_PARA;
 goto err_exit;
 }
 
+u16 tag = be16_to_cpu(trh->tag);
+
+switch (TPM_version) {
+case TPM_VERSION_1_2:
+if (tag != TPM_TAG_RQU_CMD && tag != TPM_TAG_RQU_AUTH1_CMD
+&& tag != TPM_TAG_RQU_AUTH2_CMD) {
+rc = TCG_INVALID_INPUT_PARA;
+goto err_exit;
+}
+break;
+case TPM_VERSION_2:
+if (tag != TPM2_ST_NO_SESSIONS && tag != TPM2_ST_SESSIONS) {
+rc = TCG_INVALID_INPUT_PARA;
+goto err_exit;
+}
+}
+
 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
 int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
  TPM_DURATION_TYPE_LONG /* worst case */);
-- 
2.4.3


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


[SeaBIOS] [PATCH v3 02/11] tpm: Factor out tpm_extend

2016-02-02 Thread Stefan Berger
From: Stefan Berger 

In preparation for TPM 2 code support, factor out the TPM 1.2 specific
code from tpm_log_extend_event and put it into tpm_extend().

Signed-off-by: Stefan Berger 
---
 src/tcgbios.c | 18 ++
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/tcgbios.c b/src/tcgbios.c
index 0559083..799a8bf 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -287,18 +287,18 @@ determine_timeouts(void)
 }
 
 static int
-tpm_log_extend_event(struct pcpes *pcpes, const void *event)
+tpm_extend(u32 pcrindex, const u8 *digest)
 {
-if (pcpes->pcrindex >= 24)
+if (pcrindex >= 24)
 return -1;
 
 struct tpm_req_extend tre = {
 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
 .hdr.totlen  = cpu_to_be32(sizeof(tre)),
 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
-.pcrindex= cpu_to_be32(pcpes->pcrindex),
+.pcrindex= cpu_to_be32(pcrindex),
 };
-memcpy(tre.digest, pcpes->digest, sizeof(tre.digest));
+memcpy(tre.digest, digest, sizeof(tre.digest));
 
 struct tpm_rsp_extend rsp;
 u32 resp_length = sizeof(rsp);
@@ -307,6 +307,16 @@ tpm_log_extend_event(struct pcpes *pcpes, const void 
*event)
 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
 return -1;
 
+return 0;
+}
+
+static int
+tpm_log_extend_event(struct pcpes *pcpes, const void *event)
+{
+int ret = tpm_extend(pcpes->pcrindex, pcpes->digest);
+if (ret)
+return -1;
+
 return tpm_log_event(pcpes, event);
 }
 
-- 
2.4.3


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


Re: [SeaBIOS] [Qemu-devel] [iGVT-g] [vfio-users] [PATCH v3 00/11] igd passthrough chipset tweaks

2016-02-02 Thread Laszlo Ersek
Including Igor & MST

Thanks
Laszlo

On 02/02/16 17:31, Kevin O'Connor wrote:
> On Tue, Feb 02, 2016 at 09:56:20AM +0100, Gerd Hoffmann wrote:
>>   Hi,
>>
 I'd have qemu copy the data on 0xfc write then, so things continue to
 work without updating seabios.  So, the firmware has to allocate space,
 reserve it etc.,  and programming the 0xfc register.  Qemu has to make
 sure the opregion appears at the address written by the firmware, by
 whatever method it prefers.
>>>
>>> Yup. It's Qemu's responsibility to expose opregion content. 
>>>
>>> btw, prefer to do copying here. It's pointless to allow write from guest
>>> side. One write example is SWSCI mailbox, thru which gfx driver can
>>> trigger some SCI event to communicate with BIOS (specifically ACPI
>>> methods here), mostly for some monitor operations. However it's 
>>> not a right thing for guest to trigger host SCI and thus kick host 
>>> ACPI methods.
>>
>> Thanks.
>>
>> So, question again how we do that best.  Option one being the mmap way,
>> i.e. basically what the patches posted by alex are doing.  Option two
>> being the fw_cfg way, i.e. place a opregion copy in fw_cfg and have
>> seabios not only set 0xfc, but also store the opregion there by copying
>> from fw_cfg.
> 
> What about option 2a - SeaBIOS copies from fw_cfg to memory and then
> programs 0xfc.  QEMU can detect the write to 0xfc and choose to map
> that ram (thus completely ignoring the contents that were just copied
> in) or it can choose not to map that ram (thus guest uses the contents
> just copied in).
> 
> The advantage of this approach is that it is a bit simpler in the
> firmware (no size probing is needed as the size comes from fw_cfg) and
> it allows for future flexibility as the choice of mapping can be
> deferred.
> 
> Totally untested seabios code below as example.
> 
> As an aside, if this type of "program a pci register" with a memory
> address becomes common, we could enhance the acpi-style "linker
> script" system to automate this..
> 
> -Kevin
> 
> 
> static void intel_igd_opregion_setup(struct pci_device *dev, void *arg)
> {
> struct romfile_s *file = romfile_find("etc/igd-opregion");
> if (!file)
> return;
> void *data = memalign_high(PAGE_SIZE, file->size);
> if (!data) {
> warn_noalloc();
> return;
> }
> int ret = file->copy(file, data, file->size);
> if (ret < 0) {
> free(data);
> return;
> }
> pci_config_writel(dev->bdf, 0xFC, (u32)data);
> }
> 


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


Re: [SeaBIOS] [Qemu-devel] [iGVT-g] [vfio-users] [PATCH v3 00/11] igd passthrough chipset tweaks

2016-02-02 Thread Kevin O'Connor
On Tue, Feb 02, 2016 at 09:56:20AM +0100, Gerd Hoffmann wrote:
>   Hi,
> 
> > > I'd have qemu copy the data on 0xfc write then, so things continue to
> > > work without updating seabios.  So, the firmware has to allocate space,
> > > reserve it etc.,  and programming the 0xfc register.  Qemu has to make
> > > sure the opregion appears at the address written by the firmware, by
> > > whatever method it prefers.
> > 
> > Yup. It's Qemu's responsibility to expose opregion content. 
> > 
> > btw, prefer to do copying here. It's pointless to allow write from guest
> > side. One write example is SWSCI mailbox, thru which gfx driver can
> > trigger some SCI event to communicate with BIOS (specifically ACPI
> > methods here), mostly for some monitor operations. However it's 
> > not a right thing for guest to trigger host SCI and thus kick host 
> > ACPI methods.
> 
> Thanks.
> 
> So, question again how we do that best.  Option one being the mmap way,
> i.e. basically what the patches posted by alex are doing.  Option two
> being the fw_cfg way, i.e. place a opregion copy in fw_cfg and have
> seabios not only set 0xfc, but also store the opregion there by copying
> from fw_cfg.

What about option 2a - SeaBIOS copies from fw_cfg to memory and then
programs 0xfc.  QEMU can detect the write to 0xfc and choose to map
that ram (thus completely ignoring the contents that were just copied
in) or it can choose not to map that ram (thus guest uses the contents
just copied in).

The advantage of this approach is that it is a bit simpler in the
firmware (no size probing is needed as the size comes from fw_cfg) and
it allows for future flexibility as the choice of mapping can be
deferred.

Totally untested seabios code below as example.

As an aside, if this type of "program a pci register" with a memory
address becomes common, we could enhance the acpi-style "linker
script" system to automate this..

-Kevin


static void intel_igd_opregion_setup(struct pci_device *dev, void *arg)
{
struct romfile_s *file = romfile_find("etc/igd-opregion");
if (!file)
return;
void *data = memalign_high(PAGE_SIZE, file->size);
if (!data) {
warn_noalloc();
return;
}
int ret = file->copy(file, data, file->size);
if (ret < 0) {
free(data);
return;
}
pci_config_writel(dev->bdf, 0xFC, (u32)data);
}

___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios


Re: [SeaBIOS] [RFC PATCH] fw/pci: Add support for mapping Intel IGD OpRegion via QEMU

2016-02-02 Thread Laszlo Ersek
On 02/02/16 16:56, Alex Williamson wrote:
> On Tue, 2016-02-02 at 12:43 +0100, Laszlo Ersek wrote:
>> On 02/02/16 05:15, Alex Williamson wrote:
>>> The proposed IGD OpRegion support in QEMU via vfio maps the host
>>> OpRegion into VM system memory at the address written to the ASL
>>> Storage register (0xFC).  The OpRegion contains a 16-byte signature
>>> followed by a 4-byte size field.  Therefore SeaBIOS can allocate a
>>> buffer of the typical size (8KB), this results in a matching e820
>>> reserved entry for the range, then write the buffer address to the ASL
>>> Storage register, blinking the OpRegion into the VM address space.  At
>>> that point SeaBIOS can validate the signature and size and remap if
>>> necessary.  If the OpRegion is larger than 8KB, this would result in
>>> any conflicting ranges being temporarily mapped with the OpRegion,
>>> which probably needs further discussion on what that could break.
>>> Other options might be to use the same algorithm with an obscenely
>>> sized initial buffer to make sure we do not overlap, always
>>> re-allocating the proper sized buffer, or perhaps we could pass the
>>> OpRegion itself or information about the OpRegion through fw_cfg.
>>>  
>>> With the posted kernel series[1] and QEMU series[2] (on top of Gerd's
>>> IGD patches[3]), this makes the OpRegion available to the VM and
>>> tracing shows that the guest driver does access it.
>>>  
>>> [1] https://lkml.org/lkml/2016/2/1/884
>>> [2] https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg00202.html
>>> [3] https://lists.gnu.org/archive/html/qemu-devel/2016-01/msg00244.html
>>>  
>>> Signed-off-by: Alex Williamson 
>>> ---
>>>  src/fw/pciinit.c |   50 ++
>>>  1 file changed, 50 insertions(+)
>>>  
>>> diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
>>> index c31c2fa..4f3251e 100644
>>> --- a/src/fw/pciinit.c
>>> +++ b/src/fw/pciinit.c
>>> @@ -257,6 +257,52 @@ static void ich9_smbus_setup(struct pci_device *dev, 
>>> void *arg)
>>>  pci_config_writeb(bdf, ICH9_SMB_HOSTC, ICH9_SMB_HOSTC_HST_EN);
>>>  }
>>>  
>>> +static void intel_igd_opregion_setup(struct pci_device *dev, void *arg)
>>> +{
>>> +u16 bdf = dev->bdf;
>>> +u32 orig;
>>> +void *opregion;
>>> +int size = 8;
>>> +
>>> +if (!CONFIG_QEMU)
>>> +return;
>>> +
>>> +orig = pci_config_readl(bdf, 0xFC);
>>> +
>>> +realloc:
>>> +opregion = malloc_high(size * 1024);
>>> +if (!opregion) {
>>> +warn_noalloc();
>>> +return;
>>> +}
>>> +
>>> +/*
>>> + * QEMU maps the OpRegion into system memory at the address written 
>>> here,
>>> + * this overlaps our malloc, which marks the range e820 reserved.
>>> + */
>>> +pci_config_writel(bdf, 0xFC, cpu_to_le32((u32)opregion));
>>> +
>>> +if (memcmp(opregion, "IntelGraphicsMem", 16)) {
>>> +pci_config_writel(bdf, 0xFC, orig);
>>> +free(opregion);
>>> +return; /* the opregion didn't magically appear, not supported */
>>> +}
>>> +
>>> +if (size == le32_to_cpu(*(u32 *)(opregion + 16))) {
>>> +dprintf(1, "Intel IGD OpRegion enabled on %02x:%02x.%x\n",
>>> +pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), 
>>> pci_bdf_to_fn(bdf));
>>> +return; /* success! */
>>> +}
>>> +
>>> +pci_config_writel(bdf, 0xFC, orig);
>>> +free(opregion);
>>> +
>>> +if (size == 8) { /* try once more with a new size */
>>> +size = le32_to_cpu(*(u32 *)(opregion + 16));
>>> +goto realloc;
>>  
>> Is this idiomatic SeaBIOS coding style?
>>  
>> How about "for (;;)" -- the code has many instances -- and reworking
>> this last branch accordingly?
>>  
>> (Apologies, not a very important comment.)
> 
> I did check that I wasn't the only one using a goto in SeaBIOS and I
> don't see any sort of CodingStyle doc precluding it, but I apologize if
> there have been previous discussions that I've missed.

Not that I know of...

> I don't have the
> same aversion to gotos as many people do, but of course the loop can be
> reworked in any number of ways if there's a preference to avoid them.

... but I thought that goto's were mostly reserved for cleanup / error
paths in SeaBIOS (a quick grep seemed to confirm).

I recall seeing this kind of construct in the kernel source (especially
if the jump is from within a deeply nested conditional). I'm not against
it, just thought that it could count as unusual for SeaBIOS. Kevin will
know. :)

Thanks
Laszlo

> Thanks,
> 
> Alex
> 
> 
>>> +}
>>> +}
>>> +
>>>  static const struct pci_device_id pci_device_tbl[] = {
>>>  /* PIIX3/PIIX4 PCI to ISA bridge */
>>>  PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
>>> @@ -290,6 +336,10 @@ static const struct pci_device_id pci_device_tbl[] = {
>>>  PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, 
>>> apple_macio_setup),
>>>  PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, 
>>> apple_macio_setup),
>>>  

Re: [SeaBIOS] [RFC PATCH] fw/pci: Add support for mapping Intel IGD OpRegion via QEMU

2016-02-02 Thread Alex Williamson
On Tue, 2016-02-02 at 12:43 +0100, Laszlo Ersek wrote:
> On 02/02/16 05:15, Alex Williamson wrote:
> > The proposed IGD OpRegion support in QEMU via vfio maps the host
> > OpRegion into VM system memory at the address written to the ASL
> > Storage register (0xFC).  The OpRegion contains a 16-byte signature
> > followed by a 4-byte size field.  Therefore SeaBIOS can allocate a
> > buffer of the typical size (8KB), this results in a matching e820
> > reserved entry for the range, then write the buffer address to the ASL
> > Storage register, blinking the OpRegion into the VM address space.  At
> > that point SeaBIOS can validate the signature and size and remap if
> > necessary.  If the OpRegion is larger than 8KB, this would result in
> > any conflicting ranges being temporarily mapped with the OpRegion,
> > which probably needs further discussion on what that could break.
> > Other options might be to use the same algorithm with an obscenely
> > sized initial buffer to make sure we do not overlap, always
> > re-allocating the proper sized buffer, or perhaps we could pass the
> > OpRegion itself or information about the OpRegion through fw_cfg.
> > 
> > With the posted kernel series[1] and QEMU series[2] (on top of Gerd's
> > IGD patches[3]), this makes the OpRegion available to the VM and
> > tracing shows that the guest driver does access it.
> > 
> > [1] https://lkml.org/lkml/2016/2/1/884
> > [2] https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg00202.html
> > [3] https://lists.gnu.org/archive/html/qemu-devel/2016-01/msg00244.html
> > 
> > Signed-off-by: Alex Williamson 
> > ---
> >  src/fw/pciinit.c |   50 ++
> >  1 file changed, 50 insertions(+)
> > 
> > diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
> > index c31c2fa..4f3251e 100644
> > --- a/src/fw/pciinit.c
> > +++ b/src/fw/pciinit.c
> > @@ -257,6 +257,52 @@ static void ich9_smbus_setup(struct pci_device *dev, 
> > void *arg)
> >  pci_config_writeb(bdf, ICH9_SMB_HOSTC, ICH9_SMB_HOSTC_HST_EN);
> >  }
> >  
> > +static void intel_igd_opregion_setup(struct pci_device *dev, void *arg)
> > +{
> > +u16 bdf = dev->bdf;
> > +u32 orig;
> > +void *opregion;
> > +int size = 8;
> > +
> > +if (!CONFIG_QEMU)
> > +return;
> > +
> > +orig = pci_config_readl(bdf, 0xFC);
> > +
> > +realloc:
> > +opregion = malloc_high(size * 1024);
> > +if (!opregion) {
> > +warn_noalloc();
> > +return;
> > +}
> > +
> > +/*
> > + * QEMU maps the OpRegion into system memory at the address written 
> > here,
> > + * this overlaps our malloc, which marks the range e820 reserved.
> > + */
> > +pci_config_writel(bdf, 0xFC, cpu_to_le32((u32)opregion));
> > +
> > +if (memcmp(opregion, "IntelGraphicsMem", 16)) {
> > +pci_config_writel(bdf, 0xFC, orig);
> > +free(opregion);
> > +return; /* the opregion didn't magically appear, not supported */
> > +}
> > +
> > +if (size == le32_to_cpu(*(u32 *)(opregion + 16))) {
> > +dprintf(1, "Intel IGD OpRegion enabled on %02x:%02x.%x\n",
> > +pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), 
> > pci_bdf_to_fn(bdf));
> > +return; /* success! */
> > +}
> > +
> > +pci_config_writel(bdf, 0xFC, orig);
> > +free(opregion);
> > +
> > +if (size == 8) { /* try once more with a new size */
> > +size = le32_to_cpu(*(u32 *)(opregion + 16));
> > +goto realloc;
> 
> Is this idiomatic SeaBIOS coding style?
> 
> How about "for (;;)" -- the code has many instances -- and reworking
> this last branch accordingly?
> 
> (Apologies, not a very important comment.)

I did check that I wasn't the only one using a goto in SeaBIOS and I
don't see any sort of CodingStyle doc precluding it, but I apologize if
there have been previous discussions that I've missed.  I don't have the
same aversion to gotos as many people do, but of course the loop can be
reworked in any number of ways if there's a preference to avoid them.
Thanks,

Alex


> > +}
> > +}
> > +
> >  static const struct pci_device_id pci_device_tbl[] = {
> >  /* PIIX3/PIIX4 PCI to ISA bridge */
> >  PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
> > @@ -290,6 +336,10 @@ static const struct pci_device_id pci_device_tbl[] = {
> >  PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, 
> > apple_macio_setup),
> >  PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, 
> > apple_macio_setup),
> >  
> > +/* Intel IGD OpRegion setup */
> > +PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, 
> > PCI_CLASS_DISPLAY_VGA,
> > + intel_igd_opregion_setup),
> > +
> >  PCI_DEVICE_END,
> >  };
> >  
> > 
> > 
> > ___
> > SeaBIOS mailing list
> > SeaBIOS@seabios.org
> > http://www.seabios.org/mailman/listinfo/seabios
> > 
> 


___
SeaBIOS mailing list
SeaB

Re: [SeaBIOS] [RFC PATCH v1 0/9] Add TPM 2 support

2016-02-02 Thread Stefan Berger
"Kevin O'Connor"  wrote on 02/01/2016 04:50:22 PM:

> 
> On Fri, Jan 22, 2016 at 03:27:28PM -0500, Stefan Berger wrote:
> > "Kevin O'Connor"  wrote on 01/21/2016 05:37:29 PM:
> > > Thanks Stefan.  In general it looks good to me.  I have a few
> > > comments, which I'll send separately.  All of my comments could be
> > > addressed after committing this series if desired.
> > 
> > I can address those comments and repost a V2 with the 10th patch 
adding 
> > the part for the logging.
> 
> Hi Stefan.  Sorry for the delay in responding.  I have a couple of
> comments on the new patch series which I will respond with separately.
> 
> > > How does one test and/or use this support?  Does QEMU have support, 
or
> > > is there hardware available on coreboot with the tpm2 hardware?
> > 
> > I did all the testing of these patches with the vTPM with CUSE 
interface 
> > integrated into QEMU. Unfortunately the vTPM-QEMU integration train 
seems 
> > a wreck now following comments on QEMU mailing list. So, I don't know 
of 
> > any TPM 2 hardware out there, less so hardware where coreboot runs. So 

> > that's probably currently the number one problem.
> 
> Normally, I prefer to wait until upstream has committed the equivalent
> patches.  I think there is some leeway here, however, because this
> series could be considered as adding support for additional hardware.
> 
> That said, if you don't know of any TPM2 hardware that is shipping, it
> does raise the possibility that the specs might change by the time
> actual hardware does ship.  What is your feel for the trade-off
> between merging now and merging after actual implementations exist?

TPM 2 is a published TCG and ISO/IED 11889:2015 standard now.

http://www.trustedcomputinggroup.org/resources/tpm_library_specification

Devices with TPM 2 are also shipping:

http://store.hp.com/us/en/pdp/hp-elitebook-folio-1020-g1-notebook-pc-%28energy-star%29-p-l4a53ut-aba--1
http://www.notebookcheck.net/Dell-XPS-13-Ultrabook-Review.136793.0.html



> 
> > You know the TPM 1.2 PC BIOS specification, right? I think we can say 
that 
> > many of the functions implemented in this series for TPM 2 are 
necessary 
> > because of how it's done for TPM 1.2 as well as properties of the TPM 
2 
> > device. This includes the TPM initialization, S3 support, setting of 
> > timeouts, menu items, etc. The problem with TPM 2 is that there's no 
> > official spec for TPM 2 for a BIOS. So it's not quite clear to me how 
much 
> > leeway we have to go about this in the areas of ACPI tables for 
logging 
> > and the API. Regarding these topics:
> > 
> > ACPI tables for logging: The (U)EFI specification for TPM 2 don't 
require 
> > a TCPA table with the logging area because there seems to be an API 
for 
> > the OS for retrieving the log. UEFI seems to log into just some 
buffer, 
> > not connected to any ACPI table. For the BIOS we would still need that 

> > TCPA table. QEMU currently provides that. The Linux kernel (and all 
other 
> > OSes -- uuuh) would then have to allow a TCPA table for logging for 
TPM 2 
> > even though we cannot point to a spec for that. Not sure whether we 
can 
> > create a standard for this little gap here...
> 
> It sounds like the creators of the spec assumed only EFI machines
> would have a TPM2 device.  Unless there is evidence that OSes will
> accept the ACPI/TCPA table in the new format, I'd be inclined to leave
> it in the old format.

I think the format goes with the TPM 2. We should be able to log into the 
TCPA table. It wouldn't make sense to come up with a new table and the 
logging format should be TPM 2 specific.

> 
> > BIOS API: Some functions pass the entry to write into the log via the 
> > function directly. Patch 10 handles that and transforms that entry 
into 
> > the log entry format as required for TPM 1.2 or TPM 2 (log entries are 

> > differently formatted for TPM 1.2 and for TPM 2). So the only 
remaining 
> > problem I know of is the function that allows one to pass TPM commands 

> > through to the TPM. This may end up causing problems in the 
application if 
> > it was written for TPM 1.2 and now there's a TPM 2 running underneath, 

> > which doesn't understand the TPM 1.2 commands. I would say this is 
likely 
> > the smaller of the problems also considering that there are not many 
> > applications out there that use that API call. Possibility to just 
shut 
> > down that function call is certainly there.
> 
> I'd say returning an error code for pass-through command requests is
> the safest solution.

TPM 1.2 and TPM 2 commands all differ in the tag field. We could filter by 
that and return an error if the tag is not for the underlying TPM.

   Stefan



> 
> -Kevin
> 


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios

Re: [SeaBIOS] [RFC PATCH] fw/pci: Add support for mapping Intel IGD OpRegion via QEMU

2016-02-02 Thread Laszlo Ersek
On 02/02/16 05:15, Alex Williamson wrote:
> The proposed IGD OpRegion support in QEMU via vfio maps the host
> OpRegion into VM system memory at the address written to the ASL
> Storage register (0xFC).  The OpRegion contains a 16-byte signature
> followed by a 4-byte size field.  Therefore SeaBIOS can allocate a
> buffer of the typical size (8KB), this results in a matching e820
> reserved entry for the range, then write the buffer address to the ASL
> Storage register, blinking the OpRegion into the VM address space.  At
> that point SeaBIOS can validate the signature and size and remap if
> necessary.  If the OpRegion is larger than 8KB, this would result in
> any conflicting ranges being temporarily mapped with the OpRegion,
> which probably needs further discussion on what that could break.
> Other options might be to use the same algorithm with an obscenely
> sized initial buffer to make sure we do not overlap, always
> re-allocating the proper sized buffer, or perhaps we could pass the
> OpRegion itself or information about the OpRegion through fw_cfg.
> 
> With the posted kernel series[1] and QEMU series[2] (on top of Gerd's
> IGD patches[3]), this makes the OpRegion available to the VM and
> tracing shows that the guest driver does access it.
> 
> [1] https://lkml.org/lkml/2016/2/1/884
> [2] https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg00202.html
> [3] https://lists.gnu.org/archive/html/qemu-devel/2016-01/msg00244.html
> 
> Signed-off-by: Alex Williamson 
> ---
>  src/fw/pciinit.c |   50 ++
>  1 file changed, 50 insertions(+)
> 
> diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
> index c31c2fa..4f3251e 100644
> --- a/src/fw/pciinit.c
> +++ b/src/fw/pciinit.c
> @@ -257,6 +257,52 @@ static void ich9_smbus_setup(struct pci_device *dev, 
> void *arg)
>  pci_config_writeb(bdf, ICH9_SMB_HOSTC, ICH9_SMB_HOSTC_HST_EN);
>  }
>  
> +static void intel_igd_opregion_setup(struct pci_device *dev, void *arg)
> +{
> +u16 bdf = dev->bdf;
> +u32 orig;
> +void *opregion;
> +int size = 8;
> +
> +if (!CONFIG_QEMU)
> +return;
> +
> +orig = pci_config_readl(bdf, 0xFC);
> +
> +realloc:
> +opregion = malloc_high(size * 1024);
> +if (!opregion) {
> +warn_noalloc();
> +return;
> +}
> +
> +/*
> + * QEMU maps the OpRegion into system memory at the address written here,
> + * this overlaps our malloc, which marks the range e820 reserved.
> + */
> +pci_config_writel(bdf, 0xFC, cpu_to_le32((u32)opregion));
> +
> +if (memcmp(opregion, "IntelGraphicsMem", 16)) {
> +pci_config_writel(bdf, 0xFC, orig);
> +free(opregion);
> +return; /* the opregion didn't magically appear, not supported */
> +}
> +
> +if (size == le32_to_cpu(*(u32 *)(opregion + 16))) {
> +dprintf(1, "Intel IGD OpRegion enabled on %02x:%02x.%x\n",
> +pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), 
> pci_bdf_to_fn(bdf));
> +return; /* success! */
> +}
> +
> +pci_config_writel(bdf, 0xFC, orig);
> +free(opregion);
> +
> +if (size == 8) { /* try once more with a new size */
> +size = le32_to_cpu(*(u32 *)(opregion + 16));
> +goto realloc;

Is this idiomatic SeaBIOS coding style?

How about "for (;;)" -- the code has many instances -- and reworking
this last branch accordingly?

(Apologies, not a very important comment.)

Thanks
Laszlo

> +}
> +}
> +
>  static const struct pci_device_id pci_device_tbl[] = {
>  /* PIIX3/PIIX4 PCI to ISA bridge */
>  PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
> @@ -290,6 +336,10 @@ static const struct pci_device_id pci_device_tbl[] = {
>  PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_setup),
>  PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_setup),
>  
> +/* Intel IGD OpRegion setup */
> +PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA,
> + intel_igd_opregion_setup),
> +
>  PCI_DEVICE_END,
>  };
>  
> 
> 
> ___
> SeaBIOS mailing list
> SeaBIOS@seabios.org
> http://www.seabios.org/mailman/listinfo/seabios
> 


___
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios