386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / i386 / stand / asbootblk.c
CommitLineData
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 */
56static __inline__ void
57outb(port, val)
58short port;
59char val;
60{
61 __asm__ volatile("outb %%al, %1" : :"a" (val), "d" (port));
62}
63
64static __inline__ unsigned int
65inb(port)
66short 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
76asm ("
77 /* we're running in 16 real mode, so normal assembly doesn't work */
78bootbase:
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
96flush:
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
106const 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
112const 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
121volatile struct mailbox_entry mailbox[2];
122const 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
148int (*f)();
149
150main ()
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
219int
220as_put_byte (val)
221int val;
222{
223 while (inb (as_port + AS_STATUS) & AS_STATUS_CDF)
224 ;
225 outb (as_port + AS_DATA_OUT, val);
226}
227
228asm ("
229ebootblkcode:
230 . = 510
231 .byte 0x55
232 .byte 0xaa
233ebootblk: /* MUST BE EXACTLY 0x200 BIG FOR SURE */
234");