(headermagic123+(git-899d98836513qemu0 "1'ڠ@(stage1H?ޭ?||C| |C||C`| 8N A@|C| |C||C| 8N A@|C| |C||C`| 8N A@|C| |C||C| 8N A@|C| |C||C`| 8N A@|C| |C||C| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8 N A@|C| |C||C `| 8 N A@|C| |C||C `| 8 N A@|C| |C||C `| 8 N A@|C| |C||C `| 8 N A@|C| |C||C `| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8N A@|C| |C||C`| 8 N A@|C| |C||C `| 8!N A@|C| |C||C!`| 8"N A@|C| |C||C"`| 8#N A@|C| |C||C#`| 8$N A@|C| |C||C$`| 8%N A@|C| |C||C%`| 8&N A@|C| |C||C&`| 8'N A@|C| |C||C'`| 8(N A@|C| |C||C(`| 8)N A@|C| |C||C)`| 8*N A@|C| |C||C*`| 8+N A@|C| |C||C+`| 8,N A@|C| |C||C,`| 8-N A@|C| |C||C-`| 8.N A@|C| |C||C.`| 8/N A@|x}`9y}kcx}`dL,8` HE8` H=8` H58`SH-8`LH%8`OH8`FHHq8`I|iN!xf8`X88D"N git-899d98836513bb3db#A@aHPX`hp!xAa!Aa!Aa (8}@}H} /| 0!8N |)< !A@aHPX`hp!xAa!Aa!Aa (0}8}8}@}&H}PHb#|xH18}@}H} P}A@aHPX`hp!xAa!Aa!Aa (!8|B| |B||BL$`N |H[?25l ********************************************************************** QEMU Starting  Build Date = Oct 22 2019 15:05:10 FW Version = git-899d98836513bb3d |h|H< E1001 - Boot ROM CRC failure  E1002 - Memory could not be initialized  E1003 - Firmware image incomplete internal FLS1-FFS-0. E1004 - Unspecified Internal Firmware Error internal FLSX-SE-0.|x|#x|+x|3x9@P9@(x|J|c#xHx;|#AHH}|#x8|#8AH}B,A4Hx}B8|'0A8|' 8`AP|#x|qB8|' A||(8 8`~x}N }|+x|+xH9,@ }N |:8EPB~%x}N }(|#x|jx|#x8 |+xHE, @ ,|*@8`}(N 8`|B}(N 9J9k |-p9AN q@9N !|08@H|+xKY0|H@88!PN }|ixi,AH 9)K}N }|ixy#' pc, A8c8c0Hy#F pc, A8c8c0Hy#e pc, A8c8c0Hy# pc, A8c8c0Hy# pc, A8c8c0Hey# pc, A8c8c0HIy# pc, A8c8c0H-y#"pc, A8c8c0Hy#'pc, A8c8c0Hy#Fpc, A8c8c0Hy#epc, A8c8c0Hy#pc, A8c8c0Hy#pc, A8c8c0Hy#pc, A8c8c0Hiy#pc, A8c8c0HMy#pc, A8c8c0H1}N }|ixK}|ixKt}|ixKxf8`X88D"N |jx8`T8D"|#yA xF jN <``cxcdc`cy <`xd`JhTA8| B< `!x!d!`!8a|H58`xH< `!x!d!`!8!a|hN <@`BxBdB`BDN |fx8`8<`D\K|8Tc0T0| PT||l|||L,8cBN ``B|!xi=B9J|y)$?;}*H*/A4A(Ii}IIN!A(8!|N 9 /)/@|p="9)|xc$|*N ```B|A|zxa|#x84 0@xA?<9[x;@}[|P@8!!AaN ```BUJ:H>4 0@xAK``BH>4 0@xAtKX```B(})(>4 0@xA4 0@xAK``ByJ"H>4 0@xAK``BH>4 0@xAK```BUIyJ}IRH>4 0@xAxK\yJH>4 0@xAPK4``BxH`>4 0@xAK ``B9#9:8N,9#|F,9<N,9#|F,9>}@L,9#}F,}L(9#(L(9#0|L,9#4}`N,9#6|N,9#8} N,C9C }@T((0c46:<>C #8}#R9IL,9}}T,9I|T(9I}`T(9I|T(9I |T(9I(|T(9I0}@T( i (I0C86@})2@N ```Bc0N /8M 9%T>})9#`BBN /8M 9%8})9#`BDIBN @@L}$*H@A@/9E|RM !E|*|R}DHP}I``BIEBN /M |89#```BDIBN |!|dx|i@;8`});|8!a} N `B;KD```B|!A|#x|}x8|+x|3xa8 |;x}Cx}>Kx!Q}H `/|cA9@``B9J}J/@yJ }^RP@P}*P})9)}[8Py) P@9)})A H$@ '8};8P@B8!8`!Aa|N 9@Kt```B|a|#x|~x|+x;!aH4``B^}9)>xK5`@A8!8`a|N !|hyaA/8`A="aXp9)1xA>B!9p:!!9!!H:R18AP`|3x;!h;A}Cx%/AH}@P}Cx@@8+%889EA(}ESx%/9@9 (a!A!HAPaX`px|}Ph|c8!N `B+iAl+uAd+xA\+XAT+pAL+cAD+sA<+%A+OA,+oA$}GSx&|+x9G%}J+d@8}NR|8|:* 9%q)A(9 ~$x!/A{QA| 9(0::8::a@}{x}8!```B9%:U*>++Al=B9J%y)}*J})R})N LLLLLLLLLLLLLLLLLLLLL\LL<LLLLLLLL```B:z$||P}sx}RP*8p9 CxP8~fxK~ex~x8| PCx|PKm}{x/A|@P~x8@Aa (08@|;98K`B8`8!N `B9H9 %8A(`BKz$||P}sx}RP*8p9 Cx P8}FSxAKA~x8}ESxK}{x:K$}!8 8}sxpH`|jxAKq`A|c@\!|cPP|c|P}HHP8@}$Kx@P8cxc 9C}IH ```B}HHP}$KxP@@ 9@ I!9)!B}$Kx| Px|PCxK5}{xKH`B}A|Px89 9 p}sxCxKCx| P|PK~x8xK```B+l}{x:@|#xK+h}{x:@|#x:K```B+u}!xpAV89@9)}IH6 H9@| P8 |P~fx}sx9 CxK~ex~x8 K``B}A|P9 9 }sx8 p8CxK!}{x 9K```B9%U)>+ A}!:z p}{xK`B9 0!K```BK``B9 -(z$}RH*!}3P88K9#+M 8c|cN ,$|ixAh+$$AH<x`&```BI+ |T6q@/@+0@I8 /x@,9 I} Cx+08@؉I/xA9@08`H4``B}4(9)}EL $|hRI/M 9 8U>T>* +}4@89 @T>9J+}H4M (9)}EAN `BA9)$K/A/@K4```B8 /@88`N ```B8K9 I} CxK|@@Hx|3x}JJ9JU)0UJ0}IPPUJ}I|Hl||O|L,9)B;8A8`8!|N `Bxx<|=D`ha"8A\8`K<|=D`ha"K@/@8`K exception %llx SRR0 = %08llx%08llx SRR1 = %08llx%08llx SPRG2 = %08llx%08llx SPRG3 = %08llx%08llx SLOFERROR: Flatten device tree not available! Press "s" to enter Open Firmware. bootinfo !!! roomfs lookup(bootinfo) = %d xvectCannot find romfs file %s ofw_mainERROR: Not enough memory for Open Firmware[?25h%s%sELF32: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting ELF64: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting ELF relocation out of bounds! ERROR: Unhandled relocation (A) type %i 0x@DIDJ0DK@DKpDNtDNDODPDPDRpDSDT0DV DVDVDXDZDZpD_0D`D`D`Da DaDbDbDcDcDdDfDfDmDn DoDp0DPPPD?0?(xvect`/|i8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8 N |C| |C||C/| 8 N |C| |C||C/| 8 N |C| |C||C/| 8 N |C| |C||C/| 8 N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8N |C| |C||C/| 8 N |C| |C||C/| 8!N |C| |C||C/| 8"N |C| |C||C/| 8#N |C| |C||C/| 8$N |C| |C||C/| 8%N |C| |C||C/| 8&N |C| |C||C/| 8'N |C| |C||C/| 8(N |C| |C||C/| 8)N |C| |C||C/| 8*N |C| |C||C/| 8+N |C| |C||C/| 8,N |C| |C||C/| 8-N |C| |C||C/| 8.N |C| |C||C/| 8/N 6 5P 50ofw_mainELF@ 1X@8@Ҵa?cp?c?cQ?c ||<``cc`/<``c<`u8HH`|1CB|(!Aa (08@!HAPaX`hpx!Aa!Aa8`|x|B|B, @|<||&||B|B| |(|0|8B |H"|!8!<@v`|BvhL$|B~}|}B(|xH|xh|x |x((|x00|x88|xhh| xpp|xxx|x|x(|xH|xh|x|x|x|x|x|x(|xH|xh|x|x|x|x|x} &| ((} |d|L,((N |Ku|8`N ||iK], A N!H }i}}}kx}L$K-|8`N [?25lQEMU Starting  Build Date = Oct 22 2019 15:05:10 FW Version = git-899d98836513bb3d `````|8Tc0T0| PT||l|||L,8cBN ``B|!HkI`8!p|N /M |Tc>!Hk`8!p|N `B+A,#=9}HH./A9@8`}HI.N 8`N ```B|=bA?|zx+A|#x|+xa;/!a!@`<8W8<8@="9)`=B9JW88`9<9)k`*<=B9Jy9!xP@@=") /A\sIA="9)WI9  sIA="9)WI9  sI@dsI@`;"9Y}ISxAx?::;`:;;;]:pbV c{:yN sI8`A=B9JW*9 i8! Aa!Aa|N `B=B9JW`;;"8 |;xx8K```BiH`1/@=tI19IQ!N ```B>B:RW!xR9)!x9*2jH`2iN !x>B:RWR9)!xjHXu`2iN !x>B:RWR9)!xjHU`2iN !x>B:RWR9)!xjHT`2iN >B:RW!x<8bpx~xR9)!x9*2jHaU`2ApI29IiRN >B:RW!x<8bpx~xR9)!xjH_u`2ApI29IiRN !x9)!xH^=`N >B:RW!xR9)!x9*2jH]`R|i4U)~i)})*N =9WAx(9JAx89IiHH]y`N =B9JWx*9x889 i H\`N =9WAx(9JAx89IiHH\}`N =B9JWx*9x889 i H\1`N =9WAx(9JAxi9)(|c4H[i`N >B:RW!xR9)!x 9*88289*2jH`2iN >B:RWAx29JAx9 9IRiHρ`2iN !x>B:RWR9)!xjH`2iN !x>B:RWR9)!xjH `2iN !x>B:RWR9)!xjH#`2iN !x>B:RWR9)!xjH!1`2iN !x>B:RWR9)!xjH!e`2iN !x>B:RWR9)!xjHЙ`2iN !x>B:RWR9)!xjH`2iN Ax=9W(9JAxi9)(H˹`N Ax=9W(9JAxi9)(Hʝ`N !x9)!xHKY`N !x9)!xHu`N !x9)!xH`N !x>B:RWR9)!xjHm`2iN !x>B:RWR9)!xjH`2iN =9WAx(9JAx89IT>iHH`N Ax=9W(9JAxi9)(H1`N !x>B:RWR9)!xjH `2iN >B:RWAx29JAx9 i9IRH`2iN >B:RW!xR9)!x 9*88288j9*rj2Hg `2,#9IA3RN >B:RWAx29JAx889 9IiRHd`2,#9IA3<RN ``B>B:RW!xR9)!x 9*88288j9*rj2Hb`2,#9IA2RN !>":1WAx19JAx889 9IiQH``|jyA1QR921H-]`1r9IQ!N !x9)!xH]`N !x9)!xHV`N !x9)!xH\`N >B:RWAx29JAx8i9 9IRHZ`2/9IR@1<N ```B>B:RWAxx29JAx9I89 R9IRHWM`\2/@09IRN ```B>B:RW!xR9)!xjHM`29)2N >B:RW!xx8R9)!xHPA`\9*+2@/ 829 IN >B:RW!xR9)!xjHN`29)2N >B:RW!xxR9)!x9*2HRe`\9*+2@. 829 IN >B:RW!xR9)!xjHG`29)2N !x=B9JWJ9)!xrHLY`rN >B:RW!xR9)!xjHH`29)2N !x=B9JW8 9)!x9(*N !x=B9JW8 9)!x9(*N !x=B9JW8 9)!x9(*N !x>B:RWR9)!x9JRHY`2iN !x=B9JW8 9)!x9(*N =B9JWx*9x8889 x i xc HEi`N >B:RWAx29JAx9 9IiRHS`2,#9IA,RN ``B>B:RWAx29JAx9 9IiRHT`2,#9IA,tRN >B:RWAx29JAx9 9IRiHg%`2iN Ax=9W(9JAxi9)(Hpa`N >B:RWAx29JAxi9)2Hl`2,#A*t9 iN >B:RW!xR9)!x9*2jHqi`2iN Ax=9W(9JAxi9)(Hc`N >B:RWAx29JAx89 9IRiH``R,#jA(29IRN ```BN >B:RWAx29JAx9 9IRiHc`2iN >B:RWAx29JAx9 i9IRH`2iN Ax=9W(9JAxi9)(H`N >B:RW!xR9)!xjHa`R,#jA29IRN >B:RW!xR9)!x8j89*9 82*0|I Hy`2iN Ax=9W(9JAxi9)(H5`N !x>B:RWR9)!xjH!`2iN =B9JW!xJ9)!x992 *rH`rN Ax=9W(9JAxi9)(H `N >B:RWAx29JAx89 9IRiH`R|i4U)~})*N >B:RWAx829JAx8i9 9IRH`2iN >B:RWAx829JAx8i9 9IRH`2iN Ax=9W(9JAxi9)(H `N !x>B:RWR9)!xjH)`2iN =B9JWx*9x889 x i HyY`N =B9JW!xJ9)!x992 *rH`rN >B:RW!xR9)!x9*2jHt`2iN !x=B9JWJ9)!xrHt`rN !x=B9JWJ9)!x92*Hq`rN !x9)!xHX`=B9JW/A$=9*<8|9  N !x>B:RW~xR9)!xH^`2iN =B9JWx*9x889 i HXm`N Ax=9W(9JAxi9)(H]Q`N =B9JW!xJ9)!x992 *rH^e`rN ="9)WAxI9JAx8899R IrH]`rN =9WAx8`(9JAx89IHH]q`N !x=B9JW8`J9)!xH]`rN =9WAx8`(9JAx89IHx H\`N !x=B9JW8`J9)!xH\`rN =9WAx8`(9JAx89IHT>H\Y`N !x=B9JW8`J9)!xH[`rN =9WAx8`(9JAx89IHT>H[`N !x=B9JW8`J9)!xH[q`rN >B:RWAx8` 29JAx9 9IRHZ9`2iN >B:RW!xR9)!x9*2jHZ`2iN Ax=9W8`(9JAx9)(HY`N =B9JW!x8`J9)!x992 *HYY`rN !x>B:RWR9)!xjHYm`2iN !x>B:RWR9)!xjHY`2iN =9WAx(9JAx8i9IHHX`N !>B:RW!xR9)!x9*2/9 A(}z: :pz1~1rxH5`@|qx@=9z)hR})B*!N !x=B9JW<8 9)!x9(*N !xB:RW!xR9)!xjH=`29IiRN >B:RW!xR9)!x 9*2/A<**29)2N ```B>B:RWAx29JAx8I9 8 @@A9@IN =B9JWx*9x889 |#x});xy)`/A0+@/@xcx89D"N ``B="9)WxI9x889 |;x})+xy)`/A+@/@xcx89D"N ```B=B9JWx*9x889 T>i HRI`N ``B/@ xBcx89D"N ```B9)2N /@pxBcx89D"N ```B>B:RW9%89E2%/R|;x@Lf@ALA$})H ``B *@@A(A9J}*2}'HPB9@!xE9IAxN `B<8W<8W!xDi8|3xx9g e|*/DAj}@}(P|Z@@@h9J9)D!xN =9W!x9)!xG9JGH(A|})29)!xN =9WxH9%!x888A|=9W9)H8!xN <8WAx<8W'9JAx9I88GHIHIN !x=B9JWJ9)!x*1)})I*N =B9JW!x 9)!x(}):x1)})I(*9)*N !x=B9JWJ9)!x*})v})*N =B9JW!x 9)!x(})8})I})(*9)*N =B9JW*9 )9)!xN =B9JW*9 )9)!xN =9WxH9'!x8J/AL=9W}):9)H!x9JHN ``B<8W!xG 9J9})BG9IAxN =9W!xH9)!x9*88(*J}HKx};xy`/A+@ /@P@A} :@@@/}):A0} CxH`````B|:0@N `B=B9JW*9 N ```B/@P@A} :@@@/}):A} Cx`B|:0@N `B<8WG9 9*8'xE}3x*y|CxJ}GKxx`/A/A/AL/})R}*HP})@```B9JB!x9)!xN 5)y};xAD8y'/8}ESx@8```B,'9)88@5)A<8y'/8y }ESx@8,'9)88@4AP9)xB/8U>A,' 89J@!x9)!xN ``B9)!xN =9W!x9)!xG'}Fv}IPy)})1i)})})'(9)(N Ax<8W'9JAx I9)'y y'Fy(y) *N =B9JW!xJ9)!x* p q r)!s`B!p*N Ax<8W'9JAx I9)'y  *N =B9JW!xJ9)!x* p)!q`B!p*N Ax=9W(9JAxI9)(N !x=B9JWJ9)!x*)*N Ax=9W(9JAxI9)(N !x=B9JWJ9)!x*)*N Ax=9W(9JAxI9)(N !x=B9JWJ9)!x*)*N Ax=9W(9JAxI9)(N !x=B9JWJ9)!x*)*N Ax=9W(9JAxI9)(N !x=B9JWJ9)!x*)*N =B9JW!x 9)!x(}):x(*9)*N =B9JW!x 9)!x(});x(*9)*N =B9JW!x 9)!x(})88(*9)*N =B9JW!x 9)!x(})>4(*9)*N =B9JW!x 9)!x(})<6(*9)*N =B9JW!x 9)!x(})86(*9)*N =B9JW!x 9)!x(})9(*9)*N =B9JW!x 9)!x(})8P(*9)*N =B9JW!x 9)!x(}):(*9)*N =B9JW!x=9WJ9)!x*y)$})@P)*N !x=9W<8<8WH9)!x*9JHy)$9)})2'N x=B9JW=9W="9)H8x})0P8})t9)*N !x=B9JW=98x'y)$9)})B*N Ax<8W="9)9JAx9H})PP})tG(N =9W!x<8WH9)!x9*('*N <8W!x=9WF9)!x9*8&'*N <8W!x=9WF9)!x9*8&'*N =9W!xH9)!x**(N !x=9WH9)!x9JHN =B9JW!xJ9)!x*y)$!)}*H**N !x=9WH9)!x*8*N !x=9WH9)!x*8*N Ax=9W(8x9)(N Ax=9W(8x9)(N =B9JWxax* 9)*N >B:RWxR9'!x /@09JR})B9)!xN `B!xI9)})R9IAxN N <8Wx=9W8'H9)8'?!xN =B9JW9?x!x* 9)*N !x=B9JW<8 9)!x9(*N !x=B9JW<88 9)!x9(*N !x=B9JW<8h 9)!x9(*N !x=B9JW<8W 9)!x9(*N !x=B9JW`( 9)!x9(*N !x=B9JW`  9)!x9(*N !x=B9JW<8 9)!x9(*N !x=B9JW<8 9)!x9(*N !x=B9JW<8 9)!x9(*N !x=B9JW<8i 9)!x9(*N !x=B9JW<8G 9)!x9(*N !x=B9JW<8 9)!x9(*N !x=B9JW<8X 9)!x9(*N ="9)WAx 9*!x(}):(N =9WAx(8x9)(N =9WAx(8x9)(N N =9W;Ax(8x9)(N =9W;Ax(8x9)(N 9J9)R!xN !x9)!xN /9J9)A@`B 4 @N E})R9)!xN N !x9IAxN 9@!xE9IAxN /9J9)A`B 4 @N / A9J!9~0R:H``B@AppH`|nxoH`pA29@I!N /@8xcx89D"N !N cx89D"N N /@$P@AL} :@@@@/}):A(} Cx````B|:0@N /9J9)A(`B 4 @N N N : K9 iN 19 I!N /@8xcx89D"N N N cx89D"N 9J9)H!xN }Cx KiRN iRN 9@IN iRN iRN 8 I9 N iRN 9@I!N cx89D"N =9|*<8t9  N P@A\} :@@@P/}):A}J@P}I```BBN cx89D"N /AH|9)9JBN }&9)!xN 8KdN `B9#+@8`N ```B=")|+x!q|#x/@/@t|9=y) ;JH`BHI`@A4~+ @8` H)`~H`@@`B|8!xN /Ap|p`;PHD```BK!|P88`;K xH`x|dx8` K8 xHE`x8|~y8`@xHU`|~@pK@```Bx88``K;Xx88`K}xH`x|dx8` Kap|K```B|8|#x|~x8`!K x`H`8;`|dx8`Kx88`KxHa`x|dx8` K888`K/@$8!|N ``B8!888`|K`|a?`h`p;|3x`"x8x|;!Apx!H`B}B@*H99J/@`;@xHQ`x|dx8` K888`K||yA`A_8KQ/~AX`x8K1/~A;p8x8`KAx`H`8;€|dx8`Kx88`K xH`x|dx8` K888`K/@888`K88|~x8`K88|"cxH`9 }=.A8!xa|N `;8bH`8!xa|N ;AK`8bH`;AKx`;8bpHy`KX`8bK```B+Ac!="9)})./A|x8`|+x8Kmx88``KY;⁀88`KExH`x|dx8`K)x|c|8!N ``B8`K``B8`N ```B+Ac!="9)})./A|x8`|+x8Kx88``Ky;⁀88`KexH`x|dx8`KIx|c|8!N ``B8`K``B8`N ```BTc!q|@/A|px;`;;H``B~}?@A,xH`x|dx8`Ky9?pc@px8!x|N `B8!8`N `|`;⁠x!H`x|dx8` K`888`K`8!xc |N ||x!K}{ H```BKa@A8!|N `B|`|dx;⁰88`!K-`xH`x|dx8` K `8!|N `B||x!K8!="|ciy|N ```B|?y!KY8!|cP|c|N ```B8`N ```B|`|dx;⁸88`!K`xH`x|dx8` K`888`K`8!|N ||#x8|dx`8`;!Ku`x88`Ka`xH`x|dx8` KA`8!|N `B|`|dx;88`!K`xHq`x|dx8` K`888`K`8!|N ||#x8|dx`8`;!Ke`x88`KQ`xH`x|dx8` K1`8!|N `B||~x|#x!K}#|jx})HA(xK9|~8cK9?}_|i}J88!}CSx|N ||#x|+x|dx88``;!qKM`x88`K9`x88`K%`xH`x|dx8` K`888`K`8!|N ||+x|x88`!K`x8`8`K`;x88`Km`xH`x|dx8` KM`8!|N |`|dx;88`!K`xH`x|dx8` K`888`K`8!|N |`|dx;(88`!K}`xH`x|dx8` K]`888`KI`8!|N |`|dx;888`!K`xH`x|dx8` K`888`K`8!|N ||~x8`8`;H!Ky`x88`Ke`xH`x|dx8` KE`8!|N ``B||~x8`8`;X!K`x88`K`xHY`x|dx8` K`8!|N ``B||~x8`8`;h!KY`x88`KE`xH`x|dx8` K%`8!|N ``B|`|dx;x88`!K`xHQ`x|dx8` K`888`K`8!|N ||#x|+x|dx88``;ₐ!qK=`x88`K)`x88`K`xH`x|dx8`K`8!|c|N |`|~x;88``;₰!qK`xH`x|dx8` Km`x88`KY`xH`8|dx8`K9`xH`x|dx8` K`8!|N ``B|`|~x|+x8`8;!qK`x88``K`x;₰H`x|dx8` Ku`x88`Ka`xH`8|dx8`KA`xH`x|dx8` K!`8!|N |#x|dx`8bK|#x|dx`8bK||+x|~x|#x88`|3x!qK}`x`H`8;|dx8`KU`x88`KA`xH`8|dx8`K!`xH`x|dx8` K`888`K`/@`888`K`88|8`K`9 }8!}#Kx|N `B9 K```|~y!a@8!N `B|`8bHU``8b8HE`^}*C} A}JBx1J})/AApax```;B;(;;(;bH`BWy)тxy)$|H*|T6xH`^8xx /).}*C} A}JBx1J})H@@$ApAX@CxHm`KApax`8bHE`8!|N ``BcxH`K4`BA|#y!QA|/!xa|yx|+x@;}>IJx1){{т1);|{{$cxKM`|yA`?_888( Hm`x!xa8!|AN `B!xa|8!8`AN `B|lyAa8`l }?|Jx0@AH{ }^}*Jx3IR{!Ap8(9```B}Uxт|+xy)$}fH*}i$6q)A}+AX?9)U)>+AT8!N |H`|K`B8`N ``B8`K``B8`K```B|a|3x|#x|+x|~x!aK/|xA/A<}8! c|c8a|N `Bfxx8xH`}>/AxH`Tc/}A8! c;|c8a|N ``Bfxx8xH1`}>/A(8! c;|c8a|N `B;K```B|Aa|;x|+x|3x|}x|#x!aKY/|~xA|/@DxH=`FxexPxxH1`xxHy`8!xAa|N `BxH`FxexPxxH`8!xAa|N ``B||x!KM/AD/A8!8`|N xH`8!|N xH`8!|N `}&|!A|3xa|+x|#x|~x;.%-!QH$`B>,9]*}]PBA؁?/@܀  @*x@A,A(;{})[N!A(/@|xH`8|(P|cx Hu`x/APALA(9y})YN!A(>,9]*}]PB@08!~!Aa|} } N `8bH`8!8`!Aa|} } N `BC#,}P.}CR/A<9)*})H``B*/A}JBB8`N `Bj N ```Bc$N ```B9#9.8N,9#|F,90N,9#|F,92}@L,9#}F,}L,9# L,9#$|L,9#(}`N,9#*|N,9#,} N,C9C}@T, $c(*.02C#,yI }#J```B9IL,9}}T,9I|T,9I }`T,9I|T,9I|T,9I|T,9I}@T, i IC,*@})2@N ```}&|!A|3xa|+x|#x|~x;.%-!Q H$`B>89]6}]PBAԁ?/@ @*x@A,A(;({})[N!A(/@ |xH5` (8|(P||Hљ`(x/ATAPA(9y})YN!A(>89]6}]PB@48!~!Aa|} } N `B`8bH`8!8`!Aa|} } N `BC #8}P.}CR/A<9)6})H``B*/A}JBB8`N `BjN ```BAa|#x;```;x|x!!A;X#(#;H `B?<9[;@}[PAl>/@>(y)6d}9J)q)A/A|x;8Ђ$z6d~`B_ ?8}P.|*}_R|:/A9)6})H```B*/Ah}JBB}8*E}Bx"x )+@}ZR}?J}):)}JJA4<8h,xd}'J}):})N $$$T$$$$$$$$$$}8**@@@xH`>4 0@xA?<9[x;@}[|P@8!!AaN ```BUJ:H>4 0@xAK``BH>4 0@xAtKX```B(})(>4 0@xA4 0@xAK``ByJ"H>4 0@xAK``BH>4 0@xAK```BUIyJ}IRH>4 0@xAxK\yJH>4 0@xAPK4``BxH`>4 0@xAK ``B9#9:8N,9#|F,9<N,9#|F,9>}@L,9#}F,}L(9#(L(9#0|L,9#4}`N,9#6|N,9#8} N,C9C }@T((0c46:<>C #8}#R9IL,9}}T,9I|T(9I}`T(9I|T(9I |T(9I(|T(9I0}@T( i (I0C86@})2@N ```Bc0N ```||#x8|dx`8`;ℨ!K`x88`K`xH`x|dx8` Ka`888`KM`8!|c|N ```|@@Hx|3x}JJ9JU)0UJ0}IPPUJ}I|Hl||O|L,9)B;8A8`8!|N `Bxx<|=D`ha"8A\8`K<|=D`ha"K@/@8`K``|+|#x|x|+x!a@8;pxH)`+@ax;}Ap;@{{BcZ;HD`B/A/@Cxxx889D",>;;AL{`/A+A/@Cxxx88@9D",>;;@{{M;ApPaxxy)`/A+@0/@8`xxt`c89D"8!|N ``BCxxx889D"KCxxx889D"KxK|``B/@L8`xxt`c89D"8!|N ```B8`xxx`c89D"8!|N `B/@8`xxt`c89D"8!|N <` <`N D"N xf8`X8D"N }HH-}H,M = a)|dH8N |dx8`= a)|0@L 8`TD"= a)8`i(M 8`N |dx8`D"N 9`}*Kx} Cx|;x|3x|+x|#x|dx8` D"N |#x|dx8` Kƭ`8!|c~|N 9 xcd> Ku`8!|c~|N ``B~8cxchK`xcxKl`B|ex|~x88`8PB8`8y? D"/@HT>PBPF>}$KxxxN ;8{ 8`<8D"/A8`xcxN ```B|8`p!1K`|}yA8`4K`pA:(;8!A;=H;]aH`B8~K­`pAxK•`Tc>/ @8~K}`T|>8~Km`T{>8~K]`+xd A @+A+?x@xKY 8~K`p@t```B!Aa="/A=2/@@9 88}===K8!x|N `B=B/A=R/A9 =K``BxK,``B+_xAK8p~xK5`p}hK`8bHi`Kd Cxi$9)y)8jxc|cJN `BTD.T>|Kx|xT>#/A`88`@8D"|8`<88D"/8`xc @T>TD.})SxU#>N ``B88`@8D"|8`<88 K``BT>TD.})Sx|xU&>#/@p88`@8D"|8`<88D"/A<``cxc`cN T>PBPF>}$KxxeN `B88`@; 8D"|xK|```B|#x|x!qC/@T|xKx|}xxK5xc&||}x8!N ```BTD.T>|Kx8`@T>8;(8D"|8!xK`B|#x|x!qC/@T|xKx|}xxKu;xcd||cx8!xcN `BTD.T>|Kx8`@T>8;08D"|8!xK`B/@ N `B9#|(|M,9# |O,9#}O,N `BT>TD.})Sx|~xU?>#/A8x8`@;8D"|8`<x8D"/9@yJ @T>TD.}JKxUJ>>h(x8`@8})Qy) |JD"N x8`@88D"N x |x!a#/@dTD.T>|KxW>T>8`@88D"|W>8`@SB8SF>x 8D"8!N |ax|+xK)W>8SBSF>|~x{"8`@x 8 D"W>8$SB8`@SF>8x D"{&8`@8W>{"SB8(SF>x D"Wf>8,SfB8`@SfF>8x D"{8`@;8{80W>SBSF>{"x D"W>84SB8`@SF>8x D"8`@888D"ax8!|N ``B||+x||#xx|}x!qK8Cxi$9)y)8jxc|cJKy`/A?8y)$9)y)8x|JH`xxK}xxKx xKq9 (8!}#Kx|N `8bH`9 K``B||#x!d/A,$y)$9)y)8x|JK`x808H`8!|N `B#T>/@$88`@8D"N ``B88`@8D"N ```B8K```B|#x#/A@88`<8D"/9 @T>?N ```B88`<8D"/9 Aȑ?N ``BT>PBPF>{ #/@$x8`@88D"N <x"88`@;xD"W>; SBxSF>8`@x 8D"8`@x88D"8`@xx8D"N ``B#/A8<8`@xD";8`<x8D"/A;{x8`@88D"8`<x8D"/9 y) @T>PBPF>y) KxN `B88`PBPF>y# N ```BT>PBPF>}$KxxKP```B||#x|x!qKxiAxxKxKy@`;pxxK!!pxa)}$!pKxxK!py)1)|c8!|N UID.|cKxTc>N |8`<8D"/A8`xc |jx?/A\UC>QCBQCF>xc N /@<|8`<8D"/8`@T>N ``B8`N ```Bx x Kl`BT>x K `BTd>PdBPdF>W>SBxSF>xc |xK``B|3x#/A|H/@\;*{ ;;8`<8xD"/9 ;@T>,?=;@xN `B;K``|9 |x!A!KU`xK`!xa)}$!K`?/Ax<xx`@K`/A``8H8bXH`!xa)}$!Ki`9 8!}#Kx|N `B8@xKI`88pxK`/@?9@/A9@H9@x!I!a)}$!K`xK`9 pj@A`x88K`8!|i}#Kx|N ``B8xK`K@|8|x!KI`xK`8!|N `B|Aa9 |+x|#x88|3x|;x|x!!pK`9;})@A88AxK`xr |}rI@8x!aK`8|txxKQ`8|vxxK `8|wxxK`?g|yx|}ңw/xc"@=9 H(=Bj0=B*,Ws<<}38~i88(~s~sHP93zu z&|vHP{ W>K`s|ޑր{&8|vx A8:sExV>P{ W>K`{&9|v888pKu`};_/})})Py) AV>VD.}JCxUU>y)}7J|?;{W{>/AWi>WjD.})SxU;>wx8KQ`K`8cx H`B|K`@A9@A!p/A p`x8bH`8`Aa!8!Aa|N ```B}JCx=90U[>=B|`E(*,KH``||+x!|#x8Aa|yx|3x|;x!1K`8|vx#xK`8|ux#xKe`8|wx#xK`|x/AW>WD.})SxU<>W<x}>z ɳ8ޱHP9>{  {&|uW>HP{ W>KY`{&9|u8ExK5`}WD.}JCxU^>y)}7J|9;W>/AW>WD.})SxU<>#x8K`?==@aaJ} H@AH,`B} B@ |?9 @A/Ah}@,;P@AP;8`8!!Aa|N `B}ISxK8`K `B=!19@(8/A@T|ș8|+x|#x|xK`xKM`!xa)}$!K1`?/@8xK%`88pxKa`|~y@ԁ?9@/A9@H9@x!I!a)}$!K`+@8;pT>x8xK`x H`|yAX`x8bH`(xHI`8!px|N ```Bx;0H`8|yA8`x8b8H`K```B!0)/ADx8xHe`8/|x@|dx`8bPH1`K8`BaH;acxH%`|yAh`x8bhH`xHI`(xH9`aH8!px|N ``B8cxH"9`|y@;;/@KA`@@P|(Pxx |cxH"`/|x.@|dx`8bH%`K,``BxK``B`x8bH`K```|Aa|+x|3x|;x}CxAa||x|#x8!!!KQ`8|rxxK`8|wxxK`8|{xxKe`[|~x/AWI>WJD.})SxU:>WY<x}98)8399HP99{8 铖{&|wHP{ W>{&K`/|wA/@ ~ex988lK}`}Z<W>/}J}JPyJ AW >WD.})CxU8>yJ}[R |\9:U)>/AU*>U(D.}JCxUI>;x8KU`K`8cx H ``B|K`@A>@A8!8`Aa!Aa|N `B;9/}z }(P{( y &U>~JAH~ex88lK9`~Ƴx~x~x98K`K```B~Ƴx~x8K`~ex~x988lK`KX``BK0```B|9 8|x!!K-`!xa)}$!K`?/A@<xxK`/@8xKY`H ```B8xK`88xK`/@88xK`/@88pxK`|~y@_9 /A9 9@x(H(H(!I!a)}$!K`8! x|N ```B``88bXH!`!x;a)}$!K`8! x|N |8|x!KY`xK`8!|N `||~x8`!1K%`|yA/9 :? Ax8p~xH`~xK%`88~xK`/@88~xK`/@t8~xKy`9 !p/A08!x|N ``B8~xK)`?/@H9 =B8~x*W>9&|c})y) JxK߱`?8{988;{ |i|K߁`_?9{G.}WD./W>}):}JCxAU]>@P|?9@/@9@H9@UJ ?/@9@H?/_*=BAt9J@} W,_9 *9@~x;?бI!pa)}$!pK]`8~xK`9 ? ```Bx8;~xK1`/~@!Axa8!|N <~xx` K`/@<9 =B8p~x*PC@{ AHP{ {&A?|*xxH`<_9>U)>@/G9@A$UHD.UE>|CxU*D.U(>}SxT>U >} 3}1}PPy y}B(|?9JUJ>/AUI>UGD.});xU*>H88K-`ax|8!N ```BUCD.UG>|x8`T>@@A|axx }F;}J9}J0PyJH})R9I9)T,}@L,9>}HPP;P@yJ 9HP{ {&@t`8bH)`?_/|*Apx"|#xT>UH>Q$BQHBQ$F>QHF>x|CxKD8!N ``B?}]Sx|*K8`K|+xKt`B|y!aA/A|/ax|#x|+xAAp?/@t?B;ZB<<8CxH9`?/AW>WD.})SxU=>_W<Ex<ƙ<x8SQHP{ W>{&9|cU>;Kإ`Ȁ98ex{ |cK؁`_}=;/})9})Py) AWH>WGD.};xU>y)}*JI|?;_W>/AW>WD.})CxU=>|88KM`xApax|8!N ``B?B;ZLK`B`8b@H`ax8!8`|N 8`K```|9 ||x!a!pKU`rxK`!pxa)}$!pK`</Ax<xxK޹`/A``8`8bXH`!pxa)}$!pKm`8`8!|N ```B?8;XxxKى`/A K|8`;K%`=B/|ixjhAH=}{&{d|*988|cRK`\= W>{;U>UD.*/|3x})AT> @<=x9@/@9@H9@UJ <=x/@9@H|<=BJ/*AU*>U(D.}JCxUI>=B888x*KM`/A,K88pxKA`K|8xK}`<9|jx/A\9 x*!pa)}$!pKq`8`K`8bxH`K9K`B|8|x!K `xK]`8!|N `B|!A||xa!Q8K`8|yxxKх`8|xxxKA`8|zxxK`|}x/AW>WD.})SxU>>˖9}888P{ {&|xKU`<W>/AUI>UHD.})CxU*>{_|<;W>/AW>WD.})SxU>>x8K=`K`8cx H|K`@AP=@A8!8`!Aa|N ```B`8bHy`8!8`!Aa|N ||~x88!8p|3xH}`>=BJ<=8X|fx/*AxU'>U$D.|#x8`T>@@A||#|!}@PyH}JB9*L,;}?#})!})P}*y? yI&}%J9)|L(H\``B@@8`A|#|!}@PyH}JB;}?#})!})P}*y? yI&}%J|3x8H|Y`<^<x9?U)>/G9<ƙ`A$UHD.UE>|CxU*D.U(>}SxT>U >} 3}1}PPy y}B(|>9J=xUJ>/AUI>UGD.});xU*>H|8xKЍ`ap8!|N ```B#=BJ/*AU*>U(D.}JCxUI>,8@@@J+kA(9)P@4`|8!PN ```B`8`|K`8`|K8`K``B`8`|K8`K8`K@;p88xHx`9$8 |N,+@8xHw``x8bH``8`@|K08`K(|||x`;‡!qK?;89d9@x??8 `B?9 I`B?9I_}@,I`B?9)?Hu`?|`O,x;Ht`x|exxHw`xHt`?})x?KA|y@H=")؁\9 }D,@@A\\8 9) `8b|N,Ht`/AD8!x|N ```B} CxK``B;K```B||~x!acHs`|x~Hs`>|c8cH@Aax;K?;89h9@??8 `B?9 I9>`B}@L,?9 I`B?9I_`B?~9)?Hs1`?|`O,~;cxHs `dx|exxHu`~Hr`?})~?Hr`?|`O,~;cxHr`dx|exxHu`~Hr`_|ixx} JI.`B?9)?ax8!|K```B8!8`|N ``B||#x!qapK="9)88xap98!II8`BI8 `BI9  E,`BI9JI|K```B!1/AX||#x!A|+x|zxa|3x`;xpx;bK?";99@8n99I98`B98 `B99 ~E,`B99 E,`B99 I`B99)9``B?/A|+/@0```B?+/A/x::A8xH``BA**//@~PPx~׳x}_Sx~x~xcxHp1`/At=")ЁZ; })8P9)})9 P@A@@A~?,~x~x~x99)}#Kx9HrU`9/~@=BJ9 Cx*K,#A`Bpx!Aa|8!N k/4W~P/@xHn`/@9 =BJCx*K,#@p=")9)}@N,A9*/}*AL>+/@``B>+/A/A̍>*//@9*/}*@~|c4Tc~hcKW>WD.})SxU)>KHK8`K8`K ```B||#x|x!qK9@="9)8p9s__xFI8`BI8 `BI9  }, `BI9  `BI9JIK,#@=")9)} L,?8!|N ``B|Aa|#x|+x|~x|3x!aK;@@x="9)88t9xII8`BI8 `BI9  }, `BI9  `E(`BI9 9J E,IKi,#@4<脙9$L,@{ AD8 CxHn`8!Aa|N `B8`K```B||x!KU="9)9@8|9__xFI8`BI8 `BI9  }, `BI9JIKM,#@ =")9I*}@T(_)?8!|N |?;ޙ!/AL?88x>Hl`9 ?8!x|N ``B8`K{m`|yAL9 x} 9@```BI9)B@+A)I9)BK`K|,#="9)I@H,``B}*Kx*/@j#N `B/@N ``B||iy!A`)/AT)/AH)0/A xKe= ;a);py) xa)x>K /A? AwI?h/AP9\9 a 8x!_t9;.} N,!K,#AX;(9I[(?l|8`dKl`= 9A a)xy)xa)*Ke/@,8`8!a|N = |= x a);y)xa) x=K /AaW~>WiD.KxW>+ AxAKm`|zyAL=  9@aa)ExxA!K/A9@! 9 x8A9A} W,Kq/A!|8`d; Kk`9>; U=>H````B@@?`Y+_xA$9)8y#$x|H_e`?`9)?`};Pq=A<|./@<\xU)UJ@.})Sx})Cx?dK`BCxxKl`8`AK4`B``x8(8bhHu}`8`AKCxxKl`8`!AK```````N |y!aAp?/Ad|) > /AX?/AX9 x8 8??H]`|8!N ``BK``B= a)]dHA= HA Kax?0e)@?|9 H(@???Kn`L 8x&Km`L x&Kk `]dmI/A(= H@89<`M,axKWi>SiBSiF><< <@<`axK`B|}y!1A||!A|+xa|3x|#x=i /A4?/;A8 8xH\`9 ?>y)y* +_=h?9>} N,?U<>>y) ?U0A+Ad!Aax8!|N ; K\?px/@``B8/A8?h]lU)^T=p});xa@UJ~})Cx}J3x})Sx9_} U,KT8`Kh`/||x{A88xKj``x:`:|xx{:H(`B@}S BS F>;; ;@;`K~ƳxK8 `B|iyA|! 8|<8`@x 8D"8`KcQ`8|8`@88D"/A$8Kh `8Ke`/A$8hKg`8hKd`x8Ke`8!|N ) ```B|yA8`<|#x8?)) 8PBPF>U(>9?8_L |L,?8|4,<9JyJ |8PT:|&t}) P8}%J}S}HQ}J0PyC'|H@A?(@}IQyJ } B}$R}DT,/A(9@;}I``BI9)^By 99@|:}.9} E,F_9J}*J9F } U,? _8|0P|RT>PBPF>'|?8`N `B8`N T>PBPF>U)>Kt|a`}&|3x>|;x`!Ax;@a|+x||x|#x{{ A::b8::P!!K_`8cx~ ``B|8`<88 D"/@pT>PBPF>}$Kxpx ``B@LK_]`@A |8`<88 D"T>/PBPF>}$Kxpx A9<|L,/Ah|.9A@ P&tH@$@PH``Ba)9_|T,?|. P&t.9AA@A;9|?U2>Q2BQ2F>VR'>zJ!AyJ$x~x|P*Hi`+?~R@x~ZKp```B`x8b;@Hiq`8!CxAa!Aa|} N ~cxHi`8 |8`@8<D"|8`<88 D"@Kh|!A#/@|fp})+A8/|#xA|+x|x!88AaxpxHQ]`x= p/y) |;x@ /AU#>;Q#B9`Q#F>xxc H<;i} @Q|R;|,8|%,T>iPBPF>x Ad*9)x |HP/8} Cx|:@9@|R@} @QT>iPBi|RPF>;x @W>SBSF>8`/@ ?8hDlT=pU)^})+xU}[x`@UJ~}Jx});x})Sx9_} U,|?_4U)?() Y;(|UF>xQFB8`@QFF>8x D"|8|8`@8<D"K[=`8cx{ H ``B?_U) PAK[ `@A|yxxx8K|~x|?e)@?||8`@x88D"8,|8`@88D"9?} L,q)@{!Aax8!|N ``B`;8bhHe`8!x|N `B`|;x8b;HeQ`8!x|N 8`K``B= y) K`B`8bHe `9?``8}L,9?8b|L,9?|L,9?|L,Hd`?U) ?|/{@K`K`B``88bHd`8!x|N W>;SBSF>yg K```B}&|a9D!|+xAa|#x葁|x8`0A!$~V,y=KZu`880z |~xK\`808|yxxHL`cx88{7 K\`{: 97|xyA{ 89 .<}@=,9^ }U,9^} U,9 >@/9>::@A9@9IWF>SFB SFF>?_U'^UJ}J3x?)l_9_U)~a)@});x} U,|?_4U)?(I : |UF>~xQFB8`@QFF>8x D"|8|8`@8<D"KW `8cx} H``BPAKV`?_@U) APA``p!x88bHa```8b0;Ha`::"@H````B~#xHa`@@`8bHHa`p!xz~x&x8xK|}x|?e)@?||8`@~x88D"8$|8`@88D"8dxxK[5`A~ųx~dx~CxK[`~x80xK[ `x80KX`8!|}xcAa!Aa|} N ``B9@K```B9^.< } U,9 >A 8~ijx~cxKY`/9|rxA9.9> 8 A,.A$zF 89\}J2|-,8}@5,H9@^^9^:|U,K`B||~x`8bH!1H_`8`KWU`|yA9  88>(HH`9 8`h?? >?KU`/|dxAp}A\`8bH_`8hKV=`x8KW=`8!|N ```B88h!AaKX `8|8`@88D"8`dKS`8|88`@x 8D";|8`@x8<D"|;`B8`<8xD"T>/PB9>PF>y> }DSx.p8`@A$AKS}`K`8bH]`?99@888p8(sAt?8K`/||x@A88|0HF`888|HF`=@@Wg>SgB9 \9@ SgF>}Ix ```By*d9)y) |Q.B8?|U&>8`@Q&B8Q&F>x D"8 |8`@88D"8(|8`@88D";8`<x8D"/<x @(T>PBPF>U)a)U&>Q&BQ&F>x |8`@x8D"8`dKQ`84|<.8`@`x'8x D"8@|8`@8PBPF>U9>8P|8`@88D"8`dKP`/A``;ZT;`;: H``B|8`@Ex8<D"|8`dg{ KP9`8`<8ExD"/@T>PBPF>}$KxtTTZ{ x @/A/g{ A g{ |W>ExSB8`@SF>8x D"8;Z@x A8`<8ExD"/@$T>PBPF>}$KxtAU)?<h?>?>U)?>U)>?ax|8!xN ```B;0Kx``B8`KM`/|}x{XA88KP `9@ x}I8{`H``B H9)}]HPH9 }JI`B;(;@/A ;0(;0K(Kax|;K`B||~x`8bp!AHU`8`hKM`|yA8h8!AaH>`9  8`<8>(D"/9 @T>JKJ`8;8`<{ D"/<`x A|8`@8D"HKI`@A8`<8D"/@4x W>SBSF>q)@8`KK`|zyA88KN`|yx8`@KKe`|~yA88@KM`8@8|xxxH=`<=@xcd9} T>= PBPF>>>yJ 9:``BIB?8|W&>8`@S&B8S&F>x D"8`@KJ`|}yA88@KM5`8@8|{xxH<`cg==@@= |,y)Ƒ]e)=?8|Wf>8`@SfB8SfF>x D"@ H_8?P|g!8`@x 8D"8@|8`@8<D"8`<88D"/@ T>PBPF>}$KxpApx>?bc`;D;z { ; :`;@H `B@P;;@{ @88`<8|D"T>/PB8`}$Kxp8A|D"T>/PB~xPF>IH8a)U*>Q*BQ*F>@yF ||8`@8D"8`KG)`8`<8|D"/x@ Tx ||8`@8D"8`KF`K͕`?x#h||x#K `x/xAt;H `@;{ Apx!Aa8!|N TTdx K``B~óxHQ `KXpx;`K `8bHP`8!|N `8bHP`K`8bHP`K`8bHP`#xDx8KJ`Cx8KG`KH`8b0HPa`xx8@KJ]`x8@KGm`K `B|!|~yA=B*9)/*@4``888bHO`8!|N `Bx /A8`<8D"/8x @9 y$,x |8`@8D"8|8`@88D"X/A$`8KIQ`X8KFa` /A$H8@KI%` 8@KF5`/A$@8@KH`8@KF `8/A$P8KH`88KE`x8hKF`9 > x8!|N `Bx> ``B||~x!|8`<8D"/@d@x |8`@8D"|KB`8cx KB`8@8`<@`B8D"T>/PBPF>}$Kxp A<8|8`@8< D"8!8`|N @KB`8@8`8cx~ H(`B|K?`@A4?Ad9?} L,q)@K?`; @@`;8bHJ`;@[a)} U,|8{K/A0xCx8KD`~xx~óxKD`{# 8`xKD`x8`KA`xx!Aa8!|N ``B`;8bHJ%`8!x|N `B`;8bHI`a8!x|N `B;@[;a)} U,|8{KU/@``8H8bHI`;K``B8~xxVKB`W@.99@8 eJaJ <} 5,}Jx8(9,$9#}@5,9@|vx}I|`E,|y)8@9} E,9)B9]@K |!1#/@= |;xa)@HApx: |ux|#x|3x!z |#xA|+x;a? c#{4)W{~k{ W{@.g{c{ {x 8 8~xH19`9 8|96~E,{ y)}JH@9} E,9)BH@})PP9})P/Wʀ}Jx}@E,A~,7: : @~z }>Kx@d|958@M,U5U@.UJ}JCxU)`&@a}5,l})Cx})Sx9U} U,|5 \a)} U,|?`K;`8cx~ H`B9?} L,q)AK;`@A|?A 9?} L,q)@4; @@;<@\a)} U,|8|KY/@ ``8X8bHF`;pxx!Aa8!|N ```BWހ97xM,= y)e)7K|```B`;8b(HE`8!x|N `B`;8bHHE`8!x|N `;8bpHE`K ```BN |/A= HA8`8!N |`9 88p8`;(!KY`xH*`x|dx8` K9`8`8!|N ``B|`9 88p8`;K``B|`9 88p8`;K```B|`9 88p8`;K0```B!|xdT>/AX/ A@/A8|`8bxHCe`8!|N ``B8!xK|pP/PA0`8b@HC`8!|N ``BKɡ`/@$``88b`HB`Kl`B8`dK7`8!x|K<ƚx!Aa/AaA<襚/At#q)"A=B9J *U)*=B8<9J|;x9j9#89[:@A:`B:D:C:6;~;O:F;@3;`5;H;2;1H @@A:0V1>+cA9~/XP~)/AB:0V/>+!A=9 z1~/~1z~)N `````` L T @ t ```($84`B`8“="`8Hɚ="Kp```B}'HP9J})`B'*Bx!AaAaN >: 0j10Kl*~/: AX:}zpV>~ 9  AH:}rV>~ 9  A:1}z*O pK*~/: A:}zpV>~ 9  A:}rV>~ 9  A:1}z*o pK|*~/: Ah:}zpV>~ 9  A:}rV>~ 9  A:}rV>~ 9  A\:1}z* pK*~/: A:}zpV>~ 9  A:}rV>~ 9  A:1}z* pKh*~/: AT:}zpV>~ 9  A:}rV>~ 9  Ah:1}z* pK*~/: A:}zpV>~ 9  A:}rV>~ 9  A:1}z* pKx*~/: Ad:}zpV>~ 9  A:}rV>~ 9  Ah:}rV>~N 9  A :1}z* pK܊*~/: A:}zpV>~ 9  A 0:}rV>~ 9  A :}rV>~n 9  A :1}z* pK@*~/: A,:}zpV>~ 9  A :}rV>~ 9  A \:1}z* pK>: 0j10K*~/: A:}zpV>~ 9  A X:}rV>~ 9  A ,:}zV>~ 9  A :!}rV>; 4~. 9  A :1}z* p!K*~/: A:}zpV>~ 9  A :}rV>~ 9  A :}zV>~ 9  A l:!}rV>; 8~. 9  A 4:1}z* p!K*~/: A:}zpV>~ 9  A :}rV>~ 9  A :}zV>~ 9  A :!}rV>; 7~. 9  A :1}z* p!KL*~/: A8:}zpV>~ 9  A p:}rV>~ 9  A D:}zV>~ 9  A :}rV>~n 9  A:1}z* pK*~/: Ax:}zpV>~ 9  A:}rV>~ 9  A:}rV>~ 9  A:1}z*: S/ pK*~/: A:}zpV>~ 9  A0:}rV>~ 9  A:}zV>~ 9  A:}rV>~N 9  A:1}z* pK,*~/: A:}zpV>~ 9  A:}rV>~ 9  A:}zV>~ 9  Ap:!}rV>; 0~. 9  A8:1}z* p!K`*~/: AL:}zpV>~ 9  A,:}rV>~ 9  A:}zV>~ 9  A:!}rV>; 9~. 9  A:1}z* p!K*~/: A:}zpV>~ 9  AP:}rV>~ 9  A$:}rV>~ 9  A:1}z*: R/ pK*~/: A:}zpV>~ 9  AL:}rV>~ 9  A :}rV>~ 9  A :1}z*: Q/ pKT*~/: A@:}zpV>~ 9  A:}rV>~ 9  A:}rV>~ 9  At~ z:19P* pK>: 0j10K*~/: A:}zpV>~ 9  A :}rV>~ 9  A:}rV>~ 9  A:1}z* pK*~/: A:}zpV>~ 9  AL:}rV>~ 9  A :}zV>~ 9  A:}rV>~ 9  A:1}z* pK@>":1 1r1AP:0V1>+@}怮/Ap ~9 A:~*  pK#/A!r9"@Tr9A`:"x}/Ap ~9 A:~*  p!Kx!}倮/Ahp ~9 A4:~*  pK8pK0+@A!K pK`:"}/AXp ~9 A4:~*  p!Kp!K!Kp!K!KpKpKpKpKpKpKxpKppKhpK`pKXpKPpKHp!K;H@}>A8!8`|N 88xK`]`K888axH`8`K"`?;(/|@T``88bH+`8!8`|N `B||x!c/AKA`9 ?="9)(8iK"`8!8`|N `B/AL|!K4|} L,= 4h^4P4p}*0P}&fp|q'T`&|HP||B@>4|^4h})4U)~>4|88|x"T>PBUH>PF>QHBQHF>y)})Cx8`@}&Kx8D"/@x8!xa|N ```B8!;xa|N `B9=} L,U)F>/A9 >4KUJF>^4K``B|y!Ax_/Al|p?J+ A|+AP>48/A|9 48x8 8??H `p|8!N (08K`8(K`9 ? >48/@40K`B}&;!1#/AI;/A|A|+xx|#x88x!aiX* PK)`9>^8@}N,|zx/yH"yJ A><`@q)@9? } L,=_9_ })HU)});x} U,|9>~N,z .5@;:9 9? 9@} L,__9_ })HU)})Cx} U,|{d;|*|8`@8<D"8#xKPx83CxK`A~xx~óxK`x!Aa|8!x} N 8~xxK`9?9} L,~E,9xj"|vx|`E,9})HU)}@E,9_e)a) } U,|=; a K``B<`@K` ``B||x8`|#x!Kq`9 /A<9 88?H `88K`9 8!}#Kx|N ``B||x!/A$c 8K)`8K9`x888H `8!|N ```B|= |xy)9@a)|#x8!c08_?(H`+A,?(_9 <|D(y)&9)} J|I*8!|N ``B||x8`|#x!K`9 /A,xxK88K`9  8!}#Kx|N ``B|9|~x!4C9? 8} L,|,|=,9 })HU)})3x} E,|8`@}ESx88D";8xK48!|N ||y!aA|ax|#x<i 40/A?/;40A8 8xH`9 ?>y)y= +<h?>?>U)?>U)>?AD+A ax|8!xN ;48Kl``B<dm*/A``x8 8bxH`K```B8`K]`/|}x{4A88K`9@x} 9@{4I9)@B@+@A)I9)@B;40x/A$;4840;48K`BX/A?\;/j @<8x/A8K)8W8_e)a)U&>UJ>/AD ><8}HQyJ })R\, }JCx9)}@M(> 9<}P08acx}IQ})Ry) }'J9)\, }J3x}@M(9'}M,x(`0 x"T6Ky K9 X8?;xx>x/A8K ?y)B(}#Kx?8Ke`88(K`0>/AT? ^<8U)<})#xU}))a>y) }*J9I}U,^K_> 9<cx;`UJ<}J#xT|I`>} P0aJ})"y) }&J9 9)|E,};x}M(9&}@M,fx(`0 x"T6K) x}&@P8y*9J(Ax9H^9H })&t08}@T,})9|-,8 }JPUJy) aJ })2}@=,y*"} E,9(}@M,|K40K;;K9^x&9)<|T(}FJ~|I*|x}&@PK`ax|;KK/@`8bH`KpK/@`8b@H`K``B;|#xx|x!q8`<8D"/@|T>PBPF>}$Kxp@ 8`<8xD"/9 y) @T>PBPF>y) /U*<@x|UF>8`@QFB8QFF>x D"|;@`B8`<8xD"T>/PB9?PF>y? }DSx.p8`d@AAK `K8`|8!N 8!8`N ``Ba)y* K8|K```B|!a||yA< /@4x85K`9 < 8!|N 8;ax;3}cxK `B?P/AlxK88K 8K8Khp8K9`h8K I`8K`8K %`;(@@8(|8`@88D"80|8`@88D"|4/A$}48K`}48K `8}4P;K58`<x8D"/A/A /A<x|#xE0/ @ 9 (%0}'@P9Fy)yE 9)P@y) A9_}'PPy(9(A9 9 })&t08}D,})9|-,8 }@Uy) a })2}=,y("} U,9*}M,|x8!8`N `Bpx|8!8`N ```B}%KxK<`B|pIX >JyJd|R|U)<8`@})Cx8U&>Q&BQ&F>x D"8xKU/A\|_(}8P9*y 9JHA8>}&t^(x8})Ay) JxH`8x8HQ`(p|8x K@``B9? x&88|L(=}'2,|1* |}'PPK`BKT```B#/A/A /A|9@aJP!aAApaxh(X H }?P8 y)9)A$9>(9> }^RPP9^} L,x"|,|U,9^})H}U,9^ U)a) } U,|#xd|RU)<})Cx|U&>8`@Q&B8Q&F>x D"KQ`?B;`;Z08cx} HAzK)`@A8xK~@/@8`9 >>|Apax8!|N `B8`N ``B9 yk&9k<(,}?Z}_]( |H K```B8`K``B`8bH`8!8`|N ```B8`K0```B|a|#x|+x|3x|x88$8!!K4/@88!8`a|N ```B+,A: A?4/A:@(8}?:8_0HCxK/A,ax!}?/A09 )AK<```B= 8}?/@|/;{ { Ajx``B tJ/}CxQ& 6x @gU)>KxU;h8} =,9'x}M,K/AX}_:~x/@z=@&})BaJ@~<9)I:vP8~~xT}JCx}@M(Ku/A94`_4@}L({$} I*}?/A~Wc,xHx x"T6K|= c0{ x8Hx"T6K]|K`? 9@:($xCh|~x#4tXc#lw(K`/@u8K`u8K`xKz8K]`z8Km`8`ax!A8!a|N ```B`x8,8bH `K`BxK`8`K```B~Kx``B(xK ```B|}x|#xa8`<8!Q}8D"/;@T>PBPF>}$KxxF"8`<88D"/@T>PBPF>}$Kxx#AA;@y)d8`<J8xD"/@T>PBPF>U$>/@8`<8xD"/@T>PBPF>U$F>@8`<8xD"/@tT>PBPF>}$Kxt@\;_8`<Ex8D"/;@T>PBPF>}$Kxx"Ex8`<8D"/;@A``B8`<8xD"/@T>PBPF>}$Kxx#@/A|9:!x8y>  @x @8|;@p= {&;#Za;{ H``B8`<8xD"/x@ dx |8`@x8D"8`KE`x8Kx8`<8D"/<@T>PBPF>TR|8x xKu9>;@y> AP8`<8xD"/@H+T>PBPF>@q$/A(9>;@y> @p|!xA8!8`aN ```B9 Ay) K@9 K<``BA8!8`aN ```BT>PBPF>U:>KdH8@K`||x`8b(!QH`?8`5y)$?K9`|~yA|858aHe`9  8`<8?( D"/9 @T>J8`<88D"/9 y) @T>PBPF>y) J8`<88D"/9 y) @T>PBPF>y) J~8`<8;xD"/@PBPF>}$Kxp@$8xK/A```B8`<8xD"/@T>PBPF>}$Kxp@8`<8xD"/8x @ dx |8`@x8D";@8`<8xD"T>/PB9?PF>y? }DSx.p8`d@AAK`K88|8`@8<,D"8`<88D"/A9 >4`8bhH-``8bH`a8!|N `8b@H`8!|N ``BT>PBPF>}$Kxxp4@p8`KM`/~4@Ah88AH`~4@88;0K`|fx~4H|x"T>PBUH>PF>QHBQHF>y)})Cx8`@}&Kxx8D";^48CxK/A;!x8`<x8D"/9 ?@,x"T>PBUH>PF>QHBQHF>y)})Cxy)4xd|Kx|x"T>PBUH>PF>QHBQHF>y)})Cx8`@}&Kxx8D";>4P8#xKQ/@8`<8xD"/@xxDx|8`@x8D"|CxK!x|8`@x88D"|4@~4H8K`~4@8K `AK4|x"T>PBUH>PF>QHBQHF>y)})Cx8`@}&Kx8D">4^4x8|UF>8`@QFB8QFF>x D"48 |8`@88D";88`<x8D"/9 @,x"T>PBUH>PF>QHBQHF>y)})Cxy) 4px|Kx|x"T>PBUH>PF>QHBQHF>y)})Cx8`@x}&Kx8D";(8`<x8D"/9@UJ@T>PBPF>UJ>4})Sx|U&>xQ&B8`@Q&F>8x D";{08`<ex8D"/9 ?@,x"T>PBUH>PF>QHBQHF>y)})Cxy)4xd|Kx|x"T>PBUH>PF>QHBQHF>y)})Cx8`@}&Kxex8D"|8xK/A,8xK8||xxK|cx/@l|8`@x88D"|8`@ex88D"|4~48K `~48K`p#xKߝKp!xAaK```B|9)KT``B|<=8x8`9@!aa|9!8`8pTc&tp!AK"`a8!|N ``B=");cK8}{$"xc ;KH``B|;{ KxH`};@y# AxK9=;|dxy# K\8!x!Aa|N |?<!qK8`88|0P8ap|Ki!p8!0i|cI|N ``B=")|+x|#x;:֛8;8}9)|j;H@@ xK5@\68}|j9 @@@@@;9)H@AxKyA6W 6H@{ Aax!|9 ;`8!Cxz:Aa} } } N ``Bxc K]||AP/A|@(A8?";9X9=;}}3y? {t ;"H ``B9?~H@y? A<6}S8`}J9)P@AxK]9?H@y? ~@#x8 ~xHY`/@9<{axU) 6!Cx})8!|z:Aa} } } N ``Bxc K|~xK69IP@A,K;}K`6K |9%})|}x9)|+xy)})!qA|? x}AIj;pxH`9 8xxx }>K8?x|N ="):֛8@@A=")P/@!6/AX;9a[x7xH `B;{7{AЁ9{c @@9 AK|ixK!A`B8`8!|N AK```Bx8Ki{ PCxKU8}W>xc KEK18`AK```Bcx8{ K}=};@(``B{c ;{K%{@9 =B!a*PKT `B|="8`?ib艛>cm,!QKu= CP;pa)U0;py)xe)loxa)g88Q!tK= CPxpa)U18y)8Qe)loxa)g!tKxKxK`8b(K`x88P8pKaK8!|N N A\{ K%`9>~|xW>/|x@8!x|N ```B8!;x|N ```B|Aa|#x?|+x;h|8x8!aH}``B;H``BA||;;8xc K`+,#@exxCxH`/A/@;8!xAa|N exxCxH}`/@PK```B|iyA|!?"Aa;9h|3x|+x}?;;!Q;H``BA}<;;8xc K`+|iy@}YExxcx*H̩`/A/@8!8`!Aa|N ExxcxHM`/@@9;/=@P8`||8!!Aa|N 9/=A/A/9=y) x9)8`})AH<```BB@*8c|c/=@8c||Kl8`N 9 })K```B|!a|yx|+x|3x}Cx|#x|;x!QK}_}=9)x }_PPHA{!A|zxA<R;{{ ``Bx;K%`@{ @x8=K`{!;AD;{ ;{ ```Bx;K`@{ @A8`8!!a|N 8`K```B|iyA|!|3x|+x}?Kx!AKuxx|xxxKQ;|yxH```B}?{ xK`9?/@P;K`/|vx@{? xa;c~Azxz x;KY`@{ z@;{ { ````Bx;KE`@{ @xAa~óxK`|x| P|K`8!8`!|N 8`N  ```B}&|y!AA |xA}Cxa|3x|;x|+x|#xK|zyALHǩ`Axx!Kxex|zxxKeP|}xK`|yyAD.@t{ p;~xz H````Bx;K`@{ ~@cxpKy`9=/=A(`B}={ cxKU`9=/=@/;@\z { 97;ix{{ H````Bx;K%`@{ @{ 8;xK`@D;{ x{ ;x;K`@{ @#xK`@(`B{ 8;K`@!xAa8`|8!} N Cx~xxH`/@K~xxxAfxxax8!|x} Kx!Aa|```B8`KH ```||}x8`|#x|+x!aK`|~yA 't="8` ??Ip;pK֝`8|ix8`9I?x\K}`=B= ja#KU`违x="i/A/A]/A/A<`i`yJ 9)x}F3xy8`=(;K`|dy@ax?`?c{{{=(8`}IyE }I*|x;KM`@9 > ax8!x|N `8bxHܙ`yJ&;} P.})RU u@8@A()U>x|"@@}$KxHE`{ 8`xK`>/9)U)>y*!>@>=)>AlpAa|8!x!N `B}=#xxH`Kp``B;K;K`B|hyAl|dyH|#x9 }Cx898!e8Ke`,#@,8!x|N ``B8`N |dx`8b;H`K99 } !A9C }(Jy) B/A9C} ,?;ޝV,?U&>Q&B8`@轝Q&F>8x 8TD"g轝8`@W>8SBSF>8Tx D";T;```B8`@88|*D">88`@88|JD",=;;@8`8!N `B|!?A;a|{x;;ޝ{ ;Ap^{ qJ"A; 9@})P08`@a)8U&>Q&B8Q&F>x D"8`<88D"/@0T>PBPF>}$Kx)H8/x @|;H`By_!A@d8`K!`8`<88D"T>/PB9_PF>}$Kx)H8y) x .A+@x/A{;+T>|.@```B=")q)@tAr!pW>{ UG>U(>[;UJ})Sxy) !Aa|K`B{;+xT>|.@\Kt; 9@Kd`B<襝8`<88D"/@ T>tPBPF>}$KxpA<tkK0`8b(HՑ`8`!Aa|K}9KxK`B+A|<9 8締9|;xH A0*.@99J@8`N ```B}BH=9 8`H=B*N ``B9@ K```B8|x<襝8`8`@<襝SB8SF>|Kxx D"N `Bli/@ |#xK8`N ``B|!A="?Bi8`;Z!QK˩`|yyA88H`<8`@ CxK`??88违}:Px 8`@<@ 8D"违8`<88D"/@tT>PBPF>}$Kxp@\;1`B8`dK]`8`<88D"9?/y?!T>PBPF>U$x .@ AA#xK /@p;?a;}(x;```B88xH`|<@ }I;0@}@(;@J8`@{"8U&>Q&B88Q&F>x D"W>8`@SB8SF>x 88D"8`@8<88D"8`@8888D"8`@8888D"<8`@`8x 8D"8`@888D";z;(x;```B88xH`|<@ }I;0}@(;@@J9 {"8`@UF><@8QFB8(QFF>x D"W>8`@SB8SF>x 8(D"8`@8<8(D"8`@888(D"8`@8<8(D"8`@888( D"8`@8<8D"9 9 pa8!#x!A|N /@\#x8Kȁ`; K`8bH!`K``B# /M |?8|x辝8`@88!D"辝8`@888D"8` K`辝8`@888(D"辝8`@888(D"辝8`@8888D"辝8`@8888D"辝8`<88TD"/<`x @ Tnx <襝?8`@;ޝ88TD"8`TcK58` K`<`K!8` K`=><x`@ i@ |~Kȹ`9 x8? K`8!|N `Ba|{y!aA<襝8`<88(D"/9@yJ A`?;;?<@P@Ap9)y?&}]* q)@x8!xaN `B?T>;PB?PF>y* ;<@P@@8!xaN ``B|9*|(cxN,<@ ;| PxH`88|}8H=`|9<@8`@8|L,8(D"<@x9)U)~<@8!a|N ```B;K```B|}y!qA<襝8`<|#xp888D"/;{ @T>PBPF>{ <襝8`<888D"/A|9 ;y) ?9);y)&=x|L(xJ@ |hPH9`9 9_W,? |<襝x8`@888D"xp|8!N ```BT>;PBW~PF>}$Kxy)  @@ p8!N `B|8T~T>PBPF>{ K ```B8`Kt```Bli/@||#x|3x|+x!Ku/@<="88xɝH`8!x|K8!8`|N `B8`N ```||#x`|}x8(!q;p|exx!AH`8x |~x|H`84||"Kס`xH`8xd xK`8!|N ``B||}x!Q;pxHx`/|x@<|eVp`8@8b8H`8!x|N 9 |exxx88!H~`|x/AaKy8!x|N ``B}&|;a|+x|{x|3x|#x!A-!AA/A``88bH`H]y`H``?B.>-;`;Z; :;xxH`Hա`/At/A|AA$@}R8H`xcxH`|~yAd/@;xxHY`H1`/@`;8bhH5`H\``B``88bH`K`Bxcx:H\`/|~xAH`8bH`8!x!Aa|} } } N ``Bxcx:H\E`|~xK`B``88bHQ`H[`KH```B`x8bx;H!`KH`BH`8|dx8}HM`K `B}&|9@!A899 |xx8`|#x|+x|3x!!Ah=Bx`*K=`|zyAH88aHm``;a8b;pHť`8X8cx;H=`x888`K`/|jx@hH`/A9?/ }?AtKq`K`K`/Ax888`K1`/|jxA/@`8`080;KEH$```B`8`08;K!8CxK`aH`aH`a8!x!A|} N !utsr`qp8bPAH`xH&m`},Bar|cJxxc H%`/@0/@`;8bH`K:8~x8Hi`= 9@y);Xa)Ax"x"xFKaK^`K;`;Hxx8H=`/@D9 !<8dxCxKu|xK<;~xxxHI`:9 88~x<H`xH`.#|vx@="9@)ʑAx"x"xFHa`K~x8~óxH`9 !K;`:`x~óx8HA`|yaA~ijxH`=")/A;KT/A8c;||;Kȉ!/Ax88aH`9 !x"x"xFH1`K8H}`Hx`8|dx8aHU`=")/@X;K~x8 8HY`|c/a@0K$`~ijx;8bH`x8aH``x8bH`K(!K 8 8~xH`|c/a@|Kp888a@:HM`9 .6!;X8x8H)`888apH`K`~x8H`/A="9@)ʑAx"x"xFH]`H5`|~y@x88aH``8bT>x"x"xFH`xH&E`K`=@ffaJfg|ix|cp})P})p|cHP|cA|cK`HH`H&`/AK`/xA`;8b(H`aH`aH`aKM`8! x|N ``Bx8H`8@x8;|{xH`xxH`{ /ALcx8Ha`+|{xAK8``B;xx8H`a/@a/AHQ`apH`p`8bXT>x"x"xFHa`H9`|~yA`8bxHA``W>{"{ņ"{F"8bH!`K`B`;8bH`K|``B8@x8xH`xxH`/@`;8b8H`KP`BaK``B8@x8He`8xHE`/Ax8H`+|}xA8@x8H`x8 8H`aaK`BxH `aKp```BHq`KL`B`;8b0H`KL`;8bH`KX`;8bH`K<`,$9@M `B#+,A/A0#*,/@9*8cH@y* @N `B8`N ```B|jx8```B*+,A,/@N ``BM **,/@5JM 8cxc K```B#+,AX/AP|jx8`8c*xc *,/M ```BM *8cxc *,/@N 8`N ```B,$!|+xAX9@``B#+,A,/````BAȍ#*,/@9*8cH@y* @|/xA#+,A/A|jx;H `BA*;{ *,/@|dx|3xxH`/A(9 x}>x8!|N x|8!8`N ;K`B}&||+x!;; Aa`;d;B;.%|x:!!;p/A+A$H`/ADxxHi`|uyALDxxHQ`|P|c4+ x~ AxxxH`p8 8xHy`+A{/;{ ?i).})4U)~JA@;8 xxH!`8 8yxH`|~xxH`9>+A$A# ~0K```B8`8!!Aa|} N ``B8\xH)`|~yA\8\xH`|P|c4+ x~ Axxxx; H`pK```Bx8 xH`xyH`Kd`Bk|c4Tc~|c|cK ```B8K<```````|x |}x!Q;pxHT`/|xAx/A9 |exxx88!H[Q`|x/A`8b H`8!x|N ``B|ex`8@8bHA`8!x|N `8bH`K``B|x9 !a|px`````!|+x|;xAa`|{x;|3x";p@;A!9;BX'`:`9":"h:x:bp:8!p@``B@8 ~xHA`,#AT9```B8c@A$C+ qH. AA``B0+ * A@:K`B/A|+#At8 ~xH`,#A,:C````B2* + A@:RK`B~xCxH`/@~Xx`B}sx@A8!xpx!Aa|!AaN ``B|{xK~x~xH=`/@p/{.~VI*A ~CxxH`/@;}sxK88 ~xHy`,#@~x~xH1`}sxK~x~#xH`/@X/@<~x~cxH`~x~xH`ap~x}sxH`K{.}sx}6JIK~x~cxHM`/@ /A{.}sx}6JIKh~x~xH`/@/A{.}sx}6JIK4|a}TSx}5Kx|+x!}Cx|3xAa;h|#x|}x|;x{!!cHaP/AH-`+|ATH;@;@xH``8b0H`}@/AH`|xxxH`|x+A`@xHQ`&xexxxK9/@<AP+A`x8 H`xH`K`8bH`8`8!a!Aa|N `8bHm`8`K`8bPHU`8`K`x8; ;;@T>x"x"xFHA`H `BA0^&xexxxK@.@KLK ```||dy8!A,8a)y)|dxe)8ua)}8*H`8$x8uHi`uK-`&x8|ex~xK`~x8*xKA`/@<=@=aJ̀f8}'PU)) })8PH&@9}(PU)) })@P:c9 888c|x>~ Hm`Ku`88|ex8z< K`xx8z<.;Hu`="%K`K`HKA`/@xK-`>/@8`!8!Aa|N `B+@=BJ=")D $K```BZ< }Jx}J@8/@!9Z `: KQ`;~ ~x8|excxK`xx8~H~Q`8dx|xKI`8!Aa|N `B:<A8:8@?b{AI}R A0<`H}R A9 }(0U)) })@P8@y) I@K``B9 888ap?H}-`? _ y'!!r|9 aAyA(9@`B}R9J8@yJ })BA9 9An} ``B })BBy*y) }*Jy*})RU)>}*HqH@?K``B9Z !>:K$; `R;" :8~x8H}Q`/A!K<KtK8`N 8`K`;?;;" K8`;; ;" K `B="iK``BH=B*="iN |9 =BTc+?L 9)@8`U)>Tc.+L 8`N ``B8`TcN ``B9 9E 9@ #C# N `B+@||}xA|#xa!a=")|? x/A0@A$/A=")/A 0@@98 |9^ 9 })BBy*y) }*Jy*})R})HU)>H@>q*@q) @> /A/A/@>/{ A/A/@>m*/v@T>/@H=> HH@4/A,9 8`(Hh`B==F a@@A8?8`Aa|N =")%?;@A88`8?Aa|N ``B=")% @@q* @p^U)8~x})R ;pp8a^ ^>Hv]`^^9!89@ H@}JB@yIyJ }IRxyIx}JJx}IP>K!8`;axK>%/A4/@9J|8~0yD H `8`K8`N 9J|8~0yD H`8`K``B+@L$/@@$/@4!Q?=");ЁDP@||x|#x$/At/A8!8`N |K`88Hu`/@/A>0@ApAa}^J 8Ap=aH}^J 8AT9I}*@U)) })PP0@y) @Aa|8`8!N ~`;{88(cxHt`|zy@88cxHs`=/@XAa|8!8`N ``B/A|!xA;> ap8*;8;} ;yYcxHs`K%`x8|excxK`K`= < 8a)y)|dxe)8za)}9*Hs`x88zHr`dxx8*K`p!x8`Aa8!|N ``B;< dx8xHr`BxxK}`]8`K``B8`|K``B8`N ```B/="!@8!N `B|= 萁=Ey)ap=@e)vyyJa)|x8Tp8*8aAx!Hqa`9.9A} 9 ``B })BBy*y) }*Jxy*8p})R8p})H!K8!|N ``BHia`CxHi`+9CA= 8a)85cx`}9Q.x;pK`88xHlY`HDq`xx8|fxxHEe`A(="9)+xx)Ii}IIN!A(8!!Aa|N :;`;:K```B= 8a)cxx`}9Q.85K`<1|8T>8xK}`K( `B/!A="8!pi18`N |~x!A#x|+x%|3xHg-``x80Hi)`/A`x88Hi `;`x;@xHh`/AxxHh`;`x;@xHh`/AxxHh`PW>`x;@xHh`/AXxxHhm`|PTc>@@|}xW>9=U)>+Axx#xHg`9 ;~xx=Hf`#xHfU`+A,p*x;x`B?;?:P}DSxW>~óx*.x+?/A@(AHg`9|9_/A ?xK=BJ1Й'/A+A>9 =B; ~xx*3; He5`xHe`x/@xcxKKu`Kt`H8`B>/AA$>/AAKu`/@cxK`~*+|uAp8!;x!Aa|N `;8bHH~U`8!x!Aa|N `BxHdm`Tc>K```BxHdM`T}>K\```B~xxHc`p`;8b`H}`8!x!Aa|N xcxKIK\`;8bH}U`p8!x!Aa|N 99y9!@`88bH|`pK``B8Cx8;Hf!`pKx8Cx8;Hf`pKX888~He`K< ```B#/4A8`N ```B9@aJU (P@q !Q@||~x; #/A?;5;H>P@xxxxK9]}],#;@8`8!|N ```B9 =B8`8!*3N ``B>/Aa?b!x;;{+A; ;[;; H$```B>9]}]P@lxxxKQ|yA?/@DxxH`q`/@D?/AX/A/Ap?9) JK!xAa8`K$xxH``/AK`B%x8 xK/@!xAaK? =B8`!xAa*3K``B8{8 8Hcu`8`!xAaKP```|9 a:e`!a`z{ ;"|#x|~x`!8b: HA:;A;!$|? xHyi`="d#x6HyQ`/A!|: x8V8!;pxHb5`x888HKy`8C8D8a84K`~ijx8aH^`K`8|dx8aHb `}RxK߉`!88:Ax!!1;p:Ax:Ha`Kn`:KnQ```B}R88xKja`/A9> 9@ H@}JB@yIyJ }IRyI}JJ}JPUJ>P@@>/@4>$/D@(>"/C@>*/Ah```BKm`/AT!;{#x{{ d:AxHw`/@8`zd 8b : Hwe`HKy`8~xHai`|qy@>^:88}@=]H]`!`8bP:AxHv`8?~#x!Aa!Aa|N |Aa;e{{ |#x |3x|~x!aخ;ApCx P*{ | Px|"H_m`<}Dxx|cJ|P|~H_I`}8|P|~H_-`}>خ\})R}>ٮ\=})R=8!Aa|N a|#x|3x|+x|xA!a/APC9 +@H`B}_H+Ax/9I9)y) A}?H})Ry) H@A;}]]/A<+@t8!8`AaN ```B;{ @A8!x|ctAaxcтN `B|{/A\?H@A+AH8H}?(H@*AA,/9%8x A|(|Jx (@AȈ|Dx8H]E`;Z9)})R;9>9^y) |HR{ K`B;K8`BFxdxxKK||#x8|~x|+x|+x8!AH\a`<x88H]Y`/@+@x;;!A;=;@a;`}>}^}I}>/5A```B+5@/]A+]A/BAD/CA,/6@܁ 9?9_y) HR{ @A``Bx!Aax8!|ctxcт|N /A\+@/2A|/4A/@D}9?9y) J]HB{ H/A/A/A 9?9_y) HR{ HP```B/A/@̙=9?9y) J]HB{ ```B@@}>}^}I}>/5@t9_yI }H9(U)>+A;{ { K``B9?;y* { }^P]{ K|``B;{ Kh`Bx!A8`a8!|N ``B:8z |"#x|HY`}>9_}=JIR{ Kx!Aa8!8`|N ``B9_9?yJ y) ;}^P}>H{ UJ@.})Sx=Kt}9?;y) J] }>HJ{ KL``BJ9?;y) ]}>HJ{ K ```B:8z |"x|HX`}>9_}=JIR{ Kp:>z |~8cH_`/v6A$|8|"HXI`}>V6JI}>;p{ Kp```Bp:>z |~8cH_I`/v6A|8;|"HW`}>V6JI}>{ pK;K ``B|?|~x;6<8}88!qHWa`^8`+A9 8`})P6q)@(8!|N ```B95];>/A9@4=!;"]>2/A9 2;?>?>6/@98} 9 |;x }(JU)>B/A@97?9@;`B'9 /A _;U >+@>B/@>C/@`>]/A= ];a) ?9 8`?8!|N 9 6;?>?K(9 C;x?HR`x9#8U)>}%Kx?HU`?9)JK`9 B;x?HR`x9#8U)>}%Kx?HUa`?9)JK ```B|a|{x?8H;68;;x!AHT`=9@=")<;p64=H66=B*68KΑ`8|dx8}HHT`88xHTY`9 x!!q!v!s!K8}$8C8D84K`<< 8xx 88HKY`xcx8HKѵ`8!a|N ```B|!HZ`|xHZ`8!W}#x="i<|N ```B|!A`9 ;B?|yxa;6|#x;;!AxdRDx!pHO`DxxHO`=B9 cx;@*>=B*6=B*6K9 =B*>K``K_q`cxK̵`>./A@@l8!8`!Aa|N ``B?/A>?/@?@/@xHOU`/@=")>/AH!p=BJ< ?x8@_HN`<<9 8`6F6'6&6@_H8!!Aa|N ```B=B*>?@/AH8@xHN5`xHN`/A8;ApxDxK`/A0!pK(`BK^1`/Al+A;@KLExxcx8K1`/@>/@8`K```B8`K```B|Aa8H?||x;68;?bx?B!AHP9`<8=BJ<99 64<;p66=H68=B*6K `8|dx8}HHP%`;< =B88x*6@HO`:> 99@xA!pKQ8}$8C8D84K]`> < x88HK`xx8HK-`8!Aa|N |!|yxa|#x|+x88!;xHN`?/@|=BJ<?;6?P@X<;8x8HO`/@A{z x;x{ xK/A!/@!/A?>/A /@+A<+@9 9@A8`>>^H`B_?;,x^>?ܑ>HK!`/A/A;lxHJ`/A$x8~8HK`9 =B*<9 =B8`*>8! !a|N ```B+AA8! 8`!a|N `Bx8@8~HKE`HK(;Z:pxx~xAHL`!/A/AL/A8`AK`B_?=;,?xH< <>HI`/A>/Ax;lxHI}`/@9@=?ܙH>=B*> /A/A@exxHL`!/A4!/A(aK!`aKU````B!/A`a88Ky`KHA8! 8`!a|N ``B8`AK``B88l88atKq|c4/Adx~x8x KM/ADKx``Bx8@8~HI`HKt`Bx8HJ`K```Bx8~8HH`9 =B*^@!9)U)>+@ /Aԋ/@!=B<q)/A<;lxHF`/A$x88~HG```B9 =B*>K@_!;8H8x;`;p^>HI`>9@~,^.>0K `8|dx8~HHI)`88xHH`9 888at!HH`888apHH`xqvs͛ͳaaAK%8~$8C8D84K1`8xx 888HKΡ`x#x8HK`9 8`A>K8~8HD`K88~HD`K48@8,8~HF1`HK `="!>*}% P})p/@x|=")>,|#x/A`; `xVtH^Q`9@=="H>,|>(9 =B8!*N =")q*A/@x9)y) K```B`;p; `|VtxxHRU`!p/A$x9``B */@`x8bH]`K ``B|a|#x||x|+xA?8;>(8;!axHF)`=")?2/A/A,x88 8`K`9 )`BHA`88 ;0;@4|fxx8 H)`xx88 Kq`9@ A(Ex="9)+xx_)Ii}IIN!A(8!Aa|N =")?8888 x;;@ Km`KT`B|A|xx?8!;>(8a;]Cx!1`"|`Bx!tApHD`=")?2/A/HA`|x8}HAu`8E8|8`|8T>K`9 )```BHA1`:p`;p;}|~x~xHA`:0xH@`|xcxH@`H`88;?6|fxT>Cx8 9H`|~xcxH@e`8E8|~óx|8T>K`9 ??86;@xH@!`x8xHB``|x~xH>`xH>`|yxcxH>`>?888#Cx9;9"W$>9Kǁ`K ``B=")!a/AP|="|#x||xax?J8`|+x?b;{>(KKN1`KM`>=B+|4?LA+A0U*>/Ad+A[88`*9)*ax8!|N `B U*>+A=B9J y)}*J})R})N tt4t`B="Ap?L9 =B*?N;8x8T>H=`=")?2/A/AXx88 8`K5`9 )9 x8;&K8`K`B9 =B8`*?PK```B9 =B8`*?PK```B9 =B8`*?PK```B9 =B8`*?PK```B9 =B8`*?PK```B[0/A,+A$,``B=")?`9@=<?h?JI^}*B9)8@9 =B8`*?PK ``BH`88 ;0;@5|fxx8 Hi`x88 xḴ`= 9A(=B9J+a)Ex xx>*Ii}IIN!A(9 8`Ap;(K\``B9 =B8`*?PK@```BxK=?`<8`G?\(9J9)G?\(K```B,K``BI8`9JIK```B=")?8888!x;;@!K`K9 8`;DKPApK;0/@9 8`;(K`="Ap?LK=B c9 j?P=B*?lN ``B|="=9@?h="9`?`???p9 8!q89|#x;>(|?8`88(T'<8'?H<'?l<?0<`; '?\<'>(="I?P="I?T=" ?L="i>,="?X=" ?NHD``8bHP9`88`K="KF`KF`iRKE8(9)(KE!`KDy`K ```B*9 =B*/@4"8`K`8bHHNE`6/@t="i?J8!|N ``B9@8!9 8`ב_(=B*|N ``B`8bHM`K|!|3xA|}x|;x|;x|#xa|+x!AH>`|yA0xxH4``88xH3`|{y@8[xH2I`|~yA>/[A8.xH2%`|~yA8.8~H2 `/Ax8/H1`|}yA9?9}IP;p}J}$Kxx;p} QH2`xxx8K`/A(DxxH`8#xH2M`xH@`8!cx!Aa|N `B8]H1-`|iyAl}>HP8/x}=H1 `||yA8~Dx8~H`8/@\`x8b`HK`x;`H?`KL```B`x8b;`HKa`xH?`K``B`;`8bHK5`K`;`8bHK`K`x8b;`HJ`xH?Q`K`x8b;`HJ`xH?)`K`x8b@;`HJ`xH?`Kd`x8b@K`x8b(;`HJu`xH>`K,/|;x!|3xA,/A@/A/A4/AL/A`/At/A/A9%+@0/|#xA/A@/A8!|+xN |8p+A=B9JTx}**})R})N dXp`89 0?;?x`(x8H=`8p|Kh`8K`80K`8K`9@09"h8G&K(`B`9@09"8G&K`B`9@09"8G&K`9@09"8G&K`9@09"8G&K`9@09"08G&K`9@09"X8G&Kx|9 0 p?`;?x8@8x8P'HV`8p|K(|9 0p=B?;?x`?j8@8x(8PHU`8p|K|9 0p?`;?x8x'H<`8p|K|9 0p?`;?x8x'H;`8p|K8|9 0p?`;?x8x' H;e`8p|K`8PK<`8K0````??!A/A|a;ap|#x||x;H```B8/AX_8dxrx^H0)`/@a8`8!|N a|8!8`N ```B|||x|+x|#x8(|dx!A;pxH.`/\9 !p!vAwA;9 {b9]}I^;UJ@.}JCx}J})RB99@} H_})RB8!y#y) }#Jy#|cJ||cTc>N 9 K`B|!a|{x|+x|#x88!;!#xH-`9>+AA88p?8a;?;(;_]}?ArH.%`/Ax?+A+:A!/Ax=")?/A0I@@HI@A)8/@H`||yA?B;Z?AK`;](8x`|exCxK`xx8}6H,`8Dx|cxK`A8!!a|N aH u`|xyA;]8DxxH,`/@8DxCx\xH,`/@\8/AK <?Cx8H+`?+@xxxK,#A.K````B8DxxH,E`/AK```B$xcxHy`K`8x`|ex8x(Ku`xx8x6H+`K8E`K7`HK7`/@@cxK`8/@xAKT9 33888a;!H*`KA8`8!!a|N ``BxxKe*K ``BA8`K```B8` H1]`|xyAt8 8H)`8$x8xH)`9 x8H`?B;Z?K``B9 ?.Kx8`AK0|Aa;@|#x;|~x!Qc;ap/A+AH,`/A8:xH$`|yA|P|4+x AxxcxH'`_p88cxH-`+|iAl})Fp|;{ <~+:A<;/@T8!Aa|N ~;;K8!8`Aa|N `Bx8cxH&5`cxtH%`K ``B/Ah/:A08!8`|N ```Bx8<xH`8!|N 8(xK`8!|N `B|=@`|x9 |;x8c!|3x8_?H&`x88H&}`8!|N ||~x|dx8!q;xxH&)`888a}H&`9 x88ap!{H%`ap8!|N ``B|= y)|#x$!KQ8!|N ``B=")?/A<I@@ H0```BI@A)8/@8`N 8`N ```B|8`(!H,=`|yA8(8H$`8!x|N ``B|!qa8`@H+`|yAP8@8H$-`88xH$Y`K!`K|$ x88pd8H$1`8!x|N `B|y!A|K/@t?/@L=")?/A|=")E89 =B8`?8E8!|N `B8`@pH*`|~y@<p|8!8`N ```B="?K`B8@8H"`= =@a)yJy)x^>? > ?>?>KpK}&||#x|x8`@!qH)`|~yA$.=8@8H"I`="?Axx8H"i`y>!@A(8!|} N =")?/A=y``BI/AIyJD@@`)8/@8!|} N `BK`??= y)>Ku~K\=B*?K<|!a8a88H!I`8!p|c4Tc~|N ```B|a8||x|#x|#x8!1H`x8:H`|yAt;;H/}>|xA@88:H`9>P/@/;;|x@/@0;8!xa|N A/AK/A/A`x80H`|yAx`x88HI`/A|PT>+ApA;ApxxCxH`;9 8x>pKE|y@dAK(dxxK)8!|xax|N ``B9 ;;K x|cx|{HE`xCxK|eyAtxcxH!`AK```B|9 !Aa````|#x|~x;;BX;bP!Q;"@$;@H@dxxH(`/xx;A H`;/AX>/.@$x@DxxH`K`B|3xx}&Kx$xxH(M`K`x;``BxxH`|y}>P}*/}^RA;A*/:@}=P9@})/}]I@`x80H`?;/AD`;¤hH```B?/A 8xxH`/AxxH``x8pHM`/@`x80H`8!!Aa|N ```B`x8@H5`K$```||}x88?;F0!8ap;~H`Ku`x88*|fxxKi`8#8a8"8*K`9 8@88a!H`= 9Aa) y)e)a)*K`8|dx8aH`=@= aJa)yJy)eJe)aJa);xx8RA!K`8!|N ``B|!H!5`="iFpH!%`="iFqH!`8!p="iFr|N ``B|==@= RyJFx=a)HF0=B?!qx;*F8;޺ K 9 =B* K&`K&%`xKi`>.+AT@08!8`|N ```BK&!`/A+A;K8!8`|N `B|a?b;{F0|x|#x8c8@8!QH}`,#@@?/A$;;/@!xA; ;ApHT8@@CxHu`HCxR}!:8@8 )pK=`/A/x@t?.P/;;9%J@{H;8x8c0H`x88`xK}`/A```B!xA8!8`a|N ="i K`B8!8`axc |N ||}x8`!aHe`|yA=@9 yJ;!xApK `8p8:8|fxxK`9@9 _6?>K`8|dx8@H`A(="9)+x88x)Ii}IIN!A(xH!q`8!|N ```B^P@@>U)8}IP})/J}_@D>/@88xH`>U)8}IP})/J}_A8!9 =Ba8`*F|N 9?(;x88a!H!`aHQ`|yA88H`?9@_/@8`8!a|N 8`H`|yApK`;x;>8:|fx8 xK`x8x;PHa`9 ?NK!`8|dxxH=`?:99@886_NxU)~a)`?:H`K!`8|dxxH`K`8|dxxH`A(="9)+x8Hcx)Ii}IIN!A(xH`8!8`a|N x8H`/AtHy`8`Kh``B|N |="?a`;F`!`A|yx;\;F;;b :!1:¥0H```B8uH`|yA888`K`~x|dxxH -`~<{&y*&}\RJ/A;9)/ }?<A/#A/{&A x%xxxH`8x8`K!`xH`8|dx8`K`cxH`ex|dx8` K`888`K`|uy@<{&;y*&}\RJ/@8!!Aa|N ``B~óxH`K$xxHi`K |!K`|xHK/@8K`|P+ @8!|N ```BKK`|xK|`8bP?;F!qK!`8bXK`8b`K =")F/A`8bH`=")F/@pp`x;;;``B/81|9>X@}$xx;H`?9^}^PApxK/@(``BKq/AK+Z|iA+A@ +0AXA+9A8i|c/A?@xc&;8x8`KE`xH`8|dx8`K%`=(F/9)}*(F@L;```ByJ&}_RjHu`?/y(&}B9)}*?A8!|N 8c+@KuK```B8i|cK`B8i|cK`B`8bhH`8!|N ```B888`K%`K```||x!qpHy`p|c|H`8!x|N ``#T>/A(H@@N `BM #. @@8`N ``C$/AD/ALH@AH@```BA0@,C$/. H@@8`|iP|cN }C|iP|cN `89C``B$*$/M $*$/@N ``````#/A89 ````BC9)})/@}#KxN `B8`N ```,%AC$/AP/Ad4A\|H@AHL``BA@B@<@8C$/. H@@8`|iP|cN ```B}C|iP|cN 8`N ```D/Ax/M ||ixHB@P9)I8D/@/8|*9)}I(P}I9@M `BIBN `BN ```B|ixK```|y!qA/A|px|#xK!`|}xxK`||/@H@AH\``B;@AHxxxK)`/@px8!x|N `Bpx|8!;xN ```/8M 9%T>})9#`BBN ``/8M 9%8})9#`BDIBN `@@L}$*H@A@/9E|RM !E|*|R}DHP}I``BIEBN /M |89#```BDIBN `/8AXC$P@@<9%})H``````BB@ C$H@A|iPP|cN 8`N ```!q|}x$c/Ax/Ap||#xH `B}>/.A`A\H`|x~H`A>}|8!|iP|cN ```B8!|iP|c|N |T>|x!K`9#|J@A8}?H@ H,```B#A8c@@8`8!|N 8cxc 8cxcN xc Tj9#8jy) xc !) cy)xci)hc|cKxN ```9#+M 8c |cN ```9#+M 8c|cN ```,$|ixAh+$$AH<x`&```BI+ |T6q@/@+0@I8 /x@,9 I} Cx+08@؉I/xA9@08`H4``B}4(9)}EL $|hRI/M 9 8U>T>* +}4@89 @T>9J+}H4M (9)}EAN `BA9)$K/A/@K4```B8 /@88`N ```B8K9 I} CxK``|#y|ixAX+$&8`M <x`&``BI+ |T6q@+-9`@9 /9`I} Cx@+08 A/A$8`H4``B}4(9)}E@`&|hRI/AL9 8U>T>* +}4@89 @T>9J+}H4@``B/M |cN A9)&K9`/AD/@H+08@{"a){"8!<#GH9C}CSxAa|N @9I@tWG>}@P`|{"{"yG"y"y"ii8!|ᮙ}CSxAa|N `8!}CSxAa|N 8!9@}CSxAa|N ```,#M #U)>#N ```!/!AA0/A(|8H `|8!pN 8`K```}&=@01= 89aaJ23a)ab|+yyJy)eJ45!Qe)cdaJ67a)ef|{x|3xAp!xA} Cx9 }J9)})/@}?Kx@8`A|.'xH/;x|iA@;||@P|*epAK`/;xTc>|i@;8`});|8!a} N `B;KD```B|!A|#x|}x8|+x|3xa8 |;x}Cx}>Kx!Q}KA`/|cA9@``B9J}J/@yJ }^RP@P}*P})9)}[8Py) P@9)})A H$@ '8};8P@B8!8`!Aa|N 9@Kt```B|a|#x|~x|+x;!aH4``B^}9)>xKu`@A8!8`a|N !|hyaA/8`A`aXp9"xA`!9p:!!9!!H:BAP`|3x;!h;A}Cx%/AH}@P}Cx@@8+%889EA(}ESx%/9@9 (a!A!HAPaX`px|}Ph|c8!N `B+iAl+uAd+xA\+XAT+pAL+cAD+sA<+%A+OA,+oA$}GSx&|+x9G%}J+d@8}NR|8|:* 9%q)A(9 ~$x!/A{QA| 9(0::8::a@}{x}8!```B9%:U*>++Al=B9JHdy)}*J})R})N LLLLLLLLLLLLLLLLLLLLL\LL<LLLLLLLL```B:z$||P}sx}RP*8p9 CxP8~fxK~ex~x8| PCx|PKm}{x/A|@P~x8@Aa (08@|;98K`B8`8!N `B9H9 %8A(`BKz$||P}sx}RP*8p9 Cx P8}FSxAKA~x8}ESxK}{x:K$}!8 8}sxpKE`|jxAK`A|c@\!|cPP|c|P}HHP8@}$Kx@P8cxc 9C}IH ```B}HHP}$KxP@@ 9@ I!9)!B}$Kx| Px|PCxK5}{xKH`B}A|Px89 9 p}sxCxKCx| P|PK~x8xK```B+l}{x:@|#xK+h}{x:@|#x:K```B+u}!xpAV89@9)}IH6 H9@| P8 |P~fx}sx9 CxK~ex~x8 K``B}A|P9 9 }sx8 p8CxK!}{x 9K```B9%U)>+ A}!:z p}{xK`B9 0!K```BK``B9 -(z$}RH*!}3P88K```||+x|#x8x`!K`8!p|N |!8!AH`8!p|N `|!|dx+)A=B9JQ y)}*J})R})N ```BxK}T~>+ A9>U)>+@xK/@9x9IY)K5Ti>/ }#A9)+@K/@|=/Ap~xK/@8!8`!Aa|N ``BxK/T~>A`+ Tc>|vA/ A/ A:~HX@l~óxK%`/AXx;K5T~>Tc>+ |vA@/ A8/ A0~óxK/A```B9>}AU)>+ p@xK/A\``BCxK`/A|88CxK`99IY)iHxK}/T~>A+ Ti>}#Ap/ Ah/ A`:~ڲHT@\9>U)>+ALx;KT~>Ti>+ }#A/ A / AK/A`B}!/ pA 9>U)>+@K}/ACxK߭`/Al8K`BxK/T~>A+ Ti>}#A/ A/ A:~ڲHD@Hx;K9T~>Ti>+ }#A/ A/ AK/A9>}AU)>+ p@K/@=/@|9Dx9IYiK]`H$xK/T~>AP+ Tc>|vA@/ A8/ A0:~HX@l~óxK`/AXx;KET~>Tc>+ |vA/ A/ A~óxK/A```B9>}AU)>+ p@xK/ATCxK`/A8 K```B9U >+ A}}``B/@(K}!Dx p99IYiK`K``B}!Cx pKE`/@t8!8`!Aa|N `B}! pK8`B}! pK`B+ Ti>}#AD/ ATi>+ }#A/ A/ AK)/AKX``B+ Tc>|vA/ A/ A:~HT`B~óxK`/Ax;KT~>Tc>+ |vA/ A/ A~óxK/AK+ Ti>}#A/ A/ A:~ڲHP`B9>U)>+Ax;KqT~>Ti>+ }#Al/ Ad/ A\K /AK\``B+ Tc>|vAD/ ATc>+ |vA/ A/ A~óxKq/AK=/A~xK!K܁=/A~xK K=/A~xKK~xK9Dx9IYiK`K8`N  ```B!A$/AX|Aa;;@|}x;a|#x;pH);/A+%x@?8o9HT`B+iAl+xAd+XA\+pAT+cAL+sAD+%At+OA4+oA,}HSx'9H?}J+d@```B9}AR}ex}Bx*pxHpK-/@$;x;)/@(`BAa|8!xN ;KKphandle THENlocal-mac-addressEXECUTEkey? IF key ELSE 0 THENget-msecsusdma-allocdma-freealloc-memfree-memdma-map-indma-map-outconfig-l@config-w@config-b@config-l!config-w!config-b!translate-my-addresswrite-mm-logencode-intset-chosenencode-bytesbootp-responsedhcp-responsefind-node get-propertyBITMAP: start %lx, size %ld, blocksize %ld 0 16 32 48 63 Error: Bitmap start %lx, size %ld, requested address %lx, size %ld ELF32: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting ELF64: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting ELF relocation out of bounds! ERROR: Unhandled relocation (A) type %i elf-claim-segmentFailed to allocate memorymemory allocation failed! Device does not support virtio 1.0 %llx Features error %llx virtioblk_init%s: failed virtioblk_transfer: Access beyond end of device!virtio-blk: Unaligned sector size %d virtioblk_transfer failed! type=%i, status = %i virtio_9p_initslofVersion check failed, rc = %d Attach failed, rc = %d Walk failed, rc = %d Stat failed, rc = %d Open failed, rc = %d Read failed, rc = %d virtioscsi_initUnable to allocate virtio-net driver virtionet: Failed to allocate buffers! virtio-net: Receive buffer not big enough! virtionet: Packet too big! virtio_serial_initvirtio-serial: Failed to allocate buffers! virtio_serial_putchar failed! Error: %s 9P2000.uunknownusb_get_pipeusb_send_ctrlusb_transfer_bulkusb_setup_new_device%s: Failed ErrorDevice Error%s: alloc failed %d ohci_get_pipe_introhci_transfer_bulkohci_send_ctrlusb-ohci: Warning ED not aligned to 16byte boundary%s: alloc failed Timed out waiting for interrupt %x USB: Error TD null %p USB: Error %s %p usb-ohci: Not a bulk pipe. usb-ohci: buffer size not supported - %d %s: tds NULL recieved ED Halted %s: headp %08X tailp %08X next_td %08X attr %08X %s: timed out - failed Request: %02X OHCI: initializing usb-ohci: Unable to allocate memory usb-ohci: Unable to allocate/unaligned HCCA memory %p ** HCD Reset failed...usb-ohci: oops could not allocate intr_pipe Start removing device usb-ohci: unable to setup device on port %d ohci-hcdNOERRORCRCBITSTUFFINGDATATOGGLEMISMATCHSTALLDEVICENOTRESPONDINGPIDCHECKFAILUREUNEXPECTEDPIDDATAOVERRUNDATAUNDERRUNreservedBUFFEROVERRUNBUFFERUNDERRUNNOT ACCESSEDehci_exitehci_send_ctrlehci_transfer_bulk EHCI: Initializing usb-ehci: Unable to allocate memory usb-ehci: reset failed usb-ehci: Unable to allocate frame list usb-ehci: Unable to allocate interrupt queue head usb-ehci: Unable to allocate async queue head usb-ehci: unable to setup device on port %d %s: already called once usb-ehci: Not a control pipe. Error allocating qTDs. usb-ehci: control transfer timed out_ %s: handshake failed usb-ehci: Not a bulk pipe. usb-ehci: bulk transfer size too big usb-ehci: bulk transfer timed out_ ehci-hcdusb_slof_populate_new_devices" dev-keyb.fs" INCLUDEDs" dev-mouse.fs" INCLUDEDs" dev-storage.fs" INCLUDEDs" dev-hub.fs" INCLUDEDDevice not supported %06X %s: bulk reset failed USB Interface class -%x- Not supported usb_hid_kbd_init%s: unable to allocate keyboard buffer usb-hub: NULL usb-hub: unable to setup device on port %d xhci_get_pipeTRB_TYPE %d usb-xhci: allocation failed for interrupt endpoint usb-xhci: %s alloc_intr failed %p usb-xhci: allocation failed for bulk endpoint usb-xhci: bulk transfer size too big USB3 slot ID %d is too high (max is %d) XHCI: Initializing usb-xhci: Unable to allocate memory usb-xhci: 64 Byte context not supported usb-xhci: failed to initialize XHCI controller. xhci-hcdPowered-OFFPolling*** Disconnected ***DisabledLoopbackCompliancek****** Reset ************ Enabled ******ERROR @{[]}\~|ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()  _+{}||:"~<>?079.136428/*-+ 1234567890.|abcdefghijklmnopqrstuvwxyz1234567890  -=[]\\;'`,.//*-+ 1234567890.\free spaceCreating common NVRAM partition commonUnable to allocate veth driver veth: Failed to allocate memory ! veth: Error %ld registering interface ! veth: Dropping too big packet [%d bytes] veth: Error %ld sending packet ! Failed to read MAC address from EEPROM! 82547EI/GI Copper82547EI Mobile52546EB Copper, Dual Port82546EB Fiber, Dual Port82546GB Copper, Dual Port82546GB Fiber, Dual Port82546GB SerDes, Dual Port82545EM Copper82545EM Fiber82545GM Copper82545GM Fiber82545GM SerDes82544EI Copper82544GC Copper82541EI Copper82541EI Mobile82541GI Copper82541GI Mobile82541ER Copper82541PI82540EM Mobile82540EP Mobile82540EP Desktop82540EM DesktopE%04X: (net) TFTP: Received %s (%d KBytes) %03d Aborted Giving up after %d DHCP requests done v4 Requesting information via DHCP%s: v6ERROR: Unable to allocate memory Initializing NICCould not read MAC address Reading MAC address from device: %02x:%02x:%02x:%02x:%02x:%02x ERROR: Parameter string is too long.bootpdhcpipv6Could not get IP address Using IPv4 address: %d.%d.%d.%d Using IPv6 address: %s ARP request to TFTP server (%d.%d.%d.%d) failedCan't obtain TFTP server IP address Requesting file "%s" via TFTP from %d.%d.%d.%d Requesting file "%s" via TFTP from Not enough memory for pxelinux config file buffer!system-id/Warning: UUID property is too short.No valid entries in pxelinux config file. Not enough space for loading the initrd!linux,initrd-startlinux,initrd-endbootargsCould not initialize network device ping device-path:[device-args,]server-ip,[client-ip[\nn]],[gateway-ip][,timeout] Reading MAC address from device: E3000: Could not read MAC address E3006: Could not initialize network device %02x:%02x:%02x:%02x:%02x:%02x DHCP: Could not get ip address Own IP address: %d.%d.%d.%d Netmask : %d.%d.%d.%d Ping to %d.%d.%d.%d success pxelinux_load_parse_cfg TFTP: Received %s (%d bytes) TFTP error: %s Failed to parse this line: %s defaultlabelkernelinitrdappendCommand '%s' is not supported. Error: pxelinux prefix is too long!Error: The bootfile string is too long for deriving the pxelinux.cfg file name from it.pxelinux.cfg/Trying pxelinux.cfg files...Error: pxelinux.cfg prefix + filename too long!01-%02x-%02x-%02x-%02x-%02x-%02x%02X%02X%02X%02XERROR: Assertion 'rc < cfgsize' failed! (function %s, file pxelinux.c, line %i) :////: ERROR: Bad URL! ERROR: Bad host name! ERROR: Can't resolve domain name (DNS server is not presented)! Giving up after %d DNS requests Requesting IP address via BOOTP: %02d Giving up after %d bootp requests bladone %d KBytesblksizeoctet Receiving data: Repeating TFTP read request... Lost ACK packets: %d unable to allocate memory, parsing failed tftp:// tftp missing in %s missing ] in %s missing filename in %s wrong format IPV6 address in %s missing . seperator in %s missing domain in %s DNS failed for IPV6 net unreachablehost unreachableprotocol unreachableport unreachablefragmentation needed and DF setsource route failedunknown TFTP errorTFTP buffer of %d bytes is too small for %sfile not found: %sTFTP access violationillegal TFTP operationunknown TFTP transfer IDno such TFTP userTFTP blocksize negotiation failedfile exceeds maximum TFTP transfer sizeICMP ERROR "%s"TFTP error occurred after %d bad packets receivedTFTP error occurred after missing %d responsesTFTP error missing block %d, expected block was %d::::1%s%x%02x%s%x00:0:0:::0send_router_solicitation: Out of memory send_neighbour_solicitation: Out of memory send_neighbour_advertisement: Out of memory key?key%s%ifind-aliasOut of memory in find_aliascdromdisknetNo available boot devices! Select boot device (or press '0' to abort):%c) %6s : %s 0x ppHHEREMpNpCLIENT-ENTRY-POINTMyNROMFS-LOOKUP-ENTRYMpPNICEINITJ8hphH h PPP͠ĘhPH-EVALUATEJ8&xĀưưh-&HʘŨĀPP(8ĀP8PN*0  FORTH-WORDLISTI LASTWORDJ8HBPITIBML`POCKETSMxEREGSL˜CIREGSL°CISTACKL\ COMP-BUFFERL  PAFLOF-STARTK HEAP-STARTK(HEAP-ENDKlH FDT-STARTK,h ROMFS-BASEJÈ EPAPR-MAGICJèEPAPR-IMA-SIZEJlBRANCHI0BRANCHI`@ BREAKPOINTI0 LITH@DOTICKHXDUPHpOVERHPĈPICKHĠDROPGĸSWAPG>RG\R>GR@FRPICKET0DEPTHFHDEPTH!FD`RDEPTHExRDEPTH!EŐ+EŰ-D*DLSHIFTDDRSHIFTDASHIFTC(ANDCx@ORC4XXORBp@Bƈ!BƠC@BLƸC!BW@AW!AL@AlL!A00X@@HX!@` UNALIGNED-W@@xx UNALIGNED-W!@4ǘ UNALIGNED-L@?Ǹ UNALIGNED-L!?<?(U<:0<:(=:h@0=:0XDODO9pDO?DO9hȈDOLOOP9ȠDO+LOOP8ȸDOLEAVE<DO?LEAVE;EXIT;h SEMICOLON;80EXECUTE=PMOVE<<pRMOVE6pɈMRMOVE5ɠRFILL7ɸZCOUNT4 HASH-SIZEMHASH3 CLEAN-HASH4( HASH-TABLE4p0-1Mh0Mʈ1Mʨ2M3M4M8M(H#10MHH#20M hH#FFMˈH#FFFFM˨ H#FFFFFFFFMD#10M /CM/WM0/LMP/XMp/NM̐CELLM̰/C*J8 H/W*J8@H/L*J8`H0/X*J8̀H`/N*J8̠H͐CA+J8HWA+J8HLA+J8@H XA+J8pHPNA+J8͠H΀CA1+J8 HΰWA1+J8@HLA1+J8`HXA1+J8̀H@NA1+J8̠HpCHAR+J8HϠCELL+J8πHCHAR-J8 HCELL-J8̠H CHARSJ8HPCELLSJ8͠HxCHARS+J8HРCELLS+J8ΐHDOTOJ8ĀƘưHSLITERALJ8ĀĀPPHH?DUPJ8ĀĀHTUCKJ8ĘH2DUPJ8ĘĘH03DUPJ8İİİH`2OVERJ8İİHҰ2DROPJ8H3DROPJ8H NIPJ8HXCLEARJ8ʘpHӈROTJ8HӸ-ROTJ8H2SWAPJ8H82ROTJ8HHHxROLLJ8Ā0ʸ0ʸH-ROLLJ8ĀHʸ0ʸHՀ2>RJ8HP2R>J8H֠2R@J8(ĘH?PICK5$P2*J8ʸHhU2/J8ʸ Hט2/J8ʸ8H<<J8H>>J8 H >>AJ88HHINVERTJ8xƀHpNOTJ8؀HؠTRUEMFALSEM>J8HU>J8 H8<=J8hHh<>J8PhH٘>=J8hH0<=J8ʘxH0<>J8ʘ٨H(0>J8ʘHX0>=J8ʘHڈU<=J8HhHڸU>=J8 hHWITHINJ8Ā((HBETWEENJ8ʸ(H۰D2*J8xĘ8xHUD2/J8ר(P?hרHHD2/J8ר(P?hHܰNEGATEJ8ʘHABSJ8Ā8(HPMAXJ8@HݘUMAXJ8@ HMINJ8@H8U*J8Hވ1+J8ʸHް1-J8ʸH2+J8H2-J8H@EVENJ8xPHpBOUNDSJ8ĘHߨS>DJ8Ā8HDNEGATEJ8؀(ĀhHDABSJ8Ā8(HxM+J8ĀĀ HD+J8H8D-J8(HHx*'J8Ā8(HUM*J8ʘP@ʘȀȰH M*J8@ƀ``08(H/'J8Ā8Ę(h0ʸh(HUM/MODJ8P@ʘȀ(ȰHSM/REMJ8Ę(`8(8 ((H8FM/MODJ8Ā@ƀ8HĘ8P0(HU/MODJ8ʘH/MODJ8H/J8hH8MODJ8Hh*/MODJ8H*/J8hHWBSPLITJ8Ā˘P8 HLWSPLITJ8Ā˸PX H`XLSPLITJ8ĀPx HLBSPLITJ8x  HXWSPLITJ8xxH`XBSPLITJ8((HBWJOINJ88hHWLJOINJ8XhH8BLJOINJ8HHpWBFLIPJ8 HLWFLIPJ8xHHLXJOINJ8xhH(XLFLIPJ88H`LBFLIPJ8(HHWXJOINJ8HH8HXWFLIPJ8xHH(BXJOINJ88HpXBFLIPJ88HALIGNEDJ8̠̠(PHIJ8(HXJJ8(HUNLOOPJ8H+!J8ƘưHPCOMP7OFFJ8ưHONJ8ưHINNx TERMINALJ8ppƘưʘH@BLM BELLMBSMCARRETM LINEFEEDM 8EMITI`CRITYPEJ8߸Ș(hpȰHLL-CRJ8(pPpHSPACEJ8pH@SPACESJ8ʘȘPȰHpCOUNTJ8ĀϰHPACKJ8ĀĀ(ɀHUPCJ8ĀPaPzP HhLCCJ8ĀPAPZP HKEYIXKEY?IxACCEPTISPANNxEXPECTJ8ưHREFILLJ8h8ʘ0ư(xP(PeHBASENxDECIMALJ8ưHHEXJ8XưH8OCTALJ88ưHpPADJ8@PHTODIGITJ8ĀP P'P0HMU/MODJ8ĀHp<#J8ĀưHHOLDJ8ĀƘưHSIGNJ88P-Hh#J8ƘH#SJ8@hH#>J8ĀƘH`(.)J8Ā`ʘxpHU#J8ƘHU#SJ8(ĀHhU#>J8ĀƘH(U.)J8xH.J8PH@S.J8PHxU.J8PH.RJ8@(ĘHU.RJ8@(ĘHh.DJ8ƘPưH.HJ8ƘHPưHP.SJ8XĀ8(ʘȘ@XhİPȰH?J8ƘPHXDIGITJ8ĘxĀPAPZPP0Āʘ( hH>NUMBERJ8Āh(ĘƘƘޘƘ0ʘHϰH$NUMBERJ8Āh (ĀP-PĀxϰĀh((ʘʘhh8((HALLOTJ8@@H,J8@ư̠HC,J8@ H(W,J8@@HhL,J8@@`HX,J8@p̀HALIGNJ8@̠P ʘ8H (PLACEJ8@ϰ`߸ȘHĀhϰʸ`H STRING,J8@Ę` H HNOOPJ8HCURRENTM LASTJ8 H SEARCH-ORDERNx CONTEXTM 8 LINK>NAMEJ8H NAME>J8ϰĀаH LINK>J8  H ` NAME>STRINGJ8ϰH LATESTNx (REVEAL)I HEADERJ8 8@ Ƙ ưʘ8 ` 8H REVEALJ8 Ƙ    Ƙ ưH STRING=CI5 (FIND)I((FIND))J8Āx@(  (Ƙp0H0 (FIND-ORDER)J8 Ā 0@(ƘƘ (hh(0@0ʘH($FIND)J8Ā0 Ā H$FINDJ8@0hhHx 'IMMEDIATEM IMMEDIATE?J8P8H IMMEDIATEJ8 ƘĀhHXFINDCHARJ8ʘȘĘhĘĀPxP0hhh(Ȱ@HPARSEJ80ƘƘ0Ƙ@0hĀʸĀ0`HSKIPWSJ8ƘĀ0ƘpĘ0Ƙx(ʸ0``H PARSE-WORDJ8H WHICHPOCKETNxPOCKETJ8ƘPƘʸĀPPʘưHWORDJ8(Ā(߸ĀHȘ8ϰhĘȰHCHARJ8H(J8P)H\J80Ƙ0ưPHSTATENxx[J8H]J8PưH?COMPJ8Ƙ(PzHCOMPILE,J8Hh:J8 hJ8H:NONAMEJ8 8@hJ8H;J8hH H@C"J8P"h`Ā8߸Ș(h8Ȱ 8HS"J8Ƙ(h(P"Ā(ĀɀH@Z"J8P@ʘH."J8Ƙ(Ph(P"H`.(J8P)HCOMPILEJ8ĀƘH(THERENx+COMPJ8Ƙʸ`(@ư@@J8H-COMPJ8x`Ƙ(@(Ƙ@hH@ RESOLVE-ORIGJ8@ĘưHAHEADJ8h@ʘH8IFJ8h@ʘHTHENJ8PHELSEJ8h@ʘH CASEJ8ʘHENDCASEJ8h(PHOFJ8hĘhPhH HENDOFJ80H RESOLVE-DESTJ8@H!BEGINJ8@H!`AGAINJ8h!0PH!UNTILJ8h!0PH!WHILEJ8H"0REPEATJ8!H"hLEAVESNx" RESOLVE-LOOPJ8"ƘPĀƘ@Ęư@"ưH"DOJ8"Ƙ@hȀʘ"ưH#?DOJ8"ƘhȘ@@"ưʘH#LOOPJ8hȰ"PH$x+LOOPJ8h"PH$LEAVEJ8h"Ƙ@"ưH%?LEAVEJ8h"Ƙ@"ưH% SAVE-SOURCEJ8ƘƘ0ƘH%RESTORE-SOURCEJ80ưưưH&OK-STRok'H ABORTED-STRAborted'` EXCEPTION-STR Exception #' UNKNOWN-STRUndefined word'HW-EXCEPTION-HANDLERI' SHOW-STACK?M( SHOWSTACKJ8x(H(( NOSHOWSTACKJ8ʘ(H(h PRINT-STACKJ8((H(PRINT-EXCEPTIONJ8ĀPP8h'(ĀPP('H) PRINT-STATUSJ8PĀh((h'X8ĀxP0h'xPĀPP8Ƙ)0H) COMPILE-WORDJ8@P0 hhh((@ PhPH+8INTERPRET-WORDJ8@(hhh(@ PH,8 INTERPRETJ8ʘ0ưĀPƘ+P,PHEVALJ8H-DOABORT"J8(ưPH-ABORT"J8h-H.P UNDEFINED-STRundefined word .SET-UNDEFINED-WORDJ8(h.Ā(ɀ(ĀĀ((ɀH.'J8h .-H/QUITJ8ʘŨXXPP>pP PPh-Ā*xHH0MAP-FILEI0 UNMAP-FILEI1 WRITE-FILEI18INCLUDEDJ81@߸Ș(((@PhĀX1(H1`INCLUDEJ81xH2$CREATEJ8 hIh  H2CREATEJ82H3(DODOES>J8 Ƙ pưH3XDOES>J8h3pH3CONSTANTJ8 hM H3VALUEJ8 hM H4PVARIABLEJ8 hNxʘ H4BUFFER:J8 hN@ H5DEFERJ8 hIh@ H5pALIASJ8 hN0/ H5STRUCTJ8ʘH68 END-STRUCTJ8H6`FIELDJ8 hMĘ H6LITERALJ8hPH6 [COMPILE]J8/H7@POSTPONEJ8@h .-0h0hhhH7x[CHAR]J87H8P[']J8/hhH8FINDJ8ĀH0(((H8TOJ8/Ƙ(h(ưH9hBEHAVIORJ8ƘH9>BODYJ8ЈH: BODY>J8ЈH:X RECURSIVEJ8 H:RECURSEJ8 Ƙ pH:d#J8ƘưH;h#J8ƘHưH;po#J8ƘưH; hv-putchar3<@ hv-getchar3D<` hv-haschar3< hv-reg-crq2< hv-free-crq2t< hv-send-crq2,< hv-put-tce1=check-and-patch-sc1.`= hv-rtas-get-=HRB@1=hRB!1H=RW@1 =RW!0=RL@0=RL!00=RX@/=RX!/>hv-logical-memop/@>(hv-cas.>P hv-update-dt. >hget-print-version.>virtio-setup-vd->virtio-vring-size-P>virtio-get-qsize-?virtio-get-config,?(virtio-set-qaddr,`?Pvirtio-blk-init,$?xvirtio-blk-shutdown+?virtio-blk-read+?virtio-blk-write+ ?virtio-scsi-init)@virtio-scsi-shutdown)@@virtio-scsi-send)0@hvirtio-fs-init*@virtio-fs-shutdown*x@virtio-fs-load*(@virtio-net-open(@virtio-net-close(A virtio-net-read(LAHvirtio-net-write|Apvirtio-serial-init@Avirtio-serial-shutdownAvirtio-serial-putcharAvirtio-serial-getchar|Bvirtio-serial-haschar@B8USB-OHCI-REGISTERB`USB-EHCI-REGISTERBUSB-XHCI-REGISTERB USB-HCD-INITB USB-HCD-EXIT\B USB-HID-INIT C USB-HID-EXITC8 USB-READ-KEYBCXUSB-KEY-AVAILABLElCx USB-HUB-INIT0C USB-MSC-INITC USB-MSC-EXITCUSB-TRANSFER-CTRLdDUSB-TRANSFER-BULKD( bootmsg-cpDPbootmsg-warningXDp bootmsg-errorDbootmsg-debugcpDbootmsg-setleveltDbootmsg-nvupdateEbootmsg-checklevelE0 ELF-LOAD-FILEEXELF-LOAD-FILE-TO-ADDR,Exnvram-c@Envram-c!"Envram-w@Envram-w!#lFnvram-l@xF nvram-l!!F@nvram-x@#4F`nvram-x!"4Finternal-reset-nvram TF nvram-debug F wipe-nvram 0Fget-nvram-partition!Gget-named-nvram-partition"xG0new-nvram-partition G`increase-nvram-partition xGerase-nvram-partition%Gdelete-nvram-partition%8Ginternal-get-envpHinternal-add-envH0internal-del-env`HXinternal-set-envHinternal-nvram-init$Hget-nvram-base$Hget-nvram-size$XHget-flash-base$ Iget-flash-size#I0 get-mbx-base#IP LIBVETH-OPEN'lIp LIBVETH-CLOSE'0I LIBVETH-READ'I LIBVETH-WRITE&IE1K-OPEN&I E1K-CLOSE&TJE1K-READ&J0 E1K-WRITE0JP E1K-MAC-SETUPJpNET-LOAD4JNET-PINGJ boot-menuJHID0!tJHID0@<KHID1!K HID1@K8HID4!KPHID4@LKhHID5!KHID5@KMSR@lKMSR!KSDR1@KSDR1!4KPVR@LPIR@L(TBL@TL@TBU@LXDABR@LpDABR!LHIOR@<LHIOR!tLSPRG0@LSPRG0!LSPRG1@\MSPRG1!MSPRG2@ M0SPRG2!$MHSPRG3@ |M`SPRG3! MxHSPRG0@ MHSPRG0! DMHSPRG1@ MHSPRG1! MDEC@ NDEC! 8N(MMCR0! \N@PMC1@ NXICBI P JUMP-CLIENT NCLIENTINTERFACEI.WRITE-LOG-BYTE-ENTRYMvNWRITE-LOG-BYTE-ENTRYJ8NƘHOCALL-C OH START-RTAS DO` FLUSHCACHE pOBM-ALLOCATOR-INIT OBM-ALLOC lOBM-FREE OCRASH PDAARNxP DUMBERJ8P0ƘPP0`HP@BOOT-EXCEPTION-HANDLERIhex ' ll-cr to cr get-flash-base VALUE flash-addr get-nvram-base CONSTANT nvram-base get-nvram-size CONSTANT nvram-size 0 CONSTANT default-hvtermno 4096 CONSTANT disp-size CREATE prevga-disp-buf 4096 allot 0 value disp-ptr true value store-prevga? : store-to-disp-buffer ( ch -- ) prevga-disp-buf disp-ptr disp-size MOD + c! disp-ptr 1 + to disp-ptr ; : hvterm-emit store-prevga? IF dup store-to-disp-buffer THEN default-hvtermno SWAP hv-putchar ; : hvterm-key? default-hvtermno hv-haschar ; : hvterm-key BEGIN hvterm-key? UNTIL default-hvtermno hv-getchar ; ' hvterm-emit to emit ' hvterm-key to key ' hvterm-key? to key? : serial-emit hvterm-emit ; : serial-key? hvterm-key? ; : serial-key hvterm-key ; clean-hash : hash-find ( str len head -- 0 | link ) >r 2dup 2dup hash ( str len str len hash R: head ) dup >r @ dup ( str len str len *hash *hash R: head hash ) IF ( str len str len *hash R: head hash ) link>name name>string string=ci ( str len true|false R: head hash ) dup 0= IF THEN ELSE nip nip ( str len 0 R: head hash ) THEN IF \ hash found 2drop r> @ r> drop ( *hash R: ) exit THEN \ hash not found r> r> swap >r ((find)) ( str len head R: hash=0 ) dup IF dup r> ! ( link R: ) ELSE r> drop ( 0 R: ) THEN ; : hash-reveal hash off ; ' hash-reveal to (reveal) ' hash-find to (find) : >name ( xt -- nfa ) \ note: still has the "immediate" field! BEGIN char- dup c@ UNTIL ( @lastchar ) dup dup aligned - cell+ char- ( @lastchar lenmodcell ) dup >r - BEGIN dup c@ r@ <> WHILE cell- r> cell+ >r REPEAT r> drop char- ; VARIABLE mask -1 mask ! : default-hw-exception s" Exception #" type . ; ' default-hw-exception to hw-exception-handler : diagnostic-mode? false ; \ 2B DOTICK'D later in envvar.fs : memory-test-suite ( addr len -- fail? ) diagnostic-mode? IF ." Memory test mask value: " mask @ . cr ." No memory test suite currently implemented! " cr THEN false ; : 0.r 0 swap <# 0 ?DO # LOOP #> type ; : 2log ( n -- lb{n} ) 8 cells 0 DO 1 rshift dup 0= IF drop i LEAVE THEN LOOP ; : log2 ( n -- log2-n ) 1- 2log 1+ ; CREATE $catpad 400 allot : $cat ( str1 len1 str2 len2 -- str3 len3 ) >r >r dup >r $catpad swap move r> dup $catpad + r> swap r@ move r> + $catpad swap ; : $cat-space ( str2 len2 str1 len1 -- "str1 str2" len1+len2+1 ) 2dup + bl swap c! 1+ 2swap $cat ; : $cathex ( str len val -- str len' ) (u.) $cat ; : 2CONSTANT CREATE , , DOES> [ here ] 2@ ; CONSTANT <2constant> : $2CONSTANT $CREATE , , DOES> 2@ ; : 2VARIABLE CREATE 0 , 0 , DOES> ; : (is-user-word) ( name-str name-len xt -- ) -rot $CREATE , DOES> @ execute ; : zplace ( str len buf -- ) 2dup + 0 swap c! swap move ; : rzplace ( str len buf -- ) 2dup + 0 swap rb! swap rmove ; : strdup ( str len -- dupstr len ) here over allot swap 2dup 2>r move 2r> ; : str= ( str1 len1 str2 len2 -- equal? ) rot over <> IF 3drop false ELSE comp 0= THEN ; : from-cstring ( addr - len ) dup dup BEGIN c@ 0 <> WHILE 1 + dup REPEAT swap - ; : test-string ( param len -- true | false ) 0 ?DO dup i + c@ \ Get character / byte at current index dup 20 < swap 7e > OR IF \ Is it out of range 32 to 126 (=ASCII) drop FALSE UNLOOP EXIT \ FALSE means: No ASCII string THEN LOOP drop TRUE \ Only ASCII found --> it is a string ; : #aligned ( adr alignment -- adr' ) negate swap negate and negate ; : #join ( lo hi #bits -- x ) lshift or ; : #split ( x #bits -- lo hi ) 2dup rshift dup >r swap lshift xor r> ; : /string ( str len u -- str' len' ) >r swap r@ chars + swap r> - ; : skip ( str len c -- str' len' ) >r BEGIN dup WHILE over c@ r@ = WHILE 1 /string REPEAT THEN r> drop ; : scan ( str len c -- str' len' ) >r BEGIN dup WHILE over c@ r@ <> WHILE 1 /string REPEAT THEN r> drop ; : split ( str len char -- left len right len ) >r 2dup r> findchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; : rfindchar ( str len char -- offs true | false ) swap 1 - 0 swap do over i + c@ over dup bl = if <= else = then if 2drop i dup dup leave then -1 +loop = ; : rsplit ( str len char -- left len right len ) >r 2dup r> rfindchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; : left-parse-string ( str len char -- R-str R-len L-str L-len ) split 2swap ; : replace-char ( str len chout chin -- ) >r -rot BEGIN 2dup 4 pick findchar WHILE tuck - -rot + r@ over c! swap REPEAT r> 2drop 2drop ; : \-to-/ ( str len -- str' len ) strdup 2dup [char] \ [char] / replace-char ; : isdigit ( char -- true | false ) 30 39 between ; : $dh-number ( addr len -- true | number false ) base @ >r decimal dup 2 > IF over dup c@ [char] 0 = over 1 + c@ 20 or [char] x = AND IF hex 2 + swap 2 - rot THEN drop THEN $number r> base ! ; : // dup >r 1- + r> / ; \ division, round up : c@+ ( adr -- c adr' ) dup c@ swap char+ ; : 2c@ ( adr -- c1 c2 ) c@+ c@ ; : 4c@ ( adr -- c1 c2 c3 c4 ) c@+ c@+ c@+ c@ ; : 8c@ ( adr -- c1 c2 c3 c4 c5 c6 c7 c8 ) c@+ c@+ c@+ c@+ c@+ c@+ c@+ c@ ; : 4dup ( n1 n2 n3 n4 -- n1 n2 n3 n4 n1 n2 n3 n4 ) 2over 2over ; : 4drop ( n1 n2 n3 n4 -- ) 2drop 2drop ; : 5dup ( 1 2 3 4 5 -- 1 2 3 4 5 1 2 3 4 5 ) 4 pick 4 pick 4 pick 4 pick 4 pick ; : 5drop 4drop drop ; : 5nip nip nip nip nip nip ; : 6dup ( 1 2 3 4 5 6 -- 1 2 3 4 5 6 1 2 3 4 5 6 ) 5 pick 5 pick 5 pick 5 pick 5 pick 5 pick ; : signed ( n1 -- n2 ) dup 80000000 and IF FFFFFFFF00000000 or THEN ; : r dup r> swap c! 1+ 2 ( dst-adr+1 2 ) ELSE drop 1 ( dst-adr 1 ) THEN +LOOP ; : add-specialchar ( dst-adr special -- dst-adr' ) over c! 1+ ( dst-adr' ) 1 >in +! \ advance input-index ; : parse-" ( dst-adr -- dst-adr' ) [char] " parse dup 3 pick + >r ( dst-adr str len R: dst-adr' ) >r swap r> move r> ( dst-adr' ) ; : (") ( dst-adr -- dst-adr' ) begin ( dst-adr ) parse-" ( dst-adr' ) >in @ dup span @ >= IF ( dst-adr' >in-@ ) drop EXIT THEN ib + c@ CASE [char] ( OF parse-hexstring ENDOF [char] " OF [char] " add-specialchar ENDOF dup OF EXIT ENDOF ENDCASE again ; CREATE "pad 100 allot : " ( [text<">< >] -- text-str text-len ) state @ IF \ compile sliteral, pstr into dict "pad dup (") over - ( str len ) ['] sliteral compile, dup c, ( str len ) bounds ?DO i c@ c, LOOP align ['] count compile, ELSE pocket dup (") over - \ Interpretation, put string THEN \ in temp buffer ; immediate : (cr carret emit ; : $forget ( str len -- ) 2dup last @ ( str len str len last-bc ) BEGIN dup >r ( str len str len last-bc R: last-bc ) cell+ char+ count ( str len str len found-str found-len R: last-bc ) string=ci IF ( str len R: last-bc ) r> @ last ! 2drop clean-hash EXIT ( -- ) THEN 2dup r> @ dup 0= ( str len str len next-bc next-bc ) UNTIL drop 2drop 2drop \ clean hash table ; : forget ( "old-name<>" -- ) parse-word $forget ; : linked ( var -- ) here over @ , swap ! ; HEX VARIABLE wordlists forth-wordlist wordlists ! : wordlist ( -- wid ) here wordlists linked 0 , ; 10 CONSTANT max-in-search-order \ should define elsewhere : also ( -- ) clean-hash context dup cell+ dup to context >r @ r> ! ; : previous ( -- ) clean-hash context cell- to context ; : only ( -- ) clean-hash search-order to context ( minimal-wordlist search-order ! ) ; : seal ( -- ) clean-hash context @ search-order dup to context ! ; : get-order ( -- wid_n .. wid_1 n ) context >r search-order BEGIN dup r@ u<= WHILE dup @ swap cell+ REPEAT r> drop search-order - cell / ; : set-order ( wid_n .. wid_1 n -- ) \ XXX: special cases for 0, -1 clean-hash 1- cells search-order + dup to context BEGIN dup search-order u>= WHILE dup >r ! r> cell- REPEAT drop ; : get-current ( -- wid ) current ; : set-current ( wid -- ) to current ; : definitions ( -- ) context @ set-current ; : VOCABULARY ( C: "name" -- ) ( -- ) CREATE wordlist drop DOES> clean-hash context ! ; : FORTH ( -- ) clean-hash forth-wordlist context ! ; : .voc ( wid -- ) \ display name for wid \ needs work ( body> or something like that ) dup cell- @ ['] vocabulary ['] forth within IF 2 cells - >name name>string type ELSE u. THEN space ; : vocs ( -- ) \ display all wordlist names cr wordlists BEGIN @ dup WHILE dup .voc REPEAT drop ; : order ( -- ) cr ." context: " get-order 0 ?DO .voc LOOP cr ." current: " get-current .voc ; : voc-find ( wid -- 0 | link ) clean-hash cell+ @ (find) clean-hash ; : (function) ; defer (defer) 0 value (value) 0 constant (constant) variable (variable) create (create) alias (alias) (function) cell buffer: (buffer:) ' (function) @ \ ( ) ' (function) cell + @ \ ( ... ) ' (defer) @ \ ( ... ) ' (value) @ \ ( ... ) ' (constant) @ \ ( ... ) ' (variable) @ \ ( ... ) ' (create) @ \ ( ... ) ' (alias) @ \ ( ... ) ' (buffer:) @ \ ( ... ) forget (function) constant constant constant constant constant constant constant constant constant ' lit constant ' sliteral constant ' 0branch constant <0branch> ' branch constant ' doloop constant ' dotick constant ' doto constant ' do?do constant ' do+loop constant ' do constant ' exit constant ' doleave constant ' do?leave constant 500 CONSTANT AVAILABLE-SIZE 4000 CONSTANT MIN-RAM-RESERVE \ prevent from using first pages : MIN-RAM-SIZE \ Initially available memory size epapr-ima-size IF epapr-ima-size ELSE 20000000 \ assumed minimal memory size THEN ; MIN-RAM-SIZE CONSTANT MIN-RAM-SIZE STRUCT cell field available>address cell field available>size CONSTANT /available CREATE available AVAILABLE-SIZE /available * allot available AVAILABLE-SIZE /available * erase VARIABLE mem-pre-released 0 mem-pre-released ! : available>size@ available>size @ ; : available>address@ available>address @ ; : available>size! available>size ! ; : available>address! available>address ! ; : available! ( addr size available-ptr -- ) dup -rot available>size! available>address! ; : available@ ( available-ptr -- addr size ) dup available>address@ swap available>size@ ; : (?available-segment<) ( start1 end1 start2 end2 -- true/false ) drop < nip ; : (?available-segment>) ( start1 end1 start2 end2 -- true/false ) -rot 2drop > ; : (?available-segment-#) ( start1 end1 start2 end2 -- true/false ) 2dup 5 roll -rot ( e1 s2 e2 s1 s2 e2 ) between >r between r> and not ; : (find-available) ( addr addr+size-1 a-ptr a-size -- a-ptr' found ) ?dup 0= IF -rot 2drop false EXIT THEN \ Not Found 2dup 2/ dup >r /available * + dup available>size@ 0= IF 2drop r> RECURSE EXIT THEN dup >r available@ over + 1- 2>r 2swap 2dup 2r@ (?available-segment>) IF 2swap 2r> 2drop r> /available + -rot r> - 1- nip RECURSE EXIT \ Look Right THEN 2dup 2r@ (?available-segment<) IF 2swap 2r> 2drop r> 2drop r> RECURSE EXIT \ Look Left THEN 2dup 2r@ (?available-segment-#) IF \ Conflict - segments overlap 2r> 2r> 3drop 3drop 2drop 1212 throw THEN 2r> 3drop 3drop r> r> drop ( a-ptr' -- ) dup available>size@ 0<> ( a-ptr' found -- ) ; : (find-available) ( addr size -- seg-ptr found ) over + 1- available AVAILABLE-SIZE ['] (find-available) catch IF 2drop 2drop 0 false THEN ; : dump-available ( available-ptr -- ) cr dup available - /available / AVAILABLE-SIZE swap - 0 ?DO dup available@ ?dup 0= IF 2drop UNLOOP EXIT THEN swap . . cr /available + LOOP dup ; : .available available dump-available ; : (drop-available) ( available-ptr -- ) dup available - /available / \ current element index AVAILABLE-SIZE swap - \ # of remaining elements ( first nelements ) 1- 0 ?DO dup /available + dup available@ ( current next next>address next>size ) ?dup 0= IF 2drop LEAVE \ NULL element - goto last copy THEN 3 roll available! ( next ) LOOP 0 0 rot available! ; : (stick-to-previous-available) ( addr size available-ptr -- naddr nsize nptr success ) dup available = IF false EXIT \ This was the first available segment THEN dup /available - dup available@ + 4 pick = IF nip \ Drop available-ptr since we are going to previous one rot drop \ Drop start addr, we take the previous one dup available@ 3 roll + rot true ELSE drop false THEN ; : (insert-available) ( available-ptr -- available-ptr ) dup \ current element dup available - /available / \ current element index AVAILABLE-SIZE swap - \ # of remaining elements dup 0<= 3 pick available>size@ 0= or IF drop drop EXIT THEN over available@ rot ( first first/=current/ first>address first>size nelements ) 1- 0 ?DO 2>r /available + dup available@ 2r> 4 pick available! dup 0= IF rot /available + available! UNLOOP EXIT THEN LOOP ( first next/=last/ last[0]>address last[0]>size ) ?dup 0<> IF cr ." release error: available map overflow" cr ." Dumping available property" .available cr ." No space for one before last entry:" cr swap . . cr ." Dying ..." cr 123 throw THEN 2drop ; : insert-available ( addr size available-ptr -- addr size available-ptr ) dup available>address@ 0<> IF dup available>address@ rot dup -rot - 3 pick = IF \ if (available>address@ - size == addr) over available>size@ + swap (stick-to-previous-available) IF dup /available + (drop-available) THEN ELSE swap (stick-to-previous-available) not IF (insert-available) THEN THEN ELSE (stick-to-previous-available) drop THEN ; defer release : drop-available ( addr size available-ptr -- addr ) dup >r available@ over 4 pick swap - ?dup 0<> IF dup 3 roll swap r> available! - over - ?dup 0= IF drop ELSE swap 2 pick + swap release THEN ELSE nip ( req_addr req_size segment_size ) over - ?dup 0= IF drop r> (drop-available) ELSE -rot over + rot r> available! THEN THEN ; : pwr2roundup ( value -- pwr2value ) dup CASE 0 OF EXIT ENDOF 1 OF EXIT ENDOF ENDCASE dup 1 DO drop i dup +LOOP dup + ; : (claim-best-fit) ( len align -- len base ) pwr2roundup 1- -1 -1 available AVAILABLE-SIZE /available * + available DO i \ Must be saved now, before we use Return stack -rot >r >r swap >r available@ ?dup 0= IF drop r> r> r> LEAVE THEN \ EOL 2 pick - dup 0< IF 2drop \ Can't Fit: Too Small ELSE dup 2 pick r@ and - 0< IF 2drop \ Can't Fit When Aligned ELSE r> -rot dup r@ U< IF 2r> 2drop swap 2 pick + 2 pick invert and >r >r >r ELSE 2drop >r THEN THEN THEN r> r> r> /available +LOOP -rot 2drop ( len best-fit-base/or -1 if none found/ ) ; : (adjust-release0) ( 0 size -- addr' size' ) 2dup MIN-RAM-SIZE dup 3 roll + -rot - dup 0< IF 2drop ELSE 2swap 2drop 0 mem-pre-released ! THEN ; : claim ( [ addr ] len align -- base ) ?dup 0<> IF (claim-best-fit) dup -1 = IF 2drop cr ." claim error : aligned allocation failed" cr ." available:" cr .available 321 throw EXIT THEN swap THEN 2dup (find-available) not IF drop 2drop 321 throw EXIT THEN ( req_addr req_size available-ptr ) drop-available ; : .release ( addr len -- ) over 0= mem-pre-released @ and IF (adjust-release0) THEN 2dup (find-available) IF drop swap cr ." release error: region " . ." , " . ." already released" cr ELSE ?dup 0= IF swap cr ." release error: Bad/conflicting region " . ." , " . ." or available list full " cr ELSE ( addr size available-ptr ) insert-available ( addr size available-ptr ) available! THEN THEN ; ' .release to release 0 MIN-RAM-SIZE release 1 mem-pre-released ! 0 MIN-RAM-RESERVE 0 ' claim CATCH IF ." claim failed!" cr 2drop THEN drop paflof-start ffff not and 1f00000 0 ' claim CATCH IF ." claim failed!" cr 2drop THEN drop heap-end heap-start - log2 1+ CONSTANT (max-heads#) CREATE heads (max-heads#) cells allot heads (max-heads#) cells erase : size>head ( size -- headptr ) log2 3 max cells heads + ; : alloc-mem ( len -- a-addr ) dup 0= IF EXIT THEN 1 over log2 3 max ( len 1 log_len ) dup (max-heads#) >= IF cr ." Out of internal memory." cr 3drop 0 EXIT THEN lshift >r ( len R: 1<head dup @ IF dup @ dup >r @ swap ! r> r> drop EXIT THEN ( headptr R: 1< 2drop 2drop 0 EXIT THEN r> + >r 0 over ! swap ! r> ; : free-mem ( a-addr len -- ) dup 0= IF 2drop EXIT THEN size>head 2dup @ swap ! ! ; : #links ( a -- n ) @ 0 BEGIN over WHILE 1+ swap @ swap REPEAT nip ; : .free ( -- ) 0 (max-heads#) 0 DO heads i cells + #links dup IF cr dup . ." * " 1 i lshift dup . ." = " * dup . THEN + LOOP cr ." Total " . ; heap-start heap-end heap-start - free-mem false VALUE debug-find-component? VARIABLE device-tree VARIABLE current-node : get-node current-node @ dup 0= ABORT" No active device tree node" ; STRUCT cell FIELD node>peer cell FIELD node>parent cell FIELD node>child cell FIELD node>properties \ points to wid (grep wid>names) cell FIELD node>words cell FIELD node>instance-template cell FIELD node>instance-size cell FIELD node>space? cell FIELD node>space cell FIELD node>addr1 cell FIELD node>addr2 cell FIELD node>addr3 END-STRUCT : find-method ( str len phandle -- false | xt true ) node>words @ voc-find dup IF link> true THEN ; 0 VALUE my-self 400 CONSTANT max-instance-size STRUCT /n FIELD instance>node /n FIELD instance>parent /n FIELD instance>args /n FIELD instance>args-len /n FIELD instance>size /n FIELD instance>#units /n FIELD instance>unit1 \ For instance-specific "my-unit" /n FIELD instance>unit2 /n FIELD instance>unit3 /n FIELD instance>unit4 CONSTANT /instance-header : >instance ( offset -- myself+offset ) my-self 0= ABORT" No instance!" dup my-self instance>size @ >= ABORT" Instance access out of bounds!" my-self + ; : (create-instance-var) ( initial-value -- ) get-node dup node>instance-size @ cell+ max-instance-size >= ABORT" Instance is bigger than max-instance-size!" dup node>instance-template @ ( iv phandle tmp-ih ) swap node>instance-size dup @ ( iv tmp-ih *instance-size instance-size ) dup , \ compile current instance ptr swap 1 cells swap +! ( iv tmp-ih instance-size ) + ! ; : create-instance-var ( "name" initial-value -- ) CREATE (create-instance-var) PREVIOUS ; : (create-instance-buf) ( buffersize -- ) aligned \ align size to multiples of cells dup get-node node>instance-size @ + ( buffersize' newinstancesize ) max-instance-size > ABORT" Instance is bigger than max-instance-size!" get-node node>instance-template @ get-node node>instance-size @ + over erase \ clear according to IEEE 1275 get-node node>instance-size @ ( buffersize' old-instance-size ) dup , \ compile current instance ptr + get-node node>instance-size ! \ store new size ; : create-instance-buf ( "name" buffersize -- ) CREATE (create-instance-buf) PREVIOUS ; VOCABULARY instance-words ALSO instance-words DEFINITIONS : VARIABLE 0 create-instance-var DOES> [ here ] @ >instance ; : VALUE create-instance-var DOES> [ here ] @ >instance @ ; : DEFER 0 create-instance-var DOES> [ here ] @ >instance @ execute ; : BUFFER: create-instance-buf DOES> [ here ] @ >instance ; PREVIOUS DEFINITIONS CONSTANT CONSTANT CONSTANT CONSTANT : (instance?) ( xt -- xt true|false ) dup @ = IF dup cell+ @ cell+ @ ['] >instance = ELSE false THEN ; : (doito) ( value R:*CFA -- ) r> cell+ dup >r @ cell+ cell+ @ >instance ! ; ' (doito) CONSTANT <(doito)> : to ( value wordname<> -- ) ' (instance?) state @ IF IF ['] (doito) ELSE ['] DOTO THEN , , EXIT THEN IF cell+ cell+ @ >instance ! \ interp mode instance value ELSE cell+ ! \ interp mode normal value THEN ; IMMEDIATE : behavior ( defer-xt -- contents-xt ) dup cell+ @ = IF \ Is defer-xt an INSTANCE DEFER ? 2 cells + @ >instance @ ELSE behavior THEN ; : INSTANCE ALSO instance-words ; : my-parent my-self instance>parent @ ; : my-args my-self instance>args 2@ swap ; : set-my-args ( old-addr len -- ) dup alloc-mem \ allocate space for new args ( old-addr len new-addr ) 2dup my-self instance>args 2! \ write into instance struct ( old-addr len new-addr ) swap move \ and copy the args ( ) ; : create-instance-data ( -- instance ) get-node dup node>instance-template @ ( phandle instance-template ) swap node>instance-size @ ( instance-template instance-size ) dup >r dup alloc-mem dup >r swap move r> ( instance ) dup instance>size r> swap ! \ Store size for destroy-instance dup instance>#units 0 swap ! \ Use node unit by default ; : create-instance ( -- ) my-self create-instance-data dup to my-self instance>parent ! get-node my-self instance>node ! ; : destroy-instance ( instance -- ) dup instance>args @ ?dup IF \ Free instance args? over instance>args-len @ free-mem THEN dup instance>size @ free-mem ; : ihandle>phandle ( ihandle -- phandle ) dup 0= ABORT" no current instance" instance>node @ ; : push-my-self ( ihandle -- ) r> my-self >r >r to my-self ; : pop-my-self ( -- ) r> r> to my-self >r ; : call-package push-my-self execute pop-my-self ; : $call-static ( ... str len node -- ??? ) find-method IF execute ELSE -1 throw THEN ; : $call-my-method ( str len -- ) my-self ihandle>phandle $call-static ; : $call-method ( str len ihandle -- ) push-my-self ['] $call-my-method CATCH ?dup IF pop-my-self THROW THEN pop-my-self ; 0 VALUE calling-child : $call-parent my-self ihandle>phandle TO calling-child my-parent $call-method 0 TO calling-child ; : create-node ( parent -- new ) max-instance-size alloc-mem ( parent instance-mem ) dup max-instance-size erase >r ( parent R: instance-mem ) align wordlist >r wordlist >r ( parent R: instance-mem wl wl ) here ( parent new R: instance-mem wl wl ) 0 , swap , 0 , \ Set node>peer, node>parent & node>child r> , r> , \ Set node>properties & node>words to wl r> , /instance-header , \ Set instance-template & instance-size FALSE , 0 , \ Set node>space? and node>space 0 , 0 , 0 , \ Set node>addr* ; : peer node>peer @ ; : parent node>parent @ ; : child node>child @ ; : peer dup IF peer ELSE drop device-tree @ THEN ; : link ( new head -- ) \ link a new node at the end of a linked list BEGIN dup @ WHILE @ REPEAT ! ; : link-node ( parent child -- ) swap dup IF node>child link ELSE drop device-tree ! THEN ; : set-node ( phandle -- ) current-node @ IF previous THEN dup current-node ! ?dup IF node>words @ also context ! THEN definitions ; : get-parent get-node parent ; : new-node ( -- phandle ) \ active node becomes new node's parent; current-node @ dup create-node tuck link-node dup set-node ; : finish-node ( -- ) get-node parent set-node ; : device-end ( -- ) 0 set-node ; CREATE $indent 100 allot VARIABLE indent 0 indent ! true value encode-first? : decode-int over >r 4 /string r> 4c@ swap 2swap swap bljoin ; : decode-64 decode-int -rot decode-int -rot 2swap swap lxjoin ; : decode-string ( prop-addr1 prop-len1 -- prop-addr2 prop-len2 str len ) dup 0= IF 2dup EXIT THEN \ string properties with zero length over BEGIN dup c@ 0= IF 1+ -rot swap 2 pick over - rot over - -rot 1- EXIT THEN 1+ AGAIN ; : (prune) ( name len head -- ) dup >r (find) ?dup IF r> BEGIN dup @ WHILE 2dup @ = IF >r @ r> ! EXIT THEN @ REPEAT 2drop ELSE r> drop THEN ; : prune ( name len -- ) last (prune) ; : set-property ( data dlen name nlen phandle -- ) true to encode-first? get-current >r node>properties @ set-current 2dup prune $2CONSTANT r> set-current ; : delete-property ( name nlen -- ) get-node get-current >r node>properties @ set-current prune r> set-current ; : property ( data dlen name nlen -- ) get-node set-property ; : get-property ( str len phandle -- true | data dlen false ) ?dup 0= IF cr cr cr ." get-property for " type ." on zero phandle" cr cr true EXIT THEN node>properties @ voc-find dup IF link> execute false ELSE drop true THEN ; : get-package-property ( str len phandle -- true | data dlen false ) get-property ; : get-my-property ( str len -- true | data dlen false ) my-self ihandle>phandle get-property ; : get-parent-property ( str len -- true | data dlen false ) my-parent ihandle>phandle get-property ; : get-inherited-property ( str len -- true | data dlen false ) my-self ihandle>phandle BEGIN 3dup get-property 0= IF rot drop rot drop rot drop false EXIT THEN parent dup 0= IF 3drop true EXIT THEN AGAIN ; 20 CONSTANT indent-prop : .prop-int ( str len -- ) space 400 min 0 ?DO i over + dup ( str act-addr act-addr ) c@ 2 0.r 1+ dup c@ 2 0.r 1+ dup c@ 2 0.r 1+ c@ 2 0.r ( str ) i c and c = IF \ check for multipleof 16 bytes cr indent @ indent-prop + 1+ 0 \ linefeed + indent DO space \ print spaces LOOP ELSE space space \ print two spaces THEN 4 +LOOP drop ; : .prop-bytes ( str len -- ) 2dup -4 and .prop-int ( str len ) dup 3 and dup IF ( str len len%4 ) >r -4 and + r> ( str' len%4 ) bounds ( str' str'+len%4 ) DO i c@ 2 0.r \ Print last 3 bytes LOOP ELSE 3drop THEN ; : .prop-string ( str len ) 2dup space type cr indent @ indent-prop + 0 DO space LOOP \ Linefeed .prop-bytes ; : .propbytes ( xt -- ) execute dup IF over cell- @ execute ELSE 2drop THEN ; : .property ( lfa -- ) cr indent @ 0 ?DO space LOOP link> dup >name name>string 2dup type nip ( len ) indent-prop swap - ( xt 20-len ) dup 0< IF drop 0 THEN 0 ( xt number-of-space 0 ) ?DO space LOOP .propbytes ; : (.properties) ( phandle -- ) node>properties @ cell+ @ BEGIN dup WHILE dup .property @ REPEAT drop ; : .properties ( -- ) get-node (.properties) ; : next-property ( str len phandle -- false | str' len' true ) ?dup 0= IF device-tree @ THEN \ XXX: is this line required? node>properties @ >r 2dup 0= swap 0= or IF 2drop r> cell+ ELSE r> voc-find THEN @ dup IF link>name name>string true THEN ; : encode-start ( -- prop 0 ) ['] .prop-int compile, false to encode-first? here 0 ; : encode-int ( val -- prop prop-len ) encode-first? IF ['] .prop-int compile, \ Execution token for print false to encode-first? THEN here swap lbsplit c, c, c, c, /l ; : encode-bytes ( str len -- prop-addr prop-len ) encode-first? IF ['] .prop-bytes compile, \ Execution token for print false to encode-first? THEN here over 2dup 2>r allot swap move 2r> ; : encode-string ( str len -- prop-addr prop-len ) encode-first? IF ['] .prop-string compile, \ Execution token for print false to encode-first? THEN encode-bytes 0 c, char+ ; : encode+ ( prop1-addr prop1-len prop2-addr prop2-len -- prop-addr prop-len ) nip + ; : encode-int+ encode-int encode+ ; : encode-64 xlsplit encode-int rot encode-int+ ; : encode-64+ encode-64 encode+ ; : device-name encode-string s" name" property ; : device-type encode-string s" device_type" property ; : model encode-string s" model" property ; : compatible encode-string s" compatible" property ; : #address-cells s" #address-cells" rot parent get-property ABORT" parent doesn't have a #address-cells property!" decode-int nip nip ; : my-#address-cells ( -- #address-cells ) get-node #address-cells ; : child-#address-cells ( -- #address-cells ) s" #address-cells" get-node get-property ABORT" node doesn't have a #address-cells property!" decode-int nip nip ; : child-#size-cells ( -- #address-cells ) s" #size-cells" get-node get-property ABORT" node doesn't have a #size-cells property!" decode-int nip nip ; : encode-phys ( phys.hi ... phys.low -- prop len ) encode-first? IF encode-start ELSE here 0 THEN my-#address-cells 0 ?DO rot encode-int+ LOOP ; : encode-child-phys ( phys.hi ... phys.low -- prop len ) encode-first? IF encode-start ELSE here 0 THEN child-#address-cells 0 ?DO rot encode-int+ LOOP ; : encode-child-size ( size.hi ... size.low -- prop len ) encode-first? IF encode-start ELSE here 0 THEN child-#size-cells 0 ?DO rot encode-int+ LOOP ; : decode-phys my-#address-cells BEGIN dup WHILE 1- >r decode-int r> swap >r REPEAT drop my-#address-cells BEGIN dup WHILE 1- r> swap REPEAT drop ; : decode-phys-and-drop my-#address-cells BEGIN dup WHILE 1- >r decode-int r> swap >r REPEAT 3drop my-#address-cells BEGIN dup WHILE 1- r> swap REPEAT drop ; : reg >r encode-phys r> encode-int+ s" reg" property ; : >space node>space @ ; : >space? node>space? @ ; : >address dup >r #address-cells dup 3 > IF r@ node>addr3 @ swap THEN dup 2 > IF r@ node>addr2 @ swap THEN 1 > IF r@ node>addr1 @ THEN r> drop ; : >unit dup >r >address r> >space ; : (my-phandle) ( -- phandle ) my-self ?dup IF ihandle>phandle ELSE get-node dup 0= ABORT" no active node" THEN ; : my-space ( -- phys.hi ) (my-phandle) >space ; : my-address (my-phandle) >address ; : my-unit my-self instance>#units @ IF 0 my-self instance>#units @ 1- DO my-self instance>unit1 i cells + @ -1 +LOOP ELSE my-self ihandle>phandle >unit THEN ; : my-unit-64 ( -- phys.lo+1|phys.lo ) my-unit ( phys.lo ... phys.hi ) (my-phandle) #address-cells ( phys.lo ... phys.hi #ad-cells ) CASE 1 OF EXIT ENDOF 2 OF lxjoin EXIT ENDOF 3 OF drop lxjoin EXIT ENDOF dup OF 2drop lxjoin EXIT ENDOF ENDCASE ; : set-space get-node dup >r node>space ! true r> node>space? ! ; : set-address my-#address-cells 1 ?DO get-node node>space i cells + ! LOOP ; : set-unit set-space set-address ; : set-unit-64 ( phys.lo|phys.hi -- ) my-#address-cells 2 <> IF ." set-unit-64: #address-cells <> 2 " abort THEN xlsplit set-unit ; : set-args ( arg-str len unit-str len -- ) s" decode-unit" get-parent $call-static set-unit set-my-args ; : $cat-unit dup parent 0= IF drop EXIT THEN dup >space? not IF drop EXIT THEN dup >r >unit s" encode-unit" r> parent $call-static dup IF dup >r here swap move s" @" $cat here r> $cat ELSE 2drop THEN ; : $cat-instance-unit dup parent 0= IF drop EXIT THEN dup instance>#units @ 0= IF ihandle>phandle $cat-unit EXIT THEN dup >r push-my-self ['] my-unit CATCH IF pop-my-self r> drop EXIT THEN pop-my-self s" encode-unit" r> ihandle>phandle parent $call-static dup IF dup >r here swap move s" @" $cat here r> $cat ELSE 2drop THEN ; : node>name dup >r s" name" rot get-property IF r> (u.) ELSE 1- r> drop THEN ; : node>qname dup node>name rot ['] $cat-unit CATCH IF drop THEN ; : node>path here 0 rot BEGIN dup WHILE dup parent REPEAT 2drop dup 0= IF [char] / c, THEN BEGIN dup WHILE [char] / c, node>qname here over allot swap move REPEAT drop here 2dup - allot over - ; : interposed? ( ihandle -- flag ) dup instance>parent @ dup 0= IF 2drop false EXIT THEN ihandle>phandle swap ihandle>phandle parent <> ; : instance>qname dup >r interposed? IF s" %" ELSE 0 0 THEN r@ dup ihandle>phandle node>name rot ['] $cat-instance-unit CATCH IF drop THEN $cat r> instance>args 2@ swap dup IF 2>r s" :" $cat 2r> $cat ELSE 2drop THEN ; : instance>qpath \ With interposed nodes. here 0 rot BEGIN dup WHILE dup instance>parent @ REPEAT 2drop dup 0= IF [char] / c, THEN BEGIN dup WHILE [char] / c, instance>qname here over allot swap move REPEAT drop here 2dup - allot over - ; : instance>path \ Without interposed nodes. here 0 rot BEGIN dup WHILE dup interposed? 0= IF dup THEN instance>parent @ REPEAT 2drop dup 0= IF [char] / c, THEN BEGIN dup WHILE [char] / c, instance>qname here over allot swap move REPEAT drop here 2dup - allot over - ; : .node node>path type ; : pwd get-node .node ; : .instance instance>qpath type ; : .chain dup instance>parent @ ?dup IF recurse THEN cr dup . instance>qname type ; defer find-node : set-alias ( alias-name len device-name len -- ) encode-string 2swap s" /aliases" find-node ?dup IF set-property ELSE 4drop THEN ; : find-alias ( alias-name len -- false | dev-path len ) s" /aliases" find-node dup IF get-property 0= IF 1- dup 0= IF nip THEN ELSE false THEN THEN ; : .alias ( alias-name len -- ) find-alias dup IF type ELSE ." no alias available" THEN ; : (.print-alias) ( lfa -- ) link> dup >name name>string 2dup s" name" string=ci IF 2drop drop ELSE cr type space ." : " execute type THEN ; : (.list-alias) ( phandle -- ) node>properties @ cell+ @ BEGIN dup WHILE dup (.print-alias) @ REPEAT drop ; : list-alias ( -- ) s" /aliases" find-node dup IF (.list-alias) THEN ; d# 10 CONSTANT MAX-ALIAS 1 VALUE alias-ind : get-next-alias ( $alias-name -- $next-alias-name|FALSE ) 2dup find-alias IF drop 1 TO alias-ind BEGIN 2dup alias-ind $cathex 2dup find-alias WHILE drop 2drop alias-ind 1 + TO alias-ind alias-ind MAX-ALIAS = IF 2drop FALSE EXIT THEN REPEAT strdup 2swap 2drop THEN ; : devalias ( "{alias-name}<>{device-specifier}" -- ) parse-word parse-word dup IF set-alias ELSE 2drop dup IF .alias ELSE 2drop list-alias THEN THEN ; : sub-alias ( arg-str arg-len -- arg' len' | false ) 2dup 2dup [char] / findchar ?dup IF ELSE 2dup [char] : findchar THEN ( a l a l [p] -1|0 ) IF nip dup ELSE 2drop 0 THEN >r find-alias ?dup IF ( a l a' p' -- R:p | a' l' -- R:0 ) r@ IF 2swap r@ - swap r> + swap $cat strdup ( a" l-p+p' -- ) ELSE ( a' l' -- R:0 ) r> drop ( a' l' -- ) THEN ELSE ( a l -- R:p | -- R:0 ) r> IF 2drop THEN false ( 0 -- ) THEN ; : de-alias ( arg-str arg-len -- arg' len' ) BEGIN over c@ [char] / <> dup IF drop 2dup sub-alias ?dup THEN WHILE 2swap 2drop REPEAT ; : +indent ( not-last? -- ) IF s" | " ELSE s" " THEN $indent indent @ + swap move 4 indent +! ; : -indent ( -- ) -4 indent +! ; : ls-phandle ( node -- ) . ." : " ; : ls-node ( node -- ) cr dup ls-phandle $indent indent @ type dup peer IF ." |-- " ELSE ." +-- " THEN node>qname type ; : (ls) ( node -- ) child BEGIN dup WHILE dup ls-node dup child IF dup peer +indent dup recurse -indent THEN peer REPEAT drop ; : ls ( -- ) get-node cr dup ls-phandle dup node>path type (ls) 0 indent ! ; : show-devs ( {device-specifier} -- ) skipws 0 parse dup IF de-alias ELSE 2drop s" /" THEN ( str len ) find-node dup 0= ABORT" No such device path" (ls) ; VARIABLE interpose-node 2VARIABLE interpose-args : interpose ( arg len phandle -- ) interpose-node ! interpose-args 2! ; 0 VALUE user-instance-#units CREATE user-instance-units 4 cells allot : copy-instance-unit ( -- ) user-instance-#units IF user-instance-#units my-self instance>#units ! user-instance-units my-self instance>unit1 user-instance-#units cells move 0 to user-instance-#units THEN ; : open-node ( arg len phandle -- ihandle|0 ) current-node @ >r my-self >r \ Save current node and instance set-node create-instance set-my-args copy-instance-unit s" open" get-node find-method IF execute ELSE TRUE THEN 0= IF my-self destroy-instance 0 to my-self THEN my-self ( ihandle|0 ) r> to my-self r> set-node \ Restore current node and instance interpose-node @ IF my-self >r to my-self interpose-args 2@ interpose-node @ interpose-node off recurse r> to my-self THEN ; : close-node ( ihandle -- ) my-self >r to my-self s" close" ['] $call-my-method CATCH IF 2drop THEN my-self destroy-instance r> to my-self ; : close-dev ( ihandle -- ) my-self >r to my-self BEGIN my-self WHILE my-parent my-self close-node to my-self REPEAT r> to my-self ; : new-device ( -- ) my-self new-node ( parent-ihandle phandle ) node>instance-template @ ( parent-ihandle ihandle ) dup to my-self ( parent-ihanlde ihandle ) instance>parent ! get-node my-self instance>node ! max-instance-size my-self instance>size ! ; : finish-device ( -- ) get-node >space? 0= IF s" reg" get-node get-property 0= IF decode-int set-space 2drop THEN THEN finish-node my-parent to my-self ; : extend-device ( phandle -- ) my-self >r dup set-node node>instance-template @ dup to my-self r> swap instance>parent ! ; : split ( str len char -- left len right len ) >r 2dup r> findchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; : generic-decode-unit ( str len ncells -- addr.lo ... addr.hi ) dup >r -rot BEGIN r@ WHILE r> 1- >r [char] , split 2swap $number IF 0 THEN r> swap >r >r REPEAT r> 3drop BEGIN dup WHILE 1- r> swap REPEAT drop ; : generic-encode-unit ( addr.lo ... addr.hi ncells -- str len ) 0 0 rot ?dup IF 0 ?DO rot (u.) $cat s" ," $cat LOOP 1- THEN ; : hex-decode-unit ( str len ncells -- addr.lo ... addr.hi ) base @ >r hex generic-decode-unit r> base ! ; : hex-encode-unit ( addr.lo ... addr.hi ncells -- str len ) base @ >r hex generic-encode-unit r> base ! ; : hex64-decode-unit ( str len ncells -- addr.lo ... addr.hi ) dup 2 <> IF hex-decode-unit ELSE drop base @ >r hex $number IF 0 0 ELSE xlsplit THEN r> base ! THEN ; : hex64-encode-unit ( addr.lo ... addr.hi ncells -- str len ) dup 2 <> IF hex-encode-unit ELSE drop base @ >r hex lxjoin (u.) r> base ! THEN ; : handle-leading-/ ( path len -- path' len' ) dup IF over c@ [char] / = IF 1 /string device-tree @ set-node THEN THEN ; : match-name ( name len node -- match? ) over 0= IF 3drop true EXIT THEN s" name" rot get-property IF 2drop false EXIT THEN 1- string=ci ; \ XXX should use decode-string 0 VALUE #search-unit CREATE search-unit 4 cells allot : match-unit ( node -- match? ) dup >space? IF node>space search-unit #search-unit 0 ?DO 2dup @ swap @ <> IF 2drop false UNLOOP EXIT THEN cell+ swap cell+ swap LOOP 2drop true ELSE drop true THEN ; : match-node ( name len node -- match? ) dup >r match-name r> match-unit and ; \ XXX e3d : find-kid ( name len -- node|0 ) dup -1 = IF \ are we supposed to stay in the same node? -> resolve-relatives 2drop get-node ELSE get-node child >r BEGIN r@ WHILE 2dup r@ match-node IF 2drop r> EXIT THEN r> peer >r REPEAT r> 3drop false THEN ; : set-search-unit ( unit len -- ) 0 to #search-unit 0 to user-instance-#units dup 0= IF 2drop EXIT THEN s" #address-cells" get-node get-property THROW decode-int to #search-unit 2drop s" decode-unit" get-node $call-static #search-unit 0 ?DO search-unit i cells + ! LOOP ; : resolve-relatives ( path len -- path' len' ) 2dup 2 = swap s" .." comp 0= and IF get-node parent ?dup IF set-node drop -1 ELSE s" Already in root node." type THEN THEN 2dup 1 = swap c@ [CHAR] . = and IF drop -1 THEN ; : set-instance-unit ( unitaddr len -- ) dup 0= IF 2drop 0 to user-instance-#units EXIT THEN 2dup 0 -rot bounds ?DO i c@ [char] , = IF 1+ THEN \ Count the commas LOOP 1+ dup to user-instance-#units hex-decode-unit user-instance-#units 0 ?DO user-instance-units i cells + ! LOOP ; : split-component ( path. -- path'. args. name. unit. ) [char] / split 2swap ( path'. component. ) [char] : split 2swap ( path'. args. name@unit. ) [char] @ split ( path'. args. name. unit. ) ; : find-component ( path len -- path' len' args len node|0 ) debug-find-component? IF ." find-component for " 2dup type cr THEN split-component ( path'. args. name. unit. ) debug-find-component? IF ." -> unit =" 2dup type cr ." -> stack =" .s cr THEN ['] set-search-unit CATCH IF ." WARNING: Obsolete old wildcard hack " .s cr set-instance-unit THEN resolve-relatives find-kid ( path' len' args len node|0 ) dup IF dup >space? not #search-unit 0 > AND user-instance-#units 0= AND IF #search-unit dup to user-instance-#units 0 ?DO search-unit i cells + @ user-instance-units i cells + ! LOOP THEN THEN dup IF dup >space? user-instance-#units 0 > AND IF cr ." find-component with unit mismatch!" .s cr drop 0 THEN THEN ; : .find-node ( path len -- phandle|0 ) current-node @ >r handle-leading-/ current-node @ 0= IF 2drop r> set-node 0 EXIT THEN BEGIN dup WHILE \ handle one component: find-component ( path len args len node ) dup 0= IF 3drop 2drop r> set-node 0 EXIT THEN set-node 2drop REPEAT 2drop get-node r> set-node ; ' .find-node to find-node : find-node ( path len -- phandle|0 ) de-alias find-node ; : delete-node ( phandle -- ) dup node>instance-template @ max-instance-size free-mem dup node>parent @ node>child @ ( phandle 1st peer ) 2dup = IF node>peer @ swap node>parent @ node>child ! EXIT THEN dup node>peer @ BEGIN 2 pick 2dup <> WHILE drop nip dup node>peer @ dup 0= IF 2drop drop unloop EXIT THEN REPEAT drop node>peer @ swap node>peer ! drop ; : open-dev ( path len -- ihandle|0 ) 0 to user-instance-#units de-alias current-node @ >r handle-leading-/ current-node @ 0= IF 2drop r> set-node 0 EXIT THEN my-self >r 0 to my-self 0 0 >r >r BEGIN dup WHILE \ handle one component: ( arg len ) r> r> get-node open-node to my-self find-component ( path len args len node ) dup 0= IF 3drop 2drop my-self close-dev r> to my-self r> set-node 0 EXIT THEN set-node >r >r REPEAT 2drop r> r> get-node open-node to my-self my-self r> to my-self r> set-node ; : select-dev open-dev dup to my-self ihandle>phandle set-node ; : unselect-dev my-self close-dev 0 to my-self device-end ; : find-device ( str len -- ) \ set as active node find-node dup 0= ABORT" No such device path" set-node ; : dev parse-word find-device ; : (lsprop) ( node --) dup cr $indent indent @ type ." node: " node>qname type false +indent (.properties) cr -indent ; : (show-children) ( node -- ) child BEGIN dup WHILE dup (lsprop) dup child IF false +indent dup recurse -indent THEN peer REPEAT drop ; : lsprop ( {device-specifier} -- ) skipws 0 parse dup IF de-alias ELSE 2drop s" /" THEN find-device get-node dup dup cr ." node: " node>path type (.properties) cr (show-children) 0 indent ! ; : (node>path) node>path ; : node>path ( phandle -- str len ) node>path dup allot ; 0 VALUE packages : find-package ( name len -- false | phandle true ) dup 0 <= IF 2drop FALSE EXIT THEN over c@ [char] / = IF find-node dup IF TRUE THEN EXIT THEN 0 >r packages child BEGIN dup WHILE dup >r node>name 2over string=ci r> swap IF r> drop dup >r THEN peer REPEAT 3drop r> dup IF true THEN ; : open-package ( arg len phandle -- ihandle | 0 ) open-node ; : close-package ( ihandle -- ) close-node ; : $open-package ( arg len name len -- ihandle | 0 ) find-package IF open-package ELSE 2drop false THEN ; : pci-address-type ( node address prop_type -- type ) -rot 2 pick ( prop_type node address prop_type ) 0= IF swap s" reg" rot get-property ( prop_type address data dlen false ) ELSE swap s" assigned-addresses" rot get-property ( prop_type address data dlen false ) THEN IF 2drop -1 EXIT THEN 4 / 5 / 0 DO dup l@ FF AND 0<> ( prop_type address data cfgspace_offset? ) 3 pick 0= ( prop_type address data cfgspace_offset? reg_prop? ) AND NOT IF 2dup 4 + ( prop_type address data address data' ) 2dup @ 2 pick 8 + @ + <= -rot @ >= and IF l@ 03000000 and 18 rshift nip swap drop ( type ) UNLOOP EXIT THEN THEN 4 5 * + LOOP 3drop -1 ; : (range-read-cells) ( range-addr #cells -- range-value ) 1 = IF l@ ELSE @ THEN ; : (map-one-range) ( type range pnac nsc nac address -- address true | address false ) over 3 = 5 pick l@ 3000000 and 18 rshift 7 pick <> and IF >r 2drop 3drop r> false EXIT THEN 4 pick 4 pick 3 pick + 4 * + 3 pick (range-read-cells) 5 pick 3 pick 3 = IF 4 + THEN 3 pick (range-read-cells) dup >r dup 3 pick > >r + over <= r> or IF >r 2drop 3drop r> r> drop false EXIT THEN dup r> - 5 pick 5 pick 3 = IF 4 + THEN 3 pick 4 * + 5 pick (range-read-cells) + >r 3drop 3drop r> true ; : translate-address ( node address -- address ) 2dup 1 pci-address-type ( node address type ) dup -1 = IF drop 2dup 0 pci-address-type ( node address type ) THEN rot parent BEGIN dup parent 0= IF 2drop EXIT THEN s" #address-cells" 2 pick get-property 2drop l@ >r \ nac s" #size-cells" 2 pick get-property 2drop l@ >r \ nsc s" #address-cells" 2 pick parent get-property 2drop l@ >r \ pnac -rot ( node address type ) s" ranges" 4 pick get-property IF 3drop ABORT" no ranges property; not translatable" THEN r> r> r> 3 roll 4 / >r 3dup + + >r 5 roll r> r> swap / 0 ?DO 6dup (map-one-range) IF nip leave THEN nip 4 roll 4 pick 4 pick 4 pick + + 4 * + 4 -roll LOOP >r 2drop 2drop r> ( node type address ) swap rot parent ( address type node ) dup 0= UNTIL ; : translate-my-address ( address -- address' ) get-node swap translate-address ; : find-substr ( basestr-ptr basestr-len substr-ptr substr-len -- pos ) dup 0 = IF 2drop 2drop 0 exit THEN dup 3 pick <= IF 2 pick over - 1+ 0 DO dup 0 DO over i + c@ 4 pick j + i + c@ = IF dup i 1+ = IF 2drop 2drop j unloop unloop exit THEN ELSE leave THEN LOOP LOOP THEN 2drop nip ; : find-isubstr ( basestr-ptr basestr-len substr-ptr substr-len -- pos ) dup 0 = IF 2drop 2drop 0 exit THEN dup 3 pick <= IF 2 pick over - 1+ 0 DO dup 0 DO over i + c@ lcc 4 pick j + i + c@ lcc = IF dup i 1+ = IF 2drop 2drop j unloop unloop exit THEN ELSE leave THEN LOOP LOOP THEN 2drop nip ; : find-nextline ( str-ptr str-len -- pos ) dup 0 ?DO over i + c@ CASE 0a OF dup 1- i = IF 2drop i 1+ unloop exit THEN over i 1+ + c@ 0d = IF 2drop i 2+ ELSE 2drop i 1+ THEN unloop exit ENDOF 0d OF dup 1- i = IF 2drop i 1+ unloop exit THEN over i 1+ + c@ 0a = IF 2drop i 2+ ELSE 2drop i 1+ THEN unloop exit ENDOF ENDCASE LOOP nip ; : string-at ( str1-ptr str1-len pos -- str2-ptr str2-len ) -rot 2 pick - -rot swap chars + swap ; : string-cat ( addr1 len1 addr2 len2 -- addr1 len1+len2 ) rot dup >r over + -rot 3 pick r> chars + -rot 0 ?DO 2dup c@ swap c! char+ swap char+ swap LOOP 2drop ; : char-cat ( addr len character -- addr len+1 ) -rot 2dup >r >r 1+ rot r> r> chars + c! ; : overlap ( src dest size -- true|false ) 3dup over + within IF 3drop true ELSE rot tuck + within THEN ; : parse-2int ( str len -- val.lo val.hi ) [char] , split ?dup IF eval ELSE drop 0 THEN -rot ?dup IF eval ELSE drop 0 THEN ; : cpeek ( addr -- false | byte true ) c@ true ; : cpoke ( byte addr -- success? ) c! true ; : wpeek ( addr -- false | word true ) w@ true ; : wpoke ( word addr -- success? ) w! true ; : lpeek ( addr -- false | lword true ) l@ true ; : lpoke ( lword addr -- success? ) l! true ; defer reboot ( -- ) defer halt ( -- ) defer disable-watchdog ( -- ) defer reset-watchdog ( -- ) defer set-watchdog ( +n -- ) defer set-led ( type instance state -- status ) defer get-flashside ( -- side ) defer set-flashside ( side -- status ) defer read-bootlist ( -- ) defer furnish-boot-file ( -- adr len ) defer set-boot-file ( adr len -- ) defer mfg-mode? ( -- flag ) defer of-prompt? ( -- flag ) defer debug-boot? ( -- flag ) defer bmc-version ( -- adr len ) defer cursor-on ( -- ) defer cursor-off ( -- ) : nop-reboot ( -- ) ." reboot not available" abort ; : nop-halt ( -- ) ." halt not available" abort ; : nop-disable-watchdog ( -- ) ; : nop-reset-watchdog ( -- ) ; : nop-set-watchdog ( +n -- ) drop ; : nop-set-led ( type instance state -- status ) drop drop drop ; : nop-get-flashside ( -- side ) ." Cannot get flashside" cr ABORT ; : nop-set-flashside ( side -- status ) ." Cannot set flashside" cr ABORT ; : nop-read-bootlist ( -- ) ; : nop-furnish-bootfile ( -- adr len ) s" net:" ; : nop-set-boot-file ( adr len -- ) 2drop ; : nop-mfg-mode? ( -- flag ) false ; : nop-of-prompt? ( -- flag ) false ; : nop-debug-boot? ( -- flag ) false ; : nop-bmc-version ( -- adr len ) s" XXXXX" ; : nop-cursor-on ( -- ) ; : nop-cursor-off ( -- ) ; ' nop-reboot to reboot ' nop-halt to halt ' nop-disable-watchdog to disable-watchdog ' nop-reset-watchdog to reset-watchdog ' nop-set-watchdog to set-watchdog ' nop-set-led to set-led ' nop-get-flashside to get-flashside ' nop-set-flashside to set-flashside ' nop-read-bootlist to read-bootlist ' nop-furnish-bootfile to furnish-boot-file ' nop-set-boot-file to set-boot-file ' nop-mfg-mode? to mfg-mode? ' nop-of-prompt? to of-prompt? ' nop-debug-boot? to debug-boot? ' nop-bmc-version to bmc-version ' nop-cursor-on to cursor-on ' nop-cursor-off to cursor-off : reset-all reboot ; 10000000 VALUE default-load-base 2000000 VALUE flash-load-base 0 VALUE load-base-override : get-load-base load-base-override 0<> IF load-base-override ELSE " load-base" evaluate THEN ; : xt>name ( xt -- str len ) BEGIN cell - dup c@ 0 2 within IF dup 2+ swap 1+ c@ exit THEN AGAIN ; cell -1 * CONSTANT -cell : cell- ( n -- n-cell-size ) [ cell -1 * ] LITERAL + ; : find-xt-addr ( addr -- xt ) BEGIN dup @ = IF EXIT THEN cell- AGAIN ; : (.immediate) ( xt -- ) xt>name drop 2 - c@ \ skip len and flags immediate? IF ." IMMEDIATE" THEN ; : (.xt) ( xt -- ) xt>name type ; : trace-back ( ) 1 BEGIN cr dup dup . ." : " rpick dup . ." : " ['] tib here within IF dup rpick find-xt-addr (.xt) THEN 1+ dup rdepth 5 - >= IF cr drop EXIT THEN AGAIN ; VARIABLE see-my-type-column : (see-my-type) ( indent limit xt str len -- indent limit xt ) dup see-my-type-column @ + dup 50 >= IF -rot over " " comp 0= IF 2drop see-my-type-column ! ELSE rot drop ( indent limit xt str len ) pocket swap 2dup >r >r ( indent limit xt str pk len R: len pk ) move r> r> ( indent limit xt pk len ) 2 pick (u.) dup -rot cr type ( indent limit xt pk len xt-len ) " :" type 1+ ( indent limit xt pk len prefix-len ) 5 pick dup spaces + ( indent limit xt pk len prefix-len ) over + see-my-type-column ! ( indent limit xt pk len ) type THEN ( indent limit xt ) ELSE see-my-type-column ! type ( indent limit xt ) THEN ; : (see-my-type-init) ( -- ) ffff see-my-type-column ! \ just enforce a new line ; : (see-colon-body) ( indent limit xt -- indent limit xt ) (see-my-type-init) \ enforce new line BEGIN ( indent limit xt ) cell+ 2dup <> over @ dup <> rot and ( indent limit xt @xt flag ) WHILE ( indent limit xt @xt ) xt>name (see-my-type) " " (see-my-type) dup @ ( indent limit xt @xt) CASE <0branch> OF cell+ dup @ over + cell+ dup >r (u.) (see-my-type) r> ( indent limit xt target) 2dup < IF over 4 pick 3 + -rot recurse nip nip nip cell- ( indent limit xt ) ELSE drop ( indent limit xt ) THEN (see-my-type-init) ENDOF \ enforce new line OF cell+ dup @ over + cell+ (u.) (see-my-type) " " (see-my-type) ENDOF OF cell+ dup @ (u.) (see-my-type) " " (see-my-type) ENDOF OF cell+ dup @ (u.) (see-my-type) " " (see-my-type) ENDOF OF cell+ dup @ xt>name (see-my-type) " " (see-my-type) ENDOF OF cell+ dup @ (u.) (see-my-type) " " (see-my-type) ENDOF OF cell+ dup @ (u.) (see-my-type) " " (see-my-type) ENDOF OF cell+ dup @ over + cell+ (u.) (see-my-type) " " (see-my-type) ENDOF OF cell+ dup @ over + cell+ (u.) (see-my-type) " " (see-my-type) ENDOF OF cell+ " """ (see-my-type) dup count dup >r (see-my-type) " """ (see-my-type) " " (see-my-type) r> -cell and + ENDOF ENDCASE REPEAT drop ; : (see-colon) ( xt -- ) (see-my-type-init) 1 swap 0 swap ( indent limit xt ) " : " (see-my-type) dup xt>name (see-my-type) rot drop 4 -rot (see-colon-body) ( indent limit xt ) rot drop 1 -rot (see-my-type-init) " ;" (see-my-type) 3drop ; : (see-create) ( xt -- ) dup cell+ @ CASE <2constant> OF dup cell+ cell+ dup @ swap cell+ @ . . ." 2CONSTANT " ENDOF OF dup cell+ cell+ @ . ." INSTANCE VALUE " ENDOF OF ." INSTANCE VARIABLE " ENDOF dup OF ." CREATE " ENDOF ENDCASE (.xt) ; : (see) ( xt -- ) cr dup dup @ CASE OF ." VARIABLE " (.xt) ENDOF OF dup execute . ." VALUE " (.xt) ENDOF OF dup execute . ." CONSTANT " (.xt) ENDOF OF dup cell+ @ swap ." DEFER " (.xt) ." is " (.xt) ENDOF OF dup cell+ @ swap ." ALIAS " (.xt) ." " (.xt) ENDOF OF ." BUFFER: " (.xt) ENDOF OF (see-create) ENDOF OF (see-colon) ENDOF dup OF ." ??? PRIM " (.xt) ENDOF ENDCASE (.immediate) cr ; : see ( "old-name<>" -- ) ' (see) ; 0 value forth-ip true value trace>stepping? true value trace>print? true value trace>up? 0 value trace>depth 0 value trace>rdepth 0 value trace>recurse : trace-depth+ ( -- ) trace>depth 1+ to trace>depth ; : trace-depth- ( -- ) trace>depth 1- to trace>depth ; : stepping ( -- ) true to trace>stepping? ; : tracing ( -- ) false to trace>stepping? ; : trace-print-on ( -- ) true to trace>print? ; : trace-print-off ( -- ) false to trace>print? ; : fip-add ( n -- ) forth-ip + to forth-ip ; 0 value debug-last-xt 0 value debug-last-xt-content : trace-print ( -- ) forth-ip cr u. ." : " forth-ip @ dup ['] breakpoint = IF drop debug-last-xt-content THEN xt>name type ." " ." ( " .s ." ) | " ; : trace-interpret ( -- ) rdepth 1- to trace>rdepth BEGIN depth . [char] > dup emit emit space source expect ( str len ) ['] interpret catch print-status AGAIN ; : trace-xt ( xt -- ) trace>recurse IF r> drop \ Drop return of 'trace-xt call cell+ \ Step over ":" ELSE debug-last-xt-content = IF ['] breakpoint @ debug-last-xt ! \ Re-arm break point r> drop \ Drop return of 'trace-xt call cell+ \ Step over ":" ELSE ['] breakpoint debug-last-xt ! \ Re-arm break point 2r> 2drop THEN THEN to forth-ip true to trace>print? BEGIN trace>print? IF trace-print THEN forth-ip ( ip ) trace>stepping? IF BEGIN key CASE [char] d OF dup @ @ = IF \ recurse only into colon definitions trace-depth+ 1 to trace>recurse dup >r @ recurse THEN true ENDOF [char] u OF trace>depth IF tracing trace-print-off true ELSE false THEN ENDOF [char] f OF drop cr trace-interpret ENDOF \ quit trace and start interpreter FIXME rstack [char] c OF tracing true ENDOF [char] t OF trace-back false ENDOF [char] q OF drop cr quit ENDOF 20 OF true ENDOF dup OF cr ." Press d: Down into current word" cr ." Press u: Up to caller" cr ." Press f: Switch to forth interpreter, 'resume' will continue tracing" cr ." Press c: Switch to tracing" cr ." Press : Execute current word" cr ." Press q: Abort execution, switch to interpreter" cr false ENDOF ENDCASE UNTIL THEN ( ip' ) dup to forth-ip @ ( xt ) dup ['] breakpoint = IF drop debug-last-xt-content THEN dup ( xt xt ) CASE OF drop forth-ip cell+ dup dup c@ + -cell and to forth-ip ENDOF OF drop forth-ip cell+ @ cell fip-add ENDOF OF drop forth-ip cell+ @ cell fip-add ENDOF OF drop forth-ip cell+ @ cell+ ! cell fip-add ENDOF <(doito)> OF drop forth-ip cell+ @ cell+ cell+ @ >instance ! cell fip-add ENDOF <0branch> OF drop IF cell fip-add ELSE forth-ip cell+ @ cell+ fip-add THEN ENDOF OF drop 2dup <> IF swap >r >r cell fip-add ELSE forth-ip cell+ @ cell+ fip-add 2drop THEN ENDOF OF drop forth-ip cell+ @ cell+ fip-add ENDOF OF drop r> r> 2drop forth-ip cell+ @ cell+ fip-add ENDOF OF drop IF r> r> 2drop forth-ip cell+ @ cell+ fip-add ELSE cell fip-add THEN ENDOF OF drop r> 1+ r> 2dup = IF 2drop cell fip-add ELSE >r >r forth-ip cell+ @ cell+ fip-add THEN ENDOF OF drop r> + r> 2dup >= IF 2drop cell fip-add ELSE >r >r forth-ip cell+ @ cell+ fip-add THEN ENDOF OF trace>depth 0> IF trace-depth- 1 to trace>recurse stepping drop r> recurse ELSE drop exit THEN ENDOF OF trace>depth 0> IF trace-depth- stepping drop r> recurse ELSE drop exit THEN ENDOF dup OF execute ENDOF ENDCASE forth-ip cell+ to forth-ip AGAIN ; : resume ( -- ) trace>rdepth rdepth! forth-ip cell - trace-xt ; : debug-off ( -- ) debug-last-xt IF debug-last-xt-content debug-last-xt ! \ Restore overwritten token 0 to debug-last-xt THEN ; : (break-entry) ( -- ) debug-last-xt dup @ ['] breakpoint <> swap ( debug-addr? debug-last-xt ) debug-last-xt-content swap ! \ Restore overwritten token r> drop \ Don't return to bp, but to caller debug-last-xt-content <> and IF \ Execute non colon definition debug-last-xt cr u. ." : " debug-last-xt xt>name type ." " ." ( " .s ." ) | " key drop debug-last-xt execute ELSE debug-last-xt 0 to trace>depth 0 to trace>recurse trace-xt \ Trace colon definition THEN ; ' (break-entry) to BP : debug-address ( addr -- ) debug-off ( xt ) \ Remove active breakpoint dup to debug-last-xt ( xt ) \ Save token for later debug dup @ to debug-last-xt-content ( xt ) \ Save old value ['] breakpoint swap ! ; : (debug ( xt -- ) debug-off ( xt ) \ Remove active breakpoint dup to debug-last-xt ( xt ) \ Save token for later debug dup @ to debug-last-xt-content ( xt ) \ Save old value ['] breakpoint @ swap ! ; : debug ( "old-name<>" -- ) parse-word $find IF \ Get xt for old-name (debug ELSE ." undefined word " type cr THEN ; : words last @ BEGIN ?dup WHILE dup cell+ char+ count type space @ REPEAT ; : .calls ( xt -- ) current-node @ >r 0 set-node \ only search commands, according too IEEE1275 last BEGIN @ ?dup WHILE ( xt currxt ) dup cell+ char+ ( xt currxt name* ) dup dup c@ + 1+ aligned ( xt currxt name* CFA ) dup @ = IF ( xt currxt name* CFA ) BEGIN cell+ dup @ ['] semicolon <> WHILE ( xt currxt *name pos ) dup @ 4 pick = IF ( xt currxt *name pos ) over count type space BEGIN cell+ dup @ ['] semicolon = UNTIL cell - \ eat up other occurrences THEN REPEAT THEN 2drop ( xt currxt ) REPEAT drop r> set-node \ restore node ; 0 value #sift-count false value sift-compl-only : $inner-sift ( text-addr text-len LFA -- ... word-addr word-len true | false ) dup cell+ char+ count \ get word name 2dup 6 pick 6 pick find-isubstr \ is there a partly match? sift-compl-only IF 0= ELSE over < THEN IF #sift-count 1+ to #sift-count \ count completions true ELSE 2drop false THEN ; : $sift ( text-addr text-len -- ) current-node @ >r 0 set-node \ only search commands, according too IEEE1275 sift-compl-only >r false to sift-compl-only \ all substrings, not only compl. last BEGIN @ ?dup WHILE \ walk the whole dictionary $inner-sift IF type space THEN REPEAT 2drop 0 to #sift-count \ we don't need completions here. r> to sift-compl-only \ restore previous sifting mode r> set-node \ restore node ; : sifting ( "text< >" -- ) parse-word $sift ; : ([IF]) BEGIN BEGIN parse-word dup 0= WHILE 2drop refill REPEAT 2dup s" [IF]" str= IF 1 throw THEN 2dup s" [ELSE]" str= IF 2 throw THEN 2dup s" [THEN]" str= IF 3 throw THEN s" \" str= IF linefeed parse 2drop THEN AGAIN ; : [IF] ( flag -- ) IF exit THEN 1 BEGIN ['] ([IF]) catch CASE 1 OF 1+ ENDOF 2 OF dup 1 = if 1- then ENDOF 3 OF 1- ENDOF ENDCASE dup 0 <= UNTIL drop ; immediate : [ELSE] 0 [COMPILE] [IF] ; immediate : [THEN] ; immediate : $dnumber base @ >r decimal $number r> base ! ; : (.d) base @ >r decimal (.) r> base ! ; 4000 to default-load-base deadbeef here l! here c@ de = CONSTANT ?bigendian here c@ ef = CONSTANT ?littleendian ?bigendian [IF] : x!-le >r xbflip r> x! ; : x@-le x@ xbflip ; : l!-le >r lbflip r> l! ; : l@-le l@ lbflip ; : w!-le >r wbflip r> w! ; : w@-le w@ wbflip ; : rx!-le >r xbflip r> rx! ; : rx@-le rx@ xbflip ; : rl!-le >r lbflip r> rl! ; : rl@-le rl@ lbflip ; : rw!-le >r wbflip r> rw! ; : rw@-le rw@ wbflip ; : l!-be l! ; : l@-be l@ ; : w!-be w! ; : w@-be w@ ; : rl!-be rl! ; : rl@-be rl@ ; : rw!-be rw! ; : rw@-be rw@ ; [ELSE] : x!-le x! ; : x@-le x@ ; : l!-le l! ; : l@-le l@ ; : w!-le w! ; : w@-le w@ ; : rx!-le rx! ; : rx@-le rx@ ; : rl!-le rl! ; : rl@-le rl@ ; : rw!-le rw! ; : rw@-le rw@ ; : l!-be >r lbflip r> l! ; : l@-be l@ lbflip ; : w!-be >r wbflip r> w! ; : w@-be w@ wbflip ; : rl!-be >r lbflip r> rl! ; : rl@-be rl@ lbflip ; : rw!-be >r wbflip r> rw! ; : rw@-be rw@ wbflip ; [THEN] : #join ( lo hi #bits -- x ) lshift or ; : #split ( x #bits -- lo hi ) 2dup rshift dup >r swap lshift xor r> ; : blink ; : reset-dual-emit ; : console-clean-fifo ; : bootmsg-nvupdate ; : asm-cout 2drop drop ; defer nvramlog-write-byte : .nvramlog-write-byte ( byte -- ) drop ; ' .nvramlog-write-byte to nvramlog-write-byte : nvramlog-write-string ( str len -- ) dup 0> IF 0 DO dup c@ nvramlog-write-byte char+ LOOP ELSE drop THEN drop ; : nvramlog-write-number ( number format -- ) 0 swap <# 0 ?DO # LOOP #> nvramlog-write-string ; : nvramlog-write-string-cr ( str len -- ) nvramlog-write-string a nvramlog-write-byte d nvramlog-write-byte ; : log-string ( str len -- ) type ; : log-string 2drop ; create debugstr 255 allot 0 VALUE debuglen : cp ( checkpoint -- ) bootmsg-cp ; : (warning) ( id level ptr len -- ) dup TO debuglen debugstr swap move \ copy into buffer 0 debuglen debugstr + c! \ terminate '\0' debugstr bootmsg-warning ; : warning" ( id level [text<">] -- ) postpone s" state @ IF ['] (warning) compile, ELSE (warning) THEN ; immediate : (debug-cp) ( id level ptr len -- ) dup TO debuglen debugstr swap move \ copy into buffer 0 debuglen debugstr + c! \ terminate '\0' debugstr bootmsg-debugcp ; : debug-cp" ( id level [text<">] -- ) postpone s" state @ IF ['] (debug-cp) compile, ELSE (debug-cp) THEN ; immediate : (error) ( id ptr len -- ) dup TO debuglen debugstr swap move \ copy into buffer 0 debuglen debugstr + c! \ terminate '\0' debugstr bootmsg-error ; : error" ( id level [text<">] -- ) postpone s" state @ IF ['] (error) compile, ELSE (error) THEN ; immediate bootmsg-nvupdate 000 cp STRUCT cell FIELD >r0 cell FIELD >r1 cell FIELD >r2 cell FIELD >r3 cell FIELD >r4 cell FIELD >r5 cell FIELD >r6 cell FIELD >r7 cell FIELD >r8 cell FIELD >r9 cell FIELD >r10 cell FIELD >r11 cell FIELD >r12 cell FIELD >r13 cell FIELD >r14 cell FIELD >r15 cell FIELD >r16 cell FIELD >r17 cell FIELD >r18 cell FIELD >r19 cell FIELD >r20 cell FIELD >r21 cell FIELD >r22 cell FIELD >r23 cell FIELD >r24 cell FIELD >r25 cell FIELD >r26 cell FIELD >r27 cell FIELD >r28 cell FIELD >r29 cell FIELD >r30 cell FIELD >r31 cell FIELD >cr cell FIELD >xer cell FIELD >lr cell FIELD >ctr cell FIELD >srr0 cell FIELD >srr1 cell FIELD >dar cell FIELD >dsisr CONSTANT ciregs-size : .16 10 0.r 3 spaces ; : .8 8 spaces 8 0.r 3 spaces ; : .4regs cr 4 0 DO dup @ .16 8 cells+ LOOP drop ; : .fixed-regs cr ." R0 .. R7 R8 .. R15 R16 .. R23 R24 .. R31" dup 8 0 DO dup .4regs cell+ LOOP drop ; : .special-regs cr ." CR / XER LR / CTR SRR0 / SRR1 DAR / DSISR" cr dup >cr @ .8 dup >lr @ .16 dup >srr0 @ .16 dup >dar @ .16 cr dup >xer @ .16 dup >ctr @ .16 dup >srr1 @ .16 >dsisr @ .8 ; : .regs cr .fixed-regs cr .special-regs cr cr ; : .hw-exception ( reason-code exception-nr -- ) ." ( " dup . ." ) " CASE 200 OF ." Machine Check" ENDOF 300 OF ." Data Storage" ENDOF 380 OF ." Data Segment" ENDOF 400 OF ." Instruction Storage" ENDOF 480 OF ." Instruction Segment" ENDOF 500 OF ." External" ENDOF 600 OF ." Alignment" ENDOF 700 OF ." Program" ENDOF 800 OF ." Floating-point unavailable" ENDOF 900 OF ." Decrementer" ENDOF 980 OF ." Hypervisor Decrementer" ENDOF C00 OF ." System Call" ENDOF D00 OF ." Trace" ENDOF F00 OF ." Performance Monitor" ENDOF F20 OF ." VMX Unavailable" ENDOF 1200 OF ." System Error" ENDOF 1600 OF ." Maintenance" ENDOF 1800 OF ." Thermal" ENDOF dup OF ." Unknown" ENDOF ENDCASE ." Exception [ " . ." ]" ; : .sw-exception ( exception-nr -- ) ." Exception [ " . ." ] triggered by boot firmware." ; : be-hw-exception ( [reason-code] exception-nr -- ) cr cr dup 0> IF .hw-exception ELSE .sw-exception THEN cr eregs .regs ; ' be-hw-exception to hw-exception-handler : (boot-exception-handler) ( x1...xn exception-nr -- x1...xn) dup IF dup 0 > IF negate cp 9 emit ." : " type ELSE CASE -6d OF cr ." W3411: Client application returned." cr ENDOF -6c OF cr ." E3400: It was not possible to boot from any device " ." specified in the VPD." cr ENDOF -6b OF cr ." E3410: Boot list successfully read from VPD " ." but no useful information received." cr ENDOF -6a OF cr ." E3420: Boot list could not be read from VPD." cr ENDOF -69 OF cr ." E3406: Client application returned an error" abort"-str @ count dup IF ." : " type cr ELSE ." ." cr 2drop THEN ENDOF -68 OF cr ." E3405: No such device" cr ENDOF -67 OF cr ." E3404: Not a bootable device!" cr ENDOF -66 OF cr ." E3408: Failed to claim memory for the executable" cr ENDOF -65 OF cr ." E3407: Load failed" cr ENDOF -64 OF cr ." E3403: Bad executable: " abort"-str @ count type cr ENDOF -63 OF cr ." E3409: Unknown FORTH Word" cr ENDOF -2 OF cr ." E3401: Aborting boot, " abort"-str @ count type cr ENDOF dup OF ." E3402: Aborting boot, internal error" cr ENDOF ENDCASE THEN ELSE drop THEN ; ' (boot-exception-handler) to boot-exception-handler : throw-error ( error-code "error-string" -- ) skipws 0a parse rot throw ; : enable-ext-int ( -- ) msr@ 8000 or msr! ; : disable-ext-int ( -- ) msr@ 8000 not and msr! ; : gen-ext-int ( -- ) 7fffffff dec! \ Reset decrementer enable-ext-int \ Enable interrupt FF 20000508418 rx! \ Interrupt priority mask 10 20000508410 rx! \ Interrupt priority ; : mm-log-warning 2drop ; : write-mm-log ( data length type -- status ) 3drop 0 ; 100 cp : beep bell emit ; : TABLE-EXECUTE CREATE DOES> swap cells+ @ ?dup IF execute ELSE beep THEN ; 0 VALUE accept-adr 0 VALUE accept-max 0 VALUE accept-len 0 VALUE accept-cur : esc 1b emit ; : csi esc 5b emit ; : move-cursor ( -- ) esc ." 8" accept-cur IF csi base @ decimal accept-cur 0 .r base ! ." C" THEN ; : redraw-line ( -- ) accept-cur accept-len = IF EXIT THEN move-cursor accept-adr accept-len accept-cur /string type csi ." K" move-cursor ; : full-redraw-line ( -- ) accept-cur 0 to accept-cur move-cursor accept-adr accept-len type csi ." K" to accept-cur move-cursor ; : redraw-prompt ( -- ) cr depth . [char] > emit ; : insert-char ( char -- ) accept-len accept-max = IF drop beep EXIT THEN accept-cur accept-len <> IF csi ." @" dup emit accept-adr accept-cur + dup 1+ accept-len accept-cur - move ELSE dup emit THEN accept-adr accept-cur + c! accept-cur 1+ to accept-cur accept-len 1+ to accept-len redraw-line ; : delete-char ( -- ) accept-cur accept-len = IF beep EXIT THEN accept-len 1- to accept-len accept-adr accept-cur + dup 1+ swap accept-len accept-cur - move csi ." P" redraw-line ; STRUCT cell FIELD his>next cell FIELD his>prev cell FIELD his>len 0 FIELD his>buf CONSTANT /his 0 VALUE his-head 0 VALUE his-tail 0 VALUE his-cur : add-history ( -- ) accept-len 0= IF EXIT THEN /his accept-len + alloc-mem his-tail IF dup his-tail his>next ! ELSE dup to his-head THEN his-tail over his>prev ! 0 over his>next ! dup to his-tail accept-len over his>len ! accept-adr swap his>buf accept-len move ; : history ( -- ) his-head BEGIN dup WHILE cr dup his>buf over his>len @ type his>next @ REPEAT drop ; : select-history ( his -- ) dup to his-cur dup IF dup his>len @ accept-max min dup to accept-len to accept-cur his>buf accept-adr accept-len move ELSE drop 0 to accept-len 0 to accept-cur THEN full-redraw-line ; 0 value ?tab-pressed 0 value tab-last-adr 0 value tab-last-len : $same-string ( addr-1 len-1 addr-2 len-2 -- addr-1 len-1' ) dup 0= IF \ The second parameter is not a string. 2drop EXIT \ bail out THEN rot min 0 0 -rot ( addr1 addr2 0 len' 0 ) DO ( addr1 addr2 len-1' ) 2 pick i + c@ lcc 2 pick i + c@ lcc = IF 1 + ELSE leave THEN LOOP nip ; : $tab-sift-words ( text-addr text-len -- sift-count ) sift-compl-only >r true to sift-compl-only \ save sifting mode last BEGIN @ ?dup WHILE \ loop over all words $inner-sift IF \ any completions possible? 2dup bounds DO I c@ lcc I c! LOOP ?tab-pressed IF 2dup type space THEN \ prints possibilities tab-last-adr tab-last-len $same-string \ find matching substring ... to tab-last-len to tab-last-adr \ ... and save it THEN repeat 2drop #sift-count 0 to #sift-count \ how many words were found? r> to sift-compl-only \ restore sifting completion mode ; 0 value current-stack : new-stack ( cells <>name -- ) create >r here ( here R: cells ) dup r@ 2 + cells ( here here bytes R: cells ) dup allot erase ( here R: cells) cell+ r> ( here+1cell cells ) swap ! ( ) DOES> to current-stack ; : reset-stack ( -- ) 0 current-stack ! ; : stack-depth ( -- depth ) current-stack @ ; : push ( value -- ) current-stack @ current-stack cell+ @ over <= ABORT" Stack overflow" cells 1 current-stack +! current-stack 2 cells + + ! ; : pop ( -- value ) current-stack @ 0= ABORT" Stack underflow" current-stack @ cells current-stack + cell+ @ -1 current-stack +! ; 10 new-stack device-stack : (next-dev) ( node -- node' addr len ) device-stack dup (node>path) rot dup child IF dup push child -rot EXIT THEN dup peer IF peer -rot EXIT THEN drop BEGIN stack-depth WHILE pop peer ?dup IF -rot EXIT THEN REPEAT 0 -rot ; : $inner-sift-nodes ( text-addr text-len node -- ... path-addr path-len true | false ) (next-dev) ( text-addr text-len node' path-addr path-len ) dup 0= IF drop false EXIT THEN 2dup 6 pick 6 pick find-isubstr ( text-addr text-len node' path-addr path-len pos ) 0= IF #sift-count 1+ to #sift-count \ count completions true ELSE 2drop false THEN ; : .nodes ( -- ) s" /" find-node BEGIN dup WHILE (next-dev) type cr REPEAT drop reset-stack ; create sift-node-buffer 1000 allot 0 value sift-node-num : sift-node-buffer sift-node-buffer sift-node-num 100 * + sift-node-num 1+ dup 10 = IF drop 0 THEN to sift-node-num ; : $tab-sift-nodes ( text-addr text-len -- sift-count ) s" /" find-node BEGIN dup WHILE $inner-sift-nodes IF \ any completions possible? sift-node-buffer swap 2>r 2r@ move 2r> \ make an almost permanent copy without strdup ?tab-pressed IF 2dup type space THEN \ prints possibilities tab-last-adr tab-last-len $same-string \ find matching substring ... to tab-last-len to tab-last-adr \ ... and save it THEN REPEAT 2drop drop #sift-count 0 to #sift-count \ how many words were found? reset-stack ; : $tab-sift ( text-addr text-len -- sift-count ) ?tab-pressed IF beep space THEN \ cosmetical fix for dup IF bl rsplit dup IF 2swap THEN ELSE 0 0 THEN >r >r 0 dup to tab-last-len to tab-last-adr \ reset last possible match current-node @ IF \ if we are in a node? 2dup 2>r \ save text $tab-sift-words to #sift-count \ search in current node first 2r> \ fetch text to complete, again THEN 2dup 2>r current-node @ >r 0 set-node \ now search in global words $tab-sift-words to #sift-count r> set-node 2r> $tab-sift-nodes r> r> dup IF s" " $cat THEN tab-last-adr tab-last-len $cat to tab-last-len to tab-last-adr \ ... and save the whole string ; : handle-^A 0 to accept-cur move-cursor ; : handle-^B accept-cur ?dup IF 1- to accept-cur ( csi ." D" ) move-cursor THEN ; : handle-^D delete-char ( redraw-line ) ; : handle-^E accept-len to accept-cur move-cursor ; : handle-^F accept-cur accept-len <> IF accept-cur 1+ to accept-cur csi ." C" THEN ; : handle-^H accept-cur 0= IF beep EXIT THEN handle-^B delete-char ; : handle-^I accept-adr accept-len $tab-sift 0 > IF ?tab-pressed IF redraw-prompt full-redraw-line false to ?tab-pressed ELSE tab-last-adr accept-adr tab-last-len move \ copy matching substring tab-last-len dup to accept-len to accept-cur \ len and cursor position full-redraw-line \ redraw new string true to ?tab-pressed \ second tab will print possible matches THEN THEN ; : handle-^K BEGIN accept-cur accept-len <> WHILE delete-char REPEAT ; : handle-^L history redraw-prompt full-redraw-line ; : handle-^N his-cur IF his-cur his>next @ ELSE his-head THEN dup to his-cur select-history ; : handle-^P his-cur IF his-cur his>prev @ ELSE his-tail THEN dup to his-cur select-history ; : handle-^Q \ Does not handle terminal formatting yet. key insert-char ; : handle-^R full-redraw-line ; : handle-^U 0 to accept-len 0 to accept-cur full-redraw-line ; : handle-fn key drop beep ; TABLE-EXECUTE handle-CSI 0 , ' handle-^P , ' handle-^N , ' handle-^F , ' handle-^B , 0 , 0 , 0 , ' handle-^A , 0 , 0 , ' handle-^E , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , : handle-CSI-key key 1f and handle-CSI ; TABLE-EXECUTE handle-meta 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ' handle-fn , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ' handle-CSI-key , 0 , 0 , 0 , 0 , : handle-ESC-O key dup 48 = IF handle-^A ELSE dup 46 = IF handle-^E THEN THEN drop ; : handle-ESC-5b key dup 31 = IF \ HOME key drop ( drops closing 7e ) handle-^A ELSE dup 33 = IF \ DEL key drop handle-^D ELSE dup 34 = IF \ END key drop handle-^E ELSE dup 1f and handle-CSI THEN THEN THEN drop ; : handle-ESC key dup 5b = IF handle-ESC-5b ELSE dup 4f = IF handle-ESC-O ELSE dup 1f and handle-meta THEN THEN drop ; TABLE-EXECUTE handle-control 0 , \ ^@: ' handle-^A , ' handle-^B , 0 , \ ^C: ' handle-^D , ' handle-^E , ' handle-^F , 0 , \ ^G: ' handle-^H , ' handle-^I , \ tab 0 , \ ^J: ' handle-^K , ' handle-^L , 0 , \ ^M: enter: handled in main loop ' handle-^N , 0 , \ ^O: ' handle-^P , ' handle-^Q , ' handle-^R , 0 , \ ^S: 0 , \ ^T: ' handle-^U , 0 , \ ^V: 0 , \ ^W: 0 , \ ^X: 0 , \ ^Y: insert save buffer 0 , \ ^Z: ' handle-ESC , 0 , \ ^\: 0 , \ ^]: 0 , \ ^^: 0 , \ ^_: : (accept) ( adr len -- len' ) cursor-on to accept-max to accept-adr 0 to accept-len 0 to accept-cur 0 to his-cur 1b emit 37 emit BEGIN key dup 0d <> WHILE dup 9 <> IF 0 to ?tab-pressed THEN \ reset state machine dup 7f = IF drop 8 THEN \ Handle DEL as if it was BS. ??? bogus dup bl < IF handle-control ELSE dup 80 and IF dup a0 < IF 7f and handle-meta ELSE drop beep THEN ELSE insert-char THEN THEN REPEAT drop add-history accept-len to accept-cur move-cursor space accept-len cursor-off ; ' (accept) to accept 120 cp 1 VALUE /dump ' c@ VALUE 'dump 0 VALUE dump-first 0 VALUE dump-last 0 VALUE dump-cur : .char ( c -- ) dup bl 7f within 0= IF drop [char] . THEN emit ; : dump-line ( -- ) cr dump-cur dup 8 0.r [char] : emit 10 /dump / 0 DO space dump-cur dump-first dump-last within IF dump-cur 'dump execute /dump 2* 0.r ELSE /dump 2* spaces THEN dump-cur /dump + to dump-cur LOOP /dump 1 <> IF drop EXIT THEN to dump-cur 2 spaces 10 0 DO dump-cur dump-first dump-last within IF dump-cur 'dump execute .char ELSE space THEN dump-cur 1+ to dump-cur LOOP ; : (dump) ( addr len reader size -- ) to /dump to 'dump bounds /dump negate and to dump-first to dump-last dump-first f invert and to dump-cur base @ hex BEGIN dump-line dump-cur dump-last >= UNTIL base ! ; : du ( -- ) dump-last 100 'dump /dump (dump) ; : dump ['] c@ 1 (dump) ; : wdump ['] w@ 2 (dump) ; : ldump ['] l@ 4 (dump) ; : xdump ['] x@ 8 (dump) ; : rdump ['] rb@ 1 (dump) ; cistack ciregs >r1 ! \ kernel wants a stack :-) 140 cp STRUCT cell field romfs>file-header cell field romfs>data cell field romfs>data-size cell field romfs>flags CONSTANT /romfs-lookup-control-block CREATE romfs-lookup-cb /romfs-lookup-control-block allot romfs-lookup-cb /romfs-lookup-control-block erase : create-filename ( string -- string\0 ) here >r dup 8 + allot r@ over 8 + erase r@ zplace r> ; : romfs-lookup ( fn-str fn-len -- data size | false ) create-filename romfs-base romfs-lookup-cb romfs-lookup-entry call-c 0= IF romfs-lookup-cb dup romfs>data @ swap romfs>data-size @ ELSE false THEN ; : ibm,romfs-lookup ( fn-str fn-len -- data-high data-low size | 0 0 false ) romfs-lookup dup 0= if drop 0 0 false else swap dup 20 rshift swap ffffffff and then ; : romfs-lookup-client ibm,romfs-lookup ; STRUCT cell field romfs>next-off cell field romfs>size cell field romfs>flags cell field romfs>data-off cell field romfs>name CONSTANT /romfs-cb : romfs-map-file ( fn-str fn-len -- file-addr file-size ) romfs-base >r BEGIN 2dup r@ romfs>name zcount string=ci not WHILE ( fn-str fn-len ) ( R: rom-cb-file-addr ) r> romfs>next-off dup @ dup 0= IF 1 THROW THEN + >r REPEAT ( fn-str fn-len ) ( R: rom-cb-file-addr ) 2drop r@ romfs>data-off @ r@ + r> romfs>size @ ; : flash-header ( -- address | false ) get-flash-base 28 + \ prepare flash header file address dup rx@ \ fetch "magic123" 6d61676963313233 <> IF \ IF flash is not valid drop \ | forget address false \ | return false THEN \ FI ; CREATE bdate-str 10 allot : bdate2human ( -- addr len ) flash-header 40 + rx@ (.) drop dup 0 + bdate-str 6 + 4 move dup 4 + bdate-str 0 + 2 move dup 6 + bdate-str 3 + 2 move dup 8 + bdate-str b + 2 move a + bdate-str e + 2 move 2d bdate-str 2 + c! 2d bdate-str 5 + c! 20 bdate-str a + c! 3a bdate-str d + c! bdate-str 10 ; : included ( fn fn-len -- ) 2dup >r >r romfs-lookup dup IF r> drop r> drop evaluate ELSE drop ." Cannot open file : " r> r> type cr THEN ; : include ( " fn " -- ) parse-word included ; : ?include ( flag " fn " -- ) parse-word rot IF included ELSE 2drop THEN ; : include? ( nargs flag " fn " -- ) parse-word rot IF rot drop included ELSE 2drop 0 ?DO drop LOOP THEN ; : (print-romfs-file-info) ( file-addr -- ) 9 emit dup b 0.r 2 spaces dup 8 + @ 6 0.r 2 spaces 20 + zcount type cr ; : romfs-list ( -- ) romfs-base 0 cr BEGIN + dup (print-romfs-file-info) dup @ dup 0= UNTIL 2drop ; 200 cp : banner cr ." Type 'boot' and press return to continue booting the system." cr ." Type 'reset-all' and press return to reboot the system." cr cr ; : .banner banner console-clean-fifo ; DEFER find-boot-sector ( -- ) 240 cp d# 512000000 VALUE tb-frequency \ default value - needed for "ms" to work -1 VALUE cpu-frequency : slof-build-id ( -- str len ) flash-header 10 + dup from-cstring a min ; : slof-revision s" 001" ; : read-version-and-date flash-header 0= IF s" " encode-string ELSE flash-header 10 + 10 here swap rmove here 10 s" , " $cat bdate2human $cat encode-string THEN ; : invert-region-cs ( addr len cellsize -- ) >r over swap r@ rshift r> swap 1 hv-logical-memop drop ; : invert-region ( addr len -- ) 2dup or 7 and CASE 0 OF 3 invert-region-cs ENDOF 4 OF 2 invert-region-cs ENDOF 3 and 2 OF 1 invert-region-cs ENDOF dup OF 0 invert-region-cs ENDOF ENDCASE ; 260 cp : tb@ ( -- tb ) BEGIN tbu@ tbl@ tbu@ rot over <> WHILE 2drop REPEAT 20 lshift swap ffffffff and or ; : milliseconds ( -- ms ) tb@ d# 1000 * tb-frequency / ; : microseconds ( -- us ) tb@ d# 1000000 * tb-frequency / ; : ms ( ms-to-wait -- ) milliseconds + BEGIN milliseconds over >= UNTIL drop ; : get-msecs ( -- n ) milliseconds ; : us ( us-to-wait -- ) microseconds + BEGIN microseconds over >= UNTIL drop ; 2e0 cp 100 CONSTANT quiesce-xt# CREATE quiesce-xts quiesce-xt# cells allot quiesce-xts quiesce-xt# cells erase 0 VALUE quiesce-done? : add-quiesce-xt ( xt -- ) quiesce-xt# 0 DO quiesce-xts I cells + ( xt arrayptr ) dup @ 0= ( xt arrayptr true|false ) IF ! UNLOOP EXIT ELSE ( xt arrayptr ) over swap ( xt xt arrayptr ) @ = \ xt already stored ? IF drop UNLOOP EXIT THEN ( xt ) THEN LOOP drop ( xt -- ) ." Warning: quiesce xt list is full." cr ; : quiesce ( -- ) quiesce-done? IF EXIT THEN true to quiesce-done? quiesce-xt# 0 DO quiesce-xts I cells + ( arrayptr ) @ dup IF ( xt ) EXECUTE ELSE drop UNLOOP EXIT THEN LOOP ; 300 cp : load-dev-hci ( num name-str name-len ) s" dev-hci.fs" INCLUDED ; 0 VALUE ohci-init 0 VALUE ehci-init 0 VALUE xhci-init 0 VALUE usb-alias-num : get-usb-alias-num usb-alias-num dup 1+ to usb-alias-num ; : set-ohci-alias ( -- ) 1 to ohci-init get-usb-alias-num ( num ) s" ohci" 1 load-dev-hci ; : set-ehci-alias ( -- ) 1 to ehci-init get-usb-alias-num ( num ) s" ehci" 2 load-dev-hci ; : set-xhci-alias ( -- ) 1 to xhci-init get-usb-alias-num ( num ) s" xhci" 3 load-dev-hci ; : usb-enumerate ( hcidev -- ) USB-HCD-INIT ; : usb-scan ( -- ) ." Scanning USB " cr ohci-init 1 = IF USB-OHCI-REGISTER THEN ehci-init 1 = IF USB-EHCI-REGISTER THEN xhci-init 1 = IF USB-XHCI-REGISTER THEN usb-alias-num 0 ?DO " usb" i $cathex find-device " get-hci-dev" get-node find-method IF execute usb-enumerate ELSE ." get-base-address method not found for usb@" i . ." Device type: " " device_type" get-node get-property 0= IF decode-string type cr 2drop THEN THEN LOOP 0 set-node \ FIXME Setting it back ; 320 cp false VALUE scsi-supp-present? : scsi-xt-err ." SCSI-ERROR (Intern) " ; ' scsi-xt-err VALUE scsi-open-xt \ preset with an invalid token : .wordlists ( -- ) get-order ( -- wid1 .. widn n ) dup space 28 emit .d ." word lists : " 0 DO . 08 emit 2c emit LOOP 08 emit \ 'bs' 29 emit \ ')' cr space 28 emit ." Context: " context dup . @ 5b emit . 8 emit 5d emit space ." / Current: " current . cr ; : scsi-open ( -- ) scsi-supp-present? NOT IF s" scsi-support.fs" included ( xt-open ) to scsi-open-xt ( ) true to scsi-supp-present? THEN scsi-open-xt execute ; 340 cp 0 VALUE fdt-debug TRUE VALUE fdt-cas-fix? fdt-start 0 = IF -1 throw THEN struct 4 field >fdth_magic 4 field >fdth_tsize 4 field >fdth_struct_off 4 field >fdth_string_off 4 field >fdth_rsvmap_off 4 field >fdth_version 4 field >fdth_compat_vers 4 field >fdth_boot_cpu 4 field >fdth_string_size 4 field >fdth_struct_size constant /fdth h# d00dfeed constant OF_DT_HEADER h# 1 constant OF_DT_BEGIN_NODE h# 2 constant OF_DT_END_NODE h# 3 constant OF_DT_PROP h# 4 constant OF_DT_NOP h# 9 constant OF_DT_END 0 value fdt-start-addr 0 value fdt-struct 0 value fdt-strings : fdt-init ( fdt-start -- ) dup to fdt-start-addr dup dup >fdth_struct_off l@ + to fdt-struct dup dup >fdth_string_off l@ + to fdt-strings drop ; fdt-start fdt-init : fdt-check-header ( -- ) fdt-start-addr dup 0 = IF ." No flat device tree !" cr drop -1 throw EXIT THEN hex fdt-debug IF ." Flat device tree header at 0x" dup . s" :" type cr ." magic : 0x" dup >fdth_magic l@ . cr ." total size : 0x" dup >fdth_tsize l@ . cr ." offset to struct : 0x" dup >fdth_struct_off l@ . cr ." offset to strings: 0x" dup >fdth_string_off l@ . cr ." offset to rsvmap : 0x" dup >fdth_rsvmap_off l@ . cr ." version : " dup >fdth_version l@ decimal . hex cr ." last compat vers : " dup >fdth_compat_vers l@ decimal . hex cr dup >fdth_version l@ 2 >= IF ." boot CPU : 0x" dup >fdth_boot_cpu l@ . cr THEN dup >fdth_version l@ 3 >= IF ." strings size : 0x" dup >fdth_string_size l@ . cr THEN dup >fdth_version l@ 11 >= IF ." struct size : 0x" dup >fdth_struct_size l@ . cr THEN THEN dup >fdth_magic l@ OF_DT_HEADER <> IF ." Flat device tree has incorrect magic value !" cr drop -1 throw EXIT THEN dup >fdth_version l@ 10 < IF ." Flat device tree has usupported version !" cr drop -1 throw EXIT THEN drop ; fdt-check-header : fdt-next-tag ( addr -- nextaddr tag ) 0 ( dummy tag on stack for loop ) BEGIN drop ( drop previous tag ) dup l@ ( read new tag ) swap 4 + swap ( increment addr ) dup OF_DT_NOP <> UNTIL ( loop until not nop ) ; : fdt-fetch-unit ( addr -- addr $name ) dup from-cstring \ get string size 2dup + 1 + 3 + fffffffc and -rot ; : fdt-reg-unit ( prop-addr prop-len -- ) decode-phys ( prop-addr' prop-len' phys.lo ... phys.hi ) set-unit ( prop-addr' prop-len' ) 2drop ; : fdt-fetch-string ( index -- str-addr str-len ) fdt-strings + dup from-cstring ; : fdt-create-dec s" decode-unit" $CREATE , DOES> @ hex64-decode-unit ; : fdt-create-enc s" encode-unit" $CREATE , DOES> @ hex64-encode-unit ; : fdt-prop-is-string? ( addr len -- string? ) dup 1 < IF 2drop FALSE EXIT THEN \ Check for valid length 1- 2dup + c@ 0<> IF 2drop FALSE EXIT THEN \ Check zero-termination test-string ; : fdt-encode-prop ( addr len -- ) 2dup fdt-prop-is-string? IF 1- encode-string ELSE encode-bytes THEN ; : fdt-unflatten-node ( start -- end ) recursive fdt-next-tag dup OF_DT_BEGIN_NODE <> IF s" Weird tag 0x" type . " at start of node" type cr -1 throw THEN drop new-device fdt-fetch-unit dup 0 = IF drop drop " /" THEN 40 left-parse-string device-name dup IF " #address-cells" get-parent get-package-property IF 2drop ELSE decode-int nip nip hex-decode-unit set-unit THEN ELSE 2drop THEN BEGIN fdt-next-tag dup OF_DT_END_NODE <> WHILE dup OF_DT_PROP = IF drop dup ( drop tag, dup addr : a1 a1 ) dup l@ dup rot 4 + ( fetch size, stack is : a1 s s a2) dup l@ swap 4 + ( fetch nameid, stack is : a1 s s i a3 ) rot ( we now have: a1 s i a3 s ) fdt-encode-prop rot ( a1 s pa ps i) fdt-fetch-string ( a1 s pa ps na ns ) 2dup s" reg" str= IF 2swap 2dup fdt-reg-unit 2swap THEN property + 8 + 3 + fffffffc and ELSE dup OF_DT_BEGIN_NODE = IF drop ( drop tag ) 4 - fdt-unflatten-node ELSE drop -1 throw THEN THEN REPEAT drop \ drop tag " #address-cells" get-node get-package-property IF ELSE decode-int dup fdt-create-dec fdt-create-enc 2drop THEN finish-device ; : fdt-unflatten-tree fdt-debug IF ." Unflattening device tree..." cr THEN fdt-struct fdt-unflatten-node drop fdt-debug IF ." Done !" cr THEN ; fdt-unflatten-tree : fdt-parse-memory " /memory@0" find-device " reg" get-node get-package-property IF throw -1 THEN decode-phys 2drop decode-phys my-#address-cells 1 > IF 20 << or THEN fdt-debug IF dup ." Memory size: " . cr THEN MIN-RAM-SIZE swap MIN-RAM-SIZE - release 2drop device-end ; fdt-parse-memory : fdt-claim-reserve fdt-start-addr dup dup >fdth_tsize l@ 0 claim drop dup >fdth_rsvmap_off l@ + BEGIN dup dup x@ swap 8 + x@ dup 0 <> WHILE fdt-debug IF 2dup swap ." Reserve map entry: " . ." : " . cr THEN 0 claim drop 10 + REPEAT drop drop drop ; fdt-claim-reserve 0 VALUE (fdt-phandle-replaced) : fdt-replace-interrupt-map ( old new prop-addr prop-len -- old new ) BEGIN dup ( old new prop-addr prop-len prop-len ) WHILE swap dup 10 + ( old new prop-len prop-addr prop-addr+10 ) dup l@ 5 pick = IF 3 pick swap l! TRUE TO (fdt-phandle-replaced) ELSE drop THEN 1c + swap 1c - REPEAT 2drop ; : (fdt-replace-phandles) ( old new propname propnamelen node -- ) get-property IF 2drop EXIT THEN BEGIN dup WHILE ( old new prop-addr prop-len ) over l@ 4 pick = IF 2 pick 2 pick l! \ replace old with new in place TRUE TO (fdt-phandle-replaced) THEN 4 - swap 4 + swap REPEAT 2drop 2drop ; : fdt-replace-all-phandles ( old new node -- ) >r s" interrupt-map" r@ get-property 0= IF fdt-replace-interrupt-map THEN 2dup s" interrupt-parent" r@ (fdt-replace-phandles) 2dup s" ibm,gpu" r@ (fdt-replace-phandles) 2dup s" ibm,npu" r@ (fdt-replace-phandles) 2dup s" ibm,nvlink" r@ (fdt-replace-phandles) 2dup s" memory-region" r@ (fdt-replace-phandles) r> child BEGIN dup WHILE 3dup RECURSE PEER REPEAT 3drop ; : fdt-update-phandle ( val node -- ) >r FALSE TO (fdt-phandle-replaced) r@ s" /" find-node ( val node root ) fdt-replace-all-phandles (fdt-phandle-replaced) IF r@ set-node s" phandle" delete-property s" linux,phandle" delete-property ELSE diagnostic-mode? IF cr ." Warning: Did not replace phandle in " r@ node>path type cr THEN THEN r> drop ; : fdt-fix-node-phandle ( node -- ) >r s" phandle" r@ get-property 0= IF decode-int nip nip r@ fdt-update-phandle THEN r> drop ; : fdt-fix-phandles ( node -- ) dup fdt-fix-node-phandle child BEGIN dup WHILE dup RECURSE PEER REPEAT drop device-end ; : fdt-create-cas-node ( name -- ) 2dup 2dup " memory@" find-substr 0 = IF fdt-debug IF ." Creating memory@ " cr THEN new-device 2dup " @" find-substr nip device-name \ Parse the node name 2dup 2dup " @" find-substr rot over + 1 + -rot - 1 - \ Jump to addr afte "@" parse-2int nip xlsplit set-unit \ Parse and set unit finish-device ELSE 2dup " ibm,dynamic-reconfiguration-memory" find-substr 0 = IF fdt-debug IF ." Creating ibm,dynamic-reconfiguration-memory " cr THEN new-device device-name finish-device ELSE 2drop 2drop false to fdt-cas-fix? ." Node not supported " cr EXIT THEN THEN find-node ?dup 0 <> IF set-node THEN ; : fdt-fix-cas-node ( start -- end ) recursive fdt-next-tag dup OF_DT_BEGIN_NODE <> IF ." Error " cr false to fdt-cas-fix? EXIT THEN drop fdt-fetch-unit dup 0 = IF drop drop " /" THEN 40 left-parse-string 2swap ?dup 0 <> IF nip 1 + + \ Add the string len +@ ELSE drop THEN fdt-debug IF ." Setting node: " 2dup type cr THEN 2dup find-node ?dup 0 <> IF set-node 2drop ELSE fdt-debug IF ." Node not found, creating " 2dup type cr THEN fdt-create-cas-node THEN fdt-debug IF ." Current now: " pwd cr THEN BEGIN fdt-next-tag dup OF_DT_END_NODE <> WHILE dup OF_DT_PROP = IF fdt-debug IF ." Found property " cr THEN drop dup ( drop tag, dup addr : a1 a1 ) dup l@ dup rot 4 + ( fetch size, stack is : a1 s s a2) dup l@ swap 4 + ( fetch nameid, stack is : a1 s s i a3 ) rot ( we now have: a1 s i a3 s ) fdt-encode-prop rot ( a1 s pa ps i) fdt-fetch-string ( a1 s pa ps na ns ) property fdt-debug IF ." Setting property done " cr THEN + 8 + 3 + fffffffc and ELSE dup OF_DT_BEGIN_NODE = IF drop ( drop tag ) 4 - fdt-fix-cas-node get-parent set-node fdt-debug IF ." Returning back " pwd cr THEN ELSE ." Error " cr drop false to fdt-cas-fix? EXIT THEN THEN REPEAT drop \ drop tag ; : fdt-fix-cas-success fdt-cas-fix? ; s" /" find-node fdt-fix-phandles 360 cp defer (client-exec) defer client-exec defer callback defer continue-client 0 VALUE chosen-node : chosen chosen-node dup 0= IF drop s" /chosen" find-node dup to chosen-node THEN ; : set-chosen ( prop len name len -- ) chosen set-property ; : get-chosen ( name len -- [ prop len ] success ) chosen get-property 0= ; VARIABLE chosen-cpu-ihandle : set-chosen-cpu ( -- ) s" /cpus" find-node dup 0= ABORT" /cpus not found" child dup 0= ABORT" /cpus/cpu not found" 0 0 rot open-node dup chosen-cpu-ihandle ! encode-int s" cpu" set-chosen ; : chosen-cpu-unit ( -- ret ) chosen-cpu-ihandle @ ihandle>phandle >unit ; " /" find-node dup 0= IF drop new-device s" /" device-name ELSE extend-device THEN " /chosen" find-node dup 0= IF drop new-device s" chosen" device-name s" " encode-string s" bootargs" property s" " encode-string s" bootpath" property finish-device ELSE drop THEN new-device s" aliases" device-name : open true ; : close ; finish-device new-device s" options" device-name finish-device new-device s" openprom" device-name 0 0 s" relative-addressing" property finish-device new-device s" packages" device-name get-node to packages new-device s" deblocker" device-name INSTANCE VARIABLE offset INSTANCE VARIABLE block-size INSTANCE VARIABLE max-transfer INSTANCE VARIABLE my-block INSTANCE VARIABLE adr INSTANCE VARIABLE len INSTANCE VARIABLE fail-count : open s" block-size" ['] $call-parent CATCH IF 2drop false EXIT THEN block-size ! s" max-transfer" ['] $call-parent CATCH IF 2drop false EXIT THEN max-transfer ! block-size @ alloc-mem my-block ! 0 offset ! true ; : close my-block @ block-size @ free-mem ; : seek ( lo hi -- status ) \ XXX: perhaps we should fail if the underlying lxjoin offset ! 0 ; : block+remainder ( -- block# remainder ) offset @ block-size @ u/mod swap ; : read-blocks ( addr block# #blocks -- actual ) s" read-blocks" $call-parent ; : read ( addr len -- actual ) dup >r len ! adr ! block+remainder dup IF ( block# offset-in-block ) >r my-block @ swap 1 read-blocks drop my-block @ r@ + adr @ block-size @ r> - len @ min dup >r move r> dup negate len +! dup adr +! offset +! ELSE 2drop THEN 0 fail-count ! BEGIN len @ block-size @ >= WHILE adr @ block+remainder drop len @ max-transfer @ min block-size @ / read-blocks dup 0= IF 1 fail-count +! fail-count @ 5 >= IF r> drop EXIT THEN ELSE 0 fail-count ! THEN block-size @ * dup negate len +! dup adr +! offset +! REPEAT len @ IF my-block @ block+remainder drop 1 read-blocks drop my-block @ adr @ len @ move THEN r> ; : write-blocks ( addr block# #blocks -- #writtenblks ) s" write-blocks" $call-parent ; : write ( addr len -- actual ) dup block-size @ mod IF ." ERROR: Can not write partial sector length." cr 2drop 0 EXIT THEN block-size @ / ( addr #blocks ) offset @ ( addr #blocks offset ) dup block-size @ mod IF ." ERROR: Can not write at partial sector offset." cr 3drop 0 EXIT THEN block-size @ / swap ( addr block# #blocks ) write-blocks ( #writtenblks ) block-size @ * dup offset +! ; finish-device new-device false VALUE debug-disk-label? d# 65536 value max-prep-partition-blocks d# 4096 CONSTANT block-array-size s" disk-label" device-name 0 INSTANCE VALUE partition 0 INSTANCE VALUE part-offset 0 INSTANCE VALUE disk-chrp-boot 0 INSTANCE VALUE part-start 0 INSTANCE VALUE lpart-start 0 INSTANCE VALUE part-size 0 INSTANCE VALUE dos-logical-partitions 0 INSTANCE VALUE block-size 0 INSTANCE VALUE block 0 INSTANCE VALUE args 0 INSTANCE VALUE args-len 0 INSTANCE VALUE gpt-part-size 0 INSTANCE VALUE seek-pos INSTANCE VARIABLE block# \ variable to store logical sector# INSTANCE VARIABLE hit# \ partition counter INSTANCE VARIABLE success-flag 0ff constant END-OF-DESC 3 constant PARTITION-ID 48 constant VOL-PART-LOC STRUCT 1b8 field mbr>boot-loader /l field mbr>disk-signature /w field mbr>null 40 field mbr>partition-table /w field mbr>magic CONSTANT /mbr STRUCT /c field part-entry>active /c field part-entry>start-head /c field part-entry>start-sect /c field part-entry>start-cyl /c field part-entry>id /c field part-entry>end-head /c field part-entry>end-sect /c field part-entry>end-cyl /l field part-entry>sector-offset /l field part-entry>sector-count CONSTANT /partition-entry STRUCT 8 field gpt>signature 4 field gpt>revision 4 field gpt>header-size 4 field gpt>header-crc32 4 field gpt>reserved 8 field gpt>current-lba 8 field gpt>backup-lba 8 field gpt>first-lba 8 field gpt>last-lba 10 field gpt>disk-guid 8 field gpt>part-entry-lba 4 field gpt>num-part-entry 4 field gpt>part-entry-size 4 field gpt>part-array-crc32 1a4 field gpt>reserved CONSTANT /gpt-header STRUCT 10 field gpt-part-entry>part-type-guid 10 field gpt-part-entry>part-guid 8 field gpt-part-entry>first-lba 8 field gpt-part-entry>last-lba 8 field gpt-part-entry>attribute 48 field gpt-part-entry>part-name CONSTANT /gpt-part-entry : offset ( d.rel -- d.abs ) part-offset xlsplit d+ ; : seek ( pos.lo pos.hi -- status ) offset debug-disk-label? IF 2dup ." seek-parent: pos.hi=0x" u. ." pos.lo=0x" u. THEN s" seek" $call-parent debug-disk-label? IF dup ." status=" . cr THEN ; : read ( addr len -- actual ) debug-disk-label? IF 2dup swap ." read-parent: addr=0x" u. ." len=" .d THEN s" read" $call-parent debug-disk-label? IF dup ." actual=" .d cr THEN ; : write ( addr len -- actual ) debug-disk-label? IF 2dup swap ." write-parent: addr=0x" u. ." len=" .d THEN s" write" $call-parent debug-disk-label? IF dup ." actual=" .d cr THEN ; : read-sector ( sector-number -- ) block-size * 0 seek drop \ seek to sector block block-size read drop \ read sector ; : (.part-entry) ( part-entry ) cr ." part-entry>active: " dup part-entry>active c@ .d cr ." part-entry>start-head: " dup part-entry>start-head c@ .d cr ." part-entry>start-sect: " dup part-entry>start-sect c@ .d cr ." part-entry>start-cyl: " dup part-entry>start-cyl c@ .d cr ." part-entry>id: " dup part-entry>id c@ .d cr ." part-entry>end-head: " dup part-entry>end-head c@ .d cr ." part-entry>end-sect: " dup part-entry>end-sect c@ .d cr ." part-entry>end-cyl: " dup part-entry>end-cyl c@ .d cr ." part-entry>sector-offset: " dup part-entry>sector-offset l@-le .d cr ." part-entry>sector-count: " dup part-entry>sector-count l@-le .d cr ; : (.name) r@ begin cell - dup @ = UNTIL xt>name cr type space ; : init-block ( -- ) s" block-size" ['] $call-parent CATCH IF ABORT" parent has no block-size." THEN to block-size block-array-size alloc-mem dup block-array-size erase to block debug-disk-label? IF ." init-block: block-size=" block-size .d ." block=0x" block u. cr THEN ; : partition>part-entry ( partition -- part-entry ) 1- /partition-entry * block mbr>partition-table + ; : partition>start-sector ( partition -- sector-offset ) partition>part-entry part-entry>sector-offset l@-le ; : no-mbr? ( -- true|false ) 0 read-sector 1 partition>part-entry part-entry>id c@ ee = IF TRUE EXIT THEN \ GPT partition found block mbr>magic w@-le aa55 <> ; : no-gpt? ( -- true|false ) 0 read-sector 1 partition>part-entry part-entry>id c@ ee <> IF true EXIT THEN block mbr>magic w@-le aa55 <> ; : pc-extended-partition? ( part-entry-addr -- true|false ) part-entry>id c@ ( id ) dup 5 = swap ( true|false id ) dup f = swap ( true|false true|false id ) 85 = ( true|false true|false true|false ) or or ( true|false ) ; : count-dos-logical-partitions ( -- #logical-partitions ) no-mbr? IF 0 EXIT THEN 0 5 1 DO ( current ) i partition>part-entry ( current part-entry ) dup pc-extended-partition? IF part-entry>sector-offset l@-le ( current sector ) dup to part-start to lpart-start ( current ) BEGIN part-start read-sector \ read EBR 1 partition>start-sector IF 1+ THEN \ another logical partition 2 partition>start-sector ?dup IF lpart-start + to part-start false ELSE true THEN UNTIL ELSE drop THEN LOOP ; : (get-dos-partition-params) ( ext-part-start part-entry -- offset count active? id ) dup part-entry>sector-offset l@-le rot + swap ( offset part-entry ) dup part-entry>sector-count l@-le swap ( offset count part-entry ) dup part-entry>active c@ 80 = swap ( offset count active? part-entry ) part-entry>id c@ ( offset count active? id ) ; : find-dos-partition ( partition# -- false | offset count active? id true ) to partition 0 to part-start 0 to part-offset partition 0<= IF 0 to partition false EXIT THEN no-mbr? IF 0 to partition false EXIT THEN partition 4 <= IF \ Is this a primary partition? 0 partition partition>part-entry (get-dos-partition-params) true EXIT ELSE partition 4 - 0 5 1 DO ( logical-partition current ) i partition>part-entry ( log-part current part-entry ) dup pc-extended-partition? IF part-entry>sector-offset l@-le ( log-part current sector ) dup to part-start to lpart-start ( log-part current ) BEGIN part-start read-sector \ read EBR 1 partition>start-sector IF \ first partition entry 1+ 2dup = IF ( log-part current ) 2drop part-start 1 partition>part-entry (get-dos-partition-params) true UNLOOP EXIT THEN 2 partition>start-sector ?dup IF lpart-start + to part-start false ELSE true THEN ELSE true THEN UNTIL ELSE drop THEN LOOP 2drop false THEN ; : try-dos-partition ( -- okay? ) no-mbr? IF debug-disk-label? IF cr ." No DOS disk-label found." cr THEN false EXIT THEN count-dos-logical-partitions TO dos-logical-partitions debug-disk-label? IF ." Found " dos-logical-partitions .d ." logical partitions" cr ." Partition = " partition .d cr THEN partition 1 5 dos-logical-partitions + within 0= IF cr ." Partition # not 1-" 4 dos-logical-partitions + . cr false EXIT THEN partition find-dos-partition IF 2drop to part-size block-size * to part-offset true ELSE false THEN ; : has-iso9660-filesystem ( -- TRUE|FALSE ) 10 800 * 0 seek drop \ seek to sector block 800 read drop \ read sector block c@ 1 = block 1+ 5 s" CD001" str= and dup IF 800 to block-size THEN ; : fat-bootblock? ( addr -- flag ) dup c@ e9 = IF drop true EXIT THEN dup c@ eb = swap 2+ c@ 90 = and ; : load-from-dos-boot-partition ( addr -- size ) no-mbr? IF drop FALSE EXIT THEN \ read MBR and check for DOS disk-label magic count-dos-logical-partitions TO dos-logical-partitions debug-disk-label? IF ." Found " dos-logical-partitions .d ." logical partitions" cr ." Partition = " partition .d cr THEN 5 dos-logical-partitions + 1 DO i find-dos-partition IF ( addr offset count active? id ) 41 = and ( addr offset count prep-boot-part? ) IF ( addr offset count ) max-prep-partition-blocks min \ reduce load size swap ( addr count offset ) block-size * to part-offset 0 0 seek drop ( addr offset ) block-size * read ( size ) UNLOOP EXIT ELSE 2drop ( addr ) THEN THEN LOOP drop 0 ; 9E1A2D38 CONSTANT GPT-PREP-PARTITION-1 C612 CONSTANT GPT-PREP-PARTITION-2 4316 CONSTANT GPT-PREP-PARTITION-3 AA268B49521E5A8B CONSTANT GPT-PREP-PARTITION-4 : gpt-prep-partition? ( -- true|false ) block gpt-part-entry>part-type-guid dup l@-le GPT-PREP-PARTITION-1 <> IF drop false EXIT THEN dup 4 + w@-le GPT-PREP-PARTITION-2 <> IF drop false EXIT THEN dup 6 + w@-le GPT-PREP-PARTITION-3 <> IF drop false EXIT THEN 8 + x@ GPT-PREP-PARTITION-4 = ; EBD0A0A2 CONSTANT GPT-BASIC-DATA-PARTITION-1 B9E5 CONSTANT GPT-BASIC-DATA-PARTITION-2 4433 CONSTANT GPT-BASIC-DATA-PARTITION-3 87C068B6B72699C7 CONSTANT GPT-BASIC-DATA-PARTITION-4 : gpt-basic-data-partition? ( -- true|false ) block gpt-part-entry>part-type-guid dup l@-le GPT-BASIC-DATA-PARTITION-1 <> IF drop false EXIT THEN dup 4 + w@-le GPT-BASIC-DATA-PARTITION-2 <> IF drop false EXIT THEN dup 6 + w@-le GPT-BASIC-DATA-PARTITION-3 <> IF drop false EXIT THEN 8 + x@ GPT-BASIC-DATA-PARTITION-4 = ; 4546492050415254 CONSTANT GPT-SIGNATURE : get-gpt-partition ( -- true|false ) no-gpt? IF false EXIT THEN debug-disk-label? IF cr ." GPT partition found " cr THEN 1 read-sector block gpt>part-entry-lba x@-le block-size * to seek-pos block gpt>part-entry-size l@-le to gpt-part-size gpt-part-size block-array-size > IF cr ." GPT part size exceeds buffer allocated " cr false exit THEN block gpt>signature x@ GPT-SIGNATURE = ; : load-from-gpt-prep-partition ( addr -- size ) get-gpt-partition 0= IF false EXIT THEN block gpt>num-part-entry l@-le dup 0= IF false exit THEN 1+ 1 ?DO seek-pos 0 seek drop block gpt-part-size read drop gpt-prep-partition? IF debug-disk-label? IF ." GPT PReP partition found " cr THEN block gpt-part-entry>first-lba x@-le ( addr first-lba ) block gpt-part-entry>last-lba x@-le ( addr first-lba last-lba) over - 1+ ( addr first-lba blocks ) swap ( addr blocks first-lba ) block-size * to part-offset ( addr blocks ) 0 0 seek drop ( addr blocks ) block-size * read ( size ) UNLOOP EXIT THEN seek-pos gpt-part-size + to seek-pos LOOP false ; : try-gpt-dos-partition ( -- true|false ) get-gpt-partition 0= IF false EXIT THEN block gpt>num-part-entry l@-le dup 0= IF false EXIT THEN 1+ 1 ?DO seek-pos 0 seek drop block gpt-part-size read drop gpt-basic-data-partition? IF debug-disk-label? IF ." GPT BASIC DATA partition found " cr THEN block gpt-part-entry>first-lba x@-le ( first-lba ) dup to part-start ( first-lba ) block gpt-part-entry>last-lba x@-le ( first-lba last-lba ) over - 1+ ( first-lba s1 ) block-size * to part-size ( first-lba ) block-size * to part-offset ( ) 0 0 seek drop block block-size read drop block fat-bootblock? ( true|false ) UNLOOP EXIT THEN seek-pos gpt-part-size + to seek-pos LOOP false ; : parse-bootinfo-txt ( addr len -- str len ) 2dup s" " find-substr ( addr len pos1 ) 2dup = IF 3drop 0 0 EXIT THEN dup >r - swap r> + swap ( addr1 len1 ) 2dup s" &device;:" find-substr ( addr1 len1 posdev ) 2dup = IF 3drop 0 0 EXIT THEN 9 + \ Skip the "&device;:" string dup >r - swap r> + swap ( addr2 len2 ) 2dup s" " find-substr nip ( addr2 len3 ) debug-disk-label? IF ." Extracted boot loader from bootinfo.txt: '" 2dup type ." '" cr THEN ; : load-chrp-boot-file ( addr -- size ) my-parent instance>path disk-chrp-boot @ 1 = IF s" :1,\ppc\bootinfo.txt" $cat strdup ( addr str len ) ELSE s" :\ppc\bootinfo.txt" $cat strdup ( addr str len ) THEN open-dev dup 0= IF 2drop 0 EXIT THEN >r dup ( addr addr R:ihandle ) dup s" load" r@ $call-method ( addr addr size R:ihandle ) r> close-dev ( addr addr size ) parse-bootinfo-txt ( addr fnstr fnlen ) dup 0= IF 3drop 0 EXIT THEN 2dup 20 findchar IF >r 2dup r@ - 1- swap r@ + 1+ swap ( addr fnstr fnlen pstr plen R: offset ) encode-string s" bootargs" set-chosen drop r> THEN my-parent instance>path ( addr fnstr fnlen nstr nlen ) s" :" $cat 2swap $cat strdup ( addr str len ) 2dup encode-string s" bootpath" set-chosen open-dev dup 0= IF ." failed to load CHRP boot loader." 2drop 0 EXIT THEN >r s" load" r@ $call-method ( size R:ihandle ) r> close-dev ( size ) ; : load-from-boot-partition ( addr -- size ) debug-disk-label? IF ." Trying DOS boot " .s cr THEN dup load-from-dos-boot-partition ?dup 0 <> IF nip EXIT THEN debug-disk-label? IF ." Trying CHRP boot " .s cr THEN 1 disk-chrp-boot ! dup load-chrp-boot-file ?dup 0 <> IF nip EXIT THEN 0 disk-chrp-boot ! debug-disk-label? IF ." Trying GPT boot " .s cr THEN load-from-gpt-prep-partition ; : parse-partition ( -- okay? ) 0 to partition 0 to part-offset 0 to part-size my-args to args-len to args debug-disk-label? IF cr ." disk-label parse-partition: my-args=" my-args type cr THEN args-len 0 = IF true EXIT THEN my-args [char] , findchar 0= IF \ no comma? args c@ isdigit not IF \ ... and not a partition number? true EXIT \ ... then it's not a partition we can parse THEN ELSE drop THEN my-args [char] , split to args-len to args dup 0= IF 2drop true EXIT THEN \ no first argument base @ >r decimal $number r> base ! IF cr ." Not a partition #" false EXIT THEN to partition true ; : (interpose-filesystem) ( str len -- ) find-package IF args args-len rot interpose THEN ; : try-dos-files ( -- found? ) no-mbr? IF false EXIT THEN block fat-bootblock? 0= IF false EXIT THEN s" fat-files" (interpose-filesystem) true ; : try-ext2-files ( -- found? ) 2 read-sector \ read first superblock block d# 56 + w@-le \ fetch s_magic ef53 <> IF false EXIT THEN \ s_magic found? s" ext2-files" (interpose-filesystem) true ; : try-iso9660-files has-iso9660-filesystem 0= IF false exit THEN s" iso-9660" (interpose-filesystem) true ; : try-files ( -- found? ) args-len 0= IF true EXIT THEN try-dos-files IF true EXIT THEN try-ext2-files IF true EXIT THEN try-iso9660-files IF true EXIT THEN false ; : try-partitions ( -- found? ) try-dos-partition IF try-files EXIT THEN try-gpt-dos-partition IF try-files EXIT THEN false ; : close ( -- ) debug-disk-label? IF ." Closing disk-label: block=0x" block u. ." block-size=" block-size .d cr THEN block block-array-size free-mem ; : open ( -- true|false ) init-block parse-partition 0= IF close false EXIT THEN partition IF try-partitions ELSE try-files THEN dup 0= IF debug-disk-label? IF ." not found." cr THEN close THEN \ free memory again ; : load ( addr -- size ) debug-disk-label? IF ." load: " dup u. cr THEN args-len IF TRUE ABORT" Load done w/o filesystem" ELSE partition IF 0 0 seek drop part-size IF part-size max-prep-partition-blocks min \ Load size ELSE max-prep-partition-blocks THEN 200 * read ELSE has-iso9660-filesystem IF dup load-chrp-boot-file ?dup 0 > IF nip EXIT THEN THEN load-from-boot-partition dup 0= ABORT" No boot partition found" THEN THEN ; finish-device new-device s" fat-files" device-name INSTANCE VARIABLE bytes/sector INSTANCE VARIABLE sectors/cluster INSTANCE VARIABLE #reserved-sectors INSTANCE VARIABLE #fats INSTANCE VARIABLE #root-entries INSTANCE VARIABLE fat32-root-cluster INSTANCE VARIABLE total-#sectors INSTANCE VARIABLE media-descriptor INSTANCE VARIABLE sectors/fat INSTANCE VARIABLE sectors/track INSTANCE VARIABLE #heads INSTANCE VARIABLE #hidden-sectors INSTANCE VARIABLE fat-type INSTANCE VARIABLE bytes/cluster INSTANCE VARIABLE fat-offset INSTANCE VARIABLE root-offset INSTANCE VARIABLE cluster-offset INSTANCE VARIABLE #clusters : seek s" seek" $call-parent ; : read s" read" $call-parent ; INSTANCE VARIABLE data INSTANCE VARIABLE #data : free-data data @ ?dup IF #data @ free-mem 0 data ! THEN ; : read-data ( offset size -- ) free-data dup #data ! alloc-mem data ! xlsplit seek -2 and ABORT" fat-files read-data: seek failed" data @ #data @ read #data @ <> ABORT" fat-files read-data: read failed" ; CREATE fat-buf 8 allot : read-fat ( cluster# -- data ) fat-buf 8 erase 1 #split fat-type @ * 2/ 2/ fat-offset @ + xlsplit seek -2 and ABORT" fat-files read-fat: seek failed" fat-buf 8 read 8 <> ABORT" fat-files read-fat: read failed" fat-buf 8c@ bxjoin fat-type @ dup >r 2* #split drop r> #split rot IF swap THEN drop ; INSTANCE VARIABLE next-cluster : read-cluster ( cluster# -- ) dup bytes/cluster @ * cluster-offset @ + bytes/cluster @ read-data read-fat dup #clusters @ >= IF drop 0 THEN next-cluster ! ; : read-dir ( cluster# -- ) ?dup 0= IF #root-entries @ 0= IF fat32-root-cluster @ read-cluster ELSE root-offset @ #root-entries @ 20 * read-data 0 next-cluster ! THEN ELSE read-cluster THEN ; : get-cluster ( direntry -- cluster# ) fat-type @ 20 = IF dup 14 + 2c@ bwjoin 10 lshift ELSE 0 THEN swap 1a + 2c@ bwjoin + ; : .time ( x -- ) base @ >r decimal b #split 2 0.r [char] : emit 5 #split 2 0.r [char] : emit 2* 2 0.r r> base ! ; : .date ( x -- ) base @ >r decimal 9 #split 7bc + 4 0.r [char] - emit 5 #split 2 0.r [char] - emit 2 0.r r> base ! ; : .attr ( attr -- ) 6 0 DO dup 1 and IF s" RHSLDA" drop i + c@ ELSE bl THEN emit u2/ LOOP drop ; : .dir-entry ( adr -- ) dup 0b + c@ 8 and IF drop EXIT THEN \ volume label, not a file dup c@ e5 = IF drop EXIT THEN \ deleted file cr dup get-cluster [char] # emit 8 0.r space \ starting cluster dup 18 + 2c@ bwjoin .date space dup 16 + 2c@ bwjoin .time space dup 1c + 4c@ bljoin base @ decimal swap a .r base ! space \ size in bytes dup 0b + c@ .attr space dup 8 BEGIN 2dup 1- + c@ 20 = over and WHILE 1- REPEAT type dup 8 + 3 BEGIN 2dup 1- + c@ 20 = over and WHILE 1- REPEAT dup IF [char] . emit type ELSE 2drop THEN drop ; : .dir-entries ( adr n -- ) 0 ?DO dup i 20 * + dup c@ 0= IF drop LEAVE THEN .dir-entry LOOP drop ; : .dir ( cluster# -- ) read-dir BEGIN data @ #data @ 20 / .dir-entries next-cluster @ WHILE next-cluster @ read-cluster REPEAT ; : str-upper ( str len adr -- ) \ Copy string to adr, uppercase -rot bounds ?DO i c@ upc over c! char+ LOOP drop ; CREATE dos-name b allot : make-dos-name ( str len -- ) dos-name b bl fill 2dup [char] . findchar IF 3dup 1+ /string 3 min dos-name 8 + str-upper nip THEN 8 min dos-name str-upper ; : (find-file) ( -- cluster file-len is-dir? true | false ) data @ BEGIN dup data @ #data @ + < WHILE dup dos-name b comp WHILE 20 + REPEAT dup get-cluster swap dup 1c + 4c@ bljoin swap 0b + c@ 10 and 0<> true ELSE drop false THEN ; : find-file ( dir-cluster name len -- cluster file-len is-dir? true | false ) make-dos-name read-dir BEGIN (find-file) 0= WHILE next-cluster @ WHILE next-cluster @ read-cluster REPEAT false ELSE true THEN ; : find-path ( dir-cluster name len -- cluster file-len true | false ) dup 0= IF 3drop false ." empty name " EXIT THEN over c@ [char] \ = IF 1 /string RECURSE EXIT THEN [char] \ split 2>r find-file 0= IF 2r> 2drop false ." not found " EXIT THEN r@ 0<> <> IF 2drop 2r> 2drop false ." no dir<->file match " EXIT THEN r@ 0<> IF drop 2r> RECURSE EXIT THEN 2r> 2drop true ; : do-super ( -- ) 0 200 read-data data @ 0b + 2c@ bwjoin bytes/sector ! data @ 0d + c@ sectors/cluster ! bytes/sector @ sectors/cluster @ * bytes/cluster ! data @ 0e + 2c@ bwjoin #reserved-sectors ! data @ 10 + c@ #fats ! data @ 11 + 2c@ bwjoin #root-entries ! data @ 13 + 2c@ bwjoin total-#sectors ! data @ 15 + c@ media-descriptor ! data @ 16 + 2c@ bwjoin sectors/fat ! data @ 18 + 2c@ bwjoin sectors/track ! data @ 1a + 2c@ bwjoin #heads ! data @ 1c + 2c@ bwjoin #hidden-sectors ! total-#sectors @ 0= IF data @ 20 + 4c@ bljoin total-#sectors ! THEN sectors/fat @ 0= IF data @ 24 + 4c@ bljoin sectors/fat ! THEN #root-entries @ 0= IF data @ 2c + 4c@ bljoin ELSE 0 THEN fat32-root-cluster ! total-#sectors @ #reserved-sectors @ - sectors/fat @ #fats @ * - #root-entries @ 20 * bytes/sector @ // - sectors/cluster @ / dup #clusters ! dup ff5 < IF drop c ELSE fff5 < IF 10 ELSE 20 THEN THEN fat-type ! base @ decimal base ! #reserved-sectors @ bytes/sector @ * fat-offset ! #fats @ sectors/fat @ * bytes/sector @ * fat-offset @ + root-offset ! #root-entries @ 20 * bytes/sector @ tuck // * root-offset @ + bytes/cluster @ 2* - cluster-offset ! ; INSTANCE VARIABLE file-cluster INSTANCE VARIABLE file-len INSTANCE VARIABLE current-pos INSTANCE VARIABLE pos-in-data : seek ( lo hi -- status ) lxjoin dup current-pos ! file-cluster @ read-cluster BEGIN dup #data @ >= WHILE #data @ - next-cluster @ dup 0= IF 2drop true EXIT THEN read-cluster REPEAT pos-in-data ! false ; : read ( adr len -- actual ) file-len @ current-pos @ - min \ can't go past end of file #data @ pos-in-data @ - min >r \ length for this transfer data @ pos-in-data @ + swap r@ move \ move the data r@ pos-in-data +! r@ current-pos +! pos-in-data @ #data @ = IF next-cluster @ ?dup IF read-cluster 0 pos-in-data ! THEN THEN r> ; : read ( adr len -- actual ) file-len @ min \ len cannot be greater than file size dup >r BEGIN dup WHILE 2dup read dup 0= ABORT" fat-files: read failed" /string ( tuck - >r + r> ) REPEAT 2drop r> ; : load ( adr -- len ) file-len @ read dup file-len @ <> ABORT" fat-files: failed loading file" ; : close free-data ; : open do-super 0 my-args find-path 0= IF close false EXIT THEN file-len ! file-cluster ! 0 0 seek 0= ; finish-device new-device s" rom-files" device-name INSTANCE VARIABLE length INSTANCE VARIABLE next-file INSTANCE VARIABLE buffer INSTANCE VARIABLE buffer-size INSTANCE VARIABLE file INSTANCE VARIABLE file-size INSTANCE VARIABLE found : open true 100 dup buffer-size ! alloc-mem buffer ! false found ! ; : close buffer @ buffer-size @ free-mem ; : read ( addr len -- actual ) s" read" $call-parent ; : seek ( lo hi -- status ) s" seek" $call-parent ; : .read-file-name ( offset -- str len ) 0 seek drop buffer @ buffer-size @ read drop buffer-size @ 1 - buffer @ + 0 swap c! buffer @ zcount ; : .print-info ( offset -- ) dup 2 spaces 6 0.r 2 spaces dup 8 + 0 seek drop length 8 read drop 6 length @ swap 0.r 2 spaces 20 + .read-file-name type cr ; : .list-header cr s" --offset---size-----file-name----" type cr ; : list .list-header 0 0 BEGIN + dup .print-info dup 0 seek drop next-file 8 read drop next-file @ dup 0= UNTIL 2drop ; : (find-file) ( name len -- offset | -1 ) 0 0 seek drop false found ! file-size ! file ! 0 0 BEGIN + dup 20 + .read-file-name file @ file-size @ str= IF true found ! THEN dup 0 seek drop next-file 8 read drop next-file @ dup 0= found @ or UNTIL drop found @ 0= IF drop -1 THEN ; : load ( addr -- size ) my-parent instance>args 2@ [char] \ left-parse-string 2drop (find-file) dup -1 = IF 2drop 0 ELSE 0 0 seek drop dup 8 + 0 seek drop here 8 read drop here @ ( dest-addr offset file-size ) over 18 + 0 seek drop here 8 read drop here @ ( dest-addr offset file-size data-offset ) rot + 0 seek drop ( dest-addr file-size ) read THEN ; finish-device new-device s" ext2-files" device-name INSTANCE VARIABLE first-block INSTANCE VARIABLE inode-size INSTANCE VARIABLE block-size INSTANCE VARIABLE inodes/group INSTANCE VARIABLE group-desc-size INSTANCE VARIABLE group-descriptors : seek s" seek" $call-parent ; : read s" read" $call-parent ; INSTANCE VARIABLE data INSTANCE VARIABLE #data INSTANCE VARIABLE indirect-block INSTANCE VARIABLE dindirect-block : free-data data @ ?dup IF #data @ free-mem 0 data ! THEN ; : read-data ( offset size -- ) free-data dup #data ! alloc-mem data ! xlsplit seek -2 and ABORT" ext2-files read-data: seek failed" data @ #data @ read #data @ <> ABORT" ext2-files read-data: read failed" ; : read-block ( block# -- ) block-size @ * block-size @ read-data ; INSTANCE VARIABLE inode INSTANCE VARIABLE file-len INSTANCE VARIABLE blocks INSTANCE VARIABLE #blocks INSTANCE VARIABLE ^blocks INSTANCE VARIABLE #blocks-left : blocks-read ( n -- ) dup negate #blocks-left +! 4 * ^blocks +! ; : read-indirect-blocks ( indirect-block# -- ) read-block data @ data off dup #blocks-left @ 4 * block-size @ min dup >r ^blocks @ swap move r> 2 rshift blocks-read block-size @ free-mem ; : read-double-indirect-blocks ( double-indirect-block# -- ) read-block data @ indirect-block ! data off BEGIN indirect-block @ l@-le dup 0 <> WHILE read-indirect-blocks 4 indirect-block +! \ point to next indirect block REPEAT drop \ drop 0, the invalid block number ; : read-triple-indirect-blocks ( triple-indirect-block# -- ) read-block data @ dindirect-block ! data off BEGIN dindirect-block @ l@-le dup 0 <> WHILE read-double-indirect-blocks 4 dindirect-block +! \ point to next double indirect block REPEAT drop \ drop 0, the invalid block number ; : read-block#s ( -- ) blocks @ ?dup IF #blocks @ 4 * free-mem THEN inode @ 4 + l@-le file-len ! file-len @ block-size @ // #blocks ! #blocks @ 4 * alloc-mem blocks ! blocks @ ^blocks ! #blocks @ #blocks-left ! #blocks-left @ c min \ # direct blocks inode @ 28 + over 4 * ^blocks @ swap move blocks-read #blocks-left @ IF inode @ 58 + l@-le read-indirect-blocks THEN #blocks-left @ IF inode @ 5c + l@-le read-double-indirect-blocks THEN #blocks-left @ IF inode @ 60 + l@-le read-triple-indirect-blocks THEN ; : read-inode ( inode# -- ) 1- inodes/group @ u/mod \ # in group, group # 20 * group-descriptors @ + 8 + l@-le block-size @ * \ # in group, inode table swap inode-size @ * + xlsplit seek drop inode @ inode-size @ read drop ; : .rwx ( bits last-char-if-special special? -- ) rot dup 4 and IF ." r" ELSE ." -" THEN dup 2 and IF ." w" ELSE ." -" THEN swap IF 1 and 0= IF upc THEN emit ELSE 1 and IF ." x" ELSE ." -" THEN drop THEN ; CREATE mode-chars 10 allot s" ?pc?d?b?-?l?s???" mode-chars swap move : .mode ( mode -- ) dup c rshift f and mode-chars + c@ emit dup 6 rshift 7 and over 800 and 73 swap .rwx dup 3 rshift 7 and over 400 and 73 swap .rwx dup 7 and swap 200 and 74 swap .rwx ; : .inode ( -- ) base @ >r decimal inode @ w@-le .mode \ file mode inode @ 1a + w@-le 5 .r \ link count inode @ 02 + w@-le 9 .r \ uid inode @ 18 + w@-le 9 .r \ gid inode @ 04 + l@-le 9 .r \ size r> base ! ; : do-super ( -- ) 400 400 read-data data @ 14 + l@-le first-block ! 400 data @ 18 + l@-le lshift block-size ! data @ 28 + l@-le inodes/group ! data @ 4c + l@-le 0= IF 80 inode-size ! ELSE data @ 58 + w@-le inode-size ! THEN data @ 20 + l@-le group-desc-size ! first-block @ 1+ block-size @ * group-desc-size @ read-data data @ group-descriptors ! data off ; INSTANCE VARIABLE current-pos : read ( adr len -- actual ) file-len @ current-pos @ - min \ can't go past end of file current-pos @ block-size @ u/mod 4 * blocks @ + l@-le read-block block-size @ over - rot min >r ( adr off r: len ) data @ + swap r@ move r> dup current-pos +! ; : read ( adr len -- actual ) dup >r BEGIN dup WHILE 2dup read dup 0= ABORT" ext2-files: read failed" /string REPEAT 2drop r> ; : seek ( lo hi -- status ) lxjoin dup file-len @ > IF drop true EXIT THEN current-pos ! false ; : load ( adr -- len ) file-len @ read dup file-len @ <> ABORT" ext2-files: failed loading file" ; : .name ( adr -- ) dup 8 + swap 6 + c@ type ; : read-dir ( inode# -- adr ) read-inode read-block#s file-len @ alloc-mem 0 0 seek ABORT" ext2-files read-dir: seek failed" dup file-len @ read file-len @ <> ABORT" ext2-files read-dir: read failed" ; : .dir ( inode# -- ) read-dir dup BEGIN 2dup file-len @ - > over l@-le tuck and WHILE cr dup 8 0.r space read-inode .inode space space dup .name dup 4 + w@-le + REPEAT 2drop file-len @ free-mem ; : (find-file) ( adr name len -- inode#|0 ) 2>r dup BEGIN 2dup file-len @ - > over l@-le and WHILE dup 8 + over 6 + c@ 2r@ str= IF 2r> 2drop nip l@-le EXIT THEN dup 4 + w@-le + REPEAT 2drop 2r> 2drop 0 ; : find-file ( inode# name len -- inode#|0 ) 2>r read-dir dup 2r> (find-file) swap file-len @ free-mem ; : find-path ( inode# name len -- inode#|0 ) dup 0= IF 3drop 0 ." empty name " EXIT THEN over c@ [char] \ = IF 1 /string ." slash " RECURSE EXIT THEN [char] \ split 2>r find-file ?dup 0= IF 2r> 2drop false ." not found " EXIT THEN r@ 0<> IF 2r> ." more... " RECURSE EXIT THEN 2r> 2drop ." got it " ; : close inode @ inode-size @ free-mem group-descriptors @ group-desc-size @ free-mem free-data blocks @ ?dup IF #blocks @ 4 * free-mem THEN ; : open 0 data ! 0 blocks ! 0 #blocks ! do-super inode-size @ alloc-mem inode ! my-args nip 0= IF 0 0 ELSE 2 my-args find-path ?dup 0= IF close false EXIT THEN THEN read-inode read-block#s 0 0 seek 0= ; finish-device new-device s" obp-tftp" device-name : open ( -- okay? ) true ; : load ( addr -- size ) s" bootargs" get-chosen 0= IF 0 0 THEN >r >r s" bootpath" get-chosen 0= IF 0 0 THEN >r >r my-parent ihandle>phandle node>path encode-string s" bootpath" set-chosen dup paflof-start < IF paflof-start ELSE MIN-RAM-SIZE THEN ( addr endaddr ) over - ( addr maxlen ) my-args net-load dup 0< IF drop 0 THEN r> r> over IF s" bootpath" set-chosen ELSE 2drop THEN r> r> over IF s" bootargs" set-chosen ELSE 2drop THEN ; : close ( -- ) ; : ping ( -- ) my-args net-ping ; finish-device new-device s" iso-9660" device-name 0 VALUE iso-debug-flag : iso-debug-print ( str len -- ) iso-debug-flag IF type cr ELSE 2drop THEN ; 0 VALUE path-tbl-size 0 VALUE path-tbl-addr 0 VALUE root-dir-size 0 VALUE vol-size 0 VALUE logical-blk-size 0 VALUE path-table 0 VALUE count INSTANCE VARIABLE dir-addr INSTANCE VARIABLE data-buff INSTANCE VARIABLE #data INSTANCE VARIABLE ptable INSTANCE VARIABLE file-loc INSTANCE VARIABLE file-size INSTANCE VARIABLE cur-file-offset INSTANCE VARIABLE self INSTANCE VARIABLE index : seek ( pos.lo pos.hi -- status ) s" seek" $call-parent ; : read ( addr len -- actual ) s" read" $call-parent ; : free-data ( -- ) data-buff @ ( data-buff ) ?DUP IF #data @ free-mem 0 data-buff ! 0 #data ! THEN ; : read-data ( offset size -- ) dup #data @ > IF free-data dup dup ( offset size size size ) #data ! alloc-mem data-buff ! ( offset size ) THEN swap xlsplit ( size pos.lo pos.hi ) seek -2 and ABORT" seek failed." data-buff @ over read ( size actual ) <> ABORT" read failed." ; : extract-vol-info ( -- ) 10 800 * 800 read-data data-buff @ 88 + l@-be to path-tbl-size \ read path table size data-buff @ 94 + l@-be to path-tbl-addr \ read big-endian path table data-buff @ a2 + l@-be dir-addr ! \ gather of root directory info data-buff @ 0aa + l@-be to root-dir-size \ get volume info data-buff @ 54 + l@-be to vol-size \ size in blocks data-buff @ 82 + l@-be to logical-blk-size path-tbl-size alloc-mem dup TO path-table path-tbl-size erase path-tbl-addr 800 * xlsplit seek drop path-table path-tbl-size read drop \ pathtable in-system-memory copy ; : file-name ( str len -- str' len' ) 2dup [char] ; findchar IF nip \ Omit the trailing ";1" revision of ISO9660 file name 2dup + 1- ( str newlen endptr ) c@ [CHAR] . = IF 1- ( str len' ) \ Remove trailing dot THEN THEN ; : dup3 ( num -- num num num ) dup dup dup ; : get-next-record ( rec-addr -- next-rec-offset ) dup3 ( rec-addr rec-addr rec-addr rec-addr ) self @ 1 + self ! ( rec-addr rec-addr rec-addr rec-addr ) c@ 1 AND IF ( rec-addr rec-addr rec-addr ) c@ + 9 ( rec-addr rec-addr' rec-len ) ELSE c@ + 8 ( rec-addr rec-addr' rec-len ) THEN + swap - ( next-rec-offset ) ; : path-table-search ( str len -- TRUE | FALSE ) path-table path-tbl-size + path-table ptable @ + DO ( str len ) 2dup I 6 + w@-be index @ = ( str len str len ) -rot I 8 + I c@ iso-debug-flag IF ." ISO: comparing path name '" 4dup type ." ' with '" type ." '" cr THEN string=ci and IF ( str len ) s" Directory Matched!! " iso-debug-print ( str len ) self @ index ! ( str len ) I 2 + l@-be dir-addr ! I dup ( str len rec-addr ) get-next-record + path-table - ptable ! ( str len ) 2drop TRUE UNLOOP EXIT ( TRUE ) THEN I get-next-record ( str len next-rec-offset ) +LOOP 2drop FALSE ( FALSE ) s" Invalid path / directory " iso-debug-print ; : search-file-dir ( str len -- TRUE | FALSE ) dir-addr @ 800 * dir-addr ! ( str len ) dir-addr @ 100 read-data ( str len ) data-buff @ 0e + l@-be dup >r ( str len rec-len ) 100 > IF ( str len ) s" size dir record" iso-debug-print ( str len ) dir-addr @ r@ read-data ( str len ) THEN r> data-buff @ + data-buff @ DO ( str len ) I 19 + c@ 2 and 0= I c@ 0<> and IF ( str len ) 2dup ( str len str len ) I 21 + I 20 + c@ ( str len str len str' len' ) iso-debug-flag IF ." ISO: comparing file name '" 4dup type ." ' with '" type ." '" cr THEN file-name string=ci IF ( str len ) s" File found!" iso-debug-print ( str len ) I 6 + l@-be 800 * ( str len file-loc ) file-loc ! ( str len ) I 0e + l@-be file-size ! ( str len ) 2drop TRUE ( TRUE ) UNLOOP EXIT THEN THEN I c@ ?dup 0= IF 800 I 7ff AND - iso-debug-flag IF ." skipping " dup . ." bytes at end of sector" cr THEN THEN +LOOP 2drop FALSE ( FALSE ) s" file not found" iso-debug-print ; : search-path ( str len -- FALSE|TRUE ) 0 ptable ! 1 self ! 1 index ! dup ( str len len ) 0= IF 3drop FALSE ( FALSE ) s" Empty path name " iso-debug-print EXIT ( FALSE ) THEN OVER c@ ( str len char ) [char] \ = IF ( str len ) swap 1 + swap 1 - BEGIN ( str len ) [char] \ split ( str len str' len ' ) dup 0 = IF ( str len str' len ' ) 2drop search-file-dir EXIT ( TRUE | FALSE ) ELSE 2swap path-table-search invert IF ( str' len ' ) 2drop FALSE EXIT ( FALSE ) THEN THEN AGAIN ELSE BEGIN [char] \ split dup 0 = IF ( str len str' len' ) 2drop search-file-dir EXIT ( TRUE | FALSE ) ELSE 2swap path-table-search invert IF ( str' len ' ) 2drop FALSE EXIT ( FALSE ) THEN THEN AGAIN THEN ; 0 VALUE loc : load ( addr -- len ) dup to loc ( addr ) file-loc @ xlsplit seek drop file-size @ read ( file-size ) iso-debug-flag IF s" Bytes returned from read:" type dup . cr THEN dup file-size @ <> ABORT" read failed!" ; : close ( -- ) free-data count 1 - dup to count 0 = IF path-table path-tbl-size free-mem 0 TO path-table THEN ; : open ( -- TRUE | FALSE ) 0 data-buff ! 0 #data ! 0 ptable ! 0 file-loc ! 0 file-size ! 0 cur-file-offset ! 1 self ! 1 index ! count 0 = IF s" extract-vol-info called " iso-debug-print extract-vol-info THEN count 1 + to count my-args search-path IF file-loc @ xlsplit seek drop TRUE ( TRUE ) ELSE close FALSE ( FALSE ) THEN 0 cur-file-offset ! s" opened ISO9660 package" iso-debug-print ; : seek ( pos.lo pos.hi -- status ) lxjoin dup cur-file-offset ! ( offset ) file-loc @ + xlsplit ( pos.lo pos.hi ) s" seek" $call-parent ( status ) ; : read ( addr len -- actual ) file-size @ cur-file-offset @ - ( addr len remainder-of-file ) min ( addr len|remainder-of-file ) s" read" $call-parent ( actual ) dup cur-file-offset @ + cur-file-offset ! ( actual ) cur-file-offset @ ( offset actual ) xlsplit seek drop ( actual ) ; finish-device finish-device : open true ; : close ; finish-device 370 cp : check-boot-menu s" qemu,boot-menu" get-chosen IF decode-int 1 = IF ." Press F12 for boot menu." cr cr THEN 2drop THEN ; check-boot-menu 380 cp 0 VALUE fdtfl-debug VARIABLE fdtfl-struct VARIABLE fdtfl-struct-here VARIABLE fdtfl-strings VARIABLE fdtfl-strings-cache VARIABLE fdtfl-strings-here VARIABLE fdtfl-strings-reused \ debug only VARIABLE fdlfl-ms \ debug only : fdt-skip-string ( cur -- cur ) zcount + char+ 4 #aligned ; : zstring= ( str len zstr -- flag ) 2dup + c@ 0<> IF 3drop false EXIT THEN swap comp 0= ; : fdt-find-string ( name namelen -- nameoff true | false ) fdtfl-strings @ BEGIN dup fdtfl-strings-cache @ < WHILE 3dup zstring= IF nip nip ( curstr ) fdtfl-strings @ - true EXIT THEN fdt-skip-string REPEAT 3drop false ; : fdt-str-allot ( len -- ) fdtfl-strings-here @ + to fdtfl-strings-here ; : fdt-str-c, ( char -- ) fdtfl-strings-here @ 1 fdt-str-allot c! ; : fdt-str-align ( -- ) fdtfl-strings-here @ dup dup 4 #aligned swap - ( here bytes-to-erase ) dup -rot erase fdt-str-allot ; : fdt-str-bytes, ( data len -- ) fdtfl-strings-here @ over fdt-str-allot swap move ; : fdt-str-ztr, ( str len -- ) fdt-str-bytes, 0 fdt-str-c, ; : fdt-add-string ( name namelen -- nameoff ) fdtfl-strings-here @ -rot fdt-str-ztr, fdt-str-align fdtfl-strings @ - ; : fdt-get-string ( name namelen -- nameoff ) 2dup fdt-find-string IF -rot 2drop fdtfl-debug IF 1 fdtfl-strings-reused +! THEN EXIT THEN fdt-add-string ; : fdt-allot ( len -- ) fdtfl-struct-here @ + to fdtfl-struct-here ; : fdt-c, ( char -- ) fdtfl-struct-here @ 1 fdt-allot c! ; : fdt-align ( -- ) fdtfl-struct-here @ dup dup 4 #aligned swap - ( here bytes-to-erase ) dup -rot erase fdt-allot ; : fdt-bytes, ( data len -- ) fdtfl-struct-here @ over fdt-allot swap move ; : fdt-ztr, ( str len -- ) fdt-bytes, 0 fdt-c, ; : fdt-l, ( token -- ) fdtfl-struct-here @ l! /l fdt-allot ; : fdt-begin-node ( phandle -- ) OF_DT_BEGIN_NODE fdt-l, dup device-tree @ = IF drop s" " ELSE node>qname THEN fdt-ztr, fdt-align ; : fdt-end-node ( -- ) OF_DT_END_NODE fdt-l, ; : fdt-prop ( prop len name namelen -- ) OF_DT_PROP fdt-l, fdt-get-string ( prop len nameoff ) over fdt-l, fdt-l, ( prop len ) fdt-bytes, fdt-align ; : fdt-end ( -- ) OF_DT_END fdt-l, ; : fdt-copy-property ( link -- ) dup link> execute rot link>name name>string 2dup s" name" str= IF 4drop EXIT THEN \ skipping useless "name" fdt-prop ; : for-all-words ( wid xt -- ) \ xt has sig ( lfa -- ) >r cell+ @ BEGIN dup WHILE dup r@ execute @ REPEAT r> 2drop ; : fdt-copy-properties ( phandle -- ) dup encode-int s" phandle" fdt-prop node>properties @ ['] fdt-copy-property for-all-words ; : fdt-copy-node ( node -- ) fdtfl-debug 1 > IF dup node>path type cr THEN dup fdt-begin-node dup fdt-copy-properties child BEGIN dup WHILE dup recurse peer REPEAT drop fdt-end-node ; : fdtfl-strings-preload ( -- ) s" reg" fdt-add-string drop s" status" fdt-add-string drop s" 64-bit" fdt-add-string drop s" phandle" fdt-add-string drop s" ibm,vmx" fdt-add-string drop s" ibm,dfp" fdt-add-string drop s" slb-size" fdt-add-string drop s" ibm,purr" fdt-add-string drop s" vendor-id" fdt-add-string drop s" device-id" fdt-add-string drop s" min-grant" fdt-add-string drop s" class-code" fdt-add-string drop s" compatible" fdt-add-string drop s" interrupts" fdt-add-string drop s" cpu-version" fdt-add-string drop s" #size-cells" fdt-add-string drop s" ibm,req#msi" fdt-add-string drop s" revision-id" fdt-add-string drop s" device_type" fdt-add-string drop s" max-latency" fdt-add-string drop s" ibm,chip-id" fdt-add-string drop s" ibm,pft-size" fdt-add-string drop s" ibm,slb-size" fdt-add-string drop s" devsel-speed" fdt-add-string drop s" ibm,loc-code" fdt-add-string drop s" subsystem-id" fdt-add-string drop s" d-cache-size" fdt-add-string drop s" i-cache-size" fdt-add-string drop s" #address-cells" fdt-add-string drop s" clock-frequency" fdt-add-string drop s" cache-line-size" fdt-add-string drop s" ibm,pa-features" fdt-add-string drop s" ibm,my-drc-index" fdt-add-string drop s" d-cache-line-size" fdt-add-string drop s" i-cache-line-size" fdt-add-string drop s" assigned-addresses" fdt-add-string drop s" d-cache-block-size" fdt-add-string drop s" i-cache-block-size" fdt-add-string drop s" timebase-frequency" fdt-add-string drop s" subsystem-vendor-id" fdt-add-string drop s" ibm,segment-page-sizes" fdt-add-string drop s" ibm,ppc-interrupt-server#s" fdt-add-string drop s" ibm,processor-segment-sizes" fdt-add-string drop s" ibm,ppc-interrupt-gserver#s" fdt-add-string drop ; : fdt-append-blob ( bytes cur blob -- cur ) 3dup -rot swap move drop + ; : fdt-flatten-tree ( -- tree ) 100000 alloc-mem dup fdtfl-struct-here ! fdtfl-struct ! 100000 alloc-mem dup fdtfl-strings-here ! fdtfl-strings ! fdtfl-debug IF 0 fdtfl-strings-reused ! milliseconds fdlfl-ms ! THEN fdtfl-strings-preload fdtfl-strings-here @ fdtfl-strings-cache ! device-tree @ fdt-copy-node fdt-end fdtfl-struct-here @ fdtfl-struct @ - fdtfl-strings-here @ fdtfl-strings @ - ( struct-len strings-len ) 2dup + /fdth + 10 + \ Reserve 16 bytes for an empty reserved block fdtfl-debug IF 3dup ." FDTsize=" .d ." Strings=" .d ." Struct=" .d ." Reused str=" fdtfl-strings-reused @ .d milliseconds fdlfl-ms @ - .d ." ms" cr THEN dup alloc-mem ( struct-len strings-len total-len fdt ) >r ( struct-len strings-len total-len r: fdt ) OF_DT_HEADER r@ >fdth_magic l! dup r@ >fdth_tsize l! /fdth 10 + 2 pick + r@ >fdth_struct_off l! /fdth 10 + r@ >fdth_string_off l! /fdth r@ >fdth_rsvmap_off l! 11 r@ >fdth_version l! 10 r@ >fdth_compat_vers l! chosen-cpu-unit r@ >fdth_boot_cpu l! over r@ >fdth_string_size l! 2 pick r@ >fdth_struct_size l! drop ( struct-len strings-len r: fdt ) r@ /fdth + ( struct-len strings-len cur r: fdt ) 0 over ! cell+ 0 over ! cell+ fdtfl-strings @ fdt-append-blob fdtfl-struct @ fdt-append-blob drop fdtfl-struct @ 100000 free-mem fdtfl-strings @ 100000 free-mem r> ; : fdt-flatten-tree-free ( tree ) dup >fdth_tsize l@ free-mem ; 371 cp STRUCT /l field rtas>token /l field rtas>nargs /l field rtas>nret /l field rtas>args0 /l field rtas>args1 /l field rtas>args2 /l field rtas>args3 /l field rtas>args4 /l field rtas>args5 /l field rtas>args6 /l field rtas>args7 /l C * field rtas>args /l field rtas>bla CONSTANT /rtas-control-block CREATE rtas-cb /rtas-control-block allot rtas-cb /rtas-control-block erase 0 VALUE rtas-base 0 VALUE rtas-size 0 VALUE rtas-node s" /rtas" find-node to rtas-node 373 cp : enter-rtas ( -- ) rtas-cb rtas-base 0 rtas-base call-c drop ; : rtas-get-token ( str len -- token | 0 ) rtas-node get-package-property IF 0 ELSE drop l@ THEN ; : rtas-power-off ( x y -- status ) [ s" power-off" rtas-get-token ] LITERAL rtas-cb rtas>token l! 2 rtas-cb rtas>nargs l! 1 rtas-cb rtas>nret l! rtas-cb rtas>args0 l! rtas-cb rtas>args1 l! enter-rtas rtas-cb rtas>args2 l@ ; : power-off ( -- ) 0 0 rtas-power-off ; : rtas-system-reboot ( -- status ) [ s" system-reboot" rtas-get-token ] LITERAL rtas-cb rtas>token l! 0 rtas-cb rtas>nargs l! 1 rtas-cb rtas>nret l! rtas-cb rtas>args0 l! enter-rtas rtas-cb rtas>args1 l@ ; : rtas-start-cpu ( pid loc r3 -- status ) [ s" start-cpu" rtas-get-token ] LITERAL rtas-cb rtas>token l! 3 rtas-cb rtas>nargs l! 1 rtas-cb rtas>nret l! rtas-cb rtas>args2 l! rtas-cb rtas>args1 l! rtas-cb rtas>args0 l! 0 rtas-cb rtas>args3 l! enter-rtas rtas-cb rtas>args3 l@ ; : rtas-set-tce-bypass ( unit enable -- ) " ibm,set-tce-bypass" rtas-get-token rtas-cb rtas>token l! 2 rtas-cb rtas>nargs l! 0 rtas-cb rtas>nret l! rtas-cb rtas>args1 l! rtas-cb rtas>args0 l! enter-rtas ; : rtas-quiesce ( -- ) fdt-flatten-tree dup hv-update-dt ?dup IF dup -2 <> IF ." HV-UPDATE-DT error: " . cr ELSE drop THEN THEN fdt-flatten-tree-free " quiesce" rtas-get-token rtas-cb rtas>token l! 0 rtas-cb rtas>nargs l! 0 rtas-cb rtas>nret l! enter-rtas ; 0 value puid : rtas-do-config-@ ( config-addr size -- value) [ s" ibm,read-pci-config" rtas-get-token ] LITERAL rtas-cb rtas>token l! 4 rtas-cb rtas>nargs l! 2 rtas-cb rtas>nret l! ( addr size ) rtas-cb rtas>args3 l! puid rtas-cb rtas>args2 l! puid 20 rshift rtas-cb rtas>args1 l! ( addr ) rtas-cb rtas>args0 l! enter-rtas rtas-cb rtas>args4 l@ dup IF drop ffffffff ELSE drop rtas-cb rtas>args5 l@ THEN ; : rtas-do-config-! ( value config-addr size ) [ s" ibm,write-pci-config" rtas-get-token ] LITERAL rtas-cb rtas>token l! 5 rtas-cb rtas>nargs l! 1 rtas-cb rtas>nret l! ( value addr size ) rtas-cb rtas>args3 l! puid rtas-cb rtas>args2 l! puid 20 rshift rtas-cb rtas>args1 l! ( value addr ) rtas-cb rtas>args0 l! ( value ) rtas-cb rtas>args4 l! enter-rtas rtas-cb rtas>args5 l@ dup IF ." RTAS write config err " . cr ELSE drop THEN ; : rtas-config-b@ ( config-addr -- value ) 1 rtas-do-config-@ ff and ; : rtas-config-b! ( value config-addr -- ) 1 rtas-do-config-! ; : rtas-config-w@ ( config-addr -- value ) 2 rtas-do-config-@ ffff and ; : rtas-config-w! ( value config-addr -- ) 2 rtas-do-config-! ; : rtas-config-l@ ( config-addr -- value ) 4 rtas-do-config-@ ffffffff and ; : rtas-config-l! ( value config-addr -- ) 4 rtas-do-config-! ; : of-start-cpu rtas-start-cpu ; ' power-off to halt ' rtas-system-reboot to reboot rtas-node set-node : open true ; : close ; : store-rtas-loc ( adr ) s" /rtas" find-node >r encode-int s" slof,rtas-base" r@ set-property rtas-size encode-int s" slof,rtas-size" r> set-property ; : instantiate-rtas ( adr -- entry ) dup store-rtas-loc dup rtas-base swap rtas-size move ; hv-rtas-get dup encode-int s" rtas-size" s" /rtas" find-node set-property to rtas-size to rtas-base device-end 374 cp 3f0 cp : strequal ( str1 len1 str2 len2 -- flag ) rot dup rot = IF comp 0= ELSE 2drop drop 0 THEN ; 400 cp " /" find-device 200000 CONSTANT cas-buffer-size : ibm,client-architecture-support ( vec -- err? ) cas-buffer-size alloc-mem ( vec memaddr ) dup 0= IF ." out of memory during ibm,client-architecture-support" cr THEN swap over cas-buffer-size ( memaddr vec memaddr size ) hv-cas 0= IF ( memaddr ) dup l@ 1 >= IF \ Version number >= 1 " /" find-node set-node dup 4 + fdt-init fdt-check-header fdt-struct fdt-fix-cas-node fdt-fix-cas-success NOT s" /" find-node fdt-fix-phandles ELSE FALSE THEN ELSE TRUE THEN >r cas-buffer-size free-mem r> ; 480 cp new-device s" mmu" 2dup device-name device-type 0 0 s" translations" property : open true ; : close ; finish-device device-end 4c0 cp : fixup-tbfreq " /cpus" find-device get-node child dup 0= ABORT" CPU not found" set-node " timebase-frequency" get-node get-package-property IF 2drop ELSE decode-int to tb-frequency 2drop THEN device-end ; fixup-tbfreq 4d0 cp include fbuffer.fs 500 cp : populate-vios ( -- ) ." Populating /vdevice methods" cr " /vdevice" find-device get-node child BEGIN dup 0 <> WHILE dup set-node dup " compatible" rot get-package-property 0 = IF drop dup from-cstring 2dup " hvterm1" strequal IF " vio-hvterm.fs" included THEN 2dup " IBM,v-scsi" strequal IF " vio-vscsi.fs" included THEN 2dup " IBM,l-lan" strequal IF " vio-veth.fs" included THEN 2dup " qemu,spapr-nvram" strequal IF " rtas-nvram.fs" included THEN 2drop THEN peer REPEAT drop device-end ; populate-vios 5a0 cp VARIABLE pci-next-mem \ prefetchable memory mapped VARIABLE pci-max-mem VARIABLE pci-next-mmio \ non-prefetchable memory VARIABLE pci-max-mmio VARIABLE pci-next-io \ I/O space VARIABLE pci-max-io VARIABLE pci-next-mem64 \ prefetchable 64-bit memory mapped VARIABLE pci-max-mem64 0 VALUE pci-mem-bar-min-align 0 VALUE pci-bus-number 0 VALUE pci-device-number 0 VALUE pci-device-slots here 100 allot CONSTANT pci-device-vec 0 VALUE pci-device-vec-len 0 VALUE pci-hotplug-enabled : int2str ( int len -- str len ) swap s>d rot <# 0 ?DO # LOOP #> ; : pci-addr2bus ( addr -- busnr ) 10 rshift FF and ; : pci-addr2dev ( addr -- dev ) B rshift 1F and ; : pci-addr2fn ( addr -- dev ) 8 rshift 7 and ; : pci-bus2addr ( busnr devnr -- addr ) B lshift swap 10 lshift + ; : pci-addr-out ( addr -- ) dup pci-addr2bus 2 0.r space FFFF and 4 0.r ; : pci-dump ( addr -- ) 10 0 DO dup cr i 4 * + dup pci-addr-out space rtas-config-l@ 8 0.r LOOP drop cr ; : pci-vendor@ ( addr -- id ) rtas-config-l@ FFFF and ; : pci-device@ ( addr -- id ) rtas-config-l@ 10 rshift ; : pci-status@ ( addr -- status ) 4 + rtas-config-l@ 10 rshift ; : pci-revision@ ( addr -- id ) 8 + rtas-config-b@ ; : pci-class@ ( addr -- class ) 8 + rtas-config-l@ 8 rshift ; : pci-cache@ ( addr -- size ) C + rtas-config-b@ ; : pci-htype@ ( addr -- type ) E + rtas-config-b@ ; : pci-sub-vendor@ ( addr -- sub-id ) 2C + rtas-config-l@ FFFF and ; : pci-sub-device@ ( addr -- sub-id ) 2C + rtas-config-l@ 10 rshift FFFF and ; : pci-interrupt@ ( addr -- interrupt ) 3D + rtas-config-b@ ; : pci-min-grant@ ( addr -- min-gnt ) 3E + rtas-config-b@ ; : pci-max-lat@ ( addr -- max-lat ) 3F + rtas-config-b@ ; : pci-capabilities? ( addr -- 0|1 ) pci-status@ 4 rshift 1 and ; : pci-cap-next ( cap-addr -- next-cap-off ) rtas-config-b@ FC and ; : pci-cap-next-addr ( cap-addr -- next-cap-addr ) 1+ dup pci-cap-next dup IF swap -100 and + ELSE nip THEN ; : pci-cap-dump ( addr -- ) cr dup pci-capabilities? IF 33 + BEGIN pci-cap-next-addr dup 0<> WHILE dup pci-addr-out s" : " type dup rtas-config-b@ 2 0.r cr REPEAT s" end found " ELSE s" capabilities not enabled!" THEN type cr drop ; : pci-cap-find ( addr id -- capp-addr|0 ) swap dup pci-capabilities? IF 33 + BEGIN pci-cap-next-addr dup 0<> IF dup rtas-config-b@ 2 pick = ELSE true THEN UNTIL nip ELSE 2drop 0 THEN ; : pci-express? ( addr -- 0|1 ) 10 pci-cap-find 0<> ; : pci-x? ( addr -- 0|1 ) 07 pci-cap-find 0<> ; : pci-config-ext? ( addr -- 0|1 ) pci-express? ; : pci-device-disable ( -- ) my-space 4 + dup rtas-config-l@ 7 invert and swap rtas-config-l! ; : pci-master-enable ( -- ) my-space 4 + dup rtas-config-l@ 4 or swap rtas-config-l! ; : pci-master-disable ( -- ) my-space 4 + dup rtas-config-l@ 4 invert and swap rtas-config-l! ; : pci-mem-enable ( -- ) my-space 4 + dup rtas-config-w@ 2 or swap rtas-config-w! ; : pci-io-enable ( -- ) my-space 4 + dup rtas-config-w@ 1 or swap rtas-config-w! ; : pci-enable ( -- ) my-space 4 + dup rtas-config-w@ 7 or swap rtas-config-w! ; : pci-error-enable ( -- ) my-space 4 + dup rtas-config-w@ 140 or swap rtas-config-w! ; : pci-out ( addr char -- ) 15 spaces over pci-addr-out s" (" type emit s" ) : " type dup pci-vendor@ 4 0.r space pci-device@ 4 0.r 4 spaces ; : pci-irq-line@ ( addr -- irq-pin ) 3C + rtas-config-b@ ; : pci-irq-line! ( pin addr -- ) 3C + rtas-config-b! ; : pci-bus-prim! ( nr addr -- ) 18 + dup rtas-config-l@ FFFFFF00 and rot + swap rtas-config-l! ; : pci-bus-prim@ ( addr -- nr ) 18 + rtas-config-l@ FF and ; : pci-bus-scnd! ( nr addr -- ) 18 + dup rtas-config-l@ FFFF00FF and rot 8 lshift + swap rtas-config-l! ; : pci-bus-scnd@ ( addr -- nr ) 18 + rtas-config-l@ 8 rshift FF and ; : pci-bus-subo! ( nr addr -- ) 18 + dup rtas-config-l@ FF00FFFF and rot 10 lshift + swap rtas-config-l! ; : pci-bus-subo@ ( addr -- nr ) 18 + rtas-config-l@ 10 rshift FF and ; : pci-bus! ( subo scnd prim addr -- ) swap rot 8 lshift + rot 10 lshift + swap 18 + dup rtas-config-l@ FF000000 and rot + swap rtas-config-l! ; : pci-bus@ ( addr -- subo scnd prim ) 18 + rtas-config-l@ dup 10 rshift FF and swap dup 8 rshift FF and swap FF and ; : pci-reset-2nd ( addr -- ) 1C + dup rtas-config-l@ FFFF0000 or swap rtas-config-l! ; : pci-vec ( -- ) cr s" device-vec(" type pci-device-vec-len dup 2 0.r s" ):" type 1+ 0 DO pci-device-vec i + c@ space 2 0.r LOOP cr ; : pci-var-out ( -- ) ." pci-next-io = " pci-next-io @ 10 0.r cr ." pci-max-io = " pci-max-io @ 10 0.r cr ." pci-next-mem = " pci-next-mem @ 10 0.r cr ." pci-max-mem = " pci-max-mem @ 10 0.r cr ." pci-next-mmio = " pci-next-mmio @ 10 0.r cr ." pci-max-mmio = " pci-max-mmio @ 10 0.r cr ." pci-next-mem64 = " pci-next-mem64 @ 10 0.r cr ." pci-max-mem64 = " pci-max-mem64 @ 10 0.r cr ; : pci-set-slot ( addr -- ) pci-addr2dev dup \ calc slot number pci-device-vec-len \ the end of the vector pci-device-vec + c! \ and update the vector 80000000 swap rshift \ calc bit position of the device slot pci-device-slots or \ set this bit TO pci-device-slots \ and write it back ; : pci-bridge-set-mmio-base ( addr -- ) pci-next-mmio @ 100000 #aligned \ read the current Value and align to 1MB boundary dup pci-next-mmio ! \ and write it back 10 rshift \ mmio-base reg is only the upper 16 bits pci-max-mmio @ 1- FFFF0000 and or \ and Insert mmio Limit (set it to max) swap 20 + rtas-config-l! \ and write it into the bridge ; : pci-bridge-set-mmio-limit ( addr -- ) pci-next-mmio @ 100000 + \ add space for hot-plugging 100000 #aligned \ align to 1MB boundary dup pci-next-mmio ! \ and write it back 1- FFFF0000 and \ make it one less and keep upper 16 bits over 20 + rtas-config-l@ 0000FFFF and \ fetch original value or swap 20 + rtas-config-l! \ and write it into the Reg ; : pci-bridge-set-mem-base ( addr -- ) dup 24 + rtas-config-w@ 1 and \ does bridge support 64-bit? pci-next-mem64 @ 0<> and IF \ and do we have 64-bit memory? pci-next-mem64 @ 100000000 #aligned dup pci-next-mem64 x! 20 rshift over 28 + rtas-config-l! \ set prefetch base upper 32 bits pci-next-mem64 @ 10 rshift FFF0 and pci-max-mem64 @ 1- FFF00000 and or over 24 + rtas-config-l! \ set prefetch limit & base lower pci-max-mem64 @ 1- 20 rshift swap 2C + rtas-config-l! \ and set the limit upper 32 bits ELSE pci-next-mem @ 100000 #aligned dup pci-next-mem ! 10 rshift FFF0 and pci-max-mem @ 1- FFF00000 and or swap 24 + rtas-config-l! THEN ; : pci-bridge-set-mem-limit ( addr -- ) dup 24 + rtas-config-w@ 1 and \ does bridge support 64-bit? pci-next-mem64 @ 0<> and IF \ and do we have 64-bit memory? pci-next-mem64 @ 80000000 + 100000000 #aligned dup pci-next-mem64 x! 1- 20 rshift over 2C + rtas-config-l! \ set the limit upper 32 bits pci-next-mem64 @ 1- 10 rshift swap 26 + rtas-config-w! \ set limit lower bits ELSE pci-next-mem @ 100000 + 100000 #aligned dup pci-next-mem ! 1- 10 rshift swap 26 + rtas-config-w! THEN ; : pci-bridge-set-io-base ( addr -- ) pci-next-io @ 1000 #aligned \ read the current Value and align to 4KB boundary dup pci-next-io ! \ and write it back over 1C + rtas-config-l@ \ check if 32bit support 1 and IF \ IF 32 bit support 2dup 10 rshift \ | keep upper 16 bits pci-max-io @ FFFF0000 and or \ | insert upper 16 bits of Max-Limit swap 30 + rtas-config-l! \ | and write it into the Base-Upper16-bits THEN \ FI 8 rshift 000000FF and \ keep upper 8 bits pci-max-io @ 1- 0000FF00 and or \ insert upper 8 bits of Max-Limit over rtas-config-l@ FFFF0000 and \ fetch original Value or swap 1C + rtas-config-l! \ and write it into the bridge ; : pci-bridge-set-io-limit ( addr -- ) pci-next-io @ 800 + \ add space for hot-plugging 1000 #aligned \ align to 4KB boundary dup pci-next-io ! \ and write it back 1- \ make limit one less than boundary over 1D + rtas-config-b@ \ check if 32bit support 1 and IF \ IF 32 bit support 2dup FFFF0000 and \ | keep upper 16 bits over 30 + rtas-config-l@ \ | fetch original Value or swap 30 + rtas-config-l! \ | and write it into the Limit-Upper16-bits THEN \ FI 0000FF00 and \ keep upper 8 bits over 1C + rtas-config-l@ FFFF00FF and \ fetch original Value or swap 1C + rtas-config-l! \ and write it into the bridge ; : pci-bridge-set-bases ( addr -- ) dup pci-bridge-set-mmio-base dup pci-bridge-set-mem-base pci-bridge-set-io-base ; : pci-bridge-set-limits ( addr -- ) dup pci-bridge-set-mmio-limit dup pci-bridge-set-mem-limit pci-bridge-set-io-limit ; DEFER func-pci-probe-bus DEFER func-pci-bridge-range-props : pci-bridge-probe ( addr -- ) dup pci-bridge-set-bases \ SetUp all Base Registers dup func-pci-bridge-range-props \ Setup temporary "range pci-bus-number 1+ TO pci-bus-number \ increase number of busses found pci-device-vec-len 1+ TO pci-device-vec-len \ increase the device-slot vector depth dup \ stack config-addr for pci-bus! FF swap \ Subordinate Bus Number ( for now to max to open all subbusses ) pci-bus-number swap \ Secondary Bus Number ( the new busnumber ) dup pci-addr2bus swap \ Primary Bus Number ( the current bus ) pci-bus! \ and set them into the bridge pci-enable \ enable mem/IO transactions dup pci-bus-scnd@ func-pci-probe-bus \ and probe the secondary bus dup pci-bus-number swap pci-bus-subo! \ set SubOrdinate Bus Number to current number of busses pci-device-vec-len 1- TO pci-device-vec-len \ decrease the device-slot vector depth dup pci-bridge-set-limits \ SetUp all Limit Registers drop \ forget the config-addr ; DEFER func-pci-bridge-probe ' pci-bridge-probe TO func-pci-bridge-probe : pci-device-setup ( addr -- ) drop \ since the config-addr is coded in my-space, drop it here s" pci-device.fs" included \ and setup the device as node in the device tree ; : pci-bridge-setup ( addr -- ) drop \ since the config-addr is coded in my-space, drop it here s" pci-bridge.fs" included \ and setup the bridge as node in the device tree ; : pci-add-device ( addr -- ) new-device \ create a new device-tree node dup set-space \ set the config addr for this device tree entry dup pci-set-slot \ set the slot bit dup pci-htype@ \ read HEADER-Type 7f and \ Mask bit 7 - multifunction device CASE 0 OF pci-device-setup ENDOF \ | set up the device 1 OF pci-bridge-setup ENDOF \ | set up the bridge dup OF dup pci-htype@ pci-out ENDOF ENDCASE finish-device \ and close the device-tree node ; : pci-setup-device ( addr -- ) dup pci-htype@ \ read HEADER-Type 80 and IF 8 ELSE 1 THEN \ check for multifunction 0 DO \ LOOP over all possible functions (either 8 or only 1) dup i 8 lshift + \ calc device-function-config-addr dup pci-vendor@ \ check if valid function FFFF = IF drop \ non-valid so forget the address ELSE pci-device-number 1+ \ increase the number of devices TO pci-device-number \ and store it pci-add-device \ and add the device to the device tree and set it up THEN LOOP \ next function drop \ forget the device-addr ; : pci-probe-device ( busnr devicenr -- ) pci-bus2addr \ calc pci-address dup pci-vendor@ \ fetch Vendor-ID FFFF = IF \ check if valid drop \ if not forget it ELSE pci-setup-device \ if valid setup the device THEN ; : pci-probe-bus ( busnr -- ) 0 TO pci-device-slots \ reset slot array to unpoppulated 20 0 DO dup i pci-probe-device LOOP drop ; ' pci-probe-bus TO func-pci-probe-bus : pci-probe-all ( bus-max bus-min -- ) \ Check all busses from bus-min up to bus-max if needed 0 TO pci-device-vec-len \ reset the device-slot vector DO i TO pci-bus-number \ set current Busnumber 0 TO pci-device-number \ reset Device Number pci-bus-number pci-probe-bus \ and probe this bus pci-device-number 0 > IF LEAVE THEN \ if we found a device we're done LOOP \ else next bus ; : (probe-pci-host-bridge) ( bus-max bus-min -- ) 0d emit ." Adapters on " puid 10 0.r cr \ print the puid we're looking at ( bus-max bus-min ) pci-probe-all \ and walk the bus pci-device-number 0= IF \ IF no devices found 15 spaces \ | indent the output ." None" cr \ | tell the world our result THEN \ FI ; : probe-pci-host-bridge ( bus-max bus-min mmio-max mmio-base mem-max mem-base io-max io-base my-puid -- ) puid >r TO puid \ save puid and set the new pci-next-io ! \ save the next io-base address pci-max-io ! \ save the max io-space address pci-next-mem ! \ save the next mem-base address pci-max-mem ! \ save the max mem-space address pci-next-mmio ! \ save the next mmio-base address pci-max-mmio ! \ save the max mmio-space address (probe-pci-host-bridge) r> TO puid \ restore puid ; 0 VALUE pci-net-num 0 VALUE pci-disk-num 0 VALUE pci-cdrom-num : pci-set-alias ( str-addr str-len num -- ) $cathex strdup \ create alias name get-node node>path \ get path string set-alias \ and set the alias ; : unknown-enet ( -- pci-net-num ) pci-net-num dup 1+ TO pci-net-num ; : pci-alias-net ( config-addr -- ) drop \ forget the config address pci-net-num dup 1+ TO pci-net-num \ increase the pci-net-num s" net" rot pci-set-alias \ create the alias ; : pci-alias-disk ( config-addr -- ) drop \ forget the config address pci-disk-num dup 1+ TO pci-disk-num \ increase the pci-disk-num s" disk" rot pci-set-alias \ create the alias ; : pci-alias-cdrom ( config-addr -- ) drop \ forget the config address pci-cdrom-num dup 1+ TO pci-cdrom-num \ increase the pci-cdrom-num s" cdrom" rot pci-set-alias \ create the alias ; : pci-alias ( config-addr -- ) dup pci-class@ 10 rshift CASE 01 OF pci-alias-disk ENDOF 02 OF pci-alias-net ENDOF dup OF drop ENDOF ENDCASE ; : pci-gen-irq-map-one ( prop-addr prop-len slot pin -- prop-addr prop-len ) 2dup + 1- 3 and 1+ ( prop-addr prop-len slot pin parentpin ) >r >r ( prop-addr prop-len slot R: parentpin pin ) B lshift encode-int+ ( prop-addr prop-len R: parentpin pin ) 0 encode-64+ r> encode-int+ ( prop-addr prop-len R: parentpin ) get-parent encode-int+ get-node >space pci-addr2dev B lshift ( prop-addr prop-len parent-slot R: parentpin ) encode-int+ 0 encode-64+ r> encode-int+ ( prop-addr prop-len R: ) ; : pci-gen-irq-entry ( prop-addr prop-len config-addr -- prop-addr prop-len ) pci-addr2dev ( prop-addr prop-len slot ) -rot ( slot prop-addr prop-len ) 5 1 DO 2 pick i ( slot prop-addr prop-len slot pin ) pci-gen-irq-map-one LOOP rot drop ; : pci-set-irq-line ( config-addr -- ) drop ; : pci-msi-prop ( addr -- ) 5 pci-cap-find ( capaddr ) ?dup IF 2+ rtas-config-w@ ( msi-control ) 1 rshift 7 and ( msi-control:3:1 ) dup 6 < IF 1 swap lshift ( vectors# ) encode-int " ibm,req#msi" property ELSE ." Invalid MSI vectors number " . cr THEN THEN ; : pci-msix-prop ( addr -- ) 11 pci-cap-find ( capaddr ) ?dup IF 2+ rtas-config-w@ ( msix-control ) 7ff and ( msix-control:10:0 ) 1+ ( vectors# ) ?dup IF encode-int " ibm,req#msi-x" property THEN THEN ; : pci-set-capabilities ( config-addr -- ) dup pci-msi-prop dup pci-msix-prop drop ; : pci-class-name-00 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 01 OF s" display" ENDOF dup OF s" legacy-device" ENDOF ENDCASE ; : pci-class-name-01 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" scsi" ENDOF 01 OF s" ide" ENDOF 02 OF s" fdc" ENDOF 03 OF s" ipi" ENDOF 04 OF s" raid" ENDOF 05 OF s" ata" ENDOF 06 OF s" sata" ENDOF 07 OF s" sas" ENDOF dup OF s" mass-storage" ENDOF ENDCASE ; : pci-class-name-02 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" ethernet" ENDOF 01 OF s" token-ring" ENDOF 02 OF s" fddi" ENDOF 03 OF s" atm" ENDOF 04 OF s" isdn" ENDOF 05 OF s" worldfip" ENDOF 05 OF s" picmg" ENDOF dup OF s" network" ENDOF ENDCASE ; : pci-class-name-03 ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" vga" ENDOF 0100 OF s" xga" ENDOF 0200 OF s" 3d-controller" ENDOF dup OF s" display" ENDOF ENDCASE ; : pci-class-name-04 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" video" ENDOF 01 OF s" sound" ENDOF 02 OF s" telephony" ENDOF dup OF s" multimedia-device" ENDOF ENDCASE ; : pci-class-name-05 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" memory" ENDOF 01 OF s" flash" ENDOF dup OF s" memory-controller" ENDOF ENDCASE ; : pci-class-name-06 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" host" ENDOF 01 OF s" isa" ENDOF 02 OF s" eisa" ENDOF 03 OF s" mca" ENDOF 04 OF s" pci" ENDOF 05 OF s" pcmcia" ENDOF 06 OF s" nubus" ENDOF 07 OF s" cardbus" ENDOF 08 OF s" raceway" ENDOF 09 OF s" semi-transparent-pci" ENDOF 0A OF s" infiniband" ENDOF dup OF s" unknown-bridge" ENDOF ENDCASE ; : pci-class-name-07 ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" serial" ENDOF 0100 OF s" parallel" ENDOF 0200 OF s" multiport-serial" ENDOF 0300 OF s" modem" ENDOF 0400 OF s" gpib" ENDOF 0500 OF s" smart-card" ENDOF dup OF s" communication-controller" ENDOF ENDCASE ; : pci-class-name-08 ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" interrupt-controller" ENDOF 0100 OF s" dma-controller" ENDOF 0200 OF s" timer" ENDOF 0300 OF s" rtc" ENDOF 0400 OF s" hot-plug-controller" ENDOF 0500 OF s" sd-host-controller" ENDOF dup OF s" system-peripheral" ENDOF ENDCASE ; : pci-class-name-09 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" keyboard" ENDOF 01 OF s" pen" ENDOF 02 OF s" mouse" ENDOF 03 OF s" scanner" ENDOF 04 OF s" gameport" ENDOF dup OF s" input-controller" ENDOF ENDCASE ; : pci-class-name-0A ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" dock" ENDOF dup OF s" docking-station" ENDOF ENDCASE ; : pci-class-name-0B ( addr -- str len ) pci-class@ 8 rshift FF and CASE 02 OF s" pentium" ENDOF 20 OF s" powerpc" ENDOF 30 OF s" mips" ENDOF 40 OF s" co-processor" ENDOF dup OF s" cpu" ENDOF ENDCASE ; : pci-class-name-0C ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" firewire" ENDOF 0100 OF s" access-bus" ENDOF 0200 OF s" ssa" ENDOF 0300 OF s" usb-uhci" ENDOF 0310 OF s" usb-ohci" ENDOF 0320 OF s" usb-ehci" ENDOF 0330 OF s" usb-xhci" ENDOF 0380 OF s" usb-unknown" ENDOF 03FE OF s" usb-device" ENDOF 0400 OF s" fibre-channel" ENDOF 0500 OF s" smb" ENDOF 0600 OF s" infiniband" ENDOF 0700 OF s" ipmi" ENDOF 0701 OF s" ipmi" ENDOF 0702 OF s" ipmi" ENDOF 0800 OF s" sercos" ENDOF 0900 OF s" canbus" ENDOF dup OF s" serial-bus" ENDOF ENDCASE ; : pci-class-name-0D ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" irda" ENDOF 01 OF s" consumer-ir" ENDOF 10 OF s" rf-controller" ENDOF 11 OF s" bluetooth" ENDOF 12 OF s" broadband" ENDOF dup OF s" wireless-controller" ENDOF ENDCASE ; : pci-class-name-0E ( addr -- str len ) pci-class@ 8 rshift FF and CASE dup OF s" intelligent-io" ENDOF ENDCASE ; : pci-class-name-0F ( addr -- str len ) pci-class@ 8 rshift FF and CASE 01 OF s" satellite-tv" ENDOF 02 OF s" satellite-audio" ENDOF 03 OF s" satellite-voice" ENDOF 04 OF s" satellite-data" ENDOF dup OF s" satellite-device" ENDOF ENDCASE ; : pci-class-name-10 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" network-encryption" ENDOF 01 OF s" entertainment-encryption" ENDOF dup OF s" encryption" ENDOF ENDCASE ; : pci-class-name-11 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" dpio" ENDOF 01 OF s" counter" ENDOF 10 OF s" measurement" ENDOF 20 OF s" managment-card" ENDOF dup OF s" data-processing-controller" ENDOF ENDCASE ; : pci-class-name ( addr -- str len ) dup pci-class@ 10 rshift CASE 00 OF pci-class-name-00 ENDOF 01 OF pci-class-name-01 ENDOF 02 OF pci-class-name-02 ENDOF 03 OF pci-class-name-03 ENDOF 04 OF pci-class-name-04 ENDOF 05 OF pci-class-name-05 ENDOF 06 OF pci-class-name-06 ENDOF 07 OF pci-class-name-07 ENDOF 08 OF pci-class-name-08 ENDOF 09 OF pci-class-name-09 ENDOF 0A OF pci-class-name-0A ENDOF 0B OF pci-class-name-0B ENDOF 0C OF pci-class-name-0C ENDOF 0D OF pci-class-name-0D ENDOF 0E OF pci-class-name-0E ENDOF 0F OF pci-class-name-0F ENDOF 10 OF pci-class-name-10 ENDOF 11 OF pci-class-name-11 ENDOF dup OF drop s" unknown" ENDOF ENDCASE ; : pci-bar-size@ ( bar-addr -- bar-size ) -1 over rtas-config-l! rtas-config-l@ ; : pci-bar-size-mem@ ( bar-addr -- mem-size ) pci-bar-size@ -10 and invert 1+ FFFFFFFF and ; : pci-bar-size-io@ ( bar-addr -- io-size ) pci-bar-size@ -4 and invert 1+ FFFFFFFF and ; : pci-bar-size ( bar-addr -- bar-size-raw ) dup rtas-config-l@ swap \ fetch original Value ( bval baddr ) -1 over rtas-config-l! \ make BAR show size ( bval baddr ) dup rtas-config-l@ \ and fetch the size ( bval baddr bsize ) -rot rtas-config-l! \ restore Value ; : pci-bar-size-mem32 ( bar-addr -- bar-size ) pci-bar-size \ fetch raw size -10 and invert 1+ \ calc size FFFFFFFF and \ keep lower 32 bits ; : pci-bar-size-rom ( bar-addr -- bar-size ) pci-bar-size \ fetch raw size FFFFF800 and invert 1+ \ calc size FFFFFFFF and \ keep lower 32 bits ; : pci-bar-size-mem64 ( bar-addr -- bar-size ) dup pci-bar-size \ fetch raw size lower 32 bits swap 4 + pci-bar-size \ fetch raw size upper 32 bits 20 lshift + \ and put them together -10 and invert 1+ \ calc size ; : pci-bar-size-io ( bar-addr -- bar-size ) pci-bar-size \ fetch raw size -4 and invert 1+ \ calc size FFFFFFFF and \ keep lower 32 bits ; : pci-bar-code@ ( bar-addr -- 0|1..4|5 ) rtas-config-l@ dup \ fetch the BaseAddressRegister 1 and IF \ IO BAR ? 2 and IF 0 ELSE 1 THEN \ only '01' is valid ELSE \ Memory BAR ? F and CASE 0 OF 2 ENDOF \ Memory 32 Bit Non-Prefetchable 8 OF 3 ENDOF \ Memory 32 Bit Prefetchable 4 OF 4 ENDOF \ Memory 64 Bit Non-Prefetchable C OF 5 ENDOF \ Memory 64 Bit Prefechtable dup OF 0 ENDOF \ Not a valid BarType ENDCASE THEN ; : assign-var-align ( size align var -- al-mem ) dup >r @ \ ( size align cur-mem ) swap #aligned \ ( size al-mem ) tuck + \ ( al-mem new-mem ) r> ! \ ( al-mem ) ; : assign-var-min-align ( size min-align var -- al-mem ) >r over umax \ ( size align ) r> assign-var-align \ ( al-mem ) ; : assign-bar-value32 ( bar size var -- 4 ) over IF \ IF size > 0 >r \ | ( bar size ) pci-mem-bar-min-align \ | ( bar size min-align ) r> assign-var-min-align \ | ( bar al-mem ) set variable to next mem swap rtas-config-l! \ | ( -- ) set the bar to al-mem ELSE \ ELSE 2drop drop \ | clear stack THEN \ FI 4 \ size of the base-address-register ; : assign-io-bar-value32 ( bar size var -- 4 ) over IF \ IF size > 0 >r \ | ( bar size ) dup \ | ( bar size size-align ) r> assign-var-align \ | ( bar al-mem ) set variable to next mem swap rtas-config-l! \ | ( -- ) set the bar to al-mem ELSE \ ELSE 2drop drop \ | clear stack THEN \ FI 4 \ size of the base-address-register ; : assign-bar-value64 ( bar size var -- 8 ) over IF \ IF size > 0 >r \ | ( bar size ) pci-mem-bar-min-align \ | ( bar size min-align ) r> assign-var-min-align \ | ( bar al-mem ) set variable to next mem swap \ | ( al-mem addr ) calc config-addr of this bar 2dup rtas-config-l! \ | ( al-mem addr ) set the Lower part of the bar to al-mem 4 + swap 20 rshift \ | ( al-mem>>32 addr ) prepare the upper part of the al-mem swap rtas-config-l! \ | ( -- ) and set the upper part of the bar ELSE \ ELSE 2drop drop \ | clear stack THEN \ FI 8 \ size of the base-address-register ; : assign-mem64-bar ( bar-addr -- 8 ) dup pci-bar-size-mem64 \ fetch size pci-next-mem64 @ 0 = IF \ Check if we have 64-bit memory range pci-next-mem ELSE pci-next-mem64 THEN assign-bar-value64 \ and set it all ; : assign-mem32-bar ( bar-addr -- 4 ) dup pci-bar-size-mem32 \ fetch size pci-next-mem @ IF pci-next-mem ELSE pci-next-mmio THEN assign-bar-value32 \ and set it all ; : assign-mmio64-bar ( bar-addr -- 8 ) dup pci-bar-size-mem64 \ fetch size pci-next-mmio assign-bar-value64 \ and set it all ; : assign-mmio32-bar ( bar-addr -- 4 ) dup pci-bar-size-mem32 \ fetch size pci-next-mmio \ var to change assign-bar-value32 \ and set it all ; : assign-io-bar ( bar-addr -- 4 ) dup pci-bar-size-io \ fetch size pci-next-io \ var to change assign-io-bar-value32 \ and set it all ; : assign-rom-bar ( bar-addr -- ) dup pci-bar-size-rom \ fetch size dup IF \ IF size > 0 over >r \ | save bar addr for enable pci-next-mmio \ | var to change assign-bar-value32 \ | and set it drop \ | forget the BAR length r@ rtas-config-l@ \ | fetch BAR 1 or r> rtas-config-l! \ | and enable the ROM ELSE \ ELSE 2drop \ | clear stack THEN ; : assign-bar ( bar-addr -- reg-size ) dup pci-bar-code@ \ calc BAR type dup IF \ IF >0 CASE \ | CASE Setup the right type 1 OF assign-io-bar ENDOF \ | - set up an IO-Bar 2 OF assign-mmio32-bar ENDOF \ | - set up an 32bit MMIO-Bar 3 OF assign-mem32-bar ENDOF \ | - set up an 32bit MEM-Bar (prefetchable) 4 OF assign-mmio64-bar ENDOF \ | - set up an 64bit MMIO-Bar 5 OF assign-mem64-bar ENDOF \ | - set up an 64bit MEM-Bar (prefetchable) ENDCASE \ | ESAC ELSE \ ELSE ABORT \ | Throw an exception THEN \ FI ; : assign-all-device-bars ( configaddr -- ) 28 10 DO \ BARs start at 10 and end at 27 dup i + \ calc config-addr of the BAR assign-bar \ and set it up +LOOP \ add 4 or 8 to the index and loop 30 + assign-rom-bar \ set up the ROM if available ; : assign-all-bridge-bars ( configaddr -- ) 18 10 DO \ BARs start at 10 and end at 17 dup i + \ calc config-addr of the BAR assign-bar \ and set it up +LOOP \ add 4 or 8 to the index and loop 38 + assign-rom-bar \ set up the ROM if available ; : gen-mem64-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 8 ) dup pci-bar-size-mem64 \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch lower 32 bits ( paddr plen baddr val.lo R: size) over 4 + rtas-config-l@ \ | fetch upper 32 bits ( paddr plen baddr val.lo val.hi R: size) 20 lshift + -10 and >r \ | calc 64 bit value and save it ( paddr plen baddr R: size val ) 82000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 8 \ sizeof(BAR) = 8 Bytes ; : gen-pmem64-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 8 ) dup pci-bar-size-mem64 \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch lower 32 bits ( paddr plen baddr val.lo R: size) over 4 + rtas-config-l@ \ | fetch upper 32 bits ( paddr plen baddr val.lo val.hi R: size) 20 lshift + -10 and >r \ | calc 64 bit value and save it ( paddr plen baddr R: size val ) C3000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 8 \ sizeof(BAR) = 8 Bytes ; : gen-mem32-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 ) dup pci-bar-size-mem32 \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) -10 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) 82000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ sizeof(BAR) = 4 Bytes ; : gen-pmem32-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 ) dup pci-bar-size-mem32 \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) -10 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) C2000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ sizeof(BAR) = 4 Bytes ; : gen-io-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 ) dup pci-bar-size-io \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) -4 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) 81000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ sizeof(BAR) = 4 Bytes ; : gen-rom-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len ) dup pci-bar-size-rom \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) FFFFF800 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) 82000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI ; : pci-add-assigned-address ( prop-addr prop-len bar-addr -- prop-addr prop-len bsize ) dup pci-bar-code@ \ calc BAR type ( paddr plen baddr btype) CASE \ CASE for the BAR types ( paddr plen baddr ) 0 OF drop 4 ENDOF \ - not a valid type so do nothing 1 OF gen-io-bar-prop ENDOF \ - IO-BAR 2 OF gen-mem32-bar-prop ENDOF \ - MEM32 3 OF gen-pmem32-bar-prop ENDOF \ - MEM32 prefetchable 4 OF gen-mem64-bar-prop ENDOF \ - MEM64 5 OF gen-pmem64-bar-prop ENDOF \ - MEM64 prefetchable ENDCASE \ ESAC ( paddr plen bsize ) ; : pci-device-assigned-addresses-prop ( addr -- ) encode-start \ provide mem for property ( addr paddr plen ) 2 pick 30 + gen-rom-bar-prop \ assign the rom bar 28 10 DO \ we have 6 possible BARs 2 pick i + \ calc BAR address ( addr paddr plen bar-addr ) pci-add-assigned-address \ and generate the props for the BAR +LOOP \ increase Index by returned len s" assigned-addresses" property drop \ and write it into the device tree ; : pci-bridge-assigned-addresses-prop ( addr -- ) encode-start \ provide mem for property 2 pick 38 + gen-rom-bar-prop \ assign the rom bar 18 10 DO \ we have 2 possible BARs 2 pick i + \ ( addr paddr plen current-addr ) pci-add-assigned-address \ and generate the props for the BAR +LOOP \ increase Index by returned len s" assigned-addresses" property drop \ and write it into the device tree ; : pci-bridge-gen-range ( paddr plen base limit type -- paddr plen ) >r over - \ calc size ( paddr plen base size R:type ) dup 0< IF \ IF Size < 0 ( paddr plen base size R:type ) 2drop r> drop \ | forget values ( paddr plen ) ELSE \ ELSE 1+ swap 2swap \ | adjust stack ( size base paddr plen R:type ) r@ encode-int+ \ | Child type ( size base paddr plen R:type ) 2 pick encode-64+ \ | Child address ( size base paddr plen R:type ) r> encode-int+ \ | Parent type ( size base paddr plen ) rot encode-64+ \ | Parent address ( size paddr plen ) rot encode-64+ \ | Encode size ( paddr plen ) THEN \ FI ; : pci-bridge-gen-mmio-range ( addr prop-addr prop-len -- addr prop-addr prop-len ) 2 pick 20 + rtas-config-l@ \ fetch Value ( addr paddr plen val ) dup 0000FFF0 and 10 lshift \ calc base-address ( addr paddr plen val base ) swap 000FFFFF or \ calc limit-address ( addr paddr plen base limit ) 02000000 pci-bridge-gen-range \ and generate it ( addr paddr plen ) ; : pci-bridge-gen-mem-range ( addr prop-addr prop-len -- addr prop-addr prop-len ) 2 pick 24 + rtas-config-l@ \ fetch Value ( addr paddr plen val ) dup 000FFFFF or \ calc limit Bits 31:0 ( addr paddr plen val limit.31:0 ) swap 0000FFF0 and 10 lshift \ calc base Bits 31:0 ( addr paddr plen limit.31:0 base.31:0 ) 4 pick 28 + rtas-config-l@ \ fetch upper Basebits ( addr paddr plen limit.31:0 base.31:0 base.63:32 ) 20 lshift or swap \ and calc Base ( addr paddr plen base.63:0 limit.31:0 ) 4 pick 2C + rtas-config-l@ \ fetch upper Limitbits ( addr paddr plen base.63:0 limit.31:0 limit.63:32 ) dup -rot 20 lshift or swap \ and calc Limit ( addr paddr plen base.63:0 limit.63:0 limit.63:32 ) IF 43000000 ELSE 42000000 THEN \ 64-bit or 32-bit? ( addr paddr plen base.63:0 limit.63:0 type ) pci-bridge-gen-range \ and generate it ( addr paddr plen ) ; : pci-bridge-gen-io-range ( addr prop-addr prop-len -- addr prop-addr prop-len ) 2 pick 1C + rtas-config-l@ \ fetch Value ( addr paddr plen val ) dup 0000F000 and 00000FFF or \ calc Limit Bits 15:0 ( addr paddr plen val limit.15:0 ) swap 000000F0 and 8 lshift \ calc Base Bits 15:0 ( addr paddr plen limit.15:0 base.15:0 ) 4 pick 30 + rtas-config-l@ \ fetch upper Bits ( addr paddr plen limit.15:0 base.15:0 val ) dup FFFF and 10 lshift rot or \ calc Base ( addr paddr plen limit.15:0 val base.31:0 ) -rot FFFF0000 and or \ calc Limit ( addr paddr plen base.31:0 limit.31:0 ) 01000000 pci-bridge-gen-range \ and generate it ( addr paddr plen ) ; : pci-bridge-range-props ( addr -- ) encode-start \ provide mem for property pci-bridge-gen-mmio-range \ generate the non prefetchable Memory Entry pci-bridge-gen-mem-range \ generate the prefetchable Memory Entry pci-bridge-gen-io-range \ generate the IO Entry dup IF \ IF any space present (propsize>0) s" ranges" property \ | write it into the device tree ELSE \ ELSE s" " s" ranges" property 2drop \ | forget the properties THEN \ FI drop \ forget the address ; : pci-bridge-interrupt-map ( -- ) encode-start \ create the property ( paddr plen ) get-node child \ find the first child ( paddr plen handle ) BEGIN dup WHILE \ Loop as long as the handle is non-zero ( paddr plen handle ) dup >r >space \ Get the my-space ( paddr plen addr R: handle ) pci-gen-irq-entry \ and Encode the interrupt settings ( paddr plen R: handle) r> peer \ Get neighbour ( paddr plen handle ) REPEAT \ process next childe node ( paddr plen handle ) drop \ forget the null ( paddr plen ) s" interrupt-map" property \ and set it ( -- ) 1 encode-int s" #interrupt-cells" property \ encode the cell# f800 encode-int 0 encode-int+ 0 encode-int+ \ encode the bit mask for config addr (Dev only) 7 encode-int+ s" interrupt-map-mask" property \ encode IRQ#=7 and generate property ; : encode-mem32-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 4 ) dup pci-bar-size-mem32 \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 02000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ BAR-Len = 4 (32Bit) ; : encode-pmem32-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 4 ) dup pci-bar-size-mem32 \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 42000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ BAR-Len = 4 (32Bit) ; : encode-mem64-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 8 ) dup pci-bar-size-mem64 \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 03000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 8 \ BAR-Len = 8 (64Bit) ; : encode-pmem64-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 8 ) dup pci-bar-size-mem64 \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 43000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 8 \ BAR-Len = 8 (64Bit) ; : encode-rom-bar ( prop-addr prop-len configaddr -- prop-addr prop-len ) dup pci-bar-size-rom \ fetch raw BAR-size dup IF \ IF BAR is used >r 02000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | calc and encode the size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI ; : encode-io-bar ( prop-addr prop-len BAR-addr BAR-value -- prop-addr prop-len 4 ) dup pci-bar-size-io \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 01000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ BAR-Len = 4 (32Bit) ; : encode-bar ( prop-addr prop-len bar-addr -- prop-addr prop-len bar-len ) dup pci-bar-code@ \ calc BAR type CASE \ CASE for the BAR types ( paddr plen baddr val ) 0 OF drop 4 ENDOF \ - not a valid type so do nothing 1 OF encode-io-bar ENDOF \ - IO-BAR 2 OF encode-mem32-bar ENDOF \ - MEM32 3 OF encode-pmem32-bar ENDOF \ - MEM32 prefetchable 4 OF encode-mem64-bar ENDOF \ - MEM64 5 OF encode-pmem64-bar ENDOF \ - MEM64 prefetchable ENDCASE \ ESAC ( paddr plen blen ) ; : pci-reg-props ( configaddr -- ) dup encode-int \ configuration space ( caddr paddr plen ) 0 encode-64+ \ make the rest 0 0 encode-64+ \ encode the size as 0 2 pick pci-htype@ \ fetch Header Type ( caddr paddr plen type ) 1 and IF \ IF Bridge ( caddr paddr plen ) 18 10 DO \ | loop over all BARs 2 pick i + \ | calc bar-addr ( caddr paddr plen baddr ) encode-bar \ | encode this BAR ( caddr paddr plen blen ) +LOOP \ | increase LoopIndex by the BARlen 2 pick 38 + \ | calc ROM-BAR for a bridge ( caddr paddr plen baddr ) encode-rom-bar \ | encode the ROM-BAR ( caddr paddr plen ) ELSE \ ELSE ordinary device ( caddr paddr plen ) 28 10 DO \ | loop over all BARs 2 pick i + \ | calc bar-addr ( caddr paddr plen baddr ) encode-bar \ | encode this BAR ( caddr paddr plen blen ) +LOOP \ | increase LoopIndex by the BARlen 2 pick 30 + \ | calc ROM-BAR for a device ( caddr paddr plen baddr ) encode-rom-bar \ | encode the ROM-BAR ( caddr paddr plen ) THEN \ FI ( caddr paddr plen ) s" reg" property \ and store it into the property drop ; : pci-common-props ( addr -- ) dup pci-class-name device-name dup pci-vendor@ encode-int s" vendor-id" property dup pci-device@ encode-int s" device-id" property dup pci-revision@ encode-int s" revision-id" property dup pci-class@ encode-int s" class-code" property 3 encode-int s" #address-cells" property 2 encode-int s" #size-cells" property dup pci-config-ext? IF 1 encode-int s" ibm,pci-config-space-type" property THEN dup pci-status@ dup 9 rshift 3 and encode-int s" devsel-speed" property dup 7 rshift 1 and IF 0 0 s" fast-back-to-back" property THEN dup 6 rshift 1 and IF 0 0 s" 66mhz-capable" property THEN 5 rshift 1 and IF 0 0 s" udf-supported" property THEN dup pci-cache@ ?dup IF encode-int s" cache-line-size" property THEN pci-interrupt@ ?dup IF encode-int s" interrupts" property THEN ; : pci-device-props ( addr -- ) dup pci-common-props dup pci-min-grant@ encode-int s" min-grant" property dup pci-max-lat@ encode-int s" max-latency" property dup pci-sub-device@ ?dup IF encode-int s" subsystem-id" property THEN dup pci-sub-vendor@ ?dup IF encode-int s" subsystem-vendor-id" property THEN dup pci-device-assigned-addresses-prop pci-reg-props pci-hotplug-enabled IF dup dup pci-addr2bus 8 lshift swap pci-addr2dev 3 lshift or 40000000 + encode-int s" ibm,my-drc-index" property dup dup pci-addr2bus 20 * swap pci-addr2dev + a base ! s" Slot " rot $cathex hex encode-string s" ibm,loc-code" property THEN ; : pci-bridge-props ( addr -- ) dup pci-bus@ encode-int s" primary-bus" property encode-int s" secondary-bus" property encode-int s" subordinate-bus" property dup pci-bus@ drop encode-int rot encode-int+ s" bus-range" property pci-device-slots encode-int s" slot-names" property dup pci-bridge-range-props dup pci-bridge-assigned-addresses-prop s" interrupt-map" get-node get-property IF pci-bridge-interrupt-map ELSE 2drop THEN pci-reg-props ; : pci-bridge-generic-setup ( addr -- ) pci-device-slots >r \ save the slot array on return stack dup pci-common-props \ set the common properties before scanning the bus s" pci" device-type \ the type is allways "pci" dup func-pci-bridge-probe \ find all device connected to it dup assign-all-bridge-bars \ set up all memory access BARs dup pci-set-irq-line \ set the interrupt pin dup pci-set-capabilities \ set up the capabilities pci-bridge-props \ and generate all properties r> TO pci-device-slots \ and reset the slot array ; DEFER func-pci-device-props : pci-device-generic-setup ( config-addr -- ) dup assign-all-device-bars \ calc all BARs dup pci-set-irq-line \ set the interrupt pin dup pci-set-capabilities \ set up the capabilities dup func-pci-device-props \ and generate all properties drop \ forget the config-addr ; ' pci-device-props TO func-pci-device-props ' pci-bridge-range-props TO func-pci-bridge-range-props : populate-pci-busses ( -- ) " /" find-device get-node child BEGIN dup 0 <> WHILE dup set-node dup " name" rot get-package-property 0 = IF drop dup from-cstring 2dup s" pci" strequal IF s" pci-phb.fs" included THEN 2drop THEN peer REPEAT drop device-end ; populate-pci-busses 600 cp : check-patch-kernel-sc1 ( -- ) ciregs >r4 @ dup 1000000 + dup 2000000 < IF 0 ELSE dup 2000000 - THEN swap check-and-patch-sc1 ; ' check-patch-kernel-sc1 add-quiesce-xt ' rtas-quiesce add-quiesce-xt 6c0 cp set-chosen-cpu s" /memory@0" open-dev encode-int s" memory" set-chosen 700 cp s" /openprom" find-device s" SLOF," slof-build-id here swap rmove here slof-build-id nip $cat encode-string s" model" property 0 0 s" relative-addressing" property device-end s" /mmu" open-dev encode-int s" mmu" set-chosen VARIABLE chosen-memory-ih 0 chosen-memory-ih ! : (chosen-memory-ph) ( -- phandle ) chosen-memory-ih @ ?dup 0= IF s" memory" get-chosen IF decode-int nip nip dup chosen-memory-ih ! ihandle>phandle ELSE 0 THEN ELSE ihandle>phandle THEN ; : (set-available-prop) ( prop plen -- ) s" available" (chosen-memory-ph) ?dup 0<> IF set-property ELSE cr ." Can't find chosen memory node - " ." no available property created" cr 2dup 2dup THEN ; : update-available-property ( available-ptr -- ) dup >r available>size@ 0= r@ available AVAILABLE-SIZE /available * + >= or IF available r> available - encode-bytes (set-available-prop) ELSE r> /available + RECURSE THEN ; : update-available-property available update-available-property ; : claim ( [ addr ] len align -- base ) claim update-available-property ; : release ( addr len -- ) release update-available-property ; update-available-property 0 VALUE read-xt 0 VALUE write-xt VARIABLE stdin VARIABLE stdout : set-stdin ( ihandle -- ) stdin @ ?dup IF close-dev THEN dup stdin ! encode-int s" stdin" set-chosen ; : set-stdout ( ihandle -- ) stdout @ ?dup IF close-dev THEN dup stdout ! encode-int s" stdout" set-chosen ; : input ( dev-str dev-len -- ) open-dev ?dup IF dup s" read" rot ihandle>phandle find-method 0= IF drop cr ." Cannot find the read method for the given input console " cr EXIT THEN to read-xt set-stdin THEN ; : output ( dev-str dev-len -- ) open-dev ?dup IF dup s" write" rot ihandle>phandle find-method 0= IF drop cr ." Cannot find the write method for the given output console " cr EXIT THEN to write-xt set-stdout THEN ; : io ( dev-str dev-len -- ) 2dup input output ; 1 BUFFER: (term-io-char-buf) : term-io-emit ( char -- ) write-xt IF (term-io-char-buf) c! (term-io-char-buf) 1 write-xt stdout @ call-package drop ELSE serial-emit THEN ; ' term-io-emit to emit : term-io-key ( -- char ) read-xt IF BEGIN (term-io-char-buf) 1 read-xt stdin @ call-package 0 > UNTIL (term-io-char-buf) c@ ELSE serial-key THEN ; ' term-io-key to key : term-io-key? ( -- true|false ) stdin @ ?dup IF >r \ store ihandle on return stack s" device_type" r@ ihandle>phandle ( propstr len phandle ) get-property ( true | data dlen false ) IF false ELSE 1 - \ remove 1 from length to ignore null-termination char 2dup s" serial" str= IF 2drop serial-key? r> drop EXIT THEN \ call serial-key, cleanup return-stack, exit 2dup s" keyboard" str= IF 2drop ( ) s" key-available?" r@ ihandle>phandle find-method IF drop s" key-available?" r@ $call-method ELSE false THEN r> drop EXIT \ cleanup return-stack, exit THEN 2drop r> drop false EXIT \ unknown device_type cleanup return-stack, return false THEN ELSE serial-key? THEN ; ' term-io-key? to key? 800 cp 51 CONSTANT nvram-partition-type-cpulog 60 CONSTANT nvram-partition-type-sas 61 CONSTANT nvram-partition-type-sms 6e CONSTANT nvram-partition-type-debug 6f CONSTANT nvram-partition-type-history 70 CONSTANT nvram-partition-type-common 7f CONSTANT nvram-partition-type-freespace a0 CONSTANT nvram-partition-type-linux : rztype ( str len -- ) \ stop at zero byte, read with nvram-c@ 0 DO dup i + nvram-c@ ?dup IF ( str char ) emit ELSE ( str ) drop UNLOOP EXIT THEN LOOP ; create tmpStr 500 allot : rzcount ( zstr -- str len ) dup tmpStr >r BEGIN dup nvram-c@ dup r> dup 1+ >r c! WHILE char+ REPEAT r> drop over - swap drop tmpStr swap ; : calc-header-cksum ( offset -- cksum ) dup nvram-c@ 10 2 DO over I + nvram-c@ + LOOP wbsplit + nip ; : bad-header? ( offset -- flag ) dup 2+ nvram-w@ ( offset length ) 0= IF ( offset ) drop true EXIT ( ) THEN dup calc-header-cksum ( offset checksum' ) swap 1+ nvram-c@ ( checksum ' checksum ) <> ( flag ) ; : .header ( offset -- ) cr ( offset ) dup bad-header? IF ( offset ) ." BAD HEADER -- trying to print it anyway" cr THEN space ( offset ) dup nvram-c@ 2 0.r ( offset ) space space ( offset ) dup 2+ nvram-w@ 10 * 5 .r ( offset ) space space ( offset ) 4 + 0c rztype ( ) ; : .headers ( -- ) cr cr ." Type Size Name" cr ." ========================" 0 BEGIN ( offset ) dup nvram-c@ ( offset type ) WHILE dup .header ( offset ) dup 2+ nvram-w@ 10 * + ( offset offset' ) dup nvram-size < IF ( offset ) ELSE drop EXIT ( ) THEN REPEAT drop ( ) cr cr ; : reset-nvram ( -- ) internal-reset-nvram ; : dump-partition ['] nvram-c@ 1 (dump) ; : type-no-zero ( addr len -- ) 0 DO dup I + dup nvram-c@ 0= IF drop ELSE nvram-c@ emit THEN LOOP drop ; : type-no-zero-part ( from-str cnt-str addr len ) 0 DO dup i + dup nvram-c@ 0= IF drop ELSE 3 pick 0= 3 pick 0 > AND IF dup 1 type-no-zero THEN nvram-c@ a = IF 2 pick 0= IF over 1- 0 max rot drop swap THEN 2 pick 1- 0 max 3 roll drop rot rot THEN THEN LOOP drop ; : (dmesg-prepare) ( base-addr -- base-addr' addr len act-off ) 10 - \ go back to header dup 14 + nvram-l@ dup >r ( base-addr act-off ) ( R: act-off ) over over over + swap 10 + nvram-w@ + >r ( base-addr act-off ) ( R: act-off nvram-act-addr ) over 2 + nvram-w@ 10 * swap - over swap ( base-addr base-addr start-size ) ( R: act-off nvram-act-addr ) r> swap rot 10 + nvram-w@ - r> ; : .dmesg ( base-addr -- ) (dmesg-prepare) >r cr type-no-zero ( base-addr ) ( R: act-off ) dup 10 + nvram-w@ + r> type-no-zero ; : .dmesg-part ( from-str cnt-str base-addr -- ) (dmesg-prepare) >r >r >r -rot r> r> cr type-no-zero-part rot ( base-addr ) ( R: act-off ) dup 10 + nvram-w@ + r> type-no-zero-part ; : dmesg-part ( from-str cnt-str -- left-from-str left-cnt-str ) 2dup s" ibm,CPU0log" get-named-nvram-partition IF 2drop EXIT THEN drop .dmesg-part nip nip ; : dmesg2 ( -- ) s" ibm,CPU1log" get-named-nvram-partition IF ." No log partition." cr EXIT THEN drop .dmesg ; : dmesg ( -- ) s" ibm,CPU0log" get-named-nvram-partition IF ." No log partition." cr EXIT THEN drop .dmesg ; 880 cp wordlist CONSTANT envvars : listenv ( -- ) get-current envvars set-current words set-current ; : create-env ( "name" -- ) get-current envvars set-current CREATE set-current ; : env-int ( n -- ) 1 c, align , DOES> char+ aligned @ ; : env-bytes ( a len -- ) 2 c, align dup , here swap dup allot move DOES> char+ aligned dup @ >r cell+ r> ; : env-string ( str len -- ) 3 c, align dup , here over allot swap move DOES> char+ aligned dup @ >r cell+ r> ; : env-flag ( f -- ) 4 c, c, DOES> char+ c@ 0<> ; : env-secmode ( sm -- ) 5 c, c, DOES> char+ c@ ; : default-int ( n "name" -- ) create-env env-int ; : default-bytes ( a len "name" -- ) create-env env-bytes ; : default-string ( a len "name" -- ) create-env env-string ; : default-flag ( f "name" -- ) create-env env-flag ; : default-secmode ( sm "name" -- ) create-env env-secmode ; : set-option ( option-name len option len -- ) 2swap encode-string 2swap s" /options" find-node dup IF set-property ELSE drop 2drop 2drop THEN ; : findenv ( name len -- adr def-adr type | 0 ) 2dup envvars voc-find dup 0<> IF ( ABORT" not a configuration variable" ) link> >body char+ >r (find-order) link> >body dup char+ swap c@ r> swap ELSE nip nip THEN ; : test-flag ( param len -- true | false ) 2dup s" true" string=ci -rot s" false" string=ci or ; : test-secmode ( param len -- true | false ) 2dup s" none" string=ci -rot 2dup s" command" string=ci -rot s" full" string=ci or or ; : test-int ( param len -- true | false ) $dh-number IF false ELSE drop true THEN ; : findtype ( param len name len -- param len name len type ) 2dup findenv \ try to find type of envvar dup IF \ found a type? nip nip EXIT THEN drop 2swap 2dup test-flag IF 4 -rot \ boolean type ELSE 2dup test-secmode IF 5 -rot \ secmode type ELSE 2dup test-int IF 1 -rot \ integer type ELSE 2dup test-string IF 3 ELSE 2 THEN \ 3 = string, 2 = default to bytes -rot THEN THEN THEN rot >r 2swap r> ; : $setenv ( param len name len -- ) 4dup set-option findtype -rot $CREATE CASE 1 OF $dh-number IF 0 THEN env-int ENDOF \ XXX: wants decimal and 0x... 2 OF env-bytes ENDOF 3 OF env-string ENDOF 4 OF evaluate env-flag ENDOF 5 OF evaluate env-secmode ENDOF \ XXX: recognize none, command, full ENDCASE ; : (printenv) ( adr type -- ) CASE 1 OF aligned @ . ENDOF 2 OF aligned dup cell+ swap @ swap . . ENDOF 3 OF aligned dup @ >r cell+ r> type ENDOF 4 OF c@ IF ." true" ELSE ." false" THEN ENDOF 5 OF c@ . ENDOF \ XXX: print symbolically ENDCASE ; : .printenv-header ( -- ) cr s" ---environment variable--------current value-------------default value------" type cr ; DEFER old-emit 0 VALUE emit-counter : emit-and-count emit-counter 1 + to emit-counter old-emit ; : .enable-emit-counter 0 to emit-counter ['] emit behavior to old-emit ['] emit-and-count to emit ; : .disable-emit-counter ['] old-emit behavior to emit ; : .spaces ( number-of-spaces -- ) dup 0 > IF spaces ELSE drop space THEN ; : .print-one-env ( name len -- ) 3 .spaces 2dup dup -rot type 1c swap - .spaces findenv rot over .enable-emit-counter (printenv) .disable-emit-counter 1a emit-counter - .spaces (printenv) ; : .print-all-env .printenv-header envvars cell+ BEGIN @ dup WHILE dup link> >name name>string .print-one-env cr REPEAT drop ; : printenv parse-word dup 0= IF 2drop .print-all-env ELSE findenv dup 0= ABORT" not a configuration variable" rot over cr ." Current: " (printenv) cr ." Default: " (printenv) THEN ; : (set-default) ( def-xt -- ) dup >name name>string 2dup $CREATE rot dup >body c@ >r execute r> CASE 1 OF dup env-int (.d) 2swap set-option ENDOF 2 OF 2dup env-bytes 2swap set-option ENDOF 3 OF 2dup env-string 2swap set-option ENDOF 4 OF dup env-flag IF s" true" ELSE s" false" THEN 2swap set-option ENDOF 5 OF dup env-secmode (.d) 2swap set-option ENDOF ENDCASE ; true default-flag auto-boot? s" " default-string boot-device s" " default-string boot-file s" boot" default-string boot-command s" " default-string diag-device s" " default-string diag-file false default-flag diag-switch? true default-flag fcode-debug? s" " default-string input-device s" " default-string nvramrc s" " default-string oem-banner false default-flag oem-banner? 0 0 default-bytes oem-logo false default-flag oem-logo? s" " default-string output-device 200 default-int screen-#columns 200 default-int screen-#rows 0 default-int security-#badlogins 0 default-secmode security-mode s" " default-string security-password 0 default-int selftest-#megs false default-flag use-nvramrc? false default-flag direct-serial? true default-flag real-mode? default-load-base default-int load-base VARIABLE nvoff \ offset in envvar partition : (nvupdate-one) ( adr type -- "value" ) CASE 1 OF aligned @ (.d) ENDOF 2 OF drop 0 0 ENDOF 3 OF aligned dup @ >r cell+ r> ENDOF 4 OF c@ IF s" true" ELSE s" false" THEN ENDOF 5 OF c@ (.) ENDOF \ XXX: print symbolically ENDCASE ; : nvupdate-one ( def-xt -- ) >r nvram-partition-type-common get-nvram-partition ( part.addr part.len FALSE|TRUE R: def-xt ) ABORT" No valid NVRAM." r> ( part.addr part.len def-xt ) >name name>string ( part.addr part.len var.a var.l ) 2dup findenv nip (nvupdate-one) internal-add-env drop ; : (nvupdate) ( -- ) nvram-partition-type-common get-nvram-partition ABORT" No valid NVRAM." erase-nvram-partition drop envvars cell+ BEGIN @ dup WHILE dup link> nvupdate-one REPEAT drop ; : nvupdate ( -- ) ." nvupdate is obsolete." cr ; : set-default parse-word envvars voc-find dup 0= ABORT" not a configuration variable" link> (set-default) ; : (set-defaults) envvars cell+ BEGIN @ dup WHILE dup link> (set-default) REPEAT drop ; (set-defaults) : set-defaults (set-defaults) (nvupdate) ; : setenv parse-word ( skipws ) 0d parse -leading 2swap $setenv (nvupdate) ; : get-nv ( -- ) nvram-partition-type-common get-nvram-partition ( addr offset not-found | not-found ) \ find partition header IF ." No NVRAM common partition, re-initializing..." cr internal-reset-nvram (nvupdate) EXIT THEN drop ( addr ) \ throw away offset BEGIN dup rzcount dup \ make string from offset and make condition WHILE ( offset offset length ) 2dup [char] = split \ Split string at equal sign (=) 2swap ( offset offset length param len name len ) $setenv \ Set envvar nip \ throw away old string begin + 1+ \ calc new offset REPEAT 2drop drop \ cleanup ; get-nv : check-for-nvramrc ( -- ) use-nvramrc? IF s" Executing following code from nvramrc: " s" nvramrc" evaluate $cat nvramlog-write-string-cr s" (!) Executing code specified in nvramrc" type cr s" SLOF Setup = " type .enable-emit-counter s" nvramrc" evaluate ['] evaluate CATCH IF 2drop emit-counter 0 DO 8 emit LOOP s" (!) Code in nvramrc triggered exception. " 2dup nvramlog-write-string type cr 12 spaces s" Aborting nvramrc execution" 2dup nvramlog-write-string-cr type cr s" SLOF Setup = " type THEN .disable-emit-counter THEN ; : (nv-findalias) ( alias-ptr alias-len -- pos ) here 0 s" devalias " string-cat 3 pick 3 pick string-cat s" " string-cat s" nvramrc" evaluate 2swap find-substr nip nip ; : (nv-build-real-entry) ( name-ptr name-len dev-ptr dev-len -- str-ptr str-len ) 2swap here 0 s" devalias " string-cat 2swap string-cat s" " string-cat 2swap string-cat 0d char-cat 0a char-cat ; : (nv-build-null-entry) ( name-ptr name-len dev-ptr dev-len -- str-ptr str-len ) 4drop here 0 ; : (nv-build-nvramrc) ( name-str name-len dev-str dev-len xt-build-entry -- ) 4 pick 4 pick (nv-findalias) dup s" nvramrc" evaluate nip >= IF drop execute s" nvramrc" evaluate string-cat dup allot s" nvramrc" $setenv ELSE \ if our alias is still defined in nvramrc 5 pick 5 pick 5 pick 5 pick 5 pick execute nip over + s" nvramrc" evaluate 3 pick string-at 2dup find-nextline string-at nip + alloc-mem 0 s" nvramrc" evaluate drop 3 pick string-cat rot >r >r >r execute r> r> 2swap string-cat ( mem, len ) ( R: alias-pos ) s" nvramrc" evaluate r> string-at 2dup find-nextline string-at string-cat 2dup s" nvramrc" $setenv free-mem THEN ; : $nvalias ( name-str name-len dev-str dev-len -- ) 4dup ['] (nv-build-real-entry) (nv-build-nvramrc) set-alias s" true" s" use-nvramrc?" $setenv (nvupdate) ; : nvalias ( "alias-name< >device-specifier" -- ) parse-word parse-word dup 0<> IF $nvalias ELSE 2drop 2drop cr " Usage: nvalias (""alias-name< >device-specifier"" -- )" type cr THEN ; : $nvunalias ( name-str name-len -- ) s" " ['] (nv-build-null-entry) (nv-build-nvramrc) (nvupdate) ; : nvunalias ( "alias-name< >" -- ) parse-word $nvunalias ; : diagnostic-mode? ( -- diag-switch? ) diag-switch? ; check-for-nvramrc 890 cp defer set-boot-device defer add-boot-device : add-boot-aliases ( str -- ) 2dup add-boot-device ( $str ) MAX-ALIAS 1 DO 2dup i $cathex 2dup ( $str $strN $strN ) find-alias 0 > IF ( $str $strN false | $result ) drop strdup add-boot-device ( $str ) ELSE 2drop THEN LOOP 2drop ; : is-strict-boot? ( bl-str bl-len -- strict? ) dup 4 > IF + 5 - 5 s" HALT" str= ELSE s" HALT" str= THEN ; : qemu-read-bootlist ( -- ) " qemu,boot-list" get-chosen IF 1- \ Ignore the trailing NUL character 2dup set-boot-device is-strict-boot? IF EXIT THEN ELSE 0 0 set-boot-device THEN " qemu,boot-device" get-chosen not IF " boot-device" evaluate swap drop 0= IF " disk" add-boot-aliases " cdrom" add-boot-aliases " net" add-boot-aliases THEN EXIT THEN 0 ?DO dup i + c@ CASE 0 OF ENDOF [char] a OF ENDOF [char] b OF ENDOF [char] c OF " disk" add-boot-aliases ENDOF [char] d OF " cdrom" add-boot-aliases ENDOF [char] n OF " net" add-boot-aliases ENDOF ENDCASE cr LOOP drop ; ' qemu-read-bootlist to read-bootlist 8a0 cp 0 VALUE debug-client-interface? VOCABULARY client-voc \ We store all client-interface callable words here. 6789 CONSTANT sc-exit 4711 CONSTANT sc-yield VARIABLE client-callback \ Address of client's callback function : client-data ciregs >r3 @ ; : nargs client-data la1+ l@ ; : nrets client-data la1+ la1+ l@ ; : client-data-to-stack client-data 3 la+ nargs 0 ?DO dup l@ swap la1+ LOOP drop ; : stack-to-client-data client-data nargs nrets + 2 + la+ nrets 0 ?DO tuck l! /l - LOOP drop ; : call-client ( args len client-entry -- ) >r ciregs >r7 ! ciregs >r6 ! client-entry-point @ ciregs >r5 ! cistack ciregs >r1 ! r> jump-client drop BEGIN client-data-to-stack client-data l@ zcount ALSO client-voc $find PREVIOUS dup 0= >r IF CATCH ?dup IF dup CASE sc-exit OF drop r> drop EXIT ENDOF sc-yield OF drop r> drop EXIT ENDOF ENDCASE THROW THEN stack-to-client-data ELSE cr type ." NOT FOUND" THEN r> ciregs >r3 ! ciregs >r4 @ jump-client UNTIL ; : flip-stack ( a1 ... an n -- an ... a1 ) ?dup IF 1 ?DO i roll LOOP THEN ; : (callback) ( "service-name<>" "arguments" -- ) client-callback @ \ client-callback points to the function prolog dup 8 + @ ciregs >r2 ! \ Set up the TOC pointer (???) @ call-client ; \ Resolve the function's address from the prolog ' (callback) to callback : (continue-client) s" " \ make call-client happy, client won't use the string anyways. ciregs >r4 @ call-client ; ' (continue-client) to continue-client : string-to-buffer ( str len buf len -- len' ) 2dup erase rot min dup >r move r> ; ALSO client-voc DEFINITIONS : exit sc-exit THROW ; : yield sc-yield THROW ; : test ( zstr -- missing? ) zcount debug-client-interface? IF ." ci: test " 2dup type cr THEN ALSO client-voc $find PREVIOUS IF drop FALSE ELSE 2drop TRUE THEN ; : finddevice ( zstr -- phandle ) zcount debug-client-interface? IF ." ci: finddevice " 2dup type cr THEN 2dup " /memory" str= IF 2drop " /memory@0" THEN find-node dup 0= IF drop -1 THEN ; : getprop ( phandle zstr buf len -- len' ) >r >r zcount rot ( str-adr str-len phandle R: len buf ) debug-client-interface? IF ." ci: getprop " 3dup . ." '" type ." '" THEN get-property debug-client-interface? IF dup IF ." ** not found **" THEN cr THEN 0= IF r> swap dup r> min swap >r move r> ELSE r> r> 2drop -1 THEN ; : getproplen ( phandle zstr -- len ) zcount rot get-property 0= IF nip ELSE -1 THEN ; : setprop ( phandle zstr buf len -- size|-1 ) dup >r \ save len encode-bytes ( phandle zstr prop-addr prop-len ) 2swap zcount rot ( prop-addr prop-len name-addr name-len phandle ) current-node @ >r \ save current node set-node \ change to specified node property \ set property r> set-node \ restore original node r> \ always return size, because we can not fail. ; : canon ( zstr buf len -- len' ) 2dup erase >r >r zcount >r dup c@ [char] / = IF r> r> swap r> over >r min move r> ELSE r> find-alias ?dup 0= IF r> r> 2drop -1 ELSE dup -rot r> swap r> min move THEN THEN ; : nextprop ( phandle zstr buf -- flag ) \ -1 invalid, 0 end, 1 ok >r zcount rot next-property IF r> zplace 1 ELSE r> drop 0 THEN ; : open ( zstr -- ihandle ) zcount debug-client-interface? IF ." ci: open " 2dup type cr THEN open-dev ; : close ( ihandle -- ) debug-client-interface? IF ." ci: close " dup . cr THEN s" stdin" get-chosen IF decode-int nip nip over = IF close-dev quiesce ELSE close-dev THEN ELSE close-dev THEN ; : write ( ihandle str len -- len' ) rot s" write" rot ['] $call-method CATCH IF 2drop 3drop -1 THEN ; : read ( ihandle str len -- len' ) rot s" read" rot ['] $call-method CATCH IF 2drop 3drop -1 THEN ; : seek ( ihandle hi lo -- status ) swap rot s" seek" rot ['] $call-method CATCH IF 2drop 3drop -1 THEN ; : claim ( addr len align -- base ) debug-client-interface? IF ." ci: claim " .s cr THEN dup IF rot drop ['] claim CATCH IF 2drop -1 THEN ELSE ['] claim CATCH IF 3drop -1 THEN THEN ; : release ( addr len -- ) debug-client-interface? IF ." ci: release " .s cr THEN release ; : instance-to-package ( ihandle -- phandle ) ihandle>phandle ; : package-to-path ( phandle buf len -- len' ) 2>r node>path 2r> string-to-buffer ; : instance-to-path ( ihandle buf len -- len' ) 2>r instance>path 2r> string-to-buffer ; : instance-to-interposed-path ( ihandle buf len -- len' ) 2>r instance>qpath 2r> string-to-buffer ; : call-method ( str ihandle arg ... arg -- result return ... return ) nargs flip-stack zcount debug-client-interface? IF ." ci: call-method " 2dup type cr THEN rot ['] $call-method CATCH nrets 0= IF drop ELSE \ if called with 0 return args do not return the catch result dup IF nrets 1 ?DO -444 LOOP THEN nrets flip-stack THEN ; : test-method ( phandle str -- missing? ) zcount debug-client-interface? IF ." ci: test-method " 2dup type cr THEN rot find-method dup IF nip THEN 0= ; : milliseconds milliseconds ; : start-cpu ( phandle addr r3 -- ) >r >r s" reg" rot get-property 0= IF drop l@ ELSE true ABORT" start-cpu called with invalid phandle" THEN r> r> of-start-cpu drop ; : quiesce ( -- ) debug-client-interface? IF ." ci: quiesce" cr THEN quiesce ; : boot ( zstr -- ) zcount debug-client-interface? IF ." ci: boot " 2dup type cr THEN " boot " 2swap $cat " boot-command" $setenv (nvupdate) reset-all ; : interpret ( ... zstr -- result ... ) zcount debug-client-interface? IF ." ci: interpret " 2dup type cr THEN ['] evaluate CATCH ; : set-callback ( newfunc -- oldfunc ) client-callback @ swap client-callback ! ; : fdt-fetch ( buf len -- ret ) fdt-flatten-tree ( buf len dtb ) dup >r >fdth_tsize l@ ( buf len size r: dtb ) 2dup < IF ." ERROR: need " .d ." bytes, the buffer is " .d ." bytes only" cr drop -1 ELSE nip r@ -rot move 0 THEN r> fdt-flatten-tree-free ; PREVIOUS DEFINITIONS false value elf-claim? 0 value last-claim 0 VALUE cur-brk : elf-claim-segment ( addr size -- errorcode ) 2dup elf-claim? IF >r here last-claim , to last-claim \ Setup ptr to last claim dup , r> dup , ( addr size ) 0 ['] claim CATCH IF ." Memory for ELF file is already in use!" cr true ABORT" Memory for ELF file already in use " THEN drop ELSE 2drop THEN + to cur-brk 0 ; : elf-load-claim ( file-addr destaddr -- claim-list entry imagetype ) true to elf-claim? 0 to last-claim dup -1 = IF \ If destaddr == -1 then load to addr from ELF header drop ['] elf-load-file CATCH IF false to elf-claim? ABORT THEN ELSE ['] elf-load-file-to-addr CATCH IF false to elf-claim? ABORT THEN THEN >r last-claim swap false to elf-claim? r> ; : elf-release ( claim-list -- ) BEGIN dup cell+ ( claim-list claim-list-addr ) dup @ swap cell+ @ ( claim-list claim-list-addr claim-list-sz ) release ( claim-list ) @ dup 0= ( Next-element ) UNTIL drop ; CREATE bootdevice 2 cells allot bootdevice 2 cells erase CREATE bootargs 2 cells allot bootargs 2 cells erase CREATE load-list 2 cells allot load-list 2 cells erase : start-elf ( arg len entry -- ) msr@ 7fffffffffffffff and 2000 or ciregs >srr1 ! call-client ; : start-elf64 ( arg len entry r2 -- ) msr@ 2000 or ciregs >srr1 ! ciregs >r2 ! call-client \ entry point is pointer to .opd ; : set-bootpath s" disk" find-alias dup IF ELSE drop s" boot-device" evaluate find-alias THEN dup IF strdup ELSE 0 THEN encode-string s" bootpath" set-chosen ; : set-netbootpath s" net" find-alias ?dup IF strdup encode-string s" bootpath" set-chosen THEN ; : set-bootargs skipws 0 parse dup 0= IF 2drop s" boot-file" evaluate THEN encode-string s" bootargs" set-chosen ; : .(client-exec) ( arg len -- rc ) s" snk" romfs-lookup 0<> IF paflof-start f00000 + elf-load-file-to-addr drop \ FIXME - check this for LE, currently its BE only dup @ swap 8 + @ \ populate entry r2 start-elf64 client-data ELSE 2drop false THEN ; ' .(client-exec) to (client-exec) : .client-exec ( arg len -- rc ) set-bootargs (client-exec) ; ' .client-exec to client-exec : ping ( "{device-path:[device-args,]server-ip,[client-ip[\nn]],[gateway-ip][,timeout]}" -- ) my-self >r current-node @ >r \ Save my-self (parse-line) open-dev dup IF dup to my-self dup ihandle>phandle set-node dup s" ping" rot ['] $call-method CATCH IF cr ." Not a pingable device" cr 3drop THEN swap close-dev ELSE cr ." Usage: ping device-path:[device-args,]server-ip,[client-ip[\nn]],[gateway-ip][,timeout]" cr drop THEN r> set-node r> to my-self \ Restore my-self ; 8a8 cp CREATE version-str 10 ALLOT 0 value temp-ptr : dump-display-write s" screen" find-alias IF drop terminal-write drop ELSE s" vsterm" find-alias IF drop type THEN THEN ; : dump-display-buffer disp-ptr to temp-ptr " SLOF **********************************************************************" dump-display-write cr version-str get-print-version version-str @ \ start version-str 8 + @ \ end over - dump-display-write " Press 's' to enter Open Firmware." dump-display-write cr cr temp-ptr disp-size > IF temp-ptr disp-size MOD dup prevga-disp-buf + swap disp-size swap - dump-display-write temp-ptr disp-size MOD prevga-disp-buf swap 1 - dump-display-write ELSE prevga-disp-buf temp-ptr dump-display-write THEN ; : enable-framebuffer-output ( -- ) s" screen" find-alias ?dup IF open-dev close-node false to store-prevga? s" display-emit" $find IF to emit dump-display-buffer ELSE 2drop THEN THEN ; enable-framebuffer-output 8b0 cp usb-scan 8c0 cp romfs-base 400000 0 ' claim CATCH IF ." claim failed!" cr 2drop THEN drop 8d0 cp : get-stdout-path ( - [ prop len ] success ) s" stdout-path" get-chosen ?dup NOT IF s" linux,stdout-path" get-chosen ?dup NOT IF FALSE THEN THEN ; : set-default-console get-stdout-path IF decode-string ." Using default console: " 2dup type cr io 2drop ELSE ." No console specified " " screen" find-alias dup IF nip THEN " keyboard" find-alias dup IF nip THEN AND IF ." using screen " s" direct-serial?" evaluate IF ." & hvterm" s" hvterm" input ELSE ." & keyboard" s" keyboard" input THEN cr s" screen" output ELSE " hvterm" find-alias IF drop ." using hvterm" cr " hvterm" io ELSE " vsterm" find-alias IF drop ." using vsterm" cr " vsterm" io false to store-prevga? dump-display-buffer ELSE " /openprom" find-node ?dup IF set-node ." and no default found, creating dev-null" cr " dev-null.fs" included " devnull-console" io 0 set-node THEN THEN THEN THEN THEN s" input-device" evaluate dup IF ." User selected input-device console: " 2dup type cr input ELSE 2drop THEN s" output-device" evaluate dup IF ." User selected output-device console: " 2dup type cr output ELSE 2drop THEN ; set-default-console 8e0 cp 0 VALUE direct-ram-boot-base 0 VALUE direct-ram-boot-size : (boot-ram) direct-ram-boot-size 0<> IF ." Booting from memory..." cr s" go-args 2@ " evaluate direct-ram-boot-base 0 s" true state-valid ! " evaluate s" disable-watchdog go-64" evaluate THEN ; 8e8 cp : check-boot-from-ram s" qemu,boot-kernel" get-chosen IF decode-int -rot decode-int -rot ( n1 n2 p s ) decode-int -rot decode-int -rot ( n1 n2 n3 n4 p s ) 2drop swap 20 << or to direct-ram-boot-size swap 20 << or to direct-ram-boot-base ." Detected RAM kernel at " direct-ram-boot-base . ." (" direct-ram-boot-size . ." bytes) " cr s" boot-command" $create " (boot-ram)" env-string THEN ; check-boot-from-ram 8ff cp : (boot) ( -- ) s" Executing following boot-command: " boot-command $cat nvramlog-write-string-cr s" boot-command" evaluate \ get boot command ['] evaluate catch ?dup IF \ and execute it ." boot attempt returned: " abort"-str @ count type cr nip nip \ drop string from 1st evaluate throw THEN ; : (function-key) ( -- n ) key? IF key CASE 50 OF 1 ENDOF 7e OF 1 ENDOF dup OF 0 ENDOF ENDCASE THEN ; : (esc-sequence) ( -- n ) key? IF key CASE 4f OF (function-key) ENDOF 5b OF key key (function-key) ENDOF dup OF 0 ENDOF ENDCASE THEN ; : (s-pressed) ( -- ) s" An 's' has been pressed. Entering Open Firmware Prompt" nvramlog-write-string-cr ; : (boot?) ( -- ) of-prompt? not auto-boot? and IF (boot) THEN ; TRUE VALUE use-load-watchdog? : boot-menu-start boot-menu ?dup IF s" boot " 2swap $cat ['] evaluate catch ?dup IF ." boot attempt returned: " abort"-str @ count type cr throw THEN 0 0 load-list 2! THEN ; : boot-menu-enabled? ( -- true|false ) s" qemu,boot-menu" get-chosen IF decode-int 1 = IF 2drop TRUE EXIT THEN 2drop THEN FALSE ; : f12-pressed? 34 = >r 32 = r> and IF TRUE ELSE FALSE THEN ; : start-it ( -- ) key? IF key CASE [char] s OF (s-pressed) ENDOF 1b OF (esc-sequence) CASE 1 OF console-clean-fifo f12-pressed? boot-menu-enabled? and IF boot-menu-start ELSE (boot?) THEN ENDOF dup OF (boot?) ENDOF ENDCASE ENDOF dup OF (boot?) ENDOF ENDCASE ELSE (boot?) THEN disable-watchdog FALSE to use-load-watchdog? .banner ; ." " \ Clear last checkpoint 0 VALUE load-size 0 VALUE go-entry VARIABLE state-valid false state-valid ! CREATE go-args 2 cells allot go-args 2 cells erase 4000 CONSTANT bootdev-size 0 VALUE bootdev-buf : alloc-bootdev-buf ( -- ) bootdev-size alloc-mem ?dup 0= ABORT" Unable to allocate bootdev buffer!" dup bootdev-size erase to bootdev-buf ; : free-bootdev-buf ( -- ) bootdev-buf bootdev-size free-mem 0 to bootdev-buf ; : bootdev-string-cat ( addr1 len1 addr2 len2 -- addr1 len1+len2 ) dup 3 pick + bootdev-size > ABORT" bootdev size too big!" string-cat ; : $bootargs bootargs 2@ ?dup IF ELSE s" diagnostic-mode?" evaluate and IF s" diag-file" evaluate ELSE s" boot-file" evaluate THEN THEN ; : $bootdev ( -- device-name len ) alloc-bootdev-buf bootdevice 2@ ?dup IF swap bootdev-buf 2 pick move bootdev-buf swap s" " bootdev-string-cat ELSE drop bootdev-buf 0 THEN s" diagnostic-mode?" evaluate IF s" diag-device" evaluate ELSE s" boot-device" evaluate THEN bootdev-string-cat \ concatenate both strdup free-bootdev-buf ?dup 0= IF disable-watchdog drop true ABORT" No boot device!" THEN ; : set-boot-args ( str len -- ) dup IF strdup ELSE nip dup THEN bootargs 2! ; : (set-boot-device) ( str len -- ) ?dup IF 1+ strdup 1- ELSE drop 0 0 THEN bootdevice 2! ; ' (set-boot-device) to set-boot-device : (add-boot-device) ( str len -- ) \ Concatenate " str" to "bootdevice" bootdevice 2@ ?dup IF alloc-bootdev-buf swap bootdev-buf 2 pick move bootdev-buf swap s" " bootdev-string-cat 2swap bootdev-string-cat ELSE drop THEN set-boot-device bootdev-buf 0 <> IF free-bootdev-buf THEN ; ' (add-boot-device) to add-boot-device 0 value claim-list : no-go ( -- ) -64 boot-exception-handler ABORT ; defer go ( -- ) : go-32 ( -- ) state-valid @ IF 0 ciregs >r3 ! 0 ciregs >r4 ! go-args 2@ go-entry start-elf client-data claim-list elf-release 0 to claim-list THEN -6d boot-exception-handler ABORT ; : go-64 ( args len entry r2 -- ) 0 ciregs >r3 ! 0 ciregs >r4 ! start-elf64 client-data claim-list elf-release 0 to claim-list ; : set-le ( -- ) 1 ciregs >r13 ! ; : set-be ( -- ) 0 ciregs >r13 ! ; : go-64-be ( -- ) state-valid @ IF set-be go-args 2@ go-entry @ go-entry 8 + @ go-64 THEN -6d boot-exception-handler ABORT ; : go-32-be set-be go-32 ; : go-32-lev1 set-le go-32 ; : go-64-lev1 state-valid @ IF go-args 2@ go-entry @ xbflip go-entry 8 + @ xbflip set-le go-64 THEN -6d boot-exception-handler ABORT ; : go-64-lev2 state-valid @ IF go-args 2@ go-entry 0 set-le go-64 THEN -6d boot-exception-handler ABORT ; : load-elf-init ( arg len file-addr -- success ) false state-valid ! \ Not valid anymore ... claim-list IF \ Release claimed mem claim-list elf-release 0 to claim-list \ from last load THEN true swap -1 ( arg len true file-addr -1 ) elf-load-claim ( arg len true claim-list entry elftype ) CASE 1 OF ['] go-32-be ENDOF ( arg len true claim-list entry go ) 2 OF ['] go-64-be ENDOF ( arg len true claim-list entry go ) 3 OF ['] go-64-lev1 ENDOF ( arg len true claim-list entry go ) 4 OF ['] go-64-lev2 ENDOF ( arg len true claim-list entry go ) 5 OF ['] go-32-lev1 ENDOF ( arg len true claim-list entry go ) dup OF ['] no-go to go 2drop 3drop false EXIT ENDOF ( false ) ENDCASE to go to go-entry to claim-list dup state-valid ! -rot 2 pick IF go-args 2! ELSE 2drop THEN ; : init-program ( -- ) $bootargs get-load-base ['] load-elf-init CATCH ?dup IF boot-exception-handler 2drop 2drop false \ Could not claim ELSE IF 0 ciregs 2dup >r3 ! >r4 ! \ Valid (ELF ) Image THEN THEN ; : do-load ( devstr len -- img-size ) \ Device method wrapper use-load-watchdog? IF 4ec set-watchdog THEN 2dup " HALT" str= IF 2drop 0 EXIT THEN my-self >r current-node @ >r \ Save my-self ." Trying to load: " $bootargs type ." from: " 2dup type ." ... " 2dup open-dev dup IF dup to my-self dup ihandle>phandle set-node -rot ( ihandle devstr len ) encode-string s" bootpath" set-chosen $bootargs encode-string s" bootargs" set-chosen get-load-base s" load" 3 pick ['] $call-method CATCH IF -67 boot-exception-handler 3drop drop false ELSE dup 0> IF init-program ELSE false state-valid ! drop 0 \ Could not load THEN THEN swap close-dev device-end dup to load-size ELSE -68 boot-exception-handler 3drop false THEN r> set-node r> to my-self \ Restore my-self ; : parse-load ( "{devlist}" -- success ) \ Parse-execute boot-device list cr BEGIN parse-word dup WHILE de-alias do-load dup 0< IF drop 0 THEN IF state-valid @ IF ." Successfully loaded" cr THEN true 0d parse strdup load-list 2! EXIT THEN REPEAT 2drop 0 0 load-list 2! false ; : load ( "{params}"} -- success ) \ Client interface to load parse-word 0d parse -leading 2swap ?dup IF de-alias set-boot-device ELSE drop THEN set-boot-args save-source -1 to source-id $bootdev dup #ib ! span ! to ib 0 >in ! ['] parse-load catch restore-source throw ; : load-next ( -- success ) \ Continue after go failed load-list 2@ ?dup IF save-source -1 to source-id dup #ib ! span ! to ib 0 >in ! ['] parse-load catch restore-source throw ELSE drop false THEN ; : noload false ; ' no-go to go : (go-and-catch) ( -- ) get-load-base c@ 5c = get-load-base 1+ c@ 20 = AND IF load-size alloc-mem ( allocated-addr ) ?dup 0= IF ." alloc-mem failed." cr EXIT THEN load-size >r >r ( R: allocate-addr load-size ) get-load-base r@ load-size move \ Move away from load-base r@ load-size evaluate \ Run the script r> r> free-mem EXIT THEN ['] go behavior CATCH IF -69 boot-exception-handler THEN ; read-bootlist : boot load 0= IF -65 boot-exception-handler EXIT THEN disable-watchdog (go-and-catch) BEGIN load-next WHILE disable-watchdog (go-and-catch) REPEAT ; : load load 0= IF -65 boot-exception-handler THEN ; cr .( Welcome to Open Firmware) cr cr .( Copyright (c) char ) emit .( 2004, 2017 IBM Corporation All rights reserved.) cr .( This program and the accompanying materials are made available) cr .( under the terms of the BSD License available at) cr .( http://www.opensource.org/licenses/bsd-license.php) cr cr ' start-it CATCH drop : boot boot .banner ; cr ." Ready!" `hp((P `8xh(P xhP   0@Xp X pyz{ 0&@'P(`pvwx|^cScbPbXPGNU5M4DJA GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0v( hx ( Ӵ,y@HGZjv`Lqq \@s}h  vL|Hd8d)t9wPDCMw[0 guHx(d`4|,x(Px z||w8l'?}LR ]doxp{l`y(t ~<{p   8`p!7h?N$VgLplxHx@~4~(p}| | 0 H, 8@KzPtY btm~Hev {@D~p0y0 zh(-D {x9XvP`Zm~L(whDDp 8$oxqDePT pH*l;wJpYpahDx~yH Ty vxLqHXX8X!H(1HBzTXd ilvxeHty`D~XHh<l|x+yB  Q |4Xwg(Tvs !xT~@X}t|X  1  | 40 D Q Pp0 ` ` hw v Pd  xP 8 @D tD @t  @8 {X uxp !w \ - ; C O| ` gx w0P yX z z x }( 0 T   `  p ( D 08 78 C8 W ^@ d0L {0 }8   p  H  ` P  d }   p 'zd p  ; Gx Pt ]h| d~@ s0 {  T xd T @ X p @ } & 9 K   Td b͠ u  x P8 h HT xP p `  X4t pp0tl:,BhQy_m~ (pP }  _(`H tx(04p4B(O qWu$hwH0u Pepl,|0=}TO8akPv<T\$ |L0X0 z (wPH{d*43xhL]q{(0v0<ppwvHDqyL@| }P q`$8wpF|`]h.LC29.LC4.patch_broken_sc1e1k_mac_setupSLOF_set_chosen_intstrcpyvirtio_serial_initset_ipv4_routerenginehandle_dhcpv6usb_hcd_initvsprintfio_printhex16virtio_get_host_featuresthe_data_stackget_partitionrecvincrease_nvram_partition_sizevirtio_get_vring_deschandle_arpget_arg_ptrbootmsg_warningset_timersend_ipv4get_sec_ticksstderr_databootmsg_nvupdatep9_clunkmemmovenvram_write_qwordhandle_udphv_casvirtio_vring_sizeSLOF_dma_map_outmac2eui64neighbor_createusb_devpool_getreset_nvramvirtio_queue_term_vqSLOF_usleephv_rtas_broken_sc1_sizevirtioblk_shutdownhash_tableusb_key_availableSLOF_pci_config_read8check_broken_sc1get_ipv4_netmaskSLOF_bm_freeusb_hid_initthe_client_stackvirtionet_closememcpyelf_forth_claimpingthe_system_stackputsneighbor_addusb_dev_populate_pipep9_statp9_transactiontolowerset_ipv4_addressnvram_read_dwordmallocSLOF_pci_config_read32virtioscsi_initvsnprintfvirtio_9p_initset_mac_addressvirtio_negotiate_guest_featuresvirtio_setup_vdusb_put_pipep9_reg_transporthandle_udp_dunthe_pocketsstrtoul_slof_textelf_load_filebootmenuhandle_dnsget_partition_fskeycodes_shift_UShandle_ipv4socketdevpoolelf_byteswap_header64virtioscsi_sendpxelinux_load_parse_cfghv_logical_ci_loadSLOF_encode_bootp_responseelf_load_file_to_addrstr_to_ipv6ip6_create_prefix_infoe1k_closehv_rtas_broken_sc1virtioscsi_shutdownget_mac_addressget_timerisxdigitstdin_datapong_ipv4strtolfill_udphdr.call_cip6_prefix2addrwriteLogBytekeycodes_alt_GRp9_readrouter_addclear_nvram_partitionusb_hid_kbd_exitSLOF_alloc_memc_romfs_lookupstrrchrdelete_nvram_partitionvirtionet_readfree_nvram_bufferSLOF_encode_dhcp_responsehv_rtas_sizehv_logical_ci_storeusb_transfer_bulk_start_OFio_putchardhcpv6_generate_transaction_idstrcathandle_tftp_dunnvram_read_qwordelf_byteswap_header32nvram_debugheadlibveth_readkeycodes_ctrle1k_openusb_hid_exitusb_get_pipeSLOF_get_propertyvirtio_9p_loadipv6_get_default_routersend_router_solicitationhandle_dhcpvirtio_get_vring_usedstrtoip_netmaskSLOF_bm_allocator_initepapr_ima_sizestrstrSLOF_dma_allocipv6_to_strthe_comp_bufferget_nvram_bufferstrncmpvirtio_9p_shutdownvirtioblk_initusb_read_keybstrncpyvirtio_queue_init_vqstrcasecmpnvram_write_bytethe_return_stackp9_attachvirtio_queue_notifynvram_read_wordepapr_magicnvram_read_bytehv_rtasSLOF_dma_freelibveth_openget_args_counttftp_get_error_infoparse_tftp_argsp9_opennvram_add_envbootmsg_cpmemcmp.hv_hascharusb_ehci_registerelf_get_eflags_64bootmsg_checklevelSLOF_msleepfind_neighborstrtoiphandle_ipv6virtio_set_qaddrdhcpv4SLOF_dma_map_inusb_msc_resetrecoverysbrkelf_load_segments32elf_load_segments64SLOF_translate_my_addressvirtio_get_confighandle_tftpip6_cmpusb_hid_kbd_initthe_exception_framethe_heapsend_ipmemsetfill_ip6hdrnew_nvram_partitionall_nodes_llvirtio_serial_shutdownsrandvirtio_get_statuslibveth_writefdt_startusb_msc_initusb_hub_init.call_clientsend_ipv6_binary_OF_fsi_startdns_get_ipunknown_prefixvirtio_reset_devicethe_memelf_get_base_addr32hv_send_crqe1k_readGET_WRNG_LVLstrcmpvirtionet_openhandle_icmpv6fast_rfillsend_neighbour_solicitationdhcpv4_generate_transaction_idusb_msc_exithv_putcharnetloadnvram_del_envreset_buffersusb_send_ctrl__virtio_read_configpxelinux_parse_cfgprint_version_endset_ledsusb_msc_reset_binary_OF_fsi_endspnvram_write_dwordusb_ohci_registerhv_getcharusb_setup_new_devicevirtio_serial_hascharbootpdhcp_send_releaserouter_createsend_etherbootmsg_debugcpusb_slof_populate_new_deviceprint_msgargncpyhandle_tcp_dunSLOF_bm_allocusb3_dev_initget_ipv6_addresskbd_bufferp9_versionusb_transfer_ctrlstdout_datavirtioblk_transferisdigitip6_statevirtio_serial_getcharset_ipv4_netmaskget_nvram_sizebootmsg_errorwrite_mm_logip6addr_addnvram_set_envusb_hcd_exitthe_tibbootmsg_setlevelis_ra_receivedvirtionet_writevirtio_serial_putcharfind_router_slof_text_endromfs_basenvram_write_word.client_entry_pointnew_nvram_partition_fskeycodes_std_USerase_nvramhv_logical_memopvirtio_get_qsizevirtio_set_statususb_xhci_registerping_ipv4handle_tcpfill_iphdrstrlendns_inittoupperp9_walklibveth_closevirtio_fill_descget_print_bannernvram_initprint_versionnvram_get_envSLOF_alloc_mem_alignedstrchrelf_get_base_addr64ndp_initget_default_ipv4_netmaskusb_hcd_registerhv_send_logical_lanelf_relocate64set_ipv6_addressasm_coutfill_ethhdrusb_poll_intrSLOF_free_memio_printSLOF_set_chosen_byteshv_genericreceive_ethervfprintfthe_client_framee1k_writevirtio_set_guest_featuresSLOF_GetTimervirtio_get_vring_availwipe_nvramnvramlog_printf//&*:X>XJXNXR.V.\ &&A, *.969HZ,w 8 n2r0220020&2@*0@.22062(:2>0B0(R2Z0^@b2(j@(n2r@vA2zA02 0 20202'`0'`2"0N2R0202'`0'`"2"020  2  0  2 0 \:  n2 r0   2 0  2 0 >2 B0 r2 v0 2 0 0E  F2 J0 E  2 0 .  2 0 "2 &0 b2 f0 2 0 2 0 2 0 J2 N0 ~2 0 2 0 2 0*2.0^2b02020 20>2B0z2~020202"0V2Z0202020:2>0n2r0202020N2R0202020>2B0z2~0Z 20@ 62:0 20 2260`[ ~20I 20 20 .220:?2>?0lf 20?2?0Y  # 2"0L v2z0) 20 20H# Z2^0 20 20L f2j0 20 20 62:0T r2v06 20 20 &2*0D; b2f0' 20 8  0 F2J0d 20 20,  200 F2J0d ~20+ 208& b2f0 20H v2z0F <   D`  h0  z2 ~0   2 0!D2 !2!0! !2!0! "62":0"\' "z2"~0"\ "2"0# #:2#>0#X #n2#r0#0 #2#0#2#0$&2$*0$^2$b0$" $2$0$2$0%(C %:2%>0%p %2%0%{ &2&0&< &Z2&^0&k &2&0& &2&0' '62':0'\@ 'n2'r0' '2'0(4 (N2(R0( (2(0(= (2(0) )22)60)b )2)0)m )2)0*M **2*.0*d *~2*0* *2*0*O +"2+&0+l +2+0+ +2+0,4 ,*2,.0,H ,b2,f0, ,2,0, - 2-0-86 -V2-Z0-t* -2-0-R -8 -2-0-32-30.l2.l0.&2.*0.HW .b2.f0.h .2.0.B .2.0/,) /B2/F0/5 /2/0/ /2/00d 0220600p 02000d 02000 121014d 1J21N01 12101d 12102W 2.22202\ 2z22~02W 22202W 32303, 3J23N03h 32303 32304,G 4F524J504v24z04~524504524504 42405< 5&25*0525052506r26v072707H 72708280828092909j29n0929092909290:62::0:j2:n0:2:0:2:0;:2;>0;j2;n0;2;0;2;0<2<0<>20@z2@~0@2@0A2A0A62A:0Ar2Av0A2A0A2A0B2B0BR2BV0B2B0B2B0B2B0C62C:0Cz2C~0C2C0D2D0DF2DJ0D2D0D2D0E2E0EV2EZ0Eb2Ef0E2E0E2E0E2E0E2E0E2F0F2F 0FJ2FN0FR2FV0F2F0F2F0F2F0F2F0G2G0G2G"0G^2Gb0Gj2Gn0G2G0G2G0H2H0HV2HZ0H2H0H2H0H2I0I22I60Ib2If0I2I0I2I0J:2J>0Jr2Jv0Jz2J~0J2J0J2J0J2J0J/2J/0K22K60K:2K>0Kr2Kv0Kz2&K~@&K2K0K2%K@%K2K0K2K0L&2L*0L.2L20Lb2Lf0Lj<2Ln<0L2L0LZ2LZ0L2L0L2L0M2M0MV2M"V0MR2MV0MZ(2M^(0M2M0M2M0M2M0NB2NF0Nz2N~0O> P > R2R0R2R0S2S0T T T, Tr2(Tz0(T T T< T TH T< U20U  U&00U4 U<< UP U U28U< U08U U U< U V VP Vn2Vv2@Vz@@V~2V@V0V2V0V2V0V< W W W"2pW.0pW0 WF2WN0WP Wp Wz2W|< W0W W W< W W W W X> XR2XZ0X\B X2xX0xXB X2HX0HXB X2X0Y2Y0YD YV2XYX Yb0XYl Yt< Y Y2Y0Z$ Z62XZ8 ZB0XZL ZT< Zh Z2`Z0`[$< [8 [2x[0x[< [ [ \^ \0^ \j2\r0\ \< \ \^ \2\0]*2].0]8^ ]2]0] ]< ] ] ^*2^20^< ^P ^\< ^p ^2^0^ ^< ^ ^ _:2_B0_L _` _l< _ _} _S _} `V2`Z0`d `x ` `< ` ` a a&2a, a60aD aP< ad a2a0a a< a a b2b"0b4 b@< bT bh b2b0b b< b b c&2 c.0 c8 cL cX< cl c20c00c c c< c dF2@dN0@dX dl dx< d d2Pd0Pd d< e e ef2hej0het e e e< e e2xf 0xf2f0f$ f0< fD fX fd< fx f< f f2f0g g2g g&0g(< g< gP g\< gp g|< g g2g0gV g2g0gV h4 hB2hD< hR0h\ hp h|< h h< h h h h iv2iz0i i2i0i i2i2 i2$i0i0$i0 j  jt j2`j0`j j kT} k n2hn0hn o"2o&0oJ p4J qJ q q q r r r< rX rt r r r r s s s8 sT sp tP tX t` t t t t t tU t t t t t t t u ua u vp 8v v wP w 8xI x0 xHN x x y 8y4I yT z\% z| {2{0{ ~<% ~X ~2~0~ 2P200P002,0,D D  20 0 << P d H8 @8 `8  2D6D:>l ~L  L L } 7 7 7 7 $7 4L h t7  \L r2v0x 4 | 6  <_ L6  6 6 8G p  _  20 @S T 7  \   7  2"26"0:2B0D f"2j"0n2r0t  7 7 Q 2 200 00 7 H\ \ 7    87 D   6 0 D_ X 2(0(20@02,0,2(0(A 8A \A  ^ ^ &2.00 "2"02x0x 2@0@B "2(.0(B20F00N2,V0,6  _  xA A  280808$ 47 P7 l\  7 20T ,Q D b2f20j0n00p 7 7  28082.0228608   20 $ 8 N2V0X ? 2(0( E 2@0@ $ $ H y 2p0p 2X0X p6  _  $A TA  ^ ^ A A A A T7 p7 Q  \    €7 ²2¶20º0¾00 7 (7 4 |} ð> ü   7 X7 r2<Ă0<Ą\ Ď2<Ē0<Ĝ} ĺ2<0< A PA 2@0@$7 4 ` Q 2<0< 20 7 0S ^0@t7 ǂ2dž0Lj S 7  2<0<0S L1 `1 Ȧ2<Ȯ2@Ȳ0@ȶ0<H> R2@f0@v0@ ʲ2ʶ0ʸ ˢ2B˦0B˪2<ˮ0<˸ 2<0<,A PA  2L0L"2&0( ͌ ͜7 ͸7 Q 28200800 7 F2XN0XX |} Ά2hΒ@hA 2x@x>2xB@x^2Ҁb@Ҁς2҈ϒ0҈ϔ  _ 7 .2P20P4 x7 Є 6  _ $ |A  ^ ^ b2f0h  2Ҁ@Ҁ2X2҈0҈0X> 2҈2x@x0҈ 0҈2`0`b2xf@xԔ 2Ҁ@Ҁ2҈0҈"2&@*2.@226@:2>@Z2f@p z2~@Ո Ւ@Ֆ2՚022@202@0$ L V2^0` ת2׮0׸ ׾20(< H< \> h< ؀F ؎2ؒ@ض2غ0 L< \< و َ2ْ0< 4< H> T< l< ڐ< ڤ> ڰ< F X ^2b0F 22pN0pX ^2b0p ݆2݊@> 2@F ހ< ޖ2ޚ@ިF ޶2޺@ߤ ߮2߲00F >2B@ 20XF f2j@>  20tF 2@`2`0 4} `2`0r2v2z0~0 2062(:0(@ j2n020 00 2000 B2F2J0N0P  , 22 00    h | D 4S DS   X  X(    @ l   , ` | > 8 R2V2@^0b0@d  8 + +    4 >2V0      2X2 0X0  +  + $ 4S 20"2*0^2 r24x2 (0 04x0 (^ 4^ 4 b2j0p   T^ ^  R2 @Z0 @\ 2 `0 ` 2 0  2p2 0p0  @ R2pV2 Z0p^0 `  4 L d ^ ^ 22 00  2 2 0   0 ( :2 >0 @ d + + +   22 60 @ L} p  2 `0 `  S ( T 2 2 0   ,  T  h  p   `  z2  ~2  0  0     /      r2 8 v0 8 x    2  0   2404$L   x  ( 2 H0 H } , t^ ^   , D \     2 8"0 8 $ ,/ H d  2 `0 ` 2 0   .2 20 4 B2 F0 H \+ l z2 ~0  +  2002 2 h0 0 h +  +  +  $+ 4 DS ^ ^ t^  H ` t ^ ^ ^ 2 0   (+ <+ P+ ` 2 0  2 0  < J2 N2 R0 V0 X   ^ ^  8  F2 0 J2  N0 0 R0  T  2 0  !2 !0 ! !B2H!J0H!L !25X!05X!L ":2"N0"X "d< "x "2"0"2"0# 2#0#r2P#v0P#| # X#2#0# # $2$28$ 0$08$ $$ $@ X$R2$V@$2$@$2$0$2$2$0$0%z2#%~0#&"32&&30&*2&.]2&2]0&6@&:2&>@&2&0+n2+r0323042405v25z06x26"x08 9R 9 9 9 9 : :0 :8 :B2:F0:D : : :2:0;2x; 2;0x;0; ;pS ;2;0; ; ;2;0;2;0  0>| > >^ >^ > 0>/ ? ? ?< 0?p ? ? ?^ ? 0?^ @ @2@0@ @T @^ @^ A:2A>0A@ C C<+ CL D D `E+ E + E| F FL F` F+ F F Gl G H H H `I\ J2J2PJ0J0PJ J4 JT J K L L, L@ M8 N, N:2xN>0xN@ NL NZ2N^0N` O2 P0S Px 8P P P P P+ P P+ P QL+ Q\ Ql Q Q+ Q Q RS R20R00R00T, `T> T V@^ VJ20VR00Vh^ V `W22W60W8 W XL Y( Y Y Z Z / ZL Zh+ Zx Z Z+ Z [2[0[ [$ ] ] `^  _B2_F0_P _h} _ ` 8ad2 a2@a0@a a2pa0pa a2a0a bD bd b| b c c c+ d d( dH fp 8f f f+ f g gF25gJ05gTL g28g08gW h2<h 0<hF28hR08h h h2<h0<i 28i08iPW i2<i0<i28i08i i j4 jD (j28j08j2@j0@j2<j0<j2Hj@Hj2<j0<j j2<j0<k2@k0@kXW k2<k0<k (k2<k0<k2@k0@lW l| @l2<l0<l @l m0 m m$< m@ mX m2<m0<m @m2m0m n2<n0<nJ28nN08nW n2<n0<n2@n0@o(W ol0 o|0 o o2<o0<o28o08p,W pb2<pf0<p2@p0@pW p2<p0<p28p08q 2Pq0PqV2PqZ0Pq qP r62<r:0<r28r08r s s (s2Xs0Xt$ tH t u\> u| u2<u0<u28u08u2Pu0Pv, v vW w"2<w*@<w,4 wd4 w4 w x4 x( xD x y22<y60<yr28yz08y y y y4 z z 4 z$ z4 { {N2<{R0<{b28{f08{r2P{v0P{ |H4 |\4 |l0 |p |4 | |2P|0P}2<}.@<}<4 }t } } 0} 0}2}0}a }2(}0(} } ~"2<~&0<~l ~ J2hZ0ht   $ f2hr0h  T |   ,    , h   4 F <    ( H l   , L l  ( } 2x> 2t0t2p2ր 2p0p0pG .@x2@ր4G >2ֈF@ֈL} V@xZ2֐^@֐j@րW W B2PF0PH R2xV@xdS n2ֈr@ֈS 2֐@֐S S 2x0x 2000 LS xW 2x@xS 2ֈ@ֈS 2֐@֐S 2t0t&2.2p60F0p W ,> M 20 B2֠F0֠N2֨^@֨z@֨2֠60֠ b2֠f@֠2֨@֨J2N0P 27x07x2֠@֠2֨@֨>2֨B@֨j2֨n@֨ 2֨2֠@֨0֠}  0 :2֨J@֨f@֨  < \ S 20 2֨@֨"@֨< F@֨^@֨v@֨@֨@֨2֨@֨2֠0֠    8+ PS 2֨@֨2֠0֠"2֠*0֠>  R2֨V@֨2֨@֨2֠0֠> 2֨@֨ *2֨:@֨< \ 20  N $# 0< D$  20  ( 2200   282080  PO `   2@0@ 2200  2x0x l 2200  2P0P  > V2b0d}  20B  _  !  o 0_ N2V0\ r2z0 S ] ] 2(0( $P < V2p^0p`B  > 2@20( :2>@n2r@< K 2@22"0&0( N2R@lc 2H0HB 2@]    20 B <T h  > 2@  H &2*@H R2Z0\ r2z0 T    , 8 N2V@20 T T  e L V2^0` v2~0  2@  0 T j2n0   O 2@,> L> d >  >   ( 8 d       < L t   20 g @ P   2H0H T   @ ` |> 2p0p O  > 2@s &2204 D N2V0X xs    20 2@D   g    ,g X h     L d  > 20B     T ( < v2 z0 |B % 20 20 < 2 0 V 2x"0x(B p >     ( @ \ p   2h0h _ 20 $P H `H n20r00 9 > 2p0p 9 !   X (r 8o N2 V0 X d] p] |T     0> P! \H j20n00 9 2P0P 2`0` 20   &2.00 \ l   s K  2 0  2"0$ 62>0@  2p.0pp    s 0 Hs X< H H 4 \ l<   @ Z2^0` 20 20 2@2P28*2H.2J20Ž00–2Xš08ž0X¢0@¦0Pª0H®0H XH è D l ĘH İ      4 h < < F2J0LB d< t< Ɛ ƨ "2"02200   B2XR0XT l dž20ǎ00ǐ Ǩ  0 R2Z0\ h< z2x~0xȀB 20B 2(0(B 200 X ɪ2ɮ0ɰ> 20 20.260T l ʎ2ʖ0ʜ ʮ2ʲ029 09 , P ˀ ^  Pj ̰> > 220&0*260:2F0d ~2͂0͆ 2͎ 02X0Xz2~2΂0Ά0Ύ2XΒ0X>2J2N0R0t |n ϊ2Xώ0Xϰ> > n Q  220&0B0Є Ќn ФQ м> 2^0^!  o X Z2X^0Xb2Xf0XѦ2Ѫ0Ѱn Q >  F2XJ0X ӂ29ӆ09Ӗ2Ӟ0Ӱ 202200"2:0R2XV0XX r2Xv0XԮ2XԲ29Ժ0XԾ2909290909290929092X29 090X B2XF0Xb2Xf0Xh Ղ2XՆ0Xբ2Xզ0Xը 2X0X2X0X2X0X20022^60^>2B0؂2^؆0^> ( &2^.0^0> t: > ( dU ڌ 22X0X08n H 20 8>  n Q n ,> D> \ ݰ>  &2.0ސ  20߄[   4  > B2J0P < 22d60dL  < t >    20t 2j0j; 2j0j2j0j$> j2z2d~00d 20 20 20  &2.04 L ^2f0l    < L r2jv0j2l0l <  !  o $X 2 0  < <  &28.080 x 2X0X 20 > 0> L 2n0n V2lb0l2d0d  H l 2l0l> 2 2*0>2J0N0 x 2o@o  ; t  n $> 8 l t!   0o \ n2v0| n  2o@o>  2 (0 ( > > > > L  2909 x> > 2oK @o> @o*2o8K F@o\> j@o2o0o2909> h< > < > 2o&0o@ J2o4R2uV0u^0o4b2o6f0o6j2o8n0o8pn >   Xt 2u 0u ;  ` l 2u0u202o0o  &2w6@w:2o>@oB2oF@oH pR2wV0wX! ` lX < 2w0w2u 0u ( 22o62oB@oF@oJ@oN@o2w0w <  o  2o0o2u 2w  2o42u0u0o42o60o62o80o82o0on  > 0u 2o@*0o@, 60w P Xdt n0w r0u ;   "2u&0u*2o.0oB29R09T  @2w0w < L< h v2uz0u2w0w <> 2u 2w0u 0w< 0w< 2w0w2w 0w 2u 0u H 2w@w> @ L! x=  ( @< X> | 2u0u ( ( (V2uZ0up<  2w0w n >  8> P> | Xt ;     B2w(J@w(b2w,f0w,2 80 8 2w,2w(0w,0w(29092909 2 8 0 8   R2" Z0" \  2w( 0w(  2x0 @x0 t    8  Pt  j2 n0 2x8 @x8 ;  2w( *0w( R2 V0 Z2 P ^0 P h  r2x0 v@x0 2x8 @x8 <  <  2 H 0 H <  <  t  <  2 H "0 H 0<  D<  T<  `   2x8 @x8 <  <  <  <  t  2x8 @x8 <  4>  >2x8 B@x8 H<  \<  p>  |<  <  >  <  <  >  2 0R2x8Z2 Hb@x8f0 Hp< < < < @x8; 29@9 2xH&@xH22w(60w(< @! H Z2xLf0xL29@9> 2xL0xL 2xN0xN2xH0xH0xHz2 H~0 HH H <  < W 2xN*0xN62xL:0xLD 2x`@x`2xP0xP2xl0xl2 0 22xL:0xLB2xNF0xN\ f2x0j@x0t  2xP0xP2xP0xP2xP0xP&2xP.0xPF2xPN0xP2x`@x`2xH2xh0xh@xH2xP0xP  t &2*02xP0xP 2x`@x`2x\0x\0x\2x8@x84; v2xL~0xL2xP0xP2xl0xl2xh2x`0xh2xp@x`2x82w(0xp0w(@x8"2$*0$62xH>0xHB2xlF0xlJ2x0N0x0R2x\V2 pZ0 p^0x\b2w(f0w(j2xPn0xPr2xTv0xTz2xL~0xL2w,0w,2xX0xX2xN0xN 2 X0 X  29@9!  @x8 X ,o p! x X 29@9  < P! X z29~@9 2 0  2xH@xH29@9"2 &0 ( K  2 0  H H H H T l   ] H H $g :2!8B0!8D T] r2 z0  ] 2!0! 2 0  2!0! ] 2!`0!`  ] &2!.0!4 @] N2!V0!^2!f0!l x] :2T>0Tj2!n0!v2xxz0xx~2#X0#X 2!0!2"0"2!0!2"@0"@2"0"2"0".2"60"J2"R0"f2#n0#2#00#02xx2"0xx0"& 2xh2xx0xx2"X @xh0"X$& R2xxV2#Z0xx^0#p 2xx2#h0xx0#h 2xx2#0xx0#  .2"( 20"( :2! >0! f2x j@x !> "> "2x"0x" #2x#@x#P #b2x#f0x#pn #Q #> # # $ $< $b2x$f@x$p> $ $ $ $n % Q % > %,! %4 %@o %TX %> % &$K &< &P> &dC &n2x&r0x&p 'H 'L 'ds ( (,< (R2x(V@x( ( ),( )> )> *> *> *8> *, *2x*@x+DK +\ +K + +> +n +, ,> ,P ,j2x,n@x,z2~,~@~,2~,@~,K ,2x,@x- -H% -K - -2x-@x-> -2x-@x-% -2-0-2-0-2-0. 2.0."2x.*@x.22x.:@x.<% .@J .L .T* .d! .l .o .X .* .2x.@x/Pn /Z2x/^@x/l, /z2x/~@x/ 0 0,H 0hH 02$00$0 12$10$1 1L 1l 1 1> 1 2> 2Z2$02^2$(2b2$2f220$020$(20$202 2 3 3$ 322$83:0$83H 32$30$3 32$@30$@3 4 4 2$H40$H4 4&2$4.0$40 4r24z04| 4204004 4 4 5t 5,> 5Pn 5d> 5 5 52p50p5 62q6 0q6 62r6"0r6F2x6f@x6j206r@06v286z296@86096 @6296096! 6 6X 7o 7^207f007 7 8 8\> 8t= 8298099K 9H 9d 9|n 9> 92909] :"2:"0: 2$P:0$P: :B2:F@:K : : : ;> ;(n ;<> ;J2;N0;|] ;"2;"0;2$;0$; <0>  <- <2<0=4> => =2=0>> > ><> >K > > >> >n >> ?( ?0 ?D> ?Ln ?`> ?n2?r0?] ?- ?C @"2@"0@ 2$@0$@ @0> @L @|v @ @i @> @% @ Az A*2A.@A:2AF@AJ@Ab2An@Ar2Av@AK A A> A> B62B:@B B2B@Cj2Cn@Cz2C@C@C2C@C2C@CK D D> D4> Dv2Dz@D E62E:@E>2EB@EF2EJ@EN2ER@Ez2$E~0$E< E E E2$E0$E< F F$ FZ2Fb2Fn2$Fr0Fv2$F2%F@F0$F0$F0%FK F G> Gx G G< G G< G G HdB Hx H^ H H^ H H^ I2%(I0%(I"2I&0I0 I62%0I:0%0I< IB2%8IF0%8IH IN2IR0I^2%`If0%`IhB Ir2Iv0I2%I0%I I J J  Jl Jx< J J2J@J0J] K KR2%@KV0%@KXB K K< K O < O0< Ox Q> Q> R|< W"2:W.@:WB@:Wb2:Wf@:W2W0Y Y Z2Z@[ \> ]W ^< _.2%_:0%_F2%_f0%aJ2_daN0_dbT !bt !c4 !c|W c< d, !dd !d| !e@ !e !flN fY f2f0gY gV2gZ0gh< g| g2%g0%g h h i2h i0h j "j "hk  "k, "hkH "Pk "kp l  "l8 "hll "hl< ls l "m( "mP "hm "hm< m "n "n0 "hnX "hn n "n n "o( "ho\ "hol< o o< p "p "hq$ qD "qp "hq "q "hrDp rd "r "hr "Pr "Pr "Pr "Ps tD "t "tq2tq0t "uN uN u v&v3v&v 3v0& v83vH&`vP3v`&vh3vx&Qv3v&Sv3v&T`v3v&Wv3v&Wv3v&Xv3w&Yw3w &Zw(3w8&Z`w@3wP&ZwX3wh&[ wp3w&[pw3w&[w3w&\w3w&\w3w&] w3w&]x3x&^0x3x(&^x03x@&_xH3xX&`x`3xp&`xx3x&ax3x&ax3x&b0x3x&bx3x&c@x3y&cy3y&dy 3y0&ey83yH&eyP3y`&fyh3yx&gPy3y&hy3y&jy3y&ky3y&m y3y1&y3z&z3z u&z(3z8&sPz@3zP&t@zX3zh&uzp3z&vz3z&wz3z&ypz3z&yz3z&zz3z&{`{3{&}P{3{(&}{03{@&{H3{X&{`3{p&{x3{&{3{&{3{&{3{&{3{&{3|&p|3|&| 3|0&|83|H&|P3|`&P|h3|x&|3|&|3|& |3|&|3|&|3|&|3}&}3} &}(3}8&}@3}P&}X3}h&p}p3}&}3}&}3}&}3}&p}3}& }3}&p~3~&p~3~(&~03~@&~H3~X&~`3~p&~x3~&0~3~&~3~&`~3~&Š~3~&ƀ~3&P3&p 30&`83H&ΰP3`&аh3x&3& 3&P3&3&Ր3&03&@3 &(38&݀@3P&ހX3h&p3&3&3&3&3&03&3&`3(&@03@&H3X&`3p& x3&@3&@3& 3&3& 3&3& 30&83H&PP3`&h3x&3&3&p3&p3&P3& 3&3 & (38& @3P& X3h& Pp3& `3& 3&3&3&3&3&3(&p03@&H3X&`3p&!@x3&"P3&63&7P3&9P3&93&:03&: 30&;83H&;pP3`&>h3x&@3&A3&D3&D3&E 3&E3&F`3 &G(38&L@3P&NX3h&Pp3&S03&U3&Yp3&]03&e@3&e3&f3(&g03@&gH3X&h`3p&hx3&h3&i3&i3&j@3&k3&l3&l 30&mP83H&mP3`&n`h3x&n3&oP3&op3&p03&s3&s3&u 3 &u@(38&u@3P&vX3h&w p3&xp3&x3&{3&|3&| 3&|@3&}03(&~P03@&@H3X&`3p&@x3&3& 3&3&`3&3&3&0 30&83H&P3`&h3x&3&@3&3&3&3&`3&3 &@(38&`@3P&X3h&@p3&3&3&3&3&3&à3&ǐ3(&03@& H3X&@`3p&ʀx3&3&3&P3&p3&Ґ3&@3&` 30&Ӏ83H&ӠP3`&h3x&3&P3&Ԑ3&ذ3& 3&3&03 &p(38&@3P&X3h&p3& 3&3&3&P3&p3&3&`3(&`03@&`H3X&`3p&x3&P3&3&p3&3&@3&3&  30& 83H&P3`&h3x&@3&3&`3&P3& P3&$3&&P3 &&p(38&'`@3P&'X3h&(pp3&(3&)03&)3&*03&+`3&-3&-3(&0@03@&2H3X&3`3p&4@x3&5P3&73&8@3&8`3&93&? 3&? 30&@083H&@P3`&A`h3x&A3&Bp3&C03&Cp3&C3&DP3&F3 &G(38&I@3P&JX3h&J`p3&J3&K@3&K3&LP3&L3&M3&N03(&Np03@&OH3X&O`3p&P`x3&P3&Q3&Q`3&Q3&Q3&S`3&U  30&U`83H&UP3`&Y@h3x&Yp3&Y3&[03&\`3&]3&dP3&d3 &d(38&e@@3P&eX3h&fp3&f@3&gp3&q03&r3&r3&r3&sP3 &(&0&1 @&KH&P&Hp&Kx&&&K~&&p&H8&+@&+&7&]H&+@&u &7&t&+@&9 &7(&s0&+(8&@&+(H&P&+pX&,`&+@h&'xp&Yx&&0 &&H8&&1P&7&[&+X&[&-&`&-&7&[h&+@&&Y& &Z(&0 0&1p8&,@&+XH&+(X&/(`&*p&+x&+&&&*&+X&+(&/(&*&&&&qx&G&q&&0&H88&0 @&*P&Gp&KLx&)8&K˜&)P¨&J°&)p&J&)&J\&)&J &) &I(&)@&IH&*`&Ilh&* À&I,È&*@à&Hè&*`&H&*&Hl&*&G&*&G` &)8&G0@&*P&FX&+h&Fp&+0Ā&FĈ&+HĘ&FPĠ&+`İ&Fĸ&+x&E&+&E&+&E\&+&E&+(&D0&+@&CTH&,X&D`&, p&DDx&,8ň&CŐ&,PŨ&CŰ&,h&C&,&B&,&B&,&BD&, &B(&,8&A@&-P&AxX&-h&A4p&-0ƀ&@ƈ&-HƘ&@Ơ&-`ư&@Ƹ&-x&@L&-&@&-&?&-&?&-(&?l0&-@&?0H&.X&>`&. p&>x&.8ǐ&>xǘ&.Pǰ&>4Ǹ&.p&=&.&=&.&=(&. &8(&.8&8@&/P&8hX&/h&80p&/0Ȁ&7Ȉ&/HȘ&7hȠ&/`Ȱ&7ȸ&/x&6&/&:&/&9&/(&9h0&/H&98P&0h&;p&0(ɀ&:<Ɉ&0Hɘ&4pɠ&0`ɰ&3ɸ&0x&5&0&2&0&K&0 &1(&0@&2H&1`&2ph&&x&Kʈ&1@ʘ&Kʨ&1`ʸ&K&1&K&1&K&1&K(&18&KH&2X&Kh&2 x&Kˈ&2@˘&K˨&2`˸&K&2&K&2&K&2 &K0&2@&KP&3`&Kp&3(̀&K̐&3H̠&K̰&3h&K&3&H8&2&,&0 &3&H8&3 &,(&0 0&3@&H8H&38P&,X&0 `&4p&H8x&3X̀&,͈&0 ͐&48͠&H8ͨ&3xͰ&,͸&0 &4h&H8&3&,&0 &4&H8&3&,&0  &40&H88&4@&,H&0 P&4`&H8h&4Hp&,x&0 ΀&5(ΐ&H8Θ&4xΠ&,Ψ&0 ΰ&5X&H8&2&,&0 &5&H8&3&,&0 &5 &H8(&380&,8&0 @&5P&H8X&3X`&,h&0 p&6π&H8ψ&3xϐ&,Ϙ&0 Ϡ&6Hϰ&H8ϸ&5&0 &6x&H8&6X&0 &6&H8&2&,&0  &60&H88&3x@&,H&0 P&6`&H8h&3p&0 x&7(Ј&H8А&4xИ&0 Р&7Pа&H8и&4&0 &7x&H8&5h&0 &7&H8&+&6&+X &+(&-p0&68&-@&0 H&7`&H8h&+p&6x&+Xр&+Xш&-ѐ&,ј&+(Ѩ&-(Ѱ&+Ѹ&0 &8 &H8&+X&*&+X&0 &8&H8&+ &+p(&0 0&8@&H8H&+pP&+pX&0 `&9p&H8x&1Ҁ&+҈&1Ґ&+Ҙ&1Ҡ&+Ҩ&0 Ұ&98&H8&1&+&1&+&0 &9&H8&+&+&0  &90&H88&+@&+H&+P&0 X&9h&H8p&+x&+Ӏ&0 ӈ&:0Ә&H8Ӡ&1pӨ&,HӰ&0 Ӹ&:`&H8&+&+&+&+&0 &:&H8&+&+ &+(&+0&0 8&:H&H8P&+X&:`&+h&:p&0 x&;Ԉ&H8Ԑ&+Ԙ&+Ԡ&; Ԩ&+԰&+Ը&; &0 &;P&H8&+X&8&*&:&+&1&, &*0&88&*H&+P&:X&1`&,h&*x&0 Հ&;Ր&H8՘&+Xՠ&8ը&*ո&+&:&+&+&+&1&,&*&8&*&+ &+(&10&,8&*H&0 P&(x&H8׀&1׈&,א&0 ט&>@ר&H8װ&1׸&,&0 &>p&H8&1&-&0 &>&H8&,&0  &>0&H88&,@&0 H&>X&H8`&-h&0 p&? ؀&H8؈&1Pؐ&-Xؘ&0 ؠ&?Hذ&H8ظ&?X&0 &?x&K&?&K&?&H8 &+(&.0&0 8&?H&H8P&+X&.`&0 h&@x&H8ـ&?و&/@ِ&0 ٘&@@٨&H8ٰ&/(ٸ&/@&0 &@p&H8&.&/@&0 &@&H8&1p&@P &0 (&@8&H8@&1pH&@P&0 X&Ah&H8p&1px&?ڀ&0 ڈ&A0ژ&H8ڠ&1pڨ&@ڰ&0 ڸ&A`&H8&@ &/@&0 &A&H8&.&/@&0 &A(&H80&:8&+X@&:H&@P&*`&9h&?p&0x&?ۀ&*ې&?ۘ&0۠&?ۨ&0 ۰&A&H8&1&,&B&0 &B&H8&>P&+p&/ &,(&+0&>P8&+@&0 H&BX&H8`&+h&>p&,x&+(܈&,ܐ&-@ܘ&+ܠ&>ܨ&0 ܰ&C &H8&+&>&,&+(&,&-@&+&>&0 &C(&H80&1p8&+@&,H&0 P&C`&H8h&+Xp&/x&*݈&Dݐ&0 ݘ&D(ݨ&H8ݰ&9ݸ&.&*&+&+&0 &Dp&H8&9&.&* &+(&+0&0 8&DH&H8P&9X&?`&*p&+x&+ހ&0 ވ&Eޘ&H8ޠ&,ި&0 ް&E`&H8&1&,&0 &E&H8&1&,&0 &E &H8(&10&,8&0 @&EP&H8X&1`&,h&0 p&F߀&H8߈&Eߐ&1Pߘ&-(ߠ&0 ߨ&FH߸&H8&+p&,&+&0 &F&H8&+X&/&0 &F(&H80&?X8&+@&DH&+XP&/@X&+`&+h&,p&0 x&F&H8&+X&/&*&G&0 &GP&H8&+&+&+X&+&,&+X&+&.&+ &+(&,0&0 8&GH&H8P&+X&G`&+h&,p&0 x&H&H8&G&H &0 &HP&H8&+&+X&/&+&B&+&*&,&G&+&0  &H0&H88&1p@&:H&+(X&1p`&/Xh&Hp&/&+&0 &H&H8&9&-X&+&+&D8&+&D8&I&+&/&*&G&0 &Ih(&H80&+8&+X@&/H&+P&BX&+`&+ph&,p&Ax&-@&*&+&1&-@&+&,&,&+&0 &I&H8&+(&1p&/X&J&/ &+(&+0&0 8&JH&H8P&+pX&+`&+h&G`p&,x&D8&J&+&/&*&D&+&/&*&D&+&D&+&0 &K&H8&+X&+ &9(&-X0&/8&+@&K H&+pP&AX&+`&-(h&*x&E&+&+&,&+&0&+&+&0 &K&H8&1p&+&J&0 &L&H8&+&F &+(&K0&0 8&LH&H8P&LX&:@`&0 h&Mx&H8&L&+&0 &M@&H8&+&Ix&+&K&0 &Mp&H8&M&:@&0 &M &H8(&+X0&2p8&-(@&+H&2P&,X&0 `&Mx&H8&+X&2&-(&+&20&,&0 &N8&H8&+X&2&-(&+&2P&,&0 &N(&H80&NP8&+@&MH&+P&MX&0 `&Nx&H8&N&+&NP&+&NP&0 &O8&H8&N&+&O&+&O&0 &O&H8&2 &,(&-@0&0 8&OH&H8P&20X&,`&-@h&0 p&P&H8&O&+&O&+&P &0 &PH&H8&M&+&O&0 &P&H8&NP&+&P  &0 (&P8&H8@&2PH&,P&-@X&0 `&Qp&H8x&N&+&Q&0 &Q8&H8&O&+&; &+&PX&0 &Qp&H8&P &+&P &+&Q &0 (&Q8&H8@&OPH&+P&; X&+`&Qh&0 p&R&H8&PX&+&PX&+&Q&0 &RH&H8&N&Q&+&Q&Q&0 &R&H8 &3x(&E0&,8&3x@&DH&-(P&0 X&Rh&H8p&+x&,&+&+&0 &S0&H8&+&+&+&,&+&+&+&+&+&+&0 &Sp&H8 &+(&+0&+8&9@&+H&0 P&S`&H8h&8p&-px&,&+&-&0 &T(&5&Tp&H8&?&+&-&0 &T&H8&?&+&-&0  &T0&H88&-@&+XH&+(X&@`&*p&+(&,&0 &T&H8&+X&6&-p&+&-p&0 &Uh&H8&+X&+&-&+&6&- &0 (&U@&H8H&FP&/p`&S@h&-p&Px&S@&-&3&/&0 &V&H8&F&/p&S@&.&P&S@&.&38&/ &0 (&V@&H8H&FP&/p`&S@h&.p&Qx&S@&.&38&/&0 &W&H8&F&/p&S@&.0&R&S@&.H&3X&/ &0 (&W@&H8H&FP&/p`&S@h&.0p&Rx&S@&.H&3X&/&0 &X&H8&F&/p&S@&.0&QH&S@&.H&3X&/ &0 (&X8&;@&YP&H8X&+(h&Yp&0 x&Y&H8&+(&Y&0 &YP&Lx&Y&Lx&Y&H8&,0 &+(&Y0&-p8&+@&,`H&YP&-X&0@`&+h&Yp&-x&+&+&1p&0 &Y&H8&8&*&Y&-p&,&+&Y&-&+&+&+&,H&+ &+(&0 0&Zp@&H8H&1PP&ZX&0 `&[p&Lx&[8&K&[X&Lx&[x&K&[&H8&[h&[&-p&0  &[0&Lx@&[X&H8`&)Hh&7p&[hx&[H&-p&[&-&1p&7&[&0 &\&K&\&K&\&K&\(&K8&\P&K`&]p&G&]8&G&]X&H8&F&/p&S@&-&]H&/&0 &]x&H8&] &]H(&](0&]H8&0 @&]P&H8X&\`&]Hh&0 p&^&H8&1p&/p&^(&/&0 &^H&H8&+X&6&+&-&0 &^&H8&+X &+(&E0&+8&+X@&,H&-P&0XX&+`&0 h&^x&H8&+X&+(&+(&B&*&+(&,&0 &_@&H8&+X&+(&+( &B(&*8&+(H&,P&0 X&_h&Gx&`0&G&`P&G&`p&Lx&`&H8&`&`&-&0 &` &H8(&[0&/@8&*H&[P&`X&1p`&\h&-p&?x&0&[&1P&/(&*&?&0&+(&Z&0 &`&Lx&a&H8&2 &a(&-0&0 8&aH&H8P&20X&a`&-h&0 p&b&H8&2&a&-&0 &bH&H8&&&+(&,&0 &b&H8&+X&+( &?(&*8&+(H&,P&+(`&,h&0 p&b&H8&+X&+&L&+&+&+&J&+&0 &cH&H8&b&+X&-&0 &c&H8 &b(&+X0&-p8&E@&8H&+P&-X&-`&0 h&cx&H8&/&*&+(&c&0 &d@&H8&a&-p&cX&:&b&c&0 &d&H8 &d(&90&-@8&*H&*X&0 `&dp&H8x&9&b&+X&-p&8&,&0 &e8&H8&c&+X&+&D8&1p&d&+&dP&eH&0 &e(&H80&a8&-p@&LH&+P&bX&c`&0 h&ex&H8&f&+X&*&*&0 &f@&H8&+&b&+X&-p&8&,&0 &f&H8 &c(&fP0&f8&0 @&fP&H8X&e`&]h&^(p&0 x&g&H8&g(&0 &gP&H8&f&]&^(&0 &gx&H8&+&e&:&9&.&*(&+p0&,8&^X@&*P&+X&]`&0 h&gx&H8&+&f&:&9&.&*&+p&,&^X&*&+&]&0 &h@&H8&a&-p &+(&a0&g(8&a@&-H&0 P&h`&H8h&ap&-px&+&b &g(&a&-&0 &i(&H8&,0&+X&/&*&+&0&1p&/p&,0&S@ &,(&E0&+8&g(@&/P&0 X&ih&H8p&-px&g(&0 &j0&H8&+p&_P&+X&+(&+(&B&*&+(&,&+(&, &+X(&:0&1p8&+@&BH&*X&:@`&?h&*x&+&?&0 &j`&H8&+X&/@&*&0&+p&-&a&-p&jp&*&+&+ &+(&+0&+8&a@&-pH&EpP&+X&a`&-ph&Ip&:x&,&+&1p&H &+&6&+&E&*&+&0 &kh&H8&+X&/@&*&+ &+(&?0&08&+@&+XH&+P&-X&+(h&/(p&+Xx&*&+&6&+&E&+X&/@&*&+&+&+&?&0&+&+&1p&1p&+&+ &k(&:@0&/@8&*H&+P&+X&*h&Dp&?x&0&+&+&+&?&0 &l&H8&&&,&7&&&0 &n&H8&&&-&3x&n &0 (&n8&H8@&&H&-P&2X&n`&0 h&ox&H8&&&-&3&n&0 &o@&H8&&&.&38&n&0 &o&H8 && &.H &3X &n &0  (&o 8&H8 @&& H&3x P&E X&-( `&* p&1p x&o &* &0  &p &H8 &9 &- &6 &+ &78 &F &/p &+X &- &S@ &- &6 &1 &78 (&/ 8&+ @&0  H&pp `&H8 h&& p&+p x&E &78 &n &p &0  &q  &H8 &0  &( &K &( &q &H8 &q &6 &0  &q 0&Lx 8&( &q &K &r &r &H8 &6 &0  &r &H8 (&6 0&+X 8&- @&E H&7 P&R X&0  `&r p&H8 x&r &r &0  &s8 &H8 &6 &^ &0  &sh &Lx &s &G &s &H8 (&p 0&& 8&q @&-p H&n P&s X&- `&1p h&o p&q8 x&p &0  &s &H8 &s &-p &r &s &s &s &-p &q &- &0  &t`&3&t &G0&tH&H8P&+XX&*h&+p&9x&,&r&s&t&*&9&+&0&+&-p&*&:&?&0 &u&H8&r &+X(&+0&r8&A@&*P&9X&,`&-ph&6p&-px&t&8&*&:@&:@&+&+&0&+&7&*&+&:&1p&0 &u&H8 &u(&+X0&*@&rH&+XP&rX&+`&-h&?p&0 x&v&H8&9&v&*&+&:@&:@&?&*&?&0 &wP&K&w0&H88&w@&-(H&AP&0 X&wp&H8x&q&-p&6&+X&-&w&-@&+&-&0 &x0&H8&+&1p&/p&+p&S@&, &-(&+p0&+X8&\@&/(H&*X&@P`&*p&/(x&*&S@&S&:@&:@&?&0&/&+&+&?&0 &x&H8&+&[h&\&-p &,(&`0&-p8&\@&-pH&,P&9X&+`&xh&*x&:@&+X&1&,&*&+X&\&T8&0 &y&H8&[h&`&-p&+X&\&-p&?&*(&+p0&\8&-p@&,H&-P&\X&@P`&*p&1x&\&T8&*&+&+&0 &z&H8&z&\&y&0 &{&Lx&{(&H80&)h8&{@&-pH&+(X&,`&,h&{p&-px&1&,&+X&+(&/(&*&+&1p&{&-&0 &{&H8&|&+&y&+X&, &-(&F0&+8&+X@&; H&/pX&6`&S@h&-p&+px&-&/&+&0 &|&H8&{&+&-&0 &}x&H8&+(&y&9&0 &}(&H80&\8&-p@&EH&\P&-X&](`&yh&9p&0 x&}&Lx&~P&H8&~`&T&0 &~p&H8&+(&~`&-&0 &~&H8 &~`(&-p0&*@&0H&+(X&Z`&0 h&~&H8&n&0 &@&H8&{&s&+@&H8&X&~&0 &p&H8&p&&&+@ &H8(&X0&~8&0 @&P&H8X&~`&+@h&0 p&Xx&tp&~&0 &&H8&~&+(&y&+@&88&X&+X&o&F&/p&S@&-&o &/0&p8&0 @&hP&H8X&~``&-ph&*x&x&+@&^&X&0&+(&y&+X&+&|&+X&+&+&0X&+&+&0 &&H8 &((&90&,8&1p@&+H&-P&+X&0 `&p&H8x&~`&-p&*&(&+@&]&X&0&+(&y&]&0 &8&H8&+(&y&] &0 (&@&H8H&+P&6X&+X`&-ph&Xp&+x&0 &&Lx&X&H8&~`&-p&1&~`&T8&*&0&&&h&-&)&7 &&(&0&H88&0 @&xP&H8X&1P`&~`h&T8p&~`x&-p&*&0&&0&h&-p&7&&&)&0@&0 &&H8&&&+p&6&, &+(&-0&0 8&H&H8P&X&+@`&*h&Xp&&x&1p&X&0 &&H8&&+@&*&X&&&1p&X&0 &h&H8&~&&(&0  &0&H88&~@&+@H&*P&XX&&`&1ph&Xp&+x&&0 &&H8&&1p&0 &`&H8&~&+@&+&X&8 &* &E &+ & (&* 8&( @&0  H& X&H8 `&~ h&E p&+ x&+@ &+p &X &+@ &/( &X &x &+@ &+ &X &+ &0  &  &H8 &~ &+!&!&+!&0 !&!0&H8!8&&!@&6!H&,!P&X!X&0 !`&!p&H8!x&!&&!&0 !&8!&H8!&~!&+@!&*!&X!&!&(!&0 !&h!&H8!&~"&+@"&*"&X"&" &("(&0 "0&"@&H8"H&~"P&x"X&+"`&0 "h&"x&H8"&~"&x"&"&0 "&@"&Lx"&x"&H8"&"&-p"&8"&*#&+X#&-p#&+# &&#(&+p#0&,#8&+#@&-#H&*#X&&#`&,#h&X#p&#x&-#&0 #&#&H8#&#&#&-p#&&#&+@#&/X#&X#&1p#&#&-#&0 #&`$&H8$&$&$ &-p$(&+@$0&/p$8&X$@&&$H&&$P&$X&-$`&1p$h&X$p&0 $x&$&H8$&~$&+@$&/$&X$&$&($&0 $&P$&H8$&~$&+@$&/$&X%&%&(%&0 %&%(&H8%0&~%8&+@%@&/%H&X%P&%X&-p%`&&%h&%p&-%x&X%&0 %&%&H8%&~%&+@%&/%&X%&%&-p%&&%&%&-%&X%&0 %&`&&H8&&+& &[h&(&+&0&[&8&-p&@&+&H&[&P&+&X&`&`&-p&h&+&p&\&x&-p&&+&&+&&0 &&&&H8&&+&&+&&\&&-&&+&&`&&-&&+&&7'&['&+'&['&-' &+'(&7'0&[h'8&+'@&0 'H&p'`& '&8'&X'&'&G(&(&K((&(@&H8(H&1P(P&7(X&(`&0 (h&(&H8(&1p(&7(&(&0 (&@(&H8(&(&*(&+(&+(&i(&+)&+)&0 )&)0&H8)8&+X)@&+()P&/()X&*)h&+@)p&)x&^)&])&]h)&+)&0)&+X)&+()&/()&*)&+)&0)&)&0 )&*&H8*&^(*&+X* &/@*(&**8&*@&+@*H&0*P&**`&+X*h&1P*p&/(*x&**&+@*&P*&^*&]*&**&+X*&+(*&/(*&**&Y*&-p*&^+&]+&++&*+ &+(&]h+0&0 +8&+P&H8+X&9+`&v+h&*+x&x+&*+&:@+&:@+&0@+&0+&X+&9+&0+&9+&l+&*+&]+&+(,&Z,&+@,&+(,&X, &X,(&9,0&0 ,8&,P&H8,X&9,`&v,h&*,x&+,&:@,&:@,&0@,&0,&9,&l,&*,&],&+(,&Z,&+,&9,&+,&0 -&-&H8- &1p-(&\-0&--8&{-@&+X-H&*-X&~`-`&-p-h&*-x&(-&*-&(-&*-&9-&0 -&'`-&H8-&'x-&0 -&-&H8.&+.&*.&Y. &-.(&+(.8&Z.@&+.H&0 .P&.`&H8.h&x.p&+@.x&.&X.&0 .&(.&h.&H8.&|.&+.&+@.&/&+X/&-/&E/&,/ &+/(&0X/0&,/8&+X/@&-/H&E/P&,/X&+/`&+X/h&,/p&-/x&,/&,/&-/&0X/&+/&0 /&/&H8/&{/&w`/&/@/&*/&/&?/&+0&0&0 0&0 &H80(&1p00&,08&~0@&\00H&,00P&g(0X&+(0h&]H0p&^(0x&`0&*0&^(0&+@0&0&Y0&+X0&0&*0&*0&0 0&1&G1&1(&G18&1P&G1`&1x&H81&1&91&+1&+1&F1&/p1&+1&,1&+1&+1&,1&,1&,1&+1&92&](2&x2&*2 &:@2(&+X20&+28&'x2@&+2H&E2P&/2`&+2h&+2p&2x&0 2&82&H82&{2&P2&0 2&X2&H82&s2&+@2&G2&X2&+@3&q3&63&X3&tp3 &0 3(&38&H83@&{3H&3P&0 3X&3p&H83x&+3&63&s3&-p3&sH3&63&-3&0 3&03&H83&+@3&H3&X3&0 3&4&H84&{4&s4 &+@4(&K40&X48&X4@&tp4H&0 4P&4`&H84h&{4p&s4x&+@4&K4&X4&X4&tp4&0 4&(4&H84&{4&s4&+@4&Lx4&X4&1p4&X5&tp5&0 5&5(&H850&{58&s5@&+@5H&L@5P&X5X&n5`&tp5h&0 5p&5&H85&{5&s5&+@5&G5&X5&+@5&[5&X5&tp5&0 5&H5&H85&{5&s6&+@6&L06&X6&6 &X6(&tp60&0 68&6H&H86P&1p6X&0 6`&6x&H86&+6&0 6&86&H86&{6&s6&+@6&K6&X6&+p6&n6&,6&tp6&0 6&h7&H87&+@7 &+(7(&X70&X78&0 7@&7X&H87`&7h&X7p&0 7x&7&H87&{7&97&v7&/@7&*7&7&?7&+7&7&x7&/@7&*8&+@8&+@8&X8 &X8(&+@80&X88&X8@&98H&0 8P&P8`&H88h&}8p&8x&0 8&(8&H88&8&+@8&+@8&X8&X8&0 8&X8&H88&+X8&^8&v8&*9&:9&+9&?9 &+9(&x90&*9@&D9H&09P&?9X&09`&0 9h&9x&H89&9&~`9&-p9&*9&+@9&79&X9&X9&09&69&-9&0 9&@:&H8:&6:&-p:&0 : &:0&H8:8&1:@&7`:H&,:P&0 :X&:h&H8:p&1:x&7`:&,:&0 :&0:&H8:&tp:&0 :&h:&H8:&s:&-p:&sH:&X;&0 ;&;&H8; &{;(&a;0&-p;8&+;@&a;H&'x;P&+;X&a;`&-;h&0 ;p&;&H8;&{;&a;&-p;&+;&b ;&'x;&+;&a;&-;&0 ;&H;&H8;&{;&a<&-p<&+<&bX<&'x< &+<(&a<0&-<8&0 <@&&->&> &->(&>H&-@>P&>`&,>h&(>&, >&@>&,>&`>&+>&>&+P?&? &+?(&?H&*?P&?p&*`?x&(?&*$?&P?&)?&x?&)?&@&) @&@8&'@@&@`&'@h&@&'0@&@@&(@&h@&(x@&@&((@&A&&A &A@&&AH&Ah&&LAp& A&|A&HA&@A&pA&A&B&B&B0&|B8&BX&@B`&B&B&8B&B&`B&B&B&B&C&\C&C0& C8&CP&CX&Cp&Cx&0C&lC&PC&0C&xC&C&C&D&D &dD(&DH&DP&Dh&Dp&(D&XD&HD&D&pD&D&E&tE&E(&E0&EP&EX&Ep&Ex&0E&,E&PE&E&xE& E&E&F&F&!lF &F8&xF@&FX&F`&Fx&!4F&8F& 4F&XF&TF&xF& F&G&0G&G(&G0&GX& xG`&G&G&8G&xG&`G&#G&H&#8H&H(&pH0&HP&HX&Hx&`H&0H&H&XH&"H&H&"H&I&"XI&I(&" I0&IH&!IP&Ih&!Ip&(I&%lI&HI&%0I&hI&%I&I&$I&J&$J&J(&$TJ0&JH&$JP&Jh&0Jp&(J&J&HJ&4J&hJ&J&J&J&K&tK&K&<K &K0&K8&KH&KP&K`&Kh&(Kx&LK&@K&K&XK&K&pK&lK&K&K&K&K&L&4L&L &L(&L8&L@&LP&TLX&Lh&Lp&0L& L&HL& L&`L& <L&xL& tL&L& L&L& M&M& \M&M(& M0&M@& MH&MX& $M`& Mp& |Mx&8M& M&PM& M&hM& DM&M& M&N& N&N &N(&N8&8N@&NP& \NX&Nh& Np&0N& N&&(N& N&`N&GN&&XN&KO&O&O(&H8O0&O8&-pO@&0 OH&OX&O`& Ox& DO&8O&pO&XO&O&xO&lO&P&P&P& P &P0&LxP@&PP&H8PX&P`&-pPh&-Pp&+(P&P&T8P&0 P&P&G͠& 8ͨ& @Ͱ& H͸& X& p& x& & & & & & & & & &  & ((& 0& 8& `@& 8H& P& X& `& xh& ΀&pΈ& ΐ& Θ& hΠ&(Ψ& ΰ& θ&& &&&P&& & &x(&hX&x&Ϙ&ϸ&&&(&8&X&x&0И&Hа&0&H&X&x&(&@&X&p&ш&Ѡ&(Ѹ&8&H&X&h&x0&H&`&x&Ґ&Ҩ&&&`&Ӏ&X.symtab.strtab.shstrtab.rela.slof.loader.rela.text.rela.opd.got.rela.data.comment.bss d@h 2s -@ =vv#(8@FP B((L((:G@@O R0ӴӴ+[Ӵ!0  x 0`H0bootinfo<<_(ide.fs1 encode-int s" #address-cells" property 0 encode-int s" #size-cells" property : decode-unit 1 hex-decode-unit ; : encode-unit 1 hex-encode-unit ; 0 VALUE >ata \ base address for command-block 0 VALUE >ata1 \ base address for control block true VALUE no-timeout \ flag that no timeout occurred 0c CONSTANT #cdb-bytes \ command descriptor block (12 bytes) 800 CONSTANT atapi-size 200 CONSTANT ata-size : ata-ctrl! 2 >ata1 + io-c! ; \ device control reg : ata-astat@ 2 >ata1 + io-c@ ; \ read alternate status : ata-data@ 0 >ata + io-w@ ; \ data reg : ata-data! 0 >ata + io-w! ; \ data reg : ata-err@ 1 >ata + io-c@ ; \ error reg : ata-feat! 1 >ata + io-c! ; \ feature reg : ata-cnt@ 2 >ata + io-c@ ; \ sector count reg : ata-cnt! 2 >ata + io-c! ; \ sector count reg : ata-lbal! 3 >ata + io-c! ; \ lba low reg : ata-lbal@ 3 >ata + io-c@ ; \ lba low reg : ata-lbam! 4 >ata + io-c! ; \ lba mid reg : ata-lbam@ 4 >ata + io-c@ ; \ lba mid reg : ata-lbah! 5 >ata + io-c! ; \ lba high reg : ata-lbah@ 5 >ata + io-c@ ; \ lba high reg : ata-dev! 6 >ata + io-c! ; \ device reg : ata-dev@ 6 >ata + io-c@ ; \ device reg : ata-cmd! 7 >ata + io-c! ; \ command reg : ata-stat@ 7 >ata + io-c@ ; \ status reg 00 CONSTANT cmd#nop \ ATA and ATAPI 08 CONSTANT cmd#device-reset \ ATAPI only (mandatory) 20 CONSTANT cmd#read-sector \ ATA and ATAPI 90 CONSTANT cmd#execute-device-diagnostic \ ATA and ATAPI a0 CONSTANT cmd#packet \ ATAPI only (mandatory) a1 CONSTANT cmd#identify-packet-device \ ATAPI only (mandatory) ec CONSTANT cmd#identify-device \ ATA and ATAPI : set-regs ( n -- ) dup 01 and \ only Chan 0 or Chan 1 allowed 3 lshift dup 10 + config-l@ -4 and to >ata 14 + config-l@ -4 and to >ata1 02 ata-ctrl! \ disable interrupts 02 and IF 10 ELSE 00 THEN ata-dev! ; ata-size VALUE block-size 80000 VALUE max-transfer \ Arbitrary, really CREATE sector d# 512 allot CREATE packet-cdb #cdb-bytes allot CREATE return-buffer atapi-size allot scsi-open \ add scsi functions : show-regs cr cr ." alt. Status: " ata-astat@ . cr ." Status : " ata-stat@ . cr ." Device : " ata-dev@ . cr ." Error-Reg : " ata-err@ . cr ." Sect-Count : " ata-cnt@ . cr ." LBA-Low : " ata-lbal@ . cr ." LBA-Med : " ata-lbam@ . cr ." LBA-High : " ata-lbah@ . ; : status-check ( -- ) ata-stat@ dup 01 and \ is 'check' flag set ? IF cr ." - ATAPI-Status: " . ata-err@ \ retrieve sense code dup 60 = \ sense code = 6 ? IF ." ( media changed or reset )" \ 'unit attention' drop \ drop err-reg content ELSE dup ." (Err : " . \ show err-reg content space rshift 4 .sense-text \ show text string 29 emit THEN cr ELSE drop \ remove unused status THEN ; : wait-for-ready get-msecs \ start timer BEGIN ata-stat@ 80 and 0<> \ busy flag still set ? no-timeout and WHILE \ yes dup get-msecs swap - \ calculate timer difference FFFF AND \ reduce to 65.5 seconds d# 5000 > \ difference > 5 seconds ? IF false to no-timeout THEN REPEAT drop ; : wait-for-status ( val mask -- ) get-msecs \ initial timer value (start) >r BEGIN 2dup \ val mask ata-stat@ and <> \ expected status ? no-timeout and \ and no timeout ? WHILE get-msecs r@ - \ calculate timer difference FFFF AND \ mask-off overflow bits d# 5000 > \ 5 seconds exceeded ? IF false to no-timeout \ set global flag THEN REPEAT r> \ clean return stack 3drop ; : cut-string ( saddr nul -- ) swap over + swap 1 rshift \ bytecount -> wordcount 0 do /w - dup ( addr -- addr addr ) w@ ( addr addr -- addr nuw ) dup ( addr nuw -- addr nuw nuw ) 2020 = IF drop 0 ELSE LEAVE THEN over w! LOOP drop drop ; : show-model ( dev# chan# -- ) 2dup ." CH " . \ channel 0 / 1 0= IF ." / MA" \ Master / Slave ELSE ." / SL" THEN swap 2 * + ." (@" . ." ) : " \ device number sector 1 + c@ 80 AND 0= IF ." ATA-Drive " ELSE ." ATAPI-Drive " THEN 22 emit \ start string display with " sector d# 54 + \ string starts 54 bytes from buffer start dup d# 40 \ and is 40 chars long cut-string \ remove all trailing spaces BEGIN dup w@ wbflip wbsplit dup 0<> \ first char IF emit dup 0<> \ second char IF emit wa1+ \ increment address for next false ELSE \ second char = EndOfString drop true THEN ELSE \ first char = EndOfString drop drop true THEN UNTIL \ end of string detected drop 22 emit \ end string display sector c@ \ get lower byte of first doublet 80 AND \ check bit 7 IF ." (removable media)" THEN sector 1 + c@ 80 AND 0= IF \ is this an ATA drive ? sector d# 120 + \ get word 60 + 61 rl@-le \ read 32-bit as little endian value d# 512 \ standard ATA block-size swap .capacity-text ( block-size #blocks -- ) THEN sector d# 98 + \ goto word 49 w@ wbflip 200 and 0= IF cr ." ** LBA is not supported " THEN sector c@ \ get lower byte of first doublet 03 AND 01 = \ we use 12-byte packet commands (=00b) IF cr ." packet size = 16 ** not supported ! **" THEN no-timeout not \ any timeout occurred so far ? IF cr ." ** timeout **" THEN ; : pio-sector ( addr -- ) 100 0 DO ata-data@ over w! wa1+ LOOP drop ; : pio-sector ( addr -- ) wait-for-ready pio-sector ; : pio-sectors ( n addr -- ) swap 0 ?DO dup pio-sector 200 + LOOP drop ; : lba! lbsplit 0f and 40 or \ always set LBA-mode + LBA (27..24) ata-dev@ 10 and or \ add current device-bit (DEV) ata-dev! \ set LBA (27..24) ata-lbah! \ set LBA (23..16) ata-lbam! \ set LBA (15..8) ata-lbal! \ set LBA (7..0) ; : read-sectors ( lba count addr -- ) >r dup >r ata-cnt! lba! 20 ata-cmd! r> r> pio-sectors ; : read-sectors ( lba count addr dev-nr -- ) set-regs ( lba count addr ) \ Set ata regs BEGIN >r dup 100 > WHILE over 100 r@ read-sectors >r 100 + r> 100 - r> 20000 + REPEAT r> read-sectors ; : ata-read-blocks ( addr block# #blocks dev# -- #read ) swap dup >r swap >r rot r> ( addr block# #blocks dev # R: #blocks ) read-sectors r> ( R: #read ) ; : set-lba ( block-length -- ) lbsplit ( quad -- b1.lo b2 b3 b4.hi ) drop \ skip upper two bytes drop ata-lbah! ata-lbam! ; : read-pio-block ( buff-addr -- buff-addr-new ) ata-lbah@ 8 lshift \ get block length High ata-lbam@ or \ get block length Low 1 rshift \ bcount -> wcount dup 0> IF \ any data to transfer? 0 DO \ words to read dup \ buffer-address ata-data@ swap w! \ write 16-bits wa1+ \ address of next entry LOOP ELSE drop ( buff-addr wcount -- buff-addr ) THEN wait-for-ready ; : send-atapi-packet ( req-buffer -- ) >r ( R: req-buffer ) atapi-size set-lba \ set regs to length limit 00 ata-feat! cmd#packet ata-cmd! \ A0 = ATAPI packet command 48 C8 wait-for-status ( val mask -- ) \ BSY:0 DRDY:1 DRQ:1 6 0 do packet-cdb i 2 * + \ transfer command block (12 bytes) w@ ata-data! \ 6 doublets PIO transfer to device loop \ copy packet to data-reg status-check ( -- ) \ status err bit set ? -> display wait-for-ready ( -- ) \ busy released ? BEGIN ata-stat@ 08 and 08 = WHILE \ Data-Request-Bit set ? r> \ get last target buffer address read-pio-block \ only if from device requested >r \ start of next block REPEAT r> \ original value drop \ return clean ; : atapi-packet-io ( -- ) return-buffer atapi-size erase \ clear return buffer return-buffer send-atapi-packet \ send 'packet-cdb' , get 'return-buffer' ; : atapi-test ( -- true|false ) packet-cdb scsi-build-test-unit-ready \ command-code: 00 atapi-packet-io ( ) \ send CDB, get return-buffer ata-stat@ 1 and IF false ELSE true THEN ; : atapi-sense ( -- ascq asc sense-key ) d# 252 packet-cdb scsi-build-request-sense ( alloc-len cdb -- ) atapi-packet-io ( ) \ send CDB, get return-buffer return-buffer scsi-get-sense-data ( cdb-addr -- ascq asc sense-key ) ; : atapi-read-blocks ( address block# #blocks dev# -- #read-blocks ) set-regs ( address block# #blocks ) dup >r ( address block# #blocks ) packet-cdb scsi-build-read-10 ( address block# #blocks cdb -- ) send-atapi-packet ( address -- ) r> \ return requested number of blocks ; : atapi-read-capacity ( -- ) packet-cdb scsi-build-read-cap-10 \ fill block with command atapi-packet-io ( ) \ send CDB, get return-buffer return-buffer scsi-get-capacity-10 ( cdb -- block-size #blocks ) .capacity-text ( block-size #blocks -- ) status-check ( -- ) ; : atapi-read-capacity-ext ( -- ) packet-cdb scsi-build-read-cap-16 \ fill block with command atapi-packet-io ( ) \ send CDB, get return-buffer return-buffer scsi-get-capacity-16 ( cdb -- block-size #blocks ) .capacity-text ( block-size #blocks -- ) status-check ( -- ) ; : wait-for-media-ready ( -- true|false ) get-msecs \ initial timer value (start) >r BEGIN atapi-test \ unit ready? false if not not no-timeout and WHILE atapi-sense ( -- ascq asc sense-key ) 02 = \ sense key 2 = media error IF \ check add. sense code 3A = \ asc: device not ready ? IF false to no-timeout ." empty (" . 29 emit \ show asc qualifier ELSE drop \ discard asc qualifier THEN \ medium not present, abort waiting ELSE drop \ discard asc drop \ discard ascq THEN get-msecs r@ - \ calculate timer difference FFFF AND \ mask-off overflow bits d# 5000 > \ 5 seconds exceeded ? IF false to no-timeout \ set global flag THEN REPEAT r> drop no-timeout ; 2 CONSTANT #chan 2 CONSTANT #dev : #totaldev #dev #chan * ; CREATE read-blocks-xt #totaldev cells allot read-blocks-xt #totaldev cells erase : dev-read-blocks ( address block# #blocks dev# -- #read-blocks ) dup cells read-blocks-xt + @ execute ; : read-ident ( -- true|false ) false 00 ata-lbal! \ clear previous signature 00 ata-lbam! 00 ata-lbah! cmd#identify-device ata-cmd! wait-for-ready \ first try ATA, ATAPI aborts command ata-stat@ CF and 48 = IF drop true \ cmd accepted, this is a ATA d# 512 set-lba \ set LBA to sector-length ELSE \ ATAPI sends signature instead ata-lbam@ 14 = IF \ cylinder low = 14 ? ata-lbah@ EB = IF \ cylinder high = EB ? cmd#device-reset ata-cmd! wait-for-ready \ only supported by ATAPI cmd#identify-packet-device ata-cmd! wait-for-ready \ first try ata ata-stat@ CF and 48 = IF drop true \ replace flag THEN THEN THEN THEN dup IF ata-stat@ 8 AND IF \ data requested (as expected) ? sector read-pio-block drop \ discard address end ELSE drop false THEN THEN no-timeout not IF \ check without any timeout ? drop false \ no, detection discarded THEN ; scsi-close \ remove scsi commands from word list : find-disks ( -- ) #chan 0 DO \ check 2 channels (primary & secondary) #dev 0 DO \ check 2 devices per channel (master / slave) i 2 * j + set-regs \ set base address and dev-register for register access ata-stat@ 7f and 7f <> \ Check, if device is connected IF true to no-timeout \ preset timeout-flag read-ident ( -- true|false ) IF i j show-model \ print manufacturer + device string sector 1+ c@ C0 and 80 = \ Check for ata or atapi IF wait-for-media-ready \ wait up to 5 sec if not ready no-timeout and IF atapi-read-capacity atapi-size to block-size \ ATAPI: 2048 bytes 80000 to max-transfer ['] atapi-read-blocks i 2 * j + cells read-blocks-xt + ! s" cdrom" strdup i 2 * j + s" generic-disk.fs" included ELSE ." -" \ show hint for not registered THEN ELSE ata-size to block-size \ ATA: 512 bytes 80000 to max-transfer ['] ata-read-blocks i 2 * j + cells read-blocks-xt + ! s" disk" strdup i 2 * j + s" generic-disk.fs" included THEN cr THEN THEN i 2 * j + 200 + cp LOOP LOOP ; find-disks -P-0fbuffer.fs0 VALUE line# 0 VALUE column# false VALUE inverse? false VALUE inverse-screen? 18 VALUE #lines 50 VALUE #columns false VALUE cursor false VALUE saved-cursor defer draw-character \ 2B inited by display driver defer reset-screen \ 2B inited by display driver defer toggle-cursor \ 2B inited by display driver defer erase-screen \ 2B inited by display driver defer blink-screen \ 2B inited by display driver defer invert-screen \ 2B inited by display driver defer insert-characters \ 2B inited by display driver defer delete-characters \ 2B inited by display driver defer insert-lines \ 2B inited by display driver defer delete-lines \ 2B inited by display driver defer draw-logo \ 2B inited by display driver : nop-toggle-cursor ( nop ) ; ' nop-toggle-cursor to toggle-cursor : (cursor-off) ( -- ) cursor dup to saved-cursor IF toggle-cursor false to cursor THEN ; : (cursor-on) ( -- ) cursor dup to saved-cursor 0= IF toggle-cursor true to cursor THEN ; : restore-cursor ( -- ) saved-cursor dup cursor <> IF toggle-cursor to cursor ELSE drop THEN ; ' (cursor-off) to cursor-off ' (cursor-on) to cursor-on false VALUE esc-on false VALUE csi-on defer esc-process 0 VALUE esc-num-parm 0 VALUE esc-num-parm2 0 VALUE saved-line# 0 VALUE saved-column# : get-esc-parm ( default -- value ) esc-num-parm dup 0> IF nip ELSE drop THEN 0 to esc-num-parm ; : get-esc-parm2 ( default -- value ) esc-num-parm2 dup 0> IF nip ELSE drop THEN 0 to esc-num-parm2 ; : set-esc-parm ( newdigit -- ) [char] 0 - esc-num-parm a * + to esc-num-parm ; : reverse-cursor ( oldpos -- newpos) dup IF 1 get-esc-parm - THEN ; : advance-cursor ( bound oldpos -- newpos) tuck > IF 1 get-esc-parm + THEN ; : erase-in-line #columns column# - dup 0> IF delete-characters ELSE drop THEN ; : terminal-line++ ( -- ) line# 1+ dup #lines = IF 1- 0 to line# 1 delete-lines THEN to line# ; 0 VALUE dang 0 VALUE blipp false VALUE stopcsi 0 VALUE term-background 7 VALUE term-foreground : set-term-color dup d# 30 d# 39 between IF dup d# 30 - to term-foreground THEN dup d# 40 d# 49 between IF dup d# 40 - to term-background THEN 0 = IF 0 to term-background 7 to term-foreground THEN term-foreground term-background <= to inverse? ; : ansi-esc ( char -- ) csi-on IF dup [char] 0 [char] 9 between IF set-esc-parm ELSE true to stopcsi CASE [char] A OF line# reverse-cursor to line# ENDOF [char] B OF #lines line# advance-cursor to line# ENDOF [char] C OF #columns column# advance-cursor to column# ENDOF [char] D OF column# reverse-cursor to column# ENDOF [char] E OF ( FIXME: Cursor Next Line - No idea what does it mean ) #lines line# advance-cursor to line# ENDOF [char] f OF 1 get-esc-parm2 to line# column# get-esc-parm to column# ENDOF [char] H OF 1 get-esc-parm2 to line# column# get-esc-parm to column# ENDOF [char] ; OF false to stopcsi 0 get-esc-parm to esc-num-parm2 ENDOF [char] ? OF false to stopcsi ENDOF ( FIXME: Ignore that for now ) [char] l OF ENDOF ( FIXME: ?25l should hide cursor ) [char] h OF ENDOF ( FIXME: ?25h should show cursor ) [char] J OF #lines line# - dup 0> IF line# 1+ to line# delete-lines line# 1- to line# ELSE drop THEN erase-in-line ENDOF [char] K OF erase-in-line ENDOF [char] L OF 1 get-esc-parm insert-lines ENDOF [char] M OF 1 get-esc-parm delete-lines ENDOF [char] @ OF 1 get-esc-parm insert-characters ENDOF [char] P OF 1 get-esc-parm delete-characters ENDOF [char] m OF 0 get-esc-parm set-term-color ENDOF [char] p OF inverse-screen? IF false to inverse-screen? inverse? 0= to inverse? invert-screen THEN ENDOF [char] q OF inverse-screen? 0= IF true to inverse-screen? inverse? 0= to inverse? invert-screen THEN ENDOF [char] u OF saved-line# to line# saved-column# to column# ENDOF dup dup to dang OF blink-screen ENDOF ENDCASE stopcsi IF false to csi-on false to esc-on 0 to esc-num-parm 0 to esc-num-parm2 THEN THEN ELSE CASE [char] 7 OF line# to saved-line# column# to saved-column# ENDOF [char] 8 OF saved-line# to line# saved-column# to column# ENDOF [char] [ OF true to csi-on ENDOF dup dup OF false to esc-on to blipp ENDOF ENDCASE csi-on 0= IF false to esc-on THEN 0 to esc-num-parm 0 to esc-num-parm2 THEN ; ' ansi-esc to esc-process CREATE twtracebuf 4000 allot twtracebuf 4000 erase twtracebuf VALUE twbp 0 VALUE twbc 0 VALUE twtrace-enabled? : twtrace twbc 4000 = IF 0 to twbc twtracebuf to twbp THEN dup twbp c! twbp 1+ to twbp twbc 1+ to twbc ; : terminal-write ( addr len -- actual-len ) cursor-off tuck bounds ?DO i c@ twtrace-enabled? IF twtrace THEN esc-on IF esc-process ELSE CASE 1B OF true to esc-on ENDOF carret OF 0 to column# ENDOF linefeed OF terminal-line++ ENDOF bell OF blink-screen ENDOF 9 ( TAB ) OF column# 7 + -8 and dup #columns < IF to column# ELSE drop THEN ENDOF B ( VT ) OF line# ?dup IF 1- to line# THEN ENDOF C ( FF ) OF 0 to line# 0 to column# erase-screen ENDOF bs OF column# 1- dup 0< IF line# IF line# 1- to line# drop #columns 1- ELSE drop column# THEN THEN to column# ( bl draw-character ) ENDOF dup OF i c@ draw-character column# 1+ dup #columns >= IF drop 0 terminal-line++ THEN to column# ENDOF ENDCASE THEN LOOP restore-cursor ; 0 VALUE char-height 0 VALUE char-width 0 VALUE fontbytes CREATE display-emit-buffer 20 allot defer dis-old-emit ' emit behavior to dis-old-emit : display-write terminal-write ; : display-emit dup dis-old-emit display-emit-buffer tuck c! 1 terminal-write drop ; : is-install ( 'open -- ) s" defer vendor-open to vendor-open" eval s" : open deadbeef vendor-open dup deadbeef = IF drop true ELSE nip THEN ;" eval s" defer write ' display-write to write" eval s" : draw-logo ['] draw-logo CATCH IF 2drop 2drop THEN ;" eval s" : reset-screen ['] reset-screen CATCH drop ;" eval ; : is-remove ( 'close -- ) s" defer close to close" eval ; : is-selftest ( 'selftest -- ) s" defer selftest to selftest" eval ; STRUCT cell FIELD font>addr cell FIELD font>width cell FIELD font>height cell FIELD font>advance cell FIELD font>min-char cell FIELD font>#glyphs CONSTANT /font CREATE default-font-ctrblk /font allot default-font-ctrblk dup font>addr 0 swap ! dup font>width 8 swap ! dup font>height -10 swap ! dup font>advance 1 swap ! dup font>min-char 20 swap ! font>#glyphs 7f swap ! : display-default-font ( str len -- ) romfs-lookup dup 0= IF drop EXIT THEN 600 <> IF ." Only support 60x8x16 fonts ! " drop EXIT THEN default-font-ctrblk font>addr ! ; s" default-font.bin" display-default-font : .scan-lines ( height -- scanlines ) dup 0>= IF 1- ELSE negate THEN ; : set-font ( addr width height advance min-char #glyphs -- ) default-font-ctrblk /font + /font 0 DO 1 cells - dup >r ! r> 1 cells +LOOP drop default-font-ctrblk dup font>height @ abs to char-height dup font>width @ to char-width font>advance @ to fontbytes ; : >font ( char -- addr ) dup default-font-ctrblk dup >r font>min-char @ dup r@ font>#glyphs + within IF r@ font>min-char @ - r@ font>advance @ * r@ font>height @ .scan-lines * r> font>addr @ + ELSE drop r> font>addr @ THEN ; : default-font ( -- addr width height advance min-char #glyphs ) default-font-ctrblk /font 0 DO dup cell+ >r @ r> 1 cells +LOOP drop ; 0 VALUE frame-buffer-adr 0 VALUE screen-height 0 VALUE screen-width 0 VALUE screen-depth 0 VALUE screen-line-bytes 0 VALUE window-top 0 VALUE window-left 0 VALUE .sc : screen-#rows ( -- rows ) .sc IF screen-height char-height / ELSE true to .sc s" screen-#rows" eval false to .sc THEN ; : screen-#columns ( -- columns ) .sc IF screen-width char-width / ELSE true to .sc s" screen-#columns" eval false to .sc THEN ; : fb8-background inverse? ; : fb8-foreground inverse? invert ; : fb8-lines2bytes ( #lines -- #bytes ) char-height * screen-line-bytes * ; : fb8-columns2bytes ( #columns -- #bytes ) char-width * screen-depth * ; : fb8-line2addr ( line# -- addr ) char-height * window-top + screen-line-bytes * frame-buffer-adr + window-left screen-depth * + ; : fb8-erase-block ( addr len ) fb8-background rfill ; 0 VALUE .ab CREATE bitmap-buffer 400 4 * allot : active-bits ( -- new ) .ab dup 8 > IF 8 - to .ab 8 ELSE char-width to .ab ?dup 0= IF recurse THEN THEN ; : fb8-char2bitmap ( font-height font-addr -- bitmap-buffer ) bitmap-buffer >r char-height rot 0> IF r> char-width 2dup fb8-erase-block + >r 1- THEN r> -rot char-width to .ab fontbytes * bounds ?DO i c@ active-bits 0 ?DO dup 80 and IF fb8-foreground ELSE fb8-background THEN ( fb-addr fbyte colr ) 2 pick ! 1 lshift swap screen-depth + swap LOOP drop LOOP drop bitmap-buffer ; : fb8-draw-logo ( line# addr width height -- ) ." fb8-draw-logo ( " .s ." )" cr 2drop 2drop ; : fb8-toggle-cursor ( -- ) line# fb8-line2addr column# fb8-columns2bytes + char-height 2 - screen-line-bytes * + 2 0 ?DO dup char-width screen-depth * invert-region screen-line-bytes + LOOP drop ; : fb8-draw-character ( char -- ) >r default-font over + r@ -rot between IF 2swap 3drop r> >font fb8-char2bitmap ( bitmap-buf ) line# fb8-line2addr column# fb8-columns2bytes + ( bitmap-buf fb-addr ) char-height 0 ?DO 2dup char-width screen-depth * mrmove screen-line-bytes + >r char-width screen-depth * + r> LOOP 2drop ELSE 2drop r> 3drop THEN ; : fb8-insert-lines ( n -- ) fb8-lines2bytes >r line# fb8-line2addr dup dup r@ + #lines line# - fb8-lines2bytes r@ - rmove r> fb8-erase-block ; : fb8-delete-lines ( n -- ) fb8-lines2bytes >r line# fb8-line2addr dup dup r@ + swap #lines fb8-lines2bytes r@ - dup >r rmove r> + r> fb8-erase-block ; : fb8-insert-characters ( n -- ) line# fb8-line2addr column# fb8-columns2bytes + >r #columns column# - 2dup >= IF nip dup 0> IF fb8-columns2bytes r> ELSE r> 2drop EXIT THEN ELSE fb8-columns2bytes swap fb8-columns2bytes tuck - over r@ tuck + rot char-height 0 ?DO 3dup rmove -rot screen-line-bytes tuck + -rot + swap rot LOOP 3drop r> THEN char-height 0 ?DO dup 2 pick fb8-erase-block screen-line-bytes + LOOP 2drop ; : fb8-delete-characters ( n -- ) line# fb8-line2addr column# fb8-columns2bytes + >r #columns column# - 2dup >= IF nip dup 0> IF fb8-columns2bytes r> ELSE r> 2drop EXIT THEN ELSE fb8-columns2bytes swap fb8-columns2bytes tuck - over r@ + 2dup + r> swap >r rot char-height 0 ?DO 3dup rmove -rot screen-line-bytes tuck + -rot + swap rot LOOP 3drop r> over - THEN char-height 0 ?DO dup 2 pick fb8-erase-block screen-line-bytes + LOOP 2drop ; : fb8-reset-screen ( -- ) ( Left as no-op by design ) ; : fb8-erase-screen ( -- ) frame-buffer-adr screen-height screen-line-bytes * fb8-erase-block ; : fb8-invert-screen ( -- ) frame-buffer-adr screen-height screen-line-bytes * invert-region ; : fb8-blink-screen ( -- ) fb8-invert-screen fb8-invert-screen ; : fb8-install ( width height #columns #lines -- ) 1 to screen-depth 2swap to screen-height to screen-width screen-width to screen-line-bytes screen-#rows min to #lines screen-#columns min to #columns screen-height char-height #lines * - 2/ to window-top screen-width char-width #columns * - 2/ to window-left ['] fb8-toggle-cursor to toggle-cursor ['] fb8-draw-character to draw-character ['] fb8-insert-lines to insert-lines ['] fb8-delete-lines to delete-lines ['] fb8-insert-characters to insert-characters ['] fb8-delete-characters to delete-characters ['] fb8-erase-screen to erase-screen ['] fb8-blink-screen to blink-screen ['] fb8-invert-screen to invert-screen ['] fb8-reset-screen to reset-screen ['] fb8-draw-logo to draw-logo ; : fb-install ( width height #columns #lines depth -- ) >r fb8-install r> to screen-depth screen-width screen-depth * to screen-line-bytes ; : fb8-dump-bitmap cr char-height 0 ?do char-width 0 ?do dup c@ if ." @" else ." ." then 1+ loop cr loop drop ; : fb8-dump-char >font -b swap fb8-char2bitmap fb8-dump-bitmap ; 0graphics.fs: draw-rectangle ( adr x y w h -- ) frame-buffer-adr 0= IF 4drop drop EXIT THEN 0 ?DO 4dup drop ( adr x y w adr x y ) i + screen-width * + screen-depth * ( adr x y w adr offs ) frame-buffer-adr + ( adr x y w adr fb_adr ) over 3 pick screen-depth * i * + ( adr x y w adr fb_adr src ) swap 3 pick screen-depth * ( adr x y w adr src fb_adr len ) rmove \ copy line ( adr x y w adr ) drop ( adr x y w ) LOOP 4drop ; : fill-rectangle ( col x y w h -- ) frame-buffer-adr 0= IF 4drop drop EXIT THEN 0 ?DO 4dup drop ( col x y w col x y ) i + screen-width * + screen-depth * ( col x y w col offs ) frame-buffer-adr + ( col x y w col adr ) 2 pick screen-depth * 2 pick ( col x y w col adr len col ) rfill \ draw line ( col x y w col ) drop ( col x y w ) LOOP 4drop ; : read-rectangle ( adr x y w h -- ) frame-buffer-adr 0= IF 4drop drop EXIT THEN 0 ?DO 4dup drop ( adr x y w adr x y ) i + screen-width * + screen-depth * ( adr x y w adr offs ) frame-buffer-adr + ( adr x y w adr fb_adr ) over 3 pick screen-depth * i * + ( adr x y w adr fb_adr dst ) 3 pick ( adr x y w adr fb_adr dst w ) rmove \ copy line ( adr x y w adr ) drop ( adr x y w ) LOOP 4drop ; : dimensions ( -- width height ) screen-width screen-height ; : init-default-palette 100 10 DO i i i i color! LOOP 00 00 00 0 color! 00 00 aa 1 color! 00 aa 00 2 color! 00 aa aa 3 color! aa 00 00 4 color! aa 00 aa 5 color! aa 55 00 6 color! aa aa aa 7 color! 55 55 55 8 color! 55 55 ff 9 color! 55 ff 55 a color! 55 ff ff b color! ff 55 55 c color! ff 55 ff d color! ff ff 55 e color! ff ff ff f color! ; 0generic-disk.fsnew-device set-unit ( str len ) 2dup device-name s" 0 pci-alias-" 2swap $cat evaluate s" block" device-type s" block-size" $call-parent CONSTANT block-size s" max-transfer" $call-parent CONSTANT max-transfer : read-blocks ( addr block# #blocks -- #read ) my-unit s" dev-read-blocks" $call-parent ; INSTANCE VARIABLE deblocker : open ( -- okay? ) 0 0 s" deblocker" $open-package dup deblocker ! dup IF s" disk-label" find-package IF my-args rot interpose THEN THEN 0<> ; : close ( -- ) deblocker @ close-package ; : seek ( pos.lo pos.hi -- status ) s" seek" deblocker @ $call-method ; : read ( addr len -- actual ) s" read" deblocker @ $call-method ; finish-device H 0dma-function.fs: dma-alloc ( size -- virt ) my-phandle TO calling-child s" dma-alloc" my-phandle parent $call-static 0 TO calling-child ; : dma-free ( virt size -- ) my-phandle TO calling-child s" dma-free" my-phandle parent $call-static 0 TO calling-child ; : dma-map-in ( virt size cacheable? -- devaddr ) my-phandle TO calling-child s" dma-map-in" my-phandle parent $call-static 0 TO calling-child ; : dma-map-out ( virt devaddr size -- ) my-phandle TO calling-child s" dma-map-out" my-phandle parent $call-static 0 TO calling-child ; i0pci-device.fsget-node CONSTANT my-phandle s" my-puid" my-phandle parent $call-static CONSTANT my-puid : config-b@ puid >r my-puid TO puid my-space + rtas-config-b@ r> TO puid ; : config-w@ puid >r my-puid TO puid my-space + rtas-config-w@ r> TO puid ; : config-l@ puid >r my-puid TO puid my-space + rtas-config-l@ r> TO puid ; : config-b! puid >r my-puid TO puid my-space + rtas-config-b! r> TO puid ; : config-w! puid >r my-puid TO puid my-space + rtas-config-w! r> TO puid ; : config-l! puid >r my-puid TO puid my-space + rtas-config-l! r> TO puid ; : config-dump puid >r my-puid TO puid my-space pci-dump r> TO puid ; : open puid >r \ save the old puid my-puid TO puid \ set up the puid to the devices Hostbridge pci-master-enable \ And enable Bus Master, IO and MEM access again. pci-mem-enable \ enable mem access pci-io-enable \ enable io access r> TO puid \ restore puid true ; : close puid >r \ save the old puid my-puid TO puid \ set up the puid pci-device-disable \ and disable the device r> TO puid \ restore puid ; s" dma-function.fs" included : devicefile ( -- str len ) s" pci-device_" my-space pci-vendor@ 4 int2str $cat s" _" $cat my-space pci-device@ 4 int2str $cat s" .fs" $cat ; : classfile ( -- str len ) s" pci-class_" my-space pci-class@ 10 rshift 2 int2str $cat s" .fs" $cat ; : setup ( -- ) devicefile romfs-lookup ?dup IF evaluate ELSE classfile romfs-lookup ?dup IF evaluate ELSE my-space pci-class-name type 2a emit cr my-space pci-device-generic-setup THEN THEN ; pci-device-disable pci-error-enable my-space 44 pci-out \ config-addr ascii('D') setup s0pci-bridge.fsget-node CONSTANT my-phandle s" my-puid" my-phandle parent $call-static CONSTANT my-puid pci-bus-number 1+ CONSTANT my-bus s" pci-config-bridge.fs" included s" dma-function.fs" included : filename ( -- str len ) s" pci-bridge_" my-space pci-vendor@ 4 int2str $cat s" _" $cat my-space pci-device@ 4 int2str $cat s" .fs" $cat ; : setup ( -- ) filename romfs-lookup ?dup IF evaluate ELSE my-space pci-class-name type 2a emit cr my-space pci-bridge-generic-setup my-space pci-reset-2nd THEN ; pci-device-disable pci-error-enable my-space 42 pci-out \ config-addr ascii('B') setup pci-master-enable pci-mem-enable pci-io-enable 8pci-properties.fs: pci-class-name-00 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 01 OF s" display" ENDOF dup OF s" legacy-device" ENDOF ENDCASE ; : pci-class-name-01 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" scsi" ENDOF 01 OF s" ide" ENDOF 02 OF s" fdc" ENDOF 03 OF s" ipi" ENDOF 04 OF s" raid" ENDOF 05 OF s" ata" ENDOF 06 OF s" sata" ENDOF 07 OF s" sas" ENDOF dup OF s" mass-storage" ENDOF ENDCASE ; : pci-class-name-02 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" ethernet" ENDOF 01 OF s" token-ring" ENDOF 02 OF s" fddi" ENDOF 03 OF s" atm" ENDOF 04 OF s" isdn" ENDOF 05 OF s" worldfip" ENDOF 05 OF s" picmg" ENDOF dup OF s" network" ENDOF ENDCASE ; : pci-class-name-03 ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" vga" ENDOF 0100 OF s" xga" ENDOF 0200 OF s" 3d-controller" ENDOF dup OF s" display" ENDOF ENDCASE ; : pci-class-name-04 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" video" ENDOF 01 OF s" sound" ENDOF 02 OF s" telephony" ENDOF dup OF s" multimedia-device" ENDOF ENDCASE ; : pci-class-name-05 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" memory" ENDOF 01 OF s" flash" ENDOF dup OF s" memory-controller" ENDOF ENDCASE ; : pci-class-name-06 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" host" ENDOF 01 OF s" isa" ENDOF 02 OF s" eisa" ENDOF 03 OF s" mca" ENDOF 04 OF s" pci" ENDOF 05 OF s" pcmcia" ENDOF 06 OF s" nubus" ENDOF 07 OF s" cardbus" ENDOF 08 OF s" raceway" ENDOF 09 OF s" semi-transparent-pci" ENDOF 0A OF s" infiniband" ENDOF dup OF s" unknown-bridge" ENDOF ENDCASE ; : pci-class-name-07 ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" serial" ENDOF 0100 OF s" parallel" ENDOF 0200 OF s" multiport-serial" ENDOF 0300 OF s" modem" ENDOF 0400 OF s" gpib" ENDOF 0500 OF s" smart-card" ENDOF dup OF s" communication-controller" ENDOF ENDCASE ; : pci-class-name-08 ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" interrupt-controller" ENDOF 0100 OF s" dma-controller" ENDOF 0200 OF s" timer" ENDOF 0300 OF s" rtc" ENDOF 0400 OF s" hot-plug-controller" ENDOF 0500 OF s" sd-host-controller" ENDOF dup OF s" system-peripheral" ENDOF ENDCASE ; : pci-class-name-09 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" keyboard" ENDOF 01 OF s" pen" ENDOF 02 OF s" mouse" ENDOF 03 OF s" scanner" ENDOF 04 OF s" gameport" ENDOF dup OF s" input-controller" ENDOF ENDCASE ; : pci-class-name-0A ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" dock" ENDOF dup OF s" docking-station" ENDOF ENDCASE ; : pci-class-name-0B ( addr -- str len ) pci-class@ 8 rshift FF and CASE 02 OF s" pentium" ENDOF 20 OF s" powerpc" ENDOF 30 OF s" mips" ENDOF 40 OF s" co-processor" ENDOF dup OF s" cpu" ENDOF ENDCASE ; : pci-class-name-0C ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" firewire" ENDOF 0100 OF s" access-bus" ENDOF 0200 OF s" ssa" ENDOF 0300 OF s" usb-uhci" ENDOF 0310 OF s" usb-ohci" ENDOF 0320 OF s" usb-ehci" ENDOF 0330 OF s" usb-xhci" ENDOF 0380 OF s" usb-unknown" ENDOF 03FE OF s" usb-device" ENDOF 0400 OF s" fibre-channel" ENDOF 0500 OF s" smb" ENDOF 0600 OF s" infiniband" ENDOF 0700 OF s" ipmi" ENDOF 0701 OF s" ipmi" ENDOF 0702 OF s" ipmi" ENDOF 0800 OF s" sercos" ENDOF 0900 OF s" canbus" ENDOF dup OF s" serial-bus" ENDOF ENDCASE ; : pci-class-name-0D ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" irda" ENDOF 01 OF s" consumer-ir" ENDOF 10 OF s" rf-controller" ENDOF 11 OF s" bluetooth" ENDOF 12 OF s" broadband" ENDOF dup OF s" wireless-controller" ENDOF ENDCASE ; : pci-class-name-0E ( addr -- str len ) pci-class@ 8 rshift FF and CASE dup OF s" intelligent-io" ENDOF ENDCASE ; : pci-class-name-0F ( addr -- str len ) pci-class@ 8 rshift FF and CASE 01 OF s" satellite-tv" ENDOF 02 OF s" satellite-audio" ENDOF 03 OF s" satellite-voice" ENDOF 04 OF s" satellite-data" ENDOF dup OF s" satellite-device" ENDOF ENDCASE ; : pci-class-name-10 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" network-encryption" ENDOF 01 OF s" entertainment-encryption" ENDOF dup OF s" encryption" ENDOF ENDCASE ; : pci-class-name-11 ( addr -- str len ) pci-class@ 8 rshift FF and CASE 00 OF s" dpio" ENDOF 01 OF s" counter" ENDOF 10 OF s" measurement" ENDOF 20 OF s" managment-card" ENDOF dup OF s" data-processing-controller" ENDOF ENDCASE ; : pci-class-name ( addr -- str len ) dup pci-class@ 10 rshift CASE 00 OF pci-class-name-00 ENDOF 01 OF pci-class-name-01 ENDOF 02 OF pci-class-name-02 ENDOF 03 OF pci-class-name-03 ENDOF 04 OF pci-class-name-04 ENDOF 05 OF pci-class-name-05 ENDOF 06 OF pci-class-name-06 ENDOF 07 OF pci-class-name-07 ENDOF 08 OF pci-class-name-08 ENDOF 09 OF pci-class-name-09 ENDOF 0A OF pci-class-name-0A ENDOF 0B OF pci-class-name-0B ENDOF 0C OF pci-class-name-0C ENDOF 0D OF pci-class-name-0D ENDOF 0E OF pci-class-name-0E ENDOF 0F OF pci-class-name-0F ENDOF 10 OF pci-class-name-10 ENDOF 11 OF pci-class-name-11 ENDOF dup OF drop s" unknown" ENDOF ENDCASE ; : pci-bar-size@ ( bar-addr -- bar-size ) -1 over rtas-config-l! rtas-config-l@ ; : pci-bar-size-mem@ ( bar-addr -- mem-size ) pci-bar-size@ -10 and invert 1+ FFFFFFFF and ; : pci-bar-size-io@ ( bar-addr -- io-size ) pci-bar-size@ -4 and invert 1+ FFFFFFFF and ; : pci-bar-size ( bar-addr -- bar-size-raw ) dup rtas-config-l@ swap \ fetch original Value ( bval baddr ) -1 over rtas-config-l! \ make BAR show size ( bval baddr ) dup rtas-config-l@ \ and fetch the size ( bval baddr bsize ) -rot rtas-config-l! \ restore Value ; : pci-bar-size-mem32 ( bar-addr -- bar-size ) pci-bar-size \ fetch raw size -10 and invert 1+ \ calc size FFFFFFFF and \ keep lower 32 bits ; : pci-bar-size-rom ( bar-addr -- bar-size ) pci-bar-size \ fetch raw size FFFFF800 and invert 1+ \ calc size FFFFFFFF and \ keep lower 32 bits ; : pci-bar-size-mem64 ( bar-addr -- bar-size ) dup pci-bar-size \ fetch raw size lower 32 bits swap 4 + pci-bar-size \ fetch raw size upper 32 bits 20 lshift + \ and put them together -10 and invert 1+ \ calc size ; : pci-bar-size-io ( bar-addr -- bar-size ) pci-bar-size \ fetch raw size -4 and invert 1+ \ calc size FFFFFFFF and \ keep lower 32 bits ; : pci-bar-code@ ( bar-addr -- 0|1..4|5 ) rtas-config-l@ dup \ fetch the BaseAddressRegister 1 and IF \ IO BAR ? 2 and IF 0 ELSE 1 THEN \ only '01' is valid ELSE \ Memory BAR ? F and CASE 0 OF 2 ENDOF \ Memory 32 Bit Non-Prefetchable 8 OF 3 ENDOF \ Memory 32 Bit Prefetchable 4 OF 4 ENDOF \ Memory 64 Bit Non-Prefetchable C OF 5 ENDOF \ Memory 64 Bit Prefechtable dup OF 0 ENDOF \ Not a valid BarType ENDCASE THEN ; : assign-var-align ( size align var -- al-mem ) dup >r @ \ ( size align cur-mem ) swap #aligned \ ( size al-mem ) tuck + \ ( al-mem new-mem ) r> ! \ ( al-mem ) ; : assign-var-min-align ( size min-align var -- al-mem ) >r over umax \ ( size align ) r> assign-var-align \ ( al-mem ) ; : assign-bar-value32 ( bar size var -- 4 ) over IF \ IF size > 0 >r \ | ( bar size ) pci-mem-bar-min-align \ | ( bar size min-align ) r> assign-var-min-align \ | ( bar al-mem ) set variable to next mem swap rtas-config-l! \ | ( -- ) set the bar to al-mem ELSE \ ELSE 2drop drop \ | clear stack THEN \ FI 4 \ size of the base-address-register ; : assign-io-bar-value32 ( bar size var -- 4 ) over IF \ IF size > 0 >r \ | ( bar size ) dup \ | ( bar size size-align ) r> assign-var-align \ | ( bar al-mem ) set variable to next mem swap rtas-config-l! \ | ( -- ) set the bar to al-mem ELSE \ ELSE 2drop drop \ | clear stack THEN \ FI 4 \ size of the base-address-register ; : assign-bar-value64 ( bar size var -- 8 ) over IF \ IF size > 0 >r \ | ( bar size ) pci-mem-bar-min-align \ | ( bar size min-align ) r> assign-var-min-align \ | ( bar al-mem ) set variable to next mem swap \ | ( al-mem addr ) calc config-addr of this bar 2dup rtas-config-l! \ | ( al-mem addr ) set the Lower part of the bar to al-mem 4 + swap 20 rshift \ | ( al-mem>>32 addr ) prepare the upper part of the al-mem swap rtas-config-l! \ | ( -- ) and set the upper part of the bar ELSE \ ELSE 2drop drop \ | clear stack THEN \ FI 8 \ size of the base-address-register ; : assign-mem64-bar ( bar-addr -- 8 ) dup pci-bar-size-mem64 \ fetch size pci-next-mem64 @ 0 = IF \ Check if we have 64-bit memory range pci-next-mem ELSE pci-next-mem64 THEN assign-bar-value64 \ and set it all ; : assign-mem32-bar ( bar-addr -- 4 ) dup pci-bar-size-mem32 \ fetch size pci-next-mem @ IF pci-next-mem ELSE pci-next-mmio THEN assign-bar-value32 \ and set it all ; : assign-mmio64-bar ( bar-addr -- 8 ) dup pci-bar-size-mem64 \ fetch size pci-next-mmio assign-bar-value64 \ and set it all ; : assign-mmio32-bar ( bar-addr -- 4 ) dup pci-bar-size-mem32 \ fetch size pci-next-mmio \ var to change assign-bar-value32 \ and set it all ; : assign-io-bar ( bar-addr -- 4 ) dup pci-bar-size-io \ fetch size pci-next-io \ var to change assign-io-bar-value32 \ and set it all ; : assign-rom-bar ( bar-addr -- ) dup pci-bar-size-rom \ fetch size dup IF \ IF size > 0 over >r \ | save bar addr for enable pci-next-mmio \ | var to change assign-bar-value32 \ | and set it drop \ | forget the BAR length r@ rtas-config-l@ \ | fetch BAR 1 or r> rtas-config-l! \ | and enable the ROM ELSE \ ELSE 2drop \ | clear stack THEN ; : assign-bar ( bar-addr -- reg-size ) dup pci-bar-code@ \ calc BAR type dup IF \ IF >0 CASE \ | CASE Setup the right type 1 OF assign-io-bar ENDOF \ | - set up an IO-Bar 2 OF assign-mmio32-bar ENDOF \ | - set up an 32bit MMIO-Bar 3 OF assign-mem32-bar ENDOF \ | - set up an 32bit MEM-Bar (prefetchable) 4 OF assign-mmio64-bar ENDOF \ | - set up an 64bit MMIO-Bar 5 OF assign-mem64-bar ENDOF \ | - set up an 64bit MEM-Bar (prefetchable) ENDCASE \ | ESAC ELSE \ ELSE ABORT \ | Throw an exception THEN \ FI ; : assign-all-device-bars ( configaddr -- ) 28 10 DO \ BARs start at 10 and end at 27 dup i + \ calc config-addr of the BAR assign-bar \ and set it up +LOOP \ add 4 or 8 to the index and loop 30 + assign-rom-bar \ set up the ROM if available ; : assign-all-bridge-bars ( configaddr -- ) 18 10 DO \ BARs start at 10 and end at 17 dup i + \ calc config-addr of the BAR assign-bar \ and set it up +LOOP \ add 4 or 8 to the index and loop 38 + assign-rom-bar \ set up the ROM if available ; : gen-mem64-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 8 ) dup pci-bar-size-mem64 \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch lower 32 bits ( paddr plen baddr val.lo R: size) over 4 + rtas-config-l@ \ | fetch upper 32 bits ( paddr plen baddr val.lo val.hi R: size) 20 lshift + -10 and >r \ | calc 64 bit value and save it ( paddr plen baddr R: size val ) 82000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 8 \ sizeof(BAR) = 8 Bytes ; : gen-pmem64-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 8 ) dup pci-bar-size-mem64 \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch lower 32 bits ( paddr plen baddr val.lo R: size) over 4 + rtas-config-l@ \ | fetch upper 32 bits ( paddr plen baddr val.lo val.hi R: size) 20 lshift + -10 and >r \ | calc 64 bit value and save it ( paddr plen baddr R: size val ) C3000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 8 \ sizeof(BAR) = 8 Bytes ; : gen-mem32-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 ) dup pci-bar-size-mem32 \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) -10 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) 82000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ sizeof(BAR) = 4 Bytes ; : gen-pmem32-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 ) dup pci-bar-size-mem32 \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) -10 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) C2000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ sizeof(BAR) = 4 Bytes ; : gen-io-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 ) dup pci-bar-size-io \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) -4 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) 81000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ sizeof(BAR) = 4 Bytes ; : gen-rom-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len ) dup pci-bar-size-rom \ fetch BAR Size ( paddr plen baddr bsize ) dup IF \ IF Size > 0 >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) FFFFF800 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) 82000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) r> encode-64+ \ | Encode size ( paddr plen ) ELSE \ ELSE 2drop \ | don't do anything THEN \ FI ; : pci-add-assigned-address ( prop-addr prop-len bar-addr -- prop-addr prop-len bsize ) dup pci-bar-code@ \ calc BAR type ( paddr plen baddr btype) CASE \ CASE for the BAR types ( paddr plen baddr ) 0 OF drop 4 ENDOF \ - not a valid type so do nothing 1 OF gen-io-bar-prop ENDOF \ - IO-BAR 2 OF gen-mem32-bar-prop ENDOF \ - MEM32 3 OF gen-pmem32-bar-prop ENDOF \ - MEM32 prefetchable 4 OF gen-mem64-bar-prop ENDOF \ - MEM64 5 OF gen-pmem64-bar-prop ENDOF \ - MEM64 prefetchable ENDCASE \ ESAC ( paddr plen bsize ) ; : pci-device-assigned-addresses-prop ( addr -- ) encode-start \ provide mem for property ( addr paddr plen ) 2 pick 30 + gen-rom-bar-prop \ assign the rom bar 28 10 DO \ we have 6 possible BARs 2 pick i + \ calc BAR address ( addr paddr plen bar-addr ) pci-add-assigned-address \ and generate the props for the BAR +LOOP \ increase Index by returned len s" assigned-addresses" property drop \ and write it into the device tree ; : pci-bridge-assigned-addresses-prop ( addr -- ) encode-start \ provide mem for property 2 pick 38 + gen-rom-bar-prop \ assign the rom bar 18 10 DO \ we have 2 possible BARs 2 pick i + \ ( addr paddr plen current-addr ) pci-add-assigned-address \ and generate the props for the BAR +LOOP \ increase Index by returned len s" assigned-addresses" property drop \ and write it into the device tree ; : pci-bridge-gen-range ( paddr plen base limit type -- paddr plen ) >r over - \ calc size ( paddr plen base size R:type ) dup 0< IF \ IF Size < 0 ( paddr plen base size R:type ) 2drop r> drop \ | forget values ( paddr plen ) ELSE \ ELSE 1+ swap 2swap \ | adjust stack ( size base paddr plen R:type ) r@ encode-int+ \ | Child type ( size base paddr plen R:type ) 2 pick encode-64+ \ | Child address ( size base paddr plen R:type ) r> encode-int+ \ | Parent type ( size base paddr plen ) rot encode-64+ \ | Parent address ( size paddr plen ) rot encode-64+ \ | Encode size ( paddr plen ) THEN \ FI ; : pci-bridge-gen-mmio-range ( addr prop-addr prop-len -- addr prop-addr prop-len ) 2 pick 20 + rtas-config-l@ \ fetch Value ( addr paddr plen val ) dup 0000FFF0 and 10 lshift \ calc base-address ( addr paddr plen val base ) swap 000FFFFF or \ calc limit-address ( addr paddr plen base limit ) 02000000 pci-bridge-gen-range \ and generate it ( addr paddr plen ) ; : pci-bridge-gen-mem-range ( addr prop-addr prop-len -- addr prop-addr prop-len ) 2 pick 24 + rtas-config-l@ \ fetch Value ( addr paddr plen val ) dup 000FFFFF or \ calc limit Bits 31:0 ( addr paddr plen val limit.31:0 ) swap 0000FFF0 and 10 lshift \ calc base Bits 31:0 ( addr paddr plen limit.31:0 base.31:0 ) 4 pick 28 + rtas-config-l@ \ fetch upper Basebits ( addr paddr plen limit.31:0 base.31:0 base.63:32 ) 20 lshift or swap \ and calc Base ( addr paddr plen base.63:0 limit.31:0 ) 4 pick 2C + rtas-config-l@ \ fetch upper Limitbits ( addr paddr plen base.63:0 limit.31:0 limit.63:32 ) dup -rot 20 lshift or swap \ and calc Limit ( addr paddr plen base.63:0 limit.63:0 limit.63:32 ) IF 43000000 ELSE 42000000 THEN \ 64-bit or 32-bit? ( addr paddr plen base.63:0 limit.63:0 type ) pci-bridge-gen-range \ and generate it ( addr paddr plen ) ; : pci-bridge-gen-io-range ( addr prop-addr prop-len -- addr prop-addr prop-len ) 2 pick 1C + rtas-config-l@ \ fetch Value ( addr paddr plen val ) dup 0000F000 and 00000FFF or \ calc Limit Bits 15:0 ( addr paddr plen val limit.15:0 ) swap 000000F0 and 8 lshift \ calc Base Bits 15:0 ( addr paddr plen limit.15:0 base.15:0 ) 4 pick 30 + rtas-config-l@ \ fetch upper Bits ( addr paddr plen limit.15:0 base.15:0 val ) dup FFFF and 10 lshift rot or \ calc Base ( addr paddr plen limit.15:0 val base.31:0 ) -rot FFFF0000 and or \ calc Limit ( addr paddr plen base.31:0 limit.31:0 ) 01000000 pci-bridge-gen-range \ and generate it ( addr paddr plen ) ; : pci-bridge-range-props ( addr -- ) encode-start \ provide mem for property pci-bridge-gen-mmio-range \ generate the non prefetchable Memory Entry pci-bridge-gen-mem-range \ generate the prefetchable Memory Entry pci-bridge-gen-io-range \ generate the IO Entry dup IF \ IF any space present (propsize>0) s" ranges" property \ | write it into the device tree ELSE \ ELSE s" " s" ranges" property 2drop \ | forget the properties THEN \ FI drop \ forget the address ; : pci-bridge-interrupt-map ( -- ) encode-start \ create the property ( paddr plen ) get-node child \ find the first child ( paddr plen handle ) BEGIN dup WHILE \ Loop as long as the handle is non-zero ( paddr plen handle ) dup >r >space \ Get the my-space ( paddr plen addr R: handle ) pci-gen-irq-entry \ and Encode the interrupt settings ( paddr plen R: handle) r> peer \ Get neighbour ( paddr plen handle ) REPEAT \ process next childe node ( paddr plen handle ) drop \ forget the null ( paddr plen ) s" interrupt-map" property \ and set it ( -- ) 1 encode-int s" #interrupt-cells" property \ encode the cell# f800 encode-int 0 encode-int+ 0 encode-int+ \ encode the bit mask for config addr (Dev only) 7 encode-int+ s" interrupt-map-mask" property \ encode IRQ#=7 and generate property ; : encode-mem32-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 4 ) dup pci-bar-size-mem32 \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 02000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ BAR-Len = 4 (32Bit) ; : encode-pmem32-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 4 ) dup pci-bar-size-mem32 \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 42000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ BAR-Len = 4 (32Bit) ; : encode-mem64-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 8 ) dup pci-bar-size-mem64 \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 03000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 8 \ BAR-Len = 8 (64Bit) ; : encode-pmem64-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 8 ) dup pci-bar-size-mem64 \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 43000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 8 \ BAR-Len = 8 (64Bit) ; : encode-rom-bar ( prop-addr prop-len configaddr -- prop-addr prop-len ) dup pci-bar-size-rom \ fetch raw BAR-size dup IF \ IF BAR is used >r 02000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | calc and encode the size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI ; : encode-io-bar ( prop-addr prop-len BAR-addr BAR-value -- prop-addr prop-len 4 ) dup pci-bar-size-io \ calc BAR-size ( not changing the BAR ) dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) >r 01000000 or encode-int+ \ | save size and encode BAR addr 0 encode-64+ \ | make mid and lo zero r> encode-64+ \ | encode size ELSE \ ELSE 2drop \ | don't do anything THEN \ FI 4 \ BAR-Len = 4 (32Bit) ; : encode-bar ( prop-addr prop-len bar-addr -- prop-addr prop-len bar-len ) dup pci-bar-code@ \ calc BAR type CASE \ CASE for the BAR types ( paddr plen baddr val ) 0 OF drop 4 ENDOF \ - not a valid type so do nothing 1 OF encode-io-bar ENDOF \ - IO-BAR 2 OF encode-mem32-bar ENDOF \ - MEM32 3 OF encode-pmem32-bar ENDOF \ - MEM32 prefetchable 4 OF encode-mem64-bar ENDOF \ - MEM64 5 OF encode-pmem64-bar ENDOF \ - MEM64 prefetchable ENDCASE \ ESAC ( paddr plen blen ) ; : pci-reg-props ( configaddr -- ) dup encode-int \ configuration space ( caddr paddr plen ) 0 encode-64+ \ make the rest 0 0 encode-64+ \ encode the size as 0 2 pick pci-htype@ \ fetch Header Type ( caddr paddr plen type ) 1 and IF \ IF Bridge ( caddr paddr plen ) 18 10 DO \ | loop over all BARs 2 pick i + \ | calc bar-addr ( caddr paddr plen baddr ) encode-bar \ | encode this BAR ( caddr paddr plen blen ) +LOOP \ | increase LoopIndex by the BARlen 2 pick 38 + \ | calc ROM-BAR for a bridge ( caddr paddr plen baddr ) encode-rom-bar \ | encode the ROM-BAR ( caddr paddr plen ) ELSE \ ELSE ordinary device ( caddr paddr plen ) 28 10 DO \ | loop over all BARs 2 pick i + \ | calc bar-addr ( caddr paddr plen baddr ) encode-bar \ | encode this BAR ( caddr paddr plen blen ) +LOOP \ | increase LoopIndex by the BARlen 2 pick 30 + \ | calc ROM-BAR for a device ( caddr paddr plen baddr ) encode-rom-bar \ | encode the ROM-BAR ( caddr paddr plen ) THEN \ FI ( caddr paddr plen ) s" reg" property \ and store it into the property drop ; : pci-common-props ( addr -- ) dup pci-class-name device-name dup pci-vendor@ encode-int s" vendor-id" property dup pci-device@ encode-int s" device-id" property dup pci-revision@ encode-int s" revision-id" property dup pci-class@ encode-int s" class-code" property 3 encode-int s" #address-cells" property 2 encode-int s" #size-cells" property dup pci-config-ext? IF 1 encode-int s" ibm,pci-config-space-type" property THEN dup pci-status@ dup 9 rshift 3 and encode-int s" devsel-speed" property dup 7 rshift 1 and IF 0 0 s" fast-back-to-back" property THEN dup 6 rshift 1 and IF 0 0 s" 66mhz-capable" property THEN 5 rshift 1 and IF 0 0 s" udf-supported" property THEN dup pci-cache@ ?dup IF encode-int s" cache-line-size" property THEN pci-interrupt@ ?dup IF encode-int s" interrupts" property THEN ; : pci-device-props ( addr -- ) dup pci-common-props dup pci-min-grant@ encode-int s" min-grant" property dup pci-max-lat@ encode-int s" max-latency" property dup pci-sub-device@ ?dup IF encode-int s" subsystem-id" property THEN dup pci-sub-vendor@ ?dup IF encode-int s" subsystem-vendor-id" property THEN dup pci-device-assigned-addresses-prop pci-reg-props pci-hotplug-enabled IF dup dup pci-addr2bus 8 lshift swap pci-addr2dev 3 lshift or 40000000 + encode-int s" ibm,my-drc-index" property dup dup pci-addr2bus 20 * swap pci-addr2dev + a base ! s" Slot " rot $cathex hex encode-string s" ibm,loc-code" property THEN ; : pci-bridge-props ( addr -- ) dup pci-bus@ encode-int s" primary-bus" property encode-int s" secondary-bus" property encode-int s" subordinate-bus" property dup pci-bus@ drop encode-int rot encode-int+ s" bus-range" property pci-device-slots encode-int s" slot-names" property dup pci-bridge-range-props dup pci-bridge-assigned-addresses-prop s" interrupt-map" get-node get-property IF pci-bridge-interrupt-map ELSE 2drop THEN pci-reg-props ; : pci-bridge-generic-setup ( addr -- ) pci-device-slots >r \ save the slot array on return stack dup pci-common-props \ set the common properties before scanning the bus s" pci" device-type \ the type is allways "pci" dup func-pci-bridge-probe \ find all device connected to it dup assign-all-bridge-bars \ set up all memory access BARs dup pci-set-irq-line \ set the interrupt pin dup pci-set-capabilities \ set up the capabilities pci-bridge-props \ and generate all properties r> TO pci-device-slots \ and reset the slot array ; DEFER func-pci-device-props : pci-device-generic-setup ( config-addr -- ) dup assign-all-device-bars \ calc all BARs dup pci-set-irq-line \ set the interrupt pin dup pci-set-capabilities \ set up the capabilities dup func-pci-device-props \ and generate all properties drop \ forget the config-addr ; ' pci-device-props TO func-pci-device-props x 38pci-config-bridge.fs: config-xt ( config-addr xt -- data ) puid >r \ Safe puid my-puid TO puid \ Set my-puid swap dup ffff00 AND 0= IF \ Has bus-device-function been specified? my-space OR \ No: use my-space instead THEN swap execute \ Execute the rtas-config-xx function r> TO puid \ Restore previous puid ; : config-b@ ( config-addr -- data ) ['] rtas-config-b@ config-xt ; : config-w@ ( config-addr -- data ) ['] rtas-config-w@ config-xt ; : config-l@ ( config-addr -- data ) ['] rtas-config-l@ config-xt ; : config-b! ( data config-addr -- ) ['] rtas-config-b! config-xt ; : config-w! ( data config-addr -- ) ['] rtas-config-w! config-xt ; : config-l! ( data config-addr -- ) ['] rtas-config-l! config-xt ; : config-dump puid >r my-puid TO puid my-space pci-dump r> TO puid ; : decode-unit ( addr len -- phys.lo ... phys.hi ) 2 hex-decode-unit \ decode string B lshift swap \ shift the devicenumber to the right spot 8 lshift or \ add the functionnumber my-bus 10 lshift or \ add the busnumber 0 0 rot \ make phys.lo = 0 = phys.mid ; : encode-unit ( phys.lo ... phys.hi -- unit-str unit-len ) nip nip \ forget the both zeros dup 8 rshift 7 and swap \ calc Functionnumber B rshift 1F and \ calc Devicenumber over IF \ IF Function!=0 2 hex-encode-unit \ | create string with DevNum,FnNum ELSE \ ELSE nip 1 hex-encode-unit \ | create string with only DevNum THEN \ FI ; : map-in ( phys.lo phys.mid phys.hi size -- virt ) drop nip nip ( phys.hi ) dup FF AND dup 10 28 WITHIN NOT swap 30 <> AND IF cr ." phys.hi = " . cr ABORT" map-in with illegal config space address" THEN 00FFFFFF AND \ Need only bus-dev-fn+register bits dup config-l@ ( phys.hi' bar.lo ) dup 7 AND 4 = IF \ Is it a 64-bit BAR? swap 4 + config-l@ lxjoin \ Add upper part of 64-bit BAR ELSE nip THEN F NOT AND \ Clear indicator bits translate-my-address ; : map-out ( virt size -- ) 2drop ; : dma-sync ( virt devaddr size -- ) 2drop drop ; : open true ; : close ; 0update_flash.fsfalse value flash-new : update-flash-help ( -- ) cr ." update-flash tool to flash host FW " cr ." -f : Flash from file (e.g. net:\boot_rom.bin)" cr ." -l : Flash from load-base" cr ." -d : Flash from old load base (used by drone)" cr ." -c : Flash from temp to perm" cr ." -r : Flash from perm to temp" cr ; : flash-read-temp ( -- success? ) get-flashside 1 = IF flash-addr get-load-base over flash-image-size rmove true ELSE false THEN ; : flash-read-perm ( -- success? ) get-flashside 0= IF flash-addr get-load-base over flash-image-size rmove true ELSE false THEN ; : flash-switch-side ( side -- success? ) set-flashside 0<> IF s" Cannot change flashside" type cr false ELSE true THEN ; : flash-ensure-temp ( -- success? ) get-flashside 0= IF cr ." Cannot flash perm! Switching to temp side!" 1 flash-switch-side ELSE true THEN ; : update-flash ( "text" ) get-flashside >r \ Save old flashside parse-word ( str len ) \ Parse first string drop dup c@ ( str first-char ) [char] - <> IF update-flash-help r> 2drop EXIT THEN 1+ c@ ( second-char ) CASE [char] f OF parse-word cr s" do-load" evaluate flash-ensure-temp TO flash-new ENDOF [char] l OF flash-ensure-temp ENDOF [char] d OF flash-load-base get-load-base 200000 move flash-ensure-temp ENDOF [char] c OF flash-read-temp 0= flash-new or IF ." Cannot commit temp, need to boot on temp first " cr false ELSE 0 flash-switch-side THEN ENDOF [char] r OF flash-read-perm 0= IF ." Cannot commit perm, need to boot on perm first " cr false ELSE 1 flash-switch-side THEN ENDOF dup OF false ENDOF ENDCASE 0= IF update-flash-help r> drop EXIT THEN get-load-base flash-write 0= IF ." Flash write failed !! " cr THEN r> set-flashside drop \ Restore old flashside ; 00xmodem.fs01 CONSTANT XM-SOH \ Start of header 04 CONSTANT XM-EOT \ End-of-transmission 06 CONSTANT XM-ACK \ Acknowledge 15 CONSTANT XM-NAK \ Neg. acknowledge 0 VALUE xm-retries \ Retry count 0 VALUE xm-block# : xmodem-get-byte ( timeout -- byte|-1 ) d# 1000 * 0 DO key? IF key UNLOOP EXIT THEN 1 ms LOOP -1 ; : xmodem-rx-packet ( address -- success? ) 1 xmodem-get-byte \ Get block number dup 0 < IF 2drop false EXIT \ Timeout THEN 1 xmodem-get-byte \ Get neg. block number dup 0 < IF 3drop false EXIT \ Timeout THEN rot 0 ( blk# ~blk# address chksum ) 80 0 DO 1 xmodem-get-byte dup 0 < IF ( blk# ~blk# address chksum byte ) 3drop 2drop UNLOOP FALSE EXIT THEN dup 3 pick c! ( blk# ~blk# address chksum byte ) + swap 1+ swap ( blk# ~blk# address+1 chksum' ) LOOP 0ff and 1 xmodem-get-byte <> IF 3drop FALSE EXIT THEN drop ( blk# ~blk# ) over xm-block# <> IF 2drop FALSE EXIT THEN ( blk# ~blk# ) ff xor = ; : (xmodem-load) ( address -- bytes ) 1 to xm-block# 0 to xm-retries dup BEGIN d# 10 xmodem-get-byte dup >r CASE XM-SOH OF dup xmodem-rx-packet IF XM-ACK emit 80 + ( start-addr next-addr R: rx-byte ) 0 to xm-retries \ Reset retry count xm-block# 1+ ff and to xm-block# \ Increase current block# ELSE XM-NAK emit xm-retries 1+ to xm-retries \ Increase retry count THEN ENDOF XM-EOT OF XM-ACK emit ENDOF dup OF XM-NAK emit xm-retries 1+ to xm-retries \ Increase retry count ENDOF ENDCASE r> XM-EOT = xm-retries d# 10 >= OR UNTIL ( start-address end-address ) swap - ( bytes received ) ; : xmodem-load ( -- bytes ) cr ." Waiting for start of XMODEM upload..." cr get-load-base (xmodem-load) ; 0scsi-disk.fsnew-device s" disk" device-name s" block" device-type false VALUE scsi-disk-debug? scsi-open : execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... ) " execute-scsi-command" $call-parent ; : retry-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len #retries -- ... ) " retry-scsi-command" $call-parent ; 0 INSTANCE VALUE block-size 0 INSTANCE VALUE max-transfer 0 INSTANCE VALUE max-block-num 0 INSTANCE VALUE is_cdrom INSTANCE VARIABLE deblocker CREATE scratch 100 allot CREATE cdb 10 allot : dump-scsi-error ( sense-buf sense-len stat name namelen -- ) ." SCSI-DISK: " my-self instance>path type ." ," type ." failed" cr ." SCSI-DISK: Status " dup . .status-text 0<> IF ." Sense " scsi-get-sense-data dup . .sense-text ." ASC " . ." ASCQ " . cr ELSE drop THEN ; : read-blocks ( addr block# #blocks -- #read ) scsi-disk-debug? IF ." SCSI-DISK: read-blocks " .s cr THEN 2dup + max-block-num > IF ." SCSI-DISK: Access beyond end of device ! " cr drop dup max-block-num > IF drop drop 0 EXIT THEN dup max-block-num swap - THEN dup block-size * ( addr block# #blocks len ) >r rot r> ( block# #blocks addr len ) 2swap ( addr len block# #blocks ) dup >r cdb ( addr len block# #blocks cdb ) max-block-num FFFFFFFF > IF scsi-build-read-16 ( addr len ) ELSE scsi-build-read-10 ( addr len ) THEN r> -rot ( #blocks addr len ) scsi-dir-read cdb scsi-param-size 10 retry-scsi-command dup 0<> IF " read-blocks" dump-scsi-error -65 throw ELSE drop THEN ; : write-blocks ( addr block# #blocks -- #written ) scsi-disk-debug? IF ." SCSI-DISK: write-blocks " .s cr THEN over 22 < IF ." SCSI-DISK ERROR: Write access to partition table is not allowed." cr 3drop 0 EXIT THEN 2dup + max-block-num > IF ." SCSI-DISK: Access beyond end of device ! " cr 3drop 0 EXIT THEN dup block-size * ( addr block# #blocks len ) >r rot r> ( block# #blocks addr len ) 2swap ( addr len block# #blocks ) dup >r cdb ( addr len block# #blocks cdb ) max-block-num FFFFFFFF > IF scsi-build-write-16 ELSE scsi-build-write-10 THEN r> -rot ( #blocks addr len ) scsi-dir-write cdb scsi-param-size 10 retry-scsi-command dup 0<> IF s" write-blocks" dump-scsi-error -65 throw ELSE drop THEN ; : (inquiry) ( size -- buffer | NULL ) dup cdb scsi-build-inquiry scratch swap scsi-dir-read cdb scsi-param-size 10 retry-scsi-command 0= IF scratch ELSE 2drop 0 THEN ; : inquiry ( -- buffer | NULL ) scsi-disk-debug? IF ." SCSI-DISK: inquiry " .s cr THEN d# 36 (inquiry) 0= IF 0 EXIT THEN scratch inquiry-data>add-length c@ 5 + (inquiry) ; : read-capacity ( -- blocksize #blocks ) scsi-disk-debug? IF ." SCSI-DISK: read-capacity " .s cr THEN scratch 10 erase cdb scsi-build-read-cap-10 scratch scsi-length-read-cap-10-data scsi-dir-read cdb scsi-param-size 1 retry-scsi-command dup 0<> IF " read-capacity" dump-scsi-error 0 0 EXIT THEN drop scratch scsi-get-capacity-10 1 + ; : read-capacity-16 ( -- blocksize #blocks ) scsi-disk-debug? IF ." SCSI-DISK: read-capacity-16 " .s cr THEN scratch scsi-length-read-cap-16-data erase cdb scsi-build-read-cap-16 scratch scsi-length-read-cap-16-data scsi-dir-read cdb scsi-param-size 1 retry-scsi-command dup 0<> IF " read-capacity-16" dump-scsi-error 0 0 EXIT THEN drop scratch scsi-get-capacity-16 1 + ; 100 CONSTANT test-unit-retries : test-unit-ready ( true | [ ascq asc sense-key false ] ) scsi-disk-debug? IF ." SCSI-DISK: test-unit-ready " .s cr THEN cdb scsi-build-test-unit-ready 0 0 0 cdb scsi-param-size test-unit-retries retry-scsi-command 0= IF true EXIT THEN 0= IF drop 0 0 4 false EXIT THEN scsi-get-sense-data false ; : start-stop-unit ( state# -- true | false ) scsi-disk-debug? IF ." SCSI-DISK: start-stop-unit " .s cr THEN cdb scsi-build-start-stop-unit 0 0 0 cdb scsi-param-size 10 retry-scsi-command 0= IF true ELSE 2drop false THEN ; : compare-sense ( ascq asc key ascq2 asc2 key2 -- true | false ) 3 pick = ( ascq asc key ascq2 asc2 keycmp ) swap 4 pick = ( ascq asc key ascq2 keycmp asccmp ) rot 5 pick = ( ascq asc key keycmp asccmp ascqcmp ) and and nip nip nip ; 0 CONSTANT CDROM-READY 1 CONSTANT CDROM-NOT-READY 2 CONSTANT CDROM-NO-DISK 3 CONSTANT CDROM-TRAY-OPEN 4 CONSTANT CDROM-INIT-REQUIRED 5 CONSTANT CDROM-TRAY-MAYBE-OPEN : cdrom-try-close-tray ( -- ) scsi-const-load start-stop-unit drop ; : cdrom-must-close-tray ( -- ) scsi-const-load start-stop-unit not IF ." Tray open !" cr -65 throw THEN ; : get-media-event ( -- true | false ) scsi-disk-debug? IF ." SCSI-DISK: get-media-event " .s cr THEN cdb scsi-build-get-media-event scratch scsi-length-media-event scsi-dir-read cdb scsi-param-size 1 retry-scsi-command 0= IF true ELSE 2drop false THEN ; : cdrom-status ( -- status ) test-unit-ready IF CDROM-READY EXIT THEN scsi-disk-debug? IF ." TestUnitReady sense: " 3dup . . . cr THEN 3dup 1 4 2 compare-sense IF 3drop CDROM-NOT-READY EXIT THEN get-media-event IF scratch w@ 4 >= IF scratch 2 + c@ 04 = IF scratch 5 + c@ dup 02 and 0<> IF drop 3drop CDROM-READY EXIT THEN dup 01 and 0<> IF drop 3drop CDROM-TRAY-OPEN EXIT THEN drop 3drop CDROM-NO-DISK EXIT THEN THEN THEN 3dup 2 4 2 compare-sense IF 3drop CDROM-INIT-REQUIRED EXIT THEN over 4 = over 2 = and IF 3drop CDROM-READY EXIT THEN over 3a = IF 3drop CDROM-NO-DISK EXIT THEN 3drop CDROM-TRAY-MAYBE-OPEN ; : prep-cdrom ( -- ready? ) 5 0 DO cdrom-status CASE CDROM-READY OF UNLOOP true EXIT ENDOF CDROM-NO-DISK OF ." No medium !" cr UNLOOP false EXIT ENDOF CDROM-TRAY-OPEN OF cdrom-must-close-tray ENDOF CDROM-INIT-REQUIRED OF cdrom-try-close-tray ENDOF CDROM-TRAY-MAYBE-OPEN OF cdrom-try-close-tray ENDOF ENDCASE d# 1000 ms LOOP ." Drive not ready !" cr false ; : prep-disk ( -- ready? ) test-unit-ready not IF ." SCSI-DISK: Disk not ready ! " ." Sense " dup .sense-text ." [" . ." ]" ." ASC " . ." ASCQ " . cr false EXIT THEN true ; : open ( -- true | false ) scsi-disk-debug? IF ." SCSI-DISK: open [" .s ." ] unit is " my-unit . . ." [" .s ." ]" cr THEN my-unit " set-address" $call-parent inquiry dup 0= IF drop false EXIT THEN scsi-disk-debug? IF ." ---- inquiry: ----" cr dup 100 dump cr ." ------------------" cr THEN dup inquiry-data>peripheral c@ e0 and 0 <> IF inquiry-data>peripheral c@ 7f <> IF ." SCSI-DISK: Unsupported PQ != 0" cr THEN false EXIT THEN inquiry-data>peripheral c@ CASE 5 OF true to is_cdrom ENDOF 7 OF true to is_cdrom ENDOF ENDCASE scsi-disk-debug? IF is_cdrom IF ." SCSI-DISK: device treated as CD-ROM" cr ELSE ." SCSI-DISK: device treated as disk" cr THEN THEN is_cdrom IF prep-cdrom ELSE prep-disk THEN not IF false EXIT THEN " max-transfer" $call-parent to max-transfer read-capacity to max-block-num to block-size max-block-num 100000000 = IF read-capacity-16 to max-block-num to block-size THEN max-block-num 0= block-size 0= OR IF ." SCSI-DISK: Failed to get disk capacity!" cr FALSE EXIT THEN scsi-disk-debug? IF ." Capacity: " max-block-num . ." blocks of " block-size . cr THEN 0 0 " deblocker" $open-package dup deblocker ! dup IF " disk-label" find-package IF my-args rot interpose THEN THEN 0<> ; : close ( -- ) deblocker @ close-package ; : seek ( pos.lo pos.hi -- status ) s" seek" deblocker @ $call-method ; : read ( addr len -- actual ) s" read" deblocker @ $call-method ; : write ( addr len -- actual ) s" write" deblocker @ $call-method ; scsi-close finish-device ^8scsi-host-helpers.fs: check-retry-sense? ( sense-buf sense-len -- retry? ) 8 < IF -1 EXIT THEN dup sense-data>response-code c@ 7e and 70 = IF dup sense-data>sense-key c@ e0 and IF drop -1 EXIT THEN THEN scsi-get-sense-data? IF ( ascq asc sense-key ) dup 2 < IF 3drop 0 EXIT THEN dup 2 = swap 6 = or nip nip IF 1 EXIT THEN THEN -1 ; 0 INSTANCE VALUE rcmd-buf-addr 0 INSTANCE VALUE rcmd-buf-len 0 INSTANCE VALUE rcmd-dir 0 INSTANCE VALUE rcmd-cmd-addr 0 INSTANCE VALUE rcmd-cmd-len : retry-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len #retries -- ... ) >r \ stash #retries to rcmd-cmd-len to rcmd-cmd-addr to rcmd-dir to rcmd-buf-len to rcmd-buf-addr 0 \ dummy status & sense r> \ retreive #retries ( stat #retries ) 0 DO 0<> IF 2drop THEN rcmd-buf-addr rcmd-buf-len rcmd-dir rcmd-cmd-addr rcmd-cmd-len execute-scsi-command ( [ sense-buf sense-len ] stat ) dup 0= IF LEAVE THEN dup -1 = IF LEAVE THEN dup 2 = IF ( sense-buf sense-len stat ) >r \ stash stat ( sense-buf sense len ) 2dup check-retry-sense? ( sense-buf sense-len retry? ) r> swap \ unstash stat ( sense-buf sense-len stat retry? ) CASE 0 OF 3drop 0 LEAVE ENDOF \ Swallow error, return 0 -1 OF LEAVE ENDOF \ No retry ENDCASE ELSE \ Anything other than busy -> exit dup 8 <> IF LEAVE THEN THEN a ms LOOP ; CREATE sector d# 512 allot CREATE cdb 10 allot : (inquiry) ( size -- buffer | NULL ) dup cdb scsi-build-inquiry sector swap scsi-dir-read cdb scsi-param-size 10 retry-scsi-command 0= IF sector ELSE 2drop 0 THEN ; : inquiry ( -- buffer | NULL ) d# 36 (inquiry) 0= IF 0 EXIT THEN sector inquiry-data>add-length c@ 5 + (inquiry) ; : report-luns ( -- [ sector ] true | false ) 200 cdb scsi-build-report-luns sector 200 scsi-dir-read cdb scsi-param-size 10 retry-scsi-command 0= IF sector true ELSE drop false THEN ; : make-disk-alias ( $name srplun -- ) >r 2dup r> -rot ( $name srplun $name) find-alias 0<> IF 4drop exit THEN get-node node>path 20 allot " /disk@" string-cat ( $name srplun npath npathl ) rot base @ >r hex (u.) r> base ! string-cat ( $name $diskpath ) set-alias ; l8scsi-probe-helpers.fs: wrapped-inquiry ( -- true | false ) inquiry 0= IF false EXIT THEN sector inquiry-data>peripheral c@ e0 and 0 = ; : scsi-read-lun ( addr -- lun true | false ) dup c@ C0 AND CASE 40 OF w@-be 3FFF AND TRUE ENDOF 0 OF w@-be TRUE ENDOF dup dup OF ." Unsupported LUN format = " . cr FALSE ENDOF ENDCASE ; : vscsi-report-luns ( -- array ndev ) dev-max-target 3 << alloc-mem dup 0 ( devarray devcur ndev ) dev-max-target 0 DO i 0 dev-generate-srplun (set-target) report-luns nip IF sector l@ ( devarray devcur ndev size ) sector 8 + swap ( devarray devcur ndev lunarray size ) dup 8 + dup alloc-mem ( devarray devcur ndev lunarray size size+ mem ) dup rot 0 fill ( devarray devcur ndev lunarray size mem ) dup >r swap move r> ( devarray devcur ndev mem ) dup sector l@ 3 >> 0 ?DO ( devarray devcur ndev mem memcur ) dup dup scsi-read-lun IF j swap dev-generate-srplun swap x! 8 + ELSE 2drop THEN LOOP drop rot ( devarray ndev mem devcur ) dup >r x! r> 8 + ( devarray ndev devcur ) swap 1 + ELSE dev-max-target 1 = IF 16 alloc-mem ( devarray devcur ndev mem ) dup 16 0 fill ( devarray devcur ndev mem ) dup 0 0 dev-generate-srplun swap x! ( devarray devcur ndev mem ) rot x! ( devarray ndev ) 1 + UNLOOP EXIT THEN THEN LOOP nip ; : make-media-alias ( $name srplun -- ) >r get-next-alias ?dup IF r> make-disk-alias ELSE r> drop THEN ; : scsi-find-disks ( -- ) ." SCSI: Looking for devices" cr vscsi-report-luns 0 ?DO dup x@ BEGIN dup x@ dup 0= IF drop TRUE ELSE (set-target) wrapped-inquiry IF ." " current-target (u.) type ." " sector inquiry-data>peripheral c@ CASE 0 OF ." DISK : " " disk" current-target make-media-alias ENDOF 5 OF ." CD-ROM : " " cdrom" current-target make-media-alias ENDOF 7 OF ." OPTICAL : " " cdrom" current-target make-media-alias ENDOF e OF ." RED-BLOCK: " " disk" current-target make-media-alias ENDOF dup dup OF ." ? (" . 8 emit 29 emit 5 spaces ENDOF ENDCASE sector .inquiry-text cr THEN 8 + FALSE THEN UNTIL drop 8 + LOOP drop ; TS0scsi-support.fsvocabulary scsi-words \ create new word list named 'scsi-words' also scsi-words definitions \ place next definitions into new list false value scsi-param-debug \ common debugging flag d# 0 value scsi-param-size \ length of CDB processed last h# 0 value scsi-param-control \ control word for CDBs as defined in SAM-4 d# 0 value scsi-param-errors \ counter for detected errors : scsi-inc-errors scsi-param-errors 1 + to scsi-param-errors ; 00 CONSTANT scsi-cmd-test-unit-ready STRUCT /c FIELD test-unit-ready>operation-code \ 00h 4 FIELD test-unit-ready>reserved \ unused /c FIELD test-unit-ready>control \ control byte as specified in SAM-4 CONSTANT scsi-length-test-unit-ready : scsi-build-test-unit-ready ( cdb -- ) dup scsi-length-test-unit-ready erase ( cdb ) scsi-param-control swap test-unit-ready>control c! ( ) scsi-length-test-unit-ready to scsi-param-size \ update CDB length ; a0 CONSTANT scsi-cmd-report-luns STRUCT /c FIELD report-luns>operation-code \ a0h 1 FIELD report-luns>reserved \ unused /c FIELD report-luns>select-report \ report select byte 3 FIELD report-luns>reserved2 \ unused /l FIELD report-luns>alloc-length \ report length 1 FIELD report-luns>reserved3 \ unused /c FIELD report-luns>control \ control byte CONSTANT scsi-length-report-luns : scsi-build-report-luns ( alloc-len cdb -- ) dup scsi-length-report-luns erase \ 12 bytes CDB scsi-cmd-report-luns over ( alloc-len cdb cmd cdb ) report-luns>operation-code c! ( alloc-len cdb ) scsi-param-control over report-luns>control c! ( alloc-len cdb ) report-luns>alloc-length l! \ size of Data-In Buffer scsi-length-report-luns to scsi-param-size \ update CDB length ; 03 CONSTANT scsi-cmd-request-sense STRUCT /c FIELD request-sense>operation-code \ 03h 3 FIELD request-sense>reserved \ unused /c FIELD request-sense>allocation-length \ buffer-length for data response /c FIELD request-sense>control \ control byte as specified in SAM-4 CONSTANT scsi-length-request-sense : scsi-build-request-sense ( alloc-len cdb -- ) >r ( alloc-len ) ( R: -- cdb ) r@ scsi-length-request-sense erase ( alloc-len ) scsi-cmd-request-sense r@ ( alloc-len cmd cdb ) request-sense>operation-code c! ( alloc-len ) dup d# 252 > \ buffer length too big ? IF scsi-inc-errors drop d# 252 \ replace with 252 ELSE dup d# 18 < \ allocated buffer too small ? IF scsi-inc-errors drop 0 \ reject return data THEN THEN ( alloclen ) r@ request-sense>allocation-length c! ( ) scsi-param-control r> request-sense>control c! ( alloc-len cdb ) ( R: cdb -- ) scsi-length-request-sense to scsi-param-size \ update CDB length ; 70 CONSTANT scsi-response(request-sense-0) 71 CONSTANT scsi-response(request-sense-1) STRUCT /c FIELD sense-data>response-code \ 70h (current errors) or 71h (deferred errors) /c FIELD sense-data>obsolete /c FIELD sense-data>sense-key \ D3..D0 = sense key, D7 = EndOfMedium /l FIELD sense-data>info /c FIELD sense-data>alloc-length \ <= 244 (for max size) /l FIELD sense-data>command-info /c FIELD sense-data>asc \ additional sense key /c FIELD sense-data>ascq \ additional sense key qualifier /c FIELD sense-data>unit-code 3 FIELD sense-data>key-specific /c FIELD sense-data>add-sense-bytes \ start of appended extra bytes CONSTANT scsi-length-sense-data : scsi-get-sense-data ( addr -- ascq asc sense-key ) >r ( R: -- addr ) r@ sense-data>response-code c@ 7f and 72 >= IF r@ 3 + c@ ( ascq ) r@ 2 + c@ ( ascq asc ) r> 1 + c@ 0f and ( ascq asc sense-key ) ELSE r@ sense-data>ASCQ c@ ( ascq ) r@ sense-data>ASC c@ ( ascq asc ) r> sense-data>sense-key c@ 0f and ( ascq asc sense-key ) ( R: addr -- ) THEN ; : scsi-get-sense-data? ( addr -- false | ascq asc sense-key true ) dup sense-data>response-code c@ 7e AND dup 70 = swap 72 = or \ Response code (some devices have MSB set) IF scsi-get-sense-data TRUE ELSE drop FALSE \ drop addr THEN ; : scsi-get-sense-ID? ( addr -- false | ascq asc sense-key true ) dup sense-data>response-code c@ 7e AND 70 = \ Response code (some devices have MSB set) IF scsi-get-sense-data ( ascq asc sense-key ) 10 lshift ( ascq asc sense-key16 ) swap 8 lshift or ( ascq sense-key+asc ) swap or \ 24-bit sense-ID ( sense-key+asc+ascq ) TRUE ELSE drop FALSE \ drop addr THEN ; 12 CONSTANT scsi-cmd-inquiry STRUCT /c FIELD inquiry>operation-code \ 0x12 /c FIELD inquiry>reserved \ + EVPD-Bit (vital product data) /c FIELD inquiry>page-code \ page code for vital product data (if used) /w FIELD inquiry>allocation-length \ length of Data-In-Buffer /c FIELD inquiry>control \ control byte as specified in SAM-4 CONSTANT scsi-length-inquiry : scsi-build-inquiry ( alloc-len cdb -- ) dup scsi-length-inquiry erase \ 6 bytes CDB scsi-cmd-inquiry over ( alloc-len cdb cmd cdb ) inquiry>operation-code c! ( alloc-len cdb ) scsi-param-control over inquiry>control c! ( alloc-len cdb ) inquiry>allocation-length w! \ size of Data-In Buffer scsi-length-inquiry to scsi-param-size \ update CDB length ; STRUCT /c FIELD inquiry-data>peripheral \ qualifier and device type /c FIELD inquiry-data>reserved1 /c FIELD inquiry-data>version \ supported SCSI version (1,2,3) /c FIELD inquiry-data>data-format /c FIELD inquiry-data>add-length \ total block length - 4 /c FIELD inquiry-data>flags1 /c FIELD inquiry-data>flags2 /c FIELD inquiry-data>flags3 d# 8 FIELD inquiry-data>vendor-ident \ vendor string d# 16 FIELD inquiry-data>product-ident \ device string /l FIELD inquiry-data>product-revision \ revision string d# 20 FIELD inquiry-data>vendor-specific \ optional params CONSTANT scsi-length-inquiry-data 25 CONSTANT scsi-cmd-read-capacity-10 \ command code STRUCT \ SCSI 10-byte CDB structure /c FIELD read-cap-10>operation-code /c FIELD read-cap-10>reserved1 /l FIELD read-cap-10>lba /w FIELD read-cap-10>reserved2 /c FIELD read-cap-10>reserved3 /c FIELD read-cap-10>control CONSTANT scsi-length-read-cap-10 : scsi-build-read-cap-10 ( cdb -- ) dup scsi-length-read-cap-10 erase ( cdb ) scsi-cmd-read-capacity-10 over ( cdb cmd cdb ) read-cap-10>operation-code c! ( cdb ) scsi-param-control swap read-cap-10>control c! ( ) scsi-length-read-cap-10 to scsi-param-size \ update CDB length ; STRUCT /l FIELD read-cap-10-data>max-lba /l FIELD read-cap-10-data>block-size CONSTANT scsi-length-read-cap-10-data : scsi-get-capacity-10 ( addr -- block-size #blocks ) >r ( addr -- ) ( R: -- addr ) r@ read-cap-10-data>block-size l@ ( block-size ) r> read-cap-10-data>max-lba l@ ( block-size #blocks ) ( R: addr -- ) ; 9e CONSTANT scsi-cmd-read-capacity-16 \ command code STRUCT \ SCSI 16-byte CDB structure /c FIELD read-cap-16>operation-code /c FIELD read-cap-16>service-action /l FIELD read-cap-16>lba-high /l FIELD read-cap-16>lba-low /l FIELD read-cap-16>allocation-length \ should be 32 /c FIELD read-cap-16>reserved /c FIELD read-cap-16>control CONSTANT scsi-length-read-cap-16 : scsi-build-read-cap-16 ( cdb -- ) >r r@ ( R: -- cdb ) scsi-length-read-cap-16 erase ( ) scsi-cmd-read-capacity-16 ( code ) r@ read-cap-16>operation-code c! ( ) 10 r@ read-cap-16>service-action c! d# 32 \ response size 32 bytes r@ read-cap-16>allocation-length l! ( ) scsi-param-control r> read-cap-16>control c! ( R: cdb -- ) scsi-length-read-cap-16 to scsi-param-size \ update CDB length ; STRUCT /l FIELD read-cap-16-data>max-lba-high \ upper quadlet of Max-LBA /l FIELD read-cap-16-data>max-lba-low \ lower quadlet of Max-LBA /l FIELD read-cap-16-data>block-size \ logical block length in bytes /c FIELD read-cap-16-data>protect \ type of protection (4 bits) /c FIELD read-cap-16-data>exponent \ logical blocks per physical blocks /w FIELD read-cap-16-data>lowest-aligned \ first LBA of a phsy. block 10 FIELD read-cap-16-data>reserved \ 16 reserved bytes CONSTANT scsi-length-read-cap-16-data \ results in 32 : scsi-get-capacity-16 ( addr -- block-size #blocks ) >r ( R: -- addr ) r@ read-cap-16-data>block-size l@ ( block-size ) r@ read-cap-16-data>max-lba-high l@ ( block-size #blocks-high ) d# 32 lshift ( block-size #blocks-upper ) r> read-cap-16-data>max-lba-low l@ + ( block-size #blocks ) ( R: addr -- ) ; 5a CONSTANT scsi-cmd-mode-sense-10 STRUCT /c FIELD mode-sense-10>operation-code /c FIELD mode-sense-10>res-llbaa-dbd-res /c FIELD mode-sense-10>pc-page-code \ page code + page control /c FIELD mode-sense-10>sub-page-code 3 FIELD mode-sense-10>reserved2 /w FIELD mode-sense-10>allocation-length /c FIELD mode-sense-10>control CONSTANT scsi-length-mode-sense-10 : scsi-build-mode-sense-10 ( alloc-len subpage page cdb -- ) >r ( alloc-len subpage page ) ( R: -- cdb ) r@ scsi-length-mode-sense-10 erase \ 10 bytes CDB scsi-cmd-mode-sense-10 ( alloc-len subpage page cmd ) r@ mode-sense-10>operation-code c! ( alloc-len subpage page ) 10 r@ mode-sense-10>res-llbaa-dbd-res c! \ long LBAs accepted r@ mode-sense-10>pc-page-code c! ( alloc-len subpage ) r@ mode-sense-10>sub-page-code c! ( alloc-len ) r@ mode-sense-10>allocation-length w! ( ) scsi-param-control r> mode-sense-10>control c! ( R: cdb -- ) scsi-length-mode-sense-10 to scsi-param-size \ update CDB length ; STRUCT /w FIELD mode-sense-10-data>head-length /c FIELD mode-sense-10-data>head-medium /c FIELD mode-sense-10-data>head-param /c FIELD mode-sense-10-data>head-longlba /c FIELD mode-sense-10-data>head-reserved /w FIELD mode-sense-10-data>head-descr-len CONSTANT scsi-length-mode-sense-10-data : .mode-sense-data ( addr -- ) cr dup mode-sense-10-data>head-length w@ ." Mode Length: " .d space dup mode-sense-10-data>head-medium c@ ." / Medium Type: " .d space dup mode-sense-10-data>head-longlba c@ ." / Long LBA: " .d space mode-sense-10-data>head-descr-len w@ ." / Descr. Length: " .d ; 28 CONSTANT scsi-cmd-read-10 STRUCT /c FIELD read-10>operation-code /c FIELD read-10>protect /l FIELD read-10>block-address \ logical block address (32bits) /c FIELD read-10>group /w FIELD read-10>length \ transfer length (16-bits) /c FIELD read-10>control CONSTANT scsi-length-read-10 : scsi-build-read-10 ( block# #blocks cdb -- ) >r ( block# #blocks ) ( R: -- cdb ) r@ scsi-length-read-10 erase \ 10 bytes CDB scsi-cmd-read-10 r@ read-10>operation-code c! ( block# #blocks ) r@ read-10>length w! ( block# ) r@ read-10>block-address l! ( ) scsi-param-control r> read-10>control c! ( R: cdb -- ) scsi-length-read-10 to scsi-param-size \ update CDB length ; a8 CONSTANT scsi-cmd-read-12 STRUCT /c FIELD read-12>operation-code \ code: a8 /c FIELD read-12>protect \ RDPROTECT, DPO, FUA, FUA_NV /l FIELD read-12>block-address \ lba /l FIELD read-12>length \ transfer length (32bits) /c FIELD read-12>group \ group number /c FIELD read-12>control CONSTANT scsi-length-read-12 : scsi-build-read-12 ( block# #blocks cdb -- ) >r ( block# #blocks ) ( R: -- cdb ) r@ scsi-length-read-12 erase \ 12 bytes CDB scsi-cmd-read-12 r@ read-12>operation-code c! ( block# #blocks ) r@ read-12>length l! ( block# ) r@ read-12>block-address l! ( ) scsi-param-control r> read-12>control c! ( R: cdb -- ) scsi-length-read-12 to scsi-param-size \ update CDB length ; 88 CONSTANT scsi-cmd-read-16 STRUCT /c FIELD read-16>operation-code \ code: 88 /c FIELD read-16>protect \ RDPROTECT, DPO, FUA, FUA_NV /x FIELD read-16>block-address \ lba /l FIELD read-16>length \ transfer length (32bits) /c FIELD read-16>group \ group number /c FIELD read-16>control CONSTANT scsi-length-read-16 : scsi-build-read-16 ( block# #blocks cdb -- ) >r ( block# #blocks ) ( R: -- cdb ) r@ scsi-length-read-16 erase \ 16 bytes CDB scsi-cmd-read-16 r@ read-16>operation-code c! ( block# #blocks ) r@ read-16>length l! ( block# ) r@ read-16>block-address x! ( ) scsi-param-control r> read-16>control c! ( R: cdb -- ) scsi-length-read-16 to scsi-param-size \ update CDB length ; : scsi-build-read? ( block# #blocks cdb -- length ) over ( block# #blocks cdb #blocks ) fffe > \ tx-length (#blocks) exceeds 16-bit limit ? IF scsi-build-read-12 ( block# #blocks cdb -- ) scsi-length-read-12 ( length ) ELSE ( block# #blocks cdb ) scsi-build-read-10 ( block# #blocks cdb -- ) scsi-length-read-10 ( length ) THEN ; 2A CONSTANT scsi-cmd-write-10 STRUCT /c FIELD write-10>operation-code /c FIELD write-10>protect /l FIELD write-10>block-address \ logical block address (32bits) /c FIELD write-10>group /w FIELD write-10>length \ transfer length (16-bits) /c FIELD write-10>control CONSTANT scsi-length-write-10 : scsi-build-write-10 ( block# #blocks cdb -- ) >r ( block# #blocks ) ( R: -- cdb ) r@ scsi-length-write-10 erase \ 10 bytes CDB scsi-cmd-write-10 r@ write-10>operation-code c! ( block# #blocks ) r@ write-10>length w! ( block# ) r@ write-10>block-address l! ( ) scsi-param-control r> write-10>control c! ( R: cdb -- ) scsi-length-write-10 to scsi-param-size \ update CDB length ; 8A CONSTANT scsi-cmd-write-16 STRUCT /c FIELD write-16>operation-code /c FIELD write-16>protect \ RDPROTECT, DPO, FUA, FUA_NV /x FIELD write-16>block-address \ LBA /l FIELD write-16>length \ Transfer length (32-bits) /c FIELD write-16>group \ Group number /c FIELD write-16>control CONSTANT scsi-length-write-16 : scsi-build-write-16 ( block# #blocks cdb -- ) >r ( block# #blocks ) ( R: -- cdb ) r@ scsi-length-write-16 erase \ 16 bytes CDB scsi-cmd-write-16 r@ write-16>operation-code c! ( block# #blocks ) r@ write-16>length l! ( block# ) r@ write-16>block-address x! ( ) scsi-param-control r> write-16>control c! ( R: cdb -- ) scsi-length-write-16 to scsi-param-size \ update CDB length ; 1b CONSTANT scsi-cmd-start-stop-unit STRUCT /c FIELD start-stop-unit>operation-code /c FIELD start-stop-unit>immed /w FIELD start-stop-unit>reserved /c FIELD start-stop-unit>pow-condition /c FIELD start-stop-unit>control CONSTANT scsi-length-start-stop-unit f1 CONSTANT scsi-const-active-power \ param used for start-stop-unit f2 CONSTANT scsi-const-idle-power \ param used for start-stop-unit f3 CONSTANT scsi-const-standby-power \ param used for start-stop-unit 3 CONSTANT scsi-const-load \ param used for start-stop-unit 2 CONSTANT scsi-const-eject \ param used for start-stop-unit 1 CONSTANT scsi-const-start 0 CONSTANT scsi-const-stop : scsi-build-start-stop-unit ( state# cdb -- ) >r ( state# ) ( R: -- cdb ) r@ scsi-length-start-stop-unit erase \ 6 bytes CDB scsi-cmd-start-stop-unit r@ start-stop-unit>operation-code c! dup 3 > IF 4 lshift \ shift to upper nibble THEN ( state ) r@ start-stop-unit>pow-condition c! ( ) scsi-param-control r> start-stop-unit>control c! ( R: cdb -- ) scsi-length-start-stop-unit to scsi-param-size \ update CDB length ; 2b CONSTANT scsi-cmd-seek STRUCT /c FIELD seek>operation-code /c FIELD seek>reserved1 /l FIELD seek>lba 3 FIELD seek>reserved2 /c FIELD seek>control CONSTANT scsi-length-seek : scsi-build-seek ( lba cdb -- ) >r ( lba ) ( R: -- cdb ) r@ scsi-length-seek erase \ 10 bytes CDB scsi-cmd-seek r@ seek>operation-code c! r> seek>lba l! ( ) ( R: cdb -- ) scsi-length-seek to scsi-param-size \ update CDB length ; STRUCT /w FIELD media-event-data-len /c FIELD media-event-nea-class /c FIELD media-event-supp-class /l FIELD media-event-data CONSTANT scsi-length-media-event : scsi-build-get-media-event ( cdb -- ) dup c erase ( cdb ) 4a over c! ( cdb ) 01 over 1 + c! 10 over 4 + c! 08 over 8 + c! drop ; : .sense-text ( scode -- ) case 0 OF s" OK" ENDOF 1 OF s" RECOVERED ERR" ENDOF 2 OF s" NOT READY" ENDOF 3 OF s" MEDIUM ERROR" ENDOF 4 OF s" HARDWARE ERR" ENDOF 5 OF s" ILLEGAL REQUEST" ENDOF 6 OF s" UNIT ATTENTION" ENDOF 7 OF s" DATA PROTECT" ENDOF 8 OF s" BLANK CHECK" ENDOF 9 OF s" VENDOR SPECIFIC" ENDOF a OF s" COPY ABORTED" ENDOF b OF s" ABORTED COMMAND" ENDOF d OF s" VOLUME OVERFLOW" ENDOF e OF s" MISCOMPARE" ENDOF dup OF s" UNKNOWN" ENDOF endcase 5b emit type 5d emit ; : .status-text ( stat -- ) case 00 OF s" GOOD" ENDOF 02 OF s" CHECK CONDITION" ENDOF 04 OF s" CONDITION MET" ENDOF 08 OF s" BUSY" ENDOF 18 OF s" RESERVATION CONFLICT" ENDOF 28 OF s" TASK SET FULL" ENDOF 30 OF s" ACA ACTIVE" ENDOF 40 OF s" TASK ABORTED" ENDOF dup OF s" UNKNOWN" ENDOF endcase 5b emit type 5d emit ; : .dec3-2 ( prenum postnum -- ) swap base @ >r \ save actual base setting decimal \ show decimal values 4 .r 2e emit dup 9 <= IF 30 emit THEN .d \ 3 pre-decimal, right aligned r> base ! \ restore base ; : .capacity-text ( block-size #blocks -- ) scsi-param-debug \ debugging flag set ? IF \ show additional info 2dup cr ." LBAs: " .d \ highest logical block number ." / Block-Size: " .d ." / Total Capacity: " THEN * \ calculate total capacity dup d# 1000000000000 >= \ check terabyte limit IF d# 1000000000000 /mod swap d# 10000000000 / \ limit remainder to two digits .dec3-2 ." TB" \ show terabytes as xxx.yy ELSE dup d# 1000000000 >= \ check gigabyte limit IF d# 1000000000 /mod swap d# 10000000 / .dec3-2 ." GB" \ show gigabytes as xxx.yy ELSE dup d# 1000000 >= IF d# 1000000 /mod \ check mega byte limit swap d# 10000 / .dec3-2 ." MB" \ show megabytes as xxx.yy ELSE dup d# 1000 >= \ check kilo byte limit IF d# 1000 /mod swap d# 10 / .dec3-2 ." kB" ELSE .d ." Bytes" THEN THEN THEN THEN ; : .inquiry-text ( addr -- ) 22 emit \ enclose text with " dup inquiry-data>vendor-ident 8 type space dup inquiry-data>product-ident 10 type space inquiry-data>product-revision 4 type 22 emit ; : scsi-supp-init ( -- ) false to scsi-param-debug \ no debug strings h# 0 to scsi-param-size h# 0 to scsi-param-control \ common CDB control byte d# 0 to scsi-param-errors \ local errors (param limits) ; true CONSTANT scsi-dir-read false CONSTANT scsi-dir-write 0 VALUE scsi-context \ addr of word list on top : scsi-init ( -- ) also scsi-words \ append scsi word-list context to scsi-context \ save for close process scsi-supp-init \ preset all scsi-param-xxx values scsi-param-debug IF space ." SCSI-SUPPORT OPENED" cr .wordlists THEN ; : scsi-close ( -- ) scsi-param-debug IF space ." Closing SCSI-SUPPORT .. " cr THEN context scsi-context = \ scsi word list still active ? IF scsi-param-errors 0<> \ any errors occurred ? IF cr ." ** WARNING: " scsi-param-errors .d ." SCSI Errors occurred ** " cr THEN previous \ remove scsi word list on top 0 to scsi-context \ prevent from being misinterpreted ELSE cr ." ** WARNING: Trying to close non-open SCSI-SUPPORT (1) ** " cr THEN scsi-param-debug IF .wordlists THEN ; s" scsi-init" $find drop \ return execution pointer, when included previous \ remove scsi word list from search path definitions \ place next definitions into previous list q p0evaluator.fsvariable ip variable fcode-end variable fcode-num 1 value fcode-spread 2 value fcode-offset false value eva-debug? true value fcode-debug? defer fcode-rb@ defer fcode@ ' c@ to fcode-rb@ create token-table 2000 cells allot \ 1000h = 4096d : ?offset16 ( -- true|false ) fcode-offset 2 = ; : ?arch64 ( -- true|false ) cell 8 = ; : ?bigendian ( -- true|false ) deadbeef fcode-num ! fcode-num ?arch64 IF 4 + THEN c@ de = ; : reset-fcode-end ( -- ) false fcode-end ! ; : get-ip ( -- n ) ip @ ; : set-ip ( n -- ) ip ! ; : next-ip ( -- ) get-ip 1+ set-ip ; : jump-n-ip ( n -- ) get-ip + set-ip ; : read-byte ( -- n ) get-ip fcode-rb@ ; : ?compile-mode ( -- on|off ) state @ ; : save-evaluator-state get-ip eva-debug? IF ." saved ip " dup . cr THEN fcode-end @ eva-debug? IF ." saved fcode-end " dup . cr THEN fcode-offset eva-debug? IF ." saved fcode-offset " dup . cr THEN fcode-spread eva-debug? IF ." saved fcode-spread " dup . cr THEN ['] fcode@ behavior eva-debug? IF ." saved fcode@ " dup . cr THEN ; : restore-evaluator-state eva-debug? IF ." restored fcode@ " dup . cr THEN to fcode@ eva-debug? IF ." restored fcode-spread " dup . cr THEN to fcode-spread eva-debug? IF ." restored fcode-offset " dup . cr THEN to fcode-offset eva-debug? IF ." restored fcode-end " dup . cr THEN fcode-end ! eva-debug? IF ." restored ip " dup . cr THEN set-ip ; : token-table-index ( fcode# -- addr ) cells token-table + ; : join-immediate ( xt immediate? addr -- xt+immediate? addr ) -rot + swap ; : split-immediate ( xt+immediate? -- xt immediate? ) dup 1 and 2dup - rot drop swap ; : literal, ( n -- ) postpone literal ; : fc-string, postpone sliteral dup c, bounds ?do i c@ c, loop ; : set-token ( xt immediate? fcode# -- ) token-table-index join-immediate ! ; : get-token ( fcode# -- xt immediate? ) token-table-index @ split-immediate ; ?bigendian [IF] \ Big endian access functions first : read-fcode-num16 ( -- n ) 0 fcode-num ! ?arch64 IF read-byte fcode-num 6 + C! next-ip read-byte fcode-num 7 + C! ELSE read-byte fcode-num 2 + C! next-ip read-byte fcode-num 3 + C! THEN fcode-num @ ; : read-fcode-num32 ( -- n ) 0 fcode-num ! ?arch64 IF read-byte fcode-num 4 + C! next-ip read-byte fcode-num 5 + C! next-ip read-byte fcode-num 6 + C! next-ip read-byte fcode-num 7 + C! ELSE read-byte fcode-num 0 + C! next-ip read-byte fcode-num 1 + C! next-ip read-byte fcode-num 2 + C! next-ip read-byte fcode-num 3 + C! THEN fcode-num @ ; [ELSE] \ Now the little endian access functions : read-fcode-num16 ( -- n ) 0 fcode-num ! ?arch64 IF read-byte fcode-num 7 + C! next-ip read-byte fcode-num 6 + C! ELSE read-byte fcode-num 1 + C! next-ip read-byte fcode-num 0 + C! THEN fcode-num @ ; : read-fcode-num32 ( adr -- n ) 0 fcode-num ! ?arch64 IF read-byte fcode-num 7 + C! next-ip read-byte fcode-num 6 + C! next-ip read-byte fcode-num 5 + C! next-ip read-byte fcode-num 4 + C! ELSE read-byte fcode-num 3 + C! next-ip read-byte fcode-num 2 + C! next-ip read-byte fcode-num 1 + C! next-ip read-byte fcode-num 0 + C! THEN fcode-num @ ; [THEN] : read-fcode# ( -- FCode# ) read-byte dup 01 0F between IF drop read-fcode-num16 THEN ; : read-header ( adr -- ) next-ip read-byte drop next-ip read-fcode-num16 drop next-ip read-fcode-num32 drop ; : read-fcode-string ( -- str len ) read-byte \ get string length ( -- len ) next-ip get-ip \ get string addr ( -- len str ) swap \ type needs the parameters swapped ( -- str len ) dup 1- jump-n-ip \ jump to the end of the string in FCode ; -1 VALUE break-fcode-addr 0 VALUE break-fcode-steps : evaluate-fcode ( -- ) BEGIN get-ip break-fcode-addr = IF TRUE fcode-end ! THEN fcode-end @ 0= WHILE fcode@ ( fcode# ) eva-debug? IF dup get-ip 8 u.r ." : " ." [" 3 u.r ." ] " THEN get-token 0= ?compile-mode AND IF ( xt ) compile, ELSE \ immediate or "interpretation" mode eva-debug? IF dup xt>name type space THEN execute THEN eva-debug? IF .s cr THEN break-fcode-steps IF break-fcode-steps 1- TO break-fcode-steps break-fcode-steps 0= IF TRUE fcode-end ! THEN THEN next-ip REPEAT ; : steps-fcode ( n -- ) to break-fcode-steps break-fcode-addr >r -1 to break-fcode-addr reset-fcode-end evaluate-fcode r> to break-fcode-addr ; : step-fcode ( -- ) 1 steps-fcode ; : fcode-revision ( -- n ) 00030000 \ major * 65536 + minor ; : b(lit) ( -- n ) next-ip read-fcode-num32 ?compile-mode IF literal, THEN ; : b(") next-ip read-fcode-string ?compile-mode IF fc-string, align postpone count THEN ; : b(') next-ip read-fcode# get-token drop ?compile-mode IF literal, THEN ; : ?jump-direction ( n -- ) dup 8000 >= IF 10000 - \ Create cell-sized negative value THEN fcode-offset - \ IP is already behind offset, so subtract offset size ; : ?negative 8000 and ; : dest-on-top 0 >r BEGIN dup @ 0= WHILE >r REPEAT BEGIN r> dup WHILE swap REPEAT drop ; : read-fcode-offset next-ip ?offset16 IF read-fcode-num16 ELSE read-byte dup 80 and IF FF00 or THEN \ Fake 16-bit signed offset THEN ; : b?branch ( flag -- ) ?compile-mode IF read-fcode-offset ?negative IF dest-on-top postpone until ELSE postpone if THEN ELSE ( flag ) IF fcode-offset jump-n-ip \ Skip over offset value ELSE read-fcode-offset ?jump-direction jump-n-ip THEN THEN ; immediate : bbranch ( -- ) ?compile-mode IF read-fcode-offset ?negative IF dest-on-top postpone again ELSE postpone else get-ip next-ip fcode@ B2 = IF drop ELSE set-ip THEN THEN ELSE read-fcode-offset ?jump-direction jump-n-ip THEN ; immediate : b(resolve) ( -- ) ?compile-mode IF postpone then THEN ; immediate : b(;) compile, reveal postpone [ ; immediate : b(:) ( -- ) compile, ] ; immediate : b(case) ( sel -- sel ) postpone case ; immediate : b(endcase) postpone endcase ; immediate : b(of) postpone of read-fcode-offset drop \ read and discard offset ; immediate : b(endof) postpone endof read-fcode-offset drop ; immediate : b(do) postpone do read-fcode-offset drop ; immediate : b(?do) postpone ?do read-fcode-offset drop ; immediate : b(loop) postpone loop read-fcode-offset drop ; immediate : b(+loop) postpone +loop read-fcode-offset drop ; immediate : b(leave) postpone leave ; immediate 0 VALUE fc-instance? : fc-instance ( -- ) \ Mark next defining word as instance-specific. TRUE TO fc-instance? ; : new-token \ unnamed local fcode function align here next-ip read-fcode# 0 swap set-token ; : external-token ( -- ) \ named local fcode function next-ip read-fcode-string header ( str len -- ) \ create a header in the current dictionary entry new-token ; : new-token eva-debug? IF s" x" get-ip >r next-ip read-fcode# r> set-ip (u.) $cat strdup header THEN new-token ; : named-token fcode-debug? IF external-token ELSE next-ip read-fcode-string 2drop \ Forget about the name new-token THEN ; : b(to) ( val -- ) next-ip read-fcode# get-token drop ( val xt ) dup @ ( val xt @xt ) dup = over = OR IF drop >body cell - ?compile-mode IF literal, postpone ! ELSE ! THEN ELSE <> IF ( val xt ) TRUE ABORT" Invalid destination for FCODE b(to)" THEN dup cell+ @ ( val xt @xt+1cell ) dup <> swap <> AND IF TRUE ABORT" Invalid destination for FCODE b(to)" THEN >body @ ( val instance-offset ) ?compile-mode IF literal, postpone >instance postpone ! ELSE >instance ! THEN ELSE THEN ; immediate : b(value) fc-instance? IF , \ Needed for "(instance?)" for example , (create-instance-var) FALSE TO fc-instance? ELSE , , THEN reveal ; : b(variable) fc-instance? IF , \ Needed for "(instance?)" , 0 (create-instance-var) FALSE TO fc-instance? ELSE , 0 , THEN reveal ; : b(constant) , , reveal ; : undefined-defer cr cr ." Uninitialized defer word has been executed!" cr cr true fcode-end ! ; : b(defer) fc-instance? IF , \ Needed for "(instance?)" , ['] undefined-defer (create-instance-var) reveal FALSE TO fc-instance? ELSE , reveal postpone undefined-defer THEN ; : b(create) , postpone noop reveal ; : b(field) ( E: addr -- addr+offset ) ( F: offset size -- offset+size ) , over literal, postpone + compile, reveal + ; : b(buffer:) ( E: -- a-addr) ( F: size -- ) fc-instance? IF , \ Needed for "(instance?)" , (create-instance-buf) FALSE TO fc-instance? ELSE , allot THEN reveal ; : suspend-fcode ( -- ) noop \ has to be implemented more efficiently ;-) ; : offset16 ( -- ) 2 to fcode-offset ; : version1 ( -- ) 1 to fcode-spread 1 to fcode-offset read-header ; : start0 ( -- ) 0 to fcode-spread offset16 read-header ; : start1 ( -- ) 1 to fcode-spread offset16 read-header ; : start2 ( -- ) 2 to fcode-spread offset16 read-header ; : start4 ( -- ) 4 to fcode-spread offset16 read-header ; : end0 ( -- ) true fcode-end ! ; : end1 ( -- ) end0 ; : ferror ( -- ) clear end0 cr ." FCode# " fcode-num @ . ." not assigned!" cr ." FCode evaluation aborted." cr ." ( -- S:" depth . ." R:" rdepth . ." ) " .s cr abort ; : reset-local-fcodes FFF 800 DO ['] ferror 0 i set-token LOOP ; : byte-load ( addr xt -- ) >r >r save-evaluator-state r> r> reset-fcode-end 1 to fcode-spread dup 1 = IF drop ['] rb@ THEN to fcode-rb@ set-ip reset-local-fcodes depth >r evaluate-fcode r> depth 1- <> IF clear end0 cr ." Ambiguous stack depth after byte-load!" cr ." FCode evaluation aborted." cr cr ELSE restore-evaluator-state THEN ['] c@ to fcode-rb@ ; : fc-c@ ( addr -- byte ) dup MIN-RAM-SIZE > IF rb@ ELSE c@ THEN ; : fc-w@ ( addr -- word ) dup MIN-RAM-SIZE > IF rw@ ELSE w@ THEN ; : fc-= IF 10000 - THEN ; : fc-l@ ( addr -- long ) dup MIN-RAM-SIZE > IF rl@ ELSE l@ THEN ; : fc- IF rx@ ELSE x@ THEN ; : fc-c! ( byte addr -- ) dup MIN-RAM-SIZE > IF rb! ELSE c! THEN ; : fc-w! ( word addr -- ) dup MIN-RAM-SIZE > IF rw! ELSE w! THEN ; : fc-l! ( long addr -- ) dup MIN-RAM-SIZE > IF rl! ELSE l! THEN ; : fc-x! ( dlong addr -- ) dup MIN-RAM-SIZE > IF rx! ELSE x! THEN ; : fc-fill ( add len byte -- ) 2 pick MIN-RAM-SIZE > IF rfill ELSE fill THEN ; : fc-move ( src dst len -- ) 2 pick MIN-RAM-SIZE > \ Check src 2 pick MIN-RAM-SIZE > \ Check dst OR IF rmove ELSE move THEN ; : free-virtual ( virt size -- ) s" map-out" $call-parent ; : map-low ( phys.lo ... size -- virt ) my-space swap s" map-in" $call-parent ; : mac-address ( -- mac-str mac-len ) s" local-mac-address" get-my-property IF 0 0 THEN ; VARIABLE #line 0 #line ! VARIABLE #out 0 #out ! : display-status ( n -- ) ." Device status: " . cr ; VARIABLE group-code 0 group-code ! : dma-alloc ( byte -- virtual ) s" dma-alloc" $call-parent ; : my-params ( -- addr len ) s" params" get-my-property IF 0 0 THEN ; : sbus-intr>cpu ( sbus-intr# -- cpu-intr# ) ; : intr ( interrupt# vector -- ) >r sbus-intr>cpu encode-int r> encode-int+ s" intr" property ; : driver ( addr len -- ) encode-string s" name" property ; : processor-type ( -- cpu-type ) 0 ; : firmware-version ( -- n ) 10000 \ Just a dummy value ; : fcode-version ( -- n ) fcode-revision ; : fc-abort ." FCode called abort: IP " get-ip . ( ." STACK: " .s ) depth dup 0< IF abort THEN . rdepth . cr abort ; : fc-0 ." 0(lit): STACK ( S: " depth . ." R: " rdepth . ." ): " depth 0> IF .s THEN 0 ; : fc-1 ." 1(lit): STACK ( S: " depth . ." R: " rdepth . ." ): " depth 0> IF .s THEN 1 ; : parse-1hex 1 hex-decode-unit ; : fc-set-pci-mmio-tokens ( -- ) ['] rw@-le 0 232 set-token ['] rw!-le 0 233 set-token ['] rl@-le 0 234 set-token ['] rl!-le 0 235 set-token ['] rx@-le 0 22E set-token ['] rx!-le 0 22F set-token ; : fc-set-normal-mmio-tokens ( -- ) ['] rw@ 0 232 set-token ['] rw! 0 233 set-token ['] rl@ 0 234 set-token ['] rl! 0 235 set-token ['] rx@ 0 22E set-token ['] rx! 0 22F set-token ; : reset-token-table FFF 0 DO ['] ferror 0 i set-token LOOP ; reset-token-table ' end0 0 00 set-token ' b(lit) 1 10 set-token ' b(') 1 11 set-token ' b(") 1 12 set-token ' bbranch 1 13 set-token ' b?branch 1 14 set-token ' b(loop) 1 15 set-token ' b(+loop) 1 16 set-token ' b(do) 1 17 set-token ' b(?do) 1 18 set-token ' i 0 19 set-token ' j 0 1A set-token ' b(leave) 1 1B set-token ' b(of) 1 1C set-token ' execute 0 1D set-token ' + 0 1E set-token ' - 0 1F set-token ' * 0 20 set-token ' / 0 21 set-token ' mod 0 22 set-token ' and 0 23 set-token ' or 0 24 set-token ' xor 0 25 set-token ' invert 0 26 set-token ' lshift 0 27 set-token ' rshift 0 28 set-token ' >>a 0 29 set-token ' /mod 0 2A set-token ' u/mod 0 2B set-token ' negate 0 2C set-token ' abs 0 2D set-token ' min 0 2E set-token ' max 0 2F set-token ' >r 0 30 set-token ' r> 0 31 set-token ' r@ 0 32 set-token ' exit 0 33 set-token ' 0= 0 34 set-token ' 0<> 0 35 set-token ' 0< 0 36 set-token ' 0<= 0 37 set-token ' 0> 0 38 set-token ' 0>= 0 39 set-token ' < 0 3A set-token ' > 0 3B set-token ' = 0 3C set-token ' <> 0 3D set-token ' u> 0 3E set-token ' u<= 0 3F set-token ' u< 0 40 set-token ' u>= 0 41 set-token ' >= 0 42 set-token ' <= 0 43 set-token ' between 0 44 set-token ' within 0 45 set-token ' DROP 0 46 set-token ' DUP 0 47 set-token ' OVER 0 48 set-token ' SWAP 0 49 set-token ' ROT 0 4A set-token ' -ROT 0 4B set-token ' TUCK 0 4C set-token ' nip 0 4D set-token ' pick 0 4E set-token ' roll 0 4F set-token ' ?dup 0 50 set-token ' depth 0 51 set-token ' 2drop 0 52 set-token ' 2dup 0 53 set-token ' 2over 0 54 set-token ' 2swap 0 55 set-token ' 2rot 0 56 set-token ' 2/ 0 57 set-token ' u2/ 0 58 set-token ' 2* 0 59 set-token ' /c 0 5A set-token ' /w 0 5B set-token ' /l 0 5C set-token ' /n 0 5D set-token ' ca+ 0 5E set-token ' wa+ 0 5F set-token ' la+ 0 60 set-token ' na+ 0 61 set-token ' char+ 0 62 set-token ' wa1+ 0 63 set-token ' la1+ 0 64 set-token ' cell+ 0 65 set-token ' chars 0 66 set-token ' /w* 0 67 set-token ' /l* 0 68 set-token ' cells 0 69 set-token ' on 0 6A set-token ' off 0 6B set-token ' +! 0 6C set-token ' @ 0 6D set-token ' fc-l@ 0 6E set-token ' fc-w@ 0 6F set-token ' fc- 0 85 set-token ' >body 0 86 set-token ' fcode-revision 0 87 set-token ' span 0 88 set-token ' unloop 0 89 set-token ' expect 0 8A set-token ' alloc-mem 0 8B set-token ' free-mem 0 8C set-token ' key? 0 8D set-token ' key 0 8E set-token ' emit 0 8F set-token ' type 0 90 set-token ' (cr 0 91 set-token ' cr 0 92 set-token ' #out 0 93 set-token ' #line 0 94 set-token ' hold 0 95 set-token ' <# 0 96 set-token ' u#> 0 97 set-token ' sign 0 98 set-token ' u# 0 99 set-token ' u#s 0 9A set-token ' u. 0 9B set-token ' u.r 0 9C set-token ' . 0 9D set-token ' .r 0 9E set-token ' .s 0 9F set-token ' base 0 A0 set-token ' $number 0 A2 set-token ' digit 0 A3 set-token ' -1 0 A4 set-token ' 0 0 A5 set-token ' 1 0 A6 set-token ' 2 0 A7 set-token ' 3 0 A8 set-token ' bl 0 A9 set-token ' bs 0 AA set-token ' bell 0 AB set-token ' bounds 0 AC set-token ' here 0 AD set-token ' aligned 0 AE set-token ' wbsplit 0 AF set-token ' bwjoin 0 B0 set-token ' b(resolve) 1 B2 set-token ' new-token 0 B5 set-token ' named-token 0 B6 set-token ' b(:) 1 B7 set-token ' b(value) 1 B8 set-token ' b(variable) 1 B9 set-token ' b(constant) 1 BA set-token ' b(create) 1 BB set-token ' b(defer) 1 BC set-token ' b(buffer:) 1 BD set-token ' b(field) 1 BE set-token ' fc-instance 1 C0 set-token ' b(;) 1 C2 set-token ' b(to) 1 C3 set-token ' b(case) 1 C4 set-token ' b(endcase) 1 C5 set-token ' b(endof) 1 C6 set-token ' # 0 C7 set-token ' #s 0 C8 set-token ' #> 0 C9 set-token ' external-token 0 CA set-token ' $find 0 CB set-token ' offset16 0 CC set-token ' evaluate 0 CD set-token ' c, 0 D0 set-token ' w, 0 D1 set-token ' l, 0 D2 set-token ' , 0 D3 set-token ' um* 0 D4 set-token ' um/mod 0 D5 set-token ' d+ 0 D8 set-token ' d- 0 D9 set-token ' get-token 0 DA set-token ' set-token 0 DB set-token ' state 0 DC set-token \ possibly broken ' compile, 0 DD set-token ' behavior 0 DE set-token ' start0 0 F0 set-token ' start1 0 F1 set-token ' start2 0 F2 set-token ' start4 0 F3 set-token ' ferror 0 FC set-token ' version1 0 FD set-token ' end1 0 FF set-token ' dma-alloc 0 101 set-token \ Obsolete ' my-address 0 102 set-token ' my-space 0 103 set-token ' free-virtual 0 105 set-token ' my-params 0 10f set-token \ Obsolete ' property 0 110 set-token ' encode-int 0 111 set-token ' encode+ 0 112 set-token ' encode-phys 0 113 set-token ' encode-string 0 114 set-token ' encode-bytes 0 115 set-token ' reg 0 116 set-token ' intr 0 117 set-token \ Obsolete ' driver 0 118 set-token \ Obsolete ' model 0 119 set-token ' device-type 0 11A set-token ' parse-2int 0 11B set-token ' is-install 0 11C set-token \ for framebuffer code ' is-remove 0 11D set-token \ for framebuffer code ' is-selftest 0 11E set-token \ for framebuffer code ' new-device 0 11F set-token ' diagnostic-mode? 0 120 set-token ' display-status 0 121 set-token \ Maybe obsolete ' memory-test-suite 0 122 set-token ' group-code 0 123 set-token \ Obsolete ' mask 0 124 set-token ' get-msecs 0 125 set-token ' ms 0 126 set-token ' finish-device 0 127 set-token ' decode-phys 0 128 set-token ' interpose 0 12B set-token \ Recommended practice: Interposition ' map-low 0 130 set-token ' sbus-intr>cpu 0 131 set-token \ Obsolete ' #lines 0 150 set-token ' #columns 0 151 set-token ' line# 0 152 set-token ' column# 0 153 set-token ' inverse? 0 154 set-token ' inverse-screen? 0 155 set-token ' draw-character 0 157 set-token ' reset-screen 0 158 set-token ' toggle-cursor 0 159 set-token ' erase-screen 0 15A set-token ' blink-screen 0 15B set-token ' invert-screen 0 15C set-token ' insert-characters 0 15D set-token ' delete-characters 0 15E set-token ' insert-lines 0 15F set-token ' delete-lines 0 160 set-token ' draw-logo 0 161 set-token ' frame-buffer-adr 0 162 set-token ' screen-height 0 163 set-token ' screen-width 0 164 set-token ' window-top 0 165 set-token ' window-left 0 166 set-token ' default-font 0 16A set-token ' set-font 0 16B set-token ' char-height 0 16C set-token ' char-width 0 16D set-token ' >font 0 16E set-token ' fontbytes 0 16F set-token ' fb8-draw-character 0 180 set-token ' fb8-reset-screen 0 181 set-token ' fb8-toggle-cursor 0 182 set-token ' fb8-erase-screen 0 183 set-token ' fb8-blink-screen 0 184 set-token ' fb8-invert-screen 0 185 set-token ' fb8-insert-characters 0 186 set-token ' fb8-delete-characters 0 187 set-token ' fb8-insert-lines 0 188 set-token ' fb8-delete-lines 0 189 set-token ' fb8-draw-logo 0 18A set-token ' fb8-install 0 18B set-token ' mac-address 0 1A4 set-token ' device-name 0 201 set-token ' my-args 0 202 set-token ' my-self 0 203 set-token ' find-package 0 204 set-token ' open-package 0 205 set-token ' close-package 0 206 set-token ' find-method 0 207 set-token ' call-package 0 208 set-token ' $call-parent 0 209 set-token ' my-parent 0 20A set-token ' ihandle>phandle 0 20B set-token ' my-unit 0 20D set-token ' $call-method 0 20E set-token ' $open-package 0 20F set-token ' processor-type 0 210 set-token \ Obsolete ' firmware-version 0 211 set-token \ Obsolete ' fcode-version 0 212 set-token \ Obsolete ' (is-user-word) 0 214 set-token ' suspend-fcode 0 215 set-token ' fc-abort 0 216 set-token ' catch 0 217 set-token ' throw 0 218 set-token ' get-my-property 0 21A set-token ' decode-int 0 21B set-token ' decode-string 0 21C set-token ' get-inherited-property 0 21D set-token ' delete-property 0 21E set-token ' get-package-property 0 21F set-token ' cpeek 0 220 set-token ' wpeek 0 221 set-token ' lpeek 0 222 set-token ' cpoke 0 223 set-token ' wpoke 0 224 set-token ' lpoke 0 225 set-token ' lwflip 0 226 set-token ' lbflip 0 227 set-token ' lbflips 0 228 set-token ' rb@ 0 230 set-token ' rb! 0 231 set-token fc-set-normal-mmio-tokens \ Set rw@, rw!, rl@, rl!, rx@ and rx! ' wbflips 0 236 set-token ' lwflips 0 237 set-token ' child 0 23B set-token ' peer 0 23C set-token ' next-property 0 23D set-token ' byte-load 0 23E set-token ' set-args 0 23F set-token ' left-parse-string 0 240 set-token ' bxjoin 0 241 set-token ' fc- ABORT" Locals stack exceeded!" ?dup IF ( ... n ) 1 swap DO i fc-local! \ Store pre-initialized locals -1 +LOOP THEN ; : fc-push-locals ( n -- ) uses-locals? ABORT" Definition pushes locals multiple times!" true TO uses-locals? ( n ) ['] literal execute ['] (fc-push-locals) compile, ; : fc-push-0-locals 0 fc-push-locals ; : fc-push-1-locals 1 fc-push-locals ; : fc-push-2-locals 2 fc-push-locals ; : fc-push-3-locals 3 fc-push-locals ; : fc-push-4-locals 4 fc-push-locals ; : fc-push-5-locals 5 fc-push-locals ; : fc-push-6-locals 6 fc-push-locals ; : fc-push-7-locals 7 fc-push-locals ; : fc-push-8-locals 8 fc-push-locals ; : fc-pop-locals ( -- ) localsstack 8 cells - TO localsstack localsstack localsstackbuf - 0 < ABORT" Locals stack undeflow!" ; : fc-locals-exit uses-locals? IF ['] fc-pop-locals compile, THEN ['] exit compile, ; : fc-locals-b(;) uses-locals? IF ['] fc-pop-locals compile, THEN false TO uses-locals? ['] b(;) execute ; : fc-set-locals-tokens ( -- ) ['] fc-push-0-locals 1 407 set-token ['] fc-push-1-locals 1 408 set-token ['] fc-push-2-locals 1 409 set-token ['] fc-push-3-locals 1 40a set-token ['] fc-push-4-locals 1 40b set-token ['] fc-push-5-locals 1 40c set-token ['] fc-push-6-locals 1 40d set-token ['] fc-push-7-locals 1 40e set-token ['] fc-push-8-locals 1 40f set-token ['] fc-local-1-@ 0 410 set-token ['] fc-local-2-@ 0 411 set-token ['] fc-local-3-@ 0 412 set-token ['] fc-local-4-@ 0 413 set-token ['] fc-local-5-@ 0 414 set-token ['] fc-local-6-@ 0 415 set-token ['] fc-local-7-@ 0 416 set-token ['] fc-local-8-@ 0 417 set-token ['] fc-local-1-! 0 418 set-token ['] fc-local-2-! 0 419 set-token ['] fc-local-3-! 0 41a set-token ['] fc-local-4-! 0 41b set-token ['] fc-local-5-! 0 41c set-token ['] fc-local-6-! 0 41d set-token ['] fc-local-7-! 0 41e set-token ['] fc-local-8-! 0 41f set-token ['] fc-locals-exit 1 33 set-token ['] fc-locals-b(;) 1 c2 set-token ; fc-set-locals-tokens 0 value buff 0 value buff-size ' read-fcode# to fcode@ : execute-rom-fcode ( addr len | false -- ) reset-fcode-end ?dup IF diagnostic-mode? IF ." , executing ..." cr THEN dup >r r@ alloc-mem dup >r swap rmove r@ set-ip evaluate-fcode diagnostic-mode? IF ." Done." cr THEN r> r> free-mem THEN ; : rom-code-ignored ( image-addr name len -- image-addr ) diagnostic-mode? IF type ." code found in image " dup . ." , ignoring ..." cr ELSE 2drop THEN ; : pci-find-rom ( baseaddr -- addr ) dup IF dup rw@-le aa55 = IF diagnostic-mode? IF ." Device ROM header found at " dup . cr THEN ELSE drop 0 THEN THEN ; : pci-find-fcode ( baseaddr -- addr len | false ) BEGIN 1ff NOT and \ Image must start at 512 byte boundary pci-find-rom dup WHILE dup 18 + rw@-le + ( pcir-addr ) dup rw@-le 4350 ( 'PC' ) <> ( pcir-addr hasPC? ) over 2+ rw@-le 5249 ( 'IR' ) <> OR IF diagnostic-mode? IF ." Invalid PCI Data structure, ignoring ROM contents" cr THEN drop false EXIT THEN ( pcir-addr ) dup 14 + rb@ CASE \ Get image code type 0 OF s" Intel x86 BIOS" rom-code-ignored ENDOF 1 OF diagnostic-mode? IF ." Open Firmware FCode found in image at " dup . cr THEN dup 1ff NOT AND \ Back to the ROM image header dup 2+ rw@-le + \ Pointer to FCODE (PCI bus binding ch.9) swap 10 + rw@-le 200 * \ Image length EXIT ENDOF 2 OF s" HP PA RISC" rom-code-ignored ENDOF 3 OF s" EFI" rom-code-ignored ENDOF dup OF s" Unknown type" rom-code-ignored ENDOF ENDCASE dup 15 + rb@ 80 and IF \ End of last image? drop false EXIT THEN dup 10 + rw@-le 200 * + \ Next image start REPEAT ; : pci-execute-fcode ( baseaddr -- ) pci-find-fcode dup 0= IF 2drop EXIT THEN ( addr len ) fc-set-pci-mmio-tokens \ Prepare PCI access functions ['] execute-rom-fcode CATCH IF cr ." FCODE failed!" cr 2drop THEN fc-set-normal-mmio-tokens \ Restore normal MMIO access functions ; @8default-font.bin(($$~$$~$$*(( *0H0 0@  8DD@"THT" |(||00 @8DDDDDDDD88DD @x8DD8@@@HH~~@@@xx @@@xDDD8~B 8DDD8DDDD88DDD<D800000000 @ @@ ~~  "$BNRN@@$$$$~BBBB|BBB||BBB|<"`@@@@`"<xDBBBBBBDx~@@@~~@@@~~@@@~~@@@@r my-puid TO puid rtas-config-b@ r> TO puid ; : config-w@ puid >r my-puid TO puid rtas-config-w@ r> TO puid ; : config-l@ puid >r my-puid TO puid rtas-config-l@ r> TO puid ; : config-b! puid >r my-puid TO puid rtas-config-b! r> TO puid ; : config-w! puid >r my-puid TO puid rtas-config-w! r> TO puid ; : config-l! puid >r my-puid TO puid rtas-config-l! r> TO puid ; : map-in ( phys.lo phys.mid phys.hi size -- virt ) phb-debug? IF cr ." map-in called: " .s cr THEN drop nip nip ( phys.hi ) dup FF AND dup 10 28 WITHIN NOT swap 30 <> AND IF cr ." phys.hi = " . cr ABORT" map-in with illegal config space address" THEN 00FFFFFF AND \ Need only bus-dev-fn+register bits dup config-l@ ( phys.hi' bar.lo ) dup 7 AND 4 = IF \ Is it a 64-bit BAR? swap 4 + config-l@ lxjoin \ Add upper part of 64-bit BAR ELSE nip THEN F NOT AND \ Clear indicator bits translate-my-address phb-debug? IF ." map-in done: " .s cr THEN ; : map-out ( virt size -- ) phb-debug? IF ." map-out called: " .s cr THEN 2drop ; : dma-alloc ( size -- virt ) phb-debug? IF cr ." dma-alloc called: " .s cr THEN fff + fff not and \ Align size to next 4k boundary alloc-mem dup fff and IF ." Warning: dma-alloc got unaligned memory!" cr THEN ; : dma-free ( virt size -- ) phb-debug? IF cr ." dma-free called: " .s cr THEN fff + fff not and \ Align size to next 4k boundary free-mem ; 0 VALUE dma-window-liobn \ Logical I/O bus number 0 VALUE dma-window-base \ Start address of window 0 VALUE dma-window-size \ Size of the window 0 VALUE bm-handle \ Bitmap allocator handle 0 VALUE my-virt 0 VALUE my-size 0 VALUE dev-addr 0 VALUE tmp-dev-addr : (init-dma-window-vars) ( -- ) s" ibm,dma-window" calling-child get-property IF s" ibm,dma-window" calling-child parent get-property ABORT" no dma-window property available" THEN decode-int TO dma-window-liobn decode-64 TO dma-window-base decode-64 TO dma-window-size 2drop bm-handle 0= IF dma-window-base dma-window-size 1000 bm-allocator-init to bm-handle dma-window-base 0= IF bm-handle 1000 bm-alloc drop THEN THEN ; : (clear-dma-window-vars) ( -- ) 0 TO dma-window-liobn 0 TO dma-window-base 0 TO dma-window-size ; : dma-virt2dev ( virt -- devaddr ) dma-window-size mod dma-window-base + ; : dma-map-in ( virt size cachable? -- devaddr ) phb-debug? IF cr ." dma-map-in called: " .s cr THEN (init-dma-window-vars) drop ( virt size ) to my-size to my-virt bm-handle my-size bm-alloc to dev-addr dev-addr 0 < IF ." Bitmap allocation Failed " dev-addr . FALSE EXIT THEN dev-addr to tmp-dev-addr my-virt my-size bounds dup >r ( v+s virt R: virt ) swap fff + fff not and \ Align end to next 4k boundary swap fff not and ( v+s' virt' R: virt ) ?DO dma-window-liobn \ liobn tmp-dev-addr \ ioba i 3 OR \ Make a read- & writeable TCE hv-put-tce ABORT" H_PUT_TCE failed" tmp-dev-addr 1000 + to tmp-dev-addr 1000 +LOOP r> drop my-virt FFF and dev-addr or (clear-dma-window-vars) ; : dma-map-out ( virt devaddr size -- ) phb-debug? IF cr ." dma-map-out called: " .s cr THEN (init-dma-window-vars) to my-size to dev-addr to my-virt dev-addr fff not and to dev-addr dev-addr to tmp-dev-addr my-virt my-size ( virt size ) bounds ( v+s virt ) swap fff + fff not and \ Align end to next 4k boundary swap fff not and ( v+s' virt' ) ?DO dma-window-liobn \ liobn tmp-dev-addr \ ioba i \ Lowest bits not set => invalid TCE hv-put-tce ABORT" H_PUT_TCE failed" tmp-dev-addr 1000 + to tmp-dev-addr 1000 +LOOP bm-handle dev-addr my-size bm-free (clear-dma-window-vars) ; : dma-sync ( virt devaddr size -- ) phb-debug? IF cr ." dma-sync called: " .s cr THEN 3drop ; : open true ; : close ; : phb-parse-ranges ( -- ) 0 pci-next-io ! 0 pci-max-io ! 0 pci-next-mem ! 0 pci-max-mem ! 0 pci-next-mmio ! 0 pci-max-mmio ! 0 pci-next-mem64 ! 0 pci-max-mem64 ! s" ranges" get-node get-property 0<> ABORT" ranges property not found" BEGIN dup WHILE decode-int \ Decode phys.hi 3000000 AND \ Filter out address space in phys.hi CASE 1000000 OF \ I/O space? decode-64 dup >r pci-next-io ! \ Decode PCI base address decode-64 drop \ Forget the parent address decode-64 r> + pci-max-io ! \ Decode size & calc max address pci-next-io @ 0= IF pci-next-io @ 10 + pci-next-io ! \ BARs must not be set to zero THEN ENDOF 2000000 OF \ 32-bit memory space? decode-64 dup >r pci-next-mmio ! \ Decode base address decode-64 drop \ Forget the parent address decode-64 r> + pci-max-mmio ! \ calc max MMIO address ENDOF 3000000 OF \ 64-bit memory space? decode-64 dup >r pci-next-mem64 ! decode-64 drop \ Forget the parent address decode-64 r> + pci-max-mem64 ! ENDOF ENDCASE REPEAT 2drop pci-next-mem64 @ 0= IF pci-next-mmio @ pci-next-mem ! \ Start of 32-bit prefetchable pci-max-mmio @ pci-next-mmio @ - 2 / \ Calculate new size pci-next-mmio @ + \ The middle of the area dup pci-max-mem ! pci-next-mmio ! THEN phb-debug? IF pci-var-out THEN ; : phb-pci-walk-bridge ( -- ) phb-debug? IF ." Calling pci-walk-bridge " pwd cr THEN get-node child ?dup 0= IF EXIT THEN \ get and check if we have children 0 to pci-device-slots \ reset slot array to unpoppulated BEGIN dup \ Continue as long as there are children WHILE dup set-node \ Set child node as current node my-space pci-set-slot \ set the slot bit my-space pci-htype@ \ read HEADER-Type 7f and \ Mask bit 7 - multifunction device CASE 0 OF my-space pci-device-setup ENDOF \ | set up the device 1 OF my-space pci-bridge-setup ENDOF \ | set up the bridge dup OF my-space [char] ? pci-out ENDOF ENDCASE peer REPEAT drop get-parent set-node ; : phb-pci-bridge-probe ( addr -- ) dup pci-bridge-set-bases \ Set up all Base Registers dup func-pci-bridge-range-props \ Set up temporary "range" my-space pci-bus-scnd@ TO pci-bus-number \ Set correct current bus number pci-device-vec-len 1+ TO pci-device-vec-len \ increase the device-slot vector depth pci-enable \ enable mem/IO transactions phb-pci-walk-bridge \ and walk the secondary bus pci-device-vec-len 1- TO pci-device-vec-len \ decrease the device-slot vector depth pci-bridge-set-limits \ Set up all Limit Registers ; : phb-pci-device-props ( addr -- ) dup pci-class-name device-name dup pci-device-assigned-addresses-prop drop ; : phb-setup-children puid >r \ Save old value of puid my-puid TO puid \ Set current puid phb-parse-ranges 1 TO pci-hotplug-enabled s" qemu,mem-bar-min-align" get-node get-property 0= IF decode-int TO pci-mem-bar-min-align 2drop ELSE 10000 TO pci-mem-bar-min-align THEN s" qemu,phb-enumerated" get-node get-property 0<> IF 1 0 (probe-pci-host-bridge) ELSE 2drop ['] phb-pci-bridge-probe TO func-pci-bridge-probe ['] phb-pci-device-props TO func-pci-device-props phb-pci-walk-bridge \ PHB device tree is already populated. THEN r> TO puid \ Restore previous puid ; phb-setup-children 0 (rtas.fs371 cp STRUCT /l field rtas>token /l field rtas>nargs /l field rtas>nret /l field rtas>args0 /l field rtas>args1 /l field rtas>args2 /l field rtas>args3 /l field rtas>args4 /l field rtas>args5 /l field rtas>args6 /l field rtas>args7 /l C * field rtas>args /l field rtas>bla CONSTANT /rtas-control-block CREATE rtas-cb /rtas-control-block allot rtas-cb /rtas-control-block erase 0 VALUE rtas-base 0 VALUE rtas-size 0 VALUE rtas-node s" /rtas" find-node to rtas-node 373 cp : enter-rtas ( -- ) rtas-cb rtas-base 0 rtas-base call-c drop ; : rtas-get-token ( str len -- token | 0 ) rtas-node get-package-property IF 0 ELSE drop l@ THEN ; : rtas-power-off ( x y -- status ) [ s" power-off" rtas-get-token ] LITERAL rtas-cb rtas>token l! 2 rtas-cb rtas>nargs l! 1 rtas-cb rtas>nret l! rtas-cb rtas>args0 l! rtas-cb rtas>args1 l! enter-rtas rtas-cb rtas>args2 l@ ; : power-off ( -- ) 0 0 rtas-power-off ; : rtas-system-reboot ( -- status ) [ s" system-reboot" rtas-get-token ] LITERAL rtas-cb rtas>token l! 0 rtas-cb rtas>nargs l! 1 rtas-cb rtas>nret l! rtas-cb rtas>args0 l! enter-rtas rtas-cb rtas>args1 l@ ; : rtas-start-cpu ( pid loc r3 -- status ) [ s" start-cpu" rtas-get-token ] LITERAL rtas-cb rtas>token l! 3 rtas-cb rtas>nargs l! 1 rtas-cb rtas>nret l! rtas-cb rtas>args2 l! rtas-cb rtas>args1 l! rtas-cb rtas>args0 l! 0 rtas-cb rtas>args3 l! enter-rtas rtas-cb rtas>args3 l@ ; : rtas-set-tce-bypass ( unit enable -- ) " ibm,set-tce-bypass" rtas-get-token rtas-cb rtas>token l! 2 rtas-cb rtas>nargs l! 0 rtas-cb rtas>nret l! rtas-cb rtas>args1 l! rtas-cb rtas>args0 l! enter-rtas ; : rtas-quiesce ( -- ) fdt-flatten-tree dup hv-update-dt ?dup IF dup -2 <> IF ." HV-UPDATE-DT error: " . cr ELSE drop THEN THEN fdt-flatten-tree-free " quiesce" rtas-get-token rtas-cb rtas>token l! 0 rtas-cb rtas>nargs l! 0 rtas-cb rtas>nret l! enter-rtas ; 0 value puid : rtas-do-config-@ ( config-addr size -- value) [ s" ibm,read-pci-config" rtas-get-token ] LITERAL rtas-cb rtas>token l! 4 rtas-cb rtas>nargs l! 2 rtas-cb rtas>nret l! ( addr size ) rtas-cb rtas>args3 l! puid rtas-cb rtas>args2 l! puid 20 rshift rtas-cb rtas>args1 l! ( addr ) rtas-cb rtas>args0 l! enter-rtas rtas-cb rtas>args4 l@ dup IF drop ffffffff ELSE drop rtas-cb rtas>args5 l@ THEN ; : rtas-do-config-! ( value config-addr size ) [ s" ibm,write-pci-config" rtas-get-token ] LITERAL rtas-cb rtas>token l! 5 rtas-cb rtas>nargs l! 1 rtas-cb rtas>nret l! ( value addr size ) rtas-cb rtas>args3 l! puid rtas-cb rtas>args2 l! puid 20 rshift rtas-cb rtas>args1 l! ( value addr ) rtas-cb rtas>args0 l! ( value ) rtas-cb rtas>args4 l! enter-rtas rtas-cb rtas>args5 l@ dup IF ." RTAS write config err " . cr ELSE drop THEN ; : rtas-config-b@ ( config-addr -- value ) 1 rtas-do-config-@ ff and ; : rtas-config-b! ( value config-addr -- ) 1 rtas-do-config-! ; : rtas-config-w@ ( config-addr -- value ) 2 rtas-do-config-@ ffff and ; : rtas-config-w! ( value config-addr -- ) 2 rtas-do-config-! ; : rtas-config-l@ ( config-addr -- value ) 4 rtas-do-config-@ ffffffff and ; : rtas-config-l! ( value config-addr -- ) 4 rtas-do-config-! ; : of-start-cpu rtas-start-cpu ; ' power-off to halt ' rtas-system-reboot to reboot rtas-node set-node : open true ; : close ; : store-rtas-loc ( adr ) s" /rtas" find-node >r encode-int s" slof,rtas-base" r@ set-property rtas-size encode-int s" slof,rtas-size" r> set-property ; : instantiate-rtas ( adr -- entry ) dup store-rtas-loc dup rtas-base swap rtas-size move ; hv-rtas-get dup encode-int s" rtas-size" s" /rtas" find-node set-property to rtas-size to rtas-base device-end 374 cp p)8pci-device_1234_1111.fs." qemu vga" cr s" qemu-vga.fs" included 88pci-device_1013_00b8.fsmy-space pci-device-generic-setup d# 800 VALUE disp-width d# 600 VALUE disp-height d# 8 VALUE disp-depth 10 config-l@ translate-my-address f not AND VALUE fb-base -1 VALUE io-base false VALUE is-installed? : vga-io-xlate ( port -- addr ) io-base -1 = IF dup translate-my-address fff not and to io-base THEN io-base + ; : vga-w! ( value port -- ) vga-io-xlate rw!-le ; : vga-w@ ( port -- value ) vga-io-xlate rw@-le ; : vga-b! ( value port -- ) vga-io-xlate rb! ; : vga-b@ ( port -- value ) vga-io-xlate rb@ ; : vga-crt@ ( index -- value ) 3d4 vga-b! 3d5 vga-b@ ; : vga-crt! ( value index -- ) 3d4 vga-b! 3d5 vga-b! ; : vga-seq@ ( index -- value ) 3c4 vga-b! 3c5 vga-b@ ; : vga-seq! ( value index -- ) 3c4 vga-b! 3c5 vga-b! ; : vga-att@ ( index -- value ) 3c0 vga-b! 3c1 vga-b@ ; : vga-att! ( value index -- ) 3c0 vga-b! 3c0 vga-b! ; : vga-gfx@ ( index -- value ) 3ce vga-b! 3cf vga-b@ ; : vga-gfx! ( value index -- ) 3ce vga-b! 3cf vga-b! ; : color! ( r g b number -- ) 3c8 vga-b! rot 2 >> 3c9 vga-b! swap 2 >> 3c9 vga-b! 2 >> 3c9 vga-b! ; : color@ ( number -- r g b ) 3c8 vga-b! 3c9 vga-b@ 2 << 3c9 vga-b@ 2 << 3c9 vga-b@ 2 << ; : set-colors ( adr number #numbers -- ) over 3c8 vga-b! swap DO rb@ 2 >> 3c9 vga-b! rb@ 2 >> 3c9 vga-b! rb@ 2 >> 3c9 vga-b! LOOP 3drop ; : get-colors ( adr number #numbers -- ) 3drop ; include graphics.fs : init-mode 3da vga-b@ drop \ reset flip flop 0f 3c2 vga-b! \ color mode, ram enable, ... 12 06 vga-seq! \ unlock extensions 05 06 vga-gfx! \ graphic mode disp-depth CASE \ set depth 8 OF 01 07 vga-seq! ENDOF f OF 07 07 vga-seq! ENDOF 10 OF 07 07 vga-seq! ENDOF 20 OF 09 07 vga-seq! ENDOF ENDCASE ff 02 vga-seq! \ enable plane write 0a 04 vga-seq! \ memory mode 03 17 vga-crt! \ disable display disp-width disp-depth 7 + 8 / * 3 >> dup ff and 13 vga-crt! \ bottom bits 4 >> 10 and 1b vga-crt! \ top bit disp-width 3 >> 1 - 01 vga-crt! \ H_DISP disp-height 1 - ff and 12 vga-crt! \ V_DISP disp-height 1 - 7 >> 2 and disp-height 1 - 3 >> 40 and or 10 or 07 vga-crt! \ OFLOW ff 18 vga-crt! \ LINE_COMPARE 40 09 vga-crt! \ MAX_SCAN 08 04 vga-crt! \ SYNC_START 0f 02 vga-crt! \ BLANK_START 00 0c vga-crt! 00 0d vga-crt! 40 05 vga-gfx! \ gfx mode 83 17 vga-crt! \ enable display 33 3c0 vga-b! \ gfx in ar index 00 3c0 vga-b! 01 01 vga-seq! \ enable seq ; : clear-screen fb-base disp-width disp-height disp-depth 7 + 8 / * * 0 rfill ; : read-settings s" qemu,graphic-width" get-chosen IF decode-int to disp-width 2drop THEN s" qemu,graphic-height" get-chosen IF decode-int to disp-height 2drop THEN s" qemu,graphic-depth" get-chosen IF decode-int nip nip dup 8 = over f = or over 10 = or over 20 = or IF to disp-depth ELSE ." Unsupported bit depth, using 8bpp " drop cr THEN THEN ; : add-legacy-reg s" reg" get-node get-property IF encode-start ELSE encode-bytes THEN my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space 1ce encode-64+ 4 encode-64+ \ addr size my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space 3b0 encode-64+ c encode-64+ \ addr size my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space 3c0 encode-64+ 20 encode-64+ \ addr size my-space a2000000 or encode-int+ \ non-relocatable, <1MB Memory space a0000 encode-64+ 20000 encode-64+ \ addr size s" reg" property \ store "reg" property ; : setup-properties disp-width encode-int s" width" property disp-height encode-int s" height" property disp-width disp-depth 7 + 8 / * encode-int s" linebytes" property disp-depth encode-int s" depth" property s" ISO8859-1" encode-string s" character-set" property \ i hope this is ok... s" display" device-type ; : display-remove ( -- ) ; : display-install ( -- ) is-installed? NOT IF ." Installing QEMU fb" cr fb-base to frame-buffer-adr default-font set-font disp-width disp-height disp-width char-width / disp-height char-height / disp-depth 7 + 8 / ( width height #lines #cols depth ) fb-install true to is-installed? THEN ; : set-alias s" screen" find-alias 0= IF s" screen" get-node node>path set-alias ELSE drop THEN ; ." cirrus vga" cr pci-master-enable pci-mem-enable pci-io-enable add-legacy-reg read-settings init-mode clear-screen init-default-palette setup-properties ' display-install is-install ' display-remove is-remove set-alias q8pci-device_8086_100e.fss" e1000 [ net ]" type cr my-space pci-device-generic-setup pci-io-enable s" e1k.fs" included pci-device-disable (e1k.fss" network" device-type INSTANCE VARIABLE obp-tftp-package get-node CONSTANT my-phandle 10 config-l@ translate-my-address 3 not AND CONSTANT baseaddr 0 VALUE e1k-priv 0 VALUE open-count : open ( -- okay? ) open-count 0= IF open IF baseaddr e1k-open dup not IF ." e1k-open failed" EXIT THEN drop TO e1k-priv true ELSE false THEN ELSE true THEN my-args s" obp-tftp" $open-package obp-tftp-package ! open-count 1 + to open-count ; : close ( -- ) my-phandle set-node open-count 0> IF open-count 1 - dup to open-count 0= IF e1k-priv e1k-close close THEN THEN s" close" obp-tftp-package @ $call-method ; : read ( buf len -- actual ) dup IF e1k-read ELSE nip THEN ; : write ( buf len -- actual ) dup IF e1k-write ELSE nip THEN ; : load ( addr -- len ) s" load" obp-tftp-package @ $call-method ; : ping ( -- ) s" ping" obp-tftp-package @ $call-method ; 6 BUFFER: local-mac : setup-mac ( -- ) pci-mem-enable " vendor-id" get-node get-property IF EXIT THEN decode-int nip nip " device-id" get-node get-property IF EXIT THEN decode-int nip nip baseaddr local-mac e1k-mac-setup IF encode-bytes " local-mac-address" property THEN ; setup-mac : setup-alias ( -- ) " net" get-next-alias ?dup IF get-node node>path set-alias THEN ; setup-alias u0qemu-vga.fsmy-space pci-device-generic-setup d# 800 VALUE disp-width d# 600 VALUE disp-height d# 8 VALUE disp-depth : map-in " map-in" my-phandle parent $call-static ; : map-out " map-out" my-phandle parent $call-static ; 0 0 my-space h# 02000010 + 1 map-in VALUE fb-base 0 0 my-space h# 02000018 + 1 map-in VALUE reg-base false VALUE is-installed? : vga-w! ( value port -- ) 3c0 - reg-base 400 + + rw!-le ; : vga-w@ ( port -- value ) 3c0 - reg-base 400 + + rw@-le ; : vga-b! ( value port -- ) 3c0 - reg-base 400 + + rb! ; : vga-b@ ( port -- value ) 3c0 - reg-base 400 + + rb@ ; : vbe! ( value index -- ) 1 << reg-base 500 + + rw!-le ; : vbe@ ( index -- value ) 1 << reg-base 500 + + rw@-le ; : color! ( r g b number -- ) 3c8 vga-b! rot 3c9 vga-b! swap 3c9 vga-b! 3c9 vga-b! ; : color@ ( number -- r g b ) 3c8 vga-b! 3c9 vga-b@ 3c9 vga-b@ 3c9 vga-b@ ; : set-colors ( adr number #numbers -- ) over 3c8 vga-b! swap DO rb@ 3c9 vga-b! rb@ 3c9 vga-b! rb@ 3c9 vga-b! LOOP 3drop ; : get-colors ( adr number #numbers -- ) 3drop ; include graphics.fs 0 CONSTANT VBE_DISPI_INDEX_ID 1 CONSTANT VBE_DISPI_INDEX_XRES 2 CONSTANT VBE_DISPI_INDEX_YRES 3 CONSTANT VBE_DISPI_INDEX_BPP 4 CONSTANT VBE_DISPI_INDEX_ENABLE 5 CONSTANT VBE_DISPI_INDEX_BANK 6 CONSTANT VBE_DISPI_INDEX_VIRT_WIDTH 7 CONSTANT VBE_DISPI_INDEX_VIRT_HEIGHT 8 CONSTANT VBE_DISPI_INDEX_X_OFFSET 9 CONSTANT VBE_DISPI_INDEX_Y_OFFSET a CONSTANT VBE_DISPI_INDEX_NB 00 CONSTANT VBE_DISPI_DISABLED 01 CONSTANT VBE_DISPI_ENABLED 02 CONSTANT VBE_DISPI_GETCAPS 20 CONSTANT VBE_DISPI_8BIT_DAC 40 CONSTANT VBE_DISPI_LFB_ENABLED 80 CONSTANT VBE_DISPI_NOCLEARMEM : init-mode 0 3c0 vga-b! VBE_DISPI_DISABLED VBE_DISPI_INDEX_ENABLE vbe! 0 VBE_DISPI_INDEX_X_OFFSET vbe! 0 VBE_DISPI_INDEX_Y_OFFSET vbe! disp-width VBE_DISPI_INDEX_XRES vbe! disp-height VBE_DISPI_INDEX_YRES vbe! disp-depth VBE_DISPI_INDEX_BPP vbe! VBE_DISPI_ENABLED VBE_DISPI_8BIT_DAC or VBE_DISPI_INDEX_ENABLE vbe! 0 3c0 vga-b! 20 3c0 vga-b! ; : clear-screen fb-base disp-width disp-height disp-depth 7 + 8 / * * 0 rfill ; : read-settings s" qemu,graphic-width" get-chosen IF decode-int to disp-width 2drop THEN s" qemu,graphic-height" get-chosen IF decode-int to disp-height 2drop THEN s" qemu,graphic-depth" get-chosen IF decode-int nip nip dup 8 = over f = or over 10 = or over 20 = or IF to disp-depth ELSE ." Unsupported bit depth, using 8bpp " drop cr THEN THEN ; : setup-properties disp-width encode-int s" width" property disp-height encode-int s" height" property disp-width disp-depth 7 + 8 / * encode-int s" linebytes" property disp-depth encode-int s" depth" property s" ISO8859-1" encode-string s" character-set" property \ i hope this is ok... s" display" device-type s" qemu,std-vga" encode-string s" compatible" property ; : display-remove ( -- ) ; : slow-blink-screen ( -- ) invert-screen 20 ms invert-screen ; : display-install ( -- ) is-installed? NOT IF ." Installing QEMU fb" cr fb-base to frame-buffer-adr clear-screen default-font set-font disp-width disp-height disp-width char-width / disp-height char-height / disp-depth 7 + 8 / ( width height #lines #cols depth ) fb-install ['] slow-blink-screen to blink-screen true to is-installed? THEN ; : set-alias s" screen" find-alias 0= IF s" screen" get-node node>path set-alias ELSE drop THEN ; pci-master-enable pci-mem-enable read-settings init-mode init-default-palette setup-properties ' display-install is-install ' display-remove is-remove set-alias E0pci-class_02.fss" network [ " type my-space pci-class-name type s" ]" type my-space pci-device-generic-setup my-space pci-alias-net s" network" device-type cr INSTANCE VARIABLE obp-tftp-package : open ( -- okay? ) open IF \ enables PCI mem, io and Bus master and returns TRUE my-args s" obp-tftp" $open-package obp-tftp-package ! true ELSE false THEN ; : close ( -- ) obp-tftp-package @ close-package close ; \ disables PCI mem, io and Bus master : load ( addr -- len ) s" load" obp-tftp-package @ $call-method ; : ping ( -- ) s" ping" obp-tftp-package @ $call-method ; @0pci-class_0c.fss" serial bus [ " type my-space pci-class-name type s" ]" type cr my-space pci-device-generic-setup STRUCT /n FIELD hcd>base /n FIELD hcd>type /n FIELD hcd>num /n FIELD hcd>ops /n FIELD hcd>priv /n FIELD hcd>nextaddr CONSTANT /hci-dev : usb-setup-hcidev ( num hci-dev -- ) >r 10 config-l@ F AND case 0 OF 10 config-l@ translate-my-address ENDOF \ 32-bit memory space 4 OF \ 64-bit memory space 14 config-l@ 20 lshift \ Read two bars 10 config-l@ OR translate-my-address ENDOF ENDCASE F not AND ( io-base ) r@ hcd>base ! 08 config-l@ 8 rshift 0000000F0 AND 4 rshift ( usb-type ) r@ hcd>type ! ( usb-num ) r@ hcd>num ! r> drop ; : handle-usb-class ( -- ) 4 config-w@ 110 or 4 config-w! pci-master-enable \ set PCI Bus master bit and pci-mem-enable \ memory space enable for USB scan ; : handle-sbc-subclass ( -- ) my-space pci-class@ ffff and CASE \ get PCI sub-class and interface 0310 OF \ OHCI controller handle-usb-class set-ohci-alias ENDOF 0320 OF \ EHCI controller handle-usb-class set-ehci-alias ENDOF 0330 OF \ XHCI controller handle-usb-class set-xhci-alias ENDOF ENDCASE ; handle-sbc-subclass K0dev-hci.fsVALUE usb_type \ USB type device-type s" usb" rot VALUE usb_num \ controller number usb_num $cathex strdup \ create alias name 2dup find-alias 0= IF get-node node>path set-alias ELSE 3drop THEN /hci-dev BUFFER: hcidev usb_num hcidev usb-setup-hcidev TRUE VALUE first-time-init? 0 VALUE open-count false VALUE dev-hci-debug? 1 encode-int s" #address-cells" property 0 encode-int s" #size-cells" property : encode-unit ( port -- unit-str unit-len ) 1 hex-encode-unit ; : decode-unit ( addr len -- port ) 1 hex-decode-unit ; : get-hci-dev ( -- hcidev ) hcidev ; : hc-cleanup ( -- ) my-phandle set-node dev-hci-debug? IF ." USB-HCI: Cleaning up " pwd cr THEN hcidev USB-HCD-EXIT 0 set-node ; : open ( -- true | false ) true ; : close ; first-time-init? IF ['] hc-cleanup add-quiesce-xt false to first-time-init? THEN 0slofdev.fsSTRUCT /n FIELD slof-dev>udev /l FIELD slof-dev>port /l FIELD slof-dev>devaddr /l FIELD slof-dev>hcitype /l FIELD slof-dev>num /l FIELD slof-dev>devtype CONSTANT slof-usb-dev :8dev-parent-calls.fsget-node CONSTANT my-phandle s" dma-function.fs" included p10dev-keyb.fsnew-device VALUE sudev false VALUE usb-keyb-debug? s" slofdev.fs" included sudev slof-dev>port l@ dup set-unit encode-phys " reg" property sudev slof-dev>udev @ VALUE udev s" usb-keyboard" device-name s" keyboard" device-type s" EN" encode-string s" language" property s" keyboard" get-node node>path set-alias s" dev-parent-calls.fs" included 0 VALUE open-count : open ( -- true | false ) usb-keyb-debug? IF ." USB-KEYB: Opening (count is " open-count . ." )" cr THEN open-count 0= IF udev USB-HID-INIT 0= IF ." USB keyboard setup failed " pwd cr false EXIT THEN THEN open-count 1 + to open-count true ; : close usb-keyb-debug? IF ." USB-KEYB: Closing (count is " open-count . ." )" cr THEN open-count 0> IF open-count 1 - dup to open-count 0= IF my-phandle set-node udev USB-HID-EXIT drop 0 set-node THEN THEN ; : key-available? ( -- true|false ) udev USB-KEY-AVAILABLE IF TRUE ELSE FALSE THEN ; : read ( addr len -- actual ) 0= IF drop 0 EXIT THEN udev USB-READ-KEYB ?dup IF swap c! 1 ELSE 0 swap c! 0 then ; ." USB Keyboard " cr finish-device 0dev-mouse.fsnew-device VALUE sudev s" slofdev.fs" included sudev slof-dev>port l@ dup set-unit encode-phys " reg" property sudev slof-dev>udev @ VALUE udev s" usb-mouse" device-name ." USB mouse " cr finish-device X0dev-storage.fsnew-device VALUE usbdev s" slofdev.fs" included false VALUE usb-disk-debug? usbdev slof-dev>port l@ dup set-unit encode-phys " reg" property s" storage" device-name s" dev-parent-calls.fs" included 2 encode-int s" #address-cells" property 0 encode-int s" #size-cells" property : decode-unit 2 hex64-decode-unit ; : encode-unit 2 hex64-encode-unit ; 0 CONSTANT USB_PIPE_OUT 1 CONSTANT USB_PIPE_IN usbdev slof-dev>udev @ VALUE udev usbdev slof-dev>port l@ VALUE port usbdev slof-dev>hcitype l@ VALUE hcitype 0 INSTANCE VALUE lun 10000 VALUE dev-max-transfer 0 VALUE resp-buffer 0 VALUE resp-size 0f CONSTANT SCSI-COMMAND-OFFSET STRUCT dev-max-transfer FIELD usb>data 40 FIELD usb>cmd 20 FIELD usb>csw CONSTANT /dma-buf 0 VALUE dma-buf 0 VALUE dma-buf-phys 0 VALUE td-buf 0 VALUE td-buf-phys 1000 CONSTANT /td-buf : (dma-buf-init) ( -- ) /dma-buf dma-alloc TO dma-buf dma-buf /dma-buf 0 dma-map-in TO dma-buf-phys /td-buf dma-alloc TO td-buf td-buf /td-buf 0 dma-map-in TO td-buf-phys ; : (dma-buf-free) ( -- ) td-buf td-buf-phys /td-buf dma-map-out td-buf /td-buf dma-free 0 TO td-buf 0 TO td-buf-phys dma-buf dma-buf-phys /dma-buf dma-map-out dma-buf /dma-buf dma-free 0 TO dma-buf 0 TO dma-buf-phys ; scsi-open 0 INSTANCE VALUE current-target : do-bulk-command ( dir resp-buffer resp-size -- TRUE | FALSE ) TO resp-size TO resp-buffer udev USB_PIPE_OUT td-buf td-buf-phys dma-buf-phys usb>cmd 1F usb-transfer-bulk 0= IF drop FALSE EXIT THEN resp-size IF d# 125 us IF udev USB_PIPE_IN ELSE udev USB_PIPE_OUT THEN td-buf td-buf-phys resp-buffer resp-size usb-transfer-bulk 0= IF \ transfer data usb-disk-debug? IF ." Data phase failed " cr THEN THEN ELSE drop THEN d# 125 us udev USB_PIPE_IN td-buf td-buf-phys dma-buf-phys usb>csw 0D usb-transfer-bulk \ transfer CSW ; STRUCT \ cbw /l FIELD cbw>sig /l FIELD cbw>tag /l FIELD cbw>len /c FIELD cbw>flags /c FIELD cbw>lun \ 0:3 bits /c FIELD cbw>cblen \ 0:4 bits CONSTANT cbw-length STRUCT \ csw /l FIELD csw>sig /l FIELD csw>tag /l FIELD csw>data-residue /c FIELD csw>status CONSTANT cbw-length 0 VALUE cbw-addr 0 VALUE csw-addr : build-cbw ( tag xfer-len dir lun cmd-len addr -- ) TO cbw-addr ( tag xfer-len dir lun cmd-len ) cbw-addr cbw-length erase ( tag xfer-len dir lun cmd-len ) cbw-addr cbw>cblen c! ( tag xfer-len dir lun ) cbw-addr cbw>lun c! ( tag xfer-len dir ) IF 80 ELSE 0 THEN cbw-addr cbw>flags c! ( tag xfer-len ) cbw-addr cbw>len l!-le ( tag ) cbw-addr cbw>tag l!-le ( ) 43425355 cbw-addr cbw>sig l!-le ; 0 INSTANCE VALUE usb-buf-addr 0 INSTANCE VALUE usb-buf-len 0 INSTANCE VALUE usb-dir 0 INSTANCE VALUE usb-cmd-addr 0 INSTANCE VALUE usb-cmd-len 1 VALUE tag : execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... ) to usb-cmd-len to usb-cmd-addr to usb-dir to usb-buf-len to usb-buf-addr dma-buf usb>cmd 40 0 fill dma-buf usb>csw 20 0 fill tag usb-buf-len usb-dir lun usb-cmd-len dma-buf usb>cmd build-cbw 1 tag + to tag usb-cmd-addr dma-buf usb>cmd SCSI-COMMAND-OFFSET + usb-cmd-len move usb-dir not IF usb-buf-addr dma-buf usb>data usb-buf-len move THEN usb-dir dma-buf-phys usb>data usb-buf-len do-bulk-command 0= IF ." USB-DISK: Bulk command failed!" cr 0 0 -1 EXIT THEN usb-dir IF dma-buf usb>data usb-buf-addr usb-buf-len move THEN dma-buf usb>csw to csw-addr csw-addr csw>sig l@ 55534253 <> IF ." USB-DISK: CSW signature invalid " cr 0 0 -1 EXIT THEN csw-addr csw>status c@ CASE 0 OF ENDOF \ Good 1 OF usb-disk-debug? IF ." USB-DISK: CSW Data residue: " csw-addr csw>data-residue l@-le . cr THEN 0 0 8 EXIT ENDOF \ Command failed, Retry dup OF 0 0 -1 EXIT ENDOF \ Anything else -> HW error ENDCASE csw-addr csw>status c@ dup 0<> IF usb-disk-debug? IF over scsi-get-sense-data ." USB-DISK: Sense key [ " dup . ." ] " .sense-text ." ASC,ASCQ: " . . cr THEN rot THEN ; " scsi-host-helpers.fs" included 0 VALUE open-count : usb-storage-init ( -- TRUE ) td-buf 0= IF usb-disk-debug? IF ." USB-DISK: Allocating buffer " cr THEN (dma-buf-init) udev USB-MSC-INIT 0= IF ." USB-DISK: Unable to initialize MSC " cr FALSE ELSE TRUE THEN THEN ; : usb-storage-cleanup td-buf 0<> IF usb-disk-debug? IF ." USB-DISK: Freeing buffer " cr THEN (dma-buf-free) udev USB-MSC-EXIT 0= IF ." USB-DISK: Unable to exit MSC " cr THEN THEN ; : open usb-disk-debug? IF ." USB-DISK: Opening (count is " open-count . ." )" cr THEN open-count 0= IF usb-storage-init IF 1 to open-count true ELSE ." USB-DISK initialization failed !" cr false THEN ELSE open-count 1 + to open-count true THEN ; : close usb-disk-debug? IF ." USB-DISK: Closing (count is " open-count . ." )" cr THEN open-count 0> IF open-count 1 - dup to open-count 0= IF usb-storage-cleanup THEN THEN ; : (set-target) dup 20 >> FFFF and to lun dup 30 >> FF and to port to current-target usb-disk-debug? IF ." USB-DISK: udev " udev . ." lun:" lun . ." port:" port . cr THEN ; : dev-generate-srplun ( target lun-id -- srplun ) swap drop port 0100 or 10 << or 20 << ; : max-transfer ( -- n ) dev-max-transfer ; : set-address ( srplun.lo srplun.hi -- ) lxjoin (set-target) usb-disk-debug? IF ." USB-DISK: udev " udev . ." lun:" lun . ." port:" port . cr THEN ; 1 CONSTANT #target : dev-max-target ( -- #target ) #target ; " scsi-probe-helpers.fs" included scsi-close \ no further scsi words required : setup-alias s" scsi" find-alias 0= IF s" scsi" get-node node>path set-alias ELSE drop THEN ; : usb-storage-init-and-scan ( -- ) usb-disk-debug? IF ." Initializing usb-disk: udev " udev . cr THEN 0 0 get-node open-node ?dup 0= IF EXIT THEN my-self >r dup to my-self hcitype CASE 1 OF 4000 TO dev-max-transfer ENDOF \ OHCI 2 OF 10000 TO dev-max-transfer ENDOF \ EHCI 3 OF F000 TO dev-max-transfer ENDOF \ XHCI ENDCASE usb-storage-init scsi-find-disks setup-alias usb-storage-cleanup close-node r> to my-self ; ." USB Storage " cr : usb-scsi-add-disk " scsi-disk.fs" included ; usb-scsi-add-disk usb-storage-init-and-scan finish-device 80dev-hub.fsnew-device VALUE sudev s" slofdev.fs" included sudev slof-dev>port l@ dup set-unit encode-phys " reg" property sudev slof-dev>udev @ VALUE udev s" hub" device-name s" dev-parent-calls.fs" included 1 encode-int s" #address-cells" property 0 encode-int s" #size-cells" property : decode-unit 1 hex-decode-unit ; : encode-unit 1 hex-encode-unit ; : usb-hub-init ( usbdev -- true | false ) udev USB-HUB-INIT ; : open ( -- true | false ) TRUE ; : close ; ." USB HUB " cr usb-hub-init drop finish-device y8pci-device_1af4_1000.fss" virtio [ net ]" type cr my-space pci-device-generic-setup pci-io-enable s" virtio-net.fs" included pci-device-disable h%8pci-device_1af4_1041.fss" pci-device_1af4_1000.fs" included 8pci-device_1af4_1001.fss" virtio [ block ]" type cr my-space pci-device-generic-setup pci-master-enable pci-mem-enable pci-io-enable s" virtio-block.fs" included pci-device-disable h%8pci-device_1af4_1042.fss" pci-device_1af4_1001.fs" included 8pci-device_1af4_1003.fss" virtio [ serial ]" type cr my-space pci-device-generic-setup pci-master-enable pci-mem-enable pci-io-enable s" virtio-serial.fs" included pci-device-disable h%8pci-device_1af4_1043.fss" pci-device_1af4_1003.fs" included 8pci-device_1af4_1004.fss" virtio [ scsi ]" type cr my-space pci-device-generic-setup pci-master-enable pci-mem-enable pci-io-enable s" virtio-scsi.fs" included pci-device-disable h%8pci-device_1af4_1048.fss" pci-device_1af4_1004.fs" included 8pci-device_1af4_1009.fss" virtio [ network ]" type cr my-space pci-device-generic-setup s" virtio-9p" device-name pci-master-enable pci-mem-enable pci-io-enable s" virtio-fs.fs" included pci-device-disable h%8pci-device_1af4_1049.fss" pci-device_1af4_1009.fs" included 8pci-device_1af4_1050.fsmy-space pci-class@ 30000 = IF s" virtio [ vga ]" type cr s" qemu-vga.fs" included ELSE s" virtio [ gpu ]" type cr my-space pci-device-generic-setup THEN x0vio-hvterm.fs." Populating " pwd cr : open true ; : close ; : write ( adr len -- actual ) tuck 0 ?DO dup c@ my-unit SWAP hv-putchar 1 + LOOP drop ; : read ( adr len -- actual ) 0= IF drop 0 EXIT THEN my-unit hv-haschar 0= IF 0 swap c! -2 EXIT THEN my-unit hv-getchar swap c! 1 ; : setup-alias " hvterm" find-alias 0= IF " hvterm" get-node node>path set-alias ELSE drop THEN ; setup-alias X 0vio-vscsi.fs." Populating " pwd false VALUE vscsi-debug? 0 VALUE vscsi-unit : l2dma ( laddr - dma_addr) ; 0 VALUE crq-real-base 0 VALUE crq-base 0 VALUE crq-dma 0 VALUE crq-offset 1000 CONSTANT CRQ-SIZE CREATE crq 10 allot : crq-alloc ( -- ) CRQ-SIZE fff + alloc-mem to crq-real-base crq-real-base fff + fffff000 AND to crq-base 0 to crq-offset crq-base l2dma to crq-dma ; : crq-free ( -- ) vscsi-unit hv-free-crq crq-real-base CRQ-SIZE fff + free-mem 0 to crq-base 0 to crq-real-base ; : crq-init ( -- res ) crq-alloc vscsi-debug? IF ." VSCSI: allocated crq at " crq-base . cr THEN crq-base CRQ-SIZE erase vscsi-unit crq-dma CRQ-SIZE hv-reg-crq dup 0 <> IF ." VSCSI: Error " . ." registering CRQ !" cr crq-free THEN ; : crq-cleanup ( -- ) crq-base 0 = IF EXIT THEN vscsi-debug? IF ." VSCSI: freeing crq at " crq-base . cr THEN crq-free ; : crq-send ( msgaddr -- true | false ) vscsi-unit swap hv-send-crq 0 = ; : crq-poll ( -- true | false) crq-offset crq-base + dup vscsi-debug? IF ." VSCSI: crq poll " dup . THEN c@ vscsi-debug? IF ." value=" dup . cr THEN 80 and 0 <> IF dup crq 10 move 0 swap c! crq-offset 10 + dup CRQ-SIZE >= IF drop 0 THEN to crq-offset true ELSE drop false THEN ; : crq-wait ( -- true | false) 0 BEGIN drop crq-poll dup not WHILE d# 1 ms REPEAT dup not IF ." VSCSI: Timeout waiting response !" cr EXIT ELSE vscsi-debug? IF ." VSCSI: got crq: " crq dup l@ . ." " 4 + dup l@ . ." " 4 + dup l@ . ." " 4 + l@ . cr THEN THEN ; 01 CONSTANT VIOSRP_SRP_FORMAT 02 CONSTANT VIOSRP_MAD_FORMAT 03 CONSTANT VIOSRP_OS400_FORMAT 04 CONSTANT VIOSRP_AIX_FORMAT 06 CONSTANT VIOSRP_LINUX_FORMAT 07 CONSTANT VIOSRP_INLINE_FORMAT struct 1 field >crq-valid 1 field >crq-format 1 field >crq-reserved 1 field >crq-status 2 field >crq-timeout 2 field >crq-iu-len 8 field >crq-iu-data-ptr constant /crq : srp-send-crq ( addr len -- ) 80 crq >crq-valid c! VIOSRP_SRP_FORMAT crq >crq-format c! 0 crq >crq-reserved c! 0 crq >crq-status c! 0 crq >crq-timeout w! ( len ) crq >crq-iu-len w! ( addr ) l2dma crq >crq-iu-data-ptr x! crq crq-send not IF ." VSCSI: Error sending CRQ !" cr THEN ; : srp-wait-crq ( -- [tag true] | false ) crq-wait not IF false EXIT THEN crq >crq-format c@ VIOSRP_SRP_FORMAT <> IF ." VSCSI: Unsupported SRP response: " crq >crq-format c@ . cr false EXIT THEN crq >crq-iu-data-ptr x@ true ; scsi-open 0 VALUE >srp_opcode 00 CONSTANT SRP_LOGIN_REQ 01 CONSTANT SRP_TSK_MGMT 02 CONSTANT SRP_CMD 03 CONSTANT SRP_I_LOGOUT c0 CONSTANT SRP_LOGIN_RSP c1 CONSTANT SRP_RSP c2 CONSTANT SRP_LOGIN_REJ 80 CONSTANT SRP_T_LOGOUT 81 CONSTANT SRP_CRED_REQ 82 CONSTANT SRP_AER_REQ 41 CONSTANT SRP_CRED_RSP 42 CONSTANT SRP_AER_RSP 02 CONSTANT SRP_BUF_FORMAT_DIRECT 04 CONSTANT SRP_BUF_FORMAT_INDIRECT struct 1 field >srp-login-opcode 3 + 8 field >srp-login-tag 4 field >srp-login-req-it-iu-len 4 + 2 field >srp-login-req-buf-fmt 1 field >srp-login-req-flags 5 + 10 field >srp-login-init-port-ids 10 field >srp-login-trgt-port-ids constant /srp-login struct 1 field >srp-lresp-opcode 3 + 4 field >srp-lresp-req-lim-delta 8 field >srp-lresp-tag 4 field >srp-lresp-max-it-iu-len 4 field >srp-lresp-max-ti-iu-len 2 field >srp-lresp-buf-fmt 1 field >srp-lresp-flags constant /srp-login-resp struct 1 field >srp-lrej-opcode 3 + 4 field >srp-lrej-reason 8 field >srp-lrej-tag 8 + 2 field >srp-lrej-buf-fmt constant /srp-login-rej 00 CONSTANT SRP_NO_DATA_DESC 01 CONSTANT SRP_DATA_DESC_DIRECT 02 CONSTANT SRP_DATA_DESC_INDIRECT struct 1 field >srp-cmd-opcode 1 field >srp-cmd-sol-not 3 + 1 field >srp-cmd-buf-fmt 1 field >srp-cmd-dout-desc-cnt 1 field >srp-cmd-din-desc-cnt 8 field >srp-cmd-tag 4 + 8 field >srp-cmd-lun 1 + 1 field >srp-cmd-task-attr 1 + 1 field >srp-cmd-add-cdb-len 10 field >srp-cmd-cdb 0 field >srp-cmd-cdb-add constant /srp-cmd struct 1 field >srp-rsp-opcode 1 field >srp-rsp-sol-not 2 + 4 field >srp-rsp-req-lim-delta 8 field >srp-rsp-tag 2 + 1 field >srp-rsp-flags 1 field >srp-rsp-status 4 field >srp-rsp-dout-res-cnt 4 field >srp-rsp-din-res-cnt 4 field >srp-rsp-sense-len 4 field >srp-rsp-resp-len 0 field >srp-rsp-data constant /srp-rsp 01 CONSTANT SRP_RSP_FLAG_RSPVALID 02 CONSTANT SRP_RSP_FLAG_SNSVALID 04 CONSTANT SRP_RSP_FLAG_DOOVER 05 CONSTANT SRP_RSP_FLAG_DOUNDER 06 CONSTANT SRP_RSP_FLAG_DIOVER 07 CONSTANT SRP_RSP_FLAG_DIUNDER CREATE srp 100 allot 0 VALUE srp-len : srp-prep-cmd-nodata ( srplun -- ) srp /srp-cmd erase SRP_CMD srp >srp-cmd-opcode c! 1 srp >srp-cmd-tag x! srp >srp-cmd-lun x! \ 8 bytes lun /srp-cmd to srp-len ; : srp-prep-cmd-io ( addr len srplun -- ) srp-prep-cmd-nodata ( addr len ) swap l2dma ( len dmaaddr ) srp srp-len + ( len dmaaddr descaddr ) dup >r x! r> 8 + ( len descaddr+8 ) dup 0 swap l! 4 + ( len descaddr+c ) l! srp-len 10 + to srp-len ; : srp-prep-cmd-read ( addr len srplun -- ) srp-prep-cmd-io 01 srp >srp-cmd-buf-fmt c! \ in direct buffer 1 srp >srp-cmd-din-desc-cnt c! ; : srp-prep-cmd-write ( addr len srplun -- ) srp-prep-cmd-io 10 srp >srp-cmd-buf-fmt c! \ out direct buffer 1 srp >srp-cmd-dout-desc-cnt c! ; : srp-send-cmd ( -- ) vscsi-debug? IF ." VSCSI: Sending SCSI cmd " srp >srp-cmd-cdb c@ . cr THEN srp srp-len srp-send-crq ; : srp-rsp-find-sense ( -- addr len true | false ) srp >srp-rsp-flags c@ SRP_RSP_FLAG_SNSVALID and 0= IF false EXIT THEN srp >srp-rsp-data srp >srp-rsp-sense-len l@ true ; : srp-wait-rsp ( -- stat ) srp-wait-crq not IF false EXIT THEN dup 1 <> IF ." VSCSI: Invalid CRQ response tag, want 1 got " . cr -1 EXIT THEN drop srp >srp-rsp-tag x@ dup 1 <> IF ." VSCSI: Invalid SRP response tag, want 1 got " . cr -1 EXIT THEN drop srp >srp-rsp-status c@ vscsi-debug? IF ." VSCSI: Got response status: " dup .status-text cr THEN ; 8000000000000000 INSTANCE VALUE current-target : execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... ) >r >r ( buf-addr buf-len dir ) over 0= IF 3drop current-target srp-prep-cmd-nodata ELSE current-target swap IF srp-prep-cmd-read ELSE srp-prep-cmd-write THEN THEN r> r> srp >srp-cmd-cdb swap move srp-send-cmd srp-wait-rsp dup -1 = IF 0 0 rot EXIT THEN dup 0<> IF srp-rsp-find-sense IF vscsi-debug? IF over scsi-get-sense-data ." VSCSI: Sense key [ " dup . ." ] " .sense-text ." ASC,ASCQ: " . . cr THEN ELSE 0 0 ." VSCSI: No sense data" cr THEN rot THEN ; " scsi-host-helpers.fs" included TRUE VALUE first-time-init? 0 VALUE open-count : vscsi-cleanup vscsi-debug? IF ." VSCSI: Cleaning up" cr THEN crq-cleanup vscsi-unit 0 rtas-set-tce-bypass ; : vscsi-init ( -- true | false ) vscsi-debug? IF ." VSCSI: Initializing" cr THEN my-unit to vscsi-unit vscsi-unit 1 rtas-set-tce-bypass crq-init 0 <> IF false EXIT THEN " "(C0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00)" drop crq-send not IF ." VSCSI: Error sending init command" crq-cleanup false EXIT THEN crq-wait not IF crq-cleanup false EXIT THEN crq c@ c0 <> crq 1 + c@ 02 <> or IF ." VSCSI: Initial handshake failed" crq-cleanup false EXIT THEN first-time-init? IF ['] vscsi-cleanup add-quiesce-xt false to first-time-init? THEN true ; : open vscsi-debug? IF ." VSCSI: Opening (count is " open-count . ." )" cr THEN open-count 0= IF vscsi-init IF 1 to open-count true ELSE ." VSCSI initialization failed !" cr false THEN ELSE open-count 1 + to open-count true THEN ; : close vscsi-debug? IF ." VSCSI: Closing (count is " open-count . ." )" cr THEN open-count 0> IF open-count 1 - dup to open-count 0= IF vscsi-cleanup THEN THEN ; : (set-target) to current-target ; : dev-generate-srplun ( bus+target lun -- srplun ) swap dup 1 >> e0 and ( lun bus+target bus ) swap 3f and 8 << ( lun bus target ) 8000 or or or 30 << ; : set-address ( srplun.lo srplun.hi -- ) lxjoin (set-target) ; : max-transfer ( -- n ) 10000 \ Larger value seem to have problems with some CDROMs ; : dev-max-target ( -- #max-target ) 200 ; " scsi-probe-helpers.fs" included scsi-close : setup-alias " scsi" find-alias 0= IF " scsi" get-node node>path set-alias ELSE drop THEN ; : vscsi-init-and-scan ( -- ) 0 0 get-node open-node ?dup 0= IF EXIT THEN my-self >r dup to my-self scsi-find-disks setup-alias close-node r> to my-self ; : vscsi-add-disk " scsi-disk.fs" included ; vscsi-add-disk vscsi-init-and-scan 80vio-veth.fs." Populating " pwd cr " network" device-type INSTANCE VARIABLE obp-tftp-package 0 VALUE veth-priv 0 VALUE open-count : open ( -- okay? ) open-count 0= IF my-unit 1 rtas-set-tce-bypass s" local-mac-address" get-node get-property not s" reg" get-node get-property not 3 pick and IF >r nip r> libveth-open dup not IF ." libveth-open failed" EXIT THEN drop TO veth-priv THEN THEN my-args s" obp-tftp" $open-package obp-tftp-package ! open-count 1 + to open-count true ; : close ( -- ) open-count 0> IF open-count 1 - dup to open-count 0= IF veth-priv libveth-close my-unit 0 rtas-set-tce-bypass THEN THEN s" close" obp-tftp-package @ $call-method ; : read ( buf len -- actual ) dup IF veth-priv libveth-read ELSE nip THEN ; : write ( buf len -- actual ) dup IF veth-priv libveth-write ELSE nip THEN ; : load ( addr -- len ) s" load" obp-tftp-package @ $call-method ; : ping ( -- ) s" ping" obp-tftp-package @ $call-method ; : setup-alias " net" get-next-alias ?dup IF get-node node>path set-alias THEN ; setup-alias u0rtas-nvram.fs." Populating " pwd cr 0 VALUE my-nvram-fetch 0 VALUE my-nvram-store 0 VALUE my-nvram-size 0 VALUE nvram-addr : open true ; : close ; : write ( adr len -- actual ) nip ; : read ( adr len -- actual ) nip ; : setup-alias " nvram" find-alias 0= IF " nvram" get-node node>path set-alias ELSE drop THEN ; " #bytes" get-node get-package-property 0= IF decode-int to my-nvram-size 2drop " nvram-fetch" rtas-get-token to my-nvram-fetch " nvram-store" rtas-get-token to my-nvram-store my-nvram-size to nvram-size nvram-size alloc-mem to nvram-addr my-nvram-fetch my-nvram-store nvram-size nvram-addr internal-nvram-init THEN setup-alias @0virtio-net.fss" network" device-type INSTANCE VARIABLE obp-tftp-package virtio-setup-vd VALUE virtiodev 0 VALUE virtio-net-priv 0 VALUE open-count 6 BUFFER: local-mac : setup-mac ( -- ) s" local-mac-address" get-node get-property not IF 2drop EXIT THEN 6 0 DO virtiodev i 1 virtio-get-config local-mac i + c! LOOP local-mac 6 encode-bytes s" local-mac-address" property ; : open ( -- okay? ) open-count 0= IF open IF virtiodev virtio-net-open not IF ." virtio-net-open failed" cr false EXIT THEN TO virtio-net-priv setup-mac true ELSE false THEN ELSE true THEN my-args s" obp-tftp" $open-package obp-tftp-package ! open-count 1 + to open-count ; : close ( -- ) open-count 0> IF open-count 1 - dup to open-count 0= IF virtio-net-priv virtio-net-close close THEN THEN s" close" obp-tftp-package @ $call-method ; : read ( buf len -- actual ) dup IF virtio-net-priv virtio-net-read ELSE nip THEN ; : write ( buf len -- actual ) dup IF virtio-net-priv virtio-net-write ELSE nip THEN ; : load ( addr -- len ) s" load" obp-tftp-package @ $call-method ; : ping ( -- ) s" ping" obp-tftp-package @ $call-method ; : setup-alias ( -- ) " net" get-next-alias ?dup IF get-node node>path set-alias THEN ; setup-alias : virtio-net-init ( -- ) 0 0 get-node open-node ?dup IF close-node THEN ; virtio-net-init {8virtio-serial.fss" serial" device-type FALSE VALUE initialized? virtio-setup-vd VALUE virtiodev : shutdown ( -- ) initialized? IF my-phandle node>path open-dev ?dup IF virtiodev virtio-serial-shutdown close-dev THEN FALSE to initialized? THEN ; : virtio-serial-term-emit virtiodev SWAP virtio-serial-putchar ; : virtio-serial-term-key? virtiodev virtio-serial-haschar ; : virtio-serial-term-key BEGIN virtio-serial-term-key? UNTIL virtiodev virtio-serial-getchar ; : init ( -- ) virtiodev virtio-serial-init drop TRUE to initialized? ['] virtio-serial-term-emit to emit ['] virtio-serial-term-key to key ['] virtio-serial-term-key? to key? ['] shutdown add-quiesce-xt ; 0 VALUE open-count : open ( -- okay? ) open-count 0= IF open IF initialized? 0= IF init THEN true ELSE false exit THEN ELSE true THEN open-count 1 + to open-count ; : close open-count 0> IF open-count 1 - dup to open-count 0= IF close THEN THEN close ; : write ( addr len -- actual ) tuck 0 ?DO dup c@ virtiodev SWAP virtio-serial-putchar 1 + LOOP drop ; : read ( addr len -- actual ) 0= IF drop 0 EXIT THEN virtiodev virtio-serial-haschar 0= IF 0 swap c! -2 EXIT THEN virtiodev virtio-serial-getchar swap c! 1 ; : setup-alias " vsterm" find-alias 0= IF " vsterm" get-node node>path set-alias ELSE drop THEN ; setup-alias : serial-emit virtio-serial-term-emit ; : serial-key? virtio-serial-term-key? ; : serial-key virtio-serial-term-key ; 0virtio-block.fss" block" device-type FALSE VALUE initialized? 200 VALUE block-size 8000 CONSTANT max-transfer INSTANCE VARIABLE deblocker virtio-setup-vd VALUE virtiodev : shutdown ( -- ) initialized? IF my-phandle node>path open-dev ?dup IF virtiodev virtio-blk-shutdown close-dev THEN FALSE to initialized? THEN ; : init ( -- ) virtiodev virtio-blk-init to block-size TRUE to initialized? ['] shutdown add-quiesce-xt ; : read-blocks ( addr block# #blocks -- #read ) virtiodev virtio-blk-read ; : write-blocks ( addr block# #blocks -- #written ) over 22 < IF ." virtio-blk ERROR: Write access to partition table is not allowed." cr 3drop 0 EXIT THEN virtiodev virtio-blk-write ; : open ( -- okay? ) open 0= IF false EXIT THEN dup initialized? 0= AND IF init THEN 0 0 s" deblocker" $open-package dup deblocker ! dup IF s" disk-label" find-package IF my-args rot interpose THEN THEN 0<> ; : close ( -- ) deblocker @ close-package close ; : seek ( pos.lo pos.hi -- status ) s" seek" deblocker @ $call-method ; : read ( addr len -- actual ) s" read" deblocker @ $call-method ; : write ( addr len -- actual ) s" write" deblocker @ $call-method ; : (set-alias) s" disk" get-next-alias ?dup IF get-node node>path set-alias THEN ; (set-alias) 80virtio-fs.fs." Populating " pwd cr s" network" device-type 0 VALUE virtfs-rx-buffer 0 VALUE virtfs-tx-buffer FALSE VALUE initialized? 2000 CONSTANT VIRTFS-BUF-SIZE \ 8k virtio-setup-vd VALUE virtiodev : shutdown ( -- ) initialized? 0= IF EXIT THEN virtiodev virtio-fs-shutdown virtfs-rx-buffer VIRTFS-BUF-SIZE free-mem virtfs-tx-buffer VIRTFS-BUF-SIZE free-mem FALSE to initialized? ; : init ( -- success ) VIRTFS-BUF-SIZE alloc-mem to virtfs-rx-buffer VIRTFS-BUF-SIZE alloc-mem to virtfs-tx-buffer virtiodev ( dev ) virtfs-tx-buffer ( dev tx ) virtfs-rx-buffer ( reg tx rx ) VIRTFS-BUF-SIZE ( reg tx rx size ) virtio-fs-init ( success ) dup IF TRUE to initialized? ['] shutdown add-quiesce-xt THEN ; : open ( -- okay? ) open 0= IF false EXIT THEN initialized? 0= IF init 0= IF false EXIT THEN THEN true ; : load ( addr -- len ) virtiodev swap ( dev addr ) my-args ( dev addr str strlen ) 1 + \ hack to make the following allocate 1 more byte \-to-/ \ convert path elements 1 - 2dup + 0 swap c! drop virtio-fs-load ( length ) ; : close ( -- ) initialized? IF shutdown THEN close ; : ping ( -- ) cr s" ping not supported for this device" type cr cr ; : (set-alias) " virtfs" find-alias 0= IF " virtfs" get-node node>path set-alias ELSE drop THEN ; (set-alias) 0dev-null.fsnew-device " devnull-console" device-name : open true ; : close ; : write ( adr len -- actual ) nip ; : read ( adr len -- actual ) 2drop 0 ; : setup-alias " devnull-console" find-alias 0= IF " devnull-console" get-node node>path set-alias ELSE drop THEN ; : dummy-term-emit drop ; : dummy-term-key 0 ; : dummy-term-key? FALSE ; ' dummy-term-emit to emit ' dummy-term-key to key ' dummy-term-key? to key? setup-alias finish-device i0virtio-scsi.fs." Populating " pwd cr FALSE CONSTANT virtio-scsi-debug 2 encode-int s" #address-cells" property 0 encode-int s" #size-cells" property : decode-unit 2 hex64-decode-unit ; : encode-unit 2 hex64-encode-unit ; FALSE VALUE initialized? virtio-setup-vd VALUE virtiodev STRUCT \ virtio-scsi-config /l FIELD vs-cfg>num-queues /l FIELD vs-cfg>seg-max /l FIELD vs-cfg>max-sectors /l FIELD vs-cfg>cmd-per-lun /l FIELD vs-cfg>event-info-size /l FIELD vs-cfg>sense_size /l FIELD vs-cfg>cdb-size /w FIELD vs-cfg>max-channel /w FIELD vs-cfg>max-target /l FIELD vs-cfg>max-lun CONSTANT vs-cfg-length STRUCT \ virtio-scsi-req 8 FIELD vs-req>lun 8 FIELD vs-req>tag /c FIELD vs-req>task-attr /c FIELD vs-req>prio /c FIELD vs-req>crn 20 FIELD vs-req>cdb CONSTANT vs-req-length STRUCT \ virtio-scsi-resp /l FIELD vs-rsp>sense-len /l FIELD vs-rsp>residual /w FIELD vs-rsp>status-qualifier /c FIELD vs-rsp>status /c FIELD vs-rsp>response 60 FIELD vs-rsp>sense CONSTANT vs-rsp-length CREATE vs-req vs-req-length allot CREATE vs-rsp vs-rsp-length allot scsi-open 0 INSTANCE VALUE current-target : execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... ) vs-req vs-req-length erase vs-rsp vs-rsp-length erase current-target vs-req vs-req>lun x! vs-req vs-req>cdb swap move vs-req vs-rsp virtiodev virtio-scsi-send 0 <> IF ." VIRTIO-SCSI: Queuing failure !" cr 0 0 -1 EXIT THEN vs-rsp vs-rsp>response c@ CASE 0 OF ENDOF \ Good 5 OF drop 0 0 8 EXIT ENDOF \ Busy dup OF 0 0 -1 EXIT ENDOF \ Anything else -> HW error ENDCASE vs-rsp vs-rsp>status c@ dup 0<> IF vs-rsp vs-rsp>sense-len l@ dup 0= IF ." VIRTIO-SCSI: No sense data" cr 0 EXIT THEN vs-rsp vs-rsp>sense swap virtio-scsi-debug IF over scsi-get-sense-data ." VIRTIO-SCSI: Sense key [ " dup . ." ] " .sense-text ." ASC,ASCQ: " . . cr THEN rot THEN ; " scsi-host-helpers.fs" included : max-transfer ( -- n ) 10000 \ Larger value seem to have problems with some CDROMs ; : (set-target) to current-target ; : dev-generate-srplun ( target lun-id -- srplun ) dup ff > IF 4000 or THEN \ Use the LUN "flat space addressing method" swap 0100 or 10 << or 20 << ; : set-address ( srplun.lo srplun.hi -- ) lxjoin (set-target) ; 100 CONSTANT #target : dev-max-target ( -- #target ) #target ; " scsi-probe-helpers.fs" included scsi-close \ no further scsi words required : setup-alias s" scsi" find-alias 0= IF s" scsi" get-node node>path set-alias ELSE drop THEN ; : shutdown ( -- ) initialized? IF my-phandle node>path open-dev ?dup IF virtiodev virtio-scsi-shutdown close-dev THEN FALSE to initialized? THEN ; : virtio-scsi-init-and-scan ( -- ) 0 0 get-node open-node ?dup 0= IF ." exiting " cr EXIT THEN my-self >r dup to my-self virtiodev virtio-scsi-init 0= IF scsi-find-disks setup-alias TRUE to initialized? ['] shutdown add-quiesce-xt THEN close-node r> to my-self ; : virtio-scsi-add-disk " scsi-disk.fs" included ; virtio-scsi-add-disk virtio-scsi-init-and-scan 0build_info.imgprintf t[CC]t%sn build_info.img; gcc -m64 -mbig -mabi=elfv1 Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/powerpc64le-linux-gnu/7/lto-wrapper Target: powerpc64le-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.4.0-1ubuntu1~18.04.1' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=powerpc64le-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --enable-objc-gc=auto --enable-secureplt --with-cpu=power8 --enable-targets=powerpcle-linux --disable-multilib --enable-multiarch --disable-werror --with-long-double-128 --enable-checking=release --build=powerpc64le-linux-gnu --host=powerpc64le-linux-gnu --target=powerpc64le-linux-gnu Thread model: posix gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1) GNU ld (GNU Binutils for Ubuntu) 2.30 Supported emulations: elf64lppc elf32lppc elf32lppclinux elf32lppcsim elf64ppc elf32ppc elf32ppclinux elf32ppcsim <