VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS-new/system.c@ 38699

Last change on this file since 38699 was 38699, checked in by vboxsync, 13 years ago

Converted system BIOS to Watcom C.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.3 KB
Line 
1/*
2 * Copyright (C) 2006-2011 Oracle Corporation
3 *
4 * This file is part of VirtualBox Open Source Edition (OSE), as
5 * available from http://www.virtualbox.org. This file is free software;
6 * you can redistribute it and/or modify it under the terms of the GNU
7 * General Public License (GPL) as published by the Free Software
8 * Foundation, in version 2 as it comes in the "COPYING" file of the
9 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11 * --------------------------------------------------------------------
12 *
13 * This code is based on:
14 *
15 * ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
16 *
17 * Copyright (C) 2002 MandrakeSoft S.A.
18 *
19 * MandrakeSoft S.A.
20 * 43, rue d'Aboukir
21 * 75002 Paris - France
22 * http://www.linux-mandrake.com/
23 * http://www.mandrakesoft.com/
24 *
25 * This library is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU Lesser General Public
27 * License as published by the Free Software Foundation; either
28 * version 2 of the License, or (at your option) any later version.
29 *
30 * This library is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 * Lesser General Public License for more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public
36 * License along with this library; if not, write to the Free Software
37 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
38 *
39 */
40
41
42#include <stdint.h>
43#include "biosint.h"
44#include "inlines.h"
45#include "ebda.h"
46
47#if DEBUG_INT15
48# define BX_DEBUG_INT15(...) BX_DEBUG(__VA_ARGS__)
49#else
50# define BX_DEBUG_INT15(...)
51#endif
52
53
54#define UNSUPPORTED_FUNCTION 0x86 /* Specific to INT 15h. */
55
56#define BIOS_CONFIG_TABLE 0xe6f5 /* TODO: configurable? put elsewhere? */
57
58#define ACPI_DATA_SIZE 0x00010000L /* TODO: configurable? put elsewhere? */
59
60#define BX_CPU 3
61
62extern int pmode_IDT;
63extern int rmode_IDT;
64
65uint16_t read_ss(void);
66#pragma aux read_ss = "mov ax, ss" modify exact [ax] nomemory;
67
68void pm_stack_save(uint16_t cx, uint16_t es, uint16_t si);
69#pragma aux pm_stack_save = \
70 ".386" \
71 "push ds" \
72 "push eax" \
73 "xor eax, eax" \
74 "mov ds, ax" \
75 "mov ds:[467h], sp" \
76 "mov ds:[469h], ss" \
77 parm [cx] [es] [si] modify nomemory;
78
79/* Uses position independent code... because it was too hard to figure
80 * out how to code the far call in inline assembler.
81 */
82void pm_enter(void);
83#pragma aux pm_enter = \
84 ".386p" \
85 "call pentry" \
86 "pentry:" \
87 "pop di" \
88 "add di, 1Bh" \
89 "push 20h" \
90 "push di" \
91 "lgdt fword ptr es:[si+8]" \
92 "lidt fword ptr cs:pmode_IDT" \
93 "mov eax, cr0" \
94 "or al, 1" \
95 "mov cr0, eax" \
96 "retf" \
97 "pm_pm:" \
98 "mov ax, 28h" \
99 "mov ss, ax" \
100 "mov ax, 10h" \
101 "mov ds, ax" \
102 "mov ax, 18h" \
103 "mov es, ax" \
104 modify nomemory;
105
106void pm_copy(void);
107#pragma aux pm_copy = \
108 "xor si, si" \
109 "xor di, di" \
110 "cld" \
111 "rep movsw" \
112 modify nomemory;
113
114/* Restore segment limits to real mode compatible values and
115 * return to real mode.
116 */
117void pm_exit(void);
118#pragma aux pm_exit = \
119 ".386p" \
120 "call pexit" \
121 "pexit:" \
122 "pop ax" \
123 "push 0F000h" \
124 "add ax, 18h" \
125 "push ax" \
126 "mov ax, 28h" \
127 "mov ds, ax" \
128 "mov es, ax" \
129 "mov eax, cr0" \
130 "and al, 0FEh" \
131 "mov cr0, eax" \
132 "retf" \
133 "real_mode:" \
134 "lidt fword ptr cs:rmode_IDT" \
135 modify nomemory;
136
137void pm_stack_restore(void);
138#pragma aux pm_stack_restore = \
139 ".386" \
140 "xor ax, ax" \
141 "mov ds, ax" \
142 "lss sp, ds:[467h]" \
143 "pop eax" \
144 "pop ds" \
145 modify nomemory;
146
147/* The pm_switch has a few crucial differences from pm_enter, hence
148 * it is replicated here. Uses LMSW to avoid trashing high word of eax.
149 */
150void pm_switch(uint16_t reg_si);
151#pragma aux pm_switch = \
152 ".286p" \
153 "call pentry" \
154 "pentry:" \
155 "pop di" \
156 "add di, 18h" \
157 "push 38h" \
158 "push di" \
159 "lgdt fword ptr es:[si+08h]" \
160 "lidt fword ptr es:[si+10h]" \
161 "mov ax, 1" \
162 "lmsw ax" \
163 "retf" \
164 "pm_pm:" \
165 "mov ax, 28h" \
166 "mov ss, ax" \
167 "mov ax, 18h" \
168 "mov ds, ax" \
169 "mov ax, 20h" \
170 "mov es, ax" \
171 parm [si] modify nomemory;
172
173/* Return to caller - we do not use IRET because we should not enable
174 * interrupts. Note that AH must be zero on exit.
175 * WARNING: Needs to be adapted if calling sequence is modified!
176 */
177void pm_unwind(uint16_t args);
178#pragma aux pm_unwind = \
179 ".286" \
180 "mov sp, ax" \
181 "popa" \
182 "add sp, 6" \
183 "pop cx" \
184 "pop ax" \
185 "pop ax" \
186 "mov ax, 30h" \
187 "push ax" \
188 "push cx" \
189 "retf" \
190 parm [ax] modify nomemory aborts;
191
192// @todo: This method is silly. The RTC should be programmed to fire an interrupt
193// instead of hogging the CPU with inaccurate code.
194void timer_wait(uint16_t lo, uint16_t hi);
195#pragma aux timer_wait = \
196 ".386" \
197 "shl eax, 16" \
198 "mov ax, dx" \
199 "mov ebx, 15" \
200 "xor edx, edx" \
201 "div ebx" \
202 "mov ecx, eax" \
203 "in al, 61h" \
204 "and al, 10h" \
205 "mov ah, al" \
206 "or ecx, ecx" \
207 "je int1586_tick_end" \
208 "int1586_tick:" \
209 "in al, 61h" \
210 "and al, 10h" \
211 "cmp al, ah" \
212 "je int1586_tick" \
213 "mov ah, al" \
214 "dec ecx" \
215 "jnz int1586_tick" \
216 "int1586_tick_end:" \
217 parm [dx] [ax] modify [bx cx] nomemory;
218
219
220bx_bool set_enable_a20(bx_bool val)
221{
222 uint8_t oldval;
223
224 // Use PS/2 System Control port A to set A20 enable
225
226 // get current setting first
227 oldval = inb(0x92);
228
229 // change A20 status
230 if (val)
231 outb(0x92, oldval | 0x02);
232 else
233 outb(0x92, oldval & 0xfd);
234
235 return((oldval & 0x02) != 0);
236}
237
238typedef struct {
239 uint32_t start;
240 uint32_t xstart;
241 uint32_t len;
242 uint32_t xlen;
243 uint32_t type;
244} mem_range_t;
245
246void set_e820_range(uint16_t ES, uint16_t DI, uint32_t start, uint32_t end,
247 uint8_t extra_start, uint8_t extra_end, uint16_t type)
248{
249 mem_range_t __far *range;
250
251 range = ES :> (mem_range_t *)DI;
252 range->start = start;
253 range->xstart = extra_start;
254 end -= start;
255 extra_end -= extra_start;
256 range->len = end;
257 range->xlen = extra_end;
258 range->type = type;
259}
260
261// @todo: move elsewhere?
262#define AX r.gr.u.r16.ax
263#define BX r.gr.u.r16.bx
264#define CX r.gr.u.r16.cx
265#define DX r.gr.u.r16.dx
266#define SI r.gr.u.r16.si
267#define DI r.gr.u.r16.di
268#define BP r.gr.u.r16.bp
269#define SP r.gr.u.r16.sp
270#define FLAGS r.fl.u.r16.flags
271#define EAX r.gr.u.r32.eax
272#define EBX r.gr.u.r32.ebx
273#define ECX r.gr.u.r32.ecx
274#define EDX r.gr.u.r32.edx
275#define ES r.es
276
277
278void BIOSCALL int15_function(sys_regs_t r)
279{
280 uint16_t ebda_seg=read_word(0x0040,0x000E);
281 bx_bool prev_a20_enable;
282 uint16_t base15_00;
283 uint8_t base23_16;
284 uint16_t ss;
285 uint16_t bRegister;
286 uint8_t irqDisable;
287
288 BX_DEBUG_INT15("int15 AX=%04x\n",AX);
289
290 switch (GET_AH()) {
291 case 0x00: /* assorted functions */
292 if (GET_AL() != 0xc0)
293 goto undecoded;
294 /* GRUB calls int15 with ax=0x00c0 to get the ROM configuration table,
295 * which we don't support, but logging that event is annoying. In fact
296 * it is likely that they just misread some specs, because there is a
297 * int15 BIOS function AH=0xc0 which sounds quite similar to what GRUB
298 * wants to achieve. */
299 SET_CF();
300 SET_AH(UNSUPPORTED_FUNCTION);
301 break;
302 case 0x24: /* A20 Control */
303 switch (GET_AL()) {
304 case 0x00:
305 set_enable_a20(0);
306 CLEAR_CF();
307 SET_AH(0);
308 break;
309 case 0x01:
310 set_enable_a20(1);
311 CLEAR_CF();
312 SET_AH(0);
313 break;
314 case 0x02:
315 SET_AL( (inb(0x92) >> 1) & 0x01 );
316 CLEAR_CF();
317 SET_AH(0);
318 break;
319 case 0x03:
320 CLEAR_CF();
321 SET_AH(0);
322 BX = 3;
323 break;
324 default:
325 BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) GET_AL());
326 SET_CF();
327 SET_AH(UNSUPPORTED_FUNCTION);
328 }
329 break;
330
331 case 0x41:
332 SET_CF();
333 SET_AH(UNSUPPORTED_FUNCTION);
334 break;
335
336 //@todo: Why does this need special handling? All we need is to set CF
337 // but not handle this as an unknown function (regardless of CPU type).
338 case 0x4f:
339 /* keyboard intercept */
340#if BX_CPU < 2
341 SET_AH(UNSUPPORTED_FUNCTION);
342#else
343 // nop
344#endif
345 SET_CF();
346 break;
347
348 case 0x52: // removable media eject
349 CLEAR_CF();
350 SET_AH(0); // "ok ejection may proceed"
351 break;
352
353 case 0x83: {
354 if( GET_AL() ) {
355 // Set Interval requested.
356 if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
357 // Interval not already set.
358 write_byte( 0x40, 0xA0, 1 ); // Set status byte.
359 write_word( 0x40, 0x98, ES ); // Byte location, segment
360 write_word( 0x40, 0x9A, BX ); // Byte location, offset
361 write_word( 0x40, 0x9C, DX ); // Low word, delay
362 write_word( 0x40, 0x9E, CX ); // High word, delay.
363 CLEAR_CF( );
364 irqDisable = inb( 0xA1 );
365 outb( 0xA1, irqDisable & 0xFE );
366 bRegister = inb_cmos( 0xB ); // Unmask IRQ8 so INT70 will get through.
367 outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
368 } else {
369 // Interval already set.
370 BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
371 SET_CF();
372 SET_AH(UNSUPPORTED_FUNCTION);
373 }
374 } else if( GET_AL() == 1 ) {
375 // Clear Interval requested
376 write_byte( 0x40, 0xA0, 0 ); // Clear status byte
377 CLEAR_CF( );
378 bRegister = inb_cmos( 0xB );
379 outb_cmos( 0xB, bRegister & ~0x40 ); // Turn off the Periodic Interrupt timer
380 } else {
381 BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
382 SET_CF();
383 SET_AH(UNSUPPORTED_FUNCTION);
384 SET_AL(GET_AL() - 1);
385 }
386
387 break;
388 }
389
390 case 0x87:
391#if BX_CPU < 3
392 SET_AH(UNSUPPORTED_FUNCTION);
393 SET_CF();
394#endif
395 // +++ should probably have descriptor checks
396 // +++ should have exception handlers
397
398 // turn off interrupts
399 int_disable(); //@todo: aren't they disabled already?
400
401 prev_a20_enable = set_enable_a20(1); // enable A20 line
402
403 // 128K max of transfer on 386+ ???
404 // source == destination ???
405
406 // ES:SI points to descriptor table
407 // offset use initially comments
408 // ==============================================
409 // 00..07 Unused zeros Null descriptor
410 // 08..0f GDT zeros filled in by BIOS
411 // 10..17 source ssssssss source of data
412 // 18..1f dest dddddddd destination of data
413 // 20..27 CS zeros filled in by BIOS
414 // 28..2f SS zeros filled in by BIOS
415
416 //es:si
417 //eeee0
418 //0ssss
419 //-----
420
421 // check for access rights of source & dest here
422
423 // Initialize GDT descriptor
424 base15_00 = (ES << 4) + SI;
425 base23_16 = ES >> 12;
426 if (base15_00 < (ES<<4))
427 base23_16++;
428 write_word(ES, SI+0x08+0, 47); // limit 15:00 = 6 * 8bytes/descriptor
429 write_word(ES, SI+0x08+2, base15_00);// base 15:00
430 write_byte(ES, SI+0x08+4, base23_16);// base 23:16
431 write_byte(ES, SI+0x08+5, 0x93); // access
432 write_word(ES, SI+0x08+6, 0x0000); // base 31:24/reserved/limit 19:16
433
434 // Initialize CS descriptor
435 write_word(ES, SI+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
436 write_word(ES, SI+0x20+2, 0x0000);// base 15:00
437 write_byte(ES, SI+0x20+4, 0x000f);// base 23:16
438 write_byte(ES, SI+0x20+5, 0x9b); // access
439 write_word(ES, SI+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
440
441 // Initialize SS descriptor
442 ss = read_ss();
443 base15_00 = ss << 4;
444 base23_16 = ss >> 12;
445 write_word(ES, SI+0x28+0, 0xffff); // limit 15:00 = normal 64K limit
446 write_word(ES, SI+0x28+2, base15_00);// base 15:00
447 write_byte(ES, SI+0x28+4, base23_16);// base 23:16
448 write_byte(ES, SI+0x28+5, 0x93); // access
449 write_word(ES, SI+0x28+6, 0x0000); // base 31:24/reserved/limit 19:16
450
451 pm_stack_save(CX, ES, SI);
452 pm_enter();
453 pm_copy();
454 pm_exit();
455 pm_stack_restore();
456
457 set_enable_a20(prev_a20_enable);
458
459 // turn interrupts back on
460 int_enable();
461
462 SET_AH(0);
463 CLEAR_CF();
464 break;
465
466 case 0x88:
467 // Get the amount of extended memory (above 1M)
468#if BX_CPU < 2
469 SET_AH(UNSUPPORTED_FUNCTION);
470 SET_CF();
471#else
472 AX = (inb_cmos(0x31) << 8) | inb_cmos(0x30);
473
474 // According to Ralf Brown's interrupt the limit should be 15M,
475 // but real machines mostly return max. 63M.
476 if(AX > 0xffc0)
477 AX = 0xffc0;
478
479 CLEAR_CF();
480#endif
481 break;
482
483 case 0x89:
484 // Switch to Protected Mode.
485 // ES:DI points to user-supplied GDT
486 // BH/BL contains starting interrupt numbers for PIC0/PIC1
487 // This subfunction does not return!
488
489 // turn off interrupts
490 int_disable(); //@todo: aren't they off already?
491
492 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
493
494 // Initialize CS descriptor for BIOS
495 write_word(ES, SI+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
496 write_word(ES, SI+0x38+2, 0x0000);// base 15:00
497 write_byte(ES, SI+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
498 write_byte(ES, SI+0x38+5, 0x9b); // access
499 write_word(ES, SI+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
500
501 /* Reprogram the PICs. */
502 outb(PIC_MASTER, PIC_CMD_INIT);
503 outb(PIC_SLAVE, PIC_CMD_INIT);
504 outb(PIC_MASTER + 1, GET_BH());
505 outb(PIC_SLAVE + 1, GET_BL());
506 outb(PIC_MASTER + 1, 4);
507 outb(PIC_SLAVE + 1, 2);
508 outb(PIC_MASTER + 1, 1);
509 outb(PIC_SLAVE + 1, 1);
510 /* Mask all IRQs, user must re-enable. */
511 outb(PIC_MASTER_MASK, 0xff);
512 outb(PIC_SLAVE_MASK, 0xff);
513
514 pm_switch(SI);
515 pm_unwind((uint16_t)&r);
516
517 break;
518
519 case 0x90:
520 /* Device busy interrupt. Called by Int 16h when no key available */
521 break;
522
523 case 0x91:
524 /* Interrupt complete. Called by Int 16h when key becomes available */
525 break;
526
527 case 0xbf:
528 BX_INFO("*** int 15h function AH=bf not yet supported!\n");
529 SET_CF();
530 SET_AH(UNSUPPORTED_FUNCTION);
531 break;
532
533 case 0xC0:
534 CLEAR_CF();
535 SET_AH(0);
536 BX = BIOS_CONFIG_TABLE;
537 ES = 0xF000;
538 break;
539
540 case 0xc1:
541 ES = ebda_seg;
542 CLEAR_CF();
543 break;
544
545 case 0xd8:
546 bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
547 SET_CF();
548 SET_AH(UNSUPPORTED_FUNCTION);
549 break;
550
551 /* Make the BIOS warning for pretty much every Linux kernel start
552 * disappear - it calls with ax=0xe980 to figure out SMI info. */
553 case 0xe9: /* SMI functions (SpeedStep and similar things) */
554 SET_CF();
555 SET_AH(UNSUPPORTED_FUNCTION);
556 break;
557 case 0xec: /* AMD64 target operating mode callback */
558 if (GET_AL() != 0)
559 goto undecoded;
560 SET_AH(0);
561 if (GET_BL() >= 1 && GET_BL() <= 3)
562 CLEAR_CF(); /* Accepted value. */
563 else
564 SET_CF(); /* Reserved, error. */
565 break;
566undecoded:
567 default:
568 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
569 (unsigned) AX, (unsigned) BX_APM);
570 SET_CF();
571 SET_AH(UNSUPPORTED_FUNCTION);
572 break;
573 }
574}
575
576void BIOSCALL int15_function32(sys32_regs_t r)
577{
578 uint32_t extended_memory_size=0; // 64bits long
579 uint32_t extra_lowbits_memory_size=0;
580 uint8_t extra_highbits_memory_size=0;
581 uint32_t mcfgStart, mcfgSize;
582
583 BX_DEBUG_INT15("int15 AX=%04x\n",AX);
584
585 switch (GET_AH()) {
586 case 0x86:
587 // Wait for CX:DX microseconds. currently using the
588 // refresh request port 0x61 bit4, toggling every 15usec
589 int_enable();
590 timer_wait(DX, CX);
591 break;
592
593 case 0xe8:
594 switch(GET_AL()) {
595 case 0x20: // coded by osmaker aka K.J.
596 if(EDX == 0x534D4150) {
597 extended_memory_size = inb_cmos(0x35);
598 extended_memory_size <<= 8;
599 extended_memory_size |= inb_cmos(0x34);
600 extended_memory_size *= 64;
601#ifndef VBOX /* The following excludes 0xf0000000 thru 0xffffffff. Trust DevPcBios.cpp to get this right. */
602 // greater than EFF00000???
603 if(extended_memory_size > 0x3bc000) {
604 extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
605 }
606#endif /* !VBOX */
607 extended_memory_size *= 1024;
608 extended_memory_size += (16L * 1024 * 1024);
609
610 if(extended_memory_size <= (16L * 1024 * 1024)) {
611 extended_memory_size = inb_cmos(0x31);
612 extended_memory_size <<= 8;
613 extended_memory_size |= inb_cmos(0x30);
614 extended_memory_size *= 1024;
615 extended_memory_size += (1L * 1024 * 1024);
616 }
617
618#ifdef VBOX /* We've already used the CMOS entries for SATA.
619 BTW. This is the amount of memory above 4GB measured in 64KB units. */
620 extra_lowbits_memory_size = inb_cmos(0x62);
621 extra_lowbits_memory_size <<= 8;
622 extra_lowbits_memory_size |= inb_cmos(0x61);
623 extra_lowbits_memory_size <<= 16;
624 extra_highbits_memory_size = inb_cmos(0x63);
625 /* 0x64 and 0x65 can be used if we need to dig 1 TB or more at a later point. */
626#else
627 extra_lowbits_memory_size = inb_cmos(0x5c);
628 extra_lowbits_memory_size <<= 8;
629 extra_lowbits_memory_size |= inb_cmos(0x5b);
630 extra_lowbits_memory_size *= 64;
631 extra_lowbits_memory_size *= 1024;
632 extra_highbits_memory_size = inb_cmos(0x5d);
633#endif /* !VBOX */
634
635 mcfgStart = 0;
636 mcfgSize = 0;
637
638 switch(BX)
639 {
640 case 0:
641 set_e820_range(ES, DI,
642#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
643 0x0000000L, 0x0009f000L, 0, 0, 1);
644#else
645 0x0000000L, 0x0009fc00L, 0, 0, 1);
646#endif
647 EBX = 1;
648 break;
649 case 1:
650 set_e820_range(ES, DI,
651#ifndef VBOX /** @todo Upstream suggests the following, needs checking. (see next as well) */
652 0x0009f000L, 0x000a0000L, 0, 0, 2);
653#else
654 0x0009fc00L, 0x000a0000L, 0, 0, 2);
655#endif
656 EBX = 2;
657 break;
658 case 2:
659#ifdef VBOX
660 /* Mark the BIOS as reserved. VBox doesn't currently
661 * use the 0xe0000-0xeffff area. It does use the
662 * 0xd0000-0xdffff area for the BIOS logo, but it's
663 * not worth marking it as reserved. (this is not
664 * true anymore because the VGA adapter handles the logo stuff)
665 * The whole 0xe0000-0xfffff can be used for the BIOS.
666 * Note that various
667 * Windows versions don't accept (read: in debug builds
668 * they trigger the "Too many similar traps" assertion)
669 * a single reserved range from 0xd0000 to 0xffffff.
670 * A 128K area starting from 0xd0000 works. */
671 set_e820_range(ES, DI,
672 0x000f0000L, 0x00100000L, 0, 0, 2);
673#else /* !VBOX */
674 set_e820_range(ES, DI,
675 0x000e8000L, 0x00100000L, 0, 0, 2);
676#endif /* !VBOX */
677 EBX = 3;
678 break;
679 case 3:
680#if BX_ROMBIOS32 || defined(VBOX)
681 set_e820_range(ES, DI,
682 0x00100000L,
683 extended_memory_size - ACPI_DATA_SIZE, 0, 0, 1);
684 EBX = 4;
685#else
686 set_e820_range(ES, DI,
687 0x00100000L,
688 extended_memory_size, 1);
689 EBX = 5;
690#endif
691 break;
692 case 4:
693 set_e820_range(ES, DI,
694 extended_memory_size - ACPI_DATA_SIZE,
695 extended_memory_size, 0, 0, 3); // ACPI RAM
696 EBX = 5;
697 break;
698 case 5:
699 /* 256KB BIOS area at the end of 4 GB */
700#ifdef VBOX
701 /* We don't set the end to 1GB here and rely on the 32-bit
702 unsigned wrap around effect (0-0xfffc0000L). */
703#endif
704 set_e820_range(ES, DI,
705 0xfffc0000L, 0x00000000L, 0, 0, 2);
706 if (mcfgStart != 0)
707 EBX = 6;
708 else
709 {
710 if (extra_highbits_memory_size || extra_lowbits_memory_size)
711 EBX = 7;
712 else
713 EBX = 0;
714 }
715 break;
716 case 6:
717 /* PCI MMIO config space (MCFG) */
718 set_e820_range(ES, DI,
719 mcfgStart, mcfgStart + mcfgSize, 0, 0, 2);
720
721 if (extra_highbits_memory_size || extra_lowbits_memory_size)
722 EBX = 7;
723 else
724 EBX = 0;
725 break;
726 case 7:
727#ifdef VBOX /* Don't succeeded if no memory above 4 GB. */
728 /* Mapping of memory above 4 GB if present.
729 Note: set_e820_range needs do no borrowing in the
730 subtraction because of the nice numbers. */
731 if (extra_highbits_memory_size || extra_lowbits_memory_size)
732 {
733 set_e820_range(ES, DI,
734 0x00000000L, extra_lowbits_memory_size,
735 1 /*GB*/, extra_highbits_memory_size + 1 /*GB*/, 1);
736 EBX = 0;
737 }
738 break;
739 /* fall thru */
740#else /* !VBOX */
741 /* Mapping of memory above 4 GB */
742 set_e820_range(ES, DI, 0x00000000L,
743 extra_lowbits_memory_size, 1, extra_highbits_memory_size
744 + 1, 1);
745 EBX = 0;
746 break;
747#endif /* !VBOX */
748 default: /* AX=E820, DX=534D4150, BX unrecognized */
749 goto int15_unimplemented;
750 break;
751 }
752 EAX = 0x534D4150;
753 ECX = 0x14;
754 CLEAR_CF();
755 } else {
756 // if DX != 0x534D4150)
757 goto int15_unimplemented;
758 }
759 break;
760
761 case 0x01:
762 // do we have any reason to fail here ?
763 CLEAR_CF();
764
765 // my real system sets ax and bx to 0
766 // this is confirmed by Ralph Brown list
767 // but syslinux v1.48 is known to behave
768 // strangely if ax is set to 0
769 // regs.u.r16.ax = 0;
770 // regs.u.r16.bx = 0;
771
772 // Get the amount of extended memory (above 1M)
773 CX = (inb_cmos(0x31) << 8) | inb_cmos(0x30);
774
775 // limit to 15M
776 if(CX > 0x3c00)
777 CX = 0x3c00;
778
779 // Get the amount of extended memory above 16M in 64k blocks
780 DX = (inb_cmos(0x35) << 8) | inb_cmos(0x34);
781
782 // Set configured memory equal to extended memory
783 AX = CX;
784 BX = DX;
785 break;
786 default: /* AH=0xE8?? but not implemented */
787 goto int15_unimplemented;
788 }
789 break;
790 int15_unimplemented:
791 // fall into the default case
792 default:
793 BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
794 (unsigned) AX, (unsigned) BX);
795 SET_CF();
796 SET_AL(UNSUPPORTED_FUNCTION);
797 break;
798 }
799}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use