
BootingProblems with booting... numerous emails & posts about this one, that's for sure!!! Real solutions? Not really... In many cases people end up reinstalling their system from Scratch and once in a while even that doesn't work! But smart people have a way to fix their boot sectors without too much hurdle (instead of the hours it takes to install an OS.) Yes! There ought to be a reason for things not to work so well once in while. In most cases, if you only have proper Unix systems (Linux, FreeBSD, HURD, etc.) you will be fine since these systems can be anywhere any time and they usually don't walk on each others feet. Many people, however, want to be able to use MS-Windows with Linux (dual boot) and if possible multiple versions of Windows on the same drive (triple or quadruple boot!). Not wise! some people say, but I do see a great advantage to that: I don't need to have multiple computers or swap hard drives each time I want to boot on a different system. My new system will have (once complete 8-P) the following systems: Win98, Win2k, WinXP, FC5, RH9. RH9 is mainly to test new code on older systems and Win98 is for the kids to play older video games which don't work on Win2k or WinXP (or Linux if that matter... 8-P).
In this table, I show you what I use in my GRUB configuration file (menu.conf, menu.lst or grub.conf).
I use
Once the drives are properly hidden/shown, you are ready to boot from them. You need
to specify the root drive with
Another draw back from MS-Windows, they need to have the boot flag active on the partition
you're booting from. In other words, the boot flag needs to change between /dev/hda1,
/dev/hda2 and /dev/hda3 as I boot Win98, Win2k and WinXP. For the Linux partitions it is
not required and plus these are not primary partitions so it's not useful (the boot flag won't work
properly on extended partitions anyway.) The
Finally, to load the actual MBR to boot Windows, you use the Okay! We're ready to run... but what really happens?! Let's see the list of steps to boot your PC:
But... but... but... I need a driver to boot windows!!!
What the driver does is take over the 0x13 interrupt. This means it will read the structure you pass to it and convert that in the proper read commands for your hard drive. These can in general be used with any systems, but Linux is not likely to recognize such a driver and it will certainly bypass it. (On the other hand you have options to ask Linux to continue to use the BIOS even after it started its kernel in which case it will use that special driver.) Okay, now let's move on to the hard code stuff. The actual code in your boot strap and MBRs. MBR StructureThe basic MBR structure is as follow:
struct fdisk_partition {
uint8_t f_boot_flag; /* 0: not bootable, 128: bootable */
uint8_t f_begin_head; /* beginning head number */
uint8_t f_begin_cylhi : 2; /* 2 high bits for beginning cylinders */
uint8_t f_begin_sector : 6; /* beginning sector number */
uint8_t f_begin_cyllo; /* beginning cylinder low bits */
uint8_t f_system_id; /* Operating System type indicator code */
uint8_t f_end_head; /* ending head number */
uint8_t f_end_sector : 2; /* 2 high bits for ending cylinder number */
uint8_t f_end_sector : 6; /* ending sector number */
uint8_t f_end_cyllo; /* ending cylinder low bits */
uint32_t f_relative_sector; /* first sector relative to start of disk */
uint32_t f_sectors_count; /* number of sectors in partition */
};
// f_begin_cylinder = f_begin_cyllo + (f_begin_cylhi << 8);
// f_end_cylinder = f_end_cyllo + (f_end_cylhi << 8);
//
// Note that the maximum of each entry is:
// 1024 cylinder (210)
// 256 heads (28)
// 64 sectors (26)
// and thus the maximum addressable sector with these metrics are:
// 1024 x 256 x 64 = 16,777,216 (~8Gb)
//
// Until we got the LBA which solved the problem by using the same
// addressing as the SCSI drives which had it right from the beginning...
struct master_boot_record {
int8_t f_bootinst[446]; /* boot code and filesystem information */
fdisk_partition f_partitions[4]; /* primary partitions definitions */
uint16_t f_signature; /* magic word always set to 0xAA55 */
};
// Floppy parameters at 0000:001E
// This is called Floppy but is used by hard drives as well.
struct floppy_parameters {
uint8_t f_step_rate : 4; /* speed x 2 ms */
uint8_t f_head_unload : 4; /* 0x0F = 240 ms */
uint8_t f_head_load : 7; /* time x 4 ms */
uint8_t f_no_dma : 1; /* always 0 */
uint8_t f_turn_off_motor; /* in clock ticks */
uint8_t f_bytes_per_sector; /* 0: 128, 1: 256, 2: 512, 3: 1024 */
uint8_t f_sectors_per_track; /* 0xFF means variable */
uint8_t f_gap_length; /* 0x2A for 5.25", and 0x1B for 3.5" */
uint8_t f_data_length; /* used if bytes per sector is zero */
uint8_t f_format_gap_length; /* 0x50 for 5.25", and 0x6C for 3.5" */
uint8_t f_filler_byte; /* default 0xF6 */
uint8_t f_head_settle_time; /* in ms */
uint8_t f_turn_on_motor; /* in 1/8th of a second */
};
// size is 11 bytes
struct surepath {
struct floppy_parameters f_common;
uint8_t f_max_track;
uint8_t f_transfer_rate;
uint8_t f_drive_type;
};
// INT 13, AH = 42 uses the following structure which needs to be pointed by
// DS:SI (and DL is the drive number)
struct disk_packet_address {
uint8_t f_size; /* size of this packet (0x10 or 0x18) */
uint8_t f_reserved; /* always 0 */
uint16_t f_blocks_to_transfer; /* max 0x007F on Phoenix EDD */
uint32_t f_buffer_ptr; /* pointer where to load */
uint64_t f_start_sector; /* LBA or see below */
// the following is optional and only available with EDD 3.0
uint64_t f_buffer64_ptr; /* used this when f_buffer_ptr is 0xFFFFFFFF */
};
// Start Sector when LBA isn't used:
// (Cylinder x Heads + Selected Head) x Sectors per Track + Selected Sector - 1
};
Win98 Boot SectorThe following is a copy of the Win98 boot strap (or MBR). INT 19 will read that information and jump to 0x0000:0x7C00. It is expected to read other sectors and start running some operating system. # Note: it is assumed that CS is 0x0000 by this time 7C00: EB 3C jmps start go to 7C3E 7C02: 90 nop BIOS Parameter Block and Extended Block (not 100% sure, but it could be that the BIOS [or LILO/GRUB] will poke some values in here before jumping to 7C00) 7C03: 4D 53 57 49 4E 34 2E 31 MSWIN4.1 7C0B: 00 02 0x0200 (512) bytes per sector 7C0D: 40 0x40 (64) sectors per cylinder 7C0E: 01 00 0x0001 (1) reserved sector (this MBR) 7C10: 02 0x02 (2) number of FATs (File Allocation Tables) 7C11: 00 02 0x0200 (512) number of files in the root directory 7C13: 00 00 0x0000 (0) number of sectors (if 0, check large count below) 7C15: F8 media type 7C16: FA 00 0x00FA (250) sectors per FAT 7C18: 3F 00 0x003F (63) sectors per track 7C1A: FF 00 0x00FF (255) heads 7C1C: 3F 00 00 00 0x003F (63) hidden sectors 7C20: B5 CF 3B 00 0x003BCFB5 (3919797) sectors (too large for 7C13) 7C24: 80 physical disk number (always 0x80 for hard drives) 7C25: 00 unused (current head) 7C26: 29 signature (must be 0x28 or 0x29) 7C27: F8 11 08 42 Some Unique ID 7C2B: 20 20 20 20 20 20 20 20 20 20 20 Unused disk label 7C36: 46 41 54 31 36 20 20 20 FAT16, the system ID (FAT12 or FAT16) start: 7C3E: 33 C9 xor cx,cx clear CX 7C40: 8E D1 mov ss,cx clear SS 7C42: BC FC 7B mov sp,0x7BFC set SP to7BFC (just before this block) 7C45: 16 push ss copy SS to ES (i.e. clear ES) 7C46: 07 pop es 7C47: BD 78 00 mov bp,0x0078 address of INT 1E 7C4A: C5 76 00 lds si,[bp+0x00] loading DS:SI (source) 7C4D: 1E push ds save DS:SI (original INT 1E content) 7C4E: 56 push si (need to restore that later!) 7C4F: 16 push ss save SS:BP (address to INT 1E) 7C50: 55 push bp 7C51: BF 22 05 mov di,0x0522 address = 0x0522 (dest.) 7C54: 89 7E 00 mov [bp+0x00],di save ES:DI (dest.) in INT 1E 7C57: 89 4E 02 mov [bp+0x02],cx clear (segment = 0) 7C5A: B1 0B mov cl,0x0B 7C5C: FC cld 7C5D: F3 A4 rep movsb copy 11 bytes (floppy parameters) 7C5F: 06 push es clear ds (segment = 0) 7C60: 1F pop ds 7C61: BD 00 7C mov bp,0x7C00 7C64: C6 45 FE 0F mov [di-0x02],0x0F set settle time to 15 ms 7C68: 38 4E 24 cmp [bp+0x24],cl is [bp+24] negative? (i.e. hard drive) 7C6B: 7D 20 jnl boot_floppy go to 7C8D harddrive: 7C6D: 8B C1 mov ax,cx clear ax (read sector 0, partition?) 7C6F: 99 cwd clear dx 7C70: E8 7E 01 calln read go to 7DF1 7C73: 83 EB 3A sub bx,0x3A go to the 1st partition table 7C76: 66 A1 1C 7C mov eax,[0x7C1C] # of hidden sectors next_partition: 7C7A: 66 3B 07 cmp eax,[bx] 7C7D: 8A 57 FC mov dl,[bx-0x04] 7C80: 75 06 jne keep_old_read go to 7C88 7C82: 80 CA 02 or dl,0x02 7C85: 88 56 02 mov [bp+0x02],dl if 0x0E, use extended read keep_old_read: 7C88: 80 C3 10 add bl,0x10 next partition 7C8B: 73 ED jnc next_partition go to 7C7A The follow reads the root directory in which it expects to find the file JO.SYS (unlikely) or IO.SYS (more likely!) 7C8D: 33 C9 xor cx,cx 7C8F: FE 06 D8 7D inc [0x7DD8] character I -> J retry: 7C93: 8A 46 10 mov al,[bp+0x10] number of FATs 7C96: 98 cbw clear ah 7C97: F7 66 16 mul [bp+0x16] sectors per FAT 7C9A: 03 46 1C add ax,[bp+0x1C] hidden sectors (low) 7C9D: 13 56 1E adc dx,[bp+0x1E] hidden sectors (high) 7CA0: 03 46 0E add ax,[bp+0x0E] reserved sectors (low) 7CA3: 13 D1 adc dx,cx add carry if any (high) 7CA5: 8B 76 11 mov si,[bp+0x11] number of files in root dir. 7CA8: 60 pushaw 7CA9: 89 46 FC mov [bp-0x04],ax save sector # 7CAC: 89 56 FE mov [bp-0x02],dx 7CAF: B8 20 00 mov ax,0020 7CB2: F7 E6 mul si ax,dx = si x 32 (i.e. 0x00004000) 7CB4: 8B 5E 0B mov bx,[bp+0x0B] size of 1 sector 7CB7: 03 C3 add ax,bx 7CB9: 48 dec ax 7CBA: F7 F3 div bx (ax,dx + bx - 1) / bx (i.e. 0x41FF / 0x200 = 0x20) 7CBC: 01 46 FC add [bp-0x04],ax 7CBF: 11 4E FE adc [bp-0x02],cx 7CC2: 61 popaw 7CC3: BF 00 07 mov di,0x0700 7CC6: E8 28 01 calln read go to 7DF1 7CC9: 72 3E jc io_error go to 7D09 compare_next: 7CCB: 38 2D cmp [di],ch is [di] null? 7CCD: 74 17 je try_again go to 7CE6 7CCF: 60 pushaw 7CD0: B1 0B mov cl,0x0B 11 chars 7CD2: BE D8 7D mov si,0x7DD8 "JO SYS" or "IO SYS" 7CD5: F3 A6 rep cmpsb assumes that the D flag is still 0 7CD7: 61 popaw 7CD8: 74 3D je load_system go to 7D17 7CDA: 4E dec si 7CDB: 74 09 je try_again go to 7CE6 7CDD: 83 C7 20 addw di,0x0020 7CE0: 3B FB cmp di,bx 7CE2: 72 E7 jc compare_next go to 7CCB 7CE4: EB DD jmps go to 7CC3 try_again: 7CE6: FE 0E D8 7D dec [0x7DD8] restore the 'I' and try again (when we get an 'H' we don't branch) 7CEA: 7B A7 jnp retry go to 7C93 not_a_system_disk: 7CEC: BE 7F 7D mov si,0x7D7F print: // print 2 strings (input si and then "Press Any Key") 7CEF: AC lodsb load 1 byte from si (implies "inc si") 7CF0: 98 cbw clear ah 7CF1: 03 F0 add si,ax add to si next_char: 7CF3: AC lodsb load 1 character from string 7CF4: 98 cbw 7CF5: 40 inc ax is it 0xFF? (end of string followed by press a key) 7CF6: 74 0C je msg_press_key go to 7D04 7CF8: 48 dec ax is it 0x00? (end of string) 7CF9: 74 13 je msg_beep go to 7D0E 7CFB: B4 0E mov ah,0x0E put char in al on screen 7CFD: BB 07 00 mov bx,0x0007 7D00: CD 10 int 0x10 7D02: EB EF jmps next_char msg_press_key: 7D04: BE 82 7D mov si,0x7D82 7D07: EB E6 jmps print go to 7CEF io_error: 7D09: BE 80 7D mov si,0x7D80 7D0C: EB E1 jmps print go to 7CEF msg_beep: 7D0E: CD 16 int 16 getchar() (keyboard read) 7D10: 5E pop si 7D11: 1F pop ds 7D12: 66 8F 04 popd [si] 7D15: CD 19 int 19 bootstrap loader (does not return) The following found the file named JO.SYS or IO.SYS in the root directory and it starts loading its first 4 sectors and execute them On my system this file is 218Kb, so that's quite big. It certainly is the handling of all of MSDOS. load_system: 7D17: BE 81 7D mov si,0x7D81 <- this is weird... 7D1A: 8B 7D 1A mov di,[di+0x1A] 7D1D: 8D 45 FE lea ax,[di-0x02] 7D20: 8a 3E 0D mov cl,[bp+0x0D] 7D23: F7 E1 mulw cx 7D25: 03 46 FC add ax,[bp-0x04] 7D28: 13 56 FE adc dx,[bp-0x02] 7D2B: B1 04 mov cl,0x04 read 4 sectors 7D2D: E8 C2 00 calln read_nsectors go to 7DF2 7D30: 72 D7 jc io_error go to 7D09 7D32: EA 00 02 70 00 jmpf 0x0070:0x0200 start the system! read_sector: // // all these push generate a Disk Address Packet structure // note that the input is dx,ax with the LBA sector number // and bx with the address where the sector is to be read (0x0700) // // the dx,ax notation is "advanced" and here they compute // the old fashion read in al,ch,cl,dh,dl and es:bx even // if we are to read with the new extended read... This // is the opposite of that computation: // (Cylinder x Heads + Selected Head) x Sectors per Track + Selected Sector - 1 // 7D37: 52 push dx block # (high) 7D38: 50 push ax block # (low) 7D39: 06 push es buffer segment 7D3A: 53 push bx buffer address 7D3B: 6A 01 push 0x0001 # of blocks to transfer 7D3D: 6A 10 push 0x0010 packet size (16 bytes) + reserved 7D3F: 91 xchg ax,cx mov ax in cx in 1 byte 7D40: 8B 46 18 mov ax,[bp+18] get our sectors per track 7D43: A2 26 05 mov [0x0526],al copy our sectors per track info 7D46: 96 xchg ax,si mov si,ax (sectors per track) 7D47: 92 xchg ax,dx mov ax,dx 7D48: 33 D2 xor dx,dx clear dx 7D4A: F7 F6 div si dx,ax / si => ax (remainder in dx) 7D4C: 91 xchg ax,cx restore ax 7D4D: F7 F6 div si dx,ax / si => ax (remainder in dx) 7D4F: 42 inc dx 7D50: 87 CA xchg cx,dx 7D52: F7 76 1A div [bp+0x1A] dx,ax / [bp+1A] (# of heads) 7D55: 8A F2 mov dh,dl duplicate remainder 7D57: 8A E8 mov ch,al ch = low eight bits of cylinder # 7D59: C0 CC 02 ror ah,2 put bits 0..1 in bits 6..7 7D5C: 0A CC or cl,ah cl = sector number + high cylinder bits 7D5E: B8 01 02 mov ax,0x0201 read disk command (non-extended!), 1 sector 7D61: 80 7E 02 0E cmp [bp+0x02],0x0E extended detected? 7D65: 75 04 jne not_extended go to 7D16B 7D67: B4 42 mov ah,42 extended read disk command 7D69: 8B F4 mov si,sp pointer to the disk address packet not_extended: 7D6B: 8A 56 24 mov dl,[bp+0x24] drive number 7D6E: CD 13 int 13 floppy/hard disk service 7D70: 61 popaw get rid of the disk address packet 7D71: 61 popaw restore all the registers 7D72: 72 0A jc read_err go to 7D7E 7D74: 40 inc ax next sector (dx:ax + 1) 7D75: 75 01 jne no_carry go to 7D78 7D77: 42 inc dx manage overflow (32 bits number!) no_carry: 7D78: 03 5E 0b add bx,[bp+0x0B] add size of 1 sector to address 7D7B: 49 dec cx read more sectors? 7D7C: 75 77 jne read_more go to 7DF5 read_err: 7D7E: C3 retn 7D7F: 03 0x7D83 -- message "\r\nDisque non systeme \377" 7D80: 18 0x7D99 -- message "\r\nErreur d'E/S \377" 7D81: 01 0x7D83 -- message "\r\nDisque non systeme \377" 7D82: 27 0x7DAA -- message "\r\nRemplacez-le et appuyez sur une touche \r\n\0" 7D83: 0D 0A 44 69 73 71 75 65 20 6E 6F 6E 20 73 79 73 74 65 6D 65 20 FF 7D99: 0D 0A 45 72 65 75 72 20 64 27 45 2F 53 20 20 FF 7DAA: 0D 0A 52 65 6D 70 6C 61 63 65 7A 2D 6C 65 20 65 74 20 61 70 70 75 7DC0: 79 65 7A 20 73 75 72 20 75 6E 65 20 74 6F 75 63 68 65 20 20 0D 0A 00 7DD7: 00 .byte 0x00 unused 7DD8: 49 4F 20 20 20 20 20 20 53 59 53 "IO SYS" 7DE3: 4D 53 54 4F 53 20 20 20 53 59 53 "MSDOS SYS" 7DEE: 7F 01 00 .byte 0x7F, 0x01, 0x00 seems unused read: 7DF1: 41 inc cx it is assumed that cx = 0 on entry, so read 1 sector read_nsectors: 7DF2: BB 00 07 mov bx,0x0700 address where sector is to be read load_next: 7DF5: 60 pushaw save all registers 7DF6: 66 6A 00 push 0x00000000 start a read structure on the stack 7DF9: E9 3B FF jmpn load_sector go to 7D37 7DFC: 00 00 .byte 0x00, 0x00 unused 7DFE: 55 AA .byte 0x55, 0xAA valid MBR magic word Win2k Boot SectorNow there is my Win2k boot sector. It is very similar with some better handling such as interrupt protections. Also this booter will use the LBA only when necessary (i.e. whenever it has to load a sector over the drive limits, thus if over 8Gb or so) Since I moved my Win2k partition from partition 1 to partition 2, I had to change the value at offset 0x001C (0x0000003F is for partition 1). This represents the sector # of the partition where Win2k is to be booted from. (Note: You will find that number looking at the very first sector of your hard drive since that's where you have the partition.) This makes the boot go a little way further but it is not enough. What the MBR does is load some sort of NTFS loader. That loader looks for the file named boot.ini on your C: drive. You may have heard of boot.ini since it has existed for a while now. That file includes the drive and partition on which Win2k (applies to WinXP too) was installed and thus should "boot from" (i.e. read the kernel from.) Of course, mine was saying Partition(1) since it was on partition 1 before. I went in and changed the number from 1 to 2 and this time it worked all the way. The boot process succeeded and I can now enjoy Win2k. Note that you will need to make the file not Read Only and since there is no editor in the Rescue Mode of the Win2k or the WinXP CDs, I actually made the change from another Win2k install, copied the file on some Win98 partition and finally copied that file to the Win2k I needed to fix. You could also use a floppy disk. Note that if you used a FAT partition instead of NTFS, you can boot from Fedora Core or some other Linux Rescue and in there you have VI and usually one other editor like pico. # Note: it is assumed that CS is 0x0000 by this time 7C00: EB 52 jmps start go to 7C54 7C02: 90 nop 7C03: 4E 54 46 53 20 20 20 20 "NTFS " 7C0B: 00 02 0x0200 (512) bytes per sector 7C0D: 08 0x08 (64) sectors per cylinder 7C0E: 00 00 number of sectors to read (run time) 7C10: 00 00 00 00 sector to read (relative to start of partition defined in 001C) (run time) 7C14: 00 has LBA capability when not zero (run time) 7C15: F8 media type 7C16: 00 00 0x0000 (0) sectors per FAT (unused) 7C18: 3F 00 0x003F (63) sectors per track 7C1A: FF 00 0x00FF (255) heads 7C1C: 3F 00 00 00 0x003F (63) start of partition (if partition 1, 0x3F) 7C20: 00 00 00 00 sector upper limit (sector max. #) 7C24: 80 physical disk number (always 0x80 for hard drives) 7C25: 00 unused (current head) 7C26: 80 signature (must be 0x80?) 7C27: 00 unused (?) 7C28: DF AD 31 01 00 00 00 00 0x0131ADDF (20032991) total number of sectors in this partition (here ~10Gb) 7C30: 04 00 00 00 00 00 00 00 0x04 (4) logical sector for file $MFT 7C38: DD 1A 13 00 00 00 00 00 0x00131ADD (1252061) logical sector for file $MFTMirr 7C40: F6 00 00 00 0x000000F6 (246) number of sectors per file record segment 7C44: 01 00 00 00 0x01 (1) sectors per index block 7C48: 80 FA 37 7C 33 38 7C 68 volume unique identification number (GUID/Serial Number) 7C50: 00 00 00 00 checksum (always 0...) start: 7C54: FA cli 7C55: 33 C0 xor ax,ax 7C57: 8E D0 mov ss,ax 7C59: BC 00 7C mov sp,0x7C00 set stack at 0x0000:0x7C00 7C5C: FB sti 7C5D: B8 C0 07 mov ax,0x07C0 7C60: 8E D8 mov ds,ax 7C62: E8 16 00 calln check_disk go to 7C7B 7C65: B8 00 0D mov ax,0D00 read sectors at 0x0D00:0000 7C68: 8E C0 mov es,ax 7C6A: 33 DB xor bx,bx 7C6C: C6 05 0E 00 10 mov [0x7C0E],10 read 10 sectors 7C71: E8 53 00 call read go to 7CC7 check_disk: 7C7B: 8A 16 24 00 mov dl,[0x7C24] get disk # 7C7F: B4 08 mov ah,0x08 check disk info from BIOS 7C81: CD 13 int 13 7C83: 73 05 jnc valid_disk_request go to 7C8A 7C85: B9 FF FF mov cx,0xFFFF no valid info, use max. 7C88: 8A F1 mov dh,cl valid_disk_request: 7C8A: 66 0F B6 C6 movzxb eax,dh compute cylinder x heads x sectors 7C8E: 40 inc ax 7C8F: 66 0F B6 D1 movzxb edx,cl 7C93: 80 E2 3F and dl,0x3F 7C96: F7 E2 mulw dx 7C98: 86 CD xchg cl,ch 7C9A: C0 ED 06 shrb ch,6 7C9D: 41 inc cx 7C9E: 66 0F B7 C9 movzxd ecx,cx 7CA2: 66 F7 E1 muld ecx 7CA5: 66 A3 20 00 mov [0x7C20],eax save as the max. to otherwise switch to LBA feature 7CA9: C3 retn The input parameters are saved in the BPB table: Offset Size Comment ====== ==== ======= 0x7C0E 2 number of sectors to read (must be 1 or more) 0x7C10 4 logical sector to read (LBA # on 32 bits) 0x7C14 1 if 0, not checked for LBA availability; if 1 LBA capability available 0x7C18 2 number of sectors per track 0x7C1A 2 number of heads 0x7C1C 4 partition start sector number (partition 1 is at 0x3F usually) 0x7C20 4 old read limit (cylinders x heads x sectors) 0x7C24 1 drive number (usually 0x80 for hard drives) read: 7CC7: 66 60 pushad 7CC9: 1E push ds 7CCA: 06 push es next_sector: 7CCB: 66 A1 10 00 mov eax,[0x7C10] sector to read (relative to partition start) 7CCF: 66 03 06 1C 00 add eax,[0x7C1C] add partition start (partition 1 is at 0x003F) 7CD4: 66 3B 06 20 00 cmp eax,[0x7C20] check against upper limit (LBA needed?) 7CD9: 0F 82 3A 00 jc old_read go to 7D17 7CDD: 1E push ds 7CDE: 66 6A 00 pushd 0 7CE1: 66 50 push eax 7CE3: 06 push es 7CE4: 53 push bx 7CE5: 66 68 10 00 01 00 push 0x00010010 7CEB: 80 3E 14 00 00 cmpb [0x7C14],0x00 disk mode (enhanced LBA or not) 7CF0: 0F 85 0C 00 jne valid_lba go to 7D00 7CF4: E8 B3 FF calln check_lba go to 7CAA 7CF7: 80 3E 14 00 00 cmpb [0x7C14],0x00 7CFC: 0F 84 61 00 je io_error go to 7D61 valid_lba: 7D00: B4 42 mov ah,42 read floppy/hard disk 7D02: 8A 16 24 00 mov dl,[0x7C24] disk # 7D06: 16 push ss 7D07: 1F pop ds 7D08: 8B F4 mov si,sp 7D0A: CD 13 int 13 read 1 sector 7D0C: 66 58 pop eax 7D0E: 5B pop bx 7D0F: 07 pop es 7D10: 66 58 pop eax 7D12: 66 58 pop eax 7D14: 1F pop ds 7D15: EB 2D jmps check_error go to 7D44 old_read: 7D17: 66 33 D2 xor edx,edx 7D1A: 66 0F B7 0E 18 00 movzxd ecx,[0x7C18] sectors per track (word extended) 7D20: 66 F7 F1 divd ecx eax / ecx 7D23: FE C2 inc dl 7D25: 8A CA mov cl,dl 7D27: 66 8B D0 mov edx,eax 7D2A: 66 C1 EA 10 shrd edx,10 7D2E: F7 36 1A 00 divw [0x7C1A] number of heads 7D32: 86 D6 xchg dl,dh 7D34: 8A 16 24 00 mov dl,[0x7C24] disk # 7D38: 8A E8 mov ch,al 7D3A: C0 E4 06 shlb ah,06 7D3D: 0A CC or cl,ah 7D3F: B8 01 02 mov ax,0x0201 read 1 sector 7D42: CD 13 int 13 check_error: 7D44: 0F 82 19 00 jc io_error go to 7D61 7D48: 8C C0 mov ax,es increment the segment instead of the address 7D4A: 05 20 00 add ax,0x0020 this is equivalent to bx += 0x0200 7D4D: 8E C0 mov es,ax 7D4F: 66 FF 06 10 00 incd [0x7C10] next sector to read 7D54: FF 0E 0E 00 decw [0x7C0E] number of sectors to read 7D58: 0F 85 6F FF jne next_sector go to 7CCB 7D5C: 07 pop es done with this read request, return 7D5D: 1F pop ds 7D5E: 66 61 popad 7D60: C3 retn io_error: 7D61: A0 F8 01 mov al,[0x7DF8] the message to print (can change) 7D64: E8 09 00 calln print go to 7D70 7D67: A0 FB 01 mov al,[0x7DFB] "\r\nPress Ctrl+Alt+Del to restart\r\n\0" 7D6A: E8 03 00 calln print go to 7D70 7D6D: FB sti ensure interrupts are working hang: 7D6E: EB FE jmps hang go to 7D6E print: 7D70: B4 01 mov ah,0x01 7D72: 8B F0 mov si,ax si equal 0x7D<al> next_char: 7D74: AC lodsb load next character 7D75: 3C 00 cmp al,0x00 7D77: 74 09 je exit_print go to 7D82 7D79: B4 0E mov ah,0x0E print character command 7D7B: BB 07 00 mov bx,0x0007 screen or page where to write (current) 7D7E: CD 10 int 10 7D80: EB F2 jmps next_char go to 7D74 exit_print: 7D82: C3 retn Booting RedHat 9At this time I still have a problem with my Red Hat install. I moved it from one drive partition 2 (/dev/hda2) to another driver partition 6 (/dev/hda6). Usually, all you have to do is add "root=/dev/hda6" in the Grub configuration file and up it comes. In this one, it has a problem reading files on the root partition (I assume it is the root partition...) as follow: attempt to read beyond end of device 03:06: rw=0, want=1219858868, limit=2002491 kernel panic: No init found. Try passing init= to kernel. Before that, we can see nash in action loading everything it is supposed to load with success. So it looks like the loader tries to load my init file from /dev/hda1 (which is limited to 2Gb) instead of /dev/hda6 (which is 10 times bigger with 20Gb and much further away from the beginning of the drive: the partition roughly falls between 40Gb and 60Gb.) If you ask folks, most of the time they will answer you saying something like this: your disk got fried. I can see my disk just fine since I can mount it from my Fedora Core 5 and I don't even need an fsck. It is just plainly fine. The main problem is that /dev/hda2 assumption (I assume...). I regenerated the initrd file in case it was written in there and it didn't seem to make any difference either. Argh! So I looked at the script mkinitrd under Red Hat 9 and tried to rebuild my initrd.img file. This was easy, actually no errors at all (see Booting RAID 1... on that one I checked with Debian and I got plenty of errors). This was nice, so now I can add & remove files from the RAM disk. I put ls and checked out what was going on. ls of /dev shown that everything was fine. Correct /dev/root, /dev/hda and /dev/hdc are present as expected. It still panics though. Then after the mount of /dev/root I looked in /sysroot (what it is being mounted under) and all my files are right there; right name, etc. The init file is there too and ls in the RAM disk can see it just fine. Then the RAM disk exists and the kernel barks these out of range errors and panics. I'm kind of out of ideas right now (probably because it's really late too 8-). The few references to this error on the net say that happens when you specify the wrong file system in your /etc/fstab. I tried to change from ext3 to ext2 and I do get errors, much different and of course it won't boot since in this case it cannot mount the root drive. Some progress? Now I tried to do the ls right after the pivot_root and that fails. It looks very much like the pivot_root fails really bad. I'll have to look a little closer, but it could be that I need a few more instructions to make it work properly... more later! Booting RAID 1Another booting problem... I have another system which I use to develop under Linux. It had a single hard drive and a CD-ROM. Good enough in most cases, but I really wanted a RAID Level 1. So I decided to use /dev/md[5-10] for my different partitions. It seems that you should be able to boot from any partition, but at this time I get an error: md: md driver 0.90.0 MAX_MD_DEVS=256, MD_SB_DISK=27 Journal Block Device driver loaded EXT3-fs:unable to read superblock EXT2-fs:unable to read superblock cramfs: wrong magic pivot_root: no such file or directory /sbin/init: 432: cannot open dev/console: no such file Kernel panic: Attempted to kill init! I checked out this one page: Installing Debian with SATA based RAID from Transtronics (after checking many others!) And this one gave me the answer to my problem. What I'm still very much wondering about is: how/when is that initrd.img file regenerated and/or modified?! I'm wondering because I got the opposite problem: I first have 160Gb x 2 in that system and I switch to a single drive because these 2 hard disks went in another system. Okay! So I had just one drive and I could make it boot (after a few tweaks as described in my pivot_root problem page.) And that changed the initrd.img file with the proper ROOT entry. But when trying to get this new 300Gb x 2 work, it would not! It just was saying that it could not mount the drives (with the errors I just presented; that what that meant and not that the hard disk was bad as some people would most certainly tell you.) Okay... so... here is the result of my research:
# cd # cp /boot/initrd.img initrd.gz # gunzip initrd # mount -o ro,loop=/dev/loop1 initrd /mnt/initrd Notice that since the initrd file is compressed with gzip, you first need to gunzip it (may not be necessary on newer systems!) Also, I very strongly suggest that you make a copy so you have your original in a safe place! You will of course need to change each parameter to fit your system. loop1 may already be in use, just try loop2, loop3, etc. The filename for you initrd image usually includes the version of the image (i.e. initrd-2.4.20-8.img). The name /mnt/initrd is the name of any folder. Note that I put ro in the options because you cannot really write in the files you see in there... So it's just safer to mount the whole thing read-only.
So? What's that you're looking for in there now?! If you need some special file systems
or driver support, you can verify that these are present under
At least under Debian, you have a directory named /etc/mkinitrd inside which you have a configuration file. It is not extremely important to change it since you can specify most of the options on the command line. Yet, if you are not going to change your system all the time, it's easier to keep the info in one place and thus in that one file. Change the ROOT to /dev/md0 or some other multi-disk. Change the MODULES to dep. Change other variables if it seems that it is required.
There is a command (at least under Debian) to re-generate your initrd file. This is called mkinitrd. Use the -o option to specify the output is an excellent idea to not overwrite another initrd.img file. # mkinitrd -o /boot/initrd-md.img
For more info about this command, try
Copying a partitionThere are several ways to copy partitions which enable you or not to grow/reduce an existing partition. Some people will use the cp command. This works under Linux when you use the right flags (i.e. making sure that devices and FIFOs are copied as special files and not fopen()'ed) Similar to the cp command, you can use the tar command. This one too knows when it changes device and it can recognize special devices. A little better to my pointer of view: the dump + restore commands. These can be used to duplicate an entire partition file by file. Thus you can (like with cp and tar) copy a partition to another when both have different sizes and different file formats. Use a level of 0, and if you have /tmp on a separate partition, just don't copy it and tell dump + restore to use /tmp to save their temporary files. You will get only one error in this case: a warning that lost+found already exists. Now, if both your source and destination partitions have exactly the same size and exactly the same file format, you should use dd since it is a lot faster. It will read each source sector and write it on the destination as is. (actually, it can be a lot slower, not faster; but it sure copies your drive as is; i.e. it generates a perfect clone). dd will create a destination which is 100% the same and thus you need the exact same number of sectors (or more wasted sectors...) on the destination. Note that all of these can be used over your network if you have ssh/sshd working (which is pretty much the default on Linux these days.) So, what you can do with dd is copy an entire partition from one computer to another: dd if=/dev/hda1 | ssh copy.com 'dd of=/dev/hde1' This command copies partition hda1 from the source computer to hde1 on the destination computer (which name is copy.com.) Of course, for large partitions, this will take about forever, but it's fun since it goes from one computer to another. blah blah blah... maybe I'm too much of a geek 8-). Now there is no limit to the copying of partition, is there? 8-) This means next time you want to build a new computer, you can just copy entire partitions from computer A to computer B (say, your /boot and / partitions, then just change the /etc/hosts and other network identifiers, and voila!) I'm using this technique right now to copy a Win 2k partition from one to another computer. This way I will be able to run Windows from either of my systems. This is neat... we'll see if it works okay (since the hardware will be different, windows may just choke!) Okay, it choked... It says "unrecognized boot device". Looks like it's trying to read from a SATA using a totally standard IDE driver. Or something like that. I may try to install the darn thing instead... it's going to destroy my stage 1 boot loader, unless I copy that first. Hmmm... More later! |