mirror of
https://github.com/ipxe/ipxe
synced 2025-12-23 21:41:43 +03:00
Merged mcb30-realmode-redesign back to HEAD
This commit is contained in:
@@ -3,11 +3,11 @@
|
||||
* Body of routines taken from old pcbios.S
|
||||
*/
|
||||
|
||||
#ifdef PCBIOS
|
||||
|
||||
#include "etherboot.h"
|
||||
#include "stdint.h"
|
||||
#include "realmode.h"
|
||||
#include "segoff.h"
|
||||
#include "compiler.h"
|
||||
|
||||
#define BIOS_DATA_SEG 0x0040
|
||||
|
||||
#define CF ( 1 << 0 )
|
||||
|
||||
@@ -23,133 +23,101 @@ timeofday BIOS interrupt.
|
||||
#define CONFIG_BIOS_CURRTICKS 1
|
||||
#endif
|
||||
#if defined(CONFIG_BIOS_CURRTICKS)
|
||||
unsigned long currticks (void)
|
||||
{
|
||||
unsigned long currticks ( void ) {
|
||||
static uint32_t days = 0;
|
||||
uint32_t *ticks = VIRTUAL(0x0040,0x006c);
|
||||
uint8_t *midnight = VIRTUAL(0x0040,0x0070);
|
||||
uint32_t ticks;
|
||||
uint8_t midnight;
|
||||
|
||||
/* Re-enable interrupts so that the timer interrupt can occur
|
||||
*/
|
||||
RM_FRAGMENT(rm_currticks,
|
||||
"sti\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"cli\n\t"
|
||||
);
|
||||
REAL_EXEC ( rm_currticks,
|
||||
"sti\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"cli\n\t",
|
||||
0,
|
||||
OUT_CONSTRAINTS (),
|
||||
IN_CONSTRAINTS (),
|
||||
CLOBBER ( "eax" ) ); /* can't have an empty clobber list */
|
||||
|
||||
real_call ( rm_currticks, NULL, NULL );
|
||||
get_real ( ticks, BIOS_DATA_SEG, 0x006c );
|
||||
get_real ( midnight, BIOS_DATA_SEG, 0x0070 );
|
||||
|
||||
if ( *midnight ) {
|
||||
*midnight = 0;
|
||||
if ( midnight ) {
|
||||
midnight = 0;
|
||||
put_real ( midnight, BIOS_DATA_SEG, 0x0070 );
|
||||
days += 0x1800b0;
|
||||
}
|
||||
return ( days + *ticks );
|
||||
return ( days + ticks );
|
||||
}
|
||||
#endif /* CONFIG_BIOS_CURRTICKS */
|
||||
|
||||
/**************************************************************************
|
||||
INT15 - Call Interrupt 0x15
|
||||
**************************************************************************/
|
||||
int int15 ( int ax )
|
||||
{
|
||||
struct {
|
||||
reg16_t ax;
|
||||
} PACKED in_stack;
|
||||
struct {
|
||||
reg16_t flags;
|
||||
} PACKED out_stack;
|
||||
reg16_t ret_ax;
|
||||
|
||||
RM_FRAGMENT(rm_int15,
|
||||
"sti\n\t"
|
||||
"popw %ax\n\t"
|
||||
"stc\n\t"
|
||||
"int $0x15\n\t"
|
||||
"pushf\n\t"
|
||||
"cli\n\t"
|
||||
);
|
||||
|
||||
in_stack.ax.word = ax;
|
||||
ret_ax.word = real_call ( rm_int15, &in_stack, &out_stack );
|
||||
|
||||
/* Carry flag clear indicates function not supported */
|
||||
if ( ! ( out_stack.flags.word & CF ) ) return 0;
|
||||
return ret_ax.h;
|
||||
}
|
||||
|
||||
#ifdef POWERSAVE
|
||||
/**************************************************************************
|
||||
CPU_NAP - Save power by halting the CPU until the next interrupt
|
||||
**************************************************************************/
|
||||
void cpu_nap ( void )
|
||||
{
|
||||
RM_FRAGMENT(rm_cpu_nap,
|
||||
"sti\n\t"
|
||||
"hlt\n\t"
|
||||
"cli\n\t"
|
||||
);
|
||||
|
||||
real_call ( rm_cpu_nap, NULL, NULL );
|
||||
void cpu_nap ( void ) {
|
||||
REAL_EXEC ( rm_cpu_nap,
|
||||
"sti\n\t"
|
||||
"hlt\n\t"
|
||||
"cli\n\t",
|
||||
0,
|
||||
OUT_CONSTRAINTS (),
|
||||
IN_CONSTRAINTS (),
|
||||
CLOBBER ( "eax" ) ); /* can't have an empty clobber list */
|
||||
}
|
||||
#endif /* POWERSAVE */
|
||||
|
||||
#if (TRY_FLOPPY_FIRST > 0)
|
||||
/**************************************************************************
|
||||
DISK_INIT - Initialize the disk system
|
||||
**************************************************************************/
|
||||
void disk_init ( void )
|
||||
{
|
||||
RM_FRAGMENT(rm_disk_init,
|
||||
"sti\n\t"
|
||||
"xorw %ax,%ax\n\t"
|
||||
"movb $0x80,%dl\n\t"
|
||||
"int $0x13\n\t"
|
||||
"cli\n\t"
|
||||
);
|
||||
|
||||
real_call ( rm_disk_init, NULL, NULL );
|
||||
void disk_init ( void ) {
|
||||
REAL_EXEC ( rm_disk_init,
|
||||
"sti\n\t"
|
||||
"xorw %ax,%ax\n\t"
|
||||
"movb $0x80,%dl\n\t"
|
||||
"int $0x13\n\t"
|
||||
"cli\n\t",
|
||||
0,
|
||||
OUT_CONSTRAINTS (),
|
||||
IN_CONSTRAINTS (),
|
||||
CLOBBER ( "eax", "ebx", "ecx", "edx",
|
||||
"ebp", "esi", "edi" ) );
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
DISK_READ - Read a sector from disk
|
||||
**************************************************************************/
|
||||
unsigned int pcbios_disk_read ( int drive, int cylinder, int head, int sector,
|
||||
char *buf ) {
|
||||
struct {
|
||||
reg16_t ax;
|
||||
reg16_t cx;
|
||||
reg16_t dx;
|
||||
segoff_t buffer;
|
||||
} PACKED in_stack;
|
||||
struct {
|
||||
reg16_t flags;
|
||||
} PACKED out_stack;
|
||||
reg16_t ret_ax;
|
||||
char *fixme_buf ) {
|
||||
uint16_t ax, flags, discard_c, discard_d;
|
||||
segoff_t buf = SEGOFF ( fixme_buf );
|
||||
|
||||
RM_FRAGMENT(rm_pcbios_disk_read,
|
||||
"sti\n\t"
|
||||
"popw %ax\n\t"
|
||||
"popw %cx\n\t"
|
||||
"popw %dx\n\t"
|
||||
"popw %bx\n\t"
|
||||
"popw %es\n\t"
|
||||
"int $0x13\n\t"
|
||||
"pushfw\n\t"
|
||||
"cli\n\t"
|
||||
/* FIXME: buf should be passed in as a segoff_t rather than a
|
||||
* char *
|
||||
*/
|
||||
|
||||
REAL_EXEC ( rm_pcbios_disk_read,
|
||||
"sti\n\t"
|
||||
"pushl %%ebx\n\t" /* Convert %ebx to %es:bx */
|
||||
"popl %%bx\n\t"
|
||||
"popl %%es\n\t"
|
||||
"movb $0x02, %%ah\n\t" /* INT 13,2 - Read disk sector */
|
||||
"movb $0x01, %%al\n\t" /* Read one sector */
|
||||
"int $0x13\n\t"
|
||||
"pushfw\n\t"
|
||||
"popw %%bx\n\t"
|
||||
"cli\n\t",
|
||||
4,
|
||||
OUT_CONSTRAINTS ( "=a" ( ax ), "=b" ( flags ),
|
||||
"=c" ( discard_c ), "=d" ( discard_d ) ),
|
||||
IN_CONSTRAINTS ( "c" ( ( ( cylinder & 0xff ) << 8 ) |
|
||||
( ( cylinder >> 8 ) & 0x3 ) |
|
||||
sector ),
|
||||
"d" ( ( head << 8 ) | drive ),
|
||||
"b" ( buf ) ),
|
||||
CLOBBER ( "ebp", "esi", "edi" ) );
|
||||
);
|
||||
|
||||
in_stack.ax.h = 2; /* INT 13,2 - Read disk sector */
|
||||
in_stack.ax.l = 1; /* Read one sector */
|
||||
in_stack.cx.h = cylinder & 0xff;
|
||||
in_stack.cx.l = ( ( cylinder >> 8 ) & 0x3 ) | sector;
|
||||
in_stack.dx.h = head;
|
||||
in_stack.dx.l = drive;
|
||||
in_stack.buffer.segment = SEGMENT ( buf );
|
||||
in_stack.buffer.offset = OFFSET ( buf );
|
||||
ret_ax.word = real_call ( rm_pcbios_disk_read, &in_stack, &out_stack );
|
||||
return ( out_stack.flags.word & CF ) ? ret_ax.word : 0;
|
||||
return ( flags & CF ) ? ax : 0;
|
||||
}
|
||||
#endif /* TRY_FLOPPY_FIRST */
|
||||
|
||||
#endif /* PCBIOS */
|
||||
|
||||
76
src/arch/i386/firmware/pcbios/bios_console.c
Normal file
76
src/arch/i386/firmware/pcbios/bios_console.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/* Etherboot routines for PCBIOS firmware.
|
||||
*
|
||||
* Body of routines taken from old pcbios.S
|
||||
*/
|
||||
|
||||
#include "compiler.h"
|
||||
#include "realmode.h"
|
||||
#include "console.h"
|
||||
|
||||
#define ZF ( 1 << 6 )
|
||||
|
||||
/**************************************************************************
|
||||
bios_putchar - Print a character on console
|
||||
**************************************************************************/
|
||||
static void bios_putchar ( int character ) {
|
||||
REAL_EXEC ( rm_console_putc,
|
||||
"sti\n\t"
|
||||
"movb $0x0e, %%ah\n\t"
|
||||
"movl $1, %%ebx\n\t"
|
||||
"int $0x10\n\t"
|
||||
"cli\n\t",
|
||||
1,
|
||||
OUT_CONSTRAINTS ( "=a" ( character ) ),
|
||||
IN_CONSTRAINTS ( "a" ( character ) ),
|
||||
CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) );
|
||||
|
||||
/* NOTE: %eax may be clobbered, so must be specified as an output
|
||||
* parameter, even though we don't then do anything with it.
|
||||
*/
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
bios_getchar - Get a character from console
|
||||
**************************************************************************/
|
||||
static int bios_getchar ( void ) {
|
||||
uint16_t character;
|
||||
|
||||
REAL_EXEC ( rm_console_getc,
|
||||
"sti\n\t"
|
||||
"xorw %%ax, %%ax\n\t"
|
||||
"int $0x16\n\t"
|
||||
"cli\n\t",
|
||||
1,
|
||||
OUT_CONSTRAINTS ( "=a" ( character ) ),
|
||||
IN_CONSTRAINTS (),
|
||||
CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) );
|
||||
|
||||
return ( character & 0xff );
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
bios_iskey - Check for keyboard interrupt
|
||||
**************************************************************************/
|
||||
static int bios_iskey ( void ) {
|
||||
uint16_t flags;
|
||||
|
||||
REAL_EXEC ( rm_console_ischar,
|
||||
"sti\n\t"
|
||||
"movb $1, %%ah\n\t"
|
||||
"int $0x16\n\t"
|
||||
"pushfw\n\t"
|
||||
"popw %%ax\n\t"
|
||||
"cli\n\t",
|
||||
1,
|
||||
OUT_CONSTRAINTS ( "=a" ( flags ) ),
|
||||
IN_CONSTRAINTS (),
|
||||
CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) );
|
||||
|
||||
return ( ( flags & ZF ) == 0 );
|
||||
}
|
||||
|
||||
static struct console_driver bios_console __console_driver = {
|
||||
.putchar = bios_putchar,
|
||||
.getchar = bios_getchar,
|
||||
.iskey = bios_iskey,
|
||||
};
|
||||
@@ -1,85 +0,0 @@
|
||||
/* Etherboot routines for PCBIOS firmware.
|
||||
*
|
||||
* Body of routines taken from old pcbios.S
|
||||
*/
|
||||
|
||||
#ifdef PCBIOS
|
||||
|
||||
#include "etherboot.h"
|
||||
#include "realmode.h"
|
||||
#include "segoff.h"
|
||||
|
||||
#define ZF ( 1 << 6 )
|
||||
|
||||
/**************************************************************************
|
||||
CONSOLE_PUTC - Print a character on console
|
||||
**************************************************************************/
|
||||
void console_putc ( int character )
|
||||
{
|
||||
struct {
|
||||
reg16_t ax;
|
||||
} PACKED in_stack;
|
||||
|
||||
RM_FRAGMENT(rm_console_putc,
|
||||
"sti\n\t"
|
||||
"popw %ax\n\t"
|
||||
"movb $0x0e, %ah\n\t"
|
||||
"movl $1, %ebx\n\t"
|
||||
"int $0x10\n\t"
|
||||
"cli\n\t"
|
||||
);
|
||||
|
||||
in_stack.ax.l = character;
|
||||
real_call ( rm_console_putc, &in_stack, NULL );
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
CONSOLE_GETC - Get a character from console
|
||||
**************************************************************************/
|
||||
int console_getc ( void )
|
||||
{
|
||||
RM_FRAGMENT(rm_console_getc,
|
||||
"sti\n\t"
|
||||
"xorw %ax, %ax\n\t"
|
||||
"int $0x16\n\t"
|
||||
"xorb %ah, %ah\n\t"
|
||||
"cli\n\t"
|
||||
);
|
||||
|
||||
return real_call ( rm_console_getc, NULL, NULL );
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
CONSOLE_ISCHAR - Check for keyboard interrupt
|
||||
**************************************************************************/
|
||||
int console_ischar ( void )
|
||||
{
|
||||
RM_FRAGMENT(rm_console_ischar,
|
||||
"sti\n\t"
|
||||
"movb $1, %ah\n\t"
|
||||
"int $0x16\n\t"
|
||||
"pushfw\n\t"
|
||||
"popw %ax\n\t"
|
||||
"cli\n\t"
|
||||
);
|
||||
|
||||
return ( ( real_call ( rm_console_ischar, NULL, NULL ) & ZF ) == 0 );
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
GETSHIFT - Get keyboard shift state
|
||||
**************************************************************************/
|
||||
int getshift ( void )
|
||||
{
|
||||
RM_FRAGMENT(rm_getshift,
|
||||
"sti\n\t"
|
||||
"movb $2, %ah\n\t"
|
||||
"int $0x16\n\t"
|
||||
"andw $0x3, %ax\n\t"
|
||||
"cli\n\t"
|
||||
);
|
||||
|
||||
return real_call ( rm_getshift, NULL, NULL );
|
||||
}
|
||||
|
||||
#endif /* PCBIOS */
|
||||
90
src/arch/i386/firmware/pcbios/gateA20.c
Normal file
90
src/arch/i386/firmware/pcbios/gateA20.c
Normal file
@@ -0,0 +1,90 @@
|
||||
#include "realmode.h"
|
||||
#include "timer.h"
|
||||
#include "latch.h"
|
||||
#include "bios.h"
|
||||
|
||||
#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
|
||||
#define K_STATUS 0x64 /* keyboard status */
|
||||
#define K_CMD 0x64 /* keybd ctlr command (write-only) */
|
||||
|
||||
#define K_OBUF_FUL 0x01 /* output buffer full */
|
||||
#define K_IBUF_FUL 0x02 /* input buffer full */
|
||||
|
||||
#define KC_CMD_WIN 0xd0 /* read output port */
|
||||
#define KC_CMD_WOUT 0xd1 /* write output port */
|
||||
#define KB_SET_A20 0xdf /* enable A20,
|
||||
enable output buffer full interrupt
|
||||
enable data line
|
||||
disable clock line */
|
||||
#define KB_UNSET_A20 0xdd /* enable A20,
|
||||
enable output buffer full interrupt
|
||||
enable data line
|
||||
disable clock line */
|
||||
|
||||
enum { Disable_A20 = 0x2400, Enable_A20 = 0x2401, Query_A20_Status = 0x2402,
|
||||
Query_A20_Support = 0x2403 };
|
||||
|
||||
#define CF ( 1 << 0 )
|
||||
|
||||
#ifndef IBM_L40
|
||||
static void empty_8042 ( void )
|
||||
{
|
||||
unsigned long time;
|
||||
char st;
|
||||
|
||||
time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */
|
||||
while ((((st = inb(K_CMD)) & K_OBUF_FUL) ||
|
||||
(st & K_IBUF_FUL)) &&
|
||||
currticks() < time)
|
||||
inb(K_RDWR);
|
||||
}
|
||||
#endif /* IBM_L40 */
|
||||
|
||||
/*
|
||||
* Gate A20 for high memory
|
||||
*
|
||||
* Note that this function gets called as part of the return path from
|
||||
* librm's real_call, which is used to make the int15 call if librm is
|
||||
* being used. To avoid an infinite recursion, we make gateA20_set
|
||||
* return immediately if it is already part of the call stack.
|
||||
*/
|
||||
void gateA20_set ( void ) {
|
||||
static char reentry_guard = 0;
|
||||
uint16_t flags, status;
|
||||
|
||||
if ( reentry_guard )
|
||||
return;
|
||||
reentry_guard = 1;
|
||||
|
||||
REAL_EXEC ( rm_enableA20,
|
||||
"sti\n\t"
|
||||
"stc\n\t"
|
||||
"int $0x15\n\t"
|
||||
"pushfw\n\t"
|
||||
"popw %%bx\n\t"
|
||||
"cli\n\t",
|
||||
2,
|
||||
OUT_CONSTRAINTS ( "=a" ( status ), "=b" ( flags ) ),
|
||||
IN_CONSTRAINTS ( "a" ( Enable_A20 ) ),
|
||||
CLOBBER ( "ecx", "edx", "ebp", "esi", "edi" ) );
|
||||
|
||||
if ( ( flags & CF ) ||
|
||||
( ( status >> 8 ) & 0xff ) ) {
|
||||
/* INT 15 method failed, try alternatives */
|
||||
#ifdef IBM_L40
|
||||
outb(0x2, 0x92);
|
||||
#else /* IBM_L40 */
|
||||
empty_8042();
|
||||
outb(KC_CMD_WOUT, K_CMD);
|
||||
empty_8042();
|
||||
outb(KB_SET_A20, K_RDWR);
|
||||
empty_8042();
|
||||
#endif /* IBM_L40 */
|
||||
}
|
||||
|
||||
reentry_guard = 0;
|
||||
}
|
||||
|
||||
void gateA20_unset ( void ) {
|
||||
/* Not currently implemented */
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifdef PCBIOS
|
||||
|
||||
#include "etherboot.h"
|
||||
#include "stdint.h"
|
||||
#include "stddef.h"
|
||||
#include "realmode.h"
|
||||
#include "init.h"
|
||||
#include "memsizes.h"
|
||||
|
||||
#define CF ( 1 << 0 )
|
||||
|
||||
@@ -16,109 +17,131 @@ struct meminfo meminfo;
|
||||
/**************************************************************************
|
||||
BASEMEMSIZE - Get size of the conventional (base) memory
|
||||
**************************************************************************/
|
||||
unsigned short basememsize ( void )
|
||||
{
|
||||
RM_FRAGMENT(rm_basememsize,
|
||||
"int $0x12\n\t"
|
||||
);
|
||||
return real_call ( rm_basememsize, NULL, NULL );
|
||||
static unsigned short basememsize ( void ) {
|
||||
uint16_t int12_basememsize, fbms_basememsize;
|
||||
|
||||
/* There are two methods for retrieving the base memory size:
|
||||
* INT 12 and the BIOS FBMS counter at 40:13. We read both
|
||||
* and use the smaller value, to be paranoid.
|
||||
*/
|
||||
|
||||
REAL_EXEC ( rm_basememsize,
|
||||
"int $0x12\n\t",
|
||||
1,
|
||||
OUT_CONSTRAINTS ( "=a" ( int12_basememsize ) ),
|
||||
IN_CONSTRAINTS (),
|
||||
CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) );
|
||||
|
||||
get_real ( fbms_basememsize, 0x40, 0x13 );
|
||||
|
||||
return ( int12_basememsize < fbms_basememsize ?
|
||||
int12_basememsize : fbms_basememsize );
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
MEMSIZE - Determine size of extended memory
|
||||
MEMSIZE - Determine size of extended memory, in kB
|
||||
**************************************************************************/
|
||||
unsigned int memsize ( void )
|
||||
{
|
||||
struct {
|
||||
reg16_t ax;
|
||||
} PACKED in_stack;
|
||||
struct {
|
||||
reg16_t ax;
|
||||
reg16_t bx;
|
||||
reg16_t cx;
|
||||
reg16_t dx;
|
||||
reg16_t flags;
|
||||
} PACKED out_stack;
|
||||
static unsigned int memsize ( void ) {
|
||||
uint16_t extmem_1m_to_16m_k, extmem_16m_plus_64k;
|
||||
uint16_t confmem_1m_to_16m_k, confmem_16m_plus_64k;
|
||||
uint16_t flags;
|
||||
int memsize;
|
||||
|
||||
RM_FRAGMENT(rm_memsize,
|
||||
/* Some buggy BIOSes don't clear/set carry on pass/error of
|
||||
/* Try INT 15,e801 first
|
||||
*
|
||||
* Some buggy BIOSes don't clear/set carry on pass/error of
|
||||
* e801h memory size call or merely pass cx,dx through without
|
||||
* changing them, so we set carry and zero cx,dx before call.
|
||||
*/
|
||||
"stc\n\t"
|
||||
"xorw %cx,%cx\n\t"
|
||||
"xorw %dx,%dx\n\t"
|
||||
"popw %ax\n\t"
|
||||
"int $0x15\n\t"
|
||||
"pushfw\n\t"
|
||||
"pushw %dx\n\t"
|
||||
"pushw %cx\n\t"
|
||||
"pushw %bx\n\t"
|
||||
"pushw %ax\n\t"
|
||||
);
|
||||
REAL_EXEC ( rm_mem_e801,
|
||||
"stc\n\t"
|
||||
"int $0x15\n\t"
|
||||
"pushfw\n\t" /* flags -> %di */
|
||||
"popw %%di\n\t",
|
||||
5,
|
||||
OUT_CONSTRAINTS ( "=a" ( extmem_1m_to_16m_k ),
|
||||
"=b" ( extmem_16m_plus_64k ),
|
||||
"=c" ( confmem_1m_to_16m_k ),
|
||||
"=d" ( confmem_16m_plus_64k ),
|
||||
"=D" ( flags ) ),
|
||||
IN_CONSTRAINTS ( "a" ( 0xe801 ),
|
||||
"c" ( 0 ),
|
||||
"d" ( 0 ) ),
|
||||
CLOBBER ( "ebp", "esi" ) );
|
||||
|
||||
/* Try INT 15,e801 first */
|
||||
in_stack.ax.word = 0xe801;
|
||||
real_call ( rm_memsize, &in_stack, &out_stack );
|
||||
if ( out_stack.flags.word & CF ) {
|
||||
/* INT 15,e801 not supported: try INT 15,88 */
|
||||
in_stack.ax.word = 0x8800;
|
||||
memsize = real_call ( rm_memsize, &in_stack, &out_stack );
|
||||
} else {
|
||||
/* Some BIOSes report extended memory via ax,bx rather
|
||||
* than cx,dx
|
||||
*/
|
||||
if ( (out_stack.cx.word==0) && (out_stack.dx.word==0) ) {
|
||||
/* Use ax,bx */
|
||||
memsize = ( out_stack.bx.word<<6 ) + out_stack.ax.word;
|
||||
if ( ! ( flags & CF ) ) {
|
||||
/* INT 15,e801 succeeded */
|
||||
if ( confmem_1m_to_16m_k || confmem_16m_plus_64k ) {
|
||||
/* Use confmem (cx,dx) values */
|
||||
memsize = confmem_1m_to_16m_k +
|
||||
( confmem_16m_plus_64k << 6 );
|
||||
} else {
|
||||
/* Use cx,dx */
|
||||
memsize = ( out_stack.dx.word<<6 ) + out_stack.cx.word;
|
||||
/* Use extmem (ax,bx) values */
|
||||
memsize = extmem_1m_to_16m_k +
|
||||
( extmem_16m_plus_64k << 6 );
|
||||
}
|
||||
} else {
|
||||
/* INT 15,e801 failed; fall back to INT 15,88
|
||||
*
|
||||
* CF is apparently unreliable and should be ignored.
|
||||
*/
|
||||
REAL_EXEC ( rm_mem_88,
|
||||
"int $0x15\n\t",
|
||||
1,
|
||||
OUT_CONSTRAINTS ( "=a" ( extmem_1m_to_16m_k ) ),
|
||||
IN_CONSTRAINTS ( "a" ( 0x88 << 8 ) ),
|
||||
CLOBBER ( "ebx", "ecx", "edx",
|
||||
"ebp", "esi", "edi" ) );
|
||||
memsize = extmem_1m_to_16m_k;
|
||||
}
|
||||
|
||||
return memsize;
|
||||
}
|
||||
|
||||
#define SMAP ( 0x534d4150 )
|
||||
int meme820 ( struct e820entry *buf, int count )
|
||||
{
|
||||
struct {
|
||||
reg16_t flags;
|
||||
reg32_t eax;
|
||||
reg32_t ebx;
|
||||
struct e820entry entry;
|
||||
} PACKED stack;
|
||||
int index = 0;
|
||||
/**************************************************************************
|
||||
MEME820 - Retrieve the E820 BIOS memory map
|
||||
**************************************************************************/
|
||||
#define SMAP ( 0x534d4150 ) /* "SMAP" */
|
||||
static int meme820 ( struct e820entry *buf, int count ) {
|
||||
int index;
|
||||
uint16_t basemem_entry;
|
||||
uint32_t smap, next;
|
||||
uint16_t flags;
|
||||
uint32_t discard_c, discard_d;
|
||||
|
||||
RM_FRAGMENT(rm_meme820,
|
||||
"addw $6, %sp\n\t" /* skip flags, eax */
|
||||
"popl %ebx\n\t"
|
||||
"pushw %ss\n\t" /* es:di = ss:sp */
|
||||
"popw %es\n\t"
|
||||
"movw %sp, %di\n\t"
|
||||
"movl $0xe820, %eax\n\t"
|
||||
"movl $" RM_STR(SMAP) ", %edx\n\t"
|
||||
"movl $" RM_STR(E820ENTRY_SIZE) ", %ecx\n\t"
|
||||
"int $0x15\n\t"
|
||||
"pushl %ebx\n\t"
|
||||
"pushl %eax\n\t"
|
||||
"pushfw\n\t"
|
||||
);
|
||||
|
||||
stack.ebx.dword = 0; /* 'EOF' marker */
|
||||
while ( ( index < count ) &&
|
||||
( ( index == 0 ) || ( stack.ebx.dword != 0 ) ) ) {
|
||||
real_call ( rm_meme820, &stack, &stack );
|
||||
if ( stack.eax.dword != SMAP ) return 0;
|
||||
if ( stack.flags.word & CF ) return 0;
|
||||
buf[index++] = stack.entry;
|
||||
}
|
||||
index = 0;
|
||||
next = 0;
|
||||
do {
|
||||
basemem_entry = BASEMEM_PARAMETER_INIT ( buf[index] );
|
||||
REAL_EXEC ( rm_mem_e820,
|
||||
"int $0x15\n\t"
|
||||
"pushfw\n\t" /* flags -> %di */
|
||||
"popw %%di\n\t",
|
||||
5,
|
||||
OUT_CONSTRAINTS ( "=a" ( smap ),
|
||||
"=b" ( next ),
|
||||
"=c" ( discard_c ),
|
||||
"=d" ( discard_d ),
|
||||
"=D" ( flags ) ),
|
||||
IN_CONSTRAINTS ( "a" ( 0xe820 ),
|
||||
"b" ( next ),
|
||||
"c" ( sizeof (struct e820entry) ),
|
||||
"d" ( SMAP ),
|
||||
"D" ( basemem_entry ) ),
|
||||
CLOBBER ( "ebp", "esi" ) );
|
||||
BASEMEM_PARAMETER_DONE ( buf[index] );
|
||||
if ( smap != SMAP ) return 0;
|
||||
if ( flags & CF ) break;
|
||||
index++;
|
||||
} while ( ( index < count ) && ( next != 0 ) );
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void get_memsizes(void)
|
||||
{
|
||||
/**************************************************************************
|
||||
GET_MEMSIZES - Retrieve the system memory map via any available means
|
||||
**************************************************************************/
|
||||
void get_memsizes ( void ) {
|
||||
/* Ensure we don't stomp bios data structutres.
|
||||
* the interrupt table: 0x000 - 0x3ff
|
||||
* the bios data area: 0x400 - 0x502
|
||||
@@ -127,16 +150,19 @@ void get_memsizes(void)
|
||||
static const unsigned min_addr = 0x600;
|
||||
unsigned i;
|
||||
unsigned basemem;
|
||||
basemem = get_free_base_memory();
|
||||
|
||||
/* Retrieve memory information from the BIOS */
|
||||
meminfo.basememsize = basememsize();
|
||||
basemem = meminfo.basememsize << 10;
|
||||
meminfo.memsize = memsize();
|
||||
#ifndef IGNORE_E820_MAP
|
||||
meminfo.map_count = meme820(meminfo.map, E820MAX);
|
||||
meminfo.map_count = meme820 ( meminfo.map, E820MAX );
|
||||
#else
|
||||
meminfo.map_count = 0;
|
||||
#endif
|
||||
if (meminfo.map_count == 0) {
|
||||
/* If we don't have an e820 memory map fake it */
|
||||
|
||||
/* If we don't have an e820 memory map fake it */
|
||||
if ( meminfo.map_count == 0 ) {
|
||||
meminfo.map_count = 2;
|
||||
meminfo.map[0].addr = 0;
|
||||
meminfo.map[0].size = meminfo.basememsize << 10;
|
||||
@@ -145,57 +171,56 @@ void get_memsizes(void)
|
||||
meminfo.map[1].size = meminfo.memsize << 10;
|
||||
meminfo.map[1].type = E820_RAM;
|
||||
}
|
||||
|
||||
/* Scrub the e820 map */
|
||||
for(i = 0; i < meminfo.map_count; i++) {
|
||||
if (meminfo.map[i].type != E820_RAM) {
|
||||
for ( i = 0; i < meminfo.map_count; i++ ) {
|
||||
if ( meminfo.map[i].type != E820_RAM ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Reserve the bios data structures */
|
||||
if (meminfo.map[i].addr < min_addr) {
|
||||
if ( meminfo.map[i].addr < min_addr ) {
|
||||
unsigned long delta;
|
||||
delta = min_addr - meminfo.map[i].addr;
|
||||
if (delta > meminfo.map[i].size) {
|
||||
if ( delta > meminfo.map[i].size ) {
|
||||
delta = meminfo.map[i].size;
|
||||
}
|
||||
meminfo.map[i].addr = min_addr;
|
||||
meminfo.map[i].size -= delta;
|
||||
}
|
||||
/* Ensure the returned e820 map is in sync
|
||||
* with the actual memory state
|
||||
|
||||
/* Ensure the returned e820 map is in sync with the
|
||||
* actual memory state
|
||||
*/
|
||||
if ((meminfo.map[i].addr < 0xa0000) &&
|
||||
((meminfo.map[i].addr + meminfo.map[i].size) > basemem))
|
||||
{
|
||||
if (meminfo.map[i].addr <= basemem) {
|
||||
meminfo.map[i].size = basemem - meminfo.map[i].addr;
|
||||
if ( ( meminfo.map[i].addr < 0xa0000 ) &&
|
||||
(( meminfo.map[i].addr+meminfo.map[i].size ) > basemem )){
|
||||
if ( meminfo.map[i].addr <= basemem ) {
|
||||
meminfo.map[i].size = basemem
|
||||
- meminfo.map[i].addr;
|
||||
} else {
|
||||
meminfo.map[i].addr = basemem;
|
||||
meminfo.map[i].size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if MEMSIZES_DEBUG
|
||||
{
|
||||
int i;
|
||||
printf("basememsize %d\n", meminfo.basememsize);
|
||||
printf("memsize %d\n", meminfo.memsize);
|
||||
printf("Memory regions(%d):\n", meminfo.map_count);
|
||||
for(i = 0; i < meminfo.map_count; i++) {
|
||||
printf ( "basememsize %d\n", meminfo.basememsize );
|
||||
printf ( "memsize %d\n", meminfo.memsize );
|
||||
printf ( "Memory regions(%d):\n", meminfo.map_count );
|
||||
for ( i = 0; i < meminfo.map_count; i++ ) {
|
||||
unsigned long long r_start, r_end;
|
||||
r_start = meminfo.map[i].addr;
|
||||
r_end = r_start + meminfo.map[i].size;
|
||||
printf("[%X%X, %X%X) type %d\n",
|
||||
(unsigned long)(r_start >> 32),
|
||||
(unsigned long)r_start,
|
||||
(unsigned long)(r_end >> 32),
|
||||
(unsigned long)r_end,
|
||||
meminfo.map[i].type);
|
||||
#if defined(CONSOLE_FIRMWARE)
|
||||
sleep(1); /* No way to see 32 entries on a standard 80x25 screen... */
|
||||
#endif
|
||||
printf ( "[%X%X, %X%X) type %d\n",
|
||||
( unsigned long ) ( r_start >> 32 ),
|
||||
( unsigned long ) r_start,
|
||||
( unsigned long ) ( r_end >> 32 ),
|
||||
( unsigned long ) r_end,
|
||||
meminfo.map[i].type );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif /* PCBIOS */
|
||||
INIT_FN ( INIT_MEMSIZES, get_memsizes, NULL, NULL );
|
||||
|
||||
Reference in New Issue
Block a user