RE: [patch] Fix GDT re-load on ACPI resume

Li, Shaohua
2004-11-16T05:38:28Z

[-- Attachment #1: Type: text/plain, Size: 1153 bytes --]

>The ACPI resume code currently uses a real-mode 16-bit lgdt instruction
to
>reload the GDT. This only restores the lower 24 bits of the GDT base
>address. In recent kernels, the GDT seems to have moved out of the
lower
>16 megs, thereby causing the ACPI resume to fail -- an invalid GDT was
>being loaded.
>
>This simple patch adds the 0x66 prefix to lgdt, which forces it to load
>all 32 bits of the GDT base address, thereby removing any restrictions
on
>where the GDT can be placed in memory. This makes ACPI resume work for
me
>on a Thinkpad T40 laptop.
>
>-- kolya
>
>--- linux-2.6.9/arch/i386/kernel/acpi/wakeup.S 2004/11/15 09:00:34
1.1
>+++ linux-2.6.9/arch/i386/kernel/acpi/wakeup.S 2004/11/15 20:33:27
>@@ -67,6 +67,8 @@
> movw $0x0e00 + 'i', %fs:(0x12)
>
> # need a gdt
>+ .byte 0x66 # force 32-bit operands in case
>+ # the GDT is past 16 megabytes
> lgdt real_save_gdt - wakeup_code
>
> movl real_save_cr0 - wakeup_code, %eax
There is a patch from hiroit@mcn.ne.jp to fix the GDT issue. You can try
it.
Please cc 'acpi-devel@lists.sourceforge.net' for suspend/resume issue.

Thanks,
Shaohua

[-- Attachment #2: wakeup_gdt2.patch --]
[-- Type: application/octet-stream, Size: 2214 bytes --]

diff -Nru a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c
--- a/arch/i386/kernel/acpi/sleep.c 2004-10-15 11:29:15.000000000 +0900
+++ b/arch/i386/kernel/acpi/sleep.c 2004-10-19 00:59:32.000000000 +0900
@@ -17,7 +17,7 @@

extern void zap_low_mappings(void);

-extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
+extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long,unsigned long));

static void init_low_mapping(pgd_t *pgd, int pgd_limit)
{
@@ -41,7 +41,8 @@
return 1;
init_low_mapping(swapper_pg_dir, USER_PTRS_PER_PGD);
memcpy((void *) acpi_wakeup_address, &wakeup_start, &wakeup_end - &wakeup_start);
- acpi_copy_wakeup_routine(acpi_wakeup_address);
+ acpi_copy_wakeup_routine(acpi_wakeup_address,
+ virt_to_phys((void *)acpi_wakeup_address));

return 0;
}
diff -Nru a/arch/i386/kernel/acpi/wakeup.S b/arch/i386/kernel/acpi/wakeup.S
--- a/arch/i386/kernel/acpi/wakeup.S 2004-08-14 14:36:31.000000000 +0900
+++ b/arch/i386/kernel/acpi/wakeup.S 2004-10-19 05:24:42.000000000 +0900
@@ -89,6 +89,7 @@
real_magic: .long 0
video_mode: .long 0
video_flags: .long 0
+real_gdt_table: .fill GDT_ENTRIES, 8, 0

bogus_real_magic:
movw $0x0e00 + 'B', %fs:(0x12)
@@ -213,6 +214,7 @@
#
# Parameters:
# %eax: place to copy wakeup routine to
+# %edx: the second argument (physical address)
#
# Returned address is location of code in low memory (past data and stack)
#
@@ -223,6 +225,9 @@
sldt saved_ldt
str saved_tss

+ # save wakeup_start physical address in ecx
+ movl %edx, %ecx
+
movl %cr3, %edx
movl %edx, real_save_cr3 - wakeup_start (%eax)
movl %cr4, %edx
@@ -231,6 +236,16 @@
movl %edx, real_save_cr0 - wakeup_start (%eax)
sgdt real_save_gdt - wakeup_start (%eax)

+ # gdt body must be addressable from real mode by
+ # copying it to the lower mem
+ lea real_gdt_table - wakeup_start (%ecx), %ecx
+ movl %ecx, real_save_gdt + 2 - wakeup_start (%eax)
+ xor %ecx, %ecx
+ movw saved_gdt, %cx
+ movl saved_gdt + 2, %esi
+ lea real_gdt_table - wakeup_start (%eax), %edi
+ rep movsb
+
movl saved_videomode, %edx
movl %edx, video_mode - wakeup_start (%eax)
movl acpi_video_flags, %edx