278 changes: 258 additions & 20 deletions src/tcgbios.c
Expand Up @@ -161,23 +161,86 @@ struct tpm_log_entry {
+ SHA512_BUFSIZE + SM3_256_BUFSIZE];
} PACKED;

static const struct hash_parameters {
u16 hashalg;
u8 hashalg_flag;
u8 hash_buffersize;
const char *name;
} hash_parameters[] = {
{
.hashalg = TPM2_ALG_SHA1,
.hashalg_flag = TPM2_ALG_SHA1_FLAG,
.hash_buffersize = SHA1_BUFSIZE,
.name = "SHA1",
}, {
.hashalg = TPM2_ALG_SHA256,
.hashalg_flag = TPM2_ALG_SHA256_FLAG,
.hash_buffersize = SHA256_BUFSIZE,
.name = "SHA256",
}, {
.hashalg = TPM2_ALG_SHA384,
.hashalg_flag = TPM2_ALG_SHA384_FLAG,
.hash_buffersize = SHA384_BUFSIZE,
.name = "SHA384",
}, {
.hashalg = TPM2_ALG_SHA512,
.hashalg_flag = TPM2_ALG_SHA512_FLAG,
.hash_buffersize = SHA512_BUFSIZE,
.name = "SHA512",
}, {
.hashalg = TPM2_ALG_SM3_256,
.hashalg_flag = TPM2_ALG_SM3_256_FLAG,
.hash_buffersize = SM3_256_BUFSIZE,
.name = "SM3-256",
}
};

static int
tpm20_get_hash_buffersize(u16 hashAlg)
{
switch (hashAlg) {
case TPM2_ALG_SHA1:
return SHA1_BUFSIZE;
case TPM2_ALG_SHA256:
return SHA256_BUFSIZE;
case TPM2_ALG_SHA384:
return SHA384_BUFSIZE;
case TPM2_ALG_SHA512:
return SHA512_BUFSIZE;
case TPM2_ALG_SM3_256:
return SM3_256_BUFSIZE;
default:
return -1;
unsigned i;

for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
if (hash_parameters[i].hashalg == hashAlg)
return hash_parameters[i].hash_buffersize;
}
return -1;
}

static u8
tpm20_hashalg_to_flag(u16 hashAlg)
{
unsigned i;

for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
if (hash_parameters[i].hashalg == hashAlg)
return hash_parameters[i].hashalg_flag;
}
return 0;
}

static u16
tpm20_hashalg_flag_to_hashalg(u8 hashalg_flag)
{
unsigned i;

for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
if (hash_parameters[i].hashalg_flag == hashalg_flag)
return hash_parameters[i].hashalg;
}
return 0;
}

static const char *
tpm20_hashalg_flag_to_name(u8 hashalg_flag)
{
unsigned i;

for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
if (hash_parameters[i].hashalg_flag == hashalg_flag)
return hash_parameters[i].name;
}
return NULL;
}

// Add an entry at the start of the log describing digest formats
Expand Down Expand Up @@ -432,6 +495,115 @@ tpm20_get_pcrbanks(void)
return ret;
}

static int
tpm20_get_suppt_pcrbanks(u8 *suppt_pcrbanks, u8 *active_pcrbanks)
{
*suppt_pcrbanks = 0;
*active_pcrbanks = 0;

if (!tpm20_pcr_selection)
return -1;

struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
void *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;

while (1) {
u8 sizeOfSelect = sel->sizeOfSelect;
void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
if (nsel > end)
return 0;

u16 hashalg = be16_to_cpu(sel->hashAlg);
u8 hashalg_flag = tpm20_hashalg_to_flag(hashalg);

*suppt_pcrbanks |= hashalg_flag;

unsigned i;
for (i = 0; i < sizeOfSelect; i++) {
if (sel->pcrSelect[i]) {
*active_pcrbanks |= hashalg_flag;
break;
}
}

sel = nsel;
}
}

static int
tpm20_set_pcrbanks(u32 active_banks)
{
struct tpm2_req_pcr_allocate trpa = {
.hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
.hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Allocate),
.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
.authblocksize = cpu_to_be32(sizeof(trpa.authblock)),
.authblock = {
.handle = cpu_to_be32(TPM2_RS_PW),
.noncesize = cpu_to_be16(0),
.contsession = TPM2_YES,
.pwdsize = cpu_to_be16(0),
},
};
struct tpms_pcr_selection3 {
u16 hashAlg;
u8 sizeOfSelect;
u8 pcrSelect[3];
} tps[ARRAY_SIZE(trpa.tpms_pcr_selections)];
int i = 0;
u8 hashalg_flag = TPM2_ALG_SHA1_FLAG;
u8 dontcare, suppt_banks;

tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare);

while (hashalg_flag) {
if ((hashalg_flag & suppt_banks)) {
u16 hashalg = tpm20_hashalg_flag_to_hashalg(hashalg_flag);

if (hashalg) {
u8 mask = 0;
tps[i].hashAlg = cpu_to_be16(hashalg);
tps[i].sizeOfSelect = 3;

if (active_banks & hashalg_flag)
mask = 0xff;

tps[i].pcrSelect[0] = mask;
tps[i].pcrSelect[1] = mask;
tps[i].pcrSelect[2] = mask;
i++;
}
}
hashalg_flag <<= 1;
}

trpa.count = cpu_to_be32(i);
memcpy(trpa.tpms_pcr_selections, tps, i * sizeof(tps[0]));
trpa.hdr.totlen = cpu_to_be32(offsetof(struct tpm2_req_pcr_allocate,
tpms_pcr_selections) +
i * sizeof(tps[0]));

struct tpm_rsp_header rsp;
u32 resp_length = sizeof(rsp);

int ret = tpmhw_transmit(0, &trpa.hdr, &rsp, &resp_length,
TPM_DURATION_TYPE_SHORT);
ret = ret ? -1 : be32_to_cpu(rsp.errcode);

return ret;
}

static int tpm20_activate_pcrbanks(u32 active_banks)
{
int ret = tpm20_set_pcrbanks(active_banks);
if (!ret)
ret = tpm_simple_cmd(0, TPM2_CC_Shutdown,
2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
if (!ret)
reset();
return ret;
}

static int
tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
{
Expand Down Expand Up @@ -968,6 +1140,13 @@ tpm_setup(void)
if (!CONFIG_TCGBIOS)
return;

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

TPM_version = tpmhw_probe();
if (TPM_version == TPM_VERSION_NONE)
return;
Expand All @@ -976,13 +1155,6 @@ tpm_setup(void)
"TCGBIOS: Detected a TPM %s.\n",
(TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");

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

TPM_working = 1;

if (runningOnXen())
Expand Down Expand Up @@ -1947,6 +2119,68 @@ tpm12_menu(void)
}
}

static int
tpm20_menu_change_active_pcrbanks(void)
{
u8 active_banks, suppt_banks;

tpm20_get_suppt_pcrbanks(&suppt_banks, &active_banks);

u8 activate_banks = active_banks;

while (1) {
u8 hashalg_flag = TPM2_ALG_SHA1_FLAG;
u8 i = 0;

printf("\nToggle active PCR banks by pressing number key\n\n");

while (hashalg_flag) {
u8 flag = hashalg_flag & suppt_banks;
const char *hashname = tpm20_hashalg_flag_to_name(flag);

i++;
if (hashname) {
printf(" %d: %s", i, hashname);
if (activate_banks & hashalg_flag)
printf(" (enabled)");
printf("\n");
}

hashalg_flag <<= 1;
}
printf("\n"
"ESC: return to previous menu without changes\n");
if (activate_banks)
printf("A : activate selection\n");

u8 flagnum;
int show = 0;
while (!show) {
int scancode = get_keystroke(1000);

switch (scancode) {
case ~0:
continue;
case 1: /* ESC */
printf("\n");
return -1;
case 2 ... 6: /* keys 1 .. 5 */
flagnum = scancode - 1;
if (flagnum > i)
continue;
if (suppt_banks & (1 << (flagnum - 1))) {
activate_banks ^= 1 << (flagnum - 1);
show = 1;
}
break;
case 30: /* a */
if (activate_banks)
tpm20_activate_pcrbanks(activate_banks);
}
}
}
}

static void
tpm20_menu(void)
{
Expand All @@ -1955,6 +2189,7 @@ tpm20_menu(void)

for (;;) {
printf("1. Clear TPM\n");
printf("2. Change active PCR banks\n");

printf("\nIf no change is desired or if this menu was reached by "
"mistake, press ESC to\n"
Expand All @@ -1973,6 +2208,9 @@ tpm20_menu(void)
case 2:
msgCode = TPM_PPI_OP_CLEAR;
break;
case 3:
tpm20_menu_change_active_pcrbanks();
continue;
default:
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion src/util.h
Expand Up @@ -12,7 +12,7 @@ void handle_1553(struct bregs *regs);
// bmp.c
struct bmp_decdata *bmp_alloc(void);
int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size);
void bmp_get_size(struct bmp_decdata *bmp, int *width, int *height);
void bmp_get_info(struct bmp_decdata *bmp, int *width, int *height, int *bpp);
int bmp_show(struct bmp_decdata *bmp, unsigned char *pic, int width
, int height, int depth, int bytes_per_line_dest);

Expand Down
11 changes: 11 additions & 0 deletions vgasrc/Kconfig
Expand Up @@ -27,6 +27,15 @@ menu "VGA ROM"
and Bochs emulators. This is for emulators; it is not
intended for use on real Cirrus hardware.

config VGA_ATI
depends on QEMU
bool "QEMU ATI SVGA"
select VGA_STDVGA_PORTS
help
Build support for ATI VGA emulation found on QEMU
and emulators. This is for emulators; it is not
intended for use on real ATI hardware.

config VGA_BOCHS
depends on QEMU
bool "QEMU/Bochs VBE SVGA"
Expand Down Expand Up @@ -182,6 +191,7 @@ menu "VGA ROM"
hex
prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
default 0x1013 if VGA_CIRRUS
default 0x1002 if VGA_ATI
default 0x1234 if VGA_BOCHS_STDVGA
default 0x15ad if VGA_BOCHS_VMWARE
default 0x1b36 if VGA_BOCHS_QXL
Expand All @@ -198,6 +208,7 @@ menu "VGA ROM"
hex
prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
default 0x00b8 if VGA_CIRRUS
default 0x5159 if VGA_ATI
default 0x1111 if VGA_BOCHS_STDVGA
default 0x0405 if VGA_BOCHS_VMWARE
default 0x0100 if VGA_BOCHS_QXL
Expand Down
43 changes: 43 additions & 0 deletions vgasrc/ati-tables.S
@@ -0,0 +1,43 @@
//
// Fake ati bios tables.
//
// aty128fb and radeonfb try to gather informations from these tables,
// so add some stuff here to make the drivers happy. Specifically
// radeonfb needs the pll information, otherwise it'll crash with a
// division by zero ...
//
.org 0x48
.word _ati_main

// main info
.org 0x50
_ati_main:
.org 0x50 + 0x30
.word _ati_pll
.org 0x50 + 0x50
.word _ati_connector

// pll info
.org 0x100
_ati_pll:
.word 0 // ??? (not used by radeonfb)
.word 0
.word 0
.word 0
.word 23000 // sclk
.word 23000 // mclk
.word 0
.word 2700 // ref_clk
.word 4 // ref_div
.long 12000 // ppll_min
.long 35000 // ppll_max

// connector info
.org 0x140
_ati_connector:
.byte 0x10 // one chip
.byte 0x01 // one connector
.word 0x3000 // type DVI-I
.word 0 // end of list

.org 0x200
245 changes: 245 additions & 0 deletions vgasrc/atiext.c
@@ -0,0 +1,245 @@
// QEMU ATI VGABIOS Extension.
//
// This file may be distributed under the terms of the GNU LGPLv3 license.

#include "biosvar.h" // GET_GLOBAL
#include "bregs.h" // struct bregs
#include "hw/pci.h" // pci_config_readl
#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
#include "output.h" // dprintf
#include "stdvga.h" // VGAREG_SEQU_ADDRESS
#include "string.h" // memset16_far
#include "vgabios.h" // SET_VGA
#include "vgautil.h" // VBE_total_memory
#include "vgafb.h" // memset_high

#include "svgamodes.h"

#define MM_INDEX 0x0000
#define MM_DATA 0x0004
#define CRTC_GEN_CNTL 0x0050
#define CRTC_EXT_CNTL 0x0054
#define CRTC_H_TOTAL_DISP 0x0200
#define CRTC_V_TOTAL_DISP 0x0208
#define CRTC_OFFSET 0x0224
#define CRTC_PITCH 0x022c

/* CRTC control values (CRTC_GEN_CNTL) */
#define CRTC2_EXT_DISP_EN 0x01000000
#define CRTC2_EN 0x02000000

#define CRTC_PIX_WIDTH_MASK 0x00000700
#define CRTC_PIX_WIDTH_4BPP 0x00000100
#define CRTC_PIX_WIDTH_8BPP 0x00000200
#define CRTC_PIX_WIDTH_15BPP 0x00000300
#define CRTC_PIX_WIDTH_16BPP 0x00000400
#define CRTC_PIX_WIDTH_24BPP 0x00000500
#define CRTC_PIX_WIDTH_32BPP 0x00000600

/* CRTC_EXT_CNTL */
#define CRT_CRTC_DISPLAY_DIS 0x00000400
#define CRT_CRTC_ON 0x00008000

static u32 ati_io_addr VAR16 = 0;

int
is_ati_mode(struct vgamode_s *vmode_g)
{
unsigned int mcount = GET_GLOBAL(svga_mcount);

return (vmode_g >= &svga_modes[0].info &&
vmode_g <= &svga_modes[mcount-1].info);
}

struct vgamode_s *
ati_find_mode(int mode)
{
u32 io_addr = GET_GLOBAL(ati_io_addr);
struct generic_svga_mode *table_g = svga_modes;
unsigned int mcount = GET_GLOBAL(svga_mcount);

if (io_addr) {
while (table_g < &svga_modes[mcount]) {
if (GET_GLOBAL(table_g->mode) == mode)
return &table_g->info;
table_g++;
}
}

return stdvga_find_mode(mode);
}

void
ati_list_modes(u16 seg, u16 *dest, u16 *last)
{
u32 io_addr = GET_GLOBAL(ati_io_addr);
unsigned int mcount = GET_GLOBAL(svga_mcount);

dprintf(1, "%s: ati ext %s\n", __func__, io_addr ? "yes" : "no");
if (io_addr) {
int i;
for (i=0; i<mcount && dest<last; i++) {
u16 mode = GET_GLOBAL(svga_modes[i].mode);
if (mode == 0xffff)
continue;
SET_FARVAR(seg, *dest, mode);
dest++;
}
}

stdvga_list_modes(seg, dest, last);
}

/****************************************************************
* Mode setting
****************************************************************/

static inline void ati_write(u32 reg, u32 val)
{
u32 io_addr = GET_GLOBAL(ati_io_addr);

if (reg < 0x100) {
outl(val, io_addr + reg);
} else {
outl(reg, io_addr + MM_INDEX);
outl(val, io_addr + MM_DATA);
}
}

static void ati_clear(u32 offset, u32 size)
{
u8 data[64];
void *datap = MAKE_FLATPTR(GET_SEG(SS), data);
void *fb = (void*)(GET_GLOBAL(VBE_framebuffer) + offset);
u32 i, pos;

for (i = 0; i < sizeof(data); i++)
data[i] = 0;
for (pos = 0; pos < size; pos += sizeof(data)) {
memcpy_high(fb, datap, sizeof(data));
fb += sizeof(data);
}
}

static int
ati_ext_mode(struct generic_svga_mode *table, int flags)
{
u32 width = GET_GLOBAL(table->info.width);
u32 height = GET_GLOBAL(table->info.height);
u32 depth = GET_GLOBAL(table->info.depth);
u32 stride = width;
u32 offset = 0;
u32 pxmask = 0;
u32 bytes = 0;

dprintf(1, "%s: 0x%x, %dx%d-%d\n", __func__,
GET_GLOBAL(table->mode),
width, height, depth);

switch (depth) {
case 8: pxmask = CRTC_PIX_WIDTH_8BPP; bytes = 1; break;
case 15: pxmask = CRTC_PIX_WIDTH_15BPP; bytes = 2; break;
case 16: pxmask = CRTC_PIX_WIDTH_16BPP; bytes = 2; break;
case 24: pxmask = CRTC_PIX_WIDTH_24BPP; bytes = 3; break;
case 32: pxmask = CRTC_PIX_WIDTH_32BPP; bytes = 4; break;
}

/* disable display */
ati_write(CRTC_EXT_CNTL, CRT_CRTC_DISPLAY_DIS);

/* modeset */
ati_write(CRTC_GEN_CNTL, CRTC2_EXT_DISP_EN | CRTC2_EN | pxmask);
ati_write(CRTC_H_TOTAL_DISP, ((width / 8) - 1) << 16);
ati_write(CRTC_V_TOTAL_DISP, (height - 1) << 16);
ati_write(CRTC_OFFSET, offset);
ati_write(CRTC_PITCH, stride / 8);

/* clear screen */
if (!(flags & MF_NOCLEARMEM)) {
u32 size = width * height * bytes;
ati_clear(offset, size);
}

/* enable display */
ati_write(CRTC_EXT_CNTL, 0);

return 0;
}

int
ati_set_mode(struct vgamode_s *vmode_g, int flags)
{
struct generic_svga_mode *table_g =
container_of(vmode_g, struct generic_svga_mode, info);

if (is_ati_mode(vmode_g)) {
return ati_ext_mode(table_g, flags);
}

ati_write(CRTC_GEN_CNTL, 0);
return stdvga_set_mode(vmode_g, flags);
}

/****************************************************************
* init
****************************************************************/

int
ati_setup(void)
{
int ret = stdvga_setup();
if (ret)
return ret;

dprintf(1, "%s:%d\n", __func__, __LINE__);

if (GET_GLOBAL(HaveRunInit))
return 0;

int bdf = GET_GLOBAL(VgaBDF);
if (!CONFIG_VGA_PCI || bdf == 0)
return 0;

u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
u32 lfb_addr = bar & PCI_BASE_ADDRESS_MEM_MASK;
pci_config_writel(bdf, PCI_BASE_ADDRESS_0, ~0);
u32 barmask = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
u32 totalmem = ~(barmask & PCI_BASE_ADDRESS_MEM_MASK) + 1;
pci_config_writel(bdf, PCI_BASE_ADDRESS_0, bar);

bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_1);
u32 io_addr = bar & PCI_BASE_ADDRESS_IO_MASK;

bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_2);
u32 mmio_addr = bar & PCI_BASE_ADDRESS_MEM_MASK;

dprintf(1, "ati: bdf %02x:%02x.%x, lfb 0x%x, %d MB, io 0x%x, mmio 0x%x\n",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf),
lfb_addr, totalmem / (1024 * 1024), io_addr, mmio_addr);

SET_VGA(VBE_framebuffer, lfb_addr);
SET_VGA(VBE_total_memory, totalmem);
SET_VGA(ati_io_addr, io_addr);

// Validate modes
struct generic_svga_mode *m = svga_modes;
unsigned int mcount = GET_GLOBAL(svga_mcount);
for (; m < &svga_modes[mcount]; m++) {
u8 memmodel = GET_GLOBAL(m->info.memmodel);
u16 width = GET_GLOBAL(m->info.width);
u16 height = GET_GLOBAL(m->info.height);
u32 mem = (height * DIV_ROUND_UP(width * vga_bpp(&m->info), 8)
* stdvga_vram_ratio(&m->info));

if (width % 8 != 0 ||
width > 0x7ff * 8 ||
height > 0xfff ||
mem > totalmem ||
memmodel != MM_DIRECT) {
dprintf(1, "ati: removing mode 0x%x\n", GET_GLOBAL(m->mode));
SET_VGA(m->mode, 0xffff);
}
}

return 0;
}
102 changes: 16 additions & 86 deletions vgasrc/bochsvga.c
Expand Up @@ -23,98 +23,25 @@
* Mode tables
****************************************************************/

static struct bochsvga_mode
{
u16 mode;
struct vgamode_s info;
} bochsvga_modes[] VAR16 = {
/* standard modes */
{ 0x100, { MM_PACKED, 640, 400, 8, 8, 16, SEG_GRAPH } },
{ 0x101, { MM_PACKED, 640, 480, 8, 8, 16, SEG_GRAPH } },
{ 0x102, { MM_PLANAR, 800, 600, 4, 8, 16, SEG_GRAPH } },
{ 0x103, { MM_PACKED, 800, 600, 8, 8, 16, SEG_GRAPH } },
{ 0x104, { MM_PLANAR, 1024, 768, 4, 8, 16, SEG_GRAPH } },
{ 0x105, { MM_PACKED, 1024, 768, 8, 8, 16, SEG_GRAPH } },
{ 0x106, { MM_PLANAR, 1280, 1024, 4, 8, 16, SEG_GRAPH } },
{ 0x107, { MM_PACKED, 1280, 1024, 8, 8, 16, SEG_GRAPH } },
{ 0x10D, { MM_DIRECT, 320, 200, 15, 8, 16, SEG_GRAPH } },
{ 0x10E, { MM_DIRECT, 320, 200, 16, 8, 16, SEG_GRAPH } },
{ 0x10F, { MM_DIRECT, 320, 200, 24, 8, 16, SEG_GRAPH } },
{ 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 } },
{ 0x11C, { MM_PACKED, 1600, 1200, 8, 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 } },
/* BOCHS modes */
{ 0x140, { MM_DIRECT, 320, 200, 32, 8, 16, SEG_GRAPH } },
{ 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 } },
{ 0x146, { MM_PACKED, 320, 200, 8, 8, 16, SEG_GRAPH } },
{ 0x147, { MM_DIRECT, 1600, 1200, 32, 8, 16, SEG_GRAPH } },
{ 0x148, { MM_PACKED, 1152, 864, 8, 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 } },
};
#include "svgamodes.h"

static int dispi_found VAR16 = 0;

static int is_bochsvga_mode(struct vgamode_s *vmode_g)
{
return (vmode_g >= &bochsvga_modes[0].info
&& vmode_g <= &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)-1].info);
unsigned int mcount = GET_GLOBAL(svga_mcount);

return (vmode_g >= &svga_modes[0].info
&& vmode_g <= &svga_modes[mcount-1].info);
}

struct vgamode_s *bochsvga_find_mode(int mode)
{
struct bochsvga_mode *m = bochsvga_modes;
struct generic_svga_mode *m = svga_modes;
unsigned int mcount = GET_GLOBAL(svga_mcount);

if (GET_GLOBAL(dispi_found))
for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)]; m++)
for (; m < &svga_modes[mcount]; m++)
if (GET_GLOBAL(m->mode) == mode)
return &m->info;
return stdvga_find_mode(mode);
Expand All @@ -123,9 +50,11 @@ struct vgamode_s *bochsvga_find_mode(int mode)
void
bochsvga_list_modes(u16 seg, u16 *dest, u16 *last)
{
struct bochsvga_mode *m = bochsvga_modes;
struct generic_svga_mode *m = svga_modes;
unsigned int mcount = GET_GLOBAL(svga_mcount);

if (GET_GLOBAL(dispi_found)) {
for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)] && dest<last; m++) {
for (; m < &svga_modes[mcount] && dest<last; m++) {
u16 mode = GET_GLOBAL(m->mode);
if (mode == 0xffff)
continue;
Expand Down Expand Up @@ -429,8 +358,9 @@ bochsvga_setup(void)
u16 max_xres = dispi_read(VBE_DISPI_INDEX_XRES);
u16 max_bpp = dispi_read(VBE_DISPI_INDEX_BPP);
dispi_write(VBE_DISPI_INDEX_ENABLE, en);
struct bochsvga_mode *m = bochsvga_modes;
for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)]; m++) {
struct generic_svga_mode *m = svga_modes;
unsigned int mcount = GET_GLOBAL(svga_mcount);
for (; m < &svga_modes[mcount]; m++) {
u16 width = GET_GLOBAL(m->info.width);
u16 height = GET_GLOBAL(m->info.height);
u8 depth = GET_GLOBAL(m->info.depth);
Expand Down
80 changes: 80 additions & 0 deletions vgasrc/svgamodes.c
@@ -0,0 +1,80 @@
#include "stdvga.h" // SEG_GRAPH
#include "vgabios.h" // VAR16

#include "svgamodes.h"

struct generic_svga_mode svga_modes[] VAR16 = {
/* standard modes */
{ 0x100, { MM_PACKED, 640, 400, 8, 8, 16, SEG_GRAPH } },
{ 0x101, { MM_PACKED, 640, 480, 8, 8, 16, SEG_GRAPH } },
{ 0x102, { MM_PLANAR, 800, 600, 4, 8, 16, SEG_GRAPH } },
{ 0x103, { MM_PACKED, 800, 600, 8, 8, 16, SEG_GRAPH } },
{ 0x104, { MM_PLANAR, 1024, 768, 4, 8, 16, SEG_GRAPH } },
{ 0x105, { MM_PACKED, 1024, 768, 8, 8, 16, SEG_GRAPH } },
{ 0x106, { MM_PLANAR, 1280, 1024, 4, 8, 16, SEG_GRAPH } },
{ 0x107, { MM_PACKED, 1280, 1024, 8, 8, 16, SEG_GRAPH } },
{ 0x10D, { MM_DIRECT, 320, 200, 15, 8, 16, SEG_GRAPH } },
{ 0x10E, { MM_DIRECT, 320, 200, 16, 8, 16, SEG_GRAPH } },
{ 0x10F, { MM_DIRECT, 320, 200, 24, 8, 16, SEG_GRAPH } },
{ 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 } },
{ 0x11C, { MM_PACKED, 1600, 1200, 8, 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 } },
/* other modes */
{ 0x140, { MM_DIRECT, 320, 200, 32, 8, 16, SEG_GRAPH } },
{ 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 } },
{ 0x146, { MM_PACKED, 320, 200, 8, 8, 16, SEG_GRAPH } },
{ 0x147, { MM_DIRECT, 1600, 1200, 32, 8, 16, SEG_GRAPH } },
{ 0x148, { MM_PACKED, 1152, 864, 8, 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 } },
};
unsigned int svga_mcount VAR16 = ARRAY_SIZE(svga_modes);
12 changes: 12 additions & 0 deletions vgasrc/svgamodes.h
@@ -0,0 +1,12 @@
#ifndef __SVGAMODES_H
#define __SVGAMODES_H

struct generic_svga_mode {
u16 mode;
struct vgamode_s info;
};

extern struct generic_svga_mode svga_modes[] VAR16;
extern unsigned int svga_mcount VAR16;

#endif /* __SVGAMODES_H */
3 changes: 3 additions & 0 deletions vgasrc/vgaentry.S
Expand Up @@ -40,6 +40,9 @@ _rom_header_other2:
_rom_header_signature:
.asciz "IBM"

#if CONFIG_VGA_ATI
#include "ati-tables.S"
#endif

/****************************************************************
* Entry points
Expand Down
3 changes: 1 addition & 2 deletions vgasrc/vgafb.c
Expand Up @@ -187,8 +187,7 @@ gfx_packed(struct gfx_op *op)
****************************************************************/

// Use int 1587 call to copy memory to/from the framebuffer.
static void
memcpy_high(void *dest, void *src, u32 len)
void memcpy_high(void *dest, void *src, u32 len)
{
u64 gdt[6];
gdt[2] = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)src);
Expand Down
1 change: 1 addition & 0 deletions vgasrc/vgafb.h
Expand Up @@ -29,6 +29,7 @@ struct carattr {
};

// vgafb.c
void memcpy_high(void *dest, void *src, u32 len);
void init_gfx_op(struct gfx_op *op, struct vgamode_s *vmode_g);
void handle_gfx_op(struct gfx_op *op);
void *text_address(struct cursorpos cp);
Expand Down
8 changes: 8 additions & 0 deletions vgasrc/vgahw.h
Expand Up @@ -12,6 +12,8 @@
static inline struct vgamode_s *vgahw_find_mode(int mode) {
if (CONFIG_VGA_CIRRUS)
return clext_find_mode(mode);
if (CONFIG_VGA_ATI)
return ati_find_mode(mode);
if (CONFIG_VGA_BOCHS)
return bochsvga_find_mode(mode);
if (CONFIG_VGA_EMULATE_TEXT)
Expand All @@ -22,6 +24,8 @@ static inline struct vgamode_s *vgahw_find_mode(int mode) {
static inline int vgahw_set_mode(struct vgamode_s *vmode_g, int flags) {
if (CONFIG_VGA_CIRRUS)
return clext_set_mode(vmode_g, flags);
if (CONFIG_VGA_ATI)
return ati_set_mode(vmode_g, flags);
if (CONFIG_VGA_BOCHS)
return bochsvga_set_mode(vmode_g, flags);
if (CONFIG_VGA_EMULATE_TEXT)
Expand All @@ -32,6 +36,8 @@ static inline int vgahw_set_mode(struct vgamode_s *vmode_g, int flags) {
static inline void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) {
if (CONFIG_VGA_CIRRUS)
clext_list_modes(seg, dest, last);
if (CONFIG_VGA_ATI)
ati_list_modes(seg, dest, last);
else if (CONFIG_VGA_BOCHS)
bochsvga_list_modes(seg, dest, last);
else if (CONFIG_VGA_EMULATE_TEXT)
Expand All @@ -43,6 +49,8 @@ static inline void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) {
static inline int vgahw_setup(void) {
if (CONFIG_VGA_CIRRUS)
return clext_setup();
if (CONFIG_VGA_ATI)
return ati_setup();
if (CONFIG_VGA_BOCHS)
return bochsvga_setup();
if (CONFIG_VGA_GEODEGX2 || CONFIG_VGA_GEODELX)
Expand Down
6 changes: 6 additions & 0 deletions vgasrc/vgautil.h
Expand Up @@ -42,6 +42,12 @@ struct bregs;
void clext_1012(struct bregs *regs);
int clext_setup(void);

// atiext.c
struct vgamode_s *ati_find_mode(int mode);
void ati_list_modes(u16 seg, u16 *dest, u16 *last);
int ati_set_mode(struct vgamode_s *vmode_g, int flags);
int ati_setup(void);

// stdvgaio.c
u8 stdvga_pelmask_read(void);
void stdvga_pelmask_write(u8 val);
Expand Down