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