This commit is contained in:
Alex Musolino 2020-12-15 20:55:41 +10:30
commit 3749e92cdb
136 changed files with 2715 additions and 2234 deletions

View file

@ -1,3 +1,3 @@
#!/bin/rc
netdir=`{echo $3 | sed 's;/[0-9]+$;!*!0;'}
exec /bin/exportfs -a -A $netdir
exec /bin/oexportfs -a -A $netdir

View file

@ -13,6 +13,8 @@ fn dbsrc{
fn go{
type=`{file <$1 | sed 's/stdin: //'}
switch($type){
case 'Ascii'
plumbit $1 '(ascii file)'
case 'rc executable file'
plumbit $1 '(rc executable)'
case *executable* *'plan 9 boot image'*

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -13,7 +13,7 @@
1 2 '!
1 3 '"
1 4 '#
1 5 '$
1 5 '¤
1 6 '%
1 7 '&
1 8 '/
@ -40,7 +40,13 @@
3 10 ']
3 11 '}
3 12 '\
3 13 '¸
3 18 '€
3 27 '~
3 46 '¢
3 86 '|
3 39 'ø
3 40 'æ
7 13 '˛
7 39 'Ø
7 40 'Æ

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@ _1 53 '_
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@ _1 53 '_
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -345,7 +345,7 @@
2 88 0
2 89 0
2 90 0
2 91 0
2 91 0xf868
2 92 0
2 93 0
2 94 0

View file

@ -99,7 +99,7 @@ If a
argument is present, the
.I patternfile
is passed to
.IR exportfs (4)
.IR oexportfs (4)
to control how much of the local name space will be exported to
the remote system.
.PP
@ -210,7 +210,7 @@ connections, if requested by the initial protocol.
The name space of the terminal side of the
.I cpu
command is mounted, via
.IR exportfs (4),
.IR oexportfs (4),
on the CPU side on directory
.BR /mnt/term .
The files such as
@ -222,7 +222,7 @@ are bound to their standard locations from there.
.IR rcpu (1) ,
.IR rc (1) ,
.IR rio (1) ,
.IR exportfs (4) ,
.IR oexportfs (4) ,
.IR aan (8)
.SH BUGS
Binds and mounts done after the terminal

View file

@ -14,7 +14,7 @@ md \- emulator
.I Md
is an emulator for the Sega Megadrive/Genesis.
It executes the romfile given as an argument.
The \fBz\fR, \fBx\fR, \fBa\fR, return and shift keys correspond to A, B, C, Start and Select, respectively.
The \fBz\fR, \fBx\fR, \fBc\fR, return and shift keys correspond to A, B, C, Start and Select, respectively.
Other keys:
.TP
F1

View file

@ -4,6 +4,9 @@ vmx \- virtual PC
.SH SYNOPSIS
.B vmx
[
.B -D
]
[
.B -M
.I mem
]
@ -24,7 +27,7 @@ vmx \- virtual PC
.I blockfile
]
[
.B -v
.BR -v | -w
.I vga
]
[
@ -58,9 +61,17 @@ Boot modules can be specified with the
.B -m
argument.
.PP
.B -D
enables debug messages.
.PP
If
.B -v
is specified, a graphics device, PS/2 keyboard and mouse are simulated.
The
.B -w
flag behaves the same as
.B -v
but also creates a new window for the screen.
Clicking on the screen "grabs" the mouse; pressing Ctrl and Alt simultaneously releases the grab.
Valid values for the argument are
.TP

View file

@ -32,6 +32,19 @@ requires that
.I newfd
be no greater than 20 more than the highest file descriptor ever used by
the program.
.PP
.I Dup
does not copy the per file descriptor
.B OCEXEC
flag,
meaning that
.I newfd
will not be closed on
.IR exec(2)
syscall,
when
.I oldfd
had been previously opend with it.
.SH SOURCE
.B /sys/src/libc/9syscall
.SH SEE ALSO

View file

@ -147,17 +147,20 @@ messages are idempotent,
unlike
.BR swap .
.TP
.B scrollswap
inverts the scroll wheel.
.TP
.B reset
clears the mouse
to its default state.
.TP
.B blank
Blank the screen.
blanks the screen.
The screen also blanks after 30 minutes of inactivity.
The screen can be unblanked by moving the mouse.
.TP
.BI blanktime " minutes"
Set the timeout before the
sets the timeout before the
screen blanks; the default is 30 minutes.
If
.I minutes

View file

@ -1,6 +1,6 @@
.TH EXPORTFS 4
.SH NAME
exportfs, srvfs \- network file server plumbing
exportfs, srvfs \- file server plumbing
.SH SYNOPSIS
.B exportfs
[
@ -26,17 +26,11 @@ exportfs, srvfs \- network file server plumbing
.I path
.SH DESCRIPTION
.I Exportfs
is a user level file server that allows Plan 9 compute servers, rather
than file servers, to export portions of a name space across networks.
The service is started either by the
.IR cpu (1)
command or by a network listener process. An initial protocol
establishes a root directory for the exported name space.
The
connection to
.I exportfs
is then mounted, typically on
.BR /mnt/term .
is a user level file server that allows Plan 9 cpu servers, rather
than file servers, to export portions of a name space.
It is usually started by other programs such as
.IR rcpu (1)
after a secure channel has been established.
.I Exportfs
then acts as a relay file server: operations in the imported file
tree are executed on the remote server and the results returned. This
@ -44,49 +38,6 @@ gives the appearance of exporting a name space from a remote machine
into a local file tree.
.PP
The options are:
.TF "-A \fIaddress"
.PD
.TP
.B -A \fIaddress
Use the network
.I address
to announce
.IR aan (8)
connections,
if requested by the initial protocol.
.TP
.B -a
Authenticate the user with the
.I p9any
protocol before running the regular
.I exportfs
session; used when
.I exportfs
is invoked to handle an incoming network connection.
.I Exportfs
creates a new name space for each connection, using
.B /lib/namespace
by default (see
.IR namespace (6)).
.TP
.B -B \fIaddress
Dial
.IR address ,
authenticate as a
.I p9any
client, and then
serve that network connection.
Requires setting the root of the name space with
.B -r
or
.BR -s .
The remote system should run
.B import
.B -B
to handle the call.
See
.IR import (4)
for an example.
.TP
.B -d -f \fIdbgfile
Log all 9P traffic to
@ -94,31 +45,6 @@ Log all 9P traffic to
(default
.BR /tmp/exportdb ).
.TP
.B -e '\fIenc auth\fL'
Set the encryption and authentication algorithms to use for
encrypting the wire traffic (see
.IR ssl (3)).
The defaults are
.B rc4_256
and
.BR sha1 .
.TP
.B -m \fImsize
Set the maximum message size that
.I exportfs
should offer to send (see
.IR version (5));
this helps tunneled
9P connections to avoid unnecessary fragmentation.
.TP
.B -N \fInsfile
Serve the name space described by
.IR nsfile .
.TP
.B -n
Disallow mounts by user
.BR none .
.TP
.B -P \fIpatternfile
Restrict the set of exported files.
.I Patternfile
@ -137,11 +63,11 @@ must not match.
Make the served name space read only.
.TP
.B -r \fIroot
Bypass the initial protocol, serving the name space rooted at
Serve the name space rooted at
.IR root .
.TP
.B -S \fIservice
bypass the initial protocol, serving the result of mounting
Serve the result of mounting
.IR service .
A separate mount is used for each
.IR attach (5)
@ -156,29 +82,16 @@ equivalent to
.B -r
.BR / ;
kept for compatibility.
.TP
.B -m \fImsize
Set the maximum message size that
.I exportfs
should offer to send (see
.IR version (5));
this helps tunneled
9P connections to avoid unnecessary fragmentation.
.PD
.PP
The
.B cpu
command uses
.I exportfs
to serve device files in the terminal. The
.IR import (4)
command calls
.I exportfs
on a remote machine, permitting users to access arbitrary pieces of
name space on other systems.
.PP
Because the kernel disallows reads and writes on mounted pipes
(as might be found in
.BR /srv ),
.I exportfs
calls itself (with appropriate
.B -m
and
.B -S
options) to simulate reads and writes on such files.
.PP
.I Srvfs
invokes
.I exportprog
@ -251,7 +164,4 @@ cd /n/spy; ls
.br
.B /sys/src/cmd/srvfs.c
.SH SEE ALSO
.IR dial (2),
.IR import (4),
.IR aan (8),
.IR listen (8)
.IR rcpu (1)

View file

@ -45,7 +45,7 @@ A process is started on the
remote machine, with authority of the user of
.IR import ,
to perform work for the local machine using the
.IR exportfs (4)
.IR oexportfs (4)
service.
The default port used is TCP 17007.
If
@ -76,7 +76,7 @@ This is useful for connecting to foreign systems like Inferno.
.B -z
Bypass the initial protocol request for which remote tree to serve.
This is necessary when the remote
.IR exportfs (4)
.IR oexportfs (4)
is running with the
.B -r
or
@ -144,7 +144,7 @@ runs a
.I p9any
authentication (as server) over its file descriptor 0
(expected to be an incoming network connection from
.B exportfs
.B oexportfs
.BR -B ),
mounts the connection onto
.IR mntpt ,
@ -189,7 +189,7 @@ When
boots, it runs
.IP
.EX
exportfs -R -r /usr/web -B tcp!webvax!999
oexportfs -R -r /usr/web -B tcp!webvax!999
.EE
.PP
to serve a read-only copy of
@ -212,7 +212,7 @@ to restart
.IR rcpu (1),
.IR bind (1),
.IR ssl (3),
.IR exportfs (4),
.IR oexportfs (4),
.IR srv (4),
.IR aan (8),
.IR listen (8),

146
sys/man/4/oexportfs Normal file
View file

@ -0,0 +1,146 @@
.TH OEXPORTFS 4
.SH NAME
oexportfs \- legacy exportfs for cpu and import
.SH SYNOPSIS
.PP
.B oexportfs
[
.I options
]
.SH DESCRIPTION
.I Oexportfs
is older version of the
.IR exportfs (4)
program that handles an initial protocol to establish a root directory
for the exported name space.
It also provides authentication and encryption using
the
.IR ssl (3)
device.
.PP
It is used exclusively by the deprecated
.IR cpu (1)
and
.IR import (4)
services.
.PP
The options are:
.TP
.B -d -f \fIdbgfile
Log all 9P traffic to
.I dbgfile
(default
.BR /tmp/exportdb ).
.TP
.B -P \fIpatternfile
Restrict the set of exported files.
.I Patternfile
contains one regular expression per line,
to be matched against path names
relative to the current working directory
and starting with
.BR / .
For a file to be exported, all lines with a prefix
.B +
must match and all those with prefix
.B -
must not match.
.TP
.B -R
Make the served name space read only.
.TP
.B -r \fIroot
Serve the name space rooted at
.IR root .
.TP
.B -S \fIservice
Serve the result of mounting
.IR service .
A separate mount is used for each
.IR attach (5)
message,
to correctly handle servers in which each mount
corresponds to a different client
.IR e.g. , (
.IR rio (4)).
.TP
.B -s
equivalent to
.B -r
.BR / ;
kept for compatibility.
.TP
.B -m \fImsize
Set the maximum message size that
.I oexportfs
should offer to send (see
.IR version (5));
this helps tunneled
9P connections to avoid unnecessary fragmentation.
.TP
.B -A \fIaddress
Use the network
.I address
to announce
.IR aan (8)
connections,
if requested by the initial protocol.
.TP
.B -a
Authenticate the user with the
.I p9any
protocol before running the regular
.I oexportfs
session; used when
.I oexportfs
is invoked to handle an incoming network connection.
.I Exportfs
creates a new name space for each connection, using
.B /lib/namespace
by default (see
.IR namespace (6)).
.TP
.B -B \fIaddress
Dial
.IR address ,
authenticate as a
.I p9any
client, and then
serve that network connection.
Requires setting the root of the name space with
.B -r
or
.BR -s .
The remote system should run
.B import
.B -B
to handle the call.
See
.IR import (4)
for an example.
.TP
.B -e '\fIenc auth\fL'
Set the encryption and authentication algorithms to use for
encrypting the wire traffic (see
.IR ssl (3)).
The defaults are
.B rc4_256
and
.BR sha1 .
.TP
.B -N \fInsfile
Serve the name space described by
.IR nsfile .
.TP
.B -n
Disallow mounts by user
.BR none .
.EE
.SH SOURCE
.B /sys/src/cmd/exportfs/oexportfs.c
.SH SEE ALSO
.IR dial (2),
.IR exportfs (4),
.IR import (4),
.IR aan (8),
.IR listen (8)

View file

@ -7,10 +7,7 @@ filter
.B ptrap
.I port
[\fB!\fR]\fIregexp\fR
[
.I port
[\fB!\fR]\fIregexp\fR ...
]
[ +\fIattr\fR [\fB!\fR]\fIregexp\fR ... ] ...
.SH DESCRIPTION
.I Ptrap
is a program that mounts itself over a
@ -20,20 +17,20 @@ service mounted at
and filters incoming messages according to the rules provided on the command line.
.PP
.I Ptrap
accepts an arbitrary number of argument pairs; each pair consists of a port name
.I port
and a regular expression
.I regexp
(see
.IR regexp (6)).
Each incoming message that does not match
.I regexp
is discarded.
The
.I regexp
can be optionally prefixed by
.B !
to indicate logical inversion (i.e. messages matching the regexp are discarded).
accepts an arbitrary number of filters;
each filter applies to a port, and may match over both the data and attributes of plumb messages.
.PP
A filter is formatted as a port name, a data filter, and a list of attribute filters.
.PP
The data filter is a
.IR regex (6)
that matches the plumbed data.
The attribute filter consists of the attribute name prefixed with a '+', followed by a
.IR regex (6)
that matches the contents of the attribute.
Any regex may be prefixed with a '!' in order to negate a match,
causing all matches for that regex to be discarded.
All parts of a filter must match in order for a plumb message to be forwarded.
.SH EXAMPLES
Start a
.IR sam (1)
@ -52,6 +49,15 @@ instance for all other editing jobs:
ptrap edit '!^/sys/src/9/'
sam
.EE
.PP
Start an
.IR acme (1)
instance instance dedicated to reading plumbed manual pages:
.IP
.EX
ptrap edit '.*' +action '^showdata' +filename '^/man/'
acme -c1
.EE
.SH SOURCE
.B /sys/src/cmd/ptrap.c
.SH SEE ALSO

View file

@ -815,11 +815,13 @@ This deprecated option is rarely necessary in newer kernels.
This limits the maximum amount of memory (in megabytes) the graphics
image memory pool can grow. The default is unlimited for terminals
and cpu servers.
.SS \fL*nomce=\fIvalue\fP
.SS \fL*noavx=\fP
Disables AVX and AVX2 on AMD64 CPUs.
.SS \fL*nomce=\fP
If machine check exceptions are supported by the processor,
then they are enabled by default.
Setting this variable to
.B 1
Setting
.B *nomce
causes them to be disabled even when available.
.SS \fL*nomp=\fP
A multiprocessor machine will enable all processors by default.
@ -836,7 +838,12 @@ processors.
.SS \fL*apicdebug=\fP
Prints a summary of the multiprocessor APIC interrupt configuration.
.SS \fL*nomsi=\fP
Disables message signaled interrupts.
Disables message signaled interrupts for PCI devices.
This option has no effect when
.B *nomp
is set.
.SS \fL*nomtrr=\fP
Disables memory type range register (MTRR) support when set. (debug)
.SS \fL*notsc=\fP
Disables the use of the per processor timestamp counter registers
as high resolution clock.

View file

@ -9,8 +9,9 @@ statusbar, statusmsg \- display a bar graph or status message window
[
.B -w
.I minx,miny,maxx,maxy
]
] [
.I title
]
.br
.B aux/statusmsg
[

View file

@ -13,7 +13,7 @@ intelcputempok(void)
if(m->cpuiddx & Acpif)
if(strcmp(m->cpuidid, "GenuineIntel") == 0){
cpuid(6, regs);
cpuid(6, 0, regs);
return regs[0] & 1;
}
return 0;
@ -28,7 +28,7 @@ cputemprd0(Chan*, void *a, long n, vlong offset)
ulong regs[4];
static ulong tj;
cpuid(6, regs);
cpuid(6, 0, regs);
if((regs[0] & 1) == 0)
goto unsup;
if(tj == 0){

View file

@ -250,7 +250,7 @@ struct Mach
int pdbfree;
u32int dr7; /* shadow copy of dr7 */
u32int xcr0;
void* vmx;
int stack[1];

View file

@ -18,11 +18,6 @@ enum {
Qmax = 32,
};
enum {
CR4Osfxsr = 1 << 9,
CR4Oxmmex = 1 << 10,
};
enum { /* cpuid standard function codes */
Highstdfunc = 0, /* also returns vendor string */
Procsig,
@ -496,24 +491,27 @@ cpuidprint(void)
* (if so turn it on)
* - whether or not it supports the page global flag
* (if so turn it on)
* - detect PAT feature and add write-combining entry
* - detect MTRR support and synchronize state with cpu0
* - detect NX support and enable it for AMD64
* - detect watchpoint support
* - detect FPU features and enable the FPU
*/
int
cpuidentify(void)
{
char *p;
int family, model, nomce;
int family, model;
X86type *t, *tab;
uintptr cr4;
ulong regs[4];
vlong mca, mct, pat;
uintptr cr4;
cpuid(Highstdfunc, regs);
cpuid(Highstdfunc, 0, regs);
memmove(m->cpuidid, &regs[1], BY2WD); /* bx */
memmove(m->cpuidid+4, &regs[3], BY2WD); /* dx */
memmove(m->cpuidid+8, &regs[2], BY2WD); /* cx */
m->cpuidid[12] = '\0';
cpuid(Procsig, regs);
cpuid(Procsig, 0, regs);
m->cpuidax = regs[0];
m->cpuidcx = regs[2];
m->cpuiddx = regs[3];
@ -572,14 +570,13 @@ cpuidentify(void)
* If machine check was enabled clear out any lingering status.
*/
if(m->cpuiddx & (Pge|Mce|Pse)){
vlong mca, mct;
cr4 = getcr4();
if(m->cpuiddx & Pse)
cr4 |= 0x10; /* page size extensions */
if(p = getconf("*nomce"))
nomce = strtoul(p, 0, 0);
else
nomce = 0;
if((m->cpuiddx & Mce) != 0 && !nomce){
if((m->cpuiddx & Mce) != 0 && getconf("*nomce") == nil){
if((m->cpuiddx & Mca) != 0){
vlong cap;
int bank;
@ -631,7 +628,6 @@ cpuidentify(void)
cr4 |= 0x80; /* page global enable bit */
m->havepge = 1;
}
putcr4(cr4);
if((m->cpuiddx & (Mca|Mce)) == Mce)
@ -640,25 +636,20 @@ cpuidentify(void)
#ifdef PATWC
/* IA32_PAT write combining */
if((m->cpuiddx & Pat) != 0 && rdmsr(0x277, &pat) != -1){
pat &= ~(255LL<<(PATWC*8));
pat |= 1LL<<(PATWC*8); /* WC */
wrmsr(0x277, pat);
if((m->cpuiddx & Pat) != 0){
vlong pat;
if(rdmsr(0x277, &pat) != -1){
pat &= ~(255LL<<(PATWC*8));
pat |= 1LL<<(PATWC*8); /* WC */
wrmsr(0x277, pat);
}
}
#endif
if(m->cpuiddx & Mtrr)
if((m->cpuiddx & Mtrr) != 0 && getconf("*nomtrr") == nil)
mtrrsync();
if((m->cpuiddx & (Sse|Fxsr)) == (Sse|Fxsr)){ /* have sse fp? */
fpsave = fpssesave;
fprestore = fpsserestore;
putcr4(getcr4() | CR4Osfxsr|CR4Oxmmex);
} else {
fpsave = fpx87save;
fprestore = fpx87restore;
}
if(strcmp(m->cpuidid, "GenuineIntel") == 0 && (m->cpuidcx & Rdrnd) != 0)
hwrandbuf = rdrandbuf;
else
@ -669,9 +660,9 @@ cpuidentify(void)
m->havewatchpt8 = 1;
/* check and enable NX bit */
cpuid(Highextfunc, regs);
cpuid(Highextfunc, 0, regs);
if(regs[0] >= Procextfeat){
cpuid(Procextfeat, regs);
cpuid(Procextfeat, 0, regs);
if((regs[3] & (1<<20)) != 0){
vlong efer;
@ -689,14 +680,16 @@ cpuidentify(void)
|| family == 6 && (model == 15 || model == 23 || model == 28))
m->havewatchpt8 = 1;
/* Intel SDM claims amd64 support implies 8-byte watchpoint support */
cpuid(Highextfunc, regs);
cpuid(Highextfunc, 0, regs);
if(regs[0] >= Procextfeat){
cpuid(Procextfeat, regs);
cpuid(Procextfeat, 0, regs);
if((regs[3] & 1<<29) != 0)
m->havewatchpt8 = 1;
}
}
fpuinit();
cputype = t;
return t->family;
}

View file

@ -44,6 +44,7 @@ enum {
PROCB_CTLS = 0x4002,
PROCB_IRQWIN = 1<<2,
PROCB_TSCOFFSET = 1<<3,
PROCB_EXITHLT = 1<<7,
PROCB_EXITINVLPG = 1<<9,
PROCB_EXITMWAIT = 1<<10,
@ -100,6 +101,7 @@ enum {
VMENTRY_INTRCODE = 0x4018,
VMENTRY_INTRILEN = 0x401a,
VMCS_TSC_OFFSET = 0x2010,
VMCS_LINK = 0x2800,
GUEST_ES = 0x800,
@ -264,7 +266,9 @@ struct Vmx {
int index, machno;
char errstr[ERRMAX];
Ureg ureg;
uvlong tscoffset;
uintptr cr2;
uintptr xcr0;
uintptr dr[8]; /* DR7 is also kept in VMCS */
u8int launched;
u8int vpid;
@ -483,6 +487,13 @@ dr7write(Vmx *vmx, char *s)
return 0;
}
static int
xcr0write(Vmx *vmx, char *s)
{
vmx->xcr0 = parseval(s) & 7;
return 0;
}
static int
readonly(Vmx *, char *)
{
@ -581,6 +592,7 @@ static GuestReg guestregs[] = {
{VMXVAR(dr[2]), 0, "dr2"},
{VMXVAR(dr[3]), 0, "dr3"},
{VMXVAR(dr[6]), 0, "dr6", nil, dr6write},
{VMXVAR(xcr0), 0, "xcr0", nil, xcr0write},
{GUEST_DR7, 0, "dr7", nil, dr7write},
{VM_INSTRERR, 4, "instructionerror", nil, readonly},
{VM_EXREASON, 4, "exitreason", nil, readonly},
@ -857,7 +869,7 @@ vmxreset(void)
vlong msr;
int i;
cpuid(1, regs);
cpuid(1, 0, regs);
if((regs[2] & 1<<5) == 0) return;
/* check if disabled by BIOS */
if(rdmsr(0x3a, &msr) < 0) return;
@ -945,8 +957,8 @@ vmcsinit(Vmx *vmx)
if(rdmsr(VMX_PROCB_CTLS_MSR, &msr) < 0) error("rdmsr(VMX_PROCB_CTLS_MSR failed");
x = (u32int)procb_ctls | 1<<1 | 7<<4 | 1<<8 | 1<<13 | 1<<14 | 1<<26; /* currently reserved default1 bits */
x |= PROCB_EXITHLT | PROCB_EXITMWAIT;
x |= PROCB_EXITMOVDR | PROCB_EXITIO | PROCB_EXITMONITOR | PROCB_MSRBITMAP;
x |= PROCB_TSCOFFSET | PROCB_EXITMWAIT | PROCB_EXITMONITOR | PROCB_EXITHLT;
x |= PROCB_EXITMOVDR | PROCB_EXITIO | PROCB_MSRBITMAP;
x |= PROCB_USECTLS2;
x &= msr >> 32;
vmcswrite(PROCB_CTLS, x);
@ -1042,8 +1054,8 @@ vmcsinit(Vmx *vmx)
vmx->onentry = FLUSHVPID | FLUSHEPT;
fpinit();
fpsave(&vmx->fp);
vmx->xcr0 = m->xcr0 & 1; /* x87 alone */
memset(vmx->msrbits, -1, 4096);
vmxtrapmsr(vmx, Efer, 0);
vmcswrite(VMENTRY_MSRLDADDR, PADDR(vmx->msrguest));
@ -1051,6 +1063,9 @@ vmcsinit(Vmx *vmx)
vmcswrite(VMEXIT_MSRLDADDR, PADDR(vmx->msrhost));
vmcswrite(MSR_BITMAP, PADDR(vmx->msrbits));
cycles(&vmx->tscoffset);
vmcswrite(VMCS_TSC_OFFSET, vmx->tscoffset);
if(sizeof(uintptr) == 8){
vmxaddmsr(vmx, Star, 0);
vmxaddmsr(vmx, Lstar, 0);
@ -1074,7 +1089,7 @@ vmxstart(Vmx *vmx)
uintptr cr;
vlong x;
putcr4(getcr4() | 0x2000); /* set VMXE */
putcr4(getcr4() | CR4VMXE);
putcr0(getcr0() | 0x20); /* set NE */
cr = getcr0();
if(rdmsr(VMX_CR0_FIXED0, &msr) < 0) error("rdmsr(VMX_CR0_FIXED0) failed");
@ -1590,8 +1605,9 @@ runcmd(Vmx *vmx)
static void
vmxproc(void *vmxp)
{
int init, rc, x;
int init, rc, x, useend;
u32int procbctls, defprocbctls;
u64int start, end, adj;
vlong v;
Vmx *vmx;
@ -1599,6 +1615,8 @@ vmxproc(void *vmxp)
procwired(up, vmx->machno);
sched();
init = 0;
useend = 0;
adj = 0;
defprocbctls = 0;
while(waserror()){
kstrcpy(vmx->errstr, up->errstr, ERRMAX);
@ -1653,11 +1671,29 @@ vmxproc(void *vmxp)
}
if((vmx->dr[7] & ~0xd400) != 0)
putdr01236(vmx->dr);
fpsserestore(&vmx->fp);
putcr2(vmx->cr2);
fprestore(&vmx->fp);
if(m->xcr0 != 0 && vmx->xcr0 != m->xcr0)
putxcr0(vmx->xcr0);
if(vmx->cr2 != getcr2())
putcr2(vmx->cr2);
cycles(&start);
if(useend){
vmx->tscoffset -= end - start + adj;
vmcswrite(VMCS_TSC_OFFSET, vmx->tscoffset);
}
if(adj == 0){
cycles(&adj);
adj -= start;
}
rc = vmlaunch(&vmx->ureg, vmx->launched);
cycles(&end);
useend = 1;
vmx->cr2 = getcr2();
fpssesave(&vmx->fp);
if(m->xcr0 != 0 && vmx->xcr0 != m->xcr0)
putxcr0(m->xcr0);
fpsave(&vmx->fp);
splx(x);
if(rc < 0)
error("vmlaunch failed");
@ -1799,6 +1835,7 @@ vmxnew(void)
free(vmx);
nexterror();
}
memset(vmx, 0, sizeof(Vmx));
vmx->state = VMXINIT;
vmx->lastcmd = &vmx->firstcmd;
vmx->mem.next = &vmx->mem;

View file

@ -15,7 +15,8 @@ void clockintr(Ureg*, void*);
int (*cmpswap)(long*, long, long);
int cmpswap486(long*, long, long);
void (*coherence)(void);
void cpuid(int, ulong regs[]);
void cpuid(int, int, ulong regs[]);
void fpuinit(void);
int cpuidentify(void);
void cpuidprint(void);
void (*cycles)(uvlong*);
@ -40,12 +41,6 @@ void fpinit(void);
void fpoff(void);
void (*fprestore)(FPsave*);
void (*fpsave)(FPsave*);
void fpsserestore(FPsave*);
void fpssesave(FPsave*);
void fpx87restore(FPsave*);
void fpx87restore0(FPsave*);
void fpx87save(FPsave*);
void fpx87save0(FPsave*);
ulong getcr0(void);
ulong getcr2(void);
ulong getcr3(void);
@ -83,7 +78,6 @@ int iprint(char*, ...);
int isaconfig(char*, int, ISAConf*);
void* kaddr(ulong);
#define kmapinval()
void ldmxcsr(ulong);
void lgdt(ushort[3]);
void lldt(ulong);
void lidt(ushort[3]);
@ -138,6 +132,7 @@ void putcr0(ulong);
void putcr2(ulong);
void putcr3(ulong);
void putcr4(ulong);
void putxcr0(ulong);
void putdr(u32int*);
void putdr01236(uintptr*);
void putdr6(u32int);

309
sys/src/9/pc/fpu.c Normal file
View file

@ -0,0 +1,309 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
enum {
CR4Osfxsr = 1 << 9,
CR4Oxmmex = 1 << 10,
};
/* from l.s */
extern void fpsserestore(FPsave*);
extern void fpssesave(FPsave*);
extern void fpx87restore0(FPsave*);
extern void fpx87save0(FPsave*);
extern void ldmxcsr(ulong);
void
putxcr0(ulong)
{
}
/*
* we keep FPsave structure in SSE format emulating FXSAVE / FXRSTOR
* instructions for legacy x87 fpu.
*/
static void
fpx87save(FPsave *fps)
{
ushort tag;
fpx87save0(fps);
/*
* convert x87 tag word to fxsave tag byte:
* 00, 01, 10 -> 1, 11 -> 0
*/
tag = ~fps->tag;
tag = (tag | (tag >> 1)) & 0x5555;
tag = (tag | (tag >> 1)) & 0x3333;
tag = (tag | (tag >> 2)) & 0x0F0F;
tag = (tag | (tag >> 4)) & 0x00FF;
/* NOP fps->fcw = fps->control; */
fps->fsw = fps->status;
fps->ftw = tag;
fps->fop = fps->opcode;
fps->fpuip = fps->pc;
fps->cs = fps->selector;
fps->fpudp = fps->operand;
fps->ds = fps->oselector;
#define MOVA(d,s) \
*((ushort*)(d+8)) = *((ushort*)(s+8)), \
*((ulong*)(d+4)) = *((ulong*)(s+4)), \
*((ulong*)(d)) = *((ulong*)(s))
MOVA(fps->xregs+0x70, fps->regs+70);
MOVA(fps->xregs+0x60, fps->regs+60);
MOVA(fps->xregs+0x50, fps->regs+50);
MOVA(fps->xregs+0x40, fps->regs+40);
MOVA(fps->xregs+0x30, fps->regs+30);
MOVA(fps->xregs+0x20, fps->regs+20);
MOVA(fps->xregs+0x10, fps->regs+10);
MOVA(fps->xregs+0x00, fps->regs+00);
#undef MOVA
#define CLR6(d) \
*((ulong*)(d)) = 0, \
*((ushort*)(d+4)) = 0
CLR6(fps->xregs+0x70+10);
CLR6(fps->xregs+0x60+10);
CLR6(fps->xregs+0x50+10);
CLR6(fps->xregs+0x40+10);
CLR6(fps->xregs+0x30+10);
CLR6(fps->xregs+0x20+10);
CLR6(fps->xregs+0x10+10);
CLR6(fps->xregs+0x00+10);
#undef CLR6
fps->rsrvd1 = fps->rsrvd2 = fps->mxcsr = fps->mxcsr_mask = 0;
}
static void
fpx87restore(FPsave *fps)
{
ushort msk, tos, tag, *reg;
/* convert fxsave tag byte to x87 tag word */
tag = 0;
tos = 7 - ((fps->fsw >> 11) & 7);
for(msk = 0x80; msk != 0; tos--, msk >>= 1){
tag <<= 2;
if((fps->ftw & msk) != 0){
reg = (ushort*)&fps->xregs[(tos & 7) << 4];
switch(reg[4] & 0x7fff){
case 0x0000:
if((reg[0] | reg[1] | reg[2] | reg[3]) == 0){
tag |= 1; /* 01 zero */
break;
}
/* no break */
case 0x7fff:
tag |= 2; /* 10 special */
break;
default:
if((reg[3] & 0x8000) == 0)
break; /* 00 valid */
tag |= 2; /* 10 special */
break;
}
}else{
tag |= 3; /* 11 empty */
}
}
#define MOVA(d,s) \
*((ulong*)(d)) = *((ulong*)(s)), \
*((ulong*)(d+4)) = *((ulong*)(s+4)), \
*((ushort*)(d+8)) = *((ushort*)(s+8))
MOVA(fps->regs+00, fps->xregs+0x00);
MOVA(fps->regs+10, fps->xregs+0x10);
MOVA(fps->regs+20, fps->xregs+0x20);
MOVA(fps->regs+30, fps->xregs+0x30);
MOVA(fps->regs+40, fps->xregs+0x40);
MOVA(fps->regs+50, fps->xregs+0x50);
MOVA(fps->regs+60, fps->xregs+0x60);
MOVA(fps->regs+70, fps->xregs+0x70);
#undef MOVA
fps->oselector = fps->ds;
fps->operand = fps->fpudp;
fps->opcode = fps->fop & 0x7ff;
fps->selector = fps->cs;
fps->pc = fps->fpuip;
fps->tag = tag;
fps->status = fps->fsw;
/* NOP fps->control = fps->fcw; */
fps->r1 = fps->r2 = fps->r3 = fps->r4 = 0;
fpx87restore0(fps);
}
static char* mathmsg[] =
{
nil, /* handled below */
"denormalized operand",
"division by zero",
"numeric overflow",
"numeric underflow",
"precision loss",
};
static void
mathnote(ulong status, ulong pc)
{
char *msg, note[ERRMAX];
int i;
/*
* Some attention should probably be paid here to the
* exception masks and error summary.
*/
msg = "unknown exception";
for(i = 1; i <= 5; i++){
if(!((1<<i) & status))
continue;
msg = mathmsg[i];
break;
}
if(status & 0x01){
if(status & 0x40){
if(status & 0x200)
msg = "stack overflow";
else
msg = "stack underflow";
}else
msg = "invalid operation";
}
snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
msg, pc, status);
postnote(up, 1, note, NDebug);
}
/*
* math coprocessor error
*/
static void
matherror(Ureg*, void*)
{
/*
* a write cycle to port 0xF0 clears the interrupt latch attached
* to the error# line from the 387
*/
if(!(m->cpuiddx & Fpuonchip))
outb(0xF0, 0xFF);
/*
* get floating point state to check out error
*/
fpsave(up->fpsave);
up->fpstate = FPinactive;
mathnote(up->fpsave->fsw, up->fpsave->fpuip);
}
/*
* SIMD error
*/
static void
simderror(Ureg *ureg, void*)
{
fpsave(up->fpsave);
up->fpstate = FPinactive;
mathnote(up->fpsave->mxcsr & 0x3f, ureg->pc);
}
/*
* math coprocessor emulation fault
*/
static void
mathemu(Ureg *ureg, void*)
{
ulong status, control;
if(up->fpstate & FPillegal){
/* someone did floating point in a note handler */
postnote(up, 1, "sys: floating point in note handler", NDebug);
return;
}
switch(up->fpstate){
case FPinit:
fpinit();
if(fpsave == fpssesave)
ldmxcsr(0x1f80); /* no simd exceptions on 386 */
while(up->fpsave == nil)
up->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
up->fpstate = FPactive;
break;
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.
*/
status = up->fpsave->fsw;
control = up->fpsave->fcw;
if((status & ~control) & 0x07F){
mathnote(status, up->fpsave->fpuip);
break;
}
fprestore(up->fpsave);
up->fpstate = FPactive;
break;
case FPactive:
panic("math emu pid %ld %s pc 0x%lux",
up->pid, up->text, ureg->pc);
break;
}
}
/*
* math coprocessor segment overrun
*/
static void
mathover(Ureg*, void*)
{
pexit("math overrun", 0);
}
void
mathinit(void)
{
trapenable(VectorCERR, matherror, 0, "matherror");
if(m->cpuidfamily == 3)
intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
trapenable(VectorCNA, mathemu, 0, "mathemu");
trapenable(VectorCSO, mathover, 0, "mathover");
trapenable(VectorSIMD, simderror, 0, "simderror");
}
/*
* fpuinit(), called from cpuidentify() for each cpu.
*/
void
fpuinit(void)
{
uintptr cr4;
if((m->cpuiddx & (Sse|Fxsr)) == (Sse|Fxsr)){ /* have sse fp? */
fpsave = fpssesave;
fprestore = fpsserestore;
cr4 = getcr4() | CR4Osfxsr|CR4Oxmmex;
putcr4(cr4);
} else {
fpsave = fpx87save;
fprestore = fpx87restore;
}
}

View file

@ -520,7 +520,7 @@ TEXT _peekinst(SB), $0
* a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be
* toggled then it's an older 486 of some kind.
*
* cpuid(fun, regs[4]);
* cpuid(fn, sublvl, regs[4]);
*/
TEXT cpuid(SB), $0
MOVL $0x240000, AX
@ -539,6 +539,7 @@ TEXT cpuid(SB), $0
TESTL $0x200000, AX /* Id */
JZ _cpu486 /* can't toggle this bit on some 486 */
MOVL fn+0(FP), AX
MOVL sublvl+4(FP), CX
CPUID
JMP _cpuid
_cpu486:
@ -555,7 +556,7 @@ _zaprest:
XORL CX, CX
XORL DX, DX
_cpuid:
MOVL regs+4(FP), BP
MOVL regs+8(FP), BP
MOVL AX, 0(BP)
MOVL BX, 4(BP)
MOVL CX, 8(BP)

View file

@ -233,272 +233,6 @@ confinit(void)
}
}
/*
* we keep FPsave structure in SSE format emulating FXSAVE / FXRSTOR
* instructions for legacy x87 fpu.
*/
void
fpx87save(FPsave *fps)
{
ushort tag;
fpx87save0(fps);
/*
* convert x87 tag word to fxsave tag byte:
* 00, 01, 10 -> 1, 11 -> 0
*/
tag = ~fps->tag;
tag = (tag | (tag >> 1)) & 0x5555;
tag = (tag | (tag >> 1)) & 0x3333;
tag = (tag | (tag >> 2)) & 0x0F0F;
tag = (tag | (tag >> 4)) & 0x00FF;
/* NOP fps->fcw = fps->control; */
fps->fsw = fps->status;
fps->ftw = tag;
fps->fop = fps->opcode;
fps->fpuip = fps->pc;
fps->cs = fps->selector;
fps->fpudp = fps->operand;
fps->ds = fps->oselector;
#define MOVA(d,s) \
*((ushort*)(d+8)) = *((ushort*)(s+8)), \
*((ulong*)(d+4)) = *((ulong*)(s+4)), \
*((ulong*)(d)) = *((ulong*)(s))
MOVA(fps->xregs+0x70, fps->regs+70);
MOVA(fps->xregs+0x60, fps->regs+60);
MOVA(fps->xregs+0x50, fps->regs+50);
MOVA(fps->xregs+0x40, fps->regs+40);
MOVA(fps->xregs+0x30, fps->regs+30);
MOVA(fps->xregs+0x20, fps->regs+20);
MOVA(fps->xregs+0x10, fps->regs+10);
MOVA(fps->xregs+0x00, fps->regs+00);
#undef MOVA
#define CLR6(d) \
*((ulong*)(d)) = 0, \
*((ushort*)(d+4)) = 0
CLR6(fps->xregs+0x70+10);
CLR6(fps->xregs+0x60+10);
CLR6(fps->xregs+0x50+10);
CLR6(fps->xregs+0x40+10);
CLR6(fps->xregs+0x30+10);
CLR6(fps->xregs+0x20+10);
CLR6(fps->xregs+0x10+10);
CLR6(fps->xregs+0x00+10);
#undef CLR6
fps->rsrvd1 = fps->rsrvd2 = fps->mxcsr = fps->mxcsr_mask = 0;
}
void
fpx87restore(FPsave *fps)
{
ushort msk, tos, tag, *reg;
/* convert fxsave tag byte to x87 tag word */
tag = 0;
tos = 7 - ((fps->fsw >> 11) & 7);
for(msk = 0x80; msk != 0; tos--, msk >>= 1){
tag <<= 2;
if((fps->ftw & msk) != 0){
reg = (ushort*)&fps->xregs[(tos & 7) << 4];
switch(reg[4] & 0x7fff){
case 0x0000:
if((reg[0] | reg[1] | reg[2] | reg[3]) == 0){
tag |= 1; /* 01 zero */
break;
}
/* no break */
case 0x7fff:
tag |= 2; /* 10 special */
break;
default:
if((reg[3] & 0x8000) == 0)
break; /* 00 valid */
tag |= 2; /* 10 special */
break;
}
}else{
tag |= 3; /* 11 empty */
}
}
#define MOVA(d,s) \
*((ulong*)(d)) = *((ulong*)(s)), \
*((ulong*)(d+4)) = *((ulong*)(s+4)), \
*((ushort*)(d+8)) = *((ushort*)(s+8))
MOVA(fps->regs+00, fps->xregs+0x00);
MOVA(fps->regs+10, fps->xregs+0x10);
MOVA(fps->regs+20, fps->xregs+0x20);
MOVA(fps->regs+30, fps->xregs+0x30);
MOVA(fps->regs+40, fps->xregs+0x40);
MOVA(fps->regs+50, fps->xregs+0x50);
MOVA(fps->regs+60, fps->xregs+0x60);
MOVA(fps->regs+70, fps->xregs+0x70);
#undef MOVA
fps->oselector = fps->ds;
fps->operand = fps->fpudp;
fps->opcode = fps->fop & 0x7ff;
fps->selector = fps->cs;
fps->pc = fps->fpuip;
fps->tag = tag;
fps->status = fps->fsw;
/* NOP fps->control = fps->fcw; */
fps->r1 = fps->r2 = fps->r3 = fps->r4 = 0;
fpx87restore0(fps);
}
static char* mathmsg[] =
{
nil, /* handled below */
"denormalized operand",
"division by zero",
"numeric overflow",
"numeric underflow",
"precision loss",
};
static void
mathnote(ulong status, ulong pc)
{
char *msg, note[ERRMAX];
int i;
/*
* Some attention should probably be paid here to the
* exception masks and error summary.
*/
msg = "unknown exception";
for(i = 1; i <= 5; i++){
if(!((1<<i) & status))
continue;
msg = mathmsg[i];
break;
}
if(status & 0x01){
if(status & 0x40){
if(status & 0x200)
msg = "stack overflow";
else
msg = "stack underflow";
}else
msg = "invalid operation";
}
snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
msg, pc, status);
postnote(up, 1, note, NDebug);
}
/*
* math coprocessor error
*/
static void
matherror(Ureg*, void*)
{
/*
* a write cycle to port 0xF0 clears the interrupt latch attached
* to the error# line from the 387
*/
if(!(m->cpuiddx & Fpuonchip))
outb(0xF0, 0xFF);
/*
* get floating point state to check out error
*/
fpsave(up->fpsave);
up->fpstate = FPinactive;
mathnote(up->fpsave->fsw, up->fpsave->fpuip);
}
/*
* SIMD error
*/
static void
simderror(Ureg *ureg, void*)
{
fpsave(up->fpsave);
up->fpstate = FPinactive;
mathnote(up->fpsave->mxcsr & 0x3f, ureg->pc);
}
/*
* math coprocessor emulation fault
*/
static void
mathemu(Ureg *ureg, void*)
{
ulong status, control;
if(up->fpstate & FPillegal){
/* someone did floating point in a note handler */
postnote(up, 1, "sys: floating point in note handler", NDebug);
return;
}
switch(up->fpstate){
case FPinit:
fpinit();
if(fpsave == fpssesave)
ldmxcsr(0x1f80); /* no simd exceptions on 386 */
while(up->fpsave == nil)
up->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
up->fpstate = FPactive;
break;
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.
*/
status = up->fpsave->fsw;
control = up->fpsave->fcw;
if((status & ~control) & 0x07F){
mathnote(status, up->fpsave->fpuip);
break;
}
fprestore(up->fpsave);
up->fpstate = FPactive;
break;
case FPactive:
panic("math emu pid %ld %s pc 0x%lux",
up->pid, up->text, ureg->pc);
break;
}
}
/*
* math coprocessor segment overrun
*/
static void
mathover(Ureg*, void*)
{
pexit("math overrun", 0);
}
void
mathinit(void)
{
trapenable(VectorCERR, matherror, 0, "matherror");
if(m->cpuidfamily == 3)
intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
trapenable(VectorCNA, mathemu, 0, "mathemu");
trapenable(VectorCSO, mathover, 0, "mathover");
trapenable(VectorSIMD, simderror, 0, "simderror");
}
/*
* set up floating point for a new process
*/

View file

@ -49,6 +49,7 @@ PORT=\
OBJ=\
l.$O\
cga.$O\
fpu.$O\
i8253.$O\
i8259.$O\
main.$O\

View file

@ -289,9 +289,9 @@ physmask(void)
ulong regs[4];
uvlong mask;
cpuid(Exthighfunc, regs);
cpuid(Exthighfunc, 0, regs);
if(regs[0] >= Extaddrsz) { /* ax */
cpuid(Extaddrsz, regs);
cpuid(Extaddrsz, 0, regs);
mask = (1ULL << (regs[0] & 0xFF)) - 1; /* ax */
} else {
mask = (1ULL << 36) - 1;
@ -305,12 +305,14 @@ getstate(State *s)
vlong v;
int i;
s->mask = physmask();
if(rdmsr(MTRRCap, &s->cap) < 0)
return -1;
if((s->cap & (Capfix|Capvcnt)) == 0)
return -1;
if(rdmsr(MTRRDefaultType, &s->def) < 0)
return -1;
if(rdmsr(MTRRCap, &s->cap) < 0)
return -1;
if(s->cap & Capfix){
for(i = 0; i < nelem(fixreg); i++){
@ -332,6 +334,8 @@ getstate(State *s)
return -1;
}
s->mask = physmask();
if(strcmp(m->cpuidid, "AuthenticAMD") != 0
|| m->cpuidfamily < 15
|| rdmsr(AMDK8SysCfg, &v) < 0
@ -354,7 +358,7 @@ enum {
static void
putstate(State *s)
{
ulong cr0, cr4;
uintptr cr0, cr4;
int i, x;
x = splhi();
@ -674,6 +678,10 @@ mtrr(uvlong base, uvlong size, char *tstr)
if((new.type = str2type(tstr)) < 0)
return "bad cache type";
if(new.type == Writecomb
&& (cpu0state.cap & Capwc) == 0)
return "write combining not supported";
qlock(&mtrrlk);
newstate = cpu0state;
nr = getranges(&newstate, ranges, Nranges, &new);

View file

@ -21,7 +21,6 @@
#define idprint(...) if(prid) print(__VA_ARGS__); else USED(prid)
#define aprint(...) if(datapi) print(__VA_ARGS__); else USED(datapi)
#define ledprint(...) if(dled) print(__VA_ARGS__); else USED(dled)
#define Pciwaddrh(a) 0
#define Tname(c) tname[(c)->type]
#define Ticks MACHP(0)->ticks
#define MS2TK(t) (((ulong)(t)*HZ)/1000)
@ -284,20 +283,23 @@ mkalist(Aportm *m, uint flags, uchar *data, int len)
Actab *t;
Alist *l;
Aprdt *p;
uvlong pa;
t = m->ctab;
if(data && len > 0){
pa = PCIWADDR(data);
p = &t->prdt;
p->dba = PCIWADDR(data);
p->dbahi = Pciwaddrh(data);
p->dba = pa;
p->dbahi = pa>>32;
p->count = 1<<31 | len - 2 | 1;
flags |= 1<<16;
}
pa = PCIWADDR(t);
l = m->list;
l->flags = flags | 0x5;
l->len = 0;
l->ctab = PCIWADDR(t);
l->ctabhi = Pciwaddrh(t);
l->ctab = pa;
l->ctabhi = pa>>32;
return l;
}
@ -600,6 +602,7 @@ ahciwakeup(Aportc *c, uint mode)
static int
ahciconfigdrive(Ahba *h, Aportc *c, int mode)
{
uvlong pa;
Aportm *m;
Aport *p;
int i;
@ -618,10 +621,12 @@ ahciconfigdrive(Ahba *h, Aportc *c, int mode)
return -1;
}
p->list = PCIWADDR(m->list);
p->listhi = Pciwaddrh(m->list);
p->fis = PCIWADDR(m->fis.base);
p->fishi = Pciwaddrh(m->fis.base);
pa = PCIWADDR(m->list);
p->list = pa;
p->listhi = pa>>32;
pa = PCIWADDR(m->fis.base);
p->fis = pa;
p->fishi = pa>>32;
p->cmd |= Afre;
@ -1553,7 +1558,6 @@ iaenable(SDev *s)
}
if(c->ndrive == 0)
panic("iaenable: zero s->ctlr->ndrive");
pcisetbme(c->pci);
snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
/* supposed to squelch leftover interrupts here. */
@ -2228,6 +2232,7 @@ iapnp(void)
c->drive[d->driveno] = d;
iadrive[niadrive + d->driveno] = d;
}
pcisetbme(c->pci);
for(i = 0; i < n; i++){
c->drive[i]->mode = DMautoneg;
configdrive(c->drive[i]);

View file

@ -2,6 +2,8 @@ typedef struct BIOS32si BIOS32si;
typedef struct BIOS32ci BIOS32ci;
typedef struct Conf Conf;
typedef struct Confmem Confmem;
typedef struct FPssestate FPssestate;
typedef struct FPavxstate FPavxstate;
typedef struct FPsave FPsave;
typedef struct PFPU PFPU;
typedef struct ISAConf ISAConf;
@ -49,7 +51,7 @@ struct Label
uintptr pc;
};
struct FPsave
struct FPssestate
{
u16int fcw; /* x87 control word */
u16int fsw; /* x87 status word */
@ -65,6 +67,18 @@ struct FPsave
uchar ign[96]; /* reserved, ignored */
};
struct FPavxstate
{
FPssestate;
uchar header[64]; /* XSAVE header */
uchar ymm[256]; /* upper 128-bit regs (AVX) */
};
struct FPsave
{
FPavxstate;
};
enum
{
/* this is a state */
@ -224,9 +238,10 @@ struct Mach
int havewatchpt8;
int havenx;
uvlong tscticks;
u64int dr7; /* shadow copy of dr7 */
u64int xcr0;
void* vmx;
uintptr stack[1];
@ -270,8 +285,14 @@ struct PCArch
/* cpuid instruction result register bits */
enum {
/* ax */
Xsaveopt = 1<<0,
Xsaves = 1<<3,
/* cx */
Monitor = 1<<3,
Xsave = 1<<26,
Avx = 1<<28,
/* dx */
Fpuonchip = 1<<0,

View file

@ -15,7 +15,8 @@ void clockintr(Ureg*, void*);
int (*cmpswap)(long*, long, long);
int cmpswap486(long*, long, long);
void (*coherence)(void);
void cpuid(int, ulong regs[]);
void cpuid(int, int, ulong regs[]);
void fpuinit(void);
int cpuidentify(void);
void cpuidprint(void);
void (*cycles)(uvlong*);
@ -38,16 +39,17 @@ int ecwrite(uchar addr, uchar val);
void fpinit(void);
void (*fprestore)(FPsave*);
void (*fpsave)(FPsave*);
void fpsserestore(FPsave*);
void fpssesave(FPsave*);
void fpx87restore(FPsave*);
void fpx87save(FPsave*);
void fpuprocsetup(Proc*);
void fpuprocfork(Proc*);
void fpuprocsave(Proc*);
void fpuprocrestore(Proc*);
int fpusave(void);
void fpurestore(int);
u64int getcr0(void);
u64int getcr2(void);
u64int getcr3(void);
u64int getcr4(void);
u64int getxcr0(void);
u64int getdr6(void);
char* getconf(char*);
void guesscpuhz(int);
@ -138,6 +140,7 @@ void putcr0(u64int);
void putcr2(u64int);
void putcr3(u64int);
void putcr4(u64int);
void putxcr0(u64int);
void putdr(u64int*);
void putdr01236(u64int*);
void putdr6(u64int);

374
sys/src/9/pc64/fpu.c Normal file
View file

@ -0,0 +1,374 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "ureg.h"
#include "io.h"
enum {
CR4Osfxsr = 1 << 9,
CR4Oxmmex = 1 << 10,
CR4Oxsave = 1 << 18,
};
/*
* SIMD Floating Point.
* Assembler support to get at the individual instructions
* is in l.s.
*/
extern void _clts(void);
extern void _fldcw(u16int);
extern void _fnclex(void);
extern void _fninit(void);
extern void _fxrstor(void*);
extern void _fxsave(void*);
extern void _xrstor(void*);
extern void _xsave(void*);
extern void _xsaveopt(void*);
extern void _fwait(void);
extern void _ldmxcsr(u32int);
extern void _stts(void);
static void
fpssesave(FPsave *s)
{
_fxsave(s);
_stts();
}
static void
fpsserestore(FPsave *s)
{
_clts();
_fxrstor(s);
}
static void
fpxsave(FPsave *s)
{
_xsave(s);
_stts();
}
static void
fpxrestore(FPsave *s)
{
_clts();
_xrstor(s);
}
static void
fpxsaves(FPsave *s)
{
_xsaveopt(s);
_stts();
}
static void
fpxrestores(FPsave *s)
{
_clts();
_xrstor(s);
}
static void
fpxsaveopt(FPsave *s)
{
_xsaveopt(s);
_stts();
}
static char* mathmsg[] =
{
nil, /* handled below */
"denormalized operand",
"division by zero",
"numeric overflow",
"numeric underflow",
"precision loss",
};
static void
mathnote(ulong status, uintptr pc)
{
char *msg, note[ERRMAX];
int i;
/*
* Some attention should probably be paid here to the
* exception masks and error summary.
*/
msg = "unknown exception";
for(i = 1; i <= 5; i++){
if(!((1<<i) & status))
continue;
msg = mathmsg[i];
break;
}
if(status & 0x01){
if(status & 0x40){
if(status & 0x200)
msg = "stack overflow";
else
msg = "stack underflow";
}else
msg = "invalid operation";
}
snprint(note, sizeof note, "sys: fp: %s fppc=%#p status=0x%lux",
msg, pc, status);
postnote(up, 1, note, NDebug);
}
/*
* math coprocessor error
*/
static void
matherror(Ureg *, void*)
{
/*
* Save FPU state to check out the error.
*/
fpsave(up->fpsave);
up->fpstate = FPinactive | (up->fpstate & (FPnouser|FPkernel|FPindexm));
mathnote(up->fpsave->fsw, up->fpsave->rip);
}
/*
* SIMD error
*/
static void
simderror(Ureg *ureg, void*)
{
fpsave(up->fpsave);
up->fpstate = FPinactive | (up->fpstate & (FPnouser|FPkernel|FPindexm));
mathnote(up->fpsave->mxcsr & 0x3f, ureg->pc);
}
void
fpinit(void)
{
/*
* A process tries to use the FPU for the
* first time and generates a 'device not available'
* exception.
* Turn the FPU on and initialise it for use.
* Set the precision and mask the exceptions
* we don't care about from the generic Mach value.
*/
_clts();
_fninit();
_fwait();
_fldcw(0x0232);
_ldmxcsr(0x1900);
}
/*
* math coprocessor emulation fault
*/
static void
mathemu(Ureg *ureg, void*)
{
ulong status, control;
int index;
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 & ~(FPnouser|FPkernel|FPindexm)){
case FPactive | FPpush:
_clts();
fpsave(up->fpsave);
case FPinactive | FPpush:
up->fpstate += FPindex1;
case FPinit | FPpush:
case FPinit:
fpinit();
index = up->fpstate >> FPindexs;
if(index < 0 || index > (FPindexm>>FPindexs))
panic("fpslot index overflow: %d", index);
if(userureg(ureg)){
if(index != 0)
panic("fpslot index %d != 0 for user", index);
} else {
if(index == 0)
up->fpstate |= FPnouser;
up->fpstate |= FPkernel;
}
while(up->fpslot[index] == nil)
up->fpslot[index] = mallocalign(sizeof(FPsave), FPalign, 0, 0);
up->fpsave = up->fpslot[index];
up->fpstate = FPactive | (up->fpstate & (FPnouser|FPkernel|FPindexm));
break;
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.
*/
status = up->fpsave->fsw;
control = up->fpsave->fcw;
if((status & ~control) & 0x07F){
mathnote(status, up->fpsave->rip);
break;
}
fprestore(up->fpsave);
up->fpstate = FPactive | (up->fpstate & (FPnouser|FPkernel|FPindexm));
break;
case FPactive:
panic("math emu pid %ld %s pc %#p",
up->pid, up->text, ureg->pc);
break;
}
}
/*
* math coprocessor segment overrun
*/
static void
mathover(Ureg*, void*)
{
pexit("math overrun", 0);
}
void
mathinit(void)
{
trapenable(VectorCERR, matherror, 0, "matherror");
if(m->cpuidfamily == 3)
intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
trapenable(VectorCNA, mathemu, 0, "mathemu");
trapenable(VectorCSO, mathover, 0, "mathover");
trapenable(VectorSIMD, simderror, 0, "simderror");
}
/*
* fpuinit(), called from cpuidentify() for each cpu.
*/
void
fpuinit(void)
{
u64int cr4;
ulong regs[4];
cr4 = getcr4() | CR4Osfxsr|CR4Oxmmex;
if((m->cpuidcx & (Xsave|Avx)) == (Xsave|Avx) && getconf("*noavx") == nil){
cr4 |= CR4Oxsave;
putcr4(cr4);
m->xcr0 = 7; /* x87, sse, avx */
putxcr0(m->xcr0);
cpuid(0xd, 1, regs);
if(regs[0] & Xsaves){
fpsave = fpxsaves;
fprestore = fpxrestores;
} else {
if(regs[0] & Xsaveopt)
fpsave = fpxsaveopt;
else
fpsave = fpxsave;
fprestore = fpxrestore;
}
} else {
putcr4(cr4);
fpsave = fpssesave;
fprestore = fpsserestore;
}
}
void
fpuprocsetup(Proc *p)
{
p->fpstate = FPinit;
_stts();
}
void
fpuprocfork(Proc *p)
{
int s;
/* save floating point state */
s = splhi();
switch(up->fpstate & ~FPillegal){
case FPactive | FPpush:
_clts();
case FPactive:
fpsave(up->fpsave);
up->fpstate = FPinactive | (up->fpstate & FPpush);
case FPactive | FPkernel:
case FPinactive | FPkernel:
case FPinactive | FPpush:
case FPinactive:
while(p->fpslot[0] == nil)
p->fpslot[0] = mallocalign(sizeof(FPsave), FPalign, 0, 0);
memmove(p->fpsave = p->fpslot[0], up->fpslot[0], sizeof(FPsave));
p->fpstate = FPinactive;
}
splx(s);
}
void
fpuprocsave(Proc *p)
{
switch(p->fpstate & ~(FPnouser|FPkernel|FPindexm)){
case FPactive | FPpush:
_clts();
case FPactive:
if(p->state == Moribund){
_fnclex();
_stts();
break;
}
/*
* 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 | (p->fpstate & ~FPactive);
break;
}
}
void
fpuprocrestore(Proc*)
{
}
/*
* Fpusave and fpurestore lazily save and restore FPU state across
* system calls and the pagefault handler so that we can take
* advantage of SSE instructions such as AES-NI in the kernel.
*/
int
fpusave(void)
{
int ostate = up->fpstate;
if((ostate & ~(FPnouser|FPkernel|FPindexm)) == FPactive)
_stts();
up->fpstate = FPpush | (ostate & ~FPillegal);
return ostate;
}
void
fpurestore(int ostate)
{
int astate = up->fpstate;
if(astate == (FPpush | (ostate & ~FPillegal))){
if((ostate & ~(FPnouser|FPkernel|FPindexm)) == FPactive)
_clts();
} else {
if(astate == FPinit) /* don't restore on procexec()/procsetup() */
return;
if((astate & ~(FPnouser|FPkernel|FPindexm)) == FPactive)
_stts();
up->fpsave = up->fpslot[ostate>>FPindexs];
if(ostate & FPactive)
ostate = FPinactive | (ostate & ~FPactive);
}
up->fpstate = ostate;
}

View file

@ -249,9 +249,10 @@ _idle:
*/
TEXT cpuid(SB), $-4
MOVL RARG, AX /* function in AX */
MOVL cx+8(FP), CX /* sub-level in CX */
CPUID
MOVQ info+8(FP), BP
MOVQ info+16(FP), BP
MOVL AX, 0(BP)
MOVL BX, 4(BP)
MOVL CX, 8(BP)
@ -399,6 +400,21 @@ TEXT putcr4(SB), 1, $-4
MOVQ RARG, CR4
RET
TEXT getxcr0(SB), 1, $-4 /* XCR0 - extended control */
XORQ CX, CX
WORD $0x010f; BYTE $0xd0 // XGETBV
SHLQ $32, DX
ORQ DX, AX
RET
TEXT putxcr0(SB), 1, $-4
XORQ CX, CX
MOVL RARG, DX
SHRQ $32, DX
MOVL RARG, AX
WORD $0x010f; BYTE $0xd1 // XSETBV
RET
TEXT mb386(SB), 1, $-4 /* hack */
TEXT mb586(SB), 1, $-4
XORL AX, AX
@ -626,6 +642,36 @@ TEXT _fxsave(SB), 1, $-4
FXSAVE64 (RARG)
RET
TEXT _xrstor(SB), 1, $-4
MOVL $7, AX
XORL DX, DX
BYTE $0x48; BYTE $0x0f; BYTE $0xae; BYTE $0x6d; BYTE $0x00 // XRSTOR (RARG)
RET
TEXT _xrstors(SB), 1, $-4
MOVL $7, AX
XORL DX, DX
BYTE $0x48; BYTE $0x0f; BYTE $0xc7; BYTE $0x5d; BYTE $0x00 // XRSTORS (RARG)
RET
TEXT _xsave(SB), 1, $-4
MOVL $7, AX
XORL DX, DX
BYTE $0x48; BYTE $0x0f; BYTE $0xae; BYTE $0x65; BYTE $0x00 // XSAVE (RARG)
RET
TEXT _xsaveopt(SB), 1, $-4
MOVL $7, AX
XORL DX, DX
BYTE $0x48; BYTE $0x0f; BYTE $0xae; BYTE $0x75; BYTE $0x00 // XSAVEOPT (RARG)
RET
TEXT _xsaves(SB), 1, $-4
MOVL $7, AX
XORL DX, DX
BYTE $0x48; BYTE $0x0f; BYTE $0xc7; BYTE $0x6d; BYTE $0x00 // XSAVES (RARG)
RET
TEXT _fwait(SB), 1, $-4
WAIT
RET

View file

@ -293,218 +293,10 @@ reboot(void *entry, void *code, ulong size)
rebootjump((uintptr)entry & (ulong)~0xF0000000UL, PADDR(code), size);
}
/*
* SIMD Floating Point.
* Assembler support to get at the individual instructions
* is in l.s.
*/
extern void _clts(void);
extern void _fldcw(u16int);
extern void _fnclex(void);
extern void _fninit(void);
extern void _fxrstor(void*);
extern void _fxsave(void*);
extern void _fwait(void);
extern void _ldmxcsr(u32int);
extern void _stts(void);
/*
* not used, AMD64 mandated SSE
*/
void
fpx87save(FPsave*)
{
}
void
fpx87restore(FPsave*)
{
}
void
fpssesave(FPsave *s)
{
_fxsave(s);
_stts();
}
void
fpsserestore(FPsave *s)
{
_clts();
_fxrstor(s);
}
static char* mathmsg[] =
{
nil, /* handled below */
"denormalized operand",
"division by zero",
"numeric overflow",
"numeric underflow",
"precision loss",
};
static void
mathnote(ulong status, uintptr pc)
{
char *msg, note[ERRMAX];
int i;
/*
* Some attention should probably be paid here to the
* exception masks and error summary.
*/
msg = "unknown exception";
for(i = 1; i <= 5; i++){
if(!((1<<i) & status))
continue;
msg = mathmsg[i];
break;
}
if(status & 0x01){
if(status & 0x40){
if(status & 0x200)
msg = "stack overflow";
else
msg = "stack underflow";
}else
msg = "invalid operation";
}
snprint(note, sizeof note, "sys: fp: %s fppc=%#p status=0x%lux",
msg, pc, status);
postnote(up, 1, note, NDebug);
}
/*
* math coprocessor error
*/
static void
matherror(Ureg *, void*)
{
/*
* Save FPU state to check out the error.
*/
fpsave(up->fpsave);
up->fpstate = FPinactive | (up->fpstate & (FPnouser|FPkernel|FPindexm));
mathnote(up->fpsave->fsw, up->fpsave->rip);
}
/*
* SIMD error
*/
static void
simderror(Ureg *ureg, void*)
{
fpsave(up->fpsave);
up->fpstate = FPinactive | (up->fpstate & (FPnouser|FPkernel|FPindexm));
mathnote(up->fpsave->mxcsr & 0x3f, ureg->pc);
}
void
fpinit(void)
{
/*
* A process tries to use the FPU for the
* first time and generates a 'device not available'
* exception.
* Turn the FPU on and initialise it for use.
* Set the precision and mask the exceptions
* we don't care about from the generic Mach value.
*/
_clts();
_fninit();
_fwait();
_fldcw(0x0232);
_ldmxcsr(0x1900);
}
/*
* math coprocessor emulation fault
*/
static void
mathemu(Ureg *ureg, void*)
{
ulong status, control;
int index;
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 & ~(FPnouser|FPkernel|FPindexm)){
case FPactive | FPpush:
_clts();
fpsave(up->fpsave);
case FPinactive | FPpush:
up->fpstate += FPindex1;
case FPinit | FPpush:
case FPinit:
fpinit();
index = up->fpstate >> FPindexs;
if(index < 0 || index > (FPindexm>>FPindexs))
panic("fpslot index overflow: %d", index);
if(userureg(ureg)){
if(index != 0)
panic("fpslot index %d != 0 for user", index);
} else {
if(index == 0)
up->fpstate |= FPnouser;
up->fpstate |= FPkernel;
}
while(up->fpslot[index] == nil)
up->fpslot[index] = mallocalign(sizeof(FPsave), FPalign, 0, 0);
up->fpsave = up->fpslot[index];
up->fpstate = FPactive | (up->fpstate & (FPnouser|FPkernel|FPindexm));
break;
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.
*/
status = up->fpsave->fsw;
control = up->fpsave->fcw;
if((status & ~control) & 0x07F){
mathnote(status, up->fpsave->rip);
break;
}
fprestore(up->fpsave);
up->fpstate = FPactive | (up->fpstate & (FPnouser|FPkernel|FPindexm));
break;
case FPactive:
panic("math emu pid %ld %s pc %#p",
up->pid, up->text, ureg->pc);
break;
}
}
/*
* math coprocessor segment overrun
*/
static void
mathover(Ureg*, void*)
{
pexit("math overrun", 0);
}
void
mathinit(void)
{
trapenable(VectorCERR, matherror, 0, "matherror");
if(m->cpuidfamily == 3)
intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
trapenable(VectorCNA, mathemu, 0, "mathemu");
trapenable(VectorCSO, mathover, 0, "mathover");
trapenable(VectorSIMD, simderror, 0, "simderror");
}
void
procsetup(Proc *p)
{
p->fpstate = FPinit;
_stts();
fpuprocsetup(p);
/* clear debug registers */
memset(p->dr, 0, sizeof(p->dr));
@ -520,29 +312,10 @@ procsetup(Proc *p)
void
procfork(Proc *p)
{
int s;
p->kentry = up->kentry;
p->pcycles = -p->kentry;
/* save floating point state */
s = splhi();
switch(up->fpstate & ~FPillegal){
case FPactive | FPpush:
_clts();
case FPactive:
fpsave(up->fpsave);
up->fpstate = FPinactive | (up->fpstate & FPpush);
case FPactive | FPkernel:
case FPinactive | FPkernel:
case FPinactive | FPpush:
case FPinactive:
while(p->fpslot[0] == nil)
p->fpslot[0] = mallocalign(sizeof(FPsave), FPalign, 0, 0);
memmove(p->fpsave = p->fpslot[0], up->fpslot[0], sizeof(FPsave));
p->fpstate = FPinactive;
}
splx(s);
fpuprocfork(p);
}
void
@ -558,6 +331,8 @@ procrestore(Proc *p)
if(p->vmx != nil)
vmxprocrestore(p);
fpuprocrestore(p);
if(p->kp)
return;
@ -582,27 +357,7 @@ procsave(Proc *p)
if(p->state == Moribund)
p->dr[7] = 0;
switch(p->fpstate & ~(FPnouser|FPkernel|FPindexm)){
case FPactive | FPpush:
_clts();
case FPactive:
if(p->state == Moribund){
_fnclex();
_stts();
break;
}
/*
* 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 | (p->fpstate & ~FPactive);
break;
}
fpuprocsave(p);
/*
* While this processor is in the scheduler, the process could run
@ -617,36 +372,3 @@ procsave(Proc *p)
*/
mmuflushtlb();
}
/*
* Fpusave and fpurestore lazily save and restore FPU state across
* system calls and the pagefault handler so that we can take
* advantage of SSE instructions such as AES-NI in the kernel.
*/
int
fpusave(void)
{
int ostate = up->fpstate;
if((ostate & ~(FPnouser|FPkernel|FPindexm)) == FPactive)
_stts();
up->fpstate = FPpush | (ostate & ~FPillegal);
return ostate;
}
void
fpurestore(int ostate)
{
int astate = up->fpstate;
if(astate == (FPpush | (ostate & ~FPillegal))){
if((ostate & ~(FPnouser|FPkernel|FPindexm)) == FPactive)
_clts();
} else {
if(astate == FPinit) /* don't restore on procexec()/procsetup() */
return;
if((astate & ~(FPnouser|FPkernel|FPindexm)) == FPactive)
_stts();
up->fpsave = up->fpslot[ostate>>FPindexs];
if(ostate & FPactive)
ostate = FPinactive | (ostate & ~FPactive);
}
up->fpstate = ostate;
}

View file

@ -26,7 +26,7 @@
#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1))
#define PGROUND(s) ROUND(s, BY2PG)
#define BLOCKALIGN 8
#define FPalign 16
#define FPalign 64
#define MAXMACH 128 /* max # cpus system can run */

View file

@ -47,6 +47,7 @@ PORT=\
OBJ=\
l.$O\
cga.$O\
fpu.$O\
i8253.$O\
i8259.$O\
main.$O\

View file

@ -97,13 +97,12 @@ sysfauth(va_list list)
nexterror();
}
fd = newfd(ac);
/* always mark it close on exec */
fd = newfd(ac, OCEXEC);
if(fd < 0)
error(Enofd);
poperror(); /* ac */
/* always mark it close on exec */
ac->flag |= CCEXEC;
return (uintptr)fd;
}

View file

@ -1468,9 +1468,6 @@ namec(char *aname, int amode, int omode, ulong perm)
saveregisters();
c = devtab[c->type]->open(c, omode&~OCEXEC);
if(omode & OCEXEC)
c->flag |= CCEXEC;
if(omode & ORCLOSE)
c->flag |= CRCLOSE;
break;
@ -1571,11 +1568,9 @@ namec(char *aname, int amode, int omode, ulong perm)
incref(cnew->path);
cnew = devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);
poperror();
if(omode & OCEXEC)
cnew->flag |= CCEXEC;
if(omode & ORCLOSE)
cnew->flag |= CRCLOSE;
poperror();
putmhead(m);
cclose(c);
c = cnew;

View file

@ -63,6 +63,8 @@ dupopen(Chan *c, int omode)
Chan *f;
int fd, twicefd;
if(omode & ORCLOSE)
error(Eperm);
if(c->qid.type & QTDIR){
if(omode != 0)
error(Eisdir);

View file

@ -304,8 +304,6 @@ setbuttonmap(char* map)
one = two = three = 0;
for(i = 0; i < 3; i++){
if(map[i] == 0)
error(Ebadarg);
if(map[i] == '1'){
if(one)
error(Ebadarg);

View file

@ -396,6 +396,8 @@ shropen(Chan *c, int omode)
case Qcmpt:
if(omode&OTRUNC)
error(Eexist);
if(omode&ORCLOSE)
error(Eperm);
shr = sch->shr;
mpt = sch->mpt;
devpermcheck(mpt->owner, mpt->perm, mode);

View file

@ -135,6 +135,8 @@ srvopen(Chan *c, int omode)
if(omode&OTRUNC)
error(Eexist);
if(omode&ORCLOSE)
error(Eperm);
if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
error(Eperm);
devpermcheck(sp->owner, sp->perm, omode);
@ -338,8 +340,6 @@ srvwrite(Chan *c, void *va, long n, vlong)
cclose(c1);
nexterror();
}
if(c1->flag & (CCEXEC|CRCLOSE))
error("posted fd has remove-on-close or close-on-exec");
if(c1->qid.type & QTAUTH)
error("cannot post auth file in srv");
sp = srvlookup(nil, c->qid.path);

View file

@ -176,7 +176,7 @@ extern void qsort(void*, long, long, int (*)(void*, void*));
#define ORDWR 2 /* read and write */
#define OEXEC 3 /* execute, == read but check execute permission */
#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
#define OCEXEC 32 /* or'ed in, close on exec */
#define OCEXEC 32 /* or'ed in (per file descriptor), close on exec */
#define ORCLOSE 64 /* or'ed in, remove on close */
#define OEXCL 0x1000 /* or'ed in, exclusive create */

View file

@ -140,7 +140,8 @@ dupfgrp(Fgrp *f)
new = smalloc(sizeof(Fgrp));
if(f == nil){
new->fd = smalloc(DELTAFD*sizeof(Chan*));
new->flag = smalloc(DELTAFD*sizeof(new->flag[0]));
new->fd = smalloc(DELTAFD*sizeof(new->fd[0]));
new->nfd = DELTAFD;
new->ref = 1;
return new;
@ -152,12 +153,19 @@ dupfgrp(Fgrp *f)
i = new->nfd%DELTAFD;
if(i != 0)
new->nfd += DELTAFD - i;
new->fd = malloc(new->nfd*sizeof(Chan*));
new->fd = malloc(new->nfd*sizeof(new->fd[0]));
if(new->fd == nil){
unlock(f);
free(new);
error("no memory for fgrp");
}
new->flag = malloc(new->nfd*sizeof(new->flag[0]));
if(new->flag == nil){
unlock(f);
free(new->fd);
free(new);
error("no memory for fgrp");
}
new->ref = 1;
new->maxfd = f->maxfd;
@ -165,6 +173,7 @@ dupfgrp(Fgrp *f)
if((c = f->fd[i]) != nil){
incref(c);
new->fd[i] = c;
new->flag[i] = f->flag[i];
}
}
unlock(f);
@ -194,6 +203,7 @@ closefgrp(Fgrp *f)
up->closingfgrp = nil;
free(f->fd);
free(f->flag);
free(f);
}

View file

@ -125,7 +125,7 @@ enum
COPEN = 0x0001, /* for i/o */
CMSG = 0x0002, /* the message channel for a mount */
/*rsc CCREATE = 0x0004, /* permits creation if c->mnt */
CCEXEC = 0x0008, /* close on exec */
CCEXEC = 0x0008, /* close on exec (per file descriptor) */
CFREE = 0x0010, /* not in use */
CRCLOSE = 0x0020, /* remove on close */
CCACHE = 0x0080, /* client cache */
@ -509,6 +509,7 @@ struct Fgrp
Ref;
Lock;
Chan **fd;
uchar *flag; /* per file-descriptor flags (CCEXEC) */
int nfd; /* number allocated */
int maxfd; /* highest fd in use */
int exceed; /* debugging */

View file

@ -201,7 +201,7 @@ Chan* namec(char*, int, int, ulong);
void nameerror(char*, char*);
int needpages(void*);
Chan* newchan(void);
int newfd(Chan*);
int newfd(Chan*, int);
Mhead* newmhead(Chan*);
Mount* newmount(Chan*, int, char*);
Page* newpage(int, Segment **, uintptr);

View file

@ -25,33 +25,45 @@ int
growfd(Fgrp *f, int fd) /* fd is always >= 0 */
{
Chan **newfd, **oldfd;
uchar *newflag, *oldflag;
int nfd;
if(fd < f->nfd)
nfd = f->nfd;
if(fd < nfd)
return 0;
if(fd >= f->nfd+DELTAFD)
if(fd >= nfd+DELTAFD)
return -1; /* out of range */
/*
* Unbounded allocation is unwise; besides, there are only 16 bits
* of fid in 9P
*/
if(f->nfd >= 5000){
if(nfd >= 5000){
Exhausted:
print("no free file descriptors\n");
return -1;
}
newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));
oldfd = f->fd;
oldflag = f->flag;
newfd = malloc((nfd+DELTAFD)*sizeof(newfd[0]));
if(newfd == nil)
goto Exhausted;
oldfd = f->fd;
memmove(newfd, oldfd, f->nfd*sizeof(Chan*));
memmove(newfd, oldfd, nfd*sizeof(newfd[0]));
newflag = malloc((nfd+DELTAFD)*sizeof(newflag[0]));
if(newflag == nil){
free(newfd);
goto Exhausted;
}
memmove(newflag, oldflag, nfd*sizeof(newflag[0]));
f->fd = newfd;
free(oldfd);
f->nfd += DELTAFD;
f->flag = newflag;
f->nfd = nfd+DELTAFD;
if(fd > f->maxfd){
if(fd/100 > f->maxfd/100)
f->exceed = (fd/100)*100;
f->maxfd = fd;
}
free(oldfd);
free(oldflag);
return 1;
}
@ -72,9 +84,9 @@ findfreefd(Fgrp *f, int start)
}
int
newfd(Chan *c)
newfd(Chan *c, int mode)
{
int fd;
int fd, flag;
Fgrp *f;
f = up->fgrp;
@ -87,6 +99,13 @@ newfd(Chan *c)
if(fd > f->maxfd)
f->maxfd = fd;
f->fd[fd] = c;
/* per file-descriptor flags */
flag = 0;
if(mode & OCEXEC)
flag |= CCEXEC;
f->flag[fd] = flag;
unlockfgrp(f);
return fd;
}
@ -112,6 +131,8 @@ newfd2(int fd[2], Chan *c[2])
f->maxfd = fd[1];
f->fd[fd[0]] = c[0];
f->fd[fd[1]] = c[1];
f->flag[fd[0]] = 0;
f->flag[fd[1]] = 0;
unlockfgrp(f);
return 0;
}
@ -247,6 +268,7 @@ sysdup(va_list list)
oc = f->fd[fd];
f->fd[fd] = c;
f->flag[fd] = 0;
unlockfgrp(f);
if(oc != nil)
cclose(oc);
@ -255,7 +277,7 @@ sysdup(va_list list)
cclose(c);
nexterror();
}
fd = newfd(c);
fd = newfd(c, 0);
if(fd < 0)
error(Enofd);
poperror();
@ -280,7 +302,7 @@ sysopen(va_list list)
cclose(c);
nexterror();
}
fd = newfd(c);
fd = newfd(c, mode);
if(fd < 0)
error(Enofd);
poperror();
@ -295,7 +317,7 @@ fdclose(int fd, int flag)
lock(f);
c = fd <= f->maxfd ? f->fd[fd] : nil;
if(c == nil || (flag != 0 && (c->flag&flag) == 0)){
if(c == nil || (flag != 0 && ((f->flag[fd]|c->flag)&flag) == 0)){
unlock(f);
return;
}
@ -1166,7 +1188,7 @@ syscreate(va_list list)
cclose(c);
nexterror();
}
fd = newfd(c);
fd = newfd(c, mode);
if(fd < 0)
error(Enofd);
poperror();

View file

@ -83,18 +83,3 @@ void outl(int, ulong) {}
int mtrrprint(char*, long) { return 0; }
char* mtrr(uvlong, uvlong, char *) { return nil; }
void mtrrsync(void) {}
/*
* XXX until fpsave is debugged
*/
void
fpssesave(FPsave* f)
{
fpx87save(f);
}
void
fpsserestore(FPsave* f)
{
fpx87restore(f);
}

View file

@ -9,25 +9,18 @@ void clockintr(Ureg*, void*);
int (*cmpswap)(long*, long, long);
int cmpswap486(long*, long, long);
void (*coherence)(void);
void cpuid(int, ulong regs[]);
void cpuid(int, int, ulong regs[]);
void fpuinit(void);
int cpuidentify(void);
void cpuidprint(void);
void (*cycles)(uvlong*);
void delay(int);
#define evenaddr(x) /* x86 doesn't care */
void fpclear(void);
void fpenv(FPsave*);
void fpinit(void);
void fpoff(void);
void (*fprestore)(FPsave*);
void (*fpsave)(FPsave*);
void fpsserestore(FPsave*);
void fpsserestore0(FPsave*);
void fpssesave(FPsave*);
void fpssesave0(FPsave*);
ulong fpstatus(void);
void fpx87restore(FPsave*);
void fpx87save(FPsave*);
ulong getcr4(void);
char* getconf(char*);
void guesscpuhz(int);

View file

@ -163,34 +163,42 @@ TEXT fpinit(SB), $0 /* enable and init */
WAIT
RET
TEXT fpx87save(SB), $0 /* save state and disable */
TEXT fpx87save0(SB), $0 /* save state and disable */
MOVL p+0(FP), AX
FSAVE 0(AX) /* no WAIT */
FPOFF(l2)
RET
TEXT fpx87restore(SB), $0 /* enable and restore state */
TEXT fpx87restore0(SB), $0 /* enable and restore state */
FPON
MOVL p+0(FP), AX
FRSTOR 0(AX)
WAIT
RET
TEXT fpstatus(SB), $0 /* get floating point status */
FSTSW AX
RET
TEXT fpenv(SB), $0 /* save state without waiting */
MOVL p+0(FP), AX
FSTENV 0(AX)
RET
TEXT fpclear(SB), $0 /* clear pending exceptions */
FPON
FCLEX /* no WAIT */
FPOFF(l3)
RET
TEXT fpssesave(SB), $0 /* save state and disable */
MOVL p+0(FP), AX
FXSAVE 0(AX) /* no WAIT */
FPOFF(l4)
RET
TEXT fpsserestore(SB), $0 /* enable and restore state */
FPON
MOVL p+0(FP), AX
FXRSTOR 0(AX)
WAIT
RET
TEXT ldmxcsr(SB), $0 /* Load MXCSR */
LDMXCSR mxcsr+0(FP)
RET
/*
* Test-And-Set
*/

View file

@ -322,133 +322,6 @@ confinit(void)
}
}
static char* mathmsg[] =
{
nil, /* handled below */
"denormalized operand",
"division by zero",
"numeric overflow",
"numeric underflow",
"precision loss",
};
static void
mathnote(void)
{
int i;
ulong status;
char *msg, note[ERRMAX];
status = up->fpsave->status;
/*
* Some attention should probably be paid here to the
* exception masks and error summary.
*/
msg = "unknown exception";
for(i = 1; i <= 5; i++){
if(!((1<<i) & status))
continue;
msg = mathmsg[i];
break;
}
if(status & 0x01){
if(status & 0x40){
if(status & 0x200)
msg = "stack overflow";
else
msg = "stack underflow";
}else
msg = "invalid operation";
}
snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
msg, up->fpsave->pc, status);
postnote(up, 1, note, NDebug);
}
/*
* math coprocessor error
*/
static void
matherror(Ureg *ur, void*)
{
/*
* a write cycle to port 0xF0 clears the interrupt latch attached
* to the error# line from the 387
*/
if(!(m->cpuiddx & 0x01))
outb(0xF0, 0xFF);
/*
* save floating point state to check out error
*/
fpenv(up->fpsave);
mathnote();
if(ur->pc & KZERO)
panic("fp: status %ux fppc=0x%lux pc=0x%lux",
up->fpsave->status, up->fpsave->pc, ur->pc);
}
/*
* math coprocessor emulation fault
*/
static void
mathemu(Ureg *ureg, void*)
{
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:
fpinit();
while(up->fpsave == nil)
up->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
up->fpstate = FPactive;
break;
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.
*/
if((up->fpsave->status & ~up->fpsave->control) & 0x07F){
mathnote();
break;
}
fprestore(up->fpsave);
up->fpstate = FPactive;
break;
case FPactive:
panic("math emu pid %ld %s pc 0x%lux",
up->pid, up->text, ureg->pc);
break;
}
}
/*
* 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");
}
/*
* set up floating point for a new process
*/

View file

@ -68,6 +68,7 @@ OBJ=\
plan9l.$O\
xen.$O\
main.$O\
fpu.$O\
mmu.$O\
random.$O\
rdb.$O\

View file

@ -179,7 +179,7 @@ Rune kbtabesc1[Nscan] =
[0x40] 0, 0, 0, 0, 0, 0, Kbreak, Khome,
[0x48] Kup, Kpgup, 0, Kleft, 0, Kright, 0, Kend,
[0x50] Kdown, Kpgdown,Kins, Kdel, 0, 0, 0, 0,
[0x58] 0, 0, 0, 0, 0, 0, 0, 0,
[0x58] 0, 0, 0, Kmod4, 0, 0, 0, 0,
[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
[0x70] 0, 0, 0, 0, 0, 0, 0, 0,

View file

@ -21,10 +21,10 @@ initcolor(void)
text = display->black;
light = allocimagemix(display, DPalegreen, DWhite);
dark = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen);
if(light == nil || dark == nil) sysfatal("initcolor: %r");
}
Rectangle rbar;
Point ptext;
vlong n, d;
int last;
int lastp = -1;
@ -75,7 +75,7 @@ drawbar(void)
if(lastp != p){
sprint(buf, "%3d%%", p);
stringbg(screen, addpt(screen->r.min, Pt(Dx(rbar)-30, 4)), text, ZP, display->defaultfont, buf, light, ZP);
stringbg(screen, Pt(screen->r.max.x-4-stringwidth(display->defaultfont, buf), screen->r.min.y+4), text, ZP, display->defaultfont, buf, light, ZP);
lastp = p;
}
@ -94,24 +94,13 @@ drawbar(void)
void
eresized(int new)
{
Point p, q;
Rectangle r;
if(new && getwindow(display, Refnone) < 0)
fprint(2,"can't reattach to window");
r = screen->r;
draw(screen, r, light, nil, ZP);
p = string(screen, addpt(r.min, Pt(4,4)), text, ZP,
display->defaultfont, title);
p.x = r.min.x+4;
p.y += display->defaultfont->height+4;
q = subpt(r.max, Pt(4,4));
rbar = Rpt(p, q);
ptext = Pt(r.max.x-4-stringwidth(display->defaultfont, "100%"), r.min.x+4);
draw(screen, screen->r, light, nil, ZP);
if(title) string(screen, addpt(screen->r.min, Pt(4,4)), text, ZP, font, title);
rbar = insetrect(screen->r, 4);
rbar.min.y += font->height + 4;
border(screen, rbar, -2, dark, ZP);
last = 0;
lastp = -1;
@ -163,7 +152,7 @@ bar(Biobuf *b)
void
usage(void)
{
fprint(2, "usage: aux/statusbar [-kt] [-w minx,miny,maxx,maxy] 'title'\n");
fprint(2, "usage: %s [-kt] [-w minx,miny,maxx,maxy] [title]\n", argv0);
exits("usage");
}
@ -190,11 +179,14 @@ main(int argc, char **argv)
usage();
}ARGEND;
if(argc != 1)
switch(argc){
default:
usage();
title = argv[0];
case 1:
title = argv[0];
case 0:
break;
}
lfd = dup(0, -1);
while(q = strchr(p, ','))
@ -204,7 +196,7 @@ main(int argc, char **argv)
textmode = 1;
rbar = Rect(0, 0, 60, 1);
}else{
if(initdraw(0, 0, title) < 0)
if(initdraw(0, 0, title ? title : argv0) < 0)
exits("initdraw");
initcolor();
einit(Emouse|Ekeyboard);

View file

@ -22,6 +22,7 @@ initcolor(void)
{
text = display->black;
light = allocimagemix(display, DPalegreen, DWhite);
if(light == nil) sysfatal("initcolor: %r");
}
void
@ -136,7 +137,6 @@ main(int argc, char **argv)
usage();
case 1:
title = argv[0];
break;
case 0:
break;
}
@ -153,7 +153,7 @@ main(int argc, char **argv)
if((bout = Bfdopen(1, OWRITE)) == nil)
sysfatal("Bfdopen: %r");
}else{
if(initdraw(0, 0, title) < 0)
if(initdraw(0, 0, title ? title : argv0) < 0)
sysfatal("initdraw: %r");
initcolor();
einit(Emouse|Ekeyboard);

View file

@ -37,7 +37,7 @@ char *patternfile;
char *origargs;
char *srvname = "ncpu";
char *exportfs = "/bin/exportfs";
char *exportfs = "/bin/oexportfs";
char *ealgs = "rc4_256 sha1";
/* message size for exportfs; may be larger so we can do big graphics in CPU window */

View file

@ -1,135 +1,44 @@
/*
* exportfs - Export a plan 9 name space across a network
*/
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <libsec.h>
#define Extern
#include "exportfs.h"
#define QIDPATH ((1LL<<48)-1)
vlong newqid = 0;
enum {
Encnone,
Encssl,
Enctls,
};
void (*fcalls[])(Fsrpc*) =
{
[Tversion] Xversion,
[Tauth] Xauth,
[Tflush] Xflush,
[Tattach] Xattach,
[Twalk] Xwalk,
[Topen] slave,
[Tcreate] Xcreate,
[Tclunk] Xclunk,
[Tread] slave,
[Twrite] slave,
[Tremove] Xremove,
[Tstat] Xstat,
[Twstat] Xwstat,
};
/* accounting and debugging counters */
int filecnt;
int freecnt;
int qidcnt;
int qfreecnt;
int ncollision;
int srvfd = -1;
int nonone = 1;
char *filterp;
char *ealgs = "rc4_256 sha1";
char *aanfilter = "/bin/aan";
int encproto = Encnone;
int readonly;
static void mksecret(char *, uchar *);
static char *anstring = "tcp!*!0";
char *netdir = "", *local = "", *remote = "";
void filter(int, char *, char *);
void
usage(void)
{
fprint(2, "usage: %s [-adnsR] [-f dbgfile] [-m msize] [-r root] "
"[-S srvfile] [-e 'crypt hash'] [-P exclusion-file] "
"[-A announce-string] [-B address]\n", argv0);
fprint(2, "usage: %s [-dsR] [-f dbgfile] [-m msize] [-r root] "
"[-S srvfile] [-P exclusion-file]\n", argv0);
fatal("usage");
}
static void
noteconn(int fd)
{
NetConnInfo *nci;
nci = getnetconninfo(nil, fd);
if(nci == nil)
return;
netdir = estrdup(nci->dir);
local = estrdup(nci->lsys);
remote = estrdup(nci->rsys);
freenetconninfo(nci);
}
void
main(int argc, char **argv)
{
char buf[ERRMAX], ebuf[ERRMAX], initial[4], *ini, *srvfdfile;
char *dbfile, *srv, *na, *nsfile, *keyspec;
int doauth, n, fd;
AuthInfo *ai;
Fsrpc *r;
char *dbfile, *srv, *srvfdfile;
int n;
dbfile = "/tmp/exportdb";
srv = nil;
srvfd = -1;
srvfdfile = nil;
na = nil;
nsfile = nil;
keyspec = "";
doauth = 0;
ai = nil;
ARGBEGIN{
case 'a':
doauth = 1;
break;
case 'd':
dbg++;
break;
case 'e':
ealgs = EARGF(usage());
if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
ealgs = nil;
break;
case 'f':
dbfile = EARGF(usage());
break;
case 'k':
keyspec = EARGF(usage());
break;
case 'm':
messagesize = strtoul(EARGF(usage()), nil, 0);
break;
case 'n':
nonone = 0;
break;
case 'r':
srv = EARGF(usage());
break;
@ -138,22 +47,10 @@ main(int argc, char **argv)
srv = "/";
break;
case 'A':
anstring = EARGF(usage());
break;
case 'B':
na = EARGF(usage());
break;
case 'F':
/* accepted but ignored, for backwards compatibility */
break;
case 'N':
nsfile = EARGF(usage());
break;
case 'P':
patternfile = EARGF(usage());
break;
@ -173,52 +70,15 @@ main(int argc, char **argv)
}ARGEND
USED(argc, argv);
if(na == nil && doauth){
/*
* We use p9any so we don't have to visit this code again, with the
* cost that this code is incompatible with the old world, which
* requires p9sk2. (The two differ in who talks first, so compatibility
* is awkward.)
*/
ai = auth_proxy(0, auth_getkey, "proto=p9any role=server %s", keyspec);
if(ai == nil)
fatal("auth_proxy: %r");
if(nonone && strcmp(ai->cuid, "none") == 0)
fatal("exportfs by none disallowed");
if(auth_chuid(ai, nsfile) < 0)
fatal("auth_chuid: %r");
else { /* chown network connection */
Dir nd;
nulldir(&nd);
nd.mode = 0660;
nd.uid = ai->cuid;
dirfwstat(0, &nd);
}
putenv("service", "exportfs");
}
if(srvfdfile != nil){
if(srv != nil){
fprint(2, "exportfs: -S cannot be used with -r or -s\n");
usage();
}
if((srvfd = open(srvfdfile, ORDWR)) < 0)
fatal("open %s: %r", srvfdfile);
}
if(na != nil){
if(srv == nil)
fatal("-B requires -s");
local = "me";
remote = na;
if((fd = dial(netmkaddr(na, 0, "importfs"), 0, 0, 0)) < 0)
fatal("can't dial %s: %r", na);
ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec);
if(ai == nil)
fatal("%r: %s", na);
dup(fd, 0);
dup(fd, 1);
close(fd);
}
} else if(srv == nil)
usage();
exclusions();
@ -228,11 +88,6 @@ main(int argc, char **argv)
close(n);
}
if(srvfd >= 0 && srv != nil){
fprint(2, "exportfs: -S cannot be used with -r or -s\n");
usage();
}
DEBUG(DFD, "exportfs: started\n");
rfork(RFNOTEG|RFREND);
@ -246,695 +101,18 @@ main(int argc, char **argv)
fmtinstall('F', fcallfmt);
/*
* Get tree to serve from network connection,
* check we can get there and ack the connection
*/
if(srvfd != -1) {
/* do nothing */
}
else if(srv != nil) {
if(srvfd == -1) {
if(chdir(srv) < 0) {
char ebuf[ERRMAX];
ebuf[0] = '\0';
errstr(ebuf, sizeof ebuf);
r = getsbuf();
r->work.tag = NOTAG;
r->work.fid = NOFID;
r->work.type = Rerror;
r->work.ename = ebuf;
n = convS2M(&r->work, r->buf, messagesize);
write(0, r->buf, n);
DEBUG(DFD, "chdir(\"%s\"): %s\n", srv, ebuf);
exits(ebuf);
mounterror(ebuf);
}
DEBUG(DFD, "invoked as server for %s", srv);
strncpy(buf, srv, sizeof buf);
}
else {
noteconn(0);
buf[0] = 0;
n = read(0, buf, sizeof(buf)-1);
if(n < 0) {
errstr(buf, sizeof buf);
fprint(0, "read(0): %s\n", buf);
DEBUG(DFD, "read(0): %s\n", buf);
exits(buf);
}
buf[n] = 0;
if(chdir(buf) < 0) {
errstr(ebuf, sizeof ebuf);
fprint(0, "chdir(%d:\"%s\"): %s\n", n, buf, ebuf);
DEBUG(DFD, "chdir(%d:\"%s\"): %s\n", n, buf, ebuf);
exits(ebuf);
}
}
DEBUG(DFD, "\niniting root\n");
initroot();
DEBUG(DFD, "exportfs: %s\n", buf);
if(srv == nil && srvfd == -1 && write(0, "OK", 2) != 2)
fatal("open ack write");
ini = initial;
n = readn(0, initial, sizeof(initial));
if(n == 0)
fatal(nil); /* port scan or spurious open/close on exported /srv file (unmount) */
if(n < sizeof(initial))
fatal("can't read initial string: %r");
if(memcmp(ini, "impo", 4) == 0) {
char buf[128], *p, *args[3];
ini = nil;
p = buf;
for(;;){
if((n = read(0, p, 1)) < 0)
fatal("can't read impo arguments: %r");
if(n == 0)
fatal("connection closed while reading arguments");
if(*p == '\n')
*p = '\0';
if(*p++ == '\0')
break;
if(p >= buf + sizeof(buf))
fatal("import parameters too long");
}
if(tokenize(buf, args, nelem(args)) != 2)
fatal("impo arguments invalid: impo%s...", buf);
if(strcmp(args[0], "aan") == 0)
filterp = aanfilter;
else if(strcmp(args[0], "nofilter") != 0)
fatal("import filter argument unsupported: %s", args[0]);
if(strcmp(args[1], "ssl") == 0)
encproto = Encssl;
else if(strcmp(args[1], "tls") == 0)
encproto = Enctls;
else if(strcmp(args[1], "clear") != 0)
fatal("import encryption proto unsupported: %s", args[1]);
if(encproto == Enctls)
fatal("%s: tls has not yet been implemented", argv[0]);
}
if(encproto != Encnone && ealgs != nil && ai != nil) {
uchar key[16], digest[SHA1dlen];
char fromclientsecret[21];
char fromserversecret[21];
int i;
if(ai->nsecret < 8)
fatal("secret too small for ssl");
memmove(key+4, ai->secret, 8);
/* exchange random numbers */
srand(truerand());
for(i = 0; i < 4; i++)
key[i+12] = rand();
if(ini != nil)
fatal("Protocol botch: old import");
if(readn(0, key, 4) != 4)
fatal("can't read key part; %r");
if(write(0, key+12, 4) != 4)
fatal("can't write key part; %r");
/* scramble into two secrets */
sha1(key, sizeof(key), digest, nil);
mksecret(fromclientsecret, digest);
mksecret(fromserversecret, digest+10);
if(filterp != nil)
filter(0, filterp, na);
switch(encproto) {
case Encssl:
fd = pushssl(0, ealgs, fromserversecret, fromclientsecret, nil);
if(fd < 0)
fatal("can't establish ssl connection: %r");
if(fd != 0){
dup(fd, 0);
close(fd);
}
break;
case Enctls:
default:
fatal("Unsupported encryption protocol");
}
}
else if(filterp != nil) {
if(ini != nil)
fatal("Protocol botch: don't know how to deal with this");
filter(0, filterp, na);
}
dup(0, 1);
if(ai != nil)
auth_freeAI(ai);
if(ini != nil){
r = getsbuf();
memmove(r->buf, ini, BIT32SZ);
n = GBIT32(r->buf);
if(n <= BIT32SZ || n > messagesize)
fatal("bad length in 9P2000 message header");
n -= BIT32SZ;
if(readn(0, r->buf+BIT32SZ, n) != n)
fatal(nil);
n += BIT32SZ;
goto Message;
}
/*
* Start serving file requests from the network
*/
for(;;) {
r = getsbuf();
n = read9pmsg(0, r->buf, messagesize);
if(n <= 0)
fatal(nil);
Message:
if(convM2S(r->buf, n, &r->work) != n)
fatal("convM2S format error");
DEBUG(DFD, "%F\n", &r->work);
(fcalls[r->work.type])(r);
}
}
void
reply(Fcall *r, Fcall *t, char *err)
{
uchar *data;
int n;
t->tag = r->tag;
t->fid = r->fid;
if(err != nil) {
t->type = Rerror;
t->ename = err;
}
else
t->type = r->type + 1;
DEBUG(DFD, "\t%F\n", t);
data = malloc(messagesize); /* not mallocz; no need to clear */
if(data == nil)
fatal(Enomem);
n = convS2M(t, data, messagesize);
if(write(0, data, n) != n){
/* not fatal, might have got a note due to flush */
fprint(2, "exportfs: short write in reply: %r\n");
}
free(data);
}
Fid *
getfid(int nr)
{
Fid *f;
for(f = fidhash(nr); f != nil; f = f->next)
if(f->nr == nr)
return f;
return nil;
}
int
freefid(int nr)
{
Fid *f, **l;
char buf[128];
l = &fidhash(nr);
for(f = *l; f != nil; f = f->next) {
if(f->nr == nr) {
if(f->mid) {
snprint(buf, sizeof(buf), "/mnt/exportfs/%d", f->mid);
unmount(0, buf);
psmap[f->mid] = 0;
}
if(f->f != nil) {
freefile(f->f);
f->f = nil;
}
if(f->dir != nil){
free(f->dir);
f->dir = nil;
}
*l = f->next;
f->next = fidfree;
fidfree = f;
return 1;
}
l = &f->next;
}
return 0;
}
Fid *
newfid(int nr)
{
Fid *new, **l;
int i;
l = &fidhash(nr);
for(new = *l; new != nil; new = new->next)
if(new->nr == nr)
return nil;
if(fidfree == nil) {
fidfree = emallocz(sizeof(Fid) * Fidchunk);
for(i = 0; i < Fidchunk-1; i++)
fidfree[i].next = &fidfree[i+1];
fidfree[Fidchunk-1].next = nil;
}
new = fidfree;
fidfree = new->next;
memset(new, 0, sizeof(Fid));
new->next = *l;
*l = new;
new->nr = nr;
new->fid = -1;
new->mid = 0;
return new;
}
static struct {
Lock;
Fsrpc *free;
/* statistics */
int nalloc;
int nfree;
} sbufalloc;
Fsrpc *
getsbuf(void)
{
Fsrpc *w;
lock(&sbufalloc);
w = sbufalloc.free;
if(w != nil){
sbufalloc.free = w->next;
w->next = nil;
sbufalloc.nfree--;
unlock(&sbufalloc);
} else {
sbufalloc.nalloc++;
unlock(&sbufalloc);
w = emallocz(sizeof(*w) + messagesize);
}
w->flushtag = NOTAG;
return w;
}
void
putsbuf(Fsrpc *w)
{
w->flushtag = NOTAG;
lock(&sbufalloc);
w->next = sbufalloc.free;
sbufalloc.free = w;
sbufalloc.nfree++;
unlock(&sbufalloc);
}
void
freefile(File *f)
{
File *parent, *child;
while(--f->ref == 0){
freecnt++;
DEBUG(DFD, "free %s\n", f->name);
/* delete from parent */
parent = f->parent;
if(parent->child == f)
parent->child = f->childlist;
else{
for(child = parent->child; child->childlist != f; child = child->childlist) {
if(child->childlist == nil)
fatal("bad child list");
}
child->childlist = f->childlist;
}
freeqid(f->qidt);
free(f->name);
free(f);
f = parent;
}
}
File *
file(File *parent, char *name)
{
Dir *dir;
char *path;
File *f;
DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
path = makepath(parent, name);
if(patternfile != nil && excludefile(path)){
free(path);
return nil;
}
dir = dirstat(path);
free(path);
if(dir == nil)
return nil;
for(f = parent->child; f != nil; f = f->childlist)
if(strcmp(name, f->name) == 0)
break;
if(f == nil){
f = emallocz(sizeof(File));
f->name = estrdup(name);
f->parent = parent;
f->childlist = parent->child;
parent->child = f;
parent->ref++;
f->ref = 0;
filecnt++;
}
f->ref++;
f->qid.type = dir->qid.type;
f->qid.vers = dir->qid.vers;
f->qidt = uniqueqid(dir);
f->qid.path = f->qidt->uniqpath;
f->inval = 0;
free(dir);
return f;
}
void
initroot(void)
{
Dir *dir;
root = emallocz(sizeof(File));
root->name = estrdup(".");
dir = dirstat(root->name);
if(dir == nil)
fatal("root stat");
root->ref = 1;
root->qid.vers = dir->qid.vers;
root->qidt = uniqueqid(dir);
root->qid.path = root->qidt->uniqpath;
root->qid.type = QTDIR;
free(dir);
psmpt = emallocz(sizeof(File));
psmpt->name = estrdup("/");
dir = dirstat(psmpt->name);
if(dir == nil)
return;
psmpt->ref = 1;
psmpt->qid.vers = dir->qid.vers;
psmpt->qidt = uniqueqid(dir);
psmpt->qid.path = psmpt->qidt->uniqpath;
free(dir);
psmpt = file(psmpt, "mnt");
if(psmpt == nil)
return;
psmpt = file(psmpt, "exportfs");
}
char*
makepath(File *p, char *name)
{
int i, n;
char *c, *s, *path, *seg[256];
seg[0] = name;
n = strlen(name)+2;
for(i = 1; i < 256 && p; i++, p = p->parent){
seg[i] = p->name;
n += strlen(p->name)+1;
}
path = emallocz(n);
s = path;
while(i--) {
for(c = seg[i]; *c; c++)
*s++ = *c;
*s++ = '/';
}
while(s[-1] == '/')
s--;
*s = '\0';
return path;
}
int
qidhash(vlong path)
{
int h, n;
h = 0;
for(n=0; n<64; n+=Nqidbits){
h ^= path;
path >>= Nqidbits;
}
return h & (Nqidtab-1);
}
void
freeqid(Qidtab *q)
{
ulong h;
Qidtab *l;
if(--q->ref)
return;
qfreecnt++;
h = qidhash(q->path);
if(qidtab[h] == q)
qidtab[h] = q->next;
else{
for(l=qidtab[h]; l->next!=q; l=l->next)
if(l->next == nil)
fatal("bad qid list");
l->next = q->next;
}
free(q);
}
Qidtab*
qidlookup(Dir *d)
{
ulong h;
Qidtab *q;
h = qidhash(d->qid.path);
for(q=qidtab[h]; q!=nil; q=q->next)
if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path)
return q;
return nil;
}
int
qidexists(vlong path)
{
int h;
Qidtab *q;
for(h=0; h<Nqidtab; h++)
for(q=qidtab[h]; q!=nil; q=q->next)
if(q->uniqpath == path)
return 1;
return 0;
}
Qidtab*
uniqueqid(Dir *d)
{
ulong h;
vlong path;
Qidtab *q;
q = qidlookup(d);
if(q != nil){
q->ref++;
return q;
}
path = d->qid.path;
while(qidexists(path)){
DEBUG(DFD, "collision on %s\n", d->name);
/* collision: find a new one */
ncollision++;
path &= QIDPATH;
++newqid;
if(newqid >= (1<<16)){
DEBUG(DFD, "collision wraparound\n");
newqid = 1;
}
path |= newqid<<48;
DEBUG(DFD, "assign qid %.16llux\n", path);
}
qidcnt++;
q = emallocz(sizeof(Qidtab));
q->ref = 1;
q->type = d->type;
q->dev = d->dev;
q->path = d->qid.path;
q->uniqpath = path;
h = qidhash(d->qid.path);
q->next = qidtab[h];
qidtab[h] = q;
return q;
}
void
fatal(char *s, ...)
{
char buf[ERRMAX];
va_list arg;
Proc *m;
if(s != nil) {
va_start(arg, s);
vsnprint(buf, ERRMAX, s, arg);
va_end(arg);
}
/* Clear away the slave children */
for(m = Proclist; m != nil; m = m->next)
postnote(PNPROC, m->pid, "kill");
if(s != nil) {
DEBUG(DFD, "%s\n", buf);
sysfatal("%s", buf); /* caution: buf could contain '%' */
} else
exits(nil);
}
void*
emallocz(uint n)
{
void *p;
p = mallocz(n, 1);
if(p == nil)
fatal(Enomem);
setmalloctag(p, getcallerpc(&n));
return p;
}
char*
estrdup(char *s)
{
char *t;
t = strdup(s);
if(t == nil)
fatal(Enomem);
setmalloctag(t, getcallerpc(&s));
return t;
}
void
filter(int fd, char *cmd, char *host)
{
char addr[128], buf[256], *s, *file, *argv[16];
int lfd, p[2], len, argc;
if(host == nil){
/* Get a free port and post it to the client. */
if (announce(anstring, addr) < 0)
fatal("filter: Cannot announce %s: %r", anstring);
snprint(buf, sizeof(buf), "%s/local", addr);
if ((lfd = open(buf, OREAD)) < 0)
fatal("filter: Cannot open %s: %r", buf);
if ((len = read(lfd, buf, sizeof buf - 1)) < 0)
fatal("filter: Cannot read %s: %r", buf);
close(lfd);
buf[len] = '\0';
if ((s = strchr(buf, '\n')) != nil)
len = s - buf;
if (write(fd, buf, len) != len)
fatal("filter: cannot write port; %r");
} else {
/* Read address string from connection */
if ((len = read(fd, buf, sizeof buf - 1)) < 0)
sysfatal("filter: cannot write port; %r");
buf[len] = '\0';
if ((s = strrchr(buf, '!')) == nil)
sysfatal("filter: illegally formatted port %s", buf);
strecpy(addr, addr+sizeof(addr), netmkaddr(host, "tcp", s+1));
strecpy(strrchr(addr, '!'), addr+sizeof(addr), s);
}
DEBUG(DFD, "filter: %s\n", addr);
snprint(buf, sizeof(buf), "%s", cmd);
argc = tokenize(buf, argv, nelem(argv)-3);
if (argc == 0)
sysfatal("filter: empty command");
if(host != nil)
argv[argc++] = "-c";
argv[argc++] = addr;
argv[argc] = nil;
file = argv[0];
if((s = strrchr(argv[0], '/')) != nil)
argv[0] = s+1;
if(pipe(p) < 0)
sysfatal("pipe: %r");
switch(rfork(RFNOWAIT|RFPROC|RFMEM|RFFDG|RFREND)) {
case -1:
fatal("filter: rfork; %r\n");
case 0:
close(fd);
if (dup(p[0], 1) < 0)
fatal("filter: Cannot dup to 1; %r");
if (dup(p[0], 0) < 0)
fatal("filter: Cannot dup to 0; %r");
close(p[0]);
close(p[1]);
exec(file, argv);
fatal("filter: exec; %r");
default:
dup(p[1], fd);
close(p[0]);
close(p[1]);
}
}
static void
mksecret(char *t, uchar *f)
{
sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
io();
}

View file

@ -112,7 +112,10 @@ void Xwalk(Fsrpc*);
void Xwstat(Fsrpc*);
void slave(Fsrpc*);
void io(void);
void reply(Fcall*, Fcall*, char*);
void mounterror(char*);
Fid *getfid(int);
int freefid(int);
Fid *newfid(int);

View file

@ -5,8 +5,6 @@
#define Extern extern
#include "exportfs.h"
extern char *netdir, *local, *remote;
char Ebadfid[] = "Bad fid";
char Enotdir[] = "Not a directory";
char Edupfid[] = "Fid already in use";
@ -493,12 +491,6 @@ slave(Fsrpc *f)
return;
case 0:
if (local[0] != '\0')
if (netdir[0] != '\0')
procsetname("%s: %s -> %s", netdir,
local, remote);
else
procsetname("%s -> %s", local, remote);
blockingslave(m);
_exits(0);

503
sys/src/cmd/exportfs/io.c Normal file
View file

@ -0,0 +1,503 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
#define Extern
#include "exportfs.h"
#define QIDPATH ((1LL<<48)-1)
vlong newqid = 0;
void (*fcalls[])(Fsrpc*) =
{
[Tversion] Xversion,
[Tauth] Xauth,
[Tflush] Xflush,
[Tattach] Xattach,
[Twalk] Xwalk,
[Topen] slave,
[Tcreate] Xcreate,
[Tclunk] Xclunk,
[Tread] slave,
[Twrite] slave,
[Tremove] Xremove,
[Tstat] Xstat,
[Twstat] Xwstat,
};
/* accounting and debugging counters */
int filecnt;
int freecnt;
int qidcnt;
int qfreecnt;
int ncollision;
/*
* Start serving file requests from the network
*/
void
io(void)
{
Fsrpc *r;
int n;
for(;;) {
r = getsbuf();
n = read9pmsg(0, r->buf, messagesize);
if(n <= 0)
fatal(nil);
if(convM2S(r->buf, n, &r->work) != n)
fatal("convM2S format error");
DEBUG(DFD, "%F\n", &r->work);
(fcalls[r->work.type])(r);
}
}
void
reply(Fcall *r, Fcall *t, char *err)
{
uchar *data;
int n;
t->tag = r->tag;
t->fid = r->fid;
if(err != nil) {
t->type = Rerror;
t->ename = err;
}
else
t->type = r->type + 1;
DEBUG(DFD, "\t%F\n", t);
data = malloc(messagesize); /* not mallocz; no need to clear */
if(data == nil)
fatal(Enomem);
n = convS2M(t, data, messagesize);
if(write(1, data, n) != n){
/* not fatal, might have got a note due to flush */
fprint(2, "exportfs: short write in reply: %r\n");
}
free(data);
}
void
mounterror(char *err)
{
Fsrpc *r;
int n;
r = getsbuf();
r->work.tag = NOTAG;
r->work.fid = NOFID;
r->work.type = Rerror;
r->work.ename = err;
n = convS2M(&r->work, r->buf, messagesize);
write(1, r->buf, n);
exits(err);
}
Fid *
getfid(int nr)
{
Fid *f;
for(f = fidhash(nr); f != nil; f = f->next)
if(f->nr == nr)
return f;
return nil;
}
int
freefid(int nr)
{
Fid *f, **l;
char buf[128];
l = &fidhash(nr);
for(f = *l; f != nil; f = f->next) {
if(f->nr == nr) {
if(f->mid) {
snprint(buf, sizeof(buf), "/mnt/exportfs/%d", f->mid);
unmount(0, buf);
psmap[f->mid] = 0;
}
if(f->f != nil) {
freefile(f->f);
f->f = nil;
}
if(f->dir != nil){
free(f->dir);
f->dir = nil;
}
*l = f->next;
f->next = fidfree;
fidfree = f;
return 1;
}
l = &f->next;
}
return 0;
}
Fid *
newfid(int nr)
{
Fid *new, **l;
int i;
l = &fidhash(nr);
for(new = *l; new != nil; new = new->next)
if(new->nr == nr)
return nil;
if(fidfree == nil) {
fidfree = emallocz(sizeof(Fid) * Fidchunk);
for(i = 0; i < Fidchunk-1; i++)
fidfree[i].next = &fidfree[i+1];
fidfree[Fidchunk-1].next = nil;
}
new = fidfree;
fidfree = new->next;
memset(new, 0, sizeof(Fid));
new->next = *l;
*l = new;
new->nr = nr;
new->fid = -1;
new->mid = 0;
return new;
}
static struct {
Lock;
Fsrpc *free;
/* statistics */
int nalloc;
int nfree;
} sbufalloc;
Fsrpc *
getsbuf(void)
{
Fsrpc *w;
lock(&sbufalloc);
w = sbufalloc.free;
if(w != nil){
sbufalloc.free = w->next;
w->next = nil;
sbufalloc.nfree--;
unlock(&sbufalloc);
} else {
sbufalloc.nalloc++;
unlock(&sbufalloc);
w = emallocz(sizeof(*w) + messagesize);
}
w->flushtag = NOTAG;
return w;
}
void
putsbuf(Fsrpc *w)
{
w->flushtag = NOTAG;
lock(&sbufalloc);
w->next = sbufalloc.free;
sbufalloc.free = w;
sbufalloc.nfree++;
unlock(&sbufalloc);
}
void
freefile(File *f)
{
File *parent, *child;
while(--f->ref == 0){
freecnt++;
DEBUG(DFD, "free %s\n", f->name);
/* delete from parent */
parent = f->parent;
if(parent->child == f)
parent->child = f->childlist;
else{
for(child = parent->child; child->childlist != f; child = child->childlist) {
if(child->childlist == nil)
fatal("bad child list");
}
child->childlist = f->childlist;
}
freeqid(f->qidt);
free(f->name);
free(f);
f = parent;
}
}
File *
file(File *parent, char *name)
{
Dir *dir;
char *path;
File *f;
DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
path = makepath(parent, name);
if(patternfile != nil && excludefile(path)){
free(path);
return nil;
}
dir = dirstat(path);
free(path);
if(dir == nil)
return nil;
for(f = parent->child; f != nil; f = f->childlist)
if(strcmp(name, f->name) == 0)
break;
if(f == nil){
f = emallocz(sizeof(File));
f->name = estrdup(name);
f->parent = parent;
f->childlist = parent->child;
parent->child = f;
parent->ref++;
f->ref = 0;
filecnt++;
}
f->ref++;
f->qid.type = dir->qid.type;
f->qid.vers = dir->qid.vers;
f->qidt = uniqueqid(dir);
f->qid.path = f->qidt->uniqpath;
f->inval = 0;
free(dir);
return f;
}
void
initroot(void)
{
Dir *dir;
root = emallocz(sizeof(File));
root->name = estrdup(".");
dir = dirstat(root->name);
if(dir == nil)
fatal("root stat");
root->ref = 1;
root->qid.vers = dir->qid.vers;
root->qidt = uniqueqid(dir);
root->qid.path = root->qidt->uniqpath;
root->qid.type = QTDIR;
free(dir);
psmpt = emallocz(sizeof(File));
psmpt->name = estrdup("/");
dir = dirstat(psmpt->name);
if(dir == nil)
return;
psmpt->ref = 1;
psmpt->qid.vers = dir->qid.vers;
psmpt->qidt = uniqueqid(dir);
psmpt->qid.path = psmpt->qidt->uniqpath;
free(dir);
psmpt = file(psmpt, "mnt");
if(psmpt == nil)
return;
psmpt = file(psmpt, "exportfs");
}
char*
makepath(File *p, char *name)
{
int i, n;
char *c, *s, *path, *seg[256];
seg[0] = name;
n = strlen(name)+2;
for(i = 1; i < 256 && p; i++, p = p->parent){
seg[i] = p->name;
n += strlen(p->name)+1;
}
path = emallocz(n);
s = path;
while(i--) {
for(c = seg[i]; *c; c++)
*s++ = *c;
*s++ = '/';
}
while(s[-1] == '/')
s--;
*s = '\0';
return path;
}
int
qidhash(vlong path)
{
int h, n;
h = 0;
for(n=0; n<64; n+=Nqidbits){
h ^= path;
path >>= Nqidbits;
}
return h & (Nqidtab-1);
}
void
freeqid(Qidtab *q)
{
ulong h;
Qidtab *l;
if(--q->ref)
return;
qfreecnt++;
h = qidhash(q->path);
if(qidtab[h] == q)
qidtab[h] = q->next;
else{
for(l=qidtab[h]; l->next!=q; l=l->next)
if(l->next == nil)
fatal("bad qid list");
l->next = q->next;
}
free(q);
}
Qidtab*
qidlookup(Dir *d)
{
ulong h;
Qidtab *q;
h = qidhash(d->qid.path);
for(q=qidtab[h]; q!=nil; q=q->next)
if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path)
return q;
return nil;
}
int
qidexists(vlong path)
{
int h;
Qidtab *q;
for(h=0; h<Nqidtab; h++)
for(q=qidtab[h]; q!=nil; q=q->next)
if(q->uniqpath == path)
return 1;
return 0;
}
Qidtab*
uniqueqid(Dir *d)
{
ulong h;
vlong path;
Qidtab *q;
q = qidlookup(d);
if(q != nil){
q->ref++;
return q;
}
path = d->qid.path;
while(qidexists(path)){
DEBUG(DFD, "collision on %s\n", d->name);
/* collision: find a new one */
ncollision++;
path &= QIDPATH;
++newqid;
if(newqid >= (1<<16)){
DEBUG(DFD, "collision wraparound\n");
newqid = 1;
}
path |= newqid<<48;
DEBUG(DFD, "assign qid %.16llux\n", path);
}
qidcnt++;
q = emallocz(sizeof(Qidtab));
q->ref = 1;
q->type = d->type;
q->dev = d->dev;
q->path = d->qid.path;
q->uniqpath = path;
h = qidhash(d->qid.path);
q->next = qidtab[h];
qidtab[h] = q;
return q;
}
void
fatal(char *s, ...)
{
char buf[ERRMAX];
va_list arg;
Proc *m;
if(s != nil) {
va_start(arg, s);
vsnprint(buf, ERRMAX, s, arg);
va_end(arg);
}
/* Clear away the slave children */
for(m = Proclist; m != nil; m = m->next)
postnote(PNPROC, m->pid, "kill");
if(s != nil) {
DEBUG(DFD, "%s\n", buf);
sysfatal("%s", buf); /* caution: buf could contain '%' */
} else
exits(nil);
}
void*
emallocz(uint n)
{
void *p;
p = mallocz(n, 1);
if(p == nil)
fatal(Enomem);
setmalloctag(p, getcallerpc(&n));
return p;
}
char*
estrdup(char *s)
{
char *t;
t = strdup(s);
if(t == nil)
fatal(Enomem);
setmalloctag(t, getcallerpc(&s));
return t;
}

View file

@ -1,10 +1,10 @@
</$objtype/mkfile
TARG=exportfs
TARG=exportfs oexportfs
OFILES=\
exportfs.$O\
exportsrv.$O\
pattern.$O\
io.$O\
HFILES=exportfs.h\
@ -15,4 +15,4 @@ UPDATE=\
$HFILES\
${OFILES:%.$O=%.c}\
</sys/src/cmd/mkone
</sys/src/cmd/mkmany

View file

@ -0,0 +1,443 @@
/*
* oexportfs - legacy exportfs for cpu and import
*/
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <libsec.h>
#define Extern
#include "exportfs.h"
enum {
Encnone,
Encssl,
Enctls,
};
int srvfd = -1;
int nonone = 1;
char *filterp;
char *ealgs = "rc4_256 sha1";
char *aanfilter = "/bin/aan";
int encproto = Encnone;
int readonly;
static char *anstring = "tcp!*!0";
static void
filter(int fd, char *cmd, char *host)
{
char addr[128], buf[256], *s, *file, *argv[16];
int lfd, p[2], len, argc;
if(host == nil){
/* Get a free port and post it to the client. */
if (announce(anstring, addr) < 0)
fatal("filter: Cannot announce %s: %r", anstring);
snprint(buf, sizeof(buf), "%s/local", addr);
if ((lfd = open(buf, OREAD)) < 0)
fatal("filter: Cannot open %s: %r", buf);
if ((len = read(lfd, buf, sizeof buf - 1)) < 0)
fatal("filter: Cannot read %s: %r", buf);
close(lfd);
buf[len] = '\0';
if ((s = strchr(buf, '\n')) != nil)
len = s - buf;
if (write(fd, buf, len) != len)
fatal("filter: cannot write port; %r");
} else {
/* Read address string from connection */
if ((len = read(fd, buf, sizeof buf - 1)) < 0)
sysfatal("filter: cannot write port; %r");
buf[len] = '\0';
if ((s = strrchr(buf, '!')) == nil)
sysfatal("filter: illegally formatted port %s", buf);
strecpy(addr, addr+sizeof(addr), netmkaddr(host, "tcp", s+1));
strecpy(strrchr(addr, '!'), addr+sizeof(addr), s);
}
DEBUG(DFD, "filter: %s\n", addr);
snprint(buf, sizeof(buf), "%s", cmd);
argc = tokenize(buf, argv, nelem(argv)-3);
if (argc == 0)
sysfatal("filter: empty command");
if(host != nil)
argv[argc++] = "-c";
argv[argc++] = addr;
argv[argc] = nil;
file = argv[0];
if((s = strrchr(argv[0], '/')) != nil)
argv[0] = s+1;
if(pipe(p) < 0)
sysfatal("pipe: %r");
switch(rfork(RFNOWAIT|RFPROC|RFMEM|RFFDG|RFREND)) {
case -1:
fatal("filter: rfork; %r\n");
case 0:
close(fd);
if (dup(p[0], 1) < 0)
fatal("filter: Cannot dup to 1; %r");
if (dup(p[0], 0) < 0)
fatal("filter: Cannot dup to 0; %r");
close(p[0]);
close(p[1]);
exec(file, argv);
fatal("filter: exec; %r");
default:
dup(p[1], fd);
close(p[0]);
close(p[1]);
}
}
static void
mksecret(char *t, uchar *f)
{
sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
}
void
usage(void)
{
fprint(2, "usage: %s [-adnsR] [-f dbgfile] [-m msize] [-r root] "
"[-S srvfile] [-e 'crypt hash'] [-P exclusion-file] "
"[-A announce-string] [-B address]\n", argv0);
fatal("usage");
}
void
main(int argc, char **argv)
{
char buf[ERRMAX], ebuf[ERRMAX], initial[4], *ini, *srvfdfile;
char *dbfile, *srv, *na, *nsfile, *keyspec;
int doauth, n, fd;
AuthInfo *ai;
Fsrpc *r;
dbfile = "/tmp/exportdb";
srv = nil;
srvfd = -1;
srvfdfile = nil;
na = nil;
nsfile = nil;
keyspec = "";
doauth = 0;
ai = nil;
ARGBEGIN{
case 'a':
doauth = 1;
break;
case 'd':
dbg++;
break;
case 'e':
ealgs = EARGF(usage());
if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
ealgs = nil;
break;
case 'f':
dbfile = EARGF(usage());
break;
case 'k':
keyspec = EARGF(usage());
break;
case 'm':
messagesize = strtoul(EARGF(usage()), nil, 0);
break;
case 'n':
nonone = 0;
break;
case 'r':
srv = EARGF(usage());
break;
case 's':
srv = "/";
break;
case 'A':
anstring = EARGF(usage());
break;
case 'B':
na = EARGF(usage());
break;
case 'F':
/* accepted but ignored, for backwards compatibility */
break;
case 'N':
nsfile = EARGF(usage());
break;
case 'P':
patternfile = EARGF(usage());
break;
case 'R':
readonly = 1;
break;
case 'S':
if(srvfdfile != nil)
usage();
srvfdfile = EARGF(usage());
break;
default:
usage();
}ARGEND
USED(argc, argv);
if(na == nil && doauth){
/*
* We use p9any so we don't have to visit this code again, with the
* cost that this code is incompatible with the old world, which
* requires p9sk2. (The two differ in who talks first, so compatibility
* is awkward.)
*/
ai = auth_proxy(0, auth_getkey, "proto=p9any role=server %s", keyspec);
if(ai == nil)
fatal("auth_proxy: %r");
if(nonone && strcmp(ai->cuid, "none") == 0)
fatal("exportfs by none disallowed");
if(auth_chuid(ai, nsfile) < 0)
fatal("auth_chuid: %r");
else { /* chown network connection */
Dir nd;
nulldir(&nd);
nd.mode = 0660;
nd.uid = ai->cuid;
dirfwstat(0, &nd);
}
putenv("service", "exportfs");
}
if(srvfdfile != nil){
if((srvfd = open(srvfdfile, ORDWR)) < 0)
fatal("open %s: %r", srvfdfile);
}
if(na != nil){
if(srv == nil)
fatal("-B requires -s");
if((fd = dial(netmkaddr(na, 0, "importfs"), 0, 0, 0)) < 0)
fatal("can't dial %s: %r", na);
ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec);
if(ai == nil)
fatal("%r: %s", na);
dup(fd, 0);
dup(fd, 1);
close(fd);
}
exclusions();
if(dbg) {
n = create(dbfile, OWRITE|OTRUNC, 0666);
dup(n, DFD);
close(n);
}
if(srvfd >= 0 && srv != nil){
fprint(2, "%s: -S cannot be used with -r or -s\n", argv0);
usage();
}
DEBUG(DFD, "%s: started\n", argv0);
rfork(RFNOTEG|RFREND);
if(messagesize == 0){
messagesize = iounit(0);
if(messagesize == 0)
messagesize = 8192+IOHDRSZ;
}
fhash = emallocz(sizeof(Fid*)*FHASHSIZE);
fmtinstall('F', fcallfmt);
/*
* Get tree to serve from network connection,
* check we can get there and ack the connection
*/
if(srvfd != -1) {
/* do nothing */
}
else if(srv != nil) {
if(chdir(srv) < 0) {
ebuf[0] = '\0';
errstr(ebuf, sizeof ebuf);
DEBUG(DFD, "chdir(\"%s\"): %s\n", srv, ebuf);
mounterror(ebuf);
}
DEBUG(DFD, "invoked as server for %s", srv);
strncpy(buf, srv, sizeof buf);
}
else {
buf[0] = 0;
n = read(0, buf, sizeof(buf)-1);
if(n < 0) {
errstr(buf, sizeof buf);
fprint(0, "read(0): %s\n", buf);
DEBUG(DFD, "read(0): %s\n", buf);
exits(buf);
}
buf[n] = 0;
if(chdir(buf) < 0) {
errstr(ebuf, sizeof ebuf);
fprint(0, "chdir(%d:\"%s\"): %s\n", n, buf, ebuf);
DEBUG(DFD, "chdir(%d:\"%s\"): %s\n", n, buf, ebuf);
exits(ebuf);
}
}
DEBUG(DFD, "\niniting root\n");
initroot();
DEBUG(DFD, "%s: %s\n", argv0, buf);
if(srv == nil && srvfd == -1 && write(0, "OK", 2) != 2)
fatal("open ack write");
ini = initial;
n = readn(0, initial, sizeof(initial));
if(n == 0)
fatal(nil); /* port scan or spurious open/close on exported /srv file (unmount) */
if(n < sizeof(initial))
fatal("can't read initial string: %r");
if(memcmp(ini, "impo", 4) == 0) {
char buf[128], *p, *args[3];
ini = nil;
p = buf;
for(;;){
if((n = read(0, p, 1)) < 0)
fatal("can't read impo arguments: %r");
if(n == 0)
fatal("connection closed while reading arguments");
if(*p == '\n')
*p = '\0';
if(*p++ == '\0')
break;
if(p >= buf + sizeof(buf))
fatal("import parameters too long");
}
if(tokenize(buf, args, nelem(args)) != 2)
fatal("impo arguments invalid: impo%s...", buf);
if(strcmp(args[0], "aan") == 0)
filterp = aanfilter;
else if(strcmp(args[0], "nofilter") != 0)
fatal("import filter argument unsupported: %s", args[0]);
if(strcmp(args[1], "ssl") == 0)
encproto = Encssl;
else if(strcmp(args[1], "tls") == 0)
encproto = Enctls;
else if(strcmp(args[1], "clear") != 0)
fatal("import encryption proto unsupported: %s", args[1]);
if(encproto == Enctls)
fatal("%s: tls has not yet been implemented", argv[0]);
}
if(encproto != Encnone && ealgs != nil && ai != nil) {
uchar key[16], digest[SHA1dlen];
char fromclientsecret[21];
char fromserversecret[21];
int i;
if(ai->nsecret < 8)
fatal("secret too small for ssl");
memmove(key+4, ai->secret, 8);
/* exchange random numbers */
srand(truerand());
for(i = 0; i < 4; i++)
key[i+12] = rand();
if(ini != nil)
fatal("Protocol botch: old import");
if(readn(0, key, 4) != 4)
fatal("can't read key part; %r");
if(write(0, key+12, 4) != 4)
fatal("can't write key part; %r");
/* scramble into two secrets */
sha1(key, sizeof(key), digest, nil);
mksecret(fromclientsecret, digest);
mksecret(fromserversecret, digest+10);
if(filterp != nil)
filter(0, filterp, na);
switch(encproto) {
case Encssl:
fd = pushssl(0, ealgs, fromserversecret, fromclientsecret, nil);
if(fd < 0)
fatal("can't establish ssl connection: %r");
if(fd != 0){
dup(fd, 0);
close(fd);
}
break;
case Enctls:
default:
fatal("Unsupported encryption protocol");
}
}
else if(filterp != nil) {
if(ini != nil)
fatal("Protocol botch: don't know how to deal with this");
filter(0, filterp, na);
}
dup(0, 1);
if(ai != nil)
auth_freeAI(ai);
if(ini != nil){
extern void (*fcalls[])(Fsrpc*);
r = getsbuf();
memmove(r->buf, ini, BIT32SZ);
n = GBIT32(r->buf);
if(n <= BIT32SZ || n > messagesize)
fatal("bad length in 9P2000 message header");
n -= BIT32SZ;
if(readn(0, r->buf+BIT32SZ, n) != n)
fatal(nil);
n += BIT32SZ;
if(convM2S(r->buf, n, &r->work) != n)
fatal("convM2S format error");
DEBUG(DFD, "%F\n", &r->work);
(fcalls[r->work.type])(r);
}
io();
}

View file

@ -354,6 +354,7 @@ main(int argc, char **argv)
sysfatal("fork: %r");
case 0:
dup(efd[0], 0);
dup(efd[0], 1);
close(efd[0]);
close(efd[1]);
close(pfd[1]);

View file

@ -637,7 +637,7 @@ hidparse(int t, int f, int g[], int l[], int, void *a)
s->h = v;
break;
case 0x0D0051: /* Conteact identifier */
case 0x0D0051: /* Contact identifier */
s->id = v;
break;
@ -684,7 +684,7 @@ readerproc(void* a)
{
char err[ERRMAX], mbuf[80];
uchar lastk[64], uk, dk;
int i, c, nerrs, lastb, nlastk;
int i, c, nerrs, bpress, lastb, nlastk;
int abs, x, y, z, b;
Hidreport p;
Hidslot lasts[nelem(p.s)], *s, *l;
@ -774,7 +774,7 @@ readerproc(void* a)
continue;
/* combine all the slots */
abs = x = y = z = b = 0;
bpress = abs = x = y = z = b = 0;
for(i=0; i<p.ns; *l = *s, i++){
s = &p.s[i];
@ -785,7 +785,7 @@ readerproc(void* a)
if(l == &lasts[nelem(lasts)-1] || !l->valid)
*l = *s;
/* convet absolute z to relative */
/* convert absolute z to relative */
z += s->z;
if(s->abs & 4)
z -= l->z;
@ -808,6 +808,7 @@ readerproc(void* a)
b |= 2;
if(s->b & 2)
b |= 4;
bpress |= s->m;
/* X/Y are absolute? */
if((s->abs & 3) == 3){
@ -825,7 +826,9 @@ readerproc(void* a)
y += s->y;
}
}
if(bpress == 0)
b = lastb & 7;
if(z != 0)
b |= z > 0 ? 8 : 16;

View file

@ -8,6 +8,7 @@
typedef struct IOProc IOProc;
typedef struct PFilter PFilter;
typedef struct FAttr FAttr;
typedef struct PFid PFid;
struct IOProc {
@ -27,11 +28,19 @@ struct PFid {
};
Qid rootqid = {.type QTDIR};
struct FAttr {
char *name;
Reprog *filt;
int invert;
FAttr *next;
};
struct PFilter {
char *name;
Reprog *filt;
PFilter *next;
int invert;
FAttr *attr;
PFilter *next;
};
PFilter *filters;
@ -161,13 +170,33 @@ ptrapopen(Req *r)
respond(r, nil);
}
static int
filter(PFilter *f, Plumbmsg *pm)
{
FAttr *a;
char *value;
if(!(regexec(f->filt, pm->data, nil, 0) ^ f->invert))
return 0;
for(a = f->attr; a; a = a->next){
value = plumblookup(pm->attr, a->name);
if(value == nil)
return 0;
if(!(regexec(a->filt, value, nil, 0) ^ f->attr->invert))
return 0;
}
return 1;
}
static int
filterread(Req *r, PFid *pf)
{
int rc, len, more;
char *buf;
Plumbmsg *pm;
PFilter *f;
f = pf->filter;
for(;;){
if(pf->msg != nil){
rc = r->ifcall.count;
@ -194,7 +223,7 @@ filterread(Req *r, PFid *pf)
len += rc;
}
free(buf);
if(regexec(pf->filter->filt, pm->data, nil, 0) ^ pf->filter->invert){
if(filter(f, pm)){
pf->msg = plumbpack(pm, &pf->msgn);
pf->msgp = 0;
}
@ -341,7 +370,7 @@ Srv ptrapsrv = {
void
usage(void)
{
fprint(2, "usage: %s port regex [ port regex ... ]\n", argv0);
fprint(2, "usage: %s port regex [ +attr regex ... ] ...\n", argv0);
exits("usage");
}
@ -349,6 +378,7 @@ void
threadmain(int argc, char **argv)
{
PFilter *f;
FAttr *fa;
char *p;
int i;
@ -357,19 +387,33 @@ threadmain(int argc, char **argv)
}ARGEND;
if(argc == 0 || argc % 2) usage();
for(i = 0; i < argc; i += 2){
for(i = 0; i+1 < argc;){
p = argv[i];
f = emalloc9p(sizeof(PFilter));
f->name = strdup(argv[i]);
f->name = estrdup9p(p);
p = argv[i+1];
if(*p == '!'){
if(p[0] == '!'){
p++;
f->invert = 1;
}
f->filt = regcomp(p);
if(f->filt == nil)
sysfatal("%r");
if((f->filt = regcomp(p)) == nil)
sysfatal("regcomp: %r");
f->next = filters;
filters = f;
for(i += 2; p = argv[i], i+1 < argc && p[0] == '+'; i += 2){
p++;
fa = emalloc9p(sizeof(FAttr));
fa->name = estrdup9p(p);
p = argv[i+1];
if(p[0] == '!'){
p++;
fa->invert = 1;
}
if((fa->filt = regcomp(p)) == nil)
sysfatal("regcomp: %r");
fa->next = f->attr;
f->attr = fa;
}
}
threadpostmountsrv(&ptrapsrv, nil, "/mnt/plumb", MREPL | MCREATE);

View file

@ -118,37 +118,27 @@ cexecpipe(int *p0, int *p1)
Filsys*
filsysinit(Channel *cxfidalloc)
{
int n, fd, pid, p0;
int p0;
Filsys *fs;
Channel *c;
char buf[128];
fs = emalloc(sizeof(Filsys));
if(cexecpipe(&fs->cfd, &fs->sfd) < 0)
goto Rescue;
fmtinstall('F', fcallfmt);
clockfd = open("/dev/time", OREAD|OCEXEC);
fd = open("/dev/user", OREAD);
strcpy(buf, "Jean-Paul_Belmondo");
if(fd >= 0){
n = read(fd, buf, sizeof buf-1);
if(n > 0)
buf[n] = 0;
close(fd);
}
fs->user = estrdup(buf);
fs->user = getuser();
fs->csyncflush = chancreate(sizeof(int), 0);
if(fs->csyncflush == nil)
error("chancreate syncflush");
fs->cxfidalloc = cxfidalloc;
pid = getpid();
/*
* Create and post wctl pipe
*/
if(cexecpipe(&p0, &wctlfd) < 0)
goto Rescue;
snprint(srvwctl, sizeof(srvwctl), "/srv/riowctl.%s.%d", fs->user, pid);
snprint(srvwctl, sizeof(srvwctl), "/srv/riowctl.%s.%lud", fs->user, (ulong)getpid());
post(srvwctl, "wctl", p0);
close(p0);
@ -165,7 +155,7 @@ filsysinit(Channel *cxfidalloc)
/*
* Post srv pipe
*/
snprint(srvpipe, sizeof(srvpipe), "/srv/rio.%s.%d", fs->user, pid);
snprint(srvpipe, sizeof(srvpipe), "/srv/rio.%s.%lud", fs->user, (ulong)getpid());
post(srvpipe, "wsys", fs->cfd);
return fs;
@ -234,7 +224,7 @@ filsysmount(Filsys *fs, int id)
char buf[32];
close(fs->sfd); /* close server end so mount won't hang if exiting */
sprint(buf, "%d", id);
snprint(buf, sizeof buf, "%d", id);
if(mount(fs->cfd, -1, "/mnt/wsys", MREPL, buf) == -1){
fprint(2, "mount failed: %r\n");
return -1;

View file

@ -244,7 +244,7 @@ putsnarf(void)
if(snarffd<0 || nsnarf==0)
return;
fd = open("/dev/snarf", OWRITE);
fd = open("/dev/snarf", OWRITE|OCEXEC);
if(fd < 0)
return;
/* snarf buffer could be huge, so fprint will truncate; do it in blocks */
@ -394,12 +394,13 @@ portion(int x, int lo, int hi)
{
x -= lo;
hi -= lo;
if(hi < 20)
return x > 0 ? 2 : 0;
if(x < 20)
return 0;
if(x > hi-20)
return 2;
if(x < hi/2){
if(x < 20)
return 0;
} else {
if(x > hi-20)
return 2;
}
return 1;
}
@ -857,7 +858,7 @@ sweep(void)
}
void
drawedge(Image **bp, Rectangle r)
drawedge(Image **bp, Image *col, Rectangle r)
{
Image *b = *bp;
if(b != nil && Dx(b->r) == Dx(r) && Dy(b->r) == Dy(r))
@ -865,28 +866,30 @@ drawedge(Image **bp, Rectangle r)
else{
freeimage(b);
b = allocwindow(wscreen, r, Refbackup, DNofill);
if(b != nil) draw(b, r, sizecol, nil, ZP);
if(b != nil) draw(b, r, col, nil, ZP);
*bp = b;
}
}
void
drawborder(Rectangle r, int show)
drawborder(Rectangle r, Image *col)
{
static Image *b[4];
int i;
if(show == 0){
for(i = 0; i < 4; i++){
freeimage(b[i]);
b[i] = nil;
}
}else{
r = canonrect(r);
drawedge(&b[0], Rect(r.min.x, r.min.y, r.min.x+Borderwidth, r.max.y));
drawedge(&b[1], Rect(r.min.x+Borderwidth, r.min.y, r.max.x-Borderwidth, r.min.y+Borderwidth));
drawedge(&b[2], Rect(r.max.x-Borderwidth, r.min.y, r.max.x, r.max.y));
drawedge(&b[3], Rect(r.min.x+Borderwidth, r.max.y-Borderwidth, r.max.x-Borderwidth, r.max.y));
static Image *b[4], *lastcol;
if(col != lastcol){
freeimage(b[0]), b[0] = nil;
freeimage(b[1]), b[1] = nil;
freeimage(b[2]), b[2] = nil;
freeimage(b[3]), b[3] = nil;
}
if(col != nil){
r = canonrect(r);
drawedge(&b[0], col, Rect(r.min.x, r.min.y, r.min.x+Borderwidth, r.max.y));
drawedge(&b[1], col, Rect(r.min.x+Borderwidth, r.min.y, r.max.x-Borderwidth, r.min.y+Borderwidth));
drawedge(&b[2], col, Rect(r.max.x-Borderwidth, r.min.y, r.max.x, r.max.y));
drawedge(&b[3], col, Rect(r.min.x+Borderwidth, r.max.y-Borderwidth, r.max.x-Borderwidth, r.max.y));
}
lastcol = col;
}
Image*
@ -901,17 +904,17 @@ drag(Window *w)
dm = subpt(om, w->screenr.min);
d = subpt(w->screenr.max, w->screenr.min);
op = subpt(om, dm);
drawborder(Rect(op.x, op.y, op.x+d.x, op.y+d.y), 1);
drawborder(Rect(op.x, op.y, op.x+d.x, op.y+d.y), sizecol);
while(mouse->buttons==4){
p = subpt(mouse->xy, dm);
if(!eqpt(p, op)){
drawborder(Rect(p.x, p.y, p.x+d.x, p.y+d.y), 1);
drawborder(Rect(p.x, p.y, p.x+d.x, p.y+d.y), sizecol);
op = p;
}
readmouse(mousectl);
}
r = Rect(op.x, op.y, op.x+d.x, op.y+d.y);
drawborder(r, 0);
drawborder(r, nil);
p = mouse->xy;
riosetcursor(inborder(r, p) ? corners[whichcorner(r, p)] : nil);
menuing = FALSE;
@ -935,7 +938,7 @@ bandsize(Window *w)
or = w->screenr;
but = mouse->buttons;
startp = onscreen(mouse->xy);
drawborder(or, 1);
drawborder(or, sizecol);
while(mouse->buttons == but) {
p = onscreen(mouse->xy);
which = whichcorner(or, p);
@ -945,12 +948,14 @@ bandsize(Window *w)
}
r = whichrect(or, p, owhich);
if(!eqrect(r, or) && goodrect(r)){
drawborder(r, sizecol);
or = r;
drawborder(r, 1);
}
readmouse(mousectl);
}
drawborder(or, 0);
drawborder(or, nil);
if(!goodrect(or))
riosetcursor(nil);
if(mouse->buttons!=0 || !goodrect(or) || eqrect(or, w->screenr)
|| abs(p.x-startp.x)+abs(p.y-startp.y) <= 1){
flushimage(display, 1);

View file

@ -88,14 +88,19 @@ static char *params[] = {
int
goodrect(Rectangle r)
{
if(!eqrect(canonrect(r), r))
if(badrect(r) || !eqrect(canonrect(r), r))
return 0;
/* reasonable sizes only please */
if(Dx(r) > BIG*Dx(screen->r))
return 0;
if(Dy(r) > BIG*Dy(screen->r))
return 0;
if(Dx(r) < 100 || Dy(r) < 3*font->height)
/*
* the height has to be big enough to fit one line of text.
* that includes the border on each side with an extra pixel
* so that the text is still drawn
*/
if(Dx(r) < 100 || Dy(r) < 2*(Borderwidth+1)+font->height)
return 0;
/* window must be on screen */
if(!rectXrect(screen->r, r))

View file

@ -1420,7 +1420,7 @@ wclosewin(Window *w)
void
wsetpid(Window *w, int pid, int dolabel)
{
char buf[64];
char buf[32];
int ofd;
ofd = w->notefd;
@ -1428,11 +1428,11 @@ wsetpid(Window *w, int pid, int dolabel)
w->notefd = -1;
else {
if(dolabel){
snprint(buf, sizeof(buf), "rc %d", pid);
snprint(buf, sizeof(buf), "rc %lud", (ulong)pid);
free(w->label);
w->label = estrdup(buf);
}
snprint(buf, sizeof(buf), "/proc/%d/notepg", pid);
snprint(buf, sizeof(buf), "/proc/%lud/notepg", (ulong)pid);
w->notefd = open(buf, OWRITE|OCEXEC);
}
if(ofd >= 0)

View file

@ -12,7 +12,7 @@ void
main(int argc, char **argv)
{
char *ename, *arglist[16], **argp;
int n, fd, pipefd[2];
int fd, pipefd[2];
char buf[64];
int perm = 0600;
@ -39,14 +39,27 @@ main(int argc, char **argv)
*argp++ = "-R";
break;
}ARGEND
*argp = 0;
if(argc != 2)
usage();
*argp++ = "-r";
*argp++ = argv[1];
*argp = 0;
if(pipe(pipefd) < 0){
fprint(2, "can't pipe: %r\n");
exits("pipe");
}
if(argv[0][0] == '/')
strecpy(buf, buf+sizeof buf, argv[0]);
else
snprint(buf, sizeof buf, "/srv/%s", argv[0]);
fd = create(buf, OWRITE|ORCLOSE, perm);
if(fd < 0){
fprint(2, "can't create %s: %r\n", buf);
exits("create");
}
fprint(fd, "%d", pipefd[1]);
close(pipefd[1]);
switch(rfork(RFPROC|RFNOWAIT|RFNOTEG|RFFDG)){
case -1:
@ -56,39 +69,11 @@ main(int argc, char **argv)
dup(pipefd[0], 0);
dup(pipefd[0], 1);
close(pipefd[0]);
close(pipefd[1]);
exec(ename, arglist);
fprint(2, "can't exec exportfs: %r\n");
exits("exec");
default:
break;
}
close(pipefd[0]);
if(fprint(pipefd[1], "%s", argv[1]) < 0){
fprint(2, "can't write pipe: %r\n");
exits("write");
}
n = read(pipefd[1], buf, sizeof buf-1);
if(n < 0){
fprint(2, "can't read pipe: %r\n");
exits("read");
}
buf[n] = 0;
if(n != 2 || strcmp(buf, "OK") != 0){
fprint(2, "not OK (%d): %s\n", n, buf);
exits("OK");
}
if(argv[0][0] == '/')
strecpy(buf, buf+sizeof buf, argv[0]);
else
snprint(buf, sizeof buf, "/srv/%s", argv[0]);
fd = create(buf, OWRITE, perm);
if(fd < 0){
fprint(2, "can't create %s: %r\n", buf);
exits("create");
}
fprint(fd, "%d", pipefd[1]);
close(fd);
close(pipefd[1]);
exits(0);
}

View file

@ -11,6 +11,7 @@ enum {
VMDEAD,
};
extern int state;
extern int debug;
enum {
BY2PG = 4096

View file

@ -1,9 +1,8 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <bio.h>
#include "dat.h"
#include "fns.h"
#include "x86.h"
int persist = 1;
@ -118,109 +117,167 @@ eptfault(ExitInfo *ei)
typedef struct CPUID CPUID;
struct CPUID {
u32int idx;
u32int ax, bx, cx, dx;
};
static CPUID *cpuidf;
static int ncpuidf;
static u32int cpuidmax;
static u32int cpuidmaxext;
static CPUID leaf1;
static struct {
uvlong miscen;
}msr;
static void
auxcpuidproc(void *vpfd)
{
int *pfd;
pfd = vpfd;
close(pfd[1]);
close(0);
open("/dev/null", OREAD);
dup(pfd[0], 1);
close(pfd[0]);
procexecl(nil, "/bin/aux/cpuid", "cpuid", "-r", nil);
threadexits("exec: %r");
}
static uchar _cpuid[] = {
0x5E, /* POP SI (PC) */
0x5D, /* POP BP (CPUID&) */
0x58, /* POP AX */
0x59, /* POP CX */
0x51, /* PUSH CX */
0x50, /* PUSH AX */
0x55, /* PUSH BP */
0x56, /* PUSH SI */
0x31, 0xDB, /* XOR BX, BX */
0x31, 0xD2, /* XOR DX, DX */
0x0F, 0xA2, /* CPUID */
0x89, 0x45, 0x00, /* MOV AX, 0(BP) */
0x89, 0x5d, 0x04, /* MOV BX, 4(BP) */
0x89, 0x4d, 0x08, /* MOV CX, 8(BP) */
0x89, 0x55, 0x0C, /* MOV DX, 12(BP) */
0xC3, /* RET */
};
static CPUID (*getcpuid)(ulong ax, ulong cx) = (CPUID(*)(ulong, ulong)) _cpuid;
void
cpuidinit(void)
{
int pfd[2];
Biobuf *bp;
char *l, *f[5];
CPUID *cp;
pipe(pfd);
procrfork(auxcpuidproc, pfd, 4096, RFFDG);
close(pfd[0]);
bp = Bfdopen(pfd[1], OREAD);
if(bp == nil) sysfatal("Bopenfd: %r");
for(; l = Brdstr(bp, '\n', 1), l != nil; free(l)){
if(tokenize(l, f, 5) < 5) continue;
cpuidf = realloc(cpuidf, (ncpuidf + 1) * sizeof(CPUID));
cp = cpuidf + ncpuidf++;
cp->idx = strtoul(f[0], nil, 16);
cp->ax = strtoul(f[1], nil, 16);
cp->bx = strtoul(f[2], nil, 16);
cp->cx = strtoul(f[3], nil, 16);
cp->dx = strtoul(f[4], nil, 16);
CPUID r;
int f;
if(sizeof(uintptr) == 8) /* patch out POP BP -> POP AX */
_cpuid[1] = 0x58;
segflush(_cpuid, sizeof(_cpuid));
r = getcpuid(0, 0);
cpuidmax = r.ax;
r = getcpuid(0x80000000, 0);
cpuidmaxext = r.ax;
leaf1 = getcpuid(1, 0);
memset(&msr, 0, sizeof(msr));
if((f = open("/dev/msr", OREAD)) >= 0){
pread(f, &msr.miscen, 8, 0x1a0);
msr.miscen &= 1<<0; /* fast strings */
close(f);
}
Bterm(bp);
close(pfd[1]);
}
CPUID *
getcpuid(ulong idx)
{
CPUID *cp;
for(cp = cpuidf; cp < cpuidf + ncpuidf; cp++)
if(cp->idx == idx)
return cp;
return nil;
}
int maxcpuid = 7;
static int xsavesz[] = {
[1] = 512+64,
[3] = 512+64,
[7] = 512+64+256,
};
static void
cpuid(ExitInfo *ei)
{
u32int ax, bx, cx, dx;
CPUID *cp;
static CPUID def;
CPUID cp;
ax = rget(RAX);
cp = getcpuid(ax);
if(cp == nil) cp = &def;
cx = rget(RCX);
bx = dx = 0;
cp = getcpuid(ax, cx);
switch(ax){
case 0: /* highest register & GenuineIntel */
ax = maxcpuid;
bx = cp->bx;
dx = cp->dx;
cx = cp->cx;
case 0x00: /* highest register & GenuineIntel */
ax = MIN(cpuidmax, 0x18);
bx = cp.bx;
dx = cp.dx;
cx = cp.cx;
break;
case 1: /* features */
ax = cp->ax;
bx = cp->bx & 0xffff;
cx = cp->cx & 0x60de2203;
dx = cp->dx & 0x0782a179;
case 0x01: /* features */
ax = cp.ax;
bx = cp.bx & 0xffff;
/* some features removed, hypervisor added */
cx = cp.cx & 0x76de3217 | 0x80000000UL;
dx = cp.dx & 0x0f8aa579;
if(leaf1.cx & 1<<27){
if(rget("cr4real") & Cr4Osxsave)
cx |= 1<<27;
}else{
cx &= ~0x1c000000;
}
break;
case 2: goto literal; /* cache stuff */
case 3: goto zero; /* processor serial number */
case 4: goto zero; /* cache stuff */
case 5: goto zero; /* monitor/mwait */
case 6: goto zero; /* thermal management */
case 7: goto zero; /* more features */
case 10: goto zero; /* performance counters */
case 0x02: goto literal; /* cache stuff */
case 0x03: goto zero; /* processor serial number */
case 0x04: goto literal; /* cache stuff */
case 0x05: goto zero; /* monitor/mwait */
case 0x06: goto zero; /* thermal management */
case 0x07: /* more features */
if(cx == 0){
ax = 0;
bx = cp.bx & 0x2369;
cx = 0;
if((leaf1.cx & 1<<27) == 0)
bx &= ~0xdc230020;
}else{
goto zero;
}
break;
case 0x08: goto zero;
case 0x09: goto literal; /* direct cache access */
case 0x0a: goto zero; /* performance counters */
case 0x0b: goto zero; /* extended topology */
case 0x0c: goto zero;
case 0x0d: /* extended state */
if((leaf1.cx & 1<<27) == 0)
goto zero;
if(cx == 0){ /* main leaf */
ax = cp.ax & 7; /* x87, sse, avx */
bx = xsavesz[rget("xcr0")]; /* current xsave size */
cx = xsavesz[ax]; /* max xsave size */
}else if(cx == 1){ /* sub leaf */
ax = cp.ax & 7; /* xsaveopt, xsavec, xgetbv1 */
bx = xsavesz[rget("xcr0")];
cx = 0;
}else if(cx == 2){
ax = xsavesz[7] - xsavesz[3];
bx = xsavesz[3];
cx = 0;
}else{
goto zero;
}
break;
case 0x0f: goto zero; /* RDT */
case 0x10: goto zero; /* RDT */
case 0x12: goto zero; /* SGX */
case 0x14: goto zero; /* PT */
case 0x15: goto zero; /* TSC */
case 0x16: goto zero; /* cpu clock */
case 0x17: goto zero; /* SoC */
case 0x18: goto literal; /* pages, tlb */
case 0x40000000: /* hypervisor */
ax = 0;
bx = 0x4b4d564b; /* act as KVM */
cx = 0x564b4d56;
dx = 0x4d;
break;
case 0x80000000: /* highest register */
ax = 0x80000008;
bx = cx = dx = 0;
ax = MIN(cpuidmaxext, 0x80000008);
cx = 0;
break;
case 0x80000001: /* signature & ext features */
ax = cp->ax;
bx = 0;
cx = cp->cx & 0x121;
ax = cp.ax;
cx = cp.cx & 0x121;
if(sizeof(uintptr) == 8)
dx = cp->dx & 0x24100800;
dx = cp.dx & 0x24100800;
else
dx = cp->dx & 0x04100000;
dx = cp.dx & 0x04100000;
break;
case 0x80000002: goto literal; /* brand string */
case 0x80000003: goto literal; /* brand string */
@ -230,18 +287,16 @@ cpuid(ExitInfo *ei)
case 0x80000007: goto zero; /* invariant tsc */
case 0x80000008: goto literal; /* address bits */
literal:
ax = cp->ax;
bx = cp->bx;
cx = cp->cx;
dx = cp->dx;
ax = cp.ax;
bx = cp.bx;
cx = cp.cx;
dx = cp.dx;
break;
default:
vmerror("unknown cpuid field eax=%#ux", ax);
if((ax & 0xf0000000) != 0x40000000)
vmdebug("unknown cpuid field eax=%#ux", ax);
zero:
ax = 0;
bx = 0;
cx = 0;
dx = 0;
ax = cx = 0;
break;
}
rset(RAX, ax);
@ -267,12 +322,15 @@ rdwrmsr(ExitInfo *ei)
else rset("pat", val);
break;
case 0x8B: val = 0; break; /* microcode update */
case 0x1A0: /* IA32_MISC_ENABLE */
if(rd) val = msr.miscen;
break;
default:
if(rd){
vmerror("read from unknown MSR %#ux ignored", cx);
vmdebug("read from unknown MSR %#ux ignored", cx);
val = 0;
}else
vmerror("write to unknown MSR %#ux ignored (val=%#ullx)", cx, val);
vmdebug("write to unknown MSR %#ux ignored (val=%#ullx)", cx, val);
break;
}
if(rd){
@ -310,7 +368,7 @@ movcr(ExitInfo *ei)
case 0:
switch(q >> 4 & 3){
case 0:
vmdebug("illegal CR0 write, value %#ux", rget(x86reg[q >> 8 & 15]));
vmdebug("illegal CR0 write, value %#ux", (u32int)rget(x86reg[q >> 8 & 15]));
rset("cr0real", rget(x86reg[q >> 8 & 15]));
skipinstr(ei);
break;
@ -332,7 +390,7 @@ movcr(ExitInfo *ei)
case 4:
switch(q >> 4 & 3){
case 0:
vmdebug("illegal CR4 write, value %#ux", rget(x86reg[q >> 8 & 15]));
vmdebug("illegal CR4 write, value %#ux", (u32int)rget(x86reg[q >> 8 & 15]));
rset("cr4real", rget(x86reg[q >> 8 & 15]));
skipinstr(ei);
break;
@ -347,7 +405,7 @@ movcr(ExitInfo *ei)
}
break;
default:
vmerror("access to unknown control register CR%d", ei->qual & 15);
vmerror("access to unknown control register CR%ud", q & 15);
postexc("#ud", NOERRC);
}
}
@ -373,6 +431,26 @@ irqackhand(ExitInfo *ei)
irqack(ei->qual);
}
static void
xsetbv(ExitInfo *ei)
{
uvlong v;
/* this should also #ud if LOCK prefix is used */
v = rget(RAX)&0xffffffff | rget(RDX)<<32;
if(rget(RCX) & 0xffffffff)
postexc("#gp", 0);
else if(v != 1 && v != 3 && v != 7)
postexc("#gp", 0);
else if((leaf1.cx & 1<<26) == 0 || (rget("cr4real") & Cr4Osxsave) == 0)
postexc("#ud", NOERRC);
else{
rset("xcr0", v);
skipinstr(ei);
}
}
typedef struct ExitType ExitType;
struct ExitType {
char *name;
@ -389,6 +467,7 @@ static ExitType etypes[] = {
{".movdr", movdr},
{"#db", dbgexc},
{"movcr", movcr},
{".xsetbv", xsetbv},
};
void

View file

@ -1,3 +1,4 @@
#define MIN(a,b) ((a)<(b)?(a):(b))
void *emalloc(ulong);
void loadkernel(char *);
uvlong rget(char *);
@ -10,7 +11,8 @@ void pitadvance(void);
void rtcadvance(void);
void settimer(vlong targ);
void vmerror(char *, ...);
#define vmdebug vmerror
#pragma varargck argpos vmerror 1
#define vmdebug if(!debug) {} else vmerror
int ctl(char *, ...);
void registermmio(uvlong, uvlong, uvlong (*)(int, uvlong, uvlong));
void irqline(int, int);

View file

@ -118,7 +118,7 @@ idegoio(IDE *d, int wr)
addr = getlba(d);
if(addr < 0){
vmerror("ide%d: access to invalid sector address (access to CHS=(%#.4ux,%#ux,%#.2ux); geometry is (%#.4ux,%#ux,%#.2ux)", d-ide, d->cyl, d->head&0xf, d->sec, d->lcyl, d->lhead, d->lsec);
vmerror("ide%zd: access to invalid sector address (access to CHS=(%#.4ux,%#ux,%#.2ux); geometry is (%#.4ux,%#ux,%#.2ux)", d-ide, d->cyl, d->head&0xf, d->sec, d->lcyl, d->lhead, d->lsec);
postexc("#bp", NOERRC);
d->stat = IDEDRDY | IDEDSC | IDEDRQ | IDEERR;
d->err = IDEIDNF;
@ -325,7 +325,7 @@ ideioproc(void *dp)
qunlock(io);
werrstr("eof");
if(getsector(a+i, p) < 0 && pread(d->fd, p, 512, (a+i)*512) < 512){
vmerror("ide%d: read: %r", d - ide);
vmerror("ide%zd: read: %r", d - ide);
qlock(io);
io->err = IDEUNC;
qunlock(io);
@ -355,7 +355,7 @@ idecmd(IDE *d, u8int cmd)
break;
default:
if((d->flags & IDEPRESENT) == 0){
vmerror("ide%d: command %#ux issued to absent drive", d-ide, cmd);
vmerror("ide%zd: command %#ux issued to absent drive", d-ide, cmd);
return;
}
}
@ -435,7 +435,7 @@ idecmd(IDE *d, u8int cmd)
case 0x66: d->flags |= IDEKEEPFEAT; break; /* retain settings */
case 0xcc: d->flags &= ~IDEKEEPFEAT; break; /* revert to default on reset */
default:
vmerror("ide%d: unknown feature %#ux", d-ide, d->feat);
vmerror("ide%zd: unknown feature %#ux", d-ide, d->feat);
d->stat = IDEDRDY|IDEDSC|IDEERR;
d->err = IDEABRT;
return;
@ -443,7 +443,7 @@ idecmd(IDE *d, u8int cmd)
d->stat = IDEDRDY|IDEDSC;
break;
default:
vmerror("ide%d: unknown command %#ux", d-ide, cmd);
vmerror("ide%zd: unknown command %#ux", d-ide, cmd);
d->stat = IDEDRDY|IDEDSC|IDEERR;
d->err = IDEABRT;
}

View file

@ -292,7 +292,7 @@ picio(int isin, u16int port, u32int val, int sz, void *)
p->imr = 0;
p->prio = 7;
p->flags = 0;
if((val & 0x0b) != 0x01) vmerror("PIC%ld ICW1 with unsupported value %#ux", p-pic, val);
if((val & 0x0b) != 0x01) vmerror("PIC%zd ICW1 with unsupported value %#ux", p-pic, (u32int)val);
p->init = 1;
return 0;
}
@ -347,7 +347,7 @@ picio(int isin, u16int port, u32int val, int sz, void *)
case 0xa1:
switch(p->init){
default:
vmerror("write to PIC%ld in init=%d state", p-pic, p->init);
vmerror("write to PIC%zd in init=%d state", p-pic, p->init);
return 0;
case 1:
p->base = val;
@ -355,11 +355,11 @@ picio(int isin, u16int port, u32int val, int sz, void *)
return 0;
case 2:
if(p == &pic[0] && val != 4 || p == &pic[1] && val != 2)
vmerror("PIC%ld ICW3 with unsupported value %#ux", p-pic, val);
vmerror("PIC%zd ICW3 with unsupported value %#ux", p-pic, val);
p->init = 3;
return 0;
case 3:
if((val & 0xfd) != 1) vmerror("PIC%ld ICW4 with unsupported value %#ux", p-pic, val);
if((val & 0xfd) != 1) vmerror("PIC%zd ICW4 with unsupported value %#ux", p-pic, val);
if((val & 2) != 0) p->flags |= AEOI;
p->init = 4;
picupdate(p);
@ -726,7 +726,7 @@ kbdcmd(u8int val)
case 0xf2: keyputc(0xfa); keyputc(0xab); keyputc(0x41); break; /* keyboard id */
case 0xee: keyputc(0xee); break; /* echo */
default:
vmerror("unknown kbd command %#ux", val);
vmdebug("unknown kbd command %#ux", val);
keyputc(0xfe);
}
}
@ -1203,9 +1203,9 @@ u32int
iowhine(int isin, u16int port, u32int val, int sz, void *mod)
{
if(isin)
vmerror("%s%sread from unknown i/o port %#ux ignored (sz=%d, pc=%#ullx)", mod != nil ? mod : "", mod != nil ? ": " : "", port, sz, rget(RPC));
vmdebug("%s%sread from unknown i/o port %#ux ignored (sz=%d, pc=%#ullx)", mod != nil ? mod : "", mod != nil ? ": " : "", port, sz, rget(RPC));
else
vmerror("%s%swrite to unknown i/o port %#ux ignored (val=%#ux, sz=%d, pc=%#ullx)", mod != nil ? mod : "", mod != nil ? ": " : "", port, val, sz, rget(RPC));
vmdebug("%s%swrite to unknown i/o port %#ux ignored (val=%#ux, sz=%d, pc=%#ullx)", mod != nil ? mod : "", mod != nil ? ": " : "", port, val, sz, rget(RPC));
return -1;
}

View file

@ -2,6 +2,7 @@
BIN=/$objtype/bin
TARG=vmx
CLEANFILES=$O.vmxgdb
HFILES=dat.h fns.h
OFILES=\
vmx.$O \
@ -19,6 +20,10 @@ OFILES=\
</sys/src/cmd/mkone
default:V: all
all:V: $O.out $O.vmxgdb
install:V: $BIN/vmxgdb
$BIN/vmxgdb: $O.vmxgdb

View file

@ -17,14 +17,15 @@ nanosec(void)
return nsec() - xstart;
if(fasthz == 0){
if((fasthz = _tos->cyclefreq) == 0){
fasthz = ~0ULL;
if(_tos->cyclefreq){
cycles(&xstart);
fasthz = _tos->cyclefreq;
} else {
xstart = nsec();
fasthz = ~0ULL;
fprint(2, "cyclefreq not available, falling back to nsec()\n");
fprint(2, "you might want to disable aux/timesync\n");
return 0;
}else{
cycles(&xstart);
}
}
cycles(&x);

View file

@ -622,7 +622,8 @@ vesathread(void *)
if(vesaddc(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
break;
default:
vmerror("vesa: unsupported function %#x", ur.ax);
vesasetax(sp, 0x0100);
vmdebug("vesa: unsupported function %#x", ur.ax);
}
}
}

View file

@ -178,7 +178,7 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
switch(vga.sidx){
case 0: vga.seq[vga.sidx] = val & 3; return 0;
case 4: vga.seq[vga.sidx] = val & 0xe; return 0;
default: vmerror("vga: write to unknown sequencer register %#ux (val=%#ux)", vga.sidx, val); return 0;
default: vmdebug("vga: write to unknown sequencer register %#ux (val=%#ux)", vga.sidx, val); return 0;
}
case 0x3c6: return 0;
case 0x3c7: vga.rdidx = val << 2; return 0;
@ -194,7 +194,7 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
case 4: vga.graph[vga.gidx] = val & 3; break;
case 8: vga.graph[vga.gidx] = val; break;
default:
vmerror("vga: write to unknown graphics register %#ux (val=%#ux)", vga.gidx, val);
vmdebug("vga: write to unknown graphics register %#ux (val=%#ux)", vga.gidx, val);
}
return 0;
case 0x3d4: vga.cidx = val; return 0;
@ -204,7 +204,7 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
vga.crtc[vga.cidx] = val;
return 0;
default:
vmerror("vga: write to unknown CRTC register %#ux (val=%#ux)", vga.cidx, val);
vmdebug("vga: write to unknown CRTC register %#ux (val=%#ux)", vga.cidx, val);
}
return 0;
case 0x103c0: return vga.aidx & 0x3f;
@ -215,7 +215,7 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
case 0:
case 4:
return vga.seq[vga.sidx];
default: vmerror("vga: read from unknown sequencer register %#ux (val=%#ux)", vga.sidx, val); return 0;
default: vmdebug("vga: read from unknown sequencer register %#ux (val=%#ux)", vga.sidx, val); return 0;
}
case 0x103c6: return 0xff;
case 0x103c7: return vga.rdidx >> 2;
@ -232,7 +232,7 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
case 8:
return vga.graph[vga.gidx];
default:
vmerror("vga: read from unknown graphics register %#ux", vga.gidx);
vmdebug("vga: read from unknown graphics register %#ux", vga.gidx);
return 0;
}
case 0x103d4: return vga.cidx;
@ -241,7 +241,7 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
case 10: case 11: case 12: case 13: case 14: case 15:
return vga.crtc[vga.cidx];
default:
vmerror("vga: read from unknown CRTC register %#ux", vga.cidx);
vmdebug("vga: read from unknown CRTC register %#ux", vga.cidx);
return 0;
}
case 0x103ca:
@ -374,7 +374,7 @@ keyproc(void *)
nkdown[k->code >> 6] |= 1ULL<<(k->code&63);
break;
}
if(k == nil) vmerror("unknown key %d", r);
if(k == nil) vmdebug("unknown key %d", r);
}
if(mousegrab && (nkdown[0]>>29 & 1) != 0 && (nkdown[0]>>56 & 1) != 0){
mousegrab = 0;
@ -737,7 +737,7 @@ vgafbparse(char *fbstring)
void
vgainit(void)
vgainit(int new)
{
char buf[512];
int i;
@ -760,7 +760,7 @@ vgainit(void)
sysfatal("got nil ptr for framebuffer");
}
snprint(buf, sizeof(buf), "-dx %d -dy %d", maxw+50, maxh+50);
if(newwindow(buf) < 0 || initdraw(nil, nil, "vmx") < 0)
if((new && newwindow(buf) < 0) || initdraw(nil, nil, "vmx") < 0)
sysfatal("failed to initialize graphics: %r");
screeninit(1);
flushimage(display, 1);

View file

@ -11,7 +11,7 @@ Region *mmap;
int ctlfd, regsfd, mapfd, waitfd;
Channel *waitch, *sleepch, *notifch;
enum { MSEC = 1000*1000, MinSleep = MSEC, SleeperPoll = 2000*MSEC } ;
int getexit, state;
int getexit, state, debug;
typedef struct VmxNotif VmxNotif;
struct VmxNotif {
void (*f)(void *);
@ -320,9 +320,6 @@ gend(void *v)
return (u8int *) v + gavail(v);
}
void *tmp, *vgamem;
uvlong tmpoff, vgamemoff;
static void
mksegment(char *sn)
{
@ -355,8 +352,9 @@ mksegment(char *sn)
close(fd);
gmem = segattach(0, sn, nil, sz);
if(gmem == (void*)-1) sysfatal("segattach: %r");
}else{
memset(gmem, 0, sz > 1<<24 ? 1<<24 : sz);
}
memset(gmem, 0, sz > 1<<24 ? 1<<24 : sz);
p = gmem;
for(r = mmap; r != nil; r = r->next){
if(r->segname == nil) continue;
@ -365,14 +363,12 @@ mksegment(char *sn)
p += r->end - r->start;
r->ve = p;
}
vgamem = p;
vgamemoff = p - gmem;
regptr(0xa0000)->segoff = vgamemoff;
regptr(0xa0000)->v = vgamem;
/* vga */
r = regptr(0xa0000);
r->segoff = p - gmem;
r->v = p;
p += 256*1024;
regptr(0xa0000)->ve = p;
tmp = p;
tmpoff = p - gmem;
r->ve = p;
for(r = mmap; r != nil; r = r->next)
modregion(r);
@ -504,7 +500,7 @@ sendnotif(void (*f)(void *), void *arg)
send(notifch, &notif);
}
extern void vgainit(void);
extern void vgainit(int);
extern void pciinit(void);
extern void pcibusmap(void);
extern void cpuidinit(void);
@ -574,7 +570,7 @@ usage(void)
for(p = blanks; *p != 0; p++)
*p = ' ';
fprint(2, "usage: %s [ -M mem ] [ -c com1rd[,com1wr] ] [ -C com2rd[,com2r] ] [ -n nic ]\n", argv0);
fprint(2, " %s [ -d blockfile ] [ -m module ] [ -v vga ] [ -9 srv ] kernel [ args ... ]\n", blanks);
fprint(2, " %s [ -d blockfile ] [ -m module ] [ -v|-w vga ] [ -9 srv ] kernel [ args ... ]\n", blanks);
threadexitsall("usage");
}
@ -590,6 +586,7 @@ threadmain(int argc, char **argv)
static uvlong gmemsz = 64*1024*1024;
static char *srvname;
extern uintptr fbsz, fbaddr;
int newwin = 0;
int i;
quotefmtinstall();
@ -598,7 +595,7 @@ threadmain(int argc, char **argv)
waitch = chancreate(sizeof(char *), 32);
sleepch = chancreate(sizeof(ulong), 32);
notifch = chancreate(sizeof(VmxNotif), 16);
ARGBEGIN {
case 'm':
bootmod = realloc(bootmod, (bootmodn + 1) * sizeof(char *));
@ -633,10 +630,15 @@ threadmain(int argc, char **argv)
}
edevn++;
break;
case 'D':
debug++;
break;
case 'M':
gmemsz = siparse(EARGF(usage()));
if(gmemsz != (uintptr) gmemsz) sysfatal("too much memory for address space");
break;
case 'w':
newwin = 1;
case 'v':
vgafbparse(EARGF(usage()));
break;
@ -673,7 +675,7 @@ threadmain(int argc, char **argv)
loadkernel(argv[0]);
pciinit();
vgainit();
vgainit(newwin);
for(i = 0; i < edevn; i++)
if(edev[i](edevaux[i]) < 0)
sysfatal("%s: %r", edevt[i]);

View file

@ -22,8 +22,9 @@ enum {
enum {
Cr0Pg = 1<<31,
Cr4Pse = 1<<4,
Cr4Pae = 1<<5,
Cr4Pse = 1<<4,
Cr4Pae = 1<<5,
Cr4Osxsave = 1<<18,
EferLme = 1<<8,
};

View file

@ -25,7 +25,7 @@ auth9p(Req *r)
Afid *afid;
afid = emalloc9p(sizeof(Afid));
afid->afd = open("/mnt/factotum/rpc", ORDWR);
afid->afd = open("/mnt/factotum/rpc", ORDWR|OCEXEC);
if(afid->afd < 0)
goto error;

View file

@ -100,7 +100,7 @@ getremotesys(char *ndir)
snprint(buf, sizeof buf, "%s/remote", ndir);
sys = nil;
fd = open(buf, OREAD);
fd = open(buf, OREAD|OCEXEC);
if(fd >= 0){
n = read(fd, buf, sizeof(buf)-1);
if(n>0){

View file

@ -16,8 +16,8 @@ _reqqueueproc(void *v)
q = v;
rfork(RFNOTEG);
buf = smprint("/proc/%d/ctl", getpid());
fd = open(buf, OWRITE);
buf = smprint("/proc/%lud/ctl", (ulong)getpid());
fd = open(buf, OWRITE|OCEXEC);
free(buf);
for(;;){
@ -40,6 +40,8 @@ _reqqueueproc(void *v)
f(r);
}
if(fd >= 0)
close(fd);
free(r);
free(q);
threadexits(nil);

View file

@ -23,7 +23,7 @@ auth_challenge(char *fmt, ...)
return nil;
}
if((c->afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
if((c->afd = open("/mnt/factotum/rpc", ORDWR|OCEXEC)) < 0){
Error:
auth_freechal(c);
free(p);

View file

@ -16,7 +16,7 @@ auth_chuid(AuthInfo *ai, char *ns)
}
/* change uid */
fd = open("#¤/capuse", OWRITE);
fd = open("#¤/capuse", OWRITE|OCEXEC);
if(fd < 0){
werrstr("opening #¤/capuse: %r");
return -1;
@ -31,8 +31,8 @@ auth_chuid(AuthInfo *ai, char *ns)
/* get a link to factotum as new user */
fd = open("/srv/factotum", ORDWR);
if(fd >= 0){
mount(fd, -1, "/mnt", MREPL, "");
close(fd);
if(mount(fd, -1, "/mnt", MREPL, "") == -1)
close(fd);
}
/* set up new namespace */

View file

@ -32,12 +32,11 @@ auth_getuserpasswd(AuthGetkey *getkey, char *fmt, ...)
UserPasswd *up;
up = nil;
rpc = nil;
params = nil;
fd = open("/mnt/factotum/rpc", ORDWR);
fd = open("/mnt/factotum/rpc", ORDWR|OCEXEC);
if(fd < 0)
goto out;
return nil;
rpc = auth_allocrpc(fd);
if(rpc == nil)
goto out;
@ -69,7 +68,7 @@ auth_getuserpasswd(AuthGetkey *getkey, char *fmt, ...)
out:
free(params);
auth_freerpc(rpc);
close(fd);
auth_freerpc(rpc);
return up;
}

View file

@ -200,7 +200,7 @@ auth_proxy(int fd, AuthGetkey *getkey, char *fmt, ...)
va_end(arg);
ai = nil;
afd = open("/mnt/factotum/rpc", ORDWR);
afd = open("/mnt/factotum/rpc", ORDWR|OCEXEC);
if(afd < 0){
werrstr("opening /mnt/factotum/rpc: %r");
free(p);

View file

@ -31,7 +31,7 @@ dorespond(void *chal, uint nchal, char *user, uint nuser, void *resp, uint nresp
AuthRpc *rpc;
Attr *a;
if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
if((afd = open("/mnt/factotum/rpc", ORDWR|OCEXEC)) < 0)
return -1;
if((rpc = auth_allocrpc(afd)) == nil){

View file

@ -11,7 +11,7 @@ auth_userpasswd(char *user, char *passwd)
char *s;
int afd;
afd = open("/mnt/factotum/rpc", ORDWR);
afd = open("/mnt/factotum/rpc", ORDWR|OCEXEC);
if(afd < 0)
return nil;
ai = nil;

View file

@ -41,7 +41,7 @@ buildns(int newns, char *user, char *file)
rpc = nil;
/* try for factotum now because later is impossible */
afd = open("/mnt/factotum/rpc", ORDWR);
afd = open("/mnt/factotum/rpc", ORDWR|OCEXEC);
if(afd < 0 && newnsdebug)
fprint(2, "open /mnt/factotum/rpc: %r\n");
if(afd >= 0){
@ -58,8 +58,8 @@ buildns(int newns, char *user, char *file)
}
file = "/lib/namespace";
}
b = Bopen(file, OREAD);
if(b == 0){
b = Bopen(file, OREAD|OCEXEC);
if(b == nil){
werrstr("can't open %s: %r", file);
return freecloserpc(rpc);
}
@ -135,6 +135,8 @@ famount(int fd, AuthRpc *rpc, char *mntpt, int flags, char *aname)
auth_freeAI(ai);
}
ret = mount(fd, afd, mntpt, flags, aname);
if(ret == -1)
close(fd);
if(afd >= 0)
close(afd);
return ret;
@ -151,7 +153,7 @@ nsop(char *fn, int argc, char *argv[], AuthRpc *rpc)
cdroot = 0;
flags = 0;
argv0 = 0;
argv0 = nil;
if(newnsdebug){
for (i = 0; i < argc; i++)
fprint(2, "%s ", argv[i]);
@ -176,7 +178,7 @@ nsop(char *fn, int argc, char *argv[], AuthRpc *rpc)
flags |= MREPL;
if(strcmp(argv0, ".") == 0 && argc == 1){
b = Bopen(argv[0], OREAD);
b = Bopen(argv[0], OREAD|OCEXEC);
if(b == nil)
return 0;
cdroot |= nsfile(fn, b, rpc);
@ -204,8 +206,9 @@ nsop(char *fn, int argc, char *argv[], AuthRpc *rpc)
}else if(argc == 3){
if(famount(fd, rpc, argv[1], flags, argv[2]) == -1 && newnsdebug)
fprint(2, "%s: mount: %s %s %s: %r\n", fn, argv[0], argv[1], argv[2]);
} else {
close(fd);
}
close(fd);
}else if(strcmp(argv0, "cd") == 0 && argc == 1){
if(chdir(argv[0]) == 0 && *argv[0] == '/')
cdroot = 1;
@ -316,7 +319,7 @@ expandarg(char *arg, char *buf)
strcpy(env, "#e/");
strncpy(env+3, p, len);
env[3+len] = '\0';
fd = open(env, OREAD);
fd = open(env, OREAD|OCEXEC);
if(fd >= 0){
len = read(fd, &buf[n], ANAMELEN - 1);
/* some singleton environment variables have trailing NULs */
@ -345,7 +348,7 @@ setenv(char *name, char *val)
long s;
sprint(ename, "#e/%s", name);
f = create(ename, OWRITE, 0664);
f = create(ename, OWRITE|OCEXEC, 0664);
if(f < 0)
return -1;
s = strlen(val);

Some files were not shown because too many files have changed in this diff Show more