diff options
Diffstat (limited to 'arch/x86/kernel/acpi/realmode')
-rw-r--r-- | arch/x86/kernel/acpi/realmode/Makefile | 57 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/realmode/copy.S | 1 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/realmode/video-bios.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/realmode/video-mode.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/realmode/video-vesa.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/realmode/video-vga.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/realmode/wakemain.c | 81 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/realmode/wakeup.S | 113 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/realmode/wakeup.h | 36 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/realmode/wakeup.lds.S | 61 |
10 files changed, 353 insertions, 0 deletions
diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile new file mode 100644 index 000000000000..092900854acc --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/Makefile | |||
@@ -0,0 +1,57 @@ | |||
1 | # | ||
2 | # arch/x86/kernel/acpi/realmode/Makefile | ||
3 | # | ||
4 | # This file is subject to the terms and conditions of the GNU General Public | ||
5 | # License. See the file "COPYING" in the main directory of this archive | ||
6 | # for more details. | ||
7 | # | ||
8 | |||
9 | targets := wakeup.bin wakeup.elf | ||
10 | |||
11 | wakeup-y += wakeup.o wakemain.o video-mode.o copy.o | ||
12 | |||
13 | # The link order of the video-*.o modules can matter. In particular, | ||
14 | # video-vga.o *must* be listed first, followed by video-vesa.o. | ||
15 | # Hardware-specific drivers should follow in the order they should be | ||
16 | # probed, and video-bios.o should typically be last. | ||
17 | wakeup-y += video-vga.o | ||
18 | wakeup-y += video-vesa.o | ||
19 | wakeup-y += video-bios.o | ||
20 | |||
21 | targets += $(wakeup-y) | ||
22 | |||
23 | bootsrc := $(src)/../../../boot | ||
24 | |||
25 | # --------------------------------------------------------------------------- | ||
26 | |||
27 | # How to compile the 16-bit code. Note we always compile for -march=i386, | ||
28 | # that way we can complain to the user if the CPU is insufficient. | ||
29 | # Compile with _SETUP since this is similar to the boot-time setup code. | ||
30 | KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \ | ||
31 | -I$(srctree)/$(bootsrc) \ | ||
32 | $(cflags-y) \ | ||
33 | -Wall -Wstrict-prototypes \ | ||
34 | -march=i386 -mregparm=3 \ | ||
35 | -include $(srctree)/$(bootsrc)/code16gcc.h \ | ||
36 | -fno-strict-aliasing -fomit-frame-pointer \ | ||
37 | $(call cc-option, -ffreestanding) \ | ||
38 | $(call cc-option, -fno-toplevel-reorder,\ | ||
39 | $(call cc-option, -fno-unit-at-a-time)) \ | ||
40 | $(call cc-option, -fno-stack-protector) \ | ||
41 | $(call cc-option, -mpreferred-stack-boundary=2) | ||
42 | KBUILD_CFLAGS += $(call cc-option, -m32) | ||
43 | KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ | ||
44 | |||
45 | WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y)) | ||
46 | |||
47 | LDFLAGS_wakeup.elf := -T | ||
48 | |||
49 | CPPFLAGS_wakeup.lds += -P -C | ||
50 | |||
51 | $(obj)/wakeup.elf: $(src)/wakeup.lds $(WAKEUP_OBJS) FORCE | ||
52 | $(call if_changed,ld) | ||
53 | |||
54 | OBJCOPYFLAGS_wakeup.bin := -O binary | ||
55 | |||
56 | $(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE | ||
57 | $(call if_changed,objcopy) | ||
diff --git a/arch/x86/kernel/acpi/realmode/copy.S b/arch/x86/kernel/acpi/realmode/copy.S new file mode 100644 index 000000000000..dc59ebee69d8 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/copy.S | |||
@@ -0,0 +1 @@ | |||
#include "../../../boot/copy.S" | |||
diff --git a/arch/x86/kernel/acpi/realmode/video-bios.c b/arch/x86/kernel/acpi/realmode/video-bios.c new file mode 100644 index 000000000000..7deabc144a27 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/video-bios.c | |||
@@ -0,0 +1 @@ | |||
#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 new file mode 100644 index 000000000000..328ad209f113 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/video-mode.c | |||
@@ -0,0 +1 @@ | |||
#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 new file mode 100644 index 000000000000..9dbb9672226a --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/video-vesa.c | |||
@@ -0,0 +1 @@ | |||
#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 new file mode 100644 index 000000000000..bcc81255f374 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/video-vga.c | |||
@@ -0,0 +1 @@ | |||
#include "../../../boot/video-vga.c" | |||
diff --git a/arch/x86/kernel/acpi/realmode/wakemain.c b/arch/x86/kernel/acpi/realmode/wakemain.c new file mode 100644 index 000000000000..883962d9eef2 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/wakemain.c | |||
@@ -0,0 +1,81 @@ | |||
1 | #include "wakeup.h" | ||
2 | #include "boot.h" | ||
3 | |||
4 | static void udelay(int loops) | ||
5 | { | ||
6 | while (loops--) | ||
7 | io_delay(); /* Approximately 1 us */ | ||
8 | } | ||
9 | |||
10 | static void beep(unsigned int hz) | ||
11 | { | ||
12 | u8 enable; | ||
13 | |||
14 | if (!hz) { | ||
15 | enable = 0x00; /* Turn off speaker */ | ||
16 | } else { | ||
17 | u16 div = 1193181/hz; | ||
18 | |||
19 | outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */ | ||
20 | io_delay(); | ||
21 | outb(div, 0x42); /* LSB of counter */ | ||
22 | io_delay(); | ||
23 | outb(div >> 8, 0x42); /* MSB of counter */ | ||
24 | io_delay(); | ||
25 | |||
26 | enable = 0x03; /* Turn on speaker */ | ||
27 | } | ||
28 | inb(0x61); /* Dummy read of System Control Port B */ | ||
29 | io_delay(); | ||
30 | outb(enable, 0x61); /* Enable timer 2 output to speaker */ | ||
31 | io_delay(); | ||
32 | } | ||
33 | |||
34 | #define DOT_HZ 880 | ||
35 | #define DASH_HZ 587 | ||
36 | #define US_PER_DOT 125000 | ||
37 | |||
38 | /* Okay, this is totally silly, but it's kind of fun. */ | ||
39 | static void send_morse(const char *pattern) | ||
40 | { | ||
41 | char s; | ||
42 | |||
43 | while ((s = *pattern++)) { | ||
44 | switch (s) { | ||
45 | case '.': | ||
46 | beep(DOT_HZ); | ||
47 | udelay(US_PER_DOT); | ||
48 | beep(0); | ||
49 | udelay(US_PER_DOT); | ||
50 | break; | ||
51 | case '-': | ||
52 | beep(DASH_HZ); | ||
53 | udelay(US_PER_DOT * 3); | ||
54 | beep(0); | ||
55 | udelay(US_PER_DOT); | ||
56 | break; | ||
57 | default: /* Assume it's a space */ | ||
58 | udelay(US_PER_DOT * 3); | ||
59 | break; | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | void main(void) | ||
65 | { | ||
66 | /* Kill machine if structures are wrong */ | ||
67 | if (wakeup_header.real_magic != 0x12345678) | ||
68 | while (1); | ||
69 | |||
70 | if (wakeup_header.realmode_flags & 4) | ||
71 | send_morse("...-"); | ||
72 | |||
73 | if (wakeup_header.realmode_flags & 1) | ||
74 | asm volatile("lcallw $0xc000,$3"); | ||
75 | |||
76 | if (wakeup_header.realmode_flags & 2) { | ||
77 | /* Need to call BIOS */ | ||
78 | probe_cards(0); | ||
79 | set_mode(wakeup_header.video_mode); | ||
80 | } | ||
81 | } | ||
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S new file mode 100644 index 000000000000..f9b77fb37e5b --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/wakeup.S | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * ACPI wakeup real mode startup stub | ||
3 | */ | ||
4 | #include <asm/segment.h> | ||
5 | #include <asm/msr-index.h> | ||
6 | #include <asm/page.h> | ||
7 | #include <asm/pgtable.h> | ||
8 | |||
9 | .code16 | ||
10 | .section ".header", "a" | ||
11 | |||
12 | /* This should match the structure in wakeup.h */ | ||
13 | .globl wakeup_header | ||
14 | wakeup_header: | ||
15 | video_mode: .short 0 /* Video mode number */ | ||
16 | pmode_return: .byte 0x66, 0xea /* ljmpl */ | ||
17 | .long 0 /* offset goes here */ | ||
18 | .short __KERNEL_CS | ||
19 | pmode_cr0: .long 0 /* Saved %cr0 */ | ||
20 | pmode_cr3: .long 0 /* Saved %cr3 */ | ||
21 | pmode_cr4: .long 0 /* Saved %cr4 */ | ||
22 | pmode_efer: .quad 0 /* Saved EFER */ | ||
23 | pmode_gdt: .quad 0 | ||
24 | realmode_flags: .long 0 | ||
25 | real_magic: .long 0 | ||
26 | trampoline_segment: .word 0 | ||
27 | signature: .long 0x51ee1111 | ||
28 | |||
29 | .text | ||
30 | .globl _start | ||
31 | .code16 | ||
32 | wakeup_code: | ||
33 | _start: | ||
34 | cli | ||
35 | cld | ||
36 | |||
37 | /* Set up segments */ | ||
38 | movw %cs, %ax | ||
39 | movw %ax, %ds | ||
40 | movw %ax, %es | ||
41 | movw %ax, %ss | ||
42 | |||
43 | movl $wakeup_stack_end, %esp | ||
44 | |||
45 | /* Clear the EFLAGS */ | ||
46 | pushl $0 | ||
47 | popfl | ||
48 | |||
49 | /* Check header signature... */ | ||
50 | movl signature, %eax | ||
51 | cmpl $0x51ee1111, %eax | ||
52 | jne bogus_real_magic | ||
53 | |||
54 | /* Check we really have everything... */ | ||
55 | movl end_signature, %eax | ||
56 | cmpl $0x65a22c82, %eax | ||
57 | jne bogus_real_magic | ||
58 | |||
59 | /* Call the C code */ | ||
60 | calll main | ||
61 | |||
62 | /* Do any other stuff... */ | ||
63 | |||
64 | #ifndef CONFIG_64BIT | ||
65 | /* This could also be done in C code... */ | ||
66 | movl pmode_cr3, %eax | ||
67 | movl %eax, %cr3 | ||
68 | |||
69 | movl pmode_cr4, %ecx | ||
70 | jecxz 1f | ||
71 | movl %ecx, %cr4 | ||
72 | 1: | ||
73 | movl pmode_efer, %eax | ||
74 | movl pmode_efer + 4, %edx | ||
75 | movl %eax, %ecx | ||
76 | orl %edx, %ecx | ||
77 | jz 1f | ||
78 | movl $0xc0000080, %ecx | ||
79 | wrmsr | ||
80 | 1: | ||
81 | |||
82 | lgdtl pmode_gdt | ||
83 | |||
84 | /* This really couldn't... */ | ||
85 | movl pmode_cr0, %eax | ||
86 | movl %eax, %cr0 | ||
87 | jmp pmode_return | ||
88 | #else | ||
89 | pushw $0 | ||
90 | pushw trampoline_segment | ||
91 | pushw $0 | ||
92 | lret | ||
93 | #endif | ||
94 | |||
95 | bogus_real_magic: | ||
96 | 1: | ||
97 | hlt | ||
98 | jmp 1b | ||
99 | |||
100 | .data | ||
101 | .balign 4 | ||
102 | .globl HEAP, heap_end | ||
103 | HEAP: | ||
104 | .long wakeup_heap | ||
105 | heap_end: | ||
106 | .long wakeup_stack | ||
107 | |||
108 | .bss | ||
109 | wakeup_heap: | ||
110 | .space 2048 | ||
111 | wakeup_stack: | ||
112 | .space 2048 | ||
113 | wakeup_stack_end: | ||
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h new file mode 100644 index 000000000000..ef8166fe8020 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/wakeup.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Definitions for the wakeup data structure at the head of the | ||
3 | * wakeup code. | ||
4 | */ | ||
5 | |||
6 | #ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H | ||
7 | #define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H | ||
8 | |||
9 | #ifndef __ASSEMBLY__ | ||
10 | #include <linux/types.h> | ||
11 | |||
12 | /* This must match data at wakeup.S */ | ||
13 | struct wakeup_header { | ||
14 | u16 video_mode; /* Video mode number */ | ||
15 | u16 _jmp1; /* ljmpl opcode, 32-bit only */ | ||
16 | u32 pmode_entry; /* Protected mode resume point, 32-bit only */ | ||
17 | u16 _jmp2; /* CS value, 32-bit only */ | ||
18 | u32 pmode_cr0; /* Protected mode cr0 */ | ||
19 | u32 pmode_cr3; /* Protected mode cr3 */ | ||
20 | u32 pmode_cr4; /* Protected mode cr4 */ | ||
21 | u32 pmode_efer_low; /* Protected mode EFER */ | ||
22 | u32 pmode_efer_high; | ||
23 | u64 pmode_gdt; | ||
24 | u32 realmode_flags; | ||
25 | u32 real_magic; | ||
26 | u16 trampoline_segment; /* segment with trampoline code, 64-bit only */ | ||
27 | u32 signature; /* To check we have correct structure */ | ||
28 | } __attribute__((__packed__)); | ||
29 | |||
30 | extern struct wakeup_header wakeup_header; | ||
31 | #endif | ||
32 | |||
33 | #define HEADER_OFFSET 0x3f00 | ||
34 | #define WAKEUP_SIZE 0x4000 | ||
35 | |||
36 | #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 new file mode 100644 index 000000000000..22fab6c4be15 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/wakeup.lds.S | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * wakeup.ld | ||
3 | * | ||
4 | * Linker script for the real-mode wakeup code | ||
5 | */ | ||
6 | #undef i386 | ||
7 | #include "wakeup.h" | ||
8 | |||
9 | OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") | ||
10 | OUTPUT_ARCH(i386) | ||
11 | ENTRY(_start) | ||
12 | |||
13 | SECTIONS | ||
14 | { | ||
15 | . = HEADER_OFFSET; | ||
16 | .header : { | ||
17 | *(.header) | ||
18 | } | ||
19 | |||
20 | . = 0; | ||
21 | .text : { | ||
22 | *(.text*) | ||
23 | } | ||
24 | |||
25 | . = ALIGN(16); | ||
26 | .rodata : { | ||
27 | *(.rodata*) | ||
28 | } | ||
29 | |||
30 | .videocards : { | ||
31 | video_cards = .; | ||
32 | *(.videocards) | ||
33 | video_cards_end = .; | ||
34 | } | ||
35 | |||
36 | . = ALIGN(16); | ||
37 | .data : { | ||
38 | *(.data*) | ||
39 | } | ||
40 | |||
41 | .signature : { | ||
42 | end_signature = .; | ||
43 | LONG(0x65a22c82) | ||
44 | } | ||
45 | |||
46 | . = ALIGN(16); | ||
47 | .bss : { | ||
48 | __bss_start = .; | ||
49 | *(.bss) | ||
50 | __bss_end = .; | ||
51 | } | ||
52 | |||
53 | . = ALIGN(16); | ||
54 | _end = .; | ||
55 | |||
56 | /DISCARD/ : { | ||
57 | *(.note*) | ||
58 | } | ||
59 | |||
60 | . = ASSERT(_end <= WAKEUP_SIZE, "Wakeup too big!"); | ||
61 | } | ||