FreeBSD/Linux Kernel Cross Reference
sys/i386ps2/abios.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991 Carnegie Mellon University
4 * Copyright (c) 1991 IBM Corporation
5 * All Rights Reserved.
6 *
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation,
12 * and that the name IBM not be used in advertising or publicity
13 * pertaining to distribution of the software without specific, written
14 * prior permission.
15 *
16 * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 * School of Computer Science
24 * Carnegie Mellon University
25 * Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie Mellon
28 * the rights to redistribute these changes.
29 */
30
31 /*
32 * HISTORY
33 * $Log: abios.c,v $
34 * Revision 2.3 93/03/11 14:08:38 danner
35 * u_long -> u_int
36 * [93/03/09 danner]
37 *
38 * [93/03/09 danner]
39 *
40 * Revision 2.2 93/02/04 07:58:30 danner
41 * Integrate PS2 code from IBM.
42 * [93/01/18 prithvi]
43 *
44 */
45
46 #include <sys/types.h>
47
48 #include <mach/i386/vm_types.h>
49 #include <mach/i386/vm_param.h>
50 #include <i386/seg.h>
51 #include <i386ps2/abios.h>
52
53 /*
54 * We must adjust the bottom of the memory hole here.
55 * cnvmem doesn't count all the memory that ABIOS uses.
56 */
57 extern vm_offset_t hole_start;
58
59 #define MAX_SIZE 0xffff
60 #define BAD_DESCRIPT 0xffff
61 #define PTOV(x) (phystokv(x))
62
63 /*
64 * DEBUG must be defined if ABIOS_DEBUG is (get_dev is called from test_calls)
65 */
66 #define ABIOS_DEBUG 1
67
68 #if defined(ABIOS_DEBUG) && !defined(DEBUG)
69 #define DEBUG 1
70 #endif
71
72 #define MAXSEL 20
73 static struct selector_array code_array[MAXSEL] = {0};
74 static struct selector_array data_array[MAXSEL] = {0};
75 extern struct fake_descriptor gdt[];
76 struct Abios_header *abios_info = 0;
77
78 char *make_32();
79 u_short allocate_gdt();
80
81 #ifdef DEBUG
82 #define DEBUGF(x,y) if (x) y
83 char *get_dev();
84
85 int abiosdebug = 0;
86 #else
87 #define DEBUGF(x,y)
88 #endif
89
90 static struct real_descriptor *gdt_hint
91 = (struct real_descriptor *) &gdt[ABIOS_FIRST_AVAIL_SEL];
92 /* a hint for allocate_gdt */
93
94 /* put the variables referenced in init_ps2 in data */
95
96 abios_init()
97 {
98 struct Abios_header *abhp = abios_info;
99 int rc,i;
100 int data_count;
101
102 DEBUGF(abiosdebug,printf("abhp = %x\n",abhp));
103 if (abhp == 0) {
104 printf("ABIOS not found. Not initialized!\n");
105 return;
106 }
107 abhp = (struct Abios_header *) PTOV(abhp);
108
109 /* map the abios data area into virtual memory */
110 system_param_p = (struct System_parameter_table *)
111 PTOV(abhp->sys_table);
112
113 /* build addresses to get to the abios common data area */
114 anchor_pointer = (struct Common_data_area_head *)
115 PTOV(abhp->common_block);
116
117 if ((anchor_seg = allocate_gdt()) == BAD_DESCRIPT) {
118 printf("out of gdt for anchor_seg\n");
119 return(-1);
120 }
121 make_gdt_desc(anchor_seg,
122 (unsigned int) anchor_pointer,
123 anchor_pointer->data_ptr_0+7,
124 ACC_DATA_W,
125 0);
126
127
128 /* copy to the fake table before fixups.. */
129 bcopy(anchor_pointer,abios_common,anchor_pointer->data_ptr_0+8);
130
131 /*
132 * now fix up the logical device pointers
133 */
134 for (i=0; i < anchor_pointer->number_logical_ids; i++) {
135 fixup(&logical_device(i+1),i+1);
136 }
137
138 /*
139 * fix up the data pointers
140 */
141 data_count = *(u_short *)(data_pointer0 + 1);
142 for (i=0 ; i < data_count; i++) {
143 struct Data_pointer *dp = &data_pointer(i);
144
145 dp->dp_segment = (dp->dp_offset >> 4) + (dp->dp_segment << 12);
146 dp->dp_offset &= 0xf;
147 abios_convert(data_array, &(dp->dp_offset),
148 ACC_DATA_W, dp->dp_length);
149 }
150
151 /*
152 * build the fake anchor_pointer table
153 */
154 anchor_pointer = (struct Common_data_area_head *) abios_common;
155 for (i=0; i < anchor_pointer->number_logical_ids; i++) {
156 logical_device(i+1).device_block = (struct Device_block *)
157 make_32(logical_device(i+1).device_block);
158 logical_device(i+1).function_transfer_table =
159 (struct Function_transfer_table *)
160 make_32(logical_device(i+1).function_transfer_table);
161 }
162
163 /*
164 * fixup the common entry point stuff
165 */
166 abios_convert(code_array,&(system_param_p->common_start),
167 ACC_CODE_R, MAX_SIZE);
168 abios_convert(code_array,&(system_param_p->common_interrupt),
169 ACC_CODE_R, MAX_SIZE);
170 abios_convert(code_array,&(system_param_p->common_timeout),
171 ACC_CODE_R, MAX_SIZE);
172 return(0);
173 }
174
175 abios_common_start(request,flags)
176 struct generic_request *request;
177 int flags;
178 {
179 abios_xlate(system_param_p->common_start,request,flags);
180 }
181
182 abios_common_interrupt(request,flags)
183 struct generic_request *request;
184 int flags;
185 {
186 abios_xlate(system_param_p->common_interrupt,request,flags);
187 }
188
189 abios_common_timeout(request,flags)
190 struct generic_request *request;
191 int flags;
192 {
193 abios_xlate(system_param_p->common_timeout,request,flags);
194 }
195
196 abios_next_LID(dev_id,last_LID)
197 int last_LID;
198 {
199 int i;
200 struct Device_block *db;
201
202 if (abios_info == 0)
203 return(0); /* no abios - no LIDs */
204
205 for (i=last_LID+1; i <= anchor_pointer->number_logical_ids; i++) {
206 if (db = logical_device(i).device_block) {
207 if (db->device_id == dev_id) {
208 return(i);
209 }
210 }
211 }
212 /* no LID found */
213 return(0);
214 }
215
216 abios_xlate(abios_routine,request,flags)
217 char *abios_routine;
218 struct generic_request *request;
219 int flags;
220 {
221 u_short selector;
222 u_int req_addr;
223 u_int data_addr;
224 u_int save_data = 0;
225 int i,s;
226
227 selector = allocate_gdt();
228 if (selector == 0) {
229 panic("abios_xlate: out of selectors");
230 }
231 make_gdt_desc(selector,
232 (unsigned int) request,
233 request->r_current_req_blck_len,
234 ACC_DATA_W,
235 0);
236
237 req_addr = selector << 16;
238 if ((flags & LOG_POINTER) && ((request->r_function == ABIOS_READ) ||
239 (request->r_function == ABIOS_WRITE) ||
240 (request->r_function == ABIOS_ADDITIONAL_XFER))) {
241 u_short data_select = allocate_gdt();
242 if (data_select == 0) {
243 panic("abios_xlate: out of selectors");
244 }
245 data_addr = *((u_int *)&request->g_data_offset);
246 make_gdt_desc(data_select,
247 data_addr,
248 MAX_SIZE,
249 ACC_DATA_W,
250 0);
251 request->g_data_offset = 0;
252 request->g_data_selector = data_select;
253 save_data++;
254 }
255
256 req_addr = selector << 16;
257
258 abios_call(0,0,req_addr,anchor_seg,abios_routine,0,0,0,0);
259
260 if (save_data) {
261 free_gdt(request->g_data_selector);
262 *(u_int *)&request->g_data_offset = data_addr;
263 }
264 free_gdt(selector);
265 }
266
267 static int abios_last_addr = 0;
268 static struct Function_transfer_table *abios_ftt_array[50];
269
270 fixup(device,LID)
271 struct Logical_device *device;
272 int LID;
273 {
274 struct Function_transfer_table *ftt =
275 (struct Function_transfer_table *)make_32
276 (device->function_transfer_table);
277 struct Device_block *db = (struct Device_block *)
278 make_32(device->device_block);
279 int i;
280 int done;
281
282 DEBUGF(abiosdebug,printf("LID %x",LID));
283 if (ftt) {
284 DEBUGF(abiosdebug,printf(", %d functions, ftt=%x",ftt->function_count,ftt));
285 done = 0;
286 for (i=0; i < abios_last_addr; i++) {
287 if (ftt == abios_ftt_array[i]) {
288 done = 1;
289 DEBUGF(abiosdebug,printf(" (fixups already done)"));
290 break;
291 }
292 }
293 if (!done) {
294 abios_ftt_array[abios_last_addr++] = ftt;
295 abios_convert(code_array,&(ftt->start),
296 ACC_CODE_R, MAX_SIZE);
297 abios_convert(code_array,&(ftt->interrupt),
298 ACC_CODE_R, MAX_SIZE);
299 abios_convert(code_array,&(ftt->timeout),
300 ACC_CODE_R, MAX_SIZE);
301
302 /*
303 * first fix up the FTT
304 */
305 for (i=0; i < ftt->function_count; i++) {
306 abios_convert(code_array,&(ftt->function_call(i)),
307 ACC_CODE_R, MAX_SIZE);
308 }
309 }
310 abios_convert(data_array,&(device->function_transfer_table),
311 ACC_DATA_W, MAX_SIZE);
312 }
313 if (device->device_block) {
314 DEBUGF(abiosdebug,printf(", %s",get_dev(db->device_id)));
315 abios_convert(data_array,&(device->device_block),
316 ACC_DATA_W, MAX_SIZE);
317 }
318 DEBUGF(abiosdebug,printf("\n"));
319 }
320
321 struct far_pointer {
322 u_short offset;
323 u_short selector;
324 };
325
326 abios_convert(array,far_ptr,type,size)
327 struct selector_array *array;
328 struct far_pointer *far_ptr;
329 {
330 if (*(unsigned long *)far_ptr) {
331 far_ptr->selector =
332 get_selector(array,far_ptr->selector,type,size);
333 }
334 }
335
336 get_selector(array,segment,type,size)
337 struct selector_array *array;
338 u_short segment;
339 {
340 vm_offset_t addr;
341 int count = 0;
342
343 while (array->selector) {
344 if (array->segment == segment) {
345 return(array->selector);
346 }
347 array++;
348 count++;
349 }
350 if (count == MAXSEL) {
351 panic(" over allocated array\n");
352 }
353 array->selector = allocate_gdt();
354 array->segment = segment;
355 if (array->selector == 0) {
356 panic(" out of selectors\n");
357 }
358 addr = (vm_offset_t) make_32(segment << 16);
359 make_gdt_desc(array->selector,
360 addr,
361 size,
362 type,
363 0);
364
365 /*
366 * Adjust hole_start to be below the lowest segment
367 * mapped here. But don`t count segments below 0x1000 -
368 * we don`t use that for paging anyway. See i386_init.
369 *
370 * Addr is a virtual address; hole_start is physical.
371 */
372 addr = kvtophys(addr);
373 if (addr >= 0x1000) {
374 if (hole_start > addr)
375 hole_start = addr;
376 }
377 return(array->selector);
378 }
379
380 /*
381 * make_32 translates a dos real mode pointer (16 bit segment/16 bit offset)
382 * into a 386 flat mode paged vm pointer (32 bits).
383 * Called from several abios_init routines.
384 */
385 char *
386 make_32(value)
387 u_int value;
388 {
389 u_int phys = REALTOPHYS(value);
390 return(phys?(char *)PTOV(phys):(char *)0);
391 }
392
393 void display_request(rb_ptr)
394 struct generic_request *rb_ptr;
395 {
396
397 printf("The address of request block = %x\n\n",rb_ptr);
398 printf("The function = %d\n",rb_ptr->r_function);
399 printf("Current_req_block_len = %x\n",rb_ptr->r_current_req_blck_len);
400 printf("Logical_id = %x\n",rb_ptr->r_logical_id);
401 printf("Device ID = %x\n\n",rb_ptr->r_device_id);
402 printf("Unit = %x\n",rb_ptr->r_unit);
403 printf("Return_code = %x\n",rb_ptr->r_return_code);
404 printf("Time_out = %x\n",rb_ptr->r_time_out);
405 }
406
407
408
409 #ifdef DEBUG
410
411 /*
412 * print the ascii string for the abios device type found
413 */
414 static char *device_name[] = {
415 "ABIOS internal call", /* 0x00 */
416 "diskette", /* 0x01 */
417 "disk", /* 0x02 */
418 "video", /* 0x03 */
419 "keyboard", /* 0x04 */
420 "parallel port", /* 0x05 */
421 "async port", /* 0x06 */
422 "system timer", /* 0x07 */
423 "real-time clock", /* 0x08 */
424 "system services", /* 0x09 */
425 "NMI", /* 0x0a */
426 "mouse", /* 0x0b */
427 "reserved (0x0c)", /* 0x0c */
428 "reserved (0x0d)", /* 0x0d */
429 "NVRAM", /* 0x0e */
430 "DMA", /* 0x0f */
431 "POS", /* 0x10 */
432 "reserved (0x11)", /* 0x11 */
433 "reserved (0x12)", /* 0x12 */
434 "reserved (0x13)", /* 0x13 */
435 "reserved (0x14)", /* 0x14 */
436 "reserved (0x15)", /* 0x15 */
437 "keyboard security", /* 0x16 */
438 "reserved (0x17)", /* 0x17 */
439 };
440
441 static int known_device_ids=(sizeof(device_name)/sizeof(device_name[0]));
442
443 char *
444 get_dev(type)
445 u_int type;
446 {
447 if (type >= known_device_ids) {
448 static char buffer[] = "(unknown 0x--)";
449 static char hex[] = "0123456789ABCDEF";
450 buffer[11] = hex[(type>>4)&0xf];
451 buffer[12] = hex[type&0xf];
452 return(buffer);
453 }
454
455 return(device_name[type]);
456 }
457 #endif /* DEBUG */
458
459 #ifdef ABIOS_DEBUG
460
461 /* the following code is for testing only!!! */
462 static char *
463 map_irq (irq)
464 u_char irq;
465 {
466 static char buffer[30] = "irq00";
467 if (irq == 0xff) {
468 return("NoInt");
469 }
470 if (irq == 0xfe) {
471 return("NMI ");
472 }
473 buffer[3] = irq/10 + '';
474 buffer[4] = irq%10 + '';
475 return(buffer);
476 }
477
478 static char *
479 map_arb (arb)
480 u_char arb;
481 {
482 static char buffer[30] = "arb00 ";
483 if (arb == 0xff) {
484 return("NoArb");
485 }
486 buffer[3] = arb/10 + '';
487 buffer[4] = arb%10 + '';
488 return(buffer);
489 }
490
491 test_call()
492 {
493 int i;
494 struct generic_request req;
495
496
497 /* LID 1 is a dummy, LID 2 would call cause 'infinite' recursion..*/
498 for (i=2; i <= anchor_pointer->number_logical_ids; i++) {
499 int dev = ABIOS_ID;
500
501 if (logical_device(i).device_block) {
502 dev = logical_device(i).device_block->device_id;
503 }
504
505 if (dev != ABIOS_ID) {
506 req.r_current_req_blck_len =
507 sizeof(struct generic_request);
508 req.r_logical_id = i;
509 req.r_unit = 0;
510 req.r_function = ABIOS_LOGICAL_PARAMETER;
511 req.r_return_code = ABIOS_UNDEFINED;
512 abios_common_start(&req,0);
513 } else {
514 req.r_hardware_intr = 0xff;
515 req.r_arbitration_level = 0xff;
516 req.r_number_units = 0;
517 req.r_request_block_length =
518 sizeof(struct generic_request);
519 req.r_logical_id_flags = 0;
520 req.r_return_code = 0;
521 }
522 printf("device %02x LID %02x",dev,i);
523 if (req.r_return_code == 0) {
524 printf(" %s %s units=%d size=%3d flags=%04x",
525 map_irq(req.r_hardware_intr),
526 map_arb(req.r_arbitration_level),req.r_number_units,
527 req.r_request_block_length,req.r_logical_id_flags);
528 } else {
529 printf("ERROR, rc=0x%04x",req.r_return_code);
530 }
531 printf(": %s\n",get_dev(dev));
532 }
533 }
534 #endif /* ABIOS_DEBUG */
535
536
537 int_on_ABIOS()
538 {
539 panic("interrupt on ABIOS stack");
540 /* NOTREACHED */
541 }
542
543 trap_on_ABIOS()
544 {
545 panic("trap on ABIOS stack");
546 /* NOTREACHED */
547 }
548
Cache object: 19e9ce80f29aee88eb9124a462121da4
|