2012-05-08 18:22:53

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 00/23] x86, realmode: new infrastructure for realmode code

I've been working together with H. Peter Anvin in order
replace the ad-hoc real-mode code inside .x86_trampoline
section with an encapsulated binary that is fully relocatable
to any memory location under 1MB. Everything that is needs to
be relocated is relocated during initialization.

Benefits:
- Simplifies things. Real-mode code does not have to find its
own location any more. This makes maintaining and extending
this code much nicer experience.
- Cleans up code base a lot. Now real-mode code is encapsulated
from kernel both in source tree and in vmlinux.
- We can set proper permissions to pages of text, data/bss
and rodata. Before, .x86_trampoline had just rwx permissions.


2012-05-08 18:23:11

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 02/23] x86, realmode: realmode.bin infrastructure

Create realmode.bin and realmode.relocs files. Piggy
pack them into relocatable object that will be included
into .init.data section of the main kernel image.

The first file includes binary image of the real-mode code.
The latter file includes all relocations. The layout of the
binary image is specified in realmode.lds.S. The makefile
generates pa_ prefixed symbols for each exported global.
These are used in 32-bit code and in realmode header to
define symbols that need to be relocated.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Originally-by: H. Peter Anvin <[email protected]>
---
arch/x86/Kbuild | 2 +-
arch/x86/realmode/Makefile | 20 +++++++++++
arch/x86/realmode/rm/.gitignore | 3 ++
arch/x86/realmode/rm/Makefile | 63 ++++++++++++++++++++++++++++++++
arch/x86/realmode/rm/header.S | 16 +++++++++
arch/x86/realmode/rm/realmode.lds.S | 68 +++++++++++++++++++++++++++++++++++
arch/x86/realmode/rmpiggy.S | 18 ++++++++++
7 files changed, 189 insertions(+), 1 deletion(-)
create mode 100644 arch/x86/realmode/Makefile
create mode 100644 arch/x86/realmode/rm/.gitignore
create mode 100644 arch/x86/realmode/rm/Makefile
create mode 100644 arch/x86/realmode/rm/header.S
create mode 100644 arch/x86/realmode/rm/realmode.lds.S
create mode 100644 arch/x86/realmode/rmpiggy.S

diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild
index 0e9dec6..e5287d8 100644
--- a/arch/x86/Kbuild
+++ b/arch/x86/Kbuild
@@ -1,4 +1,3 @@
-
obj-$(CONFIG_KVM) += kvm/

# Xen paravirtualization support
@@ -7,6 +6,7 @@ obj-$(CONFIG_XEN) += xen/
# lguest paravirtualization support
obj-$(CONFIG_LGUEST_GUEST) += lguest/

+obj-y += realmode/
obj-y += kernel/
obj-y += mm/

diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile
new file mode 100644
index 0000000..f22a4f8
--- /dev/null
+++ b/arch/x86/realmode/Makefile
@@ -0,0 +1,20 @@
+#
+# arch/x86/realmode/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+#
+
+subdir- := rm
+
+obj-y += rmpiggy.o
+
+$(obj)/rmpiggy.o: $(obj)/rm/realmode.relocs $(obj)/rm/realmode.bin
+
+$(obj)/rm/realmode.bin: FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/rm $@
+
+$(obj)/rm/realmode.relocs: FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/rm $@
diff --git a/arch/x86/realmode/rm/.gitignore b/arch/x86/realmode/rm/.gitignore
new file mode 100644
index 0000000..b6ed3a2
--- /dev/null
+++ b/arch/x86/realmode/rm/.gitignore
@@ -0,0 +1,3 @@
+pasyms.h
+realmode.lds
+realmode.relocs
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
new file mode 100644
index 0000000..7c3f202
--- /dev/null
+++ b/arch/x86/realmode/rm/Makefile
@@ -0,0 +1,63 @@
+#
+# arch/x86/realmode/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+#
+
+subdir- := wakeup
+
+always := realmode.bin
+
+realmode-y += header.o
+
+targets += $(realmode-y)
+
+REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y))
+
+sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p'
+
+quiet_cmd_pasyms = PASYMS $@
+ cmd_pasyms = $(NM) $(filter-out FORCE,$^) | \
+ sed $(sed-pasyms) | sort | uniq > $@
+
+$(obj)/pasyms.h: $(REALMODE_OBJS) FORCE
+ $(call if_changed,pasyms)
+
+$(obj)/realmode.lds: $(obj)/pasyms.h
+
+LDFLAGS_realmode.elf := --emit-relocs -T
+CPPFLAGS_realmode.lds += -P -C -I$(obj)
+
+$(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE
+ $(call if_changed,ld)
+
+OBJCOPYFLAGS_realmode.bin := -O binary
+
+$(obj)/realmode.bin: $(obj)/realmode.elf
+ $(call if_changed,objcopy)
+
+quiet_cmd_relocs = RELOCS $@
+ cmd_relocs = scripts/x86-relocs --realmode $< > $@
+$(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
+ $(call if_changed,relocs)
+
+# ---------------------------------------------------------------------------
+
+# How to compile the 16-bit code. Note we always compile for -march=i386,
+# that way we can complain to the user if the CPU is insufficient.
+KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \
+ -DDISABLE_BRANCH_PROFILING \
+ -Wall -Wstrict-prototypes \
+ -march=i386 -mregparm=3 \
+ -include $(srctree)/$(src)/../../boot/code16gcc.h \
+ -fno-strict-aliasing -fomit-frame-pointer \
+ $(call cc-option, -ffreestanding) \
+ $(call cc-option, -fno-toplevel-reorder,\
+ $(call cc-option, -fno-unit-at-a-time)) \
+ $(call cc-option, -fno-stack-protector) \
+ $(call cc-option, -mpreferred-stack-boundary=2)
+KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
+GCOV_PROFILE := n
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
new file mode 100644
index 0000000..7be17f2
--- /dev/null
+++ b/arch/x86/realmode/rm/header.S
@@ -0,0 +1,16 @@
+/*
+ * Real-mode blob header; this should match realmode.h and be
+ * readonly; for mutable data instead add pointers into the .data
+ * or .bss sections as appropriate.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+ .section ".header", "a"
+
+ENTRY(real_mode_header)
+ .long pa_text_start
+ .long pa_ro_end
+ .long pa_end
+END(real_mode_header)
diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S
new file mode 100644
index 0000000..c5b8a4f
--- /dev/null
+++ b/arch/x86/realmode/rm/realmode.lds.S
@@ -0,0 +1,68 @@
+/*
+ * realmode.lds.S
+ *
+ * Linker script for the real-mode code
+ */
+
+#include <asm/page_types.h>
+
+#undef i386
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+
+SECTIONS
+{
+ real_mode_seg = 0;
+
+ . = 0;
+ .header : {
+ pa_real_mode_base = .;
+ *(.header)
+ }
+
+ . = ALIGN(4);
+ .rodata : {
+ *(.rodata)
+ *(.rodata.*)
+ }
+
+ . = ALIGN(PAGE_SIZE);
+ .text : {
+ pa_text_start = .;
+ *(.text)
+ *(.text.*)
+ }
+
+ .text32 : {
+ *(.text32)
+ *(.text32.*)
+ pa_ro_end = .;
+ }
+
+ . = ALIGN(PAGE_SIZE);
+ .data : {
+ *(.data)
+ *(.data.*)
+ }
+
+ . = ALIGN(128);
+ .bss : {
+ *(.bss*)
+ }
+
+ /* End signature for integrity checking */
+ . = ALIGN(4);
+ .signature : {
+ *(.signature)
+ pa_end = .;
+ }
+
+ /DISCARD/ : {
+ *(.note*)
+ *(.debug*)
+ *(.eh_frame*)
+ }
+
+#include "pasyms.h"
+}
diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S
new file mode 100644
index 0000000..6047d7f
--- /dev/null
+++ b/arch/x86/realmode/rmpiggy.S
@@ -0,0 +1,18 @@
+/*
+ * Wrapper script for the realmode binary as a transport object
+ * before copying to low memory.
+ */
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+ .section ".init.data","aw"
+
+ .balign PAGE_SIZE
+
+ENTRY(real_mode_blob)
+ .incbin "arch/x86/realmode/rm/realmode.bin"
+END(real_mode_blob)
+
+ENTRY(real_mode_relocs)
+ .incbin "arch/x86/realmode/rm/realmode.relocs"
+END(real_mode_relocs)
--
1.7.9.5

2012-05-08 18:23:23

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 05/23] x86, realmode: Move SMP trampoline to unified realmode code

Migrated SMP trampoline code to the real mode blob.
SMP trampoline code is not yet removed from
.x86_trampoline because it is needed by the wakeup
code.

[ hpa: always enable compiling startup_32_smp in head_32.S... it is
only a few instructions which go into .init on UP builds, and it makes
the rest of the code less #ifdef ugly. ]

Signed-off-by: Jarkko Sakkinen <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/include/asm/realmode.h | 18 ++++
arch/x86/kernel/head_32.S | 5 +-
arch/x86/kernel/head_64.S | 4 -
arch/x86/kernel/realmode.c | 14 +++
arch/x86/kernel/smpboot.c | 18 ++--
arch/x86/realmode/rm/Makefile | 1 +
arch/x86/realmode/rm/header.S | 11 +++
arch/x86/realmode/rm/trampoline_32.S | 86 +++++++++++++++++
arch/x86/realmode/rm/trampoline_64.S | 175 ++++++++++++++++++++++++++++++++++
9 files changed, 316 insertions(+), 16 deletions(-)
create mode 100644 arch/x86/realmode/rm/trampoline_32.S
create mode 100644 arch/x86/realmode/rm/trampoline_64.S

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index bf26b06..9b4a5da 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -13,6 +13,17 @@ struct real_mode_header {
#ifdef CONFIG_X86_32
u32 machine_real_restart_asm;
#endif
+ /* SMP trampoline */
+ u32 trampoline_data;
+ u32 trampoline_status;
+#ifdef CONFIG_X86_32
+ u32 startup_32_smp;
+ u32 boot_gdt;
+#else
+ u32 startup_64_smp;
+ u32 level3_ident_pgt;
+ u32 level3_kernel_pgt;
+#endif
} __attribute__((__packed__));

extern struct real_mode_header real_mode_header;
@@ -25,6 +36,13 @@ extern unsigned long initial_gs;
extern unsigned char real_mode_blob[];
extern unsigned char real_mode_relocs[];

+#ifdef CONFIG_X86_32
+extern unsigned char startup_32_smp[];
+extern unsigned char boot_gdt[];
+#else
+extern unsigned char secondary_startup_64[];
+#endif
+
extern void __init setup_real_mode(void);

#endif /* _ARCH_X86_REALMODE_H */
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index ce0be7c..a3c2b4f 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -273,10 +273,7 @@ num_subarch_entries = (. - subarch_entries) / 4
* If cpu hotplug is not supported then this code can go in init section
* which will be freed later
*/
-
__CPUINIT
-
-#ifdef CONFIG_SMP
ENTRY(startup_32_smp)
cld
movl $(__BOOT_DS),%eax
@@ -287,7 +284,7 @@ ENTRY(startup_32_smp)
movl pa(stack_start),%ecx
movl %eax,%ss
leal -__PAGE_OFFSET(%ecx),%esp
-#endif /* CONFIG_SMP */
+
default_entry:

/*
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 40f4eb3..d70bc2e 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -136,10 +136,6 @@ ident_complete:
/* Fixup phys_base */
addq %rbp, phys_base(%rip)

- /* Fixup trampoline */
- addq %rbp, trampoline_level4_pgt + 0(%rip)
- addq %rbp, trampoline_level4_pgt + (511*8)(%rip)
-
/* Due to ENTRY(), sometimes the empty space gets filled with
* zeros. Better take a jmp than relying on empty space being
* filled with 0x90 (nop)
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index 7415c42..a465775 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -58,6 +58,20 @@ void __init setup_real_mode(void)
/* Copied header will contain relocated physical addresses. */
memcpy(&real_mode_header, real_mode_base,
sizeof(struct real_mode_header));
+
+#ifdef CONFIG_X86_32
+ *((u32 *)__va(real_mode_header.startup_32_smp)) = __pa(startup_32_smp);
+ *((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt);
+#else
+ *((u64 *) __va(real_mode_header.startup_64_smp)) =
+ (u64) __pa(secondary_startup_64);
+
+ *((u64 *) __va(real_mode_header.level3_ident_pgt)) =
+ __pa(level3_ident_pgt) + _KERNPG_TABLE;
+
+ *((u64 *) __va(real_mode_header.level3_kernel_pgt)) =
+ __pa(level3_kernel_pgt) + _KERNPG_TABLE;
+#endif
}

/*
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 6e1e406..c7971ea 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -57,7 +57,7 @@
#include <asm/nmi.h>
#include <asm/irq.h>
#include <asm/idle.h>
-#include <asm/trampoline.h>
+#include <asm/realmode.h>
#include <asm/cpu.h>
#include <asm/numa.h>
#include <asm/pgtable.h>
@@ -73,6 +73,8 @@
#include <asm/smpboot_hooks.h>
#include <asm/i8259.h>

+#include <asm/realmode.h>
+
/* State of each CPU */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

@@ -662,8 +664,12 @@ static void __cpuinit announce_cpu(int cpu, int apicid)
*/
static int __cpuinit do_boot_cpu(int apicid, int cpu)
{
+ volatile u32 *trampoline_status =
+ (volatile u32 *) __va(real_mode_header.trampoline_status);
+ /* start_ip had better be page-aligned! */
+ unsigned long start_ip = real_mode_header.trampoline_data;
+
unsigned long boot_error = 0;
- unsigned long start_ip;
int timeout;
struct create_idle c_idle = {
.cpu = cpu,
@@ -713,9 +719,6 @@ do_rest:
initial_code = (unsigned long)start_secondary;
stack_start = c_idle.idle->thread.sp;

- /* start_ip had better be page-aligned! */
- start_ip = trampoline_address();
-
/* So we see what's up */
announce_cpu(cpu, apicid);

@@ -778,8 +781,7 @@ do_rest:
pr_debug("CPU%d: has booted.\n", cpu);
} else {
boot_error = 1;
- if (*(volatile u32 *)TRAMPOLINE_SYM(trampoline_status)
- == 0xA5A5A5A5)
+ if (*trampoline_status == 0xA5A5A5A5)
/* trampoline started but...? */
pr_err("CPU%d: Stuck ??\n", cpu);
else
@@ -805,7 +807,7 @@ do_rest:
}

/* mark "stuck" area as not stuck */
- *(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) = 0;
+ *trampoline_status = 0;

if (get_uv_system_type() != UV_NON_UNIQUE_APIC) {
/*
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 3f851c4..56ec64f 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -13,6 +13,7 @@ always := realmode.bin

realmode-y += header.o
realmode-$(CONFIG_X86_32) += reboot_32.o
+realmode-y += trampoline_$(BITS).o

targets += $(realmode-y)

diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index db21401..a979004 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -16,4 +16,15 @@ ENTRY(real_mode_header)
#ifdef CONFIG_X86_32
.long pa_machine_real_restart_asm
#endif
+ /* SMP trampoline */
+ .long pa_trampoline_data
+ .long pa_trampoline_status
+#ifdef CONFIG_X86_32
+ .long pa_startup_32_smp
+ .long pa_boot_gdt
+#else
+ .long pa_startup_64_smp
+ .long pa_level3_ident_pgt
+ .long pa_level3_kernel_pgt
+#endif
END(real_mode_header)
diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
new file mode 100644
index 0000000..18cb7fc
--- /dev/null
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -0,0 +1,86 @@
+/*
+ *
+ * Trampoline.S Derived from Setup.S by Linus Torvalds
+ *
+ * 4 Jan 1997 Michael Chastain: changed to gnu as.
+ *
+ * This is only used for booting secondary CPUs in SMP machine
+ *
+ * Entry: CS:IP point to the start of our code, we are
+ * in real mode with no stack, but the rest of the
+ * trampoline page to make our stack and everything else
+ * is a mystery.
+ *
+ * We jump into arch/x86/kernel/head_32.S.
+ *
+ * On entry to trampoline_data, the processor is in real mode
+ * with 16-bit addressing and 16-bit data. CS has some value
+ * and IP is zero. Thus, we load CS to the physical segment
+ * of the real mode code before doing anything further.
+ *
+ * The structure real_mode_header includes entries that need
+ * to be set up before executing this code:
+ *
+ * startup_32_smp
+ * boot_gdt
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/segment.h>
+#include <asm/page_types.h>
+
+ .text
+ .code16
+ .globl trampoline_data
+
+ .balign PAGE_SIZE
+trampoline_data:
+ wbinvd # Needed for NUMA-Q should be harmless for others
+
+ .byte 0xea # ljmpw
+ .word 1f # Offset
+ .word real_mode_seg # Segment
+1:
+ mov %cs, %ax # Code and data in the same place
+ mov %ax, %ds
+
+ cli # We should be safe anyway
+
+ movl $0xA5A5A5A5, trampoline_status
+ # write marker for master knows we're running
+
+ /* GDT tables in non default location kernel can be beyond 16MB and
+ * lgdt will not be able to load the address as in real mode default
+ * operand size is 16bit. Use lgdtl instead to force operand size
+ * to 32 bit.
+ */
+
+ lidtl boot_idt_descr # load idt with 0, 0
+ lgdtl boot_gdt_descr # load gdt with whatever is appropriate
+
+ xor %ax, %ax
+ inc %ax # protected mode (PE) bit
+ lmsw %ax # into protected mode
+
+ # flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
+ ljmpl *(startup_32_smp)
+
+ .data
+ .globl startup_32_smp, boot_gdt, trampoline_status
+
+boot_gdt_descr:
+ .word __BOOT_DS + 7 # gdt limit
+boot_gdt:
+ .long 0 # gdt base
+
+boot_idt_descr:
+ .word 0 # idt limit = 0
+ .long 0 # idt base = 0L
+
+trampoline_status:
+ .long 0
+
+startup_32_smp:
+ .long 0x00000000
+ .word __BOOT_CS, 0
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
new file mode 100644
index 0000000..063da00
--- /dev/null
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -0,0 +1,175 @@
+/*
+ *
+ * Trampoline.S Derived from Setup.S by Linus Torvalds
+ *
+ * 4 Jan 1997 Michael Chastain: changed to gnu as.
+ * 15 Sept 2005 Eric Biederman: 64bit PIC support
+ *
+ * Entry: CS:IP point to the start of our code, we are
+ * in real mode with no stack, but the rest of the
+ * trampoline page to make our stack and everything else
+ * is a mystery.
+ *
+ * On entry to trampoline_data, the processor is in real mode
+ * with 16-bit addressing and 16-bit data. CS has some value
+ * and IP is zero. Thus, data addresses need to be absolute
+ * (no relocation) and are taken with regard to r_base.
+ *
+ * With the addition of trampoline_level4_pgt this code can
+ * now enter a 64bit kernel that lives at arbitrary 64bit
+ * physical addresses.
+ *
+ * If you work on this file, check the object module with objdump
+ * --full-contents --reloc to make sure there are no relocation
+ * entries.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/pgtable_types.h>
+#include <asm/page_types.h>
+#include <asm/msr.h>
+#include <asm/segment.h>
+#include <asm/processor-flags.h>
+
+ .text
+ .balign PAGE_SIZE
+ .code16
+
+ENTRY(trampoline_data)
+ cli # We should be safe anyway
+ wbinvd
+
+ .byte 0xea # ljmpw
+ .word 1f # Offset
+ .word real_mode_seg # Segment
+1:
+ mov %cs, %ax # Code and data in the same place
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %ss
+
+ movl $0xA5A5A5A5, trampoline_status
+ # write marker for master knows we're running
+
+ # Setup stack
+ movw $trampoline_stack_end, %sp
+
+ call verify_cpu # Verify the cpu supports long mode
+ testl %eax, %eax # Check for return code
+ jnz no_longmode
+
+ /*
+ * GDT tables in non default location kernel can be beyond 16MB and
+ * lgdt will not be able to load the address as in real mode default
+ * operand size is 16bit. Use lgdtl instead to force operand size
+ * to 32 bit.
+ */
+
+ lidtl tidt # load idt with 0, 0
+ lgdtl tgdt # load gdt with whatever is appropriate
+
+ mov $X86_CR0_PE, %ax # protected mode (PE) bit
+ lmsw %ax # into protected mode
+
+ # flush prefetch and jump to startup_32
+ ljmpl *(startup_32_vector)
+
+no_longmode:
+ hlt
+ jmp no_longmode
+#include "../kernel/verify_cpu.S"
+
+ .code32
+ .balign 4
+ENTRY(startup_32)
+ movl $__KERNEL_DS, %eax # Initialize the %ds segment register
+ movl %eax, %ds
+
+ movl $X86_CR4_PAE, %eax
+ movl %eax, %cr4 # Enable PAE mode
+
+ movl pa_startup_64_smp, %esi
+ movl pa_startup_64_smp_high, %edi
+
+ # Setup trampoline 4 level pagetables
+ leal pa_trampoline_level4_pgt, %eax
+ movl %eax, %cr3
+
+ movl $MSR_EFER, %ecx
+ movl $(1 << _EFER_LME), %eax # Enable Long Mode
+ xorl %edx, %edx
+ wrmsr
+
+ # Enable paging and in turn activate Long Mode
+ # Enable protected mode
+ movl $(X86_CR0_PG | X86_CR0_PE), %eax
+ movl %eax, %cr0
+
+ /*
+ * At this point we're in long mode but in 32bit compatibility mode
+ * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
+ * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
+ * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+ */
+ ljmpl *(pa_startup_64_vector)
+
+ .code64
+ .balign 4
+ENTRY(startup_64)
+ # Now jump into the kernel using virtual addresses
+ movl %edi, %eax
+ shlq $32, %rax
+ addl %esi, %eax
+ jmp *%rax
+
+ # Careful these need to be in the same 64K segment as the above;
+tidt:
+ .word 0 # idt limit = 0
+ .word 0, 0 # idt base = 0L
+
+ # Duplicate the global descriptor table
+ # so the kernel can live anywhere
+ .balign 4
+ .globl tgdt
+tgdt:
+ .short tgdt_end - tgdt # gdt limit
+ .long pa_tgdt
+ .short 0
+ .quad 0x00cf9b000000ffff # __KERNEL32_CS
+ .quad 0x00af9b000000ffff # __KERNEL_CS
+ .quad 0x00cf93000000ffff # __KERNEL_DS
+tgdt_end:
+
+ .balign 4
+startup_32_vector:
+ .long pa_startup_32
+ .word __KERNEL32_CS, 0
+
+ .balign 4
+ .globl startup_64_vector
+startup_64_vector:
+ .long pa_startup_64
+ .word __KERNEL_CS, 0
+
+ .data
+
+ .balign 4
+ENTRY(trampoline_status)
+ .long 0
+
+trampoline_stack:
+ .org 0x1000
+trampoline_stack_end:
+
+ .globl level3_ident_pgt
+ .globl level3_kernel_pgt
+ENTRY(trampoline_level4_pgt)
+ level3_ident_pgt: .quad 0
+ .fill 510,8,0
+ level3_kernel_pgt: .quad 0
+
+ .globl startup_64_smp
+ .globl startup_64_smp_high
+startup_64_smp: .long 0
+startup_64_smp_high: .long 0
--
1.7.9.5

2012-05-08 18:23:18

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 03/23] x86, realmode: Relocator for realmode code

Implements relocator for real mode code that is called
as part of setup_arch(). Processes segment relocations
and linear relocations. Real-mode code is relocated to
a free hole below 1 MB.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/include/asm/realmode.h | 26 +++++++++++++
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/realmode.c | 79 +++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/setup.c | 2 +
4 files changed, 108 insertions(+)
create mode 100644 arch/x86/include/asm/realmode.h
create mode 100644 arch/x86/kernel/realmode.c

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
new file mode 100644
index 0000000..dc1bba5
--- /dev/null
+++ b/arch/x86/include/asm/realmode.h
@@ -0,0 +1,26 @@
+#ifndef _ARCH_X86_REALMODE_H
+#define _ARCH_X86_REALMODE_H
+
+#include <linux/types.h>
+#include <asm/io.h>
+
+/* This must match data at realmode.S */
+struct real_mode_header {
+ u32 text_start;
+ u32 ro_end;
+ u32 end;
+} __attribute__((__packed__));
+
+extern struct real_mode_header real_mode_header;
+extern unsigned char *real_mode_base;
+
+extern unsigned long init_rsp;
+extern unsigned long initial_code;
+extern unsigned long initial_gs;
+
+extern unsigned char real_mode_blob[];
+extern unsigned char real_mode_relocs[];
+
+extern void __init setup_real_mode(void);
+
+#endif /* _ARCH_X86_REALMODE_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 532d2e0..f9e19d4 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -36,6 +36,7 @@ obj-y += pci-iommu_table.o
obj-y += resource.o

obj-y += trampoline.o trampoline_$(BITS).o
+obj-y += realmode.o
obj-y += process.o
obj-y += i387.o xsave.o
obj-y += ptrace.o
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
new file mode 100644
index 0000000..7415c42
--- /dev/null
+++ b/arch/x86/kernel/realmode.c
@@ -0,0 +1,79 @@
+#include <linux/io.h>
+#include <linux/memblock.h>
+
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <asm/realmode.h>
+
+unsigned char *real_mode_base;
+struct real_mode_header real_mode_header;
+
+void __init setup_real_mode(void)
+{
+ phys_addr_t mem;
+ u16 real_mode_seg;
+ u32 *rel;
+ u32 count;
+ u32 *ptr;
+ u16 *seg;
+ int i;
+
+ struct real_mode_header *header =
+ (struct real_mode_header *) real_mode_blob;
+
+ size_t size = PAGE_ALIGN(header->end);
+
+ /* Has to be in very low memory so we can execute real-mode AP code. */
+ mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
+ if (!mem)
+ panic("Cannot allocate trampoline\n");
+
+ real_mode_base = __va(mem);
+ memblock_reserve(mem, size);
+
+ printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
+ real_mode_base, (unsigned long long)mem, size);
+
+ memcpy(real_mode_base, real_mode_blob, size);
+
+ real_mode_seg = __pa(real_mode_base) >> 4;
+ rel = (u32 *) real_mode_relocs;
+
+ /* 16-bit segment relocations. */
+ count = rel[0];
+ rel = &rel[1];
+ for (i = 0; i < count; i++) {
+ seg = (u16 *) (real_mode_base + rel[i]);
+ *seg = real_mode_seg;
+ }
+
+ /* 32-bit linear relocations. */
+ count = rel[i];
+ rel = &rel[i + 1];
+ for (i = 0; i < count; i++) {
+ ptr = (u32 *) (real_mode_base + rel[i]);
+ *ptr += __pa(real_mode_base);
+ }
+
+ /* Copied header will contain relocated physical addresses. */
+ memcpy(&real_mode_header, real_mode_base,
+ sizeof(struct real_mode_header));
+}
+
+/*
+ * set_real_mode_permissions() gets called very early, to guarantee the
+ * availability of low memory. This is before the proper kernel page
+ * tables are set up, so we cannot set page permissions in that
+ * function. Thus, we use an arch_initcall instead.
+ */
+static int __init set_real_mode_permissions(void)
+{
+ size_t all_size =
+ PAGE_ALIGN(real_mode_header.end) -
+ __pa(real_mode_base);
+
+ set_memory_x((unsigned long) real_mode_base, all_size >> PAGE_SHIFT);
+ return 0;
+}
+
+arch_initcall(set_real_mode_permissions);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 1a29015..56e4124 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -74,6 +74,7 @@
#include <asm/mtrr.h>
#include <asm/apic.h>
#include <asm/trampoline.h>
+#include <asm/realmode.h>
#include <asm/e820.h>
#include <asm/mpspec.h>
#include <asm/setup.h>
@@ -918,6 +919,7 @@ void __init setup_arch(char **cmdline_p)
max_pfn_mapped<<PAGE_SHIFT);

setup_trampolines();
+ setup_real_mode();

init_gbpages();

--
1.7.9.5

2012-05-08 18:23:39

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 06/23] x86, realmode: Move ACPI wakeup to unified realmode code

Migrated ACPI wakeup code to the real-mode blob.
Code existing in .x86_trampoline can be completely
removed. Static descriptor table in wakeup_asm.S is
courtesy of H. Peter Anvin.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/include/asm/acpi.h | 2 -
arch/x86/include/asm/realmode.h | 4 +
arch/x86/include/asm/trampoline.h | 39 ------
arch/x86/kernel/Makefile | 1 -
arch/x86/kernel/acpi/Makefile | 9 +-
arch/x86/kernel/acpi/realmode/.gitignore | 3 -
arch/x86/kernel/acpi/realmode/Makefile | 59 ---------
arch/x86/kernel/acpi/realmode/bioscall.S | 1 -
arch/x86/kernel/acpi/realmode/copy.S | 1 -
arch/x86/kernel/acpi/realmode/regs.c | 1 -
arch/x86/kernel/acpi/realmode/video-bios.c | 1 -
arch/x86/kernel/acpi/realmode/video-mode.c | 1 -
arch/x86/kernel/acpi/realmode/video-vesa.c | 1 -
arch/x86/kernel/acpi/realmode/video-vga.c | 1 -
arch/x86/kernel/acpi/realmode/wakemain.c | 81 ------------
arch/x86/kernel/acpi/realmode/wakeup.S | 170 -------------------------
arch/x86/kernel/acpi/realmode/wakeup.h | 48 -------
arch/x86/kernel/acpi/realmode/wakeup.lds.S | 62 ---------
arch/x86/kernel/acpi/sleep.c | 33 +----
arch/x86/kernel/acpi/sleep.h | 2 +-
arch/x86/kernel/acpi/wakeup_rm.S | 12 --
arch/x86/kernel/head32.c | 1 -
arch/x86/kernel/head64.c | 1 -
arch/x86/kernel/mpparse.c | 1 -
arch/x86/kernel/setup.c | 2 -
arch/x86/kernel/tboot.c | 5 +-
arch/x86/kernel/trampoline.c | 42 -------
arch/x86/kernel/trampoline_32.S | 83 ------------
arch/x86/kernel/trampoline_64.S | 171 -------------------------
arch/x86/kernel/vmlinux.lds.S | 12 --
arch/x86/realmode/rm/Makefile | 4 +
arch/x86/realmode/rm/header.S | 5 +
arch/x86/realmode/rm/realmode.lds.S | 4 +
arch/x86/realmode/rm/wakeup/.gitignore | 3 +
arch/x86/realmode/rm/wakeup/Makefile | 33 +++++
arch/x86/realmode/rm/wakeup/bioscall.S | 1 +
arch/x86/realmode/rm/wakeup/copy.S | 1 +
arch/x86/realmode/rm/wakeup/regs.c | 1 +
arch/x86/realmode/rm/wakeup/video-bios.c | 1 +
arch/x86/realmode/rm/wakeup/video-mode.c | 1 +
arch/x86/realmode/rm/wakeup/video-vesa.c | 1 +
arch/x86/realmode/rm/wakeup/video-vga.c | 1 +
arch/x86/realmode/rm/wakeup/wakemain.c | 82 ++++++++++++
arch/x86/realmode/rm/wakeup/wakeup.h | 41 ++++++
arch/x86/realmode/rm/wakeup/wakeup_asm.S | 189 ++++++++++++++++++++++++++++
drivers/acpi/sleep.c | 8 +-
46 files changed, 386 insertions(+), 840 deletions(-)
delete mode 100644 arch/x86/include/asm/trampoline.h
delete mode 100644 arch/x86/kernel/acpi/realmode/.gitignore
delete mode 100644 arch/x86/kernel/acpi/realmode/Makefile
delete mode 100644 arch/x86/kernel/acpi/realmode/bioscall.S
delete mode 100644 arch/x86/kernel/acpi/realmode/copy.S
delete mode 100644 arch/x86/kernel/acpi/realmode/regs.c
delete mode 100644 arch/x86/kernel/acpi/realmode/video-bios.c
delete mode 100644 arch/x86/kernel/acpi/realmode/video-mode.c
delete mode 100644 arch/x86/kernel/acpi/realmode/video-vesa.c
delete mode 100644 arch/x86/kernel/acpi/realmode/video-vga.c
delete mode 100644 arch/x86/kernel/acpi/realmode/wakemain.c
delete mode 100644 arch/x86/kernel/acpi/realmode/wakeup.S
delete mode 100644 arch/x86/kernel/acpi/realmode/wakeup.h
delete mode 100644 arch/x86/kernel/acpi/realmode/wakeup.lds.S
delete mode 100644 arch/x86/kernel/acpi/wakeup_rm.S
delete mode 100644 arch/x86/kernel/trampoline.c
delete mode 100644 arch/x86/kernel/trampoline_32.S
delete mode 100644 arch/x86/kernel/trampoline_64.S
create mode 100644 arch/x86/realmode/rm/wakeup/.gitignore
create mode 100644 arch/x86/realmode/rm/wakeup/Makefile
create mode 100644 arch/x86/realmode/rm/wakeup/bioscall.S
create mode 100644 arch/x86/realmode/rm/wakeup/copy.S
create mode 100644 arch/x86/realmode/rm/wakeup/regs.c
create mode 100644 arch/x86/realmode/rm/wakeup/video-bios.c
create mode 100644 arch/x86/realmode/rm/wakeup/video-mode.c
create mode 100644 arch/x86/realmode/rm/wakeup/video-vesa.c
create mode 100644 arch/x86/realmode/rm/wakeup/video-vga.c
create mode 100644 arch/x86/realmode/rm/wakeup/wakemain.c
create mode 100644 arch/x86/realmode/rm/wakeup/wakeup.h
create mode 100644 arch/x86/realmode/rm/wakeup/wakeup_asm.S

diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index 610001d..724aa44 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -29,7 +29,6 @@
#include <asm/processor.h>
#include <asm/mmu.h>
#include <asm/mpspec.h>
-#include <asm/trampoline.h>

#define COMPILER_DEPENDENT_INT64 long long
#define COMPILER_DEPENDENT_UINT64 unsigned long long
@@ -118,7 +117,6 @@ static inline void acpi_disable_pci(void)
extern int acpi_suspend_lowlevel(void);

extern const unsigned char acpi_wakeup_code[];
-#define acpi_wakeup_address (__pa(TRAMPOLINE_SYM(acpi_wakeup_code)))

/* early initialization routine */
extern void acpi_reserve_wakeup_memory(void);
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index 9b4a5da..1bfc74d 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -24,6 +24,10 @@ struct real_mode_header {
u32 level3_ident_pgt;
u32 level3_kernel_pgt;
#endif
+#ifdef CONFIG_ACPI_SLEEP
+ u32 wakeup_start;
+ u32 wakeup_header;
+#endif
} __attribute__((__packed__));

extern struct real_mode_header real_mode_header;
diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h
deleted file mode 100644
index feca311..0000000
--- a/arch/x86/include/asm/trampoline.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _ASM_X86_TRAMPOLINE_H
-#define _ASM_X86_TRAMPOLINE_H
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-#include <asm/io.h>
-
-/*
- * Trampoline 80x86 program as an array. These are in the init rodata
- * segment, but that's okay, because we only care about the relative
- * addresses of the symbols.
- */
-extern const unsigned char x86_trampoline_start [];
-extern const unsigned char x86_trampoline_end [];
-extern unsigned char *x86_trampoline_base;
-
-extern unsigned long init_rsp;
-extern unsigned long initial_code;
-extern unsigned long initial_gs;
-
-extern void __init setup_trampolines(void);
-
-extern const unsigned char trampoline_data[];
-extern const unsigned char trampoline_status[];
-
-#define TRAMPOLINE_SYM(x) \
- ((void *)(x86_trampoline_base + \
- ((const unsigned char *)(x) - x86_trampoline_start)))
-
-/* Address of the SMP trampoline */
-static inline unsigned long trampoline_address(void)
-{
- return virt_to_phys(TRAMPOLINE_SYM(trampoline_data));
-}
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _ASM_X86_TRAMPOLINE_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index b71ef35..4a20f44 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -35,7 +35,6 @@ obj-y += tsc.o io_delay.o rtc.o
obj-y += pci-iommu_table.o
obj-y += resource.o

-obj-y += trampoline.o trampoline_$(BITS).o
obj-y += realmode.o
obj-y += process.o
obj-y += i387.o xsave.o
diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile
index 6f35260..163b225 100644
--- a/arch/x86/kernel/acpi/Makefile
+++ b/arch/x86/kernel/acpi/Makefile
@@ -1,14 +1,7 @@
-subdir- := realmode
-
obj-$(CONFIG_ACPI) += boot.o
-obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_rm.o wakeup_$(BITS).o
+obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o

ifneq ($(CONFIG_ACPI_PROCESSOR),)
obj-y += cstate.o
endif

-$(obj)/wakeup_rm.o: $(obj)/realmode/wakeup.bin
-
-$(obj)/realmode/wakeup.bin: FORCE
- $(Q)$(MAKE) $(build)=$(obj)/realmode
-
diff --git a/arch/x86/kernel/acpi/realmode/.gitignore b/arch/x86/kernel/acpi/realmode/.gitignore
deleted file mode 100644
index 58f1f48..0000000
--- a/arch/x86/kernel/acpi/realmode/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-wakeup.bin
-wakeup.elf
-wakeup.lds
diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile
deleted file mode 100644
index 6a564ac..0000000
--- a/arch/x86/kernel/acpi/realmode/Makefile
+++ /dev/null
@@ -1,59 +0,0 @@
-#
-# arch/x86/kernel/acpi/realmode/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-
-always := wakeup.bin
-targets := wakeup.elf wakeup.lds
-
-wakeup-y += wakeup.o wakemain.o video-mode.o copy.o bioscall.o regs.o
-
-# The link order of the video-*.o modules can matter. In particular,
-# video-vga.o *must* be listed first, followed by video-vesa.o.
-# Hardware-specific drivers should follow in the order they should be
-# probed, and video-bios.o should typically be last.
-wakeup-y += video-vga.o
-wakeup-y += video-vesa.o
-wakeup-y += video-bios.o
-
-targets += $(wakeup-y)
-
-bootsrc := $(src)/../../../boot
-
-# ---------------------------------------------------------------------------
-
-# How to compile the 16-bit code. Note we always compile for -march=i386,
-# that way we can complain to the user if the CPU is insufficient.
-# Compile with _SETUP since this is similar to the boot-time setup code.
-KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \
- -I$(srctree)/$(bootsrc) \
- $(cflags-y) \
- -Wall -Wstrict-prototypes \
- -march=i386 -mregparm=3 \
- -include $(srctree)/$(bootsrc)/code16gcc.h \
- -fno-strict-aliasing -fomit-frame-pointer \
- $(call cc-option, -ffreestanding) \
- $(call cc-option, -fno-toplevel-reorder,\
- $(call cc-option, -fno-unit-at-a-time)) \
- $(call cc-option, -fno-stack-protector) \
- $(call cc-option, -mpreferred-stack-boundary=2)
-KBUILD_CFLAGS += $(call cc-option, -m32)
-KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
-GCOV_PROFILE := n
-
-WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
-
-LDFLAGS_wakeup.elf := -T
-
-CPPFLAGS_wakeup.lds += -P -C
-
-$(obj)/wakeup.elf: $(obj)/wakeup.lds $(WAKEUP_OBJS) FORCE
- $(call if_changed,ld)
-
-OBJCOPYFLAGS_wakeup.bin := -O binary
-
-$(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE
- $(call if_changed,objcopy)
diff --git a/arch/x86/kernel/acpi/realmode/bioscall.S b/arch/x86/kernel/acpi/realmode/bioscall.S
deleted file mode 100644
index f51eb0b..0000000
--- a/arch/x86/kernel/acpi/realmode/bioscall.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/bioscall.S"
diff --git a/arch/x86/kernel/acpi/realmode/copy.S b/arch/x86/kernel/acpi/realmode/copy.S
deleted file mode 100644
index dc59ebe..0000000
--- a/arch/x86/kernel/acpi/realmode/copy.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/copy.S"
diff --git a/arch/x86/kernel/acpi/realmode/regs.c b/arch/x86/kernel/acpi/realmode/regs.c
deleted file mode 100644
index 6206033..0000000
--- a/arch/x86/kernel/acpi/realmode/regs.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/regs.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-bios.c b/arch/x86/kernel/acpi/realmode/video-bios.c
deleted file mode 100644
index 7deabc1..0000000
--- a/arch/x86/kernel/acpi/realmode/video-bios.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-bios.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-mode.c b/arch/x86/kernel/acpi/realmode/video-mode.c
deleted file mode 100644
index 328ad20..0000000
--- a/arch/x86/kernel/acpi/realmode/video-mode.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-mode.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-vesa.c b/arch/x86/kernel/acpi/realmode/video-vesa.c
deleted file mode 100644
index 9dbb967..0000000
--- a/arch/x86/kernel/acpi/realmode/video-vesa.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-vesa.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-vga.c b/arch/x86/kernel/acpi/realmode/video-vga.c
deleted file mode 100644
index bcc8125..0000000
--- a/arch/x86/kernel/acpi/realmode/video-vga.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-vga.c"
diff --git a/arch/x86/kernel/acpi/realmode/wakemain.c b/arch/x86/kernel/acpi/realmode/wakemain.c
deleted file mode 100644
index 883962d..0000000
--- a/arch/x86/kernel/acpi/realmode/wakemain.c
+++ /dev/null
@@ -1,81 +0,0 @@
-#include "wakeup.h"
-#include "boot.h"
-
-static void udelay(int loops)
-{
- while (loops--)
- io_delay(); /* Approximately 1 us */
-}
-
-static void beep(unsigned int hz)
-{
- u8 enable;
-
- if (!hz) {
- enable = 0x00; /* Turn off speaker */
- } else {
- u16 div = 1193181/hz;
-
- outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */
- io_delay();
- outb(div, 0x42); /* LSB of counter */
- io_delay();
- outb(div >> 8, 0x42); /* MSB of counter */
- io_delay();
-
- enable = 0x03; /* Turn on speaker */
- }
- inb(0x61); /* Dummy read of System Control Port B */
- io_delay();
- outb(enable, 0x61); /* Enable timer 2 output to speaker */
- io_delay();
-}
-
-#define DOT_HZ 880
-#define DASH_HZ 587
-#define US_PER_DOT 125000
-
-/* Okay, this is totally silly, but it's kind of fun. */
-static void send_morse(const char *pattern)
-{
- char s;
-
- while ((s = *pattern++)) {
- switch (s) {
- case '.':
- beep(DOT_HZ);
- udelay(US_PER_DOT);
- beep(0);
- udelay(US_PER_DOT);
- break;
- case '-':
- beep(DASH_HZ);
- udelay(US_PER_DOT * 3);
- beep(0);
- udelay(US_PER_DOT);
- break;
- default: /* Assume it's a space */
- udelay(US_PER_DOT * 3);
- break;
- }
- }
-}
-
-void main(void)
-{
- /* Kill machine if structures are wrong */
- if (wakeup_header.real_magic != 0x12345678)
- while (1);
-
- if (wakeup_header.realmode_flags & 4)
- send_morse("...-");
-
- if (wakeup_header.realmode_flags & 1)
- asm volatile("lcallw $0xc000,$3");
-
- if (wakeup_header.realmode_flags & 2) {
- /* Need to call BIOS */
- probe_cards(0);
- set_mode(wakeup_header.video_mode);
- }
-}
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S
deleted file mode 100644
index b4fd836..0000000
--- a/arch/x86/kernel/acpi/realmode/wakeup.S
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * ACPI wakeup real mode startup stub
- */
-#include <asm/segment.h>
-#include <asm/msr-index.h>
-#include <asm/page_types.h>
-#include <asm/pgtable_types.h>
-#include <asm/processor-flags.h>
-#include "wakeup.h"
-
- .code16
- .section ".jump", "ax"
- .globl _start
-_start:
- cli
- jmp wakeup_code
-
-/* This should match the structure in wakeup.h */
- .section ".header", "a"
- .globl wakeup_header
-wakeup_header:
-video_mode: .short 0 /* Video mode number */
-pmode_return: .byte 0x66, 0xea /* ljmpl */
- .long 0 /* offset goes here */
- .short __KERNEL_CS
-pmode_cr0: .long 0 /* Saved %cr0 */
-pmode_cr3: .long 0 /* Saved %cr3 */
-pmode_cr4: .long 0 /* Saved %cr4 */
-pmode_efer: .quad 0 /* Saved EFER */
-pmode_gdt: .quad 0
-pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
-pmode_behavior: .long 0 /* Wakeup behavior flags */
-realmode_flags: .long 0
-real_magic: .long 0
-trampoline_segment: .word 0
-_pad1: .byte 0
-wakeup_jmp: .byte 0xea /* ljmpw */
-wakeup_jmp_off: .word 3f
-wakeup_jmp_seg: .word 0
-wakeup_gdt: .quad 0, 0, 0
-signature: .long WAKEUP_HEADER_SIGNATURE
-
- .text
- .code16
-wakeup_code:
- cld
-
- /* Apparently some dimwit BIOS programmers don't know how to
- program a PM to RM transition, and we might end up here with
- junk in the data segment descriptor registers. The only way
- to repair that is to go into PM and fix it ourselves... */
- movw $16, %cx
- lgdtl %cs:wakeup_gdt
- movl %cr0, %eax
- orb $X86_CR0_PE, %al
- movl %eax, %cr0
- jmp 1f
-1: ljmpw $8, $2f
-2:
- movw %cx, %ds
- movw %cx, %es
- movw %cx, %ss
- movw %cx, %fs
- movw %cx, %gs
-
- andb $~X86_CR0_PE, %al
- movl %eax, %cr0
- jmp wakeup_jmp
-3:
- /* Set up segments */
- movw %cs, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- lidtl wakeup_idt
-
- movl $wakeup_stack_end, %esp
-
- /* Clear the EFLAGS */
- pushl $0
- popfl
-
- /* Check header signature... */
- movl signature, %eax
- cmpl $WAKEUP_HEADER_SIGNATURE, %eax
- jne bogus_real_magic
-
- /* Check we really have everything... */
- movl end_signature, %eax
- cmpl $WAKEUP_END_SIGNATURE, %eax
- jne bogus_real_magic
-
- /* Call the C code */
- calll main
-
- /* Restore MISC_ENABLE before entering protected mode, in case
- BIOS decided to clear XD_DISABLE during S3. */
- movl pmode_behavior, %eax
- btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
- jnc 1f
-
- movl pmode_misc_en, %eax
- movl pmode_misc_en + 4, %edx
- movl $MSR_IA32_MISC_ENABLE, %ecx
- wrmsr
-1:
-
- /* Do any other stuff... */
-
-#ifndef CONFIG_64BIT
- /* This could also be done in C code... */
- movl pmode_cr3, %eax
- movl %eax, %cr3
-
- movl pmode_cr4, %ecx
- jecxz 1f
- movl %ecx, %cr4
-1:
- movl pmode_efer, %eax
- movl pmode_efer + 4, %edx
- movl %eax, %ecx
- orl %edx, %ecx
- jz 1f
- movl $MSR_EFER, %ecx
- wrmsr
-1:
-
- lgdtl pmode_gdt
-
- /* This really couldn't... */
- movl pmode_cr0, %eax
- movl %eax, %cr0
- jmp pmode_return
-#else
- pushw $0
- pushw trampoline_segment
- pushw $0
- lret
-#endif
-
-bogus_real_magic:
-1:
- hlt
- jmp 1b
-
- .data
- .balign 8
-
- /* This is the standard real-mode IDT */
-wakeup_idt:
- .word 0xffff /* limit */
- .long 0 /* address */
- .word 0
-
- .globl HEAP, heap_end
-HEAP:
- .long wakeup_heap
-heap_end:
- .long wakeup_stack
-
- .bss
-wakeup_heap:
- .space 2048
-wakeup_stack:
- .space 2048
-wakeup_stack_end:
-
- .section ".signature","a"
-end_signature:
- .long WAKEUP_END_SIGNATURE
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h
deleted file mode 100644
index 97a29e1..0000000
--- a/arch/x86/kernel/acpi/realmode/wakeup.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Definitions for the wakeup data structure at the head of the
- * wakeup code.
- */
-
-#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
-#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
-
-#ifndef __ASSEMBLY__
-#include <linux/types.h>
-
-/* This must match data at wakeup.S */
-struct wakeup_header {
- u16 video_mode; /* Video mode number */
- u16 _jmp1; /* ljmpl opcode, 32-bit only */
- u32 pmode_entry; /* Protected mode resume point, 32-bit only */
- u16 _jmp2; /* CS value, 32-bit only */
- u32 pmode_cr0; /* Protected mode cr0 */
- u32 pmode_cr3; /* Protected mode cr3 */
- u32 pmode_cr4; /* Protected mode cr4 */
- u32 pmode_efer_low; /* Protected mode EFER */
- u32 pmode_efer_high;
- u64 pmode_gdt;
- u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */
- u32 pmode_misc_en_high;
- u32 pmode_behavior; /* Wakeup routine behavior flags */
- u32 realmode_flags;
- u32 real_magic;
- u16 trampoline_segment; /* segment with trampoline code, 64-bit only */
- u8 _pad1;
- u8 wakeup_jmp;
- u16 wakeup_jmp_off;
- u16 wakeup_jmp_seg;
- u64 wakeup_gdt[3];
- u32 signature; /* To check we have correct structure */
-} __attribute__((__packed__));
-
-extern struct wakeup_header wakeup_header;
-#endif
-
-#define WAKEUP_HEADER_OFFSET 8
-#define WAKEUP_HEADER_SIGNATURE 0x51ee1111
-#define WAKEUP_END_SIGNATURE 0x65a22c82
-
-/* Wakeup behavior bits */
-#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0
-
-#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
deleted file mode 100644
index d4f8010..0000000
--- a/arch/x86/kernel/acpi/realmode/wakeup.lds.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * wakeup.ld
- *
- * Linker script for the real-mode wakeup code
- */
-#undef i386
-#include "wakeup.h"
-
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
-
-SECTIONS
-{
- . = 0;
- .jump : {
- *(.jump)
- } = 0x90909090
-
- . = WAKEUP_HEADER_OFFSET;
- .header : {
- *(.header)
- }
-
- . = ALIGN(16);
- .text : {
- *(.text*)
- } = 0x90909090
-
- . = ALIGN(16);
- .rodata : {
- *(.rodata*)
- }
-
- .videocards : {
- video_cards = .;
- *(.videocards)
- video_cards_end = .;
- }
-
- . = ALIGN(16);
- .data : {
- *(.data*)
- }
-
- . = ALIGN(16);
- .bss : {
- __bss_start = .;
- *(.bss)
- __bss_end = .;
- }
-
- .signature : {
- *(.signature)
- }
-
- _end = .;
-
- /DISCARD/ : {
- *(.note*)
- }
-}
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 103b6ab..9ad1b79 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -14,8 +14,9 @@
#include <asm/desc.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
+#include <asm/realmode.h>

-#include "realmode/wakeup.h"
+#include "../../realmode/rm/wakeup/wakeup.h"
#include "sleep.h"

unsigned long acpi_realmode_flags;
@@ -32,13 +33,9 @@ static char temp_stack[4096];
*/
int acpi_suspend_lowlevel(void)
{
- struct wakeup_header *header;
- /* address in low memory of the wakeup routine. */
- char *acpi_realmode;
+ struct wakeup_header *header =
+ (struct wakeup_header *) __va(real_mode_header.wakeup_header);

- acpi_realmode = TRAMPOLINE_SYM(acpi_wakeup_code);
-
- header = (struct wakeup_header *)(acpi_realmode + WAKEUP_HEADER_OFFSET);
if (header->signature != WAKEUP_HEADER_SIGNATURE) {
printk(KERN_ERR "wakeup header does not match\n");
return -EINVAL;
@@ -46,27 +43,6 @@ int acpi_suspend_lowlevel(void)

header->video_mode = saved_video_mode;

- header->wakeup_jmp_seg = acpi_wakeup_address >> 4;
-
- /*
- * Set up the wakeup GDT. We set these up as Big Real Mode,
- * that is, with limits set to 4 GB. At least the Lenovo
- * Thinkpad X61 is known to need this for the video BIOS
- * initialization quirk to work; this is likely to also
- * be the case for other laptops or integrated video devices.
- */
-
- /* GDT[0]: GDT self-pointer */
- header->wakeup_gdt[0] =
- (u64)(sizeof(header->wakeup_gdt) - 1) +
- ((u64)__pa(&header->wakeup_gdt) << 16);
- /* GDT[1]: big real mode-like code segment */
- header->wakeup_gdt[1] =
- GDT_ENTRY(0x809b, acpi_wakeup_address, 0xfffff);
- /* GDT[2]: big real mode-like data segment */
- header->wakeup_gdt[2] =
- GDT_ENTRY(0x8093, acpi_wakeup_address, 0xfffff);
-
#ifndef CONFIG_64BIT
store_gdt((struct desc_ptr *)&header->pmode_gdt);

@@ -91,7 +67,6 @@ int acpi_suspend_lowlevel(void)
header->pmode_cr3 = (u32)__pa(&initial_page_table);
saved_magic = 0x12345678;
#else /* CONFIG_64BIT */
- header->trampoline_segment = trampoline_address() >> 4;
#ifdef CONFIG_SMP
stack_start = (unsigned long)temp_stack + sizeof(temp_stack);
early_gdt_descr.address =
diff --git a/arch/x86/kernel/acpi/sleep.h b/arch/x86/kernel/acpi/sleep.h
index 416d4be..fcc1d83 100644
--- a/arch/x86/kernel/acpi/sleep.h
+++ b/arch/x86/kernel/acpi/sleep.h
@@ -2,7 +2,7 @@
* Variables and functions used by the code in sleep.c
*/

-#include <asm/trampoline.h>
+#include <asm/realmode.h>

extern unsigned long saved_video_mode;
extern long saved_magic;
diff --git a/arch/x86/kernel/acpi/wakeup_rm.S b/arch/x86/kernel/acpi/wakeup_rm.S
deleted file mode 100644
index 63b8ab5..0000000
--- a/arch/x86/kernel/acpi/wakeup_rm.S
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Wrapper script for the realmode binary as a transport object
- * before copying to low memory.
- */
-#include <asm/page_types.h>
-
- .section ".x86_trampoline","a"
- .balign PAGE_SIZE
- .globl acpi_wakeup_code
-acpi_wakeup_code:
- .incbin "arch/x86/kernel/acpi/realmode/wakeup.bin"
- .size acpi_wakeup_code, .-acpi_wakeup_code
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index 51ff186..c18f59d 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -14,7 +14,6 @@
#include <asm/sections.h>
#include <asm/e820.h>
#include <asm/page.h>
-#include <asm/trampoline.h>
#include <asm/apic.h>
#include <asm/io_apic.h>
#include <asm/bios_ebda.h>
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 3a3b779..037df57 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -24,7 +24,6 @@
#include <asm/sections.h>
#include <asm/kdebug.h>
#include <asm/e820.h>
-#include <asm/trampoline.h>
#include <asm/bios_ebda.h>

static void __init zap_identity_mappings(void)
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index ca470e4..f44d311 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -27,7 +27,6 @@
#include <asm/proto.h>
#include <asm/bios_ebda.h>
#include <asm/e820.h>
-#include <asm/trampoline.h>
#include <asm/setup.h>
#include <asm/smp.h>

diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 56e4124..7a14fec 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -73,7 +73,6 @@

#include <asm/mtrr.h>
#include <asm/apic.h>
-#include <asm/trampoline.h>
#include <asm/realmode.h>
#include <asm/e820.h>
#include <asm/mpspec.h>
@@ -918,7 +917,6 @@ void __init setup_arch(char **cmdline_p)
printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n",
max_pfn_mapped<<PAGE_SHIFT);

- setup_trampolines();
setup_real_mode();

init_gbpages();
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index 6410744..c136e23 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -32,7 +32,7 @@
#include <linux/mm.h>
#include <linux/tboot.h>

-#include <asm/trampoline.h>
+#include <asm/realmode.h>
#include <asm/processor.h>
#include <asm/bootparam.h>
#include <asm/pgtable.h>
@@ -201,7 +201,8 @@ static int tboot_setup_sleep(void)
add_mac_region(e820.map[i].addr, e820.map[i].size);
}

- tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address;
+ tboot->acpi_sinfo.kernel_s3_resume_vector =
+ real_mode_header.wakeup_start;

return 0;
}
diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c
deleted file mode 100644
index a73b610..0000000
--- a/arch/x86/kernel/trampoline.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <linux/io.h>
-#include <linux/memblock.h>
-
-#include <asm/trampoline.h>
-#include <asm/cacheflush.h>
-#include <asm/pgtable.h>
-
-unsigned char *x86_trampoline_base;
-
-void __init setup_trampolines(void)
-{
- phys_addr_t mem;
- size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start);
-
- /* Has to be in very low memory so we can execute real-mode AP code. */
- mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
- if (!mem)
- panic("Cannot allocate trampoline\n");
-
- x86_trampoline_base = __va(mem);
- memblock_reserve(mem, size);
-
- printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
- x86_trampoline_base, (unsigned long long)mem, size);
-
- memcpy(x86_trampoline_base, x86_trampoline_start, size);
-}
-
-/*
- * setup_trampolines() gets called very early, to guarantee the
- * availability of low memory. This is before the proper kernel page
- * tables are set up, so we cannot set page permissions in that
- * function. Thus, we use an arch_initcall instead.
- */
-static int __init configure_trampolines(void)
-{
- size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start);
-
- set_memory_x((unsigned long)x86_trampoline_base, size >> PAGE_SHIFT);
- return 0;
-}
-arch_initcall(configure_trampolines);
diff --git a/arch/x86/kernel/trampoline_32.S b/arch/x86/kernel/trampoline_32.S
deleted file mode 100644
index 451c0a7..0000000
--- a/arch/x86/kernel/trampoline_32.S
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *
- * Trampoline.S Derived from Setup.S by Linus Torvalds
- *
- * 4 Jan 1997 Michael Chastain: changed to gnu as.
- *
- * This is only used for booting secondary CPUs in SMP machine
- *
- * Entry: CS:IP point to the start of our code, we are
- * in real mode with no stack, but the rest of the
- * trampoline page to make our stack and everything else
- * is a mystery.
- *
- * We jump into arch/x86/kernel/head_32.S.
- *
- * On entry to trampoline_data, the processor is in real mode
- * with 16-bit addressing and 16-bit data. CS has some value
- * and IP is zero. Thus, data addresses need to be absolute
- * (no relocation) and are taken with regard to r_base.
- *
- * If you work on this file, check the object module with
- * objdump --reloc to make sure there are no relocation
- * entries except for:
- *
- * TYPE VALUE
- * R_386_32 startup_32_smp
- * R_386_32 boot_gdt
- */
-
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/segment.h>
-#include <asm/page_types.h>
-
-#ifdef CONFIG_SMP
-
- .section ".x86_trampoline","a"
- .balign PAGE_SIZE
- .code16
-
-ENTRY(trampoline_data)
-r_base = .
- wbinvd # Needed for NUMA-Q should be harmless for others
- mov %cs, %ax # Code and data in the same place
- mov %ax, %ds
-
- cli # We should be safe anyway
-
- movl $0xA5A5A5A5, trampoline_status - r_base
- # write marker for master knows we're running
-
- /* GDT tables in non default location kernel can be beyond 16MB and
- * lgdt will not be able to load the address as in real mode default
- * operand size is 16bit. Use lgdtl instead to force operand size
- * to 32 bit.
- */
-
- lidtl boot_idt_descr - r_base # load idt with 0, 0
- lgdtl boot_gdt_descr - r_base # load gdt with whatever is appropriate
-
- xor %ax, %ax
- inc %ax # protected mode (PE) bit
- lmsw %ax # into protected mode
- # flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
- ljmpl $__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET)
-
- # These need to be in the same 64K segment as the above;
- # hence we don't use the boot_gdt_descr defined in head.S
-boot_gdt_descr:
- .word __BOOT_DS + 7 # gdt limit
- .long boot_gdt - __PAGE_OFFSET # gdt base
-
-boot_idt_descr:
- .word 0 # idt limit = 0
- .long 0 # idt base = 0L
-
-ENTRY(trampoline_status)
- .long 0
-
-.globl trampoline_end
-trampoline_end:
-
-#endif /* CONFIG_SMP */
diff --git a/arch/x86/kernel/trampoline_64.S b/arch/x86/kernel/trampoline_64.S
deleted file mode 100644
index 09ff517..0000000
--- a/arch/x86/kernel/trampoline_64.S
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- *
- * Trampoline.S Derived from Setup.S by Linus Torvalds
- *
- * 4 Jan 1997 Michael Chastain: changed to gnu as.
- * 15 Sept 2005 Eric Biederman: 64bit PIC support
- *
- * Entry: CS:IP point to the start of our code, we are
- * in real mode with no stack, but the rest of the
- * trampoline page to make our stack and everything else
- * is a mystery.
- *
- * On entry to trampoline_data, the processor is in real mode
- * with 16-bit addressing and 16-bit data. CS has some value
- * and IP is zero. Thus, data addresses need to be absolute
- * (no relocation) and are taken with regard to r_base.
- *
- * With the addition of trampoline_level4_pgt this code can
- * now enter a 64bit kernel that lives at arbitrary 64bit
- * physical addresses.
- *
- * If you work on this file, check the object module with objdump
- * --full-contents --reloc to make sure there are no relocation
- * entries.
- */
-
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/pgtable_types.h>
-#include <asm/page_types.h>
-#include <asm/msr.h>
-#include <asm/segment.h>
-#include <asm/processor-flags.h>
-
- .section ".x86_trampoline","a"
- .balign PAGE_SIZE
- .code16
-
-ENTRY(trampoline_data)
-r_base = .
- cli # We should be safe anyway
- wbinvd
- mov %cs, %ax # Code and data in the same place
- mov %ax, %ds
- mov %ax, %es
- mov %ax, %ss
-
-
- movl $0xA5A5A5A5, trampoline_status - r_base
- # write marker for master knows we're running
-
- # Setup stack
- movw $(trampoline_stack_end - r_base), %sp
-
- call verify_cpu # Verify the cpu supports long mode
- testl %eax, %eax # Check for return code
- jnz no_longmode
-
- mov %cs, %ax
- movzx %ax, %esi # Find the 32bit trampoline location
- shll $4, %esi
-
- # Fixup the absolute vectors
- leal (startup_32 - r_base)(%esi), %eax
- movl %eax, startup_32_vector - r_base
- leal (startup_64 - r_base)(%esi), %eax
- movl %eax, startup_64_vector - r_base
- leal (tgdt - r_base)(%esi), %eax
- movl %eax, (tgdt + 2 - r_base)
-
- /*
- * GDT tables in non default location kernel can be beyond 16MB and
- * lgdt will not be able to load the address as in real mode default
- * operand size is 16bit. Use lgdtl instead to force operand size
- * to 32 bit.
- */
-
- lidtl tidt - r_base # load idt with 0, 0
- lgdtl tgdt - r_base # load gdt with whatever is appropriate
-
- mov $X86_CR0_PE, %ax # protected mode (PE) bit
- lmsw %ax # into protected mode
-
- # flush prefetch and jump to startup_32
- ljmpl *(startup_32_vector - r_base)
-
- .code32
- .balign 4
-startup_32:
- movl $__KERNEL_DS, %eax # Initialize the %ds segment register
- movl %eax, %ds
-
- movl $X86_CR4_PAE, %eax
- movl %eax, %cr4 # Enable PAE mode
-
- # Setup trampoline 4 level pagetables
- leal (trampoline_level4_pgt - r_base)(%esi), %eax
- movl %eax, %cr3
-
- movl $MSR_EFER, %ecx
- movl $(1 << _EFER_LME), %eax # Enable Long Mode
- xorl %edx, %edx
- wrmsr
-
- # Enable paging and in turn activate Long Mode
- # Enable protected mode
- movl $(X86_CR0_PG | X86_CR0_PE), %eax
- movl %eax, %cr0
-
- /*
- * At this point we're in long mode but in 32bit compatibility mode
- * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
- * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
- * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
- */
- ljmp *(startup_64_vector - r_base)(%esi)
-
- .code64
- .balign 4
-startup_64:
- # Now jump into the kernel using virtual addresses
- movq $secondary_startup_64, %rax
- jmp *%rax
-
- .code16
-no_longmode:
- hlt
- jmp no_longmode
-#include "verify_cpu.S"
-
- .balign 4
- # Careful these need to be in the same 64K segment as the above;
-tidt:
- .word 0 # idt limit = 0
- .word 0, 0 # idt base = 0L
-
- # Duplicate the global descriptor table
- # so the kernel can live anywhere
- .balign 4
-tgdt:
- .short tgdt_end - tgdt # gdt limit
- .long tgdt - r_base
- .short 0
- .quad 0x00cf9b000000ffff # __KERNEL32_CS
- .quad 0x00af9b000000ffff # __KERNEL_CS
- .quad 0x00cf93000000ffff # __KERNEL_DS
-tgdt_end:
-
- .balign 4
-startup_32_vector:
- .long startup_32 - r_base
- .word __KERNEL32_CS, 0
-
- .balign 4
-startup_64_vector:
- .long startup_64 - r_base
- .word __KERNEL_CS, 0
-
- .balign 4
-ENTRY(trampoline_status)
- .long 0
-
-trampoline_stack:
- .org 0x1000
-trampoline_stack_end:
-ENTRY(trampoline_level4_pgt)
- .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
- .fill 510,8,0
- .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
-
-ENTRY(trampoline_end)
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 0f703f1..22a1530 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -197,18 +197,6 @@ SECTIONS

INIT_DATA_SECTION(16)

- /*
- * Code and data for a variety of lowlevel trampolines, to be
- * copied into base memory (< 1 MiB) during initialization.
- * Since it is copied early, the main copy can be discarded
- * afterwards.
- */
- .x86_trampoline : AT(ADDR(.x86_trampoline) - LOAD_OFFSET) {
- x86_trampoline_start = .;
- *(.x86_trampoline)
- x86_trampoline_end = .;
- }
-
.x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
__x86_cpu_dev_start = .;
*(.x86_cpu_dev.init)
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 56ec64f..2432acb 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -14,9 +14,13 @@ always := realmode.bin
realmode-y += header.o
realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-y += trampoline_$(BITS).o
+realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o

targets += $(realmode-y)

+$(obj)/wakeup/wakeup.o: FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/wakeup $@
+
REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y))

sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p'
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index a979004..730b131 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -27,4 +27,9 @@ ENTRY(real_mode_header)
.long pa_level3_ident_pgt
.long pa_level3_kernel_pgt
#endif
+ /* ACPI sleep */
+#ifdef CONFIG_ACPI_SLEEP
+ .long pa_wakeup_start
+ .long pa_wakeup_header
+#endif
END(real_mode_header)
diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S
index c5b8a4f..91b83ea 100644
--- a/arch/x86/realmode/rm/realmode.lds.S
+++ b/arch/x86/realmode/rm/realmode.lds.S
@@ -25,6 +25,10 @@ SECTIONS
.rodata : {
*(.rodata)
*(.rodata.*)
+ . = ALIGN(16);
+ video_cards = .;
+ *(.videocards)
+ video_cards_end = .;
}

. = ALIGN(PAGE_SIZE);
diff --git a/arch/x86/realmode/rm/wakeup/.gitignore b/arch/x86/realmode/rm/wakeup/.gitignore
new file mode 100644
index 0000000..58f1f48
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/.gitignore
@@ -0,0 +1,3 @@
+wakeup.bin
+wakeup.elf
+wakeup.lds
diff --git a/arch/x86/realmode/rm/wakeup/Makefile b/arch/x86/realmode/rm/wakeup/Makefile
new file mode 100644
index 0000000..4c85332
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/Makefile
@@ -0,0 +1,33 @@
+#
+# arch/x86/kernel/acpi/realmode/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+always := wakeup.o
+
+wakeup-y += wakeup_asm.o wakemain.o video-mode.o
+wakeup-y += copy.o bioscall.o regs.o
+
+# The link order of the video-*.o modules can matter. In particular,
+# video-vga.o *must* be listed first, followed by video-vesa.o.
+# Hardware-specific drivers should follow in the order they should be
+# probed, and video-bios.o should typically be last.
+wakeup-y += video-vga.o
+wakeup-y += video-vesa.o
+wakeup-y += video-bios.o
+
+targets += $(wakeup-y)
+
+WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
+
+LDFLAGS_wakeup.o := -m elf_i386 -r
+$(obj)/wakeup.o: $(WAKEUP_OBJS) FORCE
+ $(call if_changed,ld)
+
+bootsrc := $(src)/../../../boot
+
+ccflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc)
+asflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc)
diff --git a/arch/x86/realmode/rm/wakeup/bioscall.S b/arch/x86/realmode/rm/wakeup/bioscall.S
new file mode 100644
index 0000000..f51eb0b
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/bioscall.S
@@ -0,0 +1 @@
+#include "../../../boot/bioscall.S"
diff --git a/arch/x86/realmode/rm/wakeup/copy.S b/arch/x86/realmode/rm/wakeup/copy.S
new file mode 100644
index 0000000..dc59ebe
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/copy.S
@@ -0,0 +1 @@
+#include "../../../boot/copy.S"
diff --git a/arch/x86/realmode/rm/wakeup/regs.c b/arch/x86/realmode/rm/wakeup/regs.c
new file mode 100644
index 0000000..6206033
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/regs.c
@@ -0,0 +1 @@
+#include "../../../boot/regs.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-bios.c b/arch/x86/realmode/rm/wakeup/video-bios.c
new file mode 100644
index 0000000..7deabc1
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/video-bios.c
@@ -0,0 +1 @@
+#include "../../../boot/video-bios.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-mode.c b/arch/x86/realmode/rm/wakeup/video-mode.c
new file mode 100644
index 0000000..328ad20
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/video-mode.c
@@ -0,0 +1 @@
+#include "../../../boot/video-mode.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-vesa.c b/arch/x86/realmode/rm/wakeup/video-vesa.c
new file mode 100644
index 0000000..9dbb967
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/video-vesa.c
@@ -0,0 +1 @@
+#include "../../../boot/video-vesa.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-vga.c b/arch/x86/realmode/rm/wakeup/video-vga.c
new file mode 100644
index 0000000..bcc8125
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/video-vga.c
@@ -0,0 +1 @@
+#include "../../../boot/video-vga.c"
diff --git a/arch/x86/realmode/rm/wakeup/wakemain.c b/arch/x86/realmode/rm/wakeup/wakemain.c
new file mode 100644
index 0000000..91405d5
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/wakemain.c
@@ -0,0 +1,82 @@
+#include "wakeup.h"
+#include "boot.h"
+
+static void udelay(int loops)
+{
+ while (loops--)
+ io_delay(); /* Approximately 1 us */
+}
+
+static void beep(unsigned int hz)
+{
+ u8 enable;
+
+ if (!hz) {
+ enable = 0x00; /* Turn off speaker */
+ } else {
+ u16 div = 1193181/hz;
+
+ outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */
+ io_delay();
+ outb(div, 0x42); /* LSB of counter */
+ io_delay();
+ outb(div >> 8, 0x42); /* MSB of counter */
+ io_delay();
+
+ enable = 0x03; /* Turn on speaker */
+ }
+ inb(0x61); /* Dummy read of System Control Port B */
+ io_delay();
+ outb(enable, 0x61); /* Enable timer 2 output to speaker */
+ io_delay();
+}
+
+#define DOT_HZ 880
+#define DASH_HZ 587
+#define US_PER_DOT 125000
+
+/* Okay, this is totally silly, but it's kind of fun. */
+static void send_morse(const char *pattern)
+{
+ char s;
+
+ while ((s = *pattern++)) {
+ switch (s) {
+ case '.':
+ beep(DOT_HZ);
+ udelay(US_PER_DOT);
+ beep(0);
+ udelay(US_PER_DOT);
+ break;
+ case '-':
+ beep(DASH_HZ);
+ udelay(US_PER_DOT * 3);
+ beep(0);
+ udelay(US_PER_DOT);
+ break;
+ default: /* Assume it's a space */
+ udelay(US_PER_DOT * 3);
+ break;
+ }
+ }
+}
+
+void main(void)
+{
+ /* Kill machine if structures are wrong */
+ if (wakeup_header.real_magic != 0x12345678)
+ while (1)
+ ;
+
+ if (wakeup_header.realmode_flags & 4)
+ send_morse("...-");
+
+ if (wakeup_header.realmode_flags & 1)
+ asm volatile("lcallw $0xc000,$3");
+
+ if (wakeup_header.realmode_flags & 2) {
+ /* Need to call BIOS */
+ probe_cards(0);
+ set_mode(wakeup_header.video_mode);
+ }
+}
diff --git a/arch/x86/realmode/rm/wakeup/wakeup.h b/arch/x86/realmode/rm/wakeup/wakeup.h
new file mode 100644
index 0000000..2dfaf06
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/wakeup.h
@@ -0,0 +1,41 @@
+/*
+ * Definitions for the wakeup data structure at the head of the
+ * wakeup code.
+ */
+
+#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
+#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+
+/* This must match data at wakeup.S */
+struct wakeup_header {
+ u16 video_mode; /* Video mode number */
+ u32 pmode_entry; /* Protected mode resume point, 32-bit only */
+ u16 pmode_cs;
+ u32 pmode_cr0; /* Protected mode cr0 */
+ u32 pmode_cr3; /* Protected mode cr3 */
+ u32 pmode_cr4; /* Protected mode cr4 */
+ u32 pmode_efer_low; /* Protected mode EFER */
+ u32 pmode_efer_high;
+ u64 pmode_gdt;
+ u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */
+ u32 pmode_misc_en_high;
+ u32 pmode_behavior; /* Wakeup routine behavior flags */
+ u32 realmode_flags;
+ u32 real_magic;
+ u32 signature; /* To check we have correct structure */
+} __attribute__((__packed__));
+
+extern struct wakeup_header wakeup_header;
+#endif
+
+#define WAKEUP_HEADER_OFFSET 8
+#define WAKEUP_HEADER_SIGNATURE 0x51ee1111
+#define WAKEUP_END_SIGNATURE 0x65a22c82
+
+/* Wakeup behavior bits */
+#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0
+
+#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
new file mode 100644
index 0000000..b61126c
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
@@ -0,0 +1,189 @@
+/*
+ * ACPI wakeup real mode startup stub
+ */
+#include <asm/segment.h>
+#include <asm/msr-index.h>
+#include <asm/page_types.h>
+#include <asm/pgtable_types.h>
+#include <asm/processor-flags.h>
+#include "wakeup.h"
+
+ .code16
+
+/* This should match the structure in wakeup.h */
+ .section ".data", "aw"
+ .globl wakeup_header
+wakeup_header:
+video_mode: .short 0 /* Video mode number */
+pmode_entry: .long 0
+pmode_cs: .short __KERNEL_CS
+pmode_cr0: .long 0 /* Saved %cr0 */
+pmode_cr3: .long 0 /* Saved %cr3 */
+pmode_cr4: .long 0 /* Saved %cr4 */
+pmode_efer: .quad 0 /* Saved EFER */
+pmode_gdt: .quad 0
+pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
+pmode_behavior: .long 0 /* Wakeup behavior flags */
+realmode_flags: .long 0
+real_magic: .long 0
+signature: .long WAKEUP_HEADER_SIGNATURE
+ .size wakeup_header, .-wakeup_header
+
+ .text
+ .code16
+ .globl wakeup_start
+wakeup_start:
+ cli
+ cld
+
+ .byte 0xea /* ljmpw */
+ .word 3f
+ .word real_mode_seg
+3:
+ /* Apparently some dimwit BIOS programmers don't know how to
+ program a PM to RM transition, and we might end up here with
+ junk in the data segment descriptor registers. The only way
+ to repair that is to go into PM and fix it ourselves... */
+ movw $16, %cx
+ lgdtl %cs:wakeup_gdt
+ movl %cr0, %eax
+ orb $X86_CR0_PE, %al
+ movl %eax, %cr0
+ ljmpw $8, $2f
+2:
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+ movw %cx, %fs
+ movw %cx, %gs
+
+ andb $~X86_CR0_PE, %al
+ movl %eax, %cr0
+ .byte 0xea /* ljmpw */
+ .word 3f
+ .word real_mode_seg
+3:
+ /* Set up segments */
+ movw %cs, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ lidtl wakeup_idt
+
+ movl $wakeup_stack_end, %esp
+
+ /* Clear the EFLAGS */
+ pushl $0
+ popfl
+
+ /* Check header signature... */
+ movl signature, %eax
+ cmpl $WAKEUP_HEADER_SIGNATURE, %eax
+ jne bogus_real_magic
+
+ /* Check we really have everything... */
+ movl end_signature, %eax
+ cmpl $WAKEUP_END_SIGNATURE, %eax
+ jne bogus_real_magic
+
+ /* Call the C code */
+ calll main
+
+ /* Restore MISC_ENABLE before entering protected mode, in case
+ BIOS decided to clear XD_DISABLE during S3. */
+ movl pmode_behavior, %eax
+ btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
+ jnc 1f
+
+ movl pmode_misc_en, %eax
+ movl pmode_misc_en + 4, %edx
+ movl $MSR_IA32_MISC_ENABLE, %ecx
+ wrmsr
+1:
+
+ /* Do any other stuff... */
+
+#ifndef CONFIG_64BIT
+ /* This could also be done in C code... */
+ movl pmode_cr3, %eax
+ movl %eax, %cr3
+
+ movl pmode_cr4, %ecx
+ jecxz 1f
+ movl %ecx, %cr4
+1:
+ movl pmode_efer, %eax
+ movl pmode_efer + 4, %edx
+ movl %eax, %ecx
+ orl %edx, %ecx
+ jz 1f
+ movl $MSR_EFER, %ecx
+ wrmsr
+1:
+
+ lgdtl pmode_gdt
+
+ /* This really couldn't... */
+ movl pmode_cr0, %eax
+ movl %eax, %cr0
+ ljmpl *pmode_entry
+#else
+ jmp trampoline_data
+#endif
+
+bogus_real_magic:
+1:
+ hlt
+ jmp 1b
+
+ .section ".rodata","a"
+
+ /*
+ * Set up the wakeup GDT. We set these up as Big Real Mode,
+ * that is, with limits set to 4 GB. At least the Lenovo
+ * Thinkpad X61 is known to need this for the video BIOS
+ * initialization quirk to work; this is likely to also
+ * be the case for other laptops or integrated video devices.
+ */
+
+ .globl wakeup_gdt
+ .balign 16
+wakeup_gdt:
+ .word 3*8-1 /* Self-descriptor */
+ .long pa_wakeup_gdt
+ .word 0
+
+ .word 0xffff /* 16-bit code segment @ real_mode_base */
+ .long 0x9b000000 + pa_real_mode_base
+ .word 0x008f /* big real mode */
+
+ .word 0xffff /* 16-bit data segment @ real_mode_base */
+ .long 0x93000000 + pa_real_mode_base
+ .word 0x008f /* big real mode */
+ .size wakeup_gdt, .-wakeup_gdt
+
+ .data
+ .balign 8
+
+ /* This is the standard real-mode IDT */
+wakeup_idt:
+ .word 0xffff /* limit */
+ .long 0 /* address */
+ .word 0
+
+ .globl HEAP, heap_end
+HEAP:
+ .long wakeup_heap
+heap_end:
+ .long wakeup_stack
+
+ .bss
+wakeup_heap:
+ .space 2048
+wakeup_stack:
+ .space 2048
+wakeup_stack_end:
+
+ .section ".signature","a"
+end_signature:
+ .long WAKEUP_END_SIGNATURE
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 1d661b5..83869ab 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -25,6 +25,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>

+#include <asm/realmode.h>
+
#include "internal.h"
#include "sleep.h"

@@ -81,13 +83,13 @@ static struct notifier_block tts_notifier = {
static int acpi_sleep_prepare(u32 acpi_state)
{
#ifdef CONFIG_ACPI_SLEEP
+ unsigned long wakeup_pa = real_mode_header.wakeup_start;
/* do we have a wakeup address for S2 and S3? */
if (acpi_state == ACPI_STATE_S3) {
- if (!acpi_wakeup_address) {
+ if (!wakeup_pa)
return -EFAULT;
- }
acpi_set_firmware_waking_vector(
- (acpi_physical_address)acpi_wakeup_address);
+ (acpi_physical_address)wakeup_pa);

}
ACPI_FLUSH_CPU_CACHE();
--
1.7.9.5

2012-05-08 18:23:56

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 14/23] x86, realmode: Replace open-coded ljmpw with a macro

From: "H. Peter Anvin" <[email protected]>

We cannot code an ljmpw to the real-mode segment directly, because gas
refuses to assemble an ljmp with a symbolic segment. Instead of
open-coding it everywhere, define a macro and use it for this case.

This is specifically an ljmpw from a 16-bit segment. This is okay, as
one should never enter real mode from a 32-bit segment: if one do, the
CPU ends up in a bizarre (and useless) mode sometimes called "unreal
mode" where segments behave like real mode but the default address and
operand sizes is 32 bits.

Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/realmode/rm/realmode.h | 16 ++++++++++++++++
arch/x86/realmode/rm/reboot_32.S | 6 ++----
arch/x86/realmode/rm/trampoline_32.S | 5 ++---
arch/x86/realmode/rm/trampoline_64.S | 5 ++---
arch/x86/realmode/rm/wakeup/wakeup_asm.S | 9 +++------
5 files changed, 25 insertions(+), 16 deletions(-)
create mode 100644 arch/x86/realmode/rm/realmode.h

diff --git a/arch/x86/realmode/rm/realmode.h b/arch/x86/realmode/rm/realmode.h
new file mode 100644
index 0000000..15ab633
--- /dev/null
+++ b/arch/x86/realmode/rm/realmode.h
@@ -0,0 +1,16 @@
+#ifndef ARCH_X86_REALMODE_RM_REALMODE_H
+#define ARCH_X86_REALMODE_RM_REALMODE_H
+
+#ifdef __ASSEMBLY__
+
+/*
+ * 16-bit ljmpw to the real_mode_seg
+ *
+ * This must be open-coded since gas will choke on using a
+ * relocatable symbol for the segment portion.
+ */
+#define LJMPW_RM(to) .byte 0xea ; .word (to), real_mode_seg
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* ARCH_X86_REALMODE_RM_REALMODE_H */
diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
index 83803c2..e90f8c4 100644
--- a/arch/x86/realmode/rm/reboot_32.S
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -2,6 +2,7 @@
#include <linux/init.h>
#include <asm/segment.h>
#include <asm/page_types.h>
+#include "realmode.h"

/*
* The following code and data reboots the machine by switching to real
@@ -82,10 +83,7 @@ machine_real_restart_asm16:
2:
andb $0x10, %dl
movl %edx, %cr0
- .byte 0xea /* ljmpw */
- .word 3f /* Offset */
- .word real_mode_seg /* Segment */
-
+ LJMPW_RM(3f)
3:
testb $0, %al
jz bios
diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 1315ef4..279f82e 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -29,6 +29,7 @@
#include <linux/init.h>
#include <asm/segment.h>
#include <asm/page_types.h>
+#include "realmode.h"

.text
.code16
@@ -38,9 +39,7 @@
trampoline_data:
wbinvd # Needed for NUMA-Q should be harmless for others

- .byte 0xea # ljmpw
- .word 1f # Offset
- .word real_mode_seg # Segment
+ LJMPW_RM(1f)
1:
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 77b72b4..7459c52 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -31,6 +31,7 @@
#include <asm/msr.h>
#include <asm/segment.h>
#include <asm/processor-flags.h>
+#include "realmode.h"

.text
.balign PAGE_SIZE
@@ -40,9 +41,7 @@ ENTRY(trampoline_data)
cli # We should be safe anyway
wbinvd

- .byte 0xea # ljmpw
- .word 1f # Offset
- .word real_mode_seg # Segment
+ LJMPW_RM(1f)
1:
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
index 4c5c5f2..8064e1c 100644
--- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
@@ -6,6 +6,7 @@
#include <asm/page_types.h>
#include <asm/pgtable_types.h>
#include <asm/processor-flags.h>
+#include "../realmode.h"
#include "wakeup.h"

.code16
@@ -36,9 +37,7 @@ wakeup_start:
cli
cld

- .byte 0xea /* ljmpw */
- .word 3f
- .word real_mode_seg
+ LJMPW_RM(3f)
3:
/* Apparently some dimwit BIOS programmers don't know how to
program a PM to RM transition, and we might end up here with
@@ -59,9 +58,7 @@ wakeup_start:

andb $~X86_CR0_PE, %al
movl %eax, %cr0
- .byte 0xea /* ljmpw */
- .word 3f
- .word real_mode_seg
+ LJMPW_RM(3f)
3:
/* Set up segments */
movw %cs, %ax
--
1.7.9.5

2012-05-08 18:24:08

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 23/23] x86, realmode: read cr4 and EFER from kernel for 64-bit trampoline

This patch changes 64-bit trampoline so that CR4 and
EFER are provided by the kernel instead of using fixed
values.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/include/asm/processor.h | 7 ++++++-
arch/x86/include/asm/realmode.h | 8 ++++++--
arch/x86/kernel/realmode.c | 8 ++++++++
arch/x86/kernel/setup.c | 2 ++
arch/x86/realmode/rm/header.S | 1 +
arch/x86/realmode/rm/trampoline_64.S | 32 +++++++-----------------------
arch/x86/realmode/rm/trampoline_common.S | 19 ++++++++++++++++++
7 files changed, 49 insertions(+), 28 deletions(-)

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 4fa7dcc..404583c 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -544,13 +544,16 @@ static inline void load_sp0(struct tss_struct *tss,
* enable), so that any CPU's that boot up
* after us can get the correct flags.
*/
-extern unsigned long mmu_cr4_features;
+extern unsigned long mmu_cr4_features;
+extern u32 *trampoline_cr4_features;

static inline void set_in_cr4(unsigned long mask)
{
unsigned long cr4;

mmu_cr4_features |= mask;
+ if (trampoline_cr4_features)
+ *trampoline_cr4_features = mmu_cr4_features;
cr4 = read_cr4();
cr4 |= mask;
write_cr4(cr4);
@@ -561,6 +564,8 @@ static inline void clear_in_cr4(unsigned long mask)
unsigned long cr4;

mmu_cr4_features &= ~mask;
+ if (trampoline_cr4_features)
+ *trampoline_cr4_features = mmu_cr4_features;
cr4 = read_cr4();
cr4 &= ~mask;
write_cr4(cr4);
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index 1421eed..937dc60 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -24,18 +24,22 @@ struct real_mode_header {
#ifdef CONFIG_X86_32
u32 machine_real_restart_asm;
#endif
-} __attribute__((__packed__));
+};

/* This must match data at trampoline_32/64.S */
struct trampoline_header {
#ifdef CONFIG_X86_32
u32 start;
+ u16 gdt_pad;
u16 gdt_limit;
u32 gdt_base;
#else
u64 start;
+ u32 cr4;
+ u32 efer_low;
+ u32 efer_high;
#endif
-} __attribute__((__packed__));
+};

extern struct real_mode_header *real_mode_header;
extern unsigned char real_mode_blob_end[];
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index 712fba8..66ac276 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -6,6 +6,7 @@
#include <asm/realmode.h>

struct real_mode_header *real_mode_header;
+u32 *trampoline_cr4_features;

void __init setup_real_mode(void)
{
@@ -64,7 +65,14 @@ void __init setup_real_mode(void)
trampoline_header->gdt_limit = __BOOT_DS + 7;
trampoline_header->gdt_base = __pa(boot_gdt);
#else
+ if (rdmsr_safe(MSR_EFER, &trampoline_header->efer_low,
+ &trampoline_header->efer_high))
+ BUG();
+
trampoline_header->start = (u64) secondary_startup_64;
+ trampoline_cr4_features = &trampoline_header->cr4;
+ *trampoline_cr4_features = read_cr4();
+
trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE;
trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE;
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 7a14fec..efcf305 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -975,6 +975,8 @@ void __init setup_arch(char **cmdline_p)
if (boot_cpu_data.cpuid_level >= 0) {
/* A CPU has %cr4 if and only if it has CPUID */
mmu_cr4_features = read_cr4();
+ if (trampoline_cr4_features)
+ *trampoline_cr4_features = mmu_cr4_features;
}

#ifdef CONFIG_X86_32
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index b4c3263..4612d53 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -9,6 +9,7 @@

.section ".header", "a"

+ .balign 16
GLOBAL(real_mode_header)
.long pa_text_start
.long pa_ro_end
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index c4a60d1..023a925 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -34,9 +34,9 @@
#include "realmode.h"

.text
- .balign PAGE_SIZE
.code16

+ .balign PAGE_SIZE
ENTRY(trampoline_start)
cli # We should be safe anyway
wbinvd
@@ -65,8 +65,8 @@ ENTRY(trampoline_start)
* to 32 bit.
*/

- lidtl tidt # load idt with 0, 0
- lgdtl tgdt # load gdt with whatever is appropriate
+ lidtl tr_idt # load idt with 0, 0
+ lgdtl tr_gdt # load gdt with whatever is appropriate

movw $__KERNEL_DS, %dx # Data segment descriptor

@@ -93,16 +93,17 @@ ENTRY(startup_32)
movl %edx, %fs
movl %edx, %gs

- movl $X86_CR4_PAE, %eax
+ movl pa_tr_cr4, %eax
movl %eax, %cr4 # Enable PAE mode

# Setup trampoline 4 level pagetables
movl $pa_trampoline_pgd, %eax
movl %eax, %cr3

+ # Set up EFER
+ movl pa_tr_efer, %eax
+ movl pa_tr_efer + 4, %edx
movl $MSR_EFER, %ecx
- movl $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax # Enable Long Mode
- xorl %edx, %edx
wrmsr

# Enable paging and in turn activate Long Mode
@@ -124,23 +125,4 @@ ENTRY(startup_64)
# Now jump into the kernel using virtual addresses
jmpq *tr_start(%rip)

- .section ".rodata","a"
- .balign 16
-tidt:
- .word 0 # idt limit = 0
- .word 0, 0 # idt base = 0L
-
- # Duplicate the global descriptor table
- # so the kernel can live anywhere
- .balign 16
- .globl tgdt
-tgdt:
- .short tgdt_end - tgdt - 1 # gdt limit
- .long pa_tgdt
- .short 0
- .quad 0x00cf9b000000ffff # __KERNEL32_CS
- .quad 0x00af9b000000ffff # __KERNEL_CS
- .quad 0x00cf93000000ffff # __KERNEL_DS
-tgdt_end:
-
#include "trampoline_common.S"
diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S
index c3f951c..cac444b 100644
--- a/arch/x86/realmode/rm/trampoline_common.S
+++ b/arch/x86/realmode/rm/trampoline_common.S
@@ -1,5 +1,20 @@
.section ".rodata","a"

+#ifdef CONFIG_X86_64
+ # Duplicate the global descriptor table
+ # so the kernel can live anywhere
+ .balign 16
+ .globl tr_gdt
+tr_gdt:
+ .short tr_gdt_end - tr_gdt - 1 # gdt limit
+ .long pa_tr_gdt
+ .short 0
+ .quad 0x00cf9b000000ffff # __KERNEL32_CS
+ .quad 0x00af9b000000ffff # __KERNEL_CS
+ .quad 0x00cf93000000ffff # __KERNEL_DS
+tr_gdt_end:
+#endif
+
.balign 4
tr_idt: .fill 1, 6, 0

@@ -8,12 +23,16 @@ tr_idt: .fill 1, 6, 0
.balign 4
GLOBAL(trampoline_status) .space 4

+ .balign 8
GLOBAL(trampoline_header)
#ifdef CONFIG_X86_32
tr_start: .space 4
+ tr_gdt_pad: .space 2
tr_gdt: .space 6
#else
tr_start: .space 8
+ GLOBAL(tr_cr4) .space 4
+ GLOBAL(tr_efer) .space 8
#endif
END(trampoline_header)

--
1.7.9.5

2012-05-08 18:24:04

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 18/23] x86, realmode: don't copy real_mode_header

Replaced copying of real_mode_header with a pointer
to beginning of RM memory.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/include/asm/realmode.h | 5 ++-
arch/x86/kernel/acpi/sleep.c | 2 +-
arch/x86/kernel/realmode.c | 57 +++++++++++++++--------------------
arch/x86/kernel/reboot.c | 2 +-
arch/x86/kernel/smpboot.c | 4 +--
arch/x86/kernel/tboot.c | 2 +-
arch/x86/realmode/rm/header.S | 1 -
arch/x86/realmode/rm/realmode.lds.S | 1 -
arch/x86/realmode/rmpiggy.S | 2 ++
drivers/acpi/sleep.c | 2 +-
10 files changed, 35 insertions(+), 43 deletions(-)

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index 1bfc74d..d3ae49f 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -8,7 +8,6 @@
struct real_mode_header {
u32 text_start;
u32 ro_end;
- u32 end;
/* reboot */
#ifdef CONFIG_X86_32
u32 machine_real_restart_asm;
@@ -30,8 +29,8 @@ struct real_mode_header {
#endif
} __attribute__((__packed__));

-extern struct real_mode_header real_mode_header;
-extern unsigned char *real_mode_base;
+extern struct real_mode_header *real_mode_header;
+extern unsigned char real_mode_blob_end[];

extern unsigned long init_rsp;
extern unsigned long initial_code;
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 9ad1b79..5250475 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -34,7 +34,7 @@ static char temp_stack[4096];
int acpi_suspend_lowlevel(void)
{
struct wakeup_header *header =
- (struct wakeup_header *) __va(real_mode_header.wakeup_header);
+ (struct wakeup_header *) __va(real_mode_header->wakeup_header);

if (header->signature != WAKEUP_HEADER_SIGNATURE) {
printk(KERN_ERR "wakeup header does not match\n");
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index e7bf82a..632c810 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -5,8 +5,7 @@
#include <asm/pgtable.h>
#include <asm/realmode.h>

-unsigned char *real_mode_base;
-struct real_mode_header real_mode_header;
+struct real_mode_header *real_mode_header;

void __init setup_real_mode(void)
{
@@ -17,33 +16,32 @@ void __init setup_real_mode(void)
u32 *ptr;
u16 *seg;
int i;
+ unsigned char *base;

- struct real_mode_header *header =
- (struct real_mode_header *) real_mode_blob;
-
- size_t size = PAGE_ALIGN(header->end);
+ size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);

/* Has to be in very low memory so we can execute real-mode AP code. */
mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
if (!mem)
panic("Cannot allocate trampoline\n");

- real_mode_base = __va(mem);
+ base = __va(mem);
memblock_reserve(mem, size);
+ real_mode_header = (struct real_mode_header *) base;

printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
- real_mode_base, (unsigned long long)mem, size);
+ base, (unsigned long long)mem, size);

- memcpy(real_mode_base, real_mode_blob, size);
+ memcpy(base, real_mode_blob, size);

- real_mode_seg = __pa(real_mode_base) >> 4;
+ real_mode_seg = __pa(base) >> 4;
rel = (u32 *) real_mode_relocs;

/* 16-bit segment relocations. */
count = rel[0];
rel = &rel[1];
for (i = 0; i < count; i++) {
- seg = (u16 *) (real_mode_base + rel[i]);
+ seg = (u16 *) (base + rel[i]);
*seg = real_mode_seg;
}

@@ -51,25 +49,21 @@ void __init setup_real_mode(void)
count = rel[i];
rel = &rel[i + 1];
for (i = 0; i < count; i++) {
- ptr = (u32 *) (real_mode_base + rel[i]);
- *ptr += __pa(real_mode_base);
+ ptr = (u32 *) (base + rel[i]);
+ *ptr += __pa(base);
}

- /* Copied header will contain relocated physical addresses. */
- memcpy(&real_mode_header, real_mode_base,
- sizeof(struct real_mode_header));
-
#ifdef CONFIG_X86_32
- *((u32 *)__va(real_mode_header.startup_32_smp)) = __pa(startup_32_smp);
- *((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt);
+ *((u32 *)__va(real_mode_header->startup_32_smp)) = __pa(startup_32_smp);
+ *((u32 *)__va(real_mode_header->boot_gdt)) = __pa(boot_gdt);
#else
- *((u64 *) __va(real_mode_header.startup_64_smp)) =
+ *((u64 *) __va(real_mode_header->startup_64_smp)) =
(u64)secondary_startup_64;

- *((u64 *) __va(real_mode_header.level3_ident_pgt)) =
+ *((u64 *) __va(real_mode_header->level3_ident_pgt)) =
__pa(level3_ident_pgt) + _KERNPG_TABLE;

- *((u64 *) __va(real_mode_header.level3_kernel_pgt)) =
+ *((u64 *) __va(real_mode_header->level3_kernel_pgt)) =
__pa(level3_kernel_pgt) + _KERNPG_TABLE;
#endif
}
@@ -82,23 +76,22 @@ void __init setup_real_mode(void)
*/
static int __init set_real_mode_permissions(void)
{
- size_t all_size =
- PAGE_ALIGN(real_mode_header.end) -
- __pa(real_mode_base);
+ unsigned char *base = (unsigned char *) real_mode_header;
+ size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);

size_t ro_size =
- PAGE_ALIGN(real_mode_header.ro_end) -
- __pa(real_mode_base);
+ PAGE_ALIGN(real_mode_header->ro_end) -
+ __pa(base);

size_t text_size =
- PAGE_ALIGN(real_mode_header.ro_end) -
- real_mode_header.text_start;
+ PAGE_ALIGN(real_mode_header->ro_end) -
+ real_mode_header->text_start;

unsigned long text_start =
- (unsigned long) __va(real_mode_header.text_start);
+ (unsigned long) __va(real_mode_header->text_start);

- set_memory_nx((unsigned long) real_mode_base, all_size >> PAGE_SHIFT);
- set_memory_ro((unsigned long) real_mode_base, ro_size >> PAGE_SHIFT);
+ set_memory_nx((unsigned long) base, size >> PAGE_SHIFT);
+ set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT);
set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT);

return 0;
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 050eff2..658f856 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -336,7 +336,7 @@ core_initcall(reboot_init);
void machine_real_restart(unsigned int type)
{
void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int))
- real_mode_header.machine_real_restart_asm;
+ real_mode_header->machine_real_restart_asm;

local_irq_disable();

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index c7971ea..b8c0661 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -665,9 +665,9 @@ static void __cpuinit announce_cpu(int cpu, int apicid)
static int __cpuinit do_boot_cpu(int apicid, int cpu)
{
volatile u32 *trampoline_status =
- (volatile u32 *) __va(real_mode_header.trampoline_status);
+ (volatile u32 *) __va(real_mode_header->trampoline_status);
/* start_ip had better be page-aligned! */
- unsigned long start_ip = real_mode_header.trampoline_data;
+ unsigned long start_ip = real_mode_header->trampoline_data;

unsigned long boot_error = 0;
int timeout;
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index c136e23..65adda4 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -202,7 +202,7 @@ static int tboot_setup_sleep(void)
}

tboot->acpi_sinfo.kernel_s3_resume_vector =
- real_mode_header.wakeup_start;
+ real_mode_header->wakeup_start;

return 0;
}
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index a91ec8f..c83005c 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -12,7 +12,6 @@
GLOBAL(real_mode_header)
.long pa_text_start
.long pa_ro_end
- .long pa_end
#ifdef CONFIG_X86_32
.long pa_machine_real_restart_asm
#endif
diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S
index 4d4afca..86b2e8d 100644
--- a/arch/x86/realmode/rm/realmode.lds.S
+++ b/arch/x86/realmode/rm/realmode.lds.S
@@ -65,7 +65,6 @@ SECTIONS
.signature : {
*(.signature)
}
- pa_end = .;

/DISCARD/ : {
*(.note*)
diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S
index fd72a99..204c6ec 100644
--- a/arch/x86/realmode/rmpiggy.S
+++ b/arch/x86/realmode/rmpiggy.S
@@ -13,6 +13,8 @@ GLOBAL(real_mode_blob)
.incbin "arch/x86/realmode/rm/realmode.bin"
END(real_mode_blob)

+GLOBAL(real_mode_blob_end);
+
GLOBAL(real_mode_relocs)
.incbin "arch/x86/realmode/rm/realmode.relocs"
END(real_mode_relocs)
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 83869ab..25f554c 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -83,7 +83,7 @@ static struct notifier_block tts_notifier = {
static int acpi_sleep_prepare(u32 acpi_state)
{
#ifdef CONFIG_ACPI_SLEEP
- unsigned long wakeup_pa = real_mode_header.wakeup_start;
+ unsigned long wakeup_pa = real_mode_header->wakeup_start;
/* do we have a wakeup address for S2 and S3? */
if (acpi_state == ACPI_STATE_S3) {
if (!wakeup_pa)
--
1.7.9.5

2012-05-08 18:24:33

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 22/23] x86, realmode: fixes compilation issue in tboot.c

Fixed include path of wakeup.h in tboot.c.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/kernel/tboot.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index 65adda4..f84fe00 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -44,7 +44,7 @@
#include <asm/e820.h>
#include <asm/io.h>

-#include "acpi/realmode/wakeup.h"
+#include "../realmode/rm/wakeup.h"

/* Global pointer to shared data; NULL means no measured launch. */
struct tboot *tboot __read_mostly;
--
1.7.9.5

2012-05-08 18:24:48

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 21/23] x86, realmode: move relocs from scripts/ to arch/x86/tools

Moved relocs tool from scripts/ to arch/x86/tools because
it is architecture specific script. Added new target archscripts
that can be used to build scripts needed building an architecture.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
Makefile | 9 +-
arch/x86/Makefile | 3 +
arch/x86/boot/compressed/Makefile | 4 +-
arch/x86/realmode/rm/Makefile | 2 +-
arch/x86/tools/.gitignore | 1 +
arch/x86/tools/Makefile | 4 +
arch/x86/tools/relocs.c | 804 +++++++++++++++++++++++++++++++++++++
scripts/Makefile | 1 -
scripts/x86-relocs.c | 804 -------------------------------------
9 files changed, 821 insertions(+), 811 deletions(-)
create mode 100644 arch/x86/tools/.gitignore
create mode 100644 arch/x86/tools/relocs.c
delete mode 100644 scripts/x86-relocs.c

diff --git a/Makefile b/Makefile
index afc868e..ee17561 100644
--- a/Makefile
+++ b/Makefile
@@ -442,7 +442,7 @@ asm-generic:

no-dot-config-targets := clean mrproper distclean \
cscope gtags TAGS tags help %docs check% coccicheck \
- include/linux/version.h headers_% archheaders \
+ include/linux/version.h headers_% archheaders archscripts \
kernelversion %src-pkg

config-targets := 0
@@ -979,7 +979,7 @@ prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
include/config/auto.conf
$(cmd_crmodverdir)

-archprepare: archheaders prepare1 scripts_basic
+archprepare: archheaders archscripts prepare1 scripts_basic

prepare0: archprepare FORCE
$(Q)$(MAKE) $(build)=.
@@ -1049,8 +1049,11 @@ hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
PHONY += archheaders
archheaders:

+PHONY += archscripts
+archscripts:
+
PHONY += __headers
-__headers: include/linux/version.h scripts_basic asm-generic archheaders FORCE
+__headers: include/linux/version.h scripts_basic asm-generic archheaders archscripts FORCE
$(Q)$(MAKE) $(build)=scripts build_unifdef

PHONY += headers_install_all
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 41a7237..94e91e4 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -134,6 +134,9 @@ KBUILD_CFLAGS += $(call cc-option,-mno-avx,)
KBUILD_CFLAGS += $(mflags-y)
KBUILD_AFLAGS += $(mflags-y)

+archscripts:
+ $(Q)$(MAKE) $(build)=arch/x86/tools relocs
+
###
# Syscall table generation

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 0435e8a..e398bb5 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -42,8 +42,8 @@ $(obj)/vmlinux.bin: vmlinux FORCE

targets += vmlinux.bin.all vmlinux.relocs

-CMD_RELOCS = scripts/x86-relocs
-quiet_cmd_relocs = RELOCS $@
+CMD_RELOCS = arch/x86/tools/relocs
+quiet_cmd_relocs = RELOCS $@
cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $<
$(obj)/vmlinux.relocs: vmlinux FORCE
$(call if_changed,relocs)
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index fc8854b..de40bc4 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -52,7 +52,7 @@ $(obj)/realmode.bin: $(obj)/realmode.elf
$(call if_changed,objcopy)

quiet_cmd_relocs = RELOCS $@
- cmd_relocs = scripts/x86-relocs --realmode $< > $@
+ cmd_relocs = arch/x86/tools/relocs --realmode $< > $@
$(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
$(call if_changed,relocs)

diff --git a/arch/x86/tools/.gitignore b/arch/x86/tools/.gitignore
new file mode 100644
index 0000000..be0ed06
--- /dev/null
+++ b/arch/x86/tools/.gitignore
@@ -0,0 +1 @@
+relocs
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
index d511aa9..733057b 100644
--- a/arch/x86/tools/Makefile
+++ b/arch/x86/tools/Makefile
@@ -36,3 +36,7 @@ HOSTCFLAGS_insn_sanity.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x
$(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c

$(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
+
+HOST_EXTRACFLAGS += -I$(srctree)/tools/include
+hostprogs-y += relocs
+relocs: $(obj)/relocs
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
new file mode 100644
index 0000000..74e16bb
--- /dev/null
+++ b/arch/x86/tools/relocs.c
@@ -0,0 +1,804 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <elf.h>
+#include <byteswap.h>
+#define USE_BSD
+#include <endian.h>
+#include <regex.h>
+#include <tools/le_byteshift.h>
+
+static void die(char *fmt, ...);
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+static Elf32_Ehdr ehdr;
+static unsigned long reloc_count, reloc_idx;
+static unsigned long *relocs;
+static unsigned long reloc16_count, reloc16_idx;
+static unsigned long *relocs16;
+
+struct section {
+ Elf32_Shdr shdr;
+ struct section *link;
+ Elf32_Sym *symtab;
+ Elf32_Rel *reltab;
+ char *strtab;
+};
+static struct section *secs;
+
+enum symtype {
+ S_ABS,
+ S_REL,
+ S_SEG,
+ S_LIN,
+ S_NSYMTYPES
+};
+
+static const char * const sym_regex_kernel[S_NSYMTYPES] = {
+/*
+ * Following symbols have been audited. There values are constant and do
+ * not change if bzImage is loaded at a different physical address than
+ * the address for which it has been compiled. Don't warn user about
+ * absolute relocations present w.r.t these symbols.
+ */
+ [S_ABS] =
+ "^(xen_irq_disable_direct_reloc$|"
+ "xen_save_fl_direct_reloc$|"
+ "VDSO|"
+ "__crc_)",
+
+/*
+ * These symbols are known to be relative, even if the linker marks them
+ * as absolute (typically defined outside any section in the linker script.)
+ */
+ [S_REL] =
+ "^_end$",
+};
+
+
+static const char * const sym_regex_realmode[S_NSYMTYPES] = {
+/*
+ * These symbols are known to be relative, even if the linker marks them
+ * as absolute (typically defined outside any section in the linker script.)
+ */
+ [S_REL] =
+ "^pa_",
+
+/*
+ * These are 16-bit segment symbols when compiling 16-bit code.
+ */
+ [S_SEG] =
+ "^real_mode_seg$",
+
+/*
+ * These are offsets belonging to segments, as opposed to linear addresses,
+ * when compiling 16-bit code.
+ */
+ [S_LIN] =
+ "^pa_",
+};
+
+static const char * const *sym_regex;
+
+static regex_t sym_regex_c[S_NSYMTYPES];
+static int is_reloc(enum symtype type, const char *sym_name)
+{
+ return sym_regex[type] &&
+ !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0);
+}
+
+static void regex_init(int use_real_mode)
+{
+ char errbuf[128];
+ int err;
+ int i;
+
+ if (use_real_mode)
+ sym_regex = sym_regex_realmode;
+ else
+ sym_regex = sym_regex_kernel;
+
+ for (i = 0; i < S_NSYMTYPES; i++) {
+ if (!sym_regex[i])
+ continue;
+
+ err = regcomp(&sym_regex_c[i], sym_regex[i],
+ REG_EXTENDED|REG_NOSUB);
+
+ if (err) {
+ regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf);
+ die("%s", errbuf);
+ }
+ }
+}
+
+static void die(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+static const char *sym_type(unsigned type)
+{
+ static const char *type_name[] = {
+#define SYM_TYPE(X) [X] = #X
+ SYM_TYPE(STT_NOTYPE),
+ SYM_TYPE(STT_OBJECT),
+ SYM_TYPE(STT_FUNC),
+ SYM_TYPE(STT_SECTION),
+ SYM_TYPE(STT_FILE),
+ SYM_TYPE(STT_COMMON),
+ SYM_TYPE(STT_TLS),
+#undef SYM_TYPE
+ };
+ const char *name = "unknown sym type name";
+ if (type < ARRAY_SIZE(type_name)) {
+ name = type_name[type];
+ }
+ return name;
+}
+
+static const char *sym_bind(unsigned bind)
+{
+ static const char *bind_name[] = {
+#define SYM_BIND(X) [X] = #X
+ SYM_BIND(STB_LOCAL),
+ SYM_BIND(STB_GLOBAL),
+ SYM_BIND(STB_WEAK),
+#undef SYM_BIND
+ };
+ const char *name = "unknown sym bind name";
+ if (bind < ARRAY_SIZE(bind_name)) {
+ name = bind_name[bind];
+ }
+ return name;
+}
+
+static const char *sym_visibility(unsigned visibility)
+{
+ static const char *visibility_name[] = {
+#define SYM_VISIBILITY(X) [X] = #X
+ SYM_VISIBILITY(STV_DEFAULT),
+ SYM_VISIBILITY(STV_INTERNAL),
+ SYM_VISIBILITY(STV_HIDDEN),
+ SYM_VISIBILITY(STV_PROTECTED),
+#undef SYM_VISIBILITY
+ };
+ const char *name = "unknown sym visibility name";
+ if (visibility < ARRAY_SIZE(visibility_name)) {
+ name = visibility_name[visibility];
+ }
+ return name;
+}
+
+static const char *rel_type(unsigned type)
+{
+ static const char *type_name[] = {
+#define REL_TYPE(X) [X] = #X
+ REL_TYPE(R_386_NONE),
+ REL_TYPE(R_386_32),
+ REL_TYPE(R_386_PC32),
+ REL_TYPE(R_386_GOT32),
+ REL_TYPE(R_386_PLT32),
+ REL_TYPE(R_386_COPY),
+ REL_TYPE(R_386_GLOB_DAT),
+ REL_TYPE(R_386_JMP_SLOT),
+ REL_TYPE(R_386_RELATIVE),
+ REL_TYPE(R_386_GOTOFF),
+ REL_TYPE(R_386_GOTPC),
+ REL_TYPE(R_386_8),
+ REL_TYPE(R_386_PC8),
+ REL_TYPE(R_386_16),
+ REL_TYPE(R_386_PC16),
+#undef REL_TYPE
+ };
+ const char *name = "unknown type rel type name";
+ if (type < ARRAY_SIZE(type_name) && type_name[type]) {
+ name = type_name[type];
+ }
+ return name;
+}
+
+static const char *sec_name(unsigned shndx)
+{
+ const char *sec_strtab;
+ const char *name;
+ sec_strtab = secs[ehdr.e_shstrndx].strtab;
+ name = "<noname>";
+ if (shndx < ehdr.e_shnum) {
+ name = sec_strtab + secs[shndx].shdr.sh_name;
+ }
+ else if (shndx == SHN_ABS) {
+ name = "ABSOLUTE";
+ }
+ else if (shndx == SHN_COMMON) {
+ name = "COMMON";
+ }
+ return name;
+}
+
+static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
+{
+ const char *name;
+ name = "<noname>";
+ if (sym->st_name) {
+ name = sym_strtab + sym->st_name;
+ }
+ else {
+ name = sec_name(sym->st_shndx);
+ }
+ return name;
+}
+
+
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+#define le16_to_cpu(val) bswap_16(val)
+#define le32_to_cpu(val) bswap_32(val)
+#endif
+
+static uint16_t elf16_to_cpu(uint16_t val)
+{
+ return le16_to_cpu(val);
+}
+
+static uint32_t elf32_to_cpu(uint32_t val)
+{
+ return le32_to_cpu(val);
+}
+
+static void read_ehdr(FILE *fp)
+{
+ if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
+ die("Cannot read ELF header: %s\n",
+ strerror(errno));
+ }
+ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
+ die("No ELF magic\n");
+ }
+ if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
+ die("Not a 32 bit executable\n");
+ }
+ if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
+ die("Not a LSB ELF executable\n");
+ }
+ if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
+ die("Unknown ELF version\n");
+ }
+ /* Convert the fields to native endian */
+ ehdr.e_type = elf16_to_cpu(ehdr.e_type);
+ ehdr.e_machine = elf16_to_cpu(ehdr.e_machine);
+ ehdr.e_version = elf32_to_cpu(ehdr.e_version);
+ ehdr.e_entry = elf32_to_cpu(ehdr.e_entry);
+ ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff);
+ ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff);
+ ehdr.e_flags = elf32_to_cpu(ehdr.e_flags);
+ ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize);
+ ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
+ ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum);
+ ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
+ ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum);
+ ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx);
+
+ if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
+ die("Unsupported ELF header type\n");
+ }
+ if (ehdr.e_machine != EM_386) {
+ die("Not for x86\n");
+ }
+ if (ehdr.e_version != EV_CURRENT) {
+ die("Unknown ELF version\n");
+ }
+ if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
+ die("Bad Elf header size\n");
+ }
+ if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
+ die("Bad program header entry\n");
+ }
+ if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
+ die("Bad section header entry\n");
+ }
+ if (ehdr.e_shstrndx >= ehdr.e_shnum) {
+ die("String table index out of bounds\n");
+ }
+}
+
+static void read_shdrs(FILE *fp)
+{
+ int i;
+ Elf32_Shdr shdr;
+
+ secs = calloc(ehdr.e_shnum, sizeof(struct section));
+ if (!secs) {
+ die("Unable to allocate %d section headers\n",
+ ehdr.e_shnum);
+ }
+ if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ ehdr.e_shoff, strerror(errno));
+ }
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (fread(&shdr, sizeof shdr, 1, fp) != 1)
+ die("Cannot read ELF section headers %d/%d: %s\n",
+ i, ehdr.e_shnum, strerror(errno));
+ sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name);
+ sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type);
+ sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags);
+ sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr);
+ sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset);
+ sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size);
+ sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link);
+ sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info);
+ sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
+ sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize);
+ if (sec->shdr.sh_link < ehdr.e_shnum)
+ sec->link = &secs[sec->shdr.sh_link];
+ }
+
+}
+
+static void read_strtabs(FILE *fp)
+{
+ int i;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (sec->shdr.sh_type != SHT_STRTAB) {
+ continue;
+ }
+ sec->strtab = malloc(sec->shdr.sh_size);
+ if (!sec->strtab) {
+ die("malloc of %d bytes for strtab failed\n",
+ sec->shdr.sh_size);
+ }
+ if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ sec->shdr.sh_offset, strerror(errno));
+ }
+ if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
+ != sec->shdr.sh_size) {
+ die("Cannot read symbol table: %s\n",
+ strerror(errno));
+ }
+ }
+}
+
+static void read_symtabs(FILE *fp)
+{
+ int i,j;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (sec->shdr.sh_type != SHT_SYMTAB) {
+ continue;
+ }
+ sec->symtab = malloc(sec->shdr.sh_size);
+ if (!sec->symtab) {
+ die("malloc of %d bytes for symtab failed\n",
+ sec->shdr.sh_size);
+ }
+ if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ sec->shdr.sh_offset, strerror(errno));
+ }
+ if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
+ != sec->shdr.sh_size) {
+ die("Cannot read symbol table: %s\n",
+ strerror(errno));
+ }
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
+ Elf32_Sym *sym = &sec->symtab[j];
+ sym->st_name = elf32_to_cpu(sym->st_name);
+ sym->st_value = elf32_to_cpu(sym->st_value);
+ sym->st_size = elf32_to_cpu(sym->st_size);
+ sym->st_shndx = elf16_to_cpu(sym->st_shndx);
+ }
+ }
+}
+
+
+static void read_relocs(FILE *fp)
+{
+ int i,j;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (sec->shdr.sh_type != SHT_REL) {
+ continue;
+ }
+ sec->reltab = malloc(sec->shdr.sh_size);
+ if (!sec->reltab) {
+ die("malloc of %d bytes for relocs failed\n",
+ sec->shdr.sh_size);
+ }
+ if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ sec->shdr.sh_offset, strerror(errno));
+ }
+ if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
+ != sec->shdr.sh_size) {
+ die("Cannot read symbol table: %s\n",
+ strerror(errno));
+ }
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+ Elf32_Rel *rel = &sec->reltab[j];
+ rel->r_offset = elf32_to_cpu(rel->r_offset);
+ rel->r_info = elf32_to_cpu(rel->r_info);
+ }
+ }
+}
+
+
+static void print_absolute_symbols(void)
+{
+ int i;
+ printf("Absolute symbols\n");
+ printf(" Num: Value Size Type Bind Visibility Name\n");
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ char *sym_strtab;
+ int j;
+
+ if (sec->shdr.sh_type != SHT_SYMTAB) {
+ continue;
+ }
+ sym_strtab = sec->link->strtab;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
+ Elf32_Sym *sym;
+ const char *name;
+ sym = &sec->symtab[j];
+ name = sym_name(sym_strtab, sym);
+ if (sym->st_shndx != SHN_ABS) {
+ continue;
+ }
+ printf("%5d %08x %5d %10s %10s %12s %s\n",
+ j, sym->st_value, sym->st_size,
+ sym_type(ELF32_ST_TYPE(sym->st_info)),
+ sym_bind(ELF32_ST_BIND(sym->st_info)),
+ sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
+ name);
+ }
+ }
+ printf("\n");
+}
+
+static void print_absolute_relocs(void)
+{
+ int i, printed = 0;
+
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ struct section *sec_applies, *sec_symtab;
+ char *sym_strtab;
+ Elf32_Sym *sh_symtab;
+ int j;
+ if (sec->shdr.sh_type != SHT_REL) {
+ continue;
+ }
+ sec_symtab = sec->link;
+ sec_applies = &secs[sec->shdr.sh_info];
+ if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
+ continue;
+ }
+ sh_symtab = sec_symtab->symtab;
+ sym_strtab = sec_symtab->link->strtab;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+ Elf32_Rel *rel;
+ Elf32_Sym *sym;
+ const char *name;
+ rel = &sec->reltab[j];
+ sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+ name = sym_name(sym_strtab, sym);
+ if (sym->st_shndx != SHN_ABS) {
+ continue;
+ }
+
+ /* Absolute symbols are not relocated if bzImage is
+ * loaded at a non-compiled address. Display a warning
+ * to user at compile time about the absolute
+ * relocations present.
+ *
+ * User need to audit the code to make sure
+ * some symbols which should have been section
+ * relative have not become absolute because of some
+ * linker optimization or wrong programming usage.
+ *
+ * Before warning check if this absolute symbol
+ * relocation is harmless.
+ */
+ if (is_reloc(S_ABS, name) || is_reloc(S_REL, name))
+ continue;
+
+ if (!printed) {
+ printf("WARNING: Absolute relocations"
+ " present\n");
+ printf("Offset Info Type Sym.Value "
+ "Sym.Name\n");
+ printed = 1;
+ }
+
+ printf("%08x %08x %10s %08x %s\n",
+ rel->r_offset,
+ rel->r_info,
+ rel_type(ELF32_R_TYPE(rel->r_info)),
+ sym->st_value,
+ name);
+ }
+ }
+
+ if (printed)
+ printf("\n");
+}
+
+static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
+ int use_real_mode)
+{
+ int i;
+ /* Walk through the relocations */
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ char *sym_strtab;
+ Elf32_Sym *sh_symtab;
+ struct section *sec_applies, *sec_symtab;
+ int j;
+ struct section *sec = &secs[i];
+
+ if (sec->shdr.sh_type != SHT_REL) {
+ continue;
+ }
+ sec_symtab = sec->link;
+ sec_applies = &secs[sec->shdr.sh_info];
+ if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
+ continue;
+ }
+ sh_symtab = sec_symtab->symtab;
+ sym_strtab = sec_symtab->link->strtab;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+ Elf32_Rel *rel;
+ Elf32_Sym *sym;
+ unsigned r_type;
+ const char *symname;
+ rel = &sec->reltab[j];
+ sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+ r_type = ELF32_R_TYPE(rel->r_info);
+
+ switch (r_type) {
+ case R_386_NONE:
+ case R_386_PC32:
+ case R_386_PC16:
+ case R_386_PC8:
+ /*
+ * NONE can be ignored and and PC relative
+ * relocations don't need to be adjusted.
+ */
+ break;
+
+ case R_386_16:
+ symname = sym_name(sym_strtab, sym);
+ if (!use_real_mode)
+ goto bad;
+ if (sym->st_shndx == SHN_ABS) {
+ if (is_reloc(S_ABS, symname))
+ break;
+ else if (!is_reloc(S_SEG, symname))
+ goto bad;
+ } else {
+ if (is_reloc(S_LIN, symname))
+ goto bad;
+ else
+ break;
+ }
+ visit(rel, sym);
+ break;
+
+ case R_386_32:
+ symname = sym_name(sym_strtab, sym);
+ if (sym->st_shndx == SHN_ABS) {
+ if (is_reloc(S_ABS, symname))
+ break;
+ else if (!is_reloc(S_REL, symname))
+ goto bad;
+ } else {
+ if (use_real_mode &&
+ !is_reloc(S_LIN, symname))
+ break;
+ }
+ visit(rel, sym);
+ break;
+ default:
+ die("Unsupported relocation type: %s (%d)\n",
+ rel_type(r_type), r_type);
+ break;
+ bad:
+ symname = sym_name(sym_strtab, sym);
+ die("Invalid %s relocation: %s\n",
+ rel_type(r_type), symname);
+ }
+ }
+ }
+}
+
+static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+{
+ if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+ reloc16_count++;
+ else
+ reloc_count++;
+}
+
+static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+{
+ /* Remember the address that needs to be adjusted. */
+ if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+ relocs16[reloc16_idx++] = rel->r_offset;
+ else
+ relocs[reloc_idx++] = rel->r_offset;
+}
+
+static int cmp_relocs(const void *va, const void *vb)
+{
+ const unsigned long *a, *b;
+ a = va; b = vb;
+ return (*a == *b)? 0 : (*a > *b)? 1 : -1;
+}
+
+static int write32(unsigned int v, FILE *f)
+{
+ unsigned char buf[4];
+
+ put_unaligned_le32(v, buf);
+ return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
+}
+
+static void emit_relocs(int as_text, int use_real_mode)
+{
+ int i;
+ /* Count how many relocations I have and allocate space for them. */
+ reloc_count = 0;
+ walk_relocs(count_reloc, use_real_mode);
+ relocs = malloc(reloc_count * sizeof(relocs[0]));
+ if (!relocs) {
+ die("malloc of %d entries for relocs failed\n",
+ reloc_count);
+ }
+
+ relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
+ if (!relocs16) {
+ die("malloc of %d entries for relocs16 failed\n",
+ reloc16_count);
+ }
+ /* Collect up the relocations */
+ reloc_idx = 0;
+ walk_relocs(collect_reloc, use_real_mode);
+
+ if (reloc16_count && !use_real_mode)
+ die("Segment relocations found but --realmode not specified\n");
+
+ /* Order the relocations for more efficient processing */
+ qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
+ qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
+
+ /* Print the relocations */
+ if (as_text) {
+ /* Print the relocations in a form suitable that
+ * gas will like.
+ */
+ printf(".section \".data.reloc\",\"a\"\n");
+ printf(".balign 4\n");
+ if (use_real_mode) {
+ printf("\t.long %lu\n", reloc16_count);
+ for (i = 0; i < reloc16_count; i++)
+ printf("\t.long 0x%08lx\n", relocs16[i]);
+ printf("\t.long %lu\n", reloc_count);
+ for (i = 0; i < reloc_count; i++) {
+ printf("\t.long 0x%08lx\n", relocs[i]);
+ }
+ } else {
+ /* Print a stop */
+ printf("\t.long 0x%08lx\n", (unsigned long)0);
+ for (i = 0; i < reloc_count; i++) {
+ printf("\t.long 0x%08lx\n", relocs[i]);
+ }
+ }
+
+ printf("\n");
+ }
+ else {
+ if (use_real_mode) {
+ write32(reloc16_count, stdout);
+ for (i = 0; i < reloc16_count; i++)
+ write32(relocs16[i], stdout);
+ write32(reloc_count, stdout);
+
+ /* Now print each relocation */
+ for (i = 0; i < reloc_count; i++)
+ write32(relocs[i], stdout);
+ } else {
+ /* Print a stop */
+ write32(0, stdout);
+
+ /* Now print each relocation */
+ for (i = 0; i < reloc_count; i++) {
+ write32(relocs[i], stdout);
+ }
+ }
+ }
+}
+
+static void usage(void)
+{
+ die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
+}
+
+int main(int argc, char **argv)
+{
+ int show_absolute_syms, show_absolute_relocs;
+ int as_text, use_real_mode;
+ const char *fname;
+ FILE *fp;
+ int i;
+
+ show_absolute_syms = 0;
+ show_absolute_relocs = 0;
+ as_text = 0;
+ use_real_mode = 0;
+ fname = NULL;
+ for (i = 1; i < argc; i++) {
+ char *arg = argv[i];
+ if (*arg == '-') {
+ if (strcmp(arg, "--abs-syms") == 0) {
+ show_absolute_syms = 1;
+ continue;
+ }
+ if (strcmp(arg, "--abs-relocs") == 0) {
+ show_absolute_relocs = 1;
+ continue;
+ }
+ if (strcmp(arg, "--text") == 0) {
+ as_text = 1;
+ continue;
+ }
+ if (strcmp(arg, "--realmode") == 0) {
+ use_real_mode = 1;
+ continue;
+ }
+ }
+ else if (!fname) {
+ fname = arg;
+ continue;
+ }
+ usage();
+ }
+ if (!fname) {
+ usage();
+ }
+ regex_init(use_real_mode);
+ fp = fopen(fname, "r");
+ if (!fp) {
+ die("Cannot open %s: %s\n",
+ fname, strerror(errno));
+ }
+ read_ehdr(fp);
+ read_shdrs(fp);
+ read_strtabs(fp);
+ read_symtabs(fp);
+ read_relocs(fp);
+ if (show_absolute_syms) {
+ print_absolute_symbols();
+ return 0;
+ }
+ if (show_absolute_relocs) {
+ print_absolute_relocs();
+ return 0;
+ }
+ emit_relocs(as_text, use_real_mode);
+ return 0;
+}
diff --git a/scripts/Makefile b/scripts/Makefile
index a241359d..3626666 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -15,7 +15,6 @@ hostprogs-$(CONFIG_LOGO) += pnmtologo
hostprogs-$(CONFIG_VT) += conmakehash
hostprogs-$(CONFIG_IKCONFIG) += bin2c
hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
-hostprogs-$(CONFIG_X86) += x86-relocs

always := $(hostprogs-y) $(hostprogs-m)

diff --git a/scripts/x86-relocs.c b/scripts/x86-relocs.c
deleted file mode 100644
index 74e16bb..0000000
--- a/scripts/x86-relocs.c
+++ /dev/null
@@ -1,804 +0,0 @@
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <elf.h>
-#include <byteswap.h>
-#define USE_BSD
-#include <endian.h>
-#include <regex.h>
-#include <tools/le_byteshift.h>
-
-static void die(char *fmt, ...);
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-static Elf32_Ehdr ehdr;
-static unsigned long reloc_count, reloc_idx;
-static unsigned long *relocs;
-static unsigned long reloc16_count, reloc16_idx;
-static unsigned long *relocs16;
-
-struct section {
- Elf32_Shdr shdr;
- struct section *link;
- Elf32_Sym *symtab;
- Elf32_Rel *reltab;
- char *strtab;
-};
-static struct section *secs;
-
-enum symtype {
- S_ABS,
- S_REL,
- S_SEG,
- S_LIN,
- S_NSYMTYPES
-};
-
-static const char * const sym_regex_kernel[S_NSYMTYPES] = {
-/*
- * Following symbols have been audited. There values are constant and do
- * not change if bzImage is loaded at a different physical address than
- * the address for which it has been compiled. Don't warn user about
- * absolute relocations present w.r.t these symbols.
- */
- [S_ABS] =
- "^(xen_irq_disable_direct_reloc$|"
- "xen_save_fl_direct_reloc$|"
- "VDSO|"
- "__crc_)",
-
-/*
- * These symbols are known to be relative, even if the linker marks them
- * as absolute (typically defined outside any section in the linker script.)
- */
- [S_REL] =
- "^_end$",
-};
-
-
-static const char * const sym_regex_realmode[S_NSYMTYPES] = {
-/*
- * These symbols are known to be relative, even if the linker marks them
- * as absolute (typically defined outside any section in the linker script.)
- */
- [S_REL] =
- "^pa_",
-
-/*
- * These are 16-bit segment symbols when compiling 16-bit code.
- */
- [S_SEG] =
- "^real_mode_seg$",
-
-/*
- * These are offsets belonging to segments, as opposed to linear addresses,
- * when compiling 16-bit code.
- */
- [S_LIN] =
- "^pa_",
-};
-
-static const char * const *sym_regex;
-
-static regex_t sym_regex_c[S_NSYMTYPES];
-static int is_reloc(enum symtype type, const char *sym_name)
-{
- return sym_regex[type] &&
- !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0);
-}
-
-static void regex_init(int use_real_mode)
-{
- char errbuf[128];
- int err;
- int i;
-
- if (use_real_mode)
- sym_regex = sym_regex_realmode;
- else
- sym_regex = sym_regex_kernel;
-
- for (i = 0; i < S_NSYMTYPES; i++) {
- if (!sym_regex[i])
- continue;
-
- err = regcomp(&sym_regex_c[i], sym_regex[i],
- REG_EXTENDED|REG_NOSUB);
-
- if (err) {
- regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf);
- die("%s", errbuf);
- }
- }
-}
-
-static void die(char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- exit(1);
-}
-
-static const char *sym_type(unsigned type)
-{
- static const char *type_name[] = {
-#define SYM_TYPE(X) [X] = #X
- SYM_TYPE(STT_NOTYPE),
- SYM_TYPE(STT_OBJECT),
- SYM_TYPE(STT_FUNC),
- SYM_TYPE(STT_SECTION),
- SYM_TYPE(STT_FILE),
- SYM_TYPE(STT_COMMON),
- SYM_TYPE(STT_TLS),
-#undef SYM_TYPE
- };
- const char *name = "unknown sym type name";
- if (type < ARRAY_SIZE(type_name)) {
- name = type_name[type];
- }
- return name;
-}
-
-static const char *sym_bind(unsigned bind)
-{
- static const char *bind_name[] = {
-#define SYM_BIND(X) [X] = #X
- SYM_BIND(STB_LOCAL),
- SYM_BIND(STB_GLOBAL),
- SYM_BIND(STB_WEAK),
-#undef SYM_BIND
- };
- const char *name = "unknown sym bind name";
- if (bind < ARRAY_SIZE(bind_name)) {
- name = bind_name[bind];
- }
- return name;
-}
-
-static const char *sym_visibility(unsigned visibility)
-{
- static const char *visibility_name[] = {
-#define SYM_VISIBILITY(X) [X] = #X
- SYM_VISIBILITY(STV_DEFAULT),
- SYM_VISIBILITY(STV_INTERNAL),
- SYM_VISIBILITY(STV_HIDDEN),
- SYM_VISIBILITY(STV_PROTECTED),
-#undef SYM_VISIBILITY
- };
- const char *name = "unknown sym visibility name";
- if (visibility < ARRAY_SIZE(visibility_name)) {
- name = visibility_name[visibility];
- }
- return name;
-}
-
-static const char *rel_type(unsigned type)
-{
- static const char *type_name[] = {
-#define REL_TYPE(X) [X] = #X
- REL_TYPE(R_386_NONE),
- REL_TYPE(R_386_32),
- REL_TYPE(R_386_PC32),
- REL_TYPE(R_386_GOT32),
- REL_TYPE(R_386_PLT32),
- REL_TYPE(R_386_COPY),
- REL_TYPE(R_386_GLOB_DAT),
- REL_TYPE(R_386_JMP_SLOT),
- REL_TYPE(R_386_RELATIVE),
- REL_TYPE(R_386_GOTOFF),
- REL_TYPE(R_386_GOTPC),
- REL_TYPE(R_386_8),
- REL_TYPE(R_386_PC8),
- REL_TYPE(R_386_16),
- REL_TYPE(R_386_PC16),
-#undef REL_TYPE
- };
- const char *name = "unknown type rel type name";
- if (type < ARRAY_SIZE(type_name) && type_name[type]) {
- name = type_name[type];
- }
- return name;
-}
-
-static const char *sec_name(unsigned shndx)
-{
- const char *sec_strtab;
- const char *name;
- sec_strtab = secs[ehdr.e_shstrndx].strtab;
- name = "<noname>";
- if (shndx < ehdr.e_shnum) {
- name = sec_strtab + secs[shndx].shdr.sh_name;
- }
- else if (shndx == SHN_ABS) {
- name = "ABSOLUTE";
- }
- else if (shndx == SHN_COMMON) {
- name = "COMMON";
- }
- return name;
-}
-
-static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
-{
- const char *name;
- name = "<noname>";
- if (sym->st_name) {
- name = sym_strtab + sym->st_name;
- }
- else {
- name = sec_name(sym->st_shndx);
- }
- return name;
-}
-
-
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define le16_to_cpu(val) (val)
-#define le32_to_cpu(val) (val)
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
-#define le16_to_cpu(val) bswap_16(val)
-#define le32_to_cpu(val) bswap_32(val)
-#endif
-
-static uint16_t elf16_to_cpu(uint16_t val)
-{
- return le16_to_cpu(val);
-}
-
-static uint32_t elf32_to_cpu(uint32_t val)
-{
- return le32_to_cpu(val);
-}
-
-static void read_ehdr(FILE *fp)
-{
- if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
- die("Cannot read ELF header: %s\n",
- strerror(errno));
- }
- if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
- die("No ELF magic\n");
- }
- if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
- die("Not a 32 bit executable\n");
- }
- if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
- die("Not a LSB ELF executable\n");
- }
- if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
- die("Unknown ELF version\n");
- }
- /* Convert the fields to native endian */
- ehdr.e_type = elf16_to_cpu(ehdr.e_type);
- ehdr.e_machine = elf16_to_cpu(ehdr.e_machine);
- ehdr.e_version = elf32_to_cpu(ehdr.e_version);
- ehdr.e_entry = elf32_to_cpu(ehdr.e_entry);
- ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff);
- ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff);
- ehdr.e_flags = elf32_to_cpu(ehdr.e_flags);
- ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize);
- ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
- ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum);
- ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
- ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum);
- ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx);
-
- if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
- die("Unsupported ELF header type\n");
- }
- if (ehdr.e_machine != EM_386) {
- die("Not for x86\n");
- }
- if (ehdr.e_version != EV_CURRENT) {
- die("Unknown ELF version\n");
- }
- if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
- die("Bad Elf header size\n");
- }
- if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
- die("Bad program header entry\n");
- }
- if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
- die("Bad section header entry\n");
- }
- if (ehdr.e_shstrndx >= ehdr.e_shnum) {
- die("String table index out of bounds\n");
- }
-}
-
-static void read_shdrs(FILE *fp)
-{
- int i;
- Elf32_Shdr shdr;
-
- secs = calloc(ehdr.e_shnum, sizeof(struct section));
- if (!secs) {
- die("Unable to allocate %d section headers\n",
- ehdr.e_shnum);
- }
- if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
- die("Seek to %d failed: %s\n",
- ehdr.e_shoff, strerror(errno));
- }
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- if (fread(&shdr, sizeof shdr, 1, fp) != 1)
- die("Cannot read ELF section headers %d/%d: %s\n",
- i, ehdr.e_shnum, strerror(errno));
- sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name);
- sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type);
- sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags);
- sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr);
- sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset);
- sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size);
- sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link);
- sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info);
- sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
- sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize);
- if (sec->shdr.sh_link < ehdr.e_shnum)
- sec->link = &secs[sec->shdr.sh_link];
- }
-
-}
-
-static void read_strtabs(FILE *fp)
-{
- int i;
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- if (sec->shdr.sh_type != SHT_STRTAB) {
- continue;
- }
- sec->strtab = malloc(sec->shdr.sh_size);
- if (!sec->strtab) {
- die("malloc of %d bytes for strtab failed\n",
- sec->shdr.sh_size);
- }
- if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
- die("Seek to %d failed: %s\n",
- sec->shdr.sh_offset, strerror(errno));
- }
- if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
- != sec->shdr.sh_size) {
- die("Cannot read symbol table: %s\n",
- strerror(errno));
- }
- }
-}
-
-static void read_symtabs(FILE *fp)
-{
- int i,j;
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- if (sec->shdr.sh_type != SHT_SYMTAB) {
- continue;
- }
- sec->symtab = malloc(sec->shdr.sh_size);
- if (!sec->symtab) {
- die("malloc of %d bytes for symtab failed\n",
- sec->shdr.sh_size);
- }
- if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
- die("Seek to %d failed: %s\n",
- sec->shdr.sh_offset, strerror(errno));
- }
- if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
- != sec->shdr.sh_size) {
- die("Cannot read symbol table: %s\n",
- strerror(errno));
- }
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
- Elf32_Sym *sym = &sec->symtab[j];
- sym->st_name = elf32_to_cpu(sym->st_name);
- sym->st_value = elf32_to_cpu(sym->st_value);
- sym->st_size = elf32_to_cpu(sym->st_size);
- sym->st_shndx = elf16_to_cpu(sym->st_shndx);
- }
- }
-}
-
-
-static void read_relocs(FILE *fp)
-{
- int i,j;
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- if (sec->shdr.sh_type != SHT_REL) {
- continue;
- }
- sec->reltab = malloc(sec->shdr.sh_size);
- if (!sec->reltab) {
- die("malloc of %d bytes for relocs failed\n",
- sec->shdr.sh_size);
- }
- if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
- die("Seek to %d failed: %s\n",
- sec->shdr.sh_offset, strerror(errno));
- }
- if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
- != sec->shdr.sh_size) {
- die("Cannot read symbol table: %s\n",
- strerror(errno));
- }
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
- Elf32_Rel *rel = &sec->reltab[j];
- rel->r_offset = elf32_to_cpu(rel->r_offset);
- rel->r_info = elf32_to_cpu(rel->r_info);
- }
- }
-}
-
-
-static void print_absolute_symbols(void)
-{
- int i;
- printf("Absolute symbols\n");
- printf(" Num: Value Size Type Bind Visibility Name\n");
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- char *sym_strtab;
- int j;
-
- if (sec->shdr.sh_type != SHT_SYMTAB) {
- continue;
- }
- sym_strtab = sec->link->strtab;
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
- Elf32_Sym *sym;
- const char *name;
- sym = &sec->symtab[j];
- name = sym_name(sym_strtab, sym);
- if (sym->st_shndx != SHN_ABS) {
- continue;
- }
- printf("%5d %08x %5d %10s %10s %12s %s\n",
- j, sym->st_value, sym->st_size,
- sym_type(ELF32_ST_TYPE(sym->st_info)),
- sym_bind(ELF32_ST_BIND(sym->st_info)),
- sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
- name);
- }
- }
- printf("\n");
-}
-
-static void print_absolute_relocs(void)
-{
- int i, printed = 0;
-
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- struct section *sec_applies, *sec_symtab;
- char *sym_strtab;
- Elf32_Sym *sh_symtab;
- int j;
- if (sec->shdr.sh_type != SHT_REL) {
- continue;
- }
- sec_symtab = sec->link;
- sec_applies = &secs[sec->shdr.sh_info];
- if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
- continue;
- }
- sh_symtab = sec_symtab->symtab;
- sym_strtab = sec_symtab->link->strtab;
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
- Elf32_Rel *rel;
- Elf32_Sym *sym;
- const char *name;
- rel = &sec->reltab[j];
- sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
- name = sym_name(sym_strtab, sym);
- if (sym->st_shndx != SHN_ABS) {
- continue;
- }
-
- /* Absolute symbols are not relocated if bzImage is
- * loaded at a non-compiled address. Display a warning
- * to user at compile time about the absolute
- * relocations present.
- *
- * User need to audit the code to make sure
- * some symbols which should have been section
- * relative have not become absolute because of some
- * linker optimization or wrong programming usage.
- *
- * Before warning check if this absolute symbol
- * relocation is harmless.
- */
- if (is_reloc(S_ABS, name) || is_reloc(S_REL, name))
- continue;
-
- if (!printed) {
- printf("WARNING: Absolute relocations"
- " present\n");
- printf("Offset Info Type Sym.Value "
- "Sym.Name\n");
- printed = 1;
- }
-
- printf("%08x %08x %10s %08x %s\n",
- rel->r_offset,
- rel->r_info,
- rel_type(ELF32_R_TYPE(rel->r_info)),
- sym->st_value,
- name);
- }
- }
-
- if (printed)
- printf("\n");
-}
-
-static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
- int use_real_mode)
-{
- int i;
- /* Walk through the relocations */
- for (i = 0; i < ehdr.e_shnum; i++) {
- char *sym_strtab;
- Elf32_Sym *sh_symtab;
- struct section *sec_applies, *sec_symtab;
- int j;
- struct section *sec = &secs[i];
-
- if (sec->shdr.sh_type != SHT_REL) {
- continue;
- }
- sec_symtab = sec->link;
- sec_applies = &secs[sec->shdr.sh_info];
- if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
- continue;
- }
- sh_symtab = sec_symtab->symtab;
- sym_strtab = sec_symtab->link->strtab;
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
- Elf32_Rel *rel;
- Elf32_Sym *sym;
- unsigned r_type;
- const char *symname;
- rel = &sec->reltab[j];
- sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
- r_type = ELF32_R_TYPE(rel->r_info);
-
- switch (r_type) {
- case R_386_NONE:
- case R_386_PC32:
- case R_386_PC16:
- case R_386_PC8:
- /*
- * NONE can be ignored and and PC relative
- * relocations don't need to be adjusted.
- */
- break;
-
- case R_386_16:
- symname = sym_name(sym_strtab, sym);
- if (!use_real_mode)
- goto bad;
- if (sym->st_shndx == SHN_ABS) {
- if (is_reloc(S_ABS, symname))
- break;
- else if (!is_reloc(S_SEG, symname))
- goto bad;
- } else {
- if (is_reloc(S_LIN, symname))
- goto bad;
- else
- break;
- }
- visit(rel, sym);
- break;
-
- case R_386_32:
- symname = sym_name(sym_strtab, sym);
- if (sym->st_shndx == SHN_ABS) {
- if (is_reloc(S_ABS, symname))
- break;
- else if (!is_reloc(S_REL, symname))
- goto bad;
- } else {
- if (use_real_mode &&
- !is_reloc(S_LIN, symname))
- break;
- }
- visit(rel, sym);
- break;
- default:
- die("Unsupported relocation type: %s (%d)\n",
- rel_type(r_type), r_type);
- break;
- bad:
- symname = sym_name(sym_strtab, sym);
- die("Invalid %s relocation: %s\n",
- rel_type(r_type), symname);
- }
- }
- }
-}
-
-static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
-{
- if (ELF32_R_TYPE(rel->r_info) == R_386_16)
- reloc16_count++;
- else
- reloc_count++;
-}
-
-static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
-{
- /* Remember the address that needs to be adjusted. */
- if (ELF32_R_TYPE(rel->r_info) == R_386_16)
- relocs16[reloc16_idx++] = rel->r_offset;
- else
- relocs[reloc_idx++] = rel->r_offset;
-}
-
-static int cmp_relocs(const void *va, const void *vb)
-{
- const unsigned long *a, *b;
- a = va; b = vb;
- return (*a == *b)? 0 : (*a > *b)? 1 : -1;
-}
-
-static int write32(unsigned int v, FILE *f)
-{
- unsigned char buf[4];
-
- put_unaligned_le32(v, buf);
- return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
-}
-
-static void emit_relocs(int as_text, int use_real_mode)
-{
- int i;
- /* Count how many relocations I have and allocate space for them. */
- reloc_count = 0;
- walk_relocs(count_reloc, use_real_mode);
- relocs = malloc(reloc_count * sizeof(relocs[0]));
- if (!relocs) {
- die("malloc of %d entries for relocs failed\n",
- reloc_count);
- }
-
- relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
- if (!relocs16) {
- die("malloc of %d entries for relocs16 failed\n",
- reloc16_count);
- }
- /* Collect up the relocations */
- reloc_idx = 0;
- walk_relocs(collect_reloc, use_real_mode);
-
- if (reloc16_count && !use_real_mode)
- die("Segment relocations found but --realmode not specified\n");
-
- /* Order the relocations for more efficient processing */
- qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
- qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
-
- /* Print the relocations */
- if (as_text) {
- /* Print the relocations in a form suitable that
- * gas will like.
- */
- printf(".section \".data.reloc\",\"a\"\n");
- printf(".balign 4\n");
- if (use_real_mode) {
- printf("\t.long %lu\n", reloc16_count);
- for (i = 0; i < reloc16_count; i++)
- printf("\t.long 0x%08lx\n", relocs16[i]);
- printf("\t.long %lu\n", reloc_count);
- for (i = 0; i < reloc_count; i++) {
- printf("\t.long 0x%08lx\n", relocs[i]);
- }
- } else {
- /* Print a stop */
- printf("\t.long 0x%08lx\n", (unsigned long)0);
- for (i = 0; i < reloc_count; i++) {
- printf("\t.long 0x%08lx\n", relocs[i]);
- }
- }
-
- printf("\n");
- }
- else {
- if (use_real_mode) {
- write32(reloc16_count, stdout);
- for (i = 0; i < reloc16_count; i++)
- write32(relocs16[i], stdout);
- write32(reloc_count, stdout);
-
- /* Now print each relocation */
- for (i = 0; i < reloc_count; i++)
- write32(relocs[i], stdout);
- } else {
- /* Print a stop */
- write32(0, stdout);
-
- /* Now print each relocation */
- for (i = 0; i < reloc_count; i++) {
- write32(relocs[i], stdout);
- }
- }
- }
-}
-
-static void usage(void)
-{
- die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
-}
-
-int main(int argc, char **argv)
-{
- int show_absolute_syms, show_absolute_relocs;
- int as_text, use_real_mode;
- const char *fname;
- FILE *fp;
- int i;
-
- show_absolute_syms = 0;
- show_absolute_relocs = 0;
- as_text = 0;
- use_real_mode = 0;
- fname = NULL;
- for (i = 1; i < argc; i++) {
- char *arg = argv[i];
- if (*arg == '-') {
- if (strcmp(arg, "--abs-syms") == 0) {
- show_absolute_syms = 1;
- continue;
- }
- if (strcmp(arg, "--abs-relocs") == 0) {
- show_absolute_relocs = 1;
- continue;
- }
- if (strcmp(arg, "--text") == 0) {
- as_text = 1;
- continue;
- }
- if (strcmp(arg, "--realmode") == 0) {
- use_real_mode = 1;
- continue;
- }
- }
- else if (!fname) {
- fname = arg;
- continue;
- }
- usage();
- }
- if (!fname) {
- usage();
- }
- regex_init(use_real_mode);
- fp = fopen(fname, "r");
- if (!fp) {
- die("Cannot open %s: %s\n",
- fname, strerror(errno));
- }
- read_ehdr(fp);
- read_shdrs(fp);
- read_strtabs(fp);
- read_symtabs(fp);
- read_relocs(fp);
- if (show_absolute_syms) {
- print_absolute_symbols();
- return 0;
- }
- if (show_absolute_relocs) {
- print_absolute_relocs();
- return 0;
- }
- emit_relocs(as_text, use_real_mode);
- return 0;
-}
--
1.7.9.5

2012-05-08 18:24:01

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 17/23] x86, realmode: fix 64-bit wakeup sequence

There were number of issues in wakeup sequence:

- Wakeup stack was placed in hardcoded address.
- NX bit in EFER was not enabled.
- Initialization incorrectly set physical address
of secondary_startup_64.
- Some alignment issues.

This patch fixes these issues and in addition:

- Unifies coding conventions in .S files.
- Sets alignments of code and data right.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Originally-by: H. Peter Anvin <[email protected]>
---
arch/x86/kernel/realmode.c | 2 +-
arch/x86/realmode/rm/Makefile | 1 +
arch/x86/realmode/rm/header.S | 2 +-
arch/x86/realmode/rm/reboot_32.S | 18 +++----
arch/x86/realmode/rm/stack.S | 19 ++++++++
arch/x86/realmode/rm/trampoline_32.S | 29 ++++++------
arch/x86/realmode/rm/trampoline_64.S | 67 +++++++++++---------------
arch/x86/realmode/rm/wakeup/wakeup_asm.S | 75 ++++++++++++++----------------
arch/x86/realmode/rmpiggy.S | 4 +-
9 files changed, 110 insertions(+), 107 deletions(-)
create mode 100644 arch/x86/realmode/rm/stack.S

diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index d85ac20..e7bf82a 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -64,7 +64,7 @@ void __init setup_real_mode(void)
*((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt);
#else
*((u64 *) __va(real_mode_header.startup_64_smp)) =
- (u64) __pa(secondary_startup_64);
+ (u64)secondary_startup_64;

*((u64 *) __va(real_mode_header.level3_ident_pgt)) =
__pa(level3_ident_pgt) + _KERNPG_TABLE;
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 2423142..c2c27a4 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -13,6 +13,7 @@ always := realmode.bin

realmode-y += header.o
realmode-y += trampoline_$(BITS).o
+realmode-y += stack.o
realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o

diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index 730b131..a91ec8f 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -9,7 +9,7 @@

.section ".header", "a"

-ENTRY(real_mode_header)
+GLOBAL(real_mode_header)
.long pa_text_start
.long pa_ro_end
.long pa_end
diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
index 50ba994..8d9bfd1 100644
--- a/arch/x86/realmode/rm/reboot_32.S
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -16,10 +16,9 @@
*/
.section ".text32", "ax"
.code32
- .globl machine_real_restart_asm

- .balign 16
-machine_real_restart_asm:
+ .balign 16
+ENTRY(machine_real_restart_asm)
/* Set up the IDT for real mode. */
lidtl pa_machine_real_restart_idt

@@ -67,7 +66,7 @@ machine_real_restart_asm:
.text
.code16

- .balign 16
+ .balign 16
machine_real_restart_asm16:
1:
xorl %ecx, %ecx
@@ -102,15 +101,15 @@ bios:
ljmpw $0xf000, $0xfff0

.section ".rodata", "a"
- .globl machine_real_restart_idt, machine_real_restart_gdt

- .balign 16
-machine_real_restart_idt:
+ .balign 16
+GLOBAL(machine_real_restart_idt)
.word 0xffff /* Length - real mode default value */
.long 0 /* Base - real mode default value */
+END(machine_real_restart_idt)

- .balign 16
-machine_real_restart_gdt:
+ .balign 16
+GLOBAL(machine_real_restart_gdt)
/* Self-pointer */
.word 0xffff /* Length - real mode default value */
.long pa_machine_real_restart_gdt
@@ -130,3 +129,4 @@ machine_real_restart_gdt:
* semantics we don't have to reload the segments once CR0.PE = 0.
*/
.quad GDT_ENTRY(0x0093, 0x100, 0xffff)
+END(machine_real_restart_gdt)
diff --git a/arch/x86/realmode/rm/stack.S b/arch/x86/realmode/rm/stack.S
new file mode 100644
index 0000000..867ae87
--- /dev/null
+++ b/arch/x86/realmode/rm/stack.S
@@ -0,0 +1,19 @@
+/*
+ * Common heap and stack allocations
+ */
+
+#include <linux/linkage.h>
+
+ .data
+GLOBAL(HEAP)
+ .long rm_heap
+GLOBAL(heap_end)
+ .long rm_stack
+
+ .bss
+ .balign 16
+GLOBAL(rm_heap)
+ .space 2048
+GLOBAL(rm_stack)
+ .space 2048
+GLOBAL(rm_stack_end)
diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 279f82e..1ecdbb5 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -33,10 +33,9 @@

.text
.code16
- .globl trampoline_data

- .balign PAGE_SIZE
-trampoline_data:
+ .balign PAGE_SIZE
+ENTRY(trampoline_data)
wbinvd # Needed for NUMA-Q should be harmless for others

LJMPW_RM(1f)
@@ -70,20 +69,22 @@ trampoline_data:
ENTRY(startup_32) # note: also used from wakeup_asm.S
jmp *%eax

- .data
- .globl startup_32_smp, boot_gdt, trampoline_status
- .balign 4
-boot_gdt_descr:
- .word __BOOT_DS + 7 # gdt limit
-boot_gdt:
- .long 0 # gdt base
+ .section ".rodata","a"

+ .balign 4
boot_idt_descr:
.word 0 # idt limit = 0
.long 0 # idt base = 0L

-trampoline_status:
- .long 0
+ .data

-startup_32_smp:
- .long 0
+boot_gdt_descr:
+ .word __BOOT_DS + 7 # gdt limit
+GLOBAL(boot_gdt)
+ .long 0 # gdt base
+
+ .bss
+
+ .balign 4
+GLOBAL(trampoline_status) .space 4
+GLOBAL(startup_32_smp) .space 4
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 7459c52..195a307 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -52,7 +52,7 @@ ENTRY(trampoline_data)
# write marker for master knows we're running

# Setup stack
- movw $trampoline_stack_end, %sp
+ movl $rm_stack_end, %esp

call verify_cpu # Verify the cpu supports long mode
testl %eax, %eax # Check for return code
@@ -68,8 +68,11 @@ ENTRY(trampoline_data)
lidtl tidt # load idt with 0, 0
lgdtl tgdt # load gdt with whatever is appropriate

- mov $X86_CR0_PE, %ax # protected mode (PE) bit
- lmsw %ax # into protected mode
+ movw $__KERNEL_DS, %dx # Data segment descriptor
+
+ # Enable protected mode
+ movl $X86_CR0_PE, %eax # protected mode (PE) bit
+ movl %eax, %cr0 # into protected mode

# flush prefetch and jump to startup_32
ljmpl $__KERNEL32_CS, $pa_startup_32
@@ -83,27 +86,27 @@ no_longmode:
.code32
.balign 4
ENTRY(startup_32)
- movl $__KERNEL_DS, %eax # Initialize the %ds segment register
- movl %eax, %ds
+ movl %edx, %ss
+ addl $pa_real_mode_base, %esp
+ movl %edx, %ds
+ movl %edx, %es
+ movl %edx, %fs
+ movl %edx, %gs

movl $X86_CR4_PAE, %eax
movl %eax, %cr4 # Enable PAE mode

- movl pa_startup_64_smp, %esi
- movl pa_startup_64_smp_high, %edi
-
- # Setup trampoline 4 level pagetables
- leal pa_trampoline_level4_pgt, %eax
+ # Setup trampoline 4 level pagetables
+ movl $pa_level3_ident_pgt, %eax
movl %eax, %cr3

movl $MSR_EFER, %ecx
- movl $(1 << _EFER_LME), %eax # Enable Long Mode
+ movl $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax # Enable Long Mode
xorl %edx, %edx
wrmsr

# Enable paging and in turn activate Long Mode
- # Enable protected mode
- movl $(X86_CR0_PG | X86_CR0_PE), %eax
+ movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax
movl %eax, %cr0

/*
@@ -119,10 +122,7 @@ ENTRY(startup_32)
.balign 4
ENTRY(startup_64)
# Now jump into the kernel using virtual addresses
- movl %edi, %eax
- shlq $32, %rax
- addl %esi, %eax
- jmp *%rax
+ jmpq *startup_64_smp(%rip)

.section ".rodata","a"
.balign 16
@@ -132,10 +132,10 @@ tidt:

# Duplicate the global descriptor table
# so the kernel can live anywhere
- .balign 4
+ .balign 16
.globl tgdt
tgdt:
- .short tgdt_end - tgdt # gdt limit
+ .short tgdt_end - tgdt - 1 # gdt limit
.long pa_tgdt
.short 0
.quad 0x00cf9b000000ffff # __KERNEL32_CS
@@ -143,23 +143,12 @@ tgdt:
.quad 0x00cf93000000ffff # __KERNEL_DS
tgdt_end:

- .data
- .balign 4
-GLOBAL(trampoline_status)
- .long 0
-
-trampoline_stack:
- .org 0x1000
-trampoline_stack_end:
-
- .globl level3_ident_pgt
- .globl level3_kernel_pgt
-GLOBAL(trampoline_level4_pgt)
- level3_ident_pgt: .quad 0
- .fill 510,8,0
- level3_kernel_pgt: .quad 0
-
- .globl startup_64_smp
- .globl startup_64_smp_high
-startup_64_smp: .long 0
-startup_64_smp_high: .long 0
+ .bss
+
+ .balign PAGE_SIZE
+GLOBAL(level3_ident_pgt) .space 511*8
+GLOBAL(level3_kernel_pgt) .space 8
+
+ .balign 8
+GLOBAL(startup_64_smp) .space 8
+GLOBAL(trampoline_status) .space 4
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
index 8064e1c..f81c1cd 100644
--- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
@@ -1,6 +1,7 @@
/*
* ACPI wakeup real mode startup stub
*/
+#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/msr-index.h>
#include <asm/page_types.h>
@@ -9,31 +10,33 @@
#include "../realmode.h"
#include "wakeup.h"

- .code16
+ .code16

/* This should match the structure in wakeup.h */
- .section ".data", "aw"
- .globl wakeup_header
-wakeup_header:
-video_mode: .short 0 /* Video mode number */
-pmode_entry: .long 0
-pmode_cs: .short __KERNEL_CS
-pmode_cr0: .long 0 /* Saved %cr0 */
-pmode_cr3: .long 0 /* Saved %cr3 */
-pmode_cr4: .long 0 /* Saved %cr4 */
-pmode_efer: .quad 0 /* Saved EFER */
-pmode_gdt: .quad 0
-pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
-pmode_behavior: .long 0 /* Wakeup behavior flags */
-realmode_flags: .long 0
-real_magic: .long 0
-signature: .long WAKEUP_HEADER_SIGNATURE
- .size wakeup_header, .-wakeup_header
+ .section ".data", "aw"
+
+ .balign 16
+GLOBAL(wakeup_header)
+ video_mode: .short 0 /* Video mode number */
+ pmode_entry: .long 0
+ pmode_cs: .short __KERNEL_CS
+ pmode_cr0: .long 0 /* Saved %cr0 */
+ pmode_cr3: .long 0 /* Saved %cr3 */
+ pmode_cr4: .long 0 /* Saved %cr4 */
+ pmode_efer: .quad 0 /* Saved EFER */
+ pmode_gdt: .quad 0
+ pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
+ pmode_behavior: .long 0 /* Wakeup behavior flags */
+ realmode_flags: .long 0
+ real_magic: .long 0
+ signature: .long WAKEUP_HEADER_SIGNATURE
+END(wakeup_header)

.text
.code16
- .globl wakeup_start
-wakeup_start:
+
+ .balign 16
+ENTRY(wakeup_start)
cli
cld

@@ -62,12 +65,14 @@ wakeup_start:
3:
/* Set up segments */
movw %cs, %ax
+ movw %ax, %ss
+ movl $rm_stack_end, %esp
movw %ax, %ds
movw %ax, %es
- movw %ax, %ss
- lidtl wakeup_idt
+ movw %ax, %fs
+ movw %ax, %gs

- movl $wakeup_stack_end, %esp
+ lidtl wakeup_idt

/* Clear the EFLAGS */
pushl $0
@@ -145,9 +150,8 @@ bogus_real_magic:
* be the case for other laptops or integrated video devices.
*/

- .globl wakeup_gdt
.balign 16
-wakeup_gdt:
+GLOBAL(wakeup_gdt)
.word 3*8-1 /* Self-descriptor */
.long pa_wakeup_gdt
.word 0
@@ -159,29 +163,18 @@ wakeup_gdt:
.word 0xffff /* 16-bit data segment @ real_mode_base */
.long 0x93000000 + pa_real_mode_base
.word 0x008f /* big real mode */
- .size wakeup_gdt, .-wakeup_gdt
+END(wakeup_gdt)

- .data
+ .section ".rodata","a"
.balign 8

/* This is the standard real-mode IDT */
-wakeup_idt:
+ .balign 16
+GLOBAL(wakeup_idt)
.word 0xffff /* limit */
.long 0 /* address */
.word 0
-
- .globl HEAP, heap_end
-HEAP:
- .long wakeup_heap
-heap_end:
- .long wakeup_stack
-
- .bss
-wakeup_heap:
- .space 2048
-wakeup_stack:
- .space 2048
-wakeup_stack_end:
+END(wakeup_idt)

.section ".signature","a"
end_signature:
diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S
index 6047d7f..fd72a99 100644
--- a/arch/x86/realmode/rmpiggy.S
+++ b/arch/x86/realmode/rmpiggy.S
@@ -9,10 +9,10 @@

.balign PAGE_SIZE

-ENTRY(real_mode_blob)
+GLOBAL(real_mode_blob)
.incbin "arch/x86/realmode/rm/realmode.bin"
END(real_mode_blob)

-ENTRY(real_mode_relocs)
+GLOBAL(real_mode_relocs)
.incbin "arch/x86/realmode/rm/realmode.relocs"
END(real_mode_relocs)
--
1.7.9.5

2012-05-08 18:25:10

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 20/23] x86, realmode: header for trampoline code

Added header for trampoline code that can be used to supply
input data to it. This makes interface between real mode code
and kernel cleaner and simpler. Replaced two confusing pointers
to level4 pgt in trampoline_64.S with a single pointer to the
beginning of the page table.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/include/asm/realmode.h | 32 ++++++++++++++++----------
arch/x86/kernel/realmode.c | 27 ++++++++++++----------
arch/x86/kernel/smpboot.c | 2 +-
arch/x86/realmode/rm/header.S | 35 +++++++++++++----------------
arch/x86/realmode/rm/trampoline_32.S | 36 +++++-------------------------
arch/x86/realmode/rm/trampoline_64.S | 18 +++++----------
arch/x86/realmode/rm/trampoline_common.S | 23 +++++++++++++++++++
arch/x86/realmode/rm/wakeup_asm.S | 2 +-
8 files changed, 87 insertions(+), 88 deletions(-)
create mode 100644 arch/x86/realmode/rm/trampoline_common.S

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index d3ae49f..1421eed 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -8,25 +8,33 @@
struct real_mode_header {
u32 text_start;
u32 ro_end;
- /* reboot */
-#ifdef CONFIG_X86_32
- u32 machine_real_restart_asm;
-#endif
/* SMP trampoline */
- u32 trampoline_data;
+ u32 trampoline_start;
u32 trampoline_status;
-#ifdef CONFIG_X86_32
- u32 startup_32_smp;
- u32 boot_gdt;
-#else
- u32 startup_64_smp;
- u32 level3_ident_pgt;
- u32 level3_kernel_pgt;
+ u32 trampoline_header;
+#ifdef CONFIG_X86_64
+ u32 trampoline_pgd;
#endif
+ /* ACPI S3 wakeup */
#ifdef CONFIG_ACPI_SLEEP
u32 wakeup_start;
u32 wakeup_header;
#endif
+ /* APM/BIOS reboot */
+#ifdef CONFIG_X86_32
+ u32 machine_real_restart_asm;
+#endif
+} __attribute__((__packed__));
+
+/* This must match data at trampoline_32/64.S */
+struct trampoline_header {
+#ifdef CONFIG_X86_32
+ u32 start;
+ u16 gdt_limit;
+ u32 gdt_base;
+#else
+ u64 start;
+#endif
} __attribute__((__packed__));

extern struct real_mode_header *real_mode_header;
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index 632c810..712fba8 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -17,8 +17,11 @@ void __init setup_real_mode(void)
u16 *seg;
int i;
unsigned char *base;
-
+ struct trampoline_header *trampoline_header;
size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
+#ifdef CONFIG_X86_64
+ u64 *trampoline_pgd;
+#endif

/* Has to be in very low memory so we can execute real-mode AP code. */
mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
@@ -28,7 +31,6 @@ void __init setup_real_mode(void)
base = __va(mem);
memblock_reserve(mem, size);
real_mode_header = (struct real_mode_header *) base;
-
printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
base, (unsigned long long)mem, size);

@@ -53,18 +55,19 @@ void __init setup_real_mode(void)
*ptr += __pa(base);
}

+ /* Must be perfomed *after* relocation. */
+ trampoline_header = (struct trampoline_header *)
+ __va(real_mode_header->trampoline_header);
+
#ifdef CONFIG_X86_32
- *((u32 *)__va(real_mode_header->startup_32_smp)) = __pa(startup_32_smp);
- *((u32 *)__va(real_mode_header->boot_gdt)) = __pa(boot_gdt);
+ trampoline_header->start = __pa(startup_32_smp);
+ trampoline_header->gdt_limit = __BOOT_DS + 7;
+ trampoline_header->gdt_base = __pa(boot_gdt);
#else
- *((u64 *) __va(real_mode_header->startup_64_smp)) =
- (u64)secondary_startup_64;
-
- *((u64 *) __va(real_mode_header->level3_ident_pgt)) =
- __pa(level3_ident_pgt) + _KERNPG_TABLE;
-
- *((u64 *) __va(real_mode_header->level3_kernel_pgt)) =
- __pa(level3_kernel_pgt) + _KERNPG_TABLE;
+ trampoline_header->start = (u64) secondary_startup_64;
+ trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
+ trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE;
+ trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE;
#endif
}

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index b8c0661..757c4b1 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -667,7 +667,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
volatile u32 *trampoline_status =
(volatile u32 *) __va(real_mode_header->trampoline_status);
/* start_ip had better be page-aligned! */
- unsigned long start_ip = real_mode_header->trampoline_data;
+ unsigned long start_ip = real_mode_header->trampoline_start;

unsigned long boot_error = 0;
int timeout;
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index c83005c..b4c3263 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -7,28 +7,25 @@
#include <linux/linkage.h>
#include <asm/page_types.h>

- .section ".header", "a"
+ .section ".header", "a"

GLOBAL(real_mode_header)
- .long pa_text_start
- .long pa_ro_end
-#ifdef CONFIG_X86_32
- .long pa_machine_real_restart_asm
-#endif
- /* SMP trampoline */
- .long pa_trampoline_data
- .long pa_trampoline_status
-#ifdef CONFIG_X86_32
- .long pa_startup_32_smp
- .long pa_boot_gdt
-#else
- .long pa_startup_64_smp
- .long pa_level3_ident_pgt
- .long pa_level3_kernel_pgt
+ .long pa_text_start
+ .long pa_ro_end
+ /* SMP trampoline */
+ .long pa_trampoline_start
+ .long pa_trampoline_status
+ .long pa_trampoline_header
+#ifdef CONFIG_X86_64
+ .long pa_trampoline_pgd;
#endif
- /* ACPI sleep */
+ /* ACPI S3 wakeup */
#ifdef CONFIG_ACPI_SLEEP
- .long pa_wakeup_start
- .long pa_wakeup_header
+ .long pa_wakeup_start
+ .long pa_wakeup_header
+#endif
+ /* APM/BIOS reboot */
+#ifdef CONFIG_X86_32
+ .long pa_machine_real_restart_asm
#endif
END(real_mode_header)
diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 1ecdbb5..6fc064b 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -13,16 +13,10 @@
*
* We jump into arch/x86/kernel/head_32.S.
*
- * On entry to trampoline_data, the processor is in real mode
+ * On entry to trampoline_start, the processor is in real mode
* with 16-bit addressing and 16-bit data. CS has some value
* and IP is zero. Thus, we load CS to the physical segment
* of the real mode code before doing anything further.
- *
- * The structure real_mode_header includes entries that need
- * to be set up before executing this code:
- *
- * startup_32_smp
- * boot_gdt
*/

#include <linux/linkage.h>
@@ -35,7 +29,7 @@
.code16

.balign PAGE_SIZE
-ENTRY(trampoline_data)
+ENTRY(trampoline_start)
wbinvd # Needed for NUMA-Q should be harmless for others

LJMPW_RM(1f)
@@ -45,7 +39,7 @@ ENTRY(trampoline_data)

cli # We should be safe anyway

- movl startup_32_smp, %eax # where we need to go
+ movl tr_start, %eax # where we need to go

movl $0xA5A5A5A5, trampoline_status
# write marker for master knows we're running
@@ -56,8 +50,8 @@ ENTRY(trampoline_data)
* operand size is 16bit. Use lgdtl instead to force operand size
* to 32 bit.
*/
- lidtl boot_idt_descr # load idt with 0, 0
- lgdtl boot_gdt_descr # load gdt with whatever is appropriate
+ lidtl tr_idt # load idt with 0, 0
+ lgdtl tr_gdt # load gdt with whatever is appropriate

movw $1, %dx # protected mode (PE) bit
lmsw %dx # into protected mode
@@ -69,22 +63,4 @@ ENTRY(trampoline_data)
ENTRY(startup_32) # note: also used from wakeup_asm.S
jmp *%eax

- .section ".rodata","a"
-
- .balign 4
-boot_idt_descr:
- .word 0 # idt limit = 0
- .long 0 # idt base = 0L
-
- .data
-
-boot_gdt_descr:
- .word __BOOT_DS + 7 # gdt limit
-GLOBAL(boot_gdt)
- .long 0 # gdt base
-
- .bss
-
- .balign 4
-GLOBAL(trampoline_status) .space 4
-GLOBAL(startup_32_smp) .space 4
+#include "trampoline_common.S"
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 195a307..c4a60d1 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -10,7 +10,7 @@
* trampoline page to make our stack and everything else
* is a mystery.
*
- * On entry to trampoline_data, the processor is in real mode
+ * On entry to trampoline_start, the processor is in real mode
* with 16-bit addressing and 16-bit data. CS has some value
* and IP is zero. Thus, data addresses need to be absolute
* (no relocation) and are taken with regard to r_base.
@@ -37,7 +37,7 @@
.balign PAGE_SIZE
.code16

-ENTRY(trampoline_data)
+ENTRY(trampoline_start)
cli # We should be safe anyway
wbinvd

@@ -97,7 +97,7 @@ ENTRY(startup_32)
movl %eax, %cr4 # Enable PAE mode

# Setup trampoline 4 level pagetables
- movl $pa_level3_ident_pgt, %eax
+ movl $pa_trampoline_pgd, %eax
movl %eax, %cr3

movl $MSR_EFER, %ecx
@@ -122,7 +122,7 @@ ENTRY(startup_32)
.balign 4
ENTRY(startup_64)
# Now jump into the kernel using virtual addresses
- jmpq *startup_64_smp(%rip)
+ jmpq *tr_start(%rip)

.section ".rodata","a"
.balign 16
@@ -143,12 +143,4 @@ tgdt:
.quad 0x00cf93000000ffff # __KERNEL_DS
tgdt_end:

- .bss
-
- .balign PAGE_SIZE
-GLOBAL(level3_ident_pgt) .space 511*8
-GLOBAL(level3_kernel_pgt) .space 8
-
- .balign 8
-GLOBAL(startup_64_smp) .space 8
-GLOBAL(trampoline_status) .space 4
+#include "trampoline_common.S"
diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S
new file mode 100644
index 0000000..c3f951c
--- /dev/null
+++ b/arch/x86/realmode/rm/trampoline_common.S
@@ -0,0 +1,23 @@
+ .section ".rodata","a"
+
+ .balign 4
+tr_idt: .fill 1, 6, 0
+
+ .bss
+
+ .balign 4
+GLOBAL(trampoline_status) .space 4
+
+GLOBAL(trampoline_header)
+#ifdef CONFIG_X86_32
+ tr_start: .space 4
+ tr_gdt: .space 6
+#else
+ tr_start: .space 8
+#endif
+END(trampoline_header)
+
+#ifdef CONFIG_X86_64
+ .balign PAGE_SIZE
+GLOBAL(trampoline_pgd) .space PAGE_SIZE
+#endif
diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S
index 8a57c5a..46108f0 100644
--- a/arch/x86/realmode/rm/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup_asm.S
@@ -132,7 +132,7 @@ ENTRY(wakeup_start)
ljmpl $__KERNEL_CS, $pa_startup_32
/* -> jmp *%eax in trampoline_32.S */
#else
- jmp trampoline_data
+ jmp trampoline_start
#endif

bogus_real_magic:
--
1.7.9.5

2012-05-08 18:25:08

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 19/23] x86, realmode: flattened rm hierachy

Simplified hierarchy under rm directory to a flat
directory because it is not anymore really justified
to have own directory for wakeup code. It only adds
more complexity.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/kernel/acpi/sleep.c | 2 +-
arch/x86/realmode/rm/Makefile | 20 ++--
arch/x86/realmode/rm/bioscall.S | 1 +
arch/x86/realmode/rm/copy.S | 1 +
arch/x86/realmode/rm/regs.c | 1 +
arch/x86/realmode/rm/video-bios.c | 1 +
arch/x86/realmode/rm/video-mode.c | 1 +
arch/x86/realmode/rm/video-vesa.c | 1 +
arch/x86/realmode/rm/video-vga.c | 1 +
arch/x86/realmode/rm/wakemain.c | 82 ++++++++++++++
arch/x86/realmode/rm/wakeup.h | 41 +++++++
arch/x86/realmode/rm/wakeup/.gitignore | 3 -
arch/x86/realmode/rm/wakeup/Makefile | 33 ------
arch/x86/realmode/rm/wakeup/bioscall.S | 1 -
arch/x86/realmode/rm/wakeup/copy.S | 1 -
arch/x86/realmode/rm/wakeup/regs.c | 1 -
arch/x86/realmode/rm/wakeup/video-bios.c | 1 -
arch/x86/realmode/rm/wakeup/video-mode.c | 1 -
arch/x86/realmode/rm/wakeup/video-vesa.c | 1 -
arch/x86/realmode/rm/wakeup/video-vga.c | 1 -
arch/x86/realmode/rm/wakeup/wakemain.c | 82 --------------
arch/x86/realmode/rm/wakeup/wakeup.h | 41 -------
arch/x86/realmode/rm/wakeup/wakeup_asm.S | 181 ------------------------------
arch/x86/realmode/rm/wakeup_asm.S | 181 ++++++++++++++++++++++++++++++
24 files changed, 325 insertions(+), 355 deletions(-)
create mode 100644 arch/x86/realmode/rm/bioscall.S
create mode 100644 arch/x86/realmode/rm/copy.S
create mode 100644 arch/x86/realmode/rm/regs.c
create mode 100644 arch/x86/realmode/rm/video-bios.c
create mode 100644 arch/x86/realmode/rm/video-mode.c
create mode 100644 arch/x86/realmode/rm/video-vesa.c
create mode 100644 arch/x86/realmode/rm/video-vga.c
create mode 100644 arch/x86/realmode/rm/wakemain.c
create mode 100644 arch/x86/realmode/rm/wakeup.h
delete mode 100644 arch/x86/realmode/rm/wakeup/.gitignore
delete mode 100644 arch/x86/realmode/rm/wakeup/Makefile
delete mode 100644 arch/x86/realmode/rm/wakeup/bioscall.S
delete mode 100644 arch/x86/realmode/rm/wakeup/copy.S
delete mode 100644 arch/x86/realmode/rm/wakeup/regs.c
delete mode 100644 arch/x86/realmode/rm/wakeup/video-bios.c
delete mode 100644 arch/x86/realmode/rm/wakeup/video-mode.c
delete mode 100644 arch/x86/realmode/rm/wakeup/video-vesa.c
delete mode 100644 arch/x86/realmode/rm/wakeup/video-vga.c
delete mode 100644 arch/x86/realmode/rm/wakeup/wakemain.c
delete mode 100644 arch/x86/realmode/rm/wakeup/wakeup.h
delete mode 100644 arch/x86/realmode/rm/wakeup/wakeup_asm.S
create mode 100644 arch/x86/realmode/rm/wakeup_asm.S

diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 5250475..1b8e5a0 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -16,7 +16,7 @@
#include <asm/cacheflush.h>
#include <asm/realmode.h>

-#include "../../realmode/rm/wakeup/wakeup.h"
+#include "../../realmode/rm/wakeup.h"
#include "sleep.h"

unsigned long acpi_realmode_flags;
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index c2c27a4..fc8854b 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -7,21 +7,26 @@
#
#

-subdir- := wakeup
-
always := realmode.bin

realmode-y += header.o
realmode-y += trampoline_$(BITS).o
realmode-y += stack.o
realmode-$(CONFIG_X86_32) += reboot_32.o
-realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o
+realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs)
+
+wakeup-objs := wakeup_asm.o wakemain.o video-mode.o
+wakeup-objs += copy.o bioscall.o regs.o
+# The link order of the video-*.o modules can matter. In particular,
+# video-vga.o *must* be listed first, followed by video-vesa.o.
+# Hardware-specific drivers should follow in the order they should be
+# probed, and video-bios.o should typically be last.
+wakeup-objs += video-vga.o
+wakeup-objs += video-vesa.o
+wakeup-objs += video-bios.o

targets += $(realmode-y)

-$(obj)/wakeup/wakeup.o: FORCE
- $(Q)$(MAKE) $(build)=$(obj)/wakeup $@
-
REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y))

sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p'
@@ -55,7 +60,8 @@ $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE

# How to compile the 16-bit code. Note we always compile for -march=i386,
# that way we can complain to the user if the CPU is insufficient.
-KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \
+KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ -D_WAKEUP \
+ -I$(srctree)/arch/x86/boot \
-DDISABLE_BRANCH_PROFILING \
-Wall -Wstrict-prototypes \
-march=i386 -mregparm=3 \
diff --git a/arch/x86/realmode/rm/bioscall.S b/arch/x86/realmode/rm/bioscall.S
new file mode 100644
index 0000000..16162d1
--- /dev/null
+++ b/arch/x86/realmode/rm/bioscall.S
@@ -0,0 +1 @@
+#include "../../boot/bioscall.S"
diff --git a/arch/x86/realmode/rm/copy.S b/arch/x86/realmode/rm/copy.S
new file mode 100644
index 0000000..b785e6f
--- /dev/null
+++ b/arch/x86/realmode/rm/copy.S
@@ -0,0 +1 @@
+#include "../../boot/copy.S"
diff --git a/arch/x86/realmode/rm/regs.c b/arch/x86/realmode/rm/regs.c
new file mode 100644
index 0000000..fbb15b9
--- /dev/null
+++ b/arch/x86/realmode/rm/regs.c
@@ -0,0 +1 @@
+#include "../../boot/regs.c"
diff --git a/arch/x86/realmode/rm/video-bios.c b/arch/x86/realmode/rm/video-bios.c
new file mode 100644
index 0000000..848b25a
--- /dev/null
+++ b/arch/x86/realmode/rm/video-bios.c
@@ -0,0 +1 @@
+#include "../../boot/video-bios.c"
diff --git a/arch/x86/realmode/rm/video-mode.c b/arch/x86/realmode/rm/video-mode.c
new file mode 100644
index 0000000..2a98b7e
--- /dev/null
+++ b/arch/x86/realmode/rm/video-mode.c
@@ -0,0 +1 @@
+#include "../../boot/video-mode.c"
diff --git a/arch/x86/realmode/rm/video-vesa.c b/arch/x86/realmode/rm/video-vesa.c
new file mode 100644
index 0000000..413eddd
--- /dev/null
+++ b/arch/x86/realmode/rm/video-vesa.c
@@ -0,0 +1 @@
+#include "../../boot/video-vesa.c"
diff --git a/arch/x86/realmode/rm/video-vga.c b/arch/x86/realmode/rm/video-vga.c
new file mode 100644
index 0000000..3085f5c
--- /dev/null
+++ b/arch/x86/realmode/rm/video-vga.c
@@ -0,0 +1 @@
+#include "../../boot/video-vga.c"
diff --git a/arch/x86/realmode/rm/wakemain.c b/arch/x86/realmode/rm/wakemain.c
new file mode 100644
index 0000000..91405d5
--- /dev/null
+++ b/arch/x86/realmode/rm/wakemain.c
@@ -0,0 +1,82 @@
+#include "wakeup.h"
+#include "boot.h"
+
+static void udelay(int loops)
+{
+ while (loops--)
+ io_delay(); /* Approximately 1 us */
+}
+
+static void beep(unsigned int hz)
+{
+ u8 enable;
+
+ if (!hz) {
+ enable = 0x00; /* Turn off speaker */
+ } else {
+ u16 div = 1193181/hz;
+
+ outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */
+ io_delay();
+ outb(div, 0x42); /* LSB of counter */
+ io_delay();
+ outb(div >> 8, 0x42); /* MSB of counter */
+ io_delay();
+
+ enable = 0x03; /* Turn on speaker */
+ }
+ inb(0x61); /* Dummy read of System Control Port B */
+ io_delay();
+ outb(enable, 0x61); /* Enable timer 2 output to speaker */
+ io_delay();
+}
+
+#define DOT_HZ 880
+#define DASH_HZ 587
+#define US_PER_DOT 125000
+
+/* Okay, this is totally silly, but it's kind of fun. */
+static void send_morse(const char *pattern)
+{
+ char s;
+
+ while ((s = *pattern++)) {
+ switch (s) {
+ case '.':
+ beep(DOT_HZ);
+ udelay(US_PER_DOT);
+ beep(0);
+ udelay(US_PER_DOT);
+ break;
+ case '-':
+ beep(DASH_HZ);
+ udelay(US_PER_DOT * 3);
+ beep(0);
+ udelay(US_PER_DOT);
+ break;
+ default: /* Assume it's a space */
+ udelay(US_PER_DOT * 3);
+ break;
+ }
+ }
+}
+
+void main(void)
+{
+ /* Kill machine if structures are wrong */
+ if (wakeup_header.real_magic != 0x12345678)
+ while (1)
+ ;
+
+ if (wakeup_header.realmode_flags & 4)
+ send_morse("...-");
+
+ if (wakeup_header.realmode_flags & 1)
+ asm volatile("lcallw $0xc000,$3");
+
+ if (wakeup_header.realmode_flags & 2) {
+ /* Need to call BIOS */
+ probe_cards(0);
+ set_mode(wakeup_header.video_mode);
+ }
+}
diff --git a/arch/x86/realmode/rm/wakeup.h b/arch/x86/realmode/rm/wakeup.h
new file mode 100644
index 0000000..2dfaf06
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup.h
@@ -0,0 +1,41 @@
+/*
+ * Definitions for the wakeup data structure at the head of the
+ * wakeup code.
+ */
+
+#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
+#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+
+/* This must match data at wakeup.S */
+struct wakeup_header {
+ u16 video_mode; /* Video mode number */
+ u32 pmode_entry; /* Protected mode resume point, 32-bit only */
+ u16 pmode_cs;
+ u32 pmode_cr0; /* Protected mode cr0 */
+ u32 pmode_cr3; /* Protected mode cr3 */
+ u32 pmode_cr4; /* Protected mode cr4 */
+ u32 pmode_efer_low; /* Protected mode EFER */
+ u32 pmode_efer_high;
+ u64 pmode_gdt;
+ u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */
+ u32 pmode_misc_en_high;
+ u32 pmode_behavior; /* Wakeup routine behavior flags */
+ u32 realmode_flags;
+ u32 real_magic;
+ u32 signature; /* To check we have correct structure */
+} __attribute__((__packed__));
+
+extern struct wakeup_header wakeup_header;
+#endif
+
+#define WAKEUP_HEADER_OFFSET 8
+#define WAKEUP_HEADER_SIGNATURE 0x51ee1111
+#define WAKEUP_END_SIGNATURE 0x65a22c82
+
+/* Wakeup behavior bits */
+#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0
+
+#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/realmode/rm/wakeup/.gitignore b/arch/x86/realmode/rm/wakeup/.gitignore
deleted file mode 100644
index 58f1f48..0000000
--- a/arch/x86/realmode/rm/wakeup/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-wakeup.bin
-wakeup.elf
-wakeup.lds
diff --git a/arch/x86/realmode/rm/wakeup/Makefile b/arch/x86/realmode/rm/wakeup/Makefile
deleted file mode 100644
index 4c85332..0000000
--- a/arch/x86/realmode/rm/wakeup/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# arch/x86/kernel/acpi/realmode/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-
-always := wakeup.o
-
-wakeup-y += wakeup_asm.o wakemain.o video-mode.o
-wakeup-y += copy.o bioscall.o regs.o
-
-# The link order of the video-*.o modules can matter. In particular,
-# video-vga.o *must* be listed first, followed by video-vesa.o.
-# Hardware-specific drivers should follow in the order they should be
-# probed, and video-bios.o should typically be last.
-wakeup-y += video-vga.o
-wakeup-y += video-vesa.o
-wakeup-y += video-bios.o
-
-targets += $(wakeup-y)
-
-WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
-
-LDFLAGS_wakeup.o := -m elf_i386 -r
-$(obj)/wakeup.o: $(WAKEUP_OBJS) FORCE
- $(call if_changed,ld)
-
-bootsrc := $(src)/../../../boot
-
-ccflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc)
-asflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc)
diff --git a/arch/x86/realmode/rm/wakeup/bioscall.S b/arch/x86/realmode/rm/wakeup/bioscall.S
deleted file mode 100644
index f51eb0b..0000000
--- a/arch/x86/realmode/rm/wakeup/bioscall.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/bioscall.S"
diff --git a/arch/x86/realmode/rm/wakeup/copy.S b/arch/x86/realmode/rm/wakeup/copy.S
deleted file mode 100644
index dc59ebe..0000000
--- a/arch/x86/realmode/rm/wakeup/copy.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/copy.S"
diff --git a/arch/x86/realmode/rm/wakeup/regs.c b/arch/x86/realmode/rm/wakeup/regs.c
deleted file mode 100644
index 6206033..0000000
--- a/arch/x86/realmode/rm/wakeup/regs.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/regs.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-bios.c b/arch/x86/realmode/rm/wakeup/video-bios.c
deleted file mode 100644
index 7deabc1..0000000
--- a/arch/x86/realmode/rm/wakeup/video-bios.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-bios.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-mode.c b/arch/x86/realmode/rm/wakeup/video-mode.c
deleted file mode 100644
index 328ad20..0000000
--- a/arch/x86/realmode/rm/wakeup/video-mode.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-mode.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-vesa.c b/arch/x86/realmode/rm/wakeup/video-vesa.c
deleted file mode 100644
index 9dbb967..0000000
--- a/arch/x86/realmode/rm/wakeup/video-vesa.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-vesa.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-vga.c b/arch/x86/realmode/rm/wakeup/video-vga.c
deleted file mode 100644
index bcc8125..0000000
--- a/arch/x86/realmode/rm/wakeup/video-vga.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-vga.c"
diff --git a/arch/x86/realmode/rm/wakeup/wakemain.c b/arch/x86/realmode/rm/wakeup/wakemain.c
deleted file mode 100644
index 91405d5..0000000
--- a/arch/x86/realmode/rm/wakeup/wakemain.c
+++ /dev/null
@@ -1,82 +0,0 @@
-#include "wakeup.h"
-#include "boot.h"
-
-static void udelay(int loops)
-{
- while (loops--)
- io_delay(); /* Approximately 1 us */
-}
-
-static void beep(unsigned int hz)
-{
- u8 enable;
-
- if (!hz) {
- enable = 0x00; /* Turn off speaker */
- } else {
- u16 div = 1193181/hz;
-
- outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */
- io_delay();
- outb(div, 0x42); /* LSB of counter */
- io_delay();
- outb(div >> 8, 0x42); /* MSB of counter */
- io_delay();
-
- enable = 0x03; /* Turn on speaker */
- }
- inb(0x61); /* Dummy read of System Control Port B */
- io_delay();
- outb(enable, 0x61); /* Enable timer 2 output to speaker */
- io_delay();
-}
-
-#define DOT_HZ 880
-#define DASH_HZ 587
-#define US_PER_DOT 125000
-
-/* Okay, this is totally silly, but it's kind of fun. */
-static void send_morse(const char *pattern)
-{
- char s;
-
- while ((s = *pattern++)) {
- switch (s) {
- case '.':
- beep(DOT_HZ);
- udelay(US_PER_DOT);
- beep(0);
- udelay(US_PER_DOT);
- break;
- case '-':
- beep(DASH_HZ);
- udelay(US_PER_DOT * 3);
- beep(0);
- udelay(US_PER_DOT);
- break;
- default: /* Assume it's a space */
- udelay(US_PER_DOT * 3);
- break;
- }
- }
-}
-
-void main(void)
-{
- /* Kill machine if structures are wrong */
- if (wakeup_header.real_magic != 0x12345678)
- while (1)
- ;
-
- if (wakeup_header.realmode_flags & 4)
- send_morse("...-");
-
- if (wakeup_header.realmode_flags & 1)
- asm volatile("lcallw $0xc000,$3");
-
- if (wakeup_header.realmode_flags & 2) {
- /* Need to call BIOS */
- probe_cards(0);
- set_mode(wakeup_header.video_mode);
- }
-}
diff --git a/arch/x86/realmode/rm/wakeup/wakeup.h b/arch/x86/realmode/rm/wakeup/wakeup.h
deleted file mode 100644
index 2dfaf06..0000000
--- a/arch/x86/realmode/rm/wakeup/wakeup.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Definitions for the wakeup data structure at the head of the
- * wakeup code.
- */
-
-#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
-#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
-
-#ifndef __ASSEMBLY__
-#include <linux/types.h>
-
-/* This must match data at wakeup.S */
-struct wakeup_header {
- u16 video_mode; /* Video mode number */
- u32 pmode_entry; /* Protected mode resume point, 32-bit only */
- u16 pmode_cs;
- u32 pmode_cr0; /* Protected mode cr0 */
- u32 pmode_cr3; /* Protected mode cr3 */
- u32 pmode_cr4; /* Protected mode cr4 */
- u32 pmode_efer_low; /* Protected mode EFER */
- u32 pmode_efer_high;
- u64 pmode_gdt;
- u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */
- u32 pmode_misc_en_high;
- u32 pmode_behavior; /* Wakeup routine behavior flags */
- u32 realmode_flags;
- u32 real_magic;
- u32 signature; /* To check we have correct structure */
-} __attribute__((__packed__));
-
-extern struct wakeup_header wakeup_header;
-#endif
-
-#define WAKEUP_HEADER_OFFSET 8
-#define WAKEUP_HEADER_SIGNATURE 0x51ee1111
-#define WAKEUP_END_SIGNATURE 0x65a22c82
-
-/* Wakeup behavior bits */
-#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0
-
-#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
deleted file mode 100644
index f81c1cd..0000000
--- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * ACPI wakeup real mode startup stub
- */
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/msr-index.h>
-#include <asm/page_types.h>
-#include <asm/pgtable_types.h>
-#include <asm/processor-flags.h>
-#include "../realmode.h"
-#include "wakeup.h"
-
- .code16
-
-/* This should match the structure in wakeup.h */
- .section ".data", "aw"
-
- .balign 16
-GLOBAL(wakeup_header)
- video_mode: .short 0 /* Video mode number */
- pmode_entry: .long 0
- pmode_cs: .short __KERNEL_CS
- pmode_cr0: .long 0 /* Saved %cr0 */
- pmode_cr3: .long 0 /* Saved %cr3 */
- pmode_cr4: .long 0 /* Saved %cr4 */
- pmode_efer: .quad 0 /* Saved EFER */
- pmode_gdt: .quad 0
- pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
- pmode_behavior: .long 0 /* Wakeup behavior flags */
- realmode_flags: .long 0
- real_magic: .long 0
- signature: .long WAKEUP_HEADER_SIGNATURE
-END(wakeup_header)
-
- .text
- .code16
-
- .balign 16
-ENTRY(wakeup_start)
- cli
- cld
-
- LJMPW_RM(3f)
-3:
- /* Apparently some dimwit BIOS programmers don't know how to
- program a PM to RM transition, and we might end up here with
- junk in the data segment descriptor registers. The only way
- to repair that is to go into PM and fix it ourselves... */
- movw $16, %cx
- lgdtl %cs:wakeup_gdt
- movl %cr0, %eax
- orb $X86_CR0_PE, %al
- movl %eax, %cr0
- ljmpw $8, $2f
-2:
- movw %cx, %ds
- movw %cx, %es
- movw %cx, %ss
- movw %cx, %fs
- movw %cx, %gs
-
- andb $~X86_CR0_PE, %al
- movl %eax, %cr0
- LJMPW_RM(3f)
-3:
- /* Set up segments */
- movw %cs, %ax
- movw %ax, %ss
- movl $rm_stack_end, %esp
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %fs
- movw %ax, %gs
-
- lidtl wakeup_idt
-
- /* Clear the EFLAGS */
- pushl $0
- popfl
-
- /* Check header signature... */
- movl signature, %eax
- cmpl $WAKEUP_HEADER_SIGNATURE, %eax
- jne bogus_real_magic
-
- /* Check we really have everything... */
- movl end_signature, %eax
- cmpl $WAKEUP_END_SIGNATURE, %eax
- jne bogus_real_magic
-
- /* Call the C code */
- calll main
-
- /* Restore MISC_ENABLE before entering protected mode, in case
- BIOS decided to clear XD_DISABLE during S3. */
- movl pmode_behavior, %eax
- btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
- jnc 1f
-
- movl pmode_misc_en, %eax
- movl pmode_misc_en + 4, %edx
- movl $MSR_IA32_MISC_ENABLE, %ecx
- wrmsr
-1:
-
- /* Do any other stuff... */
-
-#ifndef CONFIG_64BIT
- /* This could also be done in C code... */
- movl pmode_cr3, %eax
- movl %eax, %cr3
-
- movl pmode_cr4, %ecx
- jecxz 1f
- movl %ecx, %cr4
-1:
- movl pmode_efer, %eax
- movl pmode_efer + 4, %edx
- movl %eax, %ecx
- orl %edx, %ecx
- jz 1f
- movl $MSR_EFER, %ecx
- wrmsr
-1:
-
- lgdtl pmode_gdt
-
- /* This really couldn't... */
- movl pmode_entry, %eax
- movl pmode_cr0, %ecx
- movl %ecx, %cr0
- ljmpl $__KERNEL_CS, $pa_startup_32
- /* -> jmp *%eax in trampoline_32.S */
-#else
- jmp trampoline_data
-#endif
-
-bogus_real_magic:
-1:
- hlt
- jmp 1b
-
- .section ".rodata","a"
-
- /*
- * Set up the wakeup GDT. We set these up as Big Real Mode,
- * that is, with limits set to 4 GB. At least the Lenovo
- * Thinkpad X61 is known to need this for the video BIOS
- * initialization quirk to work; this is likely to also
- * be the case for other laptops or integrated video devices.
- */
-
- .balign 16
-GLOBAL(wakeup_gdt)
- .word 3*8-1 /* Self-descriptor */
- .long pa_wakeup_gdt
- .word 0
-
- .word 0xffff /* 16-bit code segment @ real_mode_base */
- .long 0x9b000000 + pa_real_mode_base
- .word 0x008f /* big real mode */
-
- .word 0xffff /* 16-bit data segment @ real_mode_base */
- .long 0x93000000 + pa_real_mode_base
- .word 0x008f /* big real mode */
-END(wakeup_gdt)
-
- .section ".rodata","a"
- .balign 8
-
- /* This is the standard real-mode IDT */
- .balign 16
-GLOBAL(wakeup_idt)
- .word 0xffff /* limit */
- .long 0 /* address */
- .word 0
-END(wakeup_idt)
-
- .section ".signature","a"
-end_signature:
- .long WAKEUP_END_SIGNATURE
diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S
new file mode 100644
index 0000000..8a57c5a
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup_asm.S
@@ -0,0 +1,181 @@
+/*
+ * ACPI wakeup real mode startup stub
+ */
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/msr-index.h>
+#include <asm/page_types.h>
+#include <asm/pgtable_types.h>
+#include <asm/processor-flags.h>
+#include "realmode.h"
+#include "wakeup.h"
+
+ .code16
+
+/* This should match the structure in wakeup.h */
+ .section ".data", "aw"
+
+ .balign 16
+GLOBAL(wakeup_header)
+ video_mode: .short 0 /* Video mode number */
+ pmode_entry: .long 0
+ pmode_cs: .short __KERNEL_CS
+ pmode_cr0: .long 0 /* Saved %cr0 */
+ pmode_cr3: .long 0 /* Saved %cr3 */
+ pmode_cr4: .long 0 /* Saved %cr4 */
+ pmode_efer: .quad 0 /* Saved EFER */
+ pmode_gdt: .quad 0
+ pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
+ pmode_behavior: .long 0 /* Wakeup behavior flags */
+ realmode_flags: .long 0
+ real_magic: .long 0
+ signature: .long WAKEUP_HEADER_SIGNATURE
+END(wakeup_header)
+
+ .text
+ .code16
+
+ .balign 16
+ENTRY(wakeup_start)
+ cli
+ cld
+
+ LJMPW_RM(3f)
+3:
+ /* Apparently some dimwit BIOS programmers don't know how to
+ program a PM to RM transition, and we might end up here with
+ junk in the data segment descriptor registers. The only way
+ to repair that is to go into PM and fix it ourselves... */
+ movw $16, %cx
+ lgdtl %cs:wakeup_gdt
+ movl %cr0, %eax
+ orb $X86_CR0_PE, %al
+ movl %eax, %cr0
+ ljmpw $8, $2f
+2:
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+ movw %cx, %fs
+ movw %cx, %gs
+
+ andb $~X86_CR0_PE, %al
+ movl %eax, %cr0
+ LJMPW_RM(3f)
+3:
+ /* Set up segments */
+ movw %cs, %ax
+ movw %ax, %ss
+ movl $rm_stack_end, %esp
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+
+ lidtl wakeup_idt
+
+ /* Clear the EFLAGS */
+ pushl $0
+ popfl
+
+ /* Check header signature... */
+ movl signature, %eax
+ cmpl $WAKEUP_HEADER_SIGNATURE, %eax
+ jne bogus_real_magic
+
+ /* Check we really have everything... */
+ movl end_signature, %eax
+ cmpl $WAKEUP_END_SIGNATURE, %eax
+ jne bogus_real_magic
+
+ /* Call the C code */
+ calll main
+
+ /* Restore MISC_ENABLE before entering protected mode, in case
+ BIOS decided to clear XD_DISABLE during S3. */
+ movl pmode_behavior, %eax
+ btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
+ jnc 1f
+
+ movl pmode_misc_en, %eax
+ movl pmode_misc_en + 4, %edx
+ movl $MSR_IA32_MISC_ENABLE, %ecx
+ wrmsr
+1:
+
+ /* Do any other stuff... */
+
+#ifndef CONFIG_64BIT
+ /* This could also be done in C code... */
+ movl pmode_cr3, %eax
+ movl %eax, %cr3
+
+ movl pmode_cr4, %ecx
+ jecxz 1f
+ movl %ecx, %cr4
+1:
+ movl pmode_efer, %eax
+ movl pmode_efer + 4, %edx
+ movl %eax, %ecx
+ orl %edx, %ecx
+ jz 1f
+ movl $MSR_EFER, %ecx
+ wrmsr
+1:
+
+ lgdtl pmode_gdt
+
+ /* This really couldn't... */
+ movl pmode_entry, %eax
+ movl pmode_cr0, %ecx
+ movl %ecx, %cr0
+ ljmpl $__KERNEL_CS, $pa_startup_32
+ /* -> jmp *%eax in trampoline_32.S */
+#else
+ jmp trampoline_data
+#endif
+
+bogus_real_magic:
+1:
+ hlt
+ jmp 1b
+
+ .section ".rodata","a"
+
+ /*
+ * Set up the wakeup GDT. We set these up as Big Real Mode,
+ * that is, with limits set to 4 GB. At least the Lenovo
+ * Thinkpad X61 is known to need this for the video BIOS
+ * initialization quirk to work; this is likely to also
+ * be the case for other laptops or integrated video devices.
+ */
+
+ .balign 16
+GLOBAL(wakeup_gdt)
+ .word 3*8-1 /* Self-descriptor */
+ .long pa_wakeup_gdt
+ .word 0
+
+ .word 0xffff /* 16-bit code segment @ real_mode_base */
+ .long 0x9b000000 + pa_real_mode_base
+ .word 0x008f /* big real mode */
+
+ .word 0xffff /* 16-bit data segment @ real_mode_base */
+ .long 0x93000000 + pa_real_mode_base
+ .word 0x008f /* big real mode */
+END(wakeup_gdt)
+
+ .section ".rodata","a"
+ .balign 8
+
+ /* This is the standard real-mode IDT */
+ .balign 16
+GLOBAL(wakeup_idt)
+ .word 0xffff /* limit */
+ .long 0 /* address */
+ .word 0
+END(wakeup_idt)
+
+ .section ".signature","a"
+end_signature:
+ .long WAKEUP_END_SIGNATURE
--
1.7.9.5

2012-05-08 18:25:59

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 16/23] x86, realmode: Fix always-zero test in reboot_32.S

From: "H. Peter Anvin" <[email protected]>

A test instruction is an "and", and an and with zero is always zero.
This would cause us to always take the BIOS path, not the APM path, in
case anyone actually cares...

Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/realmode/rm/reboot_32.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
index e90f8c4..50ba994 100644
--- a/arch/x86/realmode/rm/reboot_32.S
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -85,7 +85,7 @@ machine_real_restart_asm16:
movl %edx, %cr0
LJMPW_RM(3f)
3:
- testb $0, %al
+ andw %ax, %ax
jz bios

apm:
--
1.7.9.5

2012-05-08 18:26:22

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 15/23] x86, realmode: Move trampoline_*.S early in the link order

From: "H. Peter Anvin" <[email protected]>

Move trampoline_*.S earlier in the link order so it ends up being
first in the text segment; since the SIPI vector requires 4K alignment
it otherwise ends up padding the .text segment with that much
completely unnecessarily.

Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/realmode/rm/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 2432acb..2423142 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -12,8 +12,8 @@ subdir- := wakeup
always := realmode.bin

realmode-y += header.o
-realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-y += trampoline_$(BITS).o
+realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o

targets += $(realmode-y)
--
1.7.9.5

2012-05-08 18:23:55

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 13/23] x86, realmode: Remove indirect jumps in trampoline_32 and wakeup_asm

From: "H. Peter Anvin" <[email protected]>

Remove indirect jumps in trampoline_32.S and the 32-bit part of
wakeup_asm.S. There exist systems which are known to do weird
things if an SMI comes in right after a mode switch, and the
safest way to deal with it is to always follow with a simple
absolute far jump. In the 64-bit code we then to a register
indirect near jump; follow that pattern for the 32-bit code.

Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/realmode/rm/trampoline_32.S | 22 +++++++++++++---------
arch/x86/realmode/rm/wakeup/wakeup_asm.S | 8 +++++---
2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 1f9e331..1315ef4 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -47,24 +47,29 @@ trampoline_data:

cli # We should be safe anyway

+ movl startup_32_smp, %eax # where we need to go
+
movl $0xA5A5A5A5, trampoline_status
# write marker for master knows we're running

- /* GDT tables in non default location kernel can be beyond 16MB and
+ /*
+ * GDT tables in non default location kernel can be beyond 16MB and
* lgdt will not be able to load the address as in real mode default
* operand size is 16bit. Use lgdtl instead to force operand size
* to 32 bit.
*/
-
lidtl boot_idt_descr # load idt with 0, 0
lgdtl boot_gdt_descr # load gdt with whatever is appropriate

- xor %ax, %ax
- inc %ax # protected mode (PE) bit
- lmsw %ax # into protected mode
+ movw $1, %dx # protected mode (PE) bit
+ lmsw %dx # into protected mode

- # flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
- ljmpl *(startup_32_smp)
+ ljmpl $__BOOT_CS, $pa_startup_32
+
+ .section ".text32","ax"
+ .code32
+ENTRY(startup_32) # note: also used from wakeup_asm.S
+ jmp *%eax

.data
.globl startup_32_smp, boot_gdt, trampoline_status
@@ -82,5 +87,4 @@ trampoline_status:
.long 0

startup_32_smp:
- .long 0x00000000
- .word __BOOT_CS, 0
+ .long 0
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
index b61126c..4c5c5f2 100644
--- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
@@ -124,9 +124,11 @@ wakeup_start:
lgdtl pmode_gdt

/* This really couldn't... */
- movl pmode_cr0, %eax
- movl %eax, %cr0
- ljmpl *pmode_entry
+ movl pmode_entry, %eax
+ movl pmode_cr0, %ecx
+ movl %ecx, %cr0
+ ljmpl $__KERNEL_CS, $pa_startup_32
+ /* -> jmp *%eax in trampoline_32.S */
#else
jmp trampoline_data
#endif
--
1.7.9.5

2012-05-08 18:23:53

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 09/23] x86, realmode: Add .text64 section, make barrier symbols absolute

From: "H. Peter Anvin" <[email protected]>

Add a .text64 section. The purpose of this is to keep 16-, 32- and
64-bit code segregated into separate sections, mainly to keep
disassembly sane.

Move barrier symbols out of sections to avoid the "symbol in empty
section" problem in some versions of GNU ld.

Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/realmode/rm/realmode.lds.S | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S
index 91b83ea..4d4afca 100644
--- a/arch/x86/realmode/rm/realmode.lds.S
+++ b/arch/x86/realmode/rm/realmode.lds.S
@@ -32,8 +32,8 @@ SECTIONS
}

. = ALIGN(PAGE_SIZE);
+ pa_text_start = .;
.text : {
- pa_text_start = .;
*(.text)
*(.text.*)
}
@@ -41,9 +41,14 @@ SECTIONS
.text32 : {
*(.text32)
*(.text32.*)
- pa_ro_end = .;
}

+ .text64 : {
+ *(.text64)
+ *(.text64.*)
+ }
+ pa_ro_end = .;
+
. = ALIGN(PAGE_SIZE);
.data : {
*(.data)
@@ -59,8 +64,8 @@ SECTIONS
. = ALIGN(4);
.signature : {
*(.signature)
- pa_end = .;
}
+ pa_end = .;

/DISCARD/ : {
*(.note*)
--
1.7.9.5

2012-05-08 18:26:53

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 12/23] x86, realmode: Remove indirect jumps in trampoline_64.S

From: "H. Peter Anvin" <[email protected]>

Remove indirect jumps in trampoline_64.S which are no longer
necessary: the realmode code can relocate the absolute jumps
correctly from the start.

Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/realmode/rm/trampoline_64.S | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 66c58cf..77b72b4 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -73,7 +73,7 @@ ENTRY(trampoline_data)
lmsw %ax # into protected mode

# flush prefetch and jump to startup_32
- ljmpl *(startup_32_vector)
+ ljmpl $__KERNEL32_CS, $pa_startup_32

no_longmode:
hlt
@@ -113,7 +113,7 @@ ENTRY(startup_32)
* EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
* the new gdt/idt that has __KERNEL_CS with CS.L = 1.
*/
- ljmpl *(pa_startup_64_vector)
+ ljmpl $__KERNEL_CS, $pa_startup_64

.section ".text64","ax"
.code64
@@ -144,17 +144,6 @@ tgdt:
.quad 0x00cf93000000ffff # __KERNEL_DS
tgdt_end:

- .balign 4
-startup_32_vector:
- .long pa_startup_32
- .word __KERNEL32_CS, 0
-
- .balign 4
- .globl startup_64_vector
-startup_64_vector:
- .long pa_startup_64
- .word __KERNEL_CS, 0
-
.data
.balign 4
GLOBAL(trampoline_status)
--
1.7.9.5

2012-05-08 18:23:51

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 07/23] x86, realmode: Set permission for real mode pages

Set proper permissions for rodata, text and data, removing the
realmode trampoline area as a remaining RWX memory mapping in the
kernel.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/kernel/realmode.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index a465775..d85ac20 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -86,7 +86,21 @@ static int __init set_real_mode_permissions(void)
PAGE_ALIGN(real_mode_header.end) -
__pa(real_mode_base);

- set_memory_x((unsigned long) real_mode_base, all_size >> PAGE_SHIFT);
+ size_t ro_size =
+ PAGE_ALIGN(real_mode_header.ro_end) -
+ __pa(real_mode_base);
+
+ size_t text_size =
+ PAGE_ALIGN(real_mode_header.ro_end) -
+ real_mode_header.text_start;
+
+ unsigned long text_start =
+ (unsigned long) __va(real_mode_header.text_start);
+
+ set_memory_nx((unsigned long) real_mode_base, all_size >> PAGE_SHIFT);
+ set_memory_ro((unsigned long) real_mode_base, ro_size >> PAGE_SHIFT);
+ set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT);
+
return 0;
}

--
1.7.9.5

2012-05-08 18:27:32

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 11/23] x86, realmode: Align .data section in trampoline_32.S

From: "H. Peter Anvin" <[email protected]>

Specify the alignment of the .data section in trampoline_32.S.

Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/realmode/rm/trampoline_32.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 18cb7fc..1f9e331 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -68,7 +68,7 @@ trampoline_data:

.data
.globl startup_32_smp, boot_gdt, trampoline_status
-
+ .balign 4
boot_gdt_descr:
.word __BOOT_DS + 7 # gdt limit
boot_gdt:
--
1.7.9.5

2012-05-08 18:23:50

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 08/23] x86, realmode: Allow absolute pa_* symbols in the realmode code

From: "H. Peter Anvin" <[email protected]>

Allow pa_* symbols to be absolute (outside any section) in the
realmode linker script. Some versions of GNU ld are known to be
unhappy about symbols defined in a section that is otherwise empty.

Signed-off-by: H. Peter Anvin <[email protected]>
---
scripts/x86-relocs.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/scripts/x86-relocs.c b/scripts/x86-relocs.c
index 0291470..74e16bb 100644
--- a/scripts/x86-relocs.c
+++ b/scripts/x86-relocs.c
@@ -62,6 +62,13 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {

static const char * const sym_regex_realmode[S_NSYMTYPES] = {
/*
+ * These symbols are known to be relative, even if the linker marks them
+ * as absolute (typically defined outside any section in the linker script.)
+ */
+ [S_REL] =
+ "^pa_",
+
+/*
* These are 16-bit segment symbols when compiling 16-bit code.
*/
[S_SEG] =
--
1.7.9.5

2012-05-08 18:27:50

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 10/23] x86, realmode: Move bits to the proper sections in trampoline_64.S

From: "H. Peter Anvin" <[email protected]>

Move various bits to the sections they really belong in in
trampoline_64.S. Use GLOBAL() rather than ENTRY() for data objects:
ENTRY() should only be used with code and forces alignment to 16
bytes.

Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/realmode/rm/trampoline_64.S | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 063da00..66c58cf 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -80,6 +80,7 @@ no_longmode:
jmp no_longmode
#include "../kernel/verify_cpu.S"

+ .section ".text32","ax"
.code32
.balign 4
ENTRY(startup_32)
@@ -114,6 +115,7 @@ ENTRY(startup_32)
*/
ljmpl *(pa_startup_64_vector)

+ .section ".text64","ax"
.code64
.balign 4
ENTRY(startup_64)
@@ -123,7 +125,8 @@ ENTRY(startup_64)
addl %esi, %eax
jmp *%rax

- # Careful these need to be in the same 64K segment as the above;
+ .section ".rodata","a"
+ .balign 16
tidt:
.word 0 # idt limit = 0
.word 0, 0 # idt base = 0L
@@ -153,9 +156,8 @@ startup_64_vector:
.word __KERNEL_CS, 0

.data
-
.balign 4
-ENTRY(trampoline_status)
+GLOBAL(trampoline_status)
.long 0

trampoline_stack:
@@ -164,7 +166,7 @@ trampoline_stack_end:

.globl level3_ident_pgt
.globl level3_kernel_pgt
-ENTRY(trampoline_level4_pgt)
+GLOBAL(trampoline_level4_pgt)
level3_ident_pgt: .quad 0
.fill 510,8,0
level3_kernel_pgt: .quad 0
--
1.7.9.5

2012-05-08 18:28:22

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 04/23] x86, realmode: Move reboot_32.S to unified realmode code

Migrated reboot_32.S from x86_trampoline to the real-mode
blob.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/include/asm/realmode.h | 4 ++
arch/x86/kernel/Makefile | 1 -
arch/x86/kernel/reboot.c | 25 +------
arch/x86/kernel/reboot_32.S | 135 --------------------------------------
arch/x86/realmode/rm/Makefile | 1 +
arch/x86/realmode/rm/header.S | 3 +
arch/x86/realmode/rm/reboot_32.S | 134 +++++++++++++++++++++++++++++++++++++
7 files changed, 145 insertions(+), 158 deletions(-)
delete mode 100644 arch/x86/kernel/reboot_32.S
create mode 100644 arch/x86/realmode/rm/reboot_32.S

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index dc1bba5..bf26b06 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -9,6 +9,10 @@ struct real_mode_header {
u32 text_start;
u32 ro_end;
u32 end;
+ /* reboot */
+#ifdef CONFIG_X86_32
+ u32 machine_real_restart_asm;
+#endif
} __attribute__((__packed__));

extern struct real_mode_header real_mode_header;
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index f9e19d4..b71ef35 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -49,7 +49,6 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += cpu/
obj-y += acpi/
obj-y += reboot.o
-obj-$(CONFIG_X86_32) += reboot_32.o
obj-$(CONFIG_MCA) += mca_32.o
obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index d840e69..050eff2 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -24,6 +24,7 @@
#ifdef CONFIG_X86_32
# include <linux/ctype.h>
# include <linux/mc146818rtc.h>
+# include <asm/realmode.h>
#else
# include <asm/x86_init.h>
#endif
@@ -332,15 +333,10 @@ static int __init reboot_init(void)
}
core_initcall(reboot_init);

-extern const unsigned char machine_real_restart_asm[];
-extern const u64 machine_real_restart_gdt[3];
-
void machine_real_restart(unsigned int type)
{
- void *restart_va;
- unsigned long restart_pa;
- void (*restart_lowmem)(unsigned int);
- u64 *lowmem_gdt;
+ void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int))
+ real_mode_header.machine_real_restart_asm;

local_irq_disable();

@@ -369,21 +365,6 @@ void machine_real_restart(unsigned int type)
too. */
*((unsigned short *)0x472) = reboot_mode;

- /* Patch the GDT in the low memory trampoline */
- lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
-
- restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
- restart_pa = virt_to_phys(restart_va);
- restart_lowmem = (void (*)(unsigned int))restart_pa;
-
- /* GDT[0]: GDT self-pointer */
- lowmem_gdt[0] =
- (u64)(sizeof(machine_real_restart_gdt) - 1) +
- ((u64)virt_to_phys(lowmem_gdt) << 16);
- /* GDT[1]: 64K real mode code segment */
- lowmem_gdt[1] =
- GDT_ENTRY(0x009b, restart_pa, 0xffff);
-
/* Jump to the identity-mapped low memory code */
restart_lowmem(type);
}
diff --git a/arch/x86/kernel/reboot_32.S b/arch/x86/kernel/reboot_32.S
deleted file mode 100644
index 1d5c46d..0000000
--- a/arch/x86/kernel/reboot_32.S
+++ /dev/null
@@ -1,135 +0,0 @@
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/segment.h>
-#include <asm/page_types.h>
-
-/*
- * The following code and data reboots the machine by switching to real
- * mode and jumping to the BIOS reset entry point, as if the CPU has
- * really been reset. The previous version asked the keyboard
- * controller to pulse the CPU reset line, which is more thorough, but
- * doesn't work with at least one type of 486 motherboard. It is easy
- * to stop this code working; hence the copious comments.
- *
- * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax.
- */
- .section ".x86_trampoline","a"
- .balign 16
- .code32
-ENTRY(machine_real_restart_asm)
-r_base = .
- /* Get our own relocated address */
- call 1f
-1: popl %ebx
- subl $(1b - r_base), %ebx
-
- /* Compute the equivalent real-mode segment */
- movl %ebx, %ecx
- shrl $4, %ecx
-
- /* Patch post-real-mode segment jump */
- movw (dispatch_table - r_base)(%ebx,%eax,2),%ax
- movw %ax, (101f - r_base)(%ebx)
- movw %cx, (102f - r_base)(%ebx)
-
- /* Set up the IDT for real mode. */
- lidtl (machine_real_restart_idt - r_base)(%ebx)
-
- /*
- * Set up a GDT from which we can load segment descriptors for real
- * mode. The GDT is not used in real mode; it is just needed here to
- * prepare the descriptors.
- */
- lgdtl (machine_real_restart_gdt - r_base)(%ebx)
-
- /*
- * Load the data segment registers with 16-bit compatible values
- */
- movl $16, %ecx
- movl %ecx, %ds
- movl %ecx, %es
- movl %ecx, %fs
- movl %ecx, %gs
- movl %ecx, %ss
- ljmpl $8, $1f - r_base
-
-/*
- * This is 16-bit protected mode code to disable paging and the cache,
- * switch to real mode and jump to the BIOS reset code.
- *
- * The instruction that switches to real mode by writing to CR0 must be
- * followed immediately by a far jump instruction, which set CS to a
- * valid value for real mode, and flushes the prefetch queue to avoid
- * running instructions that have already been decoded in protected
- * mode.
- *
- * Clears all the flags except ET, especially PG (paging), PE
- * (protected-mode enable) and TS (task switch for coprocessor state
- * save). Flushes the TLB after paging has been disabled. Sets CD and
- * NW, to disable the cache on a 486, and invalidates the cache. This
- * is more like the state of a 486 after reset. I don't know if
- * something else should be done for other chips.
- *
- * More could be done here to set up the registers as if a CPU reset had
- * occurred; hopefully real BIOSs don't assume much. This is not the
- * actual BIOS entry point, anyway (that is at 0xfffffff0).
- *
- * Most of this work is probably excessive, but it is what is tested.
- */
- .code16
-1:
- xorl %ecx, %ecx
- movl %cr0, %eax
- andl $0x00000011, %eax
- orl $0x60000000, %eax
- movl %eax, %cr0
- movl %ecx, %cr3
- movl %cr0, %edx
- andl $0x60000000, %edx /* If no cache bits -> no wbinvd */
- jz 2f
- wbinvd
-2:
- andb $0x10, %al
- movl %eax, %cr0
- .byte 0xea /* ljmpw */
-101: .word 0 /* Offset */
-102: .word 0 /* Segment */
-
-bios:
- ljmpw $0xf000, $0xfff0
-
-apm:
- movw $0x1000, %ax
- movw %ax, %ss
- movw $0xf000, %sp
- movw $0x5307, %ax
- movw $0x0001, %bx
- movw $0x0003, %cx
- int $0x15
-
-END(machine_real_restart_asm)
-
- .balign 16
- /* These must match <asm/reboot.h */
-dispatch_table:
- .word bios - r_base
- .word apm - r_base
-END(dispatch_table)
-
- .balign 16
-machine_real_restart_idt:
- .word 0xffff /* Length - real mode default value */
- .long 0 /* Base - real mode default value */
-END(machine_real_restart_idt)
-
- .balign 16
-ENTRY(machine_real_restart_gdt)
- .quad 0 /* Self-pointer, filled in by PM code */
- .quad 0 /* 16-bit code segment, filled in by PM code */
- /*
- * 16-bit data segment with the selector value 16 = 0x10 and
- * base value 0x100; since this is consistent with real mode
- * semantics we don't have to reload the segments once CR0.PE = 0.
- */
- .quad GDT_ENTRY(0x0093, 0x100, 0xffff)
-END(machine_real_restart_gdt)
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 7c3f202..3f851c4 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -12,6 +12,7 @@ subdir- := wakeup
always := realmode.bin

realmode-y += header.o
+realmode-$(CONFIG_X86_32) += reboot_32.o

targets += $(realmode-y)

diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index 7be17f2..db21401 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -13,4 +13,7 @@ ENTRY(real_mode_header)
.long pa_text_start
.long pa_ro_end
.long pa_end
+#ifdef CONFIG_X86_32
+ .long pa_machine_real_restart_asm
+#endif
END(real_mode_header)
diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
new file mode 100644
index 0000000..83803c2
--- /dev/null
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -0,0 +1,134 @@
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/segment.h>
+#include <asm/page_types.h>
+
+/*
+ * The following code and data reboots the machine by switching to real
+ * mode and jumping to the BIOS reset entry point, as if the CPU has
+ * really been reset. The previous version asked the keyboard
+ * controller to pulse the CPU reset line, which is more thorough, but
+ * doesn't work with at least one type of 486 motherboard. It is easy
+ * to stop this code working; hence the copious comments.
+ *
+ * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax.
+ */
+ .section ".text32", "ax"
+ .code32
+ .globl machine_real_restart_asm
+
+ .balign 16
+machine_real_restart_asm:
+ /* Set up the IDT for real mode. */
+ lidtl pa_machine_real_restart_idt
+
+ /*
+ * Set up a GDT from which we can load segment descriptors for real
+ * mode. The GDT is not used in real mode; it is just needed here to
+ * prepare the descriptors.
+ */
+ lgdtl pa_machine_real_restart_gdt
+
+ /*
+ * Load the data segment registers with 16-bit compatible values
+ */
+ movl $16, %ecx
+ movl %ecx, %ds
+ movl %ecx, %es
+ movl %ecx, %fs
+ movl %ecx, %gs
+ movl %ecx, %ss
+ ljmpw $8, $1f
+
+/*
+ * This is 16-bit protected mode code to disable paging and the cache,
+ * switch to real mode and jump to the BIOS reset code.
+ *
+ * The instruction that switches to real mode by writing to CR0 must be
+ * followed immediately by a far jump instruction, which set CS to a
+ * valid value for real mode, and flushes the prefetch queue to avoid
+ * running instructions that have already been decoded in protected
+ * mode.
+ *
+ * Clears all the flags except ET, especially PG (paging), PE
+ * (protected-mode enable) and TS (task switch for coprocessor state
+ * save). Flushes the TLB after paging has been disabled. Sets CD and
+ * NW, to disable the cache on a 486, and invalidates the cache. This
+ * is more like the state of a 486 after reset. I don't know if
+ * something else should be done for other chips.
+ *
+ * More could be done here to set up the registers as if a CPU reset had
+ * occurred; hopefully real BIOSs don't assume much. This is not the
+ * actual BIOS entry point, anyway (that is at 0xfffffff0).
+ *
+ * Most of this work is probably excessive, but it is what is tested.
+ */
+ .text
+ .code16
+
+ .balign 16
+machine_real_restart_asm16:
+1:
+ xorl %ecx, %ecx
+ movl %cr0, %edx
+ andl $0x00000011, %edx
+ orl $0x60000000, %edx
+ movl %edx, %cr0
+ movl %ecx, %cr3
+ movl %cr0, %edx
+ andl $0x60000000, %edx /* If no cache bits -> no wbinvd */
+ jz 2f
+ wbinvd
+2:
+ andb $0x10, %dl
+ movl %edx, %cr0
+ .byte 0xea /* ljmpw */
+ .word 3f /* Offset */
+ .word real_mode_seg /* Segment */
+
+3:
+ testb $0, %al
+ jz bios
+
+apm:
+ movw $0x1000, %ax
+ movw %ax, %ss
+ movw $0xf000, %sp
+ movw $0x5307, %ax
+ movw $0x0001, %bx
+ movw $0x0003, %cx
+ int $0x15
+ /* This should never return... */
+
+bios:
+ ljmpw $0xf000, $0xfff0
+
+ .section ".rodata", "a"
+ .globl machine_real_restart_idt, machine_real_restart_gdt
+
+ .balign 16
+machine_real_restart_idt:
+ .word 0xffff /* Length - real mode default value */
+ .long 0 /* Base - real mode default value */
+
+ .balign 16
+machine_real_restart_gdt:
+ /* Self-pointer */
+ .word 0xffff /* Length - real mode default value */
+ .long pa_machine_real_restart_gdt
+ .word 0
+
+ /*
+ * 16-bit code segment pointing to real_mode_seg
+ * Selector value 8
+ */
+ .word 0xffff /* Limit */
+ .long 0x9b000000 + pa_real_mode_base
+ .word 0
+
+ /*
+ * 16-bit data segment with the selector value 16 = 0x10 and
+ * base value 0x100; since this is consistent with real mode
+ * semantics we don't have to reload the segments once CR0.PE = 0.
+ */
+ .quad GDT_ENTRY(0x0093, 0x100, 0xffff)
--
1.7.9.5

2012-05-08 18:23:09

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH 01/23] x86, realmode: 16-bit real-mode code support for relocs tool

From: "H. Peter Anvin" <[email protected]>

A new option is added to the relocs tool called '--realmode'.
This option causes the generation of 16-bit segment relocations
and 32-bit linear relocations for the real-mode code. When
the real-mode code is moved to the low-memory during kernel
initialization, these relocation entries can be used to
relocate the code properly.

In the assembly code 16-bit segment relocations must be relative
to the 'real_mode_seg' absolute symbol. Linear relocations must be
relative to a symbol prefixed with 'pa_'.

16-bit segment relocation is used to load cs:ip in 16-bit code.
Linear relocations are used in the 32-bit code for relocatable
data references. They are declared in the linker script of the
real-mode code.

The relocs tool is moved to scripts/x86-relocs.c so it will
be compiled before building the arch/x86 tree.

Signed-off-by: H. Peter Anvin <[email protected]>
Signed-off-by: Jarkko Sakkinen <[email protected]>
---
arch/x86/boot/compressed/Makefile | 11 +-
arch/x86/boot/compressed/relocs.c | 680 -------------------------------
scripts/.gitignore | 1 +
scripts/Makefile | 3 +
scripts/x86-relocs.c | 797 +++++++++++++++++++++++++++++++++++++
5 files changed, 806 insertions(+), 686 deletions(-)
delete mode 100644 arch/x86/boot/compressed/relocs.c
create mode 100644 scripts/x86-relocs.c

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index fd55a2f..0435e8a 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -40,13 +40,12 @@ OBJCOPYFLAGS_vmlinux.bin := -R .comment -S
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)

+targets += vmlinux.bin.all vmlinux.relocs

-targets += vmlinux.bin.all vmlinux.relocs relocs
-hostprogs-$(CONFIG_X86_NEED_RELOCS) += relocs
-
-quiet_cmd_relocs = RELOCS $@
- cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
-$(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE
+CMD_RELOCS = scripts/x86-relocs
+quiet_cmd_relocs = RELOCS $@
+ cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $<
+$(obj)/vmlinux.relocs: vmlinux FORCE
$(call if_changed,relocs)

vmlinux.bin.all-y := $(obj)/vmlinux.bin
diff --git a/arch/x86/boot/compressed/relocs.c b/arch/x86/boot/compressed/relocs.c
deleted file mode 100644
index d3c0b02..0000000
--- a/arch/x86/boot/compressed/relocs.c
+++ /dev/null
@@ -1,680 +0,0 @@
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <elf.h>
-#include <byteswap.h>
-#define USE_BSD
-#include <endian.h>
-#include <regex.h>
-#include <tools/le_byteshift.h>
-
-static void die(char *fmt, ...);
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-static Elf32_Ehdr ehdr;
-static unsigned long reloc_count, reloc_idx;
-static unsigned long *relocs;
-
-struct section {
- Elf32_Shdr shdr;
- struct section *link;
- Elf32_Sym *symtab;
- Elf32_Rel *reltab;
- char *strtab;
-};
-static struct section *secs;
-
-/*
- * Following symbols have been audited. There values are constant and do
- * not change if bzImage is loaded at a different physical address than
- * the address for which it has been compiled. Don't warn user about
- * absolute relocations present w.r.t these symbols.
- */
-static const char abs_sym_regex[] =
- "^(xen_irq_disable_direct_reloc$|"
- "xen_save_fl_direct_reloc$|"
- "VDSO|"
- "__crc_)";
-static regex_t abs_sym_regex_c;
-static int is_abs_reloc(const char *sym_name)
-{
- return !regexec(&abs_sym_regex_c, sym_name, 0, NULL, 0);
-}
-
-/*
- * These symbols are known to be relative, even if the linker marks them
- * as absolute (typically defined outside any section in the linker script.)
- */
-static const char rel_sym_regex[] =
- "^_end$";
-static regex_t rel_sym_regex_c;
-static int is_rel_reloc(const char *sym_name)
-{
- return !regexec(&rel_sym_regex_c, sym_name, 0, NULL, 0);
-}
-
-static void regex_init(void)
-{
- char errbuf[128];
- int err;
-
- err = regcomp(&abs_sym_regex_c, abs_sym_regex,
- REG_EXTENDED|REG_NOSUB);
- if (err) {
- regerror(err, &abs_sym_regex_c, errbuf, sizeof errbuf);
- die("%s", errbuf);
- }
-
- err = regcomp(&rel_sym_regex_c, rel_sym_regex,
- REG_EXTENDED|REG_NOSUB);
- if (err) {
- regerror(err, &rel_sym_regex_c, errbuf, sizeof errbuf);
- die("%s", errbuf);
- }
-}
-
-static void die(char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- exit(1);
-}
-
-static const char *sym_type(unsigned type)
-{
- static const char *type_name[] = {
-#define SYM_TYPE(X) [X] = #X
- SYM_TYPE(STT_NOTYPE),
- SYM_TYPE(STT_OBJECT),
- SYM_TYPE(STT_FUNC),
- SYM_TYPE(STT_SECTION),
- SYM_TYPE(STT_FILE),
- SYM_TYPE(STT_COMMON),
- SYM_TYPE(STT_TLS),
-#undef SYM_TYPE
- };
- const char *name = "unknown sym type name";
- if (type < ARRAY_SIZE(type_name)) {
- name = type_name[type];
- }
- return name;
-}
-
-static const char *sym_bind(unsigned bind)
-{
- static const char *bind_name[] = {
-#define SYM_BIND(X) [X] = #X
- SYM_BIND(STB_LOCAL),
- SYM_BIND(STB_GLOBAL),
- SYM_BIND(STB_WEAK),
-#undef SYM_BIND
- };
- const char *name = "unknown sym bind name";
- if (bind < ARRAY_SIZE(bind_name)) {
- name = bind_name[bind];
- }
- return name;
-}
-
-static const char *sym_visibility(unsigned visibility)
-{
- static const char *visibility_name[] = {
-#define SYM_VISIBILITY(X) [X] = #X
- SYM_VISIBILITY(STV_DEFAULT),
- SYM_VISIBILITY(STV_INTERNAL),
- SYM_VISIBILITY(STV_HIDDEN),
- SYM_VISIBILITY(STV_PROTECTED),
-#undef SYM_VISIBILITY
- };
- const char *name = "unknown sym visibility name";
- if (visibility < ARRAY_SIZE(visibility_name)) {
- name = visibility_name[visibility];
- }
- return name;
-}
-
-static const char *rel_type(unsigned type)
-{
- static const char *type_name[] = {
-#define REL_TYPE(X) [X] = #X
- REL_TYPE(R_386_NONE),
- REL_TYPE(R_386_32),
- REL_TYPE(R_386_PC32),
- REL_TYPE(R_386_GOT32),
- REL_TYPE(R_386_PLT32),
- REL_TYPE(R_386_COPY),
- REL_TYPE(R_386_GLOB_DAT),
- REL_TYPE(R_386_JMP_SLOT),
- REL_TYPE(R_386_RELATIVE),
- REL_TYPE(R_386_GOTOFF),
- REL_TYPE(R_386_GOTPC),
-#undef REL_TYPE
- };
- const char *name = "unknown type rel type name";
- if (type < ARRAY_SIZE(type_name) && type_name[type]) {
- name = type_name[type];
- }
- return name;
-}
-
-static const char *sec_name(unsigned shndx)
-{
- const char *sec_strtab;
- const char *name;
- sec_strtab = secs[ehdr.e_shstrndx].strtab;
- name = "<noname>";
- if (shndx < ehdr.e_shnum) {
- name = sec_strtab + secs[shndx].shdr.sh_name;
- }
- else if (shndx == SHN_ABS) {
- name = "ABSOLUTE";
- }
- else if (shndx == SHN_COMMON) {
- name = "COMMON";
- }
- return name;
-}
-
-static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
-{
- const char *name;
- name = "<noname>";
- if (sym->st_name) {
- name = sym_strtab + sym->st_name;
- }
- else {
- name = sec_name(secs[sym->st_shndx].shdr.sh_name);
- }
- return name;
-}
-
-
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define le16_to_cpu(val) (val)
-#define le32_to_cpu(val) (val)
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
-#define le16_to_cpu(val) bswap_16(val)
-#define le32_to_cpu(val) bswap_32(val)
-#endif
-
-static uint16_t elf16_to_cpu(uint16_t val)
-{
- return le16_to_cpu(val);
-}
-
-static uint32_t elf32_to_cpu(uint32_t val)
-{
- return le32_to_cpu(val);
-}
-
-static void read_ehdr(FILE *fp)
-{
- if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
- die("Cannot read ELF header: %s\n",
- strerror(errno));
- }
- if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
- die("No ELF magic\n");
- }
- if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
- die("Not a 32 bit executable\n");
- }
- if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
- die("Not a LSB ELF executable\n");
- }
- if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
- die("Unknown ELF version\n");
- }
- /* Convert the fields to native endian */
- ehdr.e_type = elf16_to_cpu(ehdr.e_type);
- ehdr.e_machine = elf16_to_cpu(ehdr.e_machine);
- ehdr.e_version = elf32_to_cpu(ehdr.e_version);
- ehdr.e_entry = elf32_to_cpu(ehdr.e_entry);
- ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff);
- ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff);
- ehdr.e_flags = elf32_to_cpu(ehdr.e_flags);
- ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize);
- ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
- ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum);
- ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
- ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum);
- ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx);
-
- if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
- die("Unsupported ELF header type\n");
- }
- if (ehdr.e_machine != EM_386) {
- die("Not for x86\n");
- }
- if (ehdr.e_version != EV_CURRENT) {
- die("Unknown ELF version\n");
- }
- if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
- die("Bad Elf header size\n");
- }
- if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
- die("Bad program header entry\n");
- }
- if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
- die("Bad section header entry\n");
- }
- if (ehdr.e_shstrndx >= ehdr.e_shnum) {
- die("String table index out of bounds\n");
- }
-}
-
-static void read_shdrs(FILE *fp)
-{
- int i;
- Elf32_Shdr shdr;
-
- secs = calloc(ehdr.e_shnum, sizeof(struct section));
- if (!secs) {
- die("Unable to allocate %d section headers\n",
- ehdr.e_shnum);
- }
- if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
- die("Seek to %d failed: %s\n",
- ehdr.e_shoff, strerror(errno));
- }
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- if (fread(&shdr, sizeof shdr, 1, fp) != 1)
- die("Cannot read ELF section headers %d/%d: %s\n",
- i, ehdr.e_shnum, strerror(errno));
- sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name);
- sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type);
- sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags);
- sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr);
- sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset);
- sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size);
- sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link);
- sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info);
- sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
- sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize);
- if (sec->shdr.sh_link < ehdr.e_shnum)
- sec->link = &secs[sec->shdr.sh_link];
- }
-
-}
-
-static void read_strtabs(FILE *fp)
-{
- int i;
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- if (sec->shdr.sh_type != SHT_STRTAB) {
- continue;
- }
- sec->strtab = malloc(sec->shdr.sh_size);
- if (!sec->strtab) {
- die("malloc of %d bytes for strtab failed\n",
- sec->shdr.sh_size);
- }
- if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
- die("Seek to %d failed: %s\n",
- sec->shdr.sh_offset, strerror(errno));
- }
- if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
- != sec->shdr.sh_size) {
- die("Cannot read symbol table: %s\n",
- strerror(errno));
- }
- }
-}
-
-static void read_symtabs(FILE *fp)
-{
- int i,j;
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- if (sec->shdr.sh_type != SHT_SYMTAB) {
- continue;
- }
- sec->symtab = malloc(sec->shdr.sh_size);
- if (!sec->symtab) {
- die("malloc of %d bytes for symtab failed\n",
- sec->shdr.sh_size);
- }
- if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
- die("Seek to %d failed: %s\n",
- sec->shdr.sh_offset, strerror(errno));
- }
- if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
- != sec->shdr.sh_size) {
- die("Cannot read symbol table: %s\n",
- strerror(errno));
- }
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
- Elf32_Sym *sym = &sec->symtab[j];
- sym->st_name = elf32_to_cpu(sym->st_name);
- sym->st_value = elf32_to_cpu(sym->st_value);
- sym->st_size = elf32_to_cpu(sym->st_size);
- sym->st_shndx = elf16_to_cpu(sym->st_shndx);
- }
- }
-}
-
-
-static void read_relocs(FILE *fp)
-{
- int i,j;
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- if (sec->shdr.sh_type != SHT_REL) {
- continue;
- }
- sec->reltab = malloc(sec->shdr.sh_size);
- if (!sec->reltab) {
- die("malloc of %d bytes for relocs failed\n",
- sec->shdr.sh_size);
- }
- if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
- die("Seek to %d failed: %s\n",
- sec->shdr.sh_offset, strerror(errno));
- }
- if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
- != sec->shdr.sh_size) {
- die("Cannot read symbol table: %s\n",
- strerror(errno));
- }
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
- Elf32_Rel *rel = &sec->reltab[j];
- rel->r_offset = elf32_to_cpu(rel->r_offset);
- rel->r_info = elf32_to_cpu(rel->r_info);
- }
- }
-}
-
-
-static void print_absolute_symbols(void)
-{
- int i;
- printf("Absolute symbols\n");
- printf(" Num: Value Size Type Bind Visibility Name\n");
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- char *sym_strtab;
- Elf32_Sym *sh_symtab;
- int j;
-
- if (sec->shdr.sh_type != SHT_SYMTAB) {
- continue;
- }
- sh_symtab = sec->symtab;
- sym_strtab = sec->link->strtab;
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
- Elf32_Sym *sym;
- const char *name;
- sym = &sec->symtab[j];
- name = sym_name(sym_strtab, sym);
- if (sym->st_shndx != SHN_ABS) {
- continue;
- }
- printf("%5d %08x %5d %10s %10s %12s %s\n",
- j, sym->st_value, sym->st_size,
- sym_type(ELF32_ST_TYPE(sym->st_info)),
- sym_bind(ELF32_ST_BIND(sym->st_info)),
- sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
- name);
- }
- }
- printf("\n");
-}
-
-static void print_absolute_relocs(void)
-{
- int i, printed = 0;
-
- for (i = 0; i < ehdr.e_shnum; i++) {
- struct section *sec = &secs[i];
- struct section *sec_applies, *sec_symtab;
- char *sym_strtab;
- Elf32_Sym *sh_symtab;
- int j;
- if (sec->shdr.sh_type != SHT_REL) {
- continue;
- }
- sec_symtab = sec->link;
- sec_applies = &secs[sec->shdr.sh_info];
- if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
- continue;
- }
- sh_symtab = sec_symtab->symtab;
- sym_strtab = sec_symtab->link->strtab;
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
- Elf32_Rel *rel;
- Elf32_Sym *sym;
- const char *name;
- rel = &sec->reltab[j];
- sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
- name = sym_name(sym_strtab, sym);
- if (sym->st_shndx != SHN_ABS) {
- continue;
- }
-
- /* Absolute symbols are not relocated if bzImage is
- * loaded at a non-compiled address. Display a warning
- * to user at compile time about the absolute
- * relocations present.
- *
- * User need to audit the code to make sure
- * some symbols which should have been section
- * relative have not become absolute because of some
- * linker optimization or wrong programming usage.
- *
- * Before warning check if this absolute symbol
- * relocation is harmless.
- */
- if (is_abs_reloc(name) || is_rel_reloc(name))
- continue;
-
- if (!printed) {
- printf("WARNING: Absolute relocations"
- " present\n");
- printf("Offset Info Type Sym.Value "
- "Sym.Name\n");
- printed = 1;
- }
-
- printf("%08x %08x %10s %08x %s\n",
- rel->r_offset,
- rel->r_info,
- rel_type(ELF32_R_TYPE(rel->r_info)),
- sym->st_value,
- name);
- }
- }
-
- if (printed)
- printf("\n");
-}
-
-static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
-{
- int i;
- /* Walk through the relocations */
- for (i = 0; i < ehdr.e_shnum; i++) {
- char *sym_strtab;
- Elf32_Sym *sh_symtab;
- struct section *sec_applies, *sec_symtab;
- int j;
- struct section *sec = &secs[i];
-
- if (sec->shdr.sh_type != SHT_REL) {
- continue;
- }
- sec_symtab = sec->link;
- sec_applies = &secs[sec->shdr.sh_info];
- if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
- continue;
- }
- sh_symtab = sec_symtab->symtab;
- sym_strtab = sec_symtab->link->strtab;
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
- Elf32_Rel *rel;
- Elf32_Sym *sym;
- unsigned r_type;
- rel = &sec->reltab[j];
- sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
- r_type = ELF32_R_TYPE(rel->r_info);
- /* Don't visit relocations to absolute symbols */
- if (sym->st_shndx == SHN_ABS &&
- !is_rel_reloc(sym_name(sym_strtab, sym))) {
- continue;
- }
- switch (r_type) {
- case R_386_NONE:
- case R_386_PC32:
- /*
- * NONE can be ignored and and PC relative
- * relocations don't need to be adjusted.
- */
- break;
- case R_386_32:
- /* Visit relocations that need to be adjusted */
- visit(rel, sym);
- break;
- default:
- die("Unsupported relocation type: %s (%d)\n",
- rel_type(r_type), r_type);
- break;
- }
- }
- }
-}
-
-static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
-{
- reloc_count += 1;
-}
-
-static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
-{
- /* Remember the address that needs to be adjusted. */
- relocs[reloc_idx++] = rel->r_offset;
-}
-
-static int cmp_relocs(const void *va, const void *vb)
-{
- const unsigned long *a, *b;
- a = va; b = vb;
- return (*a == *b)? 0 : (*a > *b)? 1 : -1;
-}
-
-static void emit_relocs(int as_text)
-{
- int i;
- /* Count how many relocations I have and allocate space for them. */
- reloc_count = 0;
- walk_relocs(count_reloc);
- relocs = malloc(reloc_count * sizeof(relocs[0]));
- if (!relocs) {
- die("malloc of %d entries for relocs failed\n",
- reloc_count);
- }
- /* Collect up the relocations */
- reloc_idx = 0;
- walk_relocs(collect_reloc);
-
- /* Order the relocations for more efficient processing */
- qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
-
- /* Print the relocations */
- if (as_text) {
- /* Print the relocations in a form suitable that
- * gas will like.
- */
- printf(".section \".data.reloc\",\"a\"\n");
- printf(".balign 4\n");
- for (i = 0; i < reloc_count; i++) {
- printf("\t .long 0x%08lx\n", relocs[i]);
- }
- printf("\n");
- }
- else {
- unsigned char buf[4];
- /* Print a stop */
- fwrite("\0\0\0\0", 4, 1, stdout);
- /* Now print each relocation */
- for (i = 0; i < reloc_count; i++) {
- put_unaligned_le32(relocs[i], buf);
- fwrite(buf, 4, 1, stdout);
- }
- }
-}
-
-static void usage(void)
-{
- die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n");
-}
-
-int main(int argc, char **argv)
-{
- int show_absolute_syms, show_absolute_relocs;
- int as_text;
- const char *fname;
- FILE *fp;
- int i;
-
- regex_init();
-
- show_absolute_syms = 0;
- show_absolute_relocs = 0;
- as_text = 0;
- fname = NULL;
- for (i = 1; i < argc; i++) {
- char *arg = argv[i];
- if (*arg == '-') {
- if (strcmp(argv[1], "--abs-syms") == 0) {
- show_absolute_syms = 1;
- continue;
- }
-
- if (strcmp(argv[1], "--abs-relocs") == 0) {
- show_absolute_relocs = 1;
- continue;
- }
- else if (strcmp(argv[1], "--text") == 0) {
- as_text = 1;
- continue;
- }
- }
- else if (!fname) {
- fname = arg;
- continue;
- }
- usage();
- }
- if (!fname) {
- usage();
- }
- fp = fopen(fname, "r");
- if (!fp) {
- die("Cannot open %s: %s\n",
- fname, strerror(errno));
- }
- read_ehdr(fp);
- read_shdrs(fp);
- read_strtabs(fp);
- read_symtabs(fp);
- read_relocs(fp);
- if (show_absolute_syms) {
- print_absolute_symbols();
- return 0;
- }
- if (show_absolute_relocs) {
- print_absolute_relocs();
- return 0;
- }
- emit_relocs(as_text);
- return 0;
-}
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 105b21f..68c0f32 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -9,3 +9,4 @@ unifdef
ihex2fw
recordmcount
docproc
+x86-relocs
diff --git a/scripts/Makefile b/scripts/Makefile
index df7678f..a241359d 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -8,11 +8,14 @@
# conmakehash: Create arrays for initializing the kernel console tables
# docproc: Used in Documentation/DocBook

+HOST_EXTRACFLAGS += -I$(srctree)/tools/include
+
hostprogs-$(CONFIG_KALLSYMS) += kallsyms
hostprogs-$(CONFIG_LOGO) += pnmtologo
hostprogs-$(CONFIG_VT) += conmakehash
hostprogs-$(CONFIG_IKCONFIG) += bin2c
hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
+hostprogs-$(CONFIG_X86) += x86-relocs

always := $(hostprogs-y) $(hostprogs-m)

diff --git a/scripts/x86-relocs.c b/scripts/x86-relocs.c
new file mode 100644
index 0000000..0291470
--- /dev/null
+++ b/scripts/x86-relocs.c
@@ -0,0 +1,797 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <elf.h>
+#include <byteswap.h>
+#define USE_BSD
+#include <endian.h>
+#include <regex.h>
+#include <tools/le_byteshift.h>
+
+static void die(char *fmt, ...);
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+static Elf32_Ehdr ehdr;
+static unsigned long reloc_count, reloc_idx;
+static unsigned long *relocs;
+static unsigned long reloc16_count, reloc16_idx;
+static unsigned long *relocs16;
+
+struct section {
+ Elf32_Shdr shdr;
+ struct section *link;
+ Elf32_Sym *symtab;
+ Elf32_Rel *reltab;
+ char *strtab;
+};
+static struct section *secs;
+
+enum symtype {
+ S_ABS,
+ S_REL,
+ S_SEG,
+ S_LIN,
+ S_NSYMTYPES
+};
+
+static const char * const sym_regex_kernel[S_NSYMTYPES] = {
+/*
+ * Following symbols have been audited. There values are constant and do
+ * not change if bzImage is loaded at a different physical address than
+ * the address for which it has been compiled. Don't warn user about
+ * absolute relocations present w.r.t these symbols.
+ */
+ [S_ABS] =
+ "^(xen_irq_disable_direct_reloc$|"
+ "xen_save_fl_direct_reloc$|"
+ "VDSO|"
+ "__crc_)",
+
+/*
+ * These symbols are known to be relative, even if the linker marks them
+ * as absolute (typically defined outside any section in the linker script.)
+ */
+ [S_REL] =
+ "^_end$",
+};
+
+
+static const char * const sym_regex_realmode[S_NSYMTYPES] = {
+/*
+ * These are 16-bit segment symbols when compiling 16-bit code.
+ */
+ [S_SEG] =
+ "^real_mode_seg$",
+
+/*
+ * These are offsets belonging to segments, as opposed to linear addresses,
+ * when compiling 16-bit code.
+ */
+ [S_LIN] =
+ "^pa_",
+};
+
+static const char * const *sym_regex;
+
+static regex_t sym_regex_c[S_NSYMTYPES];
+static int is_reloc(enum symtype type, const char *sym_name)
+{
+ return sym_regex[type] &&
+ !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0);
+}
+
+static void regex_init(int use_real_mode)
+{
+ char errbuf[128];
+ int err;
+ int i;
+
+ if (use_real_mode)
+ sym_regex = sym_regex_realmode;
+ else
+ sym_regex = sym_regex_kernel;
+
+ for (i = 0; i < S_NSYMTYPES; i++) {
+ if (!sym_regex[i])
+ continue;
+
+ err = regcomp(&sym_regex_c[i], sym_regex[i],
+ REG_EXTENDED|REG_NOSUB);
+
+ if (err) {
+ regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf);
+ die("%s", errbuf);
+ }
+ }
+}
+
+static void die(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+static const char *sym_type(unsigned type)
+{
+ static const char *type_name[] = {
+#define SYM_TYPE(X) [X] = #X
+ SYM_TYPE(STT_NOTYPE),
+ SYM_TYPE(STT_OBJECT),
+ SYM_TYPE(STT_FUNC),
+ SYM_TYPE(STT_SECTION),
+ SYM_TYPE(STT_FILE),
+ SYM_TYPE(STT_COMMON),
+ SYM_TYPE(STT_TLS),
+#undef SYM_TYPE
+ };
+ const char *name = "unknown sym type name";
+ if (type < ARRAY_SIZE(type_name)) {
+ name = type_name[type];
+ }
+ return name;
+}
+
+static const char *sym_bind(unsigned bind)
+{
+ static const char *bind_name[] = {
+#define SYM_BIND(X) [X] = #X
+ SYM_BIND(STB_LOCAL),
+ SYM_BIND(STB_GLOBAL),
+ SYM_BIND(STB_WEAK),
+#undef SYM_BIND
+ };
+ const char *name = "unknown sym bind name";
+ if (bind < ARRAY_SIZE(bind_name)) {
+ name = bind_name[bind];
+ }
+ return name;
+}
+
+static const char *sym_visibility(unsigned visibility)
+{
+ static const char *visibility_name[] = {
+#define SYM_VISIBILITY(X) [X] = #X
+ SYM_VISIBILITY(STV_DEFAULT),
+ SYM_VISIBILITY(STV_INTERNAL),
+ SYM_VISIBILITY(STV_HIDDEN),
+ SYM_VISIBILITY(STV_PROTECTED),
+#undef SYM_VISIBILITY
+ };
+ const char *name = "unknown sym visibility name";
+ if (visibility < ARRAY_SIZE(visibility_name)) {
+ name = visibility_name[visibility];
+ }
+ return name;
+}
+
+static const char *rel_type(unsigned type)
+{
+ static const char *type_name[] = {
+#define REL_TYPE(X) [X] = #X
+ REL_TYPE(R_386_NONE),
+ REL_TYPE(R_386_32),
+ REL_TYPE(R_386_PC32),
+ REL_TYPE(R_386_GOT32),
+ REL_TYPE(R_386_PLT32),
+ REL_TYPE(R_386_COPY),
+ REL_TYPE(R_386_GLOB_DAT),
+ REL_TYPE(R_386_JMP_SLOT),
+ REL_TYPE(R_386_RELATIVE),
+ REL_TYPE(R_386_GOTOFF),
+ REL_TYPE(R_386_GOTPC),
+ REL_TYPE(R_386_8),
+ REL_TYPE(R_386_PC8),
+ REL_TYPE(R_386_16),
+ REL_TYPE(R_386_PC16),
+#undef REL_TYPE
+ };
+ const char *name = "unknown type rel type name";
+ if (type < ARRAY_SIZE(type_name) && type_name[type]) {
+ name = type_name[type];
+ }
+ return name;
+}
+
+static const char *sec_name(unsigned shndx)
+{
+ const char *sec_strtab;
+ const char *name;
+ sec_strtab = secs[ehdr.e_shstrndx].strtab;
+ name = "<noname>";
+ if (shndx < ehdr.e_shnum) {
+ name = sec_strtab + secs[shndx].shdr.sh_name;
+ }
+ else if (shndx == SHN_ABS) {
+ name = "ABSOLUTE";
+ }
+ else if (shndx == SHN_COMMON) {
+ name = "COMMON";
+ }
+ return name;
+}
+
+static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
+{
+ const char *name;
+ name = "<noname>";
+ if (sym->st_name) {
+ name = sym_strtab + sym->st_name;
+ }
+ else {
+ name = sec_name(sym->st_shndx);
+ }
+ return name;
+}
+
+
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+#define le16_to_cpu(val) bswap_16(val)
+#define le32_to_cpu(val) bswap_32(val)
+#endif
+
+static uint16_t elf16_to_cpu(uint16_t val)
+{
+ return le16_to_cpu(val);
+}
+
+static uint32_t elf32_to_cpu(uint32_t val)
+{
+ return le32_to_cpu(val);
+}
+
+static void read_ehdr(FILE *fp)
+{
+ if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
+ die("Cannot read ELF header: %s\n",
+ strerror(errno));
+ }
+ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
+ die("No ELF magic\n");
+ }
+ if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
+ die("Not a 32 bit executable\n");
+ }
+ if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
+ die("Not a LSB ELF executable\n");
+ }
+ if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
+ die("Unknown ELF version\n");
+ }
+ /* Convert the fields to native endian */
+ ehdr.e_type = elf16_to_cpu(ehdr.e_type);
+ ehdr.e_machine = elf16_to_cpu(ehdr.e_machine);
+ ehdr.e_version = elf32_to_cpu(ehdr.e_version);
+ ehdr.e_entry = elf32_to_cpu(ehdr.e_entry);
+ ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff);
+ ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff);
+ ehdr.e_flags = elf32_to_cpu(ehdr.e_flags);
+ ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize);
+ ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
+ ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum);
+ ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
+ ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum);
+ ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx);
+
+ if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
+ die("Unsupported ELF header type\n");
+ }
+ if (ehdr.e_machine != EM_386) {
+ die("Not for x86\n");
+ }
+ if (ehdr.e_version != EV_CURRENT) {
+ die("Unknown ELF version\n");
+ }
+ if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
+ die("Bad Elf header size\n");
+ }
+ if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
+ die("Bad program header entry\n");
+ }
+ if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
+ die("Bad section header entry\n");
+ }
+ if (ehdr.e_shstrndx >= ehdr.e_shnum) {
+ die("String table index out of bounds\n");
+ }
+}
+
+static void read_shdrs(FILE *fp)
+{
+ int i;
+ Elf32_Shdr shdr;
+
+ secs = calloc(ehdr.e_shnum, sizeof(struct section));
+ if (!secs) {
+ die("Unable to allocate %d section headers\n",
+ ehdr.e_shnum);
+ }
+ if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ ehdr.e_shoff, strerror(errno));
+ }
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (fread(&shdr, sizeof shdr, 1, fp) != 1)
+ die("Cannot read ELF section headers %d/%d: %s\n",
+ i, ehdr.e_shnum, strerror(errno));
+ sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name);
+ sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type);
+ sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags);
+ sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr);
+ sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset);
+ sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size);
+ sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link);
+ sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info);
+ sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
+ sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize);
+ if (sec->shdr.sh_link < ehdr.e_shnum)
+ sec->link = &secs[sec->shdr.sh_link];
+ }
+
+}
+
+static void read_strtabs(FILE *fp)
+{
+ int i;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (sec->shdr.sh_type != SHT_STRTAB) {
+ continue;
+ }
+ sec->strtab = malloc(sec->shdr.sh_size);
+ if (!sec->strtab) {
+ die("malloc of %d bytes for strtab failed\n",
+ sec->shdr.sh_size);
+ }
+ if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ sec->shdr.sh_offset, strerror(errno));
+ }
+ if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
+ != sec->shdr.sh_size) {
+ die("Cannot read symbol table: %s\n",
+ strerror(errno));
+ }
+ }
+}
+
+static void read_symtabs(FILE *fp)
+{
+ int i,j;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (sec->shdr.sh_type != SHT_SYMTAB) {
+ continue;
+ }
+ sec->symtab = malloc(sec->shdr.sh_size);
+ if (!sec->symtab) {
+ die("malloc of %d bytes for symtab failed\n",
+ sec->shdr.sh_size);
+ }
+ if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ sec->shdr.sh_offset, strerror(errno));
+ }
+ if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
+ != sec->shdr.sh_size) {
+ die("Cannot read symbol table: %s\n",
+ strerror(errno));
+ }
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
+ Elf32_Sym *sym = &sec->symtab[j];
+ sym->st_name = elf32_to_cpu(sym->st_name);
+ sym->st_value = elf32_to_cpu(sym->st_value);
+ sym->st_size = elf32_to_cpu(sym->st_size);
+ sym->st_shndx = elf16_to_cpu(sym->st_shndx);
+ }
+ }
+}
+
+
+static void read_relocs(FILE *fp)
+{
+ int i,j;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (sec->shdr.sh_type != SHT_REL) {
+ continue;
+ }
+ sec->reltab = malloc(sec->shdr.sh_size);
+ if (!sec->reltab) {
+ die("malloc of %d bytes for relocs failed\n",
+ sec->shdr.sh_size);
+ }
+ if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ sec->shdr.sh_offset, strerror(errno));
+ }
+ if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
+ != sec->shdr.sh_size) {
+ die("Cannot read symbol table: %s\n",
+ strerror(errno));
+ }
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+ Elf32_Rel *rel = &sec->reltab[j];
+ rel->r_offset = elf32_to_cpu(rel->r_offset);
+ rel->r_info = elf32_to_cpu(rel->r_info);
+ }
+ }
+}
+
+
+static void print_absolute_symbols(void)
+{
+ int i;
+ printf("Absolute symbols\n");
+ printf(" Num: Value Size Type Bind Visibility Name\n");
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ char *sym_strtab;
+ int j;
+
+ if (sec->shdr.sh_type != SHT_SYMTAB) {
+ continue;
+ }
+ sym_strtab = sec->link->strtab;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
+ Elf32_Sym *sym;
+ const char *name;
+ sym = &sec->symtab[j];
+ name = sym_name(sym_strtab, sym);
+ if (sym->st_shndx != SHN_ABS) {
+ continue;
+ }
+ printf("%5d %08x %5d %10s %10s %12s %s\n",
+ j, sym->st_value, sym->st_size,
+ sym_type(ELF32_ST_TYPE(sym->st_info)),
+ sym_bind(ELF32_ST_BIND(sym->st_info)),
+ sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
+ name);
+ }
+ }
+ printf("\n");
+}
+
+static void print_absolute_relocs(void)
+{
+ int i, printed = 0;
+
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ struct section *sec_applies, *sec_symtab;
+ char *sym_strtab;
+ Elf32_Sym *sh_symtab;
+ int j;
+ if (sec->shdr.sh_type != SHT_REL) {
+ continue;
+ }
+ sec_symtab = sec->link;
+ sec_applies = &secs[sec->shdr.sh_info];
+ if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
+ continue;
+ }
+ sh_symtab = sec_symtab->symtab;
+ sym_strtab = sec_symtab->link->strtab;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+ Elf32_Rel *rel;
+ Elf32_Sym *sym;
+ const char *name;
+ rel = &sec->reltab[j];
+ sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+ name = sym_name(sym_strtab, sym);
+ if (sym->st_shndx != SHN_ABS) {
+ continue;
+ }
+
+ /* Absolute symbols are not relocated if bzImage is
+ * loaded at a non-compiled address. Display a warning
+ * to user at compile time about the absolute
+ * relocations present.
+ *
+ * User need to audit the code to make sure
+ * some symbols which should have been section
+ * relative have not become absolute because of some
+ * linker optimization or wrong programming usage.
+ *
+ * Before warning check if this absolute symbol
+ * relocation is harmless.
+ */
+ if (is_reloc(S_ABS, name) || is_reloc(S_REL, name))
+ continue;
+
+ if (!printed) {
+ printf("WARNING: Absolute relocations"
+ " present\n");
+ printf("Offset Info Type Sym.Value "
+ "Sym.Name\n");
+ printed = 1;
+ }
+
+ printf("%08x %08x %10s %08x %s\n",
+ rel->r_offset,
+ rel->r_info,
+ rel_type(ELF32_R_TYPE(rel->r_info)),
+ sym->st_value,
+ name);
+ }
+ }
+
+ if (printed)
+ printf("\n");
+}
+
+static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
+ int use_real_mode)
+{
+ int i;
+ /* Walk through the relocations */
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ char *sym_strtab;
+ Elf32_Sym *sh_symtab;
+ struct section *sec_applies, *sec_symtab;
+ int j;
+ struct section *sec = &secs[i];
+
+ if (sec->shdr.sh_type != SHT_REL) {
+ continue;
+ }
+ sec_symtab = sec->link;
+ sec_applies = &secs[sec->shdr.sh_info];
+ if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
+ continue;
+ }
+ sh_symtab = sec_symtab->symtab;
+ sym_strtab = sec_symtab->link->strtab;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+ Elf32_Rel *rel;
+ Elf32_Sym *sym;
+ unsigned r_type;
+ const char *symname;
+ rel = &sec->reltab[j];
+ sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+ r_type = ELF32_R_TYPE(rel->r_info);
+
+ switch (r_type) {
+ case R_386_NONE:
+ case R_386_PC32:
+ case R_386_PC16:
+ case R_386_PC8:
+ /*
+ * NONE can be ignored and and PC relative
+ * relocations don't need to be adjusted.
+ */
+ break;
+
+ case R_386_16:
+ symname = sym_name(sym_strtab, sym);
+ if (!use_real_mode)
+ goto bad;
+ if (sym->st_shndx == SHN_ABS) {
+ if (is_reloc(S_ABS, symname))
+ break;
+ else if (!is_reloc(S_SEG, symname))
+ goto bad;
+ } else {
+ if (is_reloc(S_LIN, symname))
+ goto bad;
+ else
+ break;
+ }
+ visit(rel, sym);
+ break;
+
+ case R_386_32:
+ symname = sym_name(sym_strtab, sym);
+ if (sym->st_shndx == SHN_ABS) {
+ if (is_reloc(S_ABS, symname))
+ break;
+ else if (!is_reloc(S_REL, symname))
+ goto bad;
+ } else {
+ if (use_real_mode &&
+ !is_reloc(S_LIN, symname))
+ break;
+ }
+ visit(rel, sym);
+ break;
+ default:
+ die("Unsupported relocation type: %s (%d)\n",
+ rel_type(r_type), r_type);
+ break;
+ bad:
+ symname = sym_name(sym_strtab, sym);
+ die("Invalid %s relocation: %s\n",
+ rel_type(r_type), symname);
+ }
+ }
+ }
+}
+
+static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+{
+ if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+ reloc16_count++;
+ else
+ reloc_count++;
+}
+
+static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+{
+ /* Remember the address that needs to be adjusted. */
+ if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+ relocs16[reloc16_idx++] = rel->r_offset;
+ else
+ relocs[reloc_idx++] = rel->r_offset;
+}
+
+static int cmp_relocs(const void *va, const void *vb)
+{
+ const unsigned long *a, *b;
+ a = va; b = vb;
+ return (*a == *b)? 0 : (*a > *b)? 1 : -1;
+}
+
+static int write32(unsigned int v, FILE *f)
+{
+ unsigned char buf[4];
+
+ put_unaligned_le32(v, buf);
+ return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
+}
+
+static void emit_relocs(int as_text, int use_real_mode)
+{
+ int i;
+ /* Count how many relocations I have and allocate space for them. */
+ reloc_count = 0;
+ walk_relocs(count_reloc, use_real_mode);
+ relocs = malloc(reloc_count * sizeof(relocs[0]));
+ if (!relocs) {
+ die("malloc of %d entries for relocs failed\n",
+ reloc_count);
+ }
+
+ relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
+ if (!relocs16) {
+ die("malloc of %d entries for relocs16 failed\n",
+ reloc16_count);
+ }
+ /* Collect up the relocations */
+ reloc_idx = 0;
+ walk_relocs(collect_reloc, use_real_mode);
+
+ if (reloc16_count && !use_real_mode)
+ die("Segment relocations found but --realmode not specified\n");
+
+ /* Order the relocations for more efficient processing */
+ qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
+ qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
+
+ /* Print the relocations */
+ if (as_text) {
+ /* Print the relocations in a form suitable that
+ * gas will like.
+ */
+ printf(".section \".data.reloc\",\"a\"\n");
+ printf(".balign 4\n");
+ if (use_real_mode) {
+ printf("\t.long %lu\n", reloc16_count);
+ for (i = 0; i < reloc16_count; i++)
+ printf("\t.long 0x%08lx\n", relocs16[i]);
+ printf("\t.long %lu\n", reloc_count);
+ for (i = 0; i < reloc_count; i++) {
+ printf("\t.long 0x%08lx\n", relocs[i]);
+ }
+ } else {
+ /* Print a stop */
+ printf("\t.long 0x%08lx\n", (unsigned long)0);
+ for (i = 0; i < reloc_count; i++) {
+ printf("\t.long 0x%08lx\n", relocs[i]);
+ }
+ }
+
+ printf("\n");
+ }
+ else {
+ if (use_real_mode) {
+ write32(reloc16_count, stdout);
+ for (i = 0; i < reloc16_count; i++)
+ write32(relocs16[i], stdout);
+ write32(reloc_count, stdout);
+
+ /* Now print each relocation */
+ for (i = 0; i < reloc_count; i++)
+ write32(relocs[i], stdout);
+ } else {
+ /* Print a stop */
+ write32(0, stdout);
+
+ /* Now print each relocation */
+ for (i = 0; i < reloc_count; i++) {
+ write32(relocs[i], stdout);
+ }
+ }
+ }
+}
+
+static void usage(void)
+{
+ die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
+}
+
+int main(int argc, char **argv)
+{
+ int show_absolute_syms, show_absolute_relocs;
+ int as_text, use_real_mode;
+ const char *fname;
+ FILE *fp;
+ int i;
+
+ show_absolute_syms = 0;
+ show_absolute_relocs = 0;
+ as_text = 0;
+ use_real_mode = 0;
+ fname = NULL;
+ for (i = 1; i < argc; i++) {
+ char *arg = argv[i];
+ if (*arg == '-') {
+ if (strcmp(arg, "--abs-syms") == 0) {
+ show_absolute_syms = 1;
+ continue;
+ }
+ if (strcmp(arg, "--abs-relocs") == 0) {
+ show_absolute_relocs = 1;
+ continue;
+ }
+ if (strcmp(arg, "--text") == 0) {
+ as_text = 1;
+ continue;
+ }
+ if (strcmp(arg, "--realmode") == 0) {
+ use_real_mode = 1;
+ continue;
+ }
+ }
+ else if (!fname) {
+ fname = arg;
+ continue;
+ }
+ usage();
+ }
+ if (!fname) {
+ usage();
+ }
+ regex_init(use_real_mode);
+ fp = fopen(fname, "r");
+ if (!fp) {
+ die("Cannot open %s: %s\n",
+ fname, strerror(errno));
+ }
+ read_ehdr(fp);
+ read_shdrs(fp);
+ read_strtabs(fp);
+ read_symtabs(fp);
+ read_relocs(fp);
+ if (show_absolute_syms) {
+ print_absolute_symbols();
+ return 0;
+ }
+ if (show_absolute_relocs) {
+ print_absolute_relocs();
+ return 0;
+ }
+ emit_relocs(as_text, use_real_mode);
+ return 0;
+}
--
1.7.9.5

2012-05-08 18:53:54

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 02/23] x86, realmode: realmode.bin infrastructure

> new file mode 100644
> index 0000000..f22a4f8
> --- /dev/null
> +++ b/arch/x86/realmode/Makefile
> @@ -0,0 +1,20 @@
> +#
> +# arch/x86/realmode/Makefile
Drop filename inside files - they will get wrong.

> +#
> +# This file is subject to the terms and conditions of the GNU General Public
> +# License. See the file "COPYING" in the main directory of this archive
> +# for more details.
This is useless boilerplate.

> --- /dev/null
> +++ b/arch/x86/realmode/rm/.gitignore
> @@ -0,0 +1,3 @@
> +pasyms.h
> +realmode.lds
> +realmode.relocs
> diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
> new file mode 100644
> index 0000000..7c3f202
> --- /dev/null
> +++ b/arch/x86/realmode/rm/Makefile
> @@ -0,0 +1,63 @@
> +#
> +# arch/x86/realmode/Makefile

And I think you proved my point concerning the filename here :-)

> +#
> +# This file is subject to the terms and conditions of the GNU General Public
> +# License. See the file "COPYING" in the main directory of this archive
> +# for more details.
> +#
> +#
> +
> +subdir- := wakeup
> +
> +always := realmode.bin
> +
> +realmode-y += header.o
I see no reason to use the "-y" variant of the name here.

> +
> +targets += $(realmode-y)
> +
> +REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y))

We try to avoid ALL_CAPS stuff in linux makefiles.
It is unreadable.

> +
> +sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p'
> +
> +quiet_cmd_pasyms = PASYMS $@
> + cmd_pasyms = $(NM) $(filter-out FORCE,$^) | \
> + sed $(sed-pasyms) | sort | uniq > $@
> +
> +$(obj)/pasyms.h: $(REALMODE_OBJS) FORCE
> + $(call if_changed,pasyms)
> +
> +$(obj)/realmode.lds: $(obj)/pasyms.h
> +
> +LDFLAGS_realmode.elf := --emit-relocs -T
> +CPPFLAGS_realmode.lds += -P -C -I$(obj)
> +
> +$(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE
> + $(call if_changed,ld)
> +
> +OBJCOPYFLAGS_realmode.bin := -O binary
> +
> +$(obj)/realmode.bin: $(obj)/realmode.elf
> + $(call if_changed,objcopy)
> +
> +quiet_cmd_relocs = RELOCS $@
> + cmd_relocs = scripts/x86-relocs --realmode $< > $@
> +$(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
> + $(call if_changed,relocs)
> +
> +# ---------------------------------------------------------------------------
> +
> +# How to compile the 16-bit code. Note we always compile for -march=i386,
> +# that way we can complain to the user if the CPU is insufficient.
> +KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \
> + -DDISABLE_BRANCH_PROFILING \
> + -Wall -Wstrict-prototypes \
> + -march=i386 -mregparm=3 \
> + -include $(srctree)/$(src)/../../boot/code16gcc.h \
> + -fno-strict-aliasing -fomit-frame-pointer \
> + $(call cc-option, -ffreestanding) \
> + $(call cc-option, -fno-toplevel-reorder,\
> + $(call cc-option, -fno-unit-at-a-time)) \
> + $(call cc-option, -fno-stack-protector) \
> + $(call cc-option, -mpreferred-stack-boundary=2)
> +KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__

How much is needed to avoid this misuse of kernel-internal build rules?
This was and is an ugly hack.

Sam

2012-05-08 19:15:05

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 02/23] x86, realmode: realmode.bin infrastructure

On 05/08/2012 11:53 AM, Sam Ravnborg wrote:
+# How to compile the 16-bit code. Note we always compile for -march=i386,
+# that way we can complain to the user if the CPU is insufficient.
+KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \
+ -DDISABLE_BRANCH_PROFILING \
+ -Wall -Wstrict-prototypes \
+ -march=i386 -mregparm=3 \
+ -include $(srctree)/$(src)/../../boot/code16gcc.h \
+ -fno-strict-aliasing -fomit-frame-pointer \
+ $(call cc-option, -ffreestanding) \
+ $(call cc-option, -fno-toplevel-reorder,\
+ $(call cc-option, -fno-unit-at-a-time)) \
+ $(call cc-option, -fno-stack-protector) \
+ $(call cc-option, -mpreferred-stack-boundary=2)
+KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__


>
> How much is needed to avoid this misuse of kernel-internal build rules?
> This was and is an ugly hack.
>

It is more or less the same as for arch/x86/boot and other things. If
there are better ways to do it suggestions are very much appreciated.

However, it is a bit of a tricky bit because we need *some* of the bits
of the target compiler configuration and some not (this is the same as
arch/x86/boot etc.) It is not "pure target" but it's also most
definitely not host.

-hpa

2012-05-08 20:15:32

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 02/23] x86, realmode: realmode.bin infrastructure

On 05/08/2012 12:14 PM, H. Peter Anvin wrote:
>>
>> How much is needed to avoid this misuse of kernel-internal build rules?
>> This was and is an ugly hack.
>>
>
> It is more or less the same as for arch/x86/boot and other things. If
> there are better ways to do it suggestions are very much appreciated.
>
> However, it is a bit of a tricky bit because we need *some* of the bits
> of the target compiler configuration and some not (this is the same as
> arch/x86/boot etc.) It is not "pure target" but it's also most
> definitely not host.
>

Anyway... to answer your direct question: all of that would have been
required anyway. In therms of build rules the overall patchset is
pretty much a lateral move from arch/x86/kernel/acpi/rm to
arch/x86/realmode/rm. That doesn't mean we couldn't do it
better/centralize/etc; however, none of this is new and would be a
separate change.

-hpa

2012-05-08 21:15:05

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 02/23] x86, realmode: realmode.bin infrastructure

On Tue, May 08, 2012 at 01:15:15PM -0700, H. Peter Anvin wrote:
> On 05/08/2012 12:14 PM, H. Peter Anvin wrote:
> >>
> >> How much is needed to avoid this misuse of kernel-internal build rules?
> >> This was and is an ugly hack.
> >>
> >
> > It is more or less the same as for arch/x86/boot and other things. If
> > there are better ways to do it suggestions are very much appreciated.
> >
> > However, it is a bit of a tricky bit because we need *some* of the bits
> > of the target compiler configuration and some not (this is the same as
> > arch/x86/boot etc.) It is not "pure target" but it's also most
> > definitely not host.
> >
>
> Anyway... to answer your direct question: all of that would have been
> required anyway. In therms of build rules the overall patchset is
> pretty much a lateral move from arch/x86/kernel/acpi/rm to
> arch/x86/realmode/rm. That doesn't mean we couldn't do it
> better/centralize/etc; however, none of this is new and would be a
> separate change.

Agreed.
It just hurst my stummack big-time when KBUILD_CFLAGS are manupulated
in a "random" Makefile.
Last time we looked at this I failed to come up with something better.

Sam

2012-05-08 21:21:46

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 02/23] x86, realmode: realmode.bin infrastructure

On 05/08/2012 02:11 PM, Sam Ravnborg wrote:
>
> Agreed.
> It just hurst my stummack big-time when KBUILD_CFLAGS are manupulated
> in a "random" Makefile.
> Last time we looked at this I failed to come up with something better.
>

Yes, I agree it sucks big time. If nothing else the bits in
arch/x86/boot and arch/x86/realmode/rm should be merged at some point.

-hpa

2012-05-08 22:14:09

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: 16-bit real-mode code support for relocs tool

Commit-ID: 433de739bbc22a5b2c87602116566ce27e3b4cab
Gitweb: http://git.kernel.org/tip/433de739bbc22a5b2c87602116566ce27e3b4cab
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:24 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:41:43 -0700

x86, realmode: 16-bit real-mode code support for relocs tool

A new option is added to the relocs tool called '--realmode'.
This option causes the generation of 16-bit segment relocations
and 32-bit linear relocations for the real-mode code. When
the real-mode code is moved to the low-memory during kernel
initialization, these relocation entries can be used to
relocate the code properly.

In the assembly code 16-bit segment relocations must be relative
to the 'real_mode_seg' absolute symbol. Linear relocations must be
relative to a symbol prefixed with 'pa_'.

16-bit segment relocation is used to load cs:ip in 16-bit code.
Linear relocations are used in the 32-bit code for relocatable
data references. They are declared in the linker script of the
real-mode code.

The relocs tool is moved to scripts/x86-relocs.c so it will
be compiled before building the arch/x86 tree.

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Jarkko Sakkinen <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/boot/compressed/Makefile | 11 +-
scripts/.gitignore | 1 +
scripts/Makefile | 3 +
.../compressed/relocs.c => scripts/x86-relocs.c | 233 +++++++++++++++-----
4 files changed, 185 insertions(+), 63 deletions(-)

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index fd55a2f..0435e8a 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -40,13 +40,12 @@ OBJCOPYFLAGS_vmlinux.bin := -R .comment -S
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)

+targets += vmlinux.bin.all vmlinux.relocs

-targets += vmlinux.bin.all vmlinux.relocs relocs
-hostprogs-$(CONFIG_X86_NEED_RELOCS) += relocs
-
-quiet_cmd_relocs = RELOCS $@
- cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
-$(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE
+CMD_RELOCS = scripts/x86-relocs
+quiet_cmd_relocs = RELOCS $@
+ cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $<
+$(obj)/vmlinux.relocs: vmlinux FORCE
$(call if_changed,relocs)

vmlinux.bin.all-y := $(obj)/vmlinux.bin
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 105b21f..68c0f32 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -9,3 +9,4 @@ unifdef
ihex2fw
recordmcount
docproc
+x86-relocs
diff --git a/scripts/Makefile b/scripts/Makefile
index df7678f..a241359d 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -8,11 +8,14 @@
# conmakehash: Create arrays for initializing the kernel console tables
# docproc: Used in Documentation/DocBook

+HOST_EXTRACFLAGS += -I$(srctree)/tools/include
+
hostprogs-$(CONFIG_KALLSYMS) += kallsyms
hostprogs-$(CONFIG_LOGO) += pnmtologo
hostprogs-$(CONFIG_VT) += conmakehash
hostprogs-$(CONFIG_IKCONFIG) += bin2c
hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
+hostprogs-$(CONFIG_X86) += x86-relocs

always := $(hostprogs-y) $(hostprogs-m)

diff --git a/arch/x86/boot/compressed/relocs.c b/scripts/x86-relocs.c
similarity index 77%
rename from arch/x86/boot/compressed/relocs.c
rename to scripts/x86-relocs.c
index fb7117a..0291470 100644
--- a/arch/x86/boot/compressed/relocs.c
+++ b/scripts/x86-relocs.c
@@ -18,6 +18,8 @@ static void die(char *fmt, ...);
static Elf32_Ehdr ehdr;
static unsigned long reloc_count, reloc_idx;
static unsigned long *relocs;
+static unsigned long reloc16_count, reloc16_idx;
+static unsigned long *relocs16;

struct section {
Elf32_Shdr shdr;
@@ -28,52 +30,82 @@ struct section {
};
static struct section *secs;

+enum symtype {
+ S_ABS,
+ S_REL,
+ S_SEG,
+ S_LIN,
+ S_NSYMTYPES
+};
+
+static const char * const sym_regex_kernel[S_NSYMTYPES] = {
/*
* Following symbols have been audited. There values are constant and do
* not change if bzImage is loaded at a different physical address than
* the address for which it has been compiled. Don't warn user about
* absolute relocations present w.r.t these symbols.
*/
-static const char abs_sym_regex[] =
+ [S_ABS] =
"^(xen_irq_disable_direct_reloc$|"
"xen_save_fl_direct_reloc$|"
"VDSO|"
- "__crc_)";
-static regex_t abs_sym_regex_c;
-static int is_abs_reloc(const char *sym_name)
-{
- return !regexec(&abs_sym_regex_c, sym_name, 0, NULL, 0);
-}
+ "__crc_)",

/*
* These symbols are known to be relative, even if the linker marks them
* as absolute (typically defined outside any section in the linker script.)
*/
-static const char rel_sym_regex[] =
- "^_end$";
-static regex_t rel_sym_regex_c;
-static int is_rel_reloc(const char *sym_name)
+ [S_REL] =
+ "^_end$",
+};
+
+
+static const char * const sym_regex_realmode[S_NSYMTYPES] = {
+/*
+ * These are 16-bit segment symbols when compiling 16-bit code.
+ */
+ [S_SEG] =
+ "^real_mode_seg$",
+
+/*
+ * These are offsets belonging to segments, as opposed to linear addresses,
+ * when compiling 16-bit code.
+ */
+ [S_LIN] =
+ "^pa_",
+};
+
+static const char * const *sym_regex;
+
+static regex_t sym_regex_c[S_NSYMTYPES];
+static int is_reloc(enum symtype type, const char *sym_name)
{
- return !regexec(&rel_sym_regex_c, sym_name, 0, NULL, 0);
+ return sym_regex[type] &&
+ !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0);
}

-static void regex_init(void)
+static void regex_init(int use_real_mode)
{
char errbuf[128];
int err;
-
- err = regcomp(&abs_sym_regex_c, abs_sym_regex,
- REG_EXTENDED|REG_NOSUB);
- if (err) {
- regerror(err, &abs_sym_regex_c, errbuf, sizeof errbuf);
- die("%s", errbuf);
- }
+ int i;

- err = regcomp(&rel_sym_regex_c, rel_sym_regex,
- REG_EXTENDED|REG_NOSUB);
- if (err) {
- regerror(err, &rel_sym_regex_c, errbuf, sizeof errbuf);
- die("%s", errbuf);
+ if (use_real_mode)
+ sym_regex = sym_regex_realmode;
+ else
+ sym_regex = sym_regex_kernel;
+
+ for (i = 0; i < S_NSYMTYPES; i++) {
+ if (!sym_regex[i])
+ continue;
+
+ err = regcomp(&sym_regex_c[i], sym_regex[i],
+ REG_EXTENDED|REG_NOSUB);
+
+ if (err) {
+ regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf);
+ die("%s", errbuf);
+ }
}
}

@@ -154,6 +186,10 @@ static const char *rel_type(unsigned type)
REL_TYPE(R_386_RELATIVE),
REL_TYPE(R_386_GOTOFF),
REL_TYPE(R_386_GOTPC),
+ REL_TYPE(R_386_8),
+ REL_TYPE(R_386_PC8),
+ REL_TYPE(R_386_16),
+ REL_TYPE(R_386_PC16),
#undef REL_TYPE
};
const char *name = "unknown type rel type name";
@@ -189,7 +225,7 @@ static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
name = sym_strtab + sym->st_name;
}
else {
- name = sec_name(secs[sym->st_shndx].shdr.sh_name);
+ name = sec_name(sym->st_shndx);
}
return name;
}
@@ -472,7 +508,7 @@ static void print_absolute_relocs(void)
* Before warning check if this absolute symbol
* relocation is harmless.
*/
- if (is_abs_reloc(name) || is_rel_reloc(name))
+ if (is_reloc(S_ABS, name) || is_reloc(S_REL, name))
continue;

if (!printed) {
@@ -496,7 +532,8 @@ static void print_absolute_relocs(void)
printf("\n");
}

-static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
+static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
+ int use_real_mode)
{
int i;
/* Walk through the relocations */
@@ -521,30 +558,62 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
Elf32_Rel *rel;
Elf32_Sym *sym;
unsigned r_type;
+ const char *symname;
rel = &sec->reltab[j];
sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
r_type = ELF32_R_TYPE(rel->r_info);
- /* Don't visit relocations to absolute symbols */
- if (sym->st_shndx == SHN_ABS &&
- !is_rel_reloc(sym_name(sym_strtab, sym))) {
- continue;
- }
+
switch (r_type) {
case R_386_NONE:
case R_386_PC32:
+ case R_386_PC16:
+ case R_386_PC8:
/*
* NONE can be ignored and and PC relative
* relocations don't need to be adjusted.
*/
break;
+
+ case R_386_16:
+ symname = sym_name(sym_strtab, sym);
+ if (!use_real_mode)
+ goto bad;
+ if (sym->st_shndx == SHN_ABS) {
+ if (is_reloc(S_ABS, symname))
+ break;
+ else if (!is_reloc(S_SEG, symname))
+ goto bad;
+ } else {
+ if (is_reloc(S_LIN, symname))
+ goto bad;
+ else
+ break;
+ }
+ visit(rel, sym);
+ break;
+
case R_386_32:
- /* Visit relocations that need to be adjusted */
+ symname = sym_name(sym_strtab, sym);
+ if (sym->st_shndx == SHN_ABS) {
+ if (is_reloc(S_ABS, symname))
+ break;
+ else if (!is_reloc(S_REL, symname))
+ goto bad;
+ } else {
+ if (use_real_mode &&
+ !is_reloc(S_LIN, symname))
+ break;
+ }
visit(rel, sym);
break;
default:
die("Unsupported relocation type: %s (%d)\n",
rel_type(r_type), r_type);
break;
+ bad:
+ symname = sym_name(sym_strtab, sym);
+ die("Invalid %s relocation: %s\n",
+ rel_type(r_type), symname);
}
}
}
@@ -552,13 +621,19 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))

static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
{
- reloc_count += 1;
+ if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+ reloc16_count++;
+ else
+ reloc_count++;
}

static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
{
/* Remember the address that needs to be adjusted. */
- relocs[reloc_idx++] = rel->r_offset;
+ if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+ relocs16[reloc16_idx++] = rel->r_offset;
+ else
+ relocs[reloc_idx++] = rel->r_offset;
}

static int cmp_relocs(const void *va, const void *vb)
@@ -568,23 +643,41 @@ static int cmp_relocs(const void *va, const void *vb)
return (*a == *b)? 0 : (*a > *b)? 1 : -1;
}

-static void emit_relocs(int as_text)
+static int write32(unsigned int v, FILE *f)
+{
+ unsigned char buf[4];
+
+ put_unaligned_le32(v, buf);
+ return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
+}
+
+static void emit_relocs(int as_text, int use_real_mode)
{
int i;
/* Count how many relocations I have and allocate space for them. */
reloc_count = 0;
- walk_relocs(count_reloc);
+ walk_relocs(count_reloc, use_real_mode);
relocs = malloc(reloc_count * sizeof(relocs[0]));
if (!relocs) {
die("malloc of %d entries for relocs failed\n",
reloc_count);
}
+
+ relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
+ if (!relocs16) {
+ die("malloc of %d entries for relocs16 failed\n",
+ reloc16_count);
+ }
/* Collect up the relocations */
reloc_idx = 0;
- walk_relocs(collect_reloc);
+ walk_relocs(collect_reloc, use_real_mode);
+
+ if (reloc16_count && !use_real_mode)
+ die("Segment relocations found but --realmode not specified\n");

/* Order the relocations for more efficient processing */
qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
+ qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);

/* Print the relocations */
if (as_text) {
@@ -593,58 +686,83 @@ static void emit_relocs(int as_text)
*/
printf(".section \".data.reloc\",\"a\"\n");
printf(".balign 4\n");
- for (i = 0; i < reloc_count; i++) {
- printf("\t .long 0x%08lx\n", relocs[i]);
+ if (use_real_mode) {
+ printf("\t.long %lu\n", reloc16_count);
+ for (i = 0; i < reloc16_count; i++)
+ printf("\t.long 0x%08lx\n", relocs16[i]);
+ printf("\t.long %lu\n", reloc_count);
+ for (i = 0; i < reloc_count; i++) {
+ printf("\t.long 0x%08lx\n", relocs[i]);
+ }
+ } else {
+ /* Print a stop */
+ printf("\t.long 0x%08lx\n", (unsigned long)0);
+ for (i = 0; i < reloc_count; i++) {
+ printf("\t.long 0x%08lx\n", relocs[i]);
+ }
}
+
printf("\n");
}
else {
- unsigned char buf[4];
- /* Print a stop */
- fwrite("\0\0\0\0", 4, 1, stdout);
- /* Now print each relocation */
- for (i = 0; i < reloc_count; i++) {
- put_unaligned_le32(relocs[i], buf);
- fwrite(buf, 4, 1, stdout);
+ if (use_real_mode) {
+ write32(reloc16_count, stdout);
+ for (i = 0; i < reloc16_count; i++)
+ write32(relocs16[i], stdout);
+ write32(reloc_count, stdout);
+
+ /* Now print each relocation */
+ for (i = 0; i < reloc_count; i++)
+ write32(relocs[i], stdout);
+ } else {
+ /* Print a stop */
+ write32(0, stdout);
+
+ /* Now print each relocation */
+ for (i = 0; i < reloc_count; i++) {
+ write32(relocs[i], stdout);
+ }
}
}
}

static void usage(void)
{
- die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n");
+ die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
}

int main(int argc, char **argv)
{
int show_absolute_syms, show_absolute_relocs;
- int as_text;
+ int as_text, use_real_mode;
const char *fname;
FILE *fp;
int i;

- regex_init();
-
show_absolute_syms = 0;
show_absolute_relocs = 0;
as_text = 0;
+ use_real_mode = 0;
fname = NULL;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (*arg == '-') {
- if (strcmp(argv[1], "--abs-syms") == 0) {
+ if (strcmp(arg, "--abs-syms") == 0) {
show_absolute_syms = 1;
continue;
}
-
- if (strcmp(argv[1], "--abs-relocs") == 0) {
+ if (strcmp(arg, "--abs-relocs") == 0) {
show_absolute_relocs = 1;
continue;
}
- else if (strcmp(argv[1], "--text") == 0) {
+ if (strcmp(arg, "--text") == 0) {
as_text = 1;
continue;
}
+ if (strcmp(arg, "--realmode") == 0) {
+ use_real_mode = 1;
+ continue;
+ }
}
else if (!fname) {
fname = arg;
@@ -655,6 +773,7 @@ int main(int argc, char **argv)
if (!fname) {
usage();
}
+ regex_init(use_real_mode);
fp = fopen(fname, "r");
if (!fp) {
die("Cannot open %s: %s\n",
@@ -673,6 +792,6 @@ int main(int argc, char **argv)
print_absolute_relocs();
return 0;
}
- emit_relocs(as_text);
+ emit_relocs(as_text, use_real_mode);
return 0;
}

2012-05-08 22:14:56

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: realmode.bin infrastructure

Commit-ID: b3266bd6ff52efb9e57c7fbfff4c8f7363dfaab3
Gitweb: http://git.kernel.org/tip/b3266bd6ff52efb9e57c7fbfff4c8f7363dfaab3
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:25 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:41:48 -0700

x86, realmode: realmode.bin infrastructure

Create realmode.bin and realmode.relocs files. Piggy
pack them into relocatable object that will be included
into .init.data section of the main kernel image.

The first file includes binary image of the real-mode code.
The latter file includes all relocations. The layout of the
binary image is specified in realmode.lds.S. The makefile
generates pa_ prefixed symbols for each exported global.
These are used in 32-bit code and in realmode header to
define symbols that need to be relocated.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Originally-by: H. Peter Anvin <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/Kbuild | 2 +-
arch/x86/realmode/Makefile | 20 ++++++++++
arch/x86/realmode/rm/.gitignore | 3 ++
arch/x86/realmode/rm/Makefile | 63 ++++++++++++++++++++++++++++++++
arch/x86/realmode/rm/header.S | 16 ++++++++
arch/x86/realmode/rm/realmode.lds.S | 68 +++++++++++++++++++++++++++++++++++
arch/x86/realmode/rmpiggy.S | 18 +++++++++
7 files changed, 189 insertions(+), 1 deletions(-)

diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild
index 0e9dec6..e5287d8 100644
--- a/arch/x86/Kbuild
+++ b/arch/x86/Kbuild
@@ -1,4 +1,3 @@
-
obj-$(CONFIG_KVM) += kvm/

# Xen paravirtualization support
@@ -7,6 +6,7 @@ obj-$(CONFIG_XEN) += xen/
# lguest paravirtualization support
obj-$(CONFIG_LGUEST_GUEST) += lguest/

+obj-y += realmode/
obj-y += kernel/
obj-y += mm/

diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile
new file mode 100644
index 0000000..f22a4f8
--- /dev/null
+++ b/arch/x86/realmode/Makefile
@@ -0,0 +1,20 @@
+#
+# arch/x86/realmode/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+#
+
+subdir- := rm
+
+obj-y += rmpiggy.o
+
+$(obj)/rmpiggy.o: $(obj)/rm/realmode.relocs $(obj)/rm/realmode.bin
+
+$(obj)/rm/realmode.bin: FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/rm $@
+
+$(obj)/rm/realmode.relocs: FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/rm $@
diff --git a/arch/x86/realmode/rm/.gitignore b/arch/x86/realmode/rm/.gitignore
new file mode 100644
index 0000000..b6ed3a2
--- /dev/null
+++ b/arch/x86/realmode/rm/.gitignore
@@ -0,0 +1,3 @@
+pasyms.h
+realmode.lds
+realmode.relocs
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
new file mode 100644
index 0000000..7c3f202
--- /dev/null
+++ b/arch/x86/realmode/rm/Makefile
@@ -0,0 +1,63 @@
+#
+# arch/x86/realmode/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+#
+
+subdir- := wakeup
+
+always := realmode.bin
+
+realmode-y += header.o
+
+targets += $(realmode-y)
+
+REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y))
+
+sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p'
+
+quiet_cmd_pasyms = PASYMS $@
+ cmd_pasyms = $(NM) $(filter-out FORCE,$^) | \
+ sed $(sed-pasyms) | sort | uniq > $@
+
+$(obj)/pasyms.h: $(REALMODE_OBJS) FORCE
+ $(call if_changed,pasyms)
+
+$(obj)/realmode.lds: $(obj)/pasyms.h
+
+LDFLAGS_realmode.elf := --emit-relocs -T
+CPPFLAGS_realmode.lds += -P -C -I$(obj)
+
+$(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE
+ $(call if_changed,ld)
+
+OBJCOPYFLAGS_realmode.bin := -O binary
+
+$(obj)/realmode.bin: $(obj)/realmode.elf
+ $(call if_changed,objcopy)
+
+quiet_cmd_relocs = RELOCS $@
+ cmd_relocs = scripts/x86-relocs --realmode $< > $@
+$(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
+ $(call if_changed,relocs)
+
+# ---------------------------------------------------------------------------
+
+# How to compile the 16-bit code. Note we always compile for -march=i386,
+# that way we can complain to the user if the CPU is insufficient.
+KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \
+ -DDISABLE_BRANCH_PROFILING \
+ -Wall -Wstrict-prototypes \
+ -march=i386 -mregparm=3 \
+ -include $(srctree)/$(src)/../../boot/code16gcc.h \
+ -fno-strict-aliasing -fomit-frame-pointer \
+ $(call cc-option, -ffreestanding) \
+ $(call cc-option, -fno-toplevel-reorder,\
+ $(call cc-option, -fno-unit-at-a-time)) \
+ $(call cc-option, -fno-stack-protector) \
+ $(call cc-option, -mpreferred-stack-boundary=2)
+KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
+GCOV_PROFILE := n
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
new file mode 100644
index 0000000..7be17f2
--- /dev/null
+++ b/arch/x86/realmode/rm/header.S
@@ -0,0 +1,16 @@
+/*
+ * Real-mode blob header; this should match realmode.h and be
+ * readonly; for mutable data instead add pointers into the .data
+ * or .bss sections as appropriate.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+ .section ".header", "a"
+
+ENTRY(real_mode_header)
+ .long pa_text_start
+ .long pa_ro_end
+ .long pa_end
+END(real_mode_header)
diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S
new file mode 100644
index 0000000..c5b8a4f
--- /dev/null
+++ b/arch/x86/realmode/rm/realmode.lds.S
@@ -0,0 +1,68 @@
+/*
+ * realmode.lds.S
+ *
+ * Linker script for the real-mode code
+ */
+
+#include <asm/page_types.h>
+
+#undef i386
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+
+SECTIONS
+{
+ real_mode_seg = 0;
+
+ . = 0;
+ .header : {
+ pa_real_mode_base = .;
+ *(.header)
+ }
+
+ . = ALIGN(4);
+ .rodata : {
+ *(.rodata)
+ *(.rodata.*)
+ }
+
+ . = ALIGN(PAGE_SIZE);
+ .text : {
+ pa_text_start = .;
+ *(.text)
+ *(.text.*)
+ }
+
+ .text32 : {
+ *(.text32)
+ *(.text32.*)
+ pa_ro_end = .;
+ }
+
+ . = ALIGN(PAGE_SIZE);
+ .data : {
+ *(.data)
+ *(.data.*)
+ }
+
+ . = ALIGN(128);
+ .bss : {
+ *(.bss*)
+ }
+
+ /* End signature for integrity checking */
+ . = ALIGN(4);
+ .signature : {
+ *(.signature)
+ pa_end = .;
+ }
+
+ /DISCARD/ : {
+ *(.note*)
+ *(.debug*)
+ *(.eh_frame*)
+ }
+
+#include "pasyms.h"
+}
diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S
new file mode 100644
index 0000000..6047d7f
--- /dev/null
+++ b/arch/x86/realmode/rmpiggy.S
@@ -0,0 +1,18 @@
+/*
+ * Wrapper script for the realmode binary as a transport object
+ * before copying to low memory.
+ */
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+ .section ".init.data","aw"
+
+ .balign PAGE_SIZE
+
+ENTRY(real_mode_blob)
+ .incbin "arch/x86/realmode/rm/realmode.bin"
+END(real_mode_blob)
+
+ENTRY(real_mode_relocs)
+ .incbin "arch/x86/realmode/rm/realmode.relocs"
+END(real_mode_relocs)

2012-05-08 22:15:50

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Relocator for realmode code

Commit-ID: 084ee1c641a068bfd1194d545f7dc9ab2043eb35
Gitweb: http://git.kernel.org/tip/084ee1c641a068bfd1194d545f7dc9ab2043eb35
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:26 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:41:49 -0700

x86, realmode: Relocator for realmode code

Implements relocator for real mode code that is called
as part of setup_arch(). Processes segment relocations
and linear relocations. Real-mode code is relocated to
a free hole below 1 MB.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/include/asm/realmode.h | 26 +++++++++++++
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/realmode.c | 79 +++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/setup.c | 2 +
4 files changed, 108 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
new file mode 100644
index 0000000..dc1bba5
--- /dev/null
+++ b/arch/x86/include/asm/realmode.h
@@ -0,0 +1,26 @@
+#ifndef _ARCH_X86_REALMODE_H
+#define _ARCH_X86_REALMODE_H
+
+#include <linux/types.h>
+#include <asm/io.h>
+
+/* This must match data at realmode.S */
+struct real_mode_header {
+ u32 text_start;
+ u32 ro_end;
+ u32 end;
+} __attribute__((__packed__));
+
+extern struct real_mode_header real_mode_header;
+extern unsigned char *real_mode_base;
+
+extern unsigned long init_rsp;
+extern unsigned long initial_code;
+extern unsigned long initial_gs;
+
+extern unsigned char real_mode_blob[];
+extern unsigned char real_mode_relocs[];
+
+extern void __init setup_real_mode(void);
+
+#endif /* _ARCH_X86_REALMODE_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 532d2e0..f9e19d4 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -36,6 +36,7 @@ obj-y += pci-iommu_table.o
obj-y += resource.o

obj-y += trampoline.o trampoline_$(BITS).o
+obj-y += realmode.o
obj-y += process.o
obj-y += i387.o xsave.o
obj-y += ptrace.o
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
new file mode 100644
index 0000000..7415c42
--- /dev/null
+++ b/arch/x86/kernel/realmode.c
@@ -0,0 +1,79 @@
+#include <linux/io.h>
+#include <linux/memblock.h>
+
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <asm/realmode.h>
+
+unsigned char *real_mode_base;
+struct real_mode_header real_mode_header;
+
+void __init setup_real_mode(void)
+{
+ phys_addr_t mem;
+ u16 real_mode_seg;
+ u32 *rel;
+ u32 count;
+ u32 *ptr;
+ u16 *seg;
+ int i;
+
+ struct real_mode_header *header =
+ (struct real_mode_header *) real_mode_blob;
+
+ size_t size = PAGE_ALIGN(header->end);
+
+ /* Has to be in very low memory so we can execute real-mode AP code. */
+ mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
+ if (!mem)
+ panic("Cannot allocate trampoline\n");
+
+ real_mode_base = __va(mem);
+ memblock_reserve(mem, size);
+
+ printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
+ real_mode_base, (unsigned long long)mem, size);
+
+ memcpy(real_mode_base, real_mode_blob, size);
+
+ real_mode_seg = __pa(real_mode_base) >> 4;
+ rel = (u32 *) real_mode_relocs;
+
+ /* 16-bit segment relocations. */
+ count = rel[0];
+ rel = &rel[1];
+ for (i = 0; i < count; i++) {
+ seg = (u16 *) (real_mode_base + rel[i]);
+ *seg = real_mode_seg;
+ }
+
+ /* 32-bit linear relocations. */
+ count = rel[i];
+ rel = &rel[i + 1];
+ for (i = 0; i < count; i++) {
+ ptr = (u32 *) (real_mode_base + rel[i]);
+ *ptr += __pa(real_mode_base);
+ }
+
+ /* Copied header will contain relocated physical addresses. */
+ memcpy(&real_mode_header, real_mode_base,
+ sizeof(struct real_mode_header));
+}
+
+/*
+ * set_real_mode_permissions() gets called very early, to guarantee the
+ * availability of low memory. This is before the proper kernel page
+ * tables are set up, so we cannot set page permissions in that
+ * function. Thus, we use an arch_initcall instead.
+ */
+static int __init set_real_mode_permissions(void)
+{
+ size_t all_size =
+ PAGE_ALIGN(real_mode_header.end) -
+ __pa(real_mode_base);
+
+ set_memory_x((unsigned long) real_mode_base, all_size >> PAGE_SHIFT);
+ return 0;
+}
+
+arch_initcall(set_real_mode_permissions);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 1a29015..56e4124 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -74,6 +74,7 @@
#include <asm/mtrr.h>
#include <asm/apic.h>
#include <asm/trampoline.h>
+#include <asm/realmode.h>
#include <asm/e820.h>
#include <asm/mpspec.h>
#include <asm/setup.h>
@@ -918,6 +919,7 @@ void __init setup_arch(char **cmdline_p)
max_pfn_mapped<<PAGE_SHIFT);

setup_trampolines();
+ setup_real_mode();

init_gbpages();

2012-05-08 22:16:44

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Move reboot_32. S to unified realmode code

Commit-ID: 5a8c9aebe04a78b069828d364798d5f24c5a42bd
Gitweb: http://git.kernel.org/tip/5a8c9aebe04a78b069828d364798d5f24c5a42bd
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:27 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:41:50 -0700

x86, realmode: Move reboot_32.S to unified realmode code

Migrated reboot_32.S from x86_trampoline to the real-mode
blob.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/include/asm/realmode.h | 4 +
arch/x86/kernel/Makefile | 1 -
arch/x86/kernel/reboot.c | 25 +-------
arch/x86/realmode/rm/Makefile | 1 +
arch/x86/realmode/rm/header.S | 3 +
arch/x86/{kernel => realmode/rm}/reboot_32.S | 83 +++++++++++++-------------
6 files changed, 52 insertions(+), 65 deletions(-)

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index dc1bba5..bf26b06 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -9,6 +9,10 @@ struct real_mode_header {
u32 text_start;
u32 ro_end;
u32 end;
+ /* reboot */
+#ifdef CONFIG_X86_32
+ u32 machine_real_restart_asm;
+#endif
} __attribute__((__packed__));

extern struct real_mode_header real_mode_header;
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index f9e19d4..b71ef35 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -49,7 +49,6 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += cpu/
obj-y += acpi/
obj-y += reboot.o
-obj-$(CONFIG_X86_32) += reboot_32.o
obj-$(CONFIG_MCA) += mca_32.o
obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index d840e69..050eff2 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -24,6 +24,7 @@
#ifdef CONFIG_X86_32
# include <linux/ctype.h>
# include <linux/mc146818rtc.h>
+# include <asm/realmode.h>
#else
# include <asm/x86_init.h>
#endif
@@ -332,15 +333,10 @@ static int __init reboot_init(void)
}
core_initcall(reboot_init);

-extern const unsigned char machine_real_restart_asm[];
-extern const u64 machine_real_restart_gdt[3];
-
void machine_real_restart(unsigned int type)
{
- void *restart_va;
- unsigned long restart_pa;
- void (*restart_lowmem)(unsigned int);
- u64 *lowmem_gdt;
+ void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int))
+ real_mode_header.machine_real_restart_asm;

local_irq_disable();

@@ -369,21 +365,6 @@ void machine_real_restart(unsigned int type)
too. */
*((unsigned short *)0x472) = reboot_mode;

- /* Patch the GDT in the low memory trampoline */
- lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
-
- restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
- restart_pa = virt_to_phys(restart_va);
- restart_lowmem = (void (*)(unsigned int))restart_pa;
-
- /* GDT[0]: GDT self-pointer */
- lowmem_gdt[0] =
- (u64)(sizeof(machine_real_restart_gdt) - 1) +
- ((u64)virt_to_phys(lowmem_gdt) << 16);
- /* GDT[1]: 64K real mode code segment */
- lowmem_gdt[1] =
- GDT_ENTRY(0x009b, restart_pa, 0xffff);
-
/* Jump to the identity-mapped low memory code */
restart_lowmem(type);
}
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 7c3f202..3f851c4 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -12,6 +12,7 @@ subdir- := wakeup
always := realmode.bin

realmode-y += header.o
+realmode-$(CONFIG_X86_32) += reboot_32.o

targets += $(realmode-y)

diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index 7be17f2..db21401 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -13,4 +13,7 @@ ENTRY(real_mode_header)
.long pa_text_start
.long pa_ro_end
.long pa_end
+#ifdef CONFIG_X86_32
+ .long pa_machine_real_restart_asm
+#endif
END(real_mode_header)
diff --git a/arch/x86/kernel/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
similarity index 73%
rename from arch/x86/kernel/reboot_32.S
rename to arch/x86/realmode/rm/reboot_32.S
index 1d5c46d..83803c2 100644
--- a/arch/x86/kernel/reboot_32.S
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -13,34 +13,21 @@
*
* This code is called with the restart type (0 = BIOS, 1 = APM) in %eax.
*/
- .section ".x86_trampoline","a"
- .balign 16
+ .section ".text32", "ax"
.code32
-ENTRY(machine_real_restart_asm)
-r_base = .
- /* Get our own relocated address */
- call 1f
-1: popl %ebx
- subl $(1b - r_base), %ebx
-
- /* Compute the equivalent real-mode segment */
- movl %ebx, %ecx
- shrl $4, %ecx
-
- /* Patch post-real-mode segment jump */
- movw (dispatch_table - r_base)(%ebx,%eax,2),%ax
- movw %ax, (101f - r_base)(%ebx)
- movw %cx, (102f - r_base)(%ebx)
+ .globl machine_real_restart_asm

+ .balign 16
+machine_real_restart_asm:
/* Set up the IDT for real mode. */
- lidtl (machine_real_restart_idt - r_base)(%ebx)
+ lidtl pa_machine_real_restart_idt

/*
* Set up a GDT from which we can load segment descriptors for real
* mode. The GDT is not used in real mode; it is just needed here to
* prepare the descriptors.
*/
- lgdtl (machine_real_restart_gdt - r_base)(%ebx)
+ lgdtl pa_machine_real_restart_gdt

/*
* Load the data segment registers with 16-bit compatible values
@@ -51,7 +38,7 @@ r_base = .
movl %ecx, %fs
movl %ecx, %gs
movl %ecx, %ss
- ljmpl $8, $1f - r_base
+ ljmpw $8, $1f

/*
* This is 16-bit protected mode code to disable paging and the cache,
@@ -76,27 +63,32 @@ r_base = .
*
* Most of this work is probably excessive, but it is what is tested.
*/
+ .text
.code16
+
+ .balign 16
+machine_real_restart_asm16:
1:
xorl %ecx, %ecx
- movl %cr0, %eax
- andl $0x00000011, %eax
- orl $0x60000000, %eax
- movl %eax, %cr0
+ movl %cr0, %edx
+ andl $0x00000011, %edx
+ orl $0x60000000, %edx
+ movl %edx, %cr0
movl %ecx, %cr3
movl %cr0, %edx
andl $0x60000000, %edx /* If no cache bits -> no wbinvd */
jz 2f
wbinvd
2:
- andb $0x10, %al
- movl %eax, %cr0
+ andb $0x10, %dl
+ movl %edx, %cr0
.byte 0xea /* ljmpw */
-101: .word 0 /* Offset */
-102: .word 0 /* Segment */
+ .word 3f /* Offset */
+ .word real_mode_seg /* Segment */

-bios:
- ljmpw $0xf000, $0xfff0
+3:
+ testb $0, %al
+ jz bios

apm:
movw $0x1000, %ax
@@ -106,30 +98,37 @@ apm:
movw $0x0001, %bx
movw $0x0003, %cx
int $0x15
+ /* This should never return... */

-END(machine_real_restart_asm)
+bios:
+ ljmpw $0xf000, $0xfff0

- .balign 16
- /* These must match <asm/reboot.h */
-dispatch_table:
- .word bios - r_base
- .word apm - r_base
-END(dispatch_table)
+ .section ".rodata", "a"
+ .globl machine_real_restart_idt, machine_real_restart_gdt

.balign 16
machine_real_restart_idt:
.word 0xffff /* Length - real mode default value */
.long 0 /* Base - real mode default value */
-END(machine_real_restart_idt)

.balign 16
-ENTRY(machine_real_restart_gdt)
- .quad 0 /* Self-pointer, filled in by PM code */
- .quad 0 /* 16-bit code segment, filled in by PM code */
+machine_real_restart_gdt:
+ /* Self-pointer */
+ .word 0xffff /* Length - real mode default value */
+ .long pa_machine_real_restart_gdt
+ .word 0
+
+ /*
+ * 16-bit code segment pointing to real_mode_seg
+ * Selector value 8
+ */
+ .word 0xffff /* Limit */
+ .long 0x9b000000 + pa_real_mode_base
+ .word 0
+
/*
* 16-bit data segment with the selector value 16 = 0x10 and
* base value 0x100; since this is consistent with real mode
* semantics we don't have to reload the segments once CR0.PE = 0.
*/
.quad GDT_ENTRY(0x0093, 0x100, 0xffff)
-END(machine_real_restart_gdt)

2012-05-08 22:17:40

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Move SMP trampoline to unified realmode code

Commit-ID: 48927bbb97c7d4cf343c05827ab9ac30c60678cb
Gitweb: http://git.kernel.org/tip/48927bbb97c7d4cf343c05827ab9ac30c60678cb
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:28 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:41:51 -0700

x86, realmode: Move SMP trampoline to unified realmode code

Migrated SMP trampoline code to the real mode blob.
SMP trampoline code is not yet removed from
.x86_trampoline because it is needed by the wakeup
code.

[ hpa: always enable compiling startup_32_smp in head_32.S... it is
only a few instructions which go into .init on UP builds, and it makes
the rest of the code less #ifdef ugly. ]

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/include/asm/realmode.h | 18 ++++
arch/x86/kernel/head_32.S | 5 +-
arch/x86/kernel/head_64.S | 4 -
arch/x86/kernel/realmode.c | 14 +++
arch/x86/kernel/smpboot.c | 18 +++--
arch/x86/realmode/rm/Makefile | 1 +
arch/x86/realmode/rm/header.S | 11 +++
arch/x86/{kernel => realmode/rm}/trampoline_32.S | 63 ++++++++-------
arch/x86/{kernel => realmode/rm}/trampoline_64.S | 94 +++++++++++----------
9 files changed, 137 insertions(+), 91 deletions(-)

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index bf26b06..9b4a5da 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -13,6 +13,17 @@ struct real_mode_header {
#ifdef CONFIG_X86_32
u32 machine_real_restart_asm;
#endif
+ /* SMP trampoline */
+ u32 trampoline_data;
+ u32 trampoline_status;
+#ifdef CONFIG_X86_32
+ u32 startup_32_smp;
+ u32 boot_gdt;
+#else
+ u32 startup_64_smp;
+ u32 level3_ident_pgt;
+ u32 level3_kernel_pgt;
+#endif
} __attribute__((__packed__));

extern struct real_mode_header real_mode_header;
@@ -25,6 +36,13 @@ extern unsigned long initial_gs;
extern unsigned char real_mode_blob[];
extern unsigned char real_mode_relocs[];

+#ifdef CONFIG_X86_32
+extern unsigned char startup_32_smp[];
+extern unsigned char boot_gdt[];
+#else
+extern unsigned char secondary_startup_64[];
+#endif
+
extern void __init setup_real_mode(void);

#endif /* _ARCH_X86_REALMODE_H */
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index ce0be7c..a3c2b4f 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -273,10 +273,7 @@ num_subarch_entries = (. - subarch_entries) / 4
* If cpu hotplug is not supported then this code can go in init section
* which will be freed later
*/
-
__CPUINIT
-
-#ifdef CONFIG_SMP
ENTRY(startup_32_smp)
cld
movl $(__BOOT_DS),%eax
@@ -287,7 +284,7 @@ ENTRY(startup_32_smp)
movl pa(stack_start),%ecx
movl %eax,%ss
leal -__PAGE_OFFSET(%ecx),%esp
-#endif /* CONFIG_SMP */
+
default_entry:

/*
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 40f4eb3..d70bc2e 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -136,10 +136,6 @@ ident_complete:
/* Fixup phys_base */
addq %rbp, phys_base(%rip)

- /* Fixup trampoline */
- addq %rbp, trampoline_level4_pgt + 0(%rip)
- addq %rbp, trampoline_level4_pgt + (511*8)(%rip)
-
/* Due to ENTRY(), sometimes the empty space gets filled with
* zeros. Better take a jmp than relying on empty space being
* filled with 0x90 (nop)
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index 7415c42..a465775 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -58,6 +58,20 @@ void __init setup_real_mode(void)
/* Copied header will contain relocated physical addresses. */
memcpy(&real_mode_header, real_mode_base,
sizeof(struct real_mode_header));
+
+#ifdef CONFIG_X86_32
+ *((u32 *)__va(real_mode_header.startup_32_smp)) = __pa(startup_32_smp);
+ *((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt);
+#else
+ *((u64 *) __va(real_mode_header.startup_64_smp)) =
+ (u64) __pa(secondary_startup_64);
+
+ *((u64 *) __va(real_mode_header.level3_ident_pgt)) =
+ __pa(level3_ident_pgt) + _KERNPG_TABLE;
+
+ *((u64 *) __va(real_mode_header.level3_kernel_pgt)) =
+ __pa(level3_kernel_pgt) + _KERNPG_TABLE;
+#endif
}

/*
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 6e1e406..c7971ea 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -57,7 +57,7 @@
#include <asm/nmi.h>
#include <asm/irq.h>
#include <asm/idle.h>
-#include <asm/trampoline.h>
+#include <asm/realmode.h>
#include <asm/cpu.h>
#include <asm/numa.h>
#include <asm/pgtable.h>
@@ -73,6 +73,8 @@
#include <asm/smpboot_hooks.h>
#include <asm/i8259.h>

+#include <asm/realmode.h>
+
/* State of each CPU */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

@@ -662,8 +664,12 @@ static void __cpuinit announce_cpu(int cpu, int apicid)
*/
static int __cpuinit do_boot_cpu(int apicid, int cpu)
{
+ volatile u32 *trampoline_status =
+ (volatile u32 *) __va(real_mode_header.trampoline_status);
+ /* start_ip had better be page-aligned! */
+ unsigned long start_ip = real_mode_header.trampoline_data;
+
unsigned long boot_error = 0;
- unsigned long start_ip;
int timeout;
struct create_idle c_idle = {
.cpu = cpu,
@@ -713,9 +719,6 @@ do_rest:
initial_code = (unsigned long)start_secondary;
stack_start = c_idle.idle->thread.sp;

- /* start_ip had better be page-aligned! */
- start_ip = trampoline_address();
-
/* So we see what's up */
announce_cpu(cpu, apicid);

@@ -778,8 +781,7 @@ do_rest:
pr_debug("CPU%d: has booted.\n", cpu);
} else {
boot_error = 1;
- if (*(volatile u32 *)TRAMPOLINE_SYM(trampoline_status)
- == 0xA5A5A5A5)
+ if (*trampoline_status == 0xA5A5A5A5)
/* trampoline started but...? */
pr_err("CPU%d: Stuck ??\n", cpu);
else
@@ -805,7 +807,7 @@ do_rest:
}

/* mark "stuck" area as not stuck */
- *(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) = 0;
+ *trampoline_status = 0;

if (get_uv_system_type() != UV_NON_UNIQUE_APIC) {
/*
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 3f851c4..56ec64f 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -13,6 +13,7 @@ always := realmode.bin

realmode-y += header.o
realmode-$(CONFIG_X86_32) += reboot_32.o
+realmode-y += trampoline_$(BITS).o

targets += $(realmode-y)

diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index db21401..a979004 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -16,4 +16,15 @@ ENTRY(real_mode_header)
#ifdef CONFIG_X86_32
.long pa_machine_real_restart_asm
#endif
+ /* SMP trampoline */
+ .long pa_trampoline_data
+ .long pa_trampoline_status
+#ifdef CONFIG_X86_32
+ .long pa_startup_32_smp
+ .long pa_boot_gdt
+#else
+ .long pa_startup_64_smp
+ .long pa_level3_ident_pgt
+ .long pa_level3_kernel_pgt
+#endif
END(real_mode_header)
diff --git a/arch/x86/kernel/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
similarity index 53%
copy from arch/x86/kernel/trampoline_32.S
copy to arch/x86/realmode/rm/trampoline_32.S
index 451c0a7..18cb7fc 100644
--- a/arch/x86/kernel/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -6,8 +6,8 @@
*
* This is only used for booting secondary CPUs in SMP machine
*
- * Entry: CS:IP point to the start of our code, we are
- * in real mode with no stack, but the rest of the
+ * Entry: CS:IP point to the start of our code, we are
+ * in real mode with no stack, but the rest of the
* trampoline page to make our stack and everything else
* is a mystery.
*
@@ -15,16 +15,14 @@
*
* On entry to trampoline_data, the processor is in real mode
* with 16-bit addressing and 16-bit data. CS has some value
- * and IP is zero. Thus, data addresses need to be absolute
- * (no relocation) and are taken with regard to r_base.
+ * and IP is zero. Thus, we load CS to the physical segment
+ * of the real mode code before doing anything further.
*
- * If you work on this file, check the object module with
- * objdump --reloc to make sure there are no relocation
- * entries except for:
+ * The structure real_mode_header includes entries that need
+ * to be set up before executing this code:
*
- * TYPE VALUE
- * R_386_32 startup_32_smp
- * R_386_32 boot_gdt
+ * startup_32_smp
+ * boot_gdt
*/

#include <linux/linkage.h>
@@ -32,21 +30,24 @@
#include <asm/segment.h>
#include <asm/page_types.h>

-#ifdef CONFIG_SMP
-
- .section ".x86_trampoline","a"
- .balign PAGE_SIZE
+ .text
.code16
+ .globl trampoline_data

-ENTRY(trampoline_data)
-r_base = .
+ .balign PAGE_SIZE
+trampoline_data:
wbinvd # Needed for NUMA-Q should be harmless for others
+
+ .byte 0xea # ljmpw
+ .word 1f # Offset
+ .word real_mode_seg # Segment
+1:
mov %cs, %ax # Code and data in the same place
mov %ax, %ds

cli # We should be safe anyway

- movl $0xA5A5A5A5, trampoline_status - r_base
+ movl $0xA5A5A5A5, trampoline_status
# write marker for master knows we're running

/* GDT tables in non default location kernel can be beyond 16MB and
@@ -55,29 +56,31 @@ r_base = .
* to 32 bit.
*/

- lidtl boot_idt_descr - r_base # load idt with 0, 0
- lgdtl boot_gdt_descr - r_base # load gdt with whatever is appropriate
+ lidtl boot_idt_descr # load idt with 0, 0
+ lgdtl boot_gdt_descr # load gdt with whatever is appropriate

xor %ax, %ax
- inc %ax # protected mode (PE) bit
- lmsw %ax # into protected mode
+ inc %ax # protected mode (PE) bit
+ lmsw %ax # into protected mode
+
# flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
- ljmpl $__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET)
+ ljmpl *(startup_32_smp)
+
+ .data
+ .globl startup_32_smp, boot_gdt, trampoline_status

- # These need to be in the same 64K segment as the above;
- # hence we don't use the boot_gdt_descr defined in head.S
boot_gdt_descr:
.word __BOOT_DS + 7 # gdt limit
- .long boot_gdt - __PAGE_OFFSET # gdt base
+boot_gdt:
+ .long 0 # gdt base

boot_idt_descr:
.word 0 # idt limit = 0
.long 0 # idt base = 0L

-ENTRY(trampoline_status)
+trampoline_status:
.long 0

-.globl trampoline_end
-trampoline_end:
-
-#endif /* CONFIG_SMP */
+startup_32_smp:
+ .long 0x00000000
+ .word __BOOT_CS, 0
diff --git a/arch/x86/kernel/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
similarity index 71%
copy from arch/x86/kernel/trampoline_64.S
copy to arch/x86/realmode/rm/trampoline_64.S
index 09ff517..063da00 100644
--- a/arch/x86/kernel/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -5,8 +5,8 @@
* 4 Jan 1997 Michael Chastain: changed to gnu as.
* 15 Sept 2005 Eric Biederman: 64bit PIC support
*
- * Entry: CS:IP point to the start of our code, we are
- * in real mode with no stack, but the rest of the
+ * Entry: CS:IP point to the start of our code, we are
+ * in real mode with no stack, but the rest of the
* trampoline page to make our stack and everything else
* is a mystery.
*
@@ -32,42 +32,33 @@
#include <asm/segment.h>
#include <asm/processor-flags.h>

- .section ".x86_trampoline","a"
+ .text
.balign PAGE_SIZE
.code16

ENTRY(trampoline_data)
-r_base = .
cli # We should be safe anyway
wbinvd
+
+ .byte 0xea # ljmpw
+ .word 1f # Offset
+ .word real_mode_seg # Segment
+1:
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
mov %ax, %es
mov %ax, %ss

+ movl $0xA5A5A5A5, trampoline_status
+ # write marker for master knows we're running

- movl $0xA5A5A5A5, trampoline_status - r_base
- # write marker for master knows we're running
-
- # Setup stack
- movw $(trampoline_stack_end - r_base), %sp
+ # Setup stack
+ movw $trampoline_stack_end, %sp

call verify_cpu # Verify the cpu supports long mode
testl %eax, %eax # Check for return code
jnz no_longmode

- mov %cs, %ax
- movzx %ax, %esi # Find the 32bit trampoline location
- shll $4, %esi
-
- # Fixup the absolute vectors
- leal (startup_32 - r_base)(%esi), %eax
- movl %eax, startup_32_vector - r_base
- leal (startup_64 - r_base)(%esi), %eax
- movl %eax, startup_64_vector - r_base
- leal (tgdt - r_base)(%esi), %eax
- movl %eax, (tgdt + 2 - r_base)
-
/*
* GDT tables in non default location kernel can be beyond 16MB and
* lgdt will not be able to load the address as in real mode default
@@ -75,26 +66,34 @@ r_base = .
* to 32 bit.
*/

- lidtl tidt - r_base # load idt with 0, 0
- lgdtl tgdt - r_base # load gdt with whatever is appropriate
+ lidtl tidt # load idt with 0, 0
+ lgdtl tgdt # load gdt with whatever is appropriate

mov $X86_CR0_PE, %ax # protected mode (PE) bit
lmsw %ax # into protected mode

# flush prefetch and jump to startup_32
- ljmpl *(startup_32_vector - r_base)
+ ljmpl *(startup_32_vector)
+
+no_longmode:
+ hlt
+ jmp no_longmode
+#include "../kernel/verify_cpu.S"

.code32
.balign 4
-startup_32:
+ENTRY(startup_32)
movl $__KERNEL_DS, %eax # Initialize the %ds segment register
movl %eax, %ds

movl $X86_CR4_PAE, %eax
movl %eax, %cr4 # Enable PAE mode

+ movl pa_startup_64_smp, %esi
+ movl pa_startup_64_smp_high, %edi
+
# Setup trampoline 4 level pagetables
- leal (trampoline_level4_pgt - r_base)(%esi), %eax
+ leal pa_trampoline_level4_pgt, %eax
movl %eax, %cr3

movl $MSR_EFER, %ecx
@@ -113,22 +112,17 @@ startup_32:
* EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
* the new gdt/idt that has __KERNEL_CS with CS.L = 1.
*/
- ljmp *(startup_64_vector - r_base)(%esi)
+ ljmpl *(pa_startup_64_vector)

.code64
.balign 4
-startup_64:
+ENTRY(startup_64)
# Now jump into the kernel using virtual addresses
- movq $secondary_startup_64, %rax
+ movl %edi, %eax
+ shlq $32, %rax
+ addl %esi, %eax
jmp *%rax

- .code16
-no_longmode:
- hlt
- jmp no_longmode
-#include "verify_cpu.S"
-
- .balign 4
# Careful these need to be in the same 64K segment as the above;
tidt:
.word 0 # idt limit = 0
@@ -137,10 +131,11 @@ tidt:
# Duplicate the global descriptor table
# so the kernel can live anywhere
.balign 4
+ .globl tgdt
tgdt:
.short tgdt_end - tgdt # gdt limit
- .long tgdt - r_base
- .short 0
+ .long pa_tgdt
+ .short 0
.quad 0x00cf9b000000ffff # __KERNEL32_CS
.quad 0x00af9b000000ffff # __KERNEL_CS
.quad 0x00cf93000000ffff # __KERNEL_DS
@@ -148,14 +143,17 @@ tgdt_end:

.balign 4
startup_32_vector:
- .long startup_32 - r_base
+ .long pa_startup_32
.word __KERNEL32_CS, 0

.balign 4
+ .globl startup_64_vector
startup_64_vector:
- .long startup_64 - r_base
+ .long pa_startup_64
.word __KERNEL_CS, 0

+ .data
+
.balign 4
ENTRY(trampoline_status)
.long 0
@@ -163,9 +161,15 @@ ENTRY(trampoline_status)
trampoline_stack:
.org 0x1000
trampoline_stack_end:
-ENTRY(trampoline_level4_pgt)
- .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
- .fill 510,8,0
- .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE

-ENTRY(trampoline_end)
+ .globl level3_ident_pgt
+ .globl level3_kernel_pgt
+ENTRY(trampoline_level4_pgt)
+ level3_ident_pgt: .quad 0
+ .fill 510,8,0
+ level3_kernel_pgt: .quad 0
+
+ .globl startup_64_smp
+ .globl startup_64_smp_high
+startup_64_smp: .long 0
+startup_64_smp_high: .long 0

2012-05-08 22:18:40

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Move ACPI wakeup to unified realmode code

Commit-ID: c9b77ccb52a5c77233b0e557b7d4417b00ef4012
Gitweb: http://git.kernel.org/tip/c9b77ccb52a5c77233b0e557b7d4417b00ef4012
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:29 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:46:05 -0700

x86, realmode: Move ACPI wakeup to unified realmode code

Migrated ACPI wakeup code to the real-mode blob.
Code existing in .x86_trampoline can be completely
removed. Static descriptor table in wakeup_asm.S is
courtesy of H. Peter Anvin.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Cc: Rafael J. Wysocki <[email protected]>
Cc: Len Brown <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/include/asm/acpi.h | 2 -
arch/x86/include/asm/realmode.h | 4 +
arch/x86/include/asm/trampoline.h | 39 -----
arch/x86/kernel/Makefile | 1 -
arch/x86/kernel/acpi/Makefile | 9 +-
arch/x86/kernel/acpi/realmode/Makefile | 59 -------
arch/x86/kernel/acpi/realmode/wakeup.lds.S | 62 -------
arch/x86/kernel/acpi/sleep.c | 33 +----
arch/x86/kernel/acpi/sleep.h | 2 +-
arch/x86/kernel/acpi/wakeup_rm.S | 12 --
arch/x86/kernel/head32.c | 1 -
arch/x86/kernel/head64.c | 1 -
arch/x86/kernel/mpparse.c | 1 -
arch/x86/kernel/setup.c | 2 -
arch/x86/kernel/tboot.c | 5 +-
arch/x86/kernel/trampoline.c | 42 -----
arch/x86/kernel/trampoline_32.S | 83 ----------
arch/x86/kernel/trampoline_64.S | 171 --------------------
arch/x86/kernel/vmlinux.lds.S | 12 --
arch/x86/realmode/rm/Makefile | 4 +
arch/x86/realmode/rm/header.S | 5 +
arch/x86/realmode/rm/realmode.lds.S | 4 +
.../realmode => realmode/rm/wakeup}/.gitignore | 0
arch/x86/realmode/rm/wakeup/Makefile | 33 ++++
.../realmode => realmode/rm/wakeup}/bioscall.S | 0
.../acpi/realmode => realmode/rm/wakeup}/copy.S | 0
.../acpi/realmode => realmode/rm/wakeup}/regs.c | 0
.../realmode => realmode/rm/wakeup}/video-bios.c | 0
.../realmode => realmode/rm/wakeup}/video-mode.c | 0
.../realmode => realmode/rm/wakeup}/video-vesa.c | 0
.../realmode => realmode/rm/wakeup}/video-vga.c | 0
.../realmode => realmode/rm/wakeup}/wakemain.c | 3 +-
.../acpi/realmode => realmode/rm/wakeup}/wakeup.h | 9 +-
.../wakeup.S => realmode/rm/wakeup/wakeup_asm.S} | 69 +++++---
drivers/acpi/sleep.c | 8 +-
35 files changed, 111 insertions(+), 565 deletions(-)

diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index 610001d..724aa44 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -29,7 +29,6 @@
#include <asm/processor.h>
#include <asm/mmu.h>
#include <asm/mpspec.h>
-#include <asm/trampoline.h>

#define COMPILER_DEPENDENT_INT64 long long
#define COMPILER_DEPENDENT_UINT64 unsigned long long
@@ -118,7 +117,6 @@ static inline void acpi_disable_pci(void)
extern int acpi_suspend_lowlevel(void);

extern const unsigned char acpi_wakeup_code[];
-#define acpi_wakeup_address (__pa(TRAMPOLINE_SYM(acpi_wakeup_code)))

/* early initialization routine */
extern void acpi_reserve_wakeup_memory(void);
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index 9b4a5da..1bfc74d 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -24,6 +24,10 @@ struct real_mode_header {
u32 level3_ident_pgt;
u32 level3_kernel_pgt;
#endif
+#ifdef CONFIG_ACPI_SLEEP
+ u32 wakeup_start;
+ u32 wakeup_header;
+#endif
} __attribute__((__packed__));

extern struct real_mode_header real_mode_header;
diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h
deleted file mode 100644
index feca311..0000000
--- a/arch/x86/include/asm/trampoline.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _ASM_X86_TRAMPOLINE_H
-#define _ASM_X86_TRAMPOLINE_H
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-#include <asm/io.h>
-
-/*
- * Trampoline 80x86 program as an array. These are in the init rodata
- * segment, but that's okay, because we only care about the relative
- * addresses of the symbols.
- */
-extern const unsigned char x86_trampoline_start [];
-extern const unsigned char x86_trampoline_end [];
-extern unsigned char *x86_trampoline_base;
-
-extern unsigned long init_rsp;
-extern unsigned long initial_code;
-extern unsigned long initial_gs;
-
-extern void __init setup_trampolines(void);
-
-extern const unsigned char trampoline_data[];
-extern const unsigned char trampoline_status[];
-
-#define TRAMPOLINE_SYM(x) \
- ((void *)(x86_trampoline_base + \
- ((const unsigned char *)(x) - x86_trampoline_start)))
-
-/* Address of the SMP trampoline */
-static inline unsigned long trampoline_address(void)
-{
- return virt_to_phys(TRAMPOLINE_SYM(trampoline_data));
-}
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _ASM_X86_TRAMPOLINE_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index b71ef35..4a20f44 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -35,7 +35,6 @@ obj-y += tsc.o io_delay.o rtc.o
obj-y += pci-iommu_table.o
obj-y += resource.o

-obj-y += trampoline.o trampoline_$(BITS).o
obj-y += realmode.o
obj-y += process.o
obj-y += i387.o xsave.o
diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile
index 6f35260..163b225 100644
--- a/arch/x86/kernel/acpi/Makefile
+++ b/arch/x86/kernel/acpi/Makefile
@@ -1,14 +1,7 @@
-subdir- := realmode
-
obj-$(CONFIG_ACPI) += boot.o
-obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_rm.o wakeup_$(BITS).o
+obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o

ifneq ($(CONFIG_ACPI_PROCESSOR),)
obj-y += cstate.o
endif

-$(obj)/wakeup_rm.o: $(obj)/realmode/wakeup.bin
-
-$(obj)/realmode/wakeup.bin: FORCE
- $(Q)$(MAKE) $(build)=$(obj)/realmode
-
diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile
deleted file mode 100644
index 6a564ac..0000000
--- a/arch/x86/kernel/acpi/realmode/Makefile
+++ /dev/null
@@ -1,59 +0,0 @@
-#
-# arch/x86/kernel/acpi/realmode/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-
-always := wakeup.bin
-targets := wakeup.elf wakeup.lds
-
-wakeup-y += wakeup.o wakemain.o video-mode.o copy.o bioscall.o regs.o
-
-# The link order of the video-*.o modules can matter. In particular,
-# video-vga.o *must* be listed first, followed by video-vesa.o.
-# Hardware-specific drivers should follow in the order they should be
-# probed, and video-bios.o should typically be last.
-wakeup-y += video-vga.o
-wakeup-y += video-vesa.o
-wakeup-y += video-bios.o
-
-targets += $(wakeup-y)
-
-bootsrc := $(src)/../../../boot
-
-# ---------------------------------------------------------------------------
-
-# How to compile the 16-bit code. Note we always compile for -march=i386,
-# that way we can complain to the user if the CPU is insufficient.
-# Compile with _SETUP since this is similar to the boot-time setup code.
-KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \
- -I$(srctree)/$(bootsrc) \
- $(cflags-y) \
- -Wall -Wstrict-prototypes \
- -march=i386 -mregparm=3 \
- -include $(srctree)/$(bootsrc)/code16gcc.h \
- -fno-strict-aliasing -fomit-frame-pointer \
- $(call cc-option, -ffreestanding) \
- $(call cc-option, -fno-toplevel-reorder,\
- $(call cc-option, -fno-unit-at-a-time)) \
- $(call cc-option, -fno-stack-protector) \
- $(call cc-option, -mpreferred-stack-boundary=2)
-KBUILD_CFLAGS += $(call cc-option, -m32)
-KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
-GCOV_PROFILE := n
-
-WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
-
-LDFLAGS_wakeup.elf := -T
-
-CPPFLAGS_wakeup.lds += -P -C
-
-$(obj)/wakeup.elf: $(obj)/wakeup.lds $(WAKEUP_OBJS) FORCE
- $(call if_changed,ld)
-
-OBJCOPYFLAGS_wakeup.bin := -O binary
-
-$(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE
- $(call if_changed,objcopy)
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
deleted file mode 100644
index d4f8010..0000000
--- a/arch/x86/kernel/acpi/realmode/wakeup.lds.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * wakeup.ld
- *
- * Linker script for the real-mode wakeup code
- */
-#undef i386
-#include "wakeup.h"
-
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
-
-SECTIONS
-{
- . = 0;
- .jump : {
- *(.jump)
- } = 0x90909090
-
- . = WAKEUP_HEADER_OFFSET;
- .header : {
- *(.header)
- }
-
- . = ALIGN(16);
- .text : {
- *(.text*)
- } = 0x90909090
-
- . = ALIGN(16);
- .rodata : {
- *(.rodata*)
- }
-
- .videocards : {
- video_cards = .;
- *(.videocards)
- video_cards_end = .;
- }
-
- . = ALIGN(16);
- .data : {
- *(.data*)
- }
-
- . = ALIGN(16);
- .bss : {
- __bss_start = .;
- *(.bss)
- __bss_end = .;
- }
-
- .signature : {
- *(.signature)
- }
-
- _end = .;
-
- /DISCARD/ : {
- *(.note*)
- }
-}
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 146a49c..d941b62 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -14,8 +14,9 @@
#include <asm/desc.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
+#include <asm/realmode.h>

-#include "realmode/wakeup.h"
+#include "../../realmode/rm/wakeup/wakeup.h"
#include "sleep.h"

unsigned long acpi_realmode_flags;
@@ -36,13 +37,9 @@ asmlinkage void acpi_enter_s3(void)
*/
int acpi_suspend_lowlevel(void)
{
- struct wakeup_header *header;
- /* address in low memory of the wakeup routine. */
- char *acpi_realmode;
+ struct wakeup_header *header =
+ (struct wakeup_header *) __va(real_mode_header.wakeup_header);

- acpi_realmode = TRAMPOLINE_SYM(acpi_wakeup_code);
-
- header = (struct wakeup_header *)(acpi_realmode + WAKEUP_HEADER_OFFSET);
if (header->signature != WAKEUP_HEADER_SIGNATURE) {
printk(KERN_ERR "wakeup header does not match\n");
return -EINVAL;
@@ -50,27 +47,6 @@ int acpi_suspend_lowlevel(void)

header->video_mode = saved_video_mode;

- header->wakeup_jmp_seg = acpi_wakeup_address >> 4;
-
- /*
- * Set up the wakeup GDT. We set these up as Big Real Mode,
- * that is, with limits set to 4 GB. At least the Lenovo
- * Thinkpad X61 is known to need this for the video BIOS
- * initialization quirk to work; this is likely to also
- * be the case for other laptops or integrated video devices.
- */
-
- /* GDT[0]: GDT self-pointer */
- header->wakeup_gdt[0] =
- (u64)(sizeof(header->wakeup_gdt) - 1) +
- ((u64)__pa(&header->wakeup_gdt) << 16);
- /* GDT[1]: big real mode-like code segment */
- header->wakeup_gdt[1] =
- GDT_ENTRY(0x809b, acpi_wakeup_address, 0xfffff);
- /* GDT[2]: big real mode-like data segment */
- header->wakeup_gdt[2] =
- GDT_ENTRY(0x8093, acpi_wakeup_address, 0xfffff);
-
#ifndef CONFIG_64BIT
store_gdt((struct desc_ptr *)&header->pmode_gdt);

@@ -95,7 +71,6 @@ int acpi_suspend_lowlevel(void)
header->pmode_cr3 = (u32)__pa(&initial_page_table);
saved_magic = 0x12345678;
#else /* CONFIG_64BIT */
- header->trampoline_segment = trampoline_address() >> 4;
#ifdef CONFIG_SMP
stack_start = (unsigned long)temp_stack + sizeof(temp_stack);
early_gdt_descr.address =
diff --git a/arch/x86/kernel/acpi/sleep.h b/arch/x86/kernel/acpi/sleep.h
index d68677a..5653a57 100644
--- a/arch/x86/kernel/acpi/sleep.h
+++ b/arch/x86/kernel/acpi/sleep.h
@@ -2,8 +2,8 @@
* Variables and functions used by the code in sleep.c
*/

-#include <asm/trampoline.h>
#include <linux/linkage.h>
+#include <asm/realmode.h>

extern unsigned long saved_video_mode;
extern long saved_magic;
diff --git a/arch/x86/kernel/acpi/wakeup_rm.S b/arch/x86/kernel/acpi/wakeup_rm.S
deleted file mode 100644
index 63b8ab5..0000000
--- a/arch/x86/kernel/acpi/wakeup_rm.S
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Wrapper script for the realmode binary as a transport object
- * before copying to low memory.
- */
-#include <asm/page_types.h>
-
- .section ".x86_trampoline","a"
- .balign PAGE_SIZE
- .globl acpi_wakeup_code
-acpi_wakeup_code:
- .incbin "arch/x86/kernel/acpi/realmode/wakeup.bin"
- .size acpi_wakeup_code, .-acpi_wakeup_code
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index 51ff186..c18f59d 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -14,7 +14,6 @@
#include <asm/sections.h>
#include <asm/e820.h>
#include <asm/page.h>
-#include <asm/trampoline.h>
#include <asm/apic.h>
#include <asm/io_apic.h>
#include <asm/bios_ebda.h>
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 3a3b779..037df57 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -24,7 +24,6 @@
#include <asm/sections.h>
#include <asm/kdebug.h>
#include <asm/e820.h>
-#include <asm/trampoline.h>
#include <asm/bios_ebda.h>

static void __init zap_identity_mappings(void)
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index ca470e4..f44d311 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -27,7 +27,6 @@
#include <asm/proto.h>
#include <asm/bios_ebda.h>
#include <asm/e820.h>
-#include <asm/trampoline.h>
#include <asm/setup.h>
#include <asm/smp.h>

diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 56e4124..7a14fec 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -73,7 +73,6 @@

#include <asm/mtrr.h>
#include <asm/apic.h>
-#include <asm/trampoline.h>
#include <asm/realmode.h>
#include <asm/e820.h>
#include <asm/mpspec.h>
@@ -918,7 +917,6 @@ void __init setup_arch(char **cmdline_p)
printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n",
max_pfn_mapped<<PAGE_SHIFT);

- setup_trampolines();
setup_real_mode();

init_gbpages();
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index 6410744..c136e23 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -32,7 +32,7 @@
#include <linux/mm.h>
#include <linux/tboot.h>

-#include <asm/trampoline.h>
+#include <asm/realmode.h>
#include <asm/processor.h>
#include <asm/bootparam.h>
#include <asm/pgtable.h>
@@ -201,7 +201,8 @@ static int tboot_setup_sleep(void)
add_mac_region(e820.map[i].addr, e820.map[i].size);
}

- tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address;
+ tboot->acpi_sinfo.kernel_s3_resume_vector =
+ real_mode_header.wakeup_start;

return 0;
}
diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c
deleted file mode 100644
index a73b610..0000000
--- a/arch/x86/kernel/trampoline.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <linux/io.h>
-#include <linux/memblock.h>
-
-#include <asm/trampoline.h>
-#include <asm/cacheflush.h>
-#include <asm/pgtable.h>
-
-unsigned char *x86_trampoline_base;
-
-void __init setup_trampolines(void)
-{
- phys_addr_t mem;
- size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start);
-
- /* Has to be in very low memory so we can execute real-mode AP code. */
- mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
- if (!mem)
- panic("Cannot allocate trampoline\n");
-
- x86_trampoline_base = __va(mem);
- memblock_reserve(mem, size);
-
- printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
- x86_trampoline_base, (unsigned long long)mem, size);
-
- memcpy(x86_trampoline_base, x86_trampoline_start, size);
-}
-
-/*
- * setup_trampolines() gets called very early, to guarantee the
- * availability of low memory. This is before the proper kernel page
- * tables are set up, so we cannot set page permissions in that
- * function. Thus, we use an arch_initcall instead.
- */
-static int __init configure_trampolines(void)
-{
- size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start);
-
- set_memory_x((unsigned long)x86_trampoline_base, size >> PAGE_SHIFT);
- return 0;
-}
-arch_initcall(configure_trampolines);
diff --git a/arch/x86/kernel/trampoline_32.S b/arch/x86/kernel/trampoline_32.S
deleted file mode 100644
index 451c0a7..0000000
--- a/arch/x86/kernel/trampoline_32.S
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *
- * Trampoline.S Derived from Setup.S by Linus Torvalds
- *
- * 4 Jan 1997 Michael Chastain: changed to gnu as.
- *
- * This is only used for booting secondary CPUs in SMP machine
- *
- * Entry: CS:IP point to the start of our code, we are
- * in real mode with no stack, but the rest of the
- * trampoline page to make our stack and everything else
- * is a mystery.
- *
- * We jump into arch/x86/kernel/head_32.S.
- *
- * On entry to trampoline_data, the processor is in real mode
- * with 16-bit addressing and 16-bit data. CS has some value
- * and IP is zero. Thus, data addresses need to be absolute
- * (no relocation) and are taken with regard to r_base.
- *
- * If you work on this file, check the object module with
- * objdump --reloc to make sure there are no relocation
- * entries except for:
- *
- * TYPE VALUE
- * R_386_32 startup_32_smp
- * R_386_32 boot_gdt
- */
-
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/segment.h>
-#include <asm/page_types.h>
-
-#ifdef CONFIG_SMP
-
- .section ".x86_trampoline","a"
- .balign PAGE_SIZE
- .code16
-
-ENTRY(trampoline_data)
-r_base = .
- wbinvd # Needed for NUMA-Q should be harmless for others
- mov %cs, %ax # Code and data in the same place
- mov %ax, %ds
-
- cli # We should be safe anyway
-
- movl $0xA5A5A5A5, trampoline_status - r_base
- # write marker for master knows we're running
-
- /* GDT tables in non default location kernel can be beyond 16MB and
- * lgdt will not be able to load the address as in real mode default
- * operand size is 16bit. Use lgdtl instead to force operand size
- * to 32 bit.
- */
-
- lidtl boot_idt_descr - r_base # load idt with 0, 0
- lgdtl boot_gdt_descr - r_base # load gdt with whatever is appropriate
-
- xor %ax, %ax
- inc %ax # protected mode (PE) bit
- lmsw %ax # into protected mode
- # flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
- ljmpl $__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET)
-
- # These need to be in the same 64K segment as the above;
- # hence we don't use the boot_gdt_descr defined in head.S
-boot_gdt_descr:
- .word __BOOT_DS + 7 # gdt limit
- .long boot_gdt - __PAGE_OFFSET # gdt base
-
-boot_idt_descr:
- .word 0 # idt limit = 0
- .long 0 # idt base = 0L
-
-ENTRY(trampoline_status)
- .long 0
-
-.globl trampoline_end
-trampoline_end:
-
-#endif /* CONFIG_SMP */
diff --git a/arch/x86/kernel/trampoline_64.S b/arch/x86/kernel/trampoline_64.S
deleted file mode 100644
index 09ff517..0000000
--- a/arch/x86/kernel/trampoline_64.S
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- *
- * Trampoline.S Derived from Setup.S by Linus Torvalds
- *
- * 4 Jan 1997 Michael Chastain: changed to gnu as.
- * 15 Sept 2005 Eric Biederman: 64bit PIC support
- *
- * Entry: CS:IP point to the start of our code, we are
- * in real mode with no stack, but the rest of the
- * trampoline page to make our stack and everything else
- * is a mystery.
- *
- * On entry to trampoline_data, the processor is in real mode
- * with 16-bit addressing and 16-bit data. CS has some value
- * and IP is zero. Thus, data addresses need to be absolute
- * (no relocation) and are taken with regard to r_base.
- *
- * With the addition of trampoline_level4_pgt this code can
- * now enter a 64bit kernel that lives at arbitrary 64bit
- * physical addresses.
- *
- * If you work on this file, check the object module with objdump
- * --full-contents --reloc to make sure there are no relocation
- * entries.
- */
-
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/pgtable_types.h>
-#include <asm/page_types.h>
-#include <asm/msr.h>
-#include <asm/segment.h>
-#include <asm/processor-flags.h>
-
- .section ".x86_trampoline","a"
- .balign PAGE_SIZE
- .code16
-
-ENTRY(trampoline_data)
-r_base = .
- cli # We should be safe anyway
- wbinvd
- mov %cs, %ax # Code and data in the same place
- mov %ax, %ds
- mov %ax, %es
- mov %ax, %ss
-
-
- movl $0xA5A5A5A5, trampoline_status - r_base
- # write marker for master knows we're running
-
- # Setup stack
- movw $(trampoline_stack_end - r_base), %sp
-
- call verify_cpu # Verify the cpu supports long mode
- testl %eax, %eax # Check for return code
- jnz no_longmode
-
- mov %cs, %ax
- movzx %ax, %esi # Find the 32bit trampoline location
- shll $4, %esi
-
- # Fixup the absolute vectors
- leal (startup_32 - r_base)(%esi), %eax
- movl %eax, startup_32_vector - r_base
- leal (startup_64 - r_base)(%esi), %eax
- movl %eax, startup_64_vector - r_base
- leal (tgdt - r_base)(%esi), %eax
- movl %eax, (tgdt + 2 - r_base)
-
- /*
- * GDT tables in non default location kernel can be beyond 16MB and
- * lgdt will not be able to load the address as in real mode default
- * operand size is 16bit. Use lgdtl instead to force operand size
- * to 32 bit.
- */
-
- lidtl tidt - r_base # load idt with 0, 0
- lgdtl tgdt - r_base # load gdt with whatever is appropriate
-
- mov $X86_CR0_PE, %ax # protected mode (PE) bit
- lmsw %ax # into protected mode
-
- # flush prefetch and jump to startup_32
- ljmpl *(startup_32_vector - r_base)
-
- .code32
- .balign 4
-startup_32:
- movl $__KERNEL_DS, %eax # Initialize the %ds segment register
- movl %eax, %ds
-
- movl $X86_CR4_PAE, %eax
- movl %eax, %cr4 # Enable PAE mode
-
- # Setup trampoline 4 level pagetables
- leal (trampoline_level4_pgt - r_base)(%esi), %eax
- movl %eax, %cr3
-
- movl $MSR_EFER, %ecx
- movl $(1 << _EFER_LME), %eax # Enable Long Mode
- xorl %edx, %edx
- wrmsr
-
- # Enable paging and in turn activate Long Mode
- # Enable protected mode
- movl $(X86_CR0_PG | X86_CR0_PE), %eax
- movl %eax, %cr0
-
- /*
- * At this point we're in long mode but in 32bit compatibility mode
- * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
- * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
- * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
- */
- ljmp *(startup_64_vector - r_base)(%esi)
-
- .code64
- .balign 4
-startup_64:
- # Now jump into the kernel using virtual addresses
- movq $secondary_startup_64, %rax
- jmp *%rax
-
- .code16
-no_longmode:
- hlt
- jmp no_longmode
-#include "verify_cpu.S"
-
- .balign 4
- # Careful these need to be in the same 64K segment as the above;
-tidt:
- .word 0 # idt limit = 0
- .word 0, 0 # idt base = 0L
-
- # Duplicate the global descriptor table
- # so the kernel can live anywhere
- .balign 4
-tgdt:
- .short tgdt_end - tgdt # gdt limit
- .long tgdt - r_base
- .short 0
- .quad 0x00cf9b000000ffff # __KERNEL32_CS
- .quad 0x00af9b000000ffff # __KERNEL_CS
- .quad 0x00cf93000000ffff # __KERNEL_DS
-tgdt_end:
-
- .balign 4
-startup_32_vector:
- .long startup_32 - r_base
- .word __KERNEL32_CS, 0
-
- .balign 4
-startup_64_vector:
- .long startup_64 - r_base
- .word __KERNEL_CS, 0
-
- .balign 4
-ENTRY(trampoline_status)
- .long 0
-
-trampoline_stack:
- .org 0x1000
-trampoline_stack_end:
-ENTRY(trampoline_level4_pgt)
- .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
- .fill 510,8,0
- .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
-
-ENTRY(trampoline_end)
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 0f703f1..22a1530 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -197,18 +197,6 @@ SECTIONS

INIT_DATA_SECTION(16)

- /*
- * Code and data for a variety of lowlevel trampolines, to be
- * copied into base memory (< 1 MiB) during initialization.
- * Since it is copied early, the main copy can be discarded
- * afterwards.
- */
- .x86_trampoline : AT(ADDR(.x86_trampoline) - LOAD_OFFSET) {
- x86_trampoline_start = .;
- *(.x86_trampoline)
- x86_trampoline_end = .;
- }
-
.x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
__x86_cpu_dev_start = .;
*(.x86_cpu_dev.init)
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 56ec64f..2432acb 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -14,9 +14,13 @@ always := realmode.bin
realmode-y += header.o
realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-y += trampoline_$(BITS).o
+realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o

targets += $(realmode-y)

+$(obj)/wakeup/wakeup.o: FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/wakeup $@
+
REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y))

sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p'
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index a979004..730b131 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -27,4 +27,9 @@ ENTRY(real_mode_header)
.long pa_level3_ident_pgt
.long pa_level3_kernel_pgt
#endif
+ /* ACPI sleep */
+#ifdef CONFIG_ACPI_SLEEP
+ .long pa_wakeup_start
+ .long pa_wakeup_header
+#endif
END(real_mode_header)
diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S
index c5b8a4f..91b83ea 100644
--- a/arch/x86/realmode/rm/realmode.lds.S
+++ b/arch/x86/realmode/rm/realmode.lds.S
@@ -25,6 +25,10 @@ SECTIONS
.rodata : {
*(.rodata)
*(.rodata.*)
+ . = ALIGN(16);
+ video_cards = .;
+ *(.videocards)
+ video_cards_end = .;
}

. = ALIGN(PAGE_SIZE);
diff --git a/arch/x86/kernel/acpi/realmode/.gitignore b/arch/x86/realmode/rm/wakeup/.gitignore
similarity index 100%
rename from arch/x86/kernel/acpi/realmode/.gitignore
rename to arch/x86/realmode/rm/wakeup/.gitignore
diff --git a/arch/x86/realmode/rm/wakeup/Makefile b/arch/x86/realmode/rm/wakeup/Makefile
new file mode 100644
index 0000000..4c85332
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup/Makefile
@@ -0,0 +1,33 @@
+#
+# arch/x86/kernel/acpi/realmode/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+always := wakeup.o
+
+wakeup-y += wakeup_asm.o wakemain.o video-mode.o
+wakeup-y += copy.o bioscall.o regs.o
+
+# The link order of the video-*.o modules can matter. In particular,
+# video-vga.o *must* be listed first, followed by video-vesa.o.
+# Hardware-specific drivers should follow in the order they should be
+# probed, and video-bios.o should typically be last.
+wakeup-y += video-vga.o
+wakeup-y += video-vesa.o
+wakeup-y += video-bios.o
+
+targets += $(wakeup-y)
+
+WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
+
+LDFLAGS_wakeup.o := -m elf_i386 -r
+$(obj)/wakeup.o: $(WAKEUP_OBJS) FORCE
+ $(call if_changed,ld)
+
+bootsrc := $(src)/../../../boot
+
+ccflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc)
+asflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc)
diff --git a/arch/x86/kernel/acpi/realmode/bioscall.S b/arch/x86/realmode/rm/wakeup/bioscall.S
similarity index 100%
rename from arch/x86/kernel/acpi/realmode/bioscall.S
rename to arch/x86/realmode/rm/wakeup/bioscall.S
diff --git a/arch/x86/kernel/acpi/realmode/copy.S b/arch/x86/realmode/rm/wakeup/copy.S
similarity index 100%
rename from arch/x86/kernel/acpi/realmode/copy.S
rename to arch/x86/realmode/rm/wakeup/copy.S
diff --git a/arch/x86/kernel/acpi/realmode/regs.c b/arch/x86/realmode/rm/wakeup/regs.c
similarity index 100%
rename from arch/x86/kernel/acpi/realmode/regs.c
rename to arch/x86/realmode/rm/wakeup/regs.c
diff --git a/arch/x86/kernel/acpi/realmode/video-bios.c b/arch/x86/realmode/rm/wakeup/video-bios.c
similarity index 100%
rename from arch/x86/kernel/acpi/realmode/video-bios.c
rename to arch/x86/realmode/rm/wakeup/video-bios.c
diff --git a/arch/x86/kernel/acpi/realmode/video-mode.c b/arch/x86/realmode/rm/wakeup/video-mode.c
similarity index 100%
rename from arch/x86/kernel/acpi/realmode/video-mode.c
rename to arch/x86/realmode/rm/wakeup/video-mode.c
diff --git a/arch/x86/kernel/acpi/realmode/video-vesa.c b/arch/x86/realmode/rm/wakeup/video-vesa.c
similarity index 100%
rename from arch/x86/kernel/acpi/realmode/video-vesa.c
rename to arch/x86/realmode/rm/wakeup/video-vesa.c
diff --git a/arch/x86/kernel/acpi/realmode/video-vga.c b/arch/x86/realmode/rm/wakeup/video-vga.c
similarity index 100%
rename from arch/x86/kernel/acpi/realmode/video-vga.c
rename to arch/x86/realmode/rm/wakeup/video-vga.c
diff --git a/arch/x86/kernel/acpi/realmode/wakemain.c b/arch/x86/realmode/rm/wakeup/wakemain.c
similarity index 98%
rename from arch/x86/kernel/acpi/realmode/wakemain.c
rename to arch/x86/realmode/rm/wakeup/wakemain.c
index 883962d..91405d5 100644
--- a/arch/x86/kernel/acpi/realmode/wakemain.c
+++ b/arch/x86/realmode/rm/wakeup/wakemain.c
@@ -65,7 +65,8 @@ void main(void)
{
/* Kill machine if structures are wrong */
if (wakeup_header.real_magic != 0x12345678)
- while (1);
+ while (1)
+ ;

if (wakeup_header.realmode_flags & 4)
send_morse("...-");
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/realmode/rm/wakeup/wakeup.h
similarity index 82%
rename from arch/x86/kernel/acpi/realmode/wakeup.h
rename to arch/x86/realmode/rm/wakeup/wakeup.h
index 97a29e1..2dfaf06 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.h
+++ b/arch/x86/realmode/rm/wakeup/wakeup.h
@@ -12,9 +12,8 @@
/* This must match data at wakeup.S */
struct wakeup_header {
u16 video_mode; /* Video mode number */
- u16 _jmp1; /* ljmpl opcode, 32-bit only */
u32 pmode_entry; /* Protected mode resume point, 32-bit only */
- u16 _jmp2; /* CS value, 32-bit only */
+ u16 pmode_cs;
u32 pmode_cr0; /* Protected mode cr0 */
u32 pmode_cr3; /* Protected mode cr3 */
u32 pmode_cr4; /* Protected mode cr4 */
@@ -26,12 +25,6 @@ struct wakeup_header {
u32 pmode_behavior; /* Wakeup routine behavior flags */
u32 realmode_flags;
u32 real_magic;
- u16 trampoline_segment; /* segment with trampoline code, 64-bit only */
- u8 _pad1;
- u8 wakeup_jmp;
- u16 wakeup_jmp_off;
- u16 wakeup_jmp_seg;
- u64 wakeup_gdt[3];
u32 signature; /* To check we have correct structure */
} __attribute__((__packed__));

diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
similarity index 72%
rename from arch/x86/kernel/acpi/realmode/wakeup.S
rename to arch/x86/realmode/rm/wakeup/wakeup_asm.S
index b4fd836..b61126c 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.S
+++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
@@ -8,21 +8,15 @@
#include <asm/processor-flags.h>
#include "wakeup.h"

- .code16
- .section ".jump", "ax"
- .globl _start
-_start:
- cli
- jmp wakeup_code
+ .code16

/* This should match the structure in wakeup.h */
- .section ".header", "a"
+ .section ".data", "aw"
.globl wakeup_header
wakeup_header:
video_mode: .short 0 /* Video mode number */
-pmode_return: .byte 0x66, 0xea /* ljmpl */
- .long 0 /* offset goes here */
- .short __KERNEL_CS
+pmode_entry: .long 0
+pmode_cs: .short __KERNEL_CS
pmode_cr0: .long 0 /* Saved %cr0 */
pmode_cr3: .long 0 /* Saved %cr3 */
pmode_cr4: .long 0 /* Saved %cr4 */
@@ -32,19 +26,20 @@ pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
pmode_behavior: .long 0 /* Wakeup behavior flags */
realmode_flags: .long 0
real_magic: .long 0
-trampoline_segment: .word 0
-_pad1: .byte 0
-wakeup_jmp: .byte 0xea /* ljmpw */
-wakeup_jmp_off: .word 3f
-wakeup_jmp_seg: .word 0
-wakeup_gdt: .quad 0, 0, 0
signature: .long WAKEUP_HEADER_SIGNATURE
+ .size wakeup_header, .-wakeup_header

.text
.code16
-wakeup_code:
+ .globl wakeup_start
+wakeup_start:
+ cli
cld

+ .byte 0xea /* ljmpw */
+ .word 3f
+ .word real_mode_seg
+3:
/* Apparently some dimwit BIOS programmers don't know how to
program a PM to RM transition, and we might end up here with
junk in the data segment descriptor registers. The only way
@@ -54,8 +49,7 @@ wakeup_code:
movl %cr0, %eax
orb $X86_CR0_PE, %al
movl %eax, %cr0
- jmp 1f
-1: ljmpw $8, $2f
+ ljmpw $8, $2f
2:
movw %cx, %ds
movw %cx, %es
@@ -65,7 +59,9 @@ wakeup_code:

andb $~X86_CR0_PE, %al
movl %eax, %cr0
- jmp wakeup_jmp
+ .byte 0xea /* ljmpw */
+ .word 3f
+ .word real_mode_seg
3:
/* Set up segments */
movw %cs, %ax
@@ -130,12 +126,9 @@ wakeup_code:
/* This really couldn't... */
movl pmode_cr0, %eax
movl %eax, %cr0
- jmp pmode_return
+ ljmpl *pmode_entry
#else
- pushw $0
- pushw trampoline_segment
- pushw $0
- lret
+ jmp trampoline_data
#endif

bogus_real_magic:
@@ -143,6 +136,32 @@ bogus_real_magic:
hlt
jmp 1b

+ .section ".rodata","a"
+
+ /*
+ * Set up the wakeup GDT. We set these up as Big Real Mode,
+ * that is, with limits set to 4 GB. At least the Lenovo
+ * Thinkpad X61 is known to need this for the video BIOS
+ * initialization quirk to work; this is likely to also
+ * be the case for other laptops or integrated video devices.
+ */
+
+ .globl wakeup_gdt
+ .balign 16
+wakeup_gdt:
+ .word 3*8-1 /* Self-descriptor */
+ .long pa_wakeup_gdt
+ .word 0
+
+ .word 0xffff /* 16-bit code segment @ real_mode_base */
+ .long 0x9b000000 + pa_real_mode_base
+ .word 0x008f /* big real mode */
+
+ .word 0xffff /* 16-bit data segment @ real_mode_base */
+ .long 0x93000000 + pa_real_mode_base
+ .word 0x008f /* big real mode */
+ .size wakeup_gdt, .-wakeup_gdt
+
.data
.balign 8

diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index eb6fd23..e77aa4a 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -25,6 +25,8 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>

+#include <asm/realmode.h>
+
#include "internal.h"
#include "sleep.h"

@@ -91,13 +93,13 @@ static struct notifier_block tts_notifier = {
static int acpi_sleep_prepare(u32 acpi_state)
{
#ifdef CONFIG_ACPI_SLEEP
+ unsigned long wakeup_pa = real_mode_header.wakeup_start;
/* do we have a wakeup address for S2 and S3? */
if (acpi_state == ACPI_STATE_S3) {
- if (!acpi_wakeup_address) {
+ if (!wakeup_pa)
return -EFAULT;
- }
acpi_set_firmware_waking_vector(
- (acpi_physical_address)acpi_wakeup_address);
+ (acpi_physical_address)wakeup_pa);

}
ACPI_FLUSH_CPU_CACHE();

2012-05-08 22:19:23

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Set permission for real mode pages

Commit-ID: f156ffc439951b63cfa9f4d999a8d54267f13282
Gitweb: http://git.kernel.org/tip/f156ffc439951b63cfa9f4d999a8d54267f13282
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:30 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:47:08 -0700

x86, realmode: Set permission for real mode pages

Set proper permissions for rodata, text and data, removing the
realmode trampoline area as a remaining RWX memory mapping in the
kernel.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/kernel/realmode.c | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index a465775..d85ac20 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -86,7 +86,21 @@ static int __init set_real_mode_permissions(void)
PAGE_ALIGN(real_mode_header.end) -
__pa(real_mode_base);

- set_memory_x((unsigned long) real_mode_base, all_size >> PAGE_SHIFT);
+ size_t ro_size =
+ PAGE_ALIGN(real_mode_header.ro_end) -
+ __pa(real_mode_base);
+
+ size_t text_size =
+ PAGE_ALIGN(real_mode_header.ro_end) -
+ real_mode_header.text_start;
+
+ unsigned long text_start =
+ (unsigned long) __va(real_mode_header.text_start);
+
+ set_memory_nx((unsigned long) real_mode_base, all_size >> PAGE_SHIFT);
+ set_memory_ro((unsigned long) real_mode_base, ro_size >> PAGE_SHIFT);
+ set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT);
+
return 0;
}

2012-05-08 22:20:11

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Allow absolute pa_* symbols in the realmode code

Commit-ID: 2a6de3148cfd1a0240a85ea4a1cad34d250d882f
Gitweb: http://git.kernel.org/tip/2a6de3148cfd1a0240a85ea4a1cad34d250d882f
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:31 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:47:11 -0700

x86, realmode: Allow absolute pa_* symbols in the realmode code

Allow pa_* symbols to be absolute (outside any section) in the
realmode linker script. Some versions of GNU ld are known to be
unhappy about symbols defined in a section that is otherwise empty.

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
scripts/x86-relocs.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/scripts/x86-relocs.c b/scripts/x86-relocs.c
index 0291470..74e16bb 100644
--- a/scripts/x86-relocs.c
+++ b/scripts/x86-relocs.c
@@ -62,6 +62,13 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {

static const char * const sym_regex_realmode[S_NSYMTYPES] = {
/*
+ * These symbols are known to be relative, even if the linker marks them
+ * as absolute (typically defined outside any section in the linker script.)
+ */
+ [S_REL] =
+ "^pa_",
+
+/*
* These are 16-bit segment symbols when compiling 16-bit code.
*/
[S_SEG] =

2012-05-08 22:21:00

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Add .text64 section, make barrier symbols absolute

Commit-ID: 487f50ffeb142d8f86fff6e43a8852ce3d46c173
Gitweb: http://git.kernel.org/tip/487f50ffeb142d8f86fff6e43a8852ce3d46c173
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:32 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:47:18 -0700

x86, realmode: Add .text64 section, make barrier symbols absolute

Add a .text64 section. The purpose of this is to keep 16-, 32- and
64-bit code segregated into separate sections, mainly to keep
disassembly sane.

Move barrier symbols out of sections to avoid the "symbol in empty
section" problem in some versions of GNU ld.

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
arch/x86/realmode/rm/realmode.lds.S | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S
index 91b83ea..4d4afca 100644
--- a/arch/x86/realmode/rm/realmode.lds.S
+++ b/arch/x86/realmode/rm/realmode.lds.S
@@ -32,8 +32,8 @@ SECTIONS
}

. = ALIGN(PAGE_SIZE);
+ pa_text_start = .;
.text : {
- pa_text_start = .;
*(.text)
*(.text.*)
}
@@ -41,9 +41,14 @@ SECTIONS
.text32 : {
*(.text32)
*(.text32.*)
- pa_ro_end = .;
}

+ .text64 : {
+ *(.text64)
+ *(.text64.*)
+ }
+ pa_ro_end = .;
+
. = ALIGN(PAGE_SIZE);
.data : {
*(.data)
@@ -59,8 +64,8 @@ SECTIONS
. = ALIGN(4);
.signature : {
*(.signature)
- pa_end = .;
}
+ pa_end = .;

/DISCARD/ : {
*(.note*)

2012-05-08 22:21:49

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Move bits to the proper sections in trampoline_64.S

Commit-ID: 024742861124ef26dae4cfc620250f8f47ac934a
Gitweb: http://git.kernel.org/tip/024742861124ef26dae4cfc620250f8f47ac934a
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:33 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:03 -0700

x86, realmode: Move bits to the proper sections in trampoline_64.S

Move various bits to the sections they really belong in in
trampoline_64.S. Use GLOBAL() rather than ENTRY() for data objects:
ENTRY() should only be used with code and forces alignment to 16
bytes.

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
arch/x86/realmode/rm/trampoline_64.S | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 063da00..66c58cf 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -80,6 +80,7 @@ no_longmode:
jmp no_longmode
#include "../kernel/verify_cpu.S"

+ .section ".text32","ax"
.code32
.balign 4
ENTRY(startup_32)
@@ -114,6 +115,7 @@ ENTRY(startup_32)
*/
ljmpl *(pa_startup_64_vector)

+ .section ".text64","ax"
.code64
.balign 4
ENTRY(startup_64)
@@ -123,7 +125,8 @@ ENTRY(startup_64)
addl %esi, %eax
jmp *%rax

- # Careful these need to be in the same 64K segment as the above;
+ .section ".rodata","a"
+ .balign 16
tidt:
.word 0 # idt limit = 0
.word 0, 0 # idt base = 0L
@@ -153,9 +156,8 @@ startup_64_vector:
.word __KERNEL_CS, 0

.data
-
.balign 4
-ENTRY(trampoline_status)
+GLOBAL(trampoline_status)
.long 0

trampoline_stack:
@@ -164,7 +166,7 @@ trampoline_stack_end:

.globl level3_ident_pgt
.globl level3_kernel_pgt
-ENTRY(trampoline_level4_pgt)
+GLOBAL(trampoline_level4_pgt)
level3_ident_pgt: .quad 0
.fill 510,8,0
level3_kernel_pgt: .quad 0

2012-05-08 22:22:39

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Align . data section in trampoline_32.S

Commit-ID: f7436a9da902922a48cccc208099763b87d6171f
Gitweb: http://git.kernel.org/tip/f7436a9da902922a48cccc208099763b87d6171f
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:34 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:03 -0700

x86, realmode: Align .data section in trampoline_32.S

Specify the alignment of the .data section in trampoline_32.S.

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
arch/x86/realmode/rm/trampoline_32.S | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 18cb7fc..1f9e331 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -68,7 +68,7 @@ trampoline_data:

.data
.globl startup_32_smp, boot_gdt, trampoline_status
-
+ .balign 4
boot_gdt_descr:
.word __BOOT_DS + 7 # gdt limit
boot_gdt:

2012-05-08 22:23:28

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Remove indirect jumps in trampoline_64.S

Commit-ID: 056a43a6d3ab903a798d8ee4435ad67d6fccc3e6
Gitweb: http://git.kernel.org/tip/056a43a6d3ab903a798d8ee4435ad67d6fccc3e6
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:35 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:03 -0700

x86, realmode: Remove indirect jumps in trampoline_64.S

Remove indirect jumps in trampoline_64.S which are no longer
necessary: the realmode code can relocate the absolute jumps
correctly from the start.

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
arch/x86/realmode/rm/trampoline_64.S | 15 ++-------------
1 files changed, 2 insertions(+), 13 deletions(-)

diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 66c58cf..77b72b4 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -73,7 +73,7 @@ ENTRY(trampoline_data)
lmsw %ax # into protected mode

# flush prefetch and jump to startup_32
- ljmpl *(startup_32_vector)
+ ljmpl $__KERNEL32_CS, $pa_startup_32

no_longmode:
hlt
@@ -113,7 +113,7 @@ ENTRY(startup_32)
* EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
* the new gdt/idt that has __KERNEL_CS with CS.L = 1.
*/
- ljmpl *(pa_startup_64_vector)
+ ljmpl $__KERNEL_CS, $pa_startup_64

.section ".text64","ax"
.code64
@@ -144,17 +144,6 @@ tgdt:
.quad 0x00cf93000000ffff # __KERNEL_DS
tgdt_end:

- .balign 4
-startup_32_vector:
- .long pa_startup_32
- .word __KERNEL32_CS, 0
-
- .balign 4
- .globl startup_64_vector
-startup_64_vector:
- .long pa_startup_64
- .word __KERNEL_CS, 0
-
.data
.balign 4
GLOBAL(trampoline_status)

2012-05-08 22:24:19

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Remove indirect jumps in trampoline_32 and wakeup_asm

Commit-ID: 968ff9ee56f1e3ed4ff4a6d10185865dc77d8f7e
Gitweb: http://git.kernel.org/tip/968ff9ee56f1e3ed4ff4a6d10185865dc77d8f7e
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:36 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:03 -0700

x86, realmode: Remove indirect jumps in trampoline_32 and wakeup_asm

Remove indirect jumps in trampoline_32.S and the 32-bit part of
wakeup_asm.S. There exist systems which are known to do weird
things if an SMI comes in right after a mode switch, and the
safest way to deal with it is to always follow with a simple
absolute far jump. In the 64-bit code we then to a register
indirect near jump; follow that pattern for the 32-bit code.

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
arch/x86/realmode/rm/trampoline_32.S | 22 +++++++++++++---------
arch/x86/realmode/rm/wakeup/wakeup_asm.S | 8 +++++---
2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 1f9e331..1315ef4 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -47,24 +47,29 @@ trampoline_data:

cli # We should be safe anyway

+ movl startup_32_smp, %eax # where we need to go
+
movl $0xA5A5A5A5, trampoline_status
# write marker for master knows we're running

- /* GDT tables in non default location kernel can be beyond 16MB and
+ /*
+ * GDT tables in non default location kernel can be beyond 16MB and
* lgdt will not be able to load the address as in real mode default
* operand size is 16bit. Use lgdtl instead to force operand size
* to 32 bit.
*/
-
lidtl boot_idt_descr # load idt with 0, 0
lgdtl boot_gdt_descr # load gdt with whatever is appropriate

- xor %ax, %ax
- inc %ax # protected mode (PE) bit
- lmsw %ax # into protected mode
+ movw $1, %dx # protected mode (PE) bit
+ lmsw %dx # into protected mode

- # flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
- ljmpl *(startup_32_smp)
+ ljmpl $__BOOT_CS, $pa_startup_32
+
+ .section ".text32","ax"
+ .code32
+ENTRY(startup_32) # note: also used from wakeup_asm.S
+ jmp *%eax

.data
.globl startup_32_smp, boot_gdt, trampoline_status
@@ -82,5 +87,4 @@ trampoline_status:
.long 0

startup_32_smp:
- .long 0x00000000
- .word __BOOT_CS, 0
+ .long 0
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
index b61126c..4c5c5f2 100644
--- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
@@ -124,9 +124,11 @@ wakeup_start:
lgdtl pmode_gdt

/* This really couldn't... */
- movl pmode_cr0, %eax
- movl %eax, %cr0
- ljmpl *pmode_entry
+ movl pmode_entry, %eax
+ movl pmode_cr0, %ecx
+ movl %ecx, %cr0
+ ljmpl $__KERNEL_CS, $pa_startup_32
+ /* -> jmp *%eax in trampoline_32.S */
#else
jmp trampoline_data
#endif

2012-05-08 22:25:10

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Replace open-coded ljmpw with a macro

Commit-ID: e5684ec438a094bec0f7d5c52652c0901b48b613
Gitweb: http://git.kernel.org/tip/e5684ec438a094bec0f7d5c52652c0901b48b613
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:37 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:03 -0700

x86, realmode: Replace open-coded ljmpw with a macro

We cannot code an ljmpw to the real-mode segment directly, because gas
refuses to assemble an ljmp with a symbolic segment. Instead of
open-coding it everywhere, define a macro and use it for this case.

This is specifically an ljmpw from a 16-bit segment. This is okay, as
one should never enter real mode from a 32-bit segment: if one do, the
CPU ends up in a bizarre (and useless) mode sometimes called "unreal
mode" where segments behave like real mode but the default address and
operand sizes is 32 bits.

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
arch/x86/realmode/rm/realmode.h | 16 ++++++++++++++++
arch/x86/realmode/rm/reboot_32.S | 6 ++----
arch/x86/realmode/rm/trampoline_32.S | 5 ++---
arch/x86/realmode/rm/trampoline_64.S | 5 ++---
arch/x86/realmode/rm/wakeup/wakeup_asm.S | 9 +++------
5 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/arch/x86/realmode/rm/realmode.h b/arch/x86/realmode/rm/realmode.h
new file mode 100644
index 0000000..15ab633
--- /dev/null
+++ b/arch/x86/realmode/rm/realmode.h
@@ -0,0 +1,16 @@
+#ifndef ARCH_X86_REALMODE_RM_REALMODE_H
+#define ARCH_X86_REALMODE_RM_REALMODE_H
+
+#ifdef __ASSEMBLY__
+
+/*
+ * 16-bit ljmpw to the real_mode_seg
+ *
+ * This must be open-coded since gas will choke on using a
+ * relocatable symbol for the segment portion.
+ */
+#define LJMPW_RM(to) .byte 0xea ; .word (to), real_mode_seg
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* ARCH_X86_REALMODE_RM_REALMODE_H */
diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
index 83803c2..e90f8c4 100644
--- a/arch/x86/realmode/rm/reboot_32.S
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -2,6 +2,7 @@
#include <linux/init.h>
#include <asm/segment.h>
#include <asm/page_types.h>
+#include "realmode.h"

/*
* The following code and data reboots the machine by switching to real
@@ -82,10 +83,7 @@ machine_real_restart_asm16:
2:
andb $0x10, %dl
movl %edx, %cr0
- .byte 0xea /* ljmpw */
- .word 3f /* Offset */
- .word real_mode_seg /* Segment */
-
+ LJMPW_RM(3f)
3:
testb $0, %al
jz bios
diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 1315ef4..279f82e 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -29,6 +29,7 @@
#include <linux/init.h>
#include <asm/segment.h>
#include <asm/page_types.h>
+#include "realmode.h"

.text
.code16
@@ -38,9 +39,7 @@
trampoline_data:
wbinvd # Needed for NUMA-Q should be harmless for others

- .byte 0xea # ljmpw
- .word 1f # Offset
- .word real_mode_seg # Segment
+ LJMPW_RM(1f)
1:
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 77b72b4..7459c52 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -31,6 +31,7 @@
#include <asm/msr.h>
#include <asm/segment.h>
#include <asm/processor-flags.h>
+#include "realmode.h"

.text
.balign PAGE_SIZE
@@ -40,9 +41,7 @@ ENTRY(trampoline_data)
cli # We should be safe anyway
wbinvd

- .byte 0xea # ljmpw
- .word 1f # Offset
- .word real_mode_seg # Segment
+ LJMPW_RM(1f)
1:
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
index 4c5c5f2..8064e1c 100644
--- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
@@ -6,6 +6,7 @@
#include <asm/page_types.h>
#include <asm/pgtable_types.h>
#include <asm/processor-flags.h>
+#include "../realmode.h"
#include "wakeup.h"

.code16
@@ -36,9 +37,7 @@ wakeup_start:
cli
cld

- .byte 0xea /* ljmpw */
- .word 3f
- .word real_mode_seg
+ LJMPW_RM(3f)
3:
/* Apparently some dimwit BIOS programmers don't know how to
program a PM to RM transition, and we might end up here with
@@ -59,9 +58,7 @@ wakeup_start:

andb $~X86_CR0_PE, %al
movl %eax, %cr0
- .byte 0xea /* ljmpw */
- .word 3f
- .word real_mode_seg
+ LJMPW_RM(3f)
3:
/* Set up segments */
movw %cs, %ax

2012-05-08 22:26:03

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Move trampoline_*. S early in the link order

Commit-ID: be60828920d23758da8124bed771404a0438f369
Gitweb: http://git.kernel.org/tip/be60828920d23758da8124bed771404a0438f369
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:38 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:03 -0700

x86, realmode: Move trampoline_*.S early in the link order

Move trampoline_*.S earlier in the link order so it ends up being
first in the text segment; since the SIPI vector requires 4K alignment
it otherwise ends up padding the .text segment with that much
completely unnecessarily.

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
arch/x86/realmode/rm/Makefile | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 2432acb..2423142 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -12,8 +12,8 @@ subdir- := wakeup
always := realmode.bin

realmode-y += header.o
-realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-y += trampoline_$(BITS).o
+realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o

targets += $(realmode-y)

2012-05-08 22:26:49

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Fix always-zero test in reboot_32.S

Commit-ID: 6feb592dceaed1a6cf26c9747b1180958d5156cd
Gitweb: http://git.kernel.org/tip/6feb592dceaed1a6cf26c9747b1180958d5156cd
Author: H. Peter Anvin <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:39 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:04 -0700

x86, realmode: Fix always-zero test in reboot_32.S

A test instruction is an "and", and an and with zero is always zero.
This would cause us to always take the BIOS path, not the APM path, in
case anyone actually cares...

Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
arch/x86/realmode/rm/reboot_32.S | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
index e90f8c4..50ba994 100644
--- a/arch/x86/realmode/rm/reboot_32.S
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -85,7 +85,7 @@ machine_real_restart_asm16:
movl %edx, %cr0
LJMPW_RM(3f)
3:
- testb $0, %al
+ andw %ax, %ax
jz bios

apm:

2012-05-08 22:27:45

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: fix 64-bit wakeup sequence

Commit-ID: 8e029fcdd8702719c9179317cae9ef84ebe7027e
Gitweb: http://git.kernel.org/tip/8e029fcdd8702719c9179317cae9ef84ebe7027e
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:40 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:11 -0700

x86, realmode: fix 64-bit wakeup sequence

There were number of issues in wakeup sequence:

- Wakeup stack was placed in hardcoded address.
- NX bit in EFER was not enabled.
- Initialization incorrectly set physical address
of secondary_startup_64.
- Some alignment issues.

This patch fixes these issues and in addition:

- Unifies coding conventions in .S files.
- Sets alignments of code and data right.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Originally-by: H. Peter Anvin <[email protected]>
Cc: Rafael J. Wysocki <[email protected]>
Cc: Len Brown <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/kernel/realmode.c | 2 +-
arch/x86/realmode/rm/Makefile | 1 +
arch/x86/realmode/rm/header.S | 2 +-
arch/x86/realmode/rm/reboot_32.S | 18 ++++----
arch/x86/realmode/rm/stack.S | 19 ++++++++
arch/x86/realmode/rm/trampoline_32.S | 29 ++++++------
arch/x86/realmode/rm/trampoline_64.S | 67 +++++++++++---------------
arch/x86/realmode/rm/wakeup/wakeup_asm.S | 75 +++++++++++++----------------
arch/x86/realmode/rmpiggy.S | 4 +-
9 files changed, 110 insertions(+), 107 deletions(-)

diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index d85ac20..e7bf82a 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -64,7 +64,7 @@ void __init setup_real_mode(void)
*((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt);
#else
*((u64 *) __va(real_mode_header.startup_64_smp)) =
- (u64) __pa(secondary_startup_64);
+ (u64)secondary_startup_64;

*((u64 *) __va(real_mode_header.level3_ident_pgt)) =
__pa(level3_ident_pgt) + _KERNPG_TABLE;
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 2423142..c2c27a4 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -13,6 +13,7 @@ always := realmode.bin

realmode-y += header.o
realmode-y += trampoline_$(BITS).o
+realmode-y += stack.o
realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o

diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index 730b131..a91ec8f 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -9,7 +9,7 @@

.section ".header", "a"

-ENTRY(real_mode_header)
+GLOBAL(real_mode_header)
.long pa_text_start
.long pa_ro_end
.long pa_end
diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
index 50ba994..8d9bfd1 100644
--- a/arch/x86/realmode/rm/reboot_32.S
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -16,10 +16,9 @@
*/
.section ".text32", "ax"
.code32
- .globl machine_real_restart_asm

- .balign 16
-machine_real_restart_asm:
+ .balign 16
+ENTRY(machine_real_restart_asm)
/* Set up the IDT for real mode. */
lidtl pa_machine_real_restart_idt

@@ -67,7 +66,7 @@ machine_real_restart_asm:
.text
.code16

- .balign 16
+ .balign 16
machine_real_restart_asm16:
1:
xorl %ecx, %ecx
@@ -102,15 +101,15 @@ bios:
ljmpw $0xf000, $0xfff0

.section ".rodata", "a"
- .globl machine_real_restart_idt, machine_real_restart_gdt

- .balign 16
-machine_real_restart_idt:
+ .balign 16
+GLOBAL(machine_real_restart_idt)
.word 0xffff /* Length - real mode default value */
.long 0 /* Base - real mode default value */
+END(machine_real_restart_idt)

- .balign 16
-machine_real_restart_gdt:
+ .balign 16
+GLOBAL(machine_real_restart_gdt)
/* Self-pointer */
.word 0xffff /* Length - real mode default value */
.long pa_machine_real_restart_gdt
@@ -130,3 +129,4 @@ machine_real_restart_gdt:
* semantics we don't have to reload the segments once CR0.PE = 0.
*/
.quad GDT_ENTRY(0x0093, 0x100, 0xffff)
+END(machine_real_restart_gdt)
diff --git a/arch/x86/realmode/rm/stack.S b/arch/x86/realmode/rm/stack.S
new file mode 100644
index 0000000..867ae87
--- /dev/null
+++ b/arch/x86/realmode/rm/stack.S
@@ -0,0 +1,19 @@
+/*
+ * Common heap and stack allocations
+ */
+
+#include <linux/linkage.h>
+
+ .data
+GLOBAL(HEAP)
+ .long rm_heap
+GLOBAL(heap_end)
+ .long rm_stack
+
+ .bss
+ .balign 16
+GLOBAL(rm_heap)
+ .space 2048
+GLOBAL(rm_stack)
+ .space 2048
+GLOBAL(rm_stack_end)
diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 279f82e..1ecdbb5 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -33,10 +33,9 @@

.text
.code16
- .globl trampoline_data

- .balign PAGE_SIZE
-trampoline_data:
+ .balign PAGE_SIZE
+ENTRY(trampoline_data)
wbinvd # Needed for NUMA-Q should be harmless for others

LJMPW_RM(1f)
@@ -70,20 +69,22 @@ trampoline_data:
ENTRY(startup_32) # note: also used from wakeup_asm.S
jmp *%eax

- .data
- .globl startup_32_smp, boot_gdt, trampoline_status
- .balign 4
-boot_gdt_descr:
- .word __BOOT_DS + 7 # gdt limit
-boot_gdt:
- .long 0 # gdt base
+ .section ".rodata","a"

+ .balign 4
boot_idt_descr:
.word 0 # idt limit = 0
.long 0 # idt base = 0L

-trampoline_status:
- .long 0
+ .data

-startup_32_smp:
- .long 0
+boot_gdt_descr:
+ .word __BOOT_DS + 7 # gdt limit
+GLOBAL(boot_gdt)
+ .long 0 # gdt base
+
+ .bss
+
+ .balign 4
+GLOBAL(trampoline_status) .space 4
+GLOBAL(startup_32_smp) .space 4
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 7459c52..f71ea08 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -52,7 +52,7 @@ ENTRY(trampoline_data)
# write marker for master knows we're running

# Setup stack
- movw $trampoline_stack_end, %sp
+ movl $rm_stack_end, %esp

call verify_cpu # Verify the cpu supports long mode
testl %eax, %eax # Check for return code
@@ -68,8 +68,11 @@ ENTRY(trampoline_data)
lidtl tidt # load idt with 0, 0
lgdtl tgdt # load gdt with whatever is appropriate

- mov $X86_CR0_PE, %ax # protected mode (PE) bit
- lmsw %ax # into protected mode
+ movw $__KERNEL_DS, %dx # Data segment descriptor
+
+ # Enable protected mode
+ movl $X86_CR0_PE, %eax # protected mode (PE) bit
+ movl %eax, %cr0 # into protected mode

# flush prefetch and jump to startup_32
ljmpl $__KERNEL32_CS, $pa_startup_32
@@ -83,27 +86,27 @@ no_longmode:
.code32
.balign 4
ENTRY(startup_32)
- movl $__KERNEL_DS, %eax # Initialize the %ds segment register
- movl %eax, %ds
+ movl %edx, %ss
+ addl $pa_real_mode_base, %esp
+ movl %edx, %ds
+ movl %edx, %es
+ movl %edx, %fs
+ movl %edx, %gs

movl $X86_CR4_PAE, %eax
movl %eax, %cr4 # Enable PAE mode

- movl pa_startup_64_smp, %esi
- movl pa_startup_64_smp_high, %edi
-
- # Setup trampoline 4 level pagetables
- leal pa_trampoline_level4_pgt, %eax
+ # Setup trampoline 4 level pagetables
+ movl $pa_level3_ident_pgt, %eax
movl %eax, %cr3

movl $MSR_EFER, %ecx
- movl $(1 << _EFER_LME), %eax # Enable Long Mode
+ movl $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax # Enable Long Mode
xorl %edx, %edx
wrmsr

# Enable paging and in turn activate Long Mode
- # Enable protected mode
- movl $(X86_CR0_PG | X86_CR0_PE), %eax
+ movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax
movl %eax, %cr0

/*
@@ -119,10 +122,7 @@ ENTRY(startup_32)
.balign 4
ENTRY(startup_64)
# Now jump into the kernel using virtual addresses
- movl %edi, %eax
- shlq $32, %rax
- addl %esi, %eax
- jmp *%rax
+ jmpq *startup_64_smp(%rip)

.section ".rodata","a"
.balign 16
@@ -132,10 +132,10 @@ tidt:

# Duplicate the global descriptor table
# so the kernel can live anywhere
- .balign 4
+ .balign 16
.globl tgdt
tgdt:
- .short tgdt_end - tgdt # gdt limit
+ .short tgdt_end - tgdt - 1 # gdt limit
.long pa_tgdt
.short 0
.quad 0x00cf9b000000ffff # __KERNEL32_CS
@@ -143,23 +143,12 @@ tgdt:
.quad 0x00cf93000000ffff # __KERNEL_DS
tgdt_end:

- .data
- .balign 4
-GLOBAL(trampoline_status)
- .long 0
-
-trampoline_stack:
- .org 0x1000
-trampoline_stack_end:
-
- .globl level3_ident_pgt
- .globl level3_kernel_pgt
-GLOBAL(trampoline_level4_pgt)
- level3_ident_pgt: .quad 0
- .fill 510,8,0
- level3_kernel_pgt: .quad 0
-
- .globl startup_64_smp
- .globl startup_64_smp_high
-startup_64_smp: .long 0
-startup_64_smp_high: .long 0
+ .bss
+
+ .balign PAGE_SIZE
+GLOBAL(level3_ident_pgt) .space 511*8
+GLOBAL(level3_kernel_pgt) .space 8
+
+ .balign 8
+GLOBAL(startup_64_smp) .space 8
+GLOBAL(trampoline_status) .space 4
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
index 8064e1c..f81c1cd 100644
--- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
@@ -1,6 +1,7 @@
/*
* ACPI wakeup real mode startup stub
*/
+#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/msr-index.h>
#include <asm/page_types.h>
@@ -9,31 +10,33 @@
#include "../realmode.h"
#include "wakeup.h"

- .code16
+ .code16

/* This should match the structure in wakeup.h */
- .section ".data", "aw"
- .globl wakeup_header
-wakeup_header:
-video_mode: .short 0 /* Video mode number */
-pmode_entry: .long 0
-pmode_cs: .short __KERNEL_CS
-pmode_cr0: .long 0 /* Saved %cr0 */
-pmode_cr3: .long 0 /* Saved %cr3 */
-pmode_cr4: .long 0 /* Saved %cr4 */
-pmode_efer: .quad 0 /* Saved EFER */
-pmode_gdt: .quad 0
-pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
-pmode_behavior: .long 0 /* Wakeup behavior flags */
-realmode_flags: .long 0
-real_magic: .long 0
-signature: .long WAKEUP_HEADER_SIGNATURE
- .size wakeup_header, .-wakeup_header
+ .section ".data", "aw"
+
+ .balign 16
+GLOBAL(wakeup_header)
+ video_mode: .short 0 /* Video mode number */
+ pmode_entry: .long 0
+ pmode_cs: .short __KERNEL_CS
+ pmode_cr0: .long 0 /* Saved %cr0 */
+ pmode_cr3: .long 0 /* Saved %cr3 */
+ pmode_cr4: .long 0 /* Saved %cr4 */
+ pmode_efer: .quad 0 /* Saved EFER */
+ pmode_gdt: .quad 0
+ pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
+ pmode_behavior: .long 0 /* Wakeup behavior flags */
+ realmode_flags: .long 0
+ real_magic: .long 0
+ signature: .long WAKEUP_HEADER_SIGNATURE
+END(wakeup_header)

.text
.code16
- .globl wakeup_start
-wakeup_start:
+
+ .balign 16
+ENTRY(wakeup_start)
cli
cld

@@ -62,12 +65,14 @@ wakeup_start:
3:
/* Set up segments */
movw %cs, %ax
+ movw %ax, %ss
+ movl $rm_stack_end, %esp
movw %ax, %ds
movw %ax, %es
- movw %ax, %ss
- lidtl wakeup_idt
+ movw %ax, %fs
+ movw %ax, %gs

- movl $wakeup_stack_end, %esp
+ lidtl wakeup_idt

/* Clear the EFLAGS */
pushl $0
@@ -145,9 +150,8 @@ bogus_real_magic:
* be the case for other laptops or integrated video devices.
*/

- .globl wakeup_gdt
.balign 16
-wakeup_gdt:
+GLOBAL(wakeup_gdt)
.word 3*8-1 /* Self-descriptor */
.long pa_wakeup_gdt
.word 0
@@ -159,29 +163,18 @@ wakeup_gdt:
.word 0xffff /* 16-bit data segment @ real_mode_base */
.long 0x93000000 + pa_real_mode_base
.word 0x008f /* big real mode */
- .size wakeup_gdt, .-wakeup_gdt
+END(wakeup_gdt)

- .data
+ .section ".rodata","a"
.balign 8

/* This is the standard real-mode IDT */
-wakeup_idt:
+ .balign 16
+GLOBAL(wakeup_idt)
.word 0xffff /* limit */
.long 0 /* address */
.word 0
-
- .globl HEAP, heap_end
-HEAP:
- .long wakeup_heap
-heap_end:
- .long wakeup_stack
-
- .bss
-wakeup_heap:
- .space 2048
-wakeup_stack:
- .space 2048
-wakeup_stack_end:
+END(wakeup_idt)

.section ".signature","a"
end_signature:
diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S
index 6047d7f..fd72a99 100644
--- a/arch/x86/realmode/rmpiggy.S
+++ b/arch/x86/realmode/rmpiggy.S
@@ -9,10 +9,10 @@

.balign PAGE_SIZE

-ENTRY(real_mode_blob)
+GLOBAL(real_mode_blob)
.incbin "arch/x86/realmode/rm/realmode.bin"
END(real_mode_blob)

-ENTRY(real_mode_relocs)
+GLOBAL(real_mode_relocs)
.incbin "arch/x86/realmode/rm/realmode.relocs"
END(real_mode_relocs)

2012-05-08 22:28:30

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: don't copy real_mode_header

Commit-ID: b429dbf6e866bd6dadb56fae66f61f611cde57ff
Gitweb: http://git.kernel.org/tip/b429dbf6e866bd6dadb56fae66f61f611cde57ff
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:41 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:45 -0700

x86, realmode: don't copy real_mode_header

Replaced copying of real_mode_header with a pointer
to beginning of RM memory.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/include/asm/realmode.h | 5 +--
arch/x86/kernel/acpi/sleep.c | 2 +-
arch/x86/kernel/realmode.c | 57 +++++++++++++++-------------------
arch/x86/kernel/reboot.c | 2 +-
arch/x86/kernel/smpboot.c | 4 +-
arch/x86/kernel/tboot.c | 2 +-
arch/x86/realmode/rm/header.S | 1 -
arch/x86/realmode/rm/realmode.lds.S | 1 -
arch/x86/realmode/rmpiggy.S | 2 +
drivers/acpi/sleep.c | 2 +-
10 files changed, 35 insertions(+), 43 deletions(-)

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index 1bfc74d..d3ae49f 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -8,7 +8,6 @@
struct real_mode_header {
u32 text_start;
u32 ro_end;
- u32 end;
/* reboot */
#ifdef CONFIG_X86_32
u32 machine_real_restart_asm;
@@ -30,8 +29,8 @@ struct real_mode_header {
#endif
} __attribute__((__packed__));

-extern struct real_mode_header real_mode_header;
-extern unsigned char *real_mode_base;
+extern struct real_mode_header *real_mode_header;
+extern unsigned char real_mode_blob_end[];

extern unsigned long init_rsp;
extern unsigned long initial_code;
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index d941b62..6ca3f54 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -38,7 +38,7 @@ asmlinkage void acpi_enter_s3(void)
int acpi_suspend_lowlevel(void)
{
struct wakeup_header *header =
- (struct wakeup_header *) __va(real_mode_header.wakeup_header);
+ (struct wakeup_header *) __va(real_mode_header->wakeup_header);

if (header->signature != WAKEUP_HEADER_SIGNATURE) {
printk(KERN_ERR "wakeup header does not match\n");
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index e7bf82a..632c810 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -5,8 +5,7 @@
#include <asm/pgtable.h>
#include <asm/realmode.h>

-unsigned char *real_mode_base;
-struct real_mode_header real_mode_header;
+struct real_mode_header *real_mode_header;

void __init setup_real_mode(void)
{
@@ -17,33 +16,32 @@ void __init setup_real_mode(void)
u32 *ptr;
u16 *seg;
int i;
+ unsigned char *base;

- struct real_mode_header *header =
- (struct real_mode_header *) real_mode_blob;
-
- size_t size = PAGE_ALIGN(header->end);
+ size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);

/* Has to be in very low memory so we can execute real-mode AP code. */
mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
if (!mem)
panic("Cannot allocate trampoline\n");

- real_mode_base = __va(mem);
+ base = __va(mem);
memblock_reserve(mem, size);
+ real_mode_header = (struct real_mode_header *) base;

printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
- real_mode_base, (unsigned long long)mem, size);
+ base, (unsigned long long)mem, size);

- memcpy(real_mode_base, real_mode_blob, size);
+ memcpy(base, real_mode_blob, size);

- real_mode_seg = __pa(real_mode_base) >> 4;
+ real_mode_seg = __pa(base) >> 4;
rel = (u32 *) real_mode_relocs;

/* 16-bit segment relocations. */
count = rel[0];
rel = &rel[1];
for (i = 0; i < count; i++) {
- seg = (u16 *) (real_mode_base + rel[i]);
+ seg = (u16 *) (base + rel[i]);
*seg = real_mode_seg;
}

@@ -51,25 +49,21 @@ void __init setup_real_mode(void)
count = rel[i];
rel = &rel[i + 1];
for (i = 0; i < count; i++) {
- ptr = (u32 *) (real_mode_base + rel[i]);
- *ptr += __pa(real_mode_base);
+ ptr = (u32 *) (base + rel[i]);
+ *ptr += __pa(base);
}

- /* Copied header will contain relocated physical addresses. */
- memcpy(&real_mode_header, real_mode_base,
- sizeof(struct real_mode_header));
-
#ifdef CONFIG_X86_32
- *((u32 *)__va(real_mode_header.startup_32_smp)) = __pa(startup_32_smp);
- *((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt);
+ *((u32 *)__va(real_mode_header->startup_32_smp)) = __pa(startup_32_smp);
+ *((u32 *)__va(real_mode_header->boot_gdt)) = __pa(boot_gdt);
#else
- *((u64 *) __va(real_mode_header.startup_64_smp)) =
+ *((u64 *) __va(real_mode_header->startup_64_smp)) =
(u64)secondary_startup_64;

- *((u64 *) __va(real_mode_header.level3_ident_pgt)) =
+ *((u64 *) __va(real_mode_header->level3_ident_pgt)) =
__pa(level3_ident_pgt) + _KERNPG_TABLE;

- *((u64 *) __va(real_mode_header.level3_kernel_pgt)) =
+ *((u64 *) __va(real_mode_header->level3_kernel_pgt)) =
__pa(level3_kernel_pgt) + _KERNPG_TABLE;
#endif
}
@@ -82,23 +76,22 @@ void __init setup_real_mode(void)
*/
static int __init set_real_mode_permissions(void)
{
- size_t all_size =
- PAGE_ALIGN(real_mode_header.end) -
- __pa(real_mode_base);
+ unsigned char *base = (unsigned char *) real_mode_header;
+ size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);

size_t ro_size =
- PAGE_ALIGN(real_mode_header.ro_end) -
- __pa(real_mode_base);
+ PAGE_ALIGN(real_mode_header->ro_end) -
+ __pa(base);

size_t text_size =
- PAGE_ALIGN(real_mode_header.ro_end) -
- real_mode_header.text_start;
+ PAGE_ALIGN(real_mode_header->ro_end) -
+ real_mode_header->text_start;

unsigned long text_start =
- (unsigned long) __va(real_mode_header.text_start);
+ (unsigned long) __va(real_mode_header->text_start);

- set_memory_nx((unsigned long) real_mode_base, all_size >> PAGE_SHIFT);
- set_memory_ro((unsigned long) real_mode_base, ro_size >> PAGE_SHIFT);
+ set_memory_nx((unsigned long) base, size >> PAGE_SHIFT);
+ set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT);
set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT);

return 0;
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 050eff2..658f856 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -336,7 +336,7 @@ core_initcall(reboot_init);
void machine_real_restart(unsigned int type)
{
void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int))
- real_mode_header.machine_real_restart_asm;
+ real_mode_header->machine_real_restart_asm;

local_irq_disable();

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index c7971ea..b8c0661 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -665,9 +665,9 @@ static void __cpuinit announce_cpu(int cpu, int apicid)
static int __cpuinit do_boot_cpu(int apicid, int cpu)
{
volatile u32 *trampoline_status =
- (volatile u32 *) __va(real_mode_header.trampoline_status);
+ (volatile u32 *) __va(real_mode_header->trampoline_status);
/* start_ip had better be page-aligned! */
- unsigned long start_ip = real_mode_header.trampoline_data;
+ unsigned long start_ip = real_mode_header->trampoline_data;

unsigned long boot_error = 0;
int timeout;
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index c136e23..65adda4 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -202,7 +202,7 @@ static int tboot_setup_sleep(void)
}

tboot->acpi_sinfo.kernel_s3_resume_vector =
- real_mode_header.wakeup_start;
+ real_mode_header->wakeup_start;

return 0;
}
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index a91ec8f..c83005c 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -12,7 +12,6 @@
GLOBAL(real_mode_header)
.long pa_text_start
.long pa_ro_end
- .long pa_end
#ifdef CONFIG_X86_32
.long pa_machine_real_restart_asm
#endif
diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S
index 4d4afca..86b2e8d 100644
--- a/arch/x86/realmode/rm/realmode.lds.S
+++ b/arch/x86/realmode/rm/realmode.lds.S
@@ -65,7 +65,6 @@ SECTIONS
.signature : {
*(.signature)
}
- pa_end = .;

/DISCARD/ : {
*(.note*)
diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S
index fd72a99..204c6ec 100644
--- a/arch/x86/realmode/rmpiggy.S
+++ b/arch/x86/realmode/rmpiggy.S
@@ -13,6 +13,8 @@ GLOBAL(real_mode_blob)
.incbin "arch/x86/realmode/rm/realmode.bin"
END(real_mode_blob)

+GLOBAL(real_mode_blob_end);
+
GLOBAL(real_mode_relocs)
.incbin "arch/x86/realmode/rm/realmode.relocs"
END(real_mode_relocs)
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index e77aa4a..0613900 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -93,7 +93,7 @@ static struct notifier_block tts_notifier = {
static int acpi_sleep_prepare(u32 acpi_state)
{
#ifdef CONFIG_ACPI_SLEEP
- unsigned long wakeup_pa = real_mode_header.wakeup_start;
+ unsigned long wakeup_pa = real_mode_header->wakeup_start;
/* do we have a wakeup address for S2 and S3? */
if (acpi_state == ACPI_STATE_S3) {
if (!wakeup_pa)

2012-05-08 22:29:20

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: flattened rm hierachy

Commit-ID: c4845474a01f699966272536e8416222e3f2d2cb
Gitweb: http://git.kernel.org/tip/c4845474a01f699966272536e8416222e3f2d2cb
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:42 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:45 -0700

x86, realmode: flattened rm hierachy

Simplified hierarchy under rm directory to a flat
directory because it is not anymore really justified
to have own directory for wakeup code. It only adds
more complexity.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/kernel/acpi/sleep.c | 2 +-
arch/x86/realmode/rm/Makefile | 20 +++++++++-----
arch/x86/realmode/rm/bioscall.S | 1 +
arch/x86/realmode/rm/copy.S | 1 +
arch/x86/realmode/rm/regs.c | 1 +
arch/x86/realmode/rm/video-bios.c | 1 +
arch/x86/realmode/rm/video-mode.c | 1 +
arch/x86/realmode/rm/video-vesa.c | 1 +
arch/x86/realmode/rm/video-vga.c | 1 +
arch/x86/realmode/rm/{wakeup => }/wakemain.c | 0
arch/x86/realmode/rm/{wakeup => }/wakeup.h | 0
arch/x86/realmode/rm/wakeup/.gitignore | 3 --
arch/x86/realmode/rm/wakeup/Makefile | 33 ------------------------
arch/x86/realmode/rm/wakeup/bioscall.S | 1 -
arch/x86/realmode/rm/wakeup/copy.S | 1 -
arch/x86/realmode/rm/wakeup/regs.c | 1 -
arch/x86/realmode/rm/wakeup/video-bios.c | 1 -
arch/x86/realmode/rm/wakeup/video-mode.c | 1 -
arch/x86/realmode/rm/wakeup/video-vesa.c | 1 -
arch/x86/realmode/rm/wakeup/video-vga.c | 1 -
arch/x86/realmode/rm/{wakeup => }/wakeup_asm.S | 2 +-
21 files changed, 22 insertions(+), 52 deletions(-)

diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 6ca3f54..95bf99d 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -16,7 +16,7 @@
#include <asm/cacheflush.h>
#include <asm/realmode.h>

-#include "../../realmode/rm/wakeup/wakeup.h"
+#include "../../realmode/rm/wakeup.h"
#include "sleep.h"

unsigned long acpi_realmode_flags;
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index c2c27a4..fc8854b 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -7,21 +7,26 @@
#
#

-subdir- := wakeup
-
always := realmode.bin

realmode-y += header.o
realmode-y += trampoline_$(BITS).o
realmode-y += stack.o
realmode-$(CONFIG_X86_32) += reboot_32.o
-realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o
+realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs)
+
+wakeup-objs := wakeup_asm.o wakemain.o video-mode.o
+wakeup-objs += copy.o bioscall.o regs.o
+# The link order of the video-*.o modules can matter. In particular,
+# video-vga.o *must* be listed first, followed by video-vesa.o.
+# Hardware-specific drivers should follow in the order they should be
+# probed, and video-bios.o should typically be last.
+wakeup-objs += video-vga.o
+wakeup-objs += video-vesa.o
+wakeup-objs += video-bios.o

targets += $(realmode-y)

-$(obj)/wakeup/wakeup.o: FORCE
- $(Q)$(MAKE) $(build)=$(obj)/wakeup $@
-
REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y))

sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p'
@@ -55,7 +60,8 @@ $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE

# How to compile the 16-bit code. Note we always compile for -march=i386,
# that way we can complain to the user if the CPU is insufficient.
-KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \
+KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ -D_WAKEUP \
+ -I$(srctree)/arch/x86/boot \
-DDISABLE_BRANCH_PROFILING \
-Wall -Wstrict-prototypes \
-march=i386 -mregparm=3 \
diff --git a/arch/x86/realmode/rm/bioscall.S b/arch/x86/realmode/rm/bioscall.S
new file mode 100644
index 0000000..16162d1
--- /dev/null
+++ b/arch/x86/realmode/rm/bioscall.S
@@ -0,0 +1 @@
+#include "../../boot/bioscall.S"
diff --git a/arch/x86/realmode/rm/copy.S b/arch/x86/realmode/rm/copy.S
new file mode 100644
index 0000000..b785e6f
--- /dev/null
+++ b/arch/x86/realmode/rm/copy.S
@@ -0,0 +1 @@
+#include "../../boot/copy.S"
diff --git a/arch/x86/realmode/rm/regs.c b/arch/x86/realmode/rm/regs.c
new file mode 100644
index 0000000..fbb15b9
--- /dev/null
+++ b/arch/x86/realmode/rm/regs.c
@@ -0,0 +1 @@
+#include "../../boot/regs.c"
diff --git a/arch/x86/realmode/rm/video-bios.c b/arch/x86/realmode/rm/video-bios.c
new file mode 100644
index 0000000..848b25a
--- /dev/null
+++ b/arch/x86/realmode/rm/video-bios.c
@@ -0,0 +1 @@
+#include "../../boot/video-bios.c"
diff --git a/arch/x86/realmode/rm/video-mode.c b/arch/x86/realmode/rm/video-mode.c
new file mode 100644
index 0000000..2a98b7e
--- /dev/null
+++ b/arch/x86/realmode/rm/video-mode.c
@@ -0,0 +1 @@
+#include "../../boot/video-mode.c"
diff --git a/arch/x86/realmode/rm/video-vesa.c b/arch/x86/realmode/rm/video-vesa.c
new file mode 100644
index 0000000..413eddd
--- /dev/null
+++ b/arch/x86/realmode/rm/video-vesa.c
@@ -0,0 +1 @@
+#include "../../boot/video-vesa.c"
diff --git a/arch/x86/realmode/rm/video-vga.c b/arch/x86/realmode/rm/video-vga.c
new file mode 100644
index 0000000..3085f5c
--- /dev/null
+++ b/arch/x86/realmode/rm/video-vga.c
@@ -0,0 +1 @@
+#include "../../boot/video-vga.c"
diff --git a/arch/x86/realmode/rm/wakeup/wakemain.c b/arch/x86/realmode/rm/wakemain.c
similarity index 100%
rename from arch/x86/realmode/rm/wakeup/wakemain.c
rename to arch/x86/realmode/rm/wakemain.c
diff --git a/arch/x86/realmode/rm/wakeup/wakeup.h b/arch/x86/realmode/rm/wakeup.h
similarity index 100%
rename from arch/x86/realmode/rm/wakeup/wakeup.h
rename to arch/x86/realmode/rm/wakeup.h
diff --git a/arch/x86/realmode/rm/wakeup/.gitignore b/arch/x86/realmode/rm/wakeup/.gitignore
deleted file mode 100644
index 58f1f48..0000000
--- a/arch/x86/realmode/rm/wakeup/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-wakeup.bin
-wakeup.elf
-wakeup.lds
diff --git a/arch/x86/realmode/rm/wakeup/Makefile b/arch/x86/realmode/rm/wakeup/Makefile
deleted file mode 100644
index 4c85332..0000000
--- a/arch/x86/realmode/rm/wakeup/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# arch/x86/kernel/acpi/realmode/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-
-always := wakeup.o
-
-wakeup-y += wakeup_asm.o wakemain.o video-mode.o
-wakeup-y += copy.o bioscall.o regs.o
-
-# The link order of the video-*.o modules can matter. In particular,
-# video-vga.o *must* be listed first, followed by video-vesa.o.
-# Hardware-specific drivers should follow in the order they should be
-# probed, and video-bios.o should typically be last.
-wakeup-y += video-vga.o
-wakeup-y += video-vesa.o
-wakeup-y += video-bios.o
-
-targets += $(wakeup-y)
-
-WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
-
-LDFLAGS_wakeup.o := -m elf_i386 -r
-$(obj)/wakeup.o: $(WAKEUP_OBJS) FORCE
- $(call if_changed,ld)
-
-bootsrc := $(src)/../../../boot
-
-ccflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc)
-asflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc)
diff --git a/arch/x86/realmode/rm/wakeup/bioscall.S b/arch/x86/realmode/rm/wakeup/bioscall.S
deleted file mode 100644
index f51eb0b..0000000
--- a/arch/x86/realmode/rm/wakeup/bioscall.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/bioscall.S"
diff --git a/arch/x86/realmode/rm/wakeup/copy.S b/arch/x86/realmode/rm/wakeup/copy.S
deleted file mode 100644
index dc59ebe..0000000
--- a/arch/x86/realmode/rm/wakeup/copy.S
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/copy.S"
diff --git a/arch/x86/realmode/rm/wakeup/regs.c b/arch/x86/realmode/rm/wakeup/regs.c
deleted file mode 100644
index 6206033..0000000
--- a/arch/x86/realmode/rm/wakeup/regs.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/regs.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-bios.c b/arch/x86/realmode/rm/wakeup/video-bios.c
deleted file mode 100644
index 7deabc1..0000000
--- a/arch/x86/realmode/rm/wakeup/video-bios.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-bios.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-mode.c b/arch/x86/realmode/rm/wakeup/video-mode.c
deleted file mode 100644
index 328ad20..0000000
--- a/arch/x86/realmode/rm/wakeup/video-mode.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-mode.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-vesa.c b/arch/x86/realmode/rm/wakeup/video-vesa.c
deleted file mode 100644
index 9dbb967..0000000
--- a/arch/x86/realmode/rm/wakeup/video-vesa.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-vesa.c"
diff --git a/arch/x86/realmode/rm/wakeup/video-vga.c b/arch/x86/realmode/rm/wakeup/video-vga.c
deleted file mode 100644
index bcc8125..0000000
--- a/arch/x86/realmode/rm/wakeup/video-vga.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../boot/video-vga.c"
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S
similarity index 99%
rename from arch/x86/realmode/rm/wakeup/wakeup_asm.S
rename to arch/x86/realmode/rm/wakeup_asm.S
index f81c1cd..8a57c5a 100644
--- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup_asm.S
@@ -7,7 +7,7 @@
#include <asm/page_types.h>
#include <asm/pgtable_types.h>
#include <asm/processor-flags.h>
-#include "../realmode.h"
+#include "realmode.h"
#include "wakeup.h"

.code16

2012-05-08 22:30:11

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: header for trampoline code

Commit-ID: f37240f16bec91f15ce564515f70a6ca9715ce96
Gitweb: http://git.kernel.org/tip/f37240f16bec91f15ce564515f70a6ca9715ce96
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:43 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 11:48:45 -0700

x86, realmode: header for trampoline code

Added header for trampoline code that can be used to supply
input data to it. This makes interface between real mode code
and kernel cleaner and simpler. Replaced two confusing pointers
to level4 pgt in trampoline_64.S with a single pointer to the
beginning of the page table.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/include/asm/realmode.h | 32 ++++++++++++++++----------
arch/x86/kernel/realmode.c | 27 ++++++++++++----------
arch/x86/kernel/smpboot.c | 2 +-
arch/x86/realmode/rm/header.S | 35 +++++++++++++---------------
arch/x86/realmode/rm/trampoline_32.S | 36 +++++-------------------------
arch/x86/realmode/rm/trampoline_64.S | 18 ++++----------
arch/x86/realmode/rm/trampoline_common.S | 23 +++++++++++++++++++
arch/x86/realmode/rm/wakeup_asm.S | 2 +-
8 files changed, 87 insertions(+), 88 deletions(-)

diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index d3ae49f..1421eed 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -8,25 +8,33 @@
struct real_mode_header {
u32 text_start;
u32 ro_end;
- /* reboot */
-#ifdef CONFIG_X86_32
- u32 machine_real_restart_asm;
-#endif
/* SMP trampoline */
- u32 trampoline_data;
+ u32 trampoline_start;
u32 trampoline_status;
-#ifdef CONFIG_X86_32
- u32 startup_32_smp;
- u32 boot_gdt;
-#else
- u32 startup_64_smp;
- u32 level3_ident_pgt;
- u32 level3_kernel_pgt;
+ u32 trampoline_header;
+#ifdef CONFIG_X86_64
+ u32 trampoline_pgd;
#endif
+ /* ACPI S3 wakeup */
#ifdef CONFIG_ACPI_SLEEP
u32 wakeup_start;
u32 wakeup_header;
#endif
+ /* APM/BIOS reboot */
+#ifdef CONFIG_X86_32
+ u32 machine_real_restart_asm;
+#endif
+} __attribute__((__packed__));
+
+/* This must match data at trampoline_32/64.S */
+struct trampoline_header {
+#ifdef CONFIG_X86_32
+ u32 start;
+ u16 gdt_limit;
+ u32 gdt_base;
+#else
+ u64 start;
+#endif
} __attribute__((__packed__));

extern struct real_mode_header *real_mode_header;
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index 632c810..712fba8 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -17,8 +17,11 @@ void __init setup_real_mode(void)
u16 *seg;
int i;
unsigned char *base;
-
+ struct trampoline_header *trampoline_header;
size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
+#ifdef CONFIG_X86_64
+ u64 *trampoline_pgd;
+#endif

/* Has to be in very low memory so we can execute real-mode AP code. */
mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
@@ -28,7 +31,6 @@ void __init setup_real_mode(void)
base = __va(mem);
memblock_reserve(mem, size);
real_mode_header = (struct real_mode_header *) base;
-
printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
base, (unsigned long long)mem, size);

@@ -53,18 +55,19 @@ void __init setup_real_mode(void)
*ptr += __pa(base);
}

+ /* Must be perfomed *after* relocation. */
+ trampoline_header = (struct trampoline_header *)
+ __va(real_mode_header->trampoline_header);
+
#ifdef CONFIG_X86_32
- *((u32 *)__va(real_mode_header->startup_32_smp)) = __pa(startup_32_smp);
- *((u32 *)__va(real_mode_header->boot_gdt)) = __pa(boot_gdt);
+ trampoline_header->start = __pa(startup_32_smp);
+ trampoline_header->gdt_limit = __BOOT_DS + 7;
+ trampoline_header->gdt_base = __pa(boot_gdt);
#else
- *((u64 *) __va(real_mode_header->startup_64_smp)) =
- (u64)secondary_startup_64;
-
- *((u64 *) __va(real_mode_header->level3_ident_pgt)) =
- __pa(level3_ident_pgt) + _KERNPG_TABLE;
-
- *((u64 *) __va(real_mode_header->level3_kernel_pgt)) =
- __pa(level3_kernel_pgt) + _KERNPG_TABLE;
+ trampoline_header->start = (u64) secondary_startup_64;
+ trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
+ trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE;
+ trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE;
#endif
}

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index b8c0661..757c4b1 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -667,7 +667,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
volatile u32 *trampoline_status =
(volatile u32 *) __va(real_mode_header->trampoline_status);
/* start_ip had better be page-aligned! */
- unsigned long start_ip = real_mode_header->trampoline_data;
+ unsigned long start_ip = real_mode_header->trampoline_start;

unsigned long boot_error = 0;
int timeout;
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index c83005c..b4c3263 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -7,28 +7,25 @@
#include <linux/linkage.h>
#include <asm/page_types.h>

- .section ".header", "a"
+ .section ".header", "a"

GLOBAL(real_mode_header)
- .long pa_text_start
- .long pa_ro_end
-#ifdef CONFIG_X86_32
- .long pa_machine_real_restart_asm
-#endif
- /* SMP trampoline */
- .long pa_trampoline_data
- .long pa_trampoline_status
-#ifdef CONFIG_X86_32
- .long pa_startup_32_smp
- .long pa_boot_gdt
-#else
- .long pa_startup_64_smp
- .long pa_level3_ident_pgt
- .long pa_level3_kernel_pgt
+ .long pa_text_start
+ .long pa_ro_end
+ /* SMP trampoline */
+ .long pa_trampoline_start
+ .long pa_trampoline_status
+ .long pa_trampoline_header
+#ifdef CONFIG_X86_64
+ .long pa_trampoline_pgd;
#endif
- /* ACPI sleep */
+ /* ACPI S3 wakeup */
#ifdef CONFIG_ACPI_SLEEP
- .long pa_wakeup_start
- .long pa_wakeup_header
+ .long pa_wakeup_start
+ .long pa_wakeup_header
+#endif
+ /* APM/BIOS reboot */
+#ifdef CONFIG_X86_32
+ .long pa_machine_real_restart_asm
#endif
END(real_mode_header)
diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 1ecdbb5..6fc064b 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -13,16 +13,10 @@
*
* We jump into arch/x86/kernel/head_32.S.
*
- * On entry to trampoline_data, the processor is in real mode
+ * On entry to trampoline_start, the processor is in real mode
* with 16-bit addressing and 16-bit data. CS has some value
* and IP is zero. Thus, we load CS to the physical segment
* of the real mode code before doing anything further.
- *
- * The structure real_mode_header includes entries that need
- * to be set up before executing this code:
- *
- * startup_32_smp
- * boot_gdt
*/

#include <linux/linkage.h>
@@ -35,7 +29,7 @@
.code16

.balign PAGE_SIZE
-ENTRY(trampoline_data)
+ENTRY(trampoline_start)
wbinvd # Needed for NUMA-Q should be harmless for others

LJMPW_RM(1f)
@@ -45,7 +39,7 @@ ENTRY(trampoline_data)

cli # We should be safe anyway

- movl startup_32_smp, %eax # where we need to go
+ movl tr_start, %eax # where we need to go

movl $0xA5A5A5A5, trampoline_status
# write marker for master knows we're running
@@ -56,8 +50,8 @@ ENTRY(trampoline_data)
* operand size is 16bit. Use lgdtl instead to force operand size
* to 32 bit.
*/
- lidtl boot_idt_descr # load idt with 0, 0
- lgdtl boot_gdt_descr # load gdt with whatever is appropriate
+ lidtl tr_idt # load idt with 0, 0
+ lgdtl tr_gdt # load gdt with whatever is appropriate

movw $1, %dx # protected mode (PE) bit
lmsw %dx # into protected mode
@@ -69,22 +63,4 @@ ENTRY(trampoline_data)
ENTRY(startup_32) # note: also used from wakeup_asm.S
jmp *%eax

- .section ".rodata","a"
-
- .balign 4
-boot_idt_descr:
- .word 0 # idt limit = 0
- .long 0 # idt base = 0L
-
- .data
-
-boot_gdt_descr:
- .word __BOOT_DS + 7 # gdt limit
-GLOBAL(boot_gdt)
- .long 0 # gdt base
-
- .bss
-
- .balign 4
-GLOBAL(trampoline_status) .space 4
-GLOBAL(startup_32_smp) .space 4
+#include "trampoline_common.S"
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index f71ea08..3f72932 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -10,7 +10,7 @@
* trampoline page to make our stack and everything else
* is a mystery.
*
- * On entry to trampoline_data, the processor is in real mode
+ * On entry to trampoline_start, the processor is in real mode
* with 16-bit addressing and 16-bit data. CS has some value
* and IP is zero. Thus, data addresses need to be absolute
* (no relocation) and are taken with regard to r_base.
@@ -37,7 +37,7 @@
.balign PAGE_SIZE
.code16

-ENTRY(trampoline_data)
+ENTRY(trampoline_start)
cli # We should be safe anyway
wbinvd

@@ -97,7 +97,7 @@ ENTRY(startup_32)
movl %eax, %cr4 # Enable PAE mode

# Setup trampoline 4 level pagetables
- movl $pa_level3_ident_pgt, %eax
+ movl $pa_trampoline_pgd, %eax
movl %eax, %cr3

movl $MSR_EFER, %ecx
@@ -122,7 +122,7 @@ ENTRY(startup_32)
.balign 4
ENTRY(startup_64)
# Now jump into the kernel using virtual addresses
- jmpq *startup_64_smp(%rip)
+ jmpq *tr_start(%rip)

.section ".rodata","a"
.balign 16
@@ -143,12 +143,4 @@ tgdt:
.quad 0x00cf93000000ffff # __KERNEL_DS
tgdt_end:

- .bss
-
- .balign PAGE_SIZE
-GLOBAL(level3_ident_pgt) .space 511*8
-GLOBAL(level3_kernel_pgt) .space 8
-
- .balign 8
-GLOBAL(startup_64_smp) .space 8
-GLOBAL(trampoline_status) .space 4
+#include "trampoline_common.S"
diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S
new file mode 100644
index 0000000..c3f951c
--- /dev/null
+++ b/arch/x86/realmode/rm/trampoline_common.S
@@ -0,0 +1,23 @@
+ .section ".rodata","a"
+
+ .balign 4
+tr_idt: .fill 1, 6, 0
+
+ .bss
+
+ .balign 4
+GLOBAL(trampoline_status) .space 4
+
+GLOBAL(trampoline_header)
+#ifdef CONFIG_X86_32
+ tr_start: .space 4
+ tr_gdt: .space 6
+#else
+ tr_start: .space 8
+#endif
+END(trampoline_header)
+
+#ifdef CONFIG_X86_64
+ .balign PAGE_SIZE
+GLOBAL(trampoline_pgd) .space PAGE_SIZE
+#endif
diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S
index 8a57c5a..46108f0 100644
--- a/arch/x86/realmode/rm/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup_asm.S
@@ -132,7 +132,7 @@ ENTRY(wakeup_start)
ljmpl $__KERNEL_CS, $pa_startup_32
/* -> jmp *%eax in trampoline_32.S */
#else
- jmp trampoline_data
+ jmp trampoline_start
#endif

bogus_real_magic:

2012-05-08 22:31:10

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: move relocs from scripts/ to arch/x86/tools

Commit-ID: f2604c141a00c00b92b7fd2f9d2455517fdd6c15
Gitweb: http://git.kernel.org/tip/f2604c141a00c00b92b7fd2f9d2455517fdd6c15
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:44 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 15:03:35 -0700

x86, realmode: move relocs from scripts/ to arch/x86/tools

Moved relocs tool from scripts/ to arch/x86/tools because
it is architecture specific script. Added new target archscripts
that can be used to build scripts needed building an architecture.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
Cc: Sam Ravnborg <[email protected]>
Cc: Michal Marek <[email protected]>
---
Makefile | 9 ++++++---
arch/x86/Makefile | 3 +++
arch/x86/boot/compressed/Makefile | 4 ++--
arch/x86/realmode/rm/Makefile | 2 +-
arch/x86/tools/.gitignore | 1 +
arch/x86/tools/Makefile | 4 ++++
scripts/x86-relocs.c => arch/x86/tools/relocs.c | 0
scripts/Makefile | 1 -
8 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/Makefile b/Makefile
index 9e384ae..ed1bd29 100644
--- a/Makefile
+++ b/Makefile
@@ -442,7 +442,7 @@ asm-generic:

no-dot-config-targets := clean mrproper distclean \
cscope gtags TAGS tags help %docs check% coccicheck \
- include/linux/version.h headers_% archheaders \
+ include/linux/version.h headers_% archheaders archscripts \
kernelversion %src-pkg

config-targets := 0
@@ -979,7 +979,7 @@ prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
include/config/auto.conf
$(cmd_crmodverdir)

-archprepare: archheaders prepare1 scripts_basic
+archprepare: archheaders archscripts prepare1 scripts_basic

prepare0: archprepare FORCE
$(Q)$(MAKE) $(build)=.
@@ -1049,8 +1049,11 @@ hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
PHONY += archheaders
archheaders:

+PHONY += archscripts
+archscripts:
+
PHONY += __headers
-__headers: include/linux/version.h scripts_basic asm-generic archheaders FORCE
+__headers: include/linux/version.h scripts_basic asm-generic archheaders archscripts FORCE
$(Q)$(MAKE) $(build)=scripts build_unifdef

PHONY += headers_install_all
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 41a7237..94e91e4 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -134,6 +134,9 @@ KBUILD_CFLAGS += $(call cc-option,-mno-avx,)
KBUILD_CFLAGS += $(mflags-y)
KBUILD_AFLAGS += $(mflags-y)

+archscripts:
+ $(Q)$(MAKE) $(build)=arch/x86/tools relocs
+
###
# Syscall table generation

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 0435e8a..e398bb5 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -42,8 +42,8 @@ $(obj)/vmlinux.bin: vmlinux FORCE

targets += vmlinux.bin.all vmlinux.relocs

-CMD_RELOCS = scripts/x86-relocs
-quiet_cmd_relocs = RELOCS $@
+CMD_RELOCS = arch/x86/tools/relocs
+quiet_cmd_relocs = RELOCS $@
cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $<
$(obj)/vmlinux.relocs: vmlinux FORCE
$(call if_changed,relocs)
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index fc8854b..de40bc4 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -52,7 +52,7 @@ $(obj)/realmode.bin: $(obj)/realmode.elf
$(call if_changed,objcopy)

quiet_cmd_relocs = RELOCS $@
- cmd_relocs = scripts/x86-relocs --realmode $< > $@
+ cmd_relocs = arch/x86/tools/relocs --realmode $< > $@
$(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
$(call if_changed,relocs)

diff --git a/arch/x86/tools/.gitignore b/arch/x86/tools/.gitignore
new file mode 100644
index 0000000..be0ed06
--- /dev/null
+++ b/arch/x86/tools/.gitignore
@@ -0,0 +1 @@
+relocs
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
index d511aa9..733057b 100644
--- a/arch/x86/tools/Makefile
+++ b/arch/x86/tools/Makefile
@@ -36,3 +36,7 @@ HOSTCFLAGS_insn_sanity.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x
$(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c

$(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
+
+HOST_EXTRACFLAGS += -I$(srctree)/tools/include
+hostprogs-y += relocs
+relocs: $(obj)/relocs
diff --git a/scripts/x86-relocs.c b/arch/x86/tools/relocs.c
similarity index 100%
rename from scripts/x86-relocs.c
rename to arch/x86/tools/relocs.c
diff --git a/scripts/Makefile b/scripts/Makefile
index a241359d..3626666 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -15,7 +15,6 @@ hostprogs-$(CONFIG_LOGO) += pnmtologo
hostprogs-$(CONFIG_VT) += conmakehash
hostprogs-$(CONFIG_IKCONFIG) += bin2c
hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
-hostprogs-$(CONFIG_X86) += x86-relocs

always := $(hostprogs-y) $(hostprogs-m)

2012-05-08 22:31:50

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: fixes compilation issue in tboot.c

Commit-ID: bf8b88e97716feb750c3d34492f00d9c085e1183
Gitweb: http://git.kernel.org/tip/bf8b88e97716feb750c3d34492f00d9c085e1183
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:45 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 15:04:27 -0700

x86, realmode: fixes compilation issue in tboot.c

Fixed include path of wakeup.h in tboot.c.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/kernel/tboot.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index 65adda4..f84fe00 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -44,7 +44,7 @@
#include <asm/e820.h>
#include <asm/io.h>

-#include "acpi/realmode/wakeup.h"
+#include "../realmode/rm/wakeup.h"

/* Global pointer to shared data; NULL means no measured launch. */
struct tboot *tboot __read_mostly;

2012-05-08 22:32:42

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: read cr4 and EFER from kernel for 64-bit trampoline

Commit-ID: cda846f101fb1396b6924f1d9b68ac3d42de5403
Gitweb: http://git.kernel.org/tip/cda846f101fb1396b6924f1d9b68ac3d42de5403
Author: Jarkko Sakkinen <[email protected]>
AuthorDate: Tue, 8 May 2012 21:22:46 +0300
Committer: H. Peter Anvin <[email protected]>
CommitDate: Tue, 8 May 2012 15:04:27 -0700

x86, realmode: read cr4 and EFER from kernel for 64-bit trampoline

This patch changes 64-bit trampoline so that CR4 and
EFER are provided by the kernel instead of using fixed
values.

Signed-off-by: Jarkko Sakkinen <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/include/asm/processor.h | 7 +++++-
arch/x86/include/asm/realmode.h | 8 +++++-
arch/x86/kernel/realmode.c | 8 +++++++
arch/x86/kernel/setup.c | 2 +
arch/x86/realmode/rm/header.S | 1 +
arch/x86/realmode/rm/trampoline_64.S | 32 ++++++-----------------------
arch/x86/realmode/rm/trampoline_common.S | 19 +++++++++++++++++
7 files changed, 49 insertions(+), 28 deletions(-)

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 4fa7dcc..404583c 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -544,13 +544,16 @@ static inline void load_sp0(struct tss_struct *tss,
* enable), so that any CPU's that boot up
* after us can get the correct flags.
*/
-extern unsigned long mmu_cr4_features;
+extern unsigned long mmu_cr4_features;
+extern u32 *trampoline_cr4_features;

static inline void set_in_cr4(unsigned long mask)
{
unsigned long cr4;

mmu_cr4_features |= mask;
+ if (trampoline_cr4_features)
+ *trampoline_cr4_features = mmu_cr4_features;
cr4 = read_cr4();
cr4 |= mask;
write_cr4(cr4);
@@ -561,6 +564,8 @@ static inline void clear_in_cr4(unsigned long mask)
unsigned long cr4;

mmu_cr4_features &= ~mask;
+ if (trampoline_cr4_features)
+ *trampoline_cr4_features = mmu_cr4_features;
cr4 = read_cr4();
cr4 &= ~mask;
write_cr4(cr4);
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index 1421eed..937dc60 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -24,18 +24,22 @@ struct real_mode_header {
#ifdef CONFIG_X86_32
u32 machine_real_restart_asm;
#endif
-} __attribute__((__packed__));
+};

/* This must match data at trampoline_32/64.S */
struct trampoline_header {
#ifdef CONFIG_X86_32
u32 start;
+ u16 gdt_pad;
u16 gdt_limit;
u32 gdt_base;
#else
u64 start;
+ u32 cr4;
+ u32 efer_low;
+ u32 efer_high;
#endif
-} __attribute__((__packed__));
+};

extern struct real_mode_header *real_mode_header;
extern unsigned char real_mode_blob_end[];
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index 712fba8..66ac276 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -6,6 +6,7 @@
#include <asm/realmode.h>

struct real_mode_header *real_mode_header;
+u32 *trampoline_cr4_features;

void __init setup_real_mode(void)
{
@@ -64,7 +65,14 @@ void __init setup_real_mode(void)
trampoline_header->gdt_limit = __BOOT_DS + 7;
trampoline_header->gdt_base = __pa(boot_gdt);
#else
+ if (rdmsr_safe(MSR_EFER, &trampoline_header->efer_low,
+ &trampoline_header->efer_high))
+ BUG();
+
trampoline_header->start = (u64) secondary_startup_64;
+ trampoline_cr4_features = &trampoline_header->cr4;
+ *trampoline_cr4_features = read_cr4();
+
trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE;
trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE;
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 7a14fec..efcf305 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -975,6 +975,8 @@ void __init setup_arch(char **cmdline_p)
if (boot_cpu_data.cpuid_level >= 0) {
/* A CPU has %cr4 if and only if it has CPUID */
mmu_cr4_features = read_cr4();
+ if (trampoline_cr4_features)
+ *trampoline_cr4_features = mmu_cr4_features;
}

#ifdef CONFIG_X86_32
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index b4c3263..4612d53 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -9,6 +9,7 @@

.section ".header", "a"

+ .balign 16
GLOBAL(real_mode_header)
.long pa_text_start
.long pa_ro_end
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 3f72932..66e26f0 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -34,9 +34,9 @@
#include "realmode.h"

.text
- .balign PAGE_SIZE
.code16

+ .balign PAGE_SIZE
ENTRY(trampoline_start)
cli # We should be safe anyway
wbinvd
@@ -65,8 +65,8 @@ ENTRY(trampoline_start)
* to 32 bit.
*/

- lidtl tidt # load idt with 0, 0
- lgdtl tgdt # load gdt with whatever is appropriate
+ lidtl tr_idt # load idt with 0, 0
+ lgdtl tr_gdt # load gdt with whatever is appropriate

movw $__KERNEL_DS, %dx # Data segment descriptor

@@ -93,16 +93,17 @@ ENTRY(startup_32)
movl %edx, %fs
movl %edx, %gs

- movl $X86_CR4_PAE, %eax
+ movl pa_tr_cr4, %eax
movl %eax, %cr4 # Enable PAE mode

# Setup trampoline 4 level pagetables
movl $pa_trampoline_pgd, %eax
movl %eax, %cr3

+ # Set up EFER
+ movl pa_tr_efer, %eax
+ movl pa_tr_efer + 4, %edx
movl $MSR_EFER, %ecx
- movl $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax # Enable Long Mode
- xorl %edx, %edx
wrmsr

# Enable paging and in turn activate Long Mode
@@ -124,23 +125,4 @@ ENTRY(startup_64)
# Now jump into the kernel using virtual addresses
jmpq *tr_start(%rip)

- .section ".rodata","a"
- .balign 16
-tidt:
- .word 0 # idt limit = 0
- .word 0, 0 # idt base = 0L
-
- # Duplicate the global descriptor table
- # so the kernel can live anywhere
- .balign 16
- .globl tgdt
-tgdt:
- .short tgdt_end - tgdt - 1 # gdt limit
- .long pa_tgdt
- .short 0
- .quad 0x00cf9b000000ffff # __KERNEL32_CS
- .quad 0x00af9b000000ffff # __KERNEL_CS
- .quad 0x00cf93000000ffff # __KERNEL_DS
-tgdt_end:
-
#include "trampoline_common.S"
diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S
index c3f951c..cac444b 100644
--- a/arch/x86/realmode/rm/trampoline_common.S
+++ b/arch/x86/realmode/rm/trampoline_common.S
@@ -1,5 +1,20 @@
.section ".rodata","a"

+#ifdef CONFIG_X86_64
+ # Duplicate the global descriptor table
+ # so the kernel can live anywhere
+ .balign 16
+ .globl tr_gdt
+tr_gdt:
+ .short tr_gdt_end - tr_gdt - 1 # gdt limit
+ .long pa_tr_gdt
+ .short 0
+ .quad 0x00cf9b000000ffff # __KERNEL32_CS
+ .quad 0x00af9b000000ffff # __KERNEL_CS
+ .quad 0x00cf93000000ffff # __KERNEL_DS
+tr_gdt_end:
+#endif
+
.balign 4
tr_idt: .fill 1, 6, 0

@@ -8,12 +23,16 @@ tr_idt: .fill 1, 6, 0
.balign 4
GLOBAL(trampoline_status) .space 4

+ .balign 8
GLOBAL(trampoline_header)
#ifdef CONFIG_X86_32
tr_start: .space 4
+ tr_gdt_pad: .space 2
tr_gdt: .space 6
#else
tr_start: .space 8
+ GLOBAL(tr_cr4) .space 4
+ GLOBAL(tr_efer) .space 8
#endif
END(trampoline_header)

2012-05-09 07:12:58

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH 04/23] x86, realmode: Move reboot_32.S to unified realmode code

Il 08/05/2012 20:22, Jarkko Sakkinen ha scritto:
> + xorl %ecx, %ecx
> + movl %cr0, %edx
> + andl $0x00000011, %edx
> + orl $0x60000000, %edx
> + movl %edx, %cr0
> + movl %ecx, %cr3
> + movl %cr0, %edx
> + andl $0x60000000, %edx /* If no cache bits -> no wbinvd */

Shouldn't this be a testl?

> + jz 2f
> + wbinvd
> +2:
> + andb $0x10, %dl

... because otherwise this is really a mov $0, %edx and it sounds wrong.
It doesn't really matter, nobody really uses bit 4 of CR0 anymore,
still would be nice to fix it.

> + movl %edx, %cr0

Paolo

2012-05-09 13:53:46

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 04/23] x86, realmode: Move reboot_32.S to unified realmode code

On 05/09/2012 05:37 AM, Jarkko Sakkinen wrote:
>
> It's true that it doesn't matter much but still it is a
> regression. And it doesn't cause any kind of overhead
> or bloat to fix this.
>

However, the big thing is that we jump to the BIOS with caches off. I
personally think it is the wrong thing to do (we don't jump to the real
reset vector anyway) but it is what has been tested for a long time.

-hpa

2012-05-09 14:16:14

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH 04/23] x86, realmode: Move reboot_32.S to unified realmode code

Il 09/05/2012 15:53, H. Peter Anvin ha scritto:
>> > It's true that it doesn't matter much but still it is a
>> > regression. And it doesn't cause any kind of overhead
>> > or bloat to fix this.
>> >
> However, the big thing is that we jump to the BIOS with caches off. I
> personally think it is the wrong thing to do (we don't jump to the real
> reset vector anyway) but it is what has been tested for a long time.

I'm not sure I understand. The code has

andl $0x60000000, %edx ; clear ET/PE
jz 2f
...
2:
andb $0x10, %dl ; clear CD/WT, %edx is always 0


What I've suggested is:

testl $0x60000000, %edx
jz 2f
...
2:
andb $0x10, %dl ; clear PE only


What would jump to the BIOS with caches on is:

testl $0x60000000, %edx
jz 2f
...
2:
andl $0x10, %edx ; Clear CD/WT/PE


Am I missing something?

Paolo

2012-05-09 14:18:07

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 04/23] x86, realmode: Move reboot_32.S to unified realmode code

On 05/09/2012 07:15 AM, Paolo Bonzini wrote:
>
> I'm not sure I understand. The code has
>
> andl $0x60000000, %edx ; clear ET/PE
> jz 2f
> ...
> 2:
> andb $0x10, %dl ; clear CD/WT, %edx is always 0
>
>
> What I've suggested is:
>
> testl $0x60000000, %edx
> jz 2f
> ...
> 2:
> andb $0x10, %dl ; clear PE only
>
>
> What would jump to the BIOS with caches on is:
>
> testl $0x60000000, %edx
> jz 2f
> ...
> 2:
> andl $0x10, %edx ; Clear CD/WT/PE
>
>
> Am I missing something?
>

Not awake yet, sorry...

-hpa

2012-05-09 15:51:49

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 02/23] x86, realmode: realmode.bin infrastructure

On 05/08/2012 11:22 AM, Jarkko Sakkinen wrote:
> diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile
> new file mode 100644
> index 0000000..f22a4f8
> --- /dev/null
> +++ b/arch/x86/realmode/Makefile
> @@ -0,0 +1,20 @@
> +#
> +# arch/x86/realmode/Makefile
> +#
> +# This file is subject to the terms and conditions of the GNU General Public
> +# License. See the file "COPYING" in the main directory of this archive
> +# for more details.
> +#
> +#
> +
> +subdir- := rm
> +
> +obj-y += rmpiggy.o
> +
> +$(obj)/rmpiggy.o: $(obj)/rm/realmode.relocs $(obj)/rm/realmode.bin
> +
> +$(obj)/rm/realmode.bin: FORCE
> + $(Q)$(MAKE) $(build)=$(obj)/rm $@
> +
> +$(obj)/rm/realmode.relocs: FORCE
> + $(Q)$(MAKE) $(build)=$(obj)/rm $@

OK, this bit seems to cause serious problems. Specifically, this
invokes the rm/ Makefile twice, and they end up doing two independent
builds in parallel, stepping on each other in the process.

Sam, Michal: do you have any suggestions for how to do the above better?

-hpa

2012-05-09 20:06:17

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 02/23] x86, realmode: realmode.bin infrastructure

On 05/09/2012 12:57 PM, Jarkko Sakkinen wrote:
>
> diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile
> index f22a4f8..615878e 100644
> --- a/arch/x86/realmode/Makefile
> +++ b/arch/x86/realmode/Makefile
> @@ -15,6 +15,3 @@ $(obj)/rmpiggy.o: $(obj)/rm/realmode.relocs
> $(obj)/rm/realmode.bin
>
> $(obj)/rm/realmode.bin: FORCE
> $(Q)$(MAKE) $(build)=$(obj)/rm $@
> -
> -$(obj)/rm/realmode.relocs: FORCE
> - $(Q)$(MAKE) $(build)=$(obj)/rm $@
> diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
> index de40bc4..1c1d3d3 100644
> --- a/arch/x86/realmode/rm/Makefile
> +++ b/arch/x86/realmode/rm/Makefile
> @@ -48,7 +48,7 @@ $(obj)/realmode.elf: $(obj)/realmode.lds
> $(REALMODE_OBJS) FORCE
>
> OBJCOPYFLAGS_realmode.bin := -O binary
>
> -$(obj)/realmode.bin: $(obj)/realmode.elf
> +$(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs
> $(call if_changed,objcopy)
>
> quiet_cmd_relocs = RELOCS $@
>
> Would this resolve the existing issues or not?
>

That should would work, although it is definitely a hack. It all really
comes down to make not having a good way to deal with a single process
generating more than one output. I discussed this about a decade(!) ago
with the GNU make maintainers, and they said that make *can* be made to
do the right thing by doing a pattern rule:

%.foo %.bar: %.baz

... as pattern rules with multiple targets are handled differently than
non-pattern rules with multiple targets. They were -- and still are --
reluctant to actually fix the problem since it wouldn't be backwards
compatible, but of course that is true with any new Make feature.

Not sure how to use the pattern rule in this case, so I guess we might
as well go with the hack. Can you send it as a proper patch (with a
description and Signed-off-by:), please?

-hpa

2012-05-16 20:37:44

by H. Peter Anvin

[permalink] [raw]
Subject: [tip:x86/trampoline] x86, realmode: Mask out EFER. LMA when saving trampoline EFER

Commit-ID: 796038799a72adb279d785c9154df6eeb98b6e8d
Gitweb: http://git.kernel.org/tip/796038799a72adb279d785c9154df6eeb98b6e8d
Author: H. Peter Anvin <[email protected]>
AuthorDate: Wed, 16 May 2012 13:22:41 -0700
Committer: H. Peter Anvin <[email protected]>
CommitDate: Wed, 16 May 2012 13:22:41 -0700

x86, realmode: Mask out EFER.LMA when saving trampoline EFER

Some AMD processors apparently #GP(0) if EFER.LMA is set in WRMSR,
rather than ignoring it. Thus, we need to mask it out.

Reported-by: Ingo Molnar <[email protected]>
Tested-by: Borislav Petkov <[email protected]>
Cc: Jarkko Sakkinen <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
---
arch/x86/kernel/realmode.c | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index 66ac276..0992779 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -22,6 +22,7 @@ void __init setup_real_mode(void)
size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
#ifdef CONFIG_X86_64
u64 *trampoline_pgd;
+ u32 efer_low, efer_high;
#endif

/* Has to be in very low memory so we can execute real-mode AP code. */
@@ -65,9 +66,13 @@ void __init setup_real_mode(void)
trampoline_header->gdt_limit = __BOOT_DS + 7;
trampoline_header->gdt_base = __pa(boot_gdt);
#else
- if (rdmsr_safe(MSR_EFER, &trampoline_header->efer_low,
- &trampoline_header->efer_high))
- BUG();
+ /*
+ * Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR
+ * so we need to mask it out.
+ */
+ rdmsr(MSR_EFER, efer_low, efer_high);
+ trampoline_header->efer_low = efer_low & ~EFER_LMA;
+ trampoline_header->efer_high = efer_high;

trampoline_header->start = (u64) secondary_startup_64;
trampoline_cr4_features = &trampoline_header->cr4;