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

« back to all changes in this revision

Viewing changes to .pc/0036-SeaBIOS-CD-DVD-abbreviations.patch/src/boot.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn, Serge Hallyn, Dustin Kirkland
  • Date: 2011-02-14 14:38:50 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20110214143850-cmzexufi3dlrt7ga
Tags: 0.6.1.2-0ubuntu1
[ Serge Hallyn ]
* upstream merge
  - updated debian/watch
  - remove all patches as they are applied upstream
  - removed debian-changes-0.6.0-0ubuntu2 - I'm not certain about this one,
    so it may re-introduce a regression

[ Dustin Kirkland ]
* debian/rules: fix lintian warnings, install changelog, make binary build
  arch indep
* debian/control: update standards version

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
 
            wait_irq();
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
 
}