merge
This commit is contained in:
commit
3749e92cdb
136 changed files with 2715 additions and 2234 deletions
|
@ -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
|
||||
|
|
|
@ -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'*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 'Æ
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
146
sys/man/4/oexportfs
Normal 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)
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
[
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -250,7 +250,7 @@ struct Mach
|
|||
int pdbfree;
|
||||
|
||||
u32int dr7; /* shadow copy of dr7 */
|
||||
|
||||
u32int xcr0;
|
||||
void* vmx;
|
||||
|
||||
int stack[1];
|
||||
|
|
|
@ -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, ®s[1], BY2WD); /* bx */
|
||||
memmove(m->cpuidid+4, ®s[3], BY2WD); /* dx */
|
||||
memmove(m->cpuidid+8, ®s[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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
309
sys/src/9/pc/fpu.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -49,6 +49,7 @@ PORT=\
|
|||
OBJ=\
|
||||
l.$O\
|
||||
cga.$O\
|
||||
fpu.$O\
|
||||
i8253.$O\
|
||||
i8259.$O\
|
||||
main.$O\
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
374
sys/src/9/pc64/fpu.c
Normal 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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ PORT=\
|
|||
OBJ=\
|
||||
l.$O\
|
||||
cga.$O\
|
||||
fpu.$O\
|
||||
i8253.$O\
|
||||
i8259.$O\
|
||||
main.$O\
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -68,6 +68,7 @@ OBJ=\
|
|||
plan9l.$O\
|
||||
xen.$O\
|
||||
main.$O\
|
||||
fpu.$O\
|
||||
mmu.$O\
|
||||
random.$O\
|
||||
rdb.$O\
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
503
sys/src/cmd/exportfs/io.c
Normal 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;
|
||||
}
|
|
@ -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
|
||||
|
|
443
sys/src/cmd/exportfs/oexportfs.c
Normal file
443
sys/src/cmd/exportfs/oexportfs.c
Normal 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();
|
||||
}
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ enum {
|
|||
VMDEAD,
|
||||
};
|
||||
extern int state;
|
||||
extern int debug;
|
||||
|
||||
enum {
|
||||
BY2PG = 4096
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, ¬if);
|
||||
}
|
||||
|
||||
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]);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue