Index: grub/ChangeLog
===================================================================
RCS file: /sources/grub/grub/ChangeLog,v
retrieving revision 1.639
diff -u -r1.639 ChangeLog
--- grub/ChangeLog	24 Jun 2006 14:40:02 -0000	1.639
+++ grub/ChangeLog	15 Aug 2006 19:34:56 -0000
@@ -1,3 +1,11 @@
+2006-08-15  Xuân Baldauf  <xuan--2006.08--grub@software.contributions.by.baldauf.org>
+	* stage2/builtins.c: introduce "write_func" and "write16_func"
+	These functions are good to write to BIOS memory at boot time.
+	This is necessary for some laptops with exchanged TFT displays where
+	the ordinary TFT display detection is broken. Manually writing to
+	specific memory locations allows to correct the broken data structures
+	in BIOS memory.
+
 2006-06-24  Yoshinori K. Okuji  <okuji@enbug.org>
 
 	* docs/grub.texi: Changed the license term to the GNU Free
Index: grub/stage2/builtins.c
===================================================================
RCS file: /sources/grub/grub/stage2/builtins.c,v
retrieving revision 1.152
diff -u -r1.152 builtins.c
--- grub/stage2/builtins.c	21 Mar 2006 20:51:58 -0000	1.152
+++ grub/stage2/builtins.c	15 Aug 2006 19:34:59 -0000
@@ -3058,6 +3058,223 @@
 };
 
 
+static long read_pci_config(long address) {
+  long result;
+  
+  __asm__(
+      "movw   $0x0CF8,%%DX\n\t"
+      "out    %%EAX,%%DX\n\t"
+      "movw   $0x0CFC,%%DX\n\t"
+      "in     %%DX,%%EAX\n\t"
+      : "=a" (result)
+      : "a" (address)
+      : "ebx", "ecx", "edx", "cc");
+  
+  return result;
+}
+
+static void write_pci_config(long address,long value) {
+  
+  __asm__(
+      "movw   $0x0CF8,%%DX\n\t"
+      "out    %%EAX,%%DX\n\t"
+      "movw   $0x0CFC,%%DX\n\t"
+      "movl   %%EBX,%%EAX\n\t"
+      "out    %%EAX,%%DX\n\t"
+      :
+      : "a" (address) , "b" (value)
+      :  "ecx", "edx", "cc");
+}
+
+/**
+	write_func and write16_func (both written by Xuân Baldauf)
+	are experimental.
+*/
+static int
+write_func (char *arg, int flags)
+{
+  int addr;
+  int value;
+  int previousValue;
+  char*	valueArg;
+  long CR0orig = 0;
+  long shadowRAMorig = 0;
+
+
+  valueArg = skip_to (0, arg);
+
+  if (!safe_parse_maxint (&arg, &addr))
+    return 1;
+
+  if (!safe_parse_maxint (&valueArg, &value))
+    return 1;
+
+  previousValue = *((unsigned *) RAW_ADDR (addr));
+
+/*
+  __asm__(
+      "xorl    %%edx, %%edx\n\t"
+      "xorl    %%eax, %%eax\n\t"
+      "movl    $0x268,%%ecx\n\t"
+      "wrmsr\n\t"
+      "movl    $0x269,%%ecx\n\t"
+      "wrmsr\n\t"
+      :
+      :
+      : "eax", "ebx", "ecx", "edx");
+  __asm__(
+      "movl    $0x00000000, %%edx\n\t"
+      "movl    $0x00000006, %%eax\n\t"
+      "movl    $0x2ff,%%ecx\n\t"
+      "wrmsr\n\t"
+      :
+      :
+      : "eax", "ebx", "ecx", "edx");
+  __asm__(
+      "movl    %%CR0, %%eax\n\t"
+      "movl    %%eax, %%ebx\n\t"
+      "andl    $0x8ffefffe, %%eax\n\t"
+      "movl    %%EAX,%%CR0\n\t"
+      : "=b" (CR0orig)
+      :
+      : "eax", "ecx", "edx");
+*/  
+  /**
+  	shadowRAMorig = 0x00000204
+	- readable
+		- E8000h-EBFFFh
+		- E8000h-EBFFFh
+	- writable:
+		- none
+  */
+  shadowRAMorig = read_pci_config(0x80000090);
+  /*
+  __asm__(
+      "movw   $0x0CF8,%%DX\n\t"
+      "movl   $0x80000090,%%EAX\n\t"
+      "out    %%EAX,%%DX\n\t"
+      "movw   $0x0CFC,%%DX\n\t"
+      "in     %%DX,%%EAX\n\t"
+      : "=a" (shadowRAMorig)
+      :
+      : "ebx", "ecx", "edx", "cc");
+  
+  __asm__(
+      "movw   $0x0CF8,%%DX\n\t"
+      "movl   $0x80000090,%%EAX\n\t"
+      "out    %%EAX,%%DX\n\t"
+      "movw   $0x0CFC,%%DX\n\t"
+      "movl   $0xFFFFFFFF,%%EAX\n\t"
+      "out    %%EAX,%%DX\n\t"
+      :
+      :
+      : "eax", "ebx", "ecx", "edx", "cc");
+  */
+  
+  write_pci_config(0x80000090,shadowRAMorig|0x22222220);
+  
+  *((unsigned *) RAW_ADDR (addr)) = value;
+  
+  write_pci_config(0x80000090,shadowRAMorig);
+  
+  /*
+  __asm__(
+      "movw   $0x0CF8,%%DX\n\t"
+      "movl   $0x80000090,%%EAX\n\t"
+      "out    %%EAX,%%DX\n\t"
+      "movw   $0x0CFC,%%DX\n\t"
+      "movl   %%EBX,%%EAX\n\t"
+      "out    %%EAX,%%DX\n\t"
+      :
+      : "b" (shadowRAMorig)
+      : "eax", "ecx", "edx", "cc");
+  */
+  
+  /*
+  __asm__(
+      "movl    %%EAX,%%CR0\n\t"
+      :
+      : "a" (CR0orig)
+      : "ebx", "ecx", "edx", "cc");
+  */
+  
+//grub_printf ("writev7: Address 0x%x: Changed value from 0x%x to 0x%x (CR0orig=0x%x, shadowRAMorig=0x%x)\n", addr, previousValue, *((unsigned *) RAW_ADDR (addr)),CR0orig,shadowRAMorig);
+  grub_printf ("writev8: Address 0x%x: Changed value from 0x%x to 0x%x (shadowRAMorig=0x%x)\n", addr, previousValue, *((unsigned *) RAW_ADDR (addr)),shadowRAMorig);
+  
+  return 0;
+}
+
+static struct builtin builtin_write =
+{
+  "write",
+  write_func,
+  BUILTIN_CMDLINE,
+  "write ADDR VALUE",
+  "Write a 31-bit value to memory at address ADDR."
+};
+
+
+static int
+write16_func (char *arg, int flags)
+{
+  int addr;
+  int tmpValue;
+  short value;
+  short previousValue;
+  char*	valueArg;
+  long shadowRAMorig = 0;
+
+
+  valueArg = skip_to (0, arg);
+
+  if (!safe_parse_maxint (&arg, &addr))
+    return 1;
+
+  if (!safe_parse_maxint (&valueArg, &tmpValue))
+    return 1;
+  
+  value = (tmpValue)&0xFFFFF;
+
+  previousValue = *((unsigned short *) RAW_ADDR (addr));
+
+  shadowRAMorig = read_pci_config(0x80000090);
+  /*
+  	Under some systems, some RAM is not writable.
+	
+  	This makes some BIOS shadow RAM memory locations writeable under
+	some systems. More exactly, this works on Intel 855PM northbridge,
+	as documented in
+	http://download.intel.com/design/chipsets/datashts/25261303.pdf
+	section 3.7.28. This code makes memory writable in following regions:
+	0xF0000..0x100000
+	0xC0000..0xE0000
+	Memory region 0xE0000..0xF0000 is left out for simplicity, but
+	should also be considered for completeness.
+	
+	Note that this code won't make write-protected RAM writable
+	under systems where the way to configure the northbridge is different.
+	And yes, there exist such systems.
+  */
+  write_pci_config(0x80000090,shadowRAMorig|0x22222220);
+  
+  *((unsigned short *) RAW_ADDR (addr)) = value;
+  
+  write_pci_config(0x80000090,shadowRAMorig);
+  grub_printf ("write16: Address 0x%x: Changed value from 0x%x to 0x%x (shadowRAMorig=0x%x)\n", addr, previousValue, *((unsigned short *) RAW_ADDR (addr)),shadowRAMorig);
+  
+  return 0;
+}
+
+static struct builtin builtin_write16 =
+{
+  "write16",
+  write16_func,
+  BUILTIN_CMDLINE,
+  "write16 ADDR VALUE",
+  "Write a 16-bit value to memory at address ADDR."
+};
+
+
 /* reboot */
 static int
 reboot_func (char *arg, int flags)
@@ -4880,5 +5097,7 @@
   &builtin_unhide,
   &builtin_uppermem,
   &builtin_vbeprobe,
+  &builtin_write,
+  &builtin_write16,
   0
 };
