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:
Giacomo Tesio 2017-08-11 01:47:15 +02:00
parent 1bc08b7631
commit 93dde48355
145 changed files with 34164 additions and 33891 deletions

View File

@ -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 int memlineendsize(int);
extern void _memmkcmap(void);
extern void memimageinit(void);
extern int memimageinit(void);
/*
* Subfont management

View File

@ -9,40 +9,39 @@
typedef struct Pool Pool;
struct Pool {
char* name;
uint32_t maxsize;
char* name;
uintptr_t maxsize;
uint32_t cursize;
uint32_t curfree;
uint32_t curalloc;
uintptr_t cursize;
uintptr_t curfree;
uintptr_t curalloc;
uint32_t minarena; /* smallest size of new arena */
uint32_t quantum; /* allocated blocks should be multiple of */
uint32_t minblock; /* smallest newly allocated block */
void* freeroot; /* actually Free* */
void* arenalist; /* actually Arena* */
int flags;
int nfree;
int lastcompact;
void* (*alloc)(uint32_t);
int (*merge)(void*, void*);
void (*move)(void* from, void* to);
void* freeroot; /* actually Free* */
void* arenalist; /* actually Arena* */
int flags;
int nfree;
int lastcompact;
void* (*alloc)(uint32_t);
int (*merge)(void*, void*);
void (*move)(void* from, void* to);
void (*lock)(Pool*);
void (*unlock)(Pool*);
void (*print)(Pool*, char*, ...);
void (*panic)(Pool*, char*, ...);
void (*logstack)(Pool*);
void (*lock)(Pool*);
void (*unlock)(Pool*);
void (*print)(Pool*, char*, ...);
void (*panic)(Pool*, char*, ...);
void (*logstack)(Pool*);
void* private;
void* private;
};
extern void* poolalloc(Pool*, uint32_t);
extern void* poolallocalign(Pool*, uint32_t, uint32_t, int32_t,
uint32_t);
extern void* poolallocalign(Pool*, uint32_t, uint32_t, int32_t, uint32_t);
extern void poolfree(Pool*, void*);
extern uint32_t poolmsize(Pool*, void*);
extern void* poolrealloc(Pool*, void*, uint32_t);

View File

@ -57,8 +57,8 @@ main(int argc, char *argv[])
srv = "screenconsole";
/* first try in /dev so that binding can work */
if((fd = open("/dev/ps2keyb", OREAD)) <= 0)
if((fd = open("#P/ps2keyb", OREAD)) <= 0)
if((fd = open("/dev/scancode", OREAD)) <= 0)
if((fd = open("#b/scancode", OREAD)) <= 0)
sysfatal("open keyboard: %r");
dup(fd, 0);
close(fd);

View File

@ -1,7 +1,7 @@
{
"realemu": {
"Cflags": [
"-I", "/sys/src/kern/386/"
"-I", "/sys/src/kern/$ARCH/"
],
"Include": [
"/sys/src/cmd/cmd.json"

View File

@ -1,7 +1,7 @@
{
"vga": {
"Cflags": [
"-I", "/sys/src/kern/386/"
"-I", "/sys/src/kern/$ARCH/"
],
"Include": [
"/sys/src/cmd/cmd.json"

View File

@ -120,9 +120,6 @@ main(int argc, char **argv)
case 'c':
mntflags |= MCREATE;
break;
case 'C':
mntflags |= MCACHE;
break;
case 'd':
debug++;
break;

View File

@ -71,9 +71,6 @@ main(int argc, char *argv[])
case 'd':
setmntdevice(EARGF(usage()));
break;
case 'C':
flag |= MCACHE;
break;
case 'k':
keyspec = EARGF(usage());
break;

View File

@ -103,11 +103,6 @@ main(int argc, char *argv[])
domount = 1;
reallymount = 1;
break;
case 'C':
mountflag |= MCACHE;
domount = 1;
reallymount = 1;
break;
case 'e':
doexec = 1;
break;

View File

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

View File

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

View File

@ -20,8 +20,6 @@ procrestore(Proc *p)
return;
cycles(&t);
p->pcycles -= t;
fpuprocrestore(p);
}
/*
@ -35,11 +33,35 @@ procsave(Proc *p)
cycles(&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
@ -76,12 +98,21 @@ onIdleSpin(void)
/*
* put the processor in the halt state if we've no processes to run.
* 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
idlehands(void)
{
extern int nrdy;
if(sys->nonline == 1)
if(sys->nmach == 1)
halt();
else if (SUPPORT_MWAIT)
mwait32(&nrdy, 0);

View File

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

429
sys/src/kern/amd64/archmp.c Normal file
View File

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

View File

@ -6,7 +6,6 @@
"Include": [
"core.json",
"devdraw.json",
"../386/include.json",
"../ip/include.json",
"../port/include.json"
],
@ -18,7 +17,6 @@
"int printallsyscalls;"
],
"Dev": [
"acpi",
"arch",
"bridge",
"cap",
@ -29,6 +27,7 @@
"ether",
"ip",
"kprof",
"kbd",
"ninep",
"pci",
"pipe",
@ -87,7 +86,6 @@
"autogenerated.c",
"sdata.c",
"cga.c",
"devacpi.c",
"usbehcipc.c",
"usbohci.c",
"usbuhci.c"

View File

@ -179,7 +179,7 @@ cgaprinthex(uintptr_t x)
cgaputc('\n');
}
void
static void
cgaconsputs(char* s, int n)
{
ilock(&cgalock);
@ -235,7 +235,7 @@ cgawrite(Chan* c, void *vbuf, long len, int64_t off)
}
void
cgainit(void)
screen_init(void)
{
ilock(&cgalock);
@ -245,5 +245,6 @@ cgainit(void)
cgablinkoff();
cgainitdone = 1;
iunlock(&cgalock);
screenputs = cgaconsputs;
addarchfile("cgamem", 0666, cgaread, cgawrite);
}

View File

@ -62,7 +62,24 @@
"inith.json"
],
"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",
"ec.c",
"l64v.S",
"l64fpu.S",
"cpuidamd64.S",
@ -70,26 +87,24 @@
"l64vsyscall.S",
"acpi.c",
"arch.c",
"archamd64.c",
"archmp.c",
"devarch.c",
"fpu.c",
"hpet.c",
"i8254.c",
"i8253.c",
"i8259.c",
"ioapic.c",
"lapic.c",
"main.c",
"map.c",
"memory.c",
"mmu.c",
"mp.c",
"msi.c",
"mtrr.c",
"multiboot.c",
"sipi.c",
"squidboy.c",
"syscall.c",
"systab.c",
"trap.c",
"vsvm.c"
"trap.c"
]
}
}

View File

@ -3,25 +3,18 @@
*/
.globl cpuid
cpuid:
pushq %rbx
pushq %rcx
pushq %rdx
movq %rdi, %rax
movq %rsi, %rcx
pushq %r15
movq %rdx, %r15
cpuid /* Argument in %rax */
// 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
pushq %rbx
pushq %rcx
pushq %rdx
movl %edi, %eax
cpuid
movl %eax, 0(%rsi)
movl %ebx, 4(%rsi)
movl %ecx, 8(%rsi)
movl %edx, 12(%rsi)
popq %rdx
popq %rcx
pop %rbx
popq %rbx
ret
/*

View File

@ -8,11 +8,11 @@ fi
cd $JEHANNE/sys/src/kern/amd64
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
objcopy -O binary -j .text l64sipi l64sipi.out
x86_64-jehanne-gcc -c -O0 -static -fplan9-extensions -mno-red-zone -ffreestanding -fno-builtin -mcmodel=kernel l64sipi.S
x86_64-jehanne-ld -Ttext 0x00003000 -e 0x00003000 l64sipi.o -o l64sipi
x86_64-jehanne-objcopy -O binary -j .text l64sipi l64sipi.out
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
echo '};' >> sipi.h
rm l64sipi.out
#rm l64sipi.out

View File

@ -1,7 +1,7 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@ -17,6 +17,7 @@
*/
typedef struct BIOS32si BIOS32si;
typedef struct BIOS32ci BIOS32ci;
typedef struct Confmem Confmem;
typedef struct Fxsave Fxsave;
typedef struct IOConf IOConf;
typedef struct ISAConf ISAConf;
@ -25,27 +26,35 @@ typedef struct Lock Lock;
typedef struct LockEntry LockEntry;
typedef struct MCPU MCPU;
typedef struct MFPU MFPU;
typedef struct MMU MMU;
typedef struct MMMU MMMU;
typedef struct Mach Mach;
typedef uint64_t Mpl;
typedef Mpl Mreg; /* GAK */
typedef struct Ptpage Ptpage;
typedef struct Segdesc Segdesc;
typedef struct Pcidev Pcidev;
typedef struct PFPU PFPU;
typedef struct PMMU PMMU;
typedef struct PNOTIFY PNOTIFY;
typedef struct PPAGE PPAGE;
typedef uint64_t PTE;
typedef struct RMap RMap;
typedef struct Proc Proc;
typedef struct Sys Sys;
typedef uint64_t uintmem; /* horrible name */
typedef long Tval;
typedef struct Ureg Ureg;
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 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
@ -58,10 +67,16 @@ typedef struct Vctl Vctl;
*/
struct Lock
{
LockEntry* head;
LockEntry* e;
uint64_t sr;
uintptr_t pc;
Proc *lp;
Mach *lm;
uint32_t key;
uint16_t isilock;
long lockcycles;
};
struct Label
{
uintptr_t sp;
@ -69,6 +84,24 @@ struct Label
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 {
uint16_t fcw; /* x87 control word */
uint16_t fsw; /* x87 status word */
@ -84,40 +117,41 @@ struct Fxsave {
uint8_t ign[96]; /* reserved, ignored */
};
/*
* FPU stuff in Proc
*/
struct PFPU {
int fpustate;
uint8_t fxsave[sizeof(Fxsave)+15];
void* fpusave;
union FPsave {
uint8_t align[512+15];
Fxsave;
};
struct Ptpage
struct Segdesc
{
PTE* pte; /* kernel-addressible page table entries */
uintmem pa; /* physical address (from physalloc) */
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 */
uint32_t d0;
uint32_t d1;
};
/*
* MMU structure for PDP, PD, PT pages.
*/
struct MMU
{
MMU* next;
uintptr_t* page;
int index;
int level;
};
/*
* MMU stuff in Proc
*/
#define NCOLOR 1
struct PMMU
{
Ptpage* mmuptp[4]; /* page table pages for each level */
Ptpage* ptpfree;
int nptpbusy;
};
/*
* MMU stuff in Page
*/
struct PPAGE
{
uint8_t* nothing;
MMU* mmuhead;
MMU* mmutail;
MMU* kmaphead;
MMU* kmaptail;
unsigned long kmapcount;
unsigned long kmapindex;
unsigned long mmucount;
};
/*
@ -138,8 +172,6 @@ struct IOConf
};
extern IOConf ioconf;
#define MAXMDOM 8 /* maximum memory/cpu domains */
#include "../port/portdat.h"
/*
@ -164,24 +196,26 @@ struct MFPU {
/*
* MMU stuff in Mach.
*/
enum
{
NPGSZ = 4
};
typedef struct {
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;
} Tss;
struct MMMU
{
Ptpage* pml4; /* pml4 for this processor */
PTE* pmap; /* unused as of yet */
Ptpage* ptpfree; /* per-mach free list */
int nptpfree;
uint64_t* pml4; /* pml4 base for this processor (va) */
Tss* tss; /* tss for this processor */
Segdesc* gdt; /* gdt for this processor */
uint32_t pgszlg2[NPGSZ]; /* per Mach or per Sys? */
uintmem pgszmask[NPGSZ];
uint32_t pgsz[NPGSZ];
int npgsz;
Ptpage pml4kludge;
uint64_t mmumap[4]; /* bitmap of pml4 entries for zapping */
MMU* mmufree; /* freelist for MMU structures */
unsigned long mmucount; /* number of MMU structures in freelist */
};
/*
@ -212,8 +246,6 @@ struct Mach
uintptr_t stack;
uint8_t* vsvm;
void* gdt;
void* tss;
uint64_t ticks; /* of the clock since boot time */
Label sched; /* scheduler wakeup */
@ -241,18 +273,36 @@ struct Mach
int lastintr;
int loopconst;
Lock apictimerlock;
uint64_t cyclefreq; /* Frequency of user readable cycle counter */
int64_t cpuhz;
uint64_t cpuhz;
int cpumhz;
int cpuidax;
int cpuidcx;
int cpuiddx;
char cpuidid[16];
char* cpuidtype;
int havetsc;
int havepge;
uint64_t tscticks;
uint64_t rdtsc;
LockEntry locks[8];
// LockEntry locks[8];
MFPU FPU;
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.
* 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
* the unions.
*/
struct Sys {
uint8_t machstk[MACHSTKSZ];
struct Sys
{
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)]; /* */
PTE pdp[PTSZ/sizeof(PTE)];
PTE pd[PTSZ/sizeof(PTE)];
PTE pt[PTSZ/sizeof(PTE)];
unsigned int copymode; /* 0 is copy on write, 1 is copy on reference */
unsigned int ialloc; /* max interrupt time allocation in bytes */
unsigned int pipeqsize; /* size in bytes of pipe queues */
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 pmoccupied; /* how much is occupied */
uint64_t pmunassigned; /* how much to keep back from 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 */
uint64_t pmstart; /* physical memory */
uint64_t pmoccupied; /* how much is occupied */
uint64_t pmunassigned; /* how much to keep back from page pool */
uint64_t pmpaged; /* how much assigned to page pool */
};
extern Sys* sys;
extern uint32_t MemMin; /* set by entry.S */
/*
* KMap
*/
typedef void KMap;
#define kunmap(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
{
Lock;
char machs[MACHMAX]; /* bitmap of active CPUs */
int exiting; /* shutdown */
int ispanic; /* shutdown in response to a panic */
int thunderbirdsarego; /* F.A.B. */
@ -354,6 +444,8 @@ typedef struct BIOS32ci { /* BIOS32 Calling Interface */
uint32_t edi;
} BIOS32ci;
#define MACHP(n) (sys->machptr[n])
/*
* The Mach structures must be available via the per-processor
* MMU information array machptr, mainly for disambiguation and access to

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,8 @@
"SourceFiles": [
"../port/devdraw.c",
"../port/devmouse.c",
"../386/vgavesa.c",
"../port/swcursor.c",
"vgavesa.c",
"screen.c",
"devvga.c",
"mouse.c",

View File

@ -503,8 +503,6 @@ ethershutdown(void)
ether = etherxx[i];
if(ether == nil)
continue;
if(ether->irq >= 0)
intrdisable(ether->vector);
if(ether->shutdown == nil) {
jehanne_print("#l%d: no shutdown function\n", i);
continue;

447
sys/src/kern/amd64/devkbd.c Normal file
View File

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

View File

@ -24,9 +24,6 @@
#include <cursor.h>
#include "screen.h"
#define RMBUF ((void*)(KZERO + 0x9000)) // see 9/386/vgavesa.c
#define LORMBUF (0x9000)
enum {
Qdir,
Qvgabios,
@ -45,8 +42,6 @@ static Dirtab vgadir[] = {
enum {
CMactualsize,
CMblank,
CMblanktime,
CMdrawinit,
CMhwaccel,
CMhwblank,
@ -57,13 +52,12 @@ enum {
CMsize,
CMtextmode,
CMtype,
CMunblank,
CMsoftscreen,
CMpcidev,
};
static Cmdtab vgactlmsg[] = {
CMactualsize, "actualsize", 2,
CMblank, "blank", 1,
CMblanktime, "blanktime", 2,
CMdrawinit, "drawinit", 1,
CMhwaccel, "hwaccel", 2,
CMhwblank, "hwblank", 2,
@ -74,66 +68,39 @@ static Cmdtab vgactlmsg[] = {
CMsize, "size", 3,
CMtextmode, "textmode", 1,
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
vgareset(void)
{
Pcidev *pci;
VGAscr *scr;
/* reserve the 'standard' vga registers */
if(ioalloc(0x2b0, 0x2df-0x2b0+1, 0, "vga") < 0)
panic("vga ports already allocated");
if(ioalloc(0x3c0, 0x3da-0x3c0+1, 0, "vga") < 0)
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*
vgaattach(Chan *c, Chan *ac, char *spec, int flags)
{
if(*spec && jehanne_strcmp(spec, "0"))
if(*spec && strcmp(spec, "0"))
error(Eio);
return devattach('v', spec);
}
@ -159,7 +126,7 @@ vgaopen(Chan* c, unsigned long omode)
scr = &vgascreen[0];
if ((uint32_t)c->qid.path == Qvgaovlctl) {
if (scr->dev && scr->dev->ovlctl)
scr->dev->ovlctl(scr, c, openctl, jehanne_strlen(openctl));
scr->dev->ovlctl(scr, c, openctl, strlen(openctl));
else
error(Enonexist);
}
@ -176,10 +143,10 @@ vgaclose(Chan* c)
if((uint32_t)c->qid.path == Qvgaovlctl)
if(scr->dev && scr->dev->ovlctl){
if(waserror()){
jehanne_print("ovlctl error: %s\n", up->errstr);
print("ovlctl error: %s\n", up->errstr);
return;
}
scr->dev->ovlctl(scr, c, closectl, jehanne_strlen(closectl));
scr->dev->ovlctl(scr, c, closectl, strlen(closectl));
poperror();
}
}
@ -187,8 +154,7 @@ vgaclose(Chan* c)
static long
vgaread(Chan* c, void* a, long n, int64_t off)
{
int len;
char *p, *s;
char *p, *s, *e;
VGAscr *scr;
uint32_t offset = off;
char chbuf[30];
@ -203,50 +169,41 @@ vgaread(Chan* c, void* a, long n, int64_t off)
return 0;
if(offset+n >= 0x100000)
n = 0x100000 - offset;
jehanne_memmove(a, (unsigned char*)KADDR(0)+offset, n);
memmove(a, (uint8_t*)KADDR(0)+offset, n);
return n;
case Qvgactl:
scr = &vgascreen[0];
p = jehanne_malloc(READSTR);
if(p == nil)
error(Enomem);
s = smalloc(READSTR);
if(waserror()){
jehanne_free(p);
free(s);
nexterror();
}
len = 0;
if(scr->dev)
s = scr->dev->name;
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",
p = s, e = s+READSTR;
p = seprint(p, e, "type %s\n",
scr->dev != nil ? scr->dev->name : "cga");
if(scr->gscreen != nil) {
p = seprint(p, e, "size %dx%dx%d %s\n",
scr->gscreen->r.max.x, scr->gscreen->r.max.y,
scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan));
if(Dx(scr->gscreen->r) != Dx(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);
}
len += jehanne_snprint(p+len, READSTR-len, "blank time %lud idle %d state %s\n",
blanktime, drawidletime(), scr->isblank ? "off" : "on");
len += jehanne_snprint(p+len, READSTR-len, "hwaccel %s\n", hwaccel ? "on" : "off");
len += jehanne_snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");
len += jehanne_snprint(p+len, READSTR-len, "panning %s\n", panning ? "on" : "off");
len += jehanne_snprint(p+len, READSTR-len, "addr p 0x%lux v 0x%p size 0x%ux\n", scr->paddr, scr->vaddr, scr->apsize);
USED(len);
n = readstr(offset, a, n, p);
p = seprint(p, e, "hwgc %s\n",
scr->cur != nil ? scr->cur->name : "off");
p = seprint(p, e, "hwaccel %s\n", hwaccel ? "on" : "off");
p = seprint(p, e, "hwblank %s\n", hwblank ? "on" : "off");
p = seprint(p, e, "panning %s\n", panning ? "on" : "off");
p = seprint(p, e, "addr p %#p v %#p size %#ux\n",
scr->paddr, scr->vaddr, scr->apsize);
p = seprint(p, e, "softscreen %s\n", scr->softscreen ? "on" : "off");
USED(p);
n = readstr(offset, a, n, s);
poperror();
jehanne_free(p);
free(s);
return n;
@ -263,6 +220,8 @@ vgaread(Chan* c, void* a, long n, int64_t off)
return 0;
}
//static char Ebusy[] = "vga already configured";
static void
vgactl(Cmdbuf *cb)
{
@ -278,47 +237,69 @@ vgactl(Cmdbuf *cb)
ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg));
switch(ct->index){
case CMhwgc:
if(jehanne_strcmp(cb->f[1], "off") == 0){
lock(&cursor.l);
if(scr->gscreen == nil)
error("hwgc: no gscreen");
if(strcmp(cb->f[1], "off") == 0){
lock(&cursor);
if(scr->cur){
if(scr->cur->disable)
scr->cur->disable(scr);
scr->cur = nil;
}
unlock(&cursor.l);
unlock(&cursor);
return;
}
if(jehanne_strcmp(cb->f[1], "soft") == 0){
lock(&cursor.l);
if(strcmp(cb->f[1], "soft") == 0){
lock(&cursor);
swcursorinit();
if(scr->cur && scr->cur->disable)
scr->cur->disable(scr);
scr->cur = &swcursor;
if(scr->cur->enable)
scr->cur->enable(scr);
unlock(&cursor.l);
unlock(&cursor);
return;
}
for(i = 0; vgacur[i]; i++){
if(jehanne_strcmp(cb->f[1], vgacur[i]->name))
if(strcmp(cb->f[1], vgacur[i]->name))
continue;
lock(&cursor.l);
lock(&cursor);
if(scr->cur && scr->cur->disable)
scr->cur->disable(scr);
scr->cur = vgacur[i];
if(scr->cur->enable)
scr->cur->enable(scr);
unlock(&cursor.l);
unlock(&cursor);
return;
}
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:
for(i = 0; vgadev[i]; i++){
if(jehanne_strcmp(cb->f[1], vgadev[i]->name))
if(strcmp(cb->f[1], vgadev[i]->name))
continue;
if(scr->dev && scr->dev->disable)
scr->dev->disable(scr);
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 = vgadev[i];
if(scr->dev->enable)
scr->dev->enable(scr);
@ -327,23 +308,24 @@ vgactl(Cmdbuf *cb)
break;
case CMtextmode:
cgainit();
screen_init();
bootscreenconf(nil);
return;
case CMsize:
x = jehanne_strtoul(cb->f[1], &p, 0);
x = strtoul(cb->f[1], &p, 0);
if(x == 0 || x > 10240)
error(Ebadarg);
if(*p)
p++;
y = jehanne_strtoul(p, &p, 0);
y = strtoul(p, &p, 0);
if(y == 0 || y > 10240)
error(Ebadarg);
if(*p)
p++;
z = jehanne_strtoul(p, &p, 0);
z = strtoul(p, &p, 0);
chanstr = cb->f[2];
if((chan = strtochan(chanstr)) == 0)
@ -352,26 +334,24 @@ vgactl(Cmdbuf *cb)
if(chantodepth(chan) != z)
error("depth, channel do not match");
cursoroff(1);
cursoroff();
deletescreenimage();
if(screensize(x, y, z, chan))
error(Egreg);
vgascreenwin(scr);
resetscreenimage();
cursoron(1);
bootscreenconf(scr);
return;
case CMactualsize:
if(scr->gscreen == nil)
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)
error(Ebadarg);
if(*p)
p++;
y = jehanne_strtoul(p, nil, 0);
y = strtoul(p, nil, 0);
if(y == 0 || y > 2048)
error(Ebadarg);
@ -383,51 +363,57 @@ vgactl(Cmdbuf *cb)
return;
case CMpalettedepth:
x = jehanne_strtoul(cb->f[1], &p, 0);
x = strtoul(cb->f[1], &p, 0);
if(x != 8 && x != 6)
error(Ebadarg);
scr->palettedepth = x;
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:
if(scr->gscreen == nil)
error("drawinit: no gscreen");
if(scr->dev && scr->dev->drawinit)
scr->dev->drawinit(scr);
hwblank = scr->blank != nil;
hwaccel = scr->fill != nil || scr->scroll != nil;
vgascreenwin(scr);
resetscreenimage();
cursoron();
return;
case CMlinear:
if(cb->nf!=2 && cb->nf!=3)
error(Ebadarg);
size = jehanne_strtoul(cb->f[1], 0, 0);
size = strtoul(cb->f[1], 0, 0);
if(cb->nf == 2)
align = 0;
else
align = jehanne_strtoul(cb->f[2], 0, 0);
align = strtoul(cb->f[2], 0, 0);
if(screenaperture(size, align) < 0)
error("not enough free address space");
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:
if(jehanne_strcmp(cb->f[1], "on") == 0){
if(strcmp(cb->f[1], "on") == 0){
if(scr == nil || scr->cur == nil)
error("set screen first");
if(!scr->cur->doespanning)
@ -435,7 +421,7 @@ vgactl(Cmdbuf *cb)
scr->gscreen->clipr = scr->gscreen->r;
panning = 1;
}
else if(jehanne_strcmp(cb->f[1], "off") == 0){
else if(strcmp(cb->f[1], "off") == 0){
scr->gscreen->clipr = physgscreenr;
panning = 0;
}else
@ -443,18 +429,18 @@ vgactl(Cmdbuf *cb)
return;
case CMhwaccel:
if(jehanne_strcmp(cb->f[1], "on") == 0)
if(strcmp(cb->f[1], "on") == 0)
hwaccel = 1;
else if(jehanne_strcmp(cb->f[1], "off") == 0)
else if(strcmp(cb->f[1], "off") == 0)
hwaccel = 0;
else
break;
return;
case CMhwblank:
if(jehanne_strcmp(cb->f[1], "on") == 0)
if(strcmp(cb->f[1], "on") == 0)
hwblank = 1;
else if(jehanne_strcmp(cb->f[1], "off") == 0)
else if(strcmp(cb->f[1], "off") == 0)
hwblank = 0;
else
break;
@ -483,12 +469,12 @@ vgawrite(Chan* c, void* a, long n, int64_t off)
error(Ebadarg);
cb = parsecmd(a, n);
if(waserror()){
jehanne_free(cb);
free(cb);
nexterror();
}
vgactl(cb);
poperror();
jehanne_free(cb);
free(cb);
return n;
case Qvgaovl:

174
sys/src/kern/amd64/ec.c Normal file
View File

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

View File

@ -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 "amd64.h"
#ifndef __ASSEMBLER__
#define __ASSEMBLER__
#endif
#include "multiboot.h"
.code32
/* do we enter in 16-bit mode? If so, take the code from coreboot that goes from
* 16->32
/* This code (up to _start64v) is linked and loaded at physical address
* 0x00100000 (1MB), which is the start of extended memory. (See kernel.ld)
*/
/*
* Enter here in 32-bit protected mode. Welcome to 1982.
* 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.
/* boottext must be text: http://sourceware.org/binutils/docs/as/Section.html
*/
#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"
.code32
.align 4
_protected:
multiboot_header:
.long MULTIBOOT_HEADER_MAGIC
.long MULTIBOOT_HEADER_FLAGS
.long CHECKSUM
#define MBFLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
_multibootheader:
.long MULTIBOOT_HEADER_MAGIC
.long MBFLAGS
.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
_start:
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
* 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
movl $SELECTOR(2, SELGDT, 0), %eax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/* Restore the BIST value to %eax */
movl %ebp, %eax
jmp _warp64
entry32:
1:
movb $0x30, %al
movw $0x30, %dx
outb %dx
// 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
.align 16
_gdt:
/* null descriptor */
.long 0
.long 0
_startofheader:
.byte 0x90 /* NOP */
.byte 0x90 /* NOP */
/* (KESEG) 64 bit long mode exec segment */
.long 0xFFFF
.long SEGL|SEGG|SEGP|(0xF<<16)|SEGPL(0)|SEGEXEC|SEGR
_multibootheader: /* must be 4-byte aligned */
.long 0x1badb002 /* magic */
.long 0x00000003 /* flags */
.long -(0x1badb002 + 0x00000003) /* checksum */
/* 32 bit data segment descriptor for 4 gigabytes (PL 0) */
.long 0xFFFF
.long SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW
_gdt32p:
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x00cf9a000000ffff /* CS */
.quad 0x00cf92000000ffff /* DS */
.quad 0x0020980000000000 /* Long mode CS */
/* 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 _gdt32p
_gdt64p:
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0020980000000000 /* CS */
.long _gdt
.align 4
_gdtptr64p:
.word 2*8-1
.quad _gdt64p
_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
*/
.word 4*8-1
.quad _gdt
/*
* Macros for accessing page table entries; change the
@ -195,45 +151,55 @@ _endofheader:
#define PTO(v) ((PTLX((v), 0))<<3)
_warp64:
movl $_protected-(MACHSTKSZ+4*PTSZ+5*(4*KiB)+MACHSZ), %esi
movl $((CPU0END-CPU0PML4)>>2), %ecx
movl $(CPU0PML4-KZERO), %esi
movl %esi, %edi
xorl %eax, %eax
movl $((MACHSTKSZ+4*PTSZ+5*(4*KiB)+MACHSZ)>>2), %ecx
cld
rep; stosl /* stack, P*, vsvm, m, sys */
rep; stosl
movl %esi, %eax /* sys-KZERO */
addl $(MACHSTKSZ), %eax /* PML4 */
movl %eax, %cr3 /* load the mmu */
movl %esi, %eax /* PML4 */
movl %eax, %edx
addl $(PTSZ|PteRW|PteP), %edx /* PDP at PML4 + PTSZ */
movl %edx, PML4O(0)(%eax) /* PML4E for identity map */
movl %edx, PML4O(KZERO)(%eax) /* PML4E for KZERO, PMAPADDR */
addl $(PTSZ|PTEWRITE|PTEVALID), %edx /* PDP at PML4 + PTSZ */
movl %edx, PML4O(0)(%eax) /* PML4E for double-map */
movl %edx, PML4O(KZERO)(%eax) /* PML4E for KZERO */
addl $PTSZ, %eax /* PDP at PML4 + PTSZ */
addl $PTSZ, %edx /* PD at PML4 + 2*PTSZ */
movl %edx, PDPO(0)(%eax) /* PDPE for identity map */
movl %edx, PDPO(KZERO)(%eax) /* PDPE for KZERO, PMAPADDR */
addl $PTSZ, %eax /* PDP at PML4 + PTSZ */
addl $PTSZ, %edx /* PD0 at PML4 + 2*PTSZ */
movl %edx, PDPO(0)(%eax) /* PDPE for double-map */
movl %edx, PDPO(KZERO)(%eax) /* PDPE for KZERO */
addl $PTSZ, %eax /* PD at PML4 + 2*PTSZ */
movl $(PtePS|PteRW|PteP), %edx
movl %edx, PDO(0)(%eax) /* PDE for identity 0-[24]MiB */
/*
* add PDPE for KZERO+1GB early as Vmware
* hangs when modifying kernel PDP
*/
addl $PTSZ, %edx /* PD1 */
movl %edx, PDPO(KZERO+GiB)(%eax)
movl %eax, %ecx
addl $PDO(KZERO), %ecx
addl $PTSZ, %eax /* PD0 at PML4 + 2*PTSZ */
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:
movl %edx, 0(%ecx)
movl %edx, (%eax)
addl $PGLSZ(1), %edx
addl $8, %ecx
cmpl $(32*MiB), %edx
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 */
addl $8, %eax
loop memloop
/*
* 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.
*/
lme:
movl %esi, %cr3 /* load the mmu */
jmp 1f
1:
movl %cr4, %eax
andl $~Pse, %eax /* Page Size */
orl $(Pge|Pae), %eax /* Page Global, Phys. Address */
@ -260,7 +229,8 @@ lme:
orl $(Pg|Wp), %edx /* Paging Enable */
movl %edx, %cr0
ljmp $0x18, $_identity
ljmp $0x8, $_identity
/*
* Long mode. Welcome to 2003.
@ -270,69 +240,60 @@ lme:
.code64
_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
jmp *%rax
.section .text
_gdt64v:
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0020980000000000 /* CS */
.align 4
.globl _gdtptr64v
_gdtptr64v:
.word 2*8-1
.quad _gdt64v
.word 4*8-1
.quad _gdt+KZERO
.word 0
// At this point, we are safe to use kernel addresses, as we are in
// kernel virtual address space.
.align 4
_start64v:
movq $_gdtptr64v, %rax
lgdt (%rax)
xorq %rdx, %rdx
movw %dx, %ds /* not used in long mode */
movw %dx, %es /* not used in long mode */
movw %dx, %fs
movw %dx, %gs
movw %dx, %ss /* not used in long mode */
xorq %rax, %rax
movw %ax, %ds /* not used in long mode */
movw %ax, %es /* not used in long mode */
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss /* not used in long mode */
movq %rsi, %rsi /* sys-KZERO */
movq %rsi, %rax
addq $KZERO, %rax
movq %rax, sys /* sys */
lldt %ax
addq $(MACHSTKSZ), %rax /* PML4 and top of stack */
movq %rax, %rsp /* set stack */
movq $(CPU0MACH+MACHSIZE), %rsp
movq $CPU0MACH, %r15 /* m = CPU0MACH */
movq %rax, %r14 /* up = 0; */
_zap0pml4:
cmpq $PML4O(KZERO), %rdx /* KZER0 & 0x0000ff8000000000 */
je _zap0pdp
movq %rdx, PML4O(0)(%rax) /* zap identity map PML4E */
_zap0pdp:
addq $PTSZ, %rax /* PDP at PML4 + PTSZ */
cmpq $PDPO(KZERO), %rdx /* KZER0 & 0x0000007fc0000000 */
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 */
_clearbss:
movq $edata, %rdi
movq $end, %rcx
addq $(PGSZ-1), %rdi
andq $(~(PGSZ-1)), %rdi
subq %rdi, %rcx /* end-edata bytes */
shrq $2, %rcx /* end-edata doublewords */
addq $(2*PTSZ+4*KiB), %rax /* PD+PT+vsvm */
movq %rax, %r15
movq %rdx, %r14
movq $0, (%rax) /* m->machno = 0 */
cld
rep; stosl
pushq %rdx /* clear flags */
pushq %rax
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
.globl ndnr

View File

@ -746,7 +746,7 @@ rtl8139match(Ether* edev, int id)
if(pcigetpms(p) > 0){
pcisetpms(p, 0);
for(i = 0; i < 6; i++)
pcicfgw32(p, PciBAR0+i*4, p->mem[i].bar);
pcicfgw8(p, PciINTL, p->intl);

View File

@ -434,7 +434,7 @@ enum {
i82575,
i82576,
i82577,
i82577m,
i82577m,
i82578,
i82578m,
i82579,
@ -1974,7 +1974,7 @@ didtype(int d)
case 0x150f: /* fiber */
case 0x1510: /* backplane */
case 0x1511: /* sfp */
case 0x1516:
case 0x1516:
return i82580;
case 0x1506: /* v */
return i82583;

View File

@ -91,7 +91,7 @@ enum {
MACPortMII = 1<<2,
MACEnable = 1<<23 | 1<<22 | 1<<21 | 1 << 15 | 1 << 14 | 1<<12 | 1<<11,
MACHalfDuplex = 1<<1,
MACEventStatus = 0x404,
MACEventEnable = 0x408,
MACAddress = 0x410,
@ -105,7 +105,7 @@ enum {
TxMACLengths = 0x464,
MACHash = 0x470,
RxRules = 0x480,
RxRulesConf = 0x500,
LowWaterMax = 0x504,
LowWaterMaxMask = ~0xFFFF,
@ -120,13 +120,13 @@ enum {
SendBDSelectorMode = 0x1400,
SendBDInitiatorMode = 0x1800,
SendBDCompletionMode = 0x1C00,
RxListPlacementMode = 0x2000,
RxListPlacement = 0x2010,
RxListPlacementConf = 0x2014,
RxStats = 1<<0,
RxListPlacementMask = 0x2018,
RxDataBDInitiatorMode = 0x2400,
RxBDHostAddr = 0x2450,
RxBDFlags = 0x2458,
@ -134,7 +134,7 @@ enum {
RxDataCompletionMode = 0x2800,
RxBDInitiatorMode = 0x2C00,
RxBDRepl = 0x2C18,
RxBDCompletionMode = 0x3000,
HostCoalMode = 0x3C00,
HostCoalRxTicks = 0x3C08,
@ -147,27 +147,27 @@ enum {
FlowAttention = 0x3C48,
MemArbiterMode = 0x4000,
BufferManMode = 0x4400,
MBUFLowWater = 0x4414,
MBUFHighWater = 0x4418,
ReadDMAMode = 0x4800,
ReadDMAStatus = 0x4804,
WriteDMAMode = 0x4C00,
WriteDMAStatus = 0x4C04,
RISCState = 0x5004,
FTQReset = 0x5C00,
MSIMode = 0x6000,
ModeControl = 0x6800,
ByteWordSwap = 1<<4 | 1<<5 | 1<<2, // | 1<<1,
HostStackUp = 1<<16,
HostSendBDs = 1<<17,
InterruptOnMAC = 1<<26,
MiscConf = 0x6804,
CoreClockBlocksReset = 1<<0,
GPHYPwrdnOverride = 1<<26,
@ -177,7 +177,7 @@ enum {
MiscLocalControl = 0x6808,
InterruptOnAttn = 1<<3,
AutoSEEPROM = 1<<24,
SwArbitration = 0x7020,
SwArbitSet1 = 1<<1,
SwArbitWon1 = 1<<9,
@ -186,11 +186,11 @@ enum {
PhyAuxControl = 0x18,
PhyIntStatus = 0x1A,
PhyIntMask = 0x1B,
Updated = 1<<0,
LinkStateChange = 1<<1,
Error = 1<<2,
PacketEnd = 1<<2,
FrameError = 1<<10,
};
@ -389,7 +389,7 @@ replenish(Ctlr *ctlr)
uint32_t incr;
uint32_t *next;
Block *bp;
incr = (ctlr->recvprodi + 1) & (RxProdRingLen - 1);
if(incr == (ctlr->status[2] >> 16))
return -1;
@ -419,7 +419,7 @@ bcmreceive(Ether *edev)
uint32_t *pkt;
Ctlr *ctlr;
Block *bp;
ctlr = edev->ctlr;
for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {
bp = ctlr->rxs[pkt[7]];
@ -444,7 +444,7 @@ static void
bcmtransclean(Ether *edev)
{
Ctlr *ctlr;
ctlr = edev->ctlr;
ilock(&ctlr->txlock);
while(ctlr->sendcleani != (ctlr->status[4] >> 16)) {
@ -462,7 +462,7 @@ bcmtransmit(Ether *edev)
uint32_t *next;
Ctlr *ctlr;
Block *bp;
ctlr = edev->ctlr;
ilock(&ctlr->txlock);
for(;;){
@ -491,7 +491,7 @@ static void
bcmerror(Ether *edev)
{
Ctlr *ctlr;
ctlr = edev->ctlr;
if(csr32(ctlr, FlowAttention)) {
if(csr32(ctlr, FlowAttention) & 0xf8ff8080)
@ -518,7 +518,7 @@ bcminterrupt(Ureg*, void *arg)
uint32_t status, tag, dummy;
Ether *edev;
Ctlr *ctlr;
edev = arg;
ctlr = edev->ctlr;
ilock(&ctlr->imlock);
@ -579,7 +579,7 @@ bcminit(Ether *edev)
uint32_t i;
uint32_t j;
Ctlr *ctlr;
ctlr = edev->ctlr;
dprint("bcm: reset\n");
/* initialization procedure according to the datasheet */
@ -748,7 +748,7 @@ didtype(Pcidev *p)
{
if(p->vid != 0x14e4)
return -1;
switch(p->did){
default:
return -1;
@ -825,7 +825,7 @@ static void
bcmpromiscuous(void* arg, int on)
{
Ctlr *ctlr;
ctlr = ((Ether*)arg)->ctlr;
if(on)
csr32(ctlr, RxMACMode) |= 1<<8;
@ -848,7 +848,7 @@ bcmpnp(Ether* edev)
bcmpci();
done = 1;
}
redux:
for(ctlr = bcmhead; ; ctlr = ctlr->next) {
if(ctlr == nil)

View File

@ -1958,7 +1958,7 @@ igbepci(void)
case 0x08:
case 0x10:
break;
}
}
ctlr = jehanne_malloc(sizeof(Ctlr));
if(ctlr == nil){
jehanne_print("igbe: can't allocate memory\n");
@ -2038,4 +2038,3 @@ etherigbelink(void)
addethercard("i82543", igbepnp);
addethercard("igbe", igbepnp);
}

View File

@ -390,7 +390,7 @@ atapirwfis(Sfis *f, uint8_t *c, uint8_t *cdb, int cdblen, int ndata)
c[Ffeat] = 1; /* dma */
else
c[Ffeat] = 0; /* features (exp); */
c[Flba0] = 0;
c[Flba0] = 0;
c[Flba8] = ndata;
c[Flba16] = ndata >> 8;
c[Fdev] = Ataobs;

View File

@ -31,7 +31,6 @@ void mouseenable(void);
int mousecmd(int);
void aamloop(int);
void acpiinit(int);
Dirtab* addarchfile(char*, int,
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 asmmapinit(uint64_t, uint64_t, int);
void asmmodinit(uint32_t, uint32_t, char*);
void cgaconsputs(char*, int);
void cgainit(void);
void cgapost(int);
void screen_init(void);
uintptr_t cankaddr(uintptr_t pa);
void (*coherence)(void);
void cpuid(int, uint32_t regs[]);
int cpuidentify(void);
void cpuidprint(void);
int corecolor(int);
uint32_t cpuid(uint32_t, uint32_t, uint32_t[4]);
void (*cycles)(uint64_t*);
int dbgprint(char*, ...);
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 */
int e820(void);
int fpudevprocio(Proc*, void*, int32_t, uintptr_t, int);
void fpuinit(void);
void fpunoted(void);
void fpunotify(Ureg*);
void fpuprocrestore(Proc*);
void fpuprocsave(Proc*);
void fpusysprocsetup(Proc*);
void fpusysrfork(Ureg*);
void fpusysrforkchild(Proc*, Proc*);
void fpclear(void);
void fpinit(void);
void fpoff(void);
void (*fprestore)(FPsave*);
void (*fpsave)(FPsave*);
void fpsserestore(FPsave*);
void fpssesave(FPsave*);
void fpprocfork(Proc *p);
void fpprocsetup(Proc* p);
char* getconf(char*);
void guesscpuhz(int);
void _halt(void);
void halt(void);
void hpetinit(uint32_t, uint32_t, uintmem, int);
/*int i8042auxcmd(int);
int i8042auxcmds(uint8_t*, int);
void i8042auxenable(void (*)(int, int));*/
void i8042systemreset(void);
Uart* i8250console(char*);
int i8042auxcmd(int);
void i8042auxenable(void (*)(int, int));
void i8042reset(void);
void i8250console(void);
void* i8250alloc(int, int, int);
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 idthandlers(void);
int inb(int);
@ -85,7 +97,7 @@ uint16_t ins(int);
void inss(int, void*, int);
uint32_t inl(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 invlpg(uintptr_t va);
void iofree(int);
@ -96,16 +108,20 @@ int ioreserve(int, int, int, char*);
int iprint(char*, ...);
int isaconfig(char*, int, ISAConf*);
int isdmaok(void*, usize, int);
void keybenable(void); // 386/i8042.c
void keybinit(void); // 386/i8042.c
void keybenable(void); // i8042.c
void keybinit(void); // i8042.c
void kexit(Ureg*);
KMap* kmap(uintptr_t pa);
void kunmap(KMap*);
#define kmapinval()
void lfence(void);
void links(void);
#define lockgetpc(l) (l->pc)
int machdom(Mach*);
void machinit(void);
void mach0init(void);
void mapraminit(uint64_t, uint64_t);
void mathinit(void);
void memdebug(void);
void meminit(void);
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 mfence(void);
void mmudump(Proc*);
void mmuflushtlb(uint64_t);
#define mmuflushtlb() cr3put(cr3get())
void mmuinit(void);
#define mmucachectl(pg, why) USED(pg, why) /* x86 doesn't need it */
uint64_t mmuphysaddr(uintptr_t);
int mmuwalk(uintptr_t, int, PTE**, uint64_t (*)(usize));
int multiboot(uint32_t, uint32_t, int);
uintptr_t* mmuwalk(uintptr_t* table, uintptr_t va, int level, int create);
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);
uint64_t mwait64(void*, uint64_t);
void ndnr(void);
uint8_t nvramread(int);
void nvramwrite(int, uint8_t);
@ -131,6 +151,7 @@ void outs(int, uint16_t);
void outss(int, void*, int);
void outl(int, uint32_t);
void outsl(int, void*, int);
void patwc(void *a, int n);
void pause(void);
int pciscan(int, Pcidev**);
uint32_t pcibarsize(Pcidev*, int);
@ -156,7 +177,9 @@ void pcisetmwi(Pcidev*);
int pcisetpms(Pcidev*, int);
uintmem pcixcfgspace(int);
void* pcixcfgaddr(Pcidev*, int);
void pmap(uintptr_t *pml4, uintptr_t pa, uintptr_t va, long size);
void printcpufreq(void);
void* rampage(void);
int screenprint(char*, ...); /* debugging */
void sfence(void);
void spldone(void);
@ -170,11 +193,15 @@ void* sysexecregs(uintptr_t, uint32_t);
uintptr_t sysexecstack(uintptr_t, int);
void sysprocsetup(Proc*);
void tssrsp0(uint64_t);
uint64_t tscticks(uint64_t *hz);
void trapenable(int, void (*)(Ureg*, void*), void*, char*);
void trapinit(void);
void trapinit0(void);
int userureg(Ureg*);
void* vmap(uintmem, usize);
void vsvminit(int);
uintptr_t upaalloc(int size, int align);
void upafree(uintptr_t pa, int size);
void upareserve(uintptr_t pa, int size);
void* vmap(uintptr_t, usize);
void vunmap(void*, usize);
extern Mreg cr0get(void);
@ -186,13 +213,18 @@ extern Mreg cr4get(void);
extern void cr4put(Mreg);
extern void gdtget(void*);
extern void gdtput(int, uint64_t, uint16_t);
extern void lgdt(void*);
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 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*);
#define userureg(ur) (((ur)->cs & 3) == 3)
extern int islo(void);
extern void spldone(void);
extern Mreg splhi(void);
@ -222,8 +254,10 @@ void sysrforkret(void);
#define PTR2UINT(p) ((uintptr_t)(p))
#define UINT2PTR(i) ((void*)(i))
void* KADDR(uintmem);
uintptr_t PADDR(void*);
uintptr_t mmu_physical_address(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)
@ -235,10 +269,13 @@ extern void millidelay(int);
/*
* i8259.c
*/
extern int i8259init(int);
extern int i8259irqdisable(int);
extern int i8259irqenable(int);
extern void i8259init(void);
extern int i8259disable(int);
extern int i8259enable(Vctl* v);
extern int i8259isr(int);
extern void i8259on(void);
extern void i8259off(void);
extern int i8259vecno(int irq);
/*
* sipi.c
@ -250,6 +287,9 @@ void basefree(void*, usize);
void physallocinit(void);
void uartpush(void);
void rdrandbuf(void*, uint32_t);
/* horror */
static inline void __clobber_callee_regs(void)
{

View File

@ -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
* terms in the LICENSE file found in the top-level directory of this
@ -12,7 +12,7 @@
/*
* SIMD Floating Point.
* 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
* restoring the state and allocating the storage needed.
*/
@ -21,6 +21,7 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "amd64.h"
#include "ureg.h"
@ -87,368 +88,116 @@ extern void _fwait(void);
extern void _ldmxcsr(uint32_t*);
extern void _stts(void);
int
fpudevprocio(Proc* proc, void* a, int32_t n, uintptr_t offset, int write)
void
fpclear(void)
{
uint8_t *p;
_clts();
_fnclex();
_stts();
}
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;
/*
* 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...
* Some attention should probably be paid here to the
* exception masks and error summary.
*/
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);
msg = "unknown exception";
for(i = 1; i <= 5; i++){
if(!((1<<i) & status))
continue;
msg = mathmsg[i];
break;
}
return n;
}
void
fpunotify(Ureg* u)
{
/*
* 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();
_fnclex();
_stts();
p->FPU.fpustate = Init;
return;
}
/*
* 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";
if(status & 0x01){
if(status & 0x40){
if(status & 0x200)
msg = "stack overflow";
else
cm = "Stack Underflow";
}
else
cm = "Invalid Operation";
msg = "stack underflow";
}else
msg = "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;
snprint(note, sizeof note, "sys: fp: %s fppc=%#p status=0x%lux",
msg, pc, status);
postnote(up, 1, note, NDebug);
}
char*
xfpuxf(Ureg* ureg, void* v)
/*
* math coprocessor error
*/
static void
matherror(Ureg* _, void* __)
{
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;
fpsave(&up->fpsave);
up->fpstate = FPinactive;
mathnote(up->fpsave.fsw, up->fpsave.rip);
}
void
fpuxf(Ureg *ureg, void *p)
/*
* SIMD error
*/
static void
simderror(Ureg *ureg, void* _)
{
char *n;
n = xfpuxf(ureg, p);
if(n != nil)
postnote(up, 1, n, NDebug);
fpsave(&up->fpsave);
up->fpstate = FPinactive;
mathnote(up->fpsave.mxcsr & 0x3f, ureg->ip);
}
char*
acfpuxf(Ureg *ureg, void *p)
/*
* math coprocessor emulation fault
*/
static void
mathemu(Ureg *ureg, void* _)
{
return xfpuxf(ureg, p);
}
unsigned int status, control;
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:
if(up->fpstate & FPillegal){
/* someone did floating point in a note handler */
postnote(up, 1, "sys: floating point in note handler", NDebug);
return;
}
switch(up->fpstate){
case FPinit:
/*
* A process tries to use the FPU for the
* first time and generates a 'device not available'
@ -460,87 +209,78 @@ xfpunm(Ureg* ureg, void* v)
_clts();
_fninit();
_fwait();
_fldcw(&m->FPU.fcw);
_ldmxcsr(&m->FPU.mxcsr);
up->FPU.fpusave = (void*)((PTR2UINT(up->FPU.fxsave) + 15) & ~15);
up->FPU.fpustate = Busy;
up->fpsave.fcw = 0x0232;
_fldcw(&up->fpsave.fcw);
up->fpsave.mxcsr = 0x1900;
_ldmxcsr(&up->fpsave.mxcsr);
up->fpstate = FPactive;
break;
case Idle:
case FPinactive:
/*
* Before restoring the state, check for any pending
* exceptions, there's no way to restore the state without
* generating an unmasked exception.
* More attention should probably be paid here to the
* exception masks and error summary.
*/
fpusave = up->FPU.fpusave;
if((fpusave->fsw & ~fpusave->fcw) & (Sff|P|U|O|Z|D|I))
return fpunote();
/*
* Sff is sticky.
*/
fpusave->fcw &= ~Sff;
_clts();
_fxrstor(fpusave);
up->FPU.fpustate = Busy;
status = up->fpsave.fsw;
control = up->fpsave.fcw;
if((status & ~control) & 0x07F){
mathnote(status, up->fpsave.rip);
break;
}
fprestore(&up->fpsave);
up->fpstate = FPactive;
break;
case FPactive:
panic("math emu pid %ld %s pc %#p",
up->pid, up->text, ureg->ip);
break;
}
return nil;
}
void
fpunm(Ureg *ureg, void *p)
fpprocsetup(Proc* p)
{
char *n;
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;
p->fpstate = FPinit;
_stts();
if(m->machno != 0)
return;
/*
* Set up the exception handlers.
*/
trapenable(IdtNM, fpunm, 0, "#NM");
trapenable(IdtMF, fpumf, 0, "#MF");
trapenable(IdtXF, fpuxf, 0, "#XF");
}
void
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);
}
/*
* math coprocessor segment overrun
*/
static void
mathover(Ureg* _, void* __)
{
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");
}

317
sys/src/kern/amd64/i8253.c Normal file
View File

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

View File

@ -3,131 +3,102 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
/*
* 8259 Interrupt Controller and compatibles.
* 8259 interrupt controllers
*/
enum { /* I/O ports */
Cntrl1 = 0x20,
Cntrl2 = 0xa0,
enum
{
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 */
Icw2 = 1,
Icw3 = 1,
Icw4 = 1,
Icw1= 0x10, /* select bit in ctl register */
Ocw2= 0x00,
Ocw3= 0x08,
Ocw1 = 1, /* Operational Control Word 1 */
Ocw2 = 0,
Ocw3 = 0,
EOI= 0x20, /* non-specific end of interrupt */
Imr = Ocw1, /* Interrupt Mask Register */
Isr = Ocw3, /* In-Service Register */
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 */
Elcr1= 0x4D0, /* Edge/Level Triggered Register */
Elcr2= 0x4D1,
};
static Lock i8259lock;
static int i8259mask = ~0; /* mask of disabled interrupts */
static int i8259elcr; /* mask of level interrupts */
static int i8259mask = 0xFFFF; /* disabled interrupts */
int i8259elcr; /* mask of level-triggered interrupts */
int
i8259init(int vectorbase)
void
i8259init(void)
{
int elcr;
vectorbase &= ~0x07;
int x;
ioalloc(Int0ctl, 2, 0, "i8259.0");
ioalloc(Int1ctl, 2, 0, "i8259.1");
ilock(&i8259lock);
/*
* Boilerplate to initialise the pair of 8259 controllers,
* see one of the Intel bridge datasheets for details,
* e.g. 82371AB (PIIX4). The default settings are 80x86 mode,
* edge-sensitive detection, normal EOI, non-buffered and
* cascade mode. Cntrl1 is connected as the master and Cntrl2
* as the slave; IRQ2 is used to cascade the two controllers.
* Set up the first 8259 interrupt processor.
* Make 8259 interrupts start at CPU vector VectorPIC.
* Set the 8259 as master with edge triggered
* input with fully nested interrupts.
*/
outb(Cntrl1+Icw1, Icw1sel|Ic4);
outb(Cntrl1+Icw2, vectorbase);
outb(Cntrl1+Icw3, Cascaded);
outb(Cntrl1+Icw4, Microprocessor);
outb(Cntrl2+Icw1, Icw1sel|Ic4);
outb(Cntrl2+Icw2, vectorbase+8);
outb(Cntrl2+Icw3, SlaveIRQ2);
outb(Cntrl2+Icw4, Microprocessor);
outb(Int0ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered,
ICW4 will be sent */
outb(Int0aux, VectorPIC); /* ICW2 - interrupt vector offset */
outb(Int0aux, 0x04); /* ICW3 - have slave on level 2 */
outb(Int0aux, 0x01); /* ICW4 - 8086 mode, not buffered */
/*
* Set the interrupt masks, allowing interrupts
* to pass from Cntrl2 to Cntrl1 on IRQ2.
* Set up the second 8259 interrupt processor.
* 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(Cntrl2+Imr, (i8259mask>>8) & 0xff);
outb(Cntrl1+Imr, i8259mask & 0xff);
outb(Cntrl1+Ocw2, Ocw2sel|Eoi);
outb(Cntrl2+Ocw2, Ocw2sel|Eoi);
outb(Int1ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered,
ICW4 will be sent */
outb(Int1aux, VectorPIC+8); /* ICW2 - interrupt vector offset */
outb(Int1aux, 0x02); /* ICW3 - I am a slave on level 2 */
outb(Int1aux, 0x01); /* ICW4 - 8086 mode, not buffered */
outb(Int1aux, (i8259mask>>8) & 0xFF);
/*
* Set Ocw3 to return the ISR when read for i8259isr()
* (after initialisation status read is set to return the IRR).
* pass #2 8259 interrupts to #1
*/
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
* interrupt.
*/
inb(Cntrl1+Irr);
outb(Cntrl1+Ocw3, Ocw3sel|Isrread);
inb(Cntrl2+Irr);
outb(Cntrl2+Ocw3, Ocw3sel|Isrread);
inb(Int0ctl);
outb(Int0ctl, Ocw3|0x03);
inb(Int1ctl);
outb(Int1ctl, Ocw3|0x03);
/*
* Check for Edge/Level Control register.
* Check for Edge/Level register.
* This check may not work for all chipsets.
* First try a non-intrusive test - the bits for
* IRQs 13, 8, 2, 1 and 0 must be edge (0). If
* that's OK try a R/W test.
*/
elcr = (inb(Elcr2)<<8)|inb(Elcr1);
if(!(elcr & 0x2107)){
x = (inb(Elcr2)<<8)|inb(Elcr1);
if(!(x & 0x2107)){
outb(Elcr1, 0);
if(inb(Elcr1) == 0){
outb(Elcr1, 0x20);
if(inb(Elcr1) == 0x20)
i8259elcr = elcr;
outb(Elcr1, elcr & 0xff);
i8259elcr = x;
outb(Elcr1, x & 0xFF);
print("ELCR: %4.4uX\n", i8259elcr);
}
}
iunlock(&i8259lock);
return vectorbase;
}
int
@ -135,25 +106,108 @@ i8259isr(int vno)
{
int irq, isr;
if(vno < IdtPIC || vno > IdtPIC+15)
if(vno < VectorPIC || vno > VectorPIC+MaxIrqPIC)
return 0;
irq = vno-IdtPIC;
irq = vno-VectorPIC;
/*
* Collect the interrupt status,
* acknowledge the interrupt and return whether
* the acknowledged interrupt was the correct
* one (this could be better but it's not really
* used).
* tell the 8259 that we're done with the
* highest level interrupt (interrupts are still
* off at this point)
*/
ilock(&i8259lock);
isr = inb(Cntrl1+Isr);
outb(Cntrl1+Ocw2, Ocw2sel|Eoi);
isr = inb(Int0ctl);
outb(Int0ctl, EOI);
if(irq >= 8){
isr |= inb(Cntrl2+Isr)<<8;
outb(Cntrl2+Ocw2, Ocw2sel|Eoi);
isr |= inb(Int1ctl)<<8;
outb(Int1ctl, EOI);
}
iunlock(&i8259lock);
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);
}

View File

@ -7,6 +7,11 @@
* 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 {
VectorNMI = 2, /* non-maskable interrupt */
VectorBPT = 3, /* breakpoint */
@ -14,9 +19,14 @@ enum {
VectorCNA = 7, /* coprocessor not available */
Vector2F = 8, /* double fault */
VectorCSO = 9, /* coprocessor segment overrun */
VectorSNP = 11, /* segment not present */
VectorGPF = 13, /* general protection fault */
VectorPF = 14, /* page fault */
Vector15 = 15, /* reserved */
VectorCERR = 16, /* coprocessor error */
VectorAC = 17, /* alignment check */
VectorMC = 18, /* machine check */
VectorSIMD = 19, /* simd error */
VectorPIC = 32, /* external i8259 interrupts */
IrqCLOCK = 0,
@ -33,13 +43,13 @@ enum {
IrqATA1 = 15,
MaxIrqPIC = 15,
VectorLAPIC = VectorPIC+16, /* local APIC interrupts */
IrqLINT0 = VectorLAPIC+0,
VectorLAPIC = VectorPIC+16, /* local APIC interrupts */
IrqLINT0 = VectorLAPIC+0, /* LINT[01] must be offsets 0 and 1 */
IrqLINT1 = VectorLAPIC+1,
IrqTIMER = VectorLAPIC+2,
IrqERROR = VectorLAPIC+3,
IrqPCINT = VectorLAPIC+4,
IrqSPURIOUS = VectorLAPIC+15,
IrqSPURIOUS = VectorLAPIC+15, /* must have bits [3-0] == 0x0F */
MaxIrqLAPIC = VectorLAPIC+15,
VectorSYSCALL = 64,
@ -69,20 +79,15 @@ enum {
typedef struct Vctl {
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 *type;
int isintr; /* interrupt or fault/trap */
int irq;
int tbdf;
int (*isr)(int); /* get isr bit for this irq */
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;
enum {
@ -139,8 +144,7 @@ enum { /* type 0 and type 1 pre-defined header */
PciBAR0 = 0x10, /* base address */
PciBAR1 = 0x14,
PciCP = 0x34, /* capabilities pointer */
PciCAP = 0x34, /* capabilities pointer */
PciINTL = 0x3C, /* interrupt line */
PciINTP = 0x3D, /* interrupt pin */
};
@ -197,7 +201,7 @@ enum {
enum { /* type 0 pre-defined header */
PciCIS = 0x28, /* cardbus CIS pointer */
PciSVID = 0x2C, /* subsystem vendor ID */
PciSID = 0x2E, /* cardbus CIS pointer */
PciSID = 0x2E, /* subsystem ID */
PciEBAR0 = 0x30, /* expansion ROM base address */
PciMGNT = 0x3E, /* burst period length */
PciMLT = 0x3F, /* maximum latency between bursts */
@ -274,8 +278,6 @@ struct Pcidev
int tbdf; /* type+bus+device+function */
uint16_t vid; /* vendor ID */
uint16_t did; /* device ID */
uint16_t svid; /* subsystem vid */
uint16_t sdid; /* subsystem did */
uint16_t pcr;
@ -308,7 +310,12 @@ struct Pcidev
} ioa, mema;
int pmrb; /* power management register block */
void* xcfg; /* PCIe configuration block */
};
enum {
/* vendor ids */
Vintel = 0x8086,
Vmyricom= 0x14c1,
};
#define PCIWINDOW 0
@ -319,4 +326,110 @@ struct Pcidev
#define PCIWADDRL(va) ((uint32_t)PCIWADDR64(va))
#define PCIWADDRH(va) ((uint32_t)(PCIWADDR64(va)>>32))
#pragma varargck type "T" int
/* 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" uint

View File

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

View File

@ -10,7 +10,7 @@ ENTRY(_start)
/* start the kernel at 0x110000.
* That way we can use lower ram for critical structures
*/
KERN_LOAD_ADDR = 0xfffffffff0000000;
KERN_LOAD_ADDR = 0xffffffff80000000;
SECTIONS
{

View File

@ -2,6 +2,7 @@
* Interrupt/exception handling.
*/
#include "amd64.h"
#include "mem.h"
.code64
@ -81,7 +82,7 @@ _intrcommon:
xchgq %rax, 0(%rsp)
// 0(%rsp) now has the vno
subq $16, %rsp /* R1[45] */
cmpw $SSEL(SiCS, SsTIGDT|SsRPL0), 40(%rsp) /* old CS */
cmpw $KESEL, 40(%rsp) /* old CS */
je _intrnested
movq %r14, 0(%rsp)
@ -131,7 +132,7 @@ _intrr:
popq %r12
popq %r13
cmpw $SSEL(SiCS, SsTIGDT|SsRPL0), 40(%rsp) /* old CS */
cmpw $KESEL, 40(%rsp) /* old CS */
je _iretnested
swapgs

View File

@ -11,9 +11,6 @@
* CS base set to startup memory address;
* CS limit set to 64KiB;
* 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 "amd64.h"
@ -22,190 +19,126 @@
#endif
.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
.align 4096
.globl sipihandler
sipihandler:
_real:
ljmp $0x0, $_endofheader
_startofheader:
NOP; NOP; NOP
.quad 0xa5a5a5a5a5a5a5a5
_gdt32p:
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x00cf9a000000ffff /* CS */
.quad 0x00cf92000000ffff /* DS */
.quad 0x0020980000000000 /* .long mode CS */
_gdtptr32p:
.word 4*8-1 /* includes .long mode */
.long _gdt32p
_gdt64:
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0020980000000000 /* CS */
.quad 0x0000800000000000 /* DS */
_gdtptr64v:
.word 3*8-1
.quad _gdt64
_endofheader:
.align 4
apbootstrap:
ljmp $0x0, $_apbootstrap
nop
nop
nop
_apvector: /* address APBOOTSTRAP+0x08 */
.quad 0
_appml4: /* address APBOOTSTRAP+0x10 */
.quad 0
_apapic: /* address APBOOTSTRAP+0x18 */
.quad 0
_apmach: /* address APBOOTSTRAP+0x20 */
.quad 0
_apbootstrap:
mov %cs, %ax
mov %ax, %ds
lgdt _gdtptr32p /* load a basic gdt */
mov %cr0, %eax
or $Pe, %ax
mov %eax, %cr0 /* turn on protected mode */
lgdt _gdtptr32p
movl %cr0, %eax
or $0x1, %ax
mov %eax, %cr0
jmp 1f
1:
mov $(SSEL(SiDS, SsTIGDT|SsRPL0)), %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
ljmp $0x18, $_ap32
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
_ap32:
movl $SELECTOR(2, SELGDT, 0), %eax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/*
* Macros for accessing page table entries; must turn
* the C-style array-index macros into a page table byte
* offset.
*/
#define PML4O(v) ((PTLX((v), 3))<<3)
#define PDPO(v) ((PTLX((v), 2))<<3)
#define PDO(v) ((PTLX((v), 1))<<3)
#define PTO(v) ((PTLX((v), 0))<<3)
movl _appml4, %eax /* physical address of PML4 */
movl %eax, %cr3 /* load the mmu */
jmp 2f
2:
movl %cr4, %eax
andl $0xffffffef, %eax /* Page Size (~0x00000010 = 0xffffffef) */
orl $0xa0, %eax /* Page Global, Phys. Address */
movl %eax, %cr4
_protected:
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 */
movl $0xc0000080, %ecx /* Extended Feature Enable */
rdmsr
or $Lme, %eax /* .long Mode Enable */
orl $0x00000100, %eax /* Long Mode Enable */
wrmsr
mov %cr0, %edx
and $~(Cd|Nw|Ts|Mp), %edx
or $(Pg|Wp), %edx /* Paging Enable */
mov %edx, %cr0
movl %cr0, %edx
andl $0x9ffffff5, %edx /* (~0x6000000a = 0x9ffffff5) */
orl $0x80010000, %edx /* Paging Enable, Write Protect */
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
_identity:
mov $(_start64v+KZERO), %rax
jmpq *%rax
_start64v:
mov $_gdtptr64v, %rax
_ap64:
movq $_gdtptr64v, %rax
lgdt (%rax)
xor %rdx, %rdx /* DX is 0 from here on */
mov %edx, %ds /* not used in .long mode */
mov %edx, %es /* not used in .long mode */
mov %edx, %fs
mov %edx, %gs
mov %edx, %ss /* not used in .long mode */
xorq %rax, %rax
movw %ax, %ds /* not used in long mode */
movw %ax, %es /* not used in long mode */
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss /* not used in long mode */
mov %esi, %esi /* sipi[apicno].pml4 */
mov %rsi, %rax
add $KZERO, %rax /* PML4 */
lldt %ax
mov %rdx, PML4O(0)(%rax) /* zap identity map */
mov %rsi, %cr3 /* flush TLB */
movq _apmach, %rsp
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
mov %ebp, %ebp /* APIC ID */
push %rbp /* apicno */
mov 16(%rbx), %r15 /* sipi[apicno].mach */
mov %rdx, %r14
mov 24(%rbx), %rax /* sipi[apicno].pc */
callq *%rax /* (*sipi[apicno].pc)(apicno) */
movq _apvector, %rax
movq _apapic, %rdi
pushq %rbp
_ndnr:
jmp _ndnr
call *%rax
.globl sipihandlerend
sipihandlerend:
jmp sipihandlerend
_halt:
hlt
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

View File

@ -116,6 +116,16 @@ gdtget:
sgdt (%rdi) /* Note: 10 bytes returned */
ret
.global lgdt
lgdt:
lgdt (%rdi)
ret
.global lidt
lidt:
lgdt (%rdi)
ret
// Called with the address of gdt in rdi.
// Load the gdt, then do a ret which will use the argument on the stack as
// a segment #. This stuff is just crazy.
@ -159,8 +169,6 @@ idtput:
.global trput
trput:
// panic
//mov 0, %rax
ltr %di
ret
@ -219,36 +227,45 @@ rdtsc:
ORQ %rdx, %rax /* (hi<<32)|lo */
ret
.global _rdmsr
_rdmsr:
/* int rdmsr(uint32_t reg, uint64_t* value); */
.global rdmsr
rdmsr:
pushq %rcx
pushq %rdx
pushq %rbp
xorq %rbp, %rbp
movl %edi, %ecx
.global _rdmsrinst
_rdmsrinst:
rdmsr
/* u64int rdmsr(u32int); */
xchgl %edx, %eax /* swap lo/hi, zero-extend */
SHLQ $32, %rax /* hi<<32 */
ORQ %rdx, %rax /* (hi<<32)|lo */
xchgl %edx, %eax /* swap lo/hi, zero-extend */
shlq $32, %rax /* hi<<32 */
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 %rcx
ret
.global _wrmsr
_wrmsr:
pushq %rax // do we need to do this?
/*int wrmsr(uint32_t reg, uint64_t value) */
.global wrmsr
wrmsr:
pushq %rcx
pushq %rdx
pushq %rbp
movl %edi, %ecx
movl %esi, %eax
movq %rsi, %rdx
shrq $32, %rdx
xorq %rbp, %rbp
.global _wrmsrinst
_wrmsrinst:
wrmsr
movq %rbp, %rax
popq %rbp
popq %rdx
popq %rcx
popq %rax
ret
.global invlpg
@ -380,6 +397,24 @@ adec:
subl $1, %eax
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,
* and don't have the same overflow/underflow conditions
@ -564,38 +599,86 @@ _mm32done:
movl (%rdi), %eax
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
_monitor:
movq %rdi, %rax /* linear address to monitor */
xorq %rcx, %rcx /* no optional extensions yet */
xorq %rdx, %rdx /* no optional hints yet */
.byte 0x0f; .byte 0x01; .byte 0xc8 /* monitor */
rdrand32:
loop32:
rdrand %eax
jc loop32
ret
.global _mwait
_mwait:
movq %rdi, %rcx /* optional extensions */
.byte 0x0f; .byte 0x01; .byte 0xc9 /* mwait */
rdrand64:
loop64:
rdrand %rax
jc loop64
ret
.global k10mwait
k10mwait:
k10mwloop:
movq %rdi,%rcx
movq (%rcx), %rax
cmpq $0, %rax
jne k10mwdone
movq %rdi, %rax /* linear address to monitor */
xorq %rcx, %rcx /* no optional extensions yet */
xorq %rdx, %rdx /* no optional hints yet */
.byte 0x0f; .byte 0x01; .byte 0xc8 /* monitor */
movq %rdi, %rcx
movq 0(%rcx), %rax
cmpq $0, %rax
jne k10mwdone
xorq %rcx, %rcx /* optional extensions */
.byte 0x0f; .byte 0x01; .byte 0xc9 /* mwait */
jmp k10mwloop
k10mwdone:
ret
.globl rdrandbuf
rdrandbuf:
movq %rdi, %rdx
movl %esi, %ecx
shrq $3, %rcx
eights:
cmpl $0, %ecx
jg f1
call rdrand64
movq %rax, 0(%rdx)
addq $8, %rdx
subl $1, %ecx
jmp eights
f1:
movl %esi, %ecx
andl $7, %ecx
shrq $2, %rcx
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

View File

@ -11,6 +11,10 @@
touser:
cli
swapgs
movq $0, %r15
movq $0, %r14
movq $SSEL(SiUDS, SsRPL3), %rax
movw %ax, %ds
movw %ax, %es
@ -39,10 +43,10 @@ syscallentry:
addq $KSTACK, %rsp
/* build Ureg */
pushq $SSEL(SiUDS, SsRPL3) /* old stack segment */
pushq $UDSEL /* old stack segment */
pushq %r13 /* old sp */
pushq %r11 /* old flags */
pushq $SSEL(SiUCS, SsRPL3) /* old code segment */
pushq $UESEL /* old code segment */
pushq %rcx /* old ip */
movq %r14, 24(%r15) /* restore %r14 from m->tmp0 */
@ -116,6 +120,6 @@ syscallreturn:
.globl sysrforkret
sysrforkret:
movq $0, 0(%rsp)
movq %r14, (13*8)(%rsp) /* preserve up-> */
movq %r15, (14*8)(%rsp) /* preserve m-> */
// movq %r14, (13*8)(%rsp) /* preserve up-> */
// movq %r15, (14*8)(%rsp) /* preserve m-> */
jmp syscallreturn

View File

@ -3,475 +3,445 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "apic.h"
#include "io.h"
#include "adr.h"
#undef DBG
#define DBG jehanne_print
#include "mp.h"
enum { /* Local APIC registers */
Id = 0x0020, /* Identification */
Ver = 0x0030, /* Version */
Tp = 0x0080, /* Task Priority */
Ap = 0x0090, /* Arbitration Priority */
Pp = 0x00a0, /* Processor Priority */
Eoi = 0x00b0, /* EOI */
Ld = 0x00d0, /* Logical Destination */
Df = 0x00e0, /* Destination Format */
Siv = 0x00f0, /* Spurious Interrupt Vector */
Is = 0x0100, /* Interrupt Status (8) */
Tm = 0x0180, /* Trigger Mode (8) */
Ir = 0x0200, /* Interrupt Request (8) */
Es = 0x0280, /* Error Status */
Iclo = 0x0300, /* Interrupt Command */
Ichi = 0x0310, /* Interrupt Command [63:32] */
Lvt0 = 0x0320, /* Local Vector Table 0 */
Lvt5 = 0x0330, /* Local Vector Table 5 */
Lvt4 = 0x0340, /* Local Vector Table 4 */
Lvt1 = 0x0350, /* Local Vector Table 1 */
Lvt2 = 0x0360, /* Local Vector Table 2 */
Lvt3 = 0x0370, /* Local Vector Table 3 */
Tic = 0x0380, /* Timer Initial Count */
Tcc = 0x0390, /* Timer Current Count */
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 { /* Local APIC registers */
LapicID = 0x0020, /* ID */
LapicVER = 0x0030, /* Version */
LapicTPR = 0x0080, /* Task Priority */
LapicAPR = 0x0090, /* Arbitration Priority */
LapicPPR = 0x00A0, /* Processor Priority */
LapicEOI = 0x00B0, /* EOI */
LapicLDR = 0x00D0, /* Logical Destination */
LapicDFR = 0x00E0, /* Destination Format */
LapicSVR = 0x00F0, /* Spurious Interrupt Vector */
LapicISR = 0x0100, /* Interrupt Status (8 registers) */
LapicTMR = 0x0180, /* Trigger Mode (8 registers) */
LapicIRR = 0x0200, /* Interrupt Request (8 registers) */
LapicESR = 0x0280, /* Error Status */
LapicICRLO = 0x0300, /* Interrupt Command */
LapicICRHI = 0x0310, /* Interrupt Command [63:32] */
LapicTIMER = 0x0320, /* Local Vector Table 0 (TIMER) */
LapicPCINT = 0x0340, /* Performance Counter LVT */
LapicLINT0 = 0x0350, /* Local Vector Table 1 (LINT0) */
LapicLINT1 = 0x0360, /* Local Vector Table 2 (LINT1) */
LapicERROR = 0x0370, /* Local Vector Table 3 (ERROR) */
LapicTICR = 0x0380, /* Timer Initial Count */
LapicTCCR = 0x0390, /* Timer Current Count */
LapicTDCR = 0x03E0, /* Timer Divide Configuration */
};
enum { /* Siv */
Swen = 0x00000100, /* Software Enable */
Fdis = 0x00000200, /* Focus Disable */
enum { /* LapicSVR */
LapicENABLE = 0x00000100, /* Unit Enable */
LapicFOCUS = 0x00000200, /* Focus Processor Checking Disable */
};
enum { /* Iclo */
Lassert = 0x00004000, /* Assert level */
enum { /* LapicICRLO */
/* [14] IPI Trigger Mode Level (RW) */
LapicDEASSERT = 0x00000000, /* Deassert level-sensitive interrupt */
LapicASSERT = 0x00004000, /* Assert level-sensitive interrupt */
DSnone = 0x00000000, /* Use Destination Field */
DSself = 0x00040000, /* Self is only destination */
DSallinc = 0x00080000, /* All including self */
DSallexc = 0x000c0000, /* All Excluding self */
/* [17:16] Remote Read Status */
LapicINVALID = 0x00000000, /* Invalid */
LapicWAIT = 0x00010000, /* In-Progress */
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 */
Periodic = 0x00020000, /* Periodic Timer Mode */
enum { /* LapicESR */
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 */
DivX2 = 0x00000000, /* Divide by 2 */
DivX4 = 0x00000001, /* Divide by 4 */
DivX8 = 0x00000002, /* Divide by 8 */
DivX16 = 0x00000003, /* Divide by 16 */
DivX32 = 0x00000008, /* Divide by 32 */
DivX64 = 0x00000009, /* Divide by 64 */
DivX128 = 0x0000000a, /* Divide by 128 */
DivX1 = 0x0000000b, /* Divide by 1 */
enum { /* LapicTIMER */
/* [17] Timer Mode (RW) */
LapicONESHOT = 0x00000000, /* One-shot */
LapicPERIODIC = 0x00020000, /* Periodic */
/* [19:18] Timer Base (RW) */
LapicCLKIN = 0x00000000, /* use CLKIN as input */
LapicTMBASE = 0x00040000, /* use TMBASE */
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 Lapic xlapic[Napic];
Lapic*
lapiclookup(uint32_t id)
typedef struct Apictimer Apictimer;
struct Apictimer
{
Lapic *a;
uint64_t hz;
uint32_t max;
uint32_t min;
uint32_t div;
int tdx;
};
if(id >= nelem(xlapic))
return nil;
a = xlapic + id;
if(a->useable)
return a;
return nil;
}
static Apictimer lapictimer[MACHMAX];
static uint32_t
lapicrget(int r)
lapicr(int r)
{
return lapicbase[r/4];
return *(lapicbase+(r/sizeof(*lapicbase)));
}
static void
lapicrput(int r, uint32_t data)
lapicw(int r, uint32_t data)
{
if(lapicbase != nil){
/* early panics can occur with lapicbase uninitialized
* but if we let it fault, we loose the actual panic PC
*/
lapicbase[r/4] = data;
}
}
int
lapiceoi(int vecno)
{
lapicrput(Eoi, 0