aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/acpi/realmode
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/acpi/realmode')
-rw-r--r--arch/x86/kernel/acpi/realmode/Makefile57
-rw-r--r--arch/x86/kernel/acpi/realmode/copy.S1
-rw-r--r--arch/x86/kernel/acpi/realmode/video-bios.c1
-rw-r--r--arch/x86/kernel/acpi/realmode/video-mode.c1
-rw-r--r--arch/x86/kernel/acpi/realmode/video-vesa.c1
-rw-r--r--arch/x86/kernel/acpi/realmode/video-vga.c1
-rw-r--r--arch/x86/kernel/acpi/realmode/wakemain.c81
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.S113
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.h36
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.lds.S61
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
9targets := wakeup.bin wakeup.elf
10
11wakeup-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.
17wakeup-y += video-vga.o
18wakeup-y += video-vesa.o
19wakeup-y += video-bios.o
20
21targets += $(wakeup-y)
22
23bootsrc := $(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.
30KBUILD_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)
42KBUILD_CFLAGS += $(call cc-option, -m32)
43KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
44
45WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
46
47LDFLAGS_wakeup.elf := -T
48
49CPPFLAGS_wakeup.lds += -P -C
50
51$(obj)/wakeup.elf: $(src)/wakeup.lds $(WAKEUP_OBJS) FORCE
52 $(call if_changed,ld)
53
54OBJCOPYFLAGS_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
4static void udelay(int loops)
5{
6 while (loops--)
7 io_delay(); /* Approximately 1 us */
8}
9
10static 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. */
39static 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
64void 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
14wakeup_header:
15video_mode: .short 0 /* Video mode number */
16pmode_return: .byte 0x66, 0xea /* ljmpl */
17 .long 0 /* offset goes here */
18 .short __KERNEL_CS
19pmode_cr0: .long 0 /* Saved %cr0 */
20pmode_cr3: .long 0 /* Saved %cr3 */
21pmode_cr4: .long 0 /* Saved %cr4 */
22pmode_efer: .quad 0 /* Saved EFER */
23pmode_gdt: .quad 0
24realmode_flags: .long 0
25real_magic: .long 0
26trampoline_segment: .word 0
27signature: .long 0x51ee1111
28
29 .text
30 .globl _start
31 .code16
32wakeup_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
721:
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
801:
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
95bogus_real_magic:
961:
97 hlt
98 jmp 1b
99
100 .data
101 .balign 4
102 .globl HEAP, heap_end
103HEAP:
104 .long wakeup_heap
105heap_end:
106 .long wakeup_stack
107
108 .bss
109wakeup_heap:
110 .space 2048
111wakeup_stack:
112 .space 2048
113wakeup_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 */
13struct 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
30extern 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
9OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
10OUTPUT_ARCH(i386)
11ENTRY(_start)
12
13SECTIONS
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}