Commit | Line | Data |
---|---|---|
f7da4ecf WJ |
1 | /* |
2 | * sys/i386/stand/asbootblk.c | |
3 | * | |
4 | * Boot block for Adaptech 1542 SCSI | |
5 | * | |
6 | * April 10, 1992 | |
7 | * Pace Willisson | |
8 | * pace@blitz.com | |
9 | * | |
10 | * Placed in the public domain with NO WARRANTIES, not even the | |
11 | * implied warranties for MERCHANTABILITY or FITNESS FOR A | |
12 | * PARTICULAR PURPOSE. | |
13 | * | |
14 | * To compile: | |
15 | * | |
16 | * cc -O -c -DRELOC=0x70000 asbootblk.c | |
17 | * ld -N -T 7c00 asbootblk.o | |
18 | * | |
19 | * This should result in a file with 512 bytes of text and no initialized | |
20 | * data. Strip the 32 bit header and place in block 0. | |
21 | * | |
22 | * When run, this program copies at least the first 8 blocks of SCSI | |
23 | * target 0 to the address specified by RELOC, then jumps to the | |
24 | * address RELOC+1024 (skipping the boot block and disk label). Usually, | |
25 | * disks have 512 bytes per block, but I don't think they ever have | |
26 | * less, and it wont hurt if they are bigger, as long as RELOC + 8*SIZE | |
27 | * is less than 0xa0000. | |
28 | * | |
29 | * This bootblock does not support fdisk partitions, and can only be used | |
30 | * as the master boot block. | |
31 | */ | |
32 | ||
33 | #include "param.h" | |
34 | #include "disklabel.h" | |
35 | #include "i386/isa/asreg.h" | |
36 | ||
37 | /* RELOC should be defined with a -D flag to cc */ | |
38 | ||
39 | #define SECOND_LEVEL_BOOT_START (RELOC + 0x400) | |
40 | #define READ_SIZE 8192 | |
41 | ||
42 | #define as_port 0x330 | |
43 | #define target 0 | |
44 | ||
45 | ||
46 | #define NBLOCKS (READ_SIZE / 512) /* how many logical blocks to read */ | |
47 | ||
48 | ||
49 | /* These are the parameters to pass to the second level boot */ | |
50 | #define dev 4 /* major device number of as driver in | |
51 | i386/stand/conf.c and i386/i386/conf.c */ | |
52 | #define unit 0 /* partition number of root file system */ | |
53 | #define off 0 /* block offset of root file system */ | |
54 | ||
55 | /* inline i/o borrowed from Roell X server */ | |
56 | static __inline__ void | |
57 | outb(port, val) | |
58 | short port; | |
59 | char val; | |
60 | { | |
61 | __asm__ volatile("outb %%al, %1" : :"a" (val), "d" (port)); | |
62 | } | |
63 | ||
64 | static __inline__ unsigned int | |
65 | inb(port) | |
66 | short port; | |
67 | { | |
68 | unsigned int ret; | |
69 | __asm__ volatile("xorl %%eax, %%eax; inb %1, %%al" | |
70 | : "=a" (ret) : "d" (port)); | |
71 | return ret; | |
72 | } | |
73 | ||
74 | /* this code is linked at 0x7c00 and is loaded there by the BIOS */ | |
75 | ||
76 | asm (" | |
77 | /* we're running in 16 real mode, so normal assembly doesn't work */ | |
78 | bootbase: | |
79 | /* interrupts off */ | |
80 | cli | |
81 | ||
82 | /* load gdt */ | |
83 | .byte 0x2e,0x0f,0x01,0x16 /* lgdt %cs:$imm */ | |
84 | .word _gdtarg + 2 | |
85 | ||
86 | /* turn on protected mode */ | |
87 | smsw %ax | |
88 | orb $1,%al | |
89 | lmsw %ax | |
90 | ||
91 | /* flush prefetch queue and reload %cs */ | |
92 | .byte 0xea /* ljmp $8, flush */ | |
93 | .word flush | |
94 | .word 8 | |
95 | ||
96 | flush: | |
97 | /* now running in 32 bit mode */ | |
98 | movl $0x10,%eax | |
99 | movl %ax,%ds | |
100 | movl %ax,%es | |
101 | movl %ax,%ss | |
102 | movl $0x7c00,%esp | |
103 | call _main | |
104 | "); /* end of asm */ | |
105 | ||
106 | const char gdt[] = { | |
107 | 0, 0, 0, 0, 0, 0, 0, 0, | |
108 | 0xff, 0xff, 0, 0, 0, 0x9f, 0xcf, 0, /* code segment */ | |
109 | 0xff, 0xff, 0, 0, 0, 0x93, 0xcf, 0, /* data segment */ | |
110 | }; | |
111 | ||
112 | const struct { | |
113 | short filler; | |
114 | short size; | |
115 | const char *gdt; | |
116 | } gdtarg = { 0, sizeof gdt - 1, gdt }; | |
117 | ||
118 | #define CRTBASE ((char *)0xb8000) | |
119 | #define CHECKPOINT(x) (CRTBASE[0] = x) | |
120 | ||
121 | volatile struct mailbox_entry mailbox[2]; | |
122 | const char ccb[] = { | |
123 | 3, /* opcode: normal read/write */ | |
124 | (target << 5) | 8, /* target num and read flag */ | |
125 | 10, /* scsi cmd len */ | |
126 | 1, /* no automatic request for sense */ | |
127 | READ_SIZE >> 16, /* data length */ | |
128 | READ_SIZE >> 8, | |
129 | READ_SIZE, | |
130 | RELOC >> 16, /* data pointer */ | |
131 | RELOC >> 8, | |
132 | RELOC, | |
133 | 0, 0, 0, /* link pointer */ | |
134 | 0, /* link id */ | |
135 | 0, /* host status */ | |
136 | 0, /* target status */ | |
137 | 0, 0, /* reserved */ | |
138 | ||
139 | /* scsi cdb */ | |
140 | 0x28, /* read opcode */ | |
141 | 0, /* logical unit number */ | |
142 | 0, 0, 0, 0, /* logical block address */ | |
143 | 0, /* reserved */ | |
144 | 0, NBLOCKS, /* transfer length */ | |
145 | 0, /* link control */ | |
146 | }; | |
147 | ||
148 | int (*f)(); | |
149 | ||
150 | main () | |
151 | { | |
152 | int i; | |
153 | extern char edata[], end[]; | |
154 | char volatile * volatile p, *q; | |
155 | int physaddr; | |
156 | ||
157 | CHECKPOINT ('a'); | |
158 | ||
159 | /* clear bss */ | |
160 | for (p = edata; p < end; p++) | |
161 | *p = 0; | |
162 | ||
163 | f = (int (*)())SECOND_LEVEL_BOOT_START; | |
164 | ||
165 | /* dma setup: see page 5-31 in the Adaptech manual */ | |
166 | /* this knows we are using drq 5 */ | |
167 | outb (0xd6, 0xc1); | |
168 | outb (0xd4, 0x01); | |
169 | ||
170 | outb (as_port + AS_CONTROL, AS_CONTROL_SRST); | |
171 | ||
172 | /* delay a little */ | |
173 | inb (0x84); | |
174 | ||
175 | while (inb (as_port + AS_STATUS) != (AS_STATUS_INIT | AS_STATUS_IDLE)) | |
176 | ; | |
177 | ||
178 | CHECKPOINT ('b'); | |
179 | ||
180 | as_put_byte (AS_CMD_MAILBOX_INIT); | |
181 | as_put_byte (1); /* one mailbox out, one in */ | |
182 | as_put_byte ((int)mailbox >> 16); | |
183 | as_put_byte ((int)mailbox >> 8); | |
184 | as_put_byte ((int)mailbox); | |
185 | ||
186 | while (inb (as_port + AS_STATUS) & AS_STATUS_INIT) | |
187 | ; | |
188 | ||
189 | CHECKPOINT ('c'); | |
190 | ||
191 | mailbox[0].msb = (int)ccb >> 16; | |
192 | mailbox[0].mid = (int)ccb >> 8; | |
193 | mailbox[0].lsb = (int)ccb; | |
194 | mailbox[0].cmd = 1; | |
195 | ||
196 | as_put_byte (AS_CMD_START_SCSI_COMMAND); | |
197 | ||
198 | /* wait for done */ | |
199 | while (mailbox[1].cmd == 0) | |
200 | ; | |
201 | ||
202 | CHECKPOINT ('d'); | |
203 | ||
204 | if (mailbox[1].cmd != 1) { | |
205 | /* some error */ | |
206 | CHECKPOINT ('X'); | |
207 | while (1); | |
208 | } | |
209 | ||
210 | CHECKPOINT ('e'); | |
211 | ||
212 | /* the optimazation that gcc uses when it knows we are jumpping | |
213 | * to a constant address is broken, so we have to use a variable | |
214 | * here | |
215 | */ | |
216 | (*f)(dev, unit, off); | |
217 | } | |
218 | ||
219 | int | |
220 | as_put_byte (val) | |
221 | int val; | |
222 | { | |
223 | while (inb (as_port + AS_STATUS) & AS_STATUS_CDF) | |
224 | ; | |
225 | outb (as_port + AS_DATA_OUT, val); | |
226 | } | |
227 | ||
228 | asm (" | |
229 | ebootblkcode: | |
230 | . = 510 | |
231 | .byte 0x55 | |
232 | .byte 0xaa | |
233 | ebootblk: /* MUST BE EXACTLY 0x200 BIG FOR SURE */ | |
234 | "); |