aboutsummaryrefslogtreecommitdiff
path: root/src/boot.c
blob: 828be1459d026b1b6fa6e1b91a80f9804845d55f (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
// 16bit code to load disk image and start system boot.
//
// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2002  MandrakeSoft S.A.
//
// This file may be distributed under the terms of the GNU GPLv3 license.

#include "types.h" // VISIBLE
#include "util.h" // irq_enable
#include "biosvar.h" // struct bregs
#include "farptr.h" // SET_SEG

static inline void
__call_irq(u8 nr)
{
    asm volatile("int %0" : : "N" (nr));
}

static inline u32
call_irq(u8 nr, struct bregs *callregs)
{
    u32 flags;
    asm volatile(
        // Save current registers
        "pushal\n"
        // Pull in calling registers.
        "movl 0x04(%%eax), %%edi\n"
        "movl 0x08(%%eax), %%esi\n"
        "movl 0x0c(%%eax), %%ebp\n"
        "movl 0x14(%%eax), %%ebx\n"
        "movl 0x18(%%eax), %%edx\n"
        "movl 0x1c(%%eax), %%ecx\n"
        "movl 0x20(%%eax), %%eax\n"
        // Invoke interrupt
        "int %1\n"
        // Restore registers
        "popal\n"
        // Exract flags
        "pushfw\n"
        "popl %%eax\n"
        : "=a" (flags): "N" (nr), "a" (callregs), "m" (*callregs));
    return flags;
}

static void
print_boot_failure()
{
    bprintf(0, "Boot failed\n");
}

static void
try_boot()
{
    // XXX - assume floppy
    u16 bootseg = 0x07c0;
    u8 bootdrv = 0;

    // Read sector
    struct bregs cr;
    memset(&cr, 0, sizeof(cr));
    cr.dl = bootdrv;
    SET_SEG(ES, bootseg);
    cr.bx = 0;
    cr.ah = 2;
    cr.al = 1;
    cr.ch = 0;
    cr.cl = 1;
    cr.dh = 0;
    u32 status = call_irq(0x13, &cr);

    if (status & F_CF) {
        print_boot_failure();
        return;
    }

    u16 bootip = (bootseg & 0x0fff) << 4;
    bootseg &= 0xf000;

    u32 segoff = (bootseg << 16) | bootip;
    asm volatile (
        "pushf\n"
        "pushl %0\n"
        "movb %b1, %%dl\n"
        // Set the magic number in ax and the boot drive in dl.
        "movw $0xaa55, %%ax\n"
        // Zero some of the other registers.
        "xorw %%bx, %%bx\n"
        "movw %%bx, %%ds\n"
        "movw %%bx, %%es\n"
        "movw %%bx, %%bp\n"
        // Go!
        "iretw\n"
        : : "r" (segoff), "ri" (bootdrv));
}

// Boot Failure recovery: try the next device.
void VISIBLE
handle_18(struct bregs *regs)
{
    debug_enter(regs);
    try_boot();
}

// INT 19h Boot Load Service Entry Point
void VISIBLE
handle_19(struct bregs *regs)
{
    debug_enter(regs);
    try_boot();
}

// Callback from 32bit entry - start boot process
void VISIBLE
begin_boot()
{
    irq_enable();
    __call_irq(0x19);
}