Add mbr/ - update --grub handling
authorMichael Prokop <mika@grml.org>
Mon, 2 Mar 2009 10:31:22 +0000 (11:31 +0100)
committerMichael Prokop <mika@grml.org>
Mon, 2 Mar 2009 10:31:22 +0000 (11:31 +0100)
debian/rules
grml2usb
mbr/Makefile [new file with mode: 0644]
mbr/mbr.S [new file with mode: 0644]

index 2b987f7..0606291 100755 (executable)
@@ -16,6 +16,7 @@ build-stamp:
 
        # Add here commands to compile the package.
        $(MAKE)
+       cd mbr && $(MAKE) && cd ..
        touch build-stamp
 
 clean:
@@ -25,13 +26,14 @@ clean:
 
        # Add here commands to clean up after the build process.
        $(MAKE) clean
+       cd mbr && $(MAKE) clean && cd ..
        dh_clean
 
 install: build
        dh_testdir
        dh_testroot
        dh_clean -k
-       dh_installdirs usr/share/grml2usb/lilo usr/share/grml2usb/grub
+       dh_installdirs usr/share/grml2usb/lilo usr/share/grml2usb/grub usr/share/grml2usb/mbr
 
        # Add here commands to install the package into debian/grml2usb.
        install -m 755 grml2usb               debian/grml2usb/usr/sbin/grml2usb
@@ -39,6 +41,7 @@ install: build
        install -m 755 lilo/lilo.static.amd64 debian/grml2usb//usr/share/grml2usb/lilo/lilo.static.amd64
        install -m 644 grub/splash.xpm.gz     debian/grml2usb/usr/share/grml2usb/grub/splash.xpm.gz
        install -m 644 grub/stage2_eltorito   debian/grml2usb/usr/share/grml2usb/grub/stage2_eltorito
+       install -m 644 mbr/mbrmgr             debian/grml2usb/usr/share/grml2usb/mbr/mbrmgr
 
 # Build architecture-dependent files here.
 binary-arch: build install
index 982623f..3909e2e 100755 (executable)
--- a/grml2usb
+++ b/grml2usb
@@ -223,6 +223,7 @@ def generate_main_grub2_config(grml_flavour, install_partition, bootoptions):
     local_datestamp = DATESTAMP
 
     return("""\
+## main grub2 configuration - generated by grml2usb [main config generated at: %(local_datestamp)s]
 set default=0
 set timeout=5
 
@@ -237,7 +238,6 @@ else
   set menu_color_highlight=white/blue
 fi
 
-## main grub2 configuration - generated by grml2usb [main config generated at: %(local_datestamp)s]
 menuentry "%(grml_flavour)s (default)" {
     set root=(hd0,%(install_partition)s)
     linux   /boot/release/%(grml_flavour)s/linux26 apm=power-off lang=us vga=791 quiet boot=live nomce module=%(grml_flavour)s %(bootoptions)s
@@ -363,12 +363,14 @@ splashimage=/boot/grub/splash.xpm.gz
 foreground  = 000000
 background  = FFCC33
 
+# root=(hd0,%(install_partition)s)
+
 # define entries:
 title %(grml_flavour)s  - Default boot (using 1024x768 framebuffer)
 kernel /boot/release/%(grml_flavour)s/linux26 apm=power-off lang=us vga=791 quiet boot=live nomce module=%(grml_flavour)s
 initrd /boot/release/%(grml_flavour)s/initrd.gz
 
-""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions} )
+""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
 def generate_isolinux_splash(grml_flavour):
@@ -508,7 +510,7 @@ def install_grub(device):
         try:
             mount(device, device_mountpoint, "")
             logging.debug("grub-install --root-directory=%s %s", device_mountpoint, device)
-            proc = subprocess.Popen(["grub-install", "--root-directory=%s" % device_mountpoint, device])
+            proc = subprocess.Popen(["grub-install", "--root-directory=%s" % device_mountpoint, device], stdout=file(os.devnull, "r+"))
             proc.wait()
             if proc.returncode != 0:
                 raise Exception("error executing grub-install")
@@ -567,13 +569,6 @@ def install_bootloader(device):
 def install_lilo_mbr(lilo, device):
     """TODO"""
 
-    # TODO: check out the *real* difference between:
-    # * mbr-install /dev/ice
-    # * lilo -S /dev/null -M /dev/ice ext && lilo -S /dev/null -A /dev/ice 1
-    # * cat /usr/lib/syslinux/mbr.bin > /dev/ice
-    # * syslinux -sf /dev/iceX
-    # * ...?
-
     # to support -A for extended partitions:
     logging.info("Installing MBR")
     logging.debug("%s -S /dev/null -M %s ext" % (lilo, device))
@@ -607,6 +602,76 @@ def install_syslinux_mbr(device):
         logging.critical("Execution failed:", error)
 
 
+def InstallMBR(mbrtemplate, device, partition, ismirbsdmbr=True):
+    """Installs an MBR to a device.
+
+    Retrieve the partition table from "device", install an MBR from
+    the "mbrtemplate" file, set the "partition" (0..3) active, and
+    install the result back to "device".
+
+    "device" may be the name of a file assumed to be a hard disc
+    (or USB stick) image, or something like "/dev/sdb". "partition"
+    must be a number between 0 and 3, inclusive. "mbrtemplate" must
+    be a valid MBR file of at least 440 (439 if ismirbsdmbr) bytes.
+
+    If "ismirbsdmbr", the partitions' active flags are not changed.
+    Instead, the MBR's default value is set accordingly.
+    """
+
+    if (partition < 0) or (partition > 3):
+        raise ValueError("partition must be between 0 and 3")
+
+    if ismirbsdmbr:
+        nmbrbytes = 439
+    else:
+        nmbrbytes = 440
+
+    tmpf = tempfile.NamedTemporaryFile()
+
+    logging.debug("executing: dd if='%s' of='%s' bs=512 count=1" % (device, tmpf.name))
+    proc = subprocess.Popen(["dd", "if=%s" % device, "of=%s" % tmpf.name, "bs=512", "count=1"], stderr=file(os.devnull, "r+"))
+    proc.wait()
+    if proc.returncode != 0:
+        raise Exception("error executing dd (first run)")
+    # os.system("dd if='%s' of='%s' bs=512 count=1" % (device, tmpf.name))
+
+    logging.debug("executing: dd if=%s of=%s bs=%s count=1 conv=notrunc" % (mbrtemplate, tmpf.name, nmbrbytes))
+    proc = subprocess.Popen(["dd", "if=%s" % mbrtemplate, "of=%s" % tmpf.name, "bs=%s" % nmbrbytes, "count=1", "conv=notrunc"], stderr=file(os.devnull, "r+"))
+    proc.wait()
+    if proc.returncode != 0:
+        raise Exception("error executing dd (second run)")
+    # os.system("dd if='%s' of='%s' bs=%d count=1 conv=notrunc" % (mbrtemplate, tmpf.name, nmbrbytes))
+
+    mbrcode = tmpf.file.read(512)
+    if len(mbrcode) < 512:
+        raise EOFError("MBR size (%d) < 512" % len(mbrcode))
+
+    if ismirbsdmbr:
+        mbrcode = mbrcode[0:439] + chr(partition) + \
+          mbrcode[440:510] + "\x55\xAA"
+    else:
+        actives = ["\x00", "\x00", "\x00", "\x00"]
+        actives[partition] = "\x80"
+        mbrcode = mbrcode[0:446] + actives[0] + \
+          mbrcode[447:462] + actives[1] + \
+          mbrcode[463:478] + actives[2] + \
+          mbrcode[479:494] + actives[3] + \
+          mbrcode[495:510] + "\x55\xAA"
+
+    tmpf.file.seek(0)
+    tmpf.file.truncate()
+    tmpf.file.write(mbrcode)
+    tmpf.file.close()
+
+    #os.system("dd if='%s' of='%s' bs=512 count=1 conv=notrunc" % (tmpf.name, device))
+    logging.debug("executing: dd if='%s' of='%s' bs=512 count=1 conv=notrunc" % (tmpf.name, "/tmp/mbr"))
+    proc = subprocess.Popen(["dd", "if=%s" % tmpf.name, "of=%s" % "/tmp/mbr", "bs=512", "count=1", "conv=notrunc"], stderr=file(os.devnull, "r+"))
+    proc.wait()
+    if proc.returncode != 0:
+        raise Exception("error executing dd (third run)")
+    # os.system("dd if='%s' of='%s' bs=512 count=1 conv=notrunc" % (tmpf.name, "/tmp/mbr"))
+    del tmpf
+
 def install_mbr(device):
     """Install a default master boot record on given device
 
@@ -662,7 +727,7 @@ def mount(source, target, mount_options):
     @target: directory where the ISO should be mounted to
     @options: mount specific options"""
 
-    # notice: options.dryrun does not work here, as we have to
+    # note: options.dryrun does not work here, as we have to
     # locate files and identify the grml flavour
     logging.debug("mount %s %s %s" % (mount_options, source, target))
     proc = subprocess.Popen(["mount"] + list(mount_options) + [source, target])
@@ -729,7 +794,7 @@ def check_for_fat(partition):
 
         if udev_info.returncode == 2:
             raise CriticalException("Failed to read device %s"
-                                    "(wrong UID/permissions or device not present?)" % partition)
+                                    " (wrong UID/permissions or device not present?)" % partition)
 
         if filesystem != "vfat":
             raise CriticalException("Device %s does not contain a FAT16 partition." % partition)
@@ -921,7 +986,6 @@ def install_iso_files(grml_flavour, iso_mount, device, target):
     # * make sure grml_flavour, iso_mount, target are set when the function is called, otherwise raise exception
     # * provide alternative search_file() if file information is stored in a config.ini file?
     # * catch "install: .. No space left on device" & CO
-    # * abstract copy logic to make the code shorter and get rid of spaghettis ;)
 
     if options.dryrun:
         logging.info("Would copy files to %s", iso_mount)
@@ -938,7 +1002,7 @@ def install_iso_files(grml_flavour, iso_mount, device, target):
         copy_bootloader_files(iso_mount, target)
 
         if not options.dryrun:
-            handle_bootloader_config(grml_flavour, device, target) # FIXME
+            handle_bootloader_config(grml_flavour, device, target)
 
     # make sure we sync filesystems before returning
     proc = subprocess.Popen(["sync"])
@@ -978,9 +1042,8 @@ def identify_grml_flavour(mountpath):
 
     return grml_flavour
 
-
-def handle_bootloader_config(grml_flavour, device, target):
-    """TODO"""
+def handle_grub_config(grml_flavour, device, target):
+    """ TODO """
 
     logging.debug("Generating grub configuration")
     #with open("...", "w") as f:
@@ -994,11 +1057,10 @@ def handle_bootloader_config(grml_flavour, device, target):
         install_partition = device[-1:]
 
     # grub1 config
-    logging.debug("Creating grub1 configuration file")
-    grub_config_file = open(grub_target + 'menu.lst', 'w')
-    grub_config_file.write(generate_grub1_config(grml_flavour, install_partition, options.bootoptions))
-    grub_config_file.close()
-
+    #logging.debug("Creating grub1 configuration file")
+    #grub_config_file = open(grub_target + 'menu.lst', 'w')
+    #grub_config_file.write(generate_grub1_config(grml_flavour, install_partition, options.bootoptions))
+    #grub_config_file.close()
     # TODO => generate_main_grub1_config() && generate_flavour_specific_grub1_config()
 
     # grub2 config
@@ -1011,7 +1073,7 @@ def handle_bootloader_config(grml_flavour, device, target):
         main_identifier = re.compile(".*main config generated at: %s.*" % re.escape(str(DATESTAMP)))
         if not re.match(main_identifier, string):
             grub2_config_file = open(grub2_cfg, 'w')
-            logging.info("Notice: grml flavour %s is being installed as the default booting system." % grml_flavour)
+            logging.info("Note: grml flavour %s is being installed as the default booting system." % grml_flavour)
             grub2_config_file.write(generate_main_grub2_config(grml_flavour, install_partition, options.bootoptions))
             grub2_config_file.close()
     else:
@@ -1022,7 +1084,7 @@ def handle_bootloader_config(grml_flavour, device, target):
     grub_flavour_config = True
     if os.path.isfile(grub2_cfg):
         string = open(grub2_cfg).readlines()
-        logging.info("Notice: you can boot flavour %s using '%s' on the commandline." % (grml_flavour, grml_flavour))
+        logging.info("Note: you can boot flavour %s using '%s' on the commandline." % (grml_flavour, grml_flavour))
         flavour = re.compile("grml2usb for %s: %s" % (re.escape(grml_flavour), re.escape(str(DATESTAMP))))
         for line in string:
             if flavour.match(line):
@@ -1034,6 +1096,10 @@ def handle_bootloader_config(grml_flavour, device, target):
         grub2_config_file.close( )
 
 
+def handle_syslinux_config(grml_flavour, target):
+    """ TODO
+    """
+
     logging.info("Generating syslinux configuration")
     syslinux_target = target + '/boot/syslinux/'
     # should be present via  copy_bootloader_files(), but make sure it exits:
@@ -1046,7 +1112,7 @@ def handle_bootloader_config(grml_flavour, device, target):
         main_identifier = re.compile(".*main config generated at: %s.*" % re.escape(str(DATESTAMP)))
         if not re.match(main_identifier, string):
             syslinux_config_file = open(syslinux_cfg, 'w')
-            logging.info("Notice: grml flavour %s is being installed as the default booting system." % grml_flavour)
+            logging.info("Note: grml flavour %s is being installed as the default booting system." % grml_flavour)
             syslinux_config_file.write(generate_main_syslinux_config(grml_flavour, options.bootoptions))
             syslinux_config_file.close()
     else:
@@ -1059,7 +1125,7 @@ def handle_bootloader_config(grml_flavour, device, target):
     syslinux_flavour_config = True
     if os.path.isfile(syslinux_cfg):
         string = open(syslinux_cfg).readlines()
-        logging.info("Notice: you can boot flavour %s using '%s' on the commandline." % (grml_flavour, grml_flavour))
+        logging.info("Note: you can boot flavour %s using '%s' on the commandline." % (grml_flavour, grml_flavour))
         flavour = re.compile("grml2usb for %s: %s" % (re.escape(grml_flavour), re.escape(str(DATESTAMP))))
         for line in string:
             if flavour.match(line):
@@ -1076,6 +1142,15 @@ def handle_bootloader_config(grml_flavour, device, target):
     isolinux_splash.close( )
 
 
+def handle_bootloader_config(grml_flavour, device, target):
+    """TODO"""
+
+    if options.grub:
+        handle_grub_config(grml_flavour, device, target)
+    else:
+        handle_syslinux_config(grml_flavour, target)
+
+
 def handle_iso(iso, device):
     """Main logic for mounting ISOs and copying files.
 
@@ -1158,9 +1233,11 @@ def handle_mbr(device):
     if not options.skipmbr:
         if device[-1:].isdigit():
             mbr_device = re.match(r'(.*?)\d*$', device).group(1)
+            partition_number = int(device[-1:]) - 1
 
         try:
-            install_mbr(mbr_device)
+            # install_mbr(mbr_device)
+            InstallMBR('/usr/share/grml2usb/mbr/mbrmgr', mbr_device, partition_number, True)
         except IOError, error:
             logging.critical("Execution failed: %s", error)
             sys.exit(1)
@@ -1266,6 +1343,14 @@ def main():
     device = args[len(args) - 1]
     isos = args[0:len(args) - 1]
 
+    if device[-1:].isdigit():
+        if int(device[-1:]) > 4:
+            logging.critical("Fatal: installation on partition number >4 not supported. (As the BIOS won't support it.)")
+            sys.exit(1)
+    else:
+        logging.critical("Fatal: installation on raw device not supported. (As the BIOS won't support it.)")
+        sys.exit(1)
+
     # provide upgrade path
     handle_compat_warning(device)
 
diff --git a/mbr/Makefile b/mbr/Makefile
new file mode 100644 (file)
index 0000000..2531eb3
--- /dev/null
@@ -0,0 +1,9 @@
+all: mbrmgr
+
+clean:
+       rm -f mbrmgr mbrmgr.elf mbr.o
+
+mbrmgr:
+       gcc -D_ASM_SOURCE -DBOOTMANAGER -D__BOOT_VER=\"0AA6\" -c mbr.S
+       ld -nostdlib -Ttext 0x0600 -N -Bstatic -e _start -o mbrmgr.elf mbr.o
+       objcopy -O binary mbrmgr.elf mbrmgr
diff --git a/mbr/mbr.S b/mbr/mbr.S
new file mode 100644 (file)
index 0000000..fc0400b
--- /dev/null
+++ b/mbr/mbr.S
@@ -0,0 +1,292 @@
+/* $MirOS: src/sys/arch/i386/stand/mbr/mbr.S,v 1.12 2009/01/31 23:39:55 tg Exp $ */
+
+/*-
+ * Copyright (c) 2009
+ *     Thorsten Glaser <tg@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ *-
+ * Compile commands:
+ *     $ gcc -D_ASM_SOURCE -DBOOTMANAGER -D__BOOT_VER=\"0AA6\" -c mbr.S
+ *     $ ld -nostdlib -Ttext 0x0600 -N -Bstatic -e _start -o mbrmgr.elf mbr.o
+ *     $ objcopy -O binary mbrmgr.elf mbrmgr
+ */
+
+       .intel_syntax noprefix
+       .code16
+       .text
+
+       .globl  _start
+_start:        xor     eax,eax
+       mov     ss,ax
+       mov     sp,offset Lstack
+       push    eax
+       popfd
+       mov     ds,ax
+       mov     es,ax
+       mov     si,offset Lbadr
+       mov     di,offset _start
+       mov     cx,0x0200       /* size of one sector */
+       push    si              /* load / return address */
+       push    ax
+       push    offset Lmain
+       rep     movsb
+       lret
+
+       /* entry message */
+Lemsg: .ascii  "Mir-"
+       .ascii  __BOOT_VER
+#ifdef BOOTMANAGER
+       /* Lem<nn> are patch points */
+       .ascii  ": 0="
+Lem00: .ascii  "00 1="
+Lem01: .ascii  "00 2="
+Lem02: .ascii  "00 3="
+Lem03: .ascii  "00 4=hd0 5=fd0  Enter=default (timeout)\r\n"
+#endif
+       .asciz  ">"
+
+       /* failure message */
+Lfmsg: .asciz  "bad magic\r\n"
+
+#if 1
+       /* okay boot message */
+Lbmsg: .asciz  " OK\r"
+#endif
+
+       /* output NUL-terminated string from ds:si */
+Lotxt0:        mov     ah,0x0E
+       mov     bx,7
+       int     0x10
+Lotxt: lodsb
+       or      al,al
+       jnz     Lotxt0
+       ret
+
+Lmain: sti
+#ifdef BOOTMANAGER
+       /* patch the partition type values into the message */
+       mov     di,offset Lem00
+       mov     al,ds:[Lptab + 0x04]
+       call    LpBY
+       mov     di,offset Lem01
+       mov     al,ds:[Lptab + 0x14]
+       call    LpBY
+       mov     di,offset Lem02
+       mov     al,ds:[Lptab + 0x24]
+       call    LpBY
+       mov     di,offset Lem03
+       mov     al,ds:[Lptab + 0x34]
+       call    LpBY
+       mov     si,offset Lemsg
+       call    Lotxt
+#endif
+
+       /* fake invalid partition entry for MBR/FDD boot */
+       mov     di,offset Lptab + 0x40
+       xor     eax,eax
+       stosw
+       inc     ax
+       stosw
+       dec     ax
+       stosd
+       stosd
+
+       /* force bad magic if sector load fails */
+       mov     ds:[Lbmag],al
+
+#ifdef BOOTMANAGER
+#if 0 /* see above, eax is already zero here */
+       xor     ax,ax           /* read CMOS clock ticks since midnight */
+#endif
+       int     0x1A            /* 32-bit result in cx:dx */
+       mov     di,cx           /* save it in edi for later */
+       shl     edi,16
+       mov     di,dx
+       add     edi,183         /* 10 seconds, rounded up one tick */
+       Lptmo = . - 4           /* offset of the "183" above */
+
+       /* input loop with timeout */
+Lwkey: mov     ah,1
+       int     0x16            /* check if a key was pressed */
+       jnz     Lgkey           /* yeap */
+       /* delay loop */
+       xor     ax,ax
+       int     0x1A
+       shl     ecx,16
+       mov     cx,dx
+       or      al,al           /* past midnight? */
+       jz      Lsday           /* no */
+       add     ecx,1573040     /* should be 1572480, but according to RBIL… */
+Lsday: cmp     ecx,edi         /* time is over? */
+       mov     al,13
+       ja      Lfkey           /* yep, fake a return keypress */
+       jmp     Lwkey
+
+       /* input loop without timeout */
+Lgkey: mov     ah,1
+       int     0x16            /* check if a key was pressed */
+       jz      Lgkey
+       mov     ah,0
+       int     0x16
+#endif /* BOOTMANAGER */
+Lfkey: mov     bx,offset Lptab
+       mov     dl,0x80         /* drive to load from */
+#ifndef BOOTMANAGER
+       jmp     Lscan
+#else
+       sub     al,13
+       je      Lscan           /* CR / Return / Enter */
+       jb      Lgkey           /* invalid input */
+       sub     al,('0' - 13)
+       jb      Lgkey           /* invalid input */
+       cmp     al,5            /* floppy */
+       ja      Lgkey           /* invalid input */
+       jb      LdoHD           /* hard disc */
+       mov     dl,0            /* drive to load from */
+       dec     ax              /* 5 -> 4 */
+#endif
+LdoHD: shl     al,4            /* 0..4 where 4 is virtual partition */
+       add     bl,al           /* we boot this one */
+       jmp     Lboot
+
+       /* scan the partition table for an active partition */
+Lscan: mov     al,[dpart]      /* try hard-coded by fdisk(8) 'fdef' first */
+       cmp     al,3
+       jbe     LdoHD
+Lspar: cmp     byte ptr [bx],0x80
+       je      Lboot           /* found an active partition */
+       add     bl,0x10
+       cmp     bl,0xFE         /* BX = 0x07FE = Lptab + 0x40 */
+       jb      Lspar
+       /* boot the virtual partition #4 (MBR) */
+
+Lboot: /* try to boot, first LBA (we're on a HDD) then CHS */
+       mov     [bx],dl         /* drive (0x80 or 0x00) */
+       mov     si,offset Lpblk /* LBA parameter block */
+       mov     di,si
+       mov     ax,0x0010
+       stosw                   /* size of LBA parameter block */
+       mov     al,1
+       stosw                   /* number of sectors to load */
+       pop     ax
+       push    ax
+       push    bx
+       stosw                   /* load address offset */
+       xor     ax,ax
+       stosw                   /* load address segment */
+       mov     eax,[bx+8]
+       stosd                   /* LBA offset of start sector (low 32 bit) */
+       xor     ax,ax
+       stosw                   /* high 32 bit */
+       stosw                   /* high 32 bit */
+       mov     ah,0x42         /* LBA extended read */
+       call    Lload           /* try to boot that */
+       pop     si              /* edited partition table entry */
+       pop     bx              /* load offset (ES=CS=SS=DS=0000h) */
+       push    bx
+       push    si
+       mov     ax,0x0201       /* CHS read 0x01 sectors */
+       mov     cx,[si+2]       /* cylinder; sector number */
+       mov     dx,[si]         /* head; drive number */
+       call    Lload
+       mov     si,offset Lfmsg
+       call    Lotxt
+#if 0
+Lfail: jmp     Lfail
+#else
+       xor     ax,ax
+       int     0x16
+       ljmp    0xF000,0xFFF0
+#endif
+
+Lload: mov     bp,4            /* number of tries */
+Lldlp: pusha
+       int     0x13
+       popa
+       jc      Lldre           /* error, try again */
+       cmp     word ptr ds:[Lbmag],0xAA55
+       jne     Lldre           /* bad magic, try again */
+#if 0
+       mov     ax,0x0E0D       /* output a carriage return */
+       xor     bx,bx
+       int     0x10
+#else
+       mov     si,offset Lbmsg
+       call    Lotxt
+#endif
+       pop     si              /* Lload return address */
+       pop     si              /* partition table entry */
+       mov     dl,[si]
+       /* DS:SI point to partition table entry, DL is set */
+       cli                     /* be nice :) */
+       ret                     /* jump to 0000:7C00h */
+Lldre: pusha
+       xor     ax,ax           /* reset drive */
+       int     0x13
+       popa
+       dec     bp              /* another try left? */
+       jnz     Lldlp
+       ret
+
+#ifdef BOOTMANAGER
+LpBY:  mov     ah,al
+       shr     al,4
+       and     ah,0x0F
+       add     ax,0x3030
+       cmp     al,0x39
+       jbe     LpBY1
+       add     al,7
+LpBY1: cmp     ah,0x39
+       jbe     LpBY2
+       add     ah,7
+LpBY2: stosw
+       ret
+#endif
+
+       . = _start + 0x01B7
+       .globl  dpart
+       .size   dpart,1
+dpart: .byte   0xFF            /* default partition [0..3] or none */
+
+       . = _start + 0x01B8
+Lntid: .long   0               /* Microsoft® NT® volume identifier */
+Lpad1: .byte   0, 0
+
+       . = _start + 0x01BE
+       /* partition table */
+Lptab: .long   0, 0, 0, 0      /* partition entry #0 */
+       .long   0, 0, 0, 0      /* partition entry #1 */
+       .long   0, 0, 0, 0      /* partition entry #2 */
+       /* partition entry #3 + pre-installation hint */
+       .word   0, 0, 0, 0, 0
+       . = _start + 0x01F8
+       .size   Lhint,2
+#ifdef BOOTMANAGER
+Lhint: .word   (Lptmo - _start)
+#else
+Lhint: .word   0xFFFF
+#endif
+Lpad2: .word   0, 0
+
+       . = _start + 0x01FE
+Lpmag: .word   0xAA55          /* BIOS boot magic */
+
+       Lstack = 0x4000
+       Lpblk = 0x5000
+
+       Lbadr = 0x7C00
+       Lbmag = Lbadr + 0x01FE