~ubuntu-branches/ubuntu/oneiric/seabios/oneiric

« back to all changes in this revision

Viewing changes to .pc/0025-Allow-wait_irq-to-be-called-in-32bit-code.patch/src/boot.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2010-10-22 11:04:31 UTC
  • Revision ID: james.westby@ubuntu.com-20101022110431-fnfj73ra6xkq623n
Tags: 0.6.0-0ubuntu2
Add all patches which were included in qemu-0.13.0-rc2 (per
commit on Jul 13, 2010).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Code to load disk image and start system boot.
 
2
//
 
3
// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
 
4
// Copyright (C) 2002  MandrakeSoft S.A.
 
5
//
 
6
// This file may be distributed under the terms of the GNU LGPLv3 license.
 
7
 
 
8
#include "util.h" // dprintf
 
9
#include "biosvar.h" // GET_EBDA
 
10
#include "config.h" // CONFIG_*
 
11
#include "disk.h" // cdrom_boot
 
12
#include "bregs.h" // struct bregs
 
13
#include "boot.h" // struct ipl_s
 
14
#include "cmos.h" // inb_cmos
 
15
#include "paravirt.h"
 
16
 
 
17
struct ipl_s IPL;
 
18
 
 
19
 
 
20
/****************************************************************
 
21
 * IPL and BCV handlers
 
22
 ****************************************************************/
 
23
 
 
24
void
 
25
boot_setup(void)
 
26
{
 
27
    if (! CONFIG_BOOT)
 
28
        return;
 
29
    dprintf(3, "init boot device ordering\n");
 
30
 
 
31
    memset(&IPL, 0, sizeof(IPL));
 
32
 
 
33
    // Floppy drive
 
34
    struct ipl_entry_s *ie = &IPL.bev[0];
 
35
    ie->type = IPL_TYPE_FLOPPY;
 
36
    ie->description = "Floppy";
 
37
    ie++;
 
38
 
 
39
    // First HDD
 
40
    ie->type = IPL_TYPE_HARDDISK;
 
41
    ie->description = "Hard Disk";
 
42
    ie++;
 
43
 
 
44
    // CDROM
 
45
    if (CONFIG_CDROM_BOOT) {
 
46
        ie->type = IPL_TYPE_CDROM;
 
47
        ie->description = "CD-Rom";
 
48
        ie++;
 
49
    }
 
50
 
 
51
    if (CONFIG_COREBOOT && CONFIG_COREBOOT_FLASH) {
 
52
        ie->type = IPL_TYPE_CBFS;
 
53
        ie->description = "CBFS";
 
54
        ie++;
 
55
    }
 
56
 
 
57
    IPL.bevcount = ie - IPL.bev;
 
58
    SET_EBDA(boot_sequence, 0xffff);
 
59
    if (CONFIG_COREBOOT) {
 
60
        // XXX - hardcode defaults for coreboot.
 
61
        IPL.bootorder = 0x87654231;
 
62
        IPL.checkfloppysig = 1;
 
63
    } else {
 
64
        // On emulators, get boot order from nvram.
 
65
        IPL.bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2)
 
66
                         | ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
 
67
        if (!(inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1))
 
68
            IPL.checkfloppysig = 1;
 
69
    }
 
70
}
 
71
 
 
72
// Add a BEV vector for a given pnp compatible option rom.
 
73
void
 
74
add_bev(u16 seg, u16 bev, u16 desc)
 
75
{
 
76
    if (! CONFIG_BOOT)
 
77
        return;
 
78
    if (IPL.bevcount >= ARRAY_SIZE(IPL.bev))
 
79
        return;
 
80
 
 
81
    struct ipl_entry_s *ie = &IPL.bev[IPL.bevcount++];
 
82
    ie->type = IPL_TYPE_BEV;
 
83
    ie->vector = (seg << 16) | bev;
 
84
    const char *d = "Unknown";
 
85
    if (desc)
 
86
        d = MAKE_FLATPTR(seg, desc);
 
87
    ie->description = d;
 
88
}
 
89
 
 
90
// Add a bcv entry for an expansion card harddrive or legacy option rom
 
91
void
 
92
add_bcv(u16 seg, u16 ip, u16 desc)
 
93
{
 
94
    if (! CONFIG_BOOT)
 
95
        return;
 
96
    if (IPL.bcvcount >= ARRAY_SIZE(IPL.bcv))
 
97
        return;
 
98
 
 
99
    struct ipl_entry_s *ie = &IPL.bcv[IPL.bcvcount++];
 
100
    ie->type = BCV_TYPE_EXTERNAL;
 
101
    ie->vector = (seg << 16) | ip;
 
102
    const char *d = "Legacy option rom";
 
103
    if (desc)
 
104
        d = MAKE_FLATPTR(seg, desc);
 
105
    ie->description = d;
 
106
}
 
107
 
 
108
// Add a bcv entry for an internal harddrive
 
109
void
 
110
add_bcv_internal(struct drive_s *drive_g)
 
111
{
 
112
    if (! CONFIG_BOOT)
 
113
        return;
 
114
    if (IPL.bcvcount >= ARRAY_SIZE(IPL.bcv))
 
115
        return;
 
116
 
 
117
    struct ipl_entry_s *ie = &IPL.bcv[IPL.bcvcount++];
 
118
    if (CONFIG_THREADS) {
 
119
        // Add to bcv list with assured drive order.
 
120
        struct ipl_entry_s *end = ie;
 
121
        for (;;) {
 
122
            struct ipl_entry_s *prev = ie - 1;
 
123
            if (prev < IPL.bcv || prev->type != BCV_TYPE_INTERNAL)
 
124
                break;
 
125
            struct drive_s *prevdrive = (void*)prev->vector;
 
126
            if (prevdrive->type < drive_g->type
 
127
                || (prevdrive->type == drive_g->type
 
128
                    && prevdrive->cntl_id < drive_g->cntl_id))
 
129
                break;
 
130
            ie--;
 
131
        }
 
132
        if (ie != end)
 
133
            memmove(ie+1, ie, (void*)end-(void*)ie);
 
134
    }
 
135
    ie->type = BCV_TYPE_INTERNAL;
 
136
    ie->vector = (u32)drive_g;
 
137
    ie->description = "";
 
138
}
 
139
 
 
140
 
 
141
/****************************************************************
 
142
 * Boot menu and BCV execution
 
143
 ****************************************************************/
 
144
 
 
145
// Show a generic menu item
 
146
static int
 
147
menu_show_default(struct ipl_entry_s *ie, int menupos)
 
148
{
 
149
    char desc[33];
 
150
    printf("%d. %s\n", menupos
 
151
           , strtcpy(desc, ie->description, ARRAY_SIZE(desc)));
 
152
    return 1;
 
153
}
 
154
 
 
155
// Show floppy menu item - but only if there exists a floppy drive.
 
156
static int
 
157
menu_show_floppy(struct ipl_entry_s *ie, int menupos)
 
158
{
 
159
    int i;
 
160
    for (i = 0; i < Drives.floppycount; i++) {
 
161
        struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, i);
 
162
        printf("%d. Floppy [%s]\n", menupos + i, drive_g->desc);
 
163
    }
 
164
    return Drives.floppycount;
 
165
}
 
166
 
 
167
// Show menu items from BCV list.
 
168
static int
 
169
menu_show_harddisk(struct ipl_entry_s *ie, int menupos)
 
170
{
 
171
    int i;
 
172
    for (i = 0; i < IPL.bcvcount; i++) {
 
173
        struct ipl_entry_s *ie = &IPL.bcv[i];
 
174
        struct drive_s *drive_g = (void*)ie->vector;
 
175
        switch (ie->type) {
 
176
        case BCV_TYPE_INTERNAL:
 
177
            printf("%d. %s\n", menupos + i, drive_g->desc);
 
178
            break;
 
179
        default:
 
180
            menu_show_default(ie, menupos+i);
 
181
            break;
 
182
        }
 
183
    }
 
184
    return IPL.bcvcount;
 
185
}
 
186
 
 
187
// Show cdrom menu item - but only if there exists a cdrom drive.
 
188
static int
 
189
menu_show_cdrom(struct ipl_entry_s *ie, int menupos)
 
190
{
 
191
    int i;
 
192
    for (i = 0; i < Drives.cdcount; i++) {
 
193
        struct drive_s *drive_g = getDrive(EXTTYPE_CD, i);
 
194
        printf("%d. CD-Rom [%s]\n", menupos + i, drive_g->desc);
 
195
    }
 
196
    return Drives.cdcount;
 
197
}
 
198
 
 
199
// Show coreboot-fs menu item.
 
200
static int
 
201
menu_show_cbfs(struct ipl_entry_s *ie, int menupos)
 
202
{
 
203
    int count = 0;
 
204
    struct cbfs_file *file = NULL;
 
205
    for (;;) {
 
206
        file = cbfs_findprefix("img/", file);
 
207
        if (!file)
 
208
            break;
 
209
        const char *filename = cbfs_filename(file);
 
210
        printf("%d. Payload [%s]\n", menupos + count, &filename[4]);
 
211
        count++;
 
212
        if (count > 8)
 
213
            break;
 
214
    }
 
215
    return count;
 
216
}
 
217
 
 
218
// Show IPL option menu.
 
219
static void
 
220
interactive_bootmenu(void)
 
221
{
 
222
    if (! CONFIG_BOOTMENU || ! qemu_cfg_show_boot_menu())
 
223
        return;
 
224
 
 
225
    while (get_keystroke(0) >= 0)
 
226
        ;
 
227
 
 
228
    printf("Press F12 for boot menu.\n\n");
 
229
 
 
230
    int scan_code = get_keystroke(CONFIG_BOOTMENU_WAIT);
 
231
    if (scan_code != 0x86)
 
232
        /* not F12 */
 
233
        return;
 
234
 
 
235
    while (get_keystroke(0) >= 0)
 
236
        ;
 
237
 
 
238
    printf("Select boot device:\n\n");
 
239
    wait_threads();
 
240
 
 
241
    int subcount[ARRAY_SIZE(IPL.bev)];
 
242
    int menupos = 1;
 
243
    int i;
 
244
    for (i = 0; i < IPL.bevcount; i++) {
 
245
        struct ipl_entry_s *ie = &IPL.bev[i];
 
246
        int sc;
 
247
        switch (ie->type) {
 
248
        case IPL_TYPE_FLOPPY:
 
249
            sc = menu_show_floppy(ie, menupos);
 
250
            break;
 
251
        case IPL_TYPE_HARDDISK:
 
252
            sc = menu_show_harddisk(ie, menupos);
 
253
            break;
 
254
        case IPL_TYPE_CDROM:
 
255
            sc = menu_show_cdrom(ie, menupos);
 
256
            break;
 
257
        case IPL_TYPE_CBFS:
 
258
            sc = menu_show_cbfs(ie, menupos);
 
259
            break;
 
260
        default:
 
261
            sc = menu_show_default(ie, menupos);
 
262
            break;
 
263
        }
 
264
        subcount[i] = sc;
 
265
        menupos += sc;
 
266
    }
 
267
 
 
268
    for (;;) {
 
269
        scan_code = get_keystroke(1000);
 
270
        if (scan_code == 0x01)
 
271
            // ESC
 
272
            break;
 
273
        if (scan_code < 1 || scan_code > menupos)
 
274
            continue;
 
275
        int choice = scan_code - 1;
 
276
 
 
277
        // Find out which IPL this was for.
 
278
        int bev = 0;
 
279
        while (choice > subcount[bev]) {
 
280
            choice -= subcount[bev];
 
281
            bev++;
 
282
        }
 
283
        IPL.bev[bev].subchoice = choice-1;
 
284
 
 
285
        // Add user choice to the boot order.
 
286
        IPL.bootorder = (IPL.bootorder << 4) | (bev+1);
 
287
        break;
 
288
    }
 
289
    printf("\n");
 
290
}
 
291
 
 
292
// Run the specified bcv.
 
293
static void
 
294
run_bcv(struct ipl_entry_s *ie)
 
295
{
 
296
    switch (ie->type) {
 
297
    case BCV_TYPE_INTERNAL:
 
298
        map_hd_drive((void*)ie->vector);
 
299
        break;
 
300
    case BCV_TYPE_EXTERNAL:
 
301
        call_bcv(ie->vector >> 16, ie->vector & 0xffff);
 
302
        break;
 
303
    }
 
304
}
 
305
 
 
306
// Prepare for boot - show menu and run bcvs.
 
307
void
 
308
boot_prep(void)
 
309
{
 
310
    if (! CONFIG_BOOT) {
 
311
        wait_threads();
 
312
        return;
 
313
    }
 
314
 
 
315
    // XXX - show available drives?
 
316
 
 
317
    // Allow user to modify BCV/IPL order.
 
318
    interactive_bootmenu();
 
319
    wait_threads();
 
320
 
 
321
    // Setup floppy boot order
 
322
    int override = IPL.bev[0].subchoice;
 
323
    struct drive_s *tmp = Drives.idmap[EXTTYPE_FLOPPY][0];
 
324
    Drives.idmap[EXTTYPE_FLOPPY][0] = Drives.idmap[EXTTYPE_FLOPPY][override];
 
325
    Drives.idmap[EXTTYPE_FLOPPY][override] = tmp;
 
326
 
 
327
    // Run BCVs
 
328
    override = IPL.bev[1].subchoice;
 
329
    if (override < IPL.bcvcount)
 
330
        run_bcv(&IPL.bcv[override]);
 
331
    int i;
 
332
    for (i=0; i<IPL.bcvcount; i++)
 
333
        if (i != override)
 
334
            run_bcv(&IPL.bcv[i]);
 
335
}
 
336
 
 
337
 
 
338
/****************************************************************
 
339
 * Boot code (int 18/19)
 
340
 ****************************************************************/
 
341
 
 
342
// Jump to a bootup entry point.
 
343
static void
 
344
call_boot_entry(u16 bootseg, u16 bootip, u8 bootdrv)
 
345
{
 
346
    dprintf(1, "Booting from %04x:%04x\n", bootseg, bootip);
 
347
 
 
348
    struct bregs br;
 
349
    memset(&br, 0, sizeof(br));
 
350
    br.flags = F_IF;
 
351
    br.code = SEGOFF(bootseg, bootip);
 
352
    // Set the magic number in ax and the boot drive in dl.
 
353
    br.dl = bootdrv;
 
354
    br.ax = 0xaa55;
 
355
    call16(&br);
 
356
}
 
357
 
 
358
// Boot from a disk (either floppy or harddrive)
 
359
static void
 
360
boot_disk(u8 bootdrv, int checksig)
 
361
{
 
362
    u16 bootseg = 0x07c0;
 
363
 
 
364
    // Read sector
 
365
    struct bregs br;
 
366
    memset(&br, 0, sizeof(br));
 
367
    br.flags = F_IF;
 
368
    br.dl = bootdrv;
 
369
    br.es = bootseg;
 
370
    br.ah = 2;
 
371
    br.al = 1;
 
372
    br.cl = 1;
 
373
    call16_int(0x13, &br);
 
374
 
 
375
    if (br.flags & F_CF) {
 
376
        printf("Boot failed: could not read the boot disk\n\n");
 
377
        return;
 
378
    }
 
379
 
 
380
    if (checksig) {
 
381
        struct mbr_s *mbr = (void*)0;
 
382
        if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
 
383
            printf("Boot failed: not a bootable disk\n\n");
 
384
            return;
 
385
        }
 
386
    }
 
387
 
 
388
    /* Canonicalize bootseg:bootip */
 
389
    u16 bootip = (bootseg & 0x0fff) << 4;
 
390
    bootseg &= 0xf000;
 
391
 
 
392
    call_boot_entry(bootseg, bootip, bootdrv);
 
393
}
 
394
 
 
395
// Boot from a CD-ROM
 
396
static void
 
397
boot_cdrom(struct ipl_entry_s *ie)
 
398
{
 
399
    if (! CONFIG_CDROM_BOOT)
 
400
        return;
 
401
    int status = cdrom_boot(ie->subchoice);
 
402
    if (status) {
 
403
        printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
 
404
        return;
 
405
    }
 
406
 
 
407
    u16 ebda_seg = get_ebda_seg();
 
408
    u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
 
409
    u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
 
410
    /* Canonicalize bootseg:bootip */
 
411
    u16 bootip = (bootseg & 0x0fff) << 4;
 
412
    bootseg &= 0xf000;
 
413
 
 
414
    call_boot_entry(bootseg, bootip, bootdrv);
 
415
}
 
416
 
 
417
// Boot from a CBFS payload
 
418
static void
 
419
boot_cbfs(struct ipl_entry_s *ie)
 
420
{
 
421
    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
 
422
        return;
 
423
    int count = ie->subchoice;
 
424
    struct cbfs_file *file = NULL;
 
425
    for (;;) {
 
426
        file = cbfs_findprefix("img/", file);
 
427
        if (!file)
 
428
            return;
 
429
        if (count--)
 
430
            continue;
 
431
        cbfs_run_payload(file);
 
432
    }
 
433
}
 
434
 
 
435
static void
 
436
do_boot(u16 seq_nr)
 
437
{
 
438
    if (! CONFIG_BOOT)
 
439
        panic("Boot support not compiled in.\n");
 
440
 
 
441
    u32 bootdev = IPL.bootorder;
 
442
    bootdev >>= 4 * seq_nr;
 
443
    bootdev &= 0xf;
 
444
 
 
445
    /* Translate bootdev to an IPL table offset by subtracting 1 */
 
446
    bootdev -= 1;
 
447
 
 
448
    if (bootdev >= IPL.bevcount) {
 
449
        printf("No bootable device.\n");
 
450
        // Loop with irqs enabled - this allows ctrl+alt+delete to work.
 
451
        for (;;)
 
452
            biosusleep(1000000);
 
453
    }
 
454
 
 
455
    /* Do the loading, and set up vector as a far pointer to the boot
 
456
     * address, and bootdrv as the boot drive */
 
457
    struct ipl_entry_s *ie = &IPL.bev[bootdev];
 
458
    char desc[33];
 
459
    printf("Booting from %s...\n"
 
460
           , strtcpy(desc, ie->description, ARRAY_SIZE(desc)));
 
461
 
 
462
    switch(ie->type) {
 
463
    case IPL_TYPE_FLOPPY:
 
464
        boot_disk(0x00, IPL.checkfloppysig);
 
465
        break;
 
466
    case IPL_TYPE_HARDDISK:
 
467
        boot_disk(0x80, 1);
 
468
        break;
 
469
    case IPL_TYPE_CDROM:
 
470
        boot_cdrom(ie);
 
471
        break;
 
472
    case IPL_TYPE_CBFS:
 
473
        boot_cbfs(ie);
 
474
        break;
 
475
    case IPL_TYPE_BEV:
 
476
        call_boot_entry(ie->vector >> 16, ie->vector & 0xffff, 0);
 
477
        break;
 
478
    }
 
479
 
 
480
    // Boot failed: invoke the boot recovery function
 
481
    struct bregs br;
 
482
    memset(&br, 0, sizeof(br));
 
483
    br.flags = F_IF;
 
484
    call16_int(0x18, &br);
 
485
}
 
486
 
 
487
// Boot Failure recovery: try the next device.
 
488
void VISIBLE32FLAT
 
489
handle_18(void)
 
490
{
 
491
    debug_serial_setup();
 
492
    debug_enter(NULL, DEBUG_HDL_18);
 
493
    u16 ebda_seg = get_ebda_seg();
 
494
    u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
 
495
    SET_EBDA2(ebda_seg, boot_sequence, seq);
 
496
    do_boot(seq);
 
497
}
 
498
 
 
499
// INT 19h Boot Load Service Entry Point
 
500
void VISIBLE32FLAT
 
501
handle_19(void)
 
502
{
 
503
    debug_serial_setup();
 
504
    debug_enter(NULL, DEBUG_HDL_19);
 
505
    SET_EBDA(boot_sequence, 0);
 
506
    do_boot(0);
 
507
}