mknbi-1.4.4/0040755000175000001440000000000010110544106011310 5ustar kenusersmknbi-1.4.4/LOG0100644000175000001440000001714310110544015011656 0ustar kenusersSplit off from Etherboot as mknbi-1.1-0 on 2001-02-18 + Change Z5 unpack formats to a5 because Z introduced on in Perl 5.005. + Set dl to drvid just before calling boot block, in case some boot blocks expect this. + Updated comments in first32.c to reflect Etherboot-5.0 memory map. Released as mknbi-1.1-1 (development) Released as mknbi-1.2-0 (production) + A debugging statement left behind in disnbi.pl, tsk. + Support setup.S header version 0x0202 where parameter string pointer is 32-bit pointer. + Put mknbi version into vendor string so that it will be in image. + Derive version number of mknbi.pl and first32.c from VERSION in Makefile. + Replace 0x9000 by $relocseg, and add support for placement of Linux segments at 0x90000 and 0x80000 upwards. + Makefile now makes 2 more versions of first32{,pm,elf}.linux for placement at 0x92200 and 0x82200. Released as mknbi-1.2-1 (production) + Vendor magic string changed due to addition of version number, this caused the self consistency check to fail in first-*dos. + Use --oformat binary to cater for newest ld's. + Moved setup segment of mknbi-fdos to 0x93000. 0x97000 is used by Etherboot now. Released as mknbi-1.2-2 (production) + Added the --rdbase option to mknbi-linux, for specifying the memory location of the ramdisk. + Added some tips by Phil Davey on creating bootable MSDOS images. + Henk van de Kamer pointed out that 2.88 MB floppies actually have 80 tracks and 36 sectors instead of 160/18. It doesn't matter for network booting, but I changed it to reduce confusion. + Merged in changes by Peter Lister to support --rootmode=rw|ro. + Round down top of memory as returned by memory sizing routine to next lower 4kB boundary to make sure that ramdisk will be aligned properly. + Implement missing functionality per spec: appending additional kernel options from the vendor selection. RFC1533_VENDOR_SEL option holds value of tag that holds the options string. If the 7th argument exists, append it to kernel options after the global options, but before keyword=value substitutions. Released as mknbi-1.2-3 (production) + Hyun-Joon Cha discovered a trivial bug in 1.2-3. The kernel parameters are inserted twice, which may lead to overflow of the parameter space. + A new (s)printf which does not limit the length of the output is now used. Released as mknbi-1.2-4 (production) + Renamed do_printf to vsprintf because that's the standard function it has the same signature as. + Moved include of linux-asm-string.h into string.h in anticipation of using string.h for other standalone binaries. Added signatures for more string functions. Introduced stddef.h which contains minimal definitions to port hosted programs. Current target: lua. + Daniel Wagner sent in patches to the Makefile so that distinct intermediate files are used for the various first* images, otherwise there will be problems with parallel makes (-j). + Implemented --noharddisk option to disable hard disk access. No, make that --disableharddisk. In Perl Getopt --noharddisk is automatically the inverse of --harddisk. + first-linux.S had the right parenthesis in the wrong place for the initialisation of vmagic. + Print warning if zImage kernels are large enough to extend into Etherboot area. Released as mknbi-1.2-5 (production) + Implement --rdbase for mknbi-fdos and mknbi-dos to specify starting address of ramdisk (floppy image). + Make first.*dos depend on Makefile so that the version signature gets updated when the version is updated. + Print some friendly advice if --ip is not specified and there is no ramdisk argument (i.e. probably needs NFSroot). + Shuffle segments to make more space for parameters and first32. This version and future versions may not work with Etherboot images that have been compiled with BOOTP_DATA_AT_0x93Cxx. (There is some reprieve due to first32.c not using all 6kB of the allocated room yet, but that space may be used some day.) + Implement interception and decoding of the mem= kernel parameter to use as top of memory for the purpose of relocating the ramdisk. Released as mknbi-1.2-6 (production) + Add E820 BIOS memory sizing routines from Etherboot written by Eric Biederman. May help people with recent BIOSes. + Limit the top of ramdisk to 896MB for setup version 0x202 and earlier, or the greater of the setup variable ramdisk_max or 896MB for setup version 0x203 and later. If the user overrides it with mem=, then it's their responsibility. Released as mknbi-1.2-7 (production) + Add an EXTRAVERSION to Makefile, to be printed out by first32.c. + Modified call to int15h/e801 in start32.S to check for return values in CX, DX in case BIOS doesn't return them in AX, BX. + Ported internal menu program from Etherboot to be external menu program for mknbi-menu. + Updated URL for FreeDOS kernel sources. Released as mknbi-1.2-8 (production) + Robb Main contributed an enhanced menu implementation, mknbi-nfl. Released as mknbi-1.2-9 (production) + Add finalise_image hook in Elf.pm and Nbi.pm for later use. + Fixed start32.S to not rely on where it's called from, essential for booting from Etherboot 5.1+. For this we have to switch GDT like startmenu.S does. Released as mknbi-1.2-10 (production) + Patch from Doug Ambrisko to handle BSD. + Put in serial port console. + Forgot to include binary menu in RPM version, spotted by Masaru Kawashima. Also make symlinks to man page while at it. Released as mknbi-1.2-11 (production) + Changes by Eric Biederman for checksumming. Propagate parse_elf_boot_notes to other menu programs. + printf ignores width specification now. + mknbi-rom loads ROM image at 0x60000 now. + Make printf return value of sprintf, as per C99 spec. Released as mknbi-1.2-12 (production) + Relocated menu programs to 0x60000. + Rename some calls in startmenu.S for uniformity and hide some symbols that don't have to be global. + Downloadable Lua interpreter. Released as mknbi-1.4.0 (production) + Number segments in disnbi from 0 both in messages and in filenames. + Fix problem found by Eric in startmenu.S which affects segment override on 486s. + Add -I. to CFLAGS to make sure we get our includes instead of the system's. + In disnbi, call binmode on O not 0. + Quick and dirty Perl script to convert NBI Linux images to ELF. + Patches from Robb Main to handle larger "disks". + Added a --version option to display version. + Use lret to jump off to kernel instead of indirect jump through a data location. + Warn if in a .UTF-8 locale as this may affect binary string handling. Released as mknbi-1.4.1 (production) + Fixed bug in menu generator where ANSI escapes did not work. Was broken by introduction of LUA interpreter. Released as mknbi-1.4.2 (production) + first32.c can now be conditionally compiled as a DOS trampoline. Not tested, have to postpone to 1.4.4. + Add Quit Etherboot entry to nfl.c. + Add mkelf-img program. + Use perl instead of sed to substitute variables. If they have perl for execution they should have perl for building. + Fix a serious error in mkelf-linux where a reference to a memory location in Etherboot was used after moving the initrd up in memory. Released as mknbi-1.4.3 (production) + Improved spec file from Oron Peled. + Add memcmp to string.c and add string.o to list of objects to link, as recent gcc versions don't provide a builtin memcmp anymore. + Merge patches from Isac, and Michael Brown pertaining to padding of initrds and memdisk images. + Merge patch to menu-simple.c from Isac. + Merge corrected algorithm for calculating used sectors from Isac. + Don't print warning message for UTF-8 with Perl 5.8.3 onwards. Earlier versions of 5.8.x may be safe too, let me know. Released as mknbi-1.4.4 (production) mknbi-1.4.4/lua0100755000175000001440000021265407610401063012033 0ustar kenusers0؎Ў$@p pp@0ËD$D$L$T$ ыT$b Bb Jb Bb J Ív|%jSQRVWUL$ t$$-<t)\$s)σ)f󤾐Ps󤍅sh D+P,]_^ZY[\$sġfPfhs%<+%s؎Ў%+<PsD$' ؎Ў $"ˌȎЎ؎s.&s.fs "f]t&USVWh!h-<݋lptƅpDD_^[]SVWh"h v_^[SVWh+h`_^[SVWh3hJ1Ԉ_^[USVWUu h:h%_^[]USVWM1hAh_^[]USVWMhOh _^[]SVWh\h1_^[SVWhch_^[SVW1hjh_^[SVWh{h _^[SVWhh j_^[USVWfuf] fM fUhh>%ff f f_^[]SVWhh_^[ËL$T$QYai qyAËT$D$JZbj rzuL$'U5`׮Y5`Z5`跴X5`CÐUÐU5d5`YX5h5`bXZh5`x#ÉUh5`JdXZh5`hUVS5`Y^u 5`UXZS5` t1t e[^ÍvQEPEhj׍vSEPhEސU Uh@jE@ÐU h@hhrUS ]j=SFYZ@P5`< XZS5`R ]ÐUVS u5` 1ۃuGh5`C P$$5`QY[j5` e[^ÍvPS$$5`"YX45`XZj5`C utUjuL$8ÐUSP}]~ E @8-tC]Ívxsu P&~CPEPhjE.$$U ju5` jh5`XZh5` ÐUWVS E8te[^_ÉǍX x9sBK 4C09Ew˃ t ]9r뽐Pj h QuCtuԋU ˋUU juEPEÐUVSEPE Pu8$dL`M$=t'QEPhEje[1^Ív hZ5`pehÍP7 PP5`S5`TX5`Lt9twPEPEhWPEPhEAPEPhE+UU ҋExR@DÍvRUE MxQ@D;!‰Ív@USPU ] BAB;KAt A ]ÃjS UEP+ȉȍBÉUE+PȉȍBÉUE MxRPqQYË@D UVSuu V 9sAQABA 9ىBrCe[^ÐUVS]u S9ÉƉvvAQBAB9AwCFCFe[^ÐUVSuu V&PS@C;Ft e[^ÃjVUu utÐUU xtÐUu ut 1҃8tÐ@fx tv1US u ut+1ۃ8t Pat1]Ív1Uu u+ÉUu ut EVvÐUWVS]uu SYXVSttE }e[^_'e[^1_ÉUVS]u SXZuStt3PVSge[^Ív1US u u^t8t P`uC]UVSu uV t#8tPV`u Ce[^1UVSu uVt#8tPV`u C@e[^1Uu ut8t1Ív@fx tUu ugtu @@É1Uu u;1҅tt t1҉ËPUSS];Ct ]ÃjSZ䐉USP]E UQA;Ct ]ÃjSUVSuPuu VQIC;Ft e[^ÃjVUVS] ۋut! Sp PSVe[^Íve[^ U/`UWVS }Guv~;~L~PWhV%PWu VIC;Ft e[^_ÃjVUVSuu VIZYPVaPS@;^Ct  e[^ÃjVUWVS E }x5@GD7PW_VP^S@C7e[^_Ð@7͉UE VSMx5@AD1R^SpQJVPS@Ce[^Ív@1͉UE VSuxY@FD E$pIPS@C;^tC e[^ÉjV@멉USQ]CDB;Ct ]ÃjSr䐉UE VSut`x;FT}^PD tt 1e[^Ë D BD B;Vt B ӃjVӉUVSujVKC;Ft e[^ÃjVUVS]3u SnGZYPS `3e[^ÐUE VSux!@FDSZSPV1^e[^Í@UE VSux=@FLPBPqVOLQYSPSPe[^Ð@ ʼnUSQE ]x5@CDRupS.MJRQPQP ]Ð@ˉUE RPDÐUWVS }7~GXtPE_PD GXUFNADAD1} DD FEe[^_ÉShhjjwTwPWiWTUBGPG`WT 7닍vE뭐UU ER)у M UE@\ ÉUE@` ÉUE =?U~B\U B\UVSu ]VS/NP@t,tV4hS e[^ÉBpB0UVS] ۋuxڋFXNPD ^X[^ÐUVSuu V8XZjV, PsVFtRCASBABA ACA;^CtC e[^ÐjVa ܉. 1ݐUVS]u SpXZhS DY[PVwE8t[NIt:t+Iu}fE fEm]mEe[^Éz tBEu뿉@뽐UWVS];u WV4v)S $_;]e[^_UVSE Q]juPSzBƋp;Ct Fe[^ÃjS1 ߐUU MtBABAËBAUE1҅t8tÍv@fx uUUM BdJdÐUUM BhJhÐUWVESXU)ڃ ȉȍBҋ} xR v<t Jy1[^_ÅtO吉U E0u Pƒ1t EP\UUtt1ÉB@BUW}VSutx} trU1ۅtExU;U ~KNx?;U KҍFx;U ƉEtE[^_ÐK)Ћ׉K֋C)֋룸אUE@Ht+BHÐUVS uV#u e[^ÉFX,jjPVY^PSӉUS]St C]Ð1UWVSE X\S}ƃ1t3 S8 PWVƃ1tPu(e[^_ÉUWVSE p\V}`Ã/ 1tD V PuS`t/8(t*E @BDBD؍e[^_É1UM A@UBAEp\t0ƒS"$$PVuuCuЅuE( e[^_ÃVE0jU;Bt U뻃jRpU V/UB됍vu1UB uQRVumPEPVuwЉ1i VUB9U2C UUJSM]tE HJAu[ÐUWVSE1fx"u xH tA9}%ƒ?C0$9|܋Ee[^_ÉtRPvSPO븺݉PQ)%)CAo9}9CӉLIF?@)%롉UWVSu Vju$1҅u e[^_ËC 8)SVEȉȃ BPuWbƒ? tV w, t1PuBPW> UyvtuGUQGU6UWVSE}Eu jW$u e[^1_ËC 0S t܋FЃ?wɋEERD E }e[^_UWVSEP] SuV}gƒҋt!PuRWh`V] e[^_ÉPWhVCUSU ;E]MtMU ]$v 琉UVSM AAB8CutRShVe[^ÐPSh搐UWVS} 4P]jS TCs`S{ Ce[^_ÐUVS]s+ȉȍB;E W+SȉȍBS J9~E [^"CE t][^[^UVS]s)ȉȋK BQ9} IDC[^UWVS }+U ȉȋuB)Å~0SWKtK ue[^_ÍvU UWVS u} )ȉȍLB]t#IvB BBIBB uE;Ft C e[^_ÃjV>ᐉUWVS]3{sjSClXZu SUCl3{e[^_UhUBluÉE QEEuEEPRE։UhMAlU uÍvEUEB@PuEPQKՉUWVSuF} _EEFCPVO~ BBABA Ku VËEFe[[^)_UWVSEu@)ËU} USV#{EE] ue[^_UWVS}t9 V?MQH\8\Vu^^Eȉ]ȉFE@dEthPVuf{ PV RSuUËEăthuVuI~1M9s(CFOC Fu~ 9s F EِU2~ vM;At O M u e[^_ÃjQyUˋE9s"CFCF uN 9ӉMrE0PN QSuMR RhVQU E p0uBUVSE u@)‹EEEPh%ZV]te[^ÐUSSE Hɋ]t0SF jPSWI]É0SUVSE EE]Ec\s`9s8PEPh,&SuC`)C\e[^Éu S s`뷐U1ÐUS u ]St]ÐPjjSUVS Eu t/PuVS [ 1>PSue[^ÉʐUSPuuu ]St]ÐPjjSMUSP] SS PSu]US h]S88t]Ë @AB;KAt'A u S jPS뻃jS ljUSPE ]t PSo]E ]UMAU tP jPRvthQ! jUWVSXE@UEE@lUUEBEԍEBPEu&uuU EԋUBE؍e[^_ÍvEUPlUP UP3ǐUWVS} 44V]jS S$PfxC$s`@e[^_ÐUSjD]jSP S P(@@@ @@@@f@ f@"f@$f@&@,@0@4@8@<@@C ]ÐUS]SK QC4SS@C0D$ÐUSU EBR]C`]ÐUVS] Sҋu~ S)F`PjsVG js8V9 jsV+ j3V jsV js,V jSVe[^ÐUS] CM@Q`)ƒQ`jSQ]UWVSSE1ɋx49] u})@89pE1҉;t}KtA 9} E9t~1Y[^_ËUVSuf~&ukF@PfF&u@1ۋV 9}Nxu @V C9|1;^|11ۋN49}V8xu @N4C 9|e[^Ív F4Cm;^|붐UWVS u^;} r e[^_ÉSW ;rUWVS }1WT9}1ېGP| tF9|e[^_ÉPu WT؉UVE SX9Ëut e[^Ívf{ t FC^ 3搉UWVS }EWL19*]GHtPu WLF@9~E}~Ǎe[^_ÐUSU Mw$BHu @v$ÍvBX9uCBBE M$BUWVS$]CDE@EPSE_XEPSBY^EPSnv]uout`1F;~E}E];t%{ t+SEPXZC PEPGE;~|롃SV.ƍe[^_ËC1f{EwsVEPGC 9|SUUtt ÍvB@tuB9@ۋB9@UWVS UBT~1ÐEpP~ tKue[^_à V{uF ِUVSuV ҍ^ tfz&tZ(fB&ue[^ÍvB(RVUVSuV$ҍ^$t9RtZRue[^ËBRVAUVSuV(ҍ^(t9RtZRue[^ËBRV.UM ҉x+9As PPQu&BАUWVS ]EK,9M} }4UC44tBt9u5H~)r uK,E9M|΍C,E ]e[^_UB΋B C`+BC`K0PjRS뮐UWVS E uEEF89E}@V@U萋MU<t"Ct9Eu2{ CuF8E9E|ǍF8E u [^_C NHDPS]SVSY^PSX$$ 1}h*PS$e[^UWVS$u؋]VS{,tPjVSJe[^_QjVSJ$jXZVSyG{,tŐUWVS ]sF+E xC{{f(t+h9SBf~hWjVMe[^_à C(SE{)t S%uj(j)S밍v=usS$됍v S낐UWVS u} F:uP Vw4$ jWVI Sjv7MXZjVGG먃:~`{tH{<[u/ V jWV'I4$!Y[j]V븍e[^_=uPjWVH[Xj|(t.uԃ V jWVH4$ZYPVC[UVS]u j%Sft; SZYPSyFFu ]e[^PVPSKZYPSNUSS]C[tD=t)hUS@XZj=S]] S/ZYPS:Bу S$YXj]SY봐UWVS]{Sw{,t!PљRjW[Ke[^_Ð ScC;t˃}tƃ SF%љt {,t롉PjjWKUWVSuFVEE%~,t$E>әRPjuJEe[^_à VF;tȃ}tà VEEh>hPV N t~,tj>GPjuhJ㐉UVS]C[u tY[4;t S"Fe[^ÍvCF}t=uŃ SO{=u S?FUWVS ]S(CjjPU؉EIXZj{SZY^EPSFXZj;Suu>uj{j}Sh@hVSLU܋P? e[^_ÉEPSE 9EhlPSuUWVS }G=u _=(tc(/%tE }e[^_=u }e[^_6{uу WFFe[^_à WY[VWE )}e[^_=t="= ajS?<$<놉=t=8wWG ]W uuS>A W w(jWM $UVS]uSV jSVCe[^UU1-t 1 @ÐUU^t*^K-t-*t 1+tÃ<t< /޸ >Ԑt́/  t  뜸돁 t xaUWVS(}w W ju W u SW D^wtb;E~U WO u VWrD 6PEPWlÍEPu VWD t ;Ee[^_Ãu WpU ju uÐUE=t=-w Ív1=u鐉UWVSu^{V YXC)PS<XCZ)PVe[^_ÐUWVSh`h}uWVH1ۃ~,tYj=V4$f PWVE 8tPV=e[^_ÐjDPjvD܉ VXZ]SV/ 1}hPVw GPSVA놐UVS] uSV jSv@e[^ÉUWVS8u^S?:XZEPS4$=YXEPVXZhV4$ WPS9Y_PS>$9 PuS>u hhVEPSoe[^_ÐUWVS8]sV9XZEPV$$u hhSE؃PS WuVx=Y[EPVe[^_UWVSE uEE^EjuSCE$9XZhVYXuV4$i W juSBPS<$8 PuS<EE ue[^_UVS]sj=SF$YXj,S4$XZj,SjtK S ju S jhS jhSj-j,jSe[^ÐQjjVB뱐UWVSj,]S$ h1{tWVS$$ jhSX ju Sr jWSfj/j.jSJe[^_Éhs 9CZYu뎐UWVS$]}؋sWV$W$kS,tH=t7hS5u hhS/[XWVe[^_ÉPSF˃PSUVS] u SYXVS?XZhSj]e[^UWVS4u}؋^WVEF==t>PuEPS:$R6 PuSi:u h hVZe[^_à S55 PEPS:$ 6 PuS":4$ 4$j뒃 S4 PEPSy:$5 PuS9XZWVF=t6UVS1] S VQSYZPSKF{,tكj=Sfu1RPVS YXVSke[^à SىUWVSu V]PSMZYPSPC1:t.t e[^_Ã: S jVS;$:ZYPSE5뼉UVS]SY^uVSk u PSXZVS}7e[^ÉUWVS$]}؋sWS}tQjWS_ZPV5e[^_PhWV5ZYPS[_jV6ӉUVSu ^V vA u~;t VGPF@PjS=fCfCe[^UWVS }_s(CEtE WYE_+FPS5$2 PFPS8XFZ+EPS4e[^_ÃhW02먐UVS]C= s(= =tk=>%t.=thS11e[^à S* S^=t=uVSƒVST붃 S$!VhhS뒉=t_=2= t=bVSa SSv=t=W+VS* S.VSr UWVS ]C11)t<=tY=tBh S0uj,StCƉPVWSe[^_Ív SPWPSZYPSGQ말UWVS]WSupt e[^vvh]SiZYSuUF1UWVS } _C+BNJ,uC CCCPs VQ<;C t&MES uRWQ se[^_É;s~UWVS] }SW.ƍ[K)ƒt`[эvDDDDKD uq;OtA e[^_ÃjWbߋːUuu[U f@ ÉUuu;U f@ ÉUWVS } ?u WsVHt_jVذPP HQPQPWPWPY@ PjRVٳ e[^_ShWVW1vOYtVHVP PQV8tFH\AUWVS ] ;u} S|VHDEtxjVݯBBJABAB B GBGBCBCBEA@P$EU ue[^_麲E] ue[^_7vKQtFHD2PWQVjJRQPQPe[^_ÐUWVSu uvDIÉ$kVH| tNjVͮxU PB BCBCB B$jRVױ e[^_ÉUWVS$u uvD$VH|trjVCPPHQPQP P SPSPU P x@ P$jRV2e[^_ÍvtP@BCBCՋE EPEPvDVEJRQPQP럐UWVSu FP}MQH8ۉ1t1M4uxjjSu+e[^_É FPMQH8uE1uUVSPu] SuVVte[^hjCPVUWVS EU X@ErzVSuu& SyvwŃ>XGFE말UWVS vuExEtVuu"]U ztoSupt\Pj uut2E +E@UE RU)‰Ѓ } Eve[^_hjVu빋CP~F׋UxR])ÐE 9E}*{CtPuuCxE ΃wxWu1U1҉EU~7Ru)ƋFXPSFPEP2sMM߃ ԋURRWu]u)MC+hu9pUWVSjuM UE1; s?1vRXSuuM 9T9PT9P U ;2rȃ P$\$hu5 PuuE MUP ;AtU e[^_ÃjQ MېUWVS }u )ȉȋ]B9x[E }e[^_QSVWwىUWVSdE EЋUЋM@RIhMȉEԉŰEPEԉBUB$PuXMЃfy" PA Puu6M1Eԋ}ȋEtuVuu؃?0w$E0e[^_[MU2%1=J ЋU2V PM[PRE0k؋U2@QMjPR蹪[UsH [)P$^ MFUTFVNjMT؁U [P@BFBF[MTVD݋EU04PiPV@F M1 ~WQ4VPW@GUFMF [MTVDFUF ~WR똋FE؍VBE܋BEMF E^0SPVPS@CE؉FE܍~GEGU 2RӷXZSu%F [MFDFDEU04P r@)‹M1PB PRQ[)<)Eč[)‹Mۋz{UPPW uVPVKPuL[)Uۋy /PVWuV VPVKPu~^t S&uBN~Mt& QtQjVuE@C[~׍V~Ut RuMAP$YjP$^jF Pu~~^t Sbu4F~Et PDtRj7UBkE~~^t Su4N~Mt QtPjE@K~~^t Su4V~Ut RtPjMA{~Pj Vut /hu觩PVSu[)؍p E0$~z~^t Su s Pj k1~@FFF?F PV@EElF PVQ΃FPF PVu݃FPVF Pu 뗃FPVF P҃FPF PVڃ >먃 >m~~)a~~TE V~Ut RN~Mt Quo~~t WuAE@EtUGBE@UGB߃hu蠧몃h0u苧yhMusEV܃~UthiuO~GMAQGEuFEu؋UBFރ~~thuPhwueFAVBABA FA~GAGWV܍~WUrut+FAGAGA FAVBABDuM1V%PUЋB 4QM1 $PUB PuutiUÉUM 1ɋUtEEBJBDB ÐUSP] 1tuSh PSu]UUJJBUM 1ɋUtBBEBBJ ÐUWVS u}t+t29Ɖ~RSwu f)_] )u1ҍe[^_É WW@t@O뵐U Epu P#ÐUEP;P~@DÍv1USj]j*S ;CEt]PsEPS^CEސUWVS }UM @tM)΃ FP g=? ‰e[^_Ðhw Ѝv? щUUE RDBJ ÉUSS]CS9tCQRsSCC]ÉUSP]fCE fCf;B$~f=fCfB$]Éh shڐU u jEpf UWVS uK1QH!IE 9]|;EE@t2I9}Phhjjs3v KQESȍe[^_USE H]u,}fE fEmUmUR$E@t( $S0EE ]]{v؉UE UE U~QPjRNÐQPjUu.ƒ?t1ÐuUVS ]u Su e[^ÉK@ A%? ЉAu ]e[^USS] EtRr=t%1tCC]Ãj PPҍvRsj PTQsj UVS] uSV{t e[^Ív{uE ue[^UEU Ht.rtjjjQPrjQPrjUU 1 w $`!ø %$#"۸'Ը&͐UWVS U] @EtDSuEE<7?;utBPuSu}(t!)t]ue[^_Ë'&PuSu;ƉUUE;BM t jjPQRI ÍBME IUU VSu]t)@?9uRSFu1ɍe[^ÐUWVS U u}t,SV t}] ue[^_m:e[^_ÐUWVS Mɋ}E PUPPWUwN@у?A wVEu3PVuWL<$ PU2WEe[^_à QU EERjuWPPUPaU1}D'Pju uÐU1}D&Pju uÐUWVS]} uSu} ]e[^_UWVS$EE} EpWVV@D?X v  EEEv Pj)wV PFHPGPV jj+V. EjjVE4$ PuV& V$j)uwVsSj(uwVaGG e[^_Pjj*VE[XjV0dPj(wVt3EtE ue[^_LUWVS M EɋuXtcVSS@f90EE} G  SF>덋EK$DPЋEҍB~YA@AE} RMuE9EtGPhhkS9FGUF QQƒ룃atbTGPGDrt@rn'G #ttv G G G G QQƒPW蔘 QQƒlhWm.UWVS u} @e$N$B҉~A@Aу QQƒve[^_à VyPj$hVPW6VNjN$B҉~OA@A--uN$B҉~A@A ;Bu3 QQƒ߃ QQÃ뭋N$B҉A@A.t- RTK. PWjV: N$B҉~MA@A.t N$B҉~A@A QQƒ QQƒ믃 QQƒRSWjmN$B҉~LA@A=<aN$B҉~A@A= QQƒ QQÃ밋N$B҉~LA@A==N$B҉~A@A QQƒ QQÃ밋N$B҉~LA@A=>N$B҉~A@Am QQƒ QQÃ밋N$B҉~)A@A[[)WVL QQÃӃ VwZYPv ‹@~  6Hu SHu/N$B҉~A@A QQƒSVvN$B҉~LA@A=~HN$B҉~A@A$ QQƒ QQÃUjjuf0Phh71UVSjujV/XZhVnY[jVmjt e[1^ÃhVnXZjVi] SjVyvu*hVmXZjVt jjVrPShVgzMtE~PEPh(S6XZSVmY[jVtUWVSuVVh_EXhVn;}~ e[^1_ÍvjV!iY[WVi jjVrXZjV1kt#Sh6Y[jVG h;}~뜃h@ VʉUWVS h$@jj}W/}fE fEm]m] PjjW}.ƍC"wkPSEPVHËE9t$ PXFt E@EE8t Woke[^_P1RS,$$WkPhjW,낃jW-XZjWhtjWi 볉USjj]jS.PSȄ1]ÐUS j]SR-QjjS-PSn1]ÉUSj]jSX-PSl]US ]jS,XZjSXh P$$Sj]ÐUSj]jS|,YXjSfXZjS-}YXfE fEm]mEPS&p]US]S P$$S j]ÐUS]jS*-}fE fEm]m EPjS-}XfE fEm]mZEPS P$$Si]ÉUS]S lXZjS:f@t PjjSi+YXjSe$n]ÉUSj]jS4+XZjSj+YXjSj]ÉUSj]jS+YXjS6+XZjS,+YXjSl]UWVS]jS+} jfE jfEm]mS}+XZjSRet"jS?eHtPhjS{)h0VCt+QVWS.XZjSd VWS蝽e[^_Ãh S趁UWVSujV0+} jfE jfEm]mV}R*h0PVC tQSWV螼e[^_Ðh V:֐US]S0m P$$Seg$m P$$SJg]US$jj]jS*}fE fEm]mEPSl1]US ]jS>)XZjScZYPScZYPSZg]USj]jS(XZjSVbYXjSmtЋ]Ð SOfUVS] ۋuu- Va+E~e[^PjjVg球 VfYX4 VfǐUWVSuVaǃ EPjV(8t3PWjSjV(PuSV~PVOe[^_Ívh V^뺐UVS ]SajjjSi(VPS}ZYPSe[^ÉUWVS jhujV1( jjVEEN'Y[jV4lXZjVa@t3hVTf4$`Y[jVEaXZhVh Vf`Y[jVEYa hWV&19PjWV |ËEurt;jxu@t VRde[^_ÃjV~㐃jpu?th@ V} V_+E뷃uV`_XhVgmRXSjV?f9|$u뗉UWVSj]jS% jjS%Y^jSi9Ɖ~ 1ҍe[^_ÐjSA_ V$$Sb VjSd jjShXZjS[_HujSF ^9~뒐USj]jSd$ jjSW$$ bvYXjSh1҅tNjS^XZjS^YXjS^ jjSgXZjS^Hu jS]량Ћ]US ]jS$XZjS^Ht 1]ÍvjhjSr$PhS%ЉUSj]jS|#YXjSbh P$$SOa]ÐUWVS(}W\ jjWE2#Y[jWh}jW>$}fE fEm]mshW\a V$$W`XZjWd;]|'vPSjWb VjWKe;]|s܃uW\ ujWde[^1_Í@ƉEuUWVSj}jWN"Y[jW4gEE$jW#}fE fEUm]m 1ҋu~\PVjW)b;u|UhWc`E HP$$W_^XjWc<$~_ ujWde[^_ÍvP^SjWa VjWc;]|놐UVS]uPu jScuE ]e[^cUWVS]u }jS[HtXjS[YXFPS[XZGPSu[ jjSpd^_jS[ZYHjSyZe[^_Ív}u ]e[^_\UWVS E9E }|e[^_Pu jW` ujW` jjW-Puu WE+E HtE E4PVjW_` u jWQ` jjWuPu VWE+E PQVjW`XZjWPZE HPjWE_ uVWDu ] FVjW_ jjWVt';ujW#Y͐h` WwߐPKSjW_ jjWt(;] |jWX̃h` Wv9|PSVW_jWX ujW&_ VjW_ VuWiE+U )9}'N] FE PVSW E9E  ^CuEՍvjW-X ujW^ jjW.t SuYjWWPjWWUVSPj]jS1Y^jScXZjSX@tPjjS jSW VjS8e[1^ÐUS ]jSrZ Ph S1]UWVS u1ۿ 4V\ jhVA\XZ4VC_~Ѝe[^_ÐUS]j!h S1XZh S[YXh* S^]]tUVS]uu S[XZVS[E ]e[^^UVS]uu SY[ V$$SZE ]e[^~^UWVSjh( ujVb_XjVWqQ}WjVXٽfXff fd٭d۝`٭fZ`PV?cRWSVWg Vg]tWS"wC$Puh. VEu7Puh5 V uhA VCue[^_PEPhF Vf봃hP VYXZjVUY_jV7]PuhU VfQuha V uhf zWuho Pht jV4 VX[jVUtQh jV}jVGU Sh hS2"UVStuV]jS}XfE fEm]mZEPSathjS}fE fEm]m EPVSbt"PSXXZjSTe[^É SWQh jS념UVStuV]jS}XfE fEm]mZEPS`tPjSjS}fE fEm]m EPVSrbPSWe[^Qh jSv띐UVSu] jV"Z jSVWXZjVXY[jVSt&jVRE ue[^RvjVaS jjV\\ˉUS E ]0SCW]E ]UUSE ]@$SV]E ]%UWVSE ]E}ujSRXZjSSHjSStiPh jS?_XjSX juSVY^jS}RXZjSW_XjSiRY^jS_RE ]e[^_YWS뜍vjUhhhuUh(hhuU jhu;ÐUSEP]jSXE$S-U]ÐUUxÉE TUWVSEPujVtjV}fE YfE[m]muEPhjjV?}XfE fEZm]muEPc ۉ~BE9~9%)QBPD;PVTe[^_ÍvhVTݻ뷐UWVS0 P]jS^XPS1;}1U9sC@ >P.F;|σ R|e[^_Ív P룉UWVS0 P]jSXZPS1;}1U9sC@ >P-.F;|σ Re[^_Ív P룉UWVS0 PjuKXZjuٽ_f fXW٭۝٭uN~QSWN We[^_ÉUWVSEPjuVh?jjV}XfE fEZm]muEP ~;E~PhjVQfD;P$$VQe[^_UWVS8 }WM[^PW;rVWٽf f٭۝٭Ã9tQhVWAU9s-F;~ Re[^_à P빉USP] 1Ex;X}| t؋]Ðhu@j㐉UU BHx | tHyhuj1ÉUVS] C%utT[t ؍e[^É<^t7tC<%t <]uCۊtCvhViCƉ;u΃h ViUVS u V]*a$ S)à V)ue[^É S)̓ S)ƒ S)뷃 S)묃 S)롃 S)떃 S)닃 S)9듅tUWVS ] E{^}utoC9s<%tJ{-t$9UtC9r1҃}e[^_ÉS9sB99NjU~ɍvCPWUuECUVSM Ѓ.]utH.'%t9[^AE ][^][uٍFEM ][^ vƐUWVS uҋ] t~uhug 18te[^_ɋEMC9~sCP9t;Ut C@9r1ŐFNu뻐UWVS }1E vËE;sPWuPtFCGx"vuWSu{u NxE 1e[^_ÐUWVS E] }pvWVSu9u ;sPuuPntC1e[^_ÉUWVS u^} 9CFE|D @VPWut e[^_ÐNvh%u f벐UWVSuVu] lj+DD EV@PSum t e[^_ÉD UWVSuVuu} 9\ ‹)9| PSWt'u ;e[^_É1UWVS EEE} ]E)w?$EEE]} Ee[^_e[^_É{SuƋE;8E++~c-tH?u.]u^lu^SGPu>uMU1sG8 uVSWuU*uЃ uVSWu):Mu1, uVSGPPVSP>E2E;8H! CP$u1{buCPWu"ǃ1nuCPWuǃ1FvEEE]} Ee[^_jUWVS ]}ۋu tX19uQME@+uE~HURVPW$ÉEt-QuuCS$t ))Ɖ‹Eve[^_1UWVSh%} wu 1G9}"\ t#PStuYIFG9|ލe[^_Éh7ubȐUWVS@PjuW Pju= h?jju: ٽXf fZ٭۝٭PFà Kx;~Vhjuf  uChJWj$?^DžPWSuDžu-C;s tǃ upGe[^_+QCP$$u{G +V$$u`GXZPuGDž:W)PPF`S+CP$$uF S$$uF-UWVSEUE] UjP@DjuDEXZjuzE19ƉE} >%t4 9s F;u|e[^_É Sk  >ِF >Pj u# 9s>벃 S/ Pu>Pu+ Ut tS3 wvjuGB_Xuub jPu4KY^ju4Ct]e[^_ EE Ee[^_AUWVSP!P}jW jjW@P$$jWٽf f٭۝٭ 8^Dž WDžM@NjWJB!PW; 9}gPVWDžPPPWj9v_ދu9|S)PVPR $ Yۅ$WCe[^_Ív9s9sFy PԃjWO@PhUjW@DžgUWVSEPuu] ƍ 9"EHE@t6ƒ"tb" tL9s2EHFE@uˋ9s "e[^_à S S뼉9s&\@9s 뢉 S SPjhqSl\V SWUWVSp#jjuDž[_ƍPut%%tWE䋕9s. Fuݍ P~e[^_Ð PF%tƅ% Pt ~$  V_D0PhvWuDžW)~h`uZ)QCPWPƄ+EF3 $uٽf f٭۝٭ PPS  Sh PSPrunXZ$WPuSPuu cReuL<$rhuTY9uٽf f٭߽٭ 0~U j huÐUWVS u 1ۅҋ}tW4t Cue[^_UVSd]SujVG ShVKMuE uuu h Ve[^ÐUWVST} uWVB;ZYPV];PSuVO; P]hS SWV^e[^_ÉUWVSu] }Vp99 e[^_Ð}E ue[^_UWVSu ]}VW:9t]u }e[^_3ve[^_UVS] SuVk:@t e[^ÉPh SVUWVSu V}W<t#EtVW<t?‹BfftȋA9b=‹Bf뿍B؃w4pXI:)UWSp]$h[pjtЁ P%fvBf;Jfvtt 8t B:uA9u)[^ÐUU:t@8u)ÐUUSM] t tCAJuE[UMS9] t;t 8tB:uA9u1[ÉUExUj juÐUjuu uÐUjuu uÐUWVS ]u]PZtCE+-u ;0~F1"wc1EUB< v@ J9}5C;}]w;}u:Mw <뿊E E"몃} tEU 1}}t9v "}t؍e[^_ñ(yC]  expectedlocal variablesupvaluescannot access upvalue in mainparametersarg expectedfunction arguments expected or `[' expectedinvalid constructor syntax expectedsyntax error(limit)(step)`in' expected(table)in`=' or `,' expectedno loop to break expected or `...' expectedself`%.20s' expected (to close `%.20s' at line %d)cannot access a variable in outer scopeupvalue must be global or local to immediately outer scope`item groups' in a list initializerelements in a table constructorvariables in a multiple assignment error: %s _ERRORMESSAGE`ZTZ"ZXZ`Z`Ztable index is nilinvalid key for `next'table overflowgettablesettableindexgetglobalsetglobaladdsubmuldivpowunmltconcatgcfunctionlegtgeevent `%.50s' is deprecatedtag table overflow%d is not a valid tag with default tag !+59=AEIMPWZcfi`%.50s' is not a valid event nameevent `gc' for tables is deprecatedtag %d was not created by `newtag'cannot change `%.20s' tag method for type `%.20s'%.20stag method must be a function (or nil)unexpected end of file in `%.99s'virtual machine mismatch in `%.99s': %.20s is %d but read %d`%.99s' too new: read version %d.%d; expected at most %d.%d`%.99s' too old: read version %d.%d; expected at least %d.%dunknown number format in `%.99s': read %d; expected %d`%.99s' apparently contains more than one chunkbad code in `%.99s'Luabad signature in `%.99s'sizeof(int)sizeof(size_t)sizeof(Instruction)SIZE_INSTRUCTIONSIZE_OPSIZE_Bsizeof(Number)%dindexperform arithmetic onconcatstring size overflownundefined operation`for' limit must be a number`for' step must be a number`for' index must be a number`for' table must be a table`for' initial value must be a numberxx yIy}yyyyyyz6zTzzzzz_{{{{|h||}t}}~j~~~~He{3р:control structure too longconstant table overflowline info overflowcode size overflowfunction or expression too complexAׇއ !"#$%؎؎؎Џ؎؎؎؎؎؎؎9؎؎؎؎؎؎bl~؎؎؎؎͐؎&9؎؎؎؎QQ؎؎؎؎؎؎Ўdddddddandbreakdoelseelseifendforfunctioniflocalnilnotorrepeatreturnthenuntilwhile.....==>=<=~=too many %.50s (limit=%d)0x%02Xinvalid control charlines in a chunkmalformed numberunfinished long stringunfinished stringescape sequence too largesw}ԟԟԟԟԟԟԟԟԟvԟԟvԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟvԟМԟԟԟМԟԟԟԟԟLԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟWԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟԟ8%.99s; last token read: `%.30s' at line %d in %.80sambiguous syntax (decimal point x string concatenation)unexpected `$' (pragmas are no longer supported)%s_ALERTerror: Sl <%.70s: line %d>tostringbase out of rangefunction or nil expectedgcokrun-time errorfile errorsyntax errormemory errorerror in error handling_ERRORMESSAGEtoo many argumentsuserdata(%d): %pniltable: %pfunction: %pvalue expectedassertion failed! %.90snforeachvarnextvarrawgetglobalrawsetglobalcallcollectgarbagecopytagmethodsdofiledostringerrorforeachforeachigcinfogetglobalgettagmethodglobalsnewtagnextprintrawgetrawsetrawgettablerawsettablesetglobalsettagsettagmethodtagtonumbertypeassertgetnsorttinserttremoveLua 4.0.1_VERSION`tostring' must return a string to `print'deprecated use: cannot set the `gc' tag method from Luadeprecated use: cannot get the `gc' tag method from Lua`dostring' cannot run pre-compiled codedeprecated option `p' in `call'invalid order function for sortingfunction `%.20s' is deprecated36EP]j$4L( ȧ X Ġ'  , P; J Q pZ T` (h |q x     d ȧ  X  X  |  ȥ ԣ P    \ L <flnSusourcelinedefinedwhatshort_srcfunccurrentlinenamenamewhatnupsinvalid optionfunction or level expected>%.10slevel out of rangefunction expectedgetlocalgetinfosetcallhooksetlinehooksetlocal3Dc     out of rangeinvalid valueinvalid capture indexinvalid pattern captureunbalanced patterntoo many capturesunfinished capture^$*+?.([%-string or function expected\000[-+ #0]*(%d*)%.?(%d*)invalid option in `format'strlenstrsubstrlowerstrupperstrcharstrrepasciistrbyteformatstrfindgsubmalformed pattern (missing `]')malformed pattern (ends with `%')invalid format (width or precision too long)޾hhhhhhhh&hhh1hh<hGhR]hl&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&,&&QQQQQi@`TTh n?%.8s expected, got %.8sstack overflow (%.30s)value expectedbad argument #%d to `%.50s' (%.100s)%d.0123456789ABCDEFkJcheckkeyclsgetkeygetshiftgetxygotoxyischarnocursorsetattribcurrticksansiswitchh8`$@Lmknbi-1.4.4/nfl0100755000175000001440000001723010110544101012010 0ustar kenusers0؎Ў$@p pp@0ËD$D$L$T$ ыT$b Bb Jb Bb J Ív|%jSQRVWUL$ t$$-<t)\$s)σ)f󤾐Ps󤍅sh D+P,]_^ZY[\$sġfPfhs%<+%s؎Ў%+<PsD$' ؎Ў $"ˌȎЎ؎sȎ؉&s.fs "f]USVWhh-<݋lptƅpDD_^[]SVWhh v_^[SVWhh`_^[SVWhhJ1Ԉ_^[USVWUu hh%_^[]USVWM1h h_^[]USVWMhh _^[]SVWh'h1_^[SVWh.h_^[SVW1h5h_^[SVWhFh _^[SVWhQh j_^[USVWfuf] fM fUhZh>%ff f f_^[]SVWhah_^[ËL$T$QYai qyAËT$D$JZbj rzuL$'D$=KtE=K=GtS=G~_=Ht7V=OtC=O =Mt?=Pt=St,/(! %S1ɻ<w B<vt< tBt1At< ut< u Bc~[ËD$@PD$ @Phdm S\$ uj X\$[z UWVSSSƋD$ T$$͋T$1I9})ʉhmV:XKZuPt$[_<$tt$ D$o t$ D${ZY[^_] UWVS؉Ǎh9-v\$$ T T P 9=D$XD$tFD UhmD$P T DPh~\$`S^ USD$PT U4t$VoT Df R B9PUGD$$9} T T P 9&f=T t6D$jh\$Sf jAUB0tT DP 9}/tj/SZYtXt$\$ [^pt'Ãpt u UWVSD$8ufǍX x9sZBK 4C,09w< u1j hQ uCtt D$D$9rVffP uh#[_j^5x5|h jjaf!Yf9v[vfvf!Bf9tvft1f9s"PjXZhFf;5!]rPP^_h1f;5v[shFxf;5vYrPvDPXZh1@f;5tXseDPPj]XhD$vDP8[_hFf;5tYrtDPPXZh1f;5v]shFf;5v_rtDPvDPY[hM$jXZhf5t]ָfT fR  @u =uP\_t^usrf R tfv]AfR RfvLAfT f9fR u fvNAf)BfT ҸfR f)@mtvu}f R fP @9drt AfR Pf9sKAf9fR r#f9sfT F@f)BfT ҸfR f+T  R  jh4( t4t$ _[^[^_]UWVS|$l$T$D:9stVqXCv uCtj P])[^_]ÐST$1ɀ:\$ t9uB:u[S\$L$ ڊABu[S\$;L$ tB:uAt BAu[VSt$ >\$L$tB:uCtItBCtIu[^WVS\$19ڋ|$t$}: 28t )B9|1[^_ÐUWVS,D$@t$DD$>l$H<%t&|$@tT$BT$PYF0< w F0< v>.uF0< w F0< vM9y|$@Yt T$BT$ PZ;uJ<#|$ $u$F>hu F>huFЃ |$@tD$T$@)T$D$,[^_]ÍD$Pt$j ÍD$ Pt$ t$ ÐUWVS= t$(    9У @ )ы5  H !ƃ= Tf .f;!f !9fPCf  P jP<ۉu= Gu:=d t ==l tffj P]X = Hju%=d  l t  0Pf| B^f;!f| _=u f| uf| f~ Bf;!f~ uSf~ !D= TPt=d tl PY[~ | P PXZ[^_]á Gw5|$tjh YXffj PXZá9t5jP  vjx  ô0ù 00ô ˹fôôôtf1۴tô$߉É[%d;%dH %s%s%d. %c EtherbootERROR: No menu entries found Rebuild menu program with a menu configuration file. Press any key:[3%dm[4%dmNetwork Free-Loader v0.56Quit Etherboot0123456789ABCDEF%d.$qmknbi-1.4.4/menu-simple0100755000175000001440000001416410110270706013476 0ustar kenusers0؎Ў$@p pp=@0ËD$D$L$T$ ыT$b Bb Jb Bb J Ív|%jSQRVWUL$ t$$-<t)\$s)σ)f󤾐Ps󤍅sh D+P,]_^ZY[\$sġfPfhs%<+%s؎Ў%+<PsD$' ؎Ў $"ˌȎЎ؎sȎ؉&s.fs "f]USVWhh-<݋lptƅpDD_^[]SVWhh v_^[SVWhh`_^[SVWh"hJ1Ԉ_^[USVWUu h)h%_^[]USVWM1h0h_^[]USVWMh>h _^[]SVWhKh1_^[SVWhRh_^[SVW1hYh_^[SVWhjh _^[SVWhuh j_^[USVWfuf] fM fUh~h>%ff f f_^[]SVWhh_^[ËL$T$QYai qyAËT$D$JZbj rzuL$'=t2 t t At u9 uA@ 9uS\$ uj aX\$[VS\$j/SYXtB[ u UWVS|$l$T$D:9stVXC uCtj X)[^_]SQ9s6tjjD$ PT$ 0~D$ /901҉Z[UWVSPPl$}uj] }9s^BK 4C09$w= u1j hQ uCtt D$$D$ $9r|$$lWD$:EPEPhh9}4ShC 9|huXj hhV tuj1zj s^]8/uPWPt$1[^_]ÐST$1ɀ:\$ t9uB:u[S\$L$ ڊABu[S\$;L$ tB:uAt BAu[VSt$ >\$L$tB:uCtItBCtIu[^WVS\$19ڋ|$t$}: 28t )B9|1[^_ÐUWVS,D$@t$DD$>l$H<%t&|$@tT$BT$PYF0< w F0< v>.uF0< w F0< vM9y|$@Yt T$BT$ P>Z;uJ<#|$ $u$F>hu F>huFЃ |$@tD$T$@)T$D$,[^_]ÍD$Pt$j ÍD$ Pt$ t$ ÐUWVS=t$(X X\T9У\@ \)ы5X \H !ƃ=TfP.f;bf R`9fPCfPPwjP`<ۉuffNYf fL[v fNfbfJf`fN=fHjA PjP=Gu:=t =h=tf`fj P]X =Hju%=h t `0PfB^f;bf_=du fuffBf;`fuSfbD=TPt=th`PY[PPXZ[^_]áGw5|$tjh YXf`fj PXZáp9lt5jPlRj ô0ù 00ô ˹fôôôtf1۴tô$߉ÉEtherbootEtherboot menu system called from Etherboot %d.%d Available images: %d. %s Make a selection (timeout %d seconds => 1): 0123456789ABCDEF%d.H?     mknbi-1.4.4/TODO0100644000175000001440000000065707740726513012030 0ustar kenusersWhen Etherboot 5.0 in ROM loads a mknbi-rom made 5.2 image for the 3c509 NIC, this image executes but is not able to load a NFL menu. If the 3c509 is booted from 5.2 floppy it has no problems loading a NFL menu. If the NFL menu is replaced with a DOS image or a tomsrtbt image just before chaining, there is no problem either. So it seems that 5.2 Etherboot has problems loading NFL images when it's chained to from 5.0. Bizarre. mknbi-1.4.4/menuc.pl0100755000175000001440000000473307240254657013006 0ustar kenusers#!/usr/bin/perl -w # Program to compile a menu description into a binary file # Placed under GNU Public License by Ken Yap, January 2001 # This Perl program requires Parse::RecDescent # If you cannot install this module in the standard directory, then # install RecDescent.pm in a directory that you can in and # edit the line below to include this directory in the search path. # # BEGIN { # push(@INC, '/usr/local/lib/mknbi'); # } use strict; use Getopt::Long; use Socket; use Parse::RecDescent; use constant; use constant DEBUG => 0; use constant MAXINPUT => 102400; use vars qw($output $status $text $grammar $parser $result); $grammar = q( specs: spec(s?) eofile { $return = 1 } spec: global_option | menu | global_option: timeout timeout: 'timeout' number ';' number: 'number' menu: 'menu' name '{' menu_body '}' name: 'name' menu_body: 'title' strings ';' | menu_option | items strings: string(s) string: menu_option: timeout items: item(s) item: 'item' eofile: /^\Z/ ); $::RD_HINT = 1; GetOptions('output=s' => \$output); # If an output file is specified, redirect stdout to it if (defined($output)) { die "$output: $!\n" unless open(STDOUT, ">$output"); } binmode(STDOUT); # If an input file is specified, redirect stdin from it if ($#ARGV >= 0) { die "$ARGV[0]: $!\n" unless open(STDIN, "$ARGV[0]"); } print "Menuc doesn't work yet\n"; $parser = new Parse::RecDescent($grammar); # Read up to the maximum number of bytes allowed in a specification $status = read(STDIN, $text, MAXINPUT); die "read: $!\n" unless defined($status); $result = $parser->specs($text); unless (defined($result)) { print "Syntax error in specification\n"; } __END__ =head1 NAME menuc - compile a menu description into a binary file =head1 SYNOPSIS B [--output=I] [I] =head1 DESCRIPTION B compiles menu descriptions to data file suitable for interpretation by an Etherboot menu extension program. B<--output=>I Specify the output file, can be used with all variants. Stdout is the default. The package must be installed in the destination location before the executables can be run, because it looks for library files. =head1 BUGS Please report all bugs to the author. =head1 SEE ALSO Etherboot tutorial at C =head1 COPYRIGHT B is under the GNU Public License =head1 AUTHOR Ken Yap (C) =head1 DATE Version 0.9 January 2001 mknbi-1.4.4/menu0100755000175000001440000002234010110544101012173 0ustar kenusers0؎Ў$@p pp @0ËD$D$L$T$ ыT$b Bb Jb Bb J Ív|%jSQRVWUL$ t$$-<t)\$s)σ)f󤾐Ps󤍅sh D+P,]_^ZY[\$sġfPfhs%<+%s؎Ў%+<PsD$' ؎Ў $"ˌȎЎ؎sȎ؉&s.fs "f]USVWhp!h-<݋lptƅpDD_^[]SVWhq!h v_^[SVWhz!h`_^[SVWh!hJ1Ԉ_^[USVWUu h!h%_^[]USVWM1h!h_^[]USVWMh!h _^[]SVWh!h1_^[SVWh!h_^[SVW1h!h_^[SVWh!h _^[SVWh!h j_^[USVWfuf] fM fUh!h>%ff f f_^[]SVWh!h_^[ËL$T$QYai qyAËT$D$JZbj rzuL$'UWVSSD$8ufƍx p9sZBO G,9w< u1j h!QZ uGtt D$ D$9rD$=ELFt=6th!~ YT$ D%=cSc$t=CMUt=STANu D% D% л1 %@Й$D%uGt t1Avajh@#GPD uJuD@%8GPGPXZ&Hw <@"@wuj XG~[^_]UWVS0D$D$D$ho"` 1D$ [D$HD$tUD$APD$ h"0 T$BXXYj~"z:tEPEX+D$9}}:uj ]G~L$L$j $" P1D#_=D#y_f)1)…2T%@wL$H39tRh"N Y^tjjXZ D$ { t uh"D#@~D$A9`~D$a90D$191D$xD$T$H<tOD$yL$h"zD$LL$ L$AXXD$h~"x:tEPE=X+D$9}}:uj E$X+D$9}}:tE+D$9}}:uE+D$9}}:tE+D$9}}:uE+D$9l$ }:tD$ D$ +D$9} T$ ::ut$ F+D$9D$}(L$ At<:tF+D$D$9} t<:uF+D$19}E>:t@A< w k |%Pu|$Iu|$1F+D$9}>:uFP%+D$)Ã|$L%u|$tD$|$ |$|$ h"j^_u D$ PrW2[s ujVD$$PLt$ZY9~ 0F9T~ D< 9uEOuj 7X1|$\$LD$D)|$L$tyA1h" aIAL$ Xt=tuth"iOKXǃ t;<$t<~P@C^G맅tT$LJCj YNj\$ )~ }u |$Lt?T$LD$D9s+|$L|$ D$ D$ @D$ T$L$ A}-u}:t.ع|$DltftT$DDl0[^_]UWVSSSŋ $D$8=׋tT$BD$Kz=uD$pt$@Kt%<:t!~D$PXx T$))y1$U^_[^_]Ã|$D$8jh"t$ ` uD#T$D$Au.jh"t$ 2 uT%T$D$th|$~'D$8:tT$BD$D$HD$~z:uD$~T$::uBHT$D$~Bz:t|$~ D$8=ÐST$1ɀ:\$ t9uB:u[S\$L$ ڊABu[S\$;L$ tB:uAt BAu[VSt$ >\$L$tB:uCtItBCtIu[^WVS\$19ڋ|$t$}: 28t )B9|1[^_ÐUWVS,D$@t$DD$>l$H<%t&|$@tT$BT$PYF0< w F0< v>.uF0< w F0< vM9y|$@Yt T$BT$ PzZ;uJ<#|$ $u$F>hu F>huFЃ |$@tD$T$@)T$D$,[^_]ÍD$Pt$j ÍD$ Pt$ t$ ÐUWVS=%t$(% %%%9У%@ %)ы5% %H %!ƃ=%Tf%.f;b&f %`&9fPCf%%P%jP<ۉu=%Gu:=d%t =P#=l%tfH#fj Pn]X =%Hju%=d%P# l%t %H#0Pf|%B^f;b&f|%_=L#u f|%uf|%f~%Bf;`&f~%uSf~%b&D=%TPt=d%tP#l%H#PsY[~%|%P%PEXZ[^_]á%Gw5|$tjh YXfH#fj PXZáX#9T#t5jP%%T#jx% ËT$#D$#T$ ËT$ D$!#T$ ËD$3D$3D$ ËD$ D$3D$UWVS,&@?T$@? &&`#D$d#D$ h#D$$l#D$(D$D$$p#D$EL$t# &D$ }$D #U\L$D$tt VT$ $à \$ \$L$MD$tuD$|$nD$$|$SD$T$D`#JT$Bu,[^_]VSt$ h&&?8Ytj&?8ZuPSvSmSgjKWXu`#d#Fh#Fl#F $`#$d#[$h#^$&l#ÐVSt$ 01҃< wk ATЊ0< vӉ[^SztÁt u [1SkT$v9r[ô0ù 00ô ˹fôôôtf1۴tô$߉ÉEtherbootBad argument passed from Etherboot No menu vendor tags found, returning to Etherboot No selection, returning to Etherboot List of available boot images: %c) Select: (%d seconds) Passwd:  Params:  timeout=default=0123456789ABCDEF%d.+Q+Eth #EgܺvT2                  xjVp $ν|*ƇGF0FؘiD[\"kqCy!Ib%@@QZ^&Ƕ]/SD!7Ç ZEogL*B9q"am 8D꾤K`Kp~('09|eVD")*C#9Y[e }]O~o,CN~S5:*ӆ#EgܺvT2mknbi-1.4.4/dismbr.pl0100755000175000001440000000174107237131605013144 0ustar kenusers#!/usr/bin/perl -w # # Quick and dirty program to decode a partition table in MBR # GPL, July 2000, Ken Yap # sub decodechs ($) { my ($chs) = @_; my ($c, $h, $s); ($h, $s, $c) = unpack('CCC', $chs); $c += ($s & 0xC0) << 2; $s &= 0x3F; return ($c, $h, $s); } sub dismbr ($) { my ($par) = @_; my ($flags, $chs1, $type, $chs2, $bootseg, $numsegs); ($flags, $chs1, $type, $chs2, $bootseg, $numsegs) = unpack('Ca3Ca3VV', $par); printf "%s type:%02x %d/%d/%d-%d/%d/%d boot:%04x sectors:%04x\n", ($flags & 0x80) ? '*' : ' ', $type, decodechs($chs1), decodechs($chs2), $bootseg, $numsegs; } if ($#ARGV >= 0) { open(STDIN, "$ARGV[0]") or die "$ARGV[0]: $!\n"; } binmode(STDIN); $nread = read(STDIN, $mbr, 512); (defined($nread) and $nread == 512) or die "Cannot read 512 bytes of MBR\n"; (undef, $par[0], $par[1], $par[2], $par[3], $sig) = unpack('a446a16a16a16a16v', $mbr); $sig == 0xAA55 or die "Input is not a MBR\n"; foreach $i (0..3) { print "$i: "; dismbr($par[$i]); } mknbi-1.4.4/disnbi.pl0100755000175000001440000001206407646642526013151 0ustar kenusers#!/usr/bin/perl -w # # Quick Perl program to decode and display details about # tagged images created by mknbi # -e extracts directory to `nbidir' and segments to `segmentN' # N = 0, 1, 2, ... # # Added code to dump vendor tag in hex (for DOS disk parameters) # # Ken Yap, August 1999 # use strict; use vars qw($imagefile $data $curoffset $dirfile @seglengths $vendordata $extract $status $i); sub getvendordata ($) { my ($flags) = @_; my $vendordata = ''; my $vendorlen = ($flags & 0xff) >> 4; if ($vendorlen > 0) { $vendorlen *= 4; $vendordata = unpack("a$vendorlen", substr($data, $curoffset)); $curoffset += $vendorlen; } return ($vendordata); } sub decodesegmentflags ($) { my ($flags) = @_; my ($type); $flags >>= 24; $flags &= 0x3; ($flags == 0) and $type = "Absolute"; ($flags == 1) and $type = "Follows last segment"; ($flags == 2) and $type = "Below end of memory"; ($flags == 3) and $type = "Below last segment loaded"; return ($type); } sub one_nbi_segment ($) { my ($segnum) = @_; my ($type, $vendordata, @vdata, $i); my ($flags, $loadaddr, $imagelen, $memlength) = unpack('V4', substr($data, $curoffset)); $curoffset += 16; printf "Segment number %d\n", $segnum; printf "Load address:\t\t%08x\n", $loadaddr; printf "Image length:\t\t%d\n", $imagelen; printf "Memory length:\t\t%d\n", $memlength; $type = &decodesegmentflags($flags); print "Position:\t\t$type\n"; printf "Vendor tag:\t\t%d\n", ($flags >> 8) & 0xff; if (($vendordata = &getvendordata($flags)) ne '') { print "Vendor data:\t\t\"", $vendordata, "\"\n"; @vdata = unpack('C*', $vendordata); print "Vendor data in hex:\t"; foreach $i (0..$#vdata) { printf "%02x ", $vdata[$i]; } print "\n"; } print "\n"; push (@seglengths, $imagelen); return (($flags >> 26) & 1); } sub decode_nbi { my ($magic, $flags, $bx, $ds, $ip, $cs) = unpack('a4Vv4', substr($data, 0, 16)); $curoffset = 16; # Decode the header printf "Type: NBI\nHeader location:\t%04x:%04x\n", $ds, $bx; if (($flags >> 31) & 1) { printf "Start address:\t\t%04x%04x (flat)\n", $cs, $ip; } else { printf "Start address:\t\t%04x:%04x\n", $cs, $ip; } print "Flags:\n"; print "\tReturn to loader after execution (extension)\n" if (($flags >> 8) & 1); if (($vendordata = &getvendordata($flags)) ne '') { print "Vendor data:\t\t", $vendordata, "\n"; } print "\n"; # Now decode each segment record my $segnum = 0; do { $i = &one_nbi_segment($segnum); ++$segnum; } while (!$i); } sub one_elf_segment ($$) { my ($segnum, $curoffset) = @_; my ($offset, $vaddr, $paddr, $filesz, $memsz, $flags, $align) = unpack('@4V6', substr($data, $curoffset)); printf "Segment number %d\n", $segnum; printf "Load address:\t\t%08x\n", $vaddr; printf "Image length:\t\t%d\n", $filesz; printf "Memory length:\t\t%d\n", $memsz; print "\n"; push (@seglengths, $filesz); } sub decode_elf { my ($entry, $phoff, $shoff, $flags, $ehsize, $phentsize, $phnum) = unpack('@24V4v3', $data); printf "Type: ELF\nStart address:\t\t%08x\n", $entry; print "Flags:\n"; print "\tReturn to loader after execution (extension)\n" if ($flags & 0x8000000); print "\n"; $curoffset = $phoff; foreach $i (0..$phnum-1) { &one_elf_segment($i, $curoffset); $curoffset += $phentsize; } } $extract = 0; @seglengths = (); $#ARGV >= 0 or die "Usage: disnbi [-e] Etherboot-image-file\n"; if ($ARGV[0] eq '-e') { $extract = 1; shift } $#ARGV >= 0 or die "Usage: disnbi [-e] Etherboot-image-file\n"; $imagefile= $ARGV[0]; open(I, $ARGV[0]) or die "$imagefile: $!\n"; binmode(I); (defined($status = sysread(I, $data, 512)) and $status == 512) or die "$imagefile: Cannot read header\n"; my ($magic) = unpack('a4', substr($data, 0, 4)); if ($magic eq "\x36\x13\x03\x1B") { &decode_nbi(); $dirfile = 'nbidir'; } elsif ($magic eq "\x7FELF") { &decode_elf(); $dirfile = 'elfdir'; } else { die "$imagefile: Not a tagged or ELF image file\n"; } exit(0) if ($extract == 0); print "Dumping directory to `$dirfile'...\n"; open(O, ">$dirfile") or die "$dirfile: $!\n"; binmode(O); print O $data; close(O); $data = ''; foreach $i (0..$#seglengths) { print "Extracting segment $i to `segment$i'...\n"; open(O, ">segment$i") or die "segment$i: $!\n"; binmode(O); (defined($status = sysread(I, $data, $seglengths[$i])) and $status = $seglengths[$i]) or die "$imagefile: Cannot read data\n"; print O $data; close(O); } print "Done\n"; exit(0); __END__ =head1 NAME disnbi - display Etherboot image =head1 SYNOPSIS B [C<-e>] I =head1 DESCRIPTION B is a program that to display in symbolic form the contents of a Etherboot image created by mknbi or mkelf. Detection of image type is automatic. B<-e> Extract contents of image as well. The directory will be written to C or C and the segments to CI where I is 0, 1, 2, etc. =head1 BUGS Please report all bugs to the author. =head1 SEE ALSO Etherboot tutorial at C =head1 COPYRIGHT B is under the GNU Public License =head1 AUTHOR Ken Yap (C) =head1 DATE Version 1.4 December 2002 mknbi-1.4.4/Elf.pm0100644000175000001440000002327107603276272012401 0ustar kenusers# Class to handle Elf images # Placed under GNU Public License by Ken Yap, December 2000 package Elf; use strict; use IO::Seekable; use constant; use constant TFTPBLOCKSIZE => 512; # ELF magic header in first 4 bytes use constant MAGIC => "\x7FELF"; # This is defined by the bootrom layout use constant HEADERSIZE => 512; # Size of ELF header use constant ELF_HDR_LEN => 52; # Type code use constant ELFCLASS32 => 1; # Byte order use constant ELFDATA2LSB => 1; # ELF version use constant EV_CURRENT => 1; # File type use constant ET_EXEC => 2; # Machine type use constant EM_386 => 3; # Size of each program header use constant PROG_HDR_LEN => 32; # Type of header use constant PT_LOAD => 1; use constant PT_NOTE => 4; # Size of each section header (there is just one) use constant SECT_HDR_LEN => 40; # Note types use constant EIN_PROGRAM_NAME => 0x00000001; use constant EIN_PROGRAM_VERSION => 0x00000002; use constant EIN_PROGRAM_CHECKSUM => 0x00000003; sub new { my $class = shift; my $self = { }; $self->{libdir} = shift; $self->{segdescs} = []; $self->{offset} = 0; # cumulative offset from beginning of file $self->{checksum} = 0; # cumulative checksum of the file $self->{summed} = 0; # number of bytes checksummed $self->{data} = ""; # string buffer containing the output file bless $self, $class; # $self->_initialize(); return $self; } sub add_pm_header ($$$$$) { my ($self, $vendorinfo, $headerseg, $bootaddr, $progreturns) = @_; push(@{$self->{segdescs}}, pack('A4C4@16v2V5v6', MAGIC, ELFCLASS32, ELFDATA2LSB, EV_CURRENT, 255, # embedded ABI ET_EXEC, # e_type EM_386, # e_machine EV_CURRENT, # e_version $bootaddr, # e_entry ELF_HDR_LEN, # e_phoff 0, # e_shoff (come back and patch this) ($progreturns ? 0x8000000 : 0), # e_flags ELF_HDR_LEN, # e_ehsize PROG_HDR_LEN, # e_phentsize 0, # e_phnum (come back and patch this) SECT_HDR_LEN, # e_shentsize 1, # e_shnum, one mandatory entry 0 0)); # e_shstrndx $self->{offset} = HEADERSIZE; } sub compute_ip_checksum { my ($str) = @_; my ($checksum, $i, $size, $shorts); $checksum = 0; $size = length($$str); $shorts = $size >> 1; # Perl has a fairly large loop overhead so a straight forward # implementation of the ip checksum is intolerably slow. # Instead we use the unpack checksum computation function, # and sum 16bit little endian words into a 32bit number, on at # most 64K of data at a time. This ensures we do not overflow # the 32bit sum allowing carry wrap around to be implemented by # hand. for($i = 0; $i < $shorts; $i += 32768) { $checksum += unpack("%32v32768", substr($$str, $i <<1, 65536)); while($checksum > 0xffff) { $checksum = ($checksum & 0xffff) + ($checksum >> 16); } } if ($size & 1) { $checksum += unpack('C', substr($$str, -1, 1)); while($checksum > 0xffff) { $checksum = ($checksum & 0xffff) + ($checksum >> 16); } } $checksum = (~$checksum) & 0xFFFF; return $checksum; } sub add_summed_data { my ($self, $str) = @_; my $new_sum = compute_ip_checksum($str); my $new = $new_sum; my $sum = $self->{checksum}; my $checksum; $sum = ~$sum & 0xFFFF; $new = ~$new & 0xFFFF; if ($self->{summed} & 1) { $new = (($new >> 8) & 0xff) | (($new << 8) & 0xff00); } $checksum = $sum + $new; if ($checksum > 0xFFFF) { $checksum -= 0xFFFF; } $self->{checksum} = (~$checksum) & 0xFFFF; $self->{summed} += length($$str); print "$$str"; # $self->{data} .= $$str; # print STDERR sprintf("sum: %02x %02x sz: %08x summed: %08x\n", # $new_sum, $self->{checksum}, length($$str), $self->{summed}); } # This should not get called as we don't cater for real mode calls but # is here just in case sub add_header ($$$$$) { my ($self, $vendorinfo, $headerseg, $bootseg, $bootoff) = @_; $self->add_pm_header($vendorinfo, $headerseg, ($bootseg << 4) + $bootoff, 0); } sub roundup ($$) { # Round up to next multiple of $blocksize, assumes that it's a power of 2 my ($size, $blocksize) = @_; # Default to TFTPBLOCKSIZE if not specified $blocksize = TFTPBLOCKSIZE if (!defined($blocksize)); return ($size + $blocksize - 1) & ~($blocksize - 1); } # Grab N bytes from a file sub peek_file ($$$$) { my ($self, $descriptor, $dataptr, $datalen) = @_; my ($file, $fromoff, $status); $file = $$descriptor{'file'} if exists $$descriptor{'file'}; $fromoff = $$descriptor{'fromoff'} if exists $$descriptor{'fromoff'}; return 0 if !defined($file) or !open(R, "$file"); binmode(R); if (defined($fromoff)) { return 0 if !seek(R, $fromoff, SEEK_SET); } # Read up to $datalen bytes $status = read(R, $$dataptr, $datalen); close(R); return ($status); } # Add a segment descriptor from a file or a string sub add_segment ($$$) { my ($self, $descriptor, $vendorinfo) = @_; my ($file, $string, $segment, $len, $maxlen, $fromoff, $align, $id, $end, $vilen); $end = 0; $file = $$descriptor{'file'} if exists $$descriptor{'file'}; $string = $$descriptor{'string'} if exists $$descriptor{'string'}; $segment = $$descriptor{'segment'} if exists $$descriptor{'segment'}; $len = $$descriptor{'len'} if exists $$descriptor{'len'}; $maxlen = $$descriptor{'maxlen'} if exists $$descriptor{'maxlen'}; $fromoff = $$descriptor{'fromoff'} if exists $$descriptor{'fromoff'}; $align = $$descriptor{'align'} if exists $$descriptor{'align'}; $id = $$descriptor{'id'} if exists $$descriptor{'id'}; $end = $$descriptor{'end'} if exists $$descriptor{'end'}; if (!defined($len)) { if (defined($string)) { $len = length($string); } else { if (defined($fromoff)) { $len = (-s $file) - $fromoff; } else { $len = -s $file; } return 0 if !defined($len); # no such file } } if (defined($align)) { $len = &roundup($len, $align); } else { $len = &roundup($len); } $maxlen = $len if (!defined($maxlen)); push(@{$self->{segdescs}}, pack('V8', PT_LOAD, $self->{offset}, # p_offset $segment << 4, # p_vaddr $segment << 4, # p_paddr $len, # p_filesz $len, # p_memsz == p_filesz 7, # p_flags == rwx TFTPBLOCKSIZE)); # p_align $self->{offset} += $len; return ($len); # assumes always > 0 } sub pad_with_nulls ($$$) { my ($self, $i, $blocksize) = @_; $blocksize = TFTPBLOCKSIZE if (!defined($blocksize)); # Pad with nulls to next block boundary $i %= $blocksize; if ($i != 0) { # Nulls do not change the checksum print "\0" x ($blocksize - $i); # $self->{data} .= "\0" x ($blocksize - $i); $self->{summed} += ($blocksize - $i); } } # Copy data from file to stdout sub copy_file ($$) { my ($self, $descriptor) = @_; my ($i, $file, $fromoff, $align, $len, $seglen, $nread, $data, $status); $file = $$descriptor{'file'} if exists $$descriptor{'file'}; $fromoff = $$descriptor{'fromoff'} if exists $$descriptor{'fromoff'}; $align = $$descriptor{'align'} if exists $$descriptor{'align'}; $len = $$descriptor{'len'} if exists $$descriptor{'len'}; return 0 if !open(R, "$file"); if (defined($fromoff)) { return 0 if !seek(R, $fromoff, SEEK_SET); $len = (-s $file) - $fromoff if !defined($len); } else { $len = -s $file if !defined($len); } binmode(R); # Copy file in TFTPBLOCKSIZE chunks $nread = 0; while ($nread != $len) { $status = read(R, $data, TFTPBLOCKSIZE); last if (!defined($status) or $status == 0); $self->add_summed_data(\$data); $nread += $status; } close(R); if (defined($align)) { $self->pad_with_nulls($nread, $align); } else { $self->pad_with_nulls($nread); } return ($nread); } # Copy data from string to stdout sub copy_string ($$) { my ($self, $descriptor) = @_; my ($i, $string, $len, $align, $data); $string = $$descriptor{'string'} if exists $$descriptor{'string'}; $len = $$descriptor{'len'} if exists $$descriptor{'len'}; $align = $$descriptor{'align'} if exists $$descriptor{'align'}; return 0 if !defined($string); $len = length($string) if !defined($len); $data = substr($string, 0, $len); $self->add_summed_data(\$data); defined($align) ? $self->pad_with_nulls($len, $align) : $self->pad_with_nulls($len); return ($len); } sub dump_segments { my ($self) = @_; my ($s, $nsegs, @segdescs); # generate the note header my $notes = pack('V3Z8S2', 8, # n_namesz 2, # n_descsz EIN_PROGRAM_CHECKSUM, # n_type "ELFBoot", # n_name 0, # n_desc (Initial checksum value) 0); # padding to a 4byte boundary my $note_len = length($notes); # Add the note header push(@{$self->{segdescs}}, pack('V8', PT_NOTE, # p_type HEADERSIZE - $note_len, # p_offset 0, # p_vaddr 0, # p_paddr $note_len, # p_filesz 0, # p_memsz == p_filesz 0, # p_flags 0)); # p_align @segdescs = @{$self->{segdescs}}; $nsegs = $#segdescs; # number of program header entries # fill in e_phnum substr($segdescs[0], 44, 2) = pack('v', $nsegs); # fill in e_shoff to point to a record after program headers substr($segdescs[0], 32, 4) = pack('V', ELF_HDR_LEN + PROG_HDR_LEN * $nsegs); $self->{checksum} = 0; $self->{summed} = 0; while ($s = shift(@segdescs)) { $self->add_summed_data(\$s); } # insert section header 0 # we just need to account for the length, the null fill # will create the record we want # warn if we have overflowed allocated header area print STDERR "Warning, too many segments in file\n" if ($self->{summed} > HEADERSIZE - SECT_HDR_LEN - $note_len); print "\0" x (HEADERSIZE - $self->{summed}); # $self->{data} .= "\0" x (HEADERSIZE - $self->{summed}); # Write the note header; seek(STDOUT, HEADERSIZE - $note_len, SEEK_SET) or die "Cannot seek to note header\n"; print "$notes"; # substr($self->{data}, HEADERSIZE - $note_len, $note_len) = $notes } sub finalise_image { my ($self) = @_; # Fill in the checksum seek(STDOUT, HEADERSIZE - 4, SEEK_SET) or die "Cannot seek to checksum\n"; print pack('S', $self->{checksum}); # substr($self->{data}, (HEADERSIZE - 4), 2) = pack('S', $self->{checksum}); # print $self->{data}; } 1; mknbi-1.4.4/first32@0x82800.linux0100755000175000001440000001010210110544077014640 0ustar kenusers *)؎Ў$(,*@p pp,* *ËD$USVWMVff _^[]USVW}(u V'f1f fPAMSfrf=PAMSufNft fufX)_^[]SVW11Ҹr$utȉf%fff f%ff__^[fJfUSVWEà fff ؎fofPfS˃f_^[].g f"f)؎Ё(1X(PX-(P( ؎Ў f"fȎ؎fÉ')((8҉8t-BÊ6]u;th7N $-_8=cSc8D$t=CMUt=STANu 8 8F%T01ɉh8Bu%AT~ޡp8P8t8@D$ fx@Al8v@T$ D$B(@D$D$f)fB ?fB"1|$Iq\$!8 @=EthD$¸)9~B~C N~ BCNC8@ɉˆL$ Ʌɍ@~8:uNI@~~@D$ D$))D$t$F~a1|$I)9}HC ҋt$~8~&E<~u }bu\ <~u}cu :CNEECNCT$KJ;\$u888 t u$8B8B t t܅o8҉  =t@88B88R  =u887=8C1҅uS71u>7u)7u7҃e78-8u\78uD78u.78wt8 8¡8fu6787t#8@t< t< u788@t < t< 8pph7588k88:8H88: 8%\8t8:86rut78#t d8N78t d8/78t8d88MuC8Š0< w C0< vl$H<%t&|$@tT$BT$PYF0< w F0< v>.uF0< w F0< vM9y|$@Yt T$BT$ PZ;uJ<#|$ $u$F>hu F>huFЃ 8W ǍD$C9rOcL$ u ED$ T$ ύL$ 9s)|$@Yt T$BT$ PWX9rF>|$@tD$T$@)T$D$,[^_]ÍD$Pt$j ÍD$ Pt$ t$ ÐST$1ɀ:\$ t9uB:u[S\$L$ ڊABu[S\$;L$ tB:uAt BAu[VSt$ >\$L$tB:uCtItBCtIu[^WVS\$19ڋ|$t$}: 28t )B9|1[^_Out of parameter space %@mknbi-1.4.4/first32.c (GPL) Bad argument vganfsrootiprdbasememaskextendednormal0xrom%@:%@:topasisTop of ramdisk is %#X Ramdisk at %#X, size %#X 0123456789ABCDEF%d.mknbi-1.4.4/Makefile0100644000175000001440000002212110110270701012740 0ustar kenusersVERSION=1.4.4 EXTRAVERSION= TARVERSION=1.4.4 # spec file can override RPMVERSION=$(VERSION) # If you don't have either nasm or the ELKS as86, then just do make # and make install because the assembler sources are supplied preassembled # If you do make realclean you will have to unpack the mknbi archive again # Use nasm or as86 ASM=nasm # This must be the as86 from the ELKS project, the default Linux one won't do #ASM=as86 # for first32*.linux # This one makes multiple versions FIRSTRELOCS= 0x92800 0x82800 OLDGAS:= $(shell $(AS) --version | grep -q '2\.9\.1' && echo -DGAS291) CFLAGS= -I. -Os -ffreestanding -fstrength-reduce -fomit-frame-pointer \ -mcpu=i386 \ -Wall -W -Wno-format -Wno-unused -DVERSION=\"$(VERSION)$(EXTRAVERSION)\" LDBINARYFLAG= --oformat binary FIRST32SIZE= 6144 # for first32dos F32DRELOC=0x93000 # for FreeDOS FDKSEG= 0x60 # for menu MENURELOC= 0x60000 # Options for auxiliary menu program # Available: -DANSIESC -DMOTD -DUSRPARMS -DPASSWD # -DCONSOLE_CRT -DCONSOLE_SERIAL -DSHOW_NUMERIC -DPOWERSAVE # Might as well take the lot since code size is not a concern # Must pick ANSIMODE=1 if ANSIESC is chosen BOOTMENU_FLAGS= -DCONSOLE_CRT -DANSIESC -DANSIMODE=1 -DMOTD -DUSRPARMS -DPASSWD -DPOWERSAVE -DCOMCONSOLE=0x3f8 -DCOMPRESERVE PREFIX= /usr/local INSTPREFIX= $(BUILD_ROOT)$(PREFIX) LIBDIR= $(PREFIX)/lib/mknbi INSTLIBDIR= $(INSTPREFIX)/lib/mknbi BINDIR= $(INSTPREFIX)/bin MANDIR= $(INSTPREFIX)/share/man/man1 DOCDIR= $(INSTPREFIX)/share/doc/packages/mknbi-$(RPMVERSION) INSTALL= install PROG= mknbi disnbi dismbr disdosbb nbitoelf MODULES=Nbi.pm Elf.pm TruncFD.pm FIRSTS= $(foreach i,$(FIRSTRELOCS),first32@$(i).linux first32elf@$(i).linux) \ first.dos first.fdos menu nfl ALTBOOT=altboot.bin RMRD= rmrd.com MANS= mknbi.1 disnbi.1 menuc.1 HTMLS= mknbi.html disnbi.html menuc.html DOCS= $(MANS) $(HTMLS) all: $(PROG) $(FIRSTS) $(RMRD) $(DOCS) # Tagged image builder mknbi: mknbi.pl Nbi.pm TruncFD.pm perl -ne 's|\@\@VERSION\@\@|$(VERSION)|; s|\@\@LIBDIR\@\@|$(LIBDIR)|; s|\@\@FDKSEG\@\@|$(FDKSEG)|; print $$_;' mknbi.pl > $@ chmod 755 $@ # Tagged image display and disassemble disnbi: disnbi.pl cp -p disnbi.pl disnbi chmod 755 disnbi # Master boot record display dismbr: dismbr.pl cp -p dismbr.pl dismbr chmod 755 dismbr # DOS boot block display disdosbb: disdosbb.pl cp -p disdosbb.pl disdosbb chmod 755 disdosbb # NBI to ELF converter nbitoelf: nbitoelf.pl cp -p nbitoelf.pl nbitoelf chmod 755 nbitoelf # 32-bit first stage protected mode call setup program first32@%.linux: start32@%.o first32.o memsizes.o printf.o string.o $(LD) -N -Ttext $* -e _start $(LDBINARYFLAG) -o $@ start32@$*.o first32.o memsizes.o printf.o string.o @if [ `wc -c < $@` -gt $(FIRST32SIZE) ]; then echo Binary too large; fi # 32-bit first stage ELF setup program first32elf@%.linux: start32@%.o first32elf.o memsizes.o printf.o string.o $(LD) -N -Ttext $* -e _start $(LDBINARYFLAG) -o $@ start32@$*.o first32elf.o memsizes.o printf.o string.o @if [ `wc -c < $@` -gt $(FIRST32SIZE) ]; then echo Binary too large; fi # 32-bit first stage ELF DOS setup program first32elf@%.dos: start32@%.o first32dos.o printf.o string.o $(LD) -N -Ttext $* -e _start $(LDBINARYFLAG) -o $@ start32@$*.o first32dos.o printf.o string.o start32@%.o: start32.S gcc -E -DRELOC=$* $(OLDGAS) start32.S | $(AS) -o start32@$*.o first32.o: first32.c etherboot.h start32.h gcc $(CFLAGS) -o first32.o -c first32.c first32elf.o: first32.c etherboot.h start32.h gcc $(CFLAGS) -DFIRST32ELF -o first32elf.o -c first32.c first32dos.o: first32.c etherboot.h start32.h gcc $(CFLAGS) -DRELOC=$(F32DRELOC) -DFIRST32DOS -DFIRST32ELF -o first32dos.o -c first32.c memsizes.o: memsizes.c gcc $(CFLAGS) -c $*.c printf.o: printf.c gcc $(CFLAGS) -c $*.c # DOS first stage setup program, depend on Makefile for version number first.dos: first-dos.S first-dos.h version-dos.h Makefile ifeq ($(ASM),as86) gcc $(ASMCFLAGS) -DUSE_AS86 -DVENDOR_MAGIC=\"mknbi-dos-$(VERSION)\" -E -traditional -o first-dos.s first-dos.S as86 -0 -b first.dos first-dos.s else gcc $(ASMCFLAGS) -DUSE_NASM -DVENDOR_MAGIC=\"mknbi-dos-$(VERSION)\" -E -traditional -o first-dos.s first-dos.S nasm -f bin first-dos.s -o first.dos endif # FreeDOS first stage setup program, depend on Makefile for version number first.fdos: first-dos.S first-dos.h version-dos.h Makefile ifeq ($(ASM),as86) gcc $(ASMCFLAGS) -DFREEDOS -DFDKSEG=$(FDKSEG) -DUSE_AS86 -DVENDOR_MAGIC=\"mknbi-fdos-$(VERSION)\" -E -traditional -o first-fdos.s first-dos.S as86 -0 -b first.fdos first-fdos.s else gcc $(ASMCFLAGS) -DFREEDOS -DFDKSEG=$(FDKSEG) -DUSE_NASM -DVENDOR_MAGIC=\"mknbi-fdos-$(VERSION)\" -E -traditional -o first-fdos.s first-dos.S nasm -f bin first-fdos.s -o first.fdos endif first-elf.dos: first.dos first32elf@$(F32DRELOC).dos cat first.dos first32elf@$(F32DRELOC).dos > first-elf.dos first-elf.fdos: first.fdos first32elf@$(F32DRELOC).dos cat first.fdos first32elf@$(F32DRELOC).dos > first-elf.fdos # Menu first stage program menu: startmenu.o menu.o bootmenu.o string.o printf.o ansiesc.o md5.o misc.o serial.o $(LD) -N -Ttext $(MENURELOC) -e _start $(LDBINARYFLAG) -o $@ startmenu.o menu.o bootmenu.o string.o printf.o ansiesc.o md5.o misc.o serial.o # Another menu program, this one simpler menu-simple: startmenu.o menu-simple.o string.o printf.o ansiesc.o $(LD) -N -Ttext $(MENURELOC) -e _start $(LDBINARYFLAG) -o $@ startmenu.o menu-simple.o string.o printf.o ansiesc.o # Network FreeLoader (light-bar menu program) nfl: startmenu.o nfl.o string.o printf.o ansiesc.o $(LD) -N -Ttext $(MENURELOC) -e _start $(LDBINARYFLAG) -o $@ startmenu.o nfl.o string.o printf.o ansiesc.o # LUA interpreter lua/bin/lua: cd lua; make startmenu.o: startmenu.S startmenu.h gcc -E -Ui386 -DRELOC=$(MENURELOC) $(OLDGAS) startmenu.S | $(AS) -o startmenu.o menu.o: menu.c stddef.h string.h printf.h ansiesc.h \ misc.h linux-asm-io.h etherboot.h gcc $(CFLAGS) $(BOOTMENU_FLAGS) -c $*.c bootmenu.o: bootmenu.h bootmenu.c stddef.h string.h md5.h misc.h etherboot.h start32.h gcc $(CFLAGS) $(BOOTMENU_FLAGS) -c $*.c string.o: string.h string.c gcc $(CFLAGS) -c $*.c ansiesc.o: ansiesc.h ansiesc.c stddef.h string.h etherboot.h gcc $(CFLAGS) -DGFX -c $*.c md5.o: md5.h md5.c etherboot.h gcc $(CFLAGS) $(BOOTMENU_FLAGS) -c $*.c misc.o: misc.h misc.c ansiesc.h etherboot.h start32.h gcc $(CFLAGS) $(BOOTMENU_FLAGS) -c $*.c serial.o: serial.c gcc $(CFLAGS) $(BOOTMENU_FLAGS) -c $*.c menu-simple.o: menu-simple.h menu-simple.c string.h etherboot.h gcc $(CFLAGS) -c $*.c # Remove ramdisk utility under DOS rmrd.com: rmrd.S ifeq ($(ASM),as86) gcc $(ASMCFLAGS) -DUSE_AS86 -E -traditional -o rmrd.s rmrd.S # -s appears to be necessary to start binary at 0x100 as86 -0 -b rmrd.com -s rmrd.map rmrd.s else gcc $(ASMCFLAGS) -DUSE_NASM -E -traditional -o rmrd.s rmrd.S nasm -f bin rmrd.s -o rmrd.com endif # Alternate boot block, taken from netboot mknbi-dos # Not made by default because not everybody has as86 installed $(ALTBOOT): altboot.S gcc -E altboot.S > altboot.s as86 -s /dev/null -b $(ALTBOOT) altboot.s $(RM) altboot.s $(MANS): mknbi.pl disnbi.pl Makefile pod2man --date=`date +%Y-%m-%d` --release="Mknbi $(VERSION)$(EXTRAVERSION)" --center="Etherboot tools" mknbi.pl > mknbi.1 pod2man --date=`date +%Y-%m-%d` --release="Mknbi $(VERSION)$(EXTRAVERSION)" --center="Etherboot tools" disnbi.pl > disnbi.1 pod2man --date=`date +%Y-%m-%d` --release="Mknbi $(VERSION)$(EXTRAVERSION)" --center="Etherboot tools" menuc.pl > menuc.1 $(HTMLS): mknbi.pl disnbi.pl pod2html mknbi.pl > mknbi.html pod2html disnbi.pl > disnbi.html pod2html menuc.pl > menuc.html install: all $(ALTBOOT) -mkdir -p $(INSTLIBDIR) $(INSTALL) $(PROG) $(INSTLIBDIR)/ $(INSTALL) -m 644 $(MODULES) $(FIRSTS) $(ALTBOOT) $(RMRD) $(INSTLIBDIR)/ if [ -e lua-4.0.1/bin/lua ]; then \ cp -p lua-4.0.1/bin/lua lua; \ fi if [ -e lua ]; then \ $(INSTALL) -m 644 lua $(INSTLIBDIR)/lua; \ fi -mkdir -p $(BINDIR) cd $(BINDIR); \ for i in linux rom fdos dos menu nfl; \ do \ ln -sf ../lib/mknbi/mknbi mknbi-$$i; \ done; \ for i in linux img menu nfl lua; \ do \ ln -sf ../lib/mknbi/mknbi mkelf-$$i; \ done (cd $(BINDIR); ln -sf ../lib/mknbi/disnbi disnbi) (cd $(BINDIR); ln -sf ../lib/mknbi/dismbr dismbr) (cd $(BINDIR); ln -sf ../lib/mknbi/disdosbb disdosbb) (cd $(BINDIR); ln -sf ../lib/mknbi/nbitoelf nbitoelf) -mkdir -p $(MANDIR) $(INSTALL) -m 644 mknbi.1 disnbi.1 $(MANDIR)/ cd $(MANDIR); \ for i in mkelf mknbi-linux mkelf-linux mknbi-rom mkelf-img mknbi-menu mkelf-menu mknbi-nfl mkelf-nfl mknbi-dos mknbi-fdos mkelf-lua; \ do \ ln -sf mknbi.1 $$i.1; \ done -mkdir -p $(DOCDIR) $(INSTALL) -m 644 COPYING README LOG spec.txt $(DOCDIR)/ tarball: mkdir -p luabuild -diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1 lua-4.0.1 > luabuild/luapatch.txt (cd ..; tar zcf /tmp/mknbi-$(TARVERSION).tar.gz --exclude CVS --exclude lua-4.0.1 mknbi-$(TARVERSION)) clean: $(RM) -f $(PROG) start32*.o first32*.o \ printf.o menu.o menu-simple.o nfl.o startmenu.o \ bootmenu.o md5.o misc.o serial.o ansiesc.o string.o memsizes.o \ first-dos.s first-fdos.s rmrd.s rmrd.map *.l pod2htm* realclean: clean $(RM) -f $(FIRSTS) $(RMRD) $(DOCS) mknbi-1.4.4/first-elf.fdos0100644000175000001440000001324510106323723014067 0ustar kenusersڌȎ،.6>FFFF P&;u.&G;u$&G$<u1t!&:AuG6>.˾_ t&Eu&E&]f h &E &]  أj &0&n &Ap &At &Ar &Al &A w &A v Av r2T&>uO&>t&>u?&&04r*FTv &8$u&> u&> &:r tbPX6>.1> t &<u߹t ΀<u3뱃ێÿ' 6, u31Ɂ<u As"/&E"&:mt&Eu & 1YQı%0YVt S0[^ DOS Net Boot Image Loader Version 0.8.1 mknbi-fdos-1.4.4 GPLed by G. Kuhlmann 6mknbi-fdos-1.4.4cScCMUSTANpp Error in load record data Invalid boot header magic number Invalid vendor magic ID Error while accessing ramdisk Wrong ramdisk image BOOTP record invalid RPL=JuQYPXJX..X uD<u.h .f .j <u ˺' .% <u˺T .v .z <uMuP.| . ~ uC/v sJr.w tu$0u.T .u 0 ..T vJS0r݀uʜ.T .u Rʀu.T ru 뼜.T ZS&'[PXUF]X0<<x t R0ҜT Zr0[\&'[[RQSPs2X[YZ;p r;n v [(s @uX[YZ0[u r .l 6t 11[0[[RQP XsYZ[r ċn p SQÈ11Ɋt ȁr S1 t PRZX[ـ?:r wIxȁ;p r w;n rY[VWQRP t f h Tt1ұ0؁UuȎ XZY_^û@.d {0[r00Ou%j A9wS´ 8[ t z * uz z +f h r=PUPFFNX].6~ .6| [. . Ȏм QRVWȎ[_^ZY. . Sv  &E u1&;u&=u uT ڌش/،9u9u u t/u1` &b &> &MP t ` z tR Z t ƒ¿1[0AP` NetB@h `P` NO NAME FAT12  2 1 ؎Ў$0 2 H p pp2  2 ËD$USVWMDff_^[]USVW}0 u Vf1f fPAMSfrf=PAMSufNft fufX)_^[]SVW11Ҹr$utȉf%fff f%ffM_^[}f8fUSVWEà Tf]fPfS˃f_^[].g f"f1 ؎Ё0 1X0 PX-0 P0  ؎Ў f"fȎ؎f'1 0 0 UWVS|$hU6 ?Zufw _9sZBN <F,89w< u1j hx6 Q uFtt D$D$9݉rD$8ELFu D$8th6 $X6 t$h6 t$h J [^_1]S\$ uj Y\$[AUWVS,D$@t$DD$>l$H<%t&|$@tT$BT$PYF0< w F0< v>.uF0< w F0< vM9y|$@Yt T$BT$ P3Z;uJ<#|$ $u$F>hu F>huFЃ |$@tD$T$@)T$D$,[^_]ÍD$Pt$j ÍD$ Pt$ t$ ÐST$1ɀ:\$ t9uB:u[S\$L$ ڊABu[S\$;L$ tB:uAt BAu[VSt$ >\$L$tB:uCtItBCtIu[^WVS\$19ڋ|$t$}: 28t )B9|1[^_mknbi-1.4.4/first32.c (ELF) (GPL) EtherbootBad argument 0123456789ABCDEF%d.mknbi-1.4.4/first32elf@0x93000.dos0100755000175000001440000000324510106323723014757 0ustar kenusers 2 1 ؎Ў$0 2 H p pp2  2 ËD$USVWMDff_^[]USVW}0 u Vf1f fPAMSfrf=PAMSufNft fufX)_^[]SVW11Ҹr$utȉf%fff f%ffM_^[}f8fUSVWEà Tf]fPfS˃f_^[].g f"f1 ؎Ё0 1X0 PX-0 P0  ؎Ў f"fȎ؎f'1 0 0 UWVS|$hU6 ?Zufw _9sZBN <F,89w< u1j hx6 Q uFtt D$D$9݉rD$8ELFu D$8th6 $X6 t$h6 t$h J [^_1]S\$ uj Y\$[AUWVS,D$@t$DD$>l$H<%t&|$@tT$BT$PYF0< w F0< v>.uF0< w F0< vM9y|$@Yt T$BT$ P3Z;uJ<#|$ $u$F>hu F>huFЃ |$@tD$T$@)T$D$,[^_]ÍD$Pt$j ÍD$ Pt$ t$ ÐST$1ɀ:\$ t9uB:u[S\$L$ ڊABu[S\$;L$ tB:uAt BAu[VSt$ >\$L$tB:uCtItBCtIu[^WVS\$19ڋ|$t$}: 28t )B9|1[^_mknbi-1.4.4/first32.c (ELF) (GPL) EtherbootBad argument 0123456789ABCDEF%d.mknbi-1.4.4/first32.c0100644000175000001440000004172110110034301012741 0ustar kenusers#include "stddef.h" #include "string.h" #include "linux-asm-io.h" #include "etherboot.h" #include "start32.h" #include "elf_boot.h" #ifndef FIRST32DOS #define FIRST32LINUX 1 #endif #ifdef FIRST32LINUX #define SERIAL_CONSOLE 0 /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. */ /* Memory layout assumed by mknbi and this program 0x07C00-0x07FFF 0.5 kB floppy boot sector if loaded from floppy 0x0F???-0x0FFFF ? kB large Etherboot data buffers (deprecated) 0x10000-0x8FFFF 512.0 kB kernel (from tagged image) 0x90000-0x901FF 0.5 kB Linux floppy boot sector (from Linux image) 0x90200-0x921FF 8.0 kB kernel setup (from Linux image) 0x92200-0x923FF 0.5 kB tagged image header ("directory") 0x92400-0x927FF 1.0 kB kernel parameters (generated by mknbi) 0x92800-0x93FFF 6.0 kB this program (generated by mknbi) 0x94000-0x9FFFF 48.0 kB Etherboot (top few kB may be used by BIOS) Normally Etherboot starts at 0x94000 0x100000- kernel (if bzImage) (from tagged image) after bzImage kernel ramdisk (optional) (from tagged image) moved to below top of memory by this program but not higher than 896kB or what the limit in setup.S says */ #define PARAMSIZE 512 extern void printf(const char *, ...); extern int sprintf(char *, const char *, ...); extern void xstartlinux(unsigned long); extern void exit(int); #ifdef FIRST32ELF static Elf32_Phdr *seg[S_END] = { 0 }; #else static struct segment *seg[S_END] = { 0 }; #endif static unsigned char *ip, *op; static short *vgamode; static struct bootp_t *bp; static unsigned char *vendortags; unsigned long top_of_initrd = 0; static enum { RD_TOP, RD_ASIS, RD_HEXADDR } rdmode = RD_TOP; static unsigned long rdaddr; #if SERIAL_CONSOLE /* Base Address */ #define TTYS0 0x3f8 /* Data */ #define TTYS0_RBR (TTYS0+0x00) #define TTYS0_TBR (TTYS0+0x00) /* Control */ #define TTYS0_IER (TTYS0+0x01) #define TTYS0_IIR (TTYS0+0x02) #define TTYS0_FCR (TTYS0+0x02) #define TTYS0_LCR (TTYS0+0x03) #define TTYS0_MCR (TTYS0+0x04) #define TTYS0_DLL (TTYS0+0x00) #define TTYS0_DLM (TTYS0+0x01) /* Status */ #define TTYS0_LSR (TTYS0+0x05) #define TTYS0_MSR (TTYS0+0x06) #define TTYS0_SCR (TTYS0+0x07) static void ttys0_tx_byte(unsigned byte) { while((inb(TTYS0_LSR) & 0x20) == 0) ; outb(byte, TTYS0_TBR); } #endif void putchar(int c) { if (c == '\n') putchar('\r'); #if SERIAL_CONSOLE ttys0_tx_byte(c); #endif console_putc(c); } static inline void quit(void) { printf("Bad argument\n"); exit(0); } static void nomem(void) { printf("Out of parameter space\n"); exit(0); } static inline void checkvendor(void) { union { unsigned long l; unsigned char c[4]; } u; memcpy(u.c, vendortags, sizeof(u)); if (u.l == RFC_1048 || u.l == VEND_CMU || u.l == VEND_STAN) vendortags += 4; else vendortags = 0; } #ifdef FIRST32ELF static inline void locate_segs(union infoblock *header) { int i; Elf32_Phdr *s; s = (Elf32_Phdr *)((char *)header + header->ehdr.e_phoff); for (i = 0; i < S_END && i < header->ehdr.e_phnum; i++, s++) { seg[i] = s; #if DEBUG > 1 printf("%d %#X\n", i, s->p_paddr); #endif } } #else static inline void locate_segs(union infoblock *header) { int i; struct segment *s; s = (struct segment *)((char *)header + sizeof(struct imgheader) + ((header->img.length & 0xF0) >> 2)); for (i = 0; i < S_END; i++, s++) { seg[i] = s; #if DEBUG > 1 printf("%d %#X\n", i, s->p_paddr); #endif if (s->flags & F_FINAL) break; s = (struct segment *)((char *)s + ((s->lengths & 0xF0) >> 2)); } } #endif /* !FIRST32ELF */ /* * Find DHCP vendor tag, return pointer to tag length */ static unsigned char *gettag(unsigned int tag) { unsigned char *p; unsigned char c; static unsigned char emptytag[] = { 0, 0 }; if (vendortags == 0) return (emptytag); for (p = vendortags; (c = *p) != RFC1533_END; ) { if (c == RFC1533_PAD) p++; else if (c == tag) return (p + 1); else p += p[1] + 2; } return (emptytag); } static void outtag(unsigned char *value) { int len; len = *value++; if (op + len > ip) nomem(); while (len-- > 0) *op++ = *value++; } /* Return 1 if s2 is a prefix of s1 */ static int strprefix(const unsigned char *s1, const unsigned char *s2) { while (*s1 != '\0' && *s2 != '\0' && *s1++ == *s2++) ; /* Have we reached the end of s2? */ return (*s2 == '\0'); } enum keyword { K_VGA, K_NFSROOT, K_IP, K_RDBASE, K_MEM }; static inline int match_keyword(const unsigned char *start) { if (strprefix(start, "vga")) return (K_VGA); if (strprefix(start, "nfsroot")) return (K_NFSROOT); if (strprefix(start, "ip")) return (K_IP); if (strprefix(start, "rdbase")) return (K_RDBASE); if (strprefix(start, "mem")) return (K_MEM); return (-1); } #define isws(c) ((c) == ' ' || (c) == '\t') static inline int copy_and_match(void) { int c; unsigned char *start; start = ip; /* Stop copying at = if it exists */ while ((c = *ip) != '\0' && !isws(c) && c != '=') { *op++ = *ip++; } if (c == '=') { ip++; *op++ = '='; return (match_keyword(start)); } return (-1); } static unsigned long gethex(const unsigned char *p) { unsigned long value = 0; for (;;) { int c = *p++; if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'a' && c <= 'f') c -= 'a' - 10; else if (c >= 'A' && c <= 'F') c -= 'A' - 10; else break; value <<= 4; value |= c; } return (value); } static int getdec(const unsigned char *p) { int value = 0, sign = 0; if (*p == '-') { sign = 1; p++; } for (;;) { int c = *p++; if (c >= '0' && c <= '9') c -= '0'; else break; value *= 10; value += c; } return (sign ? -value : value); } static void copy_nonws(void) { int c; /* Copy up to next whitespace */ while ((c = *ip) != '\0' && !isws(c)) *op++ = *ip++; } static void discard_arg(void) { int c; /* Discard up to next whitespace */ while ((c = *ip) != '\0' && !isws(c)) ip++; } static int outip(const unsigned char *p) { long ip; if (*p == 0) return (0); memcpy(&ip, p + 1, sizeof(ip)); return sprintf(op, "%@", ip); } static inline void subst_value(int kwindex) { int c; unsigned char *p; if (kwindex == K_VGA) { /* backup over "vga=" */ op -= sizeof("vga=") - 1; if (strprefix(ip, "ask")) c = -3; else if (strprefix(ip, "extended")) c = -2; else if (strprefix(ip, "normal")) c = -1; else if (strprefix(ip, "0x")) c = gethex(ip+2); else /* assume decimal mode number */ c = getdec(ip); *vgamode = c; discard_arg(); } else if (kwindex == K_NFSROOT && strprefix(ip, "rom") && (ip[3] == '\0' || isws(ip[3]))) { outtag(gettag(RFC1533_ROOTPATH)); discard_arg(); } else if (kwindex == K_IP && strprefix(ip, "rom") && (ip[3] == '\0' || isws(ip[3]))) { long ip; op += sprintf(op, "%@:%@:", bp->bp_yiaddr, bp->bp_siaddr); p = gettag(RFC1533_GATEWAY); op += outip(p); *op++ = ':'; p = gettag(RFC1533_NETMASK); op += outip(p); *op++ = ':'; outtag(gettag(RFC1533_HOSTNAME)); p = gettag(RFC1533_VENDOR_ETHDEV); if (*p) *op++ = ':'; outtag(p); discard_arg(); } else if (kwindex == K_RDBASE) { if (strprefix(ip, "top")) rdmode = RD_TOP; else if (strprefix(ip, "asis")) rdmode = RD_ASIS; else if (strprefix(ip, "0x")) { rdmode = RD_HEXADDR; rdaddr = gethex(ip+2); } discard_arg(); } else if (kwindex == K_MEM) { unsigned char *p; unsigned long memsize; memsize = getdec(p = ip); while (*p >= '0' && *p <= '9') ++p; if (*p == 'G') memsize <<= 30; else if (*p == 'M') memsize <<= 20; else if (*p == 'K') memsize <<= 10; top_of_initrd = memsize; copy_nonws(); } else copy_nonws(); } static inline int skipws(void) { int c; while ((c = *ip) != '\0' && isws(c)) ip++; return (c); } /* * The parameters are copied from the input area to the output * area, looking out for keyword=value pairs while doing so. * If a possible keyword is found, indicated by an =, * it is matched against a small list. * If it matches none of the keywords on the list, * the value is copied unchanged. * If it matches a keyword, then the appropriate substitutions * are made. * While doing the substitution, a check is made that the output * pointer doesn't overrun the input pointer. This is the only * place it could happen, as the substitution may be longer than * the original. */ static inline void process_params(void) { int i; while (skipws() != '\0') { if ((i = copy_and_match()) >= 0) subst_value(i); else copy_nonws(); *op++ = ' '; } /* There may be a space after the last arg, probably does not matter but this is a reminder */ *op = '\0'; } /* * String is not null terminated, count of chars following is in first element * If there are 6 colons, returns char position after 6th colon * Else returns one position after string * which forces the length calculated below to be negative * Length of 7th argument can be calculated by subtracting the * length of the string preceding from the total length. */ static inline unsigned char *skip6colons(unsigned char *p) { int len, coloncount; for (len = *p++, coloncount = 6; len > 0 && coloncount > 0; p++, len--) if (*p == ':') coloncount--; return (p + (coloncount > 0)); } static void parse_elf_boot_notes( void *notes, union infoblock **rheader, struct bootp_t **rbootp) { unsigned char *note, *end; Elf_Bhdr *bhdr; Elf_Nhdr *hdr; bhdr = notes; if (bhdr->b_signature != ELF_BHDR_MAGIC) { return; } note = ((char *)bhdr) + sizeof(*bhdr); end = ((char *)bhdr) + bhdr->b_size; while (note < end) { unsigned char *n_name, *n_desc, *next; hdr = (Elf_Nhdr *)note; n_name = note + sizeof(*hdr); n_desc = n_name + ((hdr->n_namesz + 3) & ~3); next = n_desc + ((hdr->n_descsz + 3) & ~3); if (next > end) break; #if 0 printf("n_type: %x n_name(%d): n_desc(%d): \n", hdr->n_type, hdr->n_namesz, hdr->n_descsz); #endif if ((hdr->n_namesz == 10) && (memcmp(n_name, "Etherboot", 10) == 0)) { switch(hdr->n_type) { case EB_BOOTP_DATA: *rbootp = *((void **)n_desc); break; case EB_HEADER: *rheader = *((void **)n_desc); break; default: break; } } note = next; } } int first(struct ebinfo *eb, union infoblock *header, struct bootp_t *bootp) { int i; unsigned char *p, *q, *params; struct bootblock *boot; struct setupblock *setup; union { unsigned long l; unsigned char c[4]; } u; #if DEBUG > 1 printf("&eb = %#X\n", &eb); #endif printf(MKNBI_VERSION "/" __FILE__ #ifdef FIRST32ELF " (ELF)" #endif " (GPL)\n"); #if DEBUG > 1 printf("eb = %#X, header = %#X, bootp = %#X\n", eb, header, bootp); #endif /* Sanity checks */ #ifdef FIRST32ELF parse_elf_boot_notes(eb, &header, &bootp); if (header->img.magic != ELF_MAGIC #else if (header->img.magic != TAG_MAGIC #endif || bootp->bp_op != BOOTP_REPLY) quit(); bp = bootp; vendortags = (unsigned char *)bootp->bp_vend; checkvendor(); locate_segs(header); /* Locate boot block */ boot = (struct bootblock *)seg[S_BOOT]->p_paddr; /* Point to word to alter if vga=... specified */ vgamode = &boot->vgamode; /* Locate setup block */ setup = (struct setupblock *)seg[S_SETUP]->p_paddr; /* Adjust loader type byte */ setup->su_type = SU_MY_LOADER_TYPE; /* If setup version >= 0x202, use new command line protocol. This frees setup.S from being tied to 0x90000 */ if (setup->su_version >= 0x202) setup->su_cmd_line_ptr = params = (unsigned char *)seg[S_PARAMS]->p_paddr; else { /* Use old protocol */ /* Adjust boot block pointers to point to command line */ boot->cl_magic = CL_MAGIC; boot->cl_offset = (params = (unsigned char *)seg[S_PARAMS]->p_paddr) - ((unsigned char *)boot); } p = params + (i = strlen(params) + 1); /* Append T129 if present */ q = gettag(RFC1533_VENDOR_MAGIC); /* Check T128 present and correct */ if (*q == 6 && (memcpy(u.c, q + 1, sizeof(u)), u.l == VEND_EB)) { q = gettag(RFC1533_VENDOR_ADDPARM); i = PARAMSIZE - 1 - i; /* +1 for SPACE */ if (i > *q) /* enough space? */ i = *q; q++; if (i > 0) p[-1] = ' '; /* NUL -> space */ while (i-- > 0) *p++ = *q++; *p++ = '\0'; /* position past NUL */ if (*(q = gettag(RFC1533_VENDOR_SELECTION)) == 1 && *(q = gettag(q[1])) > 0) { unsigned char *r = skip6colons(q); /* If we have an argument and enough space, copy it */ if ((i = *q - (r - q) + 1) > 0 && i < PARAMSIZE - 2 - strlen(params)) { /* +2 for SPACE and final NUL */ p[-1] = ' '; while (i-- > 0) { /* escapes: ~b -> \\, ~c -> : */ if (i > 0 && r[0] == '~' && r[1] == 'b') *p++ = '\\', r += 2, --i; else if (i > 0 && r[0] == '~' && r[1] == 'c') *p++ = ':', r += 2, --i; else *p++ = *r++; } *p++ = '\0'; } } } /* Move parameters to end of parameter area, tail first to avoid overwriting */ q = params + PARAMSIZE; /* At least 1 byte is copied, the NUL */ do { *--q = *--p; } while (p != params); ip = q; op = params; #ifdef DEBUG printf("Parameters: %s\n", p); #endif /* mem= param affects top_of_initrd */ process_params(); if (seg[S_RAMDISK] != 0) { unsigned long max; get_memsizes(); max = (setup->su_version >= 0x203) ? setup->ramdisk_max : 0x37FFFFFF; /* compute top of initrd only if user has not overridden it */ if (top_of_initrd == 0) { struct e820entry *e; /* look for highest E820_RAM that is under ramdisk_max strictly speaking we should also check that we have room for the ramdisk in the memory segment */ for (i = 0; i < meminfo.map_count; i++) { e = &meminfo.map[i]; if (e->type == E820_RAM && e->addr < max && (e->addr + e->size) > top_of_initrd) top_of_initrd = e->addr + e->size; } /*2004/05/08: memdisk needs 64k between initrd and the computed top */ top_of_initrd -= 0x10000; } if (top_of_initrd > max) top_of_initrd = max; /* Round down to next lower 4k boundary */ top_of_initrd &= ~0xFFF; printf("Top of ramdisk is %#X\n", top_of_initrd); if (rdmode == RD_TOP || rdmode == RD_HEXADDR) { long *dp, *sp; /*2004/05/08: now we have a true size rd, hence need to align tail pointer to 4k boundary up */ sp = (long *)((p = (unsigned char *)seg[S_RAMDISK]->p_paddr) + (i = ((seg[S_RAMDISK]->p_filesz + 0xfff) & ~0xfff))); /* * If user specified address, align dest tail pointer to 4k boundary below */ if (rdmode == RD_HEXADDR) dp = (long *)((rdaddr & ~0xfff) + i); else dp = (long *)top_of_initrd; /* Copy to destination by longwords, tail first; seg[] might get overwritten, save rd size first */ i = seg[S_RAMDISK]->p_filesz; while (sp > (long *)p) *--dp = *--sp; printf("Ramdisk at %#X, size %#X\n", (setup->su_ramdisk_start = (unsigned long)dp), (setup->su_ramdisk_size = i)); } else { /* leave ramdisk as loaded, just report */ printf("Ramdisk at %#X, size %#X\n", (setup->su_ramdisk_start = (unsigned long)seg[S_RAMDISK]->p_paddr), (setup->su_ramdisk_size = seg[S_RAMDISK]->p_filesz)); } } #ifdef DEBUG printf("Ready\n"); #endif #if DEBUG > 3 /* Delay so we can read display */ for (i = 0; i < 0x7ffffff; i++) ; #endif xstartlinux((unsigned long)setup); return (0); } #endif /* FIRST32LINUX */ #ifdef FIRST32DOS extern void printf(const char *, ...); extern void xstart(unsigned long, union infoblock *, struct bootp_t *); extern void exit(int); struct bootp_t bpcopy; void putchar(int c) { if (c == '\n') putchar('\r'); console_putc(c); } static inline void quit(void) { printf("Bad argument\n"); exit(0); } static void parse_elf_boot_notes( void *notes, union infoblock **rheader, struct bootp_t **rbootp) { unsigned char *note, *end; Elf_Bhdr *bhdr; Elf_Nhdr *hdr; bhdr = notes; if (bhdr->b_signature != ELF_BHDR_MAGIC) { return; } note = ((char *)bhdr) + sizeof(*bhdr); end = ((char *)bhdr) + bhdr->b_size; while (note < end) { unsigned char *n_name, *n_desc, *next; hdr = (Elf_Nhdr *)note; n_name = note + sizeof(*hdr); n_desc = n_name + ((hdr->n_namesz + 3) & ~3); next = n_desc + ((hdr->n_descsz + 3) & ~3); if (next > end) break; #if 0 printf("n_type: %x n_name(%d): n_desc(%d): \n", hdr->n_type, hdr->n_namesz, hdr->n_descsz); #endif if ((hdr->n_namesz == 10) && (memcmp(n_name, "Etherboot", 10) == 0)) { switch(hdr->n_type) { case EB_BOOTP_DATA: *rbootp = *((void **)n_desc); break; case EB_HEADER: *rheader = *((void **)n_desc); break; default: break; } } note = next; } } int first(struct ebinfo *eb, union infoblock *header, struct bootp_t *bootp) { #if DEBUG > 1 printf("&eb = %#X\n", &eb); #endif printf(MKNBI_VERSION "/" __FILE__ " (ELF)" " (GPL)\n"); #if DEBUG > 1 printf("eb = %#X, header = %#X, bootp = %#X\n", eb, header, bootp); #endif /* Sanity checks */ parse_elf_boot_notes(eb, &header, &bootp); if (header->img.magic != ELF_MAGIC || bootp->bp_op != BOOTP_REPLY) quit(); memcpy(&bpcopy, bootp, sizeof(bpcopy)); xstart(RELOC - 0x1000, header, &bpcopy); return (0); } #endif /* FIRST32DOS */ mknbi-1.4.4/first.dos0100644000175000001440000001000010110544077013141 0ustar kenusersڌȎ،.6>F~FFF O~&;u.&G;u$&G$<u1t!&:AuG6>.˾^ t&Eu&E&]f h &E &]  أj &0&n &Ap &At &Ar &Al &A w &A v Av r2Q&>uO&>t&>u?&&01r*FQv &8$u&> u&> &:r taPX6>.1> t &<u߹t ΀<u3뱃ێÿ' 6, u31Ɂ<u As"/~&E"&:mt&Eu & 1YQı%0YVt S0[^ DOS Net Boot Image Loader Version 0.8.1 mknbi-dos-1.4.4 GPLed by G. Kuhlmann 6mknbi-dos-1.4.4cScCMUSTANpp Error in load record data Invalid boot header magic number Invalid vendor magic ID Error while accessing ramdisk Wrong ramdisk image BOOTP record invalid RPL=JuQYPXJX..X uD<u.h .f .j <u ˺' .% <u˺T .v .z <uMuP.| . ~ uC/v sJr.w tu$0u.T .u 0 ..T vJS0r݀uʜ.T .u Rʀu.T ru 뼜.T ZS&'[PXUF]X0<<x t R0ҜT Zr0[\&'[[RQSPs2X[YZ;p r;n v [(s @uX[YZ0[u r .l 6t 11[0[[RQP XsYZ[r ċn p SQÈ11Ɋt ȁr S1 t PRZX[ـ?:r wIxȁ;p r w;n rY[VWQRP t f h Tt1ұ0؁UuȎ XZY_^û@.d {0[r00Ou%j A9wS´ 8[ t z * uz z +f h r=PUPFFNX].6~ .6| [. . Ȏм QRVWȎ[_^ZY. . Sv  &E u1&;u&=u uT ڌش/،9u9u u t/u1` &b &> &MP t ` z tR Z t ƒ¿1[0AP` NetB@h `P` NO NAME FAT12 mknbi-1.4.4/first32elf@0x92800.linux0100755000175000001440000001027610110544076015343 0ustar kenusers * ) ؎Ў$( ,* @ p pp,*  * ËD$USVWMVff _^[]USVW}( u V'f1f fPAMSfrf=PAMSufNft fufX)_^[]SVW11Ҹr$utȉf%fff f%ff__^[fJfUSVWEà fff ؎fofPfS˃f_^[].g f"f) ؎Ё( 1X( PX-( P(  ؎Ў f"fȎ؎fÉ') ( ( 8 ҉8 t-BÊ]uf^ ~9sZBK 4C,09w< u1j h8 Qi uCtt D$8D$49rD$48ELFu D$88th%8 H $_D$88 =cSc8 D$t=CMUt=STANu 8  8 T$4J1fz,t 8 C B,9|8 P 8 8 @ D$ fx@A8 v@ T$ D$B(@ D$D$f)fB ?fB"1|$Iq\$8 @=EthD$¸)9~B~C N~ BCNOC8@<ɉˆL$ Ʌɍ@~8:uNI@~~@D$ D$))D$t$F~a1|$I)9}HC ҋt$~8~&E<~u }bu\ <~u}cu :CNEECNCT$KJ;\$u8 8 8  t u$8 B8 B t t܅o8 ҉  =t@8 8 B8 8 R  =u8 8 38 =8 1҅uS78 u>?8 u)B8 uI8 ҃eM8 8 -8 Pu\Q8 8 8uDZ8 8 u.a8 8 t8  8 B¡8 fu6d8 8 t#8 @t< t< uid8 8 8 @t < t< 8 pphh8 58 8 8 8 :8 b8 8 : 8 8t8 :8 ruto8 8 t 8 Ns8 8 t 8 /a8 8 xt8 8 z8 MuC8 Š0< w C0< vl$H<%t&|$@tT$BT$PYF0< w F0< v>.uF0< w F0< vM9y|$@Yt T$BT$ PZ;uJ<#|$ $u$F>hu F>huFЃ |$@tD$T$@)T$D$,[^_]ÍD$Pt$j ÍD$ Pt$ t$ ÐST$1ɀ:\$ t9uB:u[S\$L$ ڊABu[S\$;L$ tB:uAt BAu[VSt$ >\$L$tB:uCtItBCtIu[^WVS\$19ڋ|$t$}: 28t )B9|1[^_Out of parameter space %@mknbi-1.4.4/first32.c (ELF) (GPL) EtherbootBad argument vganfsrootiprdbasememaskextendednormal0xrom%@:%@:topasisTop of ramdisk is %#X Ramdisk at %#X, size %#X 0123456789ABCDEF%d.mknbi-1.4.4/altboot.S0100644000175000001440000000775706536322472013136 0ustar kenusers! bootsect.S - boot sector for DOS ramdisk ! ! Copyright (C) 1996-1998 Gero Kuhlmann ! ! This program is free software; you can redistribute it and/or modify ! it under the terms of the GNU General Public License as published by ! the Free Software Foundation; either version 2 of the License, or ! any later version. ! ! This program is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! GNU General Public License for more details. ! ! You should have received a copy of the GNU General Public License ! along with this program; if not, write to the Free Software ! Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #ifndef ASM_DEBUG #undef ASM_DEBUG #endif #include "boot.inc" .text .org BOOT_OFFSET _main: jmp start nop ! Define boot record (defaults are for 1.44MB floppy disk) .ascii "MSDOS5.0" ! OEM name bpsect: .word SECT_SIZE ! bytes per sector spc: .byte BOOT_SPC ! number of sectors per cluster resvd: .word 1 ! number of reserved sectors fatnum: .byte 2 ! number of FATs dirnum: .word BOOT_DIRNUM ! number of entries in root directory secnum: .word BOOT_SECNUM ! total number of sectors on disk fmtid: .byte BOOT_FORMAT ! media ID spfat: .word BOOT_SPFAT ! sectors per fat sptrk: .word BOOT_SPTRK ! sectors per track .word 2 ! number of heads hidden: .long 0 ! number of hidden sectors .long 0 ! total number of sectors on disk bootid: .byte BOOT_ID ! BIOS number of boot device .byte 0 ! head number of boot sector .byte 0x29 ! disk attributes .long 0 ! volume number .ascii "NO NAME " ! volume name .ascii "FAT12 " ! filesystem name iosys: .word 3 ! no of sectors in IO.SYS ! Start of main routine start: cli xor ax,ax mov ss,ax mov sp,#_main ! set stack to beginning of code mov ds,ax ! set segment registers mov es,ax sti xor dx,dx int 0x13 ! initialize disk system ! Compute the logical number of the first sector of the data area. We ! assume that IO.SYS is always located at the beginning. This might ! not be true for a real DOS disk, but is always correct for a disk ! image produced by mknbi. mov al,fatnum mul word ptr (spfat) ! compute size of FAT add ax,word ptr (hidden+0) adc dx,word ptr (hidden+2) ! add number of hidden sectors add ax,resvd adc dx,#0 ! add number of reserved sectors mov bx,#DIR_SEG * 16 call rdsect ! read first directory sector jc doerr1 push dx mov cx,ax mov ax,#32 mul word ptr (dirnum) ! compute size of root directory mov bx,bpsect ! area add ax,bx ! round up to sector size dec ax div bx add ax,cx ! add number of sectors used by pop dx ! root directory adc dx,#0 ! Now load the first 3 sectors of IO.SYS at 0x0070. push dx push ax mov bx,#IOSYS_SEG * 16 ! get offset to IO.SYS segment from mov cx,iosys ! start of current data segment (0) start1: call rdsect jc doerr add ax,#1 adc dx,#0 ! continue with next sector add bx,bpsect loop start1 pop bx pop ax mov si,#endata mov ch,fmtid ! prepare registers for IO.SYS mov dl,bootid jmpi 0,IOSYS_SEG ! call IO.SYS ! Print error message and terminate doerr: pop ax pop ax doerr1: mov si,#errmsg doerr2: lodsb or al,al jz doerr3 mov ah,#0x0e mov bx,#7 ! print using BIOS int 0x10 jmp doerr2 doerr3: xor ax,ax int 0x16 ! wait for key press int 0x19 ! reboot the system ! Read one logical sector into ES:BX rdsect: push ax push dx push cx div word ptr (sptrk) inc dl mov cl,dl ! convert logical sector number into mov dh,al ! cylinder/head/sector format and dh,#0x01 shr al,#1 mov ch,al mov ax,#0x0201 mov dl,bootid ! read one sector from ramdisk int 0x13 pop cx pop dx pop ax ret ! Data area errmsg: .byte 0x0d, 0x0a .ascii "Ramdisk error - press any key to continue" .byte 0x0d, 0x0a .byte 0 endata: ! The end of the boot sectors has to contain the boot signature. .org BOOT_SIG_OFS .word BOOT_SIG ! boot sector signature mknbi-1.4.4/md5.c0100644000175000001440000000774607500637442012173 0ustar kenusers#ifdef PASSWD /* * This is an implementation of the "MD5 Message Digest Algorithm" as * described in * Bruce Schneier 'Applied Cryptography', pages 436-441, 2nd Edition, 1996, * John Wiley & Sons, Inc., ISBN 0-471-11709-9. * The MD5 algorithm has been invented by Ron Rivest/"RSA Data Security, Inc."; * Bruce Schneier refers to RFC1321 as the original publication. * * This implementation is copyright 1997 by M. Gutschke. * * This implementation has been optimized for size rather than for speed; * there are a few assumptions that require a little-endian architecture. * The maximum input length is 4GB. */ #include "stddef.h" #include "string.h" #include "etherboot.h" static unsigned long md5_buf[16]; static unsigned long ABCD[4]={0x67452301L,0xefcdab89L,0x98badcfeL,0x10325476L}; static unsigned long md5_len = 0; static unsigned long F(unsigned long X,unsigned long Y,unsigned long Z) { return((X&Y)|((~X)&Z)); } static unsigned long G(unsigned long X,unsigned long Y,unsigned long Z) { return((X&Z)|(Y&(~Z))); } static unsigned long H(unsigned long X,unsigned long Y,unsigned long Z) { return(X^Y^Z); } static unsigned long I(unsigned long X,unsigned long Y,unsigned long Z) { return(Y^(X|(~Z))); } static inline unsigned long rotate(unsigned long i,int s) { return((i << s) | (i >> (32-s))); } static unsigned long ff(unsigned long (*fnc)(unsigned long,unsigned long, unsigned long), unsigned long a,unsigned long b,unsigned long c, unsigned long d,unsigned long M,int s, unsigned long t) { return(b+(rotate((a+fnc(b,c,d)+M+t),s))); } static void md5_loop(void) { static unsigned char shifts[4][4] = { {22,17,12,7},{20,14,9,5},{23,16,11,4},{21,15,10,6}}; static unsigned char idx[64] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, 1, 6,11, 0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 5, 8,11,14, 1, 4, 7,10,13, 0, 3, 6, 9,12,15, 2, 0, 7,14, 5,12, 3,10, 1, 8,15, 6,13, 4,11, 2, 9 }; static unsigned long masks[64] = { 0xd76aa478L,0xe8c7b756L,0x242070dbL,0xc1bdceeeL, 0xf57c0fafL,0x4787c62aL,0xa8304613L,0xfd469501L, 0x698098d8L,0x8b44f7afL,0xffff5bb1L,0x895cd7beL, 0x6b901122L,0xfd987193L,0xa679438eL,0x49b40821L, 0xf61e2562L,0xc040b340L,0x265e5a51L,0xe9b6c7aaL, 0xd62f105dL,0x02441453L,0xd8a1e681L,0xe7d3fbc8L, 0x21e1cde6L,0xc33707d6L,0xf4d50d87L,0x455a14edL, 0xa9e3e905L,0xfcefa3f8L,0x676f02d9L,0x8d2a4c8aL, 0xfffa3942L,0x8771f681L,0x6d9d6122L,0xfde5380cL, 0xa4beea44L,0x4bdecfa9L,0xf6bb4b60L,0xbebfbc70L, 0x289b7ec6L,0xeaa127faL,0xd4ef3085L,0x04881d05L, 0xd9d4d039L,0xe6db99e5L,0x1fa27cf8L,0xc4ac5665L, 0xf4292244L,0x432aff97L,0xab9423a7L,0xfc93a039L, 0x655b59c3L,0x8f0ccc92L,0xffeff47dL,0x85845dd1L, 0x6fa87e4fL,0xfe2ce6e0L,0xa3014314L,0x4e0811a1L, 0xf7537e82L,0xbd3af235L,0x2ad7d2bbL,0xeb86d391L}; static unsigned long (*fncs[4])(unsigned long,unsigned long, unsigned long) = { F,G,H,I }; int i,j,k,l; unsigned long abcd[4]; memcpy(abcd, ABCD, 16); for (i = j = 0; j < 4; j++) /* rounds FF..II */ for (k = 0; k < 4; k++) /* 0..3 */ for (l = 4; l--; i++) /* a,b,c,d..b,c,d,a */ abcd[(l+1)&3] = ff(fncs[j], abcd[(l+1)&3],abcd[(l+2)&3],abcd[(l+3)&3],abcd[l], md5_buf[idx[i]],shifts[j][l],masks[i]); for (i = 4; i--; ) ABCD[i] += abcd[i]; return; } void md5_put(unsigned int ch) { /* this code assumes a little endian architecture! */ ((unsigned char *)md5_buf)[md5_len%64] = ch; if (((++md5_len)%64) == 0) md5_loop(); return; } void md5_done(unsigned char *buf) { unsigned long len = md5_len; int i; /* this code assumes a little endian architecture! */ md5_put(0x80); while ((md5_len%64) != 56) md5_put(0); md5_put(len << 3); md5_put(len >> 5); md5_put(len >> 13); md5_put(len >> 21); for (i = 4; i--; ) md5_put(0); memcpy(buf, ABCD, 16); md5_len = 0; {static unsigned long init[4]={ 0x67452301L,0xefcdab89L,0x98badcfeL,0x10325476L}; memcpy(ABCD, init, 16); } return; } #endif mknbi-1.4.4/md5.h0100644000175000001440000000011207500640147012150 0ustar kenusersextern void md5_done(unsigned char *); extern void md5_put(unsigned int); mknbi-1.4.4/nfl.c0100644000175000001440000004147007733605554012264 0ustar kenusers#include "stddef.h" #include "string.h" #include "linux-asm-io.h" #include "string.h" #include "etherboot.h" #include "startmenu.h" #include "elf_boot.h" #include "nfl.h" /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. */ /* This is an example program which shows how the extension routine feature in Etherboot 5.0 works. This program presents a list of valid boot images from a data segment that is loaded into another area of memory, and prompts the user for a number, and modifies the bootp record to the filename to be loaded. You can make the menu program as elaborate as you like, the sky is the limit. Ideally, there should be a menu generation program that takes a high-level description of menus and valid inputs and creates a data file to be loaded to the data area. The menu program should agree with the menu generator on the layout of the data area. This program is linked to run at 0x60000, and expects to find config data at 0x70000. This means the code can be up to 64kB long. When the program starts it receives 3 parameters from Etherboot: Pointer to ebinfo structure Pointer to image header structure (either a tagged or ELF image header) Pointer to bootp/DHCP reply obtained by Etherboot from bootpd or DHCPD Etherboot expects this program to return an int. The values have these meanings: <0 Do not use 0 Same as 1, for implementation reasons 1 Redo tftp with possibly modified bootp record 2 Redo bootp and tftp 255 Exit Etherboot Observe that this program causes Etherboot to load a different program next by modifying the contents of the filename field in the bootp record and then returning 1. It can also send parameters to the next program by modifying tag 129 in the bootp record. This is how the menu system works. The data segment that this particular program expects is of the form choice 1\nchoice 2\nchoice 3\n\0 where the \n are newlines and the \0 the teminating zero byte. Therefore you can create this file with a Unix text editor (but see next paragraph). choice 1, etc are the pathnames or filenames of the next file to load by TFTP. If the string starts with / then it's assumed to be a pathname and the whole of the bootp filename area is replaced by it, otherwise just the filename portion of the pathname, i.e. the same directory as the menu file is assumed. This program also illustrates the use of a timeout to select a default item by using currticks() to obtain the value of the BIOS clock and console_ischar to determine if a character has been typed at the keyboard. Commentary: This program is just to illustrate a very simple menu system. There are known bugs: mknbi-menu/mkelf-menu does not add the ending NUL byte, but this is present due to the NUL fill to the next block boundary. If the size of the data goes exactly up to a block boundary, then it is possible there will be a spurious final item that goes up the next NUL byte in memory. Another bug is that there is no overflow checking when writing into bootp->bp_file. Yet another bug is that there is no facility to correct input entry on lines. getline() should be smarter. */ /* Memory layout assumed by mknbi and this program 0x60000-0x6FFFF 64 kB Menu program 0x70000-0x7FFFF 64 kB Menu data (initial) */ #define NFL_VERSION "0.56" #define TIMEOUT 10 /* seconds */ #define MENU_DATA ((char *)0x70000) #define MENU_COLS 75 #define MENU_ROWS 14 #define MAX_ENTRIES 100 static int dbg_count1=0; static char *menu_entries[MAX_ENTRIES]; static unsigned short num_entries; static unsigned short cur_entry; static unsigned short top_entry; static int timeout = 0; /* Color settings. */ static int color_fg = 7; static int color_bg = 4; static int number_entries = 0; /* Default Menu Size */ static unsigned short menu_ulx = 1; static unsigned short menu_uly = 1; static unsigned short menu_rows = 0x0800; static unsigned short menu_cols = 0x0800; /* Terminal types. */ static int terminal = TERMINAL_CONSOLE; /* Defined in ANSI.C */ extern unsigned short rows, columns, attr; extern void ansi_putc(unsigned int); extern void ansi_reset(void); extern void enable_cursor(int); extern void printf(const char *, ...); extern void sprintf(char *, const char *, ...); extern char *strcat(char *, const char *); extern char *strncat(char *, const char *, unsigned int); /* --------------------------------------------------------------------------*/ void putchar(int c) { if (c == '\n') ansi_putc('\r'); ansi_putc(c); } /* --------------------------------------------------------------------------*/ int getchar(void) { int c; c = console_getc(); if (c == '\r') c = '\n'; return (c); } /* Wait for a keypress and return its code. --------------------------------------------------------------------------*/ int getkey (void) { int c = -1; if ((terminal & TERMINAL_CONSOLE) #ifdef SUPPORT_HERCULES || (terminal & TERMINAL_HERCULES) #endif /* SUPPORT_HERCULES */ ) c = console_getkey (); #ifdef SUPPORT_SERIAL else if (terminal & TERMINAL_SERIAL) c = serial_getkey (); #endif /* SUPPORT_SERIAL */ return c; } /* Check if a key code is available. --------------------------------------------------------------------------*/ int checkkey (void) { int c = -1; if ((terminal & TERMINAL_CONSOLE) #ifdef SUPPORT_HERCULES || (terminal & TERMINAL_HERCULES) #endif /* SUPPORT_HERCULES */ ) c = console_checkkey (); #ifdef SUPPORT_SERIAL if (terminal & TERMINAL_SERIAL) c = serial_checkkey (); #endif /* SUPPORT_SERIAL */ return c; } /* Translate a special key to a common ascii code. --------------------------------------------------------------------------*/ int translate_keycode (int c) { #if 0 //def SUPPORT_SERIAL if (terminal & TERMINAL_SERIAL) { /* In a serial terminal, things are complicated, because several key codes start from the character ESC, while we want to accept ESC itself. */ if (c == '\e') { int start; /* Get current time. */ start = currticks (); while (checkkey () == -1) { /* Wait for a next character, at least for 0.1 sec (18.2 ticks/sec). */ int now; now = currticks (); if (now - start >= 2) return c; } c = getkey (); if (c == '[') { int c1, c2; /* To filter illegal states. */ c = 0; c1 = getkey (); switch (c1) { case 'A': /* KEY_UP */ c = 16; break; case 'B': /* KEY_DOWN */ c = 14; break; case 'C': /* KEY_RIGHT */ c = 6; break; case 'D': /* KEY_LEFT */ c = 2; break; case 'F': /* End */ c = 5; break; case 'H': /* Home */ c = 1; break; case '1': c2 = getkey (); if (c2 == '~') { /* One of control keys (pos1,....). */ c = 1; } break; case '3': c2 = getkey (); if (c2 == '~') { /* One of control keys (del,....). */ c = 4; } break; case '4': /* Del */ c = 4; break; } } } } else # endif /* SUPPORT_SERIAL */ { switch (c) { case KEY_LEFT: c = 2; break; case KEY_RIGHT: c = 6; break; case KEY_UP: c = 16; break; case KEY_DOWN: c = 14; break; case KEY_HOME: c = 1; break; case KEY_END: c = 5; break; case KEY_DC: c = 4; break; case KEY_BACKSPACE: c = 8; break; } } return ASCII_CHAR (c); } /* Get a line, ignore characters after array limit reached. Echo the character if the flag says so. --------------------------------------------------------------------------*/ int getline(char *line, int length, int echo) { int c; char *p = line; while ((c = getchar()) != '\n') { if (p < &line[length-1]) { /* within array? */ if (echo) ansi_putc(c); *p++ = c; } } *p++ = '\0'; if (echo) ansi_putc('\n'); return (line - p); } /* Build menu entries array starting at index one for clarity... --------------------------------------------------------------------------*/ int scan_entries(void) { int i = 0, first_entry_char = 1; char *p = MENU_DATA; if (p == '\0') return( 0 ); do { /* Skip leading white-space */ while ((*p == '\b') || (*p == '\t')) p++; menu_entries[i+1] = p; while ((*p != '\0') && (*p != '\n')) { /* Point to next character */ p++; /* At least one non-blank character, index to next entry */ if (first_entry_char) { first_entry_char = 0; i++; } } if (*p == '\0') break; if (*p == '\n') { /* Null-terminate this entry string */ *p++ = '\0'; /* Set 'waiting for first entry character' flag */ first_entry_char = 1; } } while (i < MAX_ENTRIES); return ( i ); } /* NOTE: ANSI defines (1,1) as upper left corner, IBM BIOS uses (0,0) --------------------------------------------------------------------------*/ void gotoxy (int x, int y) { printf ("\e[%d;%dH", y+1, x+1); } /* Display screen border. --------------------------------------------------------------------------*/ static void show_border ( void ) { unsigned short i; int disp_ul = DISP_UL; int disp_ur = DISP_UR; int disp_ll = DISP_LL; int disp_lr = DISP_LR; int disp_horiz = DISP_HORIZ; int disp_vert = DISP_VERT; /* Clear the screen, and set foreground and background attributes */ for (i = 0; i num_entries) bot_entry = num_entries; */ #if 0 gotoxy( 30, 15 ); printf( "[%d]SE(1R:%d, #:%d, cur:%d, top:%d", dbg_count1++, first_row, num_rows, cur_entry, top_entry ); #endif /* for (i = 0; i <= bot_entry-top_entry; i++) { */ for (i = first_row; ((i < first_row+num_rows) && ((top_entry+i-1) <= num_entries)); i++) { *szTmp = 0; *szBuff = 0; if (number_entries) { if ((top_entry+i-1) <= 9) strncat( szBuff, " ", len_entry ); sprintf ( szTmp, "%d. ", (top_entry+i-1) ); strncat( szBuff, szTmp, len_entry ); // len_entry -= strlen( szBuff ); } /* add the entry to the current string */ strncat ( szBuff, menu_entries[top_entry+i-1], len_entry ); pad_printxy( szBuff, menu_ulx+1, menu_uly+i, len_entry, ((top_entry+i-1) == cur_entry) ); #if 0 if (i == first_row) { gotoxy( 30, 16); printf( "%d. %d [%s]", i, cur_entry, szBuff ); gotoxy( 30, 17); printf( " " ); gotoxy( 30, 18); printf( " " ); gotoxy( 30, 19); printf( " " ); } else if (i == first_row+1) { gotoxy( 30,17); printf( "%d. %d [%s]", i, cur_entry, szBuff ); } #endif } if (top_entry != 1) { *szBuff = 0; sprintf ( szBuff, " %c ", disp_up ); pad_printxy( szBuff, menu_ulx+1, menu_uly+1, len_entry, 0 ); #if 0 gotoxy( 30, 18); printf( "%d. %d [%s]", i, cur_entry, szBuff ); #endif } if ((top_entry+menu_rows-1) < num_entries) { *szBuff = 0; sprintf ( szBuff, " %c ", disp_down ); pad_printxy( szBuff, menu_ulx+1, menu_uly+menu_rows, len_entry, 0 ); #if 0 gotoxy( 30, 19); printf( "%d. %d [%s]", i, cur_entry, szBuff ); #endif } } /* --------------------------------------------------------------------------*/ static int select_entry ( void ) { int c, c1, count=0; unsigned short bot_entry; unsigned short tmp; ansi_reset(); enable_cursor(0); printf ( "\e[3%dm\e[4%dm", color_fg, color_bg ); gotoxy( 20, 5 ); tmp = columns-5; if (menu_cols > tmp) menu_cols = tmp; tmp = rows-3; if (menu_rows > tmp) menu_rows = tmp; show_border (); top_entry = 1; cur_entry = 1; bot_entry = top_entry+menu_rows-1; show_entries ( 1, menu_rows ); while (1) { if ((checkkey () != -1) || (timeout == -1)) { /* Key was pressed, show which entry is selected before GETKEY, since we're comming in here also on TIMEOUT == -1 and hang in GETKEY */ c1 = getkey(); c = translate_keycode( c1 ); #if 0 gotoxy( 30, 10 ); printf( "\e[K%d [%X]->[%X]", count++, c1, c ); gotoxy( 30, 11 ); printf( "cur:%d top:%d bot:%d rows:%d num_entries:%d", cur_entry, top_entry, bot_entry, menu_rows, num_entries ); #endif /* We told them above (at least in SUPPORT_SERIAL) to use '^' or 'v' so accept these keys. */ if (c == 16 || c == '^') { if (terminal & TERMINAL_DUMB) { if (cur_entry > 1) cur_entry--; } else { if (cur_entry > 1) { cur_entry--; if ((cur_entry == top_entry) && (top_entry > 1)) { top_entry--; bot_entry--; show_entries ( 1, (bot_entry-top_entry+1) ); } else show_entries ( (cur_entry-top_entry+1), 2 ); } } } if ((c == 14 || c == 'v') && ((cur_entry + 1) <= num_entries)) { if (terminal & TERMINAL_DUMB) cur_entry++; else { if (cur_entry < num_entries) { cur_entry++; if ((cur_entry >= bot_entry) && (bot_entry < num_entries)) { top_entry++; bot_entry++; show_entries ( 1, (bot_entry-top_entry+1) ); } else show_entries( (cur_entry-top_entry), 2 ); } } } if (c == '\r') { return( cur_entry ); } } } } /* Set new filename in bootp path --------------------------------------------------------------------------*/ void set_file_to_load( struct bootp_t *bootp, char *file2load ) { char *p, *szPath = bootp->bp_file; if (*file2load != '/') { /* if reletive path, append to current path */ if ((p = strrchr( szPath, '/')) != 0) szPath = p+1; } strcpy( szPath, file2load ); } static void parse_elf_boot_notes( void *notes, union infoblock **rheader, struct bootp_t **rbootp) { unsigned char *note, *end; Elf_Bhdr *bhdr; Elf_Nhdr *hdr; bhdr = notes; if (bhdr->b_signature != ELF_BHDR_MAGIC) { return; } note = ((char *)bhdr) + sizeof(*bhdr); end = ((char *)bhdr) + bhdr->b_size; while (note < end) { unsigned char *n_name, *n_desc, *next; hdr = (Elf_Nhdr *)note; n_name = note + sizeof(*hdr); n_desc = n_name + ((hdr->n_namesz + 3) & ~3); next = n_desc + ((hdr->n_descsz + 3) & ~3); if (next > end) break; #if 0 printf("n_type: %x n_name(%d): n_desc(%d): \n", hdr->n_type, hdr->n_namesz, hdr->n_descsz); #endif if ((hdr->n_namesz == 10) && (memcmp(n_name, "Etherboot", 10) == 0)) { switch(hdr->n_type) { case EB_BOOTP_DATA: *rbootp = *((void **)n_desc); break; case EB_HEADER: *rheader = *((void **)n_desc); break; default: break; } } note = next; } } /* --------------------------------------------------------------------------*/ int menu(struct ebinfo *eb, union infoblock *header, struct bootp_t *bootp) { int i; parse_elf_boot_notes(eb, &header, &bootp); num_entries = scan_entries(); if (!num_entries) { printf( "ERROR: No menu entries found\n" #if 1 "Rebuild menu program with a menu configuration file.\n" #endif "Press any key:" ); getchar(); /* 2 = Tell Etherboot to retry */ return( 2 ); } i = select_entry( ); #if 0 gotoxy( 30, 13 ); printf( "Selected entry:%d [%s]", i, menu_entries[i] ); getchar(); #else console_cls(); #endif if (memcmp(menu_entries[i], "Quit Etherboot", sizeof("Quit Etherboot")) == 0) return (255); set_file_to_load ( bootp, menu_entries[ i ] ); return ( 1 ); } mknbi-1.4.4/nfl.h0100644000175000001440000001454007610224647012261 0ustar kenusers #define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ #define K_STATUS 0x64 /* keyboard status */ #define K_CMD 0x64 /* keybd ctlr command (write-only) */ #define K_OBUF_FUL 0x01 /* output buffer full */ #define K_IBUF_FUL 0x02 /* input buffer full */ #define KC_CMD_WIN 0xd0 /* read output port */ #define KC_CMD_WOUT 0xd1 /* write output port */ #define KB_OUTPUT_MASK 0xdd /* enable output buffer full interrupt enable data line enable clock line */ #define KB_A20_ENABLE 0x02 /* Codes for getchar. */ #define ASCII_CHAR(x) ((x) & 0xFF) #define KEY_LEFT 0x4B00 #define KEY_RIGHT 0x4D00 #define KEY_UP 0x4800 #define KEY_DOWN 0x5000 #define KEY_IC 0x5200 /* insert char */ #define KEY_DC 0x5300 /* delete char */ #define KEY_BACKSPACE 0x0008 #define KEY_HOME 0x4700 #define KEY_END 0x4F00 #define KEY_NPAGE 0x4900 #define KEY_PPAGE 0x5100 /* Default video attributes */ #define A_NORMAL 0x7 #define A_REVERSE 0x70 /* Define ACS_* ourselves, since the definitions are not consistent among various curses implementations. */ #undef ACS_ULCORNER #undef ACS_URCORNER #undef ACS_LLCORNER #undef ACS_LRCORNER #undef ACS_HLINE #undef ACS_VLINE #undef ACS_LARROW #undef ACS_RARROW #undef ACS_UARROW #undef ACS_DARROW #define ACS_ULCORNER '+' #define ACS_URCORNER '+' #define ACS_LLCORNER '+' #define ACS_LRCORNER '+' #define ACS_HLINE '-' #define ACS_VLINE '|' #define ACS_LARROW '<' #define ACS_RARROW '>' #define ACS_UARROW '^' #define ACS_DARROW 'v' /* Special graphics characters for IBM displays. */ #define DISP_UL 218 #define DISP_UR 191 #define DISP_LL 192 #define DISP_LR 217 #define DISP_HORIZ 196 #define DISP_VERT 179 #define DISP_LEFT 0x1b #define DISP_RIGHT 0x1a #define DISP_UP 0x18 #define DISP_DOWN 0x19 #ifndef ASM_FILE /* * Below this should be ONLY defines and other constructs for C code. */ /* The flag for debug mode. */ extern int debug; /* Color settings */ extern int normal_color, highlight_color; /* If LINEAR is nonzero, then set the Intel processor to linear mode. Otherwise, bit 20 of all memory accesses is always forced to zero, causing a wraparound effect for bugwards compatibility with the 8086 CPU. */ void gateA20 (int linear); /* memory probe routines */ int get_memsize (int type); int get_eisamemsize (void); /* Get the linear address of a ROM configuration table. Return zero, if fails. */ unsigned long get_rom_config_table (void); /* Get APM BIOS information. */ void get_apm_info (void); /* Get VBE controller information. */ /*int get_vbe_controller_info (struct vbe_controller *controller);*/ /* Get VBE mode information. */ /*int get_vbe_mode_info (int mode_number, struct vbe_mode *mode);*/ /* Set VBE mode. */ int set_vbe_mode (int mode_number); /* Return the data area immediately following our code. */ int get_code_end (void); /* low-level timing info */ /*int getrtsecs (void); int currticks (void);*/ /* Clear the screen. */ void cls (void); /* The console part of cls. */ void console_cls (void); /* Turn off cursor. */ void console_nocursor (void); /* Get the current cursor position (where 0,0 is the top left hand corner of the screen). Returns packed values, (RET >> 8) is x, (RET & 0xff) is y. */ int getxy (void); /* The console part of getxy. */ int console_getxy (void); /* Set the cursor position. */ void gotoxy (int x, int y); /* The console part of gotoxy. */ void console_gotoxy (int x, int y); /* The console part of putchar. */ void console_putchar (int c); /* Wait for a keypress, and return its packed BIOS/ASCII key code. Use ASCII_CHAR(ret) to extract the ASCII code. */ int getkey (void); /* The console part of getkey. */ int console_getkey (void); /* Like GETKEY, but doesn't block, and returns -1 if no keystroke is available. */ int checkkey (void); /* The console part of checkkey. */ int console_checkkey (void); /* Sets text mode character attribute at the cursor position. See A_* constants defined above. */ void set_attrib (int attr); /* The console part of set_attrib. */ void console_setattrib (int attr); /* The table for a builtin. */ struct builtin { /* The command name. */ char *name; /* The callback function. */ int (*func) (char *, int); /* The combination of the flags defined above. */ int flags; /* The short version of the documentation. */ char *short_doc; /* The long version of the documentation. */ char *long_doc; }; /* All the builtins are registered in this. */ extern struct builtin *builtin_table[]; extern int show_menu; /* Control the auto fill mode. */ extern int auto_fill; /* This variable specifies which console should be used. */ extern int terminal; #define TERMINAL_CONSOLE (1 << 0) /* keyboard and screen */ #define TERMINAL_SERIAL (1 << 1) /* serial console */ #define TERMINAL_HERCULES (1 << 2) /* hercules */ #define TERMINAL_DUMB (1 << 16) /* dumb terminal */ void init_builtins (void); void init_config (void); char *skip_to (int after_equal, char *cmdline); struct builtin *find_command (char *command); #endif void init_bios_info (void); /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. */ /* * Definitions of data structures generated by the menu compiler * and expected by the menu program. All offsets are from the * beginning of the data area. */ /* * Structure describing the data area, starts at 0. */ struct menu_header { char major, minor; /* Versions */ unsigned short flags; /* Capabilities */ unsigned int timeout; /* Global timeout */ unsigned int selectprompt; /* Offset of string saying Select... */ unsigned int confirmprompt; /* Offset of string saying Confirm... */ unsigned int nmenus; /* Number of menus stored */ /* Here follow unsigned int offsets of menus */ }; /* * Structure describing one menu. The number of items is one * greater than the last valid index. The 0th item holds the * data to be displayed before any user input. */ struct menu { unsigned int timeout; /* Timeout for this menu */ unsigned int nitems; /* Items in this menu */ /* Here follow unsigned int offsets of items */ }; /* * Structure describing one item in a menu. */ struct item { unsigned int title; }; mknbi-1.4.4/spec.txt0100644000175000001440000005020107533722301013010 0ustar kenusers Draft Net Boot Image Proposal 0.3 Jamie Honan and Gero Kuhlmann, gero AT minix PERIOD han PERIOD de June 15, 1997 This is the specification of the "tagged image" format ______________________________________________________________________ Table of Contents 1. Note 2. Preamble - the why 3. The target 4. Net Boot Process Description. 5. Image Format with Initial Magic Number. 6. Boot prom entry points. 7. Example of a boot image. 8. Terms 9. References ______________________________________________________________________ 11.. NNoottee In order to provide more functionality to the boot rom code Jamie's draft has been changed a little bit. All of Gero Kuhmnann's changes are preceded and followed by ((ggkk)). All of Ken Yap's changes are preceded and followed by ((kkyy)). Gero Kuhlmann 22.. PPrreeaammbbllee -- tthhee wwhhyy Whilst researching what other boot proms do (at least those implementing TCP/IP protocols) it is clear that each 'does their own thing' in terms of what they expect in a boot image. If we could all agree on working toward an open standard, O/S suppliers and boot rom suppliers can build their products to this norm, and be confident that they will work with each other. This is a description of how I will implement the boot rom for Linux. I believe it to be flexible enough for any OS that will be loaded when a PC boots from a network in the TCP/IP environment. It would be good if this could be turned into some form of standard. This is very much a first draft. I am inviting comment. The ideas presented here should be independant of any implementation. In the end, where there is a conflict between the final of this draft, and an implementation, this description should prevail. The terms I use are defined at the end. ((ggkk))IMPORTANT NOTE: The scope of this document starts at the point where the net boot process gains control from the BIOS, to where the booted image reaches a state from which there is no return to the net boot program possible.((ggkk)) 33.. TThhee ttaarrggeett The target is to have a PC retrieve a boot image from a network in the TCP/IP environment. ((ggkk))The boot may take place from a network adaptor rom, from a boot floppy.((ggkk)) 44.. NNeett BBoooott PPrroocceessss DDeessccrriippttiioonn.. ((ggkk))The net boot process is started as a result of the PC boot process. The net boot program can reside on a rom, e.g. on an adaptor card, or in ram as a result of reading off disk.((ggkk)) The boot process may execute in any mode (e.g. 8086, 80386) it desires. When it jumps to the start location in the boot image, it must be in 8086 mode and be capable of going into any mode supported by the underlying processor. The image cannot be loaded into address spaces below 10000h((kkyy:: TThhiiss rreessttrriiccttiioonn rreemmoovveedd iinn EEtthheerrbboooott)), or between A0000h through FFFFFh, or between 98000h((kkyy:: CChhaannggeedd ttoo 9944000000hh iinn EEtthheerrbboooott 55..xx oonnwwaarrddss)) through 9FFFFh. ((ggkk))Only when the image is not going to return to the boot process, all the memory is available to it once it has been started, so it can relocate parts of itself to these areas.((ggkk)) The boot process must be capable of loading the image into all other memory locations. Specifically, where the machine supports this, this means memory over 100000h. The net boot process must execute the bootp protocol, followed by the tftp protocol, as defined in the relevant rfc's. The file name used in the tftp protocol must be that given by the bootp record. If less than 512 bytes are loaded, the net boot process attempts to display on the screen any ascii data at the start of the image. The net boot process then exits in the normal manner. For a boot prom, this will allow normal disk booting. ((ggkk))Reference to DOS deleted.((ggkk)) When the first 512 bytes have been loaded, the boot process checks for an initial magic number, which is defined later. If this number is present, the net process continues loading under the control of the image format. The image, which is described later, tells the net boot process where to put this record and all subsequent data. If no initial magic number is present the net boot process checks for a second magic number at offset 510. If the magic number 510 = 55h, 511 = AAh, then the net process continues. If this second magic number is not present, then the net boot process terminates the tftp protocol, displays an error message and exits in the normal manner. If no initial magic number is present and the second one is, the net boot process relocates the 512 bytes to location 7c00h. The net boot process continues to load any further image data to 10000h up. This data can overwrite the first 512 boot bytes. If the image reaches 98000h, then any further data is continued to be loaded above 100000h. When all the data has been loaded, the net boot process jumps to location 0:7c00.((kkyy))NNoo lloonnggeerr ssuuppppoorrtteedd iinn EEtthheerrbboooott((kkyy)) ((ggkk))When the net boot program calls the image, it places 2 far pointers onto the stack, in standard intel order (e.g. segment:offset representation). The first far pointer which immediately follows the return address on the stack, points to the loaded boot image header. The second far pointer which is placed above the first one, shows to the memory area where the net boot process saved the bootp reply. If the boot image is flagged as being returnable to the boot process, the boot program has to provide the boot image with interrupt vector 78h. It's an interface to services provided by the net boot program (see below for further description). If the boot image is not flagged as being returnable to the boot process, before the boot image is called, the boot program has to set the system into a state in which it was before the net boot process has started.((ggkk)) 55.. IImmaaggee FFoorrmmaatt wwiitthh IInniittiiaall MMaaggiicc NNuummbbeerr.. The first 512 bytes of the image file contain the image header, and image loading information records. This contains all the information needed by the net boot process as to where data is to be loaded. The magic number (in time-honoured tradition (well why not?)) is: ______________________________________________________________________ 0 = 36h 1 = 13h 2 = 03h 3 = 1Bh ______________________________________________________________________ Apart from the two magic numbers, all words and double words are in PC native endian. Including the initial magic number the header record is: ______________________________________________________________________ +---------------------+ | | | Initial Magic No. | 4 bytes +---------------------+ | | | Flags and length | double word +---------------------+ | | | Location Address | double word in ds:bx format +---------------------+ | | | Execute Address | double word in cs:ip format +---------------------+ ______________________________________________________________________ The Location address is where to place the 512 bytes. The net boot process does this before loading the rest of the image. The location address cannot be one of the reserved locations mentioned above, but must be an address lower than 100000h. The rest of the image must not overwrite these initial 512 bytes, placed at the required location. The writing of data by the net boot process into these 512 bytes is deprecated. These 512 bytes must be available for the image to interogate once it is loaded and running. The execute address is the location in cs:ip of the initial instruction once the full image has been loaded. This must be lower than 100000h, since the initial instructions will be executed in 8086 mode. When the jump (actually a far call) is made to the boot image, the stack contains a far return address, with a far pointer parameter above that, pointing to the location of this header. ((kkyy)) If bit 31 in the flags is set, then the execute address is interpreted as a linear 32-bit address, and a call is made to this address. There is no restriction on the range of the execute address. The arguments to the routine are: a pointer to an Etherboot specific header, a pointer to the tagged image header, and a pointer to the bootp reply. The called routine may return to the boot loader.((kkyy)) The flags and length field is broken up in the following way: Bits 0 to 3 (lowest 4 bits) define the length of the non-vendor header in double words. Currently the value is 4. Bits 4 to 7 define the length required by the vendor extra information in double words. A value of zero indicates no extra vendor information. ((ggkk))Bit 8 is set if the boot image can return to the net boot process after execution. If this bit is not set the boot image does never return to the net boot process, and the net boot program has to set the system into a clean state before calling the boot image.((ggkk)) ((kkyy))Bit 31 is set if the execute address of the boot image is a linear 32-bit address to be called. The boot image may return to the boot loader.((kkyy)) ((ggkk++kkyy))Bits 9 to 30 are reserved for future use and must be set to zero.((ggkk++kkyy)) After this header, and any vendor header, come the image loading information records. These specify where data is to be loaded, how long it is, and communicates to the loaded image what sort of data it is. The format of each image loading information record is : ______________________________________________________________________ +---------------------+ | Flags, tags and | double word | lengths | +---------------------+ | | | Load Address | double word +---------------------+ | | | Image Length | double word +---------------------+ | | | Memory Length | double word +---------------------+ ______________________________________________________________________ Each image loading information record follows the previous, or the header. The memory length, image length and load address fields are unsigned 32 numbers. They do not have the segment:offset format used by the 8086. The flags, tags and lengths field is broken up as follows: Bits 0 to 3 (lowest 4 bits) are the length of the non vendor part of this header in double words. Currently this value is 4. Bits 4 to 7 indicate the length of any vendor information, in double words. Bits 8 to 15 are for vendor's tags. The vendor tag is a private number that the loaded image can use to determine what sort of image is at this particular location. Bits 16 to 23 are for future expansion and should be set to zero. Bits 24 to 31 are for flags, which are defined later. Vendors may place further information after this information record, and before the next. Each information record may have a different vendor length. There are two restrictions on vendor information. One is that the header and all information records that the net boot process is to use fall within the first 512 bytes. The second restriction is that the net boot process must ignore all vendor additions. The net boot process may not overwrite vendor supplied information, or other undefined data in the initial 512 bytes. The flags are used to modify the load address field, and to indicate that this is the last information record that the net boot process should use. Bit 24 works in conjunction with bit 25 to specify the meaning of the load address. ______________________________________________________________________ B24 B25 0 0 load address is an absolute 32 number 1 0 add the load address to the location one past the last byte of the memory area required by the last image loaded. If the first image, then add to 512 plus the location where the 512 bytes were placed 0 1 subtract the load address from the one past the last writeable location in memory. Thus 1 would be the last location one could write in memory. 1 1 load address is subtracted from the start of the last image loaded. If the first image, then subtract from the start of where the 512 bytes were placed ______________________________________________________________________ (For convenience bit 24 is byte 0 of the flag field) Bit 26 is the end marker for the net boot process. It is set when this is the last information record the net boot process should look at. More records may be present, but the net boot process will not look at them. (Vendors can continue information records out past the 512 boundary for private use in this manner). The image length tells the net boot process how many bytes are to be loaded. Zero is a valid value. This can be used to mark memory areas such as shared memory for interprocessor communication, flash eproms, data in eproms. The image length can also be different from the memory length. This allows decompression programs to fluff up the kernel image. It also allows a file system to be larger then the loaded file system image. Bits 27 through 31 are not defined as yet and must be set to zero until they are. 66.. BBoooott pprroomm eennttrryy ppooiinnttss.. ((ggkk))As mentioned above the net boot process has to provide interrupt 78h as an entry point in case, the returnable flag (bit 9 of the flags field in the image header) of the boot image has been set. When calling this interface interrupt, the caller has to load the AH register with a value indicating the type of operation requested: ______________________________________________________________________ 00h - Installation check Input: none Output: AX - returns the value 474Bh BX - flags indicating what further services are provided by the net boot program: Bit 0 - packet driver interface (see below) Bits 1 to 15 are unused and have to be zero 01h - Cleanup and terminate the boot process services. This will also remove the services provided by interrupt 87h. Input: none Output: none ______________________________________________________________________ Further functions are not yet defined. These functions are only available to boot images which have the first magic number at the beginning of the image header, and have the returnable flag set in the flags field. In order to provide compatibility with net boot programs written to match an earlier version of this document, the loaded image should check for the existence of interrupt 78h by looking at it's vector. If that's 0:0, or if it does not return a proper magic ID after calling the installation check function, the boot image has to assume that the net boot program does not support this services interrupt. If the bit 0 of register BX of function 00h is set, the boot program has to provide a packet driver interface at interrupt 79h as described in the packet driver interface standard, version 1.09, published by FTP Software, Inc., which is not repeated here. It serves as an interface to the system's network card. It is important to note that the net boot process has to provide a clean packet driver interface without any handles being defined when the boot image gets started. It is expected that the boot image sets up it's own TCP/IP or other network's stack on top of this packet driver interface. When the boot image returns to the net boot process, it has to return a clean packet driver interface as well, without any handles being defined.((ggkk)) 77.. EExxaammppllee ooff aa bboooott iimmaaggee.. Here is an example of how the boot image would look for Linux: ______________________________________________________________________ 0x1B031336, /* magic number */ 0x4, /* length of header is 16 bytes, no vendor info */ 0x90000000, /* location in ds:bx format */ 0x90000200, /* execute address in cs:ip format */ /* 2048 setup.S bytes */ 0x4, /* flags, not end, absolute address, 16 bytes this record, no vendor info */ 0x90200, /* load address - note format */ 0x800, /* 4 8 512 byte blocks for linux */ 0x800, /* kernel image */ 0x4, /* flags, not end, absolute address, 16 bytes this record, no vendor info */ 0x10000, /* load address - note format */ 0x80000, /* 512K (this could be shorter */ 0x80000, /* ramdisk for root file system */ 0x04000004, /* flags = last, absolute address, 16 bytes this record, no vendor info *// 0x100000, /* load address - in extended memory */ 0x80000, /* 512K for instance */ 0x80000, /* Then follows linux specific information */ ______________________________________________________________________ 88.. TTeerrmmss When I say 'the net boot process', I mean the act of loading the image into memory, setting up any tables, up until the jump to the required location in the image. The net booting program executes the net boot process. The net boot program may be a rom, but not neccassarily. It is a set of instructions and data residing on the booting machine. The image, or boot image, consists of the data loaded by the net boot process. When I say 'the PC boot process', I mean the general PC rom bios boot process, the setting up of hardware, the scanning for adaptor roms, the execution of adaptor roms, the loading in of the initial boot track. The PC boot process will include the net boot process, if one is present. When I say client, I mean the PC booting up. When I say 'image host', I mean the host where the boot image is comming from. This may not have the same architecture as the client. The bootp protocol is defined in RFC951 and RFC1084. The tftp protocol is defined in RFC783. These are available on many sites. See Comer 1991 for details on how to obtain them. A bootp server is the machine that answers the bootp request. It is not neccessarily the image host. "Can" and "may" means doesn't have to, but is allowed to and might. "Must" means just that. "Cannot" means must not. 99.. RReeffeerreenncceess Comer, D.E. 1991, Internetworking with TCP/IP Vol I: Principles, Protocols, and Architecture Second Edition, Prentice Hall, Englewood Cliffs, N.J., 1991 Stevens, W.R 1990, Unix Network Programming, Prentice Hall, Englewood Cliffs, N.J., 1990 mknbi-1.4.4/Nbi.pm0100644000175000001440000001342707543256024012401 0ustar kenusers# Class to handle tagged images # Placed under GNU Public License by Ken Yap, April 2000 package Nbi; use strict; use IO::Seekable; use constant; use constant TFTPBLOCKSIZE => 512; # This is correct for the current version of the netboot specs # Note: reverse of the way it is in the specs because of Intel byte order use constant MAGIC => "\x36\x13\x03\x1B"; # This is needed at the end of the boot block, again byte reversed use constant MAGIC2 => "\x55\xAA"; # This is defined by the bootrom layout use constant HEADERSIZE => 512; use vars qw($libdir $bootseg $bootoff @segdescs); sub new { my $class = shift; $libdir = shift; my $self = {}; bless $self, $class; # $self->_initialize(); return $self; } sub add_header ($$$$$) { my ($class, $vendorinfo, $headerseg, $bootseg, $bootoff) = @_; my ($vilen); $vilen = length($vendorinfo); $vilen += 4; # three plus one for null byte $vilen &= ~0x3; # round to multiple of 4 push(@segdescs, pack("A4V3a$vilen", MAGIC, ($vilen << 2) + 4, $headerseg << 16, ($bootseg << 16) + $bootoff, $vendorinfo)); } sub add_pm_header ($$$$$) { my ($class, $vendorinfo, $headerseg, $bootaddr, $progreturns) = @_; my ($vilen); $vilen = length($vendorinfo); $vilen += 4; # three plus one for null byte $vilen &= ~0x3; # round to multiple of 4 push(@segdescs, pack("A4V3a$vilen", MAGIC, (($vilen << 2) + 4) | (1 << 31) | ($progreturns << 8), $headerseg << 16, $bootaddr, $vendorinfo)); } sub roundup ($$) { # Round up to next multiple of $blocksize, assumes that it's a power of 2 my ($size, $blocksize) = @_; # Default to TFTPBLOCKSIZE if not specified $blocksize = TFTPBLOCKSIZE if (!defined($blocksize)); return ($size + $blocksize - 1) & ~($blocksize - 1); } # Grab N bytes from a file sub peek_file ($$$$) { my ($class, $descriptor, $dataptr, $datalen) = @_; my ($file, $fromoff, $status); $file = $$descriptor{'file'} if exists $$descriptor{'file'}; $fromoff = $$descriptor{'fromoff'} if exists $$descriptor{'fromoff'}; return 0 if !defined($file) or !open(R, "$file"); binmode(R); if (defined($fromoff)) { return 0 if !seek(R, $fromoff, SEEK_SET); } # Read up to $datalen bytes $status = read(R, $$dataptr, $datalen); close(R); return ($status); } # Add a segment descriptor from a file or a string sub add_segment ($$$) { my ($class, $descriptor, $vendorinfo) = @_; my ($file, $string, $segment, $len, $maxlen, $fromoff, $align, $id, $end, $vilen); $end = 0; $file = $$descriptor{'file'} if exists $$descriptor{'file'}; $string = $$descriptor{'string'} if exists $$descriptor{'string'}; $segment = $$descriptor{'segment'} if exists $$descriptor{'segment'}; $len = $$descriptor{'len'} if exists $$descriptor{'len'}; $maxlen = $$descriptor{'maxlen'} if exists $$descriptor{'maxlen'}; $fromoff = $$descriptor{'fromoff'} if exists $$descriptor{'fromoff'}; $align = $$descriptor{'align'} if exists $$descriptor{'align'}; $id = $$descriptor{'id'} if exists $$descriptor{'id'}; $end = $$descriptor{'end'} if exists $$descriptor{'end'}; if (!defined($len)) { if (defined($string)) { $len = length($string); } else { if (defined($fromoff)) { $len = (-s $file) - $fromoff; } else { $len = -s $file; } return 0 if !defined($len); # no such file } } if (defined($align)) { $len = &roundup($len, $align); } else { $len = &roundup($len); } $maxlen = $len if (!defined($maxlen)); if (!defined($vendorinfo)) { push(@segdescs, pack('V4', 4 + ($id << 8) + ($end << 26), $segment << 4, $len, $maxlen)); } else { $vilen = length($vendorinfo); $vilen += 3; # three plus one for null byte $vilen &= ~0x3; # round to multiple of 4 push(@segdescs, pack("V4a$vilen", ($vilen << 2) + 4 + ($id << 8) + ($end << 26), $segment << 4, $len, $maxlen, $vendorinfo)); } return ($len); # assumes always > 0 } sub pad_with_nulls ($$) { my ($i, $blocksize) = @_; $blocksize = TFTPBLOCKSIZE if (!defined($blocksize)); # Pad with nulls to next block boundary $i %= $blocksize; print "\0" x ($blocksize - $i) if ($i != 0); } # Copy data from file to stdout sub copy_file ($$) { my ($class, $descriptor) = @_; my ($i, $file, $fromoff, $align, $len, $seglen, $nread, $data, $status); $file = $$descriptor{'file'} if exists $$descriptor{'file'}; $fromoff = $$descriptor{'fromoff'} if exists $$descriptor{'fromoff'}; $align = $$descriptor{'align'} if exists $$descriptor{'align'}; $len = $$descriptor{'len'} if exists $$descriptor{'len'}; return 0 if !open(R, "$file"); if (defined($fromoff)) { return 0 if !seek(R, $fromoff, SEEK_SET); $len = (-s $file) - $fromoff if !defined($len); } else { $len = -s $file if !defined($len); } binmode(R); # Copy file in TFTPBLOCKSIZE chunks $nread = 0; while ($nread != $len) { $status = read(R, $data, TFTPBLOCKSIZE); last if (!defined($status) or $status == 0); print $data; $nread += $status; } close(R); if (defined($align)) { &pad_with_nulls($nread, $align); } else { &pad_with_nulls($nread); } return ($nread); } # Copy data from string to stdout sub copy_string ($$) { my ($class, $descriptor) = @_; my ($i, $string, $len, $align); $string = $$descriptor{'string'} if exists $$descriptor{'string'}; $len = $$descriptor{'len'} if exists $$descriptor{'len'}; $align = $$descriptor{'align'} if exists $$descriptor{'align'}; return 0 if !defined($string); $len = length($string) if !defined($len); print substr($string, 0, $len); defined($align) ? &pad_with_nulls($len, $align) : &pad_with_nulls($len); return ($len); } sub dump_segments { my ($s, $len); $len = 0; while ($s = shift(@segdescs)) { $len += length($s); print $s; } print "\0" x (HEADERSIZE - 2 - $len), MAGIC2; } # This empty for now, but is available as a hook to do any actions # before closing the image file sub finalise_image { } @segdescs = (); 1; mknbi-1.4.4/README0100644000175000001440000000247107764324541012215 0ustar kenusersmknbi.pl 1.4.4 mknbi is a utility for building a tagged image for a kernel for various operating systems. It can also build a tagged images for an Etherboot ROM image and an external menu program, which aren't really operating systems. mknbi has several advantages over the mknbi tools in netboot-0.8.1 and contrib: It is more portable, as it is written in Perl. It should be possible to execute the Perl script unchanged on various platforms to which Perl5 has been ported. January 2001: I have since received word of one person uring mknbi on an WinNT system with only a couple of changes. It will be able to cope with any additional load formats that Etherboot might support in future, because the image format specific handling has been abstracted into a class, Nbi.pm. As of January 2001, there is a new class for handling ELF format, Elf.pm. It is more readable. While this is a matter of opinion, my personal perspective is that Perl is more concise than C, and this aids comprehension because one can keep more context with the limited number of lines on the screen. Perl's powerful builtin functions and useful data types handle situations such as structure extraction and packing, and byte ordering simply. It is relatively easy to add support for new features. The drawback is that the programmer must be fluent in Perl. mknbi-1.4.4/startmenu.S0100644000175000001440000004422007624624642013501 0ustar kenusers/* * Converted to use Eric Biederman's _real_call routine which frees * the 16 bit code from running in the same 64kB segment as the * 32 bit code's stack. */ /* #defines because ljmp wants a number, probably gas bug */ /* .equ KERN_CODE_SEG,_pmcs-_gdt */ #define KERN_CODE_SEG 0x08 .equ KERN_DATA_SEG,_pmds-_gdt /* .equ REAL_CODE_SEG,_rmcs-_gdt */ #define REAL_CODE_SEG 0x18 .equ REAL_DATA_SEG,_rmds-_gdt .equ CR0_PE,1 #ifdef GAS291 #define DATA32 data32; #define ADDR32 addr32; #define LJMPI(x) ljmp x #else #define DATA32 data32 #define ADDR32 addr32 /* newer GAS295 require #define LJMPI(x) ljmp *x */ #define LJMPI(x) ljmp x #endif #define DO_REAL_CALL pushl $10f; pushl $20f-10f; call _real_call; .section ".text16"; 10: .code16 #define DO_REAL_RETURN ret; 20: .code32; .previous .section ".text" .section ".text16","ax",@progbits .previous .code32 .arch i386 /* * NOTE: if you write a subroutine that is called from C code (gcc/egcs), * then you only have to take care of %ebx, %esi, %edi and %ebp. These * registers must not be altered under any circumstance. All other registers * may be clobbered without any negative side effects. If you don't follow * this rule then you'll run into strange effects that only occur on some * gcc versions (because the register allocator may use different registers). * * All the data32 prefixes for the ljmp instructions are necessary, because * the assembler emits code with a relocation address of 0. This means that * all destinations are initially negative, which the assembler doesn't grok, * because for some reason negative numbers don't fit into 16 bits. The addr32 * prefixes are there for the same reasons, because otherwise the memory * references are only 16 bit wide. Theoretically they are all superfluous. */ /************************************************************************** START - Where all the fun begins.... **************************************************************************/ /* this must be the first thing in the file because we enter from the top */ .global _start _start: /* We have to use our own GDT when running in our segment because the old GDT will have the wrong descriptors for the real code segments */ sgdt gdtsave /* save old GDT */ lgdt gdtarg /* load ours */ /* reload the segment registers */ movl $KERN_DATA_SEG,%eax movl %eax,%ds movl %eax,%es movl %eax,%ss movl %eax,%fs movl %eax,%gs /* flush prefetch queue, and reload %cs:%eip */ ljmp $KERN_CODE_SEG,$1f 1: /* save the stack pointer and call the routine */ movl %esp,%eax movl %eax,initsp movl $RELOC+0x20000,%esp /* change stack */ pushl 12(%eax) /* replicate args on new stack */ pushl 8(%eax) pushl 4(%eax) call menu _exit: /* we reset sp to the location just before entering first instead of relying on the return from menu because exit could have been called from anywhere */ movl initsp,%ebx movl %ebx,%esp lgdt gdtsave /* restore old GDT */ ret .globl exit exit: movl 4(%esp),%eax jmp _exit /************************************************************************** SET_SEG_BASE - Set the base address of a segment register Stolen from Etherboot 5.1. With thanks to Eric Biederman **************************************************************************/ /* .globl set_seg_base */ set_seg_base: /* Low half of the gdt base */ movl 4(%esp), %eax shll $16, %eax /* High half of the gdt base */ movl 4(%esp), %ecx shrl $16, %ecx andl $0xff, %ecx movl 4(%esp), %edx andl $0xff000000, %edx orl %edx, %ecx movl 8(%esp), %edx /* Fixup the code segment */ andl $0x0000ffff, 0(%edx) orl %eax , 0(%edx) andl $0x00ffff00, 4(%edx) orl %ecx , 4(%edx) /* Fixup the data segment */ andl $0x0000ffff, 8(%edx) orl %eax , 8(%edx) andl $0x00ffff00, 12(%edx) orl %ecx , 12(%edx) ret /************************************************************************** _REAL_CALL - Run some code in real mode. Stolen from Etherboot 5.1. With thanks to Eric Biederman **************************************************************************/ /* MAX_REAL_MODE_STACK is carefully tuned to work * with the stack bottom at 0x7c00 while not chancing * overwriting data below 0x500. */ #define MAX_REAL_MODE_STACK 29696 #define RADDR(sym) (((sym) - _end16) + MAX_REAL_MODE_STACK) .balign 4 /* .globl real_mode_stack */ real_mode_stack: .long 0x7c00 /* Put the stack just below the dos load address */ real_stack_top: .long 0 _save_esp: .long 0 /* .globl _real_call */ _real_call: /* Save the original %esp value */ movl %esp, _save_esp /* Save the temporary registers I use */ pushl $0 pushl %ebx pushl %ecx pushl %edx pushl %esi pushl %edi pushl %ebp /* Load up the registers */ movl 32(%esp), %ecx /* The 16bit code len */ movl 36(%esp), %esi /* The 16bit code start */ movl virt_offset, %ebp /* The virtual offset */ /* stack top = phys_to_virt(real_mode_stack - MAX_REAL_MODE_STACK) */ movl real_mode_stack, %ebx /* The stack top */ subl $MAX_REAL_MODE_STACK, %ebx movl %ebx, real_stack_top subl %ebp, %ebx /* Save the real mode stack top */ movl %ebx, 24(%esp) /* Compute where the copied code goes */ leal RADDR(__real_call)(%ebx), %edi subl %ecx, %edi andl $0xfffffffc, %edi /* 4 byte aligned */ /* Remember where the code is executed */ movl %edi, %eax subl %ebx, %eax movw %ax, real_ip /* Copy the user code onto the real mode stack */ rep movsb /* Copy the trampoline onto the stack */ movl $__real_call, %esi movl $_end16 - __real_call, %ecx leal RADDR(__real_call)(%ebx), %edi rep movsb /* Fixup real_gdtarg */ leal _gdt(%ebp), %eax movl %eax, RADDR(real_gdtarg +2)(%ebx) /* Fixup the gdt */ pushl $_rmcs leal 0(%ebx, %ebp), %eax pushl %eax call set_seg_base addl $8, %esp /* Restore the saved registers */ popl %ebp popl %edi popl %esi popl %edx popl %ecx popl %ebx /* And switch stacks */ popl %esp movzwl RADDR(real_ip)(%esp), %eax addl %eax, %esp /* Setup for jump to real mode */ movl real_stack_top, %eax shrl $4, %eax pushw %ax pushw $RADDR(real16) /* Switch stack from %esp 32bit virtual to %sp 16bit physical */ addl virt_offset, %esp subl real_stack_top, %esp /* Jump to 16bit code */ ljmp $REAL_CODE_SEG, $RADDR(code16) /* jump to a 16 bit segment */ _real_call_ret: /* reload segment registers */ movl $KERN_DATA_SEG,%eax movl %eax,%ds movl %eax,%es movl %eax,%ss movl %eax,%fs movl %eax,%gs /* Restore the stack */ movl _save_esp, %esp /* Restore the direction flag */ cld /* Get the real mode stack pointer */ movl real_stack_top, %eax subl virt_offset, %eax pushl %eax movzwl RADDR(real_sp)(%eax), %eax addl 0(%esp), %eax addl $4, %esp /* Return to my caller */ ret $8 .balign 16 __real_call: real_sp: .word 0 real_ip: .word 0 real_gdtarg: .word _gdt_end - _gdt - 1 /* limit */ .long _gdt /* addr */ .code16 code16: /* Load 16bit segment descriptors to force 16bit segment limit */ movw $REAL_DATA_SEG, %ax movw %ax,%ds movw %ax,%ss movw %ax,%es movw %ax,%fs movw %ax,%gs /* clear the PE bit of CR0 */ movl %cr0,%eax andb $0!CR0_PE,%al movl %eax,%cr0 /* make intersegment jmp to flush the processor pipeline * and reload %cs:%eip (to clear upper 16 bits of %eip). */ lret real16: /* we are in real mode now * set up the real mode segment registers : %ds, $ss, %es */ movw %cs, %ax movw %ax, %ss movw %ax, %ds movw %ax, %fs movw %ax, %gs /* Enable interrupts */ sti /* Call the user supplied code */ call *RADDR(real_ip) /* Save the stack pointer */ /* Reload %ds */ movw %cs, %ax movw %ax, %ds movw %sp, RADDR(real_sp) /* Disable interrupts */ cli /* Switch back to protected mode */ cs DATA32 lgdt RADDR(real_gdtarg) movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 /* turn on protected mode */ /* flush prefetch queue, and reload %cs:%eip */ DATA32 ljmp $KERN_CODE_SEG, $_real_call_ret .code32 __end16: .balign 16 _end16: .code32 /************************************************************************** CURRTICKS - Get Time Use direct memory access to BIOS variables, longword 0040:006C (ticks today) and byte 0040:0070 (midnight crossover flag) instead of calling timeofday BIOS interrupt. **************************************************************************/ .globl currticks currticks: pushl %ebp pushl %ebx pushl %esi pushl %edi DO_REAL_CALL DO_REAL_RETURN movl virt_offset,%ebp negl %ebp movl 0x46C(%ebp), %eax movb 0x470(%ebp), %bl cmpb $0, %bl je notmidnite movb $0, 0x470(%ebp) /* clear the flag */ addl $0x1800b0,days /* 0x1800b0 ticks per day */ notmidnite: addl days,%eax popl %edi popl %esi popl %ebx popl %ebp ret /************************************************************************** console_cls() BIOS call "INT 10H Function 0Fh" to get current video mode Call with %ah = 0x0f Returns %al = (video mode) %bh = (page number) BIOS call "INT 10H Function 00h" to set the video mode (clears screen) Call with %ah = 0x00 %al = (video mode) **************************************************************************/ .globl console_cls console_cls: pushl %ebx pushl %esi pushl %edi DO_REAL_CALL movb $0xf, %ah int $0x10 /* Get Current Video mode */ xorb %ah, %ah int $0x10 /* Set Video mode (clears screen) */ DO_REAL_RETURN popl %edi popl %esi popl %ebx ret /************************************************************************** console_nocursor() BIOS call "INT 10H Function 01h" to set cursor type Call with %ah = 0x01 %ch = cursor starting scanline %cl = cursor ending scanline **************************************************************************/ .globl console_nocursor console_nocursor: pushl %ebx pushl %esi pushl %edi DO_REAL_CALL movw $0x2000, %cx movb $0x1, %ah int $0x10 DO_REAL_RETURN popl %edi popl %esi popl %ebx ret /************************************************************************** console_getxy() BIOS call "INT 10H Function 03h" to get cursor position Call with %ah = 0x03 %bh = page Returns %ch = starting scan line %cl = ending scan line %dh = row (0 is top) %dl = column (0 is left) **************************************************************************/ .globl console_getxy console_getxy: pushl %ebx pushl %esi pushl %edi DO_REAL_CALL xorb %bh, %bh /* set page to 0 */ movb $0x3, %ah int $0x10 /* get cursor position */ DO_REAL_RETURN xor %eax, %eax movb %dl, %ah movb %dh, %al popl %edi popl %esi popl %ebx ret /************************************************************************** console_gotoxy(x,y) BIOS call "INT 10H Function 02h" to set cursor position Call with %ah = 0x02 %bh = page %dh = row (0 is top) %dl = column (0 is left) **************************************************************************/ .globl console_gotoxy console_gotoxy: pushl %ebp movl %esp,%ebp pushl %ebx pushl %esi pushl %edi movb 0x8(%ebp), %dl /* %dl = x */ movb 0xC(%ebp), %dh /* %dh = y */ DO_REAL_CALL xorb %bh, %bh /* set page to 0 */ movb $0x2, %ah int $0x10 /* set cursor position */ DO_REAL_RETURN popl %edi popl %esi popl %ebx popl %ebp ret /************************************************************************** * console_setattrib(attr) : Sets the character attributes for character at * current cursor position. * * Bitfields for character's display attribute: * Bit(s) Description * 7 foreground blink * 6-4 background color * 3 foreground bright * 2-0 foreground color * * Values for character color: * Normal Bright * 000b black dark gray * 001b blue light blue * 010b green light green * 011b cyan light cyan * 100b red light red * 101b magenta light magenta * 110b brown yellow * 111b light gray white * * BIOS call "INT 10H Function 08h" to read character and attribute data * Call with %ah = 0x08 * %bh = page * Returns %ah = character attribute * %al = character value * BIOS call "INT 10H Function 09h" to write character and attribute data * Call with %ah = 0x09 * %al = character value * %bh = page * %bl = character attribute * %cx = count to display (???, possible side-effects!!) **************************************************************************/ .globl console_setattrib console_setattrib: pushl %ebp movl %esp,%ebp pushl %ebx pushl %esi pushl %edi movl 0x8(%ebp), %ecx xorl %ebx, %ebx DO_REAL_CALL movb $0x8, %ah int $0x10 movb $0x9, %ah movb %cl, %bl movw $1, %cx int $0x10 DO_REAL_RETURN popl %edi popl %esi popl %ebx popl %ebp ret /************************************************************************** CONSOLE_PUTC - Print a character on console **************************************************************************/ .globl console_putc console_putc: pushl %ebp movl %esp,%ebp pushl %ebx pushl %esi pushl %edi movb 8(%ebp),%cl DO_REAL_CALL movl $1,%ebx movb $0x0e,%ah movb %cl,%al int $0x10 DO_REAL_RETURN popl %edi popl %esi popl %ebx popl %ebp ret /************************************************************************** CONSOLE_GETC - Get a character from console **************************************************************************/ .globl console_getc console_getc: pushl %ebx pushl %esi pushl %edi DO_REAL_CALL movb $0x0,%ah int $0x16 movb %al,%bl DO_REAL_RETURN xor %eax,%eax movzbl %bl,%eax popl %edi popl %esi popl %ebx ret /************************************************************************** console_getkey() BIOS call "INT 16H Function 00H" to read character from keyboard Call with %ah = 0x10 Return: %ah = keyboard scan code %al = ASCII character **************************************************************************/ .globl console_getkey console_getkey: pushl %ebx pushl %esi pushl %edi DO_REAL_CALL movb $0x0,%ah int $0x16 movw %ax, %bx DO_REAL_RETURN movzwl %bx, %eax popl %edi popl %esi popl %ebx ret /************************************************************************** console_checkkey() if there is a character pending, return it; otherwise return -1 BIOS call "INT 16H Function 01H" to check whether a character is pending Call with %ah = 0x1 Return: If key waiting to be input: %ah = keyboard scan code %al = ASCII character Zero flag = clear else Zero flag = set **************************************************************************/ .globl console_checkkey console_checkkey: pushl %ebx pushl %esi pushl %edi xorl %ebx, %ebx DO_REAL_CALL movb $0x1, %ah int $0x16 jz 1f movw %ax, %bx jmp 2f 1: movl $0xFFFFFFFF, %ebx 2: DO_REAL_RETURN movzwl %bx, %eax popl %edi popl %esi popl %ebx ret /************************************************************************** ISCHAR - Check for keyboard interrupt **************************************************************************/ .globl console_ischar console_ischar: pushl %ebx pushl %esi pushl %edi DO_REAL_CALL xorw %bx,%bx movb $0x1,%ah int $0x16 jz 2f movb %al,%bl 2: DO_REAL_RETURN movzbl %bl,%eax popl %edi popl %esi popl %ebx ret /************************************************************************** GETSHIFT - Get keyboard shift state **************************************************************************/ .globl console_getshift console_getshift: pushl %ebx pushl %esi pushl %edi DO_REAL_CALL movb $2,%ah int $0x16 andb $0xdf,%al movw %ax,%bx DO_REAL_RETURN movzbl %bl,%eax popl %edi popl %esi popl %ebx ret /************************************************************************** INT10 - Call Interrupt 0x10 **************************************************************************/ .globl _int10 _int10: push %ebp mov %esp,%ebp push %ebx push %esi push %edi movw 8(%ebp),%si movw 10(%ebp),%bx movw 12(%ebp),%cx movw 14(%ebp),%dx DO_REAL_CALL movw %si,%ax int $0x10 movw %ax,%si DO_REAL_RETURN movl %esi,%eax andl $0xFFFF,%eax movw %ax,int10ret movw %bx,int10ret+2 shl $16,%ebx orl %ebx,%eax movw %cx,int10ret+4 movw %dx,int10ret+6 pop %edi pop %esi pop %ebx pop %ebp ret .globl int10ret int10ret: .word 0,0,0,0 /************************************************************************** CPU_NAP - Save power by halting the CPU until the next interrupt **************************************************************************/ .globl cpu_nap cpu_nap: pushl %ebx pushl %esi pushl %edi DO_REAL_CALL hlt DO_REAL_RETURN popl %edi popl %esi popl %ebx ret /************************************************************************** SETJMP - Save stack context for non-local goto **************************************************************************/ .globl setjmp setjmp: movl 4(%esp),%ecx movl 0(%esp),%edx movl %edx,0(%ecx) movl %ebx,4(%ecx) movl %esp,8(%ecx) movl %ebp,12(%ecx) movl %esi,16(%ecx) movl %edi,20(%ecx) movl %eax,24(%ecx) movl $0,%eax ret /************************************************************************** LONGJMP - Non-local jump to a saved stack context **************************************************************************/ .globl longjmp longjmp: movl 4(%esp),%edx movl 8(%esp),%eax movl 0(%edx),%ecx movl 4(%edx),%ebx movl 8(%edx),%esp movl 12(%edx),%ebp movl 16(%edx),%esi movl 20(%edx),%edi cmpl $0,%eax jne 1f movl $1,%eax 1: movl %ecx,0(%esp) ret /************************************************************************** GLOBAL DESCRIPTOR TABLE **************************************************************************/ .align 4 _gdt: gdtarg: .word 0x27 /* limit */ .long _gdt /* addr */ .byte 0,0 _pmcs: /* 32 bit protected mode code segment */ .word 0xffff,0 .byte 0,0x9f,0xcf,0 _pmds: /* 32 bit protected mode data segment */ .word 0xffff,0 .byte 0,0x93,0xcf,0 _rmcs: /* 16 bit real mode code segment */ .word 0xffff,(0&0xffff) .byte (0>>16),0x9b,0x00,(0>>24) _rmds: /* 16 bit real mode data segment */ .word 0xffff,(0&0xffff) .byte (0>>16),0x93,0x00,(0>>24) _gdt_end: gdtsave: .long 0,0,0 /* previous GDT */ virt_offset: .long 0 initsp: .long 0 days: .long 0 mknbi-1.4.4/startmenu.h0100644000175000001440000000100707610376602013515 0ustar kenusers/* Assembler routines */ extern unsigned long currticks(void); extern int console_getc(void); extern void console_putc(int); extern int console_ischar(void); extern int console_getshift(void); extern void cpu_nap(void); /* Additional routines in startmenu.S */ extern int console_checkkey(void); extern void console_cls(void); extern int console_getkey(void); extern int console_getxy(void); extern void console_gotoxy(int console_x, int y); extern void console_nocursor(void); extern void console_setattrib(int attr); mknbi-1.4.4/scripts/0040755000175000001440000000000007705274041013015 5ustar kenusersmknbi-1.4.4/scripts/mkimg-fd0.sh0100644000175000001440000000021607705274031015117 0ustar kenusers#! /bin/sh # Makes an NBI of the 1.44MB disk in drive /dev/fd0 dd if=/dev/fd0 of=$1.img bs=512 count=2880 mknbi-dos $1.img > $1.nbi rm $1.img mknbi-1.4.4/scripts/mkfd-nbi.sh0100644000175000001440000000145707653425576015061 0ustar kenusers#! /bin/sh # Make an NBI floppy disk image using MTOOLS & DOS files # DOES NOT require a diskette in drive /dev/fd0 # DOES requires a bootsector from your target OS in file 'bootsect.bin' # Make this once from a bootable floppy with the command: # dd if=/dev/fd0 of=bootsect.bin bs=512 count=1 mv ~/.mtoolsrc ~/.mtoolsrc.tmp echo drive x: file=\"$1.img\" > ~/.mtoolsrc # comment out the line below if image is a VFAT aware OS (Win9X+) echo 'mtools_no_vfat=1' >> ~/.mtoolsrc rm -f $1.img #dd if=/dev/zero of=$1.img bs=512 count=2880 # Make a 1.44MB disk image file mformat -C -f 1440 -B bootsect.bin x: mcopy io.sys x: mcopy msdos.sys x: mcopy command.com x: # additional files below this line # additional files above this line mknbi-dos $1.img > $1.nbi rm $1.img rm -f ~/.mtoolsrc mv ~./mtoolsrc.tmp ~/.mtoolsrc mknbi-1.4.4/scripts/mkhd-nbi.sh0100644000175000001440000000146607653425637015061 0ustar kenusers#! /bin/sh # Make an NBI hard disk image using MTOOLS & DOS files # Requires a bootsector from your target OS in file 'bootsect.bin' # Make this once from a bootable floppy with the command: # dd if=/dev/fd0 of=bootsect.bin bs=512 count=1 mv ~/.mtoolsrc ~/.mtoolsrc.tmp echo drive x: file=\"$1.img\" > ~/.mtoolsrc # comment out the line below if image is a VFAT aware OS (Win9X+) echo 'mtools_no_vfat=1' >> ~/.mtoolsrc rm -f $1.img # Capacity in bytes = (cyls)*(heads)*(sectors_per_track)*512 # example for a 10MB disk (10485760 = 320 * 8 * 8 * 512) mformat -C -t 320 -h 4 -n 16 -B bootsect.bin x: mcopy io.sys x: mcopy msdos.sys x: mcopy command.com x: # additional files below this line # additional files above this line mknbi-dos --harddisk $1.img > $1.nbi rm $1.img rm -f ~/.mtoolsrc mv ~./mtoolsrc.tmp ~/.mtoolsrc mknbi-1.4.4/first.fdos0100644000175000001440000001000010110544077013307 0ustar kenusersڌȎ،.6>FFFF P&;u.&G;u$&G$<u1t!&:AuG6>.˾_ t&Eu&E&]f h &E &]  أj &0&n &Ap &At &Ar &Al &A w &A v Av r2T&>uO&>t&>u?&&04r*FTv &8$u&> u&> &:r tbPX6>.1> t &<u߹t ΀<u3뱃ێÿ' 6, u31Ɂ<u As"/&E"&:mt&Eu & 1YQı%0YVt S0[^ DOS Net Boot Image Loader Version 0.8.1 mknbi-fdos-1.4.4 GPLed by G. Kuhlmann 6mknbi-fdos-1.4.4cScCMUSTANpp Error in load record data Invalid boot header magic number Invalid vendor magic ID Error while accessing ramdisk Wrong ramdisk image BOOTP record invalid RPL=JuQYPXJX..X uD<u.h .f .j <u ˺' .% <u˺T .v .z <uMuP.| . ~ uC/v sJr.w tu$0u.T .u 0 ..T vJS0r݀uʜ.T .u Rʀu.T ru 뼜.T ZS&'[PXUF]X0<<x t R0ҜT Zr0[\&'[[RQSPs2X[YZ;p r;n v [(s @uX[YZ0[u r .l 6t 11[0[[RQP XsYZ[r ċn p SQÈ11Ɋt ȁr S1 t PRZX[ـ?:r wIxȁ;p r w;n rY[VWQRP t f h Tt1ұ0؁UuȎ XZY_^û@.d {0[r00Ou%j A9wS´ 8[ t z * uz z +f h r=PUPFFNX].6~ .6| [. . Ȏм QRVWȎ[_^ZY. . Sv  &E u1&;u&=u uT ڌش/،9u9u u t/u1` &b &> &MP t ` z tR Z t ƒ¿1[0AP` NetB@h `P` NO NAME FAT12 mknbi-1.4.4/ansiesc.c0100644000175000001440000003333007714554247013127 0ustar kenusers#include "stddef.h" #include "string.h" #include "etherboot.h" #include "ansiesc.h" /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. */ /* * Display attributes * * Code Effect * [0m normal text * [1m high-intensity on * [21m high-intensity off * [5m blinking on * [25m blinking off * [7m reverse video on * [27m reverse video off * [3xm set foreground color: * [4xm set background color. x can be: * 0 - black 4 - blue * 1 - red 5 - magenta * 2 - green 6 - cyan * 3 - yellow 7 - white * [=xh set video mode * 0 - 40x25 mono (text) 13 - 40x25 16colors (gfx) * 1 - 40x25 16colors (text) 14 - 80x25 16colors (gfx) * 2 - 80x25 mono (text) 15 - 80x25 mono (gfx) * 3 - 80x25 16colors (text) 16 - 80x25 16colors (gfx) * 4 - 40x25 4colors (gfx) 17 - 80x30 mono (gfx) * 5 - 40x25 mono (gfx) 18 - 80x30 16colors (gfx) * 6 - 80x25 mono (gfx) 19 - 40x25 256colors(gfx) * * * Cursor control * * Code Effect * [r;cH move cursor to row r col c (r and c are both numbers) * [r;cf move cursor to row r col c (r and c are both numbers) * [rA move cursor up r rows * [rB move cursor down r rows * [cC move cursor right c columns * [cD move cursor left c columns * [?7l turn off line wrap * [?7h turn on line wrap * [J clear screen and home cursor * [K clear to end of line * [s save the cursor position * [u return cursor to saved position * * Extended features * * Code Effect * [a;b;c;d+ * draw pixel data; use one byte per pixel. Parameters * differ depending on the number of parameters passed: * cnt * "cnt" bytes follow; they will be drawn to the * right of the last graphics position * rle;col * the next "rle" pixels have the value "col"; they * will be drawn to the right of the last graphics * position * x;y;cnt * "cnt" bytes follow; they will be drawn relative to * the text cursor position with an offset of (x/y) * x;y;rle;col * the next "rle" pixels have the value "col"; the * will be drawn relative to the text cursor position * with an offset of (x/y) * [a;b;c;d- * same as above, but pack pixels into three bits. * */ #define MAXARGS 8 #define MAXSTRARGS 1 #define MAXSTRARGLEN 40 extern union { struct { unsigned char al,ah,bl,bh,cl,ch,dl,dh; } __attribute__ ((packed)) lh; struct { unsigned short ax,bx,cx,dx; } __attribute__ ((packed)) x; unsigned long axbx; } __attribute__ ((packed)) int10ret; union axbxstruct { struct { unsigned char al,ah,bl,bh; } __attribute__ ((packed)) lh; struct { unsigned short ax,bx; } __attribute__ ((packed)) x; unsigned long axbx; } __attribute__ ((packed)); #define int10(a,b,c,d) _int10((unsigned long)(a)+((unsigned long)(b)<<16), \ (unsigned long)(c)+((unsigned long)(d)<<16)) extern unsigned long _int10(unsigned long axbx,unsigned long cxdx); static enum { esc_init, esc_std, esc_esc, esc_bracket, esc_digit, esc_semicolon, esc_str, esc_quote } esc_state = esc_init; /* Don't declare these static, so we can access them from code in other files */ unsigned short rows,columns,attr = 7; static unsigned short scr,cx = 0,cy = 0, scx = 0,scy = 0; static int fg = 7, bg = 0, blink = 0,reverse = 0, bright = 0; static int wraparound = 1; static int argn = 0; static int argi[MAXARGS]; static char args[MAXSTRARGS][MAXSTRARGLEN]; static const unsigned char coltable[9] = "\000\004\002\006\001\005\003\007"; #ifdef GFX static unsigned short gfx_rows,gfx_columns,char_width,char_height,gfx_x,gfx_y; static int in_gfx = 0, gfx_packed,gfx_data,gfx_nbits; static int defaultmode = -1, curmode = -1, curmodetype = 0; #endif void ansi_reset(void) { #ifdef GFX /* this will not execute, when the serial console is used, because both curmode and defaultmode will be -1 */ if (curmode != defaultmode) { in_gfx = 0; curmodetype = 0; int10(curmode = defaultmode,0,0,0); esc_state = esc_init; ansi_putc('\010'); /* force reinitialization */ } return; #endif } void enable_cursor(int enable) { #ifdef GFX /* this will not execute, when the serial console is used, because curmodetype will be 0 */ if (curmodetype == 'G' || curmodetype == 'H') { if (enable) int10(0x09DB,7,1,0); else int10(0x0920,(attr/16)&7,1,0); } return; #endif } static void docommand(unsigned char ch) { #ifdef GFX if (ch == '+' || ch == '-') { /* gfx bitmap */ int i; gfx_packed = ((ch == '-') ? 3 : 8); gfx_nbits = 0; if (argn > 2) { gfx_x = argi[0]; gfx_y = argi[1]; if (curmodetype == 'T') { gfx_x += cx; gfx_y += cy; } else { gfx_x += cx*char_width; gfx_y += cy*char_height; } i = 2; } else i = 0; in_gfx = argi[i+0]; if (argn == i+2) while (in_gfx) ansi_putc(argi[i+1]); } else #endif if (ch == 'm') { /* set attribute */ int i,j; for (j = 0; (i = argi[j]), (j++ < argn); ) if (i == 0 || /* reset attributes */ i == 20) { blink = reverse = bright = bg = 0; fg = 7; goto doattr; } else if (i == 1) { /* high intensity on */ bright = 1; goto doattr; } else if (i == 21) { /* high intensity off */ bright = 0; goto doattr; } else if (i == 5) { /* blinking on */ blink = 1; goto doattr; } else if (i == 25) { /* blinking off */ blink = 0; goto doattr; } else if (i == 7) { /* reverse video on */ reverse = 1; isreverse: attr = #ifdef GFX curmodetype != 'T' ? (fg?128:0)+16*fg+(fg^(8*bright+bg)) : #endif 128*blink+16*fg+8*bright+bg; } else if (i == 27) { /* reverse video off */ reverse = 0; isnormal: attr = #ifdef GFX curmodetype != 'T' ? (bg?128:0)+16*bg+(bg^(8*bright+fg)) : #endif 128*blink+16*bg+8*bright+fg; } else if (i >= 30 && i <= 37) { fg = coltable[i-30]; doattr: if (reverse) goto isreverse; else goto isnormal; } else if (i >= 40 && i <= 47) { bg = coltable[i-40]; goto doattr; } } else if (ch == 'H' || /* set cursor position */ ch == 'f') { /* set cursor position */ cy = argi[0]; cx = argi[1]; updatecursor: int10(0x0200,256*scr,0,256*cy+cx); } else if (ch == 'A') { /* move cursor up */ if (cy < argi[0]) cy = 0; else cy -= argi[0]; goto updatecursor; } else if (ch == 'B') { /* move cursor down */ if ((cy += argi[0]) >= rows) cy = rows-1; goto updatecursor; } else if (ch == 'C') { /* move cursor right */ if ((cx += argi[0]) >= columns) cx = columns-1; goto updatecursor; } else if (ch == 'D') { /* move cursor left */ if (cx < argi[0]) cx = 0; else cx -= argi[0]; goto updatecursor; } else if (ch == 'l') { /* turn off line wrapping or set text mode */ if (argi[0] == 7) wraparound = 0; #ifdef GFX else { /* text mode */ curmodetype = 0; int10(curmode = defaultmode,0,0,0); esc_state = esc_init; } #endif } else if (ch == 'h') { /* turn on line wrapping or set graphics mode */ if (argi[0] == 7) wraparound = 1; #ifdef GFX else { /* graphics mode */ curmodetype = 0; int10(curmode = argi[0],0,0,0); esc_state = esc_init; } #endif } else if (ch == 'J') { /* clear screen and home cursor */ #ifdef GFX int10(0x0600,256*(curmodetype != 'T' ? reverse ? fg : bg : attr),0, 256*(rows-1)+columns-1); #else int10(0x0600,256*attr,0,256*(rows-1)+columns-1); #endif cx = cy = 0; goto updatecursor; } else if (ch == 'K') /* clear to end of line */ #ifdef GFX int10(curmodetype == 'T' ? 0x0920 : 0x09DB, curmodetype == 'T' ? 256*scr+attr : reverse ? fg : bg, columns-cx,0); #else int10(0x0920,256*scr+attr,columns-cx,0); #endif else if (ch == 's') { /* save cursor position */ scx = cx; scy = cy; } else if (ch == 'u') { /* restore cursor position */ cx = scx; cy = scy; goto updatecursor; } return; } void ansi_putc(unsigned int ch) { union axbxstruct u; #ifdef GFX if (in_gfx) { gfx_data = (gfx_data << 8) | ch; gfx_nbits += 8; while (gfx_nbits >= gfx_packed && in_gfx) { in_gfx--; ch = (gfx_data >> (gfx_nbits -= gfx_packed)) & ((1 << gfx_packed) - 1); if (curmodetype == 'T') { if (gfx_x < columns && gfx_y < rows*2) { int pix[2]; int10(0x0200,256*scr,0, /* move cursor position */ 256*(gfx_y/2)+gfx_x++); u.axbx = int10(0x0800,256*scr,0,0); /* read character/attribute */ if (u.lh.al == 0xDB) pix[0] = pix[1] = u.lh.ah &0xF; else if (u.lh.al == 0xDC) { pix[0] = (u.lh.ah/16)&0xF; pix[1] = u.lh.ah &0xF; } else pix[0] = pix[1] = (u.lh.ah/16)&0xF; pix[gfx_y&1] = coltable[ch & 0x7]; int10(0x0900| /* output char */ (pix[0]==pix[1]?0xDB:0xDC), 256*scr+(0x7F&(pix[0]*16+pix[1])),1,0); } if (!in_gfx) int10(0x0200,256*scr,0, /* restore cursor position */ 256*cy+cx); } else if (gfx_x < gfx_columns && gfx_y < gfx_rows) int10(0x0C00| /* write pixel */ (ch <= 7 ? coltable[ch] : ch),256*scr,gfx_x++,gfx_y); } return; } #endif switch (esc_state) { case esc_esc: if (ch == '[') { esc_state = esc_bracket; argn = 0; memset(&argi, 0, sizeof(argi)); memset(args, 0, MAXSTRARGS*MAXSTRARGLEN); } else { esc_state = esc_std; goto doputchar; } break; case esc_bracket: case esc_semicolon: if (ch == '\'') { esc_state = esc_str; break; } /* fall thru */ if (ch == '=' || ch == '?') break; /* fall thru */ case esc_digit: if (ch >= '0' && ch <= '9') { esc_state = esc_digit; if (argn < MAXARGS) argi[argn] = 10*argi[argn] + ch - '0'; } else quote: if (ch == ';') { esc_state = esc_semicolon; argn++; } else { if (esc_state == esc_digit || esc_state == esc_quote) argn++; esc_state = esc_std; docommand(ch); } break; case esc_str: if (ch == '\'') { esc_state = esc_quote; break; } { int i; if (argn < MAXSTRARGS && (i = strlen(args[argn])) < MAXSTRARGLEN-2) args[argn][i] = ch; } break; case esc_quote: goto quote; case esc_init: { int i; esc_state = esc_std; u.axbx = int10(0x0F00,0,0,0); /* get graphics mode information */ #ifdef GFX if (defaultmode < 0) defaultmode = curmode = u.lh.al ? u.lh.al : 3; #endif columns = u.lh.ah; scr = u.lh.bh; int10(0x0200,256*scr,0,0); /* put cursor to home position */ for (i = 0; ++i < 100; ) { int10(0x0E0A,256*scr,0,0); /* output LF */ int10(0x0300,256*scr,0,0); /* get cursor position */ if (int10ret.lh.dh != i) /* row */ break; } rows = i; int10(0x0200,256*scr,0,0); /* put cursor to home position */ #ifdef GFX char_width = 8; char_height = *(unsigned char *)0x485; if (char_height < 8 || char_height > 20) char_height = 8; gfx_columns = char_width*columns; gfx_rows = char_height*rows; if (!curmodetype) { int10(0x0941,256*scr+127,1,0); /* 'A', bright, white on white */ u.axbx = int10(0x0800,256*scr,0,0); /* read character/attribute */ if (u.lh.al == 0x41 && u.lh.ah == 127) curmodetype = 'T'; else { int10(0x0C40,256*scr,0,0); /* write pixel */ u.axbx = int10(0x0D00,256*scr,0,0); /* read pixel color */ if (u.lh.al == 0x40) curmodetype = 'H'; else curmodetype = 'G'; } } #endif attr = fg = 7; cx = cy = scx = scy = bg = blink = reverse = bright = 0; wraparound = 1; #ifdef GFX int10(0x0600, /* clear screen */ curmodetype != 'T' ? 0 : 7*256,0,256*(rows-1)+columns-1); } #else int10(0x0600, /* clear screen */ 7*256,0,256*(rows-1)+columns-1); } #endif /* fall thru */ default: if (ch == 0x1B) esc_state = esc_esc; else if (ch == '\t') { int i; for (i = 8-cx%8; i--; ) ansi_putc(' '); } else if (ch == '\r') { cx = 0; goto updatecursor; } else if (ch == '\n') { ansi_putc('\r'); goto newline; } else if (ch == '\010') { if (cx) { cx--; goto updatecursor; } } else { doputchar: #ifdef GFX if (curmodetype == 'G' && (reverse ? fg : bg)) int10(0x09DB,(attr/16)&0x07,1,0);/* set background in gfx mode */ #endif #ifdef GFX int10(0x0900|ch, /* output char */ curmodetype == 'H' ? reverse ? fg*256+bg : bg*256+fg : 256*scr+attr,1,0); #else int10(0x0900|ch,256*scr+attr,1,0); /* output char */ #endif if (++cx == columns) { if (!wraparound) cx--; else { cx = 0; newline: if (++cy == rows) #ifdef GFX int10(0x0601, /* scroll screen */ 256*(curmodetype != 'T' ? reverse ? fg : bg : attr),0, 256*--cy+columns-1); } #else int10(0x0601,256*attr,0, /* scroll screen */ 256*--cy+columns-1); } #endif } updatecursor: int10(0x0200,256*scr,0,256*cy+cx); /* update cursor position */ } } return; } mknbi-1.4.4/ansiesc.h0100644000175000001440000000014607500622145013115 0ustar kenusersextern void ansi_reset(void); extern void ansi_putc(unsigned int ch); extern void enable_cursor(int); mknbi-1.4.4/menuc.html0100644000175000001440000000374310110544104013307 0ustar kenusers menuc - compile a menu description into a binary file


NAME

menuc - compile a menu description into a binary file


SYNOPSIS

menuc [--output=outputfile] [inputfile]


DESCRIPTION

menuc compiles menu descriptions to data file suitable for interpretation by an Etherboot menu extension program.

--output=outputfile Specify the output file, can be used with all variants. Stdout is the default.

The package must be installed in the destination location before the executables can be run, because it looks for library files.


BUGS

Please report all bugs to the author.


SEE ALSO

Etherboot tutorial at http://etherboot.sourceforge.net/


COPYRIGHT

menuc is under the GNU Public License


AUTHOR

Ken Yap (ken_yap@users.sourceforge.net)


DATE

Version 0.9 January 2001

mknbi-1.4.4/disnbi.10100644000175000001440000001116510110544103012640 0ustar kenusers.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.14 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "DISNBI 1" .TH DISNBI 1 "2004-08-18" "Mknbi 1.4.4" "Etherboot tools" .SH "NAME" disnbi \- display Etherboot image .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBdisnbi\fR [\f(CW\*(C`\-e\*(C'\fR] \fIEtherboot-file\fR .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBdisnbl\fR is a program that to display in symbolic form the contents of a Etherboot image created by mknbi or mkelf. Detection of image type is automatic. .PP \&\fB\-e\fR Extract contents of image as well. The directory will be written to \f(CW\*(C`nbidir\*(C'\fR or \f(CW\*(C`elfdir\*(C'\fR and the segments to \f(CW\*(C`segment\*(C'\fR\fIn\fR where \fIn\fR is 0, 1, 2, etc. .SH "BUGS" .IX Header "BUGS" Please report all bugs to the author. .SH "SEE ALSO" .IX Header "SEE ALSO" Etherboot tutorial at \f(CW\*(C`http://etherboot.sourceforge.net/\*(C'\fR .SH "COPYRIGHT" .IX Header "COPYRIGHT" \&\fBdisnbl\fR is under the \s-1GNU\s0 Public License .SH "AUTHOR" .IX Header "AUTHOR" Ken Yap (\f(CW\*(C`ken_yap@users.sourceforge.net\*(C'\fR) .SH "DATE" .IX Header "DATE" Version 1.4 December 2002 mknbi-1.4.4/rmrd.com0100644000175000001440000000025707763526537013011 0ustar kenusers1Zu =t^%tot0P ! !XL!NetBNo ramdisk found$Ramdisk is not drive A:$Can't remove ramdisk$Ramdisk removed$ $mknbi-1.4.4/elf_boot.h0100644000175000001440000000511607600542063013264 0ustar kenusers#ifndef ELF_BOOT_H #define ELF_BOOT_H typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; /* This defines the structure of a table of parameters useful for ELF * bootable images. These parameters are all passed and generated * by the bootloader to the booted image. For simplicity and * consistency the Elf Note format is reused. * * All of the information must be Position Independent Data. * That is it must be safe to relocate the whole ELF boot parameter * block without changing the meaning or correctnes of the data. * Additionally it must be safe to permute the order of the ELF notes * to any possible permutation without changing the meaning or correctness * of the data. * */ #define ELF_BHDR_MAGIC 0x0E1FB007 typedef uint16_t Elf_Half; typedef uint32_t Elf_Word; typedef struct Elf_Bhdr { Elf_Word b_signature; /* "0x0E1FB007" */ Elf_Word b_size; Elf_Half b_checksum; Elf_Half b_records; } Elf_Bhdr; typedef struct Elf_Nhdr { Elf_Word n_namesz; /* Length of the note's name. */ Elf_Word n_descsz; /* Length of the note's descriptor. */ Elf_Word n_type; /* Type of the note. */ } Elf_Nhdr; /* Standardized Elf image notes for booting... The name for all of these is ELFBoot */ #define ELF_NOTE_BOOT "ELFBoot" #define EIN_PROGRAM_NAME 0x00000001 /* The program in this ELF file */ #define EIN_PROGRAM_VERSION 0x00000002 /* The version of the program in this ELF file */ #define EIN_PROGRAM_CHECKSUM 0x00000003 /* ip style checksum of the memory image. */ /* Notes that are passed to a loaded image */ /* For standard notes n_namesz must be zero */ #define EBN_FIRMWARE_TYPE 0x00000001 /* ASCIZ name of the platform firmware. */ #define EBN_BOOTLOADER_NAME 0x00000002 /* This specifies just the ASCIZ name of the bootloader */ #define EBN_BOOTLOADER_VERSION 0x00000003 /* This specifies the version of the bootloader as an ASCIZ string */ #define EBN_COMMAND_LINE 0x00000004 /* This specifies a command line that can be set by user interaction, * and is provided as a free form ASCIZ string to the loaded image. */ #define EBN_NOP 0x00000005 /* A note nop note has no meaning, useful for inserting explicit padding */ #define EBN_LOADED_IMAGE 0x00000006 /* An ASCIZ string naming the loaded image */ /* Etherboot specific notes */ #define EB_PARAM_NOTE "Etherboot" #define EB_IA64_SYSTAB 0x00000001 #define EB_IA64_MEMMAP 0x00000002 #define EB_IA64_FPSWA 0x00000003 #define EB_IA64_CONINFO 0x00000004 #define EB_BOOTP_DATA 0x00000005 #define EB_HEADER 0x00000006 #define EB_IA64_IMAGE_HANDLE 0x00000007 #endif /* ELF_BOOT_H */ mknbi-1.4.4/menuc.10100644000175000001440000001120210110544103012467 0ustar kenusers.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.14 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "MENUC 1" .TH MENUC 1 "2004-08-18" "Mknbi 1.4.4" "Etherboot tools" .SH "NAME" menuc \- compile a menu description into a binary file .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBmenuc\fR [\-\-output=\fIoutputfile\fR] [\fIinputfile\fR] .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBmenuc\fR compiles menu descriptions to data file suitable for interpretation by an Etherboot menu extension program. .PP \&\fB\-\-output=\fR\fIoutputfile\fR Specify the output file, can be used with all variants. Stdout is the default. .PP The package must be installed in the destination location before the executables can be run, because it looks for library files. .SH "BUGS" .IX Header "BUGS" Please report all bugs to the author. .SH "SEE ALSO" .IX Header "SEE ALSO" Etherboot tutorial at \f(CW\*(C`http://etherboot.sourceforge.net/\*(C'\fR .SH "COPYRIGHT" .IX Header "COPYRIGHT" \&\fBmenuc\fR is under the \s-1GNU\s0 Public License .SH "AUTHOR" .IX Header "AUTHOR" Ken Yap (\f(CW\*(C`ken_yap@users.sourceforge.net\*(C'\fR) .SH "DATE" .IX Header "DATE" Version 0.9 January 2001 mknbi-1.4.4/first32elf@0x82800.linux0100755000175000001440000001027610110544077015343 0ustar kenusers *)؎Ў$(,*@p pp,* *ËD$USVWMVff _^[]USVW}(u V'f1f fPAMSfrf=PAMSufNft fufX)_^[]SVW11Ҹr$utȉf%fff f%ff__^[fJfUSVWEÃ fff ؎fofPfS˃f_^[].g f"f)؎Ё(1X(PX-(P( ؎Ў f"fȎ؎fÉ')((8҉8t-BÊ]uf^ ~9sZBK 4C,09w< u1j h8Qi uCtt D$8D$49rD$48ELFu D$88th%8H $_D$88=cSc8D$t=CMUt=STANu 8 8T$4J1fz,t 8C B,9|8P 88@ D$ fx@A8v@ T$ D$B(@ D$D$f)fB ?fB"1|$Iq\$8 @=EthD$¸)9~B~C N~ BCNOC8@<ɉˆL$ Ʌɍ@~8:uNI@~~@D$ D$))D$t$F~a1|$I)9}HC ҋt$~8~&E<~u }bu\ <~u}cu :CNEECNCT$KJ;\$u888 t u$8B8B t t܅o8҉  =t@88B88R  =u8838=81҅uS78u>?8u)B8uI8҃eM88-8Pu\Q888uDZ88 u.a88 t8 8B¡8fu6d88t#8@t< t< uid888@t < t< 8pphh858888:8b88: 88t8:8ruto88t 8Ns88t 8/a88xt88z8MuC8Š0< w C0< vl$H<%t&|$@tT$BT$PYF0< w F0< v>.uF0< w F0< vM9y|$@Yt T$BT$ PZ;uJ<#|$ $u$F>hu F>huFЃ |$@tD$T$@)T$D$,[^_]ÍD$Pt$j ÍD$ Pt$ t$ ÐST$1ɀ:\$ t9uB:u[S\$L$ ڊABu[S\$;L$ tB:uAt BAu[VSt$ >\$L$tB:uCtItBCtIu[^WVS\$19ڋ|$t$}: 28t )B9|1[^_Out of parameter space %@mknbi-1.4.4/first32.c (ELF) (GPL) EtherbootBad argument vganfsrootiprdbasememaskextendednormal0xrom%@:%@:topasisTop of ramdisk is %#X Ramdisk at %#X, size %#X 0123456789ABCDEF%d.mknbi-1.4.4/first-dos.S0100644000175000001440000013276207716624552013404 0ustar kenusers; first.S - primary boot loader for DOS ; ; Copyright (C) 1996-1998 Gero Kuhlmann ; Modifications for booting FreeDOS by Ken Yap ; ; 2003.04.28 Robb Main ; Tweaks & bugfixes to allow use with much larger disk images, remove ; '2 head assumption', use 32-bit GDT, and other 'stuff'. ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #if !defined(USE_NASM) && !defined(USE_AS86) #define USE_AS86 #endif #ifdef USE_AS86 #define CON(x) *x #define BCON(x) *x #define LOC(x) x #define BLOC(x) byte ptr x #define WLOC(x) word ptr x #define JMP(x) jmp x #define STRDECL(s) .ascii s #define SEGCS seg cs #define SEGES seg es #define ALIGN(x) .align x #define SPACE(x) .space x #endif #ifdef USE_NASM #define CON(x) x #define BCON(x) byte x #define LOC(x) [x] #define BLOC(x) byte [x] #define WLOC(x) word [x] #define JMP(x) jmp short x #define STRDECL(s) db s #define SEGCS cs #define SEGES es #define ALIGN(x) align x, db 0 #define SPACE(x) times x db 0 #endif #ifndef ASM_DEBUG #undef ASM_DEBUG #endif #include "first-dos.h" #include "version-dos.h" #ifdef USE_AS86 .text .org 0 #endif #ifdef USE_NASM text #endif _start: mov dx,ds mov ax,cs ; set DS mov ds,ax mov LOC(oldES),es mov LOC(oldDS),dx ; save old register values in case mov LOC(oldBP),bp ; we have to return to the boot rom mov LOC(oldSI),si mov LOC(oldDI),di mov bp,sp mov ax,[bp+4] mov LOC(header+0),ax ; load the address of the boot header mov ax,[bp+6] mov LOC(header+2),ax mov ax,[bp+8] mov LOC(bootp+0),ax ; load the address of the bootp block mov ax,[bp+10] mov LOC(bootp+2),ax ; Tell the user who we are and that we started running mov si,CON(sigmsg) call prnstr ; Check if the boot image header is correct. les bx,LOC(header) mov si,CON(bmerr) ; prepare for correct error message SEGES mov ax,[bx+BOOT_HD_MAGIC+0] cmp ax,LOC(bmagic+0) ; compare boot rom magic numbers jne doerr1 SEGES mov ax,[bx+BOOT_HD_MAGIC+2] cmp ax,LOC(bmagic+2) jne doerr1 mov si,CON(vmerr) ; prepare for correct error message SEGES mov al,[bx+BOOT_HD_LENGTH] mov cl,CON(4) shr al,cl and al,CON(0x0F) cmp al,CON(VENDOR_SIZE) ; check vendor ID size jne doerr1 xor di,di dovmag: mov al,[di+vmagic] ; check vendor ID or al,al jz getrd ; vendor ID ok, continue SEGES cmp al,[bx+di+BOOT_HD_VENDOR] jne doerr1 inc di JMP(dovmag) doerr1: call prnstr ; in case of error return to the mov si,LOC(oldSI) ; boot rom with registers set mov di,LOC(oldDI) ; correctly mov bp,LOC(oldBP) mov es,LOC(oldES) mov ds,LOC(oldDS) retf ; Next get the address of the ramdisk and its size. getrd: mov si,CON(recerr) mov al,CON(VENDOR_RAMDISK) call fndldr ; find load record for ramdisk mov ax,es or ax,di jz doerr1 SEGES mov al,[di+BOOT_LD_FLAGS] ; get load record flags test al,CON(BOOT_FLAG_B0 + BOOT_FLAG_B1) ; check that it has a jnz doerr1 ; correct flag SEGES mov ax,[di+BOOT_LD_ADDR+0] ; get base adress of ramdisk SEGES mov bx,[di+BOOT_LD_ADDR+2] mov LOC(rdaddr+0),ax mov LOC(rdaddr+2),bx SEGES mov ax,[di+BOOT_LD_MLENGTH+0] ; get ramdisk size SEGES mov bx,[di+BOOT_LD_MLENGTH+2] add ax,CON(0x03ff) ; round to nearest kb adc bx,BCON(0) mov cl,CON(10) shr ax,cl ; convert into kb mov cl,CON(6) shl bx,cl or ax,bx mov LOC(rdsize),ax ; Get the disk geometry out of the vendor information block in the ; load record SEGES mov bl,[di+BOOT_LD_LENGTH] and bl,CON(0x0f) xor bh,bh ; compute pointer to shl bx,CON(1) ; vendor block shl bx,CON(1) SEGES mov ax,[di+bx+BOOT_LD_SECNUM] ; get number of sectors mov LOC(secnumlo),ax SEGES mov ax,[di+bx+BOOT_LD_SECNUM+2] ; get number of sectors mov LOC(secnumhi),ax SEGES mov ax,[di+bx+BOOT_LD_HEADS] ; get head count mov LOC(heads),al SEGES mov ax,[di+bx+BOOT_LD_SPT] ; get sectors per track mov LOC(secptk),al SEGES mov ax,[di+bx+BOOT_LD_CYL] ; get number of cylinders mov LOC(cylnum),ax SEGES mov al,[di+bx+BOOT_LD_NOHD] ; get no-hard-disk flag mov LOC(nohd),al SEGES mov al,[di+bx+BOOT_LD_DRIVE] ; get ram disk drive id mov LOC(drvid),al ; Set the address of the BIOS disk status byte mov bx,CON(BIOS_FDSTAT) cmp al,CON(0x80) jb setsts mov bx,CON(BIOS_HDSTAT) setsts: mov LOC(statof),bx ; Get system configuration from BIOS push ax int 0x11 mov LOC(syscnf),ax pop ax ; Get the number of floppy or hard disk drives in the system and set ; the DOS disk parameter block cmp al,BCON(0x80) jae getnm2 mov ah,CON(0x08) xor dl,dl int 0x13 ; get the number of floppy disk jc getnm1 ; drives from the BIOS or dl,dl jnz gotnum inc dl ; indicate at least one drive JMP(gotnum) getnm1: mov dx,LOC(syscnf) ; if int 13h didnt work try it with test dl,CON(0x01) ; the mainboard dip switch config jz getnm3 mov cl,CON(6) shr dl,cl and dl,CON(0x03) ; determine number of floppy disk inc dl ; drives JMP(gotnum) getnm2: mov ah,CON(0x08) mov dl,CON(0x80) int 0x13 ; get the number of hard disk jc getnm3 ; drives from the BIOS inc dl JMP(gotnum) ; The next line was mov dl,1 in netboot-0.8.1. This was probably an error. getnm3: mov dl,CON(1) ; we have at least one drive gotnum: mov LOC(drvnum),dl ; save number of disk drives call setdpb ; set disk parameter block ; Now get the boot sector of the ramdisk and check that its correct. If ; we are simulating a hard disk the boot sector contains the partition ; table, which we have to analyze. Then load the partitions boot sector. mov ax,CON(TEMP_SEGMENT) mov es,ax ; pointer to temporary buffer xor bx,bx xor dx,dx ; first sector xor ax,ax xor ch,ch ; indicate read mov cl,1 ; one sector call rwsect ; read boot sector mov si,CON(rderr) jc doerr2 cmp BLOC(drvid),CON(0x80) ; if the ram disk is simulates a jb chkbot ; floppy, there is no partition table mov si,CON(dskerr) ; prepare for correct error message SEGES cmp BLOC(PART_STATUS),CON(PART_ACTIVE) jne doerr2 SEGES cmp BLOC(PART_TYPE),CON(PART_FAT16) je partok SEGES cmp BLOC(PART_TYPE),CON(PART_FAT12) jne doerr2 partok: SEGES mov dx,[PART_ABS_SECT+2] ; get number of first sector SEGES mov ax,[PART_ABS_SECT+0] xor ch,ch ; indicate read mov cl,1 ; one sector call rwsect ; read boot sector mov si,CON(rderr) jc doerr2 #ifndef HD_PARM_CHECK JMP(dobotp) #endif chkbot: mov si,CON(dskerr) ; prepare for correct error message mov al,LOC(drvid) SEGES cmp BLOC(DISK_BOOT),al ; check boot disk number jne doerr2 SEGES cmp WLOC(DISK_BPS),CON(SECT_SIZE) ; check sector size jne doerr2 SEGES cmp WLOC(DISK_HEADS),BCON(16) ; check number of heads jg doerr2 SEGES mov ax,LOC(DISK_SPT) ; check number of sectors per track cmp al,LOC(secptk) je dobotp doerr2: call prnstr ; in case of error return to the #if 1 push ax mov ah,0 ; wait for a keypress, so user int 0x16 ; can read the error message pop ax #endif mov si,LOC(oldSI) ; boot rom with registers set mov di,LOC(oldDI) ; correctly mov bp,LOC(oldBP) mov es,LOC(oldES) mov ds,LOC(oldDS) retf ; Save the BOOTP record for later retrieval by a DOS program. dobotp: cld xor dx,dx les di,LOC(bootp) mov ax,es or ax,di jz dobot9 SEGES mov al,[di+BOOTP_OP] ; op code must indicate reply cmp al,CON(BOOTP_REPLY) jne dobot9 ; it isnt add di,CON(BOOTP_VEND) mov bx,di mov si,CON(pmagic) ; compare vendor ID dobot1: mov di,bx mov cx,CON(BOOTP_MAGIC_LEN) repe cmpsb jz dobot2 ; vendor ID is valid add si,cx #ifdef USE_AS86 cmp byte ptr[si],CON(0) ; check next vendor ID #endif #ifdef USE_NASM cmp byte [si],CON(0) ; check next vendor ID #endif jne dobot1 dobot9: JMP(nobot2) ; vendor ID not found doerr6: JMP(doerr2) dobot2: sub si,BCON(BOOTP_MAGIC_LEN) sub si,CON(pmagic) mov ax,si push ds mov bx,ds mov es,bx mov di,CON(btpnew) lds si,LOC(bootp) mov bx,si mov dx,CON(BOOTP_SIZE) or ax,ax ; if not RFC vendor ID the bootp jnz dobot7 ; record has fixed length xor cx,cx add si,CON(BOOTP_VEND + BOOTP_MAGIC_LEN) dobot3: lodsb cmp al,CON(BOOTP_RFC_NOP) ; handle NOP tag jnz dobot4 inc cx cmp cx,BCON(16) ; more than 16 NOP tags is VERY unusual jae dobot7 ; so the bootp record maybe broken JMP(dobot3) ; loop to next tag nobot2: JMP(nobotp) dobot4: cmp al,CON(BOOTP_RFC_END) ; handle END tag jnz dobot6 mov dx,si sub dx,bx ; compute length of bootp record cmp dx,CON(BOOTP_SIZE) jae dobot7 mov dx,CON(BOOTP_SIZE) ; use minimum size JMP(dobot7) dobot6: lodsb ; handle all other tags mov cl,al xor ch,ch add si,cx ; jump to next tag xor cx,cx ; reset NOP counter JMP(dobot3) ; proceed with next tag dobot7: mov si,CON(btperr) mov ax,CON(btpnew) ; bootp record cannot be larger add ax,dx ; than the current segment jc doerr6 mov cx,dx mov si,bx ; restore source pointer rep movsb ; save the bootp record pop ds nobotp: mov LOC(btplen),dx ; set length of bootp record ; Everything is right, so we can now move the resident section to the ; end of the conventional memory, thus overwriting the bootrom data ; area. Therefore there is no chance of returning to the bootrom from ; now on. ; Note that the resident section doesnt start at offset 0, so we have ; to set the segment address to somewhere lower. #ifdef ASM_DEBUG mov si,CON(debug1) call prnstr #endif cli mov ax,CON(TEMP_SEGMENT) ; set new stack mov ss,ax mov sp,CON(0xFFF0) cld int 0x12 ; get memory size in kB #ifdef FREEDOS push ax ; save mem size in kB #endif /* FREEDOS */ mov cl,CON(6) shl ax,cl ; compute last usable segment mov bx,CON(btpnew) add bx,LOC(btplen) mov dx,bx mov cl,CON(4) shr bx,cl ; compute size of code segment in inc bx ; paragraphs #ifdef FREEDOS push bx ; save size in paragraphs #endif /* FREEDOS */ sub ax,bx ; compute new code segment mov LOC(resseg),ax mov es,ax ; set source and destination ptrs mov si,CON(start_resident) mov di,si mov cx,dx sub cx,si ; compute size of resident area rep movsb ; move it #ifdef FREEDOS ; New code for FreeDOS, adjust the value of the top of memory returned by ; int 0x12. Currently there is no code to restore the original size pop bx ; restore size in paragraphs add bx,BCON(63) ; round up to next kB mov cl,CON(6) ; divide by 64 shr bx,cl pop ax ; restore size in kB sub ax,bx mov bx,CON(0x40) mov es,bx SEGES mov LOC(0x13),ax ; store at 0x40:0x13 for int 12h ; End of new code #endif /* FREEDOS */ ; Setup all interrupt vectors mov bx,LOC(resseg) push ds mov ds,bx xor ax,ax mov es,ax SEGES mov ax,LOC(I13_INT+0) mov LOC(old13h+0),ax SEGES mov ax,LOC(I13_INT+2) mov LOC(old13h+2),ax SEGES mov ax,LOC(I2F_INT+0) mov LOC(old2Fh+0),ax SEGES mov ax,LOC(I2F_INT+2) mov LOC(old2Fh+2),ax SEGES mov ax,LOC(IF1_INT+0) mov LOC(oldF1h+0),ax SEGES mov ax,LOC(IF1_INT+2) mov LOC(oldF1h+2),ax SEGES mov ax,LOC(IF8_INT+0) mov LOC(oldF8h+0),ax SEGES mov ax,LOC(IF8_INT+2) mov LOC(oldF8h+2),ax pop ds SEGES mov LOC(I13_INT+2),bx ; interrupt vector 13h SEGES mov WLOC(I13_INT+0),CON(int13) SEGES mov LOC(I2F_INT+2),bx ; interrupt vector 2Fh SEGES mov WLOC(I2F_INT+0),CON(int2F) SEGES mov LOC(IF8_INT+2),bx ; interrupt vector F8h SEGES mov WLOC(IF8_INT+0),CON(intF8) mov di,CON(IF1_INT) mov si,CON(if1sig) ; interrupt vector F1h mov cx,CON(4) ; contains the string "NetB" rep ; to provide as an installation movsb ; check sti ; Output some debugging messages by simply calling the interrupt vectors ; which we just created. #ifdef DRV_DEBUG mov ax,CON(0x4A06) int 0x2F mov si,CON(consz) call prnstr ; print out amount of conventional mov ax,dx ; memory mov cl,CON(12) shr ax,cl call prnwrd mov ax,dx mov cl,CON(4) shl ax,cl call prnwrd mov si,CON(bytes) call prnstr mov ax,CON(0x8800) int 0x15 push ax mov si,CON(extsz) call prnstr ; print out amount of extended memory mov cl,CON(6) shr ax,cl call prnwrd pop ax mov cl,CON(10) shl ax,cl call prnwrd mov si,CON(bytes) call prnstr #endif #ifndef FREEDOS ; The boot sector had to be placed into a temporary memory area to ; avoid overwriting any bootrom structures. However, a call back ; to the bootrom is no longer possible, so we can move the bootblock ; where it belongs. push ds mov ax,CON(TEMP_SEGMENT) mov ds,ax xor ax,ax mov es,ax xor si,si mov di,CON(BOOT_OFFSET) mov cx,CON(SECT_SIZE) rep movsb ; move it pop ds ; Finally call the boot sector #else ; Finally call kernel.sys #endif /* FREEDOS */ #ifdef ASM_DEBUG mov si,CON(debug2) call prnstr #endif #ifdef FREEDOS mov bl,LOC(drvid) ; FreeDOS gets boot drive from bl, 0=A #else mov dl,LOC(drvid) ; boot block may expect this #endif #ifdef ASM_FREEZE_AFTER_INIT lop: JMP(lop) #else #ifdef FREEDOS jmp FDKSEG:0 ; FreeDOS kernel.sys entry point #else jmp 0:BOOT_OFFSET #endif /* FREEDOS */ #endif ;==================================================================== ; ; Setup DOS drive parameter block (DPB) for floppy disk drive. The ; DPB is required to activate the floppy disk drive after the ramdisk ; has been turned off. ; Input: none ; Output: none ; Registers changed: AX, BX, CX, DX setdpb: push es push si push di mov dl,LOC(drvid) cmp dl,CON(0x80) ; can only restore floppy drives jae setdp8 ; First get the drive parameters from the BIOS mov LOC(dpb_phys),dl ; set physical drive ID mov ah,CON(0x08) ; get drive parameters from BIOS int 0x13 jc setdp8 xor ah,ah mov al,ch ; set max number of cylinders inc ax mov LOC(dpb_cyls),ax mov si,CON(dpb_bpb_cur) mov al,cl ; set max number of sectors per track mov [si+BPB_SPT],ax mov al,dh inc ax ; set max number of heads mov [si+BPB_HEADS],ax ; Determine DOS disk parameters by drive type cmp bl,CON(5) jb setdp1 ; check for invalid drive type mov bl,CON(4) setdp1: xor bh,bh dec bx push bx shl bx,CON(1) shl bx,CON(1) ; compute address into drive para- add bx,CON(drvtab) ; meter table xor ah,ah mov al,[bx+0] ; get # of entries in root dir mov [si+BPB_DIR],al mov al,[bx+1] ; get # of sectors per FAT mov [si+BPB_SPF],ax mov al,[bx+2] ; get # of sectors per cluster mov [si+BPB_SPC],al mov al,[bx+3] ; get media ID mov [si+BPB_MEDIA_ID],al pop bx mov al,[bx+typtab] ; get drive type mov LOC(dpb_type),al ; Determine number of bytes per sector SEGES mov cl,[di+3] ; get shift value from BIOS media mov ax,CON(128) ; parameter table shl ax,cl ; shift base value mov [si+BPB_BPS],ax JMP(setdp4) setdp8: JMP(setdp9) ; needed for short jumps ; Determine total number of sectors setdp4: mov ax,[si+BPB_SPT] mul WLOC(dpb_cyls) or dx,dx ; should not overflow jnz setdp8 #ifdef USE_AS86 cmp [si+BPB_HEADS],BCON(2) #endif #ifdef USE_NASM cmp word [si+BPB_HEADS],BCON(2) #endif jb setdp3 shl ax,CON(1) jc setdp8 setdp3: mov [si+BPB_TOT_SECTS],ax ; Determine if the drive can detect disk changes mov ah,CON(0x15) mov dl,LOC(drvid) int 0x13 ; get DASD type from BIOS mov bl,ah mov ax,CON(DPB_F_DEFAULT) jc setdp2 cmp bl,CON(0x02) ; check if drive detects disk changes jne setdp2 or ax,CON(DPB_F_DOOR) setdp2: mov LOC(dpb_flags),ax ; set flags ; Thats it inc BLOC(dpb_valid) ; increment valid flag setdp9: pop di pop si pop es ret ;==================================================================== ; ; Find a load record in the boot header. The ID number of the load ; record is in AL, and ES:DI points to requested load record, or is ; the NULL pointer if load record not found. ; ; Changed registers: AX, DI, ES fndldr: push cx mov ch,al les di,LOC(header) ; examine boot image header SEGES mov al,[di+BOOT_HD_LENGTH] ; get length of image header call getlen add di,ax ; get the pointer to first load record fndl1: SEGES cmp ch,[di+BOOT_LD_TAG1] ; is it the desired one ? je fndl3 SEGES mov al,[di+BOOT_LD_FLAGS] ; no, so check if its the last record test al,CON(BOOT_FLAG_EOF) jnz fndl2 SEGES mov al,[di+BOOT_LD_LENGTH] ; no, get the address of the next one call getlen add di,ax JMP(fndl1) fndl2: xor ax,ax ; couldnt find the desired record mov es,ax mov di,ax fndl3: pop cx ret ;==================================================================== ; ; Compute the length of a load record address from a length byte ; in AL. Return the offset in AX. ; ; Changed registers: AX getlen: push cx mov ah,al mov cl,CON(4) shr ah,cl and ax,CON(0x0f0f) ; compute the total length in add al,ah ; bytes from the length of the xor ah,ah ; record and that of the vendor shl ax,1 ; information. shl ax,1 pop cx ret ;==================================================================== ; Print a string in DS:SI onto the console ; ; Changed registers: AL prnstr: push si cld prns1: lodsb ; loop over all characters of or al,al ; string jz prns2 push bx mov ah,CON(0x0E) ; print it mov bl,CON(0x07) xor bh,bh int 0x10 pop bx JMP(prns1) prns2: pop si ret #ifdef DRV_DEBUG ;==================================================================== ; ; Print hexadecimal values (in AX or AL) or characters onto the console ; ; Changed registers: AX prnwrd: push ax mov al,ah call prnbyt ; print the upper byte pop ax prnbyt: push ax shr al,1 ; prepare upper nibble shr al,1 shr al,1 shr al,1 call prnnib ; print it pop ax prnnib: and al,CON(0x0F) ; prepare lower nibble add al,CON(0x30) cmp al,CON(0x39) ; convert it into hex jle prnchr add al,CON(7) prnchr: push bx mov ah,CON(0x0E) ; print it mov bl,CON(0x07) xor bh,bh int 0x10 pop bx ret #endif ;==================================================================== ; ; String and constants definitions ; Startup signature sigmsg: db 0x0D, 0x0A STRDECL('DOS Net Boot Image Loader ') STRDECL(VERSION) db ' ' STRDECL(VENDOR_MAGIC) db 0x0D, 0x0A STRDECL(COPYRIGHT) db 0x0D, 0x0A crlf: db 0x0D, 0x0A db 0 ; Magic numbers for boot record and bootp entry bmagic: dd BOOT_MAGIC ; boot image magic number vmagic: STRDECL(VENDOR_MAGIC) ; vendor magic ID db 0 ; end of vendor magic ID pmagic: db BOOTP_MAGIC_RFC ; bootp magic ID for RFC 1048 db BOOTP_MAGIC_CMU ; bootp magic ID for CMU db BOOTP_MAGIC_STA ; bootp magic ID for Stanford db 0 ; Specifications for different types of disk drives. The order is: ; # dir entries, # sects per FAT, # sects per cluster, media ID drvtab: db 112, 2, 2, 0xfd ; 360kB disk db 224, 7, 1, 0xf9 ; 1.2MB disk db 112, 3, 2, 0xf9 ; 720kB disk db 224, 9, 1, 0xf0 ; 1.44 MB disk typtab: db DPB_T_360 ; type values for drive parameter block db DPB_T_1200 db DPB_T_720 db DPB_T_1440 ; Error messages recerr: STRDECL('Error in load record data') db 0x0D, 0x0A db 0 bmerr: STRDECL('Invalid boot header magic number') db 0x0D, 0x0A db 0 vmerr: STRDECL('Invalid vendor magic ID') db 0x0D, 0x0A db 0 rderr: STRDECL('Error while accessing ramdisk') db 0x0D, 0x0A db 0 dskerr: STRDECL('Wrong ramdisk image') db 0x0D, 0x0A db 0 btperr: STRDECL('BOOTP record invalid') db 0x0D, 0x0A db 0 ; Debug messages #ifdef ASM_DEBUG debug1: STRDECL('Making driver resident') db 0x0D, 0x0A db 0 debug2: #ifdef ASM_FREEZE_AFTER_INIT STRDECL('Freezing;') #else STRDECL('Calling boot block') #endif db 0x0D, 0x0A db 0 #endif #ifdef DRV_DEBUG consz: STRDECL('RAMDISK: reporting conventional memory size: ') db 0 extsz: STRDECL('RAMDISK: reporting extended memory size: ') db 0 bytes: STRDECL(' bytes') db 0x0D,0x0A db 0 #endif ;==================================================================== ; ; Variable definitions header: dd 0 ; pointer to boot header from boot rom bootp: dd 0 ; pointer to bootp block from boot rom resseg: dw 0 ; segment of resident section oldDS: dw 0 ; old DS from boot rom oldES: dw 0 ; old ES from boot rom oldBP: dw 0 ; old BP from boot rom oldSI: dw 0 ; old SI from boot rom oldDI: dw 0 ; old DI from boot rom ;==================================================================== ; ; Start of resident section. This will be placed at the end of the ; low 640kB RAM area. ; ;==================================================================== ; ALIGN(16) ; has to be paragraph aligned start_resident: ; indicate start of resident section ;==================================================================== ; ; New interrupt 2Fh routine. This routine gets called by IO.SYS ; in order to determine the maximum amount of memory usable to ; DOS. This only works with DOS versions 5.0 and higher. The DOS ; function which gets installed into the interrupt 2Fh vector ; does not call the old vector (i.e. it does not daisy-chain), ; and therefore we can redirect 2Fh without a problem even when ; considering to remove the ram disk lateron. ; ; NOTE THAT THIS INTERRUPT HAS TO BE THE FIRST ROUTINE IN THE ; RESIDENT SECTION! ; ; Input: AX - Magic ID ; DX - segment following last usable byte ; Output: DX - new segment following last usable byte ; Registers changed: DX int2F: JMP(int2F1) ; this has to be a relative jump nop STRDECL('RPL') ; magic ID string for DOS int2F1: cmp ax,CON(0x4A06) ; check for magic ID jne int2F9 push cx mov dx,CON(start_resident) ; determine last usable segment mov cl,CON(4) ; from segment and offset of shr dx,cl ; the resident section pop cx push ax push cs pop ax add dx,ax ; add offset to segment dec dx pop ax iret int2F9: SEGCS jmp far [old2Fh] ; jump to old interrupt routine ;==================================================================== ; ; New interrupt F8h routine. It can be used to retrieve several ; values from the resident driver. ; Input: AX - function code ; Output: depends on function: ; ; Installation check (AX = 0x9C00) ; AX - contains 0x009C ; ; Return ramdisk size and address (AX = 0x9C01) ; BX:DX - address of ramdisk ; CX - size of ramdisk in kb ; ; Return size and address of BOOTP block (AX = 0x9C02) ; BX:DX - address of BOOTP block ; CX - size of BOOTP block ; ; Return miscellaneous values for handling the ramdisk (AX = 0x9C03) ; AX - XMS handle for ram disk ; BX:DX - address of old interrupt vector table ; CL - ramdisk id ; ; Remove ramdisk (AX = 0x9C04) ; AL - non-zero if error ; ; Registers changed: depends on function intF8: cmp ah,CON(0x9C) ; check for magic ID jne intF89 cmp al,CON(01) ; check for function number jne intF81 SEGCS mov bx,LOC(rdaddr+2) ; return ramdisk address SEGCS mov dx,LOC(rdaddr+0) SEGCS mov cx,LOC(rdsize) ; return ramdisk size iret intF81: cmp al,CON(0x02) jne intF82 mov bx,cs ; return address of BOOTP record mov dx,CON(btpnew) SEGCS mov cx,LOC(btplen) ; return BOOTP length iret intF82: cmp al,CON(0x03) jne intF83 mov bx,cs ; return address of old interrupt mov dx,CON(oldints) ; vector table SEGCS mov cl,LOC(drvid) ; return drive id SEGCS mov ax,LOC(xmshdl) ; return XMS handle iret intF83: cmp al,CON(0x04) jne intF88 call rmrd ; remove ramdisk iret intF88: or al,al jnz intF89 xchg al,ah ; return installation check code intF89: iret ;==================================================================== ; ; New interrupt 13h routine to handle disk accesses. It is different ; for simulating either a floppy drive or a hard disk. DOS provides ; a way for restoring this interrupt to its original value when we ; want to remove the ramdisk lateron. ; Input: AH - function code ; DL - driver number ; Output: carry flag set if error ; Registers changed: depends on function int13: sti ; we dont need interrupts disabled push ax SEGCS mov ax,LOC(xmsadr+0) SEGCS or ax,LOC(xmsadr+2) ; check if XMS already initialized jnz int13s mov ax,CON(0x4300) ; check if XMS available int 0x2f cmp al,CON(0x80) ; XMS not available jne int13s push bx push es mov ax,CON(0x4310) ; get XMS driver address int 0x2f SEGCS mov LOC(xmsadr+0),bx ; save driver address SEGCS mov LOC(xmsadr+2),es pop es call inixms ; initialize XMS pop bx int13s: pop ax SEGCS cmp dl,LOC(drvid) ; check if its for us je int132 SEGCS cmp BLOC(drvid),CON(0x80) ; check if we are to simulate a hard jae int13h ; disk drive ; First comes the floppy drive redirector cmp dl,CON(0x80) ; check if its for a hard disk jb int133 SEGCS test BLOC(nohd),CON(0xff) ; check if hard disk accesses allowed jz int131 cmp ah,CON(0x08) ; function 0x08 should not return error mov ah,CON(0x80) ; return with error jne int135 xor dl,dl ; indicate no hard disk present JMP(int13f) ; return without error ; Handle function 0x08 for disk drives other than the ramdisk. int133: cmp ah,CON(0x08) jne int131 pushf SEGCS ; function 0x08 has to return the call far [old13h] ; correct number of disk drives SEGCS mov dl,LOC(drvnum) int13f: xor ah,ah ; never return an error JMP(int136) ; Jump directly to the BIOS int131: SEGCS jmp far [old13h] ; call the old interrupt routine ; Now handle all ramdisk functions. First check if the function number ; is correct. int132: cmp ah,CON(0x18) jbe int134 mov ah,CON(0x01) ; unknown command int135: stc int136: push ds JMP(int13e) ; Determine the handlers address according to the function number in AH ; and jump to it. int134: push ds push cs pop ds ; set data segment push bx mov bl,ah xor bh,bh shl bx,CON(1) ; compute pointer into routine table jmp [bx+fntab] ; Now comes the hard disk drive redirector int13h: cmp dl,CON(0x80) ; check if its for a floppy drive jb int131 ; Handle function 0x08 for hard disk drives other than the ramdisk. cmp ah,CON(0x08) jne int137 dec dl pushf SEGCS ; function 0x08 has to return the call far [old13h] ; correct number of disk drives SEGCS mov dl,LOC(drvnum) JMP(int13f) ; always return without error ; Handle function 0x15 for disk drives other than the ramdisk. This is ; the only function besides 0x08 which returns a value in DX and therefore ; has to have special handling. int137: push dx dec dl cmp ah,CON(0x15) jne int138 pushf SEGCS call far [old13h] ; call the BIOS for handling jc int139 cmp ah,CON(0x03) ; DX is only used if AH = 0x03 jne int139 add sp,BCON(0x0002) ; remove DX from stack if the BIOS JMP(int136) ; returned a value in it ; Handle all other functions for drives other than the ramdisk. This will ; just call the original BIOS handler. int138: pushf SEGCS call far [old13h] ; simply call the old int 13h routine int139: pop dx JMP(int136) ; Save the return status into the BIOS data area and return to the caller ; while preserving the carry flag. int13e: push es ; return from function handler push bx ; this code is not allowed to change call getsts ; any register or flag SEGES mov [bx],ah ; set disk operation status pop bx pop es intend: pop ds push ax ; general exit point for interrupts pushf pop ax push bp mov bp,sp mov [bp+8],al ; put the flags onto the stack pop bp pop ax iret ; Function table fntab: dw f1300 ; function 00: reset disk system dw f1301 ; function 01: return last error dw f1302 ; function 02: read disk dw f1303 ; function 03: write disk dw f1304 ; function 04: verify disk dw f1305 ; function 05: format disk dw f1306 ; function 06: format track dw f1307 ; function 07: format disk dw f1308 ; function 08: get drive parameters dw f1309 ; function 09: intialize controller dw f130A ; function 0A: read long sectors dw f130B ; function 0B: write long sectors dw f130C ; function 0C: seek for cylinder dw f130D ; function 0D: disk reset dw f130E ; function 0E: read sector buffer dw f130F ; function 0F: write sector buffer dw f1310 ; function 10: check if drive ready dw f1311 ; function 11: recalibrate drive dw f1312 ; function 12: controller ram diagnostic dw f1313 ; function 13: drive diagnostic dw f1314 ; function 14: controller int diagnostic dw f1315 ; function 15: get disk type dw f1316 ; function 16: detect disk change dw f1317 ; function 17: set media type for format dw f1318 ; function 18: set media type for format f13end: JMP(int13e) ;==================================================================== ; ; Function 00 - reset disk system ; f1300: test WLOC(syscnf),CON(0x0001) ; check if we have physical floppy jz f13001 ; drives at all push dx xor dl,dl ; always reset the floppy system pushf call far [old13h] ; call old disk interrupt pop dx jc f13002 f13001: xor ah,ah ; no error f13002: pop bx JMP(f13end) ;==================================================================== ; ; Function 01 - return last error status ; f1301: push es call getsts ; get offset to status byte SEGES mov ah,[bx] ; get disk operation status pop es pop bx clc JMP(intend) ;==================================================================== ; ; Function 02/03 - read from/write to disk f1302: f1303: pop bx ; get old BX from stack push dx push cx push bx push ax xchg cx,ax sub ch,2 ; ch=0 for reads, ch=1 for writes call cvtsec ; get linear sector number jnc f13026 pop ax mov ah,CON(0x04) ; error: sector not found f13021: pop bx pop cx pop dx stc JMP(f13end) ; terminate f13022: cmp dx,LOC(secnumhi) ; check if sector is still correct jb f13024 cmp ax,LOC(secnumlo) jbe f13024 mov ah,CON(0x04) ; error: sector not found f13023: pop bx mov al,bl sub al,cl ; compute number of sectors processed JMP(f13021) f13024: call rwsect ; actually handle request jnc f13025 mov ah,CON(0x20) ; error: disk controller error JMP(f13023) f13025: inc ax ; proceed with next linear sector adc dx,CON(0) add bx,CON(SECT_SIZE) ; increment src/dst address dec cl ; decrement sector count f13026: or cl,cl jnz f13022 f13027: pop ax pop bx pop cx pop dx xor ah,ah ; no error f13e1: JMP(f13end) ;==================================================================== ; ; Function 08 - get disk drive parameters f1308: pop bx ; get old BX from stack mov dl,LOC(drvnum) ; get number of disk drives mov cl,LOC(secptk) ; get sectors per track mov ch,LOC(cylnum) ; number of cylinders mov dh,LOC(heads) ; number of heads - 1 dec dh xor bx,bx ; ramdisk drive type xor ax,ax dec ch JMP(f13e1) ;==================================================================== ; ; Function 04, 05, 06, 07, 09, 0D, 10, 11, 12, 13, 14, 16 - no operation f1304: f1305: f1306: f1307: f1309: f130D: f1310: f1311: f1312: f1313: f1314: f1316: pop bx ; get old BX from stack xor ah,ah ; no error JMP(f13e1) ;==================================================================== ; ; Function 0A, 0B, 0E, 0F, 17, 18 - not implemented f130A: f130B: f130E: f130F: f1317: f1318: pop bx ; get old BX from stack mov ah,CON(0x01) ; invalid opcode stc JMP(f13e1) ;==================================================================== ; ; Function 0C - seek for cylinder f130C: pop bx ; get old BX from stack push dx push cx push ax xchg ax,cx call cvtsec ; get linear sector number pop ax mov ah,CON(0x00) ; no error jnc f130C1 mov ah,CON(0x04) ; error: sector not found f130C1: pop cx pop dx JMP(f13e1) ; terminate ;==================================================================== ; ; Function 15 - get disk type f1315: pop bx ; get old BX from stack mov ah,CON(0x02) ; indicate floppy disk cmp dl,CON(0x80) ; check if floppy disk type requested jb f13159 inc ah ; indicate hard disk mov dx,LOC(secnumlo) ; get number of sectors on disk mov cx,LOC(secnumhi) f13159: clc JMP(f13e1) ;==================================================================== ; ; Convert Cyl/Sec/Head notation into a linear sector number ; Input: AH - cylinder number ; AL - sector number ; DH - head number ; Output: DX:AX - 32-bit linear sector number ; carry flag set if invalid sector number ; Registers changed: AX,DX cvtsec: push bx push cx mov bl,al ; move sector number into BL mov bh,dh ; move head number into BH xchg ah,al ; compute track number into AX, the mov cl,CON(6) ; upper two bits of CL are the high shr ah,cl ; bits of the 10 bit cylinder number xor dx,dx xor cx,cx mov cl,LOC(heads) mul cx ; compute track number from cylinders mov cl,bh add ax,cx adc dx,CON(0) mov cl,LOC(secptk) push bx xor bx,bx or dx,dx ; is 32-bit value > 16-bits yet? jz cvts6 push ax push dx mov ax,dx ; multiply upper 16-bits first mul cx mov bx,ax ; save result in bx pop dx pop ax cvts6: mul cx ; compute number of track starting add dx,bx ; fixup upper 16-bits pop bx mov cl,bl and cl,CON(0x3F) ; move sector number into AX cmp cl,LOC(secptk) ; check if sector number is correct ja cvts8 dec cx ; sector numbers start with 1 js cvts8 ; therefore sector 0 does not exist add ax,cx ; compute final sector number adc dx,CON(0) cmp dx,LOC(secnumhi) ; check if the sector is valid jb cvts8 ja cvts7 cmp ax,LOC(secnumlo) jb cvts8 cvts7: stc JMP(cvts9) cvts8: clc ; return with error cvts9: pop cx pop bx ret ;==================================================================== ; ; Read/write a sector from the ram disk. This routine requires a ; sector to be 512 bytes long. ; Input: CH - non-zero if write to ram disk ; DX:AX - logical sector number ; ES:BX - pointer to destination buffer ; Output: carry flag set if error ; Registers changed: AX rwsect: push si push di push cx push dx push ax mov si,rd_srcb mov di,rd_dstb or ch,ch ; check direction of transfer jz rwsec1 mov si,rd_dstb mov di,rd_srcb rwsec1: mov cx,CON(SECT_SIZE) ; compute linear ramdisk address mul cx ; from sector number add ax,LOC(rdaddr+0) adc dx,LOC(rdaddr+2) mov [si],ax ; set src for read, dst for write mov [si+2],dl mov [si+5],dh mov ax,es xor dx,dx mov cl,CON(0x10) xor ch,ch mul cx ; compute linear buffer address add ax,bx adc dx,CON(0) mov [di],ax ; set dst for read, src for write mov [di+2],dl mov [di+5],dh push es mov ax,cs mov es,ax mov si,CON(rd_gdt) mov cx,CON(SECT_SIZE/2) ; copy 512 bytes, e.g. 256 words mov ax,CON(0x8700) ; let the BIOS move the sector int 0x15 pop es pop ax pop dx pop cx pop di pop si ret ;==================================================================== ; ; Return a pointer to the disk drive status byte. This routine should ; not change any flags! ; Input: none ; Output: ES:BX - pointer to disk drive status byte ; Registers changed: BX, ES getsts: mov bx,CON(BIOS_SEG) ; status byte is in BIOS data mov es,bx ; segment SEGCS mov bx,LOC(statof) ret ;==================================================================== ; ; Initialize the XMS interface. This is necessary to prevent the ; ram disk from getting overwritten. The way this works is to ; first allocate all of the available XMS, then resize the memory ; block to end just above the ramdisk and lock it. Unfortunately ; we have to do it this complicated because there is no way of ; knowing how the XMS is going to allocate the available memory. ; Another problem is that at least HIMEM.SYS requires up to 256 ; bytes of stack, and we cannot assume the caller of INT 13 to ; provide that much so we have to change stacks. ; Input: none ; Output: none ; Registers changed: AX, BX inixms: call setstk ; set new stack ; First check that the XMS version number is correct. To support all ; necessary functions it has to be version 2.0+. xor ah,ah call callxm ; get version number cmp ah,CON(0x02) jb inixm8 ; wrong XMS version ; Determine how much memory we can allocate. mov ah,CON(0x08) xor bl,bl ; get amount of extended memory call callxm or bl,bl ; check for error jnz inixm8 mov bx,LOC(rdsize) ; get size of ramdisk add bx,BCON(65) ; care for a missing HMA cmp bx,ax ; check if enough memory for ram disk ja inixm8 ; Grab all of the extended memory. push bx mov dx,ax ; grab largest block - which is whole mov ah,CON(0x09) ; memory because there should be no call callxm ; other process using XMS pop bx or ax,ax ; check for error jz inixm8 mov LOC(xmshdl),dx ; save handle ; Now resize the memory block so that it will contain the ramdisk image. mov ah,CON(0x0f) ; reallocate memory block call callxm or ax,ax ; check for error jnz inixm1 inixm8: mov WLOC(xmshdl),CON(0) ; in case of error dont return handle JMP(inixm9) ; Now lock the memory block and check that the physical address of the ; memory block is correct. inixm1: mov dx,LOC(xmshdl) mov ah,CON(0x0c) ; lock memory block call callxm add bx,CON(0x03ff) adc dx,BCON(0x0001) ; add 65kb - maximum difference sub bx,LOC(rdaddr+0) ; check that ramdisk address is below sbb dx,LOC(rdaddr+2) jc inixm8 ; Thats it. Restore all registers and swap the stack back to its ; original state. inixm9: call rststk ; restore old stack ret ;==================================================================== ; ; Call XMS driver. ; Input: AH - function code ; other registers depending on function code ; Output: depends on called function ; Registers changed: depends on called function callxm: push ax push bp push ax mov bp,sp mov ax,[bp+6] mov [bp+4],ax ; make far return address from mov [bp+6],cs ; near call pop ax pop bp SEGCS push WLOC(xmsadr+2) ; push address of XMS driver SEGCS push WLOC(xmsadr+0) retf ; call XMS driver ;==================================================================== ; ; Set new stack ; Input: none ; Output: none ; Registers changed: AX, BX, DS, SS, SP setstk: cli pop bx ; get return address mov ax,sp SEGCS mov LOC(oldstk+0),ax SEGCS mov LOC(oldstk+2),ss ; save old stack pointer mov ax,cs mov ss,ax mov sp,CON(newtos - 2) ; change to new stack sti push cx push dx push si ; save all registers push di push es push ds mov ax,cs ; set DS to current segment mov ds,ax jmp bx ; return to caller ;==================================================================== ; ; Reset stack to old stack ; Input: none ; Output: none ; Registers changed: all (reset to old state) rststk: pop bx ; get return address pop ds pop es pop di pop si ; restore all registers pop dx pop cx cli SEGCS mov ax,LOC(oldstk+0) ; restore old stack SEGCS mov ss,LOC(oldstk+2) mov sp,ax sti jmp bx ; return to caller ;==================================================================== ; ; Remove ramdisk from memory. This involves restoring all interrupt ; vectors, freeing all used memory and restoring the DOS drive para- ; meter table. Since we need to call the XMS drive, we have to switch ; stacks like with inixms. ; Input: none ; Output: AL - non-zero if error ; Registers changed: AX rmrd: push bx call setstk ; set new stack mov al,LOC(drvid) cmp al,CON(0x80) ; can only restore floppy drives jb rmrd1 rmrd8: call rststk ; return with error pop bx mov al,CON(0x01) ret ; First determine the address of the DOS disk parameter block for the ; ramdisk and check that the open count is zero, i.e. no open file on ; the device. rmrd1: push ds mov ax,CON(0x0803) int 0x2f ; get address of drive parameter mov ax,ds ; table from DOS mov es,ax pop ds rmrd2: SEGES mov al,[di+4] ; get physical unit number cmp al,LOC(drvid) ; is it our drive? je rmrd3 cmp di,CON(0xffff) ; error if we couldnt find the DPB je rmrd8 ; for the ramdisk SEGES les di,[di] ; get pointer to next entry JMP(rmrd2) rmrd3: mov LOC(dpb_addr+0),di mov LOC(dpb_addr+2),es SEGES mov ax,[di+0x20] ; get device open count or ax,ax jnz rmrd8 ; Next restore the interrupt vectors. Int 13h is special as it is ; redirected by DOS. However, DOS provides a function to restore ; that interrupt. Interrupt 2Fh doesnt have to get restored because ; DOS does never call the old interrupt again. xor ax,ax mov es,ax mov ax,cs SEGES ; first check that nobody redirected cmp ax,LOC(IF8_INT+2) ; our own interrupts. In that case jne rmrd8 ; there is no chance of removing the SEGES ; ramdisk. mov ax,LOC(IF8_INT+0) cmp ax,CON(intF8) jne rmrd8 mov si,CON(if1sig) mov di,CON(IF1_INT) mov cx,CON(4) ; interrupt F1h contains a signature repz ; and no vector cmpsb jnz rmrd8 push ds les bx,LOC(old13h) ; get old interrupt vector 13h mov dx,bx mov ax,es ; save it into DS:DX and ES:BX mov ds,ax mov ah,CON(0x13) int 0x2f ; call DOS to restore vector mov ax,ds mov cx,cs cmp ax,cx ; check that its indeed our interrupt jne rmrd4 ; which we are replacing mov ax,es cmp ax,cx jne rmrd4 cmp bx,CON(int13) jne rmrd4 cmp dx,CON(int13) je rmrd5 rmrd4: mov ah,CON(0x13) int 0x2f ; restore old interrupt pop ds ; someone redirected the interrupt #ifdef USE_AS86 jmp near rmrd8 ; already, cant restore #endif #ifdef USE_NASM jmp rmrd8 ; already, cant restore #endif rmrd5: pop ds ; restore the other interrupts cli xor ax,ax mov es,ax mov ax,LOC(oldF8h+0) SEGES mov LOC(IF8_INT+0),ax mov ax,LOC(oldF8h+2) SEGES mov LOC(IF8_INT+2),ax sti ; OK, we can now setup the DOS drive parameter table to contain the ; correct values for the physical floppy drive. If we couldnt create ; a valid parameter table entry for this drive, simply mark the DOS ; entry as invalid. This will cause "Not Ready" errors in DOS. This ; doesnt work with DR-DOS 5.0! les di,LOC(dpb_addr) ; get address of DPB SEGES #ifdef USE_AS86 or [di+0x1f],BCON(80) ; mark drive as invalid #endif #ifdef USE_NASM or word [di+0x1f],BCON(80) ; mark drive as invalid #endif test BLOC(dpb_valid),CON(0xff) ; check if DPB valid jz rmrd6 cld ; got correct table entry mov cx,CON(dpb_end - dpb) mov si,CON(dpb) add di,BCON(4) rep movsb ; simply copy the DPB ; Next remove the ramdisk image from extended memory using the XMS driver. rmrd6: mov dx,LOC(xmshdl) or dx,dx ; only free memory if we really jz rmrd7 ; assigned it with XMS push dx mov ah,CON(0x0d) call callxm ; unlock memory block pop dx or ax,ax ; dont free block if error jz rmrd7 mov ah,CON(0x0a) call callxm ; free memory block ; Finally we can remove the memory for the ramdisk driver. We only ; reset the owner field of the memory control block to 0 to indicate ; it as free. rmrd7: mov dx,CON(start_resident) ; determine last usable segment mov cl,CON(4) ; from segment and offset of shr dx,cl ; the resident section mov ax,cs add dx,ax ; add offset to segment sub dx,BCON(2) mov es,dx mov di,CON(1) xor ax,ax ; set owner field to 0 stosw add di,BCON(5) mov cx,CON(4) ; clear owner name rep stosw ; Thats it. Return to caller. rmrd9: call rststk ; restore old stack pop bx xor al,al ; return without error ret ;==================================================================== ; ; Variables for the resident section ALIGN(2) oldints: old13h: dd 0 ; old interrupt 13h vector old2Fh: dd 0 ; old interrupt 2Fh vector oldF1h: dd 0 ; old interrupt F1h vector oldF8h: dd 0 ; old interrupt F8h vector ; Disk parameters for ram disk statof: dw BIOS_FDSTAT ; offset to BIOS disk status byte rdaddr: dd 0 ; base address of ram disk rdsize: dw 0 ; size of ram disk in kb cylnum: dw 80 ; number of cylinders secnumlo: dw 2400 ; number of sectors on disk secnumhi: dw 0 secptk: dw 15 ; number of sectors per track heads: db 1 ; number of heads drvnum: db 1 ; number of disk drives drvid: db 0 ; ram disk drive id nohd: db 0 ; no-hard-disk flag syscnf: dw 0 ; system configuration from BIOS ALIGN(2) ; Variables used to access the XMS interface xmshdl: dw 0 ; XMS handle for ram disk xmsadr: dd 0 ; address of XMS driver interface ; Variables used to redirect the stack oldstk: dd 0 ; old stack pointer newstk: SPACE(512) ; new stack for calling XMS driver newtos: ; new top of stack ; Signature to put into interrupt vector F1h if1sig: STRDECL('NetB') ALIGN(16) ; has to be paragraph aligned ; Descriptor table to access ram disk using the BIOS rd_gdt: dw 0,0,0,0 dw 0,0,0,0 rd_src: dw 0xffff ; length rd_srcb: db 0,0,0 ; base db 0x93 ; typebyte db 0 ; limit16 =0 rd_srcbh: db 0 ; base24 rd_dst: dw 0xffff ; length rd_dstb: db 0,0,0 ; base db 0x93 ; typebyte db 0 ; limit16 =0 rd_dstbh: db 0 ; base24 dw 0,0,0,0 ; BIOS CS dw 0,0,0,0 ; BIOS DS ; DOS disk parameter block. It contains the definitions for the ; floppy disk drive which is redirected by the ramdisk, and used ; for removing the ramdisk drive. Note that this DPB is only ; valid for DOS 4.0 and higher. dpb_addr: dd 0 ; address of DPB in DOS data area dpb_valid: db 0 ; non-zero if DPB is valid dpb: dpb_phys: db 0 ; BIOS ID of physical drive dpb_log: db 0 ; logical DOS drive ID dpb_bpb_low: dw 512 ; BIOS param block for lowest capacity db 0xff dw 1 db 2 dw 64 dw 360 db 0x00 dw 2 dw 9 dw 1 dd 0 dd 0 dpb_fat: db 0 ; flag indicating 16-bit FAT dpb_open: dw 0 ; device open count dpb_type: db 0x01 ; device type dpb_flags: dw DPB_F_DEFAULT ; flags describing drive dpb_cyls: dw 80 ; number of cylinders dpb_bpb_cur: dw 512 ; BIOS parameter block for current db 1 dw 1 db 2 dw 224 dw 2400 db 0xf9 dw 7 dw 15 dw 2 dd 0 dd 0 dpb_rsvd: db 0, 0, 0, 0, 0, 0 dpb_ltrack: db 0xff ; last accessed track dpb_lacc: dd 0xffffffff ; time of last disk access dpb_volname: STRDECL('NO NAME ') ; volume name db 0 dpb_sernum: dd 0 ; volume serial number dpb_fsname: STRDECL('FAT12 ') ; file system name db 0 dpb_end: ; Copy of bootp block from bootrom. This has to be last in the data area! btplen: dw 0 ; length of bootp block btpnew: ; bootp block has to be at the very end _end: SPACE(4096-(_end-_start)) mknbi-1.4.4/first-dos.h0100644000175000001440000002027407653425527013424 0ustar kenusers/* * first.inc - constants for assembler module for DOS boot loader * * Copyright (C) 1996-1998 Gero Kuhlmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* *==================================================================== * * Definitions for accessing the BIOS data area */ #define BIOS_SEG 0x0040 /* Segment of BIOS data area */ #define BIOS_FDSTAT 0x0041 /* Floppy disk status byte */ #define BIOS_HDSTAT 0x0074 /* Hard disk status byte */ #define I13_INT 0x13 * 4 /* interrupt vector 13h */ #define I2F_INT 0x2F * 4 /* interrupt vector 2Fh */ #define IF1_INT 0xF1 * 4 /* interrupt vector F1h */ #define IF8_INT 0xF8 * 4 /* interrupt vector F8h */ /* *==================================================================== * * Layout of disk boot sector */ #define SECT_SIZE 512 /* sector size must be 512 bytes */ #define DISK_BPS 11 /* offset of bytes per sectors */ #define DISK_SECTS 19 /* offset of total number of sects */ #define DISK_SPT 24 /* offset of sectors per track */ #define DISK_HEADS 26 /* offset of number of heads */ #define DISK_BOOT 36 /* offset of disk ID to boot from */ #define PART_STATUS 0x01BE /* offset of partition status */ #define PART_FRST_HEAD 0x01BF /* offset of first head number */ #define PART_FRST_SECT 0x01C0 /* offset of first sector number */ #define PART_FRST_CYL 0x01C1 /* offset of first cylinder number */ #define PART_TYPE 0x01C2 /* offset of partition id */ #define PART_LAST_HEAD 0x01C3 /* offset of last head number */ #define PART_LAST_SECT 0x01C4 /* offset of last sector number */ #define PART_LAST_CYL 0x01C5 /* offset of last cylinder number */ #define PART_ABS_SECT 0x01C6 /* offset of first sector number */ #define PART_SEC_NUM 0x01CA /* offset of number of sectors */ #define PART_ACTIVE 0x80 /* indicates active partition */ #define PART_FAT12 0x01 /* indicates partition type */ #define PART_FAT16 0x04 /* indicates partition type */ #define BOOT_ID_FD 0x00 /* BIOS id of floppy boot disk */ #define BOOT_ID_HD 0x80 /* BIOS id of hard boot disk */ #define BOOT_OFFSET 0x7C00 /* offset for boot block in segment 0 */ #define TEMP_SEGMENT 0x7000 /* segment for temporary storage */ /* *==================================================================== * * Layout of BIOS parameter block as used by DOS */ #define BPB_BPS 0 /* offset to bytes per sector */ #define BPB_SPC 2 /* offset to sectors per cluster */ #define BPB_RES 3 /* offset to # of reserved sectors */ #define BPB_FATS 5 /* offset to # of FATs */ #define BPB_DIR 6 /* offset to # of root dir entries */ #define BPB_TOT_SECTS 8 /* offset to total # of sectors */ #define BPB_MEDIA_ID 10 /* offset to media ID */ #define BPB_SPF 11 /* offset to # of sectors per FAT */ #define BPB_SPT 13 /* offset to # of sectors per track */ #define BPB_HEADS 15 /* offset to # of heads */ #define BPB_HIDDEN 17 /* offset to # of hidden sectors */ /* *==================================================================== * * Flags for DOS drive parameter block */ #define DPB_F_FIXED 0x0001 /* fixed media */ #define DPB_F_DOOR 0x0002 /* drive supports door lock status */ #define DPB_F_TSIZE 0x0004 /* all sectors in track are same size */ #define DPB_F_MULTI 0x0008 /* multiple logical units in drive */ #define DPB_F_SHARED 0x0010 /* logical for shared physical drive */ #define DPB_F_CHANGE 0x0020 /* disk change detected */ #define DPB_F_NEWPARA 0x0040 /* device parameters were changed */ #define DPB_F_FORMAT 0x0080 /* disk reformatted */ #define DPB_F_ACCESS 0x0100 /* access flag - fixed media only */ #define DPB_F_DEFAULT DPB_F_CHANGE + DPB_F_NEWPARA #define DPB_T_360 0 /* type ID for 360kB disk */ #define DPB_T_1200 1 /* type ID for 1.2MB disk */ #define DPB_T_720 2 /* type ID for 720kB disk */ #define DPB_T_SD8 3 /* type ID for SD 8 inch disk */ #define DPB_T_HD8 4 /* type ID for HD 8 inch disk */ #define DPB_T_FIXED 5 /* type ID for fixed disk */ #define DPB_T_TAPE 6 /* type ID for tape drive */ #define DPB_T_1440 7 /* type ID for 1.44MB disk */ #define DPB_T_OPTICAL 8 /* type ID for optical disk */ #define DPB_T_2880 9 /* type ID for 2.88MB disk */ /* *==================================================================== * * Vendor information for the boot rom image. These values have to be * identical to those in mknbi.h. */ #ifdef FREEDOS #define VENDOR_SIZE 5 /* sizeof "mknbi-fdos-1.x-y" in dwords */ #else #define VENDOR_SIZE 4 /* sizeof "mknbi-dos-1.x-y" in dwords */ #endif #define VENDOR_BOOTL 16 /* tag for boot loader segment */ #ifdef FREEDOS #define VENDOR_RAMDISK 18 /* tag for ramdisk image */ #else #define VENDOR_RAMDISK 17 /* tag for ramdisk image */ #endif /* *==================================================================== * * Layout and magic ID of boot rom image header. These values have to * be identical to those used by the boot rom. See SPEC.DOC of the * boot rom source for further information. */ #define BOOT_MAGIC 0x1B031336 /* boot image header magic cookie */ #define BOOT_SIZE 512 /* total size of boot image header */ #define BOOT_HD_SIZE 4 /* size of header in dwords */ #define BOOT_HD_MAGIC 0 /* offset for header magic number */ #define BOOT_HD_LENGTH 4 /* offset for header length */ #define BOOT_HD_FLAG1 5 /* offset for header flag 1 */ #define BOOT_HD_FLAG2 6 /* offset for header flag 2 */ #define BOOT_HD_FLAG3 7 /* offset for header flag 3 */ #define BOOT_HD_LOCN 8 /* offset for header location */ #define BOOT_HD_EXEC 12 /* offset for execute address */ #define BOOT_HD_VENDOR 16 /* offset for header vendor information */ #define BOOT_LD_SIZE 4 /* size of load record in dwords */ #define BOOT_LD_LENGTH 0 /* offset for load record length */ #define BOOT_LD_TAG1 1 /* offset for load record tag 1 */ #define BOOT_LD_TAG2 2 /* offset for load record tag 2 */ #define BOOT_LD_FLAGS 3 /* offset for load record flags */ #define BOOT_LD_ADDR 4 /* offset for absolute address */ #define BOOT_LD_ILENGTH 8 /* offset for image length */ #define BOOT_LD_MLENGTH 12 /* offset for memory length */ #define BOOT_LD_VENDOR 16 /* offset for vendor information */ #define BOOT_FLAG_B0 0x01 /* mask for load record flag B0 */ #define BOOT_FLAG_B1 0x02 /* mask for load record flag B1 */ #define BOOT_FLAG_EOF 0x04 /* mask for load record flag EOF */ #define BOOT_LD_SECNUM 0 /* offset of total number of sectors */ #define BOOT_LD_HEADS 4 /* offset of head count */ #define BOOT_LD_SPT 6 /* offset of sectors per track */ #define BOOT_LD_CYL 8 /* offset of number of cylinders */ #define BOOT_LD_DRIVE 10 /* offset of boot drive ID */ #define BOOT_LD_NOHD 11 /* offset of no-hard-disk flag */ /* *==================================================================== * * Layout and magic ID of bootp record. Refer to RFC 951, RFC 1048 * and RFC 1533 for further information. The BOOTP record can be * longer than the standard length as the bootrom might be able to * load a vendor extension file via tftp. */ #define BOOTP_MAGIC_RFC 0x63, 0x82, 0x53, 0x63 /* RFC 1048 vendor ID */ #define BOOTP_MAGIC_CMU 0x43, 0x4D, 0x55, 0x00 /* CMU vendor ID */ #define BOOTP_MAGIC_STA 0x53, 0x54, 0x41, 0x4E /* Stanford vendor ID */ #define BOOTP_MAGIC_LEN 4 /* length of vendor ID */ #define BOOTP_REQUEST 1 /* bootp OP-code */ #define BOOTP_REPLY 2 #define BOOTP_OP 0 /* offset to bootp OP-code */ #define BOOTP_VEND 236 /* offset to vendor information */ #define BOOTP_SIZE 300 /* size of complete bootp record */ #define BOOTP_RFC_NOP 0 /* RFC vendor tag for NO-OP */ #define BOOTP_RFC_END 255 /* RFC vendor tag for end of record */ mknbi-1.4.4/mknbi.10100644000175000001440000006602110110544103012471 0ustar kenusers.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.14 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "MKNBI 1" .TH MKNBI 1 "2004-08-18" "Mknbi 1.4.4" "Etherboot tools" .SH "NAME" mknbi \- make network bootable image .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBmknbi\fR \-\-version .PP \&\fBmknbi\fR \-\-format=\fIformat\fR \-\-target=\fItarget\fR [\-\-output=\fIoutputfile\fR] \fItarget-specific-arguments\fR .PP \&\fBmkelf-linux\fR [\-\-output=\fIoutputfile\fR] \fIkernelimage\fR [\fIramdisk\fR] .PP \&\fBmknbi-linux\fR [\-\-output=\fIoutputfile\fR] \fIkernelimage\fR [\fIramdisk\fR] .PP \&\fBmknbi-rom\fR [\-\-output=\fIoutputfile\fR] \fI.z?rom\-file\fR .PP \&\fBmkelf-img\fR [\-\-output=\fIoutputfile\fR] \fI.z?img\-file\fR .PP \&\fBmkelf-menu\fR [\-\-output=\fIoutputfile\fR] [\fIdataimage\fR] .PP \&\fBmknbi-menu\fR [\-\-output=\fIoutputfile\fR] [\fIdataimage\fR] .PP \&\fBmkelf-nfl\fR [\-\-output=\fIoutputfile\fR] [\fIdataimage\fR] .PP \&\fBmknbi-nfl\fR [\-\-output=\fIoutputfile\fR] [\fIdataimage\fR] .PP \&\fBmkelf-lua\fR [\-\-output=\fIoutputfile\fR] \fIluabin\fR .PP \&\fBmknbi-fdos\fR [\-\-output=\fIoutputfile\fR] \fIkernel.sys floppyimage\fR .PP \&\fBmknbi-dos\fR [\-\-output=\fIoutputfile\fR] \fIfloppyimage\fR .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBmknbi\fR is a program that makes network bootable images for various operating systems suitable for network loading by Etherboot or Netboot, which are \s-1ROM\s0 boot loaders. If you are looking to boot using \s-1PXE\s0, look no further, mknbi is not what you want. You probably want something like \&\s-1PXELINUX\s0 which is part of the \s-1SYSLINUX\s0 package. .PP \&\fBmknbi\fR \-\-version prints the current version. Use this before reporting problems. .PP \&\fBmknbi\fR can be invoked with the \fB\-\-format\fR and \fB\-\-target\fR options or links can be made to it under format and target specific names. E.g. mkelf-linux is the same as mknbi \-\-format=elf \-\-target=linux. .PP \&\fB\-\-format\fR=\fIformat\fR Specify the format of the output. Currently available are nbi and elf. \s-1ELF\s0 format only works with linux and menu. Otherwise the invocation is the same as for mknbi. In discussions below, the mknbi form is used. .PP \&\fB\-\-target\fR=\fItarget\fR Specify the target binary. Currently available are linux, menu, rom, fdos and dos. \fBmknbi\fR is not needed for booting FreeBSD. .PP \&\fB\-\-output=\fR\fIoutputfile\fR Specify the output file, can be used with all variants. Stdout is the default. .PP The package must be installed in the destination location before the executables can be run, because it looks for library files. .PP Each of the variants will be described separately. .SH "MKELF-LINUX" .IX Header "MKELF-LINUX" \&\fBmkelf-linux\fR and \fBmknbi-linux\fR makes a boot image from a Linux kernel image, either a zImage or a bzImage. .SH "MKELF-LINUX OPTIONS" .IX Header "MKELF-LINUX OPTIONS" \&\fB\-\-param=\fR\fIstring\fR Replace the default parameter string with the specified one. This option overrides all the following options so you should know what you are doing. .PP \&\fB\-\-append\fR=\fIstring\fR Appends the specified string to the existing parameter string. This option operates after the other parameter options have been evaluated. .PP \&\fB\-\-rootdir\fR=\fIrootdir\fR Define name of directory to mount via \s-1NFS\s0 from the boot server. .PP In the absence of this option, the default is to use the directory \&\f(CW\*(C`/tftpboot/\*(C'\fR\fI%s\fR, with the \fI%s\fR representing the hostname or IP-address of the booting system, depending on whether the hostname attribute is present in the \s-1BOOTP/DHCP\s0 reply. .PP If \f(CW\*(C`rom\*(C'\fR is given, and if the \s-1BOOTP/DHCP\s0 server is able to handle the \s-1RFC\s0 1497 extensions, the value of the rootpath option is used as the root directory. .PP If the name given to the option starts with \f(CW\*(C`/dev/\*(C'\fR, the corresponding device is used as the root device, and no \s-1NFS\s0 directory will be mounted. .PP \&\fB\-\-rootmode\fR=\f(CW\*(C`ro|rw\*(C'\fR Defines whether the root device will be mounted read-only or read-write respectively. Without this parameter, the default is \f(CW\*(C`rw\*(C'\fR. .PP \&\fB\-\-ip=\fR\fIstring\fR Define client and server \s-1IP\s0 addresses. .PP In the absence of this option no \s-1IP\s0 addresses are defined, and the kernel will determine the \s-1IP\s0 addresses by itself, usually by using \s-1DHCP\s0, \&\s-1BOOTP\s0 or \s-1RARP\s0. Note that the kernel's query is \fIin addition to\fR the query made by the bootrom, and requires the \s-1IP:\s0 kernel level autoconfiguration (\s-1CONFIG_IP_PNP\s0) feature to be included in the kernel. .PP Important note: In Linux kernels 2.2.x where x >= 18, and 2.4.x where x >= 5, it is \fBnecessary\fR to specify one of the enabling options in the next paragraph to cause the \s-1IP\s0 autoconfiguration to be activated. Unlike in previous kernels, \s-1IP\s0 autoconfiguration does not happen by default. Also note that \s-1IP\s0 autoconfiguration and NFSroot are likely to go away in Linux 2.6 and that userspace \s-1IP\s0 configuration methods using ramdisk and userspace \s-1DHCP\s0 daemons are preferred now. .PP If one of the following: \f(CW\*(C`off, none, on, any, dhcp, bootp, rarp, both\*(C'\fR, is given, then the option will be passed unmodified to the kernel and cause that autoconfig option to be chosen. .PP If \f(CW\*(C`rom\*(C'\fR is given as the argument to this option, all necessary \s-1IP\s0 addresses for \s-1NFS\s0 root mounting will be inherited from the \s-1BOOTP/DHCP\s0 answer the bootrom got from the server. .PP It's also possible to define the addresses during compilation of the boot image. Then, all addresses must be separated by a colon, and ordered in the following way: .PP \&\f(CW\*(C`\-\-ip=\*(C'\fR\fIclient:server:gateway:netmask:hostname[:dev[:proto]]\fR .PP Using this option \fBmkelf-linux\fR will automatically convert system names into decimal \s-1IP\s0 addresses for the first three entries in this string. The \fBhostname\fR entry will be used by the kernel to set the host name of the booted Linux diskless client. When more than one network interface is installed in the diskless client, it is possible to specify the name of the interface to use for mounting the root directory via \s-1NFS\s0 by giving the optional value \f(CW\*(C`dev\*(C'\fR. This entry has to start with the string \f(CW\*(C`eth\*(C'\fR followed by a number from 0 to 9. However, if only one interface is installed in the client, this \fIdev\fR entry including the preceding semicolon can be left out. The \fIproto\fR argument is one of the \&\s-1IP\s0 autoconfiguration enabling options listed above. (Author: it's not clear to me what the \s-1IP\s0 autoconfiguration does when the parameters are already specified. Perhaps it's to obtain parameters not specified, e.g. \s-1NIS\s0 domain.) .PP \&\fB\-\-rdbase=\fR\fItop|asis|0xNNNNNNNN\fR Set the ramdisk load address. \f(CW\*(C`top\*(C'\fR moves the ramdisk to the top of memory before jumping to the kernel. This is the default if rdbase is not specified. This option requires that first\-linux's kernel sizing work correctly. \f(CW\*(C`asis\*(C'\fR loads it at 0x100000 (1MB) if the kernel is loaded low; or leaves it just after the kernel in memory, if the kernel is loaded high. For this option to work, the kernel must be able to handle ramdisks at these addresses. \&\fI0xNNNNNNNN\fR moves the ramdisk to the hex address specified. The onus is on the user to specify a suitable address that is acceptable to the kernel and doesn't overlap with any other segments. Etherboot will round address down to multiple of 4k (last 3 digits to zero). .PP \&\fB\-\-rdnopad\fR By default, etherboot pads (with nulls) the given initrd of any size to multiple of 4k bytes (aligning to memory page boundary). Use this option to disable padding if it causes problem. .PP \&\fB\-\-first32=\fR\fIprogram\fR Override the default first stage setup program. It can be used to call extensions to the Etherboot code, which paves the way for additional useful functionality without enlarging the size of the Etherboot footprint. \-\-first32 is implied by the \s-1ELF\s0 format. .PP \&\fB\-\-progreturns\fR This option is used in conjunction with and only valid with the \-\-first32 option to indicate to the Etherboot loader that the called program will return to loader and hence Etherboot should not disable the network device as is the case when the program will never return to Etherboot. .PP \&\fB\-\-relocseg=\fR\fIsegaddr\fR This option is used to specify a relocation of the Linux first, boot, setup, and parameter segments to another 64k band. Currently the only valid values are 0x9000 and 0x8000, corresponding to linear addresses of 0x90000 and 0x80000 upwards. The default is 0x9000. Usually you use this option if you have relocated Etherboot to 0x84000 to avoid other code in the 0x90000 segment like \&\s-1DOC\s0. The Linux kernel must support relocation which implies a 2.4 kernel or later. \-\-relocseg only works reliably with \s-1ELF\s0 or \-\-first32=. .PP \&\fBmem=\fR\fImemsize\fR This is not a command line option but a kernel parameter that is intercepted by the first32 stage and used as the top of memory, to match Linux's interpretation. \fImemsize\fR can be suffixed by \f(CW\*(C`G\*(C'\fR to indicate gibibytes (times 2^30), \f(CW\*(C`M\*(C'\fR to indicate mebibytes (times 2^20) or \f(CW\*(C`K\*(C'\fR to indicate kibibytes (times 2^10). Note that the suffixes are uppercase. This kernel parameter can be specified in \&\-\-append= or option\-129 of the \s-1DHCP/BOOTP\s0 record. .PP Run the program thus: .PP mkelf-linux \fIkernel-image\fR [\fIramdisk-image\fR] > linux.nb .PP Then move \fIlinux.nb\fR to where the network booting process expects to find it. .SH "MKELF-LINUX BOOTP/DHCP VENDOR TAGS" .IX Header "MKELF-LINUX BOOTP/DHCP VENDOR TAGS" \&\fBmkelf-linux\fR includes a startup code at the beginning of the Linux kernel which is able to detect certain \s-1DHCP\s0 vendor defined options. These can be used to modify the kernel loading process at runtime. To use these options with \s-1ISC\s0 \s-1DHCPD\s0 v3, a popular \s-1DHCP\s0 daemon, the syntax is as below. You will need to adjust the syntax for other \s-1DHCP\s0 or \s-1BOOTP\s0 daemons. .PP option etherboot-signature code 128 = string; .PP option kernel-parameters code 129 = text; .PP \&... .PP .Vb 1 \& option etherboot-signature E4:45:74:68:00:00; .Ve .PP .Vb 1 \& option kernel-parameters "INITRD_DBG=6 NIC=3c509"; .Ve .PP Option 128 is required to be the six byte signature above. See the vendortags appendix of the Etherboot user manual for details. .PP The following option is presently supported by \fBmkelf-linux\fR: .PP \&\fB129\fR The \fIstring\fR value given with this option is appended verbatim to the end of the kernel command line. It can be used to specify arguments like I/O addresses or \s-1DMA\s0 channels required for special hardware like \s-1SCSI\s0 adapters, network cards etc. Please consult the Linux kernel documentation about the syntax required by those options. It is the same as the \fB\-\-append\fR command line option to \fBmkelf-linux\fR, but works at boot time instead of image build time. .PP \&\fB130\fR With this option it is possible to the select the network adapter used for mounting root via \s-1NFS\s0 on a multihomed diskless client. The syntax for the \fIstring\fR value is the same as for the \f(CW\*(C`dev\*(C'\fR entry used with the \fB\-\-ip=\fR option as described above. However note that the \&\fBmkelf-linux\fR runtime setup routine does not check the syntax of the string. .SH "MKNBI-ROM" .IX Header "MKNBI-ROM" \&\fBmknbi-rom\fR makes a boot image from an Etherboot \f(CW\*(C`.rom\*(C'\fR or \f(CW\*(C`.zrom\*(C'\fR boot \s-1ROM\s0 image. This allows it to be netbooted using an existing \&\s-1ROM\s0. This is useful for developing Etherboot drivers or to load a newer version of Etherboot with an older one. .PP Run mknbi-rom like this: .PP mknbi-rom nic.zrom > nic.nb .PP Move \fInic.nb\fR to where the network booting process expects to find it. The boot \s-1ROM\s0 will load this as the \fIoperating system\fR and execute the \&\s-1ROM\s0 image. .SH "MKELF-IMG" .IX Header "MKELF-IMG" \&\fBmkelf-img\fR makes a boot image from an Etherboot \f(CW\*(C`.img\*(C'\fR or \f(CW\*(C`.zimg\*(C'\fR image. This allows it to be netbooted using an existing \s-1ROM\s0. This is useful for developing Etherboot drivers or to load a newer version of Etherboot with an older one. .PP Run mkelf-img like this: .PP mkelf-img nic.zimg > nic.nb .PP Move \fInic.nb\fR to where the network booting process expects to find it. The boot \s-1ROM\s0 will load this as the \fIoperating system\fR and execute the image. .PP Note that this does not test the \s-1ROM\s0 loader portion that's in a \f(CW\*(C`.z?rom\*(C'\fR image, but not in a \f(CW\*(C`.z?img\*(C'\fR. .SH "MKELF-MENU" .IX Header "MKELF-MENU" \&\fBmkelf-menu\fR and \fBmknbi-menu\fR make a boot image from an auxiliary menu program. Etherboot has the ability to load an auxiliary program which can interact with the user, modify the \s-1DHCP\s0 structure, and return a status. Based on the status, Etherboot can load another binary, restart or exit. This makes it possible to have elaborate user interface programs without having to modify Etherboot. The specification for auxiliary program is documented in the Etherboot Developer's Manual. .PP \&\fBmkelf-menu\fR and \fBmknbi-menu\fR take a binary named \f(CW\*(C`menu\*(C'\fR from the library directory, which is assumed to have an entry point of 0x60000. An optional argument is accepted, and this is loaded at 0x80000. This can be a data file used by the menu program. .PP Currently, the menu binary provided duplicates the builtin menu facility of Etherboot with the exception of a couple of small differences: no server or gateway specifications are used and nested \s-1TFTP\s0 loads don't work. You should not have \s-1MOTD\s0 or \s-1IMAGE_MENU\s0 defined in your Etherboot build to be able to use this external menu binary. The specifications of the \s-1DHCP\s0 option required is in the vendortags document in the Etherboot user manual. .PP Typical usage is like this: .PP mkelf-menu > menu.nb .PP Then put menu.nb in the \s-1TFTP\s0 boot directory and edit your \s-1DHCP\s0 options according to the documentation. .PP Alternate user interface programs are highly encouraged. .SH "MKELF-NFL" .IX Header "MKELF-NFL" \&\fBmkelf-nfl\fR and \fBmknbi-nfl\fR make a boot image from the \s-1NFL\s0 menu program. This menu program takes the names of images from a menu-text-file file which just contains lines with the filenames (relative to the tftpd root directory) of images to load. The user-interface is a light\-bar, similar to that used in \s-1GRUB\s0. There is a sample menu-text-file in \f(CW\*(C`menu\-nfl.eg\*(C'\fR. The special entry \*(L"Quit Etherboot\*(R" (without quotes, of course) can be used in menu-text-files as an entry that causes Etherboot to quit and return to the invoking environment, which is the \s-1BIOS\s0 in the case of ROMs. .PP Typical usage is: .PP mkelf-nfl \fImenu-text-file\fR > nfl.nb .PP Then put nfl.nb in the \s-1TFTP\s0 boot directory and specify as the boot image. Chaining to other menus works. .PP Enhancements to the menu format accepted to specify other features such as titles, timeout, colours, and so forth are highly encouraged. .SH "MKELF-LUA" .IX Header "MKELF-LUA" \&\fBmkelf-lua\fR makes an \s-1ELF\s0 image from a precompiled Lua (\f(CW\*(C`http://www.tecgraf.puc\-rio.br/lua/\*(C'\fR) program. .PP Typical usage is: .PP mkelf-lua hello.lb > luaprog.nb .PP where \f(CW\*(C`hello.lb\*(C'\fR was generated from a Lua program by: .PP luac \-o hello.lb hello.lua .PP The functions available to Lua programs in this environment is described in a separate document. .SH "MKNBI-FDOS" .IX Header "MKNBI-FDOS" \&\fBmknbi-fdos\fR makes a boot image from a FreeDOS kernel file and a floppy image. Note that the kernel image is not read from the floppy section of the boot image, but is a separate section in the boot image. The bootloader has been adjusted to jump to it directly. This means the space that would be taken up on the \fIfloppy\fR by the kernel image file can now be used for applications and data. .PP Obtain a distribution of FreeDOS with a recent kernel, probably at least 2006. It has been tested with 2012 but nothing older. You can get the FreeDOS kernel here: .PP \&\f(CW\*(C`http://freedos.sourceforge.net/\*(C'\fR .PP Follow the instructions to make a bootable floppy. Then get an image of the floppy with: .PP dd if=/dev/fd0 of=/tmp/floppyimage .PP Also extract \fIkernel.sys\fR from the floppy. You can do this from the image using the mtools package, by specifying a file as a \fIdrive\fR with a declaration like this in \fI~/.mtoolsrc\fR: .PP drive x: file=\*(L"/tmp/floppyimage\*(R" .PP Then run: .PP mcopy x:kernel.sys . .PP Then run mknbi by: .PP mknbi-fdos kernel.sys /tmp/floppyimage > freedos.nb .PP where \fIkernel.sys\fR and \fI/tmp/floppyimage\fR are the files extracted above. Then move \fIfreedos.nb\fR to where the network booting process expects to find it. .PP If you have got it to netboot successfully, then you can go back and add your files to the floppy image. You can delete \fIkernel.sys\fR in the floppy image to save space, that is not needed. Note that you can create a floppy image of any size you desire with the mformat program from mtools, you are not restricted to the actual size of the boot floppy. .SH "MKNBI-FDOS OPTIONS" .IX Header "MKNBI-FDOS OPTIONS" \&\fB\-\-harddisk\fR Make the boot ramdisk the first hard disk, i.e. C:. One reason you might want to do this is because you want to use the real floppy. The limit on \*(L"disk size\*(R" in the boot image is not raised by this option so that is not a reason to use this option. This option is incompatible with \-\-disableharddisk. .PP \&\fB\-\-disableharddisk\fR When the ramdisk is simulating a floppy disk drive, this switch will disable hard disk accesses. This is necessary if the client should use a network file system as drive C:, which is only possible if there are no hard disks found by \s-1DOS\s0. This option is incompatible with \-\-harddisk. .PP \&\fB\-\-nosquash\fR Do not try to chop unused sectors from the end of the floppy image. This increases the boot image size and hence loading time if the \s-1FAT\s0 filesystem on the floppy is mostly empty but you may wish to use this option if you have doubts as to whether the squashing algorithm is working correctly. .PP \&\fB\-\-rdbase=\fR\fI0xNNNNNNNN\fR Set the ramdisk load address. The default load address for the ramdisk is 0x110000. It can be moved higher (lower will not work) if for some reason you need to load other stuff at the address it currently occupies. As this is a linear address and not a segment address, the last 4 bits are not used and should be 0. .SH "MKNBI-DOS" .IX Header "MKNBI-DOS" \&\fBmknbi-dos\fR makes a boot image from a floppy image containing a bootable \s-1DOS\s0 filesystem. It is not necessary to build the filesystem on a physical floppy if you have the mtools package, but you need a bootable floppy of any size to start with. First extract the boot block from the floppy, this boot block must match the \s-1DOS\s0 kernel files you will copy in the next step: .PP dd if=/dev/fd0 of=bootblock bs=512 count=1 .PP Then get the \s-1DOS\s0 kernel files (this is correct for \s-1DR\-DOS\s0, the names are different in \s-1MS\-DOS\s0, \s-1IO\s0.SYS and \s-1MSDOS\s0.SYS): .PP mcopy a:IBMBIO.COM a:IBMDOS.COM a:COMMAND.COM . .PP Next make an entry in \fI~/.mtoolsrc\fR to declare a floppy to be mapped to a file: .PP drive x: file=\*(L"/tmp/floppyimage\*(R" .PP Now format a floppy of the desired size, in this example a 2.88 \s-1MB\s0 floppy, at the same time writing the bootblock onto it: .PP mformat \-C \-t 80 \-s 36 \-h 2 \-B bootblock x: .PP The size of the \*(L"floppy\*(R" is only limited by the limits on the number of cylinders, sectors and heads, which are 1023, 63 and 255 respectively, and the amount of \s-1RAM\s0 you are willing to allocate to the \*(L"floppy\*(R" in memory. As \s-1RAM\s0 is precious, choose a size slightly bigger than what is needed to hold your \*(L"floppy\*(R" files. .PP Finally, copy all your desired files onto the floppy: .PP mcopy \s-1IBMBIO\s0.COM x: .PP mcopy \s-1IBMDOS\s0.COM x: .PP mcopy \s-1COMMAND\s0.COM x: .PP mcopy \s-1CONFIG\s0.SYS \s-1AUTOEXEC\s0.BAT \s-1APP\s0.EXE \s-1APP\s0.DAT ... x: .PP For MS-DOS substitute \s-1IO\s0.SYS for \s-1IBMIO\s0.COM, and \s-1MSDOS\s0.SYS for \&\s-1IBMDOS\s0.COM. The case of the files must be preserved, it may not work if \&\s-1VFAT\s0 lower case names are generated in the floppy image. Pay attention to the order of copying as the boot block may expect the first two entries on a newly formatted disk to be \s-1IO\s0.SYS, \s-1MSDOS\s0.SYS. Possibly too \&\s-1COMMAND\s0.COM has to be the third entry so we play safe. Thanks to Phil Davey and Phillip Roa for these tips. .PP I have reports that the bootblock of MS-DOS 6.22 sometimes fails to boot the ramdisk. You could try using the boot block from Netboot instead of getting the boot block off the floppy. I have provided this boot block in the distribution as altboot.bin, and in source form as altboot.S and boot.inc. One essential thing is to make \s-1IO\s0.SYS the first file on the disk, or this bootblock will not work. .PP If you happen to have a media of the same size you could test if the image is bootable by copying it onto the media, and then booting it: .PP dd if=/tmp/floppyimage of=/dev/fd0 .PP Then run mknbi-dos over the image \fI/tmp/floppyimage\fR to create a boot image: .PP mknbi-dos /tmp/floppyimage > dos.nb .PP Move \fIdos.nb\fR to where the network booting process expects to find it. .SH "MKNBI-DOS OPTIONS" .IX Header "MKNBI-DOS OPTIONS" \&\fB\-\-harddisk\fR Make the boot ramdisk the first hard disk, i.e. C:. One reason you might want to do this is because you want to use the real floppy. The limit on \*(L"disk size\*(R" in the boot image is not raised by this option so that is not a reason to use this option. This option is incompatible with \-\-disableharddisk. .PP \&\fB\-\-disableharddisk\fR When the ramdisk is simulating a floppy disk drive, this switch will disable hard disk accesses. This is necessary if the client should use a network file system as drive C:, which is only possible if there are no hard disks found by \s-1DOS\s0. This option is incompatible with \-\-harddisk. .PP \&\fB\-\-nosquash\fR Do not try to chop unused sectors from the end of the floppy image. This increases the boot image size and hence loading time if the \s-1FAT\s0 filesystem on the floppy is mostly empty but you may wish to use this option if you have doubts as to whether the squashing algorithm is working correctly. .PP \&\fB\-\-rdbase=\fR\fI0xNNNNNNNN\fR Set the ramdisk load address. The default load address for the ramdisk is 0x110000. It can be moved higher (lower will not work) if for some reason you need to load other stuff at the address it currently occupies. As this is a linear address and not a segment address, the last 4 bits are not used and should be 0. .SH "BUGS" .IX Header "BUGS" Please report all bugs to Etherboot users mailing list: .SH "SEE ALSO" .IX Header "SEE ALSO" Etherboot tutorial at \f(CW\*(C`http://etherboot.sourceforge.net/\*(C'\fR Mtools package is at \f(CW\*(C`http://wauug.erols.com/pub/knaff/mtools/\*(C'\fR Make sure you have a recent version, the ability to map a drive to a file is not present in old versions. .SH "COPYRIGHT" .IX Header "COPYRIGHT" \&\fBmknbi\fR is under the \s-1GNU\s0 Public License .SH "AUTHOR" .IX Header "AUTHOR" Ken Yap .PP mk{elf,nbi}\-nfl was contributed by Robb Main of Genedyne. .SH "DATE" .IX Header "DATE" See man page footer for date and version. Sorry, not available in the \&\s-1HTML\s0 version. mknbi-1.4.4/altboot.bin0100644000175000001440000000100007544635464013463 0ustar kenusers>MSDOS5.0@ )NO NAME FAT12 1м|؎1|&||||`rGR &| |HZRP>|9r |[X}.|$|pXX|t 1PRQ6|ˆшƀŸ$|YZX Ramdisk error - press any key to continue Umknbi-1.4.4/disnbi.html0100644000175000001440000000365210110544104013447 0ustar kenusers disnbi - display Etherboot image


NAME

disnbi - display Etherboot image


SYNOPSIS

disnbi [-e] Etherboot-file


DESCRIPTION

disnbl is a program that to display in symbolic form the contents of a Etherboot image created by mknbi or mkelf. Detection of image type is automatic.

-e Extract contents of image as well. The directory will be written to nbidir or elfdir and the segments to segmentn where n is 0, 1, 2, etc.


BUGS

Please report all bugs to the author.


SEE ALSO

Etherboot tutorial at http://etherboot.sourceforge.net/


COPYRIGHT

disnbl is under the GNU Public License


AUTHOR

Ken Yap (ken_yap@users.sourceforge.net)


DATE

Version 1.4 December 2002

mknbi-1.4.4/memsizes.c0100644000175000001440000000111607610231557013322 0ustar kenusers#include "etherboot.h" #include "start32.h" /* Taken from Etherboot */ /* by Eric Biederman */ struct meminfo meminfo; void get_memsizes(void) { int i; meminfo.basememsize = basememsize(); meminfo.memsize = memsize(); meminfo.map_count = meme820(meminfo.map, E820MAX); if (meminfo.map_count == 0) { /* If we don't have an e820 memory map fake it */ meminfo.map_count = 2; meminfo.map[0].size = meminfo.basememsize << 10; meminfo.map[0].type = E820_RAM; meminfo.map[1].addr = 1024*1024; meminfo.map[1].size = meminfo.memsize << 10; meminfo.map[1].type = E820_RAM; } } mknbi-1.4.4/first-elf.dos0100644000175000001440000001324510106323723013721 0ustar kenusersڌȎ،.6>F~FFF O~&;u.&G;u$&G$<u1t!&:AuG6>.˾^ t&Eu&E&]f h &E &]  أj &0&n &Ap &At &Ar &Al &A w &A v Av r2Q&>uO&>t&>u?&&01r*FQv &8$u&> u&> &:r taPX6>.1> t &<u߹t ΀<u3뱃ێÿ' 6, u31Ɂ<u As"/~&E"&:mt&Eu & 1YQı%0YVt S0[^ DOS Net Boot Image Loader Version 0.8.1 mknbi-dos-1.4.4 GPLed by G. Kuhlmann 6mknbi-dos-1.4.4cScCMUSTANpp Error in load record data Invalid boot header magic number Invalid vendor magic ID Error while accessing ramdisk Wrong ramdisk image BOOTP record invalid RPL=JuQYPXJX..X uD<u.h .f .j <u ˺' .% <u˺T .v .z <uMuP.| . ~ uC/v sJr.w tu$0u.T .u 0 ..T vJS0r݀uʜ.T .u Rʀu.T ru 뼜.T ZS&'[PXUF]X0<<x t R0ҜT Zr0[\&'[[RQSPs2X[YZ;p r;n v [(s @uX[YZ0[u r .l 6t 11[0[[RQP XsYZ[r ċn p SQÈ11Ɋt ȁr S1 t PRZX[ـ?:r wIxȁ;p r w;n rY[VWQRP t f h Tt1ұ0؁UuȎ XZY_^û@.d {0[r00Ou%j A9wS´ 8[ t z * uz z +f h r=PUPFFNX].6~ .6| [. . Ȏм QRVWȎ[_^ZY. . Sv  &E u1&;u&=u uT ڌش/،9u9u u t/u1` &b &> &MP t ` z tR Z t ƒ¿1[0AP` NetB@h `P` NO NAME FAT12  2 1 ؎Ў$0 2 H p pp2  2 ËD$USVWMDff_^[]USVW}0 u Vf1f fPAMSfrf=PAMSufNft fufX)_^[]SVW11Ҹr$utȉf%fff f%ffM_^[}f8fUSVWEà Tf]fPfS˃f_^[].g f"f1 ؎Ё0 1X0 PX-0 P0  ؎Ў f"fȎ؎f'1 0 0 UWVS|$hU6 ?Zufw _9sZBN <F,89w< u1j hx6 Q uFtt D$D$9݉rD$8ELFu D$8th6 $X6 t$h6 t$h J [^_1]S\$ uj Y\$[AUWVS,D$@t$DD$>l$H<%t&|$@tT$BT$PYF0< w F0< v>.uF0< w F0< vM9y|$@Yt T$BT$ P3Z;uJ<#|$ $u$F>hu F>huFЃ |$@tD$T$@)T$D$,[^_]ÍD$Pt$j ÍD$ Pt$ t$ ÐST$1ɀ:\$ t9uB:u[S\$L$ ڊABu[S\$;L$ tB:uAt BAu[VSt$ >\$L$tB:uCtItBCtIu[^WVS\$19ڋ|$t$}: 28t )B9|1[^_mknbi-1.4.4/first32.c (ELF) (GPL) EtherbootBad argument 0123456789ABCDEF%d.mknbi-1.4.4/luabuild/0040755000175000001440000000000007610551042013121 5ustar kenusersmknbi-1.4.4/luabuild/luapatch.txt0100644000175000001440000005006510110544112015453 0ustar kenusersdiff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/config lua-4.0.1/config --- /usr/local/src/lua-4.0.1/config 2000-11-07 07:28:20.000000000 +1100 +++ lua-4.0.1/config 2003-01-13 10:49:43.000000000 +1100 @@ -28,8 +28,10 @@ # ------------------------------------------------------------------ C compiler # You need an ANSI C compiler. gcc is a popular one. -CC= gcc -WARN= -ansi -pedantic -Wall +CC= /usr/i386-linux-uclibc/bin/i386-uclibc-gcc -nostdlib -Os -ffreestanding -fstrength-reduce -mcpu=i386 +WARN=-Wall -W -Wno-format -Wno-unused +LUA_RELOC=0x60000 +EXTRA_DEFS=-DLUA_RELOC=$(LUA_RELOC) -DDATA_START=0x80000 # On IRIX, cc is a good ANSI compiler. #CC= cc @@ -56,7 +58,8 @@ # in libm.a (-lm). If your C library already includes the math functions, # or if you are using a modified interpreter that does not need them, # then comment the following line. -EXTRA_LIBS= -lm +#EXTRA_LIBS= -lm +EXTRA_LIBS= /usr/i386-linux-uclibc/lib/libc.a # ------------------------------------------------------------------ librarian diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/byteswap.h lua-4.0.1/include/byteswap.h --- /usr/local/src/lua-4.0.1/include/byteswap.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/byteswap.h 2003-01-07 22:27:31.000000000 +1100 @@ -0,0 +1,65 @@ +#define __LITTLE_ENDIAN /* x86 */ + +/* Taken from /usr/include/linux/hfs_sysdep.h */ +#if defined(__BIG_ENDIAN) +# if !defined(__constant_htonl) +# define __constant_htonl(x) (x) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) (x) +# endif +#elif defined(__LITTLE_ENDIAN) +# if !defined(__constant_htonl) +# define __constant_htonl(x) \ + ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ + (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ + (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) \ + ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) +# endif +#else +# error "Don't know if bytes are big- or little-endian!" +#endif + +#define ntohl(x) \ +(__builtin_constant_p(x) ? \ + __constant_htonl((x)) : \ + __swap32(x)) +#define htonl(x) \ +(__builtin_constant_p(x) ? \ + __constant_htonl((x)) : \ + __swap32(x)) +#define ntohs(x) \ +(__builtin_constant_p(x) ? \ + __constant_htons((x)) : \ + __swap16(x)) +#define htons(x) \ +(__builtin_constant_p(x) ? \ + __constant_htons((x)) : \ + __swap16(x)) + +static inline unsigned long int __swap32(unsigned long int x) +{ + __asm__("xchgb %b0,%h0\n\t" + "rorl $16,%0\n\t" + "xchgb %b0,%h0" + : "=q" (x) + : "0" (x)); + return x; +} + +static inline unsigned short int __swap16(unsigned short int x) +{ + __asm__("xchgb %b0,%h0" + : "=q" (x) + : "0" (x)); + return x; +} + +/* Make routines available to all */ +#define swap32(x) __swap32(x) +#define swap16(x) __swap16(x) diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/elf_boot.h lua-4.0.1/include/elf_boot.h --- /usr/local/src/lua-4.0.1/include/elf_boot.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/elf_boot.h 2003-01-07 22:27:31.000000000 +1100 @@ -0,0 +1 @@ +#include "../../elf_boot.h" diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/etherboot.h lua-4.0.1/include/etherboot.h --- /usr/local/src/lua-4.0.1/include/etherboot.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/etherboot.h 2003-01-07 22:27:31.000000000 +1100 @@ -0,0 +1 @@ +#include "../../etherboot.h" diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/lualib.h lua-4.0.1/include/lualib.h --- /usr/local/src/lua-4.0.1/include/lualib.h 2000-10-28 03:15:53.000000000 +1100 +++ lua-4.0.1/include/lualib.h 2003-01-13 11:02:01.000000000 +1100 @@ -23,6 +23,7 @@ LUALIB_API void lua_strlibopen (lua_State *L); LUALIB_API void lua_mathlibopen (lua_State *L); LUALIB_API void lua_dblibopen (lua_State *L); +LUALIB_API void lua_userlibopen (lua_State *L); diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/misc.h lua-4.0.1/include/misc.h --- /usr/local/src/lua-4.0.1/include/misc.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/misc.h 2003-01-13 01:07:18.000000000 +1100 @@ -0,0 +1 @@ +#include "../../misc.h" diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/printf.h lua-4.0.1/include/printf.h --- /usr/local/src/lua-4.0.1/include/printf.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/printf.h 2003-01-07 22:27:31.000000000 +1100 @@ -0,0 +1 @@ +#include "../../printf.h" diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/setjmp.h lua-4.0.1/include/setjmp.h --- /usr/local/src/lua-4.0.1/include/setjmp.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/setjmp.h 2003-01-07 22:27:31.000000000 +1100 @@ -0,0 +1 @@ +#include "../../setjmp.h" diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/signal.h lua-4.0.1/include/signal.h --- /usr/local/src/lua-4.0.1/include/signal.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/signal.h 2003-01-13 11:02:54.000000000 +1100 @@ -0,0 +1,4 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H +#define signal(a,b) +#endif diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/startmenu.h lua-4.0.1/include/startmenu.h --- /usr/local/src/lua-4.0.1/include/startmenu.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/startmenu.h 2003-01-12 20:18:10.000000000 +1100 @@ -0,0 +1 @@ +#include "../../startmenu.h" diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/stddef.h lua-4.0.1/include/stddef.h --- /usr/local/src/lua-4.0.1/include/stddef.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/stddef.h 2003-01-07 22:27:31.000000000 +1100 @@ -0,0 +1 @@ +#include "../../stddef.h" diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/include/stdio.h lua-4.0.1/include/stdio.h --- /usr/local/src/lua-4.0.1/include/stdio.h 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/include/stdio.h 2003-01-07 22:27:31.000000000 +1100 @@ -0,0 +1,16 @@ +#ifndef _STDIO_H +#define _STDIO_H +#include "stddef.h" +#include "printf.h" +#define BUFSIZ 8192 +typedef void FILE; +extern FILE *stdin, *stdout, *stderr; +extern int sprintf(char *str, const char *fmt, ...); +extern int vsprintf(char *buf, const char *fmt, const int *dp); +extern inline int fprintf(FILE *f, const char *fmt, ...) { + return (vsprintf(0, fmt, ((const int *)&fmt)+1)); +} +#define fputs(s,f) printf("%s",s) +#define fread(a,b,c,d) 1 +#define feof(f) 0 +#endif diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/Makefile lua-4.0.1/Makefile --- /usr/local/src/lua-4.0.1/Makefile 2000-11-01 04:32:01.000000000 +1100 +++ lua-4.0.1/Makefile 2003-01-07 22:27:31.000000000 +1100 @@ -10,8 +10,9 @@ all clean co klean: cd include; $(MAKE) $@ cd src; $(MAKE) $@ - cd src/luac; $(MAKE) $@ + # cd src/luac; $(MAKE) $@ cd src/lib; $(MAKE) $@ + cd sa; $(MAKE) $@ cd src/lua; $(MAKE) $@ # remove debug information from binaries diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/sa/brk.c lua-4.0.1/sa/brk.c --- /usr/local/src/lua-4.0.1/sa/brk.c 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/sa/brk.c 2003-01-07 22:27:31.000000000 +1100 @@ -0,0 +1,31 @@ +#include + +extern void _end; +static void *curr_heap_top = &_end; + +int brk(void *end_data_segment) { + int sp; + + /* Give 256 bytes of room between heap and stack */ + if (end_data_segment > (void *)&sp - 0x100) { + errno = ENOMEM; + return (-1); + } + curr_heap_top = end_data_segment; + return (0); +} + +void *sbrk(unsigned long increment) { + int sp; + + if (increment <= 0) + return (curr_heap_top); + void *p = curr_heap_top; + /* Give 256 bytes of room between heap and stack */ + if (p + increment > (void *)&sp - 0x100) { + errno = ENOMEM; + return (0); + } + curr_heap_top += increment; + return (p); +} diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/sa/luserlib.c lua-4.0.1/sa/luserlib.c --- /usr/local/src/lua-4.0.1/sa/luserlib.c 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/sa/luserlib.c 2003-01-13 10:43:39.000000000 +1100 @@ -0,0 +1,80 @@ +/* + * Interface to available routines in BIOS library. + * GPL, Ken Yap 2003 + * (I know the filename suggests ineptitude, but it's not a + * very rich set of routines anyway. :-) + */ + +#include "lauxlib.h" +#include "lualib.h" + +#include "startmenu.h" +#include "misc.h" + +#define zero_result(x) x; return 0 +#define single_result(x) lua_pushnumber(L, x); return 1 + +static int l_checkkey(lua_State *L) { single_result(console_checkkey()); } + +static int l_cls(lua_State *L) { zero_result(console_cls()); } + +static int l_getkey(lua_State *L) { single_result(console_getkey()); } + +static int l_getshift(lua_State *L) { single_result(console_getshift()); } + +static int l_getxy(lua_State *L) { single_result(console_getxy()); } + +static int l_gotoxy(lua_State *L) { + int n = lua_gettop(L); + if (n < 2) { + single_result(0); + } + zero_result(console_gotoxy(luaL_check_number(L, 1), luaL_check_number(L, 2))); +} + +static int l_ischar(lua_State *L) { single_result(console_ischar()); } + +static int l_nocursor(lua_State *L) { zero_result(console_nocursor()); } + +static int l_setattrib(lua_State *L) { + int n = lua_gettop(L); + if (n < 1) { + single_result(0); + } + zero_result(console_setattrib(luaL_check_number(L, 1))); +} + +static int l_currticks(lua_State *L) { single_result(currticks()); } + +#if ANSIMODE==-1 +static int l_ansiswitch(lua_State *L) { + int n = lua_gettop(L); + if (n < 1) { + single_result(0); + } + zero_result(ansiswitch(luaL_check_number(L, 1))); +} +#endif + +static const struct luaL_reg userlib[] = { + {"checkkey",l_checkkey}, + {"cls",l_cls}, + {"getkey",l_getkey}, + {"getshift",l_getshift}, + {"getxy",l_getxy}, + {"gotoxy",l_gotoxy}, + {"ischar",l_ischar}, + {"nocursor",l_nocursor}, + {"setattrib",l_setattrib}, + {"currticks",l_currticks}, +#if ANSIMODE==-1 + {"ansiswitch",l_ansiswitch}, +#endif +}; + +/* +** Open user library +*/ +LUALIB_API void lua_userlibopen (lua_State *L) { + luaL_openl(L, userlib); +} diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/sa/Makefile lua-4.0.1/sa/Makefile --- /usr/local/src/lua-4.0.1/sa/Makefile 1970-01-01 10:00:00.000000000 +1000 +++ lua-4.0.1/sa/Makefile 2003-01-13 01:08:33.000000000 +1100 @@ -0,0 +1,40 @@ +LUA= .. +include $(LUA)/config + +# Options for auxiliary menu program +# Available: -DANSIESC -DANSIMODE -DCONSOLE_CRT/CONSOLE_SERIAL -DPOWERSAVE -DCOMCONSOLE -DCOMPRESERVE +# ANSIMODE requires ANSIESC, see misc.c for choices +# Might as well take the lot since code size is not a concern +EXTRA_FLAGS= -DCONSOLE_CRT -DANSIESC -DANSIMODE=-1 -DPOWERSAVE -DCOMCONSOLE=0x3f8 -DCOMPRESERVE + +# We steal the malloc .o's from uclibc. They have to be in libsalib.a +# otherwise they bind to the s/brk in uclibc instead of our substitute +UCLIBC= /usr/i386-linux-uclibc/lib/libc.a +MOBJS= malloc.o realloc.o heap_alloc.o heap_alloc_at.o free.o heap_free.o + +all: ../lib/libsalib.a startmenu.o + +../lib/libsalib.a: printf.o misc.o ansiesc.o brk.o luserlib.o $(UCLIBC) + ar xv $(UCLIBC) $(MOBJS) + $(AR) $@ printf.o misc.o ansiesc.o brk.o luserlib.o $(MOBJS) + +startmenu.o: ../../startmenu.S + gcc -E -Ui386 -DRELOC=$(LUA_RELOC) ../../startmenu.S | $(AS) -o startmenu.o + +printf.o: ../../printf.c + $(CC) $(CFLAGS) -c ../../$*.c + +misc.o: ../../misc.h ../../misc.c ../../ansiesc.h ../../etherboot.h + $(CC) $(CFLAGS) $(EXTRA_FLAGS) -c ../../$*.c + +ansiesc.o: ../../ansiesc.h ../../ansiesc.c ../../stddef.h ../../string.h ../../etherboot.h + $(CC) $(CFLAGS) $(EXTRA_FLAGS) -c ../../$*.c + +brk.o: brk.c + $(CC) $(CFLAGS) -c $*.c + +luserlib.o: luserlib.c + $(CC) $(CFLAGS) $(EXTRA_FLAGS) -c $*.c + +clean: + rm *.o diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/src/ldo.c lua-4.0.1/src/ldo.c --- /usr/local/src/lua-4.0.1/src/ldo.c 2002-06-21 00:24:40.000000000 +1000 +++ lua-4.0.1/src/ldo.c 2003-01-07 22:27:31.000000000 +1100 @@ -260,6 +260,7 @@ static int parse_file (lua_State *L, const char *filename) { +#if 0 ZIO z; int status; int bin; /* flag for file mode */ @@ -284,6 +285,9 @@ if (f != stdin) fclose(f); return status; +#else + return 0; +#endif } diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/src/lib/lbaselib.c lua-4.0.1/src/lib/lbaselib.c --- /usr/local/src/lua-4.0.1/src/lib/lbaselib.c 2002-06-12 03:01:50.000000000 +1000 +++ lua-4.0.1/src/lib/lbaselib.c 2003-01-07 22:27:31.000000000 +1100 @@ -75,11 +75,15 @@ s = lua_tostring(L, -1); /* get result */ if (s == NULL) lua_error(L, "`tostring' must return a string to `print'"); +#if 0 if (i>1) fputs("\t", stdout); +#endif fputs(s, stdout); lua_pop(L, 1); /* pop result */ } +#if 0 fputs("\n", stdout); +#endif return 0; } diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/src/lib/Makefile lua-4.0.1/src/lib/Makefile --- /usr/local/src/lua-4.0.1/src/lib/Makefile 2000-09-20 13:13:52.000000000 +1100 +++ lua-4.0.1/src/lib/Makefile 2003-01-07 22:27:31.000000000 +1100 @@ -7,8 +7,8 @@ # actually only used in liolib.c EXTRA_DEFS= $(POPEN) -OBJS= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o lstrlib.o -SRCS= lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c lstrlib.c +OBJS= lauxlib.o lbaselib.o ldblib.o lstrlib.o +SRCS= lauxlib.c lbaselib.c ldblib.c lstrlib.c T= $(LIB)/liblualib.a diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/src/llimits.h lua-4.0.1/src/llimits.h --- /usr/local/src/lua-4.0.1/src/llimits.h 2000-10-26 23:47:05.000000000 +1100 +++ lua-4.0.1/src/llimits.h 2003-01-07 22:28:25.000000000 +1100 @@ -42,7 +42,7 @@ typedef LUA_NUM_TYPE Number; /* function to convert a Number to a string */ -#define NUMBER_FMT "%.16g" /* LUA_NUMBER */ +#define NUMBER_FMT "%d" /* LUA_NUMBER */ #define lua_number2str(s,n) sprintf((s), NUMBER_FMT, (n)) /* function to convert a string to a Number */ diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/src/lparser.c lua-4.0.1/src/lparser.c --- /usr/local/src/lua-4.0.1/src/lparser.c 2000-11-29 22:57:42.000000000 +1100 +++ lua-4.0.1/src/lparser.c 2003-01-07 22:27:31.000000000 +1100 @@ -1019,7 +1019,7 @@ } -static int stat (LexState *ls) { +static int statm (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->t.token) { case TK_IF: { /* stat -> ifstat */ @@ -1115,7 +1115,7 @@ /* chunk -> { stat [';'] } */ int islast = 0; while (!islast && !block_follow(ls->t.token)) { - islast = stat(ls); + islast = statm(ls); optional(ls, ';'); LUA_ASSERT(ls->fs->stacklevel == ls->fs->nactloc, "stack size != # local vars"); diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/src/lua/lua.c lua-4.0.1/src/lua/lua.c --- /usr/local/src/lua-4.0.1/src/lua/lua.c 2000-10-21 03:36:32.000000000 +1100 +++ lua-4.0.1/src/lua/lua.c 2003-01-10 13:03:11.000000000 +1100 @@ -15,6 +15,12 @@ #include "luadebug.h" #include "lualib.h" +#include "etherboot.h" +#include "elf_boot.h" +#include "byteswap.h" + +#define LUA_VERSION_CHECK 0x04000100 /* 4.0.1.0 */ + static lua_State *L = NULL; @@ -50,11 +56,16 @@ static void userinit (void) { lua_baselibopen(L); +#if 0 lua_iolibopen(L); +#endif lua_strlibopen(L); +#if 0 lua_mathlibopen(L); +#endif lua_dblibopen(L); /* add your libraries here */ + lua_userlibopen(L); } @@ -150,6 +161,7 @@ } +#if 0 static int file_input (const char *argv) { int result = ldo(lua_dofile, argv); if (result) { @@ -283,6 +295,7 @@ } return EXIT_SUCCESS; } +#endif static void getstacksize (int argc, char *argv[], struct Options *opt) { @@ -306,6 +319,7 @@ } +#if 0 int main (int argc, char *argv[]) { struct Options opt; int status; @@ -319,4 +333,86 @@ lua_close(L); return status; } +#endif + +static void parse_elf_boot_notes( + void *notes, union infoblock **rheader, struct bootp_t **rbootp) +{ + unsigned char *note, *end; + Elf_Bhdr *bhdr; + Elf_Nhdr *hdr; + + bhdr = notes; + if (bhdr->b_signature != ELF_BHDR_MAGIC) { + return; + } + + note = ((char *)bhdr) + sizeof(*bhdr); + end = ((char *)bhdr) + bhdr->b_size; + while (note < end) { + unsigned char *n_name, *n_desc, *next; + hdr = (Elf_Nhdr *)note; + n_name = note + sizeof(*hdr); + n_desc = n_name + ((hdr->n_namesz + 3) & ~3); + next = n_desc + ((hdr->n_descsz + 3) & ~3); + if (next > end) + break; +#if 0 + printf("n_type: %x n_name(%d): n_desc(%d): \n", + hdr->n_type, hdr->n_namesz, hdr->n_descsz); +#endif + if ((hdr->n_namesz == 10) && + (memcmp(n_name, "Etherboot", 10) == 0)) { + switch(hdr->n_type) { + case EB_BOOTP_DATA: + *rbootp = *((void **)n_desc); + break; + case EB_HEADER: + *rheader = *((void **)n_desc); + break; + default: + break; + } + } + note = next; + } +} + +static uint32_t getlong(const char *p) { + union { + uint8_t c[4]; + uint32_t l; + } u; + memcpy(u.c, p, sizeof(uint32_t)); + return (ntohl(u.l)); +} + +int menu(struct ebinfo *eb, union infoblock *header, struct bootp_t *bootp) +{ + uint32_t l; + parse_elf_boot_notes(eb, &header, &bootp); + L = lua_open(0); /* create state */ + userinit(); /* open libraries */ + print_version(); + const char *name = (const char *)DATA_START; + if ((l = getlong(name)) != LUA_VERSION_CHECK) { + fprintf(stderr, "Lua version mismatch (%#X != %#X)\n", l, LUA_VERSION_CHECK); + return 0; + } + name += sizeof(uint32_t); + int len = (strlen(name) + sizeof(uint32_t)) & ~(sizeof(uint32_t)-1); + int top = lua_gettop(L); + int res = lua_dobuffer(L, name + len + sizeof(uint32_t), getlong(name + len), name); + lua_settop(L, top); /* remove eventual results */ + lua_close(L); + /* Lua gives no message in such cases, so lua.c provides one */ + if (res == LUA_ERRMEM) { + fprintf(stderr, "lua: memory allocation error\n"); + } + else if (res == LUA_ERRERR) + fprintf(stderr, "lua: error in error message\n"); + else if (res != 0) + fprintf(stderr, "lua: error %d\n", res); + return 0; +} diff -ur --exclude='*.a' --exclude='*.o' --exclude='*.map' --unidirectional-new-file /usr/local/src/lua-4.0.1/src/lua/Makefile lua-4.0.1/src/lua/Makefile --- /usr/local/src/lua-4.0.1/src/lua/Makefile 2000-03-31 23:52:56.000000000 +1000 +++ lua-4.0.1/src/lua/Makefile 2003-01-07 22:27:31.000000000 +1100 @@ -4,7 +4,7 @@ include $(LUA)/config -EXTRA_DEFS= $(POSIX) +EXTRA_DEFS+= $(POSIX) OBJS= lua.o SRCS= lua.c @@ -13,8 +13,8 @@ all: $T -$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a - $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) +$T: $(OBJS) $(LUA)/sa/startmenu.o $(LIB)/liblua.a $(LIB)/liblualib.a $(LIB)/libsalib.a + $(LD) -M --oformat binary -N -Ttext $(LUA_RELOC) -e _start -o $@ $(LUA)/sa/startmenu.o $(OBJS) -L$(LIB) -llua -llualib -lsalib $(EXTRA_LIBS) > lua.map $(LIB)/liblua.a: cd ..; $(MAKE) @@ -22,6 +22,12 @@ $(LIB)/liblualib.a: cd ../lib; $(MAKE) +$(LUA)/sa/startmenu.o: + cd ../../sa; $(MAKE) startmenu.o + +$(LIB)/libsalib.a: + cd ../../sa; $(MAKE) ../lib/libsalib.a + clean: rm -f $(OBJS) $T mknbi-1.4.4/luabuild/HOWTO0100644000175000001440000000277307610550726013762 0ustar kenusersTo rebuild the Lua interpreter, you need the Lua source distribution (of course), and the uClibc library. The uClibc library is used to provide routines needed by the downloadable interpreter. uClibc can be found here: http://www.uclibc.org The version used was 0.9.16. You need to build with MMU enabled and no shared libraries, otherwise it will use mmap instead of sbrk to obtain more memory (which we don't support) and will not create a libc.a without shared library hooks (which we also don't support). Lua can be found here: http://www.tecgraf.puC-rio.br/lua/ The version used is 4.0.1. You need to build a luac compiler separately, say in /usr/local. You will need to build it with LUA_NUM_TYPE=long (in config) and NUMBER_FMT=%ld. This is not the default as distributed. If you don't change the settings as shown, then you will get a sizeof mismatch when you try to execute Lua binary scripts. (To fix this to use the default of LUA_NUM_TYPE=double, I need to figure out how to implement %g in printf.) Then unpack Lua again in the directory above this one and then apply the patch in this directory to it. I.e., if you have the distribution in /usr/local/src/lua-4.0.1.tar.gz, tar zxvf /usr/local/src/lua-4.0.1.tar.gz cd lua-4.0.1 patch -p1 < ../luabuild/luapatch.txt make and hopeully everything will compile ok. If not, check the settings in config and the various Makefiles. The program is in lua-4.0.1/bin/lua, which is copied to lua and thence to the library directory by a make install on mknbi. mknbi-1.4.4/luabuild/README0100644000175000001440000000122707610551042014000 0ustar kenusersThis directory contains the patch for building a downloadable binary of the Lua interpreter. Lua is a Pascal-like extension language that is often used for providing embedded scripting. It is described here: http://www.tecgraf.puc-rio.br/lua/ The downloadable binary does not implement the full set of calls as distributed. Missing are any filesystem calls (naturally) and the math library (mainly for reasons of space, although it should not be a problem to reinstate it). However provided are a set of calls to interface to the standalone library used by the menuing programs in mknbi. The calls available are in sa/luserlib.c. This is a work-in-progress. mknbi-1.4.4/luabuild/format.lua0100644000175000001440000000011107606035054015107 0ustar kenusers-- test format function s = format("%s %d\n", "Hello Lua", 42) print(s) mknbi-1.4.4/luabuild/format.lb0100644000175000001440000000026607606035067014742 0ustar kenusersLua@  [A @format.luasformat%s %d Hello Luaprint LF B  mknbi-1.4.4/luabuild/hello.lua0100644000175000001440000000002507606033504014724 0ustar kenusersprint("Hello Lua\n") mknbi-1.4.4/luabuild/hello.lb0100644000175000001440000000017207606033511014541 0ustar kenusersLua@  [A @hello.luaprint Hello Lua  Gmknbi-1.4.4/menu.c0100644000175000001440000001226007610230320012417 0ustar kenusers#include "stddef.h" #include "string.h" #include "printf.h" #include "ansiesc.h" #include "misc.h" #include "linux-asm-io.h" #include "etherboot.h" #include "startmenu.h" #include "elf_boot.h" #include "bootmenu.h" /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. */ /* This is an example program which shows how the extension routine feature in Etherboot 5.0 works. This program is linked to run at 0x60000, and expects to find config data if any at 0x70000. This means the code can be up to 64kB long. When the program starts it receives 3 parameters from Etherboot: Pointer to ebinfo structure Pointer to image header structure (either a tagged or ELF image header) Pointer to bootp/DHCP reply obtained by Etherboot from bootpd or DHCPD Etherboot expects this program to return an int. The values have these meanings: <0 Do not use 0 Same as 1, for implementation reasons 1 Redo tftp with possibly modified bootp record 2 Redo bootp and tftp 255 Exit Etherboot Observe that this program causes Etherboot to load a different program next by modifying the contents of the filename field in the bootp record and then returning 1. It can also send parameters to the next program by modifying tag 129 in the bootp record. */ /* Memory layout assumed by mknbi and this program 0x60000-0x6FFFF 64 kB Menu program 0x70000-0x7FFFF 64 kB Menu data (initial) */ static unsigned char *vendortags; static unsigned char *end_of_rfc1533; #ifdef IMAGE_FREEBSD /* yes this is a pain FreeBSD uses this for swap, however, there are cases when you don't want swap and then you want this set to get the extra features so lets just set if dealing with FreeBSD. I haven't run into any troubles with this but I have without it */ static int vendorext_is_valid = 1; #else static int vendorext_is_valid = 0; #endif static unsigned char *motd[RFC1533_VENDOR_NUMOFMOTD] = { 0 }; static unsigned char *imagelist[RFC1533_VENDOR_NUMOFIMG] = { 0 }; static inline void checkvendor(void) { union { unsigned long l; unsigned char c[4]; } u; memcpy(u.c, vendortags, sizeof(u)); if (u.l == RFC_1048 || u.l == VEND_CMU || u.l == VEND_STAN) vendortags += 4; else vendortags = 0; } static void parsebootp() { unsigned char *p; unsigned int c; static unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* Eth */ memset(motd, 0, sizeof(motd)); memset(imagelist, 0, sizeof(imagelist)); if (vendortags == 0) return; for (p = vendortags; (c = *p) != RFC1533_END; ) { if (c == RFC1533_PAD) { p++; continue; } #if DEBUG > 1 printf("Tag %d\n", c); #endif switch (c) { case RFC1533_VENDOR_MAGIC: if (TAG_LEN(p) >= 6 && !memcmp(p+2, vendorext_magic, 4) && p[6] == RFC1533_VENDOR_MAJOR) vendorext_is_valid = 1; break; case RFC1533_VENDOR_MENUOPTS: parse_menuopts(p+2, TAG_LEN(p)); break; default: if (c >= RFC1533_VENDOR_MOTD && c < RFC1533_VENDOR_MOTD + RFC1533_VENDOR_NUMOFMOTD) motd[c-RFC1533_VENDOR_MOTD] = p; else if (c >= RFC1533_VENDOR_IMG && c < RFC1533_VENDOR_IMG + RFC1533_VENDOR_NUMOFIMG) imagelist[c-RFC1533_VENDOR_IMG] = p; break; } p += p[1] + 2; } end_of_rfc1533 = p; } static void parse_elf_boot_notes( void *notes, union infoblock **rheader, struct bootpd_t **rbootp) { unsigned char *note, *end; Elf_Bhdr *bhdr; Elf_Nhdr *hdr; bhdr = notes; if (bhdr->b_signature != ELF_BHDR_MAGIC) { return; } note = ((char *)bhdr) + sizeof(*bhdr); end = ((char *)bhdr) + bhdr->b_size; while (note < end) { unsigned char *n_name, *n_desc, *next; hdr = (Elf_Nhdr *)note; n_name = note + sizeof(*hdr); n_desc = n_name + ((hdr->n_namesz + 3) & ~3); next = n_desc + ((hdr->n_descsz + 3) & ~3); if (next > end) break; #if 0 printf("n_type: %x n_name(%d): n_desc(%d): \n", hdr->n_type, hdr->n_namesz, hdr->n_descsz); #endif if ((hdr->n_namesz == 10) && (memcmp(n_name, "Etherboot", 10) == 0)) { switch(hdr->n_type) { case EB_BOOTP_DATA: *rbootp = *((void **)n_desc); break; case EB_HEADER: *rheader = *((void **)n_desc); break; default: break; } } note = next; } } int menu(struct ebinfo *eb, union infoblock *header, struct bootpd_t *bootp) { int i; extern int serial_init(void); extern void serial_fini(void); #ifdef DEBUG printf(MKNBI_VERSION "\n"); #endif parse_elf_boot_notes(eb, &header, &bootp); /* Sanity check */ if (header->img.magic != ELF_MAGIC && header->img.magic != TAG_MAGIC) { printf("Bad argument passed from Etherboot\n"); return (255); } vendortags = (unsigned char *)bootp->bootp_reply.bp_vend; checkvendor(); parsebootp(); if (!vendorext_is_valid) { printf("No menu vendor tags found, returning to Etherboot\n"); sleep(10); return(2); } #ifdef CONSOLE_SERIAL serial_init(); #endif #ifdef ANSIESC ansi_reset(); #endif show_motd(motd); i = selectImage(bootp, imagelist, end_of_rfc1533); if (i == 2) { printf("No selection, returning to Etherboot\n"); sleep(10); } #ifdef CONSOLE_SERIAL serial_fini(); #endif return (i); } mknbi-1.4.4/misc.c0100644000175000001440000000423310106323713012412 0ustar kenusers#include "ansiesc.h" #include "etherboot.h" #include "start32.h" #include "misc.h" #if ANSIMODE==-1 static int ansion = 0; #endif /************************************************************************** SLEEP **************************************************************************/ void sleep(int secs) { unsigned long tmo; for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; ) /* Nothing */; } int getdec(unsigned char **ptr) { char *p = *ptr; int ret=0; if ((*p < '0') || (*p > '9')) return(-1); while ((*p >= '0') && (*p <= '9')) { ret = ret*10 + (*p - '0'); p++; } *ptr = p; return(ret); } #if ANSIMODE==-1 void ansiswitch(int i) { ansion = i; } #endif void putchar(int c) { #ifdef CONSOLE_CRT #if ANSIMODE==-1 /* choose by variable */ if (ansion) ansi_putc(c); else { if (c == '\n') console_putc('\r'); console_putc(c); } #elif ANSIMODE==1 /* always ANSI */ ansi_putc(c); #else /* always console */ if (c == '\n') console_putc('\r'); console_putc(c); #endif #endif #ifdef CONSOLE_SERIAL if (c == '\n') serial_putc('\r'); serial_putc(c); #endif } /************************************************************************** GETCHAR - Read the next character from input device WITHOUT ECHO **************************************************************************/ int getchar(void) { int c = 256; do { #ifdef POWERSAVE /* Doze for a while (until the next interrupt). This works * fine, because the keyboard is interrupt-driven, and the * timer interrupt (approx. every 50msec) takes care of the * serial port, which is read by polling. This reduces the * power dissipation of a modern CPU considerably, and also * makes Etherboot waiting for user interaction waste a lot * less CPU time in a VMware session. */ cpu_nap(); #endif /* POWERSAVE */ #ifdef CONSOLE_CRT if (console_ischar()) c = console_getc(); #endif #ifdef CONSOLE_SERIAL if (serial_ischar()) c = serial_getc(); #endif } while (c==256); if (c == '\r') c = '\n'; return c; } int iskey(void) { #ifdef CONSOLE_CRT if (console_ischar()) return 1; #endif #ifdef CONSOLE_SERIAL if (serial_ischar()) return 1; #endif return 0; } mknbi-1.4.4/misc.h0100644000175000001440000000031210106323116012406 0ustar kenusersextern void sleep(int secs); extern int getdec(unsigned char **ptr); #if ANSIMODE==-1 extern void ansiswitch(int i); #endif extern void putchar(int c); extern int getchar(void); extern int iskey(void); mknbi-1.4.4/mklnim0100755000175000001440000000222407173304415012536 0ustar kenusers#!/bin/sh # # Make Linux Netinstall Image # Takes a RedHat, TurboLinux or SuSE CD # and creates a network bootable image # # mklnim outputfile [path-to-cdrom] # # path-to-cdrom defaults to /mnt/cdrom # if [ $# -lt 1 ] then echo Usage: $0 outputfile [path-to-cdrom] exit 1 fi pathtocdrom=${2:-"/mnt/cdrom"} trap '' INT tmpmount=/tmp/lnim.$$ mkdir $tmpmount if [ -r $pathtocdrom/images/cdboot.img ] then bootfloppyimage="$pathtocdrom/images/cdboot.img" echo TurboLinux CDROM elif [ -r $pathtocdrom/images/bootnet.img ] then bootfloppyimage="$pathtocdrom/images/bootnet.img" append='--append=network' echo RedHat 6.x CDROM elif [ -r $pathtocdrom/images/boot.img ] then bootfloppyimage="$pathtocdrom/images/boot.img" echo RedHat 5.2 CDROM elif [ -r $pathtocdrom/disks/bootdisk ] then bootfloppyimage="$pathtocdrom/disks/bootdisk" linuximage=linux initdisk=initdisk.gz echo SuSE 6.x CDROM else echo Cannot find either TurboLinux, RedHat or SuSE CD trap INT exit 1 fi mount -t msdos -o loop,ro $bootfloppyimage $tmpmount mknbi-linux $append --output=$1 $tmpmount/${linuximage:-vmlinuz} $tmpmount/${initdisk:-initrd.img} umount $tmpmount rmdir $tmpmount trap INT mknbi-1.4.4/menu-simple.c0100644000175000001440000001555110110270655013720 0ustar kenusers#include "stddef.h" #include "string.h" #include "linux-asm-io.h" #include "string.h" #include "etherboot.h" #include "startmenu.h" #include "elf_boot.h" /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. */ /* This is an example program which shows how the extension routine feature in Etherboot 5.0 works. This program presents a list of valid boot images from a data segment that is loaded into another area of memory, and prompts the user for a number, and modifies the bootp record to the filename to be loaded. You can make the menu program as elaborate as you like, the sky is the limit. Ideally, there should be a menu generation program that takes a high-level description of menus and valid inputs and creates a data file to be loaded to the data area. The menu program should agree with the menu generator on the layout of the data area. This program is linked to run at 0x60000, and expects to find config data at 0x70000. This means the code can be up to 64kB long. When the program starts it receives 3 parameters from Etherboot: Pointer to ebinfo structure Pointer to image header structure (either a tagged or ELF image header) Pointer to bootp/DHCP reply obtained by Etherboot from bootpd or DHCPD Etherboot expects this program to return an int. The values have these meanings: <0 Do not use 0 Same as 1, for implementation reasons 1 Redo tftp with possibly modified bootp record 2 Redo bootp and tftp 255 Exit Etherboot Observe that this program causes Etherboot to load a different program next by modifying the contents of the filename field in the bootp record and then returning 1. It can also send parameters to the next program by modifying tag 129 in the bootp record. This is how the menu system works. The data segment that this particular program expects is of the form choice 1\nchoice 2\nchoice 3\n\0 where the \n are newlines and the \0 the teminating zero byte. Therefore you can create this file with a Unix text editor (but see next paragraph). choice 1, etc are the pathnames or filenames of the next file to load by TFTP. If the string starts with / then it's assumed to be a pathname and the whole of the bootp filename area is replaced by it, otherwise just the filename portion of the pathname, i.e. the same directory as the menu file is assumed. This program also illustrates the use of a timeout to select a default item by using currticks() to obtain the value of the BIOS clock and console_ischar to determine if a character has been typed at the keyboard. Commentary: This program is just to illustrate a very simple menu system. There are known bugs: mknbi-menu/mkelf-menu does not add the ending NUL byte, but this is present due to the NUL fill to the next block boundary. If the size of the data goes exactly up to a block boundary, then it is possible there will be a spurious final item that goes up the next NUL byte in memory. Another bug is that there is no overflow checking when writing into bootp->bp_file. Yet another bug is that there is no facility to correct input entry on lines. getline() should be smarter. */ /* Memory layout assumed by mknbi and this program 0x60000-0x6FFFF 64 kB Menu program 0x70000-0x7FFFF 64 kB Menu data (initial) */ #define TIMEOUT 10 /* seconds */ #define MENU_DATA ((char *)0x70000) static char *items[10]; extern void printf(const char *, ...); extern void ansi_putc(unsigned int); void putchar(int c) { if (c == '\n') ansi_putc('\r'); ansi_putc(c); } int getchar(void) { int c; c = console_getc(); if (c == '\r') c = '\n'; return (c); } /* * Get a line, ignore characters after array limit reached. * Echo the character if the flag says so. */ int getline(char *line, int length, int echo) { int c; char *p = line; while ((c = getchar()) != '\n') { if (p < &line[length-1]) { /* within array? */ if (echo) ansi_putc(c); *p++ = c; } } *p++ = '\0'; if (echo) ansi_putc('\n'); return (line - p); } int scan_items(void) { int i; char *p; for (i = 1, p = MENU_DATA; i < 10 && *p != '\0'; i++) { items[i] = p; while (*p != '\0' && *p != '\n') p++; if (*p == '\n') *p++ = '\0'; } return (i); } /* * Find the location of the last / of the filename in the bootp * pathname, and return the next location, where the filename * starts. If no / exists, return the beginning of input string. */ char *locate_file(char *pathname) { char *p; if ((p = strrchr(pathname, '/')) == 0) return (pathname); return (p + 1); } /* * Return an index from 1..last-1 if valid character, else 0 * If timeout after 10 seconds occurs, return -1. */ int get_index(int last) { int i; char line[2]; unsigned long now, timeout; timeout = currticks() + TIMEOUT * TICKS_PER_SEC; while ((now = currticks()) < timeout && !console_ischar()) ; if (now >= timeout) return (-1); getline(line, sizeof(line), 1); i = line[0]; if (i >= '1' && i <= '0' + last - 1) return (i - '0'); return (0); } static void parse_elf_boot_notes( void *notes, union infoblock **rheader, struct bootp_t **rbootp) { unsigned char *note, *end; Elf_Bhdr *bhdr; Elf_Nhdr *hdr; bhdr = notes; if (bhdr->b_signature != ELF_BHDR_MAGIC) { return; } note = ((char *)bhdr) + sizeof(*bhdr); end = ((char *)bhdr) + bhdr->b_size; while (note < end) { unsigned char *n_name, *n_desc, *next; hdr = (Elf_Nhdr *)note; n_name = note + sizeof(*hdr); n_desc = n_name + ((hdr->n_namesz + 3) & ~3); next = n_desc + ((hdr->n_descsz + 3) & ~3); if (next > end) break; #if 0 printf("n_type: %x n_name(%d): n_desc(%d): \n", hdr->n_type, hdr->n_namesz, hdr->n_descsz); #endif if ((hdr->n_namesz == 10) && (memcmp(n_name, "Etherboot", 10) == 0)) { switch(hdr->n_type) { case EB_BOOTP_DATA: *rbootp = *((void **)n_desc); break; case EB_HEADER: *rheader = *((void **)n_desc); break; default: break; } } note = next; } } int menu(struct ebinfo *eb, union infoblock *header, struct bootp_t *bootp) { int i, nitems; char *path, *file; /* place to insert filename */ parse_elf_boot_notes(eb, &header, &bootp); path = bootp->bp_file; file = locate_file(path); nitems = scan_items(); printf("\033[J\033[34mEtherboot menu system called from Etherboot %d.%d\033[37m\n\n", eb->major, eb->minor); printf("Available images:\n\n"); for (i = 1; i < nitems; ++i) printf("%d. %s\n", i, items[i]); printf("\n"); do { printf("Make a selection (timeout %d seconds => 1): ", TIMEOUT); i = get_index(nitems); } while (i == 0); if (i == -1) { ansi_putc('1'); ansi_putc('\n'); i = 1; /* pick the first one if timeout */ } if (*items[i] == '/') /* absolute path? overwrite pathname */ strcpy(path, items[i]); else /* use directory of current pathname */ strcpy(file, items[i]); return (1); } mknbi-1.4.4/menu-simple.h0100644000175000001440000000241007230245654013725 0ustar kenusers/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. */ /* * Definitions of data structures generated by the menu compiler * and expected by the menu program. All offsets are from the * beginning of the data area. */ /* * Structure describing the data area, starts at 0. */ struct menu_header { char major, minor; /* Versions */ unsigned short flags; /* Capabilities */ unsigned int timeout; /* Global timeout */ unsigned int selectprompt; /* Offset of string saying Select... */ unsigned int confirmprompt; /* Offset of string saying Confirm... */ unsigned int nmenus; /* Number of menus stored */ /* Here follow unsigned int offsets of menus */ }; /* * Structure describing one menu. The number of items is one * greater than the last valid index. The 0th item holds the * data to be displayed before any user input. */ struct menu { unsigned int timeout; /* Timeout for this menu */ unsigned int nitems; /* Items in this menu */ /* Here follow unsigned int offsets of items */ }; /* * Structure describing one item in a menu. */ struct item { unsigned int title; }; mknbi-1.4.4/rmrd.S0100644000175000001440000000430107136340321012402 0ustar kenusers; rmrd.S - DOS program to remove ramdisk ; ; Copyright (C) 1996-1998 Gero Kuhlmann ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #if !defined(USE_NASM) && !defined(USE_AS86) #define USE_AS86 #endif #ifdef USE_AS86 #define CON(x) *x #define BCON(x) *x #define JMP(x) jmp x #define STRDECL(s) .ascii s #endif #ifdef USE_NASM #define CON(x) x #define BCON(x) byte x #define JMP(x) jmp short x #define STRDECL(s) db s #endif #ifdef USE_AS86 .text entry start #endif #ifdef USE_NASM text #endif org 0x100 start: push cs pop ds xor ax,ax mov es,ax mov si,CON(rdsig) mov di,CON(0xF1) * 4 ; check ramdisk driver signature mov cx,CON(4) repz cmpsb jnz start4 mov ax,CON(0x9C00) int 0xF8 ; check if a ramdisk driver is cmp ax,CON(0x009C) ; installed je start1 start4: mov al,BCON(1) mov dx,CON(noramd) JMP(start9) start1: mov ax,CON(0x9C03) int 0xF8 ; get ramdisk ID or cl,cl ; has to be drive A: (e.g. floppy) jz start2 mov al,BCON(2) mov dx,CON(noflop) JMP(start9) start2: mov ax,CON(0x9C04) int 0xF8 ; remove ramdisk or al,al jz start3 mov al,BCON(3) mov dx,CON(rderr) JMP(start9) start3: xor al,al mov dx,CON(rdok) start9: push ax mov ah,BCON(0x09) int 0x21 ; print error message mov dx,CON(crlf) mov ah,BCON(0x09) int 0x21 ; print CR/LF pop ax mov ah,BCON(0x4C) int 0x21 ; terminate program ; Data area rdsig: STRDECL("NetB") noramd: STRDECL("No ramdisk found$") noflop: STRDECL("Ramdisk is not drive A:$") rderr: STRDECL("Can't remove ramdisk$") rdok: STRDECL("Ramdisk removed$") crlf: db 0x0D,0x0A STRDECL("$") mknbi-1.4.4/disdosbb.pl0100755000175000001440000000253507240641175013461 0ustar kenusers#!/usr/bin/perl -w if ($#ARGV >= 0) { open(STDIN, "$ARGV[0]") or die "$ARGV[0]: $!\n"; } binmode(STDIN); $nread = read(STDIN, $params, 0x3e); (defined($nread) and $nread == 0x3e) or die "Cannot read 0x3e bytes of boot block\n"; (undef, $oem_name, $bytes_per_sector, $sectors_per_cluster, $reserved_sectors, $fat_copies, $root_dir_entries, $total_disk_sectors, $media_descriptor, $sectors_per_fat, $sectors_per_track, $sides, $hidden_sectors_low, $hidden_sectors_high, $total_num_sectors, $phys_drive_number_1, $phys_drive_number_2, $boot_record_sig, $vol_serial_num, $volume_label, $file_system_id) = unpack('A3a8vCvCvvCvvvvvVCCCVa11a8', $params); print <= 0x0201 */ unsigned char fill[8]; /* realmode_switch, start_sys_seg kernel_version */ unsigned char su_type; /* type of loader */ unsigned char su_load_flags; unsigned short su_move_size; unsigned long su_32_start; unsigned long su_ramdisk_start; unsigned long su_ramdisk_size; unsigned short su_bootsect_kludge[2]; unsigned short su_heap_end_ptr; unsigned short su_pad; unsigned char *su_cmd_line_ptr;/* new cmd line protocol used when su_version >= 0x202 */ unsigned long ramdisk_max; /* highest safe address for the contents of an initrd su_version >= 0x203 */ }; #define SU_MY_LOADER_TYPE 0x41 struct ebinfo { unsigned char major, minor; unsigned short flags; }; struct e820entry { unsigned long long addr; unsigned long long size; unsigned long type; #define E820_RAM 1 #define E820_RESERVED 2 #define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ #define E820_NVS 4 }; #define E820MAX 32 struct meminfo { unsigned short basememsize; unsigned int memsize; int map_count; struct e820entry map[E820MAX]; }; extern struct meminfo meminfo; extern void get_memsizes(void); mknbi-1.4.4/printf.c0100644000175000001440000000672207604574505013006 0ustar kenusers/************************************************************************** MISC Support Routines **************************************************************************/ #include "misc.h" #include "printf.h" #include "etherboot.h" /* Recursive call of sprintf in vsprintf */ int sprintf(char *buf, const char *fmt, ...); extern void putchar(int); /************************************************************************** PRINTF and friends Formats: %[#]x - 4 bytes long (8 hex digits, lower case) %[#]X - 4 bytes long (8 hex digits, upper case) %[#]hx - 2 bytes int (4 hex digits, lower case) %[#]hX - 2 bytes int (4 hex digits, upper case) %[#]hhx - 1 byte int (2 hex digits, lower case) %[#]hhX - 1 byte int (2 hex digits, upper case) - optional # prefixes 0x or 0X %d - decimal int %c - char %s - string %@ - Internet address in ddd.ddd.ddd.ddd notation #ifdef PRINT_ENET_ADDRS %! - Ethernet address in xx:xx:xx:xx:xx:xx notation #endif Note: width specification ignored **************************************************************************/ int vsprintf(char *buf, const char *fmt, const int *dp) { char *p, *s; s = buf; for ( ; *fmt != '\0'; ++fmt) { if (*fmt != '%') { buf ? *s++ = *fmt : putchar(*fmt); continue; } /* skip width specs */ fmt++; while (*fmt >= '0' && *fmt <= '9') fmt++; if (*fmt == '.') fmt++; while (*fmt >= '0' && *fmt <= '9') fmt++; if (*fmt == 's') { for (p = (char *)*dp++; *p != '\0'; p++) buf ? *s++ = *p : putchar(*p); } else { /* Length of item is bounded */ char tmp[20], *q = tmp; int alt = 0; int shift = 28; if (*fmt == '#') { alt = 1; fmt++; } if (*fmt == 'h') { shift = 12; fmt++; } if (*fmt == 'h') { shift = 4; fmt++; } /* * Before each format q points to tmp buffer * After each format q points past end of item */ if ((*fmt | 0x20) == 'x') { /* With x86 gcc, sizeof(long) == sizeof(int) */ const long *lp = (const long *)dp; long h = *lp++; int ncase = (*fmt & 0x20); dp = (const int *)lp; if (alt) { *q++ = '0'; *q++ = 'X' | ncase; } for ( ; shift >= 0; shift -= 4) *q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase; } else if (*fmt == 'd') { int i = *dp++; char *r; if (i < 0) { *q++ = '-'; i = -i; } p = q; /* save beginning of digits */ do { *q++ = '0' + (i % 10); i /= 10; } while (i); /* reverse digits, stop in middle */ r = q; /* don't alter q */ while (--r > p) { i = *r; *r = *p; *p++ = i; } } else if (*fmt == '@') { unsigned char *r; union { long l; unsigned char c[4]; } u; const long *lp = (const long *)dp; u.l = *lp++; dp = (const int *)lp; for (r = &u.c[0]; r < &u.c[4]; ++r) q += sprintf(q, "%d.", *r); --q; } #ifdef PRINT_ENET_ADDRS else if (*fmt == '!') { char *r; p = (char *)*dp++; for (r = p + ETH_ALEN; p < r; ++p) q += sprintf(q, "%hhX:", *p); --q; } #endif /* PRINT_ENET_ADDRS */ else if (*fmt == 'c') *q++ = *dp++; else *q++ = *fmt; /* now output the saved string */ for (p = tmp; p < q; ++p) buf ? *s++ = *p : putchar(*p); } } if (buf) *s = '\0'; return (s - buf); } int sprintf(char *buf, const char *fmt, ...) { return vsprintf(buf, fmt, ((const int *)&fmt)+1); } int printf(const char *fmt, ...) { return vsprintf(0, fmt, ((const int *)&fmt)+1); } mknbi-1.4.4/printf.h0100644000175000001440000000022407604574513013001 0ustar kenusers#ifndef _PRINTF_H #define _PRINTF_H extern int printf(const char *fmt, ...); extern int vsprintf(char *buf, const char *fmt, const int *dp); #endif mknbi-1.4.4/stddef.h0100644000175000001440000000016207604573434012752 0ustar kenusers#ifndef _STDDEF_H #define _STDDEF_H typedef int size_t; #ifndef NULL #define NULL 0 #endif #endif /* _STDDEF_H */ mknbi-1.4.4/TruncFD.pm0100755000175000001440000000537710110035557013174 0ustar kenusers# Perl subroutine to shorten a floppy image by omitting trailing sectors # that are not in use # # AFAIK works on FAT12 and FAT16. Won't work on FAT32 # # 2003.04.28 R. Main. # Fixes for images with > 65535 sectors # # Placed under GNU Public License by Ken Yap, April 2000 package TruncFD; use strict; use IO::Seekable; use POSIX qw(ceil); use constant; use constant DEBUG => 0; sub truncfd ($) { my ($file) = @_; my ($nread, $buffer, $cylinders, $clusters, $fatsectors, $rootdirsectors, @fatents, $i, $lastclus, $clusstart, $lastsector); return -1 if (!defined($file) or !open(F, "$file")); binmode(F); $nread = read(F, $buffer, 512); return -1 if (!defined($nread) or $nread < 512); my ($dummy1, $bytepersect, $sectperclus, $resvsectors, $fats, $rootdirents, $sectors, $dummy2, $sectperfat, $sectpertrk, $heads, $hidsectors, $bigsectors, $dummy3, $fstype) = unpack('a11vCvCvvavvvVVa18a5', $buffer); if ($sectors == 0) { $sectors = $bigsectors; } $cylinders = $sectors / ($sectpertrk * $heads); $fatsectors = $fats * $sectperfat; $rootdirsectors = POSIX::ceil(($rootdirents * 32) / $bytepersect); $clusstart = $resvsectors + $fatsectors + $rootdirsectors; $clusters = int (($sectors - $clusstart) / $sectperclus); return (-s $file) unless $clusters < 65525; $fstype = $clusters < 4085? 'FAT12':'FAT16' if ($fstype ne 'FAT12' && $fstype ne 'FAT16'); if (DEBUG) { print STDERR <