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