00001 #if !defined(__ATA_DRIVE_HPP__)
00002 #define __ATA_DRIVE_HPP__
00003
00004
00005
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
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,
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
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;
00164 unsigned commit_bytes;
00165 uint8_t buffer[BUFFER_SIZE];
00166 uint8_t *data_ptr, *end_ptr;
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
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
00239
00240 inline void set_irq(const l4_irq_t irq)
00241 {
00242
00243 if (machine.is_valid_irq(irq)) this->irq=irq;
00244 }
00245
00246 inline void assert_irq_if_enabled(void) const
00247 {
00248
00249
00250
00251
00252 if (likely(!control_block.device_control.nIEN)) machine.assert_irq(irq);
00253 }
00254
00255
00256
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
00266
00267
00268 int read_write_DMA(uint8_t read_write, l4_gpa_t PRD_base);
00269
00270 protected:
00271
00272
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
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
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
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
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
00372