ATA PIO with GRUB
Posted: Thu Feb 25, 2021 7:21 am
So I've gone down the rabbithole of making an OS. And so far, I've used my own bootlaoder to learn stuff, but it started getting difficult with video mode switching, and all of that, so I decided to use GRUB instead. But since the reason for the switch was to use high resolution graphics, I obviously needed to load some fonts. With my old system, what I would do is to use an ATA driver to load some stuff from the disk using it's LBA. And this worked fine, but with GRUB, it does not seem to like it.
This is how I generate my image:
So basically I create a binary, and I literally just copy the files into it. This has worked so far, the offsets were hard-coded, but I could just calculate the start address and load stuff from there. This is the code for loading it:
And the code for reading the bytes:
Of course inb and outb, inw and all of that are just standard wrappers around some inline assembly code, and it has worked every time, so this is not the root of the problem.
So to wrap it up: can I use this how I used to with my own bootloader, or does GRUB do something that makes this approach unusable? I know I can use GRUB modules but I want the code to be usable with legacy BIOS booting, GRUB and UEFI, so I can learn the new and the old stuff as well, and have a reference to use later on if I need to.
EDIT: I didn't specify my problem: the ATA code starts, but it just hangs up in an infinite loop, maybe in the while loops. I experimented with reading from the 1st sector, but it still hangs up.
This is how I generate my image:
Code: Select all
dd if=$(BUILD_DIR)/kernel.elf of=$(BUILD_DIR)/os_image.bin bs=512 seek=0 count=128
dd if=fonts/zap-light16.psf of=$(BUILD_DIR)/os_image.bin bs=512 seek=128 count=12
Code: Select all
uint32_t font_offset = 128;
uint32_t font_size = 12;
uint32_t font_addr = kmalloc(font_size * 512);
read_sectors_ATA_PIO(font_offset, font_offset, font_size);
Code: Select all
void read_sectors_ATA_PIO(uint32_t target_address, uint32_t LBA, uint8_t sector_count)
{
ATA_wait_BSY();
outb(0x1F6,0xE0 | ((LBA >> 24) & 0xF));
outb(0x1F2, sector_count);
outb(0x1F3, (uint8_t) LBA);
outb(0x1F4, (uint8_t)(LBA >> 8));
outb(0x1F5, (uint8_t)(LBA >> 16));
outb(0x1F7, 0x20); //Send the read command
uint16_t* target = (uint16_t*) target_address;
for (int j = 0; j < sector_count;j ++)
{
ATA_wait_BSY();
ATA_wait_DRQ();
for(int i = 0; i < 256; i++)
target[i] = inw(0x1F0);
target += 256;
}
}
Code: Select all
static void ATA_wait_BSY() //Wait for bsy to be 0
{
while(inb(0x1F7) & STATUS_BSY);
}
static void ATA_wait_DRQ() //Wait fot drq to be 1
{
while(!(inb(0x1F7) & STATUS_RDY));
}
So to wrap it up: can I use this how I used to with my own bootloader, or does GRUB do something that makes this approach unusable? I know I can use GRUB modules but I want the code to be usable with legacy BIOS booting, GRUB and UEFI, so I can learn the new and the old stuff as well, and have a reference to use later on if I need to.
EDIT: I didn't specify my problem: the ATA code starts, but it just hangs up in an infinite loop, maybe in the while loops. I experimented with reading from the 1st sector, but it still hangs up.