221 changes: 113 additions & 108 deletions src/hw/usb-xhci.c
Expand Up @@ -226,6 +226,11 @@ struct xhci_ring {
struct mutex_s lock;
};

struct xhci_portmap {
u8 start;
u8 count;
};

struct usb_xhci_s {
struct usb_s usb;

Expand All @@ -234,6 +239,8 @@ struct usb_xhci_s {
u32 ports;
u32 slots;
u8 context64;
struct xhci_portmap usb2;
struct xhci_portmap usb3;

/* xhci registers */
struct xhci_caps *caps;
Expand Down Expand Up @@ -347,6 +354,9 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port)
// A USB2 port - perform device reset
xhci_print_port_state(3, __func__, port, portsc);
writel(&xhci->pr[port].portsc, portsc | XHCI_PORTSC_PR);
if (wait_bit(&xhci->pr[port].portsc, XHCI_PORTSC_PED, XHCI_PORTSC_PED, 100) != 0)
return -1;
msleep(20); // Patch to make XHCI work on AMD Mullins
break;
default:
return -1;
Expand Down Expand Up @@ -374,6 +384,23 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port)
return rc;
}

static int
xhci_hub_portmap(struct usbhub_s *hub, u32 vport)
{
struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb);
u32 pport = vport + 1;

if (vport + 1 >= xhci->usb3.start &&
vport + 1 < xhci->usb3.start + xhci->usb3.count)
pport = vport + 2 - xhci->usb3.start;

if (vport + 1 >= xhci->usb2.start &&
vport + 1 < xhci->usb2.start + xhci->usb2.count)
pport = vport + 2 - xhci->usb2.start;

return pport;
}

static void
xhci_hub_disconnect(struct usbhub_s *hub, u32 port)
{
Expand All @@ -383,6 +410,7 @@ xhci_hub_disconnect(struct usbhub_s *hub, u32 port)
static struct usbhub_op_s xhci_hub_ops = {
.detect = xhci_hub_detect,
.reset = xhci_hub_reset,
.portmap = xhci_hub_portmap,
.disconnect = xhci_hub_disconnect,
};

Expand Down Expand Up @@ -553,17 +581,29 @@ xhci_controller_setup(struct pci_device *pci)
case 0x02:
name = readl(&xcap->data[0]);
ports = readl(&xcap->data[1]);
u8 major = (cap >> 24) & 0xff;
u8 minor = (cap >> 16) & 0xff;
u8 count = (ports >> 8) & 0xff;
u8 start = (ports >> 0) & 0xff;
dprintf(1, "XHCI protocol %c%c%c%c %x.%02x"
", %d ports (offset %d), def %x\n"
, (name >> 0) & 0xff
, (name >> 8) & 0xff
, (name >> 16) & 0xff
, (name >> 24) & 0xff
, (cap >> 24) & 0xff
, (cap >> 16) & 0xff
, (ports >> 8) & 0xff
, (ports >> 0) & 0xff
, major, minor
, count, start
, ports >> 16);
if (name == 0x20425355 /* "USB " */) {
if (major == 2) {
xhci->usb2.start = start;
xhci->usb2.count = count;
}
if (major == 3) {
xhci->usb3.start = start;
xhci->usb3.count = count;
}
}
break;
default:
dprintf(1, "XHCI extcap 0x%x @ %p\n", cap & 0xff, addr);
Expand Down Expand Up @@ -604,13 +644,16 @@ xhci_setup(void)
* End point communication
****************************************************************/

// Signal the hardware to process events on a TRB ring
static void xhci_doorbell(struct usb_xhci_s *xhci, u32 slotid, u32 value)
{
dprintf(5, "%s: slotid %d, epid %d\n", __func__, slotid, value);
struct xhci_db *db = xhci->db;
void *addr = &db[slotid].doorbell;
writel(addr, value);
}

// Dequeue events on the XHCI command ring generated by the hardware
static void xhci_process_events(struct usb_xhci_s *xhci)
{
struct xhci_ring *evts = xhci->evts;
Expand Down Expand Up @@ -675,13 +718,15 @@ static void xhci_process_events(struct usb_xhci_s *xhci)
}
}

// Check if a ring has any pending TRBs
static int xhci_ring_busy(struct xhci_ring *ring)
{
u32 eidx = ring->eidx;
u32 nidx = ring->nidx;
return (eidx != nidx);
}

// Wait for a ring to empty (all TRBs processed by hardware)
static int xhci_event_wait(struct usb_xhci_s *xhci,
struct xhci_ring *ring,
u32 timeout)
Expand All @@ -702,125 +747,100 @@ static int xhci_event_wait(struct usb_xhci_s *xhci,
}
}

static void xhci_trb_queue(struct xhci_ring *ring,
struct xhci_trb *trb)
// Add a TRB to the given ring
static void xhci_trb_fill(struct xhci_ring *ring
, void *data, u32 xferlen, u32 flags)
{
u32 nidx = ring->nidx;
u32 cs = ring->cs;
struct xhci_trb *dst;
u32 control;

if (nidx == XHCI_RING_ITEMS-1) {
dst = ring->ring + nidx;
control = (TR_LINK << 10); // trb type
control |= TRB_LK_TC;
control |= (cs ? TRB_C : 0);
dst->ptr_low = (u32)&ring[0];
struct xhci_trb *dst = &ring->ring[ring->nidx];
if (flags & TRB_TR_IDT) {
memcpy(&dst->ptr_low, data, xferlen);
} else {
dst->ptr_low = (u32)data;
dst->ptr_high = 0;
dst->status = 0;
dst->control = control;
nidx = 0;
cs = cs ? 0 : 1;
ring->nidx = nidx;
ring->cs = cs;
}
dst->status = xferlen;
dst->control = flags | (ring->cs ? TRB_C : 0);
}

// Queue a TRB onto a ring, wrapping ring as needed
static void xhci_trb_queue(struct xhci_ring *ring,
void *data, u32 xferlen, u32 flags)
{
if (ring->nidx >= ARRAY_SIZE(ring->ring) - 1) {
xhci_trb_fill(ring, ring->ring, 0, (TR_LINK << 10) | TRB_LK_TC);
ring->nidx = 0;
ring->cs ^= 1;
dprintf(5, "%s: ring %p [linked]\n", __func__, ring);
}

dst = ring->ring + nidx;
control = trb->control | (cs ? TRB_C : 0);

dst->ptr_low = trb->ptr_low;
dst->ptr_high = trb->ptr_high;
dst->status = trb->status;
dst->control = control;
nidx++;
ring->nidx = nidx;

xhci_trb_fill(ring, data, xferlen, flags);
ring->nidx++;
dprintf(5, "%s: ring %p [nidx %d, len %d]\n",
__func__, ring, nidx,
trb->status & 0xffff);
__func__, ring, ring->nidx, xferlen);
}

static int xhci_cmd_submit(struct usb_xhci_s *xhci,
struct xhci_trb *cmd)
// Submit a command to the xhci controller ring
static int xhci_cmd_submit(struct usb_xhci_s *xhci, struct xhci_inctx *inctx
, u32 flags)
{
int rc;
if (inctx) {
struct xhci_slotctx *slot = (void*)&inctx[1 << xhci->context64];
u32 port = ((slot->ctx[1] >> 16) & 0xff) - 1;
u32 portsc = readl(&xhci->pr[port].portsc);
if (!(portsc & XHCI_PORTSC_CCS)) {
// Device no longer connected?!
xhci_print_port_state(1, __func__, port, portsc);
return -1;
}
}

mutex_lock(&xhci->cmds->lock);
xhci_trb_queue(xhci->cmds, cmd);
xhci_trb_queue(xhci->cmds, inctx, 0, flags);
xhci_doorbell(xhci, 0, 0);
rc = xhci_event_wait(xhci, xhci->cmds, 1000);
int rc = xhci_event_wait(xhci, xhci->cmds, 1000);
mutex_unlock(&xhci->cmds->lock);
return rc;
}

static int xhci_cmd_enable_slot(struct usb_xhci_s *xhci)
{
struct xhci_trb cmd = {
.ptr_low = 0,
.ptr_high = 0,
.status = 0,
.control = (CR_ENABLE_SLOT << 10)
};
dprintf(3, "%s:\n", __func__);
int cc = xhci_cmd_submit(xhci, &cmd);
int cc = xhci_cmd_submit(xhci, NULL, CR_ENABLE_SLOT << 10);
if (cc != CC_SUCCESS)
return -1;
return (xhci->cmds->evt.control >> 24) & 0xff;
}

static int xhci_cmd_disable_slot(struct usb_xhci_s *xhci, u32 slotid)
{
struct xhci_trb cmd = {
.ptr_low = 0,
.ptr_high = 0,
.status = 0,
.control = (slotid << 24) | (CR_DISABLE_SLOT << 10)
};
dprintf(3, "%s: slotid %d\n", __func__, slotid);
return xhci_cmd_submit(xhci, &cmd);
return xhci_cmd_submit(xhci, NULL, (CR_DISABLE_SLOT << 10) | (slotid << 24));
}

static int xhci_cmd_address_device(struct usb_xhci_s *xhci, u32 slotid
, struct xhci_inctx *inctx)
{
struct xhci_trb cmd = {
.ptr_low = (u32)inctx,
.ptr_high = 0,
.status = 0,
.control = (slotid << 24) | (CR_ADDRESS_DEVICE << 10)
};
dprintf(3, "%s: slotid %d\n", __func__, slotid);
return xhci_cmd_submit(xhci, &cmd);
return xhci_cmd_submit(xhci, inctx
, (CR_ADDRESS_DEVICE << 10) | (slotid << 24));
}

static int xhci_cmd_configure_endpoint(struct usb_xhci_s *xhci, u32 slotid
, struct xhci_inctx *inctx)
{
struct xhci_trb cmd = {
.ptr_low = (u32)inctx,
.ptr_high = 0,
.status = 0,
.control = (slotid << 24) | (CR_CONFIGURE_ENDPOINT << 10)
};
dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
slotid, inctx->add, inctx->del);
return xhci_cmd_submit(xhci, &cmd);
return xhci_cmd_submit(xhci, inctx
, (CR_CONFIGURE_ENDPOINT << 10) | (slotid << 24));
}

static int xhci_cmd_evaluate_context(struct usb_xhci_s *xhci, u32 slotid
, struct xhci_inctx *inctx)
{
struct xhci_trb cmd = {
.ptr_low = (u32)inctx,
.ptr_high = 0,
.status = 0,
.control = (slotid << 24) | (CR_EVALUATE_CONTEXT << 10)
};
dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
slotid, inctx->add, inctx->del);
return xhci_cmd_submit(xhci, &cmd);
return xhci_cmd_submit(xhci, inctx
, (CR_EVALUATE_CONTEXT << 10) | (slotid << 24));
}

static struct xhci_inctx *
Expand Down Expand Up @@ -1055,37 +1075,31 @@ xhci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe
return upipe;
}

static void xhci_xfer_queue(struct xhci_pipe *pipe,
void *data, int datalen, u32 flags)
{
struct xhci_trb trb;
memset(&trb, 0, sizeof(trb));
if (flags & TRB_TR_IDT)
memcpy(&trb.ptr_low, data, datalen);
else
trb.ptr_low = (u32)data;
trb.status = datalen;
trb.control = flags;
xhci_trb_queue(&pipe->reqs, &trb);
}

static void xhci_xfer_kick(struct xhci_pipe *pipe)
// Submit a USB "setup" message request to the pipe's ring
static void xhci_xfer_setup(struct xhci_pipe *pipe, int dir, void *cmd
, void *data, int datalen)
{
struct usb_xhci_s *xhci = container_of(
pipe->pipe.cntl, struct usb_xhci_s, usb);
u32 slotid = pipe->slotid;
u32 epid = pipe->epid;

dprintf(5, "%s: ring %p, slotid %d, epid %d\n",
__func__, &pipe->reqs, slotid, epid);
xhci_doorbell(xhci, slotid, epid);
xhci_trb_queue(&pipe->reqs, cmd, USB_CONTROL_SETUP_SIZE
, (TR_SETUP << 10) | TRB_TR_IDT
| ((datalen ? (dir ? 3 : 2) : 0) << 16));
if (datalen)
xhci_trb_queue(&pipe->reqs, data, datalen, (TR_DATA << 10)
| ((dir ? 1 : 0) << 16));
xhci_trb_queue(&pipe->reqs, NULL, 0, (TR_STATUS << 10) | TRB_TR_IOC
| ((dir ? 0 : 1) << 16));
xhci_doorbell(xhci, pipe->slotid, pipe->epid);
}

// Submit a USB transfer request to the pipe's ring
static void xhci_xfer_normal(struct xhci_pipe *pipe,
void *data, int datalen)
{
xhci_xfer_queue(pipe, data, datalen, (TR_NORMAL << 10) | TRB_TR_IOC);
xhci_xfer_kick(pipe);
struct usb_xhci_s *xhci = container_of(
pipe->pipe.cntl, struct usb_xhci_s, usb);
xhci_trb_queue(&pipe->reqs, data, datalen, (TR_NORMAL << 10) | TRB_TR_IOC);
xhci_doorbell(xhci, pipe->slotid, pipe->epid);
}

int
Expand All @@ -1103,16 +1117,7 @@ xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
if (req->bRequest == USB_REQ_SET_ADDRESS)
// Set address command sent during xhci_alloc_pipe.
return 0;

xhci_xfer_queue(pipe, (void*)req, USB_CONTROL_SETUP_SIZE
, (TR_SETUP << 10) | TRB_TR_IDT
| ((datalen ? (dir ? 3 : 2) : 0) << 16));
if (datalen)
xhci_xfer_queue(pipe, data, datalen, (TR_DATA << 10)
| ((dir ? 1 : 0) << 16));
xhci_xfer_queue(pipe, NULL, 0, (TR_STATUS << 10) | TRB_TR_IOC
| ((dir ? 0 : 1) << 16));
xhci_xfer_kick(pipe);
xhci_xfer_setup(pipe, dir, (void*)req, data, datalen);
} else {
xhci_xfer_normal(pipe, data, datalen);
}
Expand Down
2 changes: 1 addition & 1 deletion src/hw/usb.c
Expand Up @@ -456,7 +456,7 @@ usb_hub_port_setup(void *data)
goto done;
}

u32 usb_time_sigatt;
static u32 usb_time_sigatt;

void
usb_enumerate(struct usbhub_s *hub)
Expand Down
3 changes: 2 additions & 1 deletion src/hw/usb.h
Expand Up @@ -56,6 +56,7 @@ struct usbhub_s {
struct usbhub_op_s {
int (*detect)(struct usbhub_s *hub, u32 port);
int (*reset)(struct usbhub_s *hub, u32 port);
int (*portmap)(struct usbhub_s *hub, u32 port);
void (*disconnect)(struct usbhub_s *hub, u32 port);
};

Expand All @@ -77,7 +78,7 @@ struct usbhub_op_s {
****************************************************************/

// USB mandated timings (in ms)
#define USB_TIME_SIGATT 100
#define USB_TIME_SIGATT 500 // 100 // WIV changed to 500 to make ADATA CIO3 stick working ( 200 is sufficient for SanDisk Ultra USB 3.0)
#define USB_TIME_ATTDB 100
#define USB_TIME_DRST 10
#define USB_TIME_DRSTR 50
Expand Down
17 changes: 9 additions & 8 deletions src/hw/virtio-blk.c
Expand Up @@ -32,9 +32,9 @@ struct virtiodrive_s {
static int
virtio_blk_op(struct disk_op_s *op, int write)
{
struct virtiodrive_s *vdrive_gf =
container_of(op->drive_gf, struct virtiodrive_s, drive);
struct vring_virtqueue *vq = vdrive_gf->vq;
struct virtiodrive_s *vdrive =
container_of(op->drive_fl, struct virtiodrive_s, drive);
struct vring_virtqueue *vq = vdrive->vq;
struct virtio_blk_outhdr hdr = {
.type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN,
.ioprio = 0,
Expand All @@ -48,7 +48,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
},
{
.addr = op->buf_fl,
.length = vdrive_gf->drive.blksize * op->count,
.length = vdrive->drive.blksize * op->count,
},
{
.addr = (void*)(&status),
Expand All @@ -61,7 +61,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
vring_add_buf(vq, sg, 2, 1, 0, 0);
else
vring_add_buf(vq, sg, 1, 2, 0, 0);
vring_kick(&vdrive_gf->vp, vq, 1);
vring_kick(&vdrive->vp, vq, 1);

/* Wait for reply */
while (!vring_more_used(vq))
Expand All @@ -73,7 +73,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
/* Clear interrupt status register. Avoid leaving interrupts stuck if
* VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
*/
vp_get_isr(&vdrive_gf->vp);
vp_get_isr(&vdrive->vp);

return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
}
Expand All @@ -99,7 +99,7 @@ init_virtio_blk(void *data)
struct pci_device *pci = data;
u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER;
dprintf(1, "found virtio-blk at %pP\n", pci);
struct virtiodrive_s *vdrive = malloc_fseg(sizeof(*vdrive));
struct virtiodrive_s *vdrive = malloc_low(sizeof(*vdrive));
if (!vdrive) {
warn_noalloc();
return;
Expand All @@ -118,13 +118,14 @@ init_virtio_blk(void *data)
struct vp_device *vp = &vdrive->vp;
u64 features = vp_get_features(vp);
u64 version1 = 1ull << VIRTIO_F_VERSION_1;
u64 iommu_platform = 1ull << VIRTIO_F_IOMMU_PLATFORM;
u64 blk_size = 1ull << VIRTIO_BLK_F_BLK_SIZE;
if (!(features & version1)) {
dprintf(1, "modern device without virtio_1 feature bit: %pP\n", pci);
goto fail;
}

features = features & (version1 | blk_size);
features = features & (version1 | iommu_platform | blk_size);
vp_set_features(vp, features);
status |= VIRTIO_CONFIG_S_FEATURES_OK;
vp_set_status(vp, status);
Expand Down
6 changes: 3 additions & 3 deletions src/hw/virtio-pci.c
Expand Up @@ -19,7 +19,7 @@
#include "malloc.h" // free
#include "output.h" // dprintf
#include "pci.h" // pci_config_readl
#include "pcidevice.h" // pci_find_capability
#include "pcidevice.h" // struct pci_device
#include "pci_regs.h" // PCI_BASE_ADDRESS_0
#include "string.h" // memset
#include "virtio-pci.h"
Expand Down Expand Up @@ -381,7 +381,7 @@ int vp_find_vq(struct vp_device *vp, int queue_index,

void vp_init_simple(struct vp_device *vp, struct pci_device *pci)
{
u8 cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, 0);
u8 cap = pci_find_capability(pci->bdf, PCI_CAP_ID_VNDR, 0);
struct vp_cap *vp_cap;
const char *mode;
u32 offset, base, mul;
Expand Down Expand Up @@ -479,7 +479,7 @@ void vp_init_simple(struct vp_device *vp, struct pci_device *pci)
vp_cap->cap, type, vp_cap->bar, addr, offset, mode);
}

cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, cap);
cap = pci_find_capability(pci->bdf, PCI_CAP_ID_VNDR, cap);
}

if (vp->common.cap && vp->notify.cap && vp->isr.cap && vp->device.cap) {
Expand Down
1 change: 0 additions & 1 deletion src/hw/virtio-ring.c
Expand Up @@ -16,7 +16,6 @@
*
*/

#include "biosvar.h" // GET_GLOBAL
#include "output.h" // panic
#include "virtio-ring.h"
#include "virtio-pci.h"
Expand Down
1 change: 1 addition & 0 deletions src/hw/virtio-ring.h
Expand Up @@ -18,6 +18,7 @@

/* v1.0 compliant. */
#define VIRTIO_F_VERSION_1 32
#define VIRTIO_F_IOMMU_PLATFORM 33

#define MAX_QUEUE_NUM (128)

Expand Down
44 changes: 29 additions & 15 deletions src/hw/virtio-scsi.c
Expand Up @@ -7,7 +7,6 @@
//
// This file may be distributed under the terms of the GNU LGPLv3 license.

#include "biosvar.h" // GET_GLOBALFLAT
#include "block.h" // struct drive_s
#include "blockcmd.h" // scsi_drive_setup
#include "config.h" // CONFIG_*
Expand Down Expand Up @@ -39,7 +38,7 @@ virtio_scsi_process_op(struct disk_op_s *op)
if (! CONFIG_VIRTIO_SCSI)
return 0;
struct virtio_lun_s *vlun =
container_of(op->drive_gf, struct virtio_lun_s, drive);
container_of(op->drive_fl, struct virtio_lun_s, drive);
struct vp_device *vp = vlun->vp;
struct vring_virtqueue *vq = vlun->vq;
struct virtio_scsi_req_cmd req;
Expand Down Expand Up @@ -94,15 +93,11 @@ virtio_scsi_process_op(struct disk_op_s *op)
return DISK_RET_EBADTRACK;
}

static int
virtio_scsi_add_lun(struct pci_device *pci, struct vp_device *vp,
struct vring_virtqueue *vq, u16 target, u16 lun)
static void
virtio_scsi_init_lun(struct virtio_lun_s *vlun, struct pci_device *pci,
struct vp_device *vp, struct vring_virtqueue *vq,
u16 target, u16 lun)
{
struct virtio_lun_s *vlun = malloc_fseg(sizeof(*vlun));
if (!vlun) {
warn_noalloc();
return -1;
}
memset(vlun, 0, sizeof(*vlun));
vlun->drive.type = DTYPE_VIRTIO_SCSI;
vlun->drive.cntl_id = pci->bdf;
Expand All @@ -111,8 +106,22 @@ virtio_scsi_add_lun(struct pci_device *pci, struct vp_device *vp,
vlun->vq = vq;
vlun->target = target;
vlun->lun = lun;
}

int prio = bootprio_find_scsi_device(pci, target, lun);
static int
virtio_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv)
{
struct virtio_lun_s *tmpl_vlun =
container_of(tmpl_drv, struct virtio_lun_s, drive);
struct virtio_lun_s *vlun = malloc_low(sizeof(*vlun));
if (!vlun) {
warn_noalloc();
return -1;
}
virtio_scsi_init_lun(vlun, tmpl_vlun->pci, tmpl_vlun->vp, tmpl_vlun->vq,
tmpl_vlun->target, lun);

int prio = bootprio_find_scsi_device(vlun->pci, vlun->target, vlun->lun);
int ret = scsi_drive_setup(&vlun->drive, "virtio-scsi", prio);
if (ret)
goto fail;
Expand All @@ -127,9 +136,13 @@ static int
virtio_scsi_scan_target(struct pci_device *pci, struct vp_device *vp,
struct vring_virtqueue *vq, u16 target)
{
/* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */
int ret = virtio_scsi_add_lun(pci, vp, vq, target, 0);
return ret < 0 ? 0 : 1;

struct virtio_lun_s vlun0;

virtio_scsi_init_lun(&vlun0, pci, vp, vq, target, 0);

int ret = scsi_rep_luns_scan(&vlun0.drive, virtio_scsi_add_lun);
return ret < 0 ? 0 : ret;
}

static void
Expand All @@ -149,12 +162,13 @@ init_virtio_scsi(void *data)
if (vp->use_modern) {
u64 features = vp_get_features(vp);
u64 version1 = 1ull << VIRTIO_F_VERSION_1;
u64 iommu_platform = 1ull << VIRTIO_F_IOMMU_PLATFORM;
if (!(features & version1)) {
dprintf(1, "modern device without virtio_1 feature bit: %pP\n", pci);
goto fail;
}

vp_set_features(vp, version1);
vp_set_features(vp, features & (version1 | iommu_platform));
status |= VIRTIO_CONFIG_S_FEATURES_OK;
vp_set_status(vp, status);
if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) {
Expand Down
18 changes: 17 additions & 1 deletion src/kbd.c
Expand Up @@ -29,7 +29,7 @@ kbd_init(void)
, x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf));
}

static u8
u8
enqueue_key(u16 keycode)
{
u16 buffer_start = GET_BDA(kbd_buf_start_offset);
Expand Down Expand Up @@ -375,6 +375,22 @@ struct scaninfo key_ext_slash VAR16 = {
0xe02f, 0xe02f, 0x9500, 0xa400
};

u16 ascii_to_keycode(u8 ascii)
{
int i;

for (i = 0; i < ARRAY_SIZE(scan_to_keycode); i++) {
if ((GET_GLOBAL(scan_to_keycode[i].normal) & 0xff) == ascii)
return GET_GLOBAL(scan_to_keycode[i].normal);
if ((GET_GLOBAL(scan_to_keycode[i].shift) & 0xff) == ascii)
return GET_GLOBAL(scan_to_keycode[i].shift);
if ((GET_GLOBAL(scan_to_keycode[i].control) & 0xff) == ascii)
return GET_GLOBAL(scan_to_keycode[i].control);
}
return 0;
}

// Handle a ps2 style scancode read from the keyboard.
static void
kbd_set_flag(int key_release, u16 set_bit0, u8 set_bit1, u16 toggle_bit)
{
Expand Down
8 changes: 0 additions & 8 deletions src/misc.c
Expand Up @@ -51,14 +51,6 @@ handle_05(struct bregs *regs)
debug_enter(regs, DEBUG_HDL_05);
}

// INT 10h Video Support Service Entry Point
void VISIBLE16
handle_10(struct bregs *regs)
{
debug_enter(regs, DEBUG_HDL_10);
// don't do anything, since the VGA BIOS handles int10h requests
}

// NMI handler
void VISIBLE16
handle_02(void)
Expand Down
29 changes: 16 additions & 13 deletions src/optionroms.c
Expand Up @@ -136,9 +136,12 @@ init_optionrom(struct rom_header *rom, u16 bdf, int isvga)

tpm_option_rom(newrom, rom->size * 512);

if (isvga || get_pnp_rom(newrom))
// Only init vga and PnP roms here.
callrom(newrom, bdf);
//TODO: Find a way to hide initialisation string of iPXE
//which was printed by calling callrom function

if (isvga)
// Only init vga roms here.
callrom(newrom, bdf);

return rom_confirm(newrom->size * 512);
}
Expand Down Expand Up @@ -188,15 +191,18 @@ deploy_romfile(struct romfile_s *file)
static void
run_file_roms(const char *prefix, int isvga, u64 *sources)
{
int pxen = find_pxen();
struct romfile_s *file = NULL;
for (;;) {
file = romfile_findprefix(prefix, file);
if (!file)
break;
struct rom_header *rom = deploy_romfile(file);
if (rom) {
setRomSource(sources, rom, (u32)file);
init_optionrom(rom, 0, isvga);
if ((strcmp(file->name, "genroms/pxe.rom") == 0) && (pxen == 1)) {
struct rom_header *rom = deploy_romfile(file);
if (rom) {
setRomSource(sources, rom, (u32)file);
init_optionrom(rom, 0, isvga);
}
}
}
}
Expand Down Expand Up @@ -432,12 +438,9 @@ vgarom_setup(void)
run_file_roms("vgaroms/", 1, NULL);
rom_reserve(0);

if (rom_get_last() == BUILD_ROM_START)
// No VGA rom found
return;

VgaROM = (void*)BUILD_ROM_START;
enable_vga_console();
if (rom_get_last() != BUILD_ROM_START)
// VGA rom found
VgaROM = (void*)BUILD_ROM_START;
}

void
Expand Down
2 changes: 2 additions & 0 deletions src/post.c
Expand Up @@ -208,6 +208,8 @@ maininit(void)

// Run vga option rom
vgarom_setup();
sercon_setup();
enable_vga_console();

// Do hardware initialization (if running synchronously)
if (!threads_during_optionroms()) {
Expand Down
8 changes: 6 additions & 2 deletions src/resume.c
Expand Up @@ -17,6 +17,7 @@
#include "string.h" // memset
#include "util.h" // dma_setup
#include "tcgbios.h" // tpm_s3_resume
#include "fw/romfile_loader.h" // romfile_fw_cfg_resume

// Handler for post calls that look like a resume.
void VISIBLE16
Expand Down Expand Up @@ -105,6 +106,9 @@ s3_resume(void)
tpm_s3_resume();
s3_resume_vga();

/* Replay any fw_cfg entries that go back to the host */
romfile_fw_cfg_resume();

make_bios_readonly();

// Invoke the resume vector.
Expand All @@ -121,8 +125,8 @@ tryReboot(void)
{
dprintf(1, "Attempting a hard reboot\n");

// Setup for reset on qemu.
qemu_prep_reset();
// Use a QEMU specific reboot on QEMU
qemu_reboot();

// Reboot using ACPI RESET_REG
acpi_reboot();
Expand Down
93 changes: 90 additions & 3 deletions src/romfile.c
Expand Up @@ -9,6 +9,7 @@
#include "output.h" // dprintf
#include "romfile.h" // struct romfile_s
#include "string.h" // memcmp
#include "fw/coreboot.h" // cbfs_romfile overrides

static struct romfile_s *RomfileRoot VARVERIFY32INIT;

Expand All @@ -28,8 +29,16 @@ __romfile_findprefix(const char *prefix, int prefixlen, struct romfile_s *prev)
if (prev)
cur = prev->next;
while (cur) {
if (memcmp(prefix, cur->name, prefixlen) == 0)
return cur;
if (memcmp(prefix, cur->name, prefixlen) == 0) {

int dont_hide;
// Check if we should hide this
char *data = get_cbmem_file( (char *) cur->name, &dont_hide );
if (!data) // no override for this file
return cur;
if (dont_hide) // We know it and shouldn't hide
return cur;
}
cur = cur->next;
}
return NULL;
Expand All @@ -52,6 +61,17 @@ romfile_find(const char *name)
void *
romfile_loadfile(const char *name, int *psize)
{
// First try to read a file override from cbmem
char *data = get_cbmem_file( (char *) name, psize );

if ( data ) {
if ( !*psize ) {
dprintf(3, "Hiding romfile '%s'\n", name);
return NULL;
}
return data;
}

struct romfile_s *file = romfile_find(name);
if (!file)
return NULL;
Expand All @@ -60,7 +80,7 @@ romfile_loadfile(const char *name, int *psize)
if (!filesize)
return NULL;

char *data = malloc_tmphigh(filesize+1);
data = malloc_tmphigh(filesize+1);
if (!data) {
warn_noalloc();
return NULL;
Expand All @@ -83,6 +103,27 @@ romfile_loadfile(const char *name, int *psize)
u64
romfile_loadint(const char *name, u64 defval)
{
int size;

// First try to read a file override from cbmem
char *data = get_cbmem_file( (char *) name, &size );

if ( data ) {
u64 val = 0;

switch (size){
case 1:
case 2:
case 4:
case 8:
memcpy(&val, data, size);
break;
default:
return defval;
}
return val;
}

struct romfile_s *file = romfile_find(name);
if (!file)
return defval;
Expand All @@ -98,3 +139,49 @@ romfile_loadint(const char *name, u64 defval)
return defval;
return val;
}

struct const_romfile_s {
struct romfile_s file;
void *data;
};

static int
const_read_file(struct romfile_s *file, void *dst, u32 maxlen)
{
if (file->size > maxlen)
return -1;
struct const_romfile_s *cfile;
cfile = container_of(file, struct const_romfile_s, file);
if (maxlen > file->size)
maxlen = file->size;
memcpy(dst, cfile->data, maxlen);
return file->size;
}

static void
const_romfile_add(char *name, void *data, int size)
{
struct const_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
if (!cfile) {
warn_noalloc();
return;
}
memset(cfile, 0, sizeof(*cfile));
strtcpy(cfile->file.name, name, sizeof(cfile->file.name));
cfile->file.size = size;
cfile->file.copy = const_read_file;
cfile->data = data;
romfile_add(&cfile->file);
}

void
const_romfile_add_int(char *name, u32 value)
{
u32 *data = malloc_tmp(sizeof(*data));
if (!data) {
warn_noalloc();
return;
}
*data = value;
const_romfile_add(name, data, sizeof(*data));
}
2 changes: 2 additions & 0 deletions src/romfile.h
Expand Up @@ -16,4 +16,6 @@ struct romfile_s *romfile_find(const char *name);
void *romfile_loadfile(const char *name, int *psize);
u64 romfile_loadint(const char *name, u64 defval);

void const_romfile_add_int(char *name, u32 value);

#endif // romfile.h
50 changes: 49 additions & 1 deletion src/romlayout.S
Expand Up @@ -414,6 +414,53 @@ __csm_return:
popfw
lretw

// Serial console "hooked vga" entry point
DECLFUNC entry_sercon
entry_sercon:
// Setup for chain loading to real vga handler
pushfw
pushl %cs:sercon_real_vga_handler

// Set %ds to varlow segment
cli
cld
pushw %ds
pushl %eax
movl $_zonelow_seg, %eax
movl %eax, %ds

// Test if the sercon handler can be called
movl %esp, %eax // Test for broken x86emu
pushl $1f
retl
1: cmpl %esp, %eax
jne 4f
cmpb $0, sercon_enable // Test that sercon is enabled
je 3f

// call handle_sercon
popl %eax
popw %ds
2: pushl $handle_sercon
#if CONFIG_ENTRY_EXTRASTACK
jmp irqentry_arg_extrastack
#else
jmp irqentry_arg
#endif

// sercon disabled - check for legacy text modeset and otherwise exit
3: popl %eax
popw %ds
cmpw $0x0007, %ax
jle 2b
iretw

// Running on broken x86emu - restore stack and exit
4: movl %eax, %esp
popl %eax
popw %ds
iretw


/****************************************************************
* Interrupt entry points
Expand Down Expand Up @@ -597,7 +644,8 @@ entry_10_0x0f:
iretw

ORG 0xf065
IRQ_ENTRY_ARG 10
entry_10:
iretw

// 0xf0a4 - VideoParams in misc.c

Expand Down
665 changes: 665 additions & 0 deletions src/sercon.c

Large diffs are not rendered by default.

18 changes: 13 additions & 5 deletions src/stacks.c
Expand Up @@ -66,8 +66,10 @@ call32_prep(u8 method)

// Backup cmos index register and disable nmi
u8 cmosindex = inb(PORT_CMOS_INDEX);
outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
inb(PORT_CMOS_DATA);
if (!(cmosindex & NMI_DISABLE_BIT)) {
outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
inb(PORT_CMOS_DATA);
}
SET_LOW(Call16Data.cmosindex, cmosindex);

SET_LOW(Call16Data.method, method);
Expand All @@ -84,7 +86,9 @@ call32_post(void)

if (!CONFIG_CALL32_SMM || method != C16_SMM) {
// Restore a20
set_a20(GET_LOW(Call16Data.a20));
u8 a20 = GET_LOW(Call16Data.a20);
if (!a20)
set_a20(0);

// Restore gdt and fs/gs
struct descloc_s gdt;
Expand All @@ -101,8 +105,11 @@ call32_post(void)
}

// Restore cmos index register
outb(GET_LOW(Call16Data.cmosindex), PORT_CMOS_INDEX);
inb(PORT_CMOS_DATA);
u8 cmosindex = GET_LOW(Call16Data.cmosindex);
if (!(cmosindex & NMI_DISABLE_BIT)) {
outb(cmosindex, PORT_CMOS_INDEX);
inb(PORT_CMOS_DATA);
}
return method;
}

Expand Down Expand Up @@ -496,6 +503,7 @@ void
thread_setup(void)
{
CanInterrupt = 1;
call16_override(1);
if (! CONFIG_THREADS)
return;
ThreadControl = romfile_loadint("etc/threads", 1);
Expand Down
7 changes: 0 additions & 7 deletions src/std/acpi.h
Expand Up @@ -294,12 +294,6 @@ struct acpi_table_mcfg {
struct acpi_mcfg_allocation allocation[0];
} PACKED;


struct rsdt_descriptor {
ACPI_TABLE_HEADER_DEF
u32 entry[1];
} PACKED;

#define TCPA_SIGNATURE 0x41504354
struct tcpa_descriptor_rev2
{
Expand All @@ -313,5 +307,4 @@ struct tcpa_descriptor_rev2
#define TCPA_ACPI_CLASS_CLIENT 0
#define TCPA_ACPI_CLASS_SERVER 1


#endif // acpi.h
199 changes: 97 additions & 102 deletions src/std/tcg.h
Expand Up @@ -3,6 +3,17 @@

#include "types.h"

#define SHA1_BUFSIZE 20
#define SHA256_BUFSIZE 32
#define SHA384_BUFSIZE 48
#define SHA512_BUFSIZE 64
#define SM3_256_BUFSIZE 32


/****************************************************************
* 16bit BIOS interface
****************************************************************/

/* Define for section 12.3 */
#define TCG_PC_OK 0x0
#define TCG_PC_TPMERROR 0x1
Expand Down Expand Up @@ -48,35 +59,6 @@
#define TCG_PC_TPM_NOT_PRESENT (TPM_RET_BASE + 0x22)
#define TCG_PC_TPM_DEACTIVATED (TPM_RET_BASE + 0x23)


#define TPM_ORD_SelfTestFull 0x00000050
#define TPM_ORD_ForceClear 0x0000005d
#define TPM_ORD_GetCapability 0x00000065
#define TPM_ORD_PhysicalEnable 0x0000006f
#define TPM_ORD_PhysicalDisable 0x00000070
#define TPM_ORD_SetOwnerInstall 0x00000071
#define TPM_ORD_PhysicalSetDeactivated 0x00000072
#define TPM_ORD_SetTempDeactivated 0x00000073
#define TPM_ORD_Startup 0x00000099
#define TPM_ORD_PhysicalPresence 0x4000000a
#define TPM_ORD_Extend 0x00000014
#define TSC_ORD_ResetEstablishmentBit 0x4000000b


#define TPM_ST_CLEAR 0x1
#define TPM_ST_STATE 0x2
#define TPM_ST_DEACTIVATED 0x3


/* TPM command error codes */
#define TPM_INVALID_POSTINIT 0x26
#define TPM_BAD_LOCALITY 0x3d

/* TPM command tags */
#define TPM_TAG_RQU_CMD 0x00c1
#define TPM_TAG_RQU_AUTH1_CMD 0x00c2
#define TPM_TAG_RQU_AUTH2_CMD 0x00c3

/* interrupt identifiers (al register) */
enum irq_ids {
TCG_StatusCheck = 0,
Expand All @@ -89,22 +71,6 @@ enum irq_ids {
TCG_CompactHashLogExtendEvent = 7,
};

/* event types: 10.4.1 / table 11 */
#define EV_POST_CODE 1
#define EV_NO_ACTION 3
#define EV_SEPARATOR 4
#define EV_ACTION 5
#define EV_EVENT_TAG 6
#define EV_COMPACT_HASH 12
#define EV_IPL 13
#define EV_IPL_PARTITION_DATA 14

#define SHA1_BUFSIZE 20
#define SHA256_BUFSIZE 32
#define SHA384_BUFSIZE 48
#define SHA512_BUFSIZE 64
#define SM3_256_BUFSIZE 32

/* Input and Output blocks for the TCG BIOS commands */

struct hleei_short
Expand All @@ -118,7 +84,6 @@ struct hleei_short
u32 logdatalen;
} PACKED;


struct hleei_long
{
u16 ipblength;
Expand All @@ -131,7 +96,6 @@ struct hleei_long
u32 logdatalen;
} PACKED;


struct hleeo
{
u16 opblength;
Expand All @@ -140,7 +104,6 @@ struct hleeo
u8 digest[SHA1_BUFSIZE];
} PACKED;


struct pttti
{
u16 ipblength;
Expand All @@ -150,15 +113,13 @@ struct pttti
u8 tpmopin[0];
} PACKED;


struct pttto
{
u16 opblength;
u16 reserved;
u8 tpmopout[0];
};


struct hlei
{
u16 ipblength;
Expand All @@ -171,15 +132,13 @@ struct hlei
u32 logdatalen;
} PACKED;


struct hleo
{
u16 opblength;
u16 reserved;
u32 eventnumber;
} PACKED;


struct hai
{
u16 ipblength;
Expand All @@ -189,7 +148,6 @@ struct hai
u32 algorithmid;
} PACKED;


struct ti
{
u16 ipblength;
Expand All @@ -199,15 +157,13 @@ struct ti
u8 tssoperandin[0];
} PACKED;


struct to
{
u16 opblength;
u16 reserved;
u8 tssoperandout[0];
} PACKED;


struct pcpes
{
u32 pcrindex;
Expand All @@ -217,50 +173,64 @@ struct pcpes
u8 event[0];
} PACKED;

struct pcctes
{
u32 eventid;
u32 eventdatasize;
u8 digest[SHA1_BUFSIZE];
} PACKED;

struct pcctes_romex
{
u32 eventid;
u32 eventdatasize;
u16 reserved;
u16 pfa;
u8 digest[SHA1_BUFSIZE];
} PACKED;
/****************************************************************
* TPM v1.2 hardware commands
****************************************************************/

#define TPM_ORD_SelfTestFull 0x00000050
#define TPM_ORD_ForceClear 0x0000005d
#define TPM_ORD_GetCapability 0x00000065
#define TPM_ORD_PhysicalEnable 0x0000006f
#define TPM_ORD_PhysicalDisable 0x00000070
#define TPM_ORD_SetOwnerInstall 0x00000071
#define TPM_ORD_PhysicalSetDeactivated 0x00000072
#define TPM_ORD_SetTempDeactivated 0x00000073
#define TPM_ORD_Startup 0x00000099
#define TPM_ORD_PhysicalPresence 0x4000000a
#define TPM_ORD_Extend 0x00000014
#define TSC_ORD_ResetEstablishmentBit 0x4000000b

#define TPM_ST_CLEAR 0x0001
#define TPM_ST_STATE 0x0002
#define TPM_ST_DEACTIVATED 0x0003

#define TPM_PP_CMD_ENABLE 0x0020
#define TPM_PP_PRESENT 0x0008
#define TPM_PP_NOT_PRESENT_LOCK 0x0014

/* TPM command error codes */
#define TPM_INVALID_POSTINIT 0x26
#define TPM_BAD_LOCALITY 0x3d

/* TPM command tags */
#define TPM_TAG_RQU_CMD 0x00c1
#define TPM_TAG_RQU_AUTH1_CMD 0x00c2
#define TPM_TAG_RQU_AUTH2_CMD 0x00c3

struct tpm_req_header {
u16 tag;
u32 totlen;
u32 ordinal;
} PACKED;


struct tpm_rsp_header {
u16 tag;
u32 totlen;
u32 errcode;
} PACKED;


struct tpm_req_extend {
struct tpm_req_header hdr;
u32 pcrindex;
u8 digest[SHA1_BUFSIZE];
} PACKED;


struct tpm_rsp_extend {
struct tpm_rsp_header hdr;
u8 digest[SHA1_BUFSIZE];
} PACKED;


struct tpm_req_getcap {
struct tpm_req_header hdr;
u32 capArea;
Expand All @@ -276,13 +246,11 @@ struct tpm_req_getcap {
#define TPM_CAP_PROP_TIS_TIMEOUT 0x115
#define TPM_CAP_PROP_DURATION 0x120


struct tpm_permanent_flags {
u16 tag;
u8 flags[20];
} PACKED;


enum permFlagsIndex {
PERM_FLAG_IDX_DISABLE = 0,
PERM_FLAG_IDX_OWNERSHIP,
Expand All @@ -295,7 +263,6 @@ enum permFlagsIndex {
PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE,
};


struct tpm_res_getcap_perm_flags {
struct tpm_rsp_header hdr;
u32 size;
Expand Down Expand Up @@ -325,53 +292,32 @@ struct tpm_res_getcap_ownerauth {
u8 flag;
} PACKED;


struct tpm_res_getcap_timeouts {
struct tpm_rsp_header hdr;
u32 size;
u32 timeouts[4];
} PACKED;


struct tpm_res_getcap_durations {
struct tpm_rsp_header hdr;
u32 size;
u32 durations[3];
} PACKED;


struct tpm_res_sha1start {
struct tpm_rsp_header hdr;
u32 max_num_bytes;
} PACKED;


struct tpm_res_sha1complete {
struct tpm_rsp_header hdr;
u8 hash[20];
} PACKED;

#define TPM_STATE_ENABLED 1
#define TPM_STATE_ACTIVE 2
#define TPM_STATE_OWNED 4
#define TPM_STATE_OWNERINSTALL 8

/*
* physical presence interface
*/

#define TPM_PPI_OP_NOOP 0
#define TPM_PPI_OP_ENABLE 1
#define TPM_PPI_OP_DISABLE 2
#define TPM_PPI_OP_ACTIVATE 3
#define TPM_PPI_OP_DEACTIVATE 4
#define TPM_PPI_OP_CLEAR 5
#define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8
#define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9

/*
* TPM 2
*/
/****************************************************************
* TPM v2.0 hardware commands
****************************************************************/

#define TPM2_NO 0
#define TPM2_YES 1
Expand Down Expand Up @@ -414,7 +360,8 @@ struct tpm_res_sha1complete {

/* TPM 2 data structures */

struct tpm2b_stir {
struct tpm2_req_stirrandom {
struct tpm_req_header hdr;
u16 size;
u64 stir;
} PACKED;
Expand Down Expand Up @@ -506,7 +453,20 @@ struct tpml_pcr_selection {
struct tpms_pcr_selection selections[0];
} PACKED;

/* TPM 2 log entry */

/****************************************************************
* ACPI TCPA table interface
****************************************************************/

/* event types: 10.4.1 / table 11 */
#define EV_POST_CODE 1
#define EV_NO_ACTION 3
#define EV_SEPARATOR 4
#define EV_ACTION 5
#define EV_EVENT_TAG 6
#define EV_COMPACT_HASH 12
#define EV_IPL 13
#define EV_IPL_PARTITION_DATA 14

struct tpm2_digest_value {
u16 hashAlg;
Expand Down Expand Up @@ -556,4 +516,39 @@ struct TCG_EfiSpecIdEventStruct {

#define TPM_TCPA_ACPI_CLASS_CLIENT 0

struct pcctes
{
u32 eventid;
u32 eventdatasize;
u8 digest[SHA1_BUFSIZE];
} PACKED;

struct pcctes_romex
{
u32 eventid;
u32 eventdatasize;
u16 reserved;
u16 pfa;
u8 digest[SHA1_BUFSIZE];
} PACKED;


/****************************************************************
* Physical presence interface
****************************************************************/

#define TPM_STATE_ENABLED 1
#define TPM_STATE_ACTIVE 2
#define TPM_STATE_OWNED 4
#define TPM_STATE_OWNERINSTALL 8

#define TPM_PPI_OP_NOOP 0
#define TPM_PPI_OP_ENABLE 1
#define TPM_PPI_OP_DISABLE 2
#define TPM_PPI_OP_ACTIVATE 3
#define TPM_PPI_OP_DEACTIVATE 4
#define TPM_PPI_OP_CLEAR 5
#define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8
#define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9

#endif // tcg.h
639 changes: 281 additions & 358 deletions src/tcgbios.c

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion src/util.h
Expand Up @@ -37,6 +37,7 @@ int bootprio_find_named_rom(const char *name, int instance);
struct usbdevice_s;
int bootprio_find_usb(struct usbdevice_s *usbdev, int lun);
int get_keystroke(int msec);
int find_pxen(void);

// bootsplash.c
void enable_vga_console(void);
Expand Down Expand Up @@ -72,6 +73,7 @@ extern struct rsdp_descriptor *RsdpAddr;
extern u32 acpi_pm1a_cnt;
extern u16 acpi_pm_base;
void *find_acpi_rsdp(void);
void *find_acpi_table(u32 signature);
u32 find_resume_vector(void);
void acpi_reboot(void);
void find_acpi_features(void);
Expand Down Expand Up @@ -122,7 +124,7 @@ void pirtable_setup(void);
// fw/shadow.c
void make_bios_writable(void);
void make_bios_readonly(void);
void qemu_prep_reset(void);
void qemu_reboot(void);

// fw/smbios.c
void smbios_legacy_setup(void);
Expand Down Expand Up @@ -185,6 +187,8 @@ int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width
void kbd_init(void);
void handle_15c2(struct bregs *regs);
void process_key(u8 key);
u8 enqueue_key(u16 keycode);
u16 ascii_to_keycode(u8 ascii);

// misc.c
extern int HaveRunPost;
Expand Down Expand Up @@ -228,6 +232,10 @@ void startBoot(void);
void reloc_preinit(void *f, void *arg);
void code_mutable_preinit(void);

// sercon.c
void sercon_setup(void);
void sercon_check_event(void);

// serial.c
void serial_setup(void);
void lpt_setup(void);
Expand Down
7 changes: 4 additions & 3 deletions src/x86.h
Expand Up @@ -258,9 +258,10 @@ static inline u8 get_a20(void) {
}

static inline u8 set_a20(u8 cond) {
u8 val = inb(PORT_A20);
outb((val & ~A20_ENABLE_BIT) | (cond ? A20_ENABLE_BIT : 0), PORT_A20);
return (val & A20_ENABLE_BIT) != 0;
u8 val = inb(PORT_A20), a20_enabled = (val & A20_ENABLE_BIT) != 0;
if (a20_enabled != !!cond)
outb(val ^ A20_ENABLE_BIT, PORT_A20);
return a20_enabled;
}

// x86.c
Expand Down
117 changes: 114 additions & 3 deletions vgasrc/cbvga.c
@@ -1,6 +1,7 @@
// Simple framebuffer vgabios for use with coreboot native vga init.
//
// Copyright (C) 2014 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2017 Patrick Rudolph <siro@das-labor.org>
//
// This file may be distributed under the terms of the GNU LGPLv3 license.

Expand All @@ -18,19 +19,109 @@ static struct vgamode_s CBmodeinfo VAR16;
static struct vgamode_s CBemulinfo VAR16;
static u32 CBlinelength VAR16;

static struct cbvga_mode_s
{
u16 mode;
struct vgamode_s info;
} cbvesa_modes[] VAR16 = {
/* VESA 1.0 modes */
{ 0x110, { MM_DIRECT, 640, 480, 15, 8, 16, SEG_GRAPH } },
{ 0x111, { MM_DIRECT, 640, 480, 16, 8, 16, SEG_GRAPH } },
{ 0x112, { MM_DIRECT, 640, 480, 24, 8, 16, SEG_GRAPH } },
{ 0x113, { MM_DIRECT, 800, 600, 15, 8, 16, SEG_GRAPH } },
{ 0x114, { MM_DIRECT, 800, 600, 16, 8, 16, SEG_GRAPH } },
{ 0x115, { MM_DIRECT, 800, 600, 24, 8, 16, SEG_GRAPH } },
{ 0x116, { MM_DIRECT, 1024, 768, 15, 8, 16, SEG_GRAPH } },
{ 0x117, { MM_DIRECT, 1024, 768, 16, 8, 16, SEG_GRAPH } },
{ 0x118, { MM_DIRECT, 1024, 768, 24, 8, 16, SEG_GRAPH } },
{ 0x119, { MM_DIRECT, 1280, 1024, 15, 8, 16, SEG_GRAPH } },
{ 0x11A, { MM_DIRECT, 1280, 1024, 16, 8, 16, SEG_GRAPH } },
{ 0x11B, { MM_DIRECT, 1280, 1024, 24, 8, 16, SEG_GRAPH } },
{ 0x11D, { MM_DIRECT, 1600, 1200, 15, 8, 16, SEG_GRAPH } },
{ 0x11E, { MM_DIRECT, 1600, 1200, 16, 8, 16, SEG_GRAPH } },
{ 0x11F, { MM_DIRECT, 1600, 1200, 24, 8, 16, SEG_GRAPH } },
/* VESA 2.0 modes */
{ 0x141, { MM_DIRECT, 640, 400, 32, 8, 16, SEG_GRAPH } },
{ 0x142, { MM_DIRECT, 640, 480, 32, 8, 16, SEG_GRAPH } },
{ 0x143, { MM_DIRECT, 800, 600, 32, 8, 16, SEG_GRAPH } },
{ 0x144, { MM_DIRECT, 1024, 768, 32, 8, 16, SEG_GRAPH } },
{ 0x145, { MM_DIRECT, 1280, 1024, 32, 8, 16, SEG_GRAPH } },
{ 0x147, { MM_DIRECT, 1600, 1200, 32, 8, 16, SEG_GRAPH } },
{ 0x149, { MM_DIRECT, 1152, 864, 15, 8, 16, SEG_GRAPH } },
{ 0x14a, { MM_DIRECT, 1152, 864, 16, 8, 16, SEG_GRAPH } },
{ 0x14b, { MM_DIRECT, 1152, 864, 24, 8, 16, SEG_GRAPH } },
{ 0x14c, { MM_DIRECT, 1152, 864, 32, 8, 16, SEG_GRAPH } },
{ 0x175, { MM_DIRECT, 1280, 768, 16, 8, 16, SEG_GRAPH } },
{ 0x176, { MM_DIRECT, 1280, 768, 24, 8, 16, SEG_GRAPH } },
{ 0x177, { MM_DIRECT, 1280, 768, 32, 8, 16, SEG_GRAPH } },
{ 0x178, { MM_DIRECT, 1280, 800, 16, 8, 16, SEG_GRAPH } },
{ 0x179, { MM_DIRECT, 1280, 800, 24, 8, 16, SEG_GRAPH } },
{ 0x17a, { MM_DIRECT, 1280, 800, 32, 8, 16, SEG_GRAPH } },
{ 0x17b, { MM_DIRECT, 1280, 960, 16, 8, 16, SEG_GRAPH } },
{ 0x17c, { MM_DIRECT, 1280, 960, 24, 8, 16, SEG_GRAPH } },
{ 0x17d, { MM_DIRECT, 1280, 960, 32, 8, 16, SEG_GRAPH } },
{ 0x17e, { MM_DIRECT, 1440, 900, 16, 8, 16, SEG_GRAPH } },
{ 0x17f, { MM_DIRECT, 1440, 900, 24, 8, 16, SEG_GRAPH } },
{ 0x180, { MM_DIRECT, 1440, 900, 32, 8, 16, SEG_GRAPH } },
{ 0x181, { MM_DIRECT, 1400, 1050, 16, 8, 16, SEG_GRAPH } },
{ 0x182, { MM_DIRECT, 1400, 1050, 24, 8, 16, SEG_GRAPH } },
{ 0x183, { MM_DIRECT, 1400, 1050, 32, 8, 16, SEG_GRAPH } },
{ 0x184, { MM_DIRECT, 1680, 1050, 16, 8, 16, SEG_GRAPH } },
{ 0x185, { MM_DIRECT, 1680, 1050, 24, 8, 16, SEG_GRAPH } },
{ 0x186, { MM_DIRECT, 1680, 1050, 32, 8, 16, SEG_GRAPH } },
{ 0x187, { MM_DIRECT, 1920, 1200, 16, 8, 16, SEG_GRAPH } },
{ 0x188, { MM_DIRECT, 1920, 1200, 24, 8, 16, SEG_GRAPH } },
{ 0x189, { MM_DIRECT, 1920, 1200, 32, 8, 16, SEG_GRAPH } },
{ 0x18a, { MM_DIRECT, 2560, 1600, 16, 8, 16, SEG_GRAPH } },
{ 0x18b, { MM_DIRECT, 2560, 1600, 24, 8, 16, SEG_GRAPH } },
{ 0x18c, { MM_DIRECT, 2560, 1600, 32, 8, 16, SEG_GRAPH } },
{ 0x18d, { MM_DIRECT, 1280, 720, 16, 8, 16, SEG_GRAPH } },
{ 0x18e, { MM_DIRECT, 1280, 720, 24, 8, 16, SEG_GRAPH } },
{ 0x18f, { MM_DIRECT, 1280, 720, 32, 8, 16, SEG_GRAPH } },
{ 0x190, { MM_DIRECT, 1920, 1080, 16, 8, 16, SEG_GRAPH } },
{ 0x191, { MM_DIRECT, 1920, 1080, 24, 8, 16, SEG_GRAPH } },
{ 0x192, { MM_DIRECT, 1920, 1080, 32, 8, 16, SEG_GRAPH } },
};

struct vgamode_s *cbvga_find_mode(int mode)
{
if (mode == GET_GLOBAL(CBmode))
return &CBmodeinfo;
if (mode == 0x03)
return &CBemulinfo;

int i;
for (i = 0; i < ARRAY_SIZE(cbvesa_modes); i++) {
struct cbvga_mode_s *cbmode_g = &cbvesa_modes[i];
if (GET_GLOBAL(cbmode_g->mode) == 0xffff)
continue;
if (GET_GLOBAL(cbmode_g->mode) == mode)
return &cbmode_g->info;
}
return NULL;
}

void
cbvga_list_modes(u16 seg, u16 *dest, u16 *last)
{
if (dest<last) {
if (GET_GLOBAL(CBmode) != 0x3) {
/* Advertise additional SVGA modes for Microsoft NTLDR graphical mode.
* Microsoft NTLDR:
* + Graphical mode uses a maximum resolution of 1600x1200.
* + Expects to find VESA mode with 800x600 or 1024x768.
* + 24 Bpp and 32 Bpp are supported
*/
int i;
for (i = 0; i < ARRAY_SIZE(cbvesa_modes) && dest < last; i++) {
struct cbvga_mode_s *cbmode_g = &cbvesa_modes[i];
u16 mode = GET_GLOBAL(cbmode_g->mode);
if (mode == 0xffff)
continue;
SET_FARVAR(seg, *dest, mode);
dest++;
}
}
if (dest < last) {
SET_FARVAR(seg, *dest, GET_GLOBAL(CBmode));
dest++;
}
Expand Down Expand Up @@ -104,7 +195,7 @@ cbvga_set_mode(struct vgamode_s *vmode_g, int flags)
return 0;
}
struct gfx_op op;
init_gfx_op(&op, vmode_g);
init_gfx_op(&op, &CBmodeinfo);
op.x = op.y = 0;
op.xlen = GET_GLOBAL(CBmodeinfo.width);
op.ylen = GET_GLOBAL(CBmodeinfo.height);
Expand All @@ -114,6 +205,13 @@ cbvga_set_mode(struct vgamode_s *vmode_g, int flags)
return 0;
}

int
cbvga_get_linesize(struct vgamode_s *vmode_g)
{
/* Can't change mode, always report active pitch. */
return GET_GLOBAL(CBlinelength);
}

#define CB_TAG_FRAMEBUFFER 0x0012
struct cb_framebuffer {
u32 tag;
Expand All @@ -137,6 +235,7 @@ struct cb_framebuffer {
int
cbvga_setup(void)
{
int i;
dprintf(1, "coreboot vga init\n");

if (GET_GLOBAL(HaveRunInit))
Expand Down Expand Up @@ -164,7 +263,8 @@ cbvga_setup(void)
}

u64 addr = GET_FARVAR(0, cbfb->physical_address);
u8 bpp = GET_FARVAR(0, cbfb->bits_per_pixel);
u8 bpp = cbfb->blue_mask_size + cbfb->green_mask_size
+ cbfb->red_mask_size + cbfb->reserved_mask_size;
u32 xlines = GET_FARVAR(0, cbfb->x_resolution);
u32 ylines = GET_FARVAR(0, cbfb->y_resolution);
u32 linelength = GET_FARVAR(0, cbfb->bytes_per_line);
Expand All @@ -190,5 +290,16 @@ cbvga_setup(void)
memcpy_far(get_global_seg(), &CBemulinfo
, get_global_seg(), &CBmodeinfo, sizeof(CBemulinfo));

// Validate modes
for (i = 0; i < ARRAY_SIZE(cbvesa_modes); i++) {
struct cbvga_mode_s *cbmode_g = &cbvesa_modes[i];
/* Skip VBE modes that doesn't fit into coreboot's framebuffer */
if ((GET_GLOBAL(cbmode_g->info.height) > ylines)
|| (GET_GLOBAL(cbmode_g->info.width) > xlines)
|| (GET_GLOBAL(cbmode_g->info.depth) != bpp)) {
dprintf(3, "Removing mode %x\n", GET_GLOBAL(cbmode_g->mode));
SET_VGA(cbmode_g->mode, 0xffff);
}
}
return 0;
}
5 changes: 5 additions & 0 deletions vgasrc/stdvga.c
Expand Up @@ -321,6 +321,11 @@ stdvga_set_dacformat(struct vgamode_s *vmode_g, int val)
return -1;
}

int
stdvga_get_linesize(struct vgamode_s *vmode_g)
{
return DIV_ROUND_UP(GET_GLOBAL(vmode_g->width) * vga_bpp(vmode_g), 8);
}

/****************************************************************
* Save/Restore state
Expand Down
2 changes: 1 addition & 1 deletion vgasrc/vbe.c
Expand Up @@ -107,7 +107,7 @@ vbe_104f01(struct bregs *regs)
// Basic information about mode.
int width = GET_GLOBAL(vmode_g->width);
int height = GET_GLOBAL(vmode_g->height);
int linesize = DIV_ROUND_UP(width * vga_bpp(vmode_g), 8);
int linesize = vgahw_get_linesize(vmode_g);
SET_FARVAR(seg, info->bytes_per_scanline, linesize);
SET_FARVAR(seg, info->xres, width);
SET_FARVAR(seg, info->yres, height);
Expand Down
2 changes: 1 addition & 1 deletion vgasrc/vgabios.h
Expand Up @@ -73,7 +73,7 @@ static inline int vga_emulate_text(void) {

// Debug settings
#define DEBUG_VGA_POST 1
#define DEBUG_VGA_10 3
#define DEBUG_VGA_10 9

// vgabios.c
int vga_bpp(struct vgamode_s *vmode_g);
Expand Down
6 changes: 6 additions & 0 deletions vgasrc/vgahw.h
Expand Up @@ -139,4 +139,10 @@ static inline int vgahw_save_restore(int cmd, u16 seg, void *data) {
return stdvga_save_restore(cmd, seg, data);
}

static inline int vgahw_get_linesize(struct vgamode_s *vmode_g) {
if (CONFIG_VGA_COREBOOT)
return cbvga_get_linesize(vmode_g);
return stdvga_get_linesize(vmode_g);
}

#endif // vgahw.h
2 changes: 2 additions & 0 deletions vgasrc/vgautil.h
Expand Up @@ -17,6 +17,7 @@ int cbvga_get_dacformat(struct vgamode_s *vmode_g);
int cbvga_set_dacformat(struct vgamode_s *vmode_g, int val);
int cbvga_save_restore(int cmd, u16 seg, void *data);
int cbvga_set_mode(struct vgamode_s *vmode_g, int flags);
int cbvga_get_linesize(struct vgamode_s *vmode_g);
int cbvga_setup(void);

// clext.c
Expand Down Expand Up @@ -63,6 +64,7 @@ void stdvga_list_modes(u16 seg, u16 *dest, u16 *last);
void stdvga_build_video_param(void);
void stdvga_override_crtc(int mode, u8 *crtc);
int stdvga_set_mode(struct vgamode_s *vmode_g, int flags);
int stdvga_get_linesize(struct vgamode_s *vmode_g);
void stdvga_set_packed_palette(void);

// swcursor.c
Expand Down