i am trying to read one sector from my (already detected by "identify") drive, but i am not getting any interrupts.
what i do is the following:
Code: Select all
static void read_sector(uint32_t number, channel_t *channel, err_t *error)
{
#define PORT_DATA 0x0
#define PORT_ERROR 0x1
#define PORT_SECTORCOUNT 0x2
#define PORT_LBA_LOW 0x3
#define PORT_LBA_MID 0x4
#define PORT_LBA_HIGH 0x5
#define PORT_DRIVESELECT 0x6
#define PORT_HEADSELECT PORT_DRIVESELECT
#define PORT_COMMAND 0x7
#define PORT_STATUS PORT_COMMAND
#define COMMAND_IDENTIFY 0xec
#define COMMAND_READSECTORS 0x20
#define BIT_ERR 0x1
#define BIT_DRQ 0x8
#define BIT_BUSY 0x80
#define PORTBASE_PRIMARY 0x1f0
#define PORTBASE_SECONDARY 0x170
...
static void select_drive(boolean_t master, boolean_t primary, err_t *error)
{
uint32_t value = 0;
uint32_t port_base = 0;
if (master) {
value = 0xa0;
} else {
value = 0xb0;
}
if (primary) {
port_base = PORTBASE_PRIMARY;
} else {
port_base = PORTBASE_SECONDARY;
}
terror(call_syscall_outb(port_base | PORT_DRIVESELECT, value, error))
finish:
return;
}
...
static void read_sector(uint32_t number, channel_t *channel, err_t *error)
{
uint32_t i = 0;
uint32_t bytes = 0;
uint32_t port_base = 0;
boolean_t master = ((channel->bus_info & BUSINFO_MASTER) != 0);
boolean_t primary = ((channel->bus_info & BUSINFO_PRIMARY) != 0);
uint8_t value = 0;
uint32_t irq_expected = 0;
if (number >= channel->lba_sectors) {
//TODO: set error...
}
//TODO: check if drive is present (and maybe type)
terror(select_drive(master, primary, error))
if (master) {
value = 0xe0;
} else {
value = 0xf0;
}
if (primary) {
port_base = PORTBASE_PRIMARY;
} else {
port_base = PORTBASE_SECONDARY;
}
terror(call_syscall_outb(port_base | PORT_DRIVESELECT, (value | (number >> 24)), error))
//can be left out
//terror(call_syscall_outb(port_base | PORT_ERROR, 0))
//read one sector
terror(call_syscall_outb(port_base | PORT_SECTORCOUNT, 1, error))
terror(call_syscall_outb(port_base | PORT_LBA_LOW, (number & 0xff), error))
terror(call_syscall_outb(port_base | PORT_LBA_MID, ((number >> 8) & 0xff), error))
terror(call_syscall_outb(port_base | PORT_LBA_HIGH, ((number >> 16) & 0xff), error))
terror(call_syscall_outb(port_base | PORT_COMMAND, COMMAND_READSECTORS, error))
irq_expected = primary ? 14 : 15;
for(;;) {
terror(bytes = call_syscall_receive(ANYPROC, NULL, 0, error))
if ((*error) == irq_expected) {
break;
}
}
for (i = 0; i < 256; i++) {
terror(buffer[i] = call_syscall_inw(port_base | PORT_DATA, error))
}
//wait 400 ns
finish:
return;
}
Code: Select all
#define hasFailed(x) (x < OK)
#define terror(x) \
x; \
if (hasFailed((*error))) { \
goto finish; \
}
IRQs and ports have to be claimed by user space programs beforehand (which I also do).
So just to clarify that I don't think anything with my port-IRQ handling mechanism is going wrong per se (I use it successfully in my tty driver).
Also, I put some debugging code in my kernel just to make sure there really is no interrupt from the hard drive.
What I found out is that my code never returns from call_syscall_receive() (no interrupt occurs after sending the sector read command). The system itself doesn't hang. My tty continues to work and react to user input. Could you have a look particularly at how I send the sector read command to the drive and see if I'm missing something here?
Thanks