]>
Commit | Line | Data |
---|---|---|
14c7c974 | 1 | /* |
57c72a9a | 2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. |
14c7c974 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
57c72a9a | 6 | * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights |
4f6e3300 A |
7 | * Reserved. This file contains Original Code and/or Modifications of |
8 | * Original Code as defined in and that are subject to the Apple Public | |
57c72a9a | 9 | * Source License Version 2.0 (the "License"). You may not use this file |
4f6e3300 A |
10 | * except in compliance with the License. Please obtain a copy of the |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
14c7c974 A |
13 | * |
14 | * The Original Code and all software distributed under the License are | |
4f6e3300 | 15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
4f6e3300 A |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License. | |
14c7c974 A |
21 | * |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* | |
25 | * Copyright 1993 NeXT Computer, Inc. | |
26 | * All rights reserved. | |
27 | */ | |
28 | ||
f083c6c3 | 29 | #include "bootstruct.h" |
14c7c974 | 30 | #include "libsaio.h" |
14c7c974 | 31 | |
f083c6c3 A |
32 | #define MAX_DRIVES 8 |
33 | ||
14c7c974 | 34 | static biosBuf_t bb; |
14c7c974 A |
35 | |
36 | int bgetc(void) | |
37 | { | |
38 | bb.intno = 0x16; | |
39 | bb.eax.r.h = 0x00; | |
40 | bios(&bb); | |
41 | return bb.eax.rr; | |
42 | } | |
43 | ||
44 | int readKeyboardStatus(void) | |
45 | { | |
46 | bb.intno = 0x16; | |
47 | bb.eax.r.h = 0x01; | |
48 | bios(&bb); | |
49 | if (bb.flags.zf) { | |
75b89a82 | 50 | return 0; |
14c7c974 | 51 | } else { |
75b89a82 | 52 | return bb.eax.rr; |
14c7c974 A |
53 | } |
54 | } | |
55 | ||
56 | int readKeyboardShiftFlags(void) | |
57 | { | |
58 | bb.intno = 0x16; | |
59 | bb.eax.r.h = 0x02; | |
60 | bios(&bb); | |
61 | return bb.eax.r.l; | |
62 | } | |
63 | ||
64 | unsigned int time18(void) | |
65 | { | |
66 | union { | |
75b89a82 A |
67 | struct { |
68 | unsigned int low:16; | |
69 | unsigned int high:16; | |
70 | } s; | |
71 | unsigned int i; | |
14c7c974 A |
72 | } time; |
73 | ||
74 | bb.intno = 0x1a; | |
75 | bb.eax.r.h = 0x00; | |
76 | bios(&bb); | |
77 | time.s.low = bb.edx.rr; | |
78 | time.s.high = bb.ecx.rr; | |
79 | return time.i; | |
80 | } | |
81 | ||
f083c6c3 A |
82 | unsigned long getMemoryMap( MemoryRange * rangeArray, |
83 | unsigned long maxRangeCount, | |
84 | unsigned long * conMemSizePtr, | |
85 | unsigned long * extMemSizePtr ) | |
14c7c974 | 86 | { |
f083c6c3 A |
87 | #define kMemoryMapSignature 'SMAP' |
88 | #define kDescriptorSizeMin 20 | |
89 | ||
bba600dd | 90 | MemoryRange * range = (MemoryRange *)BIOS_ADDR; |
f083c6c3 A |
91 | unsigned long count = 0; |
92 | unsigned long long conMemSize = 0; | |
57c72a9a | 93 | unsigned long long extMemSize = 0; |
f083c6c3 | 94 | |
f083c6c3 A |
95 | // Prepare for the INT15 E820h call. Each call returns a single |
96 | // memory range. A continuation value is returned that must be | |
97 | // provided on a subsequent call to fetch the next range. | |
98 | // | |
99 | // Certain BIOSes (Award 6.00PG) expect the upper word in EAX | |
100 | // to be cleared on entry, otherwise only a single range will | |
101 | // be reported. | |
102 | // | |
103 | // Some BIOSes will simply ignore the value of ECX on entry. | |
104 | // Probably best to keep its value at 20 to avoid surprises. | |
105 | ||
bba600dd A |
106 | //printf("Get memory map 0x%x, %d\n", rangeArray);getc(); |
107 | if (maxRangeCount > (BIOS_LEN / sizeof(MemoryRange))) { | |
108 | maxRangeCount = (BIOS_LEN / sizeof(MemoryRange)); | |
109 | } | |
f083c6c3 A |
110 | bb.ebx.rx = 0; // Initial continuation value must be zero. |
111 | ||
112 | while ( count < maxRangeCount ) | |
47b0a8bd | 113 | { |
f083c6c3 A |
114 | bb.intno = 0x15; |
115 | bb.eax.rx = 0xe820; | |
116 | bb.ecx.rx = kDescriptorSizeMin; | |
117 | bb.edx.rx = kMemoryMapSignature; | |
118 | bb.edi.rr = OFFSET( (unsigned long) range ); | |
119 | bb.es = SEGMENT( (unsigned long) range ); | |
120 | bios(&bb); | |
47b0a8bd | 121 | |
f083c6c3 | 122 | // Check for errors. |
47b0a8bd | 123 | |
f083c6c3 A |
124 | if ( bb.flags.cf |
125 | || bb.eax.rx != kMemoryMapSignature | |
bba600dd A |
126 | || bb.ecx.rx != kDescriptorSizeMin ) { |
127 | //printf("Got an error %x %x %x\n", bb.flags.cf, | |
128 | // bb.eax.rx, bb.ecx.rx); | |
129 | break; | |
130 | } | |
47b0a8bd | 131 | |
f083c6c3 | 132 | // Tally up the conventional/extended memory sizes. |
47b0a8bd | 133 | |
f083c6c3 A |
134 | if ( range->type == kMemoryRangeUsable || |
135 | range->type == kMemoryRangeACPI || | |
136 | range->type == kMemoryRangeNVS ) | |
137 | { | |
138 | // Tally the conventional memory ranges. | |
57c72a9a | 139 | if ( range->base + range->length <= 0xa0000 ) { |
f083c6c3 | 140 | conMemSize += range->length; |
57c72a9a | 141 | } |
f083c6c3 A |
142 | |
143 | // Record the top of extended memory. | |
57c72a9a A |
144 | if ( range->base >= EXTENDED_ADDR ) { |
145 | extMemSize += range->length; | |
146 | } | |
f083c6c3 A |
147 | } |
148 | ||
149 | range++; | |
150 | count++; | |
151 | ||
152 | // Is this the last address range? | |
153 | ||
bba600dd A |
154 | if ( bb.ebx.rx == 0 ) { |
155 | //printf("last range\n"); | |
156 | break; | |
157 | } | |
14c7c974 | 158 | } |
f083c6c3 | 159 | *conMemSizePtr = conMemSize / 1024; // size in KB |
57c72a9a A |
160 | *extMemSizePtr = extMemSize / 1024; // size in KB |
161 | ||
bba600dd A |
162 | // Copy out data |
163 | bcopy((char *)BIOS_ADDR, rangeArray, ((char *)range - (char *)BIOS_ADDR)); | |
164 | ||
57c72a9a A |
165 | #if DEBUG |
166 | { | |
bba600dd A |
167 | int i; |
168 | printf("%d total ranges\n", count);getc(); | |
169 | for (i=0, range = rangeArray; i<count; i++, range++) { | |
170 | printf("range: type %d, base 0x%x, length 0x%x\n", | |
171 | range->type, (unsigned int)range->base, (unsigned int)range->length); getc(); | |
57c72a9a A |
172 | } |
173 | } | |
174 | #endif | |
f083c6c3 A |
175 | |
176 | return count; | |
177 | } | |
178 | ||
179 | unsigned long getExtendedMemorySize() | |
180 | { | |
181 | // Get extended memory size for large configurations. Not used unless | |
182 | // the INT15, E820H call (Get System Address Map) failed. | |
183 | // | |
184 | // Input: | |
185 | // | |
186 | // AX Function Code E801h | |
187 | // | |
188 | // Outputs: | |
189 | // | |
190 | // CF Carry Flag Carry cleared indicates no error. | |
191 | // AX Extended 1 Number of contiguous KB between 1 and 16 MB, | |
192 | // maximum 0x3C00 = 15 MB. | |
193 | // BX Extended 2 Number of contiguous 64 KB blocks between | |
194 | // 16 MB and 4 GB. | |
195 | // CX Configured 1 Number of contiguous KB between 1 and 16 MB, | |
196 | // maximum 0x3C00 = 15 MB. | |
197 | // DX Configured 2 Number of contiguous 64 KB blocks between | |
198 | // 16 MB and 4 GB. | |
199 | ||
200 | bb.intno = 0x15; | |
201 | bb.eax.rx = 0xe801; | |
202 | bios(&bb); | |
203 | ||
204 | // Return the size of memory above 1MB (extended memory) in kilobytes. | |
205 | ||
206 | if ( bb.flags.cf == 0 ) return (bb.ebx.rr * 64 + bb.eax.rr); | |
207 | ||
208 | // Get Extended memory size. Called on last resort since the return | |
209 | // value is limited to 16-bits (a little less than 64MB max). May | |
210 | // not be supported by modern BIOSes. | |
211 | // | |
212 | // Input: | |
213 | // | |
214 | // AX Function Code E801h | |
215 | // | |
216 | // Outputs: | |
217 | // | |
218 | // CF Carry Flag Carry cleared indicates no error. | |
219 | // AX Memory Count Number of contiguous KB above 1MB. | |
220 | ||
221 | bb.intno = 0x15; | |
222 | bb.eax.rx = 0x88; | |
223 | bios(&bb); | |
224 | ||
225 | // Return the size of memory above 1MB (extended memory) in kilobytes. | |
226 | ||
227 | return bb.flags.cf ? 0 : bb.eax.rr; | |
228 | } | |
229 | ||
230 | unsigned long getConventionalMemorySize() | |
231 | { | |
232 | bb.intno = 0x12; | |
233 | bios(&bb); | |
234 | return bb.eax.rr; // kilobytes | |
14c7c974 A |
235 | } |
236 | ||
237 | void video_mode(int mode) | |
238 | { | |
239 | bb.intno = 0x10; | |
240 | bb.eax.r.h = 0x00; | |
241 | bb.eax.r.l = mode; | |
242 | bios(&bb); | |
243 | } | |
244 | ||
245 | int biosread(int dev, int cyl, int head, int sec, int num) | |
246 | { | |
247 | int i; | |
248 | ||
249 | bb.intno = 0x13; | |
75b89a82 | 250 | sec += 1; /* sector numbers start at 1 */ |
14c7c974 A |
251 | |
252 | for (i=0;;) { | |
75b89a82 A |
253 | bb.ecx.r.h = cyl; |
254 | bb.ecx.r.l = ((cyl & 0x300) >> 2) | (sec & 0x3F); | |
255 | bb.edx.r.h = head; | |
256 | bb.edx.r.l = dev; | |
257 | bb.eax.r.l = num; | |
258 | bb.ebx.rr = OFFSET(ptov(BIOS_ADDR)); | |
259 | bb.es = SEGMENT(ptov(BIOS_ADDR)); | |
260 | ||
261 | bb.eax.r.h = 0x02; | |
262 | bios(&bb); | |
14c7c974 | 263 | |
75b89a82 A |
264 | if ((bb.eax.r.h == 0x00) || (i++ >= 5)) |
265 | break; | |
14c7c974 | 266 | |
75b89a82 A |
267 | /* reset disk subsystem and try again */ |
268 | bb.eax.r.h = 0x00; | |
269 | bios(&bb); | |
14c7c974 A |
270 | } |
271 | return bb.eax.r.h; | |
272 | } | |
273 | ||
274 | int ebiosread(int dev, long sec, int count) | |
275 | { | |
276 | int i; | |
75b89a82 A |
277 | static struct { |
278 | unsigned char size; | |
279 | unsigned char reserved; | |
280 | unsigned char numblocks; | |
281 | unsigned char reserved2; | |
282 | unsigned short bufferOffset; | |
283 | unsigned short bufferSegment; | |
284 | unsigned long long startblock; | |
57c72a9a | 285 | } addrpacket __attribute__((aligned(16))) = {0}; |
14c7c974 A |
286 | addrpacket.size = sizeof(addrpacket); |
287 | ||
288 | for (i=0;;) { | |
75b89a82 | 289 | bb.intno = 0x13; |
14c7c974 A |
290 | bb.eax.r.h = 0x42; |
291 | bb.edx.r.l = dev; | |
75b89a82 A |
292 | bb.esi.rr = OFFSET((unsigned)&addrpacket); |
293 | bb.ds = SEGMENT((unsigned)&addrpacket); | |
294 | addrpacket.reserved = addrpacket.reserved2 = 0; | |
295 | addrpacket.numblocks = count; | |
296 | addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR)); | |
297 | addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR)); | |
298 | addrpacket.startblock = sec; | |
14c7c974 A |
299 | bios(&bb); |
300 | if ((bb.eax.r.h == 0x00) || (i++ >= 5)) | |
301 | break; | |
302 | ||
303 | /* reset disk subsystem and try again */ | |
304 | bb.eax.r.h = 0x00; | |
305 | bios(&bb); | |
306 | } | |
307 | return bb.eax.r.h; | |
308 | } | |
309 | ||
57c72a9a A |
310 | int ebioswrite(int dev, long sec, int count) |
311 | { | |
312 | int i; | |
313 | static struct { | |
314 | unsigned char size; | |
315 | unsigned char reserved; | |
316 | unsigned char numblocks; | |
317 | unsigned char reserved2; | |
318 | unsigned short bufferOffset; | |
319 | unsigned short bufferSegment; | |
320 | unsigned long long startblock; | |
321 | } addrpacket __attribute__((aligned(16))) = {0}; | |
322 | addrpacket.size = sizeof(addrpacket); | |
323 | ||
324 | for (i=0;;) { | |
325 | bb.intno = 0x13; | |
326 | bb.eax.r.l = 0; /* Don't verify */ | |
327 | bb.eax.r.h = 0x43; | |
328 | bb.edx.r.l = dev; | |
329 | bb.esi.rr = OFFSET((unsigned)&addrpacket); | |
330 | bb.ds = SEGMENT((unsigned)&addrpacket); | |
331 | addrpacket.reserved = addrpacket.reserved2 = 0; | |
332 | addrpacket.numblocks = count; | |
333 | addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR)); | |
334 | addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR)); | |
335 | addrpacket.startblock = sec; | |
336 | bios(&bb); | |
337 | if ((bb.eax.r.h == 0x00) || (i++ >= 5)) | |
338 | break; | |
339 | ||
340 | /* reset disk subsystem and try again */ | |
341 | bb.eax.r.h = 0x00; | |
342 | bios(&bb); | |
343 | } | |
344 | return bb.eax.r.h; | |
345 | } | |
346 | ||
14c7c974 A |
347 | void putc(int ch) |
348 | { | |
349 | bb.intno = 0x10; | |
75b89a82 A |
350 | bb.ebx.r.h = 0x00; /* background black */ |
351 | bb.ebx.r.l = 0x0F; /* foreground white */ | |
14c7c974 A |
352 | bb.eax.r.h = 0x0e; |
353 | bb.eax.r.l = ch; | |
354 | bios(&bb); | |
355 | } | |
356 | ||
75b89a82 A |
357 | void putca(int ch, int attr, int repeat) |
358 | { | |
359 | bb.intno = 0x10; | |
360 | bb.ebx.r.h = 0x00; /* page number */ | |
361 | bb.ebx.r.l = attr; /* attribute */ | |
362 | bb.eax.r.h = 0x9; | |
363 | bb.eax.r.l = ch; | |
364 | bb.ecx.rx = repeat; /* repeat count */ | |
365 | bios(&bb); | |
366 | } | |
367 | ||
f083c6c3 A |
368 | /* Check to see if the passed-in drive is in El Torito no-emulation mode. */ |
369 | int is_no_emulation(int drive) | |
14c7c974 | 370 | { |
f083c6c3 A |
371 | struct packet { |
372 | unsigned char packet_size; | |
373 | unsigned char media_type; | |
374 | unsigned char drive_num; | |
375 | unsigned char ctrlr_index; | |
376 | unsigned long lba; | |
377 | unsigned short device_spec; | |
378 | unsigned short buffer_segment; | |
379 | unsigned short load_segment; | |
380 | unsigned short sector_count; | |
381 | unsigned char cyl_count; | |
382 | unsigned char sec_count; | |
383 | unsigned char head_count; | |
384 | unsigned char reseved; | |
57c72a9a | 385 | } __attribute__((packed)); |
f083c6c3 | 386 | static struct packet pkt; |
14c7c974 | 387 | |
f083c6c3 A |
388 | bzero(&pkt, sizeof(pkt)); |
389 | pkt.packet_size = 0x13; | |
390 | ||
391 | bb.intno = 0x13; | |
392 | bb.eax.r.h = 0x4b; | |
393 | bb.eax.r.l = 0x01; // subfunc: get info | |
394 | bb.edx.r.l = drive; | |
395 | bb.esi.rr = OFFSET((unsigned)&pkt); | |
396 | bb.ds = SEGMENT((unsigned)&pkt); | |
397 | ||
398 | bios(&bb); | |
399 | #if DEBUG | |
400 | printf("el_torito info drive %x\n", drive); | |
401 | ||
402 | printf("--> cf %x, eax %x\n", bb.flags.cf, bb.eax.rr); | |
14c7c974 | 403 | |
f083c6c3 A |
404 | printf("pkt_size: %x\n", pkt.packet_size); |
405 | printf("media_type: %x\n", pkt.media_type); | |
406 | printf("drive_num: %x\n", pkt.drive_num); | |
407 | printf("device_spec: %x\n", pkt.device_spec); | |
408 | printf("press a key->\n");getc(); | |
409 | #endif | |
410 | ||
411 | /* Some BIOSes erroneously return cf = 1 */ | |
412 | /* Just check to see if the drive number is the same. */ | |
413 | if (pkt.drive_num == drive) { | |
414 | if ((pkt.media_type & 0x0F) == 0) { | |
415 | /* We are in no-emulation mode. */ | |
416 | return 1; | |
417 | } | |
418 | } | |
419 | ||
420 | return 0; | |
421 | } | |
422 | ||
423 | #if DEBUG | |
424 | /* | |
425 | * BIOS drive information. | |
426 | */ | |
427 | void print_drive_info(boot_drive_info_t *dp) | |
428 | { | |
429 | // printf("buf_size = %x\n", dp->params.buf_size); | |
430 | printf("info_flags = %x\n", dp->params.info_flags); | |
431 | printf(" phys_cyls = %lx\n", dp->params. phys_cyls); | |
432 | printf(" phys_heads = %lx\n", dp->params. phys_heads); | |
433 | printf(" phys_spt = %lx\n", dp->params. phys_spt); | |
434 | printf("phys_sectors = %lx%lx\n", ((unsigned long *)(&dp->params.phys_sectors))[1], | |
435 | ((unsigned long *)(&dp->params.phys_sectors))[0]); | |
436 | printf("phys_nbps = %x\n", dp->params.phys_nbps); | |
437 | // printf("dpte_offset = %x\n", dp->params.dpte_offset); | |
438 | // printf("dpte_segment = %x\n", dp->params.dpte_segment); | |
439 | // printf("key = %x\n", dp->params.key); | |
440 | // printf("path_len = %x\n", dp->params. path_len); | |
441 | // printf("reserved1 = %x\n", dp->params. reserved1); | |
442 | // printf("reserved2 = %x\n", dp->params.reserved2); | |
443 | //printf("bus_type[4] = %x\n", dp->params. bus_type[4]); | |
444 | //printf("interface_type[8] = %x\n", dp->params. interface_type[8]); | |
445 | //printf("interface_path[8] = %x\n", dp->params. interface_path[8]); | |
446 | //printf("dev_path[8] = %x\n", dp->params. dev_path[8]); | |
447 | // printf("reserved3 = %x\n", dp->params. reserved3); | |
448 | // printf("checksum = %x\n", dp->params. checksum); | |
449 | ||
450 | printf(" io_port_base = %x\n", dp->dpte.io_port_base); | |
451 | printf(" control_port_base = %x\n", dp->dpte.control_port_base); | |
452 | printf(" head_flags = %x\n", dp->dpte. head_flags); | |
453 | printf(" vendor_info = %x\n", dp->dpte. vendor_info); | |
454 | printf(" irq = %x\n", dp->dpte. irq); | |
455 | // printf(" irq_unused = %x\n", dp->dpte. irq_unused); | |
456 | printf(" block_count = %x\n", dp->dpte. block_count); | |
457 | printf(" dma_channe = %x\n", dp->dpte. dma_channel); | |
458 | printf(" dma_type = %x\n", dp->dpte. dma_type); | |
459 | printf(" pio_type = %x\n", dp->dpte. pio_type); | |
460 | printf(" pio_unused = %x\n", dp->dpte. pio_unused); | |
461 | printf(" option_flags = %x\n", dp->dpte.option_flags); | |
462 | // printf(" reserved = %x\n", dp->dpte.reserved); | |
463 | printf(" revision = %x\n", dp->dpte. revision); | |
464 | // printf(" checksum = %x\n", dp->dpte. checksum); | |
465 | } | |
466 | ||
467 | #endif | |
468 | ||
469 | int get_drive_info(int drive, struct driveInfo *dp) | |
470 | { | |
471 | boot_drive_info_t *di = &dp->di; | |
472 | int ret = 0; | |
473 | ||
57c72a9a | 474 | #if UNUSED |
14c7c974 | 475 | if (maxhd == 0) { |
75b89a82 A |
476 | bb.intno = 0x13; |
477 | bb.eax.r.h = 0x08; | |
478 | bb.edx.r.l = 0x80; | |
479 | bios(&bb); | |
480 | if (bb.flags.cf == 0) | |
481 | maxhd = 0x7f + bb.edx.r.l; | |
14c7c974 A |
482 | }; |
483 | ||
484 | if (drive > maxhd) | |
75b89a82 | 485 | return 0; |
f083c6c3 A |
486 | #endif |
487 | ||
488 | bzero(dp, sizeof(struct driveInfo)); | |
489 | dp->biosdev = drive; | |
490 | ||
491 | /* Check for El Torito no-emulation mode. */ | |
492 | dp->no_emulation = is_no_emulation(drive); | |
14c7c974 A |
493 | |
494 | /* Check drive for EBIOS support. */ | |
495 | bb.intno = 0x13; | |
496 | bb.eax.r.h = 0x41; | |
497 | bb.edx.r.l = drive; | |
498 | bb.ebx.rr = 0x55aa; | |
499 | bios(&bb); | |
f083c6c3 | 500 | if((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) { |
75b89a82 | 501 | /* Get flags for supported operations. */ |
f083c6c3 | 502 | dp->uses_ebios = bb.ecx.r.l; |
75b89a82 | 503 | } |
14c7c974 | 504 | |
f083c6c3 | 505 | if (dp->uses_ebios & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) { |
14c7c974 | 506 | /* Get EBIOS drive info. */ |
f083c6c3 A |
507 | static struct drive_params params; |
508 | ||
509 | params.buf_size = sizeof(params); | |
14c7c974 A |
510 | bb.intno = 0x13; |
511 | bb.eax.r.h = 0x48; | |
512 | bb.edx.r.l = drive; | |
f083c6c3 A |
513 | bb.esi.rr = OFFSET((unsigned)¶ms); |
514 | bb.ds = SEGMENT((unsigned)¶ms); | |
14c7c974 | 515 | bios(&bb); |
f083c6c3 A |
516 | if(bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) { |
517 | dp->uses_ebios = 0; | |
518 | di->params.buf_size = 1; | |
519 | } else { | |
520 | bcopy(¶ms, &di->params, sizeof(params)); | |
521 | ||
522 | if (drive >= BASE_HD_DRIVE && | |
523 | (dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && | |
524 | di->params.buf_size >= 30 && | |
525 | !(di->params.dpte_offset == 0xFFFF && di->params.dpte_segment == 0xFFFF)) { | |
526 | void *ptr = (void *)(di->params.dpte_offset + ((unsigned int)di->params.dpte_segment << 4)); | |
527 | bcopy(ptr, &di->dpte, sizeof(di->dpte)); | |
528 | } | |
529 | } | |
14c7c974 A |
530 | } |
531 | ||
f083c6c3 A |
532 | if (di->params.phys_heads == 0 || di->params.phys_spt == 0) { |
533 | /* Either it's not EBIOS, or EBIOS didn't tell us. */ | |
534 | bb.intno = 0x13; | |
535 | bb.eax.r.h = 0x08; | |
536 | bb.edx.r.l = drive; | |
537 | bios(&bb); | |
538 | if (bb.flags.cf == 0 && bb.eax.r.h == 0) { | |
539 | unsigned long cyl; | |
540 | unsigned long sec; | |
541 | unsigned long hds; | |
542 | ||
543 | hds = bb.edx.r.h; | |
544 | sec = bb.ecx.r.l & 0x3F; | |
545 | if((dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && (sec != 0)) { | |
546 | cyl = (di->params.phys_sectors / ((hds + 1) * sec)) - 1; | |
547 | } | |
548 | else { | |
549 | cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2); | |
550 | } | |
551 | di->params.phys_heads = hds; | |
552 | di->params.phys_spt = sec; | |
553 | di->params.phys_cyls = cyl; | |
554 | } else { | |
555 | ret = -1; | |
556 | } | |
557 | } | |
558 | ||
559 | if (dp->no_emulation) { | |
560 | /* Some BIOSes give us erroneous EBIOS support information. | |
561 | * Assume that if you're on a CD, then you can use | |
562 | * EBIOS disk calls. | |
563 | */ | |
564 | dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS; | |
565 | } | |
566 | #if DEBUG | |
567 | print_drive_info(di); | |
568 | printf("uses_ebios = 0x%x\n", dp->uses_ebios); | |
bba600dd | 569 | printf("result %d\n", ret); |
f083c6c3 A |
570 | printf("press a key->\n");getc(); |
571 | #endif | |
572 | ||
573 | if (ret == 0) { | |
574 | dp->valid = 1; | |
14c7c974 | 575 | } |
f083c6c3 | 576 | return ret; |
14c7c974 A |
577 | } |
578 | ||
75b89a82 | 579 | void setCursorPosition(int x, int y, int page) |
14c7c974 A |
580 | { |
581 | bb.intno = 0x10; | |
582 | bb.eax.r.h = 0x02; | |
75b89a82 | 583 | bb.ebx.r.h = page; /* page 0 for graphics */ |
14c7c974 A |
584 | bb.edx.r.l = x; |
585 | bb.edx.r.h = y; | |
586 | bios(&bb); | |
587 | } | |
588 | ||
75b89a82 A |
589 | void setCursorType(int type) |
590 | { | |
591 | bb.intno = 0x10; | |
592 | bb.eax.r.h = 0x01; | |
593 | bb.ecx.rr = type; | |
594 | bios(&bb); | |
595 | } | |
596 | ||
597 | void getCursorPositionAndType(int * x, int * y, int * type) | |
598 | { | |
599 | bb.intno = 0x10; | |
600 | bb.eax.r.h = 0x03; | |
601 | bios(&bb); | |
602 | *x = bb.edx.r.l; | |
603 | *y = bb.edx.r.h; | |
604 | *type = bb.ecx.rr; | |
605 | } | |
606 | ||
607 | void scollPage(int x1, int y1, int x2, int y2, int attr, int rows, int dir) | |
608 | { | |
609 | bb.intno = 0x10; | |
610 | bb.eax.r.h = (dir > 0) ? 0x06 : 0x07; | |
611 | bb.eax.r.l = rows; | |
612 | bb.ebx.r.h = attr; | |
613 | bb.ecx.r.h = y1; | |
614 | bb.ecx.r.l = x1; | |
615 | bb.edx.r.h = y2; | |
616 | bb.edx.r.l = x2; | |
617 | bios(&bb); | |
618 | } | |
619 | ||
620 | void clearScreenRows( int y1, int y2 ) | |
621 | { | |
622 | scollPage( 0, y1, 80 - 1, y2, 0x07, y2 - y1 + 1, 1 ); | |
623 | } | |
624 | ||
625 | void setActiveDisplayPage( int page ) | |
626 | { | |
627 | bb.intno = 0x10; | |
628 | bb.eax.r.h = 5; | |
629 | bb.eax.r.l = page; | |
630 | bios(&bb); | |
631 | } | |
632 | ||
14c7c974 A |
633 | #if DEBUG |
634 | ||
75b89a82 A |
635 | int terminateDiskEmulation() |
636 | { | |
f083c6c3 | 637 | static char cd_spec[0x13]; |
75b89a82 A |
638 | |
639 | bb.intno = 0x13; | |
640 | bb.eax.r.h = 0x4b; | |
641 | bb.eax.r.l = 0; // subfunc: terminate emulation | |
642 | bb.esi.rr = OFFSET((unsigned)&cd_spec); | |
643 | bb.ds = SEGMENT((unsigned)&cd_spec); | |
644 | bios(&bb); | |
645 | return bb.eax.r.h; | |
646 | } | |
647 | ||
14c7c974 A |
648 | int readDriveParameters(int drive, struct driveParameters *dp) |
649 | { | |
650 | bb.intno = 0x13; | |
651 | bb.edx.r.l = drive; | |
652 | bb.eax.r.h = 0x08; | |
653 | bios(&bb); | |
654 | if (bb.eax.r.h == 0) { | |
75b89a82 A |
655 | dp->heads = bb.edx.r.h; |
656 | dp->sectors = bb.ecx.r.l & 0x3F; | |
657 | dp->cylinders = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2); | |
658 | dp->totalDrives = bb.edx.r.l; | |
14c7c974 | 659 | } else { |
75b89a82 | 660 | bzero(dp, sizeof(*dp)); |
14c7c974 A |
661 | } |
662 | return bb.eax.r.h; | |
663 | ||
664 | } | |
665 | #endif | |
666 | ||
57c72a9a A |
667 | #ifdef APM_SUPPORT |
668 | ||
75b89a82 A |
669 | #define APM_INTNO 0x15 |
670 | #define APM_INTCODE 0x53 | |
14c7c974 A |
671 | |
672 | int | |
673 | APMPresent(void) | |
674 | { | |
14c7c974 A |
675 | bb.intno = APM_INTNO; |
676 | bb.eax.r.h = APM_INTCODE; | |
677 | bb.eax.r.l = 0x00; | |
678 | bb.ebx.rr = 0x0000; | |
679 | bios(&bb); | |
680 | if ((bb.flags.cf == 0) && | |
75b89a82 A |
681 | (bb.ebx.r.h == 'P') && |
682 | (bb.ebx.r.l == 'M')) { | |
683 | /* Success */ | |
f083c6c3 A |
684 | bootArgs->apmConfig.major_vers = bb.eax.r.h; |
685 | bootArgs->apmConfig.minor_vers = bb.eax.r.l; | |
686 | bootArgs->apmConfig.flags.data = bb.ecx.rr; | |
75b89a82 | 687 | return 1; |
14c7c974 A |
688 | } |
689 | return 0; | |
690 | } | |
691 | ||
692 | int | |
693 | APMConnect32(void) | |
694 | { | |
14c7c974 A |
695 | bb.intno = APM_INTNO; |
696 | bb.eax.r.h = APM_INTCODE; | |
697 | bb.eax.r.l = 0x03; | |
698 | bb.ebx.rr = 0x0000; | |
699 | bios(&bb); | |
700 | if (bb.flags.cf == 0) { | |
75b89a82 | 701 | /* Success */ |
f083c6c3 A |
702 | bootArgs->apmConfig.cs32_base = (bb.eax.rr) << 4; |
703 | bootArgs->apmConfig.entry_offset = bb.ebx.rx; | |
704 | bootArgs->apmConfig.cs16_base = (bb.ecx.rr) << 4; | |
705 | bootArgs->apmConfig.ds_base = (bb.edx.rr) << 4; | |
706 | if (bootArgs->apmConfig.major_vers >= 1 && | |
707 | bootArgs->apmConfig.minor_vers >= 1) { | |
708 | bootArgs->apmConfig.cs_length = bb.esi.rr; | |
709 | bootArgs->apmConfig.ds_length = bb.edi.rr; | |
75b89a82 | 710 | } else { |
f083c6c3 A |
711 | bootArgs->apmConfig.cs_length = |
712 | bootArgs->apmConfig.ds_length = 64 * 1024; | |
75b89a82 | 713 | } |
f083c6c3 | 714 | bootArgs->apmConfig.connected = 1; |
75b89a82 | 715 | return 1; |
14c7c974 A |
716 | } |
717 | return 0; | |
718 | } | |
719 | ||
57c72a9a A |
720 | #endif /* APM_SUPPORT */ |
721 | ||
75b89a82 | 722 | #ifdef EISA_SUPPORT |
14c7c974 A |
723 | BOOL |
724 | eisa_present( | |
725 | void | |
726 | ) | |
727 | { | |
75b89a82 A |
728 | static BOOL checked; |
729 | static BOOL isEISA; | |
14c7c974 A |
730 | |
731 | if (!checked) { | |
75b89a82 A |
732 | if (strncmp((char *)0xfffd9, "EISA", 4) == 0) |
733 | isEISA = TRUE; | |
734 | ||
735 | checked = TRUE; | |
14c7c974 A |
736 | } |
737 | ||
738 | return (isEISA); | |
739 | } | |
740 | ||
741 | int | |
742 | ReadEISASlotInfo(EISA_slot_info_t *ep, int slot) | |
743 | { | |
744 | union { | |
75b89a82 A |
745 | struct { |
746 | unsigned char char2h :2; | |
747 | unsigned char char1 :5; | |
748 | unsigned char char3 :5; | |
749 | unsigned char char2l :3; | |
750 | unsigned char d2 :4; | |
751 | unsigned char d1 :4; | |
752 | unsigned char d4 :4; | |
753 | unsigned char d3 :4; | |
754 | } s; | |
755 | unsigned char data[4]; | |
14c7c974 A |
756 | } u; |
757 | static char hex[0x10] = "0123456789ABCDEF"; | |
75b89a82 | 758 | |
14c7c974 A |
759 | |
760 | bb.intno = 0x15; | |
761 | bb.eax.r.h = 0xd8; | |
762 | bb.eax.r.l = 0x00; | |
763 | bb.ecx.r.l = slot; | |
764 | bios(&bb); | |
765 | if (bb.flags.cf) | |
75b89a82 | 766 | return bb.eax.r.h; |
14c7c974 A |
767 | ep->u_ID.d = bb.eax.r.l; |
768 | ep->configMajor = bb.ebx.r.h; | |
769 | ep->configMinor = bb.ebx.r.l; | |
770 | ep->checksum = bb.ecx.rr; | |
771 | ep->numFunctions = bb.edx.r.h; | |
772 | ep->u_resources.d = bb.edx.r.l; | |
773 | u.data[0] = bb.edi.r.l; | |
774 | u.data[1] = bb.edi.r.h; | |
775 | u.data[2] = bb.esi.r.l; | |
776 | u.data[3] = bb.esi.r.h; | |
777 | ep->id[0] = u.s.char1 + ('A' - 1); | |
778 | ep->id[1] = (u.s.char2l | (u.s.char2h << 3)) + ('A' - 1); | |
779 | ep->id[2] = u.s.char3 + ('A' - 1); | |
780 | ep->id[3] = hex[u.s.d1]; | |
781 | ep->id[4] = hex[u.s.d2]; | |
782 | ep->id[5] = hex[u.s.d3]; | |
783 | ep->id[6] = hex[u.s.d4]; | |
784 | ep->id[7] = 0; | |
785 | return 0; | |
786 | } | |
787 | ||
788 | /* | |
789 | * Note: ep must point to an address below 64k. | |
790 | */ | |
791 | ||
792 | int | |
793 | ReadEISAFuncInfo(EISA_func_info_t *ep, int slot, int function) | |
794 | { | |
795 | bb.intno = 0x15; | |
796 | bb.eax.r.h = 0xd8; | |
797 | bb.eax.r.l = 0x01; | |
798 | bb.ecx.r.l = slot; | |
799 | bb.ecx.r.h = function; | |
800 | bb.esi.rr = (unsigned int)ep->data; | |
801 | bios(&bb); | |
802 | if (bb.eax.r.h == 0) { | |
75b89a82 A |
803 | ep->slot = slot; |
804 | ep->function = function; | |
14c7c974 A |
805 | } |
806 | return bb.eax.r.h; | |
807 | } | |
75b89a82 | 808 | #endif /* EISA_SUPPORT */ |
14c7c974 A |
809 | |
810 | #define PCI_SIGNATURE 0x20494350 /* "PCI " */ | |
811 | ||
812 | int | |
813 | ReadPCIBusInfo(PCI_bus_info_t *pp) | |
814 | { | |
815 | bb.intno = 0x1a; | |
816 | bb.eax.r.h = 0xb1; | |
817 | bb.eax.r.l = 0x01; | |
818 | bios(&bb); | |
819 | if ((bb.eax.r.h == 0) && (bb.edx.rx == PCI_SIGNATURE)) { | |
75b89a82 A |
820 | pp->BIOSPresent = 1; |
821 | pp->u_bus.d = bb.eax.r.l; | |
822 | pp->majorVersion = bb.ebx.r.h; | |
823 | pp->minorVersion = bb.ebx.r.l; | |
824 | pp->maxBusNum = bb.ecx.r.l; | |
825 | return 0; | |
14c7c974 A |
826 | } |
827 | return -1; | |
828 | } | |
f083c6c3 A |
829 | |
830 | void sleep(int n) | |
831 | { | |
832 | unsigned int endtime = (time18() + 18*n); | |
833 | while (time18() < endtime); | |
834 | } | |
835 | ||
836 | void delay(int ms) | |
837 | { | |
838 | bb.intno = 0x15; | |
839 | bb.eax.r.h = 0x86; | |
840 | bb.ecx.rr = ms >> 16; | |
841 | bb.edx.rr = ms & 0xFFFF; | |
842 | bios(&bb); | |
843 | } | |
57c72a9a | 844 |