Initial checkin.
[people/mcb30/legacybios.git] / src / boot.c
1 // 16bit 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 GPLv3 license.
7
8 #include "types.h" // VISIBLE
9 #include "util.h" // irq_enable
10 #include "biosvar.h" // struct bregs
11 #include "farptr.h" // SET_SEG
12
13 static inline void
14 __call_irq(u8 nr)
15 {
16     asm volatile("int %0" : : "N" (nr));
17 }
18
19 static inline u32
20 call_irq(u8 nr, struct bregs *callregs)
21 {
22     u32 flags;
23     asm volatile(
24         // Save current registers
25         "pushal\n"
26         // Pull in calling registers.
27         "movl 0x04(%%eax), %%edi\n"
28         "movl 0x08(%%eax), %%esi\n"
29         "movl 0x0c(%%eax), %%ebp\n"
30         "movl 0x14(%%eax), %%ebx\n"
31         "movl 0x18(%%eax), %%edx\n"
32         "movl 0x1c(%%eax), %%ecx\n"
33         "movl 0x20(%%eax), %%eax\n"
34         // Invoke interrupt
35         "int %1\n"
36         // Restore registers
37         "popal\n"
38         // Exract flags
39         "pushfw\n"
40         "popl %%eax\n"
41         : "=a" (flags): "N" (nr), "a" (callregs), "m" (*callregs));
42     return flags;
43 }
44
45 static void
46 print_boot_failure()
47 {
48     bprintf(0, "Boot failed\n");
49 }
50
51 static void
52 try_boot()
53 {
54     // XXX - assume floppy
55     u16 bootseg = 0x07c0;
56     u8 bootdrv = 0;
57
58     // Read sector
59     struct bregs cr;
60     memset(&cr, 0, sizeof(cr));
61     cr.dl = bootdrv;
62     SET_SEG(ES, bootseg);
63     cr.bx = 0;
64     cr.ah = 2;
65     cr.al = 1;
66     cr.ch = 0;
67     cr.cl = 1;
68     cr.dh = 0;
69     u32 status = call_irq(0x13, &cr);
70
71     if (status & F_CF) {
72         print_boot_failure();
73         return;
74     }
75
76     u16 bootip = (bootseg & 0x0fff) << 4;
77     bootseg &= 0xf000;
78
79     u32 segoff = (bootseg << 16) | bootip;
80     asm volatile (
81         "pushf\n"
82         "pushl %0\n"
83         "movb %b1, %%dl\n"
84         // Set the magic number in ax and the boot drive in dl.
85         "movw $0xaa55, %%ax\n"
86         // Zero some of the other registers.
87         "xorw %%bx, %%bx\n"
88         "movw %%bx, %%ds\n"
89         "movw %%bx, %%es\n"
90         "movw %%bx, %%bp\n"
91         // Go!
92         "iretw\n"
93         : : "r" (segoff), "ri" (bootdrv));
94 }
95
96 // Boot Failure recovery: try the next device.
97 void VISIBLE
98 handle_18(struct bregs *regs)
99 {
100     debug_enter(regs);
101     try_boot();
102 }
103
104 // INT 19h Boot Load Service Entry Point
105 void VISIBLE
106 handle_19(struct bregs *regs)
107 {
108     debug_enter(regs);
109     try_boot();
110 }
111
112 // Callback from 32bit entry - start boot process
113 void VISIBLE
114 begin_boot()
115 {
116     irq_enable();
117     __call_irq(0x19);
118 }