9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
From: tlaronde@polynum.com
To: Fans of the OS Plan 9 from Bell Labs <9fans@cse.psu.edu>
Subject: [9fans] Re: [explanations] MBR messed up on installation
Date: Mon, 28 May 2007 20:05:58 +0200	[thread overview]
Message-ID: <20070528180558.GA162@polynum.com> (raw)
In-Reply-To: <20070523183556.GA2037@polynum.com>

Hello,

The time for me to discover Plan 9 and to be able to dig/edit/compile
under Plan 9 for the patches here are, at least, explanations about the
process on i386 involving CHS addressing, the BIOS and the partition
table.

Position of the problem
1. After installing Plan 9 on an i386 with already NetBSD installed,
the partition table hold by the MBR was changed: the absolute start
(sector in LBA) for the NetBSD partition was changed, the CHS values too
(but irrelevant in part because out of reach of CHS addressing), leading
to the impossibility to boot in NetBSD.

The story

ATA CHS addressing scheme

2. The ATA standard specified a CHS based addressing scheme on 28
bits, allowing theorically 128 GiB of disk space (2^28 for sectors, with
512 bytes per sector).
The mapping was this:
C	H	S
16	4	8

3. The PC BIOS provides services. The INT 13H is dedicated to disk
access, and one of its function deals with CHS addressing.
The CHS addressing passed to the BIOS was supposed, in legacy PC, to be
passed as is to the ATA controler.
But, since it's the PC, the CHS addressing used by the BIOS is distinct
from the CHS addressing used by ATA...

In the BIOS:
C	H	S
10	8	6

that is only 24 bits.

Furthermore, to make things even more interesting, while cylinders and
heads are indexed starting at 0, sectors are indexed starting at 1:

C: 0..1023
H: 0..255
S: 1..63

To continue in the same mood, Microsoft made a fault in the initial
programmation, and didn't even allow the maximum of 256 heads, leading
to:

C: 0..1023
H: 0..254
S: 1..63

4. The main result, since the legacy BIOS passes the CHS values as is to
the ATA controler, is that only the minimal common denominator between
the two specification can be used:

C	H	S
10	4	6	

that is the limit: 1024 * 16 * 63 sectors hence the 504MiB.

5. Since the disk finally exceeded this 504MiB, a hack was designed. The
BIOS was modified to _not_ pass the specification as is to the ATA
controler, but to do a mapping between BIOS CHS addressing and ATA CHS
addressing, allowing the use of the full range (minus the
idiosyncrasies) of the 24 bits.

This is called ECHS, and this works even with legacy boot loaders using
INT 13H services, since this is the BIOS that does the job. This has
nothing to do with LBA, but this allows disk up to:

1024 * 254 * 63 sectors that is 7.8GiB.

The first problem is that the cylinder boundary in BIOS CHS addressing
may not match the hardware ATA CHS cylinder boundary. The "correct"
value is to align on a hardware boundary (if this makes sense).

Some fdisk(8) programs try to find a match between BIOS "cylinders" and
ATA (hardware) cylinders (that is what NetBSD seems to do):

------ fdisk on NetBSD
Disk: /dev/rwd0d
NetBSD disklabel disk geometry:
cylinders: 38792, heads: 16, sectors/track: 63 (1008 sectors/cylinder)
total sectors: 39102336

BIOS disk geometry:
cylinders: 1024, heads: 255, sectors/track: 63 (16065 sectors/cylinder)
total sectors: 39102336
------

The first specification is the hardware description (ATA).
The second is an ECHS description.

6. If the disk capacity exceeds the BIOS CHS addressing capabilities,
the only option is for the boot loader to use LBA services (and for the
BIOS to provide these services).

7. The only value that shall not be touched for a chunk (partition)
already in use in the absolute sector value (LBA) [and the problem is
that Plan 9 fdisk modifies this value].

The partition table.

8. Since the MBR is a "BIOS" program---by a signature, and because, due
to its size, it has to use BIOS services---the CHS values are already
computed in the partition table for a direct use by the BIOS services,
i.e. in the partition table one finds BIOS CHS values.

Here is the description in pseudo-code (pseudo because it is not
portable, assumes packing of fields and little endianness):

/* 3 bytes i.e. 24 bits */
struct Chs {
	unsigned int head: 8;
	unsigned int sector: 6;
	unsigned int cylh: 2; /* high two bits of cylinder */
	unsigned int cyll: 8; /* low eight bits of cylinder */
};

/* 16 bytes */
struc Part {
	uint8_t status;
	struct Chs Chs_start;
	uint8_t type;
	struct Chs Chs_end;
	uint32_t lba_start;
	uint32_t size_in_sectors;
};

9. In the MBR the partition table starts at offset 0x1BE (446), with 
4 Part entries (4 * 16 = 64) and the last two byte with the signature.

Hence, it is easy to see the details of the computation (here using
NetBSD tool hexdump(1) ---same can be done with xd(1)--- and awk(1)):

------awk script
{
	print "partition:", NR
	print "status:", ($1 == 128) ? "ACTIVE" : "NOT ACTIVE"
	print "start CHS:", int($3 / 64) * 256 + $4, $2, $3 % 64
	printf "type: %#x\n", $5 
	print "end CHS:", int($7 / 64) * 256 + $8, $6, $7 % 64
	print "start LBA:", $9 + $10 * 256 + $11 * 65536 + $12 * 16777216
	print "size in sectors:", $13 + $14 * 256 + $15 * 65536 + $16 * 16777216
	print ""
}
-----

Looking at the NetBSD computed mbr :

$ hexdump -s 0x1BE -n 64 -e '16/1 "%u " "\n"' /tmp/mbr | awk -f mbrtbl.awk

partition: 1
status: NOT ACTIVE
start CHS: 0 1 1
type: 0x39
end CHS: 138 254 63
start LBA: 63
size in sectors: 2232972

partition: 2
status: NOT ACTIVE
start CHS: 139 139 1
type: 0xa9
end CHS: 1023 134 63
start LBA: 2241792
size in sectors: 14329728

partition: 3
status: ACTIVE
start CHS: 1023 135 1
type: 0xa9
end CHS: 1023 116 63
start LBA: 16571520
size in sectors: 8192016

partition: 4
status: NOT ACTIVE
start CHS: 0 0 0
type: 0
end CHS: 0 0 0
start LBA: 0
size in sectors: 0

As can be seen the values are ECHS (more than 16 heads).
Have no sense when we cross the 7.8 GiB border.

TODO: track the Plan 9 sources to see the manipulation done.
Found where the hardware description is obtained (for the ATA CHS
values at least).
Problem of portability (this is i386 specific).
Why is fdisk(8) recomputing the absolute sector to put it in a BIOS
cylinder boundary (that has almost no sense). And why does it redefines
the starting sector of a partition it has neither created nor modified
(for the geometry). It seems that this is modified when setting the
ACTIVE flag, that is all the record is overwritten, including recomputed
CHS and LBA values.

To be continued.
-- 
Thierry Laronde (Alceste) <tlaronde +AT+ polynum +dot+ com>
                 http://www.kergis.com/
Key fingerprint = 0FF7 E906 FBAF FE95 FD89  250D 52B1 AE95 6006 F40C


  parent reply	other threads:[~2007-05-28 18:05 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-23 18:35 [9fans] " tlaronde
2007-05-24 12:55 ` erik quanstrom
2007-05-24 13:13   ` Paweł Lasek
2007-05-28 18:05 ` tlaronde [this message]
2007-05-28 23:31   ` [9fans] Re: [explanations] " Paweł Lasek
2007-05-29  0:14     ` tlaronde

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070528180558.GA162@polynum.com \
    --to=tlaronde@polynum.com \
    --cc=9fans@cse.psu.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).