New upstream version 2.0-0.9
Some checks failed
Build / build (push) Has been cancelled

This commit is contained in:
geos_one
2025-08-14 09:28:49 +02:00
parent c338ff82fb
commit 17bb5d7efa
634 changed files with 19105 additions and 52303 deletions

View File

@@ -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;