1 /*
2 * $Id:$
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 "sys/param.h"
34 #include "disklabel.h"
35 #include "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
outb(port,val)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
inb(port)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 #define CHECKPOINT2(x) (CRTBASE[2] = x)
121
122 volatile struct mailbox_entry mailbox[2];
123 const char ccb[] = {
124 3, /* opcode: normal read/write */
125 (target << 5) | 8, /* target num and read flag */
126 10, /* scsi cmd len */
127 1, /* no automatic request for sense */
128 READ_SIZE >> 16, /* data length */
129 READ_SIZE >> 8,
130 READ_SIZE,
131 RELOC >> 16, /* data pointer */
132 RELOC >> 8,
133 RELOC,
134 0, 0, 0, /* link pointer */
135 0, /* link id */
136 0, /* host status */
137 0, /* target status */
138 0, 0, /* reserved */
139
140 /* scsi cdb */
141 0x28, /* read opcode */
142 0, /* logical unit number */
143 0, 0, 0, 0, /* logical block address */
144 0, /* reserved */
145 0, NBLOCKS, /* transfer length */
146 0, /* link control */
147 };
148
149 int (*f)();
150 asm(" .globl ___main ; ___main: ret ");
151
main()152 main ()
153 {
154 int i;
155 extern char edata[], end[];
156 extern char base();
157 char volatile * volatile p, *q;
158
159 CHECKPOINT ('a');
160
161 /* clear bss */
162 for (p = edata; p < end; p++)
163 *p = 0;
164
165 f = (int (*)())SECOND_LEVEL_BOOT_START;
166
167 /* dma setup: see page 5-31 in the Adaptec manual */
168 /* this knows we are using drq 5 */
169 outb (0xd6, 0xc1);
170 outb (0xd4, 0x01);
171
172 outb (as_port + AS_CONTROL, AS_CONTROL_SRST);
173
174 /* delay a little */
175 /*for (i=100000; i > 0 ; i--)
176 (void)inb (0x84);*/
177
178 /*if (inb (as_port + AS_INTR) & AS_INTR_HACC)
179 outb (as_port + AS_CONTROL, AS_CONTROL_IRST); */
180
181 while (inb (as_port + AS_STATUS) != (AS_STATUS_INIT | AS_STATUS_IDLE))
182 ;
183
184 /*if (inb (as_port + AS_INTR))
185 outb (as_port + AS_CONTROL, AS_CONTROL_IRST); */
186 /* if (inb (as_port + AS_INTR) & AS_INTR_HACC)
187 outb (as_port + AS_CONTROL, AS_CONTROL_IRST); */
188
189 CHECKPOINT ('A');
190 /*while (inb (as_port + AS_STATUS) & AS_STATUS_DF) {
191 for (i=10000; i > 0 ; i--)
192 (void)inb (0x84);
193 (void) inb (as_port + AS_INTR);
194 }*/
195
196 /*CHECKPOINT ('b');*/
197
198 as_put_byte (AS_CMD_MAILBOX_INIT);
199 as_put_byte (1); /* one mailbox out, one in */
200 as_put_byte ((int)mailbox >> 16);
201 as_put_byte ((int)mailbox >> 8);
202 as_put_byte ((int)mailbox);
203
204 /*if (inb (as_port + AS_INTR) & AS_INTR_HACC)
205 outb (as_port + AS_CONTROL, AS_CONTROL_IRST);*/
206
207 /* CHECKPOINT ('B'); */
208 /* while ((inb (as_port + AS_INTR) & AS_INTR_HACC) == 0)
209 ;
210
211 outb (as_port + AS_CONTROL, AS_CONTROL_IRST); */
212
213 CHECKPOINT ('C');
214 while (inb (as_port + AS_STATUS) & AS_STATUS_INIT)
215 ;
216
217 CHECKPOINT ('c');
218
219 mailbox[0].msb = (int)ccb >> 16;
220 mailbox[0].mid = (int)ccb >> 8;
221 mailbox[0].lsb = (int)ccb;
222 mailbox[0].cmd = 1;
223 p = (char *)base;
224 q = (char *)ccb;
225 q[20] = p[3];
226 q[21] = p[2];
227 q[22] = p[1];
228 q[23] = p[0];
229
230 as_put_byte (AS_CMD_START_SCSI_COMMAND);
231
232 /* wait for done */
233 while (mailbox[1].cmd == 0)
234 ;
235
236 #ifdef NOPE
237 CHECKPOINT ('d');
238
239 if (mailbox[1].cmd != 1) {
240 /* some error */
241 CHECKPOINT2 ('@' + mailbox[1].cmd);
242 for (i=100000; i > 0 ; i--)
243 (void)inb (0x84);
244 }
245
246 CHECKPOINT ('e');
247 #endif
248
249 /* the optimazation that gcc uses when it knows we are jumpping
250 * to a constant address is broken, so we have to use a variable
251 * here
252 */
253 (*f)(dev, unit, *(long *)p);
254 }
255
256 int
as_put_byte(val)257 as_put_byte (val)
258 int val;
259 {
260 while (inb (as_port + AS_STATUS) & AS_STATUS_CDF)
261 ;
262 outb (as_port + AS_DATA_OUT, val);
263 }
264
265 asm ("
266 ebootblkcode:
267 . = 506
268 .globl _base
269 _base: .long 0x0000
270 .byte 0x55
271 .byte 0xaa
272 ebootblk: /* MUST BE EXACTLY 0x200 BIG FOR SURE */
273 ");
274