Subject: RFC: start.S
To: None <current-users@NetBSD.ORG>
From: VaX#n8 <vax@linkdead.paranoia.com>
List: current-users
Date: 06/16/1996 20:43:30
Below I've included a new start.S that only does a stage1 boot (so far).
I have included an objdump so that you can see the discrepancy between
the opcodes and what the new gas creates.

It seems gas needs a bit of work on 16-bit code. :(

I'd appreciate comments, improvements, etc.  Be nice, it's my first
x86 assembler project.

I don't think it will run in it's current state.
I tried it a few edit-compile cycles ago and it crashed, probably
because of the irregular treatment of 16-bit regs.

/*	$NetBSD: start.S,v 1.12 1995/01/18 17:34:18 mycroft Exp $	*/

/* heavily edited by VaX#n8 (vax@linkdead.paranoia.com) 16 Jun 1996 */

/*
 * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
 *
 * Mach Operating System
 * Copyright (c) 1992, 1991 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */

/*
  Copyright 1988, 1989, 1990, 1991, 1992 
   by Intel Corporation, Santa Clara, California.

                All Rights Reserved

Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appears in all
copies and that both the copyright notice and this permission notice
appear in supporting documentation, and that the name of Intel
not be used in advertising or publicity pertaining to distribution
of the software without specific, written prior permission.

INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <machine/asm.h>

BOOTSEG		=	0x0100	/* boot2 will be loaded here (below 640K) */
BOOTSTACK	=	0xfffc	/* boot stack */
SIGNATURE	=	0xaa55	/* magic num at end of partition table */
LOADSZ		=	15	/* size of unix boot */
PARTSTART	=	0x1be	/* starting address of partition table */
NUMPART		=	4	/* number of partitions in partition table */
PARTSZ		=	16	/* each partition table entry is 16 bytes */
BSDPART		=	0xA5	/* value of boot_ind, means bsd partition */
BOOTABLE	=	0x80	/* value of boot_ind, means bootable part'n */
BOOT2		=	0x200	/* offset to boot2 from $BOOTSEG */
CHAR_S		=	'S'
CHAR_F		=	'F'
CHAR_H		=	'H'
CHAR_D		=	'D'
CHAR_L		=	'L'

	.file "start.S"
	.code16

	/* boot1 is automatically located at 0x0:7c00 by your BIOS int 0x19 */
ENTRY(boot1)
	/* set up %ss and %sp */
	movw	$BOOTSEG, %ax
	movw	%ax, %ss
	movw	$BOOTSTACK, %sp

	/* set up %es, (where we will load boot2 and possibly MBR to) */
	movw	%ax, %es

#ifdef SERIAL
	/* BIOS int 0x14 service 0x00 : initialize serial port */
	pushw	%dx
	movw	$0x00e3, %ax	/* init port, to 9600/N/1/8 */
	xorw	%dx, %dx	/* port (%dx=0) */
	int	$0x14
	popw	%dx
#endif

#ifdef	DEBUG
	movb	$CHAR_S, %al
	call	message
#endif

	/* bootstrap passes us drive number in %dl */
	pushw	%dx

	/* BIOS int 0x13 service 0x08 : get drive parameters */
	movb	$8, %ah
	int	$0x13
	jnc	worked

	/* call failed due to funky BIOS, assume CHS of 80:2:15 */
	movw	$0x500f, %cx
	/* max_head_num <- 1 */
	movb	$1, %dh

worked:
	/* get number of heads */
	xorb	%ah, %ah	/* %ah <- 0 */
	movb	%dh, %al	/* %al <- (max_head_num) */
	incw	%ax		/* %ax <- (number_of_heads) */
	movw	%ax, heads

	/* get number of cylinders */
	xorb	%ah, %ah	/* %ah <- 0 */
	movb	%cl, %al
	shlw	$2, %ax		/* %ah <- (max_cyl_num:8-9) */
	movb	%ch, %al	/* %al <- (max_cyl_num:0-7) */
	incw	%ax		/* %ax <- (number_of_cyls) */
	movw	%ax, cylinders

	/* get number of sectors */
	movb	%cl, %al
	andb	$0x3F, %al
	movb	%al, sectors

	/* test drive type (fd or hd) */
	popw	%dx
	cmpb	$0x80, %dl
	jae	hd

fd:     /* start reading at 0:0:1 */
#ifdef	DEBUG
	movb	$CHAR_F, %al
	call	message
#endif

	movw	$0x0001, %cx	/* cyl 0, sector 1 */
	xorb	%dh, %dh	/* head (%dh=0) */
	jmp	load

hd:	/* look at the partition table */
#ifdef	DEBUG
	movb	$CHAR_H, %al
	call	message
#endif
	/* see if the partition table entry is pointed to by %ds:%si */
	/* for compatibility with OS-BS and many other bootloaders */
	/* this enables us to boot from extended partitions or 2nd disk */

	/* a partition table entry: */
	/* byte	meaning */
	/* 0	active */
	/* 1-3	starting CHS */
	/* 4	system type id */

	/* prepare for a successful comparison: */
	/* TODO: shouldn't have to use 32-bit reg here */
	movb	1(%esi), %dh	/* starting head */
	movw	2(%esi), %cx	/* starting cyl/sector */
	movb	4(%esi), %al	/* system id / partition type */
	cmpb	$BSDPART, %al

	/* jump if we know where our partition is */
	je	load

	/* no; time to search the disk */

#ifdef	DEBUG
	movb	$CHAR_D, %al
	call	message
#endif

	/* BIOS int 0x13 service 0x02 : read from disk (see comment later) */
	movw	$0x0201, %ax	/* will read (%al=1) sector */
	xorw	%bx, %bx	/* to %es:%bx (where %bx=0) */
	movw	$0x0001, %cx	/* cyl=0, sector=1 */
	movb	%dh, %dh	/* head (%dh=0) */
	int	$0x13
	jc	read_error

	/* find the first BSD partition */
	movw	$PARTSTART, %bx
	movw	$NUMPART, %cx
again:
	movb    %es:4(%ebx), %al
	cmpb	$BSDPART, %al
	je	found
	addw	$PARTSZ, %bx
	loop	again
	/* could not find partition */
	/* TODO - search in extended partitions */
	movw	$enoboot, %si
	jmp	err_stop

found:
	/* TODO: fix this, should not need 32-bit reg */
	movb	%es:1(%ebx), %dh	/* head */
	movw	%es:2(%ebx), %cx	/* sect, cyl */

load:
#ifdef	DEBUG
	movb	$CHAR_L, %al
	call	message
#endif
	/* TODO: add one to the sector number (with carry) to */
	/* avoid loading "boot sector" (usually this program) */
	/* over again */

	/* BIOS int 0x13 service 0x02 : read sectors from disk */
	/* Call with %ah = 0x2 */
	/*           %al = number of sectors */
	/*           %ch = cylinder */
	/*           %cl = sector (bits 6-7 are high bits of cyl on hd) */
	/*           %dh = head */
	/*           %dl = drive (0x80 for hard disk, 0x0 for floppy disk) */
	/*           %es:%bx = segment:offset of buffer */
	/* Return    carry flag = clear if ok/set if error */
	/*           %al = num sectors transferred */
	/*           %ah = status */

	movw	$0x200 | LOADSZ, %ax	/* read $LOADSZ blocks */
	xorw	%bx, %bx		/* put it at BOOTSEG:0x00 */
	int	$0x13
	jc	read_error

	/* ljmp to the second stage boot loader (boot2). */
	/* After ljmp, %cs is BOOTSEG */

	ljmp	$BOOTSEG, $BOOT2

print_char:	/* write char in %al to console */
	/* %al = char to print */
	/* %ah = scratch (serial printchar retval) */

#ifndef SERIAL
	/* BIOS int 0x10 service 0x0e : video - teletype output */
	movb	$0x0e, %ah
	pushw	%bx
	movw	$0x001, %bx	/* page=%bh=0x00, forecolor=%bl=0x01 */
	int	$0x10
	popw	%bx
#else	/* SERIAL */
	/* BIOS int 0x14 service 0x01 : serial - write char to port */
	movb	$0x01, %ah
	pushw	%dx
	movw	$0x00, %dx	/* port=%dx=0x00 */
	int	$0x14
	popw	%dx
#endif	/* SERIAL */
	ret

read_error:	/* create "read error" message and stop */
	movw	$eread, %si
	/* fall through: */
err_stop:	/* print a message in %ds:%si and stop */
	call	message
	jmp	stop

message:	/* write the error message in %ds:%si to console */
	/* %ds:%si = string to print */
	/* %al = scratch */
	/* %ah = scratch (serial char retval) */

	cld
#ifndef SERIAL
	pushw	%bx		/* save %bx */
#else	/* SERIAL */
	pushw	%dx
#endif 	/* SERIAL */

nextb:
	lodsb			/* load a byte into %al */
	testb	%al, %al	/* test for null terminator byte */
	jz	done		/* if null, we're done */
#ifndef SERIAL
	/* BIOS int 0x10 service 0x0e : video - teletype output */
	movb	$0x0e, %ah
	movw	$0x001, %bx	/* page=%bh=0x00, forecolor=%bl=0x01 */
	int	$0x10
#else	/* SERIAL */
	/* BIOS int 0x14 service 0x01 : serial - write char to port */
	movb	$0x01, %ah
	movw	$0x00, %dx	/* port=%dx=0x00 */
	int	$0x14
#endif	/* SERIAL */
	jmp	nextb

done:
#ifndef SERIAL
	popw	%bx		/* restore %bx */
#else	/* SERIAL */
	popw	%dx		/* restore %dx */
#endif 	/* SERIAL */
	ret

stop:	/* halt the machine */
	cli
	hlt

eread:		ASMSTR	"Read error\r\n"
enoboot:	ASMSTR	"No bootable partition\r\n"
/* scratch space */
sectors:	.byte	0
heads:		.word	0
cylinders:	.word	0
endofcode:
	/* throw in a partition in case we are block0 as well */
	/* flag, head, sec, cyl, typ, ehead, esect, ecyl, start, len */
	. = _C_LABEL(boot1) + PARTSTART
	.byte	0x0,0,0,0,0,0,0,0
	.long	0,0
	.byte	0x0,0,0,0,0,0,0,0
	.long	0,0
	.byte	0x0,0,0,0,0,0,0,0
	.long	0,0
	.byte	BOOTABLE,0,1,0,BSDPART,255,255,255
	.long	0,50000
	/* the last 2 bytes in the sector 0 contain the signature */
	. = _C_LABEL(boot1) + 0x1fe
	.short	SIGNATURE
	. = _C_LABEL(boot1) + BOOT2

(compiled with -DDEBUG)

boot.sym:     file format a.out-mach3

Disassembly of section .text:
00000000 <_boot1-7c00> movl   $0xd08e0100,%eax
00000005 <_boot1-7bfb> movl   $0xc08efffc,%esp
0000000a <_boot1-7bf6> movb   $0x53,%al
0000000c <_boot1-7bf4> call   000000e2 <BSDPART+3d>
00000012 <_boot1-7bee> pushl  %edx
00000013 <_boot1-7bed> movb   $0x8,%ah
00000015 <_boot1-7beb> int    $0x13
00000017 <_boot1-7be9> jae    0000001f <PARTSZ+f>
0000001a <_boot1-7be6> movl   $0x1b6500f,%ecx
0000001f <_boot1-7be1> xorb   %ah,%ah
00000021 <_boot1-7bdf> movb   %dh,%al
00000023 <_boot1-7bdd> incl   %eax
00000024 <_boot1-7bdc> addr16 movl %eax,0x7d1f
00000028 <_boot1-7bd8> addb   %al,(%eax)
0000002a <_boot1-7bd6> xorb   %ah,%ah
0000002c <_boot1-7bd4> movb   %cl,%al
0000002e <_boot1-7bd2> shll   $0x2,%eax
00000031 <_boot1-7bcf> movb   %ch,%al
00000033 <_boot1-7bcd> incl   %eax
00000034 <_boot1-7bcc> addr16 movl %eax,0x7d21
00000038 <_boot1-7bc8> addb   %al,(%eax)
0000003a <_boot1-7bc6> movb   %cl,%al
0000003c <_boot1-7bc4> andb   $0x3f,%al
0000003e <_boot1-7bc2> addr16 movb %al,0x7d1e
00000045 <_boot1-7bbb> popl   %edx
00000046 <_boot1-7bba> cmpb   $0x80,%dl
00000049 <_boot1-7bb7> jae    0000005c <CHAR_S+9>
0000004c <_boot1-7bb4> movb   $0x46,%al
0000004e <_boot1-7bb2> call   000000e2 <BSDPART+3d>
00000054 <_boot1-7bac> movl   $0xf6300001,%ecx
00000059 <_boot1-7ba7> jmp    000000b1 <BSDPART+c>
0000005c <_boot1-7ba4> movb   $0x48,%al
0000005e <_boot1-7ba2> call   000000e2 <BSDPART+3d>
00000064 <_boot1-7b9c> addr16 movb 0x1(%esi),%dh
00000068 <_boot1-7b98> addr16 movl 0x2(%esi),%ecx
0000006c <_boot1-7b94> addr16 movb 0x4(%esi),%al
00000070 <_boot1-7b90> cmpb   $0xa5,%al
00000072 <_boot1-7b8e> je     000000b1 <BSDPART+c>
00000075 <_boot1-7b8b> movb   $0x44,%al
00000077 <_boot1-7b89> call   000000e2 <BSDPART+3d>
0000007d <_boot1-7b83> movl   $0xdb310201,%eax
00000082 <_boot1-7b7e> movl   $0xf6880001,%ecx
00000087 <_boot1-7b79> int    $0x13
00000089 <_boot1-7b77> jb     000000d6 <BSDPART+31>
0000008c <_boot1-7b74> movl   $0x4b901be,%ebx
00000091 <_boot1-7b6f> addb   %ah,0x26(%edi)
00000094 <_boot1-7b6c> movb   0x4(%ebx),%al
00000097 <_boot1-7b69> cmpb   $0xa5,%al
00000099 <_boot1-7b67> je     000000a7 <BSDPART+2>
0000009c <_boot1-7b64> addl   $0x10,%ebx
0000009f <_boot1-7b61> loop   00000092 <BOOTABLE+12>
000000a1 <_boot1-7b5f> movl   $0xeb667d06,%esi
000000a6 <_boot1-7b5a> xorb   0x26(%edi),%ah
000000a9 <_boot1-7b57> movb   0x1(%ebx),%dh
000000ac <_boot1-7b54> addr16 movl %es:0x2(%ebx),%ecx
000000b1 <_boot1-7b4f> movb   $0x4c,%al
000000b3 <_boot1-7b4d> call   000000e2 <BSDPART+3d>
000000b9 <_boot1-7b47> movl   $0xdb31020f,%eax
000000be <_boot1-7b42> int    $0x13
000000c0 <_boot1-7b40> jb     000000d6 <BSDPART+31>
000000c3 <_boot1-7b3d> ljmp   0x100,0x200
000000cb <_boot1-7b35> movb   $0xe,%ah
000000cd <_boot1-7b33> pushl  %ebx
000000ce <_boot1-7b32> movl   $0x10cd0001,%ebx
000000d3 <_boot1-7b2d> popl   %ebx
000000d4 <_boot1-7b2c> ret    
000000d6 <_boot1-7b2a> movl   $0xe8667cf9,%esi
000000db <_boot1-7b25> addl   (%eax),%eax
000000dd <_boot1-7b23> addb   %al,(%eax)
000000df <_boot1-7b21> jmp    000000f7 <BSDPART+52>
000000e2 <_boot1-7b1e> cld    
000000e3 <_boot1-7b1d> pushl  %ebx
000000e4 <_boot1-7b1c> lodsb  %ds:(%esi),%al
000000e5 <_boot1-7b1b> testb  %al,%al
000000e7 <_boot1-7b19> je     000000f4 <BSDPART+4f>
000000ea <_boot1-7b16> movb   $0xe,%ah
000000ec <_boot1-7b14> movl   $0x10cd0001,%ebx
000000f1 <_boot1-7b0f> jmp    000000e4 <BSDPART+3f>
000000f4 <_boot1-7b0c> popl   %ebx
000000f5 <_boot1-7b0b> ret    
000000f7 <_boot1-7b09> cli    
000000f8 <_boot1-7b08> hlt    
000000f9 <_boot1-7b07> pushl  %edx
000000fa <_boot1-7b06> popa   
000000fc <_boot1-7b04> andb   %ah,%fs:0x72(%ebp)
00000100 <_boot1-7b00> jb     00000171 <BOOTSEG+71>
00000102 <_boot1-7afe> jb     00000111 <BOOTSEG+11>
00000104 <_boot1-7afc> orb    (%eax),%al
00000106 <_boot1-7afa> decl   %esi
00000107 <_boot1-7af9> outsl  %ds:(%esi),(%dx)
00000108 <_boot1-7af8> andb   %ah,0x6f(%edx)
0000010b <_boot1-7af5> outsl  %ds:(%esi),(%dx)
0000010c <_boot1-7af4> je     0000016f <BOOTSEG+6f>
0000010e <_boot1-7af2> boundl 0x20(%ebp,2),%ebp
00000112 <_boot1-7aee> jo     00000175 <BOOTSEG+75>
00000114 <_boot1-7aec> jb     0000018a <BOOTSEG+8a>
00000116 <_boot1-7aea> imull  $0xa0d6e,0x6f(%ecx,%ebp,2),%esi
...
000001ee <_boot1-7a12> addb   $0x1,(%eax)
000001f1 <_boot1-7a0f> addb   %ah,0xffffff(%ebp)
000001f7 <_boot1-7a09> addb   %al,(%eax)
000001f9 <_boot1-7a07> addb   %dl,0xffffffc3(%eax)
000001fc <_boot1-7a04> addb   %al,(%eax)
000001fe <_boot1-7a02> pushl  %ebp
000001ff <_boot1-7a01> Address 0x200 is out of bounds.