96 changes: 82 additions & 14 deletions src/hw/floppy.c
Expand Up @@ -34,15 +34,28 @@
#define FLOPPY_GAPLEN 0x1B
#define FLOPPY_FORMAT_GAPLEN 0x6c
#define FLOPPY_PIO_TIMEOUT 1000
#define FLOPPY_IRQ_TIMEOUT 5000
#define FLOPPY_SPECIFY1 0xAF // step rate 12ms, head unload 240ms
#define FLOPPY_SPECIFY2 0x02 // head load time 4ms, DMA used
#define FLOPPY_STARTUP_TIME 8 // 1 second

#define FLOPPY_DOR_MOTOR_D 0x80 // Set to turn drive 3's motor ON
#define FLOPPY_DOR_MOTOR_C 0x40 // Set to turn drive 2's motor ON
#define FLOPPY_DOR_MOTOR_B 0x20 // Set to turn drive 1's motor ON
#define FLOPPY_DOR_MOTOR_A 0x10 // Set to turn drive 0's motor ON
#define FLOPPY_DOR_MOTOR_MASK 0xf0
#define FLOPPY_DOR_IRQ 0x08 // Set to enable IRQs and DMA
#define FLOPPY_DOR_RESET 0x04 // Clear = enter reset mode, Set = normal operation
#define FLOPPY_DOR_DSEL_MASK 0x03 // "Select" drive number for next access

// New diskette parameter table adding 3 parameters from IBM
// Since no provisions are made for multiple drive types, most
// values in this table are ignored. I set parameters for 1.44M
// floppy here
struct floppy_ext_dbt_s diskette_param_table2 VARFSEG = {
.dbt = {
.specify1 = 0xAF, // step rate 12ms, head unload 240ms
.specify2 = 0x02, // head load time 4ms, DMA used
.specify1 = FLOPPY_SPECIFY1,
.specify2 = FLOPPY_SPECIFY2,
.shutoff_ticks = FLOPPY_MOTOR_TICKS, // ~2 seconds
.bps_code = FLOPPY_SIZE_CODE,
.sectors = 18,
Expand All @@ -51,7 +64,7 @@ struct floppy_ext_dbt_s diskette_param_table2 VARFSEG = {
.gap_len = FLOPPY_FORMAT_GAPLEN,
.fill_byte = FLOPPY_FILLBYTE,
.settle_time = 0x0F, // 15ms
.startup_time = 0x08, // 1 second
.startup_time = FLOPPY_STARTUP_TIME,
},
.max_track = 79, // maximum track
.data_rate = 0, // data transfer rate
Expand Down Expand Up @@ -180,27 +193,41 @@ find_floppy_type(u32 size)

u8 FloppyDOR VARLOW;

static inline u8
floppy_dor_read(void)
{
return GET_LOW(FloppyDOR);
}

static inline void
floppy_dor_write(u8 val)
{
outb(val, PORT_FD_DOR);
SET_LOW(FloppyDOR, val);
}

static inline void
floppy_dor_mask(u8 off, u8 on)
{
floppy_dor_write((floppy_dor_read() & ~off) | on);
}

static void
floppy_disable_controller(void)
{
dprintf(2, "Floppy_disable_controller\n");
floppy_dor_write(0x00);
// Clear the reset bit (enter reset state) and clear 'enable IRQ and DMA'
floppy_dor_mask(FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET, 0);
}

static int
floppy_wait_irq(void)
{
u8 frs = GET_BDA(floppy_recalibration_status);
SET_BDA(floppy_recalibration_status, frs & ~FRS_IRQ);
u32 end = timer_calc(FLOPPY_IRQ_TIMEOUT);
for (;;) {
if (!GET_BDA(floppy_motor_counter)) {
if (timer_check(end)) {
warn_timeout();
floppy_disable_controller();
return DISK_RET_ETIMEOUT;
Expand All @@ -226,6 +253,7 @@ floppy_wait_irq(void)
#define FC_READ (0xe6 | (8<<8) | (7<<12) | FCF_WAITIRQ)
#define FC_WRITE (0xc5 | (8<<8) | (7<<12) | FCF_WAITIRQ)
#define FC_FORMAT (0x4d | (5<<8) | (7<<12) | FCF_WAITIRQ)
#define FC_SPECIFY (0x03 | (2<<8) | (0<<12))

// Send the specified command and it's parameters to the floppy controller.
static int
Expand Down Expand Up @@ -302,36 +330,61 @@ static int
floppy_enable_controller(void)
{
dprintf(2, "Floppy_enable_controller\n");
SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS);
floppy_dor_write(0x00);
floppy_dor_write(0x0c);
// Clear the reset bit (enter reset state), but set 'enable IRQ and DMA'
floppy_dor_mask(FLOPPY_DOR_RESET, FLOPPY_DOR_IRQ);
// Real hardware needs a 4 microsecond delay
usleep(4);
// Set the reset bit (normal operation) and keep 'enable IRQ and DMA' on
floppy_dor_mask(0, FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET);
int ret = floppy_wait_irq();
if (ret)
return ret;

// After the interrupt is received, send 4 SENSE INTERRUPT commands to
// clear the interrupt status for each of the four logical drives,
// supported by the controller.
// See section 7.4 - "Drive Polling" of the Intel 82077AA datasheet for
// a more detailed description of why this voodoo needs to be done.
// Without this, initialization fails on real controllers (but still works
// in QEMU)
u8 param[2];
return floppy_pio(FC_CHECKIRQ, param);
int i;
for (i=0; i<4; i++) {
ret = floppy_pio(FC_CHECKIRQ, param);
if (ret)
return ret;
}
return DISK_RET_SUCCESS;
}

// Activate a drive and send a command to it.
static int
floppy_drive_pio(u8 floppyid, int command, u8 *param)
{
// Enable controller if it isn't running.
if (!(GET_LOW(FloppyDOR) & 0x04)) {
if (!(floppy_dor_read() & FLOPPY_DOR_RESET)) {
int ret = floppy_enable_controller();
if (ret)
return ret;
}

// reset the disk motor timeout value of INT 08
SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS);
// set the disk motor timeout value of INT 08 to the highest value
SET_BDA(floppy_motor_counter, 255);

// Check if the motor is already running
u8 motor_mask = FLOPPY_DOR_MOTOR_A << floppyid;
int motor_already_running = floppy_dor_read() & motor_mask;

// Turn on motor of selected drive, DMA & int enabled, normal operation
floppy_dor_write((floppyid ? 0x20 : 0x10) | 0x0c | floppyid);
floppy_dor_write(motor_mask | FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET | floppyid);

// If the motor was just started, wait for it to get up to speed
if (!motor_already_running && !CONFIG_QEMU)
msleep(FLOPPY_STARTUP_TIME * 125);

// Send command.
int ret = floppy_pio(command, param);
SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS); // reset motor timeout
if (ret)
return ret;

Expand Down Expand Up @@ -363,6 +416,15 @@ floppy_drive_recal(u8 floppyid)
return DISK_RET_SUCCESS;
}

static int
floppy_drive_specify(void)
{
u8 param[2];
param[0] = FLOPPY_SPECIFY1;
param[1] = FLOPPY_SPECIFY2;
return floppy_pio(FC_SPECIFY, param);
}

static int
floppy_drive_readid(u8 floppyid, u8 data_rate, u8 head)
{
Expand Down Expand Up @@ -440,6 +502,12 @@ floppy_prep(struct drive_s *drive_gf, u8 cylinder)
ret = floppy_media_sense(drive_gf);
if (ret)
return ret;

// Execute a SPECIFY command (sets the Step Rate Time,
// Head Load Time, Head Unload Time and the DMA enable/disable bit).
ret = floppy_drive_specify();
if (ret)
return ret;
}

// Seek to cylinder if needed.
Expand Down Expand Up @@ -668,6 +736,6 @@ floppy_tick(void)
SET_BDA(floppy_motor_counter, fcount);
if (fcount == 0)
// turn motor(s) off
floppy_dor_write(GET_LOW(FloppyDOR) & ~0xf0);
floppy_dor_mask(FLOPPY_DOR_MOTOR_MASK, 0);
}
}
4 changes: 2 additions & 2 deletions src/hw/nvme.c
Expand Up @@ -318,7 +318,7 @@ nvme_create_io_cq(struct nvme_ctrl *ctrl, struct nvme_cq *cq, u16 q_idx)
{
int rc;
struct nvme_sqe *cmd_create_cq;
u16 length = 1 + (ctrl->reg->cap & 0xffff);
u32 length = 1 + (ctrl->reg->cap & 0xffff);
if (length > NVME_PAGE_SIZE / sizeof(struct nvme_cqe))
length = NVME_PAGE_SIZE / sizeof(struct nvme_cqe);

Expand Down Expand Up @@ -362,7 +362,7 @@ nvme_create_io_sq(struct nvme_ctrl *ctrl, struct nvme_sq *sq, u16 q_idx, struct
{
int rc;
struct nvme_sqe *cmd_create_sq;
u16 length = 1 + (ctrl->reg->cap & 0xffff);
u32 length = 1 + (ctrl->reg->cap & 0xffff);
if (length > NVME_PAGE_SIZE / sizeof(struct nvme_cqe))
length = NVME_PAGE_SIZE / sizeof(struct nvme_cqe);

Expand Down
1 change: 1 addition & 0 deletions src/hw/pci_ids.h
Expand Up @@ -2265,6 +2265,7 @@

#define PCI_VENDOR_ID_REDHAT 0x1b36
#define PCI_DEVICE_ID_REDHAT_ROOT_PORT 0x000C
#define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001

#define PCI_VENDOR_ID_TEKRAM 0x1de1
#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
Expand Down
2 changes: 1 addition & 1 deletion src/hw/pvscsi.c
Expand Up @@ -310,7 +310,7 @@ init_pvscsi(void *data)
struct pvscsi_ring_dsc_s *ring_dsc = NULL;
pvscsi_init_rings(iobase, &ring_dsc);
int i;
for (i = 0; i < 7; i++)
for (i = 0; i < 64; i++)
pvscsi_scan_target(pci, iobase, ring_dsc, i);
}

Expand Down
2 changes: 1 addition & 1 deletion src/hw/sdcard.c
Expand Up @@ -132,7 +132,7 @@ struct sdhci_s {

// SDHCI timeouts
#define SDHCI_POWER_OFF_TIME 1
#define SDHCI_POWER_ON_TIME 1
#define SDHCI_POWER_ON_TIME 5
#define SDHCI_CLOCK_ON_TIME 1 // 74 clock cycles
#define SDHCI_POWERUP_TIMEOUT 1000
#define SDHCI_PIO_TIMEOUT 1000 // XXX - this is just made up
Expand Down
301 changes: 259 additions & 42 deletions src/hw/tpm_drivers.c
Expand Up @@ -36,7 +36,8 @@ struct tpm_driver {
extern struct tpm_driver tpm_drivers[];

#define TIS_DRIVER_IDX 0
#define TPM_NUM_DRIVERS 1
#define CRB_DRIVER_IDX 1
#define TPM_NUM_DRIVERS 2

#define TPM_INVALID_DRIVER 0xf

Expand All @@ -57,13 +58,62 @@ static const u32 tpm_default_durations[3] = {
static u32 tpm_default_dur[3];
static u32 tpm_default_to[4];

static u32 crb_cmd_size;
static void *crb_cmd;
static u32 crb_resp_size;
static void *crb_resp;

static u32 wait_reg8(u8* reg, u32 time, u8 mask, u8 expect)
{
if (!CONFIG_TCGBIOS)
return 0;

u32 rc = 1;
u32 end = timer_calc_usec(time);

for (;;) {
u8 value = readl(reg);
if ((value & mask) == expect) {
rc = 0;
break;
}
if (timer_check(end)) {
warn_timeout();
break;
}
yield();
}
return rc;
}

static u32 tis_wait_access(u8 locty, u32 time, u8 mask, u8 expect)
{
return wait_reg8(TIS_REG(locty, TIS_REG_ACCESS), time, mask, expect);
}

static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect)
{
return wait_reg8(TIS_REG(locty, TIS_REG_STS), time, mask, expect);
}

static u32 crb_wait_reg(u8 locty, u16 reg, u32 time, u8 mask, u8 expect)
{
return wait_reg8(CRB_REG(locty, reg), time, mask, expect);
}

/* if device is not there, return '0', '1' otherwise */
static u32 tis_probe(void)
{
if (!CONFIG_TCGBIOS)
return 0;

u32 rc = 0;
/* Wait for the interface to report it's ready */
u32 rc = tis_wait_access(0, TIS_DEFAULT_TIMEOUT_A,
TIS_ACCESS_TPM_REG_VALID_STS,
TIS_ACCESS_TPM_REG_VALID_STS);
if (rc)
return 0;

u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID));

if ((didvid != 0) && (didvid != 0xffffffff))
Expand Down Expand Up @@ -92,36 +142,51 @@ static u32 tis_probe(void)

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 */
u32 reg = readl(TIS_REG(0, TIS_REG_IFACE_ID));

/*
* FIFO interface as defined in TIS1.3 is active
* Interface capabilities are defined in TIS_REG_INTF_CAPABILITY
*/
if ((reg & 0xf) == 0xf) {
reg = readl(TIS_REG(0, TIS_REG_INTF_CAPABILITY));
/* Interface 1.3 for TPM 2.0 */
if (((reg >> 28) & 0x7) == 3)
return TPM_VERSION_2;
}
/* FIFO interface as defined in PTP for TPM 2.0 is active */
else if ((reg & 0xf) == 0) {
return TPM_VERSION_2;
}

return TPM_VERSION_1_2;
}

static u32 tis_init(void)
static void init_timeout(int driver)
{
if (!CONFIG_TCGBIOS)
return 1;

writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0);

if (tpm_drivers[TIS_DRIVER_IDX].durations == NULL) {
if (tpm_drivers[driver].durations == NULL) {
u32 *durations = tpm_default_dur;
memcpy(durations, tpm_default_durations,
sizeof(tpm_default_durations));
tpm_drivers[TIS_DRIVER_IDX].durations = durations;
tpm_drivers[driver].durations = durations;
}

if (tpm_drivers[TIS_DRIVER_IDX].timeouts == NULL) {
if (tpm_drivers[driver].timeouts == NULL) {
u32 *timeouts = tpm_default_to;
memcpy(timeouts, tis_default_timeouts,
sizeof(tis_default_timeouts));
tpm_drivers[TIS_DRIVER_IDX].timeouts = timeouts;
tpm_drivers[driver].timeouts = timeouts;
}
}

static u32 tis_init(void)
{
if (!CONFIG_TCGBIOS)
return 1;

writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0);

init_timeout(TIS_DRIVER_IDX);

return 1;
}
Expand All @@ -141,30 +206,6 @@ static void set_timeouts(u32 timeouts[4], u32 durations[3])
memcpy(dus, durations, 3 * sizeof(u32));
}


static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect)
{
if (!CONFIG_TCGBIOS)
return 0;

u32 rc = 1;
u32 end = timer_calc_usec(time);

for (;;) {
u8 sts = readb(TIS_REG(locty, TIS_REG_STS));
if ((sts & mask) == expect) {
rc = 0;
break;
}
if (timer_check(end)) {
warn_timeout();
break;
}
yield();
}
return rc;
}

static u32 tis_activate(u8 locty)
{
if (!CONFIG_TCGBIOS)
Expand Down Expand Up @@ -333,6 +374,166 @@ static u32 tis_waitrespready(enum tpmDurationType to_t)
return rc;
}

#define CRB_STATE_VALID_STS 0b10000000
#define CRB_STATE_LOC_ASSIGNED 0x00000010
#define CRB_STATE_READY_MASK (CRB_STATE_VALID_STS | CRB_STATE_LOC_ASSIGNED)

/* if device is not there, return '0', '1' otherwise */
static u32 crb_probe(void)
{
if (!CONFIG_TCGBIOS)
return 0;

/* Wait for the interface to report it's ready */
u32 rc = crb_wait_reg(0, CRB_REG_LOC_STATE, TIS2_DEFAULT_TIMEOUT_D,
CRB_STATE_READY_MASK, CRB_STATE_VALID_STS);
if (rc)
return 0;

u32 ifaceid = readl(CRB_REG(0, CRB_REG_INTF_ID));

if ((ifaceid & 0xf) != 0xf) {
if ((ifaceid & 0xf) == 1) {
/* CRB is active */
} else if ((ifaceid & (1 << 14)) == 0) {
/* CRB cannot be selected */
return 0;
}
/* write of 1 to bits 17-18 selects CRB */
writel(CRB_REG(0, CRB_REG_INTF_ID), (1 << 17));
/* lock it */
writel(CRB_REG(0, CRB_REG_INTF_ID), (1 << 19));
}

/* no support for 64 bit addressing yet */
if (readl(CRB_REG(0, CRB_REG_CTRL_CMD_HADDR)))
return 0;

u64 addr = readq(CRB_REG(0, CRB_REG_CTRL_RSP_ADDR));
if (addr > 0xffffffff)
return 0;

return 1;
}

static TPMVersion crb_get_tpm_version(void)
{
/* CRB is supposed to be TPM 2.0 only */
return TPM_VERSION_2;
}

static u32 crb_init(void)
{
if (!CONFIG_TCGBIOS)
return 1;

crb_cmd = (void*)readl(CRB_REG(0, CRB_REG_CTRL_CMD_LADDR));
crb_cmd_size = readl(CRB_REG(0, CRB_REG_CTRL_CMD_SIZE));
crb_resp = (void*)readl(CRB_REG(0, CRB_REG_CTRL_RSP_ADDR));
crb_resp_size = readl(CRB_REG(0, CRB_REG_CTRL_RSP_SIZE));

init_timeout(CRB_DRIVER_IDX);

return 0;
}

static u32 crb_activate(u8 locty)
{
if (!CONFIG_TCGBIOS)
return 0;

writeb(CRB_REG(locty, CRB_REG_LOC_CTRL), 1);

return 0;
}

static u32 crb_find_active_locality(void)
{
if (!CONFIG_TCGBIOS)
return 0;

return 0;
}

#define CRB_CTRL_REQ_CMD_READY 0b1
#define CRB_START_INVOKE 0b1
#define CRB_CTRL_STS_ERROR 0b1

static u32 crb_ready(void)
{
if (!CONFIG_TCGBIOS)
return 0;

u32 rc = 0;
u8 locty = crb_find_active_locality();
u32 timeout_c = tpm_drivers[CRB_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C];

writel(CRB_REG(locty, CRB_REG_CTRL_REQ), CRB_CTRL_REQ_CMD_READY);
rc = crb_wait_reg(locty, CRB_REG_CTRL_REQ, timeout_c,
CRB_CTRL_REQ_CMD_READY, 0);

return rc;
}

static u32 crb_senddata(const u8 *const data, u32 len)
{
if (!CONFIG_TCGBIOS)
return 0;

if (len > crb_cmd_size)
return 1;

u8 locty = crb_find_active_locality();
memcpy(crb_cmd, data, len);
writel(CRB_REG(locty, CRB_REG_CTRL_START), CRB_START_INVOKE);

return 0;
}

static u32 crb_readresp(u8 *buffer, u32 *len)
{
if (!CONFIG_TCGBIOS)
return 0;

u8 locty = crb_find_active_locality();
if (readl(CRB_REG(locty, CRB_REG_CTRL_STS)) & CRB_CTRL_STS_ERROR)
return 1;

if (*len < 6)
return 1;

memcpy(buffer, crb_resp, 6);
u32 expected = be32_to_cpu(*(u32 *) &buffer[2]);
if (expected < 6)
return 1;

*len = (*len < expected) ? *len : expected;

memcpy(buffer + 6, crb_resp + 6, *len - 6);

return 0;
}


static u32 crb_waitdatavalid(void)
{
return 0;
}

static u32 crb_waitrespready(enum tpmDurationType to_t)
{
if (!CONFIG_TCGBIOS)
return 0;

u32 rc = 0;
u8 locty = crb_find_active_locality();
u32 timeout = tpm_drivers[CRB_DRIVER_IDX].durations[to_t];

rc = crb_wait_reg(locty, CRB_REG_CTRL_START, timeout,
CRB_START_INVOKE, 0);

return rc;
}

struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
[TIS_DRIVER_IDX] =
Expand All @@ -341,6 +542,7 @@ struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
.durations = NULL,
.set_timeouts = set_timeouts,
.probe = tis_probe,
.get_tpm_version = tis_get_tpm_version,
.init = tis_init,
.activate = tis_activate,
.ready = tis_ready,
Expand All @@ -349,6 +551,21 @@ struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
.waitdatavalid = tis_waitdatavalid,
.waitrespready = tis_waitrespready,
},
[CRB_DRIVER_IDX] =
{
.timeouts = NULL,
.durations = NULL,
.set_timeouts = set_timeouts,
.probe = crb_probe,
.get_tpm_version = crb_get_tpm_version,
.init = crb_init,
.activate = crb_activate,
.ready = crb_ready,
.senddata = crb_senddata,
.readresp = crb_readresp,
.waitdatavalid = crb_waitdatavalid,
.waitrespready = crb_waitrespready,
},
};

static u8 TPMHW_driver_to_use = TPM_INVALID_DRIVER;
Expand All @@ -362,7 +579,7 @@ tpmhw_probe(void)
if (td->probe() != 0) {
td->init();
TPMHW_driver_to_use = i;
return tis_get_tpm_version();
return td->get_tpm_version();
}
}
return TPM_VERSION_NONE;
Expand Down
26 changes: 26 additions & 0 deletions src/hw/tpm_drivers.h
Expand Up @@ -24,6 +24,32 @@ int tpmhw_transmit(u8 locty, struct tpm_req_header *req,
enum tpmDurationType to_t);
void tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]);

/* CRB driver */
/* address of locality 0 (CRB) */
#define TPM_CRB_BASE_ADDRESS 0xfed40000

#define CRB_REG(LOCTY, REG) \
(void *)(TPM_CRB_BASE_ADDRESS + (LOCTY << 12) + REG)

/* hardware registers */
#define CRB_REG_LOC_STATE 0x0
#define CRB_REG_LOC_CTRL 0x8
#define CRB_REG_LOC_STS 0xC
#define CRB_REG_INTF_ID 0x30
#define CRB_REG_CTRL_EXT 0x38
#define CRB_REG_CTRL_REQ 0x40
#define CRB_REG_CTRL_STS 0x44
#define CRB_REG_CTRL_CANCEL 0x48
#define CRB_REG_CTRL_START 0x4C
#define CRB_REG_INT_ENABLE 0x50
#define CRB_REG_INT_STS 0x54
#define CRB_REG_CTRL_CMD_SIZE 0x58
#define CRB_REG_CTRL_CMD_LADDR 0x5C
#define CRB_REG_CTRL_CMD_HADDR 0x60
#define CRB_REG_CTRL_RSP_SIZE 0x64
#define CRB_REG_CTRL_RSP_ADDR 0x68
#define CRB_REG_DATA_BUFFER 0x80

/* TIS driver */
/* address of locality 0 (TIS) */
#define TPM_TIS_BASE_ADDRESS 0xfed40000
Expand Down
29 changes: 28 additions & 1 deletion src/optionroms.c
Expand Up @@ -356,7 +356,9 @@ optionrom_setup(void)
// Find and deploy PCI roms.
struct pci_device *pci;
foreachpci(pci) {
if (pci->class == PCI_CLASS_DISPLAY_VGA || pci->have_driver)
if (pci->class == PCI_CLASS_DISPLAY_VGA ||
pci->class == PCI_CLASS_DISPLAY_OTHER ||
pci->have_driver)
continue;
init_pcirom(pci, 0, sources);
}
Expand Down Expand Up @@ -406,10 +408,32 @@ optionrom_setup(void)
int ScreenAndDebug;
struct rom_header *VgaROM;

static void try_setup_display_other(void)
{
struct pci_device *pci;

dprintf(1, "No VGA found, scan for other display\n");

foreachpci(pci) {
if (pci->class != PCI_CLASS_DISPLAY_OTHER)
continue;
struct rom_header *rom = map_pcirom(pci);
if (!rom)
continue;
dprintf(1, "Other display found at %pP\n", pci);
pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
init_optionrom(rom, pci->bdf, 1);
return;
}
}

// Call into vga code to turn on console.
void
vgarom_setup(void)
{
int have_vga = 0;

if (! CONFIG_OPTIONROMS)
return;

Expand All @@ -431,8 +455,11 @@ vgarom_setup(void)
continue;
vgahook_setup(pci);
init_pcirom(pci, 1, NULL);
have_vga = 1;
break;
}
if (!have_vga)
try_setup_display_other();

// Find and deploy CBFS vga-style roms not associated with a device.
run_file_roms("vgaroms/", 1, NULL);
Expand Down
13 changes: 13 additions & 0 deletions src/pmm.c
Expand Up @@ -8,6 +8,7 @@
#include "config.h" // CONFIG_*
#include "malloc.h" // _malloc
#include "output.h" // dprintf
#include "e820map.h" // struct e820entry
#include "std/pmm.h" // PMM_SIGNATURE
#include "string.h" // checksum
#include "util.h" // pmm_init
Expand Down Expand Up @@ -75,6 +76,18 @@ handle_pmm00(u16 *args)
break;
case 2:
data = malloc_palloc(highzone, size, align);
if (!data && (flags & 8)) {
/*
* We are out of meory. So go allocate from the (big)
* ZoneTmpHigh instead and reserve the block in the e820
* map so the OS will not override it. That way we can
* handle big permanent allocations without needing a big
* ZoneHigh.
*/
data = malloc_palloc(&ZoneTmpHigh, size, align);
if (data)
e820_add(data, size, E820_RESERVED);
}
break;
case 3: {
data = malloc_palloc(lowzone, size, align);
Expand Down
13 changes: 13 additions & 0 deletions src/std/acpi.h
Expand Up @@ -307,4 +307,17 @@ struct tcpa_descriptor_rev2
#define TCPA_ACPI_CLASS_CLIENT 0
#define TCPA_ACPI_CLASS_SERVER 1

#define TPM2_SIGNATURE 0x324D5054
struct tpm2_descriptor_rev2
{
ACPI_TABLE_HEADER_DEF
u16 platform_class;
u16 reserved;
u64 address_of_control_area;
u32 start_method;
u8 start_method_params[12];
u32 log_area_minimum_length;
u64 log_area_start_address;
} PACKED;

#endif // acpi.h
52 changes: 41 additions & 11 deletions src/tcgbios.c
Expand Up @@ -48,15 +48,9 @@ struct {
u8 * log_area_last_entry;
} tpm_state VARLOW;

static int
tpm_tcpa_probe(void)
static int tpm_set_log_area(u8 *log_area_start_address,
u32 log_area_minimum_length)
{
struct tcpa_descriptor_rev2 *tcpa = find_acpi_table(TCPA_SIGNATURE);
if (!tcpa)
return -1;

u8 *log_area_start_address = (u8*)(long)tcpa->log_area_start_address;
u32 log_area_minimum_length = tcpa->log_area_minimum_length;
if (!log_area_start_address || !log_area_minimum_length)
return -1;

Expand All @@ -69,6 +63,39 @@ tpm_tcpa_probe(void)
return 0;
}

static int
tpm_tcpa_probe(void)
{
struct tcpa_descriptor_rev2 *tcpa = find_acpi_table(TCPA_SIGNATURE);
if (!tcpa)
return -1;

dprintf(DEBUG_tcg, "TCGBIOS: TCPA: LASA = %p, LAML = %u\n",
(u8 *)(long)tcpa->log_area_start_address,
tcpa->log_area_minimum_length);

return tpm_set_log_area((u8*)(long)tcpa->log_area_start_address,
tcpa->log_area_minimum_length);
}

static int
tpm_tpm2_probe(void)
{
struct tpm2_descriptor_rev2 *tpm2 = find_acpi_table(TPM2_SIGNATURE);
if (!tpm2)
return -1;

if (tpm2->length < 76)
return -1;

dprintf(DEBUG_tcg, "TCGBIOS: TPM2: LASA = %p, LAML = %u\n",
(u8 *)(long)tpm2->log_area_start_address,
tpm2->log_area_minimum_length);

return tpm_set_log_area((u8*)(long)tpm2->log_area_start_address,
tpm2->log_area_minimum_length);
}

/*
* Extend the ACPI log with the given entry by copying the
* entry data into the log.
Expand Down Expand Up @@ -949,9 +976,12 @@ tpm_setup(void)
"TCGBIOS: Detected a TPM %s.\n",
(TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");

int ret = tpm_tcpa_probe();
if (ret)
return;
int ret = tpm_tpm2_probe();
if (ret) {
ret = tpm_tcpa_probe();
if (ret)
return;
}

TPM_working = 1;

Expand Down
1 change: 1 addition & 0 deletions src/util.h
Expand Up @@ -51,6 +51,7 @@ struct disk_op_s;
int cdemu_process_op(struct disk_op_s *op);
void cdrom_prepboot(void);
int cdrom_boot(struct drive_s *drive_g);
char *cdrom_media_info(struct drive_s *drive_g);

// clock.c
void clock_setup(void);
Expand Down
5 changes: 5 additions & 0 deletions src/x86.h
Expand Up @@ -211,6 +211,11 @@ static inline void writeb(void *addr, u8 val) {
barrier();
*(volatile u8 *)addr = val;
}
static inline u64 readq(const void *addr) {
u64 val = *(volatile const u64 *)addr;
barrier();
return val;
}
static inline u32 readl(const void *addr) {
u32 val = *(volatile const u32 *)addr;
barrier();
Expand Down
24 changes: 24 additions & 0 deletions vgasrc/Kconfig
Expand Up @@ -55,6 +55,28 @@ menu "VGA ROM"
Build support for a vgabios wrapper around video
devices initialized using coreboot native vga init.

config DISPLAY_BOCHS
depends on QEMU
bool "qemu bochs-display support"
select VGA_EMULATE_TEXT
help
Build support for the qemu bochs-display device, which
is basically qemu stdvga without the legacy vga
emulation, supporting only 16+32 bpp VESA video modes
in a linear framebuffer. So this uses cbvga text mode
emulation.

The bochs-display device is available in qemu
v3.0+. The vgabios works with the qemu stdvga too (use
"qemu -device VGA,romfile=/path/to/vgabios.bin")".

config VGA_RAMFB
depends on QEMU
bool "qemu ramfb"
select VGA_EMULATE_TEXT
help
qemu ram framebuffer support (-device ramfb).

endchoice

choice
Expand Down Expand Up @@ -166,6 +188,7 @@ menu "VGA ROM"
default 0x1af4 if VGA_BOCHS_VIRTIO
default 0x100b if VGA_GEODEGX2
default 0x1022 if VGA_GEODELX
default 0x1234 if DISPLAY_BOCHS
default 0x0000
help
Vendor ID for the PCI ROM
Expand All @@ -181,6 +204,7 @@ menu "VGA ROM"
default 0x1050 if VGA_BOCHS_VIRTIO
default 0x0030 if VGA_GEODEGX2
default 0x2081 if VGA_GEODELX
default 0x1111 if DISPLAY_BOCHS
default 0x0000
help
Device ID for the PCI ROM
Expand Down
59 changes: 59 additions & 0 deletions vgasrc/bochsdisplay.c
@@ -0,0 +1,59 @@
#include "biosvar.h" // GET_BDA
#include "output.h" // dprintf
#include "string.h" // memset16_far
#include "bochsvga.h" // VBE_BOCHS_*
#include "hw/pci.h" // pci_config_readl
#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
#include "vgautil.h" // VBE_total_memory

#define FRAMEBUFFER_WIDTH 1024
#define FRAMEBUFFER_HEIGHT 768
#define FRAMEBUFFER_BPP 4
#define FRAMEBUFFER_STRIDE (FRAMEBUFFER_BPP * FRAMEBUFFER_WIDTH)
#define FRAMEBUFFER_SIZE (FRAMEBUFFER_STRIDE * FRAMEBUFFER_HEIGHT)

int
bochs_display_setup(void)
{
dprintf(1, "bochs-display: setup called\n");

if (GET_GLOBAL(HaveRunInit))
return 0;

int bdf = GET_GLOBAL(VgaBDF);
if (bdf == 0)
return 0;

u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
u32 lfb_addr = bar & PCI_BASE_ADDRESS_MEM_MASK;
bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_2);
u32 io_addr = bar & PCI_BASE_ADDRESS_IO_MASK;
dprintf(1, "bochs-display: bdf %02x:%02x.%x, bar 0 at 0x%x, bar 1 at 0x%x\n"
, pci_bdf_to_bus(bdf) , pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf),
lfb_addr, io_addr);

u16 *dispi = (void*)(io_addr + 0x500);
u8 *vga = (void*)(io_addr + 0x400);
u16 id = readw(dispi + VBE_DISPI_INDEX_ID);
dprintf(1, "bochs-display: id is 0x%x, %s\n", id
, id == VBE_DISPI_ID5 ? "good" : "FAIL");
if (id != VBE_DISPI_ID5)
return -1;

dprintf(1, "bochs-display: using %dx%d, %d bpp (%d stride)\n"
, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT
, FRAMEBUFFER_BPP * 8, FRAMEBUFFER_STRIDE);

cbvga_setup_modes(lfb_addr, FRAMEBUFFER_BPP * 8,
FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
FRAMEBUFFER_STRIDE);

writew(dispi + VBE_DISPI_INDEX_XRES, FRAMEBUFFER_WIDTH);
writew(dispi + VBE_DISPI_INDEX_YRES, FRAMEBUFFER_HEIGHT);
writew(dispi + VBE_DISPI_INDEX_BPP, FRAMEBUFFER_BPP * 8);
writew(dispi + VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);

writeb(vga, 0x20); /* unblank (for qemu -device VGA) */

return 0;
}
102 changes: 67 additions & 35 deletions vgasrc/cbvga.c
Expand Up @@ -104,6 +104,8 @@ struct vgamode_s *cbvga_find_mode(int mode)
void
cbvga_list_modes(u16 seg, u16 *dest, u16 *last)
{
int seen = 0;

if (GET_GLOBAL(CBmode) != 0x3) {
/* Advertise additional SVGA modes for Microsoft NTLDR graphical mode.
* Microsoft NTLDR:
Expand All @@ -119,9 +121,11 @@ cbvga_list_modes(u16 seg, u16 *dest, u16 *last)
continue;
SET_FARVAR(seg, *dest, mode);
dest++;
if (GET_GLOBAL(CBmode) == mode)
seen = 1;
}
}
if (dest < last) {
if (dest < last && !seen) {
SET_FARVAR(seg, *dest, GET_GLOBAL(CBmode));
dest++;
}
Expand Down Expand Up @@ -188,19 +192,29 @@ int
cbvga_set_mode(struct vgamode_s *vmode_g, int flags)
{
u8 emul = vmode_g == &CBemulinfo || GET_GLOBAL(CBmode) == 0x03;
/*
* The extra_stack flag is false when running in windows x86
* emulator, to avoid stack switching triggering bugs. Using the
* same flag here to skip screen clearing, because the windows
* emulator seems to have problems to handle the int 1587 call
* too, and GO_MEMSET uses that.
*/
u8 extra_stack = GET_BDA_EXT(flags) & BF_EXTRA_STACK;
MASK_BDA_EXT(flags, BF_EMULATE_TEXT, emul ? BF_EMULATE_TEXT : 0);
if (!(flags & MF_NOCLEARMEM)) {
if (GET_GLOBAL(CBmodeinfo.memmodel) == MM_TEXT) {
memset16_far(SEG_CTEXT, (void*)0, 0x0720, 80*25*2);
return 0;
}
struct gfx_op op;
init_gfx_op(&op, &CBmodeinfo);
op.x = op.y = 0;
op.xlen = GET_GLOBAL(CBmodeinfo.width);
op.ylen = GET_GLOBAL(CBmodeinfo.height);
op.op = GO_MEMSET;
handle_gfx_op(&op);
if (extra_stack || flags & MF_LEGACY) {
struct gfx_op op;
init_gfx_op(&op, &CBmodeinfo);
op.x = op.y = 0;
op.xlen = GET_GLOBAL(CBmodeinfo.width);
op.ylen = GET_GLOBAL(CBmodeinfo.height);
op.op = GO_MEMSET;
handle_gfx_op(&op);
}
}
return 0;
}
Expand Down Expand Up @@ -232,10 +246,45 @@ struct cb_framebuffer {
u8 reserved_mask_size;
};

void
cbvga_setup_modes(u64 addr, u8 bpp, u32 xlines, u32 ylines, u32 linelength)
{
int i;

SET_VGA(CBmode, 0x140);
SET_VGA(VBE_framebuffer, addr);
SET_VGA(VBE_total_memory, linelength * ylines);
SET_VGA(CBlinelength, linelength);
SET_VGA(CBmodeinfo.memmodel, MM_DIRECT);
SET_VGA(CBmodeinfo.width, xlines);
SET_VGA(CBmodeinfo.height, ylines);
SET_VGA(CBmodeinfo.depth, bpp);
SET_VGA(CBmodeinfo.cwidth, 8);
SET_VGA(CBmodeinfo.cheight, 16);
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);
}
if ((GET_GLOBAL(cbmode_g->info.height) == ylines)
&& (GET_GLOBAL(cbmode_g->info.width) == xlines)
&& (GET_GLOBAL(cbmode_g->info.depth) == bpp)) {
SET_VGA(CBmode, GET_GLOBAL(cbmode_g->mode));
}
}
}

int
cbvga_setup(void)
{
int i;
dprintf(1, "coreboot vga init\n");

if (GET_GLOBAL(HaveRunInit))
Expand Down Expand Up @@ -263,11 +312,17 @@ cbvga_setup(void)
}

u64 addr = GET_FARVAR(0, cbfb->physical_address);
u8 bpp = cbfb->blue_mask_size + cbfb->green_mask_size
+ cbfb->red_mask_size + cbfb->reserved_mask_size;
u8 bpp = GET_FARVAR(0, cbfb->blue_mask_size)
+ GET_FARVAR(0, cbfb->green_mask_size)
+ GET_FARVAR(0, cbfb->red_mask_size)
+ GET_FARVAR(0, 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);
//fall back to coreboot reported bpp if calculated value invalid
if (bpp != 15 && bpp != 16 && bpp != 24 && bpp != 32)
bpp = GET_FARVAR(0, cbfb->bits_per_pixel);

dprintf(1, "Found FB @ %llx %dx%d with %d bpp (%d stride)\n"
, addr, xlines, ylines, bpp, linelength);

Expand All @@ -277,29 +332,6 @@ cbvga_setup(void)
return -1;
}

SET_VGA(CBmode, 0x140);
SET_VGA(VBE_framebuffer, addr);
SET_VGA(VBE_total_memory, linelength * ylines);
SET_VGA(CBlinelength, linelength);
SET_VGA(CBmodeinfo.memmodel, MM_DIRECT);
SET_VGA(CBmodeinfo.width, xlines);
SET_VGA(CBmodeinfo.height, ylines);
SET_VGA(CBmodeinfo.depth, bpp);
SET_VGA(CBmodeinfo.cwidth, 8);
SET_VGA(CBmodeinfo.cheight, 16);
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);
}
}
cbvga_setup_modes(addr, bpp, xlines, ylines, linelength);
return 0;
}
163 changes: 163 additions & 0 deletions vgasrc/ramfb.c
@@ -0,0 +1,163 @@
#include "biosvar.h" // GET_BDA
#include "output.h" // dprintf
#include "string.h" // memset16_far
#include "vgautil.h" // VBE_total_memory
#include "std/pmm.h" // struct pmmheader
#include "byteorder.h"
#include "fw/paravirt.h"

/* ---------------------------------------------------------------------- */
/* minimal qemu fc_cfg support bits, requires dma support */

#define QEMU_CFG_FILE_DIR 0x19

struct QemuCfgFile {
u32 size; /* file size */
u16 select; /* write this to 0x510 to read it */
u16 reserved;
char name[56];
};

static void
qemu_cfg_dma_transfer(void *address, u32 length, u32 control)
{
QemuCfgDmaAccess access;

if (length == 0) {
return;
}

access.address = cpu_to_be64((u64)(u32)address);
access.length = cpu_to_be32(length);
access.control = cpu_to_be32(control);

barrier();

outl(cpu_to_be32((u32)&access), PORT_QEMU_CFG_DMA_ADDR_LOW);

while(be32_to_cpu(access.control) & ~QEMU_CFG_DMA_CTL_ERROR)
/* wait */;
}

static void
qemu_cfg_read(void *buf, int len)
{
qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_READ);
}

static void
qemu_cfg_read_entry(void *buf, int e, int len)
{
u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT
| QEMU_CFG_DMA_CTL_READ;
qemu_cfg_dma_transfer(buf, len, control);
}

static void
qemu_cfg_write_entry(void *buf, int e, int len)
{
u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT
| QEMU_CFG_DMA_CTL_WRITE;
qemu_cfg_dma_transfer(buf, len, control);
}

static int
qemu_cfg_find_file(const char *filename)
{
u32 count, e, select;

qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
count = be32_to_cpu(count);
for (select = 0, e = 0; e < count; e++) {
struct QemuCfgFile qfile;
qemu_cfg_read(&qfile, sizeof(qfile));
if (memcmp_far(GET_SEG(SS), qfile.name,
GET_SEG(CS), filename, 10) == 0)
select = be16_to_cpu(qfile.select);
}
return select;
}

/* ---------------------------------------------------------------------- */

#define FRAMEBUFFER_WIDTH 1024
#define FRAMEBUFFER_HEIGHT 768
#define FRAMEBUFFER_BPP 4
#define FRAMEBUFFER_STRIDE (FRAMEBUFFER_BPP * FRAMEBUFFER_WIDTH)
#define FRAMEBUFFER_SIZE (FRAMEBUFFER_STRIDE * FRAMEBUFFER_HEIGHT)

struct QemuRAMFBCfg {
u64 addr;
u32 fourcc;
u32 flags;
u32 width;
u32 height;
u32 stride;
};

#define fourcc_code(a, b, c, d) ((u32)(a) | ((u32)(b) << 8) | \
((u32)(c) << 16) | ((u32)(d) << 24))

#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */
#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */
#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */

static u32
allocate_framebuffer(void)
{
u32 res = allocate_pmm(FRAMEBUFFER_SIZE, 1, 1);
if (!res)
return 0;
dprintf(1, "ramfb: framebuffer allocated at %x\n", res);
return res;
}

int
ramfb_setup(void)
{
dprintf(1, "ramfb: init\n");

if (GET_GLOBAL(HaveRunInit))
return 0;

u32 select = qemu_cfg_find_file("etc/ramfb");
if (select == 0) {
dprintf(1, "ramfb: fw_cfg (etc/ramfb) file not found\n");
return -1;
}

dprintf(1, "ramfb: fw_cfg (etc/ramfb) file at slot 0x%x\n", select);
u32 fb = allocate_framebuffer();
if (!fb) {
dprintf(1, "ramfb: allocating framebuffer failed\n");
return -1;
}

u64 addr = fb;
u8 bpp = FRAMEBUFFER_BPP * 8;
u32 xlines = FRAMEBUFFER_WIDTH;
u32 ylines = FRAMEBUFFER_HEIGHT;
u32 linelength = FRAMEBUFFER_STRIDE;
dprintf(1, "Found FB @ %llx %dx%d with %d bpp (%d stride)\n"
, addr, xlines, ylines, bpp, linelength);

if (!addr || addr > 0xffffffff
|| (bpp != 15 && bpp != 16 && bpp != 24 && bpp != 32)) {
dprintf(1, "Unable to use FB\n");
return -1;
}

cbvga_setup_modes(addr, bpp, xlines, ylines, linelength);

struct QemuRAMFBCfg cfg = {
.addr = cpu_to_be64(fb),
.fourcc = cpu_to_be32(DRM_FORMAT_XRGB8888),
.flags = cpu_to_be32(0),
.width = cpu_to_be32(FRAMEBUFFER_WIDTH),
.height = cpu_to_be32(FRAMEBUFFER_HEIGHT),
.stride = cpu_to_be32(FRAMEBUFFER_STRIDE),
};
qemu_cfg_write_entry(&cfg, select, sizeof(cfg));

return 0;
}
30 changes: 17 additions & 13 deletions vgasrc/vgahw.h
Expand Up @@ -14,7 +14,7 @@ static inline struct vgamode_s *vgahw_find_mode(int mode) {
return clext_find_mode(mode);
if (CONFIG_VGA_BOCHS)
return bochsvga_find_mode(mode);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_find_mode(mode);
return stdvga_find_mode(mode);
}
Expand All @@ -24,7 +24,7 @@ static inline int vgahw_set_mode(struct vgamode_s *vmode_g, int flags) {
return clext_set_mode(vmode_g, flags);
if (CONFIG_VGA_BOCHS)
return bochsvga_set_mode(vmode_g, flags);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_set_mode(vmode_g, flags);
return stdvga_set_mode(vmode_g, flags);
}
Expand All @@ -34,7 +34,7 @@ static inline void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) {
clext_list_modes(seg, dest, last);
else if (CONFIG_VGA_BOCHS)
bochsvga_list_modes(seg, dest, last);
else if (CONFIG_VGA_COREBOOT)
else if (CONFIG_VGA_EMULATE_TEXT)
cbvga_list_modes(seg, dest, last);
else
stdvga_list_modes(seg, dest, last);
Expand All @@ -49,6 +49,10 @@ static inline int vgahw_setup(void) {
return geodevga_setup();
if (CONFIG_VGA_COREBOOT)
return cbvga_setup();
if (CONFIG_DISPLAY_BOCHS)
return bochs_display_setup();
if (CONFIG_VGA_RAMFB)
return ramfb_setup();
return stdvga_setup();
}

Expand All @@ -57,7 +61,7 @@ static inline int vgahw_get_window(struct vgamode_s *vmode_g, int window) {
return clext_get_window(vmode_g, window);
if (CONFIG_VGA_BOCHS)
return bochsvga_get_window(vmode_g, window);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_get_window(vmode_g, window);
return stdvga_get_window(vmode_g, window);
}
Expand All @@ -68,7 +72,7 @@ static inline int vgahw_set_window(struct vgamode_s *vmode_g, int window
return clext_set_window(vmode_g, window, val);
if (CONFIG_VGA_BOCHS)
return bochsvga_set_window(vmode_g, window, val);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_set_window(vmode_g, window, val);
return stdvga_set_window(vmode_g, window, val);
}
Expand All @@ -78,7 +82,7 @@ static inline int vgahw_get_linelength(struct vgamode_s *vmode_g) {
return clext_get_linelength(vmode_g);
if (CONFIG_VGA_BOCHS)
return bochsvga_get_linelength(vmode_g);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_get_linelength(vmode_g);
return stdvga_get_linelength(vmode_g);
}
Expand All @@ -88,7 +92,7 @@ static inline int vgahw_set_linelength(struct vgamode_s *vmode_g, int val) {
return clext_set_linelength(vmode_g, val);
if (CONFIG_VGA_BOCHS)
return bochsvga_set_linelength(vmode_g, val);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_set_linelength(vmode_g, val);
return stdvga_set_linelength(vmode_g, val);
}
Expand All @@ -98,7 +102,7 @@ static inline int vgahw_get_displaystart(struct vgamode_s *vmode_g) {
return clext_get_displaystart(vmode_g);
if (CONFIG_VGA_BOCHS)
return bochsvga_get_displaystart(vmode_g);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_get_displaystart(vmode_g);
return stdvga_get_displaystart(vmode_g);
}
Expand All @@ -108,23 +112,23 @@ static inline int vgahw_set_displaystart(struct vgamode_s *vmode_g, int val) {
return clext_set_displaystart(vmode_g, val);
if (CONFIG_VGA_BOCHS)
return bochsvga_set_displaystart(vmode_g, val);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_set_displaystart(vmode_g, val);
return stdvga_set_displaystart(vmode_g, val);
}

static inline int vgahw_get_dacformat(struct vgamode_s *vmode_g) {
if (CONFIG_VGA_BOCHS)
return bochsvga_get_dacformat(vmode_g);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_get_dacformat(vmode_g);
return stdvga_get_dacformat(vmode_g);
}

static inline int vgahw_set_dacformat(struct vgamode_s *vmode_g, int val) {
if (CONFIG_VGA_BOCHS)
return bochsvga_set_dacformat(vmode_g, val);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_set_dacformat(vmode_g, val);
return stdvga_set_dacformat(vmode_g, val);
}
Expand All @@ -134,13 +138,13 @@ static inline int vgahw_save_restore(int cmd, u16 seg, void *data) {
return clext_save_restore(cmd, seg, data);
if (CONFIG_VGA_BOCHS)
return bochsvga_save_restore(cmd, seg, data);
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_save_restore(cmd, seg, data);
return stdvga_save_restore(cmd, seg, data);
}

static inline int vgahw_get_linesize(struct vgamode_s *vmode_g) {
if (CONFIG_VGA_COREBOOT)
if (CONFIG_VGA_EMULATE_TEXT)
return cbvga_get_linesize(vmode_g);
return stdvga_get_linesize(vmode_g);
}
Expand Down
48 changes: 32 additions & 16 deletions vgasrc/vgainit.c
Expand Up @@ -42,13 +42,9 @@ struct pci_data rom_pci_data VAR16 VISIBLE16 = {
* PMM call and extra stack setup
****************************************************************/

u16 ExtraStackSeg VAR16 VISIBLE16;

static void
allocate_extra_stack(void)
u32
allocate_pmm(u32 size, int highmem, int aligned)
{
if (!CONFIG_VGA_ALLOCATE_EXTRA_STACK)
return;
u32 pmmscan;
for (pmmscan=0; pmmscan < BUILD_BIOS_SIZE; pmmscan+=16) {
struct pmmheader *pmm = (void*)pmmscan;
Expand All @@ -57,29 +53,49 @@ allocate_extra_stack(void)
if (checksum_far(SEG_BIOS, pmm, GET_FARVAR(SEG_BIOS, pmm->length)))
continue;
struct segoff_s entry = GET_FARVAR(SEG_BIOS, pmm->entry);
dprintf(1, "Attempting to allocate VGA stack via pmm call to %04x:%04x\n"
dprintf(1, "Attempting to allocate %u bytes %s via pmm call to %04x:%04x\n"
, size, highmem ? "highmem" : "lowmem"
, entry.seg, entry.offset);
u16 res1, res2;
u16 flags = 8 |
( highmem ? 2 : 1 )|
( aligned ? 4 : 0 );
size >>= 4;
asm volatile(
"pushl %0\n"
"pushw $(8|1)\n" // Permanent low memory request
"pushw %2\n" // flags
"pushl $0xffffffff\n" // Anonymous handle
"pushl $" __stringify(CONFIG_VGA_EXTRA_STACK_SIZE/16) "\n"
"pushl %1\n" // size
"pushw $0x00\n" // PMM allocation request
"lcallw *12(%%esp)\n"
"addl $16, %%esp\n"
"cli\n"
"cld\n"
: "+r" (entry.segoff), "=a" (res1), "=d" (res2) : : "cc", "memory");
: "+r" (entry.segoff), "+r" (size), "+r" (flags),
"=a" (res1), "=d" (res2) : : "cc", "memory");
u32 res = res1 | (res2 << 16);
if (!res || res == PMM_FUNCTION_NOT_SUPPORTED)
return;
dprintf(1, "VGA stack allocated at %x\n", res);
SET_VGA(ExtraStackSeg, res >> 4);
extern void entry_10_extrastack(void);
SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10_extrastack));
return;
return 0;
return res;
}
return 0;
}

u16 ExtraStackSeg VAR16 VISIBLE16;

static void
allocate_extra_stack(void)
{
if (!CONFIG_VGA_ALLOCATE_EXTRA_STACK)
return;
u32 res = allocate_pmm(CONFIG_VGA_EXTRA_STACK_SIZE, 0, 0);
if (!res)
return;
dprintf(1, "VGA stack allocated at %x\n", res);
SET_VGA(ExtraStackSeg, res >> 4);
extern void entry_10_extrastack(void);
SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10_extrastack));
return;
}


Expand Down
8 changes: 8 additions & 0 deletions vgasrc/vgautil.h
Expand Up @@ -18,8 +18,15 @@ 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);
void cbvga_setup_modes(u64 addr, u8 bpp, u32 xlines, u32 ylines, u32 linelength);
int cbvga_setup(void);

// bochsdisplay.c
int bochs_display_setup(void);

// ramfb.c
int ramfb_setup(void);

// clext.c
struct vgamode_s *clext_find_mode(int mode);
void clext_list_modes(u16 seg, u16 *dest, u16 *last);
Expand Down Expand Up @@ -88,6 +95,7 @@ extern u8 vgafont16alt[];
// vgainit.c
extern int VgaBDF;
extern int HaveRunInit;
u32 allocate_pmm(u32 size, int highmem, int aligned);

// vgaversion.c
extern const char VERSION[], BUILDINFO[];
Expand Down