I've set up GDT, IDT, and PIC, which work fine
Now I want to have storage in my OS, so I used
Code: Select all
qemu-img create -f raw storage.img 4G
Code: Select all
qemu-system-i386 -cdrom os.iso -drive file=storage.img,format=raw -boot d
I also followed this page
https://wiki.osdev.org/ATA_read/write_sectors#See_also
to write the read and write functions in c
However, the read function above doesn't read the disk properly
I used a binary editor to write the first 512 bytes(a sector) of my storage.img to 0x01
The output of the read function doesn't match the contents in the disk
Expected:
11111...
Outputed:
00001111...
Sometimes the 1s at the beginning would become 0es
The write function doesn't work in 99% of the time, as the wait_for_disk() function will reach the timeout, but once it doesn't reach the timeout it will work properly
Thanks for everyone who can help
Code: Select all
#ifndef FILE_SYSTEM_H
#define FILE_SYSTEM_H
#include <stdint.h>
#include "../../libraries/util/io.h"
#include "../../libraries/terminal/terminalio.h"
// ATA Ports
#define ATA_DATA_PORT 0x1F0
#define ATA_ERROR_PORT 0x1F1
#define ATA_SECTOR_COUNT_PORT 0x1F2
#define ATA_LBA_LOW_PORT 0x1F3
#define ATA_LBA_MID_PORT 0x1F4
#define ATA_LBA_HIGH_PORT 0x1F5
#define ATA_DRIVE_PORT 0x1F6
#define ATA_COMMAND_PORT 0x1F7
#define ATA_STATUS_PORT 0x1F7
// ATA Commands
#define ATA_CMD_READ_SECTORS 0x24
#define ATA_CMD_WRITE_SECTORS 0x34
// Buffer to hold the read sector data
// this will store the read and written info
static uint8_t data_buffer[512] = {0};
int wait_for_disk()
{
uint32_t time = 0;
// Poll for completion (you might want to implement a timeout mechanism)
while ((inw(ATA_STATUS_PORT) & 0x80) != 0x80)
{
++time;
if(time > 1000000)//timeout
{
printf("failed\n");
return 0;
}
}
return 1;
}
void read_sector(uint32_t sector_number)
{
outb(ATA_ERROR_PORT, 0);
// Select drive (Assuming drive 0, replace with appropriate value if needed)
// set 111 to enter LBA mode
outb(ATA_DRIVE_PORT, 0xE0 | ((sector_number >> 24) & 0x0F));
// Set sector count to 1
outb(ATA_SECTOR_COUNT_PORT, 1);
// Set LBA address
outb(ATA_LBA_LOW_PORT, sector_number & 0xFF);
outb(ATA_LBA_MID_PORT, (sector_number >> 8) & 0xFF);
outb(ATA_LBA_HIGH_PORT, (sector_number >> 16) & 0xFF);
// Issue the read command
outb(ATA_COMMAND_PORT, ATA_CMD_READ_SECTORS);
if(!wait_for_disk())
{
return;
}
// Read data from the data port
for(int i = 0; i < 512; i += 2)
{
uint16_t temp = inw(ATA_DATA_PORT);
data_buffer[i] = (uint8_t)temp;
data_buffer[i + 1] = (uint8_t)(temp >> 8);
}
}
void write_sector(uint32_t sector_number)
{
// Select drive (Assuming drive 0, replace with appropriate value if needed)
// set 111 to enter LBA mode
outb(ATA_DRIVE_PORT, 0xE0 | ((sector_number >> 24) & 0x0F));
// Set sector count to 1
outb(ATA_SECTOR_COUNT_PORT, 1);
// Set LBA address
outb(ATA_LBA_LOW_PORT, sector_number & 0xFF);
outb(ATA_LBA_MID_PORT, (sector_number >> 8) & 0xFF);
outb(ATA_LBA_HIGH_PORT, (sector_number >> 16) & 0xFF);
// Issue the read command
outb(ATA_COMMAND_PORT, ATA_CMD_WRITE_SECTORS);
if(!wait_for_disk())
{
return;
}
printf("?");
//write the data from the data buffer
for(int i = 0; i < 512; i += 2)
{
outw(ATA_DATA_PORT, (data_buffer[i] << 8) | (data_buffer[i + 1]));
}
}
#endif
Code: Select all
void outb(uint16_t port, uint8_t value) //implemented in asm
{
__asm__ volatile(
"out %0, %1"
:
: "a" (value), "Nd" (port)
);
}
uint8_t inb(uint8_t port) //implemented in asm
{
uint8_t result;
__asm__ volatile(
"in %w1, %0"
: "=a" (result)
: "Nd" (port)
);
return result;
}
uint16_t inw(uint16_t port) //implemented in asm
{
uint16_t result;
__asm__ volatile(
"in %w1, %0"
: "=a" (result)
: "Nd" (port)
);
return result;
}
void outw(uint16_t port, uint16_t value) //implemented in asm
{
__asm__ volatile(
"out %0, %1"
:
: "a" (value), "Nd" (port)
);
}
void io_wait()
{
outb(0x80, 0);
}