~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/seabios/src/boot.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

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-2013  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 "block.h" // struct drive_s
 
9
#include "bregs.h" // struct bregs
 
10
#include "config.h" // CONFIG_*
 
11
#include "fw/paravirt.h" // qemu_cfg_show_boot_menu
 
12
#include "hw/pci.h" // pci_bdf_to_*
 
13
#include "hw/pcidevice.h" // struct pci_device
 
14
#include "hw/rtc.h" // rtc_read
 
15
#include "hw/usb.h" // struct usbdevice_s
 
16
#include "list.h" // hlist_node
 
17
#include "malloc.h" // free
 
18
#include "output.h" // dprintf
 
19
#include "romfile.h" // romfile_loadint
 
20
#include "std/disk.h" // struct mbr_s
 
21
#include "string.h" // memset
 
22
#include "util.h" // irqtimer_calc
 
23
#include "tcgbios.h" // tpm_*
 
24
 
 
25
 
 
26
/****************************************************************
 
27
 * Boot priority ordering
 
28
 ****************************************************************/
 
29
 
 
30
static char **Bootorder VARVERIFY32INIT;
 
31
static int BootorderCount;
 
32
 
 
33
static void
 
34
loadBootOrder(void)
 
35
{
 
36
    if (!CONFIG_BOOTORDER)
 
37
        return;
 
38
 
 
39
    char *f = romfile_loadfile("bootorder", NULL);
 
40
    if (!f)
 
41
        return;
 
42
 
 
43
    int i = 0;
 
44
    BootorderCount = 1;
 
45
    while (f[i]) {
 
46
        if (f[i] == '\n')
 
47
            BootorderCount++;
 
48
        i++;
 
49
    }
 
50
    Bootorder = malloc_tmphigh(BootorderCount*sizeof(char*));
 
51
    if (!Bootorder) {
 
52
        warn_noalloc();
 
53
        free(f);
 
54
        BootorderCount = 0;
 
55
        return;
 
56
    }
 
57
 
 
58
    dprintf(1, "boot order:\n");
 
59
    i = 0;
 
60
    do {
 
61
        Bootorder[i] = f;
 
62
        f = strchr(f, '\n');
 
63
        if (f)
 
64
            *(f++) = '\0';
 
65
        Bootorder[i] = nullTrailingSpace(Bootorder[i]);
 
66
        dprintf(1, "%d: %s\n", i+1, Bootorder[i]);
 
67
        i++;
 
68
    } while (f);
 
69
}
 
70
 
 
71
// See if 'str' starts with 'glob' - if glob contains an '*' character
 
72
// it will match any number of characters in str that aren't a '/' or
 
73
// the next glob character.
 
74
static char *
 
75
glob_prefix(const char *glob, const char *str)
 
76
{
 
77
    for (;;) {
 
78
        if (!*glob && (!*str || *str == '/'))
 
79
            return (char*)str;
 
80
        if (*glob == '*') {
 
81
            if (!*str || *str == '/' || *str == glob[1])
 
82
                glob++;
 
83
            else
 
84
                str++;
 
85
            continue;
 
86
        }
 
87
        if (*glob != *str)
 
88
            return NULL;
 
89
        glob++;
 
90
        str++;
 
91
    }
 
92
}
 
93
 
 
94
// Search the bootorder list for the given glob pattern.
 
95
static int
 
96
find_prio(const char *glob)
 
97
{
 
98
    dprintf(1, "Searching bootorder for: %s\n", glob);
 
99
    int i;
 
100
    for (i = 0; i < BootorderCount; i++)
 
101
        if (glob_prefix(glob, Bootorder[i]))
 
102
            return i+1;
 
103
    return -1;
 
104
}
 
105
 
 
106
#define FW_PCI_DOMAIN "/pci@i0cf8"
 
107
 
 
108
static char *
 
109
build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci)
 
110
{
 
111
    // Build the string path of a bdf - for example: /pci@i0cf8/isa@1,2
 
112
    char *p = buf;
 
113
    if (pci->parent) {
 
114
        p = build_pci_path(p, max, "pci-bridge", pci->parent);
 
115
    } else {
 
116
        p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN);
 
117
        if (pci->rootbus)
 
118
            p += snprintf(p, buf+max-p, ",%x", pci->rootbus);
 
119
    }
 
120
 
 
121
    int dev = pci_bdf_to_dev(pci->bdf), fn = pci_bdf_to_fn(pci->bdf);
 
122
    p += snprintf(p, buf+max-p, "/%s@%x", devname, dev);
 
123
    if (fn)
 
124
        p += snprintf(p, buf+max-p, ",%x", fn);
 
125
    return p;
 
126
}
 
127
 
 
128
int bootprio_find_pci_device(struct pci_device *pci)
 
129
{
 
130
    if (CONFIG_CSM)
 
131
        return csm_bootprio_pci(pci);
 
132
    if (!CONFIG_BOOTORDER)
 
133
        return -1;
 
134
    // Find pci device - for example: /pci@i0cf8/ethernet@5
 
135
    char desc[256];
 
136
    build_pci_path(desc, sizeof(desc), "*", pci);
 
137
    return find_prio(desc);
 
138
}
 
139
 
 
140
int bootprio_find_scsi_device(struct pci_device *pci, int target, int lun)
 
141
{
 
142
    if (!CONFIG_BOOTORDER)
 
143
        return -1;
 
144
    if (!pci)
 
145
        // support only pci machine for now
 
146
        return -1;
 
147
    // Find scsi drive - for example: /pci@i0cf8/scsi@5/channel@0/disk@1,0
 
148
    char desc[256], *p;
 
149
    p = build_pci_path(desc, sizeof(desc), "*", pci);
 
150
    snprintf(p, desc+sizeof(desc)-p, "/*@0/*@%x,%x", target, lun);
 
151
    return find_prio(desc);
 
152
}
 
153
 
 
154
int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave)
 
155
{
 
156
    if (CONFIG_CSM)
 
157
        return csm_bootprio_ata(pci, chanid, slave);
 
158
    if (!CONFIG_BOOTORDER)
 
159
        return -1;
 
160
    if (!pci)
 
161
        // support only pci machine for now
 
162
        return -1;
 
163
    // Find ata drive - for example: /pci@i0cf8/ide@1,1/drive@1/disk@0
 
164
    char desc[256], *p;
 
165
    p = build_pci_path(desc, sizeof(desc), "*", pci);
 
166
    snprintf(p, desc+sizeof(desc)-p, "/drive@%x/disk@%x", chanid, slave);
 
167
    return find_prio(desc);
 
168
}
 
169
 
 
170
int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid)
 
171
{
 
172
    if (CONFIG_CSM)
 
173
        return csm_bootprio_fdc(pci, port, fdid);
 
174
    if (!CONFIG_BOOTORDER)
 
175
        return -1;
 
176
    if (!pci)
 
177
        // support only pci machine for now
 
178
        return -1;
 
179
    // Find floppy - for example: /pci@i0cf8/isa@1/fdc@03f1/floppy@0
 
180
    char desc[256], *p;
 
181
    p = build_pci_path(desc, sizeof(desc), "isa", pci);
 
182
    snprintf(p, desc+sizeof(desc)-p, "/fdc@%04x/floppy@%x", port, fdid);
 
183
    return find_prio(desc);
 
184
}
 
185
 
 
186
int bootprio_find_pci_rom(struct pci_device *pci, int instance)
 
187
{
 
188
    if (!CONFIG_BOOTORDER)
 
189
        return -1;
 
190
    // Find pci rom - for example: /pci@i0cf8/scsi@3:rom2
 
191
    char desc[256], *p;
 
192
    p = build_pci_path(desc, sizeof(desc), "*", pci);
 
193
    if (instance)
 
194
        snprintf(p, desc+sizeof(desc)-p, ":rom%x", instance);
 
195
    return find_prio(desc);
 
196
}
 
197
 
 
198
int bootprio_find_named_rom(const char *name, int instance)
 
199
{
 
200
    if (!CONFIG_BOOTORDER)
 
201
        return -1;
 
202
    // Find named rom - for example: /rom@genroms/linuxboot.bin
 
203
    char desc[256], *p;
 
204
    p = desc + snprintf(desc, sizeof(desc), "/rom@%s", name);
 
205
    if (instance)
 
206
        snprintf(p, desc+sizeof(desc)-p, ":rom%x", instance);
 
207
    return find_prio(desc);
 
208
}
 
209
 
 
210
static char *
 
211
build_usb_path(char *buf, int max, struct usbhub_s *hub)
 
212
{
 
213
    if (!hub->usbdev)
 
214
        // Root hub - nothing to add.
 
215
        return buf;
 
216
    char *p = build_usb_path(buf, max, hub->usbdev->hub);
 
217
    p += snprintf(p, buf+max-p, "/hub@%x", hub->usbdev->port+1);
 
218
    return p;
 
219
}
 
220
 
 
221
int bootprio_find_usb(struct usbdevice_s *usbdev, int lun)
 
222
{
 
223
    if (!CONFIG_BOOTORDER)
 
224
        return -1;
 
225
    // Find usb - for example: /pci@i0cf8/usb@1,2/storage@1/channel@0/disk@0,0
 
226
    char desc[256], *p;
 
227
    p = build_pci_path(desc, sizeof(desc), "usb", usbdev->hub->cntl->pci);
 
228
    p = build_usb_path(p, desc+sizeof(desc)-p, usbdev->hub);
 
229
    snprintf(p, desc+sizeof(desc)-p, "/storage@%x/*@0/*@0,%x"
 
230
             , usbdev->port+1, lun);
 
231
    int ret = find_prio(desc);
 
232
    if (ret >= 0)
 
233
        return ret;
 
234
    // Try usb-host/redir - for example: /pci@i0cf8/usb@1,2/usb-host@1
 
235
    snprintf(p, desc+sizeof(desc)-p, "/usb-*@%x", usbdev->port+1);
 
236
    return find_prio(desc);
 
237
}
 
238
 
 
239
 
 
240
/****************************************************************
 
241
 * Boot setup
 
242
 ****************************************************************/
 
243
 
 
244
static int BootRetryTime;
 
245
static int CheckFloppySig = 1;
 
246
 
 
247
#define DEFAULT_PRIO           9999
 
248
 
 
249
static int DefaultFloppyPrio = 101;
 
250
static int DefaultCDPrio     = 102;
 
251
static int DefaultHDPrio     = 103;
 
252
static int DefaultBEVPrio    = 104;
 
253
 
 
254
void
 
255
boot_init(void)
 
256
{
 
257
    if (! CONFIG_BOOT)
 
258
        return;
 
259
 
 
260
    if (CONFIG_QEMU) {
 
261
        // On emulators, get boot order from nvram.
 
262
        if (rtc_read(CMOS_BIOS_BOOTFLAG1) & 1)
 
263
            CheckFloppySig = 0;
 
264
        u32 bootorder = (rtc_read(CMOS_BIOS_BOOTFLAG2)
 
265
                         | ((rtc_read(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
 
266
        DefaultFloppyPrio = DefaultCDPrio = DefaultHDPrio
 
267
            = DefaultBEVPrio = DEFAULT_PRIO;
 
268
        int i;
 
269
        for (i=101; i<104; i++) {
 
270
            u32 val = bootorder & 0x0f;
 
271
            bootorder >>= 4;
 
272
            switch (val) {
 
273
            case 1: DefaultFloppyPrio = i; break;
 
274
            case 2: DefaultHDPrio = i;     break;
 
275
            case 3: DefaultCDPrio = i;     break;
 
276
            case 4: DefaultBEVPrio = i;    break;
 
277
            }
 
278
        }
 
279
    }
 
280
 
 
281
    BootRetryTime = romfile_loadint("etc/boot-fail-wait", 60*1000);
 
282
 
 
283
    loadBootOrder();
 
284
}
 
285
 
 
286
 
 
287
/****************************************************************
 
288
 * BootList handling
 
289
 ****************************************************************/
 
290
 
 
291
struct bootentry_s {
 
292
    int type;
 
293
    union {
 
294
        u32 data;
 
295
        struct segoff_s vector;
 
296
        struct drive_s *drive;
 
297
    };
 
298
    int priority;
 
299
    const char *description;
 
300
    struct hlist_node node;
 
301
};
 
302
static struct hlist_head BootList VARVERIFY32INIT;
 
303
 
 
304
#define IPL_TYPE_FLOPPY      0x01
 
305
#define IPL_TYPE_HARDDISK    0x02
 
306
#define IPL_TYPE_CDROM       0x03
 
307
#define IPL_TYPE_CBFS        0x20
 
308
#define IPL_TYPE_BEV         0x80
 
309
#define IPL_TYPE_BCV         0x81
 
310
#define IPL_TYPE_HALT        0xf0
 
311
 
 
312
static void
 
313
bootentry_add(int type, int prio, u32 data, const char *desc)
 
314
{
 
315
    if (! CONFIG_BOOT)
 
316
        return;
 
317
    struct bootentry_s *be = malloc_tmp(sizeof(*be));
 
318
    if (!be) {
 
319
        warn_noalloc();
 
320
        return;
 
321
    }
 
322
    be->type = type;
 
323
    be->priority = prio;
 
324
    be->data = data;
 
325
    be->description = desc ?: "?";
 
326
    dprintf(3, "Registering bootable: %s (type:%d prio:%d data:%x)\n"
 
327
            , be->description, type, prio, data);
 
328
 
 
329
    // Add entry in sorted order.
 
330
    struct hlist_node **pprev;
 
331
    struct bootentry_s *pos;
 
332
    hlist_for_each_entry_pprev(pos, pprev, &BootList, node) {
 
333
        if (be->priority < pos->priority)
 
334
            break;
 
335
        if (be->priority > pos->priority)
 
336
            continue;
 
337
        if (be->type < pos->type)
 
338
            break;
 
339
        if (be->type > pos->type)
 
340
            continue;
 
341
        if (be->type <= IPL_TYPE_CDROM
 
342
            && (be->drive->type < pos->drive->type
 
343
                || (be->drive->type == pos->drive->type
 
344
                    && be->drive->cntl_id < pos->drive->cntl_id)))
 
345
            break;
 
346
    }
 
347
    hlist_add(&be->node, pprev);
 
348
}
 
349
 
 
350
// Return the given priority if it's set - defaultprio otherwise.
 
351
static inline int defPrio(int priority, int defaultprio) {
 
352
    return (priority < 0) ? defaultprio : priority;
 
353
}
 
354
 
 
355
// Add a BEV vector for a given pnp compatible option rom.
 
356
void
 
357
boot_add_bev(u16 seg, u16 bev, u16 desc, int prio)
 
358
{
 
359
    bootentry_add(IPL_TYPE_BEV, defPrio(prio, DefaultBEVPrio)
 
360
                  , SEGOFF(seg, bev).segoff
 
361
                  , desc ? MAKE_FLATPTR(seg, desc) : "Unknown");
 
362
    DefaultBEVPrio = DEFAULT_PRIO;
 
363
}
 
364
 
 
365
// Add a bcv entry for an expansion card harddrive or legacy option rom
 
366
void
 
367
boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio)
 
368
{
 
369
    bootentry_add(IPL_TYPE_BCV, defPrio(prio, DefaultHDPrio)
 
370
                  , SEGOFF(seg, ip).segoff
 
371
                  , desc ? MAKE_FLATPTR(seg, desc) : "Legacy option rom");
 
372
}
 
373
 
 
374
void
 
375
boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio)
 
376
{
 
377
    bootentry_add(IPL_TYPE_FLOPPY, defPrio(prio, DefaultFloppyPrio)
 
378
                  , (u32)drive_g, desc);
 
379
}
 
380
 
 
381
void
 
382
boot_add_hd(struct drive_s *drive_g, const char *desc, int prio)
 
383
{
 
384
    bootentry_add(IPL_TYPE_HARDDISK, defPrio(prio, DefaultHDPrio)
 
385
                  , (u32)drive_g, desc);
 
386
}
 
387
 
 
388
void
 
389
boot_add_cd(struct drive_s *drive_g, const char *desc, int prio)
 
390
{
 
391
    bootentry_add(IPL_TYPE_CDROM, defPrio(prio, DefaultCDPrio)
 
392
                  , (u32)drive_g, desc);
 
393
}
 
394
 
 
395
// Add a CBFS payload entry
 
396
void
 
397
boot_add_cbfs(void *data, const char *desc, int prio)
 
398
{
 
399
    bootentry_add(IPL_TYPE_CBFS, defPrio(prio, DEFAULT_PRIO), (u32)data, desc);
 
400
}
 
401
 
 
402
 
 
403
/****************************************************************
 
404
 * Keyboard calls
 
405
 ****************************************************************/
 
406
 
 
407
// See if a keystroke is pending in the keyboard buffer.
 
408
static int
 
409
check_for_keystroke(void)
 
410
{
 
411
    struct bregs br;
 
412
    memset(&br, 0, sizeof(br));
 
413
    br.flags = F_IF|F_ZF;
 
414
    br.ah = 1;
 
415
    call16_int(0x16, &br);
 
416
    return !(br.flags & F_ZF);
 
417
}
 
418
 
 
419
// Return a keystroke - waiting forever if necessary.
 
420
static int
 
421
get_raw_keystroke(void)
 
422
{
 
423
    struct bregs br;
 
424
    memset(&br, 0, sizeof(br));
 
425
    br.flags = F_IF;
 
426
    call16_int(0x16, &br);
 
427
    return br.ah;
 
428
}
 
429
 
 
430
// Read a keystroke - waiting up to 'msec' milliseconds.
 
431
int
 
432
get_keystroke(int msec)
 
433
{
 
434
    u32 end = irqtimer_calc(msec);
 
435
    for (;;) {
 
436
        if (check_for_keystroke())
 
437
            return get_raw_keystroke();
 
438
        if (irqtimer_check(end))
 
439
            return -1;
 
440
        yield_toirq();
 
441
    }
 
442
}
 
443
 
 
444
 
 
445
/****************************************************************
 
446
 * Boot menu and BCV execution
 
447
 ****************************************************************/
 
448
 
 
449
#define DEFAULT_BOOTMENU_WAIT 2500
 
450
 
 
451
// Show IPL option menu.
 
452
void
 
453
interactive_bootmenu(void)
 
454
{
 
455
    // XXX - show available drives?
 
456
 
 
457
    if (! CONFIG_BOOTMENU || !romfile_loadint("etc/show-boot-menu", 1))
 
458
        return;
 
459
 
 
460
    while (get_keystroke(0) >= 0)
 
461
        ;
 
462
 
 
463
    char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL);
 
464
    int menukey = romfile_loadint("etc/boot-menu-key", 1);
 
465
    printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n\n");
 
466
    free(bootmsg);
 
467
 
 
468
    u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT);
 
469
    enable_bootsplash();
 
470
    int scan_code = get_keystroke(menutime);
 
471
    disable_bootsplash();
 
472
    if (scan_code != menukey)
 
473
        return;
 
474
 
 
475
    while (get_keystroke(0) >= 0)
 
476
        ;
 
477
 
 
478
    printf("Select boot device:\n\n");
 
479
    wait_threads();
 
480
 
 
481
    // Show menu items
 
482
    int maxmenu = 0;
 
483
    struct bootentry_s *pos;
 
484
    hlist_for_each_entry(pos, &BootList, node) {
 
485
        char desc[60];
 
486
        maxmenu++;
 
487
        printf("%d. %s\n", maxmenu
 
488
               , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
 
489
    }
 
490
    if (tpm_can_show_menu()) {
 
491
        printf("\nt. TPM Configuration\n");
 
492
    }
 
493
 
 
494
    // Get key press.  If the menu key is ESC, do not restart boot unless
 
495
    // 1.5 seconds have passed.  Otherwise users (trained by years of
 
496
    // repeatedly hitting keys to enter the BIOS) will end up hitting ESC
 
497
    // multiple times and immediately booting the primary boot device.
 
498
    int esc_accepted_time = irqtimer_calc(menukey == 1 ? 1500 : 0);
 
499
    for (;;) {
 
500
        scan_code = get_keystroke(1000);
 
501
        if (scan_code == 1 && !irqtimer_check(esc_accepted_time))
 
502
            continue;
 
503
        if (tpm_can_show_menu() && scan_code == 20 /* t */) {
 
504
            printf("\n");
 
505
            tpm_menu();
 
506
        }
 
507
        if (scan_code >= 1 && scan_code <= maxmenu+1)
 
508
            break;
 
509
    }
 
510
    printf("\n");
 
511
    if (scan_code == 0x01)
 
512
        // ESC
 
513
        return;
 
514
 
 
515
    // Find entry and make top priority.
 
516
    int choice = scan_code - 1;
 
517
    hlist_for_each_entry(pos, &BootList, node) {
 
518
        if (! --choice)
 
519
            break;
 
520
    }
 
521
    hlist_del(&pos->node);
 
522
    pos->priority = 0;
 
523
    hlist_add_head(&pos->node, &BootList);
 
524
}
 
525
 
 
526
// BEV (Boot Execution Vector) list
 
527
struct bev_s {
 
528
    int type;
 
529
    u32 vector;
 
530
};
 
531
static struct bev_s BEV[20];
 
532
static int BEVCount;
 
533
static int HaveHDBoot, HaveFDBoot;
 
534
 
 
535
static void
 
536
add_bev(int type, u32 vector)
 
537
{
 
538
    if (type == IPL_TYPE_HARDDISK && HaveHDBoot++)
 
539
        return;
 
540
    if (type == IPL_TYPE_FLOPPY && HaveFDBoot++)
 
541
        return;
 
542
    if (BEVCount >= ARRAY_SIZE(BEV))
 
543
        return;
 
544
    struct bev_s *bev = &BEV[BEVCount++];
 
545
    bev->type = type;
 
546
    bev->vector = vector;
 
547
}
 
548
 
 
549
// Prepare for boot - show menu and run bcvs.
 
550
void
 
551
bcv_prepboot(void)
 
552
{
 
553
    if (! CONFIG_BOOT)
 
554
        return;
 
555
 
 
556
    int haltprio = find_prio("HALT");
 
557
    if (haltprio >= 0)
 
558
        bootentry_add(IPL_TYPE_HALT, haltprio, 0, "HALT");
 
559
 
 
560
    // Map drives and populate BEV list
 
561
    struct bootentry_s *pos;
 
562
    hlist_for_each_entry(pos, &BootList, node) {
 
563
        switch (pos->type) {
 
564
        case IPL_TYPE_BCV:
 
565
            call_bcv(pos->vector.seg, pos->vector.offset);
 
566
            add_bev(IPL_TYPE_HARDDISK, 0);
 
567
            break;
 
568
        case IPL_TYPE_FLOPPY:
 
569
            map_floppy_drive(pos->drive);
 
570
            add_bev(IPL_TYPE_FLOPPY, 0);
 
571
            break;
 
572
        case IPL_TYPE_HARDDISK:
 
573
            map_hd_drive(pos->drive);
 
574
            add_bev(IPL_TYPE_HARDDISK, 0);
 
575
            break;
 
576
        case IPL_TYPE_CDROM:
 
577
            map_cd_drive(pos->drive);
 
578
            // NO BREAK
 
579
        default:
 
580
            add_bev(pos->type, pos->data);
 
581
            break;
 
582
        }
 
583
    }
 
584
 
 
585
    // If nothing added a floppy/hd boot - add it manually.
 
586
    add_bev(IPL_TYPE_FLOPPY, 0);
 
587
    add_bev(IPL_TYPE_HARDDISK, 0);
 
588
}
 
589
 
 
590
 
 
591
/****************************************************************
 
592
 * Boot code (int 18/19)
 
593
 ****************************************************************/
 
594
 
 
595
// Jump to a bootup entry point.
 
596
static void
 
597
call_boot_entry(struct segoff_s bootsegip, u8 bootdrv)
 
598
{
 
599
    dprintf(1, "Booting from %04x:%04x\n", bootsegip.seg, bootsegip.offset);
 
600
    struct bregs br;
 
601
    memset(&br, 0, sizeof(br));
 
602
    br.flags = F_IF;
 
603
    br.code = bootsegip;
 
604
    // Set the magic number in ax and the boot drive in dl.
 
605
    br.dl = bootdrv;
 
606
    br.ax = 0xaa55;
 
607
    farcall16(&br);
 
608
}
 
609
 
 
610
// Boot from a disk (either floppy or harddrive)
 
611
static void
 
612
boot_disk(u8 bootdrv, int checksig)
 
613
{
 
614
    u16 bootseg = 0x07c0;
 
615
 
 
616
    // Read sector
 
617
    struct bregs br;
 
618
    memset(&br, 0, sizeof(br));
 
619
    br.flags = F_IF;
 
620
    br.dl = bootdrv;
 
621
    br.es = bootseg;
 
622
    br.ah = 2;
 
623
    br.al = 1;
 
624
    br.cl = 1;
 
625
    call16_int(0x13, &br);
 
626
 
 
627
    if (br.flags & F_CF) {
 
628
        printf("Boot failed: could not read the boot disk\n\n");
 
629
        return;
 
630
    }
 
631
 
 
632
    if (checksig) {
 
633
        struct mbr_s *mbr = (void*)0;
 
634
        if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
 
635
            printf("Boot failed: not a bootable disk\n\n");
 
636
            return;
 
637
        }
 
638
    }
 
639
 
 
640
    tpm_add_bcv(bootdrv, MAKE_FLATPTR(bootseg, 0), 512);
 
641
 
 
642
    /* Canonicalize bootseg:bootip */
 
643
    u16 bootip = (bootseg & 0x0fff) << 4;
 
644
    bootseg &= 0xf000;
 
645
 
 
646
    call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
 
647
}
 
648
 
 
649
// Boot from a CD-ROM
 
650
static void
 
651
boot_cdrom(struct drive_s *drive_g)
 
652
{
 
653
    if (! CONFIG_CDROM_BOOT)
 
654
        return;
 
655
    printf("Booting from DVD/CD...\n");
 
656
 
 
657
    int status = cdrom_boot(drive_g);
 
658
    if (status) {
 
659
        printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
 
660
        return;
 
661
    }
 
662
 
 
663
    u8 bootdrv = CDEmu.emulated_drive;
 
664
    u16 bootseg = CDEmu.load_segment;
 
665
 
 
666
    tpm_add_cdrom(bootdrv, MAKE_FLATPTR(bootseg, 0), 512);
 
667
 
 
668
    /* Canonicalize bootseg:bootip */
 
669
    u16 bootip = (bootseg & 0x0fff) << 4;
 
670
    bootseg &= 0xf000;
 
671
 
 
672
    call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
 
673
}
 
674
 
 
675
// Boot from a CBFS payload
 
676
static void
 
677
boot_cbfs(struct cbfs_file *file)
 
678
{
 
679
    if (!CONFIG_COREBOOT_FLASH)
 
680
        return;
 
681
    printf("Booting from CBFS...\n");
 
682
    cbfs_run_payload(file);
 
683
}
 
684
 
 
685
// Boot from a BEV entry on an optionrom.
 
686
static void
 
687
boot_rom(u32 vector)
 
688
{
 
689
    printf("Booting from ROM...\n");
 
690
    struct segoff_s so;
 
691
    so.segoff = vector;
 
692
    call_boot_entry(so, 0);
 
693
}
 
694
 
 
695
// Unable to find bootable device - warn user and eventually retry.
 
696
static void
 
697
boot_fail(void)
 
698
{
 
699
    if (BootRetryTime == (u32)-1)
 
700
        printf("No bootable device.\n");
 
701
    else
 
702
        printf("No bootable device.  Retrying in %d seconds.\n"
 
703
               , BootRetryTime/1000);
 
704
    // Wait for 'BootRetryTime' milliseconds and then reboot.
 
705
    u32 end = irqtimer_calc(BootRetryTime);
 
706
    for (;;) {
 
707
        if (BootRetryTime != (u32)-1 && irqtimer_check(end))
 
708
            break;
 
709
        yield_toirq();
 
710
    }
 
711
    printf("Rebooting.\n");
 
712
    reset();
 
713
}
 
714
 
 
715
// Determine next boot method and attempt a boot using it.
 
716
static void
 
717
do_boot(int seq_nr)
 
718
{
 
719
    if (! CONFIG_BOOT)
 
720
        panic("Boot support not compiled in.\n");
 
721
 
 
722
    if (seq_nr >= BEVCount)
 
723
        boot_fail();
 
724
 
 
725
    // Boot the given BEV type.
 
726
    struct bev_s *ie = &BEV[seq_nr];
 
727
    switch (ie->type) {
 
728
    case IPL_TYPE_FLOPPY:
 
729
        printf("Booting from Floppy...\n");
 
730
        boot_disk(0x00, CheckFloppySig);
 
731
        break;
 
732
    case IPL_TYPE_HARDDISK:
 
733
        printf("Booting from Hard Disk...\n");
 
734
        boot_disk(0x80, 1);
 
735
        break;
 
736
    case IPL_TYPE_CDROM:
 
737
        boot_cdrom((void*)ie->vector);
 
738
        break;
 
739
    case IPL_TYPE_CBFS:
 
740
        boot_cbfs((void*)ie->vector);
 
741
        break;
 
742
    case IPL_TYPE_BEV:
 
743
        boot_rom(ie->vector);
 
744
        break;
 
745
    case IPL_TYPE_HALT:
 
746
        boot_fail();
 
747
        break;
 
748
    }
 
749
 
 
750
    // Boot failed: invoke the boot recovery function
 
751
    struct bregs br;
 
752
    memset(&br, 0, sizeof(br));
 
753
    br.flags = F_IF;
 
754
    call16_int(0x18, &br);
 
755
}
 
756
 
 
757
int BootSequence VARLOW = -1;
 
758
 
 
759
// Boot Failure recovery: try the next device.
 
760
void VISIBLE32FLAT
 
761
handle_18(void)
 
762
{
 
763
    debug_enter(NULL, DEBUG_HDL_18);
 
764
    int seq = BootSequence + 1;
 
765
    BootSequence = seq;
 
766
    do_boot(seq);
 
767
}
 
768
 
 
769
// INT 19h Boot Load Service Entry Point
 
770
void VISIBLE32FLAT
 
771
handle_19(void)
 
772
{
 
773
    debug_enter(NULL, DEBUG_HDL_19);
 
774
    BootSequence = 0;
 
775
    do_boot(0);
 
776
}