ATAPI can identify a device correctly

This commit is contained in:
Nigel Barink 2021-12-01 00:00:45 +01:00
parent 5a68f77b33
commit 2db83b33e1
11 changed files with 387 additions and 7 deletions

View File

@ -17,7 +17,8 @@ $(BUILD_DIR)/idt.o \
$(BUILD_DIR)/pci.o \
$(BUILD_DIR)/pic.o \
$(BUILD_DIR)/string.o \
$(BUILD_DIR)/pcidevice.o
$(BUILD_DIR)/pcidevice.o \
$(BUILD_DIR)/atapiDevice.o
@ -108,3 +109,6 @@ $(BUILD_DIR)/pci.o:
$(BUILD_DIR)/pcidevice.o:
$(CPP) -c $(SRC_DIR)/kernel/pci/pciDevice.cpp -o $(BUILD_DIR)/pcidevice.o $(CFLAGS) -fno-exceptions -fno-rtti
$(BUILD_DIR)/atapiDevice.o:
$(CPP) -c $(SRC_DIR)/kernel/drivers/atapi/atapiDevice.cpp -o $(BUILD_DIR)/atapiDevice.o $(CFLAGS) -fno-exceptions -fno-rtti

View File

@ -19,6 +19,10 @@ Multiboot information can be read by the kernel.
![PCI enumeration](screenshots/PCIBusEnumeration.png) \
Enumerating the PCI bus
![ATAPI CD-ROM Identification](screenshots/CD-ROM_Identify.png) \
Correctly identified our ATAPI device 🎉
________________________
### The goal

BIN
screenshots/CD-ROM_Identify.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,131 @@
#include "atapiDevice.h"
#define IS_BIT_SET(x, bit) ((x >> bit & 0x1) == 1)
void ATA_DEVICE::Soft_Reset(uint8_t DEVICE_CHANNEL,DEVICE_DRIVE drive){
printf("Soft reseting drive...\n");
outb(channels[DEVICE_CHANNEL].base + 7 , 0x4);
// wait a bit..
for(int i = 0 ; i < 1000000; i++){
asm volatile("NOP");
}
outb(channels[DEVICE_CHANNEL].base + 7 , 0x0);
}
void ATA_DEVICE::Identify(uint8_t DEVICE_CHANNEL,DEVICE_DRIVE drive ){
// lets ignore which port we actually want to check for now !
/*
THE STEPS INVOLVED
1. Select the target drive by sending master (0x0A) or slave (0x0B) to the
drive select IO port
2. Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
3. Send the identify command (0xEC) to the command IO port
4. Read the status port
4.2 If the value is 0x0 the drive does not exist
4.3 If it has any other value continue
5. poll the status port until bit 7 is clear.
6. Check if the LBAmid and LBAhi ports are non-zero
6.2. If non-zero stop polling this is not an ATA device
6.3 If zero continue
7. poll status port until bit 3 is set or bit 0 is set
8. if err is clear, read the data from the data port
*/
// Assuming Master here
// Select the target drive
outb(0x176, 0x0A); // on the primary bus select the master drive
// Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
outb(0x172, 0);
outb(0x173, 0);
outb(0x174, 0);
outb(0x175, 0);
// send the identify command;
outb(0x177, 0xA1);
// read the status port
uint8_t status = inb(0x177);
if( status == 0x00){
printf("No drive\n");
return;
}
while(true){
status = inb(0x177);
if( status & (~8))
break;
}
printf("Is this an ATA device?\n");
uint8_t LBAmid = inb(0x174);
uint8_t LBAhi = inb(0x175);
printf("LBAmid: 0x%x, LBAhi: 0x%x\n", LBAmid, LBAhi);
if( LBAhi != 0x0 || LBAmid != 0x0){
printf("Not ATA device.. Stopping..\n");
// return;
}
while(true){
status = inb(0x177);
printf( "Status bit: 0x%x\n", status);
if ( IS_BIT_SET(status, 3)){
printf("Status: ready!\n");
break;
}
if( IS_BIT_SET(status, 0)){
printf("Status: error!\n");
break;
}
}
if( IS_BIT_SET(status, 0) == false){
// READ DATA
uint16_t deviceIdentify [256];
for (int i= 0; i < 256; i++){
uint8_t data = inb(0x170);
uint8_t data2 = inb(0x170);
deviceIdentify[i] = (uint16_t) ( (uint16_t) data << 8 | (uint16_t) data2 );
}
printf("Data received!\n");
}
printf("Error bit was set!\n");
}
void ATA_DEVICE::Read(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
printf("Not implemented");
}
void ATA_DEVICE::Write(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
printf("Not implemented");
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <stdint.h>
#include "../io.h"
#include "../ide/ideCommands.h"
#include "../ide/sampleIDE.definitions.h"
#include "../tty/kterm.h"
/*
* This first driver wil make use of IO ports.
* Doing so means reading or writing from disk is going
* to be very cpu intensive.
*
*/
enum DEVICE_DRIVE{
MASTER = 0xA0,
SLAVE = 0xB0
};
namespace ATA_DEVICE
{
void Identify ( uint8_t, DEVICE_DRIVE );
void Read ( uint8_t, DEVICE_DRIVE );
void Write ( uint8_t, DEVICE_DRIVE );
void Soft_Reset ( uint8_t, DEVICE_DRIVE );
};

View File

@ -0,0 +1,145 @@
#include "atapiDevice.h"
#define IS_BIT_SET(x, bit) ((x >> bit & 0x1) == 1)
bool isPacketDevice(){
uint8_t LBAmid = inb(0x174);
uint8_t LBAhi = inb(0x175);
printf(" LBAmid: 0x%x, LBAhi: 0x%x");
return LBAmid == 0x14 && LBAhi == 0xEB;
}
void ATAPI_DEVICE::Identify(uint8_t DEVICE_CHANNEL,DEVICE_DRIVE drive ){
// lets ignore which port we actually want to check for now !
/* THE STEPS INVOLVED
1. Select the target drive by sending master (0x0A) or slave (0x0B) to the
drive select IO port
2. Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
3. Send the identify command (0xEC) to the command IO port
4. Read the status port
4.2 If the value is 0x0 the drive does not exist
4.3 If it has any other value continue
5. poll the status port until bit 7 is clear.
6. Check if the LBAmid and LBAhi ports are non-zero
6.2. If non-zero stop polling this is not an ATA device
6.3 If zero continue
7. poll status port until bit 3 is set or bit 0 is set
8. if err is clear, read the data from the data port
*/
// Select the target drive
outb(0x176, 0xA0); // on the secondary bus select the master drive
outb(0x170 + 0x206 , 0x0); // write 0 to the controlport for some reason
outb(0x176, 0xA0);
// read the status port
uint8_t status = inb(0x177);
printf("status after drive select: 0x%x\n",status);
if( status == 0x00){
printf("No drive\n");
return;
}
outb(0x176, 0xA0);
// Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
outb(0x172, 0);
outb(0x173, 0);
outb(0x174, 0);
outb(0x175, 0);
// send the identify command;
printf("command sent!\n");
outb(0x177, 0xA1);
// read the status port
uint8_t status2 = inb(0x177);
if( status2 == 0x00){
printf("No drive\n");
return;
}
printf("Waiting until ready...\n");
while(((status2 & 0x80 == 0x80)
&& (status2 & 0x01) != 0x01)
) status2 = inb(0x177);
if(status2 & 0x01){
printf("Error!");
return;
}
// READ DATA
uint16_t deviceIdentify [256] ={0};
for (int i= 0; i < 256; i++){
uint16_t data;
asm volatile ( "in %1, %0"
: "=a"(data)
: "Nd"(0x170) );
deviceIdentify[i] = data ;
}
printf("Model-label (ASCII hex):\n");
for(int i = 27; i < 47; i++){
printf(" %x ",deviceIdentify[i]);
}
printf("\nSerial number (ASCII hex):\n");
for (int i = 10; i < 19; i++){
printf(" %x ", deviceIdentify[i]);
}
printf("\nFirmware revision (ASCII hex):\n");
for (int i = 23; i < 26; i++){
printf(" %x ", deviceIdentify[i]);
}
printf("\nConfiguration: %x\n", deviceIdentify[0]);
printf("\nData received!\n");
}
void ATAPI_DEVICE::Read(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
printf("Not implemented");
}
void ATAPI_DEVICE::Write(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
printf("Not implemented");
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <stdint.h>
#include "../../io.h"
#include "../../ide/ideCommands.h"
#include "../../ide/sampleIDE.definitions.h"
#include "../../tty/kterm.h"
/*
* This first driver wil make use of IO ports.
* Doing so means reading or writing from disk is going
* to be very cpu intensive.
*
*/
enum DEVICE_DRIVE{
MASTER = 0xA0,
SLAVE = 0xB0
};
namespace ATAPI_DEVICE
{
bool isPacketDevice();
void Identify ( uint8_t, DEVICE_DRIVE );
void Read ( uint8_t, DEVICE_DRIVE );
void Write ( uint8_t, DEVICE_DRIVE );
};

View File

@ -7,6 +7,8 @@
#define IS_BIT_SET(x, bit) ((x >> bit & 0x1) == 1)
IDEChannelRegisters channels[2];
IDE_DEVICE ide_devices[4];
inline void CheckProgIF(uint8_t ProgIF){
if( IS_BIT_SET(ProgIF, 0) ) // Is the 0th bit set

View File

@ -5,11 +5,8 @@ struct IDEChannelRegisters{
unsigned short ctrl; // Control Base
unsigned short bmide; // Bus Master IDE
unsigned char nIEN; // IEN (no interrupt)
}channels[2];
};
extern unsigned char ide_buf[2048];
extern unsigned char ide_irq_invoked;
extern unsigned char atapi_packet[12];
struct IDE_DEVICE {
unsigned char Reserved; // 0 (Empty) or 1 (This device exists).
@ -19,7 +16,14 @@ struct IDE_DEVICE {
unsigned short Signature; // Drive Signature
unsigned short Capabilities; // Features.
unsigned int CommandSets; // Command Sets Supported.
unsigned int Size; // Size in Sectors
unsigned int Size; // Size in Sectors (NOTE: Seems unused nowadays as i've only seen the value be zero
unsigned char Model[41]; // Model in string.
} ide_devices[4];
} ;
extern IDEChannelRegisters channels[2];
extern IDE_DEVICE ide_devices[4];
extern unsigned char ide_buf[2048];
extern unsigned char ide_irq_invoked;
extern unsigned char atapi_packet[12];

View File

@ -71,6 +71,33 @@ extern "C" void kernel_main (void);
TestIDEController();
int devNumber = 0 ;
for ( auto device : ide_devices){
if (!device.Reserved)
continue;
printf("Device %d\n" , devNumber);
printf (" Device on Channel: (0x%x) %s\n" ,device.Channel, device.Channel == 0 ? "Primary" : "Secondary");
printf (" Device drive:(0x%x) %s\n" , device.Drive, device.Drive? "Slave" : "Master");
printf (" Device Type:(0x%x) %s\n" , device.Type, device.Type ? "ATAPI" : "ATA");
devNumber ++;
}
// ATAPI_DEVICE::isPacketDevice();
ATAPI_DEVICE::Identify(ATA_SECONDARY, DEVICE_DRIVE::MASTER);
while (true){
//Read time indefinetely

View File

@ -20,6 +20,8 @@ extern "C"{
#include "serial.h"
#include "pci.h"
#include "ide/ide.h"
#include "drivers/atapi/atapiDevice.h"
#define CHECK_FLAG(flags, bit) ((flags) & (1 <<(bit)))