This patch modifies the machine-specific memory.h (currently, just the
i386-specific file), adding a new type grub_machine_farptr and two
functions to convert between such far pointers and normal C pointers.

The code performing the mapping between realmode and pmode addresses is
simple, and thus is repeated in many source files like drivemap, vbe*,
mmap, etc. However, as simple as it is, its ad-hoc application tends to
be quite unwieldy, generating long code that is verges close to the tag
of write-only code.

The i386 farptr type has been implemented as an union between the uint32
that was used until now (.raw_bits) and a structure separating the
uint16 segment and offset parts for easy access and debug printing.

This post has three attachments: the patch to memory.h itself, a patch
to the i386 mmap.c and its helper asm file, to show the impact of this
patch (I've also taken the liberty of adding an offset macro just like
in drivemap, and make the changed code more elegant in my opinion), and
another patch doing the same for drivemap.

NOTE: this patch depends on the PTR_TO_UINT macro added by another patch
still on discussion, [1].

[1] http://lists.gnu.org/archive/html/grub-devel/2009-07/msg00398.html

-- 
-- Lazy, Oblivious, Recurrent Disaster -- Habbit
Index: include/grub/i386/pc/memory.h
===================================================================
--- include/grub/i386/pc/memory.h	(revisión: 2447)
+++ include/grub/i386/pc/memory.h	(copia de trabajo)
@@ -126,6 +126,32 @@
 }
 #endif
 
+typedef union
+{
+  struct
+  {
+    /* Given that i386 is little-endian, this order matches the in-memory
+       format of CPU realmode far pointers.  */
+    grub_uint16_t offset;
+    grub_uint16_t segment;
+  } __attribute__ ((packed));
+  grub_uint32_t raw_bits;
+} grub_machine_farptr;
+
+static inline void *
+grub_machine_real2linear (grub_machine_farptr ptr)
+{
+  return UINT_TO_PTR ((((grub_uint32_t) ptr.segment) << 4) + ptr.offset);
+}
+
+static inline grub_machine_farptr
+grub_machine_linear2real (void *addr)
+{
+  grub_machine_farptr ret = { { PTR_TO_UINT32 (addr) & 0x0000000F,
+			       (PTR_TO_UINT32 (addr) & 0x000FFFF0) >> 4 } };
+  return ret;
+}
+
 #endif
 
 #endif /* ! GRUB_MEMORY_MACHINE_HEADER */
Index: mmap/i386/pc/mmap_helper.S
===================================================================
--- mmap/i386/pc/mmap_helper.S	(revisión: 2447)
+++ mmap/i386/pc/mmap_helper.S	(copia de trabajo)
@@ -48,9 +48,8 @@
 	popf
 	/* ljmp */
 	.byte	0xea
-VARIABLE (grub_machine_mmaphook_int15offset)
+VARIABLE (grub_machine_mmaphook_oldint15)
 	.word	0
-VARIABLE (grub_machine_mmaphook_int15segment)
 	.word	0
 
 e801:
Index: mmap/i386/pc/mmap.c
===================================================================
--- mmap/i386/pc/mmap.c	(revisión: 2447)
+++ mmap/i386/pc/mmap.c	(copia de trabajo)
@@ -25,17 +25,20 @@
 
 #define min(a,b) (((a) < (b)) ? (a) : (b))
 
+#define OFFSET_IN_ASM(addr) ( PTR_TO_UINT (addr) \
+                          - PTR_TO_UINT (&grub_machine_mmaphook_start) )
+
 static void *hooktarget = 0;
+/* Not a null pointer, the real mode IVT is actually at address 0:0 */
+static grub_machine_farptr *grub_machine_ivt = 0;
 
-extern grub_uint8_t grub_machine_mmaphook_start;
-extern grub_uint8_t grub_machine_mmaphook_end;
-extern grub_uint8_t grub_machine_mmaphook_int12;
-extern grub_uint8_t grub_machine_mmaphook_int15;
+extern const void grub_machine_mmaphook_start;
+extern const void grub_machine_mmaphook_end;
+extern const void grub_machine_mmaphook_int12;
+extern const void grub_machine_mmaphook_int15;
 
-static grub_uint16_t grub_machine_mmaphook_int12offset = 0;
-static grub_uint16_t grub_machine_mmaphook_int12segment = 0;
-extern grub_uint16_t grub_machine_mmaphook_int15offset;
-extern grub_uint16_t grub_machine_mmaphook_int15segment;
+static grub_machine_farptr grub_machine_mmaphook_oldint12;
+extern grub_machine_farptr grub_machine_mmaphook_oldint15;
 
 extern grub_uint16_t grub_machine_mmaphook_mmap_num;
 extern grub_uint16_t grub_machine_mmaphook_kblow;
@@ -73,9 +76,8 @@
 
   grub_dprintf ("mmap", "installing preboot handlers\n");
 
-  hookmmapcur = hookmmap = (struct grub_e820_mmap_entry *)
-    ((grub_uint8_t *) hooktarget + (&grub_machine_mmaphook_end
-				    - &grub_machine_mmaphook_start));
+  hookmmapcur = hookmmap = UINT_TO_PTR (PTR_TO_UINT (hooktarget)
+                                   + OFFSET_IN_ASM(&grub_machine_mmaphook_end));
 
   grub_mmap_iterate (fill_hook);
   grub_machine_mmaphook_mmap_num = hookmmapcur - hookmmap;
@@ -90,24 +92,23 @@
   *((grub_uint16_t *) 0x413) = grub_mmap_get_lower () >> 10;
 
   /* Save old interrupt handlers. */
-  grub_machine_mmaphook_int12offset = *((grub_uint16_t *) 0x48);
-  grub_machine_mmaphook_int12segment = *((grub_uint16_t *) 0x4a);
-  grub_machine_mmaphook_int15offset = *((grub_uint16_t *) 0x54);
-  grub_machine_mmaphook_int15segment = *((grub_uint16_t *) 0x56);
+  grub_machine_mmaphook_oldint12 = grub_machine_ivt[0x12];
+  grub_machine_mmaphook_oldint15 = grub_machine_ivt[0x15];
 
   grub_dprintf ("mmap", "hooktarget = %p\n", hooktarget);
 
   /* Install the interrupt handlers. */
   grub_memcpy (hooktarget, &grub_machine_mmaphook_start,
-	       &grub_machine_mmaphook_end - &grub_machine_mmaphook_start);
+	       OFFSET_IN_ASM(&grub_machine_mmaphook_end));
 
-  *((grub_uint16_t *) 0x4a) = PTR_TO_UINT32 (hooktarget) >> 4;
-  *((grub_uint16_t *) 0x56) = PTR_TO_UINT32 (hooktarget) >> 4;
-  *((grub_uint16_t *) 0x48) = &grub_machine_mmaphook_int12
-    - &grub_machine_mmaphook_start;
-  *((grub_uint16_t *) 0x54) = &grub_machine_mmaphook_int15
-    - &grub_machine_mmaphook_start;
+  void* newint12 = UINT_TO_PTR (PTR_TO_UINT (hooktarget)
+                                + OFFSET_IN_ASM(&grub_machine_mmaphook_int12));
+  void* newint15 = UINT_TO_PTR (PTR_TO_UINT (hooktarget)
+                                + OFFSET_IN_ASM(&grub_machine_mmaphook_int15));
 
+  grub_machine_ivt[0x12] = grub_machine_linear2real(newint12);
+  grub_machine_ivt[0x15] = grub_machine_linear2real(newint15);
+
   return GRUB_ERR_NONE;
 }
 
@@ -115,10 +116,8 @@
 preboot_rest (void)
 {
   /* Restore old interrupt handlers. */
-  *((grub_uint16_t *) 0x48) = grub_machine_mmaphook_int12offset;
-  *((grub_uint16_t *) 0x4a) = grub_machine_mmaphook_int12segment;
-  *((grub_uint16_t *) 0x54) = grub_machine_mmaphook_int15offset;
-  *((grub_uint16_t *) 0x56) = grub_machine_mmaphook_int15segment;
+  grub_machine_ivt[0x12] = grub_machine_mmaphook_oldint12;
+  grub_machine_ivt[0x15] = grub_machine_mmaphook_oldint15;
 
   return GRUB_ERR_NONE;
 }
@@ -161,12 +160,11 @@
       hooktarget = 0;
     }
 
-  hooksize = &grub_machine_mmaphook_end - &grub_machine_mmaphook_start
+  hooksize = OFFSET_IN_ASM(&grub_machine_mmaphook_end)
     + regcount * sizeof (struct grub_e820_mmap_entry);
   /* Allocate an integer number of KiB. */
   hooksize = ((hooksize - 1) | 0x3ff) + 1;
-  slots_available = (hooksize - (&grub_machine_mmaphook_end
-				 - &grub_machine_mmaphook_start))
+  slots_available = (hooksize - OFFSET_IN_ASM(&grub_machine_mmaphook_end))
     / sizeof (struct grub_e820_mmap_entry);
 
   reentry = 1;
Index: commands/i386/pc/drivemap.c
===================================================================
--- commands/i386/pc/drivemap.c	(revisión: 2447)
+++ commands/i386/pc/drivemap.c	(copia de trabajo)
@@ -29,7 +29,7 @@
 
 
 /* Real mode IVT slot (seg:off far pointer) for interrupt 0x13.  */
-static grub_uint32_t *const int13slot = UINT_TO_PTR (4 * 0x13);
+static grub_machine_farptr *const int13slot = UINT_TO_PTR (4 * 0x13);
 
 /* Remember to update enum opt_idxs accordingly.  */
 static const struct grub_arg_option options[] = {
@@ -48,7 +48,7 @@
 };
 
 /* Realmode far ptr (2 * 16b) to the previous INT13h handler.  */
-extern grub_uint32_t grub_drivemap_oldhandler;
+extern grub_machine_farptr grub_drivemap_oldhandler;
 
 /* The type "void" is used for imported assembly labels, takes no storage and
    serves just to take the address with &label.  */
@@ -295,8 +295,7 @@
   /* Save the pointer to the old handler.  */
   grub_drivemap_oldhandler = *int13slot;
   grub_dprintf ("drivemap", "Original int13 handler: %04x:%04x\n",
-		(grub_drivemap_oldhandler >> 16) & 0x0ffff,
-		grub_drivemap_oldhandler & 0x0ffff);
+		grub_drivemap_oldhandler.segment, grub_drivemap_oldhandler.offset);
 
   /* Find a rmode-segment-aligned zone in conventional memory big
      enough to hold the handler and its data.  */
@@ -335,9 +334,9 @@
   grub_dprintf ("drivemap", "\t#%d: 0x00 <- 0x00 (end)\n", i);
 
   /* Install our function as the int13h handler in the IVT.  */
-  *int13slot = ((grub_uint32_t) handler_base) << 12;	/* Segment address.  */
+  *int13slot = grub_machine_linear2real(handler_base);
   grub_dprintf ("drivemap", "New int13 handler: %04x:%04x\n",
-		(*int13slot >> 16) & 0x0ffff, *int13slot & 0x0ffff);
+		int13slot->segment, int13slot->offset);
 
   return GRUB_ERR_NONE;
 }
@@ -345,14 +344,14 @@
 static grub_err_t
 uninstall_int13_handler (void)
 {
-  if (! grub_drivemap_oldhandler)
+  if (! grub_drivemap_oldhandler.raw_bits)
     return GRUB_ERR_NONE;
 
   *int13slot = grub_drivemap_oldhandler;
   grub_mmap_free_and_unregister (drivemap_mmap);
-  grub_drivemap_oldhandler = 0;
+  grub_drivemap_oldhandler.raw_bits = 0;
   grub_dprintf ("drivemap", "Restored int13 handler: %04x:%04x\n",
-		(*int13slot >> 16) & 0x0ffff, *int13slot & 0x0ffff);
+		int13slot->segment, int13slot->offset);
 
   return GRUB_ERR_NONE;
 }
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to