Skip to content

Commit f5090ab

Browse files
supercomputer7awesomekling
authored andcommitted
Kernel: Restore ATA PIO functionality
First, before this change, specifying 'force_pio' in the kernel commandline was meaningless because we nevertheless set the DMA flag to be enabled. Also, we had a problem in which we used IO::repeated_out16() in PIO write method. This might work on buggy emulators, but I suspect that on real hardware this code will fail. The most difficult problem was to restore the PIO read operation. Apparently, it seems that we can't use IO::repeated_in16() here because it will read zeroed data. Currently we rely on a simple loop that invokes IO::in16() to a buffer. Also, the interrupt handling stage in the PIO read method is moved to be handled inside the loop of reading the requested sectors.
1 parent 3f698db commit f5090ab

File tree

1 file changed

+43
-31
lines changed

1 file changed

+43
-31
lines changed

Kernel/Devices/PATAChannel.cpp

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,9 @@ PATAChannel::PATAChannel(PCI::Address address, ChannelType type, bool force_pio)
136136
{
137137
disable_irq();
138138

139-
m_dma_enabled.resource() = true;
139+
m_dma_enabled.resource() = !force_pio;
140140
ProcFS::add_sys_bool("ide_dma", m_dma_enabled);
141141

142-
m_prdt_page = MM.allocate_supervisor_physical_page();
143142
initialize(force_pio);
144143
detect_disks();
145144
disable_irq();
@@ -157,14 +156,15 @@ void PATAChannel::prepare_for_irq()
157156

158157
void PATAChannel::initialize(bool force_pio)
159158
{
160-
159+
PCI::enable_interrupt_line(pci_address());
161160
if (force_pio) {
162161
klog() << "PATAChannel: Requested to force PIO mode; not setting up DMA";
163162
return;
164163
}
164+
165165
// Let's try to set up DMA transfers.
166166
PCI::enable_bus_mastering(pci_address());
167-
PCI::enable_interrupt_line(pci_address());
167+
m_prdt_page = MM.allocate_supervisor_physical_page();
168168
prdt().end_of_table = 0x8000;
169169
m_dma_buffer_page = MM.allocate_supervisor_physical_page();
170170
klog() << "PATAChannel: Bus master IDE: " << m_bus_master_base;
@@ -402,57 +402,66 @@ bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf
402402
return true;
403403
}
404404

405-
bool PATAChannel::ata_read_sectors(u32 start_sector, u16 count, u8* outbuf, bool slave_request)
405+
bool PATAChannel::ata_read_sectors(u32 lba, u16 count, u8* outbuf, bool slave_request)
406406
{
407407
ASSERT(count <= 256);
408408
LOCKER(s_lock());
409409
#ifdef PATA_DEBUG
410-
dbg() << "PATAChannel::ata_read_sectors request (" << count << " sector(s) @ " << start_sector << " into " << outbuf << ")";
410+
dbg() << "PATAChannel::ata_read_sectors request (" << count << " sector(s) @ " << lba << " into " << outbuf << ")";
411411
#endif
412412

413413
while (m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY)
414414
;
415415

416416
#ifdef PATA_DEBUG
417-
klog() << "PATAChannel: Reading " << count << " sector(s) @ LBA " << start_sector;
417+
klog() << "PATAChannel: Reading " << count << " sector(s) @ LBA " << lba;
418418
#endif
419419

420420
u8 devsel = 0xe0;
421421
if (slave_request)
422422
devsel |= 0x10;
423423

424-
m_io_base.offset(ATA_REG_SECCOUNT0).out<u8>(count == 256 ? 0 : LSB(count));
425-
m_io_base.offset(ATA_REG_LBA0).out<u8>(start_sector & 0xff);
426-
m_io_base.offset(ATA_REG_LBA1).out<u8>((start_sector >> 8) & 0xff);
427-
m_io_base.offset(ATA_REG_LBA2).out<u8>((start_sector >> 16) & 0xff);
428-
m_io_base.offset(ATA_REG_HDDEVSEL).out<u8>(devsel | ((start_sector >> 24) & 0xf));
424+
m_control_base.offset(ATA_CTL_CONTROL).out<u8>(0);
425+
m_io_base.offset(ATA_REG_HDDEVSEL).out<u8>(devsel | (static_cast<u8>(slave_request) << 4) | 0x40);
426+
io_delay();
429427

430-
IO::out8(0x3F6, 0x08);
431-
while (!(m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_DRDY))
432-
;
428+
m_io_base.offset(ATA_REG_FEATURES).out<u8>(0);
433429

434-
prepare_for_irq();
435-
m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_READ_PIO);
436-
wait_for_irq();
430+
m_io_base.offset(ATA_REG_SECCOUNT0).out<u8>(0);
431+
m_io_base.offset(ATA_REG_LBA0).out<u8>(0);
432+
m_io_base.offset(ATA_REG_LBA1).out<u8>(0);
433+
m_io_base.offset(ATA_REG_LBA2).out<u8>(0);
437434

438-
if (m_device_error)
439-
return false;
435+
m_io_base.offset(ATA_REG_SECCOUNT0).out<u8>(count);
436+
m_io_base.offset(ATA_REG_LBA0).out<u8>((lba & 0x000000ff) >> 0);
437+
m_io_base.offset(ATA_REG_LBA1).out<u8>((lba & 0x0000ff00) >> 8);
438+
m_io_base.offset(ATA_REG_LBA2).out<u8>((lba & 0x00ff0000) >> 16);
439+
440+
for (;;) {
441+
auto status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
442+
if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY))
443+
break;
444+
}
445+
446+
m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_READ_PIO);
440447

441448
for (int i = 0; i < count; i++) {
442-
io_delay();
449+
prepare_for_irq();
450+
wait_for_irq();
451+
if (m_device_error)
452+
return false;
443453

444-
while (m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY)
445-
;
454+
u8 status = m_control_base.offset(ATA_CTL_ALTSTATUS).in<u8>();
455+
ASSERT(!(status & ATA_SR_BSY));
446456

447-
u8 status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
448-
ASSERT(status & ATA_SR_DRQ);
457+
auto* buffer = (u16*)(outbuf + i * 512);
449458
#ifdef PATA_DEBUG
450-
dbg() << "PATAChannel: Retrieving 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), outbuf=(" << (outbuf + (512 * i)) << ")...";
459+
dbg() << "PATAChannel: Retrieving 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), outbuf=(" << buffer << ")...";
451460
#endif
452-
453-
IO::repeated_in16(m_io_base.offset(ATA_REG_DATA).get(), outbuf + (512 * i), 256);
461+
for (int i = 0; i < 256; i++) {
462+
buffer[i] = IO::in16(m_io_base.offset(ATA_REG_DATA).get());
463+
}
454464
}
455-
456465
return true;
457466
}
458467

@@ -489,7 +498,7 @@ bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const u8* inbuf
489498

490499
for (int i = 0; i < count; i++) {
491500
io_delay();
492-
while (m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY)
501+
while ((m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY) || !(m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_DRQ))
493502
;
494503

495504
u8 status = m_io_base.offset(ATA_REG_STATUS).in<u8>();
@@ -499,7 +508,10 @@ bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const u8* inbuf
499508
dbg() << "PATAChannel: Writing 512 bytes (part " << i << ") (status=" << String::format("%b", status) << "), inbuf=(" << (inbuf + (512 * i)) << ")...";
500509
#endif
501510

502-
IO::repeated_out16(m_io_base.offset(ATA_REG_DATA).get(), inbuf + (512 * i), 256);
511+
auto* buffer = (u16*)(const_cast<u8*>(inbuf) + i * 512);
512+
for (int i = 0; i < 256; i++) {
513+
IO::out16(m_io_base.offset(ATA_REG_DATA).get(), buffer[i]);
514+
}
503515
prepare_for_irq();
504516
wait_for_irq();
505517
status = m_io_base.offset(ATA_REG_STATUS).in<u8>();

0 commit comments

Comments
 (0)