This commit is contained in:
@@ -29,7 +29,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef HAVE_SYS_IO_H
|
||||
#ifdef __linux__
|
||||
#include <sys/io.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
@@ -61,6 +61,8 @@ static pid_t portserver_pid = 0;
|
||||
|
||||
static unsigned char port_handles; /* number of io_handler's */
|
||||
|
||||
static const char *irq_handler_name[EMU_MAX_IRQS];
|
||||
|
||||
int in_crit_section = 0;
|
||||
static const char *crit_sect_caller;
|
||||
|
||||
@@ -189,7 +191,7 @@ static void log_port_write_d(ioport_t port, Bit32u w)
|
||||
Bit8u port_inb(ioport_t port)
|
||||
{
|
||||
Bit8u res;
|
||||
res = EMU_HANDLER(port).read_portb(port, EMU_HANDLER(port).arg);
|
||||
res = EMU_HANDLER(port).read_portb(port);
|
||||
return LOG_PORT_READ(port, res);
|
||||
}
|
||||
|
||||
@@ -203,7 +205,7 @@ Bit8u port_inb(ioport_t port)
|
||||
void port_outb(ioport_t port, Bit8u byte)
|
||||
{
|
||||
LOG_PORT_WRITE(port, byte);
|
||||
EMU_HANDLER(port).write_portb(port, byte, EMU_HANDLER(port).arg);
|
||||
EMU_HANDLER(port).write_portb(port,byte);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -219,10 +221,8 @@ Bit16u port_inw(ioport_t port)
|
||||
{
|
||||
Bit16u res;
|
||||
|
||||
if (EMU_HANDLER(port).read_portw != NULL &&
|
||||
EMU_HANDLER(port).read_portb == EMU_HANDLER(port + 1).read_portb
|
||||
) {
|
||||
res = EMU_HANDLER(port).read_portw(port, EMU_HANDLER(port).arg);
|
||||
if (EMU_HANDLER(port).read_portw != NULL) {
|
||||
res = EMU_HANDLER(port).read_portw(port);
|
||||
return LOG_PORT_READ_W(port, res);
|
||||
}
|
||||
else {
|
||||
@@ -240,11 +240,9 @@ Bit16u port_inw(ioport_t port)
|
||||
*/
|
||||
void port_outw(ioport_t port, Bit16u word)
|
||||
{
|
||||
if (EMU_HANDLER(port).write_portw != NULL &&
|
||||
EMU_HANDLER(port).write_portb == EMU_HANDLER(port + 1).write_portb
|
||||
) {
|
||||
if (EMU_HANDLER(port).write_portw != NULL) {
|
||||
LOG_PORT_WRITE_W(port, word);
|
||||
EMU_HANDLER(port).write_portw(port, word, EMU_HANDLER(port).arg);
|
||||
EMU_HANDLER(port).write_portw(port, word);
|
||||
}
|
||||
else {
|
||||
port_outb(port, word & 0xff);
|
||||
@@ -264,12 +262,8 @@ Bit32u port_ind(ioport_t port)
|
||||
{
|
||||
Bit32u res;
|
||||
|
||||
if (EMU_HANDLER(port).read_portd != NULL &&
|
||||
EMU_HANDLER(port).read_portb == EMU_HANDLER(port + 1).read_portb &&
|
||||
EMU_HANDLER(port).read_portb == EMU_HANDLER(port + 2).read_portb &&
|
||||
EMU_HANDLER(port).read_portb == EMU_HANDLER(port + 3).read_portb
|
||||
) {
|
||||
res = EMU_HANDLER(port).read_portd(port, EMU_HANDLER(port).arg);
|
||||
if (EMU_HANDLER(port).read_portd != NULL) {
|
||||
res = EMU_HANDLER(port).read_portd(port);
|
||||
}
|
||||
else {
|
||||
res = (Bit32u) port_inw(port) | (((Bit32u) port_inw(port + 2)) << 16);
|
||||
@@ -280,12 +274,8 @@ Bit32u port_ind(ioport_t port)
|
||||
void port_outd(ioport_t port, Bit32u dword)
|
||||
{
|
||||
LOG_PORT_WRITE_D(port, dword);
|
||||
if (EMU_HANDLER(port).write_portd != NULL &&
|
||||
EMU_HANDLER(port).write_portb == EMU_HANDLER(port + 1).write_portb &&
|
||||
EMU_HANDLER(port).write_portb == EMU_HANDLER(port + 2).write_portb &&
|
||||
EMU_HANDLER(port).write_portb == EMU_HANDLER(port + 3).write_portb
|
||||
) {
|
||||
EMU_HANDLER(port).write_portd(port, dword, EMU_HANDLER(port).arg);
|
||||
if (EMU_HANDLER(port).write_portd != NULL) {
|
||||
EMU_HANDLER(port).write_portd(port, dword);
|
||||
}
|
||||
else {
|
||||
port_outw(port, dword & 0xffff);
|
||||
@@ -313,7 +303,7 @@ static void check_crit_section(ioport_t port, const char *function)
|
||||
}
|
||||
}
|
||||
|
||||
static Bit8u port_not_avail_inb(ioport_t port, void *arg)
|
||||
static Bit8u port_not_avail_inb(ioport_t port)
|
||||
{
|
||||
/* it is a fact of (hardware) life that unused locations return all
|
||||
(or almost all) the bits at 1; some software can try to detect a
|
||||
@@ -330,33 +320,33 @@ static Bit8u port_not_avail_inb(ioport_t port, void *arg)
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static void port_not_avail_outb(ioport_t port, Bit8u byte, void *arg)
|
||||
static void port_not_avail_outb(ioport_t port, Bit8u byte)
|
||||
{
|
||||
check_crit_section(port, "outb");
|
||||
if (debug_level('i')) pna_emsg(port,'b',"write");
|
||||
}
|
||||
|
||||
static Bit16u port_not_avail_inw(ioport_t port, void *arg)
|
||||
static Bit16u port_not_avail_inw(ioport_t port)
|
||||
{
|
||||
if (debug_level('i')) pna_emsg(port,'w',"read");
|
||||
// idle(0, 50, 0, "inw");
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
static void port_not_avail_outw(ioport_t port, Bit16u value, void *arg)
|
||||
static void port_not_avail_outw(ioport_t port, Bit16u value)
|
||||
{
|
||||
check_crit_section(port, "outw");
|
||||
if (debug_level('i')) pna_emsg(port,'w',"write");
|
||||
}
|
||||
|
||||
static Bit32u port_not_avail_ind(ioport_t port, void *arg)
|
||||
static Bit32u port_not_avail_ind(ioport_t port)
|
||||
{
|
||||
if (debug_level('i')) pna_emsg(port,'d',"read");
|
||||
// idle(0, 50, 0, "ind");
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
static void port_not_avail_outd(ioport_t port, Bit32u value, void *arg)
|
||||
static void port_not_avail_outd(ioport_t port, Bit32u value)
|
||||
{
|
||||
check_crit_section(port, "outd");
|
||||
if (debug_level('i')) pna_emsg(port,'d',"write");
|
||||
@@ -386,7 +376,7 @@ Bit8u std_port_inb(ioport_t port)
|
||||
}
|
||||
if (!portserver_pid) {
|
||||
error ("std_port_inb(0x%X): port server unavailable\n", port);
|
||||
return port_not_avail_inb (port, NULL);
|
||||
return port_not_avail_inb (port);
|
||||
}
|
||||
pr.port = port;
|
||||
pr.type = TYPE_INB;
|
||||
@@ -395,11 +385,6 @@ Bit8u std_port_inb(ioport_t port)
|
||||
return pr.word;
|
||||
}
|
||||
|
||||
static Bit8u std_port_inb_h(ioport_t port, void *arg)
|
||||
{
|
||||
return std_port_inb(port);
|
||||
}
|
||||
|
||||
void std_port_outb(ioport_t port, Bit8u byte)
|
||||
{
|
||||
struct portreq pr;
|
||||
@@ -411,7 +396,7 @@ void std_port_outb(ioport_t port, Bit8u byte)
|
||||
if (!portserver_pid) {
|
||||
error ("std_port_outb(0x%X,0x%X): port server unavailable\n",
|
||||
port, byte);
|
||||
port_not_avail_outb (port, byte, NULL);
|
||||
port_not_avail_outb (port, byte);
|
||||
return;
|
||||
}
|
||||
pr.word = byte;
|
||||
@@ -421,23 +406,16 @@ void std_port_outb(ioport_t port, Bit8u byte)
|
||||
read(port_fd_in[0], &pr, sizeof(pr));
|
||||
}
|
||||
|
||||
static void std_port_outb_h(ioport_t port, Bit8u byte, void *arg)
|
||||
{
|
||||
std_port_outb(port, byte);
|
||||
}
|
||||
|
||||
Bit16u std_port_inw(ioport_t port)
|
||||
{
|
||||
struct portreq pr;
|
||||
|
||||
if (current_iopl == 3 || (test_bit(port, emu_io_bitmap) +
|
||||
test_bit(port + 1, emu_io_bitmap)
|
||||
== 2)) {
|
||||
if (current_iopl == 3 || test_bit(port, emu_io_bitmap)) {
|
||||
return port_real_inw(port);
|
||||
}
|
||||
if (!portserver_pid) {
|
||||
error ("std_port_inw(0x%X): port server unavailable\n", port);
|
||||
return port_not_avail_inw (port, NULL);
|
||||
return port_not_avail_inw (port);
|
||||
}
|
||||
pr.port = port;
|
||||
pr.type = TYPE_INW;
|
||||
@@ -446,25 +424,18 @@ Bit16u std_port_inw(ioport_t port)
|
||||
return pr.word;
|
||||
}
|
||||
|
||||
static Bit16u std_port_inw_h(ioport_t port, void *arg)
|
||||
{
|
||||
return std_port_inw(port);
|
||||
}
|
||||
|
||||
void std_port_outw(ioport_t port, Bit16u word)
|
||||
{
|
||||
struct portreq pr;
|
||||
|
||||
if (current_iopl == 3 || (test_bit(port, emu_io_bitmap) +
|
||||
test_bit(port + 1, emu_io_bitmap)
|
||||
== 2)) {
|
||||
if (current_iopl == 3 || test_bit(port, emu_io_bitmap)) {
|
||||
port_real_outw(port, word);
|
||||
return;
|
||||
}
|
||||
if (!portserver_pid) {
|
||||
error ("std_port_outw(0x%X,0x%X): port server unavailable\n",
|
||||
port, word);
|
||||
port_not_avail_outw (port, word, NULL);
|
||||
port_not_avail_outw (port, word);
|
||||
return;
|
||||
}
|
||||
pr.word = word;
|
||||
@@ -474,25 +445,16 @@ void std_port_outw(ioport_t port, Bit16u word)
|
||||
read(port_fd_in[0], &pr, sizeof(pr));
|
||||
}
|
||||
|
||||
static void std_port_outw_h(ioport_t port, Bit16u word, void *arg)
|
||||
{
|
||||
std_port_outw(port, word);
|
||||
}
|
||||
|
||||
Bit32u std_port_ind(ioport_t port)
|
||||
{
|
||||
struct portreq pr;
|
||||
|
||||
if (current_iopl == 3 || (test_bit(port, emu_io_bitmap) +
|
||||
test_bit(port + 1, emu_io_bitmap) +
|
||||
test_bit(port + 2, emu_io_bitmap) +
|
||||
test_bit(port + 3, emu_io_bitmap)
|
||||
== 4)) {
|
||||
if (current_iopl == 3 || test_bit(port, emu_io_bitmap)) {
|
||||
return port_real_ind(port);
|
||||
}
|
||||
if (!portserver_pid) {
|
||||
error ("std_port_ind(0x%X): port server unavailable\n", port);
|
||||
return port_not_avail_ind (port, NULL);
|
||||
return port_not_avail_ind (port);
|
||||
}
|
||||
pr.port = port;
|
||||
pr.type = TYPE_IND;
|
||||
@@ -501,27 +463,18 @@ Bit32u std_port_ind(ioport_t port)
|
||||
return pr.word;
|
||||
}
|
||||
|
||||
static Bit32u std_port_ind_h(ioport_t port, void *arg)
|
||||
{
|
||||
return std_port_ind(port);
|
||||
}
|
||||
|
||||
static int do_port_outd(ioport_t port, Bit32u dword, int pci)
|
||||
{
|
||||
struct portreq pr;
|
||||
|
||||
if (current_iopl == 3 || (test_bit(port, emu_io_bitmap) +
|
||||
test_bit(port + 1, emu_io_bitmap) +
|
||||
test_bit(port + 2, emu_io_bitmap) +
|
||||
test_bit(port + 3, emu_io_bitmap)
|
||||
== 4)) {
|
||||
if (current_iopl == 3 || test_bit(port, emu_io_bitmap)) {
|
||||
port_real_outd(port, dword);
|
||||
return 0;
|
||||
}
|
||||
if (!portserver_pid) {
|
||||
error ("std_port_outd(0x%X,0x%X): port server unavailable\n",
|
||||
port, dword);
|
||||
port_not_avail_outd (port, dword, NULL);
|
||||
port_not_avail_outd (port, dword);
|
||||
return 0;
|
||||
}
|
||||
pr.word = dword;
|
||||
@@ -538,11 +491,6 @@ void std_port_outd(ioport_t port, Bit32u dword)
|
||||
read(port_fd_in[0], &pr, sizeof(pr));
|
||||
}
|
||||
|
||||
static void std_port_outd_h(ioport_t port, Bit32u dword, void *arg)
|
||||
{
|
||||
std_port_outd(port, dword);
|
||||
}
|
||||
|
||||
void pci_port_outd(ioport_t port, Bit32u dword)
|
||||
{
|
||||
do_port_outd(port, dword, 1);
|
||||
@@ -568,9 +516,17 @@ int port_rep_inb(ioport_t port, Bit8u *base, int df, Bit32u count)
|
||||
if (count==0) return 0;
|
||||
i_printf("Doing REP insb(%#x) %d bytes at %p, DF %d\n", port,
|
||||
count, base, df);
|
||||
while (count--) {
|
||||
*dest = port_inb(port);
|
||||
if (EMU_HANDLER(port).read_portb == std_port_inb) {
|
||||
while (count--) {
|
||||
*dest = std_port_inb(port);
|
||||
dest += incr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (count--) {
|
||||
*dest = EMU_HANDLER(port).read_portb(port);
|
||||
dest += incr;
|
||||
}
|
||||
}
|
||||
if (debug_level('T')) {
|
||||
dest = base;
|
||||
@@ -591,9 +547,17 @@ int port_rep_outb(ioport_t port, Bit8u *base, int df, Bit32u count)
|
||||
if (count==0) return 0;
|
||||
i_printf("Doing REP outsb(%#x) %d bytes at %p, DF %d\n", port,
|
||||
count, base, df);
|
||||
while (count--) {
|
||||
port_outb(port, *dest);
|
||||
if (EMU_HANDLER(port).write_portb == std_port_outb) {
|
||||
while (count--) {
|
||||
std_port_outb(port, *dest);
|
||||
dest += incr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (count--) {
|
||||
EMU_HANDLER(port).write_portb(port, *dest);
|
||||
dest += incr;
|
||||
}
|
||||
}
|
||||
if (debug_level('T')) {
|
||||
dest = base;
|
||||
@@ -614,17 +578,23 @@ int port_rep_inw(ioport_t port, Bit16u *base, int df, Bit32u count)
|
||||
if (count==0) return 0;
|
||||
i_printf("Doing REP insw(%#x) %d words at %p, DF %d\n", port,
|
||||
count, base, df);
|
||||
if (EMU_HANDLER(port).read_portw == NULL) {
|
||||
if (EMU_HANDLER(port).read_portw == std_port_inw) {
|
||||
while (count--) {
|
||||
*dest = std_port_inw(port);
|
||||
dest += incr;
|
||||
}
|
||||
}
|
||||
else if (EMU_HANDLER(port).read_portw == NULL) {
|
||||
Bit16u res;
|
||||
while (count--) {
|
||||
res = port_inb(port);
|
||||
*dest = ((Bit16u)port_inb(port+1) <<8) | res;
|
||||
res = EMU_HANDLER(port).read_portb(port);
|
||||
*dest = ((Bit16u)EMU_HANDLER(port).read_portb(port+1) <<8) | res;
|
||||
dest += incr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (count--) {
|
||||
*dest = port_inw(port);
|
||||
*dest = EMU_HANDLER(port).read_portw(port);
|
||||
dest += incr;
|
||||
}
|
||||
}
|
||||
@@ -647,17 +617,23 @@ int port_rep_outw(ioport_t port, Bit16u *base, int df, Bit32u count)
|
||||
if (count==0) return 0;
|
||||
i_printf("Doing REP outsw(%#x) %d words at %p, DF %d\n", port,
|
||||
count, base, df);
|
||||
if (EMU_HANDLER(port).write_portw == NULL) {
|
||||
if (EMU_HANDLER(port).write_portw == std_port_outw) {
|
||||
while (count--) {
|
||||
std_port_outw(port, *dest);
|
||||
dest += incr;
|
||||
}
|
||||
}
|
||||
else if (EMU_HANDLER(port).write_portw == NULL) {
|
||||
Bit16u res;
|
||||
while (count--) {
|
||||
res = *dest, dest += incr;
|
||||
port_outb(port, res);
|
||||
port_outb(port+1, res>>8);
|
||||
EMU_HANDLER(port).write_portb(port, res);
|
||||
EMU_HANDLER(port).write_portb(port+1, res>>8);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (count--) {
|
||||
port_outw(port, *dest);
|
||||
EMU_HANDLER(port).write_portw(port, *dest);
|
||||
dest += incr;
|
||||
}
|
||||
}
|
||||
@@ -721,7 +697,7 @@ void do_r3da_pending (void)
|
||||
}
|
||||
}
|
||||
|
||||
static Bit8u special_port_inb(ioport_t port, void *arg)
|
||||
static Bit8u special_port_inb(ioport_t port)
|
||||
{
|
||||
Bit8u res = 0xff;
|
||||
|
||||
@@ -740,7 +716,7 @@ static Bit8u special_port_inb(ioport_t port, void *arg)
|
||||
return res;
|
||||
}
|
||||
|
||||
static void special_port_outb(ioport_t port, Bit8u byte, void *arg)
|
||||
static void special_port_outb(ioport_t port, Bit8u byte)
|
||||
{
|
||||
if (current_iopl == 3 || test_bit(port, emu_io_bitmap)) {
|
||||
port_real_outb(port, byte);
|
||||
@@ -762,16 +738,16 @@ static void special_port_outb(ioport_t port, Bit8u byte, void *arg)
|
||||
* This way we avoid extra port accesses when the program
|
||||
* is only looking for the sync bits, and we don't miss
|
||||
* the case where the read to 0x3da is used to reset the
|
||||
* index/data flipflop for port 0x3c0. Further accesses to
|
||||
* index/data flipflop for port 0x3c0. Futher accesses to
|
||||
* port 0x3c0 are handled at full speed.
|
||||
*
|
||||
* SIDOC_END_REMARK
|
||||
*/
|
||||
if (config.vga && (config.emuretrace>1)) {
|
||||
if (r3da_pending) {
|
||||
(void)std_port_inb_h(r3da_pending, arg);
|
||||
(void)std_port_inb(r3da_pending);
|
||||
r3da_pending = 0;
|
||||
std_port_outb_h(0x3c0, byte, arg);
|
||||
std_port_outb(0x3c0, byte);
|
||||
return;
|
||||
}
|
||||
goto defout;
|
||||
@@ -788,7 +764,7 @@ static void special_port_outb(ioport_t port, Bit8u byte, void *arg)
|
||||
}
|
||||
|
||||
defout:
|
||||
std_port_outb_h (port, byte, arg);
|
||||
std_port_outb (port, byte);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
@@ -814,6 +790,8 @@ int port_init(void)
|
||||
port_handler[i].write_portw = NULL;
|
||||
port_handler[i].read_portd = NULL;
|
||||
port_handler[i].write_portd = NULL;
|
||||
port_handler[i].irq = EMU_NO_IRQ;
|
||||
port_handler[i].fd = -1;
|
||||
}
|
||||
|
||||
/* handle 0 maps to the unmapped IO device handler. Basically any
|
||||
@@ -831,28 +809,28 @@ int port_init(void)
|
||||
/* the STD handles will be in use by many devices, and their fd
|
||||
will always be -1
|
||||
*/
|
||||
port_handler[HANDLE_STD_IO].read_portb = std_port_inb_h;
|
||||
port_handler[HANDLE_STD_IO].write_portb = std_port_outb_h;
|
||||
port_handler[HANDLE_STD_IO].read_portw = std_port_inw_h;
|
||||
port_handler[HANDLE_STD_IO].write_portw = std_port_outw_h;
|
||||
port_handler[HANDLE_STD_IO].read_portd = std_port_ind_h;
|
||||
port_handler[HANDLE_STD_IO].write_portd = std_port_outd_h;
|
||||
port_handler[HANDLE_STD_IO].read_portb = std_port_inb;
|
||||
port_handler[HANDLE_STD_IO].write_portb = std_port_outb;
|
||||
port_handler[HANDLE_STD_IO].read_portw = std_port_inw;
|
||||
port_handler[HANDLE_STD_IO].write_portw = std_port_outw;
|
||||
port_handler[HANDLE_STD_IO].read_portd = std_port_ind;
|
||||
port_handler[HANDLE_STD_IO].write_portd = std_port_outd;
|
||||
port_handler[HANDLE_STD_IO].handler_name = "std port io";
|
||||
|
||||
port_handler[HANDLE_STD_RD].read_portb = std_port_inb_h;
|
||||
port_handler[HANDLE_STD_RD].read_portb = std_port_inb;
|
||||
port_handler[HANDLE_STD_RD].write_portb = port_not_avail_outb;
|
||||
port_handler[HANDLE_STD_RD].read_portw = std_port_inw_h;
|
||||
port_handler[HANDLE_STD_RD].read_portw = std_port_inw;
|
||||
port_handler[HANDLE_STD_RD].write_portw = port_not_avail_outw;
|
||||
port_handler[HANDLE_STD_RD].read_portd = std_port_ind_h;
|
||||
port_handler[HANDLE_STD_RD].read_portd = std_port_ind;
|
||||
port_handler[HANDLE_STD_RD].write_portd = port_not_avail_outd;
|
||||
port_handler[HANDLE_STD_RD].handler_name = "std port read";
|
||||
|
||||
port_handler[HANDLE_STD_WR].read_portb = port_not_avail_inb;
|
||||
port_handler[HANDLE_STD_WR].write_portb = std_port_outb_h;
|
||||
port_handler[HANDLE_STD_WR].write_portb = std_port_outb;
|
||||
port_handler[HANDLE_STD_WR].read_portw = port_not_avail_inw;
|
||||
port_handler[HANDLE_STD_WR].write_portw = std_port_outw_h;
|
||||
port_handler[HANDLE_STD_WR].write_portw = std_port_outw;
|
||||
port_handler[HANDLE_STD_WR].read_portd = port_not_avail_ind;
|
||||
port_handler[HANDLE_STD_WR].write_portd = std_port_outd_h;
|
||||
port_handler[HANDLE_STD_WR].write_portd = std_port_outd;
|
||||
port_handler[HANDLE_STD_WR].handler_name = "std port write";
|
||||
#if 0
|
||||
port_handler[HANDLE_VID_IO].read_portb = video_port_in;
|
||||
@@ -863,12 +841,12 @@ int port_init(void)
|
||||
port_handler[HANDLE_VID_IO].write_portd = NULL;
|
||||
port_handler[HANDLE_VID_IO].handler_name = "video port io";
|
||||
#else
|
||||
port_handler[HANDLE_VID_IO].read_portb = std_port_inb_h;
|
||||
port_handler[HANDLE_VID_IO].write_portb = std_port_outb_h;
|
||||
port_handler[HANDLE_VID_IO].read_portw = std_port_inw_h;
|
||||
port_handler[HANDLE_VID_IO].write_portw = std_port_outw_h;
|
||||
port_handler[HANDLE_VID_IO].read_portd = std_port_ind_h;
|
||||
port_handler[HANDLE_VID_IO].write_portd = std_port_outd_h;
|
||||
port_handler[HANDLE_VID_IO].read_portb = std_port_inb;
|
||||
port_handler[HANDLE_VID_IO].write_portb = std_port_outb;
|
||||
port_handler[HANDLE_VID_IO].read_portw = std_port_inw;
|
||||
port_handler[HANDLE_VID_IO].write_portw = std_port_outw;
|
||||
port_handler[HANDLE_VID_IO].read_portd = std_port_ind;
|
||||
port_handler[HANDLE_VID_IO].write_portd = std_port_outd;
|
||||
port_handler[HANDLE_VID_IO].handler_name = "std port io";
|
||||
#endif
|
||||
|
||||
@@ -889,13 +867,13 @@ int port_init(void)
|
||||
return port_handles; /* unused but useful */
|
||||
}
|
||||
|
||||
static void portserver_exit(void *arg)
|
||||
static void portserver_exit(void)
|
||||
{
|
||||
error("port server terminated, exiting\n");
|
||||
leavedos(1);
|
||||
}
|
||||
|
||||
/* port server: this function runs in a separate process from the main
|
||||
/* port server: this function runs in a seperate process from the main
|
||||
DOSEMU. This enables the main DOSEMU to drop root privileges. The
|
||||
server can do that as well: by setting iopl(3).
|
||||
Maybe this server should wrap DOSEMU rather than be forked from
|
||||
@@ -905,7 +883,7 @@ static void port_server(void)
|
||||
{
|
||||
sigset_t set;
|
||||
struct portreq pr;
|
||||
_port_handler *ph, *ph1, *ph2, *ph3;
|
||||
_port_handler *ph;
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
signal(SIGHUP, SIG_DFL);
|
||||
@@ -926,70 +904,33 @@ static void port_server(void)
|
||||
if (pr.type >= TYPE_EXIT)
|
||||
_exit(0);
|
||||
ph = &EMU_HANDLER(pr.port);
|
||||
ph1 = &EMU_HANDLER(pr.port + 1);
|
||||
ph2 = &EMU_HANDLER(pr.port + 2);
|
||||
ph3 = &EMU_HANDLER(pr.port + 3);
|
||||
if (pr.type == TYPE_PCI) {
|
||||
/* get addr and data i/o access as close to each other
|
||||
as possible, both to minimize possible races, and
|
||||
for speed */
|
||||
struct portreq pr2;
|
||||
read(port_fd_out[0], &pr2, sizeof(pr2));
|
||||
ph->write_portd(pr.port, pr.word, ph->arg);
|
||||
ph->write_portd(pr.port, pr.word);
|
||||
pr = pr2;
|
||||
}
|
||||
switch (pr.type) {
|
||||
case TYPE_INB:
|
||||
pr.word = ph->read_portb(pr.port, ph->arg);
|
||||
pr.word = ph->read_portb(pr.port);
|
||||
break;
|
||||
case TYPE_OUTB:
|
||||
ph->write_portb(pr.port, pr.word, ph->arg);
|
||||
ph->write_portb(pr.port, pr.word);
|
||||
break;
|
||||
case TYPE_INW:
|
||||
if (ph->read_portb == ph1->read_portb) {
|
||||
pr.word = ph->read_portw(pr.port, ph->arg);
|
||||
} else {
|
||||
i_printf("PORT: splitting inw(0x%x)\n", pr.port);
|
||||
pr.word = ph->read_portb(pr.port, ph->arg) |
|
||||
(ph1->read_portb(pr.port + 1, ph->arg) << 8);
|
||||
}
|
||||
pr.word = ph->read_portw(pr.port);
|
||||
break;
|
||||
case TYPE_OUTW:
|
||||
if (ph->write_portb == ph1->write_portb) {
|
||||
ph->write_portw(pr.port, pr.word, ph->arg);
|
||||
} else {
|
||||
i_printf("PORT: splitting outw(0x%x)\n", pr.port);
|
||||
ph->write_portb(pr.port, pr.word, ph->arg);
|
||||
ph1->write_portb(pr.port + 1, pr.word >> 8, ph->arg);
|
||||
}
|
||||
ph->write_portw(pr.port, pr.word);
|
||||
break;
|
||||
case TYPE_IND:
|
||||
if (ph->read_portb == ph1->read_portb &&
|
||||
ph->read_portb == ph2->read_portb &&
|
||||
ph->read_portb == ph3->read_portb
|
||||
) {
|
||||
pr.word = ph->read_portd(pr.port, ph->arg);
|
||||
} else {
|
||||
i_printf("PORT: splitting ind(0x%x)\n", pr.port);
|
||||
pr.word = ph->read_portb(pr.port, ph->arg) |
|
||||
(ph1->read_portb(pr.port + 1, ph->arg) << 8) |
|
||||
(ph2->read_portb(pr.port + 2, ph->arg) << 16) |
|
||||
(ph3->read_portb(pr.port + 3, ph->arg) << 24);
|
||||
}
|
||||
pr.word = ph->read_portd(pr.port);
|
||||
break;
|
||||
case TYPE_OUTD:
|
||||
if (ph->write_portb == ph1->write_portb &&
|
||||
ph->write_portb == ph2->write_portb &&
|
||||
ph->write_portb == ph3->write_portb
|
||||
) {
|
||||
ph->write_portd(pr.port, pr.word, ph->arg);
|
||||
} else {
|
||||
i_printf("PORT: splitting outd(0x%x)\n", pr.port);
|
||||
ph->write_portb(pr.port, pr.word, ph->arg);
|
||||
ph1->write_portb(pr.port + 1, pr.word >> 8, ph->arg);
|
||||
ph2->write_portb(pr.port + 2, pr.word >> 16, ph->arg);
|
||||
ph3->write_portb(pr.port + 3, pr.word >> 24, ph->arg);
|
||||
}
|
||||
ph->write_portd(pr.port, pr.word);
|
||||
break;
|
||||
}
|
||||
write(port_fd_in[1], &pr, sizeof(pr));
|
||||
@@ -1047,7 +988,7 @@ int extra_port_init(void)
|
||||
close(port_fd_in[1]);
|
||||
close(port_fd_out[0]);
|
||||
sigchld_register_handler(portserver_pid,
|
||||
portserver_exit, NULL);
|
||||
portserver_exit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1070,11 +1011,21 @@ void port_exit(void)
|
||||
|
||||
void release_ports (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < port_handles; i++) {
|
||||
if (port_handler[i].fd >= 2) {
|
||||
close(port_handler[i].fd);
|
||||
/* DANG_FIXTHIS we should free the name but we are going to exit anyway
|
||||
*/
|
||||
/* free(port_handler[i].handler_name); */
|
||||
}
|
||||
}
|
||||
memset (port_handle_table, NO_HANDLE, sizeof(port_handle_table));
|
||||
memset (port_andmask, 0xff, sizeof(port_andmask));
|
||||
memset (port_ormask, 0, sizeof(port_ormask));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/*
|
||||
@@ -1089,6 +1040,12 @@ int port_register_handler(emu_iodev_t device, int flags)
|
||||
{
|
||||
int handle, i;
|
||||
|
||||
if (device.irq != EMU_NO_IRQ && device.irq >= EMU_MAX_IRQS) {
|
||||
dbug_printf("PORT: IO device %s registered with IRQ=%d above %u\n",
|
||||
device.handler_name, device.irq, EMU_MAX_IRQS - 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* first find existing handle for function or create new one */
|
||||
for (handle=0; handle < port_handles; handle++) {
|
||||
if (!strcmp(port_handler[handle].handler_name, device.handler_name))
|
||||
@@ -1102,17 +1059,34 @@ int port_register_handler(emu_iodev_t device, int flags)
|
||||
leavedos(77);
|
||||
}
|
||||
|
||||
if (device.irq != EMU_NO_IRQ && irq_handler_name[device.irq]) {
|
||||
error("PORT: IRQ %d conflict. IO devices %s & %s\n",
|
||||
device.irq, irq_handler_name[device.irq], device.handler_name);
|
||||
if (device.fd) close(device.fd);
|
||||
return 2;
|
||||
}
|
||||
if (device.irq != EMU_NO_IRQ && device.irq < EMU_MAX_IRQS)
|
||||
irq_handler_name[device.irq] = device.handler_name;
|
||||
port_handles++;
|
||||
port_handler[handle] = device;
|
||||
|
||||
/*
|
||||
* for byte and double, a NULL function means that the port
|
||||
* access is not available, while for word means that it will
|
||||
* be translated into 2 byte accesses
|
||||
*/
|
||||
if (!device.read_portb)
|
||||
port_handler[handle].read_portb = port_not_avail_inb;
|
||||
if (!device.write_portb)
|
||||
port_handler[handle].write_portb = port_not_avail_outb;
|
||||
port_handler[handle].read_portb =
|
||||
(device.read_portb? : port_not_avail_inb);
|
||||
port_handler[handle].write_portb =
|
||||
(device.write_portb? : port_not_avail_outb);
|
||||
port_handler[handle].read_portw = device.read_portw;
|
||||
port_handler[handle].write_portw = device.write_portw;
|
||||
port_handler[handle].read_portd =
|
||||
(device.read_portd? : port_not_avail_ind);
|
||||
port_handler[handle].write_portd =
|
||||
(device.write_portd? : port_not_avail_outd);
|
||||
port_handler[handle].handler_name = device.handler_name;
|
||||
port_handler[handle].irq = device.irq;
|
||||
port_handler[handle].fd = -1;
|
||||
}
|
||||
|
||||
/* change table to reflect new handler id for that address */
|
||||
@@ -1121,7 +1095,7 @@ int port_register_handler(emu_iodev_t device, int flags)
|
||||
error("PORT: conflicting devices: %s & %s for port %#x\n",
|
||||
port_handler[handle].handler_name,
|
||||
EMU_HANDLER(i).handler_name, i);
|
||||
config.exitearly = 1;
|
||||
if (device.fd) close(device.fd);
|
||||
return 4;
|
||||
}
|
||||
port_handle_table[i] = handle;
|
||||
@@ -1129,9 +1103,9 @@ int port_register_handler(emu_iodev_t device, int flags)
|
||||
set_bit(i, portfast_map);
|
||||
}
|
||||
|
||||
i_printf("PORT: registered \"%s\" handle 0x%02x [0x%04x-0x%04x]\n",
|
||||
i_printf("PORT: registered \"%s\" handle 0x%02x [0x%04x-0x%04x] fd=%d\n",
|
||||
port_handler[handle].handler_name, handle, device.start_addr,
|
||||
device.end_addr);
|
||||
device.end_addr, device.fd);
|
||||
|
||||
if (flags & PORT_FAST) {
|
||||
i_printf("PORT: trying to give fast access to ports [0x%04x-0x%04x]\n",
|
||||
@@ -1152,10 +1126,17 @@ int port_register_handler(emu_iodev_t device, int flags)
|
||||
* SIDOC_END_FUNCTION
|
||||
*/
|
||||
Boolean port_allow_io(ioport_t start, Bit16u size, int permission, Bit8u ormask,
|
||||
Bit8u andmask, int portspeed)
|
||||
Bit8u andmask, int portspeed, char *device)
|
||||
{
|
||||
static emu_iodev_t io_device;
|
||||
int usemasks = 0;
|
||||
FILE *fp;
|
||||
unsigned int beg, end, newbeg, newend;
|
||||
size_t len;
|
||||
ssize_t bytes;
|
||||
char *line, *portname, lock_file[64];
|
||||
unsigned char mapped;
|
||||
char *devrname;
|
||||
int fd, usemasks = 0;
|
||||
unsigned int flags = 0;
|
||||
|
||||
if (!can_do_root_stuff) {
|
||||
@@ -1173,6 +1154,117 @@ Boolean port_allow_io(ioport_t start, Bit16u size, int permission, Bit8u ormask,
|
||||
usemasks = 1;
|
||||
}
|
||||
|
||||
/* SIDOC_BEGIN_REMARK
|
||||
* find out whether the port address request is available;
|
||||
* this way, try to deny uncoordinated access
|
||||
*
|
||||
* If it is not listed in /proc/ioports, register them
|
||||
* (we need some syscall to do so bo 960609)...
|
||||
* (we have a module to do so AV 970813)
|
||||
* if it is registered, we need the name of a device to open
|
||||
* if we can't open it, we disallow access to that port
|
||||
* SIDOC_END_REMARK
|
||||
*/
|
||||
if ((fp = fopen("/proc/ioports", "r")) == NULL) {
|
||||
i_printf("PORT: can't open /proc/ioports\n");
|
||||
return FALSE;
|
||||
}
|
||||
mapped = beg = end = len = 0;
|
||||
portname = line = NULL;
|
||||
while ((bytes = getline(&line, &len, fp)) != -1) {
|
||||
int i;
|
||||
if (bytes > 0 && line[bytes-1] == '\n')
|
||||
line[bytes-1] = '\0';
|
||||
if (sscanf(line, "%x-%x : %n", &newbeg, &newend, &i) < 2)
|
||||
break;
|
||||
if (mapped) {
|
||||
/* only break if no overlap with previous line */
|
||||
if (newend > end) break;
|
||||
free(portname);
|
||||
mapped = 0;
|
||||
}
|
||||
beg = newbeg;
|
||||
end = newend;
|
||||
if ((start <= end) && ((start+size) > beg)) {
|
||||
/* ports are besetzt, try to open the according device */
|
||||
portname = strdup(&line[i]);
|
||||
mapped = 1;
|
||||
}
|
||||
}
|
||||
fclose (fp);
|
||||
|
||||
if (mapped) {
|
||||
const char *name = portname ? portname : "";
|
||||
i_printf("PORT: range 0x%04x-0x%04x already registered as %s\n",
|
||||
beg, end, name);
|
||||
if (!strncasecmp(name,"dosemu",6)) return FALSE;
|
||||
if (device==NULL || *device==0) {
|
||||
i_printf ("PORT: no device specified for %s\n", name);
|
||||
return FALSE;
|
||||
}
|
||||
free (portname);
|
||||
}
|
||||
|
||||
io_device.fd = -1;
|
||||
if (device && *device) {
|
||||
/* SIDOC_BEGIN_REMARK
|
||||
* We need to check if our required port range is in use
|
||||
* by some device. So we look into proc/ioports to check
|
||||
* the addresses. Fine, but at this point we must supply
|
||||
* a device name ourselves, and we can't check from here
|
||||
* if it's the right one. The device is then open and left
|
||||
* open until dosemu ends; for the rest, in the original
|
||||
* code the device wasn't used, just locked, and only then
|
||||
* port access was granted.
|
||||
* SIDOC_END_REMARK
|
||||
*/
|
||||
int devperm;
|
||||
|
||||
devrname=strrchr(device,'/');
|
||||
if (devrname==NULL) devrname=device; else devrname++;
|
||||
sprintf(lock_file, "%s/%s%s", PATH_LOCKD, NAME_LOCKF, devrname);
|
||||
|
||||
switch (permission) {
|
||||
case IO_READ: devperm = O_RDONLY;
|
||||
flags |= PORT_DEV_RD;
|
||||
break;
|
||||
case IO_WRITE: devperm = O_WRONLY;
|
||||
flags |= PORT_DEV_WR;
|
||||
break;
|
||||
default: devperm = O_RDWR;
|
||||
flags |= (PORT_DEV_RD|PORT_DEV_WR);
|
||||
}
|
||||
io_device.fd = open(device, devperm);
|
||||
if (io_device.fd == -1) {
|
||||
switch (errno) {
|
||||
case EBUSY:
|
||||
i_printf("PORT: Device %s busy\n", device);
|
||||
return FALSE;
|
||||
case EACCES:
|
||||
i_printf("PORT: Device %s, access not allowed\n", device);
|
||||
return FALSE;
|
||||
case ENOENT:
|
||||
case ENXIO:
|
||||
i_printf("PORT: No such Device '%s'\n", device);
|
||||
return FALSE;
|
||||
default:
|
||||
i_printf("PORT: Device %s error %d\n", device, errno);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
fd = open(lock_file, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
i_printf("PORT: Device %s is locked\n", device);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
i_printf("PORT: Device %s opened successfully = %d\n", device,
|
||||
io_device.fd);
|
||||
|
||||
}
|
||||
|
||||
if (permission == IO_RDWR)
|
||||
io_device.handler_name = "std port io";
|
||||
else if (permission == IO_READ)
|
||||
@@ -1182,6 +1274,7 @@ Boolean port_allow_io(ioport_t start, Bit16u size, int permission, Bit8u ormask,
|
||||
|
||||
io_device.start_addr = start;
|
||||
io_device.end_addr = start + size - 1;
|
||||
io_device.irq = EMU_NO_IRQ;
|
||||
|
||||
if (usemasks) {
|
||||
port_andmask[start] = andmask;
|
||||
@@ -1206,7 +1299,7 @@ Boolean port_allow_io(ioport_t start, Bit16u size, int permission, Bit8u ormask,
|
||||
int
|
||||
set_ioperm(int start, int size, int flag)
|
||||
{
|
||||
#ifdef HAVE_SYS_IO_H
|
||||
#ifdef __linux__
|
||||
PRIV_SAVE_AREA
|
||||
int tmp;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user