***************************************************************************** * 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 an (attractive) 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. !NEWINT13 set _new13-JmpLoc ;Offset to new handle. !F1 set $3B ; !BARWIDTH set 24 ; !ELEMENT set 8 ;Size of printed element. !TICK set 2 ; !SCODE set NewLoc - Main ;Length of setup code. !MCODE set CodeEnd - JmpLoc ;Length of the main code. !HW set !MCODE / 2 ;Half way through the code. ***************************************************************************** * The BIOS loads the boot sector at 0000:7C00. Any other boot routine * * expects to be loaded there as well (ourselves for example). * ***************************************************************************** ORG $7C00 ;$7C00 + Offset ***************************************************************************** * 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 #!HW, bp ;You'll see... move.w #$7C00, sp ;Set the Stack Pointer. inton *--* bsr.w _get_loc ;Get top of memory. dc.b $26 ; [ es ] cmp.w #$26E8, (di) ;Are we installed already? beq.s _skip_int13 ;Assume yes on match. *--* dec.w !MEMSIZE ;Allocate 1K for our handler. bsr.w _get_loc ;Get top of memory. *--* push.l $004C ;The old int 13. dc.b $26 ; [ es ] pop.l OldHandle ;Save it... push.w bx ;The new segment. push.w #!NEWINT13 ;Offset to the handler. pop.l $004C ;Install our new handler. _skip_int13: cld ;Set the direction. move.w #NewLoc, si ;Where we are reading from. move.w #!MCODE, cx ;How many bytes to move. repne:moves.b ;Move the data. *--* move.w bx, ds ;Set our Data Segment. push.w bx ;Our new segment. push.w ss ;Our new Offset. retf ;Jump to the new location. ************************************* * Save two bytes (size matters!) * ************************************* _get_loc: move.w !MEMSIZE, bx ;Top of mem in 1K blocks. rol.w #6, bx ;Convert to segment. move.w bx, es ;Set our Extra(?) Segment. rts ***************************************************************************** NewLoc: ORG $00 ;Our relocated code. ***************************************************************************** * Our important registers: * CS = [ New Segment ] * DS = [ New Segment ] * ES = [ New Segment ] * BP = !HW * SS = 0x0000 * SP = 0x7C00 ************************************************************************* * ++++ Setup the initial display screen ++++ * ************************************************************************* JmpLoc: bsr _cls * les ScreenStart-!HW(bp), di ;Load our es:di screen address. * lea BootData-!HW(bp), si ;List of strings to print. move.b #5, cl ;Maximum count of options. _show_lp: cmp.b #0, (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.b (si) ; **** Could be plus two *** bsr PrintStr ************************************************************************* * ++++ Update the status bar and wait for valid input ++++ * ************************************************************************* lea 156(bx), di ;Where to print. xor.b ah, ah ;Clear AH. trap #$1a ;Call the BIOS. move.w dx, Timer-!HW(bp) ;Do we need to print another character. pusha ; move.w #!BARWIDTH, cx ;Maximum characters to print. move.b cl, !HW-Counter(bp) ;Save it for later. move.w #$07B0, ax ; rep:stos.w ; popa ; _z_nxt: add.w #!TICK, Timer-!HW(bp) ;Set next update in ticks. _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, cl ;Need to save ah from corruption. xchg.b dl, Default-!HW(bp) ; bsr _get_default ; cmp.b #0, (si) ;Valid Choice? bne.s _valid_partition xchg.b dl, Default-!HW(bp) ;Restore the default. 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), cl ;Pre-Load Default choice. cmp.b #4, cl ;Check for next drive. 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 ++++ * ***************************************************************************** * CS = [ New Segment ] * DS = 0x0000 * ES = 0x0000 * BX = 0x7C00 * SS = 0x0000 * SP = 0x7C00 ***************************************** _valid_disk: bsr.w _set_reg ;Clear the registers. move.b #4, Default+!SCODE(bx) ;Save the default. bsr _write_boot ;Save the bugger! cs: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 DL. _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 #0, (di) ;Clear the bootable flag. lea 16(di), di ;Move to the next entry. dbra _clr_nxt * move.b dl, Default+!SCODE(bx) ;Save it as default for next boot. rol.w #4, ax ;Multiply by 16 for the correct offset. 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 sp ; push.w ss ; bsr _cls retf ; ***************************************************************************** _read_boot: move.b #$02, ah ;Read. bra.s _skip _write_boot: move.b #$03, ah ;Write. _skip: move.w #$0001, cx ;Track/Cyl & 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 di, di ;Clear move.w di, ds ;We want to work elsewhere. move.w di, es ;For our ES:BX pointer to buffer. move.w #$7C00, BX ;ditto. 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. * ***************************************************************************** PrintStr: lods.b move.b al, ah ;Set the colour. bra.s _print_lp _new_line: lea 160(bx), bx ;Move down a line. move.w bx, di ;Set the Cursor. _print_lp: lods.b ;Load the next character. cmp.b #13, al ;Return? beq.s _new_line stos.w bgt.s _print_lp _print_exit: rts ***************************************************************************** _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. rts ***************************************************************************** * Data section * ***************************************************************************** ScreenStart dc.w $0400, $B800 FKey dc.b 07,13," ",0 Default dc.b !ELEMENT, $00 BootData dc.b $05,"NT 4.0 " dc.b $00,"Windows" dc.b $06,"Windows" dc.b $00," " dc.b $00,"Next >>" DefTxt dc.b 02,13,"Default: ",0 MapNew80 dc.b $80 ;Where to map the original first drive ***************************************************************************** _new13: cmp.b #$80, dl ;Want the first drive? bne.s _check_mapped ;No, check if they want the new mapping. cs:move.b MapNew80, dl ;Give them the new drive. bra.s _call_old ;Call the old handler. _check_mapped: cs:cmp.b MapNew80, dl ;Want the mapped drive? bne.s _call_old ;No, so continue regardless. move.b #$80, dl ;Give 'em the remapped one. ***************************************************************************** _call_old: dc.b $EA ;JMP xxxx:xxxx ***************************************************************************** CodeEnd ***************************************************************************** OldHandle ds.w 2 ;The old handler Counter ds.w 1 Timer ds.w 1 ***************************************************************************** CodeEndDSS *****************************************************************************