From f2e32cc0fd96e3ee9f1d5b2b63541f8407af09cf Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sun, 3 Oct 2021 23:19:00 +0200 Subject: [PATCH 1/6] Add ATA --- core/kernel.h | 19 ++++++++++++++ core/main.c | 3 +++ drivers/ata.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/ata.h | 52 +++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 drivers/ata.c create mode 100644 drivers/ata.h diff --git a/core/kernel.h b/core/kernel.h index 89e78c4..cdb38a8 100644 --- a/core/kernel.h +++ b/core/kernel.h @@ -11,6 +11,25 @@ #define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a))) #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a)-1)) == 0) + +#ifdef __CHECKER__ +#define BUILD_BUG_ON_ZERO(e) (0) +#else /* __CHECKER__ */ +/* + * Force a compilation error if condition is true, but also produce a + * result (of value 0 and type int), so the expression can be used + * e.g. in a structure initializer (or where-ever else comma expressions + * aren't permitted). + */ +#define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); }))) +#endif /* __CHECKER__ */ +/* Are two types/vars the same type (ignoring qualifiers)? */ +#ifndef __same_type +# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) +#endif +/* &a[0] degrades to a pointer: a different type from an array */ +#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) + #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) /* diff --git a/core/main.c b/core/main.c index d6268be..44e99a8 100644 --- a/core/main.c +++ b/core/main.c @@ -1,5 +1,6 @@ #include "alloc.h" #include "allocArea.h" +#include "ata.h" #include "exception.h" #include "gdt.h" #include "idt.h" @@ -152,6 +153,8 @@ void kmain(unsigned long magic, unsigned long addr) kthreadCreate("idle ", idleThread, NULL); irqSetRoutine(IRQ_TIMER, pit_handler); + + ATAInit(); #ifdef RUN_TEST run_test(); #endif diff --git a/drivers/ata.c b/drivers/ata.c new file mode 100644 index 0000000..a2e7e01 --- /dev/null +++ b/drivers/ata.c @@ -0,0 +1,71 @@ +#include "ata.h" +#include "io.h" +#include "kernel.h" +#include "klibc.h" + +static struct ata_drive drives[4]; + +int ATADectectType(struct ata_drive *drive) +{ + outb(drive->base + ATA_PIO_DRIVE, 0xA0 | drive->isSlave << 4); + outb(drive->base + ATA_PIO_SEC_COUNT, 0x0); + outb(drive->base + ATA_PIO_LBALO, 0x0); + outb(drive->base + ATA_PIO_LBAMID, 0x0); + outb(drive->base + ATA_PIO_LBAHI, 0x0); + outb(drive->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY); + unsigned st = inb(drive->base + ATA_PIO_STATUS); + if(st & ATA_PIO_STATUS_DRIVE_BUSY) + goto no_disk; + + inb(drive->dev_ctl); /* Drop the next 4 read to wait */ + inb(drive->dev_ctl); + inb(drive->dev_ctl); + inb(drive->dev_ctl); + unsigned cl = inb(drive->base + ATA_PIO_LBAMID); /* get the "signature bytes" */ + unsigned ch = inb(drive->base + ATA_PIO_LBAHI); + + /* differentiate ATA, ATAPI, SATA and SATAPI */ + if (cl == 0x14 && ch == 0xEB) { + drive->status = ATA_DEV_PATAPI; + return 0; + } + if (cl == 0x69 && ch == 0x96) { + drive->status = ATA_DEV_SATAPI; + return 0; + } + if (cl == 0 && ch == 0) { + drive->status = ATA_DEV_PATA; + return 0; + } + if (cl == 0x3c && ch == 0xc3) { + drive->status = ATA_DEV_SATA; + return 0; + } +no_disk: + drive->status = ATA_DEV_UNKNOWN; + return -1; +} + +int ATAInit() +{ + memset(drives, 0, sizeof(drives)); + drives[0].base = 0x1F0; + drives[0].dev_ctl = 0x3F6; + drives[0].isSlave = 0; + drives[1].base = 0x1F0; + drives[1].dev_ctl = 0x3F6; + drives[1].isSlave = 1; + drives[1].base = 0x170; + drives[1].dev_ctl = 0x376; + drives[1].isSlave = 0; + drives[2].base = 0x170; + drives[2].dev_ctl = 0x376; + drives[2].isSlave = 1; + + for(uint i = 0; i < ARRAY_SIZE(drives); i++){ + if(!ATADectectType(&drives[i])){ + printf("Driver %d detected %d\n", i, drives[i].status); + } + } + return 0; +} diff --git a/drivers/ata.h b/drivers/ata.h new file mode 100644 index 0000000..761b121 --- /dev/null +++ b/drivers/ata.h @@ -0,0 +1,52 @@ +#pragma once +#include "stdarg.h" + +#define ATA_PIO_REG_DATA 0 +#define ATA_PIO_REG_ERR 1 +#define ATA_PIO_REG_FEAT 1 +#define ATA_PIO_SEC_COUNT 2 +#define ATA_PIO_LBALO 3 +#define ATA_PIO_LBAMID 4 +#define ATA_PIO_CYL_LOW 4 +#define ATA_PIO_LBAHI 5 +#define ATA_PIO_CYL_HI 5 +#define ATA_PIO_DRIVE 6 +#define ATA_PIO_STATUS 7 +#define ATA_PIO_CMD 7 + +#define ATA_PIO_CMD_IDENTIFY 0xEC + +#define ATA_PIO_ERROR_ADDR_MARK_NOT_FOUND 0 +#define ATA_PIO_ERROR_TRACK_ZERO_NOT_FOUND 1 +#define ATA_PIO_ERROR_ABORTED 2 +#define ATA_PIO_ERROR_MEDIA_CHANGE_REQUEST 3 +#define ATA_PIO_ERROR_ID_NOT_FOUND 4 +#define ATA_PIO_ERROR_MEDIA_CHANGED 5 +#define ATA_PIO_ERROR_UNCORRECTABLE_DATA 6 +#define ATA_PIO_ERROR_BAD_BLOCK 7 + +#define ATA_PIO_STATUS_REG_ERR (1<<0) +#define ATA_PIO_STATUS_IDX (1<<1) +#define ATA_PIO_STATUS_CORP (1<<2) +#define ATA_PIO_STATUS_DRQ (1<<3) +#define ATA_PIO_STATUS_SRV (1<<4) +#define ATA_PIO_STATUS_DRIVE_FAULT (1<<5) +#define ATA_PIO_STATUS_DRIVE_RDY (1<<6) +#define ATA_PIO_STATUS_DRIVE_BUSY (1<<7) + +#define ATA_DEV_PATA 1 +#define ATA_DEV_SATA 2 +#define ATA_DEV_PATAPI 3 +#define ATA_DEV_SATAPI 4 +#define ATA_DEV_UNKNOWN 0 + +struct ata_drive { + int16_t base; + int16_t dev_ctl; + int status; + int isSlave; +}; + + +int ATADectectType(struct ata_drive* drive); +int ATAInit(); From a47783ed9c06f7c2c0c3bdbcf2ed449736427f70 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 5 Oct 2021 21:59:36 +0200 Subject: [PATCH 2/6] fix ATA disk and controller detection --- core/io.h | 7 + drivers/ata.c | 505 +++++++++++++++++++++++++++++++++++++++++++++----- drivers/ata.h | 60 +++--- 3 files changed, 507 insertions(+), 65 deletions(-) diff --git a/core/io.h b/core/io.h index 5db61c7..2f766f2 100644 --- a/core/io.h +++ b/core/io.h @@ -18,3 +18,10 @@ static inline uint8_t inb(uint16_t port) asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port)); return ret; } + +static inline uint16_t inw(uint16_t port) +{ + uint16_t ret; + asm volatile("inw %w1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} diff --git a/drivers/ata.c b/drivers/ata.c index a2e7e01..9d2264e 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -2,70 +2,487 @@ #include "io.h" #include "kernel.h" #include "klibc.h" +#include "kthread.h" -static struct ata_drive drives[4]; +// from +// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ata/ns-ata-_identify_device_data +struct _IDENTIFY_DEVICE_DATA { + struct { + uint16_t Reserved1 : 1; + uint16_t Retired3 : 1; + uint16_t ResponseIncomplete : 1; + uint16_t Retired2 : 3; + uint16_t FixedDevice : 1; + uint16_t RemovableMedia : 1; + uint16_t Retired1 : 7; + uint16_t DeviceType : 1; + } GeneralConfiguration; + uint16_t NumCylinders; + uint16_t SpecificConfiguration; + uint16_t NumHeads; + uint16_t Retired1[2]; + uint16_t NumSectorsPerTrack; + uint16_t VendorUnique1[3]; + uint8_t SerialNumber[20]; + uint16_t Retired2[2]; + uint16_t Obsolete1; + uint8_t FirmwareRevision[8]; + uint8_t ModelNumber[40]; + uint8_t MaximumBlockTransfer; + uint8_t VendorUnique2; + struct { + uint16_t FeatureSupported : 1; + uint16_t Reserved : 15; + } TrustedComputing; + struct { + uint8_t CurrentLongPhysicalSectorAlignment : 2; + uint8_t ReservedByte49 : 6; + uint8_t DmaSupported : 1; + uint8_t LbaSupported : 1; + uint8_t IordyDisable : 1; + uint8_t IordySupported : 1; + uint8_t Reserved1 : 1; + uint8_t StandybyTimerSupport : 1; + uint8_t Reserved2 : 2; + uint16_t ReservedWord50; + } Capabilities; + uint16_t ObsoleteWords51[2]; + uint16_t TranslationFieldsValid : 3; + uint16_t Reserved3 : 5; + uint16_t FreeFallControlSensitivity : 8; + uint16_t NumberOfCurrentCylinders; + uint16_t NumberOfCurrentHeads; + uint16_t CurrentSectorsPerTrack; + uint32_t CurrentSectorCapacity; + uint8_t CurrentMultiSectorSetting; + uint8_t MultiSectorSettingValid : 1; + uint8_t ReservedByte59 : 3; + uint8_t SanitizeFeatureSupported : 1; + uint8_t CryptoScrambleExtCommandSupported : 1; + uint8_t OverwriteExtCommandSupported : 1; + uint8_t BlockEraseExtCommandSupported : 1; + uint32_t UserAddressableSectors; + uint16_t ObsoleteWord62; + uint16_t MultiWordDMASupport : 8; + uint16_t MultiWordDMAActive : 8; + uint16_t AdvancedPIOModes : 8; + uint16_t ReservedByte64 : 8; + uint16_t MinimumMWXferCycleTime; + uint16_t RecommendedMWXferCycleTime; + uint16_t MinimumPIOCycleTime; + uint16_t MinimumPIOCycleTimeIORDY; + struct { + uint16_t ZonedCapabilities : 2; + uint16_t NonVolatileWriteCache : 1; + uint16_t ExtendedUserAddressableSectorsSupported : 1; + uint16_t DeviceEncryptsAllUserData : 1; + uint16_t ReadZeroAfterTrimSupported : 1; + uint16_t Optional28BitCommandsSupported : 1; + uint16_t IEEE1667 : 1; + uint16_t DownloadMicrocodeDmaSupported : 1; + uint16_t SetMaxSetPasswordUnlockDmaSupported : 1; + uint16_t WriteBufferDmaSupported : 1; + uint16_t ReadBufferDmaSupported : 1; + uint16_t DeviceConfigIdentifySetDmaSupported : 1; + uint16_t LPSAERCSupported : 1; + uint16_t DeterministicReadAfterTrimSupported : 1; + uint16_t CFastSpecSupported : 1; + } AdditionalSupported; + uint16_t ReservedWords70[5]; + uint16_t QueueDepth : 5; + uint16_t ReservedWord75 : 11; + struct { + uint16_t Reserved0 : 1; + uint16_t SataGen1 : 1; + uint16_t SataGen2 : 1; + uint16_t SataGen3 : 1; + uint16_t Reserved1 : 4; + uint16_t NCQ : 1; + uint16_t HIPM : 1; + uint16_t PhyEvents : 1; + uint16_t NcqUnload : 1; + uint16_t NcqPriority : 1; + uint16_t HostAutoPS : 1; + uint16_t DeviceAutoPS : 1; + uint16_t ReadLogDMA : 1; + uint16_t Reserved2 : 1; + uint16_t CurrentSpeed : 3; + uint16_t NcqStreaming : 1; + uint16_t NcqQueueMgmt : 1; + uint16_t NcqReceiveSend : 1; + uint16_t DEVSLPtoReducedPwrState : 1; + uint16_t Reserved3 : 8; + } SerialAtaCapabilities; + struct { + uint16_t Reserved0 : 1; + uint16_t NonZeroOffsets : 1; + uint16_t DmaSetupAutoActivate : 1; + uint16_t DIPM : 1; + uint16_t InOrderData : 1; + uint16_t HardwareFeatureControl : 1; + uint16_t SoftwareSettingsPreservation : 1; + uint16_t NCQAutosense : 1; + uint16_t DEVSLP : 1; + uint16_t HybridInformation : 1; + uint16_t Reserved1 : 6; + } SerialAtaFeaturesSupported; + struct { + uint16_t Reserved0 : 1; + uint16_t NonZeroOffsets : 1; + uint16_t DmaSetupAutoActivate : 1; + uint16_t DIPM : 1; + uint16_t InOrderData : 1; + uint16_t HardwareFeatureControl : 1; + uint16_t SoftwareSettingsPreservation : 1; + uint16_t DeviceAutoPS : 1; + uint16_t DEVSLP : 1; + uint16_t HybridInformation : 1; + uint16_t Reserved1 : 6; + } SerialAtaFeaturesEnabled; + uint16_t MajorRevision; + uint16_t MinorRevision; + struct { + uint16_t SmartCommands : 1; + uint16_t SecurityMode : 1; + uint16_t RemovableMediaFeature : 1; + uint16_t PowerManagement : 1; + uint16_t Reserved1 : 1; + uint16_t WriteCache : 1; + uint16_t LookAhead : 1; + uint16_t ReleaseInterrupt : 1; + uint16_t ServiceInterrupt : 1; + uint16_t DeviceReset : 1; + uint16_t HostProtectedArea : 1; + uint16_t Obsolete1 : 1; + uint16_t WriteBuffer : 1; + uint16_t ReadBuffer : 1; + uint16_t Nop : 1; + uint16_t Obsolete2 : 1; + uint16_t DownloadMicrocode : 1; + uint16_t DmaQueued : 1; + uint16_t Cfa : 1; + uint16_t AdvancedPm : 1; + uint16_t Msn : 1; + uint16_t PowerUpInStandby : 1; + uint16_t ManualPowerUp : 1; + uint16_t Reserved2 : 1; + uint16_t SetMax : 1; + uint16_t Acoustics : 1; + uint16_t BigLba : 1; + uint16_t DeviceConfigOverlay : 1; + uint16_t FlushCache : 1; + uint16_t FlushCacheExt : 1; + uint16_t WordValid83 : 2; + uint16_t SmartErrorLog : 1; + uint16_t SmartSelfTest : 1; + uint16_t MediaSerialNumber : 1; + uint16_t MediaCardPassThrough : 1; + uint16_t StreamingFeature : 1; + uint16_t GpLogging : 1; + uint16_t WriteFua : 1; + uint16_t WriteQueuedFua : 1; + uint16_t WWN64Bit : 1; + uint16_t URGReadStream : 1; + uint16_t URGWriteStream : 1; + uint16_t ReservedForTechReport : 2; + uint16_t IdleWithUnloadFeature : 1; + uint16_t WordValid : 2; + } CommandSetSupport; + struct { + uint16_t SmartCommands : 1; + uint16_t SecurityMode : 1; + uint16_t RemovableMediaFeature : 1; + uint16_t PowerManagement : 1; + uint16_t Reserved1 : 1; + uint16_t WriteCache : 1; + uint16_t LookAhead : 1; + uint16_t ReleaseInterrupt : 1; + uint16_t ServiceInterrupt : 1; + uint16_t DeviceReset : 1; + uint16_t HostProtectedArea : 1; + uint16_t Obsolete1 : 1; + uint16_t WriteBuffer : 1; + uint16_t ReadBuffer : 1; + uint16_t Nop : 1; + uint16_t Obsolete2 : 1; + uint16_t DownloadMicrocode : 1; + uint16_t DmaQueued : 1; + uint16_t Cfa : 1; + uint16_t AdvancedPm : 1; + uint16_t Msn : 1; + uint16_t PowerUpInStandby : 1; + uint16_t ManualPowerUp : 1; + uint16_t Reserved2 : 1; + uint16_t SetMax : 1; + uint16_t Acoustics : 1; + uint16_t BigLba : 1; + uint16_t DeviceConfigOverlay : 1; + uint16_t FlushCache : 1; + uint16_t FlushCacheExt : 1; + uint16_t Resrved3 : 1; + uint16_t Words119_120Valid : 1; + uint16_t SmartErrorLog : 1; + uint16_t SmartSelfTest : 1; + uint16_t MediaSerialNumber : 1; + uint16_t MediaCardPassThrough : 1; + uint16_t StreamingFeature : 1; + uint16_t GpLogging : 1; + uint16_t WriteFua : 1; + uint16_t WriteQueuedFua : 1; + uint16_t WWN64Bit : 1; + uint16_t URGReadStream : 1; + uint16_t URGWriteStream : 1; + uint16_t ReservedForTechReport : 2; + uint16_t IdleWithUnloadFeature : 1; + uint16_t Reserved4 : 2; + } CommandSetActive; + uint16_t UltraDMASupport : 8; + uint16_t UltraDMAActive : 8; + struct { + uint16_t TimeRequired : 15; + uint16_t ExtendedTimeReported : 1; + } NormalSecurityEraseUnit; + struct { + uint16_t TimeRequired : 15; + uint16_t ExtendedTimeReported : 1; + } EnhancedSecurityEraseUnit; + uint16_t CurrentAPMLevel : 8; + uint16_t ReservedWord91 : 8; + uint16_t MasterPasswordID; + uint16_t HardwareResetResult; + uint16_t CurrentAcousticValue : 8; + uint16_t RecommendedAcousticValue : 8; + uint16_t StreamMinRequestSize; + uint16_t StreamingTransferTimeDMA; + uint16_t StreamingAccessLatencyDMAPIO; + uint32_t StreamingPerfGranularity; + uint32_t Max48BitLBA[2]; + uint16_t StreamingTransferTime; + uint16_t DsmCap; + struct { + uint16_t LogicalSectorsPerPhysicalSector : 4; + uint16_t Reserved0 : 8; + uint16_t LogicalSectorLongerThan256Words : 1; + uint16_t MultipleLogicalSectorsPerPhysicalSector : 1; + uint16_t Reserved1 : 2; + } PhysicalLogicalSectorSize; + uint16_t InterSeekDelay; + uint16_t WorldWideName[4]; + uint16_t ReservedForWorldWideName128[4]; + uint16_t ReservedForTlcTechnicalReport; + uint16_t WordsPerLogicalSector[2]; + struct { + uint16_t ReservedForDrqTechnicalReport : 1; + uint16_t WriteReadVerify : 1; + uint16_t WriteUncorrectableExt : 1; + uint16_t ReadWriteLogDmaExt : 1; + uint16_t DownloadMicrocodeMode3 : 1; + uint16_t FreefallControl : 1; + uint16_t SenseDataReporting : 1; + uint16_t ExtendedPowerConditions : 1; + uint16_t Reserved0 : 6; + uint16_t WordValid : 2; + } CommandSetSupportExt; + struct { + uint16_t ReservedForDrqTechnicalReport : 1; + uint16_t WriteReadVerify : 1; + uint16_t WriteUncorrectableExt : 1; + uint16_t ReadWriteLogDmaExt : 1; + uint16_t DownloadMicrocodeMode3 : 1; + uint16_t FreefallControl : 1; + uint16_t SenseDataReporting : 1; + uint16_t ExtendedPowerConditions : 1; + uint16_t Reserved0 : 6; + uint16_t Reserved1 : 2; + } CommandSetActiveExt; + uint16_t ReservedForExpandedSupportandActive[6]; + uint16_t MsnSupport : 2; + uint16_t ReservedWord127 : 14; + struct { + uint16_t SecuritySupported : 1; + uint16_t SecurityEnabled : 1; + uint16_t SecurityLocked : 1; + uint16_t SecurityFrozen : 1; + uint16_t SecurityCountExpired : 1; + uint16_t EnhancedSecurityEraseSupported : 1; + uint16_t Reserved0 : 2; + uint16_t SecurityLevel : 1; + uint16_t Reserved1 : 7; + } SecurityStatus; + uint16_t ReservedWord129[31]; + struct { + uint16_t MaximumCurrentInMA : 12; + uint16_t CfaPowerMode1Disabled : 1; + uint16_t CfaPowerMode1Required : 1; + uint16_t Reserved0 : 1; + uint16_t Word160Supported : 1; + } CfaPowerMode1; + uint16_t ReservedForCfaWord161[7]; + uint16_t NominalFormFactor : 4; + uint16_t ReservedWord168 : 12; + struct { + uint16_t SupportsTrim : 1; + uint16_t Reserved0 : 15; + } DataSetManagementFeature; + uint16_t AdditionalProductID[4]; + uint16_t ReservedForCfaWord174[2]; + uint16_t CurrentMediaSerialNumber[30]; + struct { + uint16_t Supported : 1; + uint16_t Reserved0 : 1; + uint16_t WriteSameSuported : 1; + uint16_t ErrorRecoveryControlSupported : 1; + uint16_t FeatureControlSuported : 1; + uint16_t DataTablesSuported : 1; + uint16_t Reserved1 : 6; + uint16_t VendorSpecific : 4; + } SCTCommandTransport; + uint16_t ReservedWord207[2]; + struct { + uint16_t AlignmentOfLogicalWithinPhysical : 14; + uint16_t Word209Supported : 1; + uint16_t Reserved0 : 1; + } BlockAlignment; + uint16_t WriteReadVerifySectorCountMode3Only[2]; + uint16_t WriteReadVerifySectorCountMode2Only[2]; + struct { + uint16_t NVCachePowerModeEnabled : 1; + uint16_t Reserved0 : 3; + uint16_t NVCacheFeatureSetEnabled : 1; + uint16_t Reserved1 : 3; + uint16_t NVCachePowerModeVersion : 4; + uint16_t NVCacheFeatureSetVersion : 4; + } NVCacheCapabilities; + uint16_t NVCacheSizeLSW; + uint16_t NVCacheSizeMSW; + uint16_t NominalMediaRotationRate; + uint16_t ReservedWord218; + struct { + uint8_t NVCacheEstimatedTimeToSpinUpInSeconds; + uint8_t Reserved; + } NVCacheOptions; + uint16_t WriteReadVerifySectorCountMode : 8; + uint16_t ReservedWord220 : 8; + uint16_t ReservedWord221; + struct { + uint16_t MajorVersion : 12; + uint16_t TransportType : 4; + } TransportMajorVersion; + uint16_t TransportMinorVersion; + uint16_t ReservedWord224[6]; + uint32_t ExtendedNumberOfUserAddressableSectors[2]; + uint16_t MinBlocksPerDownloadMicrocodeMode03; + uint16_t MaxBlocksPerDownloadMicrocodeMode03; + uint16_t ReservedWord236[19]; + uint16_t Signature : 8; + uint16_t CheckSum : 8; +} __attribute__((packed)); -int ATADectectType(struct ata_drive *drive) +static struct ata_controller controllers[MAX_ATA_CONTROLLER] = {{ + .id = 0, + .base = 0x1F0, + .dev_ctl = 0x3F6, + .present = 0, + }, + { + .id = 1, + .base = 0x170, + .dev_ctl = 0x376, + .present = 0, + }}; +int ATADetectDevice(struct ata_device *dev) { - outb(drive->base + ATA_PIO_DRIVE, 0xA0 | drive->isSlave << 4); - outb(drive->base + ATA_PIO_SEC_COUNT, 0x0); - outb(drive->base + ATA_PIO_LBALO, 0x0); - outb(drive->base + ATA_PIO_LBAMID, 0x0); - outb(drive->base + ATA_PIO_LBAHI, 0x0); - outb(drive->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY); - unsigned st = inb(drive->base + ATA_PIO_STATUS); - if(st & ATA_PIO_STATUS_DRIVE_BUSY) + struct ata_controller *ctl = dev->ctl; + outb(ctl->base + ATA_PIO_DRIVE, 0xA0 | dev->isSlave << 4); + unsigned st = inb(ctl->base + ATA_PIO_STATUS); + if (st & ATA_PIO_STATUS_DRIVE_BUSY) goto no_disk; - inb(drive->dev_ctl); /* Drop the next 4 read to wait */ - inb(drive->dev_ctl); - inb(drive->dev_ctl); - inb(drive->dev_ctl); - unsigned cl = inb(drive->base + ATA_PIO_LBAMID); /* get the "signature bytes" */ - unsigned ch = inb(drive->base + ATA_PIO_LBAHI); + unsigned cl = inb(ctl->base + ATA_PIO_LBAMID); /* get the "signature bytes" */ + unsigned ch = inb(ctl->base + ATA_PIO_LBAHI); /* differentiate ATA, ATAPI, SATA and SATAPI */ if (cl == 0x14 && ch == 0xEB) { - drive->status = ATA_DEV_PATAPI; - return 0; + return ATA_DEV_PATAPI; } if (cl == 0x69 && ch == 0x96) { - drive->status = ATA_DEV_SATAPI; - return 0; + return ATA_DEV_SATAPI; } if (cl == 0 && ch == 0) { - drive->status = ATA_DEV_PATA; - return 0; + return ATA_DEV_PATA; } if (cl == 0x3c && ch == 0xc3) { - drive->status = ATA_DEV_SATA; - return 0; + return ATA_DEV_SATA; } no_disk: - drive->status = ATA_DEV_UNKNOWN; - return -1; + return ATA_DEV_UNKNOWN; +} + +int ATAGetDeviceInfo(struct ata_device *dev) +{ + int status; + int16_t buffer[256]; + struct ata_controller *ctl = dev->ctl; + struct _IDENTIFY_DEVICE_DATA *deviceInfo; + + outb(ctl->base + ATA_PIO_DRIVE, 0xA0 | dev->isSlave << 4); + outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY); + + /* Wait for command completion (wait while busy bit is set) */ + for (int timeout = 0; timeout < 30000; timeout++) { + status = inb(ctl->base + ATA_PIO_STATUS); + if (!(status & ATA_PIO_STATUS_DRIVE_BUSY)) + break; + } + + /* DRQ bit indicates that data is ready to be read. If it is not set + after an IDENTIFY command, there is a problem */ + if (!(status & ATA_PIO_STATUS_DRQ)) { + return -1; + } + /* Read data from the controller buffer to a temporary buffer */ + for (int i = 0; i < 256; i++) + buffer[i] = inw(ctl->base + ATA_PIO_DATA); + + deviceInfo = (struct _IDENTIFY_DEVICE_DATA *)buffer; + + dev->heads = deviceInfo->NumHeads; + dev->cyls = deviceInfo->NumCylinders; + dev->sectors = deviceInfo->NumSectorsPerTrack; + printf("Disk Detected[%d][%d]: %d Ko\n", ctl->id, dev->id, + (dev->heads * dev->cyls * dev->sectors * DISK_SECTOR_SIZE) / 1024); + return 0; +} + +int ATADetectController(struct ata_controller *controller) +{ + controller->devices[0].id = 0; + controller->devices[0].isSlave = 0; + controller->devices[0].ctl = controller; + controller->devices[0].type = ATADetectDevice(&controllers->devices[0]); + + if (controller->devices[0].type == ATA_DEV_PATA || + controller->devices[0].type == ATA_DEV_SATA) { + ATAGetDeviceInfo(&controller->devices[0]); + } + + controller->devices[1].id = 1; + controller->devices[1].isSlave = 1; + controller->devices[1].ctl = controller; + controller->devices[1].type = ATADetectDevice(&controllers->devices[1]); + + if (controller->devices[1].type == ATA_DEV_PATA || + controller->devices[1].type == ATA_DEV_SATA) { + ATAGetDeviceInfo(&controller->devices[1]); + } + + return 0; } int ATAInit() { - memset(drives, 0, sizeof(drives)); - drives[0].base = 0x1F0; - drives[0].dev_ctl = 0x3F6; - drives[0].isSlave = 0; - drives[1].base = 0x1F0; - drives[1].dev_ctl = 0x3F6; - drives[1].isSlave = 1; - drives[1].base = 0x170; - drives[1].dev_ctl = 0x376; - drives[1].isSlave = 0; - drives[2].base = 0x170; - drives[2].dev_ctl = 0x376; - drives[2].isSlave = 1; - - for(uint i = 0; i < ARRAY_SIZE(drives); i++){ - if(!ATADectectType(&drives[i])){ - printf("Driver %d detected %d\n", i, drives[i].status); - } + for (uint i = 0; i < MAX_ATA_CONTROLLER; i++) { + ATADetectController(&controllers[i]); } return 0; } diff --git a/drivers/ata.h b/drivers/ata.h index 761b121..2988ad2 100644 --- a/drivers/ata.h +++ b/drivers/ata.h @@ -1,9 +1,9 @@ #pragma once #include "stdarg.h" -#define ATA_PIO_REG_DATA 0 -#define ATA_PIO_REG_ERR 1 -#define ATA_PIO_REG_FEAT 1 +#define ATA_PIO_DATA 0 +#define ATA_PIO_ERR 1 +#define ATA_PIO_FEAT 1 #define ATA_PIO_SEC_COUNT 2 #define ATA_PIO_LBALO 3 #define ATA_PIO_LBAMID 4 @@ -14,6 +14,8 @@ #define ATA_PIO_STATUS 7 #define ATA_PIO_CMD 7 +// cmd details +// https://people.freebsd.org/~imp/asiabsdcon2015/works/d2161r5-ATAATAPI_Command_Set_-_3.pdf #define ATA_PIO_CMD_IDENTIFY 0xEC #define ATA_PIO_ERROR_ADDR_MARK_NOT_FOUND 0 @@ -25,28 +27,44 @@ #define ATA_PIO_ERROR_UNCORRECTABLE_DATA 6 #define ATA_PIO_ERROR_BAD_BLOCK 7 -#define ATA_PIO_STATUS_REG_ERR (1<<0) -#define ATA_PIO_STATUS_IDX (1<<1) -#define ATA_PIO_STATUS_CORP (1<<2) -#define ATA_PIO_STATUS_DRQ (1<<3) -#define ATA_PIO_STATUS_SRV (1<<4) -#define ATA_PIO_STATUS_DRIVE_FAULT (1<<5) -#define ATA_PIO_STATUS_DRIVE_RDY (1<<6) -#define ATA_PIO_STATUS_DRIVE_BUSY (1<<7) +#define ATA_PIO_STATUS_REG_ERR (1 << 0) +#define ATA_PIO_STATUS_IDX (1 << 1) +#define ATA_PIO_STATUS_CORP (1 << 2) +#define ATA_PIO_STATUS_DRQ (1 << 3) +#define ATA_PIO_STATUS_SRV (1 << 4) +#define ATA_PIO_STATUS_DRIVE_FAULT (1 << 5) +#define ATA_PIO_STATUS_DRIVE_RDY (1 << 6) +#define ATA_PIO_STATUS_DRIVE_BUSY (1 << 7) -#define ATA_DEV_PATA 1 -#define ATA_DEV_SATA 2 -#define ATA_DEV_PATAPI 3 -#define ATA_DEV_SATAPI 4 -#define ATA_DEV_UNKNOWN 0 +#define MAX_ATA_CONTROLLER 2 +#define MAX_ATA_DEVICES 2 -struct ata_drive { - int16_t base; - int16_t dev_ctl; - int status; +#define DISK_SECTOR_SIZE 512 + +typedef enum { + ATA_DEV_UNKNOWN, + ATA_DEV_PATA, + ATA_DEV_SATA, + ATA_DEV_PATAPI, + ATA_DEV_SATAPI +} ata_type; + +struct ata_device { + int id; + ata_type type; int isSlave; + struct ata_controller *ctl; + int heads; + int cyls; + int sectors; }; +struct ata_controller { + int id; + int16_t base; + int16_t dev_ctl; + int present; + struct ata_device devices[MAX_ATA_DEVICES]; +}; -int ATADectectType(struct ata_drive* drive); int ATAInit(); From 1ce5874b0ae2651b8de0a3016042f05a520f8b7b Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 5 Oct 2021 22:01:13 +0200 Subject: [PATCH 3/6] Add disk image option to makefile --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 88a6116..63769e0 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ CFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fn CXXFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-rtti -fno-pie DEBUG_FLAGS += -g -Og -DDEBUG -fno-omit-frame-pointer -fno-inline +QEMU_OPT += -hda disk.img ARCH?=x86 SUBDIRS := core drivers tests arch/$(ARCH) @@ -30,6 +31,8 @@ fd.iso: kernel @printf "menuentry \"myos\" {\n\tmultiboot /boot/kernel\n}" > isodir/boot/grub/grub.cfg grub-mkrescue -o $@ isodir +disk.img: + qemu-img create -f qcow2 disk2.img 32M #https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#x86-Function-Attributes arch/$(ARCH)/exception_handler.o:arch/$(ARCH)/exception_handler.c @@ -46,10 +49,10 @@ arch/$(ARCH)/irq_handler.o:arch/$(ARCH)/irq_handler.c test: CFLAGS += -DRUN_TEST test: clean kernel - qemu-system-x86_64 -kernel kernel -serial stdio -m 32M + qemu-system-x86_64 -kernel kernel -serial stdio -m 32M $(QEMU_OPT) run:kernel - qemu-system-x86_64 -kernel $< + qemu-system-x86_64 -kernel $< $(QEMU_OPT) debug: CFLAGS += $(DEBUG_FLAGS) -DRUN_TEST From 4fe87718b167aaf15f9b89e0dd60f561190fc7e0 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 5 Oct 2021 22:07:17 +0200 Subject: [PATCH 4/6] Add target for disk img --- Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 63769e0..cbea915 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ fd.iso: kernel grub-mkrescue -o $@ isodir disk.img: - qemu-img create -f qcow2 disk2.img 32M + qemu-img create -f qcow2 disk.img 32M #https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#x86-Function-Attributes arch/$(ARCH)/exception_handler.o:arch/$(ARCH)/exception_handler.c @@ -48,13 +48,12 @@ arch/$(ARCH)/irq_handler.o:arch/$(ARCH)/irq_handler.c test: CFLAGS += -DRUN_TEST -test: clean kernel +test: clean kernel disk.img qemu-system-x86_64 -kernel kernel -serial stdio -m 32M $(QEMU_OPT) -run:kernel +run:kernel disk.img qemu-system-x86_64 -kernel $< $(QEMU_OPT) - debug: CFLAGS += $(DEBUG_FLAGS) -DRUN_TEST debug: CXXFLAGS += $(DEBUG_FLAGS) debug:kernel kernel.sym From 1a337881f3b6744510018e8b28d87d8f0ea1b74c Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 5 Oct 2021 23:10:10 +0200 Subject: [PATCH 5/6] ATA Add Read function --- drivers/ata.c | 41 +++++++++++++++++++++++++++++++++++++++-- drivers/ata.h | 18 +++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/drivers/ata.c b/drivers/ata.c index 9d2264e..fd48c64 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -383,17 +383,19 @@ static struct ata_controller controllers[MAX_ATA_CONTROLLER] = {{ .base = 0x1F0, .dev_ctl = 0x3F6, .present = 0, + .last_device_used = -1, }, { .id = 1, .base = 0x170, .dev_ctl = 0x376, .present = 0, + .last_device_used = -1, }}; int ATADetectDevice(struct ata_device *dev) { struct ata_controller *ctl = dev->ctl; - outb(ctl->base + ATA_PIO_DRIVE, 0xA0 | dev->isSlave << 4); + outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave? ATA_PIO_DRIVE_SLAVE: ATA_PIO_DRIVE_MASTER); unsigned st = inb(ctl->base + ATA_PIO_STATUS); if (st & ATA_PIO_STATUS_DRIVE_BUSY) goto no_disk; @@ -425,7 +427,7 @@ int ATAGetDeviceInfo(struct ata_device *dev) struct ata_controller *ctl = dev->ctl; struct _IDENTIFY_DEVICE_DATA *deviceInfo; - outb(ctl->base + ATA_PIO_DRIVE, 0xA0 | dev->isSlave << 4); + outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave? ATA_PIO_DRIVE_SLAVE: ATA_PIO_DRIVE_MASTER); outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY); /* Wait for command completion (wait while busy bit is set) */ @@ -456,11 +458,13 @@ int ATAGetDeviceInfo(struct ata_device *dev) int ATADetectController(struct ata_controller *controller) { + controller->devices[0].id = 0; controller->devices[0].isSlave = 0; controller->devices[0].ctl = controller; controller->devices[0].type = ATADetectDevice(&controllers->devices[0]); + if (controller->devices[0].type == ATA_DEV_PATA || controller->devices[0].type == ATA_DEV_SATA) { ATAGetDeviceInfo(&controller->devices[0]); @@ -486,3 +490,36 @@ int ATAInit() } return 0; } + +int ATARead(struct ata_device *dev, int lba, int size, void *buf) +{ + struct ata_controller *ctl = dev->ctl; + uint nb_block = DIV_ROUND_UP(size, DISK_SECTOR_SIZE); + + mutexLock(&ctl->mutex); + + if (ctl->last_device_used != dev->id) { + outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4); + while(inb(ctl->base +ATA_PIO_STATUS)&ATA_PIO_STATUS_DRIVE_BUSY); + ctl->last_device_used = dev->id; + } + outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA); + outb(ctl->base + ATA_PIO_SEC_COUNT, nb_block); + outb(ctl->base + ATA_PIO_LBALO, lba & 0xff); + outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff); + outb(ctl->base + ATA_PIO_LBAHI, (lba >> 16) & 0xff); + + uint16_t *ptr = (uint16_t *)buf; + for(uint block = 0; block < nb_block ; block ++){ + while(inb(ctl->base +ATA_PIO_STATUS)&ATA_PIO_STATUS_DRIVE_BUSY); + for(int i = 0; i< 256 && size >0; i++, size --){ + *ptr = inw(ctl->base +ATA_PIO_DATA); + ptr++; + } + + } + + mutexUnlock(&ctl->mutex); + + return 0; +} diff --git a/drivers/ata.h b/drivers/ata.h index 2988ad2..2afbc80 100644 --- a/drivers/ata.h +++ b/drivers/ata.h @@ -1,5 +1,6 @@ #pragma once #include "stdarg.h" +#include "synchro.h" #define ATA_PIO_DATA 0 #define ATA_PIO_ERR 1 @@ -16,7 +17,20 @@ // cmd details // https://people.freebsd.org/~imp/asiabsdcon2015/works/d2161r5-ATAATAPI_Command_Set_-_3.pdf -#define ATA_PIO_CMD_IDENTIFY 0xEC +#define ATA_PIO_CMD_IDENTIFY 0xEC /* get ATA params */ +#define ATA_PIO_CMD_ATAPI_IDENTIFY 0xA1 /* get ATAPI params*/ +#define ATA_PIO_CMD_READ 0x20 /* read command */ +#define ATA_PIO_CMD_WRITE 0x30 /* write command */ +#define ATA_PIO_CMD_READ_MULTI 0xC4 /* read multi command */ +#define ATA_PIO_CMD_WRITE_MULTI 0xC5 /* write multi command */ +#define ATA_PIO_CMD_SET_MULTI 0xC6 /* set multi size command */ +#define ATA_PIO_CMD_PACKET_CMD 0xA0 /* set multi size command */ + +#define ATA_PIO_DRIVE_IBM 0xA0 /* bits that must be set */ +#define ATA_PIO_DRIVE_LBA 0x40 /* use LBA ? */ +#define ATA_PIO_DRIVE_MASTER 0x00 /* select master */ +#define ATA_PIO_DRIVE_SLAVE 0x10 /* select slave */ + #define ATA_PIO_ERROR_ADDR_MARK_NOT_FOUND 0 #define ATA_PIO_ERROR_TRACK_ZERO_NOT_FOUND 1 @@ -65,6 +79,8 @@ struct ata_controller { int16_t dev_ctl; int present; struct ata_device devices[MAX_ATA_DEVICES]; + struct mutex mutex; + int last_device_used; }; int ATAInit(); From 19714126d12079fb01c68d2776ac41f004a13aac Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 5 Oct 2021 23:55:15 +0200 Subject: [PATCH 6/6] ATA add write and some test --- core/io.h | 5 +++ drivers/ata.c | 119 +++++++++++++++++++++++++++++++++++++++++--------- drivers/ata.h | 3 ++ tests/test.c | 22 ++++++++++ 4 files changed, 129 insertions(+), 20 deletions(-) diff --git a/core/io.h b/core/io.h index 2f766f2..f153d3b 100644 --- a/core/io.h +++ b/core/io.h @@ -12,6 +12,11 @@ static inline void outb(uint16_t port, uint8_t val) * number a wider C type */ } +static inline void outw(uint16_t port, int16_t val) +{ + asm volatile("outw %w0, %w1" :: "a"(val), "Nd"(port)); +} + static inline uint8_t inb(uint16_t port) { uint8_t ret; diff --git a/drivers/ata.c b/drivers/ata.c index fd48c64..ca9ad20 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -379,23 +379,24 @@ struct _IDENTIFY_DEVICE_DATA { } __attribute__((packed)); static struct ata_controller controllers[MAX_ATA_CONTROLLER] = {{ - .id = 0, - .base = 0x1F0, - .dev_ctl = 0x3F6, - .present = 0, + .id = 0, + .base = 0x1F0, + .dev_ctl = 0x3F6, + .present = 0, .last_device_used = -1, }, { - .id = 1, - .base = 0x170, - .dev_ctl = 0x376, - .present = 0, + .id = 1, + .base = 0x170, + .dev_ctl = 0x376, + .present = 0, .last_device_used = -1, }}; int ATADetectDevice(struct ata_device *dev) { struct ata_controller *ctl = dev->ctl; - outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave? ATA_PIO_DRIVE_SLAVE: ATA_PIO_DRIVE_MASTER); + outb(ctl->base + ATA_PIO_DRIVE, + ATA_PIO_DRIVE_IBM | dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER); unsigned st = inb(ctl->base + ATA_PIO_STATUS); if (st & ATA_PIO_STATUS_DRIVE_BUSY) goto no_disk; @@ -427,7 +428,8 @@ int ATAGetDeviceInfo(struct ata_device *dev) struct ata_controller *ctl = dev->ctl; struct _IDENTIFY_DEVICE_DATA *deviceInfo; - outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave? ATA_PIO_DRIVE_SLAVE: ATA_PIO_DRIVE_MASTER); + outb(ctl->base + ATA_PIO_DRIVE, + ATA_PIO_DRIVE_IBM | (dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER)); outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY); /* Wait for command completion (wait while busy bit is set) */ @@ -459,12 +461,13 @@ int ATAGetDeviceInfo(struct ata_device *dev) int ATADetectController(struct ata_controller *controller) { + mutexInit(&controller[0].mutex); + mutexInit(&controller[1].mutex); controller->devices[0].id = 0; controller->devices[0].isSlave = 0; controller->devices[0].ctl = controller; controller->devices[0].type = ATADetectDevice(&controllers->devices[0]); - if (controller->devices[0].type == ATA_DEV_PATA || controller->devices[0].type == ATA_DEV_SATA) { ATAGetDeviceInfo(&controller->devices[0]); @@ -491,35 +494,111 @@ int ATAInit() return 0; } -int ATARead(struct ata_device *dev, int lba, int size, void *buf) +int ATAReadSector(struct ata_device *dev, int lba, uint nb_sector, void *buf) { struct ata_controller *ctl = dev->ctl; - uint nb_block = DIV_ROUND_UP(size, DISK_SECTOR_SIZE); mutexLock(&ctl->mutex); if (ctl->last_device_used != dev->id) { outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4); - while(inb(ctl->base +ATA_PIO_STATUS)&ATA_PIO_STATUS_DRIVE_BUSY); + while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) { + } ctl->last_device_used = dev->id; } outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA); - outb(ctl->base + ATA_PIO_SEC_COUNT, nb_block); + outb(ctl->base + ATA_PIO_SEC_COUNT, nb_sector); outb(ctl->base + ATA_PIO_LBALO, lba & 0xff); outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff); outb(ctl->base + ATA_PIO_LBAHI, (lba >> 16) & 0xff); + outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_READ); uint16_t *ptr = (uint16_t *)buf; - for(uint block = 0; block < nb_block ; block ++){ - while(inb(ctl->base +ATA_PIO_STATUS)&ATA_PIO_STATUS_DRIVE_BUSY); - for(int i = 0; i< 256 && size >0; i++, size --){ - *ptr = inw(ctl->base +ATA_PIO_DATA); + for (uint sector = 0; sector < nb_sector; sector++) { + while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) { + } + if (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_REG_ERR) { + mutexUnlock(&ctl->mutex); + printf("ATA read error\n"); + return -1; + } + for (uint i = 0; i < (DISK_SECTOR_SIZE / sizeof(uint16_t)); i++) { + *ptr = inw(ctl->base + ATA_PIO_DATA); ptr++; } - } mutexUnlock(&ctl->mutex); return 0; } + +int ATAWriteSector(struct ata_device *dev, int lba, uint nb_sector, void *buf) +{ + struct ata_controller *ctl = dev->ctl; + + mutexLock(&ctl->mutex); + + if (ctl->last_device_used != dev->id) { + outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4); + while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) { + } + ctl->last_device_used = dev->id; + } + outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA); + outb(ctl->base + ATA_PIO_SEC_COUNT, nb_sector); + outb(ctl->base + ATA_PIO_LBALO, lba & 0xff); + outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff); + outb(ctl->base + ATA_PIO_LBAHI, (lba >> 16) & 0xff); + outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_WRITE); + + uint16_t *ptr = (uint16_t *)buf; + for (uint sector = 0; sector < nb_sector; sector++) { + while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) { + } + if (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_REG_ERR) { + mutexUnlock(&ctl->mutex); + printf("ATA write error\n"); + return -1; + } + while (1) { + int status = inb(ctl->base + ATA_PIO_STATUS); + if (status & ATA_PIO_STATUS_REG_ERR) { + mutexUnlock(&ctl->mutex); + printf("ATA write error\n"); + return -1; + } + if ((status & ATA_PIO_STATUS_DRQ) && + !(status & ATA_PIO_STATUS_DRIVE_BUSY)) + break; + } + for (uint i = 0; i < (DISK_SECTOR_SIZE / sizeof(uint16_t)); i++) { + outw(ctl->base + ATA_PIO_DATA, *ptr++); + } + // Wait for the device to receive the data + while (1) { + int status = inb(ctl->base + ATA_PIO_STATUS); + if (status & ATA_PIO_STATUS_REG_ERR) { + mutexUnlock(&ctl->mutex); + printf("ATA write error\n"); + return -1; + } + if (!(status & ATA_PIO_STATUS_DRQ) && + !(status & ATA_PIO_STATUS_DRIVE_BUSY)) + break; + } + } + + mutexUnlock(&ctl->mutex); + + return 0; +} + +struct ata_device *ATAGetDevice(int ctlId, int devId) +{ + if (ctlId >= MAX_ATA_CONTROLLER) + return NULL; + if (devId >= MAX_ATA_DEVICES) + return NULL; + return &controllers[ctlId].devices[devId]; +} diff --git a/drivers/ata.h b/drivers/ata.h index 2afbc80..c1b6e08 100644 --- a/drivers/ata.h +++ b/drivers/ata.h @@ -84,3 +84,6 @@ struct ata_controller { }; int ATAInit(); +int ATAReadSector(struct ata_device *dev, int lba, uint nbSector, void *buf); +int ATAWriteSector(struct ata_device *dev, int lba, uint nbSector, void *buf); +struct ata_device *ATAGetDevice(int ctlId, int devId); diff --git a/tests/test.c b/tests/test.c index b1a11c1..4c0af66 100644 --- a/tests/test.c +++ b/tests/test.c @@ -1,4 +1,5 @@ #include "alloc.h" +#include "ata.h" #include "assert.h" #include "cpu_context.h" #include "klibc.h" @@ -338,8 +339,29 @@ void testKthread() kthreadCreate("mtest3", mutThread, "mut3"); } +void testATAThread(){ + uint16_t buf[DISK_SECTOR_SIZE/2]; + struct ata_device *dev = ATAGetDevice(0, 0); + if(dev != NULL){ + ATAReadSector(dev, 0, 1, buf); + printf("Reading from disk 0x%x 0x%x 0x%x 0x%x\n", buf[0], buf[1], buf[2], buf[3]); + memset(buf, 0, sizeof(buf)); + buf[0]= 0x1; + buf[1]= 0x2; + buf[2]= 0x3; + buf[3]= 0x4; + ATAWriteSector(dev, 0, 1, buf); + } +} + +void testATA(){ + kthreadCreate("ATA_TEST", testATAThread, NULL); + //testATAThread(); +} + void run_test(void) { + testATA(); testMemcpyPerf(); { int test = 1000;