kernel: deep refactoring and cleanup
This large commit address several issues - removed 386 directory: Jehanne is 64bit only - simplified kernel options management - rewritten boot process - ported memory related stuff from 9front's 9/pc64 - removed devacpi - removed old code - deep refactor of awake syscall - removed MCACHE support for mount - fix libc's setjmp/longjmp
This commit is contained in:
parent
1bc08b7631
commit
93dde48355
|
@ -159,7 +159,7 @@ extern void memarc(Memimage*, Point, int, int, int, Memimage*, Point, int, int,
|
||||||
extern Rectangle memlinebbox(Point, Point, int, int, int);
|
extern Rectangle memlinebbox(Point, Point, int, int, int);
|
||||||
extern int memlineendsize(int);
|
extern int memlineendsize(int);
|
||||||
extern void _memmkcmap(void);
|
extern void _memmkcmap(void);
|
||||||
extern void memimageinit(void);
|
extern int memimageinit(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subfont management
|
* Subfont management
|
||||||
|
|
|
@ -10,16 +10,20 @@
|
||||||
typedef struct Pool Pool;
|
typedef struct Pool Pool;
|
||||||
struct Pool {
|
struct Pool {
|
||||||
char* name;
|
char* name;
|
||||||
uint32_t maxsize;
|
uintptr_t maxsize;
|
||||||
|
|
||||||
uint32_t cursize;
|
uintptr_t cursize;
|
||||||
uint32_t curfree;
|
uintptr_t curfree;
|
||||||
uint32_t curalloc;
|
uintptr_t curalloc;
|
||||||
|
|
||||||
uint32_t minarena; /* smallest size of new arena */
|
uint32_t minarena; /* smallest size of new arena */
|
||||||
uint32_t quantum; /* allocated blocks should be multiple of */
|
uint32_t quantum; /* allocated blocks should be multiple of */
|
||||||
uint32_t minblock; /* smallest newly allocated block */
|
uint32_t minblock; /* smallest newly allocated block */
|
||||||
|
|
||||||
|
int flags;
|
||||||
|
int nfree;
|
||||||
|
int lastcompact;
|
||||||
|
|
||||||
void* freeroot; /* actually Free* */
|
void* freeroot; /* actually Free* */
|
||||||
void* arenalist; /* actually Arena* */
|
void* arenalist; /* actually Arena* */
|
||||||
|
|
||||||
|
@ -27,10 +31,6 @@ struct Pool {
|
||||||
int (*merge)(void*, void*);
|
int (*merge)(void*, void*);
|
||||||
void (*move)(void* from, void* to);
|
void (*move)(void* from, void* to);
|
||||||
|
|
||||||
int flags;
|
|
||||||
int nfree;
|
|
||||||
int lastcompact;
|
|
||||||
|
|
||||||
void (*lock)(Pool*);
|
void (*lock)(Pool*);
|
||||||
void (*unlock)(Pool*);
|
void (*unlock)(Pool*);
|
||||||
void (*print)(Pool*, char*, ...);
|
void (*print)(Pool*, char*, ...);
|
||||||
|
@ -41,8 +41,7 @@ struct Pool {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void* poolalloc(Pool*, uint32_t);
|
extern void* poolalloc(Pool*, uint32_t);
|
||||||
extern void* poolallocalign(Pool*, uint32_t, uint32_t, int32_t,
|
extern void* poolallocalign(Pool*, uint32_t, uint32_t, int32_t, uint32_t);
|
||||||
uint32_t);
|
|
||||||
extern void poolfree(Pool*, void*);
|
extern void poolfree(Pool*, void*);
|
||||||
extern uint32_t poolmsize(Pool*, void*);
|
extern uint32_t poolmsize(Pool*, void*);
|
||||||
extern void* poolrealloc(Pool*, void*, uint32_t);
|
extern void* poolrealloc(Pool*, void*, uint32_t);
|
||||||
|
|
|
@ -57,8 +57,8 @@ main(int argc, char *argv[])
|
||||||
srv = "screenconsole";
|
srv = "screenconsole";
|
||||||
|
|
||||||
/* first try in /dev so that binding can work */
|
/* first try in /dev so that binding can work */
|
||||||
if((fd = open("/dev/ps2keyb", OREAD)) <= 0)
|
if((fd = open("/dev/scancode", OREAD)) <= 0)
|
||||||
if((fd = open("#P/ps2keyb", OREAD)) <= 0)
|
if((fd = open("#b/scancode", OREAD)) <= 0)
|
||||||
sysfatal("open keyboard: %r");
|
sysfatal("open keyboard: %r");
|
||||||
dup(fd, 0);
|
dup(fd, 0);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"realemu": {
|
"realemu": {
|
||||||
"Cflags": [
|
"Cflags": [
|
||||||
"-I", "/sys/src/kern/386/"
|
"-I", "/sys/src/kern/$ARCH/"
|
||||||
],
|
],
|
||||||
"Include": [
|
"Include": [
|
||||||
"/sys/src/cmd/cmd.json"
|
"/sys/src/cmd/cmd.json"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"vga": {
|
"vga": {
|
||||||
"Cflags": [
|
"Cflags": [
|
||||||
"-I", "/sys/src/kern/386/"
|
"-I", "/sys/src/kern/$ARCH/"
|
||||||
],
|
],
|
||||||
"Include": [
|
"Include": [
|
||||||
"/sys/src/cmd/cmd.json"
|
"/sys/src/cmd/cmd.json"
|
||||||
|
|
|
@ -120,9 +120,6 @@ main(int argc, char **argv)
|
||||||
case 'c':
|
case 'c':
|
||||||
mntflags |= MCREATE;
|
mntflags |= MCREATE;
|
||||||
break;
|
break;
|
||||||
case 'C':
|
|
||||||
mntflags |= MCACHE;
|
|
||||||
break;
|
|
||||||
case 'd':
|
case 'd':
|
||||||
debug++;
|
debug++;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -71,9 +71,6 @@ main(int argc, char *argv[])
|
||||||
case 'd':
|
case 'd':
|
||||||
setmntdevice(EARGF(usage()));
|
setmntdevice(EARGF(usage()));
|
||||||
break;
|
break;
|
||||||
case 'C':
|
|
||||||
flag |= MCACHE;
|
|
||||||
break;
|
|
||||||
case 'k':
|
case 'k':
|
||||||
keyspec = EARGF(usage());
|
keyspec = EARGF(usage());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -103,11 +103,6 @@ main(int argc, char *argv[])
|
||||||
domount = 1;
|
domount = 1;
|
||||||
reallymount = 1;
|
reallymount = 1;
|
||||||
break;
|
break;
|
||||||
case 'C':
|
|
||||||
mountflag |= MCACHE;
|
|
||||||
domount = 1;
|
|
||||||
reallymount = 1;
|
|
||||||
break;
|
|
||||||
case 'e':
|
case 'e':
|
||||||
doexec = 1;
|
doexec = 1;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,328 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
||||||
* terms in the LICENSE file found in the top-level directory of this
|
|
||||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
||||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
|
||||||
* in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
#include "../port/error.h"
|
|
||||||
|
|
||||||
#include "io.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
Data= 0x60, /* data port */
|
|
||||||
|
|
||||||
Status= 0x64, /* status port */
|
|
||||||
Inready= 0x01, /* input character ready */
|
|
||||||
Outbusy= 0x02, /* output busy */
|
|
||||||
Sysflag= 0x04, /* system flag */
|
|
||||||
Cmddata= 0x08, /* cmd==0, data==1 */
|
|
||||||
Inhibit= 0x10, /* keyboard/mouse inhibited */
|
|
||||||
Minready= 0x20, /* mouse character ready */
|
|
||||||
Rtimeout= 0x40, /* general timeout */
|
|
||||||
Parity= 0x80,
|
|
||||||
|
|
||||||
Cmd= 0x64, /* command port (write only) */
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
/* controller command byte */
|
|
||||||
Cscs1= (1<<6), /* scan code set 1 */
|
|
||||||
Cauxdis= (1<<5), /* mouse disable */
|
|
||||||
Ckeybdis= (1<<4), /* keyb disable */
|
|
||||||
Csf= (1<<2), /* system flag */
|
|
||||||
Cauxint= (1<<1), /* mouse interrupt enable */
|
|
||||||
Ckeybint= (1<<0), /* keyb interrupt enable */
|
|
||||||
};
|
|
||||||
|
|
||||||
static Queue *keybq;
|
|
||||||
static Queue *mouseq;
|
|
||||||
|
|
||||||
|
|
||||||
static int nokeyb = 1;
|
|
||||||
|
|
||||||
static Lock i8042lock;
|
|
||||||
static uint8_t ccc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* wait for output no longer busy
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
outready(void)
|
|
||||||
{
|
|
||||||
int tries;
|
|
||||||
|
|
||||||
for(tries = 0; (inb(Status) & Outbusy); tries++){
|
|
||||||
if(tries > 500)
|
|
||||||
return -1;
|
|
||||||
delay(2);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* wait for input
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
inready(void)
|
|
||||||
{
|
|
||||||
int tries;
|
|
||||||
|
|
||||||
for(tries = 0; !(inb(Status) & Inready); tries++){
|
|
||||||
if(tries > 500)
|
|
||||||
return -1;
|
|
||||||
delay(2);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
i8042systemreset(void)
|
|
||||||
{
|
|
||||||
uint16_t *s = KADDR(0x472);
|
|
||||||
int i, x;
|
|
||||||
|
|
||||||
if(nokeyb)
|
|
||||||
return;
|
|
||||||
|
|
||||||
*s = 0x1234; /* BIOS warm-boot flag */
|
|
||||||
|
|
||||||
/* newer reset the machine command */
|
|
||||||
outready();
|
|
||||||
outb(Cmd, 0xFE);
|
|
||||||
outready();
|
|
||||||
|
|
||||||
/* Pulse it by hand (old somewhat reliable) */
|
|
||||||
x = 0xDF;
|
|
||||||
for(i = 0; i < 5; i++){
|
|
||||||
x ^= 1;
|
|
||||||
outready();
|
|
||||||
outb(Cmd, 0xD1);
|
|
||||||
outready();
|
|
||||||
outb(Data, x); /* toggle reset */
|
|
||||||
delay(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
mousecmd(int cmd)
|
|
||||||
{
|
|
||||||
unsigned int c;
|
|
||||||
int tries;
|
|
||||||
static int badkbd;
|
|
||||||
|
|
||||||
if(badkbd)
|
|
||||||
return -1;
|
|
||||||
c = 0;
|
|
||||||
tries = 0;
|
|
||||||
|
|
||||||
ilock(&i8042lock);
|
|
||||||
do{
|
|
||||||
if(tries++ > 2)
|
|
||||||
break;
|
|
||||||
if(outready() < 0)
|
|
||||||
break;
|
|
||||||
outb(Cmd, 0xD4);
|
|
||||||
if(outready() < 0)
|
|
||||||
break;
|
|
||||||
outb(Data, cmd);
|
|
||||||
if(outready() < 0)
|
|
||||||
break;
|
|
||||||
if(inready() < 0)
|
|
||||||
break;
|
|
||||||
c = inb(Data);
|
|
||||||
} while(c == 0xFE || c == 0);
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
|
|
||||||
if(c != 0xFA){
|
|
||||||
jehanne_print("mousecmd: %2.2ux returned to the %2.2ux command\n", c, cmd);
|
|
||||||
badkbd = 1; /* don't keep trying; there might not be one */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
mousecmds(uint8_t *cmd, int ncmd)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ilock(&i8042lock);
|
|
||||||
for(i=0; i<ncmd; i++){
|
|
||||||
if(outready() == -1)
|
|
||||||
break;
|
|
||||||
outb(Cmd, 0xD4);
|
|
||||||
if(outready() == -1)
|
|
||||||
break;
|
|
||||||
outb(Data, cmd[i]);
|
|
||||||
}
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
i8042intr(Ureg* u, void* v)
|
|
||||||
{
|
|
||||||
uint8_t stat, data;
|
|
||||||
|
|
||||||
ilock(&i8042lock);
|
|
||||||
stat = inb(Status);
|
|
||||||
if((stat&Inready) == 0){
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data = inb(Data);
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
|
|
||||||
if(stat & Minready){
|
|
||||||
if(mouseq != nil)
|
|
||||||
qiwrite(mouseq, &data, 1);
|
|
||||||
} else {
|
|
||||||
if(keybq != nil)
|
|
||||||
qiwrite(keybq, &data, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
outbyte(int port, int c)
|
|
||||||
{
|
|
||||||
if(outready() == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
outb(port, c);
|
|
||||||
if(outready() == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
mouserwrite(Chan* c, void *vbuf, long len, int64_t off64)
|
|
||||||
{
|
|
||||||
return mousecmds(vbuf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
mouseread(Chan* c, void *vbuf, long len, int64_t off64)
|
|
||||||
{
|
|
||||||
return qread(mouseq, vbuf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
mouseenable(void)
|
|
||||||
{
|
|
||||||
mouseq = qopen(32, 0, 0, 0);
|
|
||||||
if(mouseq == nil)
|
|
||||||
panic("mouseenable");
|
|
||||||
qnoblock(mouseq, 1);
|
|
||||||
|
|
||||||
ccc &= ~Cauxdis;
|
|
||||||
ccc |= Cauxint;
|
|
||||||
|
|
||||||
ilock(&i8042lock);
|
|
||||||
if(outready() == -1)
|
|
||||||
iprint("mouseenable: failed 0\n");
|
|
||||||
outb(Cmd, 0x60); /* write control register */
|
|
||||||
if(outready() == -1)
|
|
||||||
iprint("mouseenable: failed 1\n");
|
|
||||||
outb(Data, ccc);
|
|
||||||
if(outready() == -1)
|
|
||||||
iprint("mouseenable: failed 2\n");
|
|
||||||
outb(Cmd, 0xA8); /* auxilliary device enable */
|
|
||||||
if(outready() == -1){
|
|
||||||
iprint("mouseenable: failed 3\n");
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
|
|
||||||
intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "mouse");
|
|
||||||
addarchfile("ps2mouse", 0666, mouseread, mouserwrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
keybinit(void)
|
|
||||||
{
|
|
||||||
int c, try;
|
|
||||||
|
|
||||||
/* wait for a quiescent controller */
|
|
||||||
ilock(&i8042lock);
|
|
||||||
|
|
||||||
try = 1000;
|
|
||||||
while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
|
|
||||||
if(c & Inready)
|
|
||||||
inb(Data);
|
|
||||||
delay(1);
|
|
||||||
}
|
|
||||||
if (try <= 0) {
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
jehanne_print("keybinit failed 0\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get current controller command byte */
|
|
||||||
outb(Cmd, 0x20);
|
|
||||||
if(inready() == -1){
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
jehanne_print("keybinit failed 1\n");
|
|
||||||
ccc = 0;
|
|
||||||
} else
|
|
||||||
ccc = inb(Data);
|
|
||||||
|
|
||||||
/* enable keyb xfers and interrupts */
|
|
||||||
ccc &= ~(Ckeybdis);
|
|
||||||
ccc |= Csf | Ckeybint | Cscs1;
|
|
||||||
if(outready() == -1) {
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
jehanne_print("keybinit failed 2\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outbyte(Cmd, 0x60) == -1){
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
jehanne_print("keybinit failed 3\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (outbyte(Data, ccc) == -1){
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
jehanne_print("keybinit failed 4\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nokeyb = 0;
|
|
||||||
|
|
||||||
iunlock(&i8042lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
keybread(Chan* c, void *vbuf, long len, int64_t off64)
|
|
||||||
{
|
|
||||||
return qread(keybq, vbuf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
keybenable(void)
|
|
||||||
{
|
|
||||||
keybq = qopen(32, 0, 0, 0);
|
|
||||||
if(keybq == nil)
|
|
||||||
panic("keybinit");
|
|
||||||
qnoblock(keybq, 1);
|
|
||||||
|
|
||||||
ioalloc(Data, 1, 0, "keyb");
|
|
||||||
ioalloc(Cmd, 1, 0, "keyb");
|
|
||||||
|
|
||||||
intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "keyb");
|
|
||||||
|
|
||||||
addarchfile("ps2keyb", 0666, keybread, nil);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"386": {
|
|
||||||
"SourceFiles": [
|
|
||||||
"../386/bios32.c",
|
|
||||||
"../386/devether.c",
|
|
||||||
"../386/devrtc.c",
|
|
||||||
"../386/ether8139.c",
|
|
||||||
"../386/ether8169.c",
|
|
||||||
"../386/ether82557.c",
|
|
||||||
"../386/ether82563.c",
|
|
||||||
"../386/etherigbe.c",
|
|
||||||
"../386/ethermii.c",
|
|
||||||
"../386/etherm10g.c",
|
|
||||||
"../386/i8042.c",
|
|
||||||
"../386/pci.c",
|
|
||||||
"../386/sdiahci.c",
|
|
||||||
"../386/sdscsi.c",
|
|
||||||
"../386/uarti8250.c",
|
|
||||||
"../386/uartpci.c"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -20,8 +20,6 @@ procrestore(Proc *p)
|
||||||
return;
|
return;
|
||||||
cycles(&t);
|
cycles(&t);
|
||||||
p->pcycles -= t;
|
p->pcycles -= t;
|
||||||
|
|
||||||
fpuprocrestore(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -35,11 +33,35 @@ procsave(Proc *p)
|
||||||
cycles(&t);
|
cycles(&t);
|
||||||
p->pcycles += t;
|
p->pcycles += t;
|
||||||
|
|
||||||
fpuprocsave(p);
|
if(p->fpstate == FPactive){
|
||||||
|
if(p->state == Moribund)
|
||||||
|
fpclear();
|
||||||
|
else{
|
||||||
|
/*
|
||||||
|
* Fpsave() stores without handling pending
|
||||||
|
* unmasked exeptions. Postnote() can't be called
|
||||||
|
* here as sleep() already has up->rlock, so
|
||||||
|
* the handling of pending exceptions is delayed
|
||||||
|
* until the process runs again and generates an
|
||||||
|
* emulation fault to activate the FPU.
|
||||||
|
*/
|
||||||
|
fpsave(&p->fpsave);
|
||||||
|
}
|
||||||
|
p->fpstate = FPinactive;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* While this processor is in the scheduler, the process could run
|
||||||
|
* on another processor and exit, returning the page tables to
|
||||||
|
* the free list where they could be reallocated and overwritten.
|
||||||
|
* When this processor eventually has to get an entry from the
|
||||||
|
* trashed page tables it will crash.
|
||||||
|
*
|
||||||
|
* If there's only one processor, this can't happen.
|
||||||
|
* You might think it would be a win not to do this in that case,
|
||||||
|
* especially on VMware, but it turns out not to matter.
|
||||||
*/
|
*/
|
||||||
mmuflushtlb(m->pml4->pa);
|
mmuflushtlb();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -76,12 +98,21 @@ onIdleSpin(void)
|
||||||
/*
|
/*
|
||||||
* put the processor in the halt state if we've no processes to run.
|
* put the processor in the halt state if we've no processes to run.
|
||||||
* an interrupt will get us going again.
|
* an interrupt will get us going again.
|
||||||
|
*
|
||||||
|
* halting in an smp system can result in a startup latency for
|
||||||
|
* processes that become ready.
|
||||||
|
* if idle_spin is zero, we care more about saving energy
|
||||||
|
* than reducing this latency.
|
||||||
|
*
|
||||||
|
* the performance loss with idle_spin == 0 seems to be slight
|
||||||
|
* and it reduces lock contention (thus system time and real time)
|
||||||
|
* on many-core systems with large values of NPROC.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
idlehands(void)
|
idlehands(void)
|
||||||
{
|
{
|
||||||
extern int nrdy;
|
extern int nrdy;
|
||||||
if(sys->nonline == 1)
|
if(sys->nmach == 1)
|
||||||
halt();
|
halt();
|
||||||
else if (SUPPORT_MWAIT)
|
else if (SUPPORT_MWAIT)
|
||||||
mwait32(&nrdy, 0);
|
mwait32(&nrdy, 0);
|
||||||
|
|
|
@ -1,406 +0,0 @@
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
|
|
||||||
static int
|
|
||||||
cpuidinit(void)
|
|
||||||
{
|
|
||||||
uint32_t eax, info[4];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Standard CPUID functions.
|
|
||||||
* Functions 0 and 1 will be needed multiple times
|
|
||||||
* so cache the info now.
|
|
||||||
*/
|
|
||||||
if((m->ncpuinfos = cpuid(0, 0, m->cpuinfo[0])) == 0)
|
|
||||||
return 0;
|
|
||||||
m->ncpuinfos++;
|
|
||||||
|
|
||||||
if(jehanne_memcmp(&m->cpuinfo[0][1], "GenuntelineI", 12) == 0)
|
|
||||||
m->isintelcpu = 1;
|
|
||||||
cpuid(1, 0, m->cpuinfo[1]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extended CPUID functions.
|
|
||||||
*/
|
|
||||||
if((eax = cpuid(0x80000000, 0, info)) >= 0x80000000)
|
|
||||||
m->ncpuinfoe = (eax & ~0x80000000) + 1;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
cpuidinfo(uint32_t eax, uint32_t ecx, uint32_t info[4])
|
|
||||||
{
|
|
||||||
if(m->ncpuinfos == 0 && cpuidinit() == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if(!(eax & 0x80000000)){
|
|
||||||
if(eax >= m->ncpuinfos)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if(eax >= (0x80000000|m->ncpuinfoe))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
cpuid(eax, ecx, info);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t
|
|
||||||
cpuidhz(uint32_t info[2][4])
|
|
||||||
{
|
|
||||||
int f, r;
|
|
||||||
int64_t hz;
|
|
||||||
uint64_t msr;
|
|
||||||
|
|
||||||
if(jehanne_memcmp(&info[0][1], "GenuntelineI", 12) == 0){
|
|
||||||
switch(info[1][0] & 0x0fff3ff0){
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
case 0x00000f30: /* Xeon (MP), Pentium [4D] */
|
|
||||||
case 0x00000f40: /* Xeon (MP), Pentium [4D] */
|
|
||||||
case 0x00000f60: /* Xeon 7100, 5000 or above */
|
|
||||||
msr = rdmsr(0x2c);
|
|
||||||
r = (msr>>16) & 0x07;
|
|
||||||
switch(r){
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
case 0:
|
|
||||||
hz = 266666666666ll;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
hz = 133333333333ll;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
hz = 200000000000ll;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
hz = 166666666666ll;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
hz = 333333333333ll;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hz is *1000 at this point.
|
|
||||||
* Do the scaling then round it.
|
|
||||||
* The manual is conflicting about
|
|
||||||
* the size of the msr field.
|
|
||||||
*/
|
|
||||||
hz = (((hz*(msr>>24))/100)+5)/10;
|
|
||||||
break;
|
|
||||||
case 0x00000690: /* Pentium M, Celeron M */
|
|
||||||
case 0x000006d0: /* Pentium M, Celeron M */
|
|
||||||
hz = ((rdmsr(0x2a)>>22) & 0x1f)*100 * 1000000ll;
|
|
||||||
break;
|
|
||||||
case 0x000006e0: /* Core Duo */
|
|
||||||
case 0x000006f0: /* Core 2 Duo/Quad/Extreme */
|
|
||||||
case 0x00000660: /* kvm over i5 */
|
|
||||||
case 0x00000670: /* Core 2 Extreme */
|
|
||||||
case 0x00000650: /* i5 6xx, i3 5xx */
|
|
||||||
case 0x000006c0: /* i5 4xxx */
|
|
||||||
case 0x000006a0: /* i7 paurea... */
|
|
||||||
/*
|
|
||||||
* Get the FSB frequemcy.
|
|
||||||
* If processor has Enhanced Intel Speedstep Technology
|
|
||||||
* then non-integer bus frequency ratios are possible.
|
|
||||||
*/
|
|
||||||
if(info[1][2] & 0x00000080){
|
|
||||||
msr = rdmsr(0x198);
|
|
||||||
r = (msr>>40) & 0x1f;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
msr = 0;
|
|
||||||
r = rdmsr(0x2a) & 0x1f;
|
|
||||||
}
|
|
||||||
f = rdmsr(0xcd) & 0x07;
|
|
||||||
switch(f){
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
case 5:
|
|
||||||
hz = 100000000000ll;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
hz = 133333333333ll;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
hz = 166666666666ll;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
hz = 200000000000ll;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
hz = 266666666666ll;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
hz = 333333333333ll;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
hz = 400000000000ll;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hz is *1000 at this point.
|
|
||||||
* Do the scaling then round it.
|
|
||||||
*/
|
|
||||||
if(msr & 0x0000400000000000ll)
|
|
||||||
hz = hz*(r+10) + hz/2;
|
|
||||||
else
|
|
||||||
hz = hz*(r+10);
|
|
||||||
hz = ((hz/100)+5)/10;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
DBG("cpuidhz: 0x2a: %#llux hz %lld\n", rdmsr(0x2a), hz);
|
|
||||||
}
|
|
||||||
else if(jehanne_memcmp(&info[0][1], "AuthcAMDenti", 12) == 0){
|
|
||||||
switch(info[1][0] & 0x0fff0ff0){
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
case 0x00050ff0: /* K8 Athlon Venice 64 / Qemu64 */
|
|
||||||
case 0x00020fc0: /* K8 Athlon Lima 64 */
|
|
||||||
case 0x00000f50: /* K8 Opteron 2xxx */
|
|
||||||
msr = rdmsr(0xc0010042);
|
|
||||||
r = (msr>>16) & 0x3f;
|
|
||||||
hz = 200000000ULL*(4 * 2 + r)/2;
|
|
||||||
break;
|
|
||||||
case 0x00100f60: /* K8 Athlon II */
|
|
||||||
case 0x00100f40: /* Phenom II X2 */
|
|
||||||
case 0x00100f20: /* Phenom II X4 */
|
|
||||||
case 0x00100fa0: /* Phenom II X6 */
|
|
||||||
msr = rdmsr(0xc0010042);
|
|
||||||
r = msr & 0x1f;
|
|
||||||
hz = ((r+0x10)*100000000ll)/(1<<(msr>>6 & 0x07));
|
|
||||||
break;
|
|
||||||
case 0x00100f90: /* K10 Opteron 61xx */
|
|
||||||
case 0x00600f00: /* K10 Opteron 62xx */
|
|
||||||
case 0x00600f10: /* K10 Opteron 6272, FX 6xxx/4xxx */
|
|
||||||
case 0x00600f20: /* K10 Opteron 63xx, FX 3xxx/8xxx/9xxx */
|
|
||||||
msr = rdmsr(0xc0010064);
|
|
||||||
r = msr & 0x1f;
|
|
||||||
hz = ((r+0x10)*100000000ll)/(1<<(msr>>6 & 0x07));
|
|
||||||
break;
|
|
||||||
case 0x00000620: /* QEMU64 / Athlon MP/XP */
|
|
||||||
msr = rdmsr(0xc0010064);
|
|
||||||
r = (msr>>6) & 0x07;
|
|
||||||
hz = (((msr & 0x3f)+0x10)*100000000ll)/(1<<r);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
DBG("cpuidhz: %#llux hz %lld\n", msr, hz);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return hz;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
cpuiddump(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
uint32_t info[4];
|
|
||||||
|
|
||||||
if(!DBGFLG)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(m->ncpuinfos == 0 && cpuidinit() == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for(i = 0; i < m->ncpuinfos; i++){
|
|
||||||
cpuid(i, 0, info);
|
|
||||||
DBG("eax = %#8.8ux: %8.8ux %8.8ux %8.8ux %8.8ux\n",
|
|
||||||
i, info[0], info[1], info[2], info[3]);
|
|
||||||
}
|
|
||||||
for(i = 0; i < m->ncpuinfoe; i++){
|
|
||||||
cpuid(0x80000000|i, 0, info);
|
|
||||||
DBG("eax = %#8.8ux: %8.8ux %8.8ux %8.8ux %8.8ux\n",
|
|
||||||
0x80000000|i, info[0], info[1], info[2], info[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t
|
|
||||||
archhz(void)
|
|
||||||
{
|
|
||||||
int64_t hz;
|
|
||||||
uint32_t info[2][4];
|
|
||||||
|
|
||||||
if(DBGFLG && m->machno == 0)
|
|
||||||
cpuiddump();
|
|
||||||
if(!cpuidinfo(0, 0, info[0]) || !cpuidinfo(1, 0, info[1]))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hz = cpuidhz(info);
|
|
||||||
if(hz != 0)
|
|
||||||
return hz;
|
|
||||||
else if(m->machno != 0)
|
|
||||||
return sys->machptr[0]->cpuhz;
|
|
||||||
|
|
||||||
return i8254hz(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
archenable(void)
|
|
||||||
{
|
|
||||||
// here used to be code to enable MONITOR/WAIT
|
|
||||||
// writing 0x1a0 MSR; however such register is
|
|
||||||
// supported on i386 only (MISC_ENABLE), not on x86_64.
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archmmu(void)
|
|
||||||
{
|
|
||||||
uint32_t info[4];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Should the check for m->machno != 0 be here
|
|
||||||
* or in the caller (mmuinit)?
|
|
||||||
*
|
|
||||||
* To do here:
|
|
||||||
* check and enable Pse;
|
|
||||||
* Pge; Nxe.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* How many page sizes are there?
|
|
||||||
* Always have 4*KiB, but need to check
|
|
||||||
* configured correctly.
|
|
||||||
*/
|
|
||||||
assert(PGSZ == 4*KiB);
|
|
||||||
|
|
||||||
m->pgszlg2[0] = 12;
|
|
||||||
m->pgszmask[0] = (1<<12)-1;
|
|
||||||
m->npgsz = 1;
|
|
||||||
if(m->ncpuinfos == 0 && cpuidinit() == 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the Pse bit in function 1 DX for 2*MiB support;
|
|
||||||
* if false, only 4*KiB is available.
|
|
||||||
*/
|
|
||||||
if(!(m->cpuinfo[1][3] & 0x00000008))
|
|
||||||
return 1;
|
|
||||||
m->pgszlg2[1] = 21;
|
|
||||||
m->pgszmask[1] = (1<<21)-1;
|
|
||||||
m->npgsz = 2;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the Page1GB bit in function 0x80000001 DX for 1*GiB support.
|
|
||||||
*/
|
|
||||||
if(cpuidinfo(0x80000001, 0, info) && (info[3] & 0x04000000)){
|
|
||||||
m->pgszlg2[2] = 30;
|
|
||||||
m->pgszmask[2] = (1<<30)-1;
|
|
||||||
m->npgsz = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m->npgsz;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
fmtP(Fmt* f)
|
|
||||||
{
|
|
||||||
uintmem pa;
|
|
||||||
|
|
||||||
pa = va_arg(f->args, uintmem);
|
|
||||||
|
|
||||||
if(f->flags & FmtSharp)
|
|
||||||
return jehanne_fmtprint(f, "%#16.16llux", pa);
|
|
||||||
|
|
||||||
return jehanne_fmtprint(f, "%llud", pa);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
fmtL(Fmt* f)
|
|
||||||
{
|
|
||||||
Mpl pl;
|
|
||||||
|
|
||||||
pl = va_arg(f->args, Mpl);
|
|
||||||
|
|
||||||
return jehanne_fmtprint(f, "%#16.16llux", pl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
fmtR(Fmt* f)
|
|
||||||
{
|
|
||||||
uint64_t r;
|
|
||||||
|
|
||||||
r = va_arg(f->args, uint64_t);
|
|
||||||
|
|
||||||
return jehanne_fmtprint(f, "%#16.16llux", r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* virtual address fmt */
|
|
||||||
static int
|
|
||||||
fmtW(Fmt *f)
|
|
||||||
{
|
|
||||||
uint64_t va;
|
|
||||||
|
|
||||||
va = va_arg(f->args, uint64_t);
|
|
||||||
return jehanne_fmtprint(f, "%#ullx=0x[%ullx][%ullx][%ullx][%ullx][%ullx]", va,
|
|
||||||
PTLX(va, 3), PTLX(va, 2), PTLX(va, 1), PTLX(va, 0),
|
|
||||||
va & ((1<<PGSHFT)-1));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
archfmtinstall(void)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Architecture-specific formatting. Not as neat as they
|
|
||||||
* could be (e.g. there's no defined type for a 'register':
|
|
||||||
* L - Mpl, mach priority level
|
|
||||||
* P - uintmem, physical address
|
|
||||||
* R - register
|
|
||||||
* W - virtual address
|
|
||||||
* With a little effort these routines could be written
|
|
||||||
* in a fairly architecturally-independent manner, relying
|
|
||||||
* on the compiler to optimise-away impossible conditions,
|
|
||||||
* and/or by exploiting the innards of the fmt library.
|
|
||||||
*/
|
|
||||||
jehanne_fmtinstall('P', fmtP);
|
|
||||||
jehanne_fmtinstall('L', fmtL);
|
|
||||||
jehanne_fmtinstall('R', fmtR);
|
|
||||||
jehanne_fmtinstall('W', fmtW);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
archidle(void)
|
|
||||||
{
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
microdelay(int microsecs)
|
|
||||||
{
|
|
||||||
uint64_t r, t;
|
|
||||||
|
|
||||||
r = rdtsc();
|
|
||||||
for(t = r + m->cpumhz*microsecs; r < t; r = rdtsc())
|
|
||||||
pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
millidelay(int millisecs)
|
|
||||||
{
|
|
||||||
uint64_t r, t;
|
|
||||||
|
|
||||||
r = rdtsc();
|
|
||||||
for(t = r + m->cpumhz*1000ull*millisecs; r < t; r = rdtsc())
|
|
||||||
pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
isdmaok(void *a, usize len, int range)
|
|
||||||
{
|
|
||||||
uintmem pa;
|
|
||||||
|
|
||||||
if(!iskaddr(a) || (char*)a < etext)
|
|
||||||
return 0;
|
|
||||||
pa = mmuphysaddr(PTR2UINT(a));
|
|
||||||
if(pa == 0 || pa == ~(uintmem)0)
|
|
||||||
return 0;
|
|
||||||
return range > 32 || pa+len <= 0xFFFFFFFFULL;
|
|
||||||
}
|
|
|
@ -0,0 +1,429 @@
|
||||||
|
#include "u.h"
|
||||||
|
#include "../port/lib.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
#include "mp.h"
|
||||||
|
|
||||||
|
static PCMP *pcmp;
|
||||||
|
|
||||||
|
static char* buses[] = {
|
||||||
|
"CBUSI ",
|
||||||
|
"CBUSII",
|
||||||
|
"EISA ",
|
||||||
|
"FUTURE",
|
||||||
|
"INTERN",
|
||||||
|
"ISA ",
|
||||||
|
"MBI ",
|
||||||
|
"MBII ",
|
||||||
|
"MCA ",
|
||||||
|
"MPI ",
|
||||||
|
"MPSA ",
|
||||||
|
"NUBUS ",
|
||||||
|
"PCI ",
|
||||||
|
"PCMCIA",
|
||||||
|
"TC ",
|
||||||
|
"VL ",
|
||||||
|
"VME ",
|
||||||
|
"XPRESS",
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static Bus*
|
||||||
|
mpgetbus(int busno)
|
||||||
|
{
|
||||||
|
Bus *bus;
|
||||||
|
|
||||||
|
for(bus = mpbus; bus; bus = bus->next)
|
||||||
|
if(bus->busno == busno)
|
||||||
|
return bus;
|
||||||
|
|
||||||
|
print("mpgetbus: can't find bus %d\n", busno);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Apic*
|
||||||
|
mkprocessor(PCMPprocessor* p)
|
||||||
|
{
|
||||||
|
static int machno = 1;
|
||||||
|
int apicno;
|
||||||
|
Apic *apic;
|
||||||
|
|
||||||
|
apicno = p->apicno;
|
||||||
|
if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpapic[apicno] != nil)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if((apic = xalloc(sizeof(Apic))) == nil)
|
||||||
|
panic("mkprocessor: no memory for Apic");
|
||||||
|
apic->type = PcmpPROCESSOR;
|
||||||
|
apic->apicno = apicno;
|
||||||
|
apic->flags = p->flags;
|
||||||
|
apic->lintr[0] = ApicIMASK;
|
||||||
|
apic->lintr[1] = ApicIMASK;
|
||||||
|
if(p->flags & PcmpBP)
|
||||||
|
apic->machno = 0;
|
||||||
|
else
|
||||||
|
apic->machno = machno++;
|
||||||
|
mpapic[apicno] = apic;
|
||||||
|
|
||||||
|
return apic;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bus*
|
||||||
|
mkbus(PCMPbus* p)
|
||||||
|
{
|
||||||
|
Bus *bus;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; buses[i]; i++)
|
||||||
|
if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
|
||||||
|
break;
|
||||||
|
if(buses[i] == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if((bus = xalloc(sizeof(Bus))) == nil)
|
||||||
|
panic("mkbus: no memory for Bus");
|
||||||
|
if(mpbus)
|
||||||
|
mpbuslast->next = bus;
|
||||||
|
else
|
||||||
|
mpbus = bus;
|
||||||
|
mpbuslast = bus;
|
||||||
|
|
||||||
|
bus->type = i;
|
||||||
|
bus->busno = p->busno;
|
||||||
|
if(bus->type == BusEISA){
|
||||||
|
bus->po = PcmpLOW;
|
||||||
|
bus->el = PcmpLEVEL;
|
||||||
|
if(mpeisabus != -1)
|
||||||
|
print("mkbus: more than one EISA bus\n");
|
||||||
|
mpeisabus = bus->busno;
|
||||||
|
}
|
||||||
|
else if(bus->type == BusPCI){
|
||||||
|
bus->po = PcmpLOW;
|
||||||
|
bus->el = PcmpLEVEL;
|
||||||
|
}
|
||||||
|
else if(bus->type == BusISA){
|
||||||
|
bus->po = PcmpHIGH;
|
||||||
|
bus->el = PcmpEDGE;
|
||||||
|
if(mpisabus != -1)
|
||||||
|
print("mkbus: more than one ISA bus\n");
|
||||||
|
mpisabus = bus->busno;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
bus->po = PcmpHIGH;
|
||||||
|
bus->el = PcmpEDGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Apic*
|
||||||
|
mkioapic(PCMPioapic* p)
|
||||||
|
{
|
||||||
|
void *va;
|
||||||
|
int apicno;
|
||||||
|
Apic *apic;
|
||||||
|
|
||||||
|
apicno = p->apicno;
|
||||||
|
if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpioapic[apicno] != nil)
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* Map the I/O APIC.
|
||||||
|
*/
|
||||||
|
if((va = vmap(p->addr, 1024)) == nil)
|
||||||
|
return 0;
|
||||||
|
if((apic = xalloc(sizeof(Apic))) == nil)
|
||||||
|
panic("mkioapic: no memory for Apic");
|
||||||
|
apic->type = PcmpIOAPIC;
|
||||||
|
apic->apicno = apicno;
|
||||||
|
apic->addr = va;
|
||||||
|
apic->paddr = p->addr;
|
||||||
|
apic->flags = p->flags;
|
||||||
|
mpioapic[apicno] = apic;
|
||||||
|
|
||||||
|
return apic;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Aintr*
|
||||||
|
mkiointr(PCMPintr* p)
|
||||||
|
{
|
||||||
|
Bus *bus;
|
||||||
|
Aintr *aintr;
|
||||||
|
PCMPintr* pcmpintr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* According to the MultiProcessor Specification, a destination
|
||||||
|
* I/O APIC of 0xFF means the signal is routed to all I/O APICs.
|
||||||
|
* It's unclear how that can possibly be correct so treat it as
|
||||||
|
* an error for now.
|
||||||
|
*/
|
||||||
|
if(p->apicno > MaxAPICNO || mpioapic[p->apicno] == nil)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if((bus = mpgetbus(p->busno)) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if((aintr = xalloc(sizeof(Aintr))) == nil)
|
||||||
|
panic("mkiointr: no memory for Aintr");
|
||||||
|
aintr->intr = p;
|
||||||
|
|
||||||
|
if(0)
|
||||||
|
print("mkiointr: type %d intr type %d flags %#o "
|
||||||
|
"bus %d irq %d apicno %d intin %d\n",
|
||||||
|
p->type, p->intr, p->flags,
|
||||||
|
p->busno, p->irq, p->apicno, p->intin);
|
||||||
|
/*
|
||||||
|
* Hack for Intel SR1520ML motherboard, which BIOS describes
|
||||||
|
* the i82575 dual ethernet controllers incorrectly.
|
||||||
|
*/
|
||||||
|
if(memcmp(pcmp->product, "INTEL X38MLST ", 20) == 0){
|
||||||
|
if(p->busno == 1 && p->intin == 16 && p->irq == 1){
|
||||||
|
if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
|
||||||
|
panic("iointr: no memory for PCMPintr");
|
||||||
|
memmove(pcmpintr, p, sizeof(PCMPintr));
|
||||||
|
print("mkiointr: %20.20s bus %d intin %d irq %d\n",
|
||||||
|
(char*)pcmp->product,
|
||||||
|
pcmpintr->busno, pcmpintr->intin,
|
||||||
|
pcmpintr->irq);
|
||||||
|
pcmpintr->intin = 17;
|
||||||
|
aintr->intr = pcmpintr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aintr->apic = mpioapic[p->apicno];
|
||||||
|
aintr->next = bus->aintr;
|
||||||
|
bus->aintr = aintr;
|
||||||
|
|
||||||
|
return aintr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mklintr(PCMPintr* p)
|
||||||
|
{
|
||||||
|
Apic *apic;
|
||||||
|
Bus *bus;
|
||||||
|
int i, intin, v;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The offsets of vectors for LINT[01] are known to be
|
||||||
|
* 0 and 1 from the local APIC vector space at VectorLAPIC.
|
||||||
|
*/
|
||||||
|
if((bus = mpgetbus(p->busno)) == 0)
|
||||||
|
return 0;
|
||||||
|
intin = p->intin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pentium Pros have problems if LINT[01] are set to ExtINT
|
||||||
|
* so just bag it, SMP mode shouldn't need ExtINT anyway.
|
||||||
|
*/
|
||||||
|
if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
|
||||||
|
v = ApicIMASK;
|
||||||
|
else
|
||||||
|
v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
|
||||||
|
|
||||||
|
if(p->apicno == 0xFF){
|
||||||
|
for(i=0; i<=MaxAPICNO; i++){
|
||||||
|
if((apic = mpapic[i]) == nil)
|
||||||
|
continue;
|
||||||
|
if(apic->flags & PcmpEN)
|
||||||
|
apic->lintr[intin] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(apic = mpapic[p->apicno])
|
||||||
|
if(apic->flags & PcmpEN)
|
||||||
|
apic->lintr[intin] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dumpmp(uint8_t *p, uint8_t *e)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; p < e; p++) {
|
||||||
|
if((i % 16) == 0) print("*mp%d=", i/16);
|
||||||
|
print("%.2x ", *p);
|
||||||
|
if((++i % 16) == 0) print("\n");
|
||||||
|
}
|
||||||
|
if((i % 16) != 0) print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
mpoverride(uint8_t** newp, uint8_t** e)
|
||||||
|
{
|
||||||
|
int size, i, j;
|
||||||
|
char buf[20];
|
||||||
|
uint8_t* p;
|
||||||
|
char* s;
|
||||||
|
|
||||||
|
size = strtol(getconf("*mp"), 0, 0);
|
||||||
|
if(size <= 0) panic("mpoverride: invalid size in *mp");
|
||||||
|
*newp = p = xalloc(size);
|
||||||
|
if(p == nil) panic("mpoverride: can't allocate memory");
|
||||||
|
*e = p + size;
|
||||||
|
for(i = 0; ; i++){
|
||||||
|
snprint(buf, sizeof buf, "*mp%d", i);
|
||||||
|
s = getconf(buf);
|
||||||
|
if(s == nil) break;
|
||||||
|
while(*s){
|
||||||
|
j = strtol(s, &s, 16);
|
||||||
|
if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
|
||||||
|
if(p >= *e) panic("mpoverride: overflow in %s", buf);
|
||||||
|
*p++ = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(p != *e) panic("mpoverride: size doesn't match");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pcmpinit(void)
|
||||||
|
{
|
||||||
|
uint8_t *p, *e;
|
||||||
|
Apic *apic;
|
||||||
|
void *va;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map the local APIC.
|
||||||
|
*/
|
||||||
|
va = vmap(pcmp->lapicbase, 1024);
|
||||||
|
|
||||||
|
print("LAPIC: %.8lux %#p\n", pcmp->lapicbase, va);
|
||||||
|
if(va == nil)
|
||||||
|
panic("pcmpinit: cannot map lapic %.8lux", pcmp->lapicbase);
|
||||||
|
|
||||||
|
p = ((uint8_t*)pcmp)+PCMPsz;
|
||||||
|
e = ((uint8_t*)pcmp)+pcmp->length;
|
||||||
|
if(getconf("*dumpmp") != nil)
|
||||||
|
dumpmp(p, e);
|
||||||
|
if(getconf("*mp") != nil)
|
||||||
|
mpoverride(&p, &e);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run through the table saving information needed for starting
|
||||||
|
* application processors and initialising any I/O APICs. The table
|
||||||
|
* is guaranteed to be in order such that only one pass is necessary.
|
||||||
|
*/
|
||||||
|
while(p < e) switch(*p){
|
||||||
|
default:
|
||||||
|
print("pcmpinit: unknown PCMP type 0x%uX (e-p 0x%zuX)\n",
|
||||||
|
*p, e-p);
|
||||||
|
while(p < e){
|
||||||
|
print("%uX ", *p);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PcmpPROCESSOR:
|
||||||
|
if(apic = mkprocessor((PCMPprocessor*)p)){
|
||||||
|
apic->addr = va;
|
||||||
|
apic->paddr = pcmp->lapicbase;
|
||||||
|
}
|
||||||
|
p += PCMPprocessorsz;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case PcmpBUS:
|
||||||
|
mkbus((PCMPbus*)p);
|
||||||
|
p += PCMPbussz;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case PcmpIOAPIC:
|
||||||
|
if(apic = mkioapic((PCMPioapic*)p))
|
||||||
|
ioapicinit(apic, apic->apicno);
|
||||||
|
p += PCMPioapicsz;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case PcmpIOINTR:
|
||||||
|
mkiointr((PCMPintr*)p);
|
||||||
|
p += PCMPintrsz;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case PcmpLINTR:
|
||||||
|
mklintr((PCMPintr*)p);
|
||||||
|
p += PCMPintrsz;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ininitalize local APIC and start application processors.
|
||||||
|
*/
|
||||||
|
mpinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mpreset(void)
|
||||||
|
{
|
||||||
|
/* stop application processors */
|
||||||
|
mpshutdown();
|
||||||
|
|
||||||
|
/* do generic reset */
|
||||||
|
archreset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int identify(void);
|
||||||
|
|
||||||
|
PCArch archmp = {
|
||||||
|
.id= "_MP_",
|
||||||
|
.ident= identify,
|
||||||
|
.reset= mpreset,
|
||||||
|
.intrinit= pcmpinit,
|
||||||
|
.intrenable= mpintrenable,
|
||||||
|
.intron= lapicintron,
|
||||||
|
.introff= lapicintroff,
|
||||||
|
.fastclock= i8253read,
|
||||||
|
.timerset= lapictimerset,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
identify(void)
|
||||||
|
{
|
||||||
|
char *cp;
|
||||||
|
_MP_ *_mp_;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search for an MP configuration table. For now,
|
||||||
|
* don't accept the default configurations (physaddr == 0).
|
||||||
|
* Check for correct signature, calculate the checksum and,
|
||||||
|
* if correct, check the version.
|
||||||
|
* To do: check extended table checksum.
|
||||||
|
*/
|
||||||
|
if((_mp_ = sigsearch("_MP_")) == nil || checksum(_mp_, _MP_sz) != 0 || _mp_->physaddr == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
len = PCMPsz;
|
||||||
|
if(_mp_->physaddr < MemMin)
|
||||||
|
pcmp = KADDR(_mp_->physaddr);
|
||||||
|
else if((pcmp = vmap(_mp_->physaddr, len)) == nil)
|
||||||
|
return 1;
|
||||||
|
if(pcmp->length < len
|
||||||
|
|| memcmp(pcmp, "PCMP", 4) != 0
|
||||||
|
|| (pcmp->version != 1 && pcmp->version != 4)){
|
||||||
|
Bad:
|
||||||
|
if((uintptr)pcmp < KZERO)
|
||||||
|
vunmap(pcmp, len);
|
||||||
|
pcmp = nil;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
len = pcmp->length;
|
||||||
|
if((uintptr)pcmp < KZERO)
|
||||||
|
vunmap(pcmp, PCMPsz);
|
||||||
|
if(_mp_->physaddr < MemMin)
|
||||||
|
pcmp = KADDR(_mp_->physaddr);
|
||||||
|
else if((pcmp = vmap(_mp_->physaddr, len)) == nil)
|
||||||
|
return 1;
|
||||||
|
if(checksum(pcmp, len) != 0)
|
||||||
|
goto Bad;
|
||||||
|
|
||||||
|
if(m->havetsc && getconf("*notsc") == nil)
|
||||||
|
archmp.fastclock = tscticks;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -6,7 +6,6 @@
|
||||||
"Include": [
|
"Include": [
|
||||||
"core.json",
|
"core.json",
|
||||||
"devdraw.json",
|
"devdraw.json",
|
||||||
"../386/include.json",
|
|
||||||
"../ip/include.json",
|
"../ip/include.json",
|
||||||
"../port/include.json"
|
"../port/include.json"
|
||||||
],
|
],
|
||||||
|
@ -18,7 +17,6 @@
|
||||||
"int printallsyscalls;"
|
"int printallsyscalls;"
|
||||||
],
|
],
|
||||||
"Dev": [
|
"Dev": [
|
||||||
"acpi",
|
|
||||||
"arch",
|
"arch",
|
||||||
"bridge",
|
"bridge",
|
||||||
"cap",
|
"cap",
|
||||||
|
@ -29,6 +27,7 @@
|
||||||
"ether",
|
"ether",
|
||||||
"ip",
|
"ip",
|
||||||
"kprof",
|
"kprof",
|
||||||
|
"kbd",
|
||||||
"ninep",
|
"ninep",
|
||||||
"pci",
|
"pci",
|
||||||
"pipe",
|
"pipe",
|
||||||
|
@ -87,7 +86,6 @@
|
||||||
"autogenerated.c",
|
"autogenerated.c",
|
||||||
"sdata.c",
|
"sdata.c",
|
||||||
"cga.c",
|
"cga.c",
|
||||||
"devacpi.c",
|
|
||||||
"usbehcipc.c",
|
"usbehcipc.c",
|
||||||
"usbohci.c",
|
"usbohci.c",
|
||||||
"usbuhci.c"
|
"usbuhci.c"
|
||||||
|
|
|
@ -179,7 +179,7 @@ cgaprinthex(uintptr_t x)
|
||||||
cgaputc('\n');
|
cgaputc('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
cgaconsputs(char* s, int n)
|
cgaconsputs(char* s, int n)
|
||||||
{
|
{
|
||||||
ilock(&cgalock);
|
ilock(&cgalock);
|
||||||
|
@ -235,7 +235,7 @@ cgawrite(Chan* c, void *vbuf, long len, int64_t off)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cgainit(void)
|
screen_init(void)
|
||||||
{
|
{
|
||||||
ilock(&cgalock);
|
ilock(&cgalock);
|
||||||
|
|
||||||
|
@ -245,5 +245,6 @@ cgainit(void)
|
||||||
cgablinkoff();
|
cgablinkoff();
|
||||||
cgainitdone = 1;
|
cgainitdone = 1;
|
||||||
iunlock(&cgalock);
|
iunlock(&cgalock);
|
||||||
|
screenputs = cgaconsputs;
|
||||||
addarchfile("cgamem", 0666, cgaread, cgawrite);
|
addarchfile("cgamem", 0666, cgaread, cgawrite);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,24 @@
|
||||||
"inith.json"
|
"inith.json"
|
||||||
],
|
],
|
||||||
"SourceFiles": [
|
"SourceFiles": [
|
||||||
|
"bios32.c",
|
||||||
|
"devether.c",
|
||||||
|
"devrtc.c",
|
||||||
|
"devkbd.c",
|
||||||
|
"ether8139.c",
|
||||||
|
"ether8169.c",
|
||||||
|
"ether82557.c",
|
||||||
|
"ether82563.c",
|
||||||
|
"etherigbe.c",
|
||||||
|
"ethermii.c",
|
||||||
|
"etherm10g.c",
|
||||||
|
"pci.c",
|
||||||
|
"sdiahci.c",
|
||||||
|
"sdscsi.c",
|
||||||
|
"uarti8250.c",
|
||||||
|
"uartpci.c",
|
||||||
"entry.S",
|
"entry.S",
|
||||||
|
"ec.c",
|
||||||
"l64v.S",
|
"l64v.S",
|
||||||
"l64fpu.S",
|
"l64fpu.S",
|
||||||
"cpuidamd64.S",
|
"cpuidamd64.S",
|
||||||
|
@ -70,26 +87,24 @@
|
||||||
"l64vsyscall.S",
|
"l64vsyscall.S",
|
||||||
"acpi.c",
|
"acpi.c",
|
||||||
"arch.c",
|
"arch.c",
|
||||||
"archamd64.c",
|
"archmp.c",
|
||||||
"devarch.c",
|
"devarch.c",
|
||||||
"fpu.c",
|
"fpu.c",
|
||||||
"hpet.c",
|
"hpet.c",
|
||||||
"i8254.c",
|
"i8253.c",
|
||||||
"i8259.c",
|
"i8259.c",
|
||||||
"ioapic.c",
|
|
||||||
"lapic.c",
|
"lapic.c",
|
||||||
"main.c",
|
"main.c",
|
||||||
"map.c",
|
|
||||||
"memory.c",
|
"memory.c",
|
||||||
"mmu.c",
|
"mmu.c",
|
||||||
"mp.c",
|
"mp.c",
|
||||||
"msi.c",
|
"msi.c",
|
||||||
|
"mtrr.c",
|
||||||
"multiboot.c",
|
"multiboot.c",
|
||||||
"sipi.c",
|
"squidboy.c",
|
||||||
"syscall.c",
|
"syscall.c",
|
||||||
"systab.c",
|
"systab.c",
|
||||||
"trap.c",
|
"trap.c"
|
||||||
"vsvm.c"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,22 +6,15 @@ cpuid:
|
||||||
pushq %rbx
|
pushq %rbx
|
||||||
pushq %rcx
|
pushq %rcx
|
||||||
pushq %rdx
|
pushq %rdx
|
||||||
movq %rdi, %rax
|
movl %edi, %eax
|
||||||
movq %rsi, %rcx
|
cpuid
|
||||||
pushq %r15
|
movl %eax, 0(%rsi)
|
||||||
movq %rdx, %r15
|
movl %ebx, 4(%rsi)
|
||||||
|
movl %ecx, 8(%rsi)
|
||||||
cpuid /* Argument in %rax */
|
movl %edx, 12(%rsi)
|
||||||
|
|
||||||
// Plan 9 just moves them as a,b,c,d. Weird.
|
|
||||||
movl %eax, 0(%r15)
|
|
||||||
movl %ebx, 4(%r15)
|
|
||||||
movl %ecx, 8(%r15)
|
|
||||||
movl %edx, 12(%r15)
|
|
||||||
popq %r15
|
|
||||||
popq %rdx
|
popq %rdx
|
||||||
popq %rcx
|
popq %rcx
|
||||||
pop %rbx
|
popq %rbx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,11 +8,11 @@ fi
|
||||||
|
|
||||||
cd $JEHANNE/sys/src/kern/amd64
|
cd $JEHANNE/sys/src/kern/amd64
|
||||||
|
|
||||||
gcc -c -O0 -static -fplan9-extensions -mno-red-zone -ffreestanding -fno-builtin -mcmodel=kernel l64sipi.S
|
x86_64-jehanne-gcc -c -O0 -static -fplan9-extensions -mno-red-zone -ffreestanding -fno-builtin -mcmodel=kernel l64sipi.S
|
||||||
ld -Ttext 0x00003000 -e 0x00003000 l64sipi.o -o l64sipi
|
x86_64-jehanne-ld -Ttext 0x00003000 -e 0x00003000 l64sipi.o -o l64sipi
|
||||||
objcopy -O binary -j .text l64sipi l64sipi.out
|
x86_64-jehanne-objcopy -O binary -j .text l64sipi l64sipi.out
|
||||||
|
|
||||||
echo 'uint8_t sipihandler[]={' > sipi.h
|
echo 'uint8_t sipihandler[]={' > sipi.h
|
||||||
cat l64sipi.out | hexdump -v -e '7/1 "0x%02x, " 1/1 " 0x%02x,\n"' | sed '$s/0x ,/0x00,/g'>> sipi.h
|
cat l64sipi.out | hexdump -v -e '7/1 "0x%02x, " 1/1 " 0x%02x,\n"' | sed '$s/0x ,/0x00,/g'>> sipi.h
|
||||||
echo '};' >> sipi.h
|
echo '};' >> sipi.h
|
||||||
rm l64sipi.out
|
#rm l64sipi.out
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of Jehanne.
|
* This file is part of Jehanne.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2016 Giacomo Tesio <giacomo@tesio.it>
|
* Copyright (C) 2015-2017 Giacomo Tesio <giacomo@tesio.it>
|
||||||
*
|
*
|
||||||
* Jehanne is free software: you can redistribute it and/or modify
|
* Jehanne is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
typedef struct BIOS32si BIOS32si;
|
typedef struct BIOS32si BIOS32si;
|
||||||
typedef struct BIOS32ci BIOS32ci;
|
typedef struct BIOS32ci BIOS32ci;
|
||||||
|
typedef struct Confmem Confmem;
|
||||||
typedef struct Fxsave Fxsave;
|
typedef struct Fxsave Fxsave;
|
||||||
typedef struct IOConf IOConf;
|
typedef struct IOConf IOConf;
|
||||||
typedef struct ISAConf ISAConf;
|
typedef struct ISAConf ISAConf;
|
||||||
|
@ -25,27 +26,35 @@ typedef struct Lock Lock;
|
||||||
typedef struct LockEntry LockEntry;
|
typedef struct LockEntry LockEntry;
|
||||||
typedef struct MCPU MCPU;
|
typedef struct MCPU MCPU;
|
||||||
typedef struct MFPU MFPU;
|
typedef struct MFPU MFPU;
|
||||||
|
typedef struct MMU MMU;
|
||||||
typedef struct MMMU MMMU;
|
typedef struct MMMU MMMU;
|
||||||
typedef struct Mach Mach;
|
typedef struct Mach Mach;
|
||||||
typedef uint64_t Mpl;
|
typedef uint64_t Mpl;
|
||||||
typedef Mpl Mreg; /* GAK */
|
typedef Mpl Mreg; /* GAK */
|
||||||
typedef struct Ptpage Ptpage;
|
typedef struct Segdesc Segdesc;
|
||||||
typedef struct Pcidev Pcidev;
|
typedef struct Pcidev Pcidev;
|
||||||
typedef struct PFPU PFPU;
|
typedef struct PFPU PFPU;
|
||||||
typedef struct PMMU PMMU;
|
typedef struct PMMU PMMU;
|
||||||
typedef struct PNOTIFY PNOTIFY;
|
typedef struct PNOTIFY PNOTIFY;
|
||||||
typedef struct PPAGE PPAGE;
|
typedef struct PPAGE PPAGE;
|
||||||
typedef uint64_t PTE;
|
typedef uint64_t PTE;
|
||||||
|
typedef struct RMap RMap;
|
||||||
typedef struct Proc Proc;
|
typedef struct Proc Proc;
|
||||||
typedef struct Sys Sys;
|
typedef struct Sys Sys;
|
||||||
typedef uint64_t uintmem; /* horrible name */
|
typedef uint64_t uintmem; /* horrible name */
|
||||||
|
typedef long Tval;
|
||||||
typedef struct Ureg Ureg;
|
typedef struct Ureg Ureg;
|
||||||
typedef struct Vctl Vctl;
|
typedef struct Vctl Vctl;
|
||||||
|
typedef struct PCArch PCArch;
|
||||||
|
typedef union FPsave FPsave;
|
||||||
|
typedef struct Fxsave Fxsave;
|
||||||
|
typedef struct FPstate FPstate;
|
||||||
|
typedef struct PCMmap PCMmap;
|
||||||
|
|
||||||
#pragma incomplete BIOS32si
|
#pragma incomplete BIOS32si
|
||||||
#pragma incomplete Ureg
|
#pragma incomplete Ureg
|
||||||
|
|
||||||
#define MAXSYSARG 5 /* for mount(fd, afd, mpt, flag, arg) */
|
#define MAXSYSARG 6 /* for mount(fd, afd, mpt, flag, arg, dc) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parameters for sysproc.c
|
* parameters for sysproc.c
|
||||||
|
@ -58,10 +67,16 @@ typedef struct Vctl Vctl;
|
||||||
*/
|
*/
|
||||||
struct Lock
|
struct Lock
|
||||||
{
|
{
|
||||||
LockEntry* head;
|
uint64_t sr;
|
||||||
LockEntry* e;
|
uintptr_t pc;
|
||||||
|
Proc *lp;
|
||||||
|
Mach *lm;
|
||||||
|
uint32_t key;
|
||||||
|
uint16_t isilock;
|
||||||
|
long lockcycles;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Label
|
struct Label
|
||||||
{
|
{
|
||||||
uintptr_t sp;
|
uintptr_t sp;
|
||||||
|
@ -69,6 +84,24 @@ struct Label
|
||||||
uintptr_t regs[14];
|
uintptr_t regs[14];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FPsave.status
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/* this is a state */
|
||||||
|
FPinit= 0,
|
||||||
|
FPactive= 1,
|
||||||
|
FPinactive= 2,
|
||||||
|
|
||||||
|
/* the following is a bit that can be or'd into the state */
|
||||||
|
FPillegal= 0x100,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the FP regs must be stored here, not somewhere pointed to from here.
|
||||||
|
* port code assumes this.
|
||||||
|
*/
|
||||||
struct Fxsave {
|
struct Fxsave {
|
||||||
uint16_t fcw; /* x87 control word */
|
uint16_t fcw; /* x87 control word */
|
||||||
uint16_t fsw; /* x87 status word */
|
uint16_t fsw; /* x87 status word */
|
||||||
|
@ -84,40 +117,41 @@ struct Fxsave {
|
||||||
uint8_t ign[96]; /* reserved, ignored */
|
uint8_t ign[96]; /* reserved, ignored */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
union FPsave {
|
||||||
* FPU stuff in Proc
|
uint8_t align[512+15];
|
||||||
*/
|
Fxsave;
|
||||||
struct PFPU {
|
|
||||||
int fpustate;
|
|
||||||
uint8_t fxsave[sizeof(Fxsave)+15];
|
|
||||||
void* fpusave;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Ptpage
|
struct Segdesc
|
||||||
{
|
{
|
||||||
PTE* pte; /* kernel-addressible page table entries */
|
uint32_t d0;
|
||||||
uintmem pa; /* physical address (from physalloc) */
|
uint32_t d1;
|
||||||
Ptpage* next; /* next in level's set, or free list */
|
};
|
||||||
Ptpage* parent; /* parent page table page or page directory */
|
|
||||||
uint32_t ptoff; /* index of this table's entry in parent */
|
/*
|
||||||
|
* MMU structure for PDP, PD, PT pages.
|
||||||
|
*/
|
||||||
|
struct MMU
|
||||||
|
{
|
||||||
|
MMU* next;
|
||||||
|
uintptr_t* page;
|
||||||
|
int index;
|
||||||
|
int level;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MMU stuff in Proc
|
* MMU stuff in Proc
|
||||||
*/
|
*/
|
||||||
|
#define NCOLOR 1
|
||||||
struct PMMU
|
struct PMMU
|
||||||
{
|
{
|
||||||
Ptpage* mmuptp[4]; /* page table pages for each level */
|
MMU* mmuhead;
|
||||||
Ptpage* ptpfree;
|
MMU* mmutail;
|
||||||
int nptpbusy;
|
MMU* kmaphead;
|
||||||
};
|
MMU* kmaptail;
|
||||||
|
unsigned long kmapcount;
|
||||||
/*
|
unsigned long kmapindex;
|
||||||
* MMU stuff in Page
|
unsigned long mmucount;
|
||||||
*/
|
|
||||||
struct PPAGE
|
|
||||||
{
|
|
||||||
uint8_t* nothing;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -138,8 +172,6 @@ struct IOConf
|
||||||
};
|
};
|
||||||
extern IOConf ioconf;
|
extern IOConf ioconf;
|
||||||
|
|
||||||
#define MAXMDOM 8 /* maximum memory/cpu domains */
|
|
||||||
|
|
||||||
#include "../port/portdat.h"
|
#include "../port/portdat.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -164,24 +196,26 @@ struct MFPU {
|
||||||
/*
|
/*
|
||||||
* MMU stuff in Mach.
|
* MMU stuff in Mach.
|
||||||
*/
|
*/
|
||||||
enum
|
typedef struct {
|
||||||
{
|
uint32_t _0_;
|
||||||
NPGSZ = 4
|
uint32_t rsp0[2];
|
||||||
};
|
uint32_t rsp1[2];
|
||||||
|
uint32_t rsp2[2];
|
||||||
|
uint32_t _28_[2];
|
||||||
|
uint32_t ist[14];
|
||||||
|
uint16_t _92_[5];
|
||||||
|
uint16_t iomap;
|
||||||
|
} Tss;
|
||||||
|
|
||||||
struct MMMU
|
struct MMMU
|
||||||
{
|
{
|
||||||
Ptpage* pml4; /* pml4 for this processor */
|
uint64_t* pml4; /* pml4 base for this processor (va) */
|
||||||
PTE* pmap; /* unused as of yet */
|
Tss* tss; /* tss for this processor */
|
||||||
Ptpage* ptpfree; /* per-mach free list */
|
Segdesc* gdt; /* gdt for this processor */
|
||||||
int nptpfree;
|
|
||||||
|
|
||||||
uint32_t pgszlg2[NPGSZ]; /* per Mach or per Sys? */
|
uint64_t mmumap[4]; /* bitmap of pml4 entries for zapping */
|
||||||
uintmem pgszmask[NPGSZ];
|
MMU* mmufree; /* freelist for MMU structures */
|
||||||
uint32_t pgsz[NPGSZ];
|
unsigned long mmucount; /* number of MMU structures in freelist */
|
||||||
int npgsz;
|
|
||||||
|
|
||||||
Ptpage pml4kludge;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -212,8 +246,6 @@ struct Mach
|
||||||
|
|
||||||
uintptr_t stack;
|
uintptr_t stack;
|
||||||
uint8_t* vsvm;
|
uint8_t* vsvm;
|
||||||
void* gdt;
|
|
||||||
void* tss;
|
|
||||||
|
|
||||||
uint64_t ticks; /* of the clock since boot time */
|
uint64_t ticks; /* of the clock since boot time */
|
||||||
Label sched; /* scheduler wakeup */
|
Label sched; /* scheduler wakeup */
|
||||||
|
@ -241,18 +273,36 @@ struct Mach
|
||||||
|
|
||||||
int lastintr;
|
int lastintr;
|
||||||
|
|
||||||
|
int loopconst;
|
||||||
|
|
||||||
Lock apictimerlock;
|
Lock apictimerlock;
|
||||||
uint64_t cyclefreq; /* Frequency of user readable cycle counter */
|
uint64_t cyclefreq; /* Frequency of user readable cycle counter */
|
||||||
int64_t cpuhz;
|
uint64_t cpuhz;
|
||||||
int cpumhz;
|
int cpumhz;
|
||||||
|
int cpuidax;
|
||||||
|
int cpuidcx;
|
||||||
|
int cpuiddx;
|
||||||
|
char cpuidid[16];
|
||||||
|
char* cpuidtype;
|
||||||
|
int havetsc;
|
||||||
|
int havepge;
|
||||||
|
uint64_t tscticks;
|
||||||
uint64_t rdtsc;
|
uint64_t rdtsc;
|
||||||
|
|
||||||
LockEntry locks[8];
|
// LockEntry locks[8];
|
||||||
|
|
||||||
MFPU FPU;
|
MFPU FPU;
|
||||||
MCPU;
|
MCPU;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Confmem
|
||||||
|
{
|
||||||
|
uintptr_t base;
|
||||||
|
unsigned long npage;
|
||||||
|
uintptr_t kbase;
|
||||||
|
uintptr_t klimit;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the low memory map, between 0x100000 and 0x110000.
|
* This is the low memory map, between 0x100000 and 0x110000.
|
||||||
* It is located there to allow fundamental datastructures to be
|
* It is located there to allow fundamental datastructures to be
|
||||||
|
@ -265,62 +315,102 @@ struct Mach
|
||||||
* Some of the elements must be aligned on page boundaries, hence
|
* Some of the elements must be aligned on page boundaries, hence
|
||||||
* the unions.
|
* the unions.
|
||||||
*/
|
*/
|
||||||
struct Sys {
|
struct Sys
|
||||||
uint8_t machstk[MACHSTKSZ];
|
{
|
||||||
|
Ureg* boot_regs;
|
||||||
|
unsigned int nmach; /* processors */
|
||||||
|
unsigned int nproc; /* processes */
|
||||||
|
unsigned int monitor; /* has monitor? */
|
||||||
|
unsigned int npages; /* total physical pages of memory */
|
||||||
|
unsigned int upages; /* user page pool */
|
||||||
|
unsigned int nimage; /* number of images */
|
||||||
|
Confmem mem[16]; /* physical memory */
|
||||||
|
|
||||||
PTE pml4[PTSZ/sizeof(PTE)]; /* */
|
unsigned int copymode; /* 0 is copy on write, 1 is copy on reference */
|
||||||
PTE pdp[PTSZ/sizeof(PTE)];
|
unsigned int ialloc; /* max interrupt time allocation in bytes */
|
||||||
PTE pd[PTSZ/sizeof(PTE)];
|
unsigned int pipeqsize; /* size in bytes of pipe queues */
|
||||||
PTE pt[PTSZ/sizeof(PTE)];
|
int nuart; /* number of uart devices */
|
||||||
|
|
||||||
uint8_t vsvmpage[4*KiB];
|
char* architecture;
|
||||||
|
uint64_t ticks;
|
||||||
|
Mach* machptr[MACHMAX];
|
||||||
|
|
||||||
union {
|
|
||||||
Mach mach;
|
|
||||||
uint8_t machpage[MACHSZ];
|
|
||||||
};
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint64_t pmstart; /* physical memory */
|
uint64_t pmstart; /* physical memory */
|
||||||
uint64_t pmoccupied; /* how much is occupied */
|
uint64_t pmoccupied; /* how much is occupied */
|
||||||
uint64_t pmunassigned; /* how much to keep back from page pool */
|
uint64_t pmunassigned; /* how much to keep back from page pool */
|
||||||
uint64_t pmpaged; /* how much assigned to page pool */
|
uint64_t pmpaged; /* how much assigned to page pool */
|
||||||
|
|
||||||
uintptr_t vmstart; /* base address for malloc */
|
|
||||||
uintptr_t vmunused; /* 1st unused va */
|
|
||||||
uintptr_t vmunmapped; /* 1st unmapped va in KSEG0 */
|
|
||||||
|
|
||||||
uint64_t epoch; /* crude time synchronisation */
|
|
||||||
int nmach; /* how many machs */
|
|
||||||
int nonline; /* how many machs are online */
|
|
||||||
uint64_t ticks; /* since boot (type?) */
|
|
||||||
uint32_t copymode; /* 0=copy on write; 1=copy on reference */
|
|
||||||
};
|
|
||||||
uint8_t syspage[4*KiB];
|
|
||||||
};
|
|
||||||
|
|
||||||
union {
|
|
||||||
Mach* machptr[MACHMAX];
|
|
||||||
uint8_t ptrpage[4*KiB];
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t _57344_[2][4*KiB]; /* unused */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Sys* sys;
|
extern Sys* sys;
|
||||||
|
extern uint32_t MemMin; /* set by entry.S */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* KMap
|
* KMap
|
||||||
*/
|
*/
|
||||||
typedef void KMap;
|
typedef void KMap;
|
||||||
|
|
||||||
#define kunmap(k)
|
|
||||||
#define VA(k) (void*)(k)
|
#define VA(k) (void*)(k)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* routines for things outside the PC model, like power management
|
||||||
|
*/
|
||||||
|
struct PCArch
|
||||||
|
{
|
||||||
|
char* id;
|
||||||
|
int (*ident)(void); /* this should be in the model */
|
||||||
|
void (*reset)(void); /* this should be in the model */
|
||||||
|
int (*serialpower)(int); /* 1 == on, 0 == off */
|
||||||
|
int (*modempower)(int); /* 1 == on, 0 == off */
|
||||||
|
|
||||||
|
void (*intrinit)(void);
|
||||||
|
int (*intrenable)(Vctl*);
|
||||||
|
int (*intrvecno)(int);
|
||||||
|
int (*intrdisable)(int);
|
||||||
|
void (*introff)(void);
|
||||||
|
void (*intron)(void);
|
||||||
|
|
||||||
|
void (*clockenable)(void);
|
||||||
|
uint64_t (*fastclock)(uint64_t*);
|
||||||
|
void (*timerset)(uint64_t);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PCArch *arch; /* PC architecture */
|
||||||
|
|
||||||
|
/* cpuid instruction result register bits */
|
||||||
|
enum {
|
||||||
|
/* cx */
|
||||||
|
Monitor = 1<<3,
|
||||||
|
|
||||||
|
/* dx */
|
||||||
|
Fpuonchip = 1<<0,
|
||||||
|
Vmex = 1<<1, /* virtual-mode extensions */
|
||||||
|
Pse = 1<<3, /* page size extensions */
|
||||||
|
Tsc = 1<<4, /* time-stamp counter */
|
||||||
|
Cpumsr = 1<<5, /* model-specific registers, rdmsr/wrmsr */
|
||||||
|
Pae = 1<<6, /* physical-addr extensions */
|
||||||
|
Mce = 1<<7, /* machine-check exception */
|
||||||
|
Cmpxchg8b = 1<<8,
|
||||||
|
Cpuapic = 1<<9,
|
||||||
|
Mtrr = 1<<12, /* memory-type range regs. */
|
||||||
|
Pge = 1<<13, /* page global extension */
|
||||||
|
Mca = 1<<14, /* machine-check architecture */
|
||||||
|
Pat = 1<<16, /* page attribute table */
|
||||||
|
Pse2 = 1<<17, /* more page size extensions */
|
||||||
|
Clflush = 1<<19,
|
||||||
|
Acpif = 1<<22, /* therm control msr */
|
||||||
|
Mmx = 1<<23,
|
||||||
|
Fxsr = 1<<24, /* have SSE FXSAVE/FXRSTOR */
|
||||||
|
Sse = 1<<25, /* thus sfence instr. */
|
||||||
|
Sse2 = 1<<26, /* thus mfence & lfence instr.s */
|
||||||
|
Rdrnd = 1<<30, /* RDRAND support bit */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Informations about active processors for
|
||||||
|
* bootstrap and shutdown.
|
||||||
|
*/
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
Lock;
|
char machs[MACHMAX]; /* bitmap of active CPUs */
|
||||||
int exiting; /* shutdown */
|
int exiting; /* shutdown */
|
||||||
int ispanic; /* shutdown in response to a panic */
|
int ispanic; /* shutdown in response to a panic */
|
||||||
int thunderbirdsarego; /* F.A.B. */
|
int thunderbirdsarego; /* F.A.B. */
|
||||||
|
@ -354,6 +444,8 @@ typedef struct BIOS32ci { /* BIOS32 Calling Interface */
|
||||||
uint32_t edi;
|
uint32_t edi;
|
||||||
} BIOS32ci;
|
} BIOS32ci;
|
||||||
|
|
||||||
|
#define MACHP(n) (sys->machptr[n])
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The Mach structures must be available via the per-processor
|
* The Mach structures must be available via the per-processor
|
||||||
* MMU information array machptr, mainly for disambiguation and access to
|
* MMU information array machptr, mainly for disambiguation and access to
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,7 +14,8 @@
|
||||||
"SourceFiles": [
|
"SourceFiles": [
|
||||||
"../port/devdraw.c",
|
"../port/devdraw.c",
|
||||||
"../port/devmouse.c",
|
"../port/devmouse.c",
|
||||||
"../386/vgavesa.c",
|
"../port/swcursor.c",
|
||||||
|
"vgavesa.c",
|
||||||
"screen.c",
|
"screen.c",
|
||||||
"devvga.c",
|
"devvga.c",
|
||||||
"mouse.c",
|
"mouse.c",
|
||||||
|
|
|
@ -503,8 +503,6 @@ ethershutdown(void)
|
||||||
ether = etherxx[i];
|
ether = etherxx[i];
|
||||||
if(ether == nil)
|
if(ether == nil)
|
||||||
continue;
|
continue;
|
||||||
if(ether->irq >= 0)
|
|
||||||
intrdisable(ether->vector);
|
|
||||||
if(ether->shutdown == nil) {
|
if(ether->shutdown == nil) {
|
||||||
jehanne_print("#l%d: no shutdown function\n", i);
|
jehanne_print("#l%d: no shutdown function\n", i);
|
||||||
continue;
|
continue;
|
|
@ -0,0 +1,447 @@
|
||||||
|
/*
|
||||||
|
* keyboard input
|
||||||
|
*/
|
||||||
|
#include "u.h"
|
||||||
|
#include "../port/lib.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "../port/error.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Data= 0x60, /* data port */
|
||||||
|
|
||||||
|
Status= 0x64, /* status port */
|
||||||
|
Inready= 0x01, /* input character ready */
|
||||||
|
Outbusy= 0x02, /* output busy */
|
||||||
|
Sysflag= 0x04, /* system flag */
|
||||||
|
Cmddata= 0x08, /* cmd==0, data==1 */
|
||||||
|
Inhibit= 0x10, /* keyboard/mouse inhibited */
|
||||||
|
Minready= 0x20, /* mouse character ready */
|
||||||
|
Rtimeout= 0x40, /* general timeout */
|
||||||
|
Parity= 0x80,
|
||||||
|
|
||||||
|
Cmd= 0x64, /* command port (write only) */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/* controller command byte */
|
||||||
|
Cscs1= (1<<6), /* scan code set 1 */
|
||||||
|
Cauxdis= (1<<5), /* mouse disable */
|
||||||
|
Ckbddis= (1<<4), /* kbd disable */
|
||||||
|
Csf= (1<<2), /* system flag */
|
||||||
|
Cauxint= (1<<1), /* mouse interrupt enable */
|
||||||
|
Ckbdint= (1<<0), /* kbd interrupt enable */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Qdir,
|
||||||
|
Qscancode,
|
||||||
|
Qleds,
|
||||||
|
};
|
||||||
|
|
||||||
|
static Dirtab kbdtab[] = {
|
||||||
|
".", {Qdir, 0, QTDIR}, 0, 0555,
|
||||||
|
"scancode", {Qscancode, 0}, 0, 0440,
|
||||||
|
"leds", {Qleds, 0}, 0, 0220,
|
||||||
|
};
|
||||||
|
|
||||||
|
static Lock i8042lock;
|
||||||
|
static uint8_t ccc;
|
||||||
|
static void (*auxputc)(int, int);
|
||||||
|
static int nokbd = 1; /* flag: no PS/2 keyboard */
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
Ref ref;
|
||||||
|
Queue *q;
|
||||||
|
} kbd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wait for output no longer busy
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
outready(void)
|
||||||
|
{
|
||||||
|
int tries;
|
||||||
|
|
||||||
|
for(tries = 0; (inb(Status) & Outbusy); tries++){
|
||||||
|
if(tries > 500)
|
||||||
|
return -1;
|
||||||
|
delay(2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wait for input
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
inready(void)
|
||||||
|
{
|
||||||
|
int tries;
|
||||||
|
|
||||||
|
for(tries = 0; !(inb(Status) & Inready); tries++){
|
||||||
|
if(tries > 500)
|
||||||
|
return -1;
|
||||||
|
delay(2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ask 8042 to reset the machine
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
i8042reset(void)
|
||||||
|
{
|
||||||
|
int i, x;
|
||||||
|
|
||||||
|
if(nokbd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*((uint16_t*)KADDR(0x472)) = 0x1234; /* BIOS warm-boot flag */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* newer reset the machine command
|
||||||
|
*/
|
||||||
|
outready();
|
||||||
|
outb(Cmd, 0xFE);
|
||||||
|
outready();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pulse it by hand (old somewhat reliable)
|
||||||
|
*/
|
||||||
|
x = 0xDF;
|
||||||
|
for(i = 0; i < 5; i++){
|
||||||
|
x ^= 1;
|
||||||
|
outready();
|
||||||
|
outb(Cmd, 0xD1);
|
||||||
|
outready();
|
||||||
|
outb(Data, x); /* toggle reset */
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
i8042auxcmd(int cmd)
|
||||||
|
{
|
||||||
|
unsigned int c;
|
||||||
|
int tries;
|
||||||
|
|
||||||
|
c = 0;
|
||||||
|
tries = 0;
|
||||||
|
|
||||||
|
ilock(&i8042lock);
|
||||||
|
do{
|
||||||
|
if(tries++ > 2)
|
||||||
|
break;
|
||||||
|
if(outready() < 0)
|
||||||
|
break;
|
||||||
|
outb(Cmd, 0xD4);
|
||||||
|
if(outready() < 0)
|
||||||
|
break;
|
||||||
|
outb(Data, cmd);
|
||||||
|
if(outready() < 0)
|
||||||
|
break;
|
||||||
|
if(inready() < 0)
|
||||||
|
break;
|
||||||
|
c = inb(Data);
|
||||||
|
} while(c == 0xFE || c == 0);
|
||||||
|
iunlock(&i8042lock);
|
||||||
|
|
||||||
|
if(c != 0xFA){
|
||||||
|
print("i8042: %2.2ux returned to the %2.2ux command (pc=%#p)\n",
|
||||||
|
c, cmd, getcallerpc());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set keyboard's leds for lock states (scroll, numeric, caps).
|
||||||
|
*
|
||||||
|
* at least one keyboard (from Qtronics) also sets its numeric-lock
|
||||||
|
* behaviour to match the led state, though it has no numeric keypad,
|
||||||
|
* and some BIOSes bring the system up with numeric-lock set and no
|
||||||
|
* setting to change that. this combination steals the keys for these
|
||||||
|
* characters and makes it impossible to generate them: uiolkjm&*().
|
||||||
|
* thus we'd like to be able to force the numeric-lock led (and behaviour) off.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
setleds(int leds)
|
||||||
|
{
|
||||||
|
static int old = -1;
|
||||||
|
|
||||||
|
if(nokbd || leds == old)
|
||||||
|
return;
|
||||||
|
leds &= 7;
|
||||||
|
ilock(&i8042lock);
|
||||||
|
for(;;){
|
||||||
|
if(outready() < 0)
|
||||||
|
break;
|
||||||
|
outb(Data, 0xed); /* `reset keyboard lock states' */
|
||||||
|
if(outready() < 0)
|
||||||
|
break;
|
||||||
|
outb(Data, leds);
|
||||||
|
if(outready() < 0)
|
||||||
|
break;
|
||||||
|
old = leds;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iunlock(&i8042lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* keyboard interrupt
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
i8042intr(Ureg* _, void* __)
|
||||||
|
{
|
||||||
|
int s, c;
|
||||||
|
uint8_t b;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get status
|
||||||
|
*/
|
||||||
|
ilock(&i8042lock);
|
||||||
|
s = inb(Status);
|
||||||
|
if(!(s&Inready)){
|
||||||
|
iunlock(&i8042lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get the character
|
||||||
|
*/
|
||||||
|
c = inb(Data);
|
||||||
|
iunlock(&i8042lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if it's the aux port...
|
||||||
|
*/
|
||||||
|
if(s & Minready){
|
||||||
|
if(auxputc != nil)
|
||||||
|
auxputc(c, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
b = c & 0xff;
|
||||||
|
qproduce(kbd.q, &b, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
i8042auxenable(void (*putc)(int, int))
|
||||||
|
{
|
||||||
|
static char err[] = "i8042: aux init failed\n";
|
||||||
|
|
||||||
|
ilock(&i8042lock);
|
||||||
|
|
||||||
|
/* enable kbd/aux xfers and interrupts */
|
||||||
|
ccc &= ~Cauxdis;
|
||||||
|
ccc |= Cauxint;
|
||||||
|
|
||||||
|
if(outready() < 0)
|
||||||
|
print(err);
|
||||||
|
outb(Cmd, 0x60); /* write control register */
|
||||||
|
if(outready() < 0)
|
||||||
|
print(err);
|
||||||
|
outb(Data, ccc);
|
||||||
|
if(outready() < 0)
|
||||||
|
print(err);
|
||||||
|
outb(Cmd, 0xA8); /* auxiliary device enable */
|
||||||
|
if(outready() < 0){
|
||||||
|
print(err);
|
||||||
|
iunlock(&i8042lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auxputc = putc;
|
||||||
|
intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
|
||||||
|
|
||||||
|
iunlock(&i8042lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
kbdpoll(void)
|
||||||
|
{
|
||||||
|
if(nokbd || qlen(kbd.q) > 0)
|
||||||
|
return;
|
||||||
|
i8042intr(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
kbdshutdown(void)
|
||||||
|
{
|
||||||
|
if(nokbd)
|
||||||
|
return;
|
||||||
|
/* disable kbd and aux xfers and interrupts */
|
||||||
|
ccc &= ~(Ckbdint|Cauxint);
|
||||||
|
ccc |= (Cauxdis|Ckbddis);
|
||||||
|
outready();
|
||||||
|
outb(Cmd, 0x60);
|
||||||
|
outready();
|
||||||
|
outb(Data, ccc);
|
||||||
|
outready();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Chan *
|
||||||
|
kbdattach(Chan *c, Chan *ac, char *spec, int flags)
|
||||||
|
{
|
||||||
|
return devattach(L'b', spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Walkqid*
|
||||||
|
kbdwalk(Chan *c, Chan *nc, char **name, int nname)
|
||||||
|
{
|
||||||
|
return devwalk(c, nc, name, nname, kbdtab, nelem(kbdtab), devgen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
kbdstat(Chan *c, uint8_t *dp, long n)
|
||||||
|
{
|
||||||
|
return devstat(c, dp, n, kbdtab, nelem(kbdtab), devgen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Chan*
|
||||||
|
kbdopen(Chan *c, unsigned long omode)
|
||||||
|
{
|
||||||
|
if(!iseve())
|
||||||
|
error(Eperm);
|
||||||
|
if(c->qid.path == Qscancode){
|
||||||
|
if(waserror()){
|
||||||
|
decref(&kbd.ref);
|
||||||
|
nexterror();
|
||||||
|
}
|
||||||
|
if(incref(&kbd.ref) != 1)
|
||||||
|
error(Einuse);
|
||||||
|
c = devopen(c, omode, kbdtab, nelem(kbdtab), devgen);
|
||||||
|
poperror();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return devopen(c, omode, kbdtab, nelem(kbdtab), devgen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
kbdclose(Chan *c)
|
||||||
|
{
|
||||||
|
if((c->flag & COPEN) && c->qid.path == Qscancode)
|
||||||
|
decref(&kbd.ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Block*
|
||||||
|
kbdbread(Chan *c, long n, int64_t off)
|
||||||
|
{
|
||||||
|
if(c->qid.path == Qscancode){
|
||||||
|
kbdpoll();
|
||||||
|
return qbread(kbd.q, n);
|
||||||
|
}
|
||||||
|
return devbread(c, n, off);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
kbdread(Chan *c, void *a, long n, int64_t _)
|
||||||
|
{
|
||||||
|
if(c->qid.path == Qscancode){
|
||||||
|
kbdpoll();
|
||||||
|
return qread(kbd.q, a, n);
|
||||||
|
}
|
||||||
|
if(c->qid.path == Qdir)
|
||||||
|
return devdirread(c, a, n, kbdtab, nelem(kbdtab), devgen);
|
||||||
|
error(Egreg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
kbdwrite(Chan *c, void *a, long n, int64_t _)
|
||||||
|
{
|
||||||
|
char tmp[8+1], *p;
|
||||||
|
|
||||||
|
if(c->qid.path != Qleds)
|
||||||
|
error(Egreg);
|
||||||
|
|
||||||
|
p = tmp + n;
|
||||||
|
if(n >= sizeof(tmp))
|
||||||
|
p = tmp + sizeof(tmp)-1;
|
||||||
|
memmove(tmp, a, p - tmp);
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
setleds(atoi(tmp));
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
kbdreset(void)
|
||||||
|
{
|
||||||
|
static char initfailed[] = "i8042: kbd init failed\n";
|
||||||
|
int c, try;
|
||||||
|
|
||||||
|
kbd.q = qopen(1024, Qcoalesce, 0, 0);
|
||||||
|
if(kbd.q == nil)
|
||||||
|
panic("kbdreset");
|
||||||
|
qnoblock(kbd.q, 1);
|
||||||
|
|
||||||
|
/* wait for a quiescent controller */
|
||||||
|
try = 1000;
|
||||||
|
while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
|
||||||
|
if(c & Inready)
|
||||||
|
inb(Data);
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
if (try <= 0) {
|
||||||
|
print(initfailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get current controller command byte */
|
||||||
|
outb(Cmd, 0x20);
|
||||||
|
if(inready() < 0){
|
||||||
|
print("i8042: can't read ccc\n");
|
||||||
|
ccc = 0;
|
||||||
|
} else
|
||||||
|
ccc = inb(Data);
|
||||||
|
|
||||||
|
/* enable kbd xfers and interrupts */
|
||||||
|
ccc &= ~Ckbddis;
|
||||||
|
ccc |= Csf | Ckbdint | Cscs1;
|
||||||
|
|
||||||
|
/* disable ps2 mouse */
|
||||||
|
ccc &= ~Cauxint;
|
||||||
|
ccc |= Cauxdis;
|
||||||
|
|
||||||
|
if(outready() < 0) {
|
||||||
|
print(initfailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
outb(Cmd, 0x60);
|
||||||
|
outready();
|
||||||
|
outb(Data, ccc);
|
||||||
|
outready();
|
||||||
|
|
||||||
|
nokbd = 0;
|
||||||
|
ioalloc(Cmd, 1, 0, "i8042.cs");
|
||||||
|
ioalloc(Data, 1, 0, "i8042.data");
|
||||||
|
intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
|
||||||
|
}
|
||||||
|
|
||||||
|
Dev kbddevtab = {
|
||||||
|
L'b',
|
||||||
|
"kbd",
|
||||||
|
|
||||||
|
kbdreset,
|
||||||
|
devinit,
|
||||||
|
kbdshutdown,
|
||||||
|
kbdattach,
|
||||||
|
kbdwalk,
|
||||||
|
kbdstat,
|
||||||
|
kbdopen,
|
||||||
|
devcreate,
|
||||||
|
kbdclose,
|
||||||
|
kbdread,
|
||||||
|
kbdbread,
|
||||||
|
kbdwrite,
|
||||||
|
devbwrite,
|
||||||
|
devremove,
|
||||||
|
devwstat,
|
||||||
|
};
|
|
@ -24,9 +24,6 @@
|
||||||
#include <cursor.h>
|
#include <cursor.h>
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
|
||||||
#define RMBUF ((void*)(KZERO + 0x9000)) // see 9/386/vgavesa.c
|
|
||||||
#define LORMBUF (0x9000)
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Qdir,
|
Qdir,
|
||||||
Qvgabios,
|
Qvgabios,
|
||||||
|
@ -45,8 +42,6 @@ static Dirtab vgadir[] = {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CMactualsize,
|
CMactualsize,
|
||||||
CMblank,
|
|
||||||
CMblanktime,
|
|
||||||
CMdrawinit,
|
CMdrawinit,
|
||||||
CMhwaccel,
|
CMhwaccel,
|
||||||
CMhwblank,
|
CMhwblank,
|
||||||
|
@ -57,13 +52,12 @@ enum {
|
||||||
CMsize,
|
CMsize,
|
||||||
CMtextmode,
|
CMtextmode,
|
||||||
CMtype,
|
CMtype,
|
||||||
CMunblank,
|
CMsoftscreen,
|
||||||
|
CMpcidev,
|
||||||
};
|
};
|
||||||
|
|
||||||
static Cmdtab vgactlmsg[] = {
|
static Cmdtab vgactlmsg[] = {
|
||||||
CMactualsize, "actualsize", 2,
|
CMactualsize, "actualsize", 2,
|
||||||
CMblank, "blank", 1,
|
|
||||||
CMblanktime, "blanktime", 2,
|
|
||||||
CMdrawinit, "drawinit", 1,
|
CMdrawinit, "drawinit", 1,
|
||||||
CMhwaccel, "hwaccel", 2,
|
CMhwaccel, "hwaccel", 2,
|
||||||
CMhwblank, "hwblank", 2,
|
CMhwblank, "hwblank", 2,
|
||||||
|
@ -74,66 +68,39 @@ static Cmdtab vgactlmsg[] = {
|
||||||
CMsize, "size", 3,
|
CMsize, "size", 3,
|
||||||
CMtextmode, "textmode", 1,
|
CMtextmode, "textmode", 1,
|
||||||
CMtype, "type", 2,
|
CMtype, "type", 2,
|
||||||
CMunblank, "unblank", 1,
|
CMsoftscreen, "softscreen", 2,
|
||||||
|
CMpcidev, "pcidev", 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static long
|
|
||||||
rmemrw(int isr, void *a, long n, int64_t off)
|
|
||||||
{
|
|
||||||
if(off < 0 || n < 0)
|
|
||||||
error("bad offset/count");
|
|
||||||
if(isr){
|
|
||||||
if(off >= MB)
|
|
||||||
return 0;
|
|
||||||
if(off+n >= MB)
|
|
||||||
n = MB - off;
|
|
||||||
jehanne_memmove(a, KADDR((uintptr_t)off), n);
|
|
||||||
}else{
|
|
||||||
/* realmode buf page ok, allow vga framebuf's access */
|
|
||||||
if(off >= MB)
|
|
||||||
error("Offset > MB");
|
|
||||||
if (off+n > MB)
|
|
||||||
error("off+n > MB");
|
|
||||||
if (off < LORMBUF)
|
|
||||||
error("off < LORMBUF");
|
|
||||||
if (off+n > LORMBUF+PGSZ)
|
|
||||||
error("off+n > LORMBUF+BY2PG");
|
|
||||||
if (off < 0xA0000)
|
|
||||||
error("off < 0xa0000");
|
|
||||||
if (off+n > 0xB0000+0x10000)
|
|
||||||
error("off+n > 0xb0000+0x10000");
|
|
||||||
jehanne_memmove(KADDR((uintptr_t)off), a, n);
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
rmemread(Chan*_, void *a, long n, int64_t off)
|
|
||||||
{
|
|
||||||
return rmemrw(1, a, n, off);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
rmemwrite(Chan*_, void *a, long n, int64_t off)
|
|
||||||
{
|
|
||||||
return rmemrw(0, a, n, off);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vgareset(void)
|
vgareset(void)
|
||||||
{
|
{
|
||||||
|
Pcidev *pci;
|
||||||
|
VGAscr *scr;
|
||||||
|
|
||||||
/* reserve the 'standard' vga registers */
|
/* reserve the 'standard' vga registers */
|
||||||
if(ioalloc(0x2b0, 0x2df-0x2b0+1, 0, "vga") < 0)
|
if(ioalloc(0x2b0, 0x2df-0x2b0+1, 0, "vga") < 0)
|
||||||
panic("vga ports already allocated");
|
panic("vga ports already allocated");
|
||||||
if(ioalloc(0x3c0, 0x3da-0x3c0+1, 0, "vga") < 0)
|
if(ioalloc(0x3c0, 0x3da-0x3c0+1, 0, "vga") < 0)
|
||||||
panic("vga ports already allocated");
|
panic("vga ports already allocated");
|
||||||
addarchfile("realmodemem", 0660, rmemread, rmemwrite);
|
|
||||||
|
/* find graphics card pci device */
|
||||||
|
scr = &vgascreen[0];
|
||||||
|
scr->pci = pci = nil;
|
||||||
|
while((pci = pcimatch(pci, 0, 0)) != nil){
|
||||||
|
if(pci->ccrb == Pcibcdisp){
|
||||||
|
scr->pci = pci;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sys->monitor = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Chan*
|
static Chan*
|
||||||
vgaattach(Chan *c, Chan *ac, char *spec, int flags)
|
vgaattach(Chan *c, Chan *ac, char *spec, int flags)
|
||||||
{
|
{
|
||||||
if(*spec && jehanne_strcmp(spec, "0"))
|
if(*spec && strcmp(spec, "0"))
|
||||||
error(Eio);
|
error(Eio);
|
||||||
return devattach('v', spec);
|
return devattach('v', spec);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +126,7 @@ vgaopen(Chan* c, unsigned long omode)
|
||||||
scr = &vgascreen[0];
|
scr = &vgascreen[0];
|
||||||
if ((uint32_t)c->qid.path == Qvgaovlctl) {
|
if ((uint32_t)c->qid.path == Qvgaovlctl) {
|
||||||
if (scr->dev && scr->dev->ovlctl)
|
if (scr->dev && scr->dev->ovlctl)
|
||||||
scr->dev->ovlctl(scr, c, openctl, jehanne_strlen(openctl));
|
scr->dev->ovlctl(scr, c, openctl, strlen(openctl));
|
||||||
else
|
else
|
||||||
error(Enonexist);
|
error(Enonexist);
|
||||||
}
|
}
|
||||||
|
@ -176,10 +143,10 @@ vgaclose(Chan* c)
|
||||||
if((uint32_t)c->qid.path == Qvgaovlctl)
|
if((uint32_t)c->qid.path == Qvgaovlctl)
|
||||||
if(scr->dev && scr->dev->ovlctl){
|
if(scr->dev && scr->dev->ovlctl){
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
jehanne_print("ovlctl error: %s\n", up->errstr);
|
print("ovlctl error: %s\n", up->errstr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scr->dev->ovlctl(scr, c, closectl, jehanne_strlen(closectl));
|
scr->dev->ovlctl(scr, c, closectl, strlen(closectl));
|
||||||
poperror();
|
poperror();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,8 +154,7 @@ vgaclose(Chan* c)
|
||||||
static long
|
static long
|
||||||
vgaread(Chan* c, void* a, long n, int64_t off)
|
vgaread(Chan* c, void* a, long n, int64_t off)
|
||||||
{
|
{
|
||||||
int len;
|
char *p, *s, *e;
|
||||||
char *p, *s;
|
|
||||||
VGAscr *scr;
|
VGAscr *scr;
|
||||||
uint32_t offset = off;
|
uint32_t offset = off;
|
||||||
char chbuf[30];
|
char chbuf[30];
|
||||||
|
@ -203,50 +169,41 @@ vgaread(Chan* c, void* a, long n, int64_t off)
|
||||||
return 0;
|
return 0;
|
||||||
if(offset+n >= 0x100000)
|
if(offset+n >= 0x100000)
|
||||||
n = 0x100000 - offset;
|
n = 0x100000 - offset;
|
||||||
jehanne_memmove(a, (unsigned char*)KADDR(0)+offset, n);
|
memmove(a, (uint8_t*)KADDR(0)+offset, n);
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
case Qvgactl:
|
case Qvgactl:
|
||||||
scr = &vgascreen[0];
|
scr = &vgascreen[0];
|
||||||
|
|
||||||
p = jehanne_malloc(READSTR);
|
s = smalloc(READSTR);
|
||||||
if(p == nil)
|
|
||||||
error(Enomem);
|
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
jehanne_free(p);
|
free(s);
|
||||||
nexterror();
|
nexterror();
|
||||||
}
|
}
|
||||||
|
p = s, e = s+READSTR;
|
||||||
len = 0;
|
p = seprint(p, e, "type %s\n",
|
||||||
|
scr->dev != nil ? scr->dev->name : "cga");
|
||||||
if(scr->dev)
|
if(scr->gscreen != nil) {
|
||||||
s = scr->dev->name;
|
p = seprint(p, e, "size %dx%dx%d %s\n",
|
||||||
else
|
|
||||||
s = "cga";
|
|
||||||
len += jehanne_snprint(p+len, READSTR-len, "type %s\n", s);
|
|
||||||
|
|
||||||
if(scr->gscreen) {
|
|
||||||
len += jehanne_snprint(p+len, READSTR-len, "size %dx%dx%d %s\n",
|
|
||||||
scr->gscreen->r.max.x, scr->gscreen->r.max.y,
|
scr->gscreen->r.max.x, scr->gscreen->r.max.y,
|
||||||
scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan));
|
scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan));
|
||||||
|
|
||||||
if(Dx(scr->gscreen->r) != Dx(physgscreenr)
|
if(Dx(scr->gscreen->r) != Dx(physgscreenr)
|
||||||
|| Dy(scr->gscreen->r) != Dy(physgscreenr))
|
|| Dy(scr->gscreen->r) != Dy(physgscreenr))
|
||||||
len += jehanne_snprint(p+len, READSTR-len, "actualsize %dx%d\n",
|
p = seprint(p, e, "actualsize %dx%d\n",
|
||||||
physgscreenr.max.x, physgscreenr.max.y);
|
physgscreenr.max.x, physgscreenr.max.y);
|
||||||
}
|
}
|
||||||
|
p = seprint(p, e, "hwgc %s\n",
|
||||||
len += jehanne_snprint(p+len, READSTR-len, "blank time %lud idle %d state %s\n",
|
scr->cur != nil ? scr->cur->name : "off");
|
||||||
blanktime, drawidletime(), scr->isblank ? "off" : "on");
|
p = seprint(p, e, "hwaccel %s\n", hwaccel ? "on" : "off");
|
||||||
len += jehanne_snprint(p+len, READSTR-len, "hwaccel %s\n", hwaccel ? "on" : "off");
|
p = seprint(p, e, "hwblank %s\n", hwblank ? "on" : "off");
|
||||||
len += jehanne_snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");
|
p = seprint(p, e, "panning %s\n", panning ? "on" : "off");
|
||||||
len += jehanne_snprint(p+len, READSTR-len, "panning %s\n", panning ? "on" : "off");
|
p = seprint(p, e, "addr p %#p v %#p size %#ux\n",
|
||||||
len += jehanne_snprint(p+len, READSTR-len, "addr p 0x%lux v 0x%p size 0x%ux\n", scr->paddr, scr->vaddr, scr->apsize);
|
scr->paddr, scr->vaddr, scr->apsize);
|
||||||
USED(len);
|
p = seprint(p, e, "softscreen %s\n", scr->softscreen ? "on" : "off");
|
||||||
|
USED(p);
|
||||||
n = readstr(offset, a, n, p);
|
n = readstr(offset, a, n, s);
|
||||||
poperror();
|
poperror();
|
||||||
jehanne_free(p);
|
free(s);
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
|
@ -263,6 +220,8 @@ vgaread(Chan* c, void* a, long n, int64_t off)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//static char Ebusy[] = "vga already configured";
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vgactl(Cmdbuf *cb)
|
vgactl(Cmdbuf *cb)
|
||||||
{
|
{
|
||||||
|
@ -278,47 +237,69 @@ vgactl(Cmdbuf *cb)
|
||||||
ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg));
|
ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg));
|
||||||
switch(ct->index){
|
switch(ct->index){
|
||||||
case CMhwgc:
|
case CMhwgc:
|
||||||
if(jehanne_strcmp(cb->f[1], "off") == 0){
|
if(scr->gscreen == nil)
|
||||||
lock(&cursor.l);
|
error("hwgc: no gscreen");
|
||||||
|
|
||||||
|
if(strcmp(cb->f[1], "off") == 0){
|
||||||
|
lock(&cursor);
|
||||||
if(scr->cur){
|
if(scr->cur){
|
||||||
if(scr->cur->disable)
|
if(scr->cur->disable)
|
||||||
scr->cur->disable(scr);
|
scr->cur->disable(scr);
|
||||||
scr->cur = nil;
|
scr->cur = nil;
|
||||||
}
|
}
|
||||||
unlock(&cursor.l);
|
unlock(&cursor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(jehanne_strcmp(cb->f[1], "soft") == 0){
|
if(strcmp(cb->f[1], "soft") == 0){
|
||||||
lock(&cursor.l);
|
lock(&cursor);
|
||||||
swcursorinit();
|
swcursorinit();
|
||||||
if(scr->cur && scr->cur->disable)
|
if(scr->cur && scr->cur->disable)
|
||||||
scr->cur->disable(scr);
|
scr->cur->disable(scr);
|
||||||
scr->cur = &swcursor;
|
scr->cur = &swcursor;
|
||||||
if(scr->cur->enable)
|
if(scr->cur->enable)
|
||||||
scr->cur->enable(scr);
|
scr->cur->enable(scr);
|
||||||
unlock(&cursor.l);
|
unlock(&cursor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(i = 0; vgacur[i]; i++){
|
for(i = 0; vgacur[i]; i++){
|
||||||
if(jehanne_strcmp(cb->f[1], vgacur[i]->name))
|
if(strcmp(cb->f[1], vgacur[i]->name))
|
||||||
continue;
|
continue;
|
||||||
lock(&cursor.l);
|
lock(&cursor);
|
||||||
if(scr->cur && scr->cur->disable)
|
if(scr->cur && scr->cur->disable)
|
||||||
scr->cur->disable(scr);
|
scr->cur->disable(scr);
|
||||||
scr->cur = vgacur[i];
|
scr->cur = vgacur[i];
|
||||||
if(scr->cur->enable)
|
if(scr->cur->enable)
|
||||||
scr->cur->enable(scr);
|
scr->cur->enable(scr);
|
||||||
unlock(&cursor.l);
|
unlock(&cursor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CMpcidev:
|
||||||
|
if(cb->nf == 2){
|
||||||
|
Pcidev *p;
|
||||||
|
|
||||||
|
if((p = pcimatchtbdf(strtoul(cb->f[1], 0, 16))) != nil)
|
||||||
|
scr->pci = p;
|
||||||
|
} else
|
||||||
|
error(Ebadarg);
|
||||||
|
return;
|
||||||
|
|
||||||
case CMtype:
|
case CMtype:
|
||||||
for(i = 0; vgadev[i]; i++){
|
for(i = 0; vgadev[i]; i++){
|
||||||
if(jehanne_strcmp(cb->f[1], vgadev[i]->name))
|
if(strcmp(cb->f[1], vgadev[i]->name))
|
||||||
continue;
|
continue;
|
||||||
if(scr->dev && scr->dev->disable)
|
if(scr->dev){
|
||||||
|
qlock(&drawlock);
|
||||||
|
scr->fill = nil;
|
||||||
|
scr->scroll = nil;
|
||||||
|
scr->blank = nil;
|
||||||
|
hwblank = 0;
|
||||||
|
hwaccel = 0;
|
||||||
|
qunlock(&drawlock);
|
||||||
|
if(scr->dev->disable)
|
||||||
scr->dev->disable(scr);
|
scr->dev->disable(scr);
|
||||||
|
}
|
||||||
scr->dev = vgadev[i];
|
scr->dev = vgadev[i];
|
||||||
if(scr->dev->enable)
|
if(scr->dev->enable)
|
||||||
scr->dev->enable(scr);
|
scr->dev->enable(scr);
|
||||||
|
@ -327,23 +308,24 @@ vgactl(Cmdbuf *cb)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMtextmode:
|
case CMtextmode:
|
||||||
cgainit();
|
screen_init();
|
||||||
|
bootscreenconf(nil);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case CMsize:
|
case CMsize:
|
||||||
x = jehanne_strtoul(cb->f[1], &p, 0);
|
x = strtoul(cb->f[1], &p, 0);
|
||||||
if(x == 0 || x > 10240)
|
if(x == 0 || x > 10240)
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
if(*p)
|
if(*p)
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
y = jehanne_strtoul(p, &p, 0);
|
y = strtoul(p, &p, 0);
|
||||||
if(y == 0 || y > 10240)
|
if(y == 0 || y > 10240)
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
if(*p)
|
if(*p)
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
z = jehanne_strtoul(p, &p, 0);
|
z = strtoul(p, &p, 0);
|
||||||
|
|
||||||
chanstr = cb->f[2];
|
chanstr = cb->f[2];
|
||||||
if((chan = strtochan(chanstr)) == 0)
|
if((chan = strtochan(chanstr)) == 0)
|
||||||
|
@ -352,26 +334,24 @@ vgactl(Cmdbuf *cb)
|
||||||
if(chantodepth(chan) != z)
|
if(chantodepth(chan) != z)
|
||||||
error("depth, channel do not match");
|
error("depth, channel do not match");
|
||||||
|
|
||||||
cursoroff(1);
|
cursoroff();
|
||||||
deletescreenimage();
|
deletescreenimage();
|
||||||
if(screensize(x, y, z, chan))
|
if(screensize(x, y, z, chan))
|
||||||
error(Egreg);
|
error(Egreg);
|
||||||
vgascreenwin(scr);
|
bootscreenconf(scr);
|
||||||
resetscreenimage();
|
|
||||||
cursoron(1);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case CMactualsize:
|
case CMactualsize:
|
||||||
if(scr->gscreen == nil)
|
if(scr->gscreen == nil)
|
||||||
error("set the screen size first");
|
error("set the screen size first");
|
||||||
|
|
||||||
x = jehanne_strtoul(cb->f[1], &p, 0);
|
x = strtoul(cb->f[1], &p, 0);
|
||||||
if(x == 0 || x > 2048)
|
if(x == 0 || x > 2048)
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
if(*p)
|
if(*p)
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
y = jehanne_strtoul(p, nil, 0);
|
y = strtoul(p, nil, 0);
|
||||||
if(y == 0 || y > 2048)
|
if(y == 0 || y > 2048)
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
|
|
||||||
|
@ -383,51 +363,57 @@ vgactl(Cmdbuf *cb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case CMpalettedepth:
|
case CMpalettedepth:
|
||||||
x = jehanne_strtoul(cb->f[1], &p, 0);
|
x = strtoul(cb->f[1], &p, 0);
|
||||||
if(x != 8 && x != 6)
|
if(x != 8 && x != 6)
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
|
|
||||||
scr->palettedepth = x;
|
scr->palettedepth = x;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case CMsoftscreen:
|
||||||
|
if(strcmp(cb->f[1], "on") == 0)
|
||||||
|
scr->softscreen = 1;
|
||||||
|
else if(strcmp(cb->f[1], "off") == 0)
|
||||||
|
scr->softscreen = 0;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
if(scr->gscreen == nil)
|
||||||
|
return;
|
||||||
|
x = scr->gscreen->r.max.x;
|
||||||
|
y = scr->gscreen->r.max.y;
|
||||||
|
z = scr->gscreen->depth;
|
||||||
|
chan = scr->gscreen->chan;
|
||||||
|
cursoroff();
|
||||||
|
deletescreenimage();
|
||||||
|
if(screensize(x, y, z, chan))
|
||||||
|
error(Egreg);
|
||||||
|
/* no break */
|
||||||
case CMdrawinit:
|
case CMdrawinit:
|
||||||
if(scr->gscreen == nil)
|
if(scr->gscreen == nil)
|
||||||
error("drawinit: no gscreen");
|
error("drawinit: no gscreen");
|
||||||
if(scr->dev && scr->dev->drawinit)
|
if(scr->dev && scr->dev->drawinit)
|
||||||
scr->dev->drawinit(scr);
|
scr->dev->drawinit(scr);
|
||||||
|
hwblank = scr->blank != nil;
|
||||||
|
hwaccel = scr->fill != nil || scr->scroll != nil;
|
||||||
|
vgascreenwin(scr);
|
||||||
|
resetscreenimage();
|
||||||
|
cursoron();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case CMlinear:
|
case CMlinear:
|
||||||
if(cb->nf!=2 && cb->nf!=3)
|
if(cb->nf!=2 && cb->nf!=3)
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
size = jehanne_strtoul(cb->f[1], 0, 0);
|
size = strtoul(cb->f[1], 0, 0);
|
||||||
if(cb->nf == 2)
|
if(cb->nf == 2)
|
||||||
align = 0;
|
align = 0;
|
||||||
else
|
else
|
||||||
align = jehanne_strtoul(cb->f[2], 0, 0);
|
align = strtoul(cb->f[2], 0, 0);
|
||||||
if(screenaperture(size, align) < 0)
|
if(screenaperture(size, align) < 0)
|
||||||
error("not enough free address space");
|
error("not enough free address space");
|
||||||
return;
|
return;
|
||||||
/*
|
|
||||||
case CMmemset:
|
|
||||||
jehanne_memset((void*)jehanne_strtoul(cb->f[1], 0, 0), jehanne_atoi(cb->f[2]), jehanne_atoi(cb->f[3]));
|
|
||||||
return;
|
|
||||||
*/
|
|
||||||
|
|
||||||
case CMblank:
|
|
||||||
drawblankscreen(1);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case CMunblank:
|
|
||||||
drawblankscreen(0);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case CMblanktime:
|
|
||||||
blanktime = jehanne_strtoul(cb->f[1], 0, 0);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case CMpanning:
|
case CMpanning:
|
||||||
if(jehanne_strcmp(cb->f[1], "on") == 0){
|
if(strcmp(cb->f[1], "on") == 0){
|
||||||
if(scr == nil || scr->cur == nil)
|
if(scr == nil || scr->cur == nil)
|
||||||
error("set screen first");
|
error("set screen first");
|
||||||
if(!scr->cur->doespanning)
|
if(!scr->cur->doespanning)
|
||||||
|
@ -435,7 +421,7 @@ vgactl(Cmdbuf *cb)
|
||||||
scr->gscreen->clipr = scr->gscreen->r;
|
scr->gscreen->clipr = scr->gscreen->r;
|
||||||
panning = 1;
|
panning = 1;
|
||||||
}
|
}
|
||||||
else if(jehanne_strcmp(cb->f[1], "off") == 0){
|
else if(strcmp(cb->f[1], "off") == 0){
|
||||||
scr->gscreen->clipr = physgscreenr;
|
scr->gscreen->clipr = physgscreenr;
|
||||||
panning = 0;
|
panning = 0;
|
||||||
}else
|
}else
|
||||||
|
@ -443,18 +429,18 @@ vgactl(Cmdbuf *cb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case CMhwaccel:
|
case CMhwaccel:
|
||||||
if(jehanne_strcmp(cb->f[1], "on") == 0)
|
if(strcmp(cb->f[1], "on") == 0)
|
||||||
hwaccel = 1;
|
hwaccel = 1;
|
||||||
else if(jehanne_strcmp(cb->f[1], "off") == 0)
|
else if(strcmp(cb->f[1], "off") == 0)
|
||||||
hwaccel = 0;
|
hwaccel = 0;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case CMhwblank:
|
case CMhwblank:
|
||||||
if(jehanne_strcmp(cb->f[1], "on") == 0)
|
if(strcmp(cb->f[1], "on") == 0)
|
||||||
hwblank = 1;
|
hwblank = 1;
|
||||||
else if(jehanne_strcmp(cb->f[1], "off") == 0)
|
else if(strcmp(cb->f[1], "off") == 0)
|
||||||
hwblank = 0;
|
hwblank = 0;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
@ -483,12 +469,12 @@ vgawrite(Chan* c, void* a, long n, int64_t off)
|
||||||
error(Ebadarg);
|
error(Ebadarg);
|
||||||
cb = parsecmd(a, n);
|
cb = parsecmd(a, n);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
jehanne_free(cb);
|
free(cb);
|
||||||
nexterror();
|
nexterror();
|
||||||
}
|
}
|
||||||
vgactl(cb);
|
vgactl(cb);
|
||||||
poperror();
|
poperror();
|
||||||
jehanne_free(cb);
|
free(cb);
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
case Qvgaovl:
|
case Qvgaovl:
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* embedded controller (usually at ports 0x66/0x62)
|
||||||
|
*/
|
||||||
|
#include "u.h"
|
||||||
|
#include "../port/lib.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "../port/error.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* registers */
|
||||||
|
EC_SC = 0,
|
||||||
|
EC_DATA,
|
||||||
|
|
||||||
|
/* Embedded Controller Status, EC_SC (R) */
|
||||||
|
OBF = 1<<0,
|
||||||
|
IBF = 1<<1,
|
||||||
|
CMD = 1<<3,
|
||||||
|
BURST = 1<<4,
|
||||||
|
SCI_EVT = 1<<5,
|
||||||
|
SMI_EVT = 1<<6,
|
||||||
|
|
||||||
|
/* Embedded Controller Command Set */
|
||||||
|
RD_EC = 0x80,
|
||||||
|
WR_EC = 0x81,
|
||||||
|
BE_EC = 0x82,
|
||||||
|
BD_EC = 0x83,
|
||||||
|
QR_EC = 0x84,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
Lock;
|
||||||
|
int init;
|
||||||
|
int port[2]; /* EC_SC and EC_DATA */
|
||||||
|
} ec;
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
ecrr(int reg)
|
||||||
|
{
|
||||||
|
return inb(ec.port[reg]);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
ecwr(int reg, uint8_t val)
|
||||||
|
{
|
||||||
|
outb(ec.port[reg], val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ecwait(uint8_t mask, uint8_t val)
|
||||||
|
{
|
||||||
|
int i, s;
|
||||||
|
|
||||||
|
s = 0;
|
||||||
|
for(i=0; i<1000; i++){
|
||||||
|
s = ecrr(EC_SC);
|
||||||
|
if((s & mask) == val)
|
||||||
|
return 0;
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
print("ec: wait timeout status=%x pc=%#p\n", s, getcallerpc());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ecread(uint8_t addr)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = -1;
|
||||||
|
lock(&ec);
|
||||||
|
if(!ec.init)
|
||||||
|
goto out;
|
||||||
|
if(ecwait(IBF, 0))
|
||||||
|
goto out;
|
||||||
|
ecwr(EC_SC, RD_EC);
|
||||||
|
if(ecwait(IBF, 0))
|
||||||
|
goto out;
|
||||||
|
ecwr(EC_DATA, addr);
|
||||||
|
if(ecwait(OBF, OBF))
|
||||||
|
goto out;
|
||||||
|
r = ecrr(EC_DATA);
|
||||||
|
ecwait(OBF, 0);
|
||||||
|
out:
|
||||||
|
unlock(&ec);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ecwrite(uint8_t addr, uint8_t val)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = -1;
|
||||||
|
lock(&ec);
|
||||||
|
if(!ec.init)
|
||||||
|
goto out;
|
||||||
|
if(ecwait(IBF, 0))
|
||||||
|
goto out;
|
||||||
|
ecwr(EC_SC, WR_EC);
|
||||||
|
if(ecwait(IBF, 0))
|
||||||
|
goto out;
|
||||||
|
ecwr(EC_DATA, addr);
|
||||||
|
if(ecwait(IBF, 0))
|
||||||
|
goto out;
|
||||||
|
ecwr(EC_DATA, val);
|
||||||
|
if(ecwait(IBF, 0))
|
||||||
|
goto out;
|
||||||
|
r = 0;
|
||||||
|
out:
|
||||||
|
unlock(&ec);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
ecarchread(Chan* _, void *a, long n, int64_t off)
|
||||||
|
{
|
||||||
|
int port, v;
|
||||||
|
uint8_t *p;
|
||||||
|
|
||||||
|
if(off < 0 || off >= 256)
|
||||||
|
return 0;
|
||||||
|
if(off+n > 256)
|
||||||
|
n = 256 - off;
|
||||||
|
p = a;
|
||||||
|
for(port = off; port < off+n; port++){
|
||||||
|
if((v = ecread(port)) < 0)
|
||||||
|
error(Eio);
|
||||||
|
*p++ = v;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
ecarchwrite(Chan* _, void *a, long n, int64_t off)
|
||||||
|
{
|
||||||
|
int port;
|
||||||
|
uint8_t *p;
|
||||||
|
|
||||||
|
if(off < 0 || off+n > 256)
|
||||||
|
error(Ebadarg);
|
||||||
|
p = a;
|
||||||
|
for(port = off; port < off+n; port++)
|
||||||
|
if(ecwrite(port, *p++) < 0)
|
||||||
|
error(Eio);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ecinit(int cmdport, int dataport)
|
||||||
|
{
|
||||||
|
print("ec: cmd %X, data %X\n", cmdport, dataport);
|
||||||
|
|
||||||
|
if(ioalloc(cmdport, 1, 0, "ec.sc") < 0){
|
||||||
|
print("ec: cant allocate cmd port %X\n", cmdport);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(ioalloc(dataport, 1, 0, "ec.data") < 0){
|
||||||
|
print("ec: cant allocate data port %X\n", dataport);
|
||||||
|
iofree(cmdport);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock(&ec);
|
||||||
|
ec.port[EC_SC] = cmdport;
|
||||||
|
ec.port[EC_DATA] = dataport;
|
||||||
|
ec.init = 1;
|
||||||
|
unlock(&ec);
|
||||||
|
|
||||||
|
addarchfile("ec", 0660, ecarchread, ecarchwrite);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -1,189 +1,145 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Jehanne.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||||
|
*
|
||||||
|
* Jehanne 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, version 2 of the License.
|
||||||
|
*
|
||||||
|
* Jehanne 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 Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "amd64.h"
|
#include "amd64.h"
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
#define __ASSEMBLER__
|
#define __ASSEMBLER__
|
||||||
#endif
|
#endif
|
||||||
|
#include "multiboot.h"
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
/* do we enter in 16-bit mode? If so, take the code from coreboot that goes from
|
/* This code (up to _start64v) is linked and loaded at physical address
|
||||||
* 16->32
|
* 0x00100000 (1MB), which is the start of extended memory. (See kernel.ld)
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
* Enter here in 32-bit protected mode. Welcome to 1982.
|
/* boottext must be text: http://sourceware.org/binutils/docs/as/Section.html
|
||||||
* Make sure the GDT is set as it should be:
|
|
||||||
* disable interrupts;
|
|
||||||
* load the GDT with the table in _gdt32p;
|
|
||||||
* load all the data segments
|
|
||||||
* load the code segment via a far jump.
|
|
||||||
*/
|
*/
|
||||||
#define MULTIBOOT_PAGE_ALIGN (1<<0)
|
|
||||||
#define MULTIBOOT_MEMORY_INFO (1<<1)
|
|
||||||
#define MULTIBOOT_HEADER_MAGIC (0x1BADB002)
|
|
||||||
#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
|
|
||||||
#define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS))
|
|
||||||
|
|
||||||
# The kernel bootstrap (this code) is linked and loaded at physical address
|
|
||||||
# 0x00100000 (1MB), which is the start of extended memory. (See kernel.ld)
|
|
||||||
|
|
||||||
# Flagging boottext to be text. Check out:
|
|
||||||
# http://sourceware.org/binutils/docs/as/Section.html
|
|
||||||
.section .boottext, "awx"
|
.section .boottext, "awx"
|
||||||
|
|
||||||
.code32
|
|
||||||
.align 4
|
.align 4
|
||||||
_protected:
|
#define MBFLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
|
||||||
multiboot_header:
|
_multibootheader:
|
||||||
.long MULTIBOOT_HEADER_MAGIC
|
.long MULTIBOOT_HEADER_MAGIC
|
||||||
.long MULTIBOOT_HEADER_FLAGS
|
.long MBFLAGS
|
||||||
.long CHECKSUM
|
.long (-(MULTIBOOT_HEADER_MAGIC + MBFLAGS)) /* checksum */
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.globl _boot_registers
|
||||||
|
_boot_registers:
|
||||||
|
_ax:
|
||||||
|
.quad 0
|
||||||
|
_bx:
|
||||||
|
.quad 0
|
||||||
|
_cx:
|
||||||
|
.quad 0
|
||||||
|
_dx:
|
||||||
|
.quad 0
|
||||||
|
_si:
|
||||||
|
.quad 0
|
||||||
|
_di:
|
||||||
|
.quad 0
|
||||||
|
_bp:
|
||||||
|
.quad 0
|
||||||
|
_r8:
|
||||||
|
.quad 0
|
||||||
|
_r9:
|
||||||
|
.quad 0
|
||||||
|
_r10:
|
||||||
|
.quad 0
|
||||||
|
_r11:
|
||||||
|
.quad 0
|
||||||
|
_r12:
|
||||||
|
.quad 0
|
||||||
|
_r13:
|
||||||
|
.quad 0
|
||||||
|
_r14:
|
||||||
|
.quad 0
|
||||||
|
_r15:
|
||||||
|
.quad 0
|
||||||
|
_type:
|
||||||
|
.quad 0
|
||||||
|
_error:
|
||||||
|
.quad 0
|
||||||
|
_ip:
|
||||||
|
.quad 0
|
||||||
|
_cs:
|
||||||
|
.quad 0
|
||||||
|
_flags:
|
||||||
|
.quad 0
|
||||||
|
_sp:
|
||||||
|
.quad 0
|
||||||
|
_ss:
|
||||||
|
.quad 0
|
||||||
|
|
||||||
.globl _start
|
.globl _start
|
||||||
_start:
|
_start:
|
||||||
cli
|
cli
|
||||||
jmp 1f
|
lgdt %cs:_gdtptr32p
|
||||||
|
ljmp $0x18, $_protected
|
||||||
|
|
||||||
|
_protected:
|
||||||
|
/* save initial registers (at least those available so far) */
|
||||||
|
movl %eax, _ax
|
||||||
|
movl %ebx, _bx
|
||||||
|
movl %ecx, _cx
|
||||||
|
movl %edx, _dx
|
||||||
|
movl %ebp, _bp
|
||||||
|
movl %esp, _sp
|
||||||
|
movl %esi, _si
|
||||||
|
movl %edi, _di
|
||||||
|
|
||||||
/* This is the GDT for the ROM stage part of coreboot. It
|
movl $SELECTOR(2, SELGDT, 0), %eax
|
||||||
* is different from the RAM stage GDT which is defined in
|
|
||||||
* c_start.S
|
|
||||||
*/
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
.globl gdtptr
|
|
||||||
gdt:
|
|
||||||
gdtptr:
|
|
||||||
.word gdt_end - gdt -1 /* compute the table limit */
|
|
||||||
.long gdt /* we know the offset */
|
|
||||||
.word 0
|
|
||||||
|
|
||||||
/* selgdt 0x08, flat code segment */
|
|
||||||
.word 0xffff, 0x0000
|
|
||||||
.byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
|
|
||||||
|
|
||||||
/* selgdt 0x10,flat data segment */
|
|
||||||
.word 0xffff, 0x0000
|
|
||||||
.byte 0x00, 0x93, 0xcf, 0x00
|
|
||||||
|
|
||||||
/* long mode code segment. */
|
|
||||||
.quad 0x0020980000000000 /* Long mode CS */
|
|
||||||
|
|
||||||
gdt_end:
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When we come here we are in protected mode. We expand
|
|
||||||
* the stack and copies the data segment from ROM to the
|
|
||||||
* memory.
|
|
||||||
*
|
|
||||||
* After that, we call the chipset bootstrap routine that
|
|
||||||
* does what is left of the chipset initialization.
|
|
||||||
*
|
|
||||||
* NOTE aligned to 4 so that we are sure that the prefetch
|
|
||||||
* cache will be reloaded.
|
|
||||||
*/
|
|
||||||
1:
|
|
||||||
.align 4
|
|
||||||
.globl protected_start
|
|
||||||
protected_start:
|
|
||||||
|
|
||||||
lgdt %cs:gdtptr
|
|
||||||
ljmp $8, $__protected_start
|
|
||||||
|
|
||||||
__protected_start:
|
|
||||||
/* Save the BIST value */
|
|
||||||
movl %eax, %ebp
|
|
||||||
movw $0x10, %ax
|
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
movw %ax, %ss
|
|
||||||
movw %ax, %fs
|
movw %ax, %fs
|
||||||
movw %ax, %gs
|
movw %ax, %gs
|
||||||
|
movw %ax, %ss
|
||||||
|
|
||||||
/* Restore the BIST value to %eax */
|
jmp _warp64
|
||||||
movl %ebp, %eax
|
|
||||||
|
|
||||||
entry32:
|
.align 16
|
||||||
1:
|
_gdt:
|
||||||
movb $0x30, %al
|
/* null descriptor */
|
||||||
movw $0x30, %dx
|
.long 0
|
||||||
outb %dx
|
.long 0
|
||||||
// This gets us into a reasonable mode. We can skip the plan 9 gdt code.
|
|
||||||
call 1f
|
|
||||||
1:
|
|
||||||
popl %ebp
|
|
||||||
/* when you execute this instruction, bp has the value
|
|
||||||
* of 1f.
|
|
||||||
* So add the length of this instruction and the
|
|
||||||
* 5 bytes of the jmp that follows it.
|
|
||||||
* It will then point to start of header.
|
|
||||||
*/
|
|
||||||
addl $12, %ebp
|
|
||||||
/* Now make it point to gdt32p (gdt, 32 bits, physical)
|
|
||||||
*/
|
|
||||||
addl $14, %ebp
|
|
||||||
jmp _endofheader
|
|
||||||
|
|
||||||
_startofheader:
|
/* (KESEG) 64 bit long mode exec segment */
|
||||||
.byte 0x90 /* NOP */
|
.long 0xFFFF
|
||||||
.byte 0x90 /* NOP */
|
.long SEGL|SEGG|SEGP|(0xF<<16)|SEGPL(0)|SEGEXEC|SEGR
|
||||||
|
|
||||||
_multibootheader: /* must be 4-byte aligned */
|
/* 32 bit data segment descriptor for 4 gigabytes (PL 0) */
|
||||||
.long 0x1badb002 /* magic */
|
.long 0xFFFF
|
||||||
.long 0x00000003 /* flags */
|
.long SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW
|
||||||
.long -(0x1badb002 + 0x00000003) /* checksum */
|
|
||||||
|
|
||||||
_gdt32p:
|
/* 32 bit exec segment descriptor for 4 gigabytes (PL 0) */
|
||||||
.quad 0x0000000000000000 /* NULL descriptor */
|
.long 0xFFFF
|
||||||
.quad 0x00cf9a000000ffff /* CS */
|
.long SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR
|
||||||
.quad 0x00cf92000000ffff /* DS */
|
|
||||||
.quad 0x0020980000000000 /* Long mode CS */
|
|
||||||
|
|
||||||
|
.align 4
|
||||||
_gdtptr32p:
|
_gdtptr32p:
|
||||||
.word 4*8-1
|
.word 4*8-1
|
||||||
.long _gdt32p
|
.long _gdt
|
||||||
|
|
||||||
_gdt64p:
|
|
||||||
.quad 0x0000000000000000 /* NULL descriptor */
|
|
||||||
.quad 0x0020980000000000 /* CS */
|
|
||||||
|
|
||||||
|
.align 4
|
||||||
_gdtptr64p:
|
_gdtptr64p:
|
||||||
.word 2*8-1
|
.word 4*8-1
|
||||||
.quad _gdt64p
|
.quad _gdt
|
||||||
|
|
||||||
|
|
||||||
_endofheader:
|
|
||||||
pushl %eax /* possible passed-in magic */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make the basic page tables for CPU0 to map 0-4MiB physical
|
|
||||||
* to KZERO, and include an identity map for the switch from protected
|
|
||||||
* to paging mode. There`s an assumption here that the creation and later
|
|
||||||
* removal of the identity map will not interfere with the KZERO mappings;
|
|
||||||
* the conditions for clearing the identity map are
|
|
||||||
* clear PML4 entry when (KZER0 & 0x0000ff8000000000) != 0;
|
|
||||||
* clear PDP entry when (KZER0 & 0x0000007fc0000000) != 0;
|
|
||||||
* don`t clear PD entry when (KZER0 & 0x000000003fe00000) == 0;
|
|
||||||
* the code below assumes these conditions are met.
|
|
||||||
*
|
|
||||||
* Assume a recent processor with Page Size Extensions
|
|
||||||
* and use two 2MiB entries.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* The layout is decribed in data.h:
|
|
||||||
* _protected: start of kernel text
|
|
||||||
* - 4*KiB unused
|
|
||||||
* - 4*KiB unused
|
|
||||||
* - 4*KiB ptrpage
|
|
||||||
* - 4*KiB syspage
|
|
||||||
* - MACHSZ m
|
|
||||||
* - 4*KiB vsvmpage for gdt, tss
|
|
||||||
* - PTSZ PT for PMAPADDR unused - assumes in KZERO PD
|
|
||||||
* - PTSZ PD
|
|
||||||
* - PTSZ PDP
|
|
||||||
* - PTSZ PML4
|
|
||||||
* - MACHSTKSZ stack
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Macros for accessing page table entries; change the
|
* Macros for accessing page table entries; change the
|
||||||
|
@ -195,45 +151,55 @@ _endofheader:
|
||||||
#define PTO(v) ((PTLX((v), 0))<<3)
|
#define PTO(v) ((PTLX((v), 0))<<3)
|
||||||
|
|
||||||
_warp64:
|
_warp64:
|
||||||
movl $_protected-(MACHSTKSZ+4*PTSZ+5*(4*KiB)+MACHSZ), %esi
|
movl $((CPU0END-CPU0PML4)>>2), %ecx
|
||||||
|
movl $(CPU0PML4-KZERO), %esi
|
||||||
|
|
||||||
movl %esi, %edi
|
movl %esi, %edi
|
||||||
xorl %eax, %eax
|
xorl %eax, %eax
|
||||||
movl $((MACHSTKSZ+4*PTSZ+5*(4*KiB)+MACHSZ)>>2), %ecx
|
|
||||||
|
|
||||||
cld
|
cld
|
||||||
rep; stosl /* stack, P*, vsvm, m, sys */
|
rep; stosl
|
||||||
|
|
||||||
movl %esi, %eax /* sys-KZERO */
|
movl %esi, %eax /* PML4 */
|
||||||
addl $(MACHSTKSZ), %eax /* PML4 */
|
|
||||||
movl %eax, %cr3 /* load the mmu */
|
|
||||||
movl %eax, %edx
|
movl %eax, %edx
|
||||||
addl $(PTSZ|PteRW|PteP), %edx /* PDP at PML4 + PTSZ */
|
addl $(PTSZ|PTEWRITE|PTEVALID), %edx /* PDP at PML4 + PTSZ */
|
||||||
movl %edx, PML4O(0)(%eax) /* PML4E for identity map */
|
movl %edx, PML4O(0)(%eax) /* PML4E for double-map */
|
||||||
movl %edx, PML4O(KZERO)(%eax) /* PML4E for KZERO, PMAPADDR */
|
movl %edx, PML4O(KZERO)(%eax) /* PML4E for KZERO */
|
||||||
|
|
||||||
addl $PTSZ, %eax /* PDP at PML4 + PTSZ */
|
addl $PTSZ, %eax /* PDP at PML4 + PTSZ */
|
||||||
addl $PTSZ, %edx /* PD at PML4 + 2*PTSZ */
|
addl $PTSZ, %edx /* PD0 at PML4 + 2*PTSZ */
|
||||||
movl %edx, PDPO(0)(%eax) /* PDPE for identity map */
|
movl %edx, PDPO(0)(%eax) /* PDPE for double-map */
|
||||||
movl %edx, PDPO(KZERO)(%eax) /* PDPE for KZERO, PMAPADDR */
|
movl %edx, PDPO(KZERO)(%eax) /* PDPE for KZERO */
|
||||||
|
|
||||||
addl $PTSZ, %eax /* PD at PML4 + 2*PTSZ */
|
/*
|
||||||
movl $(PtePS|PteRW|PteP), %edx
|
* add PDPE for KZERO+1GB early as Vmware
|
||||||
movl %edx, PDO(0)(%eax) /* PDE for identity 0-[24]MiB */
|
* hangs when modifying kernel PDP
|
||||||
|
*/
|
||||||
|
addl $PTSZ, %edx /* PD1 */
|
||||||
|
movl %edx, PDPO(KZERO+GiB)(%eax)
|
||||||
|
|
||||||
movl %eax, %ecx
|
addl $PTSZ, %eax /* PD0 at PML4 + 2*PTSZ */
|
||||||
addl $PDO(KZERO), %ecx
|
movl $(PTESIZE|PTEGLOBAL|PTEWRITE|PTEVALID), %edx
|
||||||
|
movl %edx, PDO(0)(%eax) /* PDE for double-map */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* map from KZERO to end using 2MB pages
|
||||||
|
*/
|
||||||
|
addl $PDO(KZERO), %eax
|
||||||
|
movl $end-KZERO, %ecx
|
||||||
|
|
||||||
|
addl $(16*MiB), %ecx /* qemu puts multiboot data after the kernel, including initrd */
|
||||||
|
|
||||||
|
addl $(PGLSZ(1)-1), %ecx
|
||||||
|
andl $(~(PGLSZ(1)-1)), %ecx
|
||||||
|
movl %ecx, MemMin-KZERO /* see memory.c */
|
||||||
|
shr $(PTSHFT+PGSHIFT), %ecx
|
||||||
|
|
||||||
memloop:
|
memloop:
|
||||||
movl %edx, 0(%ecx)
|
movl %edx, (%eax)
|
||||||
addl $PGLSZ(1), %edx
|
addl $PGLSZ(1), %edx
|
||||||
addl $8, %ecx
|
addl $8, %eax
|
||||||
cmpl $(32*MiB), %edx
|
loop memloop
|
||||||
JL memloop
|
|
||||||
|
|
||||||
movl %eax, %edx /* PD at PML4 + 2*PTSZ */
|
|
||||||
addl $(PTSZ|PteRW|PteP), %edx /* PT at PML4 + 3*PTSZ */
|
|
||||||
movl %edx, PDO(PMAPADDR)(%eax) /* PDE for PMAPADDR */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable and activate Long Mode. From the manual:
|
* Enable and activate Long Mode. From the manual:
|
||||||
|
@ -245,6 +211,9 @@ memloop:
|
||||||
* It`s all in 32-bit mode until the jump is made.
|
* It`s all in 32-bit mode until the jump is made.
|
||||||
*/
|
*/
|
||||||
lme:
|
lme:
|
||||||
|
movl %esi, %cr3 /* load the mmu */
|
||||||
|
jmp 1f
|
||||||
|
1:
|
||||||
movl %cr4, %eax
|
movl %cr4, %eax
|
||||||
andl $~Pse, %eax /* Page Size */
|
andl $~Pse, %eax /* Page Size */
|
||||||
orl $(Pge|Pae), %eax /* Page Global, Phys. Address */
|
orl $(Pge|Pae), %eax /* Page Global, Phys. Address */
|
||||||
|
@ -260,7 +229,8 @@ lme:
|
||||||
orl $(Pg|Wp), %edx /* Paging Enable */
|
orl $(Pg|Wp), %edx /* Paging Enable */
|
||||||
movl %edx, %cr0
|
movl %edx, %cr0
|
||||||
|
|
||||||
ljmp $0x18, $_identity
|
ljmp $0x8, $_identity
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Long mode. Welcome to 2003.
|
* Long mode. Welcome to 2003.
|
||||||
|
@ -270,69 +240,60 @@ lme:
|
||||||
.code64
|
.code64
|
||||||
|
|
||||||
_identity:
|
_identity:
|
||||||
|
/* save initial registers */
|
||||||
|
movq %r8, _r8
|
||||||
|
movq %r9, _r9
|
||||||
|
movq %r10, _r10
|
||||||
|
movq %r11, _r11
|
||||||
|
movq %r12, _r12
|
||||||
|
movq %r13, _r13
|
||||||
|
movq %r14, _r14
|
||||||
|
movq %r15, _r15
|
||||||
|
|
||||||
movq $_start64v, %rax
|
movq $_start64v, %rax
|
||||||
jmp *%rax
|
jmp *%rax
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
_gdt64v:
|
|
||||||
.quad 0x0000000000000000 /* NULL descriptor */
|
|
||||||
.quad 0x0020980000000000 /* CS */
|
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.globl _gdtptr64v
|
||||||
_gdtptr64v:
|
_gdtptr64v:
|
||||||
.word 2*8-1
|
.word 4*8-1
|
||||||
.quad _gdt64v
|
.quad _gdt+KZERO
|
||||||
|
.word 0
|
||||||
|
|
||||||
// At this point, we are safe to use kernel addresses, as we are in
|
.align 4
|
||||||
// kernel virtual address space.
|
|
||||||
_start64v:
|
_start64v:
|
||||||
movq $_gdtptr64v, %rax
|
movq $_gdtptr64v, %rax
|
||||||
lgdt (%rax)
|
lgdt (%rax)
|
||||||
|
|
||||||
xorq %rdx, %rdx
|
xorq %rax, %rax
|
||||||
movw %dx, %ds /* not used in long mode */
|
movw %ax, %ds /* not used in long mode */
|
||||||
movw %dx, %es /* not used in long mode */
|
movw %ax, %es /* not used in long mode */
|
||||||
movw %dx, %fs
|
movw %ax, %fs
|
||||||
movw %dx, %gs
|
movw %ax, %gs
|
||||||
movw %dx, %ss /* not used in long mode */
|
movw %ax, %ss /* not used in long mode */
|
||||||
|
|
||||||
movq %rsi, %rsi /* sys-KZERO */
|
lldt %ax
|
||||||
movq %rsi, %rax
|
|
||||||
addq $KZERO, %rax
|
|
||||||
movq %rax, sys /* sys */
|
|
||||||
|
|
||||||
addq $(MACHSTKSZ), %rax /* PML4 and top of stack */
|
movq $(CPU0MACH+MACHSIZE), %rsp
|
||||||
movq %rax, %rsp /* set stack */
|
movq $CPU0MACH, %r15 /* m = CPU0MACH */
|
||||||
|
movq %rax, %r14 /* up = 0; */
|
||||||
|
|
||||||
_zap0pml4:
|
_clearbss:
|
||||||
cmpq $PML4O(KZERO), %rdx /* KZER0 & 0x0000ff8000000000 */
|
movq $edata, %rdi
|
||||||
je _zap0pdp
|
movq $end, %rcx
|
||||||
movq %rdx, PML4O(0)(%rax) /* zap identity map PML4E */
|
addq $(PGSZ-1), %rdi
|
||||||
_zap0pdp:
|
andq $(~(PGSZ-1)), %rdi
|
||||||
addq $PTSZ, %rax /* PDP at PML4 + PTSZ */
|
subq %rdi, %rcx /* end-edata bytes */
|
||||||
cmpq $PDPO(KZERO), %rdx /* KZER0 & 0x0000007fc0000000 */
|
shrq $2, %rcx /* end-edata doublewords */
|
||||||
je _zap0pd
|
|
||||||
movq %rdx, PDPO(0)(%rax) /* zap identity map PDPE */
|
|
||||||
_zap0pd:
|
|
||||||
addq $PTSZ, %rax /* PD at PML4 + 2*PTSZ */
|
|
||||||
cmpq $PDO(KZERO), %rdx /* KZER0 & 0x000000003fe00000 */
|
|
||||||
je _zap0done
|
|
||||||
movq %rdx, PDO(0)(%rax) /* zap identity map PDE */
|
|
||||||
_zap0done:
|
|
||||||
addq $(MACHSTKSZ), %rsi /* PML4-KZERO */
|
|
||||||
movq %rsi, %cr3 /* flush TLB */
|
|
||||||
|
|
||||||
addq $(2*PTSZ+4*KiB), %rax /* PD+PT+vsvm */
|
cld
|
||||||
movq %rax, %r15
|
rep; stosl
|
||||||
movq %rdx, %r14
|
|
||||||
movq $0, (%rax) /* m->machno = 0 */
|
|
||||||
|
|
||||||
pushq %rdx /* clear flags */
|
pushq %rax
|
||||||
popfq
|
popfq
|
||||||
|
|
||||||
movq %rbx, %rbx /* push multiboot args */
|
|
||||||
movq %rbx, %rsi
|
|
||||||
movq %rax, %rax
|
|
||||||
movq %rax, %rdi /* multiboot magic */
|
|
||||||
xorq %rbp, %rbp /* stack trace ends here */
|
|
||||||
call main
|
call main
|
||||||
|
|
||||||
.globl ndnr
|
.globl ndnr
|
||||||
|
|
|
@ -2038,4 +2038,3 @@ etherigbelink(void)
|
||||||
addethercard("i82543", igbepnp);
|
addethercard("i82543", igbepnp);
|
||||||
addethercard("igbe", igbepnp);
|
addethercard("igbe", igbepnp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ void mouseenable(void);
|
||||||
int mousecmd(int);
|
int mousecmd(int);
|
||||||
|
|
||||||
void aamloop(int);
|
void aamloop(int);
|
||||||
void acpiinit(int);
|
|
||||||
Dirtab* addarchfile(char*, int,
|
Dirtab* addarchfile(char*, int,
|
||||||
long(*)(Chan*,void*,long,int64_t),
|
long(*)(Chan*,void*,long,int64_t),
|
||||||
long(*)(Chan*,void*,long,int64_t));
|
long(*)(Chan*,void*,long,int64_t));
|
||||||
|
@ -47,36 +46,49 @@ uint64_t asmalloc(uint64_t, uint64_t, int, int);
|
||||||
void asminit(void);
|
void asminit(void);
|
||||||
void asmmapinit(uint64_t, uint64_t, int);
|
void asmmapinit(uint64_t, uint64_t, int);
|
||||||
void asmmodinit(uint32_t, uint32_t, char*);
|
void asmmodinit(uint32_t, uint32_t, char*);
|
||||||
void cgaconsputs(char*, int);
|
void screen_init(void);
|
||||||
void cgainit(void);
|
uintptr_t cankaddr(uintptr_t pa);
|
||||||
void cgapost(int);
|
|
||||||
void (*coherence)(void);
|
void (*coherence)(void);
|
||||||
|
void cpuid(int, uint32_t regs[]);
|
||||||
|
int cpuidentify(void);
|
||||||
|
void cpuidprint(void);
|
||||||
int corecolor(int);
|
int corecolor(int);
|
||||||
uint32_t cpuid(uint32_t, uint32_t, uint32_t[4]);
|
void (*cycles)(uint64_t*);
|
||||||
int dbgprint(char*, ...);
|
int dbgprint(char*, ...);
|
||||||
void delay(int);
|
void delay(int);
|
||||||
|
int ecinit(int cmdport, int dataport);
|
||||||
|
int ecread(uint8_t addr);
|
||||||
|
int ecwrite(uint8_t addr, uint8_t val);
|
||||||
#define evenaddr(x) /* x86 doesn't care */
|
#define evenaddr(x) /* x86 doesn't care */
|
||||||
int e820(void);
|
int e820(void);
|
||||||
int fpudevprocio(Proc*, void*, int32_t, uintptr_t, int);
|
void fpclear(void);
|
||||||
void fpuinit(void);
|
void fpinit(void);
|
||||||
void fpunoted(void);
|
void fpoff(void);
|
||||||
void fpunotify(Ureg*);
|
void (*fprestore)(FPsave*);
|
||||||
void fpuprocrestore(Proc*);
|
void (*fpsave)(FPsave*);
|
||||||
void fpuprocsave(Proc*);
|
void fpsserestore(FPsave*);
|
||||||
void fpusysprocsetup(Proc*);
|
void fpssesave(FPsave*);
|
||||||
void fpusysrfork(Ureg*);
|
void fpprocfork(Proc *p);
|
||||||
void fpusysrforkchild(Proc*, Proc*);
|
void fpprocsetup(Proc* p);
|
||||||
char* getconf(char*);
|
char* getconf(char*);
|
||||||
|
void guesscpuhz(int);
|
||||||
void _halt(void);
|
void _halt(void);
|
||||||
void halt(void);
|
void halt(void);
|
||||||
void hpetinit(uint32_t, uint32_t, uintmem, int);
|
void hpetinit(uint32_t, uint32_t, uintmem, int);
|
||||||
/*int i8042auxcmd(int);
|
int i8042auxcmd(int);
|
||||||
int i8042auxcmds(uint8_t*, int);
|
void i8042auxenable(void (*)(int, int));
|
||||||
void i8042auxenable(void (*)(int, int));*/
|
void i8042reset(void);
|
||||||
void i8042systemreset(void);
|
void i8250console(void);
|
||||||
Uart* i8250console(char*);
|
|
||||||
void* i8250alloc(int, int, int);
|
void* i8250alloc(int, int, int);
|
||||||
int64_t i8254hz(uint32_t[2][4]);
|
int64_t i8254hz(uint32_t[2][4]);
|
||||||
|
|
||||||
|
void i8253enable(void);
|
||||||
|
void i8253init(void);
|
||||||
|
void i8253reset(void);
|
||||||
|
uint64_t i8253read(uint64_t*);
|
||||||
|
void i8253timerset(uint64_t);
|
||||||
|
|
||||||
|
void idle(void);
|
||||||
void idlehands(void);
|
void idlehands(void);
|
||||||
void idthandlers(void);
|
void idthandlers(void);
|
||||||
int inb(int);
|
int inb(int);
|
||||||
|
@ -85,7 +97,7 @@ uint16_t ins(int);
|
||||||
void inss(int, void*, int);
|
void inss(int, void*, int);
|
||||||
uint32_t inl(int);
|
uint32_t inl(int);
|
||||||
void insl(int, void*, int);
|
void insl(int, void*, int);
|
||||||
int intrdisable(void*);
|
int intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name);
|
||||||
void* intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
|
void* intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
|
||||||
void invlpg(uintptr_t va);
|
void invlpg(uintptr_t va);
|
||||||
void iofree(int);
|
void iofree(int);
|
||||||
|
@ -96,16 +108,20 @@ int ioreserve(int, int, int, char*);
|
||||||
int iprint(char*, ...);
|
int iprint(char*, ...);
|
||||||
int isaconfig(char*, int, ISAConf*);
|
int isaconfig(char*, int, ISAConf*);
|
||||||
int isdmaok(void*, usize, int);
|
int isdmaok(void*, usize, int);
|
||||||
void keybenable(void); // 386/i8042.c
|
void keybenable(void); // i8042.c
|
||||||
void keybinit(void); // 386/i8042.c
|
void keybinit(void); // i8042.c
|
||||||
void kexit(Ureg*);
|
void kexit(Ureg*);
|
||||||
|
KMap* kmap(uintptr_t pa);
|
||||||
|
void kunmap(KMap*);
|
||||||
#define kmapinval()
|
#define kmapinval()
|
||||||
void lfence(void);
|
void lfence(void);
|
||||||
void links(void);
|
void links(void);
|
||||||
|
#define lockgetpc(l) (l->pc)
|
||||||
int machdom(Mach*);
|
int machdom(Mach*);
|
||||||
void machinit(void);
|
void machinit(void);
|
||||||
void mach0init(void);
|
void mach0init(void);
|
||||||
void mapraminit(uint64_t, uint64_t);
|
void mapraminit(uint64_t, uint64_t);
|
||||||
|
void mathinit(void);
|
||||||
void memdebug(void);
|
void memdebug(void);
|
||||||
void meminit(void);
|
void meminit(void);
|
||||||
int memcolor(uintmem addr, uintmem *sizep);
|
int memcolor(uintmem addr, uintmem *sizep);
|
||||||
|
@ -113,14 +129,18 @@ void memmaprange(uintptr_t, uintmem, uintmem, PTE (*alloc)(usize), PTE);
|
||||||
void memreserve(uintmem, uintmem);
|
void memreserve(uintmem, uintmem);
|
||||||
void mfence(void);
|
void mfence(void);
|
||||||
void mmudump(Proc*);
|
void mmudump(Proc*);
|
||||||
void mmuflushtlb(uint64_t);
|
#define mmuflushtlb() cr3put(cr3get())
|
||||||
void mmuinit(void);
|
void mmuinit(void);
|
||||||
#define mmucachectl(pg, why) USED(pg, why) /* x86 doesn't need it */
|
#define mmucachectl(pg, why) USED(pg, why) /* x86 doesn't need it */
|
||||||
uint64_t mmuphysaddr(uintptr_t);
|
uint64_t mmuphysaddr(uintptr_t);
|
||||||
int mmuwalk(uintptr_t, int, PTE**, uint64_t (*)(usize));
|
uintptr_t* mmuwalk(uintptr_t* table, uintptr_t va, int level, int create);
|
||||||
int multiboot(uint32_t, uint32_t, int);
|
char* mtrr(unsigned long, unsigned long, char *);
|
||||||
|
void mtrrclock(void);
|
||||||
|
int mtrrprint(char *, long);
|
||||||
|
void mtrrsync(void);
|
||||||
|
int multiboot(int);
|
||||||
|
void mwait(void*);
|
||||||
uint32_t mwait32(void*, uint32_t);
|
uint32_t mwait32(void*, uint32_t);
|
||||||
uint64_t mwait64(void*, uint64_t);
|
|
||||||
void ndnr(void);
|
void ndnr(void);
|
||||||
uint8_t nvramread(int);
|
uint8_t nvramread(int);
|
||||||
void nvramwrite(int, uint8_t);
|
void nvramwrite(int, uint8_t);
|
||||||
|
@ -131,6 +151,7 @@ void outs(int, uint16_t);
|
||||||
void outss(int, void*, int);
|
void outss(int, void*, int);
|
||||||
void outl(int, uint32_t);
|
void outl(int, uint32_t);
|
||||||
void outsl(int, void*, int);
|
void outsl(int, void*, int);
|
||||||
|
void patwc(void *a, int n);
|
||||||
void pause(void);
|
void pause(void);
|
||||||
int pciscan(int, Pcidev**);
|
int pciscan(int, Pcidev**);
|
||||||
uint32_t pcibarsize(Pcidev*, int);
|
uint32_t pcibarsize(Pcidev*, int);
|
||||||
|
@ -156,7 +177,9 @@ void pcisetmwi(Pcidev*);
|
||||||
int pcisetpms(Pcidev*, int);
|
int pcisetpms(Pcidev*, int);
|
||||||
uintmem pcixcfgspace(int);
|
uintmem pcixcfgspace(int);
|
||||||
void* pcixcfgaddr(Pcidev*, int);
|
void* pcixcfgaddr(Pcidev*, int);
|
||||||
|
void pmap(uintptr_t *pml4, uintptr_t pa, uintptr_t va, long size);
|
||||||
void printcpufreq(void);
|
void printcpufreq(void);
|
||||||
|
void* rampage(void);
|
||||||
int screenprint(char*, ...); /* debugging */
|
int screenprint(char*, ...); /* debugging */
|
||||||
void sfence(void);
|
void sfence(void);
|
||||||
void spldone(void);
|
void spldone(void);
|
||||||
|
@ -170,11 +193,15 @@ void* sysexecregs(uintptr_t, uint32_t);
|
||||||
uintptr_t sysexecstack(uintptr_t, int);
|
uintptr_t sysexecstack(uintptr_t, int);
|
||||||
void sysprocsetup(Proc*);
|
void sysprocsetup(Proc*);
|
||||||
void tssrsp0(uint64_t);
|
void tssrsp0(uint64_t);
|
||||||
|
uint64_t tscticks(uint64_t *hz);
|
||||||
void trapenable(int, void (*)(Ureg*, void*), void*, char*);
|
void trapenable(int, void (*)(Ureg*, void*), void*, char*);
|
||||||
void trapinit(void);
|
void trapinit(void);
|
||||||
|
void trapinit0(void);
|
||||||
int userureg(Ureg*);
|
int userureg(Ureg*);
|
||||||
void* vmap(uintmem, usize);
|
uintptr_t upaalloc(int size, int align);
|
||||||
void vsvminit(int);
|
void upafree(uintptr_t pa, int size);
|
||||||
|
void upareserve(uintptr_t pa, int size);
|
||||||
|
void* vmap(uintptr_t, usize);
|
||||||
void vunmap(void*, usize);
|
void vunmap(void*, usize);
|
||||||
|
|
||||||
extern Mreg cr0get(void);
|
extern Mreg cr0get(void);
|
||||||
|
@ -186,13 +213,18 @@ extern Mreg cr4get(void);
|
||||||
extern void cr4put(Mreg);
|
extern void cr4put(Mreg);
|
||||||
extern void gdtget(void*);
|
extern void gdtget(void*);
|
||||||
extern void gdtput(int, uint64_t, uint16_t);
|
extern void gdtput(int, uint64_t, uint16_t);
|
||||||
|
extern void lgdt(void*);
|
||||||
extern void idtput(int, uint64_t);
|
extern void idtput(int, uint64_t);
|
||||||
extern uint64_t rdmsr(uint32_t);
|
extern void lidt(void*);
|
||||||
|
extern int rdmsr(uint32_t reg, long* value);
|
||||||
extern uint64_t rdtsc(void);
|
extern uint64_t rdtsc(void);
|
||||||
extern void trput(uint64_t);
|
extern void trput(uint64_t);
|
||||||
extern void wrmsr(uint32_t, uint64_t);
|
extern void wbinvd(void);
|
||||||
|
extern int wrmsr(uint32_t, uint64_t);
|
||||||
int xaddb(void*);
|
int xaddb(void*);
|
||||||
|
|
||||||
|
#define userureg(ur) (((ur)->cs & 3) == 3)
|
||||||
|
|
||||||
extern int islo(void);
|
extern int islo(void);
|
||||||
extern void spldone(void);
|
extern void spldone(void);
|
||||||
extern Mreg splhi(void);
|
extern Mreg splhi(void);
|
||||||
|
@ -222,8 +254,10 @@ void sysrforkret(void);
|
||||||
#define PTR2UINT(p) ((uintptr_t)(p))
|
#define PTR2UINT(p) ((uintptr_t)(p))
|
||||||
#define UINT2PTR(i) ((void*)(i))
|
#define UINT2PTR(i) ((void*)(i))
|
||||||
|
|
||||||
void* KADDR(uintmem);
|
uintptr_t mmu_physical_address(void*);
|
||||||
uintptr_t PADDR(void*);
|
void* mmu_kernel_address(uintptr_t);
|
||||||
|
#define KADDR(a) mmu_kernel_address(a)
|
||||||
|
#define PADDR(a) mmu_physical_address((void*)(a))
|
||||||
|
|
||||||
#define BIOSSEG(a) KADDR(((uint32_t)(a))<<4)
|
#define BIOSSEG(a) KADDR(((uint32_t)(a))<<4)
|
||||||
|
|
||||||
|
@ -235,10 +269,13 @@ extern void millidelay(int);
|
||||||
/*
|
/*
|
||||||
* i8259.c
|
* i8259.c
|
||||||
*/
|
*/
|
||||||
extern int i8259init(int);
|
extern void i8259init(void);
|
||||||
extern int i8259irqdisable(int);
|
extern int i8259disable(int);
|
||||||
extern int i8259irqenable(int);
|
extern int i8259enable(Vctl* v);
|
||||||
extern int i8259isr(int);
|
extern int i8259isr(int);
|
||||||
|
extern void i8259on(void);
|
||||||
|
extern void i8259off(void);
|
||||||
|
extern int i8259vecno(int irq);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sipi.c
|
* sipi.c
|
||||||
|
@ -250,6 +287,9 @@ void basefree(void*, usize);
|
||||||
void physallocinit(void);
|
void physallocinit(void);
|
||||||
void uartpush(void);
|
void uartpush(void);
|
||||||
|
|
||||||
|
void rdrandbuf(void*, uint32_t);
|
||||||
|
|
||||||
|
|
||||||
/* horror */
|
/* horror */
|
||||||
static inline void __clobber_callee_regs(void)
|
static inline void __clobber_callee_regs(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
|
* Copyright (C) 2016-2017 Giacomo Tesio <giacomo@tesio.it>
|
||||||
*
|
*
|
||||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
||||||
* terms in the LICENSE file found in the top-level directory of this
|
* terms in the LICENSE file found in the top-level directory of this
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
/*
|
/*
|
||||||
* SIMD Floating Point.
|
* SIMD Floating Point.
|
||||||
* Assembler support to get at the individual instructions
|
* Assembler support to get at the individual instructions
|
||||||
* is in l64fpu.s.
|
* is in l64fpu.S.
|
||||||
* There are opportunities to be lazier about saving and
|
* There are opportunities to be lazier about saving and
|
||||||
* restoring the state and allocating the storage needed.
|
* restoring the state and allocating the storage needed.
|
||||||
*/
|
*/
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
#include "amd64.h"
|
#include "amd64.h"
|
||||||
#include "ureg.h"
|
#include "ureg.h"
|
||||||
|
@ -87,368 +88,116 @@ extern void _fwait(void);
|
||||||
extern void _ldmxcsr(uint32_t*);
|
extern void _ldmxcsr(uint32_t*);
|
||||||
extern void _stts(void);
|
extern void _stts(void);
|
||||||
|
|
||||||
int
|
|
||||||
fpudevprocio(Proc* proc, void* a, int32_t n, uintptr_t offset, int write)
|
|
||||||
{
|
|
||||||
uint8_t *p;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called from procdevtab.read and procdevtab.write
|
|
||||||
* allow user process access to the FPU registers.
|
|
||||||
* This is the only FPU routine which is called directly
|
|
||||||
* from the port code; it would be nice to have dynamic
|
|
||||||
* creation of entries in the device file trees...
|
|
||||||
*/
|
|
||||||
if(offset >= sizeof(Fxsave))
|
|
||||||
return 0;
|
|
||||||
if((p = proc->FPU.fpusave) == nil)
|
|
||||||
return 0;
|
|
||||||
switch(write){
|
|
||||||
default:
|
|
||||||
if(offset+n > sizeof(Fxsave))
|
|
||||||
n = sizeof(Fxsave) - offset;
|
|
||||||
jehanne_memmove(p+offset, a, n);
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
if(offset+n > sizeof(Fxsave))
|
|
||||||
n = sizeof(Fxsave) - offset;
|
|
||||||
jehanne_memmove(a, p+offset, n);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
fpunotify(Ureg* u)
|
fpclear(void)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Called when a note is about to be delivered to a
|
|
||||||
* user process, usually at the end of a system call.
|
|
||||||
* Note handlers are not allowed to use the FPU so
|
|
||||||
* the state is marked (after saving if necessary) and
|
|
||||||
* checked in the Device Not Available handler.
|
|
||||||
*/
|
|
||||||
if(up->FPU.fpustate == Busy){
|
|
||||||
_fxsave(up->FPU.fpusave);
|
|
||||||
_stts();
|
|
||||||
up->FPU.fpustate = Idle;
|
|
||||||
}
|
|
||||||
up->FPU.fpustate |= Hold;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpunoted(void)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Called from sysnoted() via the machine-dependent
|
|
||||||
* noted() routine.
|
|
||||||
* Clear the flag set above in fpunotify().
|
|
||||||
*/
|
|
||||||
up->FPU.fpustate &= ~Hold;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpusysrfork(Ureg* u)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Called early in the non-interruptible path of
|
|
||||||
* sysrfork() via the machine-dependent syscall() routine.
|
|
||||||
* Save the state so that it can be easily copied
|
|
||||||
* to the child process later.
|
|
||||||
*/
|
|
||||||
if(up->FPU.fpustate != Busy)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_fxsave(up->FPU.fpusave);
|
|
||||||
_stts();
|
|
||||||
up->FPU.fpustate = Idle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpusysrforkchild(Proc* child, Proc* parent)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Called later in sysrfork() via the machine-dependent
|
|
||||||
* sysrforkchild() routine.
|
|
||||||
* Copy the parent FPU state to the child.
|
|
||||||
*/
|
|
||||||
child->FPU.fpustate = parent->FPU.fpustate;
|
|
||||||
child->FPU.fpusave = (void*)((PTR2UINT(up->FPU.fxsave) + 15) & ~15);
|
|
||||||
if(child->FPU.fpustate == Init)
|
|
||||||
return;
|
|
||||||
|
|
||||||
jehanne_memmove(child->FPU.fpusave, parent->FPU.fpusave, sizeof(Fxsave));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpuprocsave(Proc* p)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Called from sched() and sleep() via the machine-dependent
|
|
||||||
* procsave() routine.
|
|
||||||
* About to go in to the scheduler.
|
|
||||||
* If the process wasn't using the FPU
|
|
||||||
* there's nothing to do.
|
|
||||||
*/
|
|
||||||
if(p->FPU.fpustate != Busy)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The process is dead so clear and disable the FPU
|
|
||||||
* and set the state for whoever gets this proc struct
|
|
||||||
* next.
|
|
||||||
*/
|
|
||||||
if(p->state == Moribund){
|
|
||||||
_clts();
|
_clts();
|
||||||
_fnclex();
|
_fnclex();
|
||||||
_stts();
|
_stts();
|
||||||
p->FPU.fpustate = Init;
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fpssesave(FPsave *fps)
|
||||||
|
{
|
||||||
|
Fxsave *fx = (Fxsave*)ROUND(((uintptr_t)fps), FPalign);
|
||||||
|
|
||||||
|
_fxsave(fx);
|
||||||
|
_stts();
|
||||||
|
if(fx != (Fxsave*)fps)
|
||||||
|
memmove((Fxsave*)fps, fx, sizeof(Fxsave));
|
||||||
|
}
|
||||||
|
void
|
||||||
|
fpsserestore(FPsave *fps)
|
||||||
|
{
|
||||||
|
Fxsave *fx = (Fxsave*)ROUND(((uintptr_t)fps), FPalign);
|
||||||
|
|
||||||
|
if(fx != (Fxsave*)fps)
|
||||||
|
memmove(fx, (Fxsave*)fps, sizeof(Fxsave));
|
||||||
|
_clts();
|
||||||
|
_fxrstor(fx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* mathmsg[] =
|
||||||
|
{
|
||||||
|
nil, /* handled below */
|
||||||
|
"denormalized operand",
|
||||||
|
"division by zero",
|
||||||
|
"numeric overflow",
|
||||||
|
"numeric underflow",
|
||||||
|
"precision loss",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
mathnote(unsigned int status, uintptr_t pc)
|
||||||
|
{
|
||||||
|
char *msg, note[ERRMAX];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some attention should probably be paid here to the
|
||||||
|
* exception masks and error summary.
|
||||||
|
*/
|
||||||
|
msg = "unknown exception";
|
||||||
|
for(i = 1; i <= 5; i++){
|
||||||
|
if(!((1<<i) & status))
|
||||||
|
continue;
|
||||||
|
msg = mathmsg[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(status & 0x01){
|
||||||
|
if(status & 0x40){
|
||||||
|
if(status & 0x200)
|
||||||
|
msg = "stack overflow";
|
||||||
|
else
|
||||||
|
msg = "stack underflow";
|
||||||
|
}else
|
||||||
|
msg = "invalid operation";
|
||||||
|
}
|
||||||
|
snprint(note, sizeof note, "sys: fp: %s fppc=%#p status=0x%lux",
|
||||||
|
msg, pc, status);
|
||||||
|
postnote(up, 1, note, NDebug);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* math coprocessor error
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
matherror(Ureg* _, void* __)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Save FPU state to check out the error.
|
||||||
|
*/
|
||||||
|
fpsave(&up->fpsave);
|
||||||
|
up->fpstate = FPinactive;
|
||||||
|
mathnote(up->fpsave.fsw, up->fpsave.rip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIMD error
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
simderror(Ureg *ureg, void* _)
|
||||||
|
{
|
||||||
|
fpsave(&up->fpsave);
|
||||||
|
up->fpstate = FPinactive;
|
||||||
|
mathnote(up->fpsave.mxcsr & 0x3f, ureg->ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* math coprocessor emulation fault
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
mathemu(Ureg *ureg, void* _)
|
||||||
|
{
|
||||||
|
unsigned int status, control;
|
||||||
|
|
||||||
|
if(up->fpstate & FPillegal){
|
||||||
|
/* someone did floating point in a note handler */
|
||||||
|
postnote(up, 1, "sys: floating point in note handler", NDebug);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
switch(up->fpstate){
|
||||||
/*
|
case FPinit:
|
||||||
* Save the FPU state without handling pending
|
|
||||||
* unmasked exceptions and disable. Postnote() can't
|
|
||||||
* be called here as sleep() already has up->rlock,
|
|
||||||
* so the handling of pending exceptions is delayed
|
|
||||||
* until the process runs again and generates a
|
|
||||||
* Device Not Available exception fault to activate
|
|
||||||
* the FPU.
|
|
||||||
*/
|
|
||||||
_fxsave(p->FPU.fpusave);
|
|
||||||
_stts();
|
|
||||||
p->FPU.fpustate = Idle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpuprocrestore(Proc* p)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The process has been rescheduled and is about to run.
|
|
||||||
* Nothing to do here right now. If the process tries to use
|
|
||||||
* the FPU again it will cause a Device Not Available
|
|
||||||
* exception and the state will then be restored.
|
|
||||||
*/
|
|
||||||
USED(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpusysprocsetup(Proc* p)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Disable the FPU.
|
|
||||||
* Called from sysexec() via sysprocsetup() to
|
|
||||||
* set the FPU for the new process.
|
|
||||||
*/
|
|
||||||
if(p->FPU.fpustate != Init){
|
|
||||||
_clts();
|
|
||||||
_fnclex();
|
|
||||||
_stts();
|
|
||||||
p->FPU.fpustate = Init;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
acfpusysprocsetup(Proc *p)
|
|
||||||
{
|
|
||||||
if(p->FPU.fpustate == Init){
|
|
||||||
/* The FPU is initialized in the TC but we must initialize
|
|
||||||
* it in the AC.
|
|
||||||
*/
|
|
||||||
p->FPU.fpustate = Idle;
|
|
||||||
fpusysprocsetup(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
|
||||||
fpunote(void)
|
|
||||||
{
|
|
||||||
uint16_t fsw;
|
|
||||||
Fxsave *fpusave;
|
|
||||||
char *cm;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The Sff bit is sticky, meaning it should be explicitly
|
|
||||||
* cleared or there's no way to tell if the exception was an
|
|
||||||
* invalid operation or a stack fault.
|
|
||||||
*/
|
|
||||||
fpusave = up->FPU.fpusave;
|
|
||||||
fsw = (fpusave->fsw & ~fpusave->fcw) & (Sff|P|U|O|Z|D|I);
|
|
||||||
if(fsw & I){
|
|
||||||
if(fsw & Sff){
|
|
||||||
if(fsw & C1)
|
|
||||||
cm = "Stack Overflow";
|
|
||||||
else
|
|
||||||
cm = "Stack Underflow";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cm = "Invalid Operation";
|
|
||||||
}
|
|
||||||
else if(fsw & D)
|
|
||||||
cm = "Denormal Operand";
|
|
||||||
else if(fsw & Z)
|
|
||||||
cm = "Divide-By-Zero";
|
|
||||||
else if(fsw & O)
|
|
||||||
cm = "Numeric Overflow";
|
|
||||||
else if(fsw & U)
|
|
||||||
cm = "Numeric Underflow";
|
|
||||||
else if(fsw & P)
|
|
||||||
cm = "Precision";
|
|
||||||
else
|
|
||||||
cm = "Unknown";
|
|
||||||
|
|
||||||
jehanne_snprint(up->genbuf, sizeof(up->genbuf),
|
|
||||||
"sys: fp: %s Exception ipo=%#llux fsw=%#ux",
|
|
||||||
cm, fpusave->rip, fsw);
|
|
||||||
return up->genbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
xfpuxf(Ureg* ureg, void* v)
|
|
||||||
{
|
|
||||||
uint32_t mxcsr;
|
|
||||||
Fxsave *fpusave;
|
|
||||||
char *cm;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* #XF - SIMD Floating Point Exception (Vector 18).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Save FPU state to check out the error.
|
|
||||||
*/
|
|
||||||
fpusave = up->FPU.fpusave;
|
|
||||||
_fxsave(fpusave);
|
|
||||||
_stts();
|
|
||||||
up->FPU.fpustate = Idle;
|
|
||||||
|
|
||||||
if(ureg->ip & KZERO)
|
|
||||||
panic("#MF: ip=%#p", ureg->ip);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Notify the user process.
|
|
||||||
* The path here is similar to the x87 path described
|
|
||||||
* in fpupostnote above but without the fpupostnote()
|
|
||||||
* call.
|
|
||||||
*/
|
|
||||||
mxcsr = fpusave->mxcsr;
|
|
||||||
if((mxcsr & (Im|I)) == I)
|
|
||||||
cm = "Invalid Operation";
|
|
||||||
else if((mxcsr & (Dm|D)) == D)
|
|
||||||
cm = "Denormal Operand";
|
|
||||||
else if((mxcsr & (Zm|Z)) == Z)
|
|
||||||
cm = "Divide-By-Zero";
|
|
||||||
else if((mxcsr & (Om|O)) == O)
|
|
||||||
cm = "Numeric Overflow";
|
|
||||||
else if((mxcsr & (Um|U)) == U)
|
|
||||||
cm = "Numeric Underflow";
|
|
||||||
else if((mxcsr & (Pm|P)) == P)
|
|
||||||
cm = "Precision";
|
|
||||||
else
|
|
||||||
cm = "Unknown";
|
|
||||||
|
|
||||||
jehanne_snprint(up->genbuf, sizeof(up->genbuf),
|
|
||||||
"sys: fp: %s Exception mxcsr=%#ux", cm, mxcsr);
|
|
||||||
return up->genbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpuxf(Ureg *ureg, void *p)
|
|
||||||
{
|
|
||||||
char *n;
|
|
||||||
|
|
||||||
n = xfpuxf(ureg, p);
|
|
||||||
if(n != nil)
|
|
||||||
postnote(up, 1, n, NDebug);
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
acfpuxf(Ureg *ureg, void *p)
|
|
||||||
{
|
|
||||||
return xfpuxf(ureg, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
|
||||||
xfpumf(Ureg* ureg, void* v)
|
|
||||||
{
|
|
||||||
Fxsave *fpusave;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* #MF - x87 Floating Point Exception Pending (Vector 16).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Save FPU state to check out the error.
|
|
||||||
*/
|
|
||||||
fpusave = up->FPU.fpusave;
|
|
||||||
_fxsave(fpusave);
|
|
||||||
_stts();
|
|
||||||
up->FPU.fpustate = Idle;
|
|
||||||
|
|
||||||
if(ureg->ip & KZERO)
|
|
||||||
panic("#MF: ip=%#p rip=%#p", ureg->ip, fpusave->rip);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Notify the user process.
|
|
||||||
* The path here is
|
|
||||||
* call trap->fpumf->fpupostnote->postnote
|
|
||||||
* return ->fpupostnote->fpumf->trap
|
|
||||||
* call notify->fpunotify
|
|
||||||
* return ->notify
|
|
||||||
* then either
|
|
||||||
* call pexit
|
|
||||||
* or
|
|
||||||
* return ->trap
|
|
||||||
* return ->user note handler
|
|
||||||
*/
|
|
||||||
return fpunote();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpumf(Ureg *ureg, void *p)
|
|
||||||
{
|
|
||||||
char *n;
|
|
||||||
|
|
||||||
n = xfpumf(ureg, p);
|
|
||||||
if(n != nil)
|
|
||||||
postnote(up, 1, n, NDebug);
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
acfpumf(Ureg *ureg, void *p)
|
|
||||||
{
|
|
||||||
return xfpumf(ureg, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
|
||||||
xfpunm(Ureg* ureg, void* v)
|
|
||||||
{
|
|
||||||
Fxsave *fpusave;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* #NM - Device Not Available (Vector 7).
|
|
||||||
*/
|
|
||||||
if(up == nil)
|
|
||||||
panic("#NM: fpu in kernel: ip %#p\n", ureg->ip);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Someone tried to use the FPU in a note handler.
|
|
||||||
* That's a no-no.
|
|
||||||
*/
|
|
||||||
if(up->FPU.fpustate & Hold)
|
|
||||||
return "sys: floating point in note handler";
|
|
||||||
|
|
||||||
if(ureg->ip & KZERO)
|
|
||||||
panic("#NM: proc %d %s state %d ip %#p\n",
|
|
||||||
up->pid, up->text, up->FPU.fpustate, ureg->ip);
|
|
||||||
|
|
||||||
switch(up->FPU.fpustate){
|
|
||||||
case Busy:
|
|
||||||
default:
|
|
||||||
panic("#NM: state %d ip %#p\n", up->FPU.fpustate, ureg->ip);
|
|
||||||
break;
|
|
||||||
case Init:
|
|
||||||
/*
|
/*
|
||||||
* A process tries to use the FPU for the
|
* A process tries to use the FPU for the
|
||||||
* first time and generates a 'device not available'
|
* first time and generates a 'device not available'
|
||||||
|
@ -460,87 +209,78 @@ xfpunm(Ureg* ureg, void* v)
|
||||||
_clts();
|
_clts();
|
||||||
_fninit();
|
_fninit();
|
||||||
_fwait();
|
_fwait();
|
||||||
_fldcw(&m->FPU.fcw);
|
up->fpsave.fcw = 0x0232;
|
||||||
_ldmxcsr(&m->FPU.mxcsr);
|
_fldcw(&up->fpsave.fcw);
|
||||||
up->FPU.fpusave = (void*)((PTR2UINT(up->FPU.fxsave) + 15) & ~15);
|
up->fpsave.mxcsr = 0x1900;
|
||||||
up->FPU.fpustate = Busy;
|
_ldmxcsr(&up->fpsave.mxcsr);
|
||||||
|
up->fpstate = FPactive;
|
||||||
break;
|
break;
|
||||||
case Idle:
|
case FPinactive:
|
||||||
/*
|
/*
|
||||||
* Before restoring the state, check for any pending
|
* Before restoring the state, check for any pending
|
||||||
* exceptions, there's no way to restore the state without
|
* exceptions, there's no way to restore the state without
|
||||||
* generating an unmasked exception.
|
* generating an unmasked exception.
|
||||||
|
* More attention should probably be paid here to the
|
||||||
|
* exception masks and error summary.
|
||||||
*/
|
*/
|
||||||
fpusave = up->FPU.fpusave;
|
status = up->fpsave.fsw;
|
||||||
if((fpusave->fsw & ~fpusave->fcw) & (Sff|P|U|O|Z|D|I))
|
control = up->fpsave.fcw;
|
||||||
return fpunote();
|
if((status & ~control) & 0x07F){
|
||||||
|
mathnote(status, up->fpsave.rip);
|
||||||
/*
|
break;
|
||||||
* Sff is sticky.
|
}
|
||||||
*/
|
fprestore(&up->fpsave);
|
||||||
fpusave->fcw &= ~Sff;
|
up->fpstate = FPactive;
|
||||||
_clts();
|
break;
|
||||||
_fxrstor(fpusave);
|
case FPactive:
|
||||||
up->FPU.fpustate = Busy;
|
panic("math emu pid %ld %s pc %#p",
|
||||||
|
up->pid, up->text, ureg->ip);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fpunm(Ureg *ureg, void *p)
|
fpprocsetup(Proc* p)
|
||||||
{
|
{
|
||||||
char *n;
|
p->fpstate = FPinit;
|
||||||
|
|
||||||
n = xfpunm(ureg, p);
|
|
||||||
if(n != nil)
|
|
||||||
postnote(up, 1, n, NDebug);
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
acfpunm(Ureg *ureg, void *p)
|
|
||||||
{
|
|
||||||
return xfpunm(ureg, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpuinit(void)
|
|
||||||
{
|
|
||||||
uint64_t r;
|
|
||||||
Fxsave *fxsave;
|
|
||||||
uint8_t buf[sizeof(Fxsave)+15];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It's assumed there is an integrated FPU, so Em is cleared;
|
|
||||||
*/
|
|
||||||
r = cr0get();
|
|
||||||
r &= ~(Ts|Em);
|
|
||||||
r |= Ne|Mp;
|
|
||||||
cr0put(r);
|
|
||||||
|
|
||||||
r = cr4get();
|
|
||||||
r |= Osxmmexcpt|Osfxsr;
|
|
||||||
cr4put(r);
|
|
||||||
|
|
||||||
_fninit();
|
|
||||||
fxsave = (Fxsave*)((PTR2UINT(buf) + 15) & ~15);
|
|
||||||
jehanne_memset(fxsave, 0, sizeof(Fxsave));
|
|
||||||
_fxsave(fxsave);
|
|
||||||
m->FPU.fcw = RCn|PCd|P|U|D;
|
|
||||||
if(fxsave->mxcsrmask == 0)
|
|
||||||
m->FPU.mxcsrmask = 0x0000FFBF;
|
|
||||||
else
|
|
||||||
m->FPU.mxcsrmask = fxsave->mxcsrmask;
|
|
||||||
m->FPU.mxcsr = (Rn|Pm|Um|Dm) & m->FPU.mxcsrmask;
|
|
||||||
_stts();
|
_stts();
|
||||||
|
}
|
||||||
|
|
||||||
if(m->machno != 0)
|
void
|
||||||
return;
|
fpprocfork(Proc *p)
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
|
||||||
|
/* save floating point state */
|
||||||
|
s = splhi();
|
||||||
|
switch(up->fpstate & ~FPillegal){
|
||||||
|
case FPactive:
|
||||||
|
fpsave(&up->fpsave);
|
||||||
|
up->fpstate = FPinactive;
|
||||||
|
case FPinactive:
|
||||||
|
p->fpsave = up->fpsave;
|
||||||
|
p->fpstate = FPinactive;
|
||||||
|
}
|
||||||
|
splx(s);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the exception handlers.
|
* math coprocessor segment overrun
|
||||||
*/
|
*/
|
||||||
trapenable(IdtNM, fpunm, 0, "#NM");
|
static void
|
||||||
trapenable(IdtMF, fpumf, 0, "#MF");
|
mathover(Ureg* _, void* __)
|
||||||
trapenable(IdtXF, fpuxf, 0, "#XF");
|
{
|
||||||
|
pexit("math overrun", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mathinit(void)
|
||||||
|
{
|
||||||
|
trapenable(VectorCERR, matherror, 0, "matherror");
|
||||||
|
if(X86FAMILY(m->cpuidax) == 3)
|
||||||
|
intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
|
||||||
|
trapenable(VectorCNA, mathemu, 0, "mathemu");
|
||||||
|
trapenable(VectorCSO, mathover, 0, "mathover");
|
||||||
|
trapenable(VectorSIMD, simderror, 0, "simderror");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,317 @@
|
||||||
|
#include "u.h"
|
||||||
|
#include "../port/lib.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 8253 timer
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
T0cntr= 0x40, /* counter ports */
|
||||||
|
T1cntr= 0x41, /* ... */
|
||||||
|
T2cntr= 0x42, /* ... */
|
||||||
|
Tmode= 0x43, /* mode port (control word register) */
|
||||||
|
T2ctl= 0x61, /* counter 2 control port */
|
||||||
|
|
||||||
|
/* commands */
|
||||||
|
Latch0= 0x00, /* latch counter 0's value */
|
||||||
|
Load0l= 0x10, /* load counter 0's lsb */
|
||||||
|
Load0m= 0x20, /* load counter 0's msb */
|
||||||
|
Load0= 0x30, /* load counter 0 with 2 bytes */
|
||||||
|
|
||||||
|
Latch1= 0x40, /* latch counter 1's value */
|
||||||
|
Load1l= 0x50, /* load counter 1's lsb */
|
||||||
|
Load1m= 0x60, /* load counter 1's msb */
|
||||||
|
Load1= 0x70, /* load counter 1 with 2 bytes */
|
||||||
|
|
||||||
|
Latch2= 0x80, /* latch counter 2's value */
|
||||||
|
Load2l= 0x90, /* load counter 2's lsb */
|
||||||
|
Load2m= 0xa0, /* load counter 2's msb */
|
||||||
|
Load2= 0xb0, /* load counter 2 with 2 bytes */
|
||||||
|
|
||||||
|
/* 8254 read-back command: everything > pc-at has an 8254 */
|
||||||
|
Rdback= 0xc0, /* readback counters & status */
|
||||||
|
Rdnstat=0x10, /* don't read status */
|
||||||
|
Rdncnt= 0x20, /* don't read counter value */
|
||||||
|
Rd0cntr=0x02, /* read back for which counter */
|
||||||
|
Rd1cntr=0x04,
|
||||||
|
Rd2cntr=0x08,
|
||||||
|
|
||||||
|
/* modes */
|
||||||
|
ModeMsk=0xe,
|
||||||
|
Square= 0x6, /* periodic square wave */
|
||||||
|
Trigger=0x0, /* interrupt on terminal count */
|
||||||
|
Sstrobe=0x8, /* software triggered strobe */
|
||||||
|
|
||||||
|
/* T2ctl bits */
|
||||||
|
T2gate= (1<<0), /* enable T2 counting */
|
||||||
|
T2spkr= (1<<1), /* connect T2 out to speaker */
|
||||||
|
T2out= (1<<5), /* output of T2 */
|
||||||
|
|
||||||
|
Freq= 1193182, /* Real clock frequency */
|
||||||
|
Tickshift=8, /* extra accuracy */
|
||||||
|
MaxPeriod=Freq/HZ,
|
||||||
|
MinPeriod=Freq/(100*HZ),
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct I8253 I8253;
|
||||||
|
struct I8253
|
||||||
|
{
|
||||||
|
Lock;
|
||||||
|
uint32_t period; /* current clock period */
|
||||||
|
|
||||||
|
uint16_t last; /* last value of clock 1 */
|
||||||
|
uint64_t ticks; /* cumulative ticks of counter 1 */
|
||||||
|
|
||||||
|
uint32_t periodset;
|
||||||
|
};
|
||||||
|
static I8253 i8253;
|
||||||
|
|
||||||
|
void
|
||||||
|
i8253reset(void)
|
||||||
|
{
|
||||||
|
int loops, x;
|
||||||
|
|
||||||
|
ilock(&i8253);
|
||||||
|
|
||||||
|
i8253.last = 0;
|
||||||
|
i8253.period = Freq/HZ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enable a 1/HZ interrupt for providing scheduling interrupts
|
||||||
|
*/
|
||||||
|
outb(Tmode, Load0|Square);
|
||||||
|
outb(T0cntr, (Freq/HZ)); /* low byte */
|
||||||
|
outb(T0cntr, (Freq/HZ)>>8); /* high byte */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enable a longer period counter to use as a clock
|
||||||
|
*/
|
||||||
|
outb(Tmode, Load2|Square);
|
||||||
|
outb(T2cntr, 0); /* low byte */
|
||||||
|
outb(T2cntr, 0); /* high byte */
|
||||||
|
x = inb(T2ctl);
|
||||||
|
x |= T2gate;
|
||||||
|
outb(T2ctl, x);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Introduce a little delay to make sure the count is
|
||||||
|
* latched and the timer is counting down; with a fast
|
||||||
|
* enough processor this may not be the case.
|
||||||
|
* The i8254 (which this probably is) has a read-back
|
||||||
|
* command which can be used to make sure the counting
|
||||||
|
* register has been written into the counting element.
|
||||||
|
*/
|
||||||
|
x = (Freq/HZ);
|
||||||
|
for(loops = 0; loops < 100000 && x >= (Freq/HZ); loops++){
|
||||||
|
outb(Tmode, Latch0);
|
||||||
|
x = inb(T0cntr);
|
||||||
|
x |= inb(T0cntr)<<8;
|
||||||
|
}
|
||||||
|
|
||||||
|
iunlock(&i8253);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
i8253init(void)
|
||||||
|
{
|
||||||
|
ioalloc(T0cntr, 4, 0, "i8253");
|
||||||
|
ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");
|
||||||
|
|
||||||
|
i8253reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
guesscpuhz(int aalcycles)
|
||||||
|
{
|
||||||
|
int loops, x, y;
|
||||||
|
uint64_t a, b, cpufreq;
|
||||||
|
|
||||||
|
if(m->machno != 0){
|
||||||
|
m->cpuhz = MACHP(0)->cpuhz;
|
||||||
|
m->cpumhz = MACHP(0)->cpumhz;
|
||||||
|
m->loopconst = MACHP(0)->loopconst;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ilock(&i8253);
|
||||||
|
for(loops = 1000;;loops += 1000) {
|
||||||
|
/*
|
||||||
|
* measure time for the loop
|
||||||
|
*
|
||||||
|
* MOVL loops,CX
|
||||||
|
* aaml1: AAM
|
||||||
|
* LOOP aaml1
|
||||||
|
*
|
||||||
|
* the time for the loop should be independent of external
|
||||||
|
* cache and memory system since it fits in the execution
|
||||||
|
* prefetch buffer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
outb(Tmode, Latch2);
|
||||||
|
cycles(&a);
|
||||||
|
x = inb(T2cntr);
|
||||||
|
x |= inb(T2cntr)<<8;
|
||||||
|
aamloop(loops);
|
||||||
|
outb(Tmode, Latch2);
|
||||||
|
cycles(&b);
|
||||||
|
y = inb(T2cntr);
|
||||||
|
y |= inb(T2cntr)<<8;
|
||||||
|
|
||||||
|
x -= y;
|
||||||
|
if(x < 0)
|
||||||
|
x += 0x10000;
|
||||||
|
|
||||||
|
if(x >= MaxPeriod || loops >= 1000000)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iunlock(&i8253);
|
||||||
|
|
||||||
|
/* avoid division by zero on vmware 7 */
|
||||||
|
if(x == 0)
|
||||||
|
x = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* figure out clock frequency and a loop multiplier for delay().
|
||||||
|
* n.b. counter goes up by 2*Freq
|
||||||
|
*/
|
||||||
|
cpufreq = (long)loops*((aalcycles*2*Freq)/x);
|
||||||
|
m->loopconst = (cpufreq/1000)/aalcycles; /* AAM+LOOP's for 1 ms */
|
||||||
|
|
||||||
|
/* a == b means virtualbox has confused us */
|
||||||
|
if(m->havetsc && b > a){
|
||||||
|
b -= a;
|
||||||
|
b *= 2*Freq;
|
||||||
|
b /= x;
|
||||||
|
m->cyclefreq = b;
|
||||||
|
cpufreq = b;
|
||||||
|
}
|
||||||
|
m->cpuhz = cpufreq;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* round to the nearest megahz
|
||||||
|
*/
|
||||||
|
m->cpumhz = (cpufreq+500000)/1000000L;
|
||||||
|
if(m->cpumhz == 0)
|
||||||
|
m->cpumhz = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
i8253timerset(uint64_t next)
|
||||||
|
{
|
||||||
|
int period;
|
||||||
|
uint32_t want;
|
||||||
|
uint32_t now;
|
||||||
|
|
||||||
|
want = next>>Tickshift;
|
||||||
|
now = i8253.ticks; /* assuming whomever called us just did fastticks() */
|
||||||
|
|
||||||
|
period = want - now;
|
||||||
|
if(period < MinPeriod)
|
||||||
|
period = MinPeriod;
|
||||||
|
else if(period > MaxPeriod)
|
||||||
|
period = MaxPeriod;
|
||||||
|
|
||||||
|
/* hysteresis */
|
||||||
|
if(i8253.period != period){
|
||||||
|
ilock(&i8253);
|
||||||
|
/* load new value */
|
||||||
|
outb(Tmode, Load0|Square);
|
||||||
|
outb(T0cntr, period); /* low byte */
|
||||||
|
outb(T0cntr, period >> 8); /* high byte */
|
||||||
|
|
||||||
|
/* remember period */
|
||||||
|
i8253.period = period;
|
||||||
|
i8253.periodset++;
|
||||||
|
iunlock(&i8253);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
i8253clock(Ureg* ureg, void* _)
|
||||||
|
{
|
||||||
|
timerintr(ureg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
i8253enable(void)
|
||||||
|
{
|
||||||
|
intrenable(IrqCLOCK, i8253clock, 0, BUSUNKNOWN, "clock");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return the total ticks of counter 2. We shift by
|
||||||
|
* 8 to give timesync more wriggle room for interpretation
|
||||||
|
* of the frequency
|
||||||
|
*/
|
||||||
|
uint64_t
|
||||||
|
i8253read(uint64_t *hz)
|
||||||
|
{
|
||||||
|
uint16_t y, x;
|
||||||
|
uint64_t ticks;
|
||||||
|
|
||||||
|
if(hz)
|
||||||
|
*hz = Freq<<Tickshift;
|
||||||
|
|
||||||
|
ilock(&i8253);
|
||||||
|
outb(Tmode, Latch2);
|
||||||
|
y = inb(T2cntr);
|
||||||
|
y |= inb(T2cntr)<<8;
|
||||||
|
|
||||||
|
if(y < i8253.last)
|
||||||
|
x = i8253.last - y;
|
||||||
|
else {
|
||||||
|
x = i8253.last + (0x10000 - y);
|
||||||
|
if (x > 3*MaxPeriod) {
|
||||||
|
outb(Tmode, Load2|Square);
|
||||||
|
outb(T2cntr, 0); /* low byte */
|
||||||
|
outb(T2cntr, 0); /* high byte */
|
||||||
|
y = 0xFFFF;
|
||||||
|
x = i8253.period;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i8253.last = y;
|
||||||
|
i8253.ticks += x>>1;
|
||||||
|
ticks = i8253.ticks;
|
||||||
|
iunlock(&i8253);
|
||||||
|
|
||||||
|
return ticks<<Tickshift;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
delay(int millisecs)
|
||||||
|
{
|
||||||
|
millisecs *= m->loopconst;
|
||||||
|
if(millisecs <= 0)
|
||||||
|
millisecs = 1;
|
||||||
|
aamloop(millisecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
microdelay(int microsecs)
|
||||||
|
{
|
||||||
|
microsecs *= m->loopconst;
|
||||||
|
microsecs /= 1000;
|
||||||
|
if(microsecs <= 0)
|
||||||
|
microsecs = 1;
|
||||||
|
aamloop(microsecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* performance measurement ticks. must be low overhead.
|
||||||
|
* doesn't have to count over a second.
|
||||||
|
*/
|
||||||
|
uint64_t
|
||||||
|
perfticks(void)
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
|
||||||
|
if(m->havetsc)
|
||||||
|
cycles(&x);
|
||||||
|
else
|
||||||
|
x = 0;
|
||||||
|
return x;
|
||||||
|
}
|
|
@ -3,131 +3,102 @@
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 8259 Interrupt Controller and compatibles.
|
* 8259 interrupt controllers
|
||||||
*/
|
*/
|
||||||
enum { /* I/O ports */
|
enum
|
||||||
Cntrl1 = 0x20,
|
{
|
||||||
Cntrl2 = 0xa0,
|
Int0ctl= 0x20, /* control port (ICW1, OCW2, OCW3) */
|
||||||
|
Int0aux= 0x21, /* everything else (ICW2, ICW3, ICW4, OCW1) */
|
||||||
|
Int1ctl= 0xA0, /* control port */
|
||||||
|
Int1aux= 0xA1, /* everything else (ICW2, ICW3, ICW4, OCW1) */
|
||||||
|
|
||||||
Icw1 = 0, /* Initialisation Command Word 1 */
|
Icw1= 0x10, /* select bit in ctl register */
|
||||||
Icw2 = 1,
|
Ocw2= 0x00,
|
||||||
Icw3 = 1,
|
Ocw3= 0x08,
|
||||||
Icw4 = 1,
|
|
||||||
|
|
||||||
Ocw1 = 1, /* Operational Control Word 1 */
|
EOI= 0x20, /* non-specific end of interrupt */
|
||||||
Ocw2 = 0,
|
|
||||||
Ocw3 = 0,
|
|
||||||
|
|
||||||
Imr = Ocw1, /* Interrupt Mask Register */
|
Elcr1= 0x4D0, /* Edge/Level Triggered Register */
|
||||||
Isr = Ocw3, /* In-Service Register */
|
Elcr2= 0x4D1,
|
||||||
Irr = Ocw3, /* Interrupt Request Register */
|
|
||||||
|
|
||||||
Elcr1 = 0x4d0, /* Edge/Level Control Register */
|
|
||||||
Elcr2 = 0x4d1,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { /* Icw1 */
|
|
||||||
Ic4 = 0x01, /* there will be an Icw4 */
|
|
||||||
Icw1sel = 0x10, /* Icw/Ocw select */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { /* Icw3 */
|
|
||||||
Cascaded = 0x04, /* Cntrl1 - Cascaded Mode Enable */
|
|
||||||
SlaveIRQ2 = 0x02, /* Cntrl2 - Slave Identification Code */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { /* Icw4 */
|
|
||||||
Microprocessor = 0x01, /* 80x86-based system */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { /* Ocw2 */
|
|
||||||
Ocw2sel = 0x00, /* Ocw2 select */
|
|
||||||
Eoi = 0x20, /* Non-spcific EOI command */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { /* Ocw3 */
|
|
||||||
Irrread = 0x02, /* Read IRQ register */
|
|
||||||
Isrread = 0x03, /* Read IS register */
|
|
||||||
Ocw3sel = 0x08, /* Ocw3 select */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static Lock i8259lock;
|
static Lock i8259lock;
|
||||||
static int i8259mask = ~0; /* mask of disabled interrupts */
|
static int i8259mask = 0xFFFF; /* disabled interrupts */
|
||||||
static int i8259elcr; /* mask of level interrupts */
|
int i8259elcr; /* mask of level-triggered interrupts */
|
||||||
|
|
||||||
int
|
void
|
||||||
i8259init(int vectorbase)
|
i8259init(void)
|
||||||
{
|
{
|
||||||
int elcr;
|
int x;
|
||||||
|
|
||||||
vectorbase &= ~0x07;
|
|
||||||
|
|
||||||
|
ioalloc(Int0ctl, 2, 0, "i8259.0");
|
||||||
|
ioalloc(Int1ctl, 2, 0, "i8259.1");
|
||||||
ilock(&i8259lock);
|
ilock(&i8259lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Boilerplate to initialise the pair of 8259 controllers,
|
* Set up the first 8259 interrupt processor.
|
||||||
* see one of the Intel bridge datasheets for details,
|
* Make 8259 interrupts start at CPU vector VectorPIC.
|
||||||
* e.g. 82371AB (PIIX4). The default settings are 80x86 mode,
|
* Set the 8259 as master with edge triggered
|
||||||
* edge-sensitive detection, normal EOI, non-buffered and
|
* input with fully nested interrupts.
|
||||||
* cascade mode. Cntrl1 is connected as the master and Cntrl2
|
|
||||||
* as the slave; IRQ2 is used to cascade the two controllers.
|
|
||||||
*/
|
*/
|
||||||
outb(Cntrl1+Icw1, Icw1sel|Ic4);
|
outb(Int0ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered,
|
||||||
outb(Cntrl1+Icw2, vectorbase);
|
ICW4 will be sent */
|
||||||
outb(Cntrl1+Icw3, Cascaded);
|
outb(Int0aux, VectorPIC); /* ICW2 - interrupt vector offset */
|
||||||
outb(Cntrl1+Icw4, Microprocessor);
|
outb(Int0aux, 0x04); /* ICW3 - have slave on level 2 */
|
||||||
|
outb(Int0aux, 0x01); /* ICW4 - 8086 mode, not buffered */
|
||||||
outb(Cntrl2+Icw1, Icw1sel|Ic4);
|
|
||||||
outb(Cntrl2+Icw2, vectorbase+8);
|
|
||||||
outb(Cntrl2+Icw3, SlaveIRQ2);
|
|
||||||
outb(Cntrl2+Icw4, Microprocessor);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the interrupt masks, allowing interrupts
|
* Set up the second 8259 interrupt processor.
|
||||||
* to pass from Cntrl2 to Cntrl1 on IRQ2.
|
* Make 8259 interrupts start at CPU vector VectorPIC+8.
|
||||||
|
* Set the 8259 as slave with edge triggered
|
||||||
|
* input with fully nested interrupts.
|
||||||
*/
|
*/
|
||||||
i8259mask &= ~(1<<2);
|
outb(Int1ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered,
|
||||||
outb(Cntrl2+Imr, (i8259mask>>8) & 0xff);
|
ICW4 will be sent */
|
||||||
outb(Cntrl1+Imr, i8259mask & 0xff);
|
outb(Int1aux, VectorPIC+8); /* ICW2 - interrupt vector offset */
|
||||||
|
outb(Int1aux, 0x02); /* ICW3 - I am a slave on level 2 */
|
||||||
outb(Cntrl1+Ocw2, Ocw2sel|Eoi);
|
outb(Int1aux, 0x01); /* ICW4 - 8086 mode, not buffered */
|
||||||
outb(Cntrl2+Ocw2, Ocw2sel|Eoi);
|
outb(Int1aux, (i8259mask>>8) & 0xFF);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set Ocw3 to return the ISR when read for i8259isr()
|
* pass #2 8259 interrupts to #1
|
||||||
* (after initialisation status read is set to return the IRR).
|
*/
|
||||||
|
i8259mask &= ~0x04;
|
||||||
|
outb(Int0aux, i8259mask & 0xFF);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set Ocw3 to return the ISR when ctl read.
|
||||||
|
* After initialisation status read is set to IRR.
|
||||||
* Read IRR first to possibly deassert an outstanding
|
* Read IRR first to possibly deassert an outstanding
|
||||||
* interrupt.
|
* interrupt.
|
||||||
*/
|
*/
|
||||||
inb(Cntrl1+Irr);
|
inb(Int0ctl);
|
||||||
outb(Cntrl1+Ocw3, Ocw3sel|Isrread);
|
outb(Int0ctl, Ocw3|0x03);
|
||||||
inb(Cntrl2+Irr);
|
inb(Int1ctl);
|
||||||
outb(Cntrl2+Ocw3, Ocw3sel|Isrread);
|
outb(Int1ctl, Ocw3|0x03);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for Edge/Level Control register.
|
* Check for Edge/Level register.
|
||||||
* This check may not work for all chipsets.
|
* This check may not work for all chipsets.
|
||||||
* First try a non-intrusive test - the bits for
|
* First try a non-intrusive test - the bits for
|
||||||
* IRQs 13, 8, 2, 1 and 0 must be edge (0). If
|
* IRQs 13, 8, 2, 1 and 0 must be edge (0). If
|
||||||
* that's OK try a R/W test.
|
* that's OK try a R/W test.
|
||||||
*/
|
*/
|
||||||
elcr = (inb(Elcr2)<<8)|inb(Elcr1);
|
x = (inb(Elcr2)<<8)|inb(Elcr1);
|
||||||
if(!(elcr & 0x2107)){
|
if(!(x & 0x2107)){
|
||||||
outb(Elcr1, 0);
|
outb(Elcr1, 0);
|
||||||
if(inb(Elcr1) == 0){
|
if(inb(Elcr1) == 0){
|
||||||
outb(Elcr1, 0x20);
|
outb(Elcr1, 0x20);
|
||||||
if(inb(Elcr1) == 0x20)
|
if(inb(Elcr1) == 0x20)
|
||||||
i8259elcr = elcr;
|
i8259elcr = x;
|
||||||
outb(Elcr1, elcr & 0xff);
|
outb(Elcr1, x & 0xFF);
|
||||||
|
print("ELCR: %4.4uX\n", i8259elcr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iunlock(&i8259lock);
|
iunlock(&i8259lock);
|
||||||
|
|
||||||
return vectorbase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -135,25 +106,108 @@ i8259isr(int vno)
|
||||||
{
|
{
|
||||||
int irq, isr;
|
int irq, isr;
|
||||||
|
|
||||||
if(vno < IdtPIC || vno > IdtPIC+15)
|
if(vno < VectorPIC || vno > VectorPIC+MaxIrqPIC)
|
||||||
return 0;
|
return 0;
|
||||||
irq = vno-IdtPIC;
|
irq = vno-VectorPIC;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Collect the interrupt status,
|
* tell the 8259 that we're done with the
|
||||||
* acknowledge the interrupt and return whether
|
* highest level interrupt (interrupts are still
|
||||||
* the acknowledged interrupt was the correct
|
* off at this point)
|
||||||
* one (this could be better but it's not really
|
|
||||||
* used).
|
|
||||||
*/
|
*/
|
||||||
ilock(&i8259lock);
|
ilock(&i8259lock);
|
||||||
isr = inb(Cntrl1+Isr);
|
isr = inb(Int0ctl);
|
||||||
outb(Cntrl1+Ocw2, Ocw2sel|Eoi);
|
outb(Int0ctl, EOI);
|
||||||
if(irq >= 8){
|
if(irq >= 8){
|
||||||
isr |= inb(Cntrl2+Isr)<<8;
|
isr |= inb(Int1ctl)<<8;
|
||||||
outb(Cntrl2+Ocw2, Ocw2sel|Eoi);
|
outb(Int1ctl, EOI);
|
||||||
}
|
}
|
||||||
iunlock(&i8259lock);
|
iunlock(&i8259lock);
|
||||||
|
|
||||||
return isr & (1<<irq);
|
return isr & (1<<irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
i8259enable(Vctl* v)
|
||||||
|
{
|
||||||
|
int irq, irqbit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given an IRQ, enable the corresponding interrupt in the i8259
|
||||||
|
* and return the vector to be used. The i8259 is set to use a fixed
|
||||||
|
* range of vectors starting at VectorPIC.
|
||||||
|
*/
|
||||||
|
irq = v->irq;
|
||||||
|
if(irq < 0 || irq > MaxIrqPIC){
|
||||||
|
print("i8259enable: irq %d out of range\n", irq);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
irqbit = 1<<irq;
|
||||||
|
|
||||||
|
ilock(&i8259lock);
|
||||||
|
if(!(i8259mask & irqbit) && !(i8259elcr & irqbit)){
|
||||||
|
print("i8259enable: irq %d shared but not level\n", irq);
|
||||||
|
iunlock(&i8259lock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
i8259mask &= ~irqbit;
|
||||||
|
if(irq < 8)
|
||||||
|
outb(Int0aux, i8259mask & 0xFF);
|
||||||
|
else
|
||||||
|
outb(Int1aux, (i8259mask>>8) & 0xFF);
|
||||||
|
|
||||||
|
if(i8259elcr & irqbit)
|
||||||
|
v->eoi = i8259isr;
|
||||||
|
else
|
||||||
|
v->isr = i8259isr;
|
||||||
|
iunlock(&i8259lock);
|
||||||
|
|
||||||
|
return VectorPIC+irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
i8259vecno(int irq)
|
||||||
|
{
|
||||||
|
return VectorPIC+irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
i8259disable(int irq)
|
||||||
|
{
|
||||||
|
int irqbit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given an IRQ, disable the corresponding interrupt
|
||||||
|
* in the 8259.
|
||||||
|
*/
|
||||||
|
if(irq < 0 || irq > MaxIrqPIC){
|
||||||
|
print("i8259disable: irq %d out of range\n", irq);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
irqbit = 1<<irq;
|
||||||
|
|
||||||
|
ilock(&i8259lock);
|
||||||
|
if(!(i8259mask & irqbit)){
|
||||||
|
i8259mask |= irqbit;
|
||||||
|
if(irq < 8)
|
||||||
|
outb(Int0aux, i8259mask & 0xFF);
|
||||||
|
else
|
||||||
|
outb(Int1aux, (i8259mask>>8) & 0xFF);
|
||||||
|
}
|
||||||
|
iunlock(&i8259lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
i8259on(void)
|
||||||
|
{
|
||||||
|
outb(Int0aux, i8259mask&0xFF);
|
||||||
|
outb(Int1aux, (i8259mask>>8)&0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
i8259off(void)
|
||||||
|
{
|
||||||
|
outb(Int0aux, 0xFF);
|
||||||
|
outb(Int1aux, 0xFF);
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,11 @@
|
||||||
* in the LICENSE file.
|
* in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define X86STEPPING(x) ((x) & 0x0F)
|
||||||
|
/* incorporates extended-model and -family bits */
|
||||||
|
#define X86MODEL(x) ((((x)>>4) & 0x0F) | (((x)>>16) & 0x0F)<<4)
|
||||||
|
#define X86FAMILY(x) ((((x)>>8) & 0x0F) | (((x)>>20) & 0xFF)<<4)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
VectorNMI = 2, /* non-maskable interrupt */
|
VectorNMI = 2, /* non-maskable interrupt */
|
||||||
VectorBPT = 3, /* breakpoint */
|
VectorBPT = 3, /* breakpoint */
|
||||||
|
@ -14,9 +19,14 @@ enum {
|
||||||
VectorCNA = 7, /* coprocessor not available */
|
VectorCNA = 7, /* coprocessor not available */
|
||||||
Vector2F = 8, /* double fault */
|
Vector2F = 8, /* double fault */
|
||||||
VectorCSO = 9, /* coprocessor segment overrun */
|
VectorCSO = 9, /* coprocessor segment overrun */
|
||||||
|
VectorSNP = 11, /* segment not present */
|
||||||
|
VectorGPF = 13, /* general protection fault */
|
||||||
VectorPF = 14, /* page fault */
|
VectorPF = 14, /* page fault */
|
||||||
Vector15 = 15, /* reserved */
|
Vector15 = 15, /* reserved */
|
||||||
VectorCERR = 16, /* coprocessor error */
|
VectorCERR = 16, /* coprocessor error */
|
||||||
|
VectorAC = 17, /* alignment check */
|
||||||
|
VectorMC = 18, /* machine check */
|
||||||
|
VectorSIMD = 19, /* simd error */
|
||||||
|
|
||||||
VectorPIC = 32, /* external i8259 interrupts */
|
VectorPIC = 32, /* external i8259 interrupts */
|
||||||
IrqCLOCK = 0,
|
IrqCLOCK = 0,
|
||||||
|
@ -34,12 +44,12 @@ enum {
|
||||||
MaxIrqPIC = 15,
|
MaxIrqPIC = 15,
|
||||||
|
|
||||||
VectorLAPIC = VectorPIC+16, /* local APIC interrupts */
|
VectorLAPIC = VectorPIC+16, /* local APIC interrupts */
|
||||||
IrqLINT0 = VectorLAPIC+0,
|
IrqLINT0 = VectorLAPIC+0, /* LINT[01] must be offsets 0 and 1 */
|
||||||
IrqLINT1 = VectorLAPIC+1,
|
IrqLINT1 = VectorLAPIC+1,
|
||||||
IrqTIMER = VectorLAPIC+2,
|
IrqTIMER = VectorLAPIC+2,
|
||||||
IrqERROR = VectorLAPIC+3,
|
IrqERROR = VectorLAPIC+3,
|
||||||
IrqPCINT = VectorLAPIC+4,
|
IrqPCINT = VectorLAPIC+4,
|
||||||
IrqSPURIOUS = VectorLAPIC+15,
|
IrqSPURIOUS = VectorLAPIC+15, /* must have bits [3-0] == 0x0F */
|
||||||
MaxIrqLAPIC = VectorLAPIC+15,
|
MaxIrqLAPIC = VectorLAPIC+15,
|
||||||
|
|
||||||
VectorSYSCALL = 64,
|
VectorSYSCALL = 64,
|
||||||
|
@ -69,20 +79,15 @@ enum {
|
||||||
typedef struct Vctl {
|
typedef struct Vctl {
|
||||||
Vctl* next; /* handlers on this vector */
|
Vctl* next; /* handlers on this vector */
|
||||||
|
|
||||||
int isintr; /* interrupt or fault/trap */
|
|
||||||
int affinity; /* processor affinity (-1 for none) */
|
|
||||||
|
|
||||||
int irq;
|
|
||||||
void (*f)(Ureg*, void*); /* handler to call */
|
|
||||||
void* a; /* argument to call it with */
|
|
||||||
int tbdf;
|
|
||||||
char name[KNAMELEN]; /* of driver */
|
char name[KNAMELEN]; /* of driver */
|
||||||
char *type;
|
int isintr; /* interrupt or fault/trap */
|
||||||
|
int irq;
|
||||||
|
int tbdf;
|
||||||
int (*isr)(int); /* get isr bit for this irq */
|
int (*isr)(int); /* get isr bit for this irq */
|
||||||
int (*eoi)(int); /* eoi */
|
int (*eoi)(int); /* eoi */
|
||||||
int (*mask)(Vctl*, int); /* interrupt enable returns masked vector */
|
|
||||||
int vno;
|
void (*f)(Ureg*, void*); /* handler to call */
|
||||||
|
void* a; /* argument to call it with */
|
||||||
} Vctl;
|
} Vctl;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -139,8 +144,7 @@ enum { /* type 0 and type 1 pre-defined header */
|
||||||
PciBAR0 = 0x10, /* base address */
|
PciBAR0 = 0x10, /* base address */
|
||||||
PciBAR1 = 0x14,
|
PciBAR1 = 0x14,
|
||||||
|
|
||||||
PciCP = 0x34, /* capabilities pointer */
|
PciCAP = 0x34, /* capabilities pointer */
|
||||||
|
|
||||||
PciINTL = 0x3C, /* interrupt line */
|
PciINTL = 0x3C, /* interrupt line */
|
||||||
PciINTP = 0x3D, /* interrupt pin */
|
PciINTP = 0x3D, /* interrupt pin */
|
||||||
};
|
};
|
||||||
|
@ -197,7 +201,7 @@ enum {
|
||||||
enum { /* type 0 pre-defined header */
|
enum { /* type 0 pre-defined header */
|
||||||
PciCIS = 0x28, /* cardbus CIS pointer */
|
PciCIS = 0x28, /* cardbus CIS pointer */
|
||||||
PciSVID = 0x2C, /* subsystem vendor ID */
|
PciSVID = 0x2C, /* subsystem vendor ID */
|
||||||
PciSID = 0x2E, /* cardbus CIS pointer */
|
PciSID = 0x2E, /* subsystem ID */
|
||||||
PciEBAR0 = 0x30, /* expansion ROM base address */
|
PciEBAR0 = 0x30, /* expansion ROM base address */
|
||||||
PciMGNT = 0x3E, /* burst period length */
|
PciMGNT = 0x3E, /* burst period length */
|
||||||
PciMLT = 0x3F, /* maximum latency between bursts */
|
PciMLT = 0x3F, /* maximum latency between bursts */
|
||||||
|
@ -274,8 +278,6 @@ struct Pcidev
|
||||||
int tbdf; /* type+bus+device+function */
|
int tbdf; /* type+bus+device+function */
|
||||||
uint16_t vid; /* vendor ID */
|
uint16_t vid; /* vendor ID */
|
||||||
uint16_t did; /* device ID */
|
uint16_t did; /* device ID */
|
||||||
uint16_t svid; /* subsystem vid */
|
|
||||||
uint16_t sdid; /* subsystem did */
|
|
||||||
|
|
||||||
uint16_t pcr;
|
uint16_t pcr;
|
||||||
|
|
||||||
|
@ -308,7 +310,12 @@ struct Pcidev
|
||||||
} ioa, mema;
|
} ioa, mema;
|
||||||
|
|
||||||
int pmrb; /* power management register block */
|
int pmrb; /* power management register block */
|
||||||
void* xcfg; /* PCIe configuration block */
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* vendor ids */
|
||||||
|
Vintel = 0x8086,
|
||||||
|
Vmyricom= 0x14c1,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PCIWINDOW 0
|
#define PCIWINDOW 0
|
||||||
|
@ -319,4 +326,110 @@ struct Pcidev
|
||||||
#define PCIWADDRL(va) ((uint32_t)PCIWADDR64(va))
|
#define PCIWADDRL(va) ((uint32_t)PCIWADDR64(va))
|
||||||
#define PCIWADDRH(va) ((uint32_t)(PCIWADDR64(va)>>32))
|
#define PCIWADDRH(va) ((uint32_t)(PCIWADDR64(va)>>32))
|
||||||
|
|
||||||
|
/* SMBus transactions */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SMBquick, /* sends address only */
|
||||||
|
|
||||||
|
/* write */
|
||||||
|
SMBsend, /* sends address and cmd */
|
||||||
|
SMBbytewrite, /* sends address and cmd and 1 byte */
|
||||||
|
SMBwordwrite, /* sends address and cmd and 2 bytes */
|
||||||
|
|
||||||
|
/* read */
|
||||||
|
SMBrecv, /* sends address, recvs 1 byte */
|
||||||
|
SMBbyteread, /* sends address and cmd, recv's byte */
|
||||||
|
SMBwordread, /* sends address and cmd, recv's 2 bytes */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SMBus SMBus;
|
||||||
|
struct SMBus {
|
||||||
|
QLock; /* mutex */
|
||||||
|
Rendez r; /* rendezvous point for completion interrupts */
|
||||||
|
void *arg; /* implementation dependent */
|
||||||
|
uint32_t base; /* port or memory base of smbus */
|
||||||
|
int busy;
|
||||||
|
void (*transact)(SMBus*, int, int, int, uint8_t*);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCMCIA support code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct PCMslot PCMslot;
|
||||||
|
typedef struct PCMconftab PCMconftab;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map between ISA memory space and PCMCIA card memory space.
|
||||||
|
*/
|
||||||
|
struct PCMmap {
|
||||||
|
uint32_t ca; /* card address */
|
||||||
|
uint32_t cea; /* card end address */
|
||||||
|
uint32_t isa; /* ISA address */
|
||||||
|
int len; /* length of the ISA area */
|
||||||
|
int attr; /* attribute memory */
|
||||||
|
int ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* configuration table entry */
|
||||||
|
struct PCMconftab
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
uint16_t irqs; /* legal irqs */
|
||||||
|
uint8_t irqtype;
|
||||||
|
uint8_t bit16; /* true for 16 bit access */
|
||||||
|
struct {
|
||||||
|
uint32_t start;
|
||||||
|
uint32_t len;
|
||||||
|
} io[16];
|
||||||
|
int nio;
|
||||||
|
uint8_t vpp1;
|
||||||
|
uint8_t vpp2;
|
||||||
|
uint8_t memwait;
|
||||||
|
uint32_t maxwait;
|
||||||
|
uint32_t readywait;
|
||||||
|
uint32_t otherwait;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* a card slot */
|
||||||
|
struct PCMslot
|
||||||
|
{
|
||||||
|
Lock;
|
||||||
|
int ref;
|
||||||
|
|
||||||
|
void *cp; /* controller for this slot */
|
||||||
|
long memlen; /* memory length */
|
||||||
|
uint8_t base; /* index register base */
|
||||||
|
uint8_t slotno; /* slot number */
|
||||||
|
|
||||||
|
/* status */
|
||||||
|
uint8_t special; /* in use for a special device */
|
||||||
|
uint8_t already; /* already inited */
|
||||||
|
uint8_t occupied;
|
||||||
|
uint8_t battery;
|
||||||
|
uint8_t wrprot;
|
||||||
|
uint8_t powered;
|
||||||
|
uint8_t configed;
|
||||||
|
uint8_t enabled;
|
||||||
|
uint8_t busy;
|
||||||
|
|
||||||
|
/* cis info */
|
||||||
|
uint32_t msec; /* time of last slotinfo call */
|
||||||
|
char verstr[512]; /* version string */
|
||||||
|
int ncfg; /* number of configurations */
|
||||||
|
struct {
|
||||||
|
uint16_t cpresent; /* config registers present */
|
||||||
|
uint32_t caddr; /* relative address of config registers */
|
||||||
|
} cfg[8];
|
||||||
|
int nctab; /* number of config table entries */
|
||||||
|
PCMconftab ctab[8];
|
||||||
|
PCMconftab *def; /* default conftab */
|
||||||
|
|
||||||
|
/* memory maps */
|
||||||
|
Lock mlock; /* lock down the maps */
|
||||||
|
int time;
|
||||||
|
PCMmap mmap[4]; /* maps, last is always for the kernel */
|
||||||
|
};
|
||||||
|
|
||||||
#pragma varargck type "T" int
|
#pragma varargck type "T" int
|
||||||
|
#pragma varargck type "T" uint
|
||||||
|
|
|
@ -1,595 +0,0 @@
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
|
|
||||||
#include "apic.h"
|
|
||||||
#include "io.h"
|
|
||||||
#include "adr.h"
|
|
||||||
|
|
||||||
typedef struct Rbus Rbus;
|
|
||||||
typedef struct Rdt Rdt;
|
|
||||||
|
|
||||||
struct Rbus {
|
|
||||||
Rbus *next;
|
|
||||||
int bustype;
|
|
||||||
int devno;
|
|
||||||
Rdt *rdt;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Rdt {
|
|
||||||
IOapic *apic;
|
|
||||||
int intin;
|
|
||||||
uint32_t lo;
|
|
||||||
|
|
||||||
int ref; /* could map to multiple busses */
|
|
||||||
int enabled; /* times enabled */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { /* IOAPIC registers */
|
|
||||||
Ioregsel = 0x00, /* indirect register address */
|
|
||||||
Iowin = 0x04, /* indirect register data */
|
|
||||||
Ioipa = 0x08, /* IRQ Pin Assertion */
|
|
||||||
Ioeoi = 0x10, /* EOI */
|
|
||||||
|
|
||||||
IOapicid = 0x00, /* Identification */
|
|
||||||
IOapicver = 0x01, /* Version */
|
|
||||||
IOapicarb = 0x02, /* Arbitration */
|
|
||||||
Ioabcfg = 0x03, /* Boot Configuration */
|
|
||||||
Ioredtbl = 0x10, /* Redirection Table */
|
|
||||||
};
|
|
||||||
|
|
||||||
static Rdt rdtarray[Nrdt];
|
|
||||||
static int nrdtarray;
|
|
||||||
static int gsib;
|
|
||||||
static Rbus* rdtbus[Nbus];
|
|
||||||
static Rdt* rdtvecno[IdtMAX+1];
|
|
||||||
static int dfpolicy = 1; /* round-robin */
|
|
||||||
|
|
||||||
static Lock idtnolock;
|
|
||||||
static int idtno = IdtIOAPIC;
|
|
||||||
|
|
||||||
static IOapic xioapic[Napic];
|
|
||||||
static int isabusno = -1;
|
|
||||||
|
|
||||||
/* BOTCH: no need for this concept; we've got the bustype */
|
|
||||||
static void
|
|
||||||
ioapicisabus(int busno)
|
|
||||||
{
|
|
||||||
if(isabusno != -1){
|
|
||||||
if(busno == isabusno)
|
|
||||||
return;
|
|
||||||
jehanne_print("ioapic: isabus redefined: %d ↛ %d\n", isabusno, busno);
|
|
||||||
// return;
|
|
||||||
}
|
|
||||||
DBG("ioapic: isa busno %d\n", busno);
|
|
||||||
isabusno = busno;
|
|
||||||
}
|
|
||||||
|
|
||||||
IOapic*
|
|
||||||
ioapiclookup(uint32_t id)
|
|
||||||
{
|
|
||||||
IOapic *a;
|
|
||||||
|
|
||||||
if(id > nelem(xioapic))
|
|
||||||
return nil;
|
|
||||||
a = xioapic + id;
|
|
||||||
if(a->useable)
|
|
||||||
return a;
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
gsitoapicid(int gsi, uint32_t *intin)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
IOapic *a;
|
|
||||||
|
|
||||||
for(i=0; i<Napic; i++){
|
|
||||||
a = xioapic + i;
|
|
||||||
if(!a->useable)
|
|
||||||
continue;
|
|
||||||
if(gsi >= a->gsib && gsi < a->gsib+a->nrdt){
|
|
||||||
if(intin != nil)
|
|
||||||
*intin = gsi - a->gsib;
|
|
||||||
return a - xioapic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// jehanne_print("gsitoapicid: no ioapic found for gsi %d\n", gsi);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rtblget(IOapic* apic, int sel, uint32_t* hi, uint32_t* lo)
|
|
||||||
{
|
|
||||||
sel = Ioredtbl + 2*sel;
|
|
||||||
|
|
||||||
apic->addr[Ioregsel] = sel+1;
|
|
||||||
*hi = apic->addr[Iowin];
|
|
||||||
apic->addr[Ioregsel] = sel;
|
|
||||||
*lo = apic->addr[Iowin];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rtblput(IOapic* apic, int sel, uint32_t hi, uint32_t lo)
|
|
||||||
{
|
|
||||||
sel = Ioredtbl + 2*sel;
|
|
||||||
|
|
||||||
apic->addr[Ioregsel] = sel+1;
|
|
||||||
apic->addr[Iowin] = hi;
|
|
||||||
apic->addr[Ioregsel] = sel;
|
|
||||||
apic->addr[Iowin] = lo;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rdt*
|
|
||||||
rdtlookup(IOapic *apic, int intin)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Rdt *r;
|
|
||||||
|
|
||||||
for(i = 0; i < nrdtarray; i++){
|
|
||||||
r = rdtarray + i;
|
|
||||||
if(apic == r->apic && intin == r->intin)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ioapicintrinit(int bustype, int busno, int apicno, int intin, int devno, uint32_t lo)
|
|
||||||
{
|
|
||||||
Rbus *rbus;
|
|
||||||
Rdt *rdt;
|
|
||||||
IOapic *apic;
|
|
||||||
|
|
||||||
if(busno >= Nbus || apicno >= Napic || nrdtarray >= Nrdt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(bustype == BusISA)
|
|
||||||
ioapicisabus(busno);
|
|
||||||
|
|
||||||
apic = &xioapic[apicno];
|
|
||||||
if(!apic->useable || intin >= apic->nrdt)
|
|
||||||
panic("ioapic: intrinit: usable %d nrdt %d: bus %d apic %d intin %d dev %d lo %.8ux\n",
|
|
||||||
apic->useable, apic->nrdt, busno, apicno, intin, devno, lo);
|
|
||||||
|
|
||||||
rdt = rdtlookup(apic, intin);
|
|
||||||
if(rdt == nil){
|
|
||||||
if(nrdtarray == nelem(rdtarray)){
|
|
||||||
jehanne_print("ioapic: intrinit: rdtarray too small\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rdt = &rdtarray[nrdtarray++];
|
|
||||||
rdt->apic = apic;
|
|
||||||
rdt->intin = intin;
|
|
||||||
rdt->lo = lo;
|
|
||||||
}else{
|
|
||||||
if(lo != rdt->lo){
|
|
||||||
if(bustype == BusISA && intin < 16 && lo == (Im|IPhigh|TMedge)){
|
|
||||||
DBG("override: isa %d %.8ux\n", intin, rdt->lo);
|
|
||||||
return; /* expected; default was overridden*/
|
|
||||||
}
|
|
||||||
jehanne_print("multiple irq botch type %d bus %d %d/%d/%d lo %.8ux vs %.8ux\n",
|
|
||||||
bustype, busno, apicno, intin, devno, lo, rdt->lo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DBG("dup rdt %d %d %d %d %.8ux\n", busno, apicno, intin, devno, lo);
|
|
||||||
}
|
|
||||||
rdt->ref++;
|
|
||||||
rbus = jehanne_malloc(sizeof(*rbus));
|
|
||||||
rbus->rdt = rdt;
|
|
||||||
rbus->bustype = bustype;
|
|
||||||
rbus->devno = devno;
|
|
||||||
rbus->next = rdtbus[busno];
|
|
||||||
rdtbus[busno] = rbus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* deal with ioapics at the same physical address. seen on
|
|
||||||
* certain supermicro atom systems. the hope is that only
|
|
||||||
* one will be used, and it will be the second one initialized.
|
|
||||||
* (the pc kernel ignores this issue.) it could be that mp and
|
|
||||||
* acpi have different numbering?
|
|
||||||
*/
|
|
||||||
static IOapic*
|
|
||||||
dupaddr(uintmem pa)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
IOapic *p;
|
|
||||||
|
|
||||||
for(i = 0; i < nelem(xioapic); i++){
|
|
||||||
p = xioapic + i;
|
|
||||||
if(p->paddr == pa)
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
IOapic*
|
|
||||||
ioapicinit(int id, int ibase, uintmem pa)
|
|
||||||
{
|
|
||||||
IOapic *apic, *p;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mark the IOAPIC useable if it has a good ID
|
|
||||||
* and the registers can be mapped.
|
|
||||||
*/
|
|
||||||
if(id >= Napic)
|
|
||||||
return nil;
|
|
||||||
if((apic = xioapic+id)->useable)
|
|
||||||
return apic;
|
|
||||||
|
|
||||||
if((p = dupaddr(pa)) != nil){
|
|
||||||
jehanne_print("ioapic%d: same pa as apic%ld\n", id, p-xioapic);
|
|
||||||
if(ibase != -1)
|
|
||||||
return nil; /* mp irqs reference mp apic#s */
|
|
||||||
apic->addr = p->addr;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
//adrmapck(pa, 1024, Ammio, Mfree, Cnone); /* not in adr? */ /* TO DO */
|
|
||||||
if((apic->addr = vmap(pa, 1024)) == nil){
|
|
||||||
jehanne_print("ioapic%d: can't vmap %#P\n", id, pa);
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
apic->useable = 1;
|
|
||||||
apic->paddr = pa;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialise the I/O APIC.
|
|
||||||
* The MultiProcessor Specification says it is the
|
|
||||||
* responsibility of the O/S to set the APIC ID.
|
|
||||||
*/
|
|
||||||
lock(apic);
|
|
||||||
apic->addr[Ioregsel] = IOapicver;
|
|
||||||
apic->nrdt = ((apic->addr[Iowin]>>16) & 0xff) + 1;
|
|
||||||
if(ibase != -1)
|
|
||||||
apic->gsib = ibase;
|
|
||||||
else{
|
|
||||||
apic->gsib = gsib;
|
|
||||||
gsib += apic->nrdt;
|
|
||||||
}
|
|
||||||
apic->addr[Ioregsel] = IOapicid;
|
|
||||||
apic->addr[Iowin] = id<<24;
|
|
||||||
unlock(apic);
|
|
||||||
|
|
||||||
return apic;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iordtdump(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Rbus *rbus;
|
|
||||||
Rdt *rdt;
|
|
||||||
|
|
||||||
if(!DBGFLG)
|
|
||||||
return;
|
|
||||||
for(i = 0; i < Nbus; i++){
|
|
||||||
if((rbus = rdtbus[i]) == nil)
|
|
||||||
continue;
|
|
||||||
jehanne_print("iointr bus %d:\n", i);
|
|
||||||
for(; rbus != nil; rbus = rbus->next){
|
|
||||||
rdt = rbus->rdt;
|
|
||||||
jehanne_print(" apic %ld devno %#ux (%d %d) intin %d lo %#ux ref %d\n",
|
|
||||||
rdt->apic-xioapic, rbus->devno, rbus->devno>>2,
|
|
||||||
rbus->devno & 0x03, rdt->intin, rdt->lo, rdt->ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ioapicdump(void)
|
|
||||||
{
|
|
||||||
int i, n;
|
|
||||||
IOapic *apic;
|
|
||||||
uint32_t hi, lo;
|
|
||||||
|
|
||||||
if(!DBGFLG)
|
|
||||||
return;
|
|
||||||
for(i = 0; i < Napic; i++){
|
|
||||||
apic = &xioapic[i];
|
|
||||||
if(!apic->useable || apic->addr == 0)
|
|
||||||
continue;
|
|
||||||
jehanne_print("ioapic %d addr %#p nrdt %d ibase %d\n",
|
|
||||||
i, apic->addr, apic->nrdt, apic->gsib);
|
|
||||||
for(n = 0; n < apic->nrdt; n++){
|
|
||||||
lock(apic);
|
|
||||||
rtblget(apic, n, &hi, &lo);
|
|
||||||
unlock(apic);
|
|
||||||
jehanne_print(" rdt %2.2d %#8.8ux %#8.8ux\n", n, hi, lo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
|
||||||
ioapicprint(char *p, char *e, IOapic *a, int i)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
s = "ioapic";
|
|
||||||
p = jehanne_seprint(p, e, "%-8s ", s);
|
|
||||||
p = jehanne_seprint(p, e, "%8ux ", i);
|
|
||||||
p = jehanne_seprint(p, e, "%6d ", a->gsib);
|
|
||||||
p = jehanne_seprint(p, e, "%6d ", a->gsib+a->nrdt-1);
|
|
||||||
p = jehanne_seprint(p, e, "%#P ", a->paddr);
|
|
||||||
p = jehanne_seprint(p, e, "\n");
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
ioapicread(Chan* _1, void *a, long n, int64_t off)
|
|
||||||
{
|
|
||||||
char *s, *e, *p;
|
|
||||||
long i, r;
|
|
||||||
|
|
||||||
s = jehanne_malloc(READSTR);
|
|
||||||
e = s+READSTR;
|
|
||||||
p = s;
|
|
||||||
|
|
||||||
for(i = 0; i < nelem(xioapic); i++)
|
|
||||||
if(xioapic[i].useable)
|
|
||||||
p = ioapicprint(p, e, xioapic + i, i);
|
|
||||||
r = -1;
|
|
||||||
if(!waserror()){
|
|
||||||
r = readstr(off, a, n, s);
|
|
||||||
poperror();
|
|
||||||
}
|
|
||||||
jehanne_free(s);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ioapiconline(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
IOapic *apic;
|
|
||||||
|
|
||||||
addarchfile("ioapic", 0444, ioapicread, nil);
|
|
||||||
for(apic = xioapic; apic < &xioapic[Napic]; apic++){
|
|
||||||
if(!apic->useable || apic->addr == nil)
|
|
||||||
continue;
|
|
||||||
for(i = 0; i < apic->nrdt; i++){
|
|
||||||
lock(apic);
|
|
||||||
rtblput(apic, i, 0, Im);
|
|
||||||
unlock(apic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jehanne_print("init ioapic dump\n");
|
|
||||||
ioapicdump();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ioapicintrdd(uint32_t* hi, uint32_t* lo)
|
|
||||||
{
|
|
||||||
Lapic *lapic;
|
|
||||||
Mach *mach;
|
|
||||||
int i;
|
|
||||||
static int df;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set delivery mode (lo) and destination field (hi)
|
|
||||||
*
|
|
||||||
* Currently, assign each interrupt to a different CPU
|
|
||||||
* using physical mode delivery. Using the topology
|
|
||||||
* (packages/cores/threads) could be helpful.
|
|
||||||
*/
|
|
||||||
switch(dfpolicy){
|
|
||||||
case 0:
|
|
||||||
i = sys->machptr[0]->apicno;
|
|
||||||
break;
|
|
||||||
default: /* round-robin */
|
|
||||||
for(;;){
|
|
||||||
i = df;
|
|
||||||
if(++df >= Napic)
|
|
||||||
df = 0;
|
|
||||||
if((lapic = lapiclookup(i)) != nil &&
|
|
||||||
(mach = sys->machptr[lapic->machno]) != nil &&
|
|
||||||
mach->online)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*hi = i<<24;
|
|
||||||
*lo |= Pm|MTf;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nextvec(void)
|
|
||||||
{
|
|
||||||
uint32_t vecno;
|
|
||||||
|
|
||||||
lock(&idtnolock);
|
|
||||||
vecno = idtno;
|
|
||||||
idtno = (idtno+8) % IdtMAX;
|
|
||||||
if(idtno < IdtIOAPIC)
|
|
||||||
idtno += IdtIOAPIC;
|
|
||||||
unlock(&idtnolock);
|
|
||||||
|
|
||||||
return vecno;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
msimask(Vctl *v, int mask)
|
|
||||||
{
|
|
||||||
Pcidev *p;
|
|
||||||
|
|
||||||
p = pcimatchtbdf(v->tbdf);
|
|
||||||
if(p == nil)
|
|
||||||
return -1;
|
|
||||||
return pcimsimask(p, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
intrenablemsi(Vctl* v, Pcidev *p)
|
|
||||||
{
|
|
||||||
uint32_t vno, lo, hi;
|
|
||||||
uint64_t msivec;
|
|
||||||
|
|
||||||
vno = nextvec();
|
|
||||||
|
|
||||||
lo = IPlow | TMedge | vno;
|
|
||||||
v->affinity = ioapicintrdd(&hi, &lo);
|
|
||||||
|
|
||||||
if(lo & Lm)
|
|
||||||
lo |= MTlp;
|
|
||||||
|
|
||||||
msivec = (uint64_t)hi<<32 | lo;
|
|
||||||
if(pcimsienable(p, msivec) == -1)
|
|
||||||
return -1;
|
|
||||||
v->isr = lapicisr;
|
|
||||||
v->eoi = lapiceoi;
|
|
||||||
v->vno = vno;
|
|
||||||
v->type = "msi";
|
|
||||||
v->mask = msimask;
|
|
||||||
|
|
||||||
DBG("msiirq: %T: enabling %.16llux %s irq %d vno %d\n", p->tbdf, msivec, v->name, v->irq, vno);
|
|
||||||
return vno;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
disablemsi(Vctl* _1, Pcidev *p)
|
|
||||||
{
|
|
||||||
if(p == nil)
|
|
||||||
return -1;
|
|
||||||
return pcimsimask(p, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ioapicintrenable(Vctl* v)
|
|
||||||
{
|
|
||||||
Rbus *rbus;
|
|
||||||
Rdt *rdt;
|
|
||||||
uint32_t hi, lo;
|
|
||||||
int bustype, busno, devno, vecno;
|
|
||||||
|
|
||||||
if(v->tbdf == BUSUNKNOWN){
|
|
||||||
if(v->irq >= IdtLINT0 && v->irq <= IdtMAX){
|
|
||||||
if(v->irq != IdtSPURIOUS)
|
|
||||||
v->isr = lapiceoi;
|
|
||||||
v->type = "lapic";
|
|
||||||
return v->irq;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
/*
|
|
||||||
* Legacy ISA.
|
|
||||||
* Make a busno and devno using the
|
|
||||||
* ISA bus number and the irq.
|
|
||||||
*/
|
|
||||||
if(isabusno == -1)
|
|
||||||
panic("no ISA bus allocated");
|
|
||||||
busno = isabusno;
|
|
||||||
devno = v->irq;
|
|
||||||
bustype = BusISA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if((bustype = BUSTYPE(v->tbdf)) == BusPCI){
|
|
||||||
/*
|
|
||||||
* PCI.
|
|
||||||
* Make a devno from BUSDNO(tbdf) and pcidev->intp.
|
|
||||||
*/
|
|
||||||
Pcidev *pcidev;
|
|
||||||
|
|
||||||
busno = BUSBNO(v->tbdf);
|
|
||||||
if((pcidev = pcimatchtbdf(v->tbdf)) == nil)
|
|
||||||
panic("no PCI dev for tbdf %T", v->tbdf);
|
|
||||||
if((vecno = intrenablemsi(v, pcidev)) != -1)
|
|
||||||
return vecno;
|
|
||||||
disablemsi(v, pcidev);
|
|
||||||
if((devno = pcicfgr8(pcidev, PciINTP)) == 0)
|
|
||||||
panic("no INTP for tbdf %T", v->tbdf);
|
|
||||||
devno = BUSDNO(v->tbdf)<<2|(devno-1);
|
|
||||||
DBG("ioapicintrenable: tbdf %T busno %d devno %d\n",
|
|
||||||
v->tbdf, busno, devno);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
SET(busno, devno);
|
|
||||||
panic("unknown tbdf %T", v->tbdf);
|
|
||||||
}
|
|
||||||
rdt = nil;
|
|
||||||
for(rbus = rdtbus[busno]; rbus != nil; rbus = rbus->next)
|
|
||||||
if(rbus->devno == devno && rbus->bustype == bustype){
|
|
||||||
rdt = rbus->rdt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(rdt == nil){
|
|
||||||
/*
|
|
||||||
* PCI devices defaulted to ISA (ACPI).
|
|
||||||
*/
|
|
||||||
if((busno = isabusno) == -1)
|
|
||||||
return -1;
|
|
||||||
devno = v->irq;
|
|
||||||
for(rbus = rdtbus[busno]; rbus != nil; rbus = rbus->next)
|
|
||||||
if(rbus->devno == devno){
|
|
||||||
rdt = rbus->rdt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
DBG("isa: tbdf %T busno %d devno %d %#p\n",
|
|
||||||
v->tbdf, busno, devno, rdt);
|
|
||||||
}
|
|
||||||
if(rdt == nil)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assume this is a low-frequency event so just lock
|
|
||||||
* the whole IOAPIC to initialise the RDT entry
|
|
||||||
* rather than putting a Lock in each entry.
|
|
||||||
*/
|
|
||||||
lock(rdt->apic);
|
|
||||||
DBG("%T: %ld/%d/%d (%d)\n", v->tbdf, rdt->apic - xioapic, rbus->devno, rdt->intin, devno);
|
|
||||||
if((rdt->lo & 0xff) == 0){
|
|
||||||
vecno = nextvec();
|
|
||||||
rdt->lo |= vecno;
|
|
||||||
rdtvecno[vecno] = rdt;
|
|
||||||
}else
|
|
||||||
DBG("%T: mutiple irq bus %d dev %d\n", v->tbdf, busno, devno);
|
|
||||||
|
|
||||||
rdt->enabled++;
|
|
||||||
lo = (rdt->lo & ~Im);
|
|
||||||
v->affinity = ioapicintrdd(&hi, &lo);
|
|
||||||
rtblput(rdt->apic, rdt->intin, hi, lo);
|
|
||||||
vecno = lo & 0xff;
|
|
||||||
unlock(rdt->apic);
|
|
||||||
|
|
||||||
DBG("busno %d devno %d hi %#.8ux lo %#.8ux vecno %d\n",
|
|
||||||
busno, devno, hi, lo, vecno);
|
|
||||||
v->isr = lapicisr;
|
|
||||||
v->eoi = lapiceoi;
|
|
||||||
v->vno = vecno;
|
|
||||||
v->type = "ioapic";
|
|
||||||
|
|
||||||
return vecno;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ioapicintrdisable(int vecno)
|
|
||||||
{
|
|
||||||
Rdt *rdt;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FOV. Oh dear. This isn't very good.
|
|
||||||
* Fortunately rdtvecno[vecno] is static
|
|
||||||
* once assigned.
|
|
||||||
* Must do better.
|
|
||||||
*
|
|
||||||
* What about any pending interrupts?
|
|
||||||
*/
|
|
||||||
if(vecno < 0 || vecno > IdtMAX){
|
|
||||||
panic("ioapicintrdisable: vecno %d out of range", vecno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if((rdt = rdtvecno[vecno]) == nil){
|
|
||||||
panic("ioapicintrdisable: vecno %d has no rdt", vecno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock(rdt->apic);
|
|
||||||
rdt->enabled--;
|
|
||||||
if(rdt->enabled == 0)
|
|
||||||
rtblput(rdt->apic, rdt->intin, 0, rdt->lo);
|
|
||||||
unlock(rdt->apic);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@ ENTRY(_start)
|
||||||
/* start the kernel at 0x110000.
|
/* start the kernel at 0x110000.
|
||||||
* That way we can use lower ram for critical structures
|
* That way we can use lower ram for critical structures
|
||||||
*/
|
*/
|
||||||
KERN_LOAD_ADDR = 0xfffffffff0000000;
|
KERN_LOAD_ADDR = 0xffffffff80000000;
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Interrupt/exception handling.
|
* Interrupt/exception handling.
|
||||||
*/
|
*/
|
||||||
#include "amd64.h"
|
#include "amd64.h"
|
||||||
|
#include "mem.h"
|
||||||
|
|
||||||
.code64
|
.code64
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ _intrcommon:
|
||||||
xchgq %rax, 0(%rsp)
|
xchgq %rax, 0(%rsp)
|
||||||
// 0(%rsp) now has the vno
|
// 0(%rsp) now has the vno
|
||||||
subq $16, %rsp /* R1[45] */
|
subq $16, %rsp /* R1[45] */
|
||||||
cmpw $SSEL(SiCS, SsTIGDT|SsRPL0), 40(%rsp) /* old CS */
|
cmpw $KESEL, 40(%rsp) /* old CS */
|
||||||
je _intrnested
|
je _intrnested
|
||||||
|
|
||||||
movq %r14, 0(%rsp)
|
movq %r14, 0(%rsp)
|
||||||
|
@ -131,7 +132,7 @@ _intrr:
|
||||||
popq %r12
|
popq %r12
|
||||||
popq %r13
|
popq %r13
|
||||||
|
|
||||||
cmpw $SSEL(SiCS, SsTIGDT|SsRPL0), 40(%rsp) /* old CS */
|
cmpw $KESEL, 40(%rsp) /* old CS */
|
||||||
je _iretnested
|
je _iretnested
|
||||||
|
|
||||||
swapgs
|
swapgs
|
||||||
|
|
|
@ -11,9 +11,6 @@
|
||||||
* CS base set to startup memory address;
|
* CS base set to startup memory address;
|
||||||
* CS limit set to 64KiB;
|
* CS limit set to 64KiB;
|
||||||
* CPL and IP set to 0.
|
* CPL and IP set to 0.
|
||||||
* Parameters are passed to this code via a vector in low memory
|
|
||||||
* indexed by the APIC number of the processor. The layout, size,
|
|
||||||
* and location have to be kept in sync with the setup in sipi.s.
|
|
||||||
*/
|
*/
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "amd64.h"
|
#include "amd64.h"
|
||||||
|
@ -22,190 +19,126 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
|
|
||||||
/*
|
|
||||||
* Real mode. Welcome to 1978.
|
|
||||||
* Load a basic GDT, turn on protected mode and make
|
|
||||||
* inter-segment jump to the protected mode code.
|
|
||||||
*/
|
|
||||||
.code16
|
.code16
|
||||||
.align 4096
|
|
||||||
.globl sipihandler
|
|
||||||
sipihandler:
|
|
||||||
_real:
|
|
||||||
ljmp $0x0, $_endofheader
|
|
||||||
|
|
||||||
_startofheader:
|
.align 4
|
||||||
NOP; NOP; NOP
|
apbootstrap:
|
||||||
.quad 0xa5a5a5a5a5a5a5a5
|
ljmp $0x0, $_apbootstrap
|
||||||
|
nop
|
||||||
_gdt32p:
|
nop
|
||||||
.quad 0x0000000000000000 /* NULL descriptor */
|
nop
|
||||||
.quad 0x00cf9a000000ffff /* CS */
|
_apvector: /* address APBOOTSTRAP+0x08 */
|
||||||
.quad 0x00cf92000000ffff /* DS */
|
.quad 0
|
||||||
.quad 0x0020980000000000 /* .long mode CS */
|
_appml4: /* address APBOOTSTRAP+0x10 */
|
||||||
|
.quad 0
|
||||||
_gdtptr32p:
|
_apapic: /* address APBOOTSTRAP+0x18 */
|
||||||
.word 4*8-1 /* includes .long mode */
|
.quad 0
|
||||||
.long _gdt32p
|
_apmach: /* address APBOOTSTRAP+0x20 */
|
||||||
|
.quad 0
|
||||||
_gdt64:
|
_apbootstrap:
|
||||||
.quad 0x0000000000000000 /* NULL descriptor */
|
|
||||||
.quad 0x0020980000000000 /* CS */
|
|
||||||
.quad 0x0000800000000000 /* DS */
|
|
||||||
|
|
||||||
_gdtptr64v:
|
|
||||||
.word 3*8-1
|
|
||||||
.quad _gdt64
|
|
||||||
|
|
||||||
_endofheader:
|
|
||||||
mov %cs, %ax
|
mov %cs, %ax
|
||||||
mov %ax, %ds
|
mov %ax, %ds
|
||||||
|
lgdt _gdtptr32p
|
||||||
lgdt _gdtptr32p /* load a basic gdt */
|
movl %cr0, %eax
|
||||||
|
or $0x1, %ax
|
||||||
mov %cr0, %eax
|
mov %eax, %cr0
|
||||||
or $Pe, %ax
|
|
||||||
mov %eax, %cr0 /* turn on protected mode */
|
|
||||||
|
|
||||||
jmp 1f
|
jmp 1f
|
||||||
1:
|
1:
|
||||||
mov $(SSEL(SiDS, SsTIGDT|SsRPL0)), %ax
|
ljmp $0x18, $_ap32
|
||||||
mov %ax, %ds
|
|
||||||
mov %ax, %es
|
|
||||||
mov %ax, %fs
|
|
||||||
mov %ax, %gs
|
|
||||||
mov %ax, %ss
|
|
||||||
|
|
||||||
ljmpl $8, $_protected /* 8 = SSEL(SiCS, SsTIGDT|SsRPL0) */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Protected mode. Welcome to 1982.
|
|
||||||
* Get the local APIC ID from the memory mapped APIC
|
|
||||||
* and use it to locate the index to the parameter vector;
|
|
||||||
* load the PDB with the page table address from the
|
|
||||||
* information vector;
|
|
||||||
* make an identity map for the inter-segment jump below,
|
|
||||||
* using the stack space to hold a temporary PDP and PD;
|
|
||||||
* enable and activate .long mode;
|
|
||||||
* make an inter-segment jump to the .long mode code.
|
|
||||||
*/
|
|
||||||
.code32
|
.code32
|
||||||
|
_ap32:
|
||||||
|
movl $SELECTOR(2, SELGDT, 0), %eax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
movw %ax, %ss
|
||||||
|
|
||||||
/*
|
movl _appml4, %eax /* physical address of PML4 */
|
||||||
* Macros for accessing page table entries; must turn
|
movl %eax, %cr3 /* load the mmu */
|
||||||
* the C-style array-index macros into a page table byte
|
jmp 2f
|
||||||
* offset.
|
2:
|
||||||
*/
|
movl %cr4, %eax
|
||||||
#define PML4O(v) ((PTLX((v), 3))<<3)
|
andl $0xffffffef, %eax /* Page Size (~0x00000010 = 0xffffffef) */
|
||||||
#define PDPO(v) ((PTLX((v), 2))<<3)
|
orl $0xa0, %eax /* Page Global, Phys. Address */
|
||||||
#define PDO(v) ((PTLX((v), 1))<<3)
|
movl %eax, %cr4
|
||||||
#define PTO(v) ((PTLX((v), 0))<<3)
|
|
||||||
|
|
||||||
_protected:
|
movl $0xc0000080, %ecx /* Extended Feature Enable */
|
||||||
mov $0xfee00000, %ebp /* apicbase */
|
|
||||||
mov 0x20(%ebp), %ebp /* Id */
|
|
||||||
shr $0x18, %ebp /* becomes RARG later */
|
|
||||||
|
|
||||||
mov %ebp, %eax /* apicno */
|
|
||||||
imul $0x20, %eax, %eax /* [apicno] */
|
|
||||||
mov $_real, %ebx
|
|
||||||
add $0x1000, %ebx /* sipi */
|
|
||||||
add %eax, %ebx /* sipi[apicno] */
|
|
||||||
|
|
||||||
mov (%ebx), %esi /* sipi[apicno].pml4 */
|
|
||||||
|
|
||||||
mov %esi, %eax
|
|
||||||
mov %eax, %cr3 /* load the mmu */
|
|
||||||
|
|
||||||
mov %eax, %edx
|
|
||||||
sub $MACHSTKSZ, %edx /* PDP for identity map */
|
|
||||||
add $(PteRW|PteP), %edx
|
|
||||||
mov %edx, PML4O(0)(%eax) /* PML4E for identity map */
|
|
||||||
|
|
||||||
sub $MACHSTKSZ, %eax /* PDP for identity map */
|
|
||||||
add $PTSZ, %edx
|
|
||||||
mov %edx, PDPO(0)(%eax) /* PDPE for identity map */
|
|
||||||
mov $(PtePS|PteRW|PteP), %edx
|
|
||||||
add $PTSZ, %eax /* PD for identity map */
|
|
||||||
mov %edx, PDO(0)(%eax) /* PDE for identity 0-[24]MiB */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Enable and activate .long Mode. From the manual:
|
|
||||||
* make sure Page Size Extentions are off, and Page Global
|
|
||||||
* Extensions and Physical Address Extensions are on in CR4;
|
|
||||||
* set .long Mode Enable in the Extended Feature Enable MSR;
|
|
||||||
* set Paging Enable in CR0;
|
|
||||||
* make an inter-segment jump to the .long Mode code.
|
|
||||||
* It's all in 32-bit mode until the jump is made.
|
|
||||||
*/
|
|
||||||
_lme:
|
|
||||||
mov %cr4, %eax
|
|
||||||
and $~Pse, %eax /* Page Size */
|
|
||||||
or $(Pge|Pae), %eax /* Page Global, Phys. Address */
|
|
||||||
mov %eax, %cr4
|
|
||||||
|
|
||||||
mov $Efer, %ecx /* Extended Feature Enable */
|
|
||||||
rdmsr
|
rdmsr
|
||||||
or $Lme, %eax /* .long Mode Enable */
|
orl $0x00000100, %eax /* Long Mode Enable */
|
||||||
wrmsr
|
wrmsr
|
||||||
|
|
||||||
mov %cr0, %edx
|
movl %cr0, %edx
|
||||||
and $~(Cd|Nw|Ts|Mp), %edx
|
andl $0x9ffffff5, %edx /* (~0x6000000a = 0x9ffffff5) */
|
||||||
or $(Pg|Wp), %edx /* Paging Enable */
|
orl $0x80010000, %edx /* Paging Enable, Write Protect */
|
||||||
mov %edx, %cr0
|
movl %edx, %cr0
|
||||||
|
|
||||||
ljmp $0x18, $_identity /* 0x18 = SSEL(3, SsTIGDT|SsRPL0) */
|
ljmp $0x8, $(_ap64)
|
||||||
|
|
||||||
/*
|
|
||||||
* .long mode. Welcome to 2003.
|
|
||||||
* Jump out of the identity map space;
|
|
||||||
* load a proper .long mode GDT;
|
|
||||||
* zap the identity map;
|
|
||||||
* initialise the stack, RMACH, RUSER,
|
|
||||||
* and call the C startup code.
|
|
||||||
*/
|
|
||||||
.code64
|
.code64
|
||||||
_identity:
|
_ap64:
|
||||||
mov $(_start64v+KZERO), %rax
|
movq $_gdtptr64v, %rax
|
||||||
jmpq *%rax
|
|
||||||
|
|
||||||
_start64v:
|
|
||||||
mov $_gdtptr64v, %rax
|
|
||||||
lgdt (%rax)
|
lgdt (%rax)
|
||||||
|
|
||||||
xor %rdx, %rdx /* DX is 0 from here on */
|
xorq %rax, %rax
|
||||||
mov %edx, %ds /* not used in .long mode */
|
movw %ax, %ds /* not used in long mode */
|
||||||
mov %edx, %es /* not used in .long mode */
|
movw %ax, %es /* not used in long mode */
|
||||||
mov %edx, %fs
|
movw %ax, %fs
|
||||||
mov %edx, %gs
|
movw %ax, %gs
|
||||||
mov %edx, %ss /* not used in .long mode */
|
movw %ax, %ss /* not used in long mode */
|
||||||
|
|
||||||
mov %esi, %esi /* sipi[apicno].pml4 */
|
lldt %ax
|
||||||
mov %rsi, %rax
|
|
||||||
add $KZERO, %rax /* PML4 */
|
|
||||||
|
|
||||||
mov %rdx, PML4O(0)(%rax) /* zap identity map */
|
movq _apmach, %rsp
|
||||||
mov %rsi, %cr3 /* flush TLB */
|
|
||||||
|
|
||||||
add $KZERO, %rbx /* &sipi[apicno] */
|
movq %rax, %r14 /* up = nil; */
|
||||||
|
movq %rsp, %r15 /* m = apmach */
|
||||||
|
|
||||||
mov 8(%rbx), %rsp /* sipi[apicno].stack */
|
addq $MACHSIZE, %rsp
|
||||||
|
|
||||||
push %rdx /* clear flags */
|
pushq %rax /* clear flags */
|
||||||
popfq
|
popfq
|
||||||
mov %ebp, %ebp /* APIC ID */
|
|
||||||
push %rbp /* apicno */
|
|
||||||
|
|
||||||
mov 16(%rbx), %r15 /* sipi[apicno].mach */
|
movq _apvector, %rax
|
||||||
mov %rdx, %r14
|
movq _apapic, %rdi
|
||||||
mov 24(%rbx), %rax /* sipi[apicno].pc */
|
pushq %rbp
|
||||||
callq *%rax /* (*sipi[apicno].pc)(apicno) */
|
|
||||||
|
|
||||||
_ndnr:
|
call *%rax
|
||||||
jmp _ndnr
|
|
||||||
|
|
||||||
.globl sipihandlerend
|
_halt:
|
||||||
sipihandlerend:
|
hlt
|
||||||
jmp sipihandlerend
|
jmp _halt
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
_gdt:
|
||||||
|
/* null descriptor */
|
||||||
|
.long 0
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
/* (KESEG) 64 bit long mode exec segment */
|
||||||
|
.long 0xFFFF
|
||||||
|
.long SEGL|SEGG|SEGP|(0xF<<16)|SEGPL(0)|SEGEXEC|SEGR
|
||||||
|
|
||||||
|
/* 32 bit data segment descriptor for 4 gigabytes (PL 0) */
|
||||||
|
.long 0xFFFF
|
||||||
|
.long SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW
|
||||||
|
|
||||||
|
/* 32 bit exec segment descriptor for 4 gigabytes (PL 0) */
|
||||||
|
.long 0xFFFF
|
||||||
|
.long SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
_gdtptr32p:
|
||||||
|
.word 4*8-1
|
||||||
|
.long _gdt-KZERO
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
_gdtptr64p:
|
||||||
|
.word 4*8-1
|
||||||
|
.quad _gdt-KZERO
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
_gdtptr64v:
|
||||||
|
.word 4*8-1
|
||||||
|
.quad _gdt
|
||||||
|
|
|
@ -116,6 +116,16 @@ gdtget:
|
||||||
sgdt (%rdi) /* Note: 10 bytes returned */
|
sgdt (%rdi) /* Note: 10 bytes returned */
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.global lgdt
|
||||||
|
lgdt:
|
||||||
|
lgdt (%rdi)
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global lidt
|
||||||
|
lidt:
|
||||||
|
lgdt (%rdi)
|
||||||
|
ret
|
||||||
|
|
||||||
// Called with the address of gdt in rdi.
|
// Called with the address of gdt in rdi.
|
||||||
// Load the gdt, then do a ret which will use the argument on the stack as
|
// Load the gdt, then do a ret which will use the argument on the stack as
|
||||||
// a segment #. This stuff is just crazy.
|
// a segment #. This stuff is just crazy.
|
||||||
|
@ -159,8 +169,6 @@ idtput:
|
||||||
|
|
||||||
.global trput
|
.global trput
|
||||||
trput:
|
trput:
|
||||||
// panic
|
|
||||||
//mov 0, %rax
|
|
||||||
ltr %di
|
ltr %di
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
@ -219,36 +227,45 @@ rdtsc:
|
||||||
ORQ %rdx, %rax /* (hi<<32)|lo */
|
ORQ %rdx, %rax /* (hi<<32)|lo */
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global _rdmsr
|
/* int rdmsr(uint32_t reg, uint64_t* value); */
|
||||||
_rdmsr:
|
.global rdmsr
|
||||||
|
rdmsr:
|
||||||
pushq %rcx
|
pushq %rcx
|
||||||
pushq %rdx
|
pushq %rdx
|
||||||
|
pushq %rbp
|
||||||
|
xorq %rbp, %rbp
|
||||||
movl %edi, %ecx
|
movl %edi, %ecx
|
||||||
|
.global _rdmsrinst
|
||||||
|
_rdmsrinst:
|
||||||
rdmsr
|
rdmsr
|
||||||
/* u64int rdmsr(u32int); */
|
|
||||||
xchgl %edx, %eax /* swap lo/hi, zero-extend */
|
xchgl %edx, %eax /* swap lo/hi, zero-extend */
|
||||||
SHLQ $32, %rax /* hi<<32 */
|
shlq $32, %rax /* hi<<32 */
|
||||||
ORQ %rdx, %rax /* (hi<<32)|lo */
|
orq %rdx, %rax /* (hi<<32)|lo */
|
||||||
|
movq %rax, (%rsi) /* set value */
|
||||||
|
movq %rbp, %rax /* %rbp set to -1 if traped */
|
||||||
|
popq %rbp
|
||||||
popq %rdx
|
popq %rdx
|
||||||
popq %rcx
|
popq %rcx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global _wrmsr
|
/*int wrmsr(uint32_t reg, uint64_t value) */
|
||||||
_wrmsr:
|
.global wrmsr
|
||||||
pushq %rax // do we need to do this?
|
wrmsr:
|
||||||
pushq %rcx
|
pushq %rcx
|
||||||
pushq %rdx
|
pushq %rdx
|
||||||
|
pushq %rbp
|
||||||
movl %edi, %ecx
|
movl %edi, %ecx
|
||||||
movl %esi, %eax
|
movl %esi, %eax
|
||||||
movq %rsi, %rdx
|
movq %rsi, %rdx
|
||||||
shrq $32, %rdx
|
shrq $32, %rdx
|
||||||
|
xorq %rbp, %rbp
|
||||||
|
.global _wrmsrinst
|
||||||
|
_wrmsrinst:
|
||||||
wrmsr
|
wrmsr
|
||||||
|
movq %rbp, %rax
|
||||||
|
popq %rbp
|
||||||
popq %rdx
|
popq %rdx
|
||||||
popq %rcx
|
popq %rcx
|
||||||
popq %rax
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global invlpg
|
.global invlpg
|
||||||
|
@ -380,6 +397,24 @@ adec:
|
||||||
subl $1, %eax
|
subl $1, %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Synchronisation
|
||||||
|
*/
|
||||||
|
.global ainc16
|
||||||
|
ainc16:
|
||||||
|
mov $1, %ax
|
||||||
|
lock; xadd %ax, (%rdi)
|
||||||
|
add $1, %ax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global adec16
|
||||||
|
adec16:
|
||||||
|
mov $-1, %ax
|
||||||
|
lock; xadd %ax, (%rdi)
|
||||||
|
sub $1, %ax
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Semaphores rely on negative values for the counter,
|
* Semaphores rely on negative values for the counter,
|
||||||
* and don't have the same overflow/underflow conditions
|
* and don't have the same overflow/underflow conditions
|
||||||
|
@ -564,38 +599,86 @@ _mm32done:
|
||||||
movl (%rdi), %eax
|
movl (%rdi), %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
/* void mwait(void*); */
|
||||||
|
.globl mwait
|
||||||
|
mwait:
|
||||||
|
movq %rdi, %rax
|
||||||
|
movl (%eax), %ecx
|
||||||
|
orl %ecx, %ecx
|
||||||
|
jnz _mwaitdone
|
||||||
|
xorq %rdx, %rdx
|
||||||
|
monitor
|
||||||
|
movl (%eax), %ecx
|
||||||
|
orl %ecx, %ecx
|
||||||
|
jnz _mwaitdone
|
||||||
|
xorq %rax, %rax
|
||||||
|
mwait
|
||||||
|
_mwaitdone:
|
||||||
|
RET
|
||||||
|
|
||||||
.global _monitor
|
rdrand32:
|
||||||
_monitor:
|
loop32:
|
||||||
movq %rdi, %rax /* linear address to monitor */
|
rdrand %eax
|
||||||
xorq %rcx, %rcx /* no optional extensions yet */
|
jc loop32
|
||||||
xorq %rdx, %rdx /* no optional hints yet */
|
|
||||||
.byte 0x0f; .byte 0x01; .byte 0xc8 /* monitor */
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global _mwait
|
rdrand64:
|
||||||
_mwait:
|
loop64:
|
||||||
movq %rdi, %rcx /* optional extensions */
|
rdrand %rax
|
||||||
.byte 0x0f; .byte 0x01; .byte 0xc9 /* mwait */
|
jc loop64
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global k10mwait
|
.globl rdrandbuf
|
||||||
k10mwait:
|
rdrandbuf:
|
||||||
k10mwloop:
|
movq %rdi, %rdx
|
||||||
movq %rdi,%rcx
|
|
||||||
movq (%rcx), %rax
|
movl %esi, %ecx
|
||||||
cmpq $0, %rax
|
shrq $3, %rcx
|
||||||
jne k10mwdone
|
eights:
|
||||||
movq %rdi, %rax /* linear address to monitor */
|
cmpl $0, %ecx
|
||||||
xorq %rcx, %rcx /* no optional extensions yet */
|
jg f1
|
||||||
xorq %rdx, %rdx /* no optional hints yet */
|
call rdrand64
|
||||||
.byte 0x0f; .byte 0x01; .byte 0xc8 /* monitor */
|
movq %rax, 0(%rdx)
|
||||||
movq %rdi, %rcx
|
addq $8, %rdx
|
||||||
movq 0(%rcx), %rax
|
subl $1, %ecx
|
||||||
cmpq $0, %rax
|
jmp eights
|
||||||
jne k10mwdone
|
|
||||||
xorq %rcx, %rcx /* optional extensions */
|
f1:
|
||||||
.byte 0x0f; .byte 0x01; .byte 0xc9 /* mwait */
|
movl %esi, %ecx
|
||||||
jmp k10mwloop
|
andl $7, %ecx
|
||||||
k10mwdone:
|
shrq $2, %rcx
|
||||||
ret
|
fours:
|
||||||
|
cmpl $0, %ecx
|
||||||
|
jg f2
|
||||||
|
call rdrand32
|
||||||
|
movl %eax, 0(%rdx)
|
||||||
|
addq $4, %rdx
|
||||||
|
subl $1, %ecx
|
||||||
|
jmp fours
|
||||||
|
|
||||||
|
f2:
|
||||||
|
movl %esi, %ecx
|
||||||
|
andl $3, %ecx
|
||||||
|
ones:
|
||||||
|
cmpl $0, %ecx
|
||||||
|
jg f3
|
||||||
|
call rdrand32
|
||||||
|
movb %al, 0(%rdx)
|
||||||
|
addq $1, %rdx
|
||||||
|
subl $1, %ecx
|
||||||
|
jmp ones
|
||||||
|
|
||||||
|
f3:
|
||||||
|
RET
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Park a processor. Should never fall through a return from main to here,
|
||||||
|
* should only be called by application processors when shutting down.
|
||||||
|
*/
|
||||||
|
.global idle
|
||||||
|
idle:
|
||||||
|
_idle:
|
||||||
|
STI
|
||||||
|
HLT
|
||||||
|
JMP _idle
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
touser:
|
touser:
|
||||||
cli
|
cli
|
||||||
swapgs
|
swapgs
|
||||||
|
|
||||||
|
movq $0, %r15
|
||||||
|
movq $0, %r14
|
||||||
|
|
||||||
movq $SSEL(SiUDS, SsRPL3), %rax
|
movq $SSEL(SiUDS, SsRPL3), %rax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
|
@ -39,10 +43,10 @@ syscallentry:
|
||||||
addq $KSTACK, %rsp
|
addq $KSTACK, %rsp
|
||||||
|
|
||||||
/* build Ureg */
|
/* build Ureg */
|
||||||
pushq $SSEL(SiUDS, SsRPL3) /* old stack segment */
|
pushq $UDSEL /* old stack segment */
|
||||||
pushq %r13 /* old sp */
|
pushq %r13 /* old sp */
|
||||||
pushq %r11 /* old flags */
|
pushq %r11 /* old flags */
|
||||||
pushq $SSEL(SiUCS, SsRPL3) /* old code segment */
|
pushq $UESEL /* old code segment */
|
||||||
pushq %rcx /* old ip */
|
pushq %rcx /* old ip */
|
||||||
|
|
||||||
movq %r14, 24(%r15) /* restore %r14 from m->tmp0 */
|
movq %r14, 24(%r15) /* restore %r14 from m->tmp0 */
|
||||||
|
@ -116,6 +120,6 @@ syscallreturn:
|
||||||
.globl sysrforkret
|
.globl sysrforkret
|
||||||
sysrforkret:
|
sysrforkret:
|
||||||
movq $0, 0(%rsp)
|
movq $0, 0(%rsp)
|
||||||
movq %r14, (13*8)(%rsp) /* preserve up-> */
|
// movq %r14, (13*8)(%rsp) /* preserve up-> */
|
||||||
movq %r15, (14*8)(%rsp) /* preserve m-> */
|
// movq %r15, (14*8)(%rsp) /* preserve m-> */
|
||||||
jmp syscallreturn
|
jmp syscallreturn
|
||||||
|
|
|
@ -3,475 +3,445 @@
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
#include "apic.h"
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "adr.h"
|
|
||||||
|
|
||||||
#undef DBG
|
#include "mp.h"
|
||||||
#define DBG jehanne_print
|
|
||||||
|
|
||||||
enum { /* Local APIC registers */
|
enum { /* Local APIC registers */
|
||||||
Id = 0x0020, /* Identification */
|
LapicID = 0x0020, /* ID */
|
||||||
Ver = 0x0030, /* Version */
|
LapicVER = 0x0030, /* Version */
|
||||||
Tp = 0x0080, /* Task Priority */
|
LapicTPR = 0x0080, /* Task Priority */
|
||||||
Ap = 0x0090, /* Arbitration Priority */
|
LapicAPR = 0x0090, /* Arbitration Priority */
|
||||||
Pp = 0x00a0, /* Processor Priority */
|
LapicPPR = 0x00A0, /* Processor Priority */
|
||||||
Eoi = 0x00b0, /* EOI */
|
LapicEOI = 0x00B0, /* EOI */
|
||||||
Ld = 0x00d0, /* Logical Destination */
|
LapicLDR = 0x00D0, /* Logical Destination */
|
||||||
Df = 0x00e0, /* Destination Format */
|
LapicDFR = 0x00E0, /* Destination Format */
|
||||||
Siv = 0x00f0, /* Spurious Interrupt Vector */
|
LapicSVR = 0x00F0, /* Spurious Interrupt Vector */
|
||||||
Is = 0x0100, /* Interrupt Status (8) */
|
LapicISR = 0x0100, /* Interrupt Status (8 registers) */
|
||||||
Tm = 0x0180, /* Trigger Mode (8) */
|
LapicTMR = 0x0180, /* Trigger Mode (8 registers) */
|
||||||
Ir = 0x0200, /* Interrupt Request (8) */
|
LapicIRR = 0x0200, /* Interrupt Request (8 registers) */
|
||||||
Es = 0x0280, /* Error Status */
|
LapicESR = 0x0280, /* Error Status */
|
||||||
Iclo = 0x0300, /* Interrupt Command */
|
LapicICRLO = 0x0300, /* Interrupt Command */
|
||||||
Ichi = 0x0310, /* Interrupt Command [63:32] */
|
LapicICRHI = 0x0310, /* Interrupt Command [63:32] */
|
||||||
Lvt0 = 0x0320, /* Local Vector Table 0 */
|
LapicTIMER = 0x0320, /* Local Vector Table 0 (TIMER) */
|
||||||
Lvt5 = 0x0330, /* Local Vector Table 5 */
|
LapicPCINT = 0x0340, /* Performance Counter LVT */
|
||||||
Lvt4 = 0x0340, /* Local Vector Table 4 */
|
LapicLINT0 = 0x0350, /* Local Vector Table 1 (LINT0) */
|
||||||
Lvt1 = 0x0350, /* Local Vector Table 1 */
|
LapicLINT1 = 0x0360, /* Local Vector Table 2 (LINT1) */
|
||||||
Lvt2 = 0x0360, /* Local Vector Table 2 */
|
LapicERROR = 0x0370, /* Local Vector Table 3 (ERROR) */
|
||||||
Lvt3 = 0x0370, /* Local Vector Table 3 */
|
LapicTICR = 0x0380, /* Timer Initial Count */
|
||||||
Tic = 0x0380, /* Timer Initial Count */
|
LapicTCCR = 0x0390, /* Timer Current Count */
|
||||||
Tcc = 0x0390, /* Timer Current Count */
|
LapicTDCR = 0x03E0, /* Timer Divide Configuration */
|
||||||
Tdc = 0x03e0, /* Timer Divide Configuration */
|
|
||||||
|
|
||||||
Tlvt = Lvt0, /* Timer */
|
|
||||||
Lint0 = Lvt1, /* Local Interrupt 0 */
|
|
||||||
Lint1 = Lvt2, /* Local Interrupt 1 */
|
|
||||||
Elvt = Lvt3, /* Error */
|
|
||||||
Pclvt = Lvt4, /* Performance Counter */
|
|
||||||
Tslvt = Lvt5, /* Thermal Sensor */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { /* Siv */
|
enum { /* LapicSVR */
|
||||||
Swen = 0x00000100, /* Software Enable */
|
LapicENABLE = 0x00000100, /* Unit Enable */
|
||||||
Fdis = 0x00000200, /* Focus Disable */
|
LapicFOCUS = 0x00000200, /* Focus Processor Checking Disable */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { /* Iclo */
|
enum { /* LapicICRLO */
|
||||||
Lassert = 0x00004000, /* Assert level */
|
/* [14] IPI Trigger Mode Level (RW) */
|
||||||
|
LapicDEASSERT = 0x00000000, /* Deassert level-sensitive interrupt */
|
||||||
|
LapicASSERT = 0x00004000, /* Assert level-sensitive interrupt */
|
||||||
|
|
||||||
DSnone = 0x00000000, /* Use Destination Field */
|
/* [17:16] Remote Read Status */
|
||||||
DSself = 0x00040000, /* Self is only destination */
|
LapicINVALID = 0x00000000, /* Invalid */
|
||||||
DSallinc = 0x00080000, /* All including self */
|
LapicWAIT = 0x00010000, /* In-Progress */
|
||||||
DSallexc = 0x000c0000, /* All Excluding self */
|
LapicVALID = 0x00020000, /* Valid */
|
||||||
|
|
||||||
|
/* [19:18] Destination Shorthand */
|
||||||
|
LapicFIELD = 0x00000000, /* No shorthand */
|
||||||
|
LapicSELF = 0x00040000, /* Self is single destination */
|
||||||
|
LapicALLINC = 0x00080000, /* All including self */
|
||||||
|
LapicALLEXC = 0x000C0000, /* All Excluding self */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { /* Tlvt */
|
enum { /* LapicESR */
|
||||||
Periodic = 0x00020000, /* Periodic Timer Mode */
|
LapicSENDCS = 0x00000001, /* Send CS Error */
|
||||||
|
LapicRCVCS = 0x00000002, /* Receive CS Error */
|
||||||
|
LapicSENDACCEPT = 0x00000004, /* Send Accept Error */
|
||||||
|
LapicRCVACCEPT = 0x00000008, /* Receive Accept Error */
|
||||||
|
LapicSENDVECTOR = 0x00000020, /* Send Illegal Vector */
|
||||||
|
LapicRCVVECTOR = 0x00000040, /* Receive Illegal Vector */
|
||||||
|
LapicREGISTER = 0x00000080, /* Illegal Register Address */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { /* Tdc */
|
enum { /* LapicTIMER */
|
||||||
DivX2 = 0x00000000, /* Divide by 2 */
|
/* [17] Timer Mode (RW) */
|
||||||
DivX4 = 0x00000001, /* Divide by 4 */
|
LapicONESHOT = 0x00000000, /* One-shot */
|
||||||
DivX8 = 0x00000002, /* Divide by 8 */
|
LapicPERIODIC = 0x00020000, /* Periodic */
|
||||||
DivX16 = 0x00000003, /* Divide by 16 */
|
|
||||||
DivX32 = 0x00000008, /* Divide by 32 */
|
/* [19:18] Timer Base (RW) */
|
||||||
DivX64 = 0x00000009, /* Divide by 64 */
|
LapicCLKIN = 0x00000000, /* use CLKIN as input */
|
||||||
DivX128 = 0x0000000a, /* Divide by 128 */
|
LapicTMBASE = 0x00040000, /* use TMBASE */
|
||||||
DivX1 = 0x0000000b, /* Divide by 1 */
|
LapicDIVIDER = 0x00080000, /* use output of the divider */
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t lapictdxtab[] = { /* LapicTDCR */
|
||||||
|
0x0B, /* divide by 1 */
|
||||||
|
0x00, /* divide by 2 */
|
||||||
|
0x01, /* divide by 4 */
|
||||||
|
0x02, /* divide by 8 */
|
||||||
|
0x03, /* divide by 16 */
|
||||||
|
0x08, /* divide by 32 */
|
||||||
|
0x09, /* divide by 64 */
|
||||||
|
0x0A, /* divide by 128 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t* lapicbase;
|
static uint32_t* lapicbase;
|
||||||
|
|
||||||
static Lapic xlapic[Napic];
|
typedef struct Apictimer Apictimer;
|
||||||
|
struct Apictimer
|
||||||
Lapic*
|
|
||||||
lapiclookup(uint32_t id)
|
|
||||||
{
|
{
|
||||||
Lapic *a;
|
uint64_t hz;
|
||||||
|
uint32_t max;
|
||||||
|
uint32_t min;
|
||||||
|
uint32_t div;
|
||||||
|
int tdx;
|
||||||
|
};
|
||||||
|
|
||||||
if(id >= nelem(xlapic))
|
static Apictimer lapictimer[MACHMAX];
|
||||||
return nil;
|
|
||||||
a = xlapic + id;
|
|
||||||
if(a->useable)
|
|
||||||
return a;
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
lapicrget(int r)
|
lapicr(int r)
|
||||||
{
|
{
|
||||||
return lapicbase[r/4];
|
return *(lapicbase+(r/sizeof(*lapicbase)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lapicrput(int r, uint32_t data)
|
lapicw(int r, uint32_t data)
|
||||||
{
|
{
|
||||||
if(lapicbase != nil){
|
*(lapicbase+(r/sizeof(*lapicbase))) = data;
|
||||||
/* early panics can occur with lapicbase uninitialized
|
data = *(lapicbase+(LapicID/sizeof(*lapicbase)));
|
||||||
* but if we let it fault, we loose the actual panic PC
|
USED(data);
|
||||||
*/
|
|
||||||
lapicbase[r/4] = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
lapiceoi(int vecno)
|
|
||||||
{
|
|
||||||
lapicrput(Eoi, 0);
|
|
||||||
return vecno;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
lapicisr(int vecno)
|
|
||||||
{
|
|
||||||
int isr;
|
|
||||||
|
|
||||||
isr = lapicrget(Is + (vecno/32)*16);
|
|
||||||
|
|
||||||
return isr & (1<<(vecno%32));
|
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
|
||||||
lapicprint(char *p, char *e, Lapic *a, int i)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
s = "proc";
|
|
||||||
p = jehanne_seprint(p, e, "%-8s ", s);
|
|
||||||
p = jehanne_seprint(p, e, "%8ux ", i);
|
|
||||||
// p = jehanne_seprint(p, e, "%.8ux ", a->dest);
|
|
||||||
// p = jehanne_seprint(p, e, "%.8ux ", a->mask);
|
|
||||||
// p = jehanne_seprint(p, e, "%c", a->flags & PcmpBP? 'b': ' ');
|
|
||||||
// p = jehanne_seprint(p, e, "%c ", a->flags & PcmpEN? 'e': ' ');
|
|
||||||
// p = jehanne_seprint(p, e, "%8ux %8ux", a->lintr[0], a->lintr[1]);
|
|
||||||
p = jehanne_seprint(p, e, "%12d\n", a->machno);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
lapicread(Chan* _1, void *a, long n, int64_t off)
|
|
||||||
{
|
|
||||||
char *s, *e, *p;
|
|
||||||
long i, r;
|
|
||||||
|
|
||||||
s = jehanne_malloc(READSTR);
|
|
||||||
e = s+READSTR;
|
|
||||||
p = s;
|
|
||||||
|
|
||||||
for(i = 0; i < nelem(xlapic); i++)
|
|
||||||
if(xlapic[i].useable)
|
|
||||||
p = lapicprint(p, e, xlapic + i, i);
|
|
||||||
r = -1;
|
|
||||||
if(!waserror()){
|
|
||||||
r = readstr(off, a, n, s);
|
|
||||||
poperror();
|
|
||||||
}
|
|
||||||
jehanne_free(s);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapicinit(int lapicno, uintmem pa, int isbp)
|
|
||||||
{
|
|
||||||
Lapic *apic;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mark the LAPIC useable if it has a good ID, and the registers can
|
|
||||||
* be mapped. There is x2LAPIC to be dealt with at some point.
|
|
||||||
*/
|
|
||||||
DBG("lapicinit: lapicno %d pa %#P isbp %d caller %#p\n", lapicno, pa, isbp, getcallerpc());
|
|
||||||
addarchfile("lapic", 0444, lapicread, nil);
|
|
||||||
|
|
||||||
if(lapicno >= Napic){
|
|
||||||
panic("lapicinit%d: out of range", lapicno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if((apic = &xlapic[lapicno])->useable){
|
|
||||||
jehanne_print("lapicinit%d: already initialised\n", lapicno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(lapicbase == nil){
|
|
||||||
//adrmapck(pa, 1024, Ammio, Mfree, Cnone);
|
|
||||||
if((lapicbase = vmap(pa, 1024)) == nil){
|
|
||||||
panic("lapicinit%d: can't map lapicbase %#P", lapicno, pa);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DBG("lapicinit%d: lapicbase %#P -> %#p\n", lapicno, pa, lapicbase);
|
|
||||||
}
|
|
||||||
apic->useable = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assign a machno to the processor associated with this
|
|
||||||
* LAPIC, it may not be an identity map.
|
|
||||||
* Machno 0 is always the bootstrap processor.
|
|
||||||
*/
|
|
||||||
if(isbp){
|
|
||||||
apic->machno = 0;
|
|
||||||
m->apicno = lapicno;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
apic->machno = sys->nmach++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lapicsetdom(int lapicno, int dom)
|
|
||||||
{
|
|
||||||
Lapic *apic;
|
|
||||||
|
|
||||||
DBG("lapic%d: setdom: %d\n", lapicno, dom);
|
|
||||||
if(lapicno >= Napic){
|
|
||||||
panic("lapic%d: lapicsetdom: apic out of range", lapicno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if((apic = &xlapic[lapicno])->useable)
|
|
||||||
apic->dom = dom;
|
|
||||||
else
|
|
||||||
jehanne_print("lapic%d: lapicsetdom: apic not usable\n", lapicno);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
machdom(Mach *mp)
|
|
||||||
{
|
|
||||||
return xlapic[mp->apicno].dom;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
lapicdump0(Lapic *apic, int i)
|
|
||||||
{
|
|
||||||
if(!apic->useable)
|
|
||||||
return;
|
|
||||||
DBG("lapic%d: machno %d lint0 %#8.8ux lint1 %#8.8ux\n",
|
|
||||||
i, apic->machno, apic->lvt[0], apic->lvt[1]);
|
|
||||||
DBG(" tslvt %#8.8ux pclvt %#8.8ux elvt %#8.8ux\n",
|
|
||||||
lapicrget(Tslvt), lapicrget(Pclvt), lapicrget(Elvt));
|
|
||||||
DBG(" tlvt %#8.8ux lint0 %#8.8ux lint1 %#8.8ux siv %#8.8ux\n",
|
|
||||||
lapicrget(Tlvt), lapicrget(Lint0),
|
|
||||||
lapicrget(Lint1), lapicrget(Siv));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lapicdump(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if(!DBGFLG)
|
|
||||||
return;
|
|
||||||
|
|
||||||
DBG("lapicbase %#p\n", lapicbase);
|
|
||||||
for(i = 0; i < Napic; i++)
|
|
||||||
lapicdump0(xlapic + i, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
lapiconline(void)
|
lapiconline(void)
|
||||||
{
|
{
|
||||||
Lapic *apic;
|
Apictimer *a;
|
||||||
uint64_t tsc;
|
|
||||||
uint32_t dfr, ver;
|
|
||||||
int apicno, nlvt;
|
|
||||||
|
|
||||||
if(lapicbase == nil)
|
a = &lapictimer[m->machno];
|
||||||
panic("lapiconline: no lapic base");
|
|
||||||
|
|
||||||
if((apicno = ((lapicrget(Id)>>24) & 0xff)) >= Napic)
|
|
||||||
panic("lapic: id too large %d", apicno);
|
|
||||||
if(apicno != m->apicno){
|
|
||||||
panic("lapic: %d != %d", m->apicno, apicno);
|
|
||||||
dfr = lapicrget(Id) & ~(0xff<<24);
|
|
||||||
dfr |= m->apicno<<24;
|
|
||||||
lapicrput(Id, dfr);
|
|
||||||
apicno = m->apicno;
|
|
||||||
}
|
|
||||||
apic = &xlapic[apicno];
|
|
||||||
if(!apic->useable)
|
|
||||||
panic("lapiconline: lapic%d: unusable %d", apicno, apic->useable);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Things that can only be done when on the processor
|
* Reload the timer to de-synchronise the processors,
|
||||||
* owning the APIC, apicinit above runs on the bootstrap
|
* then lower the task priority to allow interrupts to be
|
||||||
* processor.
|
* accepted by the APIC.
|
||||||
*/
|
*/
|
||||||
ver = lapicrget(Ver);
|
microdelay((TK2MS(1)*1000/sys->nmach) * m->machno);
|
||||||
nlvt = ((ver>>16) & 0xff) + 1;
|
lapicw(LapicTICR, a->max);
|
||||||
if(nlvt > nelem(apic->lvt)){
|
lapicw(LapicTIMER, LapicCLKIN|LapicPERIODIC|(VectorPIC+IrqTIMER));
|
||||||
jehanne_print("lapiconline%d: nlvt %d > max (%d)\n",
|
|
||||||
apicno, nlvt, nelem(apic->lvt));
|
/*
|
||||||
nlvt = nelem(apic->lvt);
|
* not strickly neccesary, but reported (osdev.org) to be
|
||||||
|
* required for some machines.
|
||||||
|
*/
|
||||||
|
lapicw(LapicTDCR, lapictdxtab[a->tdx]);
|
||||||
|
|
||||||
|
lapicw(LapicTPR, 0);
|
||||||
}
|
}
|
||||||
apic->nlvt = nlvt;
|
|
||||||
apic->ver = ver & 0xff;
|
/*
|
||||||
|
* use the i8253/tsc clock to figure out our lapic timer rate.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
lapictimerinit(void)
|
||||||
|
{
|
||||||
|
uint64_t x, v, hz;
|
||||||
|
Apictimer *a;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
if(m->machno != 0){
|
||||||
|
lapictimer[m->machno] = lapictimer[0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = splhi();
|
||||||
|
a = &lapictimer[m->machno];
|
||||||
|
a->tdx = 0;
|
||||||
|
Retry:
|
||||||
|
lapicw(LapicTIMER, ApicIMASK|LapicCLKIN|LapicONESHOT|(VectorPIC+IrqTIMER));
|
||||||
|
lapicw(LapicTDCR, lapictdxtab[a->tdx]);
|
||||||
|
|
||||||
|
x = fastticks(&hz);
|
||||||
|
x += hz/10;
|
||||||
|
lapicw(LapicTICR, 0xffffffff);
|
||||||
|
do{
|
||||||
|
v = fastticks(nil);
|
||||||
|
}while(v < x);
|
||||||
|
|
||||||
|
v = (0xffffffffUL-lapicr(LapicTCCR))*10;
|
||||||
|
if(v > hz-(hz/10)){
|
||||||
|
if(v > hz+(hz/10) && a->tdx < nelem(lapictdxtab)-1){
|
||||||
|
a->tdx++;
|
||||||
|
goto Retry;
|
||||||
|
}
|
||||||
|
v = hz;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(v >= (100*HZ));
|
||||||
|
|
||||||
|
a->hz = v;
|
||||||
|
a->div = hz/a->hz;
|
||||||
|
a->max = a->hz/HZ;
|
||||||
|
a->min = a->hz/(100*HZ);
|
||||||
|
|
||||||
|
splx(s);
|
||||||
|
|
||||||
|
v = (v+500000LL)/1000000LL;
|
||||||
|
print("cpu%d: lapic clock at %lludMHz\n", m->machno, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lapicinit(Apic* apic)
|
||||||
|
{
|
||||||
|
uint32_t dfr, ldr, lvt;
|
||||||
|
|
||||||
|
if(lapicbase == 0)
|
||||||
|
lapicbase = apic->addr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These don't really matter in Physical mode;
|
* These don't really matter in Physical mode;
|
||||||
* set the defaults anyway.
|
* set the defaults anyway.
|
||||||
*/
|
*/
|
||||||
// if(jehanne_memcmp(m->cpuinfo, "AuthenticAMD", 12) == 0)
|
if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0)
|
||||||
// dfr = 0xf0000000;
|
dfr = 0xf0000000;
|
||||||
// else
|
else
|
||||||
dfr = 0xffffffff;
|
dfr = 0xffffffff;
|
||||||
lapicrput(Df, dfr);
|
ldr = 0x00000000;
|
||||||
lapicrput(Ld, 0x00000000);
|
|
||||||
|
lapicw(LapicDFR, dfr);
|
||||||
|
lapicw(LapicLDR, ldr);
|
||||||
|
lapicw(LapicTPR, 0xff);
|
||||||
|
lapicw(LapicSVR, LapicENABLE|(VectorPIC+IrqSPURIOUS));
|
||||||
|
|
||||||
|
lapictimerinit();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable interrupts until ready by setting the Task Priority
|
* Some Pentium revisions have a bug whereby spurious
|
||||||
* register to 0xff.
|
* interrupts are generated in the through-local mode.
|
||||||
*/
|
*/
|
||||||
lapicrput(Tp, 0xff);
|
switch(m->cpuidax & 0xFFF){
|
||||||
|
case 0x526: /* stepping cB1 */
|
||||||
/*
|
case 0x52B: /* stepping E0 */
|
||||||
* Software-enable the APIC in the Spurious Interrupt Vector
|
case 0x52C: /* stepping cC0 */
|
||||||
* register and set the vector number. The vector number must have
|
wrmsr(0x0E, 1<<14); /* TR12 */
|
||||||
* bits 3-0 0x0f unless the Extended Spurious Vector Enable bit
|
|
||||||
* is set in the HyperTransport Transaction Control register.
|
|
||||||
*/
|
|
||||||
lapicrput(Siv, Swen|IdtSPURIOUS);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Acknowledge any outstanding interrupts.
|
|
||||||
*/
|
|
||||||
lapicrput(Eoi, 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use the TSC to determine the lapic timer frequency.
|
|
||||||
* It might be possible to snarf this from a chipset
|
|
||||||
* register instead.
|
|
||||||
*/
|
|
||||||
lapicrput(Tdc, DivX1);
|
|
||||||
lapicrput(Tlvt, Im);
|
|
||||||
tsc = rdtsc() + m->cpuhz/10;
|
|
||||||
lapicrput(Tic, 0xffffffff);
|
|
||||||
|
|
||||||
while(rdtsc() < tsc)
|
|
||||||
;
|
|
||||||
|
|
||||||
apic->hz = (0xffffffff-lapicrget(Tcc))*10;
|
|
||||||
apic->max = apic->hz/HZ;
|
|
||||||
apic->min = apic->hz/(100*HZ);
|
|
||||||
apic->div = ((m->cpuhz/apic->max)+HZ/2)/HZ;
|
|
||||||
|
|
||||||
if(m->machno == 0 || DBGFLG){
|
|
||||||
jehanne_print("lapic%d: hz %lld max %lld min %lld div %lld\n", apicno,
|
|
||||||
apic->hz, apic->max, apic->min, apic->div);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mask interrupts on Performance Counter overflow and
|
|
||||||
* Thermal Sensor if implemented, and on Lintr0 (Legacy INTR),
|
|
||||||
* and Lintr1 (Legacy NMI).
|
|
||||||
* Clear any Error Status (write followed by read) and enable
|
|
||||||
* the Error interrupt.
|
|
||||||
*/
|
|
||||||
switch(apic->nlvt){
|
|
||||||
case 7:
|
|
||||||
case 6:
|
|
||||||
lapicrput(Tslvt, Im);
|
|
||||||
/*FALLTHROUGH*/
|
|
||||||
case 5:
|
|
||||||
lapicrput(Pclvt, Im);
|
|
||||||
/*FALLTHROUGH*/
|
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lapicrput(Lint1, apic->lvt[1]|Im|IdtLINT1);
|
|
||||||
lapicrput(Lint0, apic->lvt[0]|Im|IdtLINT0);
|
|
||||||
|
|
||||||
lapicrput(Es, 0);
|
|
||||||
lapicrget(Es);
|
|
||||||
lapicrput(Elvt, IdtERROR);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reload the timer to de-synchronise the processors.
|
* Set the local interrupts. It's likely these should just be
|
||||||
* When the caller is ready for the APIC to accept interrupts,
|
* masked off for SMP mode as some Pentium Pros have problems if
|
||||||
* it should call lapicpri to lower the task priority.
|
* LINT[01] are set to ExtINT.
|
||||||
*
|
* Acknowledge any outstanding interrupts.
|
||||||
* The timer is enabled later by the core-specific startup
|
lapicw(LapicLINT0, apic->lintr[0]);
|
||||||
* i.e. don't start the timer unless the core needs it,
|
lapicw(LapicLINT1, apic->lintr[1]);
|
||||||
* to reduce the likelihood of at least one (spurious) interrupt
|
*/
|
||||||
* from the timer when priority is lowered.
|
lapiceoi(0);
|
||||||
|
|
||||||
|
lvt = (lapicr(LapicVER)>>16) & 0xFF;
|
||||||
|
if(lvt >= 4)
|
||||||
|
lapicw(LapicPCINT, ApicIMASK);
|
||||||
|
lapicw(LapicERROR, VectorPIC+IrqERROR);
|
||||||
|
lapicw(LapicESR, 0);
|
||||||
|
lapicr(LapicESR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Issue an INIT Level De-Assert to synchronise arbitration ID's.
|
||||||
|
*/
|
||||||
|
lapicw(LapicICRHI, 0);
|
||||||
|
lapicw(LapicICRLO, LapicALLINC|ApicLEVEL|LapicDEASSERT|ApicINIT);
|
||||||
|
while(lapicr(LapicICRLO) & ApicDELIVS)
|
||||||
|
;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not allow acceptance of interrupts until all initialisation
|
||||||
|
* for this processor is done. For the bootstrap processor this can be
|
||||||
|
* early duing initialisation. For the application processors this should
|
||||||
|
* be after the bootstrap processor has lowered priority and is accepting
|
||||||
|
* interrupts.
|
||||||
|
lapicw(LapicTPR, 0);
|
||||||
*/
|
*/
|
||||||
microdelay((TK2MS(1)*1000/sys->nmach) * m->machno);
|
|
||||||
lapicrput(Tic, apic->max);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapictimerenable(void)
|
lapicstartap(Apic* apic, uintptr_t pa)
|
||||||
{
|
{
|
||||||
/*
|
int i;
|
||||||
* Perhaps apictimerenable/apictimerdisable should just
|
uint32_t crhi, crlo;
|
||||||
* clear/set Im in the existing settings of Tlvt, there may
|
|
||||||
* be a time when the timer is used in a different mode;
|
/* make apic's processor do a warm reset */
|
||||||
* if so will need to ensure the mode is set when the timer
|
crhi = apic->apicno<<24;
|
||||||
* is initialised.
|
lapicw(LapicICRHI, crhi);
|
||||||
*/
|
lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicASSERT|ApicINIT);
|
||||||
lapicrput(Tlvt, Periodic|IdtTIMER);
|
microdelay(200);
|
||||||
|
lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicDEASSERT|ApicINIT);
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
/* assumes apic is not an 82489dx */
|
||||||
|
crlo = LapicFIELD|ApicEDGE|ApicSTARTUP|((uint32_t)pa/BY2PG);
|
||||||
|
for(i = 0; i < 2; i++){
|
||||||
|
lapicw(LapicICRHI, crhi);
|
||||||
|
/* make apic's processor start at v in real mode */
|
||||||
|
lapicw(LapicICRLO, crlo);
|
||||||
|
microdelay(200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapictimerdisable(void)
|
lapicerror(Ureg* _, void* __)
|
||||||
{
|
{
|
||||||
lapicrput(Tlvt, Im|IdtTIMER);
|
uint32_t esr;
|
||||||
|
|
||||||
|
lapicw(LapicESR, 0);
|
||||||
|
esr = lapicr(LapicESR);
|
||||||
|
switch(m->cpuidax & 0xFFF){
|
||||||
|
case 0x526: /* stepping cB1 */
|
||||||
|
case 0x52B: /* stepping E0 */
|
||||||
|
case 0x52C: /* stepping cC0 */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
print("cpu%d: lapicerror: 0x%8.8luX\n", m->machno, esr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lapicspurious(Ureg* _, void* __)
|
||||||
|
{
|
||||||
|
print("cpu%d: lapicspurious\n", m->machno);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lapicisr(int v)
|
||||||
|
{
|
||||||
|
uint32_t isr;
|
||||||
|
|
||||||
|
isr = lapicr(LapicISR + (v/32));
|
||||||
|
|
||||||
|
return isr & (1<<(v%32));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lapiceoi(int v)
|
||||||
|
{
|
||||||
|
lapicw(LapicEOI, 0);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lapicicrw(uint32_t hi, uint32_t lo)
|
||||||
|
{
|
||||||
|
lapicw(LapicICRHI, hi);
|
||||||
|
lapicw(LapicICRLO, lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ioapicrdtr(Apic* apic, int sel, int* hi, int* lo)
|
||||||
|
{
|
||||||
|
uint32_t *iowin;
|
||||||
|
|
||||||
|
iowin = apic->addr+(0x10/sizeof(uint32_t));
|
||||||
|
sel = IoapicRDT + 2*sel;
|
||||||
|
|
||||||
|
lock(apic);
|
||||||
|
*apic->addr = sel+1;
|
||||||
|
if(hi)
|
||||||
|
*hi = *iowin;
|
||||||
|
*apic->addr = sel;
|
||||||
|
if(lo)
|
||||||
|
*lo = *iowin;
|
||||||
|
unlock(apic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ioapicrdtw(Apic* apic, int sel, int hi, int lo)
|
||||||
|
{
|
||||||
|
uint32_t *iowin;
|
||||||
|
|
||||||
|
iowin = apic->addr+(0x10/sizeof(uint32_t));
|
||||||
|
sel = IoapicRDT + 2*sel;
|
||||||
|
|
||||||
|
lock(apic);
|
||||||
|
*apic->addr = sel+1;
|
||||||
|
*iowin = hi;
|
||||||
|
*apic->addr = sel;
|
||||||
|
*iowin = lo;
|
||||||
|
unlock(apic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ioapicinit(Apic* apic, int apicno)
|
||||||
|
{
|
||||||
|
int hi, lo, v;
|
||||||
|
uint32_t *iowin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialise the I/O APIC.
|
||||||
|
* The MultiProcessor Specification says it is the responsibility
|
||||||
|
* of the O/S to set the APIC id.
|
||||||
|
* Make sure interrupts are all masked off for now.
|
||||||
|
*/
|
||||||
|
iowin = apic->addr+(0x10/sizeof(uint32_t));
|
||||||
|
lock(apic);
|
||||||
|
*apic->addr = IoapicVER;
|
||||||
|
apic->mre = (*iowin>>16) & 0xFF;
|
||||||
|
|
||||||
|
*apic->addr = IoapicID;
|
||||||
|
*iowin = apicno<<24;
|
||||||
|
unlock(apic);
|
||||||
|
|
||||||
|
hi = 0;
|
||||||
|
lo = ApicIMASK;
|
||||||
|
for(v = 0; v <= apic->mre; v++)
|
||||||
|
ioapicrdtw(apic, v, hi, lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapictimerset(uint64_t next)
|
lapictimerset(uint64_t next)
|
||||||
{
|
{
|
||||||
Lapic *apic;
|
|
||||||
int64_t period;
|
int64_t period;
|
||||||
|
Apictimer *a;
|
||||||
|
|
||||||
apic = &xlapic[(lapicrget(Id)>>24) & 0xff];
|
a = &lapictimer[m->machno];
|
||||||
|
period = next - fastticks(nil);
|
||||||
ilock(&m->apictimerlock);
|
period /= a->div;
|
||||||
|
if(period < a->min)
|
||||||
period = apic->max;
|
period = a->min;
|
||||||
if(next != 0){
|
else if(period > a->max - a->min)
|
||||||
if(apic->div == 0){
|
period = a->max;
|
||||||
jehanne_print("lapictimerset: apic not ready, wait for gdb\n");
|
lapicw(LapicTICR, period);
|
||||||
waitdebugger();
|
|
||||||
}
|
|
||||||
period = next - fastticks(nil); /* fastticks is just rdtsc() */
|
|
||||||
period /= apic->div;
|
|
||||||
|
|
||||||
if(period < apic->min)
|
|
||||||
period = apic->min;
|
|
||||||
else if(period > apic->max - apic->min)
|
|
||||||
period = apic->max;
|
|
||||||
}
|
|
||||||
lapicrput(Tic, period);
|
|
||||||
|
|
||||||
iunlock(&m->apictimerlock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapicsipi(int lapicno, uintmem pa)
|
lapicclock(Ureg *u, void* _)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
uint32_t crhi, crlo;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIPI - Start-up IPI.
|
* since the MTRR updates need to be synchronized across processors,
|
||||||
* To do: checks on lapic validity.
|
* we want to do this within the clock tick.
|
||||||
*/
|
*/
|
||||||
crhi = lapicno<<24;
|
mtrrclock();
|
||||||
lapicrput(Ichi, crhi);
|
timerintr(u, 0);
|
||||||
lapicrput(Iclo, DSnone|TMlevel|Lassert|MTir);
|
|
||||||
microdelay(200);
|
|
||||||
lapicrput(Iclo, DSnone|TMlevel|MTir);
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
crlo = DSnone|TMedge|MTsipi|((uint32_t)pa/(4*KiB));
|
|
||||||
for(i = 0; i < 2; i++){
|
|
||||||
lapicrput(Ichi, crhi);
|
|
||||||
lapicrput(Iclo, crlo);
|
|
||||||
microdelay(200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapicipi(int lapicno)
|
lapicintron(void)
|
||||||
{
|
{
|
||||||
lapicrput(Ichi, lapicno<<24);
|
lapicw(LapicTPR, 0);
|
||||||
lapicrput(Iclo, DSnone|TMedge|Lassert|MTf|IdtIPI);
|
|
||||||
while(lapicrget(Iclo) & Ds)
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapicpri(int pri)
|
lapicintroff(void)
|
||||||
{
|
{
|
||||||
lapicrput(Tp, pri);
|
lapicw(LapicTPR, 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lapicnmienable(void)
|
||||||
|
{
|
||||||
|
lapicw(LapicPCINT, ApicNMI);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lapicnmidisable(void)
|
||||||
|
{
|
||||||
|
lapicw(LapicPCINT, ApicIMASK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
"Include": [
|
"Include": [
|
||||||
"core.json",
|
"core.json",
|
||||||
"devdraw.json",
|
"devdraw.json",
|
||||||
"../386/include.json",
|
|
||||||
"../ip/include.json",
|
"../ip/include.json",
|
||||||
"../port/include.json"
|
"../port/include.json"
|
||||||
],
|
],
|
||||||
|
@ -18,7 +17,6 @@
|
||||||
"int printallsyscalls;"
|
"int printallsyscalls;"
|
||||||
],
|
],
|
||||||
"Dev": [
|
"Dev": [
|
||||||
"acpi",
|
|
||||||
"arch",
|
"arch",
|
||||||
"bridge",
|
"bridge",
|
||||||
"cap",
|
"cap",
|
||||||
|
@ -85,7 +83,6 @@
|
||||||
"SourceFiles": [
|
"SourceFiles": [
|
||||||
"autogenerated.c",
|
"autogenerated.c",
|
||||||
"cga.c",
|
"cga.c",
|
||||||
"devacpi.c",
|
|
||||||
"usbehcipc.c",
|
"usbehcipc.c",
|
||||||
"usbohci.c",
|
"usbohci.c",
|
||||||
"usbuhci.c"
|
"usbuhci.c"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of Jehanne.
|
* This file is part of Jehanne.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2016 Giacomo Tesio <giacomo@tesio.it>
|
* Copyright (C) 2015-2017 Giacomo Tesio <giacomo@tesio.it>
|
||||||
*
|
*
|
||||||
* Jehanne is free software: you can redistribute it and/or modify
|
* Jehanne is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,19 +20,16 @@
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
#include "ureg.h"
|
||||||
|
#include "pool.h"
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
|
|
||||||
extern void confoptions(void); /* XXX - must go */
|
|
||||||
extern void confsetenv(void); /* XXX - must go */
|
|
||||||
|
|
||||||
static uintptr_t sp; /* XXX - must go - user stack of init proc */
|
static uintptr_t sp; /* XXX - must go - user stack of init proc */
|
||||||
|
|
||||||
Sys* sys = (Sys*)0x1; /* dummy value to put it in data section
|
Sys system;
|
||||||
* - entry.S set it correctly
|
Sys* sys;
|
||||||
* - main memset to zero the bss section
|
|
||||||
*/
|
|
||||||
usize sizeofSys = sizeof(Sys);
|
usize sizeofSys = sizeof(Sys);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -42,7 +39,7 @@ usize sizeofSys = sizeof(Sys);
|
||||||
* set it all up.
|
* set it all up.
|
||||||
*/
|
*/
|
||||||
static int64_t oargc;
|
static int64_t oargc;
|
||||||
static char* oargv[20];
|
static char* oargv[64];
|
||||||
static char oargb[1024];
|
static char oargb[1024];
|
||||||
static int oargblen;
|
static int oargblen;
|
||||||
|
|
||||||
|
@ -51,7 +48,6 @@ static int numtcs = 32; /* initial # of TCs */
|
||||||
IOConf ioconf;
|
IOConf ioconf;
|
||||||
int procmax;
|
int procmax;
|
||||||
|
|
||||||
char *cputype = "amd64";
|
|
||||||
char dbgflg[256];
|
char dbgflg[256];
|
||||||
static int vflag = 1;
|
static int vflag = 1;
|
||||||
|
|
||||||
|
@ -63,6 +59,30 @@ optionsinit(char* s)
|
||||||
oargv[oargc] = nil;
|
oargv[oargc] = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
getconf(char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *a;
|
||||||
|
|
||||||
|
for(i = 0; i < oargc; i++){
|
||||||
|
a = strstr(oargv[i], name);
|
||||||
|
if(a == oargv[i]){
|
||||||
|
a += strlen(name);
|
||||||
|
if(a[0] == '=')
|
||||||
|
return ++a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isaconfig(char *class, int ctlrno, ISAConf *isa)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
options(int argc, char* argv[])
|
options(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
@ -129,251 +149,204 @@ loadenv(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
squidboy(int apicno)
|
initialize_processor(void)
|
||||||
{
|
{
|
||||||
int64_t hz;
|
int machno;
|
||||||
|
Segdesc *gdt;
|
||||||
|
uintptr_t *pml4;
|
||||||
|
|
||||||
sys->machptr[m->machno] = m;
|
machno = m->machno;
|
||||||
|
pml4 = m->pml4;
|
||||||
/*
|
gdt = m->gdt;
|
||||||
* Need something for initial delays
|
memset(m, 0, sizeof(Mach));
|
||||||
* until a timebase is worked out.
|
m->machno = machno;
|
||||||
*/
|
m->pml4 = pml4;
|
||||||
m->cpuhz = sys->machptr[0]->cpuhz;
|
m->gdt = gdt;
|
||||||
m->cyclefreq = m->cpuhz;
|
|
||||||
m->cpumhz = sys->machptr[0]->cpumhz;
|
|
||||||
m->perf.period = 1;
|
m->perf.period = 1;
|
||||||
|
|
||||||
DBG("Hello Squidboy %d %d\n", apicno, m->machno);
|
|
||||||
|
|
||||||
vsvminit(MACHSTKSZ);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Beware the Curse of The Non-Interruptable Were-Temporary.
|
* For polled uart output at boot, need
|
||||||
|
* a default delay constant. 100000 should
|
||||||
|
* be enough for a while. Cpuidentify will
|
||||||
|
* calculate the real value later.
|
||||||
*/
|
*/
|
||||||
hz = archhz();
|
m->loopconst = 100000;
|
||||||
if(hz == 0)
|
|
||||||
ndnr();
|
|
||||||
m->cpuhz = hz;
|
|
||||||
m->cpumhz = hz/1000000ll;
|
|
||||||
|
|
||||||
archenable();
|
|
||||||
|
|
||||||
mmuinit();
|
|
||||||
if(!lapiconline())
|
|
||||||
ndnr();
|
|
||||||
|
|
||||||
fpuinit();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handshake with sipi to let it
|
|
||||||
* know the Startup IPI succeeded.
|
|
||||||
*/
|
|
||||||
m->splpc = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handshake with main to proceed with initialisation.
|
|
||||||
*/
|
|
||||||
while(sys->epoch == 0)
|
|
||||||
;
|
|
||||||
wrmsr(0x10, sys->epoch);
|
|
||||||
m->rdtsc = rdtsc();
|
|
||||||
|
|
||||||
DBG("mach %d is go %#p %#p %3p\n", m->machno, m, m->pml4->pte, &apicno);
|
|
||||||
|
|
||||||
timersinit();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Cannot allow interrupts while waiting for online.
|
|
||||||
* However, by taking the lowering of the APIC task priority
|
|
||||||
* out of apiconline something could be done here with
|
|
||||||
* MONITOR/MWAIT perhaps to drop the energy used by the
|
|
||||||
* idle core.
|
|
||||||
*/
|
|
||||||
while(!m->online)
|
|
||||||
pause();
|
|
||||||
lapictimerenable();
|
|
||||||
lapicpri(0);
|
|
||||||
|
|
||||||
jehanne_print("mach%d: online color %d\n", m->machno, m->color);
|
|
||||||
schedinit();
|
|
||||||
|
|
||||||
panic("squidboy returns (type %d)", m->mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define D(c) if(0)outb(0x3f8, (c))
|
static void
|
||||||
|
initialize_boot_processor(void)
|
||||||
void
|
|
||||||
main(uint32_t ax, uint32_t bx)
|
|
||||||
{
|
{
|
||||||
int i;
|
system.nmach = 1;
|
||||||
int64_t hz;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
jehanne_memset(edata, 0, end - edata);
|
system.machptr[0] = m; /* m was set by entry.S */
|
||||||
|
|
||||||
/*
|
|
||||||
* ilock via i8250enable via i8250console
|
|
||||||
* needs m->machno, sys->machptr[] set, and
|
|
||||||
* also 'up' set to nil.
|
|
||||||
*/
|
|
||||||
cgapost(sizeof(uintptr_t)*8);
|
|
||||||
jehanne_memset(m, 0, sizeof(Mach));
|
|
||||||
m->machno = 0;
|
m->machno = 0;
|
||||||
|
m->pml4 = (uint64_t*)CPU0PML4;
|
||||||
|
m->gdt = (Segdesc*)CPU0GDT;
|
||||||
|
|
||||||
|
initialize_processor();
|
||||||
|
|
||||||
|
active.machs[0] = 1;
|
||||||
m->online = 1;
|
m->online = 1;
|
||||||
sys->machptr[m->machno] = &sys->mach;
|
|
||||||
m->stack = PTR2UINT(sys->machstk);
|
|
||||||
m->vsvm = sys->vsvmpage;
|
|
||||||
sys->nmach = 1;
|
|
||||||
sys->nonline = 1;
|
|
||||||
sys->copymode = 0; /* copy on write */
|
|
||||||
up = nil;
|
|
||||||
|
|
||||||
confoptions();
|
|
||||||
asminit();
|
|
||||||
multiboot(ax, bx, 0);
|
|
||||||
options(oargc, oargv);
|
|
||||||
p = getconf("*dbflags");
|
|
||||||
if(p != nil){
|
|
||||||
for(; *p != 0; p++)
|
|
||||||
if(*p >= 'a' && *p <= 'z' || *p >= 'A' && *p <= 'Z')
|
|
||||||
dbgflg[(uint8_t)*p] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Need something for initial delays
|
|
||||||
* until a timebase is worked out.
|
|
||||||
*/
|
|
||||||
m->cpuhz = 2000000000ll;
|
|
||||||
m->cpumhz = 2000;
|
|
||||||
|
|
||||||
cgainit();
|
|
||||||
i8250console("0");
|
|
||||||
consputs = cgaconsputs;
|
|
||||||
|
|
||||||
vsvminit(MACHSTKSZ);
|
|
||||||
|
|
||||||
active.exiting = 0;
|
active.exiting = 0;
|
||||||
|
|
||||||
fmtinit();
|
|
||||||
jehanne_print("\nJehanne Operating System\n");
|
|
||||||
|
|
||||||
if(vflag){
|
|
||||||
jehanne_print("&ax = %#p, ax = %#ux, bx = %#ux\n", &ax, ax, bx);
|
|
||||||
multiboot(ax, bx, vflag);
|
|
||||||
}
|
|
||||||
e820();
|
|
||||||
|
|
||||||
m->perf.period = 1;
|
|
||||||
if((hz = archhz()) != 0ll){
|
|
||||||
m->cpuhz = hz;
|
|
||||||
m->cpumhz = hz/1000000ll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
archenable();
|
static void
|
||||||
|
intialize_system(void)
|
||||||
|
{
|
||||||
|
extern Ureg _boot_registers;
|
||||||
|
uintptr_t p;
|
||||||
|
|
||||||
/*
|
p = (uintptr_t)&_boot_registers;
|
||||||
* Mmuinit before meminit because it
|
p += KZERO;
|
||||||
* makes mappings and
|
sys = &system;
|
||||||
* flushes the TLB via m->pml4->pa.
|
sys->boot_regs = (void*)p;
|
||||||
*/
|
sys->architecture = "amd64";
|
||||||
mmuinit();
|
}
|
||||||
|
|
||||||
ioinit();
|
static void
|
||||||
keybinit();
|
configure_kernel(void)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
int i, userpcnt;
|
||||||
|
unsigned int kpages;
|
||||||
|
|
||||||
meminit();
|
if(p = getconf("service")){
|
||||||
archinit();
|
if(strcmp(p, "cpu") == 0)
|
||||||
physallocinit();
|
cpuserver = 1;
|
||||||
D('a');
|
else if(strcmp(p,"terminal") == 0)
|
||||||
mallocinit();
|
cpuserver = 0;
|
||||||
D('b');
|
}
|
||||||
memdebug();
|
|
||||||
trapinit();
|
|
||||||
D('c');
|
|
||||||
|
|
||||||
/*
|
/* memory */
|
||||||
* Printinit will cause the first malloc
|
if(p = getconf("*kernelpercent"))
|
||||||
* call to happen (printinit->qopen->malloc).
|
userpcnt = 100 - strtol(p, 0, 0);
|
||||||
* If the system dies here it's probably due
|
else
|
||||||
* to malloc not being initialised
|
userpcnt = 0;
|
||||||
* correctly, or the data segment is misaligned
|
|
||||||
* (it's amazing how far you can get with
|
|
||||||
* things like that completely broken).
|
|
||||||
*/
|
|
||||||
printinit();
|
|
||||||
D('d');
|
|
||||||
/*
|
|
||||||
* This is necessary with GRUB and QEMU.
|
|
||||||
* Without it an interrupt can occur at a weird vector,
|
|
||||||
* because the vector base is likely different, causing
|
|
||||||
* havoc. Do it before any APIC initialisation.
|
|
||||||
*/
|
|
||||||
i8259init(IdtPIC);
|
|
||||||
D('e');
|
|
||||||
|
|
||||||
acpiinit(MACHMAX);
|
sys->npages = 0;
|
||||||
D('f');
|
for(i=0; i<nelem(sys->mem); i++)
|
||||||
// mpsinit();
|
sys->npages += sys->mem[i].npage;
|
||||||
D('g');
|
|
||||||
lapiconline();
|
|
||||||
ioapiconline();
|
|
||||||
D('h');
|
|
||||||
intrenable(IdtTIMER, timerintr, 0, -1, "APIC timer");
|
|
||||||
lapictimerenable();
|
|
||||||
lapicpri(0);
|
|
||||||
D('i');
|
|
||||||
|
|
||||||
timersinit();
|
/* processes */
|
||||||
D('j');
|
|
||||||
keybenable();
|
|
||||||
mouseenable();
|
|
||||||
D('k');
|
|
||||||
fpuinit();
|
|
||||||
D('l');
|
|
||||||
p = getconf("*procmax");
|
p = getconf("*procmax");
|
||||||
if(p != nil)
|
if(p != nil)
|
||||||
procmax = jehanne_strtoull(p, nil, 0);
|
sys->nproc = jehanne_strtoull(p, nil, 0);
|
||||||
if(procmax == 0)
|
if(sys->nproc == 0){
|
||||||
procmax = 2000;
|
sys->nproc = 100 + ((sys->npages*PGSZ)/MiB)*5;
|
||||||
psinit(procmax);
|
if(cpuserver)
|
||||||
D('m');
|
sys->nproc *= 3;
|
||||||
// imagepool_init();
|
|
||||||
D('n');
|
|
||||||
links();
|
|
||||||
D('o');
|
|
||||||
devtabreset();
|
|
||||||
D('p');
|
|
||||||
umem_init();
|
|
||||||
D('r');
|
|
||||||
|
|
||||||
userinit();
|
|
||||||
D('s');
|
|
||||||
if(!dbgflg['S'])
|
|
||||||
sipi();
|
|
||||||
D('t');
|
|
||||||
|
|
||||||
sys->epoch = rdtsc();
|
|
||||||
wrmsr(0x10, sys->epoch);
|
|
||||||
m->rdtsc = rdtsc();
|
|
||||||
|
|
||||||
D('u');
|
|
||||||
/*
|
|
||||||
* Release the hounds.
|
|
||||||
*/
|
|
||||||
for(i = 1; i < MACHMAX; i++){
|
|
||||||
if(sys->machptr[i] == nil)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ainc(&sys->nonline);
|
|
||||||
|
|
||||||
sys->machptr[i]->color = corecolor(i);
|
|
||||||
if(sys->machptr[i]->color < 0)
|
|
||||||
sys->machptr[i]->color = 0;
|
|
||||||
sys->machptr[i]->online = 1;
|
|
||||||
}
|
}
|
||||||
D('v');
|
if(sys->nproc > 2046){
|
||||||
prflush();
|
/* devproc supports at most (2^11)-2 processes */
|
||||||
|
sys->nproc = 2046;
|
||||||
|
}
|
||||||
|
sys->nimage = 256;
|
||||||
|
|
||||||
|
if(cpuserver) {
|
||||||
|
if(userpcnt < 10)
|
||||||
|
userpcnt = 70;
|
||||||
|
kpages = sys->npages - (sys->npages*userpcnt)/100;
|
||||||
|
sys->nimage = sys->nproc;
|
||||||
|
} else {
|
||||||
|
if(userpcnt < 10) {
|
||||||
|
if(sys->npages*PGSZ < 16*MiB)
|
||||||
|
userpcnt = 50;
|
||||||
|
else
|
||||||
|
userpcnt = 60;
|
||||||
|
}
|
||||||
|
kpages = sys->npages - (sys->npages*userpcnt)/100;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure terminals with low memory get at least
|
||||||
|
* 4MB on the first Image chunk allocation.
|
||||||
|
*/
|
||||||
|
if(sys->npages*PGSZ < 16*MiB)
|
||||||
|
imagmem->minarena = 4*MiB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* can't go past the end of virtual memory.
|
||||||
|
*/
|
||||||
|
if(kpages > ((uintptr_t)-KZERO)/PGSZ)
|
||||||
|
kpages = ((uintptr_t)-KZERO)/PGSZ;
|
||||||
|
|
||||||
|
sys->upages = sys->npages - kpages;
|
||||||
|
sys->ialloc = (kpages/2)*PGSZ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Guess how much is taken by the large permanent
|
||||||
|
* datastructures. Mntcache and Mntrpc are not accounted for.
|
||||||
|
*/
|
||||||
|
kpages *= PGSZ;
|
||||||
|
kpages -= sys->nproc*sizeof(Proc);
|
||||||
|
mainmem->maxsize = kpages;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the dynamic allocation will balance the load properly,
|
||||||
|
* hopefully. be careful with 32-bit overflow.
|
||||||
|
*/
|
||||||
|
imagmem->maxsize = kpages - (kpages/10);
|
||||||
|
if(p = getconf("*imagemaxmb")){
|
||||||
|
imagmem->maxsize = strtol(p, nil, 0)*MiB;
|
||||||
|
if(imagmem->maxsize > mainmem->maxsize)
|
||||||
|
imagmem->maxsize = mainmem->maxsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
intialize_system();
|
||||||
|
initialize_boot_processor();
|
||||||
|
|
||||||
|
multiboot(0);
|
||||||
|
options(oargc, oargv);
|
||||||
|
|
||||||
|
ioinit();
|
||||||
|
i8250console();
|
||||||
|
fmtinit();
|
||||||
|
screen_init();
|
||||||
|
|
||||||
|
jehanne_print("\nJehanne Operating System\n");
|
||||||
|
|
||||||
|
trapinit0();
|
||||||
|
// i8259init();
|
||||||
|
|
||||||
|
i8253init();
|
||||||
|
cpuidentify();
|
||||||
|
meminit();
|
||||||
|
|
||||||
|
configure_kernel();
|
||||||
|
|
||||||
|
xinit();
|
||||||
|
archinit();
|
||||||
|
// bootscreeninit();
|
||||||
|
// if(i8237alloc != nil)
|
||||||
|
// i8237alloc();
|
||||||
|
trapinit();
|
||||||
|
printinit();
|
||||||
|
cpuidprint();
|
||||||
|
mmuinit();
|
||||||
|
if(arch->intrinit)
|
||||||
|
arch->intrinit();
|
||||||
|
timersinit();
|
||||||
|
// keybinit();
|
||||||
|
// keybenable();
|
||||||
|
// mouseenable();
|
||||||
|
mathinit();
|
||||||
|
if(arch->clockenable)
|
||||||
|
arch->clockenable();
|
||||||
|
|
||||||
|
psinit(sys->nproc);
|
||||||
|
|
||||||
|
links();
|
||||||
|
|
||||||
|
devtabreset();
|
||||||
|
umem_init();
|
||||||
|
userinit();
|
||||||
schedinit();
|
schedinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,8 +357,6 @@ init0(void)
|
||||||
|
|
||||||
up->nerrlab = 0;
|
up->nerrlab = 0;
|
||||||
|
|
||||||
// if(consuart == nil)
|
|
||||||
// i8250console("0");
|
|
||||||
spllo();
|
spllo();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -408,11 +379,11 @@ init0(void)
|
||||||
ksetenv("service", "cpu", 0);
|
ksetenv("service", "cpu", 0);
|
||||||
else
|
else
|
||||||
ksetenv("service", "terminal", 0);
|
ksetenv("service", "terminal", 0);
|
||||||
confsetenv();
|
|
||||||
poperror();
|
poperror();
|
||||||
}
|
}
|
||||||
kproc("alarm", alarmkproc, 0);
|
kproc("alarm", alarmkproc, 0);
|
||||||
kproc("awake", awakekproc, 0);
|
kproc("atimer", awake_timer, 0);
|
||||||
|
kproc("aringer", awake_ringer, 0);
|
||||||
touser(sp);
|
touser(sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,17 +432,23 @@ userinit(void)
|
||||||
char *k;
|
char *k;
|
||||||
uintptr_t va, mmuphys;
|
uintptr_t va, mmuphys;
|
||||||
|
|
||||||
p = newproc();
|
/* NOTE: we use the global pointer up so that the kaddr()
|
||||||
p->pgrp = newpgrp();
|
* (called by segment_fault) can find it
|
||||||
p->egrp = smalloc(sizeof(Egrp));
|
*/
|
||||||
p->egrp->r.ref = 1;
|
up = newproc();
|
||||||
p->fgrp = dupfgrp(nil);
|
up->pgrp = newpgrp();
|
||||||
p->rgrp = newrgrp();
|
up->egrp = smalloc(sizeof(Egrp));
|
||||||
p->procmode = 0640;
|
up->egrp->r.ref = 1;
|
||||||
|
up->fgrp = dupfgrp(nil);
|
||||||
|
up->rgrp = newrgrp();
|
||||||
|
up->procmode = 0640;
|
||||||
|
|
||||||
kstrdup(&eve, "");
|
kstrdup(&eve, "");
|
||||||
kstrdup(&p->text, "*init*");
|
kstrdup(&up->text, "*init*");
|
||||||
kstrdup(&p->user, eve);
|
kstrdup(&up->user, eve);
|
||||||
|
|
||||||
|
sysprocsetup(up);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kernel Stack
|
* Kernel Stack
|
||||||
*
|
*
|
||||||
|
@ -480,23 +457,23 @@ userinit(void)
|
||||||
* space for gotolabel's return PC
|
* space for gotolabel's return PC
|
||||||
* AMD64 stack must be quad-aligned.
|
* AMD64 stack must be quad-aligned.
|
||||||
*/
|
*/
|
||||||
p->sched.pc = PTR2UINT(init0);
|
up->sched.pc = PTR2UINT(init0);
|
||||||
p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->arg)-sizeof(uintptr_t));
|
up->sched.sp = PTR2UINT(up->kstack+KSTACK-sizeof(up->arg)-sizeof(uintptr_t));
|
||||||
p->sched.sp = STACKALIGN(p->sched.sp);
|
up->sched.sp = STACKALIGN(up->sched.sp);
|
||||||
D('0');
|
|
||||||
/*
|
/*
|
||||||
* User Stack
|
* User Stack
|
||||||
*/
|
*/
|
||||||
s = nil;
|
s = nil;
|
||||||
if(!segment_virtual(&s, SgStack, SgRead|SgWrite, 0, USTKTOP-USTKSIZE, USTKTOP))
|
if(!segment_virtual(&s, SgStack, SgRead|SgWrite, 0, USTKTOP-USTKSIZE, USTKTOP))
|
||||||
panic("userinit: cannot create stack segment");
|
panic("userinit: cannot create stack segment");
|
||||||
D('1');
|
|
||||||
p->seg[SSEG] = s;
|
up->seg[SSEG] = s;
|
||||||
va = USTKTOP-USTKSIZE;
|
va = USTKTOP-USTKSIZE;
|
||||||
mmuphys = 0;
|
mmuphys = 0;
|
||||||
if(!segment_fault(&mmuphys, &va, s, FaultWrite))
|
if(!segment_fault(&mmuphys, &va, s, FaultWrite))
|
||||||
panic("userinit: cannot allocate first stack page");
|
panic("userinit: cannot allocate first stack page");
|
||||||
D('2');
|
|
||||||
page = segment_page(s, va);
|
page = segment_page(s, va);
|
||||||
if(page == 0)
|
if(page == 0)
|
||||||
panic("userinit: cannot find first stack page (previously faulted)");
|
panic("userinit: cannot find first stack page (previously faulted)");
|
||||||
|
@ -510,7 +487,7 @@ D('2');
|
||||||
s = nil;
|
s = nil;
|
||||||
if(!segment_userinit(&s, 0))
|
if(!segment_userinit(&s, 0))
|
||||||
panic("userinit: cannot create text segment");
|
panic("userinit: cannot create text segment");
|
||||||
p->seg[TSEG] = s;
|
up->seg[TSEG] = s;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Data
|
* Data
|
||||||
|
@ -518,8 +495,11 @@ D('2');
|
||||||
s = nil;
|
s = nil;
|
||||||
if(!segment_userinit(&s, 1))
|
if(!segment_userinit(&s, 1))
|
||||||
panic("userinit: cannot create data segment");
|
panic("userinit: cannot create data segment");
|
||||||
p->seg[DSEG] = s;
|
up->seg[DSEG] = s;
|
||||||
|
|
||||||
|
/* reset global pointer up */
|
||||||
|
p = up;
|
||||||
|
up = nil;
|
||||||
ready(p);
|
ready(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,7 +507,7 @@ static void
|
||||||
fullstop(void)
|
fullstop(void)
|
||||||
{
|
{
|
||||||
splhi();
|
splhi();
|
||||||
lapicpri(0xff);
|
// lapicpri(0xff);
|
||||||
/* i8259 was initialised as disabled */
|
/* i8259 was initialised as disabled */
|
||||||
for(;;)
|
for(;;)
|
||||||
_halt();
|
_halt();
|
||||||
|
@ -544,7 +524,7 @@ shutdown(int ispanic)
|
||||||
active.ispanic = ispanic;
|
active.ispanic = ispanic;
|
||||||
m->online = 0;
|
m->online = 0;
|
||||||
active.exiting = 1;
|
active.exiting = 1;
|
||||||
adec(&sys->nonline);
|
adec((int*)&sys->nmach);
|
||||||
|
|
||||||
iprint("cpu%d: exiting\n", m->machno);
|
iprint("cpu%d: exiting\n", m->machno);
|
||||||
/* wait for any other processors to shutdown */
|
/* wait for any other processors to shutdown */
|
||||||
|
@ -552,7 +532,7 @@ shutdown(int ispanic)
|
||||||
prflush();
|
prflush();
|
||||||
for(ms = 10*1000; ms > 0; ms -= 2){
|
for(ms = 10*1000; ms > 0; ms -= 2){
|
||||||
delay(2);
|
delay(2);
|
||||||
if(sys->nonline == 0 && consactive() == 0)
|
if(sys->nmach == 0 && consactive() == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Before mmuinit is done, we can't rely on sys->vmunmapped
|
|
||||||
* being set, so we use the static limit TMFM
|
|
||||||
*/
|
|
||||||
|
|
||||||
void*
|
|
||||||
KADDR(uintmem pa)
|
|
||||||
{
|
|
||||||
uint8_t* va;
|
|
||||||
|
|
||||||
va = UINT2PTR(pa);
|
|
||||||
if(sys->vmunmapped != 0){
|
|
||||||
if(pa < sys->vmunmapped-KSEG0)
|
|
||||||
return KSEG0+va;
|
|
||||||
}else if(pa < TMFM)
|
|
||||||
return KSEG0+va;
|
|
||||||
return KSEG2+va;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmem
|
|
||||||
PADDR(void* va)
|
|
||||||
{
|
|
||||||
uintmem pa;
|
|
||||||
|
|
||||||
pa = PTR2UINT(va);
|
|
||||||
if(pa >= KSEG2 && pa < KSEG1)
|
|
||||||
return pa-KSEG2;
|
|
||||||
if(pa >= KSEG0 && pa < KSEG0+TMFM)
|
|
||||||
return pa-KSEG0;
|
|
||||||
if(pa > KSEG2)
|
|
||||||
return pa-KSEG2;
|
|
||||||
|
|
||||||
panic("PADDR: va %#p pa #%p @ %#p\n", va, mmuphysaddr(PTR2UINT(va)), getcallerpc());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#define EiB gULL(1152921504606846976)
|
#define EiB gULL(1152921504606846976)
|
||||||
|
|
||||||
#define HOWMANY(x, y) (((x)+((y)-1))/(y))
|
#define HOWMANY(x, y) (((x)+((y)-1))/(y))
|
||||||
#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
|
#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1))
|
||||||
#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
|
#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
|
||||||
#define ROUNDDN(x, y) (((x)/(y))*(y))
|
#define ROUNDDN(x, y) (((x)/(y))*(y))
|
||||||
#define MIN(a, b) ((a) < (b)? (a): (b))
|
#define MIN(a, b) ((a) < (b)? (a): (b))
|
||||||
|
@ -44,21 +44,25 @@
|
||||||
*/
|
*/
|
||||||
#define BI2BY 8 /* bits per byte */
|
#define BI2BY 8 /* bits per byte */
|
||||||
#define BI2WD 32 /* bits per word */
|
#define BI2WD 32 /* bits per word */
|
||||||
#define BY2WD 4 /* bytes per word */
|
#define BY2WD 8 /* bytes per word */
|
||||||
#define BY2V 8 /* bytes per double word */
|
#define BY2V 8 /* bytes per double word */
|
||||||
#define BY2SE 8 /* bytes per stack element */
|
#define BY2SE 8 /* bytes per stack element */
|
||||||
#define BLOCKALIGN 8
|
#define BLOCKALIGN 8
|
||||||
|
|
||||||
#define PGSZ (4*KiB) /* page size */
|
#define PGSZ (4*KiB) /* page size */
|
||||||
|
#define BY2PG PGSZ
|
||||||
|
#define WD2PG (BY2PG/BY2WD)
|
||||||
#define PGSHFT 12 /* log(PGSZ) */
|
#define PGSHFT 12 /* log(PGSZ) */
|
||||||
#define PTSZ (4*KiB) /* page table page size */
|
#define PGSHIFT PGSHFT
|
||||||
#define PTSHFT 9 /* */
|
#define PGROUND(s) ROUNDUP(s, PGSZ)
|
||||||
|
#define BLOCKALIGN 8
|
||||||
|
#define FPalign 16
|
||||||
|
|
||||||
#define MACHSZ (4*KiB) /* Mach+stack size */
|
#define MACHSZ (2*PGSZ) /* Mach+stack size */
|
||||||
#define MACHMAX 32 /* max. number of cpus */
|
#define MACHMAX 32 /* max. number of cpus */
|
||||||
#define MACHSTKSZ (6*(4*KiB)) /* Mach stack size */
|
#define MACHSTKSZ (6*(4*KiB)) /* Mach stack size */
|
||||||
|
|
||||||
#define KSTACK (16*1024) /* Size of Proc kernel stack */
|
#define KSTACK (16*KiB) /* Size of Proc kernel stack */
|
||||||
#define STACKALIGN(sp) ((sp) & ~(BY2SE-1)) /* bug: assure with alloc */
|
#define STACKALIGN(sp) ((sp) & ~(BY2SE-1)) /* bug: assure with alloc */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -82,18 +86,46 @@
|
||||||
|
|
||||||
#define UTZERO (0+2*MiB) /* first address in user text */
|
#define UTZERO (0+2*MiB) /* first address in user text */
|
||||||
#define UTROUND(t) ROUNDUP((t), 2*MiB) /* first address beyond text for user data */
|
#define UTROUND(t) ROUNDUP((t), 2*MiB) /* first address beyond text for user data */
|
||||||
#define USTKTOP gULL(0x00007ffffffff000)
|
#define UADDRMASK gULL(0x00007fffffffffff) /* canonical address mask */
|
||||||
#define USTKSIZE (16*1024*1024) /* size of user stack */
|
#define TSTKTOP (0x00007ffffffff000ull)
|
||||||
#define TSTKTOP (USTKTOP-USTKSIZE) /* end of new stack in sysexec */
|
#define USTKSIZE (16*MiB) /* size of user stack */
|
||||||
|
#define USTKTOP (TSTKTOP-USTKSIZE) /* end of new stack in sysexec */
|
||||||
|
|
||||||
#define KSEG0 gULL(0xfffffffff0000000) /* 256MB - this is confused */
|
//#define KSEG0 gULL(0xffffffff80000000) /* 256MB - this is confused */
|
||||||
#define KSEG1 gULL(0xffffff0000000000) /* 512GB - embedded PML4 */
|
//#define KSEG1 gULL(0xffffff0000000000) /* 512GB - embedded PML4 */
|
||||||
#define KSEG2 gULL(0xfffffe0000000000) /* 1TB - KMAP */
|
//#define KSEG2 gULL(0xfffffe8000000000) /* 1TB - KMAP */
|
||||||
#define PMAPADDR gULL(0xffffffffffe00000) /* unused as of yet (KMAP?) */
|
#define PMAPADDR gULL(0xffffffffffe00000) /* unused as of yet (KMAP?) */
|
||||||
|
|
||||||
#define KZERO gULL(0xfffffffff0000000)
|
|
||||||
|
#define KZERO gULL(0xffffffff80000000)
|
||||||
#define KTZERO (KZERO+1*MiB+64*KiB)
|
#define KTZERO (KZERO+1*MiB+64*KiB)
|
||||||
|
|
||||||
|
#define VMAP gULL(0xffffff0000000000)
|
||||||
|
#define VMAPSIZE (512*GiB)
|
||||||
|
|
||||||
|
#define KMAP gULL(0xfffffe8000000000)
|
||||||
|
#define KMAPSIZE (2*MiB)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fundamental addresses - bottom 64kB saved for return to real mode
|
||||||
|
*/
|
||||||
|
#define CONFADDR (KZERO+0x1200) /* info passed from boot loader */
|
||||||
|
#define APBOOTSTRAP (KZERO+0x3000) /* AP bootstrap code */
|
||||||
|
#define IDTADDR (KZERO+0x10000) /* idt */
|
||||||
|
#define REBOOTADDR (0x11000) /* reboot code - physical address */
|
||||||
|
|
||||||
|
#define CPU0PML4 (KZERO+0x13000)
|
||||||
|
#define CPU0PDP (KZERO+0x14000)
|
||||||
|
#define CPU0PD0 (KZERO+0x15000) /* KZERO */
|
||||||
|
#define CPU0PD1 (KZERO+0x16000) /* KZERO+1GB */
|
||||||
|
|
||||||
|
#define CPU0GDT (KZERO+0x17000) /* bootstrap processor GDT */
|
||||||
|
|
||||||
|
#define CPU0MACH (KZERO+0x18000) /* Mach for bootstrap processor */
|
||||||
|
#define CPU0END (CPU0MACH+MACHSIZE)
|
||||||
|
|
||||||
|
#define MACHSIZE (2*KSTACK)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* virtual MMU
|
* virtual MMU
|
||||||
*/
|
*/
|
||||||
|
@ -104,14 +136,17 @@
|
||||||
#define SEGMAXPG (SEGMAPSIZE)
|
#define SEGMAXPG (SEGMAPSIZE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the interface between fixfault and mmuput.
|
* physical MMU
|
||||||
* Should be in port.
|
|
||||||
*/
|
*/
|
||||||
#define PTEVALID (1<<0)
|
#define PTEVALID (gULL(1)<<0)
|
||||||
#define PTEWRITE (1<<1)
|
#define PTEWT (gULL(1)<<3)
|
||||||
#define PTERONLY (0<<1)
|
#define PTEUNCACHED (gULL(1)<<4)
|
||||||
#define PTEUSER (1<<2)
|
#define PTEWRITE (gULL(1)<<1)
|
||||||
#define PTEUNCACHED (1<<4)
|
#define PTERONLY (gULL(0)<<1)
|
||||||
|
#define PTEKERNEL (gULL(0)<<2)
|
||||||
|
#define PTEUSER (gULL(1)<<2)
|
||||||
|
#define PTESIZE (gULL(1)<<7)
|
||||||
|
#define PTEGLOBAL (gULL(1)<<8)
|
||||||
|
|
||||||
#define getpgcolor(a) 0
|
#define getpgcolor(a) 0
|
||||||
|
|
||||||
|
@ -123,6 +158,9 @@
|
||||||
* and level 0 the PT pages. The PTLX macro gives an index into the
|
* and level 0 the PT pages. The PTLX macro gives an index into the
|
||||||
* page-table page at level 'l' for the virtual address 'v'.
|
* page-table page at level 'l' for the virtual address 'v'.
|
||||||
*/
|
*/
|
||||||
|
#define PTSZ (4*KiB) /* page table page size */
|
||||||
|
#define PTSHFT 9 /* */
|
||||||
|
|
||||||
#define PTLX(v, l) (((v)>>(((l)*PTSHFT)+PGSHFT)) & ((1<<PTSHFT)-1))
|
#define PTLX(v, l) (((v)>>(((l)*PTSHFT)+PGSHFT)) & ((1<<PTSHFT)-1))
|
||||||
#define PGLSZ(l) (1<<(((l)*PTSHFT)+PGSHFT))
|
#define PGLSZ(l) (1<<(((l)*PTSHFT)+PGSHFT))
|
||||||
|
|
||||||
|
@ -133,26 +171,21 @@
|
||||||
|
|
||||||
#define CACHELINESZ 64
|
#define CACHELINESZ 64
|
||||||
|
|
||||||
#define KVATOP (KSEG0&KSEG1&KSEG2)
|
//#define KVATOP (KSEG0&KSEG1&KSEG2)
|
||||||
#define iskaddr(a) (((uintptr_t)(a)&KVATOP) == KVATOP)
|
#define iskaddr(a) (((uintptr_t)(a)) > KZERO)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* known x86 segments (in GDT) and their selectors
|
* known x86 segments (in GDT) and their selectors
|
||||||
*/
|
*/
|
||||||
#define NULLSEG 0 /* null segment */
|
#define NULLSEG 0 /* null segment */
|
||||||
#define KDSEG 1 /* kernel data/stack */
|
#define KESEG 1 /* kernel executable */
|
||||||
#define KESEG 2 /* kernel executable */
|
#define KDSEG 2 /* kernel data */
|
||||||
#define UDSEG 3 /* user data/stack */
|
#define UE32SEG 3 /* user executable 32bit */
|
||||||
#define UESEG 4 /* user executable */
|
#define UDSEG 4 /* user data/stack */
|
||||||
#define TSSSEG 5 /* task segment */
|
#define UESEG 5 /* user executable 64bit */
|
||||||
#define APMCSEG 6 /* APM code segment */
|
#define TSSSEG 8 /* task segment (two descriptors) */
|
||||||
#define APMCSEG16 7 /* APM 16-bit code segment */
|
|
||||||
#define APMDSEG 8 /* APM data segment */
|
#define NGDT 10 /* number of GDT entries required */
|
||||||
#define KESEG16 9 /* kernel executable 16-bit */
|
|
||||||
#define LDTSEG 10 /* local descriptor table */
|
|
||||||
#define PROCSEG0 11 /* per process descriptor0 */
|
|
||||||
#define NPROCSEG 3 /* number of per process descriptors */
|
|
||||||
#define NGDT 14 /* number of GDT entries required */
|
|
||||||
|
|
||||||
#define SELGDT (0<<2) /* selector is in gdt */
|
#define SELGDT (0<<2) /* selector is in gdt */
|
||||||
#define SELLDT (1<<2) /* selector is in ldt */
|
#define SELLDT (1<<2) /* selector is in ldt */
|
||||||
|
@ -160,12 +193,33 @@
|
||||||
#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
|
#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
|
||||||
|
|
||||||
#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
|
#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
|
||||||
#define KDSEL SELECTOR(KDSEG, SELGDT, 0)
|
|
||||||
#define KESEL SELECTOR(KESEG, SELGDT, 0)
|
#define KESEL SELECTOR(KESEG, SELGDT, 0)
|
||||||
#define UESEL SELECTOR(UESEG, SELGDT, 3)
|
#define UE32SEL SELECTOR(UE32SEG, SELGDT, 3)
|
||||||
#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
|
#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
|
||||||
|
#define UESEL SELECTOR(UESEG, SELGDT, 3)
|
||||||
#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0)
|
#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0)
|
||||||
#define APMCSEL SELECTOR(APMCSEG, SELGDT, 0)
|
|
||||||
#define APMCSEL16 SELECTOR(APMCSEG16, SELGDT, 0)
|
/*
|
||||||
#define APMDSEL SELECTOR(APMDSEG, SELGDT, 0)
|
* fields in segment descriptors
|
||||||
#define LDTSEL SELECTOR(LDTSEG, SELGDT, 0)
|
*/
|
||||||
|
#define SEGDATA (0x10<<8) /* data/stack segment */
|
||||||
|
#define SEGEXEC (0x18<<8) /* executable segment */
|
||||||
|
#define SEGTSS (0x9<<8) /* TSS segment */
|
||||||
|
#define SEGCG (0x0C<<8) /* call gate */
|
||||||
|
#define SEGIG (0x0E<<8) /* interrupt gate */
|
||||||
|
#define SEGTG (0x0F<<8) /* trap gate */
|
||||||
|
#define SEGLDT (0x02<<8) /* local descriptor table */
|
||||||
|
#define SEGTYPE (0x1F<<8)
|
||||||
|
|
||||||
|
#define SEGP (1<<15) /* segment present */
|
||||||
|
#define SEGPL(x) ((x)<<13) /* priority level */
|
||||||
|
#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */
|
||||||
|
#define SEGD (1<<22) /* default 1==32bit (for code) */
|
||||||
|
#define SEGE (1<<10) /* expand down */
|
||||||
|
#define SEGW (1<<9) /* writable (for data/stack) */
|
||||||
|
#define SEGR (1<<9) /* readable (for code) */
|
||||||
|
#define SEGL (1<<21) /* 64 bit */
|
||||||
|
#define SEGG (1<<23) /* granularity 1==4k (for other) */
|
||||||
|
|
||||||
|
#define getpgcolor(a) 0
|
||||||
|
#define MBPGMASK (~(PGSZ-1))
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,6 @@
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
* modified, propagated, or distributed except according to the terms contained
|
||||||
* in the LICENSE file.
|
* in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "u.h"
|
#include "u.h"
|
||||||
#include "../port/lib.h"
|
#include "../port/lib.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
@ -31,8 +30,6 @@ enum
|
||||||
MousePS2= 2,
|
MousePS2= 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int mouseshifted;
|
|
||||||
|
|
||||||
static QLock mousectlqlock;
|
static QLock mousectlqlock;
|
||||||
static int mousetype;
|
static int mousetype;
|
||||||
static int intellimouse;
|
static int intellimouse;
|
||||||
|
@ -40,6 +37,7 @@ static int packetsize;
|
||||||
static int resolution;
|
static int resolution;
|
||||||
static int accelerated;
|
static int accelerated;
|
||||||
static int mousehwaccel;
|
static int mousehwaccel;
|
||||||
|
static char mouseport[5];
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -93,6 +91,76 @@ static Cmdtab mousectlmsg[] =
|
||||||
* To resynchronize, if we get a byte more than two seconds
|
* To resynchronize, if we get a byte more than two seconds
|
||||||
* after the previous byte, we assume it's the first in a packet.
|
* after the previous byte, we assume it's the first in a packet.
|
||||||
*/
|
*/
|
||||||
|
static void
|
||||||
|
ps2mouseputc(int c, int shift)
|
||||||
|
{
|
||||||
|
static short msg[4];
|
||||||
|
static int nb;
|
||||||
|
static uint8_t b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 };
|
||||||
|
static uint32_t lasttick;
|
||||||
|
uint32_t m;
|
||||||
|
int buttons, dx, dy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resynchronize in stream with timing; see comment above.
|
||||||
|
*/
|
||||||
|
m = MACHP(0)->ticks;
|
||||||
|
if(TK2SEC(m - lasttick) > 2)
|
||||||
|
nb = 0;
|
||||||
|
lasttick = m;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check byte 0 for consistency
|
||||||
|
*/
|
||||||
|
if(nb==0 && (c&0xc8)!=0x08){
|
||||||
|
if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
|
||||||
|
/* last byte of 4-byte packet */
|
||||||
|
packetsize = 4;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg[nb] = c;
|
||||||
|
if(++nb >= packetsize){
|
||||||
|
nb = 0;
|
||||||
|
if(msg[0] & 0x10)
|
||||||
|
msg[1] |= 0xFF00;
|
||||||
|
if(msg[0] & 0x20)
|
||||||
|
msg[2] |= 0xFF00;
|
||||||
|
|
||||||
|
buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
|
||||||
|
if(intellimouse && packetsize==4){
|
||||||
|
if((msg[3]&0xc8) == 0x08){
|
||||||
|
/* first byte of 3-byte packet */
|
||||||
|
packetsize = 3;
|
||||||
|
msg[0] = msg[3];
|
||||||
|
nb = 1;
|
||||||
|
/* fall through to emit previous packet */
|
||||||
|
}else{
|
||||||
|
/* The AccuPoint on the Toshiba 34[48]0CT
|
||||||
|
* encodes extra buttons as 4 and 5. They repeat
|
||||||
|
* and don't release, however, so user-level
|
||||||
|
* timing code is required. Furthermore,
|
||||||
|
* intellimice with 3buttons + scroll give a
|
||||||
|
* two's complement number in the lower 4 bits
|
||||||
|
* (bit 4 is sign extension) that describes
|
||||||
|
* the amount the scroll wheel has moved during
|
||||||
|
* the last sample. Here we use only the sign to
|
||||||
|
* decide whether the wheel is moving up or down
|
||||||
|
* and generate a single button 4 or 5 click
|
||||||
|
* accordingly.
|
||||||
|
*/
|
||||||
|
if((msg[3] >> 3) & 1)
|
||||||
|
buttons |= 1<<3;
|
||||||
|
else if(msg[3] & 0x7)
|
||||||
|
buttons |= 1<<4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dx = msg[1];
|
||||||
|
dy = -msg[2];
|
||||||
|
mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set up a ps2 mouse
|
* set up a ps2 mouse
|
||||||
|
@ -103,14 +171,12 @@ ps2mouse(void)
|
||||||
if(mousetype == MousePS2)
|
if(mousetype == MousePS2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mouseenable();
|
|
||||||
/* make mouse streaming, enabled */
|
|
||||||
mousecmd(0xEA);
|
|
||||||
mousecmd(0xF4);
|
|
||||||
|
|
||||||
mousetype = MousePS2;
|
mousetype = MousePS2;
|
||||||
packetsize = 3;
|
packetsize = 3;
|
||||||
mousehwaccel = 1;
|
mousehwaccel = 0;
|
||||||
|
|
||||||
|
i8042auxenable(ps2mouseputc);
|
||||||
|
i8042auxcmd(0xEA); /* set stream mode */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -131,7 +197,7 @@ setaccelerated(int x)
|
||||||
if(mousehwaccel){
|
if(mousehwaccel){
|
||||||
switch(mousetype){
|
switch(mousetype){
|
||||||
case MousePS2:
|
case MousePS2:
|
||||||
mousecmd(0xE7);
|
i8042auxcmd(0xE7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +211,7 @@ setlinear(void)
|
||||||
if(mousehwaccel){
|
if(mousehwaccel){
|
||||||
switch(mousetype){
|
switch(mousetype){
|
||||||
case MousePS2:
|
case MousePS2:
|
||||||
mousecmd(0xE6);
|
i8042auxcmd(0xE6);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,8 +224,8 @@ setres(int n)
|
||||||
resolution = n;
|
resolution = n;
|
||||||
switch(mousetype){
|
switch(mousetype){
|
||||||
case MousePS2:
|
case MousePS2:
|
||||||
mousecmd(0xE8);
|
i8042auxcmd(0xE8);
|
||||||
mousecmd(n);
|
i8042auxcmd(n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,12 +237,15 @@ setintellimouse(void)
|
||||||
packetsize = 4;
|
packetsize = 4;
|
||||||
switch(mousetype){
|
switch(mousetype){
|
||||||
case MousePS2:
|
case MousePS2:
|
||||||
mousecmd(0xF3); /* set sample */
|
i8042auxcmd(0xF3); /* set sample */
|
||||||
mousecmd(0xC8);
|
i8042auxcmd(0xC8);
|
||||||
mousecmd(0xF3); /* set sample */
|
i8042auxcmd(0xF3); /* set sample */
|
||||||
mousecmd(0x64);
|
i8042auxcmd(0x64);
|
||||||
mousecmd(0xF3); /* set sample */
|
i8042auxcmd(0xF3); /* set sample */
|
||||||
mousecmd(0x50);
|
i8042auxcmd(0x50);
|
||||||
|
break;
|
||||||
|
case Mouseserial:
|
||||||
|
uartsetmouseputc(mouseport, m5mouseputc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,11 +256,30 @@ resetmouse(void)
|
||||||
packetsize = 3;
|
packetsize = 3;
|
||||||
switch(mousetype){
|
switch(mousetype){
|
||||||
case MousePS2:
|
case MousePS2:
|
||||||
mousecmd(0xF6);
|
i8042auxcmd(0xF6);
|
||||||
mousecmd(0xEA); /* streaming */
|
i8042auxcmd(0xEA); /* streaming */
|
||||||
mousecmd(0xE8); /* set resolution */
|
i8042auxcmd(0xE8); /* set resolution */
|
||||||
mousecmd(3);
|
i8042auxcmd(3);
|
||||||
mousecmd(0xF4); /* enabled */
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setstream(int on)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
switch(mousetype){
|
||||||
|
case MousePS2:
|
||||||
|
/*
|
||||||
|
* disabling streaming can fail when
|
||||||
|
* a packet is currently transmitted.
|
||||||
|
*/
|
||||||
|
for(i=0; i<4; i++){
|
||||||
|
if(i8042auxcmd(on ? 0xF4 : 0xF5) != -1)
|
||||||
|
break;
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,27 +298,37 @@ mousectl(Cmdbuf *cb)
|
||||||
ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
|
ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
|
||||||
switch(ct->index){
|
switch(ct->index){
|
||||||
case CMaccelerated:
|
case CMaccelerated:
|
||||||
setaccelerated(cb->nf == 1 ? 1 : jehanne_atoi(cb->f[1]));
|
setstream(0);
|
||||||
|
setaccelerated(cb->nf == 1 ? 1 : atoi(cb->f[1]));
|
||||||
|
setstream(1);
|
||||||
break;
|
break;
|
||||||
case CMintellimouse:
|
case CMintellimouse:
|
||||||
|
setstream(0);
|
||||||
setintellimouse();
|
setintellimouse();
|
||||||
|
setstream(1);
|
||||||
break;
|
break;
|
||||||
case CMlinear:
|
case CMlinear:
|
||||||
|
setstream(0);
|
||||||
setlinear();
|
setlinear();
|
||||||
|
setstream(1);
|
||||||
break;
|
break;
|
||||||
case CMps2:
|
case CMps2:
|
||||||
intellimouse = 0;
|
intellimouse = 0;
|
||||||
ps2mouse();
|
ps2mouse();
|
||||||
|
setstream(1);
|
||||||
break;
|
break;
|
||||||
case CMps2intellimouse:
|
case CMps2intellimouse:
|
||||||
ps2mouse();
|
ps2mouse();
|
||||||
setintellimouse();
|
setintellimouse();
|
||||||
|
setstream(1);
|
||||||
break;
|
break;
|
||||||
case CMres:
|
case CMres:
|
||||||
|
setstream(0);
|
||||||
if(cb->nf >= 2)
|
if(cb->nf >= 2)
|
||||||
setres(jehanne_atoi(cb->f[1]));
|
setres(atoi(cb->f[1]));
|
||||||
else
|
else
|
||||||
setres(1);
|
setres(1);
|
||||||
|
setstream(1);
|
||||||
break;
|
break;
|
||||||
case CMreset:
|
case CMreset:
|
||||||
resetmouse();
|
resetmouse();
|
||||||
|
@ -240,11 +338,31 @@ mousectl(Cmdbuf *cb)
|
||||||
setres(resolution);
|
setres(resolution);
|
||||||
if(intellimouse)
|
if(intellimouse)
|
||||||
setintellimouse();
|
setintellimouse();
|
||||||
|
setstream(1);
|
||||||
|
break;
|
||||||
|
case CMserial:
|
||||||
|
if(mousetype == Mouseserial)
|
||||||
|
error(Emouseset);
|
||||||
|
|
||||||
|
if(cb->nf > 2){
|
||||||
|
if(strcmp(cb->f[2], "M") == 0)
|
||||||
|
uartmouse(cb->f[1], m3mouseputc, 0);
|
||||||
|
else if(strcmp(cb->f[2], "MI") == 0)
|
||||||
|
uartmouse(cb->f[1], m5mouseputc, 0);
|
||||||
|
else
|
||||||
|
uartmouse(cb->f[1], mouseputc, cb->nf == 1);
|
||||||
|
} else
|
||||||
|
uartmouse(cb->f[1], mouseputc, cb->nf == 1);
|
||||||
|
|
||||||
|
mousetype = Mouseserial;
|
||||||
|
strncpy(mouseport, cb->f[1], sizeof(mouseport)-1);
|
||||||
|
mouseport[sizeof(mouseport)-1] = 0;
|
||||||
|
packetsize = 3;
|
||||||
break;
|
break;
|
||||||
case CMhwaccel:
|
case CMhwaccel:
|
||||||
if(jehanne_strcmp(cb->f[1], "on")==0)
|
if(strcmp(cb->f[1], "on")==0)
|
||||||
mousehwaccel = 1;
|
mousehwaccel = 1;
|
||||||
else if(jehanne_strcmp(cb->f[1], "off")==0)
|
else if(strcmp(cb->f[1], "off")==0)
|
||||||
mousehwaccel = 0;
|
mousehwaccel = 0;
|
||||||
else
|
else
|
||||||
cmderror(cb, "bad mouse control message");
|
cmderror(cb, "bad mouse control message");
|
||||||
|
|
|
@ -3,426 +3,588 @@
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "apic.h"
|
#include "ureg.h"
|
||||||
|
|
||||||
#undef DBG
|
#include "mp.h"
|
||||||
#define DBG jehanne_print
|
#include "sipi.h"
|
||||||
/*
|
|
||||||
* MultiProcessor Specification Version 1.[14].
|
|
||||||
*/
|
|
||||||
typedef struct { /* MP Floating Pointer */
|
|
||||||
uint8_t signature[4]; /* "_MP_" */
|
|
||||||
uint8_t addr[4]; /* PCMP */
|
|
||||||
uint8_t length; /* 1 */
|
|
||||||
uint8_t revision; /* [14] */
|
|
||||||
uint8_t checksum;
|
|
||||||
uint8_t feature[5];
|
|
||||||
} _MP_;
|
|
||||||
|
|
||||||
typedef struct { /* MP Configuration Table */
|
/* filled in by pcmpinit or acpiinit */
|
||||||
uint8_t signature[4]; /* "PCMP" */
|
Bus* mpbus;
|
||||||
uint8_t length[2];
|
Bus* mpbuslast;
|
||||||
uint8_t revision; /* [14] */
|
int mpisabus = -1;
|
||||||
uint8_t checksum;
|
int mpeisabus = -1;
|
||||||
uint8_t string[20]; /* OEM + Product ID */
|
Apic *mpioapic[MaxAPICNO+1];
|
||||||
uint8_t oaddr[4]; /* OEM table pointer */
|
Apic *mpapic[MaxAPICNO+1];
|
||||||
uint8_t olength[2]; /* OEM table length */
|
|
||||||
uint8_t entry[2]; /* entry count */
|
|
||||||
uint8_t apicpa[4]; /* local APIC address */
|
|
||||||
uint8_t xlength[2]; /* extended table length */
|
|
||||||
uint8_t xchecksum; /* extended table checksum */
|
|
||||||
uint8_t reserved;
|
|
||||||
|
|
||||||
uint8_t entries[];
|
int
|
||||||
} PCMP;
|
mpintrinit(Bus* bus, PCMPintr* intr, int vno, int irq)
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char type[6];
|
|
||||||
int polarity; /* default for this bus */
|
|
||||||
int trigger; /* default for this bus */
|
|
||||||
} Mpbus;
|
|
||||||
|
|
||||||
static Mpbus mpbusdef[] = {
|
|
||||||
{ "PCI ", IPlow, TMlevel, },
|
|
||||||
{ "ISA ", IPhigh, TMedge, },
|
|
||||||
};
|
|
||||||
static Mpbus* mpbus[Nbus];
|
|
||||||
int mpisabusno = -1;
|
|
||||||
|
|
||||||
static void
|
|
||||||
mpintrprint(char* s, uint8_t* p)
|
|
||||||
{
|
{
|
||||||
char buf[128], *b, *e;
|
int el, po, v;
|
||||||
char format[] = " type %d flags %#ux bus %d IRQ %d APIC %d INTIN %d\n";
|
|
||||||
|
|
||||||
b = buf;
|
|
||||||
e = b + sizeof(buf);
|
|
||||||
b = jehanne_seprint(b, e, "mpparse: intr:");
|
|
||||||
if(s != nil)
|
|
||||||
b = jehanne_seprint(b, e, " %s:", s);
|
|
||||||
jehanne_seprint(b, e, format, p[1], l16get(p+2), p[4], p[5], p[6], p[7]);
|
|
||||||
jehanne_print(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t
|
|
||||||
mpmkintr(uint8_t* p)
|
|
||||||
{
|
|
||||||
uint32_t v;
|
|
||||||
Lapic *apic;
|
|
||||||
IOapic *ioapic;
|
|
||||||
int n, polarity, trigger;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check valid bus, interrupt input pin polarity
|
* Parse an I/O or Local APIC interrupt table entry and
|
||||||
* and trigger mode. If the APIC ID is 0xff it means
|
* return the encoded vector.
|
||||||
* all APICs of this type so those checks for useable
|
|
||||||
* APIC and valid INTIN must also be done later in
|
|
||||||
* the appropriate init routine in that case. It's hard
|
|
||||||
* to imagine routing a signal to all IOAPICs, the
|
|
||||||
* usual case is routing NMI and ExtINT to all LAPICs.
|
|
||||||
*/
|
*/
|
||||||
if(mpbus[p[4]] == nil){
|
v = vno;
|
||||||
mpintrprint("no source bus", p);
|
|
||||||
return 0;
|
po = intr->flags & PcmpPOMASK;
|
||||||
}
|
el = intr->flags & PcmpELMASK;
|
||||||
if(p[6] != 0xff){
|
|
||||||
if(Napic < 256 && p[6] >= Napic){
|
switch(intr->intr){
|
||||||
mpintrprint("APIC ID out of range", p);
|
default: /* PcmpINT */
|
||||||
return 0;
|
v |= ApicFIXED; /* no-op */
|
||||||
}
|
|
||||||
switch(p[0]){
|
|
||||||
default:
|
|
||||||
mpintrprint("INTIN botch", p);
|
|
||||||
return 0;
|
|
||||||
case 3: /* IOINTR */
|
|
||||||
ioapic = ioapiclookup(p[6]);
|
|
||||||
if(ioapic == nil){
|
|
||||||
mpintrprint("unuseable IO APIC", p);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(p[7] >= ioapic->nrdt){
|
|
||||||
mpintrprint("IO INTIN out of range", p);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 4: /* LINTR */
|
|
||||||
apic = lapiclookup(p[6]);
|
case PcmpNMI:
|
||||||
if(apic == nil){
|
v |= ApicNMI;
|
||||||
mpintrprint("unuseable local APIC", p);
|
po = PcmpHIGH;
|
||||||
return 0;
|
el = PcmpEDGE;
|
||||||
}
|
break;
|
||||||
if(p[7] >= nelem(apic->lvt)){
|
|
||||||
mpintrprint("LOCAL INTIN out of range", p);
|
case PcmpSMI:
|
||||||
return 0;
|
v |= ApicSMI;
|
||||||
}
|
break;
|
||||||
|
|
||||||
|
case PcmpExtINT:
|
||||||
|
v |= ApicExtINT;
|
||||||
|
/*
|
||||||
|
* The AMI Goliath doesn't boot successfully with it's LINTR0
|
||||||
|
* entry which decodes to low+level. The PPro manual says ExtINT
|
||||||
|
* should be level, whereas the Pentium is edge. Setting the
|
||||||
|
* Goliath to edge+high seems to cure the problem. Other PPro
|
||||||
|
* MP tables (e.g. ASUS P/I-P65UP5 have a entry which decodes
|
||||||
|
* to edge+high, so who knows.
|
||||||
|
* Perhaps it would be best just to not set an ExtINT entry at
|
||||||
|
* all, it shouldn't be needed for SMP mode.
|
||||||
|
*/
|
||||||
|
po = PcmpHIGH;
|
||||||
|
el = PcmpEDGE;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
n = l16get(p+2);
|
|
||||||
if((polarity = (n & 0x03)) == 2 || (trigger = ((n>>2) & 0x03)) == 2){
|
|
||||||
mpintrprint("invalid polarity/trigger", p);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the low half of the vector table entry (LVT or RDT).
|
|
||||||
* For the NMI, SMI and ExtINT cases, the polarity and trigger
|
|
||||||
* are fixed (but are not always consistent over IA-32 generations).
|
|
||||||
* For the INT case, either the polarity/trigger are given or
|
|
||||||
* it defaults to that of the source bus;
|
|
||||||
* whether INT is Fixed or Lowest Priority is left until later.
|
|
||||||
*/
|
*/
|
||||||
v = Im;
|
if(bus->type == BusEISA && !po && !el /*&& !(i8259elcr & (1<<irq))*/){
|
||||||
switch(p[1]){
|
po = PcmpHIGH;
|
||||||
default:
|
el = PcmpEDGE;
|
||||||
mpintrprint("invalid type", p);
|
|
||||||
return 0;
|
|
||||||
case 0: /* INT */
|
|
||||||
switch(polarity){
|
|
||||||
case 0:
|
|
||||||
v |= mpbus[p[4]]->polarity;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
v |= IPhigh;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
v |= IPlow;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
switch(trigger){
|
if(!po)
|
||||||
case 0:
|
po = bus->po;
|
||||||
v |= mpbus[p[4]]->trigger;
|
if(po == PcmpLOW)
|
||||||
break;
|
v |= ApicLOW;
|
||||||
case 1:
|
else if(po != PcmpHIGH){
|
||||||
v |= TMedge;
|
print("mpintrinit: bad polarity 0x%uX\n", po);
|
||||||
break;
|
return ApicIMASK;
|
||||||
case 3:
|
|
||||||
v |= TMlevel;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 1: /* NMI */
|
if(!el)
|
||||||
v |= TMedge|IPhigh|MTnmi;
|
el = bus->el;
|
||||||
break;
|
if(el == PcmpLEVEL)
|
||||||
case 2: /* SMI */
|
v |= ApicLEVEL;
|
||||||
v |= TMedge|IPhigh|MTsmi;
|
else if(el != PcmpEDGE){
|
||||||
break;
|
print("mpintrinit: bad trigger 0x%uX\n", el);
|
||||||
case 3: /* ExtINT */
|
return ApicIMASK;
|
||||||
v |= TMedge|IPhigh|MTei;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
uint64_t
|
||||||
mpparse(PCMP* pcmp)
|
tscticks(uint64_t *hz)
|
||||||
{
|
{
|
||||||
uint32_t lo;
|
if(hz != nil)
|
||||||
uint8_t *e, *p;
|
*hz = m->cpuhz;
|
||||||
int i, n, bustype;
|
|
||||||
Lapic *apic;
|
|
||||||
|
|
||||||
p = pcmp->entries;
|
cycles(&m->tscticks); /* Uses the rdtsc instruction */
|
||||||
e = ((uint8_t*)pcmp)+l16get(pcmp->length);
|
return m->tscticks;
|
||||||
while(p < e) switch(*p){
|
|
||||||
default:
|
|
||||||
jehanne_print("mpparse: unknown PCMP type %d (e-p %#ld)\n", *p, e-p);
|
|
||||||
for(i = 0; p < e; i++){
|
|
||||||
if(i && ((i & 0x0f) == 0))
|
|
||||||
jehanne_print("\n");
|
|
||||||
jehanne_print(" %#2.2ux", *p);
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
jehanne_print("\n");
|
|
||||||
break;
|
|
||||||
case 0: /* processor */
|
|
||||||
/*
|
|
||||||
* Initialise the APIC if it is enabled (p[3] & 0x01).
|
|
||||||
* p[1] is the APIC ID, the memory mapped address comes
|
|
||||||
* from the PCMP structure as the addess is local to the
|
|
||||||
* CPU and identical for all. Indicate whether this is
|
|
||||||
* the bootstrap processor (p[3] & 0x02).
|
|
||||||
*/
|
|
||||||
DBG("mpparse: APIC %d pa %#ux useable %d\n",
|
|
||||||
p[1], l32get(pcmp->apicpa), p[3] & 0x01);
|
|
||||||
if(p[3] & 0x01)
|
|
||||||
lapicinit(p[1], l32get(pcmp->apicpa), p[3] & 0x02);
|
|
||||||
p += 20;
|
|
||||||
break;
|
|
||||||
case 1: /* bus */
|
|
||||||
DBG("mpparse: bus: %d type %6.6s\n", p[1], (char*)p+2);
|
|
||||||
if(mpbus[p[1]] != nil){
|
|
||||||
jehanne_print("mpparse: bus %d already allocated\n", p[1]);
|
|
||||||
p += 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for(i = 0; i < nelem(mpbusdef); i++){
|
|
||||||
if(jehanne_memcmp(p+2, mpbusdef[i].type, 6) != 0)
|
|
||||||
continue;
|
|
||||||
if(jehanne_memcmp(p+2, "ISA ", 6) == 0){
|
|
||||||
if(mpisabusno != -1){
|
|
||||||
jehanne_print("mpparse: bus %d already have ISA bus %d\n",
|
|
||||||
p[1], mpisabusno);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mpisabusno = p[1];
|
|
||||||
}
|
|
||||||
mpbus[p[1]] = &mpbusdef[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(mpbus[p[1]] == nil)
|
|
||||||
jehanne_print("mpparse: bus %d type %6.6s unknown\n",
|
|
||||||
p[1], (char*)p+2);
|
|
||||||
|
|
||||||
p += 8;
|
|
||||||
break;
|
|
||||||
case 2: /* IOAPIC */
|
|
||||||
/*
|
|
||||||
* Initialise the IOAPIC if it is enabled (p[3] & 0x01).
|
|
||||||
* p[1] is the APIC ID, p[4-7] is the memory mapped address.
|
|
||||||
*/
|
|
||||||
DBG("mpparse: IOAPIC %d pa %#ux useable %d\n",
|
|
||||||
p[1], l32get(p+4), p[3] & 0x01);
|
|
||||||
if(p[3] & 0x01)
|
|
||||||
ioapicinit(p[1], -1, l32get(p+4));
|
|
||||||
|
|
||||||
p += 8;
|
|
||||||
break;
|
|
||||||
case 3: /* IOINTR */
|
|
||||||
/*
|
|
||||||
* p[1] is the interrupt type;
|
|
||||||
* p[2-3] contains the polarity and trigger mode;
|
|
||||||
* p[4] is the source bus;
|
|
||||||
* p[5] is the IRQ on the source bus;
|
|
||||||
* p[6] is the destination APIC;
|
|
||||||
* p[7] is the INITIN pin on the destination APIC.
|
|
||||||
*/
|
|
||||||
if(p[6] == 0xff){
|
|
||||||
mpintrprint("routed to all IOAPICs", p);
|
|
||||||
p += 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if((lo = mpmkintr(p)) == 0){
|
|
||||||
p += 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(DBGFLG)
|
|
||||||
mpintrprint(nil, p);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Always present the device number in the style
|
|
||||||
* of a PCI Interrupt Assignment Entry. For the ISA
|
|
||||||
* bus the IRQ is the device number but unencoded.
|
|
||||||
* May need to handle other buses here in the future
|
|
||||||
* (but unlikely).
|
|
||||||
*/
|
|
||||||
bustype = -1;
|
|
||||||
if(jehanne_memcmp(mpbus[p[4]]->type, "PCI ", 6) == 0)
|
|
||||||
bustype = BusPCI; /* had devno = p[5]<<2 */
|
|
||||||
else if(jehanne_memcmp(mpbus[p[4]]->type, "ISA ", 6) == 0)
|
|
||||||
bustype = BusISA;
|
|
||||||
if(bustype != -1)
|
|
||||||
ioapicintrinit(bustype, p[4], p[6], p[7], p[5], lo);
|
|
||||||
|
|
||||||
p += 8;
|
|
||||||
break;
|
|
||||||
case 4: /* LINTR */
|
|
||||||
/*
|
|
||||||
* Format is the same as IOINTR above.
|
|
||||||
*/
|
|
||||||
if((lo = mpmkintr(p)) == 0){
|
|
||||||
p += 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(DBGFLG)
|
|
||||||
mpintrprint(nil, p);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Everything was checked in mpmkintr above.
|
|
||||||
*/
|
|
||||||
if(p[6] == 0xff){
|
|
||||||
for(i = 0; i < Napic; i++){
|
|
||||||
apic = lapiclookup(i);
|
|
||||||
if(apic != nil)
|
|
||||||
apic->lvt[p[7]] = lo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
apic = lapiclookup(p[6]);
|
|
||||||
if(apic != nil)
|
|
||||||
apic->lvt[p[7]] = lo;
|
|
||||||
}
|
|
||||||
p += 8;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void
|
||||||
* There's nothing of real interest in the extended table,
|
syncclock(void)
|
||||||
* should just move along, but check it for consistency.
|
{
|
||||||
*/
|
uint64_t x;
|
||||||
p = e;
|
|
||||||
e = p + l16get(pcmp->xlength);
|
if(arch->fastclock != tscticks)
|
||||||
while(p < e) switch(*p){
|
return;
|
||||||
default:
|
|
||||||
n = p[1];
|
if(m->machno == 0){
|
||||||
jehanne_print("mpparse: unknown extended entry %d length %d\n", *p, n);
|
wrmsr(0x10, 0);
|
||||||
for(i = 0; i < n; i++){
|
m->tscticks = 0;
|
||||||
if(i && ((i & 0x0f) == 0))
|
} else {
|
||||||
jehanne_print("\n");
|
x = MACHP(0)->tscticks;
|
||||||
jehanne_print(" %#2.2ux", *p);
|
while(x == MACHP(0)->tscticks)
|
||||||
p++;
|
;
|
||||||
}
|
wrmsr(0x10, MACHP(0)->tscticks);
|
||||||
jehanne_print("\n");
|
cycles(&m->tscticks);
|
||||||
break;
|
|
||||||
case 128:
|
|
||||||
DBG("address space mapping\n");
|
|
||||||
DBG(" bus %d type %d base %#llux length %#llux\n",
|
|
||||||
p[2], p[3], l64get(p+4), l64get(p+12));
|
|
||||||
p += p[1];
|
|
||||||
break;
|
|
||||||
case 129:
|
|
||||||
DBG("bus hierarchy descriptor\n");
|
|
||||||
DBG(" bus %d sd %d parent bus %d\n",
|
|
||||||
p[2], p[3], p[4]);
|
|
||||||
p += p[1];
|
|
||||||
break;
|
|
||||||
case 130:
|
|
||||||
DBG("compatibility bus address space modifier\n");
|
|
||||||
DBG(" bus %d pr %d range list %d\n",
|
|
||||||
p[2], p[3], l32get(p+4));
|
|
||||||
p += p[1];
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mpsinit(void)
|
mpinit(void)
|
||||||
{
|
{
|
||||||
uint8_t *p;
|
int ncpu, i;
|
||||||
int i, n;
|
Apic *apic;
|
||||||
_MP_ *mp;
|
char *cp;
|
||||||
PCMP *pcmp;
|
|
||||||
|
|
||||||
if((mp = sigsearch("_MP_")) == nil)
|
i8259init();
|
||||||
return;
|
syncclock();
|
||||||
if(DBGFLG){
|
|
||||||
DBG("_MP_ @ %#p, addr %#ux length %ud rev %d",
|
|
||||||
mp, l32get(mp->addr), mp->length, mp->revision);
|
|
||||||
for(i = 0; i < sizeof(mp->feature); i++)
|
|
||||||
DBG(" %2.2#ux", mp->feature[i]);
|
|
||||||
DBG("\n");
|
|
||||||
}
|
|
||||||
if(mp->revision != 1 && mp->revision != 4)
|
|
||||||
return;
|
|
||||||
if(checksum(mp, mp->length*16) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if((pcmp = vmap(l32get(mp->addr), sizeof(PCMP))) == nil)
|
if(getconf("*apicdebug")){
|
||||||
return;
|
Bus *b;
|
||||||
if(pcmp->revision != 1 && pcmp->revision != 4){
|
Aintr *ai;
|
||||||
vunmap(pcmp, sizeof(PCMP));
|
PCMPintr *pi;
|
||||||
return;
|
|
||||||
}
|
|
||||||
n = l16get(pcmp->length) + l16get(pcmp->xlength);
|
|
||||||
vunmap(pcmp, sizeof(PCMP));
|
|
||||||
if((pcmp = vmap(l32get(mp->addr), n)) == nil)
|
|
||||||
return;
|
|
||||||
if(checksum(pcmp, l16get(pcmp->length)) != 0){
|
|
||||||
vunmap(pcmp, n);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(DBGFLG){
|
|
||||||
DBG("PCMP @ %#p length %#ux revision %d\n",
|
|
||||||
pcmp, l16get(pcmp->length), pcmp->revision);
|
|
||||||
DBG(" %20.20s oaddr %#ux olength %#ux\n",
|
|
||||||
(char*)pcmp->string, l32get(pcmp->oaddr),
|
|
||||||
l16get(pcmp->olength));
|
|
||||||
DBG(" entry %d apicpa %#ux\n",
|
|
||||||
l16get(pcmp->entry), l32get(pcmp->apicpa));
|
|
||||||
|
|
||||||
DBG(" xlength %#ux xchecksum %#ux\n",
|
for(i=0; i<=MaxAPICNO; i++){
|
||||||
l16get(pcmp->xlength), pcmp->xchecksum);
|
if(apic = mpapic[i])
|
||||||
|
print("LAPIC%d: pa=%lux va=%#p flags=%x\n",
|
||||||
|
i, apic->paddr, apic->addr, apic->flags);
|
||||||
|
if(apic = mpioapic[i])
|
||||||
|
print("IOAPIC%d: pa=%lux va=%#p flags=%x gsibase=%d mre=%d\n",
|
||||||
|
i, apic->paddr, apic->addr, apic->flags, apic->gsibase, apic->mre);
|
||||||
}
|
}
|
||||||
if(pcmp->xchecksum != 0){
|
for(b = mpbus; b; b = b->next){
|
||||||
p = ((uint8_t*)pcmp) + l16get(pcmp->length);
|
print("BUS%d type=%d flags=%x\n", b->busno, b->type, b->po|b->el);
|
||||||
i = checksum(p, l16get(pcmp->xlength));
|
for(ai = b->aintr; ai; ai = ai->next){
|
||||||
if(((i+pcmp->xchecksum) & 0xff) != 0){
|
if(pi = ai->intr)
|
||||||
jehanne_print("extended table checksums to %#ux\n", i);
|
print("\ttype=%d irq=%d (%d [%c]) apic=%d intin=%d flags=%x\n",
|
||||||
vunmap(pcmp, n);
|
pi->type, pi->irq, pi->irq>>2, "ABCD"[pi->irq&3],
|
||||||
|
pi->apicno, pi->intin, pi->flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apic = nil;
|
||||||
|
for(i=0; i<=MaxAPICNO; i++){
|
||||||
|
if(mpapic[i] == nil)
|
||||||
|
continue;
|
||||||
|
if(mpapic[i]->flags & PcmpBP){
|
||||||
|
apic = mpapic[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(apic == nil){
|
||||||
|
panic("mpinit: no bootstrap processor");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
apic->online = 1;
|
||||||
|
|
||||||
|
lapicinit(apic);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These interrupts are local to the processor
|
||||||
|
* and do not appear in the I/O APIC so it is OK
|
||||||
|
* to set them now.
|
||||||
|
*/
|
||||||
|
intrenable(IrqTIMER, lapicclock, 0, BUSUNKNOWN, "clock");
|
||||||
|
intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
|
||||||
|
intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
|
||||||
|
lapiconline();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialise the application processors.
|
||||||
|
*/
|
||||||
|
if(cp = getconf("*ncpu")){
|
||||||
|
ncpu = strtol(cp, 0, 0);
|
||||||
|
if(ncpu < 1)
|
||||||
|
ncpu = 1;
|
||||||
|
else if(ncpu > MACHMAX)
|
||||||
|
ncpu = MACHMAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ncpu = MACHMAX;
|
||||||
|
memmove((void*)APBOOTSTRAP, sipihandler, sizeof(sipihandler));
|
||||||
|
for(i=0; i<nelem(mpapic); i++){
|
||||||
|
if((apic = mpapic[i]) == nil)
|
||||||
|
continue;
|
||||||
|
if(apic->machno >= MACHMAX)
|
||||||
|
continue;
|
||||||
|
if(ncpu <= 1)
|
||||||
|
break;
|
||||||
|
if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN){
|
||||||
|
mpstartap(apic);
|
||||||
|
sys->nmach++;
|
||||||
|
ncpu--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse the PCMP table and set up the datastructures
|
* we don't really know the number of processors till
|
||||||
* for later interrupt enabling and application processor
|
* here.
|
||||||
* startup.
|
*
|
||||||
|
* set sys->copymode here if nmach > 1.
|
||||||
|
* Should look for an ExtINT line and enable it.
|
||||||
*/
|
*/
|
||||||
mpparse(pcmp);
|
if(X86FAMILY(m->cpuidax) == 3 || sys->nmach > 1)
|
||||||
|
sys->copymode = 1;
|
||||||
lapicdump();
|
}
|
||||||
iordtdump();
|
|
||||||
|
static int
|
||||||
|
mpintrcpu(void)
|
||||||
|
{
|
||||||
|
static Lock physidlock;
|
||||||
|
static int physid;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The bulk of this code was written ~1995, when there was
|
||||||
|
* one architecture and one generation of hardware, the number
|
||||||
|
* of CPUs was up to 4(8) and the choices for interrupt routing
|
||||||
|
* were physical, or flat logical (optionally with lowest
|
||||||
|
* priority interrupt). Logical mode hasn't scaled well with
|
||||||
|
* the increasing number of packages/cores/threads, so the
|
||||||
|
* fall-back is to physical mode, which works across all processor
|
||||||
|
* generations, both AMD and Intel, using the APIC and xAPIC.
|
||||||
|
*
|
||||||
|
* Interrupt routing policy can be set here.
|
||||||
|
* Currently, just assign each interrupt to a different CPU on
|
||||||
|
* a round-robin basis. Some idea of the packages/cores/thread
|
||||||
|
* topology would be useful here, e.g. to not assign interrupts
|
||||||
|
* to more than one thread in a core, or to use a "noise" core.
|
||||||
|
* But, as usual, Intel make that an onerous task.
|
||||||
|
*/
|
||||||
|
lock(&physidlock);
|
||||||
|
for(;;){
|
||||||
|
i = physid++;
|
||||||
|
if(physid >= nelem(mpapic))
|
||||||
|
physid = 0;
|
||||||
|
if(mpapic[i] == nil)
|
||||||
|
continue;
|
||||||
|
if(mpapic[i]->online)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unlock(&physidlock);
|
||||||
|
|
||||||
|
return mpapic[i]->apicno;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With the APIC a unique vector can be assigned to each
|
||||||
|
* request to enable an interrupt. There are two reasons this
|
||||||
|
* is a good idea:
|
||||||
|
* 1) to prevent lost interrupts, no more than 2 interrupts
|
||||||
|
* should be assigned per block of 16 vectors (there is an
|
||||||
|
* in-service entry and a holding entry for each priority
|
||||||
|
* level and there is one priority level per block of 16
|
||||||
|
* interrupts).
|
||||||
|
* 2) each input pin on the IOAPIC will receive a different
|
||||||
|
* vector regardless of whether the devices on that pin use
|
||||||
|
* the same IRQ as devices on another pin.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
allocvector(void)
|
||||||
|
{
|
||||||
|
static int round = 0, num = 0;
|
||||||
|
static Lock l;
|
||||||
|
int vno;
|
||||||
|
|
||||||
|
lock(&l);
|
||||||
|
vno = VectorAPIC + num;
|
||||||
|
if(vno < MaxVectorAPIC-7)
|
||||||
|
num += 8;
|
||||||
|
else
|
||||||
|
num = ++round % 8;
|
||||||
|
unlock(&l);
|
||||||
|
return vno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mpintrenablex(Vctl* v, int tbdf)
|
||||||
|
{
|
||||||
|
Bus *bus;
|
||||||
|
Aintr *aintr;
|
||||||
|
Apic *apic;
|
||||||
|
Pcidev *pcidev;
|
||||||
|
int bno, dno, pin, hi, irq, lo, n, type, vno;
|
||||||
|
|
||||||
|
type = BUSTYPE(tbdf);
|
||||||
|
bno = BUSBNO(tbdf);
|
||||||
|
dno = BUSDNO(tbdf);
|
||||||
|
|
||||||
|
pin = 0;
|
||||||
|
pcidev = nil;
|
||||||
|
if(type == BusPCI){
|
||||||
|
if(pcidev = pcimatchtbdf(tbdf))
|
||||||
|
pin = pcicfgr8(pcidev, PciINTP);
|
||||||
|
} else if(type == BusISA)
|
||||||
|
bno = mpisabus;
|
||||||
|
|
||||||
|
Findbus:
|
||||||
|
for(bus = mpbus; bus != nil; bus = bus->next){
|
||||||
|
if(bus->type != type)
|
||||||
|
continue;
|
||||||
|
if(bus->busno == bno)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bus == nil){
|
||||||
|
/*
|
||||||
|
* if the PCI device is behind a PCI-PCI bridge thats not described
|
||||||
|
* by the MP or ACPI tables then walk up the bus translating interrupt
|
||||||
|
* pin to parent bus.
|
||||||
|
*/
|
||||||
|
if(pcidev && pcidev->parent && pin > 0){
|
||||||
|
pin = ((dno+(pin-1))%4)+1;
|
||||||
|
pcidev = pcidev->parent;
|
||||||
|
bno = BUSBNO(pcidev->tbdf);
|
||||||
|
dno = BUSDNO(pcidev->tbdf);
|
||||||
|
goto Findbus;
|
||||||
|
}
|
||||||
|
print("mpintrenable: can't find bus type %d, number %d\n", type, bno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For PCI devices the interrupt pin (INT[ABCD]) and device
|
||||||
|
* number are encoded into the entry irq field, so create something
|
||||||
|
* to match on.
|
||||||
|
*/
|
||||||
|
if(bus->type == BusPCI){
|
||||||
|
if(pin > 0)
|
||||||
|
irq = (dno<<2)|(pin-1);
|
||||||
|
else
|
||||||
|
irq = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
irq = v->irq;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find a matching interrupt entry from the list of interrupts
|
||||||
|
* attached to this bus.
|
||||||
|
*/
|
||||||
|
for(aintr = bus->aintr; aintr; aintr = aintr->next){
|
||||||
|
if(aintr->intr->irq != irq)
|
||||||
|
continue;
|
||||||
|
if(0){
|
||||||
|
PCMPintr* p = aintr->intr;
|
||||||
|
print("mpintrenablex: bus %d intin %d irq %d\n",
|
||||||
|
p->busno, p->intin, p->irq);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check if already enabled. Multifunction devices may share
|
||||||
|
* INT[A-D]# so, if already enabled, check the polarity matches
|
||||||
|
* and the trigger is level.
|
||||||
|
*
|
||||||
|
* Should check the devices differ only in the function number,
|
||||||
|
* but that can wait for the planned enable/disable rewrite.
|
||||||
|
* The RDT read here is safe for now as currently interrupts
|
||||||
|
* are never disabled once enabled.
|
||||||
|
*/
|
||||||
|
apic = aintr->apic;
|
||||||
|
ioapicrdtr(apic, aintr->intr->intin, 0, &lo);
|
||||||
|
if(!(lo & ApicIMASK)){
|
||||||
|
vno = lo & 0xFF;
|
||||||
|
if(0) print("%s vector %d (!imask)\n", v->name, vno);
|
||||||
|
n = mpintrinit(bus, aintr->intr, vno, v->irq);
|
||||||
|
n |= ApicPHYSICAL; /* no-op */
|
||||||
|
lo &= ~(ApicRemoteIRR|ApicDELIVS);
|
||||||
|
if(n != lo){
|
||||||
|
print("mpintrenable: multiple botch irq %d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
|
||||||
|
v->irq, tbdf, lo, n);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
v->isr = lapicisr;
|
||||||
|
v->eoi = lapiceoi;
|
||||||
|
return vno;
|
||||||
|
}
|
||||||
|
|
||||||
|
vno = allocvector();
|
||||||
|
hi = mpintrcpu()<<24;
|
||||||
|
lo = mpintrinit(bus, aintr->intr, vno, v->irq);
|
||||||
|
lo |= ApicPHYSICAL; /* no-op */
|
||||||
|
if(lo & ApicIMASK){
|
||||||
|
print("mpintrenable: disabled irq %d, tbdf %uX, lo %8.8uX, hi %8.8uX\n",
|
||||||
|
v->irq, tbdf, lo, hi);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC)
|
||||||
|
ioapicrdtw(apic, aintr->intr->intin, hi, lo);
|
||||||
|
|
||||||
|
v->isr = lapicisr;
|
||||||
|
v->eoi = lapiceoi;
|
||||||
|
return vno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSICtrl = 0x02, /* message control register (16 bit) */
|
||||||
|
MSIAddr = 0x04, /* message address register (64 bit) */
|
||||||
|
MSIData32 = 0x08, /* message data register for 32 bit MSI (16 bit) */
|
||||||
|
MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HTMSIMapping = 0xA8,
|
||||||
|
HTMSIFlags = 0x02,
|
||||||
|
HTMSIFlagsEn = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
htmsicapenable(Pcidev *p)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
#if 0
|
||||||
|
int cap, flags;
|
||||||
|
|
||||||
|
if((cap = pcihtcap(p, HTMSIMapping)) <= 0)
|
||||||
|
return -1;
|
||||||
|
flags = pcicfgr8(p, cap + HTMSIFlags);
|
||||||
|
if((flags & HTMSIFlagsEn) == 0)
|
||||||
|
pcicfgw8(p, cap + HTMSIFlags, flags | HTMSIFlagsEn);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
htmsienable(Pcidev *pdev)
|
||||||
|
{
|
||||||
|
Pcidev *p;
|
||||||
|
|
||||||
|
p = nil;
|
||||||
|
while((p = pcimatch(p, 0x1022, 0)) != nil)
|
||||||
|
if(p->did == 0x1103 || p->did == 0x1203)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(p == nil)
|
||||||
|
return 0; /* not hypertransport platform */
|
||||||
|
|
||||||
|
p = nil;
|
||||||
|
while((p = pcimatch(p, 0x10de, 0)) != nil){
|
||||||
|
switch(p->did){
|
||||||
|
case 0x02f0: /* NVIDIA NFORCE C51 MEMC0 */
|
||||||
|
case 0x02f1: /* NVIDIA NFORCE C51 MEMC1 */
|
||||||
|
case 0x02f2: /* NVIDIA NFORCE C51 MEMC2 */
|
||||||
|
case 0x02f3: /* NVIDIA NFORCE C51 MEMC3 */
|
||||||
|
case 0x02f4: /* NVIDIA NFORCE C51 MEMC4 */
|
||||||
|
case 0x02f5: /* NVIDIA NFORCE C51 MEMC5 */
|
||||||
|
case 0x02f6: /* NVIDIA NFORCE C51 MEMC6 */
|
||||||
|
case 0x02f7: /* NVIDIA NFORCE C51 MEMC7 */
|
||||||
|
case 0x0369: /* NVIDIA NFORCE MCP55 MEMC */
|
||||||
|
htmsicapenable(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(htmsicapenable(pdev) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for(p = pdev->parent; p != nil; p = p->parent)
|
||||||
|
if(htmsicapenable(p) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
msiintrenable(Vctl *v)
|
||||||
|
{
|
||||||
|
int tbdf, vno, cap, cpu, ok64;
|
||||||
|
Pcidev *pci;
|
||||||
|
|
||||||
|
if(getconf("*nomsi") != nil)
|
||||||
|
return -1;
|
||||||
|
tbdf = v->tbdf;
|
||||||
|
if(tbdf == BUSUNKNOWN || BUSTYPE(tbdf) != BusPCI)
|
||||||
|
return -1;
|
||||||
|
pci = pcimatchtbdf(tbdf);
|
||||||
|
if(pci == nil) {
|
||||||
|
print("msiintrenable: could not find Pcidev for tbdf %uX\n", tbdf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(htmsienable(pci) < 0)
|
||||||
|
return -1;
|
||||||
|
cap = pcicap(pci, PciCapMSI);
|
||||||
|
if(cap < 0)
|
||||||
|
return -1;
|
||||||
|
vno = allocvector();
|
||||||
|
cpu = mpintrcpu();
|
||||||
|
ok64 = (pcicfgr16(pci, cap + MSICtrl) & (1<<7)) != 0;
|
||||||
|
pcicfgw32(pci, cap + MSIAddr, (0xFEE << 20) | (cpu << 12));
|
||||||
|
if(ok64) pcicfgw32(pci, cap + MSIAddr + 4, 0);
|
||||||
|
pcicfgw16(pci, cap + (ok64 ? MSIData64 : MSIData32), vno | (1<<14));
|
||||||
|
pcicfgw16(pci, cap + MSICtrl, 1);
|
||||||
|
v->isr = lapicisr;
|
||||||
|
v->eoi = lapiceoi;
|
||||||
|
return vno;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mpintrenable(Vctl* v)
|
||||||
|
{
|
||||||
|
int irq, tbdf, vno;
|
||||||
|
|
||||||
|
vno = msiintrenable(v);
|
||||||
|
if(vno != -1)
|
||||||
|
return vno;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the bus is known, try it.
|
||||||
|
* BUSUNKNOWN is given both by [E]ISA devices and by
|
||||||
|
* interrupts local to the processor (local APIC, coprocessor
|
||||||
|
* breakpoint and page-fault).
|
||||||
|
*/
|
||||||
|
tbdf = v->tbdf;
|
||||||
|
if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)
|
||||||
|
return vno;
|
||||||
|
|
||||||
|
irq = v->irq;
|
||||||
|
if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){
|
||||||
|
if(irq != IrqSPURIOUS)
|
||||||
|
v->isr = lapiceoi;
|
||||||
|
return VectorPIC+irq;
|
||||||
|
}
|
||||||
|
if(irq < 0 || irq > MaxIrqPIC){
|
||||||
|
print("mpintrenable: irq %d out of range\n", irq);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Either didn't find it or have to try the default buses
|
||||||
|
* (ISA and EISA). This hack is due to either over-zealousness
|
||||||
|
* or laziness on the part of some manufacturers.
|
||||||
|
*
|
||||||
|
* The MP configuration table on some older systems
|
||||||
|
* (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus
|
||||||
|
* but none for ISA. It also has the interrupt type and
|
||||||
|
* polarity set to 'default for this bus' which wouldn't
|
||||||
|
* be compatible with ISA.
|
||||||
|
*/
|
||||||
|
if(mpeisabus != -1){
|
||||||
|
vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));
|
||||||
|
if(vno != -1)
|
||||||
|
return vno;
|
||||||
|
}
|
||||||
|
if(mpisabus != -1){
|
||||||
|
vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));
|
||||||
|
if(vno != -1)
|
||||||
|
return vno;
|
||||||
|
}
|
||||||
|
print("mpintrenable: out of choices eisa %d isa %d tbdf %uX irq %d\n",
|
||||||
|
mpeisabus, mpisabus, v->tbdf, v->irq);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mpshutdown(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Park application processors.
|
||||||
|
*/
|
||||||
|
if(m->machno != 0){
|
||||||
|
splhi();
|
||||||
|
arch->introff();
|
||||||
|
for(;;) idle();
|
||||||
|
}
|
||||||
|
delay(1000);
|
||||||
|
splhi();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INIT all excluding self.
|
||||||
|
*/
|
||||||
|
lapicicrw(0, 0x000C0000|ApicINIT);
|
||||||
|
|
||||||
|
pcireset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
/*
|
||||||
|
* MultiProcessor Specification Version 1.[14].
|
||||||
|
*/
|
||||||
|
typedef struct { /* floating pointer */
|
||||||
|
uint8_t signature[4]; /* "_MP_" */
|
||||||
|
int32_t physaddr; /* physical address of MP configuration table */
|
||||||
|
uint8_t length; /* 1 */
|
||||||
|
uint8_t specrev; /* [14] */
|
||||||
|
uint8_t checksum; /* all bytes must add up to 0 */
|
||||||
|
uint8_t type; /* MP system configuration type */
|
||||||
|
uint8_t imcrp;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} _MP_;
|
||||||
|
|
||||||
|
#define _MP_sz (4+4+1+1+1+1+1+3)
|
||||||
|
|
||||||
|
typedef struct { /* configuration table header */
|
||||||
|
uint8_t signature[4]; /* "PCMP" */
|
||||||
|
uint16_t length; /* total table length */
|
||||||
|
uint8_t version; /* [14] */
|
||||||
|
uint8_t checksum; /* all bytes must add up to 0 */
|
||||||
|
uint8_t product[20]; /* product id */
|
||||||
|
uint32_t oemtable; /* OEM table pointer */
|
||||||
|
uint16_t oemlength; /* OEM table length */
|
||||||
|
uint16_t entry; /* entry count */
|
||||||
|
uint32_t lapicbase; /* address of local APIC */
|
||||||
|
uint16_t xlength; /* extended table length */
|
||||||
|
uint8_t xchecksum; /* extended table checksum */
|
||||||
|
uint8_t reserved;
|
||||||
|
} PCMP;
|
||||||
|
|
||||||
|
#define PCMPsz (4+2+1+1+20+4+2+2+4+2+1+1)
|
||||||
|
|
||||||
|
typedef struct { /* processor table entry */
|
||||||
|
uint8_t type; /* entry type (0) */
|
||||||
|
uint8_t apicno; /* local APIC id */
|
||||||
|
uint8_t version; /* local APIC verison */
|
||||||
|
uint8_t flags; /* CPU flags */
|
||||||
|
uint8_t signature[4]; /* CPU signature */
|
||||||
|
uint32_t feature; /* feature flags from CPUID instruction */
|
||||||
|
uint8_t reserved[8];
|
||||||
|
} PCMPprocessor;
|
||||||
|
|
||||||
|
#define PCMPprocessorsz (1+1+1+1+4+4+8)
|
||||||
|
|
||||||
|
typedef struct { /* bus table entry */
|
||||||
|
uint8_t type; /* entry type (1) */
|
||||||
|
uint8_t busno; /* bus id */
|
||||||
|
char string[6]; /* bus type string */
|
||||||
|
} PCMPbus;
|
||||||
|
|
||||||
|
#define PCMPbussz (1+1+6)
|
||||||
|
|
||||||
|
typedef struct { /* I/O APIC table entry */
|
||||||
|
uint8_t type; /* entry type (2) */
|
||||||
|
uint8_t apicno; /* I/O APIC id */
|
||||||
|
uint8_t version; /* I/O APIC version */
|
||||||
|
uint8_t flags; /* I/O APIC flags */
|
||||||
|
uint32_t addr; /* I/O APIC address */
|
||||||
|
} PCMPioapic;
|
||||||
|
|
||||||
|
#define PCMPioapicsz (1+1+1+1+4)
|
||||||
|
|
||||||
|
typedef struct { /* interrupt table entry */
|
||||||
|
uint8_t type; /* entry type ([34]) */
|
||||||
|
uint8_t intr; /* interrupt type */
|
||||||
|
uint16_t flags; /* interrupt flag */
|
||||||
|
uint8_t busno; /* source bus id */
|
||||||
|
uint8_t irq; /* source bus irq */
|
||||||
|
uint8_t apicno; /* destination APIC id */
|
||||||
|
uint8_t intin; /* destination APIC [L]INTIN# */
|
||||||
|
} PCMPintr;
|
||||||
|
|
||||||
|
#define PCMPintrsz (1+1+2+1+1+1+1)
|
||||||
|
|
||||||
|
typedef struct { /* system address space mapping entry */
|
||||||
|
uint8_t type; /* entry type (128) */
|
||||||
|
uint8_t length; /* of this entry (20) */
|
||||||
|
uint8_t busno; /* bus id */
|
||||||
|
uint8_t addrtype;
|
||||||
|
uint32_t addrbase[2];
|
||||||
|
uint32_t addrlength[2];
|
||||||
|
} PCMPsasm;
|
||||||
|
|
||||||
|
#define PCMPsasmsz (1+1+1+1+8+8)
|
||||||
|
|
||||||
|
typedef struct { /* bus hierarchy descriptor entry */
|
||||||
|
uint8_t type; /* entry type (129) */
|
||||||
|
uint8_t length; /* of this entry (8) */
|
||||||
|
uint8_t busno; /* bus id */
|
||||||
|
uint8_t info; /* bus info */
|
||||||
|
uint8_t parent; /* parent bus */
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} PCMPhierarchy;
|
||||||
|
|
||||||
|
#define PCMPhirarchysz (1+1+1+1+1+3)
|
||||||
|
|
||||||
|
typedef struct { /* compatibility bus address space modifier entry */
|
||||||
|
uint8_t type; /* entry type (130) */
|
||||||
|
uint8_t length; /* of this entry (8) */
|
||||||
|
uint8_t busno; /* bus id */
|
||||||
|
uint8_t modifier; /* address modifier */
|
||||||
|
uint32_t range; /* predefined range list */
|
||||||
|
} PCMPcbasm;
|
||||||
|
|
||||||
|
#define PCMPcbasmsz (1+1+1+1+4)
|
||||||
|
|
||||||
|
enum { /* table entry types */
|
||||||
|
PcmpPROCESSOR = 0x00, /* one entry per processor */
|
||||||
|
PcmpBUS = 0x01, /* one entry per bus */
|
||||||
|
PcmpIOAPIC = 0x02, /* one entry per I/O APIC */
|
||||||
|
PcmpIOINTR = 0x03, /* one entry per bus interrupt source */
|
||||||
|
PcmpLINTR = 0x04, /* one entry per system interrupt source */
|
||||||
|
|
||||||
|
PcmpSASM = 0x80,
|
||||||
|
PcmpHIERARCHY = 0x81,
|
||||||
|
PcmpCBASM = 0x82,
|
||||||
|
|
||||||
|
/* PCMPprocessor and PCMPioapic flags */
|
||||||
|
PcmpEN = 0x01, /* enabled */
|
||||||
|
PcmpBP = 0x02, /* bootstrap processor */
|
||||||
|
|
||||||
|
/* PCMPiointr and PCMPlintr flags */
|
||||||
|
PcmpPOMASK = 0x03, /* polarity conforms to specifications of bus */
|
||||||
|
PcmpHIGH = 0x01, /* active high */
|
||||||
|
PcmpLOW = 0x03, /* active low */
|
||||||
|
PcmpELMASK = 0x0C, /* trigger mode of APIC input signals */
|
||||||
|
PcmpEDGE = 0x04, /* edge-triggered */
|
||||||
|
PcmpLEVEL = 0x0C, /* level-triggered */
|
||||||
|
|
||||||
|
/* PCMPiointr and PCMPlintr interrupt type */
|
||||||
|
PcmpINT = 0x00, /* vectored interrupt from APIC Rdt */
|
||||||
|
PcmpNMI = 0x01, /* non-maskable interrupt */
|
||||||
|
PcmpSMI = 0x02, /* system management interrupt */
|
||||||
|
PcmpExtINT = 0x03, /* vectored interrupt from external PIC */
|
||||||
|
|
||||||
|
/* PCMPsasm addrtype */
|
||||||
|
PcmpIOADDR = 0x00, /* I/O address */
|
||||||
|
PcmpMADDR = 0x01, /* memory address */
|
||||||
|
PcmpPADDR = 0x02, /* prefetch address */
|
||||||
|
|
||||||
|
/* PCMPhierarchy info */
|
||||||
|
PcmpSD = 0x01, /* subtractive decode bus */
|
||||||
|
|
||||||
|
/* PCMPcbasm modifier */
|
||||||
|
PcmpPR = 0x01, /* predefined range list */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Condensed form of the MP Configuration Table.
|
||||||
|
* This is created during a single pass through the MP Configuration
|
||||||
|
* table.
|
||||||
|
*/
|
||||||
|
typedef struct Aintr Aintr;
|
||||||
|
typedef struct Bus Bus;
|
||||||
|
typedef struct Apic Apic;
|
||||||
|
|
||||||
|
typedef struct Bus {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t busno;
|
||||||
|
uint8_t po;
|
||||||
|
uint8_t el;
|
||||||
|
|
||||||
|
Aintr* aintr; /* interrupts tied to this bus */
|
||||||
|
Bus* next;
|
||||||
|
} Bus;
|
||||||
|
|
||||||
|
typedef struct Aintr {
|
||||||
|
PCMPintr* intr;
|
||||||
|
Apic* apic;
|
||||||
|
Aintr* next;
|
||||||
|
} Aintr;
|
||||||
|
|
||||||
|
typedef struct Apic {
|
||||||
|
int type;
|
||||||
|
int apicno;
|
||||||
|
uint32_t* addr; /* register base address */
|
||||||
|
uint32_t paddr;
|
||||||
|
int flags; /* PcmpBP|PcmpEN */
|
||||||
|
|
||||||
|
Lock; /* I/O APIC: register access */
|
||||||
|
int mre; /* I/O APIC: maximum redirection entry */
|
||||||
|
int gsibase; /* I/O APIC: global system interrupt base (acpi) */
|
||||||
|
|
||||||
|
int lintr[2]; /* Local APIC */
|
||||||
|
int machno;
|
||||||
|
|
||||||
|
int online;
|
||||||
|
} Apic;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MaxAPICNO = 254, /* 255 is physical broadcast */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { /* I/O APIC registers */
|
||||||
|
IoapicID = 0x00, /* ID */
|
||||||
|
IoapicVER = 0x01, /* version */
|
||||||
|
IoapicARB = 0x02, /* arbitration ID */
|
||||||
|
IoapicRDT = 0x10, /* redirection table */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common bits for
|
||||||
|
* I/O APIC Redirection Table Entry;
|
||||||
|
* Local APIC Local Interrupt Vector Table;
|
||||||
|
* Local APIC Inter-Processor Interrupt;
|
||||||
|
* Local APIC Timer Vector Table.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ApicFIXED = 0x00000000, /* [10:8] Delivery Mode */
|
||||||
|
ApicLOWEST = 0x00000100, /* Lowest priority */
|
||||||
|
ApicSMI = 0x00000200, /* System Management Interrupt */
|
||||||
|
ApicRR = 0x00000300, /* Remote Read */
|
||||||
|
ApicNMI = 0x00000400,
|
||||||
|
ApicINIT = 0x00000500, /* INIT/RESET */
|
||||||
|
ApicSTARTUP = 0x00000600, /* Startup IPI */
|
||||||
|
ApicExtINT = 0x00000700,
|
||||||
|
|
||||||
|
ApicPHYSICAL = 0x00000000, /* [11] Destination Mode (RW) */
|
||||||
|
ApicLOGICAL = 0x00000800,
|
||||||
|
|
||||||
|
ApicDELIVS = 0x00001000, /* [12] Delivery Status (RO) */
|
||||||
|
ApicHIGH = 0x00000000, /* [13] Interrupt Input Pin Polarity (RW) */
|
||||||
|
ApicLOW = 0x00002000,
|
||||||
|
ApicRemoteIRR = 0x00004000, /* [14] Remote IRR (RO) */
|
||||||
|
ApicEDGE = 0x00000000, /* [15] Trigger Mode (RW) */
|
||||||
|
ApicLEVEL = 0x00008000,
|
||||||
|
ApicIMASK = 0x00010000, /* [16] Interrupt Mask */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void ioapicinit(Apic*, int);
|
||||||
|
extern void ioapicrdtr(Apic*, int, int*, int*);
|
||||||
|
extern void ioapicrdtw(Apic*, int, int, int);
|
||||||
|
|
||||||
|
extern void lapicclock(Ureg*, void*);
|
||||||
|
extern int lapiceoi(int);
|
||||||
|
extern void lapicerror(Ureg*, void*);
|
||||||
|
extern void lapicicrw(uint32_t, uint32_t);
|
||||||
|
extern void lapicinit(Apic*);
|
||||||
|
extern void lapicintroff(void);
|
||||||
|
extern void lapicintron(void);
|
||||||
|
extern int lapicisr(int);
|
||||||
|
extern void lapicnmidisable(void);
|
||||||
|
extern void lapicnmienable(void);
|
||||||
|
extern void lapiconline(void);
|
||||||
|
extern void lapicspurious(Ureg*, void*);
|
||||||
|
extern void lapicstartap(Apic*, uintptr_t);
|
||||||
|
extern void lapictimerset(uint64_t);
|
||||||
|
|
||||||
|
extern int mpintrinit(Bus*, PCMPintr*, int, int);
|
||||||
|
extern void mpinit(void);
|
||||||
|
extern int mpintrenable(Vctl*);
|
||||||
|
extern void mpshutdown(void);
|
||||||
|
extern void mpstartap(Apic*);
|
||||||
|
|
||||||
|
extern Bus* mpbus;
|
||||||
|
extern Bus* mpbuslast;
|
||||||
|
extern int mpisabus;
|
||||||
|
extern int mpeisabus;
|
||||||
|
extern Apic *mpioapic[];
|
||||||
|
extern Apic *mpapic[];
|
|
@ -0,0 +1,390 @@
|
||||||
|
/*
|
||||||
|
* memory-type region registers.
|
||||||
|
*
|
||||||
|
* due to the possibility of extended addresses (for PAE)
|
||||||
|
* as large as 36 bits coming from the e820 memory map and the like,
|
||||||
|
* we'll use vlongs to hold addresses and lengths, even though we don't
|
||||||
|
* implement PAE in Plan 9.
|
||||||
|
*/
|
||||||
|
#include "u.h"
|
||||||
|
#include "../port/lib.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/*
|
||||||
|
* MTRR Physical base/mask are indexed by
|
||||||
|
* MTRRPhys{Base|Mask}N = MTRRPhys{Base|Mask}0 + 2*N
|
||||||
|
*/
|
||||||
|
MTRRPhysBase0 = 0x200,
|
||||||
|
MTRRPhysMask0 = 0x201,
|
||||||
|
MTRRDefaultType = 0x2FF,
|
||||||
|
MTRRCap = 0xFE,
|
||||||
|
Nmtrr = 8,
|
||||||
|
|
||||||
|
/* cpuid extended function codes */
|
||||||
|
Exthighfunc = 1ul << 31,
|
||||||
|
Extprocsigamd,
|
||||||
|
Extprocname0,
|
||||||
|
Extprocname1,
|
||||||
|
Extprocname2,
|
||||||
|
Exttlbl1,
|
||||||
|
Extl2,
|
||||||
|
Extapm,
|
||||||
|
Extaddrsz,
|
||||||
|
|
||||||
|
Paerange = 1LL << 36,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CR4PageGlobalEnable = 1 << 7,
|
||||||
|
CR0CacheDisable = 1 << 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Uncacheable = 0,
|
||||||
|
Writecomb = 1,
|
||||||
|
Unknown1 = 2,
|
||||||
|
Unknown2 = 3,
|
||||||
|
Writethru = 4,
|
||||||
|
Writeprot = 5,
|
||||||
|
Writeback = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Capvcnt = 0xff, /* mask: # of variable-range MTRRs we have */
|
||||||
|
Capwc = 1<<8, /* flag: have write combining? */
|
||||||
|
Capfix = 1<<10, /* flag: have fixed MTRRs? */
|
||||||
|
Deftype = 0xff, /* default MTRR type */
|
||||||
|
Deffixena = 1<<10, /* fixed-range MTRR enable */
|
||||||
|
Defena = 1<<11, /* MTRR enable */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Mtrreg Mtrreg;
|
||||||
|
typedef struct Mtrrop Mtrrop;
|
||||||
|
|
||||||
|
struct Mtrreg {
|
||||||
|
long base;
|
||||||
|
long mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *types[] = {
|
||||||
|
[Uncacheable] "uc",
|
||||||
|
[Writecomb] "wc",
|
||||||
|
[Unknown1] "uk1",
|
||||||
|
[Unknown2] "uk2",
|
||||||
|
[Writethru] "wt",
|
||||||
|
[Writeprot] "wp",
|
||||||
|
[Writeback] "wb",
|
||||||
|
nil
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dosync;
|
||||||
|
static Mtrreg mtrreg[Nmtrr];
|
||||||
|
|
||||||
|
static char *
|
||||||
|
type2str(int type)
|
||||||
|
{
|
||||||
|
if(type < 0 || type >= nelem(types))
|
||||||
|
return nil;
|
||||||
|
return types[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
str2type(char *str)
|
||||||
|
{
|
||||||
|
char **p;
|
||||||
|
|
||||||
|
for(p = types; *p != nil; p++)
|
||||||
|
if (strcmp(str, *p) == 0)
|
||||||
|
return p - types;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long
|
||||||
|
physmask(void)
|
||||||
|
{
|
||||||
|
uint32_t regs[4];
|
||||||
|
static long mask = -1;
|
||||||
|
|
||||||
|
if (mask != -1)
|
||||||
|
return mask;
|
||||||
|
cpuid(Exthighfunc, regs);
|
||||||
|
if(regs[0] >= Extaddrsz) { /* ax */
|
||||||
|
cpuid(Extaddrsz, regs);
|
||||||
|
mask = (1LL << (regs[0] & 0xFF)) - 1; /* ax */
|
||||||
|
}
|
||||||
|
mask &= Paerange - 1; /* x86 sanity */
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* limit physical addresses to 36 bits on the x86 */
|
||||||
|
static void
|
||||||
|
sanity(Mtrreg *mtrr)
|
||||||
|
{
|
||||||
|
mtrr->base &= Paerange - 1;
|
||||||
|
mtrr->mask &= Paerange - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ispow2(unsigned long ul)
|
||||||
|
{
|
||||||
|
return (ul & (ul - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* true if mtrr is valid */
|
||||||
|
static int
|
||||||
|
mtrrdec(Mtrreg *mtrr, unsigned long *ptr, unsigned long *size, int *type)
|
||||||
|
{
|
||||||
|
sanity(mtrr);
|
||||||
|
*ptr = mtrr->base & ~(BY2PG-1);
|
||||||
|
*type = mtrr->base & 0xff;
|
||||||
|
*size = (physmask() ^ (mtrr->mask & ~(BY2PG-1))) + 1;
|
||||||
|
return (mtrr->mask >> 11) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mtrrenc(Mtrreg *mtrr, unsigned long ptr, unsigned long size, int type, int ok)
|
||||||
|
{
|
||||||
|
mtrr->base = ptr | (type & 0xff);
|
||||||
|
mtrr->mask = (physmask() & ~(size - 1)) | (ok? 1<<11: 0);
|
||||||
|
sanity(mtrr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* i is the index of the MTRR, and is multiplied by 2 because
|
||||||
|
* mask and base offsets are interleaved.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
mtrrget(Mtrreg *mtrr, uint i)
|
||||||
|
{
|
||||||
|
rdmsr(MTRRPhysBase0 + 2*i, &mtrr->base);
|
||||||
|
rdmsr(MTRRPhysMask0 + 2*i, &mtrr->mask);
|
||||||
|
sanity(mtrr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mtrrput(Mtrreg *mtrr, uint i)
|
||||||
|
{
|
||||||
|
sanity(mtrr);
|
||||||
|
wrmsr(MTRRPhysBase0 + 2*i, mtrr->base);
|
||||||
|
wrmsr(MTRRPhysMask0 + 2*i, mtrr->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mtrrvcnt(void)
|
||||||
|
{
|
||||||
|
long cap;
|
||||||
|
int vcnt;
|
||||||
|
|
||||||
|
rdmsr(MTRRCap, &cap);
|
||||||
|
vcnt = cap & Capvcnt;
|
||||||
|
if(vcnt > Nmtrr)
|
||||||
|
vcnt = Nmtrr;
|
||||||
|
return vcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mtrrgetall(void)
|
||||||
|
{
|
||||||
|
int i, vcnt;
|
||||||
|
|
||||||
|
vcnt = mtrrvcnt();
|
||||||
|
for(i = 0; i < vcnt; i++)
|
||||||
|
mtrrget(&mtrreg[i], i);
|
||||||
|
return vcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mtrrputall(void)
|
||||||
|
{
|
||||||
|
int s, i, vcnt;
|
||||||
|
uint32_t cr0, cr4;
|
||||||
|
long def;
|
||||||
|
|
||||||
|
s = splhi();
|
||||||
|
|
||||||
|
cr4 = cr4get();
|
||||||
|
cr4put(cr4 & ~CR4PageGlobalEnable);
|
||||||
|
cr0 = cr0get();
|
||||||
|
wbinvd();
|
||||||
|
cr0put(cr0 | CR0CacheDisable);
|
||||||
|
wbinvd();
|
||||||
|
rdmsr(MTRRDefaultType, &def);
|
||||||
|
wrmsr(MTRRDefaultType, def & ~(long)Defena);
|
||||||
|
|
||||||
|
vcnt = mtrrvcnt();
|
||||||
|
for(i=0; i<vcnt; i++)
|
||||||
|
mtrrput(&mtrreg[i], i);
|
||||||
|
|
||||||
|
wbinvd();
|
||||||
|
wrmsr(MTRRDefaultType, def);
|
||||||
|
cr0put(cr0);
|
||||||
|
cr4put(cr4);
|
||||||
|
|
||||||
|
splx(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mtrrclock(void) /* called from clock interrupt */
|
||||||
|
{
|
||||||
|
static Ref bar1, bar2;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
if(dosync == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s = splhi();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wait for all CPUs to sync here, so that the MTRR setup gets
|
||||||
|
* done at roughly the same time on all processors.
|
||||||
|
*/
|
||||||
|
incref(&bar1);
|
||||||
|
while(bar1.ref < sys->nmach)
|
||||||
|
microdelay(10);
|
||||||
|
|
||||||
|
mtrrputall();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wait for all CPUs to sync up again, so that we don't continue
|
||||||
|
* executing while the MTRRs are still being set up.
|
||||||
|
*/
|
||||||
|
incref(&bar2);
|
||||||
|
while(bar2.ref < sys->nmach)
|
||||||
|
microdelay(10);
|
||||||
|
decref(&bar1);
|
||||||
|
while(bar1.ref > 0)
|
||||||
|
microdelay(10);
|
||||||
|
decref(&bar2);
|
||||||
|
|
||||||
|
dosync = 0;
|
||||||
|
splx(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
mtrr0(unsigned long base, unsigned long size, char *tstr)
|
||||||
|
{
|
||||||
|
int i, vcnt, slot, type, mtype, mok;
|
||||||
|
long def, cap;
|
||||||
|
unsigned long mp, msize;
|
||||||
|
|
||||||
|
if(!(m->cpuiddx & Mtrr))
|
||||||
|
return "mtrrs not supported";
|
||||||
|
if(base & (BY2PG-1) || size & (BY2PG-1) || size == 0)
|
||||||
|
return "mtrr base or size not 4k aligned or zero size";
|
||||||
|
if(base + size >= Paerange)
|
||||||
|
return "mtrr range exceeds 36 bits";
|
||||||
|
if(!ispow2(size))
|
||||||
|
return "mtrr size not power of 2";
|
||||||
|
if(base & (size - 1))
|
||||||
|
return "mtrr base not naturally aligned";
|
||||||
|
|
||||||
|
if((type = str2type(tstr)) == -1)
|
||||||
|
return "mtrr bad type";
|
||||||
|
|
||||||
|
rdmsr(MTRRCap, &cap);
|
||||||
|
rdmsr(MTRRDefaultType, &def);
|
||||||
|
|
||||||
|
switch(type){
|
||||||
|
default:
|
||||||
|
return "mtrr unknown type";
|
||||||
|
case Writecomb:
|
||||||
|
if(!(cap & Capwc))
|
||||||
|
return "mtrr type wc (write combining) unsupported";
|
||||||
|
/* fallthrough */
|
||||||
|
case Uncacheable:
|
||||||
|
case Writethru:
|
||||||
|
case Writeprot:
|
||||||
|
case Writeback:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vcnt = mtrrgetall();
|
||||||
|
|
||||||
|
slot = -1;
|
||||||
|
for(i = 0; i < vcnt; i++){
|
||||||
|
mok = mtrrdec(&mtrreg[i], &mp, &msize, &mtype);
|
||||||
|
if(slot == -1 && (!mok || mtype == (def & Deftype)))
|
||||||
|
slot = i; /* good, but look further for exact match */
|
||||||
|
if(mok && mp == base && msize == size){
|
||||||
|
slot = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(slot == -1)
|
||||||
|
return "no free mtrr slots";
|
||||||
|
|
||||||
|
mtrrenc(&mtrreg[slot], base, size, type, 1);
|
||||||
|
|
||||||
|
coherence();
|
||||||
|
|
||||||
|
dosync = 1;
|
||||||
|
mtrrclock();
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
mtrr(unsigned long base, unsigned long size, char *tstr)
|
||||||
|
{
|
||||||
|
static QLock mtrrlk;
|
||||||
|
char *err;
|
||||||
|
|
||||||
|
qlock(&mtrrlk);
|
||||||
|
err = mtrr0(base, size, tstr);
|
||||||
|
qunlock(&mtrrlk);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mtrrprint(char *buf, long bufsize)
|
||||||
|
{
|
||||||
|
int i, n, vcnt, type;
|
||||||
|
unsigned long base, size;
|
||||||
|
Mtrreg mtrr;
|
||||||
|
long def;
|
||||||
|
|
||||||
|
if(!(m->cpuiddx & Mtrr))
|
||||||
|
return 0;
|
||||||
|
rdmsr(MTRRDefaultType, &def);
|
||||||
|
n = snprint(buf, bufsize, "cache default %s\n",
|
||||||
|
type2str(def & Deftype));
|
||||||
|
vcnt = mtrrvcnt();
|
||||||
|
for(i = 0; i < vcnt; i++){
|
||||||
|
mtrrget(&mtrr, i);
|
||||||
|
if (mtrrdec(&mtrr, &base, &size, &type))
|
||||||
|
n += snprint(buf+n, bufsize-n,
|
||||||
|
"cache 0x%llux %llud %s\n",
|
||||||
|
base, size, type2str(type));
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mtrrsync(void)
|
||||||
|
{
|
||||||
|
static long cap0, def0;
|
||||||
|
long cap, def;
|
||||||
|
|
||||||
|
rdmsr(MTRRCap, &cap);
|
||||||
|
rdmsr(MTRRDefaultType, &def);
|
||||||
|
|
||||||
|
if(m->machno == 0){
|
||||||
|
cap0 = cap;
|
||||||
|
def0 = def;
|
||||||
|
mtrrgetall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cap0 != cap)
|
||||||
|
print("mtrrcap%d: %lluX %lluX\n",
|
||||||
|
m->machno, cap0, cap);
|
||||||
|
if(def0 != def)
|
||||||
|
print("mtrrdef%d: %lluX %lluX\n",
|
||||||
|
m->machno, def0, def);
|
||||||
|
mtrrputall();
|
||||||
|
}
|
|
@ -1,155 +1,126 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Jehanne.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||||
|
*
|
||||||
|
* Jehanne 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, version 2 of the License.
|
||||||
|
*
|
||||||
|
* Jehanne 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 Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
#include "u.h"
|
#include "u.h"
|
||||||
#include "../port/lib.h"
|
#include "../port/lib.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
#include "ureg.h"
|
||||||
|
#include "multiboot.h"
|
||||||
|
|
||||||
typedef struct Mbi Mbi;
|
#define AT_KERNEL(p) ((void*)(p+KZERO))
|
||||||
struct Mbi {
|
|
||||||
uint32_t flags;
|
|
||||||
uint32_t memlower;
|
|
||||||
uint32_t memupper;
|
|
||||||
uint32_t bootdevice;
|
|
||||||
uint32_t cmdline;
|
|
||||||
uint32_t modscount;
|
|
||||||
uint32_t modsaddr;
|
|
||||||
uint32_t syms[4];
|
|
||||||
uint32_t mmaplength;
|
|
||||||
uint32_t mmapaddr;
|
|
||||||
uint32_t driveslength;
|
|
||||||
uint32_t drivesaddr;
|
|
||||||
uint32_t configtable;
|
|
||||||
uint32_t bootloadername;
|
|
||||||
uint32_t apmtable;
|
|
||||||
uint32_t vbe[6];
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { /* flags */
|
extern int e820map(int type, uintptr_t base, uintptr_t top);
|
||||||
Fmem = 0x00000001, /* mem* valid */
|
|
||||||
Fbootdevice = 0x00000002, /* bootdevice valid */
|
|
||||||
Fcmdline = 0x00000004, /* cmdline valid */
|
|
||||||
Fmods = 0x00000008, /* mod* valid */
|
|
||||||
Fsyms = 0x00000010, /* syms[] has a.out info */
|
|
||||||
Felf = 0x00000020, /* syms[] has ELF info */
|
|
||||||
Fmmap = 0x00000040, /* mmap* valid */
|
|
||||||
Fdrives = 0x00000080, /* drives* valid */
|
|
||||||
Fconfigtable = 0x00000100, /* configtable* valid */
|
|
||||||
Fbootloadername = 0x00000200, /* bootloadername* valid */
|
|
||||||
Fapmtable = 0x00000400, /* apmtable* valid */
|
|
||||||
Fvbe = 0x00000800, /* vbe[] valid */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Mod Mod;
|
|
||||||
struct Mod {
|
|
||||||
uint32_t modstart;
|
|
||||||
uint32_t modend;
|
|
||||||
uint32_t string;
|
|
||||||
uint32_t reserved;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct MMap MMap;
|
|
||||||
struct MMap {
|
|
||||||
uint32_t size;
|
|
||||||
uint32_t base[2];
|
|
||||||
uint32_t length[2];
|
|
||||||
uint32_t type;
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
int
|
||||||
multiboot(uint32_t magic, uint32_t pmbi, int vflag)
|
multiboot(int just_log)
|
||||||
{
|
{
|
||||||
|
uint32_t magic;
|
||||||
char *p, *modname;
|
char *p, *modname;
|
||||||
int i, n;
|
int i, n;
|
||||||
Mbi *mbi;
|
multiboot_info_t *mbi;
|
||||||
Mod *mod;
|
multiboot_module_t *mod;
|
||||||
MMap *mmap;
|
multiboot_memory_map_t *mmap;
|
||||||
uint64_t addr, len;
|
uint64_t addr, len;
|
||||||
|
|
||||||
if(vflag)
|
magic = (uint32_t)sys->boot_regs->ax;
|
||||||
jehanne_print("magic %#ux pmbi %#ux\n", magic, pmbi);
|
mbi = (multiboot_info_t*)sys->boot_regs->bx;
|
||||||
if(magic != 0x2badb002){
|
|
||||||
//return -1;
|
|
||||||
jehanne_print("wrong magic in multiboot\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
mbi = KADDR(pmbi);
|
if(just_log)
|
||||||
if(vflag)
|
jehanne_print("magic %#ux infos at %#p\n", magic, mbi);
|
||||||
|
if(magic != 0x2badb002)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(just_log)
|
||||||
jehanne_print("flags %#ux\n", mbi->flags);
|
jehanne_print("flags %#ux\n", mbi->flags);
|
||||||
if(mbi->flags & Fcmdline){
|
if(mbi->flags & MULTIBOOT_INFO_CMDLINE){
|
||||||
p = KADDR(mbi->cmdline);
|
p = AT_KERNEL(mbi->cmdline);
|
||||||
if(vflag)
|
if(just_log)
|
||||||
jehanne_print("cmdline <%s>\n", p);
|
jehanne_print("Multiboot Command Line:\n\t%s\n", p);
|
||||||
else
|
else
|
||||||
optionsinit(p);
|
optionsinit(p);
|
||||||
}
|
}
|
||||||
if(mbi->flags & Fmods){
|
if(mbi->flags & MULTIBOOT_INFO_MODS){
|
||||||
for(i = 0; i < mbi->modscount; i++){
|
if(just_log)
|
||||||
mod = KADDR(mbi->modsaddr + i*16);
|
jehanne_print("Multiboot Modules:\n");
|
||||||
if(mod->string != 0)
|
for(i = 0; i < mbi->mods_count; i++){
|
||||||
p = KADDR(mod->string);
|
mod = AT_KERNEL(mbi->mods_addr);
|
||||||
|
if(mod->cmdline != 0)
|
||||||
|
p = AT_KERNEL(mod->cmdline);
|
||||||
else
|
else
|
||||||
p = "";
|
p = "";
|
||||||
if(vflag)
|
if(just_log)
|
||||||
jehanne_print("mod %#ux %#ux <%s>\n",
|
jehanne_print("\tModule <%s> %#ux %#ux\n",
|
||||||
mod->modstart, mod->modend, p);
|
mod->mod_start, mod->mod_end, p);
|
||||||
else {
|
else {
|
||||||
asmmodinit(mod->modstart, mod->modend, p);
|
asmmodinit(mod->mod_start, mod->mod_end, p);
|
||||||
modname = jehanne_strrchr(p, '/');
|
modname = jehanne_strrchr(p, '/');
|
||||||
if(modname == nil)
|
if(modname == nil)
|
||||||
modname = p;
|
modname = p;
|
||||||
if(*modname == '/')
|
if(*modname == '/')
|
||||||
++modname;
|
++modname;
|
||||||
addbootfile(modname, KADDR(mod->modstart), mod->modend - mod->modstart);
|
addbootfile(modname, AT_KERNEL(mod->mod_start), mod->mod_end - mod->mod_start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(mbi->flags & Fmmap){
|
if(mbi->flags & MULTIBOOT_INFO_MEM_MAP){
|
||||||
mmap = KADDR(mbi->mmapaddr);
|
if(just_log)
|
||||||
|
jehanne_print("Multiboot Memory Map:\n");
|
||||||
|
mmap = AT_KERNEL(mbi->mmap_addr);
|
||||||
n = 0;
|
n = 0;
|
||||||
while(n < mbi->mmaplength){
|
while(n < mbi->mmap_length){
|
||||||
addr = (((uint64_t)mmap->base[1])<<32)|mmap->base[0];
|
addr = mmap->addr;
|
||||||
len = (((uint64_t)mmap->length[1])<<32)|mmap->length[0];
|
len = mmap->len;
|
||||||
switch(mmap->type){
|
switch(mmap->type){
|
||||||
default:
|
default:
|
||||||
if(vflag)
|
if(just_log)
|
||||||
jehanne_print("type %ud", mmap->type);
|
jehanne_print("\ttype %ud ", mmap->type);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case MULTIBOOT_MEMORY_AVAILABLE:
|
||||||
if(vflag)
|
if(just_log)
|
||||||
jehanne_print("Memory");
|
jehanne_print("\tMemory");
|
||||||
else
|
|
||||||
asmmapinit(addr, len, mmap->type);
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case MULTIBOOT_MEMORY_RESERVED:
|
||||||
if(vflag)
|
if(just_log)
|
||||||
jehanne_print("reserved");
|
jehanne_print("\tReserved");
|
||||||
else
|
|
||||||
asmmapinit(addr, len, mmap->type);
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if(vflag)
|
if(just_log)
|
||||||
jehanne_print("ACPI Reclaim Memory");
|
jehanne_print("\tACPI Reclaim Memory");
|
||||||
else
|
|
||||||
asmmapinit(addr, len, mmap->type);
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if(vflag)
|
if(just_log)
|
||||||
jehanne_print("ACPI NVS Memory");
|
jehanne_print("\tACPI NVS Memory");
|
||||||
else
|
|
||||||
asmmapinit(addr, len, mmap->type);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(vflag)
|
if(just_log)
|
||||||
jehanne_print("\n\t %#16.16llux %#16.16llux (%llud)\n",
|
jehanne_print("\n\t %#16.16llux %#16.16llux (%llud)\n",
|
||||||
addr, addr+len, len);
|
addr, addr+len, len);
|
||||||
|
else
|
||||||
|
e820map(mmap->type, addr, addr+len);
|
||||||
|
|
||||||
n += mmap->size+sizeof(mmap->size);
|
n += mmap->size+sizeof(mmap->size);
|
||||||
mmap = KADDR(mbi->mmapaddr+n);
|
mmap = AT_KERNEL(mbi->mmap_addr+n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(vflag && (mbi->flags & Fbootloadername)){
|
if(just_log && (mbi->flags & MULTIBOOT_INFO_BOOT_LOADER_NAME)){
|
||||||
p = KADDR(mbi->bootloadername);
|
p = AT_KERNEL(mbi->boot_loader_name);
|
||||||
jehanne_print("bootloadername <%s>\n", p);
|
jehanne_print("Multiboot: Boot Loader Name <%s>\n", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -0,0 +1,222 @@
|
||||||
|
/* Copyright (C) 1999,2003,2007,2008,2009 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
|
||||||
|
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MULTIBOOT_HEADER
|
||||||
|
#define MULTIBOOT_HEADER 1
|
||||||
|
|
||||||
|
/* How many bytes from the start of the file we search for the header. */
|
||||||
|
#define MULTIBOOT_SEARCH 8192
|
||||||
|
|
||||||
|
/* The magic field should contain this. */
|
||||||
|
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
|
||||||
|
|
||||||
|
/* This should be in %eax. */
|
||||||
|
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
|
||||||
|
|
||||||
|
/* The bits in the required part of flags field we don't support. */
|
||||||
|
#define MULTIBOOT_UNSUPPORTED 0x0000fffc
|
||||||
|
|
||||||
|
/* Alignment of multiboot modules. */
|
||||||
|
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||||
|
|
||||||
|
/* Alignment of the multiboot info structure. */
|
||||||
|
#define MULTIBOOT_INFO_ALIGN 0x00000004
|
||||||
|
|
||||||
|
/* Flags set in the 'flags' member of the multiboot header. */
|
||||||
|
|
||||||
|
/* Align all boot modules on i386 page (4KB) boundaries. */
|
||||||
|
#define MULTIBOOT_PAGE_ALIGN 0x00000001
|
||||||
|
|
||||||
|
/* Must pass memory information to OS. */
|
||||||
|
#define MULTIBOOT_MEMORY_INFO 0x00000002
|
||||||
|
|
||||||
|
/* Must pass video information to OS. */
|
||||||
|
#define MULTIBOOT_VIDEO_MODE 0x00000004
|
||||||
|
|
||||||
|
/* This flag indicates the use of the address fields in the header. */
|
||||||
|
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
|
||||||
|
|
||||||
|
/* Flags to be set in the 'flags' member of the multiboot info structure. */
|
||||||
|
|
||||||
|
/* is there basic lower/upper memory information? */
|
||||||
|
#define MULTIBOOT_INFO_MEMORY 0x00000001
|
||||||
|
/* is there a boot device set? */
|
||||||
|
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
|
||||||
|
/* is the command-line defined? */
|
||||||
|
#define MULTIBOOT_INFO_CMDLINE 0x00000004
|
||||||
|
/* are there modules to do something with? */
|
||||||
|
#define MULTIBOOT_INFO_MODS 0x00000008
|
||||||
|
|
||||||
|
/* These next two are mutually exclusive */
|
||||||
|
|
||||||
|
/* is there a symbol table loaded? */
|
||||||
|
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
|
||||||
|
/* is there an ELF section header table? */
|
||||||
|
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
|
||||||
|
|
||||||
|
/* is there a full memory map? */
|
||||||
|
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
|
||||||
|
|
||||||
|
/* Is there drive info? */
|
||||||
|
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
|
||||||
|
|
||||||
|
/* Is there a config table? */
|
||||||
|
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
|
||||||
|
|
||||||
|
/* Is there a boot loader name? */
|
||||||
|
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
|
||||||
|
|
||||||
|
/* Is there a APM table? */
|
||||||
|
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
|
||||||
|
|
||||||
|
/* Is there video information? */
|
||||||
|
#define MULTIBOOT_INFO_VIDEO_INFO 0x00000800
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
typedef unsigned short multiboot_uint16_t;
|
||||||
|
typedef unsigned int multiboot_uint32_t;
|
||||||
|
typedef unsigned long long multiboot_uint64_t;
|
||||||
|
|
||||||
|
struct multiboot_header
|
||||||
|
{
|
||||||
|
/* Must be MULTIBOOT_MAGIC - see above. */
|
||||||
|
multiboot_uint32_t magic;
|
||||||
|
|
||||||
|
/* Feature flags. */
|
||||||
|
multiboot_uint32_t flags;
|
||||||
|
|
||||||
|
/* The above fields plus this one must equal 0 mod 2^32. */
|
||||||
|
multiboot_uint32_t checksum;
|
||||||
|
|
||||||
|
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
|
||||||
|
multiboot_uint32_t header_addr;
|
||||||
|
multiboot_uint32_t load_addr;
|
||||||
|
multiboot_uint32_t load_end_addr;
|
||||||
|
multiboot_uint32_t bss_end_addr;
|
||||||
|
multiboot_uint32_t entry_addr;
|
||||||
|
|
||||||
|
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
|
||||||
|
multiboot_uint32_t mode_type;
|
||||||
|
multiboot_uint32_t width;
|
||||||
|
multiboot_uint32_t height;
|
||||||
|
multiboot_uint32_t depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The symbol table for a.out. */
|
||||||
|
struct multiboot_aout_symbol_table
|
||||||
|
{
|
||||||
|
multiboot_uint32_t tabsize;
|
||||||
|
multiboot_uint32_t strsize;
|
||||||
|
multiboot_uint32_t addr;
|
||||||
|
multiboot_uint32_t reserved;
|
||||||
|
};
|
||||||
|
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
|
||||||
|
|
||||||
|
/* The section header table for ELF. */
|
||||||
|
struct multiboot_elf_section_header_table
|
||||||
|
{
|
||||||
|
multiboot_uint32_t num;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t addr;
|
||||||
|
multiboot_uint32_t shndx;
|
||||||
|
};
|
||||||
|
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
|
||||||
|
|
||||||
|
struct multiboot_info
|
||||||
|
{
|
||||||
|
/* Multiboot info version number */
|
||||||
|
multiboot_uint32_t flags;
|
||||||
|
|
||||||
|
/* Available memory from BIOS */
|
||||||
|
multiboot_uint32_t mem_lower;
|
||||||
|
multiboot_uint32_t mem_upper;
|
||||||
|
|
||||||
|
/* "root" partition */
|
||||||
|
multiboot_uint32_t boot_device;
|
||||||
|
|
||||||
|
/* Kernel command line */
|
||||||
|
multiboot_uint32_t cmdline;
|
||||||
|
|
||||||
|
/* Boot-Module list */
|
||||||
|
multiboot_uint32_t mods_count;
|
||||||
|
multiboot_uint32_t mods_addr;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
multiboot_aout_symbol_table_t aout_sym;
|
||||||
|
multiboot_elf_section_header_table_t elf_sec;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
/* Memory Mapping buffer */
|
||||||
|
multiboot_uint32_t mmap_length;
|
||||||
|
multiboot_uint32_t mmap_addr;
|
||||||
|
|
||||||
|
/* Drive Info buffer */
|
||||||
|
multiboot_uint32_t drives_length;
|
||||||
|
multiboot_uint32_t drives_addr;
|
||||||
|
|
||||||
|
/* ROM configuration table */
|
||||||
|
multiboot_uint32_t config_table;
|
||||||
|
|
||||||
|
/* Boot Loader Name */
|
||||||
|
multiboot_uint32_t boot_loader_name;
|
||||||
|
|
||||||
|
/* APM table */
|
||||||
|
multiboot_uint32_t apm_table;
|
||||||
|
|
||||||
|
/* Video */
|
||||||
|
multiboot_uint32_t vbe_control_info;
|
||||||
|
multiboot_uint32_t vbe_mode_info;
|
||||||
|
multiboot_uint16_t vbe_mode;
|
||||||
|
multiboot_uint16_t vbe_interface_seg;
|
||||||
|
multiboot_uint16_t vbe_interface_off;
|
||||||
|
multiboot_uint16_t vbe_interface_len;
|
||||||
|
};
|
||||||
|
typedef struct multiboot_info multiboot_info_t;
|
||||||
|
|
||||||
|
struct multiboot_mmap_entry
|
||||||
|
{
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint64_t addr;
|
||||||
|
multiboot_uint64_t len;
|
||||||
|
#define MULTIBOOT_MEMORY_AVAILABLE 1
|
||||||
|
#define MULTIBOOT_MEMORY_RESERVED 2
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
} __attribute__((packed));
|
||||||
|
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
|
||||||
|
|
||||||
|
struct multiboot_mod_list
|
||||||
|
{
|
||||||
|
/* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
|
||||||
|
multiboot_uint32_t mod_start;
|
||||||
|
multiboot_uint32_t mod_end;
|
||||||
|
|
||||||
|
/* Module command line */
|
||||||
|
multiboot_uint32_t cmdline;
|
||||||
|
|
||||||
|
/* padding to take it to 16 bytes (must be zero) */
|
||||||
|
multiboot_uint32_t pad;
|
||||||
|
};
|
||||||
|
typedef struct multiboot_mod_list multiboot_module_t;
|
||||||
|
|
||||||
|
#endif /* ! __ASSEMBLER__ */
|
||||||
|
|
||||||
|
#endif /* ! MULTIBOOT_HEADER */
|
|
@ -1,129 +0,0 @@
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
Conf conf;
|
|
||||||
char *confname[1] = {
|
|
||||||
"console",
|
|
||||||
};
|
|
||||||
char *confval[1] = {
|
|
||||||
"0 b115200",
|
|
||||||
};
|
|
||||||
int nconf = nelem(confname);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Where configuration info is left for the loaded programme.
|
|
||||||
* This will turn into a structure as more is done by the boot loader
|
|
||||||
* (e.g. why parse the .ini file twice?).
|
|
||||||
* There are 3584 bytes available at CONFADDR.
|
|
||||||
*/
|
|
||||||
#define CONFADDR PTR2UINT(KADDR(0x0001200))
|
|
||||||
|
|
||||||
#define BOOTLINE ((char*)CONFADDR)
|
|
||||||
#define BOOTLINELEN 64
|
|
||||||
#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN))
|
|
||||||
#define BOOTARGSLEN (4096-0x200-BOOTLINELEN)
|
|
||||||
#define MAXCONF 64
|
|
||||||
|
|
||||||
char *confname[MAXCONF];
|
|
||||||
char *confval[MAXCONF];
|
|
||||||
int nconf;
|
|
||||||
|
|
||||||
void
|
|
||||||
confoptions(void)
|
|
||||||
{
|
|
||||||
long i, n;
|
|
||||||
char *cp, *line[MAXCONF], *p, *q;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* parse configuration args from dos file plan9.ini
|
|
||||||
*/
|
|
||||||
cp = BOOTARGS; /* where b.com leaves its config */
|
|
||||||
cp[BOOTARGSLEN-1] = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Strip out '\r', change '\t' -> ' '.
|
|
||||||
*/
|
|
||||||
p = cp;
|
|
||||||
for(q = cp; *q; q++){
|
|
||||||
if(*q == '\r')
|
|
||||||
continue;
|
|
||||||
if(*q == '\t')
|
|
||||||
*q = ' ';
|
|
||||||
*p++ = *q;
|
|
||||||
}
|
|
||||||
*p = 0;
|
|
||||||
|
|
||||||
n = jehanne_getfields(cp, line, MAXCONF, 1, "\n");
|
|
||||||
for(i = 0; i < n; i++){
|
|
||||||
if(*line[i] == '#')
|
|
||||||
continue;
|
|
||||||
cp = jehanne_strchr(line[i], '=');
|
|
||||||
if(cp == nil)
|
|
||||||
continue;
|
|
||||||
*cp++ = '\0';
|
|
||||||
confname[nconf] = line[i];
|
|
||||||
confval[nconf] = cp;
|
|
||||||
nconf++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
getconf(char *name)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < nconf; i++)
|
|
||||||
if(jehanne_cistrcmp(confname[i], name) == 0)
|
|
||||||
return confval[i];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
confsetenv(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < nconf; i++){
|
|
||||||
if(confname[i][0] != '*')
|
|
||||||
ksetenv(confname[i], confval[i], 0);
|
|
||||||
ksetenv(confname[i], confval[i], 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
isaconfig(char *class, int ctlrno, ISAConf *isa)
|
|
||||||
{
|
|
||||||
char cc[32], *p;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
jehanne_snprint(cc, sizeof cc, "%s%d", class, ctlrno);
|
|
||||||
p = getconf(cc);
|
|
||||||
if(p == nil)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
isa->type = "";
|
|
||||||
isa->nopt = jehanne_tokenize(p, isa->opt, NISAOPT);
|
|
||||||
for(i = 0; i < isa->nopt; i++){
|
|
||||||
p = isa->opt[i];
|
|
||||||
if(jehanne_cistrncmp(p, "type=", 5) == 0)
|
|
||||||
isa->type = p + 5;
|
|
||||||
else if(jehanne_cistrncmp(p, "port=", 5) == 0)
|
|
||||||
isa->port = jehanne_strtoul(p+5, &p, 0);
|
|
||||||
else if(jehanne_cistrncmp(p, "irq=", 4) == 0)
|
|
||||||
isa->irq = jehanne_strtoul(p+4, &p, 0);
|
|
||||||
else if(jehanne_cistrncmp(p, "dma=", 4) == 0)
|
|
||||||
isa->dma = jehanne_strtoul(p+4, &p, 0);
|
|
||||||
else if(jehanne_cistrncmp(p, "mem=", 4) == 0)
|
|
||||||
isa->mem = jehanne_strtoul(p+4, &p, 0);
|
|
||||||
else if(jehanne_cistrncmp(p, "size=", 5) == 0)
|
|
||||||
isa->size = jehanne_strtoul(p+5, &p, 0);
|
|
||||||
else if(jehanne_cistrncmp(p, "freq=", 5) == 0)
|
|
||||||
isa->freq = jehanne_strtoul(p+5, &p, 0);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
|
@ -1554,7 +1554,7 @@ pcinextcap(Pcidev *pci, int offset)
|
||||||
if(offset == 0) {
|
if(offset == 0) {
|
||||||
if((pcicfgr16(pci, PciPSR) & (1<<4)) == 0)
|
if((pcicfgr16(pci, PciPSR) & (1<<4)) == 0)
|
||||||
return 0; /* no capabilities */
|
return 0; /* no capabilities */
|
||||||
offset = PciCP-1;
|
offset = PciCAP-1;
|
||||||
}
|
}
|
||||||
return pcicfgr8(pci, offset+1) & ~3;
|
return pcicfgr8(pci, offset+1) & ~3;
|
||||||
}
|
}
|
|
@ -101,7 +101,7 @@ pmcnregs(void)
|
||||||
nregs = PeNregAmd;
|
nregs = PeNregAmd;
|
||||||
break;
|
break;
|
||||||
case PeIntel:
|
case PeIntel:
|
||||||
cpuid(0xa, 0, info);
|
cpuid(0xa, info);
|
||||||
nregs = (info[0]>>8)&0xff;
|
nregs = (info[0]>>8)&0xff;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -124,7 +124,7 @@ pmcmsk(void)
|
||||||
msk = ~0ULL;
|
msk = ~0ULL;
|
||||||
break;
|
break;
|
||||||
case PeIntel:
|
case PeIntel:
|
||||||
cpuid(0xa, 0, info);
|
cpuid(0xa, info);
|
||||||
msk = (1<<((info[0]>>16)&0xff)) - 1;
|
msk = (1<<((info[0]>>16)&0xff)) - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
|
@ -6,7 +6,6 @@
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
* modified, propagated, or distributed except according to the terms contained
|
||||||
* in the LICENSE file.
|
* in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "u.h"
|
#include "u.h"
|
||||||
#include "../port/lib.h"
|
#include "../port/lib.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
@ -22,40 +21,25 @@
|
||||||
#include <cursor.h>
|
#include <cursor.h>
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
|
||||||
#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
|
|
||||||
|
|
||||||
Point ZP = {0, 0};
|
|
||||||
|
|
||||||
Rectangle physgscreenr;
|
Rectangle physgscreenr;
|
||||||
|
|
||||||
Memdata gscreendata;
|
|
||||||
Memimage *gscreen;
|
Memimage *gscreen;
|
||||||
|
|
||||||
VGAscr vgascreen[1];
|
VGAscr vgascreen[1];
|
||||||
|
|
||||||
Cursor arrow = {
|
|
||||||
{ -1, -1 },
|
|
||||||
{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
|
|
||||||
0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
|
|
||||||
0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
|
|
||||||
0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
|
|
||||||
},
|
|
||||||
{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
|
|
||||||
0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
|
|
||||||
0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
|
|
||||||
0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
int didswcursorinit;
|
|
||||||
|
|
||||||
static void *softscreen;
|
|
||||||
|
|
||||||
int
|
int
|
||||||
screensize(int x, int y, int z, uint32_t chan)
|
screensize(int x, int y, int _, uint32_t chan)
|
||||||
{
|
{
|
||||||
VGAscr *scr;
|
VGAscr *scr;
|
||||||
void *oldsoft;
|
|
||||||
|
qlock(&drawlock);
|
||||||
|
if(waserror()){
|
||||||
|
qunlock(&drawlock);
|
||||||
|
nexterror();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memimageinit() < 0)
|
||||||
|
error("memimageinit failed");
|
||||||
|
|
||||||
lock(&vgascreenlock);
|
lock(&vgascreenlock);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
|
@ -63,54 +47,54 @@ screensize(int x, int y, int z, uint32_t chan)
|
||||||
nexterror();
|
nexterror();
|
||||||
}
|
}
|
||||||
|
|
||||||
memimageinit();
|
|
||||||
scr = &vgascreen[0];
|
scr = &vgascreen[0];
|
||||||
oldsoft = softscreen;
|
scr->gscreendata = nil;
|
||||||
|
scr->gscreen = nil;
|
||||||
|
if(gscreen){
|
||||||
|
freememimage(gscreen);
|
||||||
|
gscreen = nil;
|
||||||
|
}
|
||||||
|
|
||||||
if(scr->paddr == 0){
|
if(scr->paddr == 0){
|
||||||
int width = (x*z)/BI2WD;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
p = jehanne_malloc(width*BY2WD*y);
|
|
||||||
if(p == nil)
|
|
||||||
error("no memory for vga soft screen");
|
|
||||||
gscreendata.bdata = softscreen = p;
|
|
||||||
if(scr->dev && scr->dev->page){
|
if(scr->dev && scr->dev->page){
|
||||||
scr->vaddr = KADDR(VGAMEM());
|
scr->vaddr = KADDR(VGAMEM());
|
||||||
scr->apsize = 1<<16;
|
scr->apsize = 1<<16;
|
||||||
}
|
}
|
||||||
scr->useflush = 1;
|
scr->softscreen = 1;
|
||||||
}
|
}
|
||||||
else{
|
if(scr->softscreen){
|
||||||
gscreendata.bdata = scr->vaddr;
|
gscreen = allocmemimage(Rect(0,0,x,y), chan);
|
||||||
|
scr->useflush = 1;
|
||||||
|
}else{
|
||||||
|
static Memdata md;
|
||||||
|
|
||||||
|
md.ref = 1;
|
||||||
|
if((md.bdata = scr->vaddr) == 0)
|
||||||
|
error("framebuffer not maped");
|
||||||
|
gscreen = allocmemimaged(Rect(0,0,x,y), chan, &md);
|
||||||
scr->useflush = scr->dev && scr->dev->flush;
|
scr->useflush = scr->dev && scr->dev->flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
scr->gscreen = nil;
|
|
||||||
if(gscreen)
|
|
||||||
freememimage(gscreen);
|
|
||||||
gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata);
|
|
||||||
if(gscreen == nil)
|
if(gscreen == nil)
|
||||||
error("no memory for vga memimage");
|
error("no memory for vga memimage");
|
||||||
vgaimageinit(chan);
|
|
||||||
|
|
||||||
scr->palettedepth = 6; /* default */
|
scr->palettedepth = 6; /* default */
|
||||||
scr->gscreendata = &gscreendata;
|
|
||||||
scr->memdefont = getmemdefont();
|
scr->memdefont = getmemdefont();
|
||||||
scr->gscreen = gscreen;
|
scr->gscreen = gscreen;
|
||||||
|
scr->gscreendata = gscreen->data;
|
||||||
|
|
||||||
physgscreenr = gscreen->r;
|
physgscreenr = gscreen->r;
|
||||||
|
|
||||||
|
vgaimageinit(chan);
|
||||||
|
|
||||||
unlock(&vgascreenlock);
|
unlock(&vgascreenlock);
|
||||||
poperror();
|
poperror();
|
||||||
if(oldsoft)
|
|
||||||
jehanne_free(oldsoft);
|
|
||||||
|
|
||||||
memimagedraw(gscreen, gscreen->r, memblack, ZP, nil, ZP, S);
|
|
||||||
flushmemscreen(gscreen->r);
|
|
||||||
|
|
||||||
if(didswcursorinit)
|
|
||||||
swcursorinit();
|
|
||||||
drawcmap();
|
drawcmap();
|
||||||
|
swcursorinit();
|
||||||
|
|
||||||
|
qunlock(&drawlock);
|
||||||
|
poperror();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,8 +120,8 @@ screenaperture(int size, int align)
|
||||||
* Need to allocate some physical address space.
|
* Need to allocate some physical address space.
|
||||||
* The driver will tell the card to use it.
|
* The driver will tell the card to use it.
|
||||||
*/
|
*/
|
||||||
size = ROUNDUP(sizeof(size), 4*KiB);
|
size = PGROUND(size);
|
||||||
scr->paddr = (uint64_t)jehanne_malloc(size);
|
scr->paddr = upaalloc(size, align);
|
||||||
if(scr->paddr == 0)
|
if(scr->paddr == 0)
|
||||||
return -1;
|
return -1;
|
||||||
scr->vaddr = vmap(scr->paddr, size);
|
scr->vaddr = vmap(scr->paddr, size);
|
||||||
|
@ -148,7 +132,7 @@ screenaperture(int size, int align)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char*
|
uint8_t*
|
||||||
attachscreen(Rectangle* r, uint32_t* chan, int* d, int* width, int *softscreen)
|
attachscreen(Rectangle* r, uint32_t* chan, int* d, int* width, int *softscreen)
|
||||||
{
|
{
|
||||||
VGAscr *scr;
|
VGAscr *scr;
|
||||||
|
@ -161,63 +145,72 @@ attachscreen(Rectangle* r, uint32_t* chan, int* d, int* width, int *softscreen)
|
||||||
*chan = scr->gscreen->chan;
|
*chan = scr->gscreen->chan;
|
||||||
*d = scr->gscreen->depth;
|
*d = scr->gscreen->depth;
|
||||||
*width = scr->gscreen->width;
|
*width = scr->gscreen->width;
|
||||||
*softscreen = scr->useflush;
|
if(scr->gscreendata->allocd){
|
||||||
|
/*
|
||||||
|
* we use a memimage as softscreen. devdraw will create its own
|
||||||
|
* screen image on the backing store of that image. when our gscreen
|
||||||
|
* and devdraws screenimage gets freed, the imagedata will
|
||||||
|
* be released.
|
||||||
|
*/
|
||||||
|
*softscreen = 0xa110c;
|
||||||
|
scr->gscreendata->ref++;
|
||||||
|
} else
|
||||||
|
*softscreen = scr->useflush ? 1 : 0;
|
||||||
return scr->gscreendata->bdata;
|
return scr->gscreendata->bdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* It would be fair to say that this doesn't work for >8-bit screens.
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
flushmemscreen(Rectangle r)
|
flushmemscreen(Rectangle r)
|
||||||
{
|
{
|
||||||
VGAscr *scr;
|
VGAscr *scr;
|
||||||
unsigned char *sp, *disp, *sdisp, *edisp;
|
uint8_t *sp, *disp, *sdisp, *edisp;
|
||||||
int y, len, incs, off, page;
|
int y, len, incs, off, page;
|
||||||
|
|
||||||
scr = &vgascreen[0];
|
scr = &vgascreen[0];
|
||||||
|
if(scr->gscreen == nil || scr->useflush == 0)
|
||||||
|
return;
|
||||||
|
if(rectclip(&r, scr->gscreen->r) == 0)
|
||||||
|
return;
|
||||||
if(scr->dev && scr->dev->flush){
|
if(scr->dev && scr->dev->flush){
|
||||||
scr->dev->flush(scr, r);
|
scr->dev->flush(scr, r);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(scr->gscreen == nil || scr->useflush == 0)
|
disp = scr->vaddr;
|
||||||
|
incs = scr->gscreen->width*sizeof(uint32_t);
|
||||||
|
off = (r.min.x*scr->gscreen->depth) / 8;
|
||||||
|
len = (r.max.x*scr->gscreen->depth + 7) / 8;
|
||||||
|
len -= off;
|
||||||
|
off += r.min.y*incs;
|
||||||
|
sp = scr->gscreendata->bdata + scr->gscreen->zero + off;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linear framebuffer with softscreen.
|
||||||
|
*/
|
||||||
|
if(scr->paddr){
|
||||||
|
sdisp = disp+off;
|
||||||
|
for(y = r.min.y; y < r.max.y; y++) {
|
||||||
|
memmove(sdisp, sp, len);
|
||||||
|
sp += incs;
|
||||||
|
sdisp += incs;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Paged framebuffer window.
|
||||||
|
*/
|
||||||
if(scr->dev == nil || scr->dev->page == nil)
|
if(scr->dev == nil || scr->dev->page == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(rectclip(&r, scr->gscreen->r) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
incs = scr->gscreen->width * BY2WD;
|
|
||||||
|
|
||||||
switch(scr->gscreen->depth){
|
|
||||||
default:
|
|
||||||
len = 0;
|
|
||||||
panic("flushmemscreen: depth\n");
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
len = Dx(r);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(len < 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
|
|
||||||
page = off/scr->apsize;
|
page = off/scr->apsize;
|
||||||
off %= scr->apsize;
|
off %= scr->apsize;
|
||||||
disp = scr->vaddr;
|
|
||||||
sdisp = disp+off;
|
sdisp = disp+off;
|
||||||
edisp = disp+scr->apsize;
|
edisp = disp+scr->apsize;
|
||||||
|
|
||||||
off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
|
|
||||||
|
|
||||||
sp = scr->gscreendata->bdata + off;
|
|
||||||
|
|
||||||
scr->dev->page(scr, page);
|
scr->dev->page(scr, page);
|
||||||
for(y = r.min.y; y < r.max.y; y++) {
|
for(y = r.min.y; y < r.max.y; y++) {
|
||||||
if(sdisp + incs < edisp) {
|
if(sdisp + incs < edisp) {
|
||||||
jehanne_memmove(sdisp, sp, len);
|
memmove(sdisp, sp, len);
|
||||||
sp += incs;
|
sp += incs;
|
||||||
sdisp += incs;
|
sdisp += incs;
|
||||||
}
|
}
|
||||||
|
@ -226,13 +219,13 @@ flushmemscreen(Rectangle r)
|
||||||
page++;
|
page++;
|
||||||
if(off <= len){
|
if(off <= len){
|
||||||
if(off > 0)
|
if(off > 0)
|
||||||
jehanne_memmove(sdisp, sp, off);
|
memmove(sdisp, sp, off);
|
||||||
scr->dev->page(scr, page);
|
scr->dev->page(scr, page);
|
||||||
if(len - off > 0)
|
if(len - off > 0)
|
||||||
jehanne_memmove(disp, sp+off, len - off);
|
memmove(disp, sp+off, len - off);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
jehanne_memmove(sdisp, sp, len);
|
memmove(sdisp, sp, len);
|
||||||
scr->dev->page(scr, page);
|
scr->dev->page(scr, page);
|
||||||
}
|
}
|
||||||
sp += incs;
|
sp += incs;
|
||||||
|
@ -261,11 +254,11 @@ getcolor(uint32_t p, uint32_t* pr, uint32_t* pg, uint32_t* pb)
|
||||||
}
|
}
|
||||||
p &= x;
|
p &= x;
|
||||||
|
|
||||||
lock(&cursor.l);
|
lock(&cursor);
|
||||||
*pr = scr->colormap[p][0];
|
*pr = scr->colormap[p][0];
|
||||||
*pg = scr->colormap[p][1];
|
*pg = scr->colormap[p][1];
|
||||||
*pb = scr->colormap[p][2];
|
*pb = scr->colormap[p][2];
|
||||||
unlock(&cursor.l);
|
unlock(&cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -277,7 +270,7 @@ setpalette(uint32_t p, uint32_t r, uint32_t g, uint32_t b)
|
||||||
scr = &vgascreen[0];
|
scr = &vgascreen[0];
|
||||||
d = scr->palettedepth;
|
d = scr->palettedepth;
|
||||||
|
|
||||||
lock(&cursor.l);
|
lock(&cursor);
|
||||||
scr->colormap[p][0] = r;
|
scr->colormap[p][0] = r;
|
||||||
scr->colormap[p][1] = g;
|
scr->colormap[p][1] = g;
|
||||||
scr->colormap[p][2] = b;
|
scr->colormap[p][2] = b;
|
||||||
|
@ -285,7 +278,7 @@ setpalette(uint32_t p, uint32_t r, uint32_t g, uint32_t b)
|
||||||
vgao(Pdata, r>>(32-d));
|
vgao(Pdata, r>>(32-d));
|
||||||
vgao(Pdata, g>>(32-d));
|
vgao(Pdata, g>>(32-d));
|
||||||
vgao(Pdata, b>>(32-d));
|
vgao(Pdata, b>>(32-d));
|
||||||
unlock(&cursor.l);
|
unlock(&cursor);
|
||||||
|
|
||||||
return ~0;
|
return ~0;
|
||||||
}
|
}
|
||||||
|
@ -322,27 +315,71 @@ setcolor(uint32_t p, uint32_t r, uint32_t g, uint32_t b)
|
||||||
return setpalette(p, r, g, b);
|
return setpalette(p, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
cursoron(int dolock)
|
swenable(VGAscr* _)
|
||||||
{
|
{
|
||||||
VGAscr *scr;
|
swcursorload(&arrow);
|
||||||
int v;
|
|
||||||
|
|
||||||
scr = &vgascreen[0];
|
|
||||||
if(scr->cur == nil || scr->cur->move == nil)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if(dolock)
|
|
||||||
lock(&cursor.l);
|
|
||||||
v = scr->cur->move(scr, mousexy());
|
|
||||||
if(dolock)
|
|
||||||
unlock(&cursor.l);
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cursoroff(int i)
|
swdisable(VGAscr* _)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
swload(VGAscr* _, Cursor *curs)
|
||||||
|
{
|
||||||
|
swcursorload(curs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
swmove(VGAscr* _, Point p)
|
||||||
|
{
|
||||||
|
swcursorhide();
|
||||||
|
swcursordraw(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VGAcur swcursor =
|
||||||
|
{
|
||||||
|
"soft",
|
||||||
|
swenable,
|
||||||
|
swdisable,
|
||||||
|
swload,
|
||||||
|
swmove,
|
||||||
|
};
|
||||||
|
|
||||||
|
VGAcur vgavesacur =
|
||||||
|
{
|
||||||
|
"soft",
|
||||||
|
swenable,
|
||||||
|
swdisable,
|
||||||
|
swload,
|
||||||
|
swmove,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
cursoron(void)
|
||||||
|
{
|
||||||
|
VGAscr *scr;
|
||||||
|
VGAcur *cur;
|
||||||
|
|
||||||
|
scr = &vgascreen[0];
|
||||||
|
cur = scr->cur;
|
||||||
|
if(cur == nil || cur->move == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(cur == &swcursor)
|
||||||
|
qlock(&drawlock);
|
||||||
|
lock(&cursor);
|
||||||
|
cur->move(scr, mousexy());
|
||||||
|
unlock(&cursor);
|
||||||
|
if(cur == &swcursor)
|
||||||
|
qunlock(&drawlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cursoroff(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,8 +395,8 @@ setcursor(Cursor* curs)
|
||||||
scr->cur->load(scr, curs);
|
scr->cur->load(scr, curs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hwaccel = 1;
|
int hwaccel = 0;
|
||||||
int hwblank = 0; /* turned on by drivers that are known good */
|
int hwblank = 0;
|
||||||
int panning = 0;
|
int panning = 0;
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -367,37 +404,30 @@ hwdraw(Memdrawparam *par)
|
||||||
{
|
{
|
||||||
VGAscr *scr;
|
VGAscr *scr;
|
||||||
Memimage *dst, *src, *mask;
|
Memimage *dst, *src, *mask;
|
||||||
|
Memdata *scrd;
|
||||||
int m;
|
int m;
|
||||||
|
|
||||||
if(hwaccel == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
scr = &vgascreen[0];
|
scr = &vgascreen[0];
|
||||||
|
scrd = scr->gscreendata;
|
||||||
|
if(scr->gscreen == nil || scrd == nil)
|
||||||
|
return 0;
|
||||||
if((dst = par->dst) == nil || dst->data == nil)
|
if((dst = par->dst) == nil || dst->data == nil)
|
||||||
return 0;
|
return 0;
|
||||||
if((src=par->src) == nil || src->data == nil)
|
if((src = par->src) && src->data == nil)
|
||||||
return 0;
|
src = nil;
|
||||||
if((mask=par->mask) == nil || mask->data == nil)
|
if((mask = par->mask) && mask->data == nil)
|
||||||
return 0;
|
mask = nil;
|
||||||
|
|
||||||
if(scr->cur == &swcursor){
|
if(scr->cur == &swcursor){
|
||||||
/*
|
if(dst->data->bdata == scrd->bdata)
|
||||||
* always calling swcursorhide here doesn't cure
|
|
||||||
* leaving cursor tracks nor failing to refresh menus
|
|
||||||
* with the latest libmemdraw/draw.c.
|
|
||||||
*/
|
|
||||||
if(dst->data->bdata == gscreendata.bdata)
|
|
||||||
swcursoravoid(par->r);
|
swcursoravoid(par->r);
|
||||||
if(src->data->bdata == gscreendata.bdata)
|
if(src && src->data->bdata == scrd->bdata)
|
||||||
swcursoravoid(par->sr);
|
swcursoravoid(par->sr);
|
||||||
if(mask->data->bdata == gscreendata.bdata)
|
if(mask && mask->data->bdata == scrd->bdata)
|
||||||
swcursoravoid(par->mr);
|
swcursoravoid(par->mr);
|
||||||
}
|
}
|
||||||
|
if(!hwaccel || scr->softscreen)
|
||||||
if(dst->data->bdata != gscreendata.bdata)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
if(dst->data->bdata != scrd->bdata || src == nil || mask == nil)
|
||||||
if(scr->fill==nil && scr->scroll==nil)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -442,36 +472,62 @@ blankscreen(int blank)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static char*
|
||||||
vgalinearpciid(VGAscr *scr, int vid, int did)
|
vgalinearaddr0(VGAscr *scr, uint32_t paddr, int size)
|
||||||
{
|
{
|
||||||
Pcidev *p;
|
int x, nsize;
|
||||||
|
uint32_t npaddr;
|
||||||
|
|
||||||
p = nil;
|
/*
|
||||||
while((p = pcimatch(p, vid, 0)) != nil){
|
* new approach. instead of trying to resize this
|
||||||
if(p->ccrb != 3) /* video card */
|
* later, let's assume that we can just allocate the
|
||||||
continue;
|
* entire window to start with.
|
||||||
if(did != 0 && p->did != did)
|
*/
|
||||||
continue;
|
if(scr->paddr == paddr && size <= scr->apsize)
|
||||||
break;
|
return nil;
|
||||||
}
|
|
||||||
if(p == nil)
|
|
||||||
error("pci video card not found");
|
|
||||||
|
|
||||||
scr->pci = p;
|
if(scr->paddr){
|
||||||
vgalinearpci(scr);
|
/*
|
||||||
|
* could call vunmap and vmap,
|
||||||
|
* but worried about dangling pointers in devdraw
|
||||||
|
*/
|
||||||
|
return "cannot grow vga frame buffer";
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/* round to page boundary, just in case */
|
||||||
vgalinearpci(VGAscr *scr)
|
x = paddr&(BY2PG-1);
|
||||||
|
npaddr = paddr-x;
|
||||||
|
nsize = PGROUND(size+x);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't bother trying to map more than 4000x4000x32 = 64MB.
|
||||||
|
* We only have a 256MB window.
|
||||||
|
*/
|
||||||
|
if(nsize > 64*MB)
|
||||||
|
nsize = 64*MB;
|
||||||
|
scr->vaddr = vmap(npaddr, nsize);
|
||||||
|
if(scr->vaddr == 0)
|
||||||
|
return "cannot allocate vga frame buffer";
|
||||||
|
|
||||||
|
patwc(scr->vaddr, nsize);
|
||||||
|
|
||||||
|
scr->vaddr = (char*)scr->vaddr+x;
|
||||||
|
scr->paddr = paddr;
|
||||||
|
scr->apsize = nsize;
|
||||||
|
|
||||||
|
mtrr(npaddr, nsize, "wc");
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
vgalinearpci0(VGAscr *scr)
|
||||||
{
|
{
|
||||||
uint32_t paddr;
|
uint32_t paddr;
|
||||||
int i, size, best;
|
int i, size, best;
|
||||||
Pcidev *p;
|
Pcidev *p;
|
||||||
|
|
||||||
p = scr->pci;
|
p = scr->pci;
|
||||||
if(p == nil)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan for largest memory region on card.
|
* Scan for largest memory region on card.
|
||||||
|
@ -500,261 +556,182 @@ vgalinearpci(VGAscr *scr)
|
||||||
if(best >= 0){
|
if(best >= 0){
|
||||||
paddr = p->mem[best].bar & ~0x0F;
|
paddr = p->mem[best].bar & ~0x0F;
|
||||||
size = p->mem[best].size;
|
size = p->mem[best].size;
|
||||||
vgalinearaddr(scr, paddr, size);
|
return vgalinearaddr0(scr, paddr, size);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
error("no video memory found on pci card");
|
return "no video memory found on pci card";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vgalinearpci(VGAscr *scr)
|
||||||
|
{
|
||||||
|
char *err;
|
||||||
|
|
||||||
|
if(scr->pci == nil)
|
||||||
|
return;
|
||||||
|
if((err = vgalinearpci0(scr)) != nil)
|
||||||
|
error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
vgalinearaddr(VGAscr *scr, uint32_t paddr, int size)
|
vgalinearaddr(VGAscr *scr, uint32_t paddr, int size)
|
||||||
{
|
{
|
||||||
int x, nsize;
|
char *err;
|
||||||
uint32_t npaddr;
|
|
||||||
|
|
||||||
/*
|
if((err = vgalinearaddr0(scr, paddr, size)) != nil)
|
||||||
* new approach. instead of trying to resize this
|
error(err);
|
||||||
* later, let's assume that we can just allocate the
|
|
||||||
* entire window to start with.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(scr->paddr == paddr && size <= scr->apsize)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(scr->paddr){
|
|
||||||
/*
|
|
||||||
* could call vunmap and vmap,
|
|
||||||
* but worried about dangling pointers in devdraw
|
|
||||||
*/
|
|
||||||
error("cannot grow vga frame buffer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* round to page boundary, just in case */
|
static char*
|
||||||
x = paddr&(4*KiB-1);
|
bootmapfb(VGAscr *scr, uint32_t pa, uint32_t sz)
|
||||||
npaddr = paddr-x;
|
|
||||||
nsize = ROUNDUP(size+x, 4*KiB);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Don't bother trying to map more than 4000x4000x32 = 64MB.
|
|
||||||
* We only have a 256MB window.
|
|
||||||
*/
|
|
||||||
if(nsize > 64*MB)
|
|
||||||
nsize = 64*MB;
|
|
||||||
scr->vaddr = vmap(npaddr, nsize);
|
|
||||||
if(scr->vaddr == 0)
|
|
||||||
error("cannot allocate vga frame buffer");
|
|
||||||
scr->vaddr = (char*)scr->vaddr+x;
|
|
||||||
scr->paddr = paddr;
|
|
||||||
scr->apsize = nsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Software cursor.
|
|
||||||
*/
|
|
||||||
int swvisible; /* is the cursor visible? */
|
|
||||||
int swenabled; /* is the cursor supposed to be on the screen? */
|
|
||||||
Memimage* swback; /* screen under cursor */
|
|
||||||
Memimage* swimg; /* cursor image */
|
|
||||||
Memimage* swmask; /* cursor mask */
|
|
||||||
Memimage* swimg1;
|
|
||||||
Memimage* swmask1;
|
|
||||||
|
|
||||||
Point swoffset;
|
|
||||||
Rectangle swrect; /* screen rectangle in swback */
|
|
||||||
Point swpt; /* desired cursor location */
|
|
||||||
Point swvispt; /* actual cursor location */
|
|
||||||
int swvers; /* incremented each time cursor image changes */
|
|
||||||
int swvisvers; /* the version on the screen */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* called with drawlock locked for us, most of the time.
|
|
||||||
* kernel prints at inopportune times might mean we don't
|
|
||||||
* hold the lock, but memimagedraw is now reentrant so
|
|
||||||
* that should be okay: worst case we get cursor droppings.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
swcursorhide(void)
|
|
||||||
{
|
{
|
||||||
if(swvisible == 0)
|
uint32_t start, end;
|
||||||
return;
|
Pcidev *p;
|
||||||
if(swback == nil)
|
int i;
|
||||||
return;
|
|
||||||
swvisible = 0;
|
for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
|
||||||
memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
|
for(i=0; i<nelem(p->mem); i++){
|
||||||
flushmemscreen(swrect);
|
if(p->mem[i].bar & 1)
|
||||||
|
continue;
|
||||||
|
start = p->mem[i].bar & ~0xF;
|
||||||
|
end = start + p->mem[i].size;
|
||||||
|
if(pa == start && (pa + sz) <= end){
|
||||||
|
scr->pci = p;
|
||||||
|
return vgalinearpci0(scr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vgalinearaddr0(scr, pa, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
char*
|
||||||
swcursoravoid(Rectangle r)
|
rgbmask2chan(char *buf, int depth, uint32_t rm, uint32_t gm, uint32_t bm)
|
||||||
{
|
{
|
||||||
if(swvisible && rectXrect(r, swrect))
|
uint32_t m[4], dm; /* r,g,b,x */
|
||||||
swcursorhide();
|
char tmp[32];
|
||||||
}
|
int c, n;
|
||||||
|
|
||||||
void
|
dm = 1<<depth-1;
|
||||||
swcursordraw(void)
|
dm |= dm-1;
|
||||||
{
|
|
||||||
if(swvisible)
|
m[0] = rm & dm;
|
||||||
return;
|
m[1] = gm & dm;
|
||||||
if(swenabled == 0)
|
m[2] = bm & dm;
|
||||||
return;
|
m[3] = (~(m[0] | m[1] | m[2])) & dm;
|
||||||
if(swback == nil || swimg1 == nil || swmask1 == nil)
|
|
||||||
return;
|
buf[0] = 0;
|
||||||
assert(!canqlock(&drawlock));
|
Next:
|
||||||
swvispt = swpt;
|
for(c=0; c<4; c++){
|
||||||
swvisvers = swvers;
|
for(n = 0; m[c] & (1<<n); n++)
|
||||||
swrect = rectaddpt(Rect(0,0,16,16), swvispt);
|
;
|
||||||
memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
|
if(n){
|
||||||
memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
|
m[0] >>= n, m[1] >>= n, m[2] >>= n, m[3] >>= n;
|
||||||
flushmemscreen(swrect);
|
snprint(tmp, sizeof tmp, "%c%d%s", "rgbx"[c], n, buf);
|
||||||
swvisible = 1;
|
strcpy(buf, tmp);
|
||||||
|
goto Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to lock drawlock for ourselves.
|
* called early on boot to attach to framebuffer
|
||||||
|
* setup by bootloader/firmware or plan9.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
swenable(VGAscr *v)
|
bootscreeninit(void)
|
||||||
{
|
{
|
||||||
swenabled = 1;
|
static Memdata md;
|
||||||
if(canqlock(&drawlock)){
|
|
||||||
swcursordraw();
|
|
||||||
qunlock(&drawlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
swdisable(VGAscr *v)
|
|
||||||
{
|
|
||||||
swenabled = 0;
|
|
||||||
if(canqlock(&drawlock)){
|
|
||||||
swcursorhide();
|
|
||||||
qunlock(&drawlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
swload(VGAscr *v, Cursor *curs)
|
|
||||||
{
|
|
||||||
unsigned char *ip, *mp;
|
|
||||||
int i, j, set, clr;
|
|
||||||
|
|
||||||
if(!swimg || !swmask || !swimg1 || !swmask1)
|
|
||||||
return;
|
|
||||||
/*
|
|
||||||
* Build cursor image and mask.
|
|
||||||
* Image is just the usual cursor image
|
|
||||||
* but mask is a transparent alpha mask.
|
|
||||||
*
|
|
||||||
* The 16x16x8 memimages do not have
|
|
||||||
* padding at the end of their scan lines.
|
|
||||||
*/
|
|
||||||
ip = byteaddr(swimg, ZP);
|
|
||||||
mp = byteaddr(swmask, ZP);
|
|
||||||
for(i=0; i<32; i++){
|
|
||||||
set = curs->set[i];
|
|
||||||
clr = curs->clr[i];
|
|
||||||
for(j=0x80; j; j>>=1){
|
|
||||||
*ip++ = set&j ? 0x00 : 0xFF;
|
|
||||||
*mp++ = (clr|set)&j ? 0xFF : 0x00;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
swoffset = curs->offset;
|
|
||||||
swvers++;
|
|
||||||
memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
|
|
||||||
memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
swmove(VGAscr *v, Point p)
|
|
||||||
{
|
|
||||||
swpt = addpt(p, swoffset);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
swcursorclock(void)
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
if(!swenabled)
|
|
||||||
return;
|
|
||||||
if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
|
|
||||||
return;
|
|
||||||
|
|
||||||
x = splhi();
|
|
||||||
if(swenabled)
|
|
||||||
if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
|
|
||||||
if(canqlock(&drawlock)){
|
|
||||||
swcursorhide();
|
|
||||||
swcursordraw();
|
|
||||||
qunlock(&drawlock);
|
|
||||||
}
|
|
||||||
splx(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
swcursorinit(void)
|
|
||||||
{
|
|
||||||
static int init, warned;
|
|
||||||
VGAscr *scr;
|
VGAscr *scr;
|
||||||
didswcursorinit = 1;
|
int x, y, z;
|
||||||
|
uint32_t chan, pa, sz;
|
||||||
|
char *s, *p, *err;
|
||||||
|
|
||||||
|
/* *bootscreen=WIDTHxHEIGHTxDEPTH CHAN PA [SZ] */
|
||||||
|
s = getconf("*bootscreen");
|
||||||
|
if(s == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
x = strtoul(s, &s, 0);
|
||||||
|
if(x == 0 || *s++ != 'x')
|
||||||
|
return;
|
||||||
|
|
||||||
|
y = strtoul(s, &s, 0);
|
||||||
|
if(y == 0 || *s++ != 'x')
|
||||||
|
return;
|
||||||
|
|
||||||
|
z = strtoul(s, &s, 0);
|
||||||
|
if(*s != ' ')
|
||||||
|
return;
|
||||||
|
if((p = strchr(++s, ' ')) == nil)
|
||||||
|
return;
|
||||||
|
*p = 0;
|
||||||
|
chan = strtochan(s);
|
||||||
|
*p = ' ';
|
||||||
|
if(chan == 0 || chantodepth(chan) != z)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sz = 0;
|
||||||
|
pa = strtoul(p+1, &s, 0);
|
||||||
|
if(pa == 0)
|
||||||
|
return;
|
||||||
|
if(*s++ == ' ')
|
||||||
|
sz = strtoul(s, nil, 0);
|
||||||
|
if(sz < x * y * (z+7)/8)
|
||||||
|
sz = x * y * (z+7)/8;
|
||||||
|
|
||||||
|
/* map framebuffer */
|
||||||
scr = &vgascreen[0];
|
scr = &vgascreen[0];
|
||||||
if(scr==nil || scr->gscreen==nil)
|
if((err = bootmapfb(scr, pa, sz)) != nil){
|
||||||
return;
|
print("bootmapfb: %s\n", err);
|
||||||
|
|
||||||
if(scr->dev == nil || scr->dev->linear == nil){
|
|
||||||
if(!warned){
|
|
||||||
jehanne_print("cannot use software cursor on non-linear vga screen\n");
|
|
||||||
warned = 1;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(swback){
|
if(memimageinit() < 0)
|
||||||
freememimage(swback);
|
|
||||||
freememimage(swmask);
|
|
||||||
freememimage(swmask1);
|
|
||||||
freememimage(swimg);
|
|
||||||
freememimage(swimg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
|
|
||||||
swmask = allocmemimage(Rect(0,0,16,16), GREY8);
|
|
||||||
swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
|
||||||
swimg = allocmemimage(Rect(0,0,16,16), GREY8);
|
|
||||||
swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
|
||||||
if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
|
|
||||||
jehanne_print("software cursor: allocmemimage fails");
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
md.ref = 1;
|
||||||
|
md.bdata = scr->vaddr;
|
||||||
|
gscreen = allocmemimaged(Rect(0,0,x,y), chan, &md);
|
||||||
|
if(gscreen == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
scr->palettedepth = 6; /* default */
|
||||||
|
scr->memdefont = getmemdefont();
|
||||||
|
scr->gscreen = gscreen;
|
||||||
|
scr->gscreendata = gscreen->data;
|
||||||
|
scr->softscreen = 0;
|
||||||
|
scr->useflush = 0;
|
||||||
|
scr->dev = nil;
|
||||||
|
|
||||||
|
physgscreenr = gscreen->r;
|
||||||
|
|
||||||
|
vgaimageinit(chan);
|
||||||
|
vgascreenwin(scr);
|
||||||
|
|
||||||
|
/* turn mouse cursor on */
|
||||||
|
swcursorinit();
|
||||||
|
scr->cur = &swcursor;
|
||||||
|
scr->cur->enable(scr);
|
||||||
|
cursoron();
|
||||||
|
|
||||||
|
sys->monitor = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memfillcolor(swmask, DOpaque);
|
/*
|
||||||
memfillcolor(swmask1, DOpaque);
|
* called from devvga when the framebuffer is setup
|
||||||
memfillcolor(swimg, DBlack);
|
* to set *bootscreen= that can be passed on to a
|
||||||
memfillcolor(swimg1, DBlack);
|
* new kernel on reboot.
|
||||||
if(!init){
|
*/
|
||||||
init = 1;
|
void
|
||||||
addclock0link(swcursorclock, 10);
|
bootscreenconf(VGAscr *scr)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VGAcur swcursor =
|
|
||||||
{
|
{
|
||||||
"soft",
|
char conf[100], chan[30];
|
||||||
swenable,
|
|
||||||
swdisable,
|
|
||||||
swload,
|
|
||||||
swmove,
|
|
||||||
};
|
|
||||||
|
|
||||||
// A bit hokey but it saves dumbness in the build tool and other code.
|
|
||||||
VGAcur vgavesacur =
|
|
||||||
{
|
|
||||||
"vesa",
|
|
||||||
swenable,
|
|
||||||
swdisable,
|
|
||||||
swload,
|
|
||||||
swmove,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
conf[0] = '\0';
|
||||||
|
if(scr != nil && scr->paddr != 0 && scr->gscreen != nil)
|
||||||
|
snprint(conf, sizeof(conf), "%dx%dx%d %s %#p %d\n",
|
||||||
|
scr->gscreen->r.max.x, scr->gscreen->r.max.y,
|
||||||
|
scr->gscreen->depth, chantostr(chan, scr->gscreen->chan),
|
||||||
|
scr->paddr, scr->apsize);
|
||||||
|
ksetenv("*bootscreen", conf, 1);
|
||||||
|
}
|
||||||
|
|
|
@ -1,21 +1,13 @@
|
||||||
/*
|
|
||||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
||||||
* terms in the LICENSE file found in the top-level directory of this
|
|
||||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
||||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
|
||||||
* in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct Cursor Cursor;
|
typedef struct Cursor Cursor;
|
||||||
typedef struct Cursorinfo Cursorinfo;
|
typedef struct Cursorinfo Cursorinfo;
|
||||||
struct Cursorinfo {
|
struct Cursorinfo {
|
||||||
Cursor c;
|
Cursor;
|
||||||
Lock l;
|
Lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* devmouse.c */
|
/* devmouse.c */
|
||||||
extern void mousetrack(int, int, int, int);
|
extern void mousetrack(int, int, int, uint32_t);
|
||||||
|
extern void absmousetrack(int, int, int, uint32_t);
|
||||||
extern Point mousexy(void);
|
extern Point mousexy(void);
|
||||||
|
|
||||||
extern void mouseaccelerate(int);
|
extern void mouseaccelerate(int);
|
||||||
|
@ -61,8 +53,8 @@ enum {
|
||||||
#define vgai(port) inb(port)
|
#define vgai(port) inb(port)
|
||||||
#define vgao(port, data) outb(port, data)
|
#define vgao(port, data) outb(port, data)
|
||||||
|
|
||||||
extern int vgaxi(int32_t, unsigned char);
|
extern int vgaxi(int32_t port, uint8_t index);
|
||||||
extern int vgaxo(int32_t, unsigned char, unsigned char);
|
extern int vgaxo(int32_t port, uint8_t index, uint8_t data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
|
@ -103,12 +95,12 @@ struct VGAscr {
|
||||||
Pcidev* pci;
|
Pcidev* pci;
|
||||||
|
|
||||||
VGAcur* cur;
|
VGAcur* cur;
|
||||||
uint32_t storage;
|
uintptr_t storage;
|
||||||
Cursor Cursor;
|
Cursor;
|
||||||
|
|
||||||
int useflush;
|
int useflush;
|
||||||
|
|
||||||
uint32_t paddr; /* frame buffer */
|
uintptr_t paddr; /* frame buffer */
|
||||||
void* vaddr;
|
void* vaddr;
|
||||||
int apsize;
|
int apsize;
|
||||||
|
|
||||||
|
@ -126,8 +118,8 @@ struct VGAscr {
|
||||||
int (*scroll)(VGAscr*, Rectangle, Rectangle);
|
int (*scroll)(VGAscr*, Rectangle, Rectangle);
|
||||||
void (*blank)(VGAscr*, int);
|
void (*blank)(VGAscr*, int);
|
||||||
uint32_t id; /* internal identifier for driver use */
|
uint32_t id; /* internal identifier for driver use */
|
||||||
int isblank;
|
|
||||||
int overlayinit;
|
int overlayinit;
|
||||||
|
int softscreen;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern VGAscr vgascreen[];
|
extern VGAscr vgascreen[];
|
||||||
|
@ -139,21 +131,26 @@ enum {
|
||||||
/* mouse.c */
|
/* mouse.c */
|
||||||
extern void mousectl(Cmdbuf*);
|
extern void mousectl(Cmdbuf*);
|
||||||
extern void mouseresize(void);
|
extern void mouseresize(void);
|
||||||
|
extern void mouseredraw(void);
|
||||||
|
|
||||||
/* screen.c */
|
/* screen.c */
|
||||||
extern int hwaccel; /* use hw acceleration; default on */
|
extern int hwaccel; /* use hw acceleration */
|
||||||
extern int hwblank; /* use hw blanking; default on */
|
extern int hwblank; /* use hw blanking */
|
||||||
extern int panning; /* use virtual screen panning; default off */
|
extern int panning; /* use virtual screen panning */
|
||||||
extern void addvgaseg(char*, uint32_t, uint32_t);
|
extern void addvgaseg(char*, uint32_t, uint32_t);
|
||||||
extern unsigned char* attachscreen(Rectangle*, uint32_t*, int*, int*, int*);
|
extern uint8_t* attachscreen(Rectangle*, uint32_t*, int*, int*, int*);
|
||||||
extern void flushmemscreen(Rectangle);
|
extern void flushmemscreen(Rectangle);
|
||||||
extern int cursoron(int);
|
extern void cursoron(void);
|
||||||
extern void cursoroff(int);
|
extern void cursoroff(void);
|
||||||
extern void setcursor(Cursor*);
|
extern void setcursor(Cursor*);
|
||||||
extern int screensize(int, int, int, uint32_t);
|
extern int screensize(int, int, int, uint32_t);
|
||||||
extern int screenaperture(int, int);
|
extern int screenaperture(int, int);
|
||||||
extern Rectangle physgscreenr; /* actual monitor size */
|
extern Rectangle physgscreenr; /* actual monitor size */
|
||||||
extern void blankscreen(int);
|
extern void blankscreen(int);
|
||||||
|
extern char* rgbmask2chan(char *buf, int depth, uint32_t rm, uint32_t gm, uint32_t bm);
|
||||||
|
|
||||||
|
extern void bootscreeninit(void);
|
||||||
|
extern void bootscreenconf(VGAscr*);
|
||||||
|
|
||||||
extern VGAcur swcursor;
|
extern VGAcur swcursor;
|
||||||
extern void swcursorinit(void);
|
extern void swcursorinit(void);
|
||||||
|
@ -165,22 +162,25 @@ extern void swcursorunhide(void);
|
||||||
extern void deletescreenimage(void);
|
extern void deletescreenimage(void);
|
||||||
extern void resetscreenimage(void);
|
extern void resetscreenimage(void);
|
||||||
extern int drawhasclients(void);
|
extern int drawhasclients(void);
|
||||||
extern uint32_t blanktime;
|
|
||||||
extern void setscreenimageclipr(Rectangle);
|
extern void setscreenimageclipr(Rectangle);
|
||||||
extern void drawflush(void);
|
extern void drawflush(void);
|
||||||
extern int drawidletime(void);
|
|
||||||
extern QLock drawlock;
|
extern QLock drawlock;
|
||||||
|
|
||||||
/* vga.c */
|
/* vga.c */
|
||||||
extern void vgascreenwin(VGAscr*);
|
extern void vgascreenwin(VGAscr*);
|
||||||
extern void vgaimageinit(uint32_t);
|
extern void vgaimageinit(uint32_t);
|
||||||
extern void vgalinearpciid(VGAscr*, int, int);
|
|
||||||
extern void vgalinearpci(VGAscr*);
|
extern void vgalinearpci(VGAscr*);
|
||||||
extern void vgalinearaddr(VGAscr*, uint32_t, int);
|
extern void vgalinearaddr(VGAscr*, uint32_t, int);
|
||||||
|
|
||||||
extern void drawblankscreen(int);
|
|
||||||
extern void vgablank(VGAscr*, int);
|
extern void vgablank(VGAscr*, int);
|
||||||
|
|
||||||
extern Lock vgascreenlock;
|
extern Lock vgascreenlock;
|
||||||
|
|
||||||
#define ishwimage(i) (vgascreen[0].gscreendata && (i)->data->bdata == vgascreen[0].gscreendata->bdata)
|
#define ishwimage(i) (vgascreen[0].gscreendata && (i)->data->bdata == vgascreen[0].gscreendata->bdata)
|
||||||
|
|
||||||
|
/* swcursor.c */
|
||||||
|
void swcursorhide(void);
|
||||||
|
void swcursoravoid(Rectangle);
|
||||||
|
void swcursordraw(Point);
|
||||||
|
void swcursorload(Cursor *);
|
||||||
|
void swcursorinit(void);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "../port/error.h"
|
#include "../port/error.h"
|
||||||
#include "../port/sd.h"
|
#include "../port/sd.h"
|
||||||
#include "../386/fis.h"
|
#include "fis.h"
|
||||||
#include "../port/sdfis.h"
|
#include "../port/sdfis.h"
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
#include "../port/led.h"
|
#include "../port/led.h"
|
||||||
|
|
|
@ -2185,7 +2185,7 @@ atadisable(SDev *sdev)
|
||||||
if (ctlr->idisable)
|
if (ctlr->idisable)
|
||||||
ctlr->idisable(ctlr);
|
ctlr->idisable(ctlr);
|
||||||
jehanne_snprint(name, sizeof(name), "%s (%s)", sdev->name, sdev->ifc->name);
|
jehanne_snprint(name, sizeof(name), "%s (%s)", sdev->name, sdev->ifc->name);
|
||||||
intrdisable(ctlr->vector);
|
intrdisable(ctlr->irq, atainterrupt, ctlr, ctlr->tbdf, name);
|
||||||
if (ctlr->bmiba) {
|
if (ctlr->bmiba) {
|
||||||
if (ctlr->pcidev)
|
if (ctlr->pcidev)
|
||||||
pciclrbme(ctlr->pcidev);
|
pciclrbme(ctlr->pcidev);
|
||||||
|
|
|
@ -1471,7 +1471,7 @@ iadisable(SDev *s)
|
||||||
ilock(c);
|
ilock(c);
|
||||||
ahcidisable(c->hba);
|
ahcidisable(c->hba);
|
||||||
jehanne_snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
|
jehanne_snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
|
||||||
intrdisable(c->vector);
|
intrdisable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
|
||||||
c->enabled = 0;
|
c->enabled = 0;
|
||||||
iunlock(c);
|
iunlock(c);
|
||||||
return 1;
|
return 1;
|
|
@ -475,4 +475,3 @@ again:
|
||||||
|
|
||||||
return rlen;
|
return rlen;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
|
|
||||||
#include "apic.h"
|
|
||||||
#include "sipi.h"
|
|
||||||
|
|
||||||
#define SIPIHANDLER (KZERO+0x3000)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parameters are passed to the bootstrap code via a vector
|
|
||||||
* in low memory indexed by the APIC number of the processor.
|
|
||||||
* The layout, size, and location have to be kept in sync
|
|
||||||
* with the handler code in l64sipi.s.
|
|
||||||
*/
|
|
||||||
typedef struct Sipi Sipi;
|
|
||||||
struct Sipi {
|
|
||||||
uint32_t pml4;
|
|
||||||
uint32_t _4_;
|
|
||||||
uintptr_t stack;
|
|
||||||
Mach* mach;
|
|
||||||
uintptr_t pc;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
sipi(void)
|
|
||||||
{
|
|
||||||
Lapic *apic;
|
|
||||||
Mach *mach;
|
|
||||||
Sipi *sipi;
|
|
||||||
int apicno, i, nproc;
|
|
||||||
uint8_t *sipiptr;
|
|
||||||
uintmem sipipa;
|
|
||||||
uint8_t *alloc, *p;
|
|
||||||
extern void squidboy(int);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Move the startup code into place,
|
|
||||||
* must be aligned properly.
|
|
||||||
*/
|
|
||||||
sipipa = mmuphysaddr(SIPIHANDLER);
|
|
||||||
if((sipipa & (4*KiB - 1)) || sipipa > (1*MiB - 2*4*KiB))
|
|
||||||
return;
|
|
||||||
sipiptr = UINT2PTR(SIPIHANDLER);
|
|
||||||
jehanne_memmove(sipiptr, sipihandler, sizeof(sipihandler));
|
|
||||||
jehanne_memset(sipiptr+4*KiB, 0, sizeof(Sipi)*Napic);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Notes:
|
|
||||||
* The Universal Startup Algorithm described in the MP Spec. 1.4.
|
|
||||||
* The data needed per-processor is the sum of the stack, page
|
|
||||||
* table pages, vsvm page and the Mach page. The layout is similar
|
|
||||||
* to that described in data.h for the bootstrap processor, but
|
|
||||||
* with any unused space elided.
|
|
||||||
*/
|
|
||||||
nproc = 0;
|
|
||||||
for(apicno = 0; apicno < Napic; apicno++){
|
|
||||||
apic = lapiclookup(apicno);
|
|
||||||
if(apic == nil || !apic->useable || apic->machno == 0)
|
|
||||||
continue;
|
|
||||||
if(++nproc >= MACHMAX){
|
|
||||||
jehanne_print("sipi: MACHMAX too small, need %d\n", nproc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sipi = &((Sipi*)(sipiptr+4*KiB))[apicno];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: for now, share the page tables with the
|
|
||||||
* bootstrap processor, until this code is worked out,
|
|
||||||
* so only the Mach and stack portions are used below.
|
|
||||||
*/
|
|
||||||
alloc = jehanne_mallocalign(MACHSTKSZ+4*PTSZ+4*KiB+MACHSZ, 4096, 0, 0);
|
|
||||||
if(alloc == nil)
|
|
||||||
continue;
|
|
||||||
jehanne_memset(alloc, 0, MACHSTKSZ+4*PTSZ+4*KiB+MACHSZ);
|
|
||||||
p = alloc+MACHSTKSZ;
|
|
||||||
|
|
||||||
sipi->pml4 = cr3get();
|
|
||||||
sipi->stack = PTR2UINT(p);
|
|
||||||
|
|
||||||
p += 4*PTSZ+4*KiB;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Committed. If the AP startup fails, can't safely
|
|
||||||
* release the resources, who knows what mischief
|
|
||||||
* the AP is up to. Perhaps should try to put it
|
|
||||||
* back into the INIT state?
|
|
||||||
*/
|
|
||||||
mach = (Mach*)p;
|
|
||||||
sipi->mach = mach;
|
|
||||||
mach->machno = apic->machno; /* NOT one-to-one... */
|
|
||||||
mach->splpc = PTR2UINT(squidboy);
|
|
||||||
sipi->pc = mach->splpc;
|
|
||||||
mach->apicno = apicno;
|
|
||||||
mach->stack = PTR2UINT(alloc);
|
|
||||||
mach->vsvm = alloc+MACHSTKSZ+4*PTSZ;
|
|
||||||
mach->pml4 = m->pml4;
|
|
||||||
|
|
||||||
p = KADDR(0x467);
|
|
||||||
*p++ = sipipa;
|
|
||||||
*p++ = sipipa>>8;
|
|
||||||
*p++ = 0;
|
|
||||||
*p = 0;
|
|
||||||
|
|
||||||
nvramwrite(0x0f, 0x0a);
|
|
||||||
lapicsipi(apicno, sipipa);
|
|
||||||
|
|
||||||
for(i = 0; i < 1000; i++){
|
|
||||||
if(mach->splpc == 0)
|
|
||||||
break;
|
|
||||||
millidelay(5);
|
|
||||||
}
|
|
||||||
nvramwrite(0x0f, 0x00);
|
|
||||||
|
|
||||||
DBG("apicno%d: machno %d mach %#p (%#p) %dMHz\n",
|
|
||||||
apicno, mach->machno,
|
|
||||||
mach, sys->machptr[mach->machno],
|
|
||||||
mach->cpumhz);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
#include "u.h"
|
||||||
|
#include "../port/lib.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "ureg.h"
|
||||||
|
|
||||||
|
#include "mp.h"
|
||||||
|
|
||||||
|
extern void initialize_processor(void);
|
||||||
|
|
||||||
|
static void
|
||||||
|
squidboy(Apic* apic)
|
||||||
|
{
|
||||||
|
initialize_processor();
|
||||||
|
mmuinit();
|
||||||
|
cpuidentify();
|
||||||
|
cpuidprint();
|
||||||
|
syncclock();
|
||||||
|
active.machs[m->machno] = 1;
|
||||||
|
apic->online = 1;
|
||||||
|
m->online = 1;
|
||||||
|
lapicinit(apic);
|
||||||
|
lapiconline();
|
||||||
|
timersinit();
|
||||||
|
schedinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mpstartap(Apic* apic)
|
||||||
|
{
|
||||||
|
uintptr_t *apbootp, *pml4, *pdp0;
|
||||||
|
Segdesc *gdt;
|
||||||
|
Mach *mach;
|
||||||
|
uint8_t *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialise the AP page-tables and Mach structure.
|
||||||
|
* Xspanalloc will panic if an allocation can't be made.
|
||||||
|
*/
|
||||||
|
p = xspanalloc(2*PTSZ + BY2PG + MACHSIZE, BY2PG, 0);
|
||||||
|
pml4 = (uintptr*)p;
|
||||||
|
p += PTSZ;
|
||||||
|
pdp0 = (uintptr*)p;
|
||||||
|
p += PTSZ;
|
||||||
|
gdt = (Segdesc*)p;
|
||||||
|
p += BY2PG;
|
||||||
|
mach = (Mach*)p;
|
||||||
|
|
||||||
|
memset(pml4, 0, PTSZ);
|
||||||
|
memset(pdp0, 0, PTSZ);
|
||||||
|
memset(gdt, 0, BY2PG);
|
||||||
|
memset(mach, 0, MACHSIZE);
|
||||||
|
|
||||||
|
mach->machno = apic->machno;
|
||||||
|
mach->pml4 = pml4;
|
||||||
|
mach->gdt = gdt; /* filled by mmuinit */
|
||||||
|
MACHP(mach->machno) = mach;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* map KZERO (note that we share the KZERO (and VMAP)
|
||||||
|
* PDP between processors.
|
||||||
|
*/
|
||||||
|
pml4[PTLX(KZERO, 3)] = MACHP(0)->pml4[PTLX(KZERO, 3)];
|
||||||
|
pml4[PTLX(VMAP, 3)] = MACHP(0)->pml4[PTLX(VMAP, 3)];
|
||||||
|
|
||||||
|
/* double map */
|
||||||
|
pml4[0] = PADDR(pdp0) | PTEWRITE|PTEVALID;
|
||||||
|
pdp0[0] = *mmuwalk(pml4, KZERO, 2, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tell the AP where its kernel vector and pdb are.
|
||||||
|
* The offsets are known in the AP bootstrap code.
|
||||||
|
*/
|
||||||
|
apbootp = (uintptr*)(APBOOTSTRAP+0x08);
|
||||||
|
apbootp[0] = (uintptr)squidboy; /* assembler jumps here eventually */
|
||||||
|
apbootp[1] = (uintptr)PADDR(pml4);
|
||||||
|
apbootp[2] = (uintptr)apic;
|
||||||
|
apbootp[3] = (uintptr)mach;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Universal Startup Algorithm.
|
||||||
|
*/
|
||||||
|
p = KADDR(0x467); /* warm-reset vector */
|
||||||
|
*p++ = PADDR(APBOOTSTRAP);
|
||||||
|
*p++ = PADDR(APBOOTSTRAP)>>8;
|
||||||
|
i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16;
|
||||||
|
/* code assumes i==0 */
|
||||||
|
if(i != 0)
|
||||||
|
print("mp: bad APBOOTSTRAP\n");
|
||||||
|
*p++ = i;
|
||||||
|
*p = i>>8;
|
||||||
|
coherence();
|
||||||
|
|
||||||
|
nvramwrite(0x0F, 0x0A); /* shutdown code: warm reset upon init ipi */
|
||||||
|
lapicstartap(apic, PADDR(APBOOTSTRAP));
|
||||||
|
for(i = 0; i < 100000; i++){
|
||||||
|
if(arch->fastclock == tscticks)
|
||||||
|
cycles(&m->tscticks); /* for ap's syncclock(); */
|
||||||
|
if(apic->online)
|
||||||
|
break;
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
nvramwrite(0x0F, 0x00);
|
||||||
|
}
|
|
@ -46,7 +46,6 @@ static void
|
||||||
noted(Ureg* cur, uintptr_t arg0)
|
noted(Ureg* cur, uintptr_t arg0)
|
||||||
{
|
{
|
||||||
NFrame *nf;
|
NFrame *nf;
|
||||||
Note note;
|
|
||||||
Ureg *nur;
|
Ureg *nur;
|
||||||
|
|
||||||
qlock(&up->debug);
|
qlock(&up->debug);
|
||||||
|
@ -55,11 +54,13 @@ noted(Ureg* cur, uintptr_t arg0)
|
||||||
pprint("suicide: call to noted when not notified\n");
|
pprint("suicide: call to noted when not notified\n");
|
||||||
pexit("Suicide", 0);
|
pexit("Suicide", 0);
|
||||||
}
|
}
|
||||||
|
awake_gc_note(up);
|
||||||
up->notified = 0;
|
up->notified = 0;
|
||||||
fpunoted();
|
|
||||||
|
|
||||||
nf = up->ureg;
|
nf = up->ureg;
|
||||||
|
|
||||||
|
up->fpstate &= ~FPillegal;
|
||||||
|
|
||||||
/* sanity clause */
|
/* sanity clause */
|
||||||
if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
|
if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
|
||||||
qunlock(&up->debug);
|
qunlock(&up->debug);
|
||||||
|
@ -115,17 +116,13 @@ noted(Ureg* cur, uintptr_t arg0)
|
||||||
cur->sp = PTR2UINT(nf);
|
cur->sp = PTR2UINT(nf);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
jehanne_memmove(¬e, &up->lastnote, sizeof(Note));
|
up->lastnote.flag = NDebug;
|
||||||
qunlock(&up->debug);
|
/* fall through */
|
||||||
pprint("suicide: bad arg %#p in noted: %s\n", arg0, note.msg);
|
|
||||||
pexit(note.msg, 0);
|
|
||||||
break;
|
|
||||||
case NDFLT:
|
case NDFLT:
|
||||||
jehanne_memmove(¬e, &up->lastnote, sizeof(Note));
|
|
||||||
qunlock(&up->debug);
|
qunlock(&up->debug);
|
||||||
if(note.flag == NDebug)
|
if(up->lastnote.flag == NDebug)
|
||||||
pprint("suicide: %s\n", note.msg);
|
pprint("suicide: %s\n", up->lastnote.msg);
|
||||||
pexit(note.msg, note.flag != NDebug);
|
pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,7 +145,11 @@ notify(Ureg* ureg)
|
||||||
if(up->nnote == 0)
|
if(up->nnote == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fpunotify(ureg);
|
if(up->fpstate == FPactive){
|
||||||
|
fpsave(&up->fpsave);
|
||||||
|
up->fpstate = FPinactive;
|
||||||
|
}
|
||||||
|
up->fpstate |= FPillegal;
|
||||||
|
|
||||||
s = spllo();
|
s = spllo();
|
||||||
qlock(&up->debug);
|
qlock(&up->debug);
|
||||||
|
@ -238,7 +239,6 @@ syscall(Syscalls scallnr, Ureg* ureg)
|
||||||
m->syscall++;
|
m->syscall++;
|
||||||
up->inkernel = 1;
|
up->inkernel = 1;
|
||||||
up->cursyscall = (Syscalls)scallnr;
|
up->cursyscall = (Syscalls)scallnr;
|
||||||
up->blockingsc = 0;
|
|
||||||
up->pc = ureg->ip;
|
up->pc = ureg->ip;
|
||||||
up->dbgreg = ureg;
|
up->dbgreg = ureg;
|
||||||
if(up->trace && (pt = proctrace) != nil)
|
if(up->trace && (pt = proctrace) != nil)
|
||||||
|
@ -250,8 +250,6 @@ syscall(Syscalls scallnr, Ureg* ureg)
|
||||||
}
|
}
|
||||||
|
|
||||||
up->scallnr = scallnr;
|
up->scallnr = scallnr;
|
||||||
if(scallnr == SysRfork)
|
|
||||||
fpusysrfork(ureg);
|
|
||||||
spllo();
|
spllo();
|
||||||
|
|
||||||
startns = 0;
|
startns = 0;
|
||||||
|
@ -355,13 +353,8 @@ syscall(Syscalls scallnr, Ureg* ureg)
|
||||||
splhi();
|
splhi();
|
||||||
if(scallnr != SysRfork && (up->procctl || up->nnote))
|
if(scallnr != SysRfork && (up->procctl || up->nnote))
|
||||||
notify(ureg);
|
notify(ureg);
|
||||||
else if(up->blockingsc){
|
else
|
||||||
if(up->blockingsc != scallnr)
|
awake_awakened(up); // we are not sleeping after all!
|
||||||
panic("syscall: up->blockingsc dirty");
|
|
||||||
if(canwakeup(scallnr))
|
|
||||||
awokeproc(up);
|
|
||||||
up->blockingsc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we delayed sched because we held a lock, sched now */
|
/* if we delayed sched because we held a lock, sched now */
|
||||||
if(up->delaysched){
|
if(up->delaysched){
|
||||||
|
@ -412,7 +405,9 @@ sysexecregs(uintptr_t entry, uint32_t ssize)
|
||||||
ureg = up->dbgreg;
|
ureg = up->dbgreg;
|
||||||
ureg->sp = PTR2UINT(sp);
|
ureg->sp = PTR2UINT(sp);
|
||||||
ureg->ip = entry;
|
ureg->ip = entry;
|
||||||
ureg->type = 64; /* fiction for acid */
|
ureg->cs = UESEL;
|
||||||
|
ureg->ss = UDSEL;
|
||||||
|
ureg->r14 = ureg->r15 = 0; /* extern user registers */
|
||||||
ureg->r12 = up->pid;
|
ureg->r12 = up->pid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -425,7 +420,9 @@ sysexecregs(uintptr_t entry, uint32_t ssize)
|
||||||
void
|
void
|
||||||
sysprocsetup(Proc* p)
|
sysprocsetup(Proc* p)
|
||||||
{
|
{
|
||||||
fpusysprocsetup(p);
|
fpprocsetup(p);
|
||||||
|
cycles(&p->kentry);
|
||||||
|
p->pcycles = -p->kentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -448,9 +445,9 @@ sysrforkchild(Proc* child, Proc* parent)
|
||||||
cureg = (Ureg*)(child->sched.sp+STACKPAD*BY2SE);
|
cureg = (Ureg*)(child->sched.sp+STACKPAD*BY2SE);
|
||||||
jehanne_memmove(cureg, parent->dbgreg, sizeof(Ureg));
|
jehanne_memmove(cureg, parent->dbgreg, sizeof(Ureg));
|
||||||
|
|
||||||
|
cureg->ax = 0;
|
||||||
|
|
||||||
/* Things from bottom of syscall which were never executed */
|
/* Things from bottom of syscall which were never executed */
|
||||||
child->psstate = 0;
|
child->psstate = 0;
|
||||||
child->inkernel = 0;
|
child->inkernel = 0;
|
||||||
|
|
||||||
fpusysrforkchild(child, parent);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include "amd64.h"
|
#include "amd64.h"
|
||||||
|
|
||||||
|
static int trapinited;
|
||||||
|
|
||||||
extern int notify(Ureg*);
|
extern int notify(Ureg*);
|
||||||
|
|
||||||
static void debugbpt(Ureg*, void*);
|
static void debugbpt(Ureg*, void*);
|
||||||
|
@ -54,12 +56,19 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
|
||||||
Vctl *v;
|
Vctl *v;
|
||||||
|
|
||||||
if(f == nil){
|
if(f == nil){
|
||||||
jehanne_print("intrenable: nil handler for %d, tbdf %#ux for %s\n",
|
print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
|
||||||
irq, tbdf, name);
|
irq, tbdf, name);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
v = jehanne_malloc(sizeof(Vctl));
|
if(tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0)){
|
||||||
|
print("intrenable: got unassigned irq %d, tbdf 0x%uX for %s\n",
|
||||||
|
irq, tbdf, name);
|
||||||
|
irq = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((v = xalloc(sizeof(Vctl))) == nil)
|
||||||
|
panic("intrenable: out of memory");
|
||||||
v->isintr = 1;
|
v->isintr = 1;
|
||||||
v->irq = irq;
|
v->irq = irq;
|
||||||
v->tbdf = tbdf;
|
v->tbdf = tbdf;
|
||||||
|
@ -69,28 +78,24 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
|
||||||
v->name[KNAMELEN-1] = 0;
|
v->name[KNAMELEN-1] = 0;
|
||||||
|
|
||||||
ilock(&vctllock);
|
ilock(&vctllock);
|
||||||
vno = ioapicintrenable(v);
|
vno = arch->intrenable(v);
|
||||||
if(vno == -1){
|
if(vno == -1){
|
||||||
iunlock(&vctllock);
|
iunlock(&vctllock);
|
||||||
jehanne_print("intrenable: couldn't enable irq %d, tbdf %#ux for %s\n",
|
print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
|
||||||
irq, tbdf, v->name);
|
irq, tbdf, v->name);
|
||||||
jehanne_free(v);
|
xfree(v);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
if(vctl[vno]){
|
if(vctl[vno]){
|
||||||
if(vctl[v->vno]->isr != v->isr || vctl[v->vno]->eoi != v->eoi)
|
if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
|
||||||
panic("intrenable: handler: %s %s %#p %#p %#p %#p",
|
panic("intrenable: handler: %s %s %#p %#p %#p %#p",
|
||||||
vctl[v->vno]->name, v->name,
|
vctl[vno]->name, v->name,
|
||||||
vctl[v->vno]->isr, v->isr, vctl[v->vno]->eoi, v->eoi);
|
vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
|
||||||
}
|
|
||||||
v->vno = vno;
|
|
||||||
v->next = vctl[vno];
|
v->next = vctl[vno];
|
||||||
|
}
|
||||||
vctl[vno] = v;
|
vctl[vno] = v;
|
||||||
iunlock(&vctllock);
|
iunlock(&vctllock);
|
||||||
|
|
||||||
if(v->mask != nil)
|
|
||||||
v->mask(v, 0);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the assigned vector so intrdisable can find
|
* Return the assigned vector so intrdisable can find
|
||||||
* the handler; the IRQ is useless in the wondrefule world
|
* the handler; the IRQ is useless in the wondrefule world
|
||||||
|
@ -100,26 +105,42 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
intrdisable(void* vector)
|
intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
|
||||||
{
|
{
|
||||||
Vctl *v, **vl;
|
Vctl **pv, *v;
|
||||||
|
int vno;
|
||||||
|
|
||||||
|
if(arch->intrvecno == nil || (tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0))){
|
||||||
|
/*
|
||||||
|
* on APIC machine, irq is pretty meaningless
|
||||||
|
* and disabling a the vector is not implemented.
|
||||||
|
* however, we still want to remove the matching
|
||||||
|
* Vctl entry to prevent calling Vctl.f() with a
|
||||||
|
* stale Vctl.a pointer.
|
||||||
|
*/
|
||||||
|
irq = -1;
|
||||||
|
vno = VectorPIC;
|
||||||
|
} else {
|
||||||
|
vno = arch->intrvecno(irq);
|
||||||
|
}
|
||||||
ilock(&vctllock);
|
ilock(&vctllock);
|
||||||
v = vector;
|
do {
|
||||||
for(vl = &vctl[v->vno]; *vl != nil; vl = &(*vl)->next)
|
for(pv = &vctl[vno]; (v = *pv) != nil; pv = &v->next){
|
||||||
if(*vl == v)
|
if(v->isintr && (v->irq == irq || irq == -1)
|
||||||
|
&& v->tbdf == tbdf && v->f == f && v->a == a
|
||||||
|
&& strcmp(v->name, name) == 0)
|
||||||
break;
|
break;
|
||||||
if(*vl == nil)
|
}
|
||||||
panic("intrdisable: v %#p", v);
|
if(v != nil){
|
||||||
if(v->mask != nil)
|
*pv = v->next;
|
||||||
v->mask(v, 1);
|
xfree(v);
|
||||||
v->f(nil, v->a);
|
|
||||||
*vl = v->next;
|
if(irq != -1 && vctl[vno] == nil && arch->intrdisable != nil)
|
||||||
ioapicintrdisable(v->vno);
|
arch->intrdisable(irq);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(irq == -1 && ++vno <= MaxVectorAPIC);
|
||||||
iunlock(&vctllock);
|
iunlock(&vctllock);
|
||||||
|
|
||||||
jehanne_free(v);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,9 +188,10 @@ trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
|
||||||
{
|
{
|
||||||
Vctl *v;
|
Vctl *v;
|
||||||
|
|
||||||
if(vno < 0 || vno >= 256)
|
if(vno < 0 || vno >= VectorPIC)
|
||||||
panic("trapenable: vno %d\n", vno);
|
panic("trapenable: vno %d", vno);
|
||||||
v = jehanne_malloc(sizeof(Vctl));
|
if((v = xalloc(sizeof(Vctl))) == nil)
|
||||||
|
panic("trapenable: out of memory");
|
||||||
v->tbdf = BUSUNKNOWN;
|
v->tbdf = BUSUNKNOWN;
|
||||||
v->f = f;
|
v->f = f;
|
||||||
v->a = a;
|
v->a = a;
|
||||||
|
@ -177,7 +199,8 @@ trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
|
||||||
v->name[KNAMELEN-1] = 0;
|
v->name[KNAMELEN-1] = 0;
|
||||||
|
|
||||||
ilock(&vctllock);
|
ilock(&vctllock);
|
||||||
v->next = vctl[vno];
|
if(vctl[vno])
|
||||||
|
v->next = vctl[vno]->next;
|
||||||
vctl[vno] = v;
|
vctl[vno] = v;
|
||||||
iunlock(&vctllock);
|
iunlock(&vctllock);
|
||||||
}
|
}
|
||||||
|
@ -194,10 +217,48 @@ nmienable(void)
|
||||||
outb(0x70, 0);
|
outb(0x70, 0);
|
||||||
|
|
||||||
x = inb(0x61) & 0x07; /* Enable NMI */
|
x = inb(0x61) & 0x07; /* Enable NMI */
|
||||||
outb(0x61, 0x08|x);
|
outb(0x61, 0x0C|x);
|
||||||
outb(0x61, x);
|
outb(0x61, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
trapinit0(void)
|
||||||
|
{
|
||||||
|
uint32_t d1, v;
|
||||||
|
uintptr_t vaddr;
|
||||||
|
Segdesc *idt;
|
||||||
|
|
||||||
|
idt = (Segdesc*)IDTADDR;
|
||||||
|
vaddr = (uintptr_t)idthandlers;
|
||||||
|
for(v = 0; v < 256; v++){
|
||||||
|
d1 = (vaddr & 0xFFFF0000)|SEGP;
|
||||||
|
switch(v){
|
||||||
|
|
||||||
|
case VectorBPT:
|
||||||
|
d1 |= SEGPL(3)|SEGIG;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VectorSYSCALL:
|
||||||
|
d1 |= SEGPL(3)|SEGIG;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
d1 |= SEGPL(0)|SEGIG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
idt->d0 = (vaddr & 0xFFFF)|(KESEL<<16);
|
||||||
|
idt->d1 = d1;
|
||||||
|
idt++;
|
||||||
|
|
||||||
|
idt->d0 = (vaddr >> 32);
|
||||||
|
idt->d1 = 0;
|
||||||
|
idt++;
|
||||||
|
|
||||||
|
vaddr += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
trapinit(void)
|
trapinit(void)
|
||||||
{
|
{
|
||||||
|
@ -208,48 +269,50 @@ trapinit(void)
|
||||||
* Special traps.
|
* Special traps.
|
||||||
* Syscall() is called directly without going through trap().
|
* Syscall() is called directly without going through trap().
|
||||||
*/
|
*/
|
||||||
trapenable(IdtBP, debugbpt, 0, "#BP");
|
// trapenable(VectorDE, debugexc, 0, "debugexc");
|
||||||
trapenable(IdtPF, faultamd64, 0, "#PF");
|
trapenable(VectorBPT, debugbpt, 0, "debugpt");
|
||||||
trapenable(IdtDF, doublefault, 0, "#DF");
|
trapenable(VectorPF, faultamd64, 0, "faultamd64");
|
||||||
trapenable(Idt0F, unexpected, 0, "#15");
|
trapenable(Vector2F, doublefault, 0, "doublefault");
|
||||||
|
trapenable(Vector15, unexpected, 0, "unexpected");
|
||||||
nmienable();
|
nmienable();
|
||||||
|
|
||||||
addarchfile("irqalloc", 0444, irqallocread, nil);
|
addarchfile("irqalloc", 0444, irqallocread, nil);
|
||||||
|
trapinited = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* excname[32] = {
|
static char* excname[32] = {
|
||||||
"#DE", /* Divide-by-Zero Error */
|
"divide error",
|
||||||
"#DB", /* Debug */
|
"debug exception",
|
||||||
"#NMI", /* Non-Maskable-Interrupt */
|
"nonmaskable interrupt",
|
||||||
"#BP", /* Breakpoint */
|
"breakpoint",
|
||||||
"#OF", /* Overflow */
|
"overflow",
|
||||||
"#BR", /* Bound-Range */
|
"bounds check",
|
||||||
"#UD", /* Invalid-Opcode */
|
"invalid opcode",
|
||||||
"#NM", /* Device-Not-Available */
|
"coprocessor not available",
|
||||||
"#DF", /* Double-Fault */
|
"double fault",
|
||||||
"#9 (reserved)",
|
"coprocessor segment overrun",
|
||||||
"#TS", /* Invalid-TSS */
|
"invalid TSS",
|
||||||
"#NP", /* Segment-Not-Present */
|
"segment not present",
|
||||||
"#SS", /* Stack */
|
"stack exception",
|
||||||
"#GP", /* General-Protection */
|
"general protection violation",
|
||||||
"#PF", /* Page-Fault */
|
"page fault",
|
||||||
"#15 (reserved)",
|
"15 (reserved)",
|
||||||
"#MF", /* x87 FPE-Pending */
|
"coprocessor error",
|
||||||
"#AC", /* Alignment-Check */
|
"alignment check",
|
||||||
"#MC", /* Machine-Check */
|
"machine check",
|
||||||
"#XF", /* SIMD Floating-Point */
|
"simd error",
|
||||||
"#20 (reserved)",
|
"20 (reserved)",
|
||||||
"#21 (reserved)",
|
"21 (reserved)",
|
||||||
"#22 (reserved)",
|
"22 (reserved)",
|
||||||
"#23 (reserved)",
|
"23 (reserved)",
|
||||||
"#24 (reserved)",
|
"24 (reserved)",
|
||||||
"#25 (reserved)",
|
"25 (reserved)",
|
||||||
"#26 (reserved)",
|
"26 (reserved)",
|
||||||
"#27 (reserved)",
|
"27 (reserved)",
|
||||||
"#28 (reserved)",
|
"28 (reserved)",
|
||||||
"#29 (reserved)",
|
"29 (reserved)",
|
||||||
"#30 (reserved)",
|
"30 (reserved)",
|
||||||
"#31 (reserved)",
|
"31 (reserved)",
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -295,6 +358,13 @@ trap(Ureg* ureg)
|
||||||
char buf[ERRMAX];
|
char buf[ERRMAX];
|
||||||
Vctl *ctl, *v;
|
Vctl *ctl, *v;
|
||||||
|
|
||||||
|
if(!trapinited){
|
||||||
|
/* faultamd64 can give a better error message */
|
||||||
|
if(ureg->type == VectorPF)
|
||||||
|
faultamd64(ureg, nil);
|
||||||
|
panic("trap %llud: not ready", ureg->type);
|
||||||
|
}
|
||||||
|
|
||||||
m->perf.intrts = perfticks();
|
m->perf.intrts = perfticks();
|
||||||
user = userureg(ureg);
|
user = userureg(ureg);
|
||||||
if(user){
|
if(user){
|
||||||
|
@ -305,10 +375,11 @@ trap(Ureg* ureg)
|
||||||
clockintr = 0;
|
clockintr = 0;
|
||||||
|
|
||||||
vno = ureg->type;
|
vno = ureg->type;
|
||||||
|
|
||||||
if(ctl = vctl[vno]){
|
if(ctl = vctl[vno]){
|
||||||
if(ctl->isintr){
|
if(ctl->isintr){
|
||||||
m->intr++;
|
m->intr++;
|
||||||
if(vno >= IdtPIC && vno != IdtSYSCALL)
|
if(vno >= VectorPIC)
|
||||||
m->lastintr = ctl->irq;
|
m->lastintr = ctl->irq;
|
||||||
}
|
}
|
||||||
if(ctl->isr)
|
if(ctl->isr)
|
||||||
|
@ -323,10 +394,8 @@ trap(Ureg* ureg)
|
||||||
if(ctl->isintr){
|
if(ctl->isintr){
|
||||||
intrtime(m, vno);
|
intrtime(m, vno);
|
||||||
|
|
||||||
if(ctl->irq == IdtPIC+IrqCLOCK || ctl->irq == IdtTIMER){
|
if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)
|
||||||
checkflushmmu();
|
|
||||||
clockintr = 1;
|
clockintr = 1;
|
||||||
}
|
|
||||||
|
|
||||||
if(up && !clockintr)
|
if(up && !clockintr)
|
||||||
preempted();
|
preempted();
|
||||||
|
@ -373,33 +442,37 @@ trap(Ureg* ureg)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if(vno == IdtNMI){
|
if(vno == VectorNMI){
|
||||||
if(active.ispanic){
|
|
||||||
/*
|
/*
|
||||||
* Use of m->dbgsp avoids stack confusion
|
* Don't re-enable, it confuses the crash dumps.
|
||||||
* caused by writing the address of the SP to
|
|
||||||
* the top of the stack.
|
|
||||||
*/
|
|
||||||
m->dbgreg = ureg;
|
|
||||||
m->dbgsp = &ureg->sp;
|
|
||||||
for(;;)
|
|
||||||
_halt();
|
|
||||||
}
|
|
||||||
if(m->perfintr != nil){
|
|
||||||
m->perfintr(ureg, nil);
|
|
||||||
nmienable();
|
nmienable();
|
||||||
|
*/
|
||||||
|
iprint("cpu%d: nmi PC %#p, status %ux\n",
|
||||||
|
m->machno, ureg->ip, inb(0x61));
|
||||||
|
while(m->machno != 0)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!user){
|
||||||
|
void (*pc)(void);
|
||||||
|
|
||||||
|
extern void _rdmsrinst(void);
|
||||||
|
extern void _wrmsrinst(void);
|
||||||
|
|
||||||
|
pc = (void*)ureg->ip;
|
||||||
|
if(pc == _rdmsrinst || pc == _wrmsrinst){
|
||||||
|
if(vno == VectorGPF){
|
||||||
|
ureg->bp = -1;
|
||||||
|
ureg->ip += 2;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nmienable();
|
|
||||||
}
|
}
|
||||||
if(vno == 39){
|
}
|
||||||
/* We get this one and didn't track it down yet: it's ok */
|
|
||||||
iprint("vno %d: buggeration @ %#p...\n", vno, ureg->ip);
|
|
||||||
}else if(vno < nelem(excname)){
|
|
||||||
dumpregs(ureg);
|
dumpregs(ureg);
|
||||||
panic("%s pc %#p", excname[vno], ureg->ip);
|
if(vno < nelem(excname))
|
||||||
}else
|
panic("%s", excname[vno]);
|
||||||
panic("unknown trap/intr: %d pc %#p\n", vno, ureg->ip);
|
panic("unknown trap/intr: %d", vno);
|
||||||
}
|
}
|
||||||
splhi();
|
splhi();
|
||||||
|
|
||||||
|
@ -581,23 +654,21 @@ faultamd64(Ureg* ureg, void* _1)
|
||||||
void (*pt)(Proc*, int, int64_t, int64_t);
|
void (*pt)(Proc*, int, int64_t, int64_t);
|
||||||
|
|
||||||
addr = cr2get();
|
addr = cr2get();
|
||||||
user = userureg(ureg);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There must be a user context.
|
|
||||||
* If not, the usual problem is causing a fault during
|
|
||||||
* initialisation before the system is fully up.
|
|
||||||
*/
|
|
||||||
if(up == nil){
|
|
||||||
panic("fault with up == nil; pc %#llux addr %#llux\n",
|
|
||||||
ureg->ip, addr);
|
|
||||||
}
|
|
||||||
if(ureg->error&2)
|
if(ureg->error&2)
|
||||||
ftype = FaultWrite;
|
ftype = FaultWrite;
|
||||||
else if(ureg->error&16)
|
else if(ureg->error&16)
|
||||||
ftype = FaultExecute;
|
ftype = FaultExecute;
|
||||||
else
|
else
|
||||||
ftype = FaultRead;
|
ftype = FaultRead;
|
||||||
|
user = userureg(ureg);
|
||||||
|
if(!user){
|
||||||
|
if(addr >= USTKTOP)
|
||||||
|
panic("kernel fault: bad address pc=%#p addr=%#p", ureg->ip, addr);
|
||||||
|
if(up == nil)
|
||||||
|
panic("kernel fault: no user process pc=%#p addr=%#p", ureg->ip, addr);
|
||||||
|
}
|
||||||
|
if(up == nil)
|
||||||
|
panic("user fault: up=0 pc=%#p addr=%#p", ureg->ip, addr);
|
||||||
|
|
||||||
if(up->trace && (pt = proctrace) != nil){
|
if(up->trace && (pt = proctrace) != nil){
|
||||||
if(ftype == FaultWrite)
|
if(ftype == FaultWrite)
|
||||||
|
@ -617,7 +688,6 @@ if(iskaddr(addr)){
|
||||||
dumpregs(ureg);
|
dumpregs(ureg);
|
||||||
}
|
}
|
||||||
if(fault(addr, ureg->ip, ftype) < 0){
|
if(fault(addr, ureg->ip, ftype) < 0){
|
||||||
splhi();
|
|
||||||
if(!user){
|
if(!user){
|
||||||
dumpregs(ureg);
|
dumpregs(ureg);
|
||||||
panic("fault: %#llux pc %#p\n", addr, ureg->ip);
|
panic("fault: %#llux pc %#p\n", addr, ureg->ip);
|
||||||
|
|
|
@ -124,13 +124,11 @@ extern PhysUart i8250physuart;
|
||||||
static Ctlr i8250ctlr[2] = {
|
static Ctlr i8250ctlr[2] = {
|
||||||
{ .io = Uart0,
|
{ .io = Uart0,
|
||||||
.irq = Uart0IRQ,
|
.irq = Uart0IRQ,
|
||||||
.tbdf = -1,
|
.tbdf = -1, },
|
||||||
.poll = 0, },
|
|
||||||
|
|
||||||
{ .io = Uart1,
|
{ .io = Uart1,
|
||||||
.irq = Uart1IRQ,
|
.irq = Uart1IRQ,
|
||||||
.tbdf = -1,
|
.tbdf = -1, },
|
||||||
.poll = 0, },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static Uart i8250uart[2] = {
|
static Uart i8250uart[2] = {
|
||||||
|
@ -161,7 +159,7 @@ i8250status(Uart* uart, void* buf, long n, long offset)
|
||||||
uint8_t ier, lcr, mcr, msr;
|
uint8_t ier, lcr, mcr, msr;
|
||||||
|
|
||||||
ctlr = uart->regs;
|
ctlr = uart->regs;
|
||||||
p = jehanne_malloc(READSTR);
|
p = smalloc(READSTR);
|
||||||
mcr = ctlr->sticky[Mcr];
|
mcr = ctlr->sticky[Mcr];
|
||||||
msr = csr8r(ctlr, Msr);
|
msr = csr8r(ctlr, Msr);
|
||||||
ier = ctlr->sticky[Ier];
|
ier = ctlr->sticky[Ier];
|
||||||
|
@ -545,8 +543,8 @@ i8250disable(Uart* uart)
|
||||||
csr8w(ctlr, Ier, ctlr->sticky[Ier]);
|
csr8w(ctlr, Ier, ctlr->sticky[Ier]);
|
||||||
|
|
||||||
if(ctlr->iena != 0){
|
if(ctlr->iena != 0){
|
||||||
if(intrdisable(ctlr->vector) == 0)
|
|
||||||
ctlr->iena = 0;
|
ctlr->iena = 0;
|
||||||
|
intrdisable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,27 +686,6 @@ i8250putc(Uart* uart, int c)
|
||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
i8250poll(Uart* uart)
|
|
||||||
{
|
|
||||||
Ctlr *ctlr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If PhysUart has a non-nil .poll member, this
|
|
||||||
* routine will be called from the uartclock timer.
|
|
||||||
* If the Ctlr .poll member is non-zero, when the
|
|
||||||
* Uart is enabled interrupts will not be enabled
|
|
||||||
* and the result is polled input and output.
|
|
||||||
* Not very useful here, but ports to new hardware
|
|
||||||
* or simulators can use this to get serial I/O
|
|
||||||
* without setting up the interrupt mechanism.
|
|
||||||
*/
|
|
||||||
ctlr = uart->regs;
|
|
||||||
if(ctlr->iena || !ctlr->poll)
|
|
||||||
return;
|
|
||||||
i8250interrupt(nil, uart);
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysUart i8250physuart = {
|
PhysUart i8250physuart = {
|
||||||
.name = "i8250",
|
.name = "i8250",
|
||||||
.pnp = i8250pnp,
|
.pnp = i8250pnp,
|
||||||
|
@ -727,73 +704,27 @@ PhysUart i8250physuart = {
|
||||||
.fifo = i8250fifo,
|
.fifo = i8250fifo,
|
||||||
.getc = i8250getc,
|
.getc = i8250getc,
|
||||||
.putc = i8250putc,
|
.putc = i8250putc,
|
||||||
.poll = i8250poll,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Uart*
|
void
|
||||||
i8250console(char* cfg)
|
i8250console(void)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Uart *uart;
|
Uart *uart;
|
||||||
Ctlr *ctlr;
|
int n;
|
||||||
char *cmd, *p;
|
char *cmd, *p;
|
||||||
ISAConf isa;
|
|
||||||
|
|
||||||
/*
|
if((p = getconf("console")) == nil)
|
||||||
* Before i8250pnp() is run can only set the console
|
return;
|
||||||
* to 0 or 1 because those are the only uart structs which
|
n = strtoul(p, &cmd, 0);
|
||||||
* will be the same before and after that.
|
if(p == cmd || n < 0 || n >= nelem(i8250uart))
|
||||||
*/
|
return;
|
||||||
if((p = getconf("console")) == nil && (p = cfg) == nil)
|
uart = &i8250uart[n];
|
||||||
return nil;
|
|
||||||
i = jehanne_strtoul(p, &cmd, 0);
|
|
||||||
if(p == cmd)
|
|
||||||
return nil;
|
|
||||||
//WTF? Something to do with the PCIe-only machine?
|
|
||||||
if((uart = uartconsole(i, cmd)) != nil){
|
|
||||||
consuart = uart;
|
|
||||||
return uart;
|
|
||||||
}
|
|
||||||
switch(i){
|
|
||||||
default:
|
|
||||||
return nil;
|
|
||||||
case 0:
|
|
||||||
uart = &i8250uart[0];
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
uart = &i8250uart[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Madness. Something to do with the PCIe-only machine?
|
|
||||||
jehanne_memset(&isa, 0, sizeof(isa));
|
|
||||||
ctlr = uart->regs;
|
|
||||||
if(isaconfig("eia", i, &isa) != 0){
|
|
||||||
if(isa.port != 0)
|
|
||||||
ctlr->io = isa.port;
|
|
||||||
if(isa.irq != 0)
|
|
||||||
ctlr->irq = isa.irq;
|
|
||||||
if(isa.freq != 0)
|
|
||||||
uart->freq = isa.freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Does it exist?
|
|
||||||
* Should be able to write/read
|
|
||||||
* the Scratch Pad.
|
|
||||||
*/
|
|
||||||
// ctlr = uart->regs;
|
|
||||||
// csr8o(ctlr, Scr, 0x55);
|
|
||||||
// if(csr8r(ctlr, Scr) != 0x55)
|
|
||||||
// return nil;
|
|
||||||
|
|
||||||
(*uart->phys->enable)(uart, 0);
|
(*uart->phys->enable)(uart, 0);
|
||||||
uartctl(uart, "b9600 l8 pn s1 i1");
|
uartctl(uart, "b9600 l8 pn s1");
|
||||||
if(*cmd != '\0')
|
if(*cmd != '\0')
|
||||||
uartctl(uart, cmd);
|
uartctl(uart, cmd);
|
||||||
|
|
||||||
consuart = uart;
|
consuart = uart;
|
||||||
uart->console = 1;
|
uart->console = 1;
|
||||||
|
|
||||||
return uart;
|
|
||||||
}
|
}
|
|
@ -1485,7 +1485,7 @@ epio(Ep *ep, Qio *io, void *a, int32_t count, int mustlock)
|
||||||
jehanne_print("\t%s\n", buf);
|
jehanne_print("\t%s\n", buf);
|
||||||
}
|
}
|
||||||
if(mustlock){
|
if(mustlock){
|
||||||
qlock(&io->ql);
|
eqlock(&io->ql);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&io->ql);
|
qunlock(&io->ql);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -1625,7 +1625,7 @@ epread(Ep *ep, void *a, int32_t count)
|
||||||
switch(ep->ttype){
|
switch(ep->ttype){
|
||||||
case Tctl:
|
case Tctl:
|
||||||
cio = ep->aux;
|
cio = ep->aux;
|
||||||
qlock(&cio->ql);
|
eqlock(&cio->ql);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&cio->ql);
|
qunlock(&cio->ql);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -1698,7 +1698,7 @@ epctlio(Ep *ep, Ctlio *cio, void *a, int32_t count)
|
||||||
cio, ep->dev->nb, ep->nb, count);
|
cio, ep->dev->nb, ep->nb, count);
|
||||||
if(count < Rsetuplen)
|
if(count < Rsetuplen)
|
||||||
error("short usb command");
|
error("short usb command");
|
||||||
qlock(&cio->ql);
|
eqlock(&cio->ql);
|
||||||
jehanne_free(cio->data);
|
jehanne_free(cio->data);
|
||||||
cio->data = nil;
|
cio->data = nil;
|
||||||
cio->ndata = 0;
|
cio->ndata = 0;
|
||||||
|
@ -1804,7 +1804,7 @@ episowrite(Ep *ep, void *a, int32_t count)
|
||||||
iso->delay = (ep->sampledelay*ep->samplesz + ep->maxpkt-1) / ep->maxpkt;
|
iso->delay = (ep->sampledelay*ep->samplesz + ep->maxpkt-1) / ep->maxpkt;
|
||||||
iso->debug = ep->debug;
|
iso->debug = ep->debug;
|
||||||
|
|
||||||
qlock(&iso->ql);
|
eqlock(&iso->ql);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&iso->ql);
|
qunlock(&iso->ql);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -2193,7 +2193,7 @@ portreset(Hci *hp, int port, int on)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ctlr = hp->aux;
|
ctlr = hp->aux;
|
||||||
qlock(&ctlr->resetl);
|
eqlock(&ctlr->resetl);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&ctlr->resetl);
|
qunlock(&ctlr->resetl);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -2225,7 +2225,7 @@ portenable(Hci *hp, int port, int on)
|
||||||
|
|
||||||
ctlr = hp->aux;
|
ctlr = hp->aux;
|
||||||
dprint("ohci: %#p port %d enable=%d\n", ctlr->ohci, port, on);
|
dprint("ohci: %#p port %d enable=%d\n", ctlr->ohci, port, on);
|
||||||
qlock(&ctlr->resetl);
|
eqlock(&ctlr->resetl);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&ctlr->resetl);
|
qunlock(&ctlr->resetl);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
|
|
@ -1031,7 +1031,7 @@ episowrite(Ep *ep, Isoio *iso, void *a, int32_t count)
|
||||||
diprint("uhci: episowrite: %#p ep%d.%d\n", iso, ep->dev->nb, ep->nb);
|
diprint("uhci: episowrite: %#p ep%d.%d\n", iso, ep->dev->nb, ep->nb);
|
||||||
|
|
||||||
ctlr = ep->hp->aux;
|
ctlr = ep->hp->aux;
|
||||||
qlock(&iso->ql);
|
eqlock(&iso->ql);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&iso->ql);
|
qunlock(&iso->ql);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -1102,7 +1102,7 @@ episoread(Ep *ep, Isoio *iso, void *a, int count)
|
||||||
|
|
||||||
b = a;
|
b = a;
|
||||||
ctlr = ep->hp->aux;
|
ctlr = ep->hp->aux;
|
||||||
qlock(&iso->ql);
|
eqlock(&iso->ql);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&iso->ql);
|
qunlock(&iso->ql);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -1306,7 +1306,7 @@ epio(Ep *ep, Qio *io, void *a, int32_t count, int mustlock)
|
||||||
jehanne_print("uchi epio: user data: %s\n", buf);
|
jehanne_print("uchi epio: user data: %s\n", buf);
|
||||||
}
|
}
|
||||||
if(mustlock){
|
if(mustlock){
|
||||||
qlock(&io->ql);
|
eqlock(&io->ql);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&io->ql);
|
qunlock(&io->ql);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -1452,7 +1452,7 @@ epread(Ep *ep, void *a, int32_t count)
|
||||||
switch(ep->ttype){
|
switch(ep->ttype){
|
||||||
case Tctl:
|
case Tctl:
|
||||||
cio = ep->aux;
|
cio = ep->aux;
|
||||||
qlock(&cio->ql);
|
eqlock(&cio->ql);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&cio->ql);
|
qunlock(&cio->ql);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -1525,7 +1525,7 @@ epctlio(Ep *ep, Ctlio *cio, void *a, int32_t count)
|
||||||
cio, ep->dev->nb, ep->nb, count);
|
cio, ep->dev->nb, ep->nb, count);
|
||||||
if(count < Rsetuplen)
|
if(count < Rsetuplen)
|
||||||
error("short usb comand");
|
error("short usb comand");
|
||||||
qlock(&cio->ql);
|
eqlock(&cio->ql);
|
||||||
jehanne_free(cio->data);
|
jehanne_free(cio->data);
|
||||||
cio->data = nil;
|
cio->data = nil;
|
||||||
cio->ndata = 0;
|
cio->ndata = 0;
|
||||||
|
@ -2013,7 +2013,7 @@ portenable(Hci *hp, int port, int on)
|
||||||
ctlr = hp->aux;
|
ctlr = hp->aux;
|
||||||
dprint("uhci: %#x port %d enable=%d\n", ctlr->port, port, on);
|
dprint("uhci: %#x port %d enable=%d\n", ctlr->port, port, on);
|
||||||
ioport = PORT(port-1);
|
ioport = PORT(port-1);
|
||||||
qlock(&ctlr->portlck);
|
eqlock(&ctlr->portlck);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
qunlock(&ctlr->portlck);
|
qunlock(&ctlr->portlck);
|
||||||
nexterror();
|
nexterror();
|
||||||
|
@ -2070,7 +2070,7 @@ portstatus(Hci *hp, int port)
|
||||||
|
|
||||||
ctlr = hp->aux;
|
ctlr = hp->aux;
|
||||||
ioport = PORT(port-1);
|
ioport = PORT(port-1);
|
||||||
qlock(&ctlr->portlck);
|
eqlock(&ctlr->portlck);
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
iunlock(&ctlr->l);
|
iunlock(&ctlr->l);
|
||||||
qunlock(&ctlr->portlck);
|
qunlock(&ctlr->portlck);
|
||||||
|
|
|
@ -225,7 +225,7 @@ vgascreenwin(VGAscr* scr)
|
||||||
window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
|
window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
|
||||||
curpos = window.min;
|
curpos = window.min;
|
||||||
|
|
||||||
consputs = vgascreenputs;
|
screenputs = vgascreenputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -275,7 +275,7 @@ cornerstring(char *s)
|
||||||
Point p;
|
Point p;
|
||||||
|
|
||||||
scr = &vgascreen[0];
|
scr = &vgascreen[0];
|
||||||
if(scr->vaddr == nil || consputs != vgascreenputs)
|
if(scr->vaddr == nil || screenputs != vgascreenputs)
|
||||||
return;
|
return;
|
||||||
p = memsubfontwidth(scr->memdefont, s);
|
p = memsubfontwidth(scr->memdefont, s);
|
||||||
w = p.x;
|
w = p.x;
|
||||||
|
|
|
@ -78,7 +78,6 @@ vbecall(VGAreg *u)
|
||||||
pa = PADDR(RMBUF);
|
pa = PADDR(RMBUF);
|
||||||
cmem->dev->write(cmem, modebuf, sizeof modebuf, pa);
|
cmem->dev->write(cmem, modebuf, sizeof modebuf, pa);
|
||||||
u->trap = 0x10;
|
u->trap = 0x10;
|
||||||
jehanne_print("vbecall: sizeof u is %d\n", sizeof *u);
|
|
||||||
creg->dev->write(creg, u, sizeof *u, 0);
|
creg->dev->write(creg, u, sizeof *u, 0);
|
||||||
|
|
||||||
creg->dev->read(creg, u, sizeof *u, 0);
|
creg->dev->read(creg, u, sizeof *u, 0);
|
|
@ -24,7 +24,7 @@
|
||||||
static Lock vgaxlock; /* access to index registers */
|
static Lock vgaxlock; /* access to index registers */
|
||||||
|
|
||||||
int
|
int
|
||||||
vgaxi(int32_t port, unsigned char index)
|
vgaxi(int32_t port, uint8_t index)
|
||||||
{
|
{
|
||||||
unsigned char data;
|
unsigned char data;
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ vgaxi(int32_t port, unsigned char index)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vgaxo(int32_t port, unsigned char index, unsigned char data)
|
vgaxo(int32_t port, uint8_t index, uint8_t data)
|
||||||
{
|
{
|
||||||
ilock(&vgaxlock);
|
ilock(&vgaxlock);
|
||||||
switch(port){
|
switch(port){
|
||||||
|
|
|
@ -1,192 +0,0 @@
|
||||||
/*
|
|
||||||
* Vestigial Segmented Virtual Memory.
|
|
||||||
* To do:
|
|
||||||
* dynamic allocation and free of descriptors;
|
|
||||||
* IST should perhaps point to a different handler;
|
|
||||||
* user-level descriptors (if not dynamic).
|
|
||||||
*/
|
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
|
|
||||||
#include "amd64.h"
|
|
||||||
#include "ureg.h"
|
|
||||||
|
|
||||||
typedef struct Gd Gd;
|
|
||||||
typedef uint64_t Sd;
|
|
||||||
typedef uint16_t Ss;
|
|
||||||
typedef struct Tss Tss;
|
|
||||||
|
|
||||||
struct Gd {
|
|
||||||
Sd sd;
|
|
||||||
uint64_t hi;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Tss {
|
|
||||||
uint32_t _0_;
|
|
||||||
uint32_t rsp0[2];
|
|
||||||
uint32_t rsp1[2];
|
|
||||||
uint32_t rsp2[2];
|
|
||||||
uint32_t _28_[2];
|
|
||||||
uint32_t ist[14];
|
|
||||||
uint16_t _92_[5];
|
|
||||||
uint16_t iomap;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
Ngdt = 16, /* max. entries in gdt */
|
|
||||||
Nidt = 256, /* max. entries in idt */
|
|
||||||
};
|
|
||||||
|
|
||||||
static Sd gdt64[Ngdt] = {
|
|
||||||
0ull, /* NULL descriptor */
|
|
||||||
SdL|SdP|SdDPL0|SdS|SdCODE, /* CS */
|
|
||||||
SdG|SdD|SdP|SdDPL0|SdS|SdW, /* DS */
|
|
||||||
SdG|SdD|SdP|SdDPL3|SdS|SdCODE|SdR|Sd4G, /* User CS 32-bit */
|
|
||||||
SdG|SdD|SdP|SdDPL3|SdS|SdW|Sd4G, /* User DS */
|
|
||||||
SdL|SdP|SdDPL3|SdS|SdCODE, /* User CS 64-bit */
|
|
||||||
|
|
||||||
0ull, /* FS */
|
|
||||||
0ull, /* GS */
|
|
||||||
|
|
||||||
0ull, /* TSS lower */
|
|
||||||
0ull, /* TSS upper */
|
|
||||||
};
|
|
||||||
//static int ngdt64 = 10; // not used
|
|
||||||
|
|
||||||
static Gd idt64[Nidt];
|
|
||||||
|
|
||||||
static Sd
|
|
||||||
mksd(uint64_t base, uint64_t limit, uint64_t bits, uint64_t* upper)
|
|
||||||
{
|
|
||||||
Sd sd;
|
|
||||||
|
|
||||||
sd = bits;
|
|
||||||
sd |= (((limit & 0x00000000000f0000ull)>>16)<<48)
|
|
||||||
|(limit & 0x000000000000ffffull);
|
|
||||||
sd |= (((base & 0x00000000ff000000ull)>>24)<<56)
|
|
||||||
|(((base & 0x0000000000ff0000ull)>>16)<<32)
|
|
||||||
|((base & 0x000000000000ffffull)<<16);
|
|
||||||
if(upper != nil)
|
|
||||||
*upper = base>>32;
|
|
||||||
|
|
||||||
return sd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
mkgd(Gd* gd, uint64_t offset, Ss ss, uint64_t bits, int ist)
|
|
||||||
{
|
|
||||||
Sd sd;
|
|
||||||
|
|
||||||
sd = bits;
|
|
||||||
sd |= (((offset & 0x00000000ffff0000ull)>>16)<<48)
|
|
||||||
|(offset & 0x000000000000ffffull);
|
|
||||||
sd |= ((ss & 0x000000000000ffffull)<<16);
|
|
||||||
sd |= (ist & (SdISTM>>32))<<32;
|
|
||||||
gd->sd = sd;
|
|
||||||
gd->hi = offset>>32;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
idtinit(void)
|
|
||||||
{
|
|
||||||
Gd *gd;
|
|
||||||
int ist, v;
|
|
||||||
uint64_t dpl;
|
|
||||||
uintptr_t offset;
|
|
||||||
|
|
||||||
gd = idt64;
|
|
||||||
offset = PTR2UINT(idthandlers);
|
|
||||||
|
|
||||||
for(v = 0; v < Nidt; v++){
|
|
||||||
ist = 0;
|
|
||||||
dpl = SdP|SdDPL0|SdIG;
|
|
||||||
switch(v){
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case IdtBP: /* #BP */
|
|
||||||
dpl = SdP|SdDPL3|SdIG;
|
|
||||||
break;
|
|
||||||
case IdtUD: /* #UD */
|
|
||||||
case IdtDF: /* #DF */
|
|
||||||
ist = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mkgd(gd, offset, SSEL(SiCS, SsTIGDT|SsRPL0), dpl, ist);
|
|
||||||
gd++;
|
|
||||||
offset += 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tssrsp0(uintptr_t sp)
|
|
||||||
{
|
|
||||||
Tss *tss;
|
|
||||||
|
|
||||||
tss = m->tss;
|
|
||||||
tss->rsp0[0] = sp;
|
|
||||||
tss->rsp0[1] = sp>>32;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
tssinit(uintptr_t sp)
|
|
||||||
{
|
|
||||||
int ist;
|
|
||||||
Tss *tss;
|
|
||||||
|
|
||||||
tss = m->tss;
|
|
||||||
jehanne_memset(tss, 0, sizeof(Tss));
|
|
||||||
|
|
||||||
tssrsp0(sp);
|
|
||||||
|
|
||||||
sp = PTR2UINT(m->vsvm+PGSZ);
|
|
||||||
for(ist = 0; ist < 14; ist += 2){
|
|
||||||
tss->ist[ist] = sp;
|
|
||||||
tss->ist[ist+1] = sp>>32;
|
|
||||||
}
|
|
||||||
tss->iomap = 0xdfff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
vsvminit(int size)
|
|
||||||
{
|
|
||||||
Sd *sd;
|
|
||||||
uint64_t r;
|
|
||||||
|
|
||||||
if(m->machno == 0)
|
|
||||||
idtinit();
|
|
||||||
|
|
||||||
m->gdt = m->vsvm;
|
|
||||||
jehanne_memmove(m->gdt, gdt64, sizeof(gdt64));
|
|
||||||
m->tss = &m->vsvm[ROUNDUP(sizeof(gdt64), 16)];
|
|
||||||
|
|
||||||
sd = &((Sd*)m->gdt)[SiTSS];
|
|
||||||
*sd = mksd(PTR2UINT(m->tss), sizeof(Tss)-1, SdP|SdDPL0|SdaTSS, sd+1);
|
|
||||||
|
|
||||||
tssinit(m->stack+size);
|
|
||||||
|
|
||||||
gdtput(sizeof(gdt64)-1, PTR2UINT(m->gdt), SSEL(SiCS, SsTIGDT|SsRPL0));
|
|
||||||
idtput(sizeof(idt64)-1, PTR2UINT(idt64));
|
|
||||||
trput(SSEL(SiTSS, SsTIGDT|SsRPL0));
|
|
||||||
|
|
||||||
wrmsr(FSbase, 0ull);
|
|
||||||
wrmsr(GSbase, PTR2UINT(&sys->machptr[m->machno]));
|
|
||||||
wrmsr(KernelGSbase, 0ull);
|
|
||||||
|
|
||||||
r = rdmsr(Efer);
|
|
||||||
r |= Sce;
|
|
||||||
wrmsr(Efer, r);
|
|
||||||
r = ((uint64_t)SSEL(SiU32CS, SsRPL3))<<48;
|
|
||||||
r |= ((uint64_t)SSEL(SiCS, SsRPL0))<<32;
|
|
||||||
wrmsr(Star, r);
|
|
||||||
wrmsr(Lstar, PTR2UINT(syscallentry));
|
|
||||||
wrmsr(Sfmask, If);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
userureg(Ureg* ureg)
|
|
||||||
{
|
|
||||||
return ureg->cs == SSEL(SiUCS, SsRPL3);
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@
|
||||||
],
|
],
|
||||||
"Include": [
|
"Include": [
|
||||||
"core.json",
|
"core.json",
|
||||||
"../386/include.json",
|
|
||||||
"../ip/include.json",
|
"../ip/include.json",
|
||||||
"../port/include.json"
|
"../port/include.json"
|
||||||
],
|
],
|
||||||
|
@ -17,7 +16,6 @@
|
||||||
"int printallsyscalls;"
|
"int printallsyscalls;"
|
||||||
],
|
],
|
||||||
"Dev": [
|
"Dev": [
|
||||||
"acpi",
|
|
||||||
"arch",
|
"arch",
|
||||||
"bridge",
|
"bridge",
|
||||||
"cap",
|
"cap",
|
||||||
|
@ -105,7 +103,6 @@
|
||||||
"autogenerated.c",
|
"autogenerated.c",
|
||||||
"sdata.c",
|
"sdata.c",
|
||||||
"cga.c",
|
"cga.c",
|
||||||
"devacpi.c",
|
|
||||||
"usbehcipc.c",
|
"usbehcipc.c",
|
||||||
"usbohci.c",
|
"usbohci.c",
|
||||||
"usbuhci.c"
|
"usbuhci.c"
|
||||||
|
|
|
@ -0,0 +1,351 @@
|
||||||
|
#include "u.h"
|
||||||
|
#include "../port/lib.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include <pool.h>
|
||||||
|
|
||||||
|
static void poolprint(Pool*, char*, ...);
|
||||||
|
static void ppanic(Pool*, char*, ...);
|
||||||
|
static void pool_lock(Pool*);
|
||||||
|
static void pool_unlock(Pool*);
|
||||||
|
|
||||||
|
typedef struct Private Private;
|
||||||
|
struct Private {
|
||||||
|
Lock lk;
|
||||||
|
char msg[256]; /* a rock for messages to be printed at unlock */
|
||||||
|
};
|
||||||
|
|
||||||
|
static Private pmainpriv;
|
||||||
|
static Pool pmainmem = {
|
||||||
|
.name= "Main",
|
||||||
|
.maxsize= 4*1024*1024,
|
||||||
|
.minarena= 128*1024,
|
||||||
|
.quantum= 32,
|
||||||
|
.alloc= xalloc,
|
||||||
|
.merge= xmerge,
|
||||||
|
.flags= POOL_TOLERANCE,
|
||||||
|
|
||||||
|
.lock= pool_lock,
|
||||||
|
.unlock= pool_unlock,
|
||||||
|
.print= poolprint,
|
||||||
|
.panic= ppanic,
|
||||||
|
|
||||||
|
.private= &pmainpriv,
|
||||||
|
};
|
||||||
|
|
||||||
|
static Private pimagpriv;
|
||||||
|
static Pool pimagmem = {
|
||||||
|
.name= "Image",
|
||||||
|
.maxsize= 16*1024*1024,
|
||||||
|
.minarena= 2*1024*1024,
|
||||||
|
.quantum= 32,
|
||||||
|
.alloc= xalloc,
|
||||||
|
.merge= xmerge,
|
||||||
|
.flags= 0,
|
||||||
|
|
||||||
|
.lock= pool_lock,
|
||||||
|
.unlock= pool_unlock,
|
||||||
|
.print= poolprint,
|
||||||
|
.panic= ppanic,
|
||||||
|
|
||||||
|
.private= &pimagpriv,
|
||||||
|
};
|
||||||
|
|
||||||
|
static Private psecrpriv;
|
||||||
|
static Pool psecrmem = {
|
||||||
|
.name= "Secrets",
|
||||||
|
.maxsize= 16*1024*1024,
|
||||||
|
.minarena= 64*1024,
|
||||||
|
.quantum= 32,
|
||||||
|
.alloc= xalloc,
|
||||||
|
.merge= xmerge,
|
||||||
|
.flags= POOL_ANTAGONISM,
|
||||||
|
|
||||||
|
.lock= pool_lock,
|
||||||
|
.unlock= pool_unlock,
|
||||||
|
.print= poolprint,
|
||||||
|
.panic= ppanic,
|
||||||
|
|
||||||
|
.private= &psecrpriv,
|
||||||
|
};
|
||||||
|
|
||||||
|
Pool* mainmem = &pmainmem;
|
||||||
|
Pool* imagmem = &pimagmem;
|
||||||
|
Pool* secrmem = &psecrmem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* because we can't print while we're holding the locks,
|
||||||
|
* we have the save the message and print it once we let go.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
poolprint(Pool *p, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list v;
|
||||||
|
Private *pv;
|
||||||
|
|
||||||
|
pv = p->private;
|
||||||
|
va_start(v, fmt);
|
||||||
|
vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
|
||||||
|
va_end(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ppanic(Pool *p, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list v;
|
||||||
|
Private *pv;
|
||||||
|
char msg[sizeof pv->msg];
|
||||||
|
|
||||||
|
pv = p->private;
|
||||||
|
va_start(v, fmt);
|
||||||
|
vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
|
||||||
|
va_end(v);
|
||||||
|
memmove(msg, pv->msg, sizeof msg);
|
||||||
|
iunlock(&pv->lk);
|
||||||
|
panic("%s", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pool_lock(Pool *p)
|
||||||
|
{
|
||||||
|
Private *pv;
|
||||||
|
|
||||||
|
pv = p->private;
|
||||||
|
ilock(&pv->lk);
|
||||||
|
// pv->lk.pc = getcallerpc();
|
||||||
|
pv->msg[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pool_unlock(Pool *p)
|
||||||
|
{
|
||||||
|
Private *pv;
|
||||||
|
char msg[sizeof pv->msg];
|
||||||
|
|
||||||
|
pv = p->private;
|
||||||
|
if(pv->msg[0] == 0){
|
||||||
|
iunlock(&pv->lk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(msg, pv->msg, sizeof msg);
|
||||||
|
iunlock(&pv->lk);
|
||||||
|
iprint("%.*s", sizeof pv->msg, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
poolsummary(Pool *p)
|
||||||
|
{
|
||||||
|
print("%s max %llud cur %llud free %llud alloc %llud\n", p->name,
|
||||||
|
(uint64_t)p->maxsize, (uint64_t)p->cursize,
|
||||||
|
(uint64_t)p->curfree, (uint64_t)p->curalloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mallocsummary(void)
|
||||||
|
{
|
||||||
|
poolsummary(mainmem);
|
||||||
|
poolsummary(imagmem);
|
||||||
|
poolsummary(secrmem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* everything from here down should be the same in libc, libdebugmalloc, and the kernel */
|
||||||
|
/* - except the code for malloc(), which alternately doesn't clear or does. */
|
||||||
|
/* - except the code for smalloc(), which lives only in the kernel. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Npadlong is the number of uint32_t's to leave at the beginning of
|
||||||
|
* each allocated buffer for our own bookkeeping. We return to the callers
|
||||||
|
* a pointer that points immediately after our bookkeeping area. Incoming pointers
|
||||||
|
* must be decremented by that much, and outgoing pointers incremented.
|
||||||
|
* The malloc tag is stored at MallocOffset from the beginning of the block,
|
||||||
|
* and the realloc tag at ReallocOffset. The offsets are from the true beginning
|
||||||
|
* of the block, not the beginning the caller sees.
|
||||||
|
*
|
||||||
|
* The extra if(Npadlong != 0) in various places is a hint for the compiler to
|
||||||
|
* compile out function calls that would otherwise be no-ops.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* non tracing
|
||||||
|
*
|
||||||
|
enum {
|
||||||
|
Npadlong = 0,
|
||||||
|
MallocOffset = 0,
|
||||||
|
ReallocOffset = 0,
|
||||||
|
};
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tracing */
|
||||||
|
enum {
|
||||||
|
Npadlong = 2,
|
||||||
|
MallocOffset = 0,
|
||||||
|
ReallocOffset = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void*
|
||||||
|
smalloc(uint32_t size)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
while((v = poolalloc(mainmem, size+Npadlong*sizeof(uint32_t))) == nil){
|
||||||
|
if(!waserror()){
|
||||||
|
resrcwait(nil, nil);
|
||||||
|
poperror();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(Npadlong){
|
||||||
|
v = (uint32_t*)v+Npadlong;
|
||||||
|
setmalloctag(v, getcallerpc());
|
||||||
|
}
|
||||||
|
memset(v, 0, size);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
jehanne_malloc(uint32_t size)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
v = poolalloc(mainmem, size+Npadlong*sizeof(uint32_t));
|
||||||
|
if(v == nil)
|
||||||
|
return nil;
|
||||||
|
if(Npadlong){
|
||||||
|
v = (uint32_t*)v+Npadlong;
|
||||||
|
setmalloctag(v, getcallerpc());
|
||||||
|
setrealloctag(v, 0);
|
||||||
|
}
|
||||||
|
memset(v, 0, size);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
jehanne_mallocz(uint32_t size, int clr)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
v = poolalloc(mainmem, size+Npadlong*sizeof(uint32_t));
|
||||||
|
if(Npadlong && v != nil){
|
||||||
|
v = (uint32_t*)v+Npadlong;
|
||||||
|
setmalloctag(v, getcallerpc());
|
||||||
|
setrealloctag(v, 0);
|
||||||
|
}
|
||||||
|
if(clr && v != nil)
|
||||||
|
memset(v, 0, size);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
jehanne_mallocalign(uint32_t size, uint32_t align, long offset, uint32_t span)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
v = poolallocalign(mainmem, size+Npadlong*sizeof(uint32_t), align, offset-Npadlong*sizeof(uint32_t), span);
|
||||||
|
if(Npadlong && v != nil){
|
||||||
|
v = (uint32_t*)v+Npadlong;
|
||||||
|
setmalloctag(v, getcallerpc());
|
||||||
|
setrealloctag(v, 0);
|
||||||
|
}
|
||||||
|
if(v)
|
||||||
|
memset(v, 0, size);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
jehanne_free(void *v)
|
||||||
|
{
|
||||||
|
if(v != nil)
|
||||||
|
poolfree(mainmem, (uint32_t*)v-Npadlong);
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
jehanne_realloc(void *v, uint32_t size)
|
||||||
|
{
|
||||||
|
void *nv;
|
||||||
|
|
||||||
|
if(v != nil)
|
||||||
|
v = (uint32_t*)v-Npadlong;
|
||||||
|
if(Npadlong !=0 && size != 0)
|
||||||
|
size += Npadlong*sizeof(uint32_t);
|
||||||
|
|
||||||
|
if(nv = poolrealloc(mainmem, v, size)){
|
||||||
|
nv = (uint32_t*)nv+Npadlong;
|
||||||
|
setrealloctag(nv, getcallerpc());
|
||||||
|
if(v == nil)
|
||||||
|
setmalloctag(nv, getcallerpc());
|
||||||
|
}
|
||||||
|
return nv;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
jehanne_msize(void *v)
|
||||||
|
{
|
||||||
|
return poolmsize(mainmem, (uint32_t*)v-Npadlong)-Npadlong*sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* secret memory, used to back cryptographic keys and cipher states */
|
||||||
|
void*
|
||||||
|
secalloc(uint32_t size)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
while((v = poolalloc(secrmem, size+Npadlong*sizeof(uint32_t))) == nil){
|
||||||
|
if(!waserror()){
|
||||||
|
resrcwait(nil, nil);
|
||||||
|
poperror();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(Npadlong){
|
||||||
|
v = (uint32_t*)v+Npadlong;
|
||||||
|
setmalloctag(v, getcallerpc());
|
||||||
|
setrealloctag(v, 0);
|
||||||
|
}
|
||||||
|
memset(v, 0, size);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
secfree(void *v)
|
||||||
|
{
|
||||||
|
if(v != nil)
|
||||||
|
poolfree(secrmem, (uint32_t*)v-Npadlong);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
jehanne_setmalloctag(void *v, uintptr_t pc)
|
||||||
|
{
|
||||||
|
USED(v, pc);
|
||||||
|
if(Npadlong <= MallocOffset || v == nil)
|
||||||
|
return;
|
||||||
|
((uint32_t*)v)[-Npadlong+MallocOffset] = (uint32_t)pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
jehanne_setrealloctag(void *v, uintptr_t pc)
|
||||||
|
{
|
||||||
|
USED(v, pc);
|
||||||
|
if(Npadlong <= ReallocOffset || v == nil)
|
||||||
|
return;
|
||||||
|
((uint32_t*)v)[-Npadlong+ReallocOffset] = (uint32_t)pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t
|
||||||
|
jehanne_getmalloctag(void *v)
|
||||||
|
{
|
||||||
|
USED(v);
|
||||||
|
if(Npadlong <= MallocOffset)
|
||||||
|
return ~0;
|
||||||
|
return (int)((uint32_t*)v)[-Npadlong+MallocOffset];
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t
|
||||||
|
jehanne_getrealloctag(void *v)
|
||||||
|
{
|
||||||
|
USED(v);
|
||||||
|
if(Npadlong <= ReallocOffset)
|
||||||
|
return ~0;
|
||||||
|
return (int)((uint32_t*)v)[-Npadlong+ReallocOffset];
|
||||||
|
}
|
|
@ -3,50 +3,46 @@
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
Hdrspc = 64, /* leave room for high-level headers */
|
Hdrspc = 64, /* leave room for high-level headers */
|
||||||
|
Tlrspc = 16, /* extra room at the end for pad/crc/mac */
|
||||||
Bdead = 0x51494F42, /* "QIOB" */
|
Bdead = 0x51494F42, /* "QIOB" */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
Lock;
|
|
||||||
uint32_t bytes;
|
|
||||||
uint32_t limit;
|
|
||||||
|
|
||||||
} ialloc;
|
|
||||||
|
|
||||||
static Block*
|
static Block*
|
||||||
_allocb(int size, int align)
|
_allocb(int size)
|
||||||
{
|
{
|
||||||
Block *b;
|
Block *b;
|
||||||
uint8_t *p;
|
uintptr_t addr;
|
||||||
int n;
|
|
||||||
|
|
||||||
if(align <= 0)
|
size += Tlrspc;
|
||||||
align = BLOCKALIGN;
|
if((b = mallocz(sizeof(Block)+size+Hdrspc, 0)) == nil)
|
||||||
n = align + ROUNDUP(size+Hdrspc, align) + sizeof(Block);
|
|
||||||
if((p = jehanne_malloc(n)) == nil)
|
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
b = (Block*)(p + n - sizeof(Block)); /* block at end of allocated space */
|
|
||||||
b->base = p;
|
|
||||||
b->next = nil;
|
b->next = nil;
|
||||||
b->list = nil;
|
b->list = nil;
|
||||||
b->free = 0;
|
b->free = nil;
|
||||||
b->flag = 0;
|
b->flag = 0;
|
||||||
|
|
||||||
/* align base and bounds of data */
|
/* align start of data portion by rounding up */
|
||||||
b->lim = (uint8_t*)(PTR2UINT(b) & ~(align-1));
|
addr = (uintptr_t)b;
|
||||||
|
addr = ROUND(addr + sizeof(Block), BLOCKALIGN);
|
||||||
|
b->base = (uint8_t*)addr;
|
||||||
|
|
||||||
/* align start of writable data, leaving space below for added headers */
|
/* align end of data portion by rounding down */
|
||||||
b->rp = b->lim - ROUNDUP(size, align);
|
b->lim = (uint8_t*)b + msize(b);
|
||||||
b->wp = b->rp;
|
addr = (uintptr_t)b->lim;
|
||||||
|
addr &= ~(BLOCKALIGN-1);
|
||||||
|
b->lim = (uint8_t*)addr;
|
||||||
|
|
||||||
if(b->rp < b->base || b->lim - b->rp < size)
|
/* leave sluff at beginning for added headers */
|
||||||
|
b->rp = b->lim - ROUND(size, BLOCKALIGN);
|
||||||
|
if(b->rp < b->base)
|
||||||
panic("_allocb");
|
panic("_allocb");
|
||||||
|
b->wp = b->rp;
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
@ -58,80 +54,44 @@ allocb(int size)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check in a process and wait until successful.
|
* Check in a process and wait until successful.
|
||||||
* Can still error out of here, though.
|
|
||||||
*/
|
*/
|
||||||
if(up == nil)
|
if(up == nil)
|
||||||
panic("allocb without up: %#p\n", getcallerpc());
|
panic("allocb without up: %#p", getcallerpc());
|
||||||
if((b = _allocb(size, 0)) == nil){
|
while((b = _allocb(size)) == nil){
|
||||||
|
if(up->nlocks || m->ilockdepth || !islo()){
|
||||||
|
xsummary();
|
||||||
mallocsummary();
|
mallocsummary();
|
||||||
panic("allocb: no memory for %d bytes\n", size);
|
panic("allocb: no memory for %d bytes", size);
|
||||||
}
|
}
|
||||||
jehanne_setmalloctag(b->base, getcallerpc());
|
if(!waserror()){
|
||||||
|
resrcwait("no memory for allocb", nil);
|
||||||
|
poperror();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setmalloctag(b, getcallerpc());
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block*
|
|
||||||
allocbalign(int size, int align)
|
|
||||||
{
|
|
||||||
Block *b;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check in a process and wait until successful.
|
|
||||||
* Can still error out of here, though.
|
|
||||||
*/
|
|
||||||
if(up == nil)
|
|
||||||
panic("allocbalign without up: %#p\n", getcallerpc());
|
|
||||||
if((b = _allocb(size, align)) == nil){
|
|
||||||
mallocsummary();
|
|
||||||
panic("allocbalign: no memory for %d bytes\n", size);
|
|
||||||
}
|
|
||||||
jehanne_setmalloctag(b->base, getcallerpc());
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ialloclimit(uint32_t limit)
|
|
||||||
{
|
|
||||||
ialloc.limit = limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block*
|
Block*
|
||||||
iallocb(int size)
|
iallocb(int size)
|
||||||
{
|
{
|
||||||
Block *b;
|
Block *b;
|
||||||
static int m1, m2, mp;
|
|
||||||
|
|
||||||
if(ialloc.bytes > ialloc.limit){
|
if((b = _allocb(size)) == nil){
|
||||||
if((m1++%10000)==0){
|
static uint32_t nerr;
|
||||||
if(mp++ > 1000){
|
if((nerr++%10000)==0){
|
||||||
active.exiting = 1;
|
if(nerr > 10000000){
|
||||||
exit(0);
|
xsummary();
|
||||||
|
mallocsummary();
|
||||||
|
panic("iallocb: out of memory");
|
||||||
}
|
}
|
||||||
iprint("iallocb: limited %lud/%lud\n",
|
iprint("iallocb: no memory for %d bytes\n", size);
|
||||||
ialloc.bytes, ialloc.limit);
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((b = _allocb(size, 0)) == nil){
|
|
||||||
if((m2++%10000)==0){
|
|
||||||
if(mp++ > 1000){
|
|
||||||
active.exiting = 1;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
iprint("iallocb: no memory %lud/%lud\n",
|
|
||||||
ialloc.bytes, ialloc.limit);
|
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
setmalloctag(b, getcallerpc());
|
||||||
b->flag = BINTR;
|
b->flag = BINTR;
|
||||||
jehanne_setmalloctag(b->base, getcallerpc());
|
|
||||||
|
|
||||||
ilock(&ialloc);
|
|
||||||
ialloc.bytes += b->lim - b->base;
|
|
||||||
iunlock(&ialloc);
|
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +100,6 @@ void
|
||||||
freeb(Block *b)
|
freeb(Block *b)
|
||||||
{
|
{
|
||||||
void *dead = (void*)Bdead;
|
void *dead = (void*)Bdead;
|
||||||
uint8_t *p;
|
|
||||||
|
|
||||||
if(b == nil)
|
if(b == nil)
|
||||||
return;
|
return;
|
||||||
|
@ -149,17 +108,10 @@ freeb(Block *b)
|
||||||
* drivers which perform non cache coherent DMA manage their own buffer
|
* drivers which perform non cache coherent DMA manage their own buffer
|
||||||
* pool of uncached buffers and provide their own free routine.
|
* pool of uncached buffers and provide their own free routine.
|
||||||
*/
|
*/
|
||||||
if(b->free) {
|
if(b->free != nil) {
|
||||||
b->free(b);
|
b->free(b);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(b->flag & BINTR) {
|
|
||||||
ilock(&ialloc);
|
|
||||||
ialloc.bytes -= b->lim - b->base;
|
|
||||||
iunlock(&ialloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
p = b->base;
|
|
||||||
|
|
||||||
/* poison the block in case someone is still holding onto it */
|
/* poison the block in case someone is still holding onto it */
|
||||||
b->next = dead;
|
b->next = dead;
|
||||||
|
@ -168,7 +120,7 @@ freeb(Block *b)
|
||||||
b->lim = dead;
|
b->lim = dead;
|
||||||
b->base = dead;
|
b->base = dead;
|
||||||
|
|
||||||
jehanne_free(p);
|
free(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -180,10 +132,10 @@ checkb(Block *b, char *msg)
|
||||||
panic("checkb b %s %#p", msg, b);
|
panic("checkb b %s %#p", msg, b);
|
||||||
if(b->base == dead || b->lim == dead || b->next == dead
|
if(b->base == dead || b->lim == dead || b->next == dead
|
||||||
|| b->rp == dead || b->wp == dead){
|
|| b->rp == dead || b->wp == dead){
|
||||||
jehanne_print("checkb: base %#p lim %#p next %#p\n",
|
print("checkb: base %#p lim %#p next %#p\n",
|
||||||
b->base, b->lim, b->next);
|
b->base, b->lim, b->next);
|
||||||
jehanne_print("checkb: rp %#p wp %#p\n", b->rp, b->wp);
|
print("checkb: rp %#p wp %#p\n", b->rp, b->wp);
|
||||||
panic("checkb dead: %s\n", msg);
|
panic("checkb dead: %s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(b->base > b->lim)
|
if(b->base > b->lim)
|
||||||
|
@ -197,9 +149,3 @@ checkb(Block *b, char *msg)
|
||||||
if(b->wp > b->lim)
|
if(b->wp > b->lim)
|
||||||
panic("checkb 4 %s %#p %#p", msg, b->wp, b->lim);
|
panic("checkb 4 %s %#p %#p", msg, b->wp, b->lim);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
iallocsummary(void)
|
|
||||||
{
|
|
||||||
jehanne_print("ialloc %lud/%lud\n", ialloc.bytes, ialloc.limit);
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,333 +21,611 @@
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
typedef struct PendingWakeup PendingWakeup;
|
/* Requirements:
|
||||||
struct PendingWakeup
|
* - each process can register several wakeups
|
||||||
|
* - wakeups registered outside a note handler will not happen
|
||||||
|
* in a note handler
|
||||||
|
* - wakeups registered by a note handler will be deleted on noted()
|
||||||
|
* - all pending wakeups of a process will be deleted on pexit()
|
||||||
|
* - future wakeups can be deleted
|
||||||
|
* - each wakeup will interrupt a blocking syscall
|
||||||
|
*/
|
||||||
|
struct AwakeAlarm /* 24 byte */
|
||||||
{
|
{
|
||||||
short notified;
|
|
||||||
uint64_t time;
|
|
||||||
Proc* p;
|
Proc* p;
|
||||||
PendingWakeup *next;
|
AwakeAlarm* next;
|
||||||
|
unsigned char notified;
|
||||||
|
unsigned char done;
|
||||||
|
unsigned long time : 48;
|
||||||
|
};
|
||||||
|
typedef struct AlarmPool
|
||||||
|
{
|
||||||
|
AwakeAlarm* alarms;
|
||||||
|
AwakeAlarm* end;
|
||||||
|
int size;
|
||||||
|
int first;
|
||||||
|
int nfree;
|
||||||
|
Lock l;
|
||||||
|
} AlarmPool;
|
||||||
|
static AlarmPool awkpool;
|
||||||
|
#define alarm2wkp(a) ~((a)->time << 16 | (a) - awkpool.alarms)
|
||||||
|
#define wkp2alarm(a) (awkpool.alarms + (~(a) & 0xffff))
|
||||||
|
|
||||||
|
static AwakeAlarm *registry;
|
||||||
|
static Lock rl;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum ElapsedAlarmFate
|
||||||
|
{
|
||||||
|
TryAgain,
|
||||||
|
Forget,
|
||||||
|
FreeAndForget
|
||||||
|
} ElapsedAlarmFate;
|
||||||
|
static AwakeAlarm *elapsed, **eEnd = &elapsed;
|
||||||
|
static Lock el;
|
||||||
|
|
||||||
|
static Rendez producer;
|
||||||
|
static Rendez consumer;
|
||||||
|
|
||||||
|
static unsigned long next_wakeup;
|
||||||
|
|
||||||
|
static const int awakeable_syscalls[] = {
|
||||||
|
[SysAwait] = 1,
|
||||||
|
[SysAwake] = 0,
|
||||||
|
[SysBind] = 0,
|
||||||
|
[SysClose] = 0,
|
||||||
|
[SysCreate] = 0,
|
||||||
|
[SysErrstr] = 0,
|
||||||
|
[SysExec] = 0,
|
||||||
|
[Sys_exits] = 0,
|
||||||
|
[SysFauth] = 0,
|
||||||
|
[SysFd2path] = 0,
|
||||||
|
[SysFstat] = 1,
|
||||||
|
[SysFversion] = 0,
|
||||||
|
[SysFwstat] = 1,
|
||||||
|
[SysMount] = 0,
|
||||||
|
[SysNoted] = 0,
|
||||||
|
[SysNotify] = 0,
|
||||||
|
[SysOpen] = 1,
|
||||||
|
[SysPread] = 1,
|
||||||
|
[SysPwrite] = 1,
|
||||||
|
[SysRemove] = 0,
|
||||||
|
[SysRendezvous] = 1,
|
||||||
|
[SysRfork] = 0,
|
||||||
|
[SysSeek] = 0,
|
||||||
|
[SysSemacquire] = 1,
|
||||||
|
[SysSemrelease] = 0,
|
||||||
|
[SysUnmount] = 0,
|
||||||
|
[SysAlarm] = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* alarms: linked list, sorted by wakeup time, protected by qlock(&l)
|
#define DEBUG
|
||||||
* wakeupafter inserts new items, forgivewakeup remove them,
|
|
||||||
* awakekproc consume the expired ones and clearwakeups remove those
|
|
||||||
* survived to their process.
|
|
||||||
*/
|
|
||||||
static PendingWakeup *alarms;
|
|
||||||
static QLock l;
|
|
||||||
|
|
||||||
static Rendez awaker;
|
#ifdef DEBUG
|
||||||
|
|
||||||
int
|
|
||||||
canwakeup(Syscalls scall)
|
|
||||||
{
|
|
||||||
if(scall == 0)
|
|
||||||
panic("canwakeup on page fault");
|
|
||||||
|
|
||||||
switch(scall){
|
|
||||||
default:
|
|
||||||
panic("canwakeup: unknown scall %d\n", scall);
|
|
||||||
case SysFstat:
|
|
||||||
case SysFwstat:
|
|
||||||
case SysOpen:
|
|
||||||
case SysPread:
|
|
||||||
case SysPwrite:
|
|
||||||
case SysRendezvous:
|
|
||||||
case SysSemacquire:
|
|
||||||
case SysSemrelease:
|
|
||||||
case SysAwait:
|
|
||||||
return 1;
|
|
||||||
case SysAwake:
|
|
||||||
case SysBind:
|
|
||||||
case SysClose:
|
|
||||||
case SysCreate:
|
|
||||||
case SysErrstr:
|
|
||||||
case SysExec:
|
|
||||||
case Sys_exits:
|
|
||||||
case SysFauth:
|
|
||||||
case SysFd2path:
|
|
||||||
case SysFversion:
|
|
||||||
case SysMount:
|
|
||||||
case SysNoted:
|
|
||||||
case SysNotify:
|
|
||||||
case SysRemove:
|
|
||||||
case SysRfork:
|
|
||||||
case SysSeek:
|
|
||||||
case SysUnmount:
|
|
||||||
case SysAlarm:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Actually wakeup a process
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
wakeupProc(Proc *p, unsigned long t)
|
|
||||||
{
|
|
||||||
Mpl pl;
|
|
||||||
Rendez *r;
|
|
||||||
Proc *d, **l;
|
|
||||||
|
|
||||||
/* this loop is to avoid lock ordering problems. */
|
|
||||||
for(;;){
|
|
||||||
pl = splhi();
|
|
||||||
lock(&p->rlock);
|
|
||||||
r = p->r;
|
|
||||||
|
|
||||||
/* waiting for a wakeup? */
|
|
||||||
if(r == nil)
|
|
||||||
break; /* no */
|
|
||||||
|
|
||||||
/* try for the second lock */
|
|
||||||
if(canlock(&r->l)){
|
|
||||||
if(p->state != Wakeme || r->p != p)
|
|
||||||
panic("wakeupProc: state %d %d %d", r->p != p, p->r != r, p->state);
|
|
||||||
p->r = nil;
|
|
||||||
r->p = nil;
|
|
||||||
ready(p);
|
|
||||||
unlock(&r->l);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* give other process time to get out of critical section and try again */
|
|
||||||
unlock(&p->rlock);
|
|
||||||
splx(pl);
|
|
||||||
sched();
|
|
||||||
}
|
|
||||||
unlock(&p->rlock);
|
|
||||||
splx(pl);
|
|
||||||
|
|
||||||
p->pendingWakeup = t;
|
|
||||||
if(p->state != Rendezvous)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Try and pull out of a rendezvous */
|
|
||||||
lock(&p->rgrp->l);
|
|
||||||
if(p->state == Rendezvous) {
|
|
||||||
p->rendval = ~0;
|
|
||||||
l = &REND(p->rgrp, p->rendtag);
|
|
||||||
for(d = *l; d; d = d->rendhash) {
|
|
||||||
if(d == p) {
|
|
||||||
*l = p->rendhash;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
l = &d->rendhash;
|
|
||||||
}
|
|
||||||
ready(p);
|
|
||||||
}
|
|
||||||
unlock(&p->rgrp->l);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
awakekproc(void* v)
|
awake_detect_loop(AwakeAlarm *head)
|
||||||
{
|
{
|
||||||
Proc *p;
|
AwakeAlarm *tail;
|
||||||
PendingWakeup *tail, *toAwake, **toAwakeEnd, *toDefer, **toDeferEnd;
|
while(head != nil){
|
||||||
uint64_t now;
|
if(!head->p)
|
||||||
|
panic("awake: free alarm head: %#p, pc %#p", head, getcallerpc());
|
||||||
for(;;){
|
if(head < awkpool.alarms || head > awkpool.end)
|
||||||
now = sys->ticks;
|
panic("awake: not an alarm head: %#p, pc %#p", head, getcallerpc());
|
||||||
toAwake = nil;
|
tail = head->next;
|
||||||
toAwakeEnd = &toAwake;
|
while(tail != nil){
|
||||||
toDefer = nil;
|
if(!tail->p)
|
||||||
toDeferEnd = &toDefer;
|
panic("awake: free alarm tail: %#p, pc %#p", tail, getcallerpc());
|
||||||
|
if(tail < awkpool.alarms || tail > awkpool.end)
|
||||||
/* search for processes to wakeup */
|
panic("awake: not an alarm tail: %#p, pc %#p", tail, getcallerpc());
|
||||||
qlock(&l);
|
if(head == tail)
|
||||||
tail = alarms;
|
panic("awake: loop detected");
|
||||||
while(tail && tail->time <= now){
|
else
|
||||||
if(tail->p->pendingWakeup > tail->p->lastWakeup
|
|
||||||
&& tail->p->state >= Ready){
|
|
||||||
*toDeferEnd = tail;
|
|
||||||
toDeferEnd = &tail->next;
|
|
||||||
} else if (!tail->notified && tail->p->notified){
|
|
||||||
/* If an awake was requested outside of
|
|
||||||
* a note handler, it cannot expire
|
|
||||||
* while executing a note handler.
|
|
||||||
* On the other hand if an awake was
|
|
||||||
* requeted while executing a note handler,
|
|
||||||
* it's up to the note handler to
|
|
||||||
* forgive it if it's not needed anymore.
|
|
||||||
*/
|
|
||||||
*toDeferEnd = tail;
|
|
||||||
toDeferEnd = &tail->next;
|
|
||||||
} else {
|
|
||||||
*toAwakeEnd = tail;
|
|
||||||
toAwakeEnd = &tail->next;
|
|
||||||
--tail->p->wakeups;
|
|
||||||
}
|
|
||||||
tail = tail->next;
|
tail = tail->next;
|
||||||
}
|
}
|
||||||
if(toAwake != nil){
|
head = head->next;
|
||||||
*toAwakeEnd = nil;
|
}
|
||||||
if(toDefer != nil){
|
}
|
||||||
*toDeferEnd = tail;
|
|
||||||
alarms = toDefer;
|
AwakeAlarm*
|
||||||
|
awake_find_first_of(Proc* p, AwakeAlarm* head)
|
||||||
|
{
|
||||||
|
AwakeAlarm* a = head;
|
||||||
|
if(head == nil)
|
||||||
|
return nil;
|
||||||
|
while(a < awkpool.end){
|
||||||
|
if(a->p == p)
|
||||||
|
return a;
|
||||||
|
++a;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
awake_can_interrupt(Syscalls scall)
|
||||||
|
{
|
||||||
|
if(scall == 0)
|
||||||
|
panic("awake_can_interrupts on page fault");
|
||||||
|
if(scall >= sizeof(awakeable_syscalls) - 1)
|
||||||
|
panic("awake_can_interrupts: unknown syscall %d", scall);
|
||||||
|
return awakeable_syscalls[scall];
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
# define awake_detect_loop(h)
|
||||||
|
# define awake_can_interrupt(scall) (awakeable_syscalls[scall])
|
||||||
|
//# undef assert
|
||||||
|
//# define assert(a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
pool_init(void)
|
||||||
|
{
|
||||||
|
awkpool.size = sys->nproc * (sys->nmach + 1);
|
||||||
|
if(awkpool.size >= 1<<16)
|
||||||
|
awkpool.size = 1<<16; /* we have 16 bit in the wakeup token for the index */
|
||||||
|
awkpool.alarms = malloc(sizeof(AwakeAlarm) * awkpool.size);
|
||||||
|
awkpool.end = awkpool.alarms + awkpool.size;
|
||||||
|
awkpool.nfree = awkpool.size;
|
||||||
|
awkpool.first = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AwakeAlarm*
|
||||||
|
alarm_new(Proc *p)
|
||||||
|
{
|
||||||
|
AwakeAlarm *a;
|
||||||
|
|
||||||
|
lock(&awkpool.l);
|
||||||
|
while(awkpool.nfree <= 2*p->nwakeups){
|
||||||
|
unlock(&awkpool.l);
|
||||||
|
resrcwait("wait-wkp", nil);
|
||||||
|
lock(&awkpool.l);
|
||||||
|
}
|
||||||
|
/* here we know that nfree > 0... */
|
||||||
|
if(awkpool.first == awkpool.size){
|
||||||
|
/* but we don't now where the first free is */
|
||||||
|
awkpool.first = -1;
|
||||||
|
while(++awkpool.first < awkpool.size && awkpool.alarms[awkpool.first].p)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
assert(awkpool.first < awkpool.size);
|
||||||
|
|
||||||
|
a = awkpool.alarms + awkpool.first;
|
||||||
|
a->p = p;
|
||||||
|
|
||||||
|
if(adec(&awkpool.nfree) > 0){
|
||||||
|
UpdateFirst:
|
||||||
|
while(++awkpool.first < awkpool.size && awkpool.alarms[awkpool.first].p)
|
||||||
|
;
|
||||||
|
if(awkpool.first == awkpool.size){
|
||||||
|
awkpool.first = -1;
|
||||||
|
goto UpdateFirst;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alarms = tail;
|
awkpool.first = awkpool.size;
|
||||||
}
|
}
|
||||||
}
|
unlock(&awkpool.l);
|
||||||
qunlock(&l);
|
|
||||||
|
|
||||||
/* wakeup sleeping processes */
|
ainc(&p->nwakeups);
|
||||||
while(toAwake != nil){
|
a->done = 0;
|
||||||
p = toAwake->p;
|
a->notified = p->notified ? 1 : 0;
|
||||||
if(p->lastWakeup < toAwake->time && p->state > Ready) {
|
a->time = 0;
|
||||||
/* debugged processes will miss wakeups,
|
a->next = nil;
|
||||||
* but the alternatives seem even worse
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
alarm_free(AwakeAlarm* a)
|
||||||
|
{
|
||||||
|
Proc *p = a->p;
|
||||||
|
#ifdef DEBUG
|
||||||
|
a->next = (void*)getcallerpc();
|
||||||
|
#endif
|
||||||
|
a->p = nil;
|
||||||
|
ainc(&awkpool.nfree);
|
||||||
|
adec(&p->nwakeups);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
awake_fell_asleep(Proc *p)
|
||||||
|
{
|
||||||
|
Syscalls cs = p->cursyscall;
|
||||||
|
if(cs != 0 && cs != SysAwake){
|
||||||
|
/* awake_register might sleep() on alarm_new and we
|
||||||
|
* don't want this sleep to be interrupted.
|
||||||
*/
|
*/
|
||||||
if(canqlock(&p->debug)){
|
p->wakeups[p->notified].blockingsc = cs;
|
||||||
if(!waserror()){
|
p->wakeups[p->notified].fell_asleep = sys->ticks;
|
||||||
wakeupProc(p, toAwake->time);
|
|
||||||
poperror();
|
|
||||||
}
|
}
|
||||||
qunlock(&p->debug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tail = toAwake->next;
|
|
||||||
jehanne_free(toAwake);
|
|
||||||
toAwake = tail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(&awaker, return0, 0);
|
int
|
||||||
|
awake_should_wake_up(Proc *p)
|
||||||
|
{
|
||||||
|
AwakeAlarm *a = p->wakeups[p->notified].elapsed;
|
||||||
|
Syscalls blockingsc = p->wakeups[p->notified].blockingsc;
|
||||||
|
return a != nil
|
||||||
|
&& blockingsc
|
||||||
|
&& awake_can_interrupt(blockingsc)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
awake_awakened(Proc *p)
|
||||||
|
{
|
||||||
|
AwakeAlarm *a;
|
||||||
|
Syscalls blockingsc = p->wakeups[p->notified].blockingsc;
|
||||||
|
if(blockingsc && awake_can_interrupt(blockingsc))
|
||||||
|
if(a = xchgm(&p->wakeups[p->notified].elapsed, nil)){
|
||||||
|
p->wakeups[p->notified].awakened = sys->ticks;
|
||||||
|
p->wakeups[p->notified].last = alarm2wkp(a);
|
||||||
|
p->wakeups[p->notified].blockingsc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called from noted() to remove all pending alarms */
|
||||||
|
void
|
||||||
|
awake_gc_note(Proc *p)
|
||||||
|
{
|
||||||
|
AwakeAlarm *a, **last;
|
||||||
|
|
||||||
|
assert(p->notified != 0);
|
||||||
|
|
||||||
|
lock(&rl);
|
||||||
|
awake_detect_loop(registry);
|
||||||
|
|
||||||
|
/* first pending alarm */
|
||||||
|
a = xchgm(&p->wakeups[1].elapsed, nil);
|
||||||
|
p->wakeups[1].blockingsc = 0;
|
||||||
|
|
||||||
|
/* then clear the registry */
|
||||||
|
last = ®istry;
|
||||||
|
for(a = *last; a != nil && p->wakeups[1].count > 0; a = *last) {
|
||||||
|
if(!a->p)
|
||||||
|
panic("awake_reset: free alarm in registry");
|
||||||
|
if(a->p == p && a->notified){
|
||||||
|
adec(&p->wakeups[a->notified].count);
|
||||||
|
*last = a->next;
|
||||||
|
alarm_free(a);
|
||||||
|
} else {
|
||||||
|
last = &a->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awake_detect_loop(registry);
|
||||||
|
if(registry)
|
||||||
|
next_wakeup = registry->time;
|
||||||
|
unlock(&rl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* called on pexit
|
* called from pexit() and sysexec() to clear all pending
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
clearwakeups(Proc *p)
|
awake_gc_proc(Proc *p)
|
||||||
{
|
{
|
||||||
PendingWakeup *w, **next, *freelist, **fend;
|
AwakeAlarm *a, **last;
|
||||||
|
|
||||||
freelist = nil;
|
/* clear all wakeups (process is exiting) */
|
||||||
|
lock(&rl);
|
||||||
|
awake_detect_loop(registry);
|
||||||
|
|
||||||
/* find all PendingWakeup* to free and remove them from alarms */
|
/* first pending alarm */
|
||||||
qlock(&l);
|
p->wakeups[0].elapsed = nil;
|
||||||
if(p->wakeups){
|
p->wakeups[0].blockingsc = 0;
|
||||||
/* note: qlock(&l) && p->wakeups > 0 => alarms != nil */
|
p->wakeups[1].elapsed = nil;
|
||||||
next = &alarms;
|
p->wakeups[1].blockingsc = 0;
|
||||||
fend = &freelist;
|
|
||||||
clearnext:
|
|
||||||
w = *next;
|
|
||||||
while (w != nil && w->p == p) {
|
|
||||||
/* found one to remove */
|
|
||||||
*fend = w; /* append to freelist */
|
|
||||||
*next = w->next; /* remove from alarms */
|
|
||||||
fend = &w->next; /* move fend to end of freelist */
|
|
||||||
*fend = nil; /* clean the end of freelist */
|
|
||||||
--p->wakeups;
|
|
||||||
w = *next; /* next to analyze */
|
|
||||||
}
|
|
||||||
/* while exited => w == nil || w->p != p */
|
|
||||||
if(p->wakeups){
|
|
||||||
/* note: p->wakeups > 0 => w != nil
|
|
||||||
* p->wakeups > 0 && w->p != p => w->next != nil
|
|
||||||
*/
|
|
||||||
next = &w->next;
|
|
||||||
goto clearnext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qunlock(&l);
|
|
||||||
|
|
||||||
/* free the found PendingWakeup* (out of the lock) */
|
/* then clear the registry */
|
||||||
w = freelist;
|
last = ®istry;
|
||||||
while(w != nil) {
|
for(a = *last; a != nil && (p->wakeups[0].count > 0 || p->wakeups[1].count > 0); a = *last) {
|
||||||
freelist = w->next;
|
if(!a->p)
|
||||||
jehanne_free(w);
|
panic("awake_reset: free alarm in registry");
|
||||||
w = freelist;
|
if(a->p == p){
|
||||||
|
adec(&p->wakeups[a->notified].count);
|
||||||
|
*last = a->next;
|
||||||
|
alarm_free(a);
|
||||||
|
} else {
|
||||||
|
last = &a->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
awake_detect_loop(registry);
|
||||||
|
if(registry)
|
||||||
|
next_wakeup = registry->time;
|
||||||
|
unlock(&rl);
|
||||||
|
|
||||||
|
assert(p->wakeups[0].count == 0);
|
||||||
|
assert(p->wakeups[1].count == 0);
|
||||||
|
|
||||||
|
while(p->nwakeups > 0)
|
||||||
|
resrcwait(nil, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
awake_register(long ms)
|
||||||
|
{
|
||||||
|
AwakeAlarm *a, *new, **last;
|
||||||
|
|
||||||
|
new = alarm_new(up);
|
||||||
|
|
||||||
|
ilock(&rl);
|
||||||
|
last = ®istry;
|
||||||
|
awake_detect_loop(registry);
|
||||||
|
|
||||||
|
new->time = (sys->ticks + ms2tk(ms) + sys->nmach) & 0xffffffffffff;
|
||||||
|
for(a = *last; a != nil && a->time <= new->time; a = *last) {
|
||||||
|
if(!a->p)
|
||||||
|
panic("awake_register: free alarm in registry");
|
||||||
|
if(a->done){
|
||||||
|
adec(&a->p->wakeups[a->notified].count);
|
||||||
|
*last = a->next;
|
||||||
|
alarm_free(a);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(a->time == new->time && a->p == up){
|
||||||
|
/* avoid two alarms at the same tick for a process */
|
||||||
|
++new->time;
|
||||||
|
}
|
||||||
|
last = &a->next;
|
||||||
|
}
|
||||||
|
*last = new;
|
||||||
|
new->next = a;
|
||||||
|
awake_detect_loop(registry);
|
||||||
|
ainc(&up->wakeups[new->notified].count);
|
||||||
|
assert(registry != nil);
|
||||||
|
next_wakeup = registry->time;
|
||||||
|
iunlock(&rl);
|
||||||
|
|
||||||
|
return alarm2wkp(new);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
awake_remove(long request)
|
||||||
|
{
|
||||||
|
AwakeAlarm *a;
|
||||||
|
|
||||||
|
if(request >= up->wakeups[up->notified].last)
|
||||||
|
return 0; /* already free */
|
||||||
|
|
||||||
|
a = wkp2alarm(request);
|
||||||
|
if(a >= awkpool.end)
|
||||||
|
return 0; /* should we send a note to up? */
|
||||||
|
|
||||||
|
if(a->p != up)
|
||||||
|
return 0; /* should we send a note to up? */
|
||||||
|
|
||||||
|
if(a->time != (~request)>>16)
|
||||||
|
return 0; /* should we send a note to up? */
|
||||||
|
|
||||||
|
lock(&rl); /* sync with awake_timer */
|
||||||
|
if(!CASV(&up->wakeups[up->notified].elapsed, a, nil)){
|
||||||
|
a->done = 1;
|
||||||
|
}
|
||||||
|
unlock(&rl);
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
long
|
||||||
|
sysawake(long request)
|
||||||
|
{
|
||||||
|
if(request == 0)
|
||||||
|
return up->wakeups[up->notified].last;
|
||||||
|
if(request < 0)
|
||||||
|
return awake_remove(request);
|
||||||
|
return awake_register(request);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* called every clock tick
|
* called every clock tick
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
checkwakeups(void)
|
awake_tick(unsigned long now)
|
||||||
{
|
{
|
||||||
PendingWakeup *p;
|
if(next_wakeup < now && (now&7) == 0)
|
||||||
uint64_t now;
|
wakeup(&producer);
|
||||||
|
}
|
||||||
|
|
||||||
p = alarms;
|
static void
|
||||||
|
try_wire_process(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* wire to an online processor to reduce context switches
|
||||||
|
* but try to avoid boot processor as it runs awake_tick
|
||||||
|
*/
|
||||||
|
if(up->mach->machno > 0)
|
||||||
|
procwired(up, up->mach->machno);
|
||||||
|
else if(sys->nmach > 1){
|
||||||
|
i = sys->nmach;
|
||||||
|
while(up->wired != nil && i > 1)
|
||||||
|
if(sys->machptr[--i]->online)
|
||||||
|
procwired(up, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
awake_timer(void* v)
|
||||||
|
{
|
||||||
|
long now;
|
||||||
|
AwakeAlarm **next, *tmp, *toAwake, **toAwakeEnd;
|
||||||
|
|
||||||
|
try_wire_process();
|
||||||
|
|
||||||
|
/* initialize wakeups wkppool */
|
||||||
|
pool_init();
|
||||||
|
|
||||||
|
CheckWakeups:
|
||||||
|
next_wakeup = ~0;
|
||||||
|
|
||||||
|
/* we fix time to preserve wakeup order */
|
||||||
now = sys->ticks;
|
now = sys->ticks;
|
||||||
|
|
||||||
if(p && p->time <= now)
|
toAwake = nil;
|
||||||
wakeup(&awaker);
|
toAwakeEnd = &toAwake;
|
||||||
|
|
||||||
|
/* search for processes to wakeup */
|
||||||
|
ilock(&rl);
|
||||||
|
next = ®istry;
|
||||||
|
while((tmp = *next) != nil && tmp->time <= now){
|
||||||
|
if(tmp->p == nil)
|
||||||
|
panic("awake_timer: free alarm in registry");
|
||||||
|
if(tmp->done){
|
||||||
|
*next = tmp->next;
|
||||||
|
adec(&tmp->p->wakeups[tmp->notified].count);
|
||||||
|
alarm_free(tmp);
|
||||||
|
} else {
|
||||||
|
if(!CASV(&tmp->p->wakeups[tmp->notified].elapsed, nil, tmp)){
|
||||||
|
/* each wakeup must have a chance */
|
||||||
|
next = &tmp->next;
|
||||||
|
} else {
|
||||||
|
adec(&tmp->p->wakeups[tmp->notified].count);
|
||||||
|
*toAwakeEnd = tmp;
|
||||||
|
toAwakeEnd = &tmp->next;
|
||||||
|
*next = tmp->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(toAwake != nil)
|
||||||
|
*toAwakeEnd = nil;
|
||||||
|
|
||||||
|
awake_detect_loop(registry);
|
||||||
|
iunlock(&rl);
|
||||||
|
|
||||||
|
if(toAwake != nil){
|
||||||
|
/* pass the elapsed wakeups to awake_ringer preserving order */
|
||||||
|
lock(&el);
|
||||||
|
*eEnd = toAwake;
|
||||||
|
eEnd = toAwakeEnd;
|
||||||
|
unlock(&el);
|
||||||
|
wakeup(&consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
if(registry)
|
||||||
wakeupafter(int64_t ms)
|
next_wakeup = registry->time;
|
||||||
|
|
||||||
|
sleep(&producer, return0, 0);
|
||||||
|
goto CheckWakeups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to wake up a process
|
||||||
|
* Returns:
|
||||||
|
* - 0 if the alarm must be preserved in the elapsed list
|
||||||
|
* - 1 if the alarm must be removed from the elapsed list and freed
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
awake_dispatch(AwakeAlarm *a)
|
||||||
{
|
{
|
||||||
PendingWakeup *w, *new, **last;
|
int canfree;
|
||||||
int64_t when;
|
Rendez *r;
|
||||||
|
Proc *p;
|
||||||
|
Syscalls bs;
|
||||||
|
|
||||||
when = ms2tk(ms) + sys->ticks + 2; /* +2 against round errors and cpu's clocks misalignment */
|
p = a->p;
|
||||||
new = jehanne_mallocz(sizeof(PendingWakeup), 1);
|
if(p == nil)
|
||||||
if(new == nil)
|
panic("awake_dispatch: free alarm in elapsed list");
|
||||||
|
|
||||||
|
if(p < procalloc.arena || p > procalloc.arena + procalloc.nproc)
|
||||||
|
panic("awake_dispatch: dirty alarm");
|
||||||
|
if(!canlock(&p->rlock))
|
||||||
return 0;
|
return 0;
|
||||||
new->p = up;
|
|
||||||
new->notified = up->notified;
|
|
||||||
new->time = when;
|
|
||||||
|
|
||||||
qlock(&l);
|
/* sched() locks p->rlock before setting p->mach and p->state
|
||||||
last = &alarms;
|
*/
|
||||||
for(w = *last; w != nil && w->time <= when; w = w->next) {
|
if(p->mach != nil && p->state <= Running){
|
||||||
last = &w->next;
|
canfree = p->state < Ready;
|
||||||
}
|
goto Done;
|
||||||
new->next = w;
|
|
||||||
*last = new;
|
|
||||||
++up->wakeups;
|
|
||||||
qunlock(&l);
|
|
||||||
|
|
||||||
return -when;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
if(p->wakeups[a->notified].elapsed != a){
|
||||||
forgivewakeup(int64_t time)
|
/* cleared by awake_awakened */
|
||||||
|
canfree = 1;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
canfree = 0;
|
||||||
|
|
||||||
|
if(a->done){
|
||||||
|
/* already signaled, we have to wait for awake_awakened */
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(a->notified && !p->notified){
|
||||||
|
/* this should never happen because p is not Running:
|
||||||
|
* either noted as been called previously (and thus awake_reset)
|
||||||
|
* or it has not
|
||||||
|
*
|
||||||
|
* so if this happens it's probably a but in awake_reset
|
||||||
|
*/
|
||||||
|
unlock(&p->rlock);
|
||||||
|
panic("awake_dispatch: notified alarm for not notified process");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p->notepending && !p->notedeferred){
|
||||||
|
/* notes take precedence */
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs = p->wakeups[a->notified].blockingsc;
|
||||||
|
if(bs == 0 || !awake_can_interrupt(bs)){
|
||||||
|
/* wait for a chance */
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = p->r;
|
||||||
|
if(r != nil){
|
||||||
|
if(canlock(&r->l)){
|
||||||
|
if(p->state != Wakeme || r->p != p)
|
||||||
|
panic("awake_dispatch: state %d %d %d", r->p != p, p->r != r, p->state);
|
||||||
|
a->done = 1;
|
||||||
|
p->r = nil;
|
||||||
|
r->p = nil;
|
||||||
|
ready(p);
|
||||||
|
unlock(&r->l);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(p->state == Rendezvous || p->state == Queueing)
|
||||||
|
if(proc_interrupt_finalize(p))
|
||||||
|
a->done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
unlock(&p->rlock);
|
||||||
|
return canfree;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
awake_ringer(void* v)
|
||||||
{
|
{
|
||||||
PendingWakeup *w, **last;
|
AwakeAlarm *pending, **pLast, **next, *a;
|
||||||
|
|
||||||
if(up->lastWakeup >= time || up->pendingWakeup >= time)
|
pending = nil;
|
||||||
return 0;
|
pLast = &pending;
|
||||||
qlock(&l);
|
|
||||||
if(alarms == nil || up->wakeups == 0){
|
CheckElapsed:
|
||||||
qunlock(&l);
|
lock(&el);
|
||||||
return 0; // nothing to do
|
*pLast = elapsed;
|
||||||
|
elapsed = nil;
|
||||||
|
eEnd = &elapsed;
|
||||||
|
unlock(&el);
|
||||||
|
|
||||||
|
pLast = &pending;
|
||||||
|
next = pLast;
|
||||||
|
while(*next != nil){
|
||||||
|
a = *next;
|
||||||
|
if(awake_dispatch(a)){
|
||||||
|
*next = a->next;
|
||||||
|
alarm_free(a);
|
||||||
|
} else {
|
||||||
|
*pLast = a;
|
||||||
|
next = &a->next;
|
||||||
|
pLast = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last = &alarms;
|
if(pending == nil){
|
||||||
for(w = *last; w != nil && w->time < time; w = w->next) {
|
assert(pLast == &pending);
|
||||||
last = &w->next;
|
sleep(&consumer, return0, 0);
|
||||||
|
} else if(elapsed == nil){
|
||||||
|
tsleep(&up->sleep, return0, 0, 30);
|
||||||
}
|
}
|
||||||
while(w != nil && w->time == time && w->p != up){
|
goto CheckElapsed;
|
||||||
last = &w->next;
|
|
||||||
w = w->next;
|
|
||||||
}
|
|
||||||
if(w == nil || w->time > time || w->p != up){
|
|
||||||
/* wakeup not found */
|
|
||||||
qunlock(&l);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*last = w->next;
|
|
||||||
--up->wakeups;
|
|
||||||
qunlock(&l);
|
|
||||||
|
|
||||||
jehanne_free(w);
|
|
||||||
|
|
||||||
return -time;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t
|
|
||||||
procawake(int64_t ms)
|
|
||||||
{
|
|
||||||
if(ms == 0)
|
|
||||||
return -up->lastWakeup; // nothing to do
|
|
||||||
if(ms < 0)
|
|
||||||
return forgivewakeup(-ms);
|
|
||||||
return wakeupafter(ms);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,360 +0,0 @@
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* - locks
|
|
||||||
* - could instead coalesce free items on demand (cf. Wulf)
|
|
||||||
* - or lazy buddy (cf. Barkley)
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum{
|
|
||||||
MinK= PGSHFT, /* default minimum size (one page) */
|
|
||||||
Nbits= sizeof(uintmem)*8,
|
|
||||||
MaxK= Nbits-1, /* last usable k (largest block is 2^k) */
|
|
||||||
|
|
||||||
Busy= 0x80, /* bit set in byte map if block busy (low order bits are block size, 0=unavailable) */
|
|
||||||
};
|
|
||||||
|
|
||||||
//#define usize uintmem
|
|
||||||
|
|
||||||
typedef struct Blk Blk;
|
|
||||||
struct Blk{
|
|
||||||
Blk* forw; /* free list */
|
|
||||||
Blk* back;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Bfree Bfree;
|
|
||||||
struct Bfree{
|
|
||||||
Blk h; /* header */
|
|
||||||
Lock;
|
|
||||||
uint32_t avail;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Bpool{
|
|
||||||
Lock lk; /* TO DO: localise lock (need CAS update of pool->kofb) (also see Johnson & Davis 1992) */
|
|
||||||
Bfree blist[Nbits]; /* increasing powers of two */
|
|
||||||
uint8_t* kofb; /* k(block_index) with top bit set if busy */
|
|
||||||
uint32_t mink;
|
|
||||||
uint32_t maxk;
|
|
||||||
uint32_t maxb; /* limit to block index, in minbsize blocks (pool size) */
|
|
||||||
Blk* blocks; /* free list pointers */
|
|
||||||
uintmem base;
|
|
||||||
uintmem minbsize;
|
|
||||||
uintmem limit;
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint8_t lg2table[256] = {
|
|
||||||
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define BI(a) ((a)>>pool->mink)
|
|
||||||
#define IB(x) ((uintmem)(x)<<pool->mink)
|
|
||||||
|
|
||||||
static int
|
|
||||||
lg2ceil(uintmem m)
|
|
||||||
{
|
|
||||||
uint32_t n, h;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = (m & (m-1)) != 0; /* not a power of two => round up */
|
|
||||||
n = (uint32_t)m;
|
|
||||||
if(sizeof(uintmem)>sizeof(uint32_t)){
|
|
||||||
h = (uint64_t)m>>32;
|
|
||||||
if(h != 0){
|
|
||||||
n = h;
|
|
||||||
r += 32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if((n>>8) == 0)
|
|
||||||
return lg2table[n] + r;
|
|
||||||
if((n>>16) == 0)
|
|
||||||
return 8 + lg2table[n>>8] + r;
|
|
||||||
if((n>>24) == 0)
|
|
||||||
return 16 + lg2table[n>>16] + r;
|
|
||||||
return 24 + lg2table[n>>24] + r;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bpool*
|
|
||||||
bpoolcreate(uint32_t mink, uint32_t maxk, uintmem base, uintmem top, void* (*alloc)(usize, int))
|
|
||||||
{
|
|
||||||
int k;
|
|
||||||
Blk *b;
|
|
||||||
Bpool *pool;
|
|
||||||
|
|
||||||
if(mink == 0)
|
|
||||||
mink = MinK;
|
|
||||||
if(maxk > MaxK)
|
|
||||||
panic("bpoolcreate");
|
|
||||||
pool = alloc(sizeof(Bpool), 1);
|
|
||||||
if(pool == nil)
|
|
||||||
panic("bpoolcreate alloc");
|
|
||||||
pool->mink = mink;
|
|
||||||
pool->maxk = maxk;
|
|
||||||
pool->base = base;
|
|
||||||
pool->limit = top;
|
|
||||||
pool->maxb = BI(top-base);
|
|
||||||
pool->minbsize = (uintmem)1<<mink;
|
|
||||||
pool->blocks = alloc((pool->maxb+1)*sizeof(*pool->blocks), 0);
|
|
||||||
if(pool->blocks == nil)
|
|
||||||
panic("bpoolinit: can't allocate %ud blocks", pool->maxb+1);
|
|
||||||
for(k = 0; k < nelem(pool->blist); k++){
|
|
||||||
b = &pool->blist[k].h;
|
|
||||||
b->forw = b->back = b;
|
|
||||||
}
|
|
||||||
pool->kofb = alloc((pool->maxb+1)*sizeof(*pool->kofb), 1);
|
|
||||||
if(pool->kofb == nil)
|
|
||||||
panic("physinit: can't allocate %ud kofb", pool->maxb+1);
|
|
||||||
jehanne_print("pool %#p space base %#P top=%#P maxb=%#ux (%d)\n", pool, base, top, pool->maxb, pool->maxb);
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintmem
|
|
||||||
bpoolalloc(Bpool *pool, usize size)
|
|
||||||
{
|
|
||||||
int j, k;
|
|
||||||
Blk *b, *b2;
|
|
||||||
uintmem a, a2;
|
|
||||||
uint32_t bi;
|
|
||||||
|
|
||||||
k = lg2ceil(size);
|
|
||||||
if(k < pool->mink)
|
|
||||||
k = pool->mink;
|
|
||||||
if(k > pool->maxk)
|
|
||||||
return 0;
|
|
||||||
DBG("%#p size=%#P k=%d\n", pool, (uintmem)size, k);
|
|
||||||
lock(&pool->lk);
|
|
||||||
for(j = k;;){
|
|
||||||
b = pool->blist[j].h.forw;
|
|
||||||
if(b != &pool->blist[j].h)
|
|
||||||
break;
|
|
||||||
if(++j > pool->maxk){
|
|
||||||
unlock(&pool->lk);
|
|
||||||
return 0; /* out of space */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(b == nil)
|
|
||||||
panic("physalloc: nil");
|
|
||||||
/* set busy state */
|
|
||||||
bi = b - pool->blocks;
|
|
||||||
if(pool->kofb[bi] & Busy || b->forw == nil || b->back == nil)
|
|
||||||
panic("physalloc: inval k=%d j=%d %#p %d %#ux %#p %#p", k, j, b, bi, pool->kofb[bi], b->forw, b->back);
|
|
||||||
pool->kofb[bi] = k | Busy;
|
|
||||||
pool->blist[j].avail--;
|
|
||||||
b->forw->back = b->back;
|
|
||||||
b->back->forw = b->forw;
|
|
||||||
a = IB(bi);
|
|
||||||
while(j != k){
|
|
||||||
/* split */
|
|
||||||
j--;
|
|
||||||
a2 = a+((uintmem)1<<j);
|
|
||||||
bi = BI(a2);
|
|
||||||
DBG("split %#llux %#llux k=%d %#llux pool->kofb=%#ux\n", a, a2, j, (uintmem)1<<j, pool->kofb[bi]);
|
|
||||||
if(pool->kofb[bi] & Busy){
|
|
||||||
if(pool->kofb[bi] & ~Busy)
|
|
||||||
panic("bal: busy block %#llux k=%d\n", a, pool->kofb[bi] & ~Busy);
|
|
||||||
}
|
|
||||||
pool->kofb[bi] = j; /* new size, not busy */
|
|
||||||
b2 = &pool->blocks[bi];
|
|
||||||
b2->forw = &pool->blist[j].h;
|
|
||||||
b2->back = pool->blist[j].h.back;
|
|
||||||
pool->blist[j].h.back = b2;
|
|
||||||
b2->back->forw = b2;
|
|
||||||
pool->blist[j].avail++;
|
|
||||||
}
|
|
||||||
unlock(&pool->lk);
|
|
||||||
return a + pool->base;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
bpoolfree(Bpool *pool, uintmem a, usize size)
|
|
||||||
{
|
|
||||||
int k;
|
|
||||||
Blk *b, *b2;
|
|
||||||
uintmem a2;
|
|
||||||
uint32_t bi, bi2;
|
|
||||||
|
|
||||||
k = lg2ceil(size); /* could look it up in pool->kofb */
|
|
||||||
if(k < pool->mink)
|
|
||||||
return;
|
|
||||||
if(k > pool->maxk)
|
|
||||||
k = pool->maxk;
|
|
||||||
DBG("%#p free %#llux %#P k%d\n", pool, a, (uintmem)size, k);
|
|
||||||
if(a < pool->base)
|
|
||||||
panic("bpoolfree");
|
|
||||||
a -= pool->base;
|
|
||||||
bi = BI(a);
|
|
||||||
lock(&pool->lk);
|
|
||||||
if(pool->kofb[bi] != 0 && pool->kofb[bi] != (Busy|k)){
|
|
||||||
unlock(&pool->lk);
|
|
||||||
panic("balfree: busy %#llux odd k k=%d kofb=%#ux\n", a, k, pool->kofb[bi]);
|
|
||||||
}
|
|
||||||
for(; k != pool->maxk; k++){
|
|
||||||
pool->kofb[bi] = Busy;
|
|
||||||
a2 = a ^ ((uintmem)1<<k); /* buddy */
|
|
||||||
bi2 = BI(a2);
|
|
||||||
b2 = &pool->blocks[bi2];
|
|
||||||
if(bi2 >= pool->maxb || pool->kofb[bi2] != k)
|
|
||||||
break;
|
|
||||||
/* valid, not busy or empty, size k */
|
|
||||||
DBG("combine %#llux %#llux %d %#llux\n", a, a2, k, (uintmem)1<<k);
|
|
||||||
b2->back->forw = b2->forw;
|
|
||||||
b2->forw->back = b2->back;
|
|
||||||
pool->kofb[bi2] = Busy;
|
|
||||||
pool->blist[k].avail--;
|
|
||||||
if(a2 < a){
|
|
||||||
a = a2;
|
|
||||||
bi = bi2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pool->kofb[bi] = k; /* sets size and resets Busy */
|
|
||||||
b = &pool->blocks[bi];
|
|
||||||
b->forw = &pool->blist[k].h;
|
|
||||||
b->back = pool->blist[k].h.back;
|
|
||||||
pool->blist[k].h.back = b;
|
|
||||||
b->back->forw = b;
|
|
||||||
pool->blist[k].avail++;
|
|
||||||
unlock(&pool->lk);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
bpoolallocrange(Bpool *pool, usize *low, usize *high)
|
|
||||||
{
|
|
||||||
*low = (usize)1<<pool->mink;
|
|
||||||
*high = (usize)1<<pool->maxk;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ibpoolfree(Bpool *pool, uintmem base, usize size)
|
|
||||||
{
|
|
||||||
bpoolfree(pool, base+pool->base, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
bpoolinitfree(Bpool *pool, uintmem base, uintmem lim)
|
|
||||||
{
|
|
||||||
uintmem m, size;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* chop limit to min block alignment */
|
|
||||||
if(base >= pool->limit)
|
|
||||||
return;
|
|
||||||
if(pool->base > base)
|
|
||||||
base = pool->base;
|
|
||||||
if(lim > pool->limit)
|
|
||||||
lim = pool->limit;
|
|
||||||
base -= pool->base;
|
|
||||||
lim -= pool->base;
|
|
||||||
lim &= ~(pool->minbsize-1);
|
|
||||||
if(BI(lim) > pool->maxb){
|
|
||||||
jehanne_print("physinitfree: address space too large");
|
|
||||||
lim = IB(pool->maxb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* round base to min block alignment */
|
|
||||||
base = (base + pool->minbsize-1) & ~(pool->minbsize-1);
|
|
||||||
|
|
||||||
size = lim - base;
|
|
||||||
if(size < pool->minbsize)
|
|
||||||
return;
|
|
||||||
DBG("bpoolinitfree %#p %#P-%#P [%#P]\n", pool, pool->base+base, pool->base+lim, size);
|
|
||||||
|
|
||||||
/* move up from base in largest blocks that remain aligned */
|
|
||||||
for(i=pool->mink; i<pool->maxk; i++){
|
|
||||||
m = (uintmem)1 << i;
|
|
||||||
if(base & m){
|
|
||||||
if(size < m)
|
|
||||||
break;
|
|
||||||
if(base & (m-1)){
|
|
||||||
jehanne_print(" ** error: %#P %#P\n", base, m);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ibpoolfree(pool, base, m);
|
|
||||||
base += m;
|
|
||||||
size -= m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* largest chunks, aligned */
|
|
||||||
m = (uintmem)1<<pool->maxk;
|
|
||||||
while(size >= m){
|
|
||||||
if(base & (m-1)){
|
|
||||||
jehanne_print(" ** error: %#P %#P\n", base, m);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ibpoolfree(pool, base, m);
|
|
||||||
base += m;
|
|
||||||
size -= m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* free remaining chunks, decreasing alignment */
|
|
||||||
for(; size >= pool->minbsize; m >>= 1){
|
|
||||||
if(size & m){
|
|
||||||
DBG("\t%#P %#P\n", base, m);
|
|
||||||
if(base & (m-1)){
|
|
||||||
jehanne_print(" ** error: %#P %#P\n", base, m);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ibpoolfree(pool, base, m);
|
|
||||||
base += m;
|
|
||||||
size &= ~m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
seprintbpoolstats(Bpool *pool, char *s, char *e)
|
|
||||||
{
|
|
||||||
Bfree *b;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
lock(&pool->lk);
|
|
||||||
for(i = 0; i < nelem(pool->blist); i++){
|
|
||||||
b = &pool->blist[i];
|
|
||||||
if(b->avail != 0)
|
|
||||||
s = jehanne_seprint(s, e, "%ud %ulldK blocks avail\n",
|
|
||||||
b->avail, (1ull<<i)/KiB);
|
|
||||||
}
|
|
||||||
unlock(&pool->lk);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
bpooldump(Bpool *pool)
|
|
||||||
{
|
|
||||||
uintmem a;
|
|
||||||
uint32_t bi;
|
|
||||||
int i, k;
|
|
||||||
Blk *b;
|
|
||||||
|
|
||||||
for(i=0; i<nelem(pool->blist); i++){
|
|
||||||
b = pool->blist[i].h.forw;
|
|
||||||
if(b != &pool->blist[i].h){
|
|
||||||
jehanne_print("%d ", i);
|
|
||||||
for(; b != &pool->blist[i].h; b = b->forw){
|
|
||||||
bi = b-pool->blocks;
|
|
||||||
a = IB(bi);
|
|
||||||
k = pool->kofb[bi];
|
|
||||||
jehanne_print(" [%#llux %d %#ux b=%#llux]", a, k, 1<<k, a^((uintmem)1<<k));
|
|
||||||
}
|
|
||||||
jehanne_print("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,543 +0,0 @@
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
NHASH = 128,
|
|
||||||
MAXCACHE = 1024*1024,
|
|
||||||
NFILE = 4096,
|
|
||||||
NEXTENT = 200, /* extent allocation size */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Extent Extent;
|
|
||||||
struct Extent
|
|
||||||
{
|
|
||||||
uint32_t start;
|
|
||||||
int len;
|
|
||||||
char *cache;
|
|
||||||
Extent *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Mntcache Mntcache;
|
|
||||||
struct Mntcache
|
|
||||||
{
|
|
||||||
Qid qid;
|
|
||||||
uint32_t devno;
|
|
||||||
Dev* dev;
|
|
||||||
QLock;
|
|
||||||
Extent *list;
|
|
||||||
Mntcache *hash;
|
|
||||||
Mntcache *prev;
|
|
||||||
Mntcache *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Cache Cache;
|
|
||||||
struct Cache
|
|
||||||
{
|
|
||||||
Lock l;
|
|
||||||
int pgno;
|
|
||||||
Mntcache *head;
|
|
||||||
Mntcache *tail;
|
|
||||||
Mntcache *hash[NHASH];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Ecache Ecache;
|
|
||||||
struct Ecache
|
|
||||||
{
|
|
||||||
Lock l;
|
|
||||||
int total;
|
|
||||||
int free;
|
|
||||||
Extent* head;
|
|
||||||
};
|
|
||||||
|
|
||||||
//static Image fscache; // not used
|
|
||||||
static Cache cache;
|
|
||||||
static Ecache ecache;
|
|
||||||
static int maxcache = MAXCACHE;
|
|
||||||
|
|
||||||
static void
|
|
||||||
extentfree(Extent* e)
|
|
||||||
{
|
|
||||||
jehanne_free(e->cache);
|
|
||||||
e->cache = nil;
|
|
||||||
lock(&ecache.l);
|
|
||||||
e->next = ecache.head;
|
|
||||||
ecache.head = e;
|
|
||||||
ecache.free++;
|
|
||||||
unlock(&ecache.l);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Extent*
|
|
||||||
extentalloc(void)
|
|
||||||
{
|
|
||||||
Extent *e;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
lock(&ecache.l);
|
|
||||||
if(ecache.head == nil){
|
|
||||||
e = jehanne_malloc(NEXTENT*sizeof(Extent));
|
|
||||||
if(e == nil){
|
|
||||||
unlock(&ecache.l);
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
for(i = 0; i < NEXTENT; i++){
|
|
||||||
e->next = ecache.head;
|
|
||||||
ecache.head = e;
|
|
||||||
e++;
|
|
||||||
}
|
|
||||||
ecache.free += NEXTENT;
|
|
||||||
ecache.total += NEXTENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
e = ecache.head;
|
|
||||||
ecache.head = e->next;
|
|
||||||
jehanne_memset(e, 0, sizeof(Extent));
|
|
||||||
ecache.free--;
|
|
||||||
unlock(&ecache.l);
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
cinit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Mntcache *mc;
|
|
||||||
|
|
||||||
if((cache.head = jehanne_malloc(sizeof(Mntcache)*NFILE)) == nil)
|
|
||||||
panic("cinit: no memory");
|
|
||||||
mc = cache.head;
|
|
||||||
|
|
||||||
/* a good algorithm to set maxcache would be nice */
|
|
||||||
|
|
||||||
for(i = 0; i < NFILE-1; i++) {
|
|
||||||
mc->next = mc+1;
|
|
||||||
mc->prev = mc-1;
|
|
||||||
mc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.tail = mc;
|
|
||||||
cache.tail->next = 0;
|
|
||||||
cache.head->prev = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
cnodata(Mntcache *mc)
|
|
||||||
{
|
|
||||||
Extent *e, *n;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Invalidate all extent data
|
|
||||||
* Image lru will waste the pages
|
|
||||||
*/
|
|
||||||
for(e = mc->list; e; e = n) {
|
|
||||||
n = e->next;
|
|
||||||
extentfree(e);
|
|
||||||
}
|
|
||||||
mc->list = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ctail(Mntcache *mc)
|
|
||||||
{
|
|
||||||
/* Unlink and send to the tail */
|
|
||||||
if(mc->prev)
|
|
||||||
mc->prev->next = mc->next;
|
|
||||||
else
|
|
||||||
cache.head = mc->next;
|
|
||||||
if(mc->next)
|
|
||||||
mc->next->prev = mc->prev;
|
|
||||||
else
|
|
||||||
cache.tail = mc->prev;
|
|
||||||
|
|
||||||
if(cache.tail) {
|
|
||||||
mc->prev = cache.tail;
|
|
||||||
cache.tail->next = mc;
|
|
||||||
mc->next = 0;
|
|
||||||
cache.tail = mc;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cache.head = mc;
|
|
||||||
cache.tail = mc;
|
|
||||||
mc->prev = 0;
|
|
||||||
mc->next = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
copen(Chan *c)
|
|
||||||
{
|
|
||||||
int h;
|
|
||||||
Extent *e, *next;
|
|
||||||
Mntcache *mc, *f, **l;
|
|
||||||
|
|
||||||
/* directories aren't cacheable and append-only files confuse us */
|
|
||||||
if(c->qid.type&(QTDIR|QTAPPEND))
|
|
||||||
return;
|
|
||||||
|
|
||||||
h = c->qid.path%NHASH;
|
|
||||||
lock(&cache.l);
|
|
||||||
for(mc = cache.hash[h]; mc != nil; mc = mc->hash) {
|
|
||||||
if(mc->qid.path == c->qid.path)
|
|
||||||
if(mc->qid.type == c->qid.type)
|
|
||||||
if(mc->devno == c->devno && mc->dev == c->dev) {
|
|
||||||
c->mc = mc;
|
|
||||||
ctail(mc);
|
|
||||||
unlock(&cache.l);
|
|
||||||
|
|
||||||
/* File was updated, invalidate cache */
|
|
||||||
if(mc->qid.vers != c->qid.vers) {
|
|
||||||
mc->qid.vers = c->qid.vers;
|
|
||||||
qlock(mc);
|
|
||||||
cnodata(mc);
|
|
||||||
qunlock(mc);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* LRU the cache headers */
|
|
||||||
mc = cache.head;
|
|
||||||
l = &cache.hash[mc->qid.path%NHASH];
|
|
||||||
for(f = *l; f; f = f->hash) {
|
|
||||||
if(f == mc) {
|
|
||||||
*l = mc->hash;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
l = &f->hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
mc->qid = c->qid;
|
|
||||||
mc->devno = c->devno;
|
|
||||||
mc->dev = c->dev;
|
|
||||||
|
|
||||||
l = &cache.hash[h];
|
|
||||||
mc->hash = *l;
|
|
||||||
*l = mc;
|
|
||||||
ctail(mc);
|
|
||||||
|
|
||||||
qlock(mc);
|
|
||||||
c->mc = mc;
|
|
||||||
e = mc->list;
|
|
||||||
mc->list = 0;
|
|
||||||
unlock(&cache.l);
|
|
||||||
|
|
||||||
while(e) {
|
|
||||||
next = e->next;
|
|
||||||
extentfree(e);
|
|
||||||
e = next;
|
|
||||||
}
|
|
||||||
qunlock(mc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
cdev(Mntcache *mc, Chan *c)
|
|
||||||
{
|
|
||||||
if(mc->qid.path != c->qid.path)
|
|
||||||
return 0;
|
|
||||||
if(mc->qid.type != c->qid.type)
|
|
||||||
return 0;
|
|
||||||
if(mc->devno != c->devno)
|
|
||||||
return 0;
|
|
||||||
if(mc->dev != c->dev)
|
|
||||||
return 0;
|
|
||||||
if(mc->qid.vers != c->qid.vers)
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
cread(Chan *c, uint8_t *buf, int len, int64_t off)
|
|
||||||
{
|
|
||||||
char *p;
|
|
||||||
Mntcache *mc;
|
|
||||||
Extent *e, **t;
|
|
||||||
int o, l, total;
|
|
||||||
uint32_t offset;
|
|
||||||
|
|
||||||
if(off+len > maxcache)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mc = c->mc;
|
|
||||||
if(mc == nil)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
qlock(mc);
|
|
||||||
if(cdev(mc, c) == 0) {
|
|
||||||
qunlock(mc);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = off;
|
|
||||||
t = &mc->list;
|
|
||||||
for(e = *t; e; e = e->next) {
|
|
||||||
if(offset >= e->start && offset < e->start+e->len)
|
|
||||||
break;
|
|
||||||
t = &e->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(e == 0) {
|
|
||||||
qunlock(mc);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
total = 0;
|
|
||||||
while(len) {
|
|
||||||
p = e->cache;
|
|
||||||
if(p == nil){
|
|
||||||
*t = e->next;
|
|
||||||
extentfree(e);
|
|
||||||
qunlock(mc);
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
o = offset - e->start;
|
|
||||||
l = len;
|
|
||||||
if(l > e->len-o)
|
|
||||||
l = e->len-o;
|
|
||||||
|
|
||||||
if(waserror()) {
|
|
||||||
qunlock(mc);
|
|
||||||
nexterror();
|
|
||||||
}
|
|
||||||
|
|
||||||
jehanne_memmove(buf, p+o, l);
|
|
||||||
|
|
||||||
poperror();
|
|
||||||
|
|
||||||
buf += l;
|
|
||||||
len -= l;
|
|
||||||
offset += l;
|
|
||||||
total += l;
|
|
||||||
t = &e->next;
|
|
||||||
e = e->next;
|
|
||||||
if(e == 0 || e->start != offset)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
qunlock(mc);
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
Extent*
|
|
||||||
cchain(uint8_t *buf, uint32_t offset, int len, Extent **tail)
|
|
||||||
{
|
|
||||||
int l;
|
|
||||||
char *p;
|
|
||||||
Extent *e, *start, **t;
|
|
||||||
|
|
||||||
start = 0;
|
|
||||||
*tail = 0;
|
|
||||||
t = &start;
|
|
||||||
while(len) {
|
|
||||||
e = extentalloc();
|
|
||||||
if(e == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
p = jehanne_mallocz(PGSZ, 0);
|
|
||||||
if(p == nil){
|
|
||||||
extentfree(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
l = len;
|
|
||||||
if(l > PGSZ)
|
|
||||||
l = PGSZ;
|
|
||||||
|
|
||||||
e->cache = p;
|
|
||||||
e->start = offset;
|
|
||||||
e->len = l;
|
|
||||||
|
|
||||||
jehanne_memmove(p, buf, l);
|
|
||||||
|
|
||||||
buf += l;
|
|
||||||
offset += l;
|
|
||||||
len -= l;
|
|
||||||
|
|
||||||
*t = e;
|
|
||||||
*tail = e;
|
|
||||||
t = &e->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
cpgmove(Extent *e, uint8_t *buf, int boff, int len)
|
|
||||||
{
|
|
||||||
if(e->cache == nil){
|
|
||||||
/* shouldn't happen */
|
|
||||||
jehanne_print("CACHE: cpgmove %#p %d %d nil\n", e, boff, len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
jehanne_memmove(e->cache+boff, buf, len);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
cupdate(Chan *c, uint8_t *buf, int len, int64_t off)
|
|
||||||
{
|
|
||||||
Mntcache *mc;
|
|
||||||
Extent *tail;
|
|
||||||
Extent *e, *f, *p;
|
|
||||||
int o, ee, eblock;
|
|
||||||
uint32_t offset;
|
|
||||||
|
|
||||||
if(off > maxcache || len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mc = c->mc;
|
|
||||||
if(mc == nil)
|
|
||||||
return;
|
|
||||||
qlock(mc);
|
|
||||||
if(cdev(mc, c) == 0) {
|
|
||||||
qunlock(mc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find the insertion point
|
|
||||||
*/
|
|
||||||
offset = off;
|
|
||||||
p = 0;
|
|
||||||
for(f = mc->list; f; f = f->next) {
|
|
||||||
if(f->start > offset)
|
|
||||||
break;
|
|
||||||
p = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* trim if there is a successor */
|
|
||||||
eblock = offset+len;
|
|
||||||
if(f != 0 && eblock > f->start) {
|
|
||||||
len -= (eblock - f->start);
|
|
||||||
if(len <= 0) {
|
|
||||||
qunlock(mc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p == 0) { /* at the head */
|
|
||||||
e = cchain(buf, offset, len, &tail);
|
|
||||||
if(e != 0) {
|
|
||||||
mc->list = e;
|
|
||||||
tail->next = f;
|
|
||||||
}
|
|
||||||
qunlock(mc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* trim to the predecessor */
|
|
||||||
ee = p->start+p->len;
|
|
||||||
if(offset < ee) {
|
|
||||||
o = ee - offset;
|
|
||||||
len -= o;
|
|
||||||
if(len <= 0) {
|
|
||||||
qunlock(mc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
buf += o;
|
|
||||||
offset += o;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* try and pack data into the predecessor */
|
|
||||||
if(offset == ee && p->len < PGSZ) {
|
|
||||||
o = len;
|
|
||||||
if(o > PGSZ - p->len)
|
|
||||||
o = PGSZ - p->len;
|
|
||||||
if(cpgmove(p, buf, p->len, o)) {
|
|
||||||
p->len += o;
|
|
||||||
buf += o;
|
|
||||||
len -= o;
|
|
||||||
offset += o;
|
|
||||||
if(len <= 0) {
|
|
||||||
if(f && p->start + p->len > f->start) jehanne_print("CACHE: p->start=%uld p->len=%d f->start=%uld\n", p->start, p->len, f->start);
|
|
||||||
qunlock(mc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e = cchain(buf, offset, len, &tail);
|
|
||||||
if(e != 0) {
|
|
||||||
p->next = e;
|
|
||||||
tail->next = f;
|
|
||||||
}
|
|
||||||
qunlock(mc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
cwrite(Chan* c, uint8_t *buf, int len, int64_t off)
|
|
||||||
{
|
|
||||||
int o, eo;
|
|
||||||
Mntcache *mc;
|
|
||||||
uint32_t eblock, ee;
|
|
||||||
Extent *p, *f, *e, *tail;
|
|
||||||
uint32_t offset;
|
|
||||||
|
|
||||||
if(off > maxcache || len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mc = c->mc;
|
|
||||||
if(mc == nil)
|
|
||||||
return;
|
|
||||||
|
|
||||||
qlock(mc);
|
|
||||||
if(cdev(mc, c) == 0) {
|
|
||||||
qunlock(mc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = off;
|
|
||||||
mc->qid.vers++;
|
|
||||||
c->qid.vers++;
|
|
||||||
|
|
||||||
p = 0;
|
|
||||||
for(f = mc->list; f; f = f->next) {
|
|
||||||
if(f->start >= offset)
|
|
||||||
break;
|
|
||||||
p = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p != 0) {
|
|
||||||
ee = p->start+p->len;
|
|
||||||
eo = offset - p->start;
|
|
||||||
/* pack in predecessor if there is space */
|
|
||||||
if(offset <= ee && eo < PGSZ) {
|
|
||||||
o = len;
|
|
||||||
if(o > PGSZ - eo)
|
|
||||||
o = PGSZ - eo;
|
|
||||||
if(cpgmove(p, buf, eo, o)) {
|
|
||||||
if(eo+o > p->len)
|
|
||||||
p->len = eo+o;
|
|
||||||
buf += o;
|
|
||||||
len -= o;
|
|
||||||
offset += o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* free the overlap -- it's a rare case */
|
|
||||||
eblock = offset+len;
|
|
||||||
while(f && f->start < eblock) {
|
|
||||||
e = f->next;
|
|
||||||
extentfree(f);
|
|
||||||
f = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* link the block (if any) into the middle */
|
|
||||||
e = cchain(buf, offset, len, &tail);
|
|
||||||
if(e != 0) {
|
|
||||||
tail->next = f;
|
|
||||||
f = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p == 0)
|
|
||||||
mc->list = f;
|
|
||||||
else
|
|
||||||
p->next = f;
|
|
||||||
qunlock(mc);
|
|
||||||
}
|
|
|
@ -151,7 +151,6 @@ newchan(void)
|
||||||
c->dri = 0;
|
c->dri = 0;
|
||||||
c->aux = 0;
|
c->aux = 0;
|
||||||
c->mchan = 0;
|
c->mchan = 0;
|
||||||
c->mc = 0;
|
|
||||||
c->mux = 0;
|
c->mux = 0;
|
||||||
jehanne_memset(&c->mqid, 0, sizeof(c->mqid));
|
jehanne_memset(&c->mqid, 0, sizeof(c->mqid));
|
||||||
c->path = 0;
|
c->path = 0;
|
||||||
|
@ -1442,9 +1441,6 @@ namec(char *aname, int amode, long omode, long perm)
|
||||||
/* save registers else error() in open has wrong value of c saved */
|
/* save registers else error() in open has wrong value of c saved */
|
||||||
saveregisters();
|
saveregisters();
|
||||||
|
|
||||||
if(omode == OEXEC)
|
|
||||||
c->flag &= ~CCACHE;
|
|
||||||
|
|
||||||
c = c->dev->open(c, omode&~OCEXEC);
|
c = c->dev->open(c, omode&~OCEXEC);
|
||||||
|
|
||||||
if(omode & OCEXEC)
|
if(omode & OCEXEC)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue