mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
Merge.
This commit is contained in:
commit
b37f6a2f57
119 files changed
+5644
-4525
No files matched your search
@@ -35,3 +35,11 @@ CFLAGS += $(foreach i, $(EXTRA_INCLUDES), -I$(i))
|
||||
|
||||
# Choose the best mirror to download linux kernel
|
||||
KERNEL_REPO = http://www.kernel.org
|
||||
|
||||
# ACM_USE_SECURITY_POLICY is set to security policy of Xen
|
||||
# Supported models are:
|
||||
# ACM_NULL_POLICY (ACM will not be built with this policy)
|
||||
# ACM_CHINESE_WALL_POLICY
|
||||
# ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY
|
||||
# ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY
|
||||
ACM_USE_SECURITY_POLICY ?= ACM_NULL_POLICY
|
||||
@@ -1,588 +0,0 @@
|
||||
Copyright: IBM Corporation (C)
|
||||
20 June 2005
|
||||
Author: Reiner Sailer
|
||||
|
||||
This document is a very short introduction into the sHype access control
|
||||
security architecture implementation and how it is perceived by users. It
|
||||
is a very preliminary draft for the courageous ones to get "their feet wet"
|
||||
and to be able to give feedback (via the xen-devel/xense-devel mailing lists).
|
||||
|
||||
Install:
|
||||
|
||||
cd into xeno-unstable.bk
|
||||
(use --dry-run option if you want to test the patch only)
|
||||
patch -p1 -g0 < *tools.diff
|
||||
patch -p1 -g0 < *xen.diff
|
||||
|
||||
(no rejects, probably some line offsets)
|
||||
|
||||
make uninstall; make mrproper; make; ./install.sh should install the default
|
||||
sHype into Xen (rebuild your initrd images if necessary). Reboot.
|
||||
|
||||
Debug output: there are two triggers for debug output:
|
||||
a) General sHype debug:
|
||||
xeno-unstable.bk/xen/include/public/acm.h
|
||||
undefine ACM_DEBUG to switch this debug off
|
||||
|
||||
b) sHype enforcement hook trace: This prints a small trace for each enforcement
|
||||
hook that is executed. The trigger is in
|
||||
xeno-unstable.bk/xen/include/acm/acm_hooks.h
|
||||
undefine ACM_TRACE_MODE to switch this debug off
|
||||
|
||||
1. The default NULL policy
|
||||
***************************
|
||||
When you apply the patches and startup xen, you should at first not notice any
|
||||
difference because the default policy is the "NULL" policy, which as the name
|
||||
implies does not enforce anything.
|
||||
|
||||
To display the currently enforced policy, use the policy tool under xeno-
|
||||
unstable.bk/tools/policy: policy_tool getpolicy. You should see output like the
|
||||
one below.
|
||||
|
||||
[root@laptop policy]#./policy_tool getpolicy
|
||||
|
||||
Policy dump:
|
||||
============
|
||||
Magic = 1debc.
|
||||
PolVer = aaaa0000.
|
||||
Len = 14.
|
||||
Primary = NULL policy (c=0, off=14).
|
||||
Secondary = NULL policy (c=0, off=14).
|
||||
No primary policy (NULL).
|
||||
No secondary policy (NULL).
|
||||
|
||||
Policy dump End.
|
||||
|
||||
Since this is a dump of a binary policy, it's not pretty. The important parts
|
||||
are the "Primary" and "Secondary" policy fields set to "NULL policy". sHype
|
||||
currently allows to set two independent policies; thus the two SSID-REF parts
|
||||
shown in 'xm list'. Right here: primary policy only means this policy is
|
||||
checked first, the secondary policy is checked if the primary results in
|
||||
"permitted access". The result of the combined policy is "permitted" if both
|
||||
policies return permitted (NULL policy always returns permitted). The result is
|
||||
"denied" if at least one of the policies returns "denied". Look into xeno-
|
||||
unstable.bk/xen/include/acm/acm_hooks.h for the general hook structure
|
||||
integrating the policy decisions (if you like, you won't need it for the rest
|
||||
of the Readme file).
|
||||
|
||||
2. Setting Chinese Wall and Simple Type Enforcement policies:
|
||||
*************************************************************
|
||||
|
||||
We'll get fast to the point. However, in order to understand what we are doing,
|
||||
we must at least understand the purpose of the policies that we are going to
|
||||
enforce. The two policies presented here are just examples and the
|
||||
implementation encourages adding new policies easily.
|
||||
|
||||
2.1. Chinese Wall policy: "decides whether a domain can be started based on
|
||||
this domain's ssidref and the ssidrefs of the currently running domains".
|
||||
Generally, the Chinese wall policy allows specifying certain types (or classes
|
||||
or categories, whatever the preferred word) that conflict; we usually assign a
|
||||
type to a workload and the set of types of those workloads running in a domain
|
||||
make up the type set for this domain. Each domain is assigned a set of types
|
||||
through its SSID-REF (we register Chinese Wall as primary policy, so the
|
||||
ssidref used for determining the Chinese Wall types is the one annotated with
|
||||
"p:" in xm list) since each SSID-REF points at a set of types. We'll see how
|
||||
SSIDREFs are represented in Xen later when we will look at the policy. (A good
|
||||
read for Chinese Wall is: Brewer/Nash The Chinese Wall Security Policy 1989.)
|
||||
|
||||
So let's assume the Chinese Wall policy we are running distinguishes 10 types:
|
||||
t0 ... t9. Let us assume further that each SSID-REF points to a set that
|
||||
includes exactly one type (attached to domains that run workloads of a single
|
||||
type). SSID-REF 0 points to {t0}, ssidref 1 points to {t1} ... 9 points to
|
||||
{t9}. [This is actually the example policy we are going to push into xen later]
|
||||
|
||||
Now the Chinese Wall policy allows you to define "Conflict type sets" and it
|
||||
guarantees that of any conflict set at most one type is "running" at any time.
|
||||
As an example, we have defined 2 conflict set: {t2, t3} and {t0, t5, t6}.
|
||||
Specifying these conflict sets, sHype ensures that at most one type of each set
|
||||
is running (either t2 or t3 but not both; either t0 or t5 or t6 but not
|
||||
multiple of them).
|
||||
|
||||
The effect is that administrators can define which workload types cannot run
|
||||
simultaneously on a single Xen system. This is useful to limit the covert
|
||||
timing channels between such payloads or to ensure that payloads don't
|
||||
interfere with each other through existing resource dependencies.
|
||||
|
||||
2.2. Simple Type Enforcement (ste) policy: "decides whether two domains can
|
||||
share data, e.g., setup event channels or grant tables to each other, based on
|
||||
the two domains' ssidref. This, as the name says, is a simple policy. Think of
|
||||
each type as of a single color. Each domain has one or more colors, i.e., the
|
||||
domains ssid for the ste policy points to a set that has set one or multiple
|
||||
types. Let us assume in our example policy we differentiate 5 colors (types)
|
||||
and define 5 different ssids referenced by ssidref=0..4. Each ssid shall have
|
||||
exactly one type set, i.e., describes a uni-color. Only ssid(0) has all types
|
||||
set, i.e., has all defined colors.
|
||||
|
||||
Sharing is enforced by the ste policy by requiring that two domains that want
|
||||
to establish an event channel or grant pages to each other must have a common
|
||||
color. Currently all domains communicate through DOM0 by default; i.e., Domain0
|
||||
will necessarily have all colors to be able to create domains (thus, we will
|
||||
assign ssidref(0) to Domain0 in our example below.
|
||||
|
||||
More complex mandatory access control policies governing sharing will follow;
|
||||
such policies are more sophisticated than the "color" scheme above by allowing
|
||||
more flexible (and complex :_) access control decisions than "share a color" or
|
||||
"don't share a color" and will be able to express finer-grained policies.
|
||||
|
||||
|
||||
2.3 Binary Policy:
|
||||
In the future, we will have a policy tool that takes as input a more humane
|
||||
policy description, using types such as development, home-banking, donated-
|
||||
Grid, CorpA-Payload ... and translates the respective policy into what we see
|
||||
today as the binary policy using 1s and 0s and sets of them. For now, we must
|
||||
live with the binary policy when working with sHype.
|
||||
|
||||
|
||||
2.4 Exemplary use of a real sHype policy on Xen. To activate a real policy,
|
||||
edit the file (yes, this will soon be a compile option):
|
||||
xeno-unstable.bk/xen/include/public/acm.h
|
||||
Change: #define ACM_USE_SECURITY_POLICY ACM_NULL_POLICY
|
||||
To : #define ACM_USE_SECURITY_POLICY ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY
|
||||
cd xeno-unstable.bk
|
||||
make mrproper
|
||||
make uninstall (manually remove /etc/xen.old if necessary)
|
||||
make
|
||||
./install.sh (recreate your kernel initrd's if necessary)
|
||||
Reboot into new xen.gz
|
||||
|
||||
After booting, check out 'xm dmesg'; should show somewhere in the middle:
|
||||
|
||||
(XEN) acm_init: Enforcing Primary CHINESE WALL policy, Secondary SIMPLE TYPE
|
||||
ENFORCEMENT policy.
|
||||
|
||||
Even though you can activate those policies in any combination and also
|
||||
independently, the policy tool currently only supports setting the policy for
|
||||
the above combination.
|
||||
|
||||
Now look at the minimal startup policy with:
|
||||
xeno-unstable.bk/tools/policytool getpolicy
|
||||
|
||||
You should see something like:
|
||||
|
||||
[root@laptop policy]# ./policy_tool getpolicy
|
||||
|
||||
Policy dump:
|
||||
============
|
||||
Magic = 1debc.
|
||||
PolVer = aaaa0000.
|
||||
Len = 36.
|
||||
Primary = CHINESE WALL policy (c=1, off=14).
|
||||
Secondary = SIMPLE TYPE ENFORCEMENT policy (c=2, off=2c).
|
||||
|
||||
|
||||
Chinese Wall policy:
|
||||
====================
|
||||
Max Types = 1.
|
||||
Max Ssidrefs = 1.
|
||||
Max ConfSets = 1.
|
||||
Ssidrefs Off = 10.
|
||||
Conflicts Off = 12.
|
||||
Runing T. Off = 14.
|
||||
C. Agg. Off = 16.
|
||||
|
||||
SSID To CHWALL-Type matrix:
|
||||
|
||||
ssidref 0: 00
|
||||
|
||||
Confict Sets:
|
||||
|
||||
c-set 0: 00
|
||||
|
||||
Running
|
||||
Types: 00
|
||||
|
||||
Conflict
|
||||
Aggregate Set: 00
|
||||
|
||||
|
||||
Simple Type Enforcement policy:
|
||||
===============================
|
||||
Max Types = 1.
|
||||
Max Ssidrefs = 1.
|
||||
Ssidrefs Off = 8.
|
||||
|
||||
SSID To STE-Type matrix:
|
||||
|
||||
ssidref 0: 01
|
||||
|
||||
|
||||
Policy dump End.
|
||||
|
||||
This is a minimal policy (of little use), except it will disable starting any
|
||||
domain that does not have ssidref set to 0x0. The Chinese Wall policy has
|
||||
nothing to enforce and the ste policy only knows one type, which is set for the
|
||||
only defined ssidref.
|
||||
|
||||
The item that defines the ssidref in a domain configuration is:
|
||||
|
||||
ssidref = 0x12345678
|
||||
|
||||
Where ssidref is interpreted as a 32bit number, where the lower 16bits become
|
||||
the ssidref for the primary policy and the higher 16bits become the ssidref for
|
||||
the secondary policy. sHype currently supports two policies but this is an
|
||||
implementation decision and can be extended if necessary.
|
||||
|
||||
This reference defines the security information of a domain. The meaning of the
|
||||
SSID-REF depends on the policy, so we explain it when we explain the real
|
||||
policies.
|
||||
|
||||
|
||||
Setting a new Security Policy:
|
||||
******************************
|
||||
The policy tool with all its current limitations has one usable example policy
|
||||
compiled-in. Please try at this time to use the setpolicy command:
|
||||
xeno-unstable.bk/tools/policy/policy_tool setpolicy
|
||||
|
||||
You should see a dump of the policy you are setting. It should say at the very
|
||||
end:
|
||||
|
||||
Policy successfully set.
|
||||
|
||||
Now try to dump the currently enforced policy, which is the policy we have just
|
||||
set and the dynamic security state information of this policy
|
||||
(<<< ... some additional explanations)
|
||||
|
||||
[root@laptop policy]# ./policy_tool getpolicy
|
||||
|
||||
Policy dump:
|
||||
============
|
||||
Magic = 1debc.
|
||||
PolVer = aaaa0000.
|
||||
Len = 112.
|
||||
Primary = CHINESE WALL policy (c=1, off=14).
|
||||
Secondary = SIMPLE TYPE ENFORCEMENT policy (c=2, off=d8).
|
||||
|
||||
|
||||
Chinese Wall policy:
|
||||
====================
|
||||
Max Types = a.
|
||||
Max Ssidrefs = 5.
|
||||
Max ConfSets = 2.
|
||||
Ssidrefs Off = 10.
|
||||
Conflicts Off = 74.
|
||||
Runing T. Off = 9c.
|
||||
C. Agg. Off = b0.
|
||||
|
||||
SSID To CHWALL-Type matrix:
|
||||
|
||||
ssidref 0: 01 00 00 00 00 00 00 00 00 00 <<< type0 is set for ssidref0
|
||||
ssidref 1: 00 01 00 00 00 00 00 00 00 00
|
||||
ssidref 2: 00 00 01 00 00 00 00 00 00 00
|
||||
ssidref 3: 00 00 00 01 00 00 00 00 00 00
|
||||
ssidref 4: 00 00 00 00 01 00 00 00 00 00 <<< type4 is set for ssidref4
|
||||
<<< types 5-9 are unused
|
||||
Confict Sets:
|
||||
|
||||
c-set 0: 00 00 01 01 00 00 00 00 00 00 <<< type2 and type3 never run together
|
||||
c-set 1: 01 00 00 00 00 01 01 00 00 00 <<< only one of types 0, 5 or 6
|
||||
<<< can run simultaneously
|
||||
Running
|
||||
Types: 01 00 00 00 00 00 00 00 00 00 <<< ref-count for types of running domains
|
||||
|
||||
Conflict
|
||||
Aggregate Set: 00 00 00 00 00 01 01 00 00 00 <<< aggregated set of types that
|
||||
<<< cannot run because they
|
||||
<<< are in conflict set 1 and
|
||||
<<< (domain 0 is running w t0)
|
||||
|
||||
|
||||
Simple Type Enforcement policy:
|
||||
===============================
|
||||
Max Types = 5.
|
||||
Max Ssidrefs = 5.
|
||||
Ssidrefs Off = 8.
|
||||
|
||||
SSID To STE-Type matrix:
|
||||
|
||||
ssidref 0: 01 01 01 01 01 <<< ssidref0 points to a set that
|
||||
<<< has all types set (colors)
|
||||
ssidref 1: 00 01 00 00 00 <<< ssidref1 has color1 set
|
||||
ssidref 2: 00 00 01 00 00 <<< ...
|
||||
ssidref 3: 00 00 00 01 00
|
||||
ssidref 4: 00 00 00 00 01
|
||||
|
||||
|
||||
Policy dump End.
|
||||
|
||||
|
||||
This is a small example policy with which we will demonstrate the enforcement.
|
||||
|
||||
Starting Domains with policy enforcement
|
||||
========================================
|
||||
Now let us play with this policy.
|
||||
|
||||
Define 3 or 4 domain configurations. I use the following config using a ramdisk
|
||||
only and about 8MBytes of memory for each DomU (test purposes):
|
||||
|
||||
#-------configuration xmsec1-------------------------
|
||||
kernel = "/boot/vmlinuz-2.6.11-xenU"
|
||||
ramdisk="/boot/U1_ramdisk.img"
|
||||
#security reference identifier
|
||||
ssidref= 0x00010001
|
||||
memory = 10
|
||||
name = "xmsec1"
|
||||
cpu = -1 # leave to Xen to pick
|
||||
# Number of network interfaces. Default is 1.
|
||||
nics=1
|
||||
dhcp="dhcp"
|
||||
#-----------------------------------------------------
|
||||
|
||||
xmsec2 and xmsec3 look the same except for the name and the ssidref line. Use
|
||||
your domain config file and add "ssidref = 0x00010001" to the first (xmsec1),
|
||||
"ssidref= 0x00020002" to the second (call it xmsec2), and "ssidref=0x00030003"
|
||||
to the third (we will call this one xmsec3).
|
||||
|
||||
First start xmsec1: xm create -c xmsec1 (succeeds)
|
||||
|
||||
Then
|
||||
[root@laptop policy]# xm list
|
||||
Name Id Mem(MB) CPU State Time(s) Console
|
||||
Domain-0 0 620 0 r---- 42.3 s:00/p:00
|
||||
xmnosec 1 9 0 -b--- 0.3 9601 s:00/p:05
|
||||
xmsec1 2 9 0 -b--- 0.2 9602 s:01/p:01
|
||||
|
||||
Shows a new domain xmsec1 running with primary (here: chinese wall) ssidref 1
|
||||
and secondary (here: simple type enforcement) ssidref 1. The ssidrefs are
|
||||
independent and can differ for a domain.
|
||||
|
||||
[root@laptop policy]# ./policy_tool getpolicy
|
||||
|
||||
Policy dump:
|
||||
============
|
||||
Magic = 1debc.
|
||||
PolVer = aaaa0000.
|
||||
Len = 112.
|
||||
Primary = CHINESE WALL policy (c=1, off=14).
|
||||
Secondary = SIMPLE TYPE ENFORCEMENT policy (c=2, off=d8).
|
||||
|
||||
|
||||
Chinese Wall policy:
|
||||
====================
|
||||
Max Types = a.
|
||||
Max Ssidrefs = 5.
|
||||
Max ConfSets = 2.
|
||||
Ssidrefs Off = 10.
|
||||
Conflicts Off = 74.
|
||||
Runing T. Off = 9c.
|
||||
C. Agg. Off = b0.
|
||||
|
||||
SSID To CHWALL-Type matrix:
|
||||
|
||||
ssidref 0: 01 00 00 00 00 00 00 00 00 00
|
||||
ssidref 1: 00 01 00 00 00 00 00 00 00 00
|
||||
ssidref 2: 00 00 01 00 00 00 00 00 00 00
|
||||
ssidref 3: 00 00 00 01 00 00 00 00 00 00
|
||||
ssidref 4: 00 00 00 00 01 00 00 00 00 00
|
||||
|
||||
Confict Sets:
|
||||
|
||||
c-set 0: 00 00 01 01 00 00 00 00 00 00
|
||||
c-set 1: 01 00 00 00 00 01 01 00 00 00 <<< t1 is not part of any c-set
|
||||
|
||||
Running
|
||||
Types: 01 01 00 00 00 00 00 00 00 00 <<< xmsec1 has ssidref 1->type1
|
||||
^^ <<< ref-count at position 1 incr
|
||||
Conflict
|
||||
Aggregate Set: 00 00 00 00 00 01 01 00 00 00 <<< domain 1 was allowed to
|
||||
<<< start since type 1 was not
|
||||
<<< in conflict with running
|
||||
<<< types
|
||||
|
||||
Simple Type Enforcement policy:
|
||||
===============================
|
||||
Max Types = 5.
|
||||
Max Ssidrefs = 5.
|
||||
Ssidrefs Off = 8.
|
||||
|
||||
SSID To STE-Type matrix:
|
||||
|
||||
ssidref 0: 01 01 01 01 01 <<< the ste policy does not maintain; we
|
||||
ssidref 1: 00 01 00 00 00 <-- <<< see that domain xmsec1 has ste
|
||||
ssidref 2: 00 00 01 00 00 <<< ssidref1->type1 and has this type in
|
||||
ssidref 3: 00 00 00 01 00 <<< common with dom0
|
||||
ssidref 4: 00 00 00 00 01
|
||||
|
||||
|
||||
Policy dump End.
|
||||
|
||||
Look at sHype output in xen dmesg:
|
||||
|
||||
[root@laptop xen]# xm dmesg
|
||||
.
|
||||
.
|
||||
[somewhere near the very end]
|
||||
(XEN) chwall_init_domain_ssid: determined chwall_ssidref to 1.
|
||||
(XEN) ste_init_domain_ssid.
|
||||
(XEN) ste_init_domain_ssid: determined ste_ssidref to 1.
|
||||
(XEN) acm_init_domain_ssid: Instantiated individual ssid for domain 0x01.
|
||||
(XEN) chwall_post_domain_create.
|
||||
(XEN) ste_pre_eventchannel_interdomain.
|
||||
(XEN) ste_pre_eventchannel_interdomain: (evtchn 0 --> 1) common type #01.
|
||||
(XEN) shype_authorize_domops.
|
||||
(XEN) ste_pre_eventchannel_interdomain.
|
||||
(XEN) ste_pre_eventchannel_interdomain: (evtchn 0 --> 1) common type #01.
|
||||
(XEN) ste_pre_eventchannel_interdomain.
|
||||
(XEN) ste_pre_eventchannel_interdomain: (evtchn 0 --> 1) common type #01.
|
||||
|
||||
|
||||
You can see that the chinese wall policy does not complain and that the ste
|
||||
policy makes three access control decisions for three event-channels setup
|
||||
between domain 0 and the new domain 1. Each time, the two domains share the
|
||||
type1 and setting up the eventchannel is permitted.
|
||||
|
||||
|
||||
Starting up a second domain xmsec2:
|
||||
|
||||
[root@laptop xen]# xm create -c xmsec2
|
||||
Using config file "xmsec2".
|
||||
Started domain xmsec2, console on port 9602
|
||||
************ REMOTE CONSOLE: CTRL-] TO QUIT ********
|
||||
Linux version 2.6.11-xenU (root@laptop.home.org) (gcc version 3.4.2 20041017
|
||||
(Red Hat 3.4.2-6.fc3)) #1 Wed Mar 30 13:14:31 EST 2005
|
||||
.
|
||||
.
|
||||
.
|
||||
[root@laptop policy]# xm list
|
||||
Name Id Mem(MB) CPU State Time(s) Console
|
||||
Domain-0 0 620 0 r---- 71.7 s:00/p:00
|
||||
xmsec1 1 9 0 -b--- 0.3 9601 s:01/p:01
|
||||
xmsec2 2 7 0 -b--- 0.3 9602 s:02/p:02 << our domain runs both policies with ssidref 2
|
||||
|
||||
|
||||
[root@laptop policy]# ./policy_tool getpolicy
|
||||
|
||||
Policy dump:
|
||||
============
|
||||
Magic = 1debc.
|
||||
PolVer = aaaa0000.
|
||||
Len = 112.
|
||||
Primary = CHINESE WALL policy (c=1, off=14).
|
||||
Secondary = SIMPLE TYPE ENFORCEMENT policy (c=2, off=d8).
|
||||
|
||||
|
||||
Chinese Wall policy:
|
||||
====================
|
||||
Max Types = a.
|
||||
Max Ssidrefs = 5.
|
||||
Max ConfSets = 2.
|
||||
Ssidrefs Off = 10.
|
||||
Conflicts Off = 74.
|
||||
Runing T. Off = 9c.
|
||||
C. Agg. Off = b0.
|
||||
|
||||
SSID To CHWALL-Type matrix:
|
||||
|
||||
ssidref 0: 01 00 00 00 00 00 00 00 00 00
|
||||
ssidref 1: 00 01 00 00 00 00 00 00 00 00
|
||||
ssidref 2: 00 00 01 00 00 00 00 00 00 00 <<< our domain has type 2 set
|
||||
ssidref 3: 00 00 00 01 00 00 00 00 00 00
|
||||
ssidref 4: 00 00 00 00 01 00 00 00 00 00
|
||||
|
||||
Confict Sets:
|
||||
|
||||
c-set 0: 00 00 01 01 00 00 00 00 00 00 <<< t2 is in c-set0 with type 3
|
||||
c-set 1: 01 00 00 00 00 01 01 00 00 00
|
||||
|
||||
Running
|
||||
Types: 01 01 01 00 00 00 00 00 00 00 <<< t2 is running since the
|
||||
^^ <<< current aggregate conflict
|
||||
<<< set (see above) does not
|
||||
<<< include type 2
|
||||
Conflict
|
||||
Aggregate Set: 00 00 00 01 00 01 01 00 00 00 <<< type 3 is added to the
|
||||
<<< conflict aggregate
|
||||
|
||||
|
||||
Simple Type Enforcement policy:
|
||||
===============================
|
||||
Max Types = 5.
|
||||
Max Ssidrefs = 5.
|
||||
Ssidrefs Off = 8.
|
||||
|
||||
SSID To STE-Type matrix:
|
||||
|
||||
ssidref 0: 01 01 01 01 01
|
||||
ssidref 1: 00 01 00 00 00
|
||||
ssidref 2: 00 00 01 00 00
|
||||
ssidref 3: 00 00 00 01 00
|
||||
ssidref 4: 00 00 00 00 01
|
||||
|
||||
|
||||
Policy dump End.
|
||||
|
||||
|
||||
The sHype xen dmesg output looks similar to the one above when starting the
|
||||
first domain.
|
||||
|
||||
Now we start xmsec3 and it has ssidref3. Thus, it tries to run as type3 which
|
||||
conflicts with running type2 (from xmsec2). As expected, creating this domain
|
||||
fails for security policy enforcement reasons.
|
||||
|
||||
[root@laptop xen]# xm create -c xmsec3
|
||||
Using config file "xmsec3".
|
||||
Error: Error creating domain: (22, 'Invalid argument')
|
||||
[root@laptop xen]#
|
||||
|
||||
[root@laptop xen]# xm dmesg
|
||||
.
|
||||
.
|
||||
[somewhere near the very end]
|
||||
(XEN) chwall_pre_domain_create.
|
||||
(XEN) chwall_pre_domain_create: CHINESE WALL CONFLICT in type 03.
|
||||
|
||||
xmsec3 ssidref3 points to type3, which is in the current conflict aggregate
|
||||
set. This domain cannot start until domain xmsec2 is destroyed, at which time
|
||||
the aggregate conflict set is reduced and type3 is excluded from it. Then,
|
||||
xmsec3 can start. Of course, afterwards, xmsec2 cannot be restarted. Try it.
|
||||
|
||||
3. Policy tool
|
||||
**************
|
||||
toos/policy/policy_tool.c
|
||||
|
||||
a) ./policy_tool getpolicy
|
||||
prints the currently enforced policy
|
||||
(see for example section 1.)
|
||||
|
||||
b) ./policy_tool setpolicy
|
||||
sets a predefined and hardcoded security
|
||||
policy (the one described in section 2.)
|
||||
|
||||
c) ./policy_tool dumpstats
|
||||
prints some status information about the caching
|
||||
of access control decisions (number of cache hits
|
||||
and number of policy evaluations for grant_table
|
||||
and event channels).
|
||||
|
||||
d) ./policy_tool loadpolicy <binary_policy_file>
|
||||
sets the policy defined in the <binary_policy_file>
|
||||
please use the policy_processor that is posted to this
|
||||
mailing list to create such a binary policy from an XML
|
||||
policy description
|
||||
|
||||
4. Policy interface:
|
||||
********************
|
||||
The Policy interface is working in "network-byte-order" (big endian). The reason for this
|
||||
is that policy files/management should be portable and independent of the platforms.
|
||||
|
||||
Our policy interface enables managers to create a single binary policy file in a trusted
|
||||
environment and distributed it to multiple systems for enforcement.
|
||||
|
||||
5. Booting with a binary policy:
|
||||
********************************
|
||||
The grub configuration file can be adapted to boot the hypervisor with an
|
||||
already active policy. To do this, a binary policy file - this can be
|
||||
the same file as used by the policy_tool - should be placed into the boot
|
||||
partition. The following entry from the grub configuration file shows how
|
||||
a binary policy can be added to the system during boot time. Note that the
|
||||
binary policy must be of the same type that the hypervisor was compiled
|
||||
for. The policy module line should also only be added as the last module
|
||||
line if XEN was compiled with the access control module (ACM).
|
||||
|
||||
title XEN0 3.0 Devel
|
||||
kernel /xen.gz dom0_mem=400000
|
||||
module /vmlinuz-2.6.12-xen0 root=/dev/hda2 ro console=tty0
|
||||
module /initrd-2.6.12-xen0.img
|
||||
module /xen_sample_policy.bin
|
||||
|
||||
|
||||
====================end-of file=======================================
|
||||
+1
-1
@@ -1763,7 +1763,7 @@ editing \path{grub.conf}.
|
||||
physical address in the memory map will be ignored. This parameter
|
||||
may be specified with a B, K, M or G suffix, representing bytes,
|
||||
kilobytes, megabytes and gigabytes respectively. The
|
||||
default unit, if no suffix is specified, is bytes.
|
||||
default unit, if no suffix is specified, is kilobytes.
|
||||
|
||||
\item [dom0\_mem=xxx ]
|
||||
Set the amount of memory to be allocated to domain0. In Xen 3.x the parameter
|
||||
|
||||
@@ -14,8 +14,7 @@ obj-y := process.o signal.o entry.o traps.o \
|
||||
|
||||
c-obj-y := semaphore.o vm86.o \
|
||||
ptrace.o sys_i386.o \
|
||||
i387.o dmi_scan.o bootflag.o \
|
||||
doublefault.o
|
||||
i387.o dmi_scan.o bootflag.o
|
||||
s-obj-y :=
|
||||
|
||||
obj-y += cpu/
|
||||
@@ -85,7 +84,7 @@ $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \
|
||||
$(obj)/vsyscall-sysenter.o FORCE
|
||||
$(call if_changed,syscall)
|
||||
|
||||
c-link := init_task.o
|
||||
c-link :=
|
||||
s-link := vsyscall-int80.o vsyscall-sysenter.o vsyscall-sigreturn.o vsyscall.lds.o syscall_table.o
|
||||
|
||||
$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-obj-m) $(c-link)) $(patsubst %.o,$(obj)/%.S,$(s-obj-y) $(s-link)):
|
||||
|
||||
@@ -569,7 +569,7 @@ void __init cpu_gdt_init(struct Xgt_desc_struct *gdt_descr)
|
||||
for (va = gdt_descr->address, f = 0;
|
||||
va < gdt_descr->address + gdt_descr->size;
|
||||
va += PAGE_SIZE, f++) {
|
||||
frames[f] = virt_to_machine(va) >> PAGE_SHIFT;
|
||||
frames[f] = virt_to_mfn(va);
|
||||
make_page_readonly((void *)va);
|
||||
}
|
||||
if (HYPERVISOR_set_gdt(frames, gdt_descr->size / 8))
|
||||
|
||||
@@ -136,9 +136,6 @@ cpu_gdt_descr:
|
||||
ENTRY(empty_zero_page)
|
||||
|
||||
.org 0x2000
|
||||
ENTRY(swapper_pg_dir)
|
||||
|
||||
.org 0x3000
|
||||
ENTRY(cpu_gdt_table)
|
||||
.quad 0x0000000000000000 /* NULL descriptor */
|
||||
.quad 0x0000000000000000 /* 0x0b reserved */
|
||||
@@ -190,10 +187,10 @@ ENTRY(cpu_gdt_table)
|
||||
.quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */
|
||||
.fill GDT_ENTRIES-32,8,0
|
||||
|
||||
.org 0x4000
|
||||
.org 0x3000
|
||||
ENTRY(default_ldt)
|
||||
|
||||
.org 0x5000
|
||||
.org 0x4000
|
||||
/*
|
||||
* Real beginning of normal "text" segment
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/init_task.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mqueue.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/desc.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct files_struct init_files = INIT_FILES;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
|
||||
#define swapper_pg_dir ((pgd_t *)NULL)
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
#undef swapper_pg_dir
|
||||
|
||||
EXPORT_SYMBOL(init_mm);
|
||||
|
||||
/*
|
||||
* Initial thread structure.
|
||||
*
|
||||
* We need to make sure that this is THREAD_SIZE aligned due to the
|
||||
* way process stacks are handled. This is done by having a special
|
||||
* "init_task" linker map entry..
|
||||
*/
|
||||
union thread_union init_thread_union
|
||||
__attribute__((__section__(".data.init_task"))) =
|
||||
{ INIT_THREAD_INFO(init_task) };
|
||||
|
||||
/*
|
||||
* Initial task structure.
|
||||
*
|
||||
* All other task structs will be allocated on slabs in fork.c
|
||||
*/
|
||||
struct task_struct init_task = INIT_TASK(init_task);
|
||||
|
||||
EXPORT_SYMBOL(init_task);
|
||||
|
||||
/*
|
||||
* per-CPU TSS segments. Threads are completely 'soft' on Linux,
|
||||
* no more per-task TSS's.
|
||||
*/
|
||||
DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp = INIT_TSS;
|
||||
|
||||
@@ -80,7 +80,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
|
||||
t->io_bitmap_ptr = bitmap;
|
||||
|
||||
op.cmd = PHYSDEVOP_SET_IOBITMAP;
|
||||
op.u.set_iobitmap.bitmap = (unsigned long)bitmap;
|
||||
op.u.set_iobitmap.bitmap = (char *)bitmap;
|
||||
op.u.set_iobitmap.nr_ports = IO_BITMAP_BITS;
|
||||
HYPERVISOR_physdev_op(&op);
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
|
||||
{
|
||||
struct mm_struct * mm = current->mm;
|
||||
__u32 entry_1, entry_2, *lp;
|
||||
unsigned long mach_lp;
|
||||
maddr_t mach_lp;
|
||||
int error;
|
||||
struct user_desc ldt_info;
|
||||
|
||||
@@ -245,7 +245,8 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
|
||||
|
||||
/* Install the new entry ... */
|
||||
install:
|
||||
error = HYPERVISOR_update_descriptor(mach_lp, entry_1, entry_2);
|
||||
error = HYPERVISOR_update_descriptor(
|
||||
mach_lp, (u64)entry_1 | ((u64)entry_2<<32));
|
||||
|
||||
out_unlock:
|
||||
up(&mm->context.sem);
|
||||
|
||||
@@ -115,20 +115,12 @@ void xen_idle(void)
|
||||
/* We don't actually take CPU down, just spin without interrupts. */
|
||||
static inline void play_dead(void)
|
||||
{
|
||||
/* Ack it */
|
||||
__get_cpu_var(cpu_state) = CPU_DEAD;
|
||||
|
||||
/* We shouldn't have to disable interrupts while dead, but
|
||||
* some interrupts just don't seem to go away, and this makes
|
||||
* it "work" for testing purposes. */
|
||||
/* Death loop */
|
||||
while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
|
||||
HYPERVISOR_yield();
|
||||
|
||||
local_irq_disable();
|
||||
__flush_tlb_all();
|
||||
cpu_set(smp_processor_id(), cpu_online_map);
|
||||
local_irq_enable();
|
||||
}
|
||||
#else
|
||||
static inline void play_dead(void)
|
||||
@@ -156,12 +148,19 @@ void cpu_idle (void)
|
||||
rmb();
|
||||
|
||||
if (cpu_is_offline(cpu)) {
|
||||
local_irq_disable();
|
||||
/* Ack it. From this point on until
|
||||
we get woken up, we're not allowed
|
||||
to take any locks. In particular,
|
||||
don't printk. */
|
||||
__get_cpu_var(cpu_state) = CPU_DEAD;
|
||||
#if defined(CONFIG_XEN) && defined(CONFIG_HOTPLUG_CPU)
|
||||
/* Tell hypervisor to take vcpu down. */
|
||||
HYPERVISOR_vcpu_down(cpu);
|
||||
#endif
|
||||
play_dead();
|
||||
}
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
__get_cpu_var(irq_stat).idle_timestamp = jiffies;
|
||||
xen_idle();
|
||||
@@ -523,16 +522,15 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
|
||||
* Load the per-thread Thread-Local Storage descriptor.
|
||||
* This is load_TLS(next, cpu) with multicalls.
|
||||
*/
|
||||
#define C(i) do { \
|
||||
if (unlikely(next->tls_array[i].a != prev->tls_array[i].a || \
|
||||
next->tls_array[i].b != prev->tls_array[i].b)) { \
|
||||
mcl->op = __HYPERVISOR_update_descriptor; \
|
||||
mcl->args[0] = virt_to_machine(&get_cpu_gdt_table(cpu) \
|
||||
[GDT_ENTRY_TLS_MIN + i]); \
|
||||
mcl->args[1] = ((u32 *)&next->tls_array[i])[0]; \
|
||||
mcl->args[2] = ((u32 *)&next->tls_array[i])[1]; \
|
||||
mcl++; \
|
||||
} \
|
||||
#define C(i) do { \
|
||||
if (unlikely(next->tls_array[i].a != prev->tls_array[i].a || \
|
||||
next->tls_array[i].b != prev->tls_array[i].b)) { \
|
||||
mcl->op = __HYPERVISOR_update_descriptor; \
|
||||
*(u64 *)&mcl->args[0] = virt_to_machine( \
|
||||
&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]);\
|
||||
*(u64 *)&mcl->args[2] = *(u64 *)&next->tls_array[i]; \
|
||||
mcl++; \
|
||||
} \
|
||||
} while (0)
|
||||
C(0); C(1); C(2);
|
||||
#undef C
|
||||
@@ -549,7 +547,7 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
|
||||
iobmp_op.cmd =
|
||||
PHYSDEVOP_SET_IOBITMAP;
|
||||
iobmp_op.u.set_iobitmap.bitmap =
|
||||
(unsigned long)next->io_bitmap_ptr;
|
||||
(char *)next->io_bitmap_ptr;
|
||||
iobmp_op.u.set_iobitmap.nr_ports =
|
||||
next->io_bitmap_ptr ? IO_BITMAP_BITS : 0;
|
||||
mcl->op = __HYPERVISOR_physdev_op;
|
||||
@@ -791,3 +789,10 @@ unsigned long arch_align_stack(unsigned long sp)
|
||||
sp -= get_random_int() % 8192;
|
||||
return sp & ~0xf;
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_X86_SMP
|
||||
void _restore_vcpu(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@@ -1604,11 +1604,10 @@ void __init setup_arch(char **cmdline_p)
|
||||
for ( i=0, j=0; i < max_pfn; i+=(PAGE_SIZE/sizeof(unsigned long)), j++ )
|
||||
{
|
||||
pfn_to_mfn_frame_list[j] =
|
||||
virt_to_machine(&phys_to_machine_mapping[i]) >> PAGE_SHIFT;
|
||||
virt_to_mfn(&phys_to_machine_mapping[i]);
|
||||
}
|
||||
HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list =
|
||||
virt_to_machine(pfn_to_mfn_frame_list) >> PAGE_SHIFT;
|
||||
|
||||
virt_to_mfn(pfn_to_mfn_frame_list);
|
||||
|
||||
/*
|
||||
* NOTE: at this point the bootmem allocator is fully available.
|
||||
|
||||
@@ -904,7 +904,7 @@ static int __init do_boot_cpu(int apicid)
|
||||
for (va = cpu_gdt_descr[cpu].address, f = 0;
|
||||
va < cpu_gdt_descr[cpu].address + cpu_gdt_descr[cpu].size;
|
||||
va += PAGE_SIZE, f++) {
|
||||
ctxt.gdt_frames[f] = virt_to_machine(va) >> PAGE_SHIFT;
|
||||
ctxt.gdt_frames[f] = virt_to_mfn(va);
|
||||
make_page_readonly((void *)va);
|
||||
}
|
||||
ctxt.gdt_ents = cpu_gdt_descr[cpu].size / 8;
|
||||
@@ -920,7 +920,7 @@ static int __init do_boot_cpu(int apicid)
|
||||
ctxt.failsafe_callback_cs = __KERNEL_CS;
|
||||
ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
|
||||
|
||||
ctxt.ctrlreg[3] = (unsigned long)virt_to_machine(swapper_pg_dir);
|
||||
ctxt.ctrlreg[3] = virt_to_mfn(swapper_pg_dir) << PAGE_SHIFT;
|
||||
|
||||
boot_error = HYPERVISOR_boot_vcpu(cpu, &ctxt);
|
||||
printk("boot error: %ld\n", boot_error);
|
||||
@@ -1616,3 +1616,21 @@ void smp_resume(void)
|
||||
smp_intr_init();
|
||||
local_setup_timer_irq();
|
||||
}
|
||||
|
||||
DECLARE_PER_CPU(int, timer_irq);
|
||||
|
||||
void _restore_vcpu(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
extern atomic_t vcpus_rebooting;
|
||||
|
||||
/* We are the first thing the vcpu runs when it comes back,
|
||||
and we are supposed to restore the IPIs and timer
|
||||
interrupts etc. When we return, the vcpu's idle loop will
|
||||
start up again. */
|
||||
_bind_virq_to_irq(VIRQ_TIMER, cpu, per_cpu(timer_irq, cpu));
|
||||
_bind_virq_to_irq(VIRQ_DEBUG, cpu, per_cpu(ldebug_irq, cpu));
|
||||
_bind_ipi_to_irq(RESCHEDULE_VECTOR, cpu, per_cpu(resched_irq, cpu) );
|
||||
_bind_ipi_to_irq(CALL_FUNCTION_VECTOR, cpu, per_cpu(callfunc_irq, cpu) );
|
||||
atomic_dec(&vcpus_rebooting);
|
||||
}
|
||||
@@ -94,9 +94,6 @@ setup_io_tlb_npages(char *str)
|
||||
iotlb_nslabs = simple_strtoul(str, &str, 0) <<
|
||||
(20 - IO_TLB_SHIFT);
|
||||
iotlb_nslabs = ALIGN(iotlb_nslabs, IO_TLB_SEGSIZE);
|
||||
/* Round up to power of two (xen_create_contiguous_region). */
|
||||
while (iotlb_nslabs & (iotlb_nslabs-1))
|
||||
iotlb_nslabs += iotlb_nslabs & ~(iotlb_nslabs-1);
|
||||
}
|
||||
if (*str == ',')
|
||||
++str;
|
||||
@@ -123,9 +120,6 @@ swiotlb_init_with_default_size (size_t default_size)
|
||||
if (!iotlb_nslabs) {
|
||||
iotlb_nslabs = (default_size >> IO_TLB_SHIFT);
|
||||
iotlb_nslabs = ALIGN(iotlb_nslabs, IO_TLB_SEGSIZE);
|
||||
/* Round up to power of two (xen_create_contiguous_region). */
|
||||
while (iotlb_nslabs & (iotlb_nslabs-1))
|
||||
iotlb_nslabs += iotlb_nslabs & ~(iotlb_nslabs-1);
|
||||
}
|
||||
|
||||
bytes = iotlb_nslabs * (1UL << IO_TLB_SHIFT);
|
||||
@@ -135,10 +129,14 @@ swiotlb_init_with_default_size (size_t default_size)
|
||||
*/
|
||||
iotlb_virt_start = alloc_bootmem_low_pages(bytes);
|
||||
if (!iotlb_virt_start)
|
||||
panic("Cannot allocate SWIOTLB buffer");
|
||||
panic("Cannot allocate SWIOTLB buffer!\n"
|
||||
"Use dom0_mem Xen boot parameter to reserve\n"
|
||||
"some DMA memory (e.g., dom0_mem=-128M).\n");
|
||||
|
||||
xen_create_contiguous_region(
|
||||
(unsigned long)iotlb_virt_start, get_order(bytes));
|
||||
for (i = 0; i < iotlb_nslabs; i += IO_TLB_SEGSIZE)
|
||||
xen_create_contiguous_region(
|
||||
(unsigned long)iotlb_virt_start + (i << IO_TLB_SHIFT),
|
||||
get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT));
|
||||
|
||||
iotlb_virt_end = iotlb_virt_start + bytes;
|
||||
|
||||
|
||||
@@ -745,7 +745,7 @@ static void __init hpet_time_init(void)
|
||||
#endif
|
||||
|
||||
/* Dynamically-mapped IRQ. */
|
||||
static DEFINE_PER_CPU(int, timer_irq);
|
||||
DEFINE_PER_CPU(int, timer_irq);
|
||||
|
||||
static struct irqaction irq_timer = {
|
||||
timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer0",
|
||||
|
||||
@@ -342,11 +342,15 @@ unsigned long long __PAGE_KERNEL_EXEC = _PAGE_KERNEL_EXEC;
|
||||
extern void __init remap_numa_kva(void);
|
||||
#endif
|
||||
|
||||
pgd_t *swapper_pg_dir;
|
||||
|
||||
static void __init pagetable_init (void)
|
||||
{
|
||||
unsigned long vaddr;
|
||||
pgd_t *pgd_base = swapper_pg_dir;
|
||||
pgd_t *old_pgd = (pgd_t *)xen_start_info.pt_base;
|
||||
pgd_t *pgd_base = (pgd_t *)xen_start_info.pt_base;
|
||||
|
||||
swapper_pg_dir = pgd_base;
|
||||
init_mm.pgd = pgd_base;
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
int i;
|
||||
@@ -367,44 +371,6 @@ static void __init pagetable_init (void)
|
||||
__PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch to proper mm_init page directory. Initialise from the current
|
||||
* page directory, write-protect the new page directory, then switch to
|
||||
* it. We clean up by write-enabling and then freeing the old page dir.
|
||||
*/
|
||||
#ifndef CONFIG_X86_PAE
|
||||
memcpy(pgd_base, old_pgd, PTRS_PER_PGD_NO_HV*sizeof(pgd_t));
|
||||
make_page_readonly(pgd_base);
|
||||
xen_pgd_pin(__pa(pgd_base));
|
||||
load_cr3(pgd_base);
|
||||
xen_pgd_unpin(__pa(old_pgd));
|
||||
make_page_writable(old_pgd);
|
||||
__flush_tlb_all();
|
||||
free_bootmem(__pa(old_pgd), PAGE_SIZE);
|
||||
#else
|
||||
{
|
||||
pud_t *old_pud = pud_offset(old_pgd+3, PAGE_OFFSET);
|
||||
pmd_t *old_pmd = pmd_offset(old_pud, PAGE_OFFSET);
|
||||
pmd_t *new_pmd = alloc_bootmem_low_pages(PAGE_SIZE);
|
||||
|
||||
memcpy(new_pmd, old_pmd, PAGE_SIZE);
|
||||
memcpy(pgd_base, old_pgd, PTRS_PER_PGD_NO_HV*sizeof(pgd_t));
|
||||
set_pgd(&pgd_base[3], __pgd(__pa(new_pmd) | _PAGE_PRESENT));
|
||||
|
||||
make_page_readonly(new_pmd);
|
||||
make_page_readonly(pgd_base);
|
||||
xen_pgd_pin(__pa(pgd_base));
|
||||
load_cr3(pgd_base);
|
||||
xen_pgd_unpin(__pa(old_pgd));
|
||||
make_page_writable(old_pgd);
|
||||
make_page_writable(old_pmd);
|
||||
__flush_tlb_all();
|
||||
|
||||
free_bootmem(__pa(old_pgd), PAGE_SIZE);
|
||||
free_bootmem(__pa(old_pmd), PAGE_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
init_mm.context.pinned = 1;
|
||||
kernel_physical_mapping_init(pgd_base);
|
||||
remap_numa_kva();
|
||||
|
||||
@@ -306,7 +306,7 @@ static int direct_remap_area_pte_fn(pte_t *pte,
|
||||
{
|
||||
mmu_update_t **v = (mmu_update_t **)data;
|
||||
|
||||
(*v)->ptr = ((physaddr_t)pfn_to_mfn(page_to_pfn(pte_page)) <<
|
||||
(*v)->ptr = ((maddr_t)pfn_to_mfn(page_to_pfn(pte_page)) <<
|
||||
PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK);
|
||||
(*v)++;
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
|
||||
__flush_tlb_one(vaddr);
|
||||
}
|
||||
|
||||
void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
|
||||
void __set_fixmap (enum fixed_addresses idx, maddr_t phys, pgprot_t flags)
|
||||
{
|
||||
unsigned long address = __fix_to_virt(idx);
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs)
|
||||
vcpu_info_t *vcpu_info = &s->vcpu_data[cpu];
|
||||
|
||||
vcpu_info->evtchn_upcall_pending = 0;
|
||||
|
||||
|
||||
/* NB. No need for a barrier here -- XCHG is a barrier on x86. */
|
||||
l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
|
||||
while ( l1 != 0 )
|
||||
@@ -158,9 +158,9 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs)
|
||||
l2 &= ~(1 << l2i);
|
||||
|
||||
port = (l1i << 5) + l2i;
|
||||
if ( (irq = evtchn_to_irq[port]) != -1 )
|
||||
if ( (irq = evtchn_to_irq[port]) != -1 ) {
|
||||
do_IRQ(irq, regs);
|
||||
else
|
||||
} else
|
||||
evtchn_device_upcall(port);
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,74 @@ void unbind_virq_from_irq(int virq)
|
||||
spin_unlock(&irq_mapping_update_lock);
|
||||
}
|
||||
|
||||
/* This is only used when a vcpu from an xm save. The ipi is expected
|
||||
to have been bound before we suspended, and so all of the xenolinux
|
||||
state is set up; we only need to restore the Xen side of things.
|
||||
The irq number has to be the same, but the evtchn number can
|
||||
change. */
|
||||
void _bind_ipi_to_irq(int ipi, int vcpu, int irq)
|
||||
{
|
||||
evtchn_op_t op;
|
||||
int evtchn;
|
||||
|
||||
spin_lock(&irq_mapping_update_lock);
|
||||
|
||||
op.cmd = EVTCHNOP_bind_ipi;
|
||||
if ( HYPERVISOR_event_channel_op(&op) != 0 )
|
||||
panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, vcpu);
|
||||
evtchn = op.u.bind_ipi.port;
|
||||
|
||||
printk("<0>IPI %d, old evtchn %d, evtchn %d.\n",
|
||||
ipi, per_cpu(ipi_to_evtchn, vcpu)[ipi],
|
||||
evtchn);
|
||||
|
||||
evtchn_to_irq[irq_to_evtchn[irq]] = -1;
|
||||
irq_to_evtchn[irq] = -1;
|
||||
|
||||
evtchn_to_irq[evtchn] = irq;
|
||||
irq_to_evtchn[irq] = evtchn;
|
||||
|
||||
printk("<0>evtchn_to_irq[%d] = %d.\n", evtchn,
|
||||
evtchn_to_irq[evtchn]);
|
||||
per_cpu(ipi_to_evtchn, vcpu)[ipi] = evtchn;
|
||||
|
||||
bind_evtchn_to_cpu(evtchn, vcpu);
|
||||
|
||||
spin_unlock(&irq_mapping_update_lock);
|
||||
|
||||
clear_bit(evtchn, (unsigned long *)HYPERVISOR_shared_info->evtchn_mask);
|
||||
clear_bit(evtchn, (unsigned long *)HYPERVISOR_shared_info->evtchn_pending);
|
||||
}
|
||||
|
||||
void _bind_virq_to_irq(int virq, int cpu, int irq)
|
||||
{
|
||||
evtchn_op_t op;
|
||||
int evtchn;
|
||||
|
||||
spin_lock(&irq_mapping_update_lock);
|
||||
|
||||
op.cmd = EVTCHNOP_bind_virq;
|
||||
op.u.bind_virq.virq = virq;
|
||||
if ( HYPERVISOR_event_channel_op(&op) != 0 )
|
||||
panic("Failed to bind virtual IRQ %d\n", virq);
|
||||
evtchn = op.u.bind_virq.port;
|
||||
|
||||
evtchn_to_irq[irq_to_evtchn[irq]] = -1;
|
||||
irq_to_evtchn[irq] = -1;
|
||||
|
||||
evtchn_to_irq[evtchn] = irq;
|
||||
irq_to_evtchn[irq] = evtchn;
|
||||
|
||||
per_cpu(virq_to_irq, cpu)[virq] = irq;
|
||||
|
||||
bind_evtchn_to_cpu(evtchn, cpu);
|
||||
|
||||
spin_unlock(&irq_mapping_update_lock);
|
||||
|
||||
clear_bit(evtchn, (unsigned long *)HYPERVISOR_shared_info->evtchn_mask);
|
||||
clear_bit(evtchn, (unsigned long *)HYPERVISOR_shared_info->evtchn_pending);
|
||||
}
|
||||
|
||||
int bind_ipi_to_irq(int ipi)
|
||||
{
|
||||
evtchn_op_t op;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <asm-xen/queues.h>
|
||||
#include <asm-xen/xenbus.h>
|
||||
#include <asm-xen/ctrl_if.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#define SHUTDOWN_INVALID -1
|
||||
#define SHUTDOWN_POWEROFF 0
|
||||
@@ -58,20 +60,74 @@ EXPORT_SYMBOL(machine_power_off);
|
||||
/* Ignore multiple shutdown requests. */
|
||||
static int shutting_down = SHUTDOWN_INVALID;
|
||||
|
||||
static void __do_suspend(void)
|
||||
#ifndef CONFIG_HOTPLUG_CPU
|
||||
#define cpu_down(x) (-EOPNOTSUPP)
|
||||
#define cpu_up(x) (-EOPNOTSUPP)
|
||||
#endif
|
||||
|
||||
static void save_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt)
|
||||
{
|
||||
int r;
|
||||
int gdt_pages;
|
||||
r = HYPERVISOR_vcpu_pickle(vcpu, ctxt);
|
||||
if (r != 0)
|
||||
panic("pickling vcpu %d -> %d!\n", vcpu, r);
|
||||
|
||||
/* Translate from machine to physical addresses where necessary,
|
||||
so that they can be translated to our new machine address space
|
||||
after resume. libxc is responsible for doing this to vcpu0,
|
||||
but we do it to the others. */
|
||||
gdt_pages = (ctxt->gdt_ents + 511) / 512;
|
||||
ctxt->ctrlreg[3] = machine_to_phys(ctxt->ctrlreg[3]);
|
||||
for (r = 0; r < gdt_pages; r++)
|
||||
ctxt->gdt_frames[r] = mfn_to_pfn(ctxt->gdt_frames[r]);
|
||||
}
|
||||
|
||||
void _restore_vcpu(int cpu);
|
||||
|
||||
atomic_t vcpus_rebooting;
|
||||
|
||||
static int restore_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt)
|
||||
{
|
||||
int r;
|
||||
int gdt_pages = (ctxt->gdt_ents + 511) / 512;
|
||||
|
||||
/* This is kind of a hack, and implicitly relies on the fact that
|
||||
the vcpu stops in a place where all of the call clobbered
|
||||
registers are already dead. */
|
||||
ctxt->user_regs.esp -= 4;
|
||||
((unsigned long *)ctxt->user_regs.esp)[0] = ctxt->user_regs.eip;
|
||||
ctxt->user_regs.eip = (unsigned long)_restore_vcpu;
|
||||
|
||||
/* De-canonicalise. libxc handles this for vcpu 0, but we need
|
||||
to do it for the other vcpus. */
|
||||
ctxt->ctrlreg[3] = phys_to_machine(ctxt->ctrlreg[3]);
|
||||
for (r = 0; r < gdt_pages; r++)
|
||||
ctxt->gdt_frames[r] = pfn_to_mfn(ctxt->gdt_frames[r]);
|
||||
|
||||
atomic_set(&vcpus_rebooting, 1);
|
||||
r = HYPERVISOR_boot_vcpu(vcpu, ctxt);
|
||||
if (r != 0) {
|
||||
printk(KERN_EMERG "Failed to reboot vcpu %d (%d)\n", vcpu, r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure we wait for the new vcpu to come up before trying to do
|
||||
anything with it or starting the next one. */
|
||||
while (atomic_read(&vcpus_rebooting))
|
||||
barrier();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __do_suspend(void *ignore)
|
||||
{
|
||||
int i, j;
|
||||
suspend_record_t *suspend_record;
|
||||
static vcpu_guest_context_t suspended_cpu_records[NR_CPUS];
|
||||
|
||||
/* Hmmm... a cleaner interface to suspend/resume blkdevs would be nice. */
|
||||
/* XXX SMH: yes it would :-( */
|
||||
#ifdef CONFIG_XEN_BLKDEV_FRONTEND
|
||||
extern void blkdev_suspend(void);
|
||||
extern void blkdev_resume(void);
|
||||
#else
|
||||
#define blkdev_suspend() do{}while(0)
|
||||
#define blkdev_resume() do{}while(0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_FRONTEND
|
||||
extern void netif_suspend(void);
|
||||
@@ -104,14 +160,64 @@ static void __do_suspend(void)
|
||||
extern unsigned long max_pfn;
|
||||
extern unsigned int *pfn_to_mfn_frame_list;
|
||||
|
||||
cpumask_t prev_online_cpus, prev_present_cpus;
|
||||
int err = 0;
|
||||
|
||||
BUG_ON(smp_processor_id() != 0);
|
||||
BUG_ON(in_interrupt());
|
||||
|
||||
#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
|
||||
if (num_online_cpus() > 1) {
|
||||
printk(KERN_WARNING "Can't suspend SMP guests without CONFIG_HOTPLUG_CPU\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
suspend_record = (suspend_record_t *)__get_free_page(GFP_KERNEL);
|
||||
if ( suspend_record == NULL )
|
||||
goto out;
|
||||
|
||||
/* Take all of the other cpus offline. We need to be careful not
|
||||
to get preempted between the final test for num_online_cpus()
|
||||
== 1 and disabling interrupts, since otherwise userspace could
|
||||
bring another cpu online, and then we'd be stuffed. At the
|
||||
same time, cpu_down can reschedule, so we need to enable
|
||||
preemption while doing that. This kind of sucks, but should be
|
||||
correct. */
|
||||
/* (We don't need to worry about other cpus bringing stuff up,
|
||||
since by the time num_online_cpus() == 1, there aren't any
|
||||
other cpus) */
|
||||
cpus_clear(prev_online_cpus);
|
||||
preempt_disable();
|
||||
while (num_online_cpus() > 1) {
|
||||
preempt_enable();
|
||||
for_each_online_cpu(i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
err = cpu_down(i);
|
||||
if (err != 0) {
|
||||
printk(KERN_CRIT "Failed to take all CPUs down: %d.\n", err);
|
||||
goto out_reenable_cpus;
|
||||
}
|
||||
cpu_set(i, prev_online_cpus);
|
||||
}
|
||||
preempt_disable();
|
||||
}
|
||||
|
||||
suspend_record->nr_pfns = max_pfn; /* final number of pfns */
|
||||
|
||||
__cli();
|
||||
|
||||
preempt_enable();
|
||||
|
||||
cpus_clear(prev_present_cpus);
|
||||
for_each_present_cpu(i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
save_vcpu_context(i, &suspended_cpu_records[i]);
|
||||
cpu_set(i, prev_present_cpus);
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
mm_pin_all();
|
||||
kmem_cache_shrink(pgd_cache);
|
||||
@@ -119,8 +225,6 @@ static void __do_suspend(void)
|
||||
|
||||
netif_suspend();
|
||||
|
||||
blkdev_suspend();
|
||||
|
||||
time_suspend();
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
@@ -141,7 +245,9 @@ static void __do_suspend(void)
|
||||
memcpy(&suspend_record->resume_info, &xen_start_info,
|
||||
sizeof(xen_start_info));
|
||||
|
||||
HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT);
|
||||
/* We'll stop somewhere inside this hypercall. When it returns,
|
||||
we'll start resuming after the restore. */
|
||||
HYPERVISOR_suspend(virt_to_mfn(suspend_record));
|
||||
|
||||
shutting_down = SHUTDOWN_INVALID;
|
||||
|
||||
@@ -157,10 +263,10 @@ static void __do_suspend(void)
|
||||
for ( i=0, j=0; i < max_pfn; i+=(PAGE_SIZE/sizeof(unsigned long)), j++ )
|
||||
{
|
||||
pfn_to_mfn_frame_list[j] =
|
||||
virt_to_machine(&phys_to_machine_mapping[i]) >> PAGE_SHIFT;
|
||||
virt_to_mfn(&phys_to_machine_mapping[i]);
|
||||
}
|
||||
HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list =
|
||||
virt_to_machine(pfn_to_mfn_frame_list) >> PAGE_SHIFT;
|
||||
virt_to_mfn(pfn_to_mfn_frame_list);
|
||||
|
||||
gnttab_resume();
|
||||
|
||||
@@ -176,17 +282,30 @@ static void __do_suspend(void)
|
||||
|
||||
time_resume();
|
||||
|
||||
blkdev_resume();
|
||||
|
||||
netif_resume();
|
||||
|
||||
usbif_resume();
|
||||
|
||||
for_each_cpu_mask(i, prev_present_cpus) {
|
||||
restore_vcpu_context(i, &suspended_cpu_records[i]);
|
||||
}
|
||||
|
||||
__sti();
|
||||
|
||||
out_reenable_cpus:
|
||||
for_each_cpu_mask(i, prev_online_cpus) {
|
||||
j = cpu_up(i);
|
||||
if (j != 0) {
|
||||
printk(KERN_CRIT "Failed to bring cpu %d back up (%d).\n",
|
||||
i, j);
|
||||
err = j;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if ( suspend_record != NULL )
|
||||
free_page((unsigned long)suspend_record);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int shutdown_process(void *__unused)
|
||||
@@ -233,6 +352,18 @@ static int shutdown_process(void *__unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct task_struct *kthread_create_on_cpu(int (*f)(void *arg),
|
||||
void *arg,
|
||||
const char *name,
|
||||
int cpu)
|
||||
{
|
||||
struct task_struct *p;
|
||||
p = kthread_create(f, arg, name);
|
||||
kthread_bind(p, cpu);
|
||||
wake_up_process(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void __shutdown_handler(void *unused)
|
||||
{
|
||||
int err;
|
||||
@@ -245,7 +376,7 @@ static void __shutdown_handler(void *unused)
|
||||
}
|
||||
else
|
||||
{
|
||||
__do_suspend();
|
||||
kthread_create_on_cpu(__do_suspend, NULL, "suspender", 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -453,8 +453,8 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *
|
||||
#define C(i) do { \
|
||||
if (unlikely(next->tls_array[i] != prev->tls_array[i])) { \
|
||||
mcl->op = __HYPERVISOR_update_descriptor; \
|
||||
mcl->args[0] = virt_to_machine(&get_cpu_gdt_table(cpu) \
|
||||
[GDT_ENTRY_TLS_MIN + i]); \
|
||||
mcl->args[0] = virt_to_machine( \
|
||||
&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]);\
|
||||
mcl->args[1] = next->tls_array[i]; \
|
||||
mcl++; \
|
||||
} \
|
||||
@@ -474,7 +474,7 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *
|
||||
iobmp_op.cmd =
|
||||
PHYSDEVOP_SET_IOBITMAP;
|
||||
iobmp_op.u.set_iobitmap.bitmap =
|
||||
(unsigned long)next->io_bitmap_ptr;
|
||||
(char *)next->io_bitmap_ptr;
|
||||
iobmp_op.u.set_iobitmap.nr_ports =
|
||||
next->io_bitmap_ptr ? IO_BITMAP_BITS : 0;
|
||||
mcl->op = __HYPERVISOR_physdev_op;
|
||||
@@ -743,3 +743,9 @@ unsigned long arch_align_stack(unsigned long sp)
|
||||
sp -= get_random_int() % 8192;
|
||||
return sp & ~0xf;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
void _restore_vcpu(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@@ -795,7 +795,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
for ( i=0, j=0; i < end_pfn; i+=(PAGE_SIZE/sizeof(unsigned long)), j++ )
|
||||
{
|
||||
pfn_to_mfn_frame_list[j] =
|
||||
virt_to_machine(&phys_to_machine_mapping[i]) >> PAGE_SHIFT;
|
||||
virt_to_mfn(&phys_to_machine_mapping[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ void __init cpu_gdt_init(struct desc_ptr *gdt_descr)
|
||||
for (va = gdt_descr->address, f = 0;
|
||||
va < gdt_descr->address + gdt_descr->size;
|
||||
va += PAGE_SIZE, f++) {
|
||||
frames[f] = virt_to_machine(va) >> PAGE_SHIFT;
|
||||
frames[f] = virt_to_mfn(va);
|
||||
make_page_readonly((void *)va);
|
||||
}
|
||||
if (HYPERVISOR_set_gdt(frames, gdt_descr->size /
|
||||
@@ -280,19 +280,16 @@ void __init cpu_init (void)
|
||||
if (cpu) {
|
||||
memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
cpu_gdt_descr[cpu].size = GDT_SIZE;
|
||||
cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu];
|
||||
|
||||
cpu_gdt_init(&cpu_gdt_descr[cpu]);
|
||||
|
||||
#ifndef CONFIG_XEN
|
||||
memcpy(me->thread.tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8);
|
||||
|
||||
#else
|
||||
memcpy(me->thread.tls_array, &get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN],
|
||||
GDT_ENTRY_TLS_ENTRIES * 8);
|
||||
|
||||
cpu_gdt_init(&cpu_gdt_descr[cpu]);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@@ -780,7 +780,7 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
|
||||
for (va = cpu_gdt_descr[cpu].address, f = 0;
|
||||
va < cpu_gdt_descr[cpu].address + cpu_gdt_descr[cpu].size;
|
||||
va += PAGE_SIZE, f++) {
|
||||
ctxt.gdt_frames[f] = virt_to_machine(va) >> PAGE_SHIFT;
|
||||
ctxt.gdt_frames[f] = virt_to_mfn(va);
|
||||
make_page_readonly((void *)va);
|
||||
}
|
||||
ctxt.gdt_ents = GDT_ENTRIES;
|
||||
@@ -795,7 +795,7 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
|
||||
ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
|
||||
ctxt.syscall_callback_eip = (unsigned long)system_call;
|
||||
|
||||
ctxt.ctrlreg[3] = (unsigned long)virt_to_machine(init_level4_pgt);
|
||||
ctxt.ctrlreg[3] = virt_to_mfn(init_level4_pgt) << PAGE_SHIFT;
|
||||
|
||||
boot_error = HYPERVISOR_boot_vcpu(cpu, &ctxt);
|
||||
|
||||
@@ -1286,4 +1286,10 @@ void smp_resume(void)
|
||||
smp_intr_init();
|
||||
local_setup_timer_irq();
|
||||
}
|
||||
|
||||
void _restore_vcpu(void)
|
||||
{
|
||||
/* XXX need to write this */
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -742,7 +742,7 @@ void __init paging_init(void)
|
||||
set_fixmap(FIX_ISAMAP_BEGIN - i, i * PAGE_SIZE);
|
||||
else
|
||||
__set_fixmap(FIX_ISAMAP_BEGIN - i,
|
||||
virt_to_machine(empty_zero_page),
|
||||
virt_to_mfn(empty_zero_page) << PAGE_SHIFT,
|
||||
PAGE_KERNEL_RO);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
|
||||
obj-y := blkback.o control.o interface.o vbd.o
|
||||
obj-y := blkback.o xenbus.o interface.o vbd.o
|
||||
@@ -104,7 +104,6 @@ static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); }
|
||||
#endif
|
||||
|
||||
static int do_block_io_op(blkif_t *blkif, int max_to_do);
|
||||
static void dispatch_probe(blkif_t *blkif, blkif_request_t *req);
|
||||
static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req);
|
||||
static void make_response(blkif_t *blkif, unsigned long id,
|
||||
unsigned short op, int st);
|
||||
@@ -349,10 +348,6 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
|
||||
dispatch_rw_block_io(blkif, req);
|
||||
break;
|
||||
|
||||
case BLKIF_OP_PROBE:
|
||||
dispatch_probe(blkif, req);
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTK("error: unknown block io operation [%d]\n",
|
||||
req->operation);
|
||||
@@ -365,66 +360,6 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
|
||||
return more_to_do;
|
||||
}
|
||||
|
||||
static void dispatch_probe(blkif_t *blkif, blkif_request_t *req)
|
||||
{
|
||||
int rsp = BLKIF_RSP_ERROR;
|
||||
int pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
|
||||
|
||||
/* We expect one buffer only. */
|
||||
if ( unlikely(req->nr_segments != 1) )
|
||||
goto out;
|
||||
|
||||
/* Make sure the buffer is page-sized. */
|
||||
if ( (blkif_first_sect(req->frame_and_sects[0]) != 0) ||
|
||||
(blkif_last_sect(req->frame_and_sects[0]) != ((PAGE_SIZE/512)-1)) )
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
{
|
||||
struct gnttab_map_grant_ref map;
|
||||
|
||||
map.host_addr = MMAP_VADDR(pending_idx, 0);
|
||||
map.flags = GNTMAP_host_map;
|
||||
map.ref = blkif_gref_from_fas(req->frame_and_sects[0]);
|
||||
map.dom = blkif->domid;
|
||||
|
||||
if ( unlikely(HYPERVISOR_grant_table_op(
|
||||
GNTTABOP_map_grant_ref, &map, 1)))
|
||||
BUG();
|
||||
|
||||
if ( map.handle < 0 )
|
||||
goto out;
|
||||
|
||||
pending_handle(pending_idx, 0) = map.handle;
|
||||
}
|
||||
#else /* else CONFIG_XEN_BLKDEV_GRANT */
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
/* Grab the real frontend out of the probe message. */
|
||||
if (req->frame_and_sects[1] == BLKTAP_COOKIE)
|
||||
blkif->is_blktap = 1;
|
||||
#endif
|
||||
|
||||
|
||||
if ( HYPERVISOR_update_va_mapping_otherdomain(
|
||||
MMAP_VADDR(pending_idx, 0),
|
||||
pfn_pte_ma(req->frame_and_sects[0] >> PAGE_SHIFT, PAGE_KERNEL),
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
0, (blkif->is_blktap ? ID_TO_DOM(req->id) : blkif->domid) ) )
|
||||
#else
|
||||
0, blkif->domid) )
|
||||
#endif
|
||||
goto out;
|
||||
#endif /* endif CONFIG_XEN_BLKDEV_GRANT */
|
||||
|
||||
rsp = vbd_probe(blkif, (vdisk_t *)MMAP_VADDR(pending_idx, 0),
|
||||
PAGE_SIZE / sizeof(vdisk_t));
|
||||
|
||||
out:
|
||||
fast_flush_area(pending_idx, 1);
|
||||
make_response(blkif, req->id, req->operation, rsp);
|
||||
}
|
||||
|
||||
static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
|
||||
{
|
||||
extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
|
||||
@@ -460,7 +395,7 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
|
||||
goto bad_descriptor;
|
||||
}
|
||||
|
||||
preq.dev = req->device;
|
||||
preq.dev = req->handle;
|
||||
preq.sector_number = req->sector_number;
|
||||
preq.nr_sects = 0;
|
||||
|
||||
@@ -730,8 +665,8 @@ static int __init blkif_init(void)
|
||||
0, SLAB_HWCACHE_ALIGN, NULL, NULL);
|
||||
#endif
|
||||
|
||||
blkif_ctrlif_init();
|
||||
|
||||
blkif_xenbus_init();
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
memset( pending_grant_handles, BLKBACK_INVALID_HANDLE, MMAP_PAGES );
|
||||
printk(KERN_ALERT "Blkif backend is using grant tables.\n");
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm-xen/ctrl_if.h>
|
||||
#include <asm-xen/evtchn.h>
|
||||
#include <asm-xen/hypervisor.h>
|
||||
#include <asm-xen/xen-public/io/blkif.h>
|
||||
@@ -47,6 +46,7 @@ typedef struct blkif_st {
|
||||
/* Physical parameters of the comms window. */
|
||||
unsigned long shmem_frame;
|
||||
unsigned int evtchn;
|
||||
unsigned int remote_evtchn;
|
||||
/* Comms information. */
|
||||
blkif_back_ring_t blk_ring;
|
||||
/* VBDs attached to this interface. */
|
||||
@@ -71,7 +71,7 @@ typedef struct blkif_st {
|
||||
struct work_struct work;
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
u16 shmem_handle;
|
||||
memory_t shmem_vaddr;
|
||||
unsigned long shmem_vaddr;
|
||||
grant_ref_t shmem_ref;
|
||||
#endif
|
||||
} blkif_t;
|
||||
@@ -81,17 +81,29 @@ void blkif_destroy(blkif_be_destroy_t *destroy);
|
||||
void blkif_connect(blkif_be_connect_t *connect);
|
||||
int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id);
|
||||
void blkif_disconnect_complete(blkif_t *blkif);
|
||||
blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle);
|
||||
blkif_t *blkif_find(domid_t domid);
|
||||
void free_blkif(blkif_t *blkif);
|
||||
int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn);
|
||||
|
||||
#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
|
||||
#define blkif_put(_b) \
|
||||
do { \
|
||||
if ( atomic_dec_and_test(&(_b)->refcnt) ) \
|
||||
blkif_disconnect_complete(_b); \
|
||||
free_blkif(_b); \
|
||||
} while (0)
|
||||
|
||||
void vbd_create(blkif_be_vbd_create_t *create);
|
||||
struct vbd;
|
||||
void vbd_free(blkif_t *blkif, struct vbd *vbd);
|
||||
|
||||
/* Creates inactive vbd. */
|
||||
struct vbd *vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, blkif_pdev_t pdevice, int readonly);
|
||||
int vbd_is_active(struct vbd *vbd);
|
||||
void vbd_activate(blkif_t *blkif, struct vbd *vbd);
|
||||
|
||||
unsigned long vbd_size(struct vbd *vbd);
|
||||
unsigned int vbd_info(struct vbd *vbd);
|
||||
unsigned long vbd_secsize(struct vbd *vbd);
|
||||
void vbd_destroy(blkif_be_vbd_destroy_t *delete);
|
||||
int vbd_probe(blkif_t *blkif, vdisk_t *vbd_info, int max_vbds);
|
||||
void destroy_all_vbds(blkif_t *blkif);
|
||||
|
||||
struct phys_req {
|
||||
@@ -104,10 +116,11 @@ struct phys_req {
|
||||
int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation);
|
||||
|
||||
void blkif_interface_init(void);
|
||||
void blkif_ctrlif_init(void);
|
||||
|
||||
void blkif_deschedule(blkif_t *blkif);
|
||||
|
||||
void blkif_xenbus_init(void);
|
||||
|
||||
irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
|
||||
|
||||
#endif /* __BLKIF__BACKEND__COMMON_H__ */
|
||||
@@ -1,61 +0,0 @@
|
||||
/******************************************************************************
|
||||
* arch/xen/drivers/blkif/backend/control.c
|
||||
*
|
||||
* Routines for interfacing with the control plane.
|
||||
*
|
||||
* Copyright (c) 2004, Keir Fraser
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
|
||||
{
|
||||
DPRINTK("Received blkif backend message, subtype=%d\n", msg->subtype);
|
||||
|
||||
switch ( msg->subtype )
|
||||
{
|
||||
case CMSG_BLKIF_BE_CREATE:
|
||||
blkif_create((blkif_be_create_t *)&msg->msg[0]);
|
||||
break;
|
||||
case CMSG_BLKIF_BE_DESTROY:
|
||||
blkif_destroy((blkif_be_destroy_t *)&msg->msg[0]);
|
||||
break;
|
||||
case CMSG_BLKIF_BE_CONNECT:
|
||||
blkif_connect((blkif_be_connect_t *)&msg->msg[0]);
|
||||
break;
|
||||
case CMSG_BLKIF_BE_DISCONNECT:
|
||||
if ( !blkif_disconnect((blkif_be_disconnect_t *)&msg->msg[0],msg->id) )
|
||||
return; /* Sending the response is deferred until later. */
|
||||
break;
|
||||
case CMSG_BLKIF_BE_VBD_CREATE:
|
||||
vbd_create((blkif_be_vbd_create_t *)&msg->msg[0]);
|
||||
break;
|
||||
case CMSG_BLKIF_BE_VBD_DESTROY:
|
||||
vbd_destroy((blkif_be_vbd_destroy_t *)&msg->msg[0]);
|
||||
break;
|
||||
default:
|
||||
DPRINTK("Parse error while reading message subtype %d, len %d\n",
|
||||
msg->subtype, msg->length);
|
||||
msg->length = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ctrl_if_send_response(msg);
|
||||
}
|
||||
|
||||
void blkif_ctrlif_init(void)
|
||||
{
|
||||
ctrl_msg_t cmsg;
|
||||
blkif_be_driver_status_t st;
|
||||
|
||||
(void)ctrl_if_register_receiver(CMSG_BLKIF_BE, blkif_ctrlif_rx,
|
||||
CALLBACK_IN_BLOCKING_CONTEXT);
|
||||
|
||||
/* Send a driver-UP notification to the domain controller. */
|
||||
cmsg.type = CMSG_BLKIF_BE;
|
||||
cmsg.subtype = CMSG_BLKIF_BE_DRIVER_STATUS;
|
||||
cmsg.length = sizeof(blkif_be_driver_status_t);
|
||||
st.status = BLKIF_DRIVER_STATUS_UP;
|
||||
memcpy(cmsg.msg, &st, sizeof(st));
|
||||
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
@@ -7,46 +7,149 @@
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <asm-xen/ctrl_if.h>
|
||||
#include <asm-xen/evtchn.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
|
||||
#endif
|
||||
|
||||
#define BLKIF_HASHSZ 1024
|
||||
#define BLKIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(BLKIF_HASHSZ-1))
|
||||
#define BLKIF_HASH(_d) (((int)(_d))&(BLKIF_HASHSZ-1))
|
||||
|
||||
static kmem_cache_t *blkif_cachep;
|
||||
static blkif_t *blkif_hash[BLKIF_HASHSZ];
|
||||
|
||||
blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle)
|
||||
blkif_t *blkif_find(domid_t domid)
|
||||
{
|
||||
blkif_t *blkif = blkif_hash[BLKIF_HASH(domid, handle)];
|
||||
while ( (blkif != NULL) &&
|
||||
((blkif->domid != domid) || (blkif->handle != handle)) )
|
||||
blkif_t *blkif = blkif_hash[BLKIF_HASH(domid)];
|
||||
|
||||
while (blkif) {
|
||||
if (blkif->domid == domid) {
|
||||
blkif_get(blkif);
|
||||
return blkif;
|
||||
}
|
||||
blkif = blkif->hash_next;
|
||||
}
|
||||
|
||||
blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
|
||||
if (!blkif)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
memset(blkif, 0, sizeof(*blkif));
|
||||
blkif->domid = domid;
|
||||
blkif->status = DISCONNECTED;
|
||||
spin_lock_init(&blkif->vbd_lock);
|
||||
spin_lock_init(&blkif->blk_ring_lock);
|
||||
atomic_set(&blkif->refcnt, 1);
|
||||
|
||||
blkif->hash_next = blkif_hash[BLKIF_HASH(domid)];
|
||||
blkif_hash[BLKIF_HASH(domid)] = blkif;
|
||||
return blkif;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_XEN_BLKDEV_GRANT
|
||||
static int map_frontend_page(blkif_t *blkif, unsigned long localaddr,
|
||||
unsigned long shared_page)
|
||||
{
|
||||
return direct_remap_area_pages(&init_mm, localaddr,
|
||||
shared_page<<PAGE_SHIFT, PAGE_SIZE,
|
||||
__pgprot(_KERNPG_TABLE), blkif->domid);
|
||||
}
|
||||
|
||||
static void unmap_frontend_page(blkif_t *blkif)
|
||||
{
|
||||
}
|
||||
#else
|
||||
static int map_frontend_page(blkif_t *blkif, unsigned long localaddr,
|
||||
unsigned long shared_page)
|
||||
{
|
||||
struct gnttab_map_grant_ref op;
|
||||
op.host_addr = localaddr;
|
||||
op.flags = GNTMAP_host_map;
|
||||
op.ref = shared_page;
|
||||
op.dom = blkif->domid;
|
||||
|
||||
BUG_ON( HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) );
|
||||
|
||||
if (op.handle < 0) {
|
||||
DPRINTK(" Grant table operation failure !\n");
|
||||
return op.handle;
|
||||
}
|
||||
|
||||
blkif->shmem_ref = shared_page;
|
||||
blkif->shmem_handle = op.handle;
|
||||
blkif->shmem_vaddr = localaddr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unmap_frontend_page(blkif_t *blkif)
|
||||
{
|
||||
struct gnttab_unmap_grant_ref op;
|
||||
|
||||
op.host_addr = blkif->shmem_vaddr;
|
||||
op.handle = blkif->shmem_handle;
|
||||
op.dev_bus_addr = 0;
|
||||
BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
|
||||
}
|
||||
#endif /* CONFIG_XEN_BLKDEV_GRANT */
|
||||
|
||||
int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
|
||||
{
|
||||
struct vm_struct *vma;
|
||||
blkif_sring_t *sring;
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain };
|
||||
int err;
|
||||
|
||||
BUG_ON(blkif->remote_evtchn);
|
||||
|
||||
if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
|
||||
return -ENOMEM;
|
||||
|
||||
err = map_frontend_page(blkif, VMALLOC_VMADDR(vma->addr), shared_page);
|
||||
if (err) {
|
||||
vfree(vma->addr);
|
||||
return err;
|
||||
}
|
||||
|
||||
op.u.bind_interdomain.dom1 = DOMID_SELF;
|
||||
op.u.bind_interdomain.dom2 = blkif->domid;
|
||||
op.u.bind_interdomain.port1 = 0;
|
||||
op.u.bind_interdomain.port2 = evtchn;
|
||||
err = HYPERVISOR_event_channel_op(&op);
|
||||
if (err) {
|
||||
unmap_frontend_page(blkif);
|
||||
vfree(vma->addr);
|
||||
return err;
|
||||
}
|
||||
|
||||
blkif->evtchn = op.u.bind_interdomain.port1;
|
||||
blkif->remote_evtchn = evtchn;
|
||||
|
||||
sring = (blkif_sring_t *)vma->addr;
|
||||
SHARED_RING_INIT(sring);
|
||||
BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
|
||||
|
||||
bind_evtchn_to_irqhandler(blkif->evtchn, blkif_be_int, 0, "blkif-backend",
|
||||
blkif);
|
||||
blkif->status = CONNECTED;
|
||||
blkif->shmem_frame = shared_page;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __blkif_disconnect_complete(void *arg)
|
||||
{
|
||||
blkif_t *blkif = (blkif_t *)arg;
|
||||
ctrl_msg_t cmsg;
|
||||
blkif_be_disconnect_t disc;
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
struct gnttab_unmap_grant_ref op;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These can't be done in blkif_disconnect() because at that point there
|
||||
* may be outstanding requests at the disc whose asynchronous responses
|
||||
* must still be notified to the remote driver.
|
||||
*/
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
op.host_addr = blkif->shmem_vaddr;
|
||||
op.handle = blkif->shmem_handle;
|
||||
op.dev_bus_addr = 0;
|
||||
BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
|
||||
#endif
|
||||
unmap_frontend_page(blkif);
|
||||
vfree(blkif->blk_ring.sring);
|
||||
|
||||
/* Construct the deferred response message. */
|
||||
@@ -81,200 +184,35 @@ void blkif_disconnect_complete(blkif_t *blkif)
|
||||
schedule_work(&blkif->work);
|
||||
}
|
||||
|
||||
void blkif_create(blkif_be_create_t *create)
|
||||
void free_blkif(blkif_t *blkif)
|
||||
{
|
||||
domid_t domid = create->domid;
|
||||
unsigned int handle = create->blkif_handle;
|
||||
blkif_t **pblkif, *blkif;
|
||||
blkif_t **pblkif;
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_close };
|
||||
|
||||
if ( (blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL)) == NULL )
|
||||
{
|
||||
DPRINTK("Could not create blkif: out of memory\n");
|
||||
create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
|
||||
return;
|
||||
op.u.close.port = blkif->evtchn;
|
||||
op.u.close.dom = DOMID_SELF;
|
||||
HYPERVISOR_event_channel_op(&op);
|
||||
op.u.close.port = blkif->remote_evtchn;
|
||||
op.u.close.dom = blkif->domid;
|
||||
HYPERVISOR_event_channel_op(&op);
|
||||
|
||||
if (blkif->evtchn)
|
||||
unbind_evtchn_from_irqhandler(blkif->evtchn, blkif);
|
||||
|
||||
if (blkif->blk_ring.sring) {
|
||||
unmap_frontend_page(blkif);
|
||||
vfree(blkif->blk_ring.sring);
|
||||
}
|
||||
|
||||
memset(blkif, 0, sizeof(*blkif));
|
||||
blkif->domid = domid;
|
||||
blkif->handle = handle;
|
||||
blkif->status = DISCONNECTED;
|
||||
spin_lock_init(&blkif->vbd_lock);
|
||||
spin_lock_init(&blkif->blk_ring_lock);
|
||||
atomic_set(&blkif->refcnt, 0);
|
||||
|
||||
pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
|
||||
while ( *pblkif != NULL )
|
||||
pblkif = &blkif_hash[BLKIF_HASH(blkif->domid)];
|
||||
while ( *pblkif != blkif )
|
||||
{
|
||||
if ( ((*pblkif)->domid == domid) && ((*pblkif)->handle == handle) )
|
||||
{
|
||||
DPRINTK("Could not create blkif: already exists\n");
|
||||
create->status = BLKIF_BE_STATUS_INTERFACE_EXISTS;
|
||||
kmem_cache_free(blkif_cachep, blkif);
|
||||
return;
|
||||
}
|
||||
BUG_ON(!*pblkif);
|
||||
pblkif = &(*pblkif)->hash_next;
|
||||
}
|
||||
|
||||
blkif->hash_next = *pblkif;
|
||||
*pblkif = blkif;
|
||||
|
||||
DPRINTK("Successfully created blkif\n");
|
||||
create->status = BLKIF_BE_STATUS_OKAY;
|
||||
}
|
||||
|
||||
void blkif_destroy(blkif_be_destroy_t *destroy)
|
||||
{
|
||||
domid_t domid = destroy->domid;
|
||||
unsigned int handle = destroy->blkif_handle;
|
||||
blkif_t **pblkif, *blkif;
|
||||
|
||||
pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
|
||||
while ( (blkif = *pblkif) != NULL )
|
||||
{
|
||||
if ( (blkif->domid == domid) && (blkif->handle == handle) )
|
||||
{
|
||||
if ( blkif->status != DISCONNECTED )
|
||||
goto still_connected;
|
||||
goto destroy;
|
||||
}
|
||||
pblkif = &blkif->hash_next;
|
||||
}
|
||||
|
||||
destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
|
||||
return;
|
||||
|
||||
still_connected:
|
||||
destroy->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
|
||||
return;
|
||||
|
||||
destroy:
|
||||
*pblkif = blkif->hash_next;
|
||||
destroy_all_vbds(blkif);
|
||||
kmem_cache_free(blkif_cachep, blkif);
|
||||
destroy->status = BLKIF_BE_STATUS_OKAY;
|
||||
}
|
||||
|
||||
void blkif_connect(blkif_be_connect_t *connect)
|
||||
{
|
||||
domid_t domid = connect->domid;
|
||||
unsigned int handle = connect->blkif_handle;
|
||||
unsigned int evtchn = connect->evtchn;
|
||||
unsigned long shmem_frame = connect->shmem_frame;
|
||||
struct vm_struct *vma;
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
int ref = connect->shmem_ref;
|
||||
#else
|
||||
pgprot_t prot;
|
||||
int error;
|
||||
#endif
|
||||
blkif_t *blkif;
|
||||
blkif_sring_t *sring;
|
||||
|
||||
blkif = blkif_find_by_handle(domid, handle);
|
||||
if ( unlikely(blkif == NULL) )
|
||||
{
|
||||
DPRINTK("blkif_connect attempted for non-existent blkif (%u,%u)\n",
|
||||
connect->domid, connect->blkif_handle);
|
||||
connect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
|
||||
{
|
||||
connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_XEN_BLKDEV_GRANT
|
||||
prot = __pgprot(_KERNPG_TABLE);
|
||||
error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr),
|
||||
shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
|
||||
prot, domid);
|
||||
if ( error != 0 )
|
||||
{
|
||||
if ( error == -ENOMEM )
|
||||
connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
|
||||
else if ( error == -EFAULT )
|
||||
connect->status = BLKIF_BE_STATUS_MAPPING_ERROR;
|
||||
else
|
||||
connect->status = BLKIF_BE_STATUS_ERROR;
|
||||
vfree(vma->addr);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
{ /* Map: Use the Grant table reference */
|
||||
struct gnttab_map_grant_ref op;
|
||||
op.host_addr = VMALLOC_VMADDR(vma->addr);
|
||||
op.flags = GNTMAP_host_map;
|
||||
op.ref = ref;
|
||||
op.dom = domid;
|
||||
|
||||
BUG_ON( HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) );
|
||||
|
||||
handle = op.handle;
|
||||
|
||||
if (op.handle < 0) {
|
||||
DPRINTK(" Grant table operation failure !\n");
|
||||
connect->status = BLKIF_BE_STATUS_MAPPING_ERROR;
|
||||
vfree(vma->addr);
|
||||
return;
|
||||
}
|
||||
|
||||
blkif->shmem_ref = ref;
|
||||
blkif->shmem_handle = handle;
|
||||
blkif->shmem_vaddr = VMALLOC_VMADDR(vma->addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( blkif->status != DISCONNECTED )
|
||||
{
|
||||
connect->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
|
||||
vfree(vma->addr);
|
||||
return;
|
||||
}
|
||||
sring = (blkif_sring_t *)vma->addr;
|
||||
SHARED_RING_INIT(sring);
|
||||
BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
|
||||
|
||||
blkif->evtchn = evtchn;
|
||||
blkif->shmem_frame = shmem_frame;
|
||||
blkif->status = CONNECTED;
|
||||
blkif_get(blkif);
|
||||
|
||||
bind_evtchn_to_irqhandler(
|
||||
blkif->evtchn, blkif_be_int, 0, "blkif-backend", blkif);
|
||||
|
||||
connect->status = BLKIF_BE_STATUS_OKAY;
|
||||
}
|
||||
|
||||
int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id)
|
||||
{
|
||||
domid_t domid = disconnect->domid;
|
||||
unsigned int handle = disconnect->blkif_handle;
|
||||
blkif_t *blkif;
|
||||
|
||||
blkif = blkif_find_by_handle(domid, handle);
|
||||
if ( unlikely(blkif == NULL) )
|
||||
{
|
||||
DPRINTK("blkif_disconnect attempted for non-existent blkif"
|
||||
" (%u,%u)\n", disconnect->domid, disconnect->blkif_handle);
|
||||
disconnect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
|
||||
return 1; /* Caller will send response error message. */
|
||||
}
|
||||
|
||||
if ( blkif->status == CONNECTED )
|
||||
{
|
||||
blkif->status = DISCONNECTING;
|
||||
blkif->disconnect_rspid = rsp_id;
|
||||
wmb(); /* Let other CPUs see the status change. */
|
||||
unbind_evtchn_from_irqhandler(blkif->evtchn, blkif);
|
||||
blkif_deschedule(blkif);
|
||||
blkif_put(blkif);
|
||||
return 0; /* Caller should not send response message. */
|
||||
}
|
||||
|
||||
disconnect->status = BLKIF_BE_STATUS_OKAY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __init blkif_interface_init(void)
|
||||
|
||||
@@ -11,13 +11,16 @@
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <asm-xen/xenbus.h>
|
||||
|
||||
struct vbd {
|
||||
blkif_vdev_t vdevice; /* what the domain refers to this vbd as */
|
||||
blkif_vdev_t handle; /* what the domain refers to this vbd as */
|
||||
unsigned char readonly; /* Non-zero -> read-only */
|
||||
unsigned char type; /* VDISK_xxx */
|
||||
blkif_pdev_t pdevice; /* phys device that this vbd maps to */
|
||||
struct block_device *bdev;
|
||||
|
||||
int active;
|
||||
rb_node_t rb; /* for linking into R-B tree lookup struct */
|
||||
};
|
||||
|
||||
@@ -33,57 +36,45 @@ static inline dev_t vbd_map_devnum(blkif_pdev_t cookie)
|
||||
#define bdev_hardsect_size(_b) 512
|
||||
#endif
|
||||
|
||||
void vbd_create(blkif_be_vbd_create_t *create)
|
||||
unsigned long vbd_size(struct vbd *vbd)
|
||||
{
|
||||
return vbd_sz(vbd);
|
||||
}
|
||||
|
||||
unsigned int vbd_info(struct vbd *vbd)
|
||||
{
|
||||
return vbd->type | (vbd->readonly?VDISK_READONLY:0);
|
||||
}
|
||||
|
||||
unsigned long vbd_secsize(struct vbd *vbd)
|
||||
{
|
||||
return bdev_hardsect_size(vbd->bdev);
|
||||
}
|
||||
|
||||
int vbd_is_active(struct vbd *vbd)
|
||||
{
|
||||
return vbd->active;
|
||||
}
|
||||
|
||||
struct vbd *vbd_create(blkif_t *blkif, blkif_vdev_t handle,
|
||||
blkif_pdev_t pdevice, int readonly)
|
||||
{
|
||||
struct vbd *vbd;
|
||||
rb_node_t **rb_p, *rb_parent = NULL;
|
||||
blkif_t *blkif;
|
||||
blkif_vdev_t vdevice = create->vdevice;
|
||||
|
||||
blkif = blkif_find_by_handle(create->domid, create->blkif_handle);
|
||||
if ( unlikely(blkif == NULL) )
|
||||
{
|
||||
DPRINTK("vbd_create attempted for non-existent blkif (%u,%u)\n",
|
||||
create->domid, create->blkif_handle);
|
||||
create->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
|
||||
rb_p = &blkif->vbd_rb.rb_node;
|
||||
while ( *rb_p != NULL )
|
||||
{
|
||||
rb_parent = *rb_p;
|
||||
vbd = rb_entry(rb_parent, struct vbd, rb);
|
||||
if ( vdevice < vbd->vdevice )
|
||||
{
|
||||
rb_p = &rb_parent->rb_left;
|
||||
}
|
||||
else if ( vdevice > vbd->vdevice )
|
||||
{
|
||||
rb_p = &rb_parent->rb_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTK("vbd_create attempted for already existing vbd\n");
|
||||
create->status = BLKIF_BE_STATUS_VBD_EXISTS;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( unlikely((vbd = kmalloc(sizeof(struct vbd), GFP_KERNEL)) == NULL) )
|
||||
{
|
||||
DPRINTK("vbd_create: out of memory\n");
|
||||
create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
|
||||
return;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
vbd->vdevice = vdevice;
|
||||
vbd->readonly = create->readonly;
|
||||
vbd->handle = handle;
|
||||
vbd->readonly = readonly;
|
||||
vbd->type = 0;
|
||||
vbd->active = 0;
|
||||
|
||||
/* Mask to 16-bit for compatibility with old tools */
|
||||
vbd->pdevice = create->pdevice & 0xffff;
|
||||
vbd->pdevice = pdevice;
|
||||
|
||||
/* FIXME: Who frees vbd on failure? --RR */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
vbd->bdev = open_by_devnum(
|
||||
vbd_map_devnum(vbd->pdevice),
|
||||
@@ -91,16 +82,14 @@ void vbd_create(blkif_be_vbd_create_t *create)
|
||||
if ( IS_ERR(vbd->bdev) )
|
||||
{
|
||||
DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
|
||||
create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
|
||||
return;
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
if ( (vbd->bdev->bd_disk == NULL) )
|
||||
{
|
||||
DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
|
||||
create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
|
||||
bdev_put(vbd->bdev);
|
||||
return;
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
if ( vbd->bdev->bd_disk->flags & GENHD_FL_CD )
|
||||
@@ -112,62 +101,64 @@ void vbd_create(blkif_be_vbd_create_t *create)
|
||||
if ( (blk_size[MAJOR(vbd->pdevice)] == NULL) || (vbd_sz(vbd) == 0) )
|
||||
{
|
||||
DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
|
||||
create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
|
||||
return;
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
|
||||
handle, blkif->domid);
|
||||
return vbd;
|
||||
}
|
||||
|
||||
void vbd_activate(blkif_t *blkif, struct vbd *vbd)
|
||||
{
|
||||
rb_node_t **rb_p, *rb_parent = NULL;
|
||||
struct vbd *i;
|
||||
BUG_ON(vbd_is_active(vbd));
|
||||
|
||||
/* Find where to put it. */
|
||||
rb_p = &blkif->vbd_rb.rb_node;
|
||||
while ( *rb_p != NULL )
|
||||
{
|
||||
rb_parent = *rb_p;
|
||||
i = rb_entry(rb_parent, struct vbd, rb);
|
||||
if ( vbd->handle < i->handle )
|
||||
{
|
||||
rb_p = &rb_parent->rb_left;
|
||||
}
|
||||
else if ( vbd->handle > i->handle )
|
||||
{
|
||||
rb_p = &rb_parent->rb_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We never create two of same vbd, so not possible. */
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we're active. */
|
||||
vbd->active = 1;
|
||||
blkif_get(blkif);
|
||||
|
||||
spin_lock(&blkif->vbd_lock);
|
||||
rb_link_node(&vbd->rb, rb_parent, rb_p);
|
||||
rb_insert_color(&vbd->rb, &blkif->vbd_rb);
|
||||
spin_unlock(&blkif->vbd_lock);
|
||||
|
||||
DPRINTK("Successful creation of vdev=%04x (dom=%u)\n",
|
||||
vdevice, create->domid);
|
||||
create->status = BLKIF_BE_STATUS_OKAY;
|
||||
}
|
||||
|
||||
|
||||
void vbd_destroy(blkif_be_vbd_destroy_t *destroy)
|
||||
void vbd_free(blkif_t *blkif, struct vbd *vbd)
|
||||
{
|
||||
blkif_t *blkif;
|
||||
struct vbd *vbd;
|
||||
rb_node_t *rb;
|
||||
blkif_vdev_t vdevice = destroy->vdevice;
|
||||
|
||||
blkif = blkif_find_by_handle(destroy->domid, destroy->blkif_handle);
|
||||
if ( unlikely(blkif == NULL) )
|
||||
{
|
||||
DPRINTK("vbd_destroy attempted for non-existent blkif (%u,%u)\n",
|
||||
destroy->domid, destroy->blkif_handle);
|
||||
destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
|
||||
return;
|
||||
if (vbd_is_active(vbd)) {
|
||||
spin_lock(&blkif->vbd_lock);
|
||||
rb_erase(&vbd->rb, &blkif->vbd_rb);
|
||||
spin_unlock(&blkif->vbd_lock);
|
||||
blkif_put(blkif);
|
||||
}
|
||||
|
||||
rb = blkif->vbd_rb.rb_node;
|
||||
while ( rb != NULL )
|
||||
{
|
||||
vbd = rb_entry(rb, struct vbd, rb);
|
||||
if ( vdevice < vbd->vdevice )
|
||||
rb = rb->rb_left;
|
||||
else if ( vdevice > vbd->vdevice )
|
||||
rb = rb->rb_right;
|
||||
else
|
||||
goto found;
|
||||
}
|
||||
|
||||
destroy->status = BLKIF_BE_STATUS_VBD_NOT_FOUND;
|
||||
return;
|
||||
|
||||
found:
|
||||
spin_lock(&blkif->vbd_lock);
|
||||
rb_erase(rb, &blkif->vbd_rb);
|
||||
spin_unlock(&blkif->vbd_lock);
|
||||
bdev_put(vbd->bdev);
|
||||
kfree(vbd);
|
||||
}
|
||||
|
||||
|
||||
void destroy_all_vbds(blkif_t *blkif)
|
||||
{
|
||||
struct vbd *vbd;
|
||||
@@ -183,74 +174,12 @@ void destroy_all_vbds(blkif_t *blkif)
|
||||
bdev_put(vbd->bdev);
|
||||
kfree(vbd);
|
||||
spin_lock(&blkif->vbd_lock);
|
||||
blkif_put(blkif);
|
||||
}
|
||||
|
||||
spin_unlock(&blkif->vbd_lock);
|
||||
}
|
||||
|
||||
|
||||
static void vbd_probe_single(
|
||||
blkif_t *blkif, vdisk_t *vbd_info, struct vbd *vbd)
|
||||
{
|
||||
vbd_info->device = vbd->vdevice;
|
||||
vbd_info->info = vbd->type | (vbd->readonly ? VDISK_READONLY : 0);
|
||||
vbd_info->capacity = vbd_sz(vbd);
|
||||
vbd_info->sector_size = bdev_hardsect_size(vbd->bdev);
|
||||
}
|
||||
|
||||
|
||||
int vbd_probe(blkif_t *blkif, vdisk_t *vbd_info, int max_vbds)
|
||||
{
|
||||
int rc = 0, nr_vbds = 0;
|
||||
rb_node_t *rb;
|
||||
|
||||
spin_lock(&blkif->vbd_lock);
|
||||
|
||||
if ( (rb = blkif->vbd_rb.rb_node) == NULL )
|
||||
goto out;
|
||||
|
||||
new_subtree:
|
||||
/* STEP 1. Find least node (it'll be left-most). */
|
||||
while ( rb->rb_left != NULL )
|
||||
rb = rb->rb_left;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
/* STEP 2. Dealt with left subtree. Now process current node. */
|
||||
vbd_probe_single(blkif, &vbd_info[nr_vbds],
|
||||
rb_entry(rb, struct vbd, rb));
|
||||
if ( ++nr_vbds == max_vbds )
|
||||
goto out;
|
||||
|
||||
/* STEP 3. Process right subtree, if any. */
|
||||
if ( rb->rb_right != NULL )
|
||||
{
|
||||
rb = rb->rb_right;
|
||||
goto new_subtree;
|
||||
}
|
||||
|
||||
/* STEP 4. Done both subtrees. Head back through ancesstors. */
|
||||
for ( ; ; )
|
||||
{
|
||||
/* We're done when we get back to the root node. */
|
||||
if ( rb->rb_parent == NULL )
|
||||
goto out;
|
||||
/* If we are left of parent, then parent is next to process. */
|
||||
if ( rb->rb_parent->rb_left == rb )
|
||||
break;
|
||||
/* If we are right of parent, then we climb to grandparent. */
|
||||
rb = rb->rb_parent;
|
||||
}
|
||||
|
||||
rb = rb->rb_parent;
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&blkif->vbd_lock);
|
||||
return (rc == 0) ? nr_vbds : rc;
|
||||
}
|
||||
|
||||
|
||||
int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
|
||||
{
|
||||
struct vbd *vbd;
|
||||
@@ -264,9 +193,9 @@ int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
|
||||
while ( rb != NULL )
|
||||
{
|
||||
vbd = rb_entry(rb, struct vbd, rb);
|
||||
if ( req->dev < vbd->vdevice )
|
||||
if ( req->dev < vbd->handle )
|
||||
rb = rb->rb_left;
|
||||
else if ( req->dev > vbd->vdevice )
|
||||
else if ( req->dev > vbd->handle )
|
||||
rb = rb->rb_right;
|
||||
else
|
||||
goto found;
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
/* Xenbus code for blkif backend
|
||||
Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm-xen/xenbus.h>
|
||||
#include "common.h"
|
||||
|
||||
struct backend_info
|
||||
{
|
||||
struct xenbus_device *dev;
|
||||
|
||||
/* our communications channel */
|
||||
blkif_t *blkif;
|
||||
struct vbd *vbd;
|
||||
|
||||
long int frontend_id;
|
||||
long int pdev;
|
||||
long int readonly;
|
||||
|
||||
/* watch back end for changes */
|
||||
struct xenbus_watch backend_watch;
|
||||
|
||||
/* watch front end for changes */
|
||||
struct xenbus_watch watch;
|
||||
char *frontpath;
|
||||
};
|
||||
|
||||
static int blkback_remove(struct xenbus_device *dev)
|
||||
{
|
||||
struct backend_info *be = dev->data;
|
||||
|
||||
if (be->watch.node)
|
||||
unregister_xenbus_watch(&be->watch);
|
||||
unregister_xenbus_watch(&be->backend_watch);
|
||||
if (be->vbd)
|
||||
vbd_free(be->blkif, be->vbd);
|
||||
if (be->blkif)
|
||||
blkif_put(be->blkif);
|
||||
if (be->frontpath)
|
||||
kfree(be->frontpath);
|
||||
kfree(be);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Front end tells us frame. */
|
||||
static void frontend_changed(struct xenbus_watch *watch, const char *node)
|
||||
{
|
||||
unsigned long sharedmfn;
|
||||
unsigned int evtchn;
|
||||
int err;
|
||||
struct backend_info *be
|
||||
= container_of(watch, struct backend_info, watch);
|
||||
|
||||
/* If other end is gone, delete ourself. */
|
||||
if (!xenbus_exists(be->frontpath, "")) {
|
||||
xenbus_rm(be->dev->nodename, "");
|
||||
device_unregister(&be->dev->dev);
|
||||
return;
|
||||
}
|
||||
if (vbd_is_active(be->vbd))
|
||||
return;
|
||||
|
||||
#ifndef CONFIG_XEN_BLKDEV_GRANT
|
||||
err = xenbus_gather(be->frontpath, "shared-frame", "%lu", &sharedmfn,
|
||||
"event-channel", "%u", &evtchn, NULL);
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err,
|
||||
"reading %s/shared-frame and event-channel",
|
||||
be->frontpath);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
err = xenbus_gather(be->frontpath, "grant-id", "%lu", &sharedmfn,
|
||||
"event-channel", "%u", &evtchn, NULL);
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err,
|
||||
"reading %s/grant-id and event-channel",
|
||||
be->frontpath);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Domains must use same shared frame for all vbds. */
|
||||
if (be->blkif->status == CONNECTED &&
|
||||
(evtchn != be->blkif->remote_evtchn ||
|
||||
sharedmfn != be->blkif->shmem_frame)) {
|
||||
xenbus_dev_error(be->dev, err,
|
||||
"Shared frame/evtchn %li/%u not same as"
|
||||
" old %li/%u",
|
||||
sharedmfn, evtchn,
|
||||
be->blkif->shmem_frame,
|
||||
be->blkif->remote_evtchn);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Supply the information about the device the frontend needs */
|
||||
err = xenbus_transaction_start(be->dev->nodename);
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err, "starting transaction");
|
||||
return;
|
||||
}
|
||||
|
||||
err = xenbus_printf(be->dev->nodename, "sectors", "%lu",
|
||||
vbd_size(be->vbd));
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err, "writing %s/sectors",
|
||||
be->dev->nodename);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* FIXME: use a typename instead */
|
||||
err = xenbus_printf(be->dev->nodename, "info", "%u",
|
||||
vbd_info(be->vbd));
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err, "writing %s/info",
|
||||
be->dev->nodename);
|
||||
goto abort;
|
||||
}
|
||||
err = xenbus_printf(be->dev->nodename, "sector-size", "%lu",
|
||||
vbd_secsize(be->vbd));
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err, "writing %s/sector-size",
|
||||
be->dev->nodename);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* First vbd? We need to map the shared frame, irq etc. */
|
||||
if (be->blkif->status != CONNECTED) {
|
||||
err = blkif_map(be->blkif, sharedmfn, evtchn);
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err,
|
||||
"mapping shared-frame %lu port %u",
|
||||
sharedmfn, evtchn);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
/* We're ready, activate. */
|
||||
vbd_activate(be->blkif, be->vbd);
|
||||
|
||||
xenbus_transaction_end(0);
|
||||
xenbus_dev_ok(be->dev);
|
||||
|
||||
return;
|
||||
|
||||
abort:
|
||||
xenbus_transaction_end(1);
|
||||
}
|
||||
|
||||
/*
|
||||
Setup supplies physical device.
|
||||
We provide event channel and device details to front end.
|
||||
Frontend supplies shared frame and event channel.
|
||||
*/
|
||||
static void backend_changed(struct xenbus_watch *watch, const char *node)
|
||||
{
|
||||
int err;
|
||||
char *p;
|
||||
char *frontend;
|
||||
long int handle, pdev;
|
||||
struct backend_info *be
|
||||
= container_of(watch, struct backend_info, backend_watch);
|
||||
struct xenbus_device *dev = be->dev;
|
||||
|
||||
frontend = NULL;
|
||||
err = xenbus_gather(dev->nodename,
|
||||
"frontend-id", "%li", &be->frontend_id,
|
||||
"frontend", NULL, &frontend,
|
||||
NULL);
|
||||
if (err == -ENOENT || err == -ERANGE ||
|
||||
strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
|
||||
if (frontend)
|
||||
kfree(frontend);
|
||||
/* If we can't get a frontend path and a frontend-id,
|
||||
* then our bus-id is no longer valid and we need to
|
||||
* destroy the backend device.
|
||||
*/
|
||||
goto device_fail;
|
||||
}
|
||||
|
||||
if (!be->frontpath || strcmp(frontend, be->frontpath)) {
|
||||
if (be->watch.node)
|
||||
unregister_xenbus_watch(&be->watch);
|
||||
if (be->frontpath)
|
||||
kfree(be->frontpath);
|
||||
be->frontpath = frontend;
|
||||
be->watch.node = be->frontpath;
|
||||
be->watch.callback = frontend_changed;
|
||||
err = register_xenbus_watch(&be->watch);
|
||||
if (err) {
|
||||
be->watch.node = NULL;
|
||||
goto device_fail;
|
||||
}
|
||||
} else
|
||||
kfree(frontend);
|
||||
|
||||
err = xenbus_scanf(dev->nodename, "physical-device", "%li", &pdev);
|
||||
if (err == -ENOENT || err == -ERANGE)
|
||||
goto out;
|
||||
if (err < 0) {
|
||||
xenbus_dev_error(dev, err, "Reading physical-device");
|
||||
goto device_fail;
|
||||
}
|
||||
if (be->pdev && be->pdev != pdev) {
|
||||
printk(KERN_WARNING
|
||||
"changing physical-device not supported\n");
|
||||
goto device_fail;
|
||||
}
|
||||
be->pdev = pdev;
|
||||
|
||||
/* If there's a read-only node, we're read only. */
|
||||
p = xenbus_read(dev->nodename, "read-only", NULL);
|
||||
if (!IS_ERR(p)) {
|
||||
be->readonly = 1;
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
if (be->blkif == NULL) {
|
||||
/* Front end dir is a number, which is used as the handle. */
|
||||
p = strrchr(be->frontpath, '/') + 1;
|
||||
handle = simple_strtoul(p, NULL, 0);
|
||||
|
||||
be->blkif = blkif_find(be->frontend_id);
|
||||
if (IS_ERR(be->blkif)) {
|
||||
err = PTR_ERR(be->blkif);
|
||||
be->blkif = NULL;
|
||||
goto device_fail;
|
||||
}
|
||||
|
||||
be->vbd = vbd_create(be->blkif, handle, be->pdev,
|
||||
be->readonly);
|
||||
if (IS_ERR(be->vbd)) {
|
||||
err = PTR_ERR(be->vbd);
|
||||
be->vbd = NULL;
|
||||
goto device_fail;
|
||||
}
|
||||
|
||||
frontend_changed(&be->watch, be->frontpath);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
device_fail:
|
||||
device_unregister(&be->dev->dev);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static int blkback_probe(struct xenbus_device *dev,
|
||||
const struct xenbus_device_id *id)
|
||||
{
|
||||
struct backend_info *be;
|
||||
int err;
|
||||
|
||||
be = kmalloc(sizeof(*be), GFP_KERNEL);
|
||||
if (!be)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(be, 0, sizeof(*be));
|
||||
|
||||
be->dev = dev;
|
||||
be->backend_watch.node = dev->nodename;
|
||||
be->backend_watch.callback = backend_changed;
|
||||
err = register_xenbus_watch(&be->backend_watch);
|
||||
if (err)
|
||||
goto free_be;
|
||||
|
||||
dev->data = be;
|
||||
|
||||
backend_changed(&be->backend_watch, dev->nodename);
|
||||
return err;
|
||||
free_be:
|
||||
kfree(be);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct xenbus_device_id blkback_ids[] = {
|
||||
{ "vbd" },
|
||||
{ "" }
|
||||
};
|
||||
|
||||
static struct xenbus_driver blkback = {
|
||||
.name = "vbd",
|
||||
.owner = THIS_MODULE,
|
||||
.ids = blkback_ids,
|
||||
.probe = blkback_probe,
|
||||
.remove = blkback_remove,
|
||||
};
|
||||
|
||||
void blkif_xenbus_init(void)
|
||||
{
|
||||
xenbus_register_backend(&blkback);
|
||||
}
|
||||
@@ -53,8 +53,8 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <asm-xen/ctrl_if.h>
|
||||
#include <asm-xen/evtchn.h>
|
||||
#include <asm-xen/xenbus.h>
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
#include <asm-xen/xen-public/grant_table.h>
|
||||
#include <asm-xen/gnttab.h>
|
||||
@@ -65,22 +65,14 @@ typedef unsigned char byte; /* from linux/ide.h */
|
||||
/* Control whether runtime update of vbds is enabled. */
|
||||
#define ENABLE_VBD_UPDATE 1
|
||||
|
||||
#if ENABLE_VBD_UPDATE
|
||||
static void vbd_update(void);
|
||||
#else
|
||||
static void vbd_update(void){};
|
||||
#endif
|
||||
|
||||
#define BLKIF_STATE_CLOSED 0
|
||||
#define BLKIF_STATE_DISCONNECTED 1
|
||||
#define BLKIF_STATE_CONNECTED 2
|
||||
|
||||
static int blkif_handle = 0;
|
||||
static unsigned int blkif_state = BLKIF_STATE_CLOSED;
|
||||
static unsigned int blkif_evtchn = 0;
|
||||
|
||||
static int blkif_control_rsp_valid;
|
||||
static blkif_response_t blkif_control_rsp;
|
||||
static unsigned int blkif_vbds = 0;
|
||||
static unsigned int blkif_vbds_connected = 0;
|
||||
|
||||
static blkif_front_ring_t blk_ring;
|
||||
|
||||
@@ -92,6 +84,7 @@ static grant_ref_t gref_head, gref_terminal;
|
||||
#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
|
||||
(BLKIF_MAX_SEGMENTS_PER_REQUEST * BLKIF_RING_SIZE)
|
||||
#define GRANTREF_INVALID (1<<15)
|
||||
static int shmem_ref;
|
||||
#endif
|
||||
|
||||
static struct blk_shadow {
|
||||
@@ -105,7 +98,7 @@ static int recovery = 0; /* Recovery in progress: protected by blkif_io_lock */
|
||||
|
||||
static void kick_pending_request_queues(void);
|
||||
|
||||
int __init xlblk_init(void);
|
||||
static int __init xlblk_init(void);
|
||||
|
||||
static void blkif_completion(struct blk_shadow *s);
|
||||
|
||||
@@ -179,19 +172,6 @@ static inline void flush_requests(void)
|
||||
|
||||
module_init(xlblk_init);
|
||||
|
||||
#if ENABLE_VBD_UPDATE
|
||||
static void update_vbds_task(void *unused)
|
||||
{
|
||||
xlvbd_update_vbds();
|
||||
}
|
||||
|
||||
static void vbd_update(void)
|
||||
{
|
||||
static DECLARE_WORK(update_tq, update_vbds_task, NULL);
|
||||
schedule_work(&update_tq);
|
||||
}
|
||||
#endif /* ENABLE_VBD_UPDATE */
|
||||
|
||||
static struct xlbd_disk_info *head_waiting = NULL;
|
||||
static void kick_pending_request_queues(void)
|
||||
{
|
||||
@@ -221,16 +201,7 @@ int blkif_open(struct inode *inode, struct file *filep)
|
||||
|
||||
int blkif_release(struct inode *inode, struct file *filep)
|
||||
{
|
||||
struct gendisk *gd = inode->i_bdev->bd_disk;
|
||||
struct xlbd_disk_info *di = (struct xlbd_disk_info *)gd->private_data;
|
||||
|
||||
/*
|
||||
* When usage drops to zero it may allow more VBD updates to occur.
|
||||
* Update of usage count is protected by a per-device semaphore.
|
||||
*/
|
||||
if ( --di->mi->usage == 0 )
|
||||
vbd_update();
|
||||
|
||||
/* FIXME: This is where we can actually free up majors, etc. --RR */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -301,7 +272,7 @@ static int blkif_queue_request(struct request *req)
|
||||
ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE :
|
||||
BLKIF_OP_READ;
|
||||
ring_req->sector_number = (blkif_sector_t)req->sector;
|
||||
ring_req->device = di->xd_device;
|
||||
ring_req->handle = di->handle;
|
||||
|
||||
ring_req->nr_segments = 0;
|
||||
rq_for_each_bio(bio, req)
|
||||
@@ -445,10 +416,6 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
BUG();
|
||||
end_that_request_last(req);
|
||||
|
||||
break;
|
||||
case BLKIF_OP_PROBE:
|
||||
memcpy(&blkif_control_rsp, bret, sizeof(*bret));
|
||||
blkif_control_rsp_valid = 1;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
@@ -483,28 +450,6 @@ static int nr_pending;
|
||||
#define blkif_io_lock io_request_lock
|
||||
|
||||
/*============================================================================*/
|
||||
#if ENABLE_VBD_UPDATE
|
||||
|
||||
/*
|
||||
* blkif_update_int/update-vbds_task - handle VBD update events.
|
||||
* Schedule a task for keventd to run, which will update the VBDs and perform
|
||||
* the corresponding updates to our view of VBD state.
|
||||
*/
|
||||
static void update_vbds_task(void *unused)
|
||||
{
|
||||
xlvbd_update_vbds();
|
||||
}
|
||||
|
||||
static void vbd_update(void)
|
||||
{
|
||||
static struct tq_struct update_tq;
|
||||
update_tq.routine = update_vbds_task;
|
||||
schedule_task(&update_tq);
|
||||
}
|
||||
|
||||
#endif /* ENABLE_VBD_UPDATE */
|
||||
/*============================================================================*/
|
||||
|
||||
static void kick_pending_request_queues(void)
|
||||
{
|
||||
/* We kick pending request queues if the ring is reasonably empty. */
|
||||
@@ -757,7 +702,8 @@ static int blkif_queue_request(unsigned long id,
|
||||
char * buffer,
|
||||
unsigned long sector_number,
|
||||
unsigned short nr_sectors,
|
||||
kdev_t device)
|
||||
kdev_t device,
|
||||
blkif_vdev_t handle)
|
||||
{
|
||||
unsigned long buffer_ma = virt_to_bus(buffer);
|
||||
unsigned long xid;
|
||||
@@ -871,7 +817,7 @@ static int blkif_queue_request(unsigned long id,
|
||||
req->id = xid;
|
||||
req->operation = operation;
|
||||
req->sector_number = (blkif_sector_t)sector_number;
|
||||
req->device = device;
|
||||
req->handle = handle;
|
||||
req->nr_segments = 1;
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
/* install a grant reference. */
|
||||
@@ -1047,108 +993,10 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
|
||||
/***************************** COMMON CODE *******************************/
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
void blkif_control_probe_send(blkif_request_t *req, blkif_response_t *rsp,
|
||||
unsigned long address)
|
||||
{
|
||||
int ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
|
||||
ASSERT( ref != -ENOSPC );
|
||||
|
||||
gnttab_grant_foreign_access_ref( ref, rdomid, address >> PAGE_SHIFT, 0 );
|
||||
|
||||
req->frame_and_sects[0] = blkif_fas_from_gref(ref, 0, (PAGE_SIZE/512)-1);
|
||||
|
||||
blkif_control_send(req, rsp);
|
||||
}
|
||||
#endif
|
||||
|
||||
void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp)
|
||||
{
|
||||
unsigned long flags, id;
|
||||
blkif_request_t *req_d;
|
||||
|
||||
retry:
|
||||
while ( RING_FULL(&blk_ring) )
|
||||
{
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(1);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&blkif_io_lock, flags);
|
||||
if ( RING_FULL(&blk_ring) )
|
||||
{
|
||||
spin_unlock_irqrestore(&blkif_io_lock, flags);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
DISABLE_SCATTERGATHER();
|
||||
req_d = RING_GET_REQUEST(&blk_ring, blk_ring.req_prod_pvt);
|
||||
*req_d = *req;
|
||||
|
||||
id = GET_ID_FROM_FREELIST();
|
||||
req_d->id = id;
|
||||
blk_shadow[id].request = (unsigned long)req;
|
||||
|
||||
pickle_request(&blk_shadow[id], req);
|
||||
|
||||
blk_ring.req_prod_pvt++;
|
||||
flush_requests();
|
||||
|
||||
spin_unlock_irqrestore(&blkif_io_lock, flags);
|
||||
|
||||
while ( !blkif_control_rsp_valid )
|
||||
{
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(1);
|
||||
}
|
||||
|
||||
memcpy(rsp, &blkif_control_rsp, sizeof(*rsp));
|
||||
blkif_control_rsp_valid = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Send a driver status notification to the domain controller. */
|
||||
static void send_driver_status(int ok)
|
||||
{
|
||||
ctrl_msg_t cmsg = {
|
||||
.type = CMSG_BLKIF_FE,
|
||||
.subtype = CMSG_BLKIF_FE_DRIVER_STATUS,
|
||||
.length = sizeof(blkif_fe_driver_status_t),
|
||||
};
|
||||
blkif_fe_driver_status_t *msg = (void*)cmsg.msg;
|
||||
|
||||
msg->status = (ok ? BLKIF_DRIVER_STATUS_UP : BLKIF_DRIVER_STATUS_DOWN);
|
||||
|
||||
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
|
||||
/* Tell the controller to bring up the interface. */
|
||||
static void blkif_send_interface_connect(void)
|
||||
{
|
||||
ctrl_msg_t cmsg = {
|
||||
.type = CMSG_BLKIF_FE,
|
||||
.subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT,
|
||||
.length = sizeof(blkif_fe_interface_connect_t),
|
||||
};
|
||||
blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
|
||||
|
||||
msg->handle = 0;
|
||||
msg->shmem_frame = (virt_to_machine(blk_ring.sring) >> PAGE_SHIFT);
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
msg->shmem_ref = gnttab_claim_grant_reference( &gref_head, gref_terminal );
|
||||
ASSERT( msg->shmem_ref != -ENOSPC );
|
||||
gnttab_grant_foreign_access_ref ( msg->shmem_ref , rdomid, msg->shmem_frame, 0 );
|
||||
#endif
|
||||
|
||||
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
|
||||
static void blkif_free(void)
|
||||
{
|
||||
/* Prevent new requests being issued until we fix things up. */
|
||||
spin_lock_irq(&blkif_io_lock);
|
||||
recovery = 1;
|
||||
blkif_state = BLKIF_STATE_DISCONNECTED;
|
||||
spin_unlock_irq(&blkif_io_lock);
|
||||
|
||||
@@ -1162,31 +1010,6 @@ static void blkif_free(void)
|
||||
blkif_evtchn = 0;
|
||||
}
|
||||
|
||||
static void blkif_close(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Move from CLOSED to DISCONNECTED state. */
|
||||
static void blkif_disconnect(void)
|
||||
{
|
||||
blkif_sring_t *sring;
|
||||
|
||||
if ( blk_ring.sring != NULL )
|
||||
free_page((unsigned long)blk_ring.sring);
|
||||
|
||||
sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
|
||||
SHARED_RING_INIT(sring);
|
||||
FRONT_RING_INIT(&blk_ring, sring, PAGE_SIZE);
|
||||
blkif_state = BLKIF_STATE_DISCONNECTED;
|
||||
blkif_send_interface_connect();
|
||||
}
|
||||
|
||||
static void blkif_reset(void)
|
||||
{
|
||||
blkif_free();
|
||||
blkif_disconnect();
|
||||
}
|
||||
|
||||
static void blkif_recover(void)
|
||||
{
|
||||
int i;
|
||||
@@ -1257,11 +1080,14 @@ static void blkif_recover(void)
|
||||
blkif_state = BLKIF_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
static void blkif_connect(blkif_fe_interface_status_t *status)
|
||||
static void blkif_connect(u16 evtchn, domid_t domid)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
blkif_evtchn = status->evtchn;
|
||||
blkif_evtchn = evtchn;
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
rdomid = domid;
|
||||
#endif
|
||||
|
||||
err = bind_evtchn_to_irqhandler(
|
||||
blkif_evtchn, blkif_int, SA_SAMPLE_RANDOM, "blkif", NULL);
|
||||
@@ -1270,142 +1096,318 @@ static void blkif_connect(blkif_fe_interface_status_t *status)
|
||||
WPRINTK("bind_evtchn_to_irqhandler failed (err=%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( recovery )
|
||||
{
|
||||
blkif_recover();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Transition to connected in case we need to do
|
||||
* a partition probe on a whole disk. */
|
||||
blkif_state = BLKIF_STATE_CONNECTED;
|
||||
|
||||
/* Probe for discs attached to the interface. */
|
||||
xlvbd_init();
|
||||
}
|
||||
|
||||
/* Kick pending requests. */
|
||||
spin_lock_irq(&blkif_io_lock);
|
||||
kick_pending_request_queues();
|
||||
spin_unlock_irq(&blkif_io_lock);
|
||||
}
|
||||
|
||||
static void unexpected(blkif_fe_interface_status_t *status)
|
||||
|
||||
static struct xenbus_device_id blkfront_ids[] = {
|
||||
{ "vbd" },
|
||||
{ "" }
|
||||
};
|
||||
|
||||
struct blkfront_info
|
||||
{
|
||||
DPRINTK(" Unexpected blkif status %u in state %u\n",
|
||||
status->status, blkif_state);
|
||||
/* We watch the backend */
|
||||
struct xenbus_watch watch;
|
||||
int vdevice;
|
||||
u16 handle;
|
||||
int connected;
|
||||
struct xenbus_device *dev;
|
||||
char *backend;
|
||||
};
|
||||
|
||||
static void watch_for_status(struct xenbus_watch *watch, const char *node)
|
||||
{
|
||||
struct blkfront_info *info;
|
||||
unsigned int binfo;
|
||||
unsigned long sectors, sector_size;
|
||||
int err;
|
||||
|
||||
info = container_of(watch, struct blkfront_info, watch);
|
||||
node += strlen(watch->node);
|
||||
|
||||
/* FIXME: clean up when error on the other end. */
|
||||
if (info->connected)
|
||||
return;
|
||||
|
||||
err = xenbus_gather(watch->node,
|
||||
"sectors", "%lu", §ors,
|
||||
"info", "%u", &binfo,
|
||||
"sector-size", "%lu", §or_size,
|
||||
NULL);
|
||||
|
||||
if (err)
|
||||
xenbus_dev_error(info->dev, err, "reading backend fields");
|
||||
else {
|
||||
xlvbd_add(sectors, info->vdevice, info->handle, binfo,
|
||||
sector_size);
|
||||
info->connected = 1;
|
||||
|
||||
/* First to connect? blkif is now connected. */
|
||||
if (blkif_vbds_connected++ == 0)
|
||||
blkif_state = BLKIF_STATE_CONNECTED;
|
||||
|
||||
xenbus_dev_ok(info->dev);
|
||||
|
||||
/* Kick pending requests. */
|
||||
spin_lock_irq(&blkif_io_lock);
|
||||
kick_pending_request_queues();
|
||||
spin_unlock_irq(&blkif_io_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void blkif_status(blkif_fe_interface_status_t *status)
|
||||
static int setup_blkring(struct xenbus_device *dev, unsigned int backend_id)
|
||||
{
|
||||
blkif_sring_t *sring;
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_alloc_unbound };
|
||||
int err;
|
||||
|
||||
sring = (void *)__get_free_page(GFP_KERNEL);
|
||||
if (!sring) {
|
||||
xenbus_dev_error(dev, -ENOMEM, "allocating shared ring");
|
||||
return -ENOMEM;
|
||||
}
|
||||
SHARED_RING_INIT(sring);
|
||||
FRONT_RING_INIT(&blk_ring, sring, PAGE_SIZE);
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
rdomid = status->domid; /* need to set rdomid early */
|
||||
shmem_ref = gnttab_claim_grant_reference(&gref_head,
|
||||
gref_terminal);
|
||||
ASSERT(shmem_ref != -ENOSPC);
|
||||
gnttab_grant_foreign_access_ref(shmem_ref,
|
||||
backend_id,
|
||||
virt_to_mfn(blk_ring.sring),
|
||||
0);
|
||||
#endif
|
||||
|
||||
if ( status->handle != blkif_handle )
|
||||
{
|
||||
WPRINTK(" Invalid blkif: handle=%u\n", status->handle);
|
||||
unexpected(status);
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( status->status )
|
||||
{
|
||||
case BLKIF_INTERFACE_STATUS_CLOSED:
|
||||
switch ( blkif_state )
|
||||
{
|
||||
case BLKIF_STATE_CLOSED:
|
||||
unexpected(status);
|
||||
break;
|
||||
case BLKIF_STATE_DISCONNECTED:
|
||||
case BLKIF_STATE_CONNECTED:
|
||||
unexpected(status);
|
||||
blkif_close();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLKIF_INTERFACE_STATUS_DISCONNECTED:
|
||||
switch ( blkif_state )
|
||||
{
|
||||
case BLKIF_STATE_CLOSED:
|
||||
blkif_disconnect();
|
||||
break;
|
||||
case BLKIF_STATE_DISCONNECTED:
|
||||
case BLKIF_STATE_CONNECTED:
|
||||
/* unexpected(status); */ /* occurs during suspend/resume */
|
||||
blkif_reset();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLKIF_INTERFACE_STATUS_CONNECTED:
|
||||
switch ( blkif_state )
|
||||
{
|
||||
case BLKIF_STATE_CLOSED:
|
||||
unexpected(status);
|
||||
blkif_disconnect();
|
||||
blkif_connect(status);
|
||||
break;
|
||||
case BLKIF_STATE_DISCONNECTED:
|
||||
blkif_connect(status);
|
||||
break;
|
||||
case BLKIF_STATE_CONNECTED:
|
||||
unexpected(status);
|
||||
blkif_connect(status);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLKIF_INTERFACE_STATUS_CHANGED:
|
||||
switch ( blkif_state )
|
||||
{
|
||||
case BLKIF_STATE_CLOSED:
|
||||
case BLKIF_STATE_DISCONNECTED:
|
||||
unexpected(status);
|
||||
break;
|
||||
case BLKIF_STATE_CONNECTED:
|
||||
vbd_update();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WPRINTK(" Invalid blkif status: %d\n", status->status);
|
||||
break;
|
||||
}
|
||||
op.u.alloc_unbound.dom = backend_id;
|
||||
err = HYPERVISOR_event_channel_op(&op);
|
||||
if (err) {
|
||||
free_page((unsigned long)blk_ring.sring);
|
||||
blk_ring.sring = 0;
|
||||
xenbus_dev_error(dev, err, "allocating event channel");
|
||||
return err;
|
||||
}
|
||||
blkif_connect(op.u.alloc_unbound.port, backend_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
|
||||
/* Common code used when first setting up, and when resuming. */
|
||||
static int talk_to_backend(struct xenbus_device *dev,
|
||||
struct blkfront_info *info)
|
||||
{
|
||||
switch ( msg->subtype )
|
||||
{
|
||||
case CMSG_BLKIF_FE_INTERFACE_STATUS:
|
||||
blkif_status((blkif_fe_interface_status_t *)
|
||||
&msg->msg[0]);
|
||||
break;
|
||||
default:
|
||||
msg->length = 0;
|
||||
break;
|
||||
}
|
||||
char *backend;
|
||||
const char *message;
|
||||
int err, backend_id;
|
||||
|
||||
ctrl_if_send_response(msg);
|
||||
backend = xenbus_read(dev->nodename, "backend", NULL);
|
||||
if (IS_ERR(backend)) {
|
||||
err = PTR_ERR(backend);
|
||||
if (err == -ENOENT)
|
||||
goto out;
|
||||
xenbus_dev_error(dev, err, "reading %s/backend",
|
||||
dev->nodename);
|
||||
goto out;
|
||||
}
|
||||
if (strlen(backend) == 0) {
|
||||
err = -ENOENT;
|
||||
goto free_backend;
|
||||
}
|
||||
|
||||
/* FIXME: This driver can't handle backends on different
|
||||
* domains. Check and fail gracefully. */
|
||||
err = xenbus_scanf(dev->nodename, "backend-id", "%i", &backend_id);
|
||||
if (err == -ENOENT)
|
||||
goto free_backend;
|
||||
if (err < 0) {
|
||||
xenbus_dev_error(dev, err, "reading %s/backend-id",
|
||||
dev->nodename);
|
||||
goto free_backend;
|
||||
}
|
||||
|
||||
/* First device? We create shared ring, alloc event channel. */
|
||||
if (blkif_vbds == 0) {
|
||||
err = setup_blkring(dev, backend_id);
|
||||
if (err)
|
||||
goto free_backend;
|
||||
}
|
||||
|
||||
err = xenbus_transaction_start(dev->nodename);
|
||||
if (err) {
|
||||
xenbus_dev_error(dev, err, "starting transaction");
|
||||
goto destroy_blkring;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
err = xenbus_printf(dev->nodename, "grant-id","%u", shmem_ref);
|
||||
if (err) {
|
||||
message = "writing grant-id";
|
||||
goto abort_transaction;
|
||||
}
|
||||
#else
|
||||
err = xenbus_printf(dev->nodename, "shared-frame", "%lu",
|
||||
virt_to_mfn(blk_ring.sring));
|
||||
if (err) {
|
||||
message = "writing shared-frame";
|
||||
goto abort_transaction;
|
||||
}
|
||||
#endif
|
||||
err = xenbus_printf(dev->nodename,
|
||||
"event-channel", "%u", blkif_evtchn);
|
||||
if (err) {
|
||||
message = "writing event-channel";
|
||||
goto abort_transaction;
|
||||
}
|
||||
|
||||
info->watch.node = info->backend = backend;
|
||||
info->watch.callback = watch_for_status;
|
||||
|
||||
err = register_xenbus_watch(&info->watch);
|
||||
if (err) {
|
||||
message = "registering watch on backend";
|
||||
goto abort_transaction;
|
||||
}
|
||||
|
||||
err = xenbus_transaction_end(0);
|
||||
if (err) {
|
||||
xenbus_dev_error(dev, err, "completing transaction");
|
||||
goto destroy_blkring;
|
||||
}
|
||||
return 0;
|
||||
|
||||
abort_transaction:
|
||||
xenbus_transaction_end(1);
|
||||
/* Have to do this *outside* transaction. */
|
||||
xenbus_dev_error(dev, err, "%s", message);
|
||||
destroy_blkring:
|
||||
if (blkif_vbds == 0)
|
||||
blkif_free();
|
||||
free_backend:
|
||||
kfree(backend);
|
||||
out:
|
||||
printk("%s:%u = %i\n", __FILE__, __LINE__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int wait_for_blkif(void)
|
||||
/* Setup supplies the backend dir, virtual device.
|
||||
|
||||
We place an event channel and shared frame entries.
|
||||
We watch backend to wait if it's ok. */
|
||||
static int blkfront_probe(struct xenbus_device *dev,
|
||||
const struct xenbus_device_id *id)
|
||||
{
|
||||
int err;
|
||||
struct blkfront_info *info;
|
||||
int vdevice;
|
||||
|
||||
/* FIXME: Use dynamic device id if this is not set. */
|
||||
err = xenbus_scanf(dev->nodename, "virtual-device", "%i", &vdevice);
|
||||
if (err == -ENOENT)
|
||||
return err;
|
||||
if (err < 0) {
|
||||
xenbus_dev_error(dev, err, "reading virtual-device");
|
||||
return err;
|
||||
}
|
||||
|
||||
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
xenbus_dev_error(dev, err, "allocating info structure");
|
||||
return err;
|
||||
}
|
||||
info->dev = dev;
|
||||
info->vdevice = vdevice;
|
||||
info->connected = 0;
|
||||
/* Front end dir is a number, which is used as the id. */
|
||||
info->handle = simple_strtoul(strrchr(dev->nodename,'/')+1, NULL, 0);
|
||||
dev->data = info;
|
||||
|
||||
err = talk_to_backend(dev, info);
|
||||
if (err) {
|
||||
kfree(info);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Call once in case entries already there. */
|
||||
watch_for_status(&info->watch, info->watch.node);
|
||||
blkif_vbds++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blkfront_remove(struct xenbus_device *dev)
|
||||
{
|
||||
struct blkfront_info *info = dev->data;
|
||||
|
||||
if (info->backend)
|
||||
unregister_xenbus_watch(&info->watch);
|
||||
|
||||
if (info->connected) {
|
||||
xlvbd_del(info->handle);
|
||||
blkif_vbds_connected--;
|
||||
}
|
||||
kfree(info->backend);
|
||||
kfree(info);
|
||||
|
||||
if (--blkif_vbds == 0)
|
||||
blkif_free();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blkfront_suspend(struct xenbus_device *dev)
|
||||
{
|
||||
struct blkfront_info *info = dev->data;
|
||||
|
||||
unregister_xenbus_watch(&info->watch);
|
||||
kfree(info->backend);
|
||||
info->backend = NULL;
|
||||
|
||||
if (--blkif_vbds == 0) {
|
||||
recovery = 1;
|
||||
blkif_free();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blkfront_resume(struct xenbus_device *dev)
|
||||
{
|
||||
struct blkfront_info *info = dev->data;
|
||||
int err;
|
||||
|
||||
/* FIXME: Check geometry hasn't changed here... */
|
||||
err = talk_to_backend(dev, info);
|
||||
if (!err) {
|
||||
if (blkif_vbds++ == 0)
|
||||
blkif_recover();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct xenbus_driver blkfront = {
|
||||
.name = "vbd",
|
||||
.owner = THIS_MODULE,
|
||||
.ids = blkfront_ids,
|
||||
.probe = blkfront_probe,
|
||||
.remove = blkfront_remove,
|
||||
.resume = blkfront_resume,
|
||||
.suspend = blkfront_suspend,
|
||||
};
|
||||
|
||||
static void __init init_blk_xenbus(void)
|
||||
{
|
||||
xenbus_register_device(&blkfront);
|
||||
}
|
||||
|
||||
static int wait_for_blkif(void)
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
send_driver_status(1);
|
||||
|
||||
/*
|
||||
* We should read 'nr_interfaces' from response message and wait
|
||||
* for notifications before proceeding. For now we assume that we
|
||||
* will be notified of exactly one interface.
|
||||
*/
|
||||
for ( i=0; (blkif_state != BLKIF_STATE_CONNECTED) && (i < 10*HZ); i++ )
|
||||
for ( i=0; blkif_state != BLKIF_STATE_CONNECTED && (i < 10*HZ); i++ )
|
||||
{
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(1);
|
||||
@@ -1419,7 +1421,7 @@ int wait_for_blkif(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
int __init xlblk_init(void)
|
||||
static int __init xlblk_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -1443,29 +1445,13 @@ int __init xlblk_init(void)
|
||||
blk_shadow[i].req.id = i+1;
|
||||
blk_shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
|
||||
|
||||
(void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
|
||||
CALLBACK_IN_BLOCKING_CONTEXT);
|
||||
init_blk_xenbus();
|
||||
|
||||
wait_for_blkif();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void blkdev_suspend(void)
|
||||
{
|
||||
}
|
||||
|
||||
void blkdev_resume(void)
|
||||
{
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
int i, j;
|
||||
for ( i = 0; i < BLK_RING_SIZE; i++ )
|
||||
for ( j = 0; j < BLKIF_MAX_SEGMENTS_PER_REQUEST; j++ )
|
||||
blk_shadow[i].req.frame_and_sects[j] |= GRANTREF_INVALID;
|
||||
#endif
|
||||
send_driver_status(1);
|
||||
}
|
||||
|
||||
static void blkif_completion(struct blk_shadow *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -100,6 +100,7 @@ struct xlbd_major_info {
|
||||
|
||||
struct xlbd_disk_info {
|
||||
int xd_device;
|
||||
blkif_vdev_t handle;
|
||||
struct xlbd_major_info *mi;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
struct xlbd_disk_info *next_waiting;
|
||||
@@ -119,17 +120,10 @@ extern int blkif_ioctl(struct inode *inode, struct file *filep,
|
||||
unsigned command, unsigned long argument);
|
||||
extern int blkif_check(dev_t dev);
|
||||
extern int blkif_revalidate(dev_t dev);
|
||||
extern void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp);
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
extern void blkif_control_probe_send(
|
||||
blkif_request_t *req, blkif_response_t *rsp, unsigned long address);
|
||||
#endif
|
||||
extern void do_blkif_request (request_queue_t *rq);
|
||||
|
||||
extern void xlvbd_update_vbds(void);
|
||||
|
||||
/* Virtual block-device subsystem. */
|
||||
extern int xlvbd_init(void);
|
||||
extern void xlvbd_cleanup(void);
|
||||
|
||||
int xlvbd_add(blkif_sector_t capacity, int device, blkif_vdev_t handle,
|
||||
u16 info, u16 sector_size);
|
||||
void xlvbd_del(blkif_vdev_t handle);
|
||||
#endif /* __XEN_DRIVERS_BLOCK_H__ */
|
||||
@@ -46,8 +46,9 @@
|
||||
struct lvdisk
|
||||
{
|
||||
blkif_sector_t capacity; /* 0: Size in terms of 512-byte sectors. */
|
||||
blkif_vdev_t device; /* 8: Device number (opaque 16 bit value). */
|
||||
u16 info;
|
||||
blkif_vdev_t handle; /* 8: Device number (opaque 16 bit value). */
|
||||
u16 info;
|
||||
dev_t dev;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
@@ -85,7 +86,7 @@ static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
|
||||
|
||||
/* Information about our VBDs. */
|
||||
#define MAX_VBDS 64
|
||||
struct list_head vbds_list;
|
||||
static LIST_HEAD(vbds_list);
|
||||
|
||||
#define MAJOR_XEN(dev) ((dev)>>8)
|
||||
#define MINOR_XEN(dev) ((dev) & 0xff)
|
||||
@@ -118,49 +119,6 @@ static void xlvbd_device_free(struct lvdisk *disk)
|
||||
kfree(disk);
|
||||
}
|
||||
|
||||
static vdisk_t *xlvbd_probe(int *ret)
|
||||
{
|
||||
blkif_response_t rsp;
|
||||
blkif_request_t req;
|
||||
vdisk_t *disk_info = NULL;
|
||||
unsigned long buf;
|
||||
int nr;
|
||||
|
||||
buf = __get_free_page(GFP_KERNEL);
|
||||
if ((void *)buf == NULL)
|
||||
goto out;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.operation = BLKIF_OP_PROBE;
|
||||
req.nr_segments = 1;
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
blkif_control_probe_send(&req, &rsp,
|
||||
(unsigned long)(virt_to_machine(buf)));
|
||||
#else
|
||||
req.frame_and_sects[0] = blkif_fas(virt_to_machine(buf), 0, (PAGE_SIZE/512)-1);
|
||||
|
||||
blkif_control_send(&req, &rsp);
|
||||
#endif
|
||||
if ( rsp.status <= 0 ) {
|
||||
WPRINTK("Could not probe disks (%d)\n", rsp.status);
|
||||
goto out;
|
||||
}
|
||||
nr = rsp.status;
|
||||
if ( nr > MAX_VBDS )
|
||||
nr = MAX_VBDS;
|
||||
|
||||
disk_info = kmalloc(nr * sizeof(vdisk_t), GFP_KERNEL);
|
||||
if (disk_info != NULL)
|
||||
memcpy(disk_info, (void *) buf, nr * sizeof(vdisk_t));
|
||||
|
||||
if (ret != NULL)
|
||||
*ret = nr;
|
||||
|
||||
out:
|
||||
free_page(buf);
|
||||
return disk_info;
|
||||
}
|
||||
|
||||
static struct xlbd_major_info *xlbd_alloc_major_info(
|
||||
int major, int minor, int index)
|
||||
{
|
||||
@@ -189,6 +147,7 @@ static struct xlbd_major_info *xlbd_alloc_major_info(
|
||||
break;
|
||||
}
|
||||
|
||||
printk("Registering block device major %i\n", ptr->major);
|
||||
if (register_blkdev(ptr->major, ptr->type->devname)) {
|
||||
WPRINTK("can't get major %d with name %s\n",
|
||||
ptr->major, ptr->type->devname);
|
||||
@@ -231,7 +190,7 @@ static struct xlbd_major_info *xlbd_get_major_info(int device)
|
||||
xlbd_alloc_major_info(major, minor, index));
|
||||
}
|
||||
|
||||
static int xlvbd_init_blk_queue(struct gendisk *gd, vdisk_t *disk)
|
||||
static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
|
||||
{
|
||||
request_queue_t *rq;
|
||||
|
||||
@@ -242,7 +201,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, vdisk_t *disk)
|
||||
elevator_init(rq, "noop");
|
||||
|
||||
/* Hard sector size and max sectors impersonate the equiv. hardware. */
|
||||
blk_queue_hardsect_size(rq, disk->sector_size);
|
||||
blk_queue_hardsect_size(rq, sector_size);
|
||||
blk_queue_max_sectors(rq, 512);
|
||||
|
||||
/* Each segment in a request is up to an aligned page in size. */
|
||||
@@ -261,8 +220,9 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, vdisk_t *disk)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct gendisk *xlvbd_alloc_gendisk(
|
||||
struct xlbd_major_info *mi, int minor, vdisk_t *disk)
|
||||
static struct gendisk *xlvbd_alloc_gendisk(
|
||||
struct xlbd_major_info *mi, int minor, blkif_sector_t capacity,
|
||||
int device, blkif_vdev_t handle, u16 info, u16 sector_size)
|
||||
{
|
||||
struct gendisk *gd;
|
||||
struct xlbd_disk_info *di;
|
||||
@@ -273,7 +233,8 @@ struct gendisk *xlvbd_alloc_gendisk(
|
||||
return NULL;
|
||||
memset(di, 0, sizeof(*di));
|
||||
di->mi = mi;
|
||||
di->xd_device = disk->device;
|
||||
di->xd_device = device;
|
||||
di->handle = handle;
|
||||
|
||||
if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
|
||||
nr_minors = 1 << mi->type->partn_shift;
|
||||
@@ -296,22 +257,22 @@ struct gendisk *xlvbd_alloc_gendisk(
|
||||
gd->first_minor = minor;
|
||||
gd->fops = &xlvbd_block_fops;
|
||||
gd->private_data = di;
|
||||
set_capacity(gd, disk->capacity);
|
||||
set_capacity(gd, capacity);
|
||||
|
||||
if (xlvbd_init_blk_queue(gd, disk)) {
|
||||
if (xlvbd_init_blk_queue(gd, sector_size)) {
|
||||
del_gendisk(gd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
di->rq = gd->queue;
|
||||
|
||||
if (disk->info & VDISK_READONLY)
|
||||
if (info & VDISK_READONLY)
|
||||
set_disk_ro(gd, 1);
|
||||
|
||||
if (disk->info & VDISK_REMOVABLE)
|
||||
if (info & VDISK_REMOVABLE)
|
||||
gd->flags |= GENHD_FL_REMOVABLE;
|
||||
|
||||
if (disk->info & VDISK_CDROM)
|
||||
if (info & VDISK_CDROM)
|
||||
gd->flags |= GENHD_FL_CD;
|
||||
|
||||
add_disk(gd);
|
||||
@@ -323,38 +284,36 @@ out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int xlvbd_device_add(struct list_head *list, vdisk_t *disk)
|
||||
int xlvbd_add(blkif_sector_t capacity, int device, blkif_vdev_t handle,
|
||||
u16 info, u16 sector_size)
|
||||
{
|
||||
struct lvdisk *new;
|
||||
int minor;
|
||||
dev_t device;
|
||||
struct block_device *bd;
|
||||
struct gendisk *gd;
|
||||
struct xlbd_major_info *mi;
|
||||
|
||||
mi = xlbd_get_major_info(disk->device);
|
||||
mi = xlbd_get_major_info(device);
|
||||
if (mi == NULL)
|
||||
return -EPERM;
|
||||
|
||||
new = xlvbd_device_alloc();
|
||||
if (new == NULL)
|
||||
return -1;
|
||||
new->capacity = disk->capacity;
|
||||
new->device = disk->device;
|
||||
new->info = disk->info;
|
||||
|
||||
minor = MINOR_XEN(disk->device);
|
||||
device = MKDEV(mi->major, minor);
|
||||
|
||||
bd = bdget(device);
|
||||
return -ENOMEM;
|
||||
new->capacity = capacity;
|
||||
new->info = info;
|
||||
new->handle = handle;
|
||||
new->dev = MKDEV(MAJOR_XEN(device), MINOR_XEN(device));
|
||||
|
||||
bd = bdget(new->dev);
|
||||
if (bd == NULL)
|
||||
goto out;
|
||||
|
||||
gd = xlvbd_alloc_gendisk(mi, minor, disk);
|
||||
gd = xlvbd_alloc_gendisk(mi, MINOR_XEN(device), capacity, device, handle,
|
||||
info, sector_size);
|
||||
if (gd == NULL)
|
||||
goto out_bd;
|
||||
|
||||
list_add(&new->list, list);
|
||||
list_add(&new->list, &vbds_list);
|
||||
out_bd:
|
||||
bdput(bd);
|
||||
out:
|
||||
@@ -363,27 +322,26 @@ out:
|
||||
|
||||
static int xlvbd_device_del(struct lvdisk *disk)
|
||||
{
|
||||
dev_t device;
|
||||
struct block_device *bd;
|
||||
struct gendisk *gd;
|
||||
struct xlbd_disk_info *di;
|
||||
int ret = 0, unused;
|
||||
request_queue_t *rq;
|
||||
|
||||
device = MKDEV(MAJOR_XEN(disk->device), MINOR_XEN(disk->device));
|
||||
|
||||
bd = bdget(device);
|
||||
bd = bdget(disk->dev);
|
||||
if (bd == NULL)
|
||||
return -1;
|
||||
|
||||
gd = get_gendisk(device, &unused);
|
||||
gd = get_gendisk(disk->dev, &unused);
|
||||
di = gd->private_data;
|
||||
|
||||
#if 0 /* This is wrong: hda and hdb share same major, for example. */
|
||||
if (di->mi->usage != 0) {
|
||||
WPRINTK("disk removal failed: used [dev=%x]\n", device);
|
||||
WPRINTK("disk removal failed: used [dev=%x]\n", disk->dev);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
rq = gd->queue;
|
||||
del_gendisk(gd);
|
||||
@@ -391,110 +349,19 @@ static int xlvbd_device_del(struct lvdisk *disk)
|
||||
blk_cleanup_queue(rq);
|
||||
|
||||
xlvbd_device_free(disk);
|
||||
out:
|
||||
bdput(bd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xlvbd_device_update(struct lvdisk *ldisk, vdisk_t *disk)
|
||||
void xlvbd_del(blkif_vdev_t handle)
|
||||
{
|
||||
dev_t device;
|
||||
struct block_device *bd;
|
||||
struct gendisk *gd;
|
||||
int unused;
|
||||
struct lvdisk *i;
|
||||
|
||||
if ((ldisk->capacity == disk->capacity) && (ldisk->info == disk->info))
|
||||
return 0;
|
||||
|
||||
device = MKDEV(MAJOR_XEN(ldisk->device), MINOR_XEN(ldisk->device));
|
||||
|
||||
bd = bdget(device);
|
||||
if (bd == NULL)
|
||||
return -1;
|
||||
|
||||
gd = get_gendisk(device, &unused);
|
||||
set_capacity(gd, disk->capacity);
|
||||
ldisk->capacity = disk->capacity;
|
||||
|
||||
bdput(bd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xlvbd_refresh(void)
|
||||
{
|
||||
vdisk_t *newdisks;
|
||||
struct list_head *tmp, *tmp2;
|
||||
struct lvdisk *disk;
|
||||
int i, nr;
|
||||
|
||||
newdisks = xlvbd_probe(&nr);
|
||||
if (newdisks == NULL) {
|
||||
WPRINTK("failed to probe\n");
|
||||
return;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
list_for_each_safe(tmp, tmp2, &vbds_list) {
|
||||
disk = list_entry(tmp, struct lvdisk, list);
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
if ( !newdisks[i].device )
|
||||
continue;
|
||||
if ( disk->device == newdisks[i].device ) {
|
||||
xlvbd_device_update(disk, &newdisks[i]);
|
||||
newdisks[i].device = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == nr) {
|
||||
xlvbd_device_del(disk);
|
||||
newdisks[i].device = 0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < nr; i++)
|
||||
if ( newdisks[i].device )
|
||||
xlvbd_device_add(&vbds_list, &newdisks[i]);
|
||||
kfree(newdisks);
|
||||
}
|
||||
|
||||
/*
|
||||
* xlvbd_update_vbds - reprobes the VBD status and performs updates driver
|
||||
* state. The VBDs need to be updated in this way when the domain is
|
||||
* initialised and also each time we receive an XLBLK_UPDATE event.
|
||||
*/
|
||||
void xlvbd_update_vbds(void)
|
||||
{
|
||||
xlvbd_refresh();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up all the linux device goop for the virtual block devices
|
||||
* (vbd's) that we know about. Note that although from the backend
|
||||
* driver's p.o.v. VBDs are addressed simply an opaque 16-bit device
|
||||
* number, the domain creation tools conventionally allocate these
|
||||
* numbers to correspond to those used by 'real' linux -- this is just
|
||||
* for convenience as it means e.g. that the same /etc/fstab can be
|
||||
* used when booting with or without Xen.
|
||||
*/
|
||||
int xlvbd_init(void)
|
||||
{
|
||||
int i, nr;
|
||||
vdisk_t *disks;
|
||||
|
||||
INIT_LIST_HEAD(&vbds_list);
|
||||
|
||||
memset(major_info, 0, sizeof(major_info));
|
||||
|
||||
disks = xlvbd_probe(&nr);
|
||||
if (disks == NULL) {
|
||||
WPRINTK("failed to probe\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr; i++)
|
||||
xlvbd_device_add(&vbds_list, &disks[i]);
|
||||
|
||||
kfree(disks);
|
||||
return 0;
|
||||
list_for_each_entry(i, &vbds_list, list) {
|
||||
if (i->handle == handle) {
|
||||
xlvbd_device_del(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
BUG();
|
||||
}
|
||||
@@ -87,7 +87,7 @@ typedef struct blkif_st {
|
||||
struct work_struct work;
|
||||
#ifdef CONFIG_XEN_BLKDEV_GRANT
|
||||
u16 shmem_handle;
|
||||
memory_t shmem_vaddr;
|
||||
unsigned long shmem_vaddr;
|
||||
grant_ref_t shmem_ref;
|
||||
#endif
|
||||
} blkif_t;
|
||||
|
||||
@@ -320,7 +320,7 @@ static void blkif_ptbe_send_interface_connect(void)
|
||||
};
|
||||
blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
|
||||
msg->handle = 0;
|
||||
msg->shmem_frame = virt_to_machine(blktap_be_ring.sring) >> PAGE_SHIFT;
|
||||
msg->shmem_frame = virt_to_mfn(blktap_be_ring.sring);
|
||||
|
||||
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
|
||||
@@ -49,13 +49,13 @@ typedef struct netif_st {
|
||||
unsigned long tx_shmem_frame;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT_TX
|
||||
u16 tx_shmem_handle;
|
||||
memory_t tx_shmem_vaddr;
|
||||
unsigned long tx_shmem_vaddr;
|
||||
grant_ref_t tx_shmem_ref;
|
||||
#endif
|
||||
unsigned long rx_shmem_frame;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT_RX
|
||||
u16 rx_shmem_handle;
|
||||
memory_t rx_shmem_vaddr;
|
||||
unsigned long rx_shmem_vaddr;
|
||||
grant_ref_t rx_shmem_ref;
|
||||
#endif
|
||||
unsigned int evtchn;
|
||||
|
||||
@@ -43,7 +43,7 @@ static void make_tx_response(netif_t *netif,
|
||||
static int make_rx_response(netif_t *netif,
|
||||
u16 id,
|
||||
s8 st,
|
||||
memory_t addr,
|
||||
unsigned long addr,
|
||||
u16 size,
|
||||
u16 csum_valid);
|
||||
|
||||
@@ -251,7 +251,7 @@ static void net_rx_action(unsigned long unused)
|
||||
#else
|
||||
struct mmuext_op *mmuext;
|
||||
#endif
|
||||
unsigned long vdata, mdata, new_mfn;
|
||||
unsigned long vdata, old_mfn, new_mfn;
|
||||
struct sk_buff_head rxq;
|
||||
struct sk_buff *skb;
|
||||
u16 notify_list[NETIF_RX_RING_SIZE];
|
||||
@@ -271,7 +271,7 @@ static void net_rx_action(unsigned long unused)
|
||||
{
|
||||
netif = netdev_priv(skb->dev);
|
||||
vdata = (unsigned long)skb->data;
|
||||
mdata = virt_to_machine(vdata);
|
||||
old_mfn = virt_to_mfn(vdata);
|
||||
|
||||
/* Memory squeeze? Back off for an arbitrary while. */
|
||||
if ( (new_mfn = alloc_mfn()) == 0 )
|
||||
@@ -293,7 +293,7 @@ static void net_rx_action(unsigned long unused)
|
||||
mcl++;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT_RX
|
||||
gop->mfn = mdata >> PAGE_SHIFT;
|
||||
gop->mfn = old_mfn;
|
||||
gop->domid = netif->domid;
|
||||
gop->handle = netif->rx->ring[
|
||||
MASK_NETIF_RX_IDX(netif->rx_resp_prod_copy)].req.gref;
|
||||
@@ -308,7 +308,7 @@ static void net_rx_action(unsigned long unused)
|
||||
mcl++;
|
||||
|
||||
mmuext->cmd = MMUEXT_REASSIGN_PAGE;
|
||||
mmuext->mfn = mdata >> PAGE_SHIFT;
|
||||
mmuext->mfn = old_mfn;
|
||||
mmuext++;
|
||||
#endif
|
||||
mmu->ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
|
||||
@@ -318,7 +318,7 @@ static void net_rx_action(unsigned long unused)
|
||||
__skb_queue_tail(&rxq, skb);
|
||||
|
||||
#ifdef DEBUG_GRANT
|
||||
dump_packet('a', mdata, vdata);
|
||||
dump_packet('a', old_mfn, vdata);
|
||||
#endif
|
||||
/* Filled the batch queue? */
|
||||
if ( (mcl - rx_mcl) == ARRAY_SIZE(rx_mcl) )
|
||||
@@ -345,10 +345,8 @@ static void net_rx_action(unsigned long unused)
|
||||
|
||||
mcl = rx_mcl;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT_RX
|
||||
if (unlikely(HYPERVISOR_grant_table_op(GNTTABOP_donate,
|
||||
grant_rx_op, gop - grant_rx_op))) {
|
||||
BUG();
|
||||
}
|
||||
BUG_ON(HYPERVISOR_grant_table_op(
|
||||
GNTTABOP_donate, grant_rx_op, gop - grant_rx_op));
|
||||
gop = grant_rx_op;
|
||||
#else
|
||||
mmuext = rx_mmuext;
|
||||
@@ -361,10 +359,9 @@ static void net_rx_action(unsigned long unused)
|
||||
/* Rederive the machine addresses. */
|
||||
new_mfn = mcl[0].args[1] >> PAGE_SHIFT;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT_RX
|
||||
mdata = (unsigned long)skb->data & ~PAGE_MASK;
|
||||
old_mfn = 0; /* XXX Fix this so we can free_mfn() on error! */
|
||||
#else
|
||||
mdata = ((mmuext[0].mfn << PAGE_SHIFT) |
|
||||
((unsigned long)skb->data & ~PAGE_MASK));
|
||||
old_mfn = mmuext[0].mfn;
|
||||
#endif
|
||||
atomic_set(&(skb_shinfo(skb)->dataref), 1);
|
||||
skb_shinfo(skb)->nr_frags = 0;
|
||||
@@ -379,18 +376,20 @@ static void net_rx_action(unsigned long unused)
|
||||
/* Check the reassignment error code. */
|
||||
status = NETIF_RSP_OKAY;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT_RX
|
||||
BUG_ON(gop->status != 0);
|
||||
BUG_ON(gop->status != 0); /* XXX */
|
||||
#else
|
||||
if ( unlikely(mcl[1].result != 0) )
|
||||
{
|
||||
DPRINTK("Failed MMU update transferring to DOM%u\n", netif->domid);
|
||||
free_mfn(mdata >> PAGE_SHIFT);
|
||||
free_mfn(old_mfn);
|
||||
status = NETIF_RSP_ERROR;
|
||||
}
|
||||
#endif
|
||||
evtchn = netif->evtchn;
|
||||
id = netif->rx->ring[MASK_NETIF_RX_IDX(netif->rx_resp_prod)].req.id;
|
||||
if ( make_rx_response(netif, id, status, mdata,
|
||||
if ( make_rx_response(netif, id, status,
|
||||
(old_mfn << PAGE_SHIFT) | /* XXX */
|
||||
((unsigned long)skb->data & ~PAGE_MASK),
|
||||
size, skb->proto_csum_valid) &&
|
||||
(rx_notify[evtchn] == 0) )
|
||||
{
|
||||
@@ -888,7 +887,7 @@ static void make_tx_response(netif_t *netif,
|
||||
static int make_rx_response(netif_t *netif,
|
||||
u16 id,
|
||||
s8 st,
|
||||
memory_t addr,
|
||||
unsigned long addr,
|
||||
u16 size,
|
||||
u16 csum_valid)
|
||||
{
|
||||
|
||||
@@ -448,11 +448,10 @@ static void network_alloc_rx_buffers(struct net_device *dev)
|
||||
}
|
||||
grant_rx_ref[id] = ref;
|
||||
gnttab_grant_foreign_transfer_ref(ref, rdomid,
|
||||
virt_to_machine(
|
||||
skb->head) >> PAGE_SHIFT);
|
||||
virt_to_mfn(skb->head));
|
||||
np->rx->ring[MASK_NETIF_RX_IDX(req_prod + i)].req.gref = ref;
|
||||
#endif
|
||||
rx_pfn_array[i] = virt_to_machine(skb->head) >> PAGE_SHIFT;
|
||||
rx_pfn_array[i] = virt_to_mfn(skb->head);
|
||||
|
||||
/* Remove this page from pseudo phys map before passing back to Xen. */
|
||||
phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT]
|
||||
@@ -543,13 +542,14 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
printk(KERN_ALERT "#### netfront can't claim tx grant reference\n");
|
||||
BUG();
|
||||
}
|
||||
mfn = virt_to_machine(skb->data) >> PAGE_SHIFT;
|
||||
mfn = virt_to_mfn(skb->data);
|
||||
gnttab_grant_foreign_access_ref(ref, rdomid, mfn, GNTMAP_readonly);
|
||||
tx->addr = (ref << PAGE_SHIFT) | ((unsigned long)skb->data & ~PAGE_MASK);
|
||||
tx->addr = ref << PAGE_SHIFT;
|
||||
grant_tx_ref[id] = ref;
|
||||
#else
|
||||
tx->addr = virt_to_machine(skb->data);
|
||||
tx->addr = virt_to_mfn(skb->data) << PAGE_SHIFT;
|
||||
#endif
|
||||
tx->addr |= (unsigned long)skb->data & ~PAGE_MASK;
|
||||
tx->size = skb->len;
|
||||
tx->csum_blank = (skb->ip_summed == CHECKSUM_HW);
|
||||
|
||||
@@ -720,7 +720,7 @@ static int netif_poll(struct net_device *dev, int *pbudget)
|
||||
while ((skb = __skb_dequeue(&rxq)) != NULL) {
|
||||
#ifdef GRANT_DEBUG
|
||||
printk(KERN_ALERT "#### rx_poll dequeue vdata=%p mfn=%lu\n",
|
||||
skb->data, virt_to_machine(skb->data)>>PAGE_SHIFT);
|
||||
skb->data, virt_to_mfn(skb->data));
|
||||
dump_packet('d', skb->data, (unsigned long)skb->data);
|
||||
#endif
|
||||
/*
|
||||
@@ -854,18 +854,23 @@ static void network_connect(struct net_device *dev,
|
||||
* interface has been down.
|
||||
*/
|
||||
for (requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++) {
|
||||
if ((unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET) {
|
||||
struct sk_buff *skb = np->tx_skbs[i];
|
||||
|
||||
tx = &np->tx->ring[requeue_idx++].req;
|
||||
|
||||
tx->id = i;
|
||||
tx->addr = virt_to_machine(skb->data);
|
||||
tx->size = skb->len;
|
||||
|
||||
np->stats.tx_bytes += skb->len;
|
||||
np->stats.tx_packets++;
|
||||
}
|
||||
if ((unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET) {
|
||||
struct sk_buff *skb = np->tx_skbs[i];
|
||||
|
||||
tx = &np->tx->ring[requeue_idx++].req;
|
||||
|
||||
tx->id = i;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT_TX
|
||||
tx->addr = 0; /*(ref << PAGE_SHIFT) |*/
|
||||
#else
|
||||
tx->addr = virt_to_mfn(skb->data) << PAGE_SHIFT;
|
||||
#endif
|
||||
tx->addr |= (unsigned long)skb->data & ~PAGE_MASK;
|
||||
tx->size = skb->len;
|
||||
|
||||
np->stats.tx_bytes += skb->len;
|
||||
np->stats.tx_packets++;
|
||||
}
|
||||
}
|
||||
wmb();
|
||||
np->tx->req_prod = requeue_idx;
|
||||
@@ -922,7 +927,7 @@ static void send_interface_connect(struct net_private *np)
|
||||
netif_fe_interface_connect_t *msg = (void*)cmsg.msg;
|
||||
|
||||
msg->handle = np->handle;
|
||||
msg->tx_shmem_frame = (virt_to_machine(np->tx) >> PAGE_SHIFT);
|
||||
msg->tx_shmem_frame = virt_to_mfn(np->tx);
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT_TX
|
||||
msg->tx_shmem_ref = (u32)gnttab_claim_grant_reference(&gref_tx_head,
|
||||
gref_tx_terminal);
|
||||
@@ -934,7 +939,7 @@ static void send_interface_connect(struct net_private *np)
|
||||
msg->tx_shmem_frame, 0);
|
||||
#endif
|
||||
|
||||
msg->rx_shmem_frame = (virt_to_machine(np->rx) >> PAGE_SHIFT);
|
||||
msg->rx_shmem_frame = virt_to_mfn(np->rx);
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT_RX
|
||||
msg->rx_shmem_ref = (u32)gnttab_claim_grant_reference(&gref_rx_head,
|
||||
gref_rx_terminal);
|
||||
|
||||
@@ -657,8 +657,8 @@ static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req)
|
||||
phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
|
||||
FOREIGN_FRAME((buffer_mach + offset) >> PAGE_SHIFT);
|
||||
|
||||
ASSERT(virt_to_machine(MMAP_VADDR(pending_idx, i))
|
||||
== buffer_mach + i << PAGE_SHIFT);
|
||||
ASSERT(virt_to_mfn(MMAP_VADDR(pending_idx, i))
|
||||
== ((buffer_mach >> PAGE_SHIFT) + i));
|
||||
}
|
||||
|
||||
if ( req->pipe_type == 0 && req->num_iso > 0 ) /* Maybe schedule ISO... */
|
||||
|
||||
@@ -195,7 +195,7 @@ static int xhci_construct_isoc(usbif_request_t *req, struct urb *urb)
|
||||
}
|
||||
|
||||
urb_priv->schedule = schedule;
|
||||
req->iso_schedule = virt_to_machine(schedule);
|
||||
req->iso_schedule = virt_to_mfn(schedule) << PAGE_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -212,7 +212,7 @@ static int xhci_queue_req(struct urb *urb)
|
||||
#if DEBUG
|
||||
printk(KERN_DEBUG
|
||||
"usbif = %p, req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n",
|
||||
usbif, usbif->req_prod, virt_to_machine(&usbif->req_prod),
|
||||
usbif, usbif->req_prod, virt_to_mfn(&usbif->req_prod),
|
||||
usbif->resp_prod, xhci->usb_resp_cons);
|
||||
#endif
|
||||
|
||||
@@ -232,7 +232,7 @@ static int xhci_queue_req(struct urb *urb)
|
||||
req->operation = USBIF_OP_IO;
|
||||
req->port = 0; /* We don't care what the port is. */
|
||||
req->id = (unsigned long) urb->hcpriv;
|
||||
req->transfer_buffer = virt_to_machine(urb->transfer_buffer);
|
||||
req->transfer_buffer = virt_to_mfn(urb->transfer_buffer) << PAGE_SHIFT;
|
||||
req->devnum = usb_pipedevice(urb->pipe);
|
||||
req->direction = usb_pipein(urb->pipe);
|
||||
req->speed = usb_pipeslow(urb->pipe);
|
||||
@@ -280,7 +280,7 @@ static inline usbif_request_t *xhci_queue_probe(usbif_vdev_t port)
|
||||
printk(KERN_DEBUG
|
||||
"queuing probe: req_prod = %d (@ 0x%lx), resp_prod = %d, "
|
||||
"resp_cons = %d\n", usbif->req_prod,
|
||||
virt_to_machine(&usbif->req_prod),
|
||||
virt_to_mfn(&usbif->req_prod),
|
||||
usbif->resp_prod, xhci->usb_resp_cons);
|
||||
#endif
|
||||
|
||||
@@ -1555,7 +1555,7 @@ static void usbif_status_change(usbif_fe_interface_status_changed_t *status)
|
||||
cmsg.type = CMSG_USBIF_FE;
|
||||
cmsg.subtype = CMSG_USBIF_FE_INTERFACE_CONNECT;
|
||||
cmsg.length = sizeof(usbif_fe_interface_connect_t);
|
||||
up.shmem_frame = virt_to_machine(sring) >> PAGE_SHIFT;
|
||||
up.shmem_frame = virt_to_mfn(sring);
|
||||
memcpy(cmsg.msg, &up, sizeof(up));
|
||||
|
||||
/* Tell the controller to bring up the interface. */
|
||||
@@ -1599,7 +1599,7 @@ static void usbif_status_change(usbif_fe_interface_status_changed_t *status)
|
||||
|
||||
DPRINTK(KERN_INFO __FILE__
|
||||
": USB XHCI: SHM at %p (0x%lx), EVTCHN %d\n",
|
||||
xhci->usb_ring.sring, virt_to_machine(xhci->usbif),
|
||||
xhci->usb_ring.sring, virt_to_mfn(xhci->usbif),
|
||||
xhci->evtchn);
|
||||
|
||||
xhci->state = USBIF_STATE_CONNECTED;
|
||||
|
||||
@@ -48,13 +48,12 @@ DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
|
||||
|
||||
static inline struct ringbuf_head *outbuf(void)
|
||||
{
|
||||
return machine_to_virt(xen_start_info.store_mfn << PAGE_SHIFT);
|
||||
return mfn_to_virt(xen_start_info.store_mfn);
|
||||
}
|
||||
|
||||
static inline struct ringbuf_head *inbuf(void)
|
||||
{
|
||||
return machine_to_virt(xen_start_info.store_mfn << PAGE_SHIFT)
|
||||
+ PAGE_SIZE/2;
|
||||
return mfn_to_virt(xen_start_info.store_mfn) + PAGE_SIZE/2;
|
||||
}
|
||||
|
||||
static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs)
|
||||
@@ -219,8 +218,7 @@ int xb_init_comms(void)
|
||||
}
|
||||
|
||||
/* FIXME zero out page -- domain builder should probably do this*/
|
||||
memset(machine_to_virt(xen_start_info.store_mfn << PAGE_SHIFT),
|
||||
0, PAGE_SIZE);
|
||||
memset(mfn_to_virt(xen_start_info.store_mfn), 0, PAGE_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -48,15 +48,7 @@ static const struct xenbus_device_id *
|
||||
match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
|
||||
{
|
||||
for (; !streq(arr->devicetype, ""); arr++) {
|
||||
if (!streq(arr->devicetype, dev->devicetype))
|
||||
continue;
|
||||
|
||||
/* If they don't care what subtype, it's a match. */
|
||||
if (streq(arr->subtype, ""))
|
||||
return arr;
|
||||
|
||||
/* If they care, device must have (same) subtype. */
|
||||
if (dev->subtype && streq(arr->subtype, dev->subtype))
|
||||
if (streq(arr->devicetype, dev->devicetype))
|
||||
return arr;
|
||||
}
|
||||
return NULL;
|
||||
@@ -72,10 +64,102 @@ static int xenbus_match(struct device *_dev, struct device_driver *_drv)
|
||||
return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
|
||||
}
|
||||
|
||||
struct xen_bus_type
|
||||
{
|
||||
char *root;
|
||||
unsigned int levels;
|
||||
int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
|
||||
int (*probe)(const char *type, const char *dir);
|
||||
struct bus_type bus;
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
/* device/<type>/<id> => <type>-<id> */
|
||||
static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
|
||||
{
|
||||
nodename = strchr(nodename, '/');
|
||||
if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
|
||||
printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
|
||||
if (!strchr(bus_id, '/')) {
|
||||
printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
*strchr(bus_id, '/') = '-';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bus type for frontend drivers. */
|
||||
static struct bus_type xenbus_type = {
|
||||
.name = "xenbus",
|
||||
.match = xenbus_match,
|
||||
static int xenbus_probe_frontend(const char *type, const char *name);
|
||||
static struct xen_bus_type xenbus_frontend = {
|
||||
.root = "device",
|
||||
.levels = 2, /* device/type/<id> */
|
||||
.get_bus_id = frontend_bus_id,
|
||||
.probe = xenbus_probe_frontend,
|
||||
.bus = {
|
||||
.name = "xen",
|
||||
.match = xenbus_match,
|
||||
},
|
||||
.dev = {
|
||||
.bus_id = "xen",
|
||||
},
|
||||
};
|
||||
|
||||
/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
|
||||
static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
|
||||
{
|
||||
int domid, err;
|
||||
const char *devid, *type, *frontend;
|
||||
unsigned int typelen;
|
||||
|
||||
type = strchr(nodename, '/');
|
||||
if (!type)
|
||||
return -EINVAL;
|
||||
type++;
|
||||
typelen = strcspn(type, "/");
|
||||
if (!typelen || type[typelen] != '/')
|
||||
return -EINVAL;
|
||||
|
||||
devid = strrchr(nodename, '/') + 1;
|
||||
|
||||
err = xenbus_gather(nodename, "frontend-id", "%i", &domid,
|
||||
"frontend", NULL, &frontend,
|
||||
NULL);
|
||||
if (err)
|
||||
return err;
|
||||
if (strlen(frontend) == 0)
|
||||
err = -ERANGE;
|
||||
|
||||
if (!err && !xenbus_exists(frontend, ""))
|
||||
err = -ENOENT;
|
||||
|
||||
if (err) {
|
||||
kfree(frontend);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (snprintf(bus_id, BUS_ID_SIZE,
|
||||
"%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
|
||||
return -ENOSPC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xenbus_probe_backend(const char *type, const char *uuid);
|
||||
static struct xen_bus_type xenbus_backend = {
|
||||
.root = "backend",
|
||||
.levels = 3, /* backend/type/<frontend>/<id> */
|
||||
.get_bus_id = backend_bus_id,
|
||||
.probe = xenbus_probe_backend,
|
||||
.bus = {
|
||||
.name = "xen-backend",
|
||||
.match = xenbus_match,
|
||||
},
|
||||
.dev = {
|
||||
.bus_id = "xen-backend",
|
||||
},
|
||||
};
|
||||
|
||||
static int xenbus_dev_probe(struct device *_dev)
|
||||
@@ -104,12 +188,13 @@ static int xenbus_dev_remove(struct device *_dev)
|
||||
return drv->remove(dev);
|
||||
}
|
||||
|
||||
int xenbus_register_driver(struct xenbus_driver *drv)
|
||||
static int xenbus_register_driver(struct xenbus_driver *drv,
|
||||
struct xen_bus_type *bus)
|
||||
{
|
||||
int err;
|
||||
|
||||
drv->driver.name = drv->name;
|
||||
drv->driver.bus = &xenbus_type;
|
||||
drv->driver.bus = &bus->bus;
|
||||
drv->driver.owner = drv->owner;
|
||||
drv->driver.probe = xenbus_dev_probe;
|
||||
drv->driver.remove = xenbus_dev_remove;
|
||||
@@ -120,6 +205,16 @@ int xenbus_register_driver(struct xenbus_driver *drv)
|
||||
return err;
|
||||
}
|
||||
|
||||
int xenbus_register_device(struct xenbus_driver *drv)
|
||||
{
|
||||
return xenbus_register_driver(drv, &xenbus_frontend);
|
||||
}
|
||||
|
||||
int xenbus_register_backend(struct xenbus_driver *drv)
|
||||
{
|
||||
return xenbus_register_driver(drv, &xenbus_backend);
|
||||
}
|
||||
|
||||
void xenbus_unregister_driver(struct xenbus_driver *drv)
|
||||
{
|
||||
down(&xenbus_lock);
|
||||
@@ -130,52 +225,98 @@ void xenbus_unregister_driver(struct xenbus_driver *drv)
|
||||
struct xb_find_info
|
||||
{
|
||||
struct xenbus_device *dev;
|
||||
const char *busid;
|
||||
const char *nodename;
|
||||
};
|
||||
|
||||
static int cmp_dev(struct device *dev, void *data)
|
||||
{
|
||||
struct xenbus_device *xendev = to_xenbus_device(dev);
|
||||
struct xb_find_info *info = data;
|
||||
|
||||
if (streq(dev->bus_id, info->busid)) {
|
||||
info->dev = container_of(get_device(dev),
|
||||
struct xenbus_device, dev);
|
||||
if (streq(xendev->nodename, info->nodename)) {
|
||||
info->dev = xendev;
|
||||
get_device(dev);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: device_find is fixed in 2.6.13-rc2 according to Greg KH --RR */
|
||||
struct xenbus_device *xenbus_device_find(const char *busid)
|
||||
struct xenbus_device *xenbus_device_find(const char *nodename,
|
||||
struct bus_type *bus)
|
||||
{
|
||||
struct xb_find_info info = { .dev = NULL, .busid = busid };
|
||||
struct xb_find_info info = { .dev = NULL, .nodename = nodename };
|
||||
|
||||
bus_for_each_dev(&xenbus_type, NULL, &info, cmp_dev);
|
||||
bus_for_each_dev(bus, NULL, &info, cmp_dev);
|
||||
return info.dev;
|
||||
}
|
||||
|
||||
static int cleanup_dev(struct device *dev, void *data)
|
||||
{
|
||||
struct xenbus_device *xendev = to_xenbus_device(dev);
|
||||
struct xb_find_info *info = data;
|
||||
int len = strlen(info->nodename);
|
||||
|
||||
if (!strncmp(xendev->nodename, info->nodename, len)) {
|
||||
info->dev = xendev;
|
||||
get_device(dev);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
|
||||
{
|
||||
struct xb_find_info info = { .nodename = path };
|
||||
|
||||
do {
|
||||
info.dev = NULL;
|
||||
bus_for_each_dev(bus, NULL, &info, cleanup_dev);
|
||||
if (info.dev) {
|
||||
device_unregister(&info.dev->dev);
|
||||
put_device(&info.dev->dev);
|
||||
}
|
||||
} while (info.dev);
|
||||
}
|
||||
|
||||
static void xenbus_release_device(struct device *dev)
|
||||
{
|
||||
if (dev) {
|
||||
struct xenbus_device *xendev = to_xenbus_device(dev);
|
||||
|
||||
kfree(xendev->subtype);
|
||||
kfree(xendev);
|
||||
}
|
||||
}
|
||||
/* devices/<typename>/<name> */
|
||||
static int xenbus_probe_device(const char *dirpath, const char *devicetype,
|
||||
const char *name)
|
||||
|
||||
/* Simplified asprintf. */
|
||||
static char *kasprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
unsigned int len;
|
||||
char *p, dummy[1];
|
||||
|
||||
va_start(ap, fmt);
|
||||
/* FIXME: vsnprintf has a bug, NULL should work */
|
||||
len = vsnprintf(dummy, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
p = kmalloc(len + 1, GFP_KERNEL);
|
||||
if (!p)
|
||||
return NULL;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(p, fmt, ap);
|
||||
va_end(ap);
|
||||
return p;
|
||||
}
|
||||
|
||||
static int xenbus_probe_node(struct xen_bus_type *bus,
|
||||
const char *type,
|
||||
const char *nodename)
|
||||
{
|
||||
int err;
|
||||
struct xenbus_device *xendev;
|
||||
unsigned int stringlen;
|
||||
|
||||
/* Nodename: /device/<typename>/<name>/ */
|
||||
stringlen = strlen(dirpath) + strlen(devicetype) + strlen(name) + 3;
|
||||
/* Typename */
|
||||
stringlen += strlen(devicetype) + 1;
|
||||
stringlen = strlen(nodename) + 1 + strlen(type) + 1;
|
||||
xendev = kmalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
|
||||
if (!xendev)
|
||||
return -ENOMEM;
|
||||
@@ -183,38 +324,103 @@ static int xenbus_probe_device(const char *dirpath, const char *devicetype,
|
||||
|
||||
/* Copy the strings into the extra space. */
|
||||
xendev->nodename = (char *)(xendev + 1);
|
||||
sprintf(xendev->nodename, "%s/%s/%s", dirpath, devicetype, name);
|
||||
strcpy(xendev->nodename, nodename);
|
||||
xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1;
|
||||
strcpy(xendev->devicetype, devicetype);
|
||||
strcpy(xendev->devicetype, type);
|
||||
|
||||
/* FIXME: look for "subtype" field. */
|
||||
snprintf(xendev->dev.bus_id, BUS_ID_SIZE, "%s-%s", devicetype, name);
|
||||
xendev->dev.bus = &xenbus_type;
|
||||
xendev->dev.parent = &bus->dev;
|
||||
xendev->dev.bus = &bus->bus;
|
||||
xendev->dev.release = xenbus_release_device;
|
||||
|
||||
err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
|
||||
if (err) {
|
||||
kfree(xendev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Register with generic device framework. */
|
||||
err = device_register(&xendev->dev);
|
||||
if (err) {
|
||||
printk("XENBUS: Registering device %s: error %i\n",
|
||||
xendev->dev.bus_id, err);
|
||||
printk("XENBUS: Registering %s device %s: error %i\n",
|
||||
bus->bus.name, xendev->dev.bus_id, err);
|
||||
kfree(xendev);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int xenbus_probe_device_type(const char *dirpath, const char *typename)
|
||||
/* device/<typename>/<name> */
|
||||
static int xenbus_probe_frontend(const char *type, const char *name)
|
||||
{
|
||||
char *nodename;
|
||||
int err;
|
||||
|
||||
nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name);
|
||||
if (!nodename)
|
||||
return -ENOMEM;
|
||||
|
||||
err = xenbus_probe_node(&xenbus_frontend, type, nodename);
|
||||
kfree(nodename);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* backend/<typename>/<frontend-uuid>/<name> */
|
||||
static int xenbus_probe_backend_unit(const char *dir,
|
||||
const char *type,
|
||||
const char *name)
|
||||
{
|
||||
char *nodename;
|
||||
int err;
|
||||
|
||||
nodename = kasprintf("%s/%s", dir, name);
|
||||
if (!nodename)
|
||||
return -ENOMEM;
|
||||
|
||||
err = xenbus_probe_node(&xenbus_backend, type, nodename);
|
||||
kfree(nodename);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* backend/<typename>/<frontend-uuid> */
|
||||
static int xenbus_probe_backend(const char *type, const char *uuid)
|
||||
{
|
||||
char *nodename;
|
||||
int err = 0;
|
||||
char **dir;
|
||||
unsigned int i, dir_n = 0;
|
||||
|
||||
nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, uuid);
|
||||
if (!nodename)
|
||||
return -ENOMEM;
|
||||
|
||||
dir = xenbus_directory(nodename, "", &dir_n);
|
||||
if (IS_ERR(dir)) {
|
||||
kfree(nodename);
|
||||
return PTR_ERR(dir);
|
||||
}
|
||||
|
||||
for (i = 0; i < dir_n; i++) {
|
||||
err = xenbus_probe_backend_unit(nodename, type, dir[i]);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
kfree(dir);
|
||||
kfree(nodename);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
|
||||
{
|
||||
int err = 0;
|
||||
char **dir;
|
||||
unsigned int dir_n = 0;
|
||||
int i;
|
||||
|
||||
dir = xenbus_directory(dirpath, typename, &dir_n);
|
||||
dir = xenbus_directory(bus->root, type, &dir_n);
|
||||
if (IS_ERR(dir))
|
||||
return PTR_ERR(dir);
|
||||
|
||||
for (i = 0; i < dir_n; i++) {
|
||||
err = xenbus_probe_device(dirpath, typename, dir[i]);
|
||||
err = bus->probe(type, dir[i]);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
@@ -222,18 +428,18 @@ static int xenbus_probe_device_type(const char *dirpath, const char *typename)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int xenbus_probe_devices(const char *path)
|
||||
static int xenbus_probe_devices(struct xen_bus_type *bus)
|
||||
{
|
||||
int err = 0;
|
||||
char **dir;
|
||||
unsigned int i, dir_n;
|
||||
|
||||
dir = xenbus_directory(path, "", &dir_n);
|
||||
dir = xenbus_directory(bus->root, "", &dir_n);
|
||||
if (IS_ERR(dir))
|
||||
return PTR_ERR(dir);
|
||||
|
||||
for (i = 0; i < dir_n; i++) {
|
||||
err = xenbus_probe_device_type(path, dir[i]);
|
||||
err = xenbus_probe_device_type(bus, dir[i]);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
@@ -251,58 +457,117 @@ static unsigned int char_count(const char *str, char c)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dev_changed(struct xenbus_watch *watch, const char *node)
|
||||
static int strsep_len(const char *str, char c, unsigned int len)
|
||||
{
|
||||
char busid[BUS_ID_SIZE];
|
||||
int exists;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; str[i]; i++)
|
||||
if (str[i] == c) {
|
||||
if (len == 0)
|
||||
return i;
|
||||
len--;
|
||||
}
|
||||
return (len == 0) ? i : -ERANGE;
|
||||
}
|
||||
|
||||
static void dev_changed(const char *node, struct xen_bus_type *bus)
|
||||
{
|
||||
int exists, rootlen;
|
||||
struct xenbus_device *dev;
|
||||
char *p;
|
||||
char type[BUS_ID_SIZE];
|
||||
const char *p, *root;
|
||||
|
||||
/* Node is of form device/<type>/<identifier>[/...] */
|
||||
if (char_count(node, '/') != 2)
|
||||
return;
|
||||
if (char_count(node, '/') < 2)
|
||||
return;
|
||||
|
||||
/* Created or deleted? */
|
||||
exists = xenbus_exists(node, "");
|
||||
|
||||
p = strchr(node, '/') + 1;
|
||||
if (strlen(p) + 1 > BUS_ID_SIZE) {
|
||||
printk("Device for node %s is too big!\n", node);
|
||||
if (!exists) {
|
||||
xenbus_cleanup_devices(node, &bus->bus);
|
||||
return;
|
||||
}
|
||||
/* Bus ID is name with / changed to - */
|
||||
strcpy(busid, p);
|
||||
*strchr(busid, '/') = '-';
|
||||
|
||||
dev = xenbus_device_find(busid);
|
||||
printk("xenbus: device %s %s\n", busid, dev ? "exists" : "new");
|
||||
if (dev && !exists) {
|
||||
printk("xenbus: Unregistering device %s\n", busid);
|
||||
/* FIXME: free? */
|
||||
device_unregister(&dev->dev);
|
||||
} else if (!dev && exists) {
|
||||
printk("xenbus: Adding device %s\n", busid);
|
||||
/* Hack bus id back into two strings. */
|
||||
*strrchr(busid, '-') = '\0';
|
||||
xenbus_probe_device("device", busid, busid+strlen(busid)+1);
|
||||
} else
|
||||
printk("xenbus: strange, %s already %s\n", busid,
|
||||
exists ? "exists" : "gone");
|
||||
if (dev)
|
||||
/* backend/<type>/... or device/<type>/... */
|
||||
p = strchr(node, '/') + 1;
|
||||
snprintf(type, BUS_ID_SIZE, "%.*s", strcspn(p, "/"), p);
|
||||
type[BUS_ID_SIZE-1] = '\0';
|
||||
|
||||
rootlen = strsep_len(node, '/', bus->levels);
|
||||
if (rootlen < 0)
|
||||
return;
|
||||
root = kasprintf("%.*s", rootlen, node);
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
dev = xenbus_device_find(root, &bus->bus);
|
||||
if (!dev)
|
||||
xenbus_probe_node(bus, type, root);
|
||||
else
|
||||
put_device(&dev->dev);
|
||||
|
||||
kfree(root);
|
||||
}
|
||||
|
||||
static void frontend_changed(struct xenbus_watch *watch, const char *node)
|
||||
{
|
||||
dev_changed(node, &xenbus_frontend);
|
||||
}
|
||||
|
||||
static void backend_changed(struct xenbus_watch *watch, const char *node)
|
||||
{
|
||||
dev_changed(node, &xenbus_backend);
|
||||
}
|
||||
|
||||
/* We watch for devices appearing and vanishing. */
|
||||
static struct xenbus_watch dev_watch = {
|
||||
/* FIXME: Ideally we'd only watch for changes 2 levels deep... */
|
||||
static struct xenbus_watch fe_watch = {
|
||||
.node = "device",
|
||||
.callback = dev_changed,
|
||||
.callback = frontend_changed,
|
||||
};
|
||||
|
||||
static struct xenbus_watch be_watch = {
|
||||
.node = "backend",
|
||||
.callback = backend_changed,
|
||||
};
|
||||
|
||||
static int suspend_dev(struct device *dev, void *data)
|
||||
{
|
||||
int err = 0;
|
||||
struct xenbus_driver *drv;
|
||||
struct xenbus_device *xdev;
|
||||
|
||||
if (dev->driver == NULL)
|
||||
return 0;
|
||||
drv = to_xenbus_driver(dev->driver);
|
||||
xdev = container_of(dev, struct xenbus_device, dev);
|
||||
if (drv->suspend)
|
||||
err = drv->suspend(xdev);
|
||||
if (err)
|
||||
printk("xenbus: suspend %s failed: %i\n", dev->bus_id, err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resume_dev(struct device *dev, void *data)
|
||||
{
|
||||
int err = 0;
|
||||
struct xenbus_driver *drv;
|
||||
struct xenbus_device *xdev;
|
||||
|
||||
if (dev->driver == NULL)
|
||||
return 0;
|
||||
drv = to_xenbus_driver(dev->driver);
|
||||
xdev = container_of(dev, struct xenbus_device, dev);
|
||||
if (drv->resume)
|
||||
err = drv->resume(xdev);
|
||||
if (err)
|
||||
printk("xenbus: resume %s failed: %i\n", dev->bus_id, err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xenbus_suspend(void)
|
||||
{
|
||||
/* We keep lock, so no comms can happen as page moves. */
|
||||
down(&xenbus_lock);
|
||||
bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
|
||||
bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
|
||||
xb_suspend_comms();
|
||||
}
|
||||
|
||||
@@ -310,6 +575,8 @@ void xenbus_resume(void)
|
||||
{
|
||||
xb_init_comms();
|
||||
reregister_xenbus_watches();
|
||||
bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
|
||||
bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
|
||||
up(&xenbus_lock);
|
||||
}
|
||||
|
||||
@@ -353,31 +620,24 @@ int do_xenbus_probe(void *unused)
|
||||
return err;
|
||||
}
|
||||
|
||||
down(&xenbus_lock);
|
||||
err = notifier_call_chain(&xenstore_chain, 0, 0);
|
||||
up(&xenbus_lock);
|
||||
|
||||
if (err == NOTIFY_BAD) {
|
||||
printk("%s: calling xenstore notify chain failed\n",
|
||||
__FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
down(&xenbus_lock);
|
||||
/* Enumerate devices in xenstore. */
|
||||
xenbus_probe_devices("device");
|
||||
xenbus_probe_devices(&xenbus_frontend);
|
||||
xenbus_probe_devices(&xenbus_backend);
|
||||
/* Watch for changes. */
|
||||
register_xenbus_watch(&dev_watch);
|
||||
register_xenbus_watch(&fe_watch);
|
||||
register_xenbus_watch(&be_watch);
|
||||
up(&xenbus_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init xenbus_probe_init(void)
|
||||
{
|
||||
bus_register(&xenbus_type);
|
||||
|
||||
bus_register(&xenbus_frontend.bus);
|
||||
bus_register(&xenbus_backend.bus);
|
||||
device_register(&xenbus_frontend.dev);
|
||||
device_register(&xenbus_backend.dev);
|
||||
|
||||
if (!xen_start_info.store_evtchn)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -187,6 +187,7 @@ static char *join(const char *dir, const char *name)
|
||||
static char buffer[4096];
|
||||
|
||||
BUG_ON(down_trylock(&xenbus_lock) == 0);
|
||||
/* XXX FIXME: might not be correct if name == "" */
|
||||
BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer));
|
||||
|
||||
strcpy(buffer, dir);
|
||||
@@ -399,9 +400,12 @@ int xenbus_gather(const char *dir, ...)
|
||||
ret = PTR_ERR(p);
|
||||
break;
|
||||
}
|
||||
if (sscanf(p, fmt, result) == 0)
|
||||
ret = -EINVAL;
|
||||
kfree(p);
|
||||
if (fmt) {
|
||||
if (sscanf(p, fmt, result) == 0)
|
||||
ret = -EINVAL;
|
||||
kfree(p);
|
||||
} else
|
||||
*(char **)result = p;
|
||||
}
|
||||
va_end(ap);
|
||||
return ret;
|
||||
|
||||
@@ -93,7 +93,7 @@ static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size)
|
||||
|
||||
static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
|
||||
{
|
||||
#define C(i) HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), ((u32 *)&t->tls_array[i])[0], ((u32 *)&t->tls_array[i])[1])
|
||||
#define C(i) HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), *(u64 *)&t->tls_array[i])
|
||||
C(0); C(1); C(2);
|
||||
#undef C
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ enum fixed_addresses {
|
||||
__end_of_fixed_addresses
|
||||
};
|
||||
|
||||
extern void __set_fixmap (enum fixed_addresses idx,
|
||||
unsigned long phys, pgprot_t flags);
|
||||
extern void __set_fixmap(
|
||||
enum fixed_addresses idx, maddr_t phys, pgprot_t flags);
|
||||
|
||||
#define set_fixmap(idx, phys) \
|
||||
__set_fixmap(idx, phys, PAGE_KERNEL)
|
||||
|
||||
@@ -163,7 +163,7 @@ HYPERVISOR_yield(
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign)
|
||||
: "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_yield)
|
||||
: "memory" );
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -178,7 +178,7 @@ HYPERVISOR_block(
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_block)
|
||||
: "memory" );
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -194,7 +194,7 @@ HYPERVISOR_shutdown(
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift))
|
||||
: "memory" );
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -210,7 +210,7 @@ HYPERVISOR_reboot(
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift))
|
||||
: "memory" );
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -228,7 +228,7 @@ HYPERVISOR_suspend(
|
||||
: "=a" (ret), "=b" (ign1), "=S" (ign2)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"b" (SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift)),
|
||||
"S" (srec) : "memory");
|
||||
"S" (srec) : "memory", "ecx");
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -244,7 +244,7 @@ HYPERVISOR_crash(
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_shutdown | (SHUTDOWN_crash << SCHEDOP_reasonshift))
|
||||
: "memory" );
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -316,16 +316,17 @@ HYPERVISOR_get_debugreg(
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_descriptor(
|
||||
unsigned long ma, unsigned long word1, unsigned long word2)
|
||||
u64 ma, u64 desc)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3;
|
||||
unsigned long ign1, ign2, ign3, ign4;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3)
|
||||
: "0" (__HYPERVISOR_update_descriptor), "1" (ma), "2" (word1),
|
||||
"3" (word2)
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4)
|
||||
: "0" (__HYPERVISOR_update_descriptor),
|
||||
"1" ((unsigned long)ma), "2" ((unsigned long)(ma>>32)),
|
||||
"3" ((unsigned long)desc), "4" ((unsigned long)(desc>>32))
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
@@ -529,12 +530,15 @@ HYPERVISOR_vcpu_down(
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1;
|
||||
/* Yes, I really do want to clobber edx here: when we resume a
|
||||
vcpu after unpickling a multi-processor domain, it returns
|
||||
here, but clobbers all of the call clobbered registers. */
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_vcpu_down | (vcpu << SCHEDOP_vcpushift))
|
||||
: "memory" );
|
||||
: "memory", "ecx", "edx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -550,8 +554,26 @@ HYPERVISOR_vcpu_up(
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_vcpu_up | (vcpu << SCHEDOP_vcpushift))
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_vcpu_pickle(
|
||||
int vcpu, vcpu_guest_context_t *ctxt)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_vcpu_pickle | (vcpu << SCHEDOP_vcpushift)),
|
||||
"2" (ctxt)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __HYPERCALL_H__ */
|
||||
@@ -63,20 +63,25 @@
|
||||
extern unsigned int *phys_to_machine_mapping;
|
||||
#define pfn_to_mfn(_pfn) ((unsigned long)(phys_to_machine_mapping[(_pfn)]))
|
||||
#define mfn_to_pfn(_mfn) ((unsigned long)(machine_to_phys_mapping[(_mfn)]))
|
||||
|
||||
/* Definitions for machine and pseudophysical addresses. */
|
||||
#ifdef CONFIG_X86_PAE
|
||||
typedef unsigned long long physaddr_t;
|
||||
typedef unsigned long long paddr_t;
|
||||
typedef unsigned long long maddr_t;
|
||||
#else
|
||||
typedef unsigned long physaddr_t;
|
||||
typedef unsigned long paddr_t;
|
||||
typedef unsigned long maddr_t;
|
||||
#endif
|
||||
static inline physaddr_t phys_to_machine(physaddr_t phys)
|
||||
|
||||
static inline maddr_t phys_to_machine(paddr_t phys)
|
||||
{
|
||||
physaddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT);
|
||||
maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT);
|
||||
machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
|
||||
return machine;
|
||||
}
|
||||
static inline physaddr_t machine_to_phys(physaddr_t machine)
|
||||
static inline paddr_t machine_to_phys(maddr_t machine)
|
||||
{
|
||||
physaddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT);
|
||||
paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT);
|
||||
phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
|
||||
return phys;
|
||||
}
|
||||
@@ -233,8 +238,10 @@ extern int sysctl_legacy_va_layout;
|
||||
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
|
||||
|
||||
/* VIRT <-> MACHINE conversion */
|
||||
#define virt_to_machine(_a) (phys_to_machine(__pa(_a)))
|
||||
#define machine_to_virt(_m) (__va(machine_to_phys(_m)))
|
||||
#define virt_to_machine(v) (phys_to_machine(__pa(v)))
|
||||
#define machine_to_virt(m) (__va(machine_to_phys(m)))
|
||||
#define virt_to_mfn(v) (pfn_to_mfn(__pa(v) >> PAGE_SHIFT))
|
||||
#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
*/
|
||||
#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
|
||||
extern unsigned long empty_zero_page[1024];
|
||||
extern pgd_t swapper_pg_dir[1024];
|
||||
extern pgd_t *swapper_pg_dir;
|
||||
extern kmem_cache_t *pgd_cache;
|
||||
extern kmem_cache_t *pmd_cache;
|
||||
extern spinlock_t pgd_lock;
|
||||
@@ -450,7 +450,7 @@ void make_pages_writable(void *va, unsigned int nr);
|
||||
#define arbitrary_virt_to_machine(__va) \
|
||||
({ \
|
||||
pte_t *__pte = virt_to_ptep(__va); \
|
||||
unsigned long __pa = (*(unsigned long *)__pte) & PAGE_MASK; \
|
||||
maddr_t __pa = (maddr_t)pte_mfn(*__pte) << PAGE_SHIFT; \
|
||||
__pa | ((unsigned long)(__va) & (PAGE_SIZE-1)); \
|
||||
})
|
||||
|
||||
|
||||
@@ -502,4 +502,21 @@ HYPERVISOR_set_segment_base(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_vcpu_pickle(
|
||||
int vcpu, vcpu_guest_context_t *ctxt)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_vcpu_pickle | (vcpu << SCHEDOP_vcpushift)),
|
||||
"2" (ctxt)
|
||||
: __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __HYPERCALL_H__ */
|
||||
@@ -65,16 +65,21 @@ void copy_page(void *, void *);
|
||||
extern u32 *phys_to_machine_mapping;
|
||||
#define pfn_to_mfn(_pfn) ((unsigned long) phys_to_machine_mapping[(unsigned int)(_pfn)])
|
||||
#define mfn_to_pfn(_mfn) ((unsigned long) machine_to_phys_mapping[(unsigned int)(_mfn)])
|
||||
static inline unsigned long phys_to_machine(unsigned long phys)
|
||||
|
||||
/* Definitions for machine and pseudophysical addresses. */
|
||||
typedef unsigned long paddr_t;
|
||||
typedef unsigned long maddr_t;
|
||||
|
||||
static inline maddr_t phys_to_machine(paddr_t phys)
|
||||
{
|
||||
unsigned long machine = pfn_to_mfn(phys >> PAGE_SHIFT);
|
||||
maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT);
|
||||
machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
|
||||
return machine;
|
||||
}
|
||||
|
||||
static inline unsigned long machine_to_phys(unsigned long machine)
|
||||
static inline paddr_t machine_to_phys(maddr_t machine)
|
||||
{
|
||||
unsigned long phys = mfn_to_pfn(machine >> PAGE_SHIFT);
|
||||
paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT);
|
||||
phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
|
||||
return phys;
|
||||
}
|
||||
@@ -211,8 +216,10 @@ extern __inline__ int get_order(unsigned long size)
|
||||
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
|
||||
|
||||
/* VIRT <-> MACHINE conversion */
|
||||
#define virt_to_machine(_a) (phys_to_machine(__pa(_a)))
|
||||
#define machine_to_virt(_m) (__va(machine_to_phys(_m)))
|
||||
#define virt_to_machine(v) (phys_to_machine(__pa(v)))
|
||||
#define machine_to_virt(m) (__va(machine_to_phys(m)))
|
||||
#define virt_to_mfn(v) (pfn_to_mfn(__pa(v) >> PAGE_SHIFT))
|
||||
#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
|
||||
|
||||
#define VM_DATA_DEFAULT_FLAGS \
|
||||
(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
/* A xenbus device. */
|
||||
struct xenbus_device {
|
||||
char *devicetype;
|
||||
char *subtype;
|
||||
char *nodename;
|
||||
struct device dev;
|
||||
int has_error;
|
||||
@@ -53,7 +52,6 @@ struct xenbus_device_id
|
||||
{
|
||||
/* .../device/<device_type>/<identifier> */
|
||||
char devicetype[32]; /* General class of device. */
|
||||
char subtype[32]; /* Contents of "subtype" for this device */
|
||||
};
|
||||
|
||||
/* A xenbus driver. */
|
||||
@@ -61,9 +59,11 @@ struct xenbus_driver {
|
||||
char *name;
|
||||
struct module *owner;
|
||||
const struct xenbus_device_id *ids;
|
||||
int (*probe) (struct xenbus_device * dev,
|
||||
const struct xenbus_device_id * id);
|
||||
int (*remove) (struct xenbus_device * dev);
|
||||
int (*probe)(struct xenbus_device *dev,
|
||||
const struct xenbus_device_id *id);
|
||||
int (*remove)(struct xenbus_device *dev);
|
||||
int (*suspend)(struct xenbus_device *dev);
|
||||
int (*resume)(struct xenbus_device *dev);
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
@@ -72,7 +72,8 @@ static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv)
|
||||
return container_of(drv, struct xenbus_driver, driver);
|
||||
}
|
||||
|
||||
int xenbus_register_driver(struct xenbus_driver *drv);
|
||||
int xenbus_register_device(struct xenbus_driver *drv);
|
||||
int xenbus_register_backend(struct xenbus_driver *drv);
|
||||
void xenbus_unregister_driver(struct xenbus_driver *drv);
|
||||
|
||||
/* Caller must hold this lock to call these functions: it's also held
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
--- linux-2.6.12/net/bridge/br_if.c 2005-06-17 14:48:29.000000000 -0500
|
||||
+++ linux-2.6.12-xen0-smp/net/bridge/br_if.c 2005-08-18 15:17:27.302615846 -0500
|
||||
@@ -382,7 +382,7 @@
|
||||
{
|
||||
struct net_bridge_port *p = dev->br_port;
|
||||
|
||||
- if (!p || p->br != br)
|
||||
+ if (!p || p->br != br || p->state == BR_STATE_DISABLED)
|
||||
return -EINVAL;
|
||||
|
||||
br_sysfs_removeif(p);
|
||||
@@ -40,7 +40,7 @@ typedef int boolean;
|
||||
typedef struct bwcpoint /* break/watch/catch point */
|
||||
{
|
||||
struct list_head list;
|
||||
memory_t address;
|
||||
unsigned long address;
|
||||
u32 domain;
|
||||
u8 old_value; /* old value for software bkpt */
|
||||
} bwcpoint_t, *bwcpoint_p;
|
||||
@@ -311,7 +311,7 @@ xendebug_continue(int xc_handle,
|
||||
/* access to one page */
|
||||
static int
|
||||
xendebug_memory_page (domain_context_p ctxt, int xc_handle, u32 vcpu,
|
||||
int protection, memory_t address, int length, u8 *buffer)
|
||||
int protection, unsigned long address, int length, u8 *buffer)
|
||||
{
|
||||
vcpu_guest_context_t *vcpu_ctxt = &ctxt->context[vcpu];
|
||||
unsigned long pde, page;
|
||||
@@ -407,7 +407,7 @@ xendebug_memory_page (domain_context_p ctxt, int xc_handle, u32 vcpu,
|
||||
/* divide a memory operation into accesses to individual pages */
|
||||
static int
|
||||
xendebug_memory_op (domain_context_p ctxt, int xc_handle, u32 vcpu,
|
||||
int protection, memory_t address, int length, u8 *buffer)
|
||||
int protection, unsigned long address, int length, u8 *buffer)
|
||||
{
|
||||
int remain; /* number of bytes to touch past this page */
|
||||
int bytes = 0;
|
||||
@@ -431,7 +431,7 @@ int
|
||||
xendebug_read_memory(int xc_handle,
|
||||
u32 domid,
|
||||
u32 vcpu,
|
||||
memory_t address,
|
||||
unsigned long address,
|
||||
u32 length,
|
||||
u8 *data)
|
||||
{
|
||||
@@ -451,7 +451,7 @@ int
|
||||
xendebug_write_memory(int xc_handle,
|
||||
u32 domid,
|
||||
u32 vcpu,
|
||||
memory_t address,
|
||||
unsigned long address,
|
||||
u32 length,
|
||||
u8 *data)
|
||||
{
|
||||
@@ -471,7 +471,7 @@ int
|
||||
xendebug_insert_memory_breakpoint(int xc_handle,
|
||||
u32 domid,
|
||||
u32 vcpu,
|
||||
memory_t address,
|
||||
unsigned long address,
|
||||
u32 length)
|
||||
{
|
||||
bwcpoint_p bkpt;
|
||||
@@ -517,7 +517,7 @@ int
|
||||
xendebug_remove_memory_breakpoint(int xc_handle,
|
||||
u32 domid,
|
||||
u32 vcpu,
|
||||
memory_t address,
|
||||
unsigned long address,
|
||||
u32 length)
|
||||
{
|
||||
bwcpoint_p bkpt = NULL;
|
||||
|
||||
@@ -45,7 +45,7 @@ int xendebug_continue(int xc_handle,
|
||||
int xendebug_read_memory(int xc_handle,
|
||||
u32 domid,
|
||||
u32 vcpu,
|
||||
memory_t address,
|
||||
unsigned long address,
|
||||
u32 length,
|
||||
u8 *data);
|
||||
|
||||
@@ -53,7 +53,7 @@ int xendebug_read_memory(int xc_handle,
|
||||
int xendebug_write_memory(int xc_handle,
|
||||
u32 domid,
|
||||
u32 vcpu,
|
||||
memory_t address,
|
||||
unsigned long address,
|
||||
u32 length,
|
||||
u8 *data);
|
||||
|
||||
@@ -61,13 +61,13 @@ int xendebug_write_memory(int xc_handle,
|
||||
int xendebug_insert_memory_breakpoint(int xc_handle,
|
||||
u32 domid,
|
||||
u32 vcpu,
|
||||
memory_t address,
|
||||
unsigned long address,
|
||||
u32 length);
|
||||
|
||||
int xendebug_remove_memory_breakpoint(int xc_handle,
|
||||
u32 domid,
|
||||
u32 vcpu,
|
||||
memory_t address,
|
||||
unsigned long address,
|
||||
u32 length);
|
||||
|
||||
int xendebug_query_domain_stop(int xc_handle,
|
||||
|
||||
@@ -26,7 +26,7 @@ static int pdb_page_fault_fn (struct pt_regs *regs, long error_code,
|
||||
typedef struct bwcpoint /* break/watch/catch point */
|
||||
{
|
||||
struct list_head list;
|
||||
memory_t address;
|
||||
unsigned long address;
|
||||
int length;
|
||||
|
||||
u8 type; /* BWC_??? */
|
||||
@@ -109,7 +109,7 @@ pdb_bwc_print_list (void)
|
||||
}
|
||||
|
||||
bwcpoint_p
|
||||
pdb_search_watchpoint (u32 process, memory_t address)
|
||||
pdb_search_watchpoint (u32 process, unsigned long address)
|
||||
{
|
||||
bwcpoint_p bwc_watch = (bwcpoint_p) 0;
|
||||
bwcpoint_p bwc_entry = (bwcpoint_p) 0;
|
||||
@@ -364,7 +364,7 @@ pdb_step (struct task_struct *target)
|
||||
|
||||
int
|
||||
pdb_insert_memory_breakpoint (struct task_struct *target,
|
||||
memory_t address, u32 length)
|
||||
unsigned long address, u32 length)
|
||||
{
|
||||
int rc = 0;
|
||||
bwcpoint_p bkpt;
|
||||
@@ -399,7 +399,7 @@ pdb_insert_memory_breakpoint (struct task_struct *target,
|
||||
|
||||
int
|
||||
pdb_remove_memory_breakpoint (struct task_struct *target,
|
||||
memory_t address, u32 length)
|
||||
unsigned long address, u32 length)
|
||||
{
|
||||
int rc = 0;
|
||||
bwcpoint_p bkpt = NULL;
|
||||
@@ -760,7 +760,7 @@ pdb_int3_fn (struct pt_regs *regs, long error_code)
|
||||
{
|
||||
pdb_response_t resp;
|
||||
bwcpoint_p bkpt = NULL;
|
||||
memory_t address = regs->eip - 1;
|
||||
unsigned long address = regs->eip - 1;
|
||||
|
||||
struct list_head *entry;
|
||||
list_for_each(entry, &bwcpoint_list)
|
||||
|
||||
@@ -199,7 +199,7 @@ pdb_interrupt (int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
}
|
||||
|
||||
static void
|
||||
pdb_send_connection_status(int status, memory_t ring)
|
||||
pdb_send_connection_status(int status, unsigned long ring)
|
||||
{
|
||||
ctrl_msg_t cmsg =
|
||||
{
|
||||
|
||||
@@ -18,9 +18,9 @@ int pdb_continue (struct task_struct *target);
|
||||
int pdb_step (struct task_struct *target);
|
||||
|
||||
int pdb_insert_memory_breakpoint (struct task_struct *target,
|
||||
memory_t address, u32 length);
|
||||
unsigned long address, u32 length);
|
||||
int pdb_remove_memory_breakpoint (struct task_struct *target,
|
||||
memory_t address, u32 length);
|
||||
unsigned long address, u32 length);
|
||||
int pdb_insert_watchpoint (struct task_struct *target,
|
||||
pdb_op_watchpt_p watchpt);
|
||||
int pdb_remove_watchpoint (struct task_struct *target,
|
||||
|
||||
@@ -203,7 +203,7 @@ dom_read_memory (value context, value address, value length)
|
||||
context_t ctx;
|
||||
int loop;
|
||||
char *buffer;
|
||||
memory_t my_address = Int32_val(address);
|
||||
unsigned long my_address = Int32_val(address);
|
||||
u32 my_length = Int_val(length);
|
||||
|
||||
printf ("(pdb) read memory\n");
|
||||
@@ -259,7 +259,7 @@ dom_write_memory (value context, value address, value val_list)
|
||||
context_t ctx;
|
||||
|
||||
char buffer[4096]; /* a big buffer */
|
||||
memory_t my_address;
|
||||
unsigned long my_address;
|
||||
u32 length = 0;
|
||||
|
||||
printf ("(pdb) write memory\n");
|
||||
@@ -279,7 +279,7 @@ dom_write_memory (value context, value address, value val_list)
|
||||
}
|
||||
buffer[length++] = Int_val(Field(node, 0));
|
||||
|
||||
my_address = (memory_t) Int32_val(address);
|
||||
my_address = (unsigned long) Int32_val(address);
|
||||
|
||||
if ( xendebug_write_memory(xc_handle, ctx.domain, ctx.vcpu,
|
||||
my_address, length, buffer) )
|
||||
@@ -344,7 +344,7 @@ dom_insert_memory_breakpoint (value context, value address, value length)
|
||||
CAMLparam3(context, address, length);
|
||||
|
||||
context_t ctx;
|
||||
memory_t my_address = (memory_t) Int32_val(address);
|
||||
unsigned long my_address = (unsigned long) Int32_val(address);
|
||||
int my_length = Int_val(length);
|
||||
|
||||
decode_context(&ctx, context);
|
||||
@@ -373,7 +373,7 @@ dom_remove_memory_breakpoint (value context, value address, value length)
|
||||
|
||||
context_t ctx;
|
||||
|
||||
memory_t my_address = (memory_t) Int32_val(address);
|
||||
unsigned long my_address = (unsigned long) Int32_val(address);
|
||||
int my_length = Int_val(length);
|
||||
|
||||
printf ("(pdb) remove memory breakpoint 0x%lx %d\n",
|
||||
|
||||
@@ -495,7 +495,7 @@ proc_insert_memory_breakpoint (value context, value address, value length)
|
||||
|
||||
req.operation = PDB_OPCODE_SET_BKPT;
|
||||
req.process = ctx.process;
|
||||
req.u.bkpt.address = (memory_t) Int32_val(address);
|
||||
req.u.bkpt.address = (unsigned long) Int32_val(address);
|
||||
req.u.bkpt.length = Int_val(length);
|
||||
|
||||
send_request(ctx.ring, ctx.evtchn, &req);
|
||||
@@ -518,7 +518,7 @@ proc_remove_memory_breakpoint (value context, value address, value length)
|
||||
|
||||
req.operation = PDB_OPCODE_CLR_BKPT;
|
||||
req.process = ctx.process;
|
||||
req.u.bkpt.address = (memory_t) Int32_val(address);
|
||||
req.u.bkpt.address = (unsigned long) Int32_val(address);
|
||||
req.u.bkpt.length = Int_val(length);
|
||||
|
||||
send_request(ctx.ring, ctx.evtchn, &req);
|
||||
@@ -542,7 +542,7 @@ proc_insert_watchpoint (value context, value kind, value address, value length)
|
||||
req.operation = PDB_OPCODE_SET_WATCHPT;
|
||||
req.process = ctx.process;
|
||||
req.u.watchpt.type = Int_val(kind);
|
||||
req.u.watchpt.address = (memory_t) Int32_val(address);
|
||||
req.u.watchpt.address = (unsigned long) Int32_val(address);
|
||||
req.u.watchpt.length = Int_val(length);
|
||||
|
||||
send_request(ctx.ring, ctx.evtchn, &req);
|
||||
@@ -566,7 +566,7 @@ proc_remove_watchpoint (value context, value kind, value address, value length)
|
||||
req.operation = PDB_OPCODE_CLR_WATCHPT;
|
||||
req.process = ctx.process;
|
||||
req.u.watchpt.type = Int_val(kind);
|
||||
req.u.watchpt.address = (memory_t) Int32_val(address);
|
||||
req.u.watchpt.address = (unsigned long) Int32_val(address);
|
||||
req.u.watchpt.length = Int_val(length);
|
||||
|
||||
send_request(ctx.ring, ctx.evtchn, &req);
|
||||
|
||||
@@ -50,7 +50,7 @@ xcs_initialize_ring (value domain, value ring)
|
||||
{
|
||||
CAMLparam2(domain, ring);
|
||||
int my_domain = Int_val(domain);
|
||||
memory_t my_ring = Int32_val(ring);
|
||||
unsigned long my_ring = Int32_val(ring);
|
||||
|
||||
pdb_front_ring_t *front_ring;
|
||||
pdb_sring_t *sring;
|
||||
|
||||
+13
-13
@@ -515,25 +515,25 @@ int xc_grant_interface_open(void);
|
||||
*/
|
||||
int xc_grant_interface_close(int xc_handle);
|
||||
|
||||
int xc_gnttab_map_grant_ref(int xc_handle,
|
||||
memory_t host_virt_addr,
|
||||
u32 dom,
|
||||
u16 ref,
|
||||
u16 flags,
|
||||
s16 *handle,
|
||||
memory_t *dev_bus_addr);
|
||||
int xc_gnttab_map_grant_ref(int xc_handle,
|
||||
u64 host_virt_addr,
|
||||
u32 dom,
|
||||
u16 ref,
|
||||
u16 flags,
|
||||
s16 *handle,
|
||||
u64 *dev_bus_addr);
|
||||
|
||||
int xc_gnttab_unmap_grant_ref(int xc_handle,
|
||||
memory_t host_virt_addr,
|
||||
memory_t dev_bus_addr,
|
||||
u16 handle,
|
||||
s16 *status);
|
||||
int xc_gnttab_unmap_grant_ref(int xc_handle,
|
||||
u64 host_virt_addr,
|
||||
u64 dev_bus_addr,
|
||||
u16 handle,
|
||||
s16 *status);
|
||||
|
||||
int xc_gnttab_setup_table(int xc_handle,
|
||||
u32 dom,
|
||||
u16 nr_frames,
|
||||
s16 *status,
|
||||
memory_t **frame_list);
|
||||
unsigned long **frame_list);
|
||||
|
||||
/* Grant debug builds only: */
|
||||
int xc_gnttab_dump_table(int xc_handle,
|
||||
|
||||
@@ -40,12 +40,12 @@ do_gnttab_op(int xc_handle,
|
||||
|
||||
|
||||
int xc_gnttab_map_grant_ref(int xc_handle,
|
||||
memory_t host_virt_addr,
|
||||
u64 host_virt_addr,
|
||||
u32 dom,
|
||||
u16 ref,
|
||||
u16 flags,
|
||||
s16 *handle,
|
||||
memory_t *dev_bus_addr)
|
||||
u64 *dev_bus_addr)
|
||||
{
|
||||
struct gnttab_map_grant_ref op;
|
||||
int rc;
|
||||
@@ -67,8 +67,8 @@ int xc_gnttab_map_grant_ref(int xc_handle,
|
||||
|
||||
|
||||
int xc_gnttab_unmap_grant_ref(int xc_handle,
|
||||
memory_t host_virt_addr,
|
||||
memory_t dev_bus_addr,
|
||||
u64 host_virt_addr,
|
||||
u64 dev_bus_addr,
|
||||
u16 handle,
|
||||
s16 *status)
|
||||
{
|
||||
@@ -92,7 +92,7 @@ int xc_gnttab_setup_table(int xc_handle,
|
||||
u32 dom,
|
||||
u16 nr_frames,
|
||||
s16 *status,
|
||||
memory_t **frame_list)
|
||||
unsigned long **frame_list)
|
||||
{
|
||||
struct gnttab_setup_table op;
|
||||
int rc, i;
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
XEN_ROOT = ../../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
CFLAGS += -static
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -O3
|
||||
CFLAGS += -fno-strict-aliasing
|
||||
CFLAGS += -I.
|
||||
|
||||
all: build
|
||||
|
||||
build: mk-symlinks
|
||||
$(MAKE) xml_to_bin
|
||||
|
||||
default: all
|
||||
|
||||
install: all
|
||||
|
||||
xml_to_bin : make_include XmlToBin.java XmlToBinInterface.java SsidsEntry.java SecurityLabel.java myHandler.java
|
||||
javac XmlToBin.java
|
||||
|
||||
make_include : c2j_include
|
||||
./c2j_include
|
||||
|
||||
c2j_include: c2j_include.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf *.class xen c2j_include policy_version.java *.bin
|
||||
|
||||
|
||||
LINUX_ROOT := $(XEN_ROOT)/linux-2.6-xen-sparse
|
||||
mk-symlinks:
|
||||
[ -e xen/linux ] || mkdir -p xen/linux
|
||||
[ -e xen/io ] || mkdir -p xen/io
|
||||
( cd xen >/dev/null ; \
|
||||
ln -sf ../$(XEN_ROOT)/xen/include/public/*.h . )
|
||||
( cd xen/io >/dev/null ; \
|
||||
ln -sf ../../$(XEN_ROOT)/xen/include/public/io/*.h . )
|
||||
( cd xen/linux >/dev/null ; \
|
||||
ln -sf ../../$(LINUX_ROOT)/include/asm-xen/linux-public/*.h . )
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* (C) Copyright IBM Corp. 2005
|
||||
*
|
||||
* $Id: SecurityLabel.java,v 1.2 2005/06/17 20:00:04 rvaldez Exp $
|
||||
*
|
||||
* Author: Ray Valdez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2 of the
|
||||
* License.
|
||||
*
|
||||
* SecurityLabel Class.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* Keeps track of types.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
*/
|
||||
import java.util.*;
|
||||
public class SecurityLabel
|
||||
{
|
||||
Vector ids;
|
||||
Vector vlans;
|
||||
Vector slots;
|
||||
Vector steTypes;
|
||||
int steSsidPosition;
|
||||
Vector chwIDs;
|
||||
Vector chwTypes;
|
||||
int chwSsidPosition;
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Author: Ray Valdez, rvaldez@us.ibm.com -->
|
||||
<!-- xml schema definition for xen xml policies -->
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.ibm.com"
|
||||
xmlns="http://www.ibm.com"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xsd:element name="TE" type="xsd:string" />
|
||||
<xsd:element name="ChWall" type="xsd:string" />
|
||||
|
||||
<xsd:element name="Definition">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
|
||||
<!-- simple type enforcement -->
|
||||
<xsd:element name="Types" minOccurs ="0" maxOccurs="1">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="TE" minOccurs ="1" maxOccurs ="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<!-- chinese wall -->
|
||||
<!-- type definition -->
|
||||
<xsd:element name="ChWallTypes" minOccurs ="0" maxOccurs="1">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="ChWall" minOccurs ="1" maxOccurs ="unbounded"/>
|
||||
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<!-- conflict set -->
|
||||
<xsd:element name="ConflictSet" minOccurs ="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="ChWall" minOccurs ="2" maxOccurs ="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="Policy">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
|
||||
<xsd:element name="PolicyHeader">
|
||||
<xsd:complexType>
|
||||
<xsd:all>
|
||||
<xsd:element name = "Name" type="xsd:string"/>
|
||||
<xsd:element name = "DateTime" type="xsd:dateTime"/>
|
||||
<xsd:element name = "Tag" minOccurs ="1" maxOccurs ="1" type="xsd:string"/>
|
||||
<xsd:element name = "TypeDefinition">
|
||||
<xsd:complexType>
|
||||
<xsd:all>
|
||||
<xsd:element name = "url" type="xsd:string"/>
|
||||
<xsd:element name = "hash" minOccurs ="0" maxOccurs ="1" type="xsd:string"/>
|
||||
</xsd:all>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:all>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="VM" minOccurs ="1" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="id" type="xsd:integer"/>
|
||||
<xsd:element ref="TE" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element ref="ChWall" minOccurs ="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="Vlan" minOccurs ="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="vid" type="xsd:integer"/>
|
||||
<xsd:element ref="TE" minOccurs="1" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="Slot" minOccurs ="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="bus" type="xsd:integer"/>
|
||||
<xsd:element name="slot" type="xsd:integer"/>
|
||||
<xsd:element ref="TE" minOccurs="1" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<!-- root element -->
|
||||
<xsd:element name="SecurityPolicySpec">
|
||||
<xsd:complexType>
|
||||
<xsd:choice>
|
||||
<xsd:element ref="Definition" minOccurs ="1" maxOccurs="unbounded"/>
|
||||
<xsd:element ref="Policy" minOccurs ="1" maxOccurs="unbounded"/>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* (C) Copyright IBM Corp. 2005
|
||||
*
|
||||
* $Id: SsidsEntry.java,v 1.2 2005/06/17 20:02:40 rvaldez Exp $
|
||||
*
|
||||
* Author: Ray Valdez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2 of the
|
||||
* License.
|
||||
*
|
||||
* SsidsEntry Class.
|
||||
* <p>
|
||||
*
|
||||
* Holds ssid information.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class SsidsEntry
|
||||
{
|
||||
int id; /* used for partition and vlan */
|
||||
int bus; /* used for slots */
|
||||
int slot;
|
||||
int ste = 0xffffffff;
|
||||
int chw = 0xffffffff;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,138 +0,0 @@
|
||||
/**
|
||||
* (C) Copyright IBM Corp. 2005
|
||||
*
|
||||
* $Id: XmlToBinInterface.java,v 1.3 2005/06/20 21:07:37 rvaldez Exp $
|
||||
*
|
||||
* Author: Ray Valdez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2 of the
|
||||
* License.
|
||||
*
|
||||
* XmlToBinInterface Class.
|
||||
* <p>
|
||||
*
|
||||
* Defines constants used by XmToBin.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* policy binary structures
|
||||
*
|
||||
* struct acm_policy_buffer {
|
||||
* u32 policy_version; * ACM_POLICY_VERSION *
|
||||
* u32 magic;
|
||||
* u32 len;
|
||||
* u32 primary_policy_code;
|
||||
* u32 primary_buffer_offset;
|
||||
* u32 secondary_policy_code;
|
||||
* u32 secondary_buffer_offset;
|
||||
* +u32 resource offset (not used yet in Xen)
|
||||
* };
|
||||
*
|
||||
*
|
||||
* struct acm_ste_policy_buffer {
|
||||
* u32 policy_version; * ACM_STE_VERSION *
|
||||
* u32 policy_code;
|
||||
* u32 ste_max_types;
|
||||
* u32 ste_max_ssidrefs;
|
||||
* u32 ste_ssid_offset;
|
||||
* };
|
||||
*
|
||||
* struct acm_chwall_policy_buffer {
|
||||
* u32 policy_version; * ACM_CHWALL_VERSION *
|
||||
* u32 policy_code;
|
||||
* u32 chwall_max_types;
|
||||
* u32 chwall_max_ssidrefs;
|
||||
* u32 chwall_max_conflictsets;
|
||||
* u32 chwall_ssid_offset;
|
||||
* u32 chwall_conflict_sets_offset;
|
||||
* u32 chwall_running_types_offset;
|
||||
* u32 chwall_conflict_aggregate_offset;
|
||||
* };
|
||||
*
|
||||
* typedef struct {
|
||||
* u16 partition_max;
|
||||
* u16 partition_offset;
|
||||
* u16 vlan_max;
|
||||
* u16 vlan_offset;
|
||||
* u16 slot_max;
|
||||
* u16 slot_offset;
|
||||
* } acm_resource_buffer_t;
|
||||
*
|
||||
* typedef struct {
|
||||
* u16 id;
|
||||
* u16 ssid_ste;
|
||||
* u16 ssid_chwall;
|
||||
* } acm_partition_entry_t;
|
||||
*
|
||||
* typedef struct {
|
||||
* u16 vlan;
|
||||
* u16 ssid_ste;
|
||||
* } acm_vlan_entry_t;
|
||||
*
|
||||
* typedef struct {
|
||||
* u16 bus;
|
||||
* u16 slot;
|
||||
* u16 ssid_ste;
|
||||
* } acm_slot_entry_t;
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface XmlToBinInterface
|
||||
{
|
||||
/* policy code (uint16) */
|
||||
final int policyCodeSize = 2;
|
||||
|
||||
/* max_types (uint16) */
|
||||
final int maxTypesSize = 2;
|
||||
|
||||
/* max_ssidrefs (uint16) */
|
||||
final int maxSsidrefSize = 2;
|
||||
|
||||
/* ssid_offset (uint32) */
|
||||
final int ssidOffsetSize = 2;
|
||||
|
||||
final short markSymbol = 0x0001;
|
||||
|
||||
final int u32Size = 4;
|
||||
final int u16Size = 2;
|
||||
|
||||
/* num of bytes for acm_ste_policy_buffer_t */
|
||||
final int steHeaderSize = (5 * u32Size);
|
||||
|
||||
/* byte for acm_chinese_wall_policy_buffer_t */
|
||||
final int chwHeaderSize = (9 * u32Size);
|
||||
|
||||
final int primaryPolicyCodeSize = u32Size;
|
||||
final int primaryBufferOffsetSize = u32Size ;
|
||||
|
||||
final int secondaryPolicyCodeSz = u32Size;
|
||||
final int secondaryBufferOffsetSz = u32Size;
|
||||
final int resourceOffsetSz = u32Size;
|
||||
|
||||
final short partitionBufferSz = (2 * u16Size);
|
||||
final short partitionEntrySz = (3 * u16Size);
|
||||
|
||||
final short slotBufferSz = (2 * u16Size);
|
||||
final short slotEntrySz = (3 * u16Size);
|
||||
|
||||
final short vlanBufferSz = (2 * u16Size);
|
||||
final short vlanEntrySz = (2 * u16Size);
|
||||
|
||||
final int binaryBufferHeaderSz = (8 * u32Size); /* 8th not used in Xen */
|
||||
|
||||
/* copied directly from acm.h */
|
||||
final int ACM_MAGIC = 0x0001debc;
|
||||
final int ACM_NULL_POLICY = 0;
|
||||
final int ACM_CHINESE_WALL_POLICY = 1;
|
||||
final int ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY = 2;
|
||||
final int ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY = 3;
|
||||
final int ACM_EMPTY_POLICY = 4;
|
||||
|
||||
/* version for compatibility check */
|
||||
final int ACM_POLICY_VERSION = 1;
|
||||
final int ACM_STE_VERSION = 1;
|
||||
final int ACM_CHWALL_VERSION = 1;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/****************************************************************
|
||||
* c2j_include.c
|
||||
*
|
||||
* Copyright (C) 2005 IBM Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Reiner Sailer <sailer@watson.ibm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2 of the
|
||||
* License.
|
||||
*
|
||||
* This tool makes some constants from acm.h available to the
|
||||
* java policyprocessor for version checking.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
#include <xen/acm.h>
|
||||
|
||||
char *filename = "policy_version.java";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
FILE *fd;
|
||||
if ((fd = fopen(filename, "w")) <= 0)
|
||||
{
|
||||
printf("File %s not found.\n", filename);
|
||||
exit(-ENOENT);
|
||||
}
|
||||
|
||||
fprintf(fd, "/*\n * This file was automatically generated\n");
|
||||
fprintf(fd, " * Do not change it manually!\n */\n");
|
||||
fprintf(fd, "public class policy_version {\n");
|
||||
fprintf(fd, " final int ACM_POLICY_VERSION = %x;\n",
|
||||
ACM_POLICY_VERSION);
|
||||
fprintf(fd, " final int ACM_CHWALL_VERSION = %x;\n",
|
||||
ACM_CHWALL_VERSION);
|
||||
fprintf(fd, " final int ACM_STE_VERSION = %x;\n",
|
||||
ACM_STE_VERSION);
|
||||
fprintf(fd, "}\n");
|
||||
fclose(fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
* (C) Copyright IBM Corp. 2005
|
||||
*
|
||||
* $Id: myHandler.java,v 1.2 2005/06/17 20:00:04 rvaldez Exp $
|
||||
*
|
||||
* Author: Ray Valdez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2 of the
|
||||
* License.
|
||||
*
|
||||
* myHandler Class.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* A dummy class used for detecting XML validating/parsing errors.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
*/
|
||||
import org.xml.sax.helpers.*;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
class myHandler extends DefaultHandler
|
||||
{
|
||||
public boolean isValid = true;
|
||||
|
||||
/* Notification of a recoverable error. */
|
||||
public void error(SAXParseException se)
|
||||
{
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
/* Notification of a non-recoverable error. */
|
||||
public void fatalError(SAXParseException se)
|
||||
{
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
/* Notification of a warning. */
|
||||
public void warning(SAXParseException se)
|
||||
{
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
# Author: Ray Valdez, rvaldez@us.ibm.com
|
||||
# Version: 1.0
|
||||
#
|
||||
# install readme
|
||||
#
|
||||
PREREQUISITES:
|
||||
|
||||
Prior to installation of the policy processor tool (XmlToBin) you must have...
|
||||
|
||||
1. Java version 1.4.2
|
||||
2. xmlParserAPIs.jar and xercesImpl.jar
|
||||
|
||||
The above can be obtained from the Sun Developer Network web site at
|
||||
http://java.sun.com/j2se/1.4.2/download.html.
|
||||
|
||||
XmlParserAPIs and xercesImpl jars can be obtained from
|
||||
http://www.apache.org/dist/xml/xerces-j (Xerces-J-bin.2.6.2.tar.gz,
|
||||
for example).
|
||||
|
||||
The tool has been tested with J2SE v1.4.2_08 JRE on Linux (32-bit
|
||||
INTEL).
|
||||
|
||||
INSTALLATION
|
||||
|
||||
1. Set PATH to include $HOME_JAVA/bin and $HOME_JAVA/jre/bin
|
||||
where $HOME_JAVA is your java installation directory
|
||||
|
||||
2. Compile XmlToBin:
|
||||
javac XmlToBin.java
|
||||
|
||||
USAGE
|
||||
|
||||
See readme.xen
|
||||
@@ -1,65 +0,0 @@
|
||||
# Author: Ray Valdez, rvaldez@us.ibm.com
|
||||
# Version: 1.0
|
||||
#
|
||||
# This readme describes the policy processor tool for sHype.
|
||||
#
|
||||
|
||||
Java program:
|
||||
|
||||
java XmlToBin -i [file.xml] -o <file.bin> -xssid <SsidFile> -xssidconf <SsidConf>
|
||||
|
||||
Command line options:
|
||||
|
||||
-i inputFile: name of policyfile (.xml)
|
||||
-o outputFile: name of binary policy file (Big Endian)
|
||||
-xssid SsidFile: xen ssids to named types text file
|
||||
-xssidconf SsidConf: xen conflict ssids to types text file
|
||||
-debug turn on debug messages
|
||||
-help help. This printout
|
||||
|
||||
Where:
|
||||
|
||||
file.xml is the (input) xml policy file to be parsed and validated.
|
||||
The syntax for file.xml is defined in the SecurityPolicySpec.xsd file.
|
||||
file.bin is the (output) binary policy file generated by XmlToBin.
|
||||
This binary policy can be activated in sHype. The binary policy file
|
||||
is laid out in network byte order (i.e., big endian). The SsidFile
|
||||
file contains the mapping of type enforcement (TE) ssids to the "named
|
||||
types". Similarly, the SsidConf file contains the mapping of Chinese
|
||||
Wall (ChWall) ssids to conflict named types. The ssidFile and SsidConf
|
||||
files are used by Xen.
|
||||
|
||||
Xml Schema and policy:
|
||||
|
||||
The SecurityPolicySpec.xsd defines the syntax of a policy file. It
|
||||
declares the tags that are used by XmlToBin to generate the binary
|
||||
policy file. The tags that XmlToBin keys on are TE, ChWall, id, vid,
|
||||
etc. The xml files that describe a policy are simple. Semantic
|
||||
checking of a policy is performed mostly by XmlToBin. A type, for
|
||||
example, is a string. No fixed values are defined for types in Xml.
|
||||
|
||||
A policy consists of two Xml files: definition and policy. The
|
||||
definition Xml declares the types that are permitted in the policy
|
||||
Xml. The policy Xml contains the assignment of labels to
|
||||
subject/object (e.g., vm). This Xml file contains an explicit
|
||||
reference to the definition Xml (e.g., <url>xen_sample_def.xml</url>).
|
||||
The policy Xml is the one provided as a command line argument.
|
||||
|
||||
|
||||
Files:
|
||||
|
||||
*.java - policy processor source
|
||||
xen_sample_policy.xml - sample xml policy file
|
||||
xen_sample_def.xml - sample user defined types
|
||||
SecurityPolicySpec.xsd - schema definition file
|
||||
|
||||
|
||||
To generate the sample binary policy:
|
||||
|
||||
export CLASSPATH=$XERCES_HOME/xercesImpl.jar:$XERCES_HOME/xmlParserAPIs.jar:.
|
||||
|
||||
java XmlToBin -i xen_sample_policy.xml -o xen_sample_policy.bin
|
||||
|
||||
where $XERCES_HOME is the installation directory of the Apache Xerces-J
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Author: Ray Valdez, rvaldez@us.ibm.com -->
|
||||
<!-- example policy type definition -->
|
||||
<SecurityPolicySpec
|
||||
xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com SecurityPolicySpec.xsd">
|
||||
|
||||
<Definition>
|
||||
<!-- an example of a simple type enforcement type definition -->
|
||||
<Types>
|
||||
<TE>LOCAL-management</TE>
|
||||
<TE>R-Company-development</TE>
|
||||
<TE>S-Company-order</TE>
|
||||
<TE>T-Company-advertising</TE>
|
||||
<TE>U-Company-computing</TE>
|
||||
<!-- TE nondevelopment -->
|
||||
</Types>
|
||||
|
||||
<!-- an example of a chinese wall type definition along with conflict sets-->
|
||||
<ChWallTypes>
|
||||
<ChWall>Q-Company</ChWall>
|
||||
<ChWall>R-Company</ChWall>
|
||||
<ChWall>S-Company</ChWall>
|
||||
<ChWall>T-Company</ChWall>
|
||||
<ChWall>U-Company</ChWall>
|
||||
<ChWall>V-Company</ChWall>
|
||||
<ChWall>W-Company</ChWall>
|
||||
<ChWall>X-Company</ChWall>
|
||||
<ChWall>Y-Company</ChWall>
|
||||
<ChWall>Z-Company</ChWall>
|
||||
</ChWallTypes>
|
||||
|
||||
<ConflictSet>
|
||||
<ChWall>T-Company</ChWall>
|
||||
<ChWall>S-Company</ChWall>
|
||||
</ConflictSet>
|
||||
|
||||
<ConflictSet>
|
||||
<ChWall>R-Company</ChWall>
|
||||
<ChWall>V-Company</ChWall>
|
||||
<ChWall>W-Company</ChWall>
|
||||
</ConflictSet>
|
||||
|
||||
</Definition>
|
||||
</SecurityPolicySpec>
|
||||
@@ -1,58 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Author: Ray Valdez, rvaldez@us.ibm.com -->
|
||||
<!-- example xen policy file -->
|
||||
|
||||
<SecurityPolicySpec
|
||||
xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com SecurityPolicySpec.xsd">
|
||||
<Policy>
|
||||
<PolicyHeader>
|
||||
<Name>xen sample policy</Name>
|
||||
<DateTime>2005-05-20T16:56:00</DateTime>
|
||||
<Tag>foobar</Tag>
|
||||
<TypeDefinition>
|
||||
<url>xen_sample_def.xml</url>
|
||||
<hash>abcdef123456abcdef</hash>
|
||||
</TypeDefinition>
|
||||
</PolicyHeader>
|
||||
|
||||
<VM>
|
||||
<id> 0 </id>
|
||||
<TE>LOCAL-management</TE>
|
||||
<TE>R-Company-development</TE>
|
||||
<TE>S-Company-order</TE>
|
||||
<TE>T-Company-advertising</TE>
|
||||
<TE>U-Company-computing</TE>
|
||||
<ChWall>Q-Company</ChWall>
|
||||
</VM>
|
||||
|
||||
<VM>
|
||||
<id> 1 </id>
|
||||
<TE>R-Company-development</TE>
|
||||
<ChWall>R-Company</ChWall>
|
||||
</VM>
|
||||
|
||||
<VM>
|
||||
<id> 2 </id>
|
||||
<TE>S-Company-order</TE>
|
||||
<ChWall>S-Company</ChWall>
|
||||
|
||||
</VM>
|
||||
|
||||
<VM>
|
||||
<id> 3 </id>
|
||||
<TE>T-Company-advertising</TE>
|
||||
<ChWall>T-Company</ChWall>
|
||||
</VM>
|
||||
|
||||
|
||||
<VM>
|
||||
<id> 4 </id>
|
||||
<TE>U-Company-computing</TE>
|
||||
<ChWall>U-Company</ChWall>
|
||||
</VM>
|
||||
|
||||
|
||||
</Policy>
|
||||
</SecurityPolicySpec>
|
||||
@@ -844,7 +844,7 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args)
|
||||
case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT):
|
||||
P2C(blkif_be_connect_t, domid, u32);
|
||||
P2C(blkif_be_connect_t, blkif_handle, u32);
|
||||
P2C(blkif_be_connect_t, shmem_frame, memory_t);
|
||||
P2C(blkif_be_connect_t, shmem_frame, unsigned long);
|
||||
P2C(blkif_be_connect_t, shmem_ref, u32);
|
||||
P2C(blkif_be_connect_t, evtchn, u16);
|
||||
break;
|
||||
@@ -906,9 +906,9 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args)
|
||||
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT):
|
||||
P2C(netif_be_connect_t, domid, u32);
|
||||
P2C(netif_be_connect_t, netif_handle, u32);
|
||||
P2C(netif_be_connect_t, tx_shmem_frame, memory_t);
|
||||
P2C(netif_be_connect_t, tx_shmem_frame, unsigned long);
|
||||
P2C(netif_be_connect_t, tx_shmem_ref, u32);
|
||||
P2C(netif_be_connect_t, rx_shmem_frame, memory_t);
|
||||
P2C(netif_be_connect_t, rx_shmem_frame, unsigned long);
|
||||
P2C(netif_be_connect_t, rx_shmem_ref, u32);
|
||||
P2C(netif_be_connect_t, evtchn, u16);
|
||||
break;
|
||||
@@ -942,7 +942,7 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args)
|
||||
P2C(usbif_fe_driver_status_changed_t, status, u32);
|
||||
break;
|
||||
case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_CONNECT):
|
||||
P2C(usbif_fe_interface_connect_t, shmem_frame, memory_t);
|
||||
P2C(usbif_fe_interface_connect_t, shmem_frame, unsigned long);
|
||||
break;
|
||||
case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT):
|
||||
break;
|
||||
@@ -956,7 +956,7 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args)
|
||||
break;
|
||||
case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CONNECT):
|
||||
P2C(usbif_be_connect_t, domid, domid_t);
|
||||
P2C(usbif_be_connect_t, shmem_frame, memory_t);
|
||||
P2C(usbif_be_connect_t, shmem_frame, unsigned long);
|
||||
P2C(usbif_be_connect_t, evtchn, u32);
|
||||
P2C(usbif_be_connect_t, bandwidth, u32);
|
||||
P2C(usbif_be_connect_t, status, u32);
|
||||
|
||||
@@ -36,8 +36,10 @@ from xen.xend.server import controller
|
||||
from xen.xend.server import SrvDaemon; xend = SrvDaemon.instance()
|
||||
from xen.xend.server import messages
|
||||
from xen.xend.server.channel import EventChannel, channelFactory
|
||||
from xen.util.blkif import blkdev_name_to_number, expand_dev_name
|
||||
|
||||
from xen.xend import sxp
|
||||
from xen.xend import Blkctl
|
||||
from xen.xend.PrettyPrint import prettyprintstring
|
||||
from xen.xend.XendBootloader import bootloader
|
||||
from xen.xend.XendLogging import log
|
||||
@@ -380,6 +382,39 @@ class XendDomainInfo:
|
||||
return ctrl
|
||||
|
||||
def createDevice(self, type, devconfig, change=False):
|
||||
if type == 'vbd':
|
||||
|
||||
backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0'))
|
||||
|
||||
devnum = blkdev_name_to_number(sxp.child_value(devconfig, 'dev'))
|
||||
|
||||
# create backend db
|
||||
backdb = backdom.db.addChild("/backend/%s/%s/%d" %
|
||||
(type, self.uuid, devnum))
|
||||
|
||||
# create frontend db
|
||||
db = self.db.addChild("/device/%s/%d" % (type, devnum))
|
||||
|
||||
db['virtual-device'] = "%i" % devnum
|
||||
#db['backend'] = sxp.child_value(devconfig, 'backend', '0')
|
||||
db['backend'] = backdb.getPath()
|
||||
db['backend-id'] = "%i" % int(sxp.child_value(devconfig,
|
||||
'backend', '0'))
|
||||
|
||||
backdb['frontend'] = db.getPath()
|
||||
(type, params) = string.split(sxp.child_value(devconfig, 'uname'), ':', 1)
|
||||
node = Blkctl.block('bind', type, params)
|
||||
backdb['frontend-id'] = "%i" % self.id
|
||||
backdb['physical-device'] = "%li" % blkdev_name_to_number(node)
|
||||
backdb.saveDB(save=True)
|
||||
|
||||
# Ok, super gross, this really doesn't belong in the frontend db...
|
||||
db['type'] = type
|
||||
db['node'] = node
|
||||
db['params'] = params
|
||||
db.saveDB(save=True)
|
||||
|
||||
return
|
||||
ctrl = self.findDeviceController(type)
|
||||
return ctrl.createDevice(devconfig, recreate=self.recreate,
|
||||
change=change)
|
||||
@@ -671,6 +706,16 @@ class XendDomainInfo:
|
||||
for ctrl in self.getDeviceControllers():
|
||||
if ctrl.isDestroyed(): continue
|
||||
ctrl.destroyController(reboot=reboot)
|
||||
ddb = self.db.addChild("/device")
|
||||
for type in ddb.keys():
|
||||
if type == 'vbd':
|
||||
typedb = ddb.addChild(type)
|
||||
for dev in typedb.keys():
|
||||
devdb = typedb.addChild(str(dev))
|
||||
Blkctl.block('unbind', devdb['type'].getData(),
|
||||
devdb['node'].getData())
|
||||
typedb[dev].delete()
|
||||
typedb.saveDB(save=True)
|
||||
|
||||
def show(self):
|
||||
"""Print virtual machine info.
|
||||
@@ -926,6 +971,7 @@ class XendDomainInfo:
|
||||
at creation time, for example when it uses NFS root.
|
||||
|
||||
"""
|
||||
return
|
||||
blkif = self.getDeviceController("vbd", error=False)
|
||||
if not blkif:
|
||||
blkif = self.createDeviceController("vbd")
|
||||
|
||||
@@ -50,7 +50,7 @@ class EventProtocol(protocol.Protocol):
|
||||
def dataReceived(self, data):
|
||||
try:
|
||||
self.parser.input(data)
|
||||
if self.parser.ready():
|
||||
while(self.parser.ready()):
|
||||
val = self.parser.get_val()
|
||||
res = self.dispatch(val)
|
||||
self.send_result(res)
|
||||
|
||||
@@ -42,7 +42,7 @@ class RelocationProtocol(protocol.Protocol):
|
||||
def dataReceived(self, data):
|
||||
try:
|
||||
self.parser.input(data)
|
||||
if self.parser.ready():
|
||||
while(self.parser.ready()):
|
||||
val = self.parser.get_val()
|
||||
res = self.dispatch(val)
|
||||
self.send_result(res)
|
||||
|
||||
+53
-9
@@ -2,27 +2,71 @@ XEN_ROOT = ../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
SRCS = secpol_tool.c
|
||||
CFLAGS += -static
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -O3
|
||||
CFLAGS += -fno-strict-aliasing
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I. -I/usr/include/libxml2
|
||||
CFLAGS_XML2BIN += $(shell xml2-config --cflags --libs )
|
||||
#if above does not work, try -L/usr/lib -lxml2 -lz -lpthread -lm
|
||||
XML2VERSION = $(shell xml2-config --version )
|
||||
VALIDATE_SCHEMA=$(shell if [[ $(XML2VERSION) < 2.6.20 ]]; then echo ""; else echo "-DVALIDATE_SCHEMA"; fi; )
|
||||
|
||||
ifeq ($(ACM_USE_SECURITY_POLICY),ACM_NULL_POLICY)
|
||||
POLICY=null
|
||||
endif
|
||||
ifeq ($(ACM_USE_SECURITY_POLICY),ACM_CHINESE_WALL_POLICY)
|
||||
POLICY=chwall
|
||||
endif
|
||||
ifeq ($(ACM_USE_SECURITY_POLICY),ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY)
|
||||
POLICY=ste
|
||||
endif
|
||||
ifeq ($(ACM_USE_SECURITY_POLICY),ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY)
|
||||
POLICY=chwall_ste
|
||||
endif
|
||||
POLICYFILE=./policies/$(POLICY)/$(POLICY).bin
|
||||
|
||||
ifneq ($(ACM_USE_SECURITY_POLICY), ACM_NULL_POLICY)
|
||||
all: build
|
||||
|
||||
install:all
|
||||
|
||||
default:all
|
||||
else
|
||||
all:
|
||||
|
||||
install:
|
||||
|
||||
default:
|
||||
endif
|
||||
|
||||
build: mk-symlinks
|
||||
$(MAKE) secpol_tool
|
||||
$(MAKE) secpol_xml2bin
|
||||
chmod 700 ./setlabel.sh
|
||||
chmod 700 ./updategrub.sh
|
||||
|
||||
default: all
|
||||
|
||||
install: all
|
||||
|
||||
secpol_tool : secpol_tool.c
|
||||
secpol_tool : secpol_tool.c secpol_compat.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf secpol_tool xen
|
||||
secpol_xml2bin : secpol_xml2bin.c secpol_xml2bin.h secpol_compat.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_XML2BIN) $(VALIDATE_SCHEMA) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf secpol_tool secpol_xml2bin xen
|
||||
|
||||
policy_clean:
|
||||
rm -rf policies/*/*.bin policies/*/*.map
|
||||
|
||||
mrproper: clean policy_clean
|
||||
|
||||
|
||||
$(POLICYFILE) : build
|
||||
@./secpol_xml2bin $(POLICY) > /dev/null
|
||||
|
||||
boot_install: $(POLICYFILE)
|
||||
@cp $(POLICYFILE) /boot
|
||||
@./updategrub.sh $(POLICY) $(PWD)/$(XEN_ROOT)
|
||||
|
||||
LINUX_ROOT := $(XEN_ROOT)/linux-2.6-xen-sparse
|
||||
mk-symlinks:
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
##
|
||||
# example.txt <description to the xen access control architecture>
|
||||
#
|
||||
# Author:
|
||||
# Reiner Sailer 08/15/2005 <sailer@watson.ibm.com>
|
||||
#
|
||||
#
|
||||
# This file introduces into the tools to manage policies
|
||||
# and to label domains and resources.
|
||||
##
|
||||
|
||||
We will show how to install and use the chwall_ste policy.
|
||||
Other policies work similarly. Feedback welcome!
|
||||
|
||||
|
||||
|
||||
1. Using secpol_xml2bin to translate the chwall_ste policy:
|
||||
===========================================================
|
||||
|
||||
#tools/security/secpol_xml2bin chwall_ste
|
||||
|
||||
Successful execution should print:
|
||||
|
||||
[root@laptopxn security]# ./secpol_xml2bin chwall_ste
|
||||
Validating label file policies/chwall_ste/chwall_ste-security_label_template.xml...
|
||||
XML Schema policies/security_policy.xsd valid.
|
||||
Validating policy file policies/chwall_ste/chwall_ste-security_policy.xml...
|
||||
XML Schema policies/security_policy.xsd valid.
|
||||
Creating ssid mappings ...
|
||||
Creating label mappings ...
|
||||
Max chwall labels: 7
|
||||
Max chwall-types: 4
|
||||
Max chwall-ssids: 5
|
||||
Max ste labels: 14
|
||||
Max ste-types: 6
|
||||
Max ste-ssids: 10
|
||||
|
||||
The tool looks in directory policies/chwall_ste for
|
||||
the label and policy files.
|
||||
|
||||
The default policy directory structure under tools/security looks like:
|
||||
|
||||
policies
|
||||
|-- security_policy.xsd
|
||||
|-- chwall
|
||||
| |-- chwall-security_label_template.xml
|
||||
| `-- chwall-security_policy.xml
|
||||
|-- chwall_ste
|
||||
| |-- chwall_ste-security_label_template.xml
|
||||
| `-- chwall_ste-security_policy.xml
|
||||
|-- null
|
||||
| |-- null-security_label_template.xml
|
||||
| `-- null-security_policy.xml
|
||||
`-- ste
|
||||
|-- ste-security_label_template.xml
|
||||
`-- ste-security_policy.xml
|
||||
|
||||
policies/security_policy.xsd contains the schema against which both the
|
||||
label-template and the policy files must validate during translation.
|
||||
|
||||
policies/chwall_ste/chwall_ste-security_policy.xml defines the
|
||||
policies and the types known to the policies.
|
||||
|
||||
policies/chwall_ste/chwall_ste-security_label_template.xml contains
|
||||
label definitions that group chwall and ste types together and make
|
||||
them easier to use for users
|
||||
|
||||
After executing the above secpol_xml2bin command, you will find 2 new
|
||||
files in the policies/chwall_ste sub-directory:
|
||||
|
||||
policies/chwall_ste/chwall_ste.map ... this file includes the mapping
|
||||
of names from the xml files into their binary code representation.
|
||||
|
||||
policies/chwall_ste/chwall_ste.bin ... this is the binary policy file,
|
||||
the result of parsing the xml files and using the mapping to extract a
|
||||
binary version that can be loaded into the hypervisor.
|
||||
|
||||
|
||||
|
||||
2. Loading and activating the policy:
|
||||
=====================================
|
||||
|
||||
We assume that xen is already configured to use the chwall_ste policy;
|
||||
please refer to install.txt for instructions.
|
||||
|
||||
To activate the policy from the command line (assuming that the
|
||||
currently established policy is the minimal boot-policy that is
|
||||
hard-coded into the hypervisor:
|
||||
|
||||
# ./secpol_tool loadpolicy policies/chwall_ste/chwall_ste.bin
|
||||
|
||||
To activate the policy at next reboot:
|
||||
|
||||
# cp policies/chwall_ste/chwall_ste.bin /boot
|
||||
|
||||
Add a module line to your /boot/grub/grub.conf Xen entry.
|
||||
My boot entry with chwall_ste enabled looks like this:
|
||||
|
||||
title Xen (2.6.12)
|
||||
root (hd0,5)
|
||||
kernel /boot/xen.gz dom0_mem=1200000 console=vga
|
||||
module /boot/vmlinuz-2.6.12-xen0 ro root=/dev/hda6 rhgb
|
||||
module /boot/initrd-2.6.12-xen0.img
|
||||
module /boot/chwall_ste.bin
|
||||
|
||||
This tells the grub boot-loader to load the binary policy, which
|
||||
the hypervisor will recognize. The hypervisor will then establish
|
||||
this binary policy during boot instead of the minimal policy that
|
||||
is hardcoded as default.
|
||||
|
||||
If you have any trouble here, maks sure you have the access control
|
||||
framework enabled (see: install.txt).
|
||||
|
||||
|
||||
|
||||
3. Labeling domains:
|
||||
====================
|
||||
|
||||
a) Labeling Domain0:
|
||||
|
||||
The chwall_ste-security_label_template.xml file includes an attribute
|
||||
"bootstrap", which is set to the label name that will be assigned to
|
||||
Dom0 (this label will be mapped to ssidref 1/1, the default for Dom0).
|
||||
|
||||
b) Labeling User Domains:
|
||||
|
||||
Use the script tools/security/setlabel.sh to choose a label and to
|
||||
assign labels to user domains.
|
||||
|
||||
To show available labels for the chwall_ste policy:
|
||||
|
||||
#tools/security/setlabel.sh -l
|
||||
|
||||
lists all available labels. For the default chwall_ste it should print
|
||||
the following:
|
||||
|
||||
[root@laptopxn security]# ./setlabel.sh -l chwall_ste
|
||||
The following labels are available:
|
||||
dom_SystemManagement
|
||||
dom_HomeBanking
|
||||
dom_Fun
|
||||
dom_BoincClient
|
||||
dom_StorageDomain
|
||||
dom_NetworkDomain
|
||||
|
||||
You need to have compiled the policy beforehand so that a .map file
|
||||
exists. Setlabel.sh uses the mapping file created throughout the
|
||||
policy translation to translate a user-friendly label string into a
|
||||
ssidref-number that is eventually used by the Xen hypervisor.
|
||||
|
||||
We distinguish two kinds of labels: a) VM labels (for domains) and RES
|
||||
Labels (for resources). We are currently working on support for
|
||||
resource labeling but will focus here on VM labels.
|
||||
|
||||
Setlabel.sh only prints VM labels (which we have prefixed with "dom_")
|
||||
since only those are used at this time.
|
||||
|
||||
If you would like to assign the dom_HomeBanking label to one of your
|
||||
user domains (which you hopefully keep clean), look at an example
|
||||
domain configuration homebanking.xm:
|
||||
|
||||
#------HOMEBANKING---------
|
||||
kernel = "/boot/vmlinuz-2.6.12-xenU"
|
||||
ramdisk="/boot/U1_ramdisk.img"
|
||||
memory = 65
|
||||
name = "test34"
|
||||
cpu = -1 # leave to Xen to pick
|
||||
# Number of network interfaces. Default is 1.
|
||||
nics=1
|
||||
dhcp="dhcp"
|
||||
#-------------------------
|
||||
|
||||
Now we label this domain
|
||||
|
||||
[root@laptopxn security]# ./setlabel.sh homebanking.xm dom_HomeBanking chwall_ste
|
||||
Mapped label 'dom_HomeBanking' to ssidref '0x00020002'.
|
||||
|
||||
The domain configuration my look now like:
|
||||
|
||||
[root@laptopxn security]# cat homebanking.xm
|
||||
#------HOMEBANKING---------
|
||||
kernel = "/boot/vmlinuz-2.6.12-xenU"
|
||||
ramdisk="/boot/U1_ramdisk.img"
|
||||
memory = 65
|
||||
name = "test34"
|
||||
cpu = -1 # leave to Xen to pick
|
||||
# Number of network interfaces. Default is 1.
|
||||
nics=1
|
||||
dhcp="dhcp"
|
||||
#-------------------------
|
||||
#ACM_POLICY=chwall_ste-security_policy.xml
|
||||
#ACM_LABEL=dom_HomeBanking
|
||||
ssidref = 0x00020002
|
||||
|
||||
You can see 3 new entries, two of which are comments. The only value
|
||||
that the hypervisor cares about is the ssidref that will reference
|
||||
those types assigned to this label. You can look them up in the
|
||||
xml label-template file for the chwall_ste policy.
|
||||
|
||||
This script will eventually move into the domain management and will
|
||||
be called when the domain is instantiated. For now, the setlabel
|
||||
script must be run on domains whenever the policy files change since
|
||||
the mapping between label names and ssidrefs can change in this case.
|
||||
|
||||
|
||||
4. Starting a labeled domain
|
||||
============================
|
||||
|
||||
Now, start the domain:
|
||||
#xm create -c homebanking.xm
|
||||
|
||||
|
||||
If you label another domain configuration as dom_Fun and try to start
|
||||
it afterwards, its start will fail. Why?
|
||||
|
||||
Because the running homebanking domain has the chinese wall type
|
||||
"cw_Sensitive". The new domain dom_Fun has the chinese wall label
|
||||
"cw_Distrusted". This domain is not allowed to run simultaneously
|
||||
because of the defined conflict set
|
||||
|
||||
<conflictset name="Protection1">
|
||||
<type>cw_Sensitive</type>
|
||||
<type>cw_Distrusted</type>
|
||||
</conflictset>
|
||||
|
||||
(in policies/chwall_ste/chwall_ste-security_policy.xml), which says
|
||||
that only one of the types cw_sensitive and cw_Distrusted can run at a
|
||||
time.
|
||||
|
||||
If you save or shutdown the HomeBanking domain, you will be able to
|
||||
start the "Fun" domain. You can look into the Xen log to see if a
|
||||
domain was denied to start because of the access control framework
|
||||
with the command 'xm dmesg'.
|
||||
|
||||
It is important (and usually non-trivial) to define the labels in a
|
||||
way that the semantics of the labels are enforced and supported by the
|
||||
types and the conflict sets.
|
||||
|
||||
Note: While the chinese wall policy enforcement is complete, the type
|
||||
enforcement is currently enforced in the Xen hypervisor
|
||||
only. Therefore, only point-to-point sharing with regard to the type
|
||||
enforcement is currently controlled. We are working on enhancements to
|
||||
Dom0 that enforce types also for network traffic that is routed
|
||||
through Dom0 and on the enforcement of resource labeling when binding
|
||||
resources to domains (e.g., enforcing types between domains and
|
||||
hardware resources, such as disk partitions).
|
||||
|
||||
|
||||
4. Adding your own policies
|
||||
===========================
|
||||
|
||||
Writing your own policy (e.g. "mypolicy") requires the following:
|
||||
|
||||
a) the policy definition (types etc.) file
|
||||
b) the label template definition (labels etc.) file
|
||||
|
||||
If your policy name is "mypolicy", you need to create a
|
||||
subdirectory mypolicy in tools/security/policies.
|
||||
|
||||
Then you create
|
||||
tools/security/policies/mypolicy/mypolicy-security_policy.xml and
|
||||
tools/security/policies/mypolicy/mypolicy-security_label_template.xml.
|
||||
|
||||
You need to keep to the schema as defined in
|
||||
tools/security/security_policy.xsd since the translation tool
|
||||
secpol_xml2bin is written against this schema.
|
||||
|
||||
If you keep to the security policy schema, then you can use all the
|
||||
tools described above. Refer to install.txt to install it.
|
||||
@@ -0,0 +1,67 @@
|
||||
##
|
||||
# install.txt <description to the xen access control architecture>
|
||||
#
|
||||
# Author:
|
||||
# Reiner Sailer 08/15/2005 <sailer@watson.ibm.com>
|
||||
#
|
||||
#
|
||||
# This file shows how to activate and install the access control
|
||||
# framework.
|
||||
##
|
||||
|
||||
|
||||
INSTALLING A SECURITY POLICY IN XEN
|
||||
===================================
|
||||
|
||||
By default, the access control architecture is disabled in Xen. To
|
||||
enable the access control architecture in Xen follow the steps below.
|
||||
This description assumes that you want to install the Chinese Wall and
|
||||
Simple Type Enforcement policy. Some file names need to be replaced
|
||||
below to activate the Chinese Wall OR the Type Enforcement policy
|
||||
exclusively (chwall_ste --> {chwall, ste}).
|
||||
|
||||
1. enable access control in Xen
|
||||
# cd "xen_root"
|
||||
# edit/xemacs/vi Config.mk
|
||||
|
||||
change the line:
|
||||
ACM_USE_SECURITY_POLICY ?= ACM_NULL_POLICY
|
||||
|
||||
to:
|
||||
ACM_USE_SECURITY_POLICY ?= ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY
|
||||
|
||||
# make all
|
||||
# ./install.sh
|
||||
|
||||
2. compile the policy from xml to a binary format that can be loaded
|
||||
into the hypervisor for enforcement
|
||||
# cd tools/security
|
||||
# make
|
||||
|
||||
manual steps (alternative to make boot_install):
|
||||
#./secpol_xml2bin chwall_ste
|
||||
#cp policies/chwall_ste/chwall_ste.bin /boot
|
||||
#edit /boot/grub/grub.conf
|
||||
add the follwoing line to your xen boot entry:
|
||||
"module chwall_ste.bin"
|
||||
|
||||
alternatively, you can try our automatic translation and
|
||||
installation of the policy:
|
||||
# make boot_install
|
||||
|
||||
[we try hard to do the right thing to the right boot entry but
|
||||
please verify boot entry in /boot/grub/grub.conf afterwards;
|
||||
your xen boot entry should have an additional module line
|
||||
specifying a chwall_ste.bin file with the correct directory
|
||||
(e.g. "/" or "/boot").]
|
||||
|
||||
|
||||
3. reboot into the newly compiled hypervisor
|
||||
|
||||
after boot
|
||||
#xm dmesg should show an entry about the policy being loaded
|
||||
during the boot process
|
||||
|
||||
#tools/security/secpol_tool getpolicy
|
||||
should print the new chwall_ste binary policy representation
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Author: Reiner Sailer, Ray Valdez {sailer,rvaldez}@us.ibm.com -->
|
||||
<!-- This file defines the security labels, which can -->
|
||||
<!-- be attached to Domains and resources. Based on -->
|
||||
<!-- these labels, the access control module decides -->
|
||||
<!-- about sharing between Domains and about access -->
|
||||
<!-- of Domains to real resources. -->
|
||||
|
||||
<SecurityLabelTemplate
|
||||
xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com security_policy.xsd">
|
||||
<LabelHeader>
|
||||
<Name>chwall-security_label_template</Name>
|
||||
<Date>2005-08-10</Date>
|
||||
<PolicyName>
|
||||
<Url>chwall-security_policy.xml</Url>
|
||||
<Reference>abcdef123456abcdef</Reference>
|
||||
</PolicyName>
|
||||
</LabelHeader>
|
||||
|
||||
<SubjectLabels bootstrap="dom_SystemManagement">
|
||||
<!-- single ste typed domains -->
|
||||
<!-- ACM enforces that only domains with -->
|
||||
<!-- the same type can share information -->
|
||||
<!-- -->
|
||||
<!-- Bootstrap label is assigned to Dom0 -->
|
||||
<VirtualMachineLabel>
|
||||
<Name>dom_HomeBanking</Name>
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_Sensitive</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<Name>dom_Fun</Name>
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_Distrusted</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<!-- donating some cycles to seti@home -->
|
||||
<Name>dom_BoincClient</Name>
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_Isolated</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<!-- Domains with multiple ste types services; such domains -->
|
||||
<!-- must keep the types inside their domain safely confined. -->
|
||||
<VirtualMachineLabel>
|
||||
<Name>dom_SystemManagement</Name>
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_SystemManagement</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<!-- serves persistent storage to other domains -->
|
||||
<Name>dom_StorageDomain</Name>
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_SystemManagement</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<!-- serves network access to other domains -->
|
||||
<Name>dom_NetworkDomain</Name>
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_SystemManagement</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
</SubjectLabels>
|
||||
</SecurityLabelTemplate>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Author: Reiner Sailer, Ray Valdez {sailer,rvaldez}@us.ibm.com -->
|
||||
<!-- This file defines the security policies, which -->
|
||||
<!-- can be enforced by the Xen Access Control Module. -->
|
||||
<!-- Currently: Chinese Wall and Simple Type Enforcement-->
|
||||
<SecurityPolicyDefinition xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com security_policy.xsd">
|
||||
<PolicyHeader>
|
||||
<Name>chwall-security_policy</Name>
|
||||
<Date>2005-08-10</Date>
|
||||
</PolicyHeader>
|
||||
<!-- -->
|
||||
<!-- example of a chinese wall type definition -->
|
||||
<!-- along with its conflict sets -->
|
||||
<!-- (typse in a confict set are exclusive, i.e. -->
|
||||
<!-- once a Domain with one type of a set is -->
|
||||
<!-- running, no other Domain with another type -->
|
||||
<!-- of the same conflict set can start.) -->
|
||||
<ChineseWall priority="PrimaryPolicyComponent">
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_SystemManagement</Type>
|
||||
<Type>cw_Sensitive</Type>
|
||||
<Type>cw_Isolated</Type>
|
||||
<Type>cw_Distrusted</Type>
|
||||
</ChineseWallTypes>
|
||||
|
||||
<ConflictSets>
|
||||
<Conflict name="Protection1">
|
||||
<Type>cw_Sensitive</Type>
|
||||
<Type>cw_Distrusted</Type>
|
||||
</Conflict>
|
||||
</ConflictSets>
|
||||
</ChineseWall>
|
||||
</SecurityPolicyDefinition>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Author: Reiner Sailer, Ray Valdez {sailer,rvaldez}@us.ibm.com -->
|
||||
<!-- This file defines the security labels, which can -->
|
||||
<!-- be attached to Domains and resources. Based on -->
|
||||
<!-- these labels, the access control module decides -->
|
||||
<!-- about sharing between Domains and about access -->
|
||||
<!-- of Domains to real resources. -->
|
||||
|
||||
<SecurityLabelTemplate
|
||||
xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com security_policy.xsd">
|
||||
<LabelHeader>
|
||||
<Name>chwall_ste-security_label_template</Name>
|
||||
<Date>2005-08-10</Date>
|
||||
<PolicyName>
|
||||
<Url>chwall_ste-security_policy.xml</Url>
|
||||
<Reference>abcdef123456abcdef</Reference>
|
||||
</PolicyName>
|
||||
</LabelHeader>
|
||||
|
||||
<SubjectLabels bootstrap="dom_SystemManagement">
|
||||
<!-- single ste typed domains -->
|
||||
<!-- ACM enforces that only domains with -->
|
||||
<!-- the same type can share information -->
|
||||
<!-- -->
|
||||
<!-- Bootstrap label is assigned to Dom0 -->
|
||||
<VirtualMachineLabel>
|
||||
<Name>dom_HomeBanking</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_Sensitive</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<Name>dom_Fun</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_Distrusted</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<!-- donating some cycles to seti@home -->
|
||||
<Name>dom_BoincClient</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_DonatedCycles</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_Isolated</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<!-- Domains with multiple ste types services; such domains -->
|
||||
<!-- must keep the types inside their domain safely confined. -->
|
||||
<VirtualMachineLabel>
|
||||
<Name>dom_SystemManagement</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<!-- since dom0 needs access to every domain and -->
|
||||
<!-- resource right now ... -->
|
||||
<Type>ste_SystemManagement</Type>
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
<Type>ste_DonatedCycles</Type>
|
||||
<Type>ste_PersistentStorageA</Type>
|
||||
<Type>ste_NetworkAdapter0</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_SystemManagement</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<!-- serves persistent storage to other domains -->
|
||||
<Name>dom_StorageDomain</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<!-- access right to the resource (hard drive a) -->
|
||||
<Type>ste_PersistentStorageA</Type>
|
||||
<!-- can serve following types -->
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_SystemManagement</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<!-- serves network access to other domains -->
|
||||
<Name>dom_NetworkDomain</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<!-- access right to the resource (ethernet card) -->
|
||||
<Type>ste_NetworkAdapter0</Type>
|
||||
<!-- can serve following types -->
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
<Type>ste_DonatedCycles</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_SystemManagement</Type>
|
||||
</ChineseWallTypes>
|
||||
</VirtualMachineLabel>
|
||||
</SubjectLabels>
|
||||
|
||||
<ObjectLabels>
|
||||
<ResourceLabel>
|
||||
<Name>res_ManagementResource</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_SystemManagement</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_HardDrive (hda)</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_PersistentStorageA</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_LogicalDiskPartition1 (hda1)</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_LogicalDiskPartition2 (hda2)</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_EthernetCard</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_NetworkAdapter0</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_SecurityToken</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_GraphicsAdapter</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_SystemManagement</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
</ObjectLabels>
|
||||
</SecurityLabelTemplate>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Author: Reiner Sailer, Ray Valdez {sailer,rvaldez}@us.ibm.com -->
|
||||
<!-- This file defines the security policies, which -->
|
||||
<!-- can be enforced by the Xen Access Control Module. -->
|
||||
<!-- Currently: Chinese Wall and Simple Type Enforcement-->
|
||||
<SecurityPolicyDefinition xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com security_policy.xsd">
|
||||
<PolicyHeader>
|
||||
<Name>chwall_ste-security_policy</Name>
|
||||
<Date>2005-08-10</Date>
|
||||
</PolicyHeader>
|
||||
<!-- -->
|
||||
<!-- example of a simple type enforcement policy definition -->
|
||||
<!-- -->
|
||||
<SimpleTypeEnforcement>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_SystemManagement</Type> <!-- machine/security management -->
|
||||
<Type>ste_PersonalFinances</Type> <!-- personal finances -->
|
||||
<Type>ste_InternetInsecure</Type> <!-- games, active X, etc. -->
|
||||
<Type>ste_DonatedCycles</Type> <!-- donation to BOINC/seti@home -->
|
||||
<Type>ste_PersistentStorageA</Type> <!-- domain managing the harddrive A-->
|
||||
<Type>ste_NetworkAdapter0</Type> <!-- type of the domain managing ethernet adapter 0-->
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</SimpleTypeEnforcement>
|
||||
<!-- -->
|
||||
<!-- example of a chinese wall type definition -->
|
||||
<!-- along with its conflict sets -->
|
||||
<!-- (typse in a confict set are exclusive, i.e. -->
|
||||
<!-- once a Domain with one type of a set is -->
|
||||
<!-- running, no other Domain with another type -->
|
||||
<!-- of the same conflict set can start.) -->
|
||||
<ChineseWall priority="PrimaryPolicyComponent">
|
||||
<ChineseWallTypes>
|
||||
<Type>cw_SystemManagement</Type>
|
||||
<Type>cw_Sensitive</Type>
|
||||
<Type>cw_Isolated</Type>
|
||||
<Type>cw_Distrusted</Type>
|
||||
</ChineseWallTypes>
|
||||
|
||||
<ConflictSets>
|
||||
<Conflict name="Protection1">
|
||||
<Type>cw_Sensitive</Type>
|
||||
<Type>cw_Distrusted</Type>
|
||||
</Conflict>
|
||||
</ConflictSets>
|
||||
</ChineseWall>
|
||||
</SecurityPolicyDefinition>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Author: Reiner Sailer, Ray Valdez {sailer,rvaldez}@us.ibm.com -->
|
||||
<!-- This file defines the security labels, which can -->
|
||||
<!-- be attached to Domains and resources. Based on -->
|
||||
<!-- these labels, the access control module decides -->
|
||||
<!-- about sharing between Domains and about access -->
|
||||
<!-- of Domains to real resources. -->
|
||||
|
||||
<SecurityLabelTemplate
|
||||
xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com security_policy.xsd">
|
||||
<LabelHeader>
|
||||
<Name>null-security_label_template</Name>
|
||||
|
||||
<Date>2005-08-10</Date>
|
||||
<PolicyName>
|
||||
<Url>null-security_policy.xml</Url>
|
||||
|
||||
<Reference>abcdef123456abcdef</Reference>
|
||||
</PolicyName>
|
||||
</LabelHeader>
|
||||
</SecurityLabelTemplate>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Author: Reiner Sailer, Ray Valdez {sailer,rvaldez}@us.ibm.com -->
|
||||
<!-- This file defines the security policies, which -->
|
||||
<!-- can be enforced by the Xen Access Control Module. -->
|
||||
<!-- Currently: Chinese Wall and Simple Type Enforcement-->
|
||||
<SecurityPolicyDefinition xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com security_policy.xsd">
|
||||
<PolicyHeader>
|
||||
<Name>null-security_policy</Name>
|
||||
<Date>2005-08-10</Date>
|
||||
</PolicyHeader>
|
||||
</SecurityPolicyDefinition>
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Author: Ray Valdez, Reiner Sailer {rvaldez,sailer}@us.ibm.com -->
|
||||
<!-- This file defines the schema, which is used to define -->
|
||||
<!-- the security policy and the security labels in Xe. -->
|
||||
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.ibm.com" xmlns="http://www.ibm.com" elementFormDefault="qualified">
|
||||
<xsd:element name="SecurityPolicyDefinition">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="PolicyHeader" minOccurs="0" maxOccurs="1"></xsd:element>
|
||||
<xsd:element ref="SimpleTypeEnforcement" minOccurs="0" maxOccurs="1"></xsd:element>
|
||||
<xsd:element ref="ChineseWall" minOccurs="0" maxOccurs="1"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="SecurityLabelTemplate">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="LabelHeader" minOccurs="1" maxOccurs="1"></xsd:element>
|
||||
<xsd:element name="SubjectLabels" minOccurs="0" maxOccurs="1">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="VirtualMachineLabel" minOccurs="1" maxOccurs="unbounded"></xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="bootstrap" type="xsd:string" use="required"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="ObjectLabels" minOccurs="0" maxOccurs="1">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="ResourceLabel" minOccurs="1" maxOccurs="unbounded"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="PolicyHeader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="Name" minOccurs="1" maxOccurs="1" />
|
||||
<xsd:element ref="Date" minOccurs="1" maxOccurs="1" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="LabelHeader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="Name"></xsd:element>
|
||||
<xsd:element ref="Date" minOccurs="1" maxOccurs="1"></xsd:element>
|
||||
<xsd:element ref="PolicyName" minOccurs="1" maxOccurs="1"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="SimpleTypeEnforcement">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="SimpleTypeEnforcementTypes" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="priority" type="PolicyOrder" use="optional"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="ChineseWall">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="ChineseWallTypes" />
|
||||
<xsd:element ref="ConflictSets" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="priority" type="PolicyOrder" use="optional"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="ChineseWallTypes">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element maxOccurs="unbounded" minOccurs="1" ref="Type" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="ConflictSets">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element maxOccurs="unbounded" minOccurs="1" ref="Conflict" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="SimpleTypeEnforcementTypes">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element maxOccurs="unbounded" minOccurs="1" ref="Type" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="Conflict">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element maxOccurs="unbounded" minOccurs="1" ref="Type" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="optional"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="VirtualMachineLabel">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="Name"></xsd:element>
|
||||
<xsd:element ref="SimpleTypeEnforcementTypes" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element ref="ChineseWallTypes" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="ResourceLabel">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="Name"></xsd:element>
|
||||
<xsd:element ref="SimpleTypeEnforcementTypes" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="PolicyName">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="Url" />
|
||||
<xsd:element ref="Reference" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="Date" type="xsd:string" />
|
||||
<xsd:element name="Name" type="xsd:string" />
|
||||
<xsd:element name="Type" type="xsd:string" />
|
||||
<xsd:element name="Reference" type="xsd:string" />
|
||||
<xsd:element name="Url"></xsd:element>
|
||||
|
||||
<xsd:simpleType name="PolicyOrder">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="PrimaryPolicyComponent"></xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
</xsd:schema>
|
||||
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Author: Reiner Sailer, Ray Valdez {sailer,rvaldez}@us.ibm.com -->
|
||||
<!-- This file defines the security labels, which can -->
|
||||
<!-- be attached to Domains and resources. Based on -->
|
||||
<!-- these labels, the access control module decides -->
|
||||
<!-- about sharing between Domains and about access -->
|
||||
<!-- of Domains to real resources. -->
|
||||
|
||||
<SecurityLabelTemplate
|
||||
xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com security_policy.xsd">
|
||||
<LabelHeader>
|
||||
<Name>ste-security_label_template</Name>
|
||||
<Date>2005-08-10</Date>
|
||||
<PolicyName>
|
||||
<Url>ste-security_policy.xml</Url>
|
||||
<Reference>abcdef123456abcdef</Reference>
|
||||
</PolicyName>
|
||||
</LabelHeader>
|
||||
|
||||
<SubjectLabels bootstrap="dom_SystemManagement">
|
||||
<!-- single ste typed domains -->
|
||||
<!-- ACM enforces that only domains with -->
|
||||
<!-- the same type can share information -->
|
||||
<!-- -->
|
||||
<!-- Bootstrap label is assigned to Dom0 -->
|
||||
<VirtualMachineLabel>
|
||||
<Name>dom_HomeBanking</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<Name>dom_Fun</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<!-- donating some cycles to seti@home -->
|
||||
<Name>dom_BoincClient</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_DonatedCycles</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<!-- Domains with multiple ste types services; such domains -->
|
||||
<!-- must keep the types inside their domain safely confined. -->
|
||||
<VirtualMachineLabel>
|
||||
<Name>dom_SystemManagement</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<!-- since dom0 needs access to every domain and -->
|
||||
<!-- resource right now ... -->
|
||||
<Type>ste_SystemManagement</Type>
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
<Type>ste_DonatedCycles</Type>
|
||||
<Type>ste_PersistentStorageA</Type>
|
||||
<Type>ste_NetworkAdapter0</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<!-- serves persistent storage to other domains -->
|
||||
<Name>dom_StorageDomain</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<!-- access right to the resource (hard drive a) -->
|
||||
<Type>ste_PersistentStorageA</Type>
|
||||
<!-- can serve following types -->
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</VirtualMachineLabel>
|
||||
|
||||
<VirtualMachineLabel>
|
||||
<!-- serves network access to other domains -->
|
||||
<Name>dom_NetworkDomain</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<!-- access right to the resource (ethernet card) -->
|
||||
<Type>ste_NetworkAdapter0</Type>
|
||||
<!-- can serve following types -->
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
<Type>ste_DonatedCycles</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</VirtualMachineLabel>
|
||||
</SubjectLabels>
|
||||
|
||||
<ObjectLabels>
|
||||
<ResourceLabel>
|
||||
<Name>res_ManagementResource</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_SystemManagement</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_HardDrive (hda)</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_PersistentStorageA</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_LogicalDiskPartition1 (hda1)</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_LogicalDiskPartition2 (hda2)</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_InternetInsecure</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_EthernetCard</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_NetworkAdapter0</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_SecurityToken</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_PersonalFinances</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
|
||||
<ResourceLabel>
|
||||
<Name>res_GraphicsAdapter</Name>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_SystemManagement</Type>
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</ResourceLabel>
|
||||
</ObjectLabels>
|
||||
</SecurityLabelTemplate>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Author: Reiner Sailer, Ray Valdez {sailer,rvaldez}@us.ibm.com -->
|
||||
<!-- This file defines the security policies, which -->
|
||||
<!-- can be enforced by the Xen Access Control Module. -->
|
||||
<!-- Currently: Chinese Wall and Simple Type Enforcement-->
|
||||
<SecurityPolicyDefinition xmlns="http://www.ibm.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.ibm.com security_policy.xsd">
|
||||
<PolicyHeader>
|
||||
<Name>ste-security_policy</Name>
|
||||
<Date>2005-08-10</Date>
|
||||
</PolicyHeader>
|
||||
<!-- -->
|
||||
<!-- example of a simple type enforcement policy definition -->
|
||||
<!-- -->
|
||||
<SimpleTypeEnforcement>
|
||||
<SimpleTypeEnforcementTypes>
|
||||
<Type>ste_SystemManagement</Type> <!-- machine/security management -->
|
||||
<Type>ste_PersonalFinances</Type> <!-- personal finances -->
|
||||
<Type>ste_InternetInsecure</Type> <!-- games, active X, etc. -->
|
||||
<Type>ste_DonatedCycles</Type> <!-- donation to BOINC/seti@home -->
|
||||
<Type>ste_PersistentStorageA</Type> <!-- domain managing the harddrive A-->
|
||||
<Type>ste_NetworkAdapter0</Type> <!-- type of the domain managing ethernet adapter 0-->
|
||||
</SimpleTypeEnforcementTypes>
|
||||
</SimpleTypeEnforcement>
|
||||
</SecurityPolicyDefinition>
|
||||
|
||||
@@ -0,0 +1,405 @@
|
||||
##
|
||||
# policy.txt <description to the Xen access control architecture>
|
||||
#
|
||||
# Author:
|
||||
# Reiner Sailer 08/15/2005 <sailer@watson.ibm.com>
|
||||
#
|
||||
#
|
||||
# This file gives an overview of the security policies currently
|
||||
# provided and also gives some reasoning about how to assign
|
||||
# labels to domains.
|
||||
##
|
||||
|
||||
Xen access control policies
|
||||
|
||||
|
||||
General explanation of supported security policies:
|
||||
=====================================================
|
||||
|
||||
We have implemented the mandatory access control architecture of our
|
||||
hypervisor security architecture (sHype) for the Xen hypervisor. It
|
||||
controls communication (in Xen: event channels, grant tables) between
|
||||
Virtual Machines (from here on called domains) and through this the
|
||||
virtual block devices, networking, and shared memory are implemented
|
||||
on top of these communication means. While we have implemented the
|
||||
described policies and access control architecture for other
|
||||
hypervisor systems, we will describe below specifically its
|
||||
implementation and use in the Xen hypervisor. The policy enforcement
|
||||
is called mandatory regarding user domains since the policy it is
|
||||
given by the security administration and enforced independently of the
|
||||
user domains by the Xen hypervisor in cooperation with the domain
|
||||
management.
|
||||
|
||||
The access control architecture consists of three parts:
|
||||
|
||||
i) The access control policy determines the "command set" of the ACM
|
||||
and the hooks with which they can be configured to constrain the
|
||||
sharing of virtual resources. The current access control architecture
|
||||
implemented for Xen supports two policies: Chinese Wall and Simple
|
||||
Type Enforcement, which we describe in turn below.
|
||||
|
||||
|
||||
ii) The actually enforced policy instantiation uses the policy
|
||||
language (i) to configure the Xen access control in a way that suits
|
||||
the specific application (home desktop environment, company desktop,
|
||||
Web server system, etc.). We have defined an exemplary policy
|
||||
instantiation for Chinese Wall (chwall policy) and Simple Type
|
||||
Enforcement (ste policy) for a desktop system. We offer these policies
|
||||
in combination since they are controlling orthogonal events.
|
||||
|
||||
|
||||
iii) The access control module (ACM) and related hooks are part of the
|
||||
core hypervisor and their controls cannot be bypassed by domains. The
|
||||
ACM and hooks are the active security components. We refer to
|
||||
publications that describe how access control is enforced in the Xen
|
||||
hypervisor using the ACM (access decision) and the hooks (decision
|
||||
enforcement) inserted into the setup of event channels and grant
|
||||
tables, and into domain operations (create, destroy, save, restore,
|
||||
migrate). These controls decide based on the active policy
|
||||
configuration (see i. and ii.) if the operation proceeds of if the
|
||||
operation is aborted (denied).
|
||||
|
||||
|
||||
In general, security policy instantiations in the Xen access control
|
||||
framework are defined by two files:
|
||||
|
||||
a) a single "policy-name"-security_policy.xml file that defines the
|
||||
types known to the ACM and policy rules based on these types
|
||||
|
||||
b) a single "policy-name"-security_label_template.xml file that
|
||||
defines labels based on known types
|
||||
|
||||
Every security policy has its own sub-directory under
|
||||
"Xen-root"/tools/security/policies in order to simplify their
|
||||
management and the security policy tools. We will describe those files
|
||||
for our example policy (Chinese Wall and Simple Type Enforcement) in
|
||||
more detail as we go along. Eventually, we will move towards a system
|
||||
installation where the policies will reside under /etc.
|
||||
|
||||
|
||||
CHINESE WALL
|
||||
============
|
||||
|
||||
The Chinese Wall policy enables the user to define "which workloads
|
||||
(domain payloads) cannot run on a single physical system at the same
|
||||
time". Why would we want to prevent workloads from running at the same
|
||||
time on the same system? This supports requirements that can (but
|
||||
don't have to) be rooted in the measure of trust into the isolation of
|
||||
different domains that share the same hardware. Since the access
|
||||
control architecture aims at high performance and non-intrusive
|
||||
implementation, it currently does not address covert (timing) channels
|
||||
and aims at medium assurance. Users can apply the Chinese Wall policy
|
||||
to guarantee an air-gap between very sensitive payloads both regarding
|
||||
covert information channels and regarding resource starvation.
|
||||
|
||||
To enable the CW control, each domain is labeled with a set of Chinese
|
||||
Wall types and CW Conflict Sets are defined which include those CW
|
||||
types that cannot run simultaneously on the same hardware. This
|
||||
interpretation of conflict sets is the only policy rule for the Chines
|
||||
Wall policy.
|
||||
|
||||
This is enforced by controlling the start of domains according to
|
||||
their assigned CW worload types. Domains with Chinese Wall types that
|
||||
appear in a common conflict set are running mutually exclusive on a
|
||||
platform, i.e., once a domain with one of the cw-types of a conflict
|
||||
set is running, no domain with another cw-type of the same conflict
|
||||
set can start until the first domain is destroyed, paused, or migrated
|
||||
away from the physical system (this assumes that such a partition can
|
||||
no longer be observed). The idea is to assign cw-types according to
|
||||
the type of payload that a domain runs and to use the Chinese Wall
|
||||
policy to ensure that payload types can be differentiated by the
|
||||
hypervisor and can be prevented from being executed on the same system
|
||||
at the same time. Using the flexible CW policy maintains system
|
||||
consolidation and workload-balancing while introducing guaranteed
|
||||
constraints where necessary.
|
||||
|
||||
|
||||
Example of a Chinese Wall Policy Instantiation
|
||||
----------------------------------------------
|
||||
|
||||
The file chwall-security_policy.xml defines the Chinese Wall types as
|
||||
well as the conflict sets for our example policy (you find it in the
|
||||
directory "xen_root"/tools/security/policies/chwall).
|
||||
|
||||
It defines four Chinese Wall types (prefixed with cw_) with the
|
||||
following meaning:
|
||||
|
||||
* cw_SystemsManagement is a type identifying workloads for systems
|
||||
management, e.g., domain management, device management, or hypervisor
|
||||
management.
|
||||
|
||||
* cw_Sensitive is identifying workloads that are critical to the user
|
||||
for one reason or another.
|
||||
|
||||
* cw_Distrusted is identifying workloads a user does not have much
|
||||
confidence in. E.g. a domain used for surfing in the internet without
|
||||
protection( i.e., active-X, java, java-script, executing web content)
|
||||
or for (Internet) Games should be typed this way.
|
||||
|
||||
* cw_Isolated is identifying workloads that are supposedly isolated by
|
||||
use of the type enforcement policy (described below). For example, if
|
||||
a user wants to donate cycles to seti@home, she can setup a separate
|
||||
domain for a Boinc (http://boinc.ssl.berkeley.edu/) client, disable
|
||||
this domain from accessing the hard drive and from communicating to
|
||||
other local domains, and type it as cw_Isolated. We will look at a
|
||||
specific example later.
|
||||
|
||||
The example policy uses the defined types to define one conflict set:
|
||||
Protection1 = {cw_Sensitive, cw_Distrusted}. This conflict set tells
|
||||
the hypervisor that once a domain typed as cw_Sensitive is running, a
|
||||
domain typed as cw_Distrusted cannot run concurrently (and the other
|
||||
way round). With this policy, a domain typed as cw_Isolated is allowed
|
||||
to run simultaneously with domains tagged as cw_Sensitive.
|
||||
|
||||
Consequently, the access control module in the Xen hypervisor
|
||||
distinguishes in this example policy 4 different workload types in
|
||||
this example policy. It is the user's responsibility to type the
|
||||
domains in a way that reflects the workloads of these domains and, in
|
||||
the case of cw_Isolated, its properties, e.g. by configuring the
|
||||
sharing capabilities of the domain accordingly by using the simple
|
||||
type enforcement policy.
|
||||
|
||||
Users can define their own or change the existing example policy
|
||||
according to their working environment and security requirements. To
|
||||
do so, replace the file chwall-security_policy.xml with the new
|
||||
policy.
|
||||
|
||||
|
||||
SIMPLE TYPE ENFORCEMENT
|
||||
=======================
|
||||
|
||||
The file ste-security_policy.xml defines the simple type enforcement
|
||||
types for our example policy (you find it in the directory
|
||||
"xen_root"/tools/security/policies/ste). The Simple Type Enforcement
|
||||
policy defines which domains can share information with which other
|
||||
domains. To this end, it controls
|
||||
|
||||
i) inter-domain communication channels (e.g., network traffic, events,
|
||||
and shared memory).
|
||||
|
||||
ii) access of domains to physical resources (e.g., hard drive, network
|
||||
cards, graphics adapter, keyboard).
|
||||
|
||||
In order to enable the hypervisor to distinguish different domains and
|
||||
the user to express access rules, the simple type enforcement defines
|
||||
a set of types (ste_types).
|
||||
|
||||
The policy defines that communication between domains is allowed if
|
||||
the domains share a common STE type. As with the chwall types, STE
|
||||
types should enable the differentiation of workloads. The simple type
|
||||
enforcement access control implementation in the hypervisor enforces
|
||||
that domains can only communicate (setup event channels, grant tables)
|
||||
if they share a common type, i.e., both domains have assigned at least
|
||||
on type in common. A domain can access a resource, if the domain and
|
||||
the resource share a common type. Hence, assigning STE types to
|
||||
domains and resources allows users to define constraints on sharing
|
||||
between domains and to keep sensitive data confined from distrusted
|
||||
domains.
|
||||
|
||||
Domain <--> Domain Sharing
|
||||
''''''''''''''''''''''''''
|
||||
(implemented but its effective use requires factorization of Dom0)
|
||||
|
||||
a) Domains with a single STE type (general user domains): Sharing
|
||||
between such domains is enforced entirely by the hypervisor access
|
||||
control. It is independent of the domains and does not require their
|
||||
co-operation.
|
||||
|
||||
b) Domains with multiple STE types: One example is a domain that
|
||||
virtualizes a physical resource (e.g., hard drive) and serves it as
|
||||
multiple virtual resources (virtual block drives) to other domains of
|
||||
different types. The idea is that only a specific device domain has
|
||||
assigned the type required to access the physical hard-drive. Logical
|
||||
drives are then assigned the types of domains that have access to this
|
||||
logical drive. Since the Xen hypervisor cannot distinguish between the
|
||||
logical drives, the access control (type enforcement) is delegated to
|
||||
the device domain, which has access to the types of domains requesting
|
||||
to mount a logical drive as well as the types assigned to the
|
||||
different available logical drives.
|
||||
|
||||
Currently in Xen, Dom0 controls all hardware, needs to communicate
|
||||
with all domains during their setup, and intercepts all communication
|
||||
between domains. Consequently, Dom0 needs to be assigned all types
|
||||
used and must be completely trusted to maintain the separation of
|
||||
informatio ncoming from domains with different STE types. Thus a
|
||||
refactoring of Dom0 is recommended for stronger confinement
|
||||
guarantees.
|
||||
|
||||
Domain --> RESOURCES Access
|
||||
'''''''''''''''''''''''''''
|
||||
(current work)
|
||||
|
||||
We define for each resource that we want to distinguish a separate STE
|
||||
type. Each STE type is assigned to the respective resource and to
|
||||
those domains that are allowed to access this resource. Type
|
||||
enforcement will guarantee that other domains cannot access this
|
||||
resource since they don't share the resource's STE type.
|
||||
|
||||
Since in the current implementation of Xen, Dom0 controls access to
|
||||
all hardware (e.g., disk drives, network), Domain-->Resource access
|
||||
control enforcement must be implemented in Dom0. This is possible
|
||||
since Dom0 has access to both the domain configuration (including the
|
||||
domain STE types) and the resource configuration (including the
|
||||
resource STE types).
|
||||
|
||||
For purposes of gaining higher assurance in the resulting system, it
|
||||
may be desirable to reduce the size of dom0 by adding one or more
|
||||
"device domains" (DDs). These DDs, e.g. providing storage or network
|
||||
access, can support one or more physical devices, and manage
|
||||
enforcement of MAC policy relevant for said devices. Security benefits
|
||||
come from the smaller size of these DDs, as they can be more easily
|
||||
audited than monolithic device driver domains. DDs can help to obtain
|
||||
maximum security benefit from sHype.
|
||||
|
||||
|
||||
Example of a Simple Type Enforcement Policy Instantiation
|
||||
---------------------------------------------------------
|
||||
|
||||
We define the following types:
|
||||
|
||||
* ste_SystemManagement identifies workloads (and domains that runs
|
||||
them) that must share information to accomplish the management of the
|
||||
system
|
||||
|
||||
* ste_PersonalFinances identifies workloads that are related to
|
||||
sensitive programs such as HomeBanking applications or safely
|
||||
configured web browsers for InternetBanking
|
||||
|
||||
* ste_InternetInsecure identifies workloads that are very
|
||||
function-rich and unrestricted to offer for example an environment
|
||||
where internet games can run efficiently
|
||||
|
||||
* ste_DonatedCycles identifies workloads that run on behalf of others,
|
||||
e.g. a Boinc client
|
||||
|
||||
* ste_PersistentStorage identifies workloads that have direct access
|
||||
to persistent storage (e.g., hard drive)
|
||||
|
||||
* ste_NetworkAccess identifies workload that have direct access to
|
||||
network cards and related networks
|
||||
|
||||
|
||||
|
||||
SECURITY LABEL TEMPLATES
|
||||
========================
|
||||
|
||||
We introduce security label templates because it is difficult for
|
||||
users to ensure tagging of domains consistently and since there are
|
||||
--as we have seen in the case of isolation-- useful dependencies
|
||||
between the policies. Security Label Templates define type sets that
|
||||
can be addressed by more user-friendly label names,
|
||||
e.g. dom_Homebanking describes a typical typeset tagged to domains
|
||||
used for sensitive Homebanking work-loads. Labels are defined in the
|
||||
file
|
||||
|
||||
Using Security Label Templates has multiple advantages:
|
||||
a) easy reference of typical sets of type assignments
|
||||
b) consistent interpretation of type combinations
|
||||
c) meaningful application-level label names
|
||||
|
||||
The definition of label templates depends on the combination of
|
||||
policies that are used. We will describe some of the labels defined
|
||||
for the Chinese Wall and Simple Type Enforcement combination.
|
||||
|
||||
In the BoincClient example, the label_template file specifies that
|
||||
this Label is assigned the Chinese Wall type cw_Isolated. We do this
|
||||
assuming that this BoincClient is isolated against the rest of the
|
||||
system infrastructure (no persistent memory, no sharing with local
|
||||
domains). Since cw_Isolated is not included in any conflict set, it
|
||||
can run at any time concurrently with any other domain. The
|
||||
ste_DonatedCycles type assigned to the BoincClient reflect the
|
||||
isolation assumption: it is only assigned to the dom_NetworkDomain
|
||||
giving the BoincClient domain access to the network to communicate
|
||||
with its BoincServer.
|
||||
|
||||
The strategy for combining types into Labels is the following: First
|
||||
we define a label for each type of general user domain
|
||||
(workload-oriented). Then we define a new label for each physical
|
||||
resource that shall be shared using a DD domain (e.g., disk) and for
|
||||
each logical resource offered through this physical resource (logical
|
||||
disk partition). We define then device domain labels (here:
|
||||
dom_SystemManagement, dom_StorageDomain, dom_NetworkDomain) which
|
||||
include the types of the physical resources (e.g. hda) their domains
|
||||
need to connect to. Such physical resources can only be accessed
|
||||
directly by device domains types with the respective device's STE
|
||||
type. Additionally we assign to such a device domain Label the STE
|
||||
types of those user domains that are allowed to access one of the
|
||||
logical resources (e.g., hda1, hda2) built on top of this physical
|
||||
resource through the device domain.
|
||||
|
||||
|
||||
Label Construction Example:
|
||||
---------------------------
|
||||
|
||||
We define here a storage domain label for a domain that owns a real
|
||||
disk drive and creates the logical disk partitions hda1 and hda2 which
|
||||
it serves to domains labeled dom_HomeBanking and dom_Fun
|
||||
respectively. The labels we refer to are defined in the label template
|
||||
file policies/chwall_ste/chwall_ste-security-label-template.xml.
|
||||
|
||||
step1: To distinguish different shared disk drives, we create a
|
||||
separate Label and STE type for each of them. Here: we create a type
|
||||
ste_PersistentStorageA for disk drive hda. If you have another disk
|
||||
drive, you may define another persistent storage type
|
||||
ste_PersistentStorageB in the chwall_ste-security_policy.xml.
|
||||
|
||||
step2: To distinguish different domains, we create multiple domain
|
||||
labels including different types. Here: label dom_HomeBanking includes
|
||||
STE type ste_PersonalFinances, label dom_Fun includes STE type
|
||||
ste_InternetInsecure.
|
||||
|
||||
step3: The storage domain in charge of the hard drive A needs access
|
||||
to this hard drive. Therefore the storage domain label
|
||||
dom_StorageDomain must include the type assigned to the hard drive
|
||||
(ste_PersistentStorageA).
|
||||
|
||||
step4: In order to serve dom hda1 to domains labeled dom_HomeBanking
|
||||
and hda2 to domains labeled dom_Fun, the storage domain label must
|
||||
include the types of those domains as well (ste_PersonalFinance,
|
||||
ste_InternetInsecure).
|
||||
|
||||
step5: In order to keep the data for different types safely apart, the
|
||||
different logical disk partitions must be assigned unique labels and
|
||||
types, which are used inside the storage domain to extend the ACM
|
||||
access enforcement to logical resources served from inside the storage
|
||||
domain. We define labels "res_LogicalDiskPartition1 (hda1)" and assign
|
||||
it to hda1 and "res_LogicalDiskPartition2 (hda2)" and assign it to
|
||||
hda2. These labels must include the STE types of those domains that
|
||||
are allowed to use them (e.g., ste_PersonalFinances for hda1).
|
||||
|
||||
The overall mandatory access control is then enforced in 3 different
|
||||
Xen components and these components use a single consistent policy to
|
||||
co-operatively enforce the policy. In the storage domain example, we
|
||||
have three components that co-operate:
|
||||
|
||||
1. The ACM module inside the hypervisor enforces: communication between
|
||||
user domains and the storage domain (only domains including types
|
||||
ste_PersonalFinances or ste_InternetInsecure can communicate with the
|
||||
storage domain and request access to logical resource). This confines
|
||||
the sharing to the types assigned to the storage domain.
|
||||
|
||||
2. The domain management will enforce (work in progress): assignment of
|
||||
real resources (hda) to domains (storage domain) that share a
|
||||
type with the resource.
|
||||
|
||||
3. If the storage domain serves multiple STE types (as in our example),
|
||||
it enforces (work in progress): that domains can access (mount)
|
||||
logical resources only if they share an STE type with the respective
|
||||
resource. In our example, domains with the STE type
|
||||
ste_PersonalFinances can request access (mount) to logical resource
|
||||
hda1 from the storage domain.
|
||||
|
||||
If you look at the virtual machine label dom_StorageDomain, you will
|
||||
see the minimal set of types assigned to our domain manageing disk
|
||||
drive hda for serving logical disk partitions exclusively to
|
||||
dom_HomeBanking and dom_Fun.
|
||||
|
||||
Similary, network domains can confine access to the network or
|
||||
network communication between user domains.
|
||||
|
||||
As a result, device domains (e.g., storage domain, network domain)
|
||||
must be simple and small to ensure their correct co-operation in the
|
||||
type enforcement model. If such trust is not possible, then hardware
|
||||
should be assigned exclusively to a single type (or to a single
|
||||
partition) in which case the hypervisor ACM enforcement enforces the
|
||||
types independently.
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
##
|
||||
# readme.txt <description to the xen access control architecture>
|
||||
#
|
||||
# Author:
|
||||
# Reiner Sailer 08/15/2005 <sailer@watson.ibm.com>
|
||||
#
|
||||
#
|
||||
# This file is a toc for information regarding
|
||||
# the access control policy and tools in Xen.
|
||||
##
|
||||
|
||||
1. policy.txt:
|
||||
|
||||
describes the general reasoning and examples for access
|
||||
control policies in Xen
|
||||
|
||||
|
||||
2. install.txt
|
||||
|
||||
describes the activation of the access control framework
|
||||
in Xen
|
||||
|
||||
3. example.txt
|
||||
|
||||
describes the available tools for managing security policies
|
||||
in Xen and the tools to label domains
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/* secpol_compat.h
|
||||
* 'translates' data types necessary to
|
||||
* include <xen/acm.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
@@ -31,18 +31,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
#include "secpol_compat.h"
|
||||
#include <xen/acm.h>
|
||||
#include <xen/acm_ops.h>
|
||||
#include <xen/linux/privcmd.h>
|
||||
@@ -270,171 +260,6 @@ void acm_dump_policy_buffer(void *buf, int buflen)
|
||||
}
|
||||
}
|
||||
|
||||
/*************************** set policy ****************************/
|
||||
|
||||
int acm_domain_set_chwallpolicy(void *bufstart, int buflen)
|
||||
{
|
||||
#define CWALL_MAX_SSIDREFS 6
|
||||
#define CWALL_MAX_TYPES 10
|
||||
#define CWALL_MAX_CONFLICTSETS 2
|
||||
|
||||
struct acm_chwall_policy_buffer *chwall_bin_pol =
|
||||
(struct acm_chwall_policy_buffer *) bufstart;
|
||||
domaintype_t *ssidrefs, *conflicts;
|
||||
int ret = 0;
|
||||
int j;
|
||||
|
||||
chwall_bin_pol->chwall_max_types = htonl(CWALL_MAX_TYPES);
|
||||
chwall_bin_pol->chwall_max_ssidrefs = htonl(CWALL_MAX_SSIDREFS);
|
||||
chwall_bin_pol->policy_code = htonl(ACM_CHINESE_WALL_POLICY);
|
||||
chwall_bin_pol->policy_version = htonl(ACM_CHWALL_VERSION);
|
||||
chwall_bin_pol->chwall_ssid_offset =
|
||||
htonl(sizeof(struct acm_chwall_policy_buffer));
|
||||
chwall_bin_pol->chwall_max_conflictsets =
|
||||
htonl(CWALL_MAX_CONFLICTSETS);
|
||||
chwall_bin_pol->chwall_conflict_sets_offset =
|
||||
htonl(ntohl(chwall_bin_pol->chwall_ssid_offset) +
|
||||
sizeof(domaintype_t) * CWALL_MAX_SSIDREFS * CWALL_MAX_TYPES);
|
||||
chwall_bin_pol->chwall_running_types_offset = 0; /* not set */
|
||||
chwall_bin_pol->chwall_conflict_aggregate_offset = 0; /* not set */
|
||||
ret += sizeof(struct acm_chwall_policy_buffer);
|
||||
/* now push example ssids into the buffer (max_ssidrefs x max_types entries) */
|
||||
/* check buffer size */
|
||||
if ((buflen - ret) <
|
||||
(CWALL_MAX_TYPES * CWALL_MAX_SSIDREFS * sizeof(domaintype_t)))
|
||||
return -1; /* not enough space */
|
||||
|
||||
ssidrefs = (domaintype_t *) (bufstart +
|
||||
ntohl(chwall_bin_pol->chwall_ssid_offset));
|
||||
memset(ssidrefs, 0,
|
||||
CWALL_MAX_TYPES * CWALL_MAX_SSIDREFS * sizeof(domaintype_t));
|
||||
|
||||
/* now set type j-1 for ssidref i+1 */
|
||||
for (j = 0; j <= CWALL_MAX_SSIDREFS; j++)
|
||||
if ((0 < j) && (j <= CWALL_MAX_TYPES))
|
||||
ssidrefs[j * CWALL_MAX_TYPES + j - 1] = htons(1);
|
||||
|
||||
ret += CWALL_MAX_TYPES * CWALL_MAX_SSIDREFS * sizeof(domaintype_t);
|
||||
if ((buflen - ret) <
|
||||
(CWALL_MAX_CONFLICTSETS * CWALL_MAX_TYPES * sizeof(domaintype_t)))
|
||||
return -1; /* not enough space */
|
||||
|
||||
/* now the chinese wall policy conflict sets */
|
||||
conflicts = (domaintype_t *) (bufstart +
|
||||
ntohl(chwall_bin_pol->
|
||||
chwall_conflict_sets_offset));
|
||||
memset((void *) conflicts, 0,
|
||||
CWALL_MAX_CONFLICTSETS * CWALL_MAX_TYPES *
|
||||
sizeof(domaintype_t));
|
||||
/* just 1 conflict set [0]={2,3}, [1]={1,5,6} */
|
||||
if (CWALL_MAX_TYPES > 3)
|
||||
{
|
||||
conflicts[2] = htons(1);
|
||||
conflicts[3] = htons(1); /* {2,3} */
|
||||
conflicts[CWALL_MAX_TYPES + 1] = htons(1);
|
||||
conflicts[CWALL_MAX_TYPES + 5] = htons(1);
|
||||
conflicts[CWALL_MAX_TYPES + 6] = htons(1); /* {0,5,6} */
|
||||
}
|
||||
ret += sizeof(domaintype_t) * CWALL_MAX_CONFLICTSETS * CWALL_MAX_TYPES;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int acm_domain_set_stepolicy(void *bufstart, int buflen)
|
||||
{
|
||||
#define STE_MAX_SSIDREFS 6
|
||||
#define STE_MAX_TYPES 5
|
||||
|
||||
struct acm_ste_policy_buffer *ste_bin_pol =
|
||||
(struct acm_ste_policy_buffer *) bufstart;
|
||||
domaintype_t *ssidrefs;
|
||||
int j, ret = 0;
|
||||
|
||||
ste_bin_pol->ste_max_types = htonl(STE_MAX_TYPES);
|
||||
ste_bin_pol->ste_max_ssidrefs = htonl(STE_MAX_SSIDREFS);
|
||||
ste_bin_pol->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
|
||||
ste_bin_pol->policy_version = htonl(ACM_STE_VERSION);
|
||||
ste_bin_pol->ste_ssid_offset =
|
||||
htonl(sizeof(struct acm_ste_policy_buffer));
|
||||
ret += sizeof(struct acm_ste_policy_buffer);
|
||||
/* check buffer size */
|
||||
if ((buflen - ret) <
|
||||
(STE_MAX_TYPES * STE_MAX_SSIDREFS * sizeof(domaintype_t)))
|
||||
return -1; /* not enough space */
|
||||
|
||||
ssidrefs =
|
||||
(domaintype_t *) (bufstart + ntohl(ste_bin_pol->ste_ssid_offset));
|
||||
memset(ssidrefs, 0,
|
||||
STE_MAX_TYPES * STE_MAX_SSIDREFS * sizeof(domaintype_t));
|
||||
/* all types 1 for ssidref 1 */
|
||||
for (j = 0; j < STE_MAX_TYPES; j++)
|
||||
ssidrefs[1 * STE_MAX_TYPES + j] = htons(1);
|
||||
/* now set type j-1 for ssidref j */
|
||||
for (j = 0; j < STE_MAX_SSIDREFS; j++)
|
||||
if ((0 < j) && (j <= STE_MAX_TYPES))
|
||||
ssidrefs[j * STE_MAX_TYPES + j - 1] = htons(1);
|
||||
ret += STE_MAX_TYPES * STE_MAX_SSIDREFS * sizeof(domaintype_t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MAX_PUSH_BUFFER 16384
|
||||
u8 push_buffer[MAX_PUSH_BUFFER];
|
||||
|
||||
int acm_domain_setpolicy(int xc_handle)
|
||||
{
|
||||
int ret;
|
||||
struct acm_policy_buffer *bin_pol;
|
||||
acm_op_t op;
|
||||
|
||||
/* future: read policy from file and set it */
|
||||
bin_pol = (struct acm_policy_buffer *) push_buffer;
|
||||
bin_pol->policy_version = htonl(ACM_POLICY_VERSION);
|
||||
bin_pol->magic = htonl(ACM_MAGIC);
|
||||
bin_pol->primary_policy_code = htonl(ACM_CHINESE_WALL_POLICY);
|
||||
bin_pol->secondary_policy_code =
|
||||
htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
|
||||
|
||||
bin_pol->len = htonl(sizeof(struct acm_policy_buffer));
|
||||
bin_pol->primary_buffer_offset = htonl(ntohl(bin_pol->len));
|
||||
ret =
|
||||
acm_domain_set_chwallpolicy(push_buffer +
|
||||
ntohl(bin_pol->primary_buffer_offset),
|
||||
MAX_PUSH_BUFFER -
|
||||
ntohl(bin_pol->primary_buffer_offset));
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("ERROR creating chwallpolicy buffer.\n");
|
||||
return -1;
|
||||
}
|
||||
bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
|
||||
bin_pol->secondary_buffer_offset = htonl(ntohl(bin_pol->len));
|
||||
ret = acm_domain_set_stepolicy(push_buffer +
|
||||
ntohl(bin_pol->secondary_buffer_offset),
|
||||
MAX_PUSH_BUFFER -
|
||||
ntohl(bin_pol->secondary_buffer_offset));
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("ERROR creating chwallpolicy buffer.\n");
|
||||
return -1;
|
||||
}
|
||||
bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
|
||||
|
||||
/* dump it and then push it down into xen/acm */
|
||||
acm_dump_policy_buffer(push_buffer, ntohl(bin_pol->len));
|
||||
|
||||
op.cmd = ACM_SETPOLICY;
|
||||
op.interface_version = ACM_INTERFACE_VERSION;
|
||||
op.u.setpolicy.pushcache = (void *) push_buffer;
|
||||
op.u.setpolicy.pushcache_size = ntohl(bin_pol->len);
|
||||
ret = do_acm_op(xc_handle, &op);
|
||||
|
||||
if (ret)
|
||||
printf("ERROR setting policy. Use 'xm dmesg' to see details.\n");
|
||||
else
|
||||
printf("Successfully changed policy.\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************* get policy ******************************/
|
||||
|
||||
#define PULL_CACHE_SIZE 8192
|
||||
@@ -602,7 +427,6 @@ int acm_domain_dumpstats(int xc_handle)
|
||||
void usage(char *progname)
|
||||
{
|
||||
printf("Use: %s \n"
|
||||
"\t setpolicy\n"
|
||||
"\t getpolicy\n"
|
||||
"\t dumpstats\n"
|
||||
"\t loadpolicy <binary policy file>\n", progname);
|
||||
@@ -623,12 +447,7 @@ int main(int argc, char **argv)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "setpolicy"))
|
||||
{
|
||||
if (argc != 2)
|
||||
usage(argv[0]);
|
||||
ret = acm_domain_setpolicy(acm_cmd_fd);
|
||||
} else if (!strcmp(argv[1], "getpolicy")) {
|
||||
if (!strcmp(argv[1], "getpolicy")) {
|
||||
if (argc != 2)
|
||||
usage(argv[0]);
|
||||
ret = acm_domain_getpolicy(acm_cmd_fd);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,139 @@
|
||||
/****************************************************************
|
||||
* secpol_xml2bin.h
|
||||
*
|
||||
* Copyright (C) 2005 IBM Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Reiner Sailer <sailer@watson.ibm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2 of the
|
||||
* License.
|
||||
*
|
||||
*/
|
||||
#define POLICY_SUBDIR "policies/"
|
||||
#define POLICY_EXTENSION "-security_policy.xml"
|
||||
#define LABEL_EXTENSION "-security_label_template.xml"
|
||||
#define BINARY_EXTENSION ".bin"
|
||||
#define MAPPING_EXTENSION ".map"
|
||||
#define PRIMARY_COMPONENT_ATTR_NAME "order"
|
||||
#define BOOTSTRAP_LABEL_ATTR_NAME "bootstrap"
|
||||
#define PRIMARY_COMPONENT "PrimaryPolicyComponent"
|
||||
#define SCHEMA_FILENAME "policies/security_policy.xsd"
|
||||
|
||||
/* basic states (used as 1 << X) */
|
||||
#define XML2BIN_SECPOL 0 /* policy tokens */
|
||||
#define XML2BIN_STE 1
|
||||
#define XML2BIN_CHWALL 2
|
||||
#define XML2BIN_CONFLICTSETS 3
|
||||
#define XML2BIN_CSTYPE 4
|
||||
|
||||
#define XML2BIN_SECTEMPLATE 5 /* label tokens */
|
||||
#define XML2BIN_POLICYHEADER 6
|
||||
#define XML2BIN_LABELHEADER 7
|
||||
#define XML2BIN_SUBJECTS 8
|
||||
#define XML2BIN_OBJECTS 9
|
||||
#define XML2BIN_VM 10
|
||||
#define XML2BIN_RES 11
|
||||
|
||||
#define XML2BIN_STETYPES 12 /* shared tokens */
|
||||
#define XML2BIN_CHWALLTYPES 13
|
||||
#define XML2BIN_TYPE 14
|
||||
#define XML2BIN_NAME 15
|
||||
#define XML2BIN_TEXT 16
|
||||
#define XML2BIN_COMMENT 17
|
||||
|
||||
/* type "data type" (currently 16bit) */
|
||||
typedef u_int16_t type_t;
|
||||
|
||||
/* list of known elements and token equivalent *
|
||||
* state constants and token positions must be *
|
||||
* in sync for correct state recognition */
|
||||
|
||||
char *token[20] = /* parser triggers */
|
||||
{
|
||||
[0] = "SecurityPolicyDefinition", /* policy xml */
|
||||
[1] = "SimpleTypeEnforcement",
|
||||
[2] = "ChineseWall",
|
||||
[3] = "ConflictSets",
|
||||
[4] = "Conflict", /* label-template xml */
|
||||
[5] = "SecurityLabelTemplate",
|
||||
[6] = "PolicyHeader",
|
||||
[7] = "LabelHeader",
|
||||
[8] = "SubjectLabels",
|
||||
[9] = "ObjectLabels",
|
||||
[10] = "VirtualMachineLabel",
|
||||
[11] = "ResourceLabel",
|
||||
[12] = "SimpleTypeEnforcementTypes", /* common tags */
|
||||
[13] = "ChineseWallTypes",
|
||||
[14] = "Type",
|
||||
[15] = "Name",
|
||||
[16] = "text",
|
||||
[17] = "comment",
|
||||
[18] = NULL,
|
||||
};
|
||||
|
||||
/* important combined states */
|
||||
#define XML2BIN_NULL 0
|
||||
|
||||
/* policy xml parsing states _S */
|
||||
|
||||
/* e.g., here we are in a <secpol,ste,stetypes> environment, *
|
||||
* so when finding a type element, we know where to put it */
|
||||
#define XML2BIN_stetype_S ((1 << XML2BIN_SECPOL) | \
|
||||
(1 << XML2BIN_STE) | \
|
||||
(1 << XML2BIN_STETYPES))
|
||||
|
||||
#define XML2BIN_chwalltype_S ((1 << XML2BIN_SECPOL) | \
|
||||
(1 << XML2BIN_CHWALL) | \
|
||||
(1 << XML2BIN_CHWALLTYPES))
|
||||
|
||||
#define XML2BIN_conflictset_S ((1 << XML2BIN_SECPOL) | \
|
||||
(1 << XML2BIN_CHWALL) | \
|
||||
(1 << XML2BIN_CONFLICTSETS))
|
||||
|
||||
#define XML2BIN_conflictsettype_S ((1 << XML2BIN_SECPOL) | \
|
||||
(1 << XML2BIN_CHWALL) | \
|
||||
(1 << XML2BIN_CONFLICTSETS) | \
|
||||
(1 << XML2BIN_CSTYPE))
|
||||
|
||||
|
||||
/* label xml states */
|
||||
#define XML2BIN_VM_S ((1 << XML2BIN_SECTEMPLATE) | \
|
||||
(1 << XML2BIN_SUBJECTS) | \
|
||||
(1 << XML2BIN_VM))
|
||||
|
||||
#define XML2BIN_RES_S ((1 << XML2BIN_SECTEMPLATE) | \
|
||||
(1 << XML2BIN_OBJECTS) | \
|
||||
(1 << XML2BIN_RES))
|
||||
|
||||
#define XML2BIN_VM_STE_S ((1 << XML2BIN_SECTEMPLATE) | \
|
||||
(1 << XML2BIN_SUBJECTS) | \
|
||||
(1 << XML2BIN_VM) | \
|
||||
(1 << XML2BIN_STETYPES))
|
||||
|
||||
#define XML2BIN_VM_CHWALL_S ((1 << XML2BIN_SECTEMPLATE) | \
|
||||
(1 << XML2BIN_SUBJECTS) | \
|
||||
(1 << XML2BIN_VM) | \
|
||||
(1 << XML2BIN_CHWALLTYPES))
|
||||
|
||||
#define XML2BIN_RES_STE_S ((1 << XML2BIN_SECTEMPLATE) | \
|
||||
(1 << XML2BIN_OBJECTS) | \
|
||||
(1 << XML2BIN_RES) | \
|
||||
(1 << XML2BIN_STETYPES))
|
||||
|
||||
|
||||
|
||||
/* check versions of headers against which the
|
||||
* xml2bin translation tool was written
|
||||
*/
|
||||
|
||||
/* protects from unnoticed changes in struct acm_policy_buffer */
|
||||
#define WRITTEN_AGAINST_ACM_POLICY_VERSION 1
|
||||
|
||||
/* protects from unnoticed changes in struct acm_chwall_policy_buffer */
|
||||
#define WRITTEN_AGAINST_ACM_CHWALL_VERSION 1
|
||||
|
||||
/* protects from unnoticed changes in struct acm_ste_policy_buffer */
|
||||
#define WRITTEN_AGAINST_ACM_STE_VERSION 1
|
||||
@@ -0,0 +1,345 @@
|
||||
#!/bin/sh
|
||||
# *
|
||||
# * setlabel
|
||||
# *
|
||||
# * Copyright (C) 2005 IBM Corporation
|
||||
# *
|
||||
# * Authors:
|
||||
# * Stefan Berger <stefanb@us.ibm.com>
|
||||
# *
|
||||
# * This program is free software; you can redistribute it and/or
|
||||
# * modify it under the terms of the GNU General Public License as
|
||||
# * published by the Free Software Foundation, version 2 of the
|
||||
# * License.
|
||||
# *
|
||||
# * 'setlabel' labels virtual machine (domain) configuration files with
|
||||
# * security identifiers that can be enforced in Xen.
|
||||
# *
|
||||
# * 'setlabel -?' shows the usage of the program
|
||||
# *
|
||||
# * 'setlabel -l vmconfig-file' lists all available labels (only VM
|
||||
# * labels are used right now)
|
||||
# *
|
||||
# * 'setlabel vmconfig-file security-label map-file' inserts the 'ssidref'
|
||||
# * that corresponds to the security-label under the
|
||||
# * current policy (if policy changes, 'label'
|
||||
# * must be re-run over the configuration files;
|
||||
# * map-file is created during policy translation and
|
||||
# * is found in the policy's directory
|
||||
#
|
||||
|
||||
if [ -z "$runbash" ]; then
|
||||
runbash="1"
|
||||
export runbash
|
||||
exec sh -c "bash $0 $*"
|
||||
fi
|
||||
|
||||
|
||||
usage ()
|
||||
{
|
||||
echo "Usage: $0 [Option] <vmfile> <label> <policy name> "
|
||||
echo " or $0 -l <policy name>"
|
||||
echo ""
|
||||
echo "Valid Options are:"
|
||||
echo "-r : to relabel a file without being prompted"
|
||||
echo ""
|
||||
echo "vmfile : XEN vm configuration file"
|
||||
echo "label : the label to map"
|
||||
echo "policy name : the name of the policy, i.e. 'chwall'"
|
||||
echo ""
|
||||
echo "-l <policy name> is used to show valid labels in the map file"
|
||||
echo ""
|
||||
}
|
||||
|
||||
|
||||
findMapFile ()
|
||||
{
|
||||
mapfile="./$1.map"
|
||||
if [ -r "$mapfile" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
mapfile="./policies/$1/$1.map"
|
||||
if [ -r "$mapfile" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
showLabels ()
|
||||
{
|
||||
mapfile=$1
|
||||
if [ ! -r "$mapfile" -o "$mapfile" == "" ]; then
|
||||
echo "Cannot read from vm configuration file $vmfile."
|
||||
return -1
|
||||
fi
|
||||
|
||||
getPrimaryPolicy $mapfile
|
||||
getSecondaryPolicy $mapfile
|
||||
|
||||
echo "The following labels are available:"
|
||||
let line=1
|
||||
while [ 1 ]; do
|
||||
ITEM=`cat $mapfile | \
|
||||
awk -vline=$line \
|
||||
-vprimary=$primary \
|
||||
'{ \
|
||||
if ($1 == "LABEL->SSID" && \
|
||||
$2 == "VM" && \
|
||||
$3 == primary ) { \
|
||||
ctr++; \
|
||||
if (ctr == line) { \
|
||||
print $4; \
|
||||
} \
|
||||
} \
|
||||
} END { \
|
||||
}'`
|
||||
|
||||
if [ "$ITEM" == "" ]; then
|
||||
break
|
||||
fi
|
||||
if [ "$secondary" != "NULL" ]; then
|
||||
LABEL=`cat $mapfile | \
|
||||
awk -vitem=$ITEM \
|
||||
'{
|
||||
if ($1 == "LABEL->SSID" && \
|
||||
$2 == "VM" && \
|
||||
$3 == "CHWALL" && \
|
||||
$4 == item ) { \
|
||||
result = item; \
|
||||
} \
|
||||
} END { \
|
||||
print result \
|
||||
}'`
|
||||
else
|
||||
LABEL=$ITEM
|
||||
fi
|
||||
|
||||
if [ "$LABEL" != "" ]; then
|
||||
echo "$LABEL"
|
||||
found=1
|
||||
fi
|
||||
let line=line+1
|
||||
done
|
||||
if [ "$found" != "1" ]; then
|
||||
echo "No labels found."
|
||||
fi
|
||||
}
|
||||
|
||||
getPrimaryPolicy ()
|
||||
{
|
||||
mapfile=$1
|
||||
primary=`cat $mapfile | \
|
||||
awk ' \
|
||||
{ \
|
||||
if ( $1 == "PRIMARY" ) { \
|
||||
res=$2; \
|
||||
} \
|
||||
} END { \
|
||||
print res; \
|
||||
} '`
|
||||
}
|
||||
|
||||
getSecondaryPolicy ()
|
||||
{
|
||||
mapfile=$1
|
||||
secondary=`cat $mapfile | \
|
||||
awk ' \
|
||||
{ \
|
||||
if ( $1 == "SECONDARY" ) { \
|
||||
res=$2; \
|
||||
} \
|
||||
} END { \
|
||||
print res; \
|
||||
} '`
|
||||
}
|
||||
|
||||
|
||||
getDefaultSsid ()
|
||||
{
|
||||
mapfile=$1
|
||||
pol=$2
|
||||
RES=`cat $mapfile \
|
||||
awk -vpol=$pol \
|
||||
{ \
|
||||
if ($1 == "LABEL->SSID" && \
|
||||
$2 == "ANY" && \
|
||||
$3 == pol && \
|
||||
$4 == "DEFAULT" ) {\
|
||||
res=$5; \
|
||||
} \
|
||||
} END { \
|
||||
printf "%04x", strtonum(res) \
|
||||
}'`
|
||||
echo "default NULL mapping is $RES"
|
||||
defaultssid=$RES
|
||||
}
|
||||
|
||||
relabel ()
|
||||
{
|
||||
vmfile=$1
|
||||
label=$2
|
||||
mapfile=$3
|
||||
mode=$4
|
||||
|
||||
if [ ! -r "$vmfile" ]; then
|
||||
echo "Cannot read from vm configuration file $vmfile."
|
||||
return -1
|
||||
fi
|
||||
|
||||
if [ ! -w "$vmfile" ]; then
|
||||
echo "Cannot write to vm configuration file $vmfile."
|
||||
return -1
|
||||
fi
|
||||
|
||||
if [ ! -r "$mapfile" ] ; then
|
||||
echo "Cannot read mapping file $mapfile."
|
||||
return -1
|
||||
fi
|
||||
|
||||
# Determine which policy is primary, which sec.
|
||||
getPrimaryPolicy $mapfile
|
||||
getSecondaryPolicy $mapfile
|
||||
|
||||
# Calculate the primary policy's SSIDREF
|
||||
if [ "$primary" == "NULL" ]; then
|
||||
SSIDLO="0000"
|
||||
else
|
||||
SSIDLO=`cat $mapfile | \
|
||||
awk -vlabel=$label \
|
||||
-vprimary=$primary \
|
||||
'{ \
|
||||
if ( $1 == "LABEL->SSID" && \
|
||||
$2 == "VM" && \
|
||||
$3 == primary && \
|
||||
$4 == label ) { \
|
||||
result=$5 \
|
||||
} \
|
||||
} END { \
|
||||
if (result != "" ) \
|
||||
{printf "%04x", strtonum(result)}\
|
||||
}'`
|
||||
fi
|
||||
|
||||
# Calculate the secondary policy's SSIDREF
|
||||
if [ "$secondary" == "NULL" ]; then
|
||||
SSIDHI="0000"
|
||||
else
|
||||
SSIDHI=`cat $mapfile | \
|
||||
awk -vlabel=$label \
|
||||
-vsecondary=$secondary \
|
||||
'{ \
|
||||
if ( $1 == "LABEL->SSID" && \
|
||||
$2 == "VM" && \
|
||||
$3 == secondary && \
|
||||
$4 == label ) { \
|
||||
result=$5 \
|
||||
} \
|
||||
} END { \
|
||||
if (result != "" ) \
|
||||
{printf "%04x", strtonum(result)}\
|
||||
}'`
|
||||
fi
|
||||
|
||||
if [ "$SSIDLO" == "" -o \
|
||||
"$SSIDHI" == "" ]; then
|
||||
echo "Could not map the given label '$label'."
|
||||
return -1
|
||||
fi
|
||||
|
||||
ACM_POLICY=`cat $mapfile | \
|
||||
awk ' { if ( $1 == "POLICY" ) { \
|
||||
result=$2 \
|
||||
} \
|
||||
} \
|
||||
END { \
|
||||
if (result != "") { \
|
||||
printf result \
|
||||
} \
|
||||
}'`
|
||||
|
||||
if [ "$ACM_POLICY" == "" ]; then
|
||||
echo "Could not find 'POLICY' entry in map file."
|
||||
return -1
|
||||
fi
|
||||
|
||||
SSIDREF="0x$SSIDHI$SSIDLO"
|
||||
|
||||
if [ "$mode" != "relabel" ]; then
|
||||
RES=`cat $vmfile | \
|
||||
awk '{ \
|
||||
if ( substr($1,0,7) == "ssidref" ) {\
|
||||
print $0; \
|
||||
} \
|
||||
}'`
|
||||
if [ "$RES" != "" ]; then
|
||||
echo "Do you want to overwrite the existing mapping ($RES)? (y/N)"
|
||||
read user
|
||||
if [ "$user" != "y" -a "$user" != "Y" ]; then
|
||||
echo "Aborted."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
#Write the output
|
||||
vmtmp1="/tmp/__setlabel.tmp1"
|
||||
vmtmp2="/tmp/__setlabel.tmp2"
|
||||
touch $vmtmp1
|
||||
touch $vmtmp2
|
||||
if [ ! -w "$vmtmp1" -o ! -w "$vmtmp2" ]; then
|
||||
echo "Cannot create temporary files. Aborting."
|
||||
return -1
|
||||
fi
|
||||
RES=`sed -e '/^#ACM_POLICY/d' $vmfile > $vmtmp1`
|
||||
RES=`sed -e '/^#ACM_LABEL/d' $vmtmp1 > $vmtmp2`
|
||||
RES=`sed -e '/^ssidref/d' $vmtmp2 > $vmtmp1`
|
||||
echo "#ACM_POLICY=$ACM_POLICY" >> $vmtmp1
|
||||
echo "#ACM_LABEL=$label" >> $vmtmp1
|
||||
echo "ssidref = $SSIDREF" >> $vmtmp1
|
||||
mv -f $vmtmp1 $vmfile
|
||||
rm -rf $vmtmp1 $vmtmp2
|
||||
echo "Mapped label '$label' to ssidref '$SSIDREF'."
|
||||
}
|
||||
|
||||
|
||||
|
||||
if [ "$1" == "-r" ]; then
|
||||
mode="relabel"
|
||||
shift
|
||||
elif [ "$1" == "-l" ]; then
|
||||
mode="show"
|
||||
shift
|
||||
elif [ "$1" == "-?" ]; then
|
||||
mode="usage"
|
||||
fi
|
||||
|
||||
if [ "$mode" == "show" ]; then
|
||||
if [ "$1" == "" ]; then
|
||||
usage
|
||||
exit -1;
|
||||
fi
|
||||
findMapFile $1
|
||||
res=$?
|
||||
if [ "$res" != "0" ]; then
|
||||
showLabels $mapfile
|
||||
else
|
||||
echo "Could not find map file for policy '$1'."
|
||||
fi
|
||||
elif [ "$mode" == "usage" ]; then
|
||||
usage
|
||||
else
|
||||
if [ "$3" == "" ]; then
|
||||
usage
|
||||
exit -1;
|
||||
fi
|
||||
findMapFile $3
|
||||
res=$?
|
||||
if [ "$res" != "0" ]; then
|
||||
relabel $1 $2 $mapfile $mode
|
||||
else
|
||||
echo "Could not find map file for policy '$3'."
|
||||
fi
|
||||
|
||||
fi
|
||||
@@ -0,0 +1,171 @@
|
||||
#!/bin/sh
|
||||
# *
|
||||
# * updategrub
|
||||
# *
|
||||
# * Copyright (C) 2005 IBM Corporation
|
||||
# *
|
||||
# * Authors:
|
||||
# * Stefan Berger <stefanb@us.ibm.com>
|
||||
# *
|
||||
# * This program is free software; you can redistribute it and/or
|
||||
# * modify it under the terms of the GNU General Public License as
|
||||
# * published by the Free Software Foundation, version 2 of the
|
||||
# * License.
|
||||
# *
|
||||
# *
|
||||
#
|
||||
|
||||
if [ -z "$runbash" ]; then
|
||||
runbash="1"
|
||||
export runbash
|
||||
exec sh -c "bash $0 $*"
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
# Show usage of this program
|
||||
usage ()
|
||||
{
|
||||
echo "Usage: $0 <policy name> <root of xen repository>"
|
||||
echo ""
|
||||
echo "<policy name> : The name of the policy, i.e. xen_null"
|
||||
echo "<root of xen repository> : The root of the XEN repositrory."
|
||||
echo ""
|
||||
}
|
||||
|
||||
# This function sets the global variable 'linux'
|
||||
# to the name of the linux kernel that was compiled
|
||||
# For now a pattern should do the trick
|
||||
getLinuxVersion ()
|
||||
{
|
||||
path=$1
|
||||
linux=""
|
||||
for f in $path/linux-*-xen0 ; do
|
||||
versionfile=$f/include/linux/version.h
|
||||
if [ -r $versionfile ]; then
|
||||
lnx=`cat $versionfile | \
|
||||
grep UTS_RELEASE | \
|
||||
awk '{ \
|
||||
len=length($3); \
|
||||
print substr($3,2,len-2) }'`
|
||||
fi
|
||||
if [ "$lnx" != "" ]; then
|
||||
linux="[./0-9a-zA-z]*$lnx"
|
||||
return;
|
||||
fi
|
||||
done
|
||||
|
||||
#Last resort.
|
||||
linux="vmlinuz-2.[45678].[0-9]*[.0-9]*-xen0$"
|
||||
}
|
||||
|
||||
#Return where the grub.conf file is.
|
||||
#I only know of one place it can be.
|
||||
findGrubConf()
|
||||
{
|
||||
grubconf="/boot/grub/grub.conf"
|
||||
if [ -w $grubconf ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
#Update the grub configuration file.
|
||||
#Search for existing entries and replace the current
|
||||
#policy entry with the policy passed to this script
|
||||
#
|
||||
#Arguments passed to this function
|
||||
# 1st : the grub configuration file
|
||||
# 2nd : the binary policy file name
|
||||
# 3rd : the name or pattern of the linux kernel name to match
|
||||
#
|
||||
# The algorithm here is based on pattern matching
|
||||
# and is working correctly if
|
||||
# - under a title a line beginning with 'kernel' is found
|
||||
# whose following item ends with "xen.gz"
|
||||
# Example: kernel /xen.gz dom0_mem=....
|
||||
# - a module line matching the 3rd parameter is found
|
||||
#
|
||||
updateGrub ()
|
||||
{
|
||||
grubconf=$1
|
||||
policyfile=$2
|
||||
linux=$3
|
||||
|
||||
tmpfile="/tmp/new_grub.conf"
|
||||
|
||||
cat $grubconf | \
|
||||
awk -vpolicy=$policyfile \
|
||||
-vlinux=$linux '{ \
|
||||
if ( $1 == "title" ) { \
|
||||
kernelfound = 0; \
|
||||
if ( policymaycome == 1 ){ \
|
||||
printf ("\tmodule %s%s\n", path, policy); \
|
||||
} \
|
||||
policymaycome = 0; \
|
||||
} \
|
||||
else if ( $1 == "kernel" ) { \
|
||||
if ( match($2,"xen.gz$") ) { \
|
||||
path=substr($2,1,RSTART-1); \
|
||||
kernelfound = 1; \
|
||||
} \
|
||||
} \
|
||||
else if ( $1 == "module" && \
|
||||
kernelfound == 1 && \
|
||||
match($2,linux) ) { \
|
||||
policymaycome = 1; \
|
||||
} \
|
||||
else if ( $1 == "module" && \
|
||||
kernelfound == 1 && \
|
||||
policymaycome == 1 && \
|
||||
match($2,"[0-9a-zA-Z]*.bin$") ) { \
|
||||
printf ("\tmodule %s%s\n", path, policy); \
|
||||
policymaycome = 0; \
|
||||
kernelfound = 0; \
|
||||
dontprint = 1; \
|
||||
} \
|
||||
else if ( $1 == "" && \
|
||||
kernelfound == 1 && \
|
||||
policymaycome == 1) { \
|
||||
dontprint = 1; \
|
||||
} \
|
||||
if (dontprint == 0) { \
|
||||
printf ("%s\n", $0); \
|
||||
} \
|
||||
dontprint = 0; \
|
||||
} END { \
|
||||
if ( policymaycome == 1 ) { \
|
||||
printf ("\tmodule %s%s\n", path, policy); \
|
||||
} \
|
||||
}' > $tmpfile
|
||||
if [ ! -r $tmpfile ]; then
|
||||
echo "Could not create temporary file! Aborting."
|
||||
exit -1
|
||||
fi
|
||||
mv -f $tmpfile $grubconf
|
||||
}
|
||||
|
||||
if [ "$1" == "" -o "$2" == "" ]; then
|
||||
usage
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [ "$1" == "-?" ]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
policy=$1
|
||||
policyfile=$policy.bin
|
||||
|
||||
getLinuxVersion $2
|
||||
|
||||
findGrubConf
|
||||
ERR=$?
|
||||
if [ $ERR -eq 0 ]; then
|
||||
echo "Could not find grub.conf. Aborting."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
updateGrub $grubconf $policyfile $linux
|
||||
+15
-15
@@ -95,13 +95,13 @@ void write_rec(unsigned int cpu, struct t_rec *rec, FILE *out)
|
||||
|
||||
/**
|
||||
* get_tbufs - get pointer to and size of the trace buffers
|
||||
* @mach_addr: location to store machine address if the trace buffers to
|
||||
* @size: location to store the size of a trace buffer to
|
||||
* @mfn: location to store mfn of the trace buffers to
|
||||
* @size: location to store the size of a trace buffer to
|
||||
*
|
||||
* Gets the machine address of the trace pointer area and the size of the
|
||||
* per CPU buffers.
|
||||
*/
|
||||
void get_tbufs(unsigned long *mach_addr, unsigned long *size)
|
||||
void get_tbufs(unsigned long *mfn, unsigned long *size)
|
||||
{
|
||||
int ret;
|
||||
dom0_op_t op; /* dom0 op we'll build */
|
||||
@@ -121,19 +121,19 @@ void get_tbufs(unsigned long *mach_addr, unsigned long *size)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
*mach_addr = op.u.tbufcontrol.mach_addr;
|
||||
*size = op.u.tbufcontrol.size;
|
||||
*mfn = op.u.tbufcontrol.buffer_mfn;
|
||||
*size = op.u.tbufcontrol.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* map_tbufs - memory map Xen trace buffers into user space
|
||||
* @tbufs: machine address of the trace buffers
|
||||
* @tbufs_mfn: mfn of the trace buffers
|
||||
* @num: number of trace buffers to map
|
||||
* @size: size of each trace buffer
|
||||
*
|
||||
* Maps the Xen trace buffers them into process address space.
|
||||
*/
|
||||
struct t_buf *map_tbufs(unsigned long tbufs_mach, unsigned int num,
|
||||
struct t_buf *map_tbufs(unsigned long tbufs_mfn, unsigned int num,
|
||||
unsigned long size)
|
||||
{
|
||||
int xc_handle; /* file descriptor for /proc/xen/privcmd */
|
||||
@@ -149,7 +149,7 @@ struct t_buf *map_tbufs(unsigned long tbufs_mach, unsigned int num,
|
||||
|
||||
tbufs_mapped = xc_map_foreign_range(xc_handle, 0 /* Dom 0 ID */,
|
||||
size * num, PROT_READ,
|
||||
tbufs_mach >> PAGE_SHIFT);
|
||||
tbufs_mfn);
|
||||
|
||||
xc_interface_close(xc_handle);
|
||||
|
||||
@@ -231,7 +231,7 @@ struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num,
|
||||
|
||||
/**
|
||||
* init_rec_ptrs - initialises data area pointers to locations in user space
|
||||
* @tbufs_mach: machine base address of the trace buffer area
|
||||
* @tbufs_mfn: base mfn of the trace buffer area
|
||||
* @tbufs_mapped: user virtual address of base of trace buffer area
|
||||
* @meta: array of user-space pointers to struct t_buf's of metadata
|
||||
* @num: number of trace buffers
|
||||
@@ -240,7 +240,7 @@ struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num,
|
||||
* mapped in user space. Note that the trace buffer metadata contains machine
|
||||
* pointers - the array returned allows more convenient access to them.
|
||||
*/
|
||||
struct t_rec **init_rec_ptrs(unsigned long tbufs_mach,
|
||||
struct t_rec **init_rec_ptrs(unsigned long tbufs_mfn,
|
||||
struct t_buf *tbufs_mapped,
|
||||
struct t_buf **meta,
|
||||
unsigned int num)
|
||||
@@ -256,7 +256,7 @@ struct t_rec **init_rec_ptrs(unsigned long tbufs_mach,
|
||||
}
|
||||
|
||||
for ( i = 0; i < num; i++ )
|
||||
data[i] = (struct t_rec *)(meta[i]->rec_addr - tbufs_mach
|
||||
data[i] = (struct t_rec *)(meta[i]->rec_addr - (tbufs_mfn<<XC_PAGE_SHIFT) /* XXX */
|
||||
+ (unsigned long)tbufs_mapped);
|
||||
|
||||
return data;
|
||||
@@ -330,7 +330,7 @@ int monitor_tbufs(FILE *logfile)
|
||||
struct t_rec **data; /* pointers to the trace buffer data areas
|
||||
* where they are mapped into user space. */
|
||||
unsigned long *cons; /* store tail indexes for the trace buffers */
|
||||
unsigned long tbufs_mach; /* machine address of the tbufs */
|
||||
unsigned long tbufs_mfn; /* mfn of the tbufs */
|
||||
unsigned int num; /* number of trace buffers / logical CPUS */
|
||||
unsigned long size; /* size of a single trace buffer */
|
||||
|
||||
@@ -340,14 +340,14 @@ int monitor_tbufs(FILE *logfile)
|
||||
num = get_num_cpus();
|
||||
|
||||
/* setup access to trace buffers */
|
||||
get_tbufs(&tbufs_mach, &size);
|
||||
tbufs_mapped = map_tbufs(tbufs_mach, num, size);
|
||||
get_tbufs(&tbufs_mfn, &size);
|
||||
tbufs_mapped = map_tbufs(tbufs_mfn, num, size);
|
||||
|
||||
size_in_recs = (size - sizeof(struct t_buf)) / sizeof(struct t_rec);
|
||||
|
||||
/* build arrays of convenience ptrs */
|
||||
meta = init_bufs_ptrs (tbufs_mapped, num, size);
|
||||
data = init_rec_ptrs (tbufs_mach, tbufs_mapped, meta, num);
|
||||
data = init_rec_ptrs (tbufs_mfn, tbufs_mapped, meta, num);
|
||||
cons = init_tail_idxs (meta, num);
|
||||
|
||||
/* now, scan buffers for events */
|
||||
|
||||
Loaded 100 of 119 files, more files were not shown because too many files have changed in this diff.
Show more