From eb3f57d3c4d74327badc321c21a9c6eb81d396a6 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 31 Dec 2009 13:07:51 +0100 Subject: [PATCH] proof of concept interrupt wrapping --- conf/i386-pc.rmk | 2 +- disk/i386/pc/biosdisk.c | 54 ++++++++++++ include/grub/i386/pc/biosdisk.h | 2 - include/grub/i386/pc/int.h | 50 +++++++++++ kern/i386/pc/startup.S | 146 ++++++++++++++++---------------- 5 files changed, 176 insertions(+), 78 deletions(-) create mode 100644 include/grub/i386/pc/int.h diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 4ae753776..45020819a 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -64,7 +64,7 @@ kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \ machine/memory.h machine/loader.h machine/vga.h machine/vbe.h \ - machine/kernel.h machine/pxe.h i386/pit.h list.h handler.h command.h i18n.h + machine/kernel.h machine/pxe.h i386/pit.h list.h handler.h command.h i18n.h machine/int.h kernel_img_CFLAGS = $(COMMON_CFLAGS) $(TARGET_IMG_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_KERNEL_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c index af184b1ba..0f75dba5f 100644 --- a/disk/i386/pc/biosdisk.c +++ b/disk/i386/pc/biosdisk.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,59 @@ #include static int cd_drive = 0; +static int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap); + +static int grub_biosdisk_get_num_floppies (void) +{ + struct grub_cpu_int_registers regs; + int drive; + + /* reset the disk system first */ + regs.ax = 0; + regs.dx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + grub_cpu_interrupt (0x13, ®s); + + for (drive = 0; drive < 2; drive++) + { + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT | GRUB_CPU_INT_FLAGS_CARRY; + regs.dx = drive; + + /* call GET DISK TYPE */ + regs.ax = 0x1500; + grub_cpu_interrupt (0x13, ®s); + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + break; + + /* check if this drive exists */ + if (!(regs.ax & 0x300)) + break; + } + + return drive; +} + +/* + * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP + * is passed for disk address packet. If an error occurs, return + * non-zero, otherwise zero. + */ + +static int +grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap) +{ + struct grub_cpu_int_registers regs; + regs.ax = ah << 8; + /* compute the address of disk_address_packet */ + regs.ds = (((grub_addr_t) dap) & 0xffff0000) >> 4; + regs.si = (((grub_addr_t) dap) & 0xffff); + regs.dx = drive; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + grub_cpu_interrupt (0x13, ®s); + return regs.ax >> 8; +} static int grub_biosdisk_get_drive (const char *name) diff --git a/include/grub/i386/pc/biosdisk.h b/include/grub/i386/pc/biosdisk.h index b87e0e433..83d833cad 100644 --- a/include/grub/i386/pc/biosdisk.h +++ b/include/grub/i386/pc/biosdisk.h @@ -106,7 +106,6 @@ struct grub_biosdisk_dap grub_uint64_t block; } __attribute__ ((packed)); -int EXPORT_FUNC(grub_biosdisk_rw_int13_extensions) (int ah, int drive, void *dap); int EXPORT_FUNC(grub_biosdisk_rw_standard) (int ah, int drive, int coff, int hoff, int soff, int nsec, int segment); int EXPORT_FUNC(grub_biosdisk_check_int13_extensions) (int drive); @@ -118,7 +117,6 @@ int EXPORT_FUNC(grub_biosdisk_get_diskinfo_standard) (int drive, unsigned long *cylinders, unsigned long *heads, unsigned long *sectors); -int EXPORT_FUNC(grub_biosdisk_get_num_floppies) (void); void grub_biosdisk_init (void); void grub_biosdisk_fini (void); diff --git a/include/grub/i386/pc/int.h b/include/grub/i386/pc/int.h new file mode 100644 index 000000000..b8cbe3260 --- /dev/null +++ b/include/grub/i386/pc/int.h @@ -0,0 +1,50 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_INTERRUPT_MACHINE_HEADER +#define GRUB_INTERRUPT_MACHINE_HEADER 1 + +#include + +struct grub_cpu_int_registers +{ + grub_uint16_t bx; + grub_uint16_t es; + grub_uint16_t cx; + grub_uint16_t ax; + grub_uint16_t dx; + grub_uint16_t ds; + grub_uint16_t di; + grub_uint16_t flags; + grub_uint16_t si; +}; + +#define GRUB_CPU_INT_FLAGS_CARRY 0x1 +#define GRUB_CPU_INT_FLAGS_PARITY 0x4 +#define GRUB_CPU_INT_FLAGS_ADJUST 0x10 +#define GRUB_CPU_INT_FLAGS_ZERO 0x40 +#define GRUB_CPU_INT_FLAGS_SIGN 0x80 +#define GRUB_CPU_INT_FLAGS_TRAP 0x100 +#define GRUB_CPU_INT_FLAGS_INTERRUPT 0x200 +#define GRUB_CPU_INT_FLAGS_DIRECTION 0x400 +#define GRUB_CPU_INT_FLAGS_OVERFLOW 0x800 +#define GRUB_CPU_INT_FLAGS_DEFAULT GRUB_CPU_INT_FLAGS_INTERRUPT + +void EXPORT_FUNC (grub_cpu_interrupt) (grub_uint8_t intno, struct grub_cpu_int_registers *regs); + +#endif diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index 06e26dea3..815686502 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -566,44 +566,6 @@ FUNCTION(grub_chainloader_real_boot) #include "../loader.S" -/* - * int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap) - * - * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP - * is passed for disk address packet. If an error occurs, return - * non-zero, otherwise zero. - */ - -FUNCTION(grub_biosdisk_rw_int13_extensions) - pushl %ebp - pushl %esi - - /* compute the address of disk_address_packet */ - movw %cx, %si - xorw %cx, %cx - shrl $4, %ecx /* save the segment to cx */ - - /* ah */ - movb %al, %dh - /* enter real mode */ - call prot_to_real - - .code16 - movb %dh, %ah - movw %cx, %ds - int $0x13 /* do the operation */ - movb %ah, %dl /* save return value */ - /* back to protected mode */ - DATA32 call real_to_prot - .code32 - - movb %dl, %al /* return value in %eax */ - - popl %esi - popl %ebp - - ret - /* * int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff, * int soff, int nsec, int segment) @@ -861,43 +823,6 @@ noclean2: ret $4 -/* - * int grub_biosdisk_get_num_floppies (void) - */ -FUNCTION(grub_biosdisk_get_num_floppies) - pushl %ebp - - xorl %edx, %edx - call prot_to_real - - .code16 - /* reset the disk system first */ - int $0x13 -1: - stc - - /* call GET DISK TYPE */ - movb $0x15, %ah - int $0x13 - - jc 2f - - /* check if this drive exists */ - testb $0x3, %ah - jz 2f - - incb %dl - cmpb $2, %dl - jne 1b -2: - DATA32 call real_to_prot - .code32 - - movl %edx, %eax - popl %ebp - ret - - /* * * grub_get_memsize(i) : return the memory size in KB. i == 0 for conventional @@ -2142,3 +2067,74 @@ FUNCTION(grub_pxe_call) popl %esi popl %ebp ret + +FUNCTION(grub_cpu_interrupt) + pushl %ebp + pushl %esi + pushl %edi + pushl %ebx + pushl %edx + movb %al, intno + movl %edx, %esi + + movl 0(%esi), %ebx + movl 4(%esi), %ecx + movl 8(%esi), %edx + movl 12(%esi), %edi + movw 16(%esi), %si + + call prot_to_real + .code16 + movl %edi, %eax + shrl $16, %eax + push %ax + + movl %ebx, %eax + shrl $16, %eax + movw %ax, %es + + movl %edx, %eax + shrl $16, %eax + movw %ax, %ds + + movl %ecx, %eax + shrl $16, %eax + + popf + .byte 0xcd +intno: + .byte 0 + + pushf + andl $0xffff, %ebx + andl $0xffff, %ecx + andl $0xffff, %edx + andl $0xffff, %edi + + shll $16, %eax + orl %eax, %ecx + + movw %ds, %ax + shll $16, %eax + orl %eax, %edx + + pop %ax + shll $16, %eax + orl %eax, %edi + + DATA32 call real_to_prot + .code32 + pushl %esi + movl 4(%esp), %esi + movl %ebx, 0(%esi) + movl %ecx, 4(%esi) + movl %edx, 8(%esi) + movl %edi, 12(%esi) + popl %eax + movw %ax, 16(%esi) + popl %eax + popl %ebx + popl %edi + popl %esi + popl %ebp + ret