ATA 读/写期间分页错误

问题描述 投票:0回答:1

大家

当我尝试在 [code]updateDir [/code] 函数中执行 ATA 读写操作时,我的自定义操作系统遇到分页错误。我已经确定问题发生在我的 updateDir 函数的以下代码块中:

// Read the current directory entries from the disk
uint8_t dir_buffer[MAX_DIR * 16] = {0};

ata_identify(ATA_PRIMARY_IO, ATA_MASTER);
ata_read(ATA_PRIMARY_IO, ATA_MASTER, START_DIR, 1, dir_buffer);

// Copy the DirEntry struct into the directory buffer at the correct position
memcpy(&dir_buffer[pos * 16], &entry, sizeof(DirEntry));

// Write the updated directory entries back to the disk
ata_identify(ATA_PRIMARY_IO, ATA_MASTER);
ata_write(ATA_PRIMARY_IO, ATA_MASTER, START_DIR, MAX_DIR * 16 / 512, dir_buffer);

当此代码运行时,CPU 会报告分页错误,并显示以下调试输出:

CR2=00000000
EIP=c01015d0

完整上下文 这是有问题的代码所在的完整函数:

bool_t updateDir(char* filename) {
    DirEntry entry = {0};
    strncpy((char *)entry.name, filename, sizeof(entry.name) - 1);
    entry.size = 0;

    int pos = -1;

    // Find the first available directory slot
    for (int i = 0; i < MAX_DIR; i++) {
        if (dir[i] == 0) {
            dir[i] = 1;
            entry.fat_entry = i;
            pos = i;
            break;
        }
    }

    if (pos == -1) {
        printf("Error: No free directory entry found\n");
        return false;
    }

    uint8_t dir_buffer[MAX_DIR * 16] = {0};

    ata_identify(ATA_PRIMARY_IO, ATA_MASTER);
    ata_read(ATA_PRIMARY_IO, ATA_MASTER, START_DIR, 1, dir_buffer);

    memcpy(&dir_buffer[pos * 16], &entry, sizeof(DirEntry));

    ata_identify(ATA_PRIMARY_IO, ATA_MASTER);
    ata_write(ATA_PRIMARY_IO, ATA_MASTER, START_DIR, MAX_DIR * 16 / 512, dir_buffer);

    return true;
}

ata.c:

#include "../Includes/ata.h"

void ata_initialize(uint16_t io_base, uint8_t drive) {
    outPort(io_base + 6, drive);
    outPort(io_base + 2, 0);
    outPort(io_base + 3, 0);
    outPort(io_base + 4, 0);
    outPort(io_base + 5, 0);
    outPort(io_base + 7, 0xEC);

    uint8_t status = inPort(io_base + 7);

    // Wait for BSY to clear
    while ((status & 0x80) != 0) {
        status = inPort(io_base + 7);
    }
}

static void ata_wait_bsy(uint16_t io_base) {
    while (inPort(io_base + 7) & 0x80); // Wait for BSY to clear
}

static void ata_wait_drq(uint16_t io_base) {
    while (!(inPort(io_base + 7) & 0x08)); // Wait for DRQ to set
}

void ata_read(uint16_t io_base, uint8_t drive, uint32_t lba, uint8_t sectors, uint8_t* buffer) {
    if (!buffer || sectors == 0) {
        return;
    }

    if (sectors > 256) {
        return;
    }

    // Select drive and LBA
    outPort(io_base + 6, 0xE0 | (drive << 4) | ((lba >> 24) & 0x0F));
    outPort(io_base + 2, sectors);
    outPort(io_base + 3, (uint8_t)(lba));
    outPort(io_base + 4, (uint8_t)(lba >> 8));
    outPort(io_base + 5, (uint8_t)(lba >> 16));
    outPort(io_base + 7, 0x20); // Read command

    for (uint8_t i = 0; i < sectors; i++) {
        ata_wait_bsy(io_base);
        if (inPort(io_base + 7) & 0x01) { // Check for error
            printf("ATA read error on sector %u.\n",RED_ON_BLACK_WARNING, lba + i);
            return;
        }

        ata_wait_drq(io_base);

        for (uint16_t j = 0; j < ATA_SECTOR_SIZE / 2; j++) {
            ((uint16_t*)buffer)[j] = inPort16(io_base);
        }
        buffer += ATA_SECTOR_SIZE;
    }
}

void ata_write(uint16_t io_base, uint8_t drive, uint32_t lba, uint8_t sectors, const uint8_t* buffer) {
    outPort(io_base + 6, 0xE0 | (drive << 4) | ((lba >> 24) & 0x0F));
    outPort(io_base + 2, sectors);
    outPort(io_base + 3, (uint8_t)(lba));
    outPort(io_base + 4, (uint8_t)(lba >> 8));
    outPort(io_base + 5, (uint8_t)(lba >> 16));
    outPort(io_base + 7, 0x30);

    for (uint8_t i = 0; i < sectors; i++) {
        ata_wait_bsy(io_base);
        ata_wait_drq(io_base);

        for (uint16_t j = 0; j < ATA_SECTOR_SIZE / 2; j++) {
            outPort16(io_base, ((uint16_t*)buffer)[j]);
        }
        buffer += ATA_SECTOR_SIZE;
    }

    ata_wait_bsy(io_base);
    outPort(io_base + 7, 0xE7);
    ata_wait_bsy(io_base);
}

void ata_identify(uint16_t io_base, uint8_t drive) {
    outPort(io_base + 6, drive);
    outPort(io_base + 2, 0);
    outPort(io_base + 3, 0);
    outPort(io_base + 4, 0);
    outPort(io_base + 5, 0);
    outPort(io_base + 7, 0xEC);

    ata_wait_bsy(io_base);

    uint8_t status = inPort(io_base + 7);
    if (status == 0) {
        printf("No ATA device detected.\n", COLOR_BLACK_ON_WHITE);
        return;
    }

    uint16_t buffer[256];
    for (uint16_t i = 0; i < 256; i++) {
        buffer[i] = inPort16(io_base);
    }
}

我尝试过的:

  1. 验证 dir_buffer 数组是否已正确分配。
  2. 检查了ata_identify和ata_read/ata_write函数,它们似乎在其他上下文中工作。
  3. 确认START_DIR地址在预期范围内。

任何帮助或建议将不胜感激!

提前谢谢您。

[url]https://github.com/IlanVinograd/OS_32Bit/blob/feature/target/Code/Kernel/Sources/keyboard.c[/url]

c x86 operating-system filesystems qemu
1个回答
0
投票

我不知道如何回答你关于遇到暂存故障的问题。

© www.soinside.com 2019 - 2024. All rights reserved.