***************************************************************************** * This is *NOT* intended to be an OS loader. This is meant to be a fully * * featured Boot Manager that uses no more than one physical sector, while * * retaining a (colourful) front end that is user friendly. * * * * If you are using Linux, you will need to install LILO or CHOS in the * * boot sector of your linux partition. You can find out how to do that * * in the respective documentation. * ***************************************************************************** !MEMSIZE set $413 ;Size of memeory in Kbytes. !F1 set $3B ; !BARWIDTH set 40 ; !BARSTART set 140 ; !ELEMENT set 7 ;Size of printed element. !SCODE set NewLoc - Main ;Length of setup code [unshared]. !MCODE set CodeEnd - JmpLoc ;Length of main code [unshared]. !SMIXED set JmpLoc - _cls ;Length of shared code. !ECODE set CodeEnd - _new13 ; !RCODE set !SMIXED + !MCODE ; !NEWINT13 set _new13 - !SCODE ;Offset to new handle. !HW set !RCODE / 2 ;Half way through the code. ***************************************************************************** ORG $7C00 ;$7C00 ***************************************************************************** * Thanks to CHOS for some of the ideas re the drive swapping routine * ***************************************************************************** Main: xor.w di, di ;Clear DI. move.w di, ds ;Setup the Data Segment. move.w di, ss ;Setup the Stack Segment. move.w #$7C00, sp ;Set the Stack Pointer. inton *--* move.w #_new13, cx ;Offset to the int 13 handler. *--* bsr.w NewLoc+_get_loc ;Get top of memory. dc.b $26 ; [ es ] cmp.b #$0F, (di) ;Are we installed already? beq.s _skip_int13 ;Assume yes on match. *--* dec.w !MEMSIZE ;Allocate 1K for our handler. bsr.w NewLoc+_get_loc ;Get top of memory. *--* push.l $004C ;The old int 13. dc.b $26 ; [ es ] pop.l OldHandle ;Save it... push.w dx push.w cx ;Offset to the handler. pop.l $004C ;Install our new handler. add.b #!ECODE, cl ; _skip_int13: cld ;Set the direction. move.w #NewLoc, si ;Where we are reading from. repne:moves.b ;Move the data. *--* push.w dx ;Our new segment. push.w #!SMIXED ;Our new Offset. ***************************************************************************** NewLoc: ORG $0000 ;Our relocated code. ***************************************************************************** _cls: * move.b #15, ah ;Get the current video mode. * trap #$10 ;Call the BIOS. * eor.b ah, ah ;Set the video mode . * trap #$10 ;Call the BIOS. retf ;Jump to the new location. ************************************* _get_loc: move.w !MEMSIZE, dx ;Top of mem in 1K blocks. rol.w #6, dx ;Convert to segment. move.w dx, es ;Set our Extra(?) Segment. rts ***************************************************************************** * Our registers: * CS = [ New Segment ] * DS = [ New Segment ] * ES = [ New Segment ] * BP = !HW * SS = 0x0000 * SP = 0x7C00 * AX = 0x00xx * BX = [ New Segment ] * CX = 0x0000 ************************************************************************* * ++++ Setup the initial display screen ++++ * ************************************************************************* JmpLoc: intoff ; * move.w dx, ds ;Set our Data Segment. move.w dx, ss ;Set the stack segment. * move.w #$B800, bx ;Set up our screen segment. move.w bx, es ;Done. * move.b #$04, bh ;Set up the screen offset. move.w bx, sp ; ...and the stack pointer. * inton * move.w #!HW, bp ;You'll see... * move.b #5, cl ;Maximum count of options. lea BootData-!HW(bp), si ;List of strings to print. _show_lp: cmp.b ch, (si) ;Can we boot this one? bne.s _show_next ;If null no boot. * lea !ELEMENT(si), si bra.s _move_next _show_next: push.w si ;Save our string location. lea FKey-!HW(bp), si ;Display the function key. bsr PrintStr ;Print it. pop.w si ;Restore our string. bsr PrintStr ;Print it. _move_next: inc.b FVal-!HW(bp) ; dbra _show_lp * lea 156(bx), bx ; bsr PrintStr ;Print the default boot info. * bsr _get_default ; inc.w si ; bsr PrintStr ************************************************************************* * ++++ Update the status bar and wait for valid input ++++ * ************************************************************************* lea !BARSTART(bx), di ;Where to print. xor.b ah, ah ;Clear AH. trap #$1a ;Call the BIOS. move.w dx, Timer-!HW(bp) ;Save the initial value. pusha ; dc.b $B1 ;move # to CL Counter dc.b !BARWIDTH ;Save it for later. move.w #$07B0, ax ; rep:stos.w ; popa ; _z_nxt: inc.w Timer-!HW(bp) ;Next tick event. _z_lp: xor.b ah, ah ;Clear AH. trap #$1a ;Call the BIOS. cmp.w dx, Timer-!HW(bp) ;Do we need to print another character. blt.s _update_bar ;Yes... _scan_keyboard: move.b #1, ah ; trap #$16 ;Any key presses? jz.s _z_lp xor.b ah, ah ; trap #$16 ;Get the scancode. sub.b #!F1, ah ; bmi.s _z_lp ;Less than ? cmp.b #4, ah ; bgt.s _z_lp ;Greater then ? beq.s _next_disk ;Not equal to ? ***************************************** * Can still use my segment here :^) * ***************************************** _check_partition: move.b ah, dh ;Need to save ah from corruption. xchg.b dh, Default-!HW(bp) ; bsr _get_default ; xchg.b dh, Default-!HW(bp) ;Restore the default. cmp.b ch, (si) ;Valid Choice? bne.s _valid_partition bra.s _z_lp _update_bar: move.w #$04B1, ax ;The colour & character to print. stos.w dec.b Counter-!HW(bp) ; bne.s _z_nxt move.b Default-!HW(bp), dh ;Pre-Load Default choice. cmp.b ah, dh ;Check for next drive ah=4 from above. bne.s _valid_partition ;Not equal, then partition selected. ***************************************** * Need to set up the ES:BX buffer... * * Using Screen area for Buffer!!! * ***************************************** _next_disk: * move.w sp, bx ; ES = 0xB800 & SP = 0x7C00 * inc.b MapNew80-!HW(bp) ;Increment to the next drive. * bsr _read_boot ;Try and read the boot sector from it. * dec.b MapNew80-!HW(bp) ;Move back to our drive. * or.b al, al ;Read next disk OK? * bne.s _z_lp ;Not zero, no disk. ***************************************************************************** * ++++ We have valid input so messing up the registers is OK ++++ * ***************************************************************************** * Registers *after* _set_reg is executed. * CS = [ New Segment ] * DS = 0x0000 * ES = 0x0000 * BX = 0x7C00 * SS = [ New Segment ] * SP = 0x0400 ***************************************** _valid_disk: bsr.w _set_reg ;Clear the registers. * move.b #4, $7C00+!SCODE+Default ;Save the default. bsr _write_boot ;Save the bugger! inc.b MapNew80-!HW(bp) ;Increment to the next drive. bsr _read_boot ;Load the next boot sector. bra.s _jmp_off ***************************************************************************** * Partition number is in DH. _valid_partition: bsr.w _set_reg ;Set registers for this area of code. lea $1BE(bx), di ;Move to start of the partition table. move.w di, si ;Save it for later use. move.b #4, cl ;The count. _clr_nxt: move.b ch, (di) ;Clear the bootable flag. lea 16(di), di ;Move to the next entry. dbra _clr_nxt * * move.b dl, $7C00+!SCODE+Default ;Save it as default for next boot. move.b #16, al ;Size of a partition entry. mul.b dh ;Multiply by wanted partition. add.w ax, si ;Move to our required partition. move.b #$80, (si) ;Flag this partition as bootable. * bsr _write_boot ; * move.b #$02, ah ;Read. move.w 2(si), cx ;Get the Start Cylinder/Sector. move.b 1(si), dh ;Start Head Number. bsr.w _read_sector ; _jmp_off: push.w ds ; push.w bx ; push.w ds ; rts ***************************************************************************** _read_boot: move.b #$02, ah ;Read. bra.s _skip _write_boot: move.b #$03, ah ;Write. _skip: move.b #$01, cl ;Sector number. move.b cl, dh ; _read_sector: move.b #$01, al ;Read/Write one sector. move.b #$80, dl ;Head & Drive numbers. trap #$13 ;Call BIOS disk services. rts ***************************************************************************** _get_default: lea Default-!HW(bp), si ;Using [cached] memory. lods.w ; mul.b ah ; add.w ax, si ; rts ***************************************************************************** _set_reg: xor.w bx, bx ;Clear move.w bx, ds ;We want to work elsewhere. move.w bx, es ;For our ES:BX pointer to buffer. move.b #$7C, bh ;ditto. _rts: rts ***************************************************************************** * Modified 16/5/99 to save space. String now terminated by a character * * being less than 13 (carriage return). Fits nicely with the scheme. * ***************************************************************************** _print_lp: stos.w _print_next: lods.b _print_chk: cmp.b #13, al ;Return? bgt.s _print_lp blt.s _rts _new_line: lea 160(bx), bx ;Move down a line. move.w bx, di ;Set the Cursor. bra.s _print_next PrintStr: move.b -1(si), ah ; bra.s _print_next ***************************************************************************** * Data section * ***************************************************************************** Default dc.b !ELEMENT, $00 dc.b 07 FKey dc.b 13,"F" FVal dc.b "1> " dc.b $03 BootData dc.b "NT 4.0" dc.b $04 dc.b "Win 98" dc.b $05 dc.b "Win 95" dc.b $06 dc.b "Test " dc.b $07 dc.b "Next >>" dc.b 02 DefTxt dc.b "Boot: ",0 ***************************************************************************** * May not be the fastest code, but it works, and fits in the 446 bytes!! * * Anyway, if they are using microsoft, they won't notice... * * Will try to optimise it later. * ***************************************************************************** _drivecheck: dc.b $80,$FA,$80 ;Compare DL with 0x80 [Gema no compile]. bne.s _check_mapped ;If not equal, check mapped. dc.b $B2 MapNew80 dc.b $80 rts _check_mapped: cs:cmp.b MapNew80, dl ;Want the mapped drive? bne.s _check_done ;No, so continue regardless. move.b #$80, dl ;Give 'em the remapped one. _check_done: rts ************************************* _ret13: push bx pushf *--* cs:move.b Function, bh cmp.b #8, bh ;Get Current Drive Parameters [DL!=Drive] beq.s _call_old ;No Swap. cmp.b #15, bh ;Write Sector Buffer [DL!=Drive]. beq.s _call_old ;No Swap. *--* bsr.w _drivecheck ; move.w sp, bx ss:pop.w 8(bx) pop.w bx iret _new13: cs:move.b ah, Function ; bsr.w _drivecheck ; pushf ;Dummy flag save. push cs ;Return to address. push #_ret13 ;Our offset. ***************************************************************************** _call_old: dc.b $EA ;JMP xxxx:xxxx ***************************************************************************** CodeEnd ***************************************************************************** OldHandle ds.w 2 ;The old handler Timer ds.w 1 Function ds.b 1 ***************************************************************************** CodeEndDSS *****************************************************************************