xref: /386bsd/usr/src/kernel/as/asbootblk.c (revision dc8b130e)
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