From c7de829c796978e519984df2f1c8cfcf921a39a4 Mon Sep 17 00:00:00 2001 From: wdenk Date: Tue, 19 Nov 2002 11:04:11 +0000 Subject: * Patch by Thomas Frieden, 13 Nov 2002: Add code for AmigaOne board (preliminary merge to U-Boot, still WIP) * Patch by Jon Diekema, 12 Nov 2002: - Adding URL for IEEE OUI lookup - Making the autoboot #defines dependent on CONFIG_AUTOBOOT_KEYED being defined. - In the CONFIG_EXTRA_ENV_SETTINGS #define, the root-on-initrd and root-on-nfs macros are designed to switch how the default boot method gets defined. --- board/MAI/bios_emulator/scitech/src/pm/linux/pm.c | 1810 +++++++++++++++++++++ 1 file changed, 1810 insertions(+) create mode 100644 board/MAI/bios_emulator/scitech/src/pm/linux/pm.c (limited to 'board/MAI/bios_emulator/scitech/src/pm/linux/pm.c') diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c b/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c new file mode 100644 index 0000000000..1d52984a6a --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c @@ -0,0 +1,1810 @@ +;/**************************************************************************** +* +* SciTech OS Portability Manager Library +* +* ======================================================================== +* +* The contents of this file are subject to the SciTech MGL Public +* License Version 1.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.scitechsoft.com/mgl-license.txt +* +* Software distributed under the License is distributed on an +* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc. +* +* The Initial Developer of the Original Code is SciTech Software, Inc. +* All Rights Reserved. +* +* ======================================================================== +* +* Portions copyright (C) Josh Vanderhoof +* +* Language: ANSI C +* Environment: Linux +* +* Description: Implementation for the OS Portability Manager Library, which +* contains functions to implement OS specific services in a +* generic, cross platform API. Porting the OS Portability +* Manager library is the first step to porting any SciTech +* products to a new platform. +* +****************************************************************************/ + +#include "pmapi.h" +#include "drvlib/os/os.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef ENABLE_MTRR +#include +#endif +#include +#ifdef __GLIBC__ +#include +#endif + +/*--------------------------- Global variables ----------------------------*/ + +#define REAL_MEM_BASE ((void *)0x10000) +#define REAL_MEM_SIZE 0x10000 +#define REAL_MEM_BLOCKS 0x100 +#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK) +#define DEFAULT_STACK_SIZE 0x1000 +#define RETURN_TO_32_INT 255 + +/* Quick and dirty fix for vm86() syscall from lrmi 0.6 */ +static int +vm86(struct vm86_struct *vm) + { + int r; +#ifdef __PIC__ + asm volatile ( + "pushl %%ebx\n\t" + "movl %2, %%ebx\n\t" + "int $0x80\n\t" + "popl %%ebx" + : "=a" (r) + : "0" (113), "r" (vm)); +#else + asm volatile ( + "int $0x80" + : "=a" (r) + : "0" (113), "b" (vm)); +#endif + return r; + } + + +static struct { + int ready; + unsigned short ret_seg, ret_off; + unsigned short stack_seg, stack_off; + struct vm86_struct vm; + } context = {0}; + +struct mem_block { + unsigned int size : 20; + unsigned int free : 1; + }; + +static struct { + int ready; + int count; + struct mem_block blocks[REAL_MEM_BLOCKS]; + } mem_info = {0}; + +int _PM_console_fd = -1; +int _PM_leds = 0,_PM_modifiers = 0; +static ibool inited = false; +static int tty_vc = 0; +static int console_count = 0; +static int startup_vc; +static int fd_mem = 0; +static ibool in_raw_mode = false; +#ifdef ENABLE_MTRR +static int mtrr_fd; +#endif +static uint VESABuf_len = 1024; /* Length of the VESABuf buffer */ +static void *VESABuf_ptr = NULL; /* Near pointer to VESABuf */ +static uint VESABuf_rseg; /* Real mode segment of VESABuf */ +static uint VESABuf_roff; /* Real mode offset of VESABuf */ +#ifdef TRACE_IO +static ulong traceAddr; +#endif + +static void (PMAPIP fatalErrorCleanup)(void) = NULL; + +/*----------------------------- Implementation ----------------------------*/ + +#ifdef TRACE_IO +extern void printk(char *msg,...); +#endif + +static inline void port_out(int value, int port) +{ +#ifdef TRACE_IO + printk("%04X:%04X: outb.%04X <- %02X\n", traceAddr >> 16, traceAddr & 0xFFFF, (ushort)port, (uchar)value); +#endif + asm volatile ("outb %0,%1" + ::"a" ((unsigned char) value), "d"((unsigned short) port)); +} + +static inline void port_outw(int value, int port) +{ +#ifdef TRACE_IO + printk("%04X:%04X: outw.%04X <- %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value); +#endif + asm volatile ("outw %0,%1" + ::"a" ((unsigned short) value), "d"((unsigned short) port)); +} + +static inline void port_outl(int value, int port) +{ +#ifdef TRACE_IO + printk("%04X:%04X: outl.%04X <- %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value); +#endif + asm volatile ("outl %0,%1" + ::"a" ((unsigned long) value), "d"((unsigned short) port)); +} + +static inline unsigned int port_in(int port) +{ + unsigned char value; + asm volatile ("inb %1,%0" + :"=a" ((unsigned char)value) + :"d"((unsigned short) port)); +#ifdef TRACE_IO + printk("%04X:%04X: inb.%04X -> %02X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (uchar)value); +#endif + return value; +} + +static inline unsigned int port_inw(int port) +{ + unsigned short value; + asm volatile ("inw %1,%0" + :"=a" ((unsigned short)value) + :"d"((unsigned short) port)); +#ifdef TRACE_IO + printk("%04X:%04X: inw.%04X -> %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value); +#endif + return value; +} + +static inline unsigned int port_inl(int port) +{ + unsigned long value; + asm volatile ("inl %1,%0" + :"=a" ((unsigned long)value) + :"d"((unsigned short) port)); +#ifdef TRACE_IO + printk("%04X:%04X: inl.%04X -> %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value); +#endif + return value; +} + +static int real_mem_init(void) +{ + void *m; + int fd_zero; + + if (mem_info.ready) + return 1; + + if ((fd_zero = open("/dev/zero", O_RDONLY)) == -1) + PM_fatalError("You must have root privledges to run this program!"); + if ((m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, fd_zero, 0)) == (void *)-1) { + close(fd_zero); + PM_fatalError("You must have root privledges to run this program!"); + } + mem_info.ready = 1; + mem_info.count = 1; + mem_info.blocks[0].size = REAL_MEM_SIZE; + mem_info.blocks[0].free = 1; + return 1; +} + +static void insert_block(int i) +{ + memmove( + mem_info.blocks + i + 1, + mem_info.blocks + i, + (mem_info.count - i) * sizeof(struct mem_block)); + mem_info.count++; +} + +static void delete_block(int i) +{ + mem_info.count--; + + memmove( + mem_info.blocks + i, + mem_info.blocks + i + 1, + (mem_info.count - i) * sizeof(struct mem_block)); +} + +static inline void set_bit(unsigned int bit, void *array) +{ + unsigned char *a = array; + a[bit / 8] |= (1 << (bit % 8)); +} + +static inline unsigned int get_int_seg(int i) +{ + return *(unsigned short *)(i * 4 + 2); +} + +static inline unsigned int get_int_off(int i) +{ + return *(unsigned short *)(i * 4); +} + +static inline void pushw(unsigned short i) +{ + struct vm86_regs *r = &context.vm.regs; + r->esp -= 2; + *(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i; +} + +ibool PMAPI PM_haveBIOSAccess(void) +{ return true; } + +void PMAPI PM_init(void) +{ + void *m; + uint r_seg,r_off; + + if (inited) + return; + + /* Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502) + * and the physical framebuffer and ROM images from (0xa0000 - 0x100000) + */ + real_mem_init(); + if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1) { + PM_fatalError("You must have root privileges to run this program!"); + } + if ((m = mmap((void *)0, 0x502, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, fd_mem, 0)) == (void *)-1) { + PM_fatalError("You must have root privileges to run this program!"); + } + if ((m = mmap((void *)0xA0000, 0xC0000 - 0xA0000, + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd_mem, 0xA0000)) == (void *)-1) { + PM_fatalError("You must have root privileges to run this program!"); + } + if ((m = mmap((void *)0xC0000, 0xD0000 - 0xC0000, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, fd_mem, 0xC0000)) == (void *)-1) { + PM_fatalError("You must have root privileges to run this program!"); + } + if ((m = mmap((void *)0xD0000, 0x100000 - 0xD0000, + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd_mem, 0xD0000)) == (void *)-1) { + PM_fatalError("You must have root privileges to run this program!"); + } + inited = 1; + + /* Allocate a stack */ + m = PM_allocRealSeg(DEFAULT_STACK_SIZE,&r_seg,&r_off); + context.stack_seg = r_seg; + context.stack_off = r_off+DEFAULT_STACK_SIZE; + + /* Allocate the return to 32 bit routine */ + m = PM_allocRealSeg(2,&r_seg,&r_off); + context.ret_seg = r_seg; + context.ret_off = r_off; + ((uchar*)m)[0] = 0xCD; /* int opcode */ + ((uchar*)m)[1] = RETURN_TO_32_INT; + memset(&context.vm, 0, sizeof(context.vm)); + + /* Enable kernel emulation of all ints except RETURN_TO_32_INT */ + memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored)); + set_bit(RETURN_TO_32_INT, &context.vm.int_revectored); + context.ready = 1; +#ifdef ENABLE_MTRR + mtrr_fd = open("/dev/cpu/mtrr", O_RDWR, 0); + if (mtrr_fd < 0) + mtrr_fd = open("/proc/mtrr", O_RDWR, 0); +#endif + /* Enable I/O permissions to directly access I/O ports. We break the + * allocation into two parts, one for the ports from 0-0x3FF and + * another for the remaining ports up to 0xFFFF. Standard Linux kernels + * only allow the first 0x400 ports to be enabled, so to enable all + * 65536 ports you need a patched kernel that will enable the full + * 8Kb I/O permissions bitmap. + */ +#ifndef TRACE_IO + ioperm(0x0,0x400,1); + ioperm(0x400,0x10000-0x400,1); +#endif + iopl(3); +} + +long PMAPI PM_getOSType(void) +{ return _OS_LINUX; } + +int PMAPI PM_getModeType(void) +{ return PM_386; } + +void PMAPI PM_backslash(char *s) +{ + uint pos = strlen(s); + if (s[pos-1] != '/') { + s[pos] = '/'; + s[pos+1] = '\0'; + } +} + +void PMAPI PM_setFatalErrorCleanup( + void (PMAPIP cleanup)(void)) +{ + fatalErrorCleanup = cleanup; +} + +void PMAPI PM_fatalError(const char *msg) +{ + if (fatalErrorCleanup) + fatalErrorCleanup(); + fprintf(stderr,"%s\n", msg); + fflush(stderr); + exit(1); +} + +static void ExitVBEBuf(void) +{ + if (VESABuf_ptr) + PM_freeRealSeg(VESABuf_ptr); + VESABuf_ptr = 0; +} + +void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff) +{ + if (!VESABuf_ptr) { + /* Allocate a global buffer for communicating with the VESA VBE */ + if ((VESABuf_ptr = PM_allocRealSeg(VESABuf_len, &VESABuf_rseg, &VESABuf_roff)) == NULL) + return NULL; + atexit(ExitVBEBuf); + } + *len = VESABuf_len; + *rseg = VESABuf_rseg; + *roff = VESABuf_roff; + return VESABuf_ptr; +} + +/* New raw console based getch and kbhit functions */ + +#define KB_CAPS LED_CAP /* 4 */ +#define KB_NUMLOCK LED_NUM /* 2 */ +#define KB_SCROLL LED_SCR /* 1 */ +#define KB_SHIFT 8 +#define KB_CONTROL 16 +#define KB_ALT 32 + +/* Structure used to save the keyboard mode to disk. We save it to disk + * so that we can properly restore the mode later if the program crashed. + */ + +typedef struct { + struct termios termios; + int kb_mode; + int leds; + int flags; + int startup_vc; + } keyboard_mode; + +/* Name of the file used to save keyboard mode information */ + +#define KBMODE_DAT "kbmode.dat" + +/**************************************************************************** +REMARKS: +Open the keyboard mode file on disk. +****************************************************************************/ +static FILE *open_kb_mode( + char *mode, + char *path) +{ + if (!PM_findBPD("graphics.bpd",path)) + return NULL; + PM_backslash(path); + strcat(path,KBMODE_DAT); + return fopen(path,mode); +} + +/**************************************************************************** +REMARKS: +Restore the keyboard to normal mode +****************************************************************************/ +void _PM_restore_kb_mode(void) +{ + FILE *kbmode; + keyboard_mode mode; + char path[PM_MAX_PATH]; + + if (_PM_console_fd != -1 && (kbmode = open_kb_mode("rb",path)) != NULL) { + if (fread(&mode,1,sizeof(mode),kbmode) == sizeof(mode)) { + if (mode.startup_vc > 0) + ioctl(_PM_console_fd, VT_ACTIVATE, mode.startup_vc); + ioctl(_PM_console_fd, KDSKBMODE, mode.kb_mode); + ioctl(_PM_console_fd, KDSETLED, mode.leds); + tcsetattr(_PM_console_fd, TCSAFLUSH, &mode.termios); + fcntl(_PM_console_fd,F_SETFL,mode.flags); + } + fclose(kbmode); + unlink(path); + in_raw_mode = false; + } +} + +/**************************************************************************** +REMARKS: +Safely abort the event module upon catching a fatal error. +****************************************************************************/ +void _PM_abort( + int signo) +{ + char buf[80]; + + sprintf(buf,"Terminating on signal %d",signo); + _PM_restore_kb_mode(); + PM_fatalError(buf); +} + +/**************************************************************************** +REMARKS: +Put the keyboard into raw mode +****************************************************************************/ +void _PM_keyboard_rawmode(void) +{ + struct termios conf; + FILE *kbmode; + keyboard_mode mode; + char path[PM_MAX_PATH]; + int i; + static int sig_list[] = { + SIGHUP, + SIGINT, + SIGQUIT, + SIGILL, + SIGTRAP, + SIGABRT, + SIGIOT, + SIGBUS, + SIGFPE, + SIGKILL, + SIGSEGV, + SIGTERM, + }; + + if ((kbmode = open_kb_mode("rb",path)) == NULL) { + if ((kbmode = open_kb_mode("wb",path)) == NULL) + PM_fatalError("Unable to open kbmode.dat file for writing!"); + if (ioctl(_PM_console_fd, KDGKBMODE, &mode.kb_mode)) + perror("KDGKBMODE"); + ioctl(_PM_console_fd, KDGETLED, &mode.leds); + _PM_leds = mode.leds & 0xF; + _PM_modifiers = 0; + tcgetattr(_PM_console_fd, &mode.termios); + conf = mode.termios; + conf.c_lflag &= ~(ICANON | ECHO | ISIG); + conf.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF); + conf.c_iflag |= (IGNBRK | IGNPAR); + conf.c_cc[VMIN] = 1; + conf.c_cc[VTIME] = 0; + conf.c_cc[VSUSP] = 0; + tcsetattr(_PM_console_fd, TCSAFLUSH, &conf); + mode.flags = fcntl(_PM_console_fd,F_GETFL); + if (ioctl(_PM_console_fd, KDSKBMODE, K_MEDIUMRAW)) + perror("KDSKBMODE"); + atexit(_PM_restore_kb_mode); + for (i = 0; i < sizeof(sig_list)/sizeof(sig_list[0]); i++) + signal(sig_list[i], _PM_abort); + mode.startup_vc = startup_vc; + if (fwrite(&mode,1,sizeof(mode),kbmode) != sizeof(mode)) + PM_fatalError("Error writing kbmode.dat!"); + fclose(kbmode); + in_raw_mode = true; + } +} + +int PMAPI PM_kbhit(void) +{ + fd_set s; + struct timeval tv = { 0, 0 }; + + if (console_count == 0) + PM_fatalError("You *must* open a console before using PM_kbhit!"); + if (!in_raw_mode) + _PM_keyboard_rawmode(); + FD_ZERO(&s); + FD_SET(_PM_console_fd, &s); + return select(_PM_console_fd+1, &s, NULL, NULL, &tv) > 0; +} + +int PMAPI PM_getch(void) +{ + static uchar c; + int release; + static struct kbentry ke; + + if (console_count == 0) + PM_fatalError("You *must* open a console before using PM_getch!"); + if (!in_raw_mode) + _PM_keyboard_rawmode(); + while (read(_PM_console_fd, &c, 1) > 0) { + release = c & 0x80; + c &= 0x7F; + if (release) { + switch(c){ + case 42: case 54: // Shift + _PM_modifiers &= ~KB_SHIFT; + break; + case 29: case 97: // Control + _PM_modifiers &= ~KB_CONTROL; + break; + case 56: case 100: // Alt / AltGr + _PM_modifiers &= ~KB_ALT; + break; + } + continue; + } + switch (c) { + case 42: case 54: // Shift + _PM_modifiers |= KB_SHIFT; + break; + case 29: case 97: // Control + _PM_modifiers |= KB_CONTROL; + break; + case 56: case 100: // Alt / AltGr + _PM_modifiers |= KB_ALT; + break; + case 58: // Caps Lock + _PM_modifiers ^= KB_CAPS; + ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7); + break; + case 69: // Num Lock + _PM_modifiers ^= KB_NUMLOCK; + ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7); + break; + case 70: // Scroll Lock + _PM_modifiers ^= KB_SCROLL; + ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7); + break; + case 28: + return 0x1C; + default: + ke.kb_index = c; + ke.kb_table = 0; + if ((_PM_modifiers & KB_SHIFT) || (_PM_modifiers & KB_CAPS)) + ke.kb_table |= K_SHIFTTAB; + if (_PM_modifiers & KB_ALT) + ke.kb_table |= K_ALTTAB; + ioctl(_PM_console_fd, KDGKBENT, (ulong)&ke); + c = ke.kb_value & 0xFF; + return c; + } + } + return 0; +} + +/**************************************************************************** +REMARKS: +Sleep until the virtual terminal is active +****************************************************************************/ +static void wait_vt_active( + int _PM_console_fd) +{ + while (ioctl(_PM_console_fd, VT_WAITACTIVE, tty_vc) < 0) { + if ((errno != EAGAIN) && (errno != EINTR)) { + perror("ioctl(VT_WAITACTIVE)"); + exit(1); + } + usleep(150000); + } +} + +/**************************************************************************** +REMARKS: +Checks the owner of the specified virtual console. +****************************************************************************/ +static int check_owner( + int vc) +{ + struct stat sbuf; + char fname[30]; + + sprintf(fname, "/dev/tty%d", vc); + if ((stat(fname, &sbuf) >= 0) && (getuid() == sbuf.st_uid)) + return 1; + printf("You must be the owner of the current console to use this program.\n"); + return 0; +} + +/**************************************************************************** +REMARKS: +Checks if the console is currently in graphics mode, and if so we forcibly +restore it back to text mode again. This handles the case when a Nucleus or +MGL program crashes and leaves the console in graphics mode. Running the +textmode utility (or any other Nucleus/MGL program) via a telnet session +into the machine will restore it back to normal. +****************************************************************************/ +static void restore_text_console( + int console_id) +{ + if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0) + LOGWARN("ioctl(KDSETMODE) failed"); + _PM_restore_kb_mode(); +} + +/**************************************************************************** +REMARKS: +Opens up the console device for output by finding an appropriate virutal +console that we can run on. +****************************************************************************/ +PM_HWND PMAPI PM_openConsole( + PM_HWND hwndUser, + int device, + int xRes, + int yRes, + int bpp, + ibool fullScreen) +{ + struct vt_mode vtm; + struct vt_stat vts; + struct stat sbuf; + char fname[30]; + + /* Check if we have already opened the console */ + if (console_count++) + return _PM_console_fd; + + /* Now, it would be great if we could use /dev/tty and see what it is + * connected to. Alas, we cannot find out reliably what VC /dev/tty is + * bound to. Thus we parse stdin through stderr for a reliable VC. + */ + startup_vc = 0; + for (_PM_console_fd = 0; _PM_console_fd < 3; _PM_console_fd++) { + if (fstat(_PM_console_fd, &sbuf) < 0) + continue; + if (ioctl(_PM_console_fd, VT_GETMODE, &vtm) < 0) + continue; + if ((sbuf.st_rdev & 0xFF00) != 0x400) + continue; + if (!(sbuf.st_rdev & 0xFF)) + continue; + tty_vc = sbuf.st_rdev & 0xFF; + restore_text_console(_PM_console_fd); + return _PM_console_fd; + } + if ((_PM_console_fd = open("/dev/console", O_RDWR)) < 0) { + printf("open_dev_console: can't open /dev/console \n"); + exit(1); + } + if (ioctl(_PM_console_fd, VT_OPENQRY, &tty_vc) < 0) + goto Error; + if (tty_vc <= 0) + goto Error; + sprintf(fname, "/dev/tty%d", tty_vc); + close(_PM_console_fd); + + /* Change our control terminal */ + setsid(); + + /* We must use RDWR to allow for output... */ + if (((_PM_console_fd = open(fname, O_RDWR)) >= 0) && + (ioctl(_PM_console_fd, VT_GETSTATE, &vts) >= 0)) { + if (!check_owner(vts.v_active)) + goto Error; + restore_text_console(_PM_console_fd); + + /* Success, redirect all stdios */ + fflush(stdin); + fflush(stdout); + fflush(stderr); + close(0); + close(1); + close(2); + dup(_PM_console_fd); + dup(_PM_console_fd); + dup(_PM_console_fd); + + /* clear screen and switch to it */ + fwrite("\e[H\e[J", 6, 1, stderr); + fflush(stderr); + if (tty_vc != vts.v_active) { + startup_vc = vts.v_active; + ioctl(_PM_console_fd, VT_ACTIVATE, tty_vc); + wait_vt_active(_PM_console_fd); + } + } + return _PM_console_fd; + +Error: + if (_PM_console_fd > 2) + close(_PM_console_fd); + console_count = 0; + PM_fatalError( + "Not running in a graphics capable console,\n" + "and unable to find one.\n"); + return -1; +} + +#define FONT_C 0x10000 /* 64KB for font data */ + +/**************************************************************************** +REMARKS: +Returns the size of the console state buffer. +****************************************************************************/ +int PMAPI PM_getConsoleStateSize(void) +{ + if (!inited) + PM_init(); + return PM_getVGAStateSize() + FONT_C*2; +} + +/**************************************************************************** +REMARKS: +Save the state of the Linux console. +****************************************************************************/ +void PMAPI PM_saveConsoleState(void *stateBuf,int console_id) +{ + uchar *regs = stateBuf; + + /* Save the current console font */ + if (ioctl(console_id,GIO_FONT,®s[PM_getVGAStateSize()]) < 0) + perror("ioctl(GIO_FONT)"); + + /* Inform the Linux console that we are going into graphics mode */ + if (ioctl(console_id, KDSETMODE, KD_GRAPHICS) < 0) + perror("ioctl(KDSETMODE)"); + + /* Save state of VGA registers */ + PM_saveVGAState(stateBuf); +} + +void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags)) +{ + /* TODO: Implement support for allowing console switching! */ +} + +/**************************************************************************** +REMARKS: +Restore the state of the Linux console. +****************************************************************************/ +void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND console_id) +{ + const uchar *regs = stateBuf; + + /* Restore the state of the VGA compatible registers */ + PM_restoreVGAState(stateBuf); + + /* Inform the Linux console that we are back from graphics modes */ + if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0) + LOGWARN("ioctl(KDSETMODE) failed"); + + /* Restore the old console font */ + if (ioctl(console_id,PIO_FONT,®s[PM_getVGAStateSize()]) < 0) + LOGWARN("ioctl(KDSETMODE) failed"); + + /* Coming back from graphics mode on Linux also restored the previous + * text mode console contents, so we need to clear the screen to get + * around this since the cursor does not get homed by our code. + */ + fflush(stdout); + fflush(stderr); + printf("\033[H\033[J"); + fflush(stdout); +} + +/**************************************************************************** +REMARKS: +Close the Linux console and put it back to normal. +****************************************************************************/ +void PMAPI PM_closeConsole(PM_HWND _PM_console_fd) +{ + /* Restore console to normal operation */ + if (--console_count == 0) { + /* Re-activate the original virtual console */ + if (startup_vc > 0) + ioctl(_PM_console_fd, VT_ACTIVATE, startup_vc); + + /* Close the console file descriptor */ + if (_PM_console_fd > 2) + close(_PM_console_fd); + _PM_console_fd = -1; + } +} + +void PM_setOSCursorLocation(int x,int y) +{ + /* Nothing to do in here */ +} + +/**************************************************************************** +REMARKS: +Set the screen width and height for the Linux console. +****************************************************************************/ +void PM_setOSScreenWidth(int width,int height) +{ + struct winsize ws; + struct vt_sizes vs; + + // Resize the software terminal + ws.ws_col = width; + ws.ws_row = height; + ioctl(_PM_console_fd, TIOCSWINSZ, &ws); + + // And the hardware + vs.v_rows = height; + vs.v_cols = width; + vs.v_scrollsize = 0; + ioctl(_PM_console_fd, VT_RESIZE, &vs); +} + +ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler ih, int frequency) +{ + // TODO: Implement this for Linux + return false; +} + +void PMAPI PM_setRealTimeClockFrequency(int frequency) +{ + // TODO: Implement this for Linux +} + +void PMAPI PM_restoreRealTimeClockHandler(void) +{ + // TODO: Implement this for Linux +} + +char * PMAPI PM_getCurrentPath( + char *path, + int maxLen) +{ + return getcwd(path,maxLen); +} + +char PMAPI PM_getBootDrive(void) +{ return '/'; } + +const char * PMAPI PM_getVBEAFPath(void) +{ return PM_getNucleusConfigPath(); } + +const char * PMAPI PM_getNucleusPath(void) +{ + char *env = getenv("NUCLEUS_PATH"); + return env ? env : "/usr/lib/nucleus"; +} + +const char * PMAPI PM_getNucleusConfigPath(void) +{ + static char path[256]; + strcpy(path,PM_getNucleusPath()); + PM_backslash(path); + strcat(path,"config"); + return path; +} + +const char * PMAPI PM_getUniqueID(void) +{ + static char buf[128]; + gethostname(buf, 128); + return buf; +} + +const char * PMAPI PM_getMachineName(void) +{ + static char buf[128]; + gethostname(buf, 128); + return buf; +} + +void * PMAPI PM_getBIOSPointer(void) +{ + static uchar *zeroPtr = NULL; + if (!zeroPtr) + zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true); + return (void*)(zeroPtr + 0x400); +} + +void * PMAPI PM_getA0000Pointer(void) +{ + /* PM_init maps in the 0xA0000 framebuffer region 1:1 with our + * address mapping, so we can return the address here. + */ + if (!inited) + PM_init(); + return (void*)(0xA0000); +} + +void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached) +{ + uchar *p; + ulong baseAddr,baseOfs; + + if (!inited) + PM_init(); + if (base >= 0xA0000 && base < 0x100000) + return (void*)base; + if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1) + return NULL; + + /* Round the physical address to a 4Kb boundary and the limit to a + * 4Kb-1 boundary before passing the values to mmap. If we round the + * physical address, then we also add an extra offset into the address + * that we return. + */ + baseOfs = base & 4095; + baseAddr = base & ~4095; + limit = ((limit+baseOfs+1+4095) & ~4095)-1; + if ((p = mmap(0, limit+1, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd_mem, baseAddr)) == (void *)-1) + return NULL; + return (void*)(p+baseOfs); +} + +void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit) +{ + if ((ulong)ptr >= 0x100000) + munmap(ptr,limit+1); +} + +ulong PMAPI PM_getPhysicalAddr(void *p) +{ + // TODO: This function should find the physical address of a linear + // address. + return 0xFFFFFFFFUL; +} + +ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress) +{ + // TODO: This function should find a range of physical addresses + // for a linear address. + return false; +} + +void PMAPI PM_sleep(ulong milliseconds) +{ + // TODO: Put the process to sleep for milliseconds +} + +int PMAPI PM_getCOMPort(int port) +{ + // TODO: Re-code this to determine real values using the Plug and Play + // manager for the OS. + switch (port) { + case 0: return 0x3F8; + case 1: return 0x2F8; + } + return 0; +} + +int PMAPI PM_getLPTPort(int port) +{ + // TODO: Re-code this to determine real values using the Plug and Play + // manager for the OS. + switch (port) { + case 0: return 0x3BC; + case 1: return 0x378; + case 2: return 0x278; + } + return 0; +} + +void * PMAPI PM_mallocShared(long size) +{ + return PM_malloc(size); +} + +void PMAPI PM_freeShared(void *ptr) +{ + PM_free(ptr); +} + +void * PMAPI PM_mapToProcess(void *base,ulong limit) +{ return (void*)base; } + +void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off) +{ + /* PM_init maps in the 0xA0000-0x100000 region 1:1 with our + * address mapping, as well as all memory blocks in a 1:1 address + * mapping so we can simply return the physical address in here. + */ + if (!inited) + PM_init(); + return (void*)MK_PHYS(r_seg,r_off); +} + +void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off) +{ + int i; + char *r = (char *)REAL_MEM_BASE; + + if (!inited) + PM_init(); + if (!mem_info.ready) + return NULL; + if (mem_info.count == REAL_MEM_BLOCKS) + return NULL; + size = (size + 15) & ~15; + for (i = 0; i < mem_info.count; i++) { + if (mem_info.blocks[i].free && size < mem_info.blocks[i].size) { + insert_block(i); + mem_info.blocks[i].size = size; + mem_info.blocks[i].free = 0; + mem_info.blocks[i + 1].size -= size; + *r_seg = (uint)(r) >> 4; + *r_off = (uint)(r) & 0xF; + return (void *)r; + } + r += mem_info.blocks[i].size; + } + return NULL; +} + +void PMAPI PM_freeRealSeg(void *mem) +{ + int i; + char *r = (char *)REAL_MEM_BASE; + + if (!mem_info.ready) + return; + i = 0; + while (mem != (void *)r) { + r += mem_info.blocks[i].size; + i++; + if (i == mem_info.count) + return; + } + mem_info.blocks[i].free = 1; + if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) { + mem_info.blocks[i].size += mem_info.blocks[i + 1].size; + delete_block(i + 1); + } + if (i - 1 >= 0 && mem_info.blocks[i - 1].free) { + mem_info.blocks[i - 1].size += mem_info.blocks[i].size; + delete_block(i); + } +} + +#define DIRECTION_FLAG (1 << 10) + +static void em_ins(int size) +{ + unsigned int edx, edi; + + edx = context.vm.regs.edx & 0xffff; + edi = context.vm.regs.edi & 0xffff; + edi += (unsigned int)context.vm.regs.ds << 4; + if (context.vm.regs.eflags & DIRECTION_FLAG) { + if (size == 4) + asm volatile ("std; insl; cld" + : "=D" (edi) : "d" (edx), "0" (edi)); + else if (size == 2) + asm volatile ("std; insw; cld" + : "=D" (edi) : "d" (edx), "0" (edi)); + else + asm volatile ("std; insb; cld" + : "=D" (edi) : "d" (edx), "0" (edi)); + } + else { + if (size == 4) + asm volatile ("cld; insl" + : "=D" (edi) : "d" (edx), "0" (edi)); + else if (size == 2) + asm volatile ("cld; insw" + : "=D" (edi) : "d" (edx), "0" (edi)); + else + asm volatile ("cld; insb" + : "=D" (edi) : "d" (edx), "0" (edi)); + } + edi -= (unsigned int)context.vm.regs.ds << 4; + context.vm.regs.edi &= 0xffff0000; + context.vm.regs.edi |= edi & 0xffff; +} + +static void em_rep_ins(int size) +{ + unsigned int ecx, edx, edi; + + ecx = context.vm.regs.ecx & 0xffff; + edx = context.vm.regs.edx & 0xffff; + edi = context.vm.regs.edi & 0xffff; + edi += (unsigned int)context.vm.regs.ds << 4; + if (context.vm.regs.eflags & DIRECTION_FLAG) { + if (size == 4) + asm volatile ("std; rep; insl; cld" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + else if (size == 2) + asm volatile ("std; rep; insw; cld" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + else + asm volatile ("std; rep; insb; cld" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + } + else { + if (size == 4) + asm volatile ("cld; rep; insl" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + else if (size == 2) + asm volatile ("cld; rep; insw" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + else + asm volatile ("cld; rep; insb" + : "=D" (edi), "=c" (ecx) + : "d" (edx), "0" (edi), "1" (ecx)); + } + + edi -= (unsigned int)context.vm.regs.ds << 4; + context.vm.regs.edi &= 0xffff0000; + context.vm.regs.edi |= edi & 0xffff; + context.vm.regs.ecx &= 0xffff0000; + context.vm.regs.ecx |= ecx & 0xffff; +} + +static void em_outs(int size) +{ + unsigned int edx, esi; + + edx = context.vm.regs.edx & 0xffff; + esi = context.vm.regs.esi & 0xffff; + esi += (unsigned int)context.vm.regs.ds << 4; + if (context.vm.regs.eflags & DIRECTION_FLAG) { + if (size == 4) + asm volatile ("std; outsl; cld" + : "=S" (esi) : "d" (edx), "0" (esi)); + else if (size == 2) + asm volatile ("std; outsw; cld" + : "=S" (esi) : "d" (edx), "0" (esi)); + else + asm volatile ("std; outsb; cld" + : "=S" (esi) : "d" (edx), "0" (esi)); + } + else { + if (size == 4) + asm volatile ("cld; outsl" + : "=S" (esi) : "d" (edx), "0" (esi)); + else if (size == 2) + asm volatile ("cld; outsw" + : "=S" (esi) : "d" (edx), "0" (esi)); + else + asm volatile ("cld; outsb" + : "=S" (esi) : "d" (edx), "0" (esi)); + } + + esi -= (unsigned int)context.vm.regs.ds << 4; + context.vm.regs.esi &= 0xffff0000; + context.vm.regs.esi |= esi & 0xffff; +} + +static void em_rep_outs(int size) +{ + unsigned int ecx, edx, esi; + + ecx = context.vm.regs.ecx & 0xffff; + edx = context.vm.regs.edx & 0xffff; + esi = context.vm.regs.esi & 0xffff; + esi += (unsigned int)context.vm.regs.ds << 4; + if (context.vm.regs.eflags & DIRECTION_FLAG) { + if (size == 4) + asm volatile ("std; rep; outsl; cld" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + else if (size == 2) + asm volatile ("std; rep; outsw; cld" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + else + asm volatile ("std; rep; outsb; cld" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + } + else { + if (size == 4) + asm volatile ("cld; rep; outsl" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + else if (size == 2) + asm volatile ("cld; rep; outsw" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + else + asm volatile ("cld; rep; outsb" + : "=S" (esi), "=c" (ecx) + : "d" (edx), "0" (esi), "1" (ecx)); + } + + esi -= (unsigned int)context.vm.regs.ds << 4; + context.vm.regs.esi &= 0xffff0000; + context.vm.regs.esi |= esi & 0xffff; + context.vm.regs.ecx &= 0xffff0000; + context.vm.regs.ecx |= ecx & 0xffff; +} + +static int emulate(void) +{ + unsigned char *insn; + struct { + unsigned int size : 1; + unsigned int rep : 1; + } prefix = { 0, 0 }; + int i = 0; + + insn = (unsigned char *)((unsigned int)context.vm.regs.cs << 4); + insn += context.vm.regs.eip; + + while (1) { +#ifdef TRACE_IO + traceAddr = ((ulong)context.vm.regs.cs << 16) + context.vm.regs.eip + i; +#endif + if (insn[i] == 0x66) { + prefix.size = 1 - prefix.size; + i++; + } + else if (insn[i] == 0xf3) { + prefix.rep = 1; + i++; + } + else if (insn[i] == 0xf0 || insn[i] == 0xf2 + || insn[i] == 0x26 || insn[i] == 0x2e + || insn[i] == 0x36 || insn[i] == 0x3e + || insn[i] == 0x64 || insn[i] == 0x65 + || insn[i] == 0x67) { + /* these prefixes are just ignored */ + i++; + } + else if (insn[i] == 0x6c) { + if (prefix.rep) + em_rep_ins(1); + else + em_ins(1); + i++; + break; + } + else if (insn[i] == 0x6d) { + if (prefix.rep) { + if (prefix.size) + em_rep_ins(4); + else + em_rep_ins(2); + } + else { + if (prefix.size) + em_ins(4); + else + em_ins(2); + } + i++; + break; + } + else if (insn[i] == 0x6e) { + if (prefix.rep) + em_rep_outs(1); + else + em_outs(1); + i++; + break; + } + else if (insn[i] == 0x6f) { + if (prefix.rep) { + if (prefix.size) + em_rep_outs(4); + else + em_rep_outs(2); + } + else { + if (prefix.size) + em_outs(4); + else + em_outs(2); + } + i++; + break; + } + else if (insn[i] == 0xec) { + *((uchar*)&context.vm.regs.eax) = port_in(context.vm.regs.edx); + i++; + break; + } + else if (insn[i] == 0xed) { + if (prefix.size) + *((ulong*)&context.vm.regs.eax) = port_inl(context.vm.regs.edx); + else + *((ushort*)&context.vm.regs.eax) = port_inw(context.vm.regs.edx); + i++; + break; + } + else if (insn[i] == 0xee) { + port_out(context.vm.regs.eax,context.vm.regs.edx); + i++; + break; + } + else if (insn[i] == 0xef) { + if (prefix.size) + port_outl(context.vm.regs.eax,context.vm.regs.edx); + else + port_outw(context.vm.regs.eax,context.vm.regs.edx); + i++; + break; + } + else + return 0; + } + + context.vm.regs.eip += i; + return 1; +} + +static void debug_info(int vret) +{ + int i; + unsigned char *p; + + fputs("vm86() failed\n", stderr); + fprintf(stderr, "return = 0x%x\n", vret); + fprintf(stderr, "eax = 0x%08lx\n", context.vm.regs.eax); + fprintf(stderr, "ebx = 0x%08lx\n", context.vm.regs.ebx); + fprintf(stderr, "ecx = 0x%08lx\n", context.vm.regs.ecx); + fprintf(stderr, "edx = 0x%08lx\n", context.vm.regs.edx); + fprintf(stderr, "esi = 0x%08lx\n", context.vm.regs.esi); + fprintf(stderr, "edi = 0x%08lx\n", context.vm.regs.edi); + fprintf(stderr, "ebp = 0x%08lx\n", context.vm.regs.ebp); + fprintf(stderr, "eip = 0x%08lx\n", context.vm.regs.eip); + fprintf(stderr, "cs = 0x%04x\n", context.vm.regs.cs); + fprintf(stderr, "esp = 0x%08lx\n", context.vm.regs.esp); + fprintf(stderr, "ss = 0x%04x\n", context.vm.regs.ss); + fprintf(stderr, "ds = 0x%04x\n", context.vm.regs.ds); + fprintf(stderr, "es = 0x%04x\n", context.vm.regs.es); + fprintf(stderr, "fs = 0x%04x\n", context.vm.regs.fs); + fprintf(stderr, "gs = 0x%04x\n", context.vm.regs.gs); + fprintf(stderr, "eflags = 0x%08lx\n", context.vm.regs.eflags); + fputs("cs:ip = [ ", stderr); + p = (unsigned char *)((context.vm.regs.cs << 4) + (context.vm.regs.eip & 0xffff)); + for (i = 0; i < 16; ++i) + fprintf(stderr, "%02x ", (unsigned int)p[i]); + fputs("]\n", stderr); + fflush(stderr); +} + +static int run_vm86(void) +{ + unsigned int vret; + + for (;;) { + vret = vm86(&context.vm); + if (VM86_TYPE(vret) == VM86_INTx) { + unsigned int v = VM86_ARG(vret); + if (v == RETURN_TO_32_INT) + return 1; + pushw(context.vm.regs.eflags); + pushw(context.vm.regs.cs); + pushw(context.vm.regs.eip); + context.vm.regs.cs = get_int_seg(v); + context.vm.regs.eip = get_int_off(v); + context.vm.regs.eflags &= ~(VIF_MASK | TF_MASK); + continue; + } + if (VM86_TYPE(vret) != VM86_UNKNOWN) + break; + if (!emulate()) + break; + } + debug_info(vret); + return 0; +} + +#define IND(ereg) context.vm.regs.ereg = regs->ereg +#define OUTD(ereg) regs->ereg = context.vm.regs.ereg + +void PMAPI DPMI_int86(int intno, DPMI_regs *regs) +{ + if (!inited) + PM_init(); + memset(&context.vm.regs, 0, sizeof(context.vm.regs)); + IND(eax); IND(ebx); IND(ecx); IND(edx); IND(esi); IND(edi); + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.cs = get_int_seg(intno); + context.vm.regs.eip = get_int_off(intno); + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + pushw(DEFAULT_VM86_FLAGS); + pushw(context.ret_seg); + pushw(context.ret_off); + run_vm86(); + OUTD(eax); OUTD(ebx); OUTD(ecx); OUTD(edx); OUTD(esi); OUTD(edi); + regs->flags = context.vm.regs.eflags; +} + +#define IN(ereg) context.vm.regs.ereg = in->e.ereg +#define OUT(ereg) out->e.ereg = context.vm.regs.ereg + +int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out) +{ + if (!inited) + PM_init(); + memset(&context.vm.regs, 0, sizeof(context.vm.regs)); + IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi); + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.cs = get_int_seg(intno); + context.vm.regs.eip = get_int_off(intno); + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + pushw(DEFAULT_VM86_FLAGS); + pushw(context.ret_seg); + pushw(context.ret_off); + run_vm86(); + OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi); + out->x.cflag = context.vm.regs.eflags & 1; + return out->x.ax; +} + +int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, + RMSREGS *sregs) +{ + if (!inited) + PM_init(); + if (intno == 0x21) { + time_t today = time(NULL); + struct tm *t; + t = localtime(&today); + out->x.cx = t->tm_year + 1900; + out->h.dh = t->tm_mon + 1; + out->h.dl = t->tm_mday; + } + else { + unsigned int seg, off; + seg = get_int_seg(intno); + off = get_int_off(intno); + memset(&context.vm.regs, 0, sizeof(context.vm.regs)); + IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi); + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.cs = seg; + context.vm.regs.eip = off; + context.vm.regs.es = sregs->es; + context.vm.regs.ds = sregs->ds; + context.vm.regs.fs = sregs->fs; + context.vm.regs.gs = sregs->gs; + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + pushw(DEFAULT_VM86_FLAGS); + pushw(context.ret_seg); + pushw(context.ret_off); + run_vm86(); + OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi); + sregs->es = context.vm.regs.es; + sregs->ds = context.vm.regs.ds; + sregs->fs = context.vm.regs.fs; + sregs->gs = context.vm.regs.gs; + out->x.cflag = context.vm.regs.eflags & 1; + } + return out->e.eax; +} + +#define OUTR(ereg) in->e.ereg = context.vm.regs.ereg + +void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in, + RMSREGS *sregs) +{ + if (!inited) + PM_init(); + memset(&context.vm.regs, 0, sizeof(context.vm.regs)); + IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi); + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.cs = seg; + context.vm.regs.eip = off; + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + context.vm.regs.es = sregs->es; + context.vm.regs.ds = sregs->ds; + context.vm.regs.fs = sregs->fs; + context.vm.regs.gs = sregs->gs; + pushw(DEFAULT_VM86_FLAGS); + pushw(context.ret_seg); + pushw(context.ret_off); + run_vm86(); + OUTR(eax); OUTR(ebx); OUTR(ecx); OUTR(edx); OUTR(esi); OUTR(edi); + sregs->es = context.vm.regs.es; + sregs->ds = context.vm.regs.ds; + sregs->fs = context.vm.regs.fs; + sregs->gs = context.vm.regs.gs; + in->x.cflag = context.vm.regs.eflags & 1; +} + +void PMAPI PM_availableMemory(ulong *physical,ulong *total) +{ + FILE *mem = fopen("/proc/meminfo","r"); + char buf[1024]; + + fgets(buf,1024,mem); + fgets(buf,1024,mem); + sscanf(buf,"Mem: %*d %*d %ld", physical); + fgets(buf,1024,mem); + sscanf(buf,"Swap: %*d %*d %ld", total); + fclose(mem); + *total += *physical; +} + +void * PMAPI PM_allocLockedMem(uint size,ulong *physAddr,ibool contiguous,ibool below16M) +{ + // TODO: Implement this for Linux + return NULL; +} + +void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous) +{ + // TODO: Implement this for Linux +} + +void * PMAPI PM_allocPage( + ibool locked) +{ + // TODO: Implement this for Linux + return NULL; +} + +void PMAPI PM_freePage( + void *p) +{ + // TODO: Implement this for Linux +} + +void PMAPI PM_setBankA(int bank) +{ + if (!inited) + PM_init(); + memset(&context.vm.regs, 0, sizeof(context.vm.regs)); + context.vm.regs.eax = 0x4F05; + context.vm.regs.ebx = 0x0000; + context.vm.regs.edx = bank; + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.cs = get_int_seg(0x10); + context.vm.regs.eip = get_int_off(0x10); + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + pushw(DEFAULT_VM86_FLAGS); + pushw(context.ret_seg); + pushw(context.ret_off); + run_vm86(); +} + +void PMAPI PM_setBankAB(int bank) +{ + if (!inited) + PM_init(); + memset(&context.vm.regs, 0, sizeof(context.vm.regs)); + context.vm.regs.eax = 0x4F05; + context.vm.regs.ebx = 0x0000; + context.vm.regs.edx = bank; + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.cs = get_int_seg(0x10); + context.vm.regs.eip = get_int_off(0x10); + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + pushw(DEFAULT_VM86_FLAGS); + pushw(context.ret_seg); + pushw(context.ret_off); + run_vm86(); + context.vm.regs.eax = 0x4F05; + context.vm.regs.ebx = 0x0001; + context.vm.regs.edx = bank; + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.cs = get_int_seg(0x10); + context.vm.regs.eip = get_int_off(0x10); + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + pushw(DEFAULT_VM86_FLAGS); + pushw(context.ret_seg); + pushw(context.ret_off); + run_vm86(); +} + +void PMAPI PM_setCRTStart(int x,int y,int waitVRT) +{ + if (!inited) + PM_init(); + memset(&context.vm.regs, 0, sizeof(context.vm.regs)); + context.vm.regs.eax = 0x4F07; + context.vm.regs.ebx = waitVRT; + context.vm.regs.ecx = x; + context.vm.regs.edx = y; + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.cs = get_int_seg(0x10); + context.vm.regs.eip = get_int_off(0x10); + context.vm.regs.ss = context.stack_seg; + context.vm.regs.esp = context.stack_off; + pushw(DEFAULT_VM86_FLAGS); + pushw(context.ret_seg); + pushw(context.ret_off); + run_vm86(); +} + +int PMAPI PM_enableWriteCombine(ulong base,ulong length,uint type) +{ +#ifdef ENABLE_MTRR + struct mtrr_sentry sentry; + + if (mtrr_fd < 0) + return PM_MTRR_ERR_NO_OS_SUPPORT; + sentry.base = base; + sentry.size = length; + sentry.type = type; + if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) == -1) { + // TODO: Need to decode MTRR error codes!! + return PM_MTRR_NOT_SUPPORTED; + } + return PM_MTRR_ERR_OK; +#else + return PM_MTRR_ERR_NO_OS_SUPPORT; +#endif +} + +/**************************************************************************** +PARAMETERS: +callback - Function to callback with write combine information + +REMARKS: +Function to enumerate all write combine regions currently enabled for the +processor. +****************************************************************************/ +int PMAPI PM_enumWriteCombine( + PM_enumWriteCombine_t callback) +{ +#ifdef ENABLE_MTRR + struct mtrr_gentry gentry; + + if (mtrr_fd < 0) + return PM_MTRR_ERR_NO_OS_SUPPORT; + + for (gentry.regnum = 0; ioctl (mtrr_fd, MTRRIOC_GET_ENTRY, &gentry) == 0; + ++gentry.regnum) { + if (gentry.size > 0) { + // WARNING: This code assumes that the types in pmapi.h match the ones + // in the Linux kernel (mtrr.h) + callback(gentry.base, gentry.size, gentry.type); + } + } + + return PM_MTRR_ERR_OK; +#else + return PM_MTRR_ERR_NO_OS_SUPPORT; +#endif +} + +ibool PMAPI PM_doBIOSPOST( + ushort axVal, + ulong BIOSPhysAddr, + void *copyOfBIOS, + ulong BIOSLen) +{ + char *bios_ptr = (char*)0xC0000; + char *old_bios; + ulong Current10, Current6D, *rvec = 0; + RMREGS regs; + RMSREGS sregs; + + /* The BIOS is mapped to 0xC0000 with a private memory mapping enabled + * which means we have a copy on write scheme. Hence we simply copy + * the secondary BIOS image over the top of the old one. + */ + if (!inited) + PM_init(); + if ((old_bios = PM_malloc(BIOSLen)) == NULL) + return false; + if (BIOSPhysAddr != 0xC0000) { + memcpy(old_bios,bios_ptr,BIOSLen); + memcpy(bios_ptr,copyOfBIOS,BIOSLen); + } + + /* The interrupt vectors should already be mmap()'ed from 0-0x400 in PM_init */ + Current10 = rvec[0x10]; + Current6D = rvec[0x6D]; + + /* POST the secondary BIOS */ + rvec[0x10] = rvec[0x42]; /* Restore int 10h to STD-BIOS */ + regs.x.ax = axVal; + PM_callRealMode(0xC000,0x0003,®s,&sregs); + + /* Restore interrupt vectors */ + rvec[0x10] = Current10; + rvec[0x6D] = Current6D; + + /* Restore original BIOS image */ + if (BIOSPhysAddr != 0xC0000) + memcpy(bios_ptr,old_bios,BIOSLen); + PM_free(old_bios); + return true; +} + +int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh) +{ + p = p; len = len; + return 1; +} + +int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh) +{ + p = p; len = len; + return 1; +} + +int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh) +{ + p = p; len = len; + return 1; +} + +int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh) +{ + p = p; len = len; + return 1; +} + +PM_MODULE PMAPI PM_loadLibrary( + const char *szDLLName) +{ + // TODO: Implement this to load shared libraries! + (void)szDLLName; + return NULL; +} + +void * PMAPI PM_getProcAddress( + PM_MODULE hModule, + const char *szProcName) +{ + // TODO: Implement this! + (void)hModule; + (void)szProcName; + return NULL; +} + +void PMAPI PM_freeLibrary( + PM_MODULE hModule) +{ + // TODO: Implement this! + (void)hModule; +} + +int PMAPI PM_setIOPL( + int level) +{ + // TODO: Move the IOPL switching into this function!! + return level; +} + +void PMAPI PM_flushTLB(void) +{ + // Do nothing on Linux. +} + -- cgit v1.2.1