[Kos-dev] ATA & LBA, more informations
Hervé Poussineau
kos-dev@enix.org
Wed, 13 Feb 2002 22:17:44 +0100
C'est un message de format MIME en plusieurs parties.
------=_NextPart_000_0045_01C1B4DC.429684D0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 8bit
Salut !
J'ai bien essayé ton code, et c'est vrai, il marche pas avec mon disque.
Mais pour avoir fait ça, j'ai intégré ton code dans le mien, et tu as le
résultat dans le fichier joint : lecture de la table des partitions avec
deux méthodes. J'ai pas le courage de comparer les procédures hd_read et
hd_read_thomas, mais tu devrais trouver ton bonheur là-dedans...
@+, pour les résultats de ton enquète...
Hervé
------=_NextPart_000_0045_01C1B4DC.429684D0
Content-Type: application/octet-stream;
name="LISTPART.C"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="LISTPART.C"
#include <conio.h>
#include <dos.h> /* juste pour delay */
#include <stdio.h>
#define REG_BASE0 0x1F0 /* base register of controller 0 */
#define REG_BASE1 0x170 /* base register of controller 1 */
#define REG_DATA 0 /* data register (offset from the base =
reg.) */
#define REG_PRECOMP 1 /* start of write precompensation */
#define REG_COUNT 2 /* sectors to transfer */
#define REG_SECTOR 3 /* sector number */
#define REG_CYL_LO 4 /* low byte of cylinder number */
#define REG_CYL_HI 5 /* high byte of cylinder number */
#define REG_LDH 6 /* lba, drive and head */
#define LDH_DEFAULT 0xA0 /* ECC enable, 512 bytes per =
sector */
#define LDH_LBA 0x40 /* Use LBA addressing */
#define ldh_init(drive) (LDH_DEFAULT | ((drive) << 4))
/* Read only registers */
#define REG_STATUS 7 /* status */
#define STATUS_BSY 0x80 /* controller busy */
#define STATUS_RDY 0x40 /* drive ready */
#define STATUS_WF 0x20 /* write fault */
#define STATUS_SC 0x10 /* seek complete (obsolete) */
#define STATUS_DRQ 0x08 /* data transfer request */
#define STATUS_CRD 0x04 /* corrected data */
#define STATUS_IDX 0x02 /* index pulse */
#define STATUS_ERR 0x01 /* error */
#define REG_ERROR 1 /* error code */
#define ERROR_BB 0x80 /* bad block */
#define ERROR_ECC 0x40 /* bad ecc bytes */
#define ERROR_ID 0x10 /* id not found */
#define ERROR_AC 0x04 /* aborted command */
#define ERROR_TK 0x02 /* track zero error */
#define ERROR_DM 0x01 /* no data address mark */
/* Write only registers */
#define REG_COMMAND 7 /* command */
#define CMD_IDLE 0x00 /* for w_command: drive idle */
#define CMD_RECALIBRATE 0x10 /* recalibrate drive */
#define CMD_READ 0x20 /* read data */
#define CMD_WRITE 0x30 /* write data */
#define CMD_READVERIFY 0x40 /* read verify */
#define CMD_FORMAT 0x50 /* format track */
#define CMD_SEEK 0x70 /* seek cylinder */
#define CMD_DIAG 0x90 /* execute device diagnostics */
#define CMD_SPECIFY 0x91 /* specify parameters */
#define ATA_IDENTIFY 0xEC /* identify drive */
#define REG_CTL 0x206 /* control register */
#define CTL_NORETRY 0x80 /* disable access retry */
#define CTL_NOECC 0x40 /* disable ecc retry */
#define CTL_EIGHTHEADS 0x08 /* more than eight heads */
#define CTL_RESET 0x04 /* reset controller */
#define CTL_INTDISABLE 0x02 /* disable interrupts */
#define SECTOR_SIZE 512
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
void hd_sethd(word reg_base, byte hd);
void partition(dword offset, int methode);
void fat_info(dword sector, int methode);
word hd_reg_base =3D 0;
byte hd_hd =3D 0;
void hd_sethd(word reg_base, byte hd)
{
hd_reg_base =3D reg_base;
hd_hd =3D hd;
}
int hd_wait(dword block)
{
long ticks =3D 5000L;
byte status;
while (ticks-- > 0) {
status =3D inp(hd_reg_base + REG_STATUS);
if ((status & STATUS_BSY) =3D=3D 0) break;
delay(1);
}
if (ticks =3D=3D -1) {
printf("%s line %d : timeout in reading at LBA =3D %lu\n", __FILE__, =
__LINE__, block);
return 1;
}
return 0;
}
int hd_input_thomas(void *buffer2, word len, dword sector_num, byte cmd)
{
int sect =3D (sector_num & 0xff);
int cyl_lo =3D (sector_num >> 8) & 0xff;
int cyl_hi =3D (sector_num >> 16) & 0xff;
int head =3D ((sector_num >> 24) & 0xf) | 0x40 /* LBA */;
int device =3D hd_hd;
int timeout;
int i;
byte status;
word *buffer =3D (word *)buffer2;
int ioaddr =3D hd_reg_base;
#define ATA_STATUS REG_STATUS
#define ATA_S_BSY STATUS_BSY
#define ATA_A_nIEN CTL_INTDISABLE
#define ATA_A_4BIT LDH_DEFAULT
#define ATA_DRIVE REG_LDH
#define ATA_ALTPORT REG_CTL
#define ATA_SECTOR_COUNT REG_COUNT
#define ATA_ERROR REG_ERROR
#define ATA_CYL_MSB REG_CYL_HI
#define ATA_CYL_LSB REG_CYL_LO
#define ATA_SECTOR_NUMBER REG_SECTOR
#define ATA_CMD REG_COMMAND
#define ATA_C_READ CMD_READ
#define ATA_S_DRQ STATUS_DRQ
#define MASTER 0
#define ATA_MASTER (0 << 4)
#define ATA_SLAVE (1 << 4)
#define inb(a) inp(a)
#define inw(a) inpw(a)
#define outb(a,b) outp(b,a)
#define usleep(a) delay(a)
#define printk printf
#define ATA_D_IBM LDH_LBA | LDH_DEFAULT
for(timeout =3D 0; timeout < 30000; timeout++)
{
status =3D inb(ioaddr + ATA_STATUS);
if(!(status & ATA_S_BSY))
break;
=20
usleep(1);
}
if(timeout =3D=3D 30000)
printk("TIMEOUT");
outb(ATA_A_nIEN | ATA_A_4BIT, ioaddr + ATA_ALTPORT);
/* select drive */
outb(ATA_D_IBM
| (device =3D=3D MASTER) ? ATA_MASTER : ATA_SLAVE
| head,=20
ioaddr + ATA_DRIVE);
// outb(0, ctrl->ioaddr + ATA_PRECOMP);
outb(1, ioaddr + ATA_SECTOR_COUNT);
outb(sect, ioaddr + ATA_SECTOR_NUMBER);
outb(cyl_lo, ioaddr + ATA_CYL_LSB);
outb(cyl_hi, ioaddr + ATA_CYL_MSB);
/* FOR THE MOMENT WE DON'T CARE ABOUT THE OPERATION TYPE ... ALWAYS
READ ... */
outb(ATA_C_READ, ioaddr + ATA_CMD);
for(timeout =3D 0; timeout < 30000; timeout++)
{
status =3D inb(ioaddr + ATA_STATUS);
if(!(status & ATA_S_BSY))
break;
usleep(1);
}
if(timeout =3D=3D 30000)
printk("TIMEOUT");
if(!(status & ATA_S_DRQ))
{
printk("Error (0x%x)\n", inb(ioaddr + ATA_ERROR));
return -1;
}
for(i =3D 0; i < 256; i++)
buffer[i] =3D inw(ioaddr);
return 0;
}
int hd_input(void *buffer, word len, dword block, byte cmd)
{
word n;
word *buf =3D buffer;
if (hd_wait(block)) return 1;
outp(hd_reg_base + REG_PRECOMP, 0);
outp(hd_reg_base + REG_COUNT, len);
outp(hd_reg_base + REG_SECTOR, (block >> 0) & 0xFF);
outp(hd_reg_base + REG_CYL_LO, (block >> 8) & 0xFF);
outp(hd_reg_base + REG_CYL_HI, (block >> 16) & 0xFF);
outp(hd_reg_base + REG_LDH, LDH_LBA | ldh_init(hd_hd) | ((block >> 24) =
& 0x7));
outp(hd_reg_base + REG_CTL, CTL_EIGHTHEADS | CTL_INTDISABLE); /* > a 8 =
tetes */
if (hd_wait(block)) return 1;
outp(hd_reg_base + REG_COMMAND, cmd);
if (hd_wait(block)) return 1;
for (n =3D 0; n < SECTOR_SIZE*len/2; ) {
word x =3D inpw(hd_reg_base + REG_DATA);
buf[n++] =3D x;
}
if (inp(hd_reg_base + REG_STATUS) & STATUS_ERR) {
printf("%s line %d : cmd 0x%02x at LBA =3D %lu (status =3D %02x, error =
=3D %02x)\n", __FILE__, __LINE__, cmd, block, inp(hd_reg_base + =
REG_STATUS), inp(hd_reg_base + REG_ERROR));
return 1;
}
return 0;
}
int hd_read(void *buffer, word len, dword sector, int methode)
{
if (methode =3D=3D 0)
return hd_input(buffer, len, sector, CMD_READ);
else
return hd_input_thomas(buffer, len, sector, CMD_READ);
}
int main(void)
{
clrscr();
hd_sethd(0x170, 1);
puts("------- READ METHODE HERVE ------");
partition(0, 0);
puts("------- READ METHODE THOMAS ------");
partition(0, 1);
return 0;
}
/* =
************************************************************************ =
*/
typedef struct {
byte status_;
byte startHead_;
byte startSecCyl_[2];
byte type_;
byte endHead_;
byte endSecCyl_[2];
dword bootSec_;
dword numSec_;
} PartitionEntryStruct;
typedef struct {
byte bootCode_[0x1BE];
PartitionEntryStruct entries_[4];
word iDCode_;
} PartitionSectorStruct;
char *nom_type(byte type)
{
static struct {
byte value;
char *name;
} types[] =3D {
{ 0x00, "None" },
{ 0x01, "FAT12" },
{ 0x02, "XENIX" },
{ 0x03, "XENIX" },
{ 0x04, "FAT16" },
{ 0x05, "Ext. part." },
{ 0x06, "FAT16 >32M" },
{ 0x07, "NTFS or HPFS" },
{ 0x0A, "Boot Mgr" },
{ 0x0b, "FAT32" },
{ 0x0c, "FAT32" },
{ 0x0e, "FAT16" },
{ 0x0f, "Ext. part." },
{ 0x51, "Ext. part. Ontrack" },
{ 0x64, "Novell" },
{ 0x75, "PCIX" },
{ 0xdb, "CPM/Concurrent" },
{ 0xff, "BBT" },
};
static char unknown[] =3D "UNKNOWN";
int i;
for (i =3D 0; i < sizeof(types) / sizeof(types[0]); i++)
if (types[i].value =3D=3D type)
return types[i].name;
return unknown;
}
void partition(dword offset, int methode)
{
int i;
dword extended =3D 0;
PartitionSectorStruct pt;
hd_read(&pt, 1, offset, methode);
/* is partition table valid ? */
for (i =3D 0; i < 4; i++) {
if (pt.entries_[i].type_ =3D=3D 0x05 || pt.entries_[i].type_ =3D=3D =
0x0f)
extended =3D pt.entries_[i].bootSec_ + offset;
if (pt.entries_[i].status_ & ~0x80)
return;
}
printf("Partition at offset %lu\n", offset);
puts("Boot Type Cyl Head Sect Cyl Head Sect Boot Sct Num Sect");
puts("=3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D =
=3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D =
=3D=3D=3D=3D=3D=3D=3D=3D");
for (i =3D 0; i < 4; i++) {
printf("0x%02x 0x%02x %4d %4d %4d %4d %4d %4d %8lu %8lu %s\n",
pt.entries_[i].status_,
pt.entries_[i].type_,
pt.entries_[i].startSecCyl_[1] + ((pt.entries_[i].startSecCyl_[0] =
>> 6) << 8),
pt.entries_[i].startHead_,
pt.entries_[i].startSecCyl_[0] & 0x3f,
pt.entries_[i].endSecCyl_[1] + ((pt.entries_[i].endSecCyl_[0] >> 6) =
<< 8),
pt.entries_[i].endHead_,
pt.entries_[i].endSecCyl_[0] & 0x3f,
pt.entries_[i].bootSec_,
pt.entries_[i].numSec_,
nom_type(pt.entries_[i].type_)
);
if (pt.entries_[i].type_ =3D=3D 0x01
|| pt.entries_[i].type_ =3D=3D 0x04
|| pt.entries_[i].type_ =3D=3D 0x06
|| pt.entries_[i].type_ =3D=3D 0x0e)
fat_info(pt.entries_[i].bootSec_, methode);
} putchar('\n');
if (extended)
partition(extended, methode);
}
/* =
************************************************************************ =
*/
typedef struct fat_bootsector {
byte Jump[3];
byte OEM_ID[8];
word bytes_per_sector;
byte sectors_per_cluster;
word reserved_sectors;
byte number_of_FATs;
word root_dir_entries; // Reserved1 for FAT32
word number_of_sectors; // Reserved1 for FAT32
byte MediaDescriptor;
word sectors_per_FAT;
word TrackSize;
word HeadCount;
dword StartSector;
dword big_number_of_sectors;
word Drive;
byte signature;
dword serial_number;
byte label[11];
byte FSID[8];
byte Loader[448];
word magic_number; // 0xaa55
};
void fat_info(dword sector, int methode)
{
struct fat_bootsector bs;
hd_read(&bs, 1, sector, methode);
printf(" fat_info : FS=3D%8.8s magic_number=3D%04x", bs.FSID, =
bs.magic_number);
putchar('\n');
}
------=_NextPart_000_0045_01C1B4DC.429684D0--