diff --git a/sys/dev/slice/slice.h b/sys/dev/slice/slice.h index ca6dfe049aaf..26c9943951ad 100644 --- a/sys/dev/slice/slice.h +++ b/sys/dev/slice/slice.h @@ -1,207 +1,207 @@ /*- * Copyright (C) 1997,1998 Julian Elischer. All rights reserved. * julian@freebsd.org * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: slice.h,v 1.3 1998/06/07 19:40:32 dfr Exp $ + * $Id: slice.h,v 1.4 1998/07/13 08:22:55 julian Exp $ */ typedef struct slice_handler *sh_p; typedef struct slice *sl_p; struct slicelimits { u_int32_t blksize; /* IN BYTES */ u_int64_t slicesize; /* IN BYTES */ }; typedef struct slicelimits *slmt_p; /* * This struct is only used by the IDE geometry guessing hack in * the MBR and disklabel code, when talked to by the IDE driver with a VERY * OLD DISK */ struct ide_geom { u_int32_t secpertrack; /* set to 0 if geom not known */ u_int16_t trackpercyl; u_int32_t cyls; }; /* * The probehints are set by the lower handler, to give direction as to * what handler is probably required above. If a slice is repartitioned, * these may change e.g. mbr may set 165 meaning "FreeBSD slice" or 4 "DOS". * -type: a string for the type that should be used. * if it's a null string ("") then don't even try find a sub handler. * defined as NO_SUBPART * if it's a NULL pointer (NULL) then probe all known types. - * -typespecific: A pointer to SOMETHING that teh lower handler thinks + * -typespecific: A pointer to SOMETHING that the lower handler thinks * may be of interest to the higher hamdlers. The "something" is dependent * on the type of the lower handler so the upper handler must know of * this in advance. The type of this should be specified in an * include file associated with the lower type. This is probably rarely * needed. */ struct probehints { sh_p trial_handler; /* methods of handler being probed */ char *type; /* don't probe, just use this type */ void *typespecific; /* the lower layer specifies this */ }; #define NO_SUBPART "" /* * The common slice structure with data, methods and linkages. */ struct slice { /* Per slice data */ char *name; /* e.g. sd0 wd0s1, wd0s1a ?? */ struct probehints probeinfo; /* how we should probe this */ u_int32_t flags; /* this device open, etc. */ u_int16_t refs; /* active references, free if 1->0 */ u_int16_t opencount; /* actual count of opens if allowed */ struct slicelimits limits; /* limits on this slice */ sh_p handler_up; /* type methods etc. */ void *private_up; /* data for the slice type */ sh_p handler_down; /* type methods etc. */ void *private_down; /* data for the slice type */ /*------- fields for the slice device driver -------*/ LIST_ENTRY(slice) hash_list; /* next slice in this bucket */ u_int32_t minor; /* the key for finding us */ void *devfs_btoken; void *devfs_ctoken; }; /* bit definitions for the slice flags */ #define SLF_CLOSED 0x00000000 /* slice not open */ #define SLF_OPEN_BLK_RD 0x00000001 /* blk slice readable */ #define SLF_OPEN_BLK_WR 0x00000002 /* blk slice writeable */ #define SLF_OPEN_BLK (SLF_OPEN_BLK_RD|SLF_OPEN_BLK_WR) #define SLF_OPEN_CHR_RD 0x00000004 /* raw slice readable */ #define SLF_OPEN_CHR_WR 0x00000008 /* raw slice writeable */ #define SLF_OPEN_CHR (SLF_OPEN_CHR_RD|SLF_OPEN_CHR_WR) #define SLF_OPEN_DEV_RD (SLF_OPEN_CHR_RD|SLF_OPEN_BLK_RD) #define SLF_OPEN_DEV_WR (SLF_OPEN_CHR_WR|SLF_OPEN_BLK_WR) #define SLF_OPEN_DEV (SLF_OPEN_DEV_RD|SLF_OPEN_DEV_WR) #define SLF_OPEN_UP_RD 0x00000010 /* upper layer is readable */ #define SLF_OPEN_UP_WR 0x00000020 /* upper layer is writable */ #define SLF_OPEN_UP 0x00000030 /* upper layer is open */ #define SLF_OPEN_WR (SLF_OPEN_UP_WR|SLF_OPEN_DEV_WR) #define SLF_OPEN_RD (SLF_OPEN_UP_RD|SLF_OPEN_DEV_RD) #define SLF_OPEN_STATE (SLF_OPEN_WR|SLF_OPEN_RD) /* Mask open state */ #define SLF_INVALID 0x00000100 /* Everything aborts */ #define SLF_LOCKED 0x00000200 /* Hold off, It's busy */ #define SLF_WANTED 0x00000400 /* I held off, wake me up */ #define SLF_PROBING 0x00000800 /* Probe state machine active */ #define SLF_PROBE_SEL 0x00001000 /* Probe selecting */ #define SLF_DONT_ARGUE 0x00002000 /* an assign, not a probe */ #define SLF_WAIT_READ 0x00008000 /* waiting for a probe read */ #define SLF_WAIT_WRITE 0x0000C000 /* waiting for a probe read */ #define SLF_PROBE_STATE 0x0000C000 /* Present probe state */ /* * prototypes for slice methods */ typedef void sl_h_IO_req_t(void *private, struct buf * buf); typedef int sl_h_ioctl_t(void *private, u_long cmd, caddr_t data, int fflag, struct proc * p); typedef int sl_h_done_t(sl_p slice, struct buf *bp); typedef int sl_h_open_t(void *private, int flags, int mode, struct proc * p); typedef void sl_h_close_t(void *private, int flags, int mode, struct proc * p); typedef int sl_h_revoke_t(void *private); typedef int sl_h_claim_t(struct slice * slice); typedef int sl_h_verify_t(struct slice *slice); typedef int sl_h_upconfig_t(struct slice *slice, int cmd, caddr_t data, int fflag, struct proc *p); typedef int sl_h_dump_t(void *private, int32_t blkoff, int32_t blkcnt); struct slice_handler { char *name; int version;/* the version of this handler */ struct slice_handler *next; /* next registered type */ int refs; /* references to this type */ sl_h_done_t *done; /* return after async request */ sl_h_IO_req_t *IOreq; /* IO req downward (to device) */ sl_h_ioctl_t *ioctl; /* ioctl downward (to device) */ sl_h_open_t *open; /* downwards travelling open */ sl_h_close_t *close; /* downwards travelling close */ sl_h_revoke_t *revoke; /* revoke upwards (towards user ) */ sl_h_claim_t *claim; /* claim a new slice */ sl_h_verify_t *verify; /* verify that a slice as it was before */ sl_h_upconfig_t *upconf; /* config requests from slice below */ sl_h_dump_t *dump; /* dump the core */ }; /* * general routines that handlers need. */ int sl_make_slice(sh_p handler_down, void *private_down, struct slicelimits *limits, sl_p *slicepp, char *name); void sl_rmslice(sl_p slice); int sl_newtype(sh_p tp); sh_p sl_findtype(char *type); void slice_start_probe(sl_p slice); int slice_lock(sl_p slice); int slice_unlock(sl_p slice); int slice_request_block(struct slice *slice, int blkno); int slice_writeblock(struct slice * slice, int blkno, void (*iodone )(struct buf *), caddr_t data, int len); void slice_probe_next(sl_p slice); /* * Definitions for "SLICE" utilities. (handler or device acting on a slice). */ enum slc_who { SLW_ABOVE, SLW_DEVICE }; /* helps to know who's calling */ void sliceio(sl_p slice, struct buf * bp, enum slc_who who); int sliceopen(sl_p slice, int flags, int mode, struct proc * p, enum slc_who who); void sliceclose(sl_p slice, int flags, int mode, struct proc * p, enum slc_who who); void sl_unref(sl_p slice); void slice_add_device(sl_p slice); void slice_remove_device(sl_p slice); /* * The geometry guessing HACK functions */ int mbr_geom_hack(struct slice * slice, struct ide_geom *geom); int dkl_geom_hack(struct slice * slice, struct ide_geom *geom); /* * The routine to produce a dummy disklabel from a slice. * Lives in disklabel.c because that's where everyhting is in scope, * but is used in slice_device.c. XXX hack. */ int dkl_dummy_ioctl(struct slice *slice, u_long cmd, caddr_t addr, int flag, struct proc * p); /* * debugging */ #if 0 #define RR printf(__FUNCTION__ " called\n") #else #define RR /* nothing */ #endif diff --git a/sys/i386/boot/biosboot/start.S b/sys/i386/boot/biosboot/start.S index e4133913b6d1..3d27c5fe5f29 100644 --- a/sys/i386/boot/biosboot/start.S +++ b/sys/i386/boot/biosboot/start.S @@ -1,458 +1,458 @@ /* * 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. * * from: Mach, Revision 2.2 92/04/04 11:36:29 rpd - * $Id: start.S,v 1.10 1997/02/22 09:30:13 peter Exp $ + * $Id: start.S,v 1.11 1998/07/02 15:36:35 wpaul Exp $ */ /* 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 "asm.h" .file "start.S" SIGNATURE= 0xaa55 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 bootable partition */ BOOTABLE= 0x80 /* value of boot_ind, means bootable partition */ NAMEBLOCKMAGIC= 0xfadefeed /* value of magicnumebr for block2 */ /* * This DEBUGMSG(msg) macro may be useful for debugging. Its use is * restricted to this file since it only works in real mode. */ #define DEBUGMSG(msg) \ data32 ; \ mov $msg, %esi ; \ data32 ; \ call message .text ENTRY(boot1) /* * XXX I have encountered at least one machine (a no-name laptop * with an AMI WinBIOS) that will refuse to run the bootblock * unless this short jump and nop are here. I'm not certain, but * this may be a case of the BIOS performing some kind of simple * virus detection. */ jmp pacify_braindead_bios nop pacify_braindead_bios: /* * start (aka boot1) is loaded at 0x0:0x7c00 but we want 0x7c0:0 * ljmp to the next instruction to adjust %cs */ data32 ljmp $0x7c0, $start start: /* set up %ds */ mov %cs, %ax mov %ax, %ds /* set up %ss and %esp */ data32 mov $BOOTSEG, %eax mov %ax, %ss /* * make a little room on the stack for * us to save the default bootstring we might find.. * effectively, we push the bootstring. */ data32 mov $BOOTSTACK-64, %esp /* set up %es, (where we will load boot2 to) */ mov %ax, %es /* bootstrap passes us drive number in %dl */ cmpb $0x80, %dl data32 jae hd fd: /* * XXX some bootstraps don't pass the drive number in %dl. * This is a problem mainly when we are block 0 on a floppy. * Force drive 0 for floppies. * XXX %dl was assumed valid in the test that led here. */ mov $0x0, %dl /* reset the disk system */ movb $0x0, %ah int $0x13 data32 mov $0x0001, %ecx /* cyl 0, sector 1 */ movb $0, %dh /* head */ data32 jmp load hd: /**** load sector 0 into the BOOTSEG ****/ data32 mov $0x0201, %eax xor %ebx, %ebx /* %bx = 0 */ data32 mov $0x0001, %ecx data32 andl $0xff, %edx /*mov $0x0080, %edx*/ int $0x13 data32 jb read_error /* find the first 386BSD partition */ data32 mov $PARTSTART, %ebx data32 mov $NUMPART, %ecx again: addr32 movb %es:4(%ebx), %al cmpb $BSDPART, %al data32 je found data32 add $PARTSZ, %ebx data32 loop again data32 mov $enoboot, %esi data32 jmp err_stop /* * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory * Call with %ah = 0x2 * %al = number of sectors * %ch = cylinder * %cl = sector * %dh = head * %dl = drive (0x80 for hard disk, 0x0 for floppy disk) * %es:%bx = segment:offset of buffer * Return: * %al = 0x0 on success; err code on failure */ found: addr32 movb %es:1(%ebx), %dh /* head */ addr32 movl %es:2(%ebx), %ecx /*sect, cyl (+ 2 bytes junk in top word) */ load: #ifdef NAMEBLOCK /* * Load the second sector and see if it is a boot instruction block. * If it is then scan the contents for the first valid string and copy it to * the location of the default boot string.. then zero it out. * Finally write the block back to disk with the zero'd out entry.. * I hate writing at this stage but we need this to be persistant. * If the boot fails, then the next boot will get the next string. - * /etc/rc will regenerate a complete block2 iff teh boot succeeds. + * /etc/rc will regenerate a complete block2 iff the boot succeeds. * * Format of block 2 is: * [NAMEBLOCKMAGIC] <--0xdeafc0de * [nulls] * [bootstring]NULL <---e.g. 0:wd(0,a)/kernel.experimental * [bootstring]NULL <---e.g. 0:wd(0,a)/kernel.old * .... * [bootstring]NULL <---e.g. 0:wd(0,f)/kernel * FF FF FF */ where: /* * save things we might smash * (that are not smashed immedatly after us anyway.) */ data32 push %ecx /* preserve 'cyl,sector ' */ data32 push %edx /* * Load the second sector * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory * Call with %ah = 0x2 * %al = number of sectors * %ch = cylinder * %cl = sector * %dh = head * %dl = drive (0x80 for hard disk, 0x0 for floppy disk) * %es:%bx = segment:offset of buffer * Return: * %al = 0x0 on success; err code on failure */ data32 movl $0x0201, %eax /function 2 (read) 1 sector */ xor %ebx, %ebx /* %bx = 0 */ /* buffer address (ES:0) */ data32 movl $0x0002, %ecx /* sector 2, cylinder 0 */ data32 andl $0x00ff, %edx /* head 0, drive N */ int $0x13 data32 jb read_error /* * confirm that it is one for us */ data32 xorl %ebx, %ebx /* magic number at start of buffer */ data32 addr32 movl %es:(%ebx), %eax data32 cmpl $NAMEBLOCKMAGIC, %eax data32 jne notours /* not ours so return to caller */ /* * scan for a bootstring * Skip the magic number, and scan till we find a non-null, * or a -1 */ incl %ebx /* quicker and smaller */ incl %ebx incl %ebx scan: incl %ebx addr32 movb %es:(%ebx), %al /* load the next byte */ testb %al, %al /* and if it is null */ data32 /* keep scanning (past deleted entries) */ jz scan incb %al /* now look for -1 */ data32 jz notours /* if we reach the 0xFF then we have finished */ /* * save our settings.. we need them twice.. */ data32 push %ebx /* * copy it to the default string location * which is just above the stack for 64 bytes. */ data32 movl $BOOTSTACK-64, %ecx /* 64 bytes at the top of the stack */ nxtbyte: addr32 movb %es:(%ebx), %al /* get the next byte in */ addr32 movb %al, %es:(%ecx) /* and transfer it to the name buffer */ incl %ebx /* get on with the next byte */ incl %ecx /* get on with the next byte */ testb %al, %al /* if it was 0 then quit this */ data32 jnz nxtbyte /* and looop if more to do */ /* * restore the saved settings and * zero it out so next time we don't try it again */ data32 pop %ebx /* get back our starting location */ #ifdef NAMEBLOCK_WRITEBACK nxtbyte2: addr32 movb %es:(%ebx), %al /* get the byte */ addr32 movb $0, %es:(%ebx) /* zero it out */ data32 incl %ebx /* point to the next byte */ testb %al, %al /* check if we have finished.. */ data32 jne nxtbyte2 /* * Write the second sector back * Load the second sector * BIOS call "INT 0x13 Function 0x3" to write sectors from memory to disk * Call with %ah = 0x3 * %al = number of sectors * %ch = cylinder * %cl = sector * %dh = head * %dl = drive (0x80 for hard disk, 0x0 for floppy disk) * %es:%bx = segment:offset of buffer * Return: * %al = 0x0 on success; err code on failure */ data32 movl $0x0301, %eax /* write 1 sector */ xor %ebx, %ebx /* buffer is at offset 0 */ data32 movl $0x0002, %ecx /* block 2 */ data32 andl $0xff, %edx /* head 0 */ int $0x13 data32 jnb notours data32 mov $eread, %esi jmp err_stop #endif /* NAMEBLOCK_WRITEBACK */ /* * return to the main-line */ notours: data32 pop %edx data32 pop %ecx #endif movb $0x2, %ah /* function 2 */ movb $LOADSZ, %al /* number of blocks */ xor %ebx, %ebx /* %bx = 0, put it at 0 in the BOOTSEG */ int $0x13 data32 jb read_error /* * ljmp to the second stage boot loader (boot2). * After ljmp, %cs is BOOTSEG and boot1 (512 bytes) will be used * as an internal buffer "intbuf". */ data32 ljmp $BOOTSEG, $ EXT(boot2) /* * read_error */ read_error: data32 mov $eread, %esi err_stop: data32 call message data32 jmp stop /* * message: write the error message in %ds:%esi to console */ message: /* * Use BIOS "int 10H Function 0Eh" to write character in teletype mode * %ah = 0xe %al = character * %bh = page %bl = foreground color (graphics modes) */ data32 push %eax data32 push %ebx data32 mov $0x0001, %ebx cld nextb: lodsb /* load a byte into %al */ cmpb $0x0, %al data32 je done movb $0xe, %ah int $0x10 /* display a byte */ data32 jmp nextb done: data32 pop %ebx data32 pop %eax data32 ret stop: hlt data32 jmp stop /* halt doesnt actually halt forever */ /* error messages */ #ifdef DEBUG one: String "1-\0" two: String "2-\0" three: String "3-\0" four: String "4-\0" #endif DEBUG #ifdef NAMEBLOCK_WRITEBACK ewrite: String "Write error\r\n\0" #endif /* NAMEBLOCK_WRITEBACK */ eread: String "Read error\r\n\0" enoboot: String "No bootable partition\r\n\0" endofcode: /* * Dummy partition table in case we are block 0. The ending c/h/s values * of the non-null partition are almost arbitary. The length of this * partition is bogus for backwards compatibility and as a signature. * A real partition table shouldn't be as weird and broken as this one, * and the isa slice initialization routine interprets this table as * saying that the whole disk is used for FreeBSD. */ /* flag, head, sec, cyl, typ, ehead, esect, ecyl, start, len */ . = EXT(boot1) + PARTSTART strttbl: .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 */ . = EXT(boot1) + 0x1fe .value SIGNATURE ENTRY(disklabel) . = EXT(boot1) + 0x400 diff --git a/sys/netatalk/at_control.c b/sys/netatalk/at_control.c index a5afb78442ad..2138995d3b48 100644 --- a/sys/netatalk/at_control.c +++ b/sys/netatalk/at_control.c @@ -1,875 +1,875 @@ /* * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. */ #include #include #include #include #include #include #include #include #include #include #undef s_net #include #include #include #include struct at_ifaddr *at_ifaddr; static int aa_dorangeroute(struct ifaddr *ifa, u_int first, u_int last, int cmd); static int aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask); static int aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask); static int aa_dosingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask, int cmd, int flags); static int at_scrub( struct ifnet *ifp, struct at_ifaddr *aa ); static int at_ifinit( struct ifnet *ifp, struct at_ifaddr *aa, struct sockaddr_at *sat ); static int aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw); # define sateqaddr(a,b) ((a)->sat_len == (b)->sat_len && \ (a)->sat_family == (b)->sat_family && \ (a)->sat_addr.s_net == (b)->sat_addr.s_net && \ (a)->sat_addr.s_node == (b)->sat_addr.s_node ) int at_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) { struct ifreq *ifr = (struct ifreq *)data; struct sockaddr_at *sat; struct netrange *nr; struct at_aliasreq *ifra = (struct at_aliasreq *)data; struct at_ifaddr *aa0; struct at_ifaddr *aa = 0; struct ifaddr *ifa, *ifa0; /* * If we have an ifp, then find the matching at_ifaddr if it exists */ if ( ifp ) { for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { if ( aa->aa_ifp == ifp ) break; } } /* * In this first switch table we are basically getting ready for * the second one, by getting the atalk-specific things set up * so that they start to look more similar to other protocols etc. */ switch ( cmd ) { case SIOCAIFADDR: case SIOCDIFADDR: /* * If we have an appletalk sockaddr, scan forward of where * we are now on the at_ifaddr list to find one with a matching * address on this interface. * This may leave aa pointing to the first address on the * NEXT interface! */ if ( ifra->ifra_addr.sat_family == AF_APPLETALK ) { for ( ; aa; aa = aa->aa_next ) { if ( aa->aa_ifp == ifp && sateqaddr( &aa->aa_addr, &ifra->ifra_addr )) { break; } } } /* * If we a retrying to delete an addres but didn't find such, * then rewurn with an error */ if ( cmd == SIOCDIFADDR && aa == 0 ) { return( EADDRNOTAVAIL ); } /*FALLTHROUGH*/ case SIOCSIFADDR: /* * If we are not superuser, then we don't get to do these ops. */ if ( suser(p->p_ucred, &p->p_acflag) ) { return( EPERM ); } sat = satosat( &ifr->ifr_addr ); nr = (struct netrange *)sat->sat_zero; if ( nr->nr_phase == 1 ) { /* * Look for a phase 1 address on this interface. * This may leave aa pointing to the first address on the * NEXT interface! */ for ( ; aa; aa = aa->aa_next ) { if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { break; } } } else { /* default to phase 2 */ /* * Look for a phase 2 address on this interface. * This may leave aa pointing to the first address on the * NEXT interface! */ for ( ; aa; aa = aa->aa_next ) { if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { break; } } } if ( ifp == 0 ) panic( "at_control" ); /* * If we failed to find an existing at_ifaddr entry, then we * allocate a fresh one. */ if ( aa == (struct at_ifaddr *) 0 ) { aa0 = malloc(sizeof(struct at_ifaddr), M_IFADDR, M_WAITOK); bzero(aa0, sizeof(struct at_ifaddr)); if (( aa = at_ifaddr ) != NULL ) { /* * Don't let the loopback be first, since the first * address is the machine's default address for * binding. * If it is, stick ourself in front, otherwise * go to the back of the list. */ if ( at_ifaddr->aa_ifp->if_flags & IFF_LOOPBACK ) { aa = aa0; aa->aa_next = at_ifaddr; at_ifaddr = aa; } else { for ( ; aa->aa_next; aa = aa->aa_next ) ; aa->aa_next = aa0; } } else { at_ifaddr = aa0; } /* * Don't Add a reference for the aa itself! * I fell into this trap. IFAFREE tests for <=0 * not <= 1 like RTFREE */ /* aa->aa_ifa.ifa_refcnt++; DON'T DO THIS!! */ aa = aa0; /* * Find the end of the interface's addresses * and link our new one on the end */ ifa = (struct ifaddr *)aa; TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); /* * Add a reference for the linking into the ifp_if_addrlist. */ ifa->ifa_refcnt++; /* * As the at_ifaddr contains the actual sockaddrs, * and the ifaddr itself, link them al together correctly. */ ifa->ifa_addr = (struct sockaddr *)&aa->aa_addr; ifa->ifa_dstaddr = (struct sockaddr *)&aa->aa_addr; ifa->ifa_netmask = (struct sockaddr *)&aa->aa_netmask; /* * Set/clear the phase 2 bit. */ if ( nr->nr_phase == 1 ) { aa->aa_flags &= ~AFA_PHASE2; } else { aa->aa_flags |= AFA_PHASE2; } /* * and link it all together */ aa->aa_ifp = ifp; } else { /* * If we DID find one then we clobber any routes dependent on it.. */ at_scrub( ifp, aa ); } break; case SIOCGIFADDR : sat = satosat( &ifr->ifr_addr ); nr = (struct netrange *)sat->sat_zero; if ( nr->nr_phase == 1 ) { /* * If the request is specifying phase 1, then * only look at a phase one address */ for ( ; aa; aa = aa->aa_next ) { if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { break; } } } else { /* * default to phase 2 */ for ( ; aa; aa = aa->aa_next ) { if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { break; } } } if ( aa == (struct at_ifaddr *) 0 ) return( EADDRNOTAVAIL ); break; } /* * By the time this switch is run we should be able to assume that * the "aa" pointer is valid when needed. */ switch ( cmd ) { case SIOCGIFADDR: /* * copy the contents of the sockaddr blindly. */ sat = (struct sockaddr_at *)&ifr->ifr_addr; *sat = aa->aa_addr; /* * and do some cleanups */ ((struct netrange *)&sat->sat_zero)->nr_phase = (aa->aa_flags & AFA_PHASE2) ? 2 : 1; ((struct netrange *)&sat->sat_zero)->nr_firstnet = aa->aa_firstnet; ((struct netrange *)&sat->sat_zero)->nr_lastnet = aa->aa_lastnet; break; case SIOCSIFADDR: return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr )); case SIOCAIFADDR: if ( sateqaddr( &ifra->ifra_addr, &aa->aa_addr )) { return( 0 ); } return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr )); case SIOCDIFADDR: /* * scrub all routes.. didn't we just DO this? XXX yes, del it */ at_scrub( ifp, aa ); /* * remove the ifaddr from the interface */ ifa0 = (struct ifaddr *)aa; TAILQ_REMOVE(&ifp->if_addrhead, ifa0, ifa_link); /* * refs goes from 1->0 if no external refs. note.. * This will not free it ... looks for -1. */ IFAFREE(ifa0); /* * Now remove the at_ifaddr from the parallel structure * as well, or we'd be in deep trouble */ aa0 = aa; if ( aa0 == ( aa = at_ifaddr )) { at_ifaddr = aa->aa_next; } else { while ( aa->aa_next && ( aa->aa_next != aa0 )) { aa = aa->aa_next; } /* * if we found it, remove it, otherwise we screwed up. */ if ( aa->aa_next ) { aa->aa_next = aa0->aa_next; } else { panic( "at_control" ); } } /* * Now dump the memory we were using. * Decrement the reference count. * This should probably be the last reference * as the count will go from 0 to -1. * (unless there is still a route referencing this) */ IFAFREE(ifa0); break; default: if ( ifp == 0 || ifp->if_ioctl == 0 ) return( EOPNOTSUPP ); return( (*ifp->if_ioctl)( ifp, cmd, data )); } return( 0 ); } /* * Given an interface and an at_ifaddr (supposedly on that interface) * remove any routes that depend on this. * Why ifp is needed I'm not sure, * as aa->at_ifaddr.ifa_ifp should be the same. */ static int at_scrub( ifp, aa ) struct ifnet *ifp; struct at_ifaddr *aa; { int error; if ( aa->aa_flags & AFA_ROUTE ) { if (ifp->if_flags & IFF_LOOPBACK) { if (error = aa_delsingleroute(&aa->aa_ifa, &aa->aa_addr.sat_addr, &aa->aa_netmask.sat_addr)) { return( error ); } } else if (ifp->if_flags & IFF_POINTOPOINT) { if ((error = rtinit( &aa->aa_ifa, RTM_DELETE, RTF_HOST)) != 0) return( error ); } else if (ifp->if_flags & IFF_BROADCAST) { error = aa_dorangeroute(&aa->aa_ifa, ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_DELETE ); } aa->aa_ifa.ifa_flags &= ~IFA_ROUTE; aa->aa_flags &= ~AFA_ROUTE; } return( 0 ); } /* * given an at_ifaddr,a sockaddr_at and an ifp, * bang them all together at high speed and see what happens */ static int at_ifinit( ifp, aa, sat ) struct ifnet *ifp; struct at_ifaddr *aa; struct sockaddr_at *sat; { struct netrange nr, onr; struct sockaddr_at oldaddr; int s = splimp(), error = 0, i, j; int netinc, nodeinc, nnets; u_short net; /* * save the old addresses in the at_ifaddr just in case we need them. */ oldaddr = aa->aa_addr; onr.nr_firstnet = aa->aa_firstnet; onr.nr_lastnet = aa->aa_lastnet; /* * take the address supplied as an argument, and add it to the * at_ifnet (also given). Remember ing to update * those parts of the at_ifaddr that need special processing */ bzero( AA_SAT( aa ), sizeof( struct sockaddr_at )); bcopy( sat->sat_zero, &nr, sizeof( struct netrange )); bcopy( sat->sat_zero, AA_SAT( aa )->sat_zero, sizeof( struct netrange )); nnets = ntohs( nr.nr_lastnet ) - ntohs( nr.nr_firstnet ) + 1; aa->aa_firstnet = nr.nr_firstnet; aa->aa_lastnet = nr.nr_lastnet; /* XXX ALC */ #if 0 printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n", ifp->if_name, ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), (aa->aa_flags & AFA_PHASE2) ? 2 : 1); #endif /* * We could eliminate the need for a second phase 1 probe (post * autoconf) if we check whether we're resetting the node. Note * that phase 1 probes use only nodes, not net.node pairs. Under * phase 2, both the net and node must be the same. */ if ( ifp->if_flags & IFF_LOOPBACK ) { AA_SAT( aa )->sat_len = sat->sat_len; AA_SAT( aa )->sat_family = AF_APPLETALK; AA_SAT( aa )->sat_addr.s_net = sat->sat_addr.s_net; AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; #if 0 } else if ( fp->if_flags & IFF_POINTOPOINT) { /* unimplemented */ /* * we'd have to copy the dstaddr field over from the sat * but it's not clear that it would contain the right info.. */ #endif } else { /* * We are a normal (probably ethernet) interface. * apply the new address to the interface structures etc. * We will probe this address on the net first, before * applying it to ensure that it is free.. If it is not, then * we will try a number of other randomly generated addresses * in this net and then increment the net. etc.etc. until * we find an unused address. */ aa->aa_flags |= AFA_PROBING; /* if not loopback we Must probe? */ AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at); AA_SAT( aa )->sat_family = AF_APPLETALK; if ( aa->aa_flags & AFA_PHASE2 ) { if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { /* * If we are phase 2, and the net was not specified * then we select a random net within the supplied netrange. * XXX use /dev/random? */ if ( nnets != 1 ) { net = ntohs( nr.nr_firstnet ) + time_second % ( nnets - 1 ); } else { net = ntohs( nr.nr_firstnet ); } } else { /* * if a net was supplied, then check that it is within * the netrange. If it is not then replace the old values * and return an error */ if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) || ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) { aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; splx(s); return( EINVAL ); } /* * otherwise just use the new net number.. */ net = ntohs( sat->sat_addr.s_net ); } } else { /* * we must be phase one, so just use whatever we were given. * I guess it really isn't going to be used... RIGHT? */ net = ntohs( sat->sat_addr.s_net ); } /* * set the node part of the address into the ifaddr. * If it's not specified, be random about it... * XXX use /dev/random? */ if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) { AA_SAT( aa )->sat_addr.s_node = time_second; } else { AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; } /* * Copy the phase. */ AA_SAT( aa )->sat_range.r_netrange.nr_phase = ((aa->aa_flags & AFA_PHASE2) ? 2:1); /* * step through the nets in the range * starting at the (possibly random) start point. */ for ( i = nnets, netinc = 1; i > 0; net = ntohs( nr.nr_firstnet ) + (( net - ntohs( nr.nr_firstnet ) + netinc ) % nnets ), i-- ) { AA_SAT( aa )->sat_addr.s_net = htons( net ); /* * using a rather strange stepping method, * stagger through the possible node addresses * Once again, starting at the (possibly random) * initial node address. */ for ( j = 0, nodeinc = time_second | 1; j < 256; j++, AA_SAT( aa )->sat_addr.s_node += nodeinc ) { if ( AA_SAT( aa )->sat_addr.s_node > 253 || AA_SAT( aa )->sat_addr.s_node < 1 ) { continue; } aa->aa_probcnt = 10; /* * start off the probes as an asynchronous activity. * though why wait 200mSec? */ aa->aa_ch = timeout( aarpprobe, (caddr_t)ifp, hz / 5 ); if ( tsleep( aa, PPAUSE|PCATCH, "at_ifinit", 0 )) { /* * theoretically we shouldn't time out here * so if we returned with an error.. */ printf( "at_ifinit: why did this happen?!\n" ); aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; splx( s ); return( EINTR ); } /* * The async activity should have woken us up. * We need to see if it was successful in finding * a free spot, or if we need to iterate to the next * address to try. */ if (( aa->aa_flags & AFA_PROBING ) == 0 ) { break; } } /* * of course we need to break out through two loops... */ if (( aa->aa_flags & AFA_PROBING ) == 0 ) { break; } /* reset node for next network */ AA_SAT( aa )->sat_addr.s_node = time_second; } /* * if we are still trying to probe, then we have finished all * the possible addresses, so we need to give up */ if ( aa->aa_flags & AFA_PROBING ) { aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; splx( s ); return( EADDRINUSE ); } } /* * Now that we have selected an address, we need to tell the interface * about it, just in case it needs to adjust something. */ if ( ifp->if_ioctl && ( error = (*ifp->if_ioctl)( ifp, SIOCSIFADDR, (caddr_t)aa ))) { /* * of course this could mean that it objects violently * so if it does, we back out again.. */ aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; splx( s ); return( error ); } /* * set up the netmask part of the at_ifaddr * and point the appropriate pointer in the ifaddr to it. * probably pointless, but what the heck.. XXX */ bzero(&aa->aa_netmask, sizeof(aa->aa_netmask)); aa->aa_netmask.sat_len = sizeof(struct sockaddr_at); aa->aa_netmask.sat_family = AF_APPLETALK; aa->aa_netmask.sat_addr.s_net = 0xffff; aa->aa_netmask.sat_addr.s_node = 0; aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */ /* * Initialize broadcast (or remote p2p) address */ bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr)); aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at); aa->aa_broadaddr.sat_family = AF_APPLETALK; aa->aa_ifa.ifa_metric = ifp->if_metric; if (ifp->if_flags & IFF_BROADCAST) { aa->aa_broadaddr.sat_addr.s_net = htons(0); aa->aa_broadaddr.sat_addr.s_node = 0xff; aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr; /* add the range of routes needed */ error = aa_dorangeroute(&aa->aa_ifa, ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD ); } else if (ifp->if_flags & IFF_POINTOPOINT) { struct at_addr rtaddr, rtmask; bzero(&rtaddr, sizeof(rtaddr)); bzero(&rtmask, sizeof(rtmask)); /* fill in the far end if we know it here XXX */ aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_dstaddr; error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); } else if ( ifp->if_flags & IFF_LOOPBACK ) { struct at_addr rtaddr, rtmask; bzero(&rtaddr, sizeof(rtaddr)); bzero(&rtmask, sizeof(rtmask)); rtaddr.s_net = AA_SAT( aa )->sat_addr.s_net; rtaddr.s_node = AA_SAT( aa )->sat_addr.s_node; rtmask.s_net = 0xffff; rtmask.s_node = 0x0; /* XXX should not be so.. should be HOST route */ error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); } /* * set the address of our "check if this addr is ours" routine. */ aa->aa_ifa.ifa_claim_addr = aa_claim_addr; /* * of course if we can't add these routes we back out, but it's getting * risky by now XXX */ if ( error ) { at_scrub( ifp, aa ); aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; splx( s ); return( error ); } /* * note that the address has a route associated with it.... */ aa->aa_ifa.ifa_flags |= IFA_ROUTE; aa->aa_flags |= AFA_ROUTE; splx( s ); return( 0 ); } /* * check whether a given address is a broadcast address for us.. */ int at_broadcast( sat ) struct sockaddr_at *sat; { struct at_ifaddr *aa; /* * If the node is not right, it can't be a broadcast */ if ( sat->sat_addr.s_node != ATADDR_BCAST ) { return( 0 ); } /* * If the node was right then if the net is right, it's a broadcast */ if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { return( 1 ); } /* * failing that, if the net is one we have, it's a broadcast as well. */ for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { if (( aa->aa_ifp->if_flags & IFF_BROADCAST ) && ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) && ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet ))) { return( 1 ); } } return( 0 ); } /* * aa_dorangeroute() * * Add a route for a range of networks from bot to top - 1. * Algorithm: * * Split the range into two subranges such that the middle * of the two ranges is the point where the highest bit of difference * between the two addresses makes its transition. * Each of the upper and lower ranges might not exist, or might be * representable by 1 or more netmasks. In addition, if both - * ranges can be represented by the same netmask, then teh can be merged + * ranges can be represented by the same netmask, then they can be merged * by using the next higher netmask.. */ static int aa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd) { u_int mask1; struct at_addr addr; struct at_addr mask; int error; /* * slight sanity check */ if (bot > top) return (EINVAL); addr.s_node = 0; mask.s_node = 0; /* * just start out with the lowest boundary * and keep extending the mask till it's too big. */ while (bot <= top) { mask1 = 1; while ((( bot & ~mask1) >= bot) && (( bot | mask1) <= top)) { mask1 <<= 1; mask1 |= 1; } mask1 >>= 1; mask.s_net = htons(~mask1); addr.s_net = htons(bot); if(cmd == RTM_ADD) { error = aa_addsingleroute(ifa,&addr,&mask); if (error) { /* XXX clean up? */ return (error); } } else { error = aa_delsingleroute(ifa,&addr,&mask); } bot = (bot | mask1) + 1; } return 0; } static int aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask) { int error; #if 0 printf("aa_addsingleroute: %x.%x mask %x.%x ...\n", ntohs(addr->s_net), addr->s_node, ntohs(mask->s_net), mask->s_node); #endif error = aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP); if (error) printf("aa_addsingleroute: error %d\n", error); return(error); } static int aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask) { int error; error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0); if (error) printf("aa_delsingleroute: error %d\n", error); return(error); } static int aa_dosingleroute(struct ifaddr *ifa, struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags) { struct sockaddr_at addr, mask; bzero(&addr, sizeof(addr)); bzero(&mask, sizeof(mask)); addr.sat_family = AF_APPLETALK; addr.sat_len = sizeof(struct sockaddr_at); addr.sat_addr.s_net = at_addr->s_net; addr.sat_addr.s_node = at_addr->s_node; mask.sat_family = AF_APPLETALK; mask.sat_len = sizeof(struct sockaddr_at); mask.sat_addr.s_net = at_mask->s_net; mask.sat_addr.s_node = at_mask->s_node; if (at_mask->s_node) flags |= RTF_HOST; return(rtrequest(cmd, (struct sockaddr *) &addr, (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr), (struct sockaddr *) &mask, flags, NULL)); } #if 0 static void aa_clean(void) { struct at_ifaddr *aa; struct ifaddr *ifa; struct ifnet *ifp; while ( aa = at_ifaddr ) { ifp = aa->aa_ifp; at_scrub( ifp, aa ); at_ifaddr = aa->aa_next; if (( ifa = ifp->if_addrlist ) == (struct ifaddr *)aa ) { ifp->if_addrlist = ifa->ifa_next; } else { while ( ifa->ifa_next && ( ifa->ifa_next != (struct ifaddr *)aa )) { ifa = ifa->ifa_next; } if ( ifa->ifa_next ) { ifa->ifa_next = ((struct ifaddr *)aa)->ifa_next; } else { panic( "at_entry" ); } } } } #endif static int aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw0) { struct sockaddr_at *addr = (struct sockaddr_at *)ifa->ifa_addr; struct sockaddr_at *gw = (struct sockaddr_at *)gw0; switch (gw->sat_range.r_netrange.nr_phase) { case 1: if(addr->sat_range.r_netrange.nr_phase == 1) return 1; case 0: case 2: /* * if it's our net (including 0), * or netranges are valid, and we are in the range, * then it's ours. */ if ((addr->sat_addr.s_net == gw->sat_addr.s_net) || ((addr->sat_range.r_netrange.nr_lastnet) && (ntohs(gw->sat_addr.s_net) >= ntohs(addr->sat_range.r_netrange.nr_firstnet )) && (ntohs(gw->sat_addr.s_net) <= ntohs(addr->sat_range.r_netrange.nr_lastnet )))) { return 1; } break; default: printf("atalk: bad phase\n"); } return 0; } diff --git a/sys/pc98/boot/biosboot/start.S b/sys/pc98/boot/biosboot/start.S index 2a545b54e7e2..013a40b142ec 100644 --- a/sys/pc98/boot/biosboot/start.S +++ b/sys/pc98/boot/biosboot/start.S @@ -1,535 +1,535 @@ /* * 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. * * from: Mach, Revision 2.2 92/04/04 11:36:29 rpd - * $Id: start.S,v 1.4 1997/02/22 09:43:09 peter Exp $ + * $Id: start.S,v 1.5 1998/05/02 02:06:07 kato Exp $ */ /* 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. */ /* * Ported to PC-9801 by Yoshio Kimura */ #include "asm.h" .file "start.S" SIGNATURE= 0xaa55 LOADSZ= 8192 /* size of unix boot */ NAMEBLOCKMAGIC= 0xfadefeed /* value of magicnumebr for block2 */ /* * This DEBUGMSG(msg) macro may be useful for debugging. Its use is * restricted to this file since it only works in real mode. */ #define DEBUGMSG(msg) \ data32 ; \ mov $msg, %esi ; \ data32 ; \ call message .text .globl start ENTRY(boot1) jmp start boot_cyl: .word 0 String "IPL1 " start: /* set up %ds */ xor %ax, %ax mov %ax, %ds /* set up %ss and %esp */ data32 mov $BOOTSEG, %eax mov %ax, %ss /* * make a little room on the stack for * us to save the default bootstring we might find.. * effectively, we push the bootstring. */ data32 mov $BOOTSTACK-64, %esp /* set up %es, (where we will load boot2 to) */ mov %ax, %es push %es push %cx push %dx data32 mov $0xa000, %eax mov %ax, %es addr32 movb 0x501, %al testb $0x08, %al jnz hireso normal: /* set up graphic screen */ movb $0x42, %ah movb $0xc0, %ch int $0x18 movb $0x40, %ah int $0x18 data32 mov $0x0a00, %eax /* 80 x 25 mode */ jmp 1f hireso: movb $0x08, %al /* set up RAM window */ outb %al, $0x91 movb $0x0a, %al outb %al, $0x93 data32 mov $0x0a10, %ax /* 80 x 31 mode */ 1: int $0x18 movb $0x0c, %ah /* text on */ int $0x18 /* cursor home and on */ xor %edx, %edx movb $0x13, %ah int $0x18 movb $0x11, %ah int $0x18 /* highreso no supported */ addr32 movb 0x501, %al testb $0x08, %al jz nothireso data32 mov $ehireso, %esi data32 call message hlt nothireso: /* keyboad reset */ movb $0x03, %ah int $0x18 /* transfer PC-9801 system common area to 0xa1000 */ data32 mov $0x0000, %esi data32 mov $0x1000, %edi data32 mov $0x0630, %ecx cld rep movsb /* transfer EPSON machine type to 0xa1200 */ push %ds data32 mov $0xfd00, %eax mov %ax, %ds addr32 data32 mov 0x804, %eax data32 and $0x00ffffff, %eax addr32 data32 .byte 0x26 mov %eax, %es: (0x1624) pop %ds pop %dx pop %cx pop %es /* bootstrap passes */ mov %cs, %bx data32 cmp $0x1fe0, %ebx jz fd data32 cmp $0x1fc0, %ebx jnz hd data32 mov %ebp, %ecx data32 mov %ebp, %edx addr32 movb 0x584, %al andb $0xf0, %al cmpb $0x30, %al jz fd cmpb $0x90, %al jnz hd fd: data32 mov $0x0200, %ecx data32 mov $0x0001, %edx movb $0xd6, %ah jmp load hd: data32 and %ecx, %ecx jnz 1f addr32 data32 mov %cs: (boot_cyl), %ecx 1: movb $0x06, %ah /* * BIOS call "INT 0x1B Function 0xn6" to read sectors from disk into memory * Call with %ah = 0xd6(for floppy disk) or 0x06(for hard disk) * %al = DA/UA * %bx = data length * %ch = sector size(for floppy) or cylinder(for hard) * %cl = cylinder * %dh = head * %dl = sector * %es:%bp = segment:offset of buffer * Return: * %ah = 0x0 on success; err code on failure */ load: #ifdef NAMEBLOCK /* * Load the second sector and see if it is a boot instruction block. * If it is then scan the contents for the first valid string and copy it to * the location of the default boot string.. then zero it out. * Finally write the block back to disk with the zero'd out entry.. * I hate writing at this stage but we need this to be persistant. * If the boot fails, then the next boot will get the next string. - * /etc/rc will regenerate a complete block2 iff teh boot succeeds. + * /etc/rc will regenerate a complete block2 iff the boot succeeds. * * Format of block 2 is: * [NAMEBLOCKMAGIC] <--0xdeafc0de * [nulls] * [bootstring]NULL <---e.g. 0:wd(0,a)/kernel.experimental * [bootstring]NULL <---e.g. 0:wd(0,a)/kernel.old * .... * [bootstring]NULL <---e.g. 0:wd(0,f)/kernel * FF FF FF */ where: /* * save things we might smash * (that are not smashed immedatly after us anyway.) */ data32 push %ecx /* preserve 'cyl,sector ' */ data32 push %edx /* * Load the second sector * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory * Call with %ah = 0x2 * %al = number of sectors * %ch = cylinder * %cl = sector * %dh = head * %dl = drive (0x80 for hard disk, 0x0 for floppy disk) * %es:%bx = segment:offset of buffer * Return: * %al = 0x0 on success; err code on failure */ data32 movl $0x0201, %eax /function 2 (read) 1 sector */ xor %ebx, %ebx /* %bx = 0 */ /* buffer address (ES:0) */ data32 movl $0x0002, %ecx /* sector 2, cylinder 0 */ data32 andl $0x00ff, %edx /* head 0, drive N */ int $0x13 data32 jb read_error /* * confirm that it is one for us */ data32 xorl %ebx, %ebx /* magic number at start of buffer */ data32 addr32 movl %es:(%ebx), %eax data32 cmpl $NAMEBLOCKMAGIC, %eax data32 jne notours /* not ours so return to caller */ /* * scan for a bootstring * Skip the magic number, and scan till we find a non-null, * or a -1 */ incl %ebx /* quicker and smaller */ incl %ebx incl %ebx scan: incl %ebx addr32 movb %es:(%ebx), %al /* load the next byte */ testb %al, %al /* and if it is null */ data32 /* keep scanning (past deleted entries) */ jz scan incb %al /* now look for -1 */ data32 jz notours /* if we reach the 0xFF then we have finished */ /* * save our settings.. we need them twice.. */ data32 push %ebx /* * copy it to the default string location * which is just above the stack for 64 bytes. */ data32 movl $BOOTSTACK-64, %ecx /* 64 bytes at the top of the stack */ nxtbyte: addr32 movb %es:(%ebx), %al /* get the next byte in */ addr32 movb %al, %es:(%ecx) /* and transfer it to the name buffer */ incl %ebx /* get on with the next byte */ incl %ecx /* get on with the next byte */ testb %al, %al /* if it was 0 then quit this */ data32 jnz nxtbyte /* and looop if more to do */ /* * restore the saved settings and * zero it out so next time we don't try it again */ data32 pop %ebx /* get back our starting location */ #ifdef NAMEBLOCK_WRITEBACK nxtbyte2: addr32 movb %es:(%ebx), %al /* get the byte */ addr32 movb $0, %es:(%ebx) /* zero it out */ data32 incl %ebx /* point to the next byte */ testb %al, %al /* check if we have finished.. */ data32 jne nxtbyte2 /* * Write the second sector back * Load the second sector * BIOS call "INT 0x13 Function 0x3" to write sectors from memory to disk * Call with %ah = 0x3 * %al = number of sectors * %ch = cylinder * %cl = sector * %dh = head * %dl = drive (0x80 for hard disk, 0x0 for floppy disk) * %es:%bx = segment:offset of buffer * Return: * %al = 0x0 on success; err code on failure */ data32 movl $0x0301, %eax /* write 1 sector */ xor %ebx, %ebx /* buffer is at offset 0 */ data32 movl $0x0002, %ecx /* block 2 */ data32 andl $0xff, %edx /* head 0 */ int $0x13 data32 jnb notours data32 mov $eread, %esi jmp err_stop #endif /* NAMEBLOCK_WRITEBACK */ /* * return to the main-line */ notours: data32 pop %edx data32 pop %ecx #endif data32 mov $LOADSZ, %ebx addr32 movb 0x584, %al xor %ebp, %ebp /* %bp = 0, put it at 0 in the BOOTSEG */ int $0x1b jc read_error /* * ljmp to the second stage boot loader (boot2). * After ljmp, %cs is BOOTSEG and boot1 (512 bytes) will be used * as an internal buffer "intbuf". */ data32 ljmp $BOOTSEG, $ EXT(boot2) /* * read_error */ read_error: data32 mov $eread, %esi err_stop: data32 call message data32 jmp stop /* * message: write the error message in %ds:%esi to console */ message: data32 push %eax data32 push %ebx push %ds push %es data32 mov $0xe000, %eax mov %ax, %es addr32 mov 0x501, %al testb $0x08, %al jnz 1f data32 mov $0xa000, %eax mov %ax, %es 1: mov %cs, %ax mov %ax, %ds addr32 data32 mov vram, %edi data32 mov $0x00e1, %ebx cld nextb: lodsb /* load a byte into %al */ cmpb $0x0, %al je done cmpb $0x0d, %al je cr_code cmpb $0x0a, %al je lf_code addr32 movb %al, (%edi) addr32 movb %bl, 0x2000(%edi) data32 inc %edi data32 inc %edi jmp nextb cr_code: data32 add $80, %edi jmp nextb lf_code: data32 mov %edi, %eax data32 mov $80, %edx data32 div %ebx data32 sub %ebx, %edi jmp nextb done: addr32 data32 mov %edi, vram pop %es pop %ds data32 pop %ebx data32 pop %eax data32 ret stop: hlt data32 jmp stop /* halt doesnt actually halt forever */ vram: .long 0 /* error messages */ #ifdef DEBUG one: String "1-\0" two: String "2-\0" three: String "3-\0" four: String "4-\0" #endif DEBUG #ifdef NAMEBLOCK_WRITEBACK ewrite: String "Write error\r\n\0" #endif /* NAMEBLOCK_WRITEBACK */ eread: String "Read error\r\n\0" enoboot: String "No bootable partition\r\n\0" endofcode: ehireso: String "Highreso not supported\r\n\0" /* the last 2 bytes in the sector 0 contain the signature */ . = EXT(boot1) + 0x1fe .value SIGNATURE ENTRY(disklabel) . = EXT(boot1) + 0x400