* [PATCH] OLPC: Add XO-1 suspend/resume support @ 2010-10-19 22:01 Daniel Drake 2010-10-19 22:06 ` Randy Dunlap 2010-10-19 22:11 ` H. Peter Anvin 0 siblings, 2 replies; 7+ messages in thread From: Daniel Drake @ 2010-10-19 22:01 UTC (permalink / raw) To: tglx, mingo, hpa, x86; +Cc: dilinger, linux-kernel Add code needed for basic suspend/resume of the XO-1 laptop. swsusp_pg_dir needs to be exposed as it is used by the assembly code run in the wakeup path. Signed-off-by: Daniel Drake <dsd@laptop.org> --- arch/x86/include/asm/olpc.h | 5 +- arch/x86/kernel/Makefile | 2 +- arch/x86/kernel/olpc-xo1-wakeup.S | 132 +++++++++++++++++++++++++++++++++++++ arch/x86/kernel/olpc-xo1.c | 79 ++++++++++++++++++++++ arch/x86/mm/init_32.c | 6 +- 5 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 arch/x86/kernel/olpc-xo1-wakeup.S diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h index 101229b..54dfe92 100644 --- a/arch/x86/include/asm/olpc.h +++ b/arch/x86/include/asm/olpc.h @@ -88,7 +88,10 @@ extern int olpc_ec_mask_unset(uint8_t bits); /* EC commands */ -#define EC_FIRMWARE_REV 0x08 +#define EC_FIRMWARE_REV 0x08 +#define EC_WAKE_UP_WLAN 0x24 +#define EC_SET_SCI_INHIBIT 0x32 +#define EC_SET_SCI_INHIBIT_RELEASE 0x34 /* SCI source values */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 4983b61..1b23334 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -106,7 +106,7 @@ obj-$(CONFIG_SCx200) += scx200.o scx200-y += scx200_32.o obj-$(CONFIG_OLPC) += olpc.o -obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o +obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o olpc-xo1-wakeup.o obj-$(CONFIG_OLPC_OPENFIRMWARE) += olpc_ofw.o obj-$(CONFIG_X86_MRST) += mrst.o diff --git a/arch/x86/kernel/olpc-xo1-wakeup.S b/arch/x86/kernel/olpc-xo1-wakeup.S new file mode 100644 index 0000000..d335074 --- /dev/null +++ b/arch/x86/kernel/olpc-xo1-wakeup.S @@ -0,0 +1,132 @@ +.text +#include <linux/linkage.h> +#include <asm/segment.h> +#include <asm/page.h> + + .macro writepost,value + movb $0x34, %al + outb %al, $0x70 + movb $\value, %al + outb %al, $0x71 + .endm + +ALIGN + .align 4096 + +wakeup_start: +# jmp wakeup_start + + cli + cld + + # Clear any dangerous flags + + pushl $0 + popfl + + writepost 0x31 + + # Set up %cr3 + movl $swsusp_pg_dir - __PAGE_OFFSET, %eax + movl %eax, %cr3 + + movl saved_cr4, %eax + movl %eax, %cr4 + + movl saved_cr0, %eax + movl %eax, %cr0 + + jmp 1f +1: + ljmpl $__KERNEL_CS,$wakeup_return + + +.org 0x1000 + +wakeup_return: + movw $__KERNEL_DS, %ax + movw %ax, %ss + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + lgdt saved_gdt + lidt saved_idt + lldt saved_ldt + ljmp $(__KERNEL_CS),$1f +1: + movl %cr3, %eax + movl %eax, %cr3 + wbinvd + + # Go back to the return point + jmp ret_point + +save_registers: + sgdt saved_gdt + sidt saved_idt + sldt saved_ldt + + pushl %edx + movl %cr4, %edx + movl %edx, saved_cr4 + + movl %cr0, %edx + movl %edx, saved_cr0 + + popl %edx + + movl %ebx, saved_context_ebx + movl %ebp, saved_context_ebp + movl %esi, saved_context_esi + movl %edi, saved_context_edi + + pushfl + popl saved_context_eflags + + ret + + +restore_registers: + movl saved_context_ebp, %ebp + movl saved_context_ebx, %ebx + movl saved_context_esi, %esi + movl saved_context_edi, %edi + + pushl saved_context_eflags + popfl + + ret + + +ENTRY(do_olpc_suspend_lowlevel) + call save_processor_state + call save_registers + + # This is the stack context we want to remember + movl %esp, saved_context_esp + + pushl $3 + call olpc_xo1_do_sleep + + jmp wakeup_start + .p2align 4,,7 +ret_point: + movl saved_context_esp, %esp + + writepost 0x32 + + call restore_registers + call restore_processor_state + ret + +.data +ALIGN + +saved_gdt: .long 0,0 +saved_idt: .long 0,0 +saved_ldt: .long 0 +saved_cr4: .long 0 +saved_cr0: .long 0 + diff --git a/arch/x86/kernel/olpc-xo1.c b/arch/x86/kernel/olpc-xo1.c index f5442c0..9a06081 100644 --- a/arch/x86/kernel/olpc-xo1.c +++ b/arch/x86/kernel/olpc-xo1.c @@ -16,6 +16,7 @@ #include <linux/pci_ids.h> #include <linux/platform_device.h> #include <linux/pm.h> +#include <linux/suspend.h> #include <asm/io.h> #include <asm/olpc.h> @@ -33,12 +34,83 @@ #define PM_SSC 0x54 /* PM registers (ACPI block) */ +#define PM1_STS 0x00 #define PM1_CNT 0x08 #define PM_GPE0_STS 0x18 +#define CS5536_PM_PWRBTN (1 << 8) + +extern void do_olpc_suspend_lowlevel(void); + static unsigned long acpi_base; static unsigned long pms_base; +static struct { + unsigned long address; + unsigned short segment; +} ofw_bios_entry = { 0xF0000 + PAGE_OFFSET, __KERNEL_CS }; + +static int xo1_power_state_enter(suspend_state_t pm_state) +{ + int r; + + /* Only STR is supported */ + if (pm_state != PM_SUSPEND_MEM) + return -EINVAL; + + r = olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0); + if (r) + return r; + + /* Save CPU state */ + do_olpc_suspend_lowlevel(); + + /* Resume path starts here */ + + /* Tell the EC to stop inhibiting SCIs */ + olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0); + + /* + * Tell the wireless module to restart USB communication. + * Must be done twice. + */ + olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0); + olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0); + + return 0; +} + +asmlinkage int olpc_xo1_do_sleep(u8 sleep_state) +{ + void *pgd_addr = __va(read_cr3()); + printk(KERN_ERR "xo1_do_sleep!\n"); /* this needs to remain here so + * that gcc doesn't optimize + * away our __va! */ + + /* Enable wakeup through power button */ + outl((CS5536_PM_PWRBTN << 16) | 0xFFFF, acpi_base + PM1_STS); + + __asm__ __volatile__("movl %0,%%eax" : : "r" (pgd_addr)); + __asm__("call *(%%edi); cld" + : : "D" (&ofw_bios_entry)); + __asm__ __volatile__("movb $0x34, %al\n\t" + "outb %al, $0x70\n\t" + "movb $0x30, %al\n\t" + "outb %al, $0x71\n\t"); + return 0; +} + +static int xo1_power_state_valid(suspend_state_t pm_state) +{ + /* suspend-to-RAM only */ + return pm_state == PM_SUSPEND_MEM; +} + +static struct platform_suspend_ops xo1_suspend_ops = { + .valid = xo1_power_state_valid, + .enter = xo1_power_state_enter, +}; + static void xo1_power_off(void) { printk(KERN_INFO "OLPC XO-1 power off sequence...\n"); @@ -101,6 +173,13 @@ static int __devinit olpc_xo1_probe(struct platform_device *pdev) if (r) return r; + /* + * Take a reference on ourself to prevent module unloading. We can't + * safely unload after changing the suspend handlers. + */ + __module_get(THIS_MODULE); + + suspend_set_ops(&xo1_suspend_ops); pm_power_off = xo1_power_off; printk(KERN_INFO "OLPC XO-1 support registered\n"); diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 43bbc29..dbdab67 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -549,7 +549,7 @@ static void __init pagetable_init(void) permanent_kmaps_init(pgd_base); } -#ifdef CONFIG_ACPI_SLEEP +#if defined(CONFIG_ACPI_SLEEP) || defined(CONFIG_OLPC_XO1) /* * ACPI suspend needs this for resume, because things like the intel-agp * driver might have split up a kernel 4MB mapping. @@ -561,11 +561,11 @@ static inline void save_pg_dir(void) { copy_page(swsusp_pg_dir, swapper_pg_dir); } -#else /* !CONFIG_ACPI_SLEEP */ +#else /* !CONFIG_ACPI_SLEEP && !CONFIG_OLPC_XO1 */ static inline void save_pg_dir(void) { } -#endif /* !CONFIG_ACPI_SLEEP */ +#endif /* !CONFIG_ACPI_SLEEP && !CONFIG_OLPC_XO1 */ void zap_low_mappings(bool early) { -- 1.7.2.3 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] OLPC: Add XO-1 suspend/resume support 2010-10-19 22:01 [PATCH] OLPC: Add XO-1 suspend/resume support Daniel Drake @ 2010-10-19 22:06 ` Randy Dunlap 2010-10-19 22:11 ` H. Peter Anvin 1 sibling, 0 replies; 7+ messages in thread From: Randy Dunlap @ 2010-10-19 22:06 UTC (permalink / raw) To: Daniel Drake; +Cc: tglx, mingo, hpa, x86, dilinger, linux-kernel On Tue, 19 Oct 2010 23:01:58 +0100 (BST) Daniel Drake wrote: > Add code needed for basic suspend/resume of the XO-1 laptop. > > swsusp_pg_dir needs to be exposed as it is used by the assembly > code run in the wakeup path. > > Signed-off-by: Daniel Drake <dsd@laptop.org> > --- > arch/x86/include/asm/olpc.h | 5 +- > arch/x86/kernel/Makefile | 2 +- > arch/x86/kernel/olpc-xo1-wakeup.S | 132 +++++++++++++++++++++++++++++++++++++ > arch/x86/kernel/olpc-xo1.c | 79 ++++++++++++++++++++++ > arch/x86/mm/init_32.c | 6 +- > 5 files changed, 219 insertions(+), 5 deletions(-) > create mode 100644 arch/x86/kernel/olpc-xo1-wakeup.S > > diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h > index 101229b..54dfe92 100644 > --- a/arch/x86/include/asm/olpc.h > +++ b/arch/x86/include/asm/olpc.h > @@ -88,7 +88,10 @@ extern int olpc_ec_mask_unset(uint8_t bits); > > /* EC commands */ > > -#define EC_FIRMWARE_REV 0x08 > +#define EC_FIRMWARE_REV 0x08 > +#define EC_WAKE_UP_WLAN 0x24 > +#define EC_SET_SCI_INHIBIT 0x32 > +#define EC_SET_SCI_INHIBIT_RELEASE 0x34 > > /* SCI source values */ > > diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile > index 4983b61..1b23334 100644 > --- a/arch/x86/kernel/Makefile > +++ b/arch/x86/kernel/Makefile > @@ -106,7 +106,7 @@ obj-$(CONFIG_SCx200) += scx200.o > scx200-y += scx200_32.o > > obj-$(CONFIG_OLPC) += olpc.o > -obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o > +obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o olpc-xo1-wakeup.o > obj-$(CONFIG_OLPC_OPENFIRMWARE) += olpc_ofw.o > obj-$(CONFIG_X86_MRST) += mrst.o > Hi, Does this build OK when CONFIG_PM is not enabled? or is that config not possible? > diff --git a/arch/x86/kernel/olpc-xo1-wakeup.S b/arch/x86/kernel/olpc-xo1-wakeup.S > new file mode 100644 > index 0000000..d335074 > --- /dev/null > +++ b/arch/x86/kernel/olpc-xo1-wakeup.S > @@ -0,0 +1,132 @@ > +.text > +#include <linux/linkage.h> > +#include <asm/segment.h> > +#include <asm/page.h> > + > + .macro writepost,value > + movb $0x34, %al > + outb %al, $0x70 > + movb $\value, %al > + outb %al, $0x71 > + .endm > + > +ALIGN > + .align 4096 > + > +wakeup_start: > +# jmp wakeup_start > + > + cli > + cld > + > + # Clear any dangerous flags > + > + pushl $0 > + popfl > + > + writepost 0x31 > + > + # Set up %cr3 > + movl $swsusp_pg_dir - __PAGE_OFFSET, %eax > + movl %eax, %cr3 > + > + movl saved_cr4, %eax > + movl %eax, %cr4 > + > + movl saved_cr0, %eax > + movl %eax, %cr0 > + > + jmp 1f > +1: > + ljmpl $__KERNEL_CS,$wakeup_return > + > + > +.org 0x1000 > + > +wakeup_return: > + movw $__KERNEL_DS, %ax > + movw %ax, %ss > + movw %ax, %ds > + movw %ax, %es > + movw %ax, %fs > + movw %ax, %gs > + > + lgdt saved_gdt > + lidt saved_idt > + lldt saved_ldt > + ljmp $(__KERNEL_CS),$1f > +1: > + movl %cr3, %eax > + movl %eax, %cr3 > + wbinvd > + > + # Go back to the return point > + jmp ret_point > + > +save_registers: > + sgdt saved_gdt > + sidt saved_idt > + sldt saved_ldt > + > + pushl %edx > + movl %cr4, %edx > + movl %edx, saved_cr4 > + > + movl %cr0, %edx > + movl %edx, saved_cr0 > + > + popl %edx > + > + movl %ebx, saved_context_ebx > + movl %ebp, saved_context_ebp > + movl %esi, saved_context_esi > + movl %edi, saved_context_edi > + > + pushfl > + popl saved_context_eflags > + > + ret > + > + > +restore_registers: > + movl saved_context_ebp, %ebp > + movl saved_context_ebx, %ebx > + movl saved_context_esi, %esi > + movl saved_context_edi, %edi > + > + pushl saved_context_eflags > + popfl > + > + ret > + > + > +ENTRY(do_olpc_suspend_lowlevel) > + call save_processor_state > + call save_registers > + > + # This is the stack context we want to remember > + movl %esp, saved_context_esp > + > + pushl $3 > + call olpc_xo1_do_sleep > + > + jmp wakeup_start > + .p2align 4,,7 > +ret_point: > + movl saved_context_esp, %esp > + > + writepost 0x32 > + > + call restore_registers > + call restore_processor_state > + ret > + > +.data > +ALIGN > + > +saved_gdt: .long 0,0 > +saved_idt: .long 0,0 > +saved_ldt: .long 0 > +saved_cr4: .long 0 > +saved_cr0: .long 0 > + > diff --git a/arch/x86/kernel/olpc-xo1.c b/arch/x86/kernel/olpc-xo1.c > index f5442c0..9a06081 100644 > --- a/arch/x86/kernel/olpc-xo1.c > +++ b/arch/x86/kernel/olpc-xo1.c > @@ -16,6 +16,7 @@ > #include <linux/pci_ids.h> > #include <linux/platform_device.h> > #include <linux/pm.h> > +#include <linux/suspend.h> > > #include <asm/io.h> > #include <asm/olpc.h> > @@ -33,12 +34,83 @@ > #define PM_SSC 0x54 > > /* PM registers (ACPI block) */ > +#define PM1_STS 0x00 > #define PM1_CNT 0x08 > #define PM_GPE0_STS 0x18 > > +#define CS5536_PM_PWRBTN (1 << 8) > + > +extern void do_olpc_suspend_lowlevel(void); > + > static unsigned long acpi_base; > static unsigned long pms_base; > > +static struct { > + unsigned long address; > + unsigned short segment; > +} ofw_bios_entry = { 0xF0000 + PAGE_OFFSET, __KERNEL_CS }; > + > +static int xo1_power_state_enter(suspend_state_t pm_state) > +{ > + int r; > + > + /* Only STR is supported */ > + if (pm_state != PM_SUSPEND_MEM) > + return -EINVAL; > + > + r = olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0); > + if (r) > + return r; > + > + /* Save CPU state */ > + do_olpc_suspend_lowlevel(); > + > + /* Resume path starts here */ > + > + /* Tell the EC to stop inhibiting SCIs */ > + olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0); > + > + /* > + * Tell the wireless module to restart USB communication. > + * Must be done twice. > + */ > + olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0); > + olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0); > + > + return 0; > +} > + > +asmlinkage int olpc_xo1_do_sleep(u8 sleep_state) > +{ > + void *pgd_addr = __va(read_cr3()); > + printk(KERN_ERR "xo1_do_sleep!\n"); /* this needs to remain here so > + * that gcc doesn't optimize > + * away our __va! */ > + > + /* Enable wakeup through power button */ > + outl((CS5536_PM_PWRBTN << 16) | 0xFFFF, acpi_base + PM1_STS); > + > + __asm__ __volatile__("movl %0,%%eax" : : "r" (pgd_addr)); > + __asm__("call *(%%edi); cld" > + : : "D" (&ofw_bios_entry)); > + __asm__ __volatile__("movb $0x34, %al\n\t" > + "outb %al, $0x70\n\t" > + "movb $0x30, %al\n\t" > + "outb %al, $0x71\n\t"); > + return 0; > +} > + > +static int xo1_power_state_valid(suspend_state_t pm_state) > +{ > + /* suspend-to-RAM only */ > + return pm_state == PM_SUSPEND_MEM; > +} > + > +static struct platform_suspend_ops xo1_suspend_ops = { > + .valid = xo1_power_state_valid, > + .enter = xo1_power_state_enter, > +}; > + > static void xo1_power_off(void) > { > printk(KERN_INFO "OLPC XO-1 power off sequence...\n"); > @@ -101,6 +173,13 @@ static int __devinit olpc_xo1_probe(struct platform_device *pdev) > if (r) > return r; > > + /* > + * Take a reference on ourself to prevent module unloading. We can't > + * safely unload after changing the suspend handlers. > + */ > + __module_get(THIS_MODULE); > + > + suspend_set_ops(&xo1_suspend_ops); > pm_power_off = xo1_power_off; > > printk(KERN_INFO "OLPC XO-1 support registered\n"); > diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c > index 43bbc29..dbdab67 100644 > --- a/arch/x86/mm/init_32.c > +++ b/arch/x86/mm/init_32.c > @@ -549,7 +549,7 @@ static void __init pagetable_init(void) > permanent_kmaps_init(pgd_base); > } > > -#ifdef CONFIG_ACPI_SLEEP > +#if defined(CONFIG_ACPI_SLEEP) || defined(CONFIG_OLPC_XO1) > /* > * ACPI suspend needs this for resume, because things like the intel-agp > * driver might have split up a kernel 4MB mapping. > @@ -561,11 +561,11 @@ static inline void save_pg_dir(void) > { > copy_page(swsusp_pg_dir, swapper_pg_dir); > } > -#else /* !CONFIG_ACPI_SLEEP */ > +#else /* !CONFIG_ACPI_SLEEP && !CONFIG_OLPC_XO1 */ > static inline void save_pg_dir(void) > { > } > -#endif /* !CONFIG_ACPI_SLEEP */ > +#endif /* !CONFIG_ACPI_SLEEP && !CONFIG_OLPC_XO1 */ > > void zap_low_mappings(bool early) > { > -- --- ~Randy *** Remember to use Documentation/SubmitChecklist when testing your code *** ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] OLPC: Add XO-1 suspend/resume support 2010-10-19 22:01 [PATCH] OLPC: Add XO-1 suspend/resume support Daniel Drake 2010-10-19 22:06 ` Randy Dunlap @ 2010-10-19 22:11 ` H. Peter Anvin 2010-10-20 5:47 ` Borislav Petkov 1 sibling, 1 reply; 7+ messages in thread From: H. Peter Anvin @ 2010-10-19 22:11 UTC (permalink / raw) To: Daniel Drake Cc: tglx, mingo, x86, dilinger, linux-kernel, Borislav Petkov, Roedel, Joerg On 10/19/2010 03:01 PM, Daniel Drake wrote: > Add code needed for basic suspend/resume of the XO-1 laptop. > > swsusp_pg_dir needs to be exposed as it is used by the assembly > code run in the wakeup path. > Okay... this is Yet Another Reason why we need to unify all the bloody trampoline page tables. What it comes down to is that there are several users which need a 1:1 mapped pagetable and a chunk of memory < 1 MiB, and they should all be combined and linked together, and share a single pagetable set that sticks around. Borislav has already been doing some of this work: [PATCH] x86-32, mm: Add an initial page table for core bootstrapping I thought that patch was already in -tip, but it looks like it's not... Borislav/Joerg... was there a newer patch or did we just miss the final version? I remember we talked about this at some length, but it looks like I dropped the ball (I was on vacation when the above message was posted.) -hpa ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] OLPC: Add XO-1 suspend/resume support 2010-10-19 22:11 ` H. Peter Anvin @ 2010-10-20 5:47 ` Borislav Petkov 2010-10-20 5:58 ` H. Peter Anvin 0 siblings, 1 reply; 7+ messages in thread From: Borislav Petkov @ 2010-10-20 5:47 UTC (permalink / raw) To: H. Peter Anvin Cc: Daniel Drake, tglx, mingo, x86, dilinger, linux-kernel, Borislav Petkov, Roedel, Joerg From: "H. Peter Anvin" <hpa@zytor.com> Date: Tue, Oct 19, 2010 at 06:11:13PM -0400 > On 10/19/2010 03:01 PM, Daniel Drake wrote: > > Add code needed for basic suspend/resume of the XO-1 laptop. > > > > swsusp_pg_dir needs to be exposed as it is used by the assembly > > code run in the wakeup path. > > > > Okay... this is Yet Another Reason why we need to unify all the bloody > trampoline page tables. > > What it comes down to is that there are several users which need a 1:1 > mapped pagetable and a chunk of memory < 1 MiB, and they should all be > combined and linked together, and share a single pagetable set that > sticks around. > > Borislav has already been doing some of this work: > > [PATCH] x86-32, mm: Add an initial page table for core bootstrapping > > I thought that patch was already in -tip, but it looks like it's not... > Borislav/Joerg... was there a newer patch or did we just miss the final > version? I remember we talked about this at some length, but it looks > like I dropped the ball (I was on vacation when the above message was > posted.) The final version with fixed ACPI sleep is this one: http://www.gossamer-threads.com/lists/linux/kernel/1270589 I ran it for a couple of weeks and it didn't show any regressions. If you want to get it into the merge window, I can get you an updated version against a -tip branch of your liking ASAP. -- Regards/Gruss, Boris. Advanced Micro Devices GmbH Einsteinring 24, 85609 Dornach General Managers: Alberto Bozzo, Andrew Bowd Registration: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] OLPC: Add XO-1 suspend/resume support 2010-10-20 5:47 ` Borislav Petkov @ 2010-10-20 5:58 ` H. Peter Anvin 2010-10-20 7:05 ` [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping Borislav Petkov 0 siblings, 1 reply; 7+ messages in thread From: H. Peter Anvin @ 2010-10-20 5:58 UTC (permalink / raw) To: Borislav Petkov Cc: Daniel Drake, tglx, mingo, x86, dilinger, linux-kernel, Roedel, Joerg On 10/19/2010 10:47 PM, Borislav Petkov wrote: > > The final version with fixed ACPI sleep is this one: > http://www.gossamer-threads.com/lists/linux/kernel/1270589 > > I ran it for a couple of weeks and it didn't show any regressions. If > you want to get it into the merge window, I can get you an updated > version against a -tip branch of your liking ASAP. > If you could prep something against tip:master we *might* be able to get it in... not sure yet (and it partly depends on when Linus decides to push the button, of course.) -hpa -- H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf. ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping 2010-10-20 5:58 ` H. Peter Anvin @ 2010-10-20 7:05 ` Borislav Petkov 2010-10-20 21:28 ` [tip:x86/trampoline] " tip-bot for Borislav Petkov 0 siblings, 1 reply; 7+ messages in thread From: Borislav Petkov @ 2010-10-20 7:05 UTC (permalink / raw) To: H. Peter Anvin Cc: Borislav Petkov, Daniel Drake, tglx, mingo, x86, dilinger, linux-kernel, Roedel, Joerg From: "H. Peter Anvin" <hpa@zytor.com> Date: Tue, Oct 19, 2010 at 10:58:30PM -0700 > If you could prep something against tip:master we *might* be able to get > it in... not sure yet (and it partly depends on when Linus decides to > push the button, of course.) Here you go, suspend-to-{ram,disk} works, will run it in the next couple of days just in case. -- From: Borislav Petkov <bp@alien8.de> Date: Sat, 28 Aug 2010 15:58:33 +0200 Subject: [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping This patch adds an initial page table with low mappings used exclusively for booting APs/resuming after ACPI suspend/machine restart. After this, there's no need to add low mappings to swapper_pg_dir and zap them later or create own swsusp PGD page solely for ACPI sleep needs - we have initial_page_table for that. [ v1.1 Fix suspend-to-ram ] Signed-off-by: Borislav Petkov <bp@alien8.de> --- arch/x86/include/asm/pgtable_32.h | 2 +- arch/x86/include/asm/tlbflush.h | 2 - arch/x86/include/asm/trampoline.h | 3 -- arch/x86/kernel/acpi/sleep.c | 7 ++++- arch/x86/kernel/head32.c | 1 + arch/x86/kernel/head_32.S | 55 +++++++++++++++++-------------------- arch/x86/kernel/reboot.c | 10 +----- arch/x86/kernel/setup.c | 18 +++++++++++- arch/x86/kernel/smpboot.c | 16 +++-------- arch/x86/kernel/trampoline.c | 16 ----------- arch/x86/mm/init_32.c | 45 ------------------------------ 11 files changed, 56 insertions(+), 119 deletions(-) diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h index f686f49..8abde9e 100644 --- a/arch/x86/include/asm/pgtable_32.h +++ b/arch/x86/include/asm/pgtable_32.h @@ -26,7 +26,7 @@ struct mm_struct; struct vm_area_struct; extern pgd_t swapper_pg_dir[1024]; -extern pgd_t trampoline_pg_dir[1024]; +extern pgd_t initial_page_table[1024]; static inline void pgtable_cache_init(void) { } static inline void check_pgt_cache(void) { } diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 7f3eba0..169be89 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -172,6 +172,4 @@ static inline void flush_tlb_kernel_range(unsigned long start, flush_tlb_all(); } -extern void zap_low_mappings(bool early); - #endif /* _ASM_X86_TLBFLUSH_H */ diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h index 4dde797..f4500fb 100644 --- a/arch/x86/include/asm/trampoline.h +++ b/arch/x86/include/asm/trampoline.h @@ -13,16 +13,13 @@ extern unsigned char *trampoline_base; extern unsigned long init_rsp; extern unsigned long initial_code; -extern unsigned long initial_page_table; extern unsigned long initial_gs; #define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE) extern unsigned long setup_trampoline(void); -extern void __init setup_trampoline_page_table(void); extern void __init reserve_trampoline_memory(void); #else -static inline void setup_trampoline_page_table(void) {} static inline void reserve_trampoline_memory(void) {} #endif /* CONFIG_X86_TRAMPOLINE */ diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index e125207..74a8478 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -13,6 +13,11 @@ #include <asm/segment.h> #include <asm/desc.h> +#ifdef CONFIG_X86_32 +#include <asm/pgtable.h> +#include <asm/pgtable_32.h> +#endif + #include "realmode/wakeup.h" #include "sleep.h" @@ -91,7 +96,7 @@ int acpi_save_state_mem(void) #ifndef CONFIG_64BIT header->pmode_entry = (u32)&wakeup_pmode_return; - header->pmode_cr3 = (u32)(swsusp_pg_dir - __PAGE_OFFSET); + header->pmode_cr3 = (u32)__pa(&initial_page_table); saved_magic = 0x12345678; #else /* CONFIG_64BIT */ header->trampoline_segment = setup_trampoline() >> 4; diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index 9a6ca23..7633101 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -18,6 +18,7 @@ #include <asm/apic.h> #include <asm/io_apic.h> #include <asm/bios_ebda.h> +#include <asm/tlbflush.h> static void __init i386_default_early_setup(void) { diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index fa8c1b8..bcece91 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -183,13 +183,12 @@ default_entry: #ifdef CONFIG_X86_PAE /* - * In PAE mode swapper_pg_dir is statically defined to contain enough - * entries to cover the VMSPLIT option (that is the top 1, 2 or 3 - * entries). The identity mapping is handled by pointing two PGD - * entries to the first kernel PMD. + * In PAE mode initial_page_table is statically defined to contain + * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3 + * entries). The identity mapping is handled by pointing two PGD entries + * to the first kernel PMD. * - * Note the upper half of each PMD or PTE are always zero at - * this stage. + * Note the upper half of each PMD or PTE are always zero at this stage. */ #define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */ @@ -197,7 +196,7 @@ default_entry: xorl %ebx,%ebx /* %ebx is kept at zero */ movl $pa(__brk_base), %edi - movl $pa(swapper_pg_pmd), %edx + movl $pa(initial_pg_pmd), %edx movl $PTE_IDENT_ATTR, %eax 10: leal PDE_IDENT_ATTR(%edi),%ecx /* Create PMD entry */ @@ -226,14 +225,14 @@ default_entry: movl %eax, pa(max_pfn_mapped) /* Do early initialization of the fixmap area */ - movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax - movl %eax,pa(swapper_pg_pmd+0x1000*KPMDS-8) + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax + movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8) #else /* Not PAE */ page_pde_offset = (__PAGE_OFFSET >> 20); movl $pa(__brk_base), %edi - movl $pa(swapper_pg_dir), %edx + movl $pa(initial_page_table), %edx movl $PTE_IDENT_ATTR, %eax 10: leal PDE_IDENT_ATTR(%edi),%ecx /* Create PDE entry */ @@ -257,8 +256,8 @@ page_pde_offset = (__PAGE_OFFSET >> 20); movl %eax, pa(max_pfn_mapped) /* Do early initialization of the fixmap area */ - movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax - movl %eax,pa(swapper_pg_dir+0xffc) + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax + movl %eax,pa(initial_page_table+0xffc) #endif jmp 3f /* @@ -334,7 +333,7 @@ ENTRY(startup_32_smp) /* * Enable paging */ - movl pa(initial_page_table), %eax + movl $pa(initial_page_table), %eax movl %eax,%cr3 /* set the page table pointer.. */ movl %cr0,%eax orl $X86_CR0_PG,%eax @@ -614,8 +613,6 @@ ignore_int: .align 4 ENTRY(initial_code) .long i386_start_kernel -ENTRY(initial_page_table) - .long pa(swapper_pg_dir) /* * BSS section @@ -623,20 +620,18 @@ ENTRY(initial_page_table) __PAGE_ALIGNED_BSS .align PAGE_SIZE_asm #ifdef CONFIG_X86_PAE -swapper_pg_pmd: +initial_pg_pmd: .fill 1024*KPMDS,4,0 #else -ENTRY(swapper_pg_dir) +ENTRY(initial_page_table) .fill 1024,4,0 #endif -swapper_pg_fixmap: +initial_pg_fixmap: .fill 1024,4,0 -#ifdef CONFIG_X86_TRAMPOLINE -ENTRY(trampoline_pg_dir) - .fill 1024,4,0 -#endif ENTRY(empty_zero_page) .fill 4096,1,0 +ENTRY(swapper_pg_dir) + .fill 1024,4,0 /* * This starts the data section. @@ -645,20 +640,20 @@ ENTRY(empty_zero_page) __PAGE_ALIGNED_DATA /* Page-aligned for the benefit of paravirt? */ .align PAGE_SIZE_asm -ENTRY(swapper_pg_dir) - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */ +ENTRY(initial_page_table) + .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */ # if KPMDS == 3 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x2000),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x2000),0 # elif KPMDS == 2 .long 0,0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0 # elif KPMDS == 1 .long 0,0 .long 0,0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 # else # error "Kernel PMDs should be 1, 2 or 3" # endif diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 7a4cf14..f7f53dc 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -371,16 +371,10 @@ void machine_real_restart(const unsigned char *code, int length) CMOS_WRITE(0x00, 0x8f); spin_unlock(&rtc_lock); - /* Remap the kernel at virtual address zero, as well as offset zero - from the kernel segment. This assumes the kernel segment starts at - virtual address PAGE_OFFSET. */ - memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, - sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS); - /* - * Use `swapper_pg_dir' as our page directory. + * Switch back to the initial page table. */ - load_cr3(swapper_pg_dir); + load_cr3(initial_page_table); /* Write 0x1234 to absolute memory location 0x472. The BIOS reads this on booting to tell it to "Bypass memory test (also warm diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 44e208e..3df995f 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -700,6 +700,17 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_X86_32 memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); visws_early_detect(); + + /* + * copy kernel address range established so far and switch + * to the proper swapper page table + */ + clone_pgd_range(swapper_pg_dir + KERNEL_PGD_BOUNDARY, + initial_page_table + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); + + load_cr3(swapper_pg_dir); + __flush_tlb_all(); #else printk(KERN_INFO "Command line: %s\n", boot_command_line); #endif @@ -985,7 +996,12 @@ void __init setup_arch(char **cmdline_p) paging_init(); x86_init.paging.pagetable_setup_done(swapper_pg_dir); - setup_trampoline_page_table(); +#ifdef CONFIG_X86_32 + /* sync back kernel address range */ + clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); +#endif tboot_probe(); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index dfb5089..6af1185 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -299,22 +299,16 @@ notrace static void __cpuinit start_secondary(void *unused) * fragile that we want to limit the things done here to the * most necessary things. */ + cpu_init(); + preempt_disable(); + smp_callin(); #ifdef CONFIG_X86_32 - /* - * Switch away from the trampoline page-table - * - * Do this before cpu_init() because it needs to access per-cpu - * data which may not be mapped in the trampoline page-table. - */ + /* switch away from the initial page table */ load_cr3(swapper_pg_dir); __flush_tlb_all(); #endif - cpu_init(); - preempt_disable(); - smp_callin(); - /* otherwise gcc will move up smp_processor_id before the cpu_init */ barrier(); /* @@ -785,7 +779,6 @@ do_rest: #ifdef CONFIG_X86_32 /* Stack for startup_32 can be just as for start_secondary onwards */ irq_ctx_init(cpu); - initial_page_table = __pa(&trampoline_pg_dir); #else clear_tsk_thread_flag(c_idle.idle, TIF_FORK); initial_gs = per_cpu_offset(cpu); @@ -934,7 +927,6 @@ int __cpuinit native_cpu_up(unsigned int cpu) per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; err = do_boot_cpu(apicid, cpu); - if (err) { pr_debug("do_boot_cpu failed %d\n", err); return -EIO; diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c index 4c3da56..a375616 100644 --- a/arch/x86/kernel/trampoline.c +++ b/arch/x86/kernel/trampoline.c @@ -38,19 +38,3 @@ unsigned long __trampinit setup_trampoline(void) memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE); return virt_to_phys(trampoline_base); } - -void __init setup_trampoline_page_table(void) -{ -#ifdef CONFIG_X86_32 - /* Copy kernel address range */ - clone_pgd_range(trampoline_pg_dir + KERNEL_PGD_BOUNDARY, - swapper_pg_dir + KERNEL_PGD_BOUNDARY, - KERNEL_PGD_PTRS); - - /* Initialize low mappings */ - clone_pgd_range(trampoline_pg_dir, - swapper_pg_dir + KERNEL_PGD_BOUNDARY, - min_t(unsigned long, KERNEL_PGD_PTRS, - KERNEL_PGD_BOUNDARY)); -#endif -} diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 5d0a671..0e969f9 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -528,48 +528,6 @@ static void __init pagetable_init(void) permanent_kmaps_init(pgd_base); } -#ifdef CONFIG_ACPI_SLEEP -/* - * ACPI suspend needs this for resume, because things like the intel-agp - * driver might have split up a kernel 4MB mapping. - */ -char swsusp_pg_dir[PAGE_SIZE] - __attribute__ ((aligned(PAGE_SIZE))); - -static inline void save_pg_dir(void) -{ - copy_page(swsusp_pg_dir, swapper_pg_dir); -} -#else /* !CONFIG_ACPI_SLEEP */ -static inline void save_pg_dir(void) -{ -} -#endif /* !CONFIG_ACPI_SLEEP */ - -void zap_low_mappings(bool early) -{ - int i; - - /* - * Zap initial low-memory mappings. - * - * Note that "pgd_clear()" doesn't do it for - * us, because pgd_clear() is a no-op on i386. - */ - for (i = 0; i < KERNEL_PGD_BOUNDARY; i++) { -#ifdef CONFIG_X86_PAE - set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); -#else - set_pgd(swapper_pg_dir+i, __pgd(0)); -#endif - } - - if (early) - __flush_tlb(); - else - flush_tlb_all(); -} - pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP); EXPORT_SYMBOL_GPL(__supported_pte_mask); @@ -882,9 +840,6 @@ void __init mem_init(void) if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); - - save_pg_dir(); - zap_low_mappings(true); } #ifdef CONFIG_MEMORY_HOTPLUG -- 1.7.2.3 -- Regards/Gruss, Boris. ^ permalink raw reply [flat|nested] 7+ messages in thread
* [tip:x86/trampoline] x86-32, mm: Add an initial page table for core bootstrapping 2010-10-20 7:05 ` [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping Borislav Petkov @ 2010-10-20 21:28 ` tip-bot for Borislav Petkov 0 siblings, 0 replies; 7+ messages in thread From: tip-bot for Borislav Petkov @ 2010-10-20 21:28 UTC (permalink / raw) To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, tglx, hpa, bp Commit-ID: b40827fa7268fda8a62490728a61c2856f33830b Gitweb: http://git.kernel.org/tip/b40827fa7268fda8a62490728a61c2856f33830b Author: Borislav Petkov <bp@alien8.de> AuthorDate: Sat, 28 Aug 2010 15:58:33 +0200 Committer: H. Peter Anvin <hpa@linux.intel.com> CommitDate: Wed, 20 Oct 2010 14:23:55 -0700 x86-32, mm: Add an initial page table for core bootstrapping This patch adds an initial page table with low mappings used exclusively for booting APs/resuming after ACPI suspend/machine restart. After this, there's no need to add low mappings to swapper_pg_dir and zap them later or create own swsusp PGD page solely for ACPI sleep needs - we have initial_page_table for that. Signed-off-by: Borislav Petkov <bp@alien8.de> LKML-Reference: <20101020070526.GA9588@liondog.tnic> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> --- arch/x86/include/asm/pgtable_32.h | 2 +- arch/x86/include/asm/tlbflush.h | 2 - arch/x86/include/asm/trampoline.h | 3 -- arch/x86/kernel/acpi/sleep.c | 7 ++++- arch/x86/kernel/head32.c | 1 + arch/x86/kernel/head_32.S | 55 +++++++++++++++++-------------------- arch/x86/kernel/reboot.c | 10 +----- arch/x86/kernel/setup.c | 18 +++++++++++- arch/x86/kernel/smpboot.c | 16 +++-------- arch/x86/kernel/trampoline.c | 16 ----------- arch/x86/mm/init_32.c | 45 ------------------------------ 11 files changed, 56 insertions(+), 119 deletions(-) diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h index f686f49..8abde9e 100644 --- a/arch/x86/include/asm/pgtable_32.h +++ b/arch/x86/include/asm/pgtable_32.h @@ -26,7 +26,7 @@ struct mm_struct; struct vm_area_struct; extern pgd_t swapper_pg_dir[1024]; -extern pgd_t trampoline_pg_dir[1024]; +extern pgd_t initial_page_table[1024]; static inline void pgtable_cache_init(void) { } static inline void check_pgt_cache(void) { } diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 7f3eba0..169be89 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -172,6 +172,4 @@ static inline void flush_tlb_kernel_range(unsigned long start, flush_tlb_all(); } -extern void zap_low_mappings(bool early); - #endif /* _ASM_X86_TLBFLUSH_H */ diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h index 4dde797..f4500fb 100644 --- a/arch/x86/include/asm/trampoline.h +++ b/arch/x86/include/asm/trampoline.h @@ -13,16 +13,13 @@ extern unsigned char *trampoline_base; extern unsigned long init_rsp; extern unsigned long initial_code; -extern unsigned long initial_page_table; extern unsigned long initial_gs; #define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE) extern unsigned long setup_trampoline(void); -extern void __init setup_trampoline_page_table(void); extern void __init reserve_trampoline_memory(void); #else -static inline void setup_trampoline_page_table(void) {} static inline void reserve_trampoline_memory(void) {} #endif /* CONFIG_X86_TRAMPOLINE */ diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 33cec15..b35e1ab 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -12,6 +12,11 @@ #include <asm/segment.h> #include <asm/desc.h> +#ifdef CONFIG_X86_32 +#include <asm/pgtable.h> +#include <asm/pgtable_32.h> +#endif + #include "realmode/wakeup.h" #include "sleep.h" @@ -90,7 +95,7 @@ int acpi_save_state_mem(void) #ifndef CONFIG_64BIT header->pmode_entry = (u32)&wakeup_pmode_return; - header->pmode_cr3 = (u32)(swsusp_pg_dir - __PAGE_OFFSET); + header->pmode_cr3 = (u32)__pa(&initial_page_table); saved_magic = 0x12345678; #else /* CONFIG_64BIT */ header->trampoline_segment = setup_trampoline() >> 4; diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index 784360c..8b9c201 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -17,6 +17,7 @@ #include <asm/apic.h> #include <asm/io_apic.h> #include <asm/bios_ebda.h> +#include <asm/tlbflush.h> static void __init i386_default_early_setup(void) { diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index fa8c1b8..bcece91 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -183,13 +183,12 @@ default_entry: #ifdef CONFIG_X86_PAE /* - * In PAE mode swapper_pg_dir is statically defined to contain enough - * entries to cover the VMSPLIT option (that is the top 1, 2 or 3 - * entries). The identity mapping is handled by pointing two PGD - * entries to the first kernel PMD. + * In PAE mode initial_page_table is statically defined to contain + * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3 + * entries). The identity mapping is handled by pointing two PGD entries + * to the first kernel PMD. * - * Note the upper half of each PMD or PTE are always zero at - * this stage. + * Note the upper half of each PMD or PTE are always zero at this stage. */ #define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */ @@ -197,7 +196,7 @@ default_entry: xorl %ebx,%ebx /* %ebx is kept at zero */ movl $pa(__brk_base), %edi - movl $pa(swapper_pg_pmd), %edx + movl $pa(initial_pg_pmd), %edx movl $PTE_IDENT_ATTR, %eax 10: leal PDE_IDENT_ATTR(%edi),%ecx /* Create PMD entry */ @@ -226,14 +225,14 @@ default_entry: movl %eax, pa(max_pfn_mapped) /* Do early initialization of the fixmap area */ - movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax - movl %eax,pa(swapper_pg_pmd+0x1000*KPMDS-8) + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax + movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8) #else /* Not PAE */ page_pde_offset = (__PAGE_OFFSET >> 20); movl $pa(__brk_base), %edi - movl $pa(swapper_pg_dir), %edx + movl $pa(initial_page_table), %edx movl $PTE_IDENT_ATTR, %eax 10: leal PDE_IDENT_ATTR(%edi),%ecx /* Create PDE entry */ @@ -257,8 +256,8 @@ page_pde_offset = (__PAGE_OFFSET >> 20); movl %eax, pa(max_pfn_mapped) /* Do early initialization of the fixmap area */ - movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax - movl %eax,pa(swapper_pg_dir+0xffc) + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax + movl %eax,pa(initial_page_table+0xffc) #endif jmp 3f /* @@ -334,7 +333,7 @@ ENTRY(startup_32_smp) /* * Enable paging */ - movl pa(initial_page_table), %eax + movl $pa(initial_page_table), %eax movl %eax,%cr3 /* set the page table pointer.. */ movl %cr0,%eax orl $X86_CR0_PG,%eax @@ -614,8 +613,6 @@ ignore_int: .align 4 ENTRY(initial_code) .long i386_start_kernel -ENTRY(initial_page_table) - .long pa(swapper_pg_dir) /* * BSS section @@ -623,20 +620,18 @@ ENTRY(initial_page_table) __PAGE_ALIGNED_BSS .align PAGE_SIZE_asm #ifdef CONFIG_X86_PAE -swapper_pg_pmd: +initial_pg_pmd: .fill 1024*KPMDS,4,0 #else -ENTRY(swapper_pg_dir) +ENTRY(initial_page_table) .fill 1024,4,0 #endif -swapper_pg_fixmap: +initial_pg_fixmap: .fill 1024,4,0 -#ifdef CONFIG_X86_TRAMPOLINE -ENTRY(trampoline_pg_dir) - .fill 1024,4,0 -#endif ENTRY(empty_zero_page) .fill 4096,1,0 +ENTRY(swapper_pg_dir) + .fill 1024,4,0 /* * This starts the data section. @@ -645,20 +640,20 @@ ENTRY(empty_zero_page) __PAGE_ALIGNED_DATA /* Page-aligned for the benefit of paravirt? */ .align PAGE_SIZE_asm -ENTRY(swapper_pg_dir) - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */ +ENTRY(initial_page_table) + .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */ # if KPMDS == 3 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x2000),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x2000),0 # elif KPMDS == 2 .long 0,0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0 # elif KPMDS == 1 .long 0,0 .long 0,0 - .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 + .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 # else # error "Kernel PMDs should be 1, 2 or 3" # endif diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 7a4cf14..f7f53dc 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -371,16 +371,10 @@ void machine_real_restart(const unsigned char *code, int length) CMOS_WRITE(0x00, 0x8f); spin_unlock(&rtc_lock); - /* Remap the kernel at virtual address zero, as well as offset zero - from the kernel segment. This assumes the kernel segment starts at - virtual address PAGE_OFFSET. */ - memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, - sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS); - /* - * Use `swapper_pg_dir' as our page directory. + * Switch back to the initial page table. */ - load_cr3(swapper_pg_dir); + load_cr3(initial_page_table); /* Write 0x1234 to absolute memory location 0x472. The BIOS reads this on booting to tell it to "Bypass memory test (also warm diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 322b24f..af6cf2b 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -728,6 +728,17 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_X86_32 memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); visws_early_detect(); + + /* + * copy kernel address range established so far and switch + * to the proper swapper page table + */ + clone_pgd_range(swapper_pg_dir + KERNEL_PGD_BOUNDARY, + initial_page_table + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); + + load_cr3(swapper_pg_dir); + __flush_tlb_all(); #else printk(KERN_INFO "Command line: %s\n", boot_command_line); #endif @@ -1009,7 +1020,12 @@ void __init setup_arch(char **cmdline_p) paging_init(); x86_init.paging.pagetable_setup_done(swapper_pg_dir); - setup_trampoline_page_table(); +#ifdef CONFIG_X86_32 + /* sync back kernel address range */ + clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); +#endif tboot_probe(); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 63a1a55..e63bb51 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -298,22 +298,16 @@ notrace static void __cpuinit start_secondary(void *unused) * fragile that we want to limit the things done here to the * most necessary things. */ + cpu_init(); + preempt_disable(); + smp_callin(); #ifdef CONFIG_X86_32 - /* - * Switch away from the trampoline page-table - * - * Do this before cpu_init() because it needs to access per-cpu - * data which may not be mapped in the trampoline page-table. - */ + /* switch away from the initial page table */ load_cr3(swapper_pg_dir); __flush_tlb_all(); #endif - cpu_init(); - preempt_disable(); - smp_callin(); - /* otherwise gcc will move up smp_processor_id before the cpu_init */ barrier(); /* @@ -772,7 +766,6 @@ do_rest: #ifdef CONFIG_X86_32 /* Stack for startup_32 can be just as for start_secondary onwards */ irq_ctx_init(cpu); - initial_page_table = __pa(&trampoline_pg_dir); #else clear_tsk_thread_flag(c_idle.idle, TIF_FORK); initial_gs = per_cpu_offset(cpu); @@ -921,7 +914,6 @@ int __cpuinit native_cpu_up(unsigned int cpu) per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; err = do_boot_cpu(apicid, cpu); - if (err) { pr_debug("do_boot_cpu failed %d\n", err); return -EIO; diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c index e2a5952..f1488a3 100644 --- a/arch/x86/kernel/trampoline.c +++ b/arch/x86/kernel/trampoline.c @@ -38,19 +38,3 @@ unsigned long __trampinit setup_trampoline(void) memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE); return virt_to_phys(trampoline_base); } - -void __init setup_trampoline_page_table(void) -{ -#ifdef CONFIG_X86_32 - /* Copy kernel address range */ - clone_pgd_range(trampoline_pg_dir + KERNEL_PGD_BOUNDARY, - swapper_pg_dir + KERNEL_PGD_BOUNDARY, - KERNEL_PGD_PTRS); - - /* Initialize low mappings */ - clone_pgd_range(trampoline_pg_dir, - swapper_pg_dir + KERNEL_PGD_BOUNDARY, - min_t(unsigned long, KERNEL_PGD_PTRS, - KERNEL_PGD_BOUNDARY)); -#endif -} diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 558f2d3..1aeac2d 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -548,48 +548,6 @@ static void __init pagetable_init(void) permanent_kmaps_init(pgd_base); } -#ifdef CONFIG_ACPI_SLEEP -/* - * ACPI suspend needs this for resume, because things like the intel-agp - * driver might have split up a kernel 4MB mapping. - */ -char swsusp_pg_dir[PAGE_SIZE] - __attribute__ ((aligned(PAGE_SIZE))); - -static inline void save_pg_dir(void) -{ - copy_page(swsusp_pg_dir, swapper_pg_dir); -} -#else /* !CONFIG_ACPI_SLEEP */ -static inline void save_pg_dir(void) -{ -} -#endif /* !CONFIG_ACPI_SLEEP */ - -void zap_low_mappings(bool early) -{ - int i; - - /* - * Zap initial low-memory mappings. - * - * Note that "pgd_clear()" doesn't do it for - * us, because pgd_clear() is a no-op on i386. - */ - for (i = 0; i < KERNEL_PGD_BOUNDARY; i++) { -#ifdef CONFIG_X86_PAE - set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); -#else - set_pgd(swapper_pg_dir+i, __pgd(0)); -#endif - } - - if (early) - __flush_tlb(); - else - flush_tlb_all(); -} - pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP); EXPORT_SYMBOL_GPL(__supported_pte_mask); @@ -958,9 +916,6 @@ void __init mem_init(void) if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); - - save_pg_dir(); - zap_low_mappings(true); } #ifdef CONFIG_MEMORY_HOTPLUG ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2010-10-20 21:28 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2010-10-19 22:01 [PATCH] OLPC: Add XO-1 suspend/resume support Daniel Drake 2010-10-19 22:06 ` Randy Dunlap 2010-10-19 22:11 ` H. Peter Anvin 2010-10-20 5:47 ` Borislav Petkov 2010-10-20 5:58 ` H. Peter Anvin 2010-10-20 7:05 ` [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping Borislav Petkov 2010-10-20 21:28 ` [tip:x86/trampoline] " tip-bot for Borislav Petkov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
Powered by JetHome