All of lore.kernel.org
 help / color / mirror / Atom feed
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, &regs);
+
+  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, &regs);
+      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, &regs);
+  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 --]

             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.