diff --git a/mentos/inc/drivers/ata.h b/mentos/inc/drivers/ata/ata.h similarity index 100% rename from mentos/inc/drivers/ata.h rename to mentos/inc/drivers/ata/ata.h diff --git a/mentos/inc/drivers/ata/ata_types.h b/mentos/inc/drivers/ata/ata_types.h new file mode 100644 index 0000000..7cec71d --- /dev/null +++ b/mentos/inc/drivers/ata/ata_types.h @@ -0,0 +1,72 @@ +/// @file ata_types.h +/// @brief Data types for managing Advanced Technology Attachment (ATA) devices. +/// @copyright (c) 2014-2023 This file is distributed under the MIT License. +/// See LICENSE.md for details. +/// @addtogroup ata +/// @{ + +#pragma once + +/// @brief ATA Error Bits +typedef enum { + ata_err_amnf = (1 << 0), ///< Address mark not found. + ata_err_tkznf = (1 << 1), ///< Track zero not found. + ata_err_abrt = (1 << 2), ///< Aborted command. + ata_err_mcr = (1 << 3), ///< Media change request. + ata_err_idnf = (1 << 4), ///< ID not found. + ata_err_mc = (1 << 5), ///< Media changed. + ata_err_unc = (1 << 6), ///< Uncorrectable data error. + ata_err_bbk = (1 << 7), ///< Bad Block detected. +} ata_error_t; + +/// @brief ATA Status Bits +typedef enum { + ata_status_err = (1 << 0), ///< Indicates an error occurred. + ata_status_idx = (1 << 1), ///< Index. Always set to zero. + ata_status_corr = (1 << 2), ///< Corrected data. Always set to zero. + ata_status_drq = (1 << 3), ///< Set when the drive has PIO data to transfer, or is ready to accept PIO data. + ata_status_srv = (1 << 4), ///< Overlapped Mode Service Request. + ata_status_df = (1 << 5), ///< Drive Fault Error (does not set ERR). + ata_status_rdy = (1 << 6), ///< Bit is clear when drive is spun down, or after an error. Set otherwise. + ata_status_bsy = (1 << 7), ///< The drive is preparing to send/receive data (wait for it to clear). +} ata_status_t; + +/// @brief ATA Control Bits +typedef enum { + ata_control_zero = 0x00, ///< Always set to zero. + ata_control_nien = 0x02, ///< Set this to stop the current device from sending interrupts. + ata_control_srst = 0x04, ///< Set, then clear (after 5us), this to do a "Software Reset" on all ATA drives on a bus, if one is misbehaving. + ata_control_hob = 0x80, ///< Set this to read back the High Order Byte (HOB) of the last LBA48 value sent to an IO port. +} ata_control_t; + +/// @brief Types of ATA devices. +typedef enum { + ata_dev_type_unknown, ///< Device type not recognized. + ata_dev_type_no_device, ///< No device detected. + ata_dev_type_pata, ///< Parallel ATA drive. + ata_dev_type_sata, ///< Serial ATA drive. + ata_dev_type_patapi, ///< Parallel ATAPI drive. + ata_dev_type_satapi ///< Serial ATAPI drive. +} ata_device_type_t; + +/// @brief Values used to manage bus mastering. +typedef enum { + ata_bm_stop_bus_master = 0x00, ///< Halts bus master operations of the controller. + ata_bm_start_bus_master = 0x01, ///< Enables bus master operation of the controller. +} ata_bus_mastering_command_t; + +/// @brief DMA specific commands. +typedef enum { + ata_dma_command_read = 0xC8, ///< Read DMA with retries (28 bit LBA). + ata_dma_command_read_no_retry = 0xC9, ///< Read DMA without retries (28 bit LBA). + ata_dma_command_write = 0xCA, ///< Write DMA with retries (28 bit LBA). + ata_dma_command_write_no_retry = 0xCB, ///< Write DMA without retries (28 bit LBA). +} ata_dma_command_t; + +/// @brief ATA identity commands. +typedef enum { + ata_command_pata_ident = 0xEC, ///< Identify Device. + ata_command_patapi_ident = 0xA1, ///< Identify Device. +} ata_identity_command_t; + +/// @} diff --git a/mentos/src/devices/pci.c b/mentos/src/devices/pci.c index 3dff74a..e48d386 100644 --- a/mentos/src/devices/pci.c +++ b/mentos/src/devices/pci.c @@ -5,10 +5,10 @@ ///! @cond Doxygen_Suppress // Setup the logging for this file (do this before any other include). -#include "sys/kernel_levels.h" // Include kernel log levels. -#define __DEBUG_HEADER__ "[PCI ]" ///< Change header. -#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level. -#include "io/debug.h" // Include debugging functions. +#include "sys/kernel_levels.h" // Include kernel log levels. +#define __DEBUG_HEADER__ "[PCI ]" ///< Change header. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level. +#include "io/debug.h" // Include debugging functions. #include "devices/pci.h" #include "io/port_io.h" diff --git a/mentos/src/drivers/ata.c b/mentos/src/drivers/ata.c index b17410a..d393435 100644 --- a/mentos/src/drivers/ata.c +++ b/mentos/src/drivers/ata.c @@ -11,9 +11,11 @@ #define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level. #include "io/debug.h" // Include debugging functions. +#include "drivers/ata/ata.h" +#include "drivers/ata/ata_types.h" + #include "descriptor_tables/isr.h" #include "devices/pci.h" -#include "drivers/ata.h" #include "fcntl.h" #include "fs/vfs.h" #include "hardware/pic8259.h" @@ -26,68 +28,6 @@ #include "sys/errno.h" #include "system/panic.h" -/// @brief ATA Error Bits -typedef enum { - ata_err_amnf = 0, ///< Address mark not found. - ata_err_tkznf = 1, ///< Track zero not found. - ata_err_abrt = 2, ///< Aborted command. - ata_err_mcr = 3, ///< Media change request. - ata_err_idnf = 4, ///< ID not found. - ata_err_mc = 5, ///< Media changed. - ata_err_unc = 6, ///< Uncorrectable data error. - ata_err_bbk = 7, ///< Bad Block detected. -} ata_error_t; - -/// @brief ATA Status Bits -typedef enum { - ata_status_err = (1 << 0), ///< Indicates an error occurred. - ata_status_idx = (1 << 1), ///< Index. Always set to zero. - ata_status_corr = (1 << 2), ///< Corrected data. Always set to zero. - ata_status_drq = (1 << 3), ///< Set when the drive has PIO data to transfer, or is ready to accept PIO data. - ata_status_srv = (1 << 4), ///< Overlapped Mode Service Request. - ata_status_df = (1 << 5), ///< Drive Fault Error (does not set ERR). - ata_status_rdy = (1 << 6), ///< Bit is clear when drive is spun down, or after an error. Set otherwise. - ata_status_bsy = (1 << 7), ///< The drive is preparing to send/receive data (wait for it to clear). -} ata_status_t; - -/// @brief ATA Control Bits -typedef enum { - ata_control_zero = 0x00, ///< Always set to zero. - ata_control_nien = 0x02, ///< Set this to stop the current device from sending interrupts. - ata_control_srst = 0x04, ///< Set, then clear (after 5us), this to do a "Software Reset" on all ATA drives on a bus, if one is misbehaving. - ata_control_hob = 0x80, ///< Set this to read back the High Order Byte (HOB) of the last LBA48 value sent to an IO port. -} ata_control_t; - -/// @brief Types of ATA devices. -typedef enum { - ata_dev_type_unknown, ///< Device type not recognized. - ata_dev_type_no_device, ///< No device detected. - ata_dev_type_pata, ///< Parallel ATA drive. - ata_dev_type_sata, ///< Serial ATA drive. - ata_dev_type_patapi, ///< Parallel ATAPI drive. - ata_dev_type_satapi ///< Serial ATAPI drive. -} ata_device_type_t; - -/// @brief Values used to manage bus mastering. -typedef enum { - ata_bm_stop_bus_master = 0x00, ///< Halts bus master operations of the controller. - ata_bm_start_bus_master = 0x01, ///< Enables bus master operation of the controller. -} ata_bus_mastering_command_t; - -/// @brief DMA specific commands. -typedef enum { - ata_dma_command_read = 0xC8, ///< Read DMA with retries (28 bit LBA). - ata_dma_command_read_no_retry = 0xC9, ///< Read DMA without retries (28 bit LBA). - ata_dma_command_write = 0xCA, ///< Write DMA with retries (28 bit LBA). - ata_dma_command_write_no_retry = 0xCB, ///< Write DMA without retries (28 bit LBA). -} ata_dma_command_t; - -/// @brief ATA identity commands. -typedef enum { - ata_command_pata_ident = 0xEC, ///< Identify Device. - ata_command_patapi_ident = 0xA1, ///< Identify Device. -} ata_identity_command_t; - /// @brief IDENTIFY device data (response to 0xEC). typedef struct ata_identity_t { /// Word 0 : General configuration. @@ -186,29 +126,6 @@ typedef struct ata_identity_t { uint16_t unused7[152]; } ata_identity_t; -typedef struct { - /// [R/W] Data Register. Read/Write PIO data bytes (16-bit). - uint8_t data; - /// [R ] Error Register. Read error generated by the last ATA command executed (8-bit). - uint8_t error; - /// [ W] Features Register. Used to control command specific interface features (8-bit). - uint8_t feature; - /// [R/W] Sector Count Register. Number of sectors to read/write (0 is a special value) (8-bit). - uint8_t sector_count; - /// [R/W] Sector Number Register. This is CHS/LBA28/LBA48 specific (8-bit). - uint8_t lba_lo; - /// [R/W] Cylinder Low Register. Partial Disk Sector address (8-bit). - uint8_t lba_mid; - /// [R/W] Cylinder High Register. Partial Disk Sector address (8-bit). - uint8_t lba_hi; - /// [R/W] Drive / Head Register. Used to select a drive and/or head. Supports extra address/flag bits (8-bit). - uint8_t hddevsel; - /// [R ] Status Register. Used to read the current status (8-bit). - uint8_t status; - /// [ W] Command Register. Used to send ATA commands to the device (8-bit). - uint8_t command; -} ata_io_reg_t; - /// @brief Physical Region Descriptor Table (PRDT) entry. /// @details /// The physical memory region to be transferred is described by a Physical @@ -217,7 +134,7 @@ typedef struct { /// Each Physical Region Descriptor entry is 8 bytes in length. /// | byte 3 | byte 2 | byte 1 | byte 0 | /// Dword 0 | Memory Region Physical Base Address [31:1] |0| -/// Dword 1 | EOT | reserved | Byte Count [15:1] |0| +/// Dword 1 | EOT | reserved | Byte Count [15:1] |0| typedef struct prdt_t { /// The first 4 bytes specify the byte address of a physical memory region. unsigned int physical_address; @@ -263,9 +180,13 @@ typedef struct ata_device_t { /// The "Control" port base. uint16_t io_control; /// If the device is connected to the primary bus. - bool_t primary; - /// If the device master or slave. - bool_t slave; + bool_t primary : 8; + /// If the device is connected to the secondary bus. + bool_t secondary : 8; + /// If the device is master. + bool_t master : 8; + /// If the device is slave. + bool_t slave : 8; /// The device identity data. ata_identity_t identity; /// Bus Master Register. The "address" of the Bus Master Register is stored @@ -344,6 +265,8 @@ static ata_device_t ata_primary_master = { }, .io_control = 0x3F6, .primary = 1, + .secondary = 0, + .master = 1, .slave = 0 }; @@ -363,6 +286,8 @@ static ata_device_t ata_primary_slave = { }, .io_control = 0x3F6, .primary = 1, + .secondary = 0, + .master = 0, .slave = 1 }; @@ -382,6 +307,8 @@ static ata_device_t ata_secondary_master = { }, .io_control = 0x376, .primary = 0, + .secondary = 1, + .master = 1, .slave = 0 }; @@ -401,6 +328,8 @@ static ata_device_t ata_secondary_slave = { }, .io_control = 0x376, .primary = 0, + .secondary = 1, + .master = 0, .slave = 1 }; @@ -410,28 +339,28 @@ static inline const char *ata_get_device_error_str(uint8_t error) { static char str[50] = { 0 }; memset(str, 0, sizeof(str)); - if (bit_check(error, ata_err_amnf)) { + if (error & ata_err_amnf) { strcat(str, "amnf,"); } - if (bit_check(error, ata_err_tkznf)) { + if (error & ata_err_tkznf) { strcat(str, "tkznf,"); } - if (bit_check(error, ata_err_abrt)) { + if (error & ata_err_abrt) { strcat(str, "abrt,"); } - if (bit_check(error, ata_err_mcr)) { + if (error & ata_err_mcr) { strcat(str, "mcr,"); } - if (bit_check(error, ata_err_idnf)) { + if (error & ata_err_idnf) { strcat(str, "idnf,"); } - if (bit_check(error, ata_err_mc)) { + if (error & ata_err_mc) { strcat(str, "mc,"); } - if (bit_check(error, ata_err_unc)) { + if (error & ata_err_unc) { strcat(str, "unc,"); } - if (bit_check(error, ata_err_bbk)) { + if (error & ata_err_bbk) { strcat(str, "bbk,"); } return str; @@ -470,10 +399,7 @@ static inline const char *ata_get_device_status_str(uint8_t status) static inline const char *ata_get_device_settings_str(ata_device_t *dev) { - if (dev->io_base == 0x1F0) { - return (dev->slave) ? "Primary Slave" : "Primary Master"; - } - return (dev->slave) ? "Secondary Slave" : "Secondary Master"; + return (dev->primary) ? ((dev->master) ? "Primary Master" : "Primary Slave") : ((dev->master) ? "Secondary Master" : "Secondary Slave"); } static inline const char *ata_get_device_type_str(ata_device_type_t type) @@ -556,25 +482,6 @@ static inline void ata_dump_device(ata_device_t *dev) pr_debug(" }\n"); } -/// @brief Read all the io registers. -/// @param dev the device for which we read the registers. -/// @return the values of all registers. -static inline ata_io_reg_t ata_read_registers(ata_device_t *dev) -{ - return (ata_io_reg_t){ - .data = inportb(dev->io_reg.data), - .error = inportb(dev->io_reg.error), - .feature = inportb(dev->io_reg.feature), - .sector_count = inportb(dev->io_reg.sector_count), - .lba_lo = inportb(dev->io_reg.lba_lo), - .lba_mid = inportb(dev->io_reg.lba_mid), - .lba_hi = inportb(dev->io_reg.lba_hi), - .hddevsel = inportb(dev->io_reg.hddevsel), - .status = inportb(dev->io_reg.status), - .command = inportb(dev->io_reg.command) - }; -} - /// @brief Waits for 400 nanoseconds. /// @param dev the device on which we wait. static inline void ata_io_wait(ata_device_t *dev) @@ -774,40 +681,10 @@ static inline void ata_dma_initialize_bus_mastering_address(ata_device_t *dev) static inline ata_device_type_t ata_detect_device_type(ata_device_t *dev) { pr_debug("[%s] Detecting device type...\n", ata_get_device_settings_str(dev)); - // Disable IRQs. - outportb(dev->io_control, 0x00); - // Wait for the command to work. - ata_io_wait(dev); // Select the drive. outportb(dev->io_reg.hddevsel, 0xA0 | (dev->slave << 4U)); // Wait for the command to work. ata_io_wait(dev); - // Get the "signature bytes" by reading low and high cylinder register. - uint8_t lba_lo = inportb(dev->io_reg.lba_hi); - uint8_t lba_mid = inportb(dev->io_reg.lba_mid); - uint8_t lba_hi = inportb(dev->io_reg.lba_hi); - // Differentiate ATA, ATAPI, SATA and SATAPI. - if ((lba_mid == 0x00) && (lba_hi == 0x00)) { - return ata_dev_type_pata; - } - if ((lba_mid == 0x3C) && (lba_hi == 0xC3)) { - return ata_dev_type_sata; - } - if ((lba_mid == 0x14) && (lba_hi == 0xEB)) { - return ata_dev_type_patapi; - } - if ((lba_mid == 0x69) && (lba_hi == 0x96)) { - return ata_dev_type_satapi; - } - if ((lba_mid == 0xFF) && (lba_hi == 0xFF)) { - return ata_dev_type_no_device; - } - return ata_dev_type_unknown; -} - -static bool_t ata_device_init(ata_device_t *dev) -{ - pr_debug("[%s] Initializing ATA device...\n", ata_get_device_settings_str(dev)); // Select the ATA device. outportb(dev->io_base + 1, 1); // Disable IRQs. @@ -838,16 +715,39 @@ static bool_t ata_device_init(ata_device_t *dev) return 1; } // Read the identity. - uint16_t *buffer = (uint16_t *)&dev->identity; - for (unsigned i = 0; i < (sizeof(ata_identity_t) / sizeof(uint16_t)); ++i) { - buffer[i] = inports(dev->io_reg.data); - } + inportsw(dev->io_reg.data, (uint16_t *)&dev->identity, (sizeof(ata_identity_t) / sizeof(uint16_t))); // Fix the serial. ata_fix_string((char *)&dev->identity.serial_number, count_of(dev->identity.serial_number) - 1); // Fix the firmware. ata_fix_string((char *)&dev->identity.firmware_revision, count_of(dev->identity.firmware_revision) - 1); // Fix the model. ata_fix_string((char *)&dev->identity.model_number, count_of(dev->identity.model_number) - 1); + // Get the "signature bytes" by reading low and high cylinder register. + uint8_t lba_lo = inportb(dev->io_reg.lba_hi); + uint8_t lba_mid = inportb(dev->io_reg.lba_mid); + uint8_t lba_hi = inportb(dev->io_reg.lba_hi); + // Differentiate ATA, ATAPI, SATA and SATAPI. + if ((lba_mid == 0x00) && (lba_hi == 0x00)) { + return ata_dev_type_pata; + } + if ((lba_mid == 0x3C) && (lba_hi == 0xC3)) { + return ata_dev_type_sata; + } + if ((lba_mid == 0x14) && (lba_hi == 0xEB)) { + return ata_dev_type_patapi; + } + if ((lba_mid == 0x69) && (lba_hi == 0x96)) { + return ata_dev_type_satapi; + } + if ((lba_mid == 0xFF) && (lba_hi == 0xFF)) { + return ata_dev_type_no_device; + } + return ata_dev_type_unknown; +} + +static bool_t ata_device_init(ata_device_t *dev) +{ + pr_debug("[%s] Initializing ATA device...\n", ata_get_device_settings_str(dev)); // Check the status of the device. if (ata_status_wait_for(dev, ata_status_drq | ata_status_rdy, 10000)) { ata_print_status_error(dev); @@ -1318,6 +1218,9 @@ static ata_device_type_t ata_device_detect(ata_device_t *dev) if (type == ata_dev_type_unknown) { pr_debug("[%s] Found unsupported device...\n", ata_get_device_settings_str(dev)); } + if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { + pr_notice(" Found %s device connected to %s.\n", ata_get_device_type_str(type), ata_get_device_settings_str(dev)); + } return type; } @@ -1365,23 +1268,10 @@ int ata_initialize() // Enable bus mastering. ata_dma_enable_bus_mastering(); - ata_device_type_t type; - type = ata_device_detect(&ata_primary_master); - if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { - pr_info(" Found %s device connected to primary master.\n", ata_get_device_type_str(type)); - } - type = ata_device_detect(&ata_primary_slave); - if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { - pr_info(" Found %s device connected to primary slave.\n", ata_get_device_type_str(type)); - } - type = ata_device_detect(&ata_secondary_master); - if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { - pr_info(" Found %s device connected to secondary master.\n", ata_get_device_type_str(type)); - } - type = ata_device_detect(&ata_secondary_slave); - if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { - pr_info(" Found %s device connected to secondary slave.\n", ata_get_device_type_str(type)); - } + ata_device_detect(&ata_primary_master); + ata_device_detect(&ata_primary_slave); + ata_device_detect(&ata_secondary_master); + ata_device_detect(&ata_secondary_slave); return 0; } diff --git a/mentos/src/kernel.c b/mentos/src/kernel.c index 316cc96..442a8c2 100644 --- a/mentos/src/kernel.c +++ b/mentos/src/kernel.c @@ -15,7 +15,7 @@ #include "descriptor_tables/idt.h" #include "drivers/keyboard/keyboard.h" #include "drivers/keyboard/keymap.h" -#include "drivers/ata.h" +#include "drivers/ata/ata.h" #include "drivers/rtc.h" #include "drivers/ps2.h" #include "process/scheduler_feedback.h" diff --git a/mentos/src/mem/zone_allocator.c b/mentos/src/mem/zone_allocator.c index 53392c8..5a08500 100644 --- a/mentos/src/mem/zone_allocator.c +++ b/mentos/src/mem/zone_allocator.c @@ -4,10 +4,10 @@ /// See LICENSE.md for details. // Setup the logging for this file (do this before any other include). -#include "sys/kernel_levels.h" // Include kernel log levels. -#define __DEBUG_HEADER__ "[PMM ]" ///< Change header. -#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level. -#include "io/debug.h" // Include debugging functions. +#include "sys/kernel_levels.h" // Include kernel log levels. +#define __DEBUG_HEADER__ "[PMM ]" ///< Change header. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level. +#include "io/debug.h" // Include debugging functions. #include "mem/zone_allocator.h" #include "mem/buddysystem.h"