summaryrefslogtreecommitdiffstats
path: root/purgatory
diff options
context:
space:
mode:
authorZou Nan hai <nanhai.zou@intel.com>2006-07-27 11:28:57 -0600
committerEric W. Biederman <ebiederm@xmission.com>2006-07-27 11:28:57 -0600
commit9241000f28eb6b86a06c0be2d6cf31498373bc1c (patch)
tree695d4baeb68efcc81784e469b4ed8e03c13e1fc6 /purgatory
parenta59caf2ae4f2027c3644551b03d5474d4d634ec5 (diff)
downloadkexec-tools-9241000f28eb6b86a06c0be2d6cf31498373bc1c.tar.gz
kdump ia64
On Fri, 2006-06-09 at 19:50, Welterlen Benoit wrote: > Zou Nan hai wrote: > > The ia64 kdump patch is in 2 parts. > > > > the kexec-kdump-ia64-2.6.16.patch should apply on top of the previous > > kexec patch by Khalid in Tony's test tree. > > > > the kexec-tools-kdump-ia64.patch should apply to kexec-tools-1.101 > > with kexec-tools-1.101-kdump.patch > > > > > > To test it. > > Build first SMP kernel with KEXEC and KDUMP enabled. > > > > Boot it with kernel parameter "crashkernel=XXX@YYY" > > means reserver XXX from YYY for crashdumping. > > Build an UP kernel with KEXEC KDUMP VMCORE enabled. > > load this kernel as a crashdumping kernel > > kexec -p vmlinux.gz --initrd=initrd --append="...." > > > > trigger a crash, > > maybe "echo c > /proc/sysrq-trigger" > > after the crash kernel boots, > > cp /proc/vmcore core > > > > gdb first_kernel_vmlinux core > > > > please test and review. > > > > Signed-off-by: Khalid Aziz <khalid_aziz@hp.com> > > Signed-off-by: Zou Nan hai <nanhai.zou@intel.com> > > > > > > https://lists.osdl.org/mailman/listinfo/fastboot > > > > Hello Nan hai, > > I tried your patches. It seems that the kexec-tools-kdump-ia64.patch > file can not be applied after the latest release of kexec-tools > http://lse.sourceforge.net/kdump/patches/1.101-kdump9/kexec-tools-1.101-kdump9.patch > > I modified it for that. (attached file). > > I have a question about kdump : > > When the second kernel is loaded, kexec checks if the segments of the > new kernel are in the reserved memory > > valid_memory_range in kexec/kexec.c : > if ((send > mem_max) || (sstart < mem_min)) return 0; > > but mem_min and mem_max are defined by the XXX@YYY argument of the > first kernel. > For me, with 512@512 : > more /proc/iomem > ... > 049cc000-77ffffff : System RAM > 20000000-3fffffff : Crash kernel > ... > So, I can not load the second kernel : Invalid memory segment > 0x4000000 - 0x469ffff > > When I set 64@64 argument for the first kernel, the checking is ok, > but I have another issue : > kexec_load failed: Cannot assign requested address > entry = 0x80020 flags = 320001 > nr_segments = 6 > segment[0].buf = 0x6000000000021b90 > segment[0].bufsz = 20 > segment[0].mem = (nil) > segment[0].memsz = 10000 > segment[1].buf = 0x60000000000222d0 > segment[1].bufsz = 10638 > segment[1].mem = 0x80000 > segment[1].memsz = 20000 > segment[2].buf = 0x2000000003b50010 > segment[2].bufsz = 23473c > segment[2].mem = 0x100000 > segment[2].memsz = 240000 > segment[3].buf = 0x20000000002f0010 > segment[3].bufsz = 692dd8 > segment[3].mem = 0x4000000 > segment[3].memsz = 6a0000 > segment[4].buf = 0x2000000000990010 > segment[4].bufsz = 42c8 > segment[4].mem = 0x46a0000 > segment[4].memsz = 10000 > segment[5].buf = 0x20000000009a0010 > segment[5].bufsz = 17c3ec > segment[5].mem = 0x46b0000 > segment[5].memsz = 2d0000 > > > Segments of the second kernel are the same than the first one > (0x0000000004000000, 0x00000000046a0000 ...) > We can not change the PHYSICAL_START as in other architectures (x86, > x86_64, powerpc). > > So, I don't understand how it should work. Can you please have some > explanation on this ? > > Thank you very much ! > > Best regards, > > Benoit Welterlen > > > ______________________________________________________________________ I modify the patch based on this one, fixed some bugs in it. please test. Thanks Zou Nan hai Signed-off-by: Zou Nan hai <nanhai.zou@intel.com> Signed-off-by: Maneesh Soni <maneesh@in.ibm.com>
Diffstat (limited to 'purgatory')
-rw-r--r--purgatory/arch/ia64/Makefile2
-rw-r--r--purgatory/arch/ia64/Makefile.orig9
-rw-r--r--purgatory/arch/ia64/console-ia64.c44
-rw-r--r--purgatory/arch/ia64/entry.S54
-rw-r--r--purgatory/arch/ia64/io.h94
-rw-r--r--purgatory/arch/ia64/purgatory-ia64.c188
-rw-r--r--purgatory/arch/ia64/purgatory-ia64.h3
-rw-r--r--purgatory/arch/ia64/vga.c143
8 files changed, 481 insertions, 56 deletions
diff --git a/purgatory/arch/ia64/Makefile b/purgatory/arch/ia64/Makefile
index 6d6d2f50..953b3ee7 100644
--- a/purgatory/arch/ia64/Makefile
+++ b/purgatory/arch/ia64/Makefile
@@ -5,5 +5,5 @@ PCFLAGS += -ffixed-r28
PURGATORY_S_SRCS+= purgatory/arch/ia64/entry.S
PURGATORY_C_SRCS+= purgatory/arch/ia64/purgatory-ia64.c
PURGATORY_C_SRCS+= purgatory/arch/ia64/console-ia64.c
-PURGATORY_C_SRCS+=
+PURGATORY_C_SRCS+= purgatory/arch/ia64/vga.c
diff --git a/purgatory/arch/ia64/Makefile.orig b/purgatory/arch/ia64/Makefile.orig
new file mode 100644
index 00000000..6d6d2f50
--- /dev/null
+++ b/purgatory/arch/ia64/Makefile.orig
@@ -0,0 +1,9 @@
+#
+# Purgatory ia64
+#
+PCFLAGS += -ffixed-r28
+PURGATORY_S_SRCS+= purgatory/arch/ia64/entry.S
+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
index 389b7be0..99d97ca6 100644
--- a/purgatory/arch/ia64/console-ia64.c
+++ b/purgatory/arch/ia64/console-ia64.c
@@ -1,5 +1,47 @@
#include <purgatory.h>
+#include "io.h"
+
+#define VGABASE UNCACHED(0xb8000)
+
+/* code based on i386 console code
+ * TODO add serial support
+ */
+#define MAX_YPOS 25
+#define MAX_XPOS 80
+
+unsigned long current_ypos = 1, current_xpos = 0;
+
+static void putchar_vga(int ch)
+{
+ int i, k, j;
+
+ 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++;
+ }
+ }
+}
+
void putchar(int ch)
{
- /* Nothing for now */
+ putchar_vga(ch);
}
diff --git a/purgatory/arch/ia64/entry.S b/purgatory/arch/ia64/entry.S
index 78169a62..18215055 100644
--- a/purgatory/arch/ia64/entry.S
+++ b/purgatory/arch/ia64/entry.S
@@ -1,7 +1,7 @@
/*
* purgatory: setup code
*
- * Copyright (C) 2005 Zou Nan hai (nanhai.zou@intel.com)
+ * Copyright (C) 2005-2006 Zou Nan hai (nanhai.zou@intel.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
@@ -16,6 +16,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define DECLARE_DATA8(name) \
+.global name; \
+.size name, 8; \
+name: data8 0x0
.global __dummy_efi_function
.align 32
@@ -35,18 +39,10 @@ purgatory_start:
ld8 gp=[r2];;
br.call.sptk.many b0=purgatory
;;
- alloc r2 = ar.pfs, 0, 0, 5, 0
+ alloc r2 = ar.pfs, 0, 0, 2, 0
;;
mov out0=r28
-
- movl r2=__command_line;;
- ld8 out1=[r2];;
- movl r2=__command_line_len;;
- ld8 out2=[r2];;
- movl r2=__ramdisk_base;;
- ld8 out3=[r2];;
- movl r2=__ramdisk_size;;
- ld8 out4=[r2];;
+ movl out1=__ramdisk_base;;
br.call.sptk.many b0=ia64_env_setup
movl r10=__kernel_entry;;
ld8 r14=[r10];;
@@ -58,28 +54,14 @@ purgatory_start:
br.call.sptk.many b0=b6
.endp purgatory_start
-.align 32
-.global __kernel_entry
-.size __kernel_entry, 8
-__kernel_entry:
- data8 0x0
-.global __command_line
-.size __command_line, 8
-__command_line:
- data8 0x0
-.global __command_line_len
-.size __command_line_len, 8
-__command_line_len:
- data8 0x0
-.global __ramdisk_base
-.size __ramdisk_base, 8
-__ramdisk_base:
- data8 0x0
-.global __ramdisk_size
-.size __ramdisk_size, 8
-__ramdisk_size:
- data8 0x0
-.global __gp_value
-.size __gp_value, 8
-__gp_value:
- data8 0x0
+DECLARE_DATA8(__kernel_entry)
+DECLARE_DATA8(__ramdisk_base)
+DECLARE_DATA8(__ramdisk_size)
+DECLARE_DATA8(__command_line)
+DECLARE_DATA8(__command_line_len)
+DECLARE_DATA8(__efi_memmap_base)
+DECLARE_DATA8(__efi_memmap_size)
+DECLARE_DATA8(__loaded_segments)
+DECLARE_DATA8(__loaded_segments_num)
+
+DECLARE_DATA8(__gp_value)
diff --git a/purgatory/arch/ia64/io.h b/purgatory/arch/ia64/io.h
new file mode 100644
index 00000000..73701595
--- /dev/null
+++ b/purgatory/arch/ia64/io.h
@@ -0,0 +1,94 @@
+#ifndef IO_H
+#define IO_H
+#define UNCACHED(x) (void *)((x)|(1UL<<63))
+#define MF() asm volatile ("mf.a" ::: "memory")
+#define IO_SPACE_ENCODING(p) ((((p) >> 2) << 12) | (p & 0xfff))
+
+static inline void *io_addr (unsigned long port)
+{
+ unsigned long offset;
+ unsigned long io_base;
+ asm volatile ("mov %0=ar.k0":"=r"(io_base));
+ offset = IO_SPACE_ENCODING(port);
+ return UNCACHED(io_base | offset);
+}
+
+static inline unsigned int inb (unsigned long port)
+{
+ volatile unsigned char *addr = io_addr(port);
+ unsigned char ret;
+ ret = *addr;
+ MF();
+ return ret;
+}
+
+static inline unsigned int inw (unsigned long port)
+{
+ volatile unsigned short *addr = io_addr(port);
+ unsigned short ret;
+
+ ret = *addr;
+ MF();
+ return ret;
+}
+
+static inline unsigned int ia64_inl (unsigned long port)
+{
+ volatile unsigned int *addr = __ia64_mk_io_addr(port);
+ unsigned int ret;
+ ret = *addr;
+ MF();
+ return ret;
+}
+
+static inline void outb (unsigned char val, unsigned long port)
+{
+ volatile unsigned char *addr = io_addr(port);
+
+ *addr = val;
+ MF();
+}
+
+static inline void outw (unsigned short val, unsigned long port)
+{
+ volatile unsigned short *addr = io_addr(port);
+
+ *addr = val;
+ MF();
+}
+
+static inline void outl (unsigned int val, unsigned long port)
+{
+ volatile unsigned int *addr = io_addr(port);
+
+ *addr = val;
+ MF();
+}
+
+
+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
diff --git a/purgatory/arch/ia64/purgatory-ia64.c b/purgatory/arch/ia64/purgatory-ia64.c
index 8d2008c4..c0115c01 100644
--- a/purgatory/arch/ia64/purgatory-ia64.c
+++ b/purgatory/arch/ia64/purgatory-ia64.c
@@ -1,9 +1,47 @@
+/*
+ * purgatory: setup code
+ *
+ * Copyright (C) 2005-2006 Zou Nan hai (nanhai.zou@intel.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 <purgatory.h>
#include <stdint.h>
#include <string.h>
#include "purgatory-ia64.h"
-#define PAGE_OFFSET 0xe000000000000000
+#define PAGE_OFFSET 0xe000000000000000UL
+
+#define EFI_PAGE_SHIFT 12
+#define EFI_PAGE_SIZE (1UL<<EFI_PAGE_SHIFT)
+#define EFI_PAGE_ALIGN(x) ((x + EFI_PAGE_SIZE - 1)&~(EFI_PAGE_SIZE-1))
+/* Memory types: */
+#define EFI_RESERVED_TYPE 0
+#define EFI_LOADER_CODE 1
+#define EFI_LOADER_DATA 2
+#define EFI_BOOT_SERVICES_CODE 3
+#define EFI_BOOT_SERVICES_DATA 4
+#define EFI_RUNTIME_SERVICES_CODE 5
+#define EFI_RUNTIME_SERVICES_DATA 6
+#define EFI_CONVENTIONAL_MEMORY 7
+#define EFI_UNUSABLE_MEMORY 8
+#define EFI_ACPI_RECLAIM_MEMORY 9
+#define EFI_ACPI_MEMORY_NVS 10
+#define EFI_MEMORY_MAPPED_IO 11
+#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12
+#define EFI_PAL_CODE 13
+#define EFI_MAX_MEMORY_TYPE 14
typedef struct {
uint64_t signature;
@@ -63,53 +101,171 @@ struct ia64_boot_param {
uint64_t initrd_size;
};
-void setup_arch(void)
+typedef struct {
+ uint32_t type;
+ uint32_t pad;
+ uint64_t phys_addr;
+ uint64_t virt_addr;
+ uint64_t num_pages;
+ uint64_t attribute;
+} efi_memory_desc_t;
+
+struct loaded_segment {
+ unsigned long start;
+ unsigned long end;
+ unsigned long reserved;
+};
+
+struct kexec_boot_params {
+ uint64_t ramdisk_base;
+ uint64_t ramdisk_size;
+ uint64_t command_line;
+ uint64_t command_line_len;
+ uint64_t efi_memmap_base;
+ uint64_t efi_memmap_size;
+ struct loaded_segment *loaded_segments;
+ unsigned long loaded_segments_num;
+};
+
+void
+setup_arch(void)
{
- /* Nothing for now */
+ reset_vga();
}
+
inline unsigned long PA(unsigned long addr)
{
return addr - PAGE_OFFSET;
}
-void flush_icache_range(char *start, unsigned long len)
+void
+patch_efi_memmap(struct kexec_boot_params *params,
+ struct ia64_boot_param *boot_param)
+{
+ void *dest = (void *)params->efi_memmap_base;
+ void *src = (void *)boot_param->efi_memmap;
+ unsigned long len = boot_param->efi_memmap_size;
+ unsigned long memdesc_size = boot_param->efi_memdesc_size;
+ uint64_t orig_type;
+ efi_memory_desc_t *md1, *md2;
+ void *p1, *p2, *src_end = src + len;
+ int i;
+ for (p1 = src, p2 = dest; p1 < src_end;
+ p1 += memdesc_size, p2 += memdesc_size) {
+ unsigned long mstart, mend;
+ md1 = p1;
+ md2 = p2;
+ if (md1->num_pages == 0)
+ continue;
+ mstart = md1->phys_addr;
+ mend = md1->phys_addr + (md1->num_pages
+ << EFI_PAGE_SHIFT);
+ switch (md1->type) {
+ case EFI_LOADER_DATA:
+ *md2 = *md1;
+ md2->type = EFI_CONVENTIONAL_MEMORY;
+ break;
+ default:
+ *md2 = *md1;
+ }
+ // segments are already sorted and aligned to 4K
+ orig_type = md2->type;
+ for (i = 0; i < params->loaded_segments_num; i++) {
+ struct loaded_segment *seg;
+ seg = &params->loaded_segments[i];
+ if (seg->start >= mstart && seg->start < mend) {
+ unsigned long start_pages, mid_pages, end_pages;
+ if (seg->end > mend) {
+ p1 += memdesc_size;
+ for(; p1 < src_end;
+ p1 += memdesc_size) {
+ md1 = p1;
+ /* TODO check contig and attribute here */
+ mend = md1->phys_addr
+ + (md1->num_pages << EFI_PAGE_SHIFT);
+ if (seg->end < mend)
+ break;
+ }
+ }
+ start_pages = (seg->start - mstart)
+ >> EFI_PAGE_SHIFT;
+ mid_pages = (seg->end - seg->start)
+ >> EFI_PAGE_SHIFT;
+ end_pages = (mend - seg->end)
+ >> EFI_PAGE_SHIFT;
+ if (start_pages) {
+ md2->num_pages = start_pages;
+ p2 += memdesc_size;
+ md2 = p2;
+ *md2 = *md1;
+ }
+ md2->phys_addr = seg->start;
+ md2->num_pages = mid_pages;
+ md2->type = seg->reserved ?
+ EFI_UNUSABLE_MEMORY:EFI_LOADER_DATA;
+ if (end_pages) {
+ p2 += memdesc_size;
+ md2 = p2;
+ *md2 = *md1;
+ md2->phys_addr = seg->end;
+ md2->num_pages = end_pages;
+ md2->type = orig_type;
+ mstart = seg->end;
+ } else
+ break;
+ }
+ }
+ }
+
+ boot_param->efi_memmap_size = p2 - dest;
+}
+
+void
+flush_icache_range(char *start, unsigned long len)
{
unsigned long i;
for (i = 0;i < len; i += 32)
- asm volatile("fc.i %0"::"r"(start+i):"memory");
+ asm volatile("fc.i %0"::"r"(start + i):"memory");
asm volatile (";;sync.i;;":::"memory");
asm volatile ("srlz.i":::"memory");
}
extern char __dummy_efi_function[], __dummy_efi_function_end[];
-void ia64_env_setup(struct ia64_boot_param *boot_param,
- uint64_t command_line, uint64_t command_line_len,
- uint64_t ramdisk_base, uint64_t ramdisk_size)
+
+void
+ia64_env_setup(struct ia64_boot_param *boot_param,
+ struct kexec_boot_params *params)
{
unsigned long len;
efi_system_table_t *systab;
efi_runtime_services_t *runtime;
unsigned long *set_virtual_address_map;
+ char *command_line = (char *)params->command_line;
+ uint64_t command_line_len = params->command_line_len;
// patch efi_runtime->set_virtual_address_map to a
// dummy function
len = __dummy_efi_function_end - __dummy_efi_function;
- memcpy((char *)command_line + command_line_len, __dummy_efi_function,
- len);
+ memcpy(command_line + command_line_len,
+ __dummy_efi_function, len);
systab = (efi_system_table_t *)boot_param->efi_systab;
runtime = (efi_runtime_services_t *)PA(systab->runtime);
set_virtual_address_map =
(unsigned long *)PA(runtime->set_virtual_address_map);
- *(set_virtual_address_map)=
- (unsigned long)((char *)command_line + command_line_len);
- flush_icache_range((char *)command_line+command_line_len, len);
+ *(set_virtual_address_map) =
+ (unsigned long)(command_line + command_line_len);
+ flush_icache_range(command_line + command_line_len, len);
+
+ patch_efi_memmap(params, boot_param);
+
+ boot_param->efi_memmap = params->efi_memmap_base;
- boot_param->command_line = command_line;
+ boot_param->command_line = params->command_line;
boot_param->console_info.orig_x = 0;
boot_param->console_info.orig_y = 0;
- boot_param->initrd_start = ramdisk_base;
- boot_param->initrd_size = ramdisk_size;
+ boot_param->initrd_start = params->ramdisk_base;
+ boot_param->initrd_size = params->ramdisk_size;
}
/* This function can be used to execute after the SHA256 verification. */
diff --git a/purgatory/arch/ia64/purgatory-ia64.h b/purgatory/arch/ia64/purgatory-ia64.h
index 773e3c00..8fd3af13 100644
--- a/purgatory/arch/ia64/purgatory-ia64.h
+++ b/purgatory/arch/ia64/purgatory-ia64.h
@@ -1,6 +1,5 @@
#ifndef PURGATORY_IA64_H
#define PURGATORY_IA64_H
-/* nothing yet */
-
+void reset_vga(void);
#endif /* PURGATORY_IA64_H */
diff --git a/purgatory/arch/ia64/vga.c b/purgatory/arch/ia64/vga.c
new file mode 100644
index 00000000..dceadb79
--- /dev/null
+++ b/purgatory/arch/ia64/vga.c
@@ -0,0 +1,143 @@
+#include "io.h"
+void 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);
+}