New upstream version 2.0pre9.2
This commit is contained in:
7
src/base/core/Makefile
Normal file
7
src/base/core/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
top_builddir=../../..
|
||||
include $(top_builddir)/Makefile.conf
|
||||
|
||||
CFILES = dyndeb.c int.c hlt.c emu.c ports.c coopth.c dump.c lowmem.c priv.c \
|
||||
vint.c
|
||||
|
||||
include $(REALTOPDIR)/src/Makefile.common
|
||||
1541
src/base/core/coopth.c
Normal file
1541
src/base/core/coopth.c
Normal file
File diff suppressed because it is too large
Load Diff
161
src/base/core/dump.c
Normal file
161
src/base/core/dump.c
Normal file
@@ -0,0 +1,161 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "emu.h"
|
||||
#include "cpu.h"
|
||||
#include "port.h"
|
||||
#include "emu-ldt.h"
|
||||
#include "emudpmi.h"
|
||||
#include "int.h"
|
||||
#include "mapping.h"
|
||||
#ifdef X86_EMULATOR
|
||||
#include "cpu-emu.h"
|
||||
#endif
|
||||
#include "dis8086.h"
|
||||
|
||||
char *emu_disasm(unsigned int ip)
|
||||
{
|
||||
static char buf[2048];
|
||||
#ifdef USE_MHPDBG
|
||||
char frmtbuf[1024];
|
||||
int rc, i;
|
||||
unsigned int cp;
|
||||
char *p;
|
||||
unsigned int refseg;
|
||||
unsigned int ref;
|
||||
|
||||
cp = SEGOFF2LINEAR(_CS, _IP);
|
||||
refseg = SREG(cs);
|
||||
|
||||
rc = dis_8086(cp, frmtbuf, 0, &ref, refseg * 16);
|
||||
|
||||
p = buf;
|
||||
for (i=0; i<rc && i<8; i++) {
|
||||
p += sprintf(p, "%02x", READ_BYTE(cp+i));
|
||||
}
|
||||
sprintf(p,"%20s", " ");
|
||||
sprintf(buf+20, "%04x:%04x %s", SREG(cs), LWORD(eip), frmtbuf);
|
||||
#else
|
||||
buf[0] = '\0';
|
||||
#endif
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
/* show_regs,show_ints @@@ 32768 MOVED_CODE_BEGIN @@@ 01/23/96, ./src/emu-i386/cpu.c --> src/base/misc/dump.c */
|
||||
void show_regs(void)
|
||||
{
|
||||
int i;
|
||||
unsigned int sp, cp;
|
||||
|
||||
cp = SEGOFF2LINEAR(_CS, _IP);
|
||||
if (cp < 1024) {
|
||||
dbug_printf("Ain't gonna do it, cs=0x%x, eip=0x%x\n",SREG(cs),LWORD(eip));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LWORD(esp))
|
||||
sp = SEGOFF2LINEAR(_SS, _SP) + 0x8000;
|
||||
else
|
||||
sp = SEGOFF2LINEAR(_SS, _SP);
|
||||
|
||||
dbug_printf("Real-mode state dump:\n");
|
||||
dbug_printf("EIP: %04x:%08x", SREG(cs), REG(eip));
|
||||
dbug_printf(" ESP: %04x:%08x", SREG(ss), REG(esp));
|
||||
#if 1
|
||||
dbug_printf(" VFLAGS(b): ");
|
||||
for (i = (1 << 0x14); i > 0; i = (i >> 1)) {
|
||||
dbug_printf((vflags & i) ? "1" : "0");
|
||||
if (i & 0x10100) dbug_printf(" ");
|
||||
}
|
||||
#else
|
||||
dbug_printf(" VFLAGS(b): ");
|
||||
for (i = (1 << 0x11); i > 0; i = (i >> 1))
|
||||
dbug_printf((vflags & i) ? "1" : "0");
|
||||
#endif
|
||||
dbug_printf("\nEAX: %08x EBX: %08x ECX: %08x EDX: %08x VFLAGS(h): %08lx",
|
||||
REG(eax), REG(ebx), REG(ecx), REG(edx), (unsigned long)vflags);
|
||||
dbug_printf("\nESI: %08x EDI: %08x EBP: %08x",
|
||||
REG(esi), REG(edi), REG(ebp));
|
||||
dbug_printf(" DS: %04x ES: %04x FS: %04x GS: %04x\n",
|
||||
SREG(ds), SREG(es), SREG(fs), SREG(gs));
|
||||
|
||||
/* display vflags symbolically...the #f "stringizes" the macro name */
|
||||
#define PFLAG(f) if (REG(eflags)&(f)) dbug_printf(#f" ")
|
||||
|
||||
dbug_printf("FLAGS: ");
|
||||
PFLAG(CF);
|
||||
PFLAG(PF);
|
||||
PFLAG(AF);
|
||||
PFLAG(ZF);
|
||||
PFLAG(SF);
|
||||
PFLAG(TF);
|
||||
PFLAG(IF);
|
||||
PFLAG(DF);
|
||||
PFLAG(OF);
|
||||
PFLAG(NT);
|
||||
PFLAG(RF);
|
||||
PFLAG(VM);
|
||||
PFLAG(AC);
|
||||
PFLAG(VIF);
|
||||
PFLAG(VIP);
|
||||
dbug_printf(" IOPL: %u\n", (unsigned) ((vflags & IOPL_MASK) >> 12));
|
||||
|
||||
/* display the 10 bytes before and after CS:EIP. the -> points
|
||||
* to the byte at address CS:EIP
|
||||
*/
|
||||
if (sp < 0xa0000 && sp > 10) {
|
||||
dbug_printf("STACK: ");
|
||||
sp -= 10;
|
||||
for (i = 0; i < 10; i++)
|
||||
dbug_printf("%02x ", READ_BYTE(sp++));
|
||||
dbug_printf("-> ");
|
||||
for (i = 0; i < 10; i++)
|
||||
dbug_printf("%02x ", READ_BYTE(sp++));
|
||||
dbug_printf("\n");
|
||||
}
|
||||
dbug_printf("OPS : ");
|
||||
cp -= 10;
|
||||
for (i = 0; i < 10; i++)
|
||||
dbug_printf("%02x ", READ_BYTE(cp++));
|
||||
dbug_printf("-> ");
|
||||
for (i = 0; i < 10; i++)
|
||||
dbug_printf("%02x ", READ_BYTE(cp++));
|
||||
dbug_printf("\n\t%s\n", emu_disasm(0));
|
||||
}
|
||||
|
||||
void
|
||||
show_ints(int min, int max)
|
||||
{
|
||||
int i, b;
|
||||
|
||||
max = (max - min) / 3;
|
||||
for (i = 0, b = min; i <= max; i++, b += 3) {
|
||||
g_printf("%02x| %04x:%04x->%06x ", b, ISEG(b), IOFF(b),
|
||||
IVEC(b));
|
||||
g_printf("%02x| %04x:%04x->%06x ", b + 1, ISEG(b + 1), IOFF(b + 1),
|
||||
IVEC(b + 1));
|
||||
g_printf("%02x| %04x:%04x->%06x\n", b + 2, ISEG(b + 2), IOFF(b + 2),
|
||||
IVEC(b + 2));
|
||||
}
|
||||
}
|
||||
|
||||
#if MAX_SELECTORS != 8192
|
||||
#error MAX_SELECTORS needs to be 8192
|
||||
#endif
|
||||
|
||||
#define IsSegment32(s) dpmi_segment_is32(s)
|
||||
|
||||
void dump_state(void)
|
||||
{
|
||||
cpuctx_t *scp = dpmi_get_scp();
|
||||
show_regs();
|
||||
if (scp)
|
||||
dbug_printf("\nProtected-mode state dump:\n%s\n", DPMI_show_state(scp));
|
||||
}
|
||||
298
src/base/core/dyndeb.c
Normal file
298
src/base/core/dyndeb.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/* dynamic debug handlers - by Tim Bird */
|
||||
/* modified to support debug levels -- peak */
|
||||
/* Rehash so we aren't changing the code all of the time. Eric Biederman */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "emu.h"
|
||||
#include "dosemu_debug.h"
|
||||
#include "dosemu_config.h"
|
||||
#include "init.h"
|
||||
#include "int.h"
|
||||
#include "port.h"
|
||||
|
||||
|
||||
FILE *dbg_fd;
|
||||
#ifdef DONT_DEBUG_BOOT
|
||||
static struct debug_class debug_save[DEBUG_CLASSES];
|
||||
#endif
|
||||
static struct debug_class debug[DEBUG_CLASSES];
|
||||
unsigned char debug_levels[DEBUG_CLASSES];
|
||||
int shut_debug;
|
||||
|
||||
#ifndef NO_DEBUGPRINT_AT_ALL
|
||||
|
||||
int register_debug_class(int letter, void (*change_level)(int level), const char *help_text)
|
||||
{
|
||||
struct debug_class *cls;
|
||||
if (letter >= DEBUG_CLASSES) {
|
||||
abort();
|
||||
}
|
||||
if ((letter >= '0') && (letter <= '9')) {
|
||||
abort();
|
||||
}
|
||||
cls = &debug[letter];
|
||||
if (cls->letter) {
|
||||
abort();
|
||||
}
|
||||
cls->letter = letter;
|
||||
cls->change_level = change_level;
|
||||
cls->help_text = help_text;
|
||||
debug_levels[letter] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unregister_debug_class(int letter)
|
||||
{
|
||||
struct debug_class *cls;
|
||||
if (letter >= DEBUG_CLASSES) {
|
||||
return -1;
|
||||
}
|
||||
cls = &debug[letter];
|
||||
if (!cls->letter) {
|
||||
return -1;
|
||||
}
|
||||
memset(cls, 0, sizeof(*cls));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_debug_level(int letter, int level)
|
||||
{
|
||||
struct debug_class *cls;
|
||||
if (letter >= DEBUG_CLASSES) {
|
||||
return -1;
|
||||
}
|
||||
cls = &debug[letter];
|
||||
if (!cls->letter) {
|
||||
return -1;
|
||||
}
|
||||
if (debug_levels[letter] != level) {
|
||||
debug_levels[letter] = level;
|
||||
if (cls->change_level) {
|
||||
cls->change_level(level);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DANG_BEGIN_FUNCTION parse_debugflags
|
||||
*
|
||||
* arguments:
|
||||
* s - string of options.
|
||||
*
|
||||
* description:
|
||||
* This part is fairly flexible...you specify the debugging
|
||||
* flags you wish with -D string. The string consists of the following
|
||||
* characters: + turns the following options on (initial state) -
|
||||
* turns the following options off a turns all the options on/off,
|
||||
* depending on whether +/- is set 0-9 sets debug levels (0 is off, 9 is
|
||||
* most verbose) # where # is a letter from the valid option list (see
|
||||
* docs), turns that option off/on depending on the +/- state.
|
||||
*
|
||||
* Any option letter can occur in any place. Even meaningless combinations,
|
||||
* such as "01-a-1+0vk" will be parsed without error, so be careful. Some
|
||||
* options are set by default, some are clear. This is subject to my whim.
|
||||
* You can ensure which are set by explicitly specifying.
|
||||
*
|
||||
* DANG_END_FUNCTION
|
||||
*/
|
||||
int parse_debugflags(const char *s, unsigned char flag)
|
||||
{
|
||||
char c;
|
||||
int ret = 0;
|
||||
|
||||
dbug_printf("debug flags: %s\n", s);
|
||||
while ((c = *(s++)))
|
||||
switch (c) {
|
||||
case '+': /* begin options to turn on */
|
||||
if (!flag)
|
||||
flag = 1;
|
||||
break;
|
||||
case '-': /* begin options to turn off */
|
||||
flag = 0;
|
||||
break;
|
||||
case '0'...'9': /* set debug level, 0 is off, 9 is most
|
||||
* verbose */
|
||||
flag = c - '0';
|
||||
break;
|
||||
default:
|
||||
ret = set_debug_level(c, flag);
|
||||
if (ret >= 0) {
|
||||
ret = 0;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown debug-msg mask: %c\n\r", c);
|
||||
dbug_printf("Unknown debug-msg mask: %c\n", c);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SetDebugFlagsHelper(char *debugStr)
|
||||
{
|
||||
return parse_debugflags(debugStr, 0);
|
||||
}
|
||||
|
||||
static char DebugFlag(int f)
|
||||
{
|
||||
if (f == 0)
|
||||
return '-';
|
||||
else if (f >= 2 && f <= 9)
|
||||
return f + '0';
|
||||
else
|
||||
return '+';
|
||||
}
|
||||
|
||||
int GetDebugFlagsHelper(char *debugStr, int print)
|
||||
{
|
||||
int i;
|
||||
struct debug_class *cls;
|
||||
|
||||
if (print) dbug_printf("GetDebugFlagsHelper\n");
|
||||
if (print) dbug_printf("debugStr at %p\n", debugStr);
|
||||
i = 0;
|
||||
|
||||
for(cls = debug; cls <= &debug[DEBUG_CLASSES-1]; cls++) {
|
||||
if (!cls->letter) {
|
||||
continue;
|
||||
}
|
||||
debugStr[i++] = DebugFlag(debug_levels[cls->letter]);
|
||||
debugStr[i++] = cls->letter;
|
||||
}
|
||||
|
||||
debugStr[i++] = '\0';
|
||||
if (print) dbug_printf("debugStr is %s\n", debugStr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int GetDebugInfoHelper(char *buf, int bufsize)
|
||||
{
|
||||
struct debug_class *cls;
|
||||
int num = 0, col;
|
||||
char ws;
|
||||
|
||||
for (cls = debug, col = 0; cls <= &debug[DEBUG_CLASSES - 1]; cls++) {
|
||||
if (!cls->letter)
|
||||
continue;
|
||||
|
||||
if (col++ % 3 != 0)
|
||||
ws = ' ';
|
||||
else
|
||||
ws = '\n';
|
||||
|
||||
num += snprintf(buf + num, bufsize - num, "%c%c%c: %-21s", ws,
|
||||
DebugFlag(debug_levels[cls->letter]), cls->letter, cls->help_text);
|
||||
|
||||
if (num >= bufsize) // snprintf output was truncated
|
||||
return 0;
|
||||
}
|
||||
|
||||
num += snprintf(buf + num, bufsize - num, "\n");
|
||||
if (num >= bufsize) // snprintf output was truncated
|
||||
return 0;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
void print_debug_usage(FILE *stream)
|
||||
{
|
||||
struct debug_class *cls;
|
||||
int i;
|
||||
fprintf(stream,
|
||||
" -D set debug-msg mask to flags {+-}{0-9}{");
|
||||
for(cls = debug; cls <= &debug[DEBUG_CLASSES-1]; cls++) {
|
||||
if (cls->letter) {
|
||||
putc(cls->letter, stream);
|
||||
}
|
||||
}
|
||||
fprintf(stream, "}\n");
|
||||
i = 0;
|
||||
for(cls = debug; cls <= &debug[DEBUG_CLASSES-1]; cls++) {
|
||||
if (!cls->letter) {
|
||||
continue;
|
||||
}
|
||||
if ((i & 1) == 0) {
|
||||
fprintf(stream, " ");
|
||||
}
|
||||
fprintf(stream, " %c=%-33.33s",
|
||||
cls->letter, cls->help_text);
|
||||
if ((i & 1) == 1) {
|
||||
fprintf(stream, "\n");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if ((i & 1) == 1) {
|
||||
fprintf(stream, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void all_change_level(int level)
|
||||
{
|
||||
int c;
|
||||
for (c = 0; c < DEBUG_CLASSES; c++) {
|
||||
if (c != 'a') {
|
||||
set_debug_level(c, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void int21_change_level(int level)
|
||||
{
|
||||
}
|
||||
static void port_trace_change_level(int level)
|
||||
{
|
||||
init_port_traceing();
|
||||
}
|
||||
|
||||
static void config_change_level(int level)
|
||||
{
|
||||
if (config_check_only && !level) {
|
||||
set_debug_level('c', 1);
|
||||
}
|
||||
}
|
||||
|
||||
CONSTRUCTOR(static void init(void))
|
||||
{
|
||||
register_debug_class('#', 0, "default int");
|
||||
register_debug_class('A', 0, "ASPI");
|
||||
register_debug_class('B', 0, "dosdebug trace");
|
||||
register_debug_class('C', 0, "CDROM");
|
||||
register_debug_class('D', int21_change_level, "dos int 21h");
|
||||
register_debug_class('E', 0, "EMS");
|
||||
register_debug_class('F', 0, "MMIO trace");
|
||||
register_debug_class('I', 0, "IPC");
|
||||
register_debug_class('N', 0, "NE2000 emulation");
|
||||
register_debug_class('P', 0, "Packet driver");
|
||||
register_debug_class('Q', 0, "Mapping driver");
|
||||
register_debug_class('R', 0, "disk READ");
|
||||
register_debug_class('S', 0, "SOUND");
|
||||
register_debug_class('T', port_trace_change_level, "I/O trace");
|
||||
register_debug_class('M', 0, "DPMI");
|
||||
register_debug_class('W', 0, "disk WRITE");
|
||||
register_debug_class('X', 0, "X support");
|
||||
register_debug_class('Z', 0, "PCI");
|
||||
register_debug_class('a', all_change_level, "Set all levels");
|
||||
register_debug_class('c', config_change_level, "configuration");
|
||||
register_debug_class('d', 0, "disk msgs");
|
||||
#ifdef X86_EMULATOR
|
||||
register_debug_class('e', 0, "cpu-emu");
|
||||
#endif
|
||||
register_debug_class('g', 0, "general messages");
|
||||
register_debug_class('h', 0, "hardware");
|
||||
register_debug_class('i', 0, "I/O instructions");
|
||||
register_debug_class('j', 0, "joystick");
|
||||
register_debug_class('k', 0, "keyboard");
|
||||
register_debug_class('m', 0, "mouse");
|
||||
register_debug_class('p', 0, "printer");
|
||||
register_debug_class('n', 0, "IPX network");
|
||||
register_debug_class('r', 0, "PIC request");
|
||||
register_debug_class('s', 0, "serial");
|
||||
#ifdef TRACE_DPMI
|
||||
register_debug_class('t', 0, "dpmi trace");
|
||||
#endif
|
||||
register_debug_class('v', 0, "video");
|
||||
register_debug_class('w', 0, "warnings");
|
||||
register_debug_class('x', 0, "XMS");
|
||||
};
|
||||
|
||||
#endif /* ! NO_DEBUGPRINT_AT_ALL */
|
||||
582
src/base/core/emu.c
Normal file
582
src/base/core/emu.c
Normal file
@@ -0,0 +1,582 @@
|
||||
/*
|
||||
* Extensions by Robert Sanders, 1992-93
|
||||
*
|
||||
* DANG_BEGIN_MODULE
|
||||
*
|
||||
* REMARK
|
||||
* Here is where DOSEMU gets booted. From emu.c external calls are made to
|
||||
* the specific I/O systems (video/keyboard/serial/etc...) to initialize
|
||||
* them. Memory is cleared/set up and the boot sector is read from the
|
||||
* boot drive. Many SIGNALS are set so that DOSEMU can exploit things like
|
||||
* timers, I/O signals, illegal instructions, etc... When every system
|
||||
* gives the green light, vm86() is called to switch into vm86 mode and
|
||||
* start executing i86 code.
|
||||
*
|
||||
* The vm86() function will return to DOSEMU when certain `exceptions` occur
|
||||
* as when some interrupt instructions occur (0xcd).
|
||||
*
|
||||
* The top level function emulate() is called from dos.c by way of a dll
|
||||
* entry point.
|
||||
*
|
||||
* /REMARK
|
||||
* DANG_END_MODULE
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* DANG_BEGIN_REMARK
|
||||
* DOSEMU must not work within the 1 meg DOS limit, so
|
||||
* start of code is loaded at a higher address, at some time this could
|
||||
* conflict with other shared libs. If DOSEMU is compiled statically
|
||||
* (without shared libs), and org instruction is used to provide the jump
|
||||
* above 1 meg.
|
||||
* DANG_END_REMARK
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#ifndef EDEADLOCK
|
||||
#define EDEADLOCK EDEADLK
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <locale.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "version.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#include "mhpdbg.h"
|
||||
#include "bios.h"
|
||||
#include "video.h"
|
||||
#include "timers.h"
|
||||
#include "cmos.h"
|
||||
#include "mouse.h"
|
||||
#include "disks.h"
|
||||
#include "xms.h"
|
||||
#include "ipx.h" /* TRB - add support for ipx */
|
||||
#include "serial.h"
|
||||
#include "int.h"
|
||||
#include "bitops.h"
|
||||
#include "pic.h"
|
||||
#include "emudpmi.h"
|
||||
#include "priv.h" /* for priv_init */
|
||||
#include "port.h" /* for port_init */
|
||||
#include "pci.h"
|
||||
#include "speaker.h"
|
||||
#include "utilities.h"
|
||||
#include "dos2linux.h"
|
||||
#include "iodev.h"
|
||||
#include "mapping.h"
|
||||
#include "dosemu_config.h"
|
||||
#include "libpacket.h"
|
||||
#include "ne2000.h"
|
||||
#include "dma.h"
|
||||
#include "hlt.h"
|
||||
#include "coopth.h"
|
||||
#include "keyboard/keyb_server.h"
|
||||
#include "sig.h"
|
||||
#include "sound.h"
|
||||
#include "ioselect.h"
|
||||
#ifdef X86_EMULATOR
|
||||
#include "cpu-emu.h"
|
||||
#endif
|
||||
#include "kvm.h"
|
||||
|
||||
static int ld_tid;
|
||||
static int can_leavedos;
|
||||
static int leavedos_code;
|
||||
static int leavedos_called;
|
||||
static pthread_mutex_t ld_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
__TLS union vm86_union vm86u;
|
||||
|
||||
volatile __thread int fault_cnt;
|
||||
volatile int in_vm86;
|
||||
int terminal_pipe;
|
||||
int terminal_fd = -1;
|
||||
int kernel_version_code;
|
||||
int console_fd = -1;
|
||||
int mem_fd = -1;
|
||||
int fatalerr;
|
||||
int in_leavedos;
|
||||
pthread_t dosemu_pthread_self;
|
||||
char * const *dosemu_envp;
|
||||
FILE *real_stderr;
|
||||
|
||||
#define MAX_EXIT_HANDLERS 5
|
||||
struct exit_hndl {
|
||||
void (*handler)(void);
|
||||
};
|
||||
static struct exit_hndl exit_hndl[MAX_EXIT_HANDLERS];
|
||||
static int exit_hndl_num;
|
||||
|
||||
static void __leavedos_main(int code, int sig);
|
||||
static void leavedos_thr(void *arg);
|
||||
|
||||
static int find_boot_drive(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < config.fdisks; i++) {
|
||||
if (disktab[i].boot)
|
||||
return i;
|
||||
}
|
||||
FOR_EACH_HDISK(i,
|
||||
if (disk_is_bootable(&hdisktab[i]))
|
||||
return HDISK_NUM(i);
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void boot(void)
|
||||
{
|
||||
unsigned buffer;
|
||||
struct disk *dp = NULL;
|
||||
|
||||
if (config.try_freedos && config.hdiskboot == -1 &&
|
||||
config.hdisks > 0 && !disk_is_bootable(&hdisktab[0])) {
|
||||
c_printf("Applying freedos boot work-around\n");
|
||||
config.swap_bootdrv = 1;
|
||||
}
|
||||
if (config.hdiskboot == -1)
|
||||
config.hdiskboot = find_boot_drive();
|
||||
switch (config.hdiskboot) {
|
||||
case -1:
|
||||
error("Bootable drive not found, exiting\n");
|
||||
leavedos(16);
|
||||
return;
|
||||
case 0:
|
||||
if (config.fdisks > 0)
|
||||
dp = &disktab[0];
|
||||
else {
|
||||
error("Drive A: not defined, can't boot!\n");
|
||||
leavedos(71);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
int d = 1;
|
||||
if (config.fdisks > 1) {
|
||||
if (config.swap_bootdrv) {
|
||||
struct disk tmp = disktab[1];
|
||||
disktab[1] = disktab[0];
|
||||
disktab[0] = tmp;
|
||||
disktab[0].drive_num = disktab[1].drive_num;
|
||||
disktab[1].drive_num = tmp.drive_num;
|
||||
d = 0;
|
||||
disk_reset();
|
||||
}
|
||||
dp = &disktab[d];
|
||||
} else if (config.fdisks == 1) {
|
||||
dp = &disktab[0];
|
||||
} else {
|
||||
error("Drive B: not defined, can't boot!\n");
|
||||
leavedos(71);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
int d = config.hdiskboot - 2;
|
||||
struct disk *dd = hdisk_find(d | 0x80);
|
||||
struct disk *cc = hdisk_find(0x80);
|
||||
if (config.swap_bootdrv && d && dd) {
|
||||
dd->drive_num = 0x80;
|
||||
cc->drive_num = d | 0x80;
|
||||
config.hdiskboot = 2;
|
||||
d = 0;
|
||||
disk_reset();
|
||||
}
|
||||
if (dd)
|
||||
dp = dd;
|
||||
else {
|
||||
error("Drive %c not defined, can't boot!\n", d + 'C');
|
||||
leavedos(71);
|
||||
}
|
||||
if (dp->type != DIR_TYPE && dp->drive_num != 0x80) {
|
||||
error("Boot from drive %c is not possible.\n", d + 'C');
|
||||
error("@Fix the $_hdimage setting or enable $_swap_bootdrive.\n");
|
||||
leavedos(72);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
disk_close();
|
||||
disk_open(dp);
|
||||
|
||||
buffer = 0x7c00;
|
||||
|
||||
if (dp->type == PARTITION) {/* we boot partition boot record, not MBR! */
|
||||
d_printf("Booting partition boot record from part=%s....\n", dp->dev_name);
|
||||
if (dos_read(dp->fdesc, buffer, SECTOR_SIZE) != SECTOR_SIZE) {
|
||||
error("reading partition boot sector using partition %s.\n", dp->dev_name);
|
||||
leavedos(16);
|
||||
}
|
||||
} else if (dp->floppy) {
|
||||
if (read_sectors(dp, buffer, 0, 1) != SECTOR_SIZE) {
|
||||
error("can't boot from %s, using harddisk\n", dp->dev_name);
|
||||
dp = hdisktab;
|
||||
goto mbr;
|
||||
}
|
||||
} else {
|
||||
if (dp->type == DIR_TYPE) {
|
||||
if (!disk_is_bootable(dp) || !disk_validate_boot_part(dp)) {
|
||||
error("Drive unbootable, exiting\n");
|
||||
leavedos(16);
|
||||
}
|
||||
}
|
||||
mbr:
|
||||
if (read_mbr(dp, buffer) != SECTOR_SIZE) {
|
||||
error("can't boot from hard disk\n");
|
||||
leavedos(16);
|
||||
}
|
||||
}
|
||||
disk_close();
|
||||
|
||||
/* put boot drive to dl */
|
||||
_DX = dp->drive_num;
|
||||
}
|
||||
|
||||
static int c_chk(void)
|
||||
{
|
||||
/* return 1 if the context is safe for coopth to do a thread switch */
|
||||
return !in_dpmi_pm();
|
||||
}
|
||||
|
||||
/*
|
||||
* DANG_BEGIN_FUNCTION emulate
|
||||
*
|
||||
* arguments:
|
||||
* argc - Argument count.
|
||||
* argv - Arguments.
|
||||
*
|
||||
* description:
|
||||
* Emulate gets called from dos.c. It initializes DOSEMU to
|
||||
* prepare it for running in vm86 mode. This involves catching signals,
|
||||
* preparing memory, calling all the initialization functions for the I/O
|
||||
* subsystems (video/serial/etc...), getting the boot sector instructions
|
||||
* and calling vm86().
|
||||
*
|
||||
* DANG_END_FUNCTION
|
||||
*
|
||||
*/
|
||||
int main(int argc, char **argv, char * const *envp)
|
||||
{
|
||||
dosemu_envp = envp;
|
||||
setlocale(LC_ALL,"");
|
||||
srand(time(NULL));
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
/* NOW! it is safe to touch the priv code. */
|
||||
priv_init(); /* This must come first! */
|
||||
|
||||
/* Before we even try to give options to the parser,
|
||||
* we pre-filter some dangerous options and delete them
|
||||
* from the arguments list
|
||||
*/
|
||||
secure_option_preparse(&argc, argv);
|
||||
|
||||
/* the transposal of (config_|stdio_)init allows the addition of -o */
|
||||
/* to specify a debug out filename, if you're wondering */
|
||||
|
||||
port_init(); /* setup port structures, before config! */
|
||||
version_init(); /* Check the OS version */
|
||||
config_init(argc, argv); /* parse the commands & config file(s) */
|
||||
#ifdef X86_EMULATOR
|
||||
#ifdef DONT_DEBUG_BOOT /* cpuemu only */
|
||||
memcpy(&debug_save, &debug, sizeof(debug));
|
||||
set_debug_level('e', 0);
|
||||
#ifdef TRACE_DPMI
|
||||
set_debug_level('t', 0);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
get_time_init();
|
||||
print_version(); /* log version information */
|
||||
memcheck_init();
|
||||
/* threads can be created only after signal_pre_init() so
|
||||
* it should be above device_init(), iodev_init(), cpu_setup() etc */
|
||||
signal_pre_init(); /* initialize sig's & sig handlers */
|
||||
cpu_setup(); /* setup the CPU */
|
||||
pci_setup();
|
||||
device_init(); /* priv initialization of video etc. */
|
||||
extra_port_init(); /* setup ports dependent on config */
|
||||
SIG_init(); /* Silly Interrupt Generator */
|
||||
LibpacketInit(); /* initialize network packet interfaces */
|
||||
|
||||
mapping_init(); /* initialize mapping drivers */
|
||||
|
||||
if (can_do_root_stuff && !under_root_login) {
|
||||
g_printf("dropping root privileges\n");
|
||||
open_kmem();
|
||||
}
|
||||
priv_drop();
|
||||
|
||||
map_memory_space(); /* maps all DOS memory (low, dpmi, xms...) */
|
||||
init_hardware_ram(); /* map the direct hardware ram */
|
||||
map_video_bios(); /* map (really: copy) the video bios */
|
||||
close_kmem();
|
||||
|
||||
/* the following duo have to be done before others who use hlt or coopth */
|
||||
vm86_hlt_state = hlt_init(BIOS_HLT_BLK_SIZE);
|
||||
coopth_init();
|
||||
coopth_set_ctx_checker_vm86(c_chk);
|
||||
ld_tid = coopth_create("leavedos", leavedos_thr);
|
||||
coopth_set_ctx_handlers(ld_tid, sig_ctx_prepare, sig_ctx_restore, NULL);
|
||||
|
||||
vm86_init();
|
||||
cputime_late_init();
|
||||
HMA_init(); /* HMA can only be done now after mapping
|
||||
is initialized*/
|
||||
memory_init(); /* initialize the memory contents */
|
||||
ioselect_init();
|
||||
/* iodev_init() can load plugins, like SDL, that can spawn a thread.
|
||||
* This must be done before initializing signals, or problems ensue.
|
||||
* This also must be done when the signals are blocked, so after
|
||||
* the signal_pre_init(), which right now blocks the signals. */
|
||||
iodev_init(); /* initialize devices */
|
||||
init_all_DOS_tables(); /* longest init function! needs to be optimized */
|
||||
signal_init(); /* initialize sig's & sig handlers */
|
||||
if (config.exitearly) {
|
||||
dbug_printf("Leaving DOS before booting\n");
|
||||
leavedos(0);
|
||||
}
|
||||
g_printf("EMULATE\n");
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
#ifdef USE_MHPDBG
|
||||
mhp_debug(DBG_INIT, 0, 0);
|
||||
#endif
|
||||
timer_interrupt_init(); /* start sending int 8h int signals */
|
||||
|
||||
/* map KVM memory */
|
||||
if (config.cpu_vm == CPUVM_KVM || config.cpu_vm_dpmi == CPUVM_KVM)
|
||||
set_kvm_memory_regions();
|
||||
|
||||
cpu_reset();
|
||||
if (config.cpu_vm == CPUVM_KVM)
|
||||
kvm_enter(0);
|
||||
can_leavedos = 1;
|
||||
|
||||
while (!fatalerr && !config.exitearly) {
|
||||
loopstep_run_vm86();
|
||||
}
|
||||
|
||||
if (fatalerr) {
|
||||
sync();
|
||||
fprintf(stderr, "Not a good day to die!!!!!\n");
|
||||
}
|
||||
leavedos(99);
|
||||
return 0; /* just to make gcc happy */
|
||||
}
|
||||
|
||||
void
|
||||
dos_ctrl_alt_del(void)
|
||||
{
|
||||
SETIVEC(0x19, BIOSSEG, INT_OFF(0x19));
|
||||
dbug_printf("DOS ctrl-alt-del requested. Rebooting!\n");
|
||||
if(in_dpmi_pm())
|
||||
fake_pm_int();
|
||||
real_run_int(0x19);
|
||||
}
|
||||
|
||||
int register_exit_handler(void (*handler)(void))
|
||||
{
|
||||
assert(exit_hndl_num < MAX_EXIT_HANDLERS);
|
||||
exit_hndl[exit_hndl_num].handler = handler;
|
||||
exit_hndl_num++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void leavedos_thr(void *arg)
|
||||
{
|
||||
dbug_printf("leavedos thread started\n");
|
||||
/* this may require working vm86() */
|
||||
video_early_close();
|
||||
dbug_printf("leavedos thread ended\n");
|
||||
}
|
||||
|
||||
/* "graceful" shutdown */
|
||||
void __leavedos(int code, int sig, const char *s, int num)
|
||||
{
|
||||
int tmp;
|
||||
dbug_printf("leavedos(%s:%i|%i) called - shutting down\n", s, num, sig);
|
||||
if (in_leavedos)
|
||||
{
|
||||
error("leavedos called recursively, forgetting the graceful exit!\n");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if (!can_leavedos) {
|
||||
config.exitearly = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
in_leavedos++;
|
||||
if (fault_cnt > 0) {
|
||||
dosemu_error("leavedos() called from within a signal context!\n");
|
||||
leavedos_main(sig);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_MHPDBG
|
||||
/* try to notify dosdebug */
|
||||
mhp_exit_intercept(sig);
|
||||
#endif
|
||||
|
||||
/* try to regain control of keyboard and video first */
|
||||
keyb_close();
|
||||
/* abandon current thread if any */
|
||||
coopth_abandon();
|
||||
/* switch to RM before closing coopthreads-related stuff */
|
||||
dpmi_done0();
|
||||
if (!config.exitearly) { // in exitearly case nothing to join
|
||||
/* try to clean up threads */
|
||||
tmp = coopth_flush_vm86();
|
||||
if (tmp)
|
||||
dbug_printf("%i threads still active\n", tmp);
|
||||
coopth_start(ld_tid, NULL);
|
||||
/* vc switch may require vm86() so call it while waiting for thread */
|
||||
coopth_join_vm86(ld_tid);
|
||||
}
|
||||
__leavedos_main(code, sig);
|
||||
}
|
||||
|
||||
static void __leavedos_main(int code, int sig)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* async signals must be disabled first or pthread_cancel() hangs on arm */
|
||||
signal_done();
|
||||
dpmi_done();
|
||||
/* now safe to stop io thread */
|
||||
ioselect_done();
|
||||
/* then stop device threads, which also stops any remaining vm86() uses */
|
||||
iodev_term();
|
||||
#ifdef USE_MHPDBG
|
||||
g_printf("closing debugger pipes\n");
|
||||
/* after vm86() is no longer used, we can do this */
|
||||
mhp_close();
|
||||
#endif
|
||||
/* now it is safe to shut down coopth. Can be done any later, if need be */
|
||||
coopth_done();
|
||||
dbug_printf("coopthreads stopped\n");
|
||||
|
||||
video_close();
|
||||
if (config.cpu_vm == CPUVM_KVM || config.cpu_vm_dpmi == CPUVM_KVM)
|
||||
kvm_done();
|
||||
if (config.speaker == SPKR_EMULATED) {
|
||||
g_printf("SPEAKER: sound off\n");
|
||||
speaker_off(); /* turn off any sound */
|
||||
}
|
||||
else if (config.speaker==SPKR_NATIVE) {
|
||||
g_printf("SPEAKER: sound off\n");
|
||||
/* Since the speaker is native hardware use port manipulation,
|
||||
* we don't know what is actually implementing the kernel's
|
||||
* ioctls.
|
||||
* My port logic is actually stolen from kd_nosound in the kernel.
|
||||
* --EB 21 September 1997
|
||||
*/
|
||||
port_outb(0x61, port_inb(0x61)&0xFC); /* turn off any sound */
|
||||
}
|
||||
|
||||
free(vm86_hlt_state);
|
||||
|
||||
SIG_close();
|
||||
|
||||
#if defined(X86_EMULATOR)
|
||||
/* if we are here with config.cpuemu>1 something went wrong... */
|
||||
if (IS_EMU()) {
|
||||
leave_cpu_emu();
|
||||
}
|
||||
#endif
|
||||
show_ints(0, 0x33);
|
||||
g_printf("calling disk_close_all\n");
|
||||
disk_close_all();
|
||||
|
||||
if (config.emuretrace) {
|
||||
do_r3da_pending ();
|
||||
set_ioperm (0x3da, 1, 1);
|
||||
set_ioperm (0x3c0, 1, 1);
|
||||
config.emuretrace = 0;
|
||||
}
|
||||
|
||||
/* terminate port server */
|
||||
port_exit();
|
||||
|
||||
g_printf("releasing ports and blocked devices\n");
|
||||
release_ports();
|
||||
|
||||
g_printf("calling shared memory exit\n");
|
||||
g_printf("calling HMA exit\n");
|
||||
hma_exit();
|
||||
g_printf("calling mapping_close()\n");
|
||||
mapping_close();
|
||||
|
||||
g_printf("calling close_all_printers\n");
|
||||
close_all_printers();
|
||||
|
||||
for (i = 0; i < exit_hndl_num; i++)
|
||||
exit_hndl[i].handler();
|
||||
|
||||
flush_log();
|
||||
|
||||
if (sig < 0)
|
||||
code = -sig;
|
||||
else if (sig > 0)
|
||||
code = sig + 128;
|
||||
else
|
||||
code &= 0x7f;
|
||||
/* We don't need to use _exit() here; this is the graceful exit path. */
|
||||
exit(code);
|
||||
}
|
||||
|
||||
void __leavedos_main_wrp(int code, int sig, const char *s, int num)
|
||||
{
|
||||
dbug_printf("leavedos_main(%s:%i|%i) called - shutting down\n", s, num, sig);
|
||||
__leavedos_main(code, sig);
|
||||
}
|
||||
|
||||
void leavedos_from_thread(int code)
|
||||
{
|
||||
pthread_mutex_lock(&ld_mtx);
|
||||
leavedos_code = code;
|
||||
leavedos_called++;
|
||||
pthread_mutex_unlock(&ld_mtx);
|
||||
}
|
||||
|
||||
void check_leavedos(void)
|
||||
{
|
||||
int ld_code, ld_called;
|
||||
pthread_mutex_lock(&ld_mtx);
|
||||
ld_code = leavedos_code;
|
||||
ld_called = leavedos_called;
|
||||
leavedos_called = 0;
|
||||
pthread_mutex_unlock(&ld_mtx);
|
||||
if (ld_called)
|
||||
leavedos(ld_code);
|
||||
}
|
||||
|
||||
void hardware_run(void)
|
||||
{
|
||||
run_sb(); /* Beat Karcher to this one .. 8-) - AM */
|
||||
keyb_server_run();
|
||||
rtc_run();
|
||||
}
|
||||
|
||||
180
src/base/core/hlt.c
Normal file
180
src/base/core/hlt.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "emu.h"
|
||||
#include "emudpmi.h"
|
||||
#include "int.h"
|
||||
#include "utilities.h"
|
||||
#include "hlt.h"
|
||||
|
||||
#define CONFIG_HLT_TRACE 1
|
||||
|
||||
/*
|
||||
* maximum number of halt handlers.
|
||||
* you can increase this to anything below 256 since an 8-bit handle
|
||||
* is used for each device
|
||||
*/
|
||||
#define MAX_HLT_HANDLERS 50
|
||||
|
||||
struct hlt_handler {
|
||||
emu_hlt_t h;
|
||||
Bit16u start_addr;
|
||||
};
|
||||
|
||||
#define MAX_HLT_BLK_SIZE 4096
|
||||
struct hlt_struct {
|
||||
struct hlt_handler hlt_handler[MAX_HLT_HANDLERS];
|
||||
int hlt_handler_id[MAX_HLT_BLK_SIZE];
|
||||
int hlt_handler_count;
|
||||
int hlt_block_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the default HLT handler for the HLT block -- assume that
|
||||
* someone did a CALLF to get to us.
|
||||
*/
|
||||
static void hlt_default(Bit16u addr, HLT_ARG(arg))
|
||||
{
|
||||
if (in_dpmi_pm()) {
|
||||
dosemu_error("HLT: DPMI hlt_default(0x%04x) called, exiting\n", addr);
|
||||
leavedos(2);
|
||||
} else {
|
||||
/* 32rtm doesn't shut down mouse driver properly, so it may
|
||||
* execute the no longer valid realmode callback.
|
||||
* See https://github.com/dosemu2/dosemu2/issues/1563 */
|
||||
error_once("HLT: vm86 hlt_default(0x%04x) called, trying retf\n", addr);
|
||||
warn("HLT: vm86 hlt_default(0x%04x) called, trying retf\n", addr);
|
||||
fake_retf();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* DANG_BEGIN_FUNCTION hlt_init(void)
|
||||
*
|
||||
* description:
|
||||
* Resets all the HLT handlers
|
||||
*
|
||||
* DANG_END_FUNCTION
|
||||
*/
|
||||
void *hlt_init(int size)
|
||||
{
|
||||
struct hlt_struct *state;
|
||||
int i;
|
||||
|
||||
state = malloc(sizeof(*state));
|
||||
state->hlt_handler[0].h.func = hlt_default;
|
||||
state->hlt_handler[0].h.name = "Unmapped HLT instruction";
|
||||
|
||||
state->hlt_handler_count = 1;
|
||||
assert(size <= MAX_HLT_BLK_SIZE);
|
||||
for (i = 0; i < size; i++)
|
||||
state->hlt_handler_id[i] = 0; /* unmapped HLT handler */
|
||||
state->hlt_block_size = size;
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* DANG_BEGIN_FUNCTION hlt_handle()
|
||||
*
|
||||
* description:
|
||||
* Handles a HLT instruction reached inside the dos emulator.
|
||||
*
|
||||
* DANG_END_FUNCTION
|
||||
*/
|
||||
int hlt_handle(void *arg, Bit16u offs, void *arg2)
|
||||
{
|
||||
struct hlt_struct *state = arg;
|
||||
struct hlt_handler *hlt = &state->hlt_handler[state->hlt_handler_id[offs]];
|
||||
#if CONFIG_HLT_TRACE > 0
|
||||
h_printf("HLT: fcn 0x%04x called in HLT block, handler: %s +%#x\n", offs,
|
||||
hlt->h.name, offs - hlt->start_addr);
|
||||
#endif
|
||||
hlt->h.func(offs - hlt->start_addr, arg2, hlt->h.arg);
|
||||
return hlt->h.ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a HLT handler.
|
||||
*/
|
||||
Bit16u hlt_register_handler(void *arg, emu_hlt_t handler)
|
||||
{
|
||||
struct hlt_struct *state = arg;
|
||||
int handle, i, j;
|
||||
Bit16u start_addr = -1;
|
||||
|
||||
/* initialization check */
|
||||
assert(state->hlt_handler_count);
|
||||
|
||||
if (state->hlt_handler_count >= MAX_HLT_HANDLERS) {
|
||||
error("HLT: too many HLT handlers, increase MAX_HLT_HANDLERS\n");
|
||||
config.exitearly = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i + handler.len <= state->hlt_block_size; i++) {
|
||||
for (j = 0; j < handler.len; j++) {
|
||||
if (state->hlt_handler_id[i + j]) {
|
||||
i += j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* see if found free block */
|
||||
if (j == handler.len) {
|
||||
start_addr = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start_addr == (Bit16u)-1) {
|
||||
error("HLT: Cannot find free block of len %i\n", handler.len);
|
||||
config.exitearly = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle = state->hlt_handler_count++;
|
||||
|
||||
state->hlt_handler[handle].h = handler;
|
||||
state->hlt_handler[handle].start_addr = start_addr;
|
||||
|
||||
/* change table to reflect new handler id for that address */
|
||||
for (j = 0; j < handler.len; j++)
|
||||
state->hlt_handler_id[start_addr + j] = handle;
|
||||
|
||||
h_printf("HLT: registered %s at %#x,%i\n",
|
||||
handler.name, start_addr, handler.len);
|
||||
|
||||
return start_addr;
|
||||
}
|
||||
|
||||
int hlt_unregister_handler(void *arg, Bit16u start_addr)
|
||||
{
|
||||
struct hlt_struct *state = arg;
|
||||
int handle, i;
|
||||
emu_hlt_t *h;
|
||||
|
||||
assert(start_addr < state->hlt_block_size);
|
||||
handle = state->hlt_handler_id[start_addr];
|
||||
if (!handle)
|
||||
return -1;
|
||||
h = &state->hlt_handler[handle].h;
|
||||
for (i = 0; i < h->len; i++)
|
||||
state->hlt_handler_id[start_addr + i] = 0;
|
||||
h->func = hlt_default;
|
||||
while (state->hlt_handler_count &&
|
||||
state->hlt_handler[state->hlt_handler_count - 1].h.func == hlt_default)
|
||||
state->hlt_handler_count--;
|
||||
return 0;
|
||||
}
|
||||
3916
src/base/core/int.c
Normal file
3916
src/base/core/int.c
Normal file
File diff suppressed because it is too large
Load Diff
178
src/base/core/lowmem.c
Normal file
178
src/base/core/lowmem.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Author: Stas Sergeev <stsp@users.sourceforge.net>
|
||||
*
|
||||
* Management for the static 32K heap in a low memory.
|
||||
* Used by various dosemu internal subsystems.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
#include "emu.h"
|
||||
#include "memory.h"
|
||||
#include "smalloc.h"
|
||||
#include "utilities.h"
|
||||
#include "emudpmi.h"
|
||||
#include "lowmem.h"
|
||||
|
||||
static smpool mp;
|
||||
unsigned char *dosemu_lmheap_base;
|
||||
static void *rm_stack;
|
||||
#define RM_STACK_SIZE 0x200
|
||||
|
||||
static void do_sm_error(int prio, const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list al;
|
||||
|
||||
va_start(al, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, al);
|
||||
va_end(al);
|
||||
if (prio)
|
||||
dosemu_error("%s\n", buf);
|
||||
else
|
||||
dbug_printf("%s\n", buf);
|
||||
}
|
||||
|
||||
int lowmem_init(void)
|
||||
{
|
||||
dosemu_lmheap_base = MK_FP32(DOSEMU_LMHEAP_SEG, DOSEMU_LMHEAP_OFF);
|
||||
sminit(&mp, dosemu_lmheap_base, DOSEMU_LMHEAP_SIZE);
|
||||
smregister_error_notifier(&mp, do_sm_error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void * lowmem_alloc(int size)
|
||||
{
|
||||
char *ptr = smalloc(&mp, size);
|
||||
if (!ptr) {
|
||||
error("lowmem_heap: OOM, size=%i\n", size);
|
||||
leavedos(86);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void * lowmem_alloc_aligned(int align, int size)
|
||||
{
|
||||
char *ptr = smalloc_aligned(&mp, align, size);
|
||||
if (!ptr) {
|
||||
error("lowmem_heap: OOM, size=%i\n", size);
|
||||
leavedos(86);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void lowmem_free(void *p)
|
||||
{
|
||||
smfree(&mp, p);
|
||||
}
|
||||
|
||||
void lowmem_reset(void)
|
||||
{
|
||||
lowmem_free(rm_stack);
|
||||
smfree_all(&mp);
|
||||
rm_stack = lowmem_alloc(RM_STACK_SIZE);
|
||||
}
|
||||
|
||||
static int in_rm_stack;
|
||||
static uint16_t rm_sp;
|
||||
#define MAX_RM_STACKS 10
|
||||
static uint64_t userval[MAX_RM_STACKS];
|
||||
|
||||
int get_rm_stack(Bit16u *ss_p, Bit16u *sp_p, uint64_t cookie)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
assert(in_rm_stack < MAX_RM_STACKS);
|
||||
userval[in_rm_stack] = cookie;
|
||||
if (!(in_rm_stack++)) {
|
||||
rm_sp = DOSEMU_LMHEAP_OFFS_OF(rm_stack) + RM_STACK_SIZE;
|
||||
*ss_p = DOSEMU_LMHEAP_SEG;
|
||||
*sp_p = rm_sp;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t put_rm_stack(uint64_t *cookie)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
assert(in_rm_stack > 0);
|
||||
if (!(--in_rm_stack)) {
|
||||
ret = rm_sp;
|
||||
}
|
||||
if (cookie)
|
||||
*cookie = userval[in_rm_stack];
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* recursion is _very_unlikely, but define an array */
|
||||
#define MAX_SAVED_REGS 5
|
||||
static struct vm86_regs rm_regs_stack[MAX_SAVED_REGS];
|
||||
|
||||
static void switch_stack(struct vm86_regs *regs)
|
||||
{
|
||||
Bit16u new_ss, new_sp;
|
||||
int stk;
|
||||
stk = get_rm_stack(&new_ss, &new_sp, 0);
|
||||
if (stk) {
|
||||
regs->ss = new_ss;
|
||||
regs->esp = new_sp;
|
||||
}
|
||||
}
|
||||
|
||||
void get_rm_stack_regs(struct vm86_regs *regs, struct vm86_regs *saved_regs)
|
||||
{
|
||||
*saved_regs = REGS;
|
||||
switch_stack(regs);
|
||||
}
|
||||
|
||||
void rm_stack_enter(void)
|
||||
{
|
||||
assert(in_rm_stack < MAX_SAVED_REGS);
|
||||
get_rm_stack_regs(®S, &rm_regs_stack[in_rm_stack]);
|
||||
}
|
||||
|
||||
void rm_stack_leave(void)
|
||||
{
|
||||
int old_tf = isset_TF();
|
||||
put_rm_stack(NULL);
|
||||
REGS = rm_regs_stack[in_rm_stack];
|
||||
if (old_tf)
|
||||
set_TF();
|
||||
}
|
||||
|
||||
#define LMHEAP_OFF 0xa000
|
||||
#define LMHEAP_SIZE 0x4000
|
||||
|
||||
static uint16_t lmheap_add(void)
|
||||
{
|
||||
return (config.dos_up == 2 ? FDPP_LMHEAP_ADD : 0);
|
||||
}
|
||||
|
||||
uint16_t lmheap_off(void)
|
||||
{
|
||||
return LMHEAP_OFF + lmheap_add();
|
||||
}
|
||||
|
||||
uint16_t lmheap_size(void)
|
||||
{
|
||||
return LMHEAP_SIZE - lmheap_add();
|
||||
}
|
||||
1263
src/base/core/ports.c
Normal file
1263
src/base/core/ports.c
Normal file
File diff suppressed because it is too large
Load Diff
257
src/base/core/priv.c
Normal file
257
src/base/core/priv.c
Normal file
@@ -0,0 +1,257 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#ifdef HAVE_SYS_IO_H
|
||||
#include <sys/io.h>
|
||||
#endif
|
||||
#include "emu.h"
|
||||
#include "priv.h"
|
||||
#include "dosemu_config.h"
|
||||
#include "mapping.h"
|
||||
#include "utilities.h"
|
||||
#ifdef X86_EMULATOR
|
||||
#include "cpu-emu.h"
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define PRIV_TESTING
|
||||
#endif
|
||||
|
||||
/* Some handy information to have around */
|
||||
static uid_t uid,euid;
|
||||
static gid_t gid,egid;
|
||||
static uid_t cur_uid, cur_euid;
|
||||
static gid_t cur_gid, cur_egid;
|
||||
|
||||
static int skip_priv_setting = 0;
|
||||
|
||||
int can_do_root_stuff;
|
||||
int under_root_login;
|
||||
int using_sudo;
|
||||
int current_iopl;
|
||||
|
||||
#define PRIVS_ARE_ON (euid == cur_euid)
|
||||
#define PRIVS_ARE_OFF (uid == cur_euid)
|
||||
#define PRIVS_WERE_ON(privs) (pop_priv(privs))
|
||||
|
||||
|
||||
static void push_priv(saved_priv_status *privs)
|
||||
{
|
||||
if (!privs || *privs != PRIV_MAGIC) {
|
||||
error("Aiiiee... not in-sync saved priv status on push_priv\n");
|
||||
leavedos(99);
|
||||
}
|
||||
*privs = PRIVS_ARE_ON;
|
||||
#ifdef PRIV_TESTING
|
||||
c_printf("PRIV: pushing %d privs_ptr=%p\n", *privs, privs);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int pop_priv(saved_priv_status *privs)
|
||||
{
|
||||
int ret;
|
||||
if (!privs || *privs == PRIV_MAGIC) {
|
||||
error("Aiiiee... not in-sync saved priv status on pop_priv\n");
|
||||
leavedos(99);
|
||||
}
|
||||
#ifdef PRIV_TESTING
|
||||
c_printf("PRIV: popping %d privs_ptr=%p\n", *privs, privs);
|
||||
#endif
|
||||
ret = (int)*privs;
|
||||
*privs = PRIV_MAGIC;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _priv_on(void)
|
||||
{
|
||||
if (PRIVS_ARE_OFF) { /* make sure the privs need to be changed */
|
||||
#ifdef PRIV_TESTING
|
||||
c_printf("PRIV: on-in %d\n", cur_euid);
|
||||
#endif
|
||||
if (setreuid(uid,euid)) {
|
||||
error("Cannot turn privs on!\n");
|
||||
return 0;
|
||||
}
|
||||
cur_uid = uid;
|
||||
cur_euid = euid;
|
||||
if (setregid(gid,egid)) {
|
||||
error("Cannot turn privs on!\n");
|
||||
return 0;
|
||||
}
|
||||
cur_gid = gid;
|
||||
cur_egid = egid;
|
||||
}
|
||||
#ifdef PRIV_TESTING
|
||||
c_printf("PRIV: on-ex %d\n", cur_euid);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _priv_off(void)
|
||||
{
|
||||
if (PRIVS_ARE_ON) { /* make sure the privs need to be changed */
|
||||
#ifdef PRIV_TESTING
|
||||
c_printf("PRIV: off-in %d\n", cur_euid);
|
||||
#endif
|
||||
if (setreuid(euid,uid)) {
|
||||
error("Cannot turn privs off!\n");
|
||||
return 0;
|
||||
}
|
||||
cur_uid = euid;
|
||||
cur_euid = uid;
|
||||
if (setregid(egid,gid)) {
|
||||
error("Cannot turn privs off!\n");
|
||||
return 0;
|
||||
}
|
||||
cur_gid = egid;
|
||||
cur_egid = gid;
|
||||
}
|
||||
#ifdef PRIV_TESTING
|
||||
c_printf("PRIV: off-ex %d\n", cur_euid);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
int real_enter_priv_on(saved_priv_status *privs)
|
||||
{
|
||||
if (skip_priv_setting) return 1;
|
||||
push_priv(privs);
|
||||
return _priv_on();
|
||||
}
|
||||
|
||||
int real_enter_priv_off(saved_priv_status *privs)
|
||||
{
|
||||
if (skip_priv_setting) return 1;
|
||||
push_priv(privs);
|
||||
return _priv_off();
|
||||
}
|
||||
|
||||
int real_leave_priv_setting(saved_priv_status *privs)
|
||||
{
|
||||
if (skip_priv_setting) return 1;
|
||||
if (PRIVS_WERE_ON(privs)) return _priv_on();
|
||||
return _priv_off();
|
||||
}
|
||||
|
||||
int priv_iopl(int pl)
|
||||
{
|
||||
#ifdef HAVE_SYS_IO_H
|
||||
int ret;
|
||||
if (PRIVS_ARE_OFF) {
|
||||
_priv_on();
|
||||
ret = iopl(pl);
|
||||
_priv_off();
|
||||
}
|
||||
else ret = iopl(pl);
|
||||
#ifdef X86_EMULATOR
|
||||
if (config.cpu_vm == CPUVM_EMU) e_priv_iopl(pl);
|
||||
#endif
|
||||
if (ret == 0)
|
||||
current_iopl = pl;
|
||||
return ret;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
uid_t get_cur_uid(void)
|
||||
{
|
||||
return cur_uid;
|
||||
}
|
||||
|
||||
uid_t get_cur_euid(void)
|
||||
{
|
||||
return cur_euid;
|
||||
}
|
||||
|
||||
gid_t get_cur_egid(void)
|
||||
{
|
||||
return cur_egid;
|
||||
}
|
||||
|
||||
uid_t get_orig_uid(void)
|
||||
{
|
||||
return uid;
|
||||
}
|
||||
|
||||
uid_t get_orig_euid(void)
|
||||
{
|
||||
return euid;
|
||||
}
|
||||
|
||||
gid_t get_orig_gid(void)
|
||||
{
|
||||
return gid;
|
||||
}
|
||||
|
||||
int priv_drop(void)
|
||||
{
|
||||
if (setreuid(uid,uid) || setregid(gid,gid))
|
||||
{
|
||||
error("Cannot drop root uid or gid!\n");
|
||||
return 0;
|
||||
}
|
||||
cur_euid = euid = cur_uid = uid;
|
||||
cur_egid = egid = cur_gid = gid;
|
||||
skip_priv_setting = 1;
|
||||
if (uid) can_do_root_stuff = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void priv_init(void)
|
||||
{
|
||||
const char *sh = getenv("SUDO_HOME"); // theoretical future var
|
||||
const char *h = getenv("HOME");
|
||||
uid = cur_uid = getuid();
|
||||
/* suid bit only sets euid & suid but not uid, sudo sets all 3 */
|
||||
if (!uid) under_root_login = 1;
|
||||
euid = cur_euid = geteuid();
|
||||
if (!euid) can_do_root_stuff = 1;
|
||||
if (!uid && !euid) skip_priv_setting = 1;
|
||||
gid = cur_gid = getgid();
|
||||
egid = cur_egid = getegid();
|
||||
|
||||
/* must store the /proc/self/exe symlink contents before dropping
|
||||
privs! */
|
||||
dosemu_proc_self_exe = readlink_malloc("/proc/self/exe");
|
||||
/* For Fedora we must also save a file descriptor to /proc/self/maps */
|
||||
dosemu_proc_self_maps_fd = open("/proc/self/maps", O_RDONLY | O_CLOEXEC);
|
||||
if (!sh)
|
||||
sh = getenv("DOSEMU_SUDO_HOME");
|
||||
/* see if -E was used */
|
||||
if (under_root_login && sh && h && strcmp(sh, h) == 0)
|
||||
{
|
||||
/* check for sudo and set to original user */
|
||||
char *s = getenv("SUDO_GID");
|
||||
if (s) {
|
||||
gid = cur_gid = atoi(s);
|
||||
if (gid) {
|
||||
setregid(gid, egid);
|
||||
}
|
||||
}
|
||||
s = getenv("SUDO_UID");
|
||||
if (s) {
|
||||
uid = cur_uid = atoi(s);
|
||||
if (uid) {
|
||||
skip_priv_setting = under_root_login = 0;
|
||||
using_sudo = 1;
|
||||
s = getenv("SUDO_USER");
|
||||
if (s) {
|
||||
initgroups(s, gid);
|
||||
setenv("USER", s, 1);
|
||||
}
|
||||
setreuid(uid, euid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!can_do_root_stuff)
|
||||
{
|
||||
skip_priv_setting = 1;
|
||||
}
|
||||
|
||||
if (!skip_priv_setting) _priv_off();
|
||||
}
|
||||
181
src/base/core/vint.c
Normal file
181
src/base/core/vint.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Purpose: virtual interrupt router (another one)
|
||||
*
|
||||
* Author: Stas Sergeev.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include "cpu.h"
|
||||
#include "int.h"
|
||||
#include "hlt.h"
|
||||
#include "memory.h"
|
||||
#include "port.h"
|
||||
#include "chipset.h"
|
||||
#include "emu.h"
|
||||
#include "vint.h"
|
||||
|
||||
#define VINT_MAX 2
|
||||
static int vi_used;
|
||||
static uint16_t vint_hlt;
|
||||
|
||||
#define ON_PIC1(n) (vih[n].orig_irq >= 8)
|
||||
|
||||
struct vihandler {
|
||||
void (*handler)(int, int);
|
||||
void (*mask)(int, int);
|
||||
uint8_t irq;
|
||||
uint8_t orig_irq;
|
||||
uint8_t interrupt;
|
||||
int tweaked;
|
||||
unsigned tw_flags;
|
||||
};
|
||||
struct vihandler vih[VINT_MAX];
|
||||
|
||||
static void poll_pic0(uint8_t irq)
|
||||
{
|
||||
port_outb(0x20, 0x0c); // OCW3, enter poll mode
|
||||
port_outb(0x20, irq); // extension, may not work on real PIC
|
||||
/* see if it worked */
|
||||
assert(pic_get_isr() & (1 << irq));
|
||||
}
|
||||
|
||||
static void poll_pic1(uint8_t irq)
|
||||
{
|
||||
port_outb(0x20, 0x0c); // OCW3, enter poll mode
|
||||
port_outb(0x20, 2); // extension, may not work on real PIC
|
||||
port_outb(0xa0, 0x0c);
|
||||
port_outb(0xa0, irq - 8);
|
||||
/* see if it worked */
|
||||
assert((pic_get_isr() & ((1 << irq) | 4)) == ((1 << irq) | 4));
|
||||
}
|
||||
|
||||
static void full_eoi(void)
|
||||
{
|
||||
port_outb(0xa0, 0x20);
|
||||
port_outb(0x20, 0x20);
|
||||
}
|
||||
|
||||
static void do_ret(int vi_num)
|
||||
{
|
||||
clear_IF();
|
||||
vih[vi_num].mask(vi_num, 0);
|
||||
do_iret();
|
||||
}
|
||||
|
||||
int vint_is_masked(int vi_num, uint8_t *imr)
|
||||
{
|
||||
uint16_t real_imr = (imr[1] << 8) | imr[0];
|
||||
return !!(real_imr & (1 << vih[vi_num].orig_irq));
|
||||
}
|
||||
|
||||
static void vint_handler(uint16_t idx, HLT_ARG(arg))
|
||||
{
|
||||
uint8_t imr[2];
|
||||
int masked;
|
||||
int vi_num = idx >> 1;
|
||||
|
||||
if (idx & 1) {
|
||||
do_ret(vi_num);
|
||||
return;
|
||||
}
|
||||
|
||||
imr[0] = port_inb(0x21);
|
||||
imr[1] = port_inb(0xa1);
|
||||
masked = vint_is_masked(vi_num, imr);
|
||||
if (masked) {
|
||||
h_printf("vint: masked, iret\n");
|
||||
do_eoi2_iret();
|
||||
} else {
|
||||
uint8_t irq = vih[vi_num].orig_irq;
|
||||
uint16_t port = (irq >= 8 ? PIC1_VECBASE_PORT : PIC0_VECBASE_PORT);
|
||||
uint8_t inum = port_inb(port) + (irq & 7);
|
||||
full_eoi();
|
||||
if (ON_PIC1(vi_num))
|
||||
poll_pic1(irq);
|
||||
else
|
||||
poll_pic0(irq);
|
||||
if (vih[vi_num].tweaked) {
|
||||
_IP++; // skip hlt
|
||||
h_printf("vint: call to inum %x\n", inum);
|
||||
real_run_int(inum);
|
||||
vih[vi_num].mask(vi_num, 1);
|
||||
} else {
|
||||
h_printf("vint: jump to inum %x\n", inum);
|
||||
jmp_to(ISEG(inum), IOFF(inum));
|
||||
}
|
||||
}
|
||||
|
||||
if (vih[vi_num].handler)
|
||||
vih[vi_num].handler(vi_num, masked);
|
||||
}
|
||||
|
||||
void vint_post_irq_dpmi(int vi_num, int masked)
|
||||
{
|
||||
full_eoi();
|
||||
if (!masked) {
|
||||
uint8_t irq = vih[vi_num].orig_irq;
|
||||
if (ON_PIC1(vi_num))
|
||||
poll_pic1(irq);
|
||||
else
|
||||
poll_pic0(irq);
|
||||
}
|
||||
}
|
||||
|
||||
void vint_init(void)
|
||||
{
|
||||
emu_hlt_t hlt_hdlr = HLT_INITIALIZER;
|
||||
|
||||
hlt_hdlr.name = "vint";
|
||||
hlt_hdlr.func = vint_handler;
|
||||
hlt_hdlr.len = VINT_MAX * 2;
|
||||
vint_hlt = hlt_register_handler_vm86(hlt_hdlr);
|
||||
}
|
||||
|
||||
void vint_setup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < VINT_MAX; i++) {
|
||||
if (vih[i].interrupt)
|
||||
SETIVEC(vih[i].interrupt, BIOS_HLT_BLK_SEG, vint_hlt + 2 * i);
|
||||
}
|
||||
}
|
||||
|
||||
int vint_register(void (*ack_handler)(int, int),
|
||||
void (*mask_handler)(int, int),
|
||||
int irq, int orig_irq, int inum)
|
||||
{
|
||||
struct vihandler *vi = &vih[vi_used];
|
||||
assert(vi_used < VINT_MAX);
|
||||
vi->handler = ack_handler;
|
||||
vi->mask = mask_handler;
|
||||
vi->irq = irq;
|
||||
vi->orig_irq = orig_irq;
|
||||
vi->interrupt = inum;
|
||||
return vi_used++;
|
||||
}
|
||||
|
||||
void vint_set_tweaked(int vi_num, int on, unsigned flags)
|
||||
{
|
||||
struct vihandler *vi = &vih[vi_num];
|
||||
assert(vi_num < VINT_MAX);
|
||||
vi->tweaked = on;
|
||||
vi->tw_flags = flags;
|
||||
}
|
||||
Reference in New Issue
Block a user