(headermagic123 pdwgqemu0 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-0ad10f26c94a86a0b#A@aHPX`hp!xAa!Aa!Aa (8}@}H} /| 0!8N |)< !A@aHPX`hp!xAa!Aa!Aa (0}8}8}@}&H}PHb#|xH-8}@}H} P}A@aHPX`hp!xAa!Aa!Aa (!8|B| |B||BL$`N H[?25l ********************************************************************** QEMU Starting  Build Date = Oct 18 2012 16:14:52 FW Version = git-0ad10f26c94a86a0 |hHAK 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@s @(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`cm<`xd`VTA8| B< `!x!d!`!8a|H58`xH< `!x!d!`!8!a|hN <@`BxBdB`BØ8B@8B@N |fx8`8<`DXK|8Tc0T0| PT||l|||L,8cBN |="9)}=bx`x$})*|dx;/!A4 A(| iIN!A(8!|N 9 / /@xpxc$|*N |#y|||x!A ?{8<@xHe`="9)}8+A4c;8 T>+A/|A(/AL8!x|N 8H`8!~x|N 8H`8!~x|N |A|3x<E`LFa؁#|;x|#x;|+x!a|x@\;/@L#;8 T>+A4#;8 T>+A/|A8/A8!xA|aN HY`ExPxxfxH}`8!x|AaN H`ExPxfxxHQ`x||~xHU`8!xA|aN |<E`LF!c8A8!p|x|N c/@c9kUk>+AСc9kUk>+A#/A,/@H)`8!p|`x|x|N H`8!p|`x|x|N |}&.%-胣|3xA|#x;@;|+x!|xaؑ!AH ,;*A؀/@/A} {=cxA,A(| ~^N!A(/@|cxHq`}8|(Px |{H`cx/|xAPAL;A(| wWN!A(,*@08!@{C |!Aa} } N ]} ZPZK ,|@.}B/ADC*9`}(R|H| 0./A$8 8}(Kx| })R@8`N h N |}&.%- |3xA|#x;@;|+x!|xaؑ!AH 8;6A/@/}@ ]ZP{=cxA,A(| (~^N!A(/@$|cxH=`} 8(|(Px |{H`(cx/|xAHAD;A(| wWN!A(86@(8!|z|!Aa} } N   8|@.}B/ADC69`}(R|H| 0./A$8 8}(Kx| })R@8`N hN |!>#(:&X>#a?;`|#x;8A|x:&8!AH<;{;@{AԀ/@>^y)6d}9J {Z6dYx A/A 8;}?@.}B|*/8|*A̡_69`}(R|H}(Kx})R| 0./A8 8| @}?(*x"x $x.| Pc}bx }b+@ }|Z})| @x~óxH-`>J@x@ }?@.}B|*/8|*@<}?(*H@@h~xH`K9xxd}KR}jZ}iN t@tt4 ttttttttttttttttttttttttttttt TtHtttttttttttt | KpT: Kdx x|  KPx KD K+ I|+xi|x|#x!a8ApaxAT @@p="i}/Ac9@- }K#9)#9ap}k8i?9)?8!|x|N +xK-9ap?8!8|xP}k讙i?|9)?N #Kd|a}Cx|;x|3x|~x|#x|+x!a8 8H`/|c9 A 9 9)})/@y) })H@<})P/})@,9)y+ >9k}i>9)>B8!8`a|N ||ixa>b:s&>!;a|#x|{xpx!AA!;@|1/A8}{HP@,/%A 8!p/9)!p@8 ap8!@|{P|cp|x!Aa!AaN 8%9ao 9@9 |+x/d}Ax/iA$/uA$/xA$/XA$/pA$/cA$/sA$/%A$/OAL/o8A } Cx9 |+x/d}@9j}k}aZ8d}Bp9 paq/0Ap/.: ;qA`/}{xAl:;:: : 0}H88 T>+ A8p} i;{ };/A@8 T >+)A95lx| } J})N |(\@\$|\(8o9j}k}aZ}Bp9 paq/0@ar:0;r/}{x@8K9!p88 8aH]`x xK`@@8|cPxc!A,8c!pxc 8c|i!p9)!pB;H$|;!p{ !p8 pxK`@AK(8p}  8x88 9xK!pxx)8!p8 p8x !p8 pK]};/@!p}{x8Kԉ}8/lA|x:K}8/hA|x:KxV88 ~698p}  xA,!p8- z$}3JapI8 p}Ґ8~Ex8 ~x98xKx~Dx8 K};K8p}  x888 8 9K!p};!p8 pKz$}3JI8p} Ґ8 8~Ex~x98xK5x~Dx8K};KXz$}3JI8p} Ґ8 8~Ex~x98xKx~Dx8K};K}:;K}:;K8iK8uK8xK8XK8pK8cK8sK9j8%}k }B}aZp9) p!p8K8OKP,$|ixA +$$8`@N 9)$i/ / , A/ AAA/}*Kx@/08 A/8`M 8`H,|4(9)L |c)$i/|`A8 T>+ 9KUJ>+ |4@8 T>+8 9k@M }`4(9)AN /@p/08@d /x@@8 i| xKDN +$8$8`@N /xA 9`0K 9)$jKPPP exception %llx SRR0 = %08llx%08llx SRR1 = %08llx%08llx SPRG2 = %08llx%08llx SPRG3 = %08llx%08llx ERROR: 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%s%s[?25h ELF relocation out of bounds! ERROR: Unhandled relocation (A) type %i 0123456789ABCDEF@CICJ,CK8CK\CMCN$CO COxCPCR CRCTCUCVCW4CZCZC[8C[C\$C\C\C]`C^C_CfpCC?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 60ofw_mainELF@H@8@ 1?c?c?ca?c0||<``cc`/Hp|1CB|(!Aa (08@!HAPaX`hpx!Aa!Aa8`|x|B|B, @|<||&||B|B| |(|0|8B |H"|!8!<@x|BL$|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]N!KU|8`N |8Tc0T0| PT||l|||L,8cBN ||3x| N!|N |!H7`8!p|N 8c|+|+x8`!q@ 8!|N /@;{ ;HH7`A0/ @8` H6`H6`@8!x|N /|!Axc H6`8!p|N |="9i|}x p/x!Aa!Aa!@P=B8j$?}j[x8`j <<8a(9X8a 8hX;hPgK{A="9Ia(*8  {A="9Ia(*8  {@\{@`;X;|(??_=>>">B>b>>`>>;wIN {8`A="9)a(i8 k 8!Pp|x!Aa!AaN ="9Ia `9k*;X;|8 i K9~a(;{+8b9I_K IN 9~a(;{+89I_K IN 9~a(;{+8Q9I_K IN 9~a(;{+8s9I_K IN 9~a(;{+89I_K IN 9~a(;{+89I_K IN 9~a(;{+89I_K IN 9~a(;{+ 9I_K IN 9~a(9B ;{+ 9I_K IN 9~a(9Va+;{ 9I_K IN 9~a(9Wr+;{ 9I_K IN ="9~a(9IB+;{ 9I_K IN ="9~a(9I+;{ 9I_K IN ="9)a ik9ki;_IN ="9~a(9Ia 8+ 8h9  _IN _IN _IN 9>a(i 9ki;{_IN 9>a(i 9ki;{_IN 9>a()i|  ;{_IN 9>a(;i9ki;{_IN 9>a(;i9ki;{_IN ;{{;{_IN 9a(9;oK/@})9ko;i_IN ="9)a ik9kxi_IN 9>a(i 9ki;{_IN 9>a(i 9ki;{_IN 9~a(;{+_ 9IK IN 9~a(;{+_ 9IK IN 9>a(;{)_ |x$| * IN 9>a(;{ _0 IN 9>a(;{)_ i iIN =b9>a(9Ka j98;{_  IN ="9^a(9)a j 89_;{  IN ="9~a(9)a ;{I+ 9I_K IN 9~a(=B9J+;{8 }JP_}Jt IIN 9>a(=B8 i;{k_9kyk$|  IN ="9~a(9Ia ="8 "J+|PP|t9I_0K ;{IN 9>a(<=B8"i;{ 9k9Ja 9_y$i| IN 9>a(=b9ka )k ;{x$}`XP_ IN 9>a(;{i_K |  0 IN 9>a(;{i_K |PP 0 IN 9>a(;{i_K |  0 IN 9>a(;{i_K }@6 0 IN 9>a(;{i_K }@6 0 IN 9>a(;{i_K }@4 0 IN 9>a(;{i_K }@8 0 IN 9>a(;{i_K }@x 0 IN 9>a(;{i_K }@x 0 IN 9>a(;{)_i IN 9~a(;{+_I 9)+ IN 9>a(;{)_i IN 9~a(;{+_I 9)+ IN 9>a(;{)_i IN 9~a(;{+_I 9)+ IN 9>a(;{)_i IN 9~a(;{+_I 9)+ IN 9>a(;{)_i IN 9~a(;{+_I 9)+ IN 9>a(;{)_i p qp IN 9^a(;{*_ i9)x"p* q IN 9>a(;{i_+ t u v wt IN 9a(|) x;{H_ j9JxF" tH      IN 9>a(;{i_K |&T|| 0 IN 9>a(;{i_K |P| 0 IN 9>a(;{)_ |v IN 9>a(;{i_K }@x0| 0 IN 9>a(;{)_ 0| IN 9a(="9ia H;{ +_ 8 9J HIN 9^a(9;j9 8 A =b9Ka j8  ;i_IN ="9)a ;{iK9JKi KPA#`{;{_IN 9a(="9ia H+8J /;{}GRI+A"I}@PP8|8PP@@ `9)+;{_IN ="{9)a ;{{Z ;{0 _IN 9~a(9;K 9JK/A=b9ka }) 0 ;i_IN ="9)a ik9ki;{_IN 9>a(i8 _IN 8a(g_9+ '9 8+ 9{}Kx|xx`/A /A l/@0@@A $|0@@ /}ZSx}{[xAH}|x| |B}B|:}(:4 @}ZSx}{[xIN ="9)a ik9ki;{_IN 9a((8 8 IxE|;xix9)}F[x(x`/|x}ISxAd/A /A9k/}JZ}KPP}I@ B;{_IN 9a(/I8 8 / 8i@8@A xA$}I} @PB@}HXP@A X@8 ;{_IN 9~a(8``c+;{_8 8 |;x9)+|+xx`/A/A/@8x9D"IN 9a(O8 *8 8  H9;A8 }z[x};KxIN 9a(9;H9HO/hAPA;{8{x!aHm`5!|xa|x@=B9 xhO|B }z[x};KxIN 9>a(;{i_8 k 8 H1Q`IN 9>a(;{_oH1=`oIN 9>a(;{_oH1A`oIN 9>a(8`;{I8 8 H0`z}{xIN 9>a(8`;{i_8  H0q`IN 9>a(;{_8 oH0`oIN 9>a(8` ;{I8 8 H/`z}{xIN 9a(;{/_ 9io/A 9koIN 9a(;{/_iHh`/8 iIN ="8i88_`;{Hj `IN 9~a(=B;{+8 9I_K IN 9>a(8`;{_H/`oIN 9>a(8`;{i_8 8 H/`IN 9>a(8`;{_H/]`oIN 9>a(8`;{i_8 8 H/=`IN 9>a(8`;{_H.`oIN 9>a(8`;{i_8 8 H.`IN 9>a(8`;{_H.}`oIN 9>a(8`;{i_8 8 H.]`IN 9>a(;{I8 8 8 8 zH.`z}{xIN 9>a(;{_oH.`oIN 9>a(;{_8 oH.`oIN 9>a(;{_8 8 oH0`oIN 9>a(;{i_8 k H2`IN 9>a(;{i_8 k H3`IN 9>a(;{I8z 8 8 H3`z}{xIN 9>a(;{I8 8 8 zH7`8/@8}{xIN 9>a(;{i_8 k H8=`IN 9>a(;{_8 8 oH8U`oIN 9>a(;{i_k8 |c4Hy`IN 9>a(;{i_8 8 8 k H`IN 9>a(;{i_8 8 k H`IN 9>a(;{i_8 8 8 k Hm`IN 9>a(;{i_8  8 k Hq`IN 9>a(;{_8 oH`|ctxcт8coIN ;{_H5`IN 9a(="8xox8x;{k_H`/x /8 iIN 9a(="8xox_;{8 8xkH`/x /8 iIN 9>a(;{_oHH5`oIN 9>a(;{_oHI`oIN 9>a(;{_oHM5`oIN 9>a(;{_oHN`oIN 9a(;{/_iHH`0IN 9a(;{/_iHJA`0IN 9a(;{/_iHL`0IN 9a(;{/_iHNE`0IN 9a(8a8/;{_HO`a9++/@ /8 i8 IN 9a(;{o9+K/9!{E 9ko}#Kx!Ha)` !8x |iH``!88a}%Kxx HN`a9++/@,9Ii9` O|xiIN 9a(8 9`/;{_8 8 | 8 I8 9!8H|P|Y9kB@@A| Y9kB}%Kx8aHP`A//@l8 8 IN 9a(;{/_8 i8 8 HRi`//8 @8 IN ;{_HT`IN ;{_HO`IN ;{_HT`IN 9a(9!}#Kxo;{8 K8 {E !H^`! 8x |iH^`o!8 8 }%KxkHV=`|`yAO8H\`/z8 A8 IN 9a(8a;{/_9i ox 9)/H^)`9!8 |ix H]`O9!}#Kx9j o9jx o!H]`8! |ix H]y`o8!8 8 }%KxkHV`/,#8 A 8 IN 9a(8a;{/9iIo{E 9)/H]`9A 8x |jH\`o89+/9+k/HW-`/,#A 9io9`i|xIN 9a(;{/_8 8 iHN`/,#8 A 8 IN 9a(;{o_9+ /9!x 9ko}#Kx!H\ `8! |ix H[`O8a9j o9jx oH[`9a8 |kx H[e`o8!8 8 }&KxkHW!`/,#8 A |8 IN 9a(;{/_8 8 iHL`/,#8 A 8 IN 9>a(;{i_8 8 8 耋 8 k xc H?)`IN 9>a(;{)_ ||L,9~a(9)+IN 9~a(;{+_8  | IN 9>a(;{)_ ||L,9~a(9)+IN 9~a(;{+_8  | IN 9>a(;{)_ |9~a(9)+IN 9~a(;{+_8  | IN 9>a(;{)_ |d9~a(9)+IN 9~a(;{+_8  | IN 9~a(;{+_8  8 IN 9~a(;{+_8  8 IN 9>a(;{i_ ||||||||9kiIN 9~a(;{+_8  | IN 9>a(;{_8 HM`oIN 9~a(;{+_8  8 IN 9~a(;{+_8  8 IN 9>a(;{)_ |9~a(9)+IN 9~a(;{+_8  | IN 9~a(;{+_8  |B IN 9~a(;{+_8  | IN 9~a(;{+_8  | B IN 9~a(;{+_8  | B IN 9>a(;{)_ |9~a(9)+IN 9~a(;{+_8  | IN 9>a(;{)_ |K9~a(9)+IN 9~a(;{+_8  |J IN 9>a(;{i_ |C9kiIN 9~a(;{+_8  |B IN 9>a(;{i_ |C9kiIN 9~a(;{+_8  |B IN 9>a(;{i_ |C9kiIN 9~a(;{+_8  |B IN 9>a(;{i_ |C9kiIN 9~a(;{+_8  |B IN 9>a(;{i_ |K9kiIN 9~a(;{+_8  |J IN 9>a(;{i_ |K9kiIN 9~a(;{+_8  |J IN 9>a(;{)_ ||æL,9~a(9)+IN 9~a(;{+_8  ||¦ IN 9>a(;{)_ |l|||L,9~a(9)+IN 9>a(;{_oK`oIN H9>a(8;{I8z Kz}{xIN 9>a(;{I8z KϹz}{xIN 9^a(;{*_8 i 8 ) }kJ9kU)0Uk0}iXPUk}i|Hl||O|L,9)BIN 9>a(;{i_ |9kiIN 9~a(;{+_8  | IN 5*x|Cx9 A,9J/y*9J@9@5J 9)@5Ix 9 A,9)/yI9)@9 5)9J@}ISx5IA9)/yIBx 9k9)A5) @;{_IN }):KtiIN 8 IN 89D"IN iIN |xi8 IN iIN iIN 9i 8Io IN {B;{_IN @@@`/}ZSx}{[x99)A 4@}ZSx}{[xIN 9 K/A9i oIN |0@@/}ZSx}{[xA|x|}| |B}B}&: }(:8 B}ZSx}{[xIN 9io9`i|xIN 8 ;{_IN /}ZSx}{[x99)A,4 @}ZSx}{[xIN @@@|/}ZSx}{[x99)A4@}ZSx}{[xIN @@@/}ZSx}{[x99)Aά4@}ZSx}{[xIN |0@@/}ZSx}{[xAp}|x| |B}B|:}(:4 @}ZSx}{[xIN | x K`|0@@\/}ZSx}{[xA }|x| |B}B|:}(:4 @}ZSx}{[xIN 9kiKܠ8x9D"IN 8xB9D"IN 8 ;{_IN =8K /8}z[x};KxAP;G;hH 4Atz!aHN=`|jx{AHN)`AP!aAO8}z[x };KxIN 8 IN }z[x};KxIN }|#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 N xf8`X88D"N |jx8`T8D"|#yA xF jN }|ixi,AK9)K}N }|ixy#' pc, A8c8c0K}y#F pc, A8c8c0Kay#e pc, A8c8c0KEy# pc, A8c8c0K)y# pc, A8c8c0K y# pc, A8c8c0Ky# pc, A8c8c0Ky#"pc, A8c8c0Ky#'pc, A8c8c0Ky#Fpc, A8c8c0Ky#epc, A8c8c0Key#pc, A8c8c0KIy#pc, A8c8c0K-y#pc, A8c8c0Ky#pc, A8c8c0Ky#pc, A8c8c0K}N }|ixK}|ixKt}|ixK|H||8xxgj|8|8N }h|ix8`CK}#KxK18`K8`K8`K8`K8`K}hN }h|ix|#x|+x8` K8` K}cxK}#KxK8` K}CSxK8` Ky8` Kq}hN 8EK}hK1}h8W@N }h8 K}h8D@tN }h|#xTc@.K8`A8`}hN |H|8Tpc|2|N N ||#x<E`LFc;!@\;/@Lc;8 T>+A4c;8 T>+A/|A(/AL8!x|N 8H`8!~x|N 8H`8!~x|N |A|3x<E`LFa؁#|;x|#x;|+x!a|x@\;/@L#;8 T>+A4#;8 T>+A/|A8/A8!xA|aN HY`ExPxxfxH}`8!x|AaN H`ExPxfxxHQ`x||~xHU`8!xA|aN |<E`LF!c8A8!p|x|N c/@c9kUk>+AСc9kUk>+A#/A,/@H)`8!p|`x|x|N H`8!p|`x|x|N |}&.%-胣|3xA|#x;@;|+x!|xaؑ!AH ,;*A؀/@/A} {=cxA,A(| ~^N!A(/@|cxHB`}8|(Px |{HBA`cx/|xAPAL;A(| wWN!A(,*@08!@{C |!Aa} } N ]} ZPZK ,|@.}B/ADC*9`}(R|H| 0./A$8 8}(Kx| })R@8`N h N |}&.%- |3xA|#x;@;|+x!|xaؑ!AH 8;6A/@/}@ ]ZP{=cxA,A(| (~^N!A(/@$|cxH@`} 8(|(Px |{H@ `(cx/|xAHAD;A(| wWN!A(86@(8!|z|!Aa} } N   8|@.}B/ADC69`}(R|H| 0./A$8 8}(Kx| })R@8`N hN |!`#(:€ `#a?;`|#x;8A|x:!AH<;{;@{AԀ/@>^y)6d}9J {Z6dYx A/A 8;}?@.}B|*/8|*A̡_69`}(R|H}(Kx})R| 0./A8 8| @}?(*x"x $x.| Pc}bx }b+@ }|Z})| @x~óxH?`>J@x@ }?@.}B|*/8|*@<}?(*H@@h~xH>`K9x,xd}KR}jZ}iN t@tt4 ttttttttttttttttttttttttttttt TtHtttttttttttt | KpT: Kdx x|  KPx KD K|#x8`@88x D"|8`<88 D"/8`xc @x T>TD.|cx|cN |x/8@x T@.T>|#x8`@88x D"|8`<88D"</`x`@4x x U >xU)D.})xT>TD.U)|[x|Kxxe|xN ||}x|#x!qK)x|xxK8!xc&||N ||}x|#x!qK}x|xxK%8!;xcd||xcN /L 88`@88D"N /L x T@.T>|#x8`@88x D"N |#x/L 88`@8x D"N |#x/L 88`@8x D"N |#x/@(/;AX@(/A/Al8`N /@8`<8|D"/8`@x K8`<8|D"/8`xc @x K8`<8|D"/;{@x88`<8|*D"/8`xc @x |cxKL8`<8|D"/8`xc @,x K$||3x/A$;x|N /#@9i8;x |Z||(P|;8`<8xD"/8;@x |4|@x|N |8|x!Kq`x8Ka`x8K`x8K`888xK!`8!8`|N |8|x!K`xKY`8!|N ||#x88|3x|+x8|~x!Aa!1pK`}?8 @Ax8K`8xz xK%`8|yxxK`8|xxxK`<|{xT<}}(Ӗ<ǣ09G09`jWH,})Ӗ})@P}(8y&8}Y1*}929@i I|Ӗ|Ӗ|||(Px x&䰉}Y*)*9 j* _|8Px x&}9:i9`i 9`i9Ap}Y9*}:Py)}8J |8x88 K`;@@(<`| HB@|@Ap/@88!|!AaN p`8bH2`8!8`|!AaN `8bhH2`8!8`|!AaN  ||;x!|yxAa|3x|+x|#x!A8K`8x{ #xK`8|xx#xK%`8|zx#xKu`||xT <|ۖ})}Iۖ}J}JHP9*|ۖ}JyH&}xBA*9 |e}'HPy' x&}8BA*9`i 9`i};Py)}:JI|:#x88 Ke`\@@H= })a)| `| H }iB@$|9iP@A/8`AL}7y` T >ykTD.|SxUj>UkD.T}kSx|[x@})|AD78`8!|!AaN | xK ="ɣ@|/|#x8|+x!q|x@8ɣ@Ky`x8Ki`x8K`8xK`88xK-`+@8x8|xKi`xH}`|yAX`8bxH-`xH)`8!px|a} N xH`8|y@x88pHq`8/|xAD!p /@8axH5`.#|x@8ax8H `.#|x@;/@HA@@|(P|x8axx H `/|{x/#@`8bHdxH,`x.;H4`x8bH,`K`8bxH,`;xxH`xH`@8!px|a} N `x8bH,`K0`8b0xH+`;Kx;NKl=b9+HkHN |8?;H!8 H)`88 H)`="9)h8! |N |=b??H;H/!8`9khpA/8`A/A+ 8`A|(P|x X@8`Ayk U`>UkD.}kxUkd8p A(| iIN!A(/8`@p_8`* U'@.T@.U)>T>|Kx}x})4|4@4 /kA} xx +A|x8axH'``8b`8xH)`8`K||}x`;p!qK=";h9`x?8 i8d x  U+>xU)D.})[xT >TD.|[xU)} x9 8<H%`?xc T`@.Tc>|x|;xH%`x|exxH'U`xH%`|xKM|y@|="]9)H$y+ U`>y)UkD.U(>}`xU)D.T})Cx|KxP@A\$ `8bU >U%D.|x8 x H%]`/A08!x|N }@SxK;K||~x!Aac!QH$`|x~H$`;@AK=";h9`;?8 i8h x  ~U+>xU)D.})[xT >TD.|[xU)} x9 8 <H#`?xc ~T`@.Tc>|x| ;cxH#`dx|exxH%U`~?H#`|zx~|H#`xc T`@.Tc>|x;{|y.xH#a`x|excxH$`~H#=`8!}<.8 !xA|aK8!8`!|AaN ||#x!qapK="9)h9{ i{ 9K9xI T >TD.|SxiW>apWD.TSx|x8 8!8  |K|A!|3xF|tx/8`a|#x|+x!Aa!AK=";Ih89n:{ {9i z{ {ބUH>Uf>:UJD.UkD. }GCxW>}j3xWD.W>WD.TCx[xUJ|Cx}J[x 9i I8~_xz`; :>b/A//x@@ ;//A/xA,xxHA ;/// @P{} ~xxxH `/A;H:x}kHP9k}k@A;W:W 6}kPP}k9k @A{` T @.T>}kx8 i|xxxH!`/`zA~ٳxx/@6xx/@`~CxH`/8`@?8;H8~x KY,#@8 T >TD.| Kx}kA48 /| A`~Ix//@ :R//A~Ix/@ KA9)/// @8 /}2Kx| @Qr|cxc8!!|Aa!AaN xKx;;`K6x//@/:A{  T @.})4T>} x?x 6x;HKx8KQK<||#x|x!qKU="9)h8s_ix9K 8pI ix  UH>xUJD.}JCxT>TD.UJ|Cx}@x9  9@K i8  K=,#@@="9)H) x  U+>xU)D.})[xT >TD.U)|[x} x8!|N |a|3x|#x|+x|~x!aK)?8 @@|x="9)h9@{f ix U>8 K 8t {k"y` ^ykTD.xƄT>UD.y@ T>}#x|;xU{D.Ue>TD.{ TD.yJT>U|x{+xUcD.{"Ue>iT#x}3xU^>|e+xUJD.T>|xTD.TxT|x}Jxx |;x|x|Sx9 K8x 8  K}|y@\="9)Hx  U+>xU%D.|[xT >TD.T|[x|x(@|x A<x8 H`8!xa|N ;K||x!KQ="9)h8xi9K 8|I ix  UH>xUJD.}JCxT>TD.UJ|Cx}@x 9@8 K KI,#@="9)H)9i*ky`"yk x  yh U>UG>xykUD.UJD.}3x}J;xUf>T>UkD.TD.U}k3xUJ|;x} [x}@xykx }`x 8!|N |=B|#x9*px !|hx `i|x8b p}Cx}f[xH`8!p|N |=b9+p8!aI|ix9JP@AL8x8kp8`|8p`c8at8t!K߭`p8!|x|N |x} x;!qKI|~x|}xc ;K5/{ @8!W>{ |N |="9)p|`x!qi9kX@AL)8`|8ȑ!p9 9`!t9 8a`c!x8pKޑ`8!|N |=b9+p8!aI|ix9JP@AHKp8`89`x`cAt8pa|8t!aK `p8!|x|N |?;p;/!qAh8`HLK|~xxK8x @@K|cTc 6|cA,|@xc @KI8/x @8!x|N |="9)p|`x!qi9kX@AHi8`9 |9@ap8A9`!x`cat8p!Kܵ`8!|N |!|#xAa||x|+x;|3x!QW6Ku="9)pi|zxKa|cP@@@8!8!xA|aN {[ cx{$ K&p|8zxc x K;;{H|;{ KxH `@|{xc ACxK |dx8zxc K8!;ZZ!|x\aAN |="9)p!qK5`8|0P88ap8|Kaap8!|ct|xcтhcN |=b9+p8!aI|ix9JP@AL8x8kp8`|8p`c8at8t!KU`p8!|x|N |="9)p|`x!qi9kX@AL)8`|8ȑ!p9 9`!t9 8a`c!x8pKٽ`8!|N |8@x x!Ka8xc 8KQ8!8xc |8K$|=b9+p8!aI|ix9JP@AL8|8kp8`8p`c8ax8x!K`p8!|x|N |="9)p|`x!qi9kX@AL)8`|8ȑ!p9 9`!t9 8a`c!x8pK=`8!|N ="9)pi8@Ai/@8  |xN ="9)p8 N ||`x!q8ap|x8!AH}`/|}x@4;{ 8p;o88K`@8!x|N |?;p}&/!A|+xa|zx|#x8;!1A.$--:;:; 8xc K]||xxK@8xc K|~A/At@A:;z ~x{ ~óx:K@uz @x$x8 H`/AW 6~@~z AX8;8!Cx|!Aa} } } N ~óxKQ@tK ;8T 6|K| || |!@$|x{ 8;K@8!|N ="9)p 8`K/|8c|c!8@ 8||xKM8!p8`|N ||#x8|+x8|x!a|3x8apK!xap8+@ 8K]x8apxxKaxpA ;;K8!x|N |a8+8!Q@?;ޣpx @#{ @{ cK%{{ |dxcxK-8|@xc A8|K8ap88Kx8apK5K88!|xa|N { K||`y!8`A||KE8`8!p|N  |||x;|#x|+x!Aa!!@H8!x|!AaN 8ap88Kxp/A|PA{ { ;||@?B;Zp:P@A\/@P8/A<;x=x{ ;K wA{ ~~x~x8KM~@ z :K~@8H~x~x8K{ {P#xd;Ke{ { Km;KUK |="9)p8`?ib!acm, K<CPp`U0xdlo`g8at8p8Q8K<CP`U1pxdlo`g8pt8Q88aKMxK9xK1`8bK `8a8p88KKu8!|N N ="9)piN ||#xx~ |xx!qK`|}xAHX|AP{ K`8xW>/|}x@8!x|N 8!;x|N |8?;|#x|~8!qx;H`{ K`;|`yx/A89?A0{ |}?K`|`y;x/@H9`x|exxHa`/?/;A @|;8!x|N |~y|8`|+xAa!aA?;;;|;@{ K`;|`y}<x/A@}*Kx9A4 { }K`;|`y}<x/@țIH!`dx|exxHI`/?/A@\;|xc K`||;A;x{{? ;{{ x;K`@{ @9xPK`CxKm`88!|x|!AaN }&|y||3x|#x|+x!Aaؑ!QAK|{yAxH]`x8x cxH`/8`@88!|!Aa} N xxKIx|zxxK#P=|~xxKY`|{y8`A.@D;|xc K5`|{;A{ K`8/=A |{ K`8/=@;;H||;K`xH5`8{ A8|}x|K`@@;;{ ;K`@;cxK`8`@{ 8;KI`@8!8`|!Aa} N 8`K$8!xx|x} x!AaK9 /A9)})/@y) }#KxN ,%8At#/A\/Ad/A\@})@@8x 8|H/8 @A,B@(@$#/@|HP||xN })K/At/M 9eyk 9k|ix}iHB@L 89)x /@/M 8x 8|9)8 BN N |ixK,%M 8x 8|x 9#BN ,%M 8x 8|89# BN @@L|*@A@/M 88x 8|}#|89) BN /M 8x 8|89# BN 8+M 8c |cN 8+M 8c|cN ||+x|#x!8|xx`H`8!p|N |=b|`x!8kШ|x8!AH`8!p|N |=";Ш|~x!qK`x|exxK{``|~x88K{u`8!|N ||+x|#x|x!A|x8@8apHi`8p|~x{ Kz`8!x|N |`9"8T>+ I|+xi|x|#x!a8ApaxAT @@p="iH/Ac9@- HK#9)#9ap}k8i?9)?8!|x|N +xK-9ap?8!8|xP}k讙i?|9)?N #Kd|a}Cx|;x|3x|~x|#x|+x!a8 8H`/|c9 A 9 9)})/@y) })H@<})P/})@,9)y+ >9k}i>9)>B8!8`a|N ||ixa`:b>!;a|#x|{xpx!AA!;@|1/A8}{HP@,/%A 8!p/9)!p@8 ap8!@|{P|cp|x!Aa!AaN 8%9ao 9@9 |+x/d}Ax/iA$/uA$/xA$/XA$/pA$/cA$/sA$/%A$/OAL/o8A } Cx9 |+x/d}@9j}k}aZ8d}Bp9 paq/0Ap/.: ;qA`/}{xAl:;:: : 0}H88 T>+ A8p} i;{ };/A@8 T >+)A95px| } J})N |(\@\$|\(8o9j}k}aZ}Bp9 paq/0@ar:0;r/}{x@8K9!p88 8aH]`x xK`@@8|cPxc!A,8c!pxc 8c|i!p9)!pB;H$|;!p{ !p8 pxK}`@AK(8p}  8x88 9xK!pxx)8!p8 p8x !p8 pK]};/@!p}{x8Kԉ}8/lA|x:K}8/hA|x:KxV88 ~698p}  xA,!p8- z$}3JapI8 p}Ґ8~Ex8 ~x98xKx~Dx8 K};K8p}  x888 8 9K!p};!p8 pKz$}3JI8p} Ґ8 8~Ex~x98xK5x~Dx8K};KXz$}3JI8p} Ґ8 8~Ex~x98xKx~Dx8K};K}:;K}:;K8iK8uK8xK8XK8pK8cK8sK9j8%}k }B}aZp9) p!p8K8OKP,$|ixA +$$8`@N 9)$i/ / , A/ AAA/}*Kx@/08 A/8`M 8`H,|4(9)L |c)$i/|`A8 T>+ 9KUJ>+ |4@8 T>+8 9k@M }`4(9)AN /@p/08@d /x@@8 i| xKDN +$8$8`@N /xA 9`0K 9)$jK@|xADBLCDFxFHILNtNO<OPXPPQ<QtQRSTHTW\YZhZ]]^H`acd|h`i|kllmmn4noTpprrtssstuu\u|v0xxhxxyzz|}}}~Td,h<l ELF relocation out of bounds! ERROR: Unhandled relocation (A) type %i elf-claim-segmentvirtioblk_read: Access beyond end of device!virtioblk_read failed! status = %i slofVersion check failed, rc = %d Attach failed, rc = %d Walk failed, rc = %d Stat failed, rc = %d Open failed, rc = %d Read failed, rc = %d Error: %s 9P2000.uunknown. NVRAM: size=%d, fetch=%x, store=%x free spaceCreating common NVRAM partition common 0123456789ABCDEFHBP |FORTH-WORDLIST 80*LASTWORD PXEVALUATE (@`xpPP`(@`(x* 8`(8@`8NOOP P SEMICOLON0 INTERPRET 0``Ph`HP SAVE-SOURCE (x(@((((P*-1 0DOTO h`(hPh SOURCE-ID DUP X#IB x!DSPAN IB DOTICK ,CATCH ((8XPRESTORE-SOURCE @x(PTHROW p``x(P0 (RDEPTH!LIT =0BRANCH SWAPDROP BRANCH x(CLIENTINTERFACE |H PRINT-STATUS 8`h`(8`@`0 `P`(@`8 `hPQUIT H(>8(`P8p``xHPSTRING, *P(BOOT-EXCEPTION-HANDLER |EMIT |p((FIND)) ``x(8p`(pPX(FIND) |2DROP P(REVEAL) |POVER 0-\HEXITINTERPRET-WORD `(X((` `(P(P>IN  PARSE-WORD (0PSTATE `@ COMPILE-WORD `P` X(((` `(P(P?LEAVE h`*PR>ph>R0CELLS+ 0PPCELL+ PACCEPT |#TIB  ABORT"-STR DEPTHCATCHER RDEPTHX8EXECUTE H?DUP ```PDEPTH! @ BREAKPOINT 0<lPICK EPAPR-IMA-SIZE + JUMP-CLIENT4pPRINT-EXCEPTION `(@`8 `(`(@`(@PPSPACE P00=Ð PRINT-STACK `(((POK-STRok ABORTED-STRAbortedĨCOUNT ``xPTYPE  X(pŰPCR |Ÿ' 0Ƹh` 0xXPX[ hPTERMINAL x@P. H`8PȠREFILL @h`8Ȱ0(@@`((ePPPLACE X`x XH`pX`pɘPɠ1+ p@PCHARS PALLOT *@*P(DUMBER 8X(8XPʐLINEFEED ʰ2DUP PR@ LINK>NAME hP NAME>STRING ` P8 STRING=CI3DROP P FALSE ˠ2OVER P LATEST +$DO?LEAVE0($FIND) H``0`Hx0PxNIP xP͈$NUMBER `h` 0((`((-@``x``h`(0(((͠h`8x`(0P(SOURCE xP SKIPWS `H`p@x`(pX`PhBL ϘPARSE (@ϰ`0`p@`XPи\ 0PXOR IMMEDIATE? (H`PXCOMPILE, ѐPLEAVE h(*P?COMP h`((zPPPLEAVES ҈ HASH-TABLEҨCHARS+ PNA+ @@PxCHAR+ pPӐNA1+ @PKEY? |@ABORT PPRPICKERASE (HPSLITERAL h``@(H(PPU<0h EPAPR-MAGIC Ԡ UNKNOWN-STRUndefined wordHW-EXCEPTION-HANDLER |PLL-CR ʠP NOSHOWSTACK P SHOW-STACK? .S ``(X@pŰP(SPACES X8ŰPC@t`BOUNDS @xP՘DO?DOHհI x(PHDOLOOPSET-UNDEFINED-WORD @( `x`@x`@XPh$FIND `00PTRUE 8DOABORT" x`((PP`OFF xPTIBx(U.) ׈PP(.) `(ذP`PEXPECT PِALIGN *H` PC!1 ŠDO+LOOPU* pPxCELL- Pڨ/C* pPDAAR +! @xPHCARRET `TUCK xPhCONTEXT ۈ8LINK> HPREVEAL  8 ܐP3DUP Pܰ3 ɀDOLEAVEp (FIND-ORDER) `(ۀ`hp`((@PNAME> ``P>NUMBER `h`(`x(x((ɰx8ި@`P1- pPNEGATE xP> x`P߀<= HhP߰FINDCHAR xXp@`@`x@`0p0(Ű@P ( ()0P8ORƨ 'IMMEDIATE XANDtp0<> P, *P+LOOP hɘ8P8] (hPREPEAT h PH CLEAN-HASHCELLS @P0CA+ @P`XA+ @P/N* pP CA1+ @PXA1+ @P/N KEY |8BLANK ( HPFILL(<( ROMFS-BASE tHICBI4 EXCEPTION-STR Exception # SHOWSTACK P`.H xPEVEN HPXDODO ALIGNED @HPh UNDEFINED-STRundefined word POCKET (p@p@`(@`P@MOVE@NOT PEVAL PHCOMPU#> 0`P`<# 0`PU#S ``P#> 0`PABS ``P#S  `P`SIGN `(-pPX, *PрC, *XPMIN H`xP*XCHAR- PCELL h/C CRASH5UNLOOP (PBS ܀ SEARCH-ORDER HEADER *ܐѐ P8LAST PhP`2 `U>= hPDIGIT `(A(ZP`((0`ިx` 0PBASE UM* (@ը ŰPROT (xxPD+ (@PpD2/ ((?0P8U> xPx IMMEDIATE ܐh`(xXPPCHAR 0PASHIFT<(0<= xPh<> @hPXLOOP hŰ8P RESOLVE-LOOP p`P`x*x*P-COMP hXh`((*XPWHILE hpxPAGAIN hP`THEN hHPHASHLA+ @P/X* pPLA1+ P@P@/X LCC `(A(ZP`( @P`XLFLIPS  X@ppɘP0 UNALIGNED-L!P FDT-START DpPMC1@4|.D x0PHEX hPx2- PXBFLIP XxXP@ABORT" XP WHICHPOCKET POCKETSxINVERT pPPAD *(@PMU/MOD `(px(P8U# pxpP@# pިpPHOLD 0`xXPL, *PPPX!ؠMAX ``xPXD#10  FLUSHCACHE5`J x(x(x(PBELL `CURRENT U<= ߐhP? PUPC `(a(zP`( PxBETWEEN p@PWITHIN ި`ި8`(H`(0P8*' (`(x`Pޘ-ROT x(xPCLEAR PM+ x(`(@`xPhUD2/ ((?PU2/ p P`LSHIFT2/ phP0WORD @(0`X `HX8`pXŰPRSHIFT>= `hPx?DO X**P+COMP hphX`(** PCOMPILE h`(PxTHERE ( COMP-BUFFER UNTIL h`PHIF `*PBEGIN *P RESOLVE-DEST *hP RESOLVE-ORIG *hxP HASH-SIZE WA+ @P/L* PpP`WA1+ 8@P(/L HXWFLIPS  X@ppɘP@X@|XLFLIP xP UNALIGNED-L@L0HEAP-END PMMCR0!4DhU.R xި``(ĸ`PDECIMAL xPH#10 2+ @PBXJOIN (((P`XLSPLIT `pHx PLBFLIP xHx(P(LXJOIN P`C" h("0`` X(pŰP>>A hPOCTAL P TODIGIT `( H`('@(0@PU/MOD xPUM/MOD (@ըŰxPW, *h8PpL!L H#FFFFFFFF  START-RTAS50>= 8PPACK `(x`XPD- P8D2* (PDABS ``PX2* pP2SWAP (P DO *ըPp.( ()0`PCISTACK d0AHEAD *PENDOF h(PZCOUNT/W* 8pP/W  XBFLIPS  X@p0pɘPXWFLIP xHxP8 UNALIGNED-W! X HEAP-START xDEC!6.R xHި``(ĸ`P8 BLJOIN 0(0PXLWSPLIT `Hxh PXH#20 LBSPLIT x(ppPLWFLIP xxP; hPHHP@>>  PhFM/MOD `(p(x`H`0x@x(P (/' (`(x`0(pP W!XL@$ H#FFFF  CALL-C5\P0> HP (DNEGATE (`hxP X?PICKT ." h`( `(("0`P CIREGS 8 OF h(@pPELSE h*xHPRMOVED LBFLIPS  X@pXpPPɘPHWXJOIN (PXWSPLIT (xxP UNALIGNED-W@ PAFLOF-START  DEC@64 U. `8P4  WLJOIN hP HBWJOIN P WBSPLIT ` Hx PWBFLIP px0P :NONAME *  P << PSM/REM ((ذ`` xxP(M* p((ذذ8`PHW@H#FF +0WRITE-LOG-BYTE-ENTRY +PPS>D `P2R@ (ި(xP Z"  @xXPS" h`( (("0`(@`(xPEREGS hENDCASE hp`(x PLWFLIPS  X@p8pPPɘPHSPRG1!3S. PXBSPLIT (P8*/ HP: 0  Px2R> ި(xPCASE PWBFLIPS  X@p ph8ɘPHSPRG1@48*/MOD ( 8Ph2>R ި(x((P82! `(hPHSPRG0!3MOD P-ROLL `p`H(ިx(pp`0xpP2@ `hxP8HSPRG0@3/ P`/MOD ( 8PPROLL `p`0ި(pp`0pP ҸP >BODY Ҹ@P BEHAVIOR hP!xTO h`((hP"FIND ` `Hި0x`((P"`['] P"[CHAR] 0#P#POSTPONE 0h` 0xXh`0P#LITERAL (P#h [COMPILE] P$PFIELD 0 ѐ@HP$ END-STRUCT P$STRUCT P%ALIAS 0 HP%pDEFER 0 |HP%BUFFER: 0 LHP&8VARIABLE 0 HP&VALUE 0 HP&CONSTANT 0 HP'(DOES> '@P'DODOES> h hP'CREATE 0'P(($CREATE  8(hHP(`INCLUDE 0(xP)INCLUDED )(( Xx(xϰ``(ɘX)P) WRITE-FILE |(MAP-FILE |) UNMAP-FILE |XNICEINIT (+(jxPHERE ԈCLIENT-ENTRY-POINT +`.WRITE-LOG-BYTE-ENTRY 0ROMFS-LOOKUP-ENTRY 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 ! VARIABLE huge-tftp-load 1 huge-tftp-load ! : sms-get-tftp-blocksize 598 ; : 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 ; : cnt-bits ( 64-bit-value -- #bits=1 ) dup IF 41 1 DO dup 1- and dup 0= IF drop i LEAVE THEN LOOP THEN ; : bcd-to-bin ( bcd -- bin ) dup f and swap 4 rshift a * + ; : 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 100 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-comma ( str2 len2 str1 len1 -- "str1, str2" len1+len2+2 ) 2dup + s" , " rot swap move 2+ 2swap $cat ; : $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 ; : 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 ; : // 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 ; : 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 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 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 IF \ IF len > 0 ( 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 ( ) ELSE \ ELSE ( old-addr len ) my-self instance>args 2! \ | set new args to zero, too ( ) THEN \ FI ; : 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 lenght 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 ; : 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@ ihandle>phandle node>qname $cat r> instance>args 2@ 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 ; : 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 ! ; : 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? ) node>space search-unit #search-unit 0 ?DO 2dup @ swap @ <> IF 2drop false UNLOOP EXIT THEN cell+ swap cell+ swap LOOP 2drop true ; : 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 ) split-component ( path'. args. name. unit. ) ['] set-search-unit CATCH IF set-instance-unit THEN resolve-relatives find-kid ( path' len' args len node|0 ) 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 8 + ( prop_type address data address data' ) 2dup l@ 2 pick 8 + l@ + <= -rot l@ >= and IF l@ 03000000 and 18 rshift nip dup 3 = IF 1- THEN 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 load-base 2000000 value flash-load-base : 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 overwriten 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 overwriten 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 occurences 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 ; defer '(r@) defer '(r!) 1 VALUE /(r) : (rfill) ( addr size pattern 'r! /r -- ) to /(r) to '(r!) ff and dup 8 lshift or dup 10 lshift or dup 20 lshift or -rot bounds ?do dup i '(r!) /(r) +loop drop ; : (fwrmove) ( src dest size -- ) >r 0 -rot r> bounds ?do + dup '(r@) i '(r!) /(r) dup +loop 2drop ; : mrmove ( src dest size -- ) 3dup or or 7 AND CASE 0 OF ['] x@ ['] rx! /x ENDOF 4 OF ['] l@ ['] rl! /l ENDOF 2 OF ['] w@ ['] rw! /w ENDOF dup OF ['] c@ ['] rb! /c ENDOF ENDCASE to /(r) to '(r!) to '(r@) (fwrmove) ; : rfill ( addr size pattern -- ) 3dup drop or 7 AND CASE 0 OF ['] rx! /x ENDOF 4 OF ['] rl! /l ENDOF 2 OF ['] rw! /w ENDOF dup OF ['] rb! /c ENDOF ENDCASE (rfill) ; : ([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 ! ; : (ipaddr) ( "a.b.c.d" -- FALSE | n1 n2 n3 n4 TRUE ) base @ >r decimal over s" 000.000.000.000" comp 0= IF 2drop false r> base ! EXIT THEN [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot $number IF false r> base ! EXIT THEN true r> base ! ; : (ipformat) ( n1 n2 n3 n4 -- str len ) base @ >r decimal 0 <# # # # [char] . hold drop # # # [char] . hold drop # # # [char] . hold drop # # #s #> r> base ! ; : ipformat ( n1 n2 n3 n4 -- ) (ipformat) type ; paflof-start 1 rshift fff not and to load-base deadbeef here l! here c@ de = CONSTANT ?bigendian here c@ ef = CONSTANT ?littleendian ?bigendian [IF] : 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] : 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 ." Intruction 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 , 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 , 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 : .slof-logo cr ." ..`. .. ....... .. ...... ......." cr ." ..`...`''.`'. .''``````..''. .`''```''`. `''``````" cr ." .`` .:' ': `''..... .''. ''` .''..''......." cr ." ``.':.';. ``````''`.''. .''. ''``''`````'`" cr ." ``.':':` .....`''.`'`...... `'`.....`''.`'` " cr ." .`.`'`` .'`'`````. ``'''''' ``''`'''`. `'` " ; 201 cp : banner cr ." Type 'boot' and press return to continue booting the system." s" /packages/sms" find-node IF cr ." Type 'sms-start' and press return to enter the configuration menu." THEN cr ." Type 'reset-all' and press return to reboot the system." cr cr ; : .banner banner console-clean-fifo ; : .banner .slof-logo .banner ; 220 cp 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 + a ; : 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 ; : from-cstring ( addr - len ) dup dup BEGIN c@ 0 <> WHILE 1 + dup REPEAT swap - ; 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 ; 270 cp variable 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 substract 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 ' 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 ' 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 ; 2e0 cp 10 CONSTANT quiesce-xt# CREATE quiesce-xts quiesce-xt# cells allot quiesce-xts quiesce-xt# cells erase : 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-xt# 0 DO quiesce-xts I cells + ( arrayptr ) @ dup IF ( xt ) EXECUTE ELSE drop UNLOOP EXIT THEN LOOP ; 300 cp 0 VALUE usb-debug-flag false VALUE scan-time? VARIABLE ihandle-bulk-tran : usb-debug-print ( str len -- ) usb-debug-flag IF type cr ELSE 2drop THEN ; : usb-debug-print-val ( str len val -- ) usb-debug-flag IF -ROT type . cr ELSE drop 2drop THEN ; 0 VALUE proceed-char : show-proceed ( -- ) scan-time? \ are we on usb-scan ? IF proceed-char CASE 0 OF 2d ENDOF \ show '-' 1 OF 5c ENDOF \ show '\' 2 OF 7c ENDOF \ show '|' dup OF 2f ENDOF \ show '/' ENDCASE emit 8 emit proceed-char 1 + 3 AND to proceed-char THEN ; : wait-proceed ( nl -- ) show-proceed BEGIN dup d# 100 > ( nl true|false ) WHILE 100 - show-proceed 100 ms \ do it in steps of 100ms REPEAT ms \ rest delay ; : do-alias-setting ( num name-str name-len ) rot $cathex strdup \ create alias name get-node node>path \ get path string set-alias \ and set the alias ; 0 VALUE ohci-alias-num : set-ohci-alias ( -- ) ohci-alias-num dup 1+ TO ohci-alias-num ( num ) s" ohci" do-alias-setting ; 0 VALUE cdrom-alias-num 0 VALUE disk-alias-num \ shall start with: pci-disk-num FALSE VALUE ext-disk-alias \ first external disk: not yet assigned : set-drive-alias ( -- ) space 5b emit s" cdrom" drop ( name-str ) get-node node>name comp 0= ( true|false ) IF \ is this a cdrom ? cdrom-alias-num dup 1+ TO cdrom-alias-num ( num ) s" cdrom" \ yes, alias = cdrom ELSE s" sbc-dev" drop \ is this a scsi-block-device? get-node node>name comp 0= ( true|false ) IF disk-alias-num dup 1 + to disk-alias-num s" disk" \ all block devices will be named "disk" ext-disk-alias not \ flag for first ext. disk already assigned IF TRUE to ext-disk-alias 2 s" hdd" \ add extra alias hdd2 for first USB disk 2dup type 2 pick . 8 emit 2f emit do-alias-setting THEN ELSE 0 s" ??? " \ unknown device THEN THEN ( num name-str name-len ) 2dup type 2 pick . 8 emit 5d emit cr do-alias-setting ; : usb-create-alias-name ( num -- str len ) >r s" ohciX" 2dup + 1- ( str len last-char-ptr R: num ) r> [char] 0 + swap c! ( str len R: ) ; : ohci-scan-node ( str len -- ) 2dup find-node ?dup IF dup set-node dup child ?dup IF delete-node s" Deleting node" usb-debug-print THEN s" enumerate" rot find-method IF drop open-dev dup to my-self s" enumerate" 2 pick $call-method \ Scan host controller close-dev 0 to my-self 0 set-node ELSE 2drop get-node dup parent node>path select-dev \ Open parent extend-device s" usb-ohci.fs" included s" open" $call-my-method 0= ABORT" OHCI open failed" s" enumerate" $call-my-method s" close" $call-my-method finish-device unselect-dev THEN ( str len R: num ) ELSE 2drop THEN ; : ohci-scan space ." Scan USB... " cr true to scan-time? \ show proceeding signs 0 to disk-alias-num \ start with disk0 s" pci-disk-num" $find \ previously detected disks ? IF execute to disk-alias-num \ overwrite start number ELSE 2drop THEN 0 >r \ Counter for alias BEGIN r@ usb-create-alias-name find-alias ?dup ( false | str len len R: num ) WHILE usb-debug-flag IF ." * Scanning hub " 2dup type ." ..." cr THEN ohci-scan-node ( R: num ) r> 1+ >r ( R: num+1 ) REPEAT r> drop 0 TO ohci-alias-num 0 TO cdrom-alias-num s" cdrom0" find-alias ( false | dev-path len ) dup IF s" cdrom" 2swap ( alias-name len' dev-path len ) set-alias ( -- ) ELSE drop ( -- ) THEN false to scan-time? \ suppress proceeding signs ; : usb-scan s" ohci0" find-alias IF drop ohci-scan THEN ; 320 cp : .ansi-attr-off 1b emit ." [0m" ; \ ESC Sequence: all terminal atributes off : .ansi-blue 1b emit ." [34m" ; \ ESC Sequence: foreground-color = blue : .ansi-green 1b emit ." [32m" ; \ ESC Sequence: foreground-color = green : .ansi-red 1b emit ." [31m" ; \ ESC Sequence: foreground-color = green : .ansi-bold 1b emit ." [1m" ; \ ESC Sequence: foreground-color bold false VALUE scsi-supp-present? : scsi-xt-err ." SCSI-ERROR (Intern) " ; ' scsi-xt-err VALUE scsi-open-xt \ preset with an invalid token : .wordlists ( -- ) .ansi-red 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 . .ansi-attr-off cr ; : .context ( num -- ) .ansi-red space 5b emit 23 emit . 3a emit context @ . 8 emit 5d emit space .ansi-attr-off ; : 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 ; 360 cp 0 VALUE fdt-debug 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 drop 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 fdt-start dup dup >fdth_struct_off l@ + value fdt-struct dup dup >fdth_string_off l@ + value fdt-strings drop : fdt-check-header ( -- ) fdt-start 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@ 17 >= 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 ; : 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 ; : 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" 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 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-all-phandles ( old new node -- ) >r s" interrupt-map" r@ get-property 0= IF fdt-replace-interrupt-map THEN s" interrupt-parent" r@ get-property 0= IF decode-int -rot 2drop ( old new val R: node ) 2 pick = IF ( old new R: node ) dup encode-int s" interrupt-parent" r@ set-property TRUE TO (fdt-phandle-replaced) THEN THEN r> child BEGIN dup WHILE 3dup RECURSE PEER REPEAT 3drop ; : fdt-fix-node-phandle ( node -- ) >r FALSE TO (fdt-phandle-replaced) s" phandle" r@ get-property 0= IF decode-int ( p-addr2 p-len2 val ) r@ s" /" find-node ( p-addr2 p-len2 val node root ) fdt-replace-all-phandles ( p-addr2 p-len2 ) 2drop (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 THEN r> drop ; : fdt-fix-phandles ( node -- ) dup fdt-fix-node-phandle child BEGIN dup WHILE dup RECURSE PEER REPEAT drop device-end ; s" /" find-node fdt-fix-phandles defer (client-exec) defer client-exec defer callback defer continue-client : set-chosen ( prop len name len -- ) s" /chosen" find-node set-property ; : get-chosen ( name len -- [ prop len ] success ) s" /chosen" find-node get-property 0= ; " /" find-device new-device s" aliases" device-name finish-device new-device s" options" device-name finish-device new-device s" openprom" device-name s" BootROM" device-type 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 : 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 BEGIN len @ block-size @ >= WHILE adr @ block+remainder drop len @ max-transfer @ min block-size @ / read-blocks 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> ; finish-device new-device false VALUE debug-disk-label? d# 16384 value max-prep-partition-blocks s" disk-label" device-name 0 INSTANCE VALUE partition 0 INSTANCE VALUE part-offset 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 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 : 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 ; : 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 d# 2048 alloc-mem dup d# 2048 erase to block debug-disk-label? IF ." init-block: block-size=" block-size .d ." block=0x" block u. cr THEN ; : no-mbr? ( -- true|false ) 0 read-sector 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 ) ; : 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 ; : 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 cr ." No DOS disk-label found." cr 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 ; : load-from-dos-boot-partition ( addr -- size ) no-mbr? IF 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 ; : load-from-boot-partition ( addr -- size ) load-from-dos-boot-partition ; : 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 ihandle>phandle node>path s" :\ppc\bootinfo.txt" $cat strdup ( addr str len ) 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 ihandle>phandle node>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 ) ; : 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 c@ e9 <> IF block c@ eb <> block 2+ c@ 90 <> or IF false EXIT THEN 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 false ; : close ( -- ) debug-disk-label? IF ." Closing disk-label: block=0x" block u. ." block-size=" block-size .d cr THEN block d# 2048 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 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-offset @ #root-entries @ 20 * read-data 0 next-cluster ! ELSE read-cluster THEN ; : .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 1a + 2c@ bwjoin [char] # emit 4 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 1a + 2c@ bwjoin 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 ." slash " 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> ." more... " RECURSE EXIT THEN 2r> 2drop true ." got it " ; : 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 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 ! cr ." FAT" base @ decimal fat-type @ . 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 ) 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 INSTANCE VARIABLE ciregs-buffer : open ( -- okay? ) ciregs-size alloc-mem ciregs-buffer ! true ; : load ( addr -- size ) ciregs ciregs-buffer @ ciregs-size move 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 (u.) s" netboot " 2swap $cat s" 60000000 " $cat 6B8 alloc-mem dup >r (u.) $cat s" " $cat huge-tftp-load @ IF s" 1 " ELSE s" 0 " THEN $cat s" 1432 " $cat my-args $cat (client-exec) dup 0< IF drop 0 THEN ciregs-buffer @ ciregs ciregs-size move r> r> r> over IF s" bootpath" set-chosen ELSE 2drop THEN r> r> over IF s" bootargs" set-chosen ELSE 2drop THEN dup 6B8 encode-bytes s" bootp-response" s" /chosen" find-node set-property 6B8 free-mem ; : close ( -- ) ciregs-buffer @ ciregs-size free-mem ; : ping ( -- ) s" ping " my-args $cat (client-exec) ; 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 ! THEN ; : read-data ( offset size -- ) free-data DUP ( offset size size ) #data ! alloc-mem data-buff ! ( offset ) xlsplit ( pos.lo pos.hi ) seek -2 and ABORT" seek failed." data-buff @ #data @ read ( actual ) #data @ <> 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 new-device s" bulk" device-name : open true ; : close ; 8 chars alloc-mem VALUE setup-packet 0 VALUE cbw-addr : build-cbw ( address tag transfer-len direction lun command-len -- ) 5 pick TO cbw-addr ( address tag transfer-len direction lun command-len ) cbw-addr 0f erase ( address tag transfer-len direction lun command-len ) cbw-addr e + c! ( address tag transfer-len direction lun ) cbw-addr d + c! ( address tag transfer-len direction ) cbw-addr c + c! ( address tag transfer-len ) cbw-addr 8 + l!-le ( address tag ) cbw-addr 4 + l!-le ( address ) 43425355 cbw-addr l!-le ( address ) drop ; 0 VALUE csw-addr : analyze-csw ( address -- residue tag true|reason false ) TO csw-addr csw-addr l@-le 53425355 = IF csw-addr c + c@ dup 0= IF ( reason ) drop csw-addr 8 + l@-le ( residue ) csw-addr 4 + l@-le ( residue tag ) \ command block tag TRUE ( residue tag TRUE ) ELSE FALSE ( reason FALSE ) THEN ELSE FALSE ( FALSE ) THEN csw-addr 0c erase ; : bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- ) s" bulk-reset-recovery-procedure" $call-parent ; finish-device finish-device : open true ; : close ; device-end 370 cp 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-entry 0 VALUE rtas-node 372 cp : find-qemu-rtas ( -- ) " /rtas" find-device get-node to rtas-node " linux,rtas-base" rtas-node get-package-property IF device-end EXIT THEN drop l@ to rtas-base " linux,rtas-base" delete-property " rtas-size" rtas-node get-package-property IF device-end EXIT THEN drop l@ to rtas-size " linux,rtas-entry" rtas-node get-package-property IF rtas-base to rtas-entry ELSE drop l@ to rtas-entry " linux,rtas-entry" delete-property THEN device-end ; find-qemu-rtas 373 cp : enter-rtas ( -- ) rtas-cb rtas-base 0 rtas-entry 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 ( -- ) " 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) " ibm,read-pci-config" rtas-get-token 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 ffffffff and 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 ) " ibm,write-pci-config" rtas-get-token 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 ffffffff and 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 ; : instantiate-rtas ( adr -- entry ) dup rtas-base swap rtas-size move rtas-entry rtas-base - + ; device-end 374 cp 390 cp STRUCT /n FIELD vd>base /l FIELD vd>type CONSTANT /vd-len : virtio-setup-vd ( vdstruct -- ) >r s" class-code" get-node get-property 0= IF 2drop s" 10 config-l@ translate-my-address 3 not AND" evaluate ( io-base ) r@ vd>base ! 0 r@ vd>type l! ELSE ." unsupported virtio interface!" cr 1 r@ vd>type l! THEN r> drop ; 3f0 cp : strequal ( str1 len1 str2 len2 -- flag ) rot dup rot = IF comp 0= ELSE 2drop drop 0 THEN ; 400 cp " /" find-device 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/@0" find-device " 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 580 cp 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 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 : next-pci-mem ( addr -- addr ) pci-next-mem ; : next-pci-mmio ( addr -- addr ) pci-next-mmio ; : next-pci-io ( addr -- addr ) pci-next-io ; : 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 ( -- ) s" mem:" type pci-next-mem @ 16 0.r cr s" mmio:" type pci-next-mmio @ 16 0.r cr s" io:" type pci-next-io @ 16 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 @ 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 #aligned \ fetch current value and align to 1MB 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 -- ) pci-next-mem @ 100000 #aligned \ read the current Value and align to 1MB boundary dup pci-next-mem ! \ and write it back over 24 + rtas-config-w@ \ check if 64bit support 1 and IF \ IF 64 bit support 2dup 20 rshift \ | keep upper 32 bits swap 28 + rtas-config-l! \ | and write it into the Base-Upper32-bits pci-max-mem @ 20 rshift \ | fetch max Limit address and keep upper 32 bits 2 pick 2C + rtas-config-l! \ | and set the Limit THEN \ FI 10 rshift \ keep upper 16 bits pci-max-mem @ FFFF0000 and or \ and Insert mmem Limit (set it to max) swap 24 + rtas-config-l! \ and write it into the bridge ; : pci-bridge-set-mem-limit ( addr -- ) pci-next-mem @ 100000 #aligned \ read the current Value and align to 1MB boundary dup pci-next-mem ! \ and write it back 1- \ make limit one less than boundary over 24 + rtas-config-w@ \ check if 64bit support 1 and IF \ IF 64 bit support 2dup 20 rshift \ | keep upper 32 bits swap 2C + rtas-config-l! \ | and write it into the Limit-Upper32-bits THEN \ FI FFFF0000 and \ keep upper 16 bits over 24 + rtas-config-l@ 0000FFFF and \ fetch original Value or swap 24 + rtas-config-l! \ and write it into the bridge ; : 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 @ 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 @ 1000 #aligned \ read the current Value and 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 : pci-bridge-probe ( addr -- ) dup pci-bridge-set-bases \ SetUp all Base Registers 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 ; : 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 1 and IF \ IF BRIDGE pci-bridge-setup \ | set up the bridge ELSE \ ELSE pci-device-setup \ | set up the device THEN \ FI 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 + 4 mod ( prop-addr prop-len slot pin parentpin ) get-node >space pci-addr2dev + 1- 4 mod 1+ \ do swizzling ( prop-addr prop-len slot pin swizzledpin ) >r >r >r ( prop-addr prop-len R: swizzledpin pin slot ) r> B lshift encode-int+ 0 encode-64+ \ device slot ( prop-addr prop-len R: swizzledpin pin ) r> encode-int+ \ device pin ( prop-addr prop-len R: swizzledpin ) get-parent encode-int+ \ parent phandle 0 encode-int+ 0 encode-64+ \ parent slot r> encode-int+ \ parent swizzled pin ( prop-addr prop-len R: ) ; : pci-gen-irq-entry ( prop-addr prop-len config-addr -- prop-addr prop-len ) pci-addr2dev 4 mod ( 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" unknown-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 0001 OF s" 8514-compatible" 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" unkown-bridge" ENDOF ENDCASE ; : pci-class-name-07 ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" serial" ENDOF 0001 OF s" 16450-serial" ENDOF 0002 OF s" 16550-serial" ENDOF 0003 OF s" 16650-serial" ENDOF 0004 OF s" 16750-serial" ENDOF 0005 OF s" 16850-serial" ENDOF 0006 OF s" 16950-serial" ENDOF 0100 OF s" parallel" ENDOF 0101 OF s" bi-directional-parallel" ENDOF 0102 OF s" ecp-1.x-parallel" ENDOF 0103 OF s" ieee1284-controller" ENDOF 01FE OF s" ieee1284-device" ENDOF 0200 OF s" multiport-serial" ENDOF 0300 OF s" modem" ENDOF 0301 OF s" 16450-modem" ENDOF 0302 OF s" 16550-modem" ENDOF 0303 OF s" 16650-modem" ENDOF 0304 OF s" 16750-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 0001 OF s" isa-pic" ENDOF 0002 OF s" eisa-pic" ENDOF 0010 OF s" io-apic" ENDOF 0020 OF s" iox-apic" ENDOF 0100 OF s" dma-controller" ENDOF 0101 OF s" isa-dma" ENDOF 0102 OF s" eisa-dma" ENDOF 0200 OF s" timer" ENDOF 0201 OF s" isa-system-timer" ENDOF 0202 OF s" eisa-system-timer" ENDOF 0300 OF s" rtc" ENDOF 0301 OF s" isa-rtc" ENDOF 0400 OF s" hot-plug-controller" ENDOF 0500 OF s" sd-host-conrtoller" ENDOF dup OF s" system-periphal" 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 00 OF s" 386" ENDOF 01 OF s" 486" ENDOF 02 OF s" pentium" ENDOF 10 OF s" alpha" 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 0380 OF s" usb" 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-smic" ENDOF 0701 OF s" ipmi-kbrd" ENDOF 0702 OF s" ipmi-bltr" 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 20 OF s" enet-802.11a" ENDOF 21 OF s" enet-802.11b" 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" satelite-tv" ENDOF 02 OF s" satelite-audio" ENDOF 03 OF s" satelite-voice" ENDOF 04 OF s" satelite-data" ENDOF dup OF s" satelite-devoce" 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 0C OF pci-class-name-0D ENDOF 0C OF pci-class-name-0E ENDOF 0C OF pci-class-name-0F ENDOF 0C OF pci-class-name-10 ENDOF 0C 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 ( size var -- al-mem ) 2dup @ \ ( size var size cur-mem ) read current free mem swap #aligned \ ( size var al-mem ) align the mem to the size dup 2swap -rot + \ ( al-mem var new-mem ) add size to aligned mem swap ! \ ( al-mem ) set variable to new mem ; : assign-bar-value32 ( bar size var -- 4 ) over IF \ IF size > 0 assign-var \ | ( 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 assign-var \ | ( 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-mem \ var to change assign-bar-value64 \ and set it all ; : assign-mem32-bar ( bar-addr -- 4 ) dup pci-bar-size-mem32 \ fetch size pci-next-mem \ var to change assign-bar-value32 \ and set it all ; : assign-mmio64-bar ( bar-addr -- 8 ) dup pci-bar-size-mem64 \ fetch size pci-next-mmio \ var to change 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-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 ) 83000000 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 ) 20 lshift or \ and calc Limit ( addr paddr plen base.63:0 limit.63:0 ) 42000000 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 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 2dup device-name device-type 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-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 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 ; : 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 pci-device-props \ and generate all properties drop \ forget the config-addr ; : 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 ' rtas-quiesce add-quiesce-xt 640 cp 690 cp 6a0 cp 6a8 cp 6b0 cp 6b8 cp 6c0 cp s" /cpus/@0" open-dev encode-int s" cpu" set-chosen s" /memory" open-dev encode-int s" memory" set-chosen 6e0 cp 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" /aliases" find-device : open true ; : close ; 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 : input ( dev-str dev-len -- ) open-dev ?dup IF s" stdin" get-chosen IF decode-int nip nip ?dup IF close-dev THEN THEN encode-int s" stdin" set-chosen THEN ; : output ( dev-str dev-len -- ) open-dev ?dup IF s" stdout" get-chosen IF decode-int nip nip ?dup IF close-dev THEN THEN encode-int s" stdout" set-chosen THEN ; : io ( dev-str dev-len -- ) 2dup input output ; 1 BUFFER: (term-io-char-buf) : term-io-key ( -- char ) s" stdin" get-chosen IF decode-int nip nip dup 0= IF 0 EXIT THEN >r BEGIN (term-io-char-buf) 1 s" read" r@ $call-method 0 > UNTIL (term-io-char-buf) c@ r> drop THEN ; ' term-io-key to key : term-io-key? ( -- true|false ) s" stdin" get-chosen IF decode-int nip nip dup 0= IF drop 0 EXIT THEN \ return false and exit if no stdin set >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 false 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,BE0log" get-named-nvram-partition IF s" ibm,CPU0log" get-named-nvram-partition IF 2drop EXIT THEN THEN drop .dmesg-part nip nip ; : dmesg2 ( -- ) s" ibm,BE1log" get-named-nvram-partition IF s" ibm,CPU1log" get-named-nvram-partition IF ." No log partition." cr EXIT THEN THEN drop .dmesg ; : dmesg ( -- ) s" ibm,BE0log" get-named-nvram-partition IF s" ibm,CPU0log" get-named-nvram-partition IF ." No log partition." cr EXIT THEN 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, string, DOES> char+ count ; : 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 ) drop c@ isdigit if true else false 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 evaluate 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 count 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 $CREATE dup >body c@ >r execute r> CASE 1 OF env-int ENDOF 2 OF env-bytes ENDOF 3 OF env-string ENDOF 4 OF env-flag ENDOF 5 OF env-secmode 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? true default-flag use-axon-ddr? VARIABLE nvoff \ offset in envvar partition : (nvupdate-one) ( adr type -- "value" ) CASE 1 OF aligned @ (.) ENDOF 2 OF drop 0 0 ENDOF 3 OF count 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) nvram-partition-type-common get-nvram-partition IF ." NVRAM seems to be broken." cr EXIT THEN 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 : qemu-read-bootlist ( -- ) 0 0 set-boot-device " qemu,boot-device" get-chosen not IF " boot-device" evaluate swap drop 0= IF " disk" add-boot-device " cdrom" add-boot-device 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-device ENDOF [char] d OF " cdrom" add-boot-device ENDOF [char] n OF " net" add-boot-device 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 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' ) over >r move r> zcount nip ; : 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 close-dev ; : 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 ; : 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 ! ; 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 -- ) msr@ 2000 or ciregs >srr1 ! dup 8 + @ 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 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 : netflash ( -- rc ) s" netflash 2000000 " (parse-line) $cat set-netbootpath client-exec ; : netsave ( "addr len {filename}[,params]" -- rc ) (parse-line) dup 0> IF s" netsave " 2swap $cat set-netbootpath client-exec ELSE cr ." Usage: netsave addr len [bootp|dhcp,]filename[,siaddr][,ciaddr][,giaddr][,bootp-retries][,tftp-retries][,use_ci]" cr 2drop THEN ; : ping ( "{device-path:[device-args,]server-ip,[client-ip],[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 s" ping" rot ['] $call-method CATCH IF cr ." Not a pingable device" cr 3drop THEN ELSE cr ." Usage: ping device-path:[device-args,]server-ip,[client-ip],[gateway-ip][,timeout]" cr drop THEN r> set-node r> to my-self \ Restore my-self ; 8a8 cp : enable-framebuffer-output ( -- ) s" screen" find-alias ?dup IF open-dev close-node s" display-emit" $find IF to emit 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 : set-default-console s" linux,stdout-path" get-chosen 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 & keyboard" cr " screen" output " keyboard" input ELSE " hvterm" find-alias IF drop ." using hvterm" cr " hvterm" io ELSE ." and no default found" cr THEN THEN THEN ; set-default-console 8e0 cp 0 VALUE direct-ram-boot-base 0 VALUE direct-ram-boot-size CREATE boot-opd 10 ALLOT : (boot-ram) direct-ram-boot-size 0<> IF ." Booting from memory..." cr direct-ram-boot-base boot-opd ! 0 boot-opd 8 + ! s" boot-opd to go-entry" evaluate 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) " 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 drop (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 ; false VALUE (sms-loaded?) false value (sms-available?) s" sms.fs" romfs-lookup IF true to (sms-available?) drop THEN (sms-available?) [IF] s" /packages" find-device new-device s" sms" device-name : open true ; : close ; finish-device device-end \ leave /packages : sms-init-nvram ( -- ) nvram-partition-type-sms get-nvram-partition IF cr ." Could not find SMS partition in NVRAM - " nvram-partition-type-sms s" SMS" d# 1024 new-nvram-partition ABORT" Failed to create SMS NVRAM partition" 2dup erase-nvram-partition drop 2dup s" lang" s" 1" internal-set-env drop 2dup s" tftp-retries" s" 5" internal-set-env drop 2dup s" tftp-blocksize" s" 512" internal-set-env drop 2dup s" bootp-retries" s" 255" internal-set-env drop 2dup s" client" s" 000.000.000.000" internal-set-env drop 2dup s" server" s" 000.000.000.000" internal-set-env drop 2dup s" gateway" s" 000.000.000.000" internal-set-env drop 2dup s" netmask" s" 255.255.255.000" internal-set-env drop 2dup s" net-protocol" s" 0" internal-set-env drop 2dup s" net-flags" s" 0" internal-set-env drop 2dup s" net-device" s" 0" internal-set-env drop 2dup s" net-client-name" s" " internal-set-env drop 2dup s" scsi-spinup" s" 6" internal-set-env drop 2dup s" scsi-id-0" s" 7" internal-set-env drop 2dup s" scsi-id-1" s" 7" internal-set-env drop 2dup s" scsi-id-2" s" 7" internal-set-env drop 2dup s" scsi-id-3" s" 7" internal-set-env drop ." created" cr THEN s" sms-nvram-partition" $2constant ; sms-init-nvram : sms-add-env ( "name" "value" -- ) sms-nvram-partition 2rot 2rot internal-add-env drop ; : sms-set-env ( "name" "value" -- ) sms-nvram-partition 2rot 2rot internal-set-env drop ; : sms-get-env ( "name" -- "value" TRUE | FALSE) sms-nvram-partition 2swap internal-get-env ; : sms-get-net-device ( -- n ) s" net-device" sms-get-env IF $dnumber IF 0 THEN ELSE 0 THEN ; : sms-set-net-device ( n -- ) (.d) s" net-device" 2swap sms-set-env ; : sms-get-net-flags ( -- n ) s" net-flags" sms-get-env IF $dnumber IF 0 THEN ELSE 0 THEN ; : sms-set-net-flags ( n -- ) (.d) s" net-flags" 2swap sms-set-env ; : sms-get-net-protocol ( -- n ) s" net-protocol" sms-get-env IF $dnumber IF 0 THEN ELSE 0 THEN ; : sms-set-net-protocol ( n -- ) (.d) s" net-protocol" 2swap sms-set-env ; : sms-get-lang ( -- n ) s" lang" sms-get-env IF $dnumber IF 1 THEN ELSE 1 THEN ; : sms-set-lang ( n -- ) (.d) s" lang" 2swap sms-set-env ; : sms-get-bootp-retries ( -- n ) s" bootp-retries" sms-get-env IF $dnumber IF 255 THEN ELSE 255 THEN ; : sms-set-bootp-retries ( n -- ) (.d) s" bootp-retries" 2swap sms-set-env ; : sms-get-tftp-retries ( -- n ) s" tftp-retries" sms-get-env IF $dnumber IF 5 THEN ELSE 5 THEN ; : sms-set-tftp-retries ( n -- ) (.d) s" tftp-retries" 2swap sms-set-env ; : sms-get-tftp-blocksize ( -- n ) s" tftp-blocksize" sms-get-env IF $dnumber IF 5 THEN ELSE 5 THEN ; : sms-set-tftp-blocksize ( n -- ) (.d) s" tftp-blocksize" 2swap sms-set-env ; : sms-get-client ( -- FALSE | n1 n2 n3 n4 TRUE ) s" client" sms-get-env IF (ipaddr) ELSE false THEN ; : sms-set-client ( n1 n2 n3 n4 -- ) (ipformat) s" client" 2swap sms-set-env ; : sms-get-server ( -- FALSE | n1 n2 n3 n4 TRUE ) s" server" sms-get-env IF (ipaddr) ELSE false THEN ; : sms-set-server ( n1 n2 n3 n4 -- ) (ipformat) s" server" 2swap sms-set-env ; : sms-get-gateway ( -- FALSE | n1 n2 n3 n4 TRUE ) s" gateway" sms-get-env IF (ipaddr) ELSE false THEN ; : sms-set-gateway ( n1 n2 n3 n4 -- ) (ipformat) s" gateway" 2swap sms-set-env ; : sms-get-subnet ( -- FALSE | n1 n2 n3 n4 TRUE ) s" netmask" sms-get-env IF (ipaddr) ELSE false THEN ; : sms-set-subnet ( n1 n2 n3 n4 -- ) (ipformat) s" netmask" 2swap sms-set-env ; : sms-get-client-name ( -- FALSE | addr len TRUE ) s" net-client-name" sms-get-env ; : sms-set-client-name ( addr len -- ) s" net-client-name" 2swap sms-set-env ; : sms-get-scsi-spinup ( -- n ) s" scsi-spinup" sms-get-env IF $dnumber IF 6 THEN ELSE 6 THEN ; : sms-set-scsi-spinup ( n -- ) (.d) s" scsi-spinup" 2swap sms-set-env ; : sms-get-scsi-id ( n -- id ) s" scsi-id-" rot (.) $cat sms-get-env IF $dnumber IF 6 THEN ELSE 6 THEN ; : sms-set-scsi-id ( id n -- ) swap (.d) rot s" scsi-id-" rot (.) $cat sms-set-env ; : sms-get-net-boot-file ( -- addr len ) s" net" sms-get-net-device (.) $cat s" :dhcp," $cat sms-get-server IF (ipformat) $cat THEN s" ," $cat sms-get-client-name IF $cat THEN s" ," $cat sms-get-client IF (ipformat) $cat THEN s" ," $cat sms-get-gateway IF (ipformat) $cat THEN s" ," $cat sms-get-bootp-retries dup ff <> IF (.) $cat ELSE drop THEN s" ," $cat sms-get-tftp-retries (.) $cat dup IF strdup ( s" :" 2swap $cat strdup ) THEN ; ' sms-get-net-boot-file to furnish-boot-file : $sms-node s" /packages/sms" ; : (sms-init-package) ( -- true|false ) (sms-loaded?) ?dup IF EXIT THEN $sms-node ['] find-device catch IF 2drop false EXIT THEN s" sms.fs" [COMPILE] included device-end true dup to (sms-loaded?) ; : (sms-evaluate) ( addr len -- ) (sms-init-package) not IF cr ." SMS is not available." cr 2drop exit THEN s" Entering SMS ..." type disable-watchdog reset-dual-emit 2>r $sms-node find-device 2r> evaluate device-end vpd-boot-import ; : sms-start ( -- ) s" sms-start" (sms-evaluate) ; : sms-fru-replacement ( -- ) s" sms-fru-replacement" (sms-evaluate) ; [ELSE] : sms-start ( -- ) cr ." SMS is not available." cr ; : sms-fru-replacement ( -- ) cr ." SMS FRU replacement is not available." cr ; [THEN] TRUE VALUE use-load-watchdog? : start-it ( -- ) key? IF key CASE [char] s OF (s-pressed) ENDOF 1b OF (esc-sequence) CASE 1 OF console-clean-fifo sms-start (boot) 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 : $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 ) bootdevice 2@ dup IF s" " $cat THEN s" diagnostic-mode?" evaluate IF s" diag-device" evaluate ELSE s" boot-device" evaluate THEN $cat \ prepend bootdevice setting from vpd-bootlist strdup ?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 $cat-space ELSE drop THEN set-boot-device ; ' (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 ( -- ) state-valid @ IF 0 ciregs >r3 ! 0 ciregs >r4 ! go-args 2@ go-entry start-elf64 client-data claim-list elf-release 0 to claim-list 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 ENDOF ( arg len true claim-list entry go ) 2 OF ['] go-64 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 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 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 ) my-args nip 0= IF 2dup 1- + c@ [char] : <> IF \ Add : to device path if missing 1+ strdup 2dup 1- + [char] : swap c! THEN THEN encode-string s" bootpath" set-chosen $bootargs encode-string s" bootargs" set-chosen 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 s" parse-load " $bootdev $cat strdup evaluate ; : load-next ( -- success ) \ Continue after go failed load-list 2@ ?dup IF s" parse-load " 2swap $cat strdup evaluate ELSE drop false THEN ; : noload false ; ' no-go to go : (go-and-catch) ( -- ) load-base c@ 5c = 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 ) 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 .banner ; : load load 0= IF -65 boot-exception-handler THEN ; : yaboot ." Use 'boot disk' instead " ; : netboot ( -- rc ) ." Use 'boot net' instead " ; : netboot-arg ( arg-string -- rc ) s" boot net " 2swap $cat (parse-line) $cat evaluate ; : netload ( -- rc ) (parse-line) load-base >r FLASH-LOAD-BASE to load-base s" load net:" strdup 2swap $cat strdup evaluate r> to load-base load-size ; : neteval ( -- ) FLASH-LOAD-BASE netload evaluate ; cr .( Welcome to Open Firmware) cr cr .( Copyright (c) char ) emit .( 2004, 2011 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 cr ." Ready!" ĐPPGCC: (GNU) 4.6.3.symtab.strtab.shstrtab.rela.slof.loader.rela.text.rela.opd.got.rela.data.comment.bss L0 2`- M =8V BLPGhx> R0[1`    x4@`(D?`&  5Cxaw@A@p8 ,L    <#3X8 H@xO$Wh)&S&,*.969H,- 7 07 <7 7 200"2 &0 * 22 062X>i2B]2Fi0J0XN]0b0vi2zi0i2i02X0X2i2p2'2S222>2622W2r20i2i0]2]02X0Xi0p0i0'0 i0 S0 :i0 J0 fi0 v0 i0 >0 i0 60 i0 @ i0 0 Fi0 JW0 vi0 zr0 I2 i0 I0 <2 i0 <0 ]2 ]0 :]2 >i0 B]0 i0 i0 i0 "i0 Ni0 i0 ]2 ]0 i0 .i0 Zi0 i0 i0 i0i02]26i0:]0r]2vi0z]0]2i0]0i0 2 0"i0& 2* 0Z]2^i0b]0fE2jE0i0E2]2E0]0i0]2]0&i0^i0i0i0i0>i0vi0i0i0i0Fi0vi0i0i0i0&i0Ni0~i0i0i0i0Ni0i0i02i0ni0i0i0i0]2 ]0Ji0z]2~]0]2]0i0]2]0r]2z]0i0]2]0]2]0"i0Bi0]2]0*i0i0Fi0i0i0h! 20i0a i0g &i0<^ Ri0 i0 i0_  i0< Vi0i0{ 20U i020.i0H+ ^i03 i0+ i03 i0(+ >i0l3 ~i0+ i03 i0 4w  Ni0 d  zi0 x  i0 Q  i0!B !&i0!D !Vi0!= !i0!% "i0",A ">i0"l: "i0"L "i0" "i0#(o #:i0#ph #i0#q #i0#N $  $i0$"2$60$D* $ri0$v2$0$, $i0$J $i0%H %*i0%@" %Vi0%l8 %i0%D %i0%s %i0& f &*i0&D &bi0& &i0' ' U '< 'i0( V (Bi0(x ( ( (9 (i0)8 )TU ) ){ )i0* *$U *\ *|U * *i0+ +,U +Tz +i0+/ +i0,  ,@U ,p ,U ,l ,i0-1 -Fi0-~ -i0-i0-i0.i0.&i0.:i0.fi0.i0.i0.i0.i0.i0/i0/Ji0/vi0/i0/i00n 0i00Fi00ri00i00i00i00i01&i01Ri01~i01i01i01i01i02 i026i02bi02i02i02i03i03>i03ji03i03i03i04i04Fi04ji04~i04i04i04i05 5i05H 5^i05 5i06 i066i0:2:0:| :| ;l# < # <# =p7 =7 =7 =7 =7 >7 >07 >L7 >h7 >7 >7 >7 >7 >7 ?7 ?,7 ?H7 @(7 @0 @87 @@7 @H7 @P7 @X7 @x7 @7 @7 @ @7 @ @7 @7 @j @` @j @` @j A` AO BP C \ C<O Cx CP C Dl D\ E EU G GU I2 I0 I"2I22HIZ0Jd J J0HL L2PL0PL L{ L M MPM MbMfMMMMP P$x Px Px Sy Sy S S Ty T`y TlZ TQ Ux U U, U@; UN2Uj0Un0V@G V2V0V W 2hW0hW Wx W W W; XG Y2(Y0(Y0(Yy Yy Y Y Zy Z2Z0Z,& Zy ZZ Z2(Z0(Z2(Z0(Z2Z0[LQ [tc [k [2[0[ [ [F \ } \8 \TK \. \2H\0H\ \2\0\ \2\0] ] ]$ ]f2]n0]p ]~20]00] ]20]00]@0]20]00]U ^U ^e2^"e0^Ne2^V20^Z@0^^00^ve0_U _C _2`_0`_ `2p`"0p`(b `.e2`2e0`{ `{ ` `{ ` a 20a00aR2aZ0ap@ a{ b{ bb b"e2b&e0b{ b{ b b{ c{ c0{ cD cT{ c cb ce2ce0dl db de2de0e2e0e20e@ f00f| f{ f20f00f h.20h:00hb he2he0i i20i00ib ie2ie0j j20j00k( kb ke2ke0l l20l00l2Xl0Xl2l0l0Xl m"2Xm&0XmZ0Xm mJ mJ n:2Xn>0Xn n2Xn0Xn0Xo( o^2Xob0XoJ o hoH oJ p2Xp0Xp| p p2Xp0Xp qLD qds qD q{ q hqD r 2Xr0Xr  r&2r:0r@ rz2Xr~0Xr0Xr s2Xs0Xst ss ss sf s2Xs0Xt20Xt\ t2Xt0Xt u2Xu0Xu^2Xub0Xu u v:2Xv>0XvJ v hvH wJ w8@ wJ x4D xj2Xxn0Xxxu xu y y,R y@ y\ y2Xy0XyJ zD z4u zD zTR zX zu { {2X{0X|J |<R |\D |R |u |s | |2X|0X|u }  }T }` @}h @}n2}r0}t }z2}0} } }2X}0X~J ~@J ~2҈~0҈~U J 8J X{ l@ 2҈0҈ J HJ p{ @  { { D {  D  D ,{   J ? ,J dD 2 u $ 4{ L@   ? J J  J PD \{ D D 2 D  \$ m2m0 m2m0{ 5 &22085 $ 5 20>20B00V00 T( 202n0( { { L  D T    4 D t&3X&3&3&@ 30&|83H&P3`&xh3x&3&?D3&@L3&A3&B3 &Dx(38&D@3P&FX3h&Gp3&J3&Lt3&L3&M<3&M3&NX3&N3(&N03@&O<H3X&Ot`3p&Ox3&P3&Q3&RH3&R3&U\3&W3&Xh 30&X83H&[P3`&[h3x&\H3&^3&_3&a3&b|3&f`3&g|3 &il(38&j@3P&kX3h&kp3&l43&l3&mT3&n3&n3&p3&pt3(&q03@&qH3X&q`3p&rx3&s3&s\3&s|3&t03&v3&vh3&v 30&v83H&wP3`&xh3x&x3&z3&{3&{3&{3&|3&}3 &T(38&@3P&X3h&p3&3&d3&3&,3&h3&3&3(&<03@&H3X&`3p&lx3&3&3&3&3@& `P& |`&0x& 8&H& & &h&p& &@&&&X&x&&& &(&0&8&@&H& P&X&h`&hh& p& (x&x& @& X& x& & &8& &x& @& X& x& & & P& (& 0&h8&0P&X&Hp& x& & &&H&x& x&&& x&& &`& & &h&(& 0&(8&@&@H&P&X&@`&Xh&@p&x&&@& &&@&@&h&& &H& &(&&x&@&&& &h(&@& P&`& Xh&x& &&D&& && & 0& ,&& &&@ &0(&0&@8&P@&0H&P&pX&(`&0h&p&(x& & &h&(& &(&(& &&(&&&(&&X&(&&&( &(&0&@8&h@&P& X&`& xp&0x&& (&(&0&&(& &@&& &(&h&& &@& &(& 0&@&H& `& h& x& && & & x&@& |&`& &P&x&& x(&0&8&@& P&xX&`& Xh& xx&& &8&x& &x& @& X& x&&&8&x& & && &h(&8& @& H& (P&`X&`&h&p& @& &P&@& x&P&&& &x& & x& &h&&  &(&0&8&@&H&P&hX&@x& |&& |& & &x& x&@&&& &P&& x & (&(0&@8&(@&H& X&`&h&hp&p& |&& & & &h&(& |&h& &H&\&`(&0&H& P&X&`& xp& x&&&p&@&&@& x&x& @&h&@& &(&h&& &00& 8&@@&(H&HP&hX& h& x& x&& & &&& x& & x&&&p&@& & &@ &(&@0& x@&xH& @X&h`&h& @p& x& & &h&!& &!&&x& &!&&&!&& &h&0& p& (& 00&"@& H&"HP&hX&"hh& p&"x&h&"& |&"& && &#& &#(& (&8& X@&PX& `&#`p& x&x& x&x&h&& &X& &#&l&& &# &(&@&2H&h& p&xx& @& X& x&&$(&8&x&& &@&x& @& X& x& &@&$X &h(&$h8& @&(H& P&hX& Hh&p&$& &%& x&@&@&% &(&(&h&&&% & (&x0&"x8& @&& H&hP&`& h&&8p&&p&&&& & &&&h& & |&&& &H&'&& x&&&(H & (&(p0&h8&pH& P&X&(`&hh&& &)&&&&&&& &&X&h&)& &)`&x&P&h&)(& 0&X8&@& xP&X&)`& h& p&x&(H&@&X&& X& x&&@& @&h&h&)& &&*p&"x& & &&8(&&p8&x@&& H&&P&*pX&"x`&*h&p&*& &h&*& &*&X&h&*& &+ &h&(& &&X&& &h(&+@8& @&+PH&P&*pX& @h&+Pp&+px&h&+& &+& &&&h&& &+& &&h &, 8& @&"xH&8P&hX&,Pp&x& & & & & &h&(8& &,& &-&&-&&h&8 & 0& @&$H&-(`&h&-H& &-`&x& x& &x&.`& && &(H&h&& & & &h&.(& 0&x8&@& xP& X& `&(Hh&@p&@x&x&@&& & @& X&x& x&(&"x&(&/&x&& x& & & &(H &@(&@0&@8& @& H&(P&(X&.`&h&p& x& & & x&0(&&@& & & &(H&h&@& &&&&h&8(& 0&8&@&H&xP& X&`&0`h& xx&& &&X&& &(&0& x&*& &+p& & & &h&&  &00& 8&@@&H& P&X&X`&h&p& x&&(&&(&0& x&&x&*&X& &x& &+p&h&1& &  &(&/0& 8&@&H&HP& X&h`&2p&x&2(& &2@&2`&2x&h&!p& &2&h&2& &!&&-@&  &!(&0&8&!@&H& P&hX&3(h& p&x&& x&@& @&h&h&3h& &3&&3& &3&h &40& 8&4X@&XH&hP&"`& h&4p&hx&4& &4&X&h&4& |&X& &&h&h&& &5 & (& @8&5`@&hH&`& h&(p&x&x€&xˆ&& &X˜& @¨&2`°&@¸&h&5h&0&5&&5 &$@& |P&h`& h&+p& x&À& È&hÐ&5è& ð& ø&&%&h&$8& &6 & &&x &(& x8& @&@H& P&&p`&h&&p&(x&/Ā&Ĉ&Đ&&Ġ&hĨ&@ĸ& & &&p&P&&&h&&t&6x & (&0&X8& @&hH&6X&H`&6p& x&(ŀ&ň& Ő&@Ř&hŠ&&`Ű&Ÿ&7 & &7X&@&&78&x&& && & (&8 0&8&x@&& H&P&XX& `&xh&p&& x&Xƀ&ƈ&*pƐ&8 Ƙ&(Ơ&hƨ&Ƹ& &&& x& &&&(H& &&h &8(0& @&8PX& `& h& xx&ǀ&Lj& @ǘ&hǠ& Ǩ&hǰ&8x& && &&h&&8& &8 &9((&80&h8&9hH& P&8X&x`&@h&9p& x&:Ȁ&(Ȉ&:hȐ&9xȘ&hȠ&Ȱ& ȸ&&&&h&:& &&4&/&2`& x & (&:0& @&hH&&X&`&p& ɀ&&ɘ&ɠ&;(ɰ& ɸ&;&h&;& &4&(&h&;& &;&; &h(&<8& H&<X& `&+h&p&Xx& ʀ&ʈ&hʐ&<`ʠ& ʰ&x& & &&h&<& &<&.P&  & (&.`0&h8&= H& P&8X&`& h&Pp& x&8ˀ&ˈ&=ː&˘&hˠ&˰& ˸&=&&=&&=&&h&=& &*(&p0& H& P&,X&x`&@h&<p&=x& ẍ&̐&̘&̠&̨&̰& ̸&& x&&&(& &@&(&*& &( &(& 0&h8&H& P&"xX&x`&& h&p&" x&6̀&h͈&>͠& ͨ&xͰ&͸& x&@&&& &?0&&>(& x& &@&  &@(&@0&?08&@&*H& P&?0X&`&?Ph&?p&Xx&(΀& Έ&@ΐ&(Θ&"xΠ&(Ψ&/ΰ& & &h&& &*&(&h&@0& &  & (&(0&h8&H& P& X&5x`&hh&@x& π&0`ψ&ϐ&hϘ&@ϰ& ϸ& & &&p&&&&X&& &&x&(& X& x(&00& @& XH& xX&&`&<(h&p&x&(HЀ&@Ј&&И& Р& Ш&а&hи&A8& & @&H& &h&2P&&'(& 8&ApH&tP&A`& h& p&Ax&hр&ѐ& ј&Ѡ&Ѩ&4Ѱ&Ѹ&h&A& &!&&*& &BP&C&h&P & (& @8&@&H&hP&C`& h&!p&Cx&D8Ҁ&h҈&D`Ҡ&Ҩ&Ҹ& &4X&h&4H& &+ &X&h&Dx& &D &X(&h0&D@& H&4P&;X&h`&"8p& x&;Ӏ&Xӈ&hӐ&DӠ& Ө&EӰ&XӸ&h&E& &E(& |&5P& & @(&5`0&h8&EH&(P&F `&h&F@Ԁ&tԈ&F`Ԙ&2Ԡ&&$& &&&%&h&Fx&  &?0(&0& 8&F@&H&?0P&X&h`&Gp& x&Հ&Ո&2`Ր&h՘&pը&հ&G8& &4&/&X&4&0(&2`&h&G0&G@& H&HP&GX&`& @p&;x&Xր&Gֈ&֐&*֘&X֠&x֨& @ָ& X& x& & &G&&h&X&@&H & (&H0&h8&H& P&X&h`&+`p&x&9׈& א& ט&HHנ&xר&װ&+׸&(&h&Hx& &HH&x&&h&H& &H &x(& x8& H&hP&:`& h& p&HHx&x؀&؈&+ؐ&(ؘ&hؠ&0ذ& ظ&x&& x&0(&h&I(& &I8&&2 & x(& 8&h@&IxP& X&`& xp& @ـ&Iو&hِ&I٠& ٨&ٰ&J(ٸ&E&&h&2& &&*p&;&&h&J0 & (&0&0`8& xH& P& X&h`&p&x&pڈ& ڐ&;ژ&(ڠ&hڨ&4ڸ& &J& &J&3&J& &( &((&(0& 8&@@&hH&K0X& h&=ۀ& ۈ&& &  &*(&0&=8&@&2H&8P&X& `&:h& 0p&*x&h܀&KPܐ& ܘ&Khܠ&ܨ&hܰ&*x& &Kx& &#&&h&K& & &K(&x0& @@& @P&LhX& xh& @x&(݀& @ݐ&(ݘ&xݠ&?ݨ& ݰ& ݸ&L& x&&(H& & &&h&0& (&M(8& @& H&MP& @`& h&6p&M8x&&ވ& ސ&hޘ&Mި& ް&@޸& &(& &h&N& &@&N &(&X&h&N(& 0&@8&O@&H& @X&O0`&2 h&(p&OHx&h߀&0Pߐ& ߘ& ߠ&#ߨ&h߰& & &=&&&x&& &2@&2 & &*p&h &Oh0& 8&H@& H&& P&hX&P(h&<p&P@& & &0&h&0& & X&&h&Pp& &!&&&& &BP&C&h &!8& @&!H&P&X& xh&xp&x& &&&(& && &&(& &!&&h&P& &&&+p& &(& x8&@@&QH&@P&QX&`&h&p&R x&p&h&R(& &!&R& &h&R& &!&& & &S&C&h&Rx & (&!0&S`8&C@&hH&SX&`&Sp& x&T&X&h&S& &E&;&h&T(& &Th&X&h&TX& &K & (&x0& @@& @P&LhX& xh& @x&X&h&Tx& &&8&&p&&&U&U &&&J(&E&*&h&UH &(&Uh@&DH&UX&2|`&Up& x&?0&& &VH&&?0&&h&V0& &V&?0&&h&V& &=&(&h &V0& 8&W @&WpH& P&WpX&W`&hh&(Xx& &W&&(p& &h&0& &)&&X& && &h &X0& 8&@& @P&XX&h`&Xp& x&x&@&Y&(& &@&Y&(&h&)P& &?0&&Y& &Y&I&h&:X & (&?00&8&H@&?H&YP&IX&h`&8p& x&HH&x&&/&+& &&*p&h&Z& &&Zh&Th&&h&T&&9(& 0&8&5x@& xP& X& `&hh&Zpx& &Z&3&&x& &(&(&(&& &@& &@& &@&h&(& 8&xP& X&`&Zp& x&@&&h&%& &&&h&Z& &x& @& @&Lh& x& @(&(0&h8&LP& X&*`&Xh&Lp&hx&=& &?&x&?&PP& x& &&@&0`& x&&@&(H&h&[P & (&@0&x8&@&@H&[P&(X& xh&p&N x&(&h&?& & &@& &(&h&& & &&h&[& & &@ &x(&@0&X8&x@&(H&#P&(X& `&(h&hp&[& &@&O&& @&O0&2 &(&O&h&\ & &*&P8&h&;x& &N0& 8&*@&AH&hP&7H`& h&7Xp&@x&H&x&&*p&&8&(&x&\`&&p&"x&&&& &&*p&&& &h&O  &(&A8& @&5xH&P&hX&\h& p&Qx&!&&&&p& &&&!&& & &h&Q& &&&*&&+p& x(&@0&8&Q@&H&R P&X&`&Qh& p&hx&]& &(&&x&& &@&h&Q& &]@&&C & (&!0&8& x@& H&SP&CX&h`&]`p& x&Q&& x& && & &h&S& &Q&&h&]& &&&( & (&h0&CH& P&X&`&h&(p& x&&h&]& &3& &^ &X&h&^& &Th&;&h&4x & (&^P0&X8&h@&^@P& `&^`x& &&8&&p&&&U&^&&&J(&E&*&h&ZX&|&W& &W &  &W(&h0&_(H&LP&_Hh&p&_h&2D&_& & &)(&?&&5x& x&&(&%& & &x&h&? 0& 8&J@&?0H&P&hX&`h& x&/& &=&X&h&^& &`@&@&`@&(&W&h&`x& &x&Z &2`(& 0&`8&P8@&hH&UX& `&ah& p&\`x& &`@&h&a@& &`&O0&2 &h&ax& &!& @&H&&#x& &x &:(&&80&&p@&&H&& P&:X&&h&*p&hx&a& &A&h&F& &` &?0&&h&H8& &x& @&0`& x(& @8&X@& @P&XX&h`&ap& x& & &Y&h&b& & @& &6&b&&& & &h&:& & &c(&^P0&8&h@&cP&LX&cp& &c&3&c& & &PP&h&(& &x&@&& &x&&*p &8 (&(0&h8&?H& P&d X&@`&hh&LPx& &\0&&&(&@&\0&(&h&d& &x&& x&d &h&dp&  &*(&O00&h8&MH& P&@X&M`&(h&Mp&hx&B8& &Q&!&&&&6& & &!&&h&d& & @&H&x &h(&e@&dH&SHX& `&Qh&p& x& && & &h&e(& &!&@&e&(&h&f &&+& &^P&; &h(&;8& H&f8`& h&&8p&&p&&&U&GH&&&J(&E&*&h&f& &g& &\`& &f&h&gP(& 0&gpH&P&g`&4h&gx& & &)`&?&&5x& x&&(&%& & &x&h&g& &h(& 0&hH8&@@&hHH&(P&hX&h`&hpx& &x&c&2`& &V&P8&h&Vp& &W& &`&@&h&(&h &h(&h8& @&`H& P&hX&h`&ip& x&!&&h& &,`&`&h&iX& &P8&h&i& &x&@&& &&@ &i(&0&2x8&(@&2`H& xX&/`& h&(p&Xx& &@&(& &h&j@& &@&x&&@&[&(&&&=&2 & x&@ &*(&2 0&(8&@&(H&(P&hX&jh&p&cp&$&j& &k&3\&2h& & &0`&h&k@& &H&@ &0((&x0&8&(@& H&(P&hX&kph&Tp&k& &&& x&l8&&x& &@& @&H&x&h&l&8&m & (&!0&8&@@&H&P& X&`& Xh& p&Rx&& & &(&h&D(& &!&& & && & & &S`&h&8&D &m8& @&&8H&&pX&&`&ch&Wpp&&x&Zh&Th&*&h&W`& &h&@&h&(&W&h&`& &W &@&` &((&`0&h8&JP&X&Rp&x&n&44&n8& &)(&x&P&h&-& &h8& &V&O0&2 &h &n`0& 8&` @&O0H&2 P&hX&np& x&x&j&2`& &` &P8&h&`0& &h& &hH&h&n& &*&& & (& 0&388&h@&O8P& X&O0`&hh&Yx& &&@&@&[&&9&Y&(&& x&0(&(&& x &0( &  &0( &  &h (&?@ 8&  @& H&  P&@ X&@ `&9 h&( p&9 x&?P &( & & x &d  &h &*` & &` &  &H &  &h & &h (&&( 8&  @&x H& P&h X&o0 h&  p&( x&( & & &@ &? &@ &  &h &l( &  &l8 & &X &  &  &*p &  &h &W &  (& 0& 8& x H&W P& X&8 `&  h&@ p& @ &H &x &@ &7X &x &@ &  &8  &( &( &h &G &  &o &  &! & &  (&  0& 8& x H&/ P&  X&D8 `&  p&C x&h &o &  &&8 &&p && &c &aP && &Zh &Th &* &h &p0 &1 & 0&  8& @&h H&g `&  h&W  p&@ x&a &( &a &h &pP &  &p` & &h &  &  &H &=0 & & & &38&h&p(& 0&(8&(@&(H&?P&@X& `&hh&ex& &Q& &h&p& &&8&&p&&&j&h&&&c&^P&*&h&q00&28&qPH& P&@X&jP`&(h&bp&hx&q& &(&?&@& &@&@&h&rP& &x&@&&(&&&h&r0&18&rH& P&rX& `&hh&s(x& &x&& x&@&?&(& &@&*&(& && x&(& &*&( & 0&h8&sH& P&xX&`&h& p&x&h&tP&1&r& &r&&h&Yx& &@&kP&(&b&h&th & (&x0&8& xH&?P&@X&*`&(h& x&& x&(&M&*&(& &h&t& &j&x& @&PP& x& @(&(0&h8&tH&1<P&\P`& h&@p&@x&\`&(&(&\`&h&(& &(H& &&h&u&1h&u &0&u8&1 &uP0&08&uhH&0P&u`&04h&ux&0`&u&/&u&0&u&/|&u&/&v&/P&v(&/$&v@ &.(&vX8&.@&vpP&.pX&vh&.p&v&,&v&,&v&,&v&,d&w&,8&w&,&w0&+&wH(&+0&w`@&-H&wxX&-t`&wx&-H&w&-&w&.&w&-&x&.D&x@ &+D(&xhH&)P&xp&(x&x&'&x&&&y&*&y0&)&y`@&&@H&yh&%p&y&$&y&$`&z&&&z &&&zH(&&0&zhH&$(P&zh&#Tp&z&#&z&#(&z&#&{&"&{(&#&{H(&"0&{pP&"pX&{p&"x&{&!&{&"&|&!&|0&!8&|P0& 8&|xX& `&|x& &|& <&|& &}&&}(&T&}P0&$8&}xX&`&}&&}&x&}&L&~&&~0&&~H(&|0&~`@&<H&~xX& `&~p&x&~&&~&\&~&,&~&&&&8& &X8&P@&xX&$`&x&&&& & &H&?0&&@&X&&(&?0&&h&&  &H(&?00&8&@@&FH&P&(X&?0`&h&hp&& &H&?0&&@&VH&&(&?0&&h&8& &8 & &,0 &  &h &h 8&  @&,` H&h P& `&  h&= p&3 x&( &h & &  &= &3 &X &h & &  & & &h &!& !&!&! &!(& x!8&!@&!H& !P& !X&@!`&!h&!p&h!x&0!& !&x!&8!&!& x!&?!& !&(H!& !& !& x!&0(!&@"&"&@"&h"&x"(& "0&"8&"@&"H& "P& "X&h"`&"p& "x&AH"&"&h"&"& "&H"&"&"&"& x"&&"&(H"& "&(p#& #&#& x# &#(&#0& #8& #@&#H& #P& #X& #`&h#h&#& #&#& @#& #& #&h#&#& #&#& #&h#&h#& $&H$&=0$&$& $ & $(&$0&2$8&X$@&,`$H&h$P&$h& $p& $x&h$&$& $& $&h$& $& $&H$&=0$&$& $& $&$& $&,`%&h%&%& % &H%(&=0%0&%8& |%@& %H&%P&"%X& %`&,`%h&h%p&%& %&H%&=0%&%& L%& %&%&,`%&h%&P%& %&H%&=0&&&& && && & & &(&,`&0&h&8&&H& &P&H&X&=0&`&&h& &p& &x& &&,`&&h&&&& &&H&&=0&&&& && && &&,`&&h&&@'& '&'&X'& ' &h'(&'@& 'H&('P&'X&8'`&'h&,0'p&'x&'&h'&'& '&H'&'&h'&@'& '&=0'&'& 8'& '&(&@(&(& (&,`( &h((&x(@& (H&H(P&(X&h(`&(x& (&(&(&@(&@(&&8(&&p(&((&(& (&@(&(&((&(& (&)&)&0)& x) &)(&x)0&@)8&)@&()H&)P&*)`&()h&()p&)x&h)&)& |)& @)& |)&)& |)T&*T&*& p* & *(&*0& *8&*@& *H&*P& *X&*`& *h&*p& *x&*& *& @*Y&*& @*d&*&*&(*&*&*& *& *&h*&!*& *[&+&5+ & +(4&+0&x+P& +Xv&+`& +& +0&&Ԑ&H0bootinfo((snkELFH@ x@8@ 2A|8c|c"|#x!xc H`88!|`||c8N |```88`!P{ H`9 J;U)0W0PW|Hl||O|L,9)B8!|N |`9`8 | |~x9@a|#x"!A8 iI| 9)@B``€$@A@P{ xH`8} $xx H)`xx\ ;9/ A>@@H;{/ {@t8!8` |!AaN 8!8{|c|!AaN ||!A8pK8pHu`8!|N ||!A8pK]8pH`8!|N }mB| B|B| @yk}kx}k}-B| B|B| @y)})xH@@8| B@BKN |mB| B|B| @xc|cxN `"H<C`ނ)xd׶}#I`4| xtK@`"H< `)xdS}#I`y)| xK|8Tc0T0| PT||l|||L,8cBN ?|;+`?;|}x!a;,pH/AxxH)`;/@/;AX`8 €P| x /@|B8 `| "X; 9/Ax}B;8!x|N 8!;x|N 8!;x|N x8xH q`/@`ax<肀`8p88;H`/@x!p`bh A(8x| iIN!A({$/|~*A|/@8cPH#`8!x|N `"h|{y?;9/:/;/{ A8$x8txK1~x8p8xK$x8x8cxK txxx8p8K/{ AT/Atydap{(x/8 }%2,,&y)dx88~Gy@GAAT8A }$:}ix@}`x@A A`9y 9|;x} 9 HKy)}IKxB| X@@X@A/} XPA/8A0xd9E|2yJ9'}GRixP}`x@|x8Dx8K|xcxDx88KxKQ|{y@D8!|!AaN 'gy)})[x| X@A|~P/|b|cAKX8xd}'2|0.)x|KxK09 Kx8K|}xK\ ||x!K]8!|dxx|K|8!axpK%|~y8`A`?x;.HKx,#A\|xpxx8px8K/xA8axxKax8!|N 8!8`|N |;|x!K5/|~xA?K9;/x8p8@Ka<8ap8/Hw`/A$<8ap8/8 Hx`/@d8x<8.880xKx|8x8@K;8!`x|N 8x<8/88xK<8/88xK<8088xKu<8088xK]<80(88xKE<8x8.x8K-8x/@<9ax "x "_?H T >9J yJ8cyId/yJ&})PP}&JxG"( 0|c ,AxK1;x8!`|N ||x!qK/A<<8088p8KI/@ /xA(8p8Hx`8!|N 8r8Hx`8!|N |="A|3xa|+x|#x|~x8i.?;ɀ!!AK8/_|{xAX`낀>??B8::?;>;Z>; \0<<80Px8K8@x<H|xP80X<X8\pcxK<80`8K8/AxK/AP8> 09A h9)>hp>(8K88!|x|!AaN >$|XP| Px d}Zk @xd;? ?B;Z0;}cx88Hj`/AKU`; |exfxx8{ KE`xx8};Hi`xK`8!|!AaN k A<9)y x&x d}k@Pyh&}kByhE}kByh}kB| xT $|XP| Px d}Z@="0?B;)Д;;Z0y@>$yWM~P~Pzd~;w 88*cxHh`K`9 ;79 879 7|dx88w Hh`&Dx88w*Hhm`0K`8|exFxcxK`cx8*KY`/8`@x?9iy` x&x d}J8PyG&}J:yGE}J:yG}J:| xT $|PPX| PxdA>88}9.8}{ Hge`K`8|ex88} K`8}xxHgi`8!;8`|!AaN ; K;|x| H8, @x?b; x >$x M})XP|HPxd;{0KH@;Ay+My >$|XP| Px d}Zk 8@Klk 8A`9)y x&x d}k@Pyh&}kByhE}kByh}kB| xT $|XP| Px d}Z@K$_K,?b; x >$x M})XP|HPxd;{PHK?;;> K88ap88He`> /~ y8a|!rA$9)U+<Z9>i|Z@9` }i9!ni|ZBx x |Jx | |K9y y*&y+d}kPPyj&}kRyjE}kRyj}kR}+Jy)U+8 KxxHL`/@K8 x%xKY/@8`Kl 8`K\8`KT|88!|yxAa;!A|? x!;pxHN`;"Kߥ`;}Kߵ`x;*:F8`x88K`/AL]ix8i9)|Z@x x |Jx | |T>PALKM`/A8`8?|!AaN /@/D@/C@*/@KQ`~x8HN`/@l="1ip/Ax8HM`=:8y>89HJ`8`K8 |88V|}x!q|? x;pxHM`x8H88K=`8C8D8~84Km`8<818~8HJE`KA`8|dx8~8HL`xKe`8?8`|N |="a|+x8;{?|~x8i1!a|#x;1;HV`="1p{~ H KxK;/{ A\xHVe`/x@| 8!a|N |A|3xa|#x|+x/|x!aAXc9 /@ H}ISxH@@8}H/Ax/9IyJ 9iA}?P}+Jy) H@A;{ @@(}}/@L;{ @A8!Cx|ctA|xcтaN /A{/Ah@A/8@(HL}%Kx(@@@|(@/AA,/9%y) 8A|H|*x (@AȈ|x8HI`{<8 |J<8 K8!8`A|aN ;K8xdxxKK|a|#x8|+x8|~xx!A!AHG`<x8PP8HH`/8`@p;;:; ;@@L|}>|/4A@+4Ah/A+A/@;@A|`&Tc8!|!AaN /BAp+BA\/5A/6@\ )8 KЮ}=J)}>Ю8 Khi8 T>+A̙})8 K<8!8`|!AaN ;_8|Ю~x|"HE`}>Ю}=J)}>Ю8 Kț  )8 K )8 K8`K |="8|}x|#x8PP!qHE9`T >+@$8!8`|N |t9 } 6p A85=;/@2/A 828;6/@8|;x9`9 8 x !}(Jy) @/A<87?9 ;g8 /A ?;x  /@B/@ĈC/@t88!8`|N 868;K<84=;  2/A K8C;xHA`x8x 8HCy`?8 KP8B;xH@`x8x 8HC5`?8 C/AKp|8?1;x8H!ax;HB`8K`8|dx88HB`888apHBa`8p8qvsK 8848D8CK`8x8H8x KE`x8HK`8!|N |A;@8a?b;{2||x?1;x!a;;|t/|x/AAHC`dx/xAH@a`dx/xAH@I`x|P|}4{ 8apH?`}!Ip8ap88 HE%`;|c4T`>+4A4T@.|`||t/.@D;|tK48`8!A|aN x8apH=`8apH>`KXk|c4Tc~xcK|?1;x?;5!8A|zxa;;x|#x!1x|+xpH=Y`xcxH=I`_H;`8`8!|!AaN +@P/@Dx8,8@H4`8K(?1|$| P|p/a|#x!?@;PT?b;{2`/ALcxVtH@!`8$88!PTa|N 8apdx|VpH?)`p/A9!o9`i /@8apH?`Kt>PTy AP/8 x @@Kt|8;;|#x8!q|x8apH4`="19)$ /Axxx8 8K`="1 9)$88ap)x A(| iIN!A(8!|N )8ap8 88K=`;; Kd|="9i2x?188;$!Aa!1 )2x8axt!pH3}`/A?;@;`;p;2p;;: 8cH0`|vxxH0`|wxxH0`|xxxH0`}68 ||`8Exd 8CxKu`8;xH0`x8x #xH2`8cH0]`8x x9H0E`8xx #xH2`xH0!`8x x9H0 `8xx #xH2u`xH/`8x x9H/`8x#xx H29`="19)$8axdx) A(| iIN!A(8!|!AaN ;p?8cH/5`;2p|yxxH/!`;|{xxH/ `y|zx;{"xH.`{?{{8ax{d 88KU`;AK |?1;$A|#x||x/a;!aAl"8`?bK;{PTK`K`/|4A/AT >/AH/A?8i8  8!xA|aN  T >+@h8(;8Dx8!A|aN ?, 9i|AXm*/A@A4?8A| 8֑i;֐(K{Z ; @@?;2pH@x8H,!`,#A8c8H, `,#A;@@xH,`x8x xH0 `/@xH,`88c|}8 H1`xc 8$T>+A8`;KKd="9)x| } J})N  ܫ8$8ap88H.Y`{ ;/;Ax8 8xKձ`8="19)$8 8 8ap)x; A(| iIN!A(8(K8$8`KKl8(;K8(;K8(;K8(;Kt8(;Kd, ?@}e9kH?89`i|@D8(;K$i;8  Kȁ_0/A\+AT,K88 |cx H-`| K$<9k  H9)|  @?,8`;@H0/@<8(;KtK?8;4I9k8 4 K?8ap8!88Ku`;;!K8D;KȫK="19)$ c8i( DN |/?1;$8|#x!q(8@8H0_8$@/A}%<828H5A`+A4c;8 T>+A/|A(/AL8!x|N 8H`8!~x|N 8H`8!~x|N |A|3x<E`LFa؁#|;x|#x;|+x!a|x@\;/@L#;8 T>+A4#;8 T>+A/|A8/A8!xA|aN HY`ExPxxfxH}`8!x|AaN H`ExPxfxxHQ`x||~xHU`8!xA|aN |<E`LF!c8A8!p|x|N c/@c9kUk>+AСc9kUk>+A#/A,/@H)`8!p|`x|x|N H`8!p|`x|x|N |}&.%-胣|3xA|#x;@;|+x!|xaؑ!AH ,;*A؀/@/A} {=cxA,A(| ~^N!A(/@|cxH `}8|(Px |{H `cx/|xAPAL;A(| wWN!A(,*@08!@{C |!Aa} } N ]} ZPZK ,|@.}B/ADC*9`}(R|H| 0./A$8 8}(Kx| })R@8`N h N |}&.%- |3xA|#x;@;|+x!|xaؑ!AH 8;6A/@/}@ ]ZP{=cxA,A(| (~^N!A(/@$|cxHy`} 8(|(Px |{H`(cx/|xAHAD;A(| wWN!A(86@(8!|z|!Aa} } N   8|@.}B/ADC69`}(R|H| 0./A$8 8}(Kx| })R@8`N hN |!>#(:9>#a?;`|#x;8A|x:9!AH<;{;@{AԀ/@>^y)6d}9J {Z6dYx A/A 8;}?@.}B|*/8|*A̡_69`}(R|H}(Kx})R| 0./A8 8| @}?(*x"x $x.| Pc}bx }b+@ }|Z})| @x~óxH`>J@x@ }?@.}B|*/8|*@<}?(*H@@h~xH`K9xxd}KR}jZ}iN t@tt4 ttttttttttttttttttttttttttttt TtHtttttttttttt | KpT: Kdx x|  KPx KD K+ 9KUJ>+ |4@8 T>+8 9k@M }`4(9)AN /@p/08@d /x@@8 i| xKDN +$8$8`@N /xA 9`0K 9)$jK,$|ixAP+$$8`@N 9)$i/ / , A/ AAA/-}*Kx8A/@/08 A/8`A8`H,|4(9)@h|e$i/|cAP8 T>+ 9KUJ>+ |4@8 T>+8 9k@A}`4(9)A/M |cN /@d/08@X /x@X8 i| xK89)/$8j@K+$8$8`@N /xA 9`0K8 i| xK||!;#a;cW9&A?B1{8 {} 9;$|x!A~/A}#9c@@ ~}i[x )@T 6/x(|;x@,xI|;xxE|;x}G;x@@4@8Ix |CxyJE}HCx|Cx9})BK@A@@ ~89 HA0IyyW( x}Cx|xxExE|Cx|#x|;x|x}B8xG" UJ6}JCxxIx 8 x(Kx |xyJE}Jx} Sx8 }k@@T /)T 6/x(A8x(K9 x |xyJE}Jx} Sx8 }k@A/@@xK`@x|c~K}i[xKL#xK}`/~AL|~}#@9cA{G"{{aC8!:$}c[x|!AaN 8@@|8P9i{G"}K`c{i{xxG"x| 8! }c[x|!AaN T>` 8!9i}c[x|!AaN 8!9`}c[x|!AaN  T>N |/8!!AA/A8H-`|`x8!p|x|N ||+x|#x!8|xx`H ]`8!p|N |=b|`x!8kP|x8!AH i`8!p|N / |`x8`M / M / M / M |4T~|N ||x!q/A/A#} A /OA|d9)})/@<8PK}`|c/At/O@p89 k?|c8!|N 8p8K%`/8`@Јap8!|N 8`?8| K|a|+x|~x8`!A!A$/A;;;?B; H(9)U >+ A </AH8 T >+)A9zx| }`Z}iN HTH,TxKxx xKY/@;x8 ) Kyxc K-/@/Aԁ>/@9)></@8`8!|!AaN xK/xx A8H~xH`/AH}! px;Kxx ~xKm/A}!)p8apK`/A8;8ap88 8 Ki`xK@~xH`/A}! px;K1xx ~xK/AKlxK /xx A4H8T>+A}! px;Kxx xK/A}!)p8apK-`/AL;8ap88 8 K}`xK@P8T>+A@}! px;KIxx xK/AKtxK%/xx AH(@}! px;Kxx xK,#A}!)p;8p8 iK`K0}! px;Kxx xKQ/AKxK/xx A8H~xK`/A}! px;KIxx ~xK/A}!)p8apK`/A;8ap88 8 K`xK\@~xK`/A}! px;Kxx ~xK]/AKl}!)p/A>/@9)>8apK`/@8!8`|!AaN }!)p/A\>/@P9)>KD}!ip/A >/@9)>K}!)p/A>/@9)>K| |||x;|#xa!A/A ;;`%H ;/A/%x@9Ao9 9h ;}k/dAl/iA/xA/XA/pA/cA/sA/%A/OA,/oA }h[x 9h;/d}k@9(})8d}aZ}!J ppx8p8Kq/@ x ;/;@8!xa|N 8o9(})}aZ}!J ppx8p8K/AK8iK8xK8XK8pK8cK8sK9H}J}aZ}ARkpxpKX8OKxK="8iPKlxc 9#8(+ 8c+L(B|`&Tc?OYB} &U)OB|&T|cKx|cx|cN ||+x|#x|x!A|x8@8apHi`8p|~x{ Ky}`8!x|N |="9): 8T>+ I|+xi|x|#x!a8ApaxAT @@p="1i%/Ac9@- %K#9)#9ap}k8i?9)?8!|x|N +xK-9ap?8!8|xP}k讙i?|9)?N #Kd|a}Cx|;x|3x|~x|#x|+x!a8 8K`/|c9 A 9 9)})/@y) })H@<})P/})@,9)y+ >9k}i>9)>B8!8`a|N ||ixa>b:s: >!;a|#x|{xpx!AA!;@|1/A8}{HP@,/%A 8!p/9)!p@8 ap8!@|{P|cp|x!Aa!AaN 8%9ao 9@9 |+x/d}Ax/iA$/uA$/xA$/XA$/pA$/cA$/sA$/%A$/OAL/o8A } Cx9 |+x/d}@9j}k}aZ8d}Bp9 paq/0Ap/.: ;qA`/}{xAl:;:: : 0}H88 T>+ A8p} i;{ };/A@8 T >+)A95&x| } J})N |(\@\$|\(8o9j}k}aZ}Bp9 paq/0@ar:0;r/}{x@8K9!p88 8aKe`x xKI`@@8|cPxc!A,8c!pxc 8c|i!p9)!pB;H$|;!p{ !p8 pxK`@AK(8p}  8x88 9xK!pxx)8!p8 p8x !p8 pK]};/@!p}{x8Kԉ}8/lA|x:K}8/hA|x:KxV88 ~698p}  xA,!p8- z$}3JapI8 p}Ґ8~Ex8 ~x98xKx~Dx8 K};K8p}  x888 8 9K!p};!p8 pKz$}3JI8p} Ґ8 8~Ex~x98xK5x~Dx8K};KXz$}3JI8p} Ґ8 8~Ex~x98xKx~Dx8K};K}:;K}:;K8iK8uK8xK8XK8pK8cK8sK9j8%}k }B}aZp9) p!p8K8OKP@HXNo net_xmit function availableNo net_ioctl function availableNo net_init function availableNo net_receive function availableCan not open "%s" because file descriptor list is full net_e1000ELF loading failed! net_bcmnet_vethnet_virtio``/rtas Could not open /rtas rtas-size Size of rtas (%x) too small to make sense Failed to allocated memory for RTAS Could not open /rtas instantiate-rtasinstantiate-rtas failed read-pci-configibm,read-pci-configwrite-pci-configibm,write-pci-configget-time-of-dayibm,romfs-lookuptestdma-map-outdma-map-ininterpretclosewritereadseekgetpropassigned-addressesregpeerchildparentfinddevice/chosen/aliasesnetbootpathopenclaimreleasecall-methodrtas-read-vpdrtas-write-vpdset-ledwrite-mm-logyieldset-callbackbootmsg-warningbootmsg-errorname#address-cells#size-cellsrangescompatibleIBM,vdeviceibm,virtiovendor-iddevice-idrevision-idclass-codeinterruptslocal-mac-addressstdinstdout No net device found /cpustimebase-frequencyclient-interface module initialized! my-parent```:////@/: ERROR: Bad URL! ERROR: Bad host name! ERROR: Can't resolve domain name (DNS server is not presented)! Giving up after %d DNS requests bla %02d Giving up after %d bootp requests . %03d Aborted Giving up after %d DHCP requests %d KBytesblksizeoctet%d Receiving data: Repeating TFTP read request... Lost ACK packets: %d Bootloader 1.6 E3000: (net) Could not read MAC address Reading MAC address from device: %02x:%02x:%02x:%02x:%02x:%02x E3006: (net) Could not initialize network devicebootpdhcpipv6 Requesting IP address via BOOTP: Requesting IP address via DHCP: E3001: (net) Could not get IP address%d.%d.%d.%d E3002: (net) ARP request to TFTP server (%d.%d.%d.%d) failedE3008: (net) Can't obtain TFTP server IP address Requesting file "%s" via TFTP from %d.%d.%d.%d TFTP: Received %s (%d KBytes) (net) unknown TFTP errorE3004: (net) TFTP buffer of %d bytes is too small for %sE3009: (net) file not found: %sE3010: (net) TFTP access violationE3011: (net) illegal TFTP operationE3012: (net) unknown TFTP transfer IDE3013: (net) no such TFTP userE3017: (net) TFTP blocksize negotiation failedE3018: (net) file exceeds maximum TFTP transfer sizeE3005: (net) ICMP ERROR "net unreachablehost unreachableprotocol unreachableport unreachablefragmentation needed and DF setsource route failedE3014: (net) TFTP error occurred after %d bad packets receivedE3015: (net) TFTP error occurred after missing %d responsesE3016: (net) TFTP error missing block %d, expected block was %d ping device-path:[device-args,]server-ip,[client-ip],[gateway-ip][,timeout] 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: Ping to %d.%d.%d.%d success failed Reading MAC address from device: netbootpingUnknown client application called argv[%d] %s No such callback function `` ELF relocation out of bounds! ERROR: Unhandled relocation (A) type %i 0123456789ABCDEF\`   \   0 l  $$ XX(@ 0Th|@X,$p  L !(!"h#$$$%l& &'$'(8()|**+X+,X,/0<13H366H7@778t89d999:$:::;D;\;t;;;;<FPU \d0 pH$:(H|8Px 8xHHtp< % .`$6DI:Z(PaluiXXlܐ(tX._start_kernel.callback_entry.exception_forwardcall_client_interfaceof_testmdelaystrcpyset_ipv4_routerioctltranslate_address_devprintfvsprintf.undo_exception_prom_entryrecvhandle_arpget_arg_ptrset_timersend_ipv4get_sec_ticksmemmoveglue_inithandle_udp_lowmem_startfd_array._exitrtas_tokenrmmod_by_typeof_finddeviceread_iomemcpypingset_ipv4_addressrtas_pci_config_readromfs_lookupmalloccimod_check_and_installrtas_callvsnprintfset_mac_addressof_getpropwrite_ioof_set_callbackhandle_udp_dunstrtoulhandle_dnsof_call_method_3handle_ipv4socketsnk_modulesof_moduleof_release__client_endelf_load_file_to_addrtb_freq_system_call_lowmem_end_callback_entrysendget_mac_addressget_timerisxdigitstdin_datapong_ipv4strtolmodules_initglue_releasefill_udphdrof_claiminsmod_by_typeget_macwritetranslate_addressof_writehandle_tftp_dunmodules_termof_readget_puidrtas_pci_config_writehandle_dhcp_startstrstrreadnetbootstrncmpof_closestrncpyudelaystrcasecmptftpget_args_count_rtasmemcmpof_childprintk_entrystrtoipsnk_kernel_interfaceof_opensbrkelf_load_segments32elf_load_segments64handle_tftpsend_ipmemsetmaingetchardns_get_ipelf_get_base_addr32dhcpexception_stack_framestrcmp__client_startsprintfrtas_call_entrybootpdhcp_send_releasesend_etherargncpyhandle_tcp_dunmalloc_alignedstdout_data._callback_entryisdigit.call_client_interfaceof_interpret_1set_ipv4_netmaskbootmsg_errorwrite_mm_log_gotcallback_exitping_ipv4handle_tcpfill_iphdrof_parentstrlenopendns_inittoupperget_module_by_type.rtas_call_entrystrchrelf_get_base_addr64elf_relocate64rtas_argsfill_ethhdrundo_exceptionrtas_initclosereceive_ethervfprintffree._entry ) b2f2r2v@z0~@$ 22@R2V2 Z0^0$b2f0x 22@@2(@(20$ $  G 0V <Q D 8HH  8 20@0   8 ـ 2X0Xd Z28^@820@0@ ـF20J@02@@@2206@0  20 @0 R2 V0 \d     $  2ʸ 0ʸ d    2ʘ 0ʘ d  2x 0x d  H)  `$  0  8o  p  x  22H 6@H \ @ n2H r@H  @ 20 2"0<u ^2Pf@P2X@X ( 22`:2ڠ>@`J0ڠL; b2hf@hL 2h@h2(0(&2h.2x2@h6@x:2pB2PJ2^@Pb@f@p2020 ڸ2X@X* &2X2@X2X@X20260X ڸf2Pj@P2X@Xp,x,???  ??&&@(&H8&Xd&]& &0)&8~&@&Hu&Po&&&X&M&&!& K& &(38&\@3P&X3h&p3ڀ&ڈ3ژ&ڠ3ڰ&ڸ3&`3&3& 3& 3(& \03@& H3X& `3p& 0x3ۈ& lې3۠& ۨ3۸& 3&$3&$3&3&  30&83H&P3`&h3x&܀3ܐ&ܘ32h0h" 2@2ˈ0ˈ. (~ <h R2V0\4 2@2p0p2@2˘0˘2 @202"@&2*062:@>2 B0 ^2n@.  ۨ2@2@x 2@ x 8 ۨF2@J0@L R2HpV2PZ0Hp^0Pb0Hpd n2hr0ht z2̀0̀ 2̘0̘ 2Hp0Hp@Hp+ `+ 2Hp0Hp+ + F2HpJ0Hp+ 2808228608 n 2̨0̨ `n j2~0 20 n $ b2j0 n  Tn ^2f0 n 20 L[ n 20  ,O  |n  2 0 !R !Xn !b2!j0! !n "2" 0"0 "2 "0 ". #28#08#n #2@#0@# $0n $:2H$N0H$X $n $2P$0P$ %n %"2X%60X%@ %r2h%z0h%" %2͈%0͈%. %" %2p%0p%" %2̀%0̀%. &,n &62͘&J0͘&T &h &2H&0H&2ݸ&2݈&2X&0ݸ&0݈&0X'Tn '^2͠'f0͠' 'n '2ͨ'0ͨ( (hn (r2Ͱ(z0Ͱ( )n )2)&0)H )n )2)0) *Tn *^2*f0*| *n *2*0* +n +2+0+0 +xn +2+0+ +n ,2,0,( ,n ,2 ,0 , ,20,00-(. -8 -L -R28-\ -b2H-j2X-n08-r0H-v0X-. -. -. -. /. /,. /4 / 0 x0, 0` 0r280z080 0. 0 18 x1J2`1L 1R0`1`. 1f2p1n0p1pu 12΀10΀1Z 1281081. 1. 2 2ΐ20ΐ2. 2"2Π2&0Π24. 2:2ΰ2>0ΰ2L. 2R22V02d. 2j22n02|. 22 20 2. 3 S 3\ x3j23n03x. 3$ 3$ 32h40h4"2H4*0H48" 4V24Z@4^2ݸ4b2݈4f2X4r0ݸ4z0݈40X42404. 42404. 42404O 5 52(50(5" 5 c 5.2052005<. 5@ 5J25R25V@5Z25^@5b(25jN25r25z05~(05N0505J 525062H6"0H689 6' 6T 6' 6T 7h' 7T 829@929092H9&0H9f29j092I9@I9O 92I9@I:R :*2p:20p:B2I:L :^0I:`R :r@I:|O :2:0:?P&PX&hh&ިp&܀x&ܘ&ܰ&&&0&&ܨ&ܰ3&X3&3&(3&3 &(38&@@3P& X3h&0p3݀&T݈3ݘ&hݠ3ݰ&|ݸ3&3&@3&3&X3(&,03@&H3X&$`3p&px3ވ&ސ3ޠ&Lި3޸&3& (3& 3&!h3&" 30&#83H&#P3`&#h3x&$l߀3ߐ&% ߘ3ߨ&%߰3&&$3&&3&'83&'3 &(|(38&)@3P&)X3h&*Xp3&*3&+X3&+3&.3&/<3&03&2H3(&203@&5H3X&5H`3p&6@x3&63&63&7t3&73&8d3&83&8 30&883H&9$P3`&h3x&3:2I:0I<<2<<0=2<2=6<0&93&:D3&:\3&:t3&:3&:3 &:(38&:@3P&;X3h&;xp3&;3&;3&<03&20I>00I>,n >D >f2π>n0π>tb >5 >2?0? b ?(b ?Lb ?l ?@ @$ @,$ @^20O@b00O@00O@n @m2@m0@2@0Av20OAz00OBb2ψBf0ψBxb BA B B$ B{ C20OC2ψC00OC0ψCn CA D$ D$ D(A D@ DP{ Dn DA E E $ E2ψE0ψFv2F0Fn G2ψG0ψH220OH:00OHN00OI$$ Ix I1 I} J20OJ00OJ$ pJ620OJ:00OJr20OJv00OJz2J0J0J20OJ00OJ2J0Jn K20OK 00OK"20OK&00OK, pK>20OKB00OKZ20OK^00OKd pKv20OKz00OL20OL 00OM\ M M$ N $ N@ N20ON00OOA O b P8n PDA P\ PdA P$ P$ P{ P2ψP0ψPb Q$ QD$ QT{ Qz20OQ00ORn R\ R~20OR00OR3 S4U STl SP TJ21xTR01xTX Ttn T T TI U U U$ VV2ӸV^0ӸV` V21xV01xV21xV01xV2ӸV0ӸW W&2ϘW.0ϘW0W WB2ϠWJ0ϠWLW WZ2ϨW^0ϨWhW WW W2ϰW0ϰWW WW W2ϸW0ϸWW WW X2X0X  Xd\ X X Y \ YT Y` Yt hYx Y YB Y Y Y2Z0Z Z@ hZJ2ZN0ZP Z2ϸZ Z0ϸZW Z [ 2@[0@[ [21x[01x[ \21x\01x\:21x\>01x\x \u \u \ ]n ] ] ] ^B ^A ^b ^21x^@1x^$ ^ _8n _T _lI _z2h_0h_ _A _$ _ _2p`2x`*0p`:0x`@ `J21x`N@1x`X `` `| `2Ѐ`0Ѐ` `2Ш`0Ш` al$ a$ a$ c$ c (dXn db2dj0dpb f $ f$ g*2gJ0gP$ h i$ i8 iT$ i21i01in iA i$ in j pj,I jL j\ j2аj0аj21j01j kW k W k<\ k\F k k l&21l.01l22Ӹl>0Ӹl l l2иl2l0иl l0l lp l l l m mB mH mPp mb2mf0mh m2m0m m n n^2nf0nh n n nq o"21o&01o@n oV2Ӹo^0Ӹod olA o$ on o poI o p phn p~21p01p$ p2p0pb p Xqp q q\ q$ r 2r0rb r8\ r$ r @r Xs s8 s\& s sn sA s$ tn t $ t8$ t` pttI t t t\ t t u @u @u0\ up u u2Ӹu0Ӹu u u\ v2Ӹv0Ӹv vD\ vf21vn01v2v0v2v0v v01v0w w w< wJ0wn w21w01wI wm2wm0xT xz2 x0 x21x01x0 xn x2x0y y y, y< ydI y y$ y y y$ y y z$ z z8 zP$ zZm2z^m0z2z z0z z { {< {b21{j01{2{ {0{ { |2|0| } }, }Db }X }p2 } }2|}0|}n ~(I ~6m2~>m0~ p$    V21Z0121012(0(w 2000  2H"2$ .0H0 :0< 0D xB     P X 0 2ј0ј 2p0p TF lF F F F 2ј0ј 2ш0ш n  6 p < D LB l6 20 - ` 20($ 20V0f2j0| 2`0` @_ 2҈0҈ s 20 &2*0@w P \ p n 2$ 0b b $$ :2ӘF0ӘH V2`Z0`\ pb y \ | f n 0 \n pn |  |  | 2H&0H(^ L dz |b b & $ 2P0P^ 2X0X^  &220PF n F b $ b $ 0n L|  | f n  (| 8f `n p 2Ұ0Ұ    20 2@0@w  2&0(w 4 B2XJ0XLw \ h | n 20 2@0@    2,0,B2 J0 Pw ` l  2p0pw    2(0(    620:00@w P \ p 2h0h    2Ԑ0Ԑ    2Ը0Ը$ 4 @ T f2j0p    20    20 w  ( < N2ѠR0ѠX h t  20w     2Ո 0Ո w  &2ՠ.0ՠ0w < J2ոR0ոTw ` n2pv0pxw  2`0`w n ` $| 4f T| df | n 20 6 2X0X - ($ 22נ60נ8 D& R2V0h |$ 2׸0׸     E (B :2>0@ f2҈j0҈l s 2x0x | f  | f , L| `F r2v0x | f 2ְ0ְ   2(0( "2&0( $\ 2а0а W W 0\ PF \  2ј0ј( 22X60X8 J2HV0Hh ?2?00 20u 20u "2 &0 ( >2HJ0H\ % Y &H3X&>`3p&?Xx3&@$3&F3&I3&I43&IP3&J3&J  30&J<83H&JXP3`&Jth3x&J3&J3&M\3&Pp3&Q|3&Q3&R3 &R(38&R@3P&SX3h&S p3&TL3&U3&U3&Z03&\,3&^3&^3(&`03@&aH3X&c`3p&f$x3&h3&i3&k3&n3&o,3&u`3&vt 30&wt83H&zXP3`&Th3x&|3&3&3&D3&3&3&h3 &(38&@3P&X3pj k r j  k 0  r h&p3&3&p3 8n &<3&3L ln 2ؘ0ؘ2x2p0x L Z0p&h3&3&3(&03@&dH3X&`3p&x3&@3&3  Z &h3&P3&3&3&P 3 ( 0&83H&P3`&h3x&3&3F21f01Hi ti @1&$3&3p &43, &320 &3@&1`&1PX 8X 2000 8   8  8C  8  F 4C T 8h | 8 8  F < 8L ` 8 8   8  8 < 8P h F   8   P P 8D2D0 8 &@(38&@3P&X3h&p3&3&3&(3, M &320V21Z01n01 l2 &2.062ŜƆ0ŜǬ2 Ǽ , d Ȝ \ l ɠ   L \ &3&,3&3`&`&&`&&`&`&`&`&`&`&`&?`&`&`&`&`&`&`&`&`&`&`&`&`& `& `& `& `& `&`&`&`&`&`&`&`&`&`&`&`&`&`&`&`&`&`&e)e'ee?>&&&v&:&<&&&t7&<&7& 7& v& g& #& /& (8& 0t& 8&@ @& Ht& P=& Xa& `g& h& p& x'& T& g& &0net_vethELF@ @8@ x h|`="9bh9)t8}iXP!x`@D#y !?@? =)? /AD8!x|!AaN ?x) A(| iIN!A(KX8!;x|!AaN  |`;(a;`/!aA,8!cxa|N ?< 8)88`  A(| iIN!A(?880)88`8 A(| iIN!A(?8`)0`c A(| iIN!A(0@/A8/A/A/A`cP8x,= 8a)Hy&8`yH`;|dy@?`;c{c?H8`| x,| *{~x;H`@?(8!8 ;`cxa|N ?0@ r2 Xv0 X202 0  z200  j2 n0 2 0 200 2 20 0 0J2 V0  2 00 0&  8&  P&  X&  `& p p& x3 & 3 & 3 &p 3 & 3 & 3   P P >P BP ^P bP((0net_e1000ELF@@@8@ pUp|=b="9kH9)j8}iXPx`!|ix@P#xcTD.|KxTi>TcD.T|cKx|xxc |N |`9"`x !x)T >TD.)`T>| Sx9b TD.kUJA(|Cx| }D#x|cZix 8IN!A(8!p|N 8`N ||}x8`(;!qK`9"?@XA9kyk&Z x @(8!x|N }iX*xyi"yk y  yj UF>T>y)ykUDD._@0TD.|3x|CxUf>U(>UkD.U)D.}k3xT})CxTT>TD.|[x|KxCxy) x|Kx;| P{ H `x88H `|@8`(K!?@8!x8 T~@|N |?;~/!qA8`8K88`K`;8` `=;?) A(| iIN!A(8`(8KQ8`(8KE8`88K988`8K-8`TKxd`8`TK8`K}ddx 8`K=8` ) A(| iIN!A(8`K=ddx 8`K=8` ) A(| iIN!A(=88)( A(| i@(@)@~@ IN!A(=<@0x)0`@*|" A(| iIN!A(88!8`|N |8`?;~/!Aa!1A88!|!AaN `;`;=<`@*)(8x ?A(| iIN!A(=8|P) 8~@0 A(| @(@)i~@ IN!A(=T`6x)p A(| iIN!A(=8@(8) @) A(| i~@ IN!A(8~@x 8`Km8`Kx`@=8`d;@0) A(| iIN!A(8`K|`xH@=;Z) A(| iIN!A(8`K]{Z!|`xApx 8`dA9`}i9<O8i| x B/;n; Aĉ<S\RU)|PUJQU}IKxT}iKxT@.T@.|Kxxx { 8`TKag8`Tx KQ;Tx8KA8};xc 8{ K)/T@;;;]{C&|88He`|@0/{&}(y "y) x  y* UE>Uf>xy)UJD.UkD.}J+x}k3xU%>T>U)D.TD.UkUJ})+x|3x}`x}IKxy)x }:} x]x ;{0@\;{"8`8K]{ 8`8KQ8`88KE8`88K98`88K-<8``K?8`8K ;{(;8}xc&|88HQ`|@0{&;}(y "y) x  y* UE>Uf>xy)UJD.UkD.}J+x}k3xU%>T>U)D.TD.UkUJ})+x|3x}`x}IKx/y)x }:} x ;{0@\8;@{"8`(KA{ 8`(K58`(8K)8`(8K8`(8K8`( 8K88``K8!88`|!AaN ;@9 )H0a$8`x K8`KI9|`x@=8`:) A(| iIN!A(8`K|`xH@=:) A(| iIN!A(8`Kz!|`xA| 98`A;9/T>{9 A,;@x 9 @,x ;@9 AKtx @!rW>pU*><RT>Py$Q\S|x|UTKxk8`@K|k9@d=UD.UF>xykUJD.|c+x}J3xUe>T>UkD.TD.}k+x|3xUJTc|c[x}@xG@0x xc|cx|jP{ H`{ T @.T>} x8 8 |88`8x`K8!x|N 8!;x|N #8`|hx8`L H2B0J2R0          2(0(f2j0n2r0d l   p      t                             8  @      @ z2( ~0(   (  8  R2 V0   20020@@&H&`&h&p&&<3&3&d3&x3&3&3& 3(&t03&X&p&(&@&X&p&& &0&@&P&`&p&0&H&`&x&&&&&&&@&4H3X&l`3&H&0net_virtioELF@@8@ x@|`="9b9)mH8}iXPx`|x!q|#x@P#8`TD.|xxc @x i8HQ`8xc A(| {[N!A(/|{xA8H`8xe cxH`8`@8|ft|x x  U+>xU&D.|[xT >TD.|[xTƀ|x8x D"?;/y &y)d| 9)} Jy)?;0@8="|;~/;8`<8|D"/8;@x |4|@x8H`;8!xa|N <|#x8`@88x D"|8`<88 D"/8`xc @x T>TD.|cx|cN |x/8@x T@.T>|#x8`@88x D"|8`<88D"</`x`@4x x U >xU)D.})xT>TD.U)|[x|Kxxe|xN ||}x|#x!qK)x|xxK8!xc&||N ||}x|#x!qK}x|xxK%8!;xcd||xcN /L 88`@88D"N /L x T@.T>|#x8`@88x D"N |#x/L 88`@8x D"N |#x/L 88`@8x D"N |#x/@(/;AX@(/A/Al8`N /@8`<8|D"/8`@x K8`<8|D"/8`xc @x K8`<8|D"/;{@x88`<8|*D"/8`xc @x |cxKL8`<8|D"/8`xc @,x K$||3x/A$;x|N /#@9i8;x |Z||(P|;8`<8xD"/8;@x |4|@x|N Module size (%llu bytes) is too big! virtio-net: Receive buffer not big enough! virtionet: Packet too big! virtionet: Failed to allocate buffers! First BAR is not an I/O BAR! malloc failed! P8 <P4  < x  @  \   @ x GCC: (GNU) 4.6.3.symtab.strtab.shstrtab.rela.code.got.bss.comment x &0+0000A9p 0O8)<0XD@N`Q0[@Doh<8(4@X8$p88dvirtio_get_vring_descvirtio_vring_sizememcpyvirtionet_interface__bss_endvqvirtiodevvirtio_queue_notifysnk_kernel_interfacevn_module_init_pci__bss_startmemsetvirtio_reset_devicesnk_module_interface__module_end__module_startvirtio_get_qsizevirtio_set_statusmodule_initvirtio_set_guest_featuresvirtio_get_vring_avail2"2&0*0b2n02 20 0 20 22 0020 &3V 2b 0j2r0  006 2: 0L ~ 2 020 2 020 2 0  2 020:2F0b 2f 0p | 20 2 0  0 : 2> 0j 2r 0*2.00 @ ~2000 &P&8&& &&<3&P3 &(38&4@3P&X3 2 0. 26 0  2  0 ( h |  2O 0O d  2x 0x 2X 0Xh&p3& 3& <3   (  |   & x3& 3& @3& 3& \3(& 03@& H3X& @`3p& xx3& 3&3<<](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 occured 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 occured 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 430fbuffer.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 : 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 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 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-width * screen-depth * ; : fb8-columns2bytes ( #columns -- #bytes ) char-width * screen-depth * ; : fb8-line2addr ( line# -- addr ) char-height * window-top + screen-width * screen-depth * 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 0 ?DO char-width screen-depth * 0 ?DO dup dup rb@ -1 xor swap rb! 1+ LOOP screen-width screen-depth * + char-width screen-depth * - 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-width screen-depth * + >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-width screen-depth * tuck + -rot + swap rot LOOP 3drop r> THEN char-height 0 ?DO dup 2 pick fb8-erase-block screen-width screen-depth * + 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-width screen-depth * tuck + -rot + swap rot LOOP 3drop r> over - THEN char-height 0 ?DO dup 2 pick fb8-erase-block screen-width screen-depth * + LOOP 2drop ; : fb8-reset-screen ( -- ) ( Left as no-op by design ) ; : fb8-erase-screen ( -- ) frame-buffer-adr screen-height screen-width * screen-depth * fb8-erase-block ; : fb8-invert-screen ( -- ) frame-buffer-adr screen-height screen-width * screen-depth * 2dup /x / 0 ?DO dup rx@ -1 xor over rx! xa1+ LOOP 3drop ; : 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-#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 ; : fb8-set-tokens ( -- ) ['] is-install 0 11C set-token ['] is-remove 0 11D set-token ['] is-selftest 0 11E set-token ['] #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 ; fb8-set-tokens : 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 ; 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 W0pci-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 ; : 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 ; : 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 V0pci-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 : 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" unknown-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 0001 OF s" 8514-compatible" 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" unkown-bridge" ENDOF ENDCASE ; : pci-class-name-07 ( addr -- str len ) pci-class@ FFFF and CASE 0000 OF s" serial" ENDOF 0001 OF s" 16450-serial" ENDOF 0002 OF s" 16550-serial" ENDOF 0003 OF s" 16650-serial" ENDOF 0004 OF s" 16750-serial" ENDOF 0005 OF s" 16850-serial" ENDOF 0006 OF s" 16950-serial" ENDOF 0100 OF s" parallel" ENDOF 0101 OF s" bi-directional-parallel" ENDOF 0102 OF s" ecp-1.x-parallel" ENDOF 0103 OF s" ieee1284-controller" ENDOF 01FE OF s" ieee1284-device" ENDOF 0200 OF s" multiport-serial" ENDOF 0300 OF s" modem" ENDOF 0301 OF s" 16450-modem" ENDOF 0302 OF s" 16550-modem" ENDOF 0303 OF s" 16650-modem" ENDOF 0304 OF s" 16750-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 0001 OF s" isa-pic" ENDOF 0002 OF s" eisa-pic" ENDOF 0010 OF s" io-apic" ENDOF 0020 OF s" iox-apic" ENDOF 0100 OF s" dma-controller" ENDOF 0101 OF s" isa-dma" ENDOF 0102 OF s" eisa-dma" ENDOF 0200 OF s" timer" ENDOF 0201 OF s" isa-system-timer" ENDOF 0202 OF s" eisa-system-timer" ENDOF 0300 OF s" rtc" ENDOF 0301 OF s" isa-rtc" ENDOF 0400 OF s" hot-plug-controller" ENDOF 0500 OF s" sd-host-conrtoller" ENDOF dup OF s" system-periphal" 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 00 OF s" 386" ENDOF 01 OF s" 486" ENDOF 02 OF s" pentium" ENDOF 10 OF s" alpha" 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 0380 OF s" usb" 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-smic" ENDOF 0701 OF s" ipmi-kbrd" ENDOF 0702 OF s" ipmi-bltr" 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 20 OF s" enet-802.11a" ENDOF 21 OF s" enet-802.11b" 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" satelite-tv" ENDOF 02 OF s" satelite-audio" ENDOF 03 OF s" satelite-voice" ENDOF 04 OF s" satelite-data" ENDOF dup OF s" satelite-devoce" 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 0C OF pci-class-name-0D ENDOF 0C OF pci-class-name-0E ENDOF 0C OF pci-class-name-0F ENDOF 0C OF pci-class-name-10 ENDOF 0C 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 ( size var -- al-mem ) 2dup @ \ ( size var size cur-mem ) read current free mem swap #aligned \ ( size var al-mem ) align the mem to the size dup 2swap -rot + \ ( al-mem var new-mem ) add size to aligned mem swap ! \ ( al-mem ) set variable to new mem ; : assign-bar-value32 ( bar size var -- 4 ) over IF \ IF size > 0 assign-var \ | ( 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 assign-var \ | ( 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-mem \ var to change assign-bar-value64 \ and set it all ; : assign-mem32-bar ( bar-addr -- 4 ) dup pci-bar-size-mem32 \ fetch size pci-next-mem \ var to change assign-bar-value32 \ and set it all ; : assign-mmio64-bar ( bar-addr -- 8 ) dup pci-bar-size-mem64 \ fetch size pci-next-mmio \ var to change 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-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 ) 83000000 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 ) 20 lshift or \ and calc Limit ( addr paddr plen base.63:0 limit.63:0 ) 42000000 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 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 2dup device-name device-type 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-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 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 ; : 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 pci-device-props \ and generate all properties drop \ forget the config-addr ; ( 8pci-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 ; : map-out ( virt size -- ) 2drop ; : dma-alloc ( ... size -- virt ) alloc-mem ; : dma-free ( virt size -- ) free-mem ; : dma-map-in ( ... virt size cacheable? -- devaddr ) 2drop ; : dma-map-out ( virt devaddr size -- ) 2drop drop ; : 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 load-base over flash-image-size rmove true ELSE false THEN ; : flash-read-perm ( -- success? ) get-flashside 0= IF flash-addr 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 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 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 load-base (xmodem-load) ; @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 : (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 ; : (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 ) 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 i dma-virt2dev \ ioba i 3 OR \ Make a read- & writeable TCE hv-put-tce ABORT" H_PUT_TCE failed" 1000 +LOOP r> dma-virt2dev (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) nip ( 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 i dma-virt2dev \ ioba i \ Lowest bits not set => invalid TCE hv-put-tce ABORT" H_PUT_TCE failed" 1000 +LOOP (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 ! 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 pci-next-mem ! \ Decode mem base address decode-64 drop \ Forget the parent address decode-64 2 / dup >r \ Decode and calc size/2 pci-next-mem @ + dup pci-max-mem ! \ and calc max mem address dup pci-next-mmio ! \ which is the same as MMIO base r> + pci-max-mmio ! \ calc max MMIO address ENDOF 3000000 OF \ 64-bit memory space? cr ." Warning: 64-bit PCI space not supported yet! " decode-64 . decode-64 . cr ENDOF ENDCASE REPEAT 2drop phb-debug? IF ." pci-next-io = " pci-next-io @ . cr ." pci-max-io = " pci-max-io @ . cr ." pci-next-mem = " pci-next-mem @ . cr ." pci-max-mem = " pci-max-mem @ . cr ." pci-next-mmio = " pci-next-mmio @ . cr ." pci-max-mmio = " pci-max-mmio @ . cr THEN ; : phb-setup-children puid >r \ Save old value of puid my-puid TO puid \ Set current puid phb-parse-ranges 1 0 (probe-pci-host-bridge) r> TO puid \ Restore previous puid ; phb-setup-children M(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-entry 0 VALUE rtas-node 372 cp : find-qemu-rtas ( -- ) " /rtas" find-device get-node to rtas-node " linux,rtas-base" rtas-node get-package-property IF device-end EXIT THEN drop l@ to rtas-base " linux,rtas-base" delete-property " rtas-size" rtas-node get-package-property IF device-end EXIT THEN drop l@ to rtas-size " linux,rtas-entry" rtas-node get-package-property IF rtas-base to rtas-entry ELSE drop l@ to rtas-entry " linux,rtas-entry" delete-property THEN device-end ; find-qemu-rtas 373 cp : enter-rtas ( -- ) rtas-cb rtas-base 0 rtas-entry 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 ( -- ) " 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) " ibm,read-pci-config" rtas-get-token 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 ffffffff and 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 ) " ibm,write-pci-config" rtas-get-token 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 ffffffff and 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 ; : instantiate-rtas ( adr -- entry ) dup rtas-base swap rtas-size move rtas-entry rtas-base - + ; device-end 374 cp 8pci-device_1234_1111.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@ ; : vbe! ( value index -- ) 1ce vga-w! 1d0 vga-w! ; : vbe@ ( index -- value ) 1ce vga-w! 1d0 vga-w@ ; : draw-rectangle ( adr x y w h -- ) is-installed? IF 0 ?DO 4dup ( adr x y w adr x y w ) drop ( adr x y w adr x y ) i + screen-width * + \ calculate offset into framebuffer ((y + i) * screen_width + x) frame-buffer-adr + \ add to frame-buffer-adr ( adr x y w adr fb_adr ) 1 pick 3 pick i * + swap 3 pick ( adr x y w adr adr_offs fb_adr w ) rmove \ copy line ( adr x y w adr ) drop ( adr x y w ) LOOP 4drop ELSE 4drop drop THEN ; : fill-rectangle ( number x y w h -- ) is-installed? IF 0 ?DO 4dup ( number x y w number x y w ) drop ( number x y w number x y ) i + screen-width * + \ calculate offset into framebuffer ((y + i) * screen_width + x) frame-buffer-adr + \ add to frame-buffer-adr ( number x y w number adr ) 2 pick 2 pick ( number x y w number adr w number ) rfill \ draw line ( number x y w number ) drop ( number x y w ) LOOP 4drop ELSE 4drop drop THEN ; : read-rectangle ( adr x y w h -- ) is-installed? IF 0 ?DO 4dup ( adr x y w adr x y w ) drop ( adr x y w adr x y ) i + screen-width * + \ calculate offset into framebuffer ((y + i) * screen_width + x) frame-buffer-adr + \ add to frame-buffer-adr ( adr x y w adr fb_adr ) 1 pick 3 pick i * + 3 pick ( adr x y w adr fb_adr adr_offs w ) rmove \ copy line ( adr x y w adr ) drop ( adr x y w ) LOOP 4drop ELSE 4drop drop THEN ; : 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 ; : default-palette 100 0 DO i i i i color! LOOP ; 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 ; : 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" encode-string s" device_type" property s" qemu,std-vga" encode-string s" compatible" property ; : display-remove ( -- ) ; : hcall-invert-screen ( -- ) frame-buffer-adr frame-buffer-adr 3 screen-height screen-width * screen-depth * /x / 1 hv-logical-memop ; : hcall-blink-screen ( -- ) hcall-invert-screen hcall-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 ['] hcall-invert-screen to invert-screen ['] hcall-blink-screen to blink-screen true to is-installed? THEN ; : dimensions ( -- width height ) disp-width disp-height ; : set-alias s" screen" find-alias 0= IF s" screen" get-node node>path set-alias ELSE drop THEN ; ." qemu vga" cr pci-master-enable pci-mem-enable pci-io-enable add-legacy-reg read-settings init-mode default-palette setup-properties ' display-install is-install ' display-remove is-remove set-alias m8pci-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! ; : draw-rectangle ( adr x y w h -- ) is-installed? IF 0 ?DO 4dup ( adr x y w adr x y w ) drop ( adr x y w adr x y ) i + screen-width * + \ calculate offset into framebuffer ((y + i) * screen_width + x) frame-buffer-adr + \ add to frame-buffer-adr ( adr x y w adr fb_adr ) 1 pick 3 pick i * + swap 3 pick ( adr x y w adr adr_offs fb_adr w ) rmove \ copy line ( adr x y w adr ) drop ( adr x y w ) LOOP 4drop ELSE 4drop drop THEN ; : fill-rectangle ( number x y w h -- ) is-installed? IF 0 ?DO 4dup ( number x y w number x y w ) drop ( number x y w number x y ) i + screen-width * + \ calculate offset into framebuffer ((y + i) * screen_width + x) frame-buffer-adr + \ add to frame-buffer-adr ( number x y w number adr ) 2 pick 2 pick ( number x y w number adr w number ) rfill \ draw line ( number x y w number ) drop ( number x y w ) LOOP 4drop ELSE 4drop drop THEN ; : read-rectangle ( adr x y w h -- ) is-installed? IF 0 ?DO 4dup ( adr x y w adr x y w ) drop ( adr x y w adr x y ) i + screen-width * + \ calculate offset into framebuffer ((y + i) * screen_width + x) frame-buffer-adr + \ add to frame-buffer-adr ( adr x y w adr fb_adr ) 1 pick 3 pick i * + 3 pick ( adr x y w adr fb_adr adr_offs w ) rmove \ copy line ( adr x y w adr ) drop ( adr x y w ) LOOP 4drop ELSE 4drop drop THEN ; : 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 ; : default-palette 100 0 DO i i i i color! LOOP ; : 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" encode-string s" device_type" property ; : 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 ; : dimensions ( -- width height ) disp-width disp-height ; : 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 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 ; 80pci-class_0c.fss" serial bus [ " type my-space pci-class-name type s" ]" type cr my-space pci-device-generic-setup : handle-usb-ohci-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 set-ohci-alias ; : handle-sbc-subclass ( -- ) my-space pci-class@ ffff and CASE \ get PCI sub-class and interface 0310 OF handle-usb-ohci-class ENDOF \ USB OHCI controller ENDCASE ; handle-sbc-subclass XX0usb-ohci.fss" usb" device-type 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 ; STRUCT /l field td>tattr /l field td>cbptr /l field td>ntd /l field td>bfrend CONSTANT /tdlen STRUCT /l field ed>eattr /l field ed>tdqtp /l field ed>tdqhp /l field ed>ned CONSTANT /edlen STRUCT /l field hc>hcattr /l field hc>hcdone CONSTANT /hclen : get-base-address ( -- baseaddr ) s" assigned-addresses" get-node get-property ABORT" Could not get OHCI base address" decode-int drop ( addr len ) decode-64 nip nip ( n ) translate-my-address ; get-base-address CONSTANT baseaddrs baseaddrs CONSTANT HcRevision baseaddrs 4 + CONSTANT hccontrol baseaddrs 8 + CONSTANT hccomstat baseaddrs 0c + CONSTANT hcintstat baseaddrs 14 + CONSTANT hcintdsbl baseaddrs 18 + CONSTANT hchccareg baseaddrs 20 + CONSTANT hcctrhead baseaddrs 24 + CONSTANT hccurcont baseaddrs 28 + CONSTANT hcbulkhead baseaddrs 2c + CONSTANT hccurbulk baseaddrs 30 + CONSTANT hcdnehead baseaddrs 34 + CONSTANT hcintrval baseaddrs 40 + CONSTANT HcPeriodicStart baseaddrs 48 + CONSTANT hcrhdescA baseaddrs 4c + CONSTANT hcrhdescB baseaddrs 50 + CONSTANT HcRhStatus baseaddrs 54 + CONSTANT hcrhpstat baseaddrs 58 + CONSTANT hcrhpstat2 baseaddrs 5c + CONSTANT hcrhpstat3 usb-debug-flag IF 0 config-l@ ." - VENDOR: " 8 .r cr 40 config-l@ ." - PMC : " 8 .r 44 config-l@ ." PMCSR : " 8 .r cr E0 config-l@ ." - EXT1 : " 8 .r E4 config-l@ ." EXT2 : " 8 .r cr THEN 2 CONSTANT WDH 1 CONSTANT RHP-CCS \ Current Connect Status 2 CONSTANT RHP-PES \ Port Enable Status 10 CONSTANT RHP-PRS \ Port Reset Status 100 CONSTANT RHP-PPS \ Port Power Status 10000 CONSTANT RHP-CSC \ Connect Status Changed 100000 CONSTANT RHP-PRSC \ Port Reset Status Changed 0 CONSTANT OHCI-DP-SETUP 1 CONSTANT OHCI-DP-OUT 2 CONSTANT OHCI-DP-IN 3 CONSTANT OHCI-DP-INVALID 8006000100001200 CONSTANT get-ddescp 8006000200000900 CONSTANT get-cdescp 8006000400000900 CONSTANT get-idescp 8006000500000700 CONSTANT get-edescp A006000000001000 CONSTANT get-hdescp 0009010000000000 CONSTANT set-cdescp 2303010004000000 CONSTANT hpenable-set 2303040001000000 CONSTANT hp1rst-set 2303040002000000 CONSTANT hp2rst-set 2303040003000000 CONSTANT hp3rst-set 2303040004000000 CONSTANT hp4rst-set 2303080001000000 CONSTANT hp1pwr-set 2303080002000000 CONSTANT hp2pwr-set 2303080003000000 CONSTANT hp3pwr-set 2303080004000000 CONSTANT hp4pwr-set A003000000000400 CONSTANT hstatus-get A300000001000400 CONSTANT hp1sta-get A300000002000400 CONSTANT hp2sta-get A300000003000400 CONSTANT hp3sta-get A300000004000400 CONSTANT hp4sta-get 8008000000000100 CONSTANT get-config A1FE000000000100 CONSTANT GET-MAX-LUN 2 18 lshift CONSTANT DATA0-TOGGLE 3 18 lshift CONSTANT DATA1-TOGGLE 0f 1c lshift CONSTANT CC-FRESH-TD 8 CONSTANT STD-REQUEST-SETUP-SIZE 0 13 lshift CONSTANT TD-DP-SETUP 1 13 lshift CONSTANT TD-DP-OUT 2 13 lshift CONSTANT TD-DP-IN 400001 CONSTANT ed-cntatr 400002 CONSTANT ed-cntatr1 80081 CONSTANT ed-hubatr 80000 CONSTANT ed-defatr 0f0e40000 CONSTANT td-attr 00 VALUE ptr 0 VALUE instance-count 200 CONSTANT MAX-TDS 0 VALUE td-freelist-head 0 VALUE td-freelist-tail 0 VALUE num-free-tds 0 VALUE max-rh-ports 0 VALUE current-stat VARIABLE td-list-region VARIABLE td-list-region-dma 14 CONSTANT MAX-EDS 0 VALUE ed-freelist-head 0 VALUE num-free-eds VARIABLE ed-list-region VARIABLE ed-list-region-dma 0 VALUE usb-address 0 VALUE initial-hub-address 0 VALUE new-device-address 0 VALUE mps 0 VALUE DEBUG-TDS 0 VALUE case-failed \ available for general use to see IF a CASE statement 0 VALUE WHILE-failed \ available for general use to see IF a WHILE LOOP 8 CONSTANT DEFAULT-CONTROL-MPS 12 CONSTANT DEVICE-DESCRIPTOR-LEN 1 CONSTANT DEVICE-DESCRIPTOR-TYPE 1 CONSTANT DEVICE-DESCRIPTOR-TYPE-OFFSET 4 CONSTANT DEVICE-DESCRIPTOR-DEVCLASS-OFFSET 7 CONSTANT DEVICE-DESCRIPTOR-MPS-OFFSET 20 CONSTANT BULK-CONFIG-DESCRIPTOR-LEN 9 CONSTANT HUB-DEVICE-CLASS 0 CONSTANT NO-CLASS 0 VALUE temp1 0 VALUE temp2 0 VALUE temp3 0 VALUE extra-bytes 0 VALUE num-td 0 VALUE current 0 VALUE device-speed 0 VALUE setup-packet \ 8 bytes for setup packet 0 VALUE ch-buffer \ 1 byte character buffer VARIABLE dd-buffer VARIABLE dd-buffer-dma VARIABLE cd-buffer VARIABLE cd-buffer-dma 109 CONSTANT OHCI-GLOBAL-DMA-BUF-SIZE 0 VALUE hchcca 0 VALUE hchcca-dma : (init-global-dma-bufs) OHCI-GLOBAL-DMA-BUF-SIZE dma-alloc TO hchcca hchcca OHCI-GLOBAL-DMA-BUF-SIZE 0 dma-map-in TO hchcca-dma hchcca ff and IF s" Warning: hchcca not aligned!" usb-debug-print THEN hchcca 8 + TO setup-packet setup-packet 1 + TO ch-buffer s" hchcca = " hchcca usb-debug-print-val ; (init-global-dma-bufs) 84 hchcca + CONSTANT hchccadneq \ HccaDoneHead hchcca-dma hchcca - CONSTANT virt2phys-offset : virt2phys ( virt -- phys ) dup 0<> IF virt2phys-offset + THEN ; : phys2virt ( phys -- virt ) dup 0<> IF virt2phys-offset - THEN ; : Show-OHCI-Register ." -> OHCI-Register: " cr ." - HcControl : " hccontrol rl@-le 8 .r ." CmdStat : " hccomstat rl@-le 8 .r ." HcInterr. : " hcintstat rl@-le 8 .r cr ." - HcFmIntval: " hcintrval rl@-le 8 .r ." Per. Start: " HcPeriodicStart rl@-le 8 .r cr ." - PortStat-1: " hcrhpstat rl@-le 8 .r ." PortStat-2: " hcrhpstat2 rl@-le 8 .r ." PortStat-3: " hcrhpstat3 rl@-le 8 .r cr ." Descr-A : " hcrhdescA rl@-le 8 .r ." Descr-B : " hcrhdescB rl@-le 8 .r ." HcRhStat : " HcRhStatus rl@-le 8 .r cr ; : display-ed ( ED-ADDRESS -- ) TO temp1 usb-debug-flag IF s" Dump OF ED " type temp1 u. cr s" eattr : " type temp1 ed>eattr l@-le u. cr s" tdqhp : " type temp1 ed>tdqhp l@-le u. cr s" tdqtp : " type temp1 ed>tdqtp l@-le u. cr s" ned : " type temp1 ed>ned l@-le u. cr THEN ; : display-td ( TD-ADDRESS -- ) TO temp1 usb-debug-flag IF s" TD " type temp1 u. s" dump: " type cr s" td>tattr : " type temp1 td>tattr l@-le u. cr s" td>cbptr : " type temp1 td>cbptr l@-le u. cr s" td>ntd : " type temp1 td>ntd l@-le u. cr s" td>bfrend : " type temp1 td>bfrend l@-le u. cr THEN ; : display-descriptors ( ED-ADDRESS -- ) 10 1- not and ( ED-ADDRESS~ ) dup display-ed ed>tdqhp l@-le phys2virt ( ED-ADDRESS~ ) BEGIN 10 1- not and ( ED-ADDRESS~ ) dup 0<> ( ED-ADDRESS~ TRUE | FALSE ) WHILE dup display-td td>ntd l@-le phys2virt ( ED-ADDRESS~ ) REPEAT drop ; : zero-out-a-td-except-link ( td -- ) dup 0 swap td>tattr l!-le ( td ) dup 0 swap td>cbptr l!-le ( td ) dup 0 swap td>bfrend l!-le ( td ) drop ; : initialize-td-free-list ( -- ) MAX-TDS 0= IF EXIT THEN td-list-region @ 0= IF EXIT THEN td-list-region @ TO temp1 0 TO temp2 BEGIN temp1 zero-out-a-td-except-link temp1 /tdlen + dup virt2phys temp1 td>ntd l!-le TO temp1 temp2 1+ TO temp2 temp2 MAX-TDS = ( TRUE | FALSE ) UNTIL temp1 /tdlen - dup 0 swap td>ntd l!-le TO td-freelist-tail td-list-region @ TO td-freelist-head MAX-TDS TO num-free-tds ; : allocate-td-list ( n -- head tail ) dup 0= IF drop 0 0 EXIT THEN ( 0 0 ) dup num-free-tds > IF drop 0 0 EXIT THEN ( 0 0 ) dup num-free-tds = IF ( n ) drop td-freelist-head td-freelist-tail ( td-freelist-head td-freelist-tail ) 0 TO td-freelist-head ( td-freelist-head td-freelist-tail ) 0 TO td-freelist-tail ( td-freelist-head td-freelist-tail ) 0 TO num-free-tds ( td-freelist-head td-freelist-tail ) EXIT THEN dup num-free-tds swap - TO num-free-tds ( n ) td-freelist-head ( n td-list-head ) dup TO temp1 ( n td-list-head ) swap ( td-list-head n ) 0 DO ( td-list-head ) temp1 TO temp2 ( td-list-head ) temp1 td>ntd l@-le phys2virt TO temp1 ( td-list-head ) LOOP ( td-list-head ) temp2 ( td-list-head td-list-tail ) dup td>ntd 0 swap l!-le ( td-list-head td-list-tail ) temp1 TO td-freelist-head ( td-list-head td-list-tail ) ; : find-td-list-tail-and-size ( head -- tail n ) TO temp1 0 TO temp2 0 TO temp3 DEBUG-TDS IF s" BEGIN find-td-list-tail-and-size: " usb-debug-print THEN BEGIN temp1 0<> ( TRUE|FALSE ) WHILE DEBUG-TDS IF temp1 u. cr THEN temp1 TO temp3 temp1 td>ntd l@-le phys2virt TO temp1 temp2 1+ TO temp2 REPEAT temp3 temp2 ( tail n ) DEBUG-TDS IF s" END find-td-list-tail-and-size" usb-debug-print THEN ; : (free-td-list) ( head -- ) dup find-td-list-tail-and-size num-free-tds + TO num-free-tds ( head tail ) td-freelist-tail 0= IF ( head tail ) dup TO td-freelist-tail ( head tail ) THEN ( head tail ) td>ntd td-freelist-head virt2phys swap l!-le ( head ) TO td-freelist-head ; : zero-out-an-ed-except-link ( ed -- ) dup 0 swap ed>eattr l!-le ( ed ) dup 0 swap ed>tdqtp l!-le ( ed ) dup 0 swap ed>tdqhp l!-le ( ed ) drop ; : initialize-ed-free-list ( -- ) MAX-EDS 0= IF EXIT THEN ed-list-region @ 0= IF s" init-ed-list: ed-list-region is not allocated!" usb-debug-print EXIT THEN ed-list-region @ TO temp1 0 TO temp2 BEGIN temp1 zero-out-an-ed-except-link usb-debug-flag IF ." ED " temp2 . ." v: " temp1 . ." p: " temp1 virt2phys . cr THEN temp1 /edlen + dup virt2phys temp1 ed>ned l!-le TO temp1 temp2 1+ TO temp2 temp2 MAX-EDS = UNTIL temp1 /edlen - ed>ned 0 swap l!-le ed-list-region @ TO ed-freelist-head MAX-EDS TO num-free-eds ; : allocate-ed ( -- ed-ptr ) num-free-eds 0= IF 0 EXIT THEN ed-freelist-head ( ed-freelist-head ) ed-freelist-head ed>ned ( ed-freelist-head ned ) l@-le phys2virt TO ed-freelist-head ( ed-freelist-head ) num-free-eds 1- TO num-free-eds ( ed-freelist-head ) dup ed>ned 0 swap l!-le \ Terminate the Link. ( ed-freelist-head ) ; : free-ed ( ed-ptr -- ) dup zero-out-an-ed-except-link ( ed-ptr ) dup ed>ned ed-freelist-head virt2phys swap l!-le ( ed-ptr ) TO ed-freelist-head num-free-eds 1+ TO num-free-eds ; : (allocate-mem) ( -- ) /tdlen MAX-TDS * 10 + dup dma-alloc ( td-region-size td-list-region-ptr ) dup td-list-region ! dup f and IF s" Warning: td-list-region not aligned!" usb-debug-print THEN swap 0 dma-map-in td-list-region-dma ! initialize-td-free-list /edlen MAX-EDS * 10 + dup dma-alloc ( ed-region-size ed-list-region-ptr ) dup ed-list-region ! dup f and IF s" Warning: ed-list-region not aligned!" usb-debug-print THEN swap 0 dma-map-in ed-list-region-dma ! initialize-ed-free-list DEVICE-DESCRIPTOR-LEN chars dup dma-alloc dup dd-buffer ! ( dd-len dd-buf ) swap 0 dma-map-in dd-buffer-dma ! BULK-CONFIG-DESCRIPTOR-LEN chars dup dma-alloc dup cd-buffer ! ( cd-len cd-buf ) swap 0 dma-map-in cd-buffer-dma ! s" td-list-region = " td-list-region @ usb-debug-print-val s" ed-list-region = " ed-list-region @ usb-debug-print-val s" dd-buffer = " dd-buffer @ usb-debug-print-val s" cd-buffer-dma = " cd-buffer-dma @ usb-debug-print-val ; : (de-allocate-mem) ( -- ) td-list-region @ ?dup IF /tdlen MAX-TDS * 10 + ( td-list-region td-region-size ) 2dup td-list-region-dma @ swap dma-map-out dma-free 0 td-list-region ! 0 td-list-region-dma ! THEN ed-list-region @ ?dup IF /edlen MAX-EDS * 10 + 2dup ed-list-region-dma @ swap dma-map-out dma-free 0 ed-list-region ! 0 ed-list-region-dma ! THEN dd-buffer @ ?dup IF DEVICE-DESCRIPTOR-LEN 2dup dd-buffer-dma @ swap dma-map-out dma-free 0 dd-buffer ! 0 dd-buffer-dma ! THEN cd-buffer @ ?dup IF BULK-CONFIG-DESCRIPTOR-LEN 2dup cd-buffer-dma @ swap dma-map-out dma-free 0 cd-buffer ! 0 cd-buffer-dma ! THEN ; : hc-quiesce ( -- ) 00C3 hccontrol rl!-le \ Suspend USB host controller hchcca hchcca-dma OHCI-GLOBAL-DMA-BUF-SIZE dma-map-out hchcca OHCI-GLOBAL-DMA-BUF-SIZE dma-free ; ' hc-quiesce add-quiesce-xt \ Assert that HC will be supsended : open ( -- TRUE|FALSE ) instance-count dup 0= IF s" OHCI First open" usb-debug-print (allocate-mem) THEN 1 + TO instance-count s" OHCI Open instance count now: " instance-count usb-debug-print-val TRUE ; : close ( -- ) instance-count dup 1 = IF s" OHCI Last close" usb-debug-print (de-allocate-mem) THEN 1 - TO instance-count s" OHCI Close instance count now: " instance-count usb-debug-print-val ; : HC-enable-control-list-processing ( -- ) hccomstat dup rl@-le 02 or swap rl!-le hccontrol dup rl@-le 10 or swap rl!-le ; : HC-enable-bulk-list-processing ( -- ) hccomstat dup rl@-le 04 or swap rl!-le hccontrol dup rl@-le 20 or swap rl!-le ; : HC-enable-interrupt-list-processing ( -- ) hccontrol dup rl@-le 04 or swap rl!-le ; : (HC-ACK-WDH) ( -- ) WDH hcintstat rl!-le ; : (HC-CHECK-WDH) ( -- updated? ) hcintstat rl@-le WDH and 0<> ; : disable-control-list-processing ( -- ) hccontrol dup rl@-le ffffffef and swap rl!-le hccomstat dup rl@-le fffffffd and swap rl!-le ; : disable-bulk-list-processing ( -- ) hccontrol dup rl@-le ffffffdf and swap rl!-le hccomstat dup rl@-le fffffffb and swap rl!-le ; : disable-interrupt-list-processing ( -- ) hccontrol dup rl@-le fffffffb and swap rl!-le ; 0 VALUE current-toggle : fill-TD-list ( start-toggle addr dlen dp MPS TD-List-Head -- ) TO temp1 ( start-toggle addr dlen dp MPS ) TO temp2 ( start-toggle addr dlen dp ) CASE ( start-toggle addr dlen ) OHCI-DP-SETUP OF TD-DP-SETUP TO temp3 ENDOF ( start-toggle addr dlen ) OHCI-DP-IN OF TD-DP-IN TO temp3 ENDOF ( start-toggle addr dlen ) OHCI-DP-OUT OF TD-DP-OUT TO temp3 ENDOF ( start-toggle addr dlen ) dup OF -1 TO temp3 ( start-toggle addr dlen ) s" fill-TD-list: Invalid DP specified" usb-debug-print ENDOF ENDCASE temp3 -1 = IF EXIT THEN ( start-toggle addr dlen ) rot ( addr dlen start-toggle ) TO current-toggle swap ( dlen addr ) BEGIN over temp2 >= ( dlen addr TRUE|FALSE ) WHILE ( dlen addr ) dup virt2phys temp1 td>cbptr l!-le ( dlen addr ) current-toggle 18 lshift ( dlen addr current-toggle~ ) DATA0-TOGGLE ( dlen addr current-toggle~ toggle ) CC-FRESH-TD temp3 or or or ( dlen addr or-result ) temp1 td>tattr l!-le ( dlen addr~ ) dup temp2 1- + virt2phys temp1 td>bfrend l!-le ( dlen addr~ ) temp2 + ( dlen next-addr ) swap temp2 - swap temp1 td>ntd l@-le phys2virt TO temp1 ( dlen next-addr ) current-toggle ( dlen next-addr current-toggle ) CASE 0 OF 1 TO current-toggle ENDOF 1 OF 0 TO current-toggle ENDOF ENDCASE REPEAT ( dlen addr ) over 0<> IF dup virt2phys temp1 td>cbptr l!-le ( dlen addr ) current-toggle 18 lshift ( dlen addr curent-toggle~ ) DATA0-TOGGLE ( dlen addr curent-toggle~ toggle ) CC-FRESH-TD temp3 or or or ( dlen addr or-result ) temp1 td>tattr l!-le ( dlen addr ) + 1- virt2phys temp1 td>bfrend l!-le ELSE 2drop THEN ; : (td-list-status) ( PointerToTDlist -- failingTD CCode TRUE | 0 ) BEGIN ( PointerToTDlist ) dup 0<> ( PointerToTDlist TRUE|FALSE ) IF ( PointerToTDlist ) dup td>tattr l@-le f0000000 and 1c rshift dup 0= TRUE swap ELSE drop FALSE dup ( FALSE ) THEN WHILE drop drop td>ntd l@-le phys2virt REPEAT ; : (wait-for-done-q) ( timeout -- TD-list TRUE | FALSE ) BEGIN ( timeout ) dup 0<> ( timeout TRUE|FALSE ) (HC-CHECK-WDH) NOT ( timeout TRUE|FALSE TRUE|FALSE ) AND \ not timed out AND WDH-bit not set WHILE 1 ms \ wait 1- ( timeout ) dup ff and 0= IF show-proceed THEN REPEAT ( timeout ) drop hchccadneq l@-le phys2virt \ read last HcDoneHead (RAM) (HC-CHECK-WDH) \ HcDoneHead was updated ? IF (HC-ACK-WDH) \ clear register bit: WDH TRUE ( td-list TRUE ) ELSE FALSE THEN ; : debug-td ( -- ) s" Num Free TDs = " num-free-tds usb-debug-print-val ; : HC-reset ( -- ) hcrhdescA rl@-le ff and ( total-rh-ports ) to max-rh-ports hcrhpstat TO current-stat \ start with first port status reg 0 \ port status default max-rh-ports 0 \ checking all ports ?DO current-stat rl@-le or \ OR-ing all stats 200 current-stat rl!-le \ Clear Port Power (CPP) current-stat 4 + TO current-stat \ check next RH-Port LOOP 100 and 0<> \ any of the ports had power ? IF d# 750 wait-proceed \ wait for power discharge THEN hccomstat dup rl@-le 01 or swap rl!-le \ issue HC reset BEGIN hccomstat rl@-le 01 and 0<> \ wait for reset end WHILE REPEAT 23f02edf hcintrval rl!-le \ frame-interval register hchcca-dma hchccareg rl!-le \ HC communication area 0000 hcctrhead rl!-le \ control transfer head 0000 hcbulkhead rl!-le \ bulk transfer head 0ffff hcintdsbl rl!-le \ interrupt disable reg. 83 hccontrol rl!-le \ set USBOPERATIONAL 23f02edf hcintrval rl!-le \ frame-interval register hchcca-dma hchccareg rl!-le \ HC communication area d# 50 ms hcrhpstat TO current-stat \ start with first port status reg max-rh-ports 0 ?DO 102 current-stat rl!-le \ power on and enable hcrhdescA rl@-le 18 rshift 2 * ms \ startup delay 30 ms (2 * POTPGT) current-stat 4 + TO current-stat \ check next RH-Port LOOP d# 500 wait-proceed \ STEC device needs 300 ms ; : error-recovery ( -- ) initialize-td-free-list initialize-ed-free-list HC-reset ; : store-initial-usb-hub-address ( -- ) usb-address TO initial-hub-address ; : reset-to-initial-usb-hub-address ( -- ) initial-hub-address TO usb-address ; : allocate-usb-address ( -- usb-address ) usb-address 7f <> ( TRUE|FALSE ) IF usb-address 1+ TO usb-address \ RISK: Check to see IF it overflows 127 usb-address ( usb-address ) THEN ( usb-address ) ; s" usb-support.fs" INCLUDED : control-std-set-address ( speedbit -- usb-address TRUE | FALSE ) >r ( R: speedbit ) 0005000000000000 setup-packet ! allocate-usb-address dup setup-packet 2 + c! ( usb-addr R: speedbit ) s" USB set-address: " 2 pick usb-debug-print-val ( usb-addr R: speedbit ) 0 0 0 setup-packet 8 r> controlxfer ( usb-addr TRUE | FALSE ) IF ( TRUE | FALSE ) TRUE ( TRUE ) ELSE drop FALSE \ PENDING: Return the allocated address back. ( FALSE ) THEN ( TRUE | FALSE ) ; : control-std-get-device-descriptor 8006000100000000 setup-packet ! 2 pick setup-packet 6 + w!-le setup-packet -rot ( data-buffer data-len setup-packet MPS fa ) >r >r >r >r >r 0 r> r> r> r> r> controlxfer ( TRUE | FALSE ) ; : control-std-get-configuration-descriptor TO temp1 ( data-buffer data-len MPS ) TO temp2 ( data-buffer data-len ) TO temp3 ( data-buffer ) 8006000200000000 setup-packet ! temp3 setup-packet 6 + w!-le 0 swap temp3 setup-packet temp2 temp1 controlxfer ; : control-std-get-maxlun ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE ) GET-MAX-LUN setup-packet ! ( MPS fun-addr dir data-buff data-len ) setup-packet 5 pick 5 pick controlxfer ( MPS fun-addr TRUE | FALSE ) nip nip ( TRUE | FALSE ) ; : control-bulk-reset ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE ) 21FF000000000000 setup-packet ! ( MPS fun-addr dir data-buff data-len ) setup-packet 5 pick 5 pick controlxfer ( MPS fun-addr TRUE | FALSE ) nip nip ( TRUE | FALSE ) ; : control-std-get-string-descriptor TO temp1 ( StringIndex data-buffer data-len MPS ) TO temp2 ( StringIndex data-buffer data-len ) TO temp3 ( StringIndex ) 8006000300000000 setup-packet ! temp3 setup-packet 6 + w!-le 409 setup-packet 4 + w!-le \ US English Language code. swap ( data buffer StringIndex ) setup-packet 2 + c! ( data-buffer ) 0 swap temp3 setup-packet temp2 temp1 controlxfer ( TRUE | FALSE ) ; : control-std-set-configuration ( configvalue FuncAddr -- TRUE|FALSE ) TO temp1 ( configvalue ) TO temp2 0009000000000000 setup-packet ! \ RISK: Endian and 64-bit assumptions temp2 setup-packet 2 + w!-le 0 0 0 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer ; 0 VALUE port-number s" usb-enumerate.fs" INCLUDED : rhport-enumerate ( port-num -- ) TO port-number device-speed control-std-set-address ( usb-addr TRUE | FALSE ) IF device-speed or ( usb-addr+speedbit ) TO new-device-address dd-buffer @ 8 erase dd-buffer @ DEFAULT-CONTROL-MPS DEFAULT-CONTROL-MPS ( buffer mps mps ) new-device-address control-std-get-device-descriptor ( TRUE | FALSE ) IF ELSE s" USB: Read Dev Descriptor failed" usb-debug-print EXIT THEN dd-buffer @ DEVICE-DESCRIPTOR-TYPE-OFFSET + c@ ( Descriptor-type ) DEVICE-DESCRIPTOR-TYPE <> IF s" USB: Error Reading Device Descriptor" usb-debug-print s" Read descriptor is not of the right type" usb-debug-print s" Aborting enumeration" usb-debug-print EXIT THEN dd-buffer @ DEVICE-DESCRIPTOR-MPS-OFFSET + c@ TO mps create-usb-device-tree ELSE s" Set address failed on port " port-number usb-debug-print-val s" Aborting Enumeration." usb-debug-print EXIT THEN ; : rhport-initialize ( -- ) hcrhpstat TO current-stat \ start with first port status reg max-rh-ports 1+ 1 ?DO usb-debug-flag IF ." Initializing RH port " i . cr THEN current-stat rl@-le RHP-CCS and 0<> ( TRUE|FALSE ) IF s" Device connected to this port!" usb-debug-print RHP-PRS current-stat rl!-le \ issue a port reset BEGIN current-stat rl@-le RHP-PRS AND \ wait for reset end WHILE REPEAT hcrhdescA rl@-le 18 rshift 2 * ms \ startup delay 30 ms (POTPGT) d# 100 ms current-stat rl@-le 200 and 4 lshift to device-speed \ store speed bit RHP-CSC RHP-PRSC or current-stat rl!-le I ['] rhport-enumerate CATCH IF \ Scan port s" USB scan failed on root hub port: " rot usb-debug-print-val reset-to-initial-usb-hub-address THEN ELSE s" No device detected at this port." usb-debug-print current-stat rl@-le 80000 and 0<> \ is over-current detected ? IF s" Warning: Overcurrent indicated" usb-debug-print THEN THEN current-stat 4 + TO current-stat \ check next RH-Port LOOP ; : enumerate ( -- ) HC-reset store-initial-usb-hub-address rhport-initialize \ Probe all available RH ports reset-to-initial-usb-hub-address ; =<0usb-support.fs0 value NEXT-TD 0 VALUE num-tds 0 VALUE td-retire-count 0 VALUE saved-tail 0 VALUE poll-timer VARIABLE controlxfer-cmd : (ed-prepare) ( dir addr dlen setup-packet MPS ep-fun -- FALSE | dir addr dlen ed-ptr setup-ptr ) allocate-ed ?dup 0= IF s" allocate-ed failed!" usb-debug-print 4drop 2drop FALSE EXIT ( FALSE ) THEN ( dir addr dlen setup-packet MPS ep-fun ed-ptr ) TO temp1 ( dir addr dlen setup-packet MPS ep-fun ) temp1 zero-out-an-ed-except-link ( dir addr dlen setup-packet MPS ep-fun ) temp1 ed>eattr l@-le or temp1 ed>eattr l!-le ( dir addr dlen setup-ptr MPS ) dup TO temp2 10 lshift temp1 ed>eattr l@-le or temp1 ed>eattr l!-le temp1 swap TRUE ( dir addr dlen ed-ptr setup-ptr TRUE ) ; : (td-prepare) ( dir addr dlen ed-ptr setup-ptr -- dir FALSE | dir addr dlen ed-ptr setup-ptr td-head td-tail ) 2 pick ( dir addr dlen ed-ptr setup-ptr dlen ) temp2 ( dir addr dlen ed-ptr setup-ptr dlen MPS ) /mod ( dir addr dlen ed-ptr setup-ptr rem quo ) swap 0<> IF ( dir addr dlen ed-ptr setup-ptr quo ) 1+ THEN 2+ dup TO num-tds ( dir addr dlen ed-ptr setup-ptr quo+2 ) allocate-td-list dup 0= IF ( dir addr dlen ed-ptr setup-ptr quo+2 ) 2drop ( dir addr dlen ed-ptr setup-ptr ) drop ( dir addr dlen ed-ptr ) free-ed ( dir addr dlen ) 2drop ( dir ) FALSE ( dir FALSE ) EXIT THEN TRUE ; : (td-ready) ( ed-ptr setup-ptr td-head td-tail -- ed-ptr setup-ptr ) swap virt2phys swap virt2phys \ Convert td-head and td-tail to physical 3 pick ( ed-ptr s-ptr td-head' td-tail' ed-ptr ) tuck ( ed-ptr s-ptr td-head' ed-ptr td-tail' ed-ptr ) ed>tdqtp l!-le ( ed-ptr s-ptr td-head' ed-ptr ) ed>tdqhp l!-le ( ed-ptr s-ptr ) over ed>ned 0 swap l!-le ( ed-ptr s-ptr ) ; : (td-setup-status) ( dir addr dlen ed-ptr setup-ptr -- dir addr dlen ed-ptr ) over ed>tdqhp l@-le phys2virt ( dir addr dlen ed-ptr setup-ptr td-head ) dup zero-out-a-td-except-link ( dir addr dlen ed-ptr setup-ptr td-head ) dup td>tattr DATA0-TOGGLE CC-FRESH-TD or swap l!-le 2dup swap virt2phys swap td>cbptr l!-le 2dup td>bfrend swap STD-REQUEST-SETUP-SIZE 1- + virt2phys swap l!-le 2drop ( dir addr dlen ed-ptr ) ; : (td-tailpointer) ( dir addr dlen ed-ptr -- dir addr dlen ed-ptr ) dup ed>tdqtp l@-le phys2virt ( dir addr dlen ed-ptr td-tail ) dup zero-out-a-td-except-link ( dir addr dlen ed-ptr td-tail ) dup td>tattr dup l@-le DATA1-TOGGLE CC-FRESH-TD or or swap l!-le 4 pick 0= ( dir addr dlen ed-ptr td-tail flag ) 3 pick 0<> ( dir addr dlen ed-ptr td-tail flag flag ) and IF ( dir addr dlen ed-ptr td-tail ) dup td>tattr dup l@-le TD-DP-OUT or swap l!-le ELSE dup td>tattr dup l@-le TD-DP-IN or swap l!-le THEN drop ( dir addr dlen ed-ptr ) ; : (td-data) ( dir addr dlen ed-ptr -- ed-ptr ) -rot ( dir ed-ptr addr dlen ) dup 0<> IF ( dir ed-ptr addr dlen ) >r >r >r TO temp1 r> r> r> temp1 ( ed-ptr addr dlen dir ) 3 pick ( ed-ptr addr dlen dir ed-ptr ) ed>tdqhp l@-le phys2virt ( ed-ptr addr dlen dir tdqhp ) td>ntd l@-le phys2virt ( ed-ptr addr dlen dir td-datahead ) 4 pick ( ed-ptr addr dlen dir td-datahead ed-ptr ) td>tattr l@-le 10 rshift ( ed-ptr addr dlen dir td-head-data MPS ) swap ( ed-ptr addr dlen dir MPS td-head-data ) >r >r >r >r >r 1 r> r> r> r> r> >r >r 0= IF ( ed-ptr 1 addr dlen dir ) OHCI-DP-IN ( ed-ptr 1 addr dlen dir OHCI-DP-IN ) ELSE OHCI-DP-OUT ( ed-ptr 1 addr dlen dir OHCI-DP-OUT ) THEN r> r> ( ed-ptr 1 addr dlen dir OHCI-DP- MPS td-head-data ) fill-TD-list ELSE 2drop nip ( ed-ptr ) THEN ; 10 CONSTANT max-retire-td : (transfer-wait-for-doneq) ( ed-ptr -- TRUE | FALSE ) dup virt2phys ( ed-ptr ed-ptr-dma ) hcctrhead rl!-le ( ed-ptr ) HC-enable-control-list-processing ( ed-ptr ) 0 TO td-retire-count ( ed-ptr ) 0 TO poll-timer ( ed-ptr ) BEGIN td-retire-count num-tds <> ( ed-ptr TRUE | FALSE ) poll-timer max-retire-td < and ( ed-ptr TRUE | FALSE ) WHILE (HC-CHECK-WDH) ( ed-ptr updated? ) IF hchccadneq l@-le phys2virt find-td-list-tail-and-size nip ( ed-ptr n ) td-retire-count + TO td-retire-count ( ed-ptr ) hchccadneq l@-le phys2virt dup ( ed-ptr done-td done-td ) (td-list-status) ( ed-ptr done-td failed-td CCcode ) IF dup >r s" (transfer-wait-for-doneq: USB device communication error." usb-debug-print ( ed-ptr done-td failed-td CCcode R: CCcode ) dup 4 = swap dup 5 = rot or ( ed-ptr done-td failed-td CCcode R: CCcode ) IF max-retire-td TO poll-timer ( ed-ptr done-td failed-td CCcode R: CCcode ) THEN usb-debug-flag IF s" CC code ->" type . cr s" Failing TD contents:" type cr display-td ELSE 2drop THEN ( ed-ptr done-td R: CCcode ) controlxfer-cmd @ GET-MAX-LUN = r> 4 = and IF s" (transfer-wait-for-doneq): GET-MAX-LUN ControlXfer STALLed" usb-debug-print ELSE drop 5030 error" (USB) Device communication error." ABORT THEN THEN ( ed-ptr done-td ) (free-td-list) ( ed-ptr ) 0 hchccadneq l!-le ( ed-ptr ) (HC-ACK-WDH) \ TDs were written to done queue. ACK the HC. THEN poll-timer 1+ TO poll-timer 4 ms \ longer 1 ms REPEAT ( ed-ptr ) disable-control-list-processing ( ed-ptr ) td-retire-count num-tds <> ( ed-ptr ) IF dup display-descriptors ( ed-ptr ) s" maximum of retire " usb-debug-print THEN free-ed td-retire-count num-tds <> IF FALSE ( FALSE ) ELSE TRUE ( TRUE ) THEN ; : controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE | FALSE ) 2 pick @ controlxfer-cmd ! (ed-prepare) ( FALSE | dir addr dlen ed-ptr setup-ptr ) invert IF FALSE EXIT THEN (td-prepare) ( pt ed-type toggle buffer length mps head ) invert IF FALSE EXIT THEN (td-ready) ( dir addr dlen ed-ptr setup-ptr ) (td-setup-status) ( dir addr dlen ed-ptr ) (td-tailpointer) ( dir addr dlen ed-ptr ) (td-data) ( ed-ptr ) dup ed>tdqtp l@-le phys2virt TO saved-tail ( ed-ptr ) dup ed>tdqtp 0 swap l!-le ( ed-ptr ) (transfer-wait-for-doneq) ( TRUE | FALSE ) ; 0201000000000000 CONSTANT CLEARHALTFEATURE 0 VALUE endpt-num 0 VALUE usb-addr-contr-req : control-std-clear-feature ( endpoint-nr usb-addr -- TRUE|FALSE ) TO usb-addr-contr-req \ usb address TO endpt-num \ endpoint number CLEARHALTFEATURE setup-packet ! endpt-num setup-packet 4 + c! \ endpoint number 0 0 0 setup-packet DEFAULT-CONTROL-MPS usb-addr-contr-req controlxfer ; 21FF000000000000 CONSTANT BULK-RESET : control-std-bulk-reset ( usb-addr -- TRUE|FALSE ) TO usb-addr-contr-req BULK-RESET setup-packet ! 0 0 0 setup-packet DEFAULT-CONTROL-MPS usb-addr-contr-req controlxfer ; : bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- ) >r ( bulk-out-endp bulk-in-endp R: usb-addr ) r@ control-std-bulk-reset IF s" bulk reset OK" ELSE s" bulk reset failed" THEN usb-debug-print 80 or r@ control-std-clear-feature IF s" control-std-clear IN endpoint OK" ELSE s" control-std-clear-IN endpoint failed" THEN usb-debug-print r@ control-std-clear-feature IF s" control-std-clear OUT endpoint OK" ELSE s" control-std-clear-OUT endpoint failed" THEN usb-debug-print r> drop ; 0 VALUE saved-rw-ed 0 VALUE num-rw-tds 0 VALUE num-rw-retired-tds 0 VALUE saved-rw-start-toggle 0 VALUE saved-list-type : (ed-prepare-rw) ( pt ed-type toggle buffer length mps address ed-ptr -- FALSE | pt ed-type toggle buffer length mps TRUE ) allocate-ed dup 0= IF drop 2drop 2drop 2drop drop saved-rw-start-toggle FALSE EXIT ( toggle FALSE ) THEN TO saved-rw-ed ( pt ed-type toggle buffer length mps address ) saved-rw-ed zero-out-an-ed-except-link saved-rw-ed ed>eattr l!-le ( pt ed-type toggle buffer length mps ) dup 10 lshift saved-rw-ed ed>eattr l@-le or saved-rw-ed ed>eattr l!-le TRUE ( pt ed-type toggle buffer length mps TRUE ) ; : (td-prepare-rw) ( pt ed-type toggle buffer length mps -- FALSE | pt ed-type toggle buffer length mps head TRUE ) 2dup ( pt ed-type toggle buffer length mps length mps ) /mod ( pt ed-type toggle buffer length mps num-tds rem ) swap 0<> IF ( pt ed-type toggle buffer length mps num-tds ) 1+ ( pt ed-type toggle buffer length mps num-tds+1 ) THEN dup TO num-rw-tds ( pt ed-type toggle buffer length mps num-tds ) allocate-td-list ( pt ed-type toggle buffer length mps head tail ) dup 0= IF 2drop 2drop 2drop 2drop saved-rw-ed free-ed ." rw-endpoint: TD list allocation failed" cr saved-rw-start-toggle FALSE ( FALSE ) EXIT THEN drop TRUE ( pt ed-type toggle buffer length mps head TRUE ) ; : (td-data-rw) 6 pick ( pt ed-type toggle buffer length mps head pt ) FALSE TO case-failed CASE 0 OF OHCI-DP-IN ENDOF 1 OF OHCI-DP-OUT ENDOF 2 OF OHCI-DP-SETUP ENDOF dup OF TRUE TO case-failed ." rw-endpoint: Invalid Packet Type!" cr ENDOF ENDCASE ( pt ed-type toggle buffer length mps head dp ) case-failed IF saved-rw-ed free-ed ( pt ed-type toggle buffer length mps head dp ) drop (free-td-list) ( pt ed-type toggle buffer length mps head ) 2drop 2drop 2drop saved-rw-start-toggle FALSE ( FALSE ) EXIT ( FALSE ) THEN -rot ( pt ed-type toggle buffer length dp mps head ) dup >r ( pt ed-type toggle buffer length dp mps head ) fill-TD-list r> TRUE ( pt et head TRUE ) ; : (ed-ready-rw) ( pt et -- - | toggle FALSE ) nip ( et ) FALSE TO case-failed CASE 0 OF \ Control List. Queue the ED to control list 0 TO saved-list-type saved-rw-ed virt2phys hcctrhead rl!-le HC-enable-control-list-processing ENDOF 1 OF \ Bulk List. Queue the ED to bulk list 1 TO saved-list-type saved-rw-ed virt2phys hcbulkhead rl!-le HC-enable-bulk-list-processing ENDOF 2 OF \ Interrupt List. 2 TO saved-list-type saved-rw-ed virt2phys hchccareg rl@-le phys2virt rl!-le HC-enable-interrupt-list-processing ENDOF dup OF saved-rw-ed ed>tdqhp l@-le phys2virt (free-td-list) saved-rw-ed free-ed TRUE TO case-failed ENDOF ENDCASE case-failed IF saved-rw-start-toggle FALSE ( toggle FALSE ) EXIT THEN TRUE ( TRUE ) ; : (wait-td-retire) ( -- ) 0 TO num-rw-retired-tds FALSE TO while-failed BEGIN num-rw-retired-tds num-rw-tds < ( TRUE | FALSE ) while-failed FALSE = and ( TRUE | FALSE ) WHILE d# 5000 (wait-for-done-q) ( TD-list TRUE|FALSE ) IF dup find-td-list-tail-and-size nip ( td-list size ) num-rw-retired-tds + TO num-rw-retired-tds ( td-list ) dup (td-list-status) ( td-list failed-TD CC ) IF dup 4 = IF saved-list-type CASE 0 OF 0 0 control-std-clear-feature s" clear feature " usb-debug-print ENDOF 1 OF \ clean bulk stalled s" clear bulk when stalled " usb-debug-print disable-bulk-list-processing \ disable procesing saved-rw-ed ed>eattr l@-le dup \ extract 780 and 7 rshift 80 or \ endpoint and swap 7f and \ usb addr control-std-clear-feature ENDOF 2 OF 0 saved-rw-ed ed>eattr l@-le control-std-clear-feature ENDOF dup OF s" unknown status " usb-debug-print ENDOF ENDCASE ELSE ( td-list failed-TD CC ) ." TD failed " 5b emit .s 5d emit cr 5040 error" (USB) device transaction error (wait-td-retire)." ABORT THEN 2drop drop TRUE TO while-failed \ transaction failed NEXT-TD 0<> \ clean the TD if we IF NEXT-TD (free-td-list) \ had a stalled THEN THEN (free-td-list) ELSE drop \ drop td-list pointer scan-time? IF 2e emit THEN \ show proceeding dots TRUE TO while-failed s" time out wait for done" usb-debug-print 20 ms \ wait for bad device THEN REPEAT ; : (process-retired-td) ( -- TRUE | FALSE ) saved-list-type CASE 0 OF disable-control-list-processing ENDOF 1 OF disable-bulk-list-processing ENDOF 2 OF disable-interrupt-list-processing ENDOF ENDCASE saved-rw-ed ed>tdqhp l@-le 2 and 0<> IF 1 s" retired 1" usb-debug-print ELSE 0 s" retired 0" usb-debug-print THEN WHILE-failed IF FALSE ( FALSE ) ELSE TRUE ( TRUE ) THEN saved-rw-ed free-ed ; : (do-rw-endpoint) 4 pick ( pt ed-type toggle buffer length mps address toggle ) TO saved-rw-start-toggle ( pt ed-type toggle buffer length mps address ) (ed-prepare-rw) ( FALSE | pt ed-type toggle buffer length mps TRUE ) invert IF FALSE EXIT THEN (td-prepare-rw) ( FALSE | pt ed-type toggle buffer length mps head TRUE ) invert IF FALSE EXIT THEN (td-data-rw) ( FALSE | pt et head TRUE ) invert IF FALSE EXIT THEN virt2phys saved-rw-ed ed>tdqhp l!-le ( pt et ) saved-rw-ed ed>tdqhp l@-le phys2virt td>ntd l@-le phys2virt TO NEXT-TD \ save for a stalled (ed-ready-rw) invert IF FALSE EXIT THEN (wait-td-retire) (process-retired-td) ( TRUE | FALSE ) ; 0 VALUE transfer-len 0 VALUE mps-current 0 VALUE addr-current 0 VALUE usb-addr 0 VALUE toggle-current 0 VALUE type-current 0 VALUE pt-current 0 VALUE read-status 0 VALUE counter 0 VALUE residue : rw-endpoint 2 pick TO transfer-len ( pt ed-type toggle buffer length mps address ) 1 pick TO mps-current ( pt ed-type toggle buffer length mps address ) TRUE TO read-status ( pt ed-type toggle buffer length mps address ) transfer-len mps-current num-free-tds * <= IF (do-rw-endpoint) ( toggle TRUE | toggle FALSE ) TO read-status ( toggle ) TO toggle-current ELSE TO usb-addr ( pt ed-type toggle buffer length mps ) 2drop ( pt ed-type toggle buffer ) TO addr-current ( pt ed-type toggle ) TO toggle-current ( pt ed-type ) TO type-current ( pt ) TO pt-current transfer-len mps-current num-free-tds * /mod ( residue count ) TO counter ( residue ) TO residue mps-current num-free-tds * TO transfer-len BEGIN counter 0 > ( TRUE | FALSE ) read-status TRUE = and ( TRUE | FALSE ) WHILE pt-current type-current toggle-current ( pt ed-type toggle ) addr-current transfer-len ( pt ed-type toggle buffer length ) mps-current ( pt ed-type toggle buffer length mps ) usb-addr (do-rw-endpoint) ( toggle TRUE | toggle FALSE ) TO read-status ( toggle ) TO toggle-current addr-current transfer-len + TO addr-current counter 1- TO counter REPEAT residue 0<> ( TRUE |FALSE ) read-status TRUE = and IF residue TO transfer-len pt-current type-current toggle-current ( pt ed-type toggle ) addr-current transfer-len ( pt ed-type toggle buffer length ) mps-current ( pt ed-type toggle buffer length mps ) usb-addr (do-rw-endpoint) ( toggle TRUE | toggle FALSE ) TO read-status TO toggle-current THEN THEN read-status invert IF THEN toggle-current ( toggle ) read-status ( TRUE | FALSE ) ; 0usb-hub.fss" hub" device-name s" usb" device-type 1 encode-int s" #address-cells" property 0 encode-int s" #size-cells" property : encode-unit ( port-addr -- unit-str unit-len ) 1 hex-encode-unit ; : decode-unit ( addr len -- port-addr ) 1 hex-decode-unit ; 0 VALUE new-device-address 0 VALUE port-number 0 VALUE MPS-DCP 0 VALUE mps 0 VALUE my-usb-address 00 value device-speed : mps-property-set ( -- ) s" HUB Compiling mps-property-set " usb-debug-print s" USB-ADDRESS" get-my-property ( TRUE | prop-addr prop-len FALSE ) IF s" notpossible" usb-debug-print ELSE decode-int nip nip to my-usb-address THEN s" MPS-DCP" get-my-property ( TRUE | prop-addr prop-len FALSE ) IF s" MPS-DCP property not found Assuming 8 as MAX PACKET SIZE" ( str len ) usb-debug-print s" for the default control pipe" usb-debug-print 8 to MPS-DCP ELSE s" MPS-DCP property found!!" usb-debug-print ( prop-addr prop-len FALSE ) decode-int nip nip to MPS-DCP THEN ; 2303080000000000 CONSTANT hppwr-set 2301080000000000 CONSTANT hppwr-clear 2303040000000000 CONSTANT hprst-set A300000000000400 CONSTANT hpsta-get 2303010000000000 CONSTANT hpena-set A006002900000000 CONSTANT hubds-get 8 CONSTANT DEFAULT-CONTROL-MPS 12 CONSTANT DEVICE-DESCRIPTOR-LEN 9 CONSTANT CONFIG-DESCRIPTOR-LEN 20 CONSTANT BULK-CONFIG-DESCRIPTOR-LEN 1 CONSTANT DEVICE-DESCRIPTOR-TYPE 1 CONSTANT DEVICE-DESCRIPTOR-TYPE-OFFSET 4 CONSTANT DEVICE-DESCRIPTOR-DEVCLASS-OFFSET 7 CONSTANT DEVICE-DESCRIPTOR-MPS-OFFSET 9 CONSTANT HUB-DEVICE-CLASS 0 CONSTANT NO-CLASS 00 VALUE temp1 00 VALUE temp2 00 VALUE temp3 00 VALUE po2pg \ Power On to Power Good : dma-alloc s" dma-alloc" $call-parent ; : dma-map-in s" dma-map-in" $call-parent ; : dma-map-out s" dma-map-out" $call-parent ; : dma-free s" dma-free" $call-parent ; 0 INSTANCE VALUE setup-packet \ 8 bytes for setup packet 0 INSTANCE VALUE ch-buffer \ 1 byte character buffer INSTANCE VARIABLE dd-buffer INSTANCE VARIABLE cd-buffer STRUCT 8 FIELD >setup-packet \ 8 bytes for setup packet DEVICE-DESCRIPTOR-LEN FIELD >dd-buffer BULK-CONFIG-DESCRIPTOR-LEN FIELD >cd-buffer 8 chars FIELD >status-buffer 9 chars FIELD >hd-buffer 1 chars FIELD >ch-buffer \ character buffer CONSTANT /hub-buf 0 INSTANCE VALUE hub-buf 0 INSTANCE VALUE hub-buf-phys : (allocate-mem) ( -- ) /hub-buf dma-alloc TO hub-buf hub-buf /hub-buf 0 dma-map-in TO hub-buf-phys hub-buf >setup-packet TO setup-packet hub-buf >ch-buffer TO ch-buffer hub-buf >dd-buffer dd-buffer ! hub-buf >cd-buffer cd-buffer ! s" hub-buf = " hub-buf usb-debug-print-val ; : (de-allocate-mem) ( -- ) hub-buf hub-buf-phys /hub-buf dma-map-out hub-buf /hub-buf dma-free 0 TO hub-buf 0 TO hub-buf-phys 0 TO setup-packet 0 TO ch-buffer 0 dd-buffer ! 0 cd-buffer ! ; : open ( -- TRUE ) (allocate-mem) TRUE ; : close ( -- ) (de-allocate-mem) ; : controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE|FALSE ) s" controlxfer" $call-parent ; : control-std-set-address ( speedbit -- usb-address TRUE|FALSE ) s" control-std-set-address" $call-parent ; : control-std-get-device-descriptor s" control-std-get-device-descriptor" $call-parent ; : control-std-get-configuration-descriptor s" control-std-get-configuration-descriptor" $call-parent ; : control-std-get-maxlun s" control-std-get-maxlun" $call-parent ; : control-std-set-configuration s" control-std-set-configuration" $call-parent ; : control-std-get-string-descriptor s" control-std-get-string-descriptor" $call-parent ; : rw-endpoint s" rw-endpoint" $call-parent ; : debug-td ( -- ) s" debug-td" $call-parent ; : control-bulk-reset ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE ) s" control-bulk-reset" $call-parent ; : control-hub-port-power-set ( port# -- TRUE|FALSE ) hppwr-set setup-packet ! ( port#) setup-packet 4 + c! 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE | FALSE ) ; : control-hub-port-power-clear ( port#-- TRUE|FALSE ) hppwr-clear setup-packet ! ( port#) setup-packet 4 + c! 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) ; : control-hub-port-reset-set ( port# -- TRUE|FALSE ) hprst-set setup-packet ! ( port# ) setup-packet 4 + c! 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) ; : control-hub-port-enable ( port# -- TRUE|FALSE ) hpena-set setup-packet ! ( port# ) setup-packet 4 + c! 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) ; : control-hub-port-status-get ( buffer port# -- TRUE|FALSE ) hpsta-get setup-packet ! ( buffer port# ) setup-packet 4 + c! ( buffer ) 0 swap 4 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) ; : control-get-hub-descriptor ( buffer buffer-length -- TRUE|FALSE ) hubds-get setup-packet ! dup setup-packet 6 + w!-le ( buffer buffer-length ) 0 -rot setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) ; s" usb-enumerate.fs" INCLUDED : hub-configure-port ( port# -- ) BEGIN ( port# ) hub-buf >status-buffer 4 erase ( port# ) hub-buf >status-buffer over control-hub-port-status-get drop ( port# ) hub-buf >status-buffer w@-le 102 and 0= ( port# TRUE|FALSE ) WHILE ( port# ) REPEAT ( port# ) po2pg 3 * ms \ wait for bPwrOn2PwrGood*3 ms dup control-hub-port-reset-set drop ( port# ) BEGIN ( port# ) hub-buf >status-buffer 4 erase ( port# ) hub-buf >status-buffer over control-hub-port-status-get drop ( port# ) hub-buf >status-buffer w@-le 10 and ( port# TRUE|FALSE ) WHILE ( port# ) REPEAT ( port# ) hub-buf >status-buffer 4 erase ( port# ) hub-buf >status-buffer over control-hub-port-status-get drop ( port# ) hub-buf >status-buffer w@-le 103 and 103 <> ( port# TRUE|FALSE ) s" Port status bits: " hub-buf >status-buffer w@-le usb-debug-print-val IF ( port# ) drop s" Connect status: No device connected " usb-debug-print EXIT THEN hub-buf >status-buffer w@-le 200 and 4 lshift \ get speed bit dup to device-speed \ store speed bit control-std-set-address ( port# usb-addr TRUE|FALSE ) 50 ms ( port# usb-addr TRUE|FALSE ) debug-td ( port# usb-addr TRUE|FALSE ) IF ( port# usb-addr ) device-speed or ( port# usb-addr+speedbit ) to new-device-address ( port# ) to port-number dd-buffer @ DEVICE-DESCRIPTOR-LEN erase dd-buffer @ DEFAULT-CONTROL-MPS DEFAULT-CONTROL-MPS new-device-address control-std-get-device-descriptor ( TRUE|FALSE ) IF dd-buffer @ DEVICE-DESCRIPTOR-TYPE-OFFSET + c@ ( descriptor-type ) DEVICE-DESCRIPTOR-TYPE <> ( TRUE|FALSE ) IF s" HUB: ERROR!! Invalid Device Descriptor for the new device" usb-debug-print ELSE dd-buffer @ DEVICE-DESCRIPTOR-MPS-OFFSET + c@ to mps dd-buffer @ DEVICE-DESCRIPTOR-LEN erase dd-buffer @ DEVICE-DESCRIPTOR-LEN mps new-device-address control-std-get-device-descriptor invert IF s" ** reading dev-descriptor failed ** " usb-debug-print THEN create-usb-device-tree THEN ELSE s" ERROR!! Failed to get device descriptor" usb-debug-print THEN ELSE ( port# ) s" USB Set Adddress failed!!" usb-debug-print ( port# ) s" Clearing Port Power..." usb-debug-print ( port# ) control-hub-port-power-clear ( TRUE|FALSE ) IF s" Port power down " usb-debug-print ELSE s" Unable to clear port power!!!" usb-debug-print THEN THEN ; : hub-enumerate ( -- ) cd-buffer @ CONFIG-DESCRIPTOR-LEN erase cd-buffer @ CONFIG-DESCRIPTOR-LEN MPS-DCP my-usb-address control-std-get-configuration-descriptor drop cd-buffer @ 1+ c@ 2 <> IF s" Unable to read configuration descriptor" usb-debug-print EXIT THEN cd-buffer @ 4 + c@ 1 <> IF s" Not a valid HUB config descriptor" usb-debug-print EXIT THEN cd-buffer @ 5 + c@ to temp1 \ Store the configuration in temp1 temp1 my-usb-address control-std-set-configuration drop my-usb-address to temp1 hub-buf >hd-buffer 9 erase hub-buf >hd-buffer 9 control-get-hub-descriptor drop hub-buf >hd-buffer 2 + c@ to temp2 \ number of downstream ports s" HUB: Found " usb-debug-print s" number of downstream hub ports! : " temp2 usb-debug-print-val hub-buf >hd-buffer 5 + c@ to po2pg \ get bPwrOn2PwrGood temp2 1+ 1 DO i control-hub-port-power-set drop d# 20 ms LOOP d# 200 ms \ some devices need a long time (10s) temp2 1+ 1 DO s" hub-configure-port: " i usb-debug-print-val i hub-configure-port LOOP ; (allocate-mem) mps-property-set hub-enumerate (de-allocate-mem) 8usb-enumerate.fs: (hub-create) ( -- ) mps port-number new-device-address port-number new-device set-space ( mps port-number usb-address ) encode-int s" USB-ADDRESS" property ( mps port-number ) s" Address Set" usb-debug-print encode-int s" reg" property ( mps ) s" Port Number Set" usb-debug-print encode-int s" MPS-DCP" property s" MPS Set" usb-debug-print s" usb-hub.fs" INCLUDED finish-device ; : (atapi-scsi-property-set) ( -- ) dd-buffer @ e + c@ ( Manuf ) dd-buffer @ f + c@ ( Manuf Prod ) dd-buffer @ 10 + c@ ( Manuf Prod Serial-Num ) cd-buffer @ 16 + w@-le ( Manuf Prod Serial-Num ep-mps ) cd-buffer @ 14 + c@ ( Manuf Prod Serial-Num ep-mps ep-addr ) cd-buffer @ 1d + w@-le ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ) cd-buffer @ 1b + c@ ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr ) mps port-number new-device-address port-number ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr mps port-num usb-addr port-num ) new-device set-space ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr mps port-num usb-addr ) encode-int s" USB-ADDRESS" property ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr mps port-num ) encode-int s" reg" property ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr mps ) encode-int s" MPS-DCP" property 2 0 DO dup 80 and IF 7f and encode-int s" BULK-IN-EP-ADDR" property encode-int s" MPS-BULKIN" property ELSE encode-int s" BULK-OUT-EP-ADDR" property encode-int s" MPS-BULKOUT" property THEN LOOP ( Manuf Prod Serial-Num ) encode-int s" iSerialNumber" property ( Manuf Prod ) encode-int s" iProduct" property ( Manuf ) encode-int s" iManufacturer" property ; : (device-classify) cd-buffer @ BULK-CONFIG-DESCRIPTOR-LEN erase cd-buffer @ BULK-CONFIG-DESCRIPTOR-LEN mps new-device-address control-std-get-configuration-descriptor IF cd-buffer @ 1+ c@ ( Descriptor-type ) 2 = IF cd-buffer @ 10 + c@ ( protocol ) cd-buffer @ f + c@ ( protocol subclass ) cd-buffer @ e + c@ ( protocol subclass class ) TRUE ELSE s" Not a valid configuration descriptor!!" usb-debug-print FALSE THEN ELSE s" Unable to read configuration descriptor!!" usb-debug-print FALSE THEN ; : (atapi-8020-create) ( -- ) (atapi-scsi-property-set) s" usb-storage.fs" INCLUDED finish-device ; : (atapi-8070-create) ( -- ) (atapi-scsi-property-set) s" usb-storage.fs" INCLUDED finish-device ; : (scsi-create) ( -- ) s" SCSI-CREATE " usb-debug-print dd-buffer @ 8 + w@-le 4b4 = \ VendorID = CYPRESS ? IF dd-buffer @ a + w@-le 6830 = \ Device = CY7C68300 ? IF d# 20 ms mps new-device-address 0 0 0 ( MPS fun-addr dir data-buff data-len ) control-bulk-reset ( TRUE|FALSE ) d# 100 ms mps new-device-address 0 0 0 ( TRUE|FALSE MPS fun-addr dir data-buff data-len ) control-bulk-reset ( TRUE|FALSE TRUE|FALSE ) and invert IF ." ** BULK-RESET failed **" cr THEN d# 20 ms THEN THEN 0 ch-buffer c! \ preset a clean response mps new-device-address 0 ch-buffer 1 control-std-get-maxlun ( TRUE|FALSE ) IF ELSE s" ERROR in GET-MAX-LUN " usb-debug-print 0 ch-buffer c! \ clear invalid numbers cd-buffer @ 5 + c@ to temp1 temp1 new-device-address control-std-set-configuration drop THEN 0 ( counter ) begin dup 8 < ( counter flag ) \ max 8 * 500 ms ch-buffer c@ f > ( counter flag flag ) \ is MuxLUN above limit ? AND ( counter flag ) while d# 500 ms \ this device is not yet ready 0 ch-buffer c! \ preset a clean response mps new-device-address 0 ch-buffer 1 control-std-get-maxlun ( TRUE|FALSE ) not IF s" ** ERROR in GET-MAX-LUN ** " usb-debug-print drop 10 \ replace counter to force loop end THEN 1+ ( counter+1 ) repeat drop ch-buffer c@ dup 0= swap f > or IF s" + LUN: " ch-buffer c@ usb-debug-print-val (atapi-scsi-property-set) s" usb-storage.fs" INCLUDED finish-device ELSE s" - LUN: " ch-buffer c@ usb-debug-print-val (atapi-scsi-property-set) s" usb-storage-wrapper.fs" INCLUDED finish-device THEN ; : (classify-storage) ( interface-protocol interface-subclass -- ) s" USB: Mass Storage Device Found!" usb-debug-print swap 50 <> IF s" USB storage: Protocol is not 50." usb-debug-print drop EXIT THEN CASE 02 OF (atapi-8020-create) s" ATAPI Interface " usb-debug-print ENDOF 05 OF (atapi-8070-create) s" ATAPI Interface " usb-debug-print ENDOF 06 OF (scsi-create) s" SCSI Interface " usb-debug-print ENDOF dup OF s" USB storage: Unsupported sub-class code." usb-debug-print ENDOF ENDCASE ; : (keyboard-create) ( -- ) cd-buffer @ 1f + c@ ( ep-mps ) cd-buffer @ 1d + c@ ( ep-mps ep-addr ) mps port-number new-device-address port-number new-device set-space ( ep-mps ep-addr mps port-num usb-addr ) encode-int s" USB-ADDRESS" property ( ep-mps ep-addr mps port-num ) encode-int s" reg" property ( ep-mps ep-addr mps ) encode-int s" MPS-DCP" property ( ep-mps ep-addr ) 7f and encode-int s" INT-IN-EP-ADDR" property encode-int s" MPS-INTIN" property new-device-address \ device-speed s" usb-keyboard.fs" INCLUDED finish-device ; : (mouse-create) ( -- ) mps port-number new-device-address port-number new-device set-space ( mps port-num usb-addr ) encode-int s" USB-ADDRESS" property ( mps port-num ) encode-int s" reg" property ( mps ) encode-int s" MPS-DCP" property s" usb-mouse.fs" INCLUDED finish-device ; : (classify-by-interface) ( -- ) (device-classify) IF CASE 08 OF (classify-storage) ENDOF 03 OF s" USB: HID Found!" usb-debug-print 01 = IF case 01 of s" USB keyboard!" usb-debug-print (keyboard-create) endof 02 of s" USB mouse!" usb-debug-print (mouse-create) endof dup of s" USB: unsupported HID!" usb-debug-print endof endcase ELSE s" USB: unsupported HID protocol " rot usb-debug-print-val THEN ENDOF dup OF s" USB: unsupported interface type." usb-debug-print 2drop ENDOF ENDCASE THEN ; : create-usb-device-tree ( -- ) dd-buffer @ DEVICE-DESCRIPTOR-DEVCLASS-OFFSET + c@ ( Device-class ) CASE HUB-DEVICE-CLASS OF s" USB: HUB found" usb-debug-print (hub-create) ENDOF NO-CLASS OF (classify-by-interface) ENDOF DUP OF s" USB: Unknown device found." usb-debug-print ENDOF ENDCASE ; 2P20usb-storage.fss" entered usb-storage.fs" usb-debug-print s" storage" device-name s" block" device-type 2 encode-int s" #address-cells" property 0 encode-int s" #size-cells" property 8 VALUE mps-bulk-out 8 VALUE mps-bulk-in 8 VALUE mps-dcp 0 VALUE bulk-in-ep 0 VALUE bulk-out-ep 0 VALUE bulk-in-toggle 0 VALUE bulk-out-toggle 0 VALUE lun 0 VALUE my-usb-address INSTANCE VARIABLE ihandle-bulk INSTANCE VARIABLE ihandle-deblocker INSTANCE VARIABLE flag INSTANCE VARIABLE count 4000 CONSTANT max-transfer 200 VALUE block-size \ default (512 Bytes) -1 VALUE max-block-num \ highest reported block-number 0f CONSTANT SCSI-COMMAND-OFFSET STRUCT max-transfer FIELD >read-buffer 80 FIELD >response-buffer 40 FIELD >command-buffer 10 FIELD >csw-buffer 8 FIELD >cfg-buffer CONSTANT /dma-buf 0 VALUE dma-buf 0 VALUE dma-buf-phys : (dma-buf-init) ( -- ) /dma-buf s" dma-alloc" $call-parent TO dma-buf dma-buf /dma-buf 0 s" dma-map-in" $call-parent TO dma-buf-phys s" storage dma-buf = " dma-buf usb-debug-print-val ; : (dma-buf-free) ( -- ) dma-buf dma-buf-phys /dma-buf s" dma-map-out" $call-parent dma-buf /dma-buf s" dma-free" $call-parent 0 TO dma-buf 0 TO dma-buf-phys ; s" usb-storage-support.fs" INCLUDED 0 VALUE bulk-cnt 0 VALUE bulk-cmd-len 0 VALUE itest 0 VALUE resp-buffer 0 VALUE resp-size : do-bulk-command ( resp-buffer resp-size -- TRUE | FALSE ) TO resp-size TO resp-buffer usb-debug-flag IF dma-buf >command-buffer 0E + c@ TO bulk-cmd-len s" cmd-length: " bulk-cmd-len usb-debug-print-val dma-buf >command-buffer bulk-cmd-len 0E + dump cr THEN 6 TO bulk-cnt \ 2 old value FALSE dup BEGIN 0= WHILE drop 1 1 bulk-out-toggle dma-buf >command-buffer 1f mps-bulk-out my-usb-address bulk-out-ep 7 lshift or rw-endpoint swap ( TRUE toggle | FALSE toggle ) to bulk-out-toggle ( TRUE | FALSE ) IF s" resp-size : " resp-size usb-debug-print-val resp-size 0<> IF \ do we need a response ?! 0 1 bulk-in-toggle resp-buffer resp-size mps-bulk-in my-usb-address bulk-in-ep 7 lshift or rw-endpoint swap ( TRUE toggle | FALSE toggle ) to bulk-in-toggle ( TRUE | FALSE ) ELSE TRUE THEN IF \ read the bulk CSW 0 1 bulk-in-toggle dma-buf >csw-buffer D mps-bulk-in my-usb-address bulk-in-ep 7 lshift or rw-endpoint swap ( TRUE toggle | FALSE toggle ) to bulk-in-toggle ( TRUE | FALSE ) IF s" Command successful." usb-debug-print TRUE dup ELSE s" Command failed in CSW stage" usb-debug-print FALSE dup THEN ELSE s" Command failed while receiving DATA... read CSW..." usb-debug-print 0 1 bulk-in-toggle dma-buf >csw-buffer D mps-bulk-in my-usb-address bulk-in-ep 7 lshift or rw-endpoint swap ( TRUE toggle | FALSE toggle ) to bulk-in-toggle ( TRUE | FALSE ) IF s" OK evaluate the CSW ..." usb-debug-print dma-buf >csw-buffer c + c@ dup TO itest s" CSW Status: " itest usb-debug-print-val dup 2 = IF \ Phase Error s" Phase error do a bulk reset-recovery ..." usb-debug-print bulk-out-ep bulk-in-ep my-usb-address bulk-reset-recovery-procedure THEN 1 = IF \ Command failed s" Command Failed do a bulk-reset-recovery" usb-debug-print bulk-out-ep bulk-in-ep my-usb-address bulk-reset-recovery-procedure THEN THEN FALSE dup THEN ELSE s" Command failed while Sending CBW ..." usb-debug-print FALSE dup THEN bulk-cnt 1 - TO bulk-cnt bulk-cnt 0= IF 2drop FALSE dup THEN REPEAT ; scsi-open usb-debug-flag to scsi-param-debug \ copy debug flag 24 CONSTANT inquiry-length \ was 20 : inquiry ( -- ) s" usb-storage: inquiry" usb-debug-print dma-buf >command-buffer 1 inquiry-length 80 lun scsi-length-inquiry build-cbw inquiry-length dma-buf >command-buffer SCSI-COMMAND-OFFSET + ( alloc-len address ) scsi-build-inquiry dma-buf >response-buffer inquiry-length erase \ provide clean buffer dma-buf >response-buffer inquiry-length do-bulk-command IF s" Successfully read INQUIRY data" usb-debug-print 0d emit space space dma-buf >response-buffer c@ \ get 'Peripheral Device Type' (PDT) CASE 0 OF ." BLOCK-DEV: " ENDOF \ SCSI Block Device 5 OF ." CD-ROM : " ENDOF 7 OF ." OPTICAL : " ENDOF e OF ." RED-BLOCK: " ENDOF \ SCSI Reduced Block Device dup dup OF ." ? (" . 8 emit 29 emit 2 spaces ENDOF ENDCASE space dma-buf >response-buffer 8 + 16 encode-string s" ident-str" property dma-buf >response-buffer .inquiry-text ELSE 5040 error" (USB) Device transaction error. (inquiry)" ABORT THEN ; : read-capacity ( -- ) s" usb-storage: read-capacity" usb-debug-print dma-buf >command-buffer 1 8 80 lun scsi-length-read-cap-10 build-cbw dma-buf >command-buffer SCSI-COMMAND-OFFSET + ( address ) scsi-build-read-cap-10 lun 5 lshift dma-buf >command-buffer SCSI-COMMAND-OFFSET + ( address ) read-cap-10>reserved1 c! dma-buf >response-buffer 8 erase \ provide clean buffer dma-buf >response-buffer 8 do-bulk-command IF s" Successfully read READ CAPACITY data" usb-debug-print ELSE 5040 error" (USB) Device transaction error. (capacity)" ABORT THEN ; : test-unit-ready ( -- TRUE | FALSE ) dma-buf >command-buffer 1 0 80 lun scsi-length-test-unit-ready \ was: 0c build-cbw dma-buf >command-buffer SCSI-COMMAND-OFFSET + ( address ) scsi-build-test-unit-ready ( cdb -- ) dma-buf >response-buffer 0 do-bulk-command IF s" Successfully read test unit ready data" usb-debug-print s" Test Unit STATUS availabe in dma-buf >csw-buffer" usb-debug-print dma-buf >csw-buffer 0c + c@ 0= IF s" Test Unit Command Successfully Executed" usb-debug-print TRUE ( TRUE ) ELSE s" Test Unit Command Failed to execute" usb-debug-print FALSE ( FALSE ) THEN ELSE 5040 error" (USB) Device transaction error. (test-unit-ready)" ABORT THEN ; : wait-for-unit-ready ( -- TRUE|FALSE ) s" --> WAIT: test-unit-ready ... " usb-debug-print d# 100 ( count ) \ up to 10 seconds BEGIN ( count ) dup 0> ( count flag ) test-unit-ready \ dup IF 2b ELSE 2d THEN emit not and ( count flag ) WHILE 1- ( count ) d# 100 wait-proceed \ wait 100 ms REPEAT ( count ) 0= IF s" ** Device not ready ** " usb-debug-print FALSE ELSE TRUE THEN ; : request-sense ( -- ) s" request-sense: Command ready." usb-debug-print dma-buf >command-buffer 1 12 80 lun scsi-length-request-sense build-cbw 12 dma-buf >command-buffer SCSI-COMMAND-OFFSET + ( alloc-len cdb ) scsi-build-request-sense ( alloc-len cdb -- ) dma-buf >response-buffer 12 do-bulk-command IF s" Read Sense data successfully" usb-debug-print ELSE 5040 error" (USB) Device transaction error. (request-sense)" ABORT THEN ; : start ( -- ) dma-buf >command-buffer 1 0 80 lun scsi-length-start-stop-unit build-cbw dma-buf >command-buffer SCSI-COMMAND-OFFSET + ( cdb ) scsi-const-start scsi-build-start-stop-unit ( state# cdb -- ) dma-buf >response-buffer 0 do-bulk-command IF s" Start successfully" usb-debug-print ELSE 5040 error" (USB) Device transaction error. (start)" ABORT THEN ; : stop ( -- ) dma-buf >command-buffer 1 0 80 lun scsi-length-start-stop-unit build-cbw dma-buf >command-buffer SCSI-COMMAND-OFFSET + ( cdb ) scsi-const-stop scsi-build-start-stop-unit ( state# cdb -- ) dma-buf >response-buffer 0 do-bulk-command IF s" Stop successfully" usb-debug-print ELSE 5040 error" (USB) Device transaction error. (stop)" ABORT THEN ; 0 VALUE temp1 0 VALUE temp2 0 VALUE temp3 : seek ( pos-lo pos-hi -- status ) 2dup lxjoin max-block-num block-size * > IF ." ** Seek Error: pos too large (" dup . over . ." -> " max-block-num block-size * . ." ) ** " cr -1 \ see spec-1275 page 183 ELSE s" seek" ihandle-deblocker @ $call-method THEN ; : read ( address length -- actual ) s" read" ihandle-deblocker @ $call-method ; : read-blocks ( address block# #blocks -- #read-blocks ) 2dup + max-block-num > IF ." ** Requested block too large " 2dup + ." (" .d ." -> " max-block-num .d bs emit ." ) ... read aborted **" cr nip nip \ leave #blocks on stack ELSE block-size * dma-buf >command-buffer ( address block# transfer-len command-buffer ) 1 2 pick 80 lun 0c build-cbw ( address block# transfer-len ) dup to temp1 ( address block# transfer-len ) block-size / ( address block# #blocks ) dma-buf >command-buffer ( address block# #blocks command-addr ) SCSI-COMMAND-OFFSET + ( address block# #blocks cdb ) scsi-build-read? ( address cdblength ) dma-buf >command-buffer 0e + c! \ update bCBWCBLength-field with resulting CDB length dma-buf >read-buffer temp1 ( address read-buffer transfer-len ) do-bulk-command ( address ) IF dma-buf >read-buffer swap temp1 ( read-buffer address transfer-len ) move s" Read data successfully" usb-debug-print ELSE drop 5040 error" (USB) Device transaction error. (read-blocks)" ABORT THEN temp1 block-size / ( #read-blocks ) THEN ; d# 800 CONSTANT media-ready-retry : make-media-ready ( -- ) s" usb-storage: make-media-ready" usb-debug-print 0 flag ! 0 count ! BEGIN flag @ 0= WHILE test-unit-ready IF s" Media ready for access." usb-debug-print 1 flag ! ELSE count @ 1 + count ! count @ media-ready-retry = IF 1 flag ! 5000 error" (USB) Media or drive not ready for this blade." ABORT THEN request-sense dma-buf >response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true ) IF ffff00 AND \ remaining: sense-key ASC CASE 023a00 OF \ MEDIUM NOT PRESENT (02 3a 00) 5010 error" (USB) No Media found! Check for the drawer/inserted media." ABORT ENDOF 020400 OF \ LOGICAL DRIVE NOT READY - INITIALIZATION REQUIRED 5010 error" (USB) No Media found! Check for the drawer/inserted media." ABORT ENDOF 033000 OF \ CANNOT READ MEDIUM - UNKNOWN FORMAT 5020 error" (USB) Unknown media format." ABORT ENDOF ENDCASE THEN THEN d# 10 ms \ wait maximum 10ms * 800 (=8s) REPEAT usb-debug-flag IF ." make-media-ready finished after " count @ decimal . hex ." tries." cr THEN ; : .showcap space test-unit-ready drop \ initial command request-sense dma-buf >response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true ) IF dup FFFF00 and 023a00 = ( sense-id flag ) IF 023a02 = \ see sense-codes SPC-3 clause 4.5.6 IF ." Tray Open!" ELSE ." No Media" THEN ELSE ( sense-id ) drop wait-for-unit-ready IF read-capacity dma-buf >response-buffer scsi-get-capacity-10 space .capacity-text ELSE request-sense dma-buf >response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true ) IF dup ff0000 and 040000 = \ sense-code = 4 ? IF ." *HW-ERROR*" ELSE CASE 023a00 OF ." No Media " ENDOF 023a02 OF ." Tray Open! " ENDOF dup OF ." ? " ENDOF ENDCASE THEN THEN THEN THEN ELSE ." ?? " THEN ; : init-dev-ready test-unit-ready drop 4 >r \ loop-counter 0 0 BEGIN 2drop request-sense dma-buf >response-buffer scsi-get-sense-data ( ascq asc sense-key ) 0<> r> 1- dup >r 0<> AND \ loop-counter or sense-key WHILE REPEAT 2drop r> drop ; scsi-close \ no further scsi words required : (init-block-size) read-capacity dma-buf >response-buffer l@ dup 0<> IF to max-block-num \ highest block-number ELSE -1 to max-block-num \ indeterminate THEN dma-buf >response-buffer 4 + l@ to block-size s" usb-storage: block-size=" block-size usb-debug-print-val ; : open ( -- TRUE ) s" usb-storage: open" usb-debug-print (dma-buf-init) ihandle-bulk s" bulk" (open-package) make-media-ready (init-block-size) \ Init block-size before opening the deblocker ihandle-deblocker s" deblocker" (open-package) s" disk-label" find-package IF ( phandle ) usb-debug-flag IF ." my-args for disk-label = " my-args swap . . cr THEN my-args rot interpose THEN TRUE ( TRUE ) ; : close ( -- ) ihandle-deblocker (close-package) ihandle-bulk (close-package) (dma-buf-free) ; : (init-device-name) ( -- ) init-dev-ready inquiry dma-buf >response-buffer c@ CASE 1 OF .showcap s" tape" device-name ENDOF 5 OF .showcap s" cdrom" device-name s" CDROM found" usb-debug-print ENDOF 0 OF .showcap s" sbc-dev" device-name s" SBC Direct access device" usb-debug-print ENDOF 7 OF .showcap s" optical" device-name s" Optical memory found" usb-debug-print ENDOF 0E OF .showcap s" rbc-dev" device-name s" RBC direct acces device found" usb-debug-print ENDOF ENDCASE ; : (initial-setup) (dma-buf-init) ihandle-bulk s" bulk" (open-package) device-init (init-device-name) set-drive-alias 200 to block-size \ Default block-size, will be overwritten in "open" ihandle-bulk (close-package) (dma-buf-free) ; (initial-setup) s" leaving usb-storage.fs" usb-debug-print  8usb-storage-support.fss" entered usb-storage-support.fs" usb-debug-print : rw-endpoint s" rw-endpoint" $call-parent ; : controlxfer ( dir addr dlen setup-packet MPS ep-fun --- TRUE|FALSE ) s" controlxfer" $call-parent ; : control-std-get-configuration-descriptor s" control-std-get-configuration-descriptor" $call-parent ; : control-std-set-configuration ( configvalue FuncAddr -- TRUE | FALSE ) s" control-std-set-configuration" $call-parent ( TRUE | FALSE ) ; : bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- ) s" bulk-reset-recovery-procedure" $call-parent ; : build-cbw ( address tag transfer-len direction lun command-len -- ) s" build-cbw" ihandle-bulk @ $call-method ; : analyze-csw ( address -- residue tag TRUE | reason FALSE ) s" analyze-csw" ihandle-bulk @ $call-method ; : device-init ( -- ) s" Starting to initialize usb-storage device" usb-debug-print s" USB-ADDRESS" get-my-property ( TRUE | propaddr proplen FALSE ) IF s" not possible" usb-debug-print ELSE decode-int nip nip to my-usb-address THEN s" MPS-BULKOUT" get-my-property ( TRUE | propaddr proplen FALSE ) IF s" not possible" usb-debug-print ELSE decode-int nip nip to mps-bulk-out THEN s" MPS-BULKIN" get-my-property ( TRUE | propaddr proplen FALSE ) IF s" not possible" usb-debug-print ELSE decode-int nip nip to mps-bulk-in THEN s" BULK-IN-EP-ADDR" get-my-property ( TRUE | propaddr proplen FALSE ) IF s" not possible" usb-debug-print ELSE decode-int nip nip to bulk-in-ep THEN s" BULK-OUT-EP-ADDR" get-my-property ( TRUE | propaddr proplen FALSE ) IF s" not possible" usb-debug-print ELSE decode-int nip nip to bulk-out-ep THEN s" MPS-DCP" get-my-property ( TRUE | propaddr proplen FALSE ) IF s" Not possible" usb-debug-print ELSE decode-int nip nip to mps-dcp THEN s" LUN" get-my-property ( TRUE | propaddr proplen FALSE ) IF s" NOT Possible to extract LUN" usb-debug-print ELSE decode-int nip nip to lun THEN s" Extracted properties inherited from parent." usb-debug-print dma-buf >cfg-buffer 8 mps-dcp my-usb-address ( buffer len mps fun-addr ) control-std-get-configuration-descriptor ( TRUE | FALSE ) drop s" Configuration descriptor extracted." usb-debug-print dma-buf >cfg-buffer 5 + c@ my-usb-address ( configvalue fun-addr ) control-std-set-configuration ( TRUE | FALSE ) s" usb-storage: Set config returned: " rot usb-debug-print-val ; : (open-package) ( ihandle-var name-str name-len -- ) find-package IF ( ihandle-var phandle ) 0 0 rot open-package ( ihandle-var ihandle ) swap ! ELSE s" Support package not found" usb-debug-print THEN ; : (close-package) ( ihandle-var -- ) dup @ close-package 0 swap ! ; s" leaving usb-storage-support.fs" usb-debug-print x38usb-storage-wrapper.fss" scsi" device-name s" block-type" device-type 1 encode-int s" #address-cells" property 0 encode-int s" #size-cells" property : encode-unit 1 hex-encode-unit ; : decode-unit 1 hex-decode-unit ; 1 chars alloc-mem VALUE ch-buffer 8 VALUE mps-dcp 0 VALUE port-number 0 VALUE my-usb-address : control-std-get-maxlun s" control-std-get-maxlun" $call-parent ; : control-std-get-configuration-descriptor s" control-std-get-configuration-descriptor" $call-parent ; : rw-endpoint s" rw-endpoint" $call-parent ; : controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE|FALSE ) s" controlxfer" $call-parent ; : control-std-set-configuration s" control-std-set-configuration" $call-parent ; : extract-properties ( -- ) s" USB-ADDRESS" get-inherited-property ( prop-addr prop-len FALSE | TRUE ) IF s" notpossible" usb-debug-print ELSE decode-int nip nip to my-usb-address THEN s" MPS-DCP" get-inherited-property ( prop-addr prop-len FALSE | TRUE ) IF s" MPS-DCP property not found.Assume 8 as MAX PACKET SIZE" usb-debug-print s" for the default control pipe" usb-debug-print 8 to mps-dcp ELSE s" MPS-DCP property found!!" usb-debug-print decode-int nip nip to mps-dcp THEN s" reg" get-inherited-property ( prop-addr prop-len FLASE | TRUE ) IF s" notpossible" usb-debug-print ELSE decode-int nip nip to port-number THEN ; : create-tree ( -- ) mps-dcp my-usb-address 0 ch-buffer 1 ( MPS fun-addr dir data-buff data-len ) control-std-get-maxlun ( TRUE | FALSE ) IF s" GET-MAX-LUN IS WORKING :" usb-debug-print ELSE s" ERROR in GET-MAX-LUN " usb-debug-print THEN ch-buffer c@ 1 + 0 ( max-lun+1 0 ) DO s" iManufacturer" get-inherited-property drop ( prop-addr prop-len TRUE ) decode-int nip nip ( iManu ) s" iProduct" get-inherited-property drop decode-int nip nip ( iManu iProd ) s" iSerialNumber" get-inherited-property drop decode-int nip nip ( iManu iProd iSerNum ) s" MPS-BULKOUT" get-inherited-property drop decode-int nip nip ( iManu iProd iSerNum MPS-BULKOUT ) s" BULK-OUT-EP-ADDR" get-inherited-property drop decode-int nip nip ( iManu iProd iSerNum MPS-BULKOUT BULK-OUT-EP-ADDR ) s" MPS-BULKIN" get-inherited-property drop ( iManu iProd iSerNum MPS-BULKOUT BULK-OUT-EP-ADDR prop-addr prop-len TRUE | FALSE ) decode-int nip nip s" BULK-IN-EP-ADDR" get-inherited-property drop ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN prop-addr prop-len TRUE | FALSE ) decode-int nip nip ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN BULKIN-EP-ADDR ) mps-dcp port-number my-usb-address I ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN BULKIN-EP-ADDR mps-dcp port-address my-usb-address lun-number ) new-device ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN BULKIN-EP-ADDR mps-dcp port-address my-usb-address lun-number ) set-space ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN BULKIN-EP-ADDR mps-dcp port-number my-usb-address ) encode-int s" USB-ADDRESS" property ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN BULKIN-EP-ADDR mps-dcp port-number ) encode-int s" reg" property encode-int s" MPS-DCP" property ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN BULKIN-EP-ADDR ) I encode-int s" LUN" property ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN BULKIN-EP-ADDR ) encode-int s" BULK-IN-EP-ADDR" property encode-int s" MPS-BULKIN" property encode-int s" BULK-OUT-EP-ADDR" property encode-int s" MPS-BULKOUT" property ( iManu iProd iSerNum ) encode-int s" iSerialNumber" property ( iManu iProd ) encode-int s" iProduct" property ( iManu ) encode-int s" iManufacturer" property ( -- ) s" usb-storage.fs" INCLUDED finish-device LOOP ; extract-properties \ Extract the properties from parent create-tree \ this method creates the node for every lun with properties .-0usb-keyboard.fss" keyboard" device-name s" keyboard" device-type ." USB Keyboard" cr 3 encode-int s" assigned-addresses" property 1 encode-int s" reg" property 1 encode-int s" configuration#" property s" EN" encode-string s" language" property 1 constant NumLk 2 constant CapsLk 4 constant ScrLk TRUE VALUE use-interrupt-transfers? s" model" s" /" find-node get-property 0= IF 2dup s" qemu" find-substr = TO use-interrupt-transfers? drop THEN 00 value kbd-addr to kbd-addr \ save speed bit 8 value mps-dcp 8 constant DEFAULT-CONTROL-MPS 0 value multi-key 0 value led-state 0 value temp1 0 value temp2 0 value temp3 0 value ret 0 value scancode 0 value kbd-shift 0 value kbd-scan 0 value key-old 0 value expire-ms 0 value mps-int-in 0 value int-in-ep 0 value int-in-toggle STRUCT 80 FIELD kb>cfg \ For config descriptors etc, size 0x80 8 FIELD kb>report \ For keyboard report, size 8 8 FIELD kb>setup-packet \ For setup-packet, size 8 4 FIELD kb>data \ Various data, size 4 CONSTANT /kbd-buf 0 VALUE kbd-buf 0 VALUE kbd-buf-dma : (kbd-buf-init) ( -- ) /kbd-buf s" dma-alloc" $call-parent TO kbd-buf kbd-buf /kbd-buf 0 s" dma-map-in" $call-parent TO kbd-buf-dma s" kbd-buf = " kbd-buf usb-debug-print-val ; : (kbd-buf-free) ( -- ) kbd-buf kbd-buf-dma /kbd-buf s" dma-map-out" $call-parent kbd-buf /kbd-buf s" dma-free" $call-parent 0 TO kbd-buf 0 TO kbd-buf-dma ; s" usb-kbd-device-support.fs" included : control-cls-set-report ( reportvalue FuncAddr -- TRUE|FALSE ) to temp1 to temp2 2109000200000100 kbd-buf kb>setup-packet ! temp2 kbd-buf kb>data l!-le 1 kbd-buf kb>data 1 kbd-buf kb>setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer ; : control-cls-get-report ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE ) to temp1 to temp2 to temp3 a101000100000000 kbd-buf kb>setup-packet ! temp3 kbd-buf kb>setup-packet 6 + w!-le 0 swap temp3 kbd-buf kb>setup-packet temp2 temp1 controlxfer ; : int-get-report ( -- ) \ get report for interrupt transfer 0 2 int-in-toggle kbd-buf kb>report 8 mps-int-in kbd-addr int-in-ep 7 lshift or rw-endpoint \ get report swap to int-in-toggle IF kbd-buf kb>report @ ff00000000000000 and 38 rshift to kbd-shift \ store shift status kbd-buf kb>report @ 0000ffffffffffff and to kbd-scan \ store scan codes ELSE 0 to kbd-shift \ clear shift status 0 to kbd-scan \ clear scan code buffer THEN ; : ctl-get-report ( -- ) \ get report for control transfer kbd-buf kb>report 8 8 kbd-addr control-cls-get-report IF \ get report kbd-buf kb>report @ ff00000000000000 and 38 rshift to kbd-shift \ store shift status kbd-buf kb>report @ 0000ffffffffffff and to kbd-scan \ store scan codes ELSE 0 to kbd-shift \ clear shift status 0 to kbd-scan \ clear scan code buffer THEN ; : kbd-get-report ( -- ) use-interrupt-transfers? IF int-get-report ELSE ctl-get-report THEN ; : set-led ( led -- ) dup to led-state kbd-addr control-cls-set-report drop ; : is-shift ( -- true|false ) kbd-shift 22 and if true else false then ; : is-alt ( -- true|false ) kbd-shift 44 and if true else false then ; : is-ctrl ( -- true|false ) kbd-shift 11 and if true else false then ; : ctrl_alt_del_key ( char -- ) is-ctrl if \ ctrl is pressed? is-alt if \ alt is pressed? 4c = if \ del is pressed? s" reboot.... " usb-debug-print drop false \ invalidate del key on top of stack then false \ dummy for last drop then then drop \ clear stack ; : get-ukbd-char ( ScanCode -- char|false ) dup ctrl_alt_del_key \ check ctrl+alt+del dup to scancode \ store scan code case \ translate scan code --> char 04 of [char] a endof 05 of [char] b endof 06 of [char] c endof 07 of [char] d endof 08 of [char] e endof 09 of [char] f endof 0a of [char] g endof 0b of [char] h endof 0c of [char] i endof 0d of [char] j endof 0e of [char] k endof 0f of [char] l endof 10 of [char] m endof 11 of [char] n endof 12 of [char] o endof 13 of [char] p endof 14 of [char] q endof 15 of [char] r endof 16 of [char] s endof 17 of [char] t endof 18 of [char] u endof 19 of [char] v endof 1a of [char] w endof 1b of [char] x endof 1c of [char] y endof 1d of [char] z endof 1e of [char] 1 endof 1f of [char] 2 endof 20 of [char] 3 endof 21 of [char] 4 endof 22 of [char] 5 endof 23 of [char] 6 endof 24 of [char] 7 endof 25 of [char] 8 endof 26 of [char] 9 endof 27 of [char] 0 endof 28 of 0d endof \ Enter 29 of 1b endof \ ESC 2a of 08 endof \ Backsace 2b of 09 endof \ Tab 2c of 20 endof \ Space 2d of [char] - endof 2e of [char] = endof 2f of [char] [ endof 30 of [char] ] endof 31 of [char] \ endof 33 of [char] ; endof 34 of [char] ' endof 35 of [char] ` endof 36 of [char] , endof 37 of [char] . endof 38 of [char] / endof 39 of led-state CapsLk xor set-led false endof \ CapsLk 3a of 1b 7e31315b to multi-key endof \ F1 3b of 1b 7e32315b to multi-key endof \ F2 3c of 1b 7e33315b to multi-key endof \ F3 3d of 1b 7e34315b to multi-key endof \ F4 3e of 1b 7e35315b to multi-key endof \ F5 3f of 1b 7e37315b to multi-key endof \ F6 40 of 1b 7e38315b to multi-key endof \ F7 41 of 1b 7e39315b to multi-key endof \ F8 42 of 1b 7e30315b to multi-key endof \ F9 43 of 1b 7e31315b to multi-key endof \ F10 44 of 1b 7e33315b to multi-key endof \ F11 45 of 1b 7e34315b to multi-key endof \ F12 47 of led-state ScrLk xor set-led false endof \ ScrLk 49 of 1b 7e315b to multi-key endof \ Ins 4a of 1b 7e325b to multi-key endof \ Home 4b of 1b 7e335b to multi-key endof \ PgUp 4c of 1b 7e345b to multi-key endof \ Del 4d of 1b 7e355b to multi-key endof \ End 4e of 1b 7e365b to multi-key endof \ PgDn 4f of 1b 435b to multi-key endof \ R-arrow 50 of 1b 445b to multi-key endof \ L-arrow 51 of 1b 425b to multi-key endof \ D-arrow 52 of 1b 415b to multi-key endof \ U-arrow 53 of led-state NumLk xor set-led false endof \ NumLk 54 of [char] / endof \ keypad / 55 of [char] * endof \ keypad * 56 of [char] - endof \ keypad - 57 of [char] + endof \ keypad + 58 of 0d endof \ keypad Enter 89 of [char] \ endof \ japanese yen dup of false endof \ other keys are false endcase to ret \ store char led-state CapsLk and 0 <> if \ if CapsLk is on scancode 03 > if \ from a to z ? scancode 1e < if ret 20 - to ret \ to Upper case then then then is-shift if \ if shift is on scancode 03 > if \ from a to z ? scancode 1e < if ret 20 - to ret \ to Upper case else scancode case \ translate scan code --> char 1e of [char] ! endof 1f of [char] @ endof 20 of [char] # endof 21 of [char] $ endof 22 of [char] % endof 23 of [char] ^ endof 24 of [char] & endof 25 of [char] * endof 26 of [char] ( endof 27 of [char] ) endof 2d of [char] _ endof 2e of [char] + endof 2f of [char] { endof 30 of [char] } endof 31 of [char] | endof 33 of [char] : endof 34 of [char] " endof 35 of [char] ~ endof 36 of [char] < endof 37 of [char] > endof 38 of [char] ? endof dup of ret endof \ other keys are no change endcase to ret \ overwrite new char then then then led-state NumLk and 0 <> if \ if NumLk is on scancode case \ translate scan code --> char 59 of [char] 1 endof 5a of [char] 2 endof 5b of [char] 3 endof 5c of [char] 4 endof 5d of [char] 5 endof 5e of [char] 6 endof 5f of [char] 7 endof 60 of [char] 8 endof 61 of [char] 9 endof 62 of [char] 0 endof 63 of [char] . endof \ keypad . dup of ret endof \ other keys are no change endcase to ret \ overwrite new char then ret \ return char ; : key-available? ( -- true|false ) multi-key 0 <> IF true \ multi scan code key was pressed... so key is available EXIT \ done THEN kbd-scan 0 = IF \ if no kbd-scan code is currently available kbd-get-report \ check for new scan codes THEN kbd-scan 0 <> \ if a kbd-scan is available, report true, else false ; : usb-kread ( -- char|false ) \ usb key read for control transfer multi-key 0 <> if \ if multi scan code key is pressed multi-key ff and \ read one byte from buffer multi-key 8 rshift to multi-key \ move to next byte else \ normal key check kbd-scan 0 = IF kbd-get-report \ read scan-code report THEN kbd-scan 0 <> if \ scan code exist? begin kbd-scan ff and dup 00 = while \ get a last scancode in report buffer kbd-scan 8 rshift to kbd-scan \ This algorithm is wrong --> must be fixed! drop \ KBD doesn't set scancode in pressed order!!! repeat ff and dup to kbd-scan \ we can only digest one key at a time dup key-old <> if \ if the scancode is new dup to key-old \ save current scan code get-ukbd-char \ translate scan code --> char milliseconds fa + to expire-ms \ set typematic delay 250ms else \ scan code is not changed milliseconds expire-ms > if \ if timer is expired ... should be considered timer carry over get-ukbd-char \ translate scan code --> char milliseconds 21 + to expire-ms \ set typematic rate 30cps else \ timer is not expired drop false \ do nothing then then kbd-scan 8 rshift to kbd-scan \ handled scan-code else 0 to key-old \ clear privious key false \ no scan code --> return false then then ; : key-read ( -- char ) 0 begin drop usb-kread dup 0 <> until \ read key input (Interrupt transfer) ; : read ( addr len -- actual ) 0= IF drop 0 EXIT THEN usb-kread ?dup IF swap c! 1 ELSE 0 swap c! -2 THEN ; (kbd-buf-init) kbd-init \ keyboard initialize milliseconds to expire-ms \ Timer initialize 0 to multi-key \ multi key buffer clear 7 set-led \ flash leds 250 ms 0 set-led (kbd-buf-free) s" keyboard" get-node node>path set-alias : open ( -- true ) (kbd-buf-init) 7 set-led 100 ms 3 set-led 100 ms 1 set-led 100 ms usb-kread drop 0 set-led true ; : close (kbd-buf-free) ; s" Keyboard init done" usb-debug-print  @usb-kbd-device-support.fs: rw-endpoint s" rw-endpoint" $call-parent ; : controlxfer s" controlxfer" $call-parent ; : control-std-get-device-descriptor s" control-std-get-device-descriptor" $call-parent ; : control-std-get-configuration-descriptor s" control-std-get-configuration-descriptor" $call-parent ; : control-std-set-configuration s" control-std-set-configuration" $call-parent ; : control-cls-set-protocol ( reportvalue FuncAddr -- TRUE|FALSE ) to temp1 to temp2 210b000000000100 kbd-buf kb>setup-packet ! temp2 kbd-buf kb>data l!-le 1 kbd-buf kb>data 1 kbd-buf kb>setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer ; : control-cls-set-idle ( reportvalue FuncAddr -- TRUE|FALSE ) to temp1 to temp2 210a000000000000 kbd-buf kb>setup-packet ! temp2 kbd-buf kb>data l!-le 0 kbd-buf kb>data 0 kbd-buf kb>setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer ; : control-std-get-report-descriptor ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE ) to temp1 to temp2 to temp3 8106002200000000 kbd-buf kb>setup-packet ! temp3 kbd-buf kb>setup-packet 6 + w!-le 0 swap temp3 kbd-buf kb>setup-packet temp2 temp1 controlxfer ; : kbd-init s" Starting to initialize keyboard" usb-debug-print s" MPS-INTIN" get-my-property if s" not possible" usb-debug-print else decode-int nip nip to mps-int-in then s" INT-IN-EP-ADDR" get-my-property if s" not possible" usb-debug-print else decode-int nip nip to int-in-ep then kbd-buf kb>cfg 12 8 kbd-addr \ get device descriptor control-std-get-device-descriptor drop kbd-buf kb>cfg 9 8 kbd-addr \ get config descriptor control-std-get-configuration-descriptor drop kbd-buf kb>cfg 5 + c@ kbd-addr \ set configuration control-std-set-configuration drop s" KBDS: Set config returned" usb-debug-print 0 kbd-addr control-cls-set-idle drop \ set idle s" KBDS: Set idle returned" usb-debug-print kbd-buf kb>cfg 3f 8 kbd-addr \ get report descriptor control-std-get-report-descriptor drop s" Finished initializing keyboard" usb-debug-print ; `'0usb-mouse.fss" mouse" device-name s" mouse" device-type ." USB Mouse" cr 1 encode-int s" configuration#" property 2 encode-int s" #buttons" property 4 encode-int s" assigned-addresses" property 2 encode-int s" reg" property : open true ; : close ; : get-event ( msec -- pos.x pos.y buttons true|false ) ; NNm0scsi-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 70 = \ 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 ; 08 CONSTANT scsi-cmd-read-6 STRUCT /c FIELD read-6>operation-code \ 08h /c FIELD read-6>block-address-msb \ upper 5 bits /w FIELD read-6>block-address \ lower 16 bits /c FIELD read-6>length \ number of blocks to read /c FIELD read-6>control \ CDB control CONSTANT scsi-length-read-6 : scsi-build-read-6 ( block# #blocks cdb -- ) >r ( block# #blocks ) ( R: -- cdb ) r@ scsi-length-read-6 erase \ 6 bytes CDB scsi-cmd-read-6 r@ read-6>operation-code c! ( block# #blocks ) dup d# 255 > \ #blocks exceeded limit ? IF scsi-inc-errors drop 1 \ replace with any valid number THEN r@ read-6>length c! \ set #blocks to read dup 1fffff > \ check address upper limit IF scsi-inc-errors drop \ remove original block# 1fffff \ replace with any valid address THEN dup d# 16 rshift r@ read-6>block-address-msb c! \ set upper 5 bits ffff and r@ read-6>block-address w! \ set lower 16 bits scsi-param-control r> read-6>control c! ( R: cdb -- ) scsi-length-read-6 to scsi-param-size \ update CDB length ; 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 ; : 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 ; 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) ; 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 occured ? IF cr ." ** WARNING: " scsi-param-errors .d ." SCSI Errors occured ** " 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 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 `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 virtiodev 0 virtio-get-qsize virtio-vring-size 1000 CLAIM VALUE queue-addr queue-addr c rshift virtiodev vd>base @ 8 + rl!-le pci-device-disable `8pci-device_1af4_1009.fss" virtio [ network ]" type cr my-space pci-device-generic-setup pci-master-enable pci-mem-enable pci-io-enable s" virtio-fs.fs" included virtiodev 0 virtio-get-qsize virtio-vring-size 1000 CLAIM VALUE queue-addr queue-addr c rshift virtiodev vd>base @ 8 + rl!-le pci-device-disable 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 0/0vio-vscsi.fs." Populating " pwd 0 CONSTANT vscsi-debug 0 VALUE vscsi-unit : l2dma ( laddr - dma_addr) ; 0 VALUE crq-base 0 VALUE crq-dma 0 VALUE crq-offset 1000 CONSTANT CRQ-SIZE CREATE crq 10 allot : crq-alloc ( -- ) CRQ-SIZE alloc-mem to crq-base 0 to crq-offset crq-base l2dma to crq-dma ; : crq-free ( -- ) vscsi-unit hv-free-crq crq-base CRQ-SIZE free-mem 0 to crq-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 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 ) srp >srp-rsp-data ; : srp-wait-rsp ( -- true | [ ascq asc sense-key false ] ) srp-wait-crq not IF false EXIT THEN dup 1 <> IF ." VSCSI: Invalid CRQ response tag, want 1 got " . cr false EXIT THEN drop srp >srp-rsp-tag x@ dup 1 <> IF ." VSCSI: Invalid SRP response tag, want 1 got " . cr false EXIT THEN drop srp >srp-rsp-status c@ vscsi-debug IF ." VSCSI: Got response status: " dup .status-text cr THEN 0 <> IF srp-rsp-find-sense scsi-get-sense-data vscsi-debug IF ." VSCSI: Sense key: " dup .sense-text cr THEN false EXIT THEN true ; CREATE sector d# 512 allot 8000000000000000 INSTANCE VALUE current-target : test-unit-ready ( -- true | [ ascq asc sense-key false ] ) current-target srp-prep-cmd-nodata srp >srp-cmd-cdb scsi-build-test-unit-ready srp-send-cmd srp-wait-rsp ; : inquiry ( -- true | false ) sector ff current-target srp-prep-cmd-read ff srp >srp-cmd-cdb scsi-build-inquiry srp-send-cmd srp-wait-rsp dup not IF nip nip nip EXIT THEN \ swallow sense ; : report-luns ( -- true | false ) sector 200 current-target srp-prep-cmd-read 200 srp >srp-cmd-cdb scsi-build-report-luns srp-send-cmd srp-wait-rsp dup not IF nip nip nip EXIT THEN \ swallow sense ; : read-capacity ( -- true | false ) sector scsi-length-read-cap-10 current-target srp-prep-cmd-read srp >srp-cmd-cdb scsi-build-read-cap-10 srp-send-cmd srp-wait-rsp dup not IF nip nip nip EXIT THEN \ swallow sense ; : start-stop-unit ( state# -- true | false ) current-target srp-prep-cmd-nodata srp >srp-cmd-cdb scsi-build-start-stop-unit srp-send-cmd srp-wait-rsp dup not IF nip nip nip EXIT THEN \ swallow sense ; : get-media-event ( -- true | false ) sector scsi-length-media-event current-target srp-prep-cmd-read srp >srp-cmd-cdb scsi-build-get-media-event srp-send-cmd srp-wait-rsp dup not IF nip nip nip EXIT THEN \ swallow sense ; : read-blocks ( -- addr block# #blocks blksz -- [ #read-blocks true ] | false ) over * ( addr block# #blocks len ) >r rot r> ( block# #blocks addr len ) 5 0 DO 2dup current-target srp-prep-cmd-read ( block# #blocks addr len ) 2swap ( addr len block# #blocks ) 2dup srp >srp-cmd-cdb scsi-build-read-10 ( addr len block# #blocks ) 2swap ( block# #blocks addr len ) srp-send-cmd srp-wait-rsp IF 2drop nip true UNLOOP EXIT THEN srp >srp-rsp-status c@ 8 <> IF nip nip nip 2drop 2drop false EXIT THEN 3drop 100 ms LOOP 2drop 2drop false ; : vscsi-cleanup crq-cleanup vscsi-unit 0 rtas-set-tce-bypass ; : vscsi-init ( -- true | false ) ." VSCSI: Initializing" cr " reg" get-node get-package-property IF ." VSCSI: Not reg property !!!" 0 THEN decode-int to vscsi-unit 2drop 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 ['] vscsi-cleanup add-quiesce-xt true ; : set-target ( srplun -- ) to current-target ; : dev-max-transfer ( -- n ) 10000 \ Larger value seem to have problems with some CDROMs ; : dev-get-capacity ( -- blocksize #blocks ) sector 10 erase read-capacity not IF 0 0 EXIT THEN sector scsi-get-capacity-10 ; : dev-read-blocks ( -- addr block# #blocks blksize -- #read-blocks ) read-blocks ; : initial-test-unit-ready ( -- true | [ ascq asc sense-key false ] ) 0 0 0 false 3 0 DO 2drop 2drop test-unit-ready dup IF UNLOOP EXIT THEN LOOP ; : 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-status ( -- status ) initial-test-unit-ready IF CDROM-READY EXIT THEN vscsi-debug IF ." TestUnitReady sense: " 3dup . . . cr THEN 3dup 1 4 2 compare-sense IF 3drop CDROM-NOT-READY EXIT THEN get-media-event IF sector w@ 4 >= IF sector 2 + c@ 04 = IF sector 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 ; : 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 ; : dev-prep-cdrom ( -- ) 5 0 DO cdrom-status CASE CDROM-READY OF UNLOOP EXIT ENDOF CDROM-NO-DISK OF ." No medium !" cr -65 THROW 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 -65 THROW ; : dev-prep-disk ( -- ) initial-test-unit-ready 0= IF ." Disk not ready!" cr 3drop THEN ; : vscsi-create-disk ( srplun -- ) " disk" 0 " vio-vscsi-device.fs" included ; : vscsi-create-cdrom ( srplun -- ) " cdrom" 1 " vio-vscsi-device.fs" included ; : wrapped-inquiry ( -- true | false ) inquiry not IF false EXIT THEN sector inquiry-data>peripheral c@ e0 and 0 = ; 8 CONSTANT #dev : vscsi-report-luns ( -- array ndev ) #dev 3 << alloc-mem dup 0 ( devarray devcur ndev ) #dev 0 DO i 8 << 8000 or 30 << set-target report-luns 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 x@ j 8 << 8000 or or 30 << swap x! 8 + LOOP drop rot ( devarray ndev mem devcur ) dup >r x! r> 8 + ( devarray ndev devcur ) swap 1 + THEN LOOP nip ; : vscsi-find-disks ( -- ) ." VSCSI: Looking for devices" cr vscsi-report-luns 0 DO dup x@ BEGIN dup x@ dup 0= IF drop FALSE ELSE set-target wrapped-inquiry IF ." " current-target (u.) type ." " sector inquiry-data>peripheral c@ CASE 0 OF ." DISK : " current-target vscsi-create-disk ENDOF 5 OF ." CD-ROM : " current-target vscsi-create-cdrom ENDOF 7 OF ." OPTICAL : " current-target vscsi-create-cdrom ENDOF e OF ." RED-BLOCK: " current-target vscsi-create-disk ENDOF dup dup OF ." ? (" . 8 emit 29 emit 5 spaces ENDOF ENDCASE sector .inquiry-text cr THEN 8 + TRUE THEN UNTIL drop 8 + LOOP drop ; 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 vscsi-init IF vscsi-find-disks setup-alias THEN close-node r> to my-self ; new-device s" disk" device-name s" block" device-type finish-device vscsi-init-and-scan m8vio-vscsi-device.fsnew-device VALUE is_cdrom rot ( $name target ) dup set-unit-64 xlsplit encode-phys " reg" property 2dup device-name 2dup find-alias 0= IF get-node node>path set-alias ELSE 3drop THEN s" block" device-type 0 INSTANCE VALUE block-size 0 INSTANCE VALUE max-block-num 0 INSTANCE VALUE max-transfer : read-blocks ( addr block# #blocks -- #read ) block-size " dev-read-blocks" $call-parent not IF ." Read blocks failed !" cr -1 throw THEN ; INSTANCE VARIABLE deblocker : open ( -- true | false ) my-unit lxjoin " set-target" $call-parent is_cdrom IF " dev-prep-cdrom" ELSE " dev-prep-disk" THEN $call-parent " dev-max-transfer" $call-parent to max-transfer " dev-get-capacity" $call-parent to max-block-num to block-size max-block-num 0= block-size 0= OR IF ." Failed to get disk capacity!" cr FALSE EXIT 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 ; finish-device @0vio-veth.fs." Populating " pwd cr " network" device-type INSTANCE VARIABLE obp-tftp-package : open ( -- okay? ) my-unit 1 rtas-set-tce-bypass my-args s" obp-tftp" $open-package obp-tftp-package ! true ; : close ( -- ) s" close" obp-tftp-package @ $call-method my-unit 0 rtas-set-tce-bypass ; : load ( addr -- len ) s" load" obp-tftp-package @ $call-method ; : ping ( -- ) s" ping" obp-tftp-package @ $call-method ; : setup-alias " net" find-alias 0= IF " net" get-node node>path set-alias ELSE drop 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 /vd-len BUFFER: virtiodev virtiodev virtio-setup-vd : open ( -- okay? ) open IF my-args s" obp-tftp" $open-package obp-tftp-package ! true ELSE false THEN ; : close ( -- ) s" close" obp-tftp-package @ $call-method close ; : load ( addr -- len ) s" load" obp-tftp-package @ $call-method ; : ping ( -- ) s" ping" obp-tftp-package @ $call-method ; 6 BUFFER: local-mac : setup-mac ( -- ) 6 0 DO virtiodev i 1 virtio-get-config local-mac i + c! LOOP local-mac 6 encode-bytes s" local-mac-address" property ; setup-mac : setup-alias ( -- ) s" net" find-alias 0= IF s" net" get-node node>path set-alias ELSE drop THEN ; setup-alias 0virtio-block.fss" block" device-type FALSE VALUE initialized? 200 CONSTANT block-size 8000 CONSTANT max-transfer INSTANCE VARIABLE deblocker /vd-len BUFFER: virtiodev virtiodev virtio-setup-vd : shutdown ( -- ) virtiodev virtio-blk-shutdown FALSE to initialized? ; : init ( -- ) virtiodev virtio-blk-init TRUE to initialized? ['] shutdown add-quiesce-xt ; : read-blocks ( addr block# #blocks -- #read ) virtiodev virtio-blk-read ; : open ( -- okay? ) open 0= IF false EXIT THEN 0 0 s" deblocker" $open-package dup deblocker ! dup IF s" disk-label" find-package IF my-args rot interpose THEN THEN dup initialized? 0= AND IF init 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 ; : (set-alias) s" disk" find-alias 0= IF s" disk" get-node node>path set-alias ELSE drop THEN ; (set-alias) H 0virtio-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 /vd-len BUFFER: virtiodev virtiodev virtio-setup-vd : 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 THEN ; (set-alias) C0build_info.imgprintf t[CC]t%sn build_info.img; /opt/cross/gcc-4.6.3-nolibc/powerpc64-linux/bin/powerpc64-linux-gcc -m64 Using built-in specs. COLLECT_GCC=/opt/cross/gcc-4.6.3-nolibc/powerpc64-linux/bin/powerpc64-linux-gcc COLLECT_LTO_WRAPPER=/opt/cross/gcc-4.6.3-nolibc/powerpc64-linux/libexec/gcc/powerpc64-linux/4.6.3/lto-wrapper Target: powerpc64-linux Configured with: /home/tony/buildall/src/gcc/configure --target=powerpc64-linux --host=x86_64-linux-gnu --build=x86_64-linux-gnu --enable-targets=all --prefix=/opt/cross/gcc-4.6.3-nolibc/powerpc64-linux/ --enable-languages=c --with-newlib --without-headers --enable-sjlj-exceptions --with-system-libunwind --disable-nls --disable-threads --disable-shared --disable-libmudflap --disable-libssp --disable-libgomp --disable-decimal-float --enable-checking=release --with-mpfr=/home/tony/buildall/src/sys-x86_64 --with-gmp=/home/tony/buildall/src/sys-x86_64 --disable-bootstrap --disable-libquadmath Thread model: single gcc version 4.6.3 (GCC) GNU ld (GNU Binutils) 2.22 Supported emulations: elf64ppc elf32ppclinux elf32ppc elf32ppcsim k]