merge with xen-unstable.hg

This commit is contained in:
Hollis Blanchard committed 2006-08-07 18:00:22 -05:00
commit fd5755e2dd
368 files changed
+26280 -11385

No files matched your search

+1
View File
@@ -156,6 +156,7 @@
^tools/xenstat/xentop/xentop$
^tools/xenstore/testsuite/tmp/.*$
^tools/xenstore/xen$
^tools/xenstore/xenstore-chmod$
^tools/xenstore/xenstore-exists$
^tools/xenstore/xenstore-list$
^tools/xenstore/xenstore-read$
+11 -5
View File
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.16.13-xen0
# Fri Jun 30 12:59:19 2006
# Fri Jul 28 16:33:47 2006
#
#
@@ -92,6 +92,7 @@ CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_XEN=y
CONFIG_XEN_IA64_DOM0_VP=y
CONFIG_XEN_IA64_VDSO_PARAVIRT=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_DMA_IS_DMA32=y
# CONFIG_IA64_GENERIC is not set
@@ -180,6 +181,8 @@ CONFIG_ACPI_CONTAINER=y
#
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_XEN_PCIDEV_FRONTEND=y
# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
CONFIG_PCI_LEGACY_PROC=y
# CONFIG_PCI_DEBUG is not set
@@ -1513,7 +1516,7 @@ CONFIG_XEN_SKBUFF=y
CONFIG_XEN_NETDEV_BACKEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_DEVMEM is not set
# CONFIG_XEN_REBOOT is not set
CONFIG_XEN_REBOOT=y
# CONFIG_XEN_SMPBOOT is not set
CONFIG_XEN_INTERFACE_VERSION=0x00030202
@@ -1523,13 +1526,16 @@ CONFIG_XEN_INTERFACE_VERSION=0x00030202
CONFIG_XEN_PRIVILEGED_GUEST=y
# CONFIG_XEN_UNPRIVILEGED_GUEST is not set
CONFIG_XEN_PRIVCMD=y
CONFIG_XEN_BACKEND=y
# CONFIG_XEN_PCIDEV_BACKEND is not set
CONFIG_XEN_BLKDEV_BACKEND=y
CONFIG_XEN_XENBUS_DEV=y
CONFIG_XEN_BACKEND=y
CONFIG_XEN_BLKDEV_BACKEND=y
# CONFIG_XEN_BLKDEV_TAP is not set
# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
CONFIG_XEN_NETDEV_LOOPBACK=y
CONFIG_XEN_PCIDEV_BACKEND=y
CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
# CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
# CONFIG_XEN_TPMDEV_BACKEND is not set
CONFIG_XEN_BLKDEV_FRONTEND=y
# CONFIG_XEN_SCRUB_PAGES is not set
+14 -2
View File
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.16.13-xenU
# Mon May 22 15:05:32 2006
# Fri Jul 28 16:32:18 2006
#
#
@@ -89,6 +89,7 @@ CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_XEN=y
CONFIG_XEN_IA64_DOM0_VP=y
CONFIG_XEN_IA64_VDSO_PARAVIRT=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_DMA_IS_DMA32=y
# CONFIG_IA64_GENERIC is not set
@@ -177,6 +178,8 @@ CONFIG_ACPI_SYSTEM=y
#
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_XEN_PCIDEV_FRONTEND=y
# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
CONFIG_PCI_LEGACY_PROC=y
# CONFIG_PCI_DEBUG is not set
@@ -1380,8 +1383,15 @@ CONFIG_CRYPTO_DES=y
#
# Hardware crypto devices
#
# CONFIG_XEN_UTIL is not set
CONFIG_HAVE_ARCH_ALLOC_SKB=y
CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y
CONFIG_XEN_BALLOON=y
CONFIG_XEN_SKBUFF=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_DEVMEM is not set
CONFIG_XEN_REBOOT=y
# CONFIG_XEN_SMPBOOT is not set
CONFIG_XEN_INTERFACE_VERSION=0x00030202
#
@@ -1389,13 +1399,15 @@ CONFIG_XEN_INTERFACE_VERSION=0x00030202
#
# CONFIG_XEN_PRIVILEGED_GUEST is not set
CONFIG_XEN_UNPRIVILEGED_GUEST=y
CONFIG_XEN_PRIVCMD=y
CONFIG_XEN_XENBUS_DEV=y
# CONFIG_XEN_BACKEND is not set
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_SCRUB_PAGES is not set
# CONFIG_XEN_DISABLE_SERIAL is not set
CONFIG_XEN_SYSFS=y
CONFIG_XEN_COMPAT_030002_AND_LATER=y
# CONFIG_XEN_COMPAT_LATEST_ONLY is not set
CONFIG_XEN_COMPAT_030002=y
CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y
CONFIG_NO_IDLE_HZ=y
+11 -5
View File
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.16.13-xen
# Thu Jun 29 16:23:48 2006
# Fri Jul 28 16:33:08 2006
#
#
@@ -92,6 +92,7 @@ CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_XEN=y
CONFIG_XEN_IA64_DOM0_VP=y
CONFIG_XEN_IA64_VDSO_PARAVIRT=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_DMA_IS_DMA32=y
# CONFIG_IA64_GENERIC is not set
@@ -180,6 +181,8 @@ CONFIG_ACPI_CONTAINER=y
#
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_XEN_PCIDEV_FRONTEND=y
# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
CONFIG_PCI_LEGACY_PROC=y
# CONFIG_PCI_DEBUG is not set
@@ -1519,7 +1522,7 @@ CONFIG_XEN_SKBUFF=y
CONFIG_XEN_NETDEV_BACKEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_DEVMEM is not set
# CONFIG_XEN_REBOOT is not set
CONFIG_XEN_REBOOT=y
# CONFIG_XEN_SMPBOOT is not set
CONFIG_XEN_INTERFACE_VERSION=0x00030202
@@ -1529,13 +1532,16 @@ CONFIG_XEN_INTERFACE_VERSION=0x00030202
CONFIG_XEN_PRIVILEGED_GUEST=y
# CONFIG_XEN_UNPRIVILEGED_GUEST is not set
CONFIG_XEN_PRIVCMD=y
CONFIG_XEN_BACKEND=y
# CONFIG_XEN_PCIDEV_BACKEND is not set
CONFIG_XEN_BLKDEV_BACKEND=y
CONFIG_XEN_XENBUS_DEV=y
CONFIG_XEN_BACKEND=y
CONFIG_XEN_BLKDEV_BACKEND=y
# CONFIG_XEN_BLKDEV_TAP is not set
# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
CONFIG_XEN_NETDEV_LOOPBACK=y
CONFIG_XEN_PCIDEV_BACKEND=y
CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
# CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
# CONFIG_XEN_TPMDEV_BACKEND is not set
CONFIG_XEN_BLKDEV_FRONTEND=y
# CONFIG_XEN_SCRUB_PAGES is not set
+657
View File
@@ -0,0 +1,657 @@
%!PS-Adobe-2.0 EPSF-2.0
%%BoundingBox: 0 0 610 400
%
% created by bmeps 1.2.6a (SCCS=1.78)
%
/pstr
610 string
def
/inputf
currentfile
/ASCII85Decode filter
/RunLengthDecode filter
def
gsave
0 400 translate
610 400 scale
610 400 8 [610 0 0 -400 0 0]
{ inputf pstr readstring pop }
image
r;Qmd6ps=,r^.#_8PW)W:fC4d:Jq*eJka?]JkgnmP"tsM!)EGd%7s,^8OZ0@77fs;
77'??705qG4Sf!e6pt0dBlJ$6H@:BtK8,-ULk:B'L4Y6'Lk:B'LAZi1L4b55LA6Du
I0Fb9BjEhVr;R-m;-@(3Bk_O*G'831IK"hMI=cm!I=cmrIK"NpI=6EfrcJ3er,r'_
rHA*Xrb2IA?VWW\rrbGT86&[h<YAS@?"./K?t*JP@UEMP?XI8M@=hm=@$4oL>KU.P
?s?uGrEfn8='8U';G^7f;cEWm%T$&$92/,W:eEo6!<5/JrCmAj;cQlt>52>&>5_TU
=+XM*=+XN'<sVf+;c?Oj:/+I^9E%Np8P)EB770F.5smgo+94/a6N0LZ9heG_;cWft
rE0#!!*0"rJl'QcJkptoO\bjL#Ydra8P)EB77I&?"@5=;5!8g*%Q6't*ATB46qBjC
9i+berDies#ZXl';c-Cf:/6C8Jk^hkJkZ>A:QXo4rs"Q\9heEFlgauZO%i5;8rW'*
rt:&I2DR$=.30ck4@D_29hnM`;u9So;Z]fm;#X2j9hg44b"I=Ya\%.Vn4>s,jHtgV
I!BaVEH,o8Bk_3g>%QEJ8P+s'R#6KCG]\+KEGoc0BkLjXA_N/87uZW-R?<GaKSG,3
J:N#pH?F+JhM2"b$RdA<+>PuC84ZHM;#O;n<E8ur!DuYl:B!t>8qKZt8qKY(8Qc"]
Xg"XjQ&q#bMM[(?IsQ-K=^(,_8cP6]YbdeROH,9WM2$Y4H?*\%>3e[Ks/*9:Ybn+b
S=,_1P`h&aK6h<Hl8CCN-mocQ1-.]l9jqaG@UWeYB4><7s+3no97fdX8qKY(8Q>_M
ZF-X&R$3VkN/NLGJ:)KU>snW`8cOgV[A][aPE:c_Mhm(;I!'726iTYEs-p[8Z`0do
SXZ%8QBRAfL44&>s#)bg-mocQ1-@oo8l\nn='Jo.<rc@fs+3mq97ffq92GS@W2lVY
Oc5*LJ:;fjG&hM8?:Orf9E0[DX.blBN/3.;IX6<`Ec5Yu7fPqGs-'dtXJDJWQBI>i
MMd.@J9u69s#)bg-n,oS1-@oo9%j!_lMlH/JkL\gN(Y,iJ=W=!O,8O?H?O=GChdZt
Ame7292#;8SY)8Bs!VPm?qUGg7/r=IX/+AIP)bETK7JFNaa8;R=oUB<0.87b,W7YM
8PB*YrqcWrn"3GU5QXKCkPG5V9+(@lPY78@PY78@p%(fWl1t3L!U9FI9*+;Qr(I%h
!r:o[fh2A7n*NdIrrW#WY4kQml1mtFn*f[;q>^"Y!U9E39BSs"8FT.Zs*U)uOc+pC
H?O:FC2!QX$"-C*84`c.Q'[X,rsNFN?qUGg7/r4?Un@Yd"H%teJ:.@r&UAV@=oUB<
0.81`,W7eQ8k]3Zrql]tLDXF&rkATFBGc!gr;QaLrC[OTs//K!s//K!s4/st9*5.n
0)S?Ds8O_>9*5.n0)\EIs8O0emJjZd9**Z;n4Nf6p&7Scn*W+%9*YFr++!>S\+iT#
s8O]En*W+%9*67Xs8W$>o1K/bs"8mrJkO]g)uk,DOc>0KI<]jPCM79h@Us%W9)hOW
s*'QeNV<A\A7]+?s$fEVLRk',QN$mcKn4[Ort9L!GB$ab3&WE<.2F0e4[Vb5s7lTl
rr^k4Gk_%6!f&JMrVlj\rC[O6s2@ISs2@ISs04`Z9*5.n+8eb5s8O2/9*5.n+8nh;
s8O06UAsdRo1K/bs"a+;!rr9Ur_!8M2XX3Cs8O06UAsdRq+CqlruXm,2E'np!rr9B
n4Ni_ruZhcJkO]g2#hcWMi!1>HZsLKCM.0e@:EbS8cMFVs*'?YM>r-RGB.V;B4PKO
@Urh;s$]?ULR=KsP`PhD!.b(K'6SA=G&UR`3&`K=.2F0e4\/:Bs7lTmrrT)Pa7fN7
f/SQbrr>[i9+[?fj?`&1j?`&1H::K`s8UsT9,.F+hXsPAruXnjs1qA.ruXnjs8UsT
9*Fqfs66<X9*OS[p&G%6rC[k)ruXm,s7nECs8UsK92".As5$CArVm$o9A]^KhYp.O
d.RG3\4cf#!)*=k"\VMFs8UsT9*P@Vq>]]Sr(@IuruXm,s7nEChZ*W4r_!=mru_7?
%SKIAp&F]p9BlJO9;DOUqF^niru_55"5a(XhYp.MhZ*W4r_!=mruZhcJkO]g2?.WL
LkgY6I!BdQD/!Tm@U`hR8H2=Us)<[JL];mPG]dtBBkCoU@Ui_8s$fKXJWlCbP)kS"
rtK^$FEMbF=8t6=2D6Ts-oaOa925H]rWN9$k:#fjrrYO$s8Vsj./!U$s6'DCs7@C,
fDiO^s4'h<s8T@11]RIshZ(827fWK1fDiO^s4.*C$o<hAmRp:2s26#Zru_265QCa*
9pPb0/kuBGZ*Q7<s1P?1eP/d<ruW?>s2Co9gJ-)qehc1*859-a+!45Wru]km]r1n\
9hkZfS"frG9DqR2s8O08Q2fDffDiO^s4'h<s8O08s8O1gs40!_b"0)CbtH[g]JfX[
(B=CV92!n:]VkeZ9@s3VVuP7>9E5#6JkL\gf1S%%Ck%(jK7A8nF`MA8B4YR^@pMS(
92#;$ItNFSIscK`Ec,Z*AcH4L>t4ic8H4.!P*;#gN/@Q6!do9;rcJ`h<rY9C2_QTu
-oaOa9i1lbrWE3#8@S0i"5bO$s8,PBhZ'k\S,]bneh^(truX`1q*@dUruX^$s8VEb
bo]DMs8O2;ruX`1q*@d4qYpL#2bs5L+%?50+8nr!s8O1,nG.Ap:B1>97S*CU+%H;+
5u.I[+&;\4+%?5*5P>$u5u'R1:B1>9:/:ih+8Z!Z7fW9M:B1>99E5#QrD"[=ru[Qr
q0G:%ruX`1q*@dUruY#9ru^q6+$iXb6Vd:E61t8(7Jfgqs8O09:AXu47fW9MqYqX,
s7nrUs8O0m:4c6m:,W&bH\$d"J:2`gF`D;6B4PL\>"&Bc:B,!SJV*oPI<p-\EGfN(
s'oJ@7/ohMs*BQaOcb]ar;RIXH$4=PCfLEr4#\]A)C[d892/7_q#1?pT4%0g!f)%#
qbT8is5`eop#Q.X5Z%L\+&N";02V]K+&Gf6s7u]U78Qh\ru_:@+&N";0C&SN0E;%o
;#gP;;#gP;rD<Im($(c9:/Luj+&Gf6ruY);s"@4KruY)7rrXqSru_/8(B=CV:f.2l
+92?_;#gPK;#gP;;#gP;rD<Im($(c9:B1>9;#gPK;#gP;;#gP;s8O2=:^4i;\c:h7
:A[j's8O0;;#gP;;#gPKs8O0;s8O`Ks8O0m;!:`-:@M"8s'p5#J:W6"H[9mXE,96"
@piD+s%Z>h@s39Ns+#QFH?XIMCh`oZ?s#er9M5>.L5_1SNrK%pL]@DJH?XLPBiG$r
5!(PO*%<s992JOdq#1?p)!Chs!P_M2,lhHOrrF8"qboJBs8Uh2huE_&92k]e+&i48
+&i4>+&c,<s,5h8`D]_8ru_+;+&i48+92?_9E5#6;u6M9;uck>rDNass8F)U5YtBX
s8O0>;u6M9;ucY8;uck>;u6Ol*s2<=+8f%Qs8O0>;uck>qYqX9s7ma8s8O0>s8O2>
;ZZpurZ;h>:fI5j+&i48+&i4>+&i4>+8Z!ZqbmXjs8T>dqG7t-ruY'6qYqX6s7mc5
ruY);q&`H5ruZhhJl(&q"TMhJH%#Ph-ZO$=An,.I5lXYWs'K_jIK+bEH[0gYEGfOk
@pW/#s%H,dF+T7.NrK%[M2-fart0HsE+`#I5<h4c/0$3&6V10Rrr3#urqucs^Hh_s
#JU6=,p`Nk;>^@oG_c,p2td3U6c8rp+&Z(ks09fJbqN,sruY3>s8O0;q>$4RqYqYj
s09fJbqS&TMp25$McAU6]N"q2+8o.?s8O2<<&XdV+&l4ms09fJbqN,nruY4gs2E4Y
fi6E"`DksP<)i_o+&l5>ru]qoZ-<6m0NA)P+&r:?+8o.?s8O2=<#"$cZ-<6m0N@oK
+&r:?+4C2.<9;g4<!:YLruXr2<#5N6+&l4ms09fJbqRiNZ-<6m0N@oK++dID<7b(P
s&s2[H2@OfEc,W(?s6Djs&;tt>&/5*s*K*=H?XOQDJK2Z>#@H_:/(\*I>*OWrre18
L4t6YrtBHkA5E4n6U*Xf*%X0?9i=nP2`CLk!IoUsrs1^e4S/T;!%#DXrrKT"qGmjZ
s*@D/s40..<\3),s48>_<r`1A<`]8#+'-)Ti)IDc]N3kgs48>_<o*f/h>aBO<pBYW
s8O2><W`=$+8](?s8O2?<\WA0s48>_<lP+=<`[TCs7MXI<m^F;p7=cT`W,s=<r`1A
<o*fUf,mL`s8O0As8O2><W`=$+8](Wh>dN,+%KAFq7Kc.ruY:go)JET7oiZ[s4/:f
<W`=$+9#:Ph>dN,+%KAfs8U[m7om>!]Rj2J<e=<?<!<5%Ao;_erss*eC1UaR9fi;R
<<$!2DKPUP1LF3X3r`&Qs(ck0L!K^RLPCM8J:@O>EGJrUs$T7>3\MI%4%;tC;c?Rn
<*!+(=]\a6TDecljs:#&rr2uBqYpW;3$8!$#"Th<>?Dt<rEB@p+!4,S>6,ffr`]mT
+'VrJ+%9C41/D+F+!4,S>7=%E8k:%&>?aB83?K@@>6,ffqHEtB+8oCG808pGr`^IA
+!4]k9JR\M<a/d%3?L7^>?arH+'Vqk+'Vr?+!4,S>6Q)j>?`0kr*'1D+8T1D808pG
r`^"61/D*r+'VrC3?L7^>?eN8Vb$Se!?WE^>6@D<+%lN:"%XLU9)`#r;_h.#>No@D
=7B8os&39<DZ"JdE,TQ-ARSeB8icoQ=8u3+BQ!`f'6%l+C1UgX<(]1N<)N[.F*`@g
KDpHHJU`)oGB7Y8?;(;g6pj!j*%!a::/b.o=^,3>?smDP@T]Q,rr^IF!6k0:!T,#O
>M<9as8Va6;hA5*>I[l@s%QU'ASD!U&SGZa?WpH+7Q19N>Q7E"?tF$LBfKa:@UE;=
:e!AC<)im,CiaiII!U-dH?j^VEG]E#>"AT_7moBn*%!a::/b(k=]o$;?X[AP@VD,,
rr^IF!5J7-!P^mO?.rQes5&Yo?%Q:4>I[lqls!.]='Ad1>$>'3=&i0p9Lh<?s'&^o
>>.pr>$>'4>$5!0<Du[e7mBZH=&eO&?t<tfChmkdCER>)AR]"N;Hj)m7moBn)C@O8
:/Fkh='&O/?!grI@>B+*rrOJHFT2:A,s7t#rrK<"Jm6o4!Zsj3Jm3h2[p)gtfi1+$
6:4%+6UF((5<V(h2bVbg>?dEH<'<Q76U=(,6:!k$4Zb\`9@oD0<0Q*H9Mn\c;,^Ck
;Gg:d9he2_g5eir6om(A-9F[l:ejhd<)m((r`]G0a#O"s#\*i7L!4$,-0G.*!FVOO
=k-Z,=+XM`<rlHgnc&g[PZ_'h=d8IV#4.OR<)HSVnc''aO%Mo16TQt@-9F[d9)_Nd
:f:3j<s2Z/s!ZLsrr>1Z!!&elrrVp3mt+Mj<.\)$<97'h;,gCg:ejb]:JOSU9M.qU
9En*Z8k_iI8,G[^3\hU#4$,hk5!M:tr^6ZR"%WC+5l:QaPYjPb^\e$4BUAaN7Y4+#
7Y3qK5ljABqEY0I4[&a+!BiRE4V9e>4?>M_3]B#W4$#,8-9F:Wr]U?I5PdVIs8Qc!
o)Ag43<0#15LhuM5(YtM54UlB4#8W3,rf7*p#lPYs7[r!o`#'_0\?@)K'7gMK'7gM
`omXq3[Pak3+#APkl1S`cR>.RrrTYX\,QDZk^r#Mk^r$<kQaL:-5n0i?VL.VrVlug
BK4W?rr_Fl8E]sOK'7gMK'7gM`omXq3[Pak3+#APkkkAea!`WkLVJn"5T$-js+9Hd
k^r#Mkf2fk6olY5,rf7*p#u5O#1%dD5]D4fq>^6R!!'dt!!%W7K'7gMPir??3[Pak
3+#AVkkkD_kQ'fHmcaQKr9+7`kQ'fHo&p&RroaC`kQ'c/!!)u]!!)lZ!!%W7K'7gM
Pir??3[Pak3+#AVkPtVZkPtVNkPtVXkPtV^kPtVRkPtV^kPtVDkPtV]kPtVZkPtU7
k^r#Mk`k996olY5,rf7*qre"[r9+7`kQ'i1rW)QR!!)o[r;Zo_!9jC^o]Q8TroaIb
kQ'i1rW!5fkQ'i1!9iVHo]Q8TrTF:_kii!G"6eqKkktL5k^r#MkaCW>6olY5,rf7*
qrmqX"m>sM!9aF^kPtVTkktJ_ki`$GkQCnL!9aFQkQ_+O!9iVHkQ(VG#QX&gki`$1
kQ(8=qZ$Z\!<20b!9aFH!<20^!.sEdk^r#ekQaL:-5n0i?VL@\!!)r\!s%NbkkkGQ
kPtV\kPtV^kQCnL!9aFQkQV%N!9iVHkkkDckQ'fHkQ'fHo]Q8TrTF7^kkkD_kQ'fH
roa=^K'7gMK'8Ze#=LU")C7@M9`+#R!;u$`!9aFH!:]1P!;u$\!<20b!9aFH!:f7X
!9aFHkQ'fHr9+=bkQ'fHkQ(8=!!)u]!W_Ear9+1^kQ(VG!!%W7K'7gMRcjuE3[Pak
3+#AVkPtV\kQCnL!9aF^kPtVTkPtV\kPtV^kQCnL!9aFPkPtV^kQ1bJ!<20a!9iVH
roa=^oB6/SrTF:_kQ(VG"9@WckQ(VG!!%W7K'7gMRcjuE3[Pak3F>JWkPtV\kQCnL
!9iYG!;#FP!!2<Ir;[#b!9iVH!:o=R!<20`!9iYG!<20^!<20^!;#CS!<)*_!9iYG
!!DHK!9j@]K'7gMK'8Wd#=LZu)C7CN9T\H<!.sEdk^r#akQaL<+rVaf?VL@\qZ,sG
qZ,mEqZ,aAq>g?T!!%W7K'7gMQKSQA4<b[i3F>I3k^r#Mk^r#nkQaL<+rVaf?VH(8
K'7gMK'8un#=LZu)C7CN9S2J[k^r#MkbI>H6p)Y3,ro=+K'7gMK'7gMUZ_qN4<b[i
3F>I3s+:9&s+:9Grs(qS+rVaf?VH(8K'7gMK'8un#=LZu)C7CN9S2J[kecQKs+9Hd
kkXEI6p)Y3,ro=+K'7gM_W^:bK'7gMq</&O4<b[i3F>I3k^r$8kj&2"k^r$okQaL<
+rVad?VH(8K':)8qYpWcT2>MP!_A[@qYu02K'<$o#=LZu)C7=L9S2J[kecQ\rr\#n
@'BRE"Li%]Gk_.9K'7gMq</&O4<b[i2d]71k^r$8kl(M`f/S$Lq>UMO0ZX.lK'7gM
q</&O4<b[i2d]71k^r$8kl1S`V_H0brrUe3L]7=*k^r$okQaL<+rVad?VH(8K':)8
"TSMb..?d-"$jX$s+9HdkkXEI6p)Y3,r]1)K'7gM_WV+%s%'Wirr_.,p]#j/K'<$o
#=LZu)C7=L9S2J[kecNbs.<]grrRt#s+9HdkkXEI6p)Y3,r]1)qWNOVK$MK`!rj,#
r;Qb=r?VGRqYpR=htcJfcAKmIchci16p)Y3,r]1)qre(+d":J5kfW)i^Hh_s#BTqG
4='t-A,H9,G_c.Z!RB&Dk_nX*dE_XQ#=LZu)C7=L9`4)Tcd7:-K':>?!IoUsrs)CI
PlLb\!'L/Y!OkVskQ0#VK'8'T!R]6kkQaL<+rVad?VLC]!7$2[K'3=#jPJYOg?R2h
@%[5o"2@\54T#-Za#Nt[!7$2[TBH@;hV7n\rmh#%"5DVfjSe9Bchuu36p)Y3,rT+(
r9+.+K'7gM"R+_#N_@VN!Ec8trs.\.,p`O;!'L/Y!T,$skQ&n[kb%&@hVaDeoe6J5
J)fPekQ&p+kQaL<,8qjd?VLC]!7$2[K'3@$gl?O$c2RfXQi-jg,lg&]b_6$Zqu6]3
5l9aFc@Y8PkQ9P"8+Y^A7ul[/kQ&p+kQaL<,8qjd?VLC]!7$2[K'3=#ge5i7rW.e!
rVm/I!%$e-s'l$kqu6]#;#BGVc@Y8PkRuZDd*P)*6-qpE6-qpE6-qpE9DmuRcMZl2
6p)\4,rT+(r9+.+K'7gM!pJAmrqt(=!QR1urs6gK!0mMY,lf7grrHN"qre%*K'8ij
"PYWV62^HR"4#4Hli$#IcMZl26p)\4,rT+(r9+.+K'7gM"6eMoqTSa:s!ZLtrs(Xd
!$qV-!%%RC!r!Q#qre%*K'8ij"5GTSc1Ul75KkhJrTF7,r9+AR4<kaj2IB/UkQ&n[
k^r""khIl8pB(B05lCWeF?F'Js+Q0urVlq4QiHsH!7$2[TBHC40Zc6HpB:34atW2\
kQ&p+kQaL<,8qjd?VLC]!7$2[K'3:"gb?qE"98C7Qh(.Ya#O,!qre%*K'8ij"5GTN
a7f0/oJFWCm/?,JcMZl26p)\4,rT+(r9+.+dHCT2!:/hL!!)3G!!&>KquHNU!<<,r
kQ(Y`lf\B)0['+ls8VgAht6pOmkEAns82![cFW3?!!(O4!<<,ikQ(Y`gZSY<!7L'5
gb?Z&rUp*hrq-Ed_o"1prTF7,r9+AR4<kaj2IB/UkQ&p&kkbA=kQ(Y`nE9lQ!<20_
!!)3G!!)o[qZ,O;!<<,ZkQ(Y`qWReVp#lPZ!9iVH!;Pa]!!)6H!!*#^!<<,ckQ9Nn
p%n:]!!*#j!!)BXquH?\rr3&G.$sZ-!k0Serr;lZ!7'KcqZ,gC!<<-!kQ(Y`l0/!E
o&p)S!:f7R!!)BLqZ-?R!<<,JkQBTo_86-C$ig;"oDem`o^aoU0^Sc%!7(N+#=L[!
)C7:K9`4)ScM6T(!!)u]!<<,GkQ(Y`j6-ICqWIq[!<20_!!(s@!<<,ZkQ(Y`qWIq[
!<20_!!)`V!<<,hkQ(Y`k3)m%0_P;7rW!#loDn:N!<<-!oDnplo^r+^"7Kn_fD>LL
k?pjDrVucY!7'Kc!<<-!kQ(Y`ki`$I!9E>E!!)HN!<<,RkQ(Y`roa@_!;G[X!!(I2
"5GTH2#d+U!!)Z`!!)Z`o>/6sm/?,JcMZl26p)\4,rT+(r9+.+puh_Y!<)*f!!)3_
!9aC_kihmDroj:\"R,%L!9jC^"R,%L!9j:[roj:\!U/bF!!MKc!9iYE!!MNL!!)6^
!;G[W!;bm[!!)u]!rr>bkkkD`ki`!Hkl(S\kktJdki`!HkPtVHqu?`\qu?`\rW)r]
qu?l`kPtVHrVuu_kkkGYkQ(Y`rTF=`!9iYE!!2<Ir;[&c!!)3_!9jC^"R,%L!9j=\
"R#gckihpE"R,%L!9jC^qWJ%:0_G#7oDJXko)SCRr;[/qo)Jd^!!)Tj!<)Ki!!*#i
#QOkr!!)TjoCMk[!;$*f$HFPKItte"Im=jCqu?QW!7'Kc!<<-!kQLqdki`!HroaLc
!9aC_kl(SXkkkD_kPtVHqu?`\rW)r]quHWX!<<,tkQ_(fki`!HkihsF#3b7N!9aC_
roaFa!9iYF!!VTM!!)6Hqu?l`kPtVHrW)iZ!<<-!kQLqdki`!HroaOd!9aC_kihpE
roj:\i919u0YP0so)Sgkrpp9`1qk[1rTF7,r9+AR4<kaj2IB/UkQ&p'kQ(Y`rTF:_
!9j=\!pBUaroaIb!9iVHroaC`!9jC^#3b7N!9aC_r9+7`!9iVHroaLc!9iVH!<20b
!!)3_!<20`!!)6^!!DHK!!)iY!!)iY!<<,ukQCkckPtV^kQ1_akl(Pdki`!Hki`$G
kQ1_akkkD_ki`!Hroaaj!9iVH!9iVH!9aC_roaC`!9jC^#O(@O!9iVH!;bm[!!)u]
"98Gc!!*#^$31(ikPtVHkPtVHrW!;hkPtVH!!)6H!!*#^"98Gc!!*#^!WW5arW!&a
kPtV[kQBTooCMkM!<D]h!"\W#!:o[\!:g*inc/[\!!)ug!<<-!ncAdko)/Onnc/[\
nc/[\q>UZFIs=4tJ%tgZqre%*hrk(@!<20c!!)6H!!*#^!WW5arW!&akPtVYkQ(Y`
roajm!9aC_ki`!Hki`!HkPtV^kQ(Y`r9+.]!;u$d!!)6H!!)3_!<20d!9aC_kPtV^
kQCkckPtV^kQV%N!!)3_!<20`!!)6^!!DHK!!)r\!<<-!kQLqdki`!HroaRe!9aC_
kPtV^kQCkckPtV^kPtVAkQBTo\ki7p!<<,unc\Ko\hNLLkQ&p+kQaL<,8qjd?VLC]
!7(B'!<<,ukQCkckPtV]kQ(Y`roa@_!;ks_!!)3_!<20b!!)3_!<)*^!!)lZ"TSPd
kPtV^kQCkckPtV^kQCkckPtV^kQ(Y`q<.eYq<.hZ!<)*a!!)3_!<20b!!)3_!<20_
!!)o["98Gc!!)r\!<<-!kR7Fkki`!Hki`!HkPtV^kQCkckPtV^kQLqdki`!HqWIq[
!<)*a!!)3_!<20j!!)6H!!)6H!!)3_!<20f!!)3_!9iVH!<20b!!)3_!<20b!!)3_
!<20_!!)o["5GU%oDA([!:o^[!!)Te!!r,q!:g*inc/[gnc8^jrpg0l!:g*irpg3m
!:o[\!;c6hna,?km/?,JcLg<#cJRj_!<20_!!*#^"98Gc!!*#^!WW5aqu?i_kPtV^
kRRXnkPtVHkPtVHkPtVH!!*#^!<<,tkkkG[kktJ`ki`!Hr9+7`!9aC_roaC`!9jC^
rTF@a!9aC_roaIb!9aC_roa@_!;u'X!<20_!!*#^#64bf!!)3_!<20`!!)6^!8coA
gb?=Nr:0jg!<)HknPHeNm/?,JcMZl26p)\4,rT+(r9+.+puh_Y!<)*a!!)3_!<)*^
!!*#^!rr>bkkb>]kPtV^kQCkckPtV^kQ(Y`rTO+Y"6eqK!<20b!!)3_!<20b!!)3_
!<20_!!)lZ!!)fX!<<,ukQ1_akkY8\kPtV^kQ:ebkihmD!pBUar9+.]!<20h!!)6H
!!)6H!!)6Z!!;?a!<20c!!)6H!!)lZ!<<,ukQ1_akkY8dki`!Hki`!HkPtV^kQh.g
kPtVHkPtV^kQCkckPtV^kQCkckPtV^kQ(Y`qre.;0_=o5nc/[hncSpmnc/[fo(`:a
nc8^jrpg0l!:g*irpg3m!:o[\!;c6hna,?km/?,JcLg<#cJRgg!!)3_!<)*^!!*#^
"98Gc!!*#^!<<,qkQ(Y`roadk!9aC_ki`!Hki`!HkkY;WkQ(Y`qWIq[!<20_!!)r\
"98Gc!!*#^!rr>bkktJcki`!HkPtV^kQCkckPtV^kQ(Y`r9+7`!9aC_rTF7^!<20c
!!)3_!9j7Z!U/bG!9!&Cgb?0>p@8@V\$e!WrTF7,r9+AR4<kaj2IB/UkQ&p'kQ(Y`
rTF@a!9aC_rTF7^!<20b!!)3_!<20b!!)3_!<20f!!)3_!9iVH!<)*^!!*#^"TSPd
kPtV^kQCkckPtV^kQCkckPtV^kQ(Y`qWInZpuh_Y!<)*a!!)3_!;ks\!!*#^"98Gc
!!*#^"98Gc!!)r\!<<-!kR7Fkki`!Hki`!HkPtV[kQ(Y`roaLc!9iVH!;bm[!!)u]
"98Gc!!)lZ#QOkgkPtVH!!*#^#QOkg!!)6H!!*#^"98Gc!!*#^"98Gc!!*#^!<<,s
kQBToo()\J!!)uf!s%ik!;l9i!!)QZ!!)re!<<-!nH8glnGiRgnHAmmnaQSZqXF^X
lf9bdrTF7,o]Q;#hrk4D!9iVH!<20_!!*#^"98Gc!!*#^!<<,qkQ(Y`roajm!9aC_
ki`!Hki`!HkPtVWkQ(Y`qrmtY"6eqK!;u$`!!)3_!<20_!!)u]rW!,c!!)3_!<20b
!!)3_!<20_!!)r\"TSPdkPtV^kQ(Y`roaRe!9aC_kPtVXkl(S@kQBToZa9T"!<<,u
nHA>`ZS:bEkQ&p+kQaL<,8qjd?VLC]!7(B'!<<,ukQCkckPtV]kQ:ebkii!G!pBUa
roaIb!9aC_roaRe!9aC_kPtV\kQ(Y`roaLc!9iVH!<20b!!)3_!<20b!!)3_!<20_
!!)o[!!)cW!<<-!kQLqdki`!HrTF=`kPtV^kQCkckPtV^kQCkckPtV\kQ(Y`roaaj
!9iVH!9iVH!9aC_rTF=`kPtV^kQLqdki`!HqWIq[!<20c!!)6H!!)u]$NTDS!!)6H
!!)3_!<20f!!)3_!9iVH!<20b!!)3_!<20b!!)3_!<20_!!)o["5GU$o)%qW!<)Eh
!:fUW!!i&a!!)QZ!!)odqu?ihnGiRfnb`C`nHA@Ij=os!kQ&p#kQ&ockQ(Y`roaRe
!9iVH!9iYG!!;?a!<20_!!)iY!<<-!kRRXnkPtVHkPtVHkPtVH!!)u]!!)r\!<<,t
kQh.gki`!HkPtV^kQh1P!!)3_!9iYG!!29`roaRe!9aC_kPtV^kQCkckPtV^kQ(Y`
r9+.]!<20e!!)6H!!)6HrW!,c!!)3_!<)*_!9aF^kQ(Y`iTLC!0XFjYnGrUirUC$[
['MIQrTF7,r9+AR4<kaj2IB/UkQ&p&kkb>^ki`!Hr94+["R#gckihmD!pBUaroaLc
!9aC_kkb>\kihmDroj=]"R#gckihpE"6eqK!<20_!!)o[!!)cWqZ-TYqu?c]kkbAZ
kkb>]kPtV[kl(PjkPtVHkPtVHkPtVHkkkD_ki`!Hroa@_!<23]!;u'X!<)-Z!<20f
!!)6H!!)3_!<20b!!)3_!<23]!!MKc!9iYE!!DHK!!*#^!<<,skQBTonaXuq!<<,r
n-&4Fj"TiukQ&p#kQ&ockQ(Y`rTF=`!9iYG!!VQd!9aC_roa@_!;PdW!"\8n!9aC_
ki`!Hki`!HkihpEqrmnW#j;6gki`!HkihsF"mG.M!9iYG!!MKc!9iYF!!VTM!!)6H
qu?i_kPtV^kQ(Y`r9+.]!<)*`!!)6HrW!2e!!)3_!9iYE!<23\!9!&Cgb>t9p@&4R
@'D?OrTF7,r9+AR4<kaj2IB/UkQ&ohkQ(Y`_<:k!jlc^F!.sD<kigeUnaY)tr;cZ_
"RkX90^Sc%!7(6#!7$2[TBHC40WeaVn-&3^XYB,?kQ&p+kQaL<,8qjd?VLC]!7'im
!!)u]!<<,9kPtVEkQ(Y`K'3C%khIl]nAju#mci^bm/?,JcLg<#c@Y8PkQBToX/bm^
"R]!a0^Sc%!7(N+#=L[!)C7:K9`4)ScKOKi!2J`Y!!%W7"6et(0ZEJ`mH<F^mJZ5K
cLg<#c@Y8PkQBToW(m!S"RW.f0^\i&!7(N+#=L[!)C7:K9`4)Sc@Y83kQ9u'0ZE;[
kMb2MmJZ5KcLg<#c@Y8PkQBToW2TFT"QrLX0^\i&!7(N+#=L[!)C7:K9`4)Sc@Y83
kQ^8,5fDO8h9+RXh:pPm5k"[8!7(6#!7$2[TBHsE5c@DU9rLdb9rLdb9rLdbW'KhM
kQ&p+kQaL<,8qjd?VLC]!7$2[K'3@$hgT:?a3Xt8[:Y'_rTF7,o]Q;#K'8ij"5ePt
G4^Lj7t^F3kQ&p+kQaL<,8qjd?VLC]!7$2[K'3@$jQM_!`\7K[K_"d6kQ&p#kQ&n[
kb%&@jQM_!oe6J5K_"d6kQ&p+kQaL<,8qje?VLC]!7$2[K'3C%kj7g1o]>c.q#9pg
p@e1FrTF7,o]Q;#K'8fi"75OKo_eC]q#9pgp@e1FrTF7,r9+AR4<b[i2d]8VkQ&n[
k^r$/kQ&p#kQ&n[k_J@%cMZl26p)Y3,r]1)r9+.+K'7gM\`a%>o]Q;#K'8!R!71T,
#=LZu)C7=L9`4)Tcd7:-K'9i1!R]6ckQ0#VK'8'T!R]6kkQaL<+rVad?VL@\!RB&D
k^r$3kQ0)Vo&p,"d":J>kQ0)Vqre8Q4<b[i2d]8Tk^q*3cFhF&cg^.McAKmIchci1
6p)Y3,r]1)K'7gMK'7gMUZ_qN4<b[i2d]71k^r#Mk^r#nkQaL<+rVad?VH(8K'7gM
K'8un#=LZu)C7=L9S2J[k^r#MkbI>H6p)Y3,r]1)K'7gMK'7gMUZ_qN4<b[i2d]71
k^r#Mk^r#nkQaL<+rVac?VH(8K'7gMK'8un#=L[!)C7:K9S2J[k^r#MkbI>H6p)\4
,rT+(K'7gMK'7gMUZ_qN4<kaj2IB.0k^r#Mk^r#nkQaL<,8qjd?VLC]JsV(U\!M^1
K';dh#=L[!)C7:K9`4)SQ\,6hs1/.0Q\+FQkjmpB6p)\4,rT+(r9+-IqYpd!q!ctH
aRk)aK)`mk!1/<$K';dh#=L[!)C7:K9`4)SQi$dhrpAIln&MTRnc".?K)`sm!1/<$
K';dh#=L[!)C7:K9`4)SQi$diq;BrLnB%i@b3o7\s+:9nrrAC;k^r$hkQaL<,8qjd
?VLC]!13T_$N8oDeaLP]Zan``K)^H&b5VI.K'7gMo&p<H4<kaj2IB/UkQ$tGrsI]G
g[N._ZEqEgon*3qs3(EBQ\+FQkjmpB6p)\4,rT+(r9+-IqYpu_oC)=l\&-G3ZHhq;
qZ$Npp\t6o!.t6&s5X+ZQ\+FQkjmpB6p)\4,r]1)r9+-Iqu7-!iVNEEd`KAF`Nutt
meZt_!.t6&s4@8NQ\+FQkjmpB6p)Y3,r]1)r9+-IrVmE%mHEL)qXi"OZEq3NZa\'R
rt,52rr<'!rr<'!rr<'!!!*'!r;_HLK)b*8!1/<$K';dh#=LZu)C7=L9`4)SQi6pp
gX4<rqYK`q\uiHR[Bm3Cqu79/!<3$!s8N'!s8N'!rr<'!!!%WNK)b!5!1/<$K';dh
#=LZu)C7=L9`4)SQi6pp^q7(lqYK]l[^3NS['R*Lqu6d!!<3$!rr;os"TSK%!<;ut
K)^H&kl1XLmHB/IPg09Tp#lWK4<b[i2d]8VkQ$tJrt!#Q[Cc%umC0F2]!o#PZ-<.G
q>^Qrs8;p$s8N'!s8W#tK)^H&l2LaMmcX\sd":JHkQ0)Vp?2`L4<b[i2d]8VkQ$tJ
rt!J_ZF/9"k-qY#Wi3),ZJGHY!<<-!rrE*"rr3!!!<3!!!!)ut!<<+Os+::8rrADS
kQ0#VK'8E^!R]6fkQaL<+rVad?VLC]!13Za&)=Cp['5AA^:^:pI$U\@kPY>\!!*#u
!<<-!rrE*"rr3$"!<;utK)^H&kl1XLn)sbsrTF=DhV7,FkLKRc"5DVfjS\4pQi-(-
VZ?bqkQ&s'kQaL<+rVad?VLC]!13Za&(I\m^nl51guG2R?YG(pl%8qes3:QDQga,<
cMcr/hVaDea=m]]J)fPdkQ$s(rrAD`kQ%OBD?92*rTF7,pZMiM4<b[i2d]8VkQ$tJ
rstZuh;PV\htlr+F]`<fG0Y^>K)a*q!130<!7(Q,"5JoZbfKedgi\Y<r9+-ILAq7?
r9+0ZDWh$$aR9*,kQ&p&kQaL<+rVad?VLC]!13Za%t:M;m^%,eoA,I;:L.7+Y(H\*
s3:QDQga,<cMcr.ge5i2rW<&@9DdoQQ\PM?Qi-%JVf(_u"3AROs8D-]cM-N-6p)Y3
,r]1)r9+-IrVmD#HZYIGDm$9m?"&/%M2fu9s+:9qrrADSkQ&p,kQ0Elrqsn8"8_XD
lhorHQeDB=!3cD&Qi-%LVf)P7lKA>kaR9*,kQ&p&kQaL<+rVad?VLC]!1/<;K)`C]
!130<!7(Q,!o,L+a8#i0mP+#*kQ$tIs8;rbs8;rorr<&&rrAD`kQ@`#s8VBJ"3ARO
s8D-]cM-N-6p)\4,r]1)r9+-IqYpd!q!ctHaRk)aK)`mk!130<!7(Q,!SfBLpB:3[
l7hT&kQ$tJrr<&arr<&mrr<&&rrAD`kQ@`#s8VBJ"3AROs8D-]cM-N-6p)\4,r]1)
r9+-Iqu7!%mG$7]a0*STrdt0%s2k9@Qga,<cMcr-gb@@Q!<<,to`5$mqXk!`n)uIl
r9+-Irr2ruqZ$Nprr;rt!WW3!!!<3#!;c`p!!N?%!<<)u!4;b+Qi-%LVf)P7roj=\
#NUn=/MTtVhu3TRkQAoImf37L!7(?&#=L[!)C7=L9`4)SQi$diq;BrLnB%i@b3o7\
s+:9nrrADSkQ&p,kQ0HmiV!0MqXjjh!;uKj!!)lg"SD0H0^S`$!13]b!!)or!!*#u
!W`6#q>UKrrrDrr!!*#u!W`6#r;Q`s[Jp5nr9+6\DZBb9kR[^nqN!6aDO6T53%9UX
s8W&]"3AROs8D-]cM-N-6p)\4,r]1)r9+-Iqu7$%i8iGWa0)bZf_C'uK)a!n!130<
!7(Q,!o,L&n+6V\!;?'a!;c<g!!)rh!<<,roE=dRk:l9#kQ$tKrr<&rrr<&urrN3#
!;ulq!!3*"qu6Wrrr3*$rrE*!r;a8*!13WI"/g&:s8M3cs8?a^K(Am?"o4W@?Ma^#
kQAoImf37L!7(?&#=L[!)C7=L9`4)SQhp^hi8r__`2p8N_T2>$s+:9orrADSkQ&p,
kQBToo^qSC!<<,qo)o$no)JdioDARhoCMk[qXXj\mH-+hr9+-Irr2ruqu6Wrrr3$"
rrE#t!!*#u!W`6#qu6Wrrr3*$rrE'!rr2ru[Jp5nr9+6\DZBb9kQLpF-S)_'rr^4p
JcG]4"3AROs8D-]cM-N-6p)\4,r]1)r9+-IqYpu_oC)=l\&-G3ZHhq;r;Qct!<3!!
!!)Zk!<<+Os+::7rrADSkQ&p,kQBTooCM>>!<<,sne2!'nc/[\nc/[\nc/[\!!)T\
!!)ld"S(j?0^S`$!13Za!!)rs!!*#u!W`6#rVlitrr3'#s8N)srr<&urr`?%!<3&u
rr<&,rrAD`kQ@`#s8W)^"l_(c9e<aLrrT,Je,AJ4aN3fLrTF7,pZMiM4<kaj2d]8V
kQ$tHrse\\qYKp6ahl$9ZaJ*Hr;Qct!<3!!!!)Zk!<<+Os+::7rrADSkQ&p,kQBTo
oCMkMr;Zigr;cZa!!)rf'*&%'!!)T\!!)T\!!)Qi!:o[\!;c6hna,?km/6&IQi-m^
!!3-"rW)rtrW!!!s8;rss8;ous8W&u"TSK%s8W#t[Jp5nr9+6\DZBb9kQZl!o^5L*
[/9k)rC225kQAoImf37L!7(?&#=L[!)C7=L9`4)SQi6ppp?h)%qYKj.`j2q`['R6`
r;Qct!<3!#!!*'!r;['%rr<'!!<;ut!<;rsK)^H&nG`KTn)sbsrTF@=0_4f$nGrUi
r:0U`%IjDunaQSZnGiRZnGiRcnHA@Ij=orukQ$s(rrAD`kQ@`#s8W)^#?>F:s6ic7
Zhsb'K0]D!"3AROs8D-]cM-N-6p)\4,r]1)r9+-IrVmD_dE^8<qXM81XgbpMZa6k5
s7u^#rr<'!rr<'!r;Zp!!!)or!<<+Os+::?rrADSkQ&p,kQBTonaZ&:!<<,rn,WLh
rpUEu!:TsgnF-DXn,NIXn,NIbn-&4Fj"TitkQ$s(rrAD`kQ@`#s8W)^!A]E/rr_^e
/$]$P!Mq=FkQAoImf37L!7(?&#=L[!)C7=L9`4)SQi6pp^q7(lqYK]l[^3NS['R*L
r;Qct!<3!"!!*&r!!<0#!<3!!!!)rs!<<+Os+::>rrADSkQ&p,kQBTonaZ,<!<<,p
n,WLhrpU!i!:]LU!!2TYquHT_"RkX90^S`$!1/H?!13WI"/g&:s8M3_0S03&"7T2<
YPnJ%UFQ6+"3AROs8D-]cM-N-6p)\4,r]1)r9+-IrVmDGZF.=9md7Ki\%9&TZa%aP
rrE*"rr3*$!<3$!r;Qct!<3!!!!)ut!<<+Os+::=rrADSkQ&p,kQBTonF4Qg"RbO6
0^S`$!1/H?!13WI"/g&:s8M3_94e&$"7T8>Y5\G%LHb\#"3AROs8D-]cM-N-6p)\4
,r]1)r9+-IrVmDTZa.!i_</54Yc=Y)Za/EbrrE*"rr3*$!<3$!r;Qct!<3!!!!*#u
!<<+Os+::<rrADSkQ&p,kQ0Hma6s/ukM\,^r9+-ILAq7?r9+6\DZBb9kQ6Mon,31j
nPq'?s8>K3rTF@)aR9*,kQ&p&kQaL<,8qje?VLC]!13Za&)=Cp['5AA^:^:pI$U\@
kPY>\!!*#u!rr?$s82iurr<&ts8Duus82kKs+::?rrADSkQ&p,kQ0Hma6EfjiS6-S
r9+-Irr;osmf*7err;osW;cjar9+6\DZBb9kQ9KgLAUuTnl@3>V^TaekQAoImf37L
!7(?&#=L[!)C7=L9`4)SQi6ppe?$9tV0:\Mj.pj*BS3JPK)^H&c2Rd1n)sbsrTFF@
5fDO8h9=^Zh:pPm5k"X7!13]b!!*#u!!)Bc!!&hp!13WI"/g&:s8M3as+)].qu6ik
=",kGs8D-`aN3fLrTF7,pZMiM4<kaj2d]8VkQ$tJrstZuh;PV\htlr+F]`<fG0Y^>
K)a*q!130<!7(Q,"5eQAX3&]kca@A;oDIePQi@!b!<3!"!<<)u!!3-"r;cisrW!'#
!<3&qs8E##rrAD`kQ@`#s8W)^"onF).ZjK)rrr7\-WBd>rTF@)aR9*,kQ&p&kQaL<
,8qje?VLC]!13Za%t:M;m^%,eoA,I;:L.7+Y(H\*s3:QDQga,<cMcr/jQM_!a=m]]
K_"d5kQ$tKrr<&urrN3#!<3!"!<3&urrN3#!<)p!!<3&rrr<&urr<&%rrAD`kQ@`#
s8W)^&-)\'I474"PEU5R.!G7_s8D-`aN3fLrTF7,pZMiM4<kaj2d]8VkQ$tJrst`K
FH`G;Y-3:[@=<0QNRNLZK)a*q!130<!7(N+"75OKo]Gi0q#9pgp@e1Fr9+-Irr;os
!WW2t!!3*"rr3'#rr<&urrN3#!;lcr!<2uu!3Z>%Qi-%LVf)P7roj=\#Ln2d.k3`*
d/F"CkQAoImf37L!7(?&#=L[!)C7=L9`4)SQ\,6hs1/.0Qga,<cF<!;Qi@!b!;uis
!;uis!<2uu!<3!%!!*$!rrDrr!!*#u!!'2%!13WI"/g&:s6AeMaN3fLrTF7,pZMiM
4<kaj2d]8VkQ$tGrs&JtnCb=moRd*ps2Y->Qga,<cF<!;Qi@!b!;uis!<3!"!<3&u
rr<&trriE&!<<'!r;Q`srr2ruY5\Kgr9+6\DZBb%kQAoImf37L!7(?&#=L[!)C7=L
9`4)SQi$dhrpAIln&MTRnc".?K)`sm!130<!7&(;!13]b!!)orrW!!!s8;ous8W&u
!rr9#rr;os!WW3!!3Q8$Qi-%LVf)P7lKA>kaR9*,kQ&p&kQaL<,8qje?VLC]!13T_
$MiW5bOEWV[E@q:K)^H&b5VI.n)sbs\**gYo)A[iQN$rOr9+3[DZAn@!Ug!dkQ&p&
kQaL<,8qje?VLC]!13T_$N8oDeaLP]Zan``K)^H&b5VI.n)sbs\**gYo)A[iQN$rO
r9+0ZDW]"@mf37L!7(?&#=L[!)C7=L9`4)SQhp^hi8r__`2p8N_T2>srrE*"K)^H&
rVlkan)sbsrTF=DhV7,FkLKRc"5DVfjS\3AQ\PM?Qi-%IVr[7Gs8D-]cM-N-6p)\4
,r]1)r9+-IqYpu_oC)=l\&-G3ZHhq;qu?Qoli6k_q>UHq!.t6&s8DrtQga,<cMcr/
hVaDea=m]]J)fPdkQ$s(rrAD`ki2X@kQ&p&kQaL<,8qje?VLC]!13T_%JJcWqY&@Z
_SsL#[Ee4<rrE*"kl1Y`!;6?m!!%WNK)bfL!130<!7(Q,"5JoZbfKedgi\Y<r9+-I
LAq7?g#rF]pZMiM4<kaj2d]8VkQ$tJrt"hjkhu=6oZY=\Zb3ZO\&nRJ!<<,ss8;rs
s8;ous8W#t"98B$!;lfp!!WE&!!*'!r;_HLK`;%=n)sbsrTF=<9?YBT!r^87qre$H
LAq7?g#rF]pZMiM4<kaj2d]8VkQ$tJrt!l3cID^en\)N9\%B&SZ`j<,!<<,trs/T)
s8N'!rr<&prr`<%rr<&srs/T)s8N'!rr<&srrE*"K)^Q)!130<!7(Q,!S]=-r5ng<
qXcK-r9+-ILAq7?g#rF]pZMiM4<kaj2d]8VkQ$tJrsuoW\&%q;n@?!6\[]#QZap#6
!<<,trs/T)s8N'!rr<&ss82iurr<&srsA`+s8N'!rr<'!s82kKs+UIQQga,<cMcr.
gbATFq#g9W0^S`$!1/H?!12C&!7(?&#=L[!)C7=L9`4)SQi6pp_m6\^oBu"TZa[NT
Za6p\r;Qct!;uj&!!*'!!!*$!!<)p'!!*'!!!*$!!;uj-!!*'!!!*$!!<3$!s8N'!
K)^Q)!130<!7(Q,!SfBLpB:3[l7hT&kQ$s(rrAD=kQ&p&kQaL<,8qje?VLC]!13Za
&(%Yg[FW1V\$E6<W33J4h>I9R!!)rs#QOl)rr<'!!!)ut#QOl)rr<'!!!)rs%fcV0
rr<'!!!*$!!<<'!!.t6)rrADSkQ&p,kQ0Hmde*V@!;Q3io^Cutm/6&IQ\PM?QeCR&
cM-N-6p)\4,r]1)r9+-IrVmD`Yd1X?Lto_WV1X/]Vn)!fs82its8W#trr;os!WW2t
!!3-"qu?cts8;p$s8N'!s8VusK)^Q)!130<!7(Q,!SfBfp&"gao`5$mq"4d^n)uIl
r9+-ILAq7?g#rF]pZMiM4<kaj2d]8VkQ$tJrt!V\]>17dh;%%dG$ep8Y3CQ<K)a*q
!130<!7(Q,!o,L&o(2q_!;#gd!!)Z`!!)fd!<<,poE=dRk:l9#kQ$s(rrAD=kQ&p&
kQaL<,8qje?VLC]!13Za&"TWSiN[L^qX]ek=D25gc@Z(Js3:QDQga,<cMcr/gbABm
p%&1a!:fX]!!*#i!rr>moDJXkoCDq^q""XZmH-+hr9+-ILAq7?g#rF]pZMiM4<kaj
2d]8VkQ$tJrssRXipO-seFVLW@o$B9<N^rRK)a*q!130<!7(Q,"5GU%oCqeV!!)KY
!<<-!nd>Etnc/[\nc/[\!!)fb"S(j?0^S`$!1/H?!12C&!7(?&#=L[!)C7=L9`4)S
Qi6ppT6k[DU2R3<IU-B1Ef#e)K)^H&c2Rd1n)sbsrTF@=0_=o2nc/[do)/Ogo)/Re
nc8^jrpg*j!:p!e!qH<kq!nRXm,]qfr9+-ILAq7?g#rF]pZMiM4<kaj2d]8VkQ$s$
s+:9]rrADSkQ&p,kQBToo()PF!<<,gnGrUirp^*k!:^$hr:'df!;Q'enE]-hm/6&I
Q\PM?QeCR&cM-N-6p)\4,r]1)r9+-IlMh!p:/=PBK)^H&ec,W9n)sbsrTF@=0_+]+
n,WLhnaHhb!:]IX!:]IX!;u<e!!)f`"RkX90^S`$!1/H?!12C&!7(?&#=L[!)C7=L
9`4)SQg4SR/2K(23.h0^s4.,LQga,<cMcr/gbA9goC)b\!;#^X!<)Eb!!;Wi!;Q$d
n*8pem/6&IQ\PM?QeCR&cM-N-6p)\4,r]1)r9+-IlMh,A2)Qj=Mi*CJK)^H&g&D&=
n)sbsrTF@=0_"SRmf`(Ci\9`skQ$s(rrAD=kQ&p&kQaL<,8qje?VLC]!13!N%kTXr
.:.^^F)(aTpo('eUk8Vus5<nWQga,<cMcr-gb?e;"RYC20^\f%!1/H?!12C&!7(?&
#=L[!)C7=L9`4)SQg4S]/N#C5Kp%U<C]FBg^qd:0K)^H&i;WeDn)sbsrTF:;0ZWG]
kMb2MmJQ/JQ\PM?QeCR&cM-N-6p)\4,r]1)r9+-IlMhAH2)Qb8P*0d"s7a@ij0=XB
s8E#prr<&_rr<%Ns,6mWQga,<cMcr1h*Ap8h;-<3"l7qb\j5`^kQ$s(rrAD=kQ&p&
kQaL<,8qje?VLC]!13!N%kTXr-\[_HE,5LJ_;jR\Nr/hV!;ZWp!9jF_!.t6/rrADS
kQ&p,kQB^kBrfA&"OFJfKCf$)!1/H?!12C&!7(?&#=L[!)C7=L9`4)SQg4S]/N#C5
Kp%U<C]F.Fj5[D)qu6]ts8W#t!WW3!!!WB&rrE*!rW!!!s8;rss8E!!s8W&uK)^i1
!130<!7(Q,"6A[.9?8dh5_S_#r9+-ILAq7?g#rF]pZMiM4<kaj2d]8VkQ$t7rsp\=
2(+*@P&OiVGJW>"Z&\_]!s&B$!<3!"!<3&urrE*"qu6]trrE&u!W`6#rr3$"rr@ZN
MuNdDn)sbsr9+7LnFQ;7p#l,Lo`Op]p$;P>!1/H?!12C&!7(?&#=L[!)C7=L9`4)S
Qg4S]/N#C5Kp%U*A7oGjj5[D)qu6`us8N)urrN3#!<2uu!<)rr!!3*"rr3!!s82it
rr@ZNMuNdDn)sbs\**gYLAq7?g#rF]pZMiM4<kaj2d]8VkQ$t7rsp\=2(+*@P%ncJ
B>W]hZ&\_]!s&B$!<3!"!<3&urr<&urr<&urrN3#!<3!"!<3&srr<%Ns,6mWQga,<
cF<!;Q\PM?QeCR&cM-N-6p)\4,r]1)r9+-IlMhAH2)Qb8P*0QqCM1NEj0=XArrW9$
rrE&u!W`6#rr2rurr2rurr3$"rrE&u!W`6#rr3$"rr@ZNMuNdDn)sbs\**gYLAq7?
g#rF]pZMiM4<kaj2d]8VkQ$t7rsp\=2(+*@P%ncJB>W]hZ&\b^rW!!!!<3!&!<<'!
!<3&ts8;ourrE&u!W`9#rW)rt!<<+Os,I$YQga,<cF<!;Q\PM?QeCR&cM-N-6p)\4
,r]1)r9+-IlMhAH2)Qb8P*0QqCM1NEj0=Vrs+::/rrADSkQ&o;kQ$s(rrAD=kQ&p&
kQaL<,8qje?VLC]!13!N%kTXr-\[_HC27Tt_W0[]Ne7:_s5<nWQga,<cF<!;Q\PM?
QeCR&cM-N-6p)\4,r]1)r9+-IlMhAH2)Qb8P*0QqCM1NEj0=Jns+::/rrADSkQ&o;
kQ$s(rrAD=kQ&p&kQaL<,8qje?VLC]!13!N%nfYm:ipu.AnPafOe88&m"57hs5<nW
Qga,<cF<!;Q\PM?QeCR&cM-N-6p)\4,r]1)r9+-IK)^H&\c2Yrn)sbs\**gYLAq7?
g#rF]pZMiM4<kaj2d]8VkQ$t7rrf`):J<_=s3Tt]s-<TaQga,<cF<!;Q\PM?QeCR&
cM-N-6p)\4,r]1)r9+-IlMgu<1G^I>oDd2$K)_,9!130<!7&(;!1/H?!12C&!7(?&
#=L[!)C7=L9`4)SQg4SV/N#C815h$IM"gqrk^ri"rrADSkQ&o;k_,;UkQ&p&kQaL<
,8qje?VLC]!13!N%kTXr.:.^^F)(aTpo('eV#LD@k^ri"rrADSkQ&n[k`P'/cM-N-
6p)\4,r]1)r9+-IlMhAH2)Qb8P*0d"s8Ibg^pA^ns3Tt]s-<TaQga,<c@Y8BkQ&s'
kQaL<,8qje?VLC]!13!N%kTXr-\[_HE,5LJ_;jR\NrK%ZkihpEqWInZki`!Hq<3G1
Q2^iNn)seud":JFkQ0)WpZMiM4<kaj2d]8VkQ$t7rsp\=2(+*@P&P4:pVGnMZ&\h`
!pJhJp?2JVki`!Hq<3G1Q2^iNmcX\sd":JHkQ0)Vp?2`L4<kaj2d]8VkQ$t7rsp\=
2(+*@P&P4:pVGnMZ&\h`!pJhJr9++\roa@_kl(PckQ'fHkii!G!U/bG!<23]!!2<I
rW)iZK)_,9!13*:K$KV+!71?%#=L[!)C7=L9`4)SQg4S]/N#C5Kp%U<@=*47j5[D)
rr3#_kktM\kQLtM!9iVHroa@_!;ks]!9aF^kQ1bJ!<20`!9aFYk^ri"rrAC;k^r$h
kQaL<,8qje?VLC]!13!N%kTXr-\[_H?=[\Z_rKd^NrK%[ki`$CkPtV^kPtV^kPtV]
kktJ^kQ(VG!<D?]!!29`q<3G1Q2^iNK'7gMo&p<H4<kaj2d]8VkQ$t7rsp\=2(+*@
P%ncJB>W]hZ&\h`!pJhJqWInZroa=^roa=^roa=^roaC`kQ(VG!W_Ear9++\q<3G1
Q2^iNK'7gMo&p<H4<kaj2d]8VkQ$t7rsp\=2(+*@P%ncJB>W]hZ&\h`!pJhJqre1`
kQ'i1!<20^!<20^!<20`!9aF^kQ1bJ!<20`!9aFYk^ri"rrAC;k^r$hkQaL<,8qje
?VLC]!13!N%kTXr-\[_HC27Tt_W0[]NrK%ZkihpE!U'O_kQV%NkPtVH!<)-[!!29`
roaC`kii!Groa@_!;ku3s-<TaQ\+FQkjmpB6p)\4,r]1)r9+-IlMhAH2)Qb8P*0Qq
CM1NEj0=XDs3Tt]s-<TaQ\+FQkjmpB6p)\4,r]1)r9+-IlMhAH2)Qb8P*0QqCM1NE
j0=XDs3Tt]s-<TaQ\+FQkjmpB6p)\4,r]1)r9+-IlMhAH2)Qb8P*0QqCM1NEj0=L@
s3Tt]s-<TaQ\+FQkjmpB6p)\4,r]1)r9+-IlMhAf:/4W-H$O"7B4[3tT8Dq6s3Tt]
s-<TaQ\+FQkjmpB6p)\4,r]1)r9+-IfDj4]K)_,9!1/<$K';dh#=L[!)C7=L9`4)S
Qg4SR[8'Lk2hM']s4.,LQ\+FQkjmpB6p)\4,r]1)r9+-IlMgu<1G^I>K)^H&ec,W9
K'7gMo&p<H4<kaj2d]8VkQ$t7rs1262(CA>MMd4As+::(rrAC;k^r$hkQaL<,8qje
?VLC]!13!N%kTXr.:.^^F)(aTpo('eUk8Vus5<nWQ\+FQkjmpB6p)\4,r]1)r9+-I
lMhAH2)Qb8P*0d"s8Ibg^pA]Gs+::/rrAC;k^r$hkQaL<,8qje?VLC]!13!N%kTXr
-\[_HE,5LJ_;jR\Nr8nW!<)ot!9X=[!.t6/rrAC;k^r$hkQaL<,8qje?VLC]!13!N
%kTXr-\[_HE,5LJ_;jR\Nr8nW!<)ot!9X:]!<2uu!.t60rrADQk^q*Ec2c2`kQaL<
,8qje?VLC]!13!N%kTXr-\[_HE,5LJ_;jR\Nr8nW!<)p!!<3&urrE-"rW!$"!!*#u
rW!!!s8;p!s8N)urr<&us8E#ts8E!!s8W&u!rr9#rr30&rrE'!s8W&u!WW3!!<3#t
!.t6\rrADRkQ/uUK'8K`!R]3dkQaL<,8qje?VLC]!13!N%kTXr-\[_HE++*;_;jR\
Nr8qS!!3*"rr36(rrE*!!<<'!r;QfurrE&u!W`6#rr3'#s8N)urrN3#!<)ot!<3!"
!<3&urrrK'!!*'!!<)ot!<3!"!<3%Ns0_k,Qga,=cd7:-PNW%pchHW.6p)\4,r]1)
r9+-IlMhAH2)Qb8P*0-^B4Sp?j0=XBrr<&trrN3#!<3!*!<3'!rrE*!!<<)t!!3*"
rr3!!s8;rss82iurr<&urr<&urrN3#!<3!"!<3&urr<&ts82iurr<%Ns0hq-Qga,<
cMcr.jPJYPg?7#cg&p*bhW4UuKU;W#j/2nWrTF7-pZMiM4<kaj2d]8VkQ$t7rsp\=
2(+*@P%ncJB>W]hZ&\b^!!)ut!W`6#rr3<*rrE*!!<<'!rrE&u!W`6#rr3-%rrE*!
!<2uu!;c]t!!*$!rr3$"rrE&u!W`6#rr2rurVlitqYpQr!.t6\rrADSkQ&p,kQB]"
N_@GI"$h@rir&!?Q\PM?Qi-%IVr_dsmf37L!7(?&#=L[!)C7=L9`4)SQg4S]/N#C5
Kp%U6CMRS"j5[D)r;Q`srVlp!rrE&u$3:)+s8N*!rrE'!rr3$"rrE&u!W`6#rr3'#
s8N)urr<&trrN3#!<3!"!<3&urrN3#!<2uu!<)ot!<2uu!<)ot!.t6\rrADSkQ&p,
kQBV#Fj.r,"5J$ZjS\3AQ\PM?Qi-%JVf(\t!m'g0rTF7,pZMiM4<kaj2d]8VkQ$t7
rsp\=2(+*@P%ncJB>W]hZ&\b^!!)ut!W`9#r;[0(!<<'!s8N*!s8;ourrE&u!W`6#
rVlp!s8W&u!WW3!!<3#t!<3#s!!3*"rVuis!WW3!!!3-"rW%QM\,QGpn)sbsrTF=<
9?YBT!r^87qre$HLAq7?r9+0ZDWq*&aN3fLrTF7,pZMiM4<kaj2d]8VkQ$t7rsp\=
2(+*@P%ncJB>W]hZ&XG9K)ad/!130<!7(Q,!S]=-r5ng<qXcK-r9+-Ig&D$PYQ"Th
r9+6\DZBb%kQAoImf37L!7(?&#=L[!)C7=L9`4)SQg4S]/N#C5Kp%U6CMRS"j5[D)
K)^H&i;WeDn)sbsrTF=<0`&ic"8)"8m/6&IQi-m^!:Bgb!;c]q!;?Hj!;c]q!9jF_
!9*qXQi-%LVf)P7lKA>kaR9*,kQ&p&kQaL<,8qje?VLC]!13!N%kTXr-\[_HC27Tt
_W0[]MLtk[s5<nWQga,<cMcr-gb?eC"SVBN0^S`$!13Za!!)<a!!)`m!!)`m!!)`m
!!)6_!!)!X!13WI"/g&:s6AeMaN3fLrTF7,pZMiM4<kaj2d]8VkQ$t7rsqat:/H%X
H"L]%AW`UWM<oioK)ad/!130<!7(Q,!SfB\o`5$mr:L'j!;c?ko^Cutm/6&IQi@!b
!;c`p!<3#t!!3-"rW!$"rrDoqrW!*$rrE*!rW)iq!!)rs!!*#u!<E0!!!WB&rrE*!
rW!!!s8;rss8E!!s8W&uj8T+Gr9+6\DZBb9kl(MdjGlnc0hmM^rVui["3AROs8D-]
cM-N-6p)\4,r]1)r9+-IK)^H&\c2Yrn)sbsrTF:;0]D^(!;c?h!!)ri!<<,ro`XpU
kV2B$kQ$tKrr<&rrr<&urrN3#!;ZWr!<3&rrr<&urrN3#!;uis!;ulq!<3!%!<3'!
rrE&u!<<,srrN3#!<3!"!<3&urrN3#!9*qXQi-%LVf)P7roamms8%d/12`GCGrR7-
q>^KnkQAoImf37L!7(?&#=L[!)C7=L9`4)SQg4SR[8'Lk2tR('k^rhmrrADSkQ&p,
kQ9Nnp$_MR!!)`brW)fe!<<,toDnplqXap^mcQ:jr9+-Irr2ruqu6Wrrr3$"rrDus
r;Zlu!;lcr!<3!$!<3'!s8;rqrr<&qrr<&urr<&urr<&ts8;ourrE&u!<E/t!!3*"
iVrnEr9+6\DZBb9kQV"bCaao+rVm&sRkJ+Es8D-`aN3fLrTF7,pZMiM4<kaj2d]8V
kQ$t7rral/1FY<Ts4Z[gs,6mWQga,<cMcr/gbABmmdgGZ!;Z3h!!)Tj!<2Tf!!2]_
quHTb"S1sB0^S`$!13]b!!)or!!*#u!W`6#rVlitrr3$"rrDrr!!*#u"9AH%rrE&u
!!)rs!!)lq!!*#u!!*#u!!*#u!!*#u!W`6#rr3$"rrDus!!)!X!13WI"/g&:s8M3b
s,ABV\GH4-`A)rDrTF@)aR9*,kQ&p&kQaL<,8qje?VLC]!13!N#V@nk.Pcp>MMV$,
g?=.gMuNdDn)sbsrTF@=0_=o&nc8^jqskC#!:g*io'ub\o'ub\nc/[\nc/[dnc\LL
jY6'!kQ$tJrr<&srr<&urrN3#!<)ot!<3!#!<<'!r;Q`srr3*$rrE'!rr30&s8N*!
rrDrr"T\Q&s8N)urr<&urr<&urrN3#!<3!"!<3&urrN3#!9*qXQi-%LVf)P7roaOF
/;$YJ[eg"*W%$3okQAoImf37L!7(?&#=L[!)C7=L9`4)SQg4S]/N#C7?A4)SCB+>/
W2?Gfrr:^9K)^c/!130<!7(Q,"5GU%oDA+W!!)Tg!;Z0c!;uC$!!)Qi!:o[\!:o[\
!:g*io'ub\qXOdZm,]qfr9+-Ir;Z]q!WW3!!<3#t!!3-"r;cisr;Zlus8E!$s8N*!
s8;p#s8N*!s82itrrE&u"p"]'!!*$!rVufr!WN0!rrN3#s8E#trrE*"j8T+Gr9+6\
DZBb9kQZl!o^5L*[/9k)rC225kQAoImf37L!7(?&#=L[!)C7=L9`4)SQg4S]/N#C5
Kp%U<C]FBg^qd:0rr;$B!W_EaqriY3MuNdDn)sbsrTF@=0_4f$nGrUir:0U`%IjDu
naQSZnGiRZnGiRcnHA@Ij=orukQ$s(rrAD`kQ@`#s8W)^#?>F:s6ic7Zhsb'K0]D!
"3AROs8D-]cM-N-6p)\4,r]1)r9+-IlMhAH2)Qb8P*0d"s7a@ij0=XDrrM?Ir;c*G
!W_EaqriY3MuNdDn)sbsrTF@=0_+]$n,WLhqX=Lc!<2Hu!!)Kg!:]IX!:TsgnF-DX
qX=XVlJjSbr9+-ILAq7?r9+6\DZBb9kQ*Gnrr3)h;(JpLrrJrHrTF@)aR9*,kQ&p&
kQaL<,8qje?VLC]!13!N%kTXr-\[_HE,5LJ_;jR\NrK%[ki`$GkPtVJkQ1bJ!;ku3
s,6mWQga,<cMcr/gbA9gnF-GY!;Q$a!!*#f!rr>jnGE7enF6>UqX=XVlJjSbr9+-I
LAq7?r9+6\DZBb9kQ*AgrVluh;C\mKrrJlErTF@)aR9*,kQ&p&kQaL<,8qje?VLC]
!13!N%kTXr-\[_HE,5LJ_;jR\NrK%[ki`$GkQ1bJkl(P`ki`$GkQV%N!9aFHkl(Pb
ki`$1!;ku3s,6mWQga,<cMcr/gbA6eamTB#l/FD`r9+-ILAq7?r9+6\DZBb9kQ+=f
r;Qlg<%>'MrrIm=rTF@)aR9*,kQ&p&kQaL<,8qje?VLC]!13!N%kTXr-\[_HE++*;
_;jR\NrK%[ki`$GkPtV\kQ1bJ!<20d!9aC_ki`$GkQCnL!9aF[k^rhmrrADSkQ&p,
kQ0Hma6s/ukM\,^r9+-Ig&D$PgA_3SrrCaP!13WI"/g&:s8M3`LGA8qrs/'o.]i[K
89Xsq"3AROs8D-]cM-N-6p)\4,r]1)r9+-IlMhAH2)Qb8P*0-^B4Sp?j0=XDrrM?I
r;ci\r;[)dkQ'fHki`$GkPtV^kQCnL!9aF[k^rhmrrADSkQ&p,kQ0Hma6EfjiS6-S
r9+-Ir;Z]qmJm+bqYpNqpAb'kl2LebrrCaP!13WI"/g&:s8M3`gF@sTrs&$p.B99o
bPgW,aN3fLrTF7,pZMiM4<kaj2d]8VkQ$t7rsp\=2(+*@P%ncJB>W]hZ&\h`!pJhJ
r9++\roaUfki`$1!9iVHroa=^roaIbkQ'fHqriY3MuNdDn)sbsrTFF@5fDO8h9=^Z
h:pPm5k"X7!13Za!!)<a!!)`m!!)`m!!*#u!!)<a!W`6#g&D&=r9+6\DZBb9kQCj9
/%,9S"nPeE0m*HokQAoImf37L!7(?&#=L[!)C7=L9`4)SQg4S]/N#C5Kp%U6CMRS"
j5[D)rr3&`kQ(PE!!*#^!!*#^!!*#^!!*#^!!*#^"9@WckQ(MDK)^c/!130<!7(Q,
"5eQAX3&]kca@A;oDIePQi@!b!;c`p!<3#t!!3-"rW!$"rrDoqrW!*$rrE*!rW)iq
!!*#u!W`9#rW!$"rrE&u"p"Z'rrE*!rW!*$rrE'!g&D&=r9+6\DZBb9kQV"_>q1s3
rVm&tO=+!$s8D-`aN3fLrTF7,pZMiM4<kaj2d]8VkQ$t7rsp\=2(+*@P%ncJB>W]h
Z&\h`!pJhJqrmtYroa=^roa=^rTO4\"R,%LkQ(MDK)^c/!130<!7(Q,"6A[.9?8dh
5_S_#r9+-Irr2ruqu6Wrrr3$"rrDlp!W`6#qu6Wrrr3$"rrDus!!)rs!!*#u!!)rs
!W`6#rr30&rr<'!rrE&u"9AH%rrCaP!13WI"/g&:s8M3ms8Ve@.6;U8PB]2<G4bh7
rTF@)aR9*,kQ&p&kQaL<,8qje?VLC]!13!N%kTXr-\[_HC27Tt_W0[]NrK(LkPtVJ
k^rhmrrADSkQ&p+kQC2@oCV2<kP5&L"8;H]lhorHQi@!b!;lcr!<3!"!<3&ss8;ou
rrDrr!!*#u"9AH%s8W#tr;Z]qrr;os#QOf(rrE*!!<2uu!<3!$!<3'!!87APQi-%L
Vf)P7roj=\#Ln2d.k3`*d/F"CkQAoImf37L!7(?&#=L[!)C7=L9`4)SQg4S]/N#C5
Kp%U6CMRS"j5[D)rr;QQ!!)<JK)^c/!130<!7&(;!13]b!!)or!!*#u!W`6#rVlit
rr3$"rrDrr!!*#u"9AH%rrE&u!!)rs!!)rs!!*#u#QXo)!<3'!rrE&u!!*#u"9AH%
rrCaP!13WI"/g&:s6AeMaN3fLrTF7,pZMiM4<kaj2d]8VkQ$t7rsp\=2(+*@P%ncJ
B>W]hZ&8P\g?=.gMuNdDn)sbs\**gYrVlitr;Q`srr3$"rrE#t!!*#u!s&B$!;uis
!<3!$!<3'!!<3!&!<<'!s8N)srr<&urr<&urr<&urr<&urr<&urr`?%!<3&PrrAD`
kQ@`#s8VBJ"3AROs8D-]cM-N-6p)\4,r]1)r9+-IlMhAf:/4W-H$O"7B4[3tT8Dq6
s4Z[gs,6mWQga,<cF<!;Qi-m^!!3-"rW)rtrW!!!s8;rss8;ous8W&u"TSK%s8W#t
"onT&s8N)rs8;rsrr<&urr<&ts8E!$s8N*!!87APQi-%LVf)P7lKA>kaR9*,kQ&p&
kQaL<,8qje?VLC]!12=;g?=.gMuNdDn)sbs\**gY_#FB7aSu7,r9+3[DZAn@!Ug!d
kQ&p&kQaL<,8qje?VLC]!13Q^#6+Defso,qK)^H&a8Z.+n)sbs\**gY_#FB7aSu7,
r9+0ZDW]"@mf37L!7(?&#=L[!)C7=L9`4)SQi$dhrpAIln&MTRnc".?K)`sm!130<
!7(Q,!p&4mjP&eIrn7J/gtq,ikQ$s(rrAD`kQ%OAmK!:ckQ&p&kQaL<,8qje?VLC]
!13T_$MiW5bOEWV[E@q:K)^H&b5VI.n)sbsrTF@?i/UIO0EXRij5U"#!1/H?!13WI
irAu@!7(?&#=L[!)C7=L9`4)SQi$dirSZben&MT;\_-\/s+:9nrrADSkQ&p,kQBV#
Fj.r,"5J$ZjS\3AQ\PM?QeCR&cM-N-6p)\4,r]1)r9+-IqYpo\jkK:CXKo1La7Y&a
K)a$o!130<!7(Q,!o-Gla8Q/=b"MWq!1/H?!12C&!7(?&#=L[!)C7=L9`4)SQhp^j
iUcO1a1&q2aKj+[rVZ]n!:0Xe!!*'!quD?KK)bQE!130<!7(Q,!S]=-r5ng<qXcK-
r9+-ILAq7?g#rF]pZMiM4<kaj2d]8VkQ$tHrse\\qYKp6ahl$9ZaJ*Hr;Qp#!<<'!
!9sLa!!%WNK)bEA!130<!7(Q,!o,L+a8#i0mP+#*kQ$s(rrAD=kQ&p&kQaL<,8qje
?VLC]!13Za&,,DSi;3<Bbf6rp]X5#Sao)/D!!*'!!!*'!r;Zlus82lrs8;p$rr<'!
!!)orr;_HLK)bcK!130<!7(Q,!SfBLpB:3[l7hT&kQ$s(rrAD=kQ&p&kQaL<,8qje
?VLC]!13Za&)5LWeGB%3]t1>T]="uOYPeD9!!*'!!!*$!!<<'!!<3$!s8N'!rr<&t
rr`<%rr<&srriB&s8N'!K)^H&rVlkan)sbsrTF:;0[fUp!!)fe"SD0H0^S`$!1/H?
!12C&!7(?&#=L[!)C7=L9`4)SQi6pp^q7(lqYK]l[^3NS['R*Lr;ZZp!WW2s!!iN(
!<<'!!<;ut#64]'!<3$!r;Qp#!<<'!!.t6&s8DrtQga,<cMcr-gb@^[quHKa!<<,p
o`XpUkV2B$kQ$s(rrAD=kQ&p&kQaL<,8qje?VLC]!13Za&&Y]\]CYIX\$NQT\$NEG
bl%JA!!)rs!<<,trs&N(s8N'!s8W#t"oeQ&rr<&srriB&s8N'!K)^H&rVlkan)sbs
rTF=<0_P#/!<<,koE>3po^i+`q"+Re!;Q0hoBtcqm/6&IQ\PM?QeCR&cM-N-6p)Y3
,r]1)r9+-IrVmDTZa.!i_</54Yc=Y)Za/EbrrE*"r;Qct!;uj#!!*'!!!)ut#64c(
!!*$!!;uj#!!*'!!!%WNK)bfL!130<!7(Q,"5GU&o_%eV!!)Q\!<<-!o)esmoCMn\
"7u*a!;Q-go'PQnm/6&IQ\PM?QeCR&cM-N-6p)Y3,r]1)r9+-IrVmD`Yd1X?Lto_W
V1X/]Vn)!grrE*"qu?Qo!<;rs!WW2u!!WE&!!*'!qu?cts8;qLs+::KrrADSkQ&p,
kQBTooCM_I!<<,gnc8^jrpgEs!:g*io'ub\nc/[bnc\LLjY6'!kQ$s(rrAD=kQ&p&
kQaL<+rVad?VLC]!13Za&(I\m^nl51guG2R?YG(pl0eQP!!%WNK)aj1!130<!7(Q,
"5GU%oD%kV!;c9b!!)Tg!<)Hh!!*#h!WW5kqZ$]g!!)fb"S(j?0^S`$!1/H?!12C&
!7(?&#=LZu)C7=L9`4)SQi6ppSYt<&Z#nn"o8n)sBOl;3mf*:f!.t6&s5O%YQga,<
cMcr/gbA<ip[J7a!:TFY!!*#g"98Gl!!)re!<<,pnHA@Ij=orukQ$s(rrAD=kQ&p&
kQaL<+rVad?VLC]!13Za%t:M;m^%,eoA,I;:L.7+Y(H\*s3:QDQga,<cMcr/gbA9g
p$_t^!:fOb!!)NX!!)NX!!)rd!<<,pn-&4Fj"TitkQ$s(rrAD=kQ&p&kQaL<+rVad
?VLC]!13Za&"e2jPG2uuYC9bcI<(1(dt7UOs3:QDQga,<cMcr/gbA9goC)b\!;#^X
!<)Eb!!;Wi!;Q$dn*8pem/6&IQ\PM?QeCR&cM-N-6p)Y3,r]1)r9+-IK)^H&\c2Yr
n)sbsrTF@=0_"SRmf`(Ci\9`skQ$s(rrAD=kQ&p&kQaL<+rVad?VLC]!13!N"LV!#
9K.S'K)aC$!130<!7(Q,!SfBLmf`%@i@sZskQ$s(rrAD=kQ&p&kQaL<+rVad?VLC]
!13!N"=u>b.6)qZK)aC$!130<!7(Q,!SfBLl3-;/gbA-nkQ$s(rrAD=kQ&p&kQaL<
+rVad?VLC]!13!N#V@nk.Pcp>MMQlaK)aO(!130<!7(Q,"l2G^hVI#3h?D`if=F69
r9+-ILAq7?g#rF]pZMiM4<b[i2d]8VkQ$t7rsp\=2(;jcKl_#/s7iOiVPJhDK)ad/
!130<!7(Q,"5eQAX3&]kca@A;oDIePQ\PM?QeCR&cM-N-6p)\4,r]1)r9+-IlMhAH
2)Qb8P*0d"s8Ibg^pA]Gs+::/rrADSkQ&p,kQBo0O\<bL"$hP1o_dnQQ\PM?QeCR&
cM-N-6p)\4,r]1)r9+-IlMhAH2)Qb8P*0d"s7a@ij0=XBs8E#prr<&_rr<%Ns,6mW
Qga,<cMZl.m-sW=k4Rp4rq-Bep@[bLkQ$s(rrAD=kQ&p&kQaL<,8qje?VLC]!13!N
%kTXr-\[_HE,5LJ_;jR\Nr/hV!;ZWp!9jF_!.t6/rrADSkQ&o;kQ$s(rrAD=kQ&p&
kQaL<,8qje?VLC]!13!N%kTXr-\[_HE,5LJ_;jR\Nr/hX!<<)t!!3-"rW!-%!<3'!
s8E!!s8W#trr;rt!WW3!!.t61rrADSkQ&o;kQ$s(rrAD=kQ&p&kQaL<,8qje?VLC]
!13!N%kTXr-\[_HE++*;_;jR\Nr/hY!<<'!rr3$"rrE&u!<<,srrN3#!<3!"!<3&u
rrN3#!.t6/rrADSkQ&o;kQ$s(rrAD=kQ&p&kQaL<,8qje?VLC]!13!N%kTXr-\[_H
?=[\Z_rKd^Nr/hY!<<'!rr3$"rrE&u!!)utr;Zlu!<3!!!<;rs!WN.Os,6mWQga,<
cF<!;Q\PM?QeCR&cM-N-6p)\4,r]1)r9+-IlMhAH2)Qb8P*0QqCM1NEj0=XArrW9$
rrE&u!W`6#rr2rurr2rurr3$"rrE&u!W`6#r;Q`sK)^c/!130<!7&(;!1/H?!12C&
!7(?&#=L[!)C7=L9`4)SQg4S]/N#C5Kp%U6CMRS"j5[D)qu6`us8N)urrN3#!<2uu
!<2uu!<3!"!<3&urrN3#!<3!"!<3%Ns,6mWQga,<cF<!;Q\PM?QeCR&cM-N-6p)\4
,r]1)r9+-IlMhAH2)Qb8P*0QqCM1NEj0=XBs8E!!rrE&u"p"]'!!*$!rVufr!WN0!
rrN3#s8E#trrE*"K)^i1!130<!7&(;!1/H?!12C&!7(?&#=L[!)C7=L9`4)SQg4S]
/N#C5Kp%U6CMRS"j5[D)K)^H&i;WeDn)sbs\**gYLAq7?g#rF]pZMiM4<kaj2d]8V
kQ$t7rsp\=2(+*@P%ncJB>W]hZ&XG9K)ad/!130<!7&(;!1/H?!12C&!7(?&#=L[!
)C7:K9`4)SQg4S]/N#C5Kp%U6CMRS"j5[D%K)^H&i;WeDn)sbs\**gYLAq7?g#rF]
pZMiM4<kaj2IB/UkQ$t7rsqat:/H%XH"L]%AW`UWM<oioK)ad/!130<!7&(;!1/H?
!12C&!7(?&#=L[!)C7:K9`4)SQ\,6hs1/.0Qga,<cF<"jQeCR&cM-N-6p)\4,rT+(
r9+-IlMh!p:/=PBK)^H&ec,W9n)sbsK'8?\!7(?&#=L[!)C7:K9`4)SQg4SR/2K(2
3.h0^s4.,LQga,<c@Y8BkQ&s'kQaL<,8qjd?VLC]!13!N#V@nk.Pcp>MMQlaK)aO(
!130<!RK,Ek`b32dEhRN#=L[!)C7:K9`4)SQg4S]/N#C7?A4)SCB+>/W2?GfK)^H&
i;WeDmcX\sd":JHkQ0)Vp?2`L4<kaj2IB/UkQ$t7rsp\=2(+*@P&P4:reA5(Z\3r1
K)ad/!13*:K$KV+!71?%#=L[!)C7:K9`4)SQg4S]/N#C5Kp%U<C]F.Fj5[D)r;ZZp
qYpNqkl1V_K)^i1!1/<$K';dh#=L[!)C7:K9`4)SQg4S]/N#C5Kp%U<C]F.Fj5[D)
r;Q`spAY*mkl1V_K)^i1!1/<$K';dh#=L[!)C7:K9`4)SQg4S]/N#C5Kp%U<C]F.F
j5[D)r;Q`sr;Q`srr3!!s8E!%rrE'!s8W&u!WW2u!<3#t!!3-"rW%QMO8f3HK'7gM
o&p<H4<kaj2IB/UkQ$t7rsp\=2(+*@P&OiVGJW>"Z&\b^r;cis"T\Q&s8N)urrE*"
qu6]trrE&u!W`6#rr3$"rr@ZNNW0!FK'7gMo&p<H4<kaj2IB/UkQ$t7rsp\=2(+*@
P$V[3AAdHfZ&\b^!!)lq!!*#u!!*#u!!)utr;Zlu!<3!!!<;rs!WN.Os,I$YQ\+FQ
kjmpB6p)Y3,rT+(r9+-IlMhAH2)Qb8P*0QqCM1NEj0=XBrr<&qrr<&urr<&urr<&u
rr<&urrN3#!<3!"!<3&srr<%Ns,I$YQ\+FQkjmpB6p)Y3,rT+(r9+-IlMhAH2)Qb8
P*0QqCM1NEj0=XBrr<&rrriE&!<<'!rr2rurr2rurr3$"rrE&u!W`6#rr3$"rr@ZN
NW0!FK'7gMo&p<H4<b[i2IB/UkQ$t7rsp\=2(+*@P%ncJB>W]hZ&\b^qu?ct!<3!&
!<<'!!<3&ts8;ourrE&u!W`9#rW)rt!<<+Os,[0[Q\+FQkjmpB6p)Y3,rT+(r9+-I
lMhAH2)Qb8P*0QqCM1NEj0=Vrs+::/rrAC;k^r$hkQaL<+rVac?VLC]!13!N%kTXr
-\[_HC27Tt_W0[]Ne7:_s5<nWQ\+FQkjmpB6p)Y3,rT+(r9+-IlMhAH2)Qb8P*0Qq
CM1NEj0=Jns+::/rrAC;k^r$hkQaL<+rVac?VLC]!13!N%nfYm:ipu.AnPafOe88&
m"57hs5<nWQ\+FQkjmpB6p)Y3,rT+(r9+-IK)^H&\c2YrK'7gMo&p<H4<b[i2IB/U
kQ$s$s+:9]rrAC;k^r$hkQaL<+rVac?VLC]!1/<;K)`C]!1/<$K';dh#=LZu)C7:K
9`4)SQ\,6hs1/.0Q\+FQkjmpB6p)Y3,rT+(r9+-IK)^H&\c2YrK'7gMo&p<H4<kaj
2IB/UkQ$s$s+:9]rrAC;k^r$hkQaL<,8qjd?VLC]!1/<;K)`C]!1/<$K';dh#=L[!
)C7:K9`4)SQ\,6hs1/.0Q\+FQkjmpB6p)\4,rT+(r9+-IK)^H&\c2YrK'7gMo&p<H
4<kaj2IB/UkQ$s$s+:9]rrAC;k^r$hkQaL<,8qjd?VLC]!1/<;K)`C]!1/<$K';dh
#=L[!)C7:K9`4)SQ\,6hs1/.0Q\+FQkjmpB6p)\4,rT+(r9+-IK)^H&\c2YrK'7gM
o&p<H4<kaj2IB/UkQ$s$s+:9]rrAC;k^r$hkQaL<,8qjd?VLC]!1/<;K)`C]!1/<$
K';dh#=L[!)C7:K9`4)SQ\,6hs1/.0Q\+FQkjmpB6p)\4,rT+(r9+-IK)^H&\c2Yr
K'7gMo&p<H4<kaj2IB/UkQ$s$s+:9]rrAC;k^r$hkQaL<,8qjd?VLC]!1/<;K)`C]
!1/<$K';dh#=L[!)C7:K9`4)SQ\,6hs1/.0Q\+FQkjmpB6p)\4,rT+(r9+-IK)^H&
\c2YrK'7gMo&p<H4<kaj2IB/UkQ$s$s+:9]rrAC;k^r$hkQaL<,8qjd?VLC]!1/<;
K)`C]!1/<$K';dh#=L[!)C7:K9`4)SQ\,6hs1/.0Q\+FQkjmpB6p)\4,rT+(r9+-I
K)^H&\c2YrK'7gMo&p<H4<kaj2IB/UkQ$s$s+:9]rrAC;k^r$hkQaL<,8qjd?VLC]
!1/<;K)`C]!1/<$K';dh#=L[!)C7:K9`4)SQ\,6hs1/.0Q\+FQkjmpB6p)\4,rT+(
r9+-IK)^H&\c2YrK'7gMo&p<H4<kaj2IB/UkQ$s$s+:9]rrAC;k^r$hkQaL<,8qjd
?VLC]!1/<;K)`C]!1/<$K';dh#=L[!)C7:K9`4)SQ\,6hs1/.0Q\+FQkjmpB6p)\4
,rT+(r9+-IK)^H&\c2YrK'7gMo&p<H4<kaj2IB/UkQ$s$s+:9]rrAC;k^r$hkQaL<
,8qjd?VLC]!1/<;K)`C]!1/<$K';dh#=L[!)C7:K9`4)SQ\,6hs1/.0Q\+FQkjmpB
6p)\4,rT+(r9+-IK)^H&\c2YrK'7gMo&p<H4<kaj2IB/UkQ$s$s+:9]rrAC;k^r$h
kQaL<,8qjd?VLC]!1/<;K)`C]!1/<$K';dh#=L[!)C7=L9`4)SQ\,6hs1/.0Q\+FQ
kjmpB6p)Y3,r]1)r9+-IK)^H&\c2YrK'7gMo&p<H4<b[i2d]8VkQ$s$s+:9]rrAC;
k^r$hkQaL<+rVad?VLC]!1/<;K)`C]!1/<$K';dh#=LZu)C7=L9`4)SQ\,6hs1/.0
Q\+FQkjmpB6p)Y3,r]1)r9+-IK)^H&\c2YrK'7gMo&p<H4<b[i2d]8VkQ$s$s+:9]
rrAC;k^r$hkQaL<+rVad?VLC]!1/<;K)`C]!1/<$K';dh#=LZu)C7=L9`4)SQ\,6h
s1/.0Q\+FQkjmpB6p)Y3,r]1)r9/a!JsXNElMlJ"K'<$o#=LZu)C7=L9S2J[kecQK
s+9HdkkXEI6p)Y3,r]1)K'7gM_W^:bK'7gMq</&O4<b[i2IB.0k^r$8kkb;\n"3GU
5QXKCkPG41k^r$okQaL<,8qjd?VH(8K':)8qu6bR(gsQH^BD#Z(jPfQs+9HdkkXEI
6p)\4,rT+(K'7gM_W^su"4oMWp\FgjLG6dIs+9HdkkXEI6p)\4,rT+(K'7gM_W_"!
#,a/qs-/5%qYpWK3/@M5K'7gMq</&O4<kaj2IB.0k^r$8kR%:hk:#g!s#^9Dq#:F]
^]4=ck^r$okQaL<,8qjd?VH(8K':)8"98Bl\,QC/49.M=rr_.,p]#j/K'<$o#=L[!
)C7:K9S2J[kecNbs.<]trrP:_4SSjWLNriNk^r$okQaL<,8qjd?VH(8K':)8!rj,#
rVls^!'Gu7,lj_;rrF8"K'7gMq</&O4<kaj2IB/UkQ9i%gOe/:g4IlAeH*EMr;QaZ
rW!'`,ldq?r;QeBLP"`AkkXEI6p)\4,rT+(r9+7>i/UH^0S2"%0EHZQr;R$b!!';(
o/m"!r;Qf,8:p&WkkXEI6p)\4,rT+(r9+7<NciQts+:9orrHN"r;Qg\!'L8\"/>hr
bl.PBa#J\7K'<$o#=L[!)C7:K9`4)Uge5hBrdt-lrW--!r;Qg\!'L8\"3^`Fbl.PB
h]RO7K'<$o#=L[!)C7=L9`4)TgG&X)K):/sbkhESQi-jb49.MCrr^IF!6kEA!P^mO
k^r$okQaL<,8qje?VLC]!o,L+K)(#ob4u'nGl7RC49-],rr[rT-0G1+!O#=Ok^r$o
kQaL<,8qje?VLC]!SfA\pO`.]pAr;or;R$b!!#m?UEon;r;Qe*T7Z9YkkXEI6p)\4
,r]1)r9+1:0S8ulo`5$me+E_A!;6$a!8@)H!!'b+!rj\#rVls^!+R>S!!+D!rVlrn
)"3(?K'<$o#=L[!)C7=L9`4)TgbA!cquH-W!<<,To`5$mrq-9l!8$lE!!)W`!<<,[
o`5$mp@SFd!8-rF!!)W`!<<-!o`5$me+EeB^Hhbt#F'qWk&`_-k5>5\BUAaNk^r$o
kQaL<,8qje?VLC]!o,L&lgt2X!9s+V!!(gH!<<,JoDnple+<Y@!;?$c!!([D!<<,k
oDnplht-pL!:oaas8Qc!o)Ag43<0#1k^r$okQaL<,8qje?VLC]"5GU&o^)/M!!)rg
"TSPo!;#g\!<2Tg!!2]_r;ZlioDJ[eo*YNuo)S@^!;#d^!;$*gqXaXc"7lKmoDARg
oDSahoDJ[doDJXqoCDq^oCDq^oCMn\$hF>uo)Jd^o)Jd^oDJXlo)Jd^oDJXioCMk[
r::F!!:p3^!!)W^!!)Tj!;#g\!;uHf!!`#p!:p3^oDJXioCMk[!;$0iqt'ad!V>p]
!!Vuc!!)W^r;cigr;Zihr;Zul!!)W^r;ZlioDAUWo)Sgko^`4cs7[r!o`#'_0\?@)
K'7gMq</&O4<kaj2d]8VkQBTooCM>>!<<,to)/Omnc/[\nc/[fncSpmnc/[hnc]!n
o'ub\rUTme%IsK!o'ub\nc/[\nc/[enc8^jrpg^&!:g*io'ub\o'ub\nc/[\nc/[g
ndb^#o'ub\nc/[\nc/[\!!)ug$NL1t!!)T\!!)Qi!<)I!!!)Qi!:o[\!:g*io'ub\
rUTme&Fof$o'ub\nc/[\!!)T\!!)ug!rr>lo)/P#nc/[\nc/[\!!)T\!!)T\!!)ug
!<<,une(p&o'ub\nc/[\!!)T\!!)Qi!<)Hh!!*#h%fcV#!!)T\!!)Qi!:o[\!:KCY
!!)``rr3&G.$sZ-!k0Serr7T6K'<$o#=L[!)C7=L9`4)VgbA?km.(/W!;uBg!!*#h
qZ$Zfo)&Ihnc/[ho(rFcnc8^jrpgKu!:o[\!:g*io'ub\o)/Oinc/[hndPR!nc/[\
nc/[\nc/[\qZ-TcqZ$Zfo)/Ojo'ub\rUL6p!:g*io'ub\o)/P#o'ub\nc/[\nc/[\
!!)T\!!)ug!<<-!nd,9ro'ub\nc/[\qZ-Tc"TSPnnc/[hndkd$o'ub\nc/[\nc/[\
nc/[go)/Oho()YX"7cElo(rCgnc/[gnc8^jrpgR"!:g*io'ub\nc/[\nc/[go)/Og
o)/Ranc/[ao)8Rjmq=]4qYpZ\?qBJZs+9HdkkXEI6p)\4,r]1)r9+7<0_4f$nGrUi
r:'df!<2Kh!!)re#QOkpnGiRZ!!*#g!<<,qnGrUirp^Bs!:fRZ!:^$hnaQSZqsa[e
!<2L!!!)Nh!:fRZ!:fRZ!:^$hq=+Ic!;l<b!!Dc]!!)uf$31(r!!)QZ!!)QZr;[E!
!!)Nh!:fRZ!:^$hnaQSZrUBmg!<2Kr!!)QZ!!)Nh!:^$hq=+Ug!:fRZ!<2L"!!)QZ
!!)Nh!:fRZ!:fRZ!;uBc!!;Zj!;u?i!!)Nh!;u?f!!)uf!<<-!nIGU"nGiRZnGiRZ
!!)QZ!!)HW!<<,nnb`=na!`WkLVJn"5T$-js+9HdkkXEI6p)\4,r]1)r9+7<0_+]"
n,WLhr9s^e!<2Hg!!)rd#QOkon,NIX!!*#f!<<,qn,WLhrpU<r!:]IX!:TsgnF-DX
qsXUd!<2Hu!!)Kg!:]IX!:]IX!:Tsgq="Cb!;u<l!!)NX!!)Kg!<)Bm!!)Kg!:]IX
!<)C"!!)Kg!:TsgnF-DXn,NIXn,NIen,WLhrpU9q!:]IX!:Tsgn,NIan-&dlnF-DX
rpUI!!:]IX!:TsgnF-DXnF-DXqX=Uf!:Tsgr9sgh!:Tsgr9s^e!<)Bf!!*#f%fcV!
!!)NX!!)Kg!:]IX!:]IY!!)Z\q>UZFIs=4tJ%tgZK'7gMq</&O4<kaj2d]8VkQBTo
naYr7qu?ff!!)uequ?cenGE7enF6DW!V#UV!<)Bf!!)uequ?rj!!)NX!!)lbrW!Ju
!!)Kg!:]IX!:]IX!:]LU!;u?a!!r&o!:]IX!:]LV!!Mck!:]LU!!)Ne!!Vl]!!)NX
r;[)ln,NIXn,NIen,WLhrUB^b"RlBknF6>UrU9sj!:]IX!<)Ec!"8;c!!)NX!!)NX
!!)uer;cidqu?lh!!)NXqu?cenGN=fnF6DW"RlBknF6AV#Oq3_!:]IX!:oU[!!)3O
"RkX90^ODTK';dh#=L[!)C7=L9`4)VgbA6eK("<[_!_Eol/FD`K'7gMo&p<H4<b[i
2d]8VkQ0HmK("<[^@)3lkM\,^K'7gMo&p<H4<b[i2d]8VkQ0HmK'IsQ^?PjaiS6-S
K'7gMo&p<H4<b[i2d]8VkQTd-`89>+K&2+9_qkRQgXj#%mt0bTkjmpB6p)Y3,r]1)
r9+7?IVGj7d"9W[cih\&AqT],k^r$hkQaL<+rVad?VLC]"6A[.97ejL0Y]:D5_S_#
K'7gMo&p<H4<b[i2d]8UkQC2@oCRY-iUqftj7rWH"8;H]l[n>PkjmpB6p)Y3,r]1)
K'7gMK'7gMUZ_qN4<b[i2d]71k^r#Mk^r#nkQaL<+rVad?VH(8K'7gMK'8un#=LZu
)C7=L9S2J[k^r#MkbI>H6p)Y3,r]1)K'7gMK'7gMUZ`"P4<kaj2d]7QRf8TQP_,'M
P(JjKP-:#KPl@!WS>&D6,8qje?VJtmrl,&X_SO(a_"kb=^APZr]RmeJ]RmfI]`#GB
^&GeT`QU_4,8qje?VKM:rn@G+rn-hopX];m!S,`re:Q/$dt6&#e)AaUdeqPreC)do
rm_D.gI+.K)C7=L9^D!CkQ'fFkk"!5k547ljFZHEjFZIGjS\'8iW.s9iX"R44<kaj
2d]8Vn+5uCm/cS?qs3k=K'@mOK'@mOjQQ^/kks]AkR$G86p)\4,r]1)rU'dTmI'E;
mJ6)Llg+H5q<@kA!U8j#k^r#Mk^r$TkkXBLk2tji6p)\4,r]1)rU'dTmI'E;mJ6)L
lg+H5q<@kA!U8j#k^r#Mk^r$TkkXBLk2tji6p)\4,r]1)rU'dTmI'E;mJ6)Llg+H5
q<@kA!U8j#k^r#Mk^r$TkkXBLk2tji6p)\4,r]1)rU'dTmI'E;mJ6)Llg+H5q<@kA
!U8j#k^r#Mk^r$TkkXBLk2tji6p)\4,r]1)rU'dTmI'E;mJ6)Llg+H5q<@kA!U8j#
k^r#Mk^r$TkkXBLk2tji6p)\4,r]1)rU'dTmI'E;mJ6)Llg+H5q<@kA!U8j#k^r#M
k^r$TkkXBLk2tji6p)\4,r]1)rU'dTmI'E;mJ6)Llg+H5q<@kA!U8j#k^r#Mk^r$T
kkXBLZa8iX6p)Y3,r]1)rU'dTmI'E;mJ6)Llg+H5q<@kA!U8j#k^r#Mk^r$TkkXBL
Za9\p6p)Y3,r]1)rU'dTmI'E;mJ6)Llg+H5q<@kA!U8j#k^r#Mk^r$TkkXBMk5YJE
6p)Y3,r]1)mJcDOm.9Q;lM]rLkih9qqrmn>K'%[IK'%[Ii8t%$qr[k=#=LZu)C7=L
9_@ZFl4*"Bkih9qkih9qkih9qqrmn>K'%[IK'%[IiT:.%roO`tZf^DVZfU::4<b[i
2d]8Ulh9W>kl^/5l08*/pZDS>k5OOqk(;`Ik(;aOjq"f)s5gSns5cX2+rVad?VL@]
rp'CFp#u57!TiGAk(;]HjauTGjj`B*jT#8AjT#8@6p)Y3,r]1)kND'mp?2A9nDs]3
jS.\die$0Aie$1MiWeH&j5T(Yj8%[>6p)Y3,r]1)o&BQ*p##l.hu2Jbhh'a;hh'b<
h\G#)Za8NFZa8NFZa8KD6p)Y3,r]1)o\B,okh:XAK%Yb/K%],9'=5%FfsA$bfsA$b
fL.hG)C7=L9^^O(f(%:Be:Q2%e:Q3-e.hr_eC=NueC4HtdmQ;B)C7=L9\eFsh;d;f
gOe.2g4J%1g=P$dg"=qF4<b[i2bm^Rnk+L%Jjb2YJjcq5#Wsaa)C7=2:.=_<JinWI
JinWIZTJ@L/gD8WYTr-Ong!]LnK[TKiZn"<dNdcrnK[TKJg8;\nfk=`![&C$Jf94Z
Jf94ZS/M
~>
grestore
currentdict /inputf undef
currentdict /pstr undef
File diff suppressed because it is too large. Load diff
+983 -1
View File
@@ -2060,6 +2060,988 @@ iptables:
iptables -A INPUT -p tcp -{}-destination-port 8002 -j REJECT
\end{verbatim}
%% Chapter Xen Mandatory Access Control Framework
\chapter{sHype/Xen Access Control}
The Xen mandatory access control framework is an implementation of the
sHype Hypervisor Security Architecture
(www.research.ibm.com/ssd\_shype). It permits or denies communication
and resource access of domains based on a security policy. The
mandatory access controls are enforced in addition to the Xen core
controls, such as memory protection. They are designed to remain
transparent during normal operation of domains (policy-conform
behavior) but to intervene when domains move outside their intended
sharing behavior. This chapter will describe how the sHype access
controls in Xen can be configured to prevent viruses from spilling
over from one into another workload type and secrets from leaking from
one workload type to another. sHype/Xen depends on the correct
behavior of Domain0 (cf previous chapter).
Benefits of configuring sHype/ACM in Xen include:
\begin{itemize}
\item robust workload and resource protection effective against rogue
user domains
\item simple, platform- and operating system-independent security
policies (ideal for heterogeneous distributed environments)
\item safety net with minimal performance overhead in case operating
system security is missing, does not scale, or fails
\end{itemize}
These benefits are very valuable because today's operating systems
become increasingly complex and often have no or insufficient
mandatory access controls. (Discretionary access controls, supported
by of most operating systems, are not effective against viruses or
misbehaving programs.) Where mandatory access control exists (e.g.,
SELinux), they usually deploy complex and difficult to understand
security policies. Additionally, multi-tier applications in business
environments usually require different types of operating systems
(e.g., AIX, Windows, Linux) which cannot be configured with compatible
security policies. Related distributed transactions and workloads
cannot be easily protected on the OS level. The Xen access control
framework steps in to offer a coarse-grained but very robust security
layer and safety net in case operating system security fails or is
missing.
To control sharing between domains, Xen mediates all inter-domain
communication (shared memory, events) as well as the access of domains
to resources such as disks. Thus, Xen can confine distributed
workloads (domain payloads) by permitting sharing among domains
running the same type of workload and denying sharing between pairs of
domains that run different workload types. We assume that--from a Xen
perspective--only one workload type is running per user domain. To
enable Xen to associate domains and resources with workload types,
security labels including the workload types are attached to domains
and resources. These labels and the hypervisor sHype controls cannot
be manipulated or bypassed and are effective even against rogue
domains.
\section{Overview}
This section gives an overview of how workloads can be protected using
the sHype mandatory access control framework in Xen.
Figure~\ref{fig:acmoverview} shows the necessary steps in activating
the Xen workload protection. These steps are described in detail in
Section~\ref{section:acmexample}.
\begin{figure}
\centering
\includegraphics[width=13cm]{figs/acm_overview.eps}
\caption{Overview of activating sHype workload protection in Xen.
Section numbers point to representative examples.}
\label{fig:acmoverview}
\end{figure}
First, the sHype/ACM access control must be enabled in the Xen
distribution and the distribution must be built and installed (cf
Subsection~\ref{subsection:acmexampleconfigure}). Before we can
enforce security, a Xen security policy must be created (cf
Subsection~\ref{subsection:acmexamplecreate}) and deployed (cf
Subsection~\ref{subsection:acmexampleinstall}). This policy defines
the workload types differentiated during access control. It also
defines the rules that compare workload types of domains and resources
to provide access decisions. Workload types are represented by
security labels that can be attached to domains and resources (cf
Subsections~\ref{subsection:acmexamplelabeldomains}
and~\ref{subsection:acmexamplelabelresources}). The functioning of
the active sHype/Xen workload protection is demonstrated using simple
resource assignment, and domain creation tests in
Subsection~\ref{subsection:acmexampletest}.
Section~\ref{section:acmpolicy} describes the syntax and semantics of
the sHype/Xen security policy in detail and introduces briefly the
tools that are available to help create valid security policies.
The next section describes all the necessary steps to create, deploy,
and test a simple workload protection policy. It is meant to enable
anybody to quickly try out the sHype/Xen workload protection. Those
readers who are interested in learning more about how the sHype access
control in Xen works and how it is configured using the XML security
policy should read Section~\ref{section:acmpolicy} as well.
Section~\ref{section:acmlimitations} concludes this chapter with
current limitations of the sHype implementation for Xen.
\section{Xen Workload Protection Step-by-Step}
\label{section:acmexample}
What you are about to do consists of the following sequence:
\begin{itemize}
\item configure and install sHype/Xen
\item create a simple workload protection security policy
\item deploy the sHype/Xen security policy
\item associate domains and resources with workload labels,
\item test the workload protection
\end{itemize}
The essential commands to create and deploy a sHype/Xen security
policy are numbered throughout the following sections. If you want a
quick-guide or return at a later time to go quickly through this
demonstration, simply look for the numbered commands and apply them in
order.
\subsection{Configuring/Building sHype Support into Xen}
\label{subsection:acmexampleconfigure}
First, we need to configure the access control module in Xen and
install the ACM-enabled Xen hypervisor. This step installs security
tools and compiles sHype/ACM controls into the Xen hypervisor.
To enable sHype/ACM in Xen, please edit the Config.mk file in the top
Xen directory.
\begin{verbatim}
(1) In Config.mk
Change: ACM_SECURITY ?= n
To: ACM_SECURITY ?= y
\end{verbatim}
Then install the security-enabled Xen environment as follows:
\begin{verbatim}
(2) # make world
# make install
\end{verbatim}
\subsection{Creating A WLP Policy in 3 Simple Steps with ezPolicy}
\label{subsection:acmexamplecreate}
We will use the ezPolicy tool to quickly create a policy that protects
workloads. You will need both the Python and wxPython packages to run
this tool. To run the tool in Domain0, you can download the wxPython
package from www.wxpython.org or use the command
\verb|yum install wxPython| in Redhat/Fedora. To run the tool on MS
Windows, you also need to download the Python package from
www.python.org. After these packages are installed, start the ezPolicy
tool with the following command:
\begin{verbatim}
(3) # xensec_ezpolicy
\end{verbatim}
Figure~\ref{fig:acmezpolicy} shows a screen-shot of the tool. The
following steps show you how to create the policy shown in
Figure~\ref{fig:acmezpolicy}. You can use \verb|<CTRL>-h| to pop up a
help window at any time. The indicators (a), (b), and (c) in
Figure~\ref{fig:acmezpolicy} show the buttons that are used during the
3 steps of creating a policy:
\begin{enumerate}
\item defining workloads
\item defining run-time conflicts
\item translating the workload definition into a sHype/Xen access
control policy
\end{enumerate}
\paragraph{Defining workloads.} Workloads are defined for each
organization and department that you enter in the left panel. Please
use the ``New Org'' button (a) to create the organizations ``Avis'',
``Hertz'', ``CocaCola'', and ``PepsiCo''.
You can refine an organization to differentiate between multiple
department workloads by right-clicking the organization and selecting
\verb|Add Department| (or selecting an organization and pressing
\verb|<CRTL>-a|). Create department workloads ``Intranet'',
``Extranet'', ``HumanResources'', and ``Payroll'' for the ``CocaCola''
organization and department workloads ``Intranet'' and ``Extranet''
for the ``PepsiCo'' organization. The resulting layout of the tool
should be similar to the left panel shown in
Figure~\ref{fig:acmezpolicy}.
\paragraph{Defining run-time conflicts.} Workloads that shall be
prohibited from running concurrently on the same hypervisor platform
are grouped into ``Run-time Exclusion rules'' on the right panel of
the window.
To prevent PepsiCo and CocaCola workloads (including their
departmental workloads) from running simultaneously on the same
hypervisor system, select the organization ``PepsiCo'' and, while
pressing the \verb|<CTRL>|-key, select the organization ``CocaCola''.
Now press the button (b) named ``Create run-time exclusion rule from
selection''. A popup window will ask for the name for this run-time
exclusion rule (enter a name or just hit \verb|<ENTER>|). A rule will
appear on the right panel. The name is used as reference only and does
not affect the hypervisor policy.
Repeat the process to create a run-time exclusion rule just for the
department workloads CocaCola.Extranet and CocaCola.Payroll.
\begin{figure}[htb]
\centering
\includegraphics[width=13cm]{figs/acm_ezpolicy.eps}
\caption{Final layout including workload definition and Run-time Exclusion rules.}
\label{fig:acmezpolicy}
\end{figure}
The resulting layout of your window should be similar to
Figure~\ref{fig:acmezpolicy}. Save this workload definition by
selecting ``Save Workload Definition as ...'' in the ``File'' menu
(c). This workload definition can be later refined if required.
\paragraph{Translating the workload definition into a sHype/Xen access
control policy.} To translate the workload definition into a access
control policy understood by Xen, please select the ``Save as Xen ACM
Security Policy'' in the ``File'' menu (c). Enter the following policy
name in the popup window: \verb|example.chwall_ste.test-wld|. If you
are running ezPolicy in Domain0, the resulting policy file
test-wld\_security-policy.xml will automatically be placed into the
right directory (/etc/xen/acm-security/ policies/example/chwall\_ste).
If you run the tool on another system, then you need to copy the
resulting policy file into Domain0 before continuing. See
Section~\ref{subsection:acmnaming} for naming conventions of security
policies.
\subsection{Deploying a WLP Policy}
\label{subsection:acmexampleinstall}
To deploy the workload protection policy we created in
Section~\ref{subsection:acmexamplecreate}, we create a policy
representation (test-wld.bin) that can be loaded into the Xen
hypervisor and we configure Xen to actually load this policy at
startup time.
The following command translates the source policy representation
into a format that can be loaded into Xen with sHype/ACM support.
Refer to the \verb|xm| man page for further details:
\begin{verbatim}
(4) # xm makepolicy example.chwall_ste.test-wld
\end{verbatim}
The easiest way to install a security policy for Xen is to include the
policy in the boot sequence. The following command does just this:
\begin{verbatim}
(5) # xm cfgbootpolicy example.chwall_ste.test-wld
\end{verbatim}
\textit{Alternatively, if this command fails} (e.g., because it cannot
identify the Xen boot entry), you can manually install the policy in 2
steps. First, manually copy the policy binary file into the boot
directory:
\begin{scriptsize}
\begin{verbatim}
# cp /etc/xen/acm-security/policies/example/chwall_ste/test-wld.bin \
/boot/example.chwall_ste.test-wld.bin
\end{verbatim}
\end{scriptsize}
Second, manually add a module line to your Xen boot entry so that grub
loads this policy file during startup:
\begin{scriptsize}
\begin{verbatim}
title Xen (2.6.16.13)
root (hd0,0)
kernel /xen.gz dom0_mem=2000000 console=vga
module /vmlinuz-2.6.16.13-xen ro root=/dev/hda3
module /initrd-2.6.16.13-xen.img
module /example.chwall_ste.test-wld.bin
\end{verbatim}
\end{scriptsize}
Now reboot into this Xen boot entry to activate the policy and the
security-enabled Xen hypervisor.
\begin{verbatim}
(6) # reboot
\end{verbatim}
After reboot, check if security is enabled:
\begin{scriptsize}
\begin{verbatim}
# xm list --label
Name ID Mem(MiB) VCPUs State Time(s) Label
Domain-0 0 1949 4 r----- 163.9 SystemManagement
\end{verbatim}
\end{scriptsize}
If the security label at the end of the line says ``INACTIV'' then the
security is not enabled. Verify the previous steps. Note: Domain0 is
assigned a default label (see \verb|bootstrap| policy attribute
explained in Section~\ref{section:acmpolicy}). All other domains must
be labeled in order to start on this sHype/ACM-enabled Xen hypervisor
(see following sections for labeling domains and resources).
\subsection{Labeling Domains}
\label{subsection:acmexamplelabeldomains}
You should have a Xen domain configuration file that looks like the
following (Note: www.jailtime.org or www.xen-get.org might be good
places to look for example domU images). The following configuration
file defines \verb|domain1|:
\begin{scriptsize}
\begin{verbatim}
# cat domain1.xm
kernel = "/boot/vmlinuz-2.6.16.13-xen"
memory = 128
name = "domain1"
vif = [ '' ]
dhcp = "dhcp"
disk = ['file:/home/xen/dom_fc5/fedora.fc5.img,sda1,w', \
'file:/home/xen/dom_fc5/fedora.swap,sda2,w']
root = "/dev/sda1 ro"
\end{verbatim}
\end{scriptsize}
If you try to start domain1, you will get the following error:
\begin{scriptsize}
\begin{verbatim}
# xm create domain1.xm
Using config file "domain1.xm".
domain1: DENIED
--> Domain not labeled
Checking resources: (skipped)
Security configuration prevents domain from starting
\end{verbatim}
\end{scriptsize}
Every domain must be associated with a security label before it can
start on sHype/Xen. Otherwise, sHype/Xen would not be able to enforce
the policy consistently. The following command prints all domain
labels available in the active policy:
\begin{scriptsize}
\begin{verbatim}
# xm labels type=dom
Avis
CocaCola
CocaCola.Extranet
CocaCola.HumanResources
CocaCola.Intranet
CocaCola.Payroll
Hertz
PepsiCo
PepsiCo.Extranet
PepsiCo.Intranet
SystemManagement
\end{verbatim}
\end{scriptsize}
Now label domain1 with the CocaCola label and another domain2 with the
PepsiCo.Extranet label. Please refer to the xm man page for further
information.
\begin{verbatim}
(7) # xm addlabel CocaCola dom domain1.xm
# xm addlabel PepsiCo.Extranet dom domain2.xm
\end{verbatim}
Let us try to start the domain again:
\begin{scriptsize}
\begin{verbatim}
# xm create domain1.xm
Using config file "domain1.xm".
file:/home/xen/dom_fc5/fedora.fc5.img: DENIED
--> res:__NULL_LABEL__ (NULL)
--> dom:CocaCola (example.chwall_ste.test-wld)
file:/home/xen/dom_fc5/fedora.swap: DENIED
--> res:__NULL_LABEL__ (NULL)
--> dom:CocaCola (example.chwall_ste.test-wld)
Security configuration prevents domain from starting
\end{verbatim}
\end{scriptsize}
This error indicates that domain1, if started, would not be able to
access its image and swap files because they are not labeled. This
makes sense because to confine workloads, access of domains to
resources must be controlled. Otherwise, domains that are not allowed
to communicate or run simultaneously could share data through storage
resources.
\subsection{Labeling Resources}
\label{subsection:acmexamplelabelresources}
You can use the \verb|xm labels type=res| command to list available
resource labels. Let us assign the CocaCola resource label to the domain1
image file representing \verb|/dev/sda1| and to its swap file:
\begin{verbatim}
(8) # xm addlabel CocaCola res \
file:/home/xen/dom_fc5/fedora.fc5.img
Resource file not found, creating new file at:
/etc/xen/acm-security/policies/resource_labels
# xm addlabel CocaCola res \
file:/home/xen/dom_fc5/fedora.swap
\end{verbatim}
Starting \verb|domain1| now will succeed:
\begin{scriptsize}
\begin{verbatim}
# xm create domain1.xm
# xm list --label
Name ID Mem(MiB) VCPUs State Time(s) Label
domain1 1 128 1 r----- 2.8 CocaCola
Domain-0 0 1949 4 r----- 387.7 SystemManagement
\end{verbatim}
\end{scriptsize}
The following command lists all labeled resources on the
system, e.g., to lookup or verify the labeling:
\begin{scriptsize}
\begin{verbatim}
# xm resources
file:/home/xen/dom_fc5/fedora.swap
policy: example.chwall_ste.test-wld
label: CocaCola
file:/home/xen/dom_fc5/fedora.fc5.img
policy: example.chwall_ste.test-wld
label: CocaCola
\end{verbatim}
\end{scriptsize}
Currently, if a labeled resource is moved to another location, the
label must first be manually removed, and after the move re-attached
using the xm commands \verb|xm rmlabel| and \verb|xm addlabel|
respectively. Please see Section~\ref{section:acmlimitations} for
further details.
\begin{verbatim}
(9) Label the resources of domain2 as PepsiCo.Extranet
Do not try to start this domain yet
\end{verbatim}
\subsection{Testing The Xen Workload Protection}
\label{subsection:acmexampletest}
We are about to demonstrate how the workload protection works by
verifying:
\begin{itemize}
\item that domains with conflicting workloads cannot run
simultaneously
\item that domains cannot access resources of other workloads
\item that domains cannot exchange network packets if they are not
associated with the same workload type
\end{itemize}
\paragraph{Test 1: Run-time exclusion rules.} We assume that domain1
with the CocaCola label is still running. While domain1 is running,
the run-time exclusion set of our policy says that domain2 cannot
start because the label of domain1 includes the CHWALL type CocaCola
and the label of domain2 includes the CHWALL type PepsiCo. The
run-time exclusion rule of our policy enforces that PepsiCo and
CocaCola cannot run at the same time on the same hypervisor platform.
Once domain1 is stopped or saved, domain2 can start but domain1 can no
longer start or be resumed. The ezPolicy tool, when creating the
Chinese Wall types for the workload labels, ensures that department
workloads inherit the organization type (and with it any organization
exclusions).
\begin{scriptsize}
\begin{verbatim}
# xm list --label
Name ID Mem(MiB) VCPUs State Time(s) Label
domain1 2 128 1 -b---- 6.9 CocaCola
Domain-0 0 1949 4 r----- 273.1 SystemManagement
# xm create domain2.xm
Using config file "domain2.xm".
Error: (1, 'Operation not permitted')
# xm destroy domain1
# xm create domain2.xm
Using config file "domain2.xm".
Started domain domain2
# xm list --label
Name ID Mem(MiB) VCPUs State Time(s) Label
domain2 4 164 1 r----- 4.3 PepsiCo.Extranet
Domain-0 0 1949 4 r----- 298.4 SystemManagement
# xm create domain1.xm
Using config file "domain1.xm".
Error: (1, 'Operation not permitted')
# xm destroy domain2
# xm list
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 1949 4 r----- 391.2
\end{verbatim}
\end{scriptsize}
You can verify that domains with Avis label can run together with
domains labeled CocaCola, PepsiCo, or Hertz.
\paragraph{Test2: Resource access.} In this test, we will re-label the
swap file for domain1 with the Avis resource label. We expect that
Domain1 will no longer start because it cannot access this resource.
This test checks the sharing abilities of domains, which are defined
by the Simple Type Enforcement Policy component.
\begin{scriptsize}
\begin{verbatim}
# xm rmlabel res file:/home/xen/dom_fc5/fedora.swap
# xm addlabel Avis res file:/home/xen/dom_fc5/fedora.swap
# xm resources
file:/home/xen/dom_fc5/fedora.swap
policy: example.chwall_ste.test-wld
label: Avis
file:/home/xen/dom_fc5/fedora.fc5.img
policy: example.chwall_ste.test-wld
label: CocaCola
# xm create domain1.xm
Using config file "domain1.xm".
file:/home/xen/dom_fc4/fedora.swap: DENIED
--> res:Avis (example.chwall_ste.test-wld)
--> dom:CocaCola (example.chwall_ste.test-wld)
Security configuration prevents domain from starting
\end{verbatim}
\end{scriptsize}
\paragraph{Test 3: Communication.} In this test we would verify that
two domains with labels Hertz and Avis cannot exchange network packets
by using the 'ping' connectivity test. It is also related to the STE
policy.{\bf Note:} sHype/Xen does control direct communication between
domains. However, domains associated with different workloads can
currently still communicate through the Domain0 virtual network. We
are working on the sHype/ACM controls for local and remote network
traffic through Domain0. Please monitor the xen-devel mailing list
for updated information.
\section{Xen Access Control Policy}
\label{section:acmpolicy}
This section describes the sHype/Xen access control policy in detail.
It gives enough information to enable the reader to write custom
access control policies and to use the available Xen policy tools. The
policy language is expressive enough to specify most symmetric access
relationships between domains and resources efficiently.
The Xen access control policy consists of two policy components. The
first component, called Chinese Wall (CHWALL) policy, controls which
domains can run simultaneously on the same virtualized platform. The
second component, called Simple Type Enforcement (STE) policy,
controls the sharing between running domains, i.e., communication or
access to shared resources. The CHWALL and STE policy components can
be configured to run alone, however in our examples we will assume
that both policy components are configured together since they
complement each other. The XML policy file includes all information
needed by Xen to enforce the policies.
Figures~\ref{fig:acmxmlfilea} and \ref{fig:acmxmlfileb} show a fully
functional but very simple example policy for Xen. The policy can
distinguish two workload types \verb|CocaCola| and \verb|PepsiCo| and
defines the labels necessary to associate domains and resources with
one of these workload types. The XML Policy consists of four parts:
\begin{enumerate}
\item policy header including the policy name
\item Simple Type Enforcement block
\item Chinese Wall Policy block
\item label definition block
\end{enumerate}
\begin{figure}
\begin{scriptsize}
\begin{verbatim}
01 <?xml version="1.0" encoding="UTF-8"?>
02 <!-- Auto-generated by ezPolicy -->
03 <SecurityPolicyDefinition
xmlns="http://www.ibm.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://www.ibm.com ../../security_policy.xsd ">
04 <PolicyHeader>
05 <PolicyName>example.chwall_ste.test</PolicyName>
06 <Date>Wed Jul 12 17:32:59 2006</Date>
07 </PolicyHeader>
08
09 <SimpleTypeEnforcement>
10 <SimpleTypeEnforcementTypes>
11 <Type>SystemManagement</Type>
12 <Type>PepsiCo</Type>
13 <Type>CocaCola</Type>
14 </SimpleTypeEnforcementTypes>
15 </SimpleTypeEnforcement>
16
17 <ChineseWall priority="PrimaryPolicyComponent">
18 <ChineseWallTypes>
19 <Type>SystemManagement</Type>
20 <Type>PepsiCo</Type>
21 <Type>CocaCola</Type>
22 </ChineseWallTypes>
23
24 <ConflictSets>
25 <Conflict name="RER1">
26 <Type>CocaCola</Type>
27 <Type>PepsiCo</Type>
28 </Conflict>
29 </ConflictSets>
30 </ChineseWall>
31
\end{verbatim}
\end{scriptsize}
\caption{Example XML security policy file -- Part I: Types and Rules Definition.}
\label{fig:acmxmlfilea}
\end{figure}
\subsection{Policy Header and Policy Name}
\label{subsection:acmnaming}
Lines 1-2 (cf Figure~\ref{fig:acmxmlfilea}) include the usual XML
header. The security policy definition starts in Line 3 and refers to
the policy schema. The XML-Schema definition for the Xen policy can be
found in the file
\textit{/etc/xen/acm-security/policies/security-policy.xsd}. Examples
for security policies can be found in the example subdirectory. The
acm-security directory is only installed if ACM security is configured
during installation (cf Section~\ref{subsection:acmexampleconfigure}).
The \verb|Policy Header| spans lines 4-7. It includes a date field and
defines the policy name \verb|example.chwall_ste.test|. It can also
include optional fields that are not shown and are for future use (see
schema definition).
The policy name serves two purposes: First, it provides a unique name
for the security policy. This name is also exported by the Xen
hypervisor to the Xen management tools in order to ensure that both
enforce the same policy. We plan to extend the policy name with a
digital fingerprint of the policy contents to better protect this
correlation. Second, it implicitly points the xm tools to the
location where the XML policy file is stored on the Xen system.
Replacing the colons in the policy name by slashes yields the local
path to the policy file starting from the global policy directory
\verb|/etc/xen/acm-security/policies|. The last part of the policy
name is the prefix for the XML policy file name, completed by
\verb|-security_policy.xml|. Consequently, the policy with the name
\verb|example.chwall_ste.test| can be found in the XML policy file
named \verb|test-security_policy.xml| that is stored in the local
directory \verb|example/chwall_ste| under the global policy directory.
\subsection{Simple Type Enforcement Policy Component}
The Simple Type Enforcement (STE) policy controls which domains can
communicate or share resources. This way, Xen can enforce confinement
of workload types by confining the domains running those workload
types. The mandatory access control framework enforces its policy when
domains access intended ways of communication or cooperation (shared
memory, events, shared resources such as block devices). It builds on
top of the core hypervisor isolation, which restricts the ways of
inter-communication to those intended means. STE does not protect or
intend to protect from covert channels in the hypervisor or hardware;
this is an orthogonal problem that can be mitigated by using the
Run-time Exclusion rules described above or by fixing the problem in
the core hypervisor.
Xen controls sharing between domains on the resource and domain level
because this is the abstraction the hypervisor and its management
understand naturally. While this is coarse-grained, it is also very
reliable and robust and it requires minimal changes to implement
mandatory access controls in the hypervisor. It enables platform- and
operation system-independent policies as part of a layered security
approach.
Lines 9-15 (cf Figure~\ref{fig:acmxmlfilea}) define the Simple Type
Enforcement policy component. Essentially, they define the workload
type names \verb|SystemManagement|, \verb|PepsiCo|, and
\verb|CocaCola| that are available in the STE policy component. The
policy rules are implicit: Xen permits a domain to communicate with
another domain if and only if the labels of the domains share an
common STE type. Xen permits a domain to access a resource if and
only if the labels of the domain and the resource share a common STE
workload type.
\subsection{Chinese Wall Policy Component}
The Chinese Wall security policy interpretation of sHype enables users
to prevent certain workloads from running simultaneously on the same
hypervisor platform. Run-time Exclusion rules (RER), also called
Conflict Sets, define a set of workload types that are not permitted
to run simultaneously. Of all the workloads specified in a Run-time
Exclusion rule, at most one type can run on the same hypervisor
platform at a time. Run-time Exclusion Rules implement a less
rigorous variant of the original Chinese Wall security component. They
do not implement the *-property of the policy, which would require to
restrict also types that are not part of an exclusion rule once they
are running together with a type in an exclusion rule (please refer to
http://www.gammassl.co.uk/topics/chinesewall.html for more information
on the original Chinese Wall policy).
Xen considers the \verb|ChineseWallTypes| part of the label for the
enforcement of the Run-time Exclusion rules. It is illegal to define
labels including conflicting Chinese Wall types.
Lines 17-30 (cf Figure~\ref{fig:acmxmlfilea}) define the Chinese Wall
policy component. Lines 17-22 define the known Chinese Wall types,
which coincide here with the STE types defined above. This usually
holds if the criteria for sharing among domains and sharing of the
hardware platform are the same. Lines 24-29 define one Run-time
Exclusion rule:
\begin{scriptsize}
\begin{verbatim}
<Conflict name="RER1">
<Type>CocaCola</Type>
<Type>PepsiCo</Type>
</Conflict>
\end{verbatim}
\end{scriptsize}
Based on this rule, Xen enforces that only one of the types
\verb|CocaCola| or \verb|PepsiCo| will run on a single hypervisor
platform at a time. For example, once a domain assigned a
\verb|CocaCola| workload type is started, domains with the
\verb|PepsiCo| type will be denied to start. When the former domain
stops and no other domains with the \verb|CocaCola| type are running,
then domains with the \verb|PepsiCo| type can start.
Xen maintains reference counts on each running workload type to keep
track of which workload types are running. Every time a domain starts
or resumes, the reference count on those Chinese Wall types that are
referenced in the domain's label are incremented. Every time a domain
is destroyed or saved, the reference counts of its Chinese Wall types
are decremented. sHype in Xen covers migration and live-migration,
which is treated the same way as saving a domain on the source
platform and resuming it on the destination platform.
Reasons why users would want to restrict which workloads or domains
can share the system hardware include:
\begin{itemize}
\item Imperfect resource management or control might enable a rogue
domain to starve another domain and the workload running in it.
\item Redundant domains might run the same workload to increase
availability; such domains should not run on the same hardware to
avoid single points of failure.
\item Imperfect Xen core domain isolation might enable two rogue
domains running different workload types to use unintended and
unknown ways (covert channels) to exchange some data. This way, they
bypass the policed Xen access control mechanisms. Such
imperfections cannot be completely eliminated and are a result of
trade-offs between security and other design requirements. For a
simple example of a covert channel see
http://www.multicians.org/timing-chn.html. Such covert channels
exist also between workloads running on different platforms if they
are connected through networks. The Xen Chinese Wall policy provides
an approximation of this imperfect ``air-gap'' between selected
workload types.
\end{itemize}
\subsection{Security Labels}
To enable Xen to associate domains with workload types running in
them, each domain is assigned a security label that includes the
workload types of the domain.
\begin{figure}
\begin{scriptsize}
\begin{verbatim}
32 <SecurityLabelTemplate>
33 <SubjectLabels bootstrap="SystemManagement">
34 <VirtualMachineLabel>
35 <Name>SystemManagement</Name>
36 <SimpleTypeEnforcementTypes>
37 <Type>SystemManagement</Type>
38 <Type>PepsiCo</Type>
39 <Type>CocaCola</Type>
40 </SimpleTypeEnforcementTypes>
41 <ChineseWallTypes>
42 <Type>SystemManagement</Type>
43 </ChineseWallTypes>
44 </VirtualMachineLabel>
45
46 <VirtualMachineLabel>
47 <Name>PepsiCo</Name>
48 <SimpleTypeEnforcementTypes>
49 <Type>PepsiCo</Type>
50 </SimpleTypeEnforcementTypes>
51 <ChineseWallTypes>
52 <Type>PepsiCo</Type>
53 </ChineseWallTypes>
54 </VirtualMachineLabel>
55
56 <VirtualMachineLabel>
57 <Name>CocaCola</Name>
58 <SimpleTypeEnforcementTypes>
59 <Type>CocaCola</Type>
60 </SimpleTypeEnforcementTypes>
61 <ChineseWallTypes>
62 <Type>CocaCola</Type>
63 </ChineseWallTypes>
64 </VirtualMachineLabel>
65 </SubjectLabels>
66
67 <ObjectLabels>
68 <ResourceLabel>
69 <Name>SystemManagement</Name>
70 <SimpleTypeEnforcementTypes>
71 <Type>SystemManagement</Type>
72 </SimpleTypeEnforcementTypes>
73 </ResourceLabel>
74
75 <ResourceLabel>
76 <Name>PepsiCo</Name>
77 <SimpleTypeEnforcementTypes>
78 <Type>PepsiCo</Type>
79 </SimpleTypeEnforcementTypes>
80 </ResourceLabel>
81
82 <ResourceLabel>
83 <Name>CocaCola</Name>
84 <SimpleTypeEnforcementTypes>
85 <Type>CocaCola</Type>
86 </SimpleTypeEnforcementTypes>
87 </ResourceLabel>
88 </ObjectLabels>
89 </SecurityLabelTemplate>
90 </SecurityPolicyDefinition>
\end{verbatim}
\end{scriptsize}
\caption{Example XML security policy file -- Part II: Label Definition.}
\label{fig:acmxmlfileb}
\end{figure}
Lines 32-89 (cf Figure~\ref{fig:acmxmlfileb}) define the
\verb|SecurityLabelTemplate|, which includes the labels that can be
attached to domains and resources when this policy is active. The
domain labels include Chinese Wall types while resource labels do not
include Chinese Wall types. Lines 33-65 define the
\verb|SubjectLabels| that can be assigned to domains. For example, the
virtual machine label \verb|CocaCola| (cf lines 56-64 in
Figure~\ref{fig:acmxmlfileb}) associates the domain that carries it
with the workload type \verb|CocaCola|.
The \verb|bootstrap| attribute names the label
\verb|SystemManagement|. Xen will assign this label to Domain0 at
boot time. All other domains are assigned labels according to their
domain configuration file (see
Section~\ref{subsection:acmexamplelabeldomains} for examples of how to
label domains). Lines 67-88 define the \verb|ObjectLabels|. Those
labels can be assigned to resources when this policy is active.
In general, user domains should be assigned labels that have only a
single SimpleTypeEnforcement workload type. This way, workloads remain
confined even if user domains become rogue. Any domain that is
assigned a label with multiple STE types must be trusted to keep
information belonging to the different STE types separate (confined).
For example, Domain0 is assigned the bootstrap label
\verb|SystemsManagement|, which includes all existing STE types.
Therefore, Domain0 must take care not to enable unauthorized
information flow (eg. through block devices or virtual networking)
between domains or resources that are assigned different STE types.
Security administrators simply use the name of a label (specified in
the \verb|<Name>| field) to associate a label with a domain (cf.
Section~\ref{subsection:acmexamplelabeldomains}). The types inside the
label are used by the Xen access control enforcement. While the name
can be arbitrarily chosen (as long as it is unique), it is advisable
to choose the label name in accordance to the security types included.
While the XML representation in the above label seems unnecessary
flexible, labels in general can consist of multiple types as we will
see in the following example.
Assume that \verb|PepsiCo| and \verb|CocaCola| workloads use virtual
disks that are provided by a virtual I/O domain hosting a physical
storage device and carrying the following label:
\begin{scriptsize}
\begin{verbatim}
<VirtualMachineLabel>
<Name>VIO</Name>
<SimpleTypeEnforcementTypes>
<Type>CocaCola</Type>
<Type>PepsiCo</Type>
</SimpleTypeEnforcementTypes>
<ChineseWallTypes>
<Type>VIOServer</Type>
</ChineseWallTypes>
</VirtualMachineLabel>
\end{verbatim}
\end{scriptsize}
This Virtual I/O domain (VIO) exports its virtualized disks by
communicating both to domains labeled with the \verb|PepsiCo| label
and domains labeled with the \verb|CocaCola| label. This requires the
VIO domain to carry both the STE types \verb|CocaCola| and
\verb|PepsiCo|. In this example, the confinement of \verb|CocaCola|
and \verb|PepsiCo| workload depends on a VIO domain that must keep the
data of those different workloads separate. The virtual disks are
labeled as well (see Section~\ref{subsection:acmexamplelabelresources}
for labeling resources) and enforcement functions inside the VIO
domain must ensure that the labels of the domain mounting a virtual
disk and the virtual disk label share a common STE type. The VIO label
carrying its own VIOServer CHWALL type introduces the flexibility to
permit the trusted VIO server to run together with CocaCola or PepsiCo
workloads.
Alternatively, a system that has two hard-drives does not need a VIO
domain but can directly assign one hardware storage device to each of
the workloads (if the platform offers an IO-MMU, cf
Section~\ref{s:ddsecurity}. Sharing hardware through virtualization
is a trade-off between the amount of trusted code (size of the trusted
computing base) and the amount of acceptable over-provisioning. This
holds both for peripherals and for system platforms.
\subsection{Tools For Creating sHype/Xen Security Policies}
To create a security policy for Xen, you can use one of the following
tools:
\begin{itemize}
\item \verb|ezPolicy| GUI tool -- start writing policies
\item \verb|xensec_gen| tool -- refine policies created with \verb|ezPolicy|
\item text or XML editor
\end{itemize}
We use the \verb|ezPolicy| tool in
Section~\ref{subsection:acmexamplecreate} to quickly create a workload
protection policy. If desired, the resulting XML policy file can be
loaded into the \verb|xensec_gen| tool to refine it. It can also be
directly edited using an XML editor. Any XML policy file is verified
against the security policy schema when it is translated (see
Subsection~\ref{subsection:acmexampleinstall}).
\section{Current Limitations}
\label{section:acmlimitations}
The sHype/ACM configuration for Xen is work in progress. There is
ongoing work for protecting virtualized resources and planned and
ongoing work for protecting access to remote resources and domains.
The following sections describe limitations of some of the areas into
which access control is being extended.
\subsection{Network Traffic}
Local and remote network traffic is currently not controlled.
Solutions to add sHype/ACM policy enforcement to the virtual network
exist but need to be discussed before they can become part of Xen.
Subjecting external network traffic to the ACM security policy is work
in progress. Manually setting up filters in domain 0 is required for
now but does not scale well.
\subsection{Resource Access and Usage Control}
Enforcing the security policy across multiple hypervisor systems and
on access to remote shared resources is work in progress. Extending
access control to new types of resources is ongoing work (e.g. network
storage).
On a single Xen system, information about the association of resources
and security labels is stored in
\verb|/etc/xen/acm-security/policy/resource_labels|. This file relates
a full resource path with a security label. This association is weak
and will break if resources are moved or renamed without adapting the
label file. Improving the protection of label-resource relationships
is ongoing work.
Controlling resource usage and enforcing resource limits in general is
ongoing work in the Xen community.
\subsection{Domain Migration}
Labels on domains are enforced during domain migration and the
destination hypervisor will ensure that the domain label is valid and
the domain is permitted to run (considering the Chinese Wall policy
rules) before it accepts the migration. However, the network between
the source and destination hypervisor as well as both hypervisors must
be trusted. Architectures and prototypes exist that both protect the
network connection and ensure that the hypervisors enforce access
control consistently but patches are not yet available for the main
stream.
\subsection{Covert Channels}
The sHype access control aims at system independent security policies.
It builds on top of the core hypervisor isolation. Any covert channels
that exist in the core hypervisor or in the hardware (e.g., shared
processor cache) will be inherited. If those covert channels are not
the result of trade-offs between security and other system properties,
then they are most effectively minimized or eliminated where they are
caused. sHype offers however some means to mitigate their impact
(cf. run-time exclusion rules).
\part{Reference}
%% Chapter Build and Boot Options
@@ -2188,7 +3170,7 @@ editing \path{grub.conf}.
\item [ tbuf\_size=xxx ] Set the size of the per-cpu trace buffers, in
pages (default 0).
\item [ sched=xxx ] Select the CPU scheduler Xen should use. The
current possibilities are `sedf' (default), `credit', and `bvt'.
current possibilities are `credit' (default), `sedf', and `bvt'.
\item [ apic\_verbosity=debug,verbose ] Print more detailed
information about local APIC and IOAPIC configuration.
\item [ lapic ] Force use of local APIC even when left disabled by
+1 -1
View File
@@ -53,7 +53,7 @@ int xencons_ring_send(const char *data, unsigned len)
static void handle_input(int port, struct pt_regs *regs, void *ign)
static void handle_input(evtchn_port_t port, struct pt_regs *regs, void *ign)
{
struct xencons_interface *intf = xencons_interface();
XENCONS_RING_IDX cons, prod;
+43 -33
View File
@@ -26,20 +26,20 @@
/* this represents a event handler. Chaining or sharing is not allowed */
typedef struct _ev_action_t {
void (*handler)(int, struct pt_regs *, void *);
evtchn_handler_t handler;
void *data;
u32 count;
} ev_action_t;
static ev_action_t ev_actions[NR_EVS];
void default_handler(int port, struct pt_regs *regs, void *data);
void default_handler(evtchn_port_t port, struct pt_regs *regs, void *data);
/*
* Demux events to different handlers.
*/
int do_event(u32 port, struct pt_regs *regs)
int do_event(evtchn_port_t port, struct pt_regs *regs)
{
ev_action_t *action;
if (port >= NR_EVS) {
@@ -60,8 +60,8 @@ int do_event(u32 port, struct pt_regs *regs)
}
int bind_evtchn( u32 port, void (*handler)(int, struct pt_regs *, void *),
void *data )
evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler,
void *data)
{
if(ev_actions[port].handler != default_handler)
printk("WARN: Handler for port %d already registered, replacing\n",
@@ -77,7 +77,7 @@ int bind_evtchn( u32 port, void (*handler)(int, struct pt_regs *, void *),
return port;
}
void unbind_evtchn( u32 port )
void unbind_evtchn(evtchn_port_t port )
{
if (ev_actions[port].handler == default_handler)
printk("WARN: No handler for port %d when unbinding\n", port);
@@ -86,8 +86,7 @@ void unbind_evtchn( u32 port )
ev_actions[port].data = NULL;
}
int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *, void *data),
void *data)
int bind_virq(uint32_t virq, evtchn_handler_t handler, void *data)
{
evtchn_op_t op;
@@ -105,11 +104,6 @@ int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *, void *data),
return 0;
}
void unbind_virq( u32 port )
{
unbind_evtchn(port);
}
#if defined(__x86_64__)
/* Allocate 4 pages for the irqstack */
#define STACK_PAGES 4
@@ -142,32 +136,48 @@ void init_events(void)
}
}
void default_handler(int port, struct pt_regs *regs, void *ignore)
void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore)
{
printk("[Port %d] - event received\n", port);
}
/* Create a port available to the pal for exchanging notifications.
Returns the result of the hypervisor call. */
/* Unfortunate confusion of terminology: the port is unbound as far
as Xen is concerned, but we automatically bind a handler to it
from inside mini-os. */
int evtchn_alloc_unbound(void (*handler)(int, struct pt_regs *regs,
void *data),
void *data)
int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler,
void *data, evtchn_port_t *port)
{
u32 port;
evtchn_op_t op;
int err;
op.cmd = EVTCHNOP_alloc_unbound;
op.u.alloc_unbound.dom = DOMID_SELF;
op.u.alloc_unbound.remote_dom = 0;
err = HYPERVISOR_event_channel_op(&op);
if (err) {
printk("Failed to alloc unbound evtchn: %d.\n", err);
return -1;
}
port = op.u.alloc_unbound.port;
bind_evtchn(port, handler, data);
return port;
evtchn_op_t op;
op.cmd = EVTCHNOP_alloc_unbound;
op.u.alloc_unbound.dom = DOMID_SELF;
op.u.alloc_unbound.remote_dom = pal;
int err = HYPERVISOR_event_channel_op(&op);
if (err)
return err;
*port = bind_evtchn(op.u.alloc_unbound.port, handler, data);
return err;
}
/* Connect to a port so as to allow the exchange of notifications with
the pal. Returns the result of the hypervisor call. */
int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
evtchn_handler_t handler, void *data,
evtchn_port_t *local_port)
{
evtchn_op_t op;
op.cmd = EVTCHNOP_bind_interdomain;
op.u.bind_interdomain.remote_dom = pal;
op.u.bind_interdomain.remote_port = remote_port;
int err = HYPERVISOR_event_channel_op(&op);
if (err)
return err;
evtchn_port_t port = op.u.bind_interdomain.local_port;
clear_evtchn(port); /* Without, handler gets invoked now! */
*local_port = bind_evtchn(port, handler, data);
return err;
}
+12
View File
@@ -137,6 +137,18 @@ gnttab_alloc_and_grant(void **map)
return gref;
}
static const char *gnttabop_error_msgs[] = GNTTABOP_error_msgs;
const char *
gnttabop_error(int16_t status)
{
status = -status;
if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs))
return "bad status";
else
return gnttabop_error_msgs[status];
}
void
init_gnttab(void)
{
+15 -13
View File
@@ -22,20 +22,22 @@
#include<traps.h>
#include <xen/event_channel.h>
/* prototypes */
int do_event(u32 port, struct pt_regs *regs);
int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *, void *data),
void *data);
int bind_evtchn( u32 virq, void (*handler)(int, struct pt_regs *, void *data),
void *data );
void unbind_evtchn( u32 port );
void init_events(void);
void unbind_virq( u32 port );
int evtchn_alloc_unbound(void (*handler)(int, struct pt_regs *regs,
void *data),
void *data);
typedef void (*evtchn_handler_t)(evtchn_port_t, struct pt_regs *, void *);
static inline int notify_remote_via_evtchn(int port)
/* prototypes */
int do_event(evtchn_port_t port, struct pt_regs *regs);
int bind_virq(uint32_t virq, evtchn_handler_t handler, void *data);
evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler,
void *data);
void unbind_evtchn(evtchn_port_t port);
void init_events(void);
int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler,
void *data, evtchn_port_t *port);
int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
evtchn_handler_t handler, void *data,
evtchn_port_t *local_port);
static inline int notify_remote_via_evtchn(evtchn_port_t port)
{
evtchn_op_t op;
op.cmd = EVTCHNOP_send;
+1
View File
@@ -10,5 +10,6 @@ grant_ref_t gnttab_grant_access(domid_t domid, unsigned long frame,
grant_ref_t gnttab_grant_transfer(domid_t domid, unsigned long pfn);
unsigned long gnttab_end_transfer(grant_ref_t gref);
int gnttab_end_access(grant_ref_t ref);
const char *gnttabop_error(int16_t status);
#endif /* !__GNTTAB_H__ */
+1 -1
View File
@@ -215,7 +215,7 @@ void block_domain(u32 millisecs)
/*
* Just a dummy
*/
static void timer_handler(int ev, struct pt_regs *regs, void *ign)
static void timer_handler(evtchn_port_t ev, struct pt_regs *regs, void *ign)
{
static int i;
+2 -1
View File
@@ -112,7 +112,8 @@ static void xenbus_thread_func(void *ign)
}
}
static void xenbus_evtchn_handler(int port, struct pt_regs *regs, void *ign)
static void xenbus_evtchn_handler(evtchn_port_t port, struct pt_regs *regs,
void *ign)
{
wake_up(&xb_waitq);
}
@@ -109,6 +109,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
init_MUTEX(&mm->context.sem);
mm->context.size = 0;
mm->context.has_foreign_mappings = 0;
old_mm = current->mm;
if (old_mm && old_mm->context.size > 0) {
down(&old_mm->context.sem);
@@ -126,6 +126,8 @@ int direct_remap_pfn_range(struct vm_area_struct *vma,
if (domid == DOMID_SELF)
return -EINVAL;
vma->vm_mm->context.has_foreign_mappings = 1;
return __direct_remap_pfn_range(
vma->vm_mm, address, mfn, size, prot, domid);
}
@@ -694,6 +694,7 @@ void _arch_exit_mmap(struct mm_struct *mm)
task_unlock(tsk);
if (test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags) &&
(atomic_read(&mm->mm_count) == 1))
(atomic_read(&mm->mm_count) == 1) &&
!mm->context.has_foreign_mappings)
mm_unpin(mm);
}
+15
View File
@@ -438,6 +438,21 @@ config PCI_DOMAINS
bool
default PCI
config XEN_PCIDEV_FRONTEND
bool "Xen PCI Frontend"
depends on PCI && XEN
default y
help
The PCI device frontend driver allows the kernel to import arbitrary
PCI devices from a PCI backend to support PCI driver domains.
config XEN_PCIDEV_FE_DEBUG
bool "Xen PCI Frontend Debugging"
depends on XEN_PCIDEV_FRONTEND
default n
help
Enables some debug statements within the PCI Frontend.
source "drivers/pci/Kconfig"
source "drivers/pci/hotplug/Kconfig"
@@ -159,7 +159,8 @@ void _arch_exit_mmap(struct mm_struct *mm)
task_unlock(tsk);
if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) )
if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) &&
!mm->context.has_foreign_mappings )
mm_unpin(mm);
}
-9
View File
@@ -143,15 +143,6 @@ config XEN_TPMDEV_BACKEND
help
The TPM-device backend driver
config XEN_TPMDEV_CLOSE_IF_VTPM_FAILS
bool "TPM backend closes upon vTPM failure"
depends on XEN_TPMDEV_BACKEND
default n
help
The TPM backend closes the channel if the vTPM in userspace indicates
a failure. The corresponding domain's channel will be closed.
Say Y if you want this feature.
config XEN_BLKDEV_FRONTEND
tristate "Block-device frontend driver"
depends on XEN
@@ -76,6 +76,10 @@ typedef struct netif_st {
struct vm_struct *tx_comms_area;
struct vm_struct *rx_comms_area;
/* Set of features that can be turned on in dev->features. */
int features;
int can_queue;
/* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
RING_IDX rx_req_cons_peek;
@@ -86,8 +90,6 @@ typedef struct netif_st {
struct timer_list credit_timeout;
/* Miscellaneous private stuff. */
enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
int active;
struct list_head list; /* scheduling list */
atomic_t refcnt;
struct net_device *dev;
@@ -121,4 +123,16 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
struct net_device_stats *netif_be_get_stats(struct net_device *dev);
irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
static inline int netbk_can_queue(struct net_device *dev)
{
netif_t *netif = netdev_priv(dev);
return netif->can_queue;
}
static inline int netbk_can_sg(struct net_device *dev)
{
netif_t *netif = netdev_priv(dev);
return netif->features & NETIF_F_SG;
}
#endif /* __NETIF__BACKEND__COMMON_H__ */
@@ -36,46 +36,74 @@
static void __netif_up(netif_t *netif)
{
struct net_device *dev = netif->dev;
netif_tx_lock_bh(dev);
netif->active = 1;
netif_tx_unlock_bh(dev);
enable_irq(netif->irq);
netif_schedule_work(netif);
}
static void __netif_down(netif_t *netif)
{
struct net_device *dev = netif->dev;
disable_irq(netif->irq);
netif_tx_lock_bh(dev);
netif->active = 0;
netif_tx_unlock_bh(dev);
netif_deschedule_work(netif);
}
static int net_open(struct net_device *dev)
{
netif_t *netif = netdev_priv(dev);
if (netif->status == CONNECTED)
if (netif_carrier_ok(dev))
__netif_up(netif);
netif_start_queue(dev);
return 0;
}
static int net_close(struct net_device *dev)
{
netif_t *netif = netdev_priv(dev);
netif_stop_queue(dev);
if (netif->status == CONNECTED)
if (netif_carrier_ok(dev))
__netif_down(netif);
return 0;
}
static int netbk_change_mtu(struct net_device *dev, int mtu)
{
int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
if (mtu > max)
return -EINVAL;
dev->mtu = mtu;
return 0;
}
static int netbk_set_sg(struct net_device *dev, u32 data)
{
if (data) {
netif_t *netif = netdev_priv(dev);
if (!(netif->features & NETIF_F_SG))
return -ENOSYS;
}
return ethtool_op_set_sg(dev, data);
}
static int netbk_set_tso(struct net_device *dev, u32 data)
{
if (data) {
netif_t *netif = netdev_priv(dev);
if (!(netif->features & NETIF_F_TSO))
return -ENOSYS;
}
return ethtool_op_set_tso(dev, data);
}
static struct ethtool_ops network_ethtool_ops =
{
.get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = netbk_set_sg,
.get_tso = ethtool_op_get_tso,
.set_tso = netbk_set_tso,
.get_link = ethtool_op_get_link,
};
@@ -93,11 +121,12 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
return ERR_PTR(-ENOMEM);
}
netif_carrier_off(dev);
netif = netdev_priv(dev);
memset(netif, 0, sizeof(*netif));
netif->domid = domid;
netif->handle = handle;
netif->status = DISCONNECTED;
atomic_set(&netif->refcnt, 1);
init_waitqueue_head(&netif->waiting_to_free);
netif->dev = dev;
@@ -110,12 +139,16 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
dev->get_stats = netif_be_get_stats;
dev->open = net_open;
dev->stop = net_close;
dev->change_mtu = netbk_change_mtu;
dev->features = NETIF_F_IP_CSUM;
SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
/* Disable queuing. */
dev->tx_queue_len = 0;
/*
* Reduce default TX queuelen so that each guest interface only
* allows it to eat around 6.4MB of host memory.
*/
dev->tx_queue_len = 100;
for (i = 0; i < ETH_ALEN; i++)
if (be_mac[i] != 0)
@@ -256,11 +289,9 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
netif->rx_req_cons_peek = 0;
netif_get(netif);
wmb(); /* Other CPUs see new state before interface is started. */
rtnl_lock();
netif->status = CONNECTED;
wmb();
netif_carrier_on(netif->dev);
if (netif_running(netif->dev))
__netif_up(netif);
rtnl_unlock();
@@ -296,20 +327,13 @@ static void netif_free(netif_t *netif)
void netif_disconnect(netif_t *netif)
{
switch (netif->status) {
case CONNECTED:
if (netif_carrier_ok(netif->dev)) {
rtnl_lock();
netif->status = DISCONNECTING;
wmb();
netif_carrier_off(netif->dev);
if (netif_running(netif->dev))
__netif_down(netif);
rtnl_unlock();
netif_put(netif);
/* fall through */
case DISCONNECTED:
netif_free(netif);
break;
default:
BUG();
}
netif_free(netif);
}
+370 -149
View File
@@ -40,17 +40,22 @@
/*#define NETBE_DEBUG_INTERRUPT*/
struct netbk_rx_meta {
skb_frag_t frag;
int id;
};
static void netif_idx_release(u16 pending_idx);
static void netif_page_release(struct page *page);
static void make_tx_response(netif_t *netif,
netif_tx_request_t *txp,
s8 st);
static int make_rx_response(netif_t *netif,
u16 id,
s8 st,
u16 offset,
u16 size,
u16 flags);
static netif_rx_response_t *make_rx_response(netif_t *netif,
u16 id,
s8 st,
u16 offset,
u16 size,
u16 flags);
static void net_tx_action(unsigned long unused);
static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0);
@@ -100,21 +105,27 @@ static spinlock_t net_schedule_list_lock;
static unsigned long mfn_list[MAX_MFN_ALLOC];
static unsigned int alloc_index = 0;
static unsigned long alloc_mfn(void)
static inline unsigned long alloc_mfn(void)
{
return mfn_list[--alloc_index];
}
static int check_mfn(int nr)
{
unsigned long mfn = 0;
struct xen_memory_reservation reservation = {
.nr_extents = MAX_MFN_ALLOC,
.extent_order = 0,
.domid = DOMID_SELF
};
set_xen_guest_handle(reservation.extent_start, mfn_list);
if ( unlikely(alloc_index == 0) )
alloc_index = HYPERVISOR_memory_op(
XENMEM_increase_reservation, &reservation);
if ( alloc_index != 0 )
mfn = mfn_list[--alloc_index];
return mfn;
if (likely(alloc_index >= nr))
return 0;
set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index);
reservation.nr_extents = MAX_MFN_ALLOC - alloc_index;
alloc_index += HYPERVISOR_memory_op(XENMEM_increase_reservation,
&reservation);
return alloc_index >= nr ? 0 : -ENOMEM;
}
static inline void maybe_schedule_tx_action(void)
@@ -136,6 +147,96 @@ static inline int is_xen_skb(struct sk_buff *skb)
return (cp == skbuff_cachep);
}
static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
{
struct skb_shared_info *ninfo;
struct sk_buff *nskb;
unsigned long offset;
int ret;
int len;
int headlen;
nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC);
if (unlikely(!nskb))
goto err;
skb_reserve(nskb, 16);
headlen = nskb->end - nskb->data;
if (headlen > skb_headlen(skb))
headlen = skb_headlen(skb);
ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
BUG_ON(ret);
ninfo = skb_shinfo(nskb);
ninfo->gso_size = skb_shinfo(skb)->gso_size;
ninfo->gso_type = skb_shinfo(skb)->gso_type;
offset = headlen;
len = skb->len - headlen;
nskb->len = skb->len;
nskb->data_len = len;
nskb->truesize += len;
while (len) {
struct page *page;
int copy;
int zero;
if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
dump_stack();
goto err_free;
}
copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
page = alloc_page(GFP_ATOMIC | zero);
if (unlikely(!page))
goto err_free;
ret = skb_copy_bits(skb, offset, page_address(page), copy);
BUG_ON(ret);
ninfo->frags[ninfo->nr_frags].page = page;
ninfo->frags[ninfo->nr_frags].page_offset = 0;
ninfo->frags[ninfo->nr_frags].size = copy;
ninfo->nr_frags++;
offset += copy;
len -= copy;
}
offset = nskb->data - skb->data;
nskb->h.raw = skb->h.raw + offset;
nskb->nh.raw = skb->nh.raw + offset;
nskb->mac.raw = skb->mac.raw + offset;
return nskb;
err_free:
kfree_skb(nskb);
err:
return NULL;
}
static inline int netbk_max_required_rx_slots(netif_t *netif)
{
if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
return 1; /* all in one */
}
static inline int netbk_queue_full(netif_t *netif)
{
RING_IDX peek = netif->rx_req_cons_peek;
RING_IDX needed = netbk_max_required_rx_slots(netif);
return ((netif->rx.sring->req_prod - peek) < needed) ||
((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
}
int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
netif_t *netif = netdev_priv(dev);
@@ -143,30 +244,26 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
BUG_ON(skb->dev != dev);
/* Drop the packet if the target domain has no receive buffers. */
if (!netif->active ||
(netif->rx_req_cons_peek == netif->rx.sring->req_prod) ||
((netif->rx_req_cons_peek - netif->rx.rsp_prod_pvt) ==
NET_RX_RING_SIZE))
if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev)))
goto drop;
if (unlikely(netbk_queue_full(netif))) {
/* Not a BUG_ON() -- misbehaving netfront can trigger this. */
if (netbk_can_queue(dev))
DPRINTK("Queue full but not stopped!\n");
goto drop;
}
/*
* We do not copy the packet unless:
* 1. The data is shared; or
* 2. The data is not allocated from our special cache.
* NB. We also couldn't cope with fragmented packets, but we won't get
* any because we not advertise the NETIF_F_SG feature.
* 3. The data is fragmented.
*/
if (skb_shared(skb) || skb_cloned(skb) || !is_xen_skb(skb)) {
int hlen = skb->data - skb->head;
int ret;
struct sk_buff *nskb = dev_alloc_skb(hlen + skb->len);
if (skb_cloned(skb) || skb_is_nonlinear(skb) || !is_xen_skb(skb)) {
struct sk_buff *nskb = netbk_copy_skb(skb);
if ( unlikely(nskb == NULL) )
goto drop;
skb_reserve(nskb, hlen);
__skb_put(nskb, skb->len);
ret = skb_copy_bits(skb, -hlen, nskb->data - hlen,
skb->len + hlen);
BUG_ON(ret);
/* Copy only the header fields we use in this driver. */
nskb->dev = skb->dev;
nskb->ip_summed = skb->ip_summed;
@@ -175,9 +272,18 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb = nskb;
}
netif->rx_req_cons_peek++;
netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
!!skb_shinfo(skb)->gso_size;
netif_get(netif);
if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
netif->rx.sring->req_event = netif->rx_req_cons_peek +
netbk_max_required_rx_slots(netif);
mb(); /* request notification /then/ check & stop the queue */
if (netbk_queue_full(netif))
netif_stop_queue(dev);
}
skb_queue_tail(&rx_queue, skb);
tasklet_schedule(&net_rx_tasklet);
@@ -208,116 +314,85 @@ int xen_network_done(void)
}
#endif
static void net_rx_action(unsigned long unused)
static u16 netbk_gop_frag(netif_t *netif, struct page *page, int count, int i)
{
netif_t *netif = NULL;
s8 status;
u16 size, id, irq, flags;
multicall_entry_t *mcl;
mmu_update_t *mmu;
gnttab_transfer_t *gop;
unsigned long vdata, old_mfn, new_mfn;
struct sk_buff_head rxq;
struct sk_buff *skb;
int notify_nr = 0;
int ret;
/*
* Putting hundreds of bytes on the stack is considered rude.
* Static works because a tasklet can only be on one CPU at any time.
*/
static u16 notify_list[NET_RX_RING_SIZE];
multicall_entry_t *mcl = rx_mcl + count;
mmu_update_t *mmu = rx_mmu + count;
gnttab_transfer_t *gop = grant_rx_op + count;
netif_rx_request_t *req;
unsigned long old_mfn, new_mfn;
skb_queue_head_init(&rxq);
mcl = rx_mcl;
mmu = rx_mmu;
gop = grant_rx_op;
while ((skb = skb_dequeue(&rx_queue)) != NULL) {
netif = netdev_priv(skb->dev);
vdata = (unsigned long)skb->data;
old_mfn = virt_to_mfn(vdata);
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
/* Memory squeeze? Back off for an arbitrary while. */
if ((new_mfn = alloc_mfn()) == 0) {
if ( net_ratelimit() )
WPRINTK("Memory squeeze in netback "
"driver.\n");
mod_timer(&net_timer, jiffies + HZ);
skb_queue_head(&rx_queue, skb);
break;
}
/*
* Set the new P2M table entry before reassigning
* the old data page. Heed the comment in
* pgtable-2level.h:pte_page(). :-)
*/
set_phys_to_machine(
__pa(skb->data) >> PAGE_SHIFT,
new_mfn);
MULTI_update_va_mapping(mcl, vdata,
pfn_pte_ma(new_mfn,
PAGE_KERNEL), 0);
mcl++;
mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
MMU_MACHPHYS_UPDATE;
mmu->val = __pa(vdata) >> PAGE_SHIFT;
mmu++;
}
gop->mfn = old_mfn;
gop->domid = netif->domid;
gop->ref = RING_GET_REQUEST(
&netif->rx, netif->rx.req_cons)->gref;
netif->rx.req_cons++;
gop++;
__skb_queue_tail(&rxq, skb);
/* Filled the batch queue? */
if ((gop - grant_rx_op) == ARRAY_SIZE(grant_rx_op))
break;
}
old_mfn = virt_to_mfn(page_address(page));
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
if (mcl == rx_mcl)
return;
new_mfn = alloc_mfn();
mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
/*
* Set the new P2M table entry before reassigning
* the old data page. Heed the comment in
* pgtable-2level.h:pte_page(). :-)
*/
set_phys_to_machine(page_to_pfn(page), new_mfn);
if (mmu - rx_mmu) {
mcl->op = __HYPERVISOR_mmu_update;
mcl->args[0] = (unsigned long)rx_mmu;
mcl->args[1] = mmu - rx_mmu;
mcl->args[2] = 0;
mcl->args[3] = DOMID_SELF;
mcl++;
}
MULTI_update_va_mapping(mcl, (unsigned long)page_address(page),
pfn_pte_ma(new_mfn, PAGE_KERNEL), 0);
ret = HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl);
BUG_ON(ret != 0);
mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
MMU_MACHPHYS_UPDATE;
mmu->val = page_to_pfn(page);
}
ret = HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op,
gop - grant_rx_op);
BUG_ON(ret != 0);
req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
gop->mfn = old_mfn;
gop->domid = netif->domid;
gop->ref = req->gref;
return req->id;
}
mcl = rx_mcl;
gop = grant_rx_op;
while ((skb = __skb_dequeue(&rxq)) != NULL) {
netif = netdev_priv(skb->dev);
size = skb->tail - skb->data;
static void netbk_gop_skb(struct sk_buff *skb, struct netbk_rx_meta *meta,
int count)
{
netif_t *netif = netdev_priv(skb->dev);
int nr_frags = skb_shinfo(skb)->nr_frags;
int i;
int extra;
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->frag_list = NULL;
meta[count].frag.page_offset = skb_shinfo(skb)->gso_type;
meta[count].frag.size = skb_shinfo(skb)->gso_size;
extra = !!meta[count].frag.size + 1;
netif->stats.tx_bytes += size;
netif->stats.tx_packets++;
for (i = 0; i < nr_frags; i++) {
meta[++count].frag = skb_shinfo(skb)->frags[i];
meta[count].id = netbk_gop_frag(netif, meta[count].frag.page,
count, i + extra);
}
/*
* This must occur at the end to ensure that we don't trash
* skb_shinfo until we're done.
*/
meta[count - nr_frags].id = netbk_gop_frag(netif,
virt_to_page(skb->data),
count - nr_frags, 0);
netif->rx.req_cons += nr_frags + extra;
}
static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta)
{
int i;
for (i = 0; i < nr_frags; i++)
put_page(meta[i].frag.page);
}
static int netbk_check_gop(int nr_frags, domid_t domid, int count)
{
multicall_entry_t *mcl = rx_mcl + count;
gnttab_transfer_t *gop = grant_rx_op + count;
int status = NETIF_RSP_OKAY;
int i;
for (i = 0; i <= nr_frags; i++) {
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
/* The update_va_mapping() must not fail. */
BUG_ON(mcl->result != 0);
@@ -325,10 +400,9 @@ static void net_rx_action(unsigned long unused)
}
/* Check the reassignment error code. */
status = NETIF_RSP_OKAY;
if (gop->status != 0) {
DPRINTK("Bad status %d from grant transfer to DOM%u\n",
gop->status, netif->domid);
gop->status, domid);
/*
* Page no longer belongs to us unless GNTST_bad_page,
* but that should be a fatal error anyway.
@@ -336,24 +410,166 @@ static void net_rx_action(unsigned long unused)
BUG_ON(gop->status == GNTST_bad_page);
status = NETIF_RSP_ERROR;
}
irq = netif->irq;
id = RING_GET_REQUEST(&netif->rx, netif->rx.rsp_prod_pvt)->id;
flags = 0;
gop++;
}
return status;
}
static void netbk_add_frag_responses(netif_t *netif, int status,
struct netbk_rx_meta *meta, int nr_frags)
{
int i;
for (i = 0; i < nr_frags; i++) {
int id = meta[i].id;
int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
make_rx_response(netif, id, status, meta[i].frag.page_offset,
meta[i].frag.size, flags);
}
}
static void net_rx_action(unsigned long unused)
{
netif_t *netif = NULL;
s8 status;
u16 id, irq, flags;
netif_rx_response_t *resp;
struct netif_extra_info *extra;
multicall_entry_t *mcl;
struct sk_buff_head rxq;
struct sk_buff *skb;
int notify_nr = 0;
int ret;
int nr_frags;
int count;
/*
* Putting hundreds of bytes on the stack is considered rude.
* Static works because a tasklet can only be on one CPU at any time.
*/
static u16 notify_list[NET_RX_RING_SIZE];
static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
skb_queue_head_init(&rxq);
count = 0;
while ((skb = skb_dequeue(&rx_queue)) != NULL) {
nr_frags = skb_shinfo(skb)->nr_frags;
*(int *)skb->cb = nr_frags;
if (!xen_feature(XENFEAT_auto_translated_physmap) &&
check_mfn(nr_frags + 1)) {
/* Memory squeeze? Back off for an arbitrary while. */
if ( net_ratelimit() )
WPRINTK("Memory squeeze in netback "
"driver.\n");
mod_timer(&net_timer, jiffies + HZ);
skb_queue_head(&rx_queue, skb);
break;
}
netbk_gop_skb(skb, meta, count);
count += nr_frags + 1;
__skb_queue_tail(&rxq, skb);
/* Filled the batch queue? */
if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
break;
}
if (!count)
return;
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
mcl = rx_mcl + count;
mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
mcl->op = __HYPERVISOR_mmu_update;
mcl->args[0] = (unsigned long)rx_mmu;
mcl->args[1] = count;
mcl->args[2] = 0;
mcl->args[3] = DOMID_SELF;
ret = HYPERVISOR_multicall(rx_mcl, count + 1);
BUG_ON(ret != 0);
}
ret = HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op, count);
BUG_ON(ret != 0);
count = 0;
while ((skb = __skb_dequeue(&rxq)) != NULL) {
nr_frags = *(int *)skb->cb;
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->frag_list = NULL;
netif = netdev_priv(skb->dev);
netif->stats.tx_bytes += skb->len;
netif->stats.tx_packets++;
netbk_free_pages(nr_frags, meta + count + 1);
status = netbk_check_gop(nr_frags, netif->domid, count);
id = meta[count].id;
flags = nr_frags ? NETRXF_more_data : 0;
if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
flags |= NETRXF_csum_blank | NETRXF_data_validated;
else if (skb->proto_data_valid) /* remote but checksummed? */
flags |= NETRXF_data_validated;
if (make_rx_response(netif, id, status,
(unsigned long)skb->data & ~PAGE_MASK,
size, flags) &&
(rx_notify[irq] == 0)) {
resp = make_rx_response(netif, id, status,
offset_in_page(skb->data),
skb_headlen(skb), flags);
extra = NULL;
if (meta[count].frag.size) {
struct netif_extra_info *gso =
(struct netif_extra_info *)
RING_GET_RESPONSE(&netif->rx,
netif->rx.rsp_prod_pvt++);
if (extra)
extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
else
resp->flags |= NETRXF_extra_info;
gso->u.gso.size = meta[count].frag.size;
gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
gso->u.gso.pad = 0;
gso->u.gso.features = 0;
gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
gso->flags = 0;
extra = gso;
}
netbk_add_frag_responses(netif, status, meta + count + 1,
nr_frags);
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
irq = netif->irq;
if (ret && !rx_notify[irq]) {
rx_notify[irq] = 1;
notify_list[notify_nr++] = irq;
}
if (netif_queue_stopped(netif->dev) &&
!netbk_queue_full(netif))
netif_wake_queue(netif->dev);
netif_put(netif);
dev_kfree_skb(skb);
gop++;
count += nr_frags + 1;
}
while (notify_nr != 0) {
@@ -404,7 +620,9 @@ static void add_to_net_schedule_list_tail(netif_t *netif)
return;
spin_lock_irq(&net_schedule_list_lock);
if (!__on_net_schedule_list(netif) && netif->active) {
if (!__on_net_schedule_list(netif) &&
likely(netif_running(netif->dev) &&
netif_carrier_ok(netif->dev))) {
list_add_tail(&netif->list, &net_schedule_list);
netif_get(netif);
}
@@ -972,8 +1190,13 @@ static void netif_page_release(struct page *page)
irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
{
netif_t *netif = dev_id;
add_to_net_schedule_list_tail(netif);
maybe_schedule_tx_action();
if (netif_queue_stopped(netif->dev) && !netbk_queue_full(netif))
netif_wake_queue(netif->dev);
return IRQ_HANDLED;
}
@@ -1007,16 +1230,15 @@ static void make_tx_response(netif_t *netif,
#endif
}
static int make_rx_response(netif_t *netif,
u16 id,
s8 st,
u16 offset,
u16 size,
u16 flags)
static netif_rx_response_t *make_rx_response(netif_t *netif,
u16 id,
s8 st,
u16 offset,
u16 size,
u16 flags)
{
RING_IDX i = netif->rx.rsp_prod_pvt;
netif_rx_response_t *resp;
int notify;
resp = RING_GET_RESPONSE(&netif->rx, i);
resp->offset = offset;
@@ -1027,9 +1249,8 @@ static int make_rx_response(netif_t *netif,
resp->status = (s16)st;
netif->rx.rsp_prod_pvt = ++i;
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, notify);
return notify;
return resp;
}
#ifdef NETBE_DEBUG_INTERRUPT
@@ -101,14 +101,12 @@ static int netback_probe(struct xenbus_device *dev,
goto abort_transaction;
}
#if 0 /* KAF: After the protocol is finalised. */
err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
"%d", 1);
if (err) {
message = "writing feature-gso-tcpv4";
goto abort_transaction;
}
#endif
err = xenbus_transaction_end(xbt, 0);
} while (err == -EAGAIN);
@@ -353,6 +351,7 @@ static int connect_rings(struct backend_info *be)
unsigned long tx_ring_ref, rx_ring_ref;
unsigned int evtchn;
int err;
int val;
DPRINTK("");
@@ -367,6 +366,30 @@ static int connect_rings(struct backend_info *be)
return err;
}
if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-rx-notify", "%d",
&val) < 0)
val = 0;
if (val)
be->netif->can_queue = 1;
else
/* Must be non-zero for pfifo_fast to work. */
be->netif->dev->tx_queue_len = 1;
if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d", &val) < 0)
val = 0;
if (val) {
be->netif->features |= NETIF_F_SG;
be->netif->dev->features |= NETIF_F_SG;
}
if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", "%d",
&val) < 0)
val = 0;
if (val) {
be->netif->features |= NETIF_F_TSO;
be->netif->dev->features |= NETIF_F_TSO;
}
/* Map the shared frame, irq etc. */
err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
if (err) {
@@ -46,11 +46,11 @@
#include <linux/ethtool.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/io.h>
#include <net/sock.h>
#include <net/pkt_sched.h>
#include <net/arp.h>
#include <net/route.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <xen/evtchn.h>
#include <xen/xenbus.h>
@@ -62,18 +62,13 @@
#include <xen/interface/grant_table.h>
#include <xen/gnttab.h>
#define RX_COPY_THRESHOLD 256
#define GRANT_INVALID_REF 0
#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
static inline void init_skb_shinfo(struct sk_buff *skb)
{
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->frag_list = NULL;
}
struct netfront_info {
struct list_head list;
struct net_device *netdev;
@@ -99,17 +94,17 @@ struct netfront_info {
struct timer_list rx_refill_timer;
/*
* {tx,rx}_skbs store outstanding skbuffs. The first entry in each
* array is an index into a chain of free entries.
* {tx,rx}_skbs store outstanding skbuffs. The first entry in tx_skbs
* is an index into a chain of free entries.
*/
struct sk_buff *tx_skbs[NET_TX_RING_SIZE+1];
struct sk_buff *rx_skbs[NET_RX_RING_SIZE+1];
struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
grant_ref_t gref_tx_head;
grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1];
grant_ref_t gref_rx_head;
grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1];
grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
struct xenbus_device *xbdev;
int tx_ring_ref;
@@ -121,8 +116,13 @@ struct netfront_info {
struct mmu_update rx_mmu[NET_RX_RING_SIZE];
};
struct netfront_rx_info {
struct netif_rx_response rx;
struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
};
/*
* Access macros for acquiring freeing slots in {tx,rx}_skbs[].
* Access macros for acquiring freeing slots in tx_skbs[].
*/
static inline void add_id_to_freelist(struct sk_buff **list, unsigned short id)
@@ -138,6 +138,29 @@ static inline unsigned short get_id_from_freelist(struct sk_buff **list)
return id;
}
static inline int xennet_rxidx(RING_IDX idx)
{
return idx & (NET_RX_RING_SIZE - 1);
}
static inline struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
RING_IDX ri)
{
int i = xennet_rxidx(ri);
struct sk_buff *skb = np->rx_skbs[i];
np->rx_skbs[i] = NULL;
return skb;
}
static inline grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
RING_IDX ri)
{
int i = xennet_rxidx(ri);
grant_ref_t ref = np->grant_rx_ref[i];
np->grant_rx_ref[i] = GRANT_INVALID_REF;
return ref;
}
#define DPRINTK(fmt, args...) \
pr_debug("netfront (%s:%d) " fmt, \
__FUNCTION__, __LINE__, ##args)
@@ -303,6 +326,24 @@ again:
goto abort_transaction;
}
err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
if (err) {
message = "writing feature-rx-notify";
goto abort_transaction;
}
err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
if (err) {
message = "writing feature-sg";
goto abort_transaction;
}
err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
if (err) {
message = "writing feature-gso-tcpv4";
goto abort_transaction;
}
err = xenbus_transaction_end(xbt, 0);
if (err) {
if (err == -EAGAIN)
@@ -456,6 +497,9 @@ static int network_open(struct net_device *dev)
network_alloc_rx_buffers(dev);
np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
netif_rx_schedule(dev);
netif_start_queue(dev);
return 0;
@@ -546,10 +590,13 @@ static void network_alloc_rx_buffers(struct net_device *dev)
unsigned short id;
struct netfront_info *np = netdev_priv(dev);
struct sk_buff *skb;
int i, batch_target;
struct page *page;
int i, batch_target, notify;
RING_IDX req_prod = np->rx.req_prod_pvt;
struct xen_memory_reservation reservation;
grant_ref_t ref;
unsigned long pfn;
void *vaddr;
if (unlikely(!netif_carrier_ok(dev)))
return;
@@ -562,29 +609,36 @@ static void network_alloc_rx_buffers(struct net_device *dev)
*/
batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
/*
* Subtract dev_alloc_skb headroom (16 bytes) and shared info
* tailroom then round down to SKB_DATA_ALIGN boundary.
*/
skb = __dev_alloc_skb(
((PAGE_SIZE - sizeof(struct skb_shared_info)) &
(-SKB_DATA_ALIGN(1))) - 16,
GFP_ATOMIC|__GFP_NOWARN);
if (skb == NULL) {
/* Allocate an skb and a page. */
skb = __dev_alloc_skb(RX_COPY_THRESHOLD,
GFP_ATOMIC | __GFP_NOWARN);
if (unlikely(!skb))
goto no_skb;
page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
if (!page) {
kfree_skb(skb);
no_skb:
/* Any skbuffs queued for refill? Force them out. */
if (i != 0)
goto refill;
/* Could not allocate any skbuffs. Try again later. */
mod_timer(&np->rx_refill_timer,
jiffies + (HZ/10));
return;
break;
}
skb_shinfo(skb)->frags[0].page = page;
skb_shinfo(skb)->nr_frags = 1;
__skb_queue_tail(&np->rx_batch, skb);
}
/* Is the batch large enough to be worthwhile? */
if (i < (np->rx_target/2))
if (i < (np->rx_target/2)) {
if (req_prod > np->rx.sring->req_prod)
goto push;
return;
}
/* Adjust our fill target if we risked running out of buffers. */
if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
@@ -598,26 +652,29 @@ static void network_alloc_rx_buffers(struct net_device *dev)
skb->dev = dev;
id = get_id_from_freelist(np->rx_skbs);
id = xennet_rxidx(req_prod + i);
BUG_ON(np->rx_skbs[id]);
np->rx_skbs[id] = skb;
RING_GET_REQUEST(&np->rx, req_prod + i)->id = id;
ref = gnttab_claim_grant_reference(&np->gref_rx_head);
BUG_ON((signed short)ref < 0);
np->grant_rx_ref[id] = ref;
pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
vaddr = page_address(skb_shinfo(skb)->frags[0].page);
gnttab_grant_foreign_transfer_ref(ref,
np->xbdev->otherend_id,
__pa(skb->head)>>PAGE_SHIFT);
np->xbdev->otherend_id, pfn);
RING_GET_REQUEST(&np->rx, req_prod + i)->gref = ref;
np->rx_pfn_array[i] = virt_to_mfn(skb->head);
np->rx_pfn_array[i] = pfn_to_mfn(pfn);
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
/* Remove this page before passing back to Xen. */
set_phys_to_machine(__pa(skb->head) >> PAGE_SHIFT,
INVALID_P2M_ENTRY);
set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
MULTI_update_va_mapping(np->rx_mcl+i,
(unsigned long)skb->head,
(unsigned long)vaddr,
__pte(0), 0);
}
}
@@ -654,7 +711,10 @@ static void network_alloc_rx_buffers(struct net_device *dev)
/* Above is a suitable barrier to ensure backend will see requests. */
np->rx.req_prod_pvt = req_prod + i;
RING_PUSH_REQUESTS(&np->rx);
push:
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
if (notify)
notify_remote_via_irq(np->irq);
}
static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
@@ -840,20 +900,232 @@ static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
return IRQ_HANDLED;
}
static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
grant_ref_t ref)
{
int new = xennet_rxidx(np->rx.req_prod_pvt);
BUG_ON(np->rx_skbs[new]);
np->rx_skbs[new] = skb;
np->grant_rx_ref[new] = ref;
RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
np->rx.req_prod_pvt++;
}
int xennet_get_extras(struct netfront_info *np,
struct netif_extra_info *extras, RING_IDX rp)
{
struct netif_extra_info *extra;
RING_IDX cons = np->rx.rsp_cons;
int err = 0;
do {
struct sk_buff *skb;
grant_ref_t ref;
if (unlikely(cons + 1 == rp)) {
if (net_ratelimit())
WPRINTK("Missing extra info\n");
err = -EBADR;
break;
}
extra = (struct netif_extra_info *)
RING_GET_RESPONSE(&np->rx, ++cons);
if (unlikely(!extra->type ||
extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
if (net_ratelimit())
WPRINTK("Invalid extra type: %d\n",
extra->type);
err = -EINVAL;
} else
memcpy(&extras[extra->type - 1], extra, sizeof(*extra));
skb = xennet_get_rx_skb(np, cons);
ref = xennet_get_rx_ref(np, cons);
xennet_move_rx_slot(np, skb, ref);
} while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
np->rx.rsp_cons = cons;
return err;
}
static int xennet_get_responses(struct netfront_info *np,
struct netfront_rx_info *rinfo, RING_IDX rp,
struct sk_buff_head *list, int count)
{
struct mmu_update *mmu = np->rx_mmu + count;
struct multicall_entry *mcl = np->rx_mcl + count;
struct netif_rx_response *rx = &rinfo->rx;
struct netif_extra_info *extras = rinfo->extras;
RING_IDX cons = np->rx.rsp_cons;
struct sk_buff *skb = xennet_get_rx_skb(np, cons);
grant_ref_t ref = xennet_get_rx_ref(np, cons);
int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
int frags = 1;
int err = 0;
if (rx->flags & NETRXF_extra_info) {
err = xennet_get_extras(np, extras, rp);
cons = np->rx.rsp_cons;
}
for (;;) {
unsigned long mfn;
if (unlikely(rx->status < 0 ||
rx->offset + rx->status > PAGE_SIZE)) {
if (net_ratelimit())
WPRINTK("rx->offset: %x, size: %u\n",
rx->offset, rx->status);
err = -EINVAL;
}
/*
* This definitely indicates a bug, either in this driver or in
* the backend driver. In future this should flag the bad
* situation to the system controller to reboot the backed.
*/
if (ref == GRANT_INVALID_REF) {
WPRINTK("Bad rx response id %d.\n", rx->id);
err = -EINVAL;
goto next;
}
/* Memory pressure, insufficient buffer headroom, ... */
if ((mfn = gnttab_end_foreign_transfer_ref(ref)) == 0) {
if (net_ratelimit())
WPRINTK("Unfulfilled rx req (id=%d, st=%d).\n",
rx->id, rx->status);
xennet_move_rx_slot(np, skb, ref);
err = -ENOMEM;
goto next;
}
gnttab_release_grant_reference(&np->gref_rx_head, ref);
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
/* Remap the page. */
struct page *page = skb_shinfo(skb)->frags[0].page;
unsigned long pfn = page_to_pfn(page);
void *vaddr = page_address(page);
MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
pfn_pte_ma(mfn, PAGE_KERNEL),
0);
mcl++;
mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT)
| MMU_MACHPHYS_UPDATE;
mmu->val = pfn;
mmu++;
set_phys_to_machine(pfn, mfn);
}
__skb_queue_tail(list, skb);
next:
if (!(rx->flags & NETRXF_more_data))
break;
if (cons + frags == rp) {
if (net_ratelimit())
WPRINTK("Need more frags\n");
err = -ENOENT;
break;
}
rx = RING_GET_RESPONSE(&np->rx, cons + frags);
skb = xennet_get_rx_skb(np, cons + frags);
ref = xennet_get_rx_ref(np, cons + frags);
frags++;
}
if (unlikely(frags > max)) {
if (net_ratelimit())
WPRINTK("Too many frags\n");
err = -E2BIG;
}
return err;
}
static RING_IDX xennet_fill_frags(struct netfront_info *np,
struct sk_buff *skb,
struct sk_buff_head *list)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
int nr_frags = shinfo->nr_frags;
RING_IDX cons = np->rx.rsp_cons;
skb_frag_t *frag = shinfo->frags + nr_frags;
struct sk_buff *nskb;
while ((nskb = __skb_dequeue(list))) {
struct netif_rx_response *rx =
RING_GET_RESPONSE(&np->rx, ++cons);
frag->page = skb_shinfo(nskb)->frags[0].page;
frag->page_offset = rx->offset;
frag->size = rx->status;
skb->data_len += rx->status;
skb_shinfo(nskb)->nr_frags = 0;
kfree_skb(nskb);
frag++;
nr_frags++;
}
shinfo->nr_frags = nr_frags;
return cons;
}
static int xennet_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
{
if (!gso->u.gso.size) {
if (net_ratelimit())
WPRINTK("GSO size must not be zero.\n");
return -EINVAL;
}
/* Currently only TCPv4 S.O. is supported. */
if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
if (net_ratelimit())
WPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
return -EINVAL;
}
skb_shinfo(skb)->gso_size = gso->u.gso.size;
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
/* Header must be checked, and gso_segs computed. */
skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
skb_shinfo(skb)->gso_segs = 0;
return 0;
}
static int netif_poll(struct net_device *dev, int *pbudget)
{
struct netfront_info *np = netdev_priv(dev);
struct sk_buff *skb, *nskb;
struct netif_rx_response *rx;
struct sk_buff *skb;
struct netfront_rx_info rinfo;
struct netif_rx_response *rx = &rinfo.rx;
struct netif_extra_info *extras = rinfo.extras;
RING_IDX i, rp;
struct mmu_update *mmu = np->rx_mmu;
struct multicall_entry *mcl = np->rx_mcl;
struct multicall_entry *mcl;
int work_done, budget, more_to_do = 1;
struct sk_buff_head rxq;
struct sk_buff_head errq;
struct sk_buff_head tmpq;
unsigned long flags;
unsigned long mfn;
grant_ref_t ref;
unsigned int len;
int pages_done;
int err;
spin_lock(&np->rx_lock);
@@ -863,53 +1135,66 @@ static int netif_poll(struct net_device *dev, int *pbudget)
}
skb_queue_head_init(&rxq);
skb_queue_head_init(&errq);
skb_queue_head_init(&tmpq);
if ((budget = *pbudget) > dev->quota)
budget = dev->quota;
rp = np->rx.sring->rsp_prod;
rmb(); /* Ensure we see queued responses up to 'rp'. */
for (i = np->rx.rsp_cons, work_done = 0;
for (i = np->rx.rsp_cons, work_done = 0, pages_done = 0;
(i != rp) && (work_done < budget);
i++, work_done++) {
rx = RING_GET_RESPONSE(&np->rx, i);
np->rx.rsp_cons = ++i, work_done++) {
memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
memset(extras, 0, sizeof(extras));
/*
* This definitely indicates a bug, either in this driver or in
* the backend driver. In future this should flag the bad
* situation to the system controller to reboot the backed.
*/
if ((ref = np->grant_rx_ref[rx->id]) == GRANT_INVALID_REF) {
WPRINTK("Bad rx response id %d.\n", rx->id);
err = xennet_get_responses(np, &rinfo, rp, &tmpq, pages_done);
pages_done += skb_queue_len(&tmpq);
if (unlikely(err)) {
err:
i = np->rx.rsp_cons + skb_queue_len(&tmpq) - 1;
work_done--;
while ((skb = __skb_dequeue(&tmpq)))
__skb_queue_tail(&errq, skb);
np->stats.rx_errors++;
continue;
}
/* Memory pressure, insufficient buffer headroom, ... */
if ((mfn = gnttab_end_foreign_transfer_ref(ref)) == 0) {
if (net_ratelimit())
WPRINTK("Unfulfilled rx req (id=%d, st=%d).\n",
rx->id, rx->status);
RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id =
rx->id;
RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref =
ref;
np->rx.req_prod_pvt++;
RING_PUSH_REQUESTS(&np->rx);
work_done--;
continue;
skb = __skb_dequeue(&tmpq);
if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
struct netif_extra_info *gso;
gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
if (unlikely(xennet_set_skb_gso(skb, gso))) {
__skb_queue_head(&tmpq, skb);
goto err;
}
}
gnttab_release_grant_reference(&np->gref_rx_head, ref);
np->grant_rx_ref[rx->id] = GRANT_INVALID_REF;
skb->nh.raw = (void *)skb_shinfo(skb)->frags[0].page;
skb->h.raw = skb->nh.raw + rx->offset;
skb = np->rx_skbs[rx->id];
add_id_to_freelist(np->rx_skbs, rx->id);
len = rx->status;
if (len > RX_COPY_THRESHOLD)
len = RX_COPY_THRESHOLD;
skb_put(skb, len);
/* NB. We handle skb overflow later. */
skb->data = skb->head + rx->offset;
skb->len = rx->status;
skb->tail = skb->data + skb->len;
if (rx->status > len) {
skb_shinfo(skb)->frags[0].page_offset =
rx->offset + len;
skb_shinfo(skb)->frags[0].size = rx->status - len;
skb->data_len = rx->status - len;
} else {
skb_shinfo(skb)->frags[0].page = NULL;
skb_shinfo(skb)->nr_frags = 0;
}
i = xennet_fill_frags(np, skb, &tmpq);
skb->truesize += skb->data_len;
skb->len += skb->data_len;
/*
* Old backends do not assert data_validated but we
@@ -925,96 +1210,38 @@ static int netif_poll(struct net_device *dev, int *pbudget)
skb->proto_csum_blank = !!(rx->flags & NETRXF_csum_blank);
np->stats.rx_packets++;
np->stats.rx_bytes += rx->status;
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
/* Remap the page. */
MULTI_update_va_mapping(mcl, (unsigned long)skb->head,
pfn_pte_ma(mfn, PAGE_KERNEL),
0);
mcl++;
mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT)
| MMU_MACHPHYS_UPDATE;
mmu->val = __pa(skb->head) >> PAGE_SHIFT;
mmu++;
set_phys_to_machine(__pa(skb->head) >> PAGE_SHIFT,
mfn);
}
np->stats.rx_bytes += skb->len;
__skb_queue_tail(&rxq, skb);
}
/* Some pages are no longer absent... */
balloon_update_driver_allowance(-work_done);
balloon_update_driver_allowance(-pages_done);
/* Do all the remapping work, and M2P updates, in one big hypercall. */
if (likely((mcl - np->rx_mcl) != 0)) {
if (likely(pages_done)) {
mcl = np->rx_mcl + pages_done;
mcl->op = __HYPERVISOR_mmu_update;
mcl->args[0] = (unsigned long)np->rx_mmu;
mcl->args[1] = mmu - np->rx_mmu;
mcl->args[1] = pages_done;
mcl->args[2] = 0;
mcl->args[3] = DOMID_SELF;
mcl++;
(void)HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
(void)HYPERVISOR_multicall(np->rx_mcl, pages_done + 1);
}
while ((skb = __skb_dequeue(&errq)))
kfree_skb(skb);
while ((skb = __skb_dequeue(&rxq)) != NULL) {
if (skb->len > (dev->mtu + ETH_HLEN + 4)) {
if (net_ratelimit())
printk(KERN_INFO "Received packet too big for "
"MTU (%d > %d)\n",
skb->len - ETH_HLEN - 4, dev->mtu);
skb->len = 0;
skb->tail = skb->data;
init_skb_shinfo(skb);
dev_kfree_skb(skb);
continue;
}
struct page *page = (struct page *)skb->nh.raw;
void *vaddr = page_address(page);
/*
* Enough room in skbuff for the data we were passed? Also,
* Linux expects at least 16 bytes headroom in each rx buffer.
*/
if (unlikely(skb->tail > skb->end) ||
unlikely((skb->data - skb->head) < 16)) {
if (net_ratelimit()) {
if (skb->tail > skb->end)
printk(KERN_INFO "Received packet "
"is %zd bytes beyond tail.\n",
skb->tail - skb->end);
else
printk(KERN_INFO "Received packet "
"is %zd bytes before head.\n",
16 - (skb->data - skb->head));
}
memcpy(skb->data, vaddr + (skb->h.raw - skb->nh.raw),
skb_headlen(skb));
nskb = __dev_alloc_skb(skb->len + 2,
GFP_ATOMIC|__GFP_NOWARN);
if (nskb != NULL) {
skb_reserve(nskb, 2);
skb_put(nskb, skb->len);
memcpy(nskb->data, skb->data, skb->len);
/* Copy any other fields we already set up. */
nskb->dev = skb->dev;
nskb->ip_summed = skb->ip_summed;
nskb->proto_data_valid = skb->proto_data_valid;
nskb->proto_csum_blank = skb->proto_csum_blank;
}
if (page != skb_shinfo(skb)->frags[0].page)
__free_page(page);
/* Reinitialise and then destroy the old skbuff. */
skb->len = 0;
skb->tail = skb->data;
init_skb_shinfo(skb);
dev_kfree_skb(skb);
/* Switch old for new, if we copied the buffer. */
if ((skb = nskb) == NULL)
continue;
}
/* Set the shinfo area, which is hidden behind the data. */
init_skb_shinfo(skb);
/* Ethernet work: Delayed to here as it peeks the header. */
skb->protocol = eth_type_trans(skb, dev);
@@ -1023,8 +1250,6 @@ static int netif_poll(struct net_device *dev, int *pbudget)
dev->last_rx = jiffies;
}
np->rx.rsp_cons = i;
/* If we get a callback with very few responses, reduce fill target. */
/* NB. Note exponential increase, linear decrease. */
if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
@@ -1103,9 +1328,7 @@ static int xennet_set_tso(struct net_device *dev, u32 data)
if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
"feature-gso-tcpv4", "%d", &val) < 0)
val = 0;
#if 0 /* KAF: After the protocol is finalised. */
if (!val)
#endif
return -ENOSYS;
}
@@ -1128,6 +1351,7 @@ static void network_connect(struct net_device *dev)
struct netfront_info *np = netdev_priv(dev);
int i, requeue_idx;
struct sk_buff *skb;
grant_ref_t ref;
xennet_set_features(dev);
@@ -1158,20 +1382,24 @@ static void network_connect(struct net_device *dev)
}
/* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
for (requeue_idx = 0, i = 1; i <= NET_RX_RING_SIZE; i++) {
if ((unsigned long)np->rx_skbs[i] < PAGE_OFFSET)
for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
if (!np->rx_skbs[i])
continue;
skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
gnttab_grant_foreign_transfer_ref(
np->grant_rx_ref[i], np->xbdev->otherend_id,
__pa(np->rx_skbs[i]->data) >> PAGE_SHIFT);
RING_GET_REQUEST(&np->rx, requeue_idx)->gref =
np->grant_rx_ref[i];
RING_GET_REQUEST(&np->rx, requeue_idx)->id = i;
ref, np->xbdev->otherend_id,
page_to_pfn(skb_shinfo(skb)->frags->page));
RING_GET_REQUEST(&np->rx, requeue_idx)->gref = ref;
RING_GET_REQUEST(&np->rx, requeue_idx)->id = requeue_idx;
requeue_idx++;
}
np->rx.req_prod_pvt = requeue_idx;
RING_PUSH_REQUESTS(&np->rx);
/*
* Step 3: All public and private state should now be sane. Get
@@ -1392,8 +1620,8 @@ static struct net_device * __devinit create_netdev(int handle,
np->grant_tx_ref[i] = GRANT_INVALID_REF;
}
for (i = 0; i <= NET_RX_RING_SIZE; i++) {
np->rx_skbs[i] = (void *)((unsigned long) i+1);
for (i = 0; i < NET_RX_RING_SIZE; i++) {
np->rx_skbs[i] = NULL;
np->grant_rx_ref[i] = GRANT_INVALID_REF;
}
@@ -232,6 +232,10 @@ static int __devinit pcistub_match_one(struct pci_dev *dev,
&& dev->bus->number == pdev_id->bus
&& dev->devfn == pdev_id->devfn)
return 1;
/* Sometimes topmost bridge links to itself. */
if (dev == dev->bus->self)
break;
}
return 0;
@@ -445,6 +445,9 @@ static struct xenbus_driver xenbus_pciback_driver = {
int __init pciback_xenbus_register(void)
{
if (!is_running_on_xen())
return -ENODEV;
return xenbus_register_backend(&xenbus_pciback_driver);
}
@@ -105,7 +105,7 @@ static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
.size = size,
};
struct pcifront_sd *sd = bus->sysdata;
struct pcifront_device *pdev = sd->pdev;
struct pcifront_device *pdev = pcifront_get_pdev(sd);
if (verbose_request)
dev_info(&pdev->xdev->dev,
@@ -144,7 +144,7 @@ static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
.value = val,
};
struct pcifront_sd *sd = bus->sysdata;
struct pcifront_device *pdev = sd->pdev;
struct pcifront_device *pdev = pcifront_get_pdev(sd);
if (verbose_request)
dev_info(&pdev->xdev->dev,
@@ -207,12 +207,13 @@ int pcifront_scan_root(struct pcifront_device *pdev,
err = -ENOMEM;
goto err_out;
}
sd->domain = domain;
sd->pdev = pdev;
pcifront_init_sd(sd, domain, pdev);
b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd);
b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
&pcifront_bus_ops, sd);
if (!b) {
dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n");
dev_err(&pdev->xdev->dev,
"Error creating PCI Frontend Bus!\n");
err = -ENOMEM;
goto err_out;
}
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <xen/xenbus.h>
#include <xen/gnttab.h>
#include "pcifront.h"
#define INVALID_GRANT_REF (0)
@@ -283,11 +284,10 @@ static struct xenbus_driver xenbus_pcifront_driver = {
static int __init pcifront_init(void)
{
int err = 0;
if (!is_running_on_xen())
return -ENODEV;
err = xenbus_register_frontend(&xenbus_pcifront_driver);
return err;
return xenbus_register_frontend(&xenbus_pcifront_driver);
}
/* Initialize after the Xen PCI Frontend Stub is initialized */
@@ -270,6 +270,7 @@ static int __init privcmd_init(void)
set_bit(__HYPERVISOR_sched_op_compat, hypercall_permission_map);
set_bit(__HYPERVISOR_event_channel_op_compat,
hypercall_permission_map);
set_bit(__HYPERVISOR_hvm_op, hypercall_permission_map);
privcmd_intf = create_xen_proc_entry("privcmd", 0400);
if (privcmd_intf != NULL)
@@ -55,7 +55,6 @@ struct packet {
enum {
PACKET_FLAG_DISCARD_RESPONSE = 1,
PACKET_FLAG_CHECK_RESPONSESTATUS = 2,
};
/* local variables */
@@ -201,21 +200,6 @@ static void packet_free(struct packet *pak)
kfree(pak);
}
static int packet_set(struct packet *pak,
const unsigned char *buffer, u32 size)
{
int rc = 0;
unsigned char *buf = kmalloc(size, GFP_KERNEL);
if (buf) {
pak->data_buffer = buf;
memcpy(buf, buffer, size);
pak->data_len = size;
} else {
rc = -ENOMEM;
}
return rc;
}
/*
* Write data to the shared memory and send it to the FE.
@@ -225,29 +209,6 @@ static int packet_write(struct packet *pak,
{
int rc = 0;
if ((pak->flags & PACKET_FLAG_CHECK_RESPONSESTATUS)) {
#ifdef CONFIG_XEN_TPMDEV_CLOSE_IF_VTPM_FAILS
u32 res;
if (copy_from_buffer(&res,
&data[2 + 4], sizeof (res),
isuserbuffer)) {
return -EFAULT;
}
if (res != 0) {
/*
* Close down this device. Should have the
* FE notified about closure.
*/
if (!pak->tpmif) {
return -EFAULT;
}
pak->tpmif->status = DISCONNECTING;
}
#endif
}
if (0 != (pak->flags & PACKET_FLAG_DISCARD_RESPONSE)) {
/* Don't send a respone to this packet. Just acknowledge it. */
rc = size;
@@ -58,6 +58,9 @@ struct xenbus_dev_data {
/* In-progress transaction. */
struct list_head transactions;
/* Active watches. */
struct list_head watches;
/* Partial request. */
unsigned int len;
union {
@@ -70,6 +73,8 @@ struct xenbus_dev_data {
char read_buffer[PAGE_SIZE];
unsigned int read_cons, read_prod;
wait_queue_head_t read_waitq;
struct mutex reply_mutex;
};
static struct proc_dir_entry *xenbus_dev_intf;
@@ -100,14 +105,60 @@ static void queue_reply(struct xenbus_dev_data *u,
{
int i;
mutex_lock(&u->reply_mutex);
for (i = 0; i < len; i++, u->read_prod++)
u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer));
mutex_unlock(&u->reply_mutex);
wake_up(&u->read_waitq);
}
struct watch_adapter
{
struct list_head list;
struct xenbus_watch watch;
struct xenbus_dev_data *dev_data;
char *token;
};
static void free_watch_adapter (struct watch_adapter *watch)
{
kfree(watch->watch.node);
kfree(watch->token);
kfree(watch);
}
static void watch_fired(struct xenbus_watch *watch,
const char **vec,
unsigned int len)
{
struct watch_adapter *adap =
container_of(watch, struct watch_adapter, watch);
struct xsd_sockmsg hdr;
const char *path, *token;
int path_len, tok_len, body_len;
path = vec[XS_WATCH_PATH];
token = adap->token;
path_len = strlen(path) + 1;
tok_len = strlen(token) + 1;
body_len = path_len + tok_len;
hdr.type = XS_WATCH_EVENT;
hdr.len = body_len;
queue_reply(adap->dev_data, (char *)&hdr, sizeof(hdr));
queue_reply(adap->dev_data, (char *)path, path_len);
queue_reply(adap->dev_data, (char *)token, tok_len);
}
static LIST_HEAD(watch_list);
static ssize_t xenbus_dev_write(struct file *filp,
const char __user *ubuf,
size_t len, loff_t *ppos)
@@ -116,6 +167,9 @@ static ssize_t xenbus_dev_write(struct file *filp,
struct xenbus_dev_transaction *trans = NULL;
uint32_t msg_type;
void *reply;
char *path, *token;
struct watch_adapter *watch, *tmp_watch;
int err;
if ((len + u->len) > sizeof(u->u.buffer))
return -EINVAL;
@@ -169,6 +223,56 @@ static ssize_t xenbus_dev_write(struct file *filp,
kfree(reply);
break;
case XS_WATCH:
case XS_UNWATCH:
path = u->u.buffer + sizeof(u->u.msg);
token = memchr(path, 0, u->u.msg.len);
if (token == NULL)
return -EILSEQ;
token++;
if (msg_type == XS_WATCH) {
static const char * XS_WATCH_RESP = "OK";
struct xsd_sockmsg hdr;
watch = kmalloc(sizeof(*watch), GFP_KERNEL);
watch->watch.node = kmalloc(strlen(path)+1,
GFP_KERNEL);
strcpy((char *)watch->watch.node, path);
watch->watch.callback = watch_fired;
watch->token = kmalloc(strlen(token)+1, GFP_KERNEL);
strcpy(watch->token, token);
watch->dev_data = u;
err = register_xenbus_watch(&watch->watch);
if (err) {
free_watch_adapter(watch);
return err;
}
list_add(&watch->list, &u->watches);
hdr.type = XS_WATCH;
hdr.len = strlen(XS_WATCH_RESP) + 1;
queue_reply(u, (char *)&hdr, sizeof(hdr));
queue_reply(u, (char *)XS_WATCH_RESP, hdr.len);
} else {
list_for_each_entry_safe(watch, tmp_watch,
&u->watches, list) {
if (!strcmp(watch->token, token) &&
!strcmp(watch->watch.node, path))
break;
{
unregister_xenbus_watch(&watch->watch);
list_del(&watch->list);
free_watch_adapter(watch);
break;
}
}
}
break;
default:
return -EINVAL;
}
@@ -191,8 +295,11 @@ static int xenbus_dev_open(struct inode *inode, struct file *filp)
return -ENOMEM;
INIT_LIST_HEAD(&u->transactions);
INIT_LIST_HEAD(&u->watches);
init_waitqueue_head(&u->read_waitq);
mutex_init(&u->reply_mutex);
filp->private_data = u;
return 0;
@@ -202,6 +309,7 @@ static int xenbus_dev_release(struct inode *inode, struct file *filp)
{
struct xenbus_dev_data *u = filp->private_data;
struct xenbus_dev_transaction *trans, *tmp;
struct watch_adapter *watch, *tmp_watch;
list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
xenbus_transaction_end(trans->handle, 1);
@@ -209,6 +317,12 @@ static int xenbus_dev_release(struct inode *inode, struct file *filp)
kfree(trans);
}
list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
unregister_xenbus_watch(&watch->watch);
list_del(&watch->list);
free_watch_adapter(watch);
}
kfree(u);
return 0;
@@ -141,7 +141,9 @@ static int read_otherend_details(struct xenbus_device *xendev,
}
if (strlen(xendev->otherend) == 0 ||
!xenbus_exists(XBT_NIL, xendev->otherend, "")) {
xenbus_dev_fatal(xendev, -ENOENT, "missing other end from %s",
xenbus_dev_fatal(xendev, -ENOENT,
"unable to read other end from %s. "
"missing or inaccessible.",
xendev->nodename);
free_otherend_details(xendev);
return -ENOENT;
@@ -187,16 +187,14 @@ MULTI_update_va_mapping(
mcl->args[0] = va;
#if defined(CONFIG_X86_64)
mcl->args[1] = new_val.pte;
mcl->args[2] = flags;
#elif defined(CONFIG_X86_PAE)
mcl->args[1] = new_val.pte_low;
mcl->args[2] = new_val.pte_high;
mcl->args[3] = flags;
#else
mcl->args[1] = new_val.pte_low;
mcl->args[2] = 0;
mcl->args[3] = flags;
#endif
mcl->args[MULTI_UVMFLAGS_INDEX] = flags;
}
static inline void
@@ -208,19 +206,15 @@ MULTI_update_va_mapping_otherdomain(
mcl->args[0] = va;
#if defined(CONFIG_X86_64)
mcl->args[1] = new_val.pte;
mcl->args[2] = flags;
mcl->args[3] = domid;
#elif defined(CONFIG_X86_PAE)
mcl->args[1] = new_val.pte_low;
mcl->args[2] = new_val.pte_high;
mcl->args[3] = flags;
mcl->args[4] = domid;
#else
mcl->args[1] = new_val.pte_low;
mcl->args[2] = 0;
mcl->args[3] = flags;
mcl->args[4] = domid;
#endif
mcl->args[MULTI_UVMFLAGS_INDEX] = flags;
mcl->args[MULTI_UVMDOMID_INDEX] = domid;
}
#endif /* __HYPERVISOR_H__ */
@@ -12,6 +12,9 @@ typedef struct {
int size;
struct semaphore sem;
void *ldt;
#ifdef CONFIG_XEN
int has_foreign_mappings;
#endif
} mm_context_t;
/* mm/memory.c:exit_mmap hook */
@@ -23,7 +23,7 @@
(*(volatile signed char *)(&(x)->slock) <= 0)
#define __raw_spin_lock_string \
"\n1:\n" \
"\n1:\t" \
LOCK \
"decb %0\n\t" \
"jns 3f\n" \
@@ -35,7 +35,7 @@
"3:\n\t"
#define __raw_spin_lock_string_flags \
"\n1:\n" \
"\n1:\t" \
LOCK \
"decb %0\n\t" \
"jns 4f\n\t" \
@@ -17,6 +17,7 @@ typedef struct {
struct semaphore sem;
#ifdef CONFIG_XEN
unsigned pinned:1;
unsigned has_foreign_mappings:1;
struct list_head unpinned;
#endif
} mm_context_t;
+40 -2
View File
@@ -11,16 +11,30 @@
#ifdef __KERNEL__
#ifndef __ia64__
struct pcifront_device;
struct pci_bus;
struct pcifront_sd {
int domain;
struct pcifront_device *pdev;
};
struct pci_bus;
static inline struct pcifront_device *
pcifront_get_pdev(struct pcifront_sd *sd)
{
return sd->pdev;
}
#ifdef CONFIG_PCI_DOMAINS
static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain,
struct pcifront_device *pdev)
{
sd->domain = domain;
sd->pdev = pdev;
}
#if defined(CONFIG_PCI_DOMAINS)
static inline int pci_domain_nr(struct pci_bus *bus)
{
struct pcifront_sd *sd = bus->sysdata;
@@ -32,6 +46,30 @@ static inline int pci_proc_domain(struct pci_bus *bus)
}
#endif /* CONFIG_PCI_DOMAINS */
#else /* __ia64__ */
#include <asm/pci.h>
#define pcifront_sd pci_controller
static inline struct pcifront_device *
pcifront_get_pdev(struct pcifront_sd *sd)
{
return (struct pcifront_device *)sd->platform_data;
}
static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain,
struct pcifront_device *pdev)
{
sd->segment = domain;
sd->acpi_handle = NULL;
sd->iommu = NULL;
sd->windows = 0;
sd->window = NULL;
sd->platform_data = pdev;
}
#endif /* __ia64__ */
extern spinlock_t pci_bus_lock;
#endif /* __KERNEL__ */
+7 -12
View File
@@ -33,9 +33,7 @@ LIBS += -lcrypto
LIBS += -lz
LIBS += -L$(XEN_XENSTORE) -lxenstore
AIOLIBS := -L $(LIBAIO_DIR)
AIOLIBS += -laio
AIOLIBS += -static
AIOLIBS := $(LIBAIO_DIR)/libaio.a
BLK-OBJS := block-aio.o
BLK-OBJS += block-sync.o
@@ -49,21 +47,18 @@ all: $(IBIN) qcow-util
LINUX_ROOT := $(wildcard $(XEN_ROOT)/linux-2.6.*-xen-sparse)
blktapctrl:
blktapctrl: blktapctrl.c
$(CC) $(CFLAGS) -o blktapctrl $(LIBS) blktapctrl.c
tapdisk: $(BLK-OBJS)
tapdisk: $(BLK-OBJS) tapdisk.c
$(CC) $(CFLAGS) -o tapdisk $(BLK-OBJS) tapdisk.c \
$(AIOLIBS) $(LIBS)
.PHONY: qcow-util
qcow-util: img2qcow qcow2raw qcow-create
qcow-util: $(BLK-OBJS)
$(CC) $(CFLAGS) -o img2qcow $(BLK-OBJS) img2qcow.c \
$(AIOLIBS) $(LIBS)
$(CC) $(CFLAGS) -o qcow2raw $(BLK-OBJS) qcow2raw.c \
$(AIOLIBS) $(LIBS)
$(CC) $(CFLAGS) -o qcow-create $(BLK-OBJS) qcow-create.c \
$(AIOLIBS) $(LIBS)
img2qcow qcow2raw qcow-create: %: $(BLK-OBJS)
$(CC) $(CFLAGS) -o $* $(BLK-OBJS) $*.c $(AIOLIBS) $(LIBS)
install: all
$(INSTALL_PROG) $(IBIN) $(QCOW_UTIL) $(DESTDIR)$(INSTALL_DIR)
+17 -4
View File
@@ -61,6 +61,7 @@
#define MSG_SIZE 4096
#define MAX_TIMEOUT 10
#define MAX_RAND_VAL 0xFFFF
#define MAX_ATTEMPTS 10
int run = 1;
int max_timeout = MAX_TIMEOUT;
@@ -626,13 +627,14 @@ int main(int argc, char *argv[])
{
char *devname;
tapdev_info_t *ctlinfo;
int tap_pfd, store_pfd, xs_fd, ret, timeout, pfd_count;
int tap_pfd, store_pfd, xs_fd, ret, timeout, pfd_count, count=0;
struct xs_handle *h;
struct pollfd pfd[NUM_POLL_FDS];
pid_t process;
__init_blkif();
openlog("BLKTAPCTRL", LOG_CONS|LOG_ODELAY, LOG_DAEMON);
daemon(0,0);
print_drivers();
init_driver_list();
@@ -651,18 +653,28 @@ int main(int argc, char *argv[])
goto open_failed;
}
retry:
/* Set up store connection and watch. */
h = xs_daemon_open();
if (h == NULL) {
DPRINTF("xs_daemon_open failed -- "
"is xenstore running?\n");
goto open_failed;
if (count < MAX_ATTEMPTS) {
count++;
sleep(2);
goto retry;
} else goto open_failed;
}
ret = add_blockdevice_probe_watch(h, "Domain-0");
if (ret != 0) {
DPRINTF("adding device probewatch\n");
goto open_failed;
DPRINTF("Failed adding device probewatch\n");
if (count < MAX_ATTEMPTS) {
count++;
sleep(2);
xs_daemon_close(h);
goto retry;
} else goto open_failed;
}
ioctl(ctlfd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE );
@@ -691,6 +703,7 @@ int main(int argc, char *argv[])
}
}
xs_daemon_close(h);
ioctl(ctlfd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_PASSTHROUGH );
close(ctlfd);
closelog();
+9 -5
View File
@@ -35,10 +35,14 @@ IBINS :=
LIB = libblktap.a libblktap.so.$(MAJOR).$(MINOR)
.PHONY: all
all: build
build:
$(MAKE) libblktap
.PHONY: build
build: libblktap.a
.PHONY: libblktap
libblktap: libblktap.a
install: all
$(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)
@@ -51,13 +55,13 @@ install: all
clean:
rm -rf *.a *.so* *.o *.rpm $(LIB) *~ $(DEPS) xen TAGS
libblktap: $(OBJS)
libblktap.a: $(OBJS)
$(CC) $(CFLAGS) -Wl,-soname -Wl,$(SONAME) -shared \
-L$(XEN_XENSTORE) -l xenstore \
-o libblktap.so.$(MAJOR).$(MINOR) $^ $(LIBS)
ln -sf libblktap.so.$(MAJOR).$(MINOR) libblktap.so.$(MAJOR)
ln -sf libblktap.so.$(MAJOR) $@.so
ar rc libblktap.a $@.so
ln -sf libblktap.so.$(MAJOR) libblktap.so
ar rc $@ libblktap.so
.PHONY: TAGS all build clean install libblktap
+16 -2
View File
@@ -239,8 +239,11 @@ case "$command" in
exit 0
fi
p=$(xenstore_read "$XENBUS_PATH/params")
mode=$(xenstore_read "$XENBUS_PATH/mode")
if [ -n "$t" ]
then
p=$(xenstore_read "$XENBUS_PATH/params")
mode=$(xenstore_read "$XENBUS_PATH/mode")
fi
case $t in
phy)
@@ -370,6 +373,13 @@ mount it read-write in a guest domain."
release_lock "block"
exit 0
;;
"")
claim_lock "block"
success
echo happy gun \"$t\" >>/tmp/block.$$
release_lock "block"
;;
esac
;;
@@ -384,6 +394,10 @@ mount it read-write in a guest domain."
losetup -d "$node"
exit 0
;;
"")
exit 0
;;
esac
;;
+3 -7
View File
@@ -66,7 +66,7 @@ vif = [ 'type=ioemu, bridge=xenbr0' ]
# and MODE is r for read-only, w for read-write.
#disk = [ 'phy:hda1,hda1,r' ]
disk = [ 'file:/var/images/min-el3-i386.img,ioemu:hda,w' ]
disk = [ 'file:/var/images/min-el3-i386.img,hda,w', ',hdc:cdrom,r' ]
#----------------------------------------------------------------------------
# Configure the behaviour when a domain exits. There are three 'reasons'
@@ -110,10 +110,6 @@ disk = [ 'file:/var/images/min-el3-i386.img,ioemu:hda,w' ]
# New stuff
device_model = '/usr/' + arch_libdir + '/xen/bin/qemu-dm'
#-----------------------------------------------------------------------------
# Disk image for
#cdrom=
#-----------------------------------------------------------------------------
# boot on floppy (a), hard disk (c) or CD-ROM (d)
#boot=[a|c|d]
@@ -153,8 +149,8 @@ serial='pty'
#-----------------------------------------------------------------------------
# enable audio support
#audio=1
# enable sound card support, [sb16|es1370|all|..,..], default none
#soundhw='sb16'
#-----------------------------------------------------------------------------
+1 -1
View File
@@ -30,7 +30,7 @@ all:
.PHONY: install
install: all
[ -d $(INSTALL_DIR) ] || install -d -m0755 $(INSTALL_DIR)
[ ! -e $(TARGET) ] || install -m0644 $(TARGET) $(INSTALL_DIR)
install -m0644 $(TARGET) $(INSTALL_DIR)
.PHONY: clean
clean:
+115 -102
View File
@@ -16,7 +16,7 @@
//* Place - Suite 330, Boston, MA 02111-1307 USA.
//**
//** DSDT for Xen with Qemu device model
//** DSDT for Xen with Qemu device model
//**
//**
@@ -50,21 +50,36 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
})
Name(PICD, 0)
Name(PICD, 0)
Method(_PIC, 1) {
Method(_PIC, 1) {
Store(Arg0, PICD)
}
Store(Arg0, PICD)
}
Scope (\_SB)
{
Device (PCI0)
/* Fix HCT test for 0x400 pci memory - need to report low 640 MB mem as motherboard resource */
Device(MEM0) {
Name(_HID, EISAID("PNP0C02"))
Name(_CRS, ResourceTemplate() {
QWordMemory (ResourceConsumer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
0x00000000,
0x00000000,
0x0009ffff,
0x00000000,
0x000a0000)
}
)
}
Device (PCI0)
{
Name (_HID, EisaId ("PNP0A03"))
Name (_UID, 0x00)
Name (_ADR, 0x00)
Name (_BBN, 0x00)
OperationRegion (PIRP, PCI_Config, 0x3c, 0x10)
Name (_HID, EisaId ("PNP0A03"))
Name (_UID, 0x00)
Name (_ADR, 0x00)
Name (_BBN, 0x00)
OperationRegion (PIRP, PCI_Config, 0x3c, 0x10)
Field(PIRP, ByteAcc, NoLock, Preserve){
IRQ3,3,
IRQ5,5,
@@ -79,7 +94,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
Name (PRT0, ResourceTemplate ()
{
/* bus number is from 0 - 255*/
/* bus number is from 0 - 255*/
WordBusNumber (ResourceConsumer, MinFixed, MaxFixed, SubDecode,
0x0000,
0x0000,
@@ -122,7 +137,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
0x00000000,
0x00030000)
/* reserve what device model consumed for PCI VGA device */
/* reserve what device model consumed for PCI VGA device */
DWordMemory (ResourceConsumer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
0x00000000,
@@ -146,9 +161,9 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
})
Return (PRT0)
}
Name(BUFA, ResourceTemplate() {
Name(BUFA, ResourceTemplate() {
IRQ(Level, ActiveLow, Shared) {
3,4,5,6,7,10,11,12,14,15}
3,4,5,6,7,10,11,12,14,15}
})
Name(BUFB, Buffer(){
@@ -156,7 +171,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
0x79, 0})
CreateWordField(BUFB, 0x01, IRQV)
Name(BUFC, Buffer(){
5, 7, 10, 11
})
@@ -165,17 +180,17 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
CreateByteField(BUFC, 0x01, PIQB)
CreateByteField(BUFC, 0x01, PIQC)
CreateByteField(BUFC, 0x01, PIQD)
Device(LNKA) {
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
Device(LNKA) {
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
Name(_UID, 1)
Method(_STA, 0) {
And(PIRA, 0x80, Local0)
If(LEqual(Local0, 0x80)) {
Return(0x09)
Return(0x09)
}
Else {
Return(0x0B)
Return(0x0B)
}
}
@@ -189,34 +204,34 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
}
Method(_CRS) {
And(PIRB, 0x0f, Local0)
ShiftLeft(0x1, Local0, IRQV)
Return(BUFB)
And(PIRB, 0x0f, Local0)
ShiftLeft(0x1, Local0, IRQV)
Return(BUFB)
}
Method(_SRS, 1) {
CreateWordField(ARG0, 0x01, IRQ1)
FindSetRightBit(IRQ1, Local0)
Decrement(Local0)
Store(Local0, PIRA)
CreateWordField(ARG0, 0x01, IRQ1)
FindSetRightBit(IRQ1, Local0)
Decrement(Local0)
Store(Local0, PIRA)
} // Method(_SRS)
}
Device(LNKB) {
Name(_HID, EISAID("PNP0C0F"))
Device(LNKB){
Name(_HID, EISAID("PNP0C0F"))
Name(_UID, 2)
Method(_STA, 0) {
And(PIRB, 0x80, Local0)
If(LEqual(Local0, 0x80)) {
Return(0x09)
Return(0x09)
}
Else {
Return(0x0B)
Return(0x0B)
}
}
Method(_PRS) {
Return(BUFA)
Return(BUFA)
} // Method(_PRS)
Method(_DIS) {
@@ -225,35 +240,35 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
}
Method(_CRS) {
And(PIRB, 0x0f, Local0)
ShiftLeft(0x1, Local0, IRQV)
Return(BUFB)
And(PIRB, 0x0f, Local0)
ShiftLeft(0x1, Local0, IRQV)
Return(BUFB)
} // Method(_CRS)
Method(_SRS, 1) {
CreateWordField(ARG0, 0x01, IRQ1)
FindSetRightBit(IRQ1, Local0)
Decrement(Local0)
Store(Local0, PIRB)
CreateWordField(ARG0, 0x01, IRQ1)
FindSetRightBit(IRQ1, Local0)
Decrement(Local0)
Store(Local0, PIRB)
} // Method(_SRS)
}
Device(LNKC) {
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
Device(LNKC){
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
Name(_UID, 3)
Method(_STA, 0) {
And(PIRC, 0x80, Local0)
And(PIRC, 0x80, Local0)
If(LEqual(Local0, 0x80)) {
Return(0x09)
Return(0x09)
}
Else {
Return(0x0B)
Return(0x0B)
}
}
Method(_PRS) {
Return(BUFA)
} // Method(_PRS)
Method(_PRS) {
Return(BUFA)
} // Method(_PRS)
Method(_DIS) {
@@ -261,91 +276,89 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
}
Method(_CRS) {
And(PIRC, 0x0f, Local0)
ShiftLeft(0x1, Local0, IRQV)
Return(BUFB)
And(PIRC, 0x0f, Local0)
ShiftLeft(0x1, Local0, IRQV)
Return(BUFB)
} // Method(_CRS)
Method(_SRS, 1) {
CreateWordField(ARG0, 0x01, IRQ1)
FindSetRightBit(IRQ1, Local0)
Decrement(Local0)
Store(Local0, PIRC)
CreateWordField(ARG0, 0x01, IRQ1)
FindSetRightBit(IRQ1, Local0)
Decrement(Local0)
Store(Local0, PIRC)
} // Method(_SRS)
}
Device(LNKD) {
Name(_HID, EISAID("PNP0C0F"))
Device(LNKD) {
Name(_HID, EISAID("PNP0C0F"))
Name(_UID, 4)
Method(_STA, 0) {
And(PIRD, 0x80, Local0)
If(LEqual(Local0, 0x80)) {
Return(0x09)
Return(0x09)
}
Else {
Return(0x0B)
Return(0x0B)
}
}
Method(_PRS) {
Return(BUFA)
} // Method(_PRS)
Method(_PRS) {
Return(BUFA)
} // Method(_PRS)
Method(_DIS) {
Or(PIRD, 0x80, PIRD)
}
Method(_CRS) {
And(PIRD, 0x0f, Local0)
ShiftLeft(0x1, Local0, IRQV)
Return(BUFB)
And(PIRD, 0x0f, Local0)
ShiftLeft(0x1, Local0, IRQV)
Return(BUFB)
} // Method(_CRS)
Method(_SRS, 1) {
CreateWordField(ARG0, 0x01, IRQ1)
FindSetRightBit(IRQ1, Local0)
Decrement(Local0)
Store(Local0, PIRD)
CreateWordField(ARG0, 0x01, IRQ1)
FindSetRightBit(IRQ1, Local0)
Decrement(Local0)
Store(Local0, PIRD)
} // Method(_SRS)
}
Method(_PRT,0) {
If(PICD) {Return(PRTA)}
Return (PRTP)
} // end _PRT
Name(PRTP, Package(){
Package(){0x0000ffff, 0, \_SB.PCI0.LNKA, 0}, // Slot 1, INTA
Package(){0x0000ffff, 1, \_SB.PCI0.LNKB, 0}, // Slot 1, INTB
Package(){0x0000ffff, 2, \_SB.PCI0.LNKC, 0}, // Slot 1, INTC
Package(){0x0000ffff, 3, \_SB.PCI0.LNKD, 0}, // Slot 1, INTD
If(PICD) {Return(PRTA)}
Return (PRTP)
} // end _PRT
Package(){0x0001ffff, 0, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB
Package(){0x0001ffff, 1, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC
Package(){0x0001ffff, 2, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD
Package(){0x0001ffff, 3, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA
Name(PRTP, Package(){
Package(){0x0000ffff, 0, \_SB.PCI0.LNKA, 0}, // Slot 1, INTA
Package(){0x0000ffff, 1, \_SB.PCI0.LNKB, 0}, // Slot 1, INTB
Package(){0x0000ffff, 2, \_SB.PCI0.LNKC, 0}, // Slot 1, INTC
Package(){0x0000ffff, 3, \_SB.PCI0.LNKD, 0}, // Slot 1, INTD
Package(){0x0001ffff, 0, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB
Package(){0x0001ffff, 1, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC
Package(){0x0001ffff, 2, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD
Package(){0x0001ffff, 3, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA
Package(){0x0002ffff, 0, \_SB.PCI0.LNKC, 0}, // Slot 3, INTC
Package(){0x0002ffff, 1, \_SB.PCI0.LNKD, 0}, // Slot 3, INTD
Package(){0x0002ffff, 2, \_SB.PCI0.LNKA, 0}, // Slot 3, INTA
Package(){0x0002ffff, 3, \_SB.PCI0.LNKB, 0}, // Slot 3, INTB
Package(){0x0002ffff, 0, \_SB.PCI0.LNKC, 0}, // Slot 3, INTC
Package(){0x0002ffff, 1, \_SB.PCI0.LNKD, 0}, // Slot 3, INTD
Package(){0x0002ffff, 2, \_SB.PCI0.LNKA, 0}, // Slot 3, INTA
Package(){0x0002ffff, 3, \_SB.PCI0.LNKB, 0}, // Slot 3, INTB
Package(){0x0003ffff, 0, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD
Package(){0x0003ffff, 1, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA
Package(){0x0003ffff, 2, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB
Package(){0x0003ffff, 3, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC
Package(){0x0003ffff, 0, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD
Package(){0x0003ffff, 1, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA
Package(){0x0003ffff, 2, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB
Package(){0x0003ffff, 3, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC
}
)
Name(PRTA, Package(){
Package(){0x0001ffff, 0, 0, 5}, // Device 1, INTA
Name(PRTA, Package(){
Package(){0x0001ffff, 0, 0, 5}, // Device 1, INTA
Package(){0x0002ffff, 0, 0, 7}, // Device 2, INTA
Package(){0x0002ffff, 0, 0, 7}, // Device 2, INTA
Package(){0x0003ffff, 0, 0, 10}, // Device 3, INTA
Package(){0x0003ffff, 0, 0, 10}, // Device 3, INTA
Package(){0x0003ffff, 0, 0, 11}, // Device 4, INTA
Package(){0x0004ffff, 0, 0, 11}, // Device 4, INTA
}
)
@@ -354,22 +367,22 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
{
Name (_ADR, 0x00000000) /* device id, PCI bus num, ... */
OperationRegion(PIRQ, PCI_Config, 0x60, 0x4)
OperationRegion(PIRQ, PCI_Config, 0x60, 0x4)
Scope(\) {
Field (\_SB.PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) {
Field (\_SB.PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) {
PIRA, 8,
PIRB, 8,
PIRC, 8,
PIRD, 8
}
}
}
Device (SYSR)
{
Name (_HID, EisaId ("PNP0C02"))
Name (_UID, 0x01)
Name (CRS, ResourceTemplate ()
{
/* TODO: list hidden resources */
/* TODO: list hidden resources */
IO (Decode16, 0x0010, 0x0010, 0x00, 0x10)
IO (Decode16, 0x0022, 0x0022, 0x00, 0x0C)
IO (Decode16, 0x0030, 0x0030, 0x00, 0x10)
@@ -417,7 +430,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
IO (Decode16, 0x0089, 0x0089, 0x00, 0x03)
IO (Decode16, 0x008F, 0x008F, 0x00, 0x01)
IO (Decode16, 0x00C0, 0x00C0, 0x00, 0x20)
IO (Decode16, 0x0480, 0x0480, 0x00, 0x10)
IO (Decode16, 0x0480, 0x0480, 0x00, 0x10)
})
}
+270 -261
View File
@@ -5,15 +5,15 @@
* Copyright (C) 2000 - 2005 Intel Corporation
* Supports ACPI Specification Revision 3.0
*
* Compilation of "acpi_dsdt.asl" - Mon Jun 12 22:33:41 2006
* Compilation of "acpi_dsdt.asl" - Thu Aug 3 11:05:15 2006
*
* C source code output
*
*/
unsigned char AmlCode[] =
{
0x44,0x53,0x44,0x54,0xC3,0x08,0x00,0x00, /* 00000000 "DSDT...." */
0x01,0x0C,0x49,0x4E,0x54,0x45,0x4C,0x00, /* 00000008 "..INTEL." */
0x44,0x53,0x44,0x54,0x0E,0x09,0x00,0x00, /* 00000000 "DSDT...." */
0x01,0x03,0x49,0x4E,0x54,0x45,0x4C,0x00, /* 00000008 "..INTEL." */
0x69,0x6E,0x74,0x2D,0x78,0x65,0x6E,0x00, /* 00000010 "int-xen." */
0xD6,0x07,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
0x13,0x05,0x05,0x20,0x08,0x50,0x4D,0x42, /* 00000020 "... .PMB" */
@@ -34,264 +34,273 @@ unsigned char AmlCode[] =
0x12,0x08,0x04,0x0A,0x07,0x0A,0x07,0x00, /* 00000098 "........" */
0x00,0x08,0x50,0x49,0x43,0x44,0x00,0x14, /* 000000A0 "..PICD.." */
0x0C,0x5F,0x50,0x49,0x43,0x01,0x70,0x68, /* 000000A8 "._PIC.ph" */
0x50,0x49,0x43,0x44,0x10,0x4E,0x80,0x5F, /* 000000B0 "PICD.N._" */
0x53,0x42,0x5F,0x5B,0x82,0x46,0x80,0x50, /* 000000B8 "SB_[.F.P" */
0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 000000C0 "CI0._HID" */
0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x55, /* 000000C8 ".A...._U" */
0x49,0x44,0x00,0x08,0x5F,0x41,0x44,0x52, /* 000000D0 "ID.._ADR" */
0x00,0x08,0x5F,0x42,0x42,0x4E,0x00,0x5B, /* 000000D8 ".._BBN.[" */
0x80,0x50,0x49,0x52,0x50,0x02,0x0A,0x3C, /* 000000E0 ".PIRP..<" */
0x0A,0x10,0x5B,0x81,0x24,0x50,0x49,0x52, /* 000000E8 "..[.$PIR" */
0x50,0x01,0x49,0x52,0x51,0x33,0x03,0x49, /* 000000F0 "P.IRQ3.I" */
0x52,0x51,0x35,0x05,0x49,0x52,0x51,0x37, /* 000000F8 "RQ5.IRQ7" */
0x07,0x49,0x52,0x51,0x39,0x09,0x49,0x52, /* 00000100 ".IRQ9.IR" */
0x51,0x41,0x0A,0x49,0x52,0x51,0x42,0x0B, /* 00000108 "QA.IRQB." */
0x14,0x48,0x0D,0x5F,0x43,0x52,0x53,0x00, /* 00000110 ".H._CRS." */
0x08,0x50,0x52,0x54,0x30,0x11,0x46,0x0C, /* 00000118 ".PRT0.F." */
0x0A,0xC2,0x88,0x0D,0x00,0x02,0x0F,0x00, /* 00000120 "........" */
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00, /* 00000128 "........" */
0x00,0x01,0x47,0x01,0xF8,0x0C,0xF8,0x0C, /* 00000130 "..G....." */
0x01,0x08,0x88,0x0D,0x00,0x01,0x0C,0x03, /* 00000138 "........" */
0x00,0x00,0x00,0x00,0xF7,0x0C,0x00,0x00, /* 00000140 "........" */
0xF8,0x0C,0x88,0x0D,0x00,0x01,0x0C,0x03, /* 00000148 "........" */
0x00,0x00,0x00,0x0D,0xFF,0x0F,0x00,0x00, /* 00000150 "........" */
0x00,0x03,0x88,0x0D,0x00,0x01,0x0D,0x03, /* 00000158 "........" */
0x00,0x00,0x00,0xC0,0x1F,0xC0,0x00,0x00, /* 00000160 "........" */
0x20,0x00,0x88,0x0D,0x00,0x01,0x0D,0x03, /* 00000168 " ......." */
0x00,0x00,0x20,0xC0,0x3F,0xC0,0x00,0x00, /* 00000170 ".. .?..." */
0x10,0x00,0x87,0x17,0x00,0x00,0x0C,0x02, /* 00000178 "........" */
0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00, /* 00000180 "........" */
0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00, /* 00000188 "........" */
0x00,0x00,0x03,0x00,0x87,0x17,0x00,0x00, /* 00000190 "........" */
0x0D,0x03,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000198 "........" */
0x00,0xF0,0xFF,0xFF,0xFF,0xF1,0x00,0x00, /* 000001A0 "........" */
0x00,0x00,0x00,0x00,0x00,0x02,0x87,0x17, /* 000001A8 "........" */
0x00,0x00,0x0D,0x03,0x00,0x00,0x00,0x00, /* 000001B0 "........" */
0x00,0x00,0x00,0xF2,0xFF,0x0F,0x00,0xF2, /* 000001B8 "........" */
0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00, /* 000001C0 "........" */
0x87,0x17,0x00,0x00,0x0D,0x03,0x00,0x00, /* 000001C8 "........" */
0x00,0x00,0x00,0x10,0x00,0xF2,0x1F,0x10, /* 000001D0 "........" */
0x00,0xF2,0x00,0x00,0x00,0x00,0x20,0x00, /* 000001D8 "...... ." */
0x00,0x00,0x79,0x00,0xA4,0x50,0x52,0x54, /* 000001E0 "..y..PRT" */
0x30,0x08,0x42,0x55,0x46,0x41,0x11,0x09, /* 000001E8 "0.BUFA.." */
0x0A,0x06,0x23,0xF8,0xDC,0x18,0x79,0x00, /* 000001F0 "..#...y." */
0x08,0x42,0x55,0x46,0x42,0x11,0x09,0x0A, /* 000001F8 ".BUFB..." */
0x06,0x23,0x00,0x00,0x18,0x79,0x00,0x8B, /* 00000200 ".#...y.." */
0x42,0x55,0x46,0x42,0x01,0x49,0x52,0x51, /* 00000208 "BUFB.IRQ" */
0x56,0x08,0x42,0x55,0x46,0x43,0x11,0x07, /* 00000210 "V.BUFC.." */
0x0A,0x04,0x05,0x07,0x0A,0x0B,0x8C,0x42, /* 00000218 ".......B" */
0x55,0x46,0x43,0x01,0x50,0x49,0x51,0x41, /* 00000220 "UFC.PIQA" */
0x8C,0x42,0x55,0x46,0x43,0x01,0x50,0x49, /* 00000228 ".BUFC.PI" */
0x51,0x42,0x8C,0x42,0x55,0x46,0x43,0x01, /* 00000230 "QB.BUFC." */
0x50,0x49,0x51,0x43,0x8C,0x42,0x55,0x46, /* 00000238 "PIQC.BUF" */
0x43,0x01,0x50,0x49,0x51,0x44,0x5B,0x82, /* 00000240 "C.PIQD[." */
0x48,0x08,0x4C,0x4E,0x4B,0x41,0x08,0x5F, /* 00000248 "H.LNKA._" */
0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 00000250 "HID.A..." */
0x08,0x5F,0x55,0x49,0x44,0x01,0x14,0x1C, /* 00000258 "._UID..." */
0x5F,0x53,0x54,0x41,0x00,0x7B,0x50,0x49, /* 00000260 "_STA.{PI" */
0x52,0x41,0x0A,0x80,0x60,0xA0,0x08,0x93, /* 00000268 "RA..`..." */
0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1,0x04, /* 00000270 "`......." */
0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50,0x52, /* 00000278 "....._PR" */
0x53,0x00,0xA4,0x42,0x55,0x46,0x41,0x14, /* 00000280 "S..BUFA." */
0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000288 "._DIS.}P" */
0x49,0x52,0x41,0x0A,0x80,0x50,0x49,0x52, /* 00000290 "IRA..PIR" */
0x41,0x14,0x1A,0x5F,0x43,0x52,0x53,0x00, /* 00000298 "A.._CRS." */
0x7B,0x50,0x49,0x52,0x42,0x0A,0x0F,0x60, /* 000002A0 "{PIRB..`" */
0x79,0x01,0x60,0x49,0x52,0x51,0x56,0xA4, /* 000002A8 "y.`IRQV." */
0x42,0x55,0x46,0x42,0x14,0x1B,0x5F,0x53, /* 000002B0 "BUFB.._S" */
0x52,0x53,0x01,0x8B,0x68,0x01,0x49,0x52, /* 000002B8 "RS..h.IR" */
0x51,0x31,0x82,0x49,0x52,0x51,0x31,0x60, /* 000002C0 "Q1.IRQ1`" */
0x76,0x60,0x70,0x60,0x50,0x49,0x52,0x41, /* 000002C8 "v`p`PIRA" */
0x5B,0x82,0x49,0x08,0x4C,0x4E,0x4B,0x42, /* 000002D0 "[.I.LNKB" */
0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000002D8 "._HID.A." */
0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 000002E0 "..._UID." */
0x02,0x14,0x1C,0x5F,0x53,0x54,0x41,0x00, /* 000002E8 "..._STA." */
0x7B,0x50,0x49,0x52,0x42,0x0A,0x80,0x60, /* 000002F0 "{PIRB..`" */
0xA0,0x08,0x93,0x60,0x0A,0x80,0xA4,0x0A, /* 000002F8 "...`...." */
0x09,0xA1,0x04,0xA4,0x0A,0x0B,0x14,0x0B, /* 00000300 "........" */
0x5F,0x50,0x52,0x53,0x00,0xA4,0x42,0x55, /* 00000308 "_PRS..BU" */
0x46,0x41,0x14,0x11,0x5F,0x44,0x49,0x53, /* 00000310 "FA.._DIS" */
0x00,0x7D,0x50,0x49,0x52,0x42,0x0A,0x80, /* 00000318 ".}PIRB.." */
0x50,0x49,0x52,0x42,0x14,0x1A,0x5F,0x43, /* 00000320 "PIRB.._C" */
0x52,0x53,0x00,0x7B,0x50,0x49,0x52,0x42, /* 00000328 "RS.{PIRB" */
0x0A,0x0F,0x60,0x79,0x01,0x60,0x49,0x52, /* 00000330 "..`y.`IR" */
0x51,0x56,0xA4,0x42,0x55,0x46,0x42,0x14, /* 00000338 "QV.BUFB." */
0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 00000340 "._SRS..h" */
0x01,0x49,0x52,0x51,0x31,0x82,0x49,0x52, /* 00000348 ".IRQ1.IR" */
0x51,0x31,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000350 "Q1`v`p`P" */
0x49,0x52,0x42,0x5B,0x82,0x49,0x08,0x4C, /* 00000358 "IRB[.I.L" */
0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49,0x44, /* 00000360 "NKC._HID" */
0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000368 ".A...._U" */
0x49,0x44,0x0A,0x03,0x14,0x1C,0x5F,0x53, /* 00000370 "ID...._S" */
0x54,0x41,0x00,0x7B,0x50,0x49,0x52,0x43, /* 00000378 "TA.{PIRC" */
0x0A,0x80,0x60,0xA0,0x08,0x93,0x60,0x0A, /* 00000380 "..`...`." */
0x80,0xA4,0x0A,0x09,0xA1,0x04,0xA4,0x0A, /* 00000388 "........" */
0x0B,0x14,0x0B,0x5F,0x50,0x52,0x53,0x00, /* 00000390 "..._PRS." */
0xA4,0x42,0x55,0x46,0x41,0x14,0x11,0x5F, /* 00000398 ".BUFA.._" */
0x44,0x49,0x53,0x00,0x7D,0x50,0x49,0x52, /* 000003A0 "DIS.}PIR" */
0x43,0x0A,0x80,0x50,0x49,0x52,0x43,0x14, /* 000003A8 "C..PIRC." */
0x1A,0x5F,0x43,0x52,0x53,0x00,0x7B,0x50, /* 000003B0 "._CRS.{P" */
0x49,0x52,0x43,0x0A,0x0F,0x60,0x79,0x01, /* 000003B8 "IRC..`y." */
0x60,0x49,0x52,0x51,0x56,0xA4,0x42,0x55, /* 000003C0 "`IRQV.BU" */
0x46,0x42,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 000003C8 "FB.._SRS" */
0x01,0x8B,0x68,0x01,0x49,0x52,0x51,0x31, /* 000003D0 "..h.IRQ1" */
0x82,0x49,0x52,0x51,0x31,0x60,0x76,0x60, /* 000003D8 ".IRQ1`v`" */
0x70,0x60,0x50,0x49,0x52,0x43,0x5B,0x82, /* 000003E0 "p`PIRC[." */
0x49,0x08,0x4C,0x4E,0x4B,0x44,0x08,0x5F, /* 000003E8 "I.LNKD._" */
0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 000003F0 "HID.A..." */
0x08,0x5F,0x55,0x49,0x44,0x0A,0x04,0x14, /* 000003F8 "._UID..." */
0x1C,0x5F,0x53,0x54,0x41,0x00,0x7B,0x50, /* 00000400 "._STA.{P" */
0x49,0x52,0x44,0x0A,0x80,0x60,0xA0,0x08, /* 00000408 "IRD..`.." */
0x93,0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1, /* 00000410 ".`......" */
0x04,0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50, /* 00000418 "......_P" */
0x52,0x53,0x00,0xA4,0x42,0x55,0x46,0x41, /* 00000420 "RS..BUFA" */
0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00000428 ".._DIS.}" */
0x50,0x49,0x52,0x44,0x0A,0x80,0x50,0x49, /* 00000430 "PIRD..PI" */
0x52,0x44,0x14,0x1A,0x5F,0x43,0x52,0x53, /* 00000438 "RD.._CRS" */
0x00,0x7B,0x50,0x49,0x52,0x44,0x0A,0x0F, /* 00000440 ".{PIRD.." */
0x60,0x79,0x01,0x60,0x49,0x52,0x51,0x56, /* 00000448 "`y.`IRQV" */
0xA4,0x42,0x55,0x46,0x42,0x14,0x1B,0x5F, /* 00000450 ".BUFB.._" */
0x53,0x52,0x53,0x01,0x8B,0x68,0x01,0x49, /* 00000458 "SRS..h.I" */
0x52,0x51,0x31,0x82,0x49,0x52,0x51,0x31, /* 00000460 "RQ1.IRQ1" */
0x60,0x76,0x60,0x70,0x60,0x50,0x49,0x52, /* 00000468 "`v`p`PIR" */
0x44,0x14,0x16,0x5F,0x50,0x52,0x54,0x00, /* 00000470 "D.._PRT." */
0xA0,0x0A,0x50,0x49,0x43,0x44,0xA4,0x50, /* 00000478 "..PICD.P" */
0x52,0x54,0x41,0xA4,0x50,0x52,0x54,0x50, /* 00000480 "RTA.PRTP" */
0x08,0x50,0x52,0x54,0x50,0x12,0x43,0x0E, /* 00000488 ".PRTP.C." */
0x10,0x12,0x0B,0x04,0x0B,0xFF,0xFF,0x00, /* 00000490 "........" */
0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0B,0x04, /* 00000498 "LNKA...." */
0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B,0x42, /* 000004A0 "....LNKB" */
0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF,0x0A, /* 000004A8 "........" */
0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0C, /* 000004B0 ".LNKC..." */
0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C,0x4E, /* 000004B8 "......LN" */
0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 000004C0 "KD......" */
0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B,0x42, /* 000004C8 "....LNKB" */
0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x01, /* 000004D0 "........" */
0x00,0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000004D8 "..LNKC.." */
0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 000004E0 "........" */
0x02,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000004E8 ".LNKD..." */
0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x03, /* 000004F0 "........" */
0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04, /* 000004F8 "LNKA...." */
0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C,0x4E, /* 00000500 "......LN" */
0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 00000508 "KC......" */
0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B,0x44, /* 00000510 "....LNKD" */
0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000518 "........" */
0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00, /* 00000520 "...LNKA." */
0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 00000528 "........" */
0x0A,0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000530 "..LNKB.." */
0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00,0x00, /* 00000538 "........" */
0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04, /* 00000540 "LNKD...." */
0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C,0x4E, /* 00000548 "......LN" */
0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000550 "KA......" */
0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E,0x4B, /* 00000558 ".....LNK" */
0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000560 "B......." */
0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43, /* 00000568 "....LNKC" */
0x00,0x08,0x50,0x52,0x54,0x41,0x12,0x32, /* 00000570 "..PRTA.2" */
0x04,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x01, /* 00000578 "........" */
0x00,0x00,0x00,0x0A,0x05,0x12,0x0B,0x04, /* 00000580 "........" */
0x0C,0xFF,0xFF,0x02,0x00,0x00,0x00,0x0A, /* 00000588 "........" */
0x07,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x03, /* 00000590 "........" */
0x00,0x00,0x00,0x0A,0x0A,0x12,0x0B,0x04, /* 00000598 "........" */
0x0C,0xFF,0xFF,0x03,0x00,0x00,0x00,0x0A, /* 000005A0 "........" */
0x0B,0x5B,0x82,0x48,0x31,0x49,0x53,0x41, /* 000005A8 ".[.H1ISA" */
0x5F,0x08,0x5F,0x41,0x44,0x52,0x00,0x5B, /* 000005B0 "_._ADR.[" */
0x80,0x50,0x49,0x52,0x51,0x02,0x0A,0x60, /* 000005B8 ".PIRQ..`" */
0x0A,0x04,0x10,0x2E,0x5C,0x00,0x5B,0x81, /* 000005C0 "....\.[." */
0x29,0x5C,0x2F,0x04,0x5F,0x53,0x42,0x5F, /* 000005C8 ")\/._SB_" */
0x50,0x43,0x49,0x30,0x49,0x53,0x41,0x5F, /* 000005D0 "PCI0ISA_" */
0x50,0x49,0x52,0x51,0x01,0x50,0x49,0x52, /* 000005D8 "PIRQ.PIR" */
0x41,0x08,0x50,0x49,0x52,0x42,0x08,0x50, /* 000005E0 "A.PIRB.P" */
0x49,0x52,0x43,0x08,0x50,0x49,0x52,0x44, /* 000005E8 "IRC.PIRD" */
0x08,0x5B,0x82,0x46,0x0B,0x53,0x59,0x53, /* 000005F0 ".[.F.SYS" */
0x52,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 000005F8 "R._HID.A" */
0xD0,0x0C,0x02,0x08,0x5F,0x55,0x49,0x44, /* 00000600 "...._UID" */
0x01,0x08,0x43,0x52,0x53,0x5F,0x11,0x4E, /* 00000608 "..CRS_.N" */
0x08,0x0A,0x8A,0x47,0x01,0x10,0x00,0x10, /* 00000610 "...G...." */
0x00,0x00,0x10,0x47,0x01,0x22,0x00,0x22, /* 00000618 "...G."."" */
0x00,0x00,0x0C,0x47,0x01,0x30,0x00,0x30, /* 00000620 "...G.0.0" */
0x00,0x00,0x10,0x47,0x01,0x44,0x00,0x44, /* 00000628 "...G.D.D" */
0x00,0x00,0x1C,0x47,0x01,0x62,0x00,0x62, /* 00000630 "...G.b.b" */
0x00,0x00,0x02,0x47,0x01,0x65,0x00,0x65, /* 00000638 "...G.e.e" */
0x00,0x00,0x0B,0x47,0x01,0x72,0x00,0x72, /* 00000640 "...G.r.r" */
0x00,0x00,0x0E,0x47,0x01,0x80,0x00,0x80, /* 00000648 "...G...." */
0x00,0x00,0x01,0x47,0x01,0x84,0x00,0x84, /* 00000650 "...G...." */
0x00,0x00,0x03,0x47,0x01,0x88,0x00,0x88, /* 00000658 "...G...." */
0x00,0x00,0x01,0x47,0x01,0x8C,0x00,0x8C, /* 00000660 "...G...." */
0x00,0x00,0x03,0x47,0x01,0x90,0x00,0x90, /* 00000668 "...G...." */
0x00,0x00,0x10,0x47,0x01,0xA2,0x00,0xA2, /* 00000670 "...G...." */
0x00,0x00,0x1C,0x47,0x01,0xE0,0x00,0xE0, /* 00000678 "...G...." */
0x00,0x00,0x10,0x47,0x01,0xA0,0x08,0xA0, /* 00000680 "...G...." */
0x08,0x00,0x04,0x47,0x01,0xC0,0x0C,0xC0, /* 00000688 "...G...." */
0x0C,0x00,0x10,0x47,0x01,0xD0,0x04,0xD0, /* 00000690 "...G...." */
0x04,0x00,0x02,0x79,0x00,0x14,0x0B,0x5F, /* 00000698 "...y..._" */
0x43,0x52,0x53,0x00,0xA4,0x43,0x52,0x53, /* 000006A0 "CRS..CRS" */
0x5F,0x5B,0x82,0x2B,0x50,0x49,0x43,0x5F, /* 000006A8 "_[.+PIC_" */
0x08,0x5F,0x48,0x49,0x44,0x0B,0x41,0xD0, /* 000006B0 "._HID.A." */
0x08,0x5F,0x43,0x52,0x53,0x11,0x18,0x0A, /* 000006B8 "._CRS..." */
0x15,0x47,0x01,0x20,0x00,0x20,0x00,0x01, /* 000006C0 ".G. . .." */
0x02,0x47,0x01,0xA0,0x00,0xA0,0x00,0x01, /* 000006C8 ".G......" */
0x02,0x22,0x04,0x00,0x79,0x00,0x5B,0x82, /* 000006D0 "."..y.[." */
0x47,0x05,0x44,0x4D,0x41,0x30,0x08,0x5F, /* 000006D8 "G.DMA0._" */
0x48,0x49,0x44,0x0C,0x41,0xD0,0x02,0x00, /* 000006E0 "HID.A..." */
0x08,0x5F,0x43,0x52,0x53,0x11,0x41,0x04, /* 000006E8 "._CRS.A." */
0x0A,0x3D,0x2A,0x10,0x04,0x47,0x01,0x00, /* 000006F0 ".=*..G.." */
0x00,0x00,0x00,0x00,0x10,0x47,0x01,0x81, /* 000006F8 ".....G.." */
0x00,0x81,0x00,0x00,0x03,0x47,0x01,0x87, /* 00000700 ".....G.." */
0x00,0x87,0x00,0x00,0x01,0x47,0x01,0x89, /* 00000708 ".....G.." */
0x00,0x89,0x00,0x00,0x03,0x47,0x01,0x8F, /* 00000710 ".....G.." */
0x00,0x8F,0x00,0x00,0x01,0x47,0x01,0xC0, /* 00000718 ".....G.." */
0x00,0xC0,0x00,0x00,0x20,0x47,0x01,0x80, /* 00000720 ".... G.." */
0x04,0x80,0x04,0x00,0x10,0x79,0x00,0x5B, /* 00000728 ".....y.[" */
0x82,0x25,0x54,0x4D,0x52,0x5F,0x08,0x5F, /* 00000730 ".%TMR_._" */
0x48,0x49,0x44,0x0C,0x41,0xD0,0x01,0x00, /* 00000738 "HID.A..." */
0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 00000740 "._CRS..." */
0x0D,0x47,0x01,0x40,0x00,0x40,0x00,0x00, /* 00000748 ".G.@.@.." */
0x04,0x22,0x01,0x00,0x79,0x00,0x5B,0x82, /* 00000750 "."..y.[." */
0x25,0x52,0x54,0x43,0x5F,0x08,0x5F,0x48, /* 00000758 "%RTC_._H" */
0x49,0x44,0x0C,0x41,0xD0,0x0B,0x00,0x08, /* 00000760 "ID.A...." */
0x5F,0x43,0x52,0x53,0x11,0x10,0x0A,0x0D, /* 00000768 "_CRS...." */
0x47,0x01,0x70,0x00,0x70,0x00,0x00,0x02, /* 00000770 "G.p.p..." */
0x22,0x00,0x01,0x79,0x00,0x5B,0x82,0x22, /* 00000778 ""..y.[."" */
0x53,0x50,0x4B,0x52,0x08,0x5F,0x48,0x49, /* 00000780 "SPKR._HI" */
0x44,0x0C,0x41,0xD0,0x08,0x00,0x08,0x5F, /* 00000788 "D.A...._" */
0x43,0x52,0x53,0x11,0x0D,0x0A,0x0A,0x47, /* 00000790 "CRS....G" */
0x01,0x61,0x00,0x61,0x00,0x00,0x01,0x79, /* 00000798 ".a.a...y" */
0x00,0x5B,0x82,0x31,0x50,0x53,0x32,0x4D, /* 000007A0 ".[.1PS2M" */
0x50,0x49,0x43,0x44,0x10,0x49,0x85,0x5F, /* 000000B0 "PICD.I._" */
0x53,0x42,0x5F,0x5B,0x82,0x49,0x04,0x4D, /* 000000B8 "SB_[.I.M" */
0x45,0x4D,0x30,0x08,0x5F,0x48,0x49,0x44, /* 000000C0 "EM0._HID" */
0x0C,0x41,0xD0,0x0C,0x02,0x08,0x5F,0x43, /* 000000C8 ".A...._C" */
0x52,0x53,0x11,0x33,0x0A,0x30,0x8A,0x2B, /* 000000D0 "RS.3.0.+" */
0x00,0x00,0x0D,0x03,0x00,0x00,0x00,0x00, /* 000000D8 "........" */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */
0x00,0x00,0x00,0x00,0xFF,0xFF,0x09,0x00, /* 000000E8 "........" */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F0 "........" */
0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00, /* 000000F8 "........" */
0x00,0x00,0x00,0x00,0x79,0x00,0x5B,0x82, /* 00000100 "....y.[." */
0x46,0x80,0x50,0x43,0x49,0x30,0x08,0x5F, /* 00000108 "F.PCI0._" */
0x48,0x49,0x44,0x0C,0x41,0xD0,0x0A,0x03, /* 00000110 "HID.A..." */
0x08,0x5F,0x55,0x49,0x44,0x00,0x08,0x5F, /* 00000118 "._UID.._" */
0x41,0x44,0x52,0x00,0x08,0x5F,0x42,0x42, /* 00000120 "ADR.._BB" */
0x4E,0x00,0x5B,0x80,0x50,0x49,0x52,0x50, /* 00000128 "N.[.PIRP" */
0x02,0x0A,0x3C,0x0A,0x10,0x5B,0x81,0x24, /* 00000130 "..<..[.$" */
0x50,0x49,0x52,0x50,0x01,0x49,0x52,0x51, /* 00000138 "PIRP.IRQ" */
0x33,0x03,0x49,0x52,0x51,0x35,0x05,0x49, /* 00000140 "3.IRQ5.I" */
0x52,0x51,0x37,0x07,0x49,0x52,0x51,0x39, /* 00000148 "RQ7.IRQ9" */
0x09,0x49,0x52,0x51,0x41,0x0A,0x49,0x52, /* 00000150 ".IRQA.IR" */
0x51,0x42,0x0B,0x14,0x48,0x0D,0x5F,0x43, /* 00000158 "QB..H._C" */
0x52,0x53,0x00,0x08,0x50,0x52,0x54,0x30, /* 00000160 "RS..PRT0" */
0x11,0x46,0x0C,0x0A,0xC2,0x88,0x0D,0x00, /* 00000168 ".F......" */
0x02,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF, /* 00000170 "........" */
0x00,0x00,0x00,0x00,0x01,0x47,0x01,0xF8, /* 00000178 ".....G.." */
0x0C,0xF8,0x0C,0x01,0x08,0x88,0x0D,0x00, /* 00000180 "........" */
0x01,0x0C,0x03,0x00,0x00,0x00,0x00,0xF7, /* 00000188 "........" */
0x0C,0x00,0x00,0xF8,0x0C,0x88,0x0D,0x00, /* 00000190 "........" */
0x01,0x0C,0x03,0x00,0x00,0x00,0x0D,0xFF, /* 00000198 "........" */
0x0F,0x00,0x00,0x00,0x03,0x88,0x0D,0x00, /* 000001A0 "........" */
0x01,0x0D,0x03,0x00,0x00,0x00,0xC0,0x1F, /* 000001A8 "........" */
0xC0,0x00,0x00,0x20,0x00,0x88,0x0D,0x00, /* 000001B0 "... ...." */
0x01,0x0D,0x03,0x00,0x00,0x20,0xC0,0x3F, /* 000001B8 "..... .?" */
0xC0,0x00,0x00,0x10,0x00,0x87,0x17,0x00, /* 000001C0 "........" */
0x00,0x0C,0x02,0x00,0x00,0x00,0x00,0x00, /* 000001C8 "........" */
0x00,0x0C,0x00,0xFF,0xFF,0x0F,0x00,0x00, /* 000001D0 "........" */
0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x87, /* 000001D8 "........" */
0x17,0x00,0x00,0x0D,0x03,0x00,0x00,0x00, /* 000001E0 "........" */
0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF, /* 000001E8 "........" */
0xF1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001F0 "........" */
0x02,0x87,0x17,0x00,0x00,0x0D,0x03,0x00, /* 000001F8 "........" */
0x00,0x00,0x00,0x00,0x00,0x00,0xF2,0xFF, /* 00000200 "........" */
0x0F,0x00,0xF2,0x00,0x00,0x00,0x00,0x00, /* 00000208 "........" */
0x10,0x00,0x00,0x87,0x17,0x00,0x00,0x0D, /* 00000210 "........" */
0x03,0x00,0x00,0x00,0x00,0x00,0x10,0x00, /* 00000218 "........" */
0xF2,0x1F,0x10,0x00,0xF2,0x00,0x00,0x00, /* 00000220 "........" */
0x00,0x20,0x00,0x00,0x00,0x79,0x00,0xA4, /* 00000228 ". ...y.." */
0x50,0x52,0x54,0x30,0x08,0x42,0x55,0x46, /* 00000230 "PRT0.BUF" */
0x41,0x11,0x09,0x0A,0x06,0x23,0xF8,0xDC, /* 00000238 "A....#.." */
0x18,0x79,0x00,0x08,0x42,0x55,0x46,0x42, /* 00000240 ".y..BUFB" */
0x11,0x09,0x0A,0x06,0x23,0x00,0x00,0x18, /* 00000248 "....#..." */
0x79,0x00,0x8B,0x42,0x55,0x46,0x42,0x01, /* 00000250 "y..BUFB." */
0x49,0x52,0x51,0x56,0x08,0x42,0x55,0x46, /* 00000258 "IRQV.BUF" */
0x43,0x11,0x07,0x0A,0x04,0x05,0x07,0x0A, /* 00000260 "C......." */
0x0B,0x8C,0x42,0x55,0x46,0x43,0x01,0x50, /* 00000268 "..BUFC.P" */
0x49,0x51,0x41,0x8C,0x42,0x55,0x46,0x43, /* 00000270 "IQA.BUFC" */
0x01,0x50,0x49,0x51,0x42,0x8C,0x42,0x55, /* 00000278 ".PIQB.BU" */
0x46,0x43,0x01,0x50,0x49,0x51,0x43,0x8C, /* 00000280 "FC.PIQC." */
0x42,0x55,0x46,0x43,0x01,0x50,0x49,0x51, /* 00000288 "BUFC.PIQ" */
0x44,0x5B,0x82,0x48,0x08,0x4C,0x4E,0x4B, /* 00000290 "D[.H.LNK" */
0x41,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000298 "A._HID.A" */
0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44, /* 000002A0 "...._UID" */
0x01,0x14,0x1C,0x5F,0x53,0x54,0x41,0x00, /* 000002A8 "..._STA." */
0x7B,0x50,0x49,0x52,0x41,0x0A,0x80,0x60, /* 000002B0 "{PIRA..`" */
0xA0,0x08,0x93,0x60,0x0A,0x80,0xA4,0x0A, /* 000002B8 "...`...." */
0x09,0xA1,0x04,0xA4,0x0A,0x0B,0x14,0x0B, /* 000002C0 "........" */
0x5F,0x50,0x52,0x53,0x00,0xA4,0x42,0x55, /* 000002C8 "_PRS..BU" */
0x46,0x41,0x14,0x11,0x5F,0x44,0x49,0x53, /* 000002D0 "FA.._DIS" */
0x00,0x7D,0x50,0x49,0x52,0x41,0x0A,0x80, /* 000002D8 ".}PIRA.." */
0x50,0x49,0x52,0x41,0x14,0x1A,0x5F,0x43, /* 000002E0 "PIRA.._C" */
0x52,0x53,0x00,0x7B,0x50,0x49,0x52,0x42, /* 000002E8 "RS.{PIRB" */
0x0A,0x0F,0x60,0x79,0x01,0x60,0x49,0x52, /* 000002F0 "..`y.`IR" */
0x51,0x56,0xA4,0x42,0x55,0x46,0x42,0x14, /* 000002F8 "QV.BUFB." */
0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 00000300 "._SRS..h" */
0x01,0x49,0x52,0x51,0x31,0x82,0x49,0x52, /* 00000308 ".IRQ1.IR" */
0x51,0x31,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000310 "Q1`v`p`P" */
0x49,0x52,0x41,0x5B,0x82,0x49,0x08,0x4C, /* 00000318 "IRA[.I.L" */
0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000320 "NKB._HID" */
0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000328 ".A...._U" */
0x49,0x44,0x0A,0x02,0x14,0x1C,0x5F,0x53, /* 00000330 "ID...._S" */
0x54,0x41,0x00,0x7B,0x50,0x49,0x52,0x42, /* 00000338 "TA.{PIRB" */
0x0A,0x80,0x60,0xA0,0x08,0x93,0x60,0x0A, /* 00000340 "..`...`." */
0x80,0xA4,0x0A,0x09,0xA1,0x04,0xA4,0x0A, /* 00000348 "........" */
0x0B,0x14,0x0B,0x5F,0x50,0x52,0x53,0x00, /* 00000350 "..._PRS." */
0xA4,0x42,0x55,0x46,0x41,0x14,0x11,0x5F, /* 00000358 ".BUFA.._" */
0x44,0x49,0x53,0x00,0x7D,0x50,0x49,0x52, /* 00000360 "DIS.}PIR" */
0x42,0x0A,0x80,0x50,0x49,0x52,0x42,0x14, /* 00000368 "B..PIRB." */
0x1A,0x5F,0x43,0x52,0x53,0x00,0x7B,0x50, /* 00000370 "._CRS.{P" */
0x49,0x52,0x42,0x0A,0x0F,0x60,0x79,0x01, /* 00000378 "IRB..`y." */
0x60,0x49,0x52,0x51,0x56,0xA4,0x42,0x55, /* 00000380 "`IRQV.BU" */
0x46,0x42,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000388 "FB.._SRS" */
0x01,0x8B,0x68,0x01,0x49,0x52,0x51,0x31, /* 00000390 "..h.IRQ1" */
0x82,0x49,0x52,0x51,0x31,0x60,0x76,0x60, /* 00000398 ".IRQ1`v`" */
0x70,0x60,0x50,0x49,0x52,0x42,0x5B,0x82, /* 000003A0 "p`PIRB[." */
0x49,0x08,0x4C,0x4E,0x4B,0x43,0x08,0x5F, /* 000003A8 "I.LNKC._" */
0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 000003B0 "HID.A..." */
0x08,0x5F,0x55,0x49,0x44,0x0A,0x03,0x14, /* 000003B8 "._UID..." */
0x1C,0x5F,0x53,0x54,0x41,0x00,0x7B,0x50, /* 000003C0 "._STA.{P" */
0x49,0x52,0x43,0x0A,0x80,0x60,0xA0,0x08, /* 000003C8 "IRC..`.." */
0x93,0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1, /* 000003D0 ".`......" */
0x04,0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50, /* 000003D8 "......_P" */
0x52,0x53,0x00,0xA4,0x42,0x55,0x46,0x41, /* 000003E0 "RS..BUFA" */
0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000003E8 ".._DIS.}" */
0x50,0x49,0x52,0x43,0x0A,0x80,0x50,0x49, /* 000003F0 "PIRC..PI" */
0x52,0x43,0x14,0x1A,0x5F,0x43,0x52,0x53, /* 000003F8 "RC.._CRS" */
0x00,0x7B,0x50,0x49,0x52,0x43,0x0A,0x0F, /* 00000400 ".{PIRC.." */
0x60,0x79,0x01,0x60,0x49,0x52,0x51,0x56, /* 00000408 "`y.`IRQV" */
0xA4,0x42,0x55,0x46,0x42,0x14,0x1B,0x5F, /* 00000410 ".BUFB.._" */
0x53,0x52,0x53,0x01,0x8B,0x68,0x01,0x49, /* 00000418 "SRS..h.I" */
0x52,0x51,0x31,0x82,0x49,0x52,0x51,0x31, /* 00000420 "RQ1.IRQ1" */
0x60,0x76,0x60,0x70,0x60,0x50,0x49,0x52, /* 00000428 "`v`p`PIR" */
0x43,0x5B,0x82,0x49,0x08,0x4C,0x4E,0x4B, /* 00000430 "C[.I.LNK" */
0x44,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000438 "D._HID.A" */
0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44, /* 00000440 "...._UID" */
0x0A,0x04,0x14,0x1C,0x5F,0x53,0x54,0x41, /* 00000448 "...._STA" */
0x00,0x7B,0x50,0x49,0x52,0x44,0x0A,0x80, /* 00000450 ".{PIRD.." */
0x60,0xA0,0x08,0x93,0x60,0x0A,0x80,0xA4, /* 00000458 "`...`..." */
0x0A,0x09,0xA1,0x04,0xA4,0x0A,0x0B,0x14, /* 00000460 "........" */
0x0B,0x5F,0x50,0x52,0x53,0x00,0xA4,0x42, /* 00000468 "._PRS..B" */
0x55,0x46,0x41,0x14,0x11,0x5F,0x44,0x49, /* 00000470 "UFA.._DI" */
0x53,0x00,0x7D,0x50,0x49,0x52,0x44,0x0A, /* 00000478 "S.}PIRD." */
0x80,0x50,0x49,0x52,0x44,0x14,0x1A,0x5F, /* 00000480 ".PIRD.._" */
0x43,0x52,0x53,0x00,0x7B,0x50,0x49,0x52, /* 00000488 "CRS.{PIR" */
0x44,0x0A,0x0F,0x60,0x79,0x01,0x60,0x49, /* 00000490 "D..`y.`I" */
0x52,0x51,0x56,0xA4,0x42,0x55,0x46,0x42, /* 00000498 "RQV.BUFB" */
0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000004A0 ".._SRS.." */
0x68,0x01,0x49,0x52,0x51,0x31,0x82,0x49, /* 000004A8 "h.IRQ1.I" */
0x52,0x51,0x31,0x60,0x76,0x60,0x70,0x60, /* 000004B0 "RQ1`v`p`" */
0x50,0x49,0x52,0x44,0x14,0x16,0x5F,0x50, /* 000004B8 "PIRD.._P" */
0x52,0x54,0x00,0xA0,0x0A,0x50,0x49,0x43, /* 000004C0 "RT...PIC" */
0x44,0xA4,0x50,0x52,0x54,0x41,0xA4,0x50, /* 000004C8 "D.PRTA.P" */
0x52,0x54,0x50,0x08,0x50,0x52,0x54,0x50, /* 000004D0 "RTP.PRTP" */
0x12,0x43,0x0E,0x10,0x12,0x0B,0x04,0x0B, /* 000004D8 ".C......" */
0xFF,0xFF,0x00,0x4C,0x4E,0x4B,0x41,0x00, /* 000004E0 "...LNKA." */
0x12,0x0B,0x04,0x0B,0xFF,0xFF,0x01,0x4C, /* 000004E8 ".......L" */
0x4E,0x4B,0x42,0x00,0x12,0x0C,0x04,0x0B, /* 000004F0 "NKB....." */
0xFF,0xFF,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000004F8 "....LNKC" */
0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF,0x0A, /* 00000500 "........" */
0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000508 ".LNKD..." */
0x04,0x0C,0xFF,0xFF,0x01,0x00,0x00,0x4C, /* 00000510 ".......L" */
0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000518 "NKB....." */
0xFF,0xFF,0x01,0x00,0x01,0x4C,0x4E,0x4B, /* 00000520 ".....LNK" */
0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000528 "C......." */
0x01,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000530 "....LNKD" */
0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01, /* 00000538 "........" */
0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000540 "...LNKA." */
0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 00000548 "........" */
0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000550 ".LNKC..." */
0x04,0x0C,0xFF,0xFF,0x02,0x00,0x01,0x4C, /* 00000558 ".......L" */
0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000560 "NKD....." */
0xFF,0xFF,0x02,0x00,0x0A,0x02,0x4C,0x4E, /* 00000568 "......LN" */
0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000570 "KA......" */
0xFF,0x02,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000578 ".....LNK" */
0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000580 "B......." */
0x03,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000588 "...LNKD." */
0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000590 "........" */
0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000598 ".LNKA..." */
0x04,0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x02, /* 000005A0 "........" */
0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000005A8 "LNKB...." */
0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x03,0x4C, /* 000005B0 ".......L" */
0x4E,0x4B,0x43,0x00,0x08,0x50,0x52,0x54, /* 000005B8 "NKC..PRT" */
0x41,0x12,0x32,0x04,0x12,0x0B,0x04,0x0C, /* 000005C0 "A.2....." */
0xFF,0xFF,0x01,0x00,0x00,0x00,0x0A,0x05, /* 000005C8 "........" */
0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 000005D0 "........" */
0x00,0x00,0x0A,0x07,0x12,0x0B,0x04,0x0C, /* 000005D8 "........" */
0xFF,0xFF,0x03,0x00,0x00,0x00,0x0A,0x0A, /* 000005E0 "........" */
0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 000005E8 "........" */
0x00,0x00,0x0A,0x0B,0x5B,0x82,0x48,0x31, /* 000005F0 "....[.H1" */
0x49,0x53,0x41,0x5F,0x08,0x5F,0x41,0x44, /* 000005F8 "ISA_._AD" */
0x52,0x00,0x5B,0x80,0x50,0x49,0x52,0x51, /* 00000600 "R.[.PIRQ" */
0x02,0x0A,0x60,0x0A,0x04,0x10,0x2E,0x5C, /* 00000608 "..`....\" */
0x00,0x5B,0x81,0x29,0x5C,0x2F,0x04,0x5F, /* 00000610 ".[.)\/._" */
0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x49, /* 00000618 "SB_PCI0I" */
0x53,0x41,0x5F,0x50,0x49,0x52,0x51,0x01, /* 00000620 "SA_PIRQ." */
0x50,0x49,0x52,0x41,0x08,0x50,0x49,0x52, /* 00000628 "PIRA.PIR" */
0x42,0x08,0x50,0x49,0x52,0x43,0x08,0x50, /* 00000630 "B.PIRC.P" */
0x49,0x52,0x44,0x08,0x5B,0x82,0x46,0x0B, /* 00000638 "IRD.[.F." */
0x53,0x59,0x53,0x52,0x08,0x5F,0x48,0x49, /* 00000640 "SYSR._HI" */
0x44,0x0C,0x41,0xD0,0x0C,0x02,0x08,0x5F, /* 00000648 "D.A...._" */
0x55,0x49,0x44,0x01,0x08,0x43,0x52,0x53, /* 00000650 "UID..CRS" */
0x5F,0x11,0x4E,0x08,0x0A,0x8A,0x47,0x01, /* 00000658 "_.N...G." */
0x10,0x00,0x10,0x00,0x00,0x10,0x47,0x01, /* 00000660 "......G." */
0x22,0x00,0x22,0x00,0x00,0x0C,0x47,0x01, /* 00000668 ""."...G." */
0x30,0x00,0x30,0x00,0x00,0x10,0x47,0x01, /* 00000670 "0.0...G." */
0x44,0x00,0x44,0x00,0x00,0x1C,0x47,0x01, /* 00000678 "D.D...G." */
0x62,0x00,0x62,0x00,0x00,0x02,0x47,0x01, /* 00000680 "b.b...G." */
0x65,0x00,0x65,0x00,0x00,0x0B,0x47,0x01, /* 00000688 "e.e...G." */
0x72,0x00,0x72,0x00,0x00,0x0E,0x47,0x01, /* 00000690 "r.r...G." */
0x80,0x00,0x80,0x00,0x00,0x01,0x47,0x01, /* 00000698 "......G." */
0x84,0x00,0x84,0x00,0x00,0x03,0x47,0x01, /* 000006A0 "......G." */
0x88,0x00,0x88,0x00,0x00,0x01,0x47,0x01, /* 000006A8 "......G." */
0x8C,0x00,0x8C,0x00,0x00,0x03,0x47,0x01, /* 000006B0 "......G." */
0x90,0x00,0x90,0x00,0x00,0x10,0x47,0x01, /* 000006B8 "......G." */
0xA2,0x00,0xA2,0x00,0x00,0x1C,0x47,0x01, /* 000006C0 "......G." */
0xE0,0x00,0xE0,0x00,0x00,0x10,0x47,0x01, /* 000006C8 "......G." */
0xA0,0x08,0xA0,0x08,0x00,0x04,0x47,0x01, /* 000006D0 "......G." */
0xC0,0x0C,0xC0,0x0C,0x00,0x10,0x47,0x01, /* 000006D8 "......G." */
0xD0,0x04,0xD0,0x04,0x00,0x02,0x79,0x00, /* 000006E0 "......y." */
0x14,0x0B,0x5F,0x43,0x52,0x53,0x00,0xA4, /* 000006E8 ".._CRS.." */
0x43,0x52,0x53,0x5F,0x5B,0x82,0x2B,0x50, /* 000006F0 "CRS_[.+P" */
0x49,0x43,0x5F,0x08,0x5F,0x48,0x49,0x44, /* 000006F8 "IC_._HID" */
0x0B,0x41,0xD0,0x08,0x5F,0x43,0x52,0x53, /* 00000700 ".A.._CRS" */
0x11,0x18,0x0A,0x15,0x47,0x01,0x20,0x00, /* 00000708 "....G. ." */
0x20,0x00,0x01,0x02,0x47,0x01,0xA0,0x00, /* 00000710 " ...G..." */
0xA0,0x00,0x01,0x02,0x22,0x04,0x00,0x79, /* 00000718 "...."..y" */
0x00,0x5B,0x82,0x47,0x05,0x44,0x4D,0x41, /* 00000720 ".[.G.DMA" */
0x30,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000728 "0._HID.A" */
0xD0,0x02,0x00,0x08,0x5F,0x43,0x52,0x53, /* 00000730 "...._CRS" */
0x11,0x41,0x04,0x0A,0x3D,0x2A,0x10,0x04, /* 00000738 ".A..=*.." */
0x47,0x01,0x00,0x00,0x00,0x00,0x00,0x10, /* 00000740 "G......." */
0x47,0x01,0x81,0x00,0x81,0x00,0x00,0x03, /* 00000748 "G......." */
0x47,0x01,0x87,0x00,0x87,0x00,0x00,0x01, /* 00000750 "G......." */
0x47,0x01,0x89,0x00,0x89,0x00,0x00,0x03, /* 00000758 "G......." */
0x47,0x01,0x8F,0x00,0x8F,0x00,0x00,0x01, /* 00000760 "G......." */
0x47,0x01,0xC0,0x00,0xC0,0x00,0x00,0x20, /* 00000768 "G...... " */
0x47,0x01,0x80,0x04,0x80,0x04,0x00,0x10, /* 00000770 "G......." */
0x79,0x00,0x5B,0x82,0x25,0x54,0x4D,0x52, /* 00000778 "y.[.%TMR" */
0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000780 "_._HID.A" */
0xD0,0x01,0x00,0x08,0x5F,0x43,0x52,0x53, /* 00000788 "...._CRS" */
0x11,0x10,0x0A,0x0D,0x47,0x01,0x40,0x00, /* 00000790 "....G.@." */
0x40,0x00,0x00,0x04,0x22,0x01,0x00,0x79, /* 00000798 "@..."..y" */
0x00,0x5B,0x82,0x25,0x52,0x54,0x43,0x5F, /* 000007A0 ".[.%RTC_" */
0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000007A8 "._HID.A." */
0x0F,0x13,0x08,0x5F,0x43,0x49,0x44,0x0C, /* 000007B0 "..._CID." */
0x41,0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53, /* 000007B8 "A....._S" */
0x54,0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F, /* 000007C0 "TA....._" */
0x43,0x52,0x53,0x11,0x08,0x0A,0x05,0x22, /* 000007C8 "CRS...."" */
0x00,0x10,0x79,0x00,0x5B,0x82,0x42,0x04, /* 000007D0 "..y.[.B." */
0x50,0x53,0x32,0x4B,0x08,0x5F,0x48,0x49, /* 000007D8 "PS2K._HI" */
0x44,0x0C,0x41,0xD0,0x03,0x03,0x08,0x5F, /* 000007E0 "D.A...._" */
0x43,0x49,0x44,0x0C,0x41,0xD0,0x03,0x0B, /* 000007E8 "CID.A..." */
0x14,0x09,0x5F,0x53,0x54,0x41,0x00,0xA4, /* 000007F0 ".._STA.." */
0x0A,0x0F,0x08,0x5F,0x43,0x52,0x53,0x11, /* 000007F8 "..._CRS." */
0x18,0x0A,0x15,0x47,0x01,0x60,0x00,0x60, /* 00000800 "...G.`.`" */
0x00,0x00,0x01,0x47,0x01,0x64,0x00,0x64, /* 00000808 "...G.d.d" */
0x00,0x00,0x01,0x22,0x02,0x00,0x79,0x00, /* 00000810 "..."..y." */
0x5B,0x82,0x3A,0x46,0x44,0x43,0x30,0x08, /* 00000818 "[.:FDC0." */
0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000820 "_HID.A.." */
0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000828 "..._STA." */
0xA4,0x0A,0x0F,0x08,0x5F,0x43,0x52,0x53, /* 00000830 "...._CRS" */
0x11,0x1B,0x0A,0x18,0x47,0x01,0xF0,0x03, /* 00000838 "....G..." */
0xF0,0x03,0x01,0x06,0x47,0x01,0xF7,0x03, /* 00000840 "....G..." */
0xF7,0x03,0x01,0x01,0x22,0x40,0x00,0x2A, /* 00000848 "...."@.*" */
0x04,0x00,0x79,0x00,0x5B,0x82,0x35,0x55, /* 00000850 "..y.[.5U" */
0x41,0x52,0x31,0x08,0x5F,0x48,0x49,0x44, /* 00000858 "AR1._HID" */
0x0C,0x41,0xD0,0x05,0x01,0x08,0x5F,0x55, /* 00000860 ".A...._U" */
0x49,0x44,0x01,0x14,0x09,0x5F,0x53,0x54, /* 00000868 "ID..._ST" */
0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 00000870 "A....._C" */
0x52,0x53,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000878 "RS....G." */
0xF8,0x03,0xF8,0x03,0x01,0x08,0x22,0x10, /* 00000880 "......"." */
0x00,0x79,0x00,0x5B,0x82,0x36,0x55,0x41, /* 00000888 ".y.[.6UA" */
0x52,0x32,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000890 "R2._HID." */
0x41,0xD0,0x05,0x01,0x08,0x5F,0x55,0x49, /* 00000898 "A...._UI" */
0x44,0x0A,0x02,0x14,0x09,0x5F,0x53,0x54, /* 000008A0 "D...._ST" */
0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 000008A8 "A....._C" */
0x52,0x53,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 000008B0 "RS....G." */
0xF8,0x02,0xF8,0x02,0x01,0x08,0x22,0x08, /* 000008B8 "......"." */
0x00,0x79,0x00,
0x0B,0x00,0x08,0x5F,0x43,0x52,0x53,0x11, /* 000007B0 "..._CRS." */
0x10,0x0A,0x0D,0x47,0x01,0x70,0x00,0x70, /* 000007B8 "...G.p.p" */
0x00,0x00,0x02,0x22,0x00,0x01,0x79,0x00, /* 000007C0 "..."..y." */
0x5B,0x82,0x22,0x53,0x50,0x4B,0x52,0x08, /* 000007C8 "[."SPKR." */
0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x08, /* 000007D0 "_HID.A.." */
0x00,0x08,0x5F,0x43,0x52,0x53,0x11,0x0D, /* 000007D8 ".._CRS.." */
0x0A,0x0A,0x47,0x01,0x61,0x00,0x61,0x00, /* 000007E0 "..G.a.a." */
0x00,0x01,0x79,0x00,0x5B,0x82,0x31,0x50, /* 000007E8 "..y.[.1P" */
0x53,0x32,0x4D,0x08,0x5F,0x48,0x49,0x44, /* 000007F0 "S2M._HID" */
0x0C,0x41,0xD0,0x0F,0x13,0x08,0x5F,0x43, /* 000007F8 ".A...._C" */
0x49,0x44,0x0C,0x41,0xD0,0x0F,0x13,0x14, /* 00000800 "ID.A...." */
0x09,0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A, /* 00000808 "._STA..." */
0x0F,0x08,0x5F,0x43,0x52,0x53,0x11,0x08, /* 00000810 ".._CRS.." */
0x0A,0x05,0x22,0x00,0x10,0x79,0x00,0x5B, /* 00000818 ".."..y.[" */
0x82,0x42,0x04,0x50,0x53,0x32,0x4B,0x08, /* 00000820 ".B.PS2K." */
0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x03, /* 00000828 "_HID.A.." */
0x03,0x08,0x5F,0x43,0x49,0x44,0x0C,0x41, /* 00000830 ".._CID.A" */
0xD0,0x03,0x0B,0x14,0x09,0x5F,0x53,0x54, /* 00000838 "....._ST" */
0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 00000840 "A....._C" */
0x52,0x53,0x11,0x18,0x0A,0x15,0x47,0x01, /* 00000848 "RS....G." */
0x60,0x00,0x60,0x00,0x00,0x01,0x47,0x01, /* 00000850 "`.`...G." */
0x64,0x00,0x64,0x00,0x00,0x01,0x22,0x02, /* 00000858 "d.d..."." */
0x00,0x79,0x00,0x5B,0x82,0x3A,0x46,0x44, /* 00000860 ".y.[.:FD" */
0x43,0x30,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000868 "C0._HID." */
0x41,0xD0,0x07,0x00,0x14,0x09,0x5F,0x53, /* 00000870 "A....._S" */
0x54,0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F, /* 00000878 "TA....._" */
0x43,0x52,0x53,0x11,0x1B,0x0A,0x18,0x47, /* 00000880 "CRS....G" */
0x01,0xF0,0x03,0xF0,0x03,0x01,0x06,0x47, /* 00000888 ".......G" */
0x01,0xF7,0x03,0xF7,0x03,0x01,0x01,0x22, /* 00000890 "......."" */
0x40,0x00,0x2A,0x04,0x00,0x79,0x00,0x5B, /* 00000898 "@.*..y.[" */
0x82,0x35,0x55,0x41,0x52,0x31,0x08,0x5F, /* 000008A0 ".5UAR1._" */
0x48,0x49,0x44,0x0C,0x41,0xD0,0x05,0x01, /* 000008A8 "HID.A..." */
0x08,0x5F,0x55,0x49,0x44,0x01,0x14,0x09, /* 000008B0 "._UID..." */
0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 000008B8 "_STA...." */
0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 000008C0 "._CRS..." */
0x0D,0x47,0x01,0xF8,0x03,0xF8,0x03,0x01, /* 000008C8 ".G......" */
0x08,0x22,0x10,0x00,0x79,0x00,0x5B,0x82, /* 000008D0 "."..y.[." */
0x36,0x55,0x41,0x52,0x32,0x08,0x5F,0x48, /* 000008D8 "6UAR2._H" */
0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 000008E0 "ID.A...." */
0x5F,0x55,0x49,0x44,0x0A,0x02,0x14,0x09, /* 000008E8 "_UID...." */
0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 000008F0 "_STA...." */
0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 000008F8 "._CRS..." */
0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02,0x01, /* 00000900 ".G......" */
0x08,0x22,0x08,0x00,0x79,0x00,
};
int DsdtLen=sizeof(AmlCode);
+6 -3
View File
@@ -42,12 +42,15 @@ OBJCOPY = objcopy
CFLAGS += $(DEFINES) -I. $(XENINC) -fno-builtin -O2 -msoft-float
LDFLAGS = -m32 -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR)
SRCS = hvmloader.c acpi_madt.c mp_tables.c util.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
.PHONY: all
all: hvmloader
hvmloader: roms.h hvmloader.c acpi_madt.c mp_tables.c
$(CC) $(CFLAGS) -c hvmloader.c acpi_madt.c mp_tables.c
$(CC) $(LDFLAGS) -o hvmloader.tmp hvmloader.o acpi_madt.o mp_tables.o
hvmloader: roms.h $(SRCS)
$(CC) $(CFLAGS) -c $(SRCS)
$(CC) $(LDFLAGS) -o hvmloader.tmp $(OBJS)
$(OBJCOPY) hvmloader.tmp hvmloader
rm -f hvmloader.tmp
+1 -3
View File
@@ -20,13 +20,11 @@
#include "../acpi/acpi2_0.h"
#include "../acpi/acpi_madt.h"
#include "util.h"
#include <xen/hvm/hvm_info_table.h>
#define NULL ((void*)0)
extern int puts(const char *s);
static struct hvm_info_table *table = NULL;
static int validate_hvm_info(struct hvm_info_table *t)
+67 -58
View File
@@ -23,15 +23,19 @@
*/
#include "roms.h"
#include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
#include "hypercall.h"
#include "util.h"
#include <xen/version.h>
#include <xen/hvm/hvm_info_table.h>
/* memory map */
#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
#define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
/* invoke SVM's paged realmode support */
#define SVM_VMMCALL_RESET_TO_REALMODE 0x00000001
#define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001
/*
* C runtime start off
@@ -75,79 +79,28 @@ extern int acpi_madt_update(unsigned char* acpi_start);
extern void create_mp_tables(void);
struct hvm_info_table *get_hvm_info_table(void);
static inline void
outw(unsigned short addr, unsigned short val)
{
__asm__ __volatile__ ("outw %%ax, %%dx" :: "d"(addr), "a"(val));
}
static inline void
outb(unsigned short addr, unsigned char val)
{
__asm__ __volatile__ ("outb %%al, %%dx" :: "d"(addr), "a"(val));
}
static inline unsigned char
inb(unsigned short addr)
{
unsigned char val;
__asm__ __volatile__ ("inb %w1,%0" : "=a" (val) : "Nd" (addr));
return val;
}
void *
memcpy(void *dest, const void *src, unsigned n)
{
int t0, t1, t2;
__asm__ __volatile__(
"cld\n"
"rep; movsl\n"
"testb $2,%b4\n"
"je 1f\n"
"movsw\n"
"1: testb $1,%b4\n"
"je 2f\n"
"movsb\n"
"2:"
: "=&c" (t0), "=&D" (t1), "=&S" (t2)
: "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
: "memory"
);
return dest;
}
int
puts(const char *s)
{
while (*s)
outb(0xE9, *s++);
return 0;
}
int
static int
cirrus_check(void)
{
outw(0x3C4, 0x9206);
return inb(0x3C5) == 0x12;
}
int
vmmcall(int edi, int esi, int edx, int ecx, int ebx)
static int
vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx)
{
int eax;
__asm__ __volatile__(
".byte 0x0F,0x01,0xD9"
: "=a" (eax)
: "a"(0x58454E00), /* XEN\0 key */
: "a"(function),
"b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi)
);
return eax;
}
int
static int
check_amd(void)
{
char id[12];
@@ -162,6 +115,60 @@ check_amd(void)
return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
}
static void
cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
__asm__ __volatile__(
"cpuid"
: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (idx) );
}
static void
wrmsr(uint32_t idx, uint64_t v)
{
__asm__ __volatile__(
"wrmsr"
: : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
}
static void
init_hypercalls(void)
{
uint32_t eax, ebx, ecx, edx;
unsigned long i;
char signature[13], number[13];
xen_extraversion_t extraversion;
cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
*(uint32_t *)(signature + 0) = ebx;
*(uint32_t *)(signature + 4) = ecx;
*(uint32_t *)(signature + 8) = edx;
signature[12] = '\0';
if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
puts("FATAL: Xen hypervisor not detected\n");
__asm__ __volatile__( "ud2" );
}
cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
puts("Detected Xen v");
puts(itoa(number, eax >> 16));
puts(".");
puts(itoa(number, eax & 0xffff));
cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
for (i = 0; i < eax; i++)
wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
hypercall_xen_version(XENVER_extraversion, extraversion);
puts(extraversion);
puts("\n");
}
int
main(void)
{
@@ -169,6 +176,8 @@ main(void)
puts("HVM Loader\n");
init_hypercalls();
puts("Loading ROMBIOS ...\n");
memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
if (t->apic_enabled)
@@ -200,7 +209,7 @@ main(void)
if (check_amd()) {
/* AMD implies this is SVM */
puts("SVM go ...\n");
vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0);
vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0);
} else {
puts("Loading VMXAssist ...\n");
memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
+180
View File
@@ -0,0 +1,180 @@
/******************************************************************************
* hypercall.h
*
* Copyright (c) 2002-2006, K A Fraser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation; or, when distributed
* separately from the Linux kernel or incorporated into other
* software packages, subject to the following license:
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this source file (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef __HVMLOADER_HYPERCALL_H__
#define __HVMLOADER_HYPERCALL_H__
/*
* NB. Hypercall address needs to be relative to a linkage symbol for
* some version of ld to relocate the relative calls properly.
* Keep this in sync with HYPERCALL_PHYSICAL_ADDRESS in hvmloader.c!
*/
#define hypercall_pa "_start - 0x80000"
#define __STR(x) #x
#define STR(x) __STR(x)
#define _hypercall0(type, name) \
({ \
long __res; \
asm volatile ( \
"call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
: "=a" (__res) \
: \
: "memory" ); \
(type)__res; \
})
#define _hypercall1(type, name, a1) \
({ \
long __res, __ign1; \
asm volatile ( \
"call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
: "=a" (__res), "=b" (__ign1) \
: "1" ((long)(a1)) \
: "memory" ); \
(type)__res; \
})
#define _hypercall2(type, name, a1, a2) \
({ \
long __res, __ign1, __ign2; \
asm volatile ( \
"call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
: "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
: "1" ((long)(a1)), "2" ((long)(a2)) \
: "memory" ); \
(type)__res; \
})
#define _hypercall3(type, name, a1, a2, a3) \
({ \
long __res, __ign1, __ign2, __ign3; \
asm volatile ( \
"call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
: "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
"=d" (__ign3) \
: "1" ((long)(a1)), "2" ((long)(a2)), \
"3" ((long)(a3)) \
: "memory" ); \
(type)__res; \
})
#define _hypercall4(type, name, a1, a2, a3, a4) \
({ \
long __res, __ign1, __ign2, __ign3, __ign4; \
asm volatile ( \
"call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
: "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
"=d" (__ign3), "=S" (__ign4) \
: "1" ((long)(a1)), "2" ((long)(a2)), \
"3" ((long)(a3)), "4" ((long)(a4)) \
: "memory" ); \
(type)__res; \
})
#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
({ \
long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
asm volatile ( \
"call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
: "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
"=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
: "1" ((long)(a1)), "2" ((long)(a2)), \
"3" ((long)(a3)), "4" ((long)(a4)), \
"5" ((long)(a5)) \
: "memory" ); \
(type)__res; \
})
static inline int
hypercall_sched_op(
int cmd, void *arg)
{
return _hypercall2(int, sched_op, cmd, arg);
}
static inline int
hypercall_memory_op(
unsigned int cmd, void *arg)
{
return _hypercall2(int, memory_op, cmd, arg);
}
static inline int
hypercall_multicall(
void *call_list, int nr_calls)
{
return _hypercall2(int, multicall, call_list, nr_calls);
}
static inline int
hypercall_event_channel_op(
int cmd, void *arg)
{
return _hypercall2(int, event_channel_op, cmd, arg);
}
static inline int
hypercall_xen_version(
int cmd, void *arg)
{
return _hypercall2(int, xen_version, cmd, arg);
}
static inline int
hypercall_console_io(
int cmd, int count, char *str)
{
return _hypercall3(int, console_io, cmd, count, str);
}
static inline int
hypercall_vm_assist(
unsigned int cmd, unsigned int type)
{
return _hypercall2(int, vm_assist, cmd, type);
}
static inline int
hypercall_vcpu_op(
int cmd, int vcpuid, void *extra_args)
{
return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
}
static inline int
hypercall_hvm_op(
int cmd, void *arg)
{
return _hypercall2(int, hvm_op, cmd, arg);
}
#endif /* __HVMLOADER_HYPERCALL_H__ */
+2 -1
View File
@@ -93,7 +93,8 @@ typedef signed long int64_t;
#define INTR_MAX_NR 16
extern int puts(const char *); /* for printing */
#include "util.h"
extern int get_vcpu_nr(void); /* for the guest's VCPU count */
/*
+96
View File
@@ -0,0 +1,96 @@
/*
* util.c: Helper library functions for HVMLoader.
*
* Leendert van Doorn, leendert@watson.ibm.com
* Copyright (c) 2005, International Business Machines Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
#include "util.h"
void outw(uint16_t addr, uint16_t val)
{
__asm__ __volatile__ ("outw %%ax, %%dx" :: "d"(addr), "a"(val));
}
void outb(uint16_t addr, uint8_t val)
{
__asm__ __volatile__ ("outb %%al, %%dx" :: "d"(addr), "a"(val));
}
uint8_t inb(uint16_t addr)
{
uint8_t val;
__asm__ __volatile__ ("inb %w1,%0" : "=a" (val) : "Nd" (addr));
return val;
}
char *itoa(char *a, unsigned int i)
{
unsigned int _i = i, x = 0;
do {
x++;
_i /= 10;
} while (_i != 0);
a += x;
*a-- = '\0';
do {
*a-- = (i % 10) + '0';
i /= 10;
} while (i != 0);
return a + 1;
}
int strcmp(const char *cs, const char *ct)
{
signed char res;
while (((res = *cs - *ct++) == 0) && (*cs++ != '\0'))
continue;
return res;
}
void *memcpy(void *dest, const void *src, unsigned n)
{
int t0, t1, t2;
__asm__ __volatile__(
"cld\n"
"rep; movsl\n"
"testb $2,%b4\n"
"je 1f\n"
"movsw\n"
"1: testb $1,%b4\n"
"je 2f\n"
"movsb\n"
"2:"
: "=&c" (t0), "=&D" (t1), "=&S" (t2)
: "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
: "memory"
);
return dest;
}
void puts(const char *s)
{
while (*s)
outb(0xE9, *s++);
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef __HVMLOADER_UTIL_H__
#define __HVMLOADER_UTIL_H__
/* I/O output */
void outw(uint16_t addr, uint16_t val);
void outb(uint16_t addr, uint8_t val);
/* I/O input */
uint8_t inb(uint16_t addr);
/* String and memory functions */
int strcmp(const char *cs, const char *ct);
void *memcpy(void *dest, const void *src, unsigned n);
char *itoa(char *a, unsigned int i);
/* Debug output */
void puts(const char *s);
#endif /* __HVMLOADER_UTIL_H__ */
+28 -3
View File
@@ -52,6 +52,31 @@ char *states[] = {
static char *rnames[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" };
#endif /* DEBUG */
#define PT_ENTRY_PRESENT 0x1
static unsigned
guest_linear_to_real(unsigned long base, unsigned off)
{
unsigned int gcr3 = oldctx.cr3;
unsigned int l1_mfn;
unsigned int l0_mfn;
if (!(oldctx.cr0 & CR0_PG))
return base + off;
l1_mfn = ((unsigned int *)gcr3)[(base >> 22) & 0x3ff ];
if (!(l1_mfn & PT_ENTRY_PRESENT))
panic("l2 entry not present\n");
l1_mfn = l1_mfn & 0xfffff000 ;
l0_mfn = ((unsigned int *)l1_mfn)[(base >> 12) & 0x3ff];
if (!(l0_mfn & PT_ENTRY_PRESENT))
panic("l1 entry not present\n");
l0_mfn = l0_mfn & 0xfffff000;
return l0_mfn + off + (base & 0xfff);
}
static unsigned
address(struct regs *regs, unsigned seg, unsigned off)
{
@@ -70,7 +95,7 @@ address(struct regs *regs, unsigned seg, unsigned off)
(mode == VM86_REAL_TO_PROTECTED && regs->cs == seg))
return ((seg & 0xFFFF) << 4) + off;
entry = ((unsigned long long *) oldctx.gdtr_base)[seg >> 3];
entry = ((unsigned long long *) guest_linear_to_real(oldctx.gdtr_base, 0))[seg >> 3];
entry_high = entry >> 32;
entry_low = entry & 0xFFFFFFFF;
@@ -94,7 +119,7 @@ void
trace(struct regs *regs, int adjust, char *fmt, ...)
{
unsigned off = regs->eip - adjust;
va_list ap;
va_list ap;
if ((traceset & (1 << mode)) &&
(mode == VM86_REAL_TO_PROTECTED || mode == VM86_REAL)) {
@@ -755,7 +780,7 @@ load_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes
return 1;
}
entry = ((unsigned long long *) oldctx.gdtr_base)[sel >> 3];
entry = ((unsigned long long *) guest_linear_to_real(oldctx.gdtr_base, 0))[sel >> 3];
/* Check the P bit first */
if (!((entry >> (15+32)) & 0x1) && sel != 0)
+109
View File
@@ -0,0 +1,109 @@
D/audio////
D/hw////
D/linux-user////
D/pc-bios////
D/slirp////
D/target-arm////
D/target-i386////
D/target-ppc////
D/target-sparc////
D/tests////
D/fpu////
D/keymaps////
D/target-mips////
D/target-sh4////
/.cvsignore/1.14/Sun Aug 6 01:03:44 2006//Trelease_0_8_2
/COPYING/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
/COPYING.LIB/1.2/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
/Changelog/1.121/Sun Aug 6 01:03:44 2006//Trelease_0_8_2
/LICENSE/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/Makefile/1.104/Sun Aug 6 01:03:44 2006//Trelease_0_8_2
/Makefile.target/1.121/Sun Aug 6 01:03:44 2006//Trelease_0_8_2
/README/1.12/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/README.distrib/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/TODO/1.39/Sun Aug 6 01:03:44 2006//Trelease_0_8_2
/VERSION/1.29/Sun Aug 6 01:03:44 2006//Trelease_0_8_2
/a.out.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/aes.c/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
/aes.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
/alpha-dis.c/1.3/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/alpha.ld/1.1/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/arm-dis.c/1.3/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/arm.ld/1.1/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/block-bochs.c/1.1/Sun Aug 6 00:55:02 2006//Trelease_0_8_2
/block-cloop.c/1.3/Sun Aug 6 00:55:02 2006//Trelease_0_8_2
/block-cow.c/1.6/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/block-dmg.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/block-qcow.c/1.7/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/block-vmdk.c/1.8/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/block-vpc.c/1.3/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/block-vvfat.c/1.6/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/block.c/1.28/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/block_int.h/1.5/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/bswap.h/1.5/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
/cocoa.m/1.10/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/configure/1.110/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/console.c/1.8/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/cpu-all.h/1.57/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/cpu-defs.h/1.16/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/cpu-exec.c/1.83/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/dis-asm.h/1.11/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/disas.c/1.31/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/disas.h/1.7/Sun Aug 6 00:55:03 2006//Trelease_0_8_2
/dyngen-exec.h/1.29/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/dyngen-op.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/dyngen.c/1.45/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/dyngen.h/1.11/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/elf.h/1.7/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/elf_ops.h/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/exec-all.h/1.48/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/exec.c/1.82/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/gdbstub.c/1.40/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/gdbstub.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/i386-dis.c/1.5/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/i386-vl.ld/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/i386.ld/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/ia64.ld/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/keymaps.c/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/kqemu.c/1.12/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/kqemu.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/linux-2.6.9-qemu-fast.patch/1.1/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/loader.c/1.3/Sun Aug 6 01:03:45 2006//Trelease_0_8_2
/m68k-dis.c/1.1/Sun Aug 6 01:03:46 2006//Trelease_0_8_2
/m68k.ld/1.1/Sun Aug 6 01:03:46 2006//Trelease_0_8_2
/mips-dis.c/1.4/Sun Aug 6 01:03:47 2006//Trelease_0_8_2
/monitor.c/1.54/Sun Aug 6 01:03:47 2006//Trelease_0_8_2
/osdep.c/1.11/Sun Aug 6 01:03:47 2006//Trelease_0_8_2
/osdep.h/1.6/Sun Aug 6 01:03:47 2006//Trelease_0_8_2
/ppc-dis.c/1.7/Sun Aug 6 01:03:48 2006//Trelease_0_8_2
/ppc.ld/1.2/Sun Aug 6 01:03:48 2006//Trelease_0_8_2
/qemu-binfmt-conf.sh/1.4/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/qemu-doc.texi/1.100/Sun Aug 6 01:03:48 2006//Trelease_0_8_2
/qemu-img.c/1.10/Sun Aug 6 01:03:48 2006//Trelease_0_8_2
/qemu-img.texi/1.2/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/qemu-tech.texi/1.9/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/qemu_socket.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/readline.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/s390.ld/1.1/Sun Aug 6 01:03:48 2006//Trelease_0_8_2
/sdl.c/1.29/Sun Aug 6 01:03:48 2006//Trelease_0_8_2
/sdl_keysym.h/1.3/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/sh4-dis.c/1.1/Sun Aug 6 01:03:48 2006//Trelease_0_8_2
/softmmu_exec.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/softmmu_header.h/1.13/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/softmmu_template.h/1.16/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/sparc-dis.c/1.3/Sun Aug 6 01:03:49 2006//Trelease_0_8_2
/sparc.ld/1.1/Sun Aug 6 01:03:49 2006//Trelease_0_8_2
/tap-win32.c/1.3/Sun Aug 6 01:03:49 2006//Trelease_0_8_2
/texi2pod.pl/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/thunk.c/1.6/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/thunk.h/1.13/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
/translate-all.c/1.14/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/translate-op.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/usb-linux.c/1.8/Sun Aug 6 01:03:49 2006//Trelease_0_8_2
/vgafont.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
/vl.c/1.202/Sun Aug 6 01:03:49 2006//Trelease_0_8_2
/vl.h/1.136/Sun Aug 6 01:03:49 2006//Trelease_0_8_2
/vnc.c/1.7/Sun Aug 6 01:03:49 2006//Trelease_0_8_2
/vnc_keysym.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
/vnchextile.h/1.2/Sun Aug 6 01:03:49 2006//Trelease_0_8_2
/x86_64.ld/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
+7
View File
@@ -0,0 +1,7 @@
A D/linux-user////
A D/slirp////
A D/target-arm////
A D/target-mips////
A D/target-ppc////
A D/target-sh4////
A D/target-sparc////
File renamed without changes.
File renamed without changes.
+1
View File
@@ -0,0 +1 @@
Nrelease_0_8_2
+13
View File
@@ -11,6 +11,8 @@ ppc64-softmmu
ppc-user
qemu-doc.html
qemu-tech.html
qemu-doc.info
qemu-tech.info
qemu.1
qemu.pod
qemu-img.1
@@ -25,5 +27,16 @@ mips-softmmu
mipsel-softmmu
mips-user
mipsel-user
.gdbinit
sh4-user
sh4-softmmu
*.aux
*.cp
*.dvi
*.fn
*.ky
*.log
*.pg
*.toc
*.tp
*.vr
-109
View File
@@ -1,109 +0,0 @@
D/audio////
D/hw////
D/linux-user////
D/pc-bios////
D/slirp////
D/target-arm////
D/target-i386////
D/target-ppc////
D/target-sparc////
D/tests////
D/fpu////
D/keymaps////
D/target-mips////
/.cvsignore/1.13/Thu May 25 18:22:25 2006//Trelease_0_8_1
/COPYING/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1
/COPYING.LIB/1.2/Wed May 17 14:47:01 2006//Trelease_0_8_1
/Changelog/1.116/Thu May 25 18:22:25 2006//Trelease_0_8_1
/LICENSE/1.2/Sat Feb 12 14:45:23 2005//Trelease_0_8_1
/Makefile/1.99/Thu May 25 18:22:25 2006//Trelease_0_8_1
/Makefile.target/1.107/Thu May 25 18:22:25 2006//Trelease_0_8_1
/README/1.12/Wed May 24 10:40:08 2006//Trelease_0_8_1
/README.distrib/1.2/Wed May 17 14:47:01 2006//Trelease_0_8_1
/TODO/1.38/Thu May 25 18:22:25 2006//Trelease_0_8_1
/VERSION/1.28/Thu May 25 18:22:25 2006//Trelease_0_8_1
/a.out.h/1.2/Wed May 24 10:40:08 2006//Trelease_0_8_1
/aes.c/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1
/aes.h/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1
/alpha-dis.c/1.3/Thu May 25 18:22:25 2006//Trelease_0_8_1
/alpha.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1
/arm-dis.c/1.3/Wed May 24 10:40:08 2006//Trelease_0_8_1
/arm.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1
/block-bochs.c/1.1/Tue Apr 26 21:34:00 2005//Trelease_0_8_1
/block-cloop.c/1.3/Thu May 25 18:22:25 2006//Trelease_0_8_1
/block-cow.c/1.5/Thu May 25 12:38:49 2006//Trelease_0_8_1
/block-dmg.c/1.4/Thu May 25 18:22:25 2006//Trelease_0_8_1
/block-qcow.c/1.6/Thu May 25 18:22:25 2006//Trelease_0_8_1
/block-vmdk.c/1.7/Thu May 25 18:22:25 2006//Trelease_0_8_1
/block-vpc.c/1.2/Thu May 25 12:38:49 2006//Trelease_0_8_1
/block-vvfat.c/1.5/Thu May 25 18:22:25 2006//Trelease_0_8_1
/block.c/1.26/Thu May 25 18:22:26 2006//Trelease_0_8_1
/block_int.h/1.4/Thu May 25 18:22:26 2006//Trelease_0_8_1
/bswap.h/1.5/Wed May 17 14:47:01 2006//Trelease_0_8_1
/cocoa.m/1.8/Thu May 25 18:22:26 2006//Trelease_0_8_1
/configure/1.100/Thu May 25 18:22:26 2006//Trelease_0_8_1
/console.c/1.5/Thu May 25 18:22:26 2006//Trelease_0_8_1
/cpu-all.h/1.54/Thu May 25 18:22:26 2006//Trelease_0_8_1
/cpu-defs.h/1.15/Thu May 25 18:22:26 2006//Trelease_0_8_1
/cpu-exec.c/1.78/Thu May 25 18:22:26 2006//Trelease_0_8_1
/dis-asm.h/1.11/Thu May 25 18:22:26 2006//Trelease_0_8_1
/disas.c/1.30/Thu May 25 18:22:26 2006//Trelease_0_8_1
/disas.h/1.7/Thu May 25 18:22:26 2006//Trelease_0_8_1
/dyngen-exec.h/1.27/Thu May 25 18:22:26 2006//Trelease_0_8_1
/dyngen-op.h/1.1/Mon Jan 3 23:40:55 2005//Trelease_0_8_1
/dyngen.c/1.42/Thu May 25 18:22:26 2006//Trelease_0_8_1
/dyngen.h/1.10/Thu May 25 18:22:26 2006//Trelease_0_8_1
/elf.h/1.6/Thu May 25 12:38:50 2006//Trelease_0_8_1
/elf_ops.h/1.3/Tue May 2 20:54:12 2006//Trelease_0_8_1
/exec-all.h/1.47/Thu May 25 18:22:26 2006//Trelease_0_8_1
/exec.c/1.79/Thu May 25 18:22:26 2006//Trelease_0_8_1
/gdbstub.c/1.36/Thu May 25 18:22:26 2006//Trelease_0_8_1
/gdbstub.h/1.2/Tue Apr 26 20:42:36 2005//Trelease_0_8_1
/i386-dis.c/1.5/Wed May 17 14:47:01 2006//Trelease_0_8_1
/i386-vl.ld/1.3/Wed May 17 14:47:01 2006//Trelease_0_8_1
/i386.ld/1.2/Wed May 17 14:47:01 2006//Trelease_0_8_1
/ia64.ld/1.1/Thu Apr 7 22:20:28 2005//Trelease_0_8_1
/keymaps.c/1.2/Thu May 25 18:22:26 2006//Trelease_0_8_1
/kqemu.c/1.10/Thu May 25 18:22:26 2006//Trelease_0_8_1
/kqemu.h/1.1/Wed Feb 8 22:39:17 2006//Trelease_0_8_1
/linux-2.6.9-qemu-fast.patch/1.1/Wed Dec 8 23:48:11 2004//Trelease_0_8_1
/loader.c/1.2/Wed Apr 26 22:05:26 2006//Trelease_0_8_1
/m68k-dis.c/1.1/Sun Nov 6 16:52:11 2005//Trelease_0_8_1
/m68k.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1
/mips-dis.c/1.3/Thu May 25 18:22:28 2006//Trelease_0_8_1
/monitor.c/1.48/Thu May 25 18:22:28 2006//Trelease_0_8_1
/osdep.c/1.10/Wed May 24 10:40:10 2006//Trelease_0_8_1
/osdep.h/1.5/Wed May 24 10:40:10 2006//Trelease_0_8_1
/ppc-dis.c/1.7/Thu May 25 12:38:51 2006//Trelease_0_8_1
/ppc.ld/1.2/Thu May 25 12:38:51 2006//Trelease_0_8_1
/qemu-binfmt-conf.sh/1.4/Thu May 25 18:22:28 2006//Trelease_0_8_1
/qemu-doc.texi/1.87/Thu May 25 18:22:29 2006//Trelease_0_8_1
/qemu-img.c/1.8/Thu May 25 12:38:51 2006//Trelease_0_8_1
/qemu-img.texi/1.2/Thu May 25 12:38:51 2006//Trelease_0_8_1
/qemu-tech.texi/1.9/Thu May 25 18:22:29 2006//Trelease_0_8_1
/qemu_socket.h/1.1/Sun Apr 30 22:53:25 2006//Trelease_0_8_1
/readline.c/1.1/Tue May 23 19:16:56 2006//Trelease_0_8_1
/s390.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1
/sdl.c/1.26/Thu May 25 18:22:29 2006//Trelease_0_8_1
/sdl_keysym.h/1.3/Tue Mar 1 21:43:41 2005//Trelease_0_8_1
/sh4-dis.c/1.1/Thu Apr 27 21:05:14 2006//Trelease_0_8_1
/softmmu_exec.h/1.1/Sun Oct 30 18:16:26 2005//Trelease_0_8_1
/softmmu_header.h/1.13/Thu May 25 18:22:29 2006//Trelease_0_8_1
/softmmu_template.h/1.16/Thu May 25 18:22:29 2006//Trelease_0_8_1
/sparc-dis.c/1.2/Thu May 25 18:22:29 2006//Trelease_0_8_1
/sparc.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1
/tap-win32.c/1.2/Sun Feb 19 12:40:00 2006//Trelease_0_8_1
/texi2pod.pl/1.1/Wed May 17 14:47:02 2006//Trelease_0_8_1
/thunk.c/1.6/Wed May 24 10:40:10 2006//Trelease_0_8_1
/thunk.h/1.13/Wed May 17 14:47:02 2006//Trelease_0_8_1
/translate-all.c/1.14/Thu May 25 18:22:29 2006//Trelease_0_8_1
/translate-op.c/1.1/Sun Mar 13 16:53:06 2005//Trelease_0_8_1
/usb-linux.c/1.4/Sat Mar 11 18:03:38 2006//Trelease_0_8_1
/vgafont.h/1.1/Wed May 17 14:47:02 2006//Trelease_0_8_1
/vl.c/1.184/Thu May 25 18:22:30 2006//Trelease_0_8_1
/vl.h/1.116/Thu May 25 18:22:30 2006//Trelease_0_8_1
/vnc.c/1.4/Mon May 1 21:44:22 2006//Trelease_0_8_1
/vnc_keysym.h/1.1/Sun Apr 30 21:28:36 2006//Trelease_0_8_1
/vnchextile.h/1.1/Sun Apr 30 21:28:36 2006//Trelease_0_8_1
/x86_64.ld/1.1/Thu Jan 6 20:50:00 2005//Trelease_0_8_1
D/target-sh4////
-1
View File
@@ -1 +0,0 @@
Nrelease_0_8_1
+19
View File
@@ -1,3 +1,22 @@
version 0.8.2:
- ACPI support
- PC VGA BIOS fixes
- switch to OpenBios for SPARC targets (Blue Swirl)
- VNC server fixes
- MIPS FPU support (Marius Groeger)
- Solaris/SPARC host support (Ben Taylor)
- PPC breakpoints and single stepping (Jason Wessel)
- USB updates (Paul Brook)
- UDP/TCP/telnet character devices (Jason Wessel)
- Windows sparse file support (Frediano Ziglio)
- RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
- PCNET NIC support (Antony T Curtis)
- Support for variable frequency host CPUs
- Workaround for win32 SMP hosts
- Support for AMD Flash memories (Jocelyn Mayer)
- Audio capture to WAV files support (malc)
version 0.8.1:
- USB tablet support (Brad Campbell, Anthony Liguori)
+25 -6
View File
@@ -1,12 +1,20 @@
# Makefile for QEMU.
XEN_ROOT=../..
include $(XEN_ROOT)/tools/Rules.mk
-include config-host.mak
.PHONY: all clean distclean dvi info install install-doc tar tarbin \
speed test test2 html dvi info
CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I.
ifdef CONFIG_DARWIN
CFLAGS+= -mdynamic-no-pic
endif
ifeq ($(ARCH),sparc)
CFLAGS+=-mcpu=ultrasparc
endif
LDFLAGS=-g
LIBS=
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
@@ -20,11 +28,15 @@ else
DOCS=
endif
all: $(DOCS)
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
TOOLS=
all: $(TOOLS) $(DOCS) recurse-all
subdir-%:
$(MAKE) -C $(subst subdir-,,$@) all
recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
@@ -42,6 +54,7 @@ clean:
distclean: clean
rm -f config-host.mak config-host.h $(DOCS)
rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \
done
@@ -63,7 +76,7 @@ install: all $(if $(BUILD_DOCS),install-doc)
# $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
# mkdir -p "$(DESTDIR)$(datadir)"
# for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
# video.x proll.elf linux_boot.bin; do \
# video.x openbios-sparc32 linux_boot.bin; do \
# $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
# done
ifndef CONFIG_WIN32
@@ -106,6 +119,12 @@ qemu-img.1: qemu-img.texi
perl -w $(SRC_PATH)/texi2pod.pl $< qemu-img.pod
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
info: qemu-doc.info qemu-tech.info
dvi: qemu-doc.dvi qemu-tech.dvi
html: qemu-doc.html qemu-tech.html
FILE=qemu-$(shell cat VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
@@ -138,7 +157,7 @@ tarbin:
$(datadir)/vgabios-cirrus.bin \
$(datadir)/ppc_rom.bin \
$(datadir)/video.x \
$(datadir)/proll.elf \
$(datadir)/openbios-sparc32 \
$(datadir)/linux_boot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
+47 -8
View File
@@ -40,6 +40,11 @@ ifeq ($(TARGET_ARCH),arm)
TARGET_ARCH2=armeb
endif
endif
ifeq ($(TARGET_ARCH),sh4)
ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
TARGET_ARCH2=sh4eb
endif
endif
ifeq ($(TARGET_ARCH),mips)
ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
TARGET_ARCH2=mipsel
@@ -114,17 +119,24 @@ LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
endif
ifeq ($(ARCH),sparc)
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
ifeq ($(CONFIG_SOLARIS),yes)
CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
else
CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
# -static is used to avoid g1/g3 usage by the dynamic linker
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
endif
endif
ifeq ($(ARCH),sparc64)
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
LDFLAGS+=-m64
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
endif
@@ -186,7 +198,12 @@ LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
elfload.o linuxload.o
ifdef TARGET_HAS_BFLT
OBJS+= flatload.o
endif
ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
@@ -323,25 +340,32 @@ endif
ifdef CONFIG_ADLIB
SOUND_HW += fmopl.o adlib.o
endif
AUDIODRV+= wavcapture.o
# SCSI layer
VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
# USB layer
VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o
VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
# PCI network cards
VL_OBJS+= ne2000.o rtl8139.o
VL_OBJS+= ne2000.o rtl8139.o pcnet.o
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o
VL_OBJS+= cirrus_vga.o mixeng.o parallel.o
VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o
VL_OBJS+= usb-uhci.o
VL_OBJS+= piix4acpi.o
VL_OBJS+= xenstore.o
DEFINES += -DHAS_AUDIO
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
DEFINES += -DHAS_AUDIO
endif
ifeq ($(TARGET_ARCH), mips)
@@ -350,7 +374,7 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
ifeq ($(TARGET_ARCH), sparc64)
VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o
VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
VL_OBJS+= cirrus_vga.o parallel.o
else
@@ -361,6 +385,7 @@ endif
ifeq ($(TARGET_BASE_ARCH), arm)
VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
VL_OBJS+= versatile_pci.o
endif
ifeq ($(TARGET_BASE_ARCH), sh4)
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
@@ -398,7 +423,7 @@ endif
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
ifndef CONFIG_SOLARIS
VL_LIBS=-lutil
VL_LIBS=-lutil -lrt
endif
endif
endif
@@ -411,6 +436,11 @@ ifeq ($(ARCH),ia64)
VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
ifeq ($(ARCH),sparc64)
VL_LDFLAGS+=-m64
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
endif
ifdef CONFIG_WIN32
SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
endif
@@ -490,6 +520,13 @@ endif
loader.o: loader.c elf_ops.h
acpi.o: acpi.c acpi-dsdt.hex
ifdef BUILD_ACPI_TABLES
$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl
iasl -tc -p $@ $<
endif
ifeq ($(TARGET_ARCH), sh4)
op.o: op.c op_mem.c cpu.h
op_helper.o: op_helper.c exec.h cpu.h
@@ -500,6 +537,8 @@ sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h
tc58128.o: tc58128.c
endif
$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+2 -8
View File
@@ -1,24 +1,20 @@
short term:
----------
- support variable tsc freq
- cycle counter for all archs
- cpu_interrupt() win32/SMP fix
- support variable tsc freq
- USB host async
- IDE async
- debug option in 'configure' script + disable -fomit-frame-pointer
- Precise VGA timings for old games/demos (malc patch)
- merge PIC spurious interrupt patch
- merge Solaris patch
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
- config file (at least for windows/Mac OS X)
- commit message if execution of code in IO memory
- update doc: PCI infos.
- VNC patch + Synaptic patch.
- basic VGA optimizations
- physical memory cache (reduce qemu-fast address space size to about 32 MB)
- better code fetch (different exception handling + CS.limit support)
- do not resize vga if invalid size.
- avoid looping if only exceptions
- cycle counter for all archs
- TLB code protection support for PPC
- see openMosix Doc
- disable SMC handling for ARM/SPARC/PPC (not finished)
@@ -31,12 +27,10 @@ short term:
- fix CCOP optimisation
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- fix arm fpu rounding (at least for float->integer conversions)
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
- SPR_ENCODE() not useful
- enable shift optimizations ?
linux-user specific:
+1 -1
View File
@@ -1 +1 @@
0.8.1
0.8.2
+20
View File
@@ -0,0 +1,20 @@
/alsaaudio.c/1.7/Sun Aug 6 01:03:49 2006//Trelease_0_8_2
/audio.c/1.14/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/audio.h/1.8/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/audio_int.h/1.10/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/audio_template.h/1.8/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/coreaudio.c/1.7/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/dsound_template.h/1.4/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/dsoundaudio.c/1.3/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/fmodaudio.c/1.7/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/mixeng.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/mixeng.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/mixeng_template.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/noaudio.c/1.7/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/ossaudio.c/1.11/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/rate_template.h/1.3/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/sdlaudio.c/1.8/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/sys-queue.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
/wavaudio.c/1.8/Sun Aug 6 01:03:50 2006//Trelease_0_8_2
/wavcapture.c/1.5/Sat Jul 22 17:06:44 2006//Trelease_0_8_2
D
File renamed without changes.
File renamed without changes.
+1
View File
@@ -0,0 +1 @@
Nrelease_0_8_2
-19
View File
@@ -1,19 +0,0 @@
/alsaaudio.c/1.5/Sun Nov 20 18:53:05 2005//Trelease_0_8_1
/audio.c/1.9/Thu May 25 18:22:31 2006//Trelease_0_8_1
/audio.h/1.5/Thu May 25 18:22:31 2006//Trelease_0_8_1
/audio_int.h/1.7/Thu May 25 18:22:31 2006//Trelease_0_8_1
/audio_template.h/1.4/Sun Nov 20 16:24:34 2005//Trelease_0_8_1
/coreaudio.c/1.5/Sun Nov 20 18:53:42 2005//Trelease_0_8_1
/dsound_template.h/1.2/Sat Nov 5 18:55:27 2005//Trelease_0_8_1
/dsoundaudio.c/1.2/Sat Nov 5 18:55:27 2005//Trelease_0_8_1
/fmodaudio.c/1.5/Thu May 25 18:22:32 2006//Trelease_0_8_1
/mixeng.c/1.4/Thu May 25 18:22:32 2006//Trelease_0_8_1
/mixeng.h/1.2/Thu May 25 18:22:32 2006//Trelease_0_8_1
/mixeng_template.h/1.2/Thu May 25 18:22:32 2006//Trelease_0_8_1
/noaudio.c/1.4/Thu May 25 18:22:32 2006//Trelease_0_8_1
/ossaudio.c/1.9/Thu May 25 18:22:32 2006//Trelease_0_8_1
/rate_template.h/1.2/Sat Nov 5 18:55:27 2005//Trelease_0_8_1
/sdlaudio.c/1.6/Thu May 25 18:22:32 2006//Trelease_0_8_1
/sys-queue.h/1.1/Sun Oct 30 18:58:22 2005//Trelease_0_8_1
/wavaudio.c/1.6/Thu May 25 18:22:32 2006//Trelease_0_8_1
D
-1
View File
@@ -1 +0,0 @@
Nrelease_0_8_1
+6 -13
View File
@@ -61,8 +61,8 @@ static struct {
.size_in_usec_in = 1,
.size_in_usec_out = 1,
#endif
.pcm_name_out = "hw:0,0",
.pcm_name_in = "hw:0,0",
.pcm_name_out = "default",
.pcm_name_in = "default",
#ifdef HIGH_LATENCY
.buffer_size_in = 400000,
.period_size_in = 400000 / 4,
@@ -606,7 +606,6 @@ static int alsa_run_out (HWVoiceOut *hw)
}
}
mixeng_clear (src, written);
rpos = (rpos + written) % hw->samples;
samples -= written;
len -= written;
@@ -663,12 +662,9 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianness)
);
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
@@ -752,12 +748,9 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianness)
);
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+419 -29
View File
@@ -29,6 +29,7 @@
/* #define DEBUG_PLIVE */
/* #define DEBUG_LIVE */
/* #define DEBUG_OUT */
/* #define DEBUG_CAPTURE */
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
@@ -137,7 +138,7 @@ int audio_bug (const char *funcname, int cond)
if (cond) {
static int shown;
AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname);
AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
if (!shown) {
shown = 1;
AUD_log (NULL, "Save all your work and restart without audio\n");
@@ -509,14 +510,28 @@ static void audio_print_settings (audsettings_t *as)
AUD_log (NULL, "invalid(%d)", as->fmt);
break;
}
AUD_log (NULL, " endianness=");
switch (as->endianness) {
case 0:
AUD_log (NULL, "little");
break;
case 1:
AUD_log (NULL, "big");
break;
default:
AUD_log (NULL, "invalid");
break;
}
AUD_log (NULL, "\n");
}
static int audio_validate_settigs (audsettings_t *as)
static int audio_validate_settings (audsettings_t *as)
{
int invalid;
invalid = as->nchannels != 1 && as->nchannels != 2;
invalid |= as->endianness != 0 && as->endianness != 1;
switch (as->fmt) {
case AUD_FMT_S8:
@@ -530,11 +545,7 @@ static int audio_validate_settigs (audsettings_t *as)
}
invalid |= as->freq <= 0;
if (invalid) {
return -1;
}
return 0;
return invalid ? -1 : 0;
}
static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
@@ -556,14 +567,11 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
return info->freq == as->freq
&& info->nchannels == as->nchannels
&& info->sign == sign
&& info->bits == bits;
&& info->bits == bits
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
}
void audio_pcm_init_info (
struct audio_pcm_info *info,
audsettings_t *as,
int swap_endian
)
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
{
int bits = 8, sign = 0;
@@ -587,7 +595,7 @@ void audio_pcm_init_info (
info->shift = (as->nchannels == 2) + (bits == 16);
info->align = (1 << info->shift) - 1;
info->bytes_per_second = info->freq << info->shift;
info->swap_endian = swap_endian;
info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
}
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
@@ -597,11 +605,11 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
}
if (info->sign) {
memset (buf, len << info->shift, 0x00);
memset (buf, 0x00, len << info->shift);
}
else {
if (info->bits == 8) {
memset (buf, len << info->shift, 0x80);
memset (buf, 0x80, len << info->shift);
}
else {
int i;
@@ -609,7 +617,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
int shift = info->nchannels - 1;
short s = INT16_MAX;
if (info->swap_endian) {
if (info->swap_endianness) {
s = bswap16 (s);
}
@@ -620,6 +628,143 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
}
}
/*
* Capture
*/
static void noop_conv (st_sample_t *dst, const void *src,
int samples, volume_t *vol)
{
(void) src;
(void) dst;
(void) samples;
(void) vol;
}
static CaptureVoiceOut *audio_pcm_capture_find_specific (
AudioState *s,
audsettings_t *as
)
{
CaptureVoiceOut *cap;
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
if (audio_pcm_info_eq (&cap->hw.info, as)) {
return cap;
}
}
return NULL;
}
static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
{
struct capture_callback *cb;
#ifdef DEBUG_CAPTURE
dolog ("notification %d sent\n", cmd);
#endif
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
cb->ops.notify (cb->opaque, cmd);
}
}
static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
{
if (cap->hw.enabled != enabled) {
audcnotification_e cmd;
cap->hw.enabled = enabled;
cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
audio_notify_capture (cap, cmd);
}
}
static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
{
HWVoiceOut *hw = &cap->hw;
SWVoiceOut *sw;
int enabled = 0;
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (sw->active) {
enabled = 1;
break;
}
}
audio_capture_maybe_changed (cap, enabled);
}
static void audio_detach_capture (HWVoiceOut *hw)
{
SWVoiceCap *sc = hw->cap_head.lh_first;
while (sc) {
SWVoiceCap *sc1 = sc->entries.le_next;
SWVoiceOut *sw = &sc->sw;
CaptureVoiceOut *cap = sc->cap;
int was_active = sw->active;
if (sw->rate) {
st_rate_stop (sw->rate);
sw->rate = NULL;
}
LIST_REMOVE (sw, entries);
LIST_REMOVE (sc, entries);
qemu_free (sc);
if (was_active) {
/* We have removed soft voice from the capture:
this might have changed the overall status of the capture
since this might have been the only active voice */
audio_recalc_and_notify_capture (cap);
}
sc = sc1;
}
}
static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
{
CaptureVoiceOut *cap;
audio_detach_capture (hw);
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
SWVoiceCap *sc;
SWVoiceOut *sw;
HWVoiceOut *hw_cap = &cap->hw;
sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
if (!sc) {
dolog ("Could not allocate soft capture voice (%zu bytes)\n",
sizeof (*sc));
return -1;
}
sc->cap = cap;
sw = &sc->sw;
sw->hw = hw_cap;
sw->info = hw->info;
sw->empty = 1;
sw->active = hw->enabled;
sw->conv = noop_conv;
sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
if (!sw->rate) {
dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
qemu_free (sw);
return -1;
}
LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
#ifdef DEBUG_CAPTURE
asprintf (&sw->name, "for %p %d,%d,%d",
hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
dolog ("Added %s active = %d\n", sw->name, sw->active);
#endif
if (sw->active) {
audio_capture_maybe_changed (cap, 1);
}
}
return 0;
}
/*
* Hard voice (capture)
*/
@@ -796,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
}
if (live == hwsamples) {
#ifdef DEBUG_OUT
dolog ("%s is full %d\n", sw->name, live);
#endif
return 0;
}
@@ -914,19 +1062,14 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
hw = sw->hw;
if (sw->active != on) {
SWVoiceOut *temp_sw;
SWVoiceCap *sc;
if (on) {
int total;
hw->pending_disable = 0;
if (!hw->enabled) {
hw->enabled = 1;
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
}
if (sw->empty) {
total = 0;
}
}
else {
if (hw->enabled) {
@@ -940,6 +1083,13 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
hw->pending_disable = nb_active == 1;
}
}
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
sc->sw.active = hw->enabled;
if (hw->enabled) {
audio_capture_maybe_changed (sc->cap, 1);
}
}
sw->active = on;
}
}
@@ -997,7 +1147,7 @@ static int audio_get_avail (SWVoiceIn *sw)
}
ldebug (
"%s: get_avail live %d ret %lld\n",
"%s: get_avail live %d ret %" PRId64 "\n",
SW_NAME (sw),
live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
);
@@ -1023,7 +1173,7 @@ static int audio_get_free (SWVoiceOut *sw)
dead = sw->hw->samples - live;
#ifdef DEBUG_OUT
dolog ("%s: get_free live %d dead %d ret %lld\n",
dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
SW_NAME (sw),
live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
#endif
@@ -1031,6 +1181,43 @@ static int audio_get_free (SWVoiceOut *sw)
return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
}
static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
{
int n;
if (hw->enabled) {
SWVoiceCap *sc;
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
SWVoiceOut *sw = &sc->sw;
int rpos2 = rpos;
n = samples;
while (n) {
int till_end_of_hw = hw->samples - rpos2;
int to_write = audio_MIN (till_end_of_hw, n);
int bytes = to_write << hw->info.shift;
int written;
sw->buf = hw->mix_buf + rpos2;
written = audio_pcm_sw_write (sw, NULL, bytes);
if (written - bytes) {
dolog ("Could not mix %d bytes into a capture "
"buffer, mixed %d\n",
bytes, written);
break;
}
n -= to_write;
rpos2 = (rpos2 + to_write) % hw->samples;
}
}
}
n = audio_MIN (samples, hw->samples - rpos);
mixeng_clear (hw->mix_buf + rpos, n);
mixeng_clear (hw->mix_buf, samples - n);
}
static void audio_run_out (AudioState *s)
{
HWVoiceOut *hw = NULL;
@@ -1038,7 +1225,7 @@ static void audio_run_out (AudioState *s)
while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
int played;
int live, free, nb_live, cleanup_required;
int live, free, nb_live, cleanup_required, prev_rpos;
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
if (!nb_live) {
@@ -1051,12 +1238,17 @@ static void audio_run_out (AudioState *s)
}
if (hw->pending_disable && !nb_live) {
SWVoiceCap *sc;
#ifdef DEBUG_OUT
dolog ("Disabling voice\n");
#endif
hw->enabled = 0;
hw->pending_disable = 0;
hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
sc->sw.active = 0;
audio_recalc_and_notify_capture (sc->cap);
}
continue;
}
@@ -1072,6 +1264,7 @@ static void audio_run_out (AudioState *s)
continue;
}
prev_rpos = hw->rpos;
played = hw->pcm_ops->run_out (hw);
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
@@ -1085,6 +1278,7 @@ static void audio_run_out (AudioState *s)
if (played) {
hw->ts_helper += played;
audio_capture_mix_and_clear (hw, prev_rpos, played);
}
cleanup_required = 0;
@@ -1115,15 +1309,18 @@ static void audio_run_out (AudioState *s)
}
if (cleanup_required) {
restart:
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
SWVoiceOut *sw1;
sw = hw->sw_head.lh_first;
while (sw) {
sw1 = sw->entries.le_next;
if (!sw->active && !sw->callback.fn) {
#ifdef DEBUG_PLIVE
dolog ("Finishing with old voice\n");
#endif
audio_close_out (s, sw);
goto restart; /* play it safe */
}
sw = sw1;
}
}
}
@@ -1158,12 +1355,60 @@ static void audio_run_in (AudioState *s)
}
}
static void audio_run_capture (AudioState *s)
{
CaptureVoiceOut *cap;
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
int live, rpos, captured;
HWVoiceOut *hw = &cap->hw;
SWVoiceOut *sw;
captured = live = audio_pcm_hw_get_live_out (hw);
rpos = hw->rpos;
while (live) {
int left = hw->samples - rpos;
int to_capture = audio_MIN (live, left);
st_sample_t *src;
struct capture_callback *cb;
src = hw->mix_buf + rpos;
hw->clip (cap->buf, src, to_capture);
mixeng_clear (src, to_capture);
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
cb->ops.capture (cb->opaque, cap->buf,
to_capture << hw->info.shift);
}
rpos = (rpos + to_capture) % hw->samples;
live -= to_capture;
}
hw->rpos = rpos;
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (!sw->active && sw->empty) {
continue;
}
if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) {
dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
captured, sw->total_hw_samples_mixed);
captured = sw->total_hw_samples_mixed;
}
sw->total_hw_samples_mixed -= captured;
sw->empty = sw->total_hw_samples_mixed == 0;
}
}
}
static void audio_timer (void *opaque)
{
AudioState *s = opaque;
audio_run_out (s);
audio_run_in (s);
audio_run_capture (s);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
}
@@ -1327,8 +1572,19 @@ static void audio_atexit (void)
HWVoiceIn *hwi = NULL;
while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
SWVoiceCap *sc;
hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
hwo->pcm_ops->fini_out (hwo);
for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
CaptureVoiceOut *cap = sc->cap;
struct capture_callback *cb;
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
cb->ops.destroy (cb->opaque);
}
}
}
while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
@@ -1383,6 +1639,7 @@ AudioState *AUD_init (void)
LIST_INIT (&s->hw_head_out);
LIST_INIT (&s->hw_head_in);
LIST_INIT (&s->cap_head);
atexit (audio_atexit);
s->ts = qemu_new_timer (vm_clock, audio_timer, s);
@@ -1479,3 +1736,136 @@ AudioState *AUD_init (void)
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
return s;
}
CaptureVoiceOut *AUD_add_capture (
AudioState *s,
audsettings_t *as,
struct audio_capture_ops *ops,
void *cb_opaque
)
{
CaptureVoiceOut *cap;
struct capture_callback *cb;
if (!s) {
/* XXX suppress */
s = &glob_audio_state;
}
if (audio_validate_settings (as)) {
dolog ("Invalid settings were passed when trying to add capture\n");
audio_print_settings (as);
goto err0;
}
cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
if (!cb) {
dolog ("Could not allocate capture callback information, size %zu\n",
sizeof (*cb));
goto err0;
}
cb->ops = *ops;
cb->opaque = cb_opaque;
cap = audio_pcm_capture_find_specific (s, as);
if (cap) {
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
return cap;
}
else {
HWVoiceOut *hw;
CaptureVoiceOut *cap;
cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
if (!cap) {
dolog ("Could not allocate capture voice, size %zu\n",
sizeof (*cap));
goto err1;
}
hw = &cap->hw;
LIST_INIT (&hw->sw_head);
LIST_INIT (&cap->cb_head);
/* XXX find a more elegant way */
hw->samples = 4096 * 4;
hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
sizeof (st_sample_t));
if (!hw->mix_buf) {
dolog ("Could not allocate capture mix buffer (%d samples)\n",
hw->samples);
goto err2;
}
audio_pcm_init_info (&hw->info, as);
cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!cap->buf) {
dolog ("Could not allocate capture buffer "
"(%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
goto err3;
}
hw->clip = mixeng_clip
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endianness]
[hw->info.bits == 16];
LIST_INSERT_HEAD (&s->cap_head, cap, entries);
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
hw = NULL;
while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
audio_attach_capture (s, hw);
}
return cap;
err3:
qemu_free (cap->hw.mix_buf);
err2:
qemu_free (cap);
err1:
qemu_free (cb);
err0:
return NULL;
}
}
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
{
struct capture_callback *cb;
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
if (cb->opaque == cb_opaque) {
cb->ops.destroy (cb_opaque);
LIST_REMOVE (cb, entries);
qemu_free (cb);
if (!cap->cb_head.lh_first) {
SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
while (sw) {
SWVoiceCap *sc = (SWVoiceCap *) sw;
#ifdef DEBUG_CAPTURE
dolog ("freeing %s\n", sw->name);
#endif
sw1 = sw->entries.le_next;
if (sw->rate) {
st_rate_stop (sw->rate);
sw->rate = NULL;
}
LIST_REMOVE (sw, entries);
LIST_REMOVE (sc, entries);
qemu_free (sc);
sw = sw1;
}
LIST_REMOVE (cap, entries);
qemu_free (cap);
}
return;
}
}
}
+41 -5
View File
@@ -24,6 +24,7 @@
#ifndef QEMU_AUDIO_H
#define QEMU_AUDIO_H
#include "config.h"
#include "sys-queue.h"
typedef void (*audio_callback_fn_t) (void *opaque, int avail);
@@ -35,14 +36,44 @@ typedef enum {
AUD_FMT_S16
} audfmt_e;
#ifdef WORDS_BIGENDIAN
#define AUDIO_HOST_ENDIANNESS 1
#else
#define AUDIO_HOST_ENDIANNESS 0
#endif
typedef struct {
int freq;
int nchannels;
audfmt_e fmt;
int endianness;
} audsettings_t;
typedef enum {
AUD_CNOTIFY_ENABLE,
AUD_CNOTIFY_DISABLE
} audcnotification_e;
struct audio_capture_ops {
void (*notify) (void *opaque, audcnotification_e cmd);
void (*capture) (void *opaque, void *buf, int size);
void (*destroy) (void *opaque);
};
struct capture_ops {
void (*info) (void *opaque);
void (*destroy) (void *opaque);
};
typedef struct CaptureState {
void *opaque;
struct capture_ops ops;
LIST_ENTRY (CaptureState) entries;
} CaptureState;
typedef struct AudioState AudioState;
typedef struct SWVoiceOut SWVoiceOut;
typedef struct CaptureVoiceOut CaptureVoiceOut;
typedef struct SWVoiceIn SWVoiceIn;
typedef struct QEMUSoundCard {
@@ -66,6 +97,13 @@ AudioState *AUD_init (void);
void AUD_help (void);
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
void AUD_remove_card (QEMUSoundCard *card);
CaptureVoiceOut *AUD_add_capture (
AudioState *s,
audsettings_t *as,
struct audio_capture_ops *ops,
void *opaque
);
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
SWVoiceOut *AUD_open_out (
QEMUSoundCard *card,
@@ -73,8 +111,7 @@ SWVoiceOut *AUD_open_out (
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
audsettings_t *settings,
int sw_endian
audsettings_t *settings
);
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
@@ -92,8 +129,7 @@ SWVoiceIn *AUD_open_in (
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
audsettings_t *settings,
int sw_endian
audsettings_t *settings
);
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
@@ -111,7 +147,7 @@ static inline void *advance (void *p, int incr)
}
uint32_t popcount (uint32_t u);
inline uint32_t lsbindex (uint32_t u);
uint32_t lsbindex (uint32_t u);
#ifdef __GNUC__
#define audio_MIN(a, b) ( __extension__ ({ \
+26 -14
View File
@@ -61,13 +61,14 @@ struct audio_pcm_info {
int align;
int shift;
int bytes_per_second;
int swap_endian;
int swap_endianness;
};
typedef struct SWVoiceCap SWVoiceCap;
typedef struct HWVoiceOut {
int enabled;
int pending_disable;
int valid;
struct audio_pcm_info info;
f_sample *clip;
@@ -79,6 +80,7 @@ typedef struct HWVoiceOut {
int samples;
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
struct audio_pcm_ops *pcm_ops;
LIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
@@ -160,14 +162,34 @@ struct audio_pcm_ops {
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
};
struct capture_callback {
struct audio_capture_ops ops;
void *opaque;
LIST_ENTRY (capture_callback) entries;
};
struct CaptureVoiceOut {
HWVoiceOut hw;
void *buf;
LIST_HEAD (cb_listhead, capture_callback) cb_head;
LIST_ENTRY (CaptureVoiceOut) entries;
};
struct SWVoiceCap {
SWVoiceOut sw;
CaptureVoiceOut *cap;
LIST_ENTRY (SWVoiceCap) entries;
};
struct AudioState {
struct audio_driver *drv;
void *drv_opaque;
QEMUTimer *ts;
LIST_HEAD (card_head, QEMUSoundCard) card_head;
LIST_HEAD (card_listhead, QEMUSoundCard) card_head;
LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
int nb_hw_voices_out;
int nb_hw_voices_in;
};
@@ -182,8 +204,7 @@ extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern volume_t nominal_volume;
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as,
int swap_endian);
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
@@ -204,15 +225,6 @@ static inline int audio_ring_dist (int dst, int src, int len)
return (dst >= src) ? (dst - src) : (len - src + dst);
}
static inline int audio_need_to_swap_endian (int endianness)
{
#ifdef WORDS_BIGENDIAN
return endianness != 1;
#else
return endianness != 0;
#endif
}
#if defined __GNUC__
#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2)))
#define INIT_FIELD(f) . f
+19 -14
View File
@@ -140,13 +140,12 @@ static int glue (audio_pcm_sw_init_, TYPE) (
SW *sw,
HW *hw,
const char *name,
audsettings_t *as,
int endian
audsettings_t *as
)
{
int err;
audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian));
audio_pcm_init_info (&sw->info, as);
sw->hw = hw;
sw->active = 0;
#ifdef DAC
@@ -164,7 +163,7 @@ static int glue (audio_pcm_sw_init_, TYPE) (
#endif
[sw->info.nchannels == 2]
[sw->info.sign]
[sw->info.swap_endian]
[sw->info.swap_endianness]
[sw->info.bits == 16];
sw->name = qemu_strdup (name);
@@ -200,6 +199,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp)
HW *hw = *hwp;
if (!hw->sw_head.lh_first) {
#ifdef DAC
audio_detach_capture (hw);
#endif
LIST_REMOVE (hw, entries);
glue (s->nb_hw_voices_, TYPE) += 1;
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
@@ -266,7 +268,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
hw->pcm_ops = drv->pcm_ops;
LIST_INIT (&hw->sw_head);
#ifdef DAC
LIST_INIT (&hw->cap_head);
#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
goto err0;
}
@@ -283,7 +287,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
#endif
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endian]
[hw->info.swap_endianness]
[hw->info.bits == 16];
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
@@ -292,6 +296,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
glue (s->nb_hw_voices_, TYPE) -= 1;
#ifdef DAC
audio_attach_capture (s, hw);
#endif
return hw;
err1:
@@ -328,8 +335,7 @@ static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
AudioState *s,
const char *sw_name,
audsettings_t *as,
int sw_endian
audsettings_t *as
)
{
SW *sw;
@@ -357,7 +363,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) {
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
goto err3;
}
@@ -399,8 +405,7 @@ SW *glue (AUD_open_, TYPE) (
const char *name,
void *callback_opaque ,
audio_callback_fn_t callback_fn,
audsettings_t *as,
int sw_endian
audsettings_t *as
)
{
AudioState *s;
@@ -421,7 +426,7 @@ SW *glue (AUD_open_, TYPE) (
s = card->audio;
if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) {
if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
audio_print_settings (as);
goto fail;
}
@@ -473,12 +478,12 @@ SW *glue (AUD_open_, TYPE) (
}
glue (audio_pcm_sw_fini_, TYPE) (sw);
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) {
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
goto fail;
}
}
else {
sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian);
sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as);
if (!sw) {
dolog ("Failed to create voice `%s'\n", name);
return NULL;
+1 -11
View File
@@ -275,8 +275,6 @@ static OSStatus audioDeviceIOProc(
#endif
}
/* cleanup */
mixeng_clear (src, frameCount);
rpos = (rpos + frameCount) % hw->samples;
core->decr += frameCount;
core->rpos = rpos;
@@ -297,7 +295,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
UInt32 propertySize;
int err;
int bits = 8;
int endianess = 0;
const char *typ = "playback";
AudioValueRange frameRange;
@@ -310,16 +307,9 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
bits = 16;
endianess = 1;
}
audio_pcm_init_info (
&hw->info,
as,
/* Following is irrelevant actually since we do not use
mixengs clipping routines */
audio_need_to_swap_endian (endianess)
);
audio_pcm_init_info (&hw->info, as);
/* open default output device */
propertySize = sizeof(core->outputDeviceID);
+9 -9
View File
@@ -70,7 +70,13 @@ static int glue (dsound_lock_, TYPE) (
int i;
LPVOID p1 = NULL, p2 = NULL;
DWORD blen1 = 0, blen2 = 0;
DWORD flag;
#ifdef DSBTYPE_IN
flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
#else
flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
#endif
for (i = 0; i < conf.lock_retries; ++i) {
hr = glue (IFACE, _Lock) (
buf,
@@ -80,13 +86,7 @@ static int glue (dsound_lock_, TYPE) (
&blen1,
&p2,
&blen2,
(entire
#ifdef DSBTYPE_IN
? DSCBLOCK_ENTIREBUFFER
#else
? DSBLOCK_ENTIREBUFFER
#endif
: 0)
flag
);
if (FAILED (hr)) {
@@ -250,8 +250,8 @@ static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
}
ds->first_time = 1;
audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0));
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
if (bc.dwBufferBytes & hw->info.align) {
dolog (
+6 -2
View File
@@ -453,13 +453,11 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
if (src_len1) {
hw->clip (dst, src1, src_len1);
mixeng_clear (src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
mixeng_clear (src2, src_len2);
}
hw->rpos = pos % hw->samples;
@@ -987,6 +985,12 @@ static void *dsound_audio_init (void)
hr = IDirectSound_Initialize (s->dsound, NULL);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not initialize DirectSound\n");
hr = IDirectSound_Release (s->dsound);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not release DirectSound\n");
}
s->dsound = NULL;
return NULL;
}
+6 -4
View File
@@ -153,13 +153,11 @@ static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
if (src_len1) {
hw->clip (dst, src1, src_len1);
mixeng_clear (src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
mixeng_clear (src2, src_len2);
}
hw->rpos = pos % hw->samples;
@@ -360,6 +358,7 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
{
int bits16, mode, channel;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
audsettings_t obt_as = *as;
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
@@ -386,7 +385,8 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
fmd->channel = channel;
/* FMOD always operates on little endian frames? */
audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;
@@ -420,6 +420,7 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
{
int bits16, mode;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
audsettings_t obt_as = *as;
if (conf.broken_adc) {
return -1;
@@ -442,7 +443,8 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
}
/* FMOD always operates on little endian frames? */
audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;
+21 -19
View File
@@ -40,22 +40,21 @@ static int no_run_out (HWVoiceOut *hw)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
int live, decr, samples;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX) {
samples = INT_MAX >> hw->info.shift;
}
else {
samples = bytes >> hw->info.shift;
}
int64_t now;
int64_t ticks;
int64_t bytes;
live = audio_pcm_hw_get_live_out (&no->hw);
if (!live) {
return 0;
}
now = qemu_get_clock (vm_clock);
ticks = now - no->old_ticks;
bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
no->old_ticks = now;
decr = audio_MIN (live, samples);
hw->rpos = (hw->rpos + decr) % hw->samples;
@@ -69,7 +68,7 @@ static int no_write (SWVoiceOut *sw, void *buf, int len)
static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
{
audio_pcm_init_info (&hw->info, as, 0);
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
@@ -88,7 +87,7 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
{
audio_pcm_init_info (&hw->info, as, 0);
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
@@ -101,17 +100,20 @@ static void no_fini_in (HWVoiceIn *hw)
static int no_run_in (HWVoiceIn *hw)
{
NoVoiceIn *no = (NoVoiceIn *) hw;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int samples;
int samples = 0;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
samples = audio_MIN (samples, dead);
if (dead) {
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
no->old_ticks = now;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
samples = audio_MIN (samples, dead);
}
return samples;
}
+23 -17
View File
@@ -55,12 +55,14 @@ static struct {
int fragsize;
const char *devpath_out;
const char *devpath_in;
int debug;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
.devpath_in = "/dev/dsp"
.devpath_in = "/dev/dsp",
.debug = 0
};
struct oss_params {
@@ -324,9 +326,20 @@ static int oss_run_out (HWVoiceOut *hw)
return 0;
}
if (abinfo.bytes < 0 || abinfo.bytes > bufsize) {
ldebug ("warning: Invalid available size, size=%d bufsize=%d\n",
abinfo.bytes, bufsize);
if (abinfo.bytes > bufsize) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
"please report your OS/audio hw to malc@pulsesoft.com\n",
abinfo.bytes, bufsize);
}
abinfo.bytes = bufsize;
}
if (abinfo.bytes < 0) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
abinfo.bytes, bufsize);
}
return 0;
}
@@ -369,15 +382,12 @@ static int oss_run_out (HWVoiceOut *hw)
"alignment %d\n",
wbytes, written, hw->info.align + 1);
}
mixeng_clear (src, wsamples);
decr -= wsamples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
}
mixeng_clear (src, convert_samples);
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
@@ -443,12 +453,9 @@ static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianness)
);
audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
@@ -587,12 +594,9 @@ static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianness)
);
audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
@@ -730,6 +734,8 @@ static struct audio_option oss_options[] = {
"Path to DAC device", NULL, 0},
{"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
"Path to ADC device", NULL, 0},
{"DEBUG", AUD_OPT_BOOL, &conf.debug,
"Turn on some debugging messages", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
+1 -1
View File
@@ -51,7 +51,7 @@ void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
if (rate->opos_inc == (1ULL + UINT_MAX)) {
int i, n = *isamp > *osamp ? *osamp : *isamp;
for (i = 0; i < n; i++) {
OP (obuf[i].l, ibuf[i].r);
OP (obuf[i].l, ibuf[i].l);
OP (obuf[i].r, ibuf[i].r);
}
*isamp = n;
+2 -6
View File
@@ -240,7 +240,6 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
mixeng_clear (src, chunk);
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->info.shift;
@@ -336,12 +335,9 @@ static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.channels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianess;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianess)
);
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
s->initialized = 1;
+2 -2
View File
@@ -81,7 +81,6 @@ static int wav_run_out (HWVoiceOut *hw)
hw->clip (dst, src, convert_samples);
qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
mixeng_clear (src, convert_samples);
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
@@ -136,7 +135,8 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
hdr[34] = bits16 ? 0x10 : 0x08;
audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0));
wav_as.endianness = 0;
audio_pcm_init_info (&hw->info, &wav_as);
hw->samples = 1024;
wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+164
View File
@@ -0,0 +1,164 @@
#include "vl.h"
typedef struct {
QEMUFile *f;
int bytes;
char *path;
int freq;
int bits;
int nchannels;
CaptureVoiceOut *cap;
} WAVState;
/* VICE code: Store number as little endian. */
static void le_store (uint8_t *buf, uint32_t val, int len)
{
int i;
for (i = 0; i < len; i++) {
buf[i] = (uint8_t) (val & 0xff);
val >>= 8;
}
}
static void wav_notify (void *opaque, audcnotification_e cmd)
{
(void) opaque;
(void) cmd;
}
static void wav_destroy (void *opaque)
{
WAVState *wav = opaque;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t datalen = wav->bytes;
uint32_t rifflen = datalen + 36;
if (!wav->f) {
return;
}
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
fclose (wav->f);
if (wav->path) {
qemu_free (wav->path);
}
}
static void wav_capture (void *opaque, void *buf, int size)
{
WAVState *wav = opaque;
qemu_put_buffer (wav->f, buf, size);
wav->bytes += size;
}
static void wav_capture_destroy (void *opaque)
{
WAVState *wav = opaque;
AUD_del_capture (wav->cap, wav);
}
static void wav_capture_info (void *opaque)
{
WAVState *wav = opaque;
char *path = wav->path;
term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
wav->freq, wav->bits, wav->nchannels,
path ? path : "<not available>", wav->bytes);
}
static struct capture_ops wav_capture_ops = {
.destroy = wav_capture_destroy,
.info = wav_capture_info
};
int wav_start_capture (CaptureState *s, const char *path, int freq,
int bits, int nchannels)
{
WAVState *wav;
uint8_t hdr[] = {
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
};
audsettings_t as;
struct audio_capture_ops ops;
int stereo, bits16, shift;
CaptureVoiceOut *cap;
if (bits != 8 && bits != 16) {
term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
return -1;
}
if (nchannels != 1 && nchannels != 2) {
term_printf ("incorrect channel count %d, must be 1 or 2\n",
nchannels);
return -1;
}
stereo = nchannels == 2;
bits16 = bits == 16;
as.freq = freq;
as.nchannels = 1 << stereo;
as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
as.endianness = 0;
ops.notify = wav_notify;
ops.capture = wav_capture;
ops.destroy = wav_destroy;
wav = qemu_mallocz (sizeof (*wav));
if (!wav) {
term_printf ("Could not allocate memory for wav capture (%zu bytes)",
sizeof (*wav));
return -1;
}
shift = bits16 + stereo;
hdr[34] = bits16 ? 0x10 : 0x08;
le_store (hdr + 22, as.nchannels, 2);
le_store (hdr + 24, freq, 4);
le_store (hdr + 28, freq << shift, 4);
le_store (hdr + 32, 1 << shift, 2);
wav->f = fopen (path, "wb");
if (!wav->f) {
term_printf ("Failed to open wave file `%s'\nReason: %s\n",
path, strerror (errno));
qemu_free (wav);
return -1;
}
wav->path = qemu_strdup (path);
wav->bits = bits;
wav->nchannels = nchannels;
wav->freq = freq;
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
cap = AUD_add_capture (NULL, &as, &ops, wav);
if (!cap) {
term_printf ("Failed to add audio capture\n");
qemu_free (wav);
return -1;
}
wav->cap = cap;
s->opaque = wav;
s->ops = wav_capture_ops;
return 0;
}
+1 -1
View File
@@ -91,7 +91,7 @@ static int bochs_open(BlockDriverState *bs, const char *filename)
int fd, i;
struct bochs_header bochs;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
+1 -1
View File
@@ -55,7 +55,7 @@ static int cloop_open(BlockDriverState *bs, const char *filename)
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size,max_compressed_block_size=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE | O_SYNC);
if (s->fd < 0)
return -1;
bs->read_only = 1;
+8 -1
View File
@@ -69,7 +69,7 @@ static int cow_open(BlockDriverState *bs, const char *filename)
struct cow_header_v2 cow_header;
int64_t size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
@@ -250,6 +250,12 @@ static int cow_create(const char *filename, int64_t image_sectors,
return 0;
}
static void cow_flush(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
fsync(s->fd);
}
BlockDriver bdrv_cow = {
"cow",
sizeof(BDRVCowState),
@@ -259,6 +265,7 @@ BlockDriver bdrv_cow = {
cow_write,
cow_close,
cow_create,
cow_flush,
cow_is_allocated,
};
#endif
+8 -1
View File
@@ -95,7 +95,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename)
int fd, len, i, shift;
QCowHeader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
@@ -693,6 +693,12 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
return 0;
}
static void qcow_flush(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
fsync(s->fd);
}
BlockDriver bdrv_qcow = {
"qcow",
sizeof(BDRVQcowState),
@@ -702,6 +708,7 @@ BlockDriver bdrv_qcow = {
qcow_write,
qcow_close,
qcow_create,
qcow_flush,
qcow_is_allocated,
qcow_set_key,
qcow_make_empty
+8 -1
View File
@@ -96,7 +96,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
uint32_t magic;
int l1_size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
@@ -426,6 +426,12 @@ static void vmdk_close(BlockDriverState *bs)
close(s->fd);
}
static void vmdk_flush(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
fsync(s->fd);
}
BlockDriver bdrv_vmdk = {
"vmdk",
sizeof(BDRVVmdkState),
@@ -435,5 +441,6 @@ BlockDriver bdrv_vmdk = {
vmdk_write,
vmdk_close,
vmdk_create,
vmdk_flush,
vmdk_is_allocated,
};
+1 -1
View File
@@ -163,7 +163,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
bitmap_offset = 512 * s->pagetable[pagetable_index];
block_offset = bitmap_offset + 512 + (512 * pageentry_index);
// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
// sector_num, pagetable_index, pageentry_index,
// bitmap_offset, block_offset);
+1
View File
@@ -2772,6 +2772,7 @@ BlockDriver bdrv_vvfat = {
vvfat_read,
vvfat_write,
vvfat_close,
NULL, /* ??? Not sure if we can do any meaningful flushing. */
NULL,
vvfat_is_allocated
};
+63 -1
View File
@@ -615,6 +615,14 @@ const char *bdrv_get_device_name(BlockDriverState *bs)
return bs->device_name;
}
void bdrv_flush(BlockDriverState *bs)
{
if (bs->drv->bdrv_flush)
bs->drv->bdrv_flush(bs);
if (bs->backing_hd)
bdrv_flush(bs->backing_hd);
}
void bdrv_info(void)
{
BlockDriverState *bs;
@@ -677,7 +685,7 @@ static int raw_open(BlockDriverState *bs, const char *filename)
int rv;
#endif
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
@@ -750,9 +758,55 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
bs->total_sectors = 0;
close(s->fd);
}
#ifdef _WIN32
#include <windows.h>
#include <winioctl.h>
int qemu_ftruncate64(int fd, int64_t length)
{
LARGE_INTEGER li;
LONG high;
HANDLE h;
BOOL res;
if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
return -1;
h = (HANDLE)_get_osfhandle(fd);
/* get current position, ftruncate do not change position */
li.HighPart = 0;
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
return -1;
high = length >> 32;
if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
return -1;
res = SetEndOfFile(h);
/* back to old position */
SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
return res ? 0 : -1;
}
static int set_sparse(int fd)
{
DWORD returned;
return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
NULL, 0, NULL, 0, &returned, NULL);
}
#else
static inline int set_sparse(int fd)
{
return 1;
}
#endif
static int raw_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
@@ -765,11 +819,18 @@ static int raw_create(const char *filename, int64_t total_size,
0644);
if (fd < 0)
return -EIO;
set_sparse(fd);
ftruncate(fd, total_size * 512);
close(fd);
return 0;
}
static void raw_flush(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
fsync(s->fd);
}
BlockDriver bdrv_raw = {
"raw",
sizeof(BDRVRawState),
@@ -779,6 +840,7 @@ BlockDriver bdrv_raw = {
raw_write,
raw_close,
raw_create,
raw_flush,
};
void bdrv_init(void)
+1
View File
@@ -36,6 +36,7 @@ struct BlockDriver {
void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, int64_t total_sectors,
const char *backing_file, int flags);
void (*bdrv_flush)(BlockDriverState *bs);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
+36 -20
View File
@@ -439,23 +439,40 @@ static void cocoa_refresh(DisplayState *ds)
kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
/* handle monitor key events */
} else {
int keysym = 0;
switch([event keyCode]) {
case 123:
kbd_put_keysym(QEMU_KEY_LEFT);
break;
case 124:
kbd_put_keysym(QEMU_KEY_RIGHT);
break;
case 125:
kbd_put_keysym(QEMU_KEY_DOWN);
break;
case 126:
kbd_put_keysym(QEMU_KEY_UP);
break;
default:
kbd_put_keysym([[event characters] characterAtIndex:0]);
break;
case 115:
keysym = QEMU_KEY_HOME;
break;
case 117:
keysym = QEMU_KEY_DELETE;
break;
case 119:
keysym = QEMU_KEY_END;
break;
case 123:
keysym = QEMU_KEY_LEFT;
break;
case 124:
keysym = QEMU_KEY_RIGHT;
break;
case 125:
keysym = QEMU_KEY_DOWN;
break;
case 126:
keysym = QEMU_KEY_UP;
break;
default:
{
NSString *ks = [event characters];
if ([ks length] > 0)
keysym = [ks characterAtIndex:0];
}
}
if (keysym)
kbd_put_keysym(keysym);
}
}
}
@@ -867,10 +884,9 @@ static void setupWindowMenu(void)
/* Finally give up our references to the objects */
[windowMenu release];
[windowMenuItem release];
}
static void CustomApplicationMain (argc, argv)
static void CustomApplicationMain(void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
QemuCocoaGUIController *gui_controller;
@@ -904,8 +920,8 @@ int main(int argc, char **argv)
{
gArgc = argc;
gArgv = argv;
CustomApplicationMain (argc, argv);
CustomApplicationMain();
return 0;
}
Vendored Regular → Executable
+38 -17
View File
@@ -96,6 +96,8 @@ check_gcc="no"
softmmu="yes"
user="no"
build_docs="no"
build_acpi_tables="no"
uname_release=""
# OS specific
targetos=`uname -s`
@@ -212,7 +214,7 @@ for opt do
;;
--fmod-inc=*) fmod_inc="$optarg"
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
;;
--disable-slirp) slirp="no"
;;
@@ -226,8 +228,6 @@ for opt do
;;
--enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
;;
--disable-gfx-check) check_gfx="no"
;;
--disable-gcc-check) check_gcc="no"
;;
--disable-system) softmmu="no"
@@ -238,6 +238,10 @@ for opt do
;;
--enable-user) user="yes"
;;
--enable-uname-release=*) uname_release="$optarg"
;;
--enable-iasl) build_acpi_tables="yes"
;;
esac
done
@@ -285,6 +289,8 @@ echo " --enable-user enable all linux usermode emulation targets"
echo " --disable-user disable all linux usermode emulation targets"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
echo " --enable-iasl compilation of ACPI tables with the IASL compiler"
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
exit 1
@@ -294,15 +300,21 @@ cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if [ ! -x "`which $cc`" ] ; then
echo "Compiler $cc could not be found"
exit
# check that the C compiler works.
cat > $TMPC <<EOF
int main(void) {}
EOF
if $cc -c -o $TMPO $TMPC 2>/dev/null ; then
: C compiler works ok
else
echo "ERROR: \"$cc\" either does not exist or does not work"
exit 1
fi
if test "$mingw32" = "yes" ; then
linux="no"
EXESUF=".exe"
gdbstub="no"
oss="no"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
@@ -553,6 +565,8 @@ fi
echo "FMOD support $fmod $fmod_support"
echo "kqemu support $kqemu"
echo "Documentation $build_docs"
[ ! -z "$uname_release" ] && \
echo "uname -r $uname_release"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -705,6 +719,9 @@ echo "TARGET_DIRS=$target_list" >> $config_mak
if [ "$build_docs" = "yes" ] ; then
echo "BUILD_DOCS=yes" >> $config_mak
fi
if [ "$build_acpi_tables" = "yes" ] ; then
echo "BUILD_ACPI_TABLES=yes" >> $config_mak
fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
@@ -713,6 +730,8 @@ if [ "$bsd" = "yes" ] ; then
echo "#define _BSD 1" >> $config_h
fi
echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
for target in $target_list; do
target_dir="$target"
config_mak=$target_dir/config.mak
@@ -725,6 +744,7 @@ target_bigendian="no"
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
[ "$target_cpu" = "mips" ] && target_bigendian=yes
[ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
@@ -736,14 +756,6 @@ if expr $target : '.*-user' > /dev/null ; then
target_user_only="yes"
fi
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
-a "$sdl" = "no" -a "$cocoa" = "no" ; then
echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
echo "To build QEMU without graphical output configure with --disable-gfx-check"
echo "Note that this will disable all output from the virtual graphics card."
exit 1;
fi
#echo "Creating $config_mak, $config_h and $target_dir/Makefile"
mkdir -p $target_dir
@@ -769,6 +781,7 @@ echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "include ../config-host.mak" >> $config_mak
echo "#include \"../config-host.h\"" >> $config_h
bflt="no"
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
@@ -789,6 +802,7 @@ elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
echo "TARGET_ARCH=arm" >> $config_mak
echo "#define TARGET_ARCH \"arm\"" >> $config_h
echo "#define TARGET_ARM 1" >> $config_h
bflt="yes"
elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
@@ -819,10 +833,13 @@ elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then
echo "TARGET_ARCH=mips" >> $config_mak
echo "#define TARGET_ARCH \"mips\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
elif test "$target_cpu" = "sh4" ; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
echo "TARGET_ARCH=sh4" >> $config_mak
echo "#define TARGET_ARCH \"sh4\"" >> $config_h
echo "#define TARGET_SH4 1" >> $config_h
bflt="yes"
else
echo "Unsupported target CPU"
exit 1
@@ -844,10 +861,14 @@ if expr $target : '.*-dm' > /dev/null ; then
echo "#define CONFIG_DM 1" >> $config_h
fi
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
fi
if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
echo "TARGET_HAS_BFLT=yes" >> $config_mak
echo "#define TARGET_HAS_BFLT 1" >> $config_h
fi
# sdl defines
if test "$target_user_only" = "no"; then
+126 -44
View File
@@ -27,8 +27,8 @@
#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define RGB(r, g, b) RGBA(r, g, b, 0xff)
#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
typedef struct TextAttributes {
uint8_t fgcol:4;
@@ -53,6 +53,57 @@ enum TTYState {
TTY_STATE_CSI,
};
typedef struct QEMUFIFO {
uint8_t *buf;
int buf_size;
int count, wptr, rptr;
} QEMUFIFO;
int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
{
int l, len;
l = f->buf_size - f->count;
if (len1 > l)
len1 = l;
len = len1;
while (len > 0) {
l = f->buf_size - f->wptr;
if (l > len)
l = len;
memcpy(f->buf + f->wptr, buf, l);
f->wptr += l;
if (f->wptr >= f->buf_size)
f->wptr = 0;
buf += l;
len -= l;
}
f->count += len1;
return len1;
}
int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
{
int l, len;
if (len1 > f->count)
len1 = f->count;
len = len1;
while (len > 0) {
l = f->buf_size - f->rptr;
if (l > len)
l = len;
memcpy(buf, f->buf + f->rptr, l);
f->rptr += l;
if (f->rptr >= f->buf_size)
f->rptr = 0;
buf += l;
len -= l;
}
f->count -= len1;
return len1;
}
/* ??? This is mis-named.
It is used for both text and graphical consoles. */
struct TextConsole {
@@ -81,8 +132,13 @@ struct TextConsole {
int nb_esc_params;
/* kbd read handler */
IOCanRWHandler *fd_can_read;
IOReadHandler *fd_read;
void *fd_opaque;
/* fifo for key pressed */
QEMUFIFO out_fifo;
uint8_t out_fifo_buf[16];
QEMUTimer *kbd_timer;
};
static TextConsole *active_console;
@@ -274,24 +330,24 @@ enum color_names {
static const uint32_t color_table_rgb[2][8] = {
{ /* dark */
RGB(0x00, 0x00, 0x00), /* black */
RGB(0xaa, 0x00, 0x00), /* red */
RGB(0x00, 0xaa, 0x00), /* green */
RGB(0xaa, 0xaa, 0x00), /* yellow */
RGB(0x00, 0x00, 0xaa), /* blue */
RGB(0xaa, 0x00, 0xaa), /* magenta */
RGB(0x00, 0xaa, 0xaa), /* cyan */
RGB(0xaa, 0xaa, 0xaa), /* white */
QEMU_RGB(0x00, 0x00, 0x00), /* black */
QEMU_RGB(0xaa, 0x00, 0x00), /* red */
QEMU_RGB(0x00, 0xaa, 0x00), /* green */
QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
},
{ /* bright */
RGB(0x00, 0x00, 0x00), /* black */
RGB(0xff, 0x00, 0x00), /* red */
RGB(0x00, 0xff, 0x00), /* green */
RGB(0xff, 0xff, 0x00), /* yellow */
RGB(0x00, 0x00, 0xff), /* blue */
RGB(0xff, 0x00, 0xff), /* magenta */
RGB(0x00, 0xff, 0xff), /* cyan */
RGB(0xff, 0xff, 0xff), /* white */
QEMU_RGB(0x00, 0x00, 0x00), /* black */
QEMU_RGB(0xff, 0x00, 0x00), /* red */
QEMU_RGB(0x00, 0xff, 0x00), /* green */
QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
QEMU_RGB(0x00, 0x00, 0xff), /* blue */
QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
QEMU_RGB(0xff, 0xff, 0xff), /* white */
}
};
@@ -563,7 +619,6 @@ static void console_put_lf(TextConsole *s)
TextCell *c;
int x, y1;
s->x = 0;
s->y++;
if (s->y >= s->height) {
s->y = s->height - 1;
@@ -712,15 +767,12 @@ static void console_putchar(TextConsole *s, int ch)
console_put_lf(s);
break;
case '\b': /* backspace */
if(s->x > 0) s->x--;
y1 = (s->y_base + s->y) % s->total_height;
c = &s->cells[y1 * s->width + s->x];
c->ch = ' ';
c->t_attrib = s->t_attrib;
update_xy(s, s->x, s->y);
if (s->x > 0)
s->x--;
break;
case '\t': /* tabspace */
if (s->x + (8 - (s->x % 8)) > s->width) {
s->x = 0;
console_put_lf(s);
} else {
s->x = s->x + (8 - (s->x % 8));
@@ -739,8 +791,10 @@ static void console_putchar(TextConsole *s, int ch)
c->t_attrib = s->t_attrib;
update_xy(s, s->x, s->y);
s->x++;
if (s->x >= s->width)
if (s->x >= s->width) {
s->x = 0;
console_put_lf(s);
}
break;
}
break;
@@ -835,6 +889,7 @@ static void console_chr_add_read_handler(CharDriverState *chr,
IOReadHandler *fd_read, void *opaque)
{
TextConsole *s = chr->opaque;
s->fd_can_read = fd_can_read;
s->fd_read = fd_read;
s->fd_opaque = opaque;
}
@@ -854,6 +909,28 @@ static void console_send_event(CharDriverState *chr, int event)
}
}
static void kbd_send_chars(void *opaque)
{
TextConsole *s = opaque;
int len;
uint8_t buf[16];
len = s->fd_can_read(s->fd_opaque);
if (len > s->out_fifo.count)
len = s->out_fifo.count;
if (len > 0) {
if (len > sizeof(buf))
len = sizeof(buf);
qemu_fifo_read(&s->out_fifo, buf, len);
s->fd_read(s->fd_opaque, buf, len);
}
/* characters are pending: we send them a bit later (XXX:
horrible, should change char device API) */
if (s->out_fifo.count > 0) {
qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
}
}
/* called when an ascii key is pressed */
void kbd_put_keysym(int keysym)
{
@@ -879,25 +956,26 @@ void kbd_put_keysym(int keysym)
console_scroll(10);
break;
default:
if (s->fd_read) {
/* convert the QEMU keysym to VT100 key string */
q = buf;
if (keysym >= 0xe100 && keysym <= 0xe11f) {
*q++ = '\033';
*q++ = '[';
c = keysym - 0xe100;
if (c >= 10)
*q++ = '0' + (c / 10);
*q++ = '0' + (c % 10);
*q++ = '~';
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
*q++ = '\033';
*q++ = '[';
*q++ = keysym & 0xff;
} else {
/* convert the QEMU keysym to VT100 key string */
q = buf;
if (keysym >= 0xe100 && keysym <= 0xe11f) {
*q++ = '\033';
*q++ = '[';
c = keysym - 0xe100;
if (c >= 10)
*q++ = '0' + (c / 10);
*q++ = '0' + (c % 10);
*q++ = '~';
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
*q++ = '\033';
*q++ = '[';
*q++ = keysym & 0xff;
} else {
*q++ = keysym;
}
s->fd_read(s->fd_opaque, buf, q - buf);
}
if (s->fd_read) {
qemu_fifo_write(&s->out_fifo, buf, q - buf);
kbd_send_chars(s);
}
break;
}
@@ -984,6 +1062,10 @@ CharDriverState *text_console_init(DisplayState *ds)
chr->chr_add_read_handler = console_chr_add_read_handler;
chr->chr_send_event = console_send_event;
s->out_fifo.buf = s->out_fifo_buf;
s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
if (!color_inited) {
color_inited = 1;
set_color_table(ds);
Loaded 100 of 368 files, more files were not shown because too many files have changed in this diff. Show more
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.