From 2db83b33e1166ea25e509f614767becfe3029099 Mon Sep 17 00:00:00 2001 From: Nigel Date: Wed, 1 Dec 2021 00:00:45 +0100 Subject: [PATCH] ATAPI can identify a device correctly --- Makefile | 6 +- README.md | 4 + screenshots/CD-ROM_Identify.png | 3 + src/kernel/drivers/ata/ataDevice.cpp | 131 ++++++++++++++++++++ src/kernel/drivers/ata/ataDevice.h | 29 +++++ src/kernel/drivers/atapi/atapiDevice.cpp | 145 +++++++++++++++++++++++ src/kernel/drivers/atapi/atapiDevice.h | 29 +++++ src/kernel/ide/ide.h | 2 + src/kernel/ide/sampleIDE.definitions.h | 16 ++- src/kernel/kernel.cpp | 27 +++++ src/kernel/kernel.h | 2 + 11 files changed, 387 insertions(+), 7 deletions(-) create mode 100644 screenshots/CD-ROM_Identify.png create mode 100644 src/kernel/drivers/ata/ataDevice.cpp create mode 100644 src/kernel/drivers/ata/ataDevice.h create mode 100644 src/kernel/drivers/atapi/atapiDevice.cpp create mode 100644 src/kernel/drivers/atapi/atapiDevice.h diff --git a/Makefile b/Makefile index ada8e52..7f3f9a4 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README.md b/README.md index 5b50e3c..1cd6063 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/screenshots/CD-ROM_Identify.png b/screenshots/CD-ROM_Identify.png new file mode 100644 index 0000000..586d2ee --- /dev/null +++ b/screenshots/CD-ROM_Identify.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a49af346df5f591fd139ebda79fbb80e9d79b1db2697bc8e037ccc6955e69959 +size 58517 diff --git a/src/kernel/drivers/ata/ataDevice.cpp b/src/kernel/drivers/ata/ataDevice.cpp new file mode 100644 index 0000000..bd5f7d1 --- /dev/null +++ b/src/kernel/drivers/ata/ataDevice.cpp @@ -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"); +} \ No newline at end of file diff --git a/src/kernel/drivers/ata/ataDevice.h b/src/kernel/drivers/ata/ataDevice.h new file mode 100644 index 0000000..cccefa4 --- /dev/null +++ b/src/kernel/drivers/ata/ataDevice.h @@ -0,0 +1,29 @@ +#pragma once +#include +#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 ); + +}; diff --git a/src/kernel/drivers/atapi/atapiDevice.cpp b/src/kernel/drivers/atapi/atapiDevice.cpp new file mode 100644 index 0000000..e619680 --- /dev/null +++ b/src/kernel/drivers/atapi/atapiDevice.cpp @@ -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"); +} + + diff --git a/src/kernel/drivers/atapi/atapiDevice.h b/src/kernel/drivers/atapi/atapiDevice.h new file mode 100644 index 0000000..51b7ffe --- /dev/null +++ b/src/kernel/drivers/atapi/atapiDevice.h @@ -0,0 +1,29 @@ +#pragma once +#include +#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 ); + +}; diff --git a/src/kernel/ide/ide.h b/src/kernel/ide/ide.h index 776915f..ce2ebc1 100644 --- a/src/kernel/ide/ide.h +++ b/src/kernel/ide/ide.h @@ -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 diff --git a/src/kernel/ide/sampleIDE.definitions.h b/src/kernel/ide/sampleIDE.definitions.h index d24f62f..957dc60 100644 --- a/src/kernel/ide/sampleIDE.definitions.h +++ b/src/kernel/ide/sampleIDE.definitions.h @@ -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]; diff --git a/src/kernel/kernel.cpp b/src/kernel/kernel.cpp index d558d6d..8f32274 100644 --- a/src/kernel/kernel.cpp +++ b/src/kernel/kernel.cpp @@ -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 diff --git a/src/kernel/kernel.h b/src/kernel/kernel.h index 240a57f..9e84d19 100644 --- a/src/kernel/kernel.h +++ b/src/kernel/kernel.h @@ -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)))