diff --git a/kernel/include/kernel/ATA.h b/kernel/include/kernel/ATA.h index b565d992..39986bd7 100644 --- a/kernel/include/kernel/ATA.h +++ b/kernel/include/kernel/ATA.h @@ -38,7 +38,9 @@ namespace Kernel : ATADevice(io_base, ctl_base, slave_bit) {} + virtual uint32_t sector_size() const override { return m_sector_words * 2; } virtual const char* type() const override { return "PATA"; } + virtual bool read(uint32_t lba, uint32_t sector_count, uint8_t* buffer) override; protected: @@ -52,6 +54,7 @@ namespace Kernel private: bool m_lba_48 = false; + uint32_t m_sector_words = 256; }; diff --git a/kernel/include/kernel/DiskIO.h b/kernel/include/kernel/DiskIO.h index 3ad0f658..24a61136 100644 --- a/kernel/include/kernel/DiskIO.h +++ b/kernel/include/kernel/DiskIO.h @@ -25,6 +25,7 @@ namespace Kernel bool initialize_partitions(); virtual bool read(uint32_t lba, uint32_t sector_count, uint8_t* buffer) = 0; + virtual uint32_t sector_size() const = 0; private: BAN::Vector m_partitions; diff --git a/kernel/kernel/ATA.cpp b/kernel/kernel/ATA.cpp index fd2acc37..bbd0fdfe 100644 --- a/kernel/kernel/ATA.cpp +++ b/kernel/kernel/ATA.cpp @@ -125,8 +125,20 @@ namespace Kernel uint16_t response[256]; for (int i = 0; i < 256; i++) response[i] = IO::inw(io_base() + ATA_IO_PORT_DATA); + m_lba_48 = response[83] & (1 << 10); + if (!(response[106] & (1 << 15)) + && (response[106] & (1 << 14)) + && (response[106] & (1 << 12))) + { + m_sector_words = ((uint32_t)response[117] << 16) | response[118]; + dprintln("using {} sector size", m_sector_words * 2); + } + + + + return true; } @@ -158,7 +170,7 @@ namespace Kernel // 7. Send the "READ SECTORS" command (0x20) to port 0x1F7: outb(0x1F7, 0x20) IO::outb(io_base() + ATA_IO_PORT_COMMAND, ATA_COMMAND_READ_SECTORS); - memset(buffer, 0, sector_count * 256 * sizeof(uint16_t)); + memset(buffer, 0, sector_count * m_sector_words * sizeof(uint16_t)); for (int i = 0; i < sector_count; i++) { // 8. Wait for an IRQ or poll. @@ -167,11 +179,11 @@ namespace Kernel // 9. Transfer 256 16-bit values, a uint16_t at a time, into your buffer from I/O port 0x1F0. // (In assembler, REP INSW works well for this.) - for (int j = 0; j < 256; j++) + for (size_t j = 0; j < m_sector_words; j++) { uint16_t word = IO::inw(io_base() + ATA_IO_PORT_DATA); - buffer[i * 512 + j * 2 + 0] = word & 0xFF; - buffer[i * 512 + j * 2 + 1] = word >> 8; + buffer[(i * m_sector_words + j) * 2 + 0] = word & 0xFF; + buffer[(i * m_sector_words + j) * 2 + 1] = word >> 8; } // 10. Then loop back to waiting for the next IRQ (or poll again -- see next note) for each successive sector. diff --git a/kernel/kernel/DiskIO.cpp b/kernel/kernel/DiskIO.cpp index 021adab9..2d53b3db 100644 --- a/kernel/kernel/DiskIO.cpp +++ b/kernel/kernel/DiskIO.cpp @@ -114,76 +114,69 @@ namespace Kernel return result; } - static bool is_valid_gpt_header(const GPTHeader& header) + static bool is_valid_gpt_header(const GPTHeader& header, uint32_t sector_size) { if (memcmp(header.signature, "EFI PART", 8) != 0) return false; if (header.revision != 0x00010000) return false; - if (header.size < 92 || header.size > 512) + if (header.size < 92 || header.size > sector_size) return false; if (header.my_lba != 1) return false; return true; } - static bool is_valid_gpt_crc32(const GPTHeader& header, const uint8_t* lba1, const uint8_t* entry_array) + static bool is_valid_gpt_crc32(const GPTHeader& header, BAN::Vector lba1, const BAN::Vector& entry_array) { - uint8_t lba1_copy[512]; - memcpy(lba1_copy, lba1, 512); - memset(lba1_copy + 16, 0, 4); - if (header.crc32 != crc32_checksum(lba1_copy, header.size)) + memset(lba1.data() + 16, 0, 4); + if (header.crc32 != crc32_checksum(lba1.data(), header.size)) return false; - if (header.partition_entry_array_crc32 != crc32_checksum(entry_array, header.partition_entry_count * header.partition_entry_size)) + if (header.partition_entry_array_crc32 != crc32_checksum(entry_array.data(), header.partition_entry_count * header.partition_entry_size)) return false; return true; } - static GPTHeader parse_gpt_header(const uint8_t* lba1) + static GPTHeader parse_gpt_header(const BAN::Vector lba1) { GPTHeader header; memset(&header, 0, sizeof(header)); - memcpy(header.signature, lba1, 8); - memcpy(header.guid, lba1 + 56, 16); - header.revision = little_endian_to_host(lba1 + 8); - header.size = little_endian_to_host(lba1 + 12); - header.crc32 = little_endian_to_host(lba1 + 16); - header.my_lba = little_endian_to_host(lba1 + 24); - header.first_lba = little_endian_to_host(lba1 + 40); - header.last_lba = little_endian_to_host(lba1 + 48); - header.partition_entry_lba = little_endian_to_host(lba1 + 72); - header.partition_entry_count = little_endian_to_host(lba1 + 80); - header.partition_entry_size = little_endian_to_host(lba1 + 84); - header.partition_entry_array_crc32 = little_endian_to_host(lba1 + 88); + memcpy(header.signature, lba1.data(), 8); + memcpy(header.guid, lba1.data() + 56, 16); + header.revision = little_endian_to_host(lba1.data() + 8); + header.size = little_endian_to_host(lba1.data() + 12); + header.crc32 = little_endian_to_host(lba1.data() + 16); + header.my_lba = little_endian_to_host(lba1.data() + 24); + header.first_lba = little_endian_to_host(lba1.data() + 40); + header.last_lba = little_endian_to_host(lba1.data() + 48); + header.partition_entry_lba = little_endian_to_host(lba1.data() + 72); + header.partition_entry_count = little_endian_to_host(lba1.data() + 80); + header.partition_entry_size = little_endian_to_host(lba1.data() + 84); + header.partition_entry_array_crc32 = little_endian_to_host(lba1.data() + 88); return header; } bool DiskDevice::initialize_partitions() { - uint8_t lba1[512]; - if (!read(1, 1, lba1)) + BAN::Vector lba1(sector_size()); + if (!read(1, 1, lba1.data())) return false; GPTHeader header = parse_gpt_header(lba1); - if (!is_valid_gpt_header(header)) + if (!is_valid_gpt_header(header, sector_size())) { dprintln("invalid gpt header"); return false; } - uint8_t* entry_array = nullptr; + BAN::Vector entry_array; { uint32_t bytes = header.partition_entry_count * header.partition_entry_size; - uint32_t sectors = (bytes + 511) / 512; - entry_array = (uint8_t*)kmalloc(sectors * 512); - if (entry_array == nullptr) + uint32_t sectors = (bytes + sector_size() - 1) / sector_size(); + MUST(entry_array.resize(sectors * sector_size())); + if (!read(header.partition_entry_lba, sectors, entry_array.data())) return false; - if (!read(header.partition_entry_lba, sectors, entry_array)) - { - kfree(entry_array); - return false; - } } if (!is_valid_gpt_crc32(header, lba1, entry_array)) @@ -194,7 +187,7 @@ namespace Kernel for (uint32_t i = 0; i < header.partition_entry_count; i++) { - uint8_t* partition_data = entry_array + header.partition_entry_size * i; + uint8_t* partition_data = entry_array.data() + header.partition_entry_size * i; Partition partition; memcpy(partition.type_guid, partition_data, 16);