Autor Thema: ATAPI CD/DVD-ROM lesen  (Gelesen 4545 mal)

Ch40zz

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« am: 10. February 2016, 00:28 »
Hey Leute :D
Hab mal wieder ein Problem, welches ich einfach nicht lösen kann.
Momentan versuche ich mithilfe eines SATA devices und AHCI den Inhalt meines ISO images zu lesen.
Die ISO ist als CD/DVD in VirtualBox im Port 0 des SATA controllers, swowohl das Laufwerk als auch die HDD werden von meinem OS erkannt.

Ich habe alles probiert, hier ist ein Link zu einem Tutorial was ich dazu gefunden habe:
1: http://wiki.osdev.org/IDE#Reading_from_an_ATAPI_Drive
2: http://wiki.osdev.org/ATAPI

Ich habe beide gelesen und denke auch verstanden, leider bekomme ich als Antwort auf mein 0xA0 Packet immer nur status=0 und error=0 zurück :(
Hier mein code:
#define ATA_DRIVE_MASTER    0xA0
#define ATA_DRIVE_SLAVE      0xB0
#define ATA_DATA(x)(x)
#define ATA_FEATURES(x)(x+1)
#define ATA_SECTOR_COUNT(x) (x+2)
#define ATA_ADDRESS1(x)(x+3)
#define ATA_ADDRESS2(x)(x+4)
#define ATA_ADDRESS3(x)(x+5)
#define ATA_DRIVE_SELECT(x)(x+6)
#define ATA_COMMAND(x)(x+7)
#define ATA_CONTROL(x)(x+0xC)
#define ATA_DCR(x)(x+0x206)
#define ATA_SELECT_DELAY(bus) \
  {inb(ATA_DCR(bus));inb(ATA_DCR(bus));inb(ATA_DCR(bus));inb(ATA_DCR(bus));}

int atapi_drive_read_sector(uint32_t bus, uint32_t drive, uint8_t is_slave, uint32_t lba, uint8_t *buffer)
{
uint8_t status;
int size;

//0xA8 is "READ SECTORS" command byte.
uint8_t read_cmd[12] = { 0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
read_cmd[9] = 1; //Sector count
read_cmd[2] = (lba >> 24) & 0xFF; //Address to read from
read_cmd[3] = (lba >> 16) & 0xFF;
read_cmd[4] = (lba >> 8) & 0xFF;
read_cmd[5] = (lba >> 0) & 0xFF;

//Enable IRQs
outb(ATA_CONTROL(bus), 0);

//Select drive (4th bit set means select slave)
outb(ATA_DRIVE_SELECT(bus), drive | (is_slave << 4));

//400ns delay
ATA_SELECT_DELAY(bus);

//PIO-Mode
outb(ATA_FEATURES(bus), 0x00);

//Max Size (2048 bytes)
outb(ATA_ADDRESS2(bus), ATAPI_SECTOR_SIZE & 0xFF);
outb(ATA_ADDRESS3(bus), ATAPI_SECTOR_SIZE >> 8);

//ATA-Packet
outb(ATA_COMMAND(bus), 0xA0);

//Is Busy?
while ((status = inb(ATA_COMMAND(bus))) & 0x80)
asm volatile ("pause");

printf("status: %X | Error: %X\n", status, inb(bus + 0x1));

//No Device
if(status == 0)
return 0;

printf("2\n");

//Data request ready? No error?
while (!((status = inb(ATA_COMMAND(bus))) & 0x8) && !(status & 0x1))
asm volatile ("pause");

printf("3\n");
}

...

uint32_t primary_base = (pci_info.address0 & 0xFFFFFFFC) + 0x1F0 * (!pci_info.address0);
uint32_t secondary_base  = (pci_info.address2 & 0xFFFFFFFC) + 0x170 * (!pci_info.address2);

int j, k, m;
for(j = 0; j < 2; j++)
{
for(k = 0; k < 3; k++)
{
for(m = 0; m < 2; m++)
{
uint32_t base = primary_base;
if(m == 1)
base = secondary_base;

if(k == 0)
atapi_drive_read_sector(base, ATA_DRIVE_MASTER, j, 0, buff);
else if(k == 1)
atapi_drive_read_sector(base, ATA_DRIVE_SLAVE, j, 0, buff);
else
atapi_drive_read_sector(base, 0, j, 0, buff);
}
}
}

pci_info.address0 und pci_info.address2 sind nicht 0 sondern Adressen im I/O Raum. (Bit-0 ist gesetzt)
Ich hoffe mir kann Jemand helfen :)
Vielen Dank im Vorraus!
« Letzte Änderung: 10. February 2016, 03:09 von Ch40zz »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 10. February 2016, 14:30 »
Der Code sieht sehr nach IDE aus (außer dass auch da die Portnummern nicht passen würden, wenn ich mich nicht sehr täusche). Wenn du wirklich ein AHCI-Gerät hast, dann ist das nicht, wie du es ansprichst. IDE und AHCI sind zwei ziemlich unterschiedliche Interfaces, auch wenn beide zusammen mit dem ATA-Befehlssatz benutzt werden.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Ch40zz

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 10. February 2016, 14:49 »
Hey Danke, das habe ich auch grade bemerkt xD (War gestern wohl ein wenig müde..)
Soweit hab ich es erstmal geschafft das Laufwerk mit einem SCSI command zu öffnen (Port ist rebased und ready):

uint8_t eject_cmd[12] = { 0x1B, 0, 0, 0, 0x02, 0, 0, 0, 0, 0, 0, 0 };
Danach hab ich versucht Daten mittels 0xA8 zu lesen, sieht nun so aus:
bool ahci_read_atapi(HBA_PORT *port, DWORD lba, DWORD count, WORD *buf, int slot_count)
{
port->is = 0xFFFFFFFF; // Clear pending interrupt bits

int i;
int spin = 0; // Spin lock timeout counter
int slot = find_cmdslot(port, slot_count);
if (slot == -1)
return false;
 
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER*)port->clb;
cmdheader += slot;
cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(DWORD); // Command FIS size
cmdheader->a = 1;
cmdheader->prdtl = 1;

//0xA8 is "READ SECTORS" command byte.
uint8_t read_cmd[12] = { 0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
read_cmd[9] = 1; //Sector count
read_cmd[2] = (lba >> 24) & 0xFF; //Address to read from
read_cmd[3] = (lba >> 16) & 0xFF;
read_cmd[4] = (lba >> 8) & 0xFF;
read_cmd[5] = (lba >> 0) & 0xFF;
 
HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL*)(cmdheader->ctba);
memset((void*)cmdtbl, 0, sizeof(HBA_CMD_TBL));
cmdtbl->prdt_entry[i].dba = (DWORD)buf;
cmdtbl->prdt_entry[i].dbc = 2048;
cmdtbl->prdt_entry[i].i = 1;

//Copy command packet
int j;
for(j = 0; j < 12; j++)
cmdtbl->acmd[j] = read_cmd[j];
 
// Setup command
FIS_REG_H2D *cmdfis = (FIS_REG_H2D*)(&cmdtbl->cfis);
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->pmport = 0;
cmdfis->c = 1; // Command
cmdfis->command = 0xA0; //ATAPI Packet command
cmdfis->featurel = 1;
 
// Wait until the port is no longer busy before issuing a new command
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)))
{
if (spin >= 1000000)
{
printf("Port doesnt respond!\n");
return false;
}

spin++;
}
 
port->ci = 1 << slot; // Issue command
 
// Wait for completion
while (1)
{
// In some longer duration reads, it may be helpful to spin on the DPS bit
// in the PxIS port field as well (1 << 5)
if ((port->ci & (1 << slot)) == 0)
break;
if (port->is & HBA_PxIS_TFES) // Task file error
{
printf("Disk error!\n");
return false;
}
}
 
// Check again
if (port->is & HBA_PxIS_TFES)
{
printf("Disk error!\n");
return false;
}
 
return true;
}

Vielen Dank für die Hilfe, die ersten paar K bytes sind einfach Nuller :D
Nun funktioniert alles!

"Since sectors 0x00-0x0F of the CD are reserved as System Area, the Volume Descriptors can be found starting at sector 0x10. The format of the volume descriptors is as follows..."
« Letzte Änderung: 10. February 2016, 15:37 von Ch40zz »

 

Einloggen