ins760z@monu4.cc.monash.edu.au (mr c.r. hames) (05/15/91)
How does the BIOS know how far in is the boot record from the start of a harddisk that is going to be autobooted from? Like how does it work out how much partition info is before the boot record ? Email please, ins760z@monu4.cc.monash.edu.au ( An Amiga owner who enjoys emulating others)
ericb@eecs.cs.pdx.edu (Eric Berggren) (05/15/91)
ins760z@monu4.cc.monash.edu.au (mr c.r. hames) writes: > How does the BIOS know how far in is the boot record from the start of >a harddisk that is going to be autobooted from? Like how does it work out >how much partition info is before the boot record ? >Email please, I already e-mailed him, here's a copy of my letter... Well.. [in case you have not already received 30 messages in 30 seconds] Located on absolute sector 0 and offset 0x1be (I believe) is the partition table. In this table contains all the necessary information such as starting and ending cylinders, heads, and sectors, as well as its size and absolute starting sector (why the redundancies, I dunno, some fdisk programs only set one of the parameters and not the others, which creates problems for some OS's other than MS-DOS). When you boot the system, the fixed disk BIOS does its magic and looks for a partition with a flag indicating it is the active one (also conatained in each partition entry) When it finds an active partition, it reads the starting sector, jumps to that and boots similarly to a floppy disk, the first sector of each partition has their own boot block, so you may have multiple operating systems on one drive and can boot off of any one by simply changing the active flag and rebooting the machine. Now DOS 4.xx+ has logical partitions in a physical partition, so each MS-DOS physical partition has a mini-partition table in it. Only the first logical partition is bootable, the rest are assigned as consecutive drives. This is a very general overview of how it works. If you want to know more about the gory details, lemme know, as I am writing my own disk partitioning program that will enable me to manipulate any type of partition. -e.b. ============================================================================== Eric Berggren | "Life is a Turing Test; Computer Science/Eng. | We're all automatons!" ericb@eecs.cs.pdx.edu | - (click, whir, buzz, chirp)
ericb@eecs.cs.pdx.edu (Eric Berggren) (05/23/91)
I'm currently constructing a program that allows a user to customize the partition table on a hard disk with any of the available 256 types of partitions and the ability to specify any starting and ending position (within reason). This is not a general purpose program, but rather intended for somebody who needs to configure the drive in a particular fashion in which many FDisk programs would not allow. For example, DOS 4.x+ only configures partitions in megs, with no control over where they go. This often causes problems for other operating system which do not recognize parculiar sizes or starting position. Note this program only manages physical partitions, not logical ones, such as used in MS-DOS 4.x+ (you must use their fdisk program to create the logical ones). There is a list of known partition types in the program. These are all of the partitions that I know of; I borrowed them from Minix. Any other ones that you know of that aren't included, lemme know. I have to put off the completion of the project until the end of the term (early June). When finished, I will post it, along with the Turbo-C source, in binaries. My only reference is The MS-DOS Programmer's Guide (Waite Group), [and not everything stated in there is true but, so far, it works]. Here's the core structures and routines from my program to help understand what goes on. I'll admit it's all basically hacked with little comments; it'll be cleaned up prior to posting. The partition table for a hard drive is stored on physical sector 0, at offset 1BEh. To get the partition table, simply read sector 0 into a buffer, then load in the 4 consecutive entries into the structure below starting at 0x1be. And that's all there is to that. This is all that can fit on the first sector; where extended number of partitions are stored, I'm not suere, perhaps the next sector. Now within the structure itself, there's a bit of encoding going on. The lower 6 bits of the start_ and end_sec holds the starting sector, while the upper MSB's hold the MSB's for the start_ and end_cyl. (here's some fancy detailed graphics): | c | c | s | s | s | s | s | s | start_sec(tor) --------| | V V-------| | c | c | c | c | c | c | c | c | c | c | start_cyl(inder) Note that the maximum number cylinders that can be represented is 1024. The extractions of these I have in the macros below. To indicate an active partition, place 0x80 into the active field, else place 0x00 in it to indicate it being inactive. Only one should be active at a time. The results of multiple active partitions or funny values, I'm not sure. I have a small structure which holds parameters for the current drive. I use function 08h (get drive parms) of Int 13h to get the info. The number of sectors and cylinders are encoded just like above. From there, you can calculate things like tracks (cylinders / heads) and size in megs, etc, found in the getparms() routine. Any other questions, lemme know. -e.b. #define MAXPARTITIONS 4 /* max number of physical partitions*/ #define SECTSIZE 512 /* sector size (bytes) */ #define PARTTABLEOFS 0x1be /* partition table offset in boot */ #define NUMPARTTYPES 256 /* number of different partitions */ #define NOPARTITION 0x00 /* empty partition type */ #define BADBLOCKPART 0xff /* partition of bad blocks */ #define ACTIVE_FLAG 0x80 /* partition active flag */ #define StartCyl(p) ( p.start_cyl + ( ( (long)p.start_sec & 0xc0 ) << 2 ) ) #define StartSec(p) ( p.start_sec & 0x3f ) #define StartHead(p) ( p.start_head ) #define EndCyl(p) ( p.end_cyl + ( ( (long)p.end_sec & 0xc0 ) << 2 ) ) #define EndSec(p) ( p.end_sec & 0x3f ) #define EndHead(p) ( p.end_head ) #define StartSector(p) ( (long)p.abs_sec ) #define NumSectors(p) ( (long)p.num_sec ) typedef struct { unsigned char active; /* 80h is active; 00h if not */ unsigned char start_head; /* head of first sector */ unsigned char start_sec; /* first sector + 2 MSB's of cyl */ unsigned char start_cyl; /* cylinder of first sector */ unsigned char type; /* partition type (OS who owns it) */ unsigned char end_head; /* head of last sector */ unsigned char end_sec; /* last sector + 2 MSB'd of cyl */ unsigned char end_cyl; /* cylinder of last sector */ unsigned long abs_sec; /* absolute starting sector */ unsigned long num_sec; /* total sectors in partition */ } Part_Entry; struct { unsigned char numdrives; /* number of consecutive drives */ unsigned char heads; /* number of surfaces */ unsigned char sect_trk; /* number of sectors per track */ unsigned int cylinders; /* number of total cylinders */ unsigned long tracks; /* calculated number of total tracks*/ unsigned long sectors; /* calculated number of total sects */ unsigned int megs; /* calculated capacity in megabytes */ } DriveParms; char Sector_Buf[ SECTSIZE ]; /* sector I/O buffer */ Part_Entry PartTable[ MAXPARTITIONS ]; /* partition table for current drive*/ char TypeTable[ NUMPARTTYPES ][ 10 ]; /* list of partition types */ int CurrentDrive = DEFAULT_DRIVE; /* current logged drive */ int ReadOnly = FALSE; /* disallows partition table update */ int Not_Valid = TRUE; /* current partition table invalid */ void init_tt() { int i; memset( &PartTable, 0, sizeof( PartTable ) ); for ( i = 0; i < NUMPARTTYPES; i ++ ) switch ( i ) { case NOPARTITION : strcpy( &TypeTable[ i ], " NONE " ); break; case 0x01 : strcpy( &TypeTable[ i ], "DOS-12FAT" ); break; case 0x02 : strcpy( &TypeTable[ i ], " XENIX " ); break; case 0x03 : strcpy( &TypeTable[ i ], "XENIX-OLD" ); break; case 0x04 : strcpy( &TypeTable[ i ], "DOS-16FAT" ); break; case 0x05 : strcpy( &TypeTable[ i ], " DOS-EXT " ); break; case 0x06 : strcpy( &TypeTable[ i ], " DOS-BIG " ); break; case 0x08 : strcpy( &TypeTable[ i ], " AIX " ); break; case 0x0A : strcpy( &TypeTable[ i ], " OPUS " ); break; case 0x51 : strcpy( &TypeTable[ i ], " NOVELL? " ); break; case 0x52 : strcpy( &TypeTable[ i ], " CPM " ); break; case 0x63 : strcpy( &TypeTable[ i ], " 386/IX " ); break; case 0x64 : strcpy( &TypeTable[ i ], " NOVELL " ); break; case 0x75 : strcpy( &TypeTable[ i ], " PCIX " ); break; case 0x80 : strcpy( &TypeTable[ i ], "MINIX-OLD" ); break; case 0x81 : strcpy( &TypeTable[ i ], " MINIX " ); break; case 0xDB : strcpy( &TypeTable[ i ], " CPM " ); break; case BADBLOCKPART : strcpy( &TypeTable[ i ], "BADBLOCKS" ); break; default : strcpy( &TypeTable[ i ], " UNKNOWN " ); break; } } void sector_to_hsc( abs_end_sec, partentry ) unsigned long abs_end_sec; Part_Entry *partentry; { unsigned int cylinder; cylinder = (unsigned int)( abs_end_sec / ( DriveParms.heads * DriveParms.sect_trk ) ); partentry->end_cyl = cylinder & 0xff; partentry->end_sec = ( abs_end_sec % DriveParms.sect_trk ) + ( ( cylinder >> 2 ) & 0xc0 ) + 1; partentry->end_head= ( abs_end_sec % ( DriveParms.heads * DriveParms.sect_trk ) ) / DriveParms.sect_trk; partentry->num_sec = abs_end_sec - partentry->abs_sec; } check_table() { return( 0 ); } getdriveparms() { char errmsg[ 35 ]; union REGS regs; regs.h.ah = 0x08; /* Function: 08h, get drive parms. */ regs.h.dl = 0x80 + CurrentDrive - 2; int86( 0x13, ®s, ®s ); DriveParms.numdrives = regs.h.dl; DriveParms.heads = regs.h.dh + 1; DriveParms.sect_trk = regs.h.cl & 0x3f; DriveParms.cylinders = regs.h.ch + ( ( regs.h.cl & 0xc0 ) << 2 ) + 2; DriveParms.tracks = (long)DriveParms.heads * (long)DriveParms.cylinders; DriveParms.sectors = DriveParms.tracks * (long)DriveParms.sect_trk; DriveParms.megs = (int)( (long)DriveParms.tracks * (long)DriveParms.sect_trk * (long)SECTSIZE / (long)1000000 ); if ( regs.x.cflag ) { sprintf( errmsg, "Error reading fixed disk %c: parameters", CurrentDrive + 'A' ); error( errmsg ); } return( regs.x.cflag ); } int writeparttab() { if ( ReadOnly ) { error( "Write protect option enabled" ); return( 1 ); } return( 0 ); } readparttab() { int i; char errormsg[ 80 ]; memset( &PartTable, 0, sizeof( PartTable ) ); if ( ( Not_Valid = readboot( CurrentDrive, &Sector_Buf ) ) != 0 ) { sprintf( errormsg, "Error reading fixed disk %c:", CurrentDrive + 'A' ); error( errormsg ); return( Not_Valid ); } for( i = 0; i < MAXPARTITIONS; i ++ ) memcpy( &PartTable[ i ], &Sector_Buf[ PARTTABLEOFS + i * sizeof( Part_Entry ) ], sizeof( Part_Entry ) ); Not_Valid = check_table(); return( Not_Valid ); } readboot( drivenum, buffer ) char drivenum; char *buffer; { union REGS regs; struct SREGS sregs; if ( drivenum < 0 || drivenum > 7 ) return( 1 ); segread( &sregs ); /* get segment registers (DS) */ regs.h.ah = 0x02; /* Function: 02h, read sectors */ regs.h.al = 0x01; /* 1 sector */ regs.h.ch = 0x00; /* cylinder 0 */ regs.h.cl = 0x01; /* first sector = 1 */ regs.h.dh = 0x00; /* head = 0 */ regs.h.dl = 0x80 + drivenum - 2; /* drive number */ sregs.es = sregs.ds; /* address of buffer (segment) */ regs.x.bx = (int)buffer; /* address of buffer (offset) */ int86x( 0x13, ®s, ®s, &sregs ); return( (int)regs.x.cflag ); /* carry set=error occurred */ } ============================================================================== Eric Berggren | "Life is a Turing Test; Computer Science/Eng. | We're all automatons!" ericb@eecs.cs.pdx.edu | - (click, whir, buzz, chirp)