From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phcoder@gmail.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: [PATCH] Proof of concept interrupt wrapping
Date: Thu, 31 Dec 2009 13:28:30 +0100 [thread overview]
Message-ID: <4B3C98EE.8020003@gmail.com> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 1558 bytes --]
Hello. We were discussing with Robert how to move BIOS interrupt
routines out of kernel. There are following possibilities:
1) Have a .lowmem section in every concerned module which will always be
placed in low memory. Currently in experimental.
Advantages:
a) moving functions to modules is straightforward
b) functions grow neither in size nor in complexity
Disadvantages:
c) needs lowmem allocators in core
2) Make every function needing bios interrupts setup its own trampoline.
Due to complexity of trampolines it's not a real option
3) Have an universal routine grub_interrupt (int intno, struct
grub_cpu_interrupt_regs *regs) which will be used by C routine to do the
interrupt calls. This would move the complexity from asm to C.
Advantages:
a) simplicity in core
b) complexity moved to a more readable language
c) we can also rename grub_interrupt to grub_interrupt_real and make
grub_interrupt dprintf registers before and after the call. This would
make debugging BIOS quirks easier.
Disadvantages:
a) Moving functions needs effort
b) C functions are probably bigger but it may be offset by possibility
of inlining functions
c) repeadetly changing from/to real mode is an overhead when executing
multiple interrupts in series. Fortunately this condition is rare in our
codebase and is only on non performance-critical parts like halting.
d) Some functions aren't covered by this. At least grub_pxe_call is in
this case. But we can use method 2 for them
--
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: intwrap.diff --]
[-- Type: text/x-diff; name="intwrap.diff", Size: 8535 bytes --]
=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk 2009-12-25 22:06:52 +0000
+++ conf/i386-pc.rmk 2009-12-31 12:07:51 +0000
@@ -64,7 +64,7 @@
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)
=== modified file 'disk/i386/pc/biosdisk.c'
--- disk/i386/pc/biosdisk.c 2009-12-10 18:15:20 +0000
+++ disk/i386/pc/biosdisk.c 2009-12-31 12:07:51 +0000
@@ -19,6 +19,7 @@
#include <grub/machine/biosdisk.h>
#include <grub/machine/memory.h>
#include <grub/machine/kernel.h>
+#include <grub/machine/int.h>
#include <grub/disk.h>
#include <grub/dl.h>
#include <grub/mm.h>
@@ -28,6 +29,59 @@
#include <grub/term.h>
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)
=== modified file 'include/grub/i386/pc/biosdisk.h'
--- include/grub/i386/pc/biosdisk.h 2009-06-10 21:04:23 +0000
+++ include/grub/i386/pc/biosdisk.h 2009-12-31 12:07:51 +0000
@@ -106,7 +106,6 @@
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 @@
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);
=== added file 'include/grub/i386/pc/int.h'
--- include/grub/i386/pc/int.h 1970-01-01 00:00:00 +0000
+++ include/grub/i386/pc/int.h 2009-12-31 12:07:51 +0000
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_INTERRUPT_MACHINE_HEADER
+#define GRUB_INTERRUPT_MACHINE_HEADER 1
+
+#include <grub/symbol.h>
+
+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
=== modified file 'kern/i386/pc/startup.S'
--- kern/i386/pc/startup.S 2009-12-25 22:01:32 +0000
+++ kern/i386/pc/startup.S 2009-12-31 12:07:51 +0000
@@ -567,44 +567,6 @@
#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)
*
@@ -862,43 +824,6 @@
/*
- * 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
* memory, i == 1 for extended memory
@@ -2142,3 +2067,74 @@
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
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]
next reply other threads:[~2009-12-31 12:28 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-12-31 12:28 Vladimir 'φ-coder/phcoder' Serbinenko [this message]
2010-01-01 12:47 ` [PATCH] Proof of concept interrupt wrapping Robert Millan
2010-01-17 20:19 ` Vladimir 'φ-coder/phcoder' Serbinenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4B3C98EE.8020003@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.