0ba91ae22a
With some newer UEFI firmware, not all pci bars get programmed and we have to assign them ourselfs. This was already done for memory bars. This change adds the same for i/o port space, by providing a ioreservewin() function which can be used to allocate port space within the parent pci-pci bridge window. Also, the pci code now allocates the pci config space i/o ports 0xCF8/0xCFC so userspace needs to use devpnp to access pci config space now. (see latest realemu change). Also, this moves the ioalloc()/iofree() code out of devarch into port/iomap.c as it can be shared with the ppc mtx kernel.
257 lines
4.3 KiB
C
257 lines
4.3 KiB
C
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "io.h"
|
|
#include "../port/error.h"
|
|
|
|
enum {
|
|
Qdir = 0,
|
|
Qiob,
|
|
Qiow,
|
|
Qiol,
|
|
Qbase,
|
|
|
|
Qmax = 16,
|
|
};
|
|
|
|
typedef long Rdwrfn(Chan*, void*, long, vlong);
|
|
|
|
static Rdwrfn *readfn[Qmax];
|
|
static Rdwrfn *writefn[Qmax];
|
|
|
|
static Dirtab archdir[] = {
|
|
".", { Qdir, 0, QTDIR }, 0, 0555,
|
|
"iob", { Qiob, 0 }, 0, 0660,
|
|
"iow", { Qiow, 0 }, 0, 0660,
|
|
"iol", { Qiol, 0 }, 0, 0660,
|
|
};
|
|
Lock archwlock; /* the lock is only for changing archdir */
|
|
int narchdir = Qbase;
|
|
int (*_pcmspecial)(char *, ISAConf *);
|
|
void (*_pcmspecialclose)(int);
|
|
|
|
/*
|
|
* Add a file to the #P listing. Once added, you can't delete it.
|
|
* You can't add a file with the same name as one already there,
|
|
* and you get a pointer to the Dirtab entry so you can do things
|
|
* like change the Qid version. Changing the Qid path is disallowed.
|
|
*/
|
|
Dirtab*
|
|
addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
|
|
{
|
|
int i;
|
|
Dirtab d;
|
|
Dirtab *dp;
|
|
|
|
memset(&d, 0, sizeof d);
|
|
strcpy(d.name, name);
|
|
d.perm = perm;
|
|
|
|
lock(&archwlock);
|
|
if(narchdir >= Qmax){
|
|
unlock(&archwlock);
|
|
return nil;
|
|
}
|
|
|
|
for(i=0; i<narchdir; i++)
|
|
if(strcmp(archdir[i].name, name) == 0){
|
|
unlock(&archwlock);
|
|
return nil;
|
|
}
|
|
|
|
d.qid.path = narchdir;
|
|
archdir[narchdir] = d;
|
|
readfn[narchdir] = rdfn;
|
|
writefn[narchdir] = wrfn;
|
|
dp = &archdir[narchdir++];
|
|
unlock(&archwlock);
|
|
|
|
return dp;
|
|
}
|
|
|
|
void
|
|
ioinit(void)
|
|
{
|
|
iomapinit(IOSIZE-1);
|
|
|
|
// a dummy entry at 2^17
|
|
ioalloc(0x20000, 1, 0, "dummy");
|
|
}
|
|
|
|
static void
|
|
checkport(int start, int end)
|
|
{
|
|
/* standard vga regs are OK */
|
|
if(start >= 0x2b0 && end <= 0x2df+1)
|
|
return;
|
|
if(start >= 0x3c0 && end <= 0x3da+1)
|
|
return;
|
|
|
|
if(iounused(start, end))
|
|
return;
|
|
error(Eperm);
|
|
}
|
|
|
|
static Chan*
|
|
archattach(char* spec)
|
|
{
|
|
return devattach('P', spec);
|
|
}
|
|
|
|
Walkqid*
|
|
archwalk(Chan* c, Chan *nc, char** name, int nname)
|
|
{
|
|
return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
|
|
}
|
|
|
|
static int
|
|
archstat(Chan* c, uchar* dp, int n)
|
|
{
|
|
return devstat(c, dp, n, archdir, narchdir, devgen);
|
|
}
|
|
|
|
static Chan*
|
|
archopen(Chan* c, int omode)
|
|
{
|
|
return devopen(c, omode, archdir, nelem(archdir), devgen);
|
|
}
|
|
|
|
static void
|
|
archclose(Chan*)
|
|
{
|
|
}
|
|
|
|
static long
|
|
archread(Chan *c, void *a, long n, vlong offset)
|
|
{
|
|
int port;
|
|
uchar *cp;
|
|
ushort *sp;
|
|
ulong *lp;
|
|
IOMap *m;
|
|
Rdwrfn *fn;
|
|
|
|
switch((ulong)c->qid.path){
|
|
|
|
case Qdir:
|
|
return devdirread(c, a, n, archdir, nelem(archdir), devgen);
|
|
|
|
case Qiob:
|
|
port = offset;
|
|
checkport(offset, offset+n);
|
|
for(cp = a; port < offset+n; port++)
|
|
*cp++ = inb(port);
|
|
return n;
|
|
|
|
case Qiow:
|
|
if((n & 0x01) || (offset & 0x01))
|
|
error(Ebadarg);
|
|
checkport(offset, offset+n+1);
|
|
n /= 2;
|
|
sp = a;
|
|
for(port = offset; port < offset+n; port += 2)
|
|
*sp++ = ins(port);
|
|
return n*2;
|
|
|
|
case Qiol:
|
|
if((n & 0x03) || (offset & 0x03))
|
|
error(Ebadarg);
|
|
checkport(offset, offset+n+3);
|
|
n /= 4;
|
|
lp = a;
|
|
for(port = offset; port < offset+n; port += 4)
|
|
*lp++ = inl(port);
|
|
return n*4;
|
|
|
|
default:
|
|
if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
|
|
return fn(c, a, n, offset);
|
|
error(Eperm);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static long
|
|
archwrite(Chan *c, void *a, long n, vlong offset)
|
|
{
|
|
int port;
|
|
uchar *cp;
|
|
ushort *sp;
|
|
ulong *lp;
|
|
Rdwrfn *fn;
|
|
|
|
switch((ulong)c->qid.path){
|
|
|
|
case Qiob:
|
|
cp = a;
|
|
checkport(offset, offset+n);
|
|
for(port = offset; port < offset+n; port++)
|
|
outb(port, *cp++);
|
|
return n;
|
|
|
|
case Qiow:
|
|
if((n & 01) || (offset & 01))
|
|
error(Ebadarg);
|
|
checkport(offset, offset+n+1);
|
|
n /= 2;
|
|
sp = a;
|
|
for(port = offset; port < offset+n; port += 2)
|
|
outs(port, *sp++);
|
|
return n*2;
|
|
|
|
case Qiol:
|
|
if((n & 0x03) || (offset & 0x03))
|
|
error(Ebadarg);
|
|
checkport(offset, offset+n+3);
|
|
n /= 4;
|
|
lp = a;
|
|
for(port = offset; port < offset+n; port += 4)
|
|
outl(port, *lp++);
|
|
return n*4;
|
|
|
|
default:
|
|
if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
|
|
return fn(c, a, n, offset);
|
|
error(Eperm);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Dev archdevtab = {
|
|
'P',
|
|
"arch",
|
|
|
|
devreset,
|
|
devinit,
|
|
devshutdown,
|
|
archattach,
|
|
archwalk,
|
|
archstat,
|
|
archopen,
|
|
devcreate,
|
|
archclose,
|
|
archread,
|
|
devbread,
|
|
archwrite,
|
|
devbwrite,
|
|
devremove,
|
|
devwstat,
|
|
};
|
|
|
|
int
|
|
pcmspecial(char *idstr, ISAConf *isa)
|
|
{
|
|
return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
|
|
}
|
|
|
|
void
|
|
pcmspecialclose(int a)
|
|
{
|
|
if (_pcmspecialclose != nil)
|
|
_pcmspecialclose(a);
|
|
}
|