summaryrefslogtreecommitdiffstats
path: root/qemu/roms/seabios/vgasrc/vgainit.c
blob: 8d12261829f663f4fed98a99faa9346f9d0b5d21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Main VGA bios initialization
//
// Copyright (C) 2009-2013  Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2001-2008 the LGPL VGABios developers Team
//
// This file may be distributed under the terms of the GNU LGPLv3 license.

#include "biosvar.h" // SET_BDA
#include "bregs.h" // struct bregs
#include "hw/pci.h" // pci_config_readw
#include "hw/pci_regs.h" // PCI_VENDOR_ID
#include "hw/serialio.h" // serial_debug_preinit
#include "output.h" // dprintf
#include "std/optionrom.h" // struct pci_data
#include "std/pmm.h" // struct pmmheader
#include "string.h" // checksum_far
#include "util.h" // VERSION
#include "vgabios.h" // video_save_pointer_table
#include "vgahw.h" // vgahw_setup

struct video_save_pointer_s video_save_pointer_table VAR16;

struct video_param_s video_param_table[29] VAR16;

// Type of emulator platform - for dprintf with certain compile options.
int PlatformRunningOn VAR16;


/****************************************************************
 * PCI Data
 ****************************************************************/

struct pci_data rom_pci_data VAR16 VISIBLE16 = {
    .signature = PCI_ROM_SIGNATURE,
    .vendor = CONFIG_VGA_VID,
    .device = CONFIG_VGA_DID,
    .dlen = 0x18,
    .class_hi = 0x300,
    .irevision = 1,
    .type = PCIROM_CODETYPE_X86,
    .indicator = 0x80,
};


/****************************************************************
 * PMM call and extra stack setup
 ****************************************************************/

u16 ExtraStackSeg VAR16 VISIBLE16;

static void
allocate_extra_stack(void)
{
    if (!CONFIG_VGA_ALLOCATE_EXTRA_STACK)
        return;
    u32 pmmscan;
    for (pmmscan=0; pmmscan < BUILD_BIOS_SIZE; pmmscan+=16) {
        struct pmmheader *pmm = (void*)pmmscan;
        if (GET_FARVAR(SEG_BIOS, pmm->signature) != PMM_SIGNATURE)
            continue;
        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"
                , entry.seg, entry.offset);
        u16 res1, res2;
        asm volatile(
            "pushl %0\n"
            "pushw $(8|1)\n"            // Permanent low memory request
            "pushl $0xffffffff\n"       // Anonymous handle
            "pushl $" __stringify(CONFIG_VGA_EXTRA_STACK_SIZE/16) "\n"
            "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");
        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;
    }
}


/****************************************************************
 * Timer hook
 ****************************************************************/

struct segoff_s Timer_Hook_Resume VAR16 VISIBLE16;

void VISIBLE16
handle_timer_hook(void)
{
    if (!vga_emulate_text())
        return;
    vgafb_set_swcursor(GET_BDA(timer_counter) % 18 < 9);
}

static void
hook_timer_irq(void)
{
    if (!CONFIG_VGA_EMULATE_TEXT)
        return;
    extern void entry_timer_hook(void);
    extern void entry_timer_hook_extrastack(void);
    struct segoff_s oldirq = GET_IVT(0x08);
    struct segoff_s newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook);
    if (CONFIG_VGA_ALLOCATE_EXTRA_STACK && GET_GLOBAL(ExtraStackSeg))
        newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook_extrastack);
    dprintf(1, "Hooking hardware timer irq (old=%x new=%x)\n"
            , oldirq.segoff, newirq.segoff);
    SET_VGA(Timer_Hook_Resume, oldirq);
    SET_IVT(0x08, newirq);
}


/****************************************************************
 * VGA post
 ****************************************************************/

static void
init_bios_area(void)
{
    // init detected hardware BIOS Area
    // set 80x25 color (not clear from RBIL but usual)
    set_equipment_flags(0x30, 0x20);

    // Set the basic modeset options
    SET_BDA(modeset_ctl, 0x51);

    SET_BDA(dcc_index, CONFIG_VGA_STDVGA_PORTS ? 0x08 : 0xff);
    SET_BDA(video_savetable
            , SEGOFF(get_global_seg(), (u32)&video_save_pointer_table));

    // FIXME
    SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
    SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
}

int VgaBDF VAR16 = -1;
int HaveRunInit VAR16;

void VISIBLE16
vga_post(struct bregs *regs)
{
    serial_debug_preinit();
    dprintf(1, "Start SeaVGABIOS (version %s)\n", VERSION);
    debug_enter(regs, DEBUG_VGA_POST);

    if (CONFIG_VGA_PCI && !GET_GLOBAL(HaveRunInit)) {
        u16 bdf = regs->ax;
        if ((pci_config_readw(bdf, PCI_VENDOR_ID)
             == GET_GLOBAL(rom_pci_data.vendor))
            && (pci_config_readw(bdf, PCI_DEVICE_ID)
                == GET_GLOBAL(rom_pci_data.device)))
            SET_VGA(VgaBDF, bdf);
    }

    int ret = vgahw_setup();
    if (ret) {
        dprintf(1, "Failed to initialize VGA hardware.  Exiting.\n");
        return;
    }

    if (GET_GLOBAL(HaveRunInit))
        return;

    init_bios_area();

    SET_VGA(video_save_pointer_table.videoparam
            , SEGOFF(get_global_seg(), (u32)video_param_table));
    if (CONFIG_VGA_STDVGA_PORTS)
        stdvga_build_video_param();

    extern void entry_10(void);
    SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));

    allocate_extra_stack();

    hook_timer_irq();

    SET_VGA(HaveRunInit, 1);

    // Fixup checksum
    extern u8 _rom_header_size, _rom_header_checksum;
    SET_VGA(_rom_header_checksum, 0);
    u8 sum = -checksum_far(get_global_seg(), 0,
                           GET_GLOBAL(_rom_header_size) * 512);
    SET_VGA(_rom_header_checksum, sum);
}