diff options
| -rw-r--r-- | mubios/arch/irq.S | 20 | ||||
| -rw-r--r-- | mubios/drivers/ata.c | 40 | ||||
| -rw-r--r-- | mubios/include/bios.h | 2 | ||||
| -rw-r--r-- | mubios/services/int13.c | 57 | ||||
| -rw-r--r-- | mubios/services/int16.c | 14 |
5 files changed, 129 insertions, 4 deletions
diff --git a/mubios/arch/irq.S b/mubios/arch/irq.S index 0c192ff..99eb9b3 100644 --- a/mubios/arch/irq.S +++ b/mubios/arch/irq.S @@ -25,6 +25,7 @@ .equ BDA_BASE, 0x0400 .equ BDA_KBD_BUFFER_START, 0x001E .equ BDA_KBD_BUFFER_END, 0x003E + .equ BDA_KBD_BREAK_PREFIX, 0x0497 .equ TIMER_TICKS_PER_DAY_LOW, 0x00B0 .equ TIMER_TICKS_PER_DAY_HIGH, 0x0018 @@ -83,12 +84,25 @@ irq1_entry: in al, 0x60 mov dl, al - test dl, 0x80 - jnz irq1_send_eoi - xor ax, ax mov ds, ax + # Ignore a PS/2 set-2 break prefix and its following release code. + cmp dl, 0xF0 + jne irq1_check_break_prefix + mov byte ptr [BDA_KBD_BREAK_PREFIX], 1 + jmp irq1_send_eoi + +irq1_check_break_prefix: + cmp byte ptr [BDA_KBD_BREAK_PREFIX], 0 + je irq1_check_set1_break + mov byte ptr [BDA_KBD_BREAK_PREFIX], 0 + jmp irq1_send_eoi + +irq1_check_set1_break: + test dl, 0x80 + jnz irq1_send_eoi + mov bx, word ptr [0x041C] mov ax, bx add ax, 2 diff --git a/mubios/drivers/ata.c b/mubios/drivers/ata.c index 928a7d1..a7c6d8d 100644 --- a/mubios/drivers/ata.c +++ b/mubios/drivers/ata.c @@ -36,6 +36,7 @@ #define ATA_STATUS_BSY 0x80u #define ATA_CMD_READ_SECTORS 0x20u +#define ATA_CMD_IDENTIFY 0xECu static u8 ata_wait_not_busy (void) @@ -111,3 +112,42 @@ ata_read_sectors28 (u32 lba, u16 *buffer, u16 count) return 0; } + +u8 +ata_identify (u16 *cylinders, u16 *heads, u16 *sectors_per_track, + u32 *total_sectors_low, u32 *total_sectors_high) +{ + u16 identify_data[256]; + u8 status; + u16 index; + + status = ata_wait_not_busy (); + if ((status & ATA_STATUS_ERR) != 0) + return 1; + + io_out8 (ATA_DRIVE, 0xE0u); + ata_delay_400ns (); + + io_out8 (ATA_SECTOR_COUNT, 0); + io_out8 (ATA_LBA_LOW, 0); + io_out8 (ATA_LBA_MID, 0); + io_out8 (ATA_LBA_HIGH, 0); + io_out8 (ATA_COMMAND, ATA_CMD_IDENTIFY); + + status = ata_wait_not_busy (); + if ((status & ATA_STATUS_ERR) != 0 || (status & ATA_STATUS_DRQ) == 0) + return 1; + + for (index = 0; index < 256; ++index) + identify_data[index] = io_in16 (ATA_DATA); + + *cylinders = identify_data[1]; + *heads = identify_data[3]; + *sectors_per_track = identify_data[6]; + *total_sectors_low + = (u32)identify_data[60] | ((u32)identify_data[61] << 16); + *total_sectors_high + = (u32)identify_data[100] | ((u32)identify_data[101] << 16); + + return 0; +} diff --git a/mubios/include/bios.h b/mubios/include/bios.h index 456d212..7ec2198 100644 --- a/mubios/include/bios.h +++ b/mubios/include/bios.h @@ -51,6 +51,8 @@ void ioapic_init (void); void ivt_init (void); u8 ata_read_sectors28 (u32 lba, u16 *buffer, u16 count); +u8 ata_identify (u16 *cylinders, u16 *heads, u16 *sectors_per_track, + u32 *total_sectors_low, u32 *total_sectors_high); struct bios_regs; diff --git a/mubios/services/int13.c b/mubios/services/int13.c index 2c12261..73d553b 100644 --- a/mubios/services/int13.c +++ b/mubios/services/int13.c @@ -35,6 +35,19 @@ struct edd_packet u32 lba_high; } __attribute__ ((packed)); +struct edd_parameters +{ + u16 size; + u16 flags; + u32 cylinders_low; + u32 cylinders_high; + u32 heads; + u32 sectors_per_track; + u32 total_sectors_low; + u32 total_sectors_high; + u16 bytes_per_sector; +} __attribute__ ((packed)); + static void int13_fail (struct bios_regs *regs) { @@ -51,6 +64,15 @@ get_edd_packet (struct bios_regs *regs) return (struct edd_packet *)address; } +static struct edd_parameters * +get_edd_parameters (struct bios_regs *regs) +{ + u32 address; + + address = ((u32)regs->ds << 4) + (u16)regs->esi; + return (struct edd_parameters *)address; +} + void int13_service (struct bios_regs *regs) { @@ -103,5 +125,40 @@ int13_service (struct bios_regs *regs) return; } + if (function == 0x48u) + { + struct edd_parameters *parameters; + u16 cylinders; + u16 heads; + u16 sectors_per_track; + u32 total_sectors_low; + u32 total_sectors_high; + + parameters = get_edd_parameters (regs); + + if (parameters->size < 0x001Eu + || ata_identify (&cylinders, &heads, §ors_per_track, + &total_sectors_low, &total_sectors_high) + != 0) + { + int13_fail (regs); + return; + } + + parameters->size = 0x001Eu; + parameters->flags = 0; + parameters->cylinders_low = cylinders; + parameters->cylinders_high = 0; + parameters->heads = heads; + parameters->sectors_per_track = sectors_per_track; + parameters->total_sectors_low = total_sectors_low; + parameters->total_sectors_high = total_sectors_high; + parameters->bytes_per_sector = 512; + + regs->eax = 0; + regs->flags &= (u16)~BIOS_CF; + return; + } + int13_fail (regs); } diff --git a/mubios/services/int16.c b/mubios/services/int16.c index 4a04828..5872fb1 100644 --- a/mubios/services/int16.c +++ b/mubios/services/int16.c @@ -27,6 +27,18 @@ #define BDA_KBD_BUFFER_END 0x003Eu static u8 +normalize_scancode (u8 scancode) +{ + switch (scancode) + { + case 0x5Au: + return 0x1Cu; + default: + return scancode; + } +} + +static u8 scancode_to_ascii (u8 scancode) { switch (scancode) @@ -126,7 +138,7 @@ int16_service (struct bios_regs *regs) position = *head; value = buffer[(position - BDA_KBD_BUFFER_START) >> 1]; - scancode = (u8)(value >> 8); + scancode = normalize_scancode ((u8)(value >> 8)); ascii = scancode_to_ascii (scancode); regs->eax = ((u32)scancode << 8) | ascii; |
