summaryrefslogtreecommitdiffstats
path: root/purgatory
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-07-27 02:36:23 -0600
committerEric W. Biederman <ebiederm@xmission.com>2006-07-27 02:36:23 -0600
commit283261998a9846019d898bc454b363e4aaf3d181 (patch)
treea4af6da4c5a2c6f7669d918c1f07dc68d6aa0ab2 /purgatory
downloadkexec-tools-283261998a9846019d898bc454b363e4aaf3d181.tar.gz
kexec-tools-1.101v1.101
- Initial import into git - initial nbi image formage support - ppc32 initial register setting fixes. - gzipped multiboot file support
Diffstat (limited to 'purgatory')
-rw-r--r--purgatory/Makefile68
-rw-r--r--purgatory/arch/alpha/Makefile7
-rw-r--r--purgatory/arch/alpha/include/limits.h57
-rw-r--r--purgatory/arch/alpha/include/stdint.h16
-rw-r--r--purgatory/arch/i386/Makefile14
-rw-r--r--purgatory/arch/i386/compat_x86_64.S100
-rw-r--r--purgatory/arch/i386/console-x86.c134
-rw-r--r--purgatory/arch/i386/entry16.S160
-rw-r--r--purgatory/arch/i386/entry32-16-debug.S195
-rw-r--r--purgatory/arch/i386/entry32-16.S160
-rw-r--r--purgatory/arch/i386/entry32.S110
-rw-r--r--purgatory/arch/i386/include/arch/debug.h316
-rw-r--r--purgatory/arch/i386/include/arch/io.h98
-rw-r--r--purgatory/arch/i386/include/limits.h58
-rw-r--r--purgatory/arch/i386/include/stdint.h16
-rw-r--r--purgatory/arch/i386/linux-entry16.S623
-rw-r--r--purgatory/arch/i386/pic.c51
-rw-r--r--purgatory/arch/i386/purgatory-x86.c40
-rw-r--r--purgatory/arch/i386/purgatory-x86.h8
-rw-r--r--purgatory/arch/i386/setup-x86.S72
-rw-r--r--purgatory/arch/i386/stack.S39
-rw-r--r--purgatory/arch/i386/timer.c10
-rw-r--r--purgatory/arch/i386/vga.c152
-rw-r--r--purgatory/arch/ia64/Makefile9
-rw-r--r--purgatory/arch/ia64/console-ia64.c5
-rw-r--r--purgatory/arch/ia64/include/limits.h57
-rw-r--r--purgatory/arch/ia64/include/stdint.h16
-rw-r--r--purgatory/arch/ia64/purgatory-ia64.c7
-rw-r--r--purgatory/arch/ia64/purgatory-ia64.h6
-rw-r--r--purgatory/arch/ppc/Makefile8
-rw-r--r--purgatory/arch/ppc/console-ppc.c5
-rw-r--r--purgatory/arch/ppc/include/limits.h58
-rw-r--r--purgatory/arch/ppc/include/stdint.h16
-rw-r--r--purgatory/arch/ppc/misc.S72
-rw-r--r--purgatory/arch/ppc/ppc_asm.h506
-rw-r--r--purgatory/arch/ppc/purgatory-ppc.c7
-rw-r--r--purgatory/arch/ppc/purgatory-ppc.h6
-rw-r--r--purgatory/arch/ppc64/Makefile7
-rw-r--r--purgatory/arch/ppc64/include/limits.h57
-rw-r--r--purgatory/arch/ppc64/include/stdint.h16
-rw-r--r--purgatory/arch/x86_64/Makefile15
-rw-r--r--purgatory/arch/x86_64/entry64-32.S134
-rw-r--r--purgatory/arch/x86_64/entry64.S100
-rw-r--r--purgatory/arch/x86_64/include/arch/debug.h317
-rw-r--r--purgatory/arch/x86_64/include/arch/io.h98
-rw-r--r--purgatory/arch/x86_64/include/limits.h57
-rw-r--r--purgatory/arch/x86_64/include/stdint.h16
-rw-r--r--purgatory/arch/x86_64/purgatory-x86_64.c12
-rw-r--r--purgatory/arch/x86_64/purgatory-x86_64.h4
-rw-r--r--purgatory/arch/x86_64/setup-x86_64.S73
-rw-r--r--purgatory/arch/x86_64/stack.S44
-rw-r--r--purgatory/include/purgatory.h8
-rw-r--r--purgatory/include/string.h10
-rw-r--r--purgatory/printf.c128
-rw-r--r--purgatory/purgatory.c47
-rw-r--r--purgatory/string.c53
56 files changed, 4478 insertions, 0 deletions
diff --git a/purgatory/Makefile b/purgatory/Makefile
new file mode 100644
index 00000000..93f58308
--- /dev/null
+++ b/purgatory/Makefile
@@ -0,0 +1,68 @@
+#
+# Purgatory (an uncomfortable intermediate state)
+# In this case the code that runs between kernels
+#
+
+# There is probably a cleaner way to do this but for now this
+# should keep us from accidentially include unsafe library functions
+# or headers.
+PCFLAGS:=-Wall -Os \
+ -I$(shell $(CC) -print-file-name=include) \
+ -Ipurgatory/include -Ipurgatory/arch/$(ARCH)/include \
+ $(CPPFLAGS)
+
+PCFLAGS += $(call cc-option, -ffreestanding)
+PCFLAGS += $(call cc-option, -fnobuiltin)
+PCFLAGS += $(call cc-option, -fnostdinc)
+PCFLAGS += $(call cc-option, -fno-zero-initialized-in-bss)
+
+PURGATORY_C_SRCS:=
+PURGATORY_C_SRCS += purgatory/purgatory.c
+PURGATORY_C_SRCS += purgatory/printf.c
+PURGATORY_C_SRCS += purgatory/string.c
+PURGATORY_S_OBJS:=
+
+include purgatory/arch/$(ARCH)/Makefile
+
+
+PURGATORY_C_OBJS:= $(patsubst %.c, $(OBJDIR)/%.o, $(PURGATORY_C_SRCS))
+PURGATORY_C_DEPS:= $(patsubst %.c, $(OBJDIR)/%.d, $(PURGATORY_C_SRCS))
+PURGATORY_S_OBJS:= $(patsubst %.S, $(OBJDIR)/%.o, $(PURGATORY_S_SRCS))
+PURGATORY_S_DEPS:= $(patsubst %.S, $(OBJDIR)/%.d, $(PURGATORY_S_SRCS))
+PURGATORY_SRCS:= $(PURGATORY_S_SRCS) $(PURGATORY_C_SRCS)
+PURGATORY_OBJS:= $(PURGATORY_S_OBJS) $(PURGATORY_C_OBJS)
+PURGATORY_DEPS:= $(PURGATORY_S_DEPS) $(PURGATORY_C_DEPS)
+PURGATORY:= $(OBJDIR)/purgatory/purgatory.ro
+
+include $(PURGATORY_DEPS)
+
+$(PURGATORY_C_DEPS): $(OBJDIR)/%.d: %.c
+ $(MKDIR) -p $(@D)
+ $(CC) $(PCFLAGS) -M $< | sed -e 's|$(patsubst %.d,%.o,$(@F))|$(patsubst %.d,%.o,$(@))|' > $@
+
+$(PURGATORY_S_DEPS): $(OBJDIR)/%.d: %.S
+ $(MKDIR) -p $(@D)
+ $(CC) $(PCFLAGS) -M $< | sed -e 's|$(patsubst %.d,%.o,$(@F))|$(patsubst %.d,%.o,$(@))|' > $@
+
+$(PURGATORY_C_OBJS): $(OBJDIR)/%.o: %.c $(OBJDIR)/%.d
+ $(MKDIR) -p $(@D)
+ $(CC) $(PCFLAGS) -o $@ -c $<
+
+$(PURGATORY_S_OBJS): $(OBJDIR)/%.o: %.S $(OBJDIR)/%.d
+ $(MKDIR) -p $(@D)
+ $(CC) $(PCFLAGS) -o $@ -c $<
+
+$(PURGATORY): $(PURGATORY_OBJS) $(UTIL_LIB)
+ $(MKDIR) -p $(@D)
+ $(LD) $(LDFLAGS) --no-undefined -e purgatory_start -r -o $@ $(PURGATORY_OBJS) $(UTIL_LIB)
+
+echo::
+ @echo "PURGATORY_C_SRCS $(PURGATORY_C_SRCS)"
+ @echo "PURGATORY_C_DEPS $(PURGATORY_C_DEPS)"
+ @echo "PURGATORY_C_OBJS $(PURGATORY_C_OBJS)"
+ @echo "PURGATORY_S_SRCS $(PURGATORY_S_SRCS)"
+ @echo "PURGATORY_S_DEPS $(PURGATORY_S_DEPS)"
+ @echo "PURGATORY_S_OBJS $(PURGATORY_S_OBJS)"
+ @echo "PURGATORY_SRCS $(PURGATORY_SRCS)"
+ @echo "PURGATORY_DEPS $(PURGATORY_DEPS)"
+ @echo "PURGATORY_OBJS $(PURGATORY_OBJS)"
diff --git a/purgatory/arch/alpha/Makefile b/purgatory/arch/alpha/Makefile
new file mode 100644
index 00000000..a626bbd7
--- /dev/null
+++ b/purgatory/arch/alpha/Makefile
@@ -0,0 +1,7 @@
+#
+# Purgatory alpha
+#
+
+PURGATORY_C_SRCS+=
+PURGATORY_S_SRCS+=
+
diff --git a/purgatory/arch/alpha/include/limits.h b/purgatory/arch/alpha/include/limits.h
new file mode 100644
index 00000000..0c6f21f9
--- /dev/null
+++ b/purgatory/arch/alpha/include/limits.h
@@ -0,0 +1,57 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 9223372036854775807L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 18446744073709551615UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/purgatory/arch/alpha/include/stdint.h b/purgatory/arch/alpha/include/stdint.h
new file mode 100644
index 00000000..2f9c592c
--- /dev/null
+++ b/purgatory/arch/alpha/include/stdint.h
@@ -0,0 +1,16 @@
+#ifndef STDINT_H
+#define STDINT_H
+
+typedef unsigned long size_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long int64_t;
+
+#endif /* STDINT_H */
diff --git a/purgatory/arch/i386/Makefile b/purgatory/arch/i386/Makefile
new file mode 100644
index 00000000..8af604c2
--- /dev/null
+++ b/purgatory/arch/i386/Makefile
@@ -0,0 +1,14 @@
+#
+# Purgatory i386
+#
+
+PURGATORY_S_SRCS+= purgatory/arch/i386/entry32-16.S
+PURGATORY_S_SRCS+= purgatory/arch/i386/entry32-16-debug.S
+PURGATORY_S_SRCS+= purgatory/arch/i386/entry32.S
+PURGATORY_S_SRCS+= purgatory/arch/i386/setup-x86.S
+PURGATORY_S_SRCS+= purgatory/arch/i386/stack.S
+PURGATORY_S_SRCS+= purgatory/arch/i386/compat_x86_64.S
+PURGATORY_C_SRCS+= purgatory/arch/i386/purgatory-x86.c
+PURGATORY_C_SRCS+= purgatory/arch/i386/console-x86.c
+PURGATORY_C_SRCS+= purgatory/arch/i386/vga.c
+PURGATORY_C_SRCS+= purgatory/arch/i386/pic.c
diff --git a/purgatory/arch/i386/compat_x86_64.S b/purgatory/arch/i386/compat_x86_64.S
new file mode 100644
index 00000000..16490853
--- /dev/null
+++ b/purgatory/arch/i386/compat_x86_64.S
@@ -0,0 +1,100 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004,2005 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ .equ MSR_K6_EFER, 0xC0000080
+ .equ EFER_LME, 0x00000100
+ .equ X86_CR4_PAE, 0x00000020
+ .equ CR0_PG, 0x80000000
+
+ .globl compat_x86_64, compat_x86_64_entry32
+ .text
+ .code64
+ .balign 16
+compat_x86_64:
+ /* Setup a temporary gdt */
+ /* This also acts as a serializing instruction ensuring
+ * my self modifying code works.
+ */
+ lgdt gdt(%rip)
+
+ /* Switch to 32bit compatiblity mode */
+ ljmp *lm_exit_addr(%rip)
+lm_exit:
+ .code32
+
+ /* Disable paging */
+ movl %cr0, %eax
+ andl $~CR0_PG, %eax
+ movl %eax, %cr0
+
+ /* Disable long mode */
+ movl $MSR_K6_EFER, %ecx
+ rdmsr
+ andl $~EFER_LME, %eax
+ wrmsr
+
+ /* Disable PAE */
+ xorl %eax, %eax
+ movl %eax, %cr4
+
+ /* load the data segments */
+ movl $0x18, %eax /* data segment */
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* set all of the registers to known values */
+ /* leave %esp alone */
+
+ xorl %eax, %eax
+ xorl %ebx, %ebx
+ xorl %ecx, %ecx
+ xorl %edx, %edx
+ xorl %esi, %esi
+ xorl %edi, %edi
+ xorl %ebp, %ebp
+
+ jmp *compat_x86_64_entry32
+
+ .section ".rodata"
+ .balign 16
+gdt: /* 0x00 unusable segment
+ * 0x08 unused
+ * so use them as the gdt ptr
+ */
+ .word gdt_end - gdt - 1
+ # A quad word pointer to the gdt with the high 32bits 0
+ .long gdt, 0
+ .word 0, 0, 0
+
+ /* 0x10 4GB flat code segment */
+ .word 0xFFFF, 0x0000, 0x9A00, 0x00CF
+ /* 0x18 4GB flat data segment */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+gdt_end:
+
+lm_exit_addr:
+ .long lm_exit
+ .long 0x10
+
+compat_x86_64_entry32:
+ .long 0
+.size compat_x86_64_entry32, . - compat_x86_64_entry32
diff --git a/purgatory/arch/i386/console-x86.c b/purgatory/arch/i386/console-x86.c
new file mode 100644
index 00000000..128f2026
--- /dev/null
+++ b/purgatory/arch/i386/console-x86.c
@@ -0,0 +1,134 @@
+#include <arch/io.h>
+#include <purgatory.h>
+
+/*
+ * VGA
+ * =============================================================================
+ */
+
+/* Simple VGA output */
+
+#define VGABASE ((void *)0xb8000)
+
+#define MAX_YPOS 25
+#define MAX_XPOS 80
+
+static int current_ypos = 1, current_xpos = 0;
+uint8_t console_vga = 0;
+
+static void putchar_vga(int ch)
+{
+ int i, k, j;
+ if (!console_vga)
+ return;
+
+ if (current_ypos >= MAX_YPOS) {
+ /* scroll 1 line up */
+ for (k = 1, j = 0; k < MAX_YPOS; k++, j++) {
+ for (i = 0; i < MAX_XPOS; i++) {
+ writew(readw(VGABASE + 2*(MAX_XPOS*k + i)),
+ VGABASE + 2*(MAX_XPOS*j + i));
+ }
+ }
+ for (i = 0; i < MAX_XPOS; i++)
+ writew(0x720, VGABASE + 2*(MAX_XPOS*j + i));
+ current_ypos = MAX_YPOS-1;
+ }
+ if (ch == '\n') {
+ current_xpos = 0;
+ current_ypos++;
+ } else if (ch != '\r') {
+ writew(((0x7 << 8) | (unsigned short) ch),
+ VGABASE + 2*(MAX_XPOS*current_ypos +
+ current_xpos++));
+ if (current_xpos >= MAX_XPOS) {
+ current_xpos = 0;
+ current_ypos++;
+ }
+ }
+}
+
+/*
+ * Serial
+ * =============================================================================
+ */
+
+/* Base Address */
+uint8_t console_serial = 0;
+uint16_t serial_base = 0x3f8; /* TTYS0 */
+uint32_t serial_baud = 0;
+
+#define XMTRDY 0x20
+
+#define DLAB 0x80
+
+#define TXR 0 /* Transmit register (WRITE) */
+#define TBR 0 /* Transmit register (WRITE) */
+#define RXR 0 /* Receive register (READ) */
+#define IER 1 /* Interrupt Enable */
+#define IIR 2 /* Interrupt ID */
+#define FCR 2 /* FIFO control */
+#define LCR 3 /* Line control */
+#define MCR 4 /* Modem control */
+#define LSR 5 /* Line Status */
+#define MSR 6 /* Modem Status */
+#define DLL 0 /* Divisor Latch Low */
+#define DLH 1 /* Divisor latch High */
+
+static void serial_init(void)
+{
+ static int initialized = 0;
+ if (!initialized) {
+ unsigned lcr;
+ outb(0x3, serial_base + LCR); /* 8n1 */
+ outb(0, serial_base + IER); /* no interrupt */
+ outb(0, serial_base + FCR); /* no fifo */
+ outb(0x3, serial_base + MCR); /* DTR + RTS */
+
+ lcr = inb(serial_base + LCR);
+ outb(lcr | DLAB, serial_base + LCR);
+ /* By default don't change the serial port baud rate */
+ if (serial_baud) {
+ unsigned divisor = 115200 / serial_baud;
+ outb(divisor & 0xff, serial_base + DLL);
+ outb((divisor >> 8) & 0xff, serial_base + DLH);
+ }
+ outb(lcr & ~DLAB, serial_base + LCR);
+ initialized = 1;
+ }
+}
+
+static void serial_tx_byte(unsigned byte)
+{
+ /* Ensure the serial port is initialized */
+ serial_init();
+
+ /* Wait until I can send a byte */
+ while((inb(serial_base + LSR) & 0x20) == 0)
+ ;
+ outb(byte, serial_base + TBR);
+ /* Wait until the byte is transmitted */
+ while(!(inb(serial_base + LSR) & 0x40))
+ ;
+}
+
+static void putchar_serial(int ch)
+{
+ if (!console_serial) {
+ return;
+ }
+ if (ch == '\n') {
+ serial_tx_byte('\r');
+ }
+ serial_tx_byte(ch);
+}
+
+/* Generic wrapper function */
+
+void putchar(int ch)
+{
+ putchar_vga(ch);
+ putchar_serial(ch);
+}
+
+
diff --git a/purgatory/arch/i386/entry16.S b/purgatory/arch/i386/entry16.S
new file mode 100644
index 00000000..c4a3dad8
--- /dev/null
+++ b/purgatory/arch/i386/entry16.S
@@ -0,0 +1,160 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef i386
+ .text
+ .globl entry16, entry16_regs
+ .arch i386
+ .balign 16
+entry16:
+ .code32
+ /* Compute where I am running at */
+ movl $entry16, %ebx
+
+ /* Fixup my real mode segment */
+ movl %ebx, %eax
+ shrl $4, %eax
+ movw %ax, 2 + realptr
+
+ /* Fixup the gdt */
+ movl %ebx, %eax
+ shll $16, %eax
+
+ movl %ebx, %ecx
+ shrl $16, %ecx
+ andl $0xff, %ecx
+
+ movl %ebx, %edx
+ andl $0xff000000, %edx
+ orl %edx, %ecx
+
+ orl %eax, 0x08 + gdt
+ orl %ecx, 0x0c + gdt
+ orl %eax, 0x10 + gdt
+ orl %ecx, 0x14 + gdt
+
+
+ /* Setup the classic BIOS interrupt table at 0x0 */
+ lidt idtptr
+
+ /* Provide us with 16bit segments that we can use */
+ lgdt gdt
+
+ /* Note we don't disable the a20 line, (this shouldn't be required)
+ * The code to do it is in kexec_test and it is a real pain.
+ * I will worry about that when I need it.
+ */
+
+ /* Load 16bit data segments, to ensure the segment limits are set */
+ movl $0x10, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* switch to 16bit mode */
+ ljmp $0x08, $1f - entry16
+1:
+ .code16
+ /* Disable Paging and protected mode */
+ /* clear the PG & PE bits of CR0 */
+ movl %cr0,%eax
+ andl $~((1 << 31)|(1<<0)),%eax
+ movl %eax,%cr0
+
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload %cs:%eip (to clear upper 16 bits of %eip).
+ */
+ ljmp *(realptr - entry16)
+3:
+ /* we are in real mode now
+ * set up the real mode segment registers : %ds, $ss, %es
+ */
+ /* Setup the data segment */
+ movw %cs, %ax
+ movw %ax, %ds
+
+ /* Load the registers */
+ movl eax - entry16, %eax
+ movl ebx - entry16, %ebx
+ movl ecx - entry16, %ecx
+ movl edx - entry16, %edx
+ movl esi - entry16, %esi
+ movl edi - entry16, %esi
+ movl esp - entry16, %esp
+ movl ebp - entry16, %ebp
+ movw es - entry16, %es
+ movw ss - entry16, %ss
+ movw fs - entry16, %fs
+ movw gs - entry16, %gs
+ movw ds - entry16, %ds
+
+ /* Jump to the kernel entrypoint */
+ ljmp %cs:*(realdest - entry16)
+
+ .balign 4
+entry16_regs:
+eax: .long 0x00000000
+ebx: .long 0x00000000
+ecx: .long 0x00000000
+edx: .long 0x00000000
+esi: .long 0x00000000
+edi: .long 0x00000000
+esp: .long 0x00000000
+ebp: .long 0x00000000
+ds: .word 0x0000
+es: .word 0x0000
+ss: .word 0x0000
+fs: .word 0x0000
+gs: .word 0x0000
+realdest:
+ip: .word 0x0000
+cs: .word 0x0000
+pad: .word 0x0000
+ .size entry16_regs, . - entry16_regs
+
+ .balign 16
+realptr:
+ .word 3b - entry16
+ .word 0x0000
+
+ .data
+ .balign 16
+
+idtptr:
+ /* 256 entry idt at 0 */
+ .word 0x400 - 1
+ .word 0, 0
+
+ .balign 16
+gdt:
+ /* 0x00 unusable segment so used as the gdt ptr */
+ .word gdt_end - gdt - 1
+ .long gdt
+ .word 0
+
+ /* 0x08 16 bit real mode code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0x00, 0x00
+
+ /* 0x10 16 bit real mode data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0x00, 0x00
+gdt_end:
diff --git a/purgatory/arch/i386/entry32-16-debug.S b/purgatory/arch/i386/entry32-16-debug.S
new file mode 100644
index 00000000..fdf70edc
--- /dev/null
+++ b/purgatory/arch/i386/entry32-16-debug.S
@@ -0,0 +1,195 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "arch/debug.h"
+
+#undef i386
+ .text
+ .globl entry16_debug, entry16_debug_regs
+ .globl entry16_debug_pre32
+ .globl entry16_debug_first32
+ .globl entry16_debug_old_first32
+ .arch i386
+ .balign 16
+entry16_debug:
+ .code32
+ /* Compute where I am running at */
+ movl $entry16_debug, %ebx
+
+ /* Fixup my real mode segment */
+ movl %ebx, %eax
+ shrl $4, %eax
+ movw %ax, 2 + realptr
+
+ /* Fixup the gdt */
+ movl %ebx, %eax
+ shll $16, %eax
+
+ movl %ebx, %ecx
+ shrl $16, %ecx
+ andl $0xff, %ecx
+
+ movl %ebx, %edx
+ andl $0xff000000, %edx
+ orl %edx, %ecx
+
+ orl %eax, 0x08 + gdt
+ orl %ecx, 0x0c + gdt
+ orl %eax, 0x10 + gdt
+ orl %ecx, 0x14 + gdt
+
+
+DEBUG('a')
+ /* Setup the classic BIOS interrupt table at 0x0 */
+ lidt idtptr
+
+DEBUG('b')
+ /* Provide us with 16bit segments that we can use */
+ lgdt gdt
+
+DEBUG('c')
+ /* Note we don't disable the a20 line, (this shouldn't be required)
+ * The code to do it is in kexec_test and it is a real pain.
+ * I will worry about that when I need it.
+ */
+
+ /* Load 16bit data segments, to ensure the segment limits are set */
+ movl $0x10, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+DEBUG('d')
+
+ /* switch to 16bit mode */
+ ljmp $0x08, $1f - entry16_debug
+1:
+ .code16
+DEBUG('e')
+ /* Disable Paging and protected mode */
+ /* clear the PG & PE bits of CR0 */
+ movl %cr0,%eax
+ andl $~((1 << 31)|(1<<0)),%eax
+ movl %eax,%cr0
+
+DEBUG('f')
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload %cs:%eip (to clear upper 16 bits of %eip).
+ */
+ ljmp *(realptr - entry16_debug)
+3:
+DEBUG('g')
+ /* we are in real mode now
+ * set up the real mode segment registers : %ds, $ss, %es
+ */
+ /* Setup the data segment */
+ movw %cs, %ax
+ movw %ax, %ds
+
+DEBUG('h')
+ /* Load the registers */
+ movl eax - entry16_debug, %eax
+ movl ebx - entry16_debug, %ebx
+ movl ecx - entry16_debug, %ecx
+ movl edx - entry16_debug, %edx
+ movl esi - entry16_debug, %esi
+ movl edi - entry16_debug, %esi
+ movl esp - entry16_debug, %esp
+ movl ebp - entry16_debug, %ebp
+ movw es - entry16_debug, %es
+ movw ss - entry16_debug, %ss
+ movw fs - entry16_debug, %fs
+ movw gs - entry16_debug, %gs
+ movw ds - entry16_debug, %ds
+
+ /* Jump to the kernel entrypoint */
+ ljmp %cs:*(realdest - entry16_debug)
+
+ .balign 4
+entry16_debug_regs:
+eax: .long 0x00000000
+ebx: .long 0x00000000
+ecx: .long 0x00000000
+edx: .long 0x00000000
+esi: .long 0x00000000
+edi: .long 0x00000000
+esp: .long 0x00000000
+ebp: .long 0x00000000
+ds: .word 0x0000
+es: .word 0x0000
+ss: .word 0x0000
+fs: .word 0x0000
+gs: .word 0x0000
+realdest:
+ip: .word 0x0000
+cs: .word 0x0000
+pad: .word 0x0000
+ .size entry16_debug_regs, . - entry16_debug_regs
+
+ .balign 16
+realptr:
+ .word 3b - entry16_debug
+ .word 0x0000
+
+ .data
+ .balign 16
+
+idtptr:
+ /* 256 entry idt at 0 */
+ .word 0x400 - 1
+ .word 0, 0
+
+gdt:
+ /* 0x00 unusable segment so used as the gdt ptr */
+ .word gdt_end - gdt - 1
+ .long gdt
+ .word 0
+
+ /* 0x08 16 bit real mode code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0x00, 0x00
+
+ /* 0x10 16 bit real mode data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0x00, 0x00
+gdt_end:
+ .size gdt, . - gdt
+
+ .text
+entry16_debug_pre32:
+ .code16
+DEBUG('i')
+ cli # no interrupts allowed !
+ movb $0x80, %al # disable NMI for bootup
+ # sequence
+ outb %al, $0x70
+ lret
+.size entry16_debug_pre32, . - entry16_debug_pre32
+
+entry16_debug_first32:
+ .code32
+DEBUG('j')
+ .byte 0xb8 /* movl $0x10000, %eax */
+entry16_debug_old_first32:
+ .long 0x100000
+ .size entry16_debug_old_first32, . - entry16_debug_old_first32
+ jmp %eax
+.size entry16_debug_first32, . - entry16_debug_first32
diff --git a/purgatory/arch/i386/entry32-16.S b/purgatory/arch/i386/entry32-16.S
new file mode 100644
index 00000000..a37fb558
--- /dev/null
+++ b/purgatory/arch/i386/entry32-16.S
@@ -0,0 +1,160 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef i386
+ .text
+ .globl entry16, entry16_regs
+ .arch i386
+ .balign 16
+entry16:
+ .code32
+ /* Compute where I am running at */
+ movl $entry16_debug, %ebx
+
+ /* Fixup my real mode segment */
+ movl %ebx, %eax
+ shrl $4, %eax
+ movw %ax, 2 + realptr
+
+ /* Fixup the gdt */
+ movl %ebx, %eax
+ shll $16, %eax
+
+ movl %ebx, %ecx
+ shrl $16, %ecx
+ andl $0xff, %ecx
+
+ movl %ebx, %edx
+ andl $0xff000000, %edx
+ orl %edx, %ecx
+
+ orl %eax, 0x08 + gdt
+ orl %ecx, 0x0c + gdt
+ orl %eax, 0x10 + gdt
+ orl %ecx, 0x14 + gdt
+
+
+ /* Setup the classic BIOS interrupt table at 0x0 */
+ lidt idtptr
+
+ /* Provide us with 16bit segments that we can use */
+ lgdt gdt
+
+ /* Note we don't disable the a20 line, (this shouldn't be required)
+ * The code to do it is in kexec_test and it is a real pain.
+ * I will worry about that when I need it.
+ */
+
+ /* Load 16bit data segments, to ensure the segment limits are set */
+ movl $0x10, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* switch to 16bit mode */
+ ljmp $0x08, $1f - entry16
+1:
+ .code16
+ /* Disable Paging and protected mode */
+ /* clear the PG & PE bits of CR0 */
+ movl %cr0,%eax
+ andl $~((1 << 31)|(1<<0)),%eax
+ movl %eax,%cr0
+
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload %cs:%eip (to clear upper 16 bits of %eip).
+ */
+ ljmp *(realptr - entry16)
+3:
+ /* we are in real mode now
+ * set up the real mode segment registers : %ds, $ss, %es
+ */
+ /* Setup the data segment */
+ movw %cs, %ax
+ movw %ax, %ds
+
+ /* Load the registers */
+ movl eax - entry16, %eax
+ movl ebx - entry16, %ebx
+ movl ecx - entry16, %ecx
+ movl edx - entry16, %edx
+ movl esi - entry16, %esi
+ movl edi - entry16, %esi
+ movl esp - entry16, %esp
+ movl ebp - entry16, %ebp
+ movw es - entry16, %es
+ movw ss - entry16, %ss
+ movw fs - entry16, %fs
+ movw gs - entry16, %gs
+ movw ds - entry16, %ds
+
+ /* Jump to the kernel entrypoint */
+ ljmp %cs:*(realdest - entry16)
+
+ .balign 4
+entry16_regs:
+eax: .long 0x00000000
+ebx: .long 0x00000000
+ecx: .long 0x00000000
+edx: .long 0x00000000
+esi: .long 0x00000000
+edi: .long 0x00000000
+esp: .long 0x00000000
+ebp: .long 0x00000000
+ds: .word 0x0000
+es: .word 0x0000
+ss: .word 0x0000
+fs: .word 0x0000
+gs: .word 0x0000
+realdest:
+ip: .word 0x0000
+cs: .word 0x0000
+pad: .word 0x0000
+ .size entry16_regs, . - entry16_regs
+
+ .balign 16
+realptr:
+ .word 3b - entry16
+ .word 0x0000
+
+ .data
+ .balign 16
+
+idtptr:
+ /* 256 entry idt at 0 */
+ .word 0x400 - 1
+ .word 0, 0
+
+ .balign 16
+gdt:
+ /* 0x00 unusable segment so used as the gdt ptr */
+ .word gdt_end - gdt - 1
+ .long gdt
+ .word 0
+
+ /* 0x08 16 bit real mode code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0x00, 0x00
+
+ /* 0x10 16 bit real mode data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0x00, 0x00
+gdt_end:
diff --git a/purgatory/arch/i386/entry32.S b/purgatory/arch/i386/entry32.S
new file mode 100644
index 00000000..f7a494f1
--- /dev/null
+++ b/purgatory/arch/i386/entry32.S
@@ -0,0 +1,110 @@
+/*
+ * purgatory: setup code
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef i386
+
+ .text
+ .arch i386
+ .globl entry32, entry32_regs
+entry32:
+ .code32
+
+ /* Setup a gdt that should that is generally usefully */
+ lgdt %cs:gdt
+
+ /* load the data segments */
+ movl $0x18, %eax /* data segment */
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* load the code segment */
+ ljmp $0x10,$1f
+1:
+
+ /* Load the registers */
+ movl eax, %eax
+ movl ecx, %ecx
+ movl edx, %edx
+ movl esi, %esi
+ movl edi, %edi
+ movl esp, %esp
+ movl ebp, %ebp
+ movl ebx, %ebx
+
+ /* Jump to the loaded image */
+ jmpl *(eip)
+
+ .section ".rodata"
+ .balign 16
+gdt:
+ /* 0x00 unusable segment so used as the gdt ptr */
+ .word gdt_end - gdt - 1
+ .long gdt
+ .word 0
+
+ /* 0x08 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+
+ /* Documented linux kernel segments */
+ /* 0x10 4GB flat code segment */
+ .word 0xFFFF, 0x0000, 0x9A00, 0x00CF
+ /* 0x18 4GB flat data segment */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+
+ /* 0x20 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x28 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x30 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x38 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x40 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x48 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x50 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x58 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+
+ /* Segments used by the 2.5.x kernel */
+ /* 0x60 4GB flat code segment */
+ .word 0xFFFF, 0x0000, 0x9A00, 0x00CF
+ /* 0x68 4GB flat data segment */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+gdt_end:
+
+ .data
+ .balign 4
+entry32_regs:
+eax: .long 0x00000000
+ebx: .long 0x00000000
+ecx: .long 0x00000000
+edx: .long 0x00000000
+esi: .long 0x00000000
+edi: .long 0x00000000
+esp: .long 0x00000000
+ebp: .long 0x00000000
+eip: .long entry16
+ .size entry32_regs, . - entry32_regs
+
diff --git a/purgatory/arch/i386/include/arch/debug.h b/purgatory/arch/i386/include/arch/debug.h
new file mode 100644
index 00000000..69deaf19
--- /dev/null
+++ b/purgatory/arch/i386/include/arch/debug.h
@@ -0,0 +1,316 @@
+/* Base Address */
+#define TTYS0_BASE 0x3f8
+/* Data */
+#define TTYS0_RBR (TTYS0_BASE+0x00)
+#define TTYS0_TBR (TTYS0_BASE+0x00)
+/* Control */
+#define TTYS0_IER (TTYS0_BASE+0x01)
+#define TTYS0_IIR (TTYS0_BASE+0x02)
+#define TTYS0_FCR (TTYS0_BASE+0x02)
+#define TTYS0_LCR (TTYS0_BASE+0x03)
+#define TTYS0_MCR (TTYS0_BASE+0x04)
+
+#define TTYS0_DLL (TTYS0_BASE+0x00)
+#define TTYS0_DLM (TTYS0_BASE+0x01)
+/* Status */
+#define TTYS0_LSR (TTYS0_BASE+0x05)
+#define TTYS0_MSR (TTYS0_BASE+0x06)
+#define TTYS0_SCR (TTYS0_BASE+0x07)
+
+#define TTYS0_BAUD 9600
+#define TTYS0_DIV (115200/TTYS0_BAUD)
+#define TTYS0_DIV_LO (TTYS0_DIV&0xFF)
+#define TTYS0_DIV_HI ((TTYS0_DIV >> 8)&0xFF)
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttyS0 baud rate
+#endif
+
+#define TTYS0_INIT \
+ /* disable interrupts */ \
+ movb $0x00, %al ; \
+ movw $TTYS0_IER, %dx ; \
+ outb %al, %dx ; \
+ ; \
+ /* enable fifos */ \
+ movb $0x01, %al ; \
+ movw $TTYS0_FCR, %dx ; \
+ outb %al, %dx ; \
+ ; \
+ /* Set Baud Rate Divisor to TTYS0_BAUD */ \
+ movw $TTYS0_LCR, %dx ; \
+ movb $0x83, %al ; \
+ outb %al, %dx ; \
+ ; \
+ movw $TTYS0_DLL, %dx ; \
+ movb $TTYS0_DIV_LO, %al ; \
+ outb %al, %dx ; \
+ ; \
+ movw $TTYS0_DLM, %dx ; \
+ movb $TTYS0_DIV_HI, %al ; \
+ outb %al, %dx ; \
+ ; \
+ movw $TTYS0_LCR, %dx ; \
+ movb $0x03, %al ; \
+ outb %al, %dx
+
+
+ /* uses: ax, dx */
+#define TTYS0_TX_AL \
+ mov %al, %ah ; \
+9: mov $TTYS0_LSR, %dx ; \
+ inb %dx, %al ; \
+ test $0x20, %al ; \
+ je 9b ; \
+ mov $TTYS0_TBR, %dx ; \
+ mov %ah, %al ; \
+ outb %al, %dx
+
+ /* uses: ax, dx */
+#define TTYS0_TX_CHAR(byte) \
+ mov byte, %al ; \
+ TTYS0_TX_AL
+
+ /* uses: eax, dx */
+#define TTYS0_TX_HEX32(lword) \
+ mov lword, %eax ; \
+ shr $28, %eax ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $24, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $20, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $16, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $12, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $8, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $4, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL
+
+ /* uses: rax, dx */
+#define TTYS0_TX_HEX64(lword) \
+ mov lword, %rax ; \
+ shr $60, %rax ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $56, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $52, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $48, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $44, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $40, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $36, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $32, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $28, %rax ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $24, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $20, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $16, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $12, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $8, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $4, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL
+
+
+#define DEBUG(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x); TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_TX_HEX64(x) TTYS0_TX_HEX64(x); TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
diff --git a/purgatory/arch/i386/include/arch/io.h b/purgatory/arch/i386/include/arch/io.h
new file mode 100644
index 00000000..13ad8871
--- /dev/null
+++ b/purgatory/arch/i386/include/arch/io.h
@@ -0,0 +1,98 @@
+#ifndef ARCH_IO_H
+#define ARCH_IO_H
+
+#include <stdint.h>
+/* Helper functions for directly doing I/O */
+
+extern inline uint8_t inb(uint16_t port)
+{
+ uint8_t result;
+
+ __asm__ __volatile__ (
+ "inb %w1,%0"
+ :"=a" (result)
+ :"Nd" (port));
+ return result;
+}
+
+extern inline uint16_t inw(uint16_t port)
+{
+ uint16_t result;
+
+ __asm__ __volatile__ (
+ "inw %w1,%0"
+ :"=a" (result)
+ :"Nd" (port));
+ return result;
+}
+
+extern inline uint32_t inl(uint32_t port)
+{
+ uint32_t result;
+
+ __asm__ __volatile__ (
+ "inl %w1,%0"
+ :"=a" (result)
+ :"Nd" (port));
+ return result;
+}
+
+extern inline void outb (uint8_t value, uint16_t port)
+{
+ __asm__ __volatile__ (
+ "outb %b0,%w1"
+ :
+ :"a" (value), "Nd" (port));
+}
+
+extern inline void outw (uint16_t value, uint16_t port)
+{
+ __asm__ __volatile__ (
+ "outw %w0,%w1"
+ :
+ :"a" (value), "Nd" (port));
+}
+
+extern inline void outl (uint32_t value, uint16_t port)
+{
+ __asm__ __volatile__ (
+ "outl %0,%w1"
+ :
+ :"a" (value), "Nd" (port));
+}
+
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+
+static inline unsigned char readb(const volatile void *addr)
+{
+ return *(volatile unsigned char *) addr;
+}
+static inline unsigned short readw(const volatile void *addr)
+{
+ return *(volatile unsigned short *) addr;
+}
+static inline unsigned int readl(const volatile void *addr)
+{
+ return *(volatile unsigned int *) addr;
+}
+
+static inline void writeb(unsigned char b, volatile void *addr)
+{
+ *(volatile unsigned char *) addr = b;
+}
+static inline void writew(unsigned short b, volatile void *addr)
+{
+ *(volatile unsigned short *) addr = b;
+}
+static inline void writel(unsigned int b, volatile void *addr)
+{
+ *(volatile unsigned int *) addr = b;
+}
+
+#endif /* ARCH_IO_H */
diff --git a/purgatory/arch/i386/include/limits.h b/purgatory/arch/i386/include/limits.h
new file mode 100644
index 00000000..d5a5a02c
--- /dev/null
+++ b/purgatory/arch/i386/include/limits.h
@@ -0,0 +1,58 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 2147483647L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 4294967295UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/purgatory/arch/i386/include/stdint.h b/purgatory/arch/i386/include/stdint.h
new file mode 100644
index 00000000..79262c20
--- /dev/null
+++ b/purgatory/arch/i386/include/stdint.h
@@ -0,0 +1,16 @@
+#ifndef STDINT_H
+#define STDINT_H
+
+typedef unsigned long size_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int64_t;
+
+#endif /* STDINT_H */
diff --git a/purgatory/arch/i386/linux-entry16.S b/purgatory/arch/i386/linux-entry16.S
new file mode 100644
index 00000000..f366a11f
--- /dev/null
+++ b/purgatory/arch/i386/linux-entry16.S
@@ -0,0 +1,623 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if 1
+#define TTYS0_BASE 0x3f8
+#define TTYS0_RBR (TTYS0_BASE+0x00)
+#define TTYS0_TBR TTYS0_RBR
+#define TTYS0_LSR (TTYS0_BASE+0x05)
+
+
+ /* uses: ax, dx */
+#define TTYS0_TX_AL \
+ mov %al, %ah ; \
+9: mov $TTYS0_LSR, %dx ; \
+ inb %dx, %al ; \
+ test $0x20, %al ; \
+ je 9b ; \
+ mov $TTYS0_TBR, %dx ; \
+ mov %ah, %al ; \
+ outb %al, %dx ; \
+9: mov $TTYS0_LSR, %dx ; \
+ inb %dx, %al ; \
+ test $0x40, %al ; \
+ jz 9b
+
+
+
+ /* uses: ax, dx */
+#define TTYS0_TX_CHAR(byte) \
+ mov byte, %al ; \
+ TTYS0_TX_AL
+
+ /* uses: ax, dx */
+#define TTYS0_TX_HEX32(lword) \
+ mov lword, %eax ; \
+ shr $28, %eax ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $24, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $20, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $16, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $12, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $8, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $4, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL
+
+
+#define DEBUG(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#else
+#define DEBUG(x)
+#define DEBUG_TX_HEX32(x)
+#endif
+
+#undef i386
+ .text
+ .globl entry16, entry16_regs
+ .arch i386
+ .balign 16
+entry16:
+ .code32
+
+DEBUG('a')
+ /* Setup the classic BIOS interrupt table at 0x0 */
+ lidt idtptr
+
+DEBUG('b')
+ /* Provide us with 16bit segments that we can use */
+ lgdt gdt
+
+DEBUG('c')
+ /* Note we don't disable the a20 line, (this shouldn't be required)
+ * The code to do it is in kexec_test and it is a real pain.
+ * I will worry about that when I need it.
+ */
+
+ /* Load 16bit data segments, to ensure the segment limits are set */
+ movl $0x10, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+DEBUG('d')
+
+ /* switch to 16bit mode */
+ ljmp $0x08, $1f - entry16
+1:
+ .code16
+DEBUG('e')
+ /* Disable Paging and protected mode */
+ /* clear the PG & PE bits of CR0 */
+ movl %cr0,%eax
+ andl $~((1 << 31)|(1<<0)),%eax
+ movl %eax,%cr0
+
+DEBUG('f')
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload %cs:%eip (to clear upper 16 bits of %eip).
+ */
+ ljmp *(realptr - entry16)
+3:
+DEBUG('g')
+ /* we are in real mode now
+ * set up the real mode segment registers : %ds, $ss, %es
+ */
+ /* Setup the data segment */
+ movw %cs, %ax
+ movw %ax, %ds
+
+DEBUG('h')
+ /* Load the registers */
+ movl eax - entry16, %eax
+ movl ebx - entry16, %ebx
+ movl ecx - entry16, %ecx
+ movl edx - entry16, %edx
+ movl esi - entry16, %esi
+ movl edi - entry16, %esi
+ movl esp - entry16, %esp
+ movl ebp - entry16, %ebp
+ movw es - entry16, %es
+ movw ss - entry16, %ss
+ movw fs - entry16, %fs
+ movw gs - entry16, %gs
+ movw ds - entry16, %ds
+
+ /* Jump to the kernel entrypoint */
+ ljmp %cs:*(realdest - entry16)
+
+ .balign 4
+entry16_regs:
+eax: .long 0x00000000
+ebx: .long 0x00000000
+ecx: .long 0x00000000
+edx: .long 0x00000000
+esi: .long 0x00000000
+edi: .long 0x00000000
+esp: .long 0x00000000
+ebp: .long 0x00000000
+ds: .word 0x0000
+es: .word 0x0000
+ss: .word 0x0000
+fs: .word 0x0000
+gs: .word 0x0000
+realdest:
+ip: .word 0x0000
+cs: .word 0x0000
+ .size entry16_regs, . - entry16_regs
+
+ .balign 16
+realptr:
+ .word 3b - entry16
+ .word 0x0000
+
+ .data
+ .balign 4
+
+idtptr:
+ /* 256 entry idt at 0 */
+ .word 0x400 - 1
+ .word 0, 0
+
+gdt:
+ /* 0x00 unusable segment so used as the gdt ptr */
+ .word gdt_end - gdt - 1
+ .long gdt
+ .word 0
+
+ /* 0x08 16 bit real mode code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0x00, 0x00
+
+ /* 0x10 16 bit real mode data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0x00, 0x00
+gdt_end:
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if 1
+#define TTYS0_BASE 0x3f8
+#define TTYS0_RBR (TTYS0_BASE+0x00)
+#define TTYS0_TBR TTYS0_RBR
+#define TTYS0_LSR (TTYS0_BASE+0x05)
+
+
+ /* uses: ax, dx */
+#define TTYS0_TX_AL \
+ mov %al, %ah ; \
+9: mov $TTYS0_LSR, %dx ; \
+ inb %dx, %al ; \
+ test $0x20, %al ; \
+ je 9b ; \
+ mov $TTYS0_TBR, %dx ; \
+ mov %ah, %al ; \
+ outb %al, %dx ; \
+9: mov $TTYS0_LSR, %dx ; \
+ inb %dx, %al ; \
+ test $0x40, %al ; \
+ jz 9b
+
+
+
+ /* uses: ax, dx */
+#define TTYS0_TX_CHAR(byte) \
+ mov byte, %al ; \
+ TTYS0_TX_AL
+
+ /* uses: ax, dx */
+#define TTYS0_TX_HEX32(lword) \
+ mov lword, %eax ; \
+ shr $28, %eax ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $24, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $20, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $16, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $12, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $8, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $4, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL
+
+
+#define DEBUG(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#else
+#define DEBUG(x)
+#define DEBUG_TX_HEX32(x)
+#endif
+
+.data
+ .globl setup16_debug_start, setup16_debug_end, setup16_debug_size, setup16_debug_align
+ .globl setup16_debug_regs
+ .globl setup16_debug_kernel_pre_protected
+ .globl setup16_debug_first_code32
+ .globl setup16_debug_old_code32
+setup16_debug_start:
+_reloc = .
+ .balign 16
+ .code32
+DEBUG('a')
+ /* Compute where I am running at */
+ call 1f
+1: popl %ebx
+ subl $(1b - _reloc), %ebx
+
+ /* Remember where I am running at */
+ movl %ebx, location - _reloc(%ebx)
+
+DEBUG('b')
+ /* Fixup my real mode segment */
+ movl %ebx, %eax
+ shrl $4, %eax
+ movw %ax, 2 + realptr - _reloc(%ebx)
+
+DEBUG('c')
+ /* Fixup the gdt */
+ movl %ebx, %eax
+ shll $16, %eax
+
+ movl %ebx, %ecx
+ shrl $16, %ecx
+ andl $0xff, %ecx
+
+ movl %ebx, %edx
+ andl $0xff000000, %edx
+ orl %edx, %ecx
+
+ addl %ebx, gdtaddr - _reloc(%ebx)
+ addl %ebx, debug_gdtaddr - _reloc(%ebx)
+ orl %eax, 0x08 + gdt - _reloc(%ebx)
+ orl %ecx, 0x0c + gdt - _reloc(%ebx)
+ orl %eax, 0x10 + gdt - _reloc(%ebx)
+ orl %ecx, 0x14 + gdt - _reloc(%ebx)
+
+
+
+DEBUG('d')
+ /* Setup the classic BIOS interrupt table at 0x0 */
+ lidt idtptr - _reloc(%ebx)
+
+ /* Provide us with 16bit segments that we can use */
+ lgdt gdtptr - _reloc(%ebx)
+
+ /* Note we don't disable the a20 line, (this shouldn't be required)
+ * The code to do it is in kexec_test and it is a real pain.
+ * I will worry about that when I need it.
+ */
+
+ /* Load 16bit data segments, to ensure the segment limits are set */
+ movl $0x10, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* switch to 16bit mode */
+
+ ljmp $0x08, $2f - _reloc
+2:
+ .code16
+DEBUG('e')
+ /* Disable Paging and protected mode */
+ /* clear the PG & PE bits of CR0 */
+ movl %cr0,%eax
+ andl $~((1 << 31)|(1<<0)),%eax
+ movl %eax,%cr0
+
+DEBUG('f')
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload %cs:%eip (to clear upper 16 bits of %eip).
+ */
+ ljmp *(realptr - _reloc)
+3:
+DEBUG('g')
+ /* we are in real mode now
+ * set up the real mode segment registers : %ds, $ss, %es
+ */
+ /* Setup the data segment */
+ movw %cs, %ax
+ movw %ax, %ds
+
+DEBUG('h')
+ /* Load the registers */
+ movl eax - _reloc, %eax
+ movl ebx - _reloc, %ebx
+ movl ecx - _reloc, %ecx
+ movl edx - _reloc, %edx
+ movl esi - _reloc, %esi
+ movl edi - _reloc, %esi
+ movl esp - _reloc, %esp
+ movl ebp - _reloc, %ebp
+ movw es - _reloc, %es
+ movw ss - _reloc, %ss
+ movw fs - _reloc, %fs
+ movw gs - _reloc, %gs
+ movw ds - _reloc, %ds
+
+ /* Jump to the kernel entrypoint */
+ ljmp %cs:*(realdest - _reloc)
+
+setup16_debug_regs:
+eax: .long 0x00000000
+ebx: .long 0x00000000
+ecx: .long 0x00000000
+edx: .long 0x00000000
+esi: .long 0x00000000
+edi: .long 0x00000000
+esp: .long 0x00000000
+ebp: .long 0x00000000
+ds: .word 0x0000
+es: .word 0x0000
+ss: .word 0x0000
+fs: .word 0x0000
+gs: .word 0x0000
+realdest:
+ip: .word 0x0000
+cs: .word 0x0000
+
+ .balign 16
+realptr:
+ .word 3b - _reloc
+ .word 0x0000
+
+idtptr:
+ /* 256 entry idt at 0 */
+ .word 0x400 - 1
+ .word 0, 0
+
+gdtptr:
+ .word gdt_end - gdt - 1
+gdtaddr:
+ .long gdt - _reloc
+
+gdt:
+ /* dummy */
+ .word 0, 0, 0, 0
+
+ /* 16 bit real mode code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0x00, 0x00
+
+ /* 16 bit real mode data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0x00, 0x00
+gdt_end:
+
+debug_gdt:
+ /* 0x00 */
+ .word debug_gdt_end - debug_gdt - 1
+debug_gdtaddr:
+ .long debug_gdt - _reloc
+ .word 0
+
+ /* 0x08 */
+ .word 0, 0, 0, 0 /* Nothing in the first gdt entry */
+
+ /* 0x10 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
+ .word 0xFFFF, 0x00, 0x9A00, 0x00CF
+ /* 0x18 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+
+
+ /* 0x20 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
+ .word 0xFFFF, 0x00, 0x9A00, 0x00CF
+ /* 0x28 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+
+
+ /* 0x30 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
+ .word 0xFFFF, 0x00, 0x9A00, 0x00CF
+ /* 0x38 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+
+
+ /* 0x40 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
+ .word 0xFFFF, 0x00, 0x9A00, 0x00CF
+ /* 0x48 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+
+
+ /* 0x50 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
+ .word 0xFFFF, 0x00, 0x9A00, 0x00CF
+ /* 0x58 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+
+
+ /* 0x60 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
+ .word 0xFFFF, 0x00, 0x9A00, 0x00CF
+ /* 0x68 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+debug_gdt_end:
+
+
+setup16_debug_kernel_pre_protected:
+ .code16
+ DEBUG('i')
+ cli # no interrupts allowed !
+ movb $0x80, %al # disable NMI for bootup
+ # sequence
+ outb %al, $0x70
+ lret
+setup16_debug_first_code32:
+ .code32
+ .byte 0xbf /* movl $0x12345678, %edi */
+location:
+ .long 0x12345678
+ DEBUG('j')
+ .byte 0xb8 /* movl $0x10000, %eax */
+setup16_debug_old_code32:
+ .long 0x10000
+ jmp %eax
+setup16_debug_end:
+setup16_debug_size:
+ .long setup16_debug_end - setup16_debug_start
+setup16_debug_align:
+ .long 16
diff --git a/purgatory/arch/i386/pic.c b/purgatory/arch/i386/pic.c
new file mode 100644
index 00000000..1b73ea9a
--- /dev/null
+++ b/purgatory/arch/i386/pic.c
@@ -0,0 +1,51 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <arch/io.h>
+#include <purgatory.h>
+#include "purgatory-x86.h"
+
+
+void x86_setup_legacy_pic(void)
+{
+ /* Load the legacy dos settings into the 8259A pic */
+ outb(0xff, 0x21); /* mask all of 8259A-1 */
+ outb(0xff, 0xa1); /* mask all of 8259A-2 */
+
+ outb(0x11, 0x20); /* ICW1: select 8259A-1 init */
+ outb(0x11, 0x80); /* A short delay */
+
+ outb(0x08, 0x21); /* ICW2: 8259A-1 IR0-7 mappend to 0x8-0xf */
+ outb(0x08, 0x80); /* A short delay */
+
+ outb(0x01, 0x21); /* Normal 8086 auto EOI mode */
+ outb(0x01, 0x80); /* A short delay */
+
+ outb(0x11, 0xa0); /* ICW1: select 8259A-2 init */
+ outb(0x11, 0x80); /* A short delay */
+
+ outb(0x70, 0xa1); /* ICW2: 8259A-2 IR0-7 mappend to 0x70-0x77 */
+ outb(0x70, 0x80); /* A short delay */
+
+ outb(0x01, 0xa1); /* Normal 8086 auto EOI mode */
+ outb(0x01, 0x80); /* A short delay */
+
+ outb(0x00, 0x21); /* Unmask all of 8259A-1 */
+ outb(0x00, 0xa1); /* Unmask all of 8259A-2 */
+}
+
diff --git a/purgatory/arch/i386/purgatory-x86.c b/purgatory/arch/i386/purgatory-x86.c
new file mode 100644
index 00000000..442358a2
--- /dev/null
+++ b/purgatory/arch/i386/purgatory-x86.c
@@ -0,0 +1,40 @@
+#include <arch/io.h>
+#include <purgatory.h>
+#include "purgatory-x86.h"
+
+/*
+ * CPU
+ * =============================================================================
+ */
+
+void x86_setup_cpu(void)
+{
+#if 0
+ /* This code is only needed for old versions of the kexec kernel patch.
+ * While it is still a good idea doing this unconditionally breaks
+ * on older cpus that did not implemented cr4.
+ * So this code is disabled for now. If this is revisited
+ * I first need to detect cpuid support and then use cpuid
+ * to conditionally change newer cpu registers.
+ */
+ /* clear special bits in %cr4 */
+ asm volatile(
+ "movl %0, %%eax\n\t"
+ "movl %%eax, %%cr4\n\t"
+ : /* outputs */
+ : "r" (0)
+ );
+#endif
+}
+
+uint8_t reset_vga = 0;
+uint8_t legacy_timer = 0;
+uint8_t legacy_pic = 0;
+
+void setup_arch(void)
+{
+ x86_setup_cpu();
+ if (reset_vga) x86_reset_vga();
+ if (legacy_pic) x86_setup_legacy_pic();
+ /* if (legacy_timer) x86_setup_legacy_timer(); */
+}
diff --git a/purgatory/arch/i386/purgatory-x86.h b/purgatory/arch/i386/purgatory-x86.h
new file mode 100644
index 00000000..4178b379
--- /dev/null
+++ b/purgatory/arch/i386/purgatory-x86.h
@@ -0,0 +1,8 @@
+#ifndef PURGATORY_X86_H
+#define PURGATORY_X86_H
+
+void x86_reset_vga(void);
+void x86_setup_legacy_pic(void);
+void x86_setup_legacy_timer(void);
+
+#endif /* PURGATORY_X86_H */
diff --git a/purgatory/arch/i386/setup-x86.S b/purgatory/arch/i386/setup-x86.S
new file mode 100644
index 00000000..f0719d4c
--- /dev/null
+++ b/purgatory/arch/i386/setup-x86.S
@@ -0,0 +1,72 @@
+/*
+ * purgatory: setup code
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#undef i386
+
+ .text
+ .arch i386
+ .globl purgatory_start
+purgatory_start:
+ .code32
+
+ /* Load a gdt so I know what the segment registers are */
+ lgdt %cs:gdt
+
+ /* load the data segments */
+ movl $0x08, %eax /* data segment */
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* load the code segment */
+ ljmp $0x10,$1f
+1:
+
+ /* Setup a stack */
+ movl $lstack_end, %esp
+
+ /* Call the C code */
+ call purgatory
+ jmp entry32
+
+ .section ".rodata"
+ .balign 16
+gdt:
+ /* 0x00 unusable segment so used as the gdt ptr */
+ .word gdt_end - gdt - 1
+ .long gdt
+ .word 0
+
+ /* 0x8 4GB flat data segment */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+
+ /* 0x10 4GB flat code segment */
+ .word 0xFFFF, 0x0000, 0x9A00, 0x00CF
+gdt_end:
+
+ /* A stack for the purgatory code */
+ .bss
+ .balign 4096
+lstack:
+ .skip 4096
+lstack_end:
+
diff --git a/purgatory/arch/i386/stack.S b/purgatory/arch/i386/stack.S
new file mode 100644
index 00000000..a597b0f1
--- /dev/null
+++ b/purgatory/arch/i386/stack.S
@@ -0,0 +1,39 @@
+/*
+ * purgatory: stack
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /* A stack for the loaded kernel.
+ * Seperate and in the data section so it can be prepopulated.
+ */
+ .data
+ .globl stack, stack_end
+ .globl stack_arg32_1, stack_arg32_2, stack_arg32_3 ,stack_arg32_4
+ .globl stack_arg32_5, stack_arg32_6, stack_arg32_7 ,stack_arg32_8
+ .balign 4096
+stack:
+ .skip 4096 - (8*4)
+stack_arg32_8: .long 0 ; .size stack_arg32_8, 4
+stack_arg32_7: .long 0 ; .size stack_arg32_7, 4
+stack_arg32_6: .long 0 ; .size stack_arg32_6, 4
+stack_arg32_5: .long 0 ; .size stack_arg32_5, 4
+stack_arg32_4: .long 0 ; .size stack_arg32_4, 4
+stack_arg32_3: .long 0 ; .size stack_arg32_3, 4
+stack_arg32_2: .long 0 ; .size stack_arg32_2, 4
+stack_arg32_1: .long 0 ; .size stack_arg32_1, 4
+stack_end:
+
diff --git a/purgatory/arch/i386/timer.c b/purgatory/arch/i386/timer.c
new file mode 100644
index 00000000..dec59384
--- /dev/null
+++ b/purgatory/arch/i386/timer.c
@@ -0,0 +1,10 @@
+#include <arch/io.h>
+#include <purgatory.h>
+#include "purgatory-x86.h"
+
+
+void x86_setup_legacy_timer(void)
+{
+ /* Load the legacy timer settings into the 8254 pit */
+}
+
diff --git a/purgatory/arch/i386/vga.c b/purgatory/arch/i386/vga.c
new file mode 100644
index 00000000..effa8ff3
--- /dev/null
+++ b/purgatory/arch/i386/vga.c
@@ -0,0 +1,152 @@
+#include <arch/io.h>
+#include <purgatory.h>
+#include "purgatory-x86.h"
+
+/* Crudely reset a VGA card to text mode 3, by writing plausible default */
+/* values into its registers. */
+/* Tim Deegan (tjd21 at cl.cam.ac.uk), March 2003 */
+/* Based on Keir Fraser's start-of-day reset code from the Xen hypervisor */
+/* Converted from Assembly 20 December 2004 -- Eric Biederman */
+
+void x86_reset_vga(void)
+{
+ /* Hello */
+ inb(0x3da);
+ outb(0, 0x3c0);
+
+ /* Sequencer registers */
+ outw(0x0300, 0x3c4);
+ outw(0x0001, 0x3c4);
+ outw(0x0302, 0x3c4);
+ outw(0x0003, 0x3c4);
+ outw(0x0204, 0x3c4);
+
+ /* Ensure CRTC regs 0-7 are unlocked by clearing bit 7 of CRTC[17] */
+ outw(0x0e11, 0x3d4);
+ /* CRTC registers */
+ outw(0x5f00, 0x3d4);
+ outw(0x4f01, 0x3d4);
+ outw(0x5002, 0x3d4);
+ outw(0x8203, 0x3d4);
+ outw(0x5504, 0x3d4);
+ outw(0x8105, 0x3d4);
+ outw(0xbf06, 0x3d4);
+ outw(0x1f07, 0x3d4);
+ outw(0x0008, 0x3d4);
+ outw(0x4f09, 0x3d4);
+ outw(0x200a, 0x3d4);
+ outw(0x0e0b, 0x3d4);
+ outw(0x000c, 0x3d4);
+ outw(0x000d, 0x3d4);
+ outw(0x010e, 0x3d4);
+ outw(0xe00f, 0x3d4);
+ outw(0x9c10, 0x3d4);
+ outw(0x8e11, 0x3d4);
+ outw(0x8f12, 0x3d4);
+ outw(0x2813, 0x3d4);
+ outw(0x1f14, 0x3d4);
+ outw(0x9615, 0x3d4);
+ outw(0xb916, 0x3d4);
+ outw(0xa317, 0x3d4);
+ outw(0xff18, 0x3d4);
+
+ /* Graphic registers */
+ outw(0x0000, 0x3ce);
+ outw(0x0001, 0x3ce);
+ outw(0x0002, 0x3ce);
+ outw(0x0003, 0x3ce);
+ outw(0x0004, 0x3ce);
+ outw(0x1005, 0x3ce);
+ outw(0x0e06, 0x3ce);
+ outw(0x0007, 0x3ce);
+ outw(0xff08, 0x3ce);
+
+ /* Attribute registers */
+ inb(0x3da);
+ outb(0x00, 0x3c0);
+ outb(0x00, 0x3c0);
+
+ inb(0x3da);
+ outb(0x01, 0x3c0);
+ outb(0x01, 0x3c0);
+
+ inb(0x3da);
+ outb(0x02, 0x3c0);
+ outb(0x02, 0x3c0);
+
+ inb(0x3da);
+ outb(0x03, 0x3c0);
+ outb(0x03, 0x3c0);
+
+ inb(0x3da);
+ outb(0x04, 0x3c0);
+ outb(0x04, 0x3c0);
+
+ inb(0x3da);
+ outb(0x05, 0x3c0);
+ outb(0x05, 0x3c0);
+
+ inb(0x3da);
+ outb(0x06, 0x3c0);
+ outb(0x14, 0x3c0);
+
+ inb(0x3da);
+ outb(0x07, 0x3c0);
+ outb(0x07, 0x3c0);
+
+ inb(0x3da);
+ outb(0x08, 0x3c0);
+ outb(0x38, 0x3c0);
+
+ inb(0x3da);
+ outb(0x09, 0x3c0);
+ outb(0x39, 0x3c0);
+
+ inb(0x3da);
+ outb(0x0a, 0x3c0);
+ outb(0x3a, 0x3c0);
+
+ inb(0x3da);
+ outb(0x0b, 0x3c0);
+ outb(0x3b, 0x3c0);
+
+ inb(0x3da);
+ outb(0x0c, 0x3c0);
+ outb(0x3c, 0x3c0);
+
+ inb(0x3da);
+ outb(0x0d, 0x3c0);
+ outb(0x3d, 0x3c0);
+
+ inb(0x3da);
+ outb(0x0e, 0x3c0);
+ outb(0x3e, 0x3c0);
+
+ inb(0x3da);
+ outb(0x0f, 0x3c0);
+ outb(0x3f, 0x3c0);
+
+ inb(0x3da);
+ outb(0x10, 0x3c0);
+ outb(0x0c, 0x3c0);
+
+ inb(0x3da);
+ outb(0x11, 0x3c0);
+ outb(0x00, 0x3c0);
+
+ inb(0x3da);
+ outb(0x12, 0x3c0);
+ outb(0x0f, 0x3c0);
+
+ inb(0x3da);
+ outb(0x13, 0x3c0);
+ outb(0x08, 0x3c0);
+
+ inb(0x3da);
+ outb(0x14, 0x3c0);
+ outb(0x00, 0x3c0);
+
+ /* Goodbye */
+ inb(0x3da);
+ outb(0x20, 0x3c0);
+}
diff --git a/purgatory/arch/ia64/Makefile b/purgatory/arch/ia64/Makefile
new file mode 100644
index 00000000..8ba596ee
--- /dev/null
+++ b/purgatory/arch/ia64/Makefile
@@ -0,0 +1,9 @@
+#
+# Purgatory ia64
+#
+
+PURGATORY_S_SRCS+=
+PURGATORY_C_SRCS+= purgatory/arch/ia64/purgatory-ia64.c
+PURGATORY_C_SRCS+= purgatory/arch/ia64/console-ia64.c
+PURGATORY_C_SRCS+=
+
diff --git a/purgatory/arch/ia64/console-ia64.c b/purgatory/arch/ia64/console-ia64.c
new file mode 100644
index 00000000..389b7be0
--- /dev/null
+++ b/purgatory/arch/ia64/console-ia64.c
@@ -0,0 +1,5 @@
+#include <purgatory.h>
+void putchar(int ch)
+{
+ /* Nothing for now */
+}
diff --git a/purgatory/arch/ia64/include/limits.h b/purgatory/arch/ia64/include/limits.h
new file mode 100644
index 00000000..0c6f21f9
--- /dev/null
+++ b/purgatory/arch/ia64/include/limits.h
@@ -0,0 +1,57 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 9223372036854775807L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 18446744073709551615UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/purgatory/arch/ia64/include/stdint.h b/purgatory/arch/ia64/include/stdint.h
new file mode 100644
index 00000000..2f9c592c
--- /dev/null
+++ b/purgatory/arch/ia64/include/stdint.h
@@ -0,0 +1,16 @@
+#ifndef STDINT_H
+#define STDINT_H
+
+typedef unsigned long size_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long int64_t;
+
+#endif /* STDINT_H */
diff --git a/purgatory/arch/ia64/purgatory-ia64.c b/purgatory/arch/ia64/purgatory-ia64.c
new file mode 100644
index 00000000..c10cbeaf
--- /dev/null
+++ b/purgatory/arch/ia64/purgatory-ia64.c
@@ -0,0 +1,7 @@
+#include <purgatory.h>
+#include "purgatory-ia64.h"
+
+void setup_arch(void)
+{
+ /* Nothing for now */
+}
diff --git a/purgatory/arch/ia64/purgatory-ia64.h b/purgatory/arch/ia64/purgatory-ia64.h
new file mode 100644
index 00000000..773e3c00
--- /dev/null
+++ b/purgatory/arch/ia64/purgatory-ia64.h
@@ -0,0 +1,6 @@
+#ifndef PURGATORY_IA64_H
+#define PURGATORY_IA64_H
+
+/* nothing yet */
+
+#endif /* PURGATORY_IA64_H */
diff --git a/purgatory/arch/ppc/Makefile b/purgatory/arch/ppc/Makefile
new file mode 100644
index 00000000..4ce40fea
--- /dev/null
+++ b/purgatory/arch/ppc/Makefile
@@ -0,0 +1,8 @@
+#
+# Purgatory ppc
+#
+
+PURGATORY_S_SRCS+= purgatory/arch/ppc/misc.S
+PURGATORY_C_SRCS+= purgatory/arch/ppc/purgatory-ppc.c
+PURGATORY_C_SRCS+= purgatory/arch/ppc/console-ppc.c
+
diff --git a/purgatory/arch/ppc/console-ppc.c b/purgatory/arch/ppc/console-ppc.c
new file mode 100644
index 00000000..389b7be0
--- /dev/null
+++ b/purgatory/arch/ppc/console-ppc.c
@@ -0,0 +1,5 @@
+#include <purgatory.h>
+void putchar(int ch)
+{
+ /* Nothing for now */
+}
diff --git a/purgatory/arch/ppc/include/limits.h b/purgatory/arch/ppc/include/limits.h
new file mode 100644
index 00000000..d5a5a02c
--- /dev/null
+++ b/purgatory/arch/ppc/include/limits.h
@@ -0,0 +1,58 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 2147483647L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 4294967295UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/purgatory/arch/ppc/include/stdint.h b/purgatory/arch/ppc/include/stdint.h
new file mode 100644
index 00000000..79262c20
--- /dev/null
+++ b/purgatory/arch/ppc/include/stdint.h
@@ -0,0 +1,16 @@
+#ifndef STDINT_H
+#define STDINT_H
+
+typedef unsigned long size_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int64_t;
+
+#endif /* STDINT_H */
diff --git a/purgatory/arch/ppc/misc.S b/purgatory/arch/ppc/misc.S
new file mode 100644
index 00000000..b0a54860
--- /dev/null
+++ b/purgatory/arch/ppc/misc.S
@@ -0,0 +1,72 @@
+/*
+ * This file contains miscellaneous low-level functions.
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * Rewrittten to work with /sbin/kexec 20 December 2004 Eric Biederman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include "ppc_asm.h"
+
+ .text
+
+/*
+ * Extended precision shifts.
+ *
+ * Updated to be valid for shift counts from 0 to 63 inclusive.
+ * -- Gabriel
+ *
+ * R3/R4 has 64 bit value
+ * R5 has shift count
+ * result in R3/R4
+ *
+ * ashrdi3: arithmetic right shift (sign propagation)
+ * lshrdi3: logical right shift
+ * ashldi3: left shift
+ */
+ .globl __ashrdi3
+__ashrdi3:
+ subfic r6,r5,32
+ srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
+ addi r7,r5,32 # could be xori, or addi with -32
+ slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
+ rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0
+ sraw r7,r3,r7 # t2 = MSW >> (count-32)
+ or r4,r4,r6 # LSW |= t1
+ slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2
+ sraw r3,r3,r5 # MSW = MSW >> count
+ or r4,r4,r7 # LSW |= t2
+ blr
+
+ .globl __ashldi3
+__ashldi3:
+ subfic r6,r5,32
+ slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count
+ addi r7,r5,32 # could be xori, or addi with -32
+ srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count)
+ slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32)
+ or r3,r3,r6 # MSW |= t1
+ slw r4,r4,r5 # LSW = LSW << count
+ or r3,r3,r7 # MSW |= t2
+ blr
+
+ .globl __lshrdi3
+__lshrdi3:
+ subfic r6,r5,32
+ srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
+ addi r7,r5,32 # could be xori, or addi with -32
+ slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
+ srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32)
+ or r4,r4,r6 # LSW |= t1
+ srw r3,r3,r5 # MSW = MSW >> count
+ or r4,r4,r7 # LSW |= t2
+ blr
+
diff --git a/purgatory/arch/ppc/ppc_asm.h b/purgatory/arch/ppc/ppc_asm.h
new file mode 100644
index 00000000..36503a90
--- /dev/null
+++ b/purgatory/arch/ppc/ppc_asm.h
@@ -0,0 +1,506 @@
+/*
+ * ppc_asm.h - mainly bits stolen from Linux kernel asm/reg.h and asm/ppc_asm.h
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+/* Condition Register Bit Fields */
+
+#define cr0 0
+#define cr1 1
+#define cr2 2
+#define cr3 3
+#define cr4 4
+#define cr5 5
+#define cr6 6
+#define cr7 7
+
+
+/* General Purpose Registers (GPRs) */
+
+#define r0 0
+#define r1 1
+#define r2 2
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+#define r9 9
+#define r10 10
+#define r11 11
+#define r12 12
+#define r13 13
+#define r14 14
+#define r15 15
+#define r16 16
+#define r17 17
+#define r18 18
+#define r19 19
+#define r20 20
+#define r21 21
+#define r22 22
+#define r23 23
+#define r24 24
+#define r25 25
+#define r26 26
+#define r27 27
+#define r28 28
+#define r29 29
+#define r30 30
+#define r31 31
+
+/* Machine State Register (MSR) Fields */
+#define MSR_SF (1<<63)
+#define MSR_ISF (1<<61)
+#define MSR_VEC (1<<25) /* Enable AltiVec */
+#define MSR_POW (1<<18) /* Enable Power Management */
+#define MSR_WE (1<<18) /* Wait State Enable */
+#define MSR_TGPR (1<<17) /* TLB Update registers in use */
+#define MSR_CE (1<<17) /* Critical Interrupt Enable */
+#define MSR_ILE (1<<16) /* Interrupt Little Endian */
+#define MSR_EE (1<<15) /* External Interrupt Enable */
+#define MSR_PR (1<<14) /* Problem State / Privilege Level */
+#define MSR_FP (1<<13) /* Floating Point enable */
+#define MSR_ME (1<<12) /* Machine Check Enable */
+#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */
+#define MSR_SE (1<<10) /* Single Step */
+#define MSR_BE (1<<9) /* Branch Trace */
+#define MSR_DE (1<<9) /* Debug Exception Enable */
+#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */
+#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */
+#define MSR_IR (1<<5) /* Instruction Relocate */
+#define MSR_DR (1<<4) /* Data Relocate */
+#define MSR_PE (1<<3) /* Protection Enable */
+#define MSR_PX (1<<2) /* Protection Exclusive Mode */
+#define MSR_RI (1<<1) /* Recoverable Exception */
+#define MSR_LE (1<<0) /* Little Endian */
+
+/* Special Purpose Registers (SPRNs)*/
+#define SPRN_CTR 0x009 /* Count Register */
+#define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */
+#define SPRN_DAR 0x013 /* Data Address Register */
+#define SPRN_TBRL 0x10C /* Time Base Read Lower Register (user, R/O) */
+#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */
+#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */
+#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */
+#define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */
+#define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */
+#define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */
+#define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */
+#define SPRN_DBAT1U 0x21A /* Data BAT 1 Upper Register */
+#define SPRN_DBAT2L 0x21D /* Data BAT 2 Lower Register */
+#define SPRN_DBAT2U 0x21C /* Data BAT 2 Upper Register */
+#define SPRN_DBAT3L 0x21F /* Data BAT 3 Lower Register */
+#define SPRN_DBAT3U 0x21E /* Data BAT 3 Upper Register */
+#define SPRN_DBAT4L 0x239 /* Data BAT 4 Lower Register */
+#define SPRN_DBAT4U 0x238 /* Data BAT 4 Upper Register */
+#define SPRN_DBAT5L 0x23B /* Data BAT 5 Lower Register */
+#define SPRN_DBAT5U 0x23A /* Data BAT 5 Upper Register */
+#define SPRN_DBAT6L 0x23D /* Data BAT 6 Lower Register */
+#define SPRN_DBAT6U 0x23C /* Data BAT 6 Upper Register */
+#define SPRN_DBAT7L 0x23F /* Data BAT 7 Lower Register */
+#define SPRN_DBAT7U 0x23E /* Data BAT 7 Upper Register */
+
+#define SPRN_DEC 0x016 /* Decrement Register */
+#define SPRN_DER 0x095 /* Debug Enable Regsiter */
+#define DER_RSTE 0x40000000 /* Reset Interrupt */
+#define DER_CHSTPE 0x20000000 /* Check Stop */
+#define DER_MCIE 0x10000000 /* Machine Check Interrupt */
+#define DER_EXTIE 0x02000000 /* External Interrupt */
+#define DER_ALIE 0x01000000 /* Alignment Interrupt */
+#define DER_PRIE 0x00800000 /* Program Interrupt */
+#define DER_FPUVIE 0x00400000 /* FP Unavailable Interrupt */
+#define DER_DECIE 0x00200000 /* Decrementer Interrupt */
+#define DER_SYSIE 0x00040000 /* System Call Interrupt */
+#define DER_TRE 0x00020000 /* Trace Interrupt */
+#define DER_SEIE 0x00004000 /* FP SW Emulation Interrupt */
+#define DER_ITLBMSE 0x00002000 /* Imp. Spec. Instruction TLB Miss */
+#define DER_ITLBERE 0x00001000 /* Imp. Spec. Instruction TLB Error */
+#define DER_DTLBMSE 0x00000800 /* Imp. Spec. Data TLB Miss */
+#define DER_DTLBERE 0x00000400 /* Imp. Spec. Data TLB Error */
+#define DER_LBRKE 0x00000008 /* Load/Store Breakpoint Interrupt */
+#define DER_IBRKE 0x00000004 /* Instruction Breakpoint Interrupt */
+#define DER_EBRKE 0x00000002 /* External Breakpoint Interrupt */
+#define DER_DPIE 0x00000001 /* Dev. Port Nonmaskable Request */
+#define SPRN_DMISS 0x3D0 /* Data TLB Miss Register */
+#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */
+#define SPRN_EAR 0x11A /* External Address Register */
+#define SPRN_HASH1 0x3D2 /* Primary Hash Address Register */
+#define SPRN_HASH2 0x3D3 /* Secondary Hash Address Resgister */
+#define SPRN_HID0 0x3F0 /* Hardware Implementation Register 0 */
+#define HID0_EMCP (1<<31) /* Enable Machine Check pin */
+#define HID0_EBA (1<<29) /* Enable Bus Address Parity */
+#define HID0_EBD (1<<28) /* Enable Bus Data Parity */
+#define HID0_SBCLK (1<<27)
+#define HID0_EICE (1<<26)
+#define HID0_TBEN (1<<26) /* Timebase enable - 745x */
+#define HID0_ECLK (1<<25)
+#define HID0_PAR (1<<24)
+#define HID0_STEN (1<<24) /* Software table search enable - 745x */
+#define HID0_HIGH_BAT (1<<23) /* Enable high BATs - 7455 */
+#define HID0_DOZE (1<<23)
+#define HID0_NAP (1<<22)
+#define HID0_SLEEP (1<<21)
+#define HID0_DPM (1<<20)
+#define HID0_BHTCLR (1<<18) /* Clear branch history table - 7450 */
+#define HID0_XAEN (1<<17) /* Extended addressing enable - 7450 */
+#define HID0_NHR (1<<16) /* Not hard reset (software bit-7450)*/
+#define HID0_ICE (1<<15) /* Instruction Cache Enable */
+#define HID0_DCE (1<<14) /* Data Cache Enable */
+#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */
+#define HID0_DLOCK (1<<12) /* Data Cache Lock */
+#define HID0_ICFI (1<<11) /* Instr. Cache Flash Invalidate */
+#define HID0_DCI (1<<10) /* Data Cache Invalidate */
+#define HID0_SPD (1<<9) /* Speculative disable */
+#define HID0_SGE (1<<7) /* Store Gathering Enable */
+#define HID0_SIED (1<<7) /* Serial Instr. Execution [Disable] */
+#define HID0_DFCA (1<<6) /* Data Cache Flush Assist */
+#define HID0_LRSTK (1<<4) /* Link register stack - 745x */
+#define HID0_BTIC (1<<5) /* Branch Target Instr Cache Enable */
+#define HID0_ABE (1<<3) /* Address Broadcast Enable */
+#define HID0_FOLD (1<<3) /* Branch Folding enable - 745x */
+#define HID0_BHTE (1<<2) /* Branch History Table Enable */
+#define HID0_BTCD (1<<1) /* Branch target cache disable */
+#define HID0_NOPDST (1<<1) /* No-op dst, dstt, etc. instr. */
+#define HID0_NOPTI (1<<0) /* No-op dcbt and dcbst instr. */
+
+#define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */
+#define HID1_EMCP (1<<31) /* 7450 Machine Check Pin Enable */
+#define HID1_PC0 (1<<16) /* 7450 PLL_CFG[0] */
+#define HID1_PC1 (1<<15) /* 7450 PLL_CFG[1] */
+#define HID1_PC2 (1<<14) /* 7450 PLL_CFG[2] */
+#define HID1_PC3 (1<<13) /* 7450 PLL_CFG[3] */
+#define HID1_SYNCBE (1<<11) /* 7450 ABE for sync, eieio */
+#define HID1_ABE (1<<10) /* 7450 Address Broadcast Enable */
+#define SPRN_HID2 0x3F8 /* Hardware Implementation Register 2 */
+#define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */
+#define SPRN_HID4 0x3F4 /* 970 HID4 */
+#define SPRN_HID5 0x3F6 /* 970 HID5 */
+#if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
+#define SPRN_IAC1 0x3F4 /* Instruction Address Compare 1 */
+#define SPRN_IAC2 0x3F5 /* Instruction Address Compare 2 */
+#endif
+#define SPRN_IBAT0L 0x211 /* Instruction BAT 0 Lower Register */
+#define SPRN_IBAT0U 0x210 /* Instruction BAT 0 Upper Register */
+#define SPRN_IBAT1L 0x213 /* Instruction BAT 1 Lower Register */
+#define SPRN_IBAT1U 0x212 /* Instruction BAT 1 Upper Register */
+#define SPRN_IBAT2L 0x215 /* Instruction BAT 2 Lower Register */
+#define SPRN_IBAT2U 0x214 /* Instruction BAT 2 Upper Register */
+#define SPRN_IBAT3L 0x217 /* Instruction BAT 3 Lower Register */
+#define SPRN_IBAT3U 0x216 /* Instruction BAT 3 Upper Register */
+#define SPRN_IBAT4L 0x231 /* Instruction BAT 4 Lower Register */
+#define SPRN_IBAT4U 0x230 /* Instruction BAT 4 Upper Register */
+#define SPRN_IBAT5L 0x233 /* Instruction BAT 5 Lower Register */
+#define SPRN_IBAT5U 0x232 /* Instruction BAT 5 Upper Register */
+#define SPRN_IBAT6L 0x235 /* Instruction BAT 6 Lower Register */
+#define SPRN_IBAT6U 0x234 /* Instruction BAT 6 Upper Register */
+#define SPRN_IBAT7L 0x237 /* Instruction BAT 7 Lower Register */
+#define SPRN_IBAT7U 0x236 /* Instruction BAT 7 Upper Register */
+#define SPRN_ICMP 0x3D5 /* Instruction TLB Compare Register */
+#define SPRN_ICTC 0x3FB /* Instruction Cache Throttling Control Reg */
+#define SPRN_ICTRL 0x3F3 /* 1011 7450 icache and interrupt ctrl */
+#define ICTRL_EICE 0x08000000 /* enable icache parity errs */
+#define ICTRL_EDC 0x04000000 /* enable dcache parity errs */
+#define ICTRL_EICP 0x00000100 /* enable icache par. check */
+#define SPRN_IMISS 0x3D4 /* Instruction TLB Miss Register */
+#define SPRN_IMMR 0x27E /* Internal Memory Map Register */
+#define SPRN_L2CR 0x3F9 /* Level 2 Cache Control Regsiter */
+#define SPRN_L2CR2 0x3f8
+#define L2CR_L2E 0x80000000 /* L2 enable */
+#define L2CR_L2PE 0x40000000 /* L2 parity enable */
+#define L2CR_L2SIZ_MASK 0x30000000 /* L2 size mask */
+#define L2CR_L2SIZ_256KB 0x10000000 /* L2 size 256KB */
+#define L2CR_L2SIZ_512KB 0x20000000 /* L2 size 512KB */
+#define L2CR_L2SIZ_1MB 0x30000000 /* L2 size 1MB */
+#define L2CR_L2CLK_MASK 0x0e000000 /* L2 clock mask */
+#define L2CR_L2CLK_DISABLED 0x00000000 /* L2 clock disabled */
+#define L2CR_L2CLK_DIV1 0x02000000 /* L2 clock / 1 */
+#define L2CR_L2CLK_DIV1_5 0x04000000 /* L2 clock / 1.5 */
+#define L2CR_L2CLK_DIV2 0x08000000 /* L2 clock / 2 */
+#define L2CR_L2CLK_DIV2_5 0x0a000000 /* L2 clock / 2.5 */
+#define L2CR_L2CLK_DIV3 0x0c000000 /* L2 clock / 3 */
+#define L2CR_L2RAM_MASK 0x01800000 /* L2 RAM type mask */
+#define L2CR_L2RAM_FLOW 0x00000000 /* L2 RAM flow through */
+#define L2CR_L2RAM_PIPE 0x01000000 /* L2 RAM pipelined */
+#define L2CR_L2RAM_PIPE_LW 0x01800000 /* L2 RAM pipelined latewr */
+#define L2CR_L2DO 0x00400000 /* L2 data only */
+#define L2CR_L2I 0x00200000 /* L2 global invalidate */
+#define L2CR_L2CTL 0x00100000 /* L2 RAM control */
+#define L2CR_L2WT 0x00080000 /* L2 write-through */
+#define L2CR_L2TS 0x00040000 /* L2 test support */
+#define L2CR_L2OH_MASK 0x00030000 /* L2 output hold mask */
+#define L2CR_L2OH_0_5 0x00000000 /* L2 output hold 0.5 ns */
+#define L2CR_L2OH_1_0 0x00010000 /* L2 output hold 1.0 ns */
+#define L2CR_L2SL 0x00008000 /* L2 DLL slow */
+#define L2CR_L2DF 0x00004000 /* L2 differential clock */
+#define L2CR_L2BYP 0x00002000 /* L2 DLL bypass */
+#define L2CR_L2IP 0x00000001 /* L2 GI in progress */
+#define SPRN_L3CR 0x3FA /* Level 3 Cache Control Regsiter */
+#define L3CR_L3E 0x80000000 /* L3 enable */
+#define L3CR_L3PE 0x40000000 /* L3 data parity enable */
+#define L3CR_L3APE 0x20000000 /* L3 addr parity enable */
+#define L3CR_L3SIZ 0x10000000 /* L3 size */
+#define L3CR_L3CLKEN 0x08000000 /* L3 clock enable */
+#define L3CR_L3RES 0x04000000 /* L3 special reserved bit */
+#define L3CR_L3CLKDIV 0x03800000 /* L3 clock divisor */
+#define L3CR_L3IO 0x00400000 /* L3 instruction only */
+#define L3CR_L3SPO 0x00040000 /* L3 sample point override */
+#define L3CR_L3CKSP 0x00030000 /* L3 clock sample point */
+#define L3CR_L3PSP 0x0000e000 /* L3 P-clock sample point */
+#define L3CR_L3REP 0x00001000 /* L3 replacement algorithm */
+#define L3CR_L3HWF 0x00000800 /* L3 hardware flush */
+#define L3CR_L3I 0x00000400 /* L3 global invalidate */
+#define L3CR_L3RT 0x00000300 /* L3 SRAM type */
+#define L3CR_L3NIRCA 0x00000080 /* L3 non-integer ratio clock adj. */
+#define L3CR_L3DO 0x00000040 /* L3 data only mode */
+#define L3CR_PMEN 0x00000004 /* L3 private memory enable */
+#define L3CR_PMSIZ 0x00000001 /* L3 private memory size */
+#define SPRN_MSSCR0 0x3f6 /* Memory Subsystem Control Register 0 */
+#define SPRN_MSSSR0 0x3f7 /* Memory Subsystem Status Register 1 */
+#define SPRN_LDSTCR 0x3f8 /* Load/Store control register */
+#define SPRN_LDSTDB 0x3f4 /* */
+#define SPRN_LR 0x008 /* Link Register */
+#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */
+#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */
+#ifndef SPRN_PIR
+#define SPRN_PIR 0x3FF /* Processor Identification Register */
+#endif
+#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 */
+#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */
+#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */
+#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */
+#define SPRN_PTEHI 0x3D5 /* 981 7450 PTE HI word (S/W TLB load) */
+#define SPRN_PTELO 0x3D6 /* 982 7450 PTE LO word (S/W TLB load) */
+#define SPRN_PVR 0x11F /* Processor Version Register */
+#define SPRN_RPA 0x3D6 /* Required Physical Address Register */
+#define SPRN_SDA 0x3BF /* Sampled Data Address Register */
+#define SPRN_SDR1 0x019 /* MMU Hash Base Register */
+#define SPRN_SIA 0x3BB /* Sampled Instruction Address Register */
+#define SPRN_SPRG0 0x110 /* Special Purpose Register General 0 */
+#define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */
+#define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */
+#define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */
+#define SPRN_SPRG4 0x114 /* Special Purpose Register General 4 */
+#define SPRN_SPRG5 0x115 /* Special Purpose Register General 5 */
+#define SPRN_SPRG6 0x116 /* Special Purpose Register General 6 */
+#define SPRN_SPRG7 0x117 /* Special Purpose Register General 7 */
+#define SPRN_SRR0 0x01A /* Save/Restore Register 0 */
+#define SPRN_SRR1 0x01B /* Save/Restore Register 1 */
+#define SPRN_THRM1 0x3FC /* Thermal Management Register 1 */
+/* these bits were defined in inverted endian sense originally, ugh, confusing */
+#define THRM1_TIN (1 << 31)
+#define THRM1_TIV (1 << 30)
+#define THRM1_THRES(x) ((x&0x7f)<<23)
+#define THRM3_SITV(x) ((x&0x3fff)<<1)
+#define THRM1_TID (1<<2)
+#define THRM1_TIE (1<<1)
+#define THRM1_V (1<<0)
+#define SPRN_THRM2 0x3FD /* Thermal Management Register 2 */
+#define SPRN_THRM3 0x3FE /* Thermal Management Register 3 */
+#define THRM3_E (1<<0)
+#define SPRN_TLBMISS 0x3D4 /* 980 7450 TLB Miss Register */
+#define SPRN_UMMCR0 0x3A8 /* User Monitor Mode Control Register 0 */
+#define SPRN_UMMCR1 0x3AC /* User Monitor Mode Control Register 0 */
+#define SPRN_UPMC1 0x3A9 /* User Performance Counter Register 1 */
+#define SPRN_UPMC2 0x3AA /* User Performance Counter Register 2 */
+#define SPRN_UPMC3 0x3AD /* User Performance Counter Register 3 */
+#define SPRN_UPMC4 0x3AE /* User Performance Counter Register 4 */
+#define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register */
+#define SPRN_VRSAVE 0x100 /* Vector Register Save Register */
+#define SPRN_XER 0x001 /* Fixed Point Exception Register */
+
+/* Bit definitions for MMCR0 and PMC1 / PMC2. */
+#define MMCR0_PMC1_CYCLES (1 << 7)
+#define MMCR0_PMC1_ICACHEMISS (5 << 7)
+#define MMCR0_PMC1_DTLB (6 << 7)
+#define MMCR0_PMC2_DCACHEMISS 0x6
+#define MMCR0_PMC2_CYCLES 0x1
+#define MMCR0_PMC2_ITLB 0x7
+#define MMCR0_PMC2_LOADMISSTIME 0x5
+
+/* Short-hand versions for a number of the above SPRNs */
+#define CTR SPRN_CTR /* Counter Register */
+#define DAR SPRN_DAR /* Data Address Register */
+#define DABR SPRN_DABR /* Data Address Breakpoint Register */
+#define DBAT0L SPRN_DBAT0L /* Data BAT 0 Lower Register */
+#define DBAT0U SPRN_DBAT0U /* Data BAT 0 Upper Register */
+#define DBAT1L SPRN_DBAT1L /* Data BAT 1 Lower Register */
+#define DBAT1U SPRN_DBAT1U /* Data BAT 1 Upper Register */
+#define DBAT2L SPRN_DBAT2L /* Data BAT 2 Lower Register */
+#define DBAT2U SPRN_DBAT2U /* Data BAT 2 Upper Register */
+#define DBAT3L SPRN_DBAT3L /* Data BAT 3 Lower Register */
+#define DBAT3U SPRN_DBAT3U /* Data BAT 3 Upper Register */
+#define DBAT4L SPRN_DBAT4L /* Data BAT 4 Lower Register */
+#define DBAT4U SPRN_DBAT4U /* Data BAT 4 Upper Register */
+#define DBAT5L SPRN_DBAT5L /* Data BAT 5 Lower Register */
+#define DBAT5U SPRN_DBAT5U /* Data BAT 5 Upper Register */
+#define DBAT6L SPRN_DBAT6L /* Data BAT 6 Lower Register */
+#define DBAT6U SPRN_DBAT6U /* Data BAT 6 Upper Register */
+#define DBAT7L SPRN_DBAT7L /* Data BAT 7 Lower Register */
+#define DBAT7U SPRN_DBAT7U /* Data BAT 7 Upper Register */
+#define DEC SPRN_DEC /* Decrement Register */
+#define DMISS SPRN_DMISS /* Data TLB Miss Register */
+#define DSISR SPRN_DSISR /* Data Storage Interrupt Status Register */
+#define EAR SPRN_EAR /* External Address Register */
+#define HASH1 SPRN_HASH1 /* Primary Hash Address Register */
+#define HASH2 SPRN_HASH2 /* Secondary Hash Address Register */
+#define HID0 SPRN_HID0 /* Hardware Implementation Register 0 */
+#define HID1 SPRN_HID1 /* Hardware Implementation Register 1 */
+#define IABR SPRN_IABR /* Instruction Address Breakpoint Register */
+#define IBAT0L SPRN_IBAT0L /* Instruction BAT 0 Lower Register */
+#define IBAT0U SPRN_IBAT0U /* Instruction BAT 0 Upper Register */
+#define IBAT1L SPRN_IBAT1L /* Instruction BAT 1 Lower Register */
+#define IBAT1U SPRN_IBAT1U /* Instruction BAT 1 Upper Register */
+#define IBAT2L SPRN_IBAT2L /* Instruction BAT 2 Lower Register */
+#define IBAT2U SPRN_IBAT2U /* Instruction BAT 2 Upper Register */
+#define IBAT3L SPRN_IBAT3L /* Instruction BAT 3 Lower Register */
+#define IBAT3U SPRN_IBAT3U /* Instruction BAT 3 Upper Register */
+#define IBAT4L SPRN_IBAT4L /* Instruction BAT 4 Lower Register */
+#define IBAT4U SPRN_IBAT4U /* Instruction BAT 4 Upper Register */
+#define IBAT5L SPRN_IBAT5L /* Instruction BAT 5 Lower Register */
+#define IBAT5U SPRN_IBAT5U /* Instruction BAT 5 Upper Register */
+#define IBAT6L SPRN_IBAT6L /* Instruction BAT 6 Lower Register */
+#define IBAT6U SPRN_IBAT6U /* Instruction BAT 6 Upper Register */
+#define IBAT7L SPRN_IBAT7L /* Instruction BAT 7 Lower Register */
+#define IBAT7U SPRN_IBAT7U /* Instruction BAT 7 Upper Register */
+#define ICMP SPRN_ICMP /* Instruction TLB Compare Register */
+#define IMISS SPRN_IMISS /* Instruction TLB Miss Register */
+#define IMMR SPRN_IMMR /* PPC 860/821 Internal Memory Map Register */
+#define L2CR SPRN_L2CR /* Classic PPC L2 cache control register */
+#define L3CR SPRN_L3CR /* PPC 745x L3 cache control register */
+#define LR SPRN_LR
+#define PVR SPRN_PVR /* Processor Version */
+#define RPA SPRN_RPA /* Required Physical Address Register */
+#define SDR1 SPRN_SDR1 /* MMU hash base register */
+#define SPR0 SPRN_SPRG0 /* Supervisor Private Registers */
+#define SPR1 SPRN_SPRG1
+#define SPR2 SPRN_SPRG2
+#define SPR3 SPRN_SPRG3
+#define SPR4 SPRN_SPRG4
+#define SPR5 SPRN_SPRG5
+#define SPR6 SPRN_SPRG6
+#define SPR7 SPRN_SPRG7
+#define SPRG0 SPRN_SPRG0
+#define SPRG1 SPRN_SPRG1
+#define SPRG2 SPRN_SPRG2
+#define SPRG3 SPRN_SPRG3
+#define SPRG4 SPRN_SPRG4
+#define SPRG5 SPRN_SPRG5
+#define SPRG6 SPRN_SPRG6
+#define SPRG7 SPRN_SPRG7
+#define SRR0 SPRN_SRR0 /* Save and Restore Register 0 */
+#define SRR1 SPRN_SRR1 /* Save and Restore Register 1 */
+#define SRR2 SPRN_SRR2 /* Save and Restore Register 2 */
+#define SRR3 SPRN_SRR3 /* Save and Restore Register 3 */
+#define ICTC SPRN_ICTC /* Instruction Cache Throttling Control Reg */
+#define THRM1 SPRN_THRM1 /* Thermal Management Register 1 */
+#define THRM2 SPRN_THRM2 /* Thermal Management Register 2 */
+#define THRM3 SPRN_THRM3 /* Thermal Management Register 3 */
+#define XER SPRN_XER
+#define TBRL SPRN_TBRL /* Time Base Read Lower Register */
+#define TBRU SPRN_TBRU /* Time Base Read Upper Register */
+#define TBWL SPRN_TBWL /* Time Base Write Lower Register */
+#define TBWU SPRN_TBWU /* Time Base Write Upper Register */
+
+/* Processor Version Register */
+
+/* Processor Version Register (PVR) field extraction */
+
+#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
+#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */
+
+/*
+ * IBM has further subdivided the standard PowerPC 16-bit version and
+ * revision subfields of the PVR for the PowerPC 403s into the following:
+ */
+
+#define PVR_FAM(pvr) (((pvr) >> 20) & 0xFFF) /* Family field */
+#define PVR_MEM(pvr) (((pvr) >> 16) & 0xF) /* Member field */
+#define PVR_CORE(pvr) (((pvr) >> 12) & 0xF) /* Core field */
+#define PVR_CFG(pvr) (((pvr) >> 8) & 0xF) /* Configuration field */
+#define PVR_MAJ(pvr) (((pvr) >> 4) & 0xF) /* Major revision field */
+#define PVR_MIN(pvr) (((pvr) >> 0) & 0xF) /* Minor revision field */
+
+/* Processor Version Numbers */
+
+#define PVR_403GA 0x00200000
+#define PVR_403GB 0x00200100
+#define PVR_403GC 0x00200200
+#define PVR_403GCX 0x00201400
+#define PVR_405GP 0x40110000
+#define PVR_STB03XXX 0x40310000
+#define PVR_NP405H 0x41410000
+#define PVR_NP405L 0x41610000
+#define PVR_440GP_RB 0x40120440
+#define PVR_440GP_RC1 0x40120481
+#define PVR_440GP_RC2 0x40200481
+#define PVR_440GX_RA 0x51b21850
+#define PVR_440GX_RB 0x51b21851
+#define PVR_440GX_RB1 0x51b21852
+#define PVR_601 0x00010000
+#define PVR_602 0x00050000
+#define PVR_603 0x00030000
+#define PVR_603e 0x00060000
+#define PVR_603ev 0x00070000
+#define PVR_603r 0x00071000
+#define PVR_604 0x00040000
+#define PVR_604e 0x00090000
+#define PVR_604r 0x000A0000
+#define PVR_620 0x00140000
+#define PVR_740 0x00080000
+#define PVR_750 PVR_740
+#define PVR_740P 0x10080000
+#define PVR_750P PVR_740P
+#define PVR_7400 0x000C0000
+#define PVR_7410 0x800C0000
+#define PVR_7450 0x80000000
+/*
+ * For the 8xx processors, all of them report the same PVR family for
+ * the PowerPC core. The various versions of these processors must be
+ * differentiated by the version number in the Communication Processor
+ * Module (CPM).
+ */
+#define PVR_821 0x00500000
+#define PVR_823 PVR_821
+#define PVR_850 PVR_821
+#define PVR_860 PVR_821
+#define PVR_8240 0x00810100
+#define PVR_8245 0x80811014
+#define PVR_8260 PVR_8240
+
+/* Segment Registers */
+#define SR0 0
+#define SR1 1
+#define SR2 2
+#define SR3 3
+#define SR4 4
+#define SR5 5
+#define SR6 6
+#define SR7 7
+#define SR8 8
+#define SR9 9
+#define SR10 10
+#define SR11 11
+#define SR12 12
+#define SR13 13
+#define SR14 14
+#define SR15 15
+
+
+/* returns r3 = relocated address of sym */
+/* modifies r0 */
+#define RELOC_SYM(sym) \
+ mflr r3; \
+ bl 1f; \
+1: mflr r0; \
+ mtlr r3; \
+ lis r3, 1b@ha; \
+ ori r3, r3, 1b@l; \
+ subf r0, r3, r0; \
+ lis r3, sym@ha; \
+ ori r3, r3, sym@l; \
+ add r3, r3, r0
+
diff --git a/purgatory/arch/ppc/purgatory-ppc.c b/purgatory/arch/ppc/purgatory-ppc.c
new file mode 100644
index 00000000..ab4d941d
--- /dev/null
+++ b/purgatory/arch/ppc/purgatory-ppc.c
@@ -0,0 +1,7 @@
+#include <purgatory.h>
+#include "purgatory-ppc.h"
+
+void setup_arch(void)
+{
+ /* Nothing for now */
+}
diff --git a/purgatory/arch/ppc/purgatory-ppc.h b/purgatory/arch/ppc/purgatory-ppc.h
new file mode 100644
index 00000000..e931cae6
--- /dev/null
+++ b/purgatory/arch/ppc/purgatory-ppc.h
@@ -0,0 +1,6 @@
+#ifndef PURGATORY_PPC_H
+#define PURGATORY_PPC_H
+
+/* nothing yet */
+
+#endif /* PURGATORY_PPC_H */
diff --git a/purgatory/arch/ppc64/Makefile b/purgatory/arch/ppc64/Makefile
new file mode 100644
index 00000000..c76794b2
--- /dev/null
+++ b/purgatory/arch/ppc64/Makefile
@@ -0,0 +1,7 @@
+#
+# Purgatory ppc
+#
+
+PURGATORY_C_SRCS+=
+PURGATORY_S_SRCS+=
+
diff --git a/purgatory/arch/ppc64/include/limits.h b/purgatory/arch/ppc64/include/limits.h
new file mode 100644
index 00000000..0c6f21f9
--- /dev/null
+++ b/purgatory/arch/ppc64/include/limits.h
@@ -0,0 +1,57 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 9223372036854775807L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 18446744073709551615UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/purgatory/arch/ppc64/include/stdint.h b/purgatory/arch/ppc64/include/stdint.h
new file mode 100644
index 00000000..2f9c592c
--- /dev/null
+++ b/purgatory/arch/ppc64/include/stdint.h
@@ -0,0 +1,16 @@
+#ifndef STDINT_H
+#define STDINT_H
+
+typedef unsigned long size_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long int64_t;
+
+#endif /* STDINT_H */
diff --git a/purgatory/arch/x86_64/Makefile b/purgatory/arch/x86_64/Makefile
new file mode 100644
index 00000000..d08edff4
--- /dev/null
+++ b/purgatory/arch/x86_64/Makefile
@@ -0,0 +1,15 @@
+#
+# Purgatory x86_64
+#
+
+PURGATORY_S_SRCS+= purgatory/arch/i386/entry32-16.S
+PURGATORY_S_SRCS+= purgatory/arch/i386/entry32-16-debug.S
+PURGATORY_S_SRCS+= purgatory/arch/x86_64/entry64-32.S
+PURGATORY_S_SRCS+= purgatory/arch/x86_64/entry64.S
+PURGATORY_S_SRCS+= purgatory/arch/x86_64/setup-x86_64.S
+PURGATORY_S_SRCS+= purgatory/arch/x86_64/stack.S
+PURGATORY_C_SRCS+= purgatory/arch/x86_64/purgatory-x86_64.c
+PURGATORY_C_SRCS+= purgatory/arch/i386/console-x86.c
+PURGATORY_C_SRCS+= purgatory/arch/i386/vga.c
+PURGATORY_C_SRCS+= purgatory/arch/i386/pic.c
+
diff --git a/purgatory/arch/x86_64/entry64-32.S b/purgatory/arch/x86_64/entry64-32.S
new file mode 100644
index 00000000..66f8a854
--- /dev/null
+++ b/purgatory/arch/x86_64/entry64-32.S
@@ -0,0 +1,134 @@
+/*
+ * purgatory: setup code
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+.data
+ .equ MSR_K6_EFER, 0xC0000080
+ .equ EFER_LME, 0x00000100
+ .equ X86_CR4_PAE, 0x00000020
+ .equ CR0_PG, 0x80000000
+
+ .text
+ .globl entry32, entry32_regs
+entry32:
+ .code64
+
+ /* Setup a gdt that should that is generally usefully */
+ lgdt gdt(%rip)
+
+ /* Switch to 32bit compatiblity mode */
+ ljmp *lm_exit_addr(%rip)
+lm_exit:
+ .code32
+
+ /* Disable paging */
+ movl %cr0, %eax
+ andl $~CR0_PG, %eax
+ movl %eax, %cr0
+
+ /* Disable long mode */
+ movl $MSR_K6_EFER, %ecx
+ rdmsr
+ andl $~EFER_LME, %eax
+ wrmsr
+
+ /* Disable PAE */
+ xorl %eax, %eax
+ movl %eax, %cr4
+
+ /* load the data segments */
+ movl $0x18, %eax /* data segment */
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* Load the registers */
+ movl eax, %eax
+ movl ecx, %ecx
+ movl edx, %edx
+ movl esi, %esi
+ movl edi, %edi
+ movl esp, %esp
+ movl ebp, %ebp
+ movl ebx, %ebx
+
+ /* Jump to the loaded image */
+ jmpl *(eip)
+
+ .section ".rodata"
+ .balign 16
+gdt: /* 0x00 unusable segment
+ * 0x08 unused
+ * so use them as the gdt ptr
+ */
+ .word gdt_end - gdt - 1
+ .quad gdt
+ .word 0, 0, 0
+
+ /* Documented linux kernel segments */
+ /* 0x10 4GB flat code segment */
+ .word 0xFFFF, 0x0000, 0x9A00, 0x00CF
+ /* 0x18 4GB flat data segment */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+
+ /* 0x20 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x28 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x30 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x38 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x40 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x48 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x50 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x58 dummy */
+ .word 0x0000, 0x0000, 0x0000, 0x000
+
+ /* Segments used by the 2.5.x kernel */
+ /* 0x60 4GB flat code segment */
+ .word 0xFFFF, 0x0000, 0x9A00, 0x00CF
+ /* 0x68 4GB flat data segment */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+gdt_end:
+
+ .section ".rodata"
+ .balign 4
+lm_exit_addr:
+ .long lm_exit
+ .long 0x10
+
+ .section ".rodata"
+ .balign 4
+entry32_regs:
+eax: .long 0x00000000
+ebx: .long 0x00000000
+ecx: .long 0x00000000
+edx: .long 0x00000000
+esi: .long 0x00000000
+edi: .long 0x00000000
+esp: .long 0x00000000
+ebp: .long 0x00000000
+eip: .long entry16
+ .size entry32_regs, . - entry32_regs
+
diff --git a/purgatory/arch/x86_64/entry64.S b/purgatory/arch/x86_64/entry64.S
new file mode 100644
index 00000000..1ed67863
--- /dev/null
+++ b/purgatory/arch/x86_64/entry64.S
@@ -0,0 +1,100 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "arch/debug.h"
+
+.text
+.code64
+ .balign 16
+ .globl entry64, entry64_regs
+entry64:
+ /* Don't worry about special registers... */
+
+ /* Setup a gdt that should be preserved */
+ lgdt gdt(%rip)
+
+ /* load the data segments */
+ movl $0x18, %eax /* data segment */
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* In 64bit mode the code segment is meaningless */
+
+ /* Load the registers */
+ movq rax(%rip), %rax
+ movq rbx(%rip), %rbx
+ movq rcx(%rip), %rcx
+ movq rdx(%rip), %rdx
+ movq rsi(%rip), %rsi
+ movq rdi(%rip), %rdi
+ movq rsp(%rip), %rsp
+ movq rbp(%rip), %rbp
+ movq r8(%rip), %r8
+ movq r9(%rip), %r9
+ movq r10(%rip), %r10
+ movq r11(%rip), %r11
+ movq r12(%rip), %r12
+ movq r13(%rip), %r13
+ movq r14(%rip), %r14
+ movq r15(%rip), %r15
+
+ /* Jump to the new code... */
+ jmpq *rip(%rip)
+
+ .section ".rodata"
+ .balign 4
+entry64_regs:
+rax: .quad 0x00000000
+rbx: .quad 0x00000000
+rcx: .quad 0x00000000
+rdx: .quad 0x00000000
+rsi: .quad 0x00000000
+rdi: .quad 0x00000000
+rsp: .quad 0x00000000
+rbp: .quad 0x00000000
+r8: .quad 0x00000000
+r9: .quad 0x00000000
+r10: .quad 0x00000000
+r11: .quad 0x00000000
+r12: .quad 0x00000000
+r13: .quad 0x00000000
+r14: .quad 0x00000000
+r15: .quad 0x00000000
+rip: .quad entry32
+ .size entry64_regs, . - entry64_regs
+
+ .section ".rodata"
+ .balign 16
+gdt: /* 0x00 unusable segment
+ * 0x08 unused
+ * so use them as the gdt ptr
+ */
+ .word gdt_end - gdt - 1
+ .quad gdt
+ .word 0, 0, 0
+
+ /* 0x10 4GB flat code segment */
+ .word 0xFFFF, 0x0000, 0x9A00, 0x00CF
+
+ /* 0x18 4GB flat data segment */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+gdt_end:
diff --git a/purgatory/arch/x86_64/include/arch/debug.h b/purgatory/arch/x86_64/include/arch/debug.h
new file mode 100644
index 00000000..39f2b16f
--- /dev/null
+++ b/purgatory/arch/x86_64/include/arch/debug.h
@@ -0,0 +1,317 @@
+/* Base Address */
+#define TTYS0_BASE 0x3f8
+/* Data */
+#define TTYS0_RBR (TTYS0_BASE+0x00)
+#define TTYS0_TBR (TTYS0_BASE+0x00)
+/* Control */
+#define TTYS0_IER (TTYS0_BASE+0x01)
+#define TTYS0_IIR (TTYS0_BASE+0x02)
+#define TTYS0_FCR (TTYS0_BASE+0x02)
+#define TTYS0_LCR (TTYS0_BASE+0x03)
+#define TTYS0_MCR (TTYS0_BASE+0x04)
+
+#define TTYS0_DLL (TTYS0_BASE+0x00)
+#define TTYS0_DLM (TTYS0_BASE+0x01)
+/* Status */
+#define TTYS0_LSR (TTYS0_BASE+0x05)
+#define TTYS0_MSR (TTYS0_BASE+0x06)
+#define TTYS0_SCR (TTYS0_BASE+0x07)
+
+#define TTYS0_BAUD 9600
+#define TTYS0_DIV (115200/TTYS0_BAUD)
+#define TTYS0_DIV_LO (TTYS0_DIV&0xFF)
+#define TTYS0_DIV_HI ((TTYS0_DIV >> 8)&0xFF)
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttyS0 baud rate
+#endif
+
+#define TTYS0_INIT \
+ /* disable interrupts */ \
+ movb $0x00, %al ; \
+ movw $TTYS0_IER, %dx ; \
+ outb %al, %dx ; \
+ ; \
+ /* enable fifos */ \
+ movb $0x01, %al ; \
+ movw $TTYS0_FCR, %dx ; \
+ outb %al, %dx ; \
+ ; \
+ /* Set Baud Rate Divisor to TTYS0_BAUD */ \
+ movw $TTYS0_LCR, %dx ; \
+ movb $0x83, %al ; \
+ outb %al, %dx ; \
+ ; \
+ movw $TTYS0_DLL, %dx ; \
+ movb $TTYS0_DIV_LO, %al ; \
+ outb %al, %dx ; \
+ ; \
+ movw $TTYS0_DLM, %dx ; \
+ movb $TTYS0_DIV_HI, %al ; \
+ outb %al, %dx ; \
+ ; \
+ movw $TTYS0_LCR, %dx ; \
+ movb $0x03, %al ; \
+ outb %al, %dx
+
+
+ /* uses: ax, dx */
+#define TTYS0_TX_AL \
+ mov %al, %ah ; \
+9: mov $TTYS0_LSR, %dx ; \
+ inb %dx, %al ; \
+ test $0x20, %al ; \
+ je 9b ; \
+ mov $TTYS0_TBR, %dx ; \
+ mov %ah, %al ; \
+ outb %al, %dx
+
+ /* uses: ax, dx */
+#define TTYS0_TX_CHAR(byte) \
+ mov byte, %al ; \
+ TTYS0_TX_AL
+
+ /* uses: eax, dx */
+#define TTYS0_TX_HEX32(lword) \
+ mov lword, %eax ; \
+ shr $28, %eax ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $24, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $20, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $16, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $12, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $8, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $4, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL
+
+ /* uses: rax, dx */
+#define TTYS0_TX_HEX64(lword) \
+ mov lword, %rax ; \
+ shr $60, %rax ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $56, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $52, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $48, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $44, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $40, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $36, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $32, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $28, %rax ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $24, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $20, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $16, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $12, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $8, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ shr $4, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL ; \
+ ; \
+ mov lword, %rax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ TTYS0_TX_AL
+
+
+#define DEBUG(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x); TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+#define DEBUG_TX_HEX64(x) TTYS0_TX_HEX64(x); TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
+
diff --git a/purgatory/arch/x86_64/include/arch/io.h b/purgatory/arch/x86_64/include/arch/io.h
new file mode 100644
index 00000000..13ad8871
--- /dev/null
+++ b/purgatory/arch/x86_64/include/arch/io.h
@@ -0,0 +1,98 @@
+#ifndef ARCH_IO_H
+#define ARCH_IO_H
+
+#include <stdint.h>
+/* Helper functions for directly doing I/O */
+
+extern inline uint8_t inb(uint16_t port)
+{
+ uint8_t result;
+
+ __asm__ __volatile__ (
+ "inb %w1,%0"
+ :"=a" (result)
+ :"Nd" (port));
+ return result;
+}
+
+extern inline uint16_t inw(uint16_t port)
+{
+ uint16_t result;
+
+ __asm__ __volatile__ (
+ "inw %w1,%0"
+ :"=a" (result)
+ :"Nd" (port));
+ return result;
+}
+
+extern inline uint32_t inl(uint32_t port)
+{
+ uint32_t result;
+
+ __asm__ __volatile__ (
+ "inl %w1,%0"
+ :"=a" (result)
+ :"Nd" (port));
+ return result;
+}
+
+extern inline void outb (uint8_t value, uint16_t port)
+{
+ __asm__ __volatile__ (
+ "outb %b0,%w1"
+ :
+ :"a" (value), "Nd" (port));
+}
+
+extern inline void outw (uint16_t value, uint16_t port)
+{
+ __asm__ __volatile__ (
+ "outw %w0,%w1"
+ :
+ :"a" (value), "Nd" (port));
+}
+
+extern inline void outl (uint32_t value, uint16_t port)
+{
+ __asm__ __volatile__ (
+ "outl %0,%w1"
+ :
+ :"a" (value), "Nd" (port));
+}
+
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+
+static inline unsigned char readb(const volatile void *addr)
+{
+ return *(volatile unsigned char *) addr;
+}
+static inline unsigned short readw(const volatile void *addr)
+{
+ return *(volatile unsigned short *) addr;
+}
+static inline unsigned int readl(const volatile void *addr)
+{
+ return *(volatile unsigned int *) addr;
+}
+
+static inline void writeb(unsigned char b, volatile void *addr)
+{
+ *(volatile unsigned char *) addr = b;
+}
+static inline void writew(unsigned short b, volatile void *addr)
+{
+ *(volatile unsigned short *) addr = b;
+}
+static inline void writel(unsigned int b, volatile void *addr)
+{
+ *(volatile unsigned int *) addr = b;
+}
+
+#endif /* ARCH_IO_H */
diff --git a/purgatory/arch/x86_64/include/limits.h b/purgatory/arch/x86_64/include/limits.h
new file mode 100644
index 00000000..0c6f21f9
--- /dev/null
+++ b/purgatory/arch/x86_64/include/limits.h
@@ -0,0 +1,57 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 9223372036854775807L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 18446744073709551615UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/purgatory/arch/x86_64/include/stdint.h b/purgatory/arch/x86_64/include/stdint.h
new file mode 100644
index 00000000..2f9c592c
--- /dev/null
+++ b/purgatory/arch/x86_64/include/stdint.h
@@ -0,0 +1,16 @@
+#ifndef STDINT_H
+#define STDINT_H
+
+typedef unsigned long size_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long int64_t;
+
+#endif /* STDINT_H */
diff --git a/purgatory/arch/x86_64/purgatory-x86_64.c b/purgatory/arch/x86_64/purgatory-x86_64.c
new file mode 100644
index 00000000..f839ab5e
--- /dev/null
+++ b/purgatory/arch/x86_64/purgatory-x86_64.c
@@ -0,0 +1,12 @@
+#include <arch/io.h>
+#include <purgatory.h>
+#include "purgatory-x86_64.h"
+
+uint8_t reset_vga = 0;
+uint8_t legacy_pic = 0;
+
+void setup_arch(void)
+{
+ if (reset_vga) x86_reset_vga();
+ if (legacy_pic) x86_setup_legacy_pic();
+}
diff --git a/purgatory/arch/x86_64/purgatory-x86_64.h b/purgatory/arch/x86_64/purgatory-x86_64.h
new file mode 100644
index 00000000..209edea6
--- /dev/null
+++ b/purgatory/arch/x86_64/purgatory-x86_64.h
@@ -0,0 +1,4 @@
+#ifndef PURGATORY_X86_64_H
+#define PURGATORY_X86_64_H
+#include "../i386/purgatory-x86.h"
+#endif /* PURGATORY_X86_64_H */
diff --git a/purgatory/arch/x86_64/setup-x86_64.S b/purgatory/arch/x86_64/setup-x86_64.S
new file mode 100644
index 00000000..d3b5993f
--- /dev/null
+++ b/purgatory/arch/x86_64/setup-x86_64.S
@@ -0,0 +1,73 @@
+/*
+ * purgatory: setup code
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "arch/debug.h"
+
+
+#undef i386
+
+ .text
+ .globl purgatory_start
+ .balign 16
+purgatory_start:
+ .code64
+
+ /* Load a gdt so I know what the segment registers are */
+ lgdt gdt(%rip)
+
+ /* load the data segments */
+ movl $0x18, %eax /* data segment */
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ /* In 64bit mode the code segment is meaningless */
+
+ /* Setup a stack */
+ movq $lstack_end, %rsp
+
+ /* Call the C code */
+ call purgatory
+ jmp entry64
+
+ .section ".rodata"
+ .balign 16
+gdt: /* 0x00 unusable segment
+ * 0x08 unused
+ * so use them as the gdt ptr
+ */
+ .word gdt_end - gdt - 1
+ .quad gdt
+ .word 0, 0, 0
+
+ /* 0x10 4GB flat code segment */
+ .word 0xFFFF, 0x0000, 0x9A00, 0x00AF
+
+ /* 0x18 4GB flat data segment */
+ .word 0xFFFF, 0x0000, 0x9200, 0x00CF
+gdt_end:
+
+ .bss
+ .balign 4096
+lstack:
+ .skip 4096
+lstack_end:
+
diff --git a/purgatory/arch/x86_64/stack.S b/purgatory/arch/x86_64/stack.S
new file mode 100644
index 00000000..4188ea32
--- /dev/null
+++ b/purgatory/arch/x86_64/stack.S
@@ -0,0 +1,44 @@
+/*
+ * purgatory: stack
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /* A stack for the loaded kernel.
+ * Seperate and in the data section so it can be prepopulated.
+ */
+ .data
+ .balign 4096
+ .globl stack, stack_end
+ .globl stack_arg32_1, stack_arg32_2, stack_arg32_3 ,stack_arg32_4
+ .globl stack_arg32_5, stack_arg32_6, stack_arg32_7 ,stack_arg32_8
+ .globl stack_arg64_1, stack_arg64_2, stack_arg64_3 ,stack_arg64_4
+
+stack:
+ .skip 4096 - (8*4)
+stack_arg64_4: ; .size stack_arg64_4, 8
+stack_arg32_8: .long 0 ; .size stack_arg32_8, 4
+stack_arg32_7: .long 0 ; .size stack_arg32_7, 4
+stack_arg64_3: ; .size stack_arg64_3, 8
+stack_arg32_6: .long 0 ; .size stack_arg32_6, 4
+stack_arg32_5: .long 0 ; .size stack_arg32_5, 4
+stack_arg64_2: ; .size stack_arg64_2, 8
+stack_arg32_4: .long 0 ; .size stack_arg32_4, 4
+stack_arg32_3: .long 0 ; .size stack_arg32_3, 4
+stack_arg64_1: ; .size stack_arg64_1, 8
+stack_arg32_2: .long 0 ; .size stack_arg32_2, 4
+stack_arg32_1: .long 0 ; .size stack_arg32_1, 4
+stack_end:
diff --git a/purgatory/include/purgatory.h b/purgatory/include/purgatory.h
new file mode 100644
index 00000000..93037f20
--- /dev/null
+++ b/purgatory/include/purgatory.h
@@ -0,0 +1,8 @@
+#ifndef PURGATORY_H
+#define PURGATORY_H
+
+void putchar(int ch);
+void printf(const char *fmt, ...);
+void setup_arch(void);
+
+#endif /* PURGATORY_H */
diff --git a/purgatory/include/string.h b/purgatory/include/string.h
new file mode 100644
index 00000000..87cc4e1c
--- /dev/null
+++ b/purgatory/include/string.h
@@ -0,0 +1,10 @@
+#ifndef STRING_H
+#define STRING_H
+
+size_t strnlen(const char *s, size_t max);
+void* memset(void* s, int c, size_t n);
+void* memcpy(void *dest, const void *src, size_t len);
+int memcmp(void *src1, void *src2, size_t len);
+
+
+#endif /* STRING_H */
diff --git a/purgatory/printf.c b/purgatory/printf.c
new file mode 100644
index 00000000..962683d6
--- /dev/null
+++ b/purgatory/printf.c
@@ -0,0 +1,128 @@
+#include <stdarg.h>
+#include <limits.h>
+#include <stdint.h>
+#include <purgatory.h>
+#include <string.h>
+
+/*
+ * Output
+ * =============================================================================
+ */
+
+#define LONG_LONG_SHIFT ((int)((sizeof(unsigned long long)*CHAR_BIT) - 4))
+#define LONG_SHIFT ((int)((sizeof(unsigned long)*CHAR_BIT) - 4))
+#define INT_SHIFT ((int)((sizeof(unsigned int)*CHAR_BIT) - 4))
+#define SHRT_SHIFT ((int)((sizeof(unsigned short)*CHAR_BIT) - 4))
+#define CHAR_SHIFT ((int)((sizeof(unsigned char)*CHAR_BIT) - 4))
+
+/**************************************************************************
+PRINTF and friends
+
+ Formats:
+ %x - 4 bytes int (8 hex digits, lower case)
+ %X - 4 bytes int (8 hex digits, upper case)
+ %lx - 8 bytes long (16 hex digits, lower case)
+ %lX - 8 bytes long (16 hex digits, upper case)
+ %hx - 2 bytes int (4 hex digits, lower case)
+ %hX - 2 bytes int (4 hex digits, upper case)
+ %hhx - 1 byte int (2 hex digits, lower case)
+ %hhX - 1 byte int (2 hex digits, upper case)
+ - optional # prefixes 0x or 0X
+ %d - decimal int
+ %c - char
+ %s - string
+ Note: width specification not supported
+**************************************************************************/
+void printf(const char *fmt, ...)
+{
+ va_list args;
+ char *p;
+ va_start(args, fmt);
+ for ( ; *fmt != '\0'; ++fmt) {
+ if (*fmt != '%') {
+ putchar(*fmt);
+ continue;
+ }
+ if (*++fmt == 's') {
+ for(p = va_arg(args, char *); *p != '\0'; p++)
+ putchar(*p);
+ }
+ else { /* Length of item is bounded */
+ char tmp[40], *q = tmp;
+ int shift = INT_SHIFT;
+ if (*fmt == 'L') {
+ shift = LONG_LONG_SHIFT;
+ fmt++;
+ }
+ else if (*fmt == 'l') {
+ shift = LONG_SHIFT;
+ fmt++;
+ }
+ else if (*fmt == 'h') {
+ shift = SHRT_SHIFT;
+ fmt++;
+ if (*fmt == 'h') {
+ shift = CHAR_SHIFT;
+ fmt++;
+ }
+ }
+
+ /*
+ * Before each format q points to tmp buffer
+ * After each format q points past end of item
+ */
+ if ((*fmt | 0x20) == 'x') {
+ /* With x86 gcc, sizeof(long) == sizeof(int) */
+ unsigned long long h;
+ int ncase;
+ if (shift > LONG_SHIFT) {
+ h = va_arg(args, unsigned long long);
+ }
+ else if (shift > INT_SHIFT) {
+ h = va_arg(args, unsigned long);
+ } else {
+ h = va_arg(args, unsigned int);
+ }
+ ncase = (*fmt & 0x20);
+ for ( ; shift >= 0; shift -= 4)
+ *q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
+ }
+ else if (*fmt == 'd') {
+ char *r;
+ long i;
+ if (shift > LONG_SHIFT) {
+ i = va_arg(args, long long);
+ }
+ else if (shift > INT_SHIFT) {
+ i = va_arg(args, long);
+ } else {
+ i = va_arg(args, int);
+ }
+ if (i < 0) {
+ *q++ = '-';
+ i = -i;
+ }
+ p = q; /* save beginning of digits */
+ do {
+ *q++ = '0' + (i % 10);
+ i /= 10;
+ } while (i);
+ /* reverse digits, stop in middle */
+ r = q; /* don't alter q */
+ while (--r > p) {
+ i = *r;
+ *r = *p;
+ *p++ = i;
+ }
+ }
+ else if (*fmt == 'c')
+ *q++ = va_arg(args, int);
+ else
+ *q++ = *fmt;
+ /* now output the saved string */
+ for (p = tmp; p < q; ++p)
+ putchar(*p);
+ }
+ }
+ va_end(args);
+}
diff --git a/purgatory/purgatory.c b/purgatory/purgatory.c
new file mode 100644
index 00000000..97fc638d
--- /dev/null
+++ b/purgatory/purgatory.c
@@ -0,0 +1,47 @@
+#include <stdarg.h>
+#include <limits.h>
+#include <stdint.h>
+#include <purgatory.h>
+#include <sha256.h>
+#include <string.h>
+#include "../kexec/kexec-sha256.h"
+
+struct sha256_region sha256_regions[SHA256_REGIONS] = {};
+sha256_digest_t sha256_digest = { };
+
+void verify_sha256_digest(void)
+{
+ struct sha256_region *ptr, *end;
+ sha256_digest_t digest;
+ int i;
+ sha256_context ctx;
+ sha256_starts(&ctx);
+ end = &sha256_regions[sizeof(sha256_regions)/sizeof(sha256_regions[0])];
+ for(ptr = sha256_regions; ptr < end; ptr++) {
+ sha256_update(&ctx, ptr->start, ptr->len);
+ }
+ sha256_finish(&ctx, digest);
+ if (memcmp(digest, sha256_digest, sizeof(digest)) != 0) {
+ printf("sha256 digests do not match :(\n");
+ printf(" digest: ");
+ for(i = 0; i < sizeof(digest); i++) {
+ printf("%hhx ", digest[i]);
+ }
+ printf("\n");
+ printf("sha256_digest: ");
+ for(i = 0; i < sizeof(sha256_digest); i++) {
+ printf("%hhx ", sha256_digest[i]);
+ }
+ printf("\n");
+ for(;;) {
+ /* loop forever */
+ }
+ }
+}
+
+void purgatory(void)
+{
+ printf("I'm in purgatory\n");
+ setup_arch();
+ verify_sha256_digest();
+}
diff --git a/purgatory/string.c b/purgatory/string.c
new file mode 100644
index 00000000..4f35613e
--- /dev/null
+++ b/purgatory/string.c
@@ -0,0 +1,53 @@
+#include <stddef.h>
+#include <string.h>
+
+size_t strnlen(const char *s, size_t max)
+{
+ size_t len = 0;
+ while(len < max && *s) {
+ len++;
+ s++;
+ }
+ return len;
+}
+
+void* memset(void* s, int c, size_t n)
+{
+ size_t i;
+ char *ss = (char*)s;
+
+ for (i=0;i<n;i++) ss[i] = c;
+ return s;
+}
+
+
+void* memcpy(void *dest, const void *src, size_t len)
+{
+ size_t i;
+ unsigned char *d;
+ const unsigned char *s;
+ d = dest;
+ s = src;
+
+ for (i=0; i < len; i++)
+ d[i] = s[i];
+
+ return dest;
+}
+
+
+int memcmp(void *src1, void *src2, size_t len)
+{
+ unsigned char *s1, *s2;
+ size_t i;
+ s1 = src1;
+ s2 = src2;
+ for(i = 0; i < len; i++) {
+ if (*s1 != *s2) {
+ return *s2 - *s1;
+ }
+ }
+ return 0;
+
+}
+