Overview   API Reference  

ata_drive.hpp

00001 #if !defined(__ATA_DRIVE_HPP__)
00002 #define __ATA_DRIVE_HPP__
00003 
00004 //
00005 // local includes
00006 //
00007 #include "core/drivers/block/block_driver.hpp"
00008 #include "core/machine/machine_base.hpp"
00009 #include "ata_command_block.hpp"
00010 #include "ata_control_block.hpp"
00011 
00015 struct ata_drive : public block_driver_constants, private noncopyable
00016 {
00020     static const uint8_t MAX_MULTIPLE_SECTORS = 128;
00021 
00026     static const uint32_t BUFFER_SIZE = SECTOR_SIZE * 256;
00027 
00028     //
00029     // keep in sync with block_driver::state_flags_constants
00030     //
00031     enum state_flags_constants
00032     {
00034         REMOVABLE   = 1 << (static_log2<block_driver::ALL_MASK>::value + 1),
00036         FAKE_IO     = REMOVABLE << 1,
00037 
00039         ALL_MASK    = block_driver::ALL_MASK | REMOVABLE | FAKE_IO
00040     };
00041 
00042     typedef bitmask<uint_value_t<ALL_MASK>::least> state_flags;
00043     static_assert(integer_traits<state_flags::word_type>::const_max >= ALL_MASK,
00044                   "state_flags's max value is too small");
00045 
00046   protected:
00050     string drive_name;
00051 
00056     machine_base &machine;
00057 
00061     l4_irq_t irq;
00062 
00066     ata_command_block command_block;
00067 
00071     ata_control_block control_block;
00072 
00076     block_driver * const driver;
00077 
00081     state_flags state;
00082 
00086     uint8_t multiple_sectors;
00087 
00091     uint8_t last_command;
00092 
00096     struct geometry
00097     {
00098         enum chs_constants
00099         {
00100             MAX_CYLINDERS = 65536,
00101             MAX_HEADS     = 16,             // 256 for larger disks
00102             MAX_SECTORS   = 255
00103         };
00104 
00106         l4_sector_t total_sectors;
00108         uint32_t    cylinders;
00110         uint16_t    heads;
00112         uint8_t     sectors;
00113 
00114         inline uint32_t get_cylinders(const uint16_t heads, const uint8_t sectors)
00115         {
00116             return total_sectors / (static_cast<l4_sector_t>(heads) * sectors);
00117         }
00118 
00119         inline int operator ()(const l4_sector_t total_sectors)
00120         {
00121             this->total_sectors=total_sectors;
00122             this->heads=MAX_HEADS;
00123 
00124             // default: ?/16/63 CHS translation
00125             static const uint8_t SECTORS[] = {63, MAX_SECTORS};
00126 
00127             for (const uint8_t *sn=beginof(SECTORS); sn != endof(SECTORS); sn++) {
00128                 cylinders=get_cylinders(heads, *sn);
00129                 if (cylinders <= MAX_CYLINDERS) {
00130                     sectors=*sn;
00131                     return 0;
00132                 }
00133             }
00134 
00135             cylinders=heads=sectors=0;
00136             return -L4_EINVAL;
00137         }
00138 
00139         inline int operator ()(const uint16_t heads, const uint8_t sectors)
00140         {
00141             const uint32_t cylinders=get_cylinders(heads, sectors);
00142             if (cylinders > MAX_CYLINDERS) return -L4_EINVAL;
00143 
00144             this->cylinders=cylinders;
00145             this->heads=heads;
00146             this->sectors=sectors;
00147             return 0;
00148         }
00149 
00150         inline uint16_t total_sectors_word(const uint8_t index)
00151         {
00152             return total_sectors >> (index * 16);
00153         }
00154     } geometry;
00155 
00159     struct transaction
00160     {
00161         const ata_drive &drive;
00162 
00163         l4_sector_t sector, number;             // [sectors]
00164         unsigned    commit_bytes;               // [bytes]
00165         uint8_t     buffer[BUFFER_SIZE];        // buffer to cache blocks
00166         uint8_t     *data_ptr, *end_ptr;        // pointer to positions in buffer
00167 
00168         inline transaction(const ata_drive &drive)
00169             : drive(drive), sector(0), number(0), commit_bytes(0), data_ptr(nullptr), end_ptr(nullptr)
00170         {}
00171 
00172         inline int reset(void)
00173         {
00174             sector=number=commit_bytes=0;
00175             data_ptr=end_ptr=nullptr;
00176             return 0;
00177         }
00178 
00179         inline int setup(l4_sector_t sector, l4_sector_t number, unsigned commit_blocks=0)
00180         {
00181             if (unlikely(data_ptr || end_ptr || commit_bytes)) {
00182                 logd(L4VMM_DEBUG_ATA >= 2, L4VMM_ERROR": %s:\n"
00183                      "  I/O buffer is not empty. %zd bytes untransferred.\n",
00184                      drive.name(), end_ptr - data_ptr);
00185 
00186                 return -L4_EBUSY;
00187             }
00188 
00189             this->sector=sector;
00190             this->number=number;
00191             data_ptr=buffer;
00192             end_ptr=data_ptr + number * SECTOR_SIZE;
00193             commit_bytes=commit_blocks * SECTOR_SIZE;
00194 
00195             return 0;
00196         }
00197 
00198         inline bool is_end_of_block(void) const
00199         {
00200             return commit_bytes && ((data_ptr - buffer) % commit_bytes) == 0;
00201         }
00202 
00203         inline bool is_end(void) const
00204         {
00205             return commit_bytes && (data_ptr >= end_ptr);
00206         }
00207     } transaction;
00208 
00209   public:
00210     //
00211     // constructor & destructor
00212     //
00213     ata_drive(machine_base &machine, block_driver *driver=nullptr, state_flags flags=0);
00214     ~ata_drive(void);
00215 
00216     inline int reset(void)
00217     {
00218         return transaction.reset() | (driver ? driver->reset() : 0);
00219     }
00220 
00221     inline const char *name(void) const
00222     {
00223         return drive_name.c_str();
00224     }
00225 
00226     inline void set_drive_name_index(const string &name, const uint8_t index)
00227     {
00228         drive_name=name;
00229         command_block.device.dev=index;
00230     }
00231 
00232     inline bool is_ready(void) const
00233     {
00234         return state.is(READY);
00235     }
00236 
00237     //
00238     // resources functions
00239     //
00240     inline void set_irq(const l4_irq_t irq)
00241     {
00242         // the controller requests an IRQ, so always (try to) use what is set
00243         if (machine.is_valid_irq(irq)) this->irq=irq;
00244     }
00245 
00246     inline void assert_irq_if_enabled(void) const
00247     {
00248         //
00249         // do not check the IRQ here. if it is not valid, we want to see the error.
00250         //     assert_irq doesn't check this too.
00251         //
00252         if (likely(!control_block.device_control.nIEN)) machine.assert_irq(irq);
00253     }
00254 
00255     //
00256     // register block functions
00257     //
00258     uint32_t read_command_block(ata_command_block::offset_t offset, access_size access_size);
00259     int write_command_block(ata_command_block::offset_t offset, uint32_t data, access_size access_size);
00260 
00261     uint32_t read_control_block(ata_control_block::offset_t offset, access_size access_size);
00262     int write_control_block(ata_control_block::offset_t offset, uint32_t data, access_size access_size);
00263 
00264     //
00265     // DMA read/write functions:
00266     //     read_write as the IDE controller was programed
00267     //
00268     int read_write_DMA(uint8_t read_write, l4_gpa_t PRD_base);
00269 
00270   protected:
00271     //
00272     // ATA command execute functions
00273     //
00274     bool check_sector_range(l4_sector_t sector, l4_sector_t number)
00275     {
00276         if (likely(sector + number <= geometry.total_sectors)) return true;
00277 
00278         logd(L4VMM_DEBUG_ATA >= 2, L4VMM_ERROR": %s:\n"
00279              "  trying to access beyond end of device\n", name());
00280         command_block.lba28_sector_address(geometry.total_sectors);
00281         return false;
00282     }
00283 
00284     void identify_device(void);
00285     void execute_command(uint8_t command);
00286 
00287     //
00288     // read functions
00289     //
00290     inline int read_from_media(uint8_t *dst, l4_sector_t sector, l4_sector_t number)
00291     {
00292         if (state.is(FAKE_IO)) return 0;
00293         const int err=driver->read_sectors(dst, sector, number);
00294 
00295         assert_logd(L4VMM_DEBUG_ATA, err == 0, "%s:\n"
00296                     "  read I/O error from block driver %s: %s (%d)\n",
00297                     name(), driver->name(), l4env_errstr(err), err);
00298         return err;
00299     }
00300 
00301     inline int read_buffer_from_media(l4_sector_t sector, l4_sector_t number, unsigned commit_blocks=0)
00302     {
00303         if (const int err=successfully(transaction.setup(sector, number, commit_blocks))) return err;
00304         return read_from_media(transaction.buffer, transaction.sector, transaction.number);
00305     }
00306 
00307     inline uint32_t read_from_buffer(access_size access_size)
00308     {
00309         assertd(L4VMM_DEBUG_ATA, transaction.data_ptr != nullptr);
00310 
00311         const uint32_t ret=*reinterpret_cast<uint32_t *>(transaction.data_ptr);
00312         transaction.data_ptr+=access_size;
00313         return ret;
00314     }
00315 
00316     //
00317     // write functions
00318     //
00319     inline int write_to_media(uint8_t *src, l4_sector_t sector, l4_sector_t number)
00320     {
00321         if (state.is(FAKE_IO)) return 0;
00322         const int err=driver->write_sectors(src, sector, number);
00323 
00324         assert_logd(L4VMM_DEBUG_ATA, err == 0, "%s:\n"
00325                     "  write I/O error from block driver %s: %s (%d)\n",
00326                     name(), driver->name(), l4env_errstr(err), err);
00327         return err;
00328     }
00329 
00330     inline int write_buffer_to_media(void)
00331     {
00332         // buffer (and transaction) was set up when the command was issued
00333         return write_to_media(transaction.buffer, transaction.sector, transaction.number);
00334     }
00335 
00336     inline int write_to_buffer(uint32_t data, access_size access_size)
00337     {
00338         assertd(L4VMM_DEBUG_ATA, transaction.data_ptr != nullptr);
00339 
00340         *reinterpret_cast<uint32_t *>(transaction.data_ptr)=data;
00341         transaction.data_ptr+=access_size;
00342         return 0;
00343     }
00344 
00345     //
00346     // DMA functions
00347     //
00348     inline int read_write_media(uint8_t read_write, l4_hva_t base, l4_hva_t size)
00349     {
00350         assertd(L4VMM_DEBUG_ATA, size % SECTOR_SIZE == 0);
00351         const l4_hva_t number=size / SECTOR_SIZE;
00352 
00353         logd(L4VMM_DEBUG_ATA >= 4, "  transferring "l4_hva_fmt" blocks ["l4_hva_fmt"] %s "l4_hva_fmt"\n",
00354              number, size, read_write ? "to" : "from", base);
00355 
00356         if (const int err=successfully((read_write) ?
00357                               read_from_media(reinterpret_cast<uint8_t *>(base), transaction.sector, number) :
00358                                   write_to_media(reinterpret_cast<uint8_t *>(base), transaction.sector, number))) {
00359             transaction.reset();
00360             return err;
00361         }
00362 
00363         transaction.sector+=number;
00364         transaction.number-=number;
00365         return 0;
00366     }
00367 };
00368 
00369 #endif
00370 
00371 // ***** end of source ***** //
00372 

L4vmm Reference Manual, written by Mario Schwalbe  © 2006-2008