Subject: Re: port-i386/19192: cannot delete unused partition from boot selector list
To: None <netbsd-bugs@netbsd.org>
From: David Laight <david@l8s.co.uk>
List: netbsd-bugs
Date: 11/28/2002 16:05:49
> >Synopsis: cannot delete unused partition from boot selector list
The fdisk.c from the following patch will fix it.
summary of changes:
- allow mbr_bootsel code to be loaded from a non-default location
- allow mbr_bootsel code to be updated without losing its config
- don't overwrite mbr_bootsel code with standard mbr code unless
explicitily requested
- allow mbr_bootsel menu name to be removed from unused partition
- let -B be specified with other options
- make displayed timeout value match that typed in
- use a timeout of -1 to imply 'indefinite timeout' (needs new mbr_bootsel.S)
- unset BFL_EXTINT13 if it is no longer needed
The mbr_bootsel.S changes:
- fix timeouts of > 30 minutes
- 0xffff => indefinite timeout
- auto-determine whether to do CHS or LBA reads (based on sector #)
- less terse error messages
- redisplay menu after error
- pass sector number read through to next boot stage.
- disk read retries removed (I don't think they are necessary)
possible bug:
- bios call to 'reset disk system' shouldbe called in error path.
David
Index: fdisk.c
===================================================================
RCS file: /cvsroot/basesrc/sbin/fdisk/fdisk.c,v
retrieving revision 1.57
diff -u -r1.57 fdisk.c
--- fdisk.c 2002/11/24 21:49:15 1.57
+++ fdisk.c 2002/11/28 15:47:06
@@ -386,8 +386,10 @@
if (sh_flag && (a_flag || i_flag || u_flag || f_flag || s_flag))
usage();
+#if 0
if (B_flag && (a_flag || i_flag || u_flag || f_flag || s_flag))
usage();
+#endif
if (partition == -1 && s_flag) {
warnx("-s flag requires a partition selected.");
@@ -633,14 +635,29 @@
init_sector0(int start, int dopart)
{
int i;
+ int copy_size = sizeof(mboot.bootinst);
#ifdef DEFAULT_BOOTCODE
- if (!bootsize)
+ if (!bootsize) {
+#ifdef __i386__
+ if (B_flag)
+ bootsize = read_boot(DEFAULT_BOOTSELCODE, bootcode,
+ sizeof bootcode);
+ else
+#endif
bootsize = read_boot(DEFAULT_BOOTCODE, bootcode,
sizeof bootcode);
+ }
#endif
+#ifdef __i386__
+ if (((struct mbr_bootsel *)&mboot.bootinst[MBR_BOOTSELOFF])->magic ==
+ MBR_MAGIC
+ && ((struct mbr_bootsel *)&bootcode[MBR_BOOTSELOFF])->magic ==
+ MBR_MAGIC)
+ copy_size = MBR_BOOTSELOFF;
+#endif
- memcpy(mboot.bootinst, bootcode, sizeof(mboot.bootinst));
+ memcpy(mboot.bootinst, bootcode, copy_size);
putshort(&mboot.signature, MBR_MAGIC);
if (dopart)
@@ -744,36 +761,41 @@
{
struct mbr_bootsel *mbs =
(struct mbr_bootsel *)&mboot.bootinst[MBR_BOOTSELOFF];
- int i, nused, firstpart = -1, item;
- char desc[PARTNAMESIZE + 2], *p;
- int timo, entry_changed = 0;
-
- for (i = nused = 0; i < NMBRPART; ++i) {
- if (mboot.parts[i].mbrp_typ != 0) {
- if (firstpart == -1)
- firstpart = i;
- nused++;
- }
- }
+ int i, item;
+ char *name, *p;
+ int tmo;
+
+ for (item = 0; item < NMBRPART; item++)
+ if (mboot.parts[item].mbrp_typ != 0)
+ break;
- if (nused == 0) {
+ if (item == NMBRPART) {
warnx("No used partitions found. Partition the disk first.");
return;
}
+ printf("\n");
+
if (mbs->magic != MBR_MAGIC) {
if (!yesno("Bootselector not yet installed. Install it now?")) {
warnx("Bootselector not installed.");
return;
}
- bootsize = read_boot(DEFAULT_BOOTSELCODE, bootcode,
- sizeof bootcode);
+ /* read default bootselect code unless we already have one */
+ if (!bootsize || ((struct mbr_bootsel *)&bootcode
+ [MBR_BOOTSELOFF])->magic != MBR_MAGIC)
+ bootsize = read_boot(DEFAULT_BOOTSELCODE, bootcode,
+ sizeof bootcode);
memcpy(mboot.bootinst, bootcode, sizeof(mboot.bootinst));
bootsel_modified = 1;
mbs->flags |= BFL_SELACTIVE;
} else {
+ /* If bootfile was specified with -c, copy it in */
+ if (bootsize && ((struct mbr_bootsel *)&bootcode
+ [MBR_BOOTSELOFF])->magic == MBR_MAGIC)
+ memcpy(mboot.bootinst, bootcode, MBR_BOOTSELOFF);
if (mbs->flags & BFL_SELACTIVE) {
- printf("The bootselector is installed and active.");
+ printf("The bootselector is installed and active.\n");
if (!yesno("Do you want to change its settings?")) {
if (yesno("Do you want to deactivate it?")) {
mbs->flags &= ~BFL_SELACTIVE;
@@ -793,71 +815,59 @@
}
}
- printf("\n\nPartition table:\n");
- for (i = 0; i < NMBRPART; i++) {
- printf("%d: ", i);
- print_part(i);
- }
-
- printf("\n\nCurrent boot selection menu option names:\n");
- for (i = 0; i < NMBRPART; i++) {
- if (mbs->nametab[i][0] != 0)
- printf("%d: %s\n", i, &mbs->nametab[i][0]);
- else
- printf("%d: <UNUSED>\n", i);
- }
- printf("\n");
-
- item = firstpart;
-
editentries:
- while (1) {
- decimal("Change which entry (-1 quits)?", &item);
+ for (;; item++) {
+ if (item < 0 || item > NMBRPART)
+ item = -1;
+ printf("\nCurrent boot selection menu option names:\n");
+ for (i = 0; i < NMBRPART; i++) {
+ const char *n = mbs->nametab[i];
+ const char *t = get_type(mboot.parts[i].mbrp_typ);
+ if (*n == 0)
+ n = "<UNUSED>";
+ printf("partition %d: %-*s (%s)\n",
+ i, PARTNAMESIZE, n, t);
+ }
+ printf("\n");
+
+ decimal("Change which partition (-1 quits)?", &item);
if (item == -1)
break;
if (item < 0 || item >= NMBRPART) {
- printf("Invalid entry number\n");
- item = -1;
- continue;
- }
- if (mboot.parts[item].mbrp_typ == 0) {
- printf("The partition entry is unused\n");
- item = -1;
+ printf("Invalid partition number\n");
+ item = -2;
continue;
}
- printf("Enter descriptions (max. 8 characters): ");
- rewind(stdin);
- if (!fgets(desc, PARTNAMESIZE + 1, stdin))
- errx(1, "EOF");
- fpurge(stdin);
- p = strchr(desc, '\n');
- if (p != NULL)
- *p = 0;
- strcpy(&mbs->nametab[item][0], desc);
- entry_changed = bootsel_modified = 1;
+ name = mbs->nametab[item];
- item++;
- }
-
- if (entry_changed)
- printf("Boot selection menu option names are now:\n");
-
- firstpart = -1;
- for (i = 0; i < NMBRPART; i++) {
- if (mbs->nametab[i][0] != 0) {
- firstpart = i;
- if (entry_changed)
- printf("%d: %s\n", i, &mbs->nametab[i][0]);
+ if (mboot.parts[item].mbrp_typ == 0) {
+ if (*name == 0) {
+ printf("The partition entry is unused\n");
+ continue;
+ }
+ printf("Removing name from unused partition\n");
+ memset(name, 0, PARTNAMESIZE + 1);
} else {
- if (entry_changed)
- printf("%d: <UNUSED>\n", i);
+ printf("Enter description (max. %d characters): ",
+ PARTNAMESIZE);
+ rewind(stdin);
+ if (!fgets(name, PARTNAMESIZE + 1, stdin))
+ errx(1, "EOF");
+ fpurge(stdin);
+ p = strchr(name, '\n');
+ if (p != NULL)
+ memset(p, 0, name + PARTNAMESIZE + 1 - p);
}
+
+ bootsel_modified = 1;
}
- if (entry_changed)
- printf("\n");
+
+ for (i = 0; i < NMBRPART; i++)
+ if (mbs->nametab[i][0] != 0)
+ break;
- if (firstpart == -1) {
+ if (i == NMBRPART) {
printf("All menu entries are now inactive.\n");
if (!yesno("Are you sure about this?"))
goto editentries;
@@ -873,11 +883,14 @@
bootsel_modified = 1;
/* The timeout value is in ticks, 18.2 Hz. Avoid using floats. */
- timo = ((1000 * mbs->timeo) / 18200);
+ /* Ticks are probably 64k/3600 - so our long timers are sligtly
+ out! newer bootcode always waits for 1 tick, so treats 0xffff
+ as wait forever. */
+ tmo = mbs->timeo == 0xffff ? -1 : (10 * mbs->timeo + 9) / 182;
do {
- decimal("Timeout value", &timo);
- } while (timo < 0 || timo > 3600);
- mbs->timeo = (u_int16_t)((timo * 18200) / 1000);
+ decimal("Timeout value (0 to 3600 seconds, -1 => never)", &tmo);
+ } while (tmo < -1 || tmo > 3600);
+ mbs->timeo = tmo == -1 ? 0xffff : (tmo * 182) / 10;
printf("Select the default boot option. Options are:\n\n");
for (i = 0; i < NMBRPART; i++) {
@@ -907,6 +920,8 @@
mbs->defkey = SCAN_F1 + item;
done:
+ /* scan active partitions to see if we need LBA reads */
+ mbs->flags &= ~BFL_EXTINT13;
for (i = 0; i < NMBRPART; i++) {
if (mboot.parts[i].mbrp_typ != 0 &&
mboot.parts[i].mbrp_start >=
Index: mbr_bootsel/mbr_bootsel.S
===================================================================
RCS file: /cvsroot/basesrc/sbin/fdisk/mbr_bootsel/mbr_bootsel.S,v
retrieving revision 1.6
diff -u -r1.6 mbr_bootsel.S
--- mbr_bootsel/mbr_bootsel.S 2002/09/09 03:01:26 1.6
+++ mbr_bootsel/mbr_bootsel.S 2002/11/28 15:47:09
@@ -81,6 +81,13 @@
* a 32-bit value (either data or addr) may be inserted in the generated
* code, or where we would need a prefix but can do without (saving some
* space).
+ *
+ * This code is optimised for space, bytes can still be extracted
+ * but it is getting harder!
+ * Writing it is hard work - you need to sort out which opcode
+ * bytes you want, then see whether gcc creates them or not.
+ * Having both the 286 and 386 programmers reference manuals helps!
+ * Fortunately there are only 450 bytes to play with!
*/
/*
@@ -106,7 +113,8 @@
#define SI_INDEX 4
#define DI_INDEX 5
-#define BP_INDEX 7
+#define BP_INDEX 6 /* only with disp8/16 */
+#define BX_INDEX 7
/*
@@ -134,19 +142,29 @@
.byte 0x8a ; .byte 0x40 | (reg << 3) | ireg ; .byte off
#define movw_iregoff_reg(ireg,off,reg) \
.byte 0x8b ; .byte 0x40 | (reg << 3) | ireg ; .byte off
+#define movb_reg_iregoff(reg,ireg,off) \
+ .byte 0x88 ; .byte 0x40 | (reg << 3) | ireg ; .byte off
+#define movw_reg_iregoff(reg,ireg,off) \
+ .byte 0x89 ; .byte 0x40 | (reg << 3) | ireg ; .byte off
+
+#define mulb_ireg0(ireg) \
+ .byte 0xf6 ; .byte (4 << 3) | ireg
#define movb_reg_mem(reg,mem) \
.byte 0x88 ; .byte 0x6 | (reg << 3) ; .word mem
#define movb_mem_reg(mem,reg) \
.byte 0x8a ; .byte 0x6 | (reg << 3) ; .word mem
+#define movb_imm_mem(imm,mem) \
+ .byte 0xc6 ; .byte 0x06 ; .word mem ; .byte imm
+#define movw_imm_mem(imm,mem) \
+ .byte 0xc7 ; .byte 0x06 ; .word mem ; .word imm
+
#define movl_imm_ireg0(imm,ireg) \
.byte 0x66 ; .byte 0xc7 ; .byte ireg ; .long imm
#define movl_imm_iregoff(imm,ireg,off) \
.byte 0x66 ; .byte 0xc7 ; .byte 0x40 | ireg ; .byte off ; .long imm
-#define cmp_imm_ax(imm) .byte 0x3d ; .word imm
-
#define cmpb_imm_ireg0(imm,reg) \
.byte 0x80 ; .byte 0x38 + reg ; .byte imm
@@ -159,11 +177,19 @@
#define cmpb_mem_reg(mem,reg) .byte 0x3a ; .byte 0x06 | (reg << 3) ; .word mem
#define cmpw_imm_reg(imm,reg) .byte 0x81 ; .byte 0xf8 + reg ; .word imm
+#define cmpw_iregoff_reg(ireg,off,reg) \
+ .byte 0x3b ; .byte 0x40 | (reg << 3) | ireg ; .byte off
+
+#define testb_imm_mem(imm,mem) \
+ .byte 0xf6 ; .byte 0x06 ; .word mem ; .byte imm
+
+#define cmp_imm_ax(imm) .byte 0x3d ; .word imm
#define and_imm_ax(imm) .byte 0x25 ; .word imm
#define BOOTADDR 0x7c00
+#define LOADADDR 0x0600 /* address were are linked to */
/*
* Each entry in the boot select table is a nul-terminated string
@@ -179,7 +205,8 @@
* or inactive. There may never be more because of space constraints.
*/
#define BFL_SELACTIVE 0x01
-#define BFL_EXTINT13 0x02
+#define BFL_EXTINT13 0x02 /* set by fdisk if LBA needed (deprecated) */
+#define BFL_READ_LBA 0x04 /* force LBA reads (in case geom mismatch) */
/*
* Scan values for the various keys we use, as returned by the BIOS
@@ -201,49 +228,51 @@
#define ERR_INVPART '1' /* Invalid partition table */
#define ERR_READ '2' /* Read error */
#define ERR_NOOS '3' /* Magic no. check failed for part. */
+#define ERR_KEY '?' /* unknown key press */
+#define ERR_PTN 'p' /* partition not defined */
.text
/*
* Move ourselves out of the way first.
+ * (to the address we are linked at - 0x600)
*/
ENTRY(start)
- data32
xorl %eax, %eax
movl %eax, %ss
- movl $BOOTADDR, %esp
+ movw_imm_reg(BOOTADDR, SP)
movl %eax, %es
movl %eax, %ds
- xorl %esi,%esi
movl %esp, %esi
movw_imm_reg(_C_LABEL(start),DI)
movw_imm_reg(0x100,CX)
rep
movsl
- jmpfar(0,1f)
+ jmpfar(0,1f) /* leap into copy of code */
+
/*
* Sanity check the drive number passed by the BIOS. Some BIOSs may not
* do this and pass garbage.
*/
1:
cmpb $MINDRV,%dl
- jl 2f
+ jb 2f
cmpb $MAXDRV,%dl
- jle 3f
+ jbe 3f
2:
- movb $0x80,%dl
+ movb $MINDRV,%dl /* garbage in, boot disk 0 */
3:
- movb_reg_mem(DL,drvno)
+ push %edx /* save drive number */
bootsel:
- movb_mem_al(flags)
- testb $BFL_SELACTIVE,%al
- jznear16(getactive)
+ testb_imm_mem( BFL_SELACTIVE, flags)
+ jz getactive
+
/*
* The bootselector is active. Walk through the selector (name) table,
* printing used entries.
*/
+bootsel_menu:
movw_imm_reg(nametab,DI)
movb $0x31,%al
- movb $4,%cl
1:
cmpb_imm_ireg0(0,DI_INDEX)
jz 2f
@@ -257,46 +286,42 @@
2:
incb %al
addl $TABENTRYSIZE,%edi
- loop 1b
+ cmpb $0x35,%al
+ jne 1b
/*
* Get the initial time value for the timeout comparison. It is returned
- * by int 1a in cx:dx. Make sure to grab the whole 32 bit value, otherwise
- * it'd wrap around every hour. Now it'll only do so every 24 hours. Boots
- * should happen infrequent enough that this isn't a problem.
+ * by int 1a in cx:dx. We do sums modulo 2^16 so it doesn't matter if
+ * the counter wraps (which it does every hour) - so we can safely
+ * ignore 'cx'.
*
* Loop around checking for a keypress until we have one, or timeout is
* reached.
*/
xorb %ah,%ah
int $0x1a
- data32
- shll $16,%ecx
- movl %edx,%edi
- data32
- orl %ecx,%edi
+ movl %edx,%edi /* start time to di */
3:
- movb $1,%ah
- int $0x16
+ movb $1,%ah /* think this just looks to */
+ int $0x16 /* see if a key has been pressed */
jnz 4f
xorb %ah,%ah
- int $0x1a
- data32
- shll $16,%ecx
- data32
- orl %ecx,%edx
- data32
+ int $0x1a /* current time to cx:dx */
subl %edi,%edx
movw_mem_ax(timeout)
- cmpl %eax,%edx
- jl 3b
- movb_mem_al(defkey)
- jmp default
+ cmpl %eax,%edx /* always wait for 1 tick... */
+ jbe 3b /* 0xffff means never timeout */
+ movb_mem_al(defkey) /* timedout - pick default key */
+ jmp check_key
4:
xorb %ah,%ah
- int $0x16
+ int $0x16 /* 'read key', code ah, ascii al */
movb %ah,%al
-default:
+
+/* We have a keycode, see what it means.
+ If we don't know we generate error '?' and go ask again
+*/
+check_key:
/*
* <enter> -> boot active partition.
*/
@@ -306,39 +331,28 @@
* F1-F4 -> boot partition 1-4
*/
subb $SCAN_F1,%al
- cmpb $9,%al
- jg 4b
cmpb $3,%al
- jle 5f
+ jbe check_good_ptn
+
/*
* F5-F10 -> boot disk 0-5. Check if the requested disk isn't above
* the number of disks actually in the system as stored in 0:0475 by
- * the BIOS. This is always sector 0, so never use int13 extensions.
+ * the BIOS.
+ * If we trust loc 475, we needn't check the upper bound on the keystroke
+ * This is always sector 0, so always read using chs
*/
subb $4,%al
cmpb_mem_reg(0x0475,AL)
- jge 4b
- movw_imm_reg(fakeent,SI)
+ jae inv_key
+ movw_imm_reg(chs_zero,SI) /* chs read sector zero info */
addb $0x80,%al
- movb %al,%dl
- jmp16(noext)
-5:
-/*
- * Check if the requested entry is actually active in the partition and
- * bootmenu table. If not, just do nothing.
- */
- movw_imm_reg(parttab,SI)
- and_imm_ax(0xff)
- movl %eax,%ebx
- shll $4,%eax
- add %eax,%esi
- cmpb_imm_iregoff(0,SI_INDEX,4)
- je 4b
- movw_imm_reg(nametab,DI)
- imul $TABENTRYSIZE,%ebx
- cmpb_imm_ireg0_bx(0,DI_INDEX)
- je 4b
- jmp boot
+ pop %edx /* dump saved drive # */
+ push %eax /* replace with new */
+ jmp read_chs
+
+inv_key:
+ movb $ERR_KEY,%al
+ jmp err_msg
/*
* Look for the (first) active partition
@@ -354,132 +368,238 @@
/*
* No active partition.
*/
-invpart:
movb $ERR_INVPART,%al
- jmp errhang
+
+/* Something went wrong,
+ output single byte error code,
+ kill timeout - and hence require user interaction
+ redisplay menu and wait for user key
+*/
+err_msg:
+ movb_al_mem( errcod );
+ movw_imm_reg(errtxt,SI);
+ call16(putasciz)
+ movw_imm_mem( 0xffff, timeout );
+ jmp16( bootsel_menu )
/*
+ * Check if the requested entry is actually active in the partition and
+ * bootmenu table. If not, just do nothing.
+ */
+check_good_ptn:
+ movw_imm_reg(parttab-0x10,SI)
+ movw_imm_reg(nametab-9,DI)
+1:
+ addl $0x10,%esi
+ addl $9,%edi
+ subb $1,%al
+ jnc 1b
+
+ movb_reg_iregoff(AL,SI_INDEX,4)
+ mulb_ireg0(DI_INDEX)
+ testl %eax,%eax
+ movb $ERR_PTN,%al /* no partition */
+ je err_msg
+
+/*
* Active partition pointed to by si.
* Read the first sector.
*
- * First determine whether we have int13-extensions, by calling
- * int 13, function 41. Check for the magic number returned,
- * and the disk packet capability.
+ * We can either do a CHS (Cylinder Head Sector) or an LBA (Logical
+ * Block Address) read. Always doing the LBA one
+ * would be nice - unfortunately not all systems support it.
+ * Also some may contain a separate (eg SCSI) bios that doesn't
+ * support it even when the main bios does.
+ *
+ * The safest thing seems to be to find out whether the sector we
+ * want is inside the CHS sector count. If it is we use CHS, if
+ * outside we use LBA.
+ *
+ * There isn't much point checking if LBA support is present! We
+ * only try to use it if it is necessary.
*/
boot:
- movb_mem_reg(drvno,DL)
-boot2:
+ data32
+ movw_iregoff_reg(SI_INDEX,8,BP) /* get sector # */
+
+ testb_imm_mem( BFL_READ_LBA, flags )
+ jnz read_lba /* fdisk forced LBA read */
+/* get maximum (bios) sector */
+ pop %edx /* collect saved drive... */
+ push %edx /* ...number to dl */
+ movb $8,%ah
+ int $0x13 /* chs info */
+
+/* We now have to extract the chs values, increment c and h, and
+ * multiply together - getting a 32 bit result (top 8 bits are 0).
+ * heads = dh + 1
+ * sector = cl & 0x3f
+ * cylinder = ((cl & 0xc0) << 2 | ch) + 1
+ * Note that if dl was 0xff (unusual cos some systems have the 'bug'
+ * I'm writing!) then we get 0, but 256 heads isn't a real geometry
+ * so LBA will almost certainly work!
+ */
+ incb %dh /* now 1..255 (or zero) */
+ movb %cl,%al
+ data32 /* we need eax[31:16] = 0 */
+ andl $0x3f,%eax /* ax now sectors 1..63 */
+ mulb %dh /* ax = heads * sectors */
+ data32
+ xchg %eax,%ecx /* 32bit count in ecx */
+ shrb $6,%al
+ xchgb %al,%ah /* 10 bit cyl in ax */
+ incl %eax /* cylinders 1..1024 */
+ data32
+ cwde /* extend ax into eax */
+ data32
+ mull %ecx /* sectors in eax */
+
+ data32
+ cmpl %ebp,%eax /* sector in CHS limit ? */
+ ja read_chs
+
+/* leave this code - it is slightly shorter than the above,
+ someday someone might want to re-instate it! */
+#if 0
movb_mem_al(flags)
- testb $BFL_EXTINT13,%al
- jz noext
+ testb $BFL_EXTINT13,%al /* fdisk enable LBA? */
+ jz read_chs
- push %esi
- push %edx
+/* First determine whether we have int13-extensions, by calling
+ * int 13, function 41. Check for the magic number returned,
+ * and the disk packet capability.
+ */
movw_imm_reg(0x55aa,BX)
movb $0x41, %ah
int $0x13
- pop %edx
- pop %esi
- jc noext
+ jc read_chs /* no int13 extensions */
cmpw_imm_reg(0xaa55,BX)
- jnz noext
+ jnz read_chs
testb $1, %cl
- jz noext
+ jz read_chs /* no LBA read */
+#endif
-/*
- * Modify the partition table entry to look like an int13-extension
- * parameter block, so we can feed it to the extended read call.
- * XXX this means that we can only use it once, we can't jump back
- * here if the read fails.
- */
- movl_imm_ireg0(0x10010,SI_INDEX)
- movl_imm_iregoff(BOOTADDR,SI_INDEX,4)
- movl_imm_iregoff(0,SI_INDEX,12)
- movb $5, %dh
-1:
- push %esi
- push %edx
+/* Get sector number from partition table and copy into preset
+ * int13-extension parameter block for LBA disk read.
+ */
+read_lba:
+ movw_imm_reg(lba_info,SI)
+ data32
+ movw_reg_iregoff(BP,SI_INDEX,8) /* sector # to ctl block */
movb $0x42, %ah
+ pop %edx /* recover drive # */
+ jmp do_int13
+
+err_msg1:
+ jmp err_msg /* too far for jumps below... */
+
+/*
+ * Sector below CHS limit
+ * Do a cylinder-head-sector read instead
+ */
+read_chs:
+ pop %edx /* recover drive # */
+ movb_iregoff_reg(SI_INDEX,1,DH) /* head */
+ movw_iregoff_reg(SI_INDEX,2,CX) /* ch=cyl, cl=sect */
+ movw_imm_reg(BOOTADDR,BX) /* es:bx is buffer */
+ movw_imm_reg(0x201,AX) /* command 2, 1 sector */
+do_int13:
+ push %edx /* save drive */
int $0x13
- pop %edx
- pop %esi
- jnc ok
- dec %dh
- jnz 1b
-rderr:
+
movb $ERR_READ,%al
-errhang:
- call16(putc)
-hang:
- sti
- jmp hang
+ jc err_msg1
+
/*
+ * Check signature for valid bootcode
+ */
+mbr_read_ok:
+ movw_mem_ax(BOOTADDR+0x1fe)
+ cmp_imm_ax(0xaa55)
+ movb $ERR_NOOS,%al
+ jnz err_msg1
+
+/* Just for fun we pass the sector number through to the next stage boot.
+ * It doesn't have to use it (indeed no other mbr code will generate) it,
+ * but it does let us have a netBSD pbr that can identify where it was
+ * read from! This lets us use this code to select between two
+ * NetBSD system on the same physical driver.
+ * (If we've read the mbr of a different disk, it gets a random number
+ * - but it wasn't expecting anything...)
+*/
+ data32
+ movl %ebp,%esi
+ pop %edx /* recover drive # */
+ jmp16(_C_LABEL(start) - LOADADDR + BOOTADDR) /* CS is zero */
+
+/*
* print a 0-terminated ASCII string. Address in si.
*/
putasciz:
- push %eax
+ pusha
+putasciz_1:
1:
lodsb
testb %al, %al
jz 2f
- call16(putc)
- jmp 1b
-2:
- pop %eax
- ret
-putc:
+
movb $0xe, %ah
movb $7, %bl
int $0x10
- ret
-/*
- * No int13-extensions available, try old the method to load the frirst
- * sector of the partition.
- */
-noext:
- movb_iregoff_reg(SI_INDEX,1,DH)
- movw_iregoff_reg(SI_INDEX,2,CX)
-load:
- movw_imm_reg(5,DI)
-1:
- movw_imm_reg(BOOTADDR,BX)
- movw_imm_reg(0x201,AX)
- push %edi
- push %edx
- int $0x13
- pop %edx
- pop %edi
- jnc ok
- dec %edi
- jnz 1b
- jmp rderr
+ jmp 1b
+2:
+ popa
+ ret
-/*
- * Check signature for valid bootcode
- */
-ok:
- movw_mem_ax(BOOTADDR+0x1fe)
- cmp_imm_ax(0xaa55)
- jz 1f
- movb $ERR_NOOS,%al
- jmp errhang
-1:
- jmpfar(0,BOOTADDR)
+#if 0
+/* This is useful for debugging - although you probably need to
+ * delete some code to fit it in!
+ * Doesn't really matter where SI points!
+ */
+dump_eax:
+ pusha /* saves bottom 16 bits only! */
+ movw_imm_reg(_C_LABEL(start),SI)
+ movl %esi,%edi
+ movw_imm_reg(8,CX);
+1: data32
+ roll $4,%eax
+ movl %eax,%ebx
+ andb $0x0f,%al
+ addb $0x30,%al /* 30..3f - clear AF */
+#if 1 /* 5 bytes to generate real hex... */
+ daa /* 30..39,40..45 */
+ addb $0xc0,%al /* f0..f9,00..05 */
+ adcb $0x40,%al /* 30..39,41..45 */
+#endif
+ stosb
+ movl %ebx,%eax
+ loop 1b
+ movw_imm_reg(0x20,AX) /* space + null */
+ stosl /* really stosw... */
+ jmp16(putasciz_1) /* save 2 bytes! */
+#endif
+errtxt: .ascii "Error " /* runs into newline... */
+errcod: .ascii "x"
newline:
.asciz "\r\n"
prefix:
.asciz "F1: "
-/*
- * Fake partition entry used to boot from other disks. First byte is
- * overloaded, it's also used as storage for the drive number. We're
- * not using that in the entry.
- */
-drvno:
-fakeent:
- .byte 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00
- .long 0x0000, 0x0001
+
+/* Control block for int-13 LBA read.
+ We need a xx,00,01,00 somewhere to load chs for sector zero,
+ by a complete fluke there is one here! */
+chs_zero:
+lba_info:
+ .long 0x10010
+ .word BOOTADDR /* offset in segment */
+ .word 0 /* segment */
+ .long 0x0000 /* sector # goes here... */
+ .long 0x0000
+
+/* Stuff from here on is overwritten by fdisk - the offset must
+ not change... */
. = _C_LABEL(start) + (0x1bc - NAMETABSIZE - 4)
/*
* Default action, as a keyvalue we'd normally read from the BIOS. This
@@ -491,36 +611,23 @@
.byte 0x01
/*
* Timeout value. 65536 ticks per hour, which is about 18.2 times per second.
+ * 0xffff means never timeout.
*/
timeout:
.word 0x00b6
/*
- * Space for name/select table and partition table. If DEBUG is defined,
- * use some values from one of my machines, for testing.
+ * Space for name/select table and partition table.
*/
nametab:
-#ifdef DEBUG
- .asciz "Windows "
- .asciz "NetBSD "
- .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-#else
.fill NAMETABSIZE,0x01,0x00
-#endif
+
. = _C_LABEL(start) + 0x1bc
ourmagic:
.byte 0x55, 0xaa
+
. = _C_LABEL(start) + 0x1be
-#ifdef DEBUG
parttab:
- .word 0x0100
- .word 0x0001, 0xde06, 0x1f3e, 0x003f, 0x0000, 0xd000, 0x0007, 0xde80
- .word 0x1f3f, 0x24a5, 0xe57e, 0xd03f, 0x0007, 0x1c80, 0x006f, 0x0000
- .word 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
- .word 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
-#else
-parttab:
.fill 0x40,0x01,0x00
-#endif
+
. = _C_LABEL(start) + 0x1fe
.byte 0x55, 0xaa
--
David Laight: david@l8s.co.uk