ATA PIO with GRUB

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Andrispowq
Posts: 2
Joined: Fri Jul 17, 2020 7:20 am

ATA PIO with GRUB

Post by Andrispowq »

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:

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
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:

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);
And the code for reading the bytes:

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));
}
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.
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: ATA PIO with GRUB

Post by Octocontrabass »

Andrispowq wrote: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.
Which loop is it hanging in?

Why are you polling the disk instead of using IRQs?
Post Reply